summaryrefslogtreecommitdiff
path: root/src/skid_buffer.sv
diff options
context:
space:
mode:
Diffstat (limited to 'src/skid_buffer.sv')
-rw-r--r--src/skid_buffer.sv53
1 files changed, 53 insertions, 0 deletions
diff --git a/src/skid_buffer.sv b/src/skid_buffer.sv
new file mode 100644
index 0000000..3ea6d0d
--- /dev/null
+++ b/src/skid_buffer.sv
@@ -0,0 +1,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