Steve Kelly | 3ab5f03 | 2020-12-18 18:35:23 -0500 | [diff] [blame] | 1 | // 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 Venn | 08cd6eb | 2020-11-16 12:01:14 +0100 | [diff] [blame] | 16 | `default_nettype none |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 17 | module mprj_ctrl_wb #( |
Tim Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 18 | 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 Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 22 | parameter IOCONFIG = 8'h 20 |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 23 | )( |
| 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 Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 37 | // Output is to serial loader |
| 38 | output serial_clock, |
| 39 | output serial_resetn, |
| 40 | output serial_data_out, |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 41 | |
Tim Edwards | 496a08a | 2020-10-26 15:44:51 -0400 | [diff] [blame] | 42 | // 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 Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 47 | // Read/write data to each GPIO pad from management SoC |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 48 | input [`MPRJ_IO_PADS-1:0] mgmt_gpio_in, |
| 49 | output [`MPRJ_IO_PADS-1:0] mgmt_gpio_out, |
Tim Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 50 | |
| 51 | // Write data to power controls |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 52 | output [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 53 | ); |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 54 | 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 Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 67 | .XFER(XFER), |
Tim Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 68 | .PWRDATA(PWRDATA), |
| 69 | .IODATA(IODATA), |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 70 | .IOCONFIG(IOCONFIG) |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 71 | ) mprj_ctrl ( |
| 72 | .clk(wb_clk_i), |
| 73 | .resetn(resetn), |
| 74 | .iomem_addr(wb_adr_i), |
| 75 | .iomem_valid(valid), |
Tim Edwards | c18c474 | 2020-10-03 11:26:39 -0400 | [diff] [blame] | 76 | .iomem_wstrb(iomem_we[1:0]), |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 77 | .iomem_wdata(wb_dat_i), |
| 78 | .iomem_rdata(wb_dat_o), |
| 79 | .iomem_ready(ready), |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 80 | |
| 81 | .serial_clock(serial_clock), |
| 82 | .serial_resetn(serial_resetn), |
| 83 | .serial_data_out(serial_data_out), |
Tim Edwards | 496a08a | 2020-10-26 15:44:51 -0400 | [diff] [blame] | 84 | .sdo_oenb_state(sdo_oenb_state), |
| 85 | .jtag_oenb_state(jtag_oenb_state), |
Tim Edwards | 44bab47 | 2020-10-04 22:09:54 -0400 | [diff] [blame] | 86 | // .mgmt_gpio_io(mgmt_gpio_io) |
| 87 | .mgmt_gpio_in(mgmt_gpio_in), |
Tim Edwards | ca2f318 | 2020-10-06 10:05:11 -0400 | [diff] [blame] | 88 | .mgmt_gpio_out(mgmt_gpio_out) |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 89 | ); |
| 90 | |
| 91 | endmodule |
| 92 | |
| 93 | module mprj_ctrl #( |
Tim Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 94 | 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 Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 99 | parameter IO_CTRL_BITS = 13 |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 100 | )( |
| 101 | input clk, |
| 102 | input resetn, |
| 103 | |
| 104 | input [31:0] iomem_addr, |
| 105 | input iomem_valid, |
Tim Edwards | c18c474 | 2020-10-03 11:26:39 -0400 | [diff] [blame] | 106 | input [1:0] iomem_wstrb, |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 107 | input [31:0] iomem_wdata, |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 108 | output reg [31:0] iomem_rdata, |
| 109 | output reg iomem_ready, |
| 110 | |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 111 | output serial_clock, |
| 112 | output serial_resetn, |
| 113 | output serial_data_out, |
Tim Edwards | 496a08a | 2020-10-26 15:44:51 -0400 | [diff] [blame] | 114 | output sdo_oenb_state, |
| 115 | output jtag_oenb_state, |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 116 | input [`MPRJ_IO_PADS-1:0] mgmt_gpio_in, |
| 117 | output [`MPRJ_IO_PADS-1:0] mgmt_gpio_out |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 118 | ); |
Tim Edwards | c18c474 | 2020-10-03 11:26:39 -0400 | [diff] [blame] | 119 | |
Tim Edwards | 44bab47 | 2020-10-04 22:09:54 -0400 | [diff] [blame] | 120 | `define IDLE 2'b00 |
| 121 | `define START 2'b01 |
| 122 | `define XBYTE 2'b10 |
| 123 | `define LOAD 2'b11 |
Tim Edwards | c18c474 | 2020-10-03 11:26:39 -0400 | [diff] [blame] | 124 | |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 125 | localparam IO_WORDS = (`MPRJ_IO_PADS % 32 != 0) + (`MPRJ_IO_PADS / 32); |
Tim Edwards | 9eda80d | 2020-10-08 21:36:44 -0400 | [diff] [blame] | 126 | |
Tim Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 127 | localparam IO_BASE_ADR = (BASE_ADR | IOCONFIG); |
| 128 | |
Tim Edwards | 44bab47 | 2020-10-04 22:09:54 -0400 | [diff] [blame] | 129 | localparam OEB = 1; // Offset of output enable in shift register. |
| 130 | localparam INP_DIS = 3; // Offset of input disable in shift register. |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 131 | |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 132 | 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 Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 136 | reg xfer_ctrl; // Transfer control (1 bit) |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 137 | |
Tim Edwards | 9eda80d | 2020-10-08 21:36:44 -0400 | [diff] [blame] | 138 | wire [IO_WORDS-1:0] io_data_sel; // wishbone selects |
Tim Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 139 | wire pwr_data_sel; |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 140 | wire xfer_sel; |
Tim Edwards | d01c637 | 2020-10-28 13:40:03 -0400 | [diff] [blame] | 141 | wire busy; |
Tim Edwards | 581068f | 2020-11-19 12:45:25 -0500 | [diff] [blame] | 142 | wire selected; |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 143 | wire [`MPRJ_IO_PADS-1:0] io_ctrl_sel; |
Ahmed Ghazy | f46273f | 2020-10-31 23:48:35 +0200 | [diff] [blame] | 144 | reg [31:0] iomem_rdata_pre; |
Tim Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 145 | |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 146 | wire [`MPRJ_IO_PADS-1:0] mgmt_gpio_in; |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 147 | |
Tim Edwards | 496a08a | 2020-10-26 15:44:51 -0400 | [diff] [blame] | 148 | 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 Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 158 | `define wtop (((i+1)*32 > `MPRJ_IO_PADS) ? `MPRJ_IO_PADS-1 : (i+1)*32-1) |
Tim Edwards | 0445c08 | 2020-10-27 20:53:54 -0400 | [diff] [blame] | 159 | `define wbot (i*32) |
| 160 | `define rtop (`wtop - `wbot) |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 161 | |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 162 | genvar i; |
Tim Edwards | 9eda80d | 2020-10-08 21:36:44 -0400 | [diff] [blame] | 163 | |
Tim Edwards | 0445c08 | 2020-10-27 20:53:54 -0400 | [diff] [blame] | 164 | // 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 Edwards | 9eda80d | 2020-10-08 21:36:44 -0400 | [diff] [blame] | 169 | generate |
| 170 | for (i=0; i<IO_WORDS; i=i+1) begin |
Tim Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 171 | assign io_data_sel[i] = (iomem_addr[7:0] == (IODATA + i*4)); |
Tim Edwards | 9eda80d | 2020-10-08 21:36:44 -0400 | [diff] [blame] | 172 | end |
Tim Edwards | 9eda80d | 2020-10-08 21:36:44 -0400 | [diff] [blame] | 173 | |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 174 | for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 175 | assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4)); |
Tim Edwards | ca2f318 | 2020-10-06 10:05:11 -0400 | [diff] [blame] | 176 | assign mgmt_gpio_out[i] = (io_ctrl[i][INP_DIS] == 1'b1) ? |
| 177 | mgmt_gpio_outr[i] : 1'bz; |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 178 | end |
| 179 | endgenerate |
| 180 | |
Tim Edwards | 0445c08 | 2020-10-27 20:53:54 -0400 | [diff] [blame] | 181 | // Set selection and iomem_rdata_pre |
| 182 | |
| 183 | assign selected = xfer_sel || pwr_data_sel || (|io_data_sel) || (|io_ctrl_sel); |
| 184 | |
Ahmed Ghazy | f46273f | 2020-10-31 23:48:35 +0200 | [diff] [blame] | 185 | 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 Edwards | 0445c08 | 2020-10-27 20:53:54 -0400 | [diff] [blame] | 190 | |
Ahmed Ghazy | f46273f | 2020-10-31 23:48:35 +0200 | [diff] [blame] | 191 | 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 Edwards | 0445c08 | 2020-10-27 20:53:54 -0400 | [diff] [blame] | 195 | endgenerate |
| 196 | |
Ahmed Ghazy | f46273f | 2020-10-31 23:48:35 +0200 | [diff] [blame] | 197 | |
| 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 Edwards | 0445c08 | 2020-10-27 20:53:54 -0400 | [diff] [blame] | 220 | // 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 Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 239 | |
| 240 | always @(posedge clk) begin |
| 241 | if (!resetn) begin |
| 242 | xfer_ctrl <= 0; |
Tim Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 243 | pwr_ctrl_out <= 0; |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 244 | end else begin |
Tim Edwards | c18c474 | 2020-10-03 11:26:39 -0400 | [diff] [blame] | 245 | if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin |
Tim Edwards | 9eda80d | 2020-10-08 21:36:44 -0400 | [diff] [blame] | 246 | if (xfer_sel) begin |
Tim Edwards | 251e0df | 2020-10-05 11:02:12 -0400 | [diff] [blame] | 247 | if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[0]; |
Tim Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 248 | end else if (pwr_data_sel) begin |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 249 | if (iomem_wstrb[0]) pwr_ctrl_out <= iomem_wdata[`MPRJ_PWR_PADS-1:0]; |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 250 | end |
Tim Edwards | 251e0df | 2020-10-05 11:02:12 -0400 | [diff] [blame] | 251 | end else begin |
| 252 | xfer_ctrl <= 1'b0; // Immediately self-resetting |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 253 | end |
| 254 | end |
| 255 | end |
| 256 | |
Tim Edwards | 9eda80d | 2020-10-08 21:36:44 -0400 | [diff] [blame] | 257 | // I/O transfer of gpio data to/from user project region under management |
| 258 | // SoC control |
| 259 | |
Tim Edwards | 9eda80d | 2020-10-08 21:36:44 -0400 | [diff] [blame] | 260 | 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 Edwards | 9eda80d | 2020-10-08 21:36:44 -0400 | [diff] [blame] | 269 | 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 Edwards | 9eda80d | 2020-10-08 21:36:44 -0400 | [diff] [blame] | 277 | |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 278 | for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 279 | always @(posedge clk) begin |
| 280 | if (!resetn) begin |
Tim Edwards | 251e0df | 2020-10-05 11:02:12 -0400 | [diff] [blame] | 281 | // NOTE: This initialization must match the defaults passed |
Tim Edwards | 496a08a | 2020-10-26 15:44:51 -0400 | [diff] [blame] | 282 | // to the control blocks. Specifically, 0x1803 is for a |
Tim Edwards | 251e0df | 2020-10-05 11:02:12 -0400 | [diff] [blame] | 283 | // bidirectional pad, and 0x0403 is for a simple input pad |
| 284 | if (i < 2) begin |
Tim Edwards | 496a08a | 2020-10-26 15:44:51 -0400 | [diff] [blame] | 285 | io_ctrl[i] <= 'h1803; |
Tim Edwards | 251e0df | 2020-10-05 11:02:12 -0400 | [diff] [blame] | 286 | end else begin |
| 287 | io_ctrl[i] <= 'h0403; |
| 288 | end |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 289 | end else begin |
Tim Edwards | ba32890 | 2020-10-27 15:03:22 -0400 | [diff] [blame] | 290 | if (iomem_valid && !iomem_ready && |
| 291 | iomem_addr[31:8] == BASE_ADR[31:8]) begin |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 292 | if (io_ctrl_sel[i]) begin |
Tim Edwards | c18c474 | 2020-10-03 11:26:39 -0400 | [diff] [blame] | 293 | // NOTE: Byte-wide write to io_ctrl is prohibited |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 294 | if (iomem_wstrb[0]) |
Tim Edwards | c18c474 | 2020-10-03 11:26:39 -0400 | [diff] [blame] | 295 | io_ctrl[i] <= iomem_wdata[IO_CTRL_BITS-1:0]; |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 296 | end |
| 297 | end |
| 298 | end |
| 299 | end |
| 300 | end |
| 301 | endgenerate |
| 302 | |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 303 | 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 Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 308 | |
Tim Edwards | c18c474 | 2020-10-03 11:26:39 -0400 | [diff] [blame] | 309 | reg [IO_CTRL_BITS-1:0] serial_data_staging; |
| 310 | |
Tim Edwards | 251e0df | 2020-10-05 11:02:12 -0400 | [diff] [blame] | 311 | wire serial_data_out; |
Tim Edwards | 251e0df | 2020-10-05 11:02:12 -0400 | [diff] [blame] | 312 | |
| 313 | assign serial_data_out = serial_data_staging[IO_CTRL_BITS-1]; |
| 314 | assign busy = (xfer_state != `IDLE); |
| 315 | |
Tim Edwards | c18c474 | 2020-10-03 11:26:39 -0400 | [diff] [blame] | 316 | always @(posedge clk or negedge resetn) begin |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 317 | if (resetn == 1'b0) begin |
| 318 | |
Tim Edwards | 44bab47 | 2020-10-04 22:09:54 -0400 | [diff] [blame] | 319 | xfer_state <= `IDLE; |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 320 | xfer_count <= 4'd0; |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 321 | pad_count <= `MPRJ_IO_PADS; |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 322 | serial_resetn <= 1'b0; |
| 323 | serial_clock <= 1'b0; |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 324 | |
| 325 | end else begin |
| 326 | |
Tim Edwards | 44bab47 | 2020-10-04 22:09:54 -0400 | [diff] [blame] | 327 | if (xfer_state == `IDLE) begin |
Ahmed Ghazy | 22d29d6 | 2020-10-28 03:42:02 +0200 | [diff] [blame] | 328 | pad_count <= `MPRJ_IO_PADS; |
Tim Edwards | 251e0df | 2020-10-05 11:02:12 -0400 | [diff] [blame] | 329 | serial_resetn <= 1'b1; |
Tim Edwards | 44bab47 | 2020-10-04 22:09:54 -0400 | [diff] [blame] | 330 | 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 Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 335 | serial_resetn <= 1'b1; |
| 336 | serial_clock <= 1'b0; |
| 337 | xfer_count <= 6'd0; |
Tim Edwards | 251e0df | 2020-10-05 11:02:12 -0400 | [diff] [blame] | 338 | pad_count <= pad_count - 1; |
| 339 | xfer_state <= `XBYTE; |
| 340 | serial_data_staging <= io_ctrl[pad_count - 1]; |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 341 | 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 Edwards | 251e0df | 2020-10-05 11:02:12 -0400 | [diff] [blame] | 345 | 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 Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 351 | end else begin |
| 352 | xfer_count <= xfer_count + 1; |
| 353 | end |
| 354 | end else begin |
Tim Edwards | c18c474 | 2020-10-03 11:26:39 -0400 | [diff] [blame] | 355 | serial_data_staging <= {serial_data_staging[IO_CTRL_BITS-2:0], 1'b0}; |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 356 | 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 Edwards | 44bab47 | 2020-10-04 22:09:54 -0400 | [diff] [blame] | 377 | xfer_state <= `IDLE; |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame] | 378 | end |
| 379 | end |
| 380 | end |
| 381 | end |
| 382 | |
| 383 | endmodule |
Tim Edwards | 581068f | 2020-11-19 12:45:25 -0500 | [diff] [blame] | 384 | `default_nettype wire |