From 12755e4e822441b73aad4ca3fdfbb157a3a86477 Mon Sep 17 00:00:00 2001 From: Ian Buckley Date: Thu, 19 Aug 2010 12:46:04 -0700 Subject: Regenerated FIFO with lower trigger level for almost full flag to reflect logic removed from nobl_fifo. Improved ext_fifo_tb further, try to simulate more combinations of decomation rates and packet arrival patterns. Strip out the logic in nobl_fifo that made it look like a Xilinx fall-through FIFO...it is now very simple logic but a propriatory interface that exposes the high inetrnal latency of reads. Allow the USED size of the external FIFO to be parameterized from the core level. Currently set at only 256 Corrected a bug in vita_tx_deframer.v that can write to a FIFO when its full causing illegal state. Made further edits that are currently commented becuase simulation indicates they cause problems, however suspect a further bug is in this code. --- usrp2/extramfifo/nobl_fifo.v | 229 +++++-------------------------------------- 1 file changed, 25 insertions(+), 204 deletions(-) (limited to 'usrp2/extramfifo/nobl_fifo.v') diff --git a/usrp2/extramfifo/nobl_fifo.v b/usrp2/extramfifo/nobl_fifo.v index 03e3f5223..19f5fb84e 100644 --- a/usrp2/extramfifo/nobl_fifo.v +++ b/usrp2/extramfifo/nobl_fifo.v @@ -1,18 +1,19 @@ // Since this FIFO uses a ZBT/NoBL SRAM for its storage which is a since port // device it can only sustain data throughput at half the RAM clock rate. // Fair arbitration to ensure this occurs is included in this logic and -// requests for transactions that can not be completed are held off by (re)using the -// "full" and "empty" flags. +// requests for transactions that can not be completed are held off. +// This FIFO requires a an external signal driving read_strobe that assures space for at least 6 +// reads since this the theopretical maximum number in flight due to pipeling. module nobl_fifo - #(parameter WIDTH=18,DEPTH=19,FDEPTH=10) + #(parameter WIDTH=18,RAM_DEPTH=19,FIFO_DEPTH=19) ( input clk, input rst, input [WIDTH-1:0] RAM_D_pi, output [WIDTH-1:0] RAM_D_po, output RAM_D_poe, - output [DEPTH-1:0] RAM_A, + output [RAM_DEPTH-1:0] RAM_A, output RAM_WEn, output RAM_CENn, output RAM_LDn, @@ -21,42 +22,32 @@ module nobl_fifo input [WIDTH-1:0] write_data, input write_strobe, output reg space_avail, - output reg [WIDTH-1:0] read_data, - input read_strobe, - output reg data_avail, - input upstream_full // (Connect to almost full flag upstream) + output [WIDTH-1:0] read_data, + input read_strobe, // Triggers a read, result in approximately 6 cycles. + output data_avail // Qulaifys read data available this cycle on read_data. ); - reg [FDEPTH-1:0] capacity; - reg [FDEPTH-1:0] wr_pointer; - reg [FDEPTH-1:0] rd_pointer; - wire [DEPTH-1:0] address; - reg supress; - reg data_avail_int; // Data available with high latency from ext FIFO flag - wire [WIDTH-1:0] data_in; - wire data_in_valid; - reg [WIDTH-1:0] read_data_pending; - reg pending_avail; - wire read_strobe_int; + reg [FIFO_DEPTH-1:0] capacity; + reg [FIFO_DEPTH-1:0] wr_pointer; + reg [FIFO_DEPTH-1:0] rd_pointer; + wire [RAM_DEPTH-1:0] address; + reg data_avail_int; // Internal not empty flag. - - - assign read = read_strobe_int && data_avail_int; - assign write = write_strobe && space_avail; + assign read = read_strobe && data_avail_int; + assign write = write_strobe && space_avail; - // When a read and write collision occur, supress the availability flags next cycle + // When a read and write collision occur, supress the space_avail flag next cycle // and complete write followed by read over 2 cycles. This forces balanced arbitration // and makes for a simple logic design. always @(posedge clk) if (rst) begin - capacity <= 1 << (FDEPTH-1); + capacity <= 1 << (FIFO_DEPTH-1); wr_pointer <= 0; rd_pointer <= 0; space_avail <= 0; data_avail_int <= 0; - supress <= 0; end else begin @@ -64,187 +55,15 @@ module nobl_fifo // Capacity is already zero; Capacity is 1 and write is asserted (lookahead); both read and write are asserted (collision) space_avail <= ~((capacity == 0) || (read&&write) || ((capacity == 1) && write) ); // Capacity has 1 cycle delay so look ahead here for corner case of read of last item in FIFO. - data_avail_int <= ~((capacity == (1 << (FDEPTH-1))) || (read&&write) || ((capacity == ((1 << (FDEPTH-1))-1)) && read) ); - supress <= read && write; + data_avail_int <= ~((capacity == (1 << (FIFO_DEPTH-1))) || ((capacity == ((1 << (FIFO_DEPTH-1))-1)) && read) ); wr_pointer <= wr_pointer + write; - rd_pointer <= rd_pointer + ((~write && read) || supress); - capacity <= capacity - write + ((~write && read) || supress); // REVISIT + rd_pointer <= rd_pointer + (~write && read); + capacity <= capacity - write + (~write && read) ; end // else: !if(rst) assign address = write ? wr_pointer : rd_pointer; - assign enable = write || read || supress; - - // - // Need to have first item in external FIFO moved into local registers for single cycle latency and throughput on read. - // 2 local registers are provided so that a read every other clock cycle can be sustained. - // No fowarding logic is provided to bypass the external FIFO as latency is of no concern. - // - always @(posedge clk) - if (rst) - begin - read_data <= 0; - data_avail <= 0; - read_data_pending <= 0; - pending_avail <= 0; - end - else - begin - case({read_strobe,data_in_valid}) - // No read externally, no new data arriving from external FIFO - 2'b00: begin - case({data_avail,pending_avail}) - // Start Data empty, Pending empty. - // - // End Data full, Pending empty - 2'b00: begin - read_data <= read_data; - data_avail <= data_avail; - read_data_pending <= read_data_pending ; - pending_avail <= pending_avail; - end - // Start Data empty, Pending full. - // Data <= Pending, - // End Data full, Penidng empty. - 2'b01: begin - read_data <= read_data_pending; - data_avail <= 1'b1; - read_data_pending <= read_data_pending ; - pending_avail <= 1'b0; - end - // Start Data full, Pending empty. - // - // End Data full, Pending empty - 2'b10: begin - read_data <= read_data; - data_avail <= data_avail; - read_data_pending <= read_data_pending ; - pending_avail <= pending_avail; - end - // Start Data full, Pending full. - // - // End Data full, Pending full. - 2'b11: begin - read_data <= read_data; - data_avail <= data_avail; - read_data_pending <= read_data_pending ; - pending_avail <= pending_avail; - end - endcase - end - // No read externally, new data arriving from external FIFO - 2'b01: begin - case({data_avail,pending_avail}) - // Start Data empty, Pending empty. - // Data <= FIFO - // End Data full, Pending empty - 2'b00: begin - read_data <= data_in; - data_avail <= 1'b1; - read_data_pending <= read_data_pending ; - pending_avail <= 1'b0; - end - // Start Data empty, Pending full. - // Data <= Pending, Pending <= FIFO - // End Data full, Penidng full. - 2'b01: begin - read_data <= read_data_pending; - data_avail <= 1'b1; - read_data_pending <= data_in ; - pending_avail <= 1'b1; - end - // Start Data full, Pending empty. - // Pending <= FIFO - // End Data full, Pending full - 2'b10: begin - read_data <= read_data; - data_avail <= 1'b1; - read_data_pending <= data_in ; - pending_avail <= 1'b1; - end - // Data full, Pending full. - // *ILLEGAL STATE* - 2'b11: begin - - end - endcase - end - // Read externally, no new data arriving from external FIFO - 2'b10: begin - case({data_avail,pending_avail}) - // Start Data empty, Pending empty. - // *ILLEGAL STATE* - 2'b00: begin - - end - // Start Data empty, Pending full. - // *ILLEGAL STATE* - 2'b01: begin - - end - // Start Data full, Pending empty. - // Out <= Data - // End Data empty, Pending empty. - 2'b10: begin - read_data <= read_data; - data_avail <= 1'b0; - read_data_pending <= read_data_pending ; - pending_avail <= 1'b0; - end - // Start Data full, Pending full. - // Out <= Data, - // End Data full, Pending empty - 2'b11: begin - read_data <= read_data_pending; - data_avail <= 1'b1; - read_data_pending <= read_data_pending ; - pending_avail <= 1'b0; - end - endcase - end - // Read externally, new data arriving from external FIFO - 2'b11: begin - case({data_avail,pending_avail}) - // Start Data empty, Pending empty. - // *ILLEGAL STATE* - 2'b00: begin - - end - // Start Data empty, Pending full. - // *ILLEGAL STATE* - 2'b01: begin - - end - // Start Data full, Pending empty. - // Out <= Data, Data <= FIFO - // End Data full, Pending empty. - 2'b10: begin - read_data <= data_in; - data_avail <= 1'b1; - read_data_pending <= read_data_pending ; - pending_avail <= 1'b0; - end - // Start Data full, Pending full. - // Out <= Data, Data <= Pending, Pending <= FIFO - // End Data full, Pending full - 2'b11: begin - read_data <= read_data_pending; - data_avail <= 1'b1; - read_data_pending <= data_in ; - pending_avail <= 1'b1; - end - endcase - end - endcase - end + assign enable = write || read; - // Start an external FIFO read as soon as a read of the buffer reg is strobed to minimise refill latency. - // If the buffer reg or the pending buffer reg is already empty also pre-emptively start a read. - // However there must be something in the main external FIFO to read for this to occur!. - // Pay special attention to upstream devices signalling full due to the number of potential in-flight reads\ that need - // to be stalled and stored somewhere. - // This means that there can be 3 outstanding reads to the ext FIFO active at any time helping to hide latency. - assign read_strobe_int = (read_strobe && data_avail && ~pending_avail && ~upstream_full) || (~data_avail && ~pending_avail && ~upstream_full); - // // Simple NoBL SRAM interface, 4 cycle read latency. @@ -265,10 +84,12 @@ module nobl_fifo .RAM_CE1n(RAM_CE1n), .address(address), .data_out(write_data), - .data_in(data_in), - .data_in_valid(data_in_valid), + .data_in(read_data), + .data_in_valid(data_avail), .write(write), .enable(enable) ); + + endmodule // nobl_fifo -- cgit v1.2.3