/* * drop_fifo.v * * Copyright 2018, 2019, 2020, 2021 Mind Chasers Inc. * Copyright 2023 Private Island Networks 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: FIFO that supports dropping data if not kept * * For more information, see https://privateisland.tech/dev/pi-doc * */ module drop_fifo( input rstn, input clk, input passthrough, // don't store / delay data, write through instead input enable, // enable the FIFO input keep, // this packet won't be dropped, start transferring it (writer must be sure FIFO won't run dry during writes) // input data input we_in, input [8:0] d_in, input wr_done, // keep should occur before wr_done is asserted. input rx_eop, // output data output reg we_out, output reg [8:0] d_out, // debug output reg active ); // local parameters and includes // nets and registers reg [10:0] wr_ptr0, wr_ptr1; // wr_ptr0 is updated on each write; wr_ptr1 is updated at end of packet reg [10:0] rd_ptr; wire [8:0] d_out_internal; reg read_run, read_run_m1, read_run_m2; // read continues while read_run is set reg kept; wire fifo_empty; /* * kept: assert for length of write duration after keep asserts (when enable is active) */ always @(posedge clk, negedge rstn) if( !rstn ) kept <= 1'b0; else if ( wr_done ) kept <= 1'b0; else if ( keep && enable ) kept <= 1'b1; /* * wr_ptr0 logic */ always @(posedge clk, negedge rstn) if( !rstn ) wr_ptr0 <= 'd0; else if ( we_in ) wr_ptr0 <= wr_ptr0 + 1'b1; /* * wr_ptr1 logic * sync pointers at end of rx packet for next packet */ always @(posedge clk, negedge rstn) if( !rstn ) wr_ptr1 <= 'd0; else if ( wr_done ) wr_ptr1 <= wr_ptr0 +1; // a write takes place with wr_done /* * read_run logic * continues until the FIFO is empty */ always @(posedge clk, negedge rstn) if( !rstn ) read_run <= 1'b0; else if (kept && wr_done) read_run <= 1'b1; else if ( fifo_empty ) read_run <= 1'b0; always @(posedge clk, negedge rstn) if( !rstn ) read_run_m1 <= 1'b0; else read_run_m1 <= read_run; always @(posedge clk, negedge rstn) if( !rstn ) read_run_m2 <= 1'b0; else read_run_m2 <= read_run_m1; /* * rd_ptr logic */ always @(posedge clk, negedge rstn) if( !rstn ) rd_ptr <= 'd0; else if (kept && wr_done) rd_ptr <= wr_ptr1; // set rd_ptr to the beginning of where the write started else if (read_run && !fifo_empty) rd_ptr <= rd_ptr+ 1'b1; /* * we_out logic */ always @(posedge clk, negedge rstn) if( !rstn ) we_out <= 1'b0; else if ( read_run_m1 && read_run_m2 ) we_out <= 1'b1; else we_out <= 1'b0; assign fifo_empty = (wr_ptr1 == rd_ptr); /* * d_out register * */ always @(posedge clk, negedge rstn) if( !rstn ) d_out <= 'd0; else d_out <= d_out_internal; 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_ptr0 ), .a_din( d_in ), .a_dout( ), // port B .b_clk( clk ), .b_clk_e( read_run ), .b_we( 1'b0 ), .b_oe( 1'b1 ), .b_addr( rd_ptr ), .b_din( 9'h0 ), .b_dout( d_out_internal ) ); endmodule