Modified the GPIO control block verilog to remove the delay stages

from the data and replace them with a single flop clocked on the
negative edge of the serial clock.  This will completely avoid hold
violations by ensuring that the block's output data bit does not
change anywhere near the clock rising edge, so clocks do not have
to be tightly aligned among all of the GPIO blocks.
This commit is contained in:
Tim Edwards 2022-07-24 16:17:56 -04:00
parent 6a6d6a8c77
commit e6030f9fb3
1 changed files with 15 additions and 34 deletions

View File

@ -39,6 +39,11 @@
* See mprj_ctrl.v for the module that registers the data for each * See mprj_ctrl.v for the module that registers the data for each
* I/O and drives the input to the shift register. * I/O and drives the input to the shift register.
* *
* Modified 7/24/2022 by Tim Edwards
* Replaced the data delay with a negative edge-triggered flop
* so that the serial data bit out from the module only changes on
* the clock half cycle. This avoids the need to fine-tune the clock
* skew between GPIO blocks.
*--------------------------------------------------------------------- *---------------------------------------------------------------------
*/ */
@ -141,15 +146,20 @@ module gpio_control_block #(
wire user_gpio_in; wire user_gpio_in;
wire gpio_in_unbuf; wire gpio_in_unbuf;
wire gpio_logic1; wire gpio_logic1;
wire serial_data_pre; reg serial_data_out;
wire serial_data_post_1;
wire serial_data_post_2;
/* Serial shift for the above (latched) values */ /* Serial shift for the above (latched) values */
reg [PAD_CTRL_BITS-1:0] shift_register; reg [PAD_CTRL_BITS-1:0] shift_register;
/* Create internal reset and load signals from input reset and clock */ /* Latch the output on the clock negative edge */
assign serial_data_pre = shift_register[PAD_CTRL_BITS-1]; always @(negedge serial_clock or negedge resetn) begin
if (resetn == 1'b0) begin
/* Clear the shift register output */
serial_data_out <= 1'b0;
end else begin
serial_data_out <= shift_register[PAD_CTRL_BITS-1];
end
end
/* Propagate the clock and reset signals so that they aren't wired */ /* Propagate the clock and reset signals so that they aren't wired */
/* all over the chip, but are just wired between the blocks. */ /* all over the chip, but are just wired between the blocks. */
@ -157,35 +167,6 @@ module gpio_control_block #(
assign resetn_out = resetn; assign resetn_out = resetn;
assign serial_load_out = serial_load; assign serial_load_out = serial_load;
/* Serial data should be buffered again to avoid hold violations */
/* Do this in two ways: (1) Add internal delay cells, and (2) */
/* add a final logic gate after that. The logic gate is */
/* synthesized and will be sized appropriately for an output buffer */
sky130_fd_sc_hd__dlygate4sd2_1 data_delay_1 (
`ifdef USE_POWER_PINS
.VPWR(vccd),
.VGND(vssd),
.VPB(vccd),
.VNB(vssd),
`endif
.X(serial_data_post_1),
.A(serial_data_pre)
);
sky130_fd_sc_hd__dlygate4sd2_1 data_delay_2 (
`ifdef USE_POWER_PINS
.VPWR(vccd),
.VGND(vssd),
.VPB(vccd),
.VNB(vssd),
`endif
.X(serial_data_post_2),
.A(serial_data_post_1)
);
assign serial_data_out = serial_data_post_2 & one;
always @(posedge serial_clock or negedge resetn) begin always @(posedge serial_clock or negedge resetn) begin
if (resetn == 1'b0) begin if (resetn == 1'b0) begin
/* Clear shift register */ /* Clear shift register */