blob: b31c23ae2c80fa5afbdbc68c2a7b3bcb958cc46a [file] [log] [blame]
Matt Venn08cd6eb2020-11-16 12:01:14 +01001`default_nettype none
shalan0d14e6e2020-08-31 16:50:48 +02002module mprj_ctrl_wb #(
Tim Edwardsba328902020-10-27 15:03:22 -04003 parameter BASE_ADR = 32'h 2300_0000,
4 parameter XFER = 8'h 00,
5 parameter PWRDATA = 8'h 04,
6 parameter IODATA = 8'h 08, // One word per 32 IOs
Ahmed Ghazy22d29d62020-10-28 03:42:02 +02007 parameter IOCONFIG = 8'h 20
shalan0d14e6e2020-08-31 16:50:48 +02008)(
9 input wb_clk_i,
10 input wb_rst_i,
11
12 input [31:0] wb_dat_i,
13 input [31:0] wb_adr_i,
14 input [3:0] wb_sel_i,
15 input wb_cyc_i,
16 input wb_stb_i,
17 input wb_we_i,
18
19 output [31:0] wb_dat_o,
20 output wb_ack_o,
21
Tim Edwards04ba17f2020-10-02 22:27:50 -040022 // Output is to serial loader
23 output serial_clock,
24 output serial_resetn,
25 output serial_data_out,
shalan0d14e6e2020-08-31 16:50:48 +020026
Tim Edwards496a08a2020-10-26 15:44:51 -040027 // Pass state of OEB bit on SDO and JTAG back to the core
28 // so that the function can be overridden for management output
29 output sdo_oenb_state,
30 output jtag_oenb_state,
31
Tim Edwards04ba17f2020-10-02 22:27:50 -040032 // Read/write data to each GPIO pad from management SoC
Ahmed Ghazy22d29d62020-10-28 03:42:02 +020033 input [`MPRJ_IO_PADS-1:0] mgmt_gpio_in,
34 output [`MPRJ_IO_PADS-1:0] mgmt_gpio_out,
Tim Edwardsba328902020-10-27 15:03:22 -040035
36 // Write data to power controls
Ahmed Ghazy22d29d62020-10-28 03:42:02 +020037 output [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out
Tim Edwards04ba17f2020-10-02 22:27:50 -040038);
shalan0d14e6e2020-08-31 16:50:48 +020039 wire resetn;
40 wire valid;
41 wire ready;
42 wire [3:0] iomem_we;
43
44 assign resetn = ~wb_rst_i;
45 assign valid = wb_stb_i && wb_cyc_i;
46
47 assign iomem_we = wb_sel_i & {4{wb_we_i}};
48 assign wb_ack_o = ready;
49
50 mprj_ctrl #(
51 .BASE_ADR(BASE_ADR),
Tim Edwards04ba17f2020-10-02 22:27:50 -040052 .XFER(XFER),
Tim Edwardsba328902020-10-27 15:03:22 -040053 .PWRDATA(PWRDATA),
54 .IODATA(IODATA),
Ahmed Ghazy22d29d62020-10-28 03:42:02 +020055 .IOCONFIG(IOCONFIG)
shalan0d14e6e2020-08-31 16:50:48 +020056 ) mprj_ctrl (
57 .clk(wb_clk_i),
58 .resetn(resetn),
59 .iomem_addr(wb_adr_i),
60 .iomem_valid(valid),
Tim Edwardsc18c4742020-10-03 11:26:39 -040061 .iomem_wstrb(iomem_we[1:0]),
shalan0d14e6e2020-08-31 16:50:48 +020062 .iomem_wdata(wb_dat_i),
63 .iomem_rdata(wb_dat_o),
64 .iomem_ready(ready),
Tim Edwards04ba17f2020-10-02 22:27:50 -040065
66 .serial_clock(serial_clock),
67 .serial_resetn(serial_resetn),
68 .serial_data_out(serial_data_out),
Tim Edwards496a08a2020-10-26 15:44:51 -040069 .sdo_oenb_state(sdo_oenb_state),
70 .jtag_oenb_state(jtag_oenb_state),
Tim Edwards44bab472020-10-04 22:09:54 -040071 // .mgmt_gpio_io(mgmt_gpio_io)
72 .mgmt_gpio_in(mgmt_gpio_in),
Tim Edwardsca2f3182020-10-06 10:05:11 -040073 .mgmt_gpio_out(mgmt_gpio_out)
shalan0d14e6e2020-08-31 16:50:48 +020074 );
75
76endmodule
77
78module mprj_ctrl #(
Tim Edwardsba328902020-10-27 15:03:22 -040079 parameter BASE_ADR = 32'h 2300_0000,
80 parameter XFER = 8'h 00,
81 parameter PWRDATA = 8'h 04,
82 parameter IODATA = 8'h 08,
83 parameter IOCONFIG = 8'h 20,
Tim Edwardsba328902020-10-27 15:03:22 -040084 parameter IO_CTRL_BITS = 13
shalan0d14e6e2020-08-31 16:50:48 +020085)(
86 input clk,
87 input resetn,
88
89 input [31:0] iomem_addr,
90 input iomem_valid,
Tim Edwardsc18c4742020-10-03 11:26:39 -040091 input [1:0] iomem_wstrb,
shalan0d14e6e2020-08-31 16:50:48 +020092 input [31:0] iomem_wdata,
shalan0d14e6e2020-08-31 16:50:48 +020093 output reg [31:0] iomem_rdata,
94 output reg iomem_ready,
95
Tim Edwards04ba17f2020-10-02 22:27:50 -040096 output serial_clock,
97 output serial_resetn,
98 output serial_data_out,
Tim Edwards496a08a2020-10-26 15:44:51 -040099 output sdo_oenb_state,
100 output jtag_oenb_state,
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200101 input [`MPRJ_IO_PADS-1:0] mgmt_gpio_in,
102 output [`MPRJ_IO_PADS-1:0] mgmt_gpio_out
shalan0d14e6e2020-08-31 16:50:48 +0200103);
Tim Edwardsc18c4742020-10-03 11:26:39 -0400104
Tim Edwards44bab472020-10-04 22:09:54 -0400105`define IDLE 2'b00
106`define START 2'b01
107`define XBYTE 2'b10
108`define LOAD 2'b11
Tim Edwardsc18c4742020-10-03 11:26:39 -0400109
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200110 localparam IO_WORDS = (`MPRJ_IO_PADS % 32 != 0) + (`MPRJ_IO_PADS / 32);
Tim Edwards9eda80d2020-10-08 21:36:44 -0400111
Tim Edwardsba328902020-10-27 15:03:22 -0400112 localparam IO_BASE_ADR = (BASE_ADR | IOCONFIG);
113
Tim Edwards44bab472020-10-04 22:09:54 -0400114 localparam OEB = 1; // Offset of output enable in shift register.
115 localparam INP_DIS = 3; // Offset of input disable in shift register.
shalan0d14e6e2020-08-31 16:50:48 +0200116
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200117 reg [IO_CTRL_BITS-1:0] io_ctrl[`MPRJ_IO_PADS-1:0]; // I/O control, 1 word per gpio pad
118 reg [`MPRJ_IO_PADS-1:0] mgmt_gpio_outr; // I/O write data, 1 bit per gpio pad
119 wire [`MPRJ_IO_PADS-1:0] mgmt_gpio_out; // I/O write data output when input disabled
120 reg [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out; // Power write data, 1 bit per power pad
Tim Edwardsba328902020-10-27 15:03:22 -0400121 reg xfer_ctrl; // Transfer control (1 bit)
shalan0d14e6e2020-08-31 16:50:48 +0200122
Tim Edwards9eda80d2020-10-08 21:36:44 -0400123 wire [IO_WORDS-1:0] io_data_sel; // wishbone selects
Tim Edwardsba328902020-10-27 15:03:22 -0400124 wire pwr_data_sel;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400125 wire xfer_sel;
Tim Edwardsd01c6372020-10-28 13:40:03 -0400126 wire busy;
Tim Edwards581068f2020-11-19 12:45:25 -0500127 wire selected;
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200128 wire [`MPRJ_IO_PADS-1:0] io_ctrl_sel;
Ahmed Ghazyf46273f2020-10-31 23:48:35 +0200129 reg [31:0] iomem_rdata_pre;
Tim Edwardsba328902020-10-27 15:03:22 -0400130
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200131 wire [`MPRJ_IO_PADS-1:0] mgmt_gpio_in;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400132
Tim Edwards496a08a2020-10-26 15:44:51 -0400133 wire sdo_oenb_state, jtag_oenb_state;
134
135 // JTAG and housekeeping SDO are normally controlled by their respective
136 // modules with OEB set to the default 1 value. If configured for an
137 // additional output by setting the OEB bit low, then pass this information
138 // back to the core so that the default signals can be overridden.
139
140 assign jtag_oenb_state = io_ctrl[0][OEB];
141 assign sdo_oenb_state = io_ctrl[1][OEB];
142
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200143 `define wtop (((i+1)*32 > `MPRJ_IO_PADS) ? `MPRJ_IO_PADS-1 : (i+1)*32-1)
Tim Edwards0445c082020-10-27 20:53:54 -0400144 `define wbot (i*32)
145 `define rtop (`wtop - `wbot)
Tim Edwards04ba17f2020-10-02 22:27:50 -0400146
shalan0d14e6e2020-08-31 16:50:48 +0200147 genvar i;
Tim Edwards9eda80d2020-10-08 21:36:44 -0400148
Tim Edwards0445c082020-10-27 20:53:54 -0400149 // Assign selection bits per address
150
151 assign xfer_sel = (iomem_addr[7:0] == XFER);
152 assign pwr_data_sel = (iomem_addr[7:0] == PWRDATA);
153
Tim Edwards9eda80d2020-10-08 21:36:44 -0400154 generate
155 for (i=0; i<IO_WORDS; i=i+1) begin
Tim Edwardsba328902020-10-27 15:03:22 -0400156 assign io_data_sel[i] = (iomem_addr[7:0] == (IODATA + i*4));
Tim Edwards9eda80d2020-10-08 21:36:44 -0400157 end
Tim Edwards9eda80d2020-10-08 21:36:44 -0400158
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200159 for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400160 assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4));
Tim Edwardsca2f3182020-10-06 10:05:11 -0400161 assign mgmt_gpio_out[i] = (io_ctrl[i][INP_DIS] == 1'b1) ?
162 mgmt_gpio_outr[i] : 1'bz;
shalan0d14e6e2020-08-31 16:50:48 +0200163 end
164 endgenerate
165
Tim Edwards0445c082020-10-27 20:53:54 -0400166 // Set selection and iomem_rdata_pre
167
168 assign selected = xfer_sel || pwr_data_sel || (|io_data_sel) || (|io_ctrl_sel);
169
Ahmed Ghazyf46273f2020-10-31 23:48:35 +0200170 wire [31:0] io_data_arr[0:IO_WORDS-1];
171 wire [31:0] io_ctrl_arr[0:`MPRJ_IO_PADS-1];
172 generate
173 for (i=0; i<IO_WORDS; i=i+1) begin
174 assign io_data_arr[i] = {{(31-`rtop){1'b0}}, mgmt_gpio_in[`wtop:`wbot]};
Tim Edwards0445c082020-10-27 20:53:54 -0400175
Ahmed Ghazyf46273f2020-10-31 23:48:35 +0200176 end
177 for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
178 assign io_ctrl_arr[i] = {{(32-IO_CTRL_BITS){1'b0}}, io_ctrl[i]};
179 end
Tim Edwards0445c082020-10-27 20:53:54 -0400180 endgenerate
181
Ahmed Ghazyf46273f2020-10-31 23:48:35 +0200182
183 integer j;
184 always @ * begin
185 iomem_rdata_pre = 'b0;
186 if (xfer_sel) begin
187 iomem_rdata_pre = {31'b0, busy};
188 end else if (pwr_data_sel) begin
189 iomem_rdata_pre = {{(32-`MPRJ_PWR_PADS){1'b0}}, pwr_ctrl_out};
190 end else if (|io_data_sel) begin
191 for (j=0; j<IO_WORDS; j=j+1) begin
192 if (io_data_sel[j]) begin
193 iomem_rdata_pre = io_data_arr[j];
194 end
195 end
196 end else begin
197 for (j=0; j<`MPRJ_IO_PADS; j=j+1) begin
198 if (io_ctrl_sel[j]) begin
199 iomem_rdata_pre = io_ctrl_arr[j];
200 end
201 end
202 end
203 end
204
Tim Edwards0445c082020-10-27 20:53:54 -0400205 // General I/O transfer
206
207 always @(posedge clk) begin
208 if (!resetn) begin
209 iomem_rdata <= 0;
210 iomem_ready <= 0;
211 end else begin
212 iomem_ready <= 0;
213 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
214 iomem_ready <= 1'b 1;
215
216 if (selected) begin
217 iomem_rdata <= iomem_rdata_pre;
218 end
219 end
220 end
221 end
222
223 // I/O write of xfer bit. Also handles iomem_ready signal and power data.
Tim Edwards04ba17f2020-10-02 22:27:50 -0400224
225 always @(posedge clk) begin
226 if (!resetn) begin
227 xfer_ctrl <= 0;
Tim Edwardsba328902020-10-27 15:03:22 -0400228 pwr_ctrl_out <= 0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400229 end else begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400230 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
Tim Edwards9eda80d2020-10-08 21:36:44 -0400231 if (xfer_sel) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400232 if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[0];
Tim Edwardsba328902020-10-27 15:03:22 -0400233 end else if (pwr_data_sel) begin
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200234 if (iomem_wstrb[0]) pwr_ctrl_out <= iomem_wdata[`MPRJ_PWR_PADS-1:0];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400235 end
Tim Edwards251e0df2020-10-05 11:02:12 -0400236 end else begin
237 xfer_ctrl <= 1'b0; // Immediately self-resetting
Tim Edwards04ba17f2020-10-02 22:27:50 -0400238 end
239 end
240 end
241
Tim Edwards9eda80d2020-10-08 21:36:44 -0400242 // I/O transfer of gpio data to/from user project region under management
243 // SoC control
244
Tim Edwards9eda80d2020-10-08 21:36:44 -0400245 generate
246 for (i=0; i<IO_WORDS; i=i+1) begin
247 always @(posedge clk) begin
248 if (!resetn) begin
249 mgmt_gpio_outr[`wtop:`wbot] <= 'd0;
250 end else begin
251 if (iomem_valid && !iomem_ready && iomem_addr[31:8] ==
252 BASE_ADR[31:8]) begin
253 if (io_data_sel[i]) begin
Tim Edwards9eda80d2020-10-08 21:36:44 -0400254 if (iomem_wstrb[0]) begin
255 mgmt_gpio_outr[`wtop:`wbot] <= iomem_wdata[`rtop:0];
256 end
257 end
258 end
259 end
260 end
261 end
Tim Edwards9eda80d2020-10-08 21:36:44 -0400262
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200263 for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
shalan0d14e6e2020-08-31 16:50:48 +0200264 always @(posedge clk) begin
265 if (!resetn) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400266 // NOTE: This initialization must match the defaults passed
Tim Edwards496a08a2020-10-26 15:44:51 -0400267 // to the control blocks. Specifically, 0x1803 is for a
Tim Edwards251e0df2020-10-05 11:02:12 -0400268 // bidirectional pad, and 0x0403 is for a simple input pad
269 if (i < 2) begin
Tim Edwards496a08a2020-10-26 15:44:51 -0400270 io_ctrl[i] <= 'h1803;
Tim Edwards251e0df2020-10-05 11:02:12 -0400271 end else begin
272 io_ctrl[i] <= 'h0403;
273 end
shalan0d14e6e2020-08-31 16:50:48 +0200274 end else begin
Tim Edwardsba328902020-10-27 15:03:22 -0400275 if (iomem_valid && !iomem_ready &&
276 iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200277 if (io_ctrl_sel[i]) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400278 // NOTE: Byte-wide write to io_ctrl is prohibited
shalan0d14e6e2020-08-31 16:50:48 +0200279 if (iomem_wstrb[0])
Tim Edwardsc18c4742020-10-03 11:26:39 -0400280 io_ctrl[i] <= iomem_wdata[IO_CTRL_BITS-1:0];
shalan0d14e6e2020-08-31 16:50:48 +0200281 end
282 end
283 end
284 end
285 end
286 endgenerate
287
Tim Edwards04ba17f2020-10-02 22:27:50 -0400288 reg [3:0] xfer_count;
289 reg [5:0] pad_count;
290 reg [1:0] xfer_state;
291 reg serial_clock;
292 reg serial_resetn;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400293
Tim Edwardsc18c4742020-10-03 11:26:39 -0400294 reg [IO_CTRL_BITS-1:0] serial_data_staging;
295
Tim Edwards251e0df2020-10-05 11:02:12 -0400296 wire serial_data_out;
Tim Edwards251e0df2020-10-05 11:02:12 -0400297
298 assign serial_data_out = serial_data_staging[IO_CTRL_BITS-1];
299 assign busy = (xfer_state != `IDLE);
300
Tim Edwardsc18c4742020-10-03 11:26:39 -0400301 always @(posedge clk or negedge resetn) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400302 if (resetn == 1'b0) begin
303
Tim Edwards44bab472020-10-04 22:09:54 -0400304 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400305 xfer_count <= 4'd0;
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200306 pad_count <= `MPRJ_IO_PADS;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400307 serial_resetn <= 1'b0;
308 serial_clock <= 1'b0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400309
310 end else begin
311
Tim Edwards44bab472020-10-04 22:09:54 -0400312 if (xfer_state == `IDLE) begin
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200313 pad_count <= `MPRJ_IO_PADS;
Tim Edwards251e0df2020-10-05 11:02:12 -0400314 serial_resetn <= 1'b1;
Tim Edwards44bab472020-10-04 22:09:54 -0400315 serial_clock <= 1'b0;
316 if (xfer_ctrl == 1'b1) begin
317 xfer_state <= `START;
318 end
319 end else if (xfer_state == `START) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400320 serial_resetn <= 1'b1;
321 serial_clock <= 1'b0;
322 xfer_count <= 6'd0;
Tim Edwards251e0df2020-10-05 11:02:12 -0400323 pad_count <= pad_count - 1;
324 xfer_state <= `XBYTE;
325 serial_data_staging <= io_ctrl[pad_count - 1];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400326 end else if (xfer_state == `XBYTE) begin
327 serial_resetn <= 1'b1;
328 serial_clock <= ~serial_clock;
329 if (serial_clock == 1'b0) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400330 if (xfer_count == IO_CTRL_BITS - 1) begin
331 if (pad_count == 0) begin
332 xfer_state <= `LOAD;
333 end else begin
334 xfer_state <= `START;
335 end
Tim Edwards04ba17f2020-10-02 22:27:50 -0400336 end else begin
337 xfer_count <= xfer_count + 1;
338 end
339 end else begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400340 serial_data_staging <= {serial_data_staging[IO_CTRL_BITS-2:0], 1'b0};
Tim Edwards04ba17f2020-10-02 22:27:50 -0400341 end
342 end else if (xfer_state == `LOAD) begin
343 xfer_count <= xfer_count + 1;
344
345 /* Load sequence: Raise clock for final data shift in;
346 * Pulse reset low while clock is high
347 * Set clock back to zero.
348 * Return to idle mode.
349 */
350 if (xfer_count == 4'd0) begin
351 serial_clock <= 1'b1;
352 serial_resetn <= 1'b1;
353 end else if (xfer_count == 4'd1) begin
354 serial_clock <= 1'b1;
355 serial_resetn <= 1'b0;
356 end else if (xfer_count == 4'd2) begin
357 serial_clock <= 1'b1;
358 serial_resetn <= 1'b1;
359 end else if (xfer_count == 4'd3) begin
360 serial_resetn <= 1'b1;
361 serial_clock <= 1'b0;
Tim Edwards44bab472020-10-04 22:09:54 -0400362 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400363 end
364 end
365 end
366 end
367
368endmodule
Tim Edwards581068f2020-11-19 12:45:25 -0500369`default_nettype wire