blob: 6b17fe20d90b58ec86f6533d8513af06128944ee [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;
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200127 wire [`MPRJ_IO_PADS-1:0] io_ctrl_sel;
Ahmed Ghazyf46273f2020-10-31 23:48:35 +0200128 reg [31:0] iomem_rdata_pre;
Tim Edwardsba328902020-10-27 15:03:22 -0400129
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200130 wire [`MPRJ_IO_PADS-1:0] mgmt_gpio_in;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400131
Tim Edwards496a08a2020-10-26 15:44:51 -0400132 wire sdo_oenb_state, jtag_oenb_state;
133
134 // JTAG and housekeeping SDO are normally controlled by their respective
135 // modules with OEB set to the default 1 value. If configured for an
136 // additional output by setting the OEB bit low, then pass this information
137 // back to the core so that the default signals can be overridden.
138
139 assign jtag_oenb_state = io_ctrl[0][OEB];
140 assign sdo_oenb_state = io_ctrl[1][OEB];
141
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200142 `define wtop (((i+1)*32 > `MPRJ_IO_PADS) ? `MPRJ_IO_PADS-1 : (i+1)*32-1)
Tim Edwards0445c082020-10-27 20:53:54 -0400143 `define wbot (i*32)
144 `define rtop (`wtop - `wbot)
Tim Edwards04ba17f2020-10-02 22:27:50 -0400145
shalan0d14e6e2020-08-31 16:50:48 +0200146 genvar i;
Tim Edwards9eda80d2020-10-08 21:36:44 -0400147
Tim Edwards0445c082020-10-27 20:53:54 -0400148 // Assign selection bits per address
149
150 assign xfer_sel = (iomem_addr[7:0] == XFER);
151 assign pwr_data_sel = (iomem_addr[7:0] == PWRDATA);
152
Tim Edwards9eda80d2020-10-08 21:36:44 -0400153 generate
154 for (i=0; i<IO_WORDS; i=i+1) begin
Tim Edwardsba328902020-10-27 15:03:22 -0400155 assign io_data_sel[i] = (iomem_addr[7:0] == (IODATA + i*4));
Tim Edwards9eda80d2020-10-08 21:36:44 -0400156 end
Tim Edwards9eda80d2020-10-08 21:36:44 -0400157
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200158 for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400159 assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4));
Tim Edwardsca2f3182020-10-06 10:05:11 -0400160 assign mgmt_gpio_out[i] = (io_ctrl[i][INP_DIS] == 1'b1) ?
161 mgmt_gpio_outr[i] : 1'bz;
shalan0d14e6e2020-08-31 16:50:48 +0200162 end
163 endgenerate
164
Tim Edwards0445c082020-10-27 20:53:54 -0400165 // Set selection and iomem_rdata_pre
166
167 assign selected = xfer_sel || pwr_data_sel || (|io_data_sel) || (|io_ctrl_sel);
168
Ahmed Ghazyf46273f2020-10-31 23:48:35 +0200169 wire [31:0] io_data_arr[0:IO_WORDS-1];
170 wire [31:0] io_ctrl_arr[0:`MPRJ_IO_PADS-1];
171 generate
172 for (i=0; i<IO_WORDS; i=i+1) begin
173 assign io_data_arr[i] = {{(31-`rtop){1'b0}}, mgmt_gpio_in[`wtop:`wbot]};
Tim Edwards0445c082020-10-27 20:53:54 -0400174
Ahmed Ghazyf46273f2020-10-31 23:48:35 +0200175 end
176 for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
177 assign io_ctrl_arr[i] = {{(32-IO_CTRL_BITS){1'b0}}, io_ctrl[i]};
178 end
Tim Edwards0445c082020-10-27 20:53:54 -0400179 endgenerate
180
Ahmed Ghazyf46273f2020-10-31 23:48:35 +0200181
182 integer j;
183 always @ * begin
184 iomem_rdata_pre = 'b0;
185 if (xfer_sel) begin
186 iomem_rdata_pre = {31'b0, busy};
187 end else if (pwr_data_sel) begin
188 iomem_rdata_pre = {{(32-`MPRJ_PWR_PADS){1'b0}}, pwr_ctrl_out};
189 end else if (|io_data_sel) begin
190 for (j=0; j<IO_WORDS; j=j+1) begin
191 if (io_data_sel[j]) begin
192 iomem_rdata_pre = io_data_arr[j];
193 end
194 end
195 end else begin
196 for (j=0; j<`MPRJ_IO_PADS; j=j+1) begin
197 if (io_ctrl_sel[j]) begin
198 iomem_rdata_pre = io_ctrl_arr[j];
199 end
200 end
201 end
202 end
203
Tim Edwards0445c082020-10-27 20:53:54 -0400204 // General I/O transfer
205
206 always @(posedge clk) begin
207 if (!resetn) begin
208 iomem_rdata <= 0;
209 iomem_ready <= 0;
210 end else begin
211 iomem_ready <= 0;
212 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
213 iomem_ready <= 1'b 1;
214
215 if (selected) begin
216 iomem_rdata <= iomem_rdata_pre;
217 end
218 end
219 end
220 end
221
222 // I/O write of xfer bit. Also handles iomem_ready signal and power data.
Tim Edwards04ba17f2020-10-02 22:27:50 -0400223
224 always @(posedge clk) begin
225 if (!resetn) begin
226 xfer_ctrl <= 0;
Tim Edwardsba328902020-10-27 15:03:22 -0400227 pwr_ctrl_out <= 0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400228 end else begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400229 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
Tim Edwards9eda80d2020-10-08 21:36:44 -0400230 if (xfer_sel) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400231 if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[0];
Tim Edwardsba328902020-10-27 15:03:22 -0400232 end else if (pwr_data_sel) begin
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200233 if (iomem_wstrb[0]) pwr_ctrl_out <= iomem_wdata[`MPRJ_PWR_PADS-1:0];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400234 end
Tim Edwards251e0df2020-10-05 11:02:12 -0400235 end else begin
236 xfer_ctrl <= 1'b0; // Immediately self-resetting
Tim Edwards04ba17f2020-10-02 22:27:50 -0400237 end
238 end
239 end
240
Tim Edwards9eda80d2020-10-08 21:36:44 -0400241 // I/O transfer of gpio data to/from user project region under management
242 // SoC control
243
Tim Edwards9eda80d2020-10-08 21:36:44 -0400244 generate
245 for (i=0; i<IO_WORDS; i=i+1) begin
246 always @(posedge clk) begin
247 if (!resetn) begin
248 mgmt_gpio_outr[`wtop:`wbot] <= 'd0;
249 end else begin
250 if (iomem_valid && !iomem_ready && iomem_addr[31:8] ==
251 BASE_ADR[31:8]) begin
252 if (io_data_sel[i]) begin
Tim Edwards9eda80d2020-10-08 21:36:44 -0400253 if (iomem_wstrb[0]) begin
254 mgmt_gpio_outr[`wtop:`wbot] <= iomem_wdata[`rtop:0];
255 end
256 end
257 end
258 end
259 end
260 end
Tim Edwards9eda80d2020-10-08 21:36:44 -0400261
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200262 for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
shalan0d14e6e2020-08-31 16:50:48 +0200263 always @(posedge clk) begin
264 if (!resetn) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400265 // NOTE: This initialization must match the defaults passed
Tim Edwards496a08a2020-10-26 15:44:51 -0400266 // to the control blocks. Specifically, 0x1803 is for a
Tim Edwards251e0df2020-10-05 11:02:12 -0400267 // bidirectional pad, and 0x0403 is for a simple input pad
268 if (i < 2) begin
Tim Edwards496a08a2020-10-26 15:44:51 -0400269 io_ctrl[i] <= 'h1803;
Tim Edwards251e0df2020-10-05 11:02:12 -0400270 end else begin
271 io_ctrl[i] <= 'h0403;
272 end
shalan0d14e6e2020-08-31 16:50:48 +0200273 end else begin
Tim Edwardsba328902020-10-27 15:03:22 -0400274 if (iomem_valid && !iomem_ready &&
275 iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200276 if (io_ctrl_sel[i]) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400277 // NOTE: Byte-wide write to io_ctrl is prohibited
shalan0d14e6e2020-08-31 16:50:48 +0200278 if (iomem_wstrb[0])
Tim Edwardsc18c4742020-10-03 11:26:39 -0400279 io_ctrl[i] <= iomem_wdata[IO_CTRL_BITS-1:0];
shalan0d14e6e2020-08-31 16:50:48 +0200280 end
281 end
282 end
283 end
284 end
285 endgenerate
286
Tim Edwards04ba17f2020-10-02 22:27:50 -0400287 reg [3:0] xfer_count;
288 reg [5:0] pad_count;
289 reg [1:0] xfer_state;
290 reg serial_clock;
291 reg serial_resetn;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400292
Tim Edwardsc18c4742020-10-03 11:26:39 -0400293 reg [IO_CTRL_BITS-1:0] serial_data_staging;
294
Tim Edwards251e0df2020-10-05 11:02:12 -0400295 wire serial_data_out;
Tim Edwards251e0df2020-10-05 11:02:12 -0400296
297 assign serial_data_out = serial_data_staging[IO_CTRL_BITS-1];
298 assign busy = (xfer_state != `IDLE);
299
Tim Edwardsc18c4742020-10-03 11:26:39 -0400300 always @(posedge clk or negedge resetn) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400301 if (resetn == 1'b0) begin
302
Tim Edwards44bab472020-10-04 22:09:54 -0400303 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400304 xfer_count <= 4'd0;
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200305 pad_count <= `MPRJ_IO_PADS;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400306 serial_resetn <= 1'b0;
307 serial_clock <= 1'b0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400308
309 end else begin
310
Tim Edwards44bab472020-10-04 22:09:54 -0400311 if (xfer_state == `IDLE) begin
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200312 pad_count <= `MPRJ_IO_PADS;
Tim Edwards251e0df2020-10-05 11:02:12 -0400313 serial_resetn <= 1'b1;
Tim Edwards44bab472020-10-04 22:09:54 -0400314 serial_clock <= 1'b0;
315 if (xfer_ctrl == 1'b1) begin
316 xfer_state <= `START;
317 end
318 end else if (xfer_state == `START) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400319 serial_resetn <= 1'b1;
320 serial_clock <= 1'b0;
321 xfer_count <= 6'd0;
Tim Edwards251e0df2020-10-05 11:02:12 -0400322 pad_count <= pad_count - 1;
323 xfer_state <= `XBYTE;
324 serial_data_staging <= io_ctrl[pad_count - 1];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400325 end else if (xfer_state == `XBYTE) begin
326 serial_resetn <= 1'b1;
327 serial_clock <= ~serial_clock;
328 if (serial_clock == 1'b0) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400329 if (xfer_count == IO_CTRL_BITS - 1) begin
330 if (pad_count == 0) begin
331 xfer_state <= `LOAD;
332 end else begin
333 xfer_state <= `START;
334 end
Tim Edwards04ba17f2020-10-02 22:27:50 -0400335 end else begin
336 xfer_count <= xfer_count + 1;
337 end
338 end else begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400339 serial_data_staging <= {serial_data_staging[IO_CTRL_BITS-2:0], 1'b0};
Tim Edwards04ba17f2020-10-02 22:27:50 -0400340 end
341 end else if (xfer_state == `LOAD) begin
342 xfer_count <= xfer_count + 1;
343
344 /* Load sequence: Raise clock for final data shift in;
345 * Pulse reset low while clock is high
346 * Set clock back to zero.
347 * Return to idle mode.
348 */
349 if (xfer_count == 4'd0) begin
350 serial_clock <= 1'b1;
351 serial_resetn <= 1'b1;
352 end else if (xfer_count == 4'd1) begin
353 serial_clock <= 1'b1;
354 serial_resetn <= 1'b0;
355 end else if (xfer_count == 4'd2) begin
356 serial_clock <= 1'b1;
357 serial_resetn <= 1'b1;
358 end else if (xfer_count == 4'd3) begin
359 serial_resetn <= 1'b1;
360 serial_clock <= 1'b0;
Tim Edwards44bab472020-10-04 22:09:54 -0400361 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400362 end
363 end
364 end
365 end
366
367endmodule