diff options
author | Matt Ettus <matt@ettus.com> | 2010-05-27 17:31:46 -0700 |
---|---|---|
committer | Matt Ettus <matt@ettus.com> | 2010-05-27 17:31:46 -0700 |
commit | 3d06fb26c5a59451b26680b6096fca7ee37e8018 (patch) | |
tree | ce172a14304474b2a46854bea6b47c2ed1f8380b | |
parent | 621ad7cc9e68b4e304b616d8f840d3a03a047c8b (diff) | |
parent | b38d2424b1ac3242146fc9305d9e4ae80e21dede (diff) | |
download | uhd-3d06fb26c5a59451b26680b6096fca7ee37e8018.tar.gz uhd-3d06fb26c5a59451b26680b6096fca7ee37e8018.tar.bz2 uhd-3d06fb26c5a59451b26680b6096fca7ee37e8018.zip |
Merge branch 'udp' into master_merge_take2
* udp: (67 commits)
better test program for just the tx side
fix typo, no functionality difference
ignores
move dsp settings regs to reclocked setting bus. Works, gets us to within 18ps of passing timing
reverting logic clean up which should have made timing better, but made it worse instead
moved fifos around, now easier to see where they are and how big
bigger fifo on UDP TX path, to possibly fix overruns on decim=4
Xilinx ISE is incorrectly parsing the verilog case statement, this is a workaround
pps and vita time debug pins
ignore emacs backup files
more debug for fixing E's
better debug pins for going after cascading E's
copy in wrong place
copied over from quad radio
just debug pin changes
typo caused the tx udp chain to be disconnected
moved into subdir
speed up timing by ignoring the too_early error. We'll need to FIXME this later
Added set time and set time at next pps. Removed the old sync pps commands, they dont make sense to use anymore.
moved around regs, added a bit to allow for alternate PPS source
...
30 files changed, 2257 insertions, 67 deletions
diff --git a/usrp2/control_lib/newfifo/fifo19_to_fifo36.v b/usrp2/control_lib/newfifo/fifo19_to_fifo36.v index e22ca0a49..5f9aeff9b 100644 --- a/usrp2/control_lib/newfifo/fifo19_to_fifo36.v +++ b/usrp2/control_lib/newfifo/fifo19_to_fifo36.v @@ -7,7 +7,8 @@ module fifo19_to_fifo36 output [35:0] f36_dataout, output f36_src_rdy_o, - input f36_dst_rdy_i + input f36_dst_rdy_i, + output [31:0] debug ); reg f36_sof, f36_eof, f36_occ; @@ -50,7 +51,9 @@ module fifo19_to_fifo36 state <= 2; 2 : if(xfer_out) - state <= 1; + if(~f19_eof) + state <= 1; + // remain in state 2 if we are at eof endcase // case(state) else if(xfer_out) @@ -67,5 +70,7 @@ module fifo19_to_fifo36 assign f19_dst_rdy_o = xfer_out | (state != 2); assign f36_dataout = {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/usrp2/control_lib/newfifo/ll8_to_fifo19.v b/usrp2/control_lib/newfifo/ll8_to_fifo19.v index c65be5136..af3b91afb 100644 --- a/usrp2/control_lib/newfifo/ll8_to_fifo19.v +++ b/usrp2/control_lib/newfifo/ll8_to_fifo19.v @@ -10,68 +10,64 @@ module ll8_to_fifo19 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; Not needed - reg f19_sof, f19_eof, f19_occ; + 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] dat0, dat1; - - always @(posedge clk) - if(ll_src_rdy & ((state==0)|xfer_out)) - f19_sof <= ll_sof; - + reg [7:0] hold_reg; + always @(posedge clk) - if(ll_src_rdy & ((state != 2)|xfer_out)) - f19_eof <= ll_eof; - + if(ll_src_rdy & (state==XFER_EMPTY)) + hold_reg <= ll_data; + always @(posedge clk) - if(ll_eof) - f19_occ <= ~state[0]; - else - f19_occ <= 0; + if(ll_sof & (state==XFER_EMPTY)) + hold_sof <= 1; + else if(xfer_out) + hold_sof <= 0; always @(posedge clk) - if(reset) - state <= 0; + if(reset | clear) + state <= XFER_EMPTY; else - if(ll_src_rdy) - case(state) - 0 : + case(state) + XFER_EMPTY : + if(ll_src_rdy) if(ll_eof) - state <= 2; + state <= XFER_HALF_WRITE; else - state <= 1; - 1 : - state <= 2; - 2 : - if(xfer_out) - state <= 1; - endcase // case(state) - else - if(xfer_out) - state <= 0; - - always @(posedge clk) - if(ll_src_rdy & (state==1)) - dat1 <= ll_data; - - always @(posedge clk) - if(ll_src_rdy & ((state==0) | xfer_out)) - dat0 <= ll_data; + 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 ll_dst_rdy = xfer_out | (state != 2); - assign f19_data = {f19_occ,f19_eof,f19_sof,dat0,dat1}; - assign f19_src_rdy_o = (state == 2); + assign f19_data = {f19_occ,f19_eof,f19_sof,hold_reg,ll_data}; endmodule // ll8_to_fifo19 diff --git a/usrp2/control_lib/settings_bus.v b/usrp2/control_lib/settings_bus.v index d01a30ab4..fc960e456 100644 --- a/usrp2/control_lib/settings_bus.v +++ b/usrp2/control_lib/settings_bus.v @@ -10,7 +10,6 @@ module settings_bus input wb_stb_i, input wb_we_i, output reg wb_ack_o, - input sys_clk, output strobe, output reg [7:0] addr, output reg [31:0] data); diff --git a/usrp2/sdr_lib/dsp_core_tx.v b/usrp2/sdr_lib/dsp_core_tx.v index 346d65ced..22d3d44a3 100644 --- a/usrp2/sdr_lib/dsp_core_tx.v +++ b/usrp2/sdr_lib/dsp_core_tx.v @@ -1,7 +1,6 @@ -`define DSP_CORE_TX_BASE 128 - module dsp_core_tx + #(parameter BASE=0) (input clk, input rst, input set_stb, input [7:0] set_addr, input [31:0] set_data, @@ -22,19 +21,19 @@ module dsp_core_tx wire [3:0] dacmux_a, dacmux_b; wire enable_hb1, enable_hb2; - setting_reg #(.my_addr(`DSP_CORE_TX_BASE+0)) sr_0 + setting_reg #(.my_addr(BASE+0)) sr_0 (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(phase_inc),.changed()); - setting_reg #(.my_addr(`DSP_CORE_TX_BASE+1)) sr_1 + setting_reg #(.my_addr(BASE+1)) sr_1 (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out({scale_i,scale_q}),.changed()); - setting_reg #(.my_addr(`DSP_CORE_TX_BASE+2)) sr_2 + setting_reg #(.my_addr(BASE+2)) sr_2 (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out({enable_hb1, enable_hb2, interp_rate}),.changed()); - setting_reg #(.my_addr(`DSP_CORE_TX_BASE+4)) sr_4 + setting_reg #(.my_addr(BASE+4)) sr_4 (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out({dacmux_b,dacmux_a}),.changed()); diff --git a/usrp2/simple_gemac/eth_tasks_f19.v b/usrp2/simple_gemac/eth_tasks_f19.v new file mode 100644 index 000000000..ff3ae5407 --- /dev/null +++ b/usrp2/simple_gemac/eth_tasks_f19.v @@ -0,0 +1,92 @@ + + +task SendFlowCtrl; + input [15:0] fc_len; + begin + $display("Sending Flow Control, quanta = %d, time = %d", fc_len,$time); + pause_time <= fc_len; + @(posedge eth_clk); + pause_req <= 1; + @(posedge eth_clk); + pause_req <= 0; + $display("Sent Flow Control"); + end +endtask // SendFlowCtrl + +task SendPacket_to_fifo19; + input [31:0] data_start; + input [15:0] data_len; + reg [15:0] count; + begin + $display("Sending Packet Len=%d, %d", data_len, $time); + count <= 2; + tx_f19_data <= {2'b0, 1'b0, 1'b1, data_start}; + tx_f19_src_rdy <= 1; + #1; + while(count < data_len) + begin + while(~tx_f19_dst_rdy) + @(posedge sys_clk); + @(posedge sys_clk); + //tx_f19_data[31:0] = tx_f19_data[31:0] + 32'h0101_0101; + count = count + 4; + //tx_f19_data[32] <= 0; + end + //tx_f19_data[33] <= 1; + while(~tx_f19_dst_rdy) + @(posedge sys_clk); + @(posedge sys_clk); + tx_f19_src_rdy <= 0; + end +endtask // SendPacket_to_fifo19 + +/* +task Waiter; + input [31:0] wait_length; + begin + tx_ll_src_rdy2 <= 0; + repeat(wait_length) + @(posedge clk); + tx_ll_src_rdy2 <= 1; + end +endtask // Waiter +*/ + +/* +task SendPacketFromFile_f19; + input [31:0] data_len; + input [31:0] wait_length; + input [31:0] wait_time; + + integer count; + begin + $display("Sending Packet From File to LL8 Len=%d, %d",data_len,$time); + $readmemh("test_packet.mem",pkt_rom ); + + while(~tx_f19_dst_rdy) + @(posedge clk); + tx_f19_data <= pkt_rom[0]; + tx_f19_src_rdy <= 1; + tx_f19_eof <= 0; + @(posedge clk); + + for(i=1;i<data_len-1;i=i+1) + begin + while(~tx_ll_dst_rdy2) + @(posedge clk); + tx_ll_data2 <= pkt_rom[i]; + tx_ll_sof2 <= 0; + @(posedge clk); +// if(i==wait_time) +// Waiter(wait_length); + end + + while(~tx_ll_dst_rdy2) + @(posedge clk); + tx_ll_eof2 <= 1; + tx_ll_data2 <= pkt_rom[data_len-1]; + @(posedge clk); + tx_ll_src_rdy2 <= 0; + end +endtask +*/ diff --git a/usrp2/simple_gemac/ll8_shortfifo.v b/usrp2/simple_gemac/ll8_shortfifo.v deleted file mode 100644 index e69de29bb..000000000 --- a/usrp2/simple_gemac/ll8_shortfifo.v +++ /dev/null diff --git a/usrp2/simple_gemac/simple_gemac.v b/usrp2/simple_gemac/simple_gemac.v index e7f327358..2dd8deb99 100644 --- a/usrp2/simple_gemac/simple_gemac.v +++ b/usrp2/simple_gemac/simple_gemac.v @@ -16,7 +16,9 @@ module simple_gemac output rx_clk, output [7:0] rx_data, output rx_valid, output rx_error, output rx_ack, // TX Client Interface - output tx_clk, input [7:0] tx_data, input tx_valid, input tx_error, output tx_ack + output tx_clk, input [7:0] tx_data, input tx_valid, input tx_error, output tx_ack, + + output [31:0] debug ); localparam SGE_IFG = 8'd12; // 12 should be the absolute minimum @@ -46,7 +48,8 @@ module simple_gemac .ucast_addr(ucast_addr), .mcast_addr(mcast_addr), .pass_ucast(pass_ucast), .pass_mcast(pass_mcast), .pass_bcast(pass_bcast), .pass_pause(pass_pause), .pass_all(pass_all), - .pause_quanta_rcvd(pause_quanta_rcvd), .pause_rcvd(pause_rcvd) + .pause_quanta_rcvd(pause_quanta_rcvd), .pause_rcvd(pause_rcvd), + .debug(debug) ); flow_ctrl_tx flow_ctrl_tx diff --git a/usrp2/simple_gemac/simple_gemac_rx.v b/usrp2/simple_gemac/simple_gemac_rx.v index 45ddd6dfa..b02bb0758 100644 --- a/usrp2/simple_gemac/simple_gemac_rx.v +++ b/usrp2/simple_gemac/simple_gemac_rx.v @@ -6,7 +6,8 @@ module simple_gemac_rx output rx_clk, output [7:0] rx_data, output reg rx_valid, output rx_error, output reg rx_ack, input [47:0] ucast_addr, input [47:0] mcast_addr, input pass_ucast, input pass_mcast, input pass_bcast, input pass_pause, input pass_all, - output reg [15:0] pause_quanta_rcvd, output pause_rcvd ); + output reg [15:0] pause_quanta_rcvd, output pause_rcvd, + output [31:0] debug ); localparam RX_IDLE = 0; localparam RX_PREAMBLE = 1; @@ -170,5 +171,7 @@ module simple_gemac_rx pause_quanta_rcvd[7:0] <= rxd_d1; assign rx_clk = GMII_RX_CLK; + + assign debug = rx_state; endmodule // simple_gemac_rx diff --git a/usrp2/simple_gemac/simple_gemac_wrapper19.build b/usrp2/simple_gemac/simple_gemac_wrapper19.build new file mode 100755 index 000000000..4be0aac1f --- /dev/null +++ b/usrp2/simple_gemac/simple_gemac_wrapper19.build @@ -0,0 +1 @@ +iverilog -Wimplict -Wportbind -y ../control_lib/newfifo/ -y ../models/ -y . -y miim -y ../coregen/ -y ../control_lib/ -o simple_gemac_wrapper19_tb simple_gemac_wrapper19_tb.v diff --git a/usrp2/simple_gemac/simple_gemac_wrapper19.v b/usrp2/simple_gemac/simple_gemac_wrapper19.v new file mode 100644 index 000000000..6cdbd1a59 --- /dev/null +++ b/usrp2/simple_gemac/simple_gemac_wrapper19.v @@ -0,0 +1,170 @@ + +module simple_gemac_wrapper19 + #(parameter RXFIFOSIZE=9, + parameter TXFIFOSIZE=6) + (input clk125, input reset, + // GMII + output GMII_GTX_CLK, output GMII_TX_EN, output GMII_TX_ER, output [7:0] GMII_TXD, + input GMII_RX_CLK, input GMII_RX_DV, input GMII_RX_ER, input [7:0] GMII_RXD, + + // Client FIFO Interfaces + input sys_clk, + output [18:0] rx_f19_data, output rx_f19_src_rdy, input rx_f19_dst_rdy, + input [18:0] tx_f19_data, input tx_f19_src_rdy, output tx_f19_dst_rdy, + + // Wishbone Interface + input wb_clk, input wb_rst, input wb_stb, input wb_cyc, output wb_ack, input wb_we, + input [7:0] wb_adr, input [31:0] wb_dat_i, output [31:0] wb_dat_o, + + // MIIM + inout mdio, output mdc, + output [31:0] debug); + + wire clear = 0; + wire [7:0] rx_data, tx_data; + wire tx_clk, tx_valid, tx_error, tx_ack; + wire rx_clk, rx_valid, rx_error, rx_ack; + + wire [47:0] ucast_addr, mcast_addr; + wire pass_ucast, pass_mcast, pass_bcast, pass_pause, pass_all; + wire pause_req; + wire pause_request_en, pause_respect_en; + wire [15:0] pause_time, pause_thresh, pause_time_req, rx_fifo_space; + + wire [31:0] debug_state; + + wire tx_reset, rx_reset; + reset_sync reset_sync_tx (.clk(tx_clk),.reset_in(reset),.reset_out(tx_reset)); + reset_sync reset_sync_rx (.clk(rx_clk),.reset_in(reset),.reset_out(rx_reset)); + + simple_gemac simple_gemac + (.clk125(clk125), .reset(reset), + .GMII_GTX_CLK(GMII_GTX_CLK), .GMII_TX_EN(GMII_TX_EN), + .GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD), + .GMII_RX_CLK(GMII_RX_CLK), .GMII_RX_DV(GMII_RX_DV), + .GMII_RX_ER(GMII_RX_ER), .GMII_RXD(GMII_RXD), + .pause_req(pause_req), .pause_time_req(pause_time_req), + .pause_respect_en(pause_respect_en), + .ucast_addr(ucast_addr), .mcast_addr(mcast_addr), + .pass_ucast(pass_ucast), .pass_mcast(pass_mcast), .pass_bcast(pass_bcast), + .pass_pause(pass_pause), .pass_all(pass_all), + .rx_clk(rx_clk), .rx_data(rx_data), + .rx_valid(rx_valid), .rx_error(rx_error), .rx_ack(rx_ack), + .tx_clk(tx_clk), .tx_data(tx_data), + .tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack), + .debug(debug_state) + ); + + simple_gemac_wb simple_gemac_wb + (.wb_clk(wb_clk), .wb_rst(wb_rst), + .wb_cyc(wb_cyc), .wb_stb(wb_stb), .wb_ack(wb_ack), .wb_we(wb_we), + .wb_adr(wb_adr), .wb_dat_i(wb_dat_i), .wb_dat_o(wb_dat_o), + .mdio(mdio), .mdc(mdc), + .ucast_addr(ucast_addr), .mcast_addr(mcast_addr), + .pass_ucast(pass_ucast), .pass_mcast(pass_mcast), .pass_bcast(pass_bcast), + .pass_pause(pass_pause), .pass_all(pass_all), + .pause_respect_en(pause_respect_en), .pause_request_en(pause_request_en), + .pause_time(pause_time), .pause_thresh(pause_thresh) ); + + // RX FIFO Chain + wire rx_ll_sof, rx_ll_eof, rx_ll_src_rdy, rx_ll_dst_rdy; + + wire rx_ll_sof2, rx_ll_eof2, rx_ll_src_rdy2, rx_ll_dst_rdy2; + wire rx_ll_sof2_n, rx_ll_eof2_n, rx_ll_src_rdy2_n, rx_ll_dst_rdy2_n; + + wire [7:0] rx_ll_data, rx_ll_data2; + + wire [18:0] rx_f19_data_int1; + wire rx_f19_src_rdy_int1, rx_f19_dst_rdy_int1; + + rxmac_to_ll8 rx_adapt + (.clk(rx_clk), .reset(rx_reset), .clear(0), + .rx_data(rx_data), .rx_valid(rx_valid), .rx_error(rx_error), .rx_ack(rx_ack), + .ll_data(rx_ll_data), .ll_sof(rx_ll_sof), .ll_eof(rx_ll_eof), .ll_error(), // error also encoded in sof/eof + .ll_src_rdy(rx_ll_src_rdy), .ll_dst_rdy(rx_ll_dst_rdy)); + + ll8_shortfifo rx_sfifo + (.clk(rx_clk), .reset(rx_reset), .clear(0), + .datain(rx_ll_data), .sof_i(rx_ll_sof), .eof_i(rx_ll_eof), + .error_i(0), .src_rdy_i(rx_ll_src_rdy), .dst_rdy_o(rx_ll_dst_rdy), + .dataout(rx_ll_data2), .sof_o(rx_ll_sof2), .eof_o(rx_ll_eof2), + .error_o(), .src_rdy_o(rx_ll_src_rdy2), .dst_rdy_i(rx_ll_dst_rdy2)); + + assign rx_ll_dst_rdy2 = ~rx_ll_dst_rdy2_n; + assign rx_ll_src_rdy2_n = ~rx_ll_src_rdy2; + assign rx_ll_sof2_n = ~rx_ll_sof2; + assign rx_ll_eof2_n = ~rx_ll_eof2; + + ll8_to_fifo19 ll8_to_fifo19 + (.clk(rx_clk), .reset(rx_reset), .clear(0), + .ll_data(rx_ll_data2), .ll_sof_n(rx_ll_sof2_n), .ll_eof_n(rx_ll_eof2_n), + .ll_src_rdy_n(rx_ll_src_rdy2_n), .ll_dst_rdy_n(rx_ll_dst_rdy2_n), + .f19_data(rx_f19_data_int1), .f19_src_rdy_o(rx_f19_src_rdy_int1), .f19_dst_rdy_i(rx_f19_dst_rdy_int1)); + + //fifo_2clock_cascade #(.WIDTH(19), .SIZE(RXFIFOSIZE)) rx_2clk_fifo + fifo_2clock_cascade #(.WIDTH(36), .SIZE(RXFIFOSIZE)) rx_2clk_fifo + (.wclk(rx_clk), .datain(rx_f19_data_int1), + .src_rdy_i(rx_f19_src_rdy_int1), .dst_rdy_o(rx_f19_dst_rdy_int1), .space(rx_fifo_space), + .rclk(sys_clk), .dataout(rx_f19_data), + .src_rdy_o(rx_f19_src_rdy), .dst_rdy_i(rx_f19_dst_rdy), .occupied(), .arst(reset)); + + // TX FIFO Chain + wire tx_ll_sof, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy; + wire tx_ll_sof2, tx_ll_eof2, tx_ll_src_rdy2, tx_ll_dst_rdy2; + wire tx_ll_sof2_n, tx_ll_eof2_n, tx_ll_src_rdy2_n, tx_ll_dst_rdy2_n; + wire [7:0] tx_ll_data, tx_ll_data2; + wire [18:0] tx_f19_data_int1; + wire tx_f19_src_rdy_int1, tx_f19_dst_rdy_int1; + + fifo_2clock_cascade #(.WIDTH(19), .SIZE(4)) tx_2clk_fifo + (.wclk(sys_clk), .datain(tx_f19_data), + .src_rdy_i(tx_f19_src_rdy), .dst_rdy_o(tx_f19_dst_rdy), .space(), + .rclk(tx_clk), .dataout(tx_f19_data_int1), + .src_rdy_o(tx_f19_src_rdy_int1), .dst_rdy_i(tx_f19_dst_rdy_int1), .occupied(), .arst(rx_reset)); + + fifo19_to_ll8 fifo19_to_ll8 + (.clk(tx_clk), .reset(tx_reset), .clear(clear), + .f19_data(tx_f19_data_int1), .f19_src_rdy_i(tx_f19_src_rdy_int1), .f19_dst_rdy_o(tx_f19_dst_rdy_int1), + .ll_data(tx_ll_data2), .ll_sof_n(tx_ll_sof2_n), .ll_eof_n(tx_ll_eof2_n), + .ll_src_rdy_n(tx_ll_src_rdy2_n), .ll_dst_rdy_n(tx_ll_dst_rdy2_n)); + + assign tx_ll_sof2 = ~tx_ll_sof2_n; + assign tx_ll_eof2 = ~tx_ll_eof2_n; + assign tx_ll_src_rdy2 = ~tx_ll_src_rdy2_n; + assign tx_ll_dst_rdy2_n = ~tx_ll_dst_rdy2; + + ll8_shortfifo tx_sfifo + (.clk(tx_clk), .reset(tx_reset), .clear(clear), + .datain(tx_ll_data2), .sof_i(tx_ll_sof2), .eof_i(tx_ll_eof2), + .error_i(0), .src_rdy_i(tx_ll_src_rdy2), .dst_rdy_o(tx_ll_dst_rdy2), + .dataout(tx_ll_data), .sof_o(tx_ll_sof), .eof_o(tx_ll_eof), + .error_o(), .src_rdy_o(tx_ll_src_rdy), .dst_rdy_i(tx_ll_dst_rdy)); + + ll8_to_txmac ll8_to_txmac + (.clk(tx_clk), .reset(tx_reset), .clear(clear), + .ll_data(tx_ll_data), .ll_sof(tx_ll_sof), .ll_eof(tx_ll_eof), + .ll_src_rdy(tx_ll_src_rdy), .ll_dst_rdy(tx_ll_dst_rdy), + .tx_data(tx_data), .tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack)); + + // Flow Control + flow_ctrl_rx flow_ctrl_rx + (.pause_request_en(pause_request_en), .pause_time(pause_time), .pause_thresh(pause_thresh), + .rx_clk(rx_clk), .rx_reset(rx_reset), .rx_fifo_space(rx_fifo_space), + .tx_clk(tx_clk), .tx_reset(tx_reset), .pause_req(pause_req), .pause_time_req(pause_time_req)); + + wire [31:0] debug_tx, debug_rx; + + assign debug_tx = { { tx_ll_data }, + { tx_ll_sof, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy, + tx_ll_sof2, tx_ll_eof2, tx_ll_src_rdy2, tx_ll_dst_rdy2 }, + { tx_valid, tx_error, tx_ack, tx_f19_src_rdy_int1, tx_f19_dst_rdy_int1, tx_f19_data_int1[18:16]}, + { tx_data} }; + assign debug_rx = { { rx_f19_src_rdy, rx_f19_dst_rdy, debug_state[5:0] }, + { rx_ll_sof, rx_ll_eof, rx_ll_src_rdy, rx_ll_dst_rdy, + rx_ll_sof2, rx_ll_eof2, rx_ll_src_rdy2, rx_ll_dst_rdy2 }, + { rx_valid, rx_error, rx_ack, rx_f19_src_rdy_int1, rx_f19_dst_rdy_int1, rx_f19_data_int1[18:16]}, + { rx_data} }; + + assign debug = debug_rx; + +endmodule // simple_gemac_wrapper19 diff --git a/usrp2/simple_gemac/simple_gemac_wrapper19_tb.v b/usrp2/simple_gemac/simple_gemac_wrapper19_tb.v new file mode 100644 index 000000000..7d57542dc --- /dev/null +++ b/usrp2/simple_gemac/simple_gemac_wrapper19_tb.v @@ -0,0 +1,209 @@ + + +module simple_gemac_wrapper19_tb; +`include "eth_tasks_f19.v" + + reg reset = 1; + initial #1000 reset = 0; + wire wb_rst = reset; + + reg eth_clk = 0; + always #50 eth_clk = ~eth_clk; + + reg wb_clk = 0; + always #173 wb_clk = ~wb_clk; + + reg sys_clk = 0; + always #77 sys_clk = ~ sys_clk; + + wire GMII_RX_DV, GMII_RX_ER, GMII_TX_EN, GMII_TX_ER, GMII_GTX_CLK; + wire [7:0] GMII_RXD, GMII_TXD; + + wire rx_valid, rx_error, rx_ack; + wire tx_ack, tx_valid, tx_error; + + wire [7:0] rx_data, tx_data; + + reg [15:0] pause_time; + reg pause_req = 0; + + wire GMII_RX_CLK = GMII_GTX_CLK; + + reg [7:0] FORCE_DAT_ERR = 0; + reg FORCE_ERR = 0; + + // Loopback + assign GMII_RX_DV = GMII_TX_EN; + assign GMII_RX_ER = GMII_TX_ER | FORCE_ERR; + assign GMII_RXD = GMII_TXD ^ FORCE_DAT_ERR; + + + wire [31:0] wb_dat_o; + reg [31:0] wb_dat_i; + reg [7:0] wb_adr; + reg wb_stb=0, wb_cyc=0, wb_we=0; + wire wb_ack; + + reg [18:0] tx_f19_data=0; + reg tx_f19_src_rdy = 0; + wire tx_f19_dst_rdy; + wire [35:0] rx_f36_data; + wire rx_f36_src_rdy; + wire rx_f36_dst_rdy = 1; + + simple_gemac_wrapper19 simple_gemac_wrapper19 + (.clk125(eth_clk), .reset(reset), + .GMII_GTX_CLK(GMII_GTX_CLK), .GMII_TX_EN(GMII_TX_EN), + .GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD), + .GMII_RX_CLK(GMII_RX_CLK), .GMII_RX_DV(GMII_RX_DV), + .GMII_RX_ER(GMII_RX_ER), .GMII_RXD(GMII_RXD), + //.pause_req(pause_req), .pause_time(pause_time), + + .sys_clk(sys_clk), .rx_f36_data(rx_f36_data), .rx_f36_src_rdy(rx_f36_src_rdy), .rx_f36_dst_rdy(rx_f36_dst_rdy), + .tx_f19_data(tx_f19_data), .tx_f19_src_rdy(tx_f19_src_rdy), .tx_f19_dst_rdy(tx_f19_dst_rdy), + + .wb_clk(wb_clk), .wb_rst(wb_rst), .wb_stb(wb_stb), .wb_cyc(wb_cyc), .wb_ack(wb_ack), .wb_we(wb_we), + .wb_adr(wb_adr), .wb_dat_i(wb_dat_i), .wb_dat_o(wb_dat_o), + + .mdio(), .mdc(), + .debug() ); + + initial $dumpfile("simple_gemac_wrapper19_tb.vcd"); + initial $dumpvars(0,simple_gemac_wrapper19_tb); + + integer i; + reg [7:0] pkt_rom[0:65535]; + reg [1023:0] ROMFile; + + initial + for (i=0;i<65536;i=i+1) + pkt_rom[i] <= 8'h0; + + initial + begin + @(negedge reset); + repeat (10) + @(posedge wb_clk); + WishboneWR(0,6'b111101); + WishboneWR(4,16'hA0B0); + WishboneWR(8,32'hC0D0_A1B1); + WishboneWR(12,16'h0000); + WishboneWR(16,32'h0000_0000); + + @(posedge eth_clk); + SendFlowCtrl(16'h0007); // Send flow control + @(posedge eth_clk); + #30000; + @(posedge eth_clk); + SendFlowCtrl(16'h0009); // Increase flow control before it expires + #10000; + @(posedge eth_clk); + SendFlowCtrl(16'h0000); // Cancel flow control before it expires + @(posedge eth_clk); + + repeat (1000) + @(posedge sys_clk); + SendPacket_to_fifo19(32'hA0B0C0D0,10); // This packet gets dropped by the filters + repeat (1000) + @(posedge sys_clk); + + SendPacket_to_fifo19(32'hAABBCCDD,100); // This packet gets dropped by the filters + repeat (10) + @(posedge sys_clk); +/* + SendPacketFromFile_f36(60,0,0); // The rest are valid packets + repeat (10) + @(posedge clk); + + SendPacketFromFile_f36(61,0,0); + repeat (10) + @(posedge clk); + SendPacketFromFile_f36(62,0,0); + repeat (10) + @(posedge clk); + SendPacketFromFile_f36(63,0,0); + repeat (1) + @(posedge clk); + SendPacketFromFile_f36(64,0,0); + repeat (10) + @(posedge clk); + SendPacketFromFile_f36(59,0,0); + repeat (1) + @(posedge clk); + SendPacketFromFile_f36(58,0,0); + repeat (1) + @(posedge clk); + SendPacketFromFile_f36(100,0,0); + repeat (1) + @(posedge clk); + SendPacketFromFile_f36(200,150,30); // waiting 14 empties the fifo, 15 underruns + repeat (1) + @(posedge clk); + SendPacketFromFile_f36(100,0,30); + */ + #100000 $finish; + end + + // Force a CRC error + initial + begin + #90000; + @(posedge eth_clk); + FORCE_DAT_ERR <= 8'h10; + @(posedge eth_clk); + FORCE_DAT_ERR <= 8'h00; + end + + // Force an RX_ER error (i.e. link loss) + initial + begin + #116000; + @(posedge eth_clk); + FORCE_ERR <= 1; + @(posedge eth_clk); + FORCE_ERR <= 0; + end +/* + // Cause receive fifo to fill, causing an RX overrun + initial + begin + #126000; + @(posedge clk); + rx_ll_dst_rdy2 <= 0; + repeat (30) // Repeat of 14 fills the shortfifo, but works. 15 overflows + @(posedge clk); + rx_ll_dst_rdy2 <= 1; + end + */ + // Tests: Send and recv flow control, send and receive good packets, RX CRC err, RX_ER, RX overrun, TX underrun + // Still need to test: CRC errors on Pause Frames, MDIO, wishbone + + task WishboneWR; + input [7:0] adr; + input [31:0] value; + begin + wb_adr <= adr; + wb_dat_i <= value; + wb_stb <= 1; + wb_cyc <= 1; + wb_we <= 1; + while (~wb_ack) + @(posedge wb_clk); + @(posedge wb_clk); + wb_stb <= 0; + wb_cyc <= 0; + wb_we <= 0; + end + endtask // WishboneWR + /* + always @(posedge clk) + if(rx_ll_src_rdy2 & rx_ll_dst_rdy2) + begin + if(rx_ll_sof2 & ~rx_ll_eof2) + $display("RX-PKT-START %d",$time); + $display("RX-PKT SOF %d EOF %d ERR%d DAT %x",rx_ll_sof2,rx_ll_eof2,rx_ll_error2,rx_ll_data2); + if(rx_ll_eof2 & ~rx_ll_sof2) + $display("RX-PKT-END %d",$time); + end + */ +endmodule // simple_gemac_wrapper19_tb diff --git a/usrp2/timing/simple_timer.v b/usrp2/timing/simple_timer.v new file mode 100644 index 000000000..17c7f1c36 --- /dev/null +++ b/usrp2/timing/simple_timer.v @@ -0,0 +1,60 @@ + + +module simple_timer + #(parameter BASE=0) + (input clk, input reset, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + output reg onetime_int, output reg periodic_int); + + reg [31:0] onetime_ctr; + always @(posedge clk) + if(reset) + begin + onetime_int <= 0; + onetime_ctr <= 0; + end + else + if(set_stb & (set_addr == BASE)) + begin + onetime_int <= 0; + onetime_ctr <= set_data; + end + else + begin + if(onetime_ctr == 1) + onetime_int <= 1; + if(onetime_ctr != 0) + onetime_ctr <= onetime_ctr - 1; + else + onetime_int <= 0; + end // else: !if(set_stb & (set_addr == BASE)) + + reg [31:0] periodic_ctr, period; + always @(posedge clk) + if(reset) + begin + periodic_int <= 0; + periodic_ctr <= 0; + period <= 0; + end + else + if(set_stb & (set_addr == (BASE+1))) + begin + periodic_int <= 0; + periodic_ctr <= set_data; + period <= set_data; + end + else + if(periodic_ctr == 1) + begin + periodic_int <= 1; + periodic_ctr <= period; + end + else + if(periodic_ctr != 0) + begin + periodic_int <= 0; + periodic_ctr <= periodic_ctr - 1; + end + +endmodule // simple_timer diff --git a/usrp2/timing/time_64bit.v b/usrp2/timing/time_64bit.v index c0a846e74..8ccde3f54 100644 --- a/usrp2/timing/time_64bit.v +++ b/usrp2/timing/time_64bit.v @@ -6,19 +6,28 @@ module time_64bit (input clk, input rst, input set_stb, input [7:0] set_addr, input [31:0] set_data, input pps, - output [63:0] vita_time + output [63:0] vita_time, output pps_int ); - localparam NEXT_TICKS = 0; - localparam NEXT_SECS = 1; + localparam NEXT_SECS = 0; + localparam NEXT_TICKS = 1; + localparam PPS_POLSRC = 2; + localparam PPS_IMM = 3; + localparam ROLLOVER = TICKS_PER_SEC - 1; + reg [31:0] seconds; + reg [31:0] ticks; + wire end_of_second; assign vita_time = {seconds,ticks}; wire [31:0] next_ticks_preset; wire [31:0] next_seconds_preset; wire set_on_pps_trig; reg set_on_next_pps; + wire pps_polarity; + wire set_imm; + wire pps_source; setting_reg #(.my_addr(BASE+NEXT_TICKS)) sr_next_ticks (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), @@ -27,18 +36,37 @@ module time_64bit setting_reg #(.my_addr(BASE+NEXT_SECS)) sr_next_secs (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(next_seconds_preset),.changed(set_on_pps_trig)); + + setting_reg #(.my_addr(BASE+PPS_POLSRC)) sr_pps_polsrc + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out({pps_source,pps_polarity}),.changed()); + + setting_reg #(.my_addr(BASE+PPS_IMM)) sr_pps_imm + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(set_imm),.changed()); + + reg [1:0] pps_del; + reg pps_reg_p, pps_reg_n, pps_reg; + wire pps_edge; - reg [31:0] seconds; - reg [31:0] ticks; + always @(posedge clk) pps_reg_p <= pps; + always @(negedge clk) pps_reg_n <= pps; + always @* pps_reg <= pps_polarity ? pps_reg_p : pps_reg_n; - wire end_of_second; + always @(posedge clk) + if(rst) + pps_del <= 2'b00; + else + pps_del <= {pps_del[0],pps_reg}; + + assign pps_edge = pps_del[0] & ~pps_del[1]; always @(posedge clk) if(rst) set_on_next_pps <= 0; else if(set_on_pps_trig) set_on_next_pps <= 1; - else if(pps) + else if(set_imm | pps_edge) set_on_next_pps <= 0; always @(posedge clk) @@ -47,7 +75,7 @@ module time_64bit seconds <= 32'd0; ticks <= 32'd0; end - else if(pps & set_on_next_pps) + else if((set_imm | pps_edge) & set_on_next_pps) begin seconds <= next_seconds_preset; ticks <= next_ticks_preset; @@ -59,5 +87,7 @@ module time_64bit end else ticks <= ticks + 1; + + assign pps_int = pps_edge; endmodule // time_64bit diff --git a/usrp2/timing/time_compare.v b/usrp2/timing/time_compare.v new file mode 100644 index 000000000..a21c9f8e0 --- /dev/null +++ b/usrp2/timing/time_compare.v @@ -0,0 +1,23 @@ + +// Top 32 bits are integer seconds, bottom 32 are clock ticks within a second + +module time_compare + (input [63:0] time_now, + input [63:0] trigger_time, + output now, + output early, + output late, + output too_early); + + wire sec_match = (time_now[63:32] == trigger_time[63:32]); + wire sec_late = (time_now[63:32] > trigger_time[63:32]); + + wire tick_match = (time_now[31:0] == trigger_time[31:0]); + wire tick_late = (time_now[31:0] > trigger_time[31:0]); + + assign now = sec_match & tick_match; + assign late = sec_late | (sec_match & tick_late); + assign early = ~now & ~late; + assign too_early = (trigger_time[63:32] > (time_now[63:32] + 4)); // Don't wait too long + +endmodule // time_compare diff --git a/usrp2/top/u2_rev3/.gitignore b/usrp2/top/u2_rev3/.gitignore index 432f8fd58..f50a2b7e5 100644 --- a/usrp2/top/u2_rev3/.gitignore +++ b/usrp2/top/u2_rev3/.gitignore @@ -54,4 +54,4 @@ /*.rpt /*.cel /*.restore -/build +/build* diff --git a/usrp2/udp/add_onescomp.v b/usrp2/udp/add_onescomp.v new file mode 100644 index 000000000..048842a86 --- /dev/null +++ b/usrp2/udp/add_onescomp.v @@ -0,0 +1,12 @@ + + +module add_onescomp + #(parameter WIDTH = 16) + (input [WIDTH-1:0] A, + input [WIDTH-1:0] B, + output [WIDTH-1:0] SUM); + + wire [WIDTH:0] SUM_INT = {1'b0,A} + {1'b0,B}; + assign SUM = SUM_INT[WIDTH-1:0] + {{WIDTH-1{1'b0}},SUM_INT[WIDTH]}; + +endmodule // add_onescomp diff --git a/usrp2/udp/fifo19_rxrealign.v b/usrp2/udp/fifo19_rxrealign.v new file mode 100644 index 000000000..35ad90951 --- /dev/null +++ b/usrp2/udp/fifo19_rxrealign.v @@ -0,0 +1,42 @@ + + +// Adds a junk line at the beginning of every packet, which the +// following stages should ignore. This gives us proper alignment due +// to the 14 byte ethernet header + +// Bit 18 -- odd length +// Bit 17 -- eof +// Bit 16 -- sof +// Bit 15:0 -- data + +module fifo19_rxrealign + (input clk, input reset, input clear, + input [18:0] datain, input src_rdy_i, output dst_rdy_o, + output [18:0] dataout, output src_rdy_o, input dst_rdy_i); + + reg rxre_state; + localparam RXRE_DUMMY = 0; + localparam RXRE_PKT = 1; + + assign dataout[18] = datain[18]; + assign dataout[17] = datain[17]; + assign dataout[16] = (rxre_state==RXRE_DUMMY) | (datain[17] & datain[16]); // allows for passing error signal + assign dataout[15:0] = datain[15:0]; + + always @(posedge clk) + if(reset | clear) + rxre_state <= RXRE_DUMMY; + else if(src_rdy_i & dst_rdy_i) + case(rxre_state) + RXRE_DUMMY : + rxre_state <= RXRE_PKT; + RXRE_PKT : + if(datain[17]) // if eof or error + rxre_state <= RXRE_DUMMY; + endcase // case (rxre_state) + + assign src_rdy_o = src_rdy_i & dst_rdy_i; // Send anytime both sides are ready + assign dst_rdy_o = src_rdy_i & dst_rdy_i & (rxre_state == RXRE_PKT); // Only consume after the dummy + +endmodule // fifo19_rxrealign + diff --git a/usrp2/udp/prot_eng_rx.v b/usrp2/udp/prot_eng_rx.v new file mode 100644 index 000000000..5df158b2b --- /dev/null +++ b/usrp2/udp/prot_eng_rx.v @@ -0,0 +1,121 @@ + + + +// Protocol Engine Receiver +// Checks each line (16 bits) against values in setting regs +// 3 options for each line -- +// Error if mismatch, Slowpath if mismatch, or ignore line +// The engine increases the length of each packet by 32 or 48 bits, +// bringing the total length to a multiple of 32 bits. The last line +// is entirely new, and contains the results of the matching operation: +// 16 bits of flags, 16 bits of data. Flags indicate error or slowpath +// Data indicates line that caused mismatch if any. + + +// Flags[2:0] is {occ, eop, sop} +// Protocol word format is: +// 22 Last Header Line +// 21 SLOWPATH if mismatch +// 20 ERROR if mismatch +// 19 This is the IP checksum +// 18 This is the UDP checksum +// 17 Compute IP checksum on this word +// 16 Compute UDP checksum on this word +// 15:0 data word to be matched + +module prot_eng_rx + #(parameter BASE=0) + (input clk, input reset, input clear, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input [18:0] datain, input src_rdy_i, output dst_rdy_o, + output [18:0] dataout, output src_rdy_o, input dst_rdy_i); + + localparam HDR_WIDTH = 16 + 7; // 16 bits plus flags + localparam HDR_LEN = 32; // Up to 64 bytes of protocol + + // Store header values in a small dual-port (distributed) ram + reg [HDR_WIDTH-1:0] header_ram[0:HDR_LEN-1]; + wire [HDR_WIDTH-1:0] header_word; + + always @(posedge clk) + if(set_stb & ((set_addr & 8'hE0) == BASE)) + header_ram[set_addr[4:0]] <= set_data; + + assign header_word = header_ram[state]; + + wire consume_input = src_rdy_i & dst_rdy_o; + wire produce_output = src_rdy_o & dst_rdy_i; + + // Main State Machine + reg [15:0] pkt_length, fail_word, dataout_int; + + reg slowpath, error, sof_o, eof_o, occ_o, odd; + + assign dataout = {occ_o, eof_o, sof_o, dataout_int}; + + wire [15:0] calc_ip_checksum, calc_udp_checksum; + reg [15:0] rx_ip_checksum, rx_udp_checksum; + + always @(posedge clk) + if(header_word[19]) + rx_ip_checksum <= datain[15:0]; + always @(posedge clk) + if(header_word[18]) + rx_udp_checksum <= datain[15:0]; + + always @(posedge clk) + if(reset | clear) + begin + slowpath <= 0; + error <= 0; + state <= 0; + fail_word <= 0; + eof_o <= 0; + occ_o <= 0; + end + else if(src_rdy_i & dst_rdy_i) + case (state) + 0 : + begin + slowpath <= 0; + error <= 0; + eof_o <= 0; + occ_o <= 0; + state <= 1; + end + + ST_SLOWPATH : + ; + ST_ERROR : + ; + ST_PAYLOAD : + ; + ST_FILLER : + ; + ST_END1 : + ; + ST_END2 : + ; + default : + if(header_word[21] && mismatch) + state <= ST_SLOWPATH; + else if(header_word[20] && mismatch) + state <= ST_ERROR; + else if(header_word[22]) + state <= ST_PAYLOAD; + else + state <= state + 1; + endcase // case (state) + + + + // IP + UDP checksum state machines + checksum_sm ip_chk + (.clk(clk), .reset(reset), .in(datain), + .calc(consume_input & header_word[17]), .clear(state==0), .checksum(ip_checksum)); + + checksum_sm udp_chk + (.clk(clk), .reset(reset), .in(datain), + .calc(consume_input & header_word[16]), .clear(state==0), .checksum(udp_checksum)); + +endmodule // prot_eng_rx diff --git a/usrp2/udp/prot_eng_tx.v b/usrp2/udp/prot_eng_tx.v new file mode 100644 index 000000000..9031011f7 --- /dev/null +++ b/usrp2/udp/prot_eng_tx.v @@ -0,0 +1,119 @@ + +// The input FIFO contents should be 16 bits wide +// The first word is 1 for fast path (accelerated protocol) +// 0 for software implemented protocol +// The second word is the number of bytes in the packet, +// and must be valid even if we are in slow path mode +// Odd means the last word is half full +// Flags[1:0] is {eop, sop} +// Protocol word format is: +// 19 Last Header Line +// 18 IP Header Checksum XOR +// 17 IP Length Here +// 16 UDP Length Here +// 15:0 data word to be sent + +module prot_eng_tx + #(parameter BASE=0) + (input clk, input reset, input clear, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input [18:0] datain, input src_rdy_i, output dst_rdy_o, + output [18:0] dataout, output src_rdy_o, input dst_rdy_i); + + wire [2:0] flags_i = datain[18:16]; + reg [15:0] dataout_int; + reg fast_path, sof_o; + + wire [2:0] flags_o = {flags_i[2], flags_i[1], sof_o}; // OCC, EOF, SOF + + assign dataout = {flags_o[2:0], dataout_int[15:0]}; + + reg [4:0] state; + wire do_payload = (state == 31); + + assign dst_rdy_o = dst_rdy_i & (do_payload | (state==0) | (state==1) | (state==30)); + assign src_rdy_o = src_rdy_i & ~((state==0) | (state==1) | (state==30)); + + localparam HDR_WIDTH = 16 + 4; // 16 bits plus flags + localparam HDR_LEN = 32; // Up to 64 bytes of protocol + + // Store header values in a small dual-port (distributed) ram + reg [HDR_WIDTH-1:0] header_ram[0:HDR_LEN-1]; + wire [HDR_WIDTH-1:0] header_word; + + always @(posedge clk) + if(set_stb & ((set_addr & 8'hE0) == BASE)) + header_ram[set_addr[4:0]] <= set_data; + + assign header_word = header_ram[state]; + + wire last_hdr_line = header_word[19]; + wire ip_chk = header_word[18]; + wire ip_len = header_word[17]; + wire udp_len = header_word[16]; + + // Protocol State Machine + reg [15:0] length; + wire [15:0] ip_length = length + 28; // IP HDR + UDP HDR + wire [15:0] udp_length = length + 8; // UDP HDR + + always @(posedge clk) + if(reset) + begin + state <= 0; + fast_path <= 0; + sof_o <= 0; + end + else + if(src_rdy_i & dst_rdy_i) + case(state) + 0 : + begin + fast_path <= datain[0]; + state <= 1; + end + 1 : + begin + length <= datain[15:0]; + sof_o <= 1; + if(fast_path) + state <= 2; + else + state <= 30; // Skip 1 word for alignment + end + 30 : + state <= 31; + 31 : + begin + sof_o <= 0; + if(flags_i[1]) // eop + state <= 0; + end + default : + begin + sof_o <= 0; + if(~last_hdr_line) + state <= state + 1; + else + state <= 31; + end + endcase // case (state) + + wire [15:0] checksum; + add_onescomp #(.WIDTH(16)) add_onescomp + (.A(header_word[15:0]),.B(ip_length),.SUM(checksum)); + + always @* + if(ip_chk) + //dataout_int <= header_word[15:0] ^ ip_length; + dataout_int <= 16'hFFFF ^ checksum; + else if(ip_len) + dataout_int <= ip_length; + else if(udp_len) + dataout_int <= udp_length; + else if(do_payload) + dataout_int <= datain[15:0]; + else + dataout_int <= header_word[15:0]; + +endmodule // prot_eng_tx diff --git a/usrp2/udp/prot_eng_tx_tb.v b/usrp2/udp/prot_eng_tx_tb.v new file mode 100644 index 000000000..e7ffeb5e1 --- /dev/null +++ b/usrp2/udp/prot_eng_tx_tb.v @@ -0,0 +1,167 @@ +module prot_eng_tx_tb(); + + localparam BASE = 128; + reg clk = 0; + reg rst = 1; + reg clear = 0; + initial #1000 rst = 0; + always #50 clk = ~clk; + + reg [31:0] f36_data; + reg [1:0] f36_occ; + reg f36_sof, f36_eof; + + wire [35:0] f36_in = {f36_occ,f36_eof,f36_sof,f36_data}; + reg src_rdy_f36i = 0; + reg [15:0] count; + + wire [35:0] casc_do; + wire [18:0] final_out, prot_out; + + wire src_rdy_final, dst_rdy_final, src_rdy_prot; + reg dst_rdy_prot =0; + + wire dst_rdy_f36o ; + fifo_long #(.WIDTH(36), .SIZE(4)) fifo_cascade36 + (.clk(clk),.reset(rst),.clear(clear), + .datain(f36_in),.src_rdy_i(src_rdy_f36i),.dst_rdy_o(dst_rdy_f36i), + .dataout(casc_do),.src_rdy_o(src_rdy_f36o),.dst_rdy_i(dst_rdy_f36o)); + + fifo36_to_fifo19 fifo_converter + (.clk(clk),.reset(rst),.clear(clear), + .f36_datain(casc_do),.f36_src_rdy_i(src_rdy_f36o),.f36_dst_rdy_o(dst_rdy_f36o), + .f19_dataout(final_out),.f19_src_rdy_o(src_rdy_final),.f19_dst_rdy_i(dst_rdy_final)); + + reg set_stb; + reg [7:0] set_addr; + reg [31:0] set_data; + + prot_eng_tx #(.BASE(BASE)) prot_eng_tx + (.clk(clk), .reset(rst), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .datain(final_out[18:0]),.src_rdy_i(src_rdy_final),.dst_rdy_o(dst_rdy_final), + .dataout(prot_out[18:0]),.src_rdy_o(src_rdy_prot),.dst_rdy_i(dst_rdy_prot)); + + reg [35:0] printer; + + task WriteSREG; + input [7:0] addr; + input [31:0] data; + + begin + @(posedge clk); + set_addr <= addr; + set_data <= data; + set_stb <= 1; + @(posedge clk); + set_stb <= 0; + end + endtask // WriteSREG + + task ReadFromFIFO36; + begin + $display("Read from FIFO36"); + #1 dst_rdy_prot <= 1; + while(~src_rdy_prot) + @(posedge clk); + while(1) + begin + while(~src_rdy_prot) + @(posedge clk); + $display("Read: %h",prot_out); + @(posedge clk); + end + end + endtask // ReadFromFIFO36 + + task PutPacketInFIFO36; + input [31:0] data_start; + input [31:0] data_len; + begin + count <= 4; + src_rdy_f36i <= 1; + f36_data <= 32'h0001_000c; + 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; + f36_data <= data_start; + while(~dst_rdy_f36i) + @(posedge clk); + @(posedge clk); + 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("prot_eng_tx_tb.vcd"); + initial $dumpvars(0,prot_eng_tx_tb); + + initial + begin + #10000; + @(posedge clk); + ReadFromFIFO36; + end + + initial + begin + @(negedge rst); + @(posedge clk); + WriteSREG(BASE, {12'b0, 4'h0, 16'h0000}); + WriteSREG(BASE+1, {12'b0, 4'h0, 16'h0000}); + WriteSREG(BASE+2, {12'b0, 4'h0, 16'hABCD}); + WriteSREG(BASE+3, {12'b0, 4'h0, 16'h1234}); + WriteSREG(BASE+4, {12'b0, 4'h8, 16'h5678}); + WriteSREG(BASE+5, {12'b0, 4'h0, 16'hABCD}); + WriteSREG(BASE+6, {12'b0, 4'h0, 16'hABCD}); + WriteSREG(BASE+7, {12'b0, 4'h0, 16'hABCD}); + WriteSREG(BASE+8, {12'b0, 4'h0, 16'hABCD}); + WriteSREG(BASE+9, {12'b0, 4'h0, 16'hABCD}); + @(posedge clk); + PutPacketInFIFO36(32'hA0B0C0D0,16); + @(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 // prot_eng_tx_tb diff --git a/usrp2/udp/udp_wrapper.v b/usrp2/udp/udp_wrapper.v new file mode 100644 index 000000000..f4c642615 --- /dev/null +++ b/usrp2/udp/udp_wrapper.v @@ -0,0 +1,92 @@ + +module udp_wrapper + #(parameter BASE=0) + (input clk, input reset, input clear, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input [18:0] rx_f19_data, input rx_f19_src_rdy_i, output rx_f19_dst_rdy_o, + output [18:0] tx_f19_data, output tx_f19_src_rdy_o, input tx_f19_dst_rdy_i, + + output [35:0] rx_f36_data, output rx_f36_src_rdy_o, input rx_f36_dst_rdy_i, + input [35:0] tx_f36_data, input tx_f36_src_rdy_i, output tx_f36_dst_rdy_o, + output [31:0] debug + ); + + wire tx_int1_src_rdy, tx_int1_dst_rdy; + wire [18:0] tx_int1_data; + + wire tx_int2_src_rdy, tx_int2_dst_rdy; + wire [18:0] tx_int2_data; + wire [31:0] debug_state; + + // TX side + fifo36_to_fifo19 fifo36_to_fifo19 + (.clk(clk), .reset(reset), .clear(clear), + .f36_datain(tx_f36_data), .f36_src_rdy_i(tx_f36_src_rdy_i), .f36_dst_rdy_o(tx_f36_dst_rdy_o), + .f19_dataout(tx_int1_data), .f19_src_rdy_o(tx_int1_src_rdy), .f19_dst_rdy_i(tx_int1_dst_rdy) ); + + fifo_short #(.WIDTH(19)) shortfifo19_a + (.clk(clk), .reset(reset), .clear(clear), + .datain(tx_int1_data), .src_rdy_i(tx_int1_src_rdy), .dst_rdy_o(tx_int1_dst_rdy), + .dataout(tx_int2_data), .src_rdy_o(tx_int2_src_rdy), .dst_rdy_i(tx_int2_dst_rdy), + .space(), .occupied() ); + + prot_eng_tx #(.BASE(BASE)) prot_eng_tx + (.clk(clk), .reset(reset), .clear(clear), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .datain(tx_int2_data), .src_rdy_i(tx_int2_src_rdy), .dst_rdy_o(tx_int2_dst_rdy), + .dataout(tx_f19_data), .src_rdy_o(tx_f19_src_rdy_o), .dst_rdy_i(tx_f19_dst_rdy_i) ); + + // RX side + wire rx_int1_src_rdy, rx_int1_dst_rdy; + wire [18:0] rx_int1_data; + + wire rx_int2_src_rdy, rx_int2_dst_rdy; + wire [18:0] rx_int2_data; + + //wire rx_int3_src_rdy, rx_int3_dst_rdy; + //wire [35:0] rx_int3_data; + +`ifdef USE_PROT_ENG + prot_eng_rx #(.BASE(BASE+32)) prot_eng_rx + (.clk(clk), .reset(reset), .clear(clear), + .datain(rx_f19_data), .src_rdy_i(rx_f19_src_rdy_i), .dst_rdy_o(rx_f19_dst_rdy_o), + .dataout(rx_int1_data), .src_rdy_o(rx_int1_src_rdy), .dst_rdy_i(rx_int1_dst_rdy) ); +`else + fifo19_rxrealign fifo19_rxrealign + (.clk(clk), .reset(reset), .clear(clear), + .datain(rx_f19_data), .src_rdy_i(rx_f19_src_rdy_i), .dst_rdy_o(rx_f19_dst_rdy_o), + .dataout(rx_int1_data), .src_rdy_o(rx_int1_src_rdy), .dst_rdy_i(rx_int1_dst_rdy) ); +`endif // !`ifdef USE_PROT_ENG + + fifo_short #(.WIDTH(19)) shortfifo19_b + (.clk(clk), .reset(reset), .clear(clear), + .datain(rx_int1_data), .src_rdy_i(rx_int1_src_rdy), .dst_rdy_o(rx_int1_dst_rdy), + .dataout(rx_int2_data), .src_rdy_o(rx_int2_src_rdy), .dst_rdy_i(rx_int2_dst_rdy), + .space(), .occupied() ); + + fifo19_to_fifo36 fifo19_to_fifo36 + (.clk(clk), .reset(reset), .clear(clear), + .f19_datain(rx_int2_data), .f19_src_rdy_i(rx_int2_src_rdy), .f19_dst_rdy_o(rx_int2_dst_rdy), + .f36_dataout(rx_f36_data), .f36_src_rdy_o(rx_f36_src_rdy_o), .f36_dst_rdy_i(rx_f36_dst_rdy_i), + .debug(debug_state)); + + /* + fifo_cascade #(.WIDTH(36),.SIZE(RXFIFOSIZE)) eth0_rxfifo + (.clk(clk), .reset(reset), .clear(clear), + .datain(rx_int3_data), .src_rdy_i(rx_int3_src_rdy), .dst_rdy_o(rx_int3_dst_rdy), + .dataout(rx_f36_data), .src_rdy_o(rx_f36_src_rdy_o), .dst_rdy_i(rx_f36_dst_rdy_i), + .space(), .occupied() ); +*/ + /* + assign debug = { { 1'b0, rx_f19_data[18:16], rx_f19_src_rdy_i, rx_f19_dst_rdy_o, rx_f36_src_rdy_o, rx_f36_dst_rdy_i }, + { 2'b0, rx_int1_src_rdy, rx_int1_dst_rdy, rx_int2_src_rdy, rx_int2_dst_rdy, rx_int3_src_rdy, rx_int3_dst_rdy}, + { rx_int3_data[35:32], rx_f36_data[35:32] }, + { debug_state[1:0], rx_int1_data[18:16], rx_int2_data[18:16] } }; + */ + + assign debug = { { 3'd0, tx_int1_src_rdy, tx_int1_dst_rdy, tx_int1_data[18:16] }, + { 3'd0, tx_int2_src_rdy, tx_int2_dst_rdy, tx_int2_data[18:16] }, + { tx_int2_data[15:8] }, + { tx_int2_data[7:0] } }; + +endmodule // udp_wrapper diff --git a/usrp2/vrt/.gitignore b/usrp2/vrt/.gitignore new file mode 100644 index 000000000..446b2daae --- /dev/null +++ b/usrp2/vrt/.gitignore @@ -0,0 +1,4 @@ +vita_rx_tb +vita_tx_tb +*.vcd +*.sav diff --git a/usrp2/vrt/vita_rx.build b/usrp2/vrt/vita_rx.build new file mode 100755 index 000000000..f6d2d75a3 --- /dev/null +++ b/usrp2/vrt/vita_rx.build @@ -0,0 +1 @@ +iverilog -Wimplict -Wportbind -y ../models -y . -y ../control_lib/ -y ../control_lib/newfifo -y ../coregen -y /opt/Xilinx/10.1/ISE/verilog/src/XilinxCoreLib -y /opt/Xilinx/10.1/ISE/verilog/src/unisims/ -y ../timing -o vita_rx_tb vita_rx_tb.v diff --git a/usrp2/vrt/vita_rx_control.v b/usrp2/vrt/vita_rx_control.v new file mode 100644 index 000000000..669b8299d --- /dev/null +++ b/usrp2/vrt/vita_rx_control.v @@ -0,0 +1,180 @@ + +module vita_rx_control + #(parameter BASE=0, + parameter WIDTH=32) + (input clk, input reset, input clear, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + input [63:0] vita_time, + output overrun, + + // To vita_rx_framer + output [4+64+WIDTH-1:0] sample_fifo_o, + output sample_fifo_src_rdy_o, + input sample_fifo_dst_rdy_i, + + // From DSP Core + input [WIDTH-1:0] sample, + output run, + input strobe, + + output [31:0] debug_rx + ); + + // FIXME add TX Interruption (halt, pause, continue) functionality + + wire [63:0] new_time; + wire [31:0] new_command; + wire sc_pre1, clear_int, clear_reg; + + assign clear_int = clear | clear_reg; + + wire [63:0] rcvtime_pre; + reg [63:0] rcvtime; + wire [29:0] numlines_pre; + wire send_imm_pre, chain_pre; + reg send_imm, chain; + wire full_ctrl, read_ctrl, empty_ctrl, write_ctrl; + reg sc_pre2; + wire [33:0] fifo_line; + reg [29:0] lines_left; + reg [2:0] ibs_state; + wire now, early, late; + wire sample_fifo_in_rdy; + + setting_reg #(.my_addr(BASE)) sr_cmd + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(new_command),.changed()); + + setting_reg #(.my_addr(BASE+1)) sr_time_h + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(new_time[63:32]),.changed()); + + setting_reg #(.my_addr(BASE+2)) sr_time_l + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(new_time[31:0]),.changed(sc_pre1)); + + setting_reg #(.my_addr(BASE+3)) sr_clear + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(),.changed(clear_reg)); + + // FIFO to store commands sent from the settings bus + always @(posedge clk) + sc_pre2 <= sc_pre1; + assign write_ctrl = sc_pre1 & ~sc_pre2; + + wire [4:0] command_queue_len; + shortfifo #(.WIDTH(96)) commandfifo + (.clk(clk),.rst(reset),.clear(clear_int), + .datain({new_command,new_time}), .write(write_ctrl&~full_ctrl), .full(full_ctrl), + .dataout({send_imm_pre,chain_pre,numlines_pre,rcvtime_pre}), + .read(read_ctrl), .empty(empty_ctrl), + .occupied(command_queue_len), .space() ); + + reg [33:0] pkt_fifo_line; + + localparam IBS_IDLE = 0; + localparam IBS_WAITING = 1; + localparam IBS_RUNNING = 2; + localparam IBS_OVERRUN = 4; + localparam IBS_BROKENCHAIN = 5; + localparam IBS_LATECMD = 6; + + wire signal_cmd_done = (lines_left == 1) & (~chain | (~empty_ctrl & (numlines_pre==0))); + wire signal_overrun = (ibs_state == IBS_OVERRUN); + wire signal_brokenchain = (ibs_state == IBS_BROKENCHAIN); + wire signal_latecmd = (ibs_state == IBS_LATECMD); + + // Buffer of samples for while we're writing the packet headers + wire [3:0] flags = {signal_overrun,signal_brokenchain,signal_latecmd,signal_cmd_done}; + + wire attempt_sample_write = ((run & strobe) | (ibs_state==IBS_OVERRUN) | + (ibs_state==IBS_BROKENCHAIN) | (ibs_state==IBS_LATECMD)); + + fifo_short #(.WIDTH(4+64+WIDTH)) rx_sample_fifo + (.clk(clk),.reset(reset),.clear(clear_int), + .datain({flags,vita_time,sample}), .src_rdy_i(attempt_sample_write), .dst_rdy_o(sample_fifo_in_rdy), + .dataout(sample_fifo_o), + .src_rdy_o(sample_fifo_src_rdy_o), .dst_rdy_i(sample_fifo_dst_rdy_i), + .space(), .occupied() ); + + // Inband Signalling State Machine + time_compare + time_compare (.time_now(vita_time), .trigger_time(rcvtime), .now(now), .early(early), .late(late)); + + wire too_late = late & ~send_imm; + wire go_now = now | send_imm; + wire full = ~sample_fifo_in_rdy; + + always @(posedge clk) + if(reset | clear_int) + begin + ibs_state <= IBS_IDLE; + lines_left <= 0; + rcvtime <= 0; + send_imm <= 0; + chain <= 0; + end + else + case(ibs_state) + IBS_IDLE : + if(~empty_ctrl) + begin + lines_left <= numlines_pre; + rcvtime <= rcvtime_pre; + ibs_state <= IBS_WAITING; + send_imm <= send_imm_pre; + chain <= chain_pre; + end + IBS_WAITING : + if(go_now) + ibs_state <= IBS_RUNNING; + else if(too_late) + ibs_state <= IBS_LATECMD; + IBS_RUNNING : + if(strobe) + if(full) + ibs_state <= IBS_OVERRUN; + else + begin + lines_left <= lines_left - 1; + if(lines_left == 1) + if(~chain) + ibs_state <= IBS_IDLE; + else if(empty_ctrl) + ibs_state <= IBS_BROKENCHAIN; + else + begin + lines_left <= numlines_pre; + rcvtime <= rcvtime_pre; + send_imm <= send_imm_pre; + chain <= chain_pre; + if(numlines_pre == 0) // If we are told to stop here + ibs_state <= IBS_IDLE; + else + ibs_state <= IBS_RUNNING; + end + end // else: !if(full) + IBS_OVERRUN : + if(sample_fifo_in_rdy) + ibs_state <= IBS_IDLE; + IBS_LATECMD : + if(sample_fifo_in_rdy) + ibs_state <= IBS_IDLE; + IBS_BROKENCHAIN : + if(sample_fifo_in_rdy) + ibs_state <= IBS_IDLE; + endcase // case(ibs_state) + + assign overrun = (ibs_state == IBS_OVERRUN); + assign run = (ibs_state == IBS_RUNNING); + + assign read_ctrl = ( (ibs_state == IBS_IDLE) | ((ibs_state == IBS_RUNNING) & strobe & ~full & (lines_left==1) & chain) ) + & ~empty_ctrl; + + assign debug_rx = { { ibs_state[2:0], command_queue_len }, + { 8'd0 }, + { go_now, too_late, run, strobe, read_ctrl, write_ctrl, full_ctrl, empty_ctrl }, + { 2'b0, overrun, chain_pre, sample_fifo_in_rdy, attempt_sample_write, sample_fifo_src_rdy_o,sample_fifo_dst_rdy_i} }; + +endmodule // rx_control diff --git a/usrp2/vrt/vita_rx_framer.v b/usrp2/vrt/vita_rx_framer.v new file mode 100644 index 000000000..f3a81664a --- /dev/null +++ b/usrp2/vrt/vita_rx_framer.v @@ -0,0 +1,199 @@ + +module vita_rx_framer + #(parameter BASE=0, + parameter MAXCHAN=1) + (input clk, input reset, input clear, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + // To FIFO interface of Buffer Pool + output [35:0] data_o, + input dst_rdy_i, + output src_rdy_o, + + // From vita_rx_control + input [4+64+(32*MAXCHAN)-1:0] sample_fifo_i, + input sample_fifo_src_rdy_i, + output sample_fifo_dst_rdy_o, + + // FIFO Levels + output [15:0] fifo_occupied, + output fifo_full, + output fifo_empty, + + output [31:0] debug_rx + ); + + localparam SAMP_WIDTH = 4+64+(32*MAXCHAN); + reg [3:0] sample_phase; + wire [3:0] numchan; + wire [3:0] flags_fifo_o = sample_fifo_i[SAMP_WIDTH-1:SAMP_WIDTH-4]; + wire [63:0] vita_time_fifo_o = sample_fifo_i[SAMP_WIDTH-5:SAMP_WIDTH-68]; + + reg [31:0] data_fifo_o; + + // The tools won't synthesize properly without this kludge because of the variable + // parameter length + + wire [127:0] FIXED_WIDTH_KLUDGE = sample_fifo_i; + always @* + case(sample_phase) + 4'd0 : data_fifo_o = FIXED_WIDTH_KLUDGE[31:0]; + 4'd1 : data_fifo_o = FIXED_WIDTH_KLUDGE[63:32]; + 4'd2 : data_fifo_o = FIXED_WIDTH_KLUDGE[95:64]; + 4'd3 : data_fifo_o = FIXED_WIDTH_KLUDGE[127:96]; + default : data_fifo_o = 32'hDEADBEEF; + endcase // case (sample_phase) + + wire clear_pkt_count, pkt_fifo_rdy, sample_fifo_in_rdy; + + wire [31:0] vita_header, vita_streamid, vita_trailer; + wire [15:0] samples_per_packet; + + reg [33:0] pkt_fifo_line; + reg [3:0] vita_state; + reg [15:0] sample_ctr; + reg [3:0] pkt_count; + + wire [15:0] vita_pkt_len = samples_per_packet + 6; + //wire [3:0] flags = {signal_overrun,signal_brokenchain,signal_latecmd,signal_cmd_done}; + + wire clear_reg; + wire clear_int = clear | clear_reg; + + setting_reg #(.my_addr(BASE+3)) sr_clear + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(),.changed(clear_reg)); + + setting_reg #(.my_addr(BASE+4)) sr_header + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(vita_header),.changed()); + + setting_reg #(.my_addr(BASE+5)) sr_streamid + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(vita_streamid),.changed(clear_pkt_count)); + + setting_reg #(.my_addr(BASE+6)) sr_trailer + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(vita_trailer),.changed()); + + setting_reg #(.my_addr(BASE+7)) sr_samples_per_pkt + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(samples_per_packet),.changed()); + + setting_reg #(.my_addr(BASE+8), .at_reset(1)) sr_numchan + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(numchan),.changed()); + + // Output FIFO for packetized data + localparam VITA_IDLE = 0; + localparam VITA_HEADER = 1; + localparam VITA_STREAMID = 2; + localparam VITA_SECS = 3; + localparam VITA_TICS = 4; + localparam VITA_TICS2 = 5; + localparam VITA_PAYLOAD = 6; + localparam VITA_TRAILER = 7; + localparam VITA_ERR_HEADER = 9; // All ERR at 4'b1000 or'ed with base + localparam VITA_ERR_STREAMID = 10; + localparam VITA_ERR_SECS = 11; + localparam VITA_ERR_TICS = 12; + localparam VITA_ERR_TICS2 = 13; + localparam VITA_ERR_PAYLOAD = 14; + localparam VITA_ERR_TRAILER = 15; + + always @(posedge clk) + if(reset | clear_pkt_count) + pkt_count <= 0; + else if((vita_state == VITA_TRAILER) & pkt_fifo_rdy) + pkt_count <= pkt_count + 1; + + always @* + case(vita_state) + VITA_HEADER, VITA_ERR_HEADER : pkt_fifo_line <= {2'b01,vita_header[31:20],pkt_count,vita_pkt_len}; + VITA_STREAMID, VITA_ERR_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid}; + VITA_SECS, VITA_ERR_SECS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]}; + VITA_TICS, VITA_ERR_TICS : pkt_fifo_line <= {2'b00,32'd0}; + VITA_TICS2, VITA_ERR_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]}; + VITA_PAYLOAD : pkt_fifo_line <= {2'b00,data_fifo_o}; + VITA_ERR_PAYLOAD : pkt_fifo_line <= {2'b00,28'd0,flags_fifo_o}; + VITA_TRAILER : pkt_fifo_line <= {2'b10,vita_trailer}; + VITA_ERR_TRAILER : pkt_fifo_line <= {2'b11,vita_trailer}; + default : pkt_fifo_line <= 34'h0_FFFF_FFFF; + endcase // case (vita_state) + + always @(posedge clk) + if(reset) + begin + vita_state <= VITA_IDLE; + sample_ctr <= 0; + sample_phase <= 0; + end + else + if(vita_state==VITA_IDLE) + begin + sample_ctr <= 1; + sample_phase <= 0; + if(sample_fifo_src_rdy_i) + if(|flags_fifo_o[3:1]) + vita_state <= VITA_ERR_HEADER; + else + vita_state <= VITA_HEADER; + end + else if(pkt_fifo_rdy) + case(vita_state) + VITA_PAYLOAD : + if(sample_fifo_src_rdy_i) + begin + if(sample_phase == (numchan-4'd1)) + begin + sample_phase <= 0; + sample_ctr <= sample_ctr + 1; + if(sample_ctr == samples_per_packet) + vita_state <= VITA_TRAILER; + if(|flags_fifo_o) // end early if any flag is set + vita_state <= VITA_TRAILER; + end + else + sample_phase <= sample_phase + 1; + end + VITA_TRAILER, VITA_ERR_TRAILER : + vita_state <= VITA_IDLE; + default : + vita_state <= vita_state + 1; + endcase // case (vita_state) + + reg req_write_pkt_fifo; + always @* + case(vita_state) + VITA_IDLE : + req_write_pkt_fifo <= 0; + VITA_HEADER, VITA_STREAMID, VITA_SECS, VITA_TICS, VITA_TICS2, VITA_TRAILER : + req_write_pkt_fifo <= 1; + VITA_PAYLOAD : + // Write if sample ready and no error flags + req_write_pkt_fifo <= (sample_fifo_src_rdy_i & ~|flags_fifo_o[3:1]); + VITA_ERR_HEADER, VITA_ERR_STREAMID, VITA_ERR_SECS, VITA_ERR_TICS, VITA_ERR_TICS2, VITA_ERR_PAYLOAD, VITA_ERR_TRAILER : + req_write_pkt_fifo <= 1; + default : + req_write_pkt_fifo <= 0; + endcase // case (vita_state) + + //wire req_write_pkt_fifo = (vita_state != VITA_IDLE) & (sample_fifo_src_rdy_i | (vita_state != VITA_PAYLOAD)); + + // Short FIFO to buffer between us and the FIFOs outside + fifo_short #(.WIDTH(34)) rx_pkt_fifo + (.clk(clk), .reset(reset), .clear(clear_int), + .datain(pkt_fifo_line), .src_rdy_i(req_write_pkt_fifo), .dst_rdy_o(pkt_fifo_rdy), + .dataout(data_o[33:0]), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i), + .space(),.occupied(fifo_occupied[4:0]) ); + assign fifo_occupied[15:5] = 0; + assign data_o[35:34] = 2'b00; // Always write full lines + assign sample_fifo_dst_rdy_o = pkt_fifo_rdy & + ( ((vita_state==VITA_PAYLOAD) & + (sample_phase == (numchan-4'd1)) & + ~|flags_fifo_o[3:1]) | + (vita_state==VITA_ERR_TRAILER)); + + assign debug_rx = vita_state; + +endmodule // rx_control diff --git a/usrp2/vrt/vita_rx_tb.v b/usrp2/vrt/vita_rx_tb.v new file mode 100644 index 000000000..b4fda9622 --- /dev/null +++ b/usrp2/vrt/vita_rx_tb.v @@ -0,0 +1,213 @@ + + +module vita_rx_tb; + + localparam DECIM = 8'd4; + localparam MAXCHAN=4; + localparam NUMCHAN=4; + + reg clk = 0; + reg reset = 1; + + initial #1000 reset = 0; + always #50 clk = ~clk; + + initial $dumpfile("vita_rx_tb.vcd"); + initial $dumpvars(0,vita_rx_tb); + + wire [(MAXCHAN*32)-1:0] sample; + wire strobe, run; + wire [35:0] data_o; + wire src_rdy; + reg dst_rdy = 1; + wire [63:0] vita_time; + + reg set_stb = 0; + reg [7:0] set_addr; + reg [31:0] set_data; + wire set_stb_dsp; + wire [7:0] set_addr_dsp; + wire [31:0] set_data_dsp; + + /* + settings_bus_crossclock settings_bus_xclk_dsp + (.clk_i(clk), .rst_i(reset), .set_stb_i(set_stb), .set_addr_i(set_addr), .set_data_i(set_data), + .clk_o(clk), .rst_o(reset), .set_stb_o(set_stb_dsp), .set_addr_o(set_addr_dsp), .set_data_o(set_data_dsp)); + */ + + wire sample_dst_rdy, sample_src_rdy; + //wire [99:0] sample_data_o; + wire [64+4+(MAXCHAN*32)-1:0] sample_data_o; + + vita_rx_control #(.BASE(0), .WIDTH(32*MAXCHAN)) vita_rx_control + (.clk(clk), .reset(reset), .clear(0), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .vita_time(vita_time), .overrun(overrun), + .sample_fifo_o(sample_data_o), .sample_fifo_dst_rdy_i(sample_dst_rdy), .sample_fifo_src_rdy_o(sample_src_rdy), + .sample(sample), .run(run), .strobe(strobe)); + + vita_rx_framer #(.BASE(0), .MAXCHAN(MAXCHAN)) vita_rx_framer + (.clk(clk), .reset(reset), .clear(0), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .data_o(data_o), .dst_rdy_i(dst_rdy), .src_rdy_o(src_rdy), + .sample_fifo_i(sample_data_o), .sample_fifo_dst_rdy_o(sample_dst_rdy), .sample_fifo_src_rdy_i(sample_src_rdy), + .fifo_occupied(), .fifo_full(), .fifo_empty() ); + + rx_dsp_model rx_dsp_model + (.clk(clk), .reset(reset), .run(run), .decim(DECIM), .strobe(strobe), .sample(sample[31:0])); + + generate + if(MAXCHAN>1) + assign sample[(MAXCHAN*32)-1:32] = 0; + endgenerate + + time_64bit #(.TICKS_PER_SEC(120000000), .BASE(0)) time_64bit + (.clk(clk), .rst(reset), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .pps(0), .vita_time(vita_time)); + + always @(posedge clk) + if(src_rdy & dst_rdy) + begin + if(data_o[32] & ~data_o[33]) + begin + $display("RX-PKT-START %d",$time); + $display(" RX-PKT-DAT %x",data_o[31:0]); + end + else if(data_o[32] & data_o[33]) + begin + $display(" RX-PKT-DAT %x -- With ERR",data_o[31:0]); + $display("RX-PKT-ERR %d",$time); + end + else if(~data_o[32] & data_o[33]) + begin + $display(" RX-PKT-DAT %x",data_o[31:0]); + $display("RX-PKT-END %d",$time); + end + else + $display(" RX-PKT DAT %x",data_o[31:0]); + end + + initial + begin + @(negedge reset); + @(posedge clk); + write_setting(4,32'hDEADBEEF); // VITA header + write_setting(5,32'hF00D1234); // VITA streamid + write_setting(6,32'h98765432); // VITA trailer + write_setting(7,8); // Samples per VITA packet + write_setting(8,NUMCHAN); // Samples per VITA packet + queue_rx_cmd(1,0,8,32'h0,32'h0); // send imm, single packet + queue_rx_cmd(1,0,16,32'h0,32'h0); // send imm, 2 packets worth + queue_rx_cmd(1,0,7,32'h0,32'h0); // send imm, 1 short packet worth + queue_rx_cmd(1,0,9,32'h0,32'h0); // send imm, just longer than 1 packet + + queue_rx_cmd(1,1,16,32'h0,32'h0); // chained + queue_rx_cmd(0,0,8,32'h0,32'h0); // 2nd in chain + + queue_rx_cmd(1,1,17,32'h0,32'h0); // chained, odd length + queue_rx_cmd(0,0,9,32'h0,32'h0); // 2nd in chain, also odd length + + queue_rx_cmd(0,0,8,32'h0,32'h340); // send at, on time + queue_rx_cmd(0,0,8,32'h0,32'h100); // send at, but late + + queue_rx_cmd(1,1,8,32'h0,32'h0); // chained, but break chain + #100000; + $display("\nEnd chain with zero samples, shouldn't error\n"); + queue_rx_cmd(1,1,8,32'h0,32'h0); // chained + queue_rx_cmd(0,0,0,32'h0,32'h0); // end chain with zero samples, should keep us out of error + #100000; + + $display("\nEnd chain with zero samples on odd-length, shouldn't error\n"); + queue_rx_cmd(1,1,14,32'h0,32'h0); // chained + queue_rx_cmd(0,0,0,32'h0,32'h0); // end chain with zero samples, should keep us out of error + #100000; + $display("Should have gotten 14 samples and EOF by now\n"); + + queue_rx_cmd(1,1,9,32'h0,32'h0); // chained, but break chain, odd length + #100000; + dst_rdy <= 0; // stop pulling out of fifo so we can get an overrun + queue_rx_cmd(1,0,100,32'h0,32'h0); // long enough to fill the fifos + queue_rx_cmd(1,0,5,32'h0,32'h0); // this command waits until the previous error packet is sent + #100000; + dst_rdy <= 1; // restart the reads so we can see what we got + #100000; + dst_rdy <= 0; // stop pulling out of fifo so we can get an overrun + queue_rx_cmd(1,1,100,32'h0,32'h0); // long enough to fill the fifos + //queue_rx_cmd(1,0,5,32'h0,32'h0); // this command waits until the previous error packet is sent + #100000; + @(posedge clk); + dst_rdy <= 1; + + #100000 $finish; + end + + task write_setting; + input [7:0] addr; + input [31:0] data; + begin + set_stb <= 0; + @(posedge clk); + set_addr <= addr; + set_data <= data; + set_stb <= 1; + @(posedge clk); + set_stb <= 0; + end + endtask // write_setting + + task queue_rx_cmd; + input send_imm; + input chain; + input [29:0] lines; + input [31:0] secs; + input [31:0] tics; + begin + write_setting(0,{send_imm,chain,lines}); + write_setting(1,secs); + write_setting(2,tics); + end + endtask // queue_rx_cmd + +endmodule // rx_control_tb + +module rx_dsp_model + (input clk, input reset, + input run, + input [7:0] decim, + output strobe, + output [31:0] sample); + + reg [15:0] pktnum = 0; + reg [15:0] counter = 0; + + reg run_d1; + always @(posedge clk) run_d1 <= run; + + always @(posedge clk) + if(run & ~run_d1) + begin + counter <= 0; + pktnum <= pktnum + 1; + end + else if(run & strobe) + counter <= counter + 1; + + assign sample = {pktnum,counter}; + + reg [7:0] stb_ctr = 0; + + always @(posedge clk) + if(reset) + stb_ctr <= 0; + else if(run & ~run_d1) + stb_ctr <= 1; + else if(run) + if(stb_ctr == decim-1) + stb_ctr <= 0; + else + stb_ctr <= stb_ctr + 1; + + assign strobe = stb_ctr == decim-1; + +endmodule // rx_dsp_model diff --git a/usrp2/vrt/vita_tx.build b/usrp2/vrt/vita_tx.build new file mode 100755 index 000000000..902929c08 --- /dev/null +++ b/usrp2/vrt/vita_tx.build @@ -0,0 +1 @@ +iverilog -Wimplict -Wportbind -y ../sdr_lib -y ../models -y . -y ../control_lib/ -y ../control_lib/newfifo -y ../coregen -y /opt/Xilinx/10.1/ISE/verilog/src/XilinxCoreLib -y /opt/Xilinx/10.1/ISE/verilog/src/unisims/ -y ../timing -o vita_tx_tb vita_tx_tb.v diff --git a/usrp2/vrt/vita_tx_control.v b/usrp2/vrt/vita_tx_control.v new file mode 100644 index 000000000..bffc64e52 --- /dev/null +++ b/usrp2/vrt/vita_tx_control.v @@ -0,0 +1,98 @@ + +module vita_tx_control + #(parameter BASE=0, + parameter WIDTH=32) + (input clk, input reset, input clear, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + input [63:0] vita_time, + output underrun, + + // From vita_tx_deframer + input [4+64+WIDTH-1:0] sample_fifo_i, + input sample_fifo_src_rdy_i, + output sample_fifo_dst_rdy_o, + + // To DSP Core + output [WIDTH-1:0] sample, + output run, + input strobe, + + output [31:0] debug + ); + + assign sample = sample_fifo_i[4+64+WIDTH-1:4+64]; + + wire [63:0] send_time = sample_fifo_i[63:0]; + wire eop = sample_fifo_i[64]; + wire eob = sample_fifo_i[65]; + wire sob = sample_fifo_i[66]; + wire send_at = sample_fifo_i[67]; + wire now, early, late, too_early; + + // FIXME ignore too_early for now for timing reasons + assign too_early = 0; + time_compare + time_compare (.time_now(vita_time), .trigger_time(send_time), .now(now), .early(early), + .late(late), .too_early()); +// .late(late), .too_early(too_early)); + + localparam IBS_IDLE = 0; + localparam IBS_RUN = 1; // FIXME do we need this? + localparam IBS_CONT_BURST = 2; + localparam IBS_UNDERRUN = 3; + localparam IBS_UNDERRUN_DONE = 4; + + reg [2:0] ibs_state; + + wire clear_state; + setting_reg #(.my_addr(BASE+1)) sr + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(),.changed(clear_state)); + + always @(posedge clk) + if(reset | clear_state) + ibs_state <= 0; + else + case(ibs_state) + IBS_IDLE : + if(sample_fifo_src_rdy_i) + if(~send_at | now) + ibs_state <= IBS_RUN; + else if(late | too_early) + ibs_state <= IBS_UNDERRUN; + + IBS_RUN : + if(strobe) + if(~sample_fifo_src_rdy_i) + ibs_state <= IBS_UNDERRUN; + else if(eop) + if(eob) + ibs_state <= IBS_IDLE; + else + ibs_state <= IBS_CONT_BURST; + + IBS_CONT_BURST : + if(strobe) + ibs_state <= IBS_UNDERRUN_DONE; + else if(sample_fifo_src_rdy_i) + ibs_state <= IBS_RUN; + + IBS_UNDERRUN : + if(sample_fifo_src_rdy_i & eop) + ibs_state <= IBS_UNDERRUN_DONE; + + IBS_UNDERRUN_DONE : + ; + endcase // case (ibs_state) + + assign sample_fifo_dst_rdy_o = (ibs_state == IBS_UNDERRUN) | (strobe & (ibs_state == IBS_RUN)); // FIXME also cleanout + assign run = (ibs_state == IBS_RUN) | (ibs_state == IBS_CONT_BURST); + assign underrun = (ibs_state == IBS_UNDERRUN_DONE); + + assign debug = { { now,early,late,too_early,eop,eob,sob,send_at }, + { sample_fifo_src_rdy_i, sample_fifo_dst_rdy_o, strobe, run, underrun, ibs_state[2:0] }, + { 8'b0 }, + { 8'b0 } }; + +endmodule // vita_tx_control diff --git a/usrp2/vrt/vita_tx_deframer.v b/usrp2/vrt/vita_tx_deframer.v new file mode 100644 index 000000000..220d3b061 --- /dev/null +++ b/usrp2/vrt/vita_tx_deframer.v @@ -0,0 +1,187 @@ + +module vita_tx_deframer + #(parameter BASE=0, + parameter MAXCHAN=1) + (input clk, input reset, input clear, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + // To FIFO interface of Buffer Pool + input [35:0] data_i, + input src_rdy_i, + output dst_rdy_o, + + output [4+64+(32*MAXCHAN)-1:0] sample_fifo_o, + output sample_fifo_src_rdy_o, + input sample_fifo_dst_rdy_i, + + // FIFO Levels + output [15:0] fifo_occupied, + output fifo_full, + output fifo_empty, + output [31:0] debug + ); + + wire [1:0] numchan; + setting_reg #(.my_addr(BASE), .at_reset(0)) sr_numchan + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(numchan),.changed()); + + reg [3:0] vita_state; + wire has_streamid, has_classid, has_secs, has_tics, has_trailer; + assign has_streamid = (data_i[31:28]==4'b0001); + assign has_classid = data_i[27]; + assign has_secs = ~(data_i[23:22]==2'b00); + assign has_tics = ~(data_i[21:20]==2'b00); + assign has_trailer = data_i[26]; + assign is_sob = data_i[25]; + assign is_eob = data_i[24]; + wire eof = data_i[33]; + + reg has_streamid_reg, has_classid_reg, has_secs_reg, has_tics_reg; + reg has_trailer_reg, is_sob_reg, is_eob_reg; + + reg [15:0] pkt_len; + reg [1:0] vector_phase; + wire line_done; + + // Output FIFO for packetized data + localparam VITA_HEADER = 0; + localparam VITA_STREAMID = 1; + localparam VITA_CLASSID = 2; + localparam VITA_CLASSID2 = 3; + localparam VITA_SECS = 4; + localparam VITA_TICS = 5; + localparam VITA_TICS2 = 6; + localparam VITA_PAYLOAD = 7; + localparam VITA_STORE = 8; + localparam VITA_TRAILER = 9; + + wire [15:0] hdr_len = 2 + has_streamid_reg + has_classid_reg + has_classid_reg + has_secs_reg + + has_tics_reg + has_tics_reg + has_trailer_reg; + + wire eop = eof | (pkt_len==hdr_len); // FIXME would ignoring eof allow larger VITA packets? + wire fifo_space; + + always @(posedge clk) + if(reset | clear) + begin + vita_state <= VITA_HEADER; + {has_streamid_reg, has_classid_reg, has_secs_reg, has_tics_reg, has_trailer_reg, is_sob_reg, is_eob_reg} + <= 0; + end + else + if((vita_state == VITA_STORE) & fifo_space) + if(eop) + if(has_trailer_reg) + vita_state <= VITA_TRAILER; + else + vita_state <= VITA_HEADER; + else + begin + vita_state <= VITA_PAYLOAD; + pkt_len <= pkt_len - 1; + end + else if(src_rdy_i) + case(vita_state) + VITA_HEADER : + begin + {has_streamid_reg, has_classid_reg, has_secs_reg, has_tics_reg, has_trailer_reg, is_sob_reg, is_eob_reg} + <= {has_streamid, has_classid, has_secs, has_tics, has_trailer, is_sob, is_eob}; + pkt_len <= data_i[15:0]; + vector_phase <= 0; + if(has_streamid) + vita_state <= VITA_STREAMID; + else if(has_classid) + vita_state <= VITA_CLASSID; + else if(has_secs) + vita_state <= VITA_SECS; + else if(has_tics) + vita_state <= VITA_TICS; + else + vita_state <= VITA_PAYLOAD; + end // case: VITA_HEADER + VITA_STREAMID : + if(has_classid_reg) + vita_state <= VITA_CLASSID; + else if(has_secs_reg) + vita_state <= VITA_SECS; + else if(has_tics_reg) + vita_state <= VITA_TICS; + else + vita_state <= VITA_PAYLOAD; + VITA_CLASSID : + vita_state <= VITA_CLASSID2; + VITA_CLASSID2 : + if(has_secs_reg) + vita_state <= VITA_SECS; + else if(has_tics_reg) + vita_state <= VITA_TICS; + else + vita_state <= VITA_PAYLOAD; + VITA_SECS : + if(has_tics_reg) + vita_state <= VITA_TICS; + else + vita_state <= VITA_PAYLOAD; + VITA_TICS : + vita_state <= VITA_TICS2; + VITA_TICS2 : + vita_state <= VITA_PAYLOAD; + VITA_PAYLOAD : + if(line_done) + begin + vector_phase <= 0; + vita_state <= VITA_STORE; + end + else + vector_phase <= vector_phase + 1; + VITA_TRAILER : + vita_state <= VITA_HEADER; + VITA_STORE : + ; + default : + vita_state <= VITA_HEADER; + endcase // case (vita_state) + + assign line_done = (vector_phase == numchan); + + wire [4+64+32*MAXCHAN-1:0] fifo_i; + reg [63:0] send_time; + reg [31:0] sample_a, sample_b, sample_c, sample_d; + + always @(posedge clk) + case(vita_state) + VITA_SECS : + send_time[63:32] <= data_i[31:0]; + VITA_TICS2 : + send_time[31:0] <= data_i[31:0]; + VITA_STORE, VITA_HEADER : + send_time[63:0] <= 64'd0; + endcase // case (vita_state) + + always @(posedge clk) + if(vita_state == VITA_PAYLOAD) + case(vector_phase) + 0: sample_a <= data_i[31:0]; + 1: sample_b <= data_i[31:0]; + 2: sample_c <= data_i[31:0]; + 3: sample_d <= data_i[31:0]; + endcase // case (vector_phase) + + wire store = (vita_state == VITA_STORE); + fifo_short #(.WIDTH(4+64+32*MAXCHAN)) short_tx_q + (.clk(clk), .reset(reset), .clear(clear), + .datain(fifo_i), .src_rdy_i(store), .dst_rdy_o(fifo_space), + .dataout(sample_fifo_o), .src_rdy_o(sample_fifo_src_rdy_o), .dst_rdy_i(sample_fifo_dst_rdy_i) ); + + // sob, eob, has_secs (send_at) ignored on all lines except first + assign fifo_i = {sample_d,sample_c,sample_b,sample_a,has_secs_reg,is_sob_reg,is_eob_reg,eop,send_time}; + + assign dst_rdy_o = ~(vita_state == VITA_PAYLOAD) & ~((vita_state==VITA_STORE)& ~fifo_space) ; + + assign debug = { { 8'b0 }, + { 8'b0 }, + { eof, line_done, store, fifo_space, src_rdy_i, dst_rdy_o, vector_phase[1:0] }, + { has_secs_reg, is_sob_reg, is_eob_reg, eop, vita_state[3:0] } }; + +endmodule // vita_tx_deframer diff --git a/usrp2/vrt/vita_tx_tb.v b/usrp2/vrt/vita_tx_tb.v new file mode 100644 index 000000000..0223d6850 --- /dev/null +++ b/usrp2/vrt/vita_tx_tb.v @@ -0,0 +1,164 @@ + + +module vita_tx_tb; + + localparam DECIM = 8'd4; + localparam INTERP = 8'd4; + + localparam MAXCHAN=1; + localparam NUMCHAN=1; + + reg clk = 0; + reg reset = 1; + + initial #1000 reset = 0; + always #50 clk = ~clk; + + initial $dumpfile("vita_tx_tb.vcd"); + initial $dumpvars(0,vita_tx_tb); + + wire [(MAXCHAN*32)-1:0] sample, sample_tx; + wire strobe, run; + reg [35:0] data_o = 36'h0; + reg src_rdy = 0; + wire dst_rdy; + + wire [63:0] vita_time; + + reg set_stb = 0; + reg [7:0] set_addr; + reg [31:0] set_data; + wire set_stb_dsp; + wire [7:0] set_addr_dsp; + wire [31:0] set_data_dsp; + + wire sample_dst_rdy, sample_src_rdy; + wire [64+4+(MAXCHAN*32)-1:0] sample_data_o, sample_data_tx; + + time_64bit #(.TICKS_PER_SEC(100000000), .BASE(0)) time_64bit + (.clk(clk), .rst(reset), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .pps(0), .vita_time(vita_time)); + + wire [35:0] data_tx; + wire src_rdy_tx, dst_rdy_tx; + wire sample_dst_rdy_tx, sample_src_rdy_tx; + + fifo_long #(.WIDTH(36)) fifo_short + (.clk(clk), .reset(reset), .clear(0), + .datain(data_o), .src_rdy_i(src_rdy), .dst_rdy_o(dst_rdy), + .dataout(data_tx), .src_rdy_o(src_rdy_tx), .dst_rdy_i(dst_rdy_tx)); + + vita_tx_deframer #(.BASE(16), .MAXCHAN(MAXCHAN)) vita_tx_deframer + (.clk(clk), .reset(reset), .clear(0), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .data_i(data_tx), .dst_rdy_o(dst_rdy_tx), .src_rdy_i(src_rdy_tx), + .sample_fifo_o(sample_data_tx), + .sample_fifo_dst_rdy_i(sample_dst_rdy_tx), .sample_fifo_src_rdy_o(sample_src_rdy_tx), + .fifo_occupied(), .fifo_full(), .fifo_empty() ); + + vita_tx_control #(.BASE(16), .WIDTH(MAXCHAN*32)) vita_tx_control + (.clk(clk), .reset(reset), .clear(0), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .vita_time(vita_time), .underrun(underrun), + .sample_fifo_i(sample_data_tx), + .sample_fifo_dst_rdy_o(sample_dst_rdy_tx), .sample_fifo_src_rdy_i(sample_src_rdy_tx), + .sample(sample_tx), .run(run_tx), .strobe(strobe_tx)); + + tx_dsp_model tx_dsp_model + (.clk(clk), .reset(reset), .run(run_tx), .interp(INTERP), .strobe(strobe_tx), .sample(sample_tx[31:0] )); + + task write_setting; + input [7:0] addr; + input [31:0] data; + begin + set_stb <= 0; + @(posedge clk); + set_addr <= addr; + set_data <= data; + set_stb <= 1; + @(posedge clk); + set_stb <= 0; + end + endtask // write_setting + + initial + begin + @(negedge reset); + @(posedge clk); + write_setting(4,32'h14900008); // VITA header + write_setting(5,32'hF00D1234); // VITA streamid + write_setting(6,32'h98765432); // VITA trailer + write_setting(7,8); // Samples per VITA packet + write_setting(8,NUMCHAN); // Samples per VITA packet + #10000; + queue_vita_packets(32'h300, 106, 32'hF00D_1234, 32'h55AA_AA55); + //queue_vita_packets(32'h300, 6, 32'hF00D_1234, 32'h0); + queue_vita_packets(32'h600, 9, 32'h9876_ABCD, 32'h0); + + #300000 $finish; + end + + task queue_vita_packets; + input [31:0] sendtime; + input [15:0] samples; + input [15:0] word; + input [31:0] trailer; + + reg [15:0] i; + + begin + @(posedge clk); + src_rdy <= 1; + data_o <= {4'b0001,4'h1,1'b0,|trailer,2'h3,8'hF0,(16'd5+samples+|trailer)}; // header + @(posedge clk); + data_o <= {4'b0000,32'h0}; // streamid + @(posedge clk); + data_o <= {4'b0000,32'h0}; // SECS + @(posedge clk); + data_o <= {4'b0000,32'h0}; // TICS + @(posedge clk); + data_o <= {4'b0000,sendtime}; // TICS + @(posedge clk); + + for(i=0;i<samples-1;i=i+1) + begin + data_o <= {4'b0000,i,word}; // Payload + @(posedge clk); + end + if(trailer==0) + begin + data_o <= {4'b0010,i,16'hBEEF}; // Last Payload + @(posedge clk); + end + else + begin + data_o <= {4'b0000,i,16'hBEEF}; // Last Payload + @(posedge clk); + data_o <= {4'b0010,trailer}; // Last Payload + @(posedge clk); + end + src_rdy <= 0; + @(posedge clk); + + end + endtask // queue_vita_packets + +endmodule // vita_tx_tb + + +module tx_dsp_model + (input clk, input reset, + input run, + input [7:0] interp, + output strobe, + input [31:0] sample); + + cic_strober strober(.clock(clk), .reset(reset), .enable(run), .rate(interp), .strobe_fast(1), .strobe_slow(strobe)); + + always @(posedge clk) + if(strobe) + $display("Time %d, Sent Sample %x",$time,sample); + + +endmodule // tx_dsp_model |