/* * drop_fifo.v * * Copyright 2018, 2019, 2020, 2021 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: FIFO that supports dropping data if not kept * */ `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 (writer must be sure FIFO won't run dry during writes) input passthrough, // don't store / delay data, write through instead // input input we_in, input wr_done, input [8:0] d_in, // output 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 on wr_done reg [10:0] rd_ptr; wire [8:0] d_out_internal; reg read_run, read_run_m1; // read continues while read_run is set // read enable for dpram wire i_keep; reg kept; wire fifo_empty; assign i_keep = keep & enable; /* * 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; /* * wr_ptr0 logic */ always @(posedge clk, negedge rstn) if( !rstn ) wr_ptr0 <= 'd0; else if ( we_in ) wr_ptr0 <= wr_ptr0 + 1; /* * wr_ptr1 logic */ 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 /* * rd_ptr logic */ always @(posedge clk, negedge rstn) if( !rstn ) rd_ptr <= 'd0; else if (read_run && !fifo_empty) rd_ptr <= rd_ptr+ 1; /* * 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; /* * we_out logic */ always @(posedge clk, negedge rstn) if( !rstn ) we_out <= 1'b0; else if ( read_run && read_run_m1 ) we_out <= 1'b1; else we_out <= 1'b0; assign fifo_empty = wr_ptr1 == rd_ptr ? 1'b1 : 1'b0; /* * 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