blob: d5c24bf9567b251d5223bf6f8dcca1ed1cfbf99d [file] [log] [blame]
Steve Kelly3ab5f032020-12-18 18:35:23 -05001// SPDX-FileCopyrightText: 2020 Efabless Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14// SPDX-License-Identifier: Apache-2.0
15
Matt Venn08cd6eb2020-11-16 12:01:14 +010016`default_nettype none
shalan0d14e6e2020-08-31 16:50:48 +020017module mprj_ctrl_wb #(
Tim Edwardsba328902020-10-27 15:03:22 -040018 parameter BASE_ADR = 32'h 2300_0000,
19 parameter XFER = 8'h 00,
20 parameter PWRDATA = 8'h 04,
21 parameter IODATA = 8'h 08, // One word per 32 IOs
Ahmed Ghazy22d29d62020-10-28 03:42:02 +020022 parameter IOCONFIG = 8'h 20
shalan0d14e6e2020-08-31 16:50:48 +020023)(
24 input wb_clk_i,
25 input wb_rst_i,
26
27 input [31:0] wb_dat_i,
28 input [31:0] wb_adr_i,
29 input [3:0] wb_sel_i,
30 input wb_cyc_i,
31 input wb_stb_i,
32 input wb_we_i,
33
34 output [31:0] wb_dat_o,
35 output wb_ack_o,
36
Tim Edwards04ba17f2020-10-02 22:27:50 -040037 // Output is to serial loader
38 output serial_clock,
39 output serial_resetn,
40 output serial_data_out,
shalan0d14e6e2020-08-31 16:50:48 +020041
Tim Edwards496a08a2020-10-26 15:44:51 -040042 // Pass state of OEB bit on SDO and JTAG back to the core
43 // so that the function can be overridden for management output
44 output sdo_oenb_state,
45 output jtag_oenb_state,
46
Tim Edwards04ba17f2020-10-02 22:27:50 -040047 // Read/write data to each GPIO pad from management SoC
Ahmed Ghazy22d29d62020-10-28 03:42:02 +020048 input [`MPRJ_IO_PADS-1:0] mgmt_gpio_in,
49 output [`MPRJ_IO_PADS-1:0] mgmt_gpio_out,
Tim Edwardsba328902020-10-27 15:03:22 -040050
51 // Write data to power controls
Ahmed Ghazy22d29d62020-10-28 03:42:02 +020052 output [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out
Tim Edwards04ba17f2020-10-02 22:27:50 -040053);
shalan0d14e6e2020-08-31 16:50:48 +020054 wire resetn;
55 wire valid;
56 wire ready;
57 wire [3:0] iomem_we;
58
59 assign resetn = ~wb_rst_i;
60 assign valid = wb_stb_i && wb_cyc_i;
61
62 assign iomem_we = wb_sel_i & {4{wb_we_i}};
63 assign wb_ack_o = ready;
64
65 mprj_ctrl #(
66 .BASE_ADR(BASE_ADR),
Tim Edwards04ba17f2020-10-02 22:27:50 -040067 .XFER(XFER),
Tim Edwardsba328902020-10-27 15:03:22 -040068 .PWRDATA(PWRDATA),
69 .IODATA(IODATA),
Ahmed Ghazy22d29d62020-10-28 03:42:02 +020070 .IOCONFIG(IOCONFIG)
shalan0d14e6e2020-08-31 16:50:48 +020071 ) mprj_ctrl (
72 .clk(wb_clk_i),
73 .resetn(resetn),
74 .iomem_addr(wb_adr_i),
75 .iomem_valid(valid),
Tim Edwardsc18c4742020-10-03 11:26:39 -040076 .iomem_wstrb(iomem_we[1:0]),
shalan0d14e6e2020-08-31 16:50:48 +020077 .iomem_wdata(wb_dat_i),
78 .iomem_rdata(wb_dat_o),
79 .iomem_ready(ready),
Tim Edwards04ba17f2020-10-02 22:27:50 -040080
81 .serial_clock(serial_clock),
82 .serial_resetn(serial_resetn),
83 .serial_data_out(serial_data_out),
Tim Edwards496a08a2020-10-26 15:44:51 -040084 .sdo_oenb_state(sdo_oenb_state),
85 .jtag_oenb_state(jtag_oenb_state),
Tim Edwards44bab472020-10-04 22:09:54 -040086 // .mgmt_gpio_io(mgmt_gpio_io)
87 .mgmt_gpio_in(mgmt_gpio_in),
Tim Edwardsca2f3182020-10-06 10:05:11 -040088 .mgmt_gpio_out(mgmt_gpio_out)
shalan0d14e6e2020-08-31 16:50:48 +020089 );
90
91endmodule
92
93module mprj_ctrl #(
Tim Edwardsba328902020-10-27 15:03:22 -040094 parameter BASE_ADR = 32'h 2300_0000,
95 parameter XFER = 8'h 00,
96 parameter PWRDATA = 8'h 04,
97 parameter IODATA = 8'h 08,
98 parameter IOCONFIG = 8'h 20,
Tim Edwardsba328902020-10-27 15:03:22 -040099 parameter IO_CTRL_BITS = 13
shalan0d14e6e2020-08-31 16:50:48 +0200100)(
101 input clk,
102 input resetn,
103
104 input [31:0] iomem_addr,
105 input iomem_valid,
Tim Edwardsc18c4742020-10-03 11:26:39 -0400106 input [1:0] iomem_wstrb,
shalan0d14e6e2020-08-31 16:50:48 +0200107 input [31:0] iomem_wdata,
shalan0d14e6e2020-08-31 16:50:48 +0200108 output reg [31:0] iomem_rdata,
109 output reg iomem_ready,
110
Tim Edwards04ba17f2020-10-02 22:27:50 -0400111 output serial_clock,
112 output serial_resetn,
113 output serial_data_out,
Tim Edwards496a08a2020-10-26 15:44:51 -0400114 output sdo_oenb_state,
115 output jtag_oenb_state,
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200116 input [`MPRJ_IO_PADS-1:0] mgmt_gpio_in,
117 output [`MPRJ_IO_PADS-1:0] mgmt_gpio_out
shalan0d14e6e2020-08-31 16:50:48 +0200118);
Tim Edwardsc18c4742020-10-03 11:26:39 -0400119
Tim Edwards44bab472020-10-04 22:09:54 -0400120`define IDLE 2'b00
121`define START 2'b01
122`define XBYTE 2'b10
123`define LOAD 2'b11
Tim Edwardsc18c4742020-10-03 11:26:39 -0400124
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200125 localparam IO_WORDS = (`MPRJ_IO_PADS % 32 != 0) + (`MPRJ_IO_PADS / 32);
Tim Edwards9eda80d2020-10-08 21:36:44 -0400126
Tim Edwardsba328902020-10-27 15:03:22 -0400127 localparam IO_BASE_ADR = (BASE_ADR | IOCONFIG);
128
Tim Edwards44bab472020-10-04 22:09:54 -0400129 localparam OEB = 1; // Offset of output enable in shift register.
130 localparam INP_DIS = 3; // Offset of input disable in shift register.
shalan0d14e6e2020-08-31 16:50:48 +0200131
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200132 reg [IO_CTRL_BITS-1:0] io_ctrl[`MPRJ_IO_PADS-1:0]; // I/O control, 1 word per gpio pad
133 reg [`MPRJ_IO_PADS-1:0] mgmt_gpio_outr; // I/O write data, 1 bit per gpio pad
134 wire [`MPRJ_IO_PADS-1:0] mgmt_gpio_out; // I/O write data output when input disabled
135 reg [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out; // Power write data, 1 bit per power pad
Tim Edwardsba328902020-10-27 15:03:22 -0400136 reg xfer_ctrl; // Transfer control (1 bit)
shalan0d14e6e2020-08-31 16:50:48 +0200137
Tim Edwards9eda80d2020-10-08 21:36:44 -0400138 wire [IO_WORDS-1:0] io_data_sel; // wishbone selects
Tim Edwardsba328902020-10-27 15:03:22 -0400139 wire pwr_data_sel;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400140 wire xfer_sel;
Tim Edwardsd01c6372020-10-28 13:40:03 -0400141 wire busy;
Tim Edwards581068f2020-11-19 12:45:25 -0500142 wire selected;
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200143 wire [`MPRJ_IO_PADS-1:0] io_ctrl_sel;
Ahmed Ghazyf46273f2020-10-31 23:48:35 +0200144 reg [31:0] iomem_rdata_pre;
Tim Edwardsba328902020-10-27 15:03:22 -0400145
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200146 wire [`MPRJ_IO_PADS-1:0] mgmt_gpio_in;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400147
Tim Edwards496a08a2020-10-26 15:44:51 -0400148 wire sdo_oenb_state, jtag_oenb_state;
149
150 // JTAG and housekeeping SDO are normally controlled by their respective
151 // modules with OEB set to the default 1 value. If configured for an
152 // additional output by setting the OEB bit low, then pass this information
153 // back to the core so that the default signals can be overridden.
154
155 assign jtag_oenb_state = io_ctrl[0][OEB];
156 assign sdo_oenb_state = io_ctrl[1][OEB];
157
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200158 `define wtop (((i+1)*32 > `MPRJ_IO_PADS) ? `MPRJ_IO_PADS-1 : (i+1)*32-1)
Tim Edwards0445c082020-10-27 20:53:54 -0400159 `define wbot (i*32)
160 `define rtop (`wtop - `wbot)
Tim Edwards04ba17f2020-10-02 22:27:50 -0400161
shalan0d14e6e2020-08-31 16:50:48 +0200162 genvar i;
Tim Edwards9eda80d2020-10-08 21:36:44 -0400163
Tim Edwards0445c082020-10-27 20:53:54 -0400164 // Assign selection bits per address
165
166 assign xfer_sel = (iomem_addr[7:0] == XFER);
167 assign pwr_data_sel = (iomem_addr[7:0] == PWRDATA);
168
Tim Edwards9eda80d2020-10-08 21:36:44 -0400169 generate
170 for (i=0; i<IO_WORDS; i=i+1) begin
Tim Edwardsba328902020-10-27 15:03:22 -0400171 assign io_data_sel[i] = (iomem_addr[7:0] == (IODATA + i*4));
Tim Edwards9eda80d2020-10-08 21:36:44 -0400172 end
Tim Edwards9eda80d2020-10-08 21:36:44 -0400173
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200174 for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400175 assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4));
Tim Edwardsca2f3182020-10-06 10:05:11 -0400176 assign mgmt_gpio_out[i] = (io_ctrl[i][INP_DIS] == 1'b1) ?
177 mgmt_gpio_outr[i] : 1'bz;
shalan0d14e6e2020-08-31 16:50:48 +0200178 end
179 endgenerate
180
Tim Edwards0445c082020-10-27 20:53:54 -0400181 // Set selection and iomem_rdata_pre
182
183 assign selected = xfer_sel || pwr_data_sel || (|io_data_sel) || (|io_ctrl_sel);
184
Ahmed Ghazyf46273f2020-10-31 23:48:35 +0200185 wire [31:0] io_data_arr[0:IO_WORDS-1];
186 wire [31:0] io_ctrl_arr[0:`MPRJ_IO_PADS-1];
187 generate
188 for (i=0; i<IO_WORDS; i=i+1) begin
189 assign io_data_arr[i] = {{(31-`rtop){1'b0}}, mgmt_gpio_in[`wtop:`wbot]};
Tim Edwards0445c082020-10-27 20:53:54 -0400190
Ahmed Ghazyf46273f2020-10-31 23:48:35 +0200191 end
192 for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
193 assign io_ctrl_arr[i] = {{(32-IO_CTRL_BITS){1'b0}}, io_ctrl[i]};
194 end
Tim Edwards0445c082020-10-27 20:53:54 -0400195 endgenerate
196
Ahmed Ghazyf46273f2020-10-31 23:48:35 +0200197
198 integer j;
199 always @ * begin
200 iomem_rdata_pre = 'b0;
201 if (xfer_sel) begin
202 iomem_rdata_pre = {31'b0, busy};
203 end else if (pwr_data_sel) begin
204 iomem_rdata_pre = {{(32-`MPRJ_PWR_PADS){1'b0}}, pwr_ctrl_out};
205 end else if (|io_data_sel) begin
206 for (j=0; j<IO_WORDS; j=j+1) begin
207 if (io_data_sel[j]) begin
208 iomem_rdata_pre = io_data_arr[j];
209 end
210 end
211 end else begin
212 for (j=0; j<`MPRJ_IO_PADS; j=j+1) begin
213 if (io_ctrl_sel[j]) begin
214 iomem_rdata_pre = io_ctrl_arr[j];
215 end
216 end
217 end
218 end
219
Tim Edwards0445c082020-10-27 20:53:54 -0400220 // General I/O transfer
221
222 always @(posedge clk) begin
223 if (!resetn) begin
224 iomem_rdata <= 0;
225 iomem_ready <= 0;
226 end else begin
227 iomem_ready <= 0;
228 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
229 iomem_ready <= 1'b 1;
230
231 if (selected) begin
232 iomem_rdata <= iomem_rdata_pre;
233 end
234 end
235 end
236 end
237
238 // I/O write of xfer bit. Also handles iomem_ready signal and power data.
Tim Edwards04ba17f2020-10-02 22:27:50 -0400239
240 always @(posedge clk) begin
241 if (!resetn) begin
242 xfer_ctrl <= 0;
Tim Edwardsba328902020-10-27 15:03:22 -0400243 pwr_ctrl_out <= 0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400244 end else begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400245 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
Tim Edwards9eda80d2020-10-08 21:36:44 -0400246 if (xfer_sel) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400247 if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[0];
Tim Edwardsba328902020-10-27 15:03:22 -0400248 end else if (pwr_data_sel) begin
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200249 if (iomem_wstrb[0]) pwr_ctrl_out <= iomem_wdata[`MPRJ_PWR_PADS-1:0];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400250 end
Tim Edwards251e0df2020-10-05 11:02:12 -0400251 end else begin
252 xfer_ctrl <= 1'b0; // Immediately self-resetting
Tim Edwards04ba17f2020-10-02 22:27:50 -0400253 end
254 end
255 end
256
Tim Edwards9eda80d2020-10-08 21:36:44 -0400257 // I/O transfer of gpio data to/from user project region under management
258 // SoC control
259
Tim Edwards9eda80d2020-10-08 21:36:44 -0400260 generate
261 for (i=0; i<IO_WORDS; i=i+1) begin
262 always @(posedge clk) begin
263 if (!resetn) begin
264 mgmt_gpio_outr[`wtop:`wbot] <= 'd0;
265 end else begin
266 if (iomem_valid && !iomem_ready && iomem_addr[31:8] ==
267 BASE_ADR[31:8]) begin
268 if (io_data_sel[i]) begin
Tim Edwards9eda80d2020-10-08 21:36:44 -0400269 if (iomem_wstrb[0]) begin
270 mgmt_gpio_outr[`wtop:`wbot] <= iomem_wdata[`rtop:0];
271 end
272 end
273 end
274 end
275 end
276 end
Tim Edwards9eda80d2020-10-08 21:36:44 -0400277
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200278 for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
shalan0d14e6e2020-08-31 16:50:48 +0200279 always @(posedge clk) begin
280 if (!resetn) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400281 // NOTE: This initialization must match the defaults passed
Tim Edwards496a08a2020-10-26 15:44:51 -0400282 // to the control blocks. Specifically, 0x1803 is for a
Tim Edwards251e0df2020-10-05 11:02:12 -0400283 // bidirectional pad, and 0x0403 is for a simple input pad
284 if (i < 2) begin
Tim Edwards496a08a2020-10-26 15:44:51 -0400285 io_ctrl[i] <= 'h1803;
Tim Edwards251e0df2020-10-05 11:02:12 -0400286 end else begin
287 io_ctrl[i] <= 'h0403;
288 end
shalan0d14e6e2020-08-31 16:50:48 +0200289 end else begin
Tim Edwardsba328902020-10-27 15:03:22 -0400290 if (iomem_valid && !iomem_ready &&
291 iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200292 if (io_ctrl_sel[i]) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400293 // NOTE: Byte-wide write to io_ctrl is prohibited
shalan0d14e6e2020-08-31 16:50:48 +0200294 if (iomem_wstrb[0])
Tim Edwardsc18c4742020-10-03 11:26:39 -0400295 io_ctrl[i] <= iomem_wdata[IO_CTRL_BITS-1:0];
shalan0d14e6e2020-08-31 16:50:48 +0200296 end
297 end
298 end
299 end
300 end
301 endgenerate
302
Tim Edwards04ba17f2020-10-02 22:27:50 -0400303 reg [3:0] xfer_count;
304 reg [5:0] pad_count;
305 reg [1:0] xfer_state;
306 reg serial_clock;
307 reg serial_resetn;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400308
Tim Edwardsc18c4742020-10-03 11:26:39 -0400309 reg [IO_CTRL_BITS-1:0] serial_data_staging;
310
Tim Edwards251e0df2020-10-05 11:02:12 -0400311 wire serial_data_out;
Tim Edwards251e0df2020-10-05 11:02:12 -0400312
313 assign serial_data_out = serial_data_staging[IO_CTRL_BITS-1];
314 assign busy = (xfer_state != `IDLE);
315
Tim Edwardsc18c4742020-10-03 11:26:39 -0400316 always @(posedge clk or negedge resetn) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400317 if (resetn == 1'b0) begin
318
Tim Edwards44bab472020-10-04 22:09:54 -0400319 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400320 xfer_count <= 4'd0;
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200321 pad_count <= `MPRJ_IO_PADS;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400322 serial_resetn <= 1'b0;
323 serial_clock <= 1'b0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400324
325 end else begin
326
Tim Edwards44bab472020-10-04 22:09:54 -0400327 if (xfer_state == `IDLE) begin
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200328 pad_count <= `MPRJ_IO_PADS;
Tim Edwards251e0df2020-10-05 11:02:12 -0400329 serial_resetn <= 1'b1;
Tim Edwards44bab472020-10-04 22:09:54 -0400330 serial_clock <= 1'b0;
331 if (xfer_ctrl == 1'b1) begin
332 xfer_state <= `START;
333 end
334 end else if (xfer_state == `START) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400335 serial_resetn <= 1'b1;
336 serial_clock <= 1'b0;
337 xfer_count <= 6'd0;
Tim Edwards251e0df2020-10-05 11:02:12 -0400338 pad_count <= pad_count - 1;
339 xfer_state <= `XBYTE;
340 serial_data_staging <= io_ctrl[pad_count - 1];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400341 end else if (xfer_state == `XBYTE) begin
342 serial_resetn <= 1'b1;
343 serial_clock <= ~serial_clock;
344 if (serial_clock == 1'b0) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400345 if (xfer_count == IO_CTRL_BITS - 1) begin
346 if (pad_count == 0) begin
347 xfer_state <= `LOAD;
348 end else begin
349 xfer_state <= `START;
350 end
Tim Edwards04ba17f2020-10-02 22:27:50 -0400351 end else begin
352 xfer_count <= xfer_count + 1;
353 end
354 end else begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400355 serial_data_staging <= {serial_data_staging[IO_CTRL_BITS-2:0], 1'b0};
Tim Edwards04ba17f2020-10-02 22:27:50 -0400356 end
357 end else if (xfer_state == `LOAD) begin
358 xfer_count <= xfer_count + 1;
359
360 /* Load sequence: Raise clock for final data shift in;
361 * Pulse reset low while clock is high
362 * Set clock back to zero.
363 * Return to idle mode.
364 */
365 if (xfer_count == 4'd0) begin
366 serial_clock <= 1'b1;
367 serial_resetn <= 1'b1;
368 end else if (xfer_count == 4'd1) begin
369 serial_clock <= 1'b1;
370 serial_resetn <= 1'b0;
371 end else if (xfer_count == 4'd2) begin
372 serial_clock <= 1'b1;
373 serial_resetn <= 1'b1;
374 end else if (xfer_count == 4'd3) begin
375 serial_resetn <= 1'b1;
376 serial_clock <= 1'b0;
Tim Edwards44bab472020-10-04 22:09:54 -0400377 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400378 end
379 end
380 end
381 end
382
383endmodule
Tim Edwards581068f2020-11-19 12:45:25 -0500384`default_nettype wire