diff options
author | Ian Buckley <ianb@server2.(none)> | 2010-08-19 12:46:04 -0700 |
---|---|---|
committer | Matt Ettus <matt@ettus.com> | 2010-11-11 12:06:12 -0800 |
commit | d4b6fa72eb3fec872a41dea136a5845d3c6ff1ec (patch) | |
tree | 2470f84108a159240250da0fba3ed22da177f24b /usrp2/extramfifo | |
parent | e5cae33e3c5e9ae1821e06af8bf57bc0444605de (diff) | |
download | uhd-d4b6fa72eb3fec872a41dea136a5845d3c6ff1ec.tar.gz uhd-d4b6fa72eb3fec872a41dea136a5845d3c6ff1ec.tar.bz2 uhd-d4b6fa72eb3fec872a41dea136a5845d3c6ff1ec.zip |
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.
Diffstat (limited to 'usrp2/extramfifo')
-rw-r--r-- | usrp2/extramfifo/ext_fifo.v | 29 | ||||
-rw-r--r-- | usrp2/extramfifo/ext_fifo_tb.v | 70 | ||||
-rw-r--r-- | usrp2/extramfifo/nobl_fifo.v | 229 |
3 files changed, 102 insertions, 226 deletions
diff --git a/usrp2/extramfifo/ext_fifo.v b/usrp2/extramfifo/ext_fifo.v index 398e5ef81..c6a64fc65 100644 --- a/usrp2/extramfifo/ext_fifo.v +++ b/usrp2/extramfifo/ext_fifo.v @@ -15,8 +15,10 @@ // packed into the IO ring. // + //`define NO_EXT_FIFO + module ext_fifo - #(parameter INT_WIDTH=36,EXT_WIDTH=18,DEPTH=19) + #(parameter INT_WIDTH=36,EXT_WIDTH=18,RAM_DEPTH=19,FIFO_DEPTH=19) ( input int_clk, input ext_clk, @@ -24,7 +26,7 @@ module ext_fifo input [EXT_WIDTH-1:0] RAM_D_pi, output [EXT_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, @@ -59,16 +61,15 @@ module ext_fifo .empty(empty1)); assign dst_rdy_o = ~full1; - -/* -----\/----- EXCLUDED -----\/----- + +`ifdef NO_EXT_FIFO assign space_avail = ~full2; assign data_avail = ~empty1; assign read_data = write_data; - -----/\----- EXCLUDED -----/\----- */ +`else - // External FIFO running at ext clock rate and 18 bit width. - nobl_fifo #(.WIDTH(EXT_WIDTH),.DEPTH(DEPTH),.FDEPTH(DEPTH)) + nobl_fifo #(.WIDTH(EXT_WIDTH),.RAM_DEPTH(RAM_DEPTH),.FIFO_DEPTH(FIFO_DEPTH)) nobl_fifo_i1 ( .clk(ext_clk), @@ -83,14 +84,14 @@ module ext_fifo .RAM_OEn(RAM_OEn), .RAM_CE1n(RAM_CE1n), .write_data(write_data), - .write_strobe(space_avail & ~empty1 ), + .write_strobe(~empty1 ), .space_avail(space_avail), .read_data(read_data), - .read_strobe(data_avail & ~full2), - .data_avail(data_avail), - .upstream_full(almost_full2) + .read_strobe(~almost_full2), + .data_avail(data_avail) ); - +`endif // !`ifdef NO_EXT_FIFO + // FIFO buffers data read from external FIFO into DSP clk domain and to TX DSP. fifo_xlnx_512x36_2clk_18to36 fifo_xlnx_512x36_2clk_18to36_i1 ( @@ -98,7 +99,7 @@ module ext_fifo .wr_clk(ext_clk), .rd_clk(int_clk), .din(read_data), // Bus [17 : 0] - .wr_en(data_avail & ~full2 ), + .wr_en(data_avail), .rd_en(dst_rdy_i), .dout(dataout), // Bus [35 : 0] .full(full2), @@ -106,5 +107,5 @@ module ext_fifo .empty(empty2)); assign src_rdy_o = ~empty2; - + endmodule // ext_fifo diff --git a/usrp2/extramfifo/ext_fifo_tb.v b/usrp2/extramfifo/ext_fifo_tb.v index a93d524d5..db5f31a9d 100644 --- a/usrp2/extramfifo/ext_fifo_tb.v +++ b/usrp2/extramfifo/ext_fifo_tb.v @@ -1,7 +1,8 @@ `timescale 1ns / 1ps `define INT_WIDTH 36 `define EXT_WIDTH 18 -`define DEPTH 19 +`define RAM_DEPTH 19 +`define FIFO_DEPTH 8 `define DUMP_VCD_FULL module ext_fifo_tb(); @@ -17,7 +18,7 @@ module ext_fifo_tb(); wire [`EXT_WIDTH-1:0] RAM_D_po; wire [`EXT_WIDTH-1:0] RAM_D; wire RAM_D_poe; - wire [`DEPTH-1:0] RAM_A; + wire [`RAM_DEPTH-1:0] RAM_A; wire RAM_WEn; wire RAM_CENn; wire RAM_LDn; @@ -30,6 +31,7 @@ module ext_fifo_tb(); reg [`INT_WIDTH-1:0] ref_dataout; wire src_rdy_o; // not EMPTY reg dst_rdy_i; + integer ether_frame; // Clocks @@ -39,7 +41,6 @@ module ext_fifo_tb(); begin int_clk <= 0; ext_clk <= 0; - datain <= 0; ref_dataout <= 1; src_rdy_i <= 0; dst_rdy_i <= 0; @@ -53,6 +54,9 @@ module ext_fifo_tb(); initial begin + datain <= 0; + ether_frame <= 0; + rst <= 1; repeat (5) @(negedge int_clk); rst <= 0; @@ -62,6 +66,18 @@ module ext_fifo_tb(); @(negedge int_clk); datain <= datain + dst_rdy_o; src_rdy_i <= dst_rdy_o; + // Simulate inter-frame time + if (ether_frame == 1500) + begin + ether_frame <= 0; + repeat(1600) + begin + @(negedge int_clk); + src_rdy_i <= 0; + end + end + else + ether_frame <= ether_frame + dst_rdy_o; end end // initial begin @@ -73,8 +89,20 @@ module ext_fifo_tb(); // Fall through fifo, first output already valid if (dataout !== ref_dataout) $display("Error: Expected %x, got %x",ref_dataout, dataout); - - while (ref_dataout < 10000) + // Decimate by 16 rate + while (ref_dataout < 2000) + begin + @(negedge int_clk); + ref_dataout <= ref_dataout + src_rdy_o ; + dst_rdy_i <= src_rdy_o; + if ((dataout !== ref_dataout) && src_rdy_o) + $display("Error: Expected %x, got %x",ref_dataout, dataout); + @(negedge int_clk); + dst_rdy_i <= 0; + repeat(14) @(negedge int_clk); + end // while (ref_dataout < 10000) + // Decimate by 8 rate + while (ref_dataout < 4000) begin @(negedge int_clk); ref_dataout <= ref_dataout + src_rdy_o ; @@ -84,7 +112,33 @@ module ext_fifo_tb(); @(negedge int_clk); dst_rdy_i <= 0; repeat(6) @(negedge int_clk); - end + end // while (ref_dataout < 10000) + // Decimate by 4 rate + while (ref_dataout < 6000) + begin + @(negedge int_clk); + ref_dataout <= ref_dataout + src_rdy_o ; + dst_rdy_i <= src_rdy_o; + if ((dataout !== ref_dataout) && src_rdy_o) + $display("Error: Expected %x, got %x",ref_dataout, dataout); + @(negedge int_clk); + dst_rdy_i <= 0; + repeat(2) @(negedge int_clk); + end // while (ref_dataout < 10000) + // Max rate + while (ref_dataout < 10000) + begin + @(negedge int_clk); + ref_dataout <= ref_dataout + src_rdy_o ; + dst_rdy_i <= src_rdy_o; + if ((dataout !== ref_dataout) && src_rdy_o) + $display("Error: Expected %x, got %x",ref_dataout, dataout); + + end // while (ref_dataout < 10000) + + @(negedge int_clk); + $finish; + end @@ -228,7 +282,7 @@ module ext_fifo_tb(); endgenerate - wire [`DEPTH-1:0] RAM_A_ext; + wire [`RAM_DEPTH-1:0] RAM_A_ext; wire RAM_WEn_ext,RAM_LDn_ext,RAM_CE1n_ext,RAM_OEn_ext,RAM_CENn_ext; assign #1 RAM_D_pi = RAM_D_pi_ext; @@ -292,7 +346,7 @@ module ext_fifo_tb(); ext_fifo - #(.INT_WIDTH(`INT_WIDTH),.EXT_WIDTH(`EXT_WIDTH),.DEPTH(`DEPTH)) + #(.INT_WIDTH(`INT_WIDTH),.EXT_WIDTH(`EXT_WIDTH),.RAM_DEPTH(`RAM_DEPTH),.FIFO_DEPTH(`FIFO_DEPTH)) ext_fifo_i1 ( .int_clk(int_clk), 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 |