aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp2/fifo
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp2/fifo')
-rw-r--r--fpga/usrp2/fifo/.gitignore3
-rw-r--r--fpga/usrp2/fifo/Makefile.srcs40
-rw-r--r--fpga/usrp2/fifo/add_routing_header.v47
-rw-r--r--fpga/usrp2/fifo/buffer_int.v184
-rw-r--r--fpga/usrp2/fifo/buffer_int2.v194
-rw-r--r--fpga/usrp2/fifo/buffer_int_tb.v435
-rw-r--r--fpga/usrp2/fifo/buffer_pool.v300
-rw-r--r--fpga/usrp2/fifo/buffer_pool_tb.v75
-rw-r--r--fpga/usrp2/fifo/crossbar36.v59
-rw-r--r--fpga/usrp2/fifo/dsp_framer36.v89
-rw-r--r--fpga/usrp2/fifo/fifo19_mux.v94
-rw-r--r--fpga/usrp2/fifo/fifo19_pad.v83
-rw-r--r--fpga/usrp2/fifo/fifo19_to_fifo36.v127
-rw-r--r--fpga/usrp2/fifo/fifo19_to_ll8.v70
-rw-r--r--fpga/usrp2/fifo/fifo36_demux.v67
-rw-r--r--fpga/usrp2/fifo/fifo36_mux.v94
-rw-r--r--fpga/usrp2/fifo/fifo36_to_fifo19.v80
-rw-r--r--fpga/usrp2/fifo/fifo36_to_fifo72.v142
-rw-r--r--fpga/usrp2/fifo/fifo36_to_ll8.v92
-rw-r--r--fpga/usrp2/fifo/fifo72_to_fifo36.v80
-rw-r--r--fpga/usrp2/fifo/fifo_19to36_tb.v99
-rw-r--r--fpga/usrp2/fifo/fifo_2clock.v139
-rw-r--r--fpga/usrp2/fifo/fifo_2clock_cascade.v58
-rw-r--r--fpga/usrp2/fifo/fifo_cascade.v69
-rw-r--r--fpga/usrp2/fifo/fifo_long.v165
-rw-r--r--fpga/usrp2/fifo/fifo_pacer.v41
-rw-r--r--fpga/usrp2/fifo/fifo_short.v112
-rw-r--r--fpga/usrp2/fifo/fifo_spec.txt36
-rw-r--r--fpga/usrp2/fifo/fifo_tb.v72
-rw-r--r--fpga/usrp2/fifo/ll8_shortfifo.v30
-rw-r--r--fpga/usrp2/fifo/ll8_to_fifo19.v104
-rw-r--r--fpga/usrp2/fifo/ll8_to_fifo36.v114
-rw-r--r--fpga/usrp2/fifo/packet32_tb.v44
-rw-r--r--fpga/usrp2/fifo/packet_dispatcher36_x3.v294
-rw-r--r--fpga/usrp2/fifo/packet_generator.v100
-rw-r--r--fpga/usrp2/fifo/packet_generator32.v40
-rw-r--r--fpga/usrp2/fifo/packet_router.v315
-rw-r--r--fpga/usrp2/fifo/packet_tb.v46
-rw-r--r--fpga/usrp2/fifo/packet_verifier.v78
-rw-r--r--fpga/usrp2/fifo/packet_verifier32.v40
-rw-r--r--fpga/usrp2/fifo/splitter36.v85
-rw-r--r--fpga/usrp2/fifo/valve36.v46
42 files changed, 4482 insertions, 0 deletions
diff --git a/fpga/usrp2/fifo/.gitignore b/fpga/usrp2/fifo/.gitignore
new file mode 100644
index 000000000..866f1faad
--- /dev/null
+++ b/fpga/usrp2/fifo/.gitignore
@@ -0,0 +1,3 @@
+*.vcd
+*.lxt
+a.out
diff --git a/fpga/usrp2/fifo/Makefile.srcs b/fpga/usrp2/fifo/Makefile.srcs
new file mode 100644
index 000000000..28d506571
--- /dev/null
+++ b/fpga/usrp2/fifo/Makefile.srcs
@@ -0,0 +1,40 @@
+#
+# Copyright 2010 Ettus Research LLC
+#
+
+##################################################
+# FIFO Sources
+##################################################
+FIFO_SRCS = $(abspath $(addprefix $(BASE_DIR)/../fifo/, \
+add_routing_header.v \
+buffer_int.v \
+buffer_int2.v \
+buffer_pool.v \
+crossbar36.v \
+dsp_framer36.v \
+fifo_2clock.v \
+fifo_2clock_cascade.v \
+ll8_shortfifo.v \
+fifo_short.v \
+fifo_long.v \
+fifo_cascade.v \
+fifo36_to_ll8.v \
+ll8_to_fifo36.v \
+fifo19_to_ll8.v \
+ll8_to_fifo19.v \
+fifo36_to_fifo19.v \
+fifo19_to_fifo36.v \
+fifo19_mux.v \
+fifo36_mux.v \
+fifo36_demux.v \
+packet_router.v \
+splitter36.v \
+valve36.v \
+fifo_pacer.v \
+packet_dispatcher36_x3.v \
+packet_generator32.v \
+packet_generator.v \
+packet_verifier32.v \
+packet_verifier.v \
+fifo19_pad.v \
+))
diff --git a/fpga/usrp2/fifo/add_routing_header.v b/fpga/usrp2/fifo/add_routing_header.v
new file mode 100644
index 000000000..ee6a635f5
--- /dev/null
+++ b/fpga/usrp2/fifo/add_routing_header.v
@@ -0,0 +1,47 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+module add_routing_header
+ #(parameter PORT_SEL = 0,
+ parameter PROT_ENG_FLAGS = 1)
+ (input clk, input reset, input clear,
+ input [35:0] data_i, input src_rdy_i, output dst_rdy_o,
+ output [35:0] data_o, output src_rdy_o, input dst_rdy_i);
+
+ reg [1:0] line;
+ wire [1:0] port_sel_bits = PORT_SEL;
+ wire [15:0] len = data_i[15:0];
+
+ always @(posedge clk)
+ if(reset)
+ line <= PROT_ENG_FLAGS ? 0 : 1;
+ else
+ if(src_rdy_o & dst_rdy_i)
+ if(data_o[33])
+ line <= PROT_ENG_FLAGS ? 0 : 1;
+ else
+ if(line != 3)
+ line <= line + 1;
+
+ assign data_o = (line == 0) ? {4'b0001, 13'b0, port_sel_bits, 1'b1, len[13:0],2'b00} :
+ (line == 1) ? {3'b000, (PROT_ENG_FLAGS ? 1'b0: 1'b1), data_i[31:0]} :
+ data_i[35:0];
+
+ assign dst_rdy_o = dst_rdy_i & (line != 0);
+ assign src_rdy_o = src_rdy_i;
+
+endmodule // add_routing_header
diff --git a/fpga/usrp2/fifo/buffer_int.v b/fpga/usrp2/fifo/buffer_int.v
new file mode 100644
index 000000000..c068226ec
--- /dev/null
+++ b/fpga/usrp2/fifo/buffer_int.v
@@ -0,0 +1,184 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// FIFO Interface to the 2K buffer RAMs
+// Read port is read-acknowledge
+// FIXME do we want to be able to interleave reads and writes?
+
+module buffer_int
+ #(parameter BUF_NUM = 0,
+ parameter BUF_SIZE = 9)
+ (// Control Interface
+ input clk,
+ input rst,
+ input [31:0] ctrl_word,
+ input go,
+ output done,
+ output error,
+ output idle,
+
+ // Buffer Interface
+ output en_o,
+ output we_o,
+ output reg [BUF_SIZE-1:0] addr_o,
+ output [31:0] dat_to_buf,
+ input [31:0] dat_from_buf,
+
+ // Write FIFO Interface
+ input [31:0] wr_data_i,
+ input [3:0] wr_flags_i,
+ input wr_ready_i,
+ output wr_ready_o,
+
+ // Read FIFO Interface
+ output [31:0] rd_data_o,
+ output [3:0] rd_flags_o,
+ output rd_ready_o,
+ input rd_ready_i
+ );
+
+ reg [31:0] ctrl_reg;
+ reg go_reg;
+
+ always @(posedge clk)
+ go_reg <= go;
+
+ always @(posedge clk)
+ if(rst)
+ ctrl_reg <= 0;
+ else
+ if(go & (ctrl_word[31:28] == BUF_NUM))
+ ctrl_reg <= ctrl_word;
+
+ wire [BUF_SIZE-1:0] firstline = ctrl_reg[BUF_SIZE-1:0];
+ wire [BUF_SIZE-1:0] lastline = ctrl_reg[2*BUF_SIZE-1:BUF_SIZE];
+
+ wire read = ctrl_reg[22];
+ wire write = ctrl_reg[23];
+ wire clear = ctrl_reg[24];
+ //wire [2:0] port = ctrl_reg[27:25]; // Ignored in this block
+ //wire [3:0] buff_num = ctrl_reg[31:28]; // Ignored here ?
+
+ localparam IDLE = 3'd0;
+ localparam PRE_READ = 3'd1;
+ localparam READING = 3'd2;
+ localparam WRITING = 3'd3;
+ localparam ERROR = 3'd4;
+ localparam DONE = 3'd5;
+
+ reg [2:0] state;
+ reg rd_sop, rd_eop;
+ wire wr_sop, wr_eop, wr_error;
+ reg [1:0] rd_occ;
+ wire [1:0] wr_occ;
+
+ always @(posedge clk)
+ if(rst)
+ begin
+ state <= IDLE;
+ rd_sop <= 0;
+ rd_eop <= 0;
+ rd_occ <= 0;
+ end
+ else
+ if(clear)
+ begin
+ state <= IDLE;
+ rd_sop <= 0;
+ rd_eop <= 0;
+ rd_occ <= 0;
+ end
+ else
+ case(state)
+ IDLE :
+ if(go_reg & read)
+ begin
+ addr_o <= firstline;
+ state <= PRE_READ;
+ end
+ else if(go_reg & write)
+ begin
+ addr_o <= firstline;
+ state <= WRITING;
+ end
+
+ PRE_READ :
+ begin
+ state <= READING;
+ addr_o <= addr_o + 1;
+ rd_occ <= 2'b00;
+ rd_sop <= 1;
+ rd_eop <= 0;
+ end
+
+ READING :
+ if(rd_ready_i)
+ begin
+ rd_sop <= 0;
+ addr_o <= addr_o + 1;
+ if(addr_o == lastline)
+ begin
+ rd_eop <= 1;
+ // FIXME assign occ here
+ rd_occ <= 0;
+ end
+ else
+ rd_eop <= 0;
+ if(rd_eop)
+ state <= DONE;
+ end
+
+ WRITING :
+ begin
+ if(wr_ready_i)
+ begin
+ addr_o <= addr_o + 1;
+ if(wr_error)
+ begin
+ state <= ERROR;
+ // Save OCC flags here
+ end
+ else if((addr_o == lastline)||wr_eop)
+ state <= DONE;
+ end // if (wr_ready_i)
+ end // case: WRITING
+
+ endcase // case(state)
+
+ assign dat_to_buf = wr_data_i;
+ assign rd_data_o = dat_from_buf;
+
+ assign rd_flags_o = { rd_occ[1:0], rd_eop, rd_sop };
+ assign rd_ready_o = (state == READING);
+
+ assign wr_sop = wr_flags_i[0];
+ assign wr_eop = wr_flags_i[1];
+ assign wr_occ = wr_flags_i[3:2];
+ assign wr_error = wr_sop & wr_eop;
+ assign wr_ready_o = (state == WRITING);
+
+ assign we_o = (state == WRITING);
+ //assign we_o = (state == WRITING) && wr_ready_i; // always write to avoid timing issue
+
+ assign en_o = ~((state==READING)& ~rd_ready_i); // FIXME potential critical path
+
+ assign done = (state == DONE);
+ assign error = (state == ERROR);
+ assign idle = (state == IDLE);
+
+endmodule // buffer_int
diff --git a/fpga/usrp2/fifo/buffer_int2.v b/fpga/usrp2/fifo/buffer_int2.v
new file mode 100644
index 000000000..7dd528dd5
--- /dev/null
+++ b/fpga/usrp2/fifo/buffer_int2.v
@@ -0,0 +1,194 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// FIFO Interface to the 2K buffer RAMs
+// Read port is read-acknowledge
+// FIXME do we want to be able to interleave reads and writes?
+
+module buffer_int2
+ #(parameter BASE = 0,
+ parameter BUF_SIZE = 9)
+ (input clk, input rst,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ output [31:0] status,
+
+ // Wishbone interface to RAM
+ input wb_clk_i,
+ input wb_rst_i,
+ input wb_we_i,
+ input wb_stb_i,
+ input [15:0] wb_adr_i,
+ input [31:0] wb_dat_i,
+ output [31:0] wb_dat_o,
+ output reg wb_ack_o,
+
+ // Write FIFO Interface
+ input [35:0] wr_data_i,
+ input wr_ready_i,
+ output wr_ready_o,
+
+ // Read FIFO Interface
+ output [35:0] rd_data_o,
+ output rd_ready_o,
+ input rd_ready_i
+ );
+
+ reg [15:0] rd_addr, wr_addr; // Handle pkt bigger than buffer
+ wire [15:0] rd_addr_next = rd_addr + 1;
+ reg [15:0] rd_length;
+
+ wire [31:0] ctrl;
+ wire wr_done, wr_error, wr_idle;
+ wire rd_done, rd_error, rd_idle;
+ wire we, en, go;
+
+ wire read = ctrl[3];
+ wire rd_clear = ctrl[2];
+ wire write = ctrl[1];
+ wire wr_clear = ctrl[0];
+
+ reg [2:0] rd_state, wr_state;
+ reg rd_sop, rd_eop;
+ wire wr_sop, wr_eop;
+ reg [1:0] rd_occ;
+ wire [1:0] wr_occ;
+
+ localparam IDLE = 3'd0;
+ localparam PRE_READ = 3'd1;
+ localparam READING = 3'd2;
+ localparam WRITING = 3'd3;
+ localparam ERROR = 3'd4;
+ localparam DONE = 3'd5;
+
+ // read state machine
+ always @(posedge clk)
+ if(rst | (rd_clear & go))
+ begin
+ rd_state <= IDLE;
+ rd_sop <= 0;
+ rd_eop <= 0;
+ rd_occ <= 0;
+ end
+ else
+ case(rd_state)
+ IDLE :
+ if(go & read)
+ begin
+ rd_addr <= 0;
+ rd_state <= PRE_READ;
+ rd_length <= ctrl[31:16];
+ end
+
+ PRE_READ :
+ begin
+ rd_state <= READING;
+ rd_addr <= rd_addr_next;
+ rd_occ <= 2'b00;
+ rd_sop <= 1;
+ rd_eop <= 0;
+ end
+
+ READING :
+ if(rd_ready_i)
+ begin
+ rd_sop <= 0;
+ rd_addr <= rd_addr_next;
+ if(rd_addr_next == rd_length)
+ begin
+ rd_eop <= 1;
+ // FIXME assign occ here
+ rd_occ <= 0;
+ end
+ else
+ rd_eop <= 0;
+ if(rd_eop)
+ rd_state <= DONE;
+ end
+
+ endcase // case(rd_state)
+
+ // write state machine
+ always @(posedge clk)
+ if(rst | (wr_clear & go))
+ wr_state <= IDLE;
+ else
+ case(wr_state)
+ IDLE :
+ if(go & write)
+ begin
+ wr_addr <= 0;
+ wr_state <= WRITING;
+ end
+
+ WRITING :
+ if(wr_ready_i)
+ begin
+ wr_addr <= wr_addr + 1;
+ if(wr_sop & wr_eop)
+ wr_state <= ERROR; // Should save OCC flags here
+ else if(wr_eop)
+ wr_state <= DONE;
+ end // if (wr_ready_i)
+ endcase // case(wr_state)
+
+ assign rd_data_o[35:32] = { rd_occ[1:0], rd_eop, rd_sop };
+ assign rd_ready_o = (rd_state == READING);
+
+ assign wr_sop = wr_data_i[32];
+ assign wr_eop = wr_data_i[33];
+ assign wr_occ = wr_data_i[35:34];
+ assign wr_ready_o = (wr_state == WRITING);
+
+ assign we = (wr_state == WRITING); // always write to avoid timing issue
+ assign en = ~((rd_state==READING)& ~rd_ready_i); // FIXME potential critical path
+
+ assign rd_done = (rd_state == DONE);
+ assign wr_done = (wr_state == DONE);
+ assign rd_error = (rd_state == ERROR);
+ assign wr_error = (wr_state == ERROR);
+ assign rd_idle = (rd_state == IDLE);
+ assign wr_idle = (wr_state == IDLE);
+
+ wire [BUF_SIZE-1:0] wr_addr_clip = (|wr_addr[15:BUF_SIZE]) ? {BUF_SIZE{1'b1}} : wr_addr[BUF_SIZE-1:0];
+
+ ram_2port #(.DWIDTH(32),.AWIDTH(BUF_SIZE)) buffer_in // CPU reads here
+ (.clka(wb_clk_i),.ena(wb_stb_i),.wea(1'b0),
+ .addra(wb_adr_i[BUF_SIZE+1:2]),.dia(0),.doa(wb_dat_o),
+ .clkb(clk),.enb(1'b1),.web(we),
+ .addrb(wr_addr_clip),.dib(wr_data_i[31:0]),.dob());
+
+ ram_2port #(.DWIDTH(32),.AWIDTH(BUF_SIZE)) buffer_out // CPU writes here
+ (.clka(wb_clk_i),.ena(wb_stb_i),.wea(wb_we_i),
+ .addra(wb_adr_i[BUF_SIZE+1:2]),.dia(wb_dat_i),.doa(),
+ .clkb(clk),.enb(en),.web(1'b0),
+ .addrb(rd_addr[BUF_SIZE-1:0]),.dib(0),.dob(rd_data_o[31:0]));
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ wb_ack_o <= 0;
+ else
+ wb_ack_o <= wb_stb_i & ~wb_ack_o;
+
+ setting_reg #(.my_addr(BASE))
+ sreg(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),.in(set_data),
+ .out(ctrl),.changed(go));
+
+ assign status = { wr_addr,
+ 8'b0,1'b0,rd_idle,rd_error,rd_done, 1'b0,wr_idle,wr_error,wr_done};
+
+endmodule // buffer_int2
diff --git a/fpga/usrp2/fifo/buffer_int_tb.v b/fpga/usrp2/fifo/buffer_int_tb.v
new file mode 100644
index 000000000..44f8be0a0
--- /dev/null
+++ b/fpga/usrp2/fifo/buffer_int_tb.v
@@ -0,0 +1,435 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module buffer_int_tb ();
+
+ reg clk = 0;
+ reg rst = 1;
+
+ initial #100 rst = 0;
+ always #5 clk = ~clk;
+
+ wire en, we;
+ wire [8:0] addr;
+ wire [31:0] fifo2buf, buf2fifo;
+
+ wire [31:0] rd_data_o;
+ wire [3:0] rd_flags_o;
+ wire rd_sop_o, rd_eop_o;
+ reg rd_error_i = 0, rd_read_i = 0;
+
+ reg [31:0] wr_data_i = 0;
+ wire [3:0] wr_flags_i;
+ reg wr_eop_i = 0, wr_sop_i = 0;
+ reg wr_write_i = 0;
+ wire wr_ready_o, wr_full_o;
+
+ reg clear = 0, write = 0, read = 0;
+ reg [8:0] firstline = 0, lastline = 0;
+ wire [3:0] step = 1;
+ wire [31:0] ctrl_word = {4'b0,3'b0,clear,write,read,step,lastline,firstline};
+ reg go = 0;
+ wire done, error;
+
+ assign wr_flags_i = {2'b00, wr_eop_i, wr_sop_i};
+ assign rd_sop_o = rd_flags_o[0];
+ assign rd_eop_o = rd_flags_o[1];
+
+ buffer_int buffer_int
+ (.clk(clk),.rst(rst),
+ .ctrl_word(ctrl_word),.go(go),
+ .done(done),.error(error),
+
+ // Buffer Interface
+ .en_o(en),.we_o(we),.addr_o(addr),
+ .dat_to_buf(fifo2buf),.dat_from_buf(buf2fifo),
+
+ // Write FIFO Interface
+ .wr_data_i(wr_data_i), .wr_flags_i(wr_flags_i), .wr_write_i(wr_write_i), .wr_ready_o(wr_ready_o),
+
+ // Read FIFO Interface
+ .rd_data_o(rd_data_o), .rd_flags_o(rd_flags_o), .rd_ready_o(rd_ready_o), .rd_read_i(rd_read_i)
+ );
+
+ reg ram_en = 0, ram_we = 0;
+ reg [8:0] ram_addr = 0;
+ reg [31:0] ram_data = 0;
+
+ ram_2port #(.DWIDTH(32),.AWIDTH(9)) ram_2port
+ (.clka(clk), .ena(ram_en), .wea(ram_we), .addra(ram_addr), .dia(ram_data), .doa(),
+ .clkb(clk), .enb(en), .web(we), .addrb(addr), .dib(fifo2buf), .dob(buf2fifo) );
+
+ initial
+ begin
+ @(negedge rst);
+ @(posedge clk);
+ FillRAM;
+
+ ResetBuffer;
+ SetBufferRead(5,10);
+ $display("Testing full read, no wait states.");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(6,0);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferRead(5,10);
+ $display("Testing full read, 2 wait states.");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(6,2);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferRead(5,10);
+ $display("Testing partial read, 0 wait states, then nothing after last.");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(3,0);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferRead(5,10);
+ $display("Testing partial read, 0 wait states, then done at same time as last.");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(2,0);
+ ReadALine;
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferRead(5,10);
+ $display("Testing partial read, 3 wait states, then error at same time as last.");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(2,3);
+ rd_error_i <= 1;
+ ReadALine;
+ rd_error_i <= 0;
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferRead(500,511);
+ $display("Testing full read, to the end of the buffer.");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(12,0);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferRead(0,511);
+ $display("Testing full read, start to end of the buffer.");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(512,0);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferRead(505,3);
+ $display("Testing full read, wraparound");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(11,0);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferWrite(10,15);
+ $display("Testing Full Write, no wait states");
+ while(!wr_ready_o)
+ @(posedge clk);
+ WriteLines(6,0,72);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferWrite(18,23);
+ $display("Testing Full Write, 1 wait states");
+ while(!wr_ready_o)
+ @(posedge clk);
+ WriteLines(6,1,101);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferWrite(27,40);
+ $display("Testing Partial Write, 0 wait states");
+ while(!wr_ready_o)
+ @(posedge clk);
+ WriteLines(6,0,201);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferWrite(45,200);
+ $display("Testing Partial Write, 0 wait states, then done and write simultaneously");
+ while(!wr_ready_o)
+ @(posedge clk);
+ wr_sop_i <= 1; wr_eop_i <= 0;
+ WriteLines(6,0,301);
+ wr_sop_i <= 0; wr_eop_i <= 1;
+ WriteALine(400);
+ wr_sop_i <= 0; wr_eop_i <= 0;
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferWrite(55,200);
+ $display("Testing Partial Write, 0 wait states, then error");
+ while(!wr_ready_o)
+ @(posedge clk);
+ WriteLines(6,0,501);
+ wr_sop_i <= 1; wr_eop_i <= 1;
+ WriteALine(400);
+ @(posedge clk);
+ repeat (10)
+ @(posedge clk);
+ wr_sop_i <= 0; wr_eop_i <= 0;
+
+ ResetBuffer;
+ SetBufferRead(0,82);
+ $display("Testing read after all the writes");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(83,0);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferWrite(508,4);
+ $display("Testing wraparound write");
+ while(!wr_ready_o)
+ @(posedge clk);
+ WriteLines(9,0,601);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferRead(506,10);
+ $display("Reading wraparound write");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(17,0);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferWrite(0,511);
+ $display("Testing Whole Buffer write");
+ while(!wr_ready_o)
+ @(posedge clk);
+ WriteLines(512,0,1000);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferRead(0,511);
+ $display("Reading Whole Buffer write");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(512,0);
+ repeat (10)
+ @(posedge clk);
+
+ /*
+ ResetBuffer;
+ SetBufferWrite(5,10);
+ $display("Testing Write Too Many");
+ while(!wr_ready_o)
+ @(posedge clk);
+ WriteLines(12,0,2000);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferRead(0,15);
+ $display("Reading back Write Too Many");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(16,0);
+ repeat (10)
+ @(posedge clk);
+ */
+ ResetBuffer;
+ SetBufferWrite(15,20);
+ $display("Testing Write One Less Than Full");
+ while(!wr_ready_o)
+ @(posedge clk);
+ wr_sop_i <= 1; wr_eop_i <= 0;
+ WriteALine(400);
+ wr_sop_i <= 0; wr_eop_i <= 0;
+ WriteLines(3,0,2000);
+ wr_sop_i <= 0; wr_eop_i <= 1;
+ WriteALine(400);
+ wr_sop_i <= 0; wr_eop_i <= 0;
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ SetBufferRead(13,22);
+ $display("Reading back Write One Less Than Full");
+ while(!rd_sop_o)
+ @(posedge clk);
+ ReadLines(10,0);
+ repeat (10)
+ @(posedge clk);
+
+ ResetBuffer;
+ repeat(100)
+ @(posedge clk);
+ $finish;
+ end
+
+ always @(posedge clk)
+ if(rd_read_i == 1'd1)
+ $display("READ Buffer %d, rd_sop_o %d, rd_eop_o %d", rd_data_o, rd_sop_o, rd_eop_o);
+
+ always @(posedge clk)
+ if(wr_write_i == 1'd1)
+ $display("WRITE Buffer %d, wr_ready_o %d, wr_full_o %d", wr_data_i, wr_ready_o, wr_full_o);
+
+ initial begin
+ $dumpfile("buffer_int_tb.lxt");
+ $dumpvars(0,buffer_int_tb);
+ end
+
+ task FillRAM;
+ begin
+ ram_addr <= 0;
+ ram_data <= 0;
+ @(posedge clk);
+ ram_en <= 1;
+ ram_we <= 1;
+ @(posedge clk);
+ repeat (511)
+ begin
+ ram_addr <= ram_addr + 1;
+ ram_data <= ram_data + 1;
+ ram_en <= 1;
+ ram_we <= 1;
+ @(posedge clk);
+ end
+ ram_en <= 0;
+ ram_we <= 0;
+ @(posedge clk);
+ $display("Filled the RAM");
+ end
+ endtask // FillRAM
+
+ task ResetBuffer;
+ begin
+ clear <= 1; read <= 0; write <= 0;
+ go <= 1;
+ @(posedge clk);
+ go <= 0;
+ @(posedge clk);
+ $display("Buffer Reset");
+ end
+ endtask // ClearBuffer
+
+ task SetBufferWrite;
+ input [8:0] start;
+ input [8:0] stop;
+ begin
+ clear <= 0; read <= 0; write <= 1;
+ firstline <= start;
+ lastline <= stop;
+ go <= 1;
+ @(posedge clk);
+ go <= 0;
+ @(posedge clk);
+ $display("Buffer Set for Write");
+ end
+ endtask // SetBufferWrite
+
+ task SetBufferRead;
+ input [8:0] start;
+ input [8:0] stop;
+ begin
+ clear <= 0; read <= 1; write <= 0;
+ firstline <= start;
+ lastline <= stop;
+ go <= 1;
+ @(posedge clk);
+ go <= 0;
+ @(posedge clk);
+ $display("Buffer Set for Read");
+ end
+ endtask // SetBufferRead
+
+ task ReadALine;
+ begin
+ while(~rd_ready_o)
+ @(posedge clk);
+ #1 rd_read_i <= 1;
+ @(posedge clk);
+ rd_read_i <= 0;
+ end
+ endtask // ReadALine
+
+ task ReadLines;
+ input [9:0] lines;
+ input [7:0] wait_states;
+ begin
+ $display("Read Lines: Number %d, Wait States %d",lines,wait_states);
+ repeat (lines)
+ begin
+ ReadALine;
+ repeat (wait_states)
+ @(posedge clk);
+ end
+ end
+ endtask // ReadLines
+
+ task WriteALine;
+ input [31:0] value;
+ begin
+ while(~wr_ready_o)
+ @(posedge clk);
+ #1 wr_write_i <= 1;
+ wr_data_i <= value;
+ @(posedge clk);
+ wr_write_i <= 0;
+ end
+ endtask // WriteALine
+
+ task WriteLines;
+ input [9:0] lines;
+ input [7:0] wait_states;
+ input [31:0] value;
+ begin
+ $display("Write Lines: Number %d, Wait States %d",lines,wait_states);
+ repeat(lines)
+ begin
+ value <= value + 1;
+ WriteALine(value);
+ repeat(wait_states)
+ @(posedge clk);
+ end
+ end
+ endtask // WriteLines
+
+endmodule // buffer_int_tb
diff --git a/fpga/usrp2/fifo/buffer_pool.v b/fpga/usrp2/fifo/buffer_pool.v
new file mode 100644
index 000000000..48f5bd69c
--- /dev/null
+++ b/fpga/usrp2/fifo/buffer_pool.v
@@ -0,0 +1,300 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Buffer pool. Contains 8 buffers, each 2K (512 by 32). Each buffer
+// is a dual-ported RAM. Port A on each of them is indirectly connected
+// to the wishbone bus by a bridge. Port B may be connected any one of the
+// 8 (4 rd, 4 wr) FIFO-like streaming interaces, or disconnected. The wishbone bus
+// provides access to all 8 buffers, and also controls the connections
+// between the ports and the buffers, allocating them as needed.
+
+// wb_adr is 16 bits --
+// bits 13:11 select which buffer
+// bits 10:2 select line in buffer
+// bits 1:0 are unused (32-bit access only)
+
+// BUF_SIZE is in address lines (i.e. log2 of number of lines).
+// For S3 it should be 9 (512 words, 2KB)
+// For V5 it should be at least 10 (1024 words, 4KB) or 11 (2048 words, 8KB)
+
+module buffer_pool
+ #(parameter BUF_SIZE = 9,
+ parameter SET_ADDR = 64)
+ (input wb_clk_i,
+ input wb_rst_i,
+ input wb_we_i,
+ input wb_stb_i,
+ input [15:0] wb_adr_i,
+ input [31:0] wb_dat_i,
+ output [31:0] wb_dat_o,
+ output reg wb_ack_o,
+ output wb_err_o,
+ output wb_rty_o,
+
+ input stream_clk,
+ input stream_rst,
+
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ output [31:0] status,
+ output sys_int_o,
+
+ output [31:0] s0, output [31:0] s1, output [31:0] s2, output [31:0] s3,
+ output [31:0] s4, output [31:0] s5, output [31:0] s6, output [31:0] s7,
+
+ // Write Interfaces
+ input [31:0] wr0_data_i, input [3:0] wr0_flags_i, input wr0_ready_i, output wr0_ready_o,
+ input [31:0] wr1_data_i, input [3:0] wr1_flags_i, input wr1_ready_i, output wr1_ready_o,
+ input [31:0] wr2_data_i, input [3:0] wr2_flags_i, input wr2_ready_i, output wr2_ready_o,
+ input [31:0] wr3_data_i, input [3:0] wr3_flags_i, input wr3_ready_i, output wr3_ready_o,
+
+ // Read Interfaces
+ output [31:0] rd0_data_o, output [3:0] rd0_flags_o, output rd0_ready_o, input rd0_ready_i,
+ output [31:0] rd1_data_o, output [3:0] rd1_flags_o, output rd1_ready_o, input rd1_ready_i,
+ output [31:0] rd2_data_o, output [3:0] rd2_flags_o, output rd2_ready_o, input rd2_ready_i,
+ output [31:0] rd3_data_o, output [3:0] rd3_flags_o, output rd3_ready_o, input rd3_ready_i
+ );
+
+ wire [7:0] sel_a;
+
+ wire [BUF_SIZE-1:0] buf_addra = wb_adr_i[BUF_SIZE+1:2]; // ignore address 1:0, 32-bit access only
+ wire [2:0] which_buf = wb_adr_i[BUF_SIZE+4:BUF_SIZE+2]; // address 15:14 selects the buffer pool
+
+ decoder_3_8 dec(.sel(which_buf),.res(sel_a));
+
+ genvar i;
+
+ wire go;
+
+ reg [2:0] port[0:7];
+ reg [3:0] read_src[0:3];
+ reg [3:0] write_src[0:3];
+
+ wire [7:0] done;
+ wire [7:0] error;
+ wire [7:0] idle;
+
+ wire [31:0] buf_doa[0:7];
+
+ wire [7:0] buf_enb;
+ wire [7:0] buf_web;
+ wire [BUF_SIZE-1:0] buf_addrb[0:7];
+ wire [31:0] buf_dib[0:7];
+ wire [31:0] buf_dob[0:7];
+
+ wire [31:0] wr_data_i[0:7];
+ wire [3:0] wr_flags_i[0:7];
+ wire [7:0] wr_ready_i;
+ wire [7:0] wr_ready_o;
+
+ wire [31:0] rd_data_o[0:7];
+ wire [3:0] rd_flags_o[0:7];
+ wire [7:0] rd_ready_o;
+ wire [7:0] rd_ready_i;
+
+ assign status = {8'd0,idle[7:0],error[7:0],done[7:0]};
+
+ assign s0 = buf_addrb[0];
+ assign s1 = buf_addrb[1];
+ assign s2 = buf_addrb[2];
+ assign s3 = buf_addrb[3];
+ assign s4 = buf_addrb[4];
+ assign s5 = buf_addrb[5];
+ assign s6 = buf_addrb[6];
+ assign s7 = buf_addrb[7];
+
+ wire [31:0] fifo_ctrl;
+ setting_reg #(.my_addr(SET_ADDR))
+ sreg(.clk(stream_clk),.rst(stream_rst),.strobe(set_stb),.addr(set_addr),.in(set_data),
+ .out(fifo_ctrl),.changed(go));
+
+ integer k;
+ always @(posedge stream_clk)
+ if(stream_rst)
+ for(k=0;k<8;k=k+1)
+ port[k] <= 4; // disabled
+ else
+ for(k=0;k<8;k=k+1)
+ if(go & (fifo_ctrl[31:28]==k))
+ port[k] <= fifo_ctrl[27:25];
+
+ always @(posedge stream_clk)
+ if(stream_rst)
+ for(k=0;k<4;k=k+1)
+ read_src[k] <= 8; // disabled
+ else
+ for(k=0;k<4;k=k+1)
+ if(go & fifo_ctrl[22] & (fifo_ctrl[27:25]==k))
+ read_src[k] <= fifo_ctrl[31:28];
+
+ always @(posedge stream_clk)
+ if(stream_rst)
+ for(k=0;k<4;k=k+1)
+ write_src[k] <= 8; // disabled
+ else
+ for(k=0;k<4;k=k+1)
+ if(go & fifo_ctrl[23] & (fifo_ctrl[27:25]==k))
+ write_src[k] <= fifo_ctrl[31:28];
+
+ generate
+ for(i=0;i<8;i=i+1)
+ begin : gen_buffer
+ RAMB16_S36_S36 dpram
+ (.DOA(buf_doa[i]),.ADDRA(buf_addra),.CLKA(wb_clk_i),.DIA(wb_dat_i),.DIPA(4'h0),
+ .ENA(wb_stb_i & sel_a[i]),.SSRA(0),.WEA(wb_we_i),
+ .DOB(buf_dob[i]),.ADDRB(buf_addrb[i]),.CLKB(stream_clk),.DIB(buf_dib[i]),.DIPB(4'h0),
+ .ENB(buf_enb[i]),.SSRB(0),.WEB(buf_web[i]) );
+
+/*
+ ram_2port #(.DWIDTH(32),.AWIDTH(BUF_SIZE)) buffer
+ (.clka(wb_clk_i),.ena(wb_stb_i & sel_a[i]),.wea(wb_we_i),
+ .addra(buf_addra),.dia(wb_dat_i),.doa(buf_doa[i]),
+ .clkb(stream_clk),.enb(buf_enb[i]),.web(buf_web[i]),
+ .addrb(buf_addrb[i]),.dib(buf_dib[i]),.dob(buf_dob[i]));
+
+ */
+
+ buffer_int #(.BUF_NUM(i),.BUF_SIZE(BUF_SIZE)) buffer_int
+ (.clk(stream_clk),.rst(stream_rst),
+ .ctrl_word(fifo_ctrl),.go(go & (fifo_ctrl[31:28]==i)),
+ .done(done[i]),.error(error[i]),.idle(idle[i]),
+ .en_o(buf_enb[i]),
+ .we_o(buf_web[i]),
+ .addr_o(buf_addrb[i]),
+ .dat_to_buf(buf_dib[i]),
+ .dat_from_buf(buf_dob[i]),
+ .wr_data_i(wr_data_i[i]),
+ .wr_flags_i(wr_flags_i[i]),
+ .wr_ready_i(wr_ready_i[i]),
+ .wr_ready_o(wr_ready_o[i]),
+ .rd_data_o(rd_data_o[i]),
+ .rd_flags_o(rd_flags_o[i]),
+ .rd_ready_o(rd_ready_o[i]),
+ .rd_ready_i(rd_ready_i[i]) );
+ mux4 #(.WIDTH(37))
+ mux4_wr (.en(~port[i][2]),.sel(port[i][1:0]),
+ .i0({wr0_data_i,wr0_flags_i,wr0_ready_i}),
+ .i1({wr1_data_i,wr1_flags_i,wr1_ready_i}),
+ .i2({wr2_data_i,wr2_flags_i,wr2_ready_i}),
+ .i3({wr3_data_i,wr3_flags_i,wr3_ready_i}),
+ .o({wr_data_i[i],wr_flags_i[i],wr_ready_i[i]}) );
+ mux4 #(.WIDTH(1))
+ mux4_rd (.en(~port[i][2]),.sel(port[i][1:0]),
+ .i0(rd0_ready_i),.i1(rd1_ready_i),.i2(rd2_ready_i),.i3(rd3_ready_i),
+ .o(rd_ready_i[i]));
+ end // block: gen_buffer
+ endgenerate
+
+ //----------------------------------------------------------------------
+ // Wishbone Outputs
+
+ // Use the following lines if ram output and mux can be made fast enough
+
+ assign wb_err_o = 1'b0; // Unused for now
+ assign wb_rty_o = 1'b0; // Unused for now
+
+ always @(posedge wb_clk_i)
+ wb_ack_o <= wb_stb_i & ~wb_ack_o;
+ assign wb_dat_o = buf_doa[which_buf];
+
+ // Use this if we can't make the RAM+MUX fast enough
+ // reg [31:0] wb_dat_o_reg;
+ // reg stb_d1;
+
+ // always @(posedge wb_clk_i)
+ // begin
+ // wb_dat_o_reg <= buf_doa[which_buf];
+ // stb_d1 <= wb_stb_i;
+ // wb_ack_o <= (stb_d1 & ~wb_ack_o) | (wb_we_i & wb_stb_i);
+ // end
+ //assign wb_dat_o = wb_dat_o_reg;
+
+ mux8 #(.WIDTH(1))
+ mux8_wr0(.en(~write_src[0][3]),.sel(write_src[0][2:0]),
+ .i0(wr_ready_o[0]), .i1(wr_ready_o[1]), .i2(wr_ready_o[2]), .i3(wr_ready_o[3]),
+ .i4(wr_ready_o[4]), .i5(wr_ready_o[5]), .i6(wr_ready_o[6]), .i7(wr_ready_o[7]),
+ .o(wr0_ready_o));
+
+ mux8 #(.WIDTH(1))
+ mux8_wr1(.en(~write_src[1][3]),.sel(write_src[1][2:0]),
+ .i0(wr_ready_o[0]), .i1(wr_ready_o[1]), .i2(wr_ready_o[2]), .i3(wr_ready_o[3]),
+ .i4(wr_ready_o[4]), .i5(wr_ready_o[5]), .i6(wr_ready_o[6]), .i7(wr_ready_o[7]),
+ .o(wr1_ready_o));
+
+ mux8 #(.WIDTH(1))
+ mux8_wr2(.en(~write_src[2][3]),.sel(write_src[2][2:0]),
+ .i0(wr_ready_o[0]), .i1(wr_ready_o[1]), .i2(wr_ready_o[2]), .i3(wr_ready_o[3]),
+ .i4(wr_ready_o[4]), .i5(wr_ready_o[5]), .i6(wr_ready_o[6]), .i7(wr_ready_o[7]),
+ .o(wr2_ready_o));
+
+ mux8 #(.WIDTH(1))
+ mux8_wr3(.en(~write_src[3][3]),.sel(write_src[3][2:0]),
+ .i0(wr_ready_o[0]), .i1(wr_ready_o[1]), .i2(wr_ready_o[2]), .i3(wr_ready_o[3]),
+ .i4(wr_ready_o[4]), .i5(wr_ready_o[5]), .i6(wr_ready_o[6]), .i7(wr_ready_o[7]),
+ .o(wr3_ready_o));
+
+ mux8 #(.WIDTH(37))
+ mux8_rd0(.en(~read_src[0][3]),.sel(read_src[0][2:0]),
+ .i0({rd_data_o[0],rd_flags_o[0],rd_ready_o[0]}),
+ .i1({rd_data_o[1],rd_flags_o[1],rd_ready_o[1]}),
+ .i2({rd_data_o[2],rd_flags_o[2],rd_ready_o[2]}),
+ .i3({rd_data_o[3],rd_flags_o[3],rd_ready_o[3]}),
+ .i4({rd_data_o[4],rd_flags_o[4],rd_ready_o[4]}),
+ .i5({rd_data_o[5],rd_flags_o[5],rd_ready_o[5]}),
+ .i6({rd_data_o[6],rd_flags_o[6],rd_ready_o[6]}),
+ .i7({rd_data_o[7],rd_flags_o[7],rd_ready_o[7]}),
+ .o({rd0_data_o,rd0_flags_o,rd0_ready_o}));
+
+ mux8 #(.WIDTH(37))
+ mux8_rd1(.en(~read_src[1][3]),.sel(read_src[1][2:0]),
+ .i0({rd_data_o[0],rd_flags_o[0],rd_ready_o[0]}),
+ .i1({rd_data_o[1],rd_flags_o[1],rd_ready_o[1]}),
+ .i2({rd_data_o[2],rd_flags_o[2],rd_ready_o[2]}),
+ .i3({rd_data_o[3],rd_flags_o[3],rd_ready_o[3]}),
+ .i4({rd_data_o[4],rd_flags_o[4],rd_ready_o[4]}),
+ .i5({rd_data_o[5],rd_flags_o[5],rd_ready_o[5]}),
+ .i6({rd_data_o[6],rd_flags_o[6],rd_ready_o[6]}),
+ .i7({rd_data_o[7],rd_flags_o[7],rd_ready_o[7]}),
+ .o({rd1_data_o,rd1_flags_o,rd1_ready_o}));
+
+ mux8 #(.WIDTH(37))
+ mux8_rd2(.en(~read_src[2][3]),.sel(read_src[2][2:0]),
+ .i0({rd_data_o[0],rd_flags_o[0],rd_ready_o[0]}),
+ .i1({rd_data_o[1],rd_flags_o[1],rd_ready_o[1]}),
+ .i2({rd_data_o[2],rd_flags_o[2],rd_ready_o[2]}),
+ .i3({rd_data_o[3],rd_flags_o[3],rd_ready_o[3]}),
+ .i4({rd_data_o[4],rd_flags_o[4],rd_ready_o[4]}),
+ .i5({rd_data_o[5],rd_flags_o[5],rd_ready_o[5]}),
+ .i6({rd_data_o[6],rd_flags_o[6],rd_ready_o[6]}),
+ .i7({rd_data_o[7],rd_flags_o[7],rd_ready_o[7]}),
+ .o({rd2_data_o,rd2_flags_o,rd2_ready_o}));
+
+ mux8 #(.WIDTH(37))
+ mux8_rd3(.en(~read_src[3][3]),.sel(read_src[3][2:0]),
+ .i0({rd_data_o[0],rd_flags_o[0],rd_ready_o[0]}),
+ .i1({rd_data_o[1],rd_flags_o[1],rd_ready_o[1]}),
+ .i2({rd_data_o[2],rd_flags_o[2],rd_ready_o[2]}),
+ .i3({rd_data_o[3],rd_flags_o[3],rd_ready_o[3]}),
+ .i4({rd_data_o[4],rd_flags_o[4],rd_ready_o[4]}),
+ .i5({rd_data_o[5],rd_flags_o[5],rd_ready_o[5]}),
+ .i6({rd_data_o[6],rd_flags_o[6],rd_ready_o[6]}),
+ .i7({rd_data_o[7],rd_flags_o[7],rd_ready_o[7]}),
+ .o({rd3_data_o,rd3_flags_o,rd3_ready_o}));
+
+ assign sys_int_o = (|error) | (|done);
+
+endmodule // buffer_pool
diff --git a/fpga/usrp2/fifo/buffer_pool_tb.v b/fpga/usrp2/fifo/buffer_pool_tb.v
new file mode 100644
index 000000000..0ee76689e
--- /dev/null
+++ b/fpga/usrp2/fifo/buffer_pool_tb.v
@@ -0,0 +1,75 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module buffer_pool_tb();
+
+ wire wb_clk_i;
+ wire wb_rst_i;
+ wire wb_we_i;
+ wire wb_stb_i;
+ wire [15:0] wb_adr_i;
+ wire [31:0] wb_dat_i;
+ wire [31:0] wb_dat_o;
+ wire wb_ack_o;
+ wire wb_err_o;
+ wire wb_rty_o;
+
+ wire stream_clk, stream_rst;
+
+ wire set_stb;
+ wire [7:0] set_addr;
+ wire [31:0] set_data;
+
+ wire [31:0] wr0_data, wr1_data, wr2_data, wr3_data;
+ wire [31:0] rd0_data, rd1_data, rd2_data, rd3_data;
+ wire [3:0] wr0_flags, wr1_flags, wr2_flags, wr3_flags;
+ wire [3:0] rd0_flags, rd1_flags, rd2_flags, rd3_flags;
+ wire wr0_ready, wr1_ready, wr2_ready, wr3_ready;
+ wire rd0_ready, rd1_ready, rd2_ready, rd3_ready;
+ wire wr0_write, wr1_write, wr2_write, wr3_write;
+ wire rd0_read, rd1_read, rd2_read, rd3_read;
+
+ buffer_pool dut
+ (.wb_clk_i(wb_clk_i),
+ .wb_rst_i(wb_rst_i),
+ .wb_we_i(wb_we_i),
+ .wb_stb_i(wb_stb_i),
+ .wb_adr_i(wb_adr_i),
+ .wb_dat_i(wb_dat_i),
+ .wb_dat_o(wb_dat_o),
+ .wb_ack_o(wb_ack_o),
+ .wb_err_o(wb_err_o),
+ .wb_rty_o(wb_rty_o),
+
+ .stream_clk(stream_clk),
+ .stream_rst(stream_rst),
+
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+
+ .wr0_data_i(wr0_data), .wr0_write_i(wr0_write), .wr0_flags_i(wr0_flags), .wr0_ready_o(wr0_ready),
+ .wr1_data_i(wr1_data), .wr1_write_i(wr1_write), .wr1_flags_i(wr1_flags), .wr1_ready_o(wr1_ready),
+ .wr2_data_i(wr2_data), .wr2_write_i(wr2_write), .wr2_flags_i(wr2_flags), .wr2_ready_o(wr2_ready),
+ .wr3_data_i(wr3_data), .wr3_write_i(wr3_write), .wr3_flags_i(wr3_flags), .wr3_ready_o(wr3_ready),
+
+ .rd0_data_o(rd0_data), .rd0_read_i(rd0_read), .rd0_flags_o(rd0_flags), .rd0_ready_o(rd0_ready),
+ .rd1_data_o(rd1_data), .rd1_read_i(rd1_read), .rd1_flags_o(rd1_flags), .rd1_ready_o(rd1_ready),
+ .rd2_data_o(rd2_data), .rd2_read_i(rd2_read), .rd2_flags_o(rd2_flags), .rd2_ready_o(rd2_ready),
+ .rd3_data_o(rd3_data), .rd3_read_i(rd3_read), .rd3_flags_o(rd3_flags), .rd3_ready_o(rd3_ready)
+ );
+
+endmodule // buffer_pool_tb
diff --git a/fpga/usrp2/fifo/crossbar36.v b/fpga/usrp2/fifo/crossbar36.v
new file mode 100644
index 000000000..4e2aed7ce
--- /dev/null
+++ b/fpga/usrp2/fifo/crossbar36.v
@@ -0,0 +1,59 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module crossbar36
+ (input clk, input reset, input clear,
+ input cross,
+ input [35:0] data0_i, input src0_rdy_i, output dst0_rdy_o,
+ input [35:0] data1_i, input src1_rdy_i, output dst1_rdy_o,
+ output [35:0] data0_o, output src0_rdy_o, input dst0_rdy_i,
+ output [35:0] data1_o, output src1_rdy_o, input dst1_rdy_i);
+
+ reg cross_int, active0, active1;
+ wire active0_next = (src0_rdy_i & dst0_rdy_o)? ~data0_i[33] : active0;
+ wire active1_next = (src1_rdy_i & dst1_rdy_o)? ~data1_i[33] : active1;
+
+ assign data0_o = cross_int ? data1_i : data0_i;
+ assign data1_o = cross_int ? data0_i : data1_i;
+
+ assign src0_rdy_o = cross_int ? src1_rdy_i : src0_rdy_i;
+ assign src1_rdy_o = cross_int ? src0_rdy_i : src1_rdy_i;
+
+ assign dst0_rdy_o = cross_int ? dst1_rdy_i : dst0_rdy_i;
+ assign dst1_rdy_o = cross_int ? dst0_rdy_i : dst1_rdy_i;
+
+ always @(posedge clk)
+ if(reset | clear)
+ active0 <= 0;
+ else
+ active0 <= active0_next;
+
+ always @(posedge clk)
+ if(reset | clear)
+ active1 <= 0;
+ else
+ active1 <= active1_next;
+
+ always @(posedge clk)
+ if(reset | clear)
+ cross_int <= 0;
+ else if(~active0_next & ~active1_next)
+ cross_int <= cross;
+
+endmodule // crossbar36
diff --git a/fpga/usrp2/fifo/dsp_framer36.v b/fpga/usrp2/fifo/dsp_framer36.v
new file mode 100644
index 000000000..ef7395551
--- /dev/null
+++ b/fpga/usrp2/fifo/dsp_framer36.v
@@ -0,0 +1,89 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// This has 3 functions:
+// Correct the VITA packet length
+// [optional] Frame DSP packets with an header line to be handled by the protocol machine
+// Hold on to the packet until there is a complete one before allowing to leave
+
+module dsp_framer36
+ #(parameter BUF_SIZE = 9,
+ parameter PORT_SEL = 0,
+ parameter PROT_ENG_FLAGS = 1)
+ (input clk, input reset, input clear,
+ input [35:0] data_i, input src_rdy_i, output dst_rdy_o,
+ output [35:0] data_o, output src_rdy_o, input dst_rdy_i);
+
+ wire dfifo_in_dst_rdy, dfifo_in_src_rdy, dfifo_out_dst_rdy, dfifo_out_src_rdy;
+ wire tfifo_in_dst_rdy, tfifo_in_src_rdy, tfifo_out_dst_rdy, tfifo_out_src_rdy;
+
+ wire do_xfer_in = dfifo_in_src_rdy & dfifo_in_dst_rdy;
+ wire do_xfer_out = src_rdy_o & dst_rdy_i;
+
+ wire have_space = dfifo_in_dst_rdy & tfifo_in_dst_rdy;
+ reg [15:0] pkt_len_in, pkt_len_out;
+ wire [15:0] tfifo_data;
+ wire [35:0] dfifo_out_data;
+
+ assign dst_rdy_o = have_space;
+ assign dfifo_in_src_rdy = src_rdy_i & have_space;
+
+ fifo_cascade #(.WIDTH(36), .SIZE(BUF_SIZE)) dfifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(data_i), .src_rdy_i(dfifo_in_src_rdy), .dst_rdy_o(dfifo_in_dst_rdy),
+ .dataout(dfifo_out_data), .src_rdy_o(dfifo_out_src_rdy), .dst_rdy_i(dfifo_out_dst_rdy) );
+
+ fifo_short #(.WIDTH(16)) tfifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(pkt_len_in), .src_rdy_i(tfifo_in_src_rdy), .dst_rdy_o(tfifo_in_dst_rdy),
+ .dataout(tfifo_data), .src_rdy_o(tfifo_out_src_rdy), .dst_rdy_i(tfifo_out_dst_rdy),
+ .space(), .occupied() );
+
+ // FIXME won't handle single-line packets, will show wrong length
+ always @(posedge clk)
+ if(reset | clear)
+ pkt_len_in <= 0;
+ else if(do_xfer_in)
+ if(data_i[32]) // sof
+ pkt_len_in <= 2; // fixes off by one since number is stored before increment
+ else
+ pkt_len_in <= pkt_len_in + 1;
+
+ assign tfifo_in_src_rdy = do_xfer_in & data_i[33]; // store length when at eof in
+ assign tfifo_out_dst_rdy = do_xfer_out & data_o[33]; // remove length from list at eof out
+
+ always @(posedge clk)
+ if(reset | clear)
+ pkt_len_out <= (PROT_ENG_FLAGS ? 1'b0 : 1'b1);
+ else if(do_xfer_out)
+ if(dfifo_out_data[33]) // eof
+ pkt_len_out <= (PROT_ENG_FLAGS ? 1'b0 : 1'b1);
+ else
+ pkt_len_out <= pkt_len_out + 1;
+
+ assign dfifo_out_dst_rdy = do_xfer_out & (pkt_len_out != 0);
+
+ wire [1:0] port_sel_bits = PORT_SEL;
+
+ assign data_o = (pkt_len_out == 0) ? {3'b000, 1'b1, 13'b0, port_sel_bits, 1'b1, tfifo_data[13:0],2'b00} :
+ (pkt_len_out == 1) ? {3'b000, (PROT_ENG_FLAGS ? 1'b0: 1'b1), dfifo_out_data[31:16],tfifo_data} :
+ {dfifo_out_data[35:33], 1'b0, dfifo_out_data[31:0] };
+
+ assign src_rdy_o = dfifo_out_src_rdy & tfifo_out_src_rdy;
+
+endmodule // dsp_framer36
diff --git a/fpga/usrp2/fifo/fifo19_mux.v b/fpga/usrp2/fifo/fifo19_mux.v
new file mode 100644
index 000000000..a23ac2bb4
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo19_mux.v
@@ -0,0 +1,94 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Mux packets from multiple FIFO interfaces onto a single one.
+// Can alternate or give priority to one port (port 0)
+// In prio mode, port 1 will never get access if port 0 is always busy
+
+module fifo19_mux
+ #(parameter prio = 0)
+ (input clk, input reset, input clear,
+ input [18:0] data0_i, input src0_rdy_i, output dst0_rdy_o,
+ input [18:0] data1_i, input src1_rdy_i, output dst1_rdy_o,
+ output [18:0] data_o, output src_rdy_o, input dst_rdy_i);
+
+ wire [18:0] data0_int, data1_int;
+ wire src0_rdy_int, dst0_rdy_int, src1_rdy_int, dst1_rdy_int;
+
+ fifo_short #(.WIDTH(19)) mux_fifo_in0
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(data0_i), .src_rdy_i(src0_rdy_i), .dst_rdy_o(dst0_rdy_o),
+ .dataout(data0_int), .src_rdy_o(src0_rdy_int), .dst_rdy_i(dst0_rdy_int));
+
+ fifo_short #(.WIDTH(19)) mux_fifo_in1
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(data1_i), .src_rdy_i(src1_rdy_i), .dst_rdy_o(dst1_rdy_o),
+ .dataout(data1_int), .src_rdy_o(src1_rdy_int), .dst_rdy_i(dst1_rdy_int));
+
+ localparam MUX_IDLE0 = 0;
+ localparam MUX_DATA0 = 1;
+ localparam MUX_IDLE1 = 2;
+ localparam MUX_DATA1 = 3;
+
+ reg [1:0] state;
+
+ wire eof0 = data0_int[17];
+ wire eof1 = data1_int[17];
+
+ wire [18:0] data_int;
+ wire src_rdy_int, dst_rdy_int;
+
+ always @(posedge clk)
+ if(reset | clear)
+ state <= MUX_IDLE0;
+ else
+ case(state)
+ MUX_IDLE0 :
+ if(src0_rdy_int)
+ state <= MUX_DATA0;
+ else if(src1_rdy_int)
+ state <= MUX_DATA1;
+
+ MUX_DATA0 :
+ if(src0_rdy_int & dst_rdy_int & eof0)
+ state <= prio ? MUX_IDLE0 : MUX_IDLE1;
+
+ MUX_IDLE1 :
+ if(src1_rdy_int)
+ state <= MUX_DATA1;
+ else if(src0_rdy_int)
+ state <= MUX_DATA0;
+
+ MUX_DATA1 :
+ if(src1_rdy_int & dst_rdy_int & eof1)
+ state <= MUX_IDLE0;
+
+ default :
+ state <= MUX_IDLE0;
+ endcase // case (state)
+
+ assign dst0_rdy_int = (state==MUX_DATA0) ? dst_rdy_int : 0;
+ assign dst1_rdy_int = (state==MUX_DATA1) ? dst_rdy_int : 0;
+ assign src_rdy_int = (state==MUX_DATA0) ? src0_rdy_int : (state==MUX_DATA1) ? src1_rdy_int : 0;
+ assign data_int = (state==MUX_DATA0) ? data0_int : data1_int;
+
+ fifo_short #(.WIDTH(19)) mux_fifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(data_int), .src_rdy_i(src_rdy_int), .dst_rdy_o(dst_rdy_int),
+ .dataout(data_o), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i));
+endmodule // fifo19_mux
diff --git a/fpga/usrp2/fifo/fifo19_pad.v b/fpga/usrp2/fifo/fifo19_pad.v
new file mode 100644
index 000000000..bb6e1fa92
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo19_pad.v
@@ -0,0 +1,83 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Pads a packet out to the minimum length
+// Packets already longer than min length are unchanged
+
+
+module fifo19_pad
+ #(parameter LENGTH=16,
+ parameter PAD_VALUE=0)
+ (input clk, input reset, input clear,
+ input [18:0] data_i,
+ input src_rdy_i,
+ output dst_rdy_o,
+ output [18:0] data_o,
+ output src_rdy_o,
+ input dst_rdy_i);
+
+ reg [15:0] count;
+ reg [1:0] pad_state;
+ localparam PAD_IDLE = 0;
+ localparam PAD_TOOSHORT = 1;
+ localparam PAD_LONGENOUGH = 2;
+ localparam PAD_PADDING = 3;
+
+ always @(posedge clk)
+ if(reset | clear)
+ pad_state <= PAD_IDLE;
+ else
+ case(pad_state)
+ PAD_IDLE :
+ begin
+ count <= 1;
+ pad_state <= PAD_TOOSHORT;
+ end
+ PAD_TOOSHORT :
+ if(src_rdy_i & dst_rdy_i)
+ begin
+ count <= count + 1;
+ if(data_i[17])
+ pad_state <= PAD_PADDING;
+ else if(count == (LENGTH-1))
+ pad_state <= PAD_LONGENOUGH;
+ end
+ PAD_PADDING :
+ if(dst_rdy_i)
+ begin
+ count <= count + 1;
+ if(count == LENGTH)
+ pad_state <= PAD_IDLE;
+ end
+ PAD_LONGENOUGH :
+ if(src_rdy_i & dst_rdy_i & data_i[17])
+ pad_state <= PAD_IDLE;
+ endcase // case (pad_state)
+
+ wire passthru = (pad_state == PAD_TOOSHORT) | (pad_state == PAD_LONGENOUGH);
+
+ assign dst_rdy_o = passthru ? dst_rdy_i : 1'b0;
+ assign src_rdy_o = passthru ? src_rdy_i : (pad_state == PAD_PADDING);
+
+ assign data_o[15:0] = (pad_state == PAD_PADDING) ? PAD_VALUE : data_i[15:0];
+ assign data_o[16] = (count == 1);
+ assign data_o[17] = (pad_state == PAD_LONGENOUGH) ? data_i[17] : (count == LENGTH);
+ assign data_o[18] = (pad_state == PAD_LONGENOUGH) ? data_i[18] : 1'b0;
+
+
+endmodule // fifo19_pad
diff --git a/fpga/usrp2/fifo/fifo19_to_fifo36.v b/fpga/usrp2/fifo/fifo19_to_fifo36.v
new file mode 100644
index 000000000..32734405a
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo19_to_fifo36.v
@@ -0,0 +1,127 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Parameter LE tells us if we are little-endian.
+// Little-endian means send lower 16 bits first.
+// Default is big endian (network order), send upper bits first.
+
+module fifo19_to_fifo36
+ #(parameter LE=0)
+ (input clk, input reset, input clear,
+ input [18:0] f19_datain,
+ input f19_src_rdy_i,
+ output f19_dst_rdy_o,
+
+ output [35:0] f36_dataout,
+ output f36_src_rdy_o,
+ input f36_dst_rdy_i,
+ output [31:0] debug
+ );
+
+ // Shortfifo on input to guarantee no deadlock
+ wire [18:0] f19_data_int;
+ wire f19_src_rdy_int, f19_dst_rdy_int;
+
+ fifo_short #(.WIDTH(19)) head_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(f19_datain), .src_rdy_i(f19_src_rdy_i), .dst_rdy_o(f19_dst_rdy_o),
+ .dataout(f19_data_int), .src_rdy_o(f19_src_rdy_int), .dst_rdy_i(f19_dst_rdy_int),
+ .space(),.occupied() );
+
+ // Actual f19 to f36 which could deadlock if not connected to shortfifos
+ reg f36_sof_int, f36_eof_int;
+ reg [1:0] f36_occ_int;
+ wire [35:0] f36_data_int;
+ wire f36_src_rdy_int, f36_dst_rdy_int;
+
+ reg [1:0] state;
+ reg [15:0] dat0, dat1;
+
+ wire f19_sof_int = f19_data_int[16];
+ wire f19_eof_int = f19_data_int[17];
+ wire f19_occ_int = f19_data_int[18];
+
+ wire xfer_out = f36_src_rdy_int & f36_dst_rdy_int;
+
+ always @(posedge clk)
+ if(f19_src_rdy_int & ((state==0)|xfer_out))
+ f36_sof_int <= f19_sof_int;
+
+ always @(posedge clk)
+ if(f19_src_rdy_int & ((state != 2)|xfer_out))
+ f36_eof_int <= f19_eof_int;
+
+ always @(posedge clk)
+ if(reset)
+ begin
+ state <= 0;
+ f36_occ_int <= 0;
+ end
+ else
+ if(f19_src_rdy_int)
+ case(state)
+ 0 :
+ begin
+ dat0 <= f19_data_int;
+ if(f19_eof_int)
+ begin
+ state <= 2;
+ f36_occ_int <= f19_occ_int ? 2'b01 : 2'b10;
+ end
+ else
+ state <= 1;
+ end
+ 1 :
+ begin
+ dat1 <= f19_data_int;
+ state <= 2;
+ if(f19_eof_int)
+ f36_occ_int <= f19_occ_int ? 2'b11 : 2'b00;
+ end
+ 2 :
+ if(xfer_out)
+ begin
+ dat0 <= f19_data_int;
+ if(f19_eof_int) // remain in state 2 if we are at eof
+ f36_occ_int <= f19_occ_int ? 2'b01 : 2'b10;
+ else
+ state <= 1;
+ end
+ endcase // case(state)
+ else
+ if(xfer_out)
+ begin
+ state <= 0;
+ f36_occ_int <= 0;
+ end
+
+ assign f19_dst_rdy_int = xfer_out | (state != 2);
+ assign f36_data_int = LE ? {f36_occ_int,f36_eof_int,f36_sof_int,dat1,dat0} :
+ {f36_occ_int,f36_eof_int,f36_sof_int,dat0,dat1};
+ assign f36_src_rdy_int = (state == 2);
+
+ assign debug = state;
+
+ // Shortfifo on output to guarantee no deadlock
+ fifo_short #(.WIDTH(36)) tail_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(f36_data_int), .src_rdy_i(f36_src_rdy_int), .dst_rdy_o(f36_dst_rdy_int),
+ .dataout(f36_dataout), .src_rdy_o(f36_src_rdy_o), .dst_rdy_i(f36_dst_rdy_i),
+ .space(),.occupied() );
+
+endmodule // fifo19_to_fifo36
diff --git a/fpga/usrp2/fifo/fifo19_to_ll8.v b/fpga/usrp2/fifo/fifo19_to_ll8.v
new file mode 100644
index 000000000..1ebb140c2
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo19_to_ll8.v
@@ -0,0 +1,70 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module fifo19_to_ll8
+ (input clk, input reset, input clear,
+ input [18:0] f19_data,
+ input f19_src_rdy_i,
+ output f19_dst_rdy_o,
+
+ output reg [7:0] ll_data,
+ output ll_sof_n,
+ output ll_eof_n,
+ output ll_src_rdy_n,
+ input ll_dst_rdy_n);
+
+ wire ll_sof, ll_eof, ll_src_rdy;
+ assign ll_sof_n = ~ll_sof;
+ assign ll_eof_n = ~ll_eof;
+ assign ll_src_rdy_n = ~ll_src_rdy;
+ wire ll_dst_rdy = ~ll_dst_rdy_n;
+
+ wire f19_sof = f19_data[16];
+ wire f19_eof = f19_data[17];
+ wire f19_occ = f19_data[18];
+
+ wire advance, end_early;
+ reg state;
+
+ always @(posedge clk)
+ if(reset)
+ state <= 0;
+ else
+ if(advance)
+ if(ll_eof)
+ state <= 0;
+ else
+ state <= state + 1;
+
+ always @*
+ case(state)
+ 0 : ll_data = f19_data[15:8];
+ 1 : ll_data = f19_data[7:0];
+ default : ll_data = f19_data[15:8];
+ endcase // case (state)
+
+ assign ll_sof = (state==0) & f19_sof;
+ assign ll_eof = f19_eof & ((f19_occ==1)|(state==1));
+
+ assign ll_src_rdy = f19_src_rdy_i;
+
+ assign advance = ll_src_rdy & ll_dst_rdy;
+ assign f19_dst_rdy_o = advance & ((state==1)|ll_eof);
+
+endmodule // fifo19_to_ll8
+
diff --git a/fpga/usrp2/fifo/fifo36_demux.v b/fpga/usrp2/fifo/fifo36_demux.v
new file mode 100644
index 000000000..6f516691a
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo36_demux.v
@@ -0,0 +1,67 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Demux packets from a fifo based on the contents of the first line
+// If first line matches the parameter and mask, send to data1, otherwise send to data0
+
+module fifo36_demux
+ #(parameter match_data = 0,
+ parameter match_mask = 0)
+ (input clk, input reset, input clear,
+ input [35:0] data_i, input src_rdy_i, output dst_rdy_o,
+ output [35:0] data0_o, output src0_rdy_o, input dst0_rdy_i,
+ output [35:0] data1_o, output src1_rdy_o, input dst1_rdy_i);
+
+ localparam DMX_IDLE = 0;
+ localparam DMX_DATA0 = 1;
+ localparam DMX_DATA1 = 2;
+
+ reg [1:0] state;
+
+ wire match = |( (data_i ^ match_data) & match_mask );
+ wire eof = data_i[33];
+
+ always @(posedge clk)
+ if(reset | clear)
+ state <= DMX_IDLE;
+ else
+ case(state)
+ DMX_IDLE :
+ if(src_rdy_i)
+ if(match)
+ state <= DMX_DATA1;
+ else
+ state <= DMX_DATA0;
+ DMX_DATA0 :
+ if(src_rdy_i & dst0_rdy_i & eof)
+ state <= DMX_IDLE;
+ DMX_DATA1 :
+ if(src_rdy_i & dst1_rdy_i & eof)
+ state <= DMX_IDLE;
+ default :
+ state <= DMX_IDLE;
+ endcase // case (state)
+
+ assign dst_rdy_o = (state==DMX_IDLE) ? 0 : (state==DMX_DATA0) ? dst0_rdy_i : dst1_rdy_i;
+ assign src0_rdy_o = (state==DMX_DATA0) ? src_rdy_i : 0;
+ assign src1_rdy_o = (state==DMX_DATA1) ? src_rdy_i : 0;
+
+ assign data0_o = data_i;
+ assign data1_o = data_i;
+
+endmodule // fifo36_demux
diff --git a/fpga/usrp2/fifo/fifo36_mux.v b/fpga/usrp2/fifo/fifo36_mux.v
new file mode 100644
index 000000000..cf7b2b4d1
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo36_mux.v
@@ -0,0 +1,94 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Mux packets from multiple FIFO interfaces onto a single one.
+// Can alternate or give priority to one port (port 0)
+// In prio mode, port 1 will never get access if port 0 is always busy
+
+module fifo36_mux
+ #(parameter prio = 0)
+ (input clk, input reset, input clear,
+ input [35:0] data0_i, input src0_rdy_i, output dst0_rdy_o,
+ input [35:0] data1_i, input src1_rdy_i, output dst1_rdy_o,
+ output [35:0] data_o, output src_rdy_o, input dst_rdy_i);
+
+ wire [35:0] data0_int, data1_int;
+ wire src0_rdy_int, dst0_rdy_int, src1_rdy_int, dst1_rdy_int;
+
+ fifo_short #(.WIDTH(36)) mux_fifo_in0
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(data0_i), .src_rdy_i(src0_rdy_i), .dst_rdy_o(dst0_rdy_o),
+ .dataout(data0_int), .src_rdy_o(src0_rdy_int), .dst_rdy_i(dst0_rdy_int));
+
+ fifo_short #(.WIDTH(36)) mux_fifo_in1
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(data1_i), .src_rdy_i(src1_rdy_i), .dst_rdy_o(dst1_rdy_o),
+ .dataout(data1_int), .src_rdy_o(src1_rdy_int), .dst_rdy_i(dst1_rdy_int));
+
+ localparam MUX_IDLE0 = 0;
+ localparam MUX_DATA0 = 1;
+ localparam MUX_IDLE1 = 2;
+ localparam MUX_DATA1 = 3;
+
+ reg [1:0] state;
+
+ wire eof0 = data0_int[33];
+ wire eof1 = data1_int[33];
+
+ wire [35:0] data_int;
+ wire src_rdy_int, dst_rdy_int;
+
+ always @(posedge clk)
+ if(reset | clear)
+ state <= MUX_IDLE0;
+ else
+ case(state)
+ MUX_IDLE0 :
+ if(src0_rdy_int)
+ state <= MUX_DATA0;
+ else if(src1_rdy_int)
+ state <= MUX_DATA1;
+
+ MUX_DATA0 :
+ if(src0_rdy_int & dst_rdy_int & eof0)
+ state <= prio ? MUX_IDLE0 : MUX_IDLE1;
+
+ MUX_IDLE1 :
+ if(src1_rdy_int)
+ state <= MUX_DATA1;
+ else if(src0_rdy_int)
+ state <= MUX_DATA0;
+
+ MUX_DATA1 :
+ if(src1_rdy_int & dst_rdy_int & eof1)
+ state <= MUX_IDLE0;
+
+ default :
+ state <= MUX_IDLE0;
+ endcase // case (state)
+
+ assign dst0_rdy_int = (state==MUX_DATA0) ? dst_rdy_int : 0;
+ assign dst1_rdy_int = (state==MUX_DATA1) ? dst_rdy_int : 0;
+ assign src_rdy_int = (state==MUX_DATA0) ? src0_rdy_int : (state==MUX_DATA1) ? src1_rdy_int : 0;
+ assign data_int = (state==MUX_DATA0) ? data0_int : data1_int;
+
+ fifo_short #(.WIDTH(36)) mux_fifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(data_int), .src_rdy_i(src_rdy_int), .dst_rdy_o(dst_rdy_int),
+ .dataout(data_o), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i));
+endmodule // fifo36_demux
diff --git a/fpga/usrp2/fifo/fifo36_to_fifo19.v b/fpga/usrp2/fifo/fifo36_to_fifo19.v
new file mode 100644
index 000000000..cb93e10ad
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo36_to_fifo19.v
@@ -0,0 +1,80 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Parameter LE tells us if we are little-endian.
+// Little-endian means send lower 16 bits first.
+// Default is big endian (network order), send upper bits first.
+
+module fifo36_to_fifo19
+ #(parameter LE=0)
+ (input clk, input reset, input clear,
+ input [35:0] f36_datain,
+ input f36_src_rdy_i,
+ output f36_dst_rdy_o,
+
+ output [18:0] f19_dataout,
+ output f19_src_rdy_o,
+ input f19_dst_rdy_i );
+
+ wire [18:0] f19_data_int;
+ wire f19_src_rdy_int, f19_dst_rdy_int;
+ wire [35:0] f36_data_int;
+ wire f36_src_rdy_int, f36_dst_rdy_int;
+
+ // Shortfifo on input to guarantee no deadlock
+ fifo_short #(.WIDTH(36)) head_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(f36_datain), .src_rdy_i(f36_src_rdy_i), .dst_rdy_o(f36_dst_rdy_o),
+ .dataout(f36_data_int), .src_rdy_o(f36_src_rdy_int), .dst_rdy_i(f36_dst_rdy_int),
+ .space(),.occupied() );
+
+ // Main fifo36_to_fifo19, needs shortfifos to guarantee no deadlock
+ wire [1:0] f36_occ_int = f36_data_int[35:34];
+ wire f36_sof_int = f36_data_int[32];
+ wire f36_eof_int = f36_data_int[33];
+
+ reg phase;
+ wire half_line = f36_eof_int & ((f36_occ_int==1)|(f36_occ_int==2));
+
+ assign f19_data_int[15:0] = (LE ^ phase) ? f36_data_int[15:0] : f36_data_int[31:16];
+ assign f19_data_int[16] = phase ? 0 : f36_sof_int;
+ assign f19_data_int[17] = phase ? f36_eof_int : half_line;
+ assign f19_data_int[18] = f19_data_int[17] & ((f36_occ_int==1)|(f36_occ_int==3));
+
+ assign f19_src_rdy_int = f36_src_rdy_int;
+ assign f36_dst_rdy_int = (phase | half_line) & f19_dst_rdy_int;
+
+ wire f19_xfer = f19_src_rdy_int & f19_dst_rdy_int;
+ wire f36_xfer = f36_src_rdy_int & f36_dst_rdy_int;
+
+ always @(posedge clk)
+ if(reset)
+ phase <= 0;
+ else if(f36_xfer)
+ phase <= 0;
+ else if(f19_xfer)
+ phase <= 1;
+
+ // Shortfifo on output to guarantee no deadlock
+ fifo_short #(.WIDTH(19)) tail_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(f19_data_int), .src_rdy_i(f19_src_rdy_int), .dst_rdy_o(f19_dst_rdy_int),
+ .dataout(f19_dataout), .src_rdy_o(f19_src_rdy_o), .dst_rdy_i(f19_dst_rdy_i),
+ .space(),.occupied() );
+
+endmodule // fifo36_to_fifo19
diff --git a/fpga/usrp2/fifo/fifo36_to_fifo72.v b/fpga/usrp2/fifo/fifo36_to_fifo72.v
new file mode 100644
index 000000000..237149cc2
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo36_to_fifo72.v
@@ -0,0 +1,142 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Parameter LE tells us if we are little-endian.
+// Little-endian means send lower 16 bits first.
+// Default is big endian (network order), send upper bits first.
+
+module fifo36_to_fifo72
+ #(parameter LE=0)
+ (input clk, input reset, input clear,
+ input [35:0] f36_datain,
+ input f36_src_rdy_i,
+ output f36_dst_rdy_o,
+
+ output [71:0] f72_dataout,
+ output f72_src_rdy_o,
+ input f72_dst_rdy_i,
+ output [31:0] debug
+ );
+
+ // Shortfifo on input to guarantee no deadlock
+ wire [35:0] f36_data_int;
+ wire f36_src_rdy_int, f36_dst_rdy_int;
+
+ fifo_short #(.WIDTH(36)) head_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(f36_datain), .src_rdy_i(f36_src_rdy_i), .dst_rdy_o(f36_dst_rdy_o),
+ .dataout(f36_data_int), .src_rdy_o(f36_src_rdy_int), .dst_rdy_i(f36_dst_rdy_int),
+ .space(),.occupied() );
+
+ // Actual f36 to f72 which could deadlock if not connected to shortfifos
+ reg f72_sof_int, f72_eof_int;
+ reg [2:0] f72_occ_int;
+ wire [71:0] f72_data_int;
+ wire f72_src_rdy_int, f72_dst_rdy_int;
+
+ reg [1:0] state;
+ reg [31:0] dat0, dat1;
+
+ wire f36_sof_int = f36_data_int[32];
+ wire f36_eof_int = f36_data_int[33];
+ wire [1:0] f36_occ_int = f36_data_int[35:34];
+
+ wire xfer_out = f72_src_rdy_int & f72_dst_rdy_int;
+
+ always @(posedge clk)
+ if(f36_src_rdy_int & ((state==0)|xfer_out))
+ f72_sof_int <= f36_sof_int;
+
+ always @(posedge clk)
+ if(f36_src_rdy_int & ((state != 2)|xfer_out))
+ f72_eof_int <= f36_eof_int;
+
+ always @(posedge clk)
+ if(reset)
+ begin
+ state <= 0;
+ f72_occ_int <= 0;
+ end
+ else
+ if(f36_src_rdy_int)
+ case(state)
+ 0 :
+ begin
+ dat0 <= f36_data_int;
+ if(f36_eof_int)
+ begin
+ state <= 2;
+ case (f36_occ_int)
+ 0 : f72_occ_int <= 3'd4;
+ 1 : f72_occ_int <= 3'd1;
+ 2 : f72_occ_int <= 3'd2;
+ 3 : f72_occ_int <= 3'd3;
+ endcase // case (f36_occ_int)
+ end
+ else
+ state <= 1;
+ end
+ 1 :
+ begin
+ dat1 <= f36_data_int;
+ state <= 2;
+ if(f36_eof_int)
+ case (f36_occ_int)
+ 0 : f72_occ_int <= 3'd0;
+ 1 : f72_occ_int <= 3'd5;
+ 2 : f72_occ_int <= 3'd6;
+ 3 : f72_occ_int <= 3'd7;
+ endcase // case (f36_occ_int)
+ end
+ 2 :
+ if(xfer_out)
+ begin
+ dat0 <= f36_data_int;
+ if(f36_eof_int) // remain in state 2 if we are at eof
+ case (f36_occ_int)
+ 0 : f72_occ_int <= 3'd4;
+ 1 : f72_occ_int <= 3'd1;
+ 2 : f72_occ_int <= 3'd2;
+ 3 : f72_occ_int <= 3'd3;
+ endcase // case (f36_occ_int)
+ else
+ state <= 1;
+ end
+ endcase // case(state)
+ else
+ if(xfer_out)
+ begin
+ state <= 0;
+ f72_occ_int <= 0;
+ end
+
+ assign f36_dst_rdy_int = xfer_out | (state != 2);
+ assign f72_data_int = LE ? {3'b000,f72_occ_int[2:0],f72_eof_int,f72_sof_int,dat1,dat0} :
+ {3'b000,f72_occ_int[2:0],f72_eof_int,f72_sof_int,dat0,dat1};
+ assign f72_src_rdy_int = (state == 2);
+
+ assign debug = state;
+
+ // Shortfifo on output to guarantee no deadlock
+ fifo_short #(.WIDTH(72)) tail_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(f72_data_int), .src_rdy_i(f72_src_rdy_int), .dst_rdy_o(f72_dst_rdy_int),
+ .dataout(f72_dataout), .src_rdy_o(f72_src_rdy_o), .dst_rdy_i(f72_dst_rdy_i),
+ .space(),.occupied() );
+
+endmodule // fifo36_to_fifo72
diff --git a/fpga/usrp2/fifo/fifo36_to_ll8.v b/fpga/usrp2/fifo/fifo36_to_ll8.v
new file mode 100644
index 000000000..5c2da812f
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo36_to_ll8.v
@@ -0,0 +1,92 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module fifo36_to_ll8
+ (input clk, input reset, input clear,
+ input [35:0] f36_data,
+ input f36_src_rdy_i,
+ output f36_dst_rdy_o,
+
+ output [7:0] ll_data,
+ output ll_sof,
+ output ll_eof,
+ output ll_src_rdy,
+ input ll_dst_rdy,
+
+ output [31:0] debug);
+
+ // Shortfifo on input to guarantee no deadlock
+ wire [35:0] f36_data_int;
+ wire f36_src_rdy_int, f36_dst_rdy_int;
+ reg [7:0] ll_data_int;
+ wire ll_sof_int, ll_eof_int, ll_src_rdy_int, ll_dst_rdy_int;
+
+ fifo_short #(.WIDTH(36)) head_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(f36_data), .src_rdy_i(f36_src_rdy_i), .dst_rdy_o(f36_dst_rdy_o),
+ .dataout(f36_data_int), .src_rdy_o(f36_src_rdy_int), .dst_rdy_i(f36_dst_rdy_int),
+ .space(),.occupied() );
+
+ // Actual fifo36 to ll8, can deadlock if not connected to shortfifo
+ wire [1:0] f36_occ_int = f36_data_int[35:34];
+ wire f36_sof_int = f36_data_int[32];
+ wire f36_eof_int = f36_data_int[33];
+ wire advance, end_early;
+ reg [1:0] state;
+
+ assign debug = {29'b0,state};
+
+ always @(posedge clk)
+ if(reset)
+ state <= 0;
+ else
+ if(advance)
+ if(ll_eof_int)
+ state <= 0;
+ else
+ state <= state + 1;
+
+ always @*
+ case(state)
+ 0 : ll_data_int = f36_data_int[31:24];
+ 1 : ll_data_int = f36_data_int[23:16];
+ 2 : ll_data_int = f36_data_int[15:8];
+ 3 : ll_data_int = f36_data_int[7:0];
+ default : ll_data_int = f36_data_int[31:24];
+ endcase // case (state)
+
+ assign ll_sof_int = (state==0) & f36_sof_int;
+ assign ll_eof_int = f36_eof_int & (((state==0)&(f36_occ_int==1)) |
+ ((state==1)&(f36_occ_int==2)) |
+ ((state==2)&(f36_occ_int==3)) |
+ (state==3));
+
+ assign ll_src_rdy_int = f36_src_rdy_int;
+
+ assign advance = ll_src_rdy_int & ll_dst_rdy_int;
+ assign f36_dst_rdy_int= advance & ((state==3)|ll_eof_int);
+
+ // Short FIFO on output to guarantee no deadlock
+ ll8_shortfifo tail_fifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(ll_data_int), .sof_i(ll_sof_int), .eof_i(ll_eof_int),
+ .error_i(0), .src_rdy_i(ll_src_rdy_int), .dst_rdy_o(ll_dst_rdy_int),
+ .dataout(ll_data), .sof_o(ll_sof), .eof_o(ll_eof),
+ .error_o(), .src_rdy_o(ll_src_rdy), .dst_rdy_i(ll_dst_rdy));
+
+endmodule // fifo36_to_ll8
diff --git a/fpga/usrp2/fifo/fifo72_to_fifo36.v b/fpga/usrp2/fifo/fifo72_to_fifo36.v
new file mode 100644
index 000000000..c365f0196
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo72_to_fifo36.v
@@ -0,0 +1,80 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Parameter LE tells us if we are little-endian.
+// Little-endian means send lower 16 bits first.
+// Default is big endian (network order), send upper bits first.
+
+module fifo72_to_fifo36
+ #(parameter LE=0)
+ (input clk, input reset, input clear,
+ input [71:0] f72_datain,
+ input f72_src_rdy_i,
+ output f72_dst_rdy_o,
+
+ output [35:0] f36_dataout,
+ output f36_src_rdy_o,
+ input f36_dst_rdy_i );
+
+ wire [35:0] f36_data_int;
+ wire f36_src_rdy_int, f36_dst_rdy_int;
+ wire [71:0] f72_data_int;
+ wire f72_src_rdy_int, f72_dst_rdy_int;
+
+ // Shortfifo on input to guarantee no deadlock
+ fifo_short #(.WIDTH(72)) head_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(f72_datain), .src_rdy_i(f72_src_rdy_i), .dst_rdy_o(f72_dst_rdy_o),
+ .dataout(f72_data_int), .src_rdy_o(f72_src_rdy_int), .dst_rdy_i(f72_dst_rdy_int),
+ .space(),.occupied() );
+
+ // Main fifo72_to_fifo36, needs shortfifos to guarantee no deadlock
+ wire [2:0] f72_occ_int = f72_data_int[68:66];
+ wire f72_sof_int = f72_data_int[64];
+ wire f72_eof_int = f72_data_int[65];
+
+ reg phase;
+ wire half_line = f72_eof_int & ( (f72_occ_int==1)|(f72_occ_int==2)|(f72_occ_int==3)|(f72_occ_int==4) );
+
+ assign f36_data_int[31:0] = (LE ^ phase) ? f72_data_int[31:0] : f72_data_int[63:32];
+ assign f36_data_int[32] = phase ? 0 : f72_sof_int;
+ assign f36_data_int[33] = phase ? f72_eof_int : half_line;
+ assign f36_data_int[35:34] = f36_data_int[33] ? f72_occ_int[1:0] : 2'b00;
+
+ assign f36_src_rdy_int = f72_src_rdy_int;
+ assign f72_dst_rdy_int = (phase | half_line) & f36_dst_rdy_int;
+
+ wire f36_xfer = f36_src_rdy_int & f36_dst_rdy_int;
+ wire f72_xfer = f72_src_rdy_int & f72_dst_rdy_int;
+
+ always @(posedge clk)
+ if(reset)
+ phase <= 0;
+ else if(f72_xfer)
+ phase <= 0;
+ else if(f36_xfer)
+ phase <= 1;
+
+ // Shortfifo on output to guarantee no deadlock
+ fifo_short #(.WIDTH(36)) tail_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(f36_data_int), .src_rdy_i(f36_src_rdy_int), .dst_rdy_o(f36_dst_rdy_int),
+ .dataout(f36_dataout), .src_rdy_o(f36_src_rdy_o), .dst_rdy_i(f36_dst_rdy_i),
+ .space(),.occupied() );
+
+endmodule // fifo72_to_fifo36
diff --git a/fpga/usrp2/fifo/fifo_19to36_tb.v b/fpga/usrp2/fifo/fifo_19to36_tb.v
new file mode 100644
index 000000000..143b92b1b
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo_19to36_tb.v
@@ -0,0 +1,99 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+module fifo_tb();
+
+ reg clk = 0;
+ reg rst = 1;
+ reg clear = 0;
+ initial #1000 rst = 0;
+ always #50 clk = ~clk;
+
+ reg [18:0] f19a;
+ wire [18:0] f19b, f19c, f19d;
+ wire [35:0] f36a, f36b;
+
+ reg f19a_sr = 0;
+ wire f19b_sr, f19c_sr, f19d_sr, f36a_sr, f36b_sr;
+ wire f19a_dr, f19b_dr, f19c_dr, f19d_dr, f36a_dr, f36b_dr;
+
+ fifo_short #(.WIDTH(19)) fifo_short1
+ (.clk(clk),.reset(rst),.clear(clear),
+ .datain(f19a),.src_rdy_i(f19a_sr),.dst_rdy_o(f19a_dr),
+ .dataout(f19b),.src_rdy_o(f19b_sr),.dst_rdy_i(f19b_dr) );
+
+ fifo19_to_fifo36 fifo19_to_fifo36
+ (.clk(clk),.reset(rst),.clear(clear),
+ .f19_datain(f19b),.f19_src_rdy_i(f19b_sr),.f19_dst_rdy_o(f19b_dr),
+ .f36_dataout(f36a),.f36_src_rdy_o(f36a_sr),.f36_dst_rdy_i(f36a_dr) );
+
+ fifo_short #(.WIDTH(36)) fifo_short2
+ (.clk(clk),.reset(rst),.clear(clear),
+ .datain(f36a),.src_rdy_i(f36a_sr),.dst_rdy_o(f36a_dr),
+ .dataout(f36b),.src_rdy_o(f36b_sr),.dst_rdy_i(f36b_dr) );
+
+ fifo36_to_fifo19 fifo36_to_fifo19
+ (.clk(clk),.reset(rst),.clear(clear),
+ .f36_datain(f36b),.f36_src_rdy_i(f36b_sr),.f36_dst_rdy_o(f36b_dr),
+ .f19_dataout(f19c),.f19_src_rdy_o(f19c_sr),.f19_dst_rdy_i(f19c_dr) );
+
+ fifo_short #(.WIDTH(19)) fifo_short3
+ (.clk(clk),.reset(rst),.clear(clear),
+ .datain(f19c),.src_rdy_i(f19c_sr),.dst_rdy_o(f19c_dr),
+ .dataout(f19d),.src_rdy_o(f19d_sr),.dst_rdy_i(f19d_dr) );
+
+ assign f19d_dr = 1;
+
+ always @(posedge clk)
+ if(f19a_sr & f19a_dr)
+ $display("18IN: %h", f19a);
+
+ always @(posedge clk)
+ if(f19d_sr & f19d_dr)
+ $display(" 18OUT: %h", f19d);
+
+ always @(posedge clk)
+ if(f36b_sr & f36b_dr)
+ $display(" 36: %h", f36b);
+
+ initial $dumpfile("fifo_tb.vcd");
+ initial $dumpvars(0,fifo_tb);
+
+ initial
+ begin
+ @(negedge rst);
+ @(posedge clk);
+ repeat (2)
+ begin
+ f19a <= 19'h1_AA01;
+ f19a_sr <= 1;
+ @(posedge clk);
+ f19a <= 19'h0_AA02;
+ repeat (4)
+ begin
+ @(posedge clk);
+ f19a <= f19a + 1;
+ end
+ f19a[18:16] <= 3'b010;
+ @(posedge clk);
+ f19a_sr <= 0;
+ f19a <= 19'h7_FFFF;
+ @(posedge clk);
+ end
+ #20000 $finish;
+ end
+endmodule // longfifo_tb
diff --git a/fpga/usrp2/fifo/fifo_2clock.v b/fpga/usrp2/fifo/fifo_2clock.v
new file mode 100644
index 000000000..756ad508f
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo_2clock.v
@@ -0,0 +1,139 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// FIXME ignores the AWIDTH (fifo size) parameter
+
+module fifo_2clock
+ #(parameter WIDTH=36, SIZE=6)
+ (input wclk, input [WIDTH-1:0] datain, input src_rdy_i, output dst_rdy_o, output [15:0] space,
+ input rclk, output [WIDTH-1:0] dataout, output src_rdy_o, input dst_rdy_i, output [15:0] occupied,
+ input arst);
+
+ wire [SIZE:0] level_rclk, level_wclk; // xilinx adds an extra bit if you ask for accurate levels
+ wire full, empty, write, read;
+
+ assign dst_rdy_o = ~full;
+ assign src_rdy_o = ~empty;
+ assign write = src_rdy_i & dst_rdy_o;
+ assign read = src_rdy_o & dst_rdy_i;
+ wire dummy;
+
+ generate
+ if(WIDTH==36)
+ if(SIZE==9)
+ fifo_xlnx_512x36_2clk fifo_xlnx_512x36_2clk
+ (.rst(arst),
+ .wr_clk(wclk),.din(datain),.full(full),.wr_en(write),.wr_data_count(level_wclk),
+ .rd_clk(rclk),.dout(dataout),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
+ else if(SIZE==11)
+ fifo_xlnx_2Kx36_2clk fifo_xlnx_2Kx36_2clk
+ (.rst(arst),
+ .wr_clk(wclk),.din(datain),.full(full),.wr_en(write),.wr_data_count(level_wclk),
+ .rd_clk(rclk),.dout(dataout),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
+ else if(SIZE==6)
+ fifo_xlnx_64x36_2clk fifo_xlnx_64x36_2clk
+ (.rst(arst),
+ .wr_clk(wclk),.din(datain),.full(full),.wr_en(write),.wr_data_count(level_wclk),
+ .rd_clk(rclk),.dout(dataout),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
+ else
+ fifo_xlnx_512x36_2clk fifo_xlnx_512x36_2clk
+ (.rst(arst),
+ .wr_clk(wclk),.din(datain),.full(full),.wr_en(write),.wr_data_count(level_wclk),
+ .rd_clk(rclk),.dout(dataout),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
+ else if((WIDTH==19) & (SIZE==4))
+ fifo_xlnx_16x19_2clk fifo_xlnx_16x19_2clk
+ (.rst(arst),
+ .wr_clk(wclk),.din(datain),.full(full),.wr_en(write),.wr_data_count(level_wclk),
+ .rd_clk(rclk),.dout(dataout),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
+ else if((WIDTH==18) & (SIZE==4))
+ fifo_xlnx_16x19_2clk fifo_xlnx_16x19_2clk
+ (.rst(arst),
+ .wr_clk(wclk),.din({1'b0,datain}),.full(full),.wr_en(write),.wr_data_count(level_wclk),
+ .rd_clk(rclk),.dout({dummy,dataout}),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
+ endgenerate
+
+ assign occupied = {{(16-SIZE-1){1'b0}},level_rclk};
+ assign space = ((1<<SIZE)+1)-level_wclk;
+
+endmodule // fifo_2clock
+
+/*
+`else
+ // ISE sucks, so the following doesn't work properly
+
+ reg [AWIDTH-1:0] wr_addr, rd_addr;
+ wire [AWIDTH-1:0] wr_addr_rclk, rd_addr_wclk;
+ wire [AWIDTH-1:0] next_rd_addr;
+ wire enb_read;
+
+ // Write side management
+ wire [AWIDTH-1:0] next_wr_addr = wr_addr + 1;
+ always @(posedge wclk or posedge arst)
+ if(arst)
+ wr_addr <= 0;
+ else if(write)
+ wr_addr <= next_wr_addr;
+ assign full = (next_wr_addr == rd_addr_wclk);
+
+ // RAM for data storage. Data out is registered, complicating the
+ // read side logic
+ ram_2port #(.DWIDTH(DWIDTH),.AWIDTH(AWIDTH)) mac_rx_ff_ram
+ (.clka(wclk),.ena(1'b1),.wea(write),.addra(wr_addr),.dia(datain),.doa(),
+ .clkb(rclk),.enb(enb_read),.web(1'b0),.addrb(next_rd_addr),.dib(0),.dob(dataout) );
+
+ // Read side management
+ reg data_valid;
+ assign empty = ~data_valid;
+ assign next_rd_addr = rd_addr + data_valid;
+ assign enb_read = read | ~data_valid;
+
+ always @(posedge rclk or posedge arst)
+ if(arst)
+ rd_addr <= 0;
+ else if(read)
+ rd_addr <= rd_addr + 1;
+
+ always @(posedge rclk or posedge arst)
+ if(arst)
+ data_valid <= 0;
+ else
+ if(read & (next_rd_addr == wr_addr_rclk))
+ data_valid <= 0;
+ else if(next_rd_addr != wr_addr_rclk)
+ data_valid <= 1;
+
+ // Send pointers across clock domains via gray code
+ gray_send #(.WIDTH(AWIDTH)) send_wr_addr
+ (.clk_in(wclk),.addr_in(wr_addr),
+ .clk_out(rclk),.addr_out(wr_addr_rclk) );
+
+ gray_send #(.WIDTH(AWIDTH)) send_rd_addr
+ (.clk_in(rclk),.addr_in(rd_addr),
+ .clk_out(wclk),.addr_out(rd_addr_wclk) );
+
+ // Generate fullness info, these are approximate and may be delayed
+ // and are only for higher-level flow control.
+ // Only full and empty are guaranteed exact.
+ always @(posedge wclk)
+ level_wclk <= wr_addr - rd_addr_wclk;
+ always @(posedge rclk)
+ level_rclk <= wr_addr_rclk - rd_addr;
+`endif
+endmodule // fifo_2clock
+
+*/
diff --git a/fpga/usrp2/fifo/fifo_2clock_cascade.v b/fpga/usrp2/fifo/fifo_2clock_cascade.v
new file mode 100644
index 000000000..49cac7097
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo_2clock_cascade.v
@@ -0,0 +1,58 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module fifo_2clock_cascade
+ #(parameter WIDTH=32, SIZE=9)
+ (input wclk, input [WIDTH-1:0] datain, input src_rdy_i, output dst_rdy_o,
+ output [15:0] space, output [15:0] short_space,
+ input rclk, output [WIDTH-1:0] dataout, output src_rdy_o, input dst_rdy_i,
+ output [15:0] occupied, output [15:0] short_occupied,
+ input arst);
+
+ wire [WIDTH-1:0] data_int1, data_int2;
+ wire src_rdy_int1, src_rdy_int2, dst_rdy_int1, dst_rdy_int2;
+ wire [SIZE-1:0] level_wclk, level_rclk;
+ wire [4:0] s1_space, s1_occupied, s2_space, s2_occupied;
+ wire [15:0] l_space, l_occupied;
+
+ fifo_short #(.WIDTH(WIDTH)) shortfifo
+ (.clk(wclk), .reset(arst), .clear(0),
+ .datain(datain), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o),
+ .dataout(data_int1), .src_rdy_o(src_rdy_int1), .dst_rdy_i(dst_rdy_int1),
+ .space(s1_space), .occupied(s1_occupied) );
+
+ fifo_2clock #(.WIDTH(WIDTH),.SIZE(SIZE)) fifo_2clock
+ (.wclk(wclk), .datain(data_int1), .src_rdy_i(src_rdy_int1), .dst_rdy_o(dst_rdy_int1), .space(l_space),
+ .rclk(rclk), .dataout(data_int2), .src_rdy_o(src_rdy_int2), .dst_rdy_i(dst_rdy_int2), .occupied(l_occupied),
+ .arst(arst) );
+
+ fifo_short #(.WIDTH(WIDTH)) shortfifo2
+ (.clk(rclk), .reset(arst), .clear(0),
+ .datain(data_int2), .src_rdy_i(src_rdy_int2), .dst_rdy_o(dst_rdy_int2),
+ .dataout(dataout), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i),
+ .space(s2_space), .occupied(s2_occupied));
+
+ // Be conservative -- Only advertise space from input side of fifo, occupied from output side
+ assign space = {11'b0,s1_space} + l_space;
+ assign occupied = {11'b0,s2_occupied} + l_occupied;
+
+ // For the fifo_extram, we only want to know the immediately adjacent space
+ assign short_space = {11'b0,s1_space};
+ assign short_occupied = {11'b0,s2_occupied};
+
+endmodule // fifo_2clock_cascade
diff --git a/fpga/usrp2/fifo/fifo_cascade.v b/fpga/usrp2/fifo/fifo_cascade.v
new file mode 100644
index 000000000..5a79c4090
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo_cascade.v
@@ -0,0 +1,69 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// This FIFO exists to provide an intermediate point for the data on its
+// long trek from one RAM (in the buffer pool) to another (in the longfifo)
+// The shortfifo is more flexible in its placement since it is based on
+// distributed RAM
+
+// This one has the shortfifo on both the in and out sides.
+module fifo_cascade
+ #(parameter WIDTH=32, SIZE=9)
+ (input clk, input reset, input clear,
+ input [WIDTH-1:0] datain,
+ input src_rdy_i,
+ output dst_rdy_o,
+ output [WIDTH-1:0] dataout,
+ output src_rdy_o,
+ input dst_rdy_i,
+ output [15:0] space,
+ output [15:0] occupied);
+
+ wire [WIDTH-1:0] data_int, data_int2;
+ wire src_rdy_1, dst_rdy_1, src_rdy_2, dst_rdy_2;
+
+ wire [4:0] s1_space, s1_occupied, s2_space, s2_occupied;
+ wire [15:0] l_space, l_occupied;
+
+ fifo_short #(.WIDTH(WIDTH)) head_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(datain), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o),
+ .dataout(data_int), .src_rdy_o(src_rdy_1), .dst_rdy_i(dst_rdy_1),
+ .space(s1_space),.occupied(s1_occupied) );
+
+ fifo_long #(.WIDTH(WIDTH),.SIZE(SIZE)) middle_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(data_int), .src_rdy_i(src_rdy_1), .dst_rdy_o(dst_rdy_1),
+ .dataout(data_int2), .src_rdy_o(src_rdy_2), .dst_rdy_i(dst_rdy_2),
+ .space(l_space),.occupied(l_occupied) );
+
+ fifo_short #(.WIDTH(WIDTH)) tail_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(data_int2), .src_rdy_i(src_rdy_2), .dst_rdy_o(dst_rdy_2),
+ .dataout(dataout), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i),
+ .space(s2_space),.occupied(s2_occupied) );
+
+ assign space = {11'b0,s1_space} + {11'b0,s2_space} + l_space;
+ assign occupied = {11'b0,s1_occupied} + {11'b0,s2_occupied} + l_occupied;
+
+endmodule // cascadefifo2
+
+
+
+
diff --git a/fpga/usrp2/fifo/fifo_long.v b/fpga/usrp2/fifo/fifo_long.v
new file mode 100644
index 000000000..c4f0a1cc2
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo_long.v
@@ -0,0 +1,165 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// FIFO intended to be interchangeable with shortfifo, but
+// based on block ram instead of SRL16's
+// only one clock domain
+
+// Port A is write port, Port B is read port
+
+module fifo_long
+ #(parameter WIDTH=32, SIZE=9)
+ (input clk, input reset, input clear,
+ input [WIDTH-1:0] datain,
+ input src_rdy_i,
+ output dst_rdy_o,
+ output [WIDTH-1:0] dataout,
+ output src_rdy_o,
+ input dst_rdy_i,
+
+ output reg [15:0] space,
+ output reg [15:0] occupied);
+
+ wire write = src_rdy_i & dst_rdy_o;
+ wire read = dst_rdy_i & src_rdy_o;
+ wire full, empty;
+
+ assign dst_rdy_o = ~full;
+ assign src_rdy_o = ~empty;
+
+ // Read side states
+ localparam EMPTY = 0;
+ localparam PRE_READ = 1;
+ localparam READING = 2;
+
+ reg [SIZE-1:0] wr_addr, rd_addr;
+ reg [1:0] read_state;
+
+ reg empty_reg, full_reg;
+ always @(posedge clk)
+ if(reset)
+ wr_addr <= 0;
+ else if(clear)
+ wr_addr <= 0;
+ else if(write)
+ wr_addr <= wr_addr + 1;
+
+ ram_2port #(.DWIDTH(WIDTH),.AWIDTH(SIZE))
+ ram (.clka(clk),
+ .ena(1'b1),
+ .wea(write),
+ .addra(wr_addr),
+ .dia(datain),
+ .doa(),
+
+ .clkb(clk),
+ .enb((read_state==PRE_READ)|read),
+ .web(0),
+ .addrb(rd_addr),
+ .dib({WIDTH{1'b1}}),
+ .dob(dataout));
+
+ always @(posedge clk)
+ if(reset)
+ begin
+ read_state <= EMPTY;
+ rd_addr <= 0;
+ empty_reg <= 1;
+ end
+ else
+ if(clear)
+ begin
+ read_state <= EMPTY;
+ rd_addr <= 0;
+ empty_reg <= 1;
+ end
+ else
+ case(read_state)
+ EMPTY :
+ if(write)
+ begin
+ //rd_addr <= wr_addr;
+ read_state <= PRE_READ;
+ end
+ PRE_READ :
+ begin
+ read_state <= READING;
+ empty_reg <= 0;
+ rd_addr <= rd_addr + 1;
+ end
+
+ READING :
+ if(read)
+ if(rd_addr == wr_addr)
+ begin
+ empty_reg <= 1;
+ if(write)
+ read_state <= PRE_READ;
+ else
+ read_state <= EMPTY;
+ end
+ else
+ rd_addr <= rd_addr + 1;
+ endcase // case(read_state)
+
+ wire [SIZE-1:0] dont_write_past_me = rd_addr - 3;
+ wire becoming_full = wr_addr == dont_write_past_me;
+
+ always @(posedge clk)
+ if(reset)
+ full_reg <= 0;
+ else if(clear)
+ full_reg <= 0;
+ else if(read & ~write)
+ full_reg <= 0;
+ //else if(write & ~read & (wr_addr == (rd_addr-3)))
+ else if(write & ~read & becoming_full)
+ full_reg <= 1;
+
+ //assign empty = (read_state != READING);
+ assign empty = empty_reg;
+
+ // assign full = ((rd_addr - 1) == wr_addr);
+ assign full = full_reg;
+
+ //////////////////////////////////////////////
+ // space and occupied are for diagnostics only
+ // not guaranteed exact
+
+ localparam NUMLINES = (1<<SIZE)-2;
+ always @(posedge clk)
+ if(reset)
+ space <= NUMLINES;
+ else if(clear)
+ space <= NUMLINES;
+ else if(read & ~write)
+ space <= space + 1;
+ else if(write & ~read)
+ space <= space - 1;
+
+ always @(posedge clk)
+ if(reset)
+ occupied <= 0;
+ else if(clear)
+ occupied <= 0;
+ else if(read & ~write)
+ occupied <= occupied - 1;
+ else if(write & ~read)
+ occupied <= occupied + 1;
+
+endmodule // fifo_long
diff --git a/fpga/usrp2/fifo/fifo_pacer.v b/fpga/usrp2/fifo/fifo_pacer.v
new file mode 100644
index 000000000..3e3fbf8b8
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo_pacer.v
@@ -0,0 +1,41 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module fifo_pacer
+ (input clk,
+ input reset,
+ input [7:0] rate,
+ input enable,
+ input src1_rdy_i, output dst1_rdy_o,
+ output src2_rdy_o, input dst2_rdy_i,
+ output underrun, overrun);
+
+ wire strobe;
+
+ cic_strober strober (.clock(clk), .reset(reset), .enable(enable),
+ .rate(rate), .strobe_fast(1), .strobe_slow(strobe));
+
+ wire all_ready = src1_rdy_i & dst2_rdy_i;
+ assign dst1_rdy_o = all_ready & strobe;
+ assign src2_rdy_o = dst1_rdy_o;
+
+ assign underrun = strobe & ~src1_rdy_i;
+ assign overrun = strobe & ~dst2_rdy_i;
+
+endmodule // fifo_pacer
diff --git a/fpga/usrp2/fifo/fifo_short.v b/fpga/usrp2/fifo/fifo_short.v
new file mode 100644
index 000000000..32f26beef
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo_short.v
@@ -0,0 +1,112 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module fifo_short
+ #(parameter WIDTH=32)
+ (input clk, input reset, input clear,
+ input [WIDTH-1:0] datain,
+ input src_rdy_i,
+ output dst_rdy_o,
+ output [WIDTH-1:0] dataout,
+ output src_rdy_o,
+ input dst_rdy_i,
+
+ output reg [4:0] space,
+ output reg [4:0] occupied);
+
+ reg full, empty;
+ wire write = src_rdy_i & dst_rdy_o;
+ wire read = dst_rdy_i & src_rdy_o;
+
+ assign dst_rdy_o = ~full;
+ assign src_rdy_o = ~empty;
+
+ reg [3:0] a;
+ genvar i;
+
+ generate
+ for (i=0;i<WIDTH;i=i+1)
+ begin : gen_srl16
+ SRL16E
+ srl16e(.Q(dataout[i]),
+ .A0(a[0]),.A1(a[1]),.A2(a[2]),.A3(a[3]),
+ .CE(write),.CLK(clk),.D(datain[i]));
+ end
+ endgenerate
+
+ always @(posedge clk)
+ if(reset)
+ begin
+ a <= 0;
+ empty <= 1;
+ full <= 0;
+ end
+ else if(clear)
+ begin
+ a <= 0;
+ empty <= 1;
+ full<= 0;
+ end
+ else if(read & ~write)
+ begin
+ full <= 0;
+ if(a==0)
+ empty <= 1;
+ else
+ a <= a - 1;
+ end
+ else if(write & ~read)
+ begin
+ empty <= 0;
+ if(~empty)
+ a <= a + 1;
+ if(a == 14)
+ full <= 1;
+ end
+
+ // NOTE will fail if you write into a full fifo or read from an empty one
+
+ //////////////////////////////////////////////////////////////
+ // space and occupied are used for diagnostics, not
+ // guaranteed correct
+
+ //assign space = full ? 0 : empty ? 16 : 15-a;
+ //assign occupied = empty ? 0 : full ? 16 : a+1;
+
+ always @(posedge clk)
+ if(reset)
+ space <= 16;
+ else if(clear)
+ space <= 16;
+ else if(read & ~write)
+ space <= space + 1;
+ else if(write & ~read)
+ space <= space - 1;
+
+ always @(posedge clk)
+ if(reset)
+ occupied <= 0;
+ else if(clear)
+ occupied <= 0;
+ else if(read & ~write)
+ occupied <= occupied - 1;
+ else if(write & ~read)
+ occupied <= occupied + 1;
+
+endmodule // fifo_short
+
diff --git a/fpga/usrp2/fifo/fifo_spec.txt b/fpga/usrp2/fifo/fifo_spec.txt
new file mode 100644
index 000000000..133b9fa8e
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo_spec.txt
@@ -0,0 +1,36 @@
+
+
+FIFO and Buffer Interface Spec
+
+Buffer Interface Data Wires -- matches fifo36
+ DATA[31:0]
+ FLAGS[3:0]
+ Bit 0 SOP
+ Bit 1 EOP
+ If SOP=1 && EOP=1, OCC contains error flags
+ Bits 3:2 OCC[1:0] --> 00 = all 4 bytes
+ 01 = 1 byte
+ 10 = 2 bytes
+ 11 = 3 bytes
+
+fifo36 --> {OCC[1:0],EOP,SOP,DATA[31:0]}
+ OCC same as buffer interface
+
+fifo19 --> {OCC,EOP,SOP,DATA[15:0]}
+ Doesn't fit well into BRAM, dist RAM ok
+ OCC = 1 means last word is half full
+ = 0 means last word is full
+
+fifo18 --> {EOP,SOP,DATA[15:0]}
+ No half-word capability? Should we drop sop instead?
+
+Control Wires - Data into FIFO
+ SRC_RDY_i Upstream has data for me
+ DST_RDY_o I have space
+ Transfer occurs if SRC_RDI_i && DST_RDY_o
+
+Control Wires - Data out of FIFO
+ SRC_RDY_o I have data for downstream
+ DST_RDY_i Downstream has space
+ Transfer occurs if SRC_RDI_o && DST_RDY_i
+
diff --git a/fpga/usrp2/fifo/fifo_tb.v b/fpga/usrp2/fifo/fifo_tb.v
new file mode 100644
index 000000000..c63c201d0
--- /dev/null
+++ b/fpga/usrp2/fifo/fifo_tb.v
@@ -0,0 +1,72 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+module fifo_tb();
+
+ reg clk = 0;
+ reg rst = 1;
+ reg clear = 0;
+ initial #1000 rst = 0;
+ always #50 clk = ~clk;
+
+ reg [31:0] f36_data = 0;
+ reg [1:0] f36_occ = 0;
+ reg f36_sof = 0, f36_eof = 0;
+ reg f36_src_rdy;
+ wire f36_dst_rdy;
+
+ wire [7:0] ll_data;
+ wire ll_src_rdy, ll_dst_rdy, ll_sof, ll_eof;
+ wire [35:0] err_dat;
+ wire err_src_rdy, err_dst_rdy;
+
+ fifo36_to_ll8 fifo36_to_ll8
+ (.clk(clk),.reset(rst),.clear(clear),
+ .f36_data({f36_occ,f36_eof,f36_sof,f36_data}),.f36_src_rdy_i(f36_src_rdy),.f36_dst_rdy_o(f36_dst_rdy),
+ .ll_data(ll_data),.ll_sof(ll_sof),.ll_eof(ll_eof),
+ .ll_src_rdy(ll_src_rdy),.ll_dst_rdy(ll_dst_rdy));
+
+ assign ll_dst_rdy = 1;
+
+ always @(posedge clk)
+ if(ll_src_rdy)
+ $display("LL: SOF %d, EOF %d, DAT %x",ll_sof,ll_eof,ll_data);
+
+ initial $dumpfile("fifo_tb.vcd");
+ initial $dumpvars(0,fifo_tb);
+
+ initial
+ begin
+ @(negedge rst);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ f36_src_rdy <= 1;
+ {f36_occ,f36_eof,f36_sof,f36_data} <= { 2'b00,1'b0,1'b1,32'h00010203};
+ @(posedge clk);
+ {f36_occ,f36_eof,f36_sof,f36_data} <= { 2'b00,1'b0,1'b0,32'h04050607};
+ @(posedge clk);
+ {f36_occ,f36_eof,f36_sof,f36_data} <= { 2'b00,1'b0,1'b0,32'h08090a0b};
+ @(posedge clk);
+ {f36_occ,f36_eof,f36_sof,f36_data} <= { 2'b11,1'b1,1'b0,32'h0c0d0e0f};
+ @(posedge clk);
+ f36_src_rdy <= 0;
+ end
+
+ initial #4000 $finish;
+endmodule // longfifo_tb
diff --git a/fpga/usrp2/fifo/ll8_shortfifo.v b/fpga/usrp2/fifo/ll8_shortfifo.v
new file mode 100644
index 000000000..49b3a3139
--- /dev/null
+++ b/fpga/usrp2/fifo/ll8_shortfifo.v
@@ -0,0 +1,30 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module ll8_shortfifo
+ (input clk, input reset, input clear,
+ input [7:0] datain, input sof_i, input eof_i, input error_i, input src_rdy_i, output dst_rdy_o,
+ output [7:0] dataout, output sof_o, output eof_o, output error_o, output src_rdy_o, input dst_rdy_i);
+
+ fifo_short #(.WIDTH(11)) fifo_short
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain({error_i,eof_i,sof_i,datain}), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o),
+ .dataout({error_o,eof_o,sof_o,dataout}), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i));
+
+endmodule // ll8_shortfifo
diff --git a/fpga/usrp2/fifo/ll8_to_fifo19.v b/fpga/usrp2/fifo/ll8_to_fifo19.v
new file mode 100644
index 000000000..4503d0c3d
--- /dev/null
+++ b/fpga/usrp2/fifo/ll8_to_fifo19.v
@@ -0,0 +1,104 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module ll8_to_fifo19
+ (input clk, input reset, input clear,
+ input [7:0] ll_data,
+ input ll_sof,
+ input ll_eof,
+ input ll_src_rdy,
+ output ll_dst_rdy,
+
+ output [18:0] f19_data,
+ output f19_src_rdy_o,
+ input f19_dst_rdy_i );
+
+ // Short FIFO on input to guarantee no deadlock
+ wire [7:0] ll_data_int;
+ wire ll_sof_int, ll_eof_int, ll_src_rdy_int, ll_dst_rdy_int;
+
+ ll8_shortfifo head_fifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(ll_data), .sof_i(ll_sof), .eof_i(ll_eof),
+ .error_i(0), .src_rdy_i(ll_src_rdy), .dst_rdy_o(ll_dst_rdy),
+ .dataout(ll_data_int), .sof_o(ll_sof_int), .eof_o(ll_eof_int),
+ .error_o(), .src_rdy_o(ll_src_rdy_int), .dst_rdy_i(ll_dst_rdy_int));
+
+ // Actual ll8_to_fifo19 which could deadlock if not connected to a shortfifo
+ localparam XFER_EMPTY = 0;
+ localparam XFER_HALF = 1;
+ localparam XFER_HALF_WRITE = 3;
+
+ wire [18:0] f19_data_int;
+ wire f19_sof_int, f19_eof_int, f19_occ_int, f19_src_rdy_int, f19_dst_rdy_int;
+
+ wire xfer_out = f19_src_rdy_int & f19_dst_rdy_int;
+ wire xfer_in = ll_src_rdy_int & ll_dst_rdy_int;
+ reg hold_sof;
+
+ reg [1:0] state;
+ reg [7:0] hold_reg;
+
+ always @(posedge clk)
+ if(ll_src_rdy_int & (state==XFER_EMPTY))
+ hold_reg <= ll_data_int;
+
+ always @(posedge clk)
+ if(ll_sof_int & (state==XFER_EMPTY))
+ hold_sof <= 1;
+ else if(xfer_out)
+ hold_sof <= 0;
+
+ always @(posedge clk)
+ if(reset | clear)
+ state <= XFER_EMPTY;
+ else
+ case(state)
+ XFER_EMPTY :
+ if(ll_src_rdy_int)
+ if(ll_eof_int)
+ state <= XFER_HALF_WRITE;
+ else
+ state <= XFER_HALF;
+ XFER_HALF :
+ if(ll_src_rdy_int & f19_dst_rdy_int)
+ state <= XFER_EMPTY;
+ XFER_HALF_WRITE :
+ if(f19_dst_rdy_int)
+ state <= XFER_EMPTY;
+ endcase // case (state)
+
+ assign ll_dst_rdy_int = (state==XFER_EMPTY) | ((state==XFER_HALF)&f19_dst_rdy_int);
+ assign f19_src_rdy_int= (state==XFER_HALF_WRITE) | ((state==XFER_HALF)&ll_src_rdy_int);
+
+ assign f19_sof_int = hold_sof | (ll_sof_int & (state==XFER_HALF));
+ assign f19_eof_int = (state == XFER_HALF_WRITE) | ll_eof_int;
+ assign f19_occ_int = (state == XFER_HALF_WRITE);
+
+ assign f19_data_int = {f19_occ_int,f19_eof_int,f19_sof_int,hold_reg,ll_data_int};
+
+ // Shortfifo on output to guarantee no deadlock
+ fifo_short #(.WIDTH(19)) tail_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain(f19_data_int), .src_rdy_i(f19_src_rdy_int), .dst_rdy_o(f19_dst_rdy_int),
+ .dataout(f19_data), .src_rdy_o(f19_src_rdy_o), .dst_rdy_i(f19_dst_rdy_i),
+ .space(),.occupied() );
+
+
+endmodule // ll8_to_fifo19
+
diff --git a/fpga/usrp2/fifo/ll8_to_fifo36.v b/fpga/usrp2/fifo/ll8_to_fifo36.v
new file mode 100644
index 000000000..b26f745d2
--- /dev/null
+++ b/fpga/usrp2/fifo/ll8_to_fifo36.v
@@ -0,0 +1,114 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module ll8_to_fifo36
+ (input clk, input reset, input clear,
+ input [7:0] ll_data,
+ input ll_sof_n,
+ input ll_eof_n,
+ input ll_src_rdy_n,
+ output ll_dst_rdy_n,
+
+ output [35:0] f36_data,
+ output f36_src_rdy_o,
+ input f36_dst_rdy_i );
+
+ wire f36_write = f36_src_rdy_o & f36_dst_rdy_i;
+
+ // Why anybody would use active low in an FPGA is beyond me...
+ wire ll_sof = ~ll_sof_n;
+ wire ll_eof = ~ll_eof_n;
+ wire ll_src_rdy = ~ll_src_rdy_n;
+ wire ll_dst_rdy;
+ assign ll_dst_rdy_n = ~ll_dst_rdy;
+
+ reg f36_sof, f36_eof;
+ reg [1:0] f36_occ;
+
+
+ reg [2:0] state;
+ reg [7:0] dat0, dat1, dat2, dat3;
+
+ always @(posedge clk)
+ if(ll_src_rdy & ((state==0)|f36_write))
+ f36_sof <= ll_sof;
+
+ always @(posedge clk)
+ if(ll_src_rdy & ((state !=4)|f36_write))
+ f36_eof <= ll_eof;
+
+ always @(posedge clk)
+ if(ll_eof)
+ f36_occ <= state[1:0] + 1;
+ else
+ f36_occ <= 0;
+
+ always @(posedge clk)
+ if(reset)
+ state <= 0;
+ else
+ if(ll_src_rdy)
+ case(state)
+ 0 :
+ if(ll_eof)
+ state <= 4;
+ else
+ state <= 1;
+ 1 :
+ if(ll_eof)
+ state <= 4;
+ else
+ state <= 2;
+ 2 :
+ if(ll_eof)
+ state <= 4;
+ else
+ state <= 3;
+ 3 : state <= 4;
+ 4 :
+ if(f36_dst_rdy_i)
+ if(ll_eof)
+ state <= 4;
+ else
+ state <= 1;
+ endcase // case(state)
+ else
+ if(f36_write)
+ state <= 0;
+
+ always @(posedge clk)
+ if(ll_src_rdy & (state==3))
+ dat3 <= ll_data;
+
+ always @(posedge clk)
+ if(ll_src_rdy & (state==2))
+ dat2 <= ll_data;
+
+ always @(posedge clk)
+ if(ll_src_rdy & (state==1))
+ dat1 <= ll_data;
+
+ always @(posedge clk)
+ if(ll_src_rdy & ((state==0) | f36_write))
+ dat0 <= ll_data;
+
+ assign ll_dst_rdy = f36_dst_rdy_i | (state != 4);
+ assign f36_data = {f36_occ,f36_eof,f36_sof,dat0,dat1,dat2,dat3}; // FIXME endianess
+ assign f36_src_rdy_o = (state == 4);
+
+endmodule // ll8_to_fifo36
diff --git a/fpga/usrp2/fifo/packet32_tb.v b/fpga/usrp2/fifo/packet32_tb.v
new file mode 100644
index 000000000..8a7cfcec5
--- /dev/null
+++ b/fpga/usrp2/fifo/packet32_tb.v
@@ -0,0 +1,44 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module packet32_tb();
+
+ wire [35:0] data;
+ wire src_rdy, dst_rdy;
+
+ wire clear = 0;
+ reg clk = 0;
+ reg reset = 1;
+
+ always #10 clk <= ~clk;
+ initial #1000 reset <= 0;
+
+ initial $dumpfile("packet32_tb.vcd");
+ initial $dumpvars(0,packet32_tb);
+
+ wire [31:0] total, crc_err, seq_err, len_err;
+
+ packet_generator32 pkt_gen (.clk(clk), .reset(reset), .clear(clear),
+ .data_o(data), .src_rdy_o(src_rdy), .dst_rdy_i(dst_rdy));
+
+ packet_verifier32 pkt_ver (.clk(clk), .reset(reset), .clear(clear),
+ .data_i(data), .src_rdy_i(src_rdy), .dst_rdy_o(dst_rdy),
+ .total(total), .crc_err(crc_err), .seq_err(seq_err), .len_err(len_err));
+
+endmodule // packet32_tb
diff --git a/fpga/usrp2/fifo/packet_dispatcher36_x3.v b/fpga/usrp2/fifo/packet_dispatcher36_x3.v
new file mode 100644
index 000000000..0f9e752c8
--- /dev/null
+++ b/fpga/usrp2/fifo/packet_dispatcher36_x3.v
@@ -0,0 +1,294 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// Packet dispatcher with fifo36 interface and 3 outputs.
+//
+// The packet dispatcher expects 2-byte padded ethernet frames.
+// The frames will be inspected at ethernet, IPv4, UDP, and VRT layers.
+// Packets are dispatched into the following streams:
+// * tx dsp stream
+// * to cpu stream
+// * to external stream
+// * to both cpu and external
+//
+// The following registers are used for dispatcher control:
+// * base + 0 = this ipv4 address (32 bits)
+// * base + 1 = udp dst port (lower 16 bits)
+//
+
+module packet_dispatcher36_x3
+ #(
+ parameter BASE = 0
+ )
+ (
+ //clocking and reset interface:
+ input clk, input rst, input clr,
+
+ //setting register interface:
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ //input stream interfaces:
+ input [35:0] com_inp_data, input com_inp_valid, output com_inp_ready,
+
+ //output stream interfaces:
+ output [35:0] ext_out_data, output ext_out_valid, input ext_out_ready,
+ output [35:0] dsp_out_data, output dsp_out_valid, input dsp_out_ready,
+ output [35:0] cpu_out_data, output cpu_out_valid, input cpu_out_ready
+ );
+
+ //setting register to program the IP address
+ wire [31:0] my_ip_addr;
+ setting_reg #(.my_addr(BASE+0)) sreg_ip_addr(
+ .clk(clk),.rst(rst),
+ .strobe(set_stb),.addr(set_addr),.in(set_data),
+ .out(my_ip_addr),.changed()
+ );
+
+ //setting register to program the UDP DSP port
+ wire [15:0] dsp_udp_port;
+ setting_reg #(.my_addr(BASE+1), .width(16)) sreg_data_port(
+ .clk(clk),.rst(rst),
+ .strobe(set_stb),.addr(set_addr),.in(set_data),
+ .out(dsp_udp_port),.changed()
+ );
+
+ ////////////////////////////////////////////////////////////////////
+ // Communication input inspector
+ // - inspect com input and send it to DSP, EXT, CPU, or BOTH
+ ////////////////////////////////////////////////////////////////////
+ localparam PD_STATE_READ_COM_PRE = 0;
+ localparam PD_STATE_READ_COM = 1;
+ localparam PD_STATE_WRITE_REGS = 2;
+ localparam PD_STATE_WRITE_LIVE = 3;
+
+ localparam PD_DEST_DSP = 0;
+ localparam PD_DEST_EXT = 1;
+ localparam PD_DEST_CPU = 2;
+ localparam PD_DEST_BOF = 3;
+
+ localparam PD_MAX_NUM_DREGS = 13; //padded_eth + ip + udp + seq + vrt_hdr
+ localparam PD_DREGS_DSP_OFFSET = 11; //offset to start dsp at
+
+ //output inspector interfaces
+ wire [35:0] pd_out_dsp_data;
+ wire pd_out_dsp_valid;
+ wire pd_out_dsp_ready;
+
+ wire [35:0] pd_out_ext_data;
+ wire pd_out_ext_valid;
+ wire pd_out_ext_ready;
+
+ wire [35:0] pd_out_cpu_data;
+ wire pd_out_cpu_valid;
+ wire pd_out_cpu_ready;
+
+ wire [35:0] pd_out_bof_data;
+ wire pd_out_bof_valid;
+ wire pd_out_bof_ready;
+
+ reg [1:0] pd_state;
+ reg [1:0] pd_dest;
+ reg [3:0] pd_dreg_count; //data registers to buffer headers
+ wire [3:0] pd_dreg_count_next = pd_dreg_count + 1'b1;
+ wire pd_dreg_counter_done = (pd_dreg_count_next == PD_MAX_NUM_DREGS)? 1'b1 : 1'b0;
+ reg [35:0] pd_dregs [PD_MAX_NUM_DREGS-1:0];
+
+ reg is_eth_dst_mac_bcast;
+ reg is_eth_type_ipv4;
+ reg is_eth_ipv4_proto_udp;
+ reg is_eth_ipv4_dst_addr_here;
+ reg is_eth_udp_dst_port_here;
+ wire is_vrt_size_zero = (com_inp_data[15:0] == 16'h0); //needed on the same cycle, so it cant be registered
+
+ //Inspector output flags special case:
+ //Inject SOF into flags at first DSP line.
+ wire [3:0] pd_out_flags = (
+ (pd_dreg_count == PD_DREGS_DSP_OFFSET) &&
+ (pd_dest == PD_DEST_DSP)
+ )? 4'b0001 : pd_dregs[pd_dreg_count][35:32];
+
+ //The communication inspector ouput data and valid signals:
+ //Mux between com input and data registers based on the state.
+ wire [35:0] pd_out_data = (pd_state == PD_STATE_WRITE_REGS)?
+ {pd_out_flags, pd_dregs[pd_dreg_count][31:0]} : com_inp_data
+ ;
+ wire pd_out_valid =
+ (pd_state == PD_STATE_WRITE_REGS)? 1'b1 : (
+ (pd_state == PD_STATE_WRITE_LIVE)? com_inp_valid : (
+ 1'b0));
+
+ //The communication inspector ouput ready signal:
+ //Mux between the various destination ready signals.
+ wire pd_out_ready =
+ (pd_dest == PD_DEST_DSP)? pd_out_dsp_ready : (
+ (pd_dest == PD_DEST_EXT)? pd_out_ext_ready : (
+ (pd_dest == PD_DEST_CPU)? pd_out_cpu_ready : (
+ (pd_dest == PD_DEST_BOF)? pd_out_bof_ready : (
+ 1'b0))));
+
+ //Always connected output data lines.
+ assign pd_out_dsp_data = pd_out_data;
+ assign pd_out_ext_data = pd_out_data;
+ assign pd_out_cpu_data = pd_out_data;
+ assign pd_out_bof_data = pd_out_data;
+
+ //Destination output valid signals:
+ //Comes from inspector valid when destination is selected, and otherwise low.
+ assign pd_out_dsp_valid = (pd_dest == PD_DEST_DSP)? pd_out_valid : 1'b0;
+ assign pd_out_ext_valid = (pd_dest == PD_DEST_EXT)? pd_out_valid : 1'b0;
+ assign pd_out_cpu_valid = (pd_dest == PD_DEST_CPU)? pd_out_valid : 1'b0;
+ assign pd_out_bof_valid = (pd_dest == PD_DEST_BOF)? pd_out_valid : 1'b0;
+
+ //The communication inspector ouput ready signal:
+ //Always ready when storing to data registers,
+ //comes from inspector ready output when live,
+ //and otherwise low.
+ assign com_inp_ready =
+ (pd_state == PD_STATE_READ_COM_PRE) ? 1'b1 : (
+ (pd_state == PD_STATE_READ_COM) ? 1'b1 : (
+ (pd_state == PD_STATE_WRITE_LIVE) ? pd_out_ready : (
+ 1'b0)));
+
+ //inspect the incoming data and mark register booleans
+ always @(posedge clk)
+ if (com_inp_ready & com_inp_valid) begin
+ case(pd_dreg_count)
+ 0: begin
+ is_eth_dst_mac_bcast <= (com_inp_data[15:0] == 16'hffff);
+ end
+ 1: begin
+ is_eth_dst_mac_bcast <= is_eth_dst_mac_bcast && (com_inp_data[31:0] == 32'hffffffff);
+ end
+ 3: begin
+ is_eth_type_ipv4 <= (com_inp_data[15:0] == 16'h800);
+ end
+ 6: begin
+ is_eth_ipv4_proto_udp <= (com_inp_data[23:16] == 8'h11);
+ end
+ 8: begin
+ is_eth_ipv4_dst_addr_here <= (com_inp_data[31:0] == my_ip_addr);
+ end
+ 9: begin
+ is_eth_udp_dst_port_here <= (com_inp_data[15:0] == dsp_udp_port);
+ end
+ endcase //pd_dreg_count
+ end
+
+ always @(posedge clk)
+ if(rst | clr) begin
+ pd_state <= PD_STATE_READ_COM_PRE;
+ pd_dreg_count <= 0;
+ end
+ else begin
+ case(pd_state)
+ PD_STATE_READ_COM_PRE: begin
+ if (com_inp_ready & com_inp_valid & com_inp_data[32]) begin
+ pd_state <= PD_STATE_READ_COM;
+ pd_dreg_count <= pd_dreg_count_next;
+ pd_dregs[pd_dreg_count] <= com_inp_data;
+ end
+ end
+
+ PD_STATE_READ_COM: begin
+ if (com_inp_ready & com_inp_valid) begin
+ pd_dregs[pd_dreg_count] <= com_inp_data;
+ if (pd_dreg_counter_done | com_inp_data[33]) begin
+ pd_state <= PD_STATE_WRITE_REGS;
+ pd_dreg_count <= 0;
+
+ //---------- begin inspection decision -----------//
+ //EOF or bcast or not IPv4 or not UDP:
+ if (
+ com_inp_data[33] || is_eth_dst_mac_bcast ||
+ ~is_eth_type_ipv4 || ~is_eth_ipv4_proto_udp
+ ) begin
+ pd_dest <= PD_DEST_BOF;
+ end
+
+ //not my IP address:
+ else if (~is_eth_ipv4_dst_addr_here) begin
+ pd_dest <= PD_DEST_EXT;
+ end
+
+ //UDP data port and VRT:
+ else if (is_eth_udp_dst_port_here && ~is_vrt_size_zero) begin
+ pd_dest <= PD_DEST_DSP;
+ pd_dreg_count <= PD_DREGS_DSP_OFFSET;
+ end
+
+ //other:
+ else begin
+ pd_dest <= PD_DEST_CPU;
+ end
+ //---------- end inspection decision -------------//
+
+ end
+ else begin
+ pd_dreg_count <= pd_dreg_count_next;
+ end
+ end
+ end
+
+ PD_STATE_WRITE_REGS: begin
+ if (pd_out_ready & pd_out_valid) begin
+ if (pd_out_data[33]) begin
+ pd_state <= PD_STATE_READ_COM_PRE;
+ pd_dreg_count <= 0;
+ end
+ else if (pd_dreg_counter_done) begin
+ pd_state <= PD_STATE_WRITE_LIVE;
+ pd_dreg_count <= 0;
+ end
+ else begin
+ pd_dreg_count <= pd_dreg_count_next;
+ end
+ end
+ end
+
+ PD_STATE_WRITE_LIVE: begin
+ if (pd_out_ready & pd_out_valid & pd_out_data[33]) begin
+ pd_state <= PD_STATE_READ_COM_PRE;
+ end
+ end
+
+ endcase //pd_state
+ end
+
+ //connect this fast-path signals directly to the DSP out
+ assign dsp_out_data = pd_out_dsp_data;
+ assign dsp_out_valid = pd_out_dsp_valid;
+ assign pd_out_dsp_ready = dsp_out_ready;
+
+ ////////////////////////////////////////////////////////////////////
+ // Splitter and output muxes for the bof packets
+ // - split the bof packets into two streams
+ // - mux split packets into cpu out and ext out
+ ////////////////////////////////////////////////////////////////////
+
+ //dummy signals to join the the splitter and muxes below
+ wire [35:0] _split_to_ext_data, _split_to_cpu_data;
+ wire _split_to_ext_valid, _split_to_cpu_valid;
+ wire _split_to_ext_ready, _split_to_cpu_ready;
+
+ splitter36 bof_out_splitter(
+ .clk(clk), .rst(rst), .clr(clr),
+ .inp_data(pd_out_bof_data), .inp_valid(pd_out_bof_valid), .inp_ready(pd_out_bof_ready),
+ .out0_data(_split_to_ext_data), .out0_valid(_split_to_ext_valid), .out0_ready(_split_to_ext_ready),
+ .out1_data(_split_to_cpu_data), .out1_valid(_split_to_cpu_valid), .out1_ready(_split_to_cpu_ready)
+ );
+
+ fifo36_mux ext_out_mux(
+ .clk(clk), .reset(rst), .clear(clr),
+ .data0_i(pd_out_ext_data), .src0_rdy_i(pd_out_ext_valid), .dst0_rdy_o(pd_out_ext_ready),
+ .data1_i(_split_to_ext_data), .src1_rdy_i(_split_to_ext_valid), .dst1_rdy_o(_split_to_ext_ready),
+ .data_o(ext_out_data), .src_rdy_o(ext_out_valid), .dst_rdy_i(ext_out_ready)
+ );
+
+ fifo36_mux cpu_out_mux(
+ .clk(clk), .reset(rst), .clear(clr),
+ .data0_i(pd_out_cpu_data), .src0_rdy_i(pd_out_cpu_valid), .dst0_rdy_o(pd_out_cpu_ready),
+ .data1_i(_split_to_cpu_data), .src1_rdy_i(_split_to_cpu_valid), .dst1_rdy_o(_split_to_cpu_ready),
+ .data_o(cpu_out_data), .src_rdy_o(cpu_out_valid), .dst_rdy_i(cpu_out_ready)
+ );
+
+endmodule // packet_dispatcher36_x3
diff --git a/fpga/usrp2/fifo/packet_generator.v b/fpga/usrp2/fifo/packet_generator.v
new file mode 100644
index 000000000..5e9d3c2ab
--- /dev/null
+++ b/fpga/usrp2/fifo/packet_generator.v
@@ -0,0 +1,100 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module packet_generator
+ (input clk, input reset, input clear,
+ output reg [7:0] data_o, output sof_o, output eof_o,
+ input [127:0] header,
+ output src_rdy_o, input dst_rdy_i);
+
+ localparam len = 32'd2000;
+
+ reg [31:0] state;
+ reg [31:0] seq;
+ reg [31:0] crc_out;
+ wire calc_crc = src_rdy_o & dst_rdy_i & ~(state[31:2] == 30'h3FFF_FFFF);
+
+
+ always @(posedge clk)
+ if(reset | clear)
+ seq <= 0;
+ else
+ if(eof_o & src_rdy_o & dst_rdy_i)
+ seq <= seq + 1;
+
+ always @(posedge clk)
+ if(reset | clear)
+ state <= 0;
+ else
+ if(src_rdy_o & dst_rdy_i)
+ if(state == (len - 1))
+ state <= 32'hFFFF_FFFC;
+ else
+ state <= state + 1;
+
+ always @*
+ case(state)
+ 0 : data_o <= len[31:24];
+ 1 : data_o <= len[23:16];
+ 2 : data_o <= len[15:8];
+ 3 : data_o <= len[7:0];
+ 4 : data_o <= seq[31:24];
+ 5 : data_o <= seq[23:16];
+ 6 : data_o <= seq[15:8];
+ 7 : data_o <= seq[7:0];
+ 8 : data_o <= header[7:0];
+ 9 : data_o <= header[15:8];
+ 10 : data_o <= header[23:16];
+ 11 : data_o <= header[31:24];
+ 12 : data_o <= header[39:32];
+ 13 : data_o <= header[47:40];
+ 14 : data_o <= header[55:48];
+ 15 : data_o <= header[63:56];
+ 16 : data_o <= header[71:64];
+ 17 : data_o <= header[79:72];
+ 18 : data_o <= header[87:80];
+ 19 : data_o <= header[95:88];
+ 20 : data_o <= header[103:96];
+ 21 : data_o <= header[111:104];
+ 22 : data_o <= header[119:112];
+ 23 : data_o <= header[127:120];
+
+ 32'hFFFF_FFFC : data_o <= crc_out[31:24];
+ 32'hFFFF_FFFD : data_o <= crc_out[23:16];
+ 32'hFFFF_FFFE : data_o <= crc_out[15:8];
+ 32'hFFFF_FFFF : data_o <= crc_out[7:0];
+ default : data_o <= state[7:0];
+ endcase // case (state)
+
+ assign src_rdy_o = 1;
+ assign sof_o = (state == 0);
+ assign eof_o = (state == 32'hFFFF_FFFF);
+
+ wire clear_crc = eof_o & src_rdy_o & dst_rdy_i;
+
+// crc crc(.clk(clk), .reset(reset), .clear(clear_crc), .data(data_o),
+// .calc(calc_crc), .crc_out(crc_out), .match());
+ always @(posedge clk)
+ if(reset | clear | clear_crc)
+ crc_out <= 0;
+ else
+ if(calc_crc)
+ crc_out <= crc_out + data_o;
+
+endmodule // packet_generator
diff --git a/fpga/usrp2/fifo/packet_generator32.v b/fpga/usrp2/fifo/packet_generator32.v
new file mode 100644
index 000000000..7b4e3bd57
--- /dev/null
+++ b/fpga/usrp2/fifo/packet_generator32.v
@@ -0,0 +1,40 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module packet_generator32
+ (input clk, input reset, input clear,
+ input [127:0] header,
+ output [35:0] data_o, output src_rdy_o, input dst_rdy_i);
+
+ wire [7:0] ll_data;
+ wire ll_sof, ll_eof, ll_src_rdy, ll_dst_rdy_n;
+
+ packet_generator pkt_gen
+ (.clk(clk), .reset(reset), .clear(clear),
+ .data_o(ll_data), .sof_o(ll_sof), .eof_o(ll_eof),
+ .header(header),
+ .src_rdy_o(ll_src_rdy), .dst_rdy_i(~ll_dst_rdy_n));
+
+ ll8_to_fifo36 ll8_to_f36
+ (.clk(clk), .reset(reset), .clear(clear),
+ .ll_data(ll_data), .ll_sof_n(~ll_sof), .ll_eof_n(~ll_eof),
+ .ll_src_rdy_n(~ll_src_rdy), .ll_dst_rdy_n(ll_dst_rdy_n),
+ .f36_data(data_o), .f36_src_rdy_o(src_rdy_o), .f36_dst_rdy_i(dst_rdy_i));
+
+endmodule // packet_generator32
diff --git a/fpga/usrp2/fifo/packet_router.v b/fpga/usrp2/fifo/packet_router.v
new file mode 100644
index 000000000..7bfa6893d
--- /dev/null
+++ b/fpga/usrp2/fifo/packet_router.v
@@ -0,0 +1,315 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+module packet_router
+ #(
+ parameter BUF_SIZE = 9,
+ parameter UDP_BASE = 0,
+ parameter CTRL_BASE = 0
+ )
+ (
+ //wishbone interface for memory mapped CPU frames
+ input wb_clk_i,
+ input wb_rst_i,
+ input wb_we_i,
+ input wb_stb_i,
+ input [15:0] wb_adr_i,
+ input [31:0] wb_dat_i,
+ output [31:0] wb_dat_o,
+ output wb_ack_o,
+ output wb_err_o,
+ output wb_rty_o,
+
+ //setting register interface
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ input stream_clk,
+ input stream_rst,
+ input stream_clr,
+
+ //output status register
+ output [31:0] status,
+
+ output sys_int_o, //want an interrupt?
+
+ output [31:0] debug,
+
+ // Input Interfaces (in to router)
+ input [35:0] ser_inp_data, input ser_inp_valid, output ser_inp_ready,
+ input [35:0] dsp0_inp_data, input dsp0_inp_valid, output dsp0_inp_ready,
+ input [35:0] dsp1_inp_data, input dsp1_inp_valid, output dsp1_inp_ready,
+ input [35:0] eth_inp_data, input eth_inp_valid, output eth_inp_ready,
+ input [35:0] err_inp_data, input err_inp_valid, output err_inp_ready,
+
+ // Output Interfaces (out of router)
+ output [35:0] ser_out_data, output ser_out_valid, input ser_out_ready,
+ output [35:0] dsp_out_data, output dsp_out_valid, input dsp_out_ready,
+ output [35:0] eth_out_data, output eth_out_valid, input eth_out_ready
+ );
+
+ assign wb_err_o = 1'b0; // Unused for now
+ assign wb_rty_o = 1'b0; // Unused for now
+
+ ////////////////////////////////////////////////////////////////////
+ // CPU interface to this packet router
+ ////////////////////////////////////////////////////////////////////
+ wire [35:0] cpu_inp_data, cpu_out_data;
+ wire cpu_inp_valid, cpu_out_valid;
+ wire cpu_inp_ready, cpu_out_ready;
+
+ ////////////////////////////////////////////////////////////////////
+ // Communication interfaces
+ ////////////////////////////////////////////////////////////////////
+ wire [35:0] com_inp_data, com_out_data, udp_out_data;
+ wire com_inp_valid, com_out_valid, udp_out_valid;
+ wire com_inp_ready, com_out_ready, udp_out_ready;
+
+ ////////////////////////////////////////////////////////////////////
+ // Control signals (setting registers and status signals)
+ // - handshake lines for the CPU communication
+ // - setting registers to program the inspector
+ ////////////////////////////////////////////////////////////////////
+
+ //setting register for mode control
+ wire [31:0] _sreg_mode_ctrl;
+ wire master_mode_flag;
+
+ setting_reg #(.my_addr(CTRL_BASE+0), .width(1)) sreg_mode_ctrl(
+ .clk(stream_clk),.rst(stream_rst),
+ .strobe(set_stb),.addr(set_addr),.in(set_data),
+ .out(master_mode_flag),.changed()
+ );
+
+ //assign status output signals
+ wire [31:0] cpu_iface_status;
+ assign status = {
+ cpu_iface_status[31:9], master_mode_flag, cpu_iface_status[7:0]
+ };
+
+ ////////////////////////////////////////////////////////////////////
+ // Communication input source crossbar
+ // When in master mode:
+ // - serdes input -> comm output combiner
+ // - ethernet input -> comm input inspector
+ // When in slave mode:
+ // - serdes input -> comm input inspector
+ // - ethernet input -> null sink
+ ////////////////////////////////////////////////////////////////////
+
+ //streaming signals from the crossbar to the combiner
+ wire [35:0] ext_inp_data;
+ wire ext_inp_valid;
+ wire ext_inp_ready;
+
+ //dummy signals for valve/xbar below
+ wire [35:0] _eth_inp_data;
+ wire _eth_inp_valid;
+ wire _eth_inp_ready;
+
+ // dummy signals to connect fifo_short
+ wire [35:0] _com_inp_data;
+ wire _com_inp_valid;
+ wire _com_inp_ready;
+
+ valve36 eth_inp_valve (
+ .clk(stream_clk), .reset(stream_rst), .clear(stream_clr), .shutoff(~master_mode_flag),
+ .data_i(eth_inp_data), .src_rdy_i(eth_inp_valid), .dst_rdy_o(eth_inp_ready),
+ .data_o(_eth_inp_data), .src_rdy_o(_eth_inp_valid), .dst_rdy_i(_eth_inp_ready)
+ );
+
+ crossbar36 com_inp_xbar (
+ .clk(stream_clk), .reset(stream_rst), .clear(stream_clr), .cross(~master_mode_flag),
+ .data0_i(_eth_inp_data), .src0_rdy_i(_eth_inp_valid), .dst0_rdy_o(_eth_inp_ready),
+ .data1_i(ser_inp_data), .src1_rdy_i(ser_inp_valid), .dst1_rdy_o(ser_inp_ready),
+ .data0_o(_com_inp_data), .src0_rdy_o(_com_inp_valid), .dst0_rdy_i(_com_inp_ready),
+ .data1_o(ext_inp_data), .src1_rdy_o(ext_inp_valid), .dst1_rdy_i(ext_inp_ready)
+ );
+
+ // short fifo in the packet inspection path to help timing
+ fifo_short #(.WIDTH(36)) com_inp_fifo
+ (.clk(stream_clk), .reset(stream_rst), .clear(stream_clr),
+ .datain(_com_inp_data), .src_rdy_i(_com_inp_valid), .dst_rdy_o(_com_inp_ready),
+ .dataout(com_inp_data), .src_rdy_o(com_inp_valid), .dst_rdy_i(com_inp_ready),
+ .space(), .occupied() );
+
+ ////////////////////////////////////////////////////////////////////
+ // Communication output sink crossbar
+ // When in master mode:
+ // - comm output -> ethernet output
+ // - insp output -> serdes output
+ // When in slave mode:
+ // - com output -> serdes output
+ // - insp output -> null sink
+ ////////////////////////////////////////////////////////////////////
+
+ //streaming signals from the inspector to the crossbar
+ wire [35:0] ext_out_data;
+ wire ext_out_valid;
+ wire ext_out_ready;
+
+ //dummy signals for valve/xbar below
+ wire [35:0] _eth_out_data;
+ wire _eth_out_valid;
+ wire _eth_out_ready;
+
+ crossbar36 com_out_xbar (
+ .clk(stream_clk), .reset(stream_rst), .clear(stream_clr), .cross(~master_mode_flag),
+ .data0_i(com_out_data), .src0_rdy_i(com_out_valid), .dst0_rdy_o(com_out_ready),
+ .data1_i(ext_out_data), .src1_rdy_i(ext_out_valid), .dst1_rdy_o(ext_out_ready),
+ .data0_o(_eth_out_data), .src0_rdy_o(_eth_out_valid), .dst0_rdy_i(_eth_out_ready),
+ .data1_o(ser_out_data), .src1_rdy_o(ser_out_valid), .dst1_rdy_i(ser_out_ready)
+ );
+
+ valve36 eth_out_valve (
+ .clk(stream_clk), .reset(stream_rst), .clear(stream_clr), .shutoff(~master_mode_flag),
+ .data_i(_eth_out_data), .src_rdy_i(_eth_out_valid), .dst_rdy_o(_eth_out_ready),
+ .data_o(eth_out_data), .src_rdy_o(eth_out_valid), .dst_rdy_i(eth_out_ready)
+ );
+
+ ////////////////////////////////////////////////////////////////////
+ // Communication output source combiner (feeds UDP proto machine)
+ // - DSP input
+ // - CPU input
+ // - ERR input
+ ////////////////////////////////////////////////////////////////////
+
+ //dummy signals to join the the muxes below
+ wire [35:0] _combiner0_data, _combiner1_data;
+ wire _combiner0_valid, _combiner1_valid;
+ wire _combiner0_ready, _combiner1_ready;
+
+ fifo36_mux #(.prio(0)) // No priority, fair sharing
+ _com_output_combiner0(
+ .clk(stream_clk), .reset(stream_rst), .clear(stream_clr),
+ .data0_i(err_inp_data), .src0_rdy_i(err_inp_valid), .dst0_rdy_o(err_inp_ready),
+ .data1_i(cpu_inp_data), .src1_rdy_i(cpu_inp_valid), .dst1_rdy_o(cpu_inp_ready),
+ .data_o(_combiner0_data), .src_rdy_o(_combiner0_valid), .dst_rdy_i(_combiner0_ready)
+ );
+
+ fifo36_mux #(.prio(0)) // No priority, fair sharing
+ _com_output_combiner1(
+ .clk(stream_clk), .reset(stream_rst), .clear(stream_clr),
+ .data0_i(dsp0_inp_data), .src0_rdy_i(dsp0_inp_valid), .dst0_rdy_o(dsp0_inp_ready),
+ .data1_i(dsp1_inp_data), .src1_rdy_i(dsp1_inp_valid), .dst1_rdy_o(dsp1_inp_ready),
+ .data_o(_combiner1_data), .src_rdy_o(_combiner1_valid), .dst_rdy_i(_combiner1_ready)
+ );
+
+ fifo36_mux #(.prio(1)) // Give priority to err/cpu over dsp
+ com_output_source(
+ .clk(stream_clk), .reset(stream_rst), .clear(stream_clr),
+ .data0_i(_combiner0_data), .src0_rdy_i(_combiner0_valid), .dst0_rdy_o(_combiner0_ready),
+ .data1_i(_combiner1_data), .src1_rdy_i(_combiner1_valid), .dst1_rdy_o(_combiner1_ready),
+ .data_o(udp_out_data), .src_rdy_o(udp_out_valid), .dst_rdy_i(udp_out_ready)
+ );
+
+ ////////////////////////////////////////////////////////////////////
+ // Interface CPU to memory mapped wishbone
+ // - Uses 1 setting register
+ ////////////////////////////////////////////////////////////////////
+ buffer_int2 #(.BASE(CTRL_BASE+3), .BUF_SIZE(BUF_SIZE)) cpu_to_wb(
+ .clk(stream_clk), .rst(stream_rst | stream_clr),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .status(cpu_iface_status),
+ // Wishbone interface to RAM
+ .wb_clk_i(wb_clk_i), .wb_rst_i(wb_rst_i),
+ .wb_we_i(wb_we_i), .wb_stb_i(wb_stb_i),
+ .wb_adr_i(wb_adr_i), .wb_dat_i(wb_dat_i),
+ .wb_dat_o(wb_dat_o), .wb_ack_o(wb_ack_o),
+ // Write FIFO Interface (from PR and into WB)
+ .wr_data_i(cpu_out_data),
+ .wr_ready_i(cpu_out_valid),
+ .wr_ready_o(cpu_out_ready),
+ // Read FIFO Interface (from WB and into PR)
+ .rd_data_o(cpu_inp_data),
+ .rd_ready_o(cpu_inp_valid),
+ .rd_ready_i(cpu_inp_ready)
+ );
+
+ ////////////////////////////////////////////////////////////////////
+ // Packet Dispatcher
+ // - Uses 2 setting registers
+ // - provide buffering before cpu for random + small packet bursts
+ ////////////////////////////////////////////////////////////////////
+ wire [35:0] _cpu_out_data;
+ wire _cpu_out_valid;
+ wire _cpu_out_ready;
+
+ packet_dispatcher36_x3 #(.BASE(CTRL_BASE+1)) packet_dispatcher(
+ .clk(stream_clk), .rst(stream_rst), .clr(stream_clr),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .com_inp_data(com_inp_data), .com_inp_valid(com_inp_valid), .com_inp_ready(com_inp_ready),
+ .ext_out_data(ext_out_data), .ext_out_valid(ext_out_valid), .ext_out_ready(ext_out_ready),
+ .dsp_out_data(dsp_out_data), .dsp_out_valid(dsp_out_valid), .dsp_out_ready(dsp_out_ready),
+ .cpu_out_data(_cpu_out_data), .cpu_out_valid(_cpu_out_valid), .cpu_out_ready(_cpu_out_ready)
+ );
+
+ fifo_cascade #(.WIDTH(36), .SIZE(9/*512 lines plenty for short pkts*/)) cpu_out_fifo (
+ .clk(stream_clk), .reset(stream_rst), .clear(stream_clr),
+ .datain(_cpu_out_data), .src_rdy_i(_cpu_out_valid), .dst_rdy_o(_cpu_out_ready),
+ .dataout(cpu_out_data), .src_rdy_o(cpu_out_valid), .dst_rdy_i(cpu_out_ready)
+ );
+
+ ////////////////////////////////////////////////////////////////////
+ // UDP TX Protocol machine
+ ////////////////////////////////////////////////////////////////////
+
+ //dummy signals to connect the components below
+ wire [35:0] _com_out_data;
+ wire _com_out_valid, _com_out_ready;
+
+ prot_eng_tx #(.BASE(UDP_BASE)) udp_prot_eng_tx
+ (.clk(stream_clk), .reset(stream_rst), .clear(stream_clr),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .datain(udp_out_data), .src_rdy_i(udp_out_valid), .dst_rdy_o(udp_out_ready),
+ .dataout(_com_out_data), .src_rdy_o(_com_out_valid), .dst_rdy_i(_com_out_ready) );
+
+ fifo36_mux com_out_mux(
+ .clk(stream_clk), .reset(stream_rst), .clear(stream_clr),
+ .data0_i(ext_inp_data), .src0_rdy_i(ext_inp_valid), .dst0_rdy_o(ext_inp_ready),
+ .data1_i(_com_out_data), .src1_rdy_i(_com_out_valid), .dst1_rdy_o(_com_out_ready),
+ .data_o(com_out_data), .src_rdy_o(com_out_valid), .dst_rdy_i(com_out_ready)
+ );
+
+ ////////////////////////////////////////////////////////////////////
+ // Assign debugs
+ ////////////////////////////////////////////////////////////////////
+
+ assign debug = {
+ //inputs to the router (12)
+ dsp0_inp_ready, dsp0_inp_valid,
+ dsp1_inp_ready, dsp1_inp_valid,
+ err_inp_ready, err_inp_valid,
+ ser_inp_ready, ser_inp_valid,
+ eth_inp_ready, eth_inp_valid,
+ cpu_inp_ready, cpu_inp_valid,
+
+ //outputs from the router (8)
+ dsp_out_ready, dsp_out_valid,
+ ser_out_ready, ser_out_valid,
+ eth_out_ready, eth_out_valid,
+ cpu_out_ready, cpu_out_valid,
+
+ //other interfaces (8)
+ ext_inp_ready, ext_inp_valid,
+ com_out_ready, com_out_valid,
+ ext_out_ready, ext_out_valid,
+ com_inp_ready, com_inp_valid,
+
+ 4'b0
+ };
+
+endmodule // packet_router
diff --git a/fpga/usrp2/fifo/packet_tb.v b/fpga/usrp2/fifo/packet_tb.v
new file mode 100644
index 000000000..ec0665e0a
--- /dev/null
+++ b/fpga/usrp2/fifo/packet_tb.v
@@ -0,0 +1,46 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module packet_tb();
+
+ wire [7:0] data;
+ wire sof, eof, src_rdy, dst_rdy;
+
+ wire clear = 0;
+ reg clk = 0;
+ reg reset = 1;
+
+ always #10 clk <= ~clk;
+ initial #1000 reset <= 0;
+
+ initial $dumpfile("packet_tb.vcd");
+ initial $dumpvars(0,packet_tb);
+
+ wire [31:0] total, crc_err, seq_err, len_err;
+
+ packet_generator pkt_gen (.clk(clk), .reset(reset), .clear(clear),
+ .data_o(data), .sof_o(sof), .eof_o(eof),
+ .src_rdy_o(src_rdy), .dst_rdy_i(dst_rdy));
+
+ packet_verifier pkt_ver (.clk(clk), .reset(reset), .clear(clear),
+ .data_i(data), .sof_i(sof), .eof_i(eof),
+ .src_rdy_i(src_rdy), .dst_rdy_o(dst_rdy),
+ .total(total), .crc_err(crc_err), .seq_err(seq_err), .len_err(len_err));
+
+endmodule // packet_tb
diff --git a/fpga/usrp2/fifo/packet_verifier.v b/fpga/usrp2/fifo/packet_verifier.v
new file mode 100644
index 000000000..3cc7b0a04
--- /dev/null
+++ b/fpga/usrp2/fifo/packet_verifier.v
@@ -0,0 +1,78 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// Packet format --
+// Line 1 -- Length, 32 bits
+// Line 2 -- Sequence number, 32 bits
+// Last line -- CRC, 32 bits
+
+module packet_verifier
+ (input clk, input reset, input clear,
+ input [7:0] data_i, input sof_i, input eof_i, input src_rdy_i, output dst_rdy_o,
+
+ output reg [31:0] total,
+ output reg [31:0] crc_err,
+ output reg [31:0] seq_err,
+ output reg [31:0] len_err);
+
+ reg [31:0] seq_num;
+ reg [31:0] length;
+ wire first_byte, last_byte;
+ reg second_byte, last_byte_d1;
+ wire match_crc;
+ wire calc_crc = src_rdy_i & dst_rdy_o;
+
+ crc crc(.clk(clk), .reset(reset), .clear(last_byte_d1), .data(data_i),
+ .calc(calc_crc), .crc_out(), .match(match_crc));
+
+ assign first_byte = src_rdy_i & dst_rdy_o & sof_i;
+ assign last_byte = src_rdy_i & dst_rdy_o & eof_i;
+ assign dst_rdy_o = ~last_byte_d1;
+
+ // stubs for now
+ wire match_seq = 1;
+ wire match_len = 1;
+
+ always @(posedge clk)
+ if(reset | clear)
+ last_byte_d1 <= 0;
+ else
+ last_byte_d1 <= last_byte;
+
+ always @(posedge clk)
+ if(reset | clear)
+ begin
+ total <= 0;
+ crc_err <= 0;
+ seq_err <= 0;
+ len_err <= 0;
+ end
+ else
+ if(last_byte_d1)
+ begin
+ total <= total + 1;
+ if(~match_crc)
+ crc_err <= crc_err + 1;
+ else if(~match_seq)
+ seq_err <= seq_err + 1;
+ else if(~match_len)
+ seq_err <= len_err + 1;
+ end
+
+endmodule // packet_verifier
diff --git a/fpga/usrp2/fifo/packet_verifier32.v b/fpga/usrp2/fifo/packet_verifier32.v
new file mode 100644
index 000000000..3579a9bcf
--- /dev/null
+++ b/fpga/usrp2/fifo/packet_verifier32.v
@@ -0,0 +1,40 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module packet_verifier32
+ (input clk, input reset, input clear,
+ input [35:0] data_i, input src_rdy_i, output dst_rdy_o,
+ output [31:0] total, output [31:0] crc_err, output [31:0] seq_err, output [31:0] len_err);
+
+ wire [7:0] ll_data;
+ wire ll_sof, ll_eof, ll_src_rdy, ll_dst_rdy;
+
+ fifo36_to_ll8 f36_to_ll8
+ (.clk(clk), .reset(reset), .clear(clear),
+ .f36_data(data_i), .f36_src_rdy_i(src_rdy_i), .f36_dst_rdy_o(dst_rdy_o),
+ .ll_data(ll_data), .ll_sof(ll_sof), .ll_eof(ll_eof),
+ .ll_src_rdy(ll_src_rdy), .ll_dst_rdy(ll_dst_rdy));
+
+ packet_verifier pkt_ver
+ (.clk(clk), .reset(reset), .clear(clear),
+ .data_i(ll_data), .sof_i(ll_sof), .eof_i(ll_eof),
+ .src_rdy_i(ll_src_rdy), .dst_rdy_o(ll_dst_rdy),
+ .total(total), .crc_err(crc_err), .seq_err(seq_err), .len_err(len_err));
+
+endmodule // packet_verifier32
diff --git a/fpga/usrp2/fifo/splitter36.v b/fpga/usrp2/fifo/splitter36.v
new file mode 100644
index 000000000..d002d7afd
--- /dev/null
+++ b/fpga/usrp2/fifo/splitter36.v
@@ -0,0 +1,85 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Split packets from a fifo based interface so it goes out identically on two interfaces
+
+module splitter36
+ (
+ input clk, input rst, input clr,
+ input [35:0] inp_data, input inp_valid, output inp_ready,
+ output [35:0] out0_data, output out0_valid, input out0_ready,
+ output [35:0] out1_data, output out1_valid, input out1_ready
+ );
+
+ localparam STATE_COPY_BOTH = 0;
+ localparam STATE_COPY_ZERO = 1;
+ localparam STATE_COPY_ONE = 2;
+
+ reg [1:0] state;
+ reg [35:0] data_reg;
+
+ assign out0_data = (state == STATE_COPY_BOTH)? inp_data : data_reg;
+ assign out1_data = (state == STATE_COPY_BOTH)? inp_data : data_reg;
+
+ assign out0_valid =
+ (state == STATE_COPY_BOTH)? inp_valid : (
+ (state == STATE_COPY_ZERO)? 1'b1 : (
+ 1'b0));
+
+ assign out1_valid =
+ (state == STATE_COPY_BOTH)? inp_valid : (
+ (state == STATE_COPY_ONE)? 1'b1 : (
+ 1'b0));
+
+ assign inp_ready = (state == STATE_COPY_BOTH)? (out0_ready | out1_ready) : 1'b0;
+
+ always @(posedge clk)
+ if (rst | clr) begin
+ state <= STATE_COPY_BOTH;
+ end
+ else begin
+ case (state)
+
+ STATE_COPY_BOTH: begin
+ if ((out0_valid & out0_ready) & ~(out1_valid & out1_ready)) begin
+ state <= STATE_COPY_ONE;
+ end
+ else if (~(out0_valid & out0_ready) & (out1_valid & out1_ready)) begin
+ state <= STATE_COPY_ZERO;
+ end
+ data_reg <= inp_data;
+ end
+
+ STATE_COPY_ZERO: begin
+ if (out0_valid & out0_ready) begin
+ state <= STATE_COPY_BOTH;
+ end
+ end
+
+ STATE_COPY_ONE: begin
+ if (out1_valid & out1_ready) begin
+ state <= STATE_COPY_BOTH;
+ end
+ end
+
+ endcase //state
+ end
+
+
+
+endmodule //splitter36
diff --git a/fpga/usrp2/fifo/valve36.v b/fpga/usrp2/fifo/valve36.v
new file mode 100644
index 000000000..795fe511e
--- /dev/null
+++ b/fpga/usrp2/fifo/valve36.v
@@ -0,0 +1,46 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module valve36
+ (input clk, input reset, input clear,
+ input shutoff,
+ input [35:0] data_i, input src_rdy_i, output dst_rdy_o,
+ output [35:0] data_o, output src_rdy_o, input dst_rdy_i);
+
+ reg shutoff_int, active;
+ wire active_next = (src_rdy_i & dst_rdy_o)? ~data_i[33] : active;
+
+ assign data_o = data_i;
+
+ assign dst_rdy_o = shutoff_int ? 1'b1 : dst_rdy_i;
+ assign src_rdy_o = shutoff_int ? 1'b0 : src_rdy_i;
+
+ always @(posedge clk)
+ if(reset | clear)
+ active <= 0;
+ else
+ active <= active_next;
+
+ always @(posedge clk)
+ if(reset | clear)
+ shutoff_int <= 0;
+ else if(~active_next)
+ shutoff_int <= shutoff;
+
+endmodule // valve36