summaryrefslogtreecommitdiffstats
path: root/usrp2/extramfifo/nobl_fifo.v
diff options
context:
space:
mode:
Diffstat (limited to 'usrp2/extramfifo/nobl_fifo.v')
-rw-r--r--usrp2/extramfifo/nobl_fifo.v229
1 files changed, 25 insertions, 204 deletions
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