Skip to content

Commit

Permalink
scan_chain: Update with new 'invert-at-each-stage' scanchain
Browse files Browse the repository at this point in the history
The scanchain.v module has less buffering stage in-to-out for
reduced delay and outputs an inverted clock. The final FF stage
is not pos-edge since the neg-edge trick is handled by outputing
an inverted clock.

The controller needs some update since you need more clock pulses
to push things through now.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
  • Loading branch information
smunaut committed Apr 15, 2023
1 parent 2796ef4 commit 012a0b3
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 68 deletions.
21 changes: 13 additions & 8 deletions verilog/rtl/scan_controller/scan_controller.v
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
`default_nettype none

module scan_controller #(
parameter integer NUM_DESIGNS = 498,
parameter integer NUM_DESIGNS = 498, // Must be even !!!
parameter integer NUM_IOS = 8,

// auto-set
Expand Down Expand Up @@ -38,7 +38,6 @@ module scan_controller #(

// Signals
// -------
assign ready = active && state == ST_IDLE;

// Reset
reg [2:0] rst_shift;
Expand Down Expand Up @@ -86,8 +85,8 @@ module scan_controller #(
reg [3:0] state_nxt;

// Scan progress
reg [$clog2(NUM_IOS)-1:0] bit_cnt;
wire bit_last;
reg [$clog2(NUM_IOS+1)-1:0] bit_cnt;
wire bit_last;

reg [8:0] proj_cnt;
wire proj_sel;
Expand Down Expand Up @@ -122,13 +121,14 @@ module scan_controller #(
// Misc
// ----

// Generate internal ties for the IO blocks
assign oeb = {`MPRJ_IO_PADS{1'b0}};

// Formal tests
`ifdef FORMAL
`include "properties.v"
`endif

// Generate internal ties for the IO blocks
assign oeb = {`MPRJ_IO_PADS{1'b0}};

// Generate our own reset, with de-assertion
// synchronized to clock
always @(negedge clk or posedge reset)
Expand All @@ -139,6 +139,9 @@ module scan_controller #(

assign rst_i = rst_shift[2];

// External ready output
assign ready = active && state == ST_IDLE;


// Scan chain and IO muxing
// ------------------------
Expand Down Expand Up @@ -290,7 +293,9 @@ module scan_controller #(
else if ((state == ST_IN_SHIFT_HI) | (state == ST_OUT_SHIFT_HI))
bit_cnt <= bit_last ? 0 : (bit_cnt + 1);

assign bit_last = (bit_cnt == (NUM_IOS - 1));
assign bit_last = ((proj_cnt[0] & ~proj_sel) | (proj_done & active_select[0])) ?
(bit_cnt == NUM_IOS) :
(bit_cnt == (NUM_IOS - 1));

// Keep track of project number
always @(posedge clk)
Expand Down
135 changes: 75 additions & 60 deletions verilog/rtl/scanchain/scanchain.v
Original file line number Diff line number Diff line change
@@ -1,96 +1,111 @@
`default_nettype none

module scanchain (
input wire clk_in,
input wire data_in,
input wire scan_select_in,
input wire latch_enable_in,
module scanchain #(
parameter NUM_IOS = 8
)(
// Chain input
input wire clk_in,
input wire data_in,
input wire scan_select_in,
input wire latch_enable_in,

// Chain output
output wire clk_out,
output wire data_out,
output wire scan_select_out,
output wire latch_enable_out,

// io, names from point of view of the user module
input wire [NUM_IOS-1:0] module_data_out,
// User module connections
input wire [NUM_IOS-1:0] module_data_out,
output wire [NUM_IOS-1:0] module_data_in
);
);

// Signals
// -------

// input buffers
// Looking at results from multiple projects the buffering is a bit
// inconsistent. So instead, we ensure at least clk buf
// Internal clock
wire clk;

sky130_fd_sc_hd__clkbuf_2 input_buf_clk (
// Scan Flop chain
wire [NUM_IOS-1:0] scan_data_out;
wire [NUM_IOS-1:0] scan_data_in;


// Clock distribution
// ------------------

// Pass-through inverter
sky130_fd_sc_hd__clkinv_4 buf_clk (
.A (clk_in),
.X (clk),
.Y (clk_out),
.VPWR (1'b1),
.VGND (1'b0)
);

// output buffers
// Same as for input, to try and be more consistent, we make our own
wire data_out_i;

sky130_fd_sc_hd__buf_4 output_buffers[3:0] (
.A ({clk, data_out_i, scan_select_in, latch_enable_in }),
.X ({clk_out, data_out, scan_select_out, latch_enable_out }),
// Internal clock net inverter
sky130_fd_sc_hd__clkinv_2 buf_clk_int (
.A (clk_out),
.Y (clk),
.VPWR (1'b1),
.VGND (1'b0)
);

parameter NUM_IOS = 8;

// wires needed
wire [NUM_IOS-1:0] scan_data_out; // output of the each scan chain flop
wire [NUM_IOS-1:0] scan_data_in; // input of each scan chain flop
// wire [NUM_IOS-1:0] module_data_in; // the data that enters the user module
// wire [NUM_IOS-1:0] module_data_out; // the data from the user module

// scan chain - link all the flops, with data coming from data_in
assign scan_data_in = {scan_data_out[NUM_IOS-2:0], data_in};
// Through buffers
// ---------------

// end of the chain is a negedge FF to increase hold margin between blocks
sky130_fd_sc_hd__dfrtn_1 out_flop (
.RESET_B (1'b1),
.CLK_N (clk),
.D (scan_data_out[NUM_IOS-1]),
.Q (data_out_i),
sky130_fd_sc_hd__buf_4 through_buffers[1:0] (
.A ({ scan_select_in, latch_enable_in }),
.X ({ scan_select_out, latch_enable_out }),
.VPWR (1'b1),
.VGND (1'b0)
);


// Scan Chain
// ----------

// Link all the flops, with data coming from data_in
assign scan_data_in = { scan_data_out[NUM_IOS-2:0], data_in };

// end of the chain output
assign data_out_i = scan_data_out[NUM_IOS-1];

// scan flops have a mux on their inputs to choose either data from the user module or the previous flop's output
// https://antmicro-skywater-pdk-docs.readthedocs.io/en/test-submodules-in-rtd/contents/libraries/sky130_fd_sc_ls/cells/sdfxtp/README.html
`ifndef FORMAL
`ifndef FORMAL_COMPAT
`ifndef FORMAL
`ifndef FORMAL_COMPAT
sky130_fd_sc_hd__sdfxtp_1 scan_flop [NUM_IOS-1:0] (
.CLK (clk),
.D (scan_data_in),
.SCD (module_data_out),
.SCE (scan_select_in),
.Q (scan_data_out),
.VPWR (1'b1),
.VGND (1'b0)
.CLK (clk),
.D (scan_data_in),
.SCD (module_data_out),
.SCE (scan_select_in),
.Q (scan_data_out),
.VPWR (1'b1),
.VGND (1'b0)
);

// end of the chain FF to compensate for clock inversion and lost cycle
// between blocks
sky130_fd_sc_hd__dfrtp_4 out_flop (
.RESET_B (1'b1),
.CLK (clk),
.D (scan_data_out[NUM_IOS-1]),
.Q (data_out),
.VPWR (1'b1),
.VGND (1'b0)
);

// latch is used to latch the input data of the user module while the scan chain is used to capture the user module's outputs
// https://antmicro-skywater-pdk-docs.readthedocs.io/en/test-submodules-in-rtd/contents/libraries/sky130_fd_sc_hd/cells/dlxtp/README.html
sky130_fd_sc_hd__dlxtp_1 latch [NUM_IOS-1:0] (
.D (scan_data_out),
.GATE (latch_enable_in),
.Q (module_data_in),
.VPWR (1'b1),
.VGND (1'b0)
);
`endif
`endif

/*
// instantiate the wokwi module
user_module_USER_MODULE_ID user_module(
.io_in (module_data_in),
.io_out (module_data_out)
.D (scan_data_out),
.GATE (latch_enable_in),
.Q (module_data_in),
.VPWR (1'b1),
.VGND (1'b0)
);
*/
`endif
`endif

endmodule
endmodule // scanchain

0 comments on commit 012a0b3

Please sign in to comment.