aboutsummaryrefslogtreecommitdiffstats
path: root/usrp2/extramfifo
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
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')
-rw-r--r--usrp2/extramfifo/Makefile.srcs16
-rw-r--r--usrp2/extramfifo/ext_fifo.v120
-rw-r--r--usrp2/extramfifo/ext_fifo_tb.cmd11
-rw-r--r--usrp2/extramfifo/ext_fifo_tb.prj9
-rw-r--r--usrp2/extramfifo/ext_fifo_tb.sh1
-rw-r--r--usrp2/extramfifo/ext_fifo_tb.v285
-rw-r--r--usrp2/extramfifo/nobl_fifo.v264
-rw-r--r--usrp2/extramfifo/nobl_if.v136
-rw-r--r--usrp2/extramfifo/test_sram_if.v171
9 files changed, 1013 insertions, 0 deletions
diff --git a/usrp2/extramfifo/Makefile.srcs b/usrp2/extramfifo/Makefile.srcs
new file mode 100644
index 000000000..7cd49f4f6
--- /dev/null
+++ b/usrp2/extramfifo/Makefile.srcs
@@ -0,0 +1,16 @@
+#
+# Copyright 2010 Ettus Research LLC
+#
+
+##################################################
+# Extram Sources
+##################################################
+EXTRAM_SRCS = $(abspath $(addprefix $(BASE_DIR)/../extramfifo/, \
+ext_fifo.v \
+nobl_if.v \
+nobl_fifo.v \
+icon.v \
+icon.xco \
+ila.v \
+ila.xco \
+))
diff --git a/usrp2/extramfifo/ext_fifo.v b/usrp2/extramfifo/ext_fifo.v
new file mode 100644
index 000000000..55935146a
--- /dev/null
+++ b/usrp2/extramfifo/ext_fifo.v
@@ -0,0 +1,120 @@
+module ext_fifo
+ #(parameter INT_WIDTH=36,EXT_WIDTH=18,DEPTH=19)
+ (
+ input int_clk,
+ input ext_clk,
+ input rst,
+ 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_WEn,
+ output RAM_CENn,
+ output RAM_LDn,
+ output RAM_OEn,
+ output RAM_CE1n,
+ input [INT_WIDTH-1:0] datain,
+ input src_rdy_i, // WRITE
+ output dst_rdy_o, // not FULL
+ output [INT_WIDTH-1:0] dataout,
+ output src_rdy_o, // not EMPTY
+ input dst_rdy_i // READ
+ );
+
+ wire [EXT_WIDTH-1:0] write_data;
+ wire [EXT_WIDTH-1:0] read_data;
+ wire full1, empty1;
+ wire full2, empty2;
+
+
+ // FIFO buffers data from UDP engine into external FIFO clock domain.
+ fifo_xlnx_512x36_2clk_36to18 fifo_xlnx_512x36_2clk_36to18_i1 (
+ .rst(rst),
+ .wr_clk(int_clk),
+ .rd_clk(ext_clk),
+ .din(datain), // Bus [35 : 0]
+ .wr_en(src_rdy_i),
+ .rd_en(space_avail&~empty1),
+ // .rd_en(~full2&~empty1),
+ .dout(write_data), // Bus [17 : 0]
+ .full(full1),
+ .empty(empty1));
+ assign dst_rdy_o = ~full1;
+
+
+
+ // External FIFO running at ext clock rate and 18 bit width.
+ nobl_fifo #(.WIDTH(EXT_WIDTH),.DEPTH(DEPTH))
+ nobl_fifo_i1
+ (
+ .clk(ext_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),
+ .write_data(write_data),
+ .write_strobe(space_avail & ~empty1 ),
+ .space_avail(space_avail),
+ .read_data(read_data),
+ .read_strobe(data_avail & ~full2),
+ .data_avail(data_avail)
+ );
+
+
+
+ // 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 (
+ .rst(rst),
+ .wr_clk(ext_clk),
+ .rd_clk(int_clk),
+ .din(read_data), // Bus [17 : 0]
+ // .din(write_data), // Bus [17 : 0]
+ .wr_en(data_avail & ~full2 ),
+ // .wr_en(~full2&~empty1),
+ .rd_en(dst_rdy_i),
+ .dout(dataout), // Bus [35 : 0]
+ .full(full2),
+ .empty(empty2));
+ assign src_rdy_o = ~empty2;
+
+
+
+ wire [35:0] CONTROL0;
+ reg [7:0] datain_reg,write_data_reg,read_data_reg ;
+ reg space_avail_reg,data_avail_reg,empty1_reg,full2_reg ;
+
+ always @(posedge ext_clk)
+ begin
+ //datain_reg <= datain[7:0];
+ write_data_reg <= write_data[7:0];
+ read_data_reg <= read_data[7:0];
+ space_avail_reg <= space_avail;
+ data_avail_reg <= data_avail;
+ empty1_reg <= empty1;
+ full2_reg <= full2;
+ end
+
+
+ icon icon_i1
+ (
+ .CONTROL0(CONTROL0)
+ );
+
+ ila ila_i1
+ (
+ .CLK(ext_clk),
+ .CONTROL(CONTROL0),
+ // .TRIG0(address_reg),
+ .TRIG0(write_data_reg[7:0]),
+ .TRIG1(read_data_reg[7:0]),
+ .TRIG2(0),
+ .TRIG3({space_avail_reg,data_avail_reg,empty1_reg,full2_reg})
+ );
+
+endmodule // ext_fifo
diff --git a/usrp2/extramfifo/ext_fifo_tb.cmd b/usrp2/extramfifo/ext_fifo_tb.cmd
new file mode 100644
index 000000000..b0ab830dc
--- /dev/null
+++ b/usrp2/extramfifo/ext_fifo_tb.cmd
@@ -0,0 +1,11 @@
+/opt/Xilinx/12.1/ISE_DS/ISE/verilog/src/glbl.v
+-y .
+-y ../coregen/
+-y ../models
+-y /home/ianb/usrp-fpga/usrp2/sdr_lib
+-y /home/ianb/usrp-fpga/usrp2/control_lib
+-y /home/ianb/usrp-fpga/usrp2/models
+-y /opt/Xilinx/12.1/ISE_DS/ISE/verilog/src/unisims
+-y /opt/Xilinx/12.1/ISE_DS/ISE/verilog/src
+-y /opt/Xilinx/12.1/ISE_DS/ISE/verilog/src/XilinxCoreLib
+
diff --git a/usrp2/extramfifo/ext_fifo_tb.prj b/usrp2/extramfifo/ext_fifo_tb.prj
new file mode 100644
index 000000000..a11a15b2f
--- /dev/null
+++ b/usrp2/extramfifo/ext_fifo_tb.prj
@@ -0,0 +1,9 @@
+verilog work "./ext_fifo_tb.v"
+verilog work "./ext_fifo.v"
+verilog work "./nobl_fifo.v"
+verilog work "./nobl_if.v"
+verilog work "../coregen/fifo_xlnx_512x36_2clk_36to18.v"
+verilog work "../coregen/fifo_xlnx_512x36_2clk_18to36.v"
+verilog work "../models/CY7C1356C/cy1356.v"
+verilog work "../models/idt71v65603s150.v"
+verilog work "$XILINX/verilog/src/glbl.v"
diff --git a/usrp2/extramfifo/ext_fifo_tb.sh b/usrp2/extramfifo/ext_fifo_tb.sh
new file mode 100644
index 000000000..a56574102
--- /dev/null
+++ b/usrp2/extramfifo/ext_fifo_tb.sh
@@ -0,0 +1 @@
+fuse -prj ext_fifo_tb.prj -t work.glbl -t work.ext_fifo_tb -L unisims_ver -L xilinxcorelib_ver -o ext_fifo_tb
diff --git a/usrp2/extramfifo/ext_fifo_tb.v b/usrp2/extramfifo/ext_fifo_tb.v
new file mode 100644
index 000000000..aa1fd6e3c
--- /dev/null
+++ b/usrp2/extramfifo/ext_fifo_tb.v
@@ -0,0 +1,285 @@
+`timescale 1ns / 1ps
+`define INT_WIDTH 36
+`define EXT_WIDTH 18
+`define DEPTH 19
+`define DUMP_VCD_FULL
+
+module ext_fifo_tb();
+
+
+ reg int_clk;
+ reg ext_clk;
+ reg rst;
+
+
+
+ wire [`EXT_WIDTH-1:0] RAM_D_pi;
+ 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_WEn;
+ wire RAM_CENn;
+ wire RAM_LDn;
+ wire RAM_OEn;
+ wire RAM_CE1n;
+ reg [`INT_WIDTH-1:0] datain;
+ reg src_rdy_i; // WRITE
+ wire dst_rdy_o; // not FULL
+ wire [`INT_WIDTH-1:0] dataout;
+ reg [`INT_WIDTH-1:0] ref_dataout;
+ wire src_rdy_o; // not EMPTY
+ reg dst_rdy_i;
+
+
+ // Clocks
+ // Int clock is 100MHz
+ // Ext clock is 125MHz
+ initial
+ begin
+ int_clk <= 0;
+ ext_clk <= 0;
+ datain <= 0;
+ ref_dataout <= 1;
+ src_rdy_i <= 0;
+ dst_rdy_i <= 0;
+ end
+
+ always
+ #5 int_clk <= ~int_clk;
+
+ always
+ #4 ext_clk <= ~ext_clk;
+
+
+ initial
+ begin
+ rst <= 1;
+ repeat (5) @(negedge int_clk);
+ rst <= 0;
+ @(negedge int_clk);
+ repeat (1000)
+ begin
+ @(negedge int_clk);
+ datain <= datain + 1;
+ src_rdy_i <= 1;
+ @(negedge int_clk);
+ src_rdy_i <= 0;
+// @(negedge int_clk);
+// dst_rdy_i <= src_rdy_o;
+// @(negedge int_clk);
+// dst_rdy_i <= 0;
+ repeat (2) @(negedge int_clk);
+ end // repeat (1000)
+ // Fall through fifo, first output already valid
+ if (dataout !== ref_dataout)
+ $display("Error: Expected %x, got %x",ref_dataout, dataout);
+ repeat (1000)
+ begin
+ @(negedge int_clk);
+ datain <= datain + 1;
+ src_rdy_i <= 1;
+ @(negedge int_clk);
+ src_rdy_i <= 0;
+ @(negedge int_clk);
+ ref_dataout <= ref_dataout + 1;
+ dst_rdy_i <= src_rdy_o;
+ @(negedge int_clk);
+ if (dataout !== ref_dataout)
+ $display("Error: Expected %x, got %x",ref_dataout, dataout);
+ dst_rdy_i <= 0;
+// repeat (2) @(negedge int_clk);
+ end // repeat (1000)
+ repeat (1000)
+ begin
+// @(negedge int_clk);
+// datain <= datain + 1;
+// src_rdy_i <= 1;
+// @(negedge int_clk);
+// src_rdy_i <= 0;
+ @(negedge int_clk);
+ ref_dataout <= ref_dataout + 1;
+ dst_rdy_i <= src_rdy_o;
+ @(negedge int_clk);
+ if (dataout !== ref_dataout)
+ $display("Error: Expected %x, got %x",ref_dataout, dataout);
+ dst_rdy_i <= 0;
+// repeat (2) @(negedge int_clk);
+ end // repeat (1000)
+
+ $finish;
+
+ end // initial begin
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Simulation control //
+ ///////////////////////////////////////////////////////////////////////////////////
+ `ifdef DUMP_LX2_TOP
+ // Set up output files
+ initial begin
+ $dumpfile("ext_fifo_tb.lx2");
+ $dumpvars(1,ext_fifo_tb);
+ end
+ `endif
+
+ `ifdef DUMP_LX2_FULL
+ // Set up output files
+ initial begin
+ $dumpfile("ext_fifo_tb.lx2");
+ $dumpvars(0,ext_fifo_tb);
+ end
+ `endif
+
+ `ifdef DUMP_VCD_TOP
+ // Set up output files
+ initial begin
+ $dumpfile("ext_fifo_tb.vcd");
+ $dumpvars(1,ext_fifo_tb);
+ end
+ `endif
+
+ `ifdef DUMP_VCD_TOP_PLUS_NEXT
+ // Set up output files
+ initial begin
+ $dumpfile("ext_fifo_tb.vcd");
+ $dumpvars(2,ext_fifo_tb);
+ end
+ `endif
+
+
+ `ifdef DUMP_VCD_FULL
+ // Set up output files
+ initial begin
+ $dumpfile("ext_fifo_tb.vcd");
+ $dumpvars(0,ext_fifo_tb);
+ end
+ `endif
+
+ // Update display every 10 us
+ always #10000 $monitor("Time in uS ",$time/1000);
+
+ wire [`EXT_WIDTH-1:0] RAM_D_pi_ext;
+ wire [`EXT_WIDTH-1:0] RAM_D_po_ext;
+ wire [`EXT_WIDTH-1:0] RAM_D_ext;
+ wire RAM_D_poe_ext;
+
+ genvar i;
+
+ //
+ // Instantiate IO for Bidirectional bus to SRAM
+ //
+
+ generate
+ for (i=0;i<18;i=i+1)
+ begin : gen_RAM_D_IO
+
+ IOBUF #(
+ .DRIVE(12),
+ .IOSTANDARD("LVCMOS25"),
+ .SLEW("FAST")
+ )
+ RAM_D_i (
+ .O(RAM_D_pi_ext[i]),
+ .I(RAM_D_po_ext[i]),
+ .IO(RAM_D[i]),
+ .T(RAM_D_poe_ext)
+ );
+ end // block: gen_RAM_D_IO
+
+ endgenerate
+
+ wire [`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;
+
+ assign #1 RAM_D_po_ext = RAM_D_po;
+
+ assign #1 RAM_D_poe_ext = RAM_D_poe;
+
+ assign #2 RAM_WEn_ext = RAM_WEn;
+
+ assign #2 RAM_LDn_ext = RAM_LDn;
+
+ assign #2 RAM_CE1n_ext = RAM_CE1n;
+
+ assign #2 RAM_OEn_ext = RAM_OEn;
+
+ assign #2 RAM_CENn_ext = RAM_CENn;
+
+ assign #2 RAM_A_ext = RAM_A;
+
+/* -----\/----- EXCLUDED -----\/-----
+ wire [13:0] temp1;
+ assign temp1 = 14'h0;
+ wire [3:0] temp2;
+ assign temp2 = 4'h0;
+ -----/\----- EXCLUDED -----/\----- */
+
+
+ idt71v65603s150 idt71v65603s150_i1
+ (
+ .A(RAM_A_ext[17:0]),
+ .adv_ld_(RAM_LDn_ext), // advance (high) / load (low)
+ .bw1_(1'b0),
+ .bw2_(1'b0),
+ .bw3_(1'b1),
+ .bw4_(1'b1), // byte write enables (low)
+ .ce1_(RAM_CE1n_ext),
+ .ce2(1'b1),
+ .ce2_(1'b0), // chip enables
+ .cen_(RAM_CENn_ext), // clock enable (low)
+ .clk(ext_clk), // clock
+ .IO({RAM_D[16:9],RAM_D[7:0]}),
+ .IOP({RAM_D[17],RAM_D[8]}), // data bus
+ .lbo_(1'b0), // linear burst order (low)
+ .oe_(RAM_OEn_ext), // output enable (low)
+ .r_w_(RAM_WEn_ext)
+ ); // read (high) / write (low)
+
+/* -----\/----- EXCLUDED -----\/-----
+
+
+ cy1356 cy1356_i1
+ ( .d(RAM_D),
+ .clk(ext_clk),
+ .a(RAM_A_ext),
+ .bws(2'b00),
+ .we_b(RAM_WEn_ext),
+ .adv_lb(RAM_LDn_ext),
+ .ce1b(RAM_CE1n_ext),
+ .ce2(1'b1),
+ .ce3b(1'b0),
+ .oeb(RAM_OEn_ext),
+ .cenb(RAM_CENn_ext),
+ .mode(1'b0)
+ );
+ -----/\----- EXCLUDED -----/\----- */
+
+
+ ext_fifo
+ #(.INT_WIDTH(`INT_WIDTH),.EXT_WIDTH(`EXT_WIDTH),.DEPTH(`DEPTH))
+ ext_fifo_i1
+ (
+ .int_clk(int_clk),
+ .ext_clk(ext_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),
+ .datain(datain),
+ .src_rdy_i(src_rdy_i), // WRITE
+ .dst_rdy_o(dst_rdy_o), // not FULL
+ .dataout(dataout),
+ .src_rdy_o(src_rdy_o), // not EMPTY
+ .dst_rdy_i(dst_rdy_i)
+ );
+
+endmodule // ext_fifo_tb
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
diff --git a/usrp2/extramfifo/nobl_if.v b/usrp2/extramfifo/nobl_if.v
new file mode 100644
index 000000000..3143ce5ba
--- /dev/null
+++ b/usrp2/extramfifo/nobl_if.v
@@ -0,0 +1,136 @@
+module nobl_if
+ #(parameter WIDTH=18,DEPTH=19)
+ (
+ input clk,
+ input rst,
+ input [WIDTH-1:0] RAM_D_pi,
+ output [WIDTH-1:0] RAM_D_po,
+ output reg 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 [DEPTH-1:0] address,
+ input [WIDTH-1:0] data_out,
+ output reg [WIDTH-1:0] data_in,
+ output reg data_in_valid,
+ input write,
+ input enable
+ );
+
+
+ reg enable_pipe1;
+ reg [DEPTH-1:0] address_pipe1;
+ reg write_pipe1;
+ reg [WIDTH-1:0] data_out_pipe1;
+
+ reg enable_pipe2;
+ reg write_pipe2;
+ reg [WIDTH-1:0] data_out_pipe2;
+
+ reg enable_pipe3;
+ reg write_pipe3;
+ reg [WIDTH-1:0] data_out_pipe3;
+
+ assign RAM_LDn = 0;
+ assign RAM_OEn = 0;
+
+
+ //
+ // Pipeline stage 1
+ //
+ always @(posedge clk)
+ if (rst)
+ begin
+ enable_pipe1 <= 0;
+ address_pipe1 <= 0;
+ write_pipe1 <= 0;
+ data_out_pipe1 <= 0;
+ end
+ else
+ begin
+ enable_pipe1 <= enable;
+
+ if (enable)
+ begin
+ address_pipe1 <= address;
+ write_pipe1 <= write;
+
+ if (write)
+ data_out_pipe1 <= data_out;
+ end
+ end // always @ (posedge clk)
+
+ // Pipeline 1 drives address, write_enable, chip_select on NoBL SRAM
+ assign RAM_A = address_pipe1;
+ assign RAM_CENn = 1'b0;
+ assign RAM_WEn = ~write_pipe1;
+ assign RAM_CE1n = ~enable_pipe1;
+
+ //
+ // Pipeline stage2
+ //
+ always @(posedge clk)
+ if (rst)
+ begin
+ enable_pipe2 <= 0;
+ data_out_pipe2 <= 0;
+ write_pipe2 <= 0;
+ end
+ else
+ begin
+ data_out_pipe2 <= data_out_pipe1;
+ write_pipe2 <= write_pipe1;
+ enable_pipe2 <= enable_pipe1;
+ end
+
+ //
+ // Pipeline stage3
+ //
+ always @(posedge clk)
+ if (rst)
+ begin
+ enable_pipe3 <= 0;
+ data_out_pipe3 <= 0;
+ write_pipe3 <= 0;
+ RAM_D_poe <= 0;
+ end
+ else
+ begin
+ data_out_pipe3 <= data_out_pipe2;
+ write_pipe3 <= write_pipe2;
+ enable_pipe3 <= enable_pipe2;
+ RAM_D_poe <= ~(write_pipe2 & enable_pipe2); // Active low driver enable in Xilinx.
+ end
+
+ // Pipeline 3 drives write data on NoBL SRAM
+ assign RAM_D_po = data_out_pipe3;
+
+
+ //
+ // Pipeline stage4
+ //
+ always @(posedge clk)
+ if (rst)
+ begin
+ data_in_valid <= 0;
+ data_in <= 0;
+ end
+ else
+ begin
+ data_in <= RAM_D_pi;
+ if (enable_pipe3 & ~write_pipe3)
+ begin
+ // Read data now available to be registered.
+ data_in_valid <= 1'b1;
+ end
+ else
+ data_in_valid <= 1'b0;
+ end // always @ (posedge clk)
+
+
+
+
+endmodule // nobl_if
diff --git a/usrp2/extramfifo/test_sram_if.v b/usrp2/extramfifo/test_sram_if.v
new file mode 100644
index 000000000..9f36b409c
--- /dev/null
+++ b/usrp2/extramfifo/test_sram_if.v
@@ -0,0 +1,171 @@
+`define WIDTH 18
+`define DEPTH 19
+
+module test_sram_if
+ (
+ 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,
+ output reg correct
+ );
+
+ reg [`DEPTH-1:0] write_count;
+ reg [`DEPTH-1:0] read_count;
+ reg enable;
+ reg write;
+ reg write_cycle;
+ reg read_cycle;
+ reg enable_reads;
+ reg [18:0] address;
+ reg [17:0] data_out;
+ wire [17:0] data_in;
+ wire data_in_valid;
+
+ reg [17:0] check_data;
+ reg [17:0] check_data_old;
+ reg [17:0] check_data_old2;
+
+ //
+ // Create counter that generates both external modulo 2^19 address and modulo 2^18 data to test RAM.
+ //
+
+ always @(posedge clk)
+ if (rst)
+ begin
+ write_count <= 19'h0;
+ read_count <= 19'h0;
+ end
+ else if (write_cycle) // Write cycle
+ if (write_count == 19'h7FFFF)
+ begin
+ write_count <= 19'h0;
+ end
+ else
+ begin
+ write_count <= write_count + 1'b1;
+ end
+ else if (read_cycle) // Read cycle
+ if (read_count == 19'h7FFFF)
+ begin
+ read_count <= 19'h0;
+ end
+ else
+ begin
+ read_count <= read_count + 1'b1;
+ end
+
+ always @(posedge clk)
+ if (rst)
+ begin
+ enable_reads <= 0;
+ read_cycle <= 0;
+ write_cycle <= 0;
+ end
+ else
+ begin
+ write_cycle <= ~write_cycle;
+ if (enable_reads)
+ read_cycle <= write_cycle;
+ if (write_count == 15) // Enable reads 15 writes after reset terminates.
+ enable_reads <= 1;
+ end // else: !if(rst)
+
+ always @(posedge clk)
+ if (rst)
+ begin
+ enable <= 0;
+ end
+ else if (write_cycle)
+ begin
+ address <= write_count;
+ data_out <= write_count[17:0];
+ enable <= 1;
+ write <= 1;
+ end
+ else if (read_cycle)
+ begin
+ address <= read_count;
+ check_data <= read_count[17:0];
+ check_data_old <= check_data;
+ check_data_old2 <= check_data_old;
+ enable <= 1;
+ write <= 0;
+ end
+ else
+ enable <= 0;
+
+ always @(posedge clk)
+ if (data_in_valid)
+ begin
+ correct <= (data_in == check_data_old2);
+ end
+
+
+ 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(data_out),
+ .data_in(data_in),
+ .data_in_valid(data_in_valid),
+ .write(write),
+ .enable(enable)
+ );
+
+
+ wire [35:0] CONTROL0;
+ reg [7:0] data_in_reg, data_out_reg, address_reg;
+ reg data_in_valid_reg,write_reg,enable_reg,correct_reg;
+
+ always @(posedge clk)
+ begin
+ data_in_reg <= data_in[7:0];
+ data_out_reg <= data_out[7:0];
+ data_in_valid_reg <= data_in_valid;
+ write_reg <= write;
+ enable_reg <= enable;
+ correct_reg <= correct;
+ address_reg <= address;
+
+ end
+
+
+ icon icon_i1
+ (
+ .CONTROL0(CONTROL0)
+ );
+
+ ila ila_i1
+ (
+ .CLK(clk),
+ .CONTROL(CONTROL0),
+ // .TRIG0(address_reg),
+ .TRIG0(data_in_reg[7:0]),
+ .TRIG1(data_out_reg[7:0]),
+ .TRIG2(address_reg[7:0]),
+ .TRIG3({data_in_valid_reg,write_reg,enable_reg,correct_reg})
+ );
+
+
+
+endmodule // test_sram_if
+
+ \ No newline at end of file