diff options
Diffstat (limited to 'fpga/usrp2/fifo')
41 files changed, 4434 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..02c567049 --- /dev/null +++ b/fpga/usrp2/fifo/Makefile.srcs @@ -0,0 +1,39 @@ +# +# Copyright 2010 Ettus Research LLC +# + +################################################## +# FIFO Sources +################################################## +FIFO_SRCS = $(abspath $(addprefix $(BASE_DIR)/../fifo/, \ +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/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 | 
