diff options
author | Ian Buckley <ianb@server2.(none)> | 2010-07-29 21:25:26 -0700 |
---|---|---|
committer | Matt Ettus <matt@ettus.com> | 2010-11-11 11:36:09 -0800 |
commit | fb73ea172526319803756b985dd3c104881304b1 (patch) | |
tree | 5f5a6d4da4f24a317395c86586e49ec6b9bb414a /usrp2/extramfifo/nobl_fifo.v | |
parent | d0742cf2a5285ed08d49e16948d8227414247f6a (diff) | |
download | uhd-fb73ea172526319803756b985dd3c104881304b1.tar.gz uhd-fb73ea172526319803756b985dd3c104881304b1.tar.bz2 uhd-fb73ea172526319803756b985dd3c104881304b1.zip |
Checkpoint checkin.
Loopback is running via the external ZBT SRAM...HOWEVER, its not running well, its stable but the data is corrupted sometimes.
Not clear if its a logic or AC timing/SI issue yet.
Diffstat (limited to 'usrp2/extramfifo/nobl_fifo.v')
-rw-r--r-- | usrp2/extramfifo/nobl_fifo.v | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/usrp2/extramfifo/nobl_fifo.v b/usrp2/extramfifo/nobl_fifo.v new file mode 100644 index 000000000..1bd7439ad --- /dev/null +++ b/usrp2/extramfifo/nobl_fifo.v @@ -0,0 +1,264 @@ +module nobl_fifo + #(parameter WIDTH=18,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_WEn, + output RAM_CENn, + output RAM_LDn, + output RAM_OEn, + output RAM_CE1n, + 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 + ); + + reg [DEPTH-1:0] capacity; + reg [DEPTH-1:0] wr_pointer; + reg [DEPTH-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; + + + + assign read = read_strobe_int && data_avail_int; + assign write = write_strobe && space_avail; + + // When a read and write collision occur, supress availability flags 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 << (DEPTH-1); + wr_pointer <= 0; + rd_pointer <= 0; + space_avail <= 0; + data_avail_int <= 0; + supress <= 0; + end + else + begin + 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 << (DEPTH-1))) || (read&&write) || (capacity == ((1 << (DEPTH-1))-1) && read) ); + supress <= read && write; + wr_pointer <= wr_pointer + write; + rd_pointer <= rd_pointer + ((~write && read) || supress); + capacity <= capacity - write + ((~write && read) || supress); // REVISIT + 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 + + // 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 ext FIFO to read. + // This means that there can be 2 outstanding reads to the ext FIFO active at any time helping to hide latency. + assign read_strobe_int = (read_strobe & data_avail & ~pending_avail) || (~data_avail && ~pending_avail); + + + // + // Simple NoBL SRAM interface, 4 cycle read latency. + // Read/Write arbitration via temprary application of empty/full flags. + // + nobl_if nobl_if_i1 + ( + .clk(clk), + .rst(rst), + .RAM_D_pi(RAM_D_pi), + .RAM_D_po(RAM_D_po), + .RAM_D_poe(RAM_D_poe), + .RAM_A(RAM_A), + .RAM_WEn(RAM_WEn), + .RAM_CENn(RAM_CENn), + .RAM_LDn(RAM_LDn), + .RAM_OEn(RAM_OEn), + .RAM_CE1n(RAM_CE1n), + .address(address), + .data_out(write_data), + .data_in(data_in), + .data_in_valid(data_in_valid), + .write(write), + .enable(enable) + ); + +endmodule // nobl_fifo |