(1) Corrected an error from a recent commit where the reset was

fixed by moving from after the managment protect to before it, but
an inversion of the signal was missed, leading to an incorrect
wb_rst_i passed to housekeeping.  (2) Revised the method to load
the serial GPIO data chain from a 2-pin, I2C-like method to a
more straightforward 3-pin method with separate reset, clock, and
load pins.  The load pin propagates through the chaing like the
other two.  Added a bit-bang signal for the load signal as well.
(3) Added an implied buffer after the data output of the GPIO
control block to ensure that the data arrives at the next control
block after the clock, to prevent hold violations.
This commit is contained in:
Tim Edwards 2021-11-03 23:18:36 -04:00
parent ba932643e6
commit b8dda9c3b1
4 changed files with 80 additions and 28 deletions

View File

@ -189,6 +189,7 @@ module caravan (
wire [`MPRJ_IO_PADS_2-`ANALOG_PADS_2-1:0] gpio_serial_link_2;
wire mprj_io_loader_resetn;
wire mprj_io_loader_clock;
wire mprj_io_loader_strobe;
wire mprj_io_loader_data_1; /* user1 side serial loader */
wire mprj_io_loader_data_2; /* user2 side serial loader */
@ -633,10 +634,14 @@ module caravan (
wire [`MPRJ_IO_PADS_2-1:0] gpio_clock_2;
wire [`MPRJ_IO_PADS_1-1:0] gpio_resetn_1;
wire [`MPRJ_IO_PADS_2-1:0] gpio_resetn_2;
wire [`MPRJ_IO_PADS_1-1:0] gpio_load_1;
wire [`MPRJ_IO_PADS_2-1:0] gpio_load_2;
wire [`MPRJ_IO_PADS_1-6:0] gpio_clock_1_shifted;
wire [`MPRJ_IO_PADS_2-7:0] gpio_clock_2_shifted;
wire [`MPRJ_IO_PADS_1-6:0] gpio_resetn_1_shifted;
wire [`MPRJ_IO_PADS_2-7:0] gpio_resetn_2_shifted;
wire [`MPRJ_IO_PADS_1-6:0] gpio_load_1_shifted;
wire [`MPRJ_IO_PADS_2-7:0] gpio_load_2_shifted;
assign gpio_clock_1_shifted = {gpio_clock_1[`MPRJ_IO_PADS_1-`ANALOG_PADS_1-2:0],
mprj_io_loader_clock};
@ -646,6 +651,10 @@ module caravan (
mprj_io_loader_resetn};
assign gpio_resetn_2_shifted = {mprj_io_loader_resetn,
gpio_resetn_2[`MPRJ_IO_PADS_2-`ANALOG_PADS_2-1:1]};
assign gpio_load_1_shifted = {gpio_load_1[`MPRJ_IO_PADS_1-`ANALOG_PADS_1-2:0],
mprj_io_loader_strobe};
assign gpio_load_2_shifted = {mprj_io_loader_strobe,
gpio_load_2[`MPRJ_IO_PADS_2-`ANALOG_PADS_2-1:1]};
wire [2:0] spi_pll_sel;
wire [2:0] spi_pll90_sel;
@ -740,6 +749,7 @@ module caravan (
.reset(ext_reset),
.serial_clock(mprj_io_loader_clock),
.serial_load(mprj_io_loader_strobe),
.serial_resetn(mprj_io_loader_resetn),
.serial_data_1(mprj_io_loader_data_1),
.serial_data_2(mprj_io_loader_data_2),
@ -1073,9 +1083,11 @@ module caravan (
.resetn(gpio_resetn_1_shifted[1:0]),
.serial_clock(gpio_clock_1_shifted[1:0]),
.serial_load(gpio_load_1_shifted[1:0]),
.resetn_out(gpio_resetn_1[1:0]),
.serial_clock_out(gpio_clock_1[1:0]),
.serial_load_out(gpio_load_1[1:0]),
.mgmt_gpio_in(mgmt_io_in[1:0]),
.mgmt_gpio_out({sdo_out, jtag_out}),
@ -1127,9 +1139,11 @@ module caravan (
.resetn(gpio_resetn_1_shifted[7:2]),
.serial_clock(gpio_clock_1_shifted[7:2]),
.serial_load(gpio_load_1_shifted[7:2]),
.resetn_out(gpio_resetn_1[7:2]),
.serial_clock_out(gpio_clock_1[7:2]),
.serial_load_out(gpio_load_1[7:2]),
.mgmt_gpio_in(mgmt_io_in[7:2]),
.mgmt_gpio_out(mgmt_io_in[7:2]),
@ -1177,9 +1191,11 @@ module caravan (
.resetn(gpio_resetn_1_shifted[(`MPRJ_IO_PADS_1-`ANALOG_PADS_1-1):8]),
.serial_clock(gpio_clock_1_shifted[(`MPRJ_IO_PADS_1-`ANALOG_PADS_1-1):8]),
.serial_load(gpio_load_1_shifted[(`MPRJ_IO_PADS_1-`ANALOG_PADS_1-1):8]),
.resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_1-`ANALOG_PADS_1-1):8]),
.serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_1-`ANALOG_PADS_1-1):8]),
.serial_load_out(gpio_load_1[(`MPRJ_IO_PADS_1-`ANALOG_PADS_1-1):8]),
.mgmt_gpio_in(mgmt_io_in[`DIG1_TOP:8]),
.mgmt_gpio_out(mgmt_io_in[`DIG1_TOP:8]),
@ -1228,9 +1244,11 @@ module caravan (
.resetn(gpio_resetn_1_shifted[(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-1):(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-3)]),
.serial_clock(gpio_clock_1_shifted[(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-1):(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-3)]),
.serial_load(gpio_load_1_shifted[(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-1):(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-3)]),
.resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-1):(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-3)]),
.serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-1):(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-3)]),
.serial_load_out(gpio_load_1[(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-1):(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-3)]),
.mgmt_gpio_in(mgmt_io_in[(`DIG2_TOP):(`DIG2_TOP-2)]),
.mgmt_gpio_out(mgmt_io_out[4:2]),
@ -1280,9 +1298,11 @@ module caravan (
.resetn(gpio_resetn_1_shifted[(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-3):0]),
.serial_clock(gpio_clock_1_shifted[(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-3):0]),
.serial_load(gpio_load_1_shifted[(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-3):0]),
.resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-3):0]),
.serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-3):0]),
.serial_load_out(gpio_load_1[(`MPRJ_IO_PADS_2-`ANALOG_PADS_2-3):0]),
.mgmt_gpio_in(mgmt_io_in[(`DIG2_TOP-2):`DIG2_BOT]),
.mgmt_gpio_out(mgmt_io_in[(`DIG2_TOP-2):`DIG2_BOT]),

View File

@ -152,6 +152,7 @@ module caravel (
wire [`MPRJ_IO_PADS_2-1:0] gpio_serial_link_2;
wire mprj_io_loader_resetn;
wire mprj_io_loader_clock;
wire mprj_io_loader_strobe;
wire mprj_io_loader_data_1; /* user1 side serial loader */
wire mprj_io_loader_data_2; /* user2 side serial loader */
@ -574,10 +575,14 @@ module caravel (
wire [`MPRJ_IO_PADS_2-1:0] gpio_clock_2;
wire [`MPRJ_IO_PADS_1-1:0] gpio_resetn_1;
wire [`MPRJ_IO_PADS_2-1:0] gpio_resetn_2;
wire [`MPRJ_IO_PADS_1-1:0] gpio_load_1;
wire [`MPRJ_IO_PADS_2-1:0] gpio_load_2;
wire [`MPRJ_IO_PADS_1-1:0] gpio_clock_1_shifted;
wire [`MPRJ_IO_PADS_2-1:0] gpio_clock_2_shifted;
wire [`MPRJ_IO_PADS_1-1:0] gpio_resetn_1_shifted;
wire [`MPRJ_IO_PADS_2-1:0] gpio_resetn_2_shifted;
wire [`MPRJ_IO_PADS_1-1:0] gpio_load_1_shifted;
wire [`MPRJ_IO_PADS_2-1:0] gpio_load_2_shifted;
assign gpio_clock_1_shifted = {gpio_clock_1[`MPRJ_IO_PADS_1-2:0],
mprj_io_loader_clock};
@ -587,6 +592,10 @@ module caravel (
mprj_io_loader_resetn};
assign gpio_resetn_2_shifted = {mprj_io_loader_resetn,
gpio_resetn_2[`MPRJ_IO_PADS_2-1:1]};
assign gpio_load_1_shifted = {gpio_load_1[`MPRJ_IO_PADS_1-2:0],
mprj_io_loader_strobe};
assign gpio_load_2_shifted = {mprj_io_loader_strobe,
gpio_load_2[`MPRJ_IO_PADS_2-1:1]};
wire [2:0] spi_pll_sel;
wire [2:0] spi_pll90_sel;
@ -638,7 +647,7 @@ module caravel (
`endif
.wb_clk_i(caravel_clk),
.wb_rst_i(caravel_rstn),
.wb_rst_i(~caravel_rstn),
.wb_adr_i(mprj_adr_o_core),
.wb_dat_i(mprj_dat_o_core),
@ -681,6 +690,7 @@ module caravel (
.reset(ext_reset),
.serial_clock(mprj_io_loader_clock),
.serial_load(mprj_io_loader_strobe),
.serial_resetn(mprj_io_loader_resetn),
.serial_data_1(mprj_io_loader_data_1),
.serial_data_2(mprj_io_loader_data_2),
@ -1125,9 +1135,11 @@ module caravel (
.resetn(gpio_resetn_1_shifted[1:0]),
.serial_clock(gpio_clock_1_shifted[1:0]),
.serial_load(gpio_load_1_shifted[1:0]),
.resetn_out(gpio_resetn_1[1:0]),
.serial_clock_out(gpio_clock_1[1:0]),
.serial_load_out(gpio_load_1[1:0]),
.mgmt_gpio_in(mgmt_io_in[1:0]),
.mgmt_gpio_out(mgmt_io_out[1:0]),
@ -1179,9 +1191,11 @@ module caravel (
.resetn(gpio_resetn_1_shifted[7:2]),
.serial_clock(gpio_clock_1_shifted[7:2]),
.serial_load(gpio_load_1_shifted[7:2]),
.resetn_out(gpio_resetn_1[7:2]),
.serial_clock_out(gpio_clock_1[7:2]),
.serial_load_out(gpio_load_1[7:2]),
.mgmt_gpio_in(mgmt_io_in[7:2]),
.mgmt_gpio_out(mgmt_io_in[7:2]),
@ -1230,9 +1244,11 @@ module caravel (
.resetn(gpio_resetn_1_shifted[(`MPRJ_IO_PADS_1-1):8]),
.serial_clock(gpio_clock_1_shifted[(`MPRJ_IO_PADS_1-1):8]),
.serial_load(gpio_load_1_shifted[(`MPRJ_IO_PADS_1-1):8]),
.resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_1-1):8]),
.serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_1-1):8]),
.serial_load_out(gpio_load_1[(`MPRJ_IO_PADS_1-1):8]),
.mgmt_gpio_in(mgmt_io_in[(`MPRJ_IO_PADS_1-1):8]),
.mgmt_gpio_out(mgmt_io_in[(`MPRJ_IO_PADS_1-1):8]),
@ -1281,9 +1297,11 @@ module caravel (
.resetn(gpio_resetn_1_shifted[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-3)]),
.serial_clock(gpio_clock_1_shifted[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-3)]),
.serial_load(gpio_load_1_shifted[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-3)]),
.resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-3)]),
.serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-3)]),
.serial_load_out(gpio_load_1[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-3)]),
.mgmt_gpio_in(mgmt_io_in[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]),
.mgmt_gpio_out(mgmt_io_out[4:2]),
@ -1333,9 +1351,11 @@ module caravel (
.resetn(gpio_resetn_1_shifted[(`MPRJ_IO_PADS_2-4):0]),
.serial_clock(gpio_clock_1_shifted[(`MPRJ_IO_PADS_2-4):0]),
.serial_load(gpio_load_1_shifted[(`MPRJ_IO_PADS_2-4):0]),
.resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_2-4):0]),
.serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_2-4):0]),
.serial_load_out(gpio_load_1[(`MPRJ_IO_PADS_2-4):0]),
.mgmt_gpio_in(mgmt_io_in[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]),
.mgmt_gpio_out(mgmt_io_in[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]),

View File

@ -60,6 +60,8 @@ module gpio_control_block #(
output resetn_out,
input serial_clock, // Global clock, locally propatated
output serial_clock_out,
input serial_load, // Register load strobe
output serial_load_out,
output mgmt_gpio_in, // Management from pad (input only)
input mgmt_gpio_out, // Management to pad (output only)
@ -139,26 +141,25 @@ module gpio_control_block #(
wire user_gpio_in;
wire gpio_in_unbuf;
wire gpio_logic1;
wire serial_data_pre;
/* 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;
assign serial_data_pre = shift_register[PAD_CTRL_BITS-1];
/* Propagate the clock and reset signals so that they aren't wired */
/* all over the chip, but are just wired between the blocks. */
assign serial_clock_out = serial_clock;
assign resetn_out = resetn;
assign serial_load_out = serial_load;
always @(posedge serial_clock or posedge int_reset) begin
if (int_reset == 1'b1) begin
/* Serial data should be buffered again to avoid hold violations */
assign serial_data_out = serial_data_pre & one;
always @(posedge serial_clock or negedge resetn) begin
if (resetn == 1'b0) begin
/* Clear shift register */
shift_register <= 'd0;
end else begin
@ -167,8 +168,8 @@ module gpio_control_block #(
end
end
always @(posedge load_data or posedge int_reset) begin
if (int_reset == 1'b1) begin
always @(posedge serial_load or negedge resetn) begin
if (resetn == 1'b0) begin
/* Initial state on reset depends on applied defaults */
mgmt_ena <= gpio_defaults[MGMT_EN];
gpio_holdover <= gpio_defaults[HLDH];

View File

@ -112,6 +112,7 @@ module housekeeping #(
// GPIO serial loader programming interface
output serial_clock,
output serial_load,
output serial_resetn,
output serial_data_1,
output serial_data_2,
@ -194,6 +195,7 @@ module housekeeping #(
reg reset_reg;
reg irq_spi;
reg serial_bb_clock;
reg serial_bb_load;
reg serial_bb_resetn;
reg serial_bb_data_1;
reg serial_bb_data_2;
@ -374,8 +376,9 @@ module housekeeping #(
// GPIO Control (bit bang and automatic)
// NOTE: "serial_busy" is the read-back signal occupying the same
// address/bit as "serial_xfer".
8'h13 : fdata = {2'b00, serial_data_2, serial_data_1, serial_bb_clock,
serial_bb_resetn, serial_bb_enable, serial_busy};
8'h13 : fdata = {1'b0, serial_data_2, serial_data_1, serial_bb_clock,
serial_bb_load, serial_bb_resetn, serial_bb_enable,
serial_busy};
/* To be added: SRAM read-only port (registers 14 to 19) */
8'h14 : fdata = {6'b000000, sram_ro_clk, sram_ro_csb};
@ -860,11 +863,13 @@ module housekeeping #(
reg serial_clock_pre;
reg serial_resetn_pre;
reg serial_load_pre;
reg serial_busy;
wire serial_data_1;
wire serial_data_2;
wire serial_clock;
wire serial_resetn;
wire serial_load;
reg [IO_CTRL_BITS-1:0] serial_data_staging_1;
reg [IO_CTRL_BITS-1:0] serial_data_staging_2;
@ -872,6 +877,8 @@ module housekeeping #(
serial_bb_clock : serial_clock_pre;
assign serial_resetn = (serial_bb_enable == 1'b1) ?
serial_bb_resetn : serial_resetn_pre;
assign serial_load = (serial_bb_enable == 1'b1) ?
serial_bb_load : serial_load_pre;
assign serial_data_1 = (serial_bb_enable == 1'b1) ?
serial_bb_data_1 : serial_data_staging_1[IO_CTRL_BITS-1];
@ -890,18 +897,20 @@ module housekeeping #(
pad_count_2 <= `MPRJ_IO_PADS_1;
serial_resetn_pre <= 1'b0;
serial_clock_pre <= 1'b0;
serial_load_pre <= 1'b0;
serial_data_staging_1 <= 0;
serial_data_staging_2 <= 0;
serial_busy <= 1'b0;
end else begin
serial_resetn_pre <= 1'b1;
case (xfer_state)
`GPIO_IDLE: begin
pad_count_1 <= `MPRJ_IO_PADS_1 - 1;
pad_count_2 <= `MPRJ_IO_PADS_1;
serial_resetn_pre <= 1'b1;
serial_clock_pre <= 1'b0;
serial_load_pre <= 1'b0;
if (serial_xfer == 1'b1) begin
xfer_state <= `GPIO_START;
serial_busy <= 1'b1;
@ -910,8 +919,8 @@ module housekeeping #(
end
end
`GPIO_START: begin
serial_resetn_pre <= 1'b1;
serial_clock_pre <= 1'b0;
serial_load_pre <= 1'b0;
xfer_count <= 6'd0;
pad_count_1 <= pad_count_1 - 1;
pad_count_2 <= pad_count_2 + 1;
@ -920,10 +929,11 @@ module housekeeping #(
serial_data_staging_2 <= gpio_configure[pad_count_2];
end
`GPIO_XBYTE: begin
serial_resetn_pre <= 1'b1;
serial_clock_pre <= ~serial_clock;
serial_load_pre <= 1'b0;
if (serial_clock == 1'b0) begin
if (xfer_count == IO_CTRL_BITS - 1) begin
xfer_count <= 4'd0;
if (pad_count_2 == `MPRJ_IO_PADS) begin
xfer_state <= `GPIO_LOAD;
end else begin
@ -942,21 +952,20 @@ module housekeeping #(
`GPIO_LOAD: begin
xfer_count <= xfer_count + 1;
/* Load sequence: Raise clock for final data shift in;
* Pulse reset low while clock is high
* Set clock back to zero.
/* Load sequence: Pulse clock for final data shift in;
* Pulse the load strobe.
* Return to idle mode.
*/
if (xfer_count == 4'd0) begin
serial_clock_pre <= 1'b1;
serial_resetn_pre <= 1'b0;
serial_clock_pre <= 1'b0;
serial_load_pre <= 1'b0;
end else if (xfer_count == 4'd1) begin
serial_clock_pre <= 1'b1;
serial_resetn_pre <= 1'b1;
serial_clock_pre <= 1'b0;
serial_load_pre <= 1'b1;
end else if (xfer_count == 4'd2) begin
serial_busy <= 1'b0;
serial_resetn_pre <= 1'b1;
serial_clock_pre <= 1'b0;
serial_load_pre <= 1'b0;
xfer_state <= `GPIO_IDLE;
end
end
@ -1032,6 +1041,7 @@ module housekeeping #(
mgmt_gpio_data <= 'd0;
mgmt_gpio_data_buf <= 'd0;
serial_bb_enable <= 1'b0;
serial_bb_load <= 1'b0;
serial_bb_data_1 <= 1'b0;
serial_bb_data_2 <= 1'b0;
serial_bb_clock <= 1'b0;
@ -1084,9 +1094,10 @@ module housekeeping #(
pll_div <= cdata[4:0];
end
8'h13: begin
serial_bb_data_2 <= cdata[5];
serial_bb_data_1 <= cdata[4];
serial_bb_clock <= cdata[3];
serial_bb_data_2 <= cdata[6];
serial_bb_data_1 <= cdata[5];
serial_bb_clock <= cdata[4];
serial_bb_load <= cdata[3];
serial_bb_resetn <= cdata[2];
serial_bb_enable <= cdata[1];
serial_xfer <= cdata[0];