summaryrefslogtreecommitdiff
path: root/src/skid_buffer.sv
blob: 3ea6d0d20132c4c99f62ba334b6354ffcdac68cd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/* adjusted from pulp common_cells/spill_register_flushable.sv */

module skid_buffer #(
	parameter unsigned W = 2
)(
	input clk_i,
	input rstx_i,

	input valid_i,
	output ready_o,
	input [W-1:0] data_i,

	output valid_o,
	input  ready_i,
	output [W-1:0] data_o
);

logic a_fill, a_full, a_drain, b_fill, b_full, b_drain;
logic [W-1:0] a, b;

/* reg a */
always_ff @(posedge clk_i or negedge rstx_i)
if (!rstx_i)
	a <= '0;
else if (a_fill)
	a <= data_i;

always_ff @(posedge clk_i or negedge rstx_i)
if (!rstx_i)
	a_full <= '0;
else if (a_fill || a_drain)
	a_full <= a_fill;

always_ff @(posedge clk_i or negedge rstx_i)
if (!rstx_i)
	b <= '0;
else if (b_fill)
	b <= a;

/* fill A first, if upstream can't read A in time, place A into B and skid the
 * input into A until upstream can clean out B */
assign a_fill  = valid_i &&  ready_o;
assign a_drain = a_full  && !b_full;

assign b_fill  = a_drain && !ready_i;
assign b_drain = b_full  &&  ready_i;

assign ready_o = !a_full || !b_full;
assign valid_o =  a_full ||  b_full;

assign data_o  = b_full ? b : a;

endmodule // skid_buffer