diff options
Diffstat (limited to 'source/drop2_fifo.v')
-rw-r--r-- | source/drop2_fifo.v | 255 |
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 |