diff options
Diffstat (limited to 'fpga/usrp2/fifo')
30 files changed, 3217 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..f0b5b7bae --- /dev/null +++ b/fpga/usrp2/fifo/Makefile.srcs @@ -0,0 +1,31 @@ +# +# 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 \ +fifo36_mux.v \ +fifo36_demux.v \ +packet_router.v \ +splitter36.v \ +valve36.v \ +)) diff --git a/fpga/usrp2/fifo/buffer_int.v b/fpga/usrp2/fifo/buffer_int.v new file mode 100644 index 000000000..49ded8c8d --- /dev/null +++ b/fpga/usrp2/fifo/buffer_int.v @@ -0,0 +1,167 @@ + +// 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..765b125fb --- /dev/null +++ b/fpga/usrp2/fifo/buffer_int2.v @@ -0,0 +1,173 @@ + +// 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 [BUF_SIZE-1:0] rd_addr, wr_addr; +   wire [31:0] 	      ctrl; +   wire 	      wr_done, wr_error, wr_idle; +   wire 	      rd_done, rd_error, rd_idle; +   wire 	      we, en, go; + +   reg [BUF_SIZE-1:0] lastline; +   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; +		lastline <= ctrl[15+BUF_SIZE:16]; +	     end +	  +	 PRE_READ : +	   begin +	      rd_state <= READING; +	      rd_addr <= rd_addr + 1; +	      rd_occ <= 2'b00; +	      rd_sop <= 1; +	      rd_eop <= 0; +	   end +	  +	 READING : +	   if(rd_ready_i) +	     begin +		rd_sop <= 0; +		rd_addr <= rd_addr + 1; +		if(rd_addr == lastline) +		  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); + +   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),.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),.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 = { {(16-BUF_SIZE){1'b0}},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..df54dcc0b --- /dev/null +++ b/fpga/usrp2/fifo/buffer_int_tb.v @@ -0,0 +1,418 @@ + +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..41ac1deb3 --- /dev/null +++ b/fpga/usrp2/fifo/buffer_pool.v @@ -0,0 +1,283 @@ + +// 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..91a01d268 --- /dev/null +++ b/fpga/usrp2/fifo/buffer_pool_tb.v @@ -0,0 +1,58 @@ + +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..2a046d8bf --- /dev/null +++ b/fpga/usrp2/fifo/crossbar36.v @@ -0,0 +1,42 @@ + + +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..34a05d91e --- /dev/null +++ b/fpga/usrp2/fifo/dsp_framer36.v @@ -0,0 +1,98 @@ + +// Frame DSP packets with a header line to be handled by the protocol machine + +module dsp_framer36 +    #(parameter BUF_SIZE = 9) +    ( +        input clk, input rst, input clr, +        input [35:0] inp_data, input inp_valid, output inp_ready, +        output [35:0] out_data, output out_valid, input out_ready +    ); + +    localparam DSP_FRM_STATE_WAIT_SOF = 0; +    localparam DSP_FRM_STATE_WAIT_EOF = 1; +    localparam DSP_FRM_STATE_WRITE_HDR = 2; +    localparam DSP_FRM_STATE_WRITE = 3; + +    reg [1:0] dsp_frm_state; +    reg [BUF_SIZE-1:0] dsp_frm_addr; +    reg [BUF_SIZE-1:0] dsp_frm_count; +    wire [BUF_SIZE-1:0] dsp_frm_addr_next = dsp_frm_addr + 1'b1; + +    //DSP input stream ready in the following states +    assign inp_ready = ( +        dsp_frm_state == DSP_FRM_STATE_WAIT_SOF || +        dsp_frm_state == DSP_FRM_STATE_WAIT_EOF +    )? 1'b1 : 1'b0; + +    //DSP framer output data mux (header or BRAM): +    //The header is generated here from the count. +    wire [31:0] dsp_frm_data_bram; +    wire [15:0] dsp_frm_bytes = {dsp_frm_count, 2'b00}; +    assign out_data = +        (dsp_frm_state == DSP_FRM_STATE_WRITE_HDR)? {4'b0001, 16'b1, dsp_frm_bytes} : ( +        (dsp_frm_addr == dsp_frm_count)           ? {4'b0010, dsp_frm_data_bram}    : ( +    {4'b0000, dsp_frm_data_bram})); +    assign out_valid = ( +        (dsp_frm_state == DSP_FRM_STATE_WRITE_HDR) || +        (dsp_frm_state == DSP_FRM_STATE_WRITE) +    )? 1'b1 : 1'b0; + +    RAMB16_S36_S36 dsp_frm_buff( +        //port A = DSP input interface (writes to BRAM) +        .DOA(),.ADDRA(dsp_frm_addr),.CLKA(clk),.DIA(inp_data[31:0]),.DIPA(4'h0), +        .ENA(inp_ready & inp_valid),.SSRA(0),.WEA(inp_ready & inp_valid), +        //port B = DSP framer interface (reads from BRAM) +        .DOB(dsp_frm_data_bram),.ADDRB(dsp_frm_addr),.CLKB(clk),.DIB(36'b0),.DIPB(4'h0), +        .ENB(out_ready & out_valid),.SSRB(0),.WEB(1'b0) +    ); + +    always @(posedge clk) +    if(rst | clr) begin +        dsp_frm_state <= DSP_FRM_STATE_WAIT_SOF; +        dsp_frm_addr <= 0; +    end +    else begin +        case(dsp_frm_state) +        DSP_FRM_STATE_WAIT_SOF: begin +            if (inp_ready & inp_valid & inp_data[32]) begin +                dsp_frm_addr <= dsp_frm_addr_next; +                dsp_frm_state <= DSP_FRM_STATE_WAIT_EOF; +            end +        end + +        DSP_FRM_STATE_WAIT_EOF: begin +            if (inp_ready & inp_valid) begin +                if (inp_data[33]) begin +                    dsp_frm_count <= dsp_frm_addr_next; +                    dsp_frm_addr <= 0; +                    dsp_frm_state <= DSP_FRM_STATE_WRITE_HDR; +                end +                else begin +                    dsp_frm_addr <= dsp_frm_addr_next; +                end +            end +        end + +        DSP_FRM_STATE_WRITE_HDR: begin +            if (out_ready & out_valid) begin +                dsp_frm_addr <= dsp_frm_addr_next; +                dsp_frm_state <= DSP_FRM_STATE_WRITE; +            end +        end + +        DSP_FRM_STATE_WRITE: begin +            if (out_ready & out_valid) begin +                if (out_data[33]) begin +                    dsp_frm_addr <= 0; +                    dsp_frm_state <= DSP_FRM_STATE_WAIT_SOF; +                end +                else begin +                    dsp_frm_addr <= dsp_frm_addr_next; +                end +            end +        end +        endcase //dsp_frm_state +    end + +endmodule //dsp_framer36 diff --git a/fpga/usrp2/fifo/fifo18_to_fifo36.v b/fpga/usrp2/fifo/fifo18_to_fifo36.v new file mode 100644 index 000000000..25bb215a1 --- /dev/null +++ b/fpga/usrp2/fifo/fifo18_to_fifo36.v @@ -0,0 +1,20 @@ + +// For now just assume FIFO18 is same as FIFO19 without occupancy bit + +module fifo18_to_fifo36 +  (input clk, input reset, input clear, +   input [17:0] f18_datain, +   input f18_src_rdy_i, +   output f18_dst_rdy_o, + +   output [35:0] f36_dataout, +   output f36_src_rdy_o, +   input f36_dst_rdy_i +   ); + +   fifo19_to_fifo36 fifo19_to_fifo36 +     (.clk(clk), .reset(reset), .clear(clear), +      .f19_datain({1'b0,f18_datain}), .f19_src_rdy_i(f18_src_rdy_i), .f19_dst_rdy_o(f18_dst_rdy_o), +      .f36_dataout(f36_dataout), .f36_src_rdy_o(f36_src_rdy_o), .f36_dst_rdy_i(f36_dst_rdy_i) ); + +endmodule // fifo18_to_fifo36 diff --git a/fpga/usrp2/fifo/fifo19_to_fifo36.v b/fpga/usrp2/fifo/fifo19_to_fifo36.v new file mode 100644 index 000000000..ae2edddc7 --- /dev/null +++ b/fpga/usrp2/fifo/fifo19_to_fifo36.v @@ -0,0 +1,90 @@ + +// 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 +    ); + +   reg 		  f36_sof, f36_eof; +   reg [1:0] 	  f36_occ; +    +   reg [1:0] 	  state; +   reg [15:0] 	  dat0, dat1; + +   wire 	  f19_sof  = f19_datain[16]; +   wire 	  f19_eof  = f19_datain[17]; +   wire 	  f19_occ  = f19_datain[18]; + +   wire 	  xfer_out = f36_src_rdy_o & f36_dst_rdy_i; + +   always @(posedge clk) +     if(f19_src_rdy_i & ((state==0)|xfer_out)) +       f36_sof 	<= f19_sof; + +   always @(posedge clk) +     if(f19_src_rdy_i & ((state != 2)|xfer_out)) +       f36_eof 	<= f19_eof; + +   always @(posedge clk) +     if(reset) +       begin +	  state 	<= 0; +	  f36_occ <= 0; +       end +     else +       if(f19_src_rdy_i) +	 case(state) +	   0 :  +	     begin +		dat0 <= f19_datain; +		if(f19_eof) +		  begin +		     state <= 2; +		     f36_occ <= f19_occ ? 2'b01 : 2'b10; +		  end +		else +		  state <= 1; +	     end +	   1 :  +	     begin +		dat1 <= f19_datain; +		state <= 2; +		if(f19_eof) +		  f36_occ <= f19_occ ? 2'b11 : 2'b00; +	     end +	   2 :  +	     if(xfer_out) +	       begin +		  dat0 <= f19_datain; +		  if(f19_eof) // remain in state 2 if we are at eof +		    f36_occ <= f19_occ ? 2'b01 : 2'b10; +		  else +		    state 	   <= 1; +	       end +	 endcase // case(state) +       else +	 if(xfer_out) +	   begin +	      state 	   <= 0; +	      f36_occ <= 0; +	   end +    +   assign    f19_dst_rdy_o  = xfer_out | (state != 2); +   assign    f36_dataout    = LE ? {f36_occ,f36_eof,f36_sof,dat1,dat0} : +			      {f36_occ,f36_eof,f36_sof,dat0,dat1}; +   assign    f36_src_rdy_o  = (state == 2); + +   assign    debug = state; +    +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..4707f7523 --- /dev/null +++ b/fpga/usrp2/fifo/fifo19_to_ll8.v @@ -0,0 +1,53 @@ + +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..a54759d4d --- /dev/null +++ b/fpga/usrp2/fifo/fifo36_demux.v @@ -0,0 +1,50 @@ + +// 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..c6fd40f27 --- /dev/null +++ b/fpga/usrp2/fifo/fifo36_mux.v @@ -0,0 +1,64 @@ + +// 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); + +   localparam MUX_IDLE0 = 0; +   localparam MUX_DATA0 = 1; +   localparam MUX_IDLE1 = 2; +   localparam MUX_DATA1 = 3; +    +   reg [1:0] 	  state; + +   wire 	  eof0 = data0_i[33]; +   wire 	  eof1 = data1_i[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_i) +	     state <= MUX_DATA0; +	   else if(src1_rdy_i) +	     state <= MUX_DATA1; + +	 MUX_DATA0 : +	   if(src0_rdy_i & dst_rdy_int & eof0) +	     state <= prio ? MUX_IDLE0 : MUX_IDLE1; + +	 MUX_IDLE1 : +	   if(src1_rdy_i) +	     state <= MUX_DATA1; +	   else if(src0_rdy_i) +	     state <= MUX_DATA0; +	    +	 MUX_DATA1 : +	   if(src1_rdy_i & dst_rdy_int & eof1) +	     state <= MUX_IDLE0; +	  +	 default : +	   state <= MUX_IDLE0; +       endcase // case (state) + +   assign dst0_rdy_o = (state==MUX_DATA0) ? dst_rdy_int : 0; +   assign dst1_rdy_o = (state==MUX_DATA1) ? dst_rdy_int : 0; +   assign src_rdy_int = (state==MUX_DATA0) ? src0_rdy_i : (state==MUX_DATA1) ? src1_rdy_i : 0; +   assign data_int = (state==MUX_DATA0) ? data0_i : data1_i; +    +   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..e016fe2c6 --- /dev/null +++ b/fpga/usrp2/fifo/fifo36_to_fifo19.v @@ -0,0 +1,45 @@ + +// 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   f36_sof  = f36_datain[32]; +   wire   f36_eof  = f36_datain[33]; +   wire [1:0] f36_occ  = f36_datain[35:34]; +    +   reg 	  phase; +    +   wire   half_line 	   = f36_eof & ((f36_occ==1)|(f36_occ==2)); +    +   assign f19_dataout[15:0] = (LE ^ phase) ? f36_datain[15:0] : f36_datain[31:16]; +   assign f19_dataout[16]  = phase ? 0 : f36_sof; +   assign f19_dataout[17]  = phase ? f36_eof : half_line; +   assign f19_dataout[18]  = f19_dataout[17] & ((f36_occ==1)|(f36_occ==3)); +    +   assign f19_src_rdy_o    = f36_src_rdy_i; +   assign f36_dst_rdy_o    = (phase | half_line) & f19_dst_rdy_i; +    +   wire   f19_xfer 	   = f19_src_rdy_o & f19_dst_rdy_i; +   wire   f36_xfer 	   = f36_src_rdy_i & f36_dst_rdy_o; +    +   always @(posedge clk) +     if(reset) +       phase 		  <= 0; +     else if(f36_xfer) +       phase 		  <= 0; +     else if(f19_xfer) +       phase 		  <= 1; +    +    +endmodule // fifo36_to_fifo19 diff --git a/fpga/usrp2/fifo/fifo36_to_ll8.v b/fpga/usrp2/fifo/fifo36_to_ll8.v new file mode 100644 index 000000000..9604d0e38 --- /dev/null +++ b/fpga/usrp2/fifo/fifo36_to_ll8.v @@ -0,0 +1,59 @@ + +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 reg [7:0] ll_data, +   output ll_sof_n, +   output ll_eof_n, +   output ll_src_rdy_n, +   input ll_dst_rdy_n, + +   output [31:0] debug); + +   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   f36_sof = f36_data[32]; +   wire   f36_eof = f36_data[33]; +   wire   f36_occ = f36_data[35:34]; +   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) +	   state  <= 0; +	 else +	   state  <= state + 1; + +   always @* +     case(state) +       0 : ll_data = f36_data[31:24]; +       1 : ll_data = f36_data[23:16]; +       2 : ll_data = f36_data[15:8]; +       3 : ll_data = f36_data[7:0]; +       default : ll_data = f36_data[31:24]; +       endcase // case (state) +    +   assign ll_sof 	 = (state==0) & f36_sof; +   assign ll_eof 	 = f36_eof & (((state==0)&(f36_occ==1)) | +			       ((state==1)&(f36_occ==2)) | +			       ((state==2)&(f36_occ==3)) | +			       (state==3)); +    +   assign ll_src_rdy 	 = f36_src_rdy_i; + +   assign advance 	 = ll_src_rdy & ll_dst_rdy; +   assign f36_dst_rdy_o  = advance & ((state==3)|ll_eof); +    +endmodule // ll8_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..c585392c3 --- /dev/null +++ b/fpga/usrp2/fifo/fifo_19to36_tb.v @@ -0,0 +1,82 @@ +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..34c85ccb4 --- /dev/null +++ b/fpga/usrp2/fifo/fifo_2clock.v @@ -0,0 +1,117 @@ + +// 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; + +   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)|(WIDTH==18)) +	if(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) ); +   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..4e8c244c2 --- /dev/null +++ b/fpga/usrp2/fifo/fifo_2clock_cascade.v @@ -0,0 +1,41 @@ + +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..fdd8449bc --- /dev/null +++ b/fpga/usrp2/fifo/fifo_cascade.v @@ -0,0 +1,52 @@ + + +// 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..0426779f6 --- /dev/null +++ b/fpga/usrp2/fifo/fifo_long.v @@ -0,0 +1,148 @@ + +// 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(0), +	  .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_short.v b/fpga/usrp2/fifo/fifo_short.v new file mode 100644 index 000000000..53a7603c7 --- /dev/null +++ b/fpga/usrp2/fifo/fifo_short.v @@ -0,0 +1,95 @@ + +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..327da4700 --- /dev/null +++ b/fpga/usrp2/fifo/fifo_tb.v @@ -0,0 +1,177 @@ +module fifo_new_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; +    +   wire [35:0] f36_in = {f36_occ,f36_eof,f36_sof,f36_data}; +   reg src_rdy_f36i  = 0; +   wire dst_rdy_f36i; + +   wire [35:0] f36_out, f36_out2; +   wire src_rdy_f36o; +   reg dst_rdy_f36o  = 0; +    +   //fifo_cascade #(.WIDTH(36), .SIZE(4)) fifo_cascade36 +   //fifo_long #(.WIDTH(36), .SIZE(4)) fifo_cascade36 + +   wire i1_sr, i1_dr; +   wire i2_sr, i2_dr; +   wire i3_sr, i3_dr; +   wire i7_sr, i7_dr; +    +   reg i4_dr = 0; +   wire i4_sr; +       +   wire [35:0] i1, i4, i7; +   wire [18:0] i2, i3; +    +   wire [7:0] ll_data; +   wire ll_src_rdy_n, ll_dst_rdy_n, ll_sof_n, ll_eof_n; +   wire [35:0] err_dat; +   wire        err_src_rdy, err_dst_rdy; + +   reg 	       trigger = 0; +   initial #10000 trigger = 1; +    +   fifo_short #(.WIDTH(36)) fifo_short1 +     (.clk(clk),.reset(rst),.clear(clear), +      .datain(f36_in),.src_rdy_i(src_rdy_f36i),.dst_rdy_o(dst_rdy_f36i), +      .dataout(i7),.src_rdy_o(i7_sr),.dst_rdy_i(i7_dr) ); + +   gen_context_pkt #(.PROT_ENG_FLAGS(1)) gcp +     (.clk(clk),.reset(rst),.clear(clear), +      .trigger(trigger), .sent(), +      .streamid(32'hDEAD_F00D), .vita_time(64'h01234567_89ABCDEF), .message(32'hBEEF_2940), +      .data_o(err_dat), .src_rdy_o(err_src_rdy), .dst_rdy_i(err_dst_rdy)); +    +   fifo36_mux #(.prio(0)) fifo36_mux +     (.clk(clk), .reset(rst), .clear(clear), +      .data0_i(i7), .src0_rdy_i(i7_sr), .dst0_rdy_o(i7_dr), +      .data1_i(err_dat), .src1_rdy_i(err_src_rdy), .dst1_rdy_o(err_dst_rdy), +      .data_o(i1), .src_rdy_o(i1_sr), .dst_rdy_i(i1_dr)); +    +   fifo36_to_fifo19 fifo36_to_fifo19 +     (.clk(clk),.reset(rst),.clear(clear), +      .f36_datain(i1),.f36_src_rdy_i(i1_sr),.f36_dst_rdy_o(i1_dr), +      .f19_dataout(i2),.f19_src_rdy_o(i2_sr),.f19_dst_rdy_i(i2_dr) ); + +   fifo19_to_ll8 fifo19_to_ll8 +     (.clk(clk),.reset(rst),.clear(clear), +      .f19_data(i2),.f19_src_rdy_i(i2_sr),.f19_dst_rdy_o(i2_dr), +      .ll_data(ll_data),.ll_sof_n(ll_sof_n),.ll_eof_n(ll_eof_n), +      .ll_src_rdy_n(ll_src_rdy_n),.ll_dst_rdy_n(ll_dst_rdy_n)); + +   ll8_to_fifo19 ll8_to_fifo19 +     (.clk(clk),.reset(rst),.clear(clear), +      .ll_data(ll_data),.ll_sof_n(ll_sof_n),.ll_eof_n(ll_eof_n), +      .ll_src_rdy_n(ll_src_rdy_n),.ll_dst_rdy_n(ll_dst_rdy_n), +      .f19_data(i3),.f19_src_rdy_o(i3_sr),.f19_dst_rdy_i(i3_dr) ); + +   fifo19_to_fifo36 fifo19_to_fifo36 +     (.clk(clk),.reset(rst),.clear(clear), +      .f19_datain(i3),.f19_src_rdy_i(i3_sr),.f19_dst_rdy_o(i3_dr), +      .f36_dataout(i4),.f36_src_rdy_o(i4_sr),.f36_dst_rdy_i(i4_dr) ); + +   task ReadFromFIFO36; +      begin +	 $display("Read from FIFO36"); +	 #1 i4_dr <= 1; +	 while(1) +	   begin +	      while(~i4_sr) +		@(posedge clk); +	      $display("Read: %h",i4); +	      @(posedge clk); +	   end +      end +   endtask // ReadFromFIFO36 + +   reg [15:0] count; +   task PutPacketInFIFO36; +      input [31:0] data_start; +      input [31:0] data_len; +      begin +	 count 	      <= 4; +	 src_rdy_f36i <= 1; +	 f36_data     <= data_start; +	 f36_sof      <= 1; +	 f36_eof      <= 0; +	 f36_occ      <= 0; +	 +	 $display("Put Packet in FIFO36"); +	 while(~dst_rdy_f36i) +	   @(posedge clk); +	 @(posedge clk); +	 $display("PPI_FIFO36: Entered First Line"); +	 f36_sof <= 0; +	 while(count+4 < data_len) +	   begin +	      f36_data <= f36_data + 32'h01010101; +	      count    <= count + 4; +	      while(~dst_rdy_f36i) +		@(posedge clk); +	      @(posedge clk); +	      $display("PPI_FIFO36: Entered New Line"); +	   end +	 f36_data  <= f36_data + 32'h01010101; +	 f36_eof   <= 1; +	 if(count + 4 == data_len) +	   f36_occ <= 0; +	 else if(count + 3 == data_len) +	   f36_occ <= 3; +	 else if(count + 2 == data_len) +	   f36_occ <= 2; +	 else +	   f36_occ <= 1; +	 while(~dst_rdy_f36i) +	   @(posedge clk); +	 @(posedge clk); +	 f36_occ      <= 0; +	 f36_eof      <= 0; +	 f36_data     <= 0; +	 src_rdy_f36i <= 0; +	 $display("PPI_FIFO36: Entered Last Line"); +      end +   endtask // PutPacketInFIFO36 +    +   initial $dumpfile("fifo_new_tb.vcd"); +   initial $dumpvars(0,fifo_new_tb); + +   initial +     begin +	@(negedge rst); +	//#10000; +	@(posedge clk); +	@(posedge clk); +	@(posedge clk); +	@(posedge clk); +	ReadFromFIFO36; +     end +    +   initial +     begin +	@(negedge rst); +	@(posedge clk); +	@(posedge clk); +	PutPacketInFIFO36(32'hA0B0C0D0,12); +	@(posedge clk); +	@(posedge clk); +	#10000; +	@(posedge clk); +	PutPacketInFIFO36(32'hE0F0A0B0,36); +	@(posedge clk); +	@(posedge clk); +	@(posedge clk); +	@(posedge clk); +	@(posedge clk); +     end + +   initial #20000 $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..39ada9a4f --- /dev/null +++ b/fpga/usrp2/fifo/ll8_shortfifo.v @@ -0,0 +1,13 @@ + + +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..af3b91afb --- /dev/null +++ b/fpga/usrp2/fifo/ll8_to_fifo19.v @@ -0,0 +1,73 @@ + +module ll8_to_fifo19 +  (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 [18:0] f19_data, +   output f19_src_rdy_o, +   input f19_dst_rdy_i ); +    +   localparam XFER_EMPTY       = 0; +   localparam XFER_HALF        = 1; +   localparam XFER_HALF_WRITE  = 3; +    +   // 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; +    +   wire  xfer_out 	   = f19_src_rdy_o & f19_dst_rdy_i; +   wire  xfer_in 	   = ll_src_rdy & ll_dst_rdy;  +    +   reg 	 hold_sof; +   wire  f19_sof, f19_eof, f19_occ; +    +   reg [1:0] state; +   reg [7:0] hold_reg; +    +   always @(posedge clk) +     if(ll_src_rdy & (state==XFER_EMPTY)) +       hold_reg 	      <= ll_data; +    +   always @(posedge clk) +     if(ll_sof & (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) +	     if(ll_eof) +	       state 	      <= XFER_HALF_WRITE; +	     else +	       state 	      <= XFER_HALF; +	 XFER_HALF : +	   if(ll_src_rdy & f19_dst_rdy_i) +	       state 	      <= XFER_EMPTY; +         XFER_HALF_WRITE : +	   if(f19_dst_rdy_i) +	     state 	<= XFER_EMPTY; +       endcase // case (state) +       +   assign ll_dst_rdy 	 = (state==XFER_EMPTY) | ((state==XFER_HALF)&f19_dst_rdy_i); +   assign f19_src_rdy_o  = (state==XFER_HALF_WRITE) | ((state==XFER_HALF)&ll_src_rdy); +    +   assign f19_sof 	 = hold_sof | (ll_sof & (state==XFER_HALF)); +   assign f19_eof 	 = (state == XFER_HALF_WRITE) | ll_eof; +   assign f19_occ 	 = (state == XFER_HALF_WRITE); +    +   assign f19_data 	 = {f19_occ,f19_eof,f19_sof,hold_reg,ll_data}; +       +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..108daa903 --- /dev/null +++ b/fpga/usrp2/fifo/ll8_to_fifo36.v @@ -0,0 +1,97 @@ + +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/packet_router.v b/fpga/usrp2/fifo/packet_router.v new file mode 100644 index 000000000..161b59016 --- /dev/null +++ b/fpga/usrp2/fifo/packet_router.v @@ -0,0 +1,535 @@ +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] dsp_inp_data, input dsp_inp_valid, output dsp_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; +    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() +    ); + +    //setting register to program the IP address +    wire [31:0] my_ip_addr; +    setting_reg #(.my_addr(CTRL_BASE+1)) sreg_ip_addr( +        .clk(stream_clk),.rst(stream_rst), +        .strobe(set_stb),.addr(set_addr),.in(set_data), +        .out(my_ip_addr),.changed() +    ); + +    //setting register to program the UDP data ports +    wire [15:0] dsp0_udp_port, dsp1_udp_port; +    setting_reg #(.my_addr(CTRL_BASE+2)) sreg_data_ports( +        .clk(stream_clk),.rst(stream_rst), +        .strobe(set_stb),.addr(set_addr),.in(set_data), +        .out({dsp1_udp_port, dsp0_udp_port}),.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; + +    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) +    ); + +    //////////////////////////////////////////////////////////////////// +    // 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 framer +    //   - CPU input +    //   - ERR input +    //////////////////////////////////////////////////////////////////// + +    //streaming signals from the dsp framer to the combiner +    wire [35:0] dsp_frm_data; +    wire        dsp_frm_valid; +    wire        dsp_frm_ready; + +    //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 _com_output_combiner0( +        .clk(stream_clk), .reset(stream_rst), .clear(stream_clr), +        .data0_i(dsp_frm_data), .src0_rdy_i(dsp_frm_valid), .dst0_rdy_o(dsp_frm_ready), +        .data1_i(err_inp_data), .src1_rdy_i(err_inp_valid), .dst1_rdy_o(err_inp_ready), +        .data_o(_combiner0_data), .src_rdy_o(_combiner0_valid), .dst_rdy_i(_combiner0_ready) +    ); + +    fifo36_mux _com_output_combiner1( +        .clk(stream_clk), .reset(stream_rst), .clear(stream_clr), +        .data0_i(32'b0), .src0_rdy_i(1'b0), .dst0_rdy_o(), //mux out from dsp1 can go here +        .data1_i(cpu_inp_data), .src1_rdy_i(cpu_inp_valid), .dst1_rdy_o(cpu_inp_ready), +        .data_o(_combiner1_data), .src_rdy_o(_combiner1_valid), .dst_rdy_i(_combiner1_ready) +    ); + +    fifo36_mux 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 +    //////////////////////////////////////////////////////////////////// +    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) +    ); + +    //////////////////////////////////////////////////////////////////// +    // Communication input inspector +    //   - inspect com input and send it to DSP, EXT, CPU, or BOTH +    //////////////////////////////////////////////////////////////////// +    localparam COM_INSP_STATE_READ_COM_PRE = 0; +    localparam COM_INSP_STATE_READ_COM = 1; +    localparam COM_INSP_STATE_WRITE_REGS = 2; +    localparam COM_INSP_STATE_WRITE_LIVE = 3; + +    localparam COM_INSP_DEST_DSP = 0; +    localparam COM_INSP_DEST_EXT = 1; +    localparam COM_INSP_DEST_CPU = 2; +    localparam COM_INSP_DEST_BOF = 3; + +    localparam COM_INSP_MAX_NUM_DREGS = 13; //padded_eth + ip + udp + seq + vrt_hdr +    localparam COM_INSP_DREGS_DSP_OFFSET = 11; //offset to start dsp at + +    //output inspector interfaces +    wire [35:0] com_insp_out_dsp_data; +    wire        com_insp_out_dsp_valid; +    wire        com_insp_out_dsp_ready; + +    wire [35:0] com_insp_out_ext_data; +    wire        com_insp_out_ext_valid; +    wire        com_insp_out_ext_ready; + +    wire [35:0] com_insp_out_cpu_data; +    wire        com_insp_out_cpu_valid; +    wire        com_insp_out_cpu_ready; + +    wire [35:0] com_insp_out_bof_data; +    wire        com_insp_out_bof_valid; +    wire        com_insp_out_bof_ready; + +    //connect this fast-path signals directly to the DSP out +    assign dsp_out_data = com_insp_out_dsp_data; +    assign dsp_out_valid = com_insp_out_dsp_valid; +    assign com_insp_out_dsp_ready = dsp_out_ready; + +    reg [1:0] com_insp_state; +    reg [1:0] com_insp_dest; +    reg [3:0] com_insp_dreg_count; //data registers to buffer headers +    wire [3:0] com_insp_dreg_count_next = com_insp_dreg_count + 1'b1; +    wire com_insp_dreg_counter_done = (com_insp_dreg_count_next == COM_INSP_MAX_NUM_DREGS)? 1'b1 : 1'b0; +    reg [35:0] com_insp_dregs [COM_INSP_MAX_NUM_DREGS-1:0]; + +    //extract various packet components: +    wire [47:0] com_insp_dregs_eth_dst_mac   = {com_insp_dregs[0][15:0], com_insp_dregs[1][31:0]}; +    wire [15:0] com_insp_dregs_eth_type      = com_insp_dregs[3][15:0]; +    wire [7:0]  com_insp_dregs_ipv4_proto    = com_insp_dregs[6][23:16]; +    wire [31:0] com_insp_dregs_ipv4_dst_addr = com_insp_dregs[8][31:0]; +    wire [15:0] com_insp_dregs_udp_dst_port  = com_insp_dregs[9][15:0]; +    wire [15:0] com_insp_dregs_vrt_size      = com_inp_data[15:0]; + +    //Inspector output flags special case: +    //Inject SOF into flags at first DSP line. +    wire [3:0] com_insp_out_flags = ( +        (com_insp_dreg_count == COM_INSP_DREGS_DSP_OFFSET) && +        (com_insp_dest == COM_INSP_DEST_DSP) +    )? 4'b0001 : com_insp_dregs[com_insp_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] com_insp_out_data = (com_insp_state == COM_INSP_STATE_WRITE_REGS)? +        {com_insp_out_flags, com_insp_dregs[com_insp_dreg_count][31:0]} : com_inp_data +    ; +    wire com_insp_out_valid = +        (com_insp_state == COM_INSP_STATE_WRITE_REGS)? 1'b1          : ( +        (com_insp_state == COM_INSP_STATE_WRITE_LIVE)? com_inp_valid : ( +    1'b0)); + +    //The communication inspector ouput ready signal: +    //Mux between the various destination ready signals. +    wire com_insp_out_ready = +        (com_insp_dest == COM_INSP_DEST_DSP)? com_insp_out_dsp_ready : ( +        (com_insp_dest == COM_INSP_DEST_EXT)? com_insp_out_ext_ready : ( +        (com_insp_dest == COM_INSP_DEST_CPU)? com_insp_out_cpu_ready : ( +        (com_insp_dest == COM_INSP_DEST_BOF)? com_insp_out_bof_ready : ( +    1'b0)))); + +    //Always connected output data lines. +    assign com_insp_out_dsp_data = com_insp_out_data; +    assign com_insp_out_ext_data = com_insp_out_data; +    assign com_insp_out_cpu_data = com_insp_out_data; +    assign com_insp_out_bof_data = com_insp_out_data; + +    //Destination output valid signals: +    //Comes from inspector valid when destination is selected, and otherwise low. +    assign com_insp_out_dsp_valid = (com_insp_dest == COM_INSP_DEST_DSP)? com_insp_out_valid : 1'b0; +    assign com_insp_out_ext_valid = (com_insp_dest == COM_INSP_DEST_EXT)? com_insp_out_valid : 1'b0; +    assign com_insp_out_cpu_valid = (com_insp_dest == COM_INSP_DEST_CPU)? com_insp_out_valid : 1'b0; +    assign com_insp_out_bof_valid = (com_insp_dest == COM_INSP_DEST_BOF)? com_insp_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 = +        (com_insp_state == COM_INSP_STATE_READ_COM_PRE)  ? 1'b1               : ( +        (com_insp_state == COM_INSP_STATE_READ_COM)      ? 1'b1               : ( +        (com_insp_state == COM_INSP_STATE_WRITE_LIVE)    ? com_insp_out_ready : ( +    1'b0))); + +    always @(posedge stream_clk) +    if(stream_rst | stream_clr) begin +        com_insp_state <= COM_INSP_STATE_READ_COM_PRE; +        com_insp_dreg_count <= 0; +    end +    else begin +        case(com_insp_state) +        COM_INSP_STATE_READ_COM_PRE: begin +            if (com_inp_ready & com_inp_valid & com_inp_data[32]) begin +                com_insp_state <= COM_INSP_STATE_READ_COM; +                com_insp_dreg_count <= com_insp_dreg_count_next; +                com_insp_dregs[com_insp_dreg_count] <= com_inp_data; +            end +        end + +        COM_INSP_STATE_READ_COM: begin +            if (com_inp_ready & com_inp_valid) begin +                com_insp_dregs[com_insp_dreg_count] <= com_inp_data; +                if (com_insp_dreg_counter_done | com_inp_data[33]) begin +                    com_insp_state <= COM_INSP_STATE_WRITE_REGS; +                    com_insp_dreg_count <= 0; + +                    //---------- begin inspection decision -----------// +                    //EOF or bcast or not IPv4 or not UDP: +                    if ( +                        com_inp_data[33] || (com_insp_dregs_eth_dst_mac == 48'hffffffffffff) || +                        (com_insp_dregs_eth_type != 16'h800) || (com_insp_dregs_ipv4_proto != 8'h11) +                    ) begin +                        com_insp_dest <= COM_INSP_DEST_BOF; +                    end + +                    //not my IP address: +                    else if (com_insp_dregs_ipv4_dst_addr != my_ip_addr) begin +                        com_insp_dest <= COM_INSP_DEST_EXT; +                    end + +                    //UDP data port and VRT: +                    else if ((com_insp_dregs_udp_dst_port == dsp0_udp_port) && (com_insp_dregs_vrt_size != 16'h0)) begin +                        com_insp_dest <= COM_INSP_DEST_DSP; +                        com_insp_dreg_count <= COM_INSP_DREGS_DSP_OFFSET; +                    end + +                    //other: +                    else begin +                        com_insp_dest <= COM_INSP_DEST_CPU; +                    end +                    //---------- end inspection decision -------------// + +                end +                else begin +                    com_insp_dreg_count <= com_insp_dreg_count_next; +                end +            end +        end + +        COM_INSP_STATE_WRITE_REGS: begin +            if (com_insp_out_ready & com_insp_out_valid) begin +                if (com_insp_out_data[33]) begin +                    com_insp_state <= COM_INSP_STATE_READ_COM_PRE; +                    com_insp_dreg_count <= 0; +                end +                else if (com_insp_dreg_counter_done) begin +                    com_insp_state <= COM_INSP_STATE_WRITE_LIVE; +                    com_insp_dreg_count <= 0; +                end +                else begin +                    com_insp_dreg_count <= com_insp_dreg_count_next; +                end +            end +        end + +        COM_INSP_STATE_WRITE_LIVE: begin +            if (com_insp_out_ready & com_insp_out_valid & com_insp_out_data[33]) begin +                com_insp_state <= COM_INSP_STATE_READ_COM_PRE; +            end +        end + +        endcase //com_insp_state +    end + +    //////////////////////////////////////////////////////////////////// +    // 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,  _cpu_out_data; +    wire        _split_to_ext_valid, _split_to_cpu_valid, _cpu_out_valid; +    wire        _split_to_ext_ready, _split_to_cpu_ready, _cpu_out_ready; + +    splitter36 bof_out_splitter( +        .clk(stream_clk), .rst(stream_rst), .clr(stream_clr), +        .inp_data(com_insp_out_bof_data), .inp_valid(com_insp_out_bof_valid), .inp_ready(com_insp_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(stream_clk), .reset(stream_rst), .clear(stream_clr), +        .data0_i(com_insp_out_ext_data), .src0_rdy_i(com_insp_out_ext_valid), .dst0_rdy_o(com_insp_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(stream_clk), .reset(stream_rst), .clear(stream_clr), +        .data0_i(com_insp_out_cpu_data), .src0_rdy_i(com_insp_out_cpu_valid), .dst0_rdy_o(com_insp_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) +    ); + +    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) +    ); + +    //////////////////////////////////////////////////////////////////// +    // DSP input framer +    //////////////////////////////////////////////////////////////////// + +    dsp_framer36 #(.BUF_SIZE(BUF_SIZE)) dsp0_framer36( +        .clk(stream_clk), .rst(stream_rst), .clr(stream_clr), +        .inp_data(dsp_inp_data), .inp_valid(dsp_inp_valid), .inp_ready(dsp_inp_ready), +        .out_data(dsp_frm_data), .out_valid(dsp_frm_valid), .out_ready(dsp_frm_ready) +    ); + +    //////////////////////////////////////////////////////////////////// +    // UDP TX Protocol machine +    //////////////////////////////////////////////////////////////////// + +    //dummy signals to connect the components below +    wire [18:0] _udp_r2s_data, _udp_s2p_data, _udp_p2s_data, _udp_s2r_data; +    wire _udp_r2s_valid, _udp_s2p_valid, _udp_p2s_valid, _udp_s2r_valid; +    wire _udp_r2s_ready, _udp_s2p_ready, _udp_p2s_ready, _udp_s2r_ready; + +    wire [35:0] _com_out_data; +    wire _com_out_valid, _com_out_ready; + +    fifo36_to_fifo19 udp_fifo36_to_fifo19 +     (.clk(stream_clk), .reset(stream_rst), .clear(stream_clr), +      .f36_datain(udp_out_data),   .f36_src_rdy_i(udp_out_valid),  .f36_dst_rdy_o(udp_out_ready), +      .f19_dataout(_udp_r2s_data), .f19_src_rdy_o(_udp_r2s_valid), .f19_dst_rdy_i(_udp_r2s_ready) ); + +    fifo_short #(.WIDTH(19)) udp_shortfifo19_inp +     (.clk(stream_clk), .reset(stream_rst), .clear(stream_clr), +      .datain(_udp_r2s_data),  .src_rdy_i(_udp_r2s_valid), .dst_rdy_o(_udp_r2s_ready), +      .dataout(_udp_s2p_data), .src_rdy_o(_udp_s2p_valid), .dst_rdy_i(_udp_s2p_ready), +      .space(), .occupied() ); + +    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_s2p_data),  .src_rdy_i(_udp_s2p_valid), .dst_rdy_o(_udp_s2p_ready), +      .dataout(_udp_p2s_data), .src_rdy_o(_udp_p2s_valid), .dst_rdy_i(_udp_p2s_ready) ); + +    fifo_short #(.WIDTH(19)) udp_shortfifo19_out +     (.clk(stream_clk), .reset(stream_rst), .clear(stream_clr), +      .datain(_udp_p2s_data),  .src_rdy_i(_udp_p2s_valid), .dst_rdy_o(_udp_p2s_ready), +      .dataout(_udp_s2r_data), .src_rdy_o(_udp_s2r_valid), .dst_rdy_i(_udp_s2r_ready), +      .space(), .occupied() ); + +    fifo19_to_fifo36 udp_fifo19_to_fifo36 +     (.clk(stream_clk), .reset(stream_rst), .clear(stream_clr), +      .f19_datain(_udp_s2r_data), .f19_src_rdy_i(_udp_s2r_valid), .f19_dst_rdy_o(_udp_s2r_ready), +      .f36_dataout(_com_out_data), .f36_src_rdy_o(_com_out_valid),  .f36_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 (8) +        dsp_inp_ready, dsp_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, + +        //inspector interfaces (8) +        com_insp_out_dsp_ready, com_insp_out_dsp_valid, +        com_insp_out_ext_ready, com_insp_out_ext_valid, +        com_insp_out_cpu_ready, com_insp_out_cpu_valid, +        com_insp_out_bof_ready, com_insp_out_bof_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 +    }; + +endmodule // packet_router diff --git a/fpga/usrp2/fifo/splitter36.v b/fpga/usrp2/fifo/splitter36.v new file mode 100644 index 000000000..ed998b4f5 --- /dev/null +++ b/fpga/usrp2/fifo/splitter36.v @@ -0,0 +1,68 @@ + +// 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..d45eee497 --- /dev/null +++ b/fpga/usrp2/fifo/valve36.v @@ -0,0 +1,29 @@ + + +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 | 
