aboutsummaryrefslogtreecommitdiff
path: root/design/slave_dispatcher.v
blob: 6377a57d2ede84fcf0f20cbd52158fe47a26a3fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
`default_nettype none

module slave_dispatcher
  (
   input wire 	      CLK,
   input wire 	      RST,

   input wire 	      S0_ACK_O,
   output wire [17:0] S0_ADR_I,
   output wire [15:0] S0_DAT_I,
   input wire [15:0]  S0_DAT_O,
   output wire 	      S0_STB_I,
   output wire 	      S0_WE_I,
   input wire 	      S0_STALL_O,

   input wire 	      S1_ACK_O,
   output wire [17:0] S1_ADR_I,
   output wire [15:0] S1_DAT_I,
   input wire [15:0]  S1_DAT_O,
   output wire 	      S1_STB_I,
   output wire 	      S1_WE_I,
   input wire 	      S1_STALL_O,

   input wire 	      S2_ACK_O,
   output wire [17:0] S2_ADR_I,
   output wire [15:0] S2_DAT_I,
   input wire [15:0]  S2_DAT_O,
   output wire 	      S2_STB_I,
   output wire 	      S2_WE_I,
   input wire 	      S2_STALL_O,

   input wire 	      S3_ACK_O,
   output wire [17:0] S3_ADR_I,
   output wire [15:0] S3_DAT_I,
   input wire [15:0]  S3_DAT_O,
   output wire 	      S3_STB_I,
   output wire 	      S3_WE_I,
   input wire 	      S3_STALL_O,

   output wire 	      S_COMBINED_ACK_O,
   input wire [19:0]  S_COMBINED_ADR_I,
   input wire [15:0]  S_COMBINED_DAT_I,
   output wire [15:0] S_COMBINED_DAT_O,
   input wire 	      S_COMBINED_STB_I,
   input wire 	      S_COMBINED_WE_I,
   output wire 	      S_COMBINED_STALL_O
   );

   wire [0:3] 	      acks;
   wire [0:3] 	      stalls;
   wire [15:0] 	      datas [0:3];
   assign acks = {S0_ACK_O, S1_ACK_O, S2_ACK_O, S3_ACK_O};
   assign stalls = {S0_STALL_O, S1_STALL_O, S2_STALL_O, S3_STALL_O};
   assign datas[0] = S0_DAT_O;
   assign datas[1] = S1_DAT_O;
   assign datas[2] = S2_DAT_O;
   assign datas[3] = S3_DAT_O;

   reg [1:0] 	      commands_awaiting;
   reg [1:0] 	      slave_last_accessed;

   wire 	      working;
   wire [1:0] 	      slave_accessed;
   wire 	      slave_switch;
   wire [1:0] 	      commands_awaiting_next_tick;
   assign working = commands_awaiting || S_COMBINED_STB_I;
   assign slave_accessed = commands_awaiting ? slave_last_accessed :
			   S_COMBINED_ADR_I[19:18];
   assign S_COMBINED_ACK_O = acks[slave_accessed] && working;
   assign S_COMBINED_DAT_O = datas[slave_accessed];
   assign slave_switch = slave_accessed != S_COMBINED_ADR_I[19:18];
   assign S_COMBINED_STALL_O = stalls[slave_accessed] || slave_switch ||
			       (commands_awaiting == 3 && !S_COMBINED_ACK_O);
   assign commands_awaiting_next_tick
     = commands_awaiting - S_COMBINED_ACK_O +
       (S_COMBINED_STB_I && !S_COMBINED_STALL_O);

`ifdef SIMULATION
   /* anything could be latched here, this is just to avoid undefined values */
   initial begin
      slave_last_accessed <= 0;
      commands_awaiting <= 2; /* It is supposed to be driven low by RST */
   end
`endif

   always @ (posedge CLK) begin
      slave_last_accessed <= slave_accessed;

      if (RST)
	commands_awaiting <= 0;
      else
	commands_awaiting <= commands_awaiting_next_tick;
   end

   assign S0_ADR_I = S_COMBINED_ADR_I[17:0];
   assign S1_ADR_I = S_COMBINED_ADR_I[17:0];
   assign S2_ADR_I = S_COMBINED_ADR_I[17:0];
   assign S3_ADR_I = S_COMBINED_ADR_I[17:0];

   assign S0_DAT_I = S_COMBINED_DAT_I;
   assign S1_DAT_I = S_COMBINED_DAT_I;
   assign S2_DAT_I = S_COMBINED_DAT_I;
   assign S3_DAT_I = S_COMBINED_DAT_I;

   wire pass_strobe;
   assign pass_strobe = S_COMBINED_STB_I && !slave_switch &&
			(commands_awaiting != 3 || S_COMBINED_ACK_O);

   assign S0_STB_I = slave_accessed == 0 && pass_strobe;
   assign S1_STB_I = slave_accessed == 1 && pass_strobe;
   assign S2_STB_I = slave_accessed == 2 && pass_strobe;
   assign S3_STB_I = slave_accessed == 3 && pass_strobe;

   assign S0_WE_I = S_COMBINED_WE_I;
   assign S1_WE_I = S_COMBINED_WE_I;
   assign S2_WE_I = S_COMBINED_WE_I;
   assign S3_WE_I = S_COMBINED_WE_I;
endmodule // slave_dispatcher