Serial chain loading of the I/O configurations is now working.
diff --git a/verilog/dv/caravel/mgmt_soc/gpio/gpio.c b/verilog/dv/caravel/mgmt_soc/gpio/gpio.c index bd6a17c..9053551 100644 --- a/verilog/dv/caravel/mgmt_soc/gpio/gpio.c +++ b/verilog/dv/caravel/mgmt_soc/gpio/gpio.c
@@ -37,7 +37,7 @@ /* Apply configuration */ reg_mprj_xfer = 1; - reg_mprj_xfer = 0; + while (reg_mprj_xfer == 1); // change the pull up and pull down (checked by the TB) reg_mprj_data = 0xa0000000; @@ -54,7 +54,7 @@ /* Apply configuration */ reg_mprj_xfer = 1; - reg_mprj_xfer = 0; + while (reg_mprj_xfer == 1); reg_mprj_data = 0x0b000000; @@ -70,7 +70,7 @@ /* Apply configuration */ reg_mprj_xfer = 1; - reg_mprj_xfer = 0; + while (reg_mprj_xfer == 1); reg_mprj_io_23 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; @@ -84,9 +84,9 @@ /* Apply configuration */ reg_mprj_xfer = 1; - reg_mprj_xfer = 0; + while (reg_mprj_xfer == 1); - // read the lower 8 pins, add 1 then o/p the result + // read the lower 8 pins, add 1 then output the result // checked by the TB reg_mprj_data = 0xab000000;
diff --git a/verilog/dv/caravel/mgmt_soc/gpio/gpio.hex b/verilog/dv/caravel/mgmt_soc/gpio/gpio.hex deleted file mode 100755 index adcdbdd..0000000 --- a/verilog/dv/caravel/mgmt_soc/gpio/gpio.hex +++ /dev/null
@@ -1,71 +0,0 @@ -@00000000 -93 00 00 00 93 01 00 00 13 02 00 00 93 02 00 00 -13 03 00 00 93 03 00 00 13 04 00 00 93 04 00 00 -13 05 00 00 93 05 00 00 13 06 00 00 93 06 00 00 -13 07 00 00 93 07 00 00 13 08 00 00 93 08 00 00 -13 09 00 00 93 09 00 00 13 0A 00 00 93 0A 00 00 -13 0B 00 00 93 0B 00 00 13 0C 00 00 93 0C 00 00 -13 0D 00 00 93 0D 00 00 13 0E 00 00 93 0E 00 00 -13 0F 00 00 93 0F 00 00 17 05 00 00 13 05 45 3E -93 05 00 00 13 06 00 00 63 D8 C5 00 14 41 94 C1 -11 05 91 05 E3 CC C5 FE 13 05 00 00 93 05 00 00 -63 57 B5 00 23 20 05 00 11 05 E3 4D B5 FE 71 28 -01 A0 01 00 B7 02 00 28 13 03 00 12 23 90 62 00 -A3 81 02 00 05 C6 21 4F 93 73 F6 0F 93 DE 73 00 -23 80 D2 01 93 EE 0E 01 23 80 D2 01 86 03 93 F3 -F3 0F 7D 1F E3 14 0F FE 23 80 62 00 A1 C9 13 0F -00 02 83 23 05 00 A1 4F 93 DE F3 01 23 80 D2 01 -93 EE 0E 01 23 80 D2 01 83 CE 02 00 93 FE 2E 00 -93 DE 1E 00 86 03 B3 E3 D3 01 7D 1F 63 17 0F 00 -23 20 75 00 11 05 83 23 05 00 FD 1F E3 96 0F FC -FD 15 F1 F1 63 04 0F 00 23 20 75 00 13 03 00 08 -A3 81 62 00 82 80 01 00 00 00 01 11 22 CE 00 10 -B7 07 00 23 23 A0 07 00 B7 07 00 23 93 87 47 08 -09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 07 08 -09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 C7 07 -09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 87 07 -09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 47 07 -09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 07 07 -09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 C7 06 -09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 87 06 -09 67 13 07 17 80 98 C3 B7 07 00 23 93 87 47 06 -13 07 30 40 98 C3 B7 07 00 23 93 87 07 06 13 07 -30 40 98 C3 B7 07 00 23 93 87 C7 05 13 07 30 40 -98 C3 B7 07 00 23 93 87 87 05 13 07 30 40 98 C3 -B7 07 00 23 93 87 47 05 13 07 30 40 98 C3 B7 07 -00 23 93 87 07 05 13 07 30 40 98 C3 B7 07 00 23 -93 87 C7 04 13 07 30 40 98 C3 B7 07 00 23 93 87 -87 04 13 07 30 40 98 C3 B7 07 00 23 91 07 05 47 -98 C3 B7 07 00 23 91 07 23 A0 07 00 B7 07 00 23 -37 07 00 A0 98 C3 B7 07 00 23 93 87 47 06 05 67 -13 07 37 80 98 C3 B7 07 00 23 93 87 07 06 05 67 -13 07 37 80 98 C3 B7 07 00 23 93 87 C7 05 05 67 -13 07 37 80 98 C3 B7 07 00 23 93 87 87 05 05 67 -13 07 37 80 98 C3 B7 07 00 23 93 87 47 05 05 67 -13 07 37 C0 98 C3 B7 07 00 23 93 87 07 05 05 67 -13 07 37 C0 98 C3 B7 07 00 23 93 87 C7 04 05 67 -13 07 37 C0 98 C3 B7 07 00 23 93 87 87 04 05 67 -13 07 37 C0 98 C3 B7 07 00 23 91 07 05 47 98 C3 -B7 07 00 23 91 07 23 A0 07 00 B7 07 00 23 37 07 -00 0B 98 C3 B7 07 00 23 93 87 47 06 05 67 13 07 -37 C0 98 C3 B7 07 00 23 93 87 07 06 05 67 13 07 -37 C0 98 C3 B7 07 00 23 93 87 C7 05 05 67 13 07 -37 C0 98 C3 B7 07 00 23 93 87 87 05 05 67 13 07 -37 C0 98 C3 B7 07 00 23 93 87 47 05 05 67 13 07 -37 80 98 C3 B7 07 00 23 93 87 07 05 05 67 13 07 -37 80 98 C3 B7 07 00 23 93 87 C7 04 05 67 13 07 -37 80 98 C3 B7 07 00 23 93 87 87 04 05 67 13 07 -37 80 98 C3 B7 07 00 23 91 07 05 47 98 C3 B7 07 -00 23 91 07 23 A0 07 00 B7 07 00 23 93 87 47 06 -05 67 13 07 37 80 98 C3 B7 07 00 23 93 87 07 06 -05 67 13 07 37 80 98 C3 B7 07 00 23 93 87 C7 05 -05 67 13 07 37 80 98 C3 B7 07 00 23 93 87 87 05 -05 67 13 07 37 80 98 C3 B7 07 00 23 93 87 47 05 -05 67 13 07 37 C0 98 C3 B7 07 00 23 93 87 07 05 -05 67 13 07 37 C0 98 C3 B7 07 00 23 93 87 C7 04 -05 67 13 07 37 C0 98 C3 B7 07 00 23 93 87 87 04 -05 67 13 07 37 C0 98 C3 B7 07 00 23 91 07 05 47 -98 C3 B7 07 00 23 91 07 23 A0 07 00 B7 07 00 23 -37 07 00 AB 98 C3 B7 07 00 23 9C 43 3E 87 B7 07 -FF 00 F9 8F 23 26 F4 FE 83 27 C4 FE 85 07 13 97 -87 01 B7 07 00 23 98 C3 F9 BF 00 00
diff --git a/verilog/rtl/caravel.v b/verilog/rtl/caravel.v index 492712e..cdefe74 100644 --- a/verilog/rtl/caravel.v +++ b/verilog/rtl/caravel.v
@@ -47,7 +47,6 @@ `include "chip_io.v" `include "user_id_programming.v" `include "gpio_control_block.v" -`include "gpio_control_block2.v" `ifdef USE_OPENRAM `include "sram_1rw1r_32_8192_8_sky130.v" @@ -368,16 +367,15 @@ wire [`MPRJ_IO_PADS-1:0] gpio_serial_link_shifted; - assign gpio_serial_link_shifted = {mprj_io_loader_data, gpio_serial_link[`MPRJ_IO_PADS-1:1]}; + assign gpio_serial_link_shifted = {gpio_serial_link[`MPRJ_IO_PADS-2:0], mprj_io_loader_data}; - // NOTE: The intention is to replace most of gpio_control_block2 - // (3 management wires per pad) with gpio_control_block (1 management - // wire per pad). However, the inout line on gpio_control_block is - // troublesome and so I am starting with the simpler interface. Ultimately - // the JTAG and SDO lines will keep the 3-pin interface and these pads will - // be located closest to the management area. + // Each control block sits next to an I/O pad in the user area. + // It gets input through a serial chain from the previous control + // block and passes it to the next control block. Due to the nature + // of the shift register, bits are presented in reverse, as the first + // bit in ends up as the last bit of the last I/O pad control block. - gpio_control_block2 #( + gpio_control_block #( .DM_INIT(3'b010), // Test: All pads set to pull-up .OENB_INIT(1'b0) // Test: All pads set to pull-up ) gpio_control_inst [`MPRJ_IO_PADS-1:0] ( @@ -387,7 +385,7 @@ .resetn(mprj_io_loader_resetn), .serial_clock(mprj_io_loader_clock), - .mgmt_gpio_in(mgmt_io_in), // For gpio_control_block2 only + .mgmt_gpio_in(mgmt_io_in), .mgmt_gpio_out({mgmt_io_in[(`MPRJ_IO_PADS-1):2], sdo_out, jtag_out}), .mgmt_gpio_oeb({{(`MPRJ_IO_PADS-2){1'b1}}, sdo_outenb, jtag_outenb}),
diff --git a/verilog/rtl/gpio_control_block.v b/verilog/rtl/gpio_control_block.v index 2325b39..5d3adb1 100644 --- a/verilog/rtl/gpio_control_block.v +++ b/verilog/rtl/gpio_control_block.v
@@ -1,17 +1,13 @@ /* *--------------------------------------------------------------------- - * This block interfaces between the sky130_fd_io GPIOv2 pad, the - * caravel management area, and the user project area. - * - * The management area has ultimate control over the setting of the - * pad, and can modify all core-voltage inputs to the pad and monitor - * the output. - * - * The user project will rely on the management SoC startup program - * to configure each I/O pad to a fixed configuration except for - * the output enable which remains under user control. - * - * This module is bit-sliced. Instantiate once for each GPIO pad. + * See gpio_control_block for description. This module is like + * gpio_contro_block except that it has an additional two management- + * Soc-facing pins, which are the out_enb line and the output line. + * If the chip is configured for output with the oeb control + * register = 1, then the oeb line is controlled by the additional + * signal from the management SoC. If the oeb control register = 0, + * then the output is disabled completely. The "io" line is input + * only in this module. * *--------------------------------------------------------------------- */ @@ -51,7 +47,9 @@ input resetn, // Global reset input serial_clock, - inout mgmt_gpio_io, // Management to/from pad + output mgmt_gpio_in, // Management from pad (input only) + input mgmt_gpio_out, // Management to pad (output only) + input mgmt_gpio_oeb, // Management to pad (output only) // Serial data chain for pad configuration input serial_data_in, @@ -72,7 +70,7 @@ output pad_gpio_ana_sel, output pad_gpio_ana_pol, output [2:0] pad_gpio_dm, - output pad_gpio_oeb, + output pad_gpio_outenb, output pad_gpio_out, input pad_gpio_in ); @@ -81,7 +79,7 @@ localparam MGMT_EN = 0; localparam OEB = 1; localparam HLDH = 2; - localparam INP_DIS = 2; + localparam INP_DIS = 3; localparam MOD_SEL = 4; localparam AN_EN = 5; localparam AN_SEL = 6; @@ -148,7 +146,7 @@ gpio_vtrip_sel <= TRIP_INIT; // CMOS mode gpio_ib_mode_sel <= IB_INIT; // CMOS mode gpio_inenb <= IENB_INIT; // Input enabled - gpio_outenb <= OENB_INIT; // Output disabled + gpio_outenb <= OENB_INIT; // (unused placeholder) gpio_dm <= DM_INIT; // Configured as input only gpio_ana_en <= AENA_INIT; // Digital enabled gpio_ana_sel <= ASEL_INIT; // Don't-care when gpio_ana_en = 0 @@ -185,34 +183,10 @@ /* Implement pad control behavior depending on state of mgmt_ena */ - /* If pad is configured for input and dm[2:1] is 01, then pad is */ - /* configured as pull-up or pull-down depending on dm[0], and to */ - /* set the pullup or pulldown condition, the pad output bit must */ - /* be set to the opposite state of dm[0]. */ - /* dm[0] = 0 is pull-down; dm[0] = 1 is pull-up. */ - /* */ - /* This is done for management control only, since the management */ - /* control has only 1 inout signal for both input and output, and */ - /* cannot set the output and read the input simultaneously. The */ - /* user has control over both lines and only needs to be told what */ - /* to set the output line to, to enable a pullup or pulldown. */ + assign pad_gpio_out = (mgmt_ena) ? mgmt_gpio_out : user_gpio_out; + assign pad_gpio_outenb = (mgmt_ena) ? mgmt_gpio_oeb : user_gpio_oeb; - assign pad_gpio_out = (mgmt_ena) ? - (((gpio_dm[2:1] == 2'b01) && (gpio_inenb == 1'b0)) ? - ~gpio_dm[0] : mgmt_gpio_io) : user_gpio_out; - - /* When under user control, gpio_outenb = 1 means that the pad is */ - /* configured as input, and the user outenb is unused. Otherwise, */ - /* the pad outenb signal is controlled by the user. */ - - assign pad_gpio_outenb = (mgmt_ena) ? gpio_outenb : - ((gpio_outenb == 1) ? 1'b1 : user_gpio_oeb); - - /* User gpio_in is grounded when the management controls the pad */ - assign user_gpio_in = (mgmt_ena) ? 1'b0 : pad_gpio_in; - - /* Management I/O line is set from the pad when the pad is */ - /* configured for input. */ - assign mgmt_gpio_io = (gpio_inenb == 0) ? pad_gpio_in : 1'bz; + assign user_gpio_in = (mgmt_ena) ? 1'b0 : pad_gpio_in; + assign mgmt_gpio_in = (mgmt_ena) ? pad_gpio_in : 1'b0; endmodule
diff --git a/verilog/rtl/gpio_control_block2.v b/verilog/rtl/gpio_control_block2.v deleted file mode 100644 index b28a02e..0000000 --- a/verilog/rtl/gpio_control_block2.v +++ /dev/null
@@ -1,193 +0,0 @@ -/* - *--------------------------------------------------------------------- - * See gpio_control_block for description. This module is like - * gpio_contro_block except that it has an additional two management- - * Soc-facing pins, which are the out_enb line and the output line. - * If the chip is configured for output with the oeb control - * register = 1, then the oeb line is controlled by the additional - * signal from the management SoC. If the oeb control register = 0, - * then the output is disabled completely. The "io" line is input - * only in this module. - * - *--------------------------------------------------------------------- - */ - -/* - *--------------------------------------------------------------------- - * - * This module instantiates a shift register chain that passes through - * each gpio cell. These are connected end-to-end around the padframe - * periphery. The purpose is to avoid a massive number of control - * wires between the digital core and I/O, passing through the user area. - * - * See mprj_ctrl.v for the module that registers the data for each - * I/O and drives the input to the shift register. - * - *--------------------------------------------------------------------- - */ - -module gpio_control_block2 #( - parameter PAD_CTRL_BITS = 13, - // Parameterized initial startup state of the pad. - // The default parameters if unspecified is for the pad to be - // an input with no pull-up or pull-down, so that it is disconnected - // from the outside world. - parameter HOLD_INIT = 1'b0, - parameter SLOW_INIT = 1'b0, - parameter TRIP_INIT = 1'b0, - parameter IB_INIT = 1'b0, - parameter IENB_INIT = 1'b0, - parameter OENB_INIT = 1'b1, - parameter DM_INIT = 3'b001, - parameter AENA_INIT = 1'b0, - parameter ASEL_INIT = 1'b0, - parameter APOL_INIT = 1'b0 -) ( - // Management Soc-facing signals - input resetn, // Global reset - input serial_clock, - - output mgmt_gpio_in, // Management from pad (input only) - input mgmt_gpio_out, // Management to pad (output only) - input mgmt_gpio_oeb, // Management to pad (output only) - - // Serial data chain for pad configuration - input serial_data_in, - output serial_data_out, - - // User-facing signals - input user_gpio_out, // User space to pad - input user_gpio_oeb, // Output enable (user) - output user_gpio_in, // Pad to user space - - // Pad-facing signals (Pad GPIOv2) - output pad_gpio_holdover, - output pad_gpio_slow_sel, - output pad_gpio_vtrip_sel, - output pad_gpio_inenb, - output pad_gpio_ib_mode_sel, - output pad_gpio_ana_en, - output pad_gpio_ana_sel, - output pad_gpio_ana_pol, - output [2:0] pad_gpio_dm, - output pad_gpio_outenb, - output pad_gpio_out, - input pad_gpio_in -); - - /* Parameters defining the bit offset of each function in the chain */ - localparam MGMT_EN = 0; - localparam OEB = 1; - localparam HLDH = 2; - localparam ENH = 3; - localparam INP_DIS = 4; - localparam MOD_SEL = 5; - localparam AN_EN = 6; - localparam AN_SEL = 7; - localparam AN_POL = 8; - localparam SLOW = 9; - localparam TRIP = 10; - localparam DM = 11; - - /* Internally registered signals */ - reg mgmt_ena; // Enable management SoC to access pad - reg gpio_holdover; - reg gpio_slow_sel; - reg gpio_vtrip_sel; - reg gpio_inenb; - reg gpio_ib_mode_sel; - reg gpio_outenb; - reg [2:0] gpio_dm; - reg gpio_ana_en; - reg gpio_ana_sel; - reg gpio_ana_pol; - - /* Derived output values */ - wire pad_gpio_holdover; - wire pad_gpio_slow_sel; - wire pad_gpio_vtrip_sel; - wire pad_gpio_inenb; - wire pad_gpio_ib_mode_sel; - wire pad_gpio_ana_en; - wire pad_gpio_ana_sel; - wire pad_gpio_ana_pol; - wire [2:0] pad_gpio_dm; - wire pad_gpio_outenb; - wire pad_gpio_out; - wire pad_gpio_in; - - /* Serial shift for the above (latched) values */ - reg [PAD_CTRL_BITS-1:0] shift_register; - - /* Utilize reset and clock to encode a load operation */ - wire load_data; - wire int_reset; - - /* Create internal reset and load signals from input reset and clock */ - assign serial_data_out = shift_register[PAD_CTRL_BITS-1]; - assign int_reset = (~resetn) & (~serial_clock); - assign load_data = (~resetn) & serial_clock; - - always @(posedge serial_clock or posedge int_reset) begin - if (int_reset == 1'b1) begin - /* Clear shift register */ - shift_register <= 'd0; - end else begin - /* Shift data in */ - shift_register <= {shift_register[PAD_CTRL_BITS-2:0], serial_data_in}; - end - end - - always @(posedge load_data or posedge int_reset) begin - if (int_reset == 1'b1) begin - /* Initial state on reset: Pad set to management input */ - mgmt_ena <= 1'b1; // Management SoC has control over all I/O - gpio_holdover <= HOLD_INIT; // All signals latched in hold mode - gpio_slow_sel <= SLOW_INIT; // Fast slew rate - gpio_vtrip_sel <= TRIP_INIT; // CMOS mode - gpio_ib_mode_sel <= IB_INIT; // CMOS mode - gpio_inenb <= IENB_INIT; // Input enabled - gpio_outenb <= OENB_INIT; // (unused placeholder) - gpio_dm <= DM_INIT; // Configured as input only - gpio_ana_en <= AENA_INIT; // Digital enabled - gpio_ana_sel <= ASEL_INIT; // Don't-care when gpio_ana_en = 0 - gpio_ana_pol <= APOL_INIT; // Don't-care when gpio_ana_en = 0 - end else begin - /* Load data */ - mgmt_ena <= shift_register[MGMT_EN]; - gpio_outenb <= shift_register[OEB]; - gpio_holdover <= shift_register[HLDH]; - gpio_inenb <= shift_register[INP_DIS]; - gpio_ib_mode_sel <= shift_register[MOD_SEL]; - gpio_ana_en <= shift_register[AN_EN]; - gpio_ana_sel <= shift_register[AN_SEL]; - gpio_ana_pol <= shift_register[AN_POL]; - gpio_slow_sel <= shift_register[SLOW]; - gpio_vtrip_sel <= shift_register[TRIP]; - gpio_dm <= shift_register[DM+2:DM]; - - end - end - - /* These pad configuration signals are static and do not change */ - /* after setup. */ - - assign pad_gpio_holdover = gpio_holdover; - assign pad_gpio_slow_sel = gpio_slow_sel; - assign pad_gpio_vtrip_sel = gpio_vtrip_sel; - assign pad_gpio_ib_mode_sel = gpio_ib_mode_sel; - assign pad_gpio_ana_en = gpio_ana_en; - assign pad_gpio_ana_sel = gpio_ana_sel; - assign pad_gpio_ana_pol = gpio_ana_pol; - assign pad_gpio_dm = gpio_dm; - assign pad_gpio_inenb = gpio_inenb; - - /* Implement pad control behavior depending on state of mgmt_ena */ - - assign pad_gpio_out = (mgmt_ena) ? mgmt_gpio_out : user_gpio_out; - assign pad_gpio_outenb = (mgmt_ena) ? mgmt_gpio_oeb : user_gpio_oeb; - - assign user_gpio_in = (mgmt_ena) ? 1'b0 : pad_gpio_in; - assign mgmt_gpio_in = (mgmt_ena) ? pad_gpio_in : 1'b0; - -endmodule
diff --git a/verilog/rtl/mprj_ctrl.v b/verilog/rtl/mprj_ctrl.v index cb67ac4..c002610 100644 --- a/verilog/rtl/mprj_ctrl.v +++ b/verilog/rtl/mprj_ctrl.v
@@ -93,7 +93,6 @@ output serial_clock, output serial_resetn, output serial_data_out, - // inout [IO_PADS-1:0] mgmt_gpio_io input [IO_PADS-1:0] mgmt_gpio_in, output [IO_PADS-1:0] mgmt_gpio_out, output [IO_PADS-1:0] mgmt_gpio_outz, @@ -170,9 +169,11 @@ end end else if (xfer_sel) begin - iomem_rdata <= {31'd0, xfer_ctrl}; - if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[1:0]; + iomem_rdata <= {31'd0, busy}; + if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[0]; end + end else begin + xfer_ctrl <= 1'b0; // Immediately self-resetting end end end @@ -181,12 +182,14 @@ for (i=0; i<IO_PADS; i=i+1) begin always @(posedge clk) begin if (!resetn) begin - // NOTE: This needs to be set to the specific bit sequence - // that initializes every I/O pad to the appropriate state on - // startup, to match the startup state at each pad. Otherwise - // surprises happen if not all pad configurations are applied - // from the program code, and a transfer is initiated. - io_ctrl[i] <= 'd0; + // NOTE: This initialization must match the defaults passed + // to the control blocks. Specifically, 0x1801 is for a + // bidirectional pad, and 0x0403 is for a simple input pad + if (i < 2) begin + io_ctrl[i] <= 'h1801; + end else begin + io_ctrl[i] <= 'h0403; + end end else begin if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin if (io_ctrl_sel[i]) begin @@ -224,7 +227,6 @@ reg [1:0] xfer_state; reg serial_clock; reg serial_resetn; - reg serial_data_out; // NOTE: Ignoring power control bits for now. . . need to revisit. // Depends on how the power pads are arranged among the GPIO, and @@ -233,20 +235,26 @@ reg [IO_CTRL_BITS-1:0] serial_data_staging; + wire serial_data_out; + wire busy; + + assign serial_data_out = serial_data_staging[IO_CTRL_BITS-1]; + assign busy = (xfer_state != `IDLE); + always @(posedge clk or negedge resetn) begin if (resetn == 1'b0) begin xfer_state <= `IDLE; xfer_count <= 4'd0; - pad_count <= 6'd0; + pad_count <= IO_PADS; serial_resetn <= 1'b0; serial_clock <= 1'b0; - serial_data_out <= 1'b0; end else begin if (xfer_state == `IDLE) begin - serial_resetn <= 1'b0; + pad_count <= IO_PADS; + serial_resetn <= 1'b1; serial_clock <= 1'b0; if (xfer_ctrl == 1'b1) begin xfer_state <= `START; @@ -255,25 +263,24 @@ serial_resetn <= 1'b1; serial_clock <= 1'b0; xfer_count <= 6'd0; - if (pad_count == IO_PADS) begin - xfer_state <= `LOAD; - end else begin - pad_count <= pad_count + 1; - xfer_state <= `XBYTE; - serial_data_staging <= io_ctrl[pad_count]; - end + pad_count <= pad_count - 1; + xfer_state <= `XBYTE; + serial_data_staging <= io_ctrl[pad_count - 1]; end else if (xfer_state == `XBYTE) begin serial_resetn <= 1'b1; serial_clock <= ~serial_clock; if (serial_clock == 1'b0) begin - if (xfer_count == IO_CTRL_BITS) begin - xfer_state <= `START; + if (xfer_count == IO_CTRL_BITS - 1) begin + if (pad_count == 0) begin + xfer_state <= `LOAD; + end else begin + xfer_state <= `START; + end end else begin xfer_count <= xfer_count + 1; end end else begin serial_data_staging <= {serial_data_staging[IO_CTRL_BITS-2:0], 1'b0}; - serial_data_out <= serial_data_staging[IO_CTRL_BITS-1]; end end else if (xfer_state == `LOAD) begin xfer_count <= xfer_count + 1;