summaryrefslogtreecommitdiffhomepage
path: root/source/drop_fifo.v
diff options
context:
space:
mode:
Diffstat (limited to 'source/drop_fifo.v')
-rw-r--r--source/drop_fifo.v220
1 files changed, 220 insertions, 0 deletions
diff --git a/source/drop_fifo.v b/source/drop_fifo.v
new file mode 100644
index 0000000..393c20b
--- /dev/null
+++ b/source/drop_fifo.v
@@ -0,0 +1,220 @@
+/*
+ * drop_fifo.v
+ *
+ * Copyright (C) 2018, 2019 Mind Chasers Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * function: Double buffered side-by-side FIFO for delaying data until keep / drop decision is made
+ *
+ */
+
+`timescale 1ns /10ps
+
+module drop_fifo(
+ input rstn,
+ input clk,
+ input enable,
+
+ // control (keep or drop by default)
+ input keep, // this packet won't be dropped, start transferring it
+ input passthrough, // don't store / delay data, write through instead
+
+ // input
+ input we_in,
+ input wr_done,
+ input [8:0] d_in,
+
+ // output
+ output we_out,
+ output reg [8:0] d_out,
+
+ // debug
+ output reg active
+);
+
+// local parameters and includes
+
+
+// nets and registers
+
+// the msbit of the ptr selects top or bottom half
+reg [10:0] wr_ptr;
+reg [10:0] rd_ptr;
+
+wire [8:0] d_out_internal;
+
+reg read_run, read_run_m1; // read continues while read_run is set
+reg i_we_out, i_we_out_m1; // internal we_out
+wire re; // read enable for dpram
+reg rd_done_p1, rd_done;
+wire i_keep;
+reg kept;
+
+assign i_keep = keep & enable;
+
+/*
+ * read_run logic
+ * read starts after each keep assertion
+ * continues until the FIFO is empty
+ */
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ read_run <= 1'b0;
+ else if ( rd_done_p1 )
+ read_run <= 1'b0;
+ else if ( i_keep )
+ read_run <= 1'b1;
+
+
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ read_run_m1 <= 1'b0;
+ else
+ read_run_m1 <= read_run;
+
+assign re = read_run;
+
+
+/*
+ * we_out logic
+ * delayed version of re
+ */
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ i_we_out <= 1'b0;
+ else if ( read_run && read_run_m1 )
+ i_we_out <= 1'b1;
+ else
+ i_we_out <= 1'b0;
+
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ i_we_out_m1 <= 1'b0;
+ else
+ i_we_out_m1 <= i_we_out;
+
+// OR these two signals to stretch we_out to the last byte from FIFO
+assign we_out = i_we_out | i_we_out_m1;
+
+/*
+ * kept: assert for length of write duration after keep asserts
+ */
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ kept <= 1'b0;
+ else if ( wr_done )
+ kept <= 1'b0;
+ else if ( i_keep )
+ kept <= 1'b1;
+
+/*
+ * upper / lower half DPRAM logic
+ * directs upper or lower write buffer in FIFO
+ * toggle each time a packet is kept and write is finished
+ */
+always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ wr_ptr[10] <= 1'b0; // init to the lower bank
+ else if ( wr_done && kept )
+ wr_ptr[10] <= ~wr_ptr[10];
+
+/*
+ * wr_ptr logic excluding msbit
+ * reset pointer when wr_done
+ */
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ wr_ptr[9:0] <= 'd0;
+ else if ( wr_done )
+ wr_ptr[9:0] <= 'd0;
+ else if ( we_in )
+ wr_ptr[9:0] <= wr_ptr[9:0] + 1;
+
+/*
+ * each time the FIFO is empty, set rd_ptr[10] to wr_ptr[10]
+ * FIFO becomes empty through reading
+ */
+always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ rd_ptr[10] <= 1'b0; // init to the lower bank
+ else if ( rd_done )
+ rd_ptr[10] <= wr_ptr[10];
+
+/*
+ * rd_ptr logic excluding msbit
+ */
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ rd_ptr[9:0] <= 'd0;
+ else if ( rd_done )
+ rd_ptr[9:0] <= 'd0;
+ else if ( re )
+ rd_ptr[9:0] <= rd_ptr[9:0] + 1;
+
+/*
+ * d_out register
+ *
+ */
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ d_out <= 'd0;
+ else
+ d_out <= d_out_internal;
+
+
+/*
+* rd_done logic
+*/
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ begin
+ rd_done_p1 <= 1'b0;
+ rd_done <= 1'b0;
+ end
+ else
+ begin
+ rd_done_p1 <= d_out_internal[8];
+ rd_done <= rd_done_p1;
+ end
+
+
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ active <= 1'b0;
+ else if ( we_in || we_out )
+ active <= 1'b1;
+ else
+ active <= 1'b0;
+
+dpram dpram_fifo(
+.rstn( rstn ),
+.a_clk( clk ),
+.a_clk_e( 1'b1 ),
+.a_we( we_in ),
+.a_oe( 1'b0 ),
+.a_addr( wr_ptr ),
+.a_din( d_in ),
+.a_dout( ),
+// port B
+.b_clk( clk ),
+.b_clk_e( re ),
+.b_we( 1'b0 ),
+.b_oe( 1'b1 ),
+.b_addr( rd_ptr ),
+.b_din( 9'h0 ),
+.b_dout( d_out_internal )
+);
+
+
+endmodule