summaryrefslogtreecommitdiffhomepage
path: root/source/drop2_fifo.v
diff options
context:
space:
mode:
Diffstat (limited to 'source/drop2_fifo.v')
-rw-r--r--source/drop2_fifo.v255
1 files changed, 255 insertions, 0 deletions
diff --git a/source/drop2_fifo.v b/source/drop2_fifo.v
new file mode 100644
index 0000000..dcadd92
--- /dev/null
+++ b/source/drop2_fifo.v
@@ -0,0 +1,255 @@
+/*
+ * drop2_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
+ * Uses 2 DPRAMs with additional logic for paths involving 1G to 100Mbit
+ *
+ */
+
+`timescale 1ns /10ps
+
+module drop2_fifo(
+ input rstn,
+ input clk,
+ input enable,
+
+ // control (drop, keep, and done are asserted for one clock )
+ input keep, // this packet won't be dropped, start transferring it (KEEPS ARE AND'ED)
+ input passthrough, // don't store 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 the DPRAM
+reg [11:0] wr_ptr;
+reg [11:0] rd_ptr;
+
+wire [8:0] d_out_0, d_out_1, 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;
+
+wire dpram0_a_clk_e, dpram1_a_clk_e;
+wire dpram0_b_clk_e, dpram1_b_clk_e;
+
+/*
+ * 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;
+
+/*
+ * read_run logic
+ * read starts after wr_done
+ * continues until the FIFO is empty
+ */
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ begin
+ read_run <= 1'b0;
+ read_run_m1 <= 1'b0;
+ end
+ else if ( rd_done_p1 )
+ begin
+ read_run <= 1'b0;
+ read_run_m1 <= 1'b0;
+ end
+ else if ( kept && wr_done )
+ begin
+ read_run <= 1'b1;
+ end
+ 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;
+
+/*
+ * upper / lower half DPRAM logic
+ * directs upper or lower write buffer in FIFO
+ * toggle on each done event (rx_data is complete)
+ * don't toggle on a drop event (reuse buffer)
+ */
+always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ wr_ptr[11] <= 1'b0; // init to the lower bank
+ else if ( wr_done && kept )
+ wr_ptr[11] <= ~wr_ptr[11];
+
+/*
+ * wr_ptr logic excluding msbit
+ * reset pointer when wr_done
+ */
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ wr_ptr[10:0] <= 'd0;
+ else if ( wr_done )
+ wr_ptr[10:0] <= 'd0;
+ else if ( we_in )
+ wr_ptr[10:0] <= wr_ptr[10:0] + 1;
+
+/*
+ * each time the FIFO is empty, set rd_ptr[11] to wr_ptr[11]
+ * FIFO becomes empty through reading
+ */
+always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ rd_ptr[11] <= 1'b0; // init to the lower bank
+ else if ( rd_done )
+ rd_ptr[11] <= wr_ptr[11];
+
+/*
+ * rd_ptr logic excluding msbit
+ */
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ rd_ptr[10:0] <= 'd0;
+ else if ( rd_done )
+ rd_ptr[10:0] <= 'd0;
+ else if ( re )
+ rd_ptr[10:0] <= rd_ptr[10: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
+
+// debug
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ active <= 1'b0;
+ else if ( we_in || we_out )
+ active <= 1'b1;
+ else
+ active <= 1'b0;
+
+assign dpram0_a_clk_e = ~wr_ptr[11];
+assign dpram1_a_clk_e = wr_ptr[11];
+
+assign dpram0_b_clk_e = ~rd_ptr[11];
+assign dpram1_b_clk_e = rd_ptr[11];
+
+assign d_out_internal = dpram0_b_clk_e ? d_out_0 : d_out_1;
+
+
+dpram dpram_0(
+.rstn( rstn ),
+.a_clk( clk ),
+.a_clk_e( dpram0_a_clk_e ),
+.a_we( we_in ),
+.a_oe( 1'b0 ),
+.a_addr( wr_ptr[10:0] ),
+.a_din( d_in ),
+.a_dout( ),
+// port B
+.b_clk( clk ),
+.b_clk_e( dpram0_b_clk_e ),
+.b_we( 1'b0 ),
+.b_oe( re ),
+.b_addr( rd_ptr[10:0] ),
+.b_din( 9'h0 ),
+.b_dout( d_out_0 )
+);
+
+dpram dpram_1(
+ .rstn( rstn ),
+ .a_clk( clk ),
+ .a_clk_e( dpram1_a_clk_e ),
+ .a_we( we_in ),
+ .a_oe( 1'b0 ),
+ .a_addr( wr_ptr[10:0] ),
+ .a_din( d_in ),
+ .a_dout( ),
+ // port B
+ .b_clk( clk ),
+ .b_clk_e( dpram1_b_clk_e ),
+ .b_we( 1'b0 ),
+ .b_oe( re ),
+ .b_addr( rd_ptr[10:0] ),
+ .b_din( 9'h0 ),
+ .b_dout( d_out_1 )
+);
+
+
+endmodule

Highly Recommended Verilog Books