Skid Buffer
A skid buffer is used to break apart a combinatorial path between a sender and receiver interface by registering the data and handshake signals. The skid buffer uses two buffer entries, a main buffer and a “skid” buffer, that allows it to maintain the full throughput, thus pipelining the data path. Because there is a one clock cycle latency through the skid buffer for backpressuring the sender if it is backpressured by the receiver, the “skid” buffer is needed to absorb one extra transaction from the sender, before it can actually backpressure the sender. Skid buffers are commonly used for pipelining and resolving timing issues by breaking long combinatorial paths between a sender and receiver. Because there are only two buffer registers, it is also a very lightweight solution.
This skid buffer implementation also provides two additional output status signals, o_accept and o_transmit,
which indicate when a transaction is successfully accepted from the input interface or successfully transmitted to
the output interface. These two additional signals are provided so that a parent module can keep track of
when the skid buffer is accepting or transmitting data. For example, this could be useful if the parent module
needs that information for some of its own control logic or if it wants to keep track of how many transcations
have been accepted and transmitted by the skid buffer.
Parameters
DATA_WIDTH: data width in bits
Ports
i_clock: input clocki_aresetn: asynchronous active-low reseti_clear: synchronous cleari_data: input datai_input_valid: valid signal from input interface. Used with o_input_ready to handshake on input interfacei_output_ready: ready signal from output interface. Used with o_output_valid to handshake on output interfaceo_data: output datao_output_valid: valid signal from output interface. Used with i_output_ready to handshake on output interfaceo_input_ready: ready signal from input interface. Used with i_input_valid to handshake on input interfaceo_accept: accept status signal that indicates whenever input data is accepted by the skid buffero_transmit: transmit status signal that indicates whenever output data is transmitted by the skid buffer
Source Code
1`ifndef LIBSV_FIFOS_SKID_BUFFER
2`define LIBSV_FIFOS_SKID_BUFFER
3
4module skid_buffer #(
5 parameter int DATA_WIDTH /* verilator public_flat_rd */ = 32
6) (
7 input logic i_clock,
8 input logic i_aresetn,
9 input logic i_clear,
10 input logic [DATA_WIDTH-1:0] i_data,
11 input logic i_input_valid,
12 input logic i_output_ready,
13 output logic [DATA_WIDTH-1:0] o_data,
14 output logic o_output_valid,
15 output logic o_input_ready,
16 output logic o_accept,
17 output logic o_transmit
18);
19
20 // CONTROL PATH -----------------------------
21
22 typedef enum logic [2:0] {
23 EMPTY = 3'b001,
24 BUSY = 3'b010,
25 FULL = 3'b100
26 } state_t;
27
28 state_t state, next_state; // state variables
29 logic accept, transmit; // handshake flags on each interface
30 logic [DATA_WIDTH-1:0] buffer; // the "skid" buffer
31
32 assign o_accept = accept;
33 assign o_transmit = transmit;
34
35 always_comb begin : next_state_logic
36 accept = i_input_valid && o_input_ready; // check for input handshake
37 transmit = o_output_valid && i_output_ready; // check for output handshake
38 next_state = EMPTY;
39 unique case (state)
40 EMPTY: begin
41 next_state = EMPTY;
42 if (accept) next_state = BUSY;
43 end
44 BUSY: begin
45 next_state = BUSY;
46 if (accept && !transmit) next_state = FULL;
47 else if (!accept && transmit) next_state = EMPTY;
48 end
49 FULL: begin
50 next_state = FULL;
51 if (transmit) next_state = BUSY;
52 end
53 default: next_state = EMPTY;
54 endcase
55 end : next_state_logic
56
57 always_ff @(posedge i_clock, negedge i_aresetn) begin : update_state_logic
58 if (!i_aresetn || i_clear) begin
59 state <= EMPTY;
60 o_input_ready <= 1'b0;
61 o_output_valid <= 1'b0;
62 end else begin
63 state <= next_state;
64 o_input_ready <= next_state != FULL;
65 o_output_valid <= next_state != EMPTY;
66 end
67 end : update_state_logic
68
69 logic buffer_write_en, o_data_write_en;
70 always_comb begin : write_en_logic
71 buffer_write_en = state == BUSY && accept && !transmit;
72 o_data_write_en = (state == EMPTY && accept && !transmit)
73 || (state == BUSY && accept && transmit)
74 || (state == FULL && !accept && transmit);
75 end : write_en_logic
76
77 // END OF CONTROL PATH ----------------------
78
79 // DATA PATH --------------------------------
80
81 always_ff @(posedge i_clock, negedge i_aresetn) begin : o_data_and_buffer_logic
82 if (!i_aresetn || i_clear) begin
83 o_data <= '0;
84 buffer <= '0;
85 end else begin
86
87 if (o_data_write_en) begin
88 if (state == FULL) o_data <= buffer;
89 else o_data <= i_data;
90 end
91
92 if (buffer_write_en) begin
93 buffer <= i_data;
94 end
95
96 end
97 end : o_data_and_buffer_logic
98
99 // END OF DATA PATH -------------------------
100
101endmodule
102
103`endif /* LIBSV_FIFOS_SKID_BUFFER */