diff options
author | Martin Braun <martin.braun@ettus.com> | 2020-01-23 16:10:22 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2020-01-28 09:35:36 -0800 |
commit | bafa9d95453387814ef25e6b6256ba8db2df612f (patch) | |
tree | 39ba24b5b67072d354775272e687796bb511848d /fpga/usrp2/vrt | |
parent | 3075b981503002df3115d5f1d0b97d2619ba30f2 (diff) | |
download | uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.gz uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.bz2 uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.zip |
Merge FPGA repository back into UHD repository
The FPGA codebase was removed from the UHD repository in 2014 to reduce
the size of the repository. However, over the last half-decade, the
split between the repositories has proven more burdensome than it has
been helpful. By merging the FPGA code back, it will be possible to
create atomic commits that touch both FPGA and UHD codebases. Continuous
integration testing is also simplified by merging the repositories,
because it was previously difficult to automatically derive the correct
UHD branch when testing a feature branch on the FPGA repository.
This commit also updates the license files and paths therein.
We are therefore merging the repositories again. Future development for
FPGA code will happen in the same repository as the UHD host code and
MPM code.
== Original Codebase and Rebasing ==
The original FPGA repository will be hosted for the foreseeable future
at its original local location: https://github.com/EttusResearch/fpga/
It can be used for bisecting, reference, and a more detailed history.
The final commit from said repository to be merged here is
05003794e2da61cabf64dd278c45685a7abad7ec. This commit is tagged as
v4.0.0.0-pre-uhd-merge.
If you have changes in the FPGA repository that you want to rebase onto
the UHD repository, simply run the following commands:
- Create a directory to store patches (this should be an empty
directory):
mkdir ~/patches
- Now make sure that your FPGA codebase is based on the same state as
the code that was merged:
cd src/fpga # Or wherever your FPGA code is stored
git rebase v4.0.0.0-pre-uhd-merge
Note: The rebase command may look slightly different depending on what
exactly you're trying to rebase.
- Create a patch set for your changes versus v4.0.0.0-pre-uhd-merge:
git format-patch v4.0.0.0-pre-uhd-merge -o ~/patches
Note: Make sure that only patches are stored in your output directory.
It should otherwise be empty. Make sure that you picked the correct
range of commits, and only commits you wanted to rebase were exported
as patch files.
- Go to the UHD repository and apply the patches:
cd src/uhd # Or wherever your UHD repository is stored
git am --directory fpga ~/patches/*
rm -rf ~/patches # This is for cleanup
== Contributors ==
The following people have contributed mainly to these files (this list
is not complete):
Co-authored-by: Alex Williams <alex.williams@ni.com>
Co-authored-by: Andrej Rode <andrej.rode@ettus.com>
Co-authored-by: Ashish Chaudhari <ashish@ettus.com>
Co-authored-by: Ben Hilburn <ben.hilburn@ettus.com>
Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Derek Kozel <derek.kozel@ettus.com>
Co-authored-by: EJ Kreinar <ej@he360.com>
Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com>
Co-authored-by: Ian Buckley <ian.buckley@gmail.com>
Co-authored-by: Jörg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Jon Kiser <jon.kiser@ni.com>
Co-authored-by: Josh Blum <josh@joshknows.com>
Co-authored-by: Jonathon Pendlum <jonathan.pendlum@ettus.com>
Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Matt Ettus <matt@ettus.com>
Co-authored-by: Michael West <michael.west@ettus.com>
Co-authored-by: Moritz Fischer <moritz.fischer@ettus.com>
Co-authored-by: Nick Foster <nick@ettus.com>
Co-authored-by: Nicolas Cuervo <nicolas.cuervo@ettus.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Paul David <paul.david@ettus.com>
Co-authored-by: Ryan Marlow <ryan.marlow@ettus.com>
Co-authored-by: Sugandha Gupta <sugandha.gupta@ettus.com>
Co-authored-by: Sylvain Munaut <tnt@246tNt.com>
Co-authored-by: Trung Tran <trung.tran@ettus.com>
Co-authored-by: Vidush Vishwanath <vidush.vishwanath@ettus.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>
Diffstat (limited to 'fpga/usrp2/vrt')
-rw-r--r-- | fpga/usrp2/vrt/.gitignore | 4 | ||||
-rw-r--r-- | fpga/usrp2/vrt/Makefile.srcs | 20 | ||||
-rw-r--r-- | fpga/usrp2/vrt/gen_context_pkt.v | 106 | ||||
-rw-r--r-- | fpga/usrp2/vrt/trigger_context_pkt.v | 69 | ||||
-rw-r--r-- | fpga/usrp2/vrt/vita_packet_demux36.v | 102 | ||||
-rw-r--r-- | fpga/usrp2/vrt/vita_pkt_gen.v | 59 | ||||
-rwxr-xr-x | fpga/usrp2/vrt/vita_rx.build | 1 | ||||
-rw-r--r-- | fpga/usrp2/vrt/vita_rx_chain.v | 114 | ||||
-rw-r--r-- | fpga/usrp2/vrt/vita_rx_control.v | 231 | ||||
-rw-r--r-- | fpga/usrp2/vrt/vita_rx_engine_glue.v | 95 | ||||
-rw-r--r-- | fpga/usrp2/vrt/vita_rx_framer.v | 224 | ||||
-rw-r--r-- | fpga/usrp2/vrt/vita_rx_tb.v | 246 | ||||
-rwxr-xr-x | fpga/usrp2/vrt/vita_tx.build | 1 | ||||
-rw-r--r-- | fpga/usrp2/vrt/vita_tx_chain.v | 162 | ||||
-rw-r--r-- | fpga/usrp2/vrt/vita_tx_control.v | 238 | ||||
-rw-r--r-- | fpga/usrp2/vrt/vita_tx_deframer.v | 261 | ||||
-rw-r--r-- | fpga/usrp2/vrt/vita_tx_engine_glue.v | 99 | ||||
-rw-r--r-- | fpga/usrp2/vrt/vita_tx_tb.v | 193 |
18 files changed, 2225 insertions, 0 deletions
diff --git a/fpga/usrp2/vrt/.gitignore b/fpga/usrp2/vrt/.gitignore new file mode 100644 index 000000000..446b2daae --- /dev/null +++ b/fpga/usrp2/vrt/.gitignore @@ -0,0 +1,4 @@ +vita_rx_tb +vita_tx_tb +*.vcd +*.sav diff --git a/fpga/usrp2/vrt/Makefile.srcs b/fpga/usrp2/vrt/Makefile.srcs new file mode 100644 index 000000000..84ba5dc29 --- /dev/null +++ b/fpga/usrp2/vrt/Makefile.srcs @@ -0,0 +1,20 @@ +# +# Copyright 2010 Ettus Research LLC +# + +################################################## +# VRT Sources +################################################## +VRT_SRCS = $(abspath $(addprefix $(BASE_DIR)/../vrt/, \ +vita_rx_control.v \ +vita_rx_framer.v \ +vita_rx_chain.v \ +vita_tx_control.v \ +vita_tx_deframer.v \ +vita_tx_chain.v \ +gen_context_pkt.v \ +trigger_context_pkt.v \ +vita_pkt_gen.v \ +vita_rx_engine_glue.v \ +vita_tx_engine_glue.v \ +)) diff --git a/fpga/usrp2/vrt/gen_context_pkt.v b/fpga/usrp2/vrt/gen_context_pkt.v new file mode 100644 index 000000000..d6674e887 --- /dev/null +++ b/fpga/usrp2/vrt/gen_context_pkt.v @@ -0,0 +1,106 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +module gen_context_pkt + #(parameter PROT_ENG_FLAGS=1, + parameter DSP_NUMBER=0) + (input clk, input reset, input clear, + input trigger, output sent, + input [31:0] streamid, + input [63:0] vita_time, + input [31:0] message, + input [31:0] seqnum, + output [35:0] data_o, output src_rdy_o, input dst_rdy_i); + + localparam CTXT_IDLE = 0; + localparam CTXT_PROT_ENG = 1; + localparam CTXT_HEADER = 2; + localparam CTXT_STREAMID = 3; + localparam CTXT_TICS = 4; + localparam CTXT_TICS2 = 5; + localparam CTXT_MESSAGE = 6; + localparam CTXT_FLOWCTRL = 7; + localparam CTXT_DONE = 8; + + reg [33:0] data_int; + wire src_rdy_int, dst_rdy_int; + reg [3:0] seqno; + reg [3:0] ctxt_state; + reg [63:0] err_time; + reg [31:0] stored_message; + + always @(posedge clk) + if(reset | clear) + stored_message <= 0; + else + if(trigger) + stored_message <= message; + else if(ctxt_state == CTXT_DONE) + stored_message <= 0; + + // Don't want to clear most of this to avoid getting stuck with a half packet in the pipe + always @(posedge clk) + if(reset) + begin + ctxt_state <= CTXT_IDLE; + seqno <= 0; + end + else + case(ctxt_state) + CTXT_IDLE : + if(trigger) + begin + err_time <= vita_time; + if(PROT_ENG_FLAGS) + ctxt_state <= CTXT_PROT_ENG; + else + ctxt_state <= CTXT_HEADER; + end + + CTXT_DONE : + begin + ctxt_state <= CTXT_IDLE; + seqno <= seqno + 4'd1; + end + default : + if(dst_rdy_int) + ctxt_state <= ctxt_state + 1; + endcase // case (ctxt_state) + + assign src_rdy_int = ~( (ctxt_state == CTXT_IDLE) | (ctxt_state == CTXT_DONE) ); + + always @* + case(ctxt_state) + CTXT_PROT_ENG : data_int <= { 2'b01, 13'b0, DSP_NUMBER[0], 1'b1, 1'b1, 16'd24 }; // UDP port 1 or 3 + CTXT_HEADER : data_int <= { 1'b0, (PROT_ENG_FLAGS ? 1'b0 : 1'b1), 12'b010100000001, seqno, 16'd6 }; + CTXT_STREAMID : data_int <= { 2'b00, streamid }; + CTXT_TICS : data_int <= { 2'b00, err_time[63:32] }; + CTXT_TICS2 : data_int <= { 2'b00, err_time[31:0] }; + CTXT_MESSAGE : data_int <= { 2'b00, message }; + CTXT_FLOWCTRL : data_int <= { 2'b10, seqnum }; + default : data_int <= {2'b00, 32'b00}; + endcase // case (ctxt_state) + + fifo_short #(.WIDTH(34)) ctxt_fifo + (.clk(clk), .reset(reset), .clear(0), + .datain(data_int), .src_rdy_i(src_rdy_int), .dst_rdy_o(dst_rdy_int), + .dataout(data_o[33:0]), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i)); + assign data_o[35:34] = 2'b00; + +endmodule // gen_context_pkt diff --git a/fpga/usrp2/vrt/trigger_context_pkt.v b/fpga/usrp2/vrt/trigger_context_pkt.v new file mode 100644 index 000000000..3d9c2e5c6 --- /dev/null +++ b/fpga/usrp2/vrt/trigger_context_pkt.v @@ -0,0 +1,69 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +module trigger_context_pkt + #(parameter BASE=0) + (input clk, input reset, input clear, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input packet_consumed, output reg trigger); + + wire [23:0] cycles; + wire [15:0] packets; + wire [6:0] dummy1; + wire [14:0] dummy2; + wire enable_cycle, enable_consumed; + reg [30:0] cycle_count, packet_count; + + + setting_reg #(.my_addr(BASE+4), .at_reset(0)) sr_cycles + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out({enable_cycle,dummy1,cycles}),.changed()); + + setting_reg #(.my_addr(BASE+5), .at_reset(0)) sr_packets + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out({enable_consumed,dummy2,packets}),.changed()); + + always @(posedge clk) + if(reset | clear) + cycle_count <= 0; + else + if(trigger) + cycle_count <= 0; + else if(enable_cycle) + cycle_count <= cycle_count + 1; + + always @(posedge clk) + if(reset | clear) + packet_count <= 0; + else + if(trigger) + packet_count <= 0; + else if(packet_consumed & enable_consumed) + packet_count <= packet_count + 1; + + always @(posedge clk) + if(reset | clear) + trigger <= 0; + else + if((cycle_count > cycles)|(packet_count > packets)) + trigger <= 1; + else + trigger <= 0; + +endmodule // trigger_context_pkt diff --git a/fpga/usrp2/vrt/vita_packet_demux36.v b/fpga/usrp2/vrt/vita_packet_demux36.v new file mode 100644 index 000000000..83fb26215 --- /dev/null +++ b/fpga/usrp2/vrt/vita_packet_demux36.v @@ -0,0 +1,102 @@ +// +// Copyright 2012 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +//demux an input stream based on the SID +//output packet has SID removed from header + +module vita_packet_demux36 +#( + parameter NUMCHAN = 1, + parameter SID_BASE = 0 +) +( + input clk, input rst, + + input [35:0] in_data, + input in_src_rdy, + output in_dst_rdy, + + output [35:0] out_data, + output [NUMCHAN-1:0] out_src_rdy, + input [NUMCHAN-1:0] out_dst_rdy +); + + reg [1:0] state; + localparam STATE_WAIT_HDR = 0; + localparam STATE_PROC_SID = 1; + localparam STATE_WRITE_HDR = 2; + localparam STATE_FORWARD = 3; + + reg [31:0] hdr; + reg [NUMCHAN-1:0] sid; + wire has_sid = in_data[28]; + reg has_sid_reg; + + wire my_out_dst_rdy = out_dst_rdy[sid]; + wire my_out_src_rdy = out_src_rdy[sid]; + + always @(posedge clk) begin + if (rst) begin + state <= STATE_WAIT_HDR; + end + else case(state) + + STATE_WAIT_HDR: begin + if (in_src_rdy && in_dst_rdy && in_data[32]) begin + state <= (has_sid)? STATE_PROC_SID : STATE_WRITE_HDR; + end + sid <= 0; + hdr <= in_data[31:0]; + has_sid_reg <= has_sid; + end + + STATE_PROC_SID: begin + if (in_src_rdy && in_dst_rdy) begin + state <= STATE_WRITE_HDR; + sid <= in_data[31:0] - SID_BASE; + hdr[28] <= 1'b0; //clear has sid + hdr[15:0] <= hdr[15:0] - 1'b1; //subtract a line + end + end + + STATE_WRITE_HDR: begin + if (my_out_src_rdy && my_out_dst_rdy) begin + state <= STATE_FORWARD; + end + end + + STATE_FORWARD: begin + if (my_out_src_rdy && my_out_dst_rdy && out_data[33]) begin + state <= STATE_WAIT_HDR; + end + end + + endcase //state + end + + assign out_data = (state == STATE_WRITE_HDR)? {4'b0001, hdr} : in_data; + wire out_src_rdy_i = (state == STATE_WRITE_HDR)? 1'b1 : ((state == STATE_FORWARD)? in_src_rdy : 1'b0); + assign in_dst_rdy = (state == STATE_WAIT_HDR || state == STATE_PROC_SID)? 1'b1 : ((state == STATE_FORWARD)? my_out_dst_rdy : 1'b0); + + genvar i; + generate + for(i = 0; i < NUMCHAN; i = i + 1) begin:valid_assign + assign out_src_rdy[i] = (i == sid)? out_src_rdy_i : 1'b0; + end + endgenerate + +endmodule //vita_packet_demux36 diff --git a/fpga/usrp2/vrt/vita_pkt_gen.v b/fpga/usrp2/vrt/vita_pkt_gen.v new file mode 100644 index 000000000..b962254a6 --- /dev/null +++ b/fpga/usrp2/vrt/vita_pkt_gen.v @@ -0,0 +1,59 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +module vita_pkt_gen + (input clk, input reset, input clear, + input [15:0] len, + output [35:0] data_o, output src_rdy_o, input dst_rdy_i); + + reg [15:0] state; + reg [31:0] seq, data; + + wire sof = (state == 0); + wire eof = (state == (len-1)); + wire consume = src_rdy_o & dst_rdy_i; + + assign src_rdy_o = 1; + + always @(posedge clk) + if(reset | clear) + begin + state <= 0; + seq <= 0; + end + else + if(consume) + if(eof) + begin + state <= 0; + seq <= seq + 1; + end + else + state <= state + 1; + + always @* + case(state) + 0 : data <= {24'h000,seq[3:0],len}; + 1 : data <= seq; + default : data <= {~state,state}; + endcase // case (state) + + assign data_o = {2'b00, eof, sof, data}; + +endmodule // vita_pkt_gen diff --git a/fpga/usrp2/vrt/vita_rx.build b/fpga/usrp2/vrt/vita_rx.build new file mode 100755 index 000000000..010d1be6e --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx.build @@ -0,0 +1 @@ +iverilog -Wimplict -Wportbind -y ../models -y . -y ../control_lib/ -y ../fifo -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/fpga/usrp2/vrt/vita_rx_chain.v b/fpga/usrp2/vrt/vita_rx_chain.v new file mode 100644 index 000000000..2788dc9d5 --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx_chain.v @@ -0,0 +1,114 @@ +// +// Copyright 2011-2012 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +module vita_rx_chain + #(parameter BASE=0, + parameter UNIT=0, + parameter FIFOSIZE=10, + parameter PROT_ENG_FLAGS=1, + parameter DSP_NUMBER=0) + (input clk, input reset, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user, + input [63:0] vita_time, + input [31:0] sample, input strobe, + output [35:0] rx_data_o, output rx_src_rdy_o, input rx_dst_rdy_i, + output overrun, output run, output clear_o, + output [31:0] debug ); + + wire [100:0] sample_data; + wire sample_dst_rdy, sample_src_rdy; + wire [31:0] vrc_debug, vrf_debug; + + wire [35:0] rx_data_int; + wire rx_src_rdy_int, rx_dst_rdy_int; + + wire clear; + assign clear_o = clear; + wire clear_int; + setting_reg #(.my_addr(BASE+8)) sr + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(),.changed(clear_int)); + + vita_rx_control #(.BASE(BASE), .WIDTH(32)) vita_rx_control + (.clk(clk), .reset(reset), .clear(clear), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .vita_time(vita_time), .overrun(overrun), + .sample(sample), .run(run), .strobe(strobe), + .sample_fifo_o(sample_data), .sample_fifo_dst_rdy_i(sample_dst_rdy), .sample_fifo_src_rdy_o(sample_src_rdy), + .debug_rx(vrc_debug)); + + vita_rx_framer #(.BASE(BASE), .MAXCHAN(1)) vita_rx_framer + (.clk(clk), .reset(reset), .clear(clear), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .sample_fifo_i(sample_data), .sample_fifo_dst_rdy_o(sample_dst_rdy), .sample_fifo_src_rdy_i(sample_src_rdy), + .data_o(rx_data_int), .src_rdy_o(rx_src_rdy_int), .dst_rdy_i(rx_dst_rdy_int), + .debug_rx(vrf_debug) ); + + wire [FIFOSIZE-1:0] access_adr, access_len; + wire access_we, access_stb, access_ok, access_done, access_skip_read; + wire [35:0] dsp_to_buf, buf_to_dsp; + wire [35:0] rx_data_int2; + wire rx_src_rdy_int2, rx_dst_rdy_int2; + + double_buffer #(.BUF_SIZE(FIFOSIZE)) db + (.clk(clk),.reset(reset),.clear(clear), + .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), + .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), + .access_dat_i(dsp_to_buf), .access_dat_o(buf_to_dsp), + + .data_i(rx_data_int), .src_rdy_i(rx_src_rdy_int), .dst_rdy_o(rx_dst_rdy_int), + .data_o(rx_data_int2), .src_rdy_o(rx_src_rdy_int2), .dst_rdy_i(rx_dst_rdy_int2)); + + vita_rx_engine_glue #(.DSPNO(DSP_NUMBER), .MAIN_SETTINGS_BASE(BASE+3), .BUF_SIZE(FIFOSIZE)) dspengine_rx + (.clock(clk),.reset(reset),.clear(clear), + .set_stb_main(set_stb), .set_addr_main(set_addr), .set_data_main(set_data), + .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user), + .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), + .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), + .access_dat_i(buf_to_dsp), .access_dat_o(dsp_to_buf)); + + add_routing_header #(.PORT_SEL(UNIT), + .PROT_ENG_FLAGS(PROT_ENG_FLAGS)) dsp_routing_header + (.clk(clk), .reset(reset), .clear(clear), + .data_i(rx_data_int2), .src_rdy_i(rx_src_rdy_int2), .dst_rdy_o(rx_dst_rdy_int2), + .data_o(rx_data_o), .src_rdy_o(rx_src_rdy_o), .dst_rdy_i(rx_dst_rdy_i) ); + + //only clear once a full packet has passed through the output interface + reg xfer_pkt, clear_oneshot; + assign clear = (clear_oneshot)? ~xfer_pkt : 0; + always @(posedge clk) begin + + if (reset || clear) begin + clear_oneshot <= 0; + end + else if (clear_int) begin + clear_oneshot <= 1; + end + + if (reset || clear) begin + xfer_pkt <= 0; + end + else if (rx_src_rdy_o && rx_dst_rdy_i) begin + xfer_pkt <= ~rx_data_o[33]; + end + end + + assign debug = vrc_debug; // | vrf_debug; + +endmodule // vita_rx_chain diff --git a/fpga/usrp2/vrt/vita_rx_control.v b/fpga/usrp2/vrt/vita_rx_control.v new file mode 100644 index 000000000..daec734a8 --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx_control.v @@ -0,0 +1,231 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +module 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 [5+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; + + wire [63:0] rcvtime_pre; + reg [63:0] rcvtime; + wire [27:0] numlines_pre; + wire send_imm_pre, chain_pre, reload_pre, stop_pre; + reg send_imm, chain, reload; + wire read_ctrl, not_empty_ctrl, write_ctrl; + reg sc_pre2; + wire [33:0] fifo_line; + reg [27:0] lines_left, lines_total; + 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)); + + // FIFO to store commands sent from the settings bus + always @(posedge clk) + if(reset | clear) + sc_pre2 <= 0; + else + sc_pre2 <= sc_pre1; + + assign write_ctrl = sc_pre1 & ~sc_pre2; + + wire [4:0] command_queue_len; + + fifo_short #(.WIDTH(96)) commandfifo + (.clk(clk),.reset(reset),.clear(clear), + .datain({new_command,new_time}), .src_rdy_i(write_ctrl), .dst_rdy_o(), + .dataout({send_imm_pre,chain_pre,reload_pre,stop_pre,numlines_pre,rcvtime_pre}), + .src_rdy_o(not_empty_ctrl), .dst_rdy_i(read_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; + localparam IBS_ZEROLEN = 7; + + wire signal_cmd_done = (lines_left == 1) & (~chain | (not_empty_ctrl & stop_pre)); + wire signal_overrun = (ibs_state == IBS_OVERRUN); + wire signal_brokenchain = (ibs_state == IBS_BROKENCHAIN); + wire signal_latecmd = (ibs_state == IBS_LATECMD); + wire signal_zerolen = (ibs_state == IBS_ZEROLEN); + + // Buffer of samples for while we're writing the packet headers + wire [4:0] flags = {signal_zerolen,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) | + (ibs_state==IBS_ZEROLEN)); + + fifo_short #(.WIDTH(5+64+WIDTH)) rx_sample_fifo + (.clk(clk),.reset(reset),.clear(clear), + .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 go_now = now | send_imm; + wire full = ~sample_fifo_in_rdy; + + reg too_late; + + always @(posedge clk) + if(reset | clear) + too_late <= 0; + else + too_late <= late & ~send_imm; + + reg late_valid; + + always @(posedge clk) + if(reset | clear) + begin + ibs_state <= IBS_IDLE; + lines_left <= 0; + lines_total <= 0; + rcvtime <= 0; + send_imm <= 0; + chain <= 0; + reload <= 0; + late_valid <= 0; + end + else + case(ibs_state) + IBS_IDLE : + if(not_empty_ctrl) + begin + lines_left <= numlines_pre; + lines_total <= numlines_pre; + rcvtime <= rcvtime_pre; + late_valid <= 0; + if(stop_pre) + ibs_state <= IBS_ZEROLEN; + else + ibs_state <= IBS_WAITING; + send_imm <= send_imm_pre; + chain <= chain_pre; + reload <= reload_pre; + end + IBS_WAITING : + begin + late_valid <= 1; + if(late_valid) + if(go_now) + ibs_state <= IBS_RUNNING; + else if(too_late) + ibs_state <= IBS_LATECMD; + end + 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(~not_empty_ctrl & reload) + begin + ibs_state <= IBS_RUNNING; + lines_left <= lines_total; + end + else if(~not_empty_ctrl) + ibs_state <= IBS_BROKENCHAIN; + else + begin + lines_left <= numlines_pre; + lines_total <= numlines_pre; + rcvtime <= rcvtime_pre; + send_imm <= send_imm_pre; + chain <= chain_pre; + reload <= reload_pre; + if(stop_pre) // 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; + IBS_ZEROLEN : + 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) ) + & not_empty_ctrl; + + assign debug_rx = { { ibs_state[2:0], command_queue_len }, + { 8'd0 }, + { go_now, too_late, run, strobe, read_ctrl, write_ctrl, 1'b0, ~not_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 // vita_rx_control diff --git a/fpga/usrp2/vrt/vita_rx_engine_glue.v b/fpga/usrp2/vrt/vita_rx_engine_glue.v new file mode 100644 index 000000000..56447a7aa --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx_engine_glue.v @@ -0,0 +1,95 @@ +// +// Copyright 2012 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +//The following module is used to re-write receive packets to the host. +//This module provides a packet-based ram interface for manipulating packets. +//By default, this module uses the built-in 16 to 8 bit converter engine. + +module vita_rx_engine_glue +#( + //the dsp unit number: 0, 1, 2... + parameter DSPNO = 0, + + //buffer size for ram interface engine + parameter BUF_SIZE = 10, + + //base address for built-in settings registers used in this module + parameter MAIN_SETTINGS_BASE = 0 +) +( + //control signals + input clock, input reset, input clear, + + //main settings bus for built-in modules + input set_stb_main, input [7:0] set_addr_main, input [31:0] set_data_main, + + //user settings bus, controlled through user setting regs API + input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user, + + //ram interface for engine + output access_we, + output access_stb, + input access_ok, + output access_done, + output access_skip_read, + output [BUF_SIZE-1:0] access_adr, + input [BUF_SIZE-1:0] access_len, + output [35:0] access_dat_o, + input [35:0] access_dat_i, + + //debug output (optional) + output [31:0] debug +); + + generate + if (DSPNO==0) begin + `ifndef RX_ENG0_MODULE + dspengine_16to8 #(.BASE(MAIN_SETTINGS_BASE), .BUF_SIZE(BUF_SIZE)) dspengine_16to8 + (.clk(clock),.reset(reset),.clear(clear), + .set_stb(set_stb_main), .set_addr(set_addr_main), .set_data(set_data_main), + .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), + .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), + .access_dat_i(access_dat_i), .access_dat_o(access_dat_o)); + `else + `RX_ENG0_MODULE #(.BUF_SIZE(BUF_SIZE)) rx_eng0_custom + (.clock(clock),.reset(reset),.clear(clear), + .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user), + .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), + .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), + .access_dat_i(access_dat_i), .access_dat_o(access_dat_o)); + `endif + end + else begin + `ifndef RX_ENG1_MODULE + dspengine_16to8 #(.BASE(MAIN_SETTINGS_BASE), .BUF_SIZE(BUF_SIZE)) dspengine_16to8 + (.clk(clock),.reset(reset),.clear(clear), + .set_stb(set_stb_main), .set_addr(set_addr_main), .set_data(set_data_main), + .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), + .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), + .access_dat_i(access_dat_i), .access_dat_o(access_dat_o)); + `else + `RX_ENG1_MODULE #(.BUF_SIZE(BUF_SIZE)) rx_eng1_custom + (.clock(clock),.reset(reset),.clear(clear), + .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user), + .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), + .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), + .access_dat_i(access_dat_i), .access_dat_o(access_dat_o)); + `endif + end + endgenerate + +endmodule //vita_rx_engine_glue diff --git a/fpga/usrp2/vrt/vita_rx_framer.v b/fpga/usrp2/vrt/vita_rx_framer.v new file mode 100644 index 000000000..6e4b8025d --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx_framer.v @@ -0,0 +1,224 @@ +// +// Copyright 2011-2012 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +module 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 [5+64+(32*MAXCHAN)-1:0] sample_fifo_i, + input sample_fifo_src_rdy_i, + output sample_fifo_dst_rdy_o, + + output [31:0] debug_rx + ); + + localparam SAMP_WIDTH = 5+64+(32*MAXCHAN); + reg [3:0] sample_phase; + wire [3:0] numchan; + wire [4:0] flags_fifo_o = sample_fifo_i[SAMP_WIDTH-1:SAMP_WIDTH-5]; + wire [63:0] vita_time_fifo_o = sample_fifo_i[SAMP_WIDTH-6:SAMP_WIDTH-69]; + + 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 [4:0] flags = {signal_zerolen,signal_overrun,signal_brokenchain,signal_latecmd,signal_cmd_done}; + + 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),.width(16)) sr_samples_per_pkt + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(samples_per_packet),.changed()); + + assign numchan = 0;/* + setting_reg #(.my_addr(BASE+8),.width(4), .at_reset(0)) 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_TICS = 3; + localparam VITA_TICS2 = 4; + localparam VITA_PAYLOAD = 5; + localparam VITA_TRAILER = 6; + localparam VITA_ERR_HEADER = 7; // All ERR at 4'b1000 or'ed with base + localparam VITA_ERR_STREAMID = 8; + localparam VITA_ERR_TICS = 9; + localparam VITA_ERR_TICS2 = 10; + localparam VITA_ERR_PAYLOAD = 11; + localparam VITA_ERR_TRAILER = 12; // Extension context packets have no trailer + + always @(posedge clk) + if(reset | clear | clear_pkt_count) + pkt_count <= 0; + else if((vita_state == VITA_TRAILER) & pkt_fifo_rdy) + pkt_count <= pkt_count + 1; + + wire has_streamid = vita_header[28]; + wire has_trailer = vita_header[26]; + reg trl_eob; + + always @* + case(vita_state) + // Data packets are IF Data packets with or w/o streamid, no classid, with trailer + VITA_HEADER : pkt_fifo_line <= {2'b01,3'b000,vita_header[28],2'b01,vita_header[25:24], + vita_header[23:20],pkt_count[3:0],vita_pkt_len[15:0]}; + VITA_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid}; + VITA_TICS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]}; + VITA_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]}; + VITA_PAYLOAD : pkt_fifo_line <= {2'b00,data_fifo_o}; + VITA_TRAILER : pkt_fifo_line <= {2'b10,vita_trailer[31:21],1'b1,vita_trailer[19:9],trl_eob,8'd0}; + + // Error packets are Extension Context packets, which have no trailer + VITA_ERR_HEADER : pkt_fifo_line <= {2'b01,4'b0101,4'b0000,vita_header[23:20],pkt_count,16'd5}; + VITA_ERR_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid}; + VITA_ERR_TICS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]}; + VITA_ERR_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]}; + VITA_ERR_PAYLOAD : pkt_fifo_line <= {2'b10,27'd0,flags_fifo_o}; + //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 | clear) + 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[4:1]) + vita_state <= VITA_ERR_HEADER; + else + vita_state <= VITA_HEADER; + end + else if(pkt_fifo_rdy) + case(vita_state) + VITA_HEADER : + if(has_streamid) + vita_state <= VITA_STREAMID; + else + vita_state <= VITA_TICS; + VITA_PAYLOAD : + if(sample_fifo_src_rdy_i) + begin + if(sample_phase == numchan) + begin + sample_phase <= 0; + sample_ctr <= sample_ctr + 1; + trl_eob <= flags_fifo_o[0]; + 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 // if (sample_fifo_src_rdy_i) + VITA_ERR_PAYLOAD : + vita_state <= VITA_IDLE; + VITA_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_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[4:1]); + VITA_ERR_HEADER, VITA_ERR_STREAMID, VITA_ERR_TICS, VITA_ERR_TICS2, VITA_ERR_PAYLOAD : + 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), + .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() ); + + 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) & + ~|flags_fifo_o[4:1]) | + (vita_state==VITA_ERR_PAYLOAD)); + + assign debug_rx = vita_state; + +endmodule // vita_rx_framer diff --git a/fpga/usrp2/vrt/vita_rx_tb.v b/fpga/usrp2/vrt/vita_rx_tb.v new file mode 100644 index 000000000..8cd08a972 --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx_tb.v @@ -0,0 +1,246 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +module vita_rx_tb; + + localparam DECIM = 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_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+5+(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'h15F00000); // VITA header + write_setting(5,32'hF00D1234); // VITA streamid + write_setting(6,32'hE0000000); // VITA trailer + write_setting(7,8); // Samples per VITA packet + write_setting(8,NUMCHAN); // Vector length + + queue_rx_cmd(1,1,0,10,32'h0,32'h0); // send imm, single packet + #10000; + + queue_rx_cmd(1,0,0,0,32'h0,32'h0); // send imm, single packet + //queue_rx_cmd(1,1,0,0,32'h0,32'h0); // send imm, single packet + + //queue_rx_cmd(1,0,0,0,32'h0,32'h0); // send imm, single packet + + /* + queue_rx_cmd(1,0,0,8,32'h0,32'h0); // send imm, single packet + queue_rx_cmd(1,0,0,16,32'h0,32'h0); // send imm, 2 packets worth + queue_rx_cmd(1,0,0,7,32'h0,32'h0); // send imm, 1 short packet worth + queue_rx_cmd(1,0,0,9,32'h0,32'h0); // send imm, just longer than 1 packet + + queue_rx_cmd(1,1,0,16,32'h0,32'h0); // chained + queue_rx_cmd(0,0,0,8,32'h0,32'h0); // 2nd in chain + + queue_rx_cmd(1,1,0,17,32'h0,32'h0); // chained, odd length + queue_rx_cmd(0,0,0,9,32'h0,32'h0); // 2nd in chain, also odd length + + queue_rx_cmd(0,0,0,8,32'h0,32'h340); // send at, on time + queue_rx_cmd(0,0,0,8,32'h0,32'h100); // send at, but late + + #100000; + $display("\nChained, break chain\n"); + queue_rx_cmd(1,1,0,8,32'h0,32'h0); // chained, but break chain + #100000; + $display("\nSingle packet\n"); + queue_rx_cmd(1,0,0,8,32'h0,32'h0); // send imm, single packet + #100000; + $display("\nEnd chain with zero samples, shouldn't error\n"); + queue_rx_cmd(1,1,0,8,32'h0,32'h0); // chained + queue_rx_cmd(0,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,0,14,32'h0,32'h0); // chained + queue_rx_cmd(0,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,0,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,0,100,32'h0,32'h0); // long enough to fill the fifos + queue_rx_cmd(1,0,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,0,100,32'h0,32'h0); // long enough to fill the fifos + //queue_rx_cmd(1,0,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 reload; + input [28:0] lines; + input [31:0] secs; + input [31:0] tics; + begin + write_setting(0,{send_imm,chain,reload,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/fpga/usrp2/vrt/vita_tx.build b/fpga/usrp2/vrt/vita_tx.build new file mode 100755 index 000000000..e7106aa10 --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx.build @@ -0,0 +1 @@ +iverilog -Wimplict -Wportbind -y ../sdr_lib -y ../models -y . -y ../control_lib/ -y ../fifo -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/fpga/usrp2/vrt/vita_tx_chain.v b/fpga/usrp2/vrt/vita_tx_chain.v new file mode 100644 index 000000000..82a43d57a --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx_chain.v @@ -0,0 +1,162 @@ +// +// Copyright 2011-2012 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +module vita_tx_chain + #(parameter BASE=0, + parameter FIFOSIZE=10, + parameter POST_ENGINE_FIFOSIZE=10, + parameter REPORT_ERROR=0, + parameter DO_FLOW_CONTROL=0, + parameter PROT_ENG_FLAGS=0, + parameter USE_TRANS_HEADER=0, + parameter DSP_NUMBER=0) + (input clk, input reset, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user, + input [63:0] vita_time, + input [35:0] tx_data_i, input tx_src_rdy_i, output tx_dst_rdy_o, + output [35:0] err_data_o, output err_src_rdy_o, input err_dst_rdy_i, + output [31:0] sample, input strobe, + output underrun, output run, output clear_o, + output [31:0] debug); + + localparam MAXCHAN = 1; + localparam FIFOWIDTH = 5+64+16+(32*MAXCHAN); + + wire [FIFOWIDTH-1:0] tx1_data; + wire tx1_src_rdy, tx1_dst_rdy; + wire [31:0] streamid, message; + wire trigger, sent; + wire [31:0] debug_vtc, debug_vtd, debug_tx_dsp; + + wire error, packet_consumed, ack; + wire [31:0] error_code; + wire clear_seqnum; + wire [31:0] current_seqnum; + + wire clear, flush; + assign clear_o = clear; + assign underrun = error; + assign message = error_code; + + setting_reg #(.my_addr(BASE+0), .width(1)) sr + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(flush),.changed(clear)); + + setting_reg #(.my_addr(BASE+2), .at_reset(0)) sr_streamid + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(streamid),.changed(clear_seqnum)); + + //flush control - full rate vacuum of input until flush cleared + wire tx_dst_rdy_int, tx_src_rdy_int; + wire [35:0] tx_data_int; + valve36 flusher_valve + (.clk(clk), .reset(reset), .clear(clear & flush), .shutoff(flush), + .data_i(tx_data_i), .src_rdy_i(tx_src_rdy_i), .dst_rdy_o(tx_dst_rdy_o), + .data_o(tx_data_int), .src_rdy_o(tx_src_rdy_int), .dst_rdy_i(tx_dst_rdy_int)); + + wire [35:0] tx_data_int1; + wire tx_src_rdy_int1, tx_dst_rdy_int1; + + generate + if (FIFOSIZE==0) begin + assign tx_data_int1 = tx_data_int; + assign tx_src_rdy_int1 = tx_src_rdy_int; + assign tx_dst_rdy_int = tx_dst_rdy_int1; + end + else begin + wire [FIFOSIZE-1:0] access_adr, access_len; + wire access_we, access_stb, access_ok, access_done, access_skip_read; + wire [35:0] dsp_to_buf, buf_to_dsp; + wire [35:0] tx_data_int0; + wire tx_src_rdy_int0, tx_dst_rdy_int0; + + double_buffer #(.BUF_SIZE(FIFOSIZE)) db + (.clk(clk),.reset(reset),.clear(clear), + .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), + .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), + .access_dat_i(dsp_to_buf), .access_dat_o(buf_to_dsp), + + .data_i(tx_data_int), .src_rdy_i(tx_src_rdy_int), .dst_rdy_o(tx_dst_rdy_int), + .data_o(tx_data_int0), .src_rdy_o(tx_src_rdy_int0), .dst_rdy_i(tx_dst_rdy_int0)); + + vita_tx_engine_glue #(.DSPNO(DSP_NUMBER), .MAIN_SETTINGS_BASE(BASE+1), .BUF_SIZE(FIFOSIZE), .HEADER_OFFSET(USE_TRANS_HEADER)) dspengine_tx + (.clock(clk),.reset(reset),.clear(clear), + .set_stb_main(set_stb), .set_addr_main(set_addr), .set_data_main(set_data), + .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user), + .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), + .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), + .access_dat_i(buf_to_dsp), .access_dat_o(dsp_to_buf)); + + fifo_cascade #(.WIDTH(36), .SIZE(POST_ENGINE_FIFOSIZE)) post_engine_buffering( + .clk(clk), .reset(reset), .clear(clear), + .datain(tx_data_int0), .src_rdy_i(tx_src_rdy_int0), .dst_rdy_o(tx_dst_rdy_int0), + .dataout(tx_data_int1), .src_rdy_o(tx_src_rdy_int1), .dst_rdy_i(tx_dst_rdy_int1)); + + end + endgenerate + + vita_tx_deframer #(.BASE(BASE), + .MAXCHAN(MAXCHAN), + .USE_TRANS_HEADER(USE_TRANS_HEADER)) + vita_tx_deframer + (.clk(clk), .reset(reset), .clear(clear), .clear_seqnum(clear_seqnum), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .data_i(tx_data_int1), .src_rdy_i(tx_src_rdy_int1), .dst_rdy_o(tx_dst_rdy_int1), + .sample_fifo_o(tx1_data), .sample_fifo_src_rdy_o(tx1_src_rdy), .sample_fifo_dst_rdy_i(tx1_dst_rdy), + .current_seqnum(current_seqnum), + .debug(debug_vtd) ); + + vita_tx_control #(.BASE(BASE), .WIDTH(32*MAXCHAN)) vita_tx_control + (.clk(clk), .reset(reset), .clear(clear), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .vita_time(vita_time), .error(error), .ack(ack), .error_code(error_code), + .sample_fifo_i(tx1_data), .sample_fifo_src_rdy_i(tx1_src_rdy), .sample_fifo_dst_rdy_o(tx1_dst_rdy), + .sample(sample), .run(run), .strobe(strobe), .packet_consumed(packet_consumed), + .debug(debug_vtc) ); + + wire [35:0] flow_data, err_data_int; + wire flow_src_rdy, flow_dst_rdy, err_src_rdy_int, err_dst_rdy_int; + + gen_context_pkt #(.PROT_ENG_FLAGS(PROT_ENG_FLAGS),.DSP_NUMBER(DSP_NUMBER)) gen_flow_pkt + (.clk(clk), .reset(reset), .clear(clear), + .trigger(trigger & (DO_FLOW_CONTROL==1)), .sent(), + .streamid(streamid), .vita_time(vita_time), .message(32'd0), + .seqnum(current_seqnum), + .data_o(flow_data), .src_rdy_o(flow_src_rdy), .dst_rdy_i(flow_dst_rdy)); + trigger_context_pkt #(.BASE(BASE)) trigger_context_pkt + (.clk(clk), .reset(reset), .clear(clear), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .packet_consumed(packet_consumed), .trigger(trigger)); + + gen_context_pkt #(.PROT_ENG_FLAGS(PROT_ENG_FLAGS),.DSP_NUMBER(DSP_NUMBER)) gen_tx_err_pkt + (.clk(clk), .reset(reset), .clear(clear), + .trigger((error|ack) & (REPORT_ERROR==1)), .sent(), + .streamid(streamid), .vita_time(vita_time), .message(message), + .seqnum(current_seqnum), + .data_o(err_data_int), .src_rdy_o(err_src_rdy_int), .dst_rdy_i(err_dst_rdy_int)); + + assign debug = debug_vtc | debug_vtd; + + fifo36_mux #(.prio(1)) mux_err_and_flow // Priority to err messages + (.clk(clk), .reset(reset), .clear(0), // Don't clear this or it could get clogged + .data0_i(err_data_int), .src0_rdy_i(err_src_rdy_int), .dst0_rdy_o(err_dst_rdy_int), + .data1_i(flow_data), .src1_rdy_i(flow_src_rdy), .dst1_rdy_o(flow_dst_rdy), + .data_o(err_data_o), .src_rdy_o(err_src_rdy_o), .dst_rdy_i(err_dst_rdy_i)); + +endmodule // vita_tx_chain diff --git a/fpga/usrp2/vrt/vita_tx_control.v b/fpga/usrp2/vrt/vita_tx_control.v new file mode 100644 index 000000000..c3ce2b96a --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx_control.v @@ -0,0 +1,238 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +module 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 error, output ack, + output reg [31:0] error_code, + output reg packet_consumed, + + // From vita_tx_deframer + input [5+64+16+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 reg run, + input strobe, + + output [31:0] debug + ); + + wire [63:0] send_time = sample_fifo_i[63:0]; + wire [15:0] seqnum = sample_fifo_i[79:64]; + wire eop = sample_fifo_i[80]; + wire eob = sample_fifo_i[81]; + wire sob = sample_fifo_i[82]; + wire send_at = sample_fifo_i[83]; + wire seqnum_err = sample_fifo_i[84]; + + wire now, early, late, too_early; + + time_compare + time_compare (.time_now(vita_time), .trigger_time(send_time), + .now(now), .early(early), .late(late), .too_early(too_early)); + + reg late_qual, late_del; + + always @(posedge clk) + if(reset | clear) + late_del <= 0; + else + late_del <= late; + + always @(posedge clk) + if(reset | clear) + late_qual <= 0; + else + late_qual <= (sample_fifo_src_rdy_i & ~sample_fifo_dst_rdy_o); + + localparam IBS_IDLE = 0; + localparam IBS_RUN = 1; // FIXME do we need this? + localparam IBS_CONT_BURST = 2; + localparam IBS_ERROR = 3; + localparam IBS_ERROR_DONE = 4; + localparam IBS_ERROR_WAIT = 5; + + wire [31:0] CODE_EOB_ACK = {seqnum,16'd1}; + wire [31:0] CODE_UNDERRUN = {seqnum,16'd2}; + wire [31:0] CODE_SEQ_ERROR = {seqnum,16'd4}; + wire [31:0] CODE_TIME_ERROR = {seqnum,16'd8}; + wire [31:0] CODE_UNDERRUN_MIDPKT = {seqnum,16'd16}; + wire [31:0] CODE_SEQ_ERROR_MIDBURST = {seqnum,16'd32}; + + reg [2:0] ibs_state; + + wire [31:0] error_policy; + setting_reg #(.my_addr(BASE+3)) sr_error_policy + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(error_policy),.changed()); + + wire policy_wait = error_policy[0]; + wire policy_next_packet = error_policy[1]; + wire policy_next_burst = error_policy[2]; + reg send_error, send_ack; + + always @(posedge clk) + if(reset | clear) + begin + ibs_state <= IBS_IDLE; + send_error <= 0; + send_ack <= 0; + error_code <= 0; + end + else + case(ibs_state) + IBS_IDLE : + if(sample_fifo_src_rdy_i) + if(seqnum_err) + begin + ibs_state <= IBS_ERROR; + error_code <= CODE_SEQ_ERROR; + send_error <= 1; + end + else if(~send_at | now) + ibs_state <= IBS_RUN; + else if((late_qual & late_del) | too_early) + begin + ibs_state <= IBS_ERROR; + error_code <= CODE_TIME_ERROR; + send_error <= 1; + end + + IBS_RUN : + if(strobe) + if(~sample_fifo_src_rdy_i) + begin + ibs_state <= IBS_ERROR; + error_code <= CODE_UNDERRUN_MIDPKT; + send_error <= 1; + end + else if(eop) + if(eob) + begin + ibs_state <= IBS_ERROR_DONE; // Not really an error + error_code <= CODE_EOB_ACK; + send_ack <= 1; + end + else + ibs_state <= IBS_CONT_BURST; + + IBS_CONT_BURST : + if(strobe) + begin + if(policy_next_packet) + ibs_state <= IBS_ERROR_DONE; + else if(policy_wait) + ibs_state <= IBS_ERROR_WAIT; + else + ibs_state <= IBS_ERROR; + error_code <= CODE_UNDERRUN; + send_error <= 1; + end + else if(sample_fifo_src_rdy_i) + if(seqnum_err) + begin + ibs_state <= IBS_ERROR; + error_code <= CODE_SEQ_ERROR_MIDBURST; + send_error <= 1; + end + else + ibs_state <= IBS_RUN; + + IBS_ERROR : + begin + send_error <= 0; + if(sample_fifo_src_rdy_i & eop) + if(policy_next_packet | (policy_next_burst & eob)) + ibs_state <= IBS_IDLE; + else if(policy_wait) + ibs_state <= IBS_ERROR_WAIT; + end + + IBS_ERROR_DONE : + begin + send_error <= 0; + send_ack <= 0; + ibs_state <= IBS_IDLE; + end + + IBS_ERROR_WAIT : + send_error <= 0; + endcase // case (ibs_state) + + + assign sample_fifo_dst_rdy_o = (ibs_state == IBS_ERROR) | (strobe & (ibs_state == IBS_RUN)); // FIXME also cleanout + + //register the output sample + reg [31:0] sample_held; + assign sample = sample_held; + always @(posedge clk) + if(reset | clear) + sample_held <= 0; + else if (~run) + sample_held <= 0; + else if (strobe) + sample_held <= sample_fifo_i[5+64+16+WIDTH-1:5+64+16]; + + assign error = send_error; + assign ack = send_ack; + + localparam MAX_IDLE = 1000000; + // approx 10 ms timeout with a 100 MHz clock, but burning samples will slow that down + reg [19:0] countdown; + + always @(posedge clk) + if(reset | clear) + begin + run <= 0; + countdown <= 0; + end + else + if (ibs_state == IBS_RUN) + if(eob & eop & strobe & sample_fifo_src_rdy_i) + run <= 0; + else + begin + run <= 1; + countdown <= MAX_IDLE; + end + else + if (countdown == 0) + run <= 0; + else + countdown <= countdown - 1; + + always @(posedge clk) + if(reset | clear) + packet_consumed <= 0; + else + packet_consumed <= eop & sample_fifo_src_rdy_i & sample_fifo_dst_rdy_o; + + assign debug = { { now,late_qual,late_del,ack,eop,eob,sob,send_at }, + { sample_fifo_src_rdy_i, sample_fifo_dst_rdy_o, strobe, run, error, ibs_state[2:0] }, + { 8'b0 }, + { 8'b0 } }; + +endmodule // vita_tx_control diff --git a/fpga/usrp2/vrt/vita_tx_deframer.v b/fpga/usrp2/vrt/vita_tx_deframer.v new file mode 100644 index 000000000..ed3916311 --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx_deframer.v @@ -0,0 +1,261 @@ +// +// Copyright 2011-2012 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +module vita_tx_deframer + #(parameter BASE=0, + parameter MAXCHAN=1, + parameter USE_TRANS_HEADER=0) + (input clk, input reset, input clear, input clear_seqnum, + 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 [5+64+16+(32*MAXCHAN)-1:0] sample_fifo_o, + output sample_fifo_src_rdy_o, + input sample_fifo_dst_rdy_i, + + output [31:0] current_seqnum, + + // FIFO Levels + output [15:0] fifo_occupied, + output fifo_full, + output fifo_empty, + output [31:0] debug + ); + + localparam FIFOWIDTH = 5+64+16+(32*MAXCHAN); + + wire [1:0] numchan = 0;/* + setting_reg #(.my_addr(BASE), .at_reset(0), .width(2)) 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]; + wire is_sob = data_i[25]; + wire 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; + + wire [31:0] seqnum = data_i; + reg [31:0] seqnum_reg; + wire [31:0] next_seqnum = seqnum_reg + 32'd1; + wire [3:0] vita_seqnum = data_i[19:16]; + reg [3:0] vita_seqnum_reg; + wire [3:0] next_vita_seqnum = vita_seqnum_reg[3:0] + 4'd1; + reg seqnum_err; + + assign current_seqnum = seqnum_reg; + + // Output FIFO for packetized data + localparam VITA_TRANS_HEADER = 0; + localparam VITA_HEADER = 1; + localparam VITA_STREAMID = 2; + localparam VITA_CLASSID = 3; + localparam VITA_CLASSID2 = 4; + localparam VITA_SECS = 5; + localparam VITA_TICS = 6; + localparam VITA_TICS2 = 7; + localparam VITA_PAYLOAD = 8; + localparam VITA_TRAILER = 10; + localparam VITA_DUMP = 11; + + 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 vita_eof = (pkt_len==hdr_len); + wire eop = eof | vita_eof; // FIXME would ignoring eof allow larger VITA packets? + wire fifo_space; + + always @(posedge clk) + if(reset | clear | clear_seqnum) + begin + seqnum_reg <= 32'hFFFF_FFFF; + vita_seqnum_reg <= 4'hF; + end + else + begin + if((vita_state==VITA_TRANS_HEADER) & src_rdy_i) + seqnum_reg <= seqnum; + if((vita_state==VITA_HEADER) & src_rdy_i) + vita_seqnum_reg <= vita_seqnum; + end // else: !if(reset | clear_seqnum) + + always @(posedge clk) + if(reset | clear) + begin + vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER; + {has_streamid_reg, has_classid_reg, has_secs_reg, has_tics_reg, has_trailer_reg, is_sob_reg, is_eob_reg} + <= 0; + seqnum_err <= 0; + end + else if(src_rdy_i & dst_rdy_o) begin //valid read + case(vita_state) + VITA_TRANS_HEADER : + begin + seqnum_err <= ~(seqnum == next_seqnum); + vita_state <= VITA_HEADER; + end + 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; + seqnum_err <= seqnum_err | ~(vita_seqnum == next_vita_seqnum); + 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 : begin + + //step through each element until line done, then reset + vector_phase <= (line_done)? 0: vector_phase + 1; + + //decrement the packet count after each line + pkt_len <= (line_done)? pkt_len - 1 : pkt_len; + + //end of frame reached, determine next state + //otherwise, keep processing through the payload + if (line_done && vita_eof) begin + + if (eof) begin + vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER; + end + else if (has_trailer_reg) begin + vita_state <= VITA_TRAILER; + end + else begin + vita_state <= VITA_DUMP; + end + + end //line_done && vita_eof + + end //end VITA_PAYLOAD + + VITA_TRAILER : + if(eof) + vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER; + else + vita_state <= VITA_DUMP; + VITA_DUMP : + if(eof) + vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER; + default : + vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER; + endcase // case (vita_state) + + end //valid read + + assign line_done = (MAXCHAN == 1)? 1 : (vector_phase == numchan); + + wire [FIFOWIDTH-1:0] fifo_i; + reg [63:0] send_time; + + always @(posedge clk) + case(vita_state) + VITA_TICS : + send_time[63:32] <= data_i[31:0]; + VITA_TICS2 : + send_time[31:0] <= data_i[31:0]; + endcase // case (vita_state) + + //sample registers for de-framing a vector input + reg [31:0] sample_reg [1:0]; + always @(posedge clk) + if(src_rdy_i && dst_rdy_o) + sample_reg[vector_phase] <= data_i[31:0]; + + wire store = (vita_state == VITA_PAYLOAD)? (src_rdy_i && line_done) : 0; + assign dst_rdy_o = (vita_state == VITA_PAYLOAD)? fifo_space : 1; + + fifo_short #(.WIDTH(FIFOWIDTH)) 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) ); + + //assign registered/live data to the samples vector + //the numchan'th sample vector is muxed to live data + wire [(32*MAXCHAN)-1:0] samples; + generate + genvar i; + for (i=0; i < MAXCHAN; i = i +1) begin : assign_samples + wire live_data = (i == (MAXCHAN-1))? 1 : numchan == i; + assign samples[32*i + 31:32*i] = (live_data)? data_i[31:0] : sample_reg[i]; + end + endgenerate + + // sob, eob, has_tics (send_at) ignored on all lines except first + assign fifo_i = {samples,seqnum_err,has_tics_reg,is_sob_reg,is_eob_reg,eop, + 12'd0,seqnum_reg[3:0],send_time}; + + 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/fpga/usrp2/vrt/vita_tx_engine_glue.v b/fpga/usrp2/vrt/vita_tx_engine_glue.v new file mode 100644 index 000000000..db0d55dee --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx_engine_glue.v @@ -0,0 +1,99 @@ +// +// Copyright 2012 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +//The following module is used to re-write transmit packets from the host. +//This module provides a packet-based ram interface for manipulating packets. +//By default, this module uses the built-in 8 to 16 bit converter engine. + +module vita_tx_engine_glue +#( + //the dsp unit number: 0, 1, 2... + parameter DSPNO = 0, + + //buffer size for ram interface engine + parameter BUF_SIZE = 10, + + //base address for built-in settings registers used in this module + parameter MAIN_SETTINGS_BASE = 0, + + //the number of 32bit lines between start of buffer and vita header + //the metadata before the header should be preserved by the engine + parameter HEADER_OFFSET = 0 +) +( + //control signals + input clock, input reset, input clear, + + //main settings bus for built-in modules + input set_stb_main, input [7:0] set_addr_main, input [31:0] set_data_main, + + //user settings bus, controlled through user setting regs API + input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user, + + //ram interface for engine + output access_we, + output access_stb, + input access_ok, + output access_done, + output access_skip_read, + output [BUF_SIZE-1:0] access_adr, + input [BUF_SIZE-1:0] access_len, + output [35:0] access_dat_o, + input [35:0] access_dat_i, + + //debug output (optional) + output [31:0] debug +); + + generate + if (DSPNO==0) begin + `ifndef TX_ENG0_MODULE + dspengine_8to16 #(.BASE(MAIN_SETTINGS_BASE), .BUF_SIZE(BUF_SIZE), .HEADER_OFFSET(HEADER_OFFSET)) dspengine_8to16 + (.clk(clock),.reset(reset),.clear(clear), + .set_stb(set_stb_main), .set_addr(set_addr_main), .set_data(set_data_main), + .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), + .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), + .access_dat_i(access_dat_i), .access_dat_o(access_dat_o)); + `else + `TX_ENG0_MODULE #(.BUF_SIZE(BUF_SIZE), .HEADER_OFFSET(HEADER_OFFSET)) tx_eng0_custom + (.clock(clock),.reset(reset),.clear(clear), + .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user), + .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), + .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), + .access_dat_i(access_dat_i), .access_dat_o(access_dat_o)); + `endif + end + else begin + `ifndef TX_ENG1_MODULE + dspengine_8to16 #(.BASE(MAIN_SETTINGS_BASE), .BUF_SIZE(BUF_SIZE), .HEADER_OFFSET(HEADER_OFFSET)) dspengine_8to16 + (.clk(clock),.reset(reset),.clear(clear), + .set_stb(set_stb_main), .set_addr(set_addr_main), .set_data(set_data_main), + .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), + .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), + .access_dat_i(access_dat_i), .access_dat_o(access_dat_o)); + `else + `TX_ENG1_MODULE #(.BUF_SIZE(BUF_SIZE), .HEADER_OFFSET(HEADER_OFFSET)) tx_eng1_custom + (.clock(clock),.reset(reset),.clear(clear), + .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user), + .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), + .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), + .access_dat_i(access_dat_i), .access_dat_o(access_dat_o)); + `endif + end + endgenerate + +endmodule //vita_tx_engine_glue diff --git a/fpga/usrp2/vrt/vita_tx_tb.v b/fpga/usrp2/vrt/vita_tx_tb.v new file mode 100644 index 000000000..b686a8a16 --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx_tb.v @@ -0,0 +1,193 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +module 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 [5+64+16+(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), .USE_TRANS_HEADER(0)) vita_tx_deframer + (.clk(clk), .reset(reset), .clear(0), .clear_seqnum(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), .error(underrun), .error_code(), + .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(0, 32'h300, 5, 32'h0000_1000, 32'h0, 4'h0, 1, 0, 1); + queue_vita_packets(0, 32'h0, 5, 32'h0000_2000, 32'h0, 4'h1, 0, 0, 0); + queue_vita_packets(0, 32'h0, 5, 32'h0000_3000, 32'h0, 4'h2, 0, 0, 0); + + queue_vita_packets(0, 32'h400, 3, 32'h0000_4000, 32'h0, 4'h3, 1, 0, 1); + queue_vita_packets(0, 32'h0, 3, 32'h0000_5000, 32'h0, 4'h4, 0, 0, 0); + queue_vita_packets(0, 32'h0, 3, 32'h0000_6000, 32'h0, 4'h5, 0, 1, 0); + + #300000 $finish; + end + + task queue_vita_packets; + input [31:0] send_secs; + input [31:0] sendtime; + input [15:0] samples; + input [15:0] word; + input [31:0] trailer; + input [3:0] seqnum; + input sob; + input eob; + input sendat; + + reg [15:0] i; + + begin + src_rdy <= 0; + @(posedge clk); + src_rdy <= 1; + data_o <= {4'b0001,4'h0,1'b0,|trailer,sob,eob,{2{sendat}},1'b0,sendat,seqnum,(16'd1+samples+|trailer+sendat+sendat+sendat)}; // header + @(posedge clk); + //data_o <= {4'b0000,32'h0}; // streamid + //@(posedge clk); + if(sendat) + begin + data_o <= {4'b0000,send_secs}; // SECS + @(posedge clk); + data_o <= {4'b0000,32'h0}; // TICS + @(posedge clk); + data_o <= {4'b0000,sendtime}; // TICS + @(posedge clk); + end + 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 |