summaryrefslogtreecommitdiffstats
path: root/usrp2/extramfifo/nobl_fifo.v
diff options
context:
space:
mode:
authorIan Buckley <ianb@server2.(none)>2010-07-29 21:25:26 -0700
committerMatt Ettus <matt@ettus.com>2010-11-11 11:36:09 -0800
commitfb73ea172526319803756b985dd3c104881304b1 (patch)
tree5f5a6d4da4f24a317395c86586e49ec6b9bb414a /usrp2/extramfifo/nobl_fifo.v
parentd0742cf2a5285ed08d49e16948d8227414247f6a (diff)
downloaduhd-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.v264
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