summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usrp2/fpga/control_lib/giantfifo.v209
-rw-r--r--usrp2/fpga/control_lib/giantfifo_tb.v173
2 files changed, 382 insertions, 0 deletions
diff --git a/usrp2/fpga/control_lib/giantfifo.v b/usrp2/fpga/control_lib/giantfifo.v
new file mode 100644
index 000000000..dba330b8a
--- /dev/null
+++ b/usrp2/fpga/control_lib/giantfifo.v
@@ -0,0 +1,209 @@
+
+
+
+module giantfifo
+ #(parameter WIDTH=36)
+ (input clk, input rst,
+ input [WIDTH-1:0] datain,
+ output [WIDTH-1:0] dataout,
+ input read,
+ input write,
+ input clear,
+ output full,
+ output empty,
+ output [15:0] space,
+ output [15:0] occupied,
+
+ // External RAM
+ inout [17:0] RAM_D,
+ output reg [18:0] RAM_A,
+ output RAM_CE1n,
+ output RAM_CENn,
+ output reg RAM_CLK,
+ output reg RAM_WEn,
+ output RAM_OEn,
+ output RAM_LDn
+ );
+
+ wire [4:0] path1_occ, path2_space;
+ wire [35:0] path1_dat, path2_dat;
+
+ shortfifo #(.WIDTH(WIDTH)) sf1
+ (.clk(clk),.rst(rst),.clear(clear),
+ .datain(datain),.write(write),.full(full),
+ .dataout(path1_dat),.read(path1_read),.empty(path1_empty),
+ .space(),.occupied(path1_occ) );
+ wire path1_almost_empty = (path1_occ == 5'd1);
+
+ shortfifo #(.WIDTH(WIDTH)) sf2
+ (.clk(clk),.rst(rst),.clear(clear),
+ .datain(path2_dat),.write(path2_write),.full(path2_full),
+ .dataout(dataout),.read(read),.empty(empty),
+ .space(path2_space),.occupied() );
+ wire path2_almost_full = (path2_space == 5'd1);
+
+ assign RAM_CE1n = 1'b0;
+ assign RAM_CENn = 1'b0;
+ always @(clk)
+ RAM_CLK <= #2 clk;
+ assign RAM_LDn = 1'b0;
+
+ // State machine
+ wire write_now, read_now, idle, phase;
+ reg ram_full, ram_empty;
+
+ reg [17:0] read_ptr, write_ptr;
+ reg [2:0] zbt_state;
+
+ localparam ZBT_IDLE = 0;
+ localparam ZBT_WRITE_UPPER = 2;
+ localparam ZBT_WRITE_LOWER = 3;
+ localparam ZBT_READ_UPPER = 4;
+ localparam ZBT_READ_LOWER = 5;
+
+ wire can_write = ~ram_full & ~path1_empty;
+ wire can_write_chain = can_write & ~path1_almost_empty;
+
+ wire can_read = ~ram_empty & ~path2_full;
+ wire can_read_chain = can_read & ~path2_almost_full;
+
+ assign phase = zbt_state[0];
+
+ reg [17:0] ram_occupied;
+ wire ram_almost_empty = (write_ptr == (read_ptr+1'b1));
+ wire ram_almost_full = ((write_ptr+1'b1) == read_ptr);
+
+ always @(posedge clk)
+ if(rst | clear)
+ begin
+ zbt_state <= ZBT_IDLE;
+ write_ptr <= 0;
+ read_ptr <= 0;
+ ram_full <= 0;
+ ram_empty <= 1;
+ ram_occupied <= 0;
+ end
+ else
+ case(zbt_state)
+ ZBT_IDLE :
+ if(can_read)
+ zbt_state <= ZBT_READ_UPPER;
+ else if(can_write)
+ zbt_state <= ZBT_WRITE_UPPER;
+
+ ZBT_WRITE_UPPER :
+ begin
+ zbt_state <= ZBT_WRITE_LOWER;
+ ram_occupied <= ram_occupied + 1;
+ ram_empty <= 0;
+ if(ram_occupied == 18'd10)
+ ram_full <= 1;
+ end
+ ZBT_WRITE_LOWER :
+ begin
+ write_ptr <= write_ptr + 1;
+ if(can_read_chain)
+ zbt_state <= ZBT_READ_UPPER;
+ else if(can_write_chain)
+ zbt_state <= ZBT_WRITE_UPPER;
+ else
+ zbt_state <= ZBT_IDLE;
+ end
+ ZBT_READ_UPPER :
+ begin
+ zbt_state <= ZBT_READ_LOWER;
+ ram_occupied <= ram_occupied - 1;
+ ram_full <= 0;
+ if(ram_occupied == 18'd1)
+ ram_empty <= 1;
+ end
+ ZBT_READ_LOWER :
+ begin
+ read_ptr <= read_ptr + 1;
+ if(can_read_chain)
+ zbt_state <= ZBT_READ_UPPER;
+ else if(can_write_chain)
+ zbt_state <= ZBT_WRITE_UPPER;
+ else
+ zbt_state <= ZBT_IDLE;
+ end
+ default :
+ zbt_state <= ZBT_IDLE;
+ endcase // case(zbt_state)
+
+ // Need to generate RAM_WEn, RAM_OEn, RAM_D, RAM_A;
+ assign path1_read = (zbt_state == ZBT_WRITE_LOWER);
+ reg path2_write, delayed_read_upper, delayed_read_lower, delayed_write;
+
+ always @(posedge clk)
+ if(delayed_read_upper)
+ path2_dat[35:18] <= RAM_D;
+ always @(posedge clk)
+ if(delayed_read_lower)
+ path2_dat[17:0] <= RAM_D;
+
+ always @(posedge clk)
+ if(rst)
+ begin
+ delayed_read_upper <= 0;
+ delayed_read_lower <= 0;
+ path2_write <= 0;
+ end
+ else
+ begin
+ delayed_read_upper <= (zbt_state == ZBT_READ_LOWER);
+ delayed_read_lower <= delayed_read_upper;
+ path2_write <= delayed_read_lower;
+ end
+
+ reg [17:0] RAM_D_pre2, RAM_D_pre1, RAM_D_out;
+
+ always @(posedge clk)
+ RAM_D_pre2 <= phase ? path1_dat[17:0] : path1_dat[35:18];
+
+ always @(posedge clk) RAM_D_pre1 <= RAM_D_pre2;
+ always @(posedge clk) RAM_D_out <= RAM_D_pre1;
+ reg wr_del_1, wr_del_2;
+ always @(posedge clk)
+ if(rst)
+ begin
+ wr_del_1 <= 0;
+ wr_del_2 <= 0;
+ delayed_write <= 0;
+ end
+ else
+ begin
+ delayed_write <= wr_del_2;
+ wr_del_2 <= wr_del_1;
+ wr_del_1 <= write_now;
+ end
+
+ reg delayed_read, rd_del_1, rd_del_2;
+ always @(posedge clk)
+ if(rst)
+ begin
+ rd_del_1 <= 0;
+ rd_del_2 <= 0;
+ delayed_read <= 0;
+ end
+ else
+ begin
+ delayed_read <= rd_del_2;
+ rd_del_2 <= rd_del_1;
+ rd_del_1 <= read_now;
+ end
+
+ assign RAM_D = delayed_write ? RAM_D_out : 18'bzzzzzzzzzzzzzzzzzz;
+ assign write_now = (zbt_state == ZBT_WRITE_UPPER) || (zbt_state == ZBT_WRITE_LOWER);
+ assign read_now = (zbt_state == ZBT_READ_UPPER) || (zbt_state == ZBT_READ_LOWER);
+
+ always @(posedge clk)
+ RAM_A <= write_now ? {write_ptr,phase} : {read_ptr,phase};
+
+ always @(posedge clk)
+ RAM_WEn <= ~write_now;
+
+ assign RAM_OEn = ~delayed_read;
+ assign RAM_OEn = 0;
+
+endmodule // giantfifo
diff --git a/usrp2/fpga/control_lib/giantfifo_tb.v b/usrp2/fpga/control_lib/giantfifo_tb.v
new file mode 100644
index 000000000..87ecd97ae
--- /dev/null
+++ b/usrp2/fpga/control_lib/giantfifo_tb.v
@@ -0,0 +1,173 @@
+module fifo_tb();
+
+ localparam WIDTH = 36;
+ reg clk, rst;
+ wire short_full, short_empty, long_full, long_empty, giant_full, giant_empty;
+ wire casc_full, casc_empty, casc2_full, casc2_empty;
+ reg read, write;
+
+ wire [WIDTH-1:0] short_do, long_do, casc_do, casc2_do, giant_do;
+ reg [WIDTH-1:0] di;
+
+ reg clear = 0;
+
+ shortfifo #(.WIDTH(WIDTH)) shortfifo
+ (.clk(clk),.rst(rst),.datain(di),.dataout(short_do),.clear(clear),
+ .read(read),.write(write),.full(short_full),.empty(short_empty));
+
+ longfifo #(.WIDTH(WIDTH), .SIZE(4)) longfifo
+ (.clk(clk),.rst(rst),.datain(di),.dataout(long_do),.clear(clear),
+ .read(read),.write(write),.full(long_full),.empty(long_empty));
+
+ cascadefifo #(.WIDTH(WIDTH), .SIZE(4)) cascadefifo
+ (.clk(clk),.rst(rst),.datain(di),.dataout(casc_do),.clear(clear),
+ .read(read),.write(write),.full(casc_full),.empty(casc_empty));
+
+ cascadefifo2 #(.WIDTH(WIDTH), .SIZE(4)) cascadefifo2
+ (.clk(clk),.rst(rst),.datain(di),.dataout(casc2_do),.clear(clear),
+ .read(read),.write(write),.full(casc2_full),.empty(casc2_empty));
+
+ wire [17:0] RAM_D;
+ wire [18:0] RAM_A;
+ wire RAM_CLK, RAM_WEn, RAM_LDn, RAM_CE1n, RAM_OEn, RAM_CENn;
+
+ giantfifo #(.WIDTH(WIDTH)) giantfifo
+ (.clk(clk),.rst(rst),.datain(di),.dataout(giant_do),.clear(clear),
+ .read(read),.write(write),.full(giant_full),.empty(giant_empty),
+ .RAM_D(RAM_D),.RAM_A(RAM_A),.RAM_CE1n(RAM_CE1n),.RAM_CENn(RAM_CENn),
+ .RAM_CLK(RAM_CLK),.RAM_WEn(RAM_WEn),.RAM_OEn(RAM_OEn),.RAM_LDn(RAM_LDn)
+ );
+
+ wire MODE = 1'b0;
+ cy1356 ram_model(.d(RAM_D),.clk(RAM_CLK),.a(RAM_A),
+ .bws(2'b00),.we_b(RAM_WEn),.adv_lb(RAM_LDn),
+ .ce1b(RAM_CE1n),.ce2(1'b1),.ce3b(1'b0),
+ .oeb(RAM_OEn),.cenb(RAM_CENn),.mode(MODE)
+ );
+
+ initial rst = 1;
+ initial #1000 rst = 0;
+ initial clk = 0;
+ always #50 clk = ~clk;
+
+ initial di = 36'h300AE;
+ initial read = 0;
+ initial write = 0;
+
+ always @(posedge clk)
+ if(write)
+ di <= di + 1;
+
+ always @(posedge clk)
+ begin
+ if(short_full != long_full)
+ $display("Error: FULL mismatch");
+ if(short_empty != long_empty)
+ $display("Note: EMPTY mismatch, usually not a problem (longfifo has 2 cycle latency)");
+ if(read & (short_do != long_do))
+ $display("Error: DATA mismatch");
+ end
+
+ initial $dumpfile("giantfifo_tb.vcd");
+ initial $dumpvars(0,fifo_tb);
+
+ initial
+ begin
+ @(negedge rst);
+ @(posedge clk);
+ repeat (10)
+ @(posedge clk);
+ write <= 1;
+ @(posedge clk);
+ write <= 0;
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ read <= 1;
+ @(posedge clk);
+ read <= 0;
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+
+ repeat(10)
+ begin
+ write <= 1;
+ @(posedge clk);
+ write <= 0;
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ read <= 1;
+ @(posedge clk);
+ read <= 0;
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ end // repeat (10)
+
+ write <= 1;
+ repeat (4)
+ @(posedge clk);
+ write <= 0;
+ @(posedge clk);
+ read <= 1;
+ repeat (4)
+ @(posedge clk);
+ read <= 0;
+ @(posedge clk);
+
+
+ write <= 1;
+ repeat (4)
+ @(posedge clk);
+ write <= 0;
+ @(posedge clk);
+ repeat (4)
+ begin
+ read <= 1;
+ @(posedge clk);
+ read <= 0;
+ @(posedge clk);
+ end
+
+ write <= 1;
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ read <= 1;
+ repeat (5)
+ @(posedge clk);
+ write <= 0;
+ @(posedge clk);
+ @(posedge clk);
+ read <= 0;
+ @(posedge clk);
+
+ write <= 1;
+ repeat (16)
+ @(posedge clk);
+ write <= 0;
+ @(posedge clk);
+
+ read <= 1;
+ repeat (16)
+ @(posedge clk);
+ read <= 0;
+ @(posedge clk);
+
+ repeat (10)
+ @(posedge clk);
+ $finish;
+ end
+endmodule // longfifo_tb