/* * 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