diff options
Diffstat (limited to 'fpga/usrp3/lib/control_200')
-rw-r--r-- | fpga/usrp3/lib/control_200/Makefile.srcs | 14 | ||||
-rw-r--r-- | fpga/usrp3/lib/control_200/cvita_uart.v | 167 | ||||
-rw-r--r-- | fpga/usrp3/lib/control_200/radio_ctrl_proc.v | 151 | ||||
-rw-r--r-- | fpga/usrp3/lib/control_200/radio_ctrl_proc_tb.v | 110 |
4 files changed, 442 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/control_200/Makefile.srcs b/fpga/usrp3/lib/control_200/Makefile.srcs new file mode 100644 index 000000000..b4ab98f9d --- /dev/null +++ b/fpga/usrp3/lib/control_200/Makefile.srcs @@ -0,0 +1,14 @@ +# +# Copyright 2013 Ettus Research LLC +# Copyright 2016 Ettus Research, a National Instruments Company +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# + +################################################## +# Control Lib Sources (2xx devices) +################################################## +CONTROL_LIB_200_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/control_200/, \ +cvita_uart.v \ +radio_ctrl_proc.v \ +)) diff --git a/fpga/usrp3/lib/control_200/cvita_uart.v b/fpga/usrp3/lib/control_200/cvita_uart.v new file mode 100644 index 000000000..1afcbb5f0 --- /dev/null +++ b/fpga/usrp3/lib/control_200/cvita_uart.v @@ -0,0 +1,167 @@ + +// +// Copyright 2013 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + +//create a compressed vita based uart data interface + +module cvita_uart +#( + parameter SIZE = 0 +) +( + //clocking interface + input clk, input rst, + + //uart interface + input rxd, output txd, + + //chdr fifo input + input [63:0] i_tdata, + input i_tlast, + input i_tvalid, + output i_tready, + + //chdr fifo output + output [63:0] o_tdata, + output o_tlast, + output o_tvalid, + input o_tready +); + + reg [31:0] sid; + + //baud clock divider + reg [15:0] clkdiv; + + //hold rx in disable until a tx event + reg rxd_enable; + + //================================================================== + //== RXD capture and packet generation interface + //================================================================== + wire [7:0] rx_char; + wire fifo_empty; + wire fifo_read; + reg [11:0] seqnum; + wire pgen_trigger; + wire pgen_done; + + //rx uart capture + simple_uart_rx #(.SIZE(SIZE)) simple_uart_rx + ( + .clk(clk), .rst(rst | ~rxd_enable), + .fifo_out(rx_char), .fifo_read(fifo_read), .fifo_level(), .fifo_empty(fifo_empty), + .clkdiv(clkdiv), .rx(rxd) + ); + + //packet generation - holds rx character + context_packet_gen context_packet_gen + ( + .clk(clk), .reset(rst), .clear(1'b0), + .trigger(pgen_trigger), + .seqnum(seqnum), + .sid({sid[15:0], sid[31:16]}), + .body({56'b0, rx_char}), + .vita_time(64'b0), + + .done(pgen_done), + .o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready) + ); + + //state machine to manage pgen and rx uart + reg [1:0] rxd_state; + localparam RXD_STATE_RECV_CHAR = 0; + localparam RXD_STATE_PGEN_TRIG = 1; + localparam RXD_STATE_WAIT_DONE = 2; + localparam RXD_STATE_READ_FIFO = 3; + + always @(posedge clk) begin + if (rst) begin + seqnum <= 12'b0; + rxd_state <= RXD_STATE_RECV_CHAR; + end + else case (rxd_state) + + RXD_STATE_RECV_CHAR: begin + if (!fifo_empty && rxd_enable) rxd_state <= RXD_STATE_PGEN_TRIG; + end + + RXD_STATE_PGEN_TRIG: begin + rxd_state <= RXD_STATE_WAIT_DONE; + end + + RXD_STATE_WAIT_DONE: begin + if (pgen_done) rxd_state <= RXD_STATE_READ_FIFO; + end + + RXD_STATE_READ_FIFO: begin + rxd_state <= RXD_STATE_RECV_CHAR; + seqnum <= seqnum + 1'b1; + end + + endcase //rxd_state + end + + assign fifo_read = (rxd_state == RXD_STATE_READ_FIFO) || (!rxd_enable); + assign pgen_trigger = (rxd_state == RXD_STATE_PGEN_TRIG); + + //================================================================== + //== TXD generation and packet control interface + //================================================================== + wire [7:0] tx_char; + wire fifo_write; + wire fifo_full; + + simple_uart_tx #(.SIZE(SIZE)) simple_uart_tx + ( + .clk(clk), .rst(rst), + .fifo_in(tx_char), .fifo_write(fifo_write), .fifo_level(), .fifo_full(fifo_full), + .clkdiv(clkdiv), .baudclk(), .tx(txd) + ); + + //state machine to manage control and tx uart + reg [1:0] txd_state; + localparam TXD_STATE_RECV_CHDR = 0; + localparam TXD_STATE_RECV_TIME = 1; + localparam TXD_STATE_RECV_BODY = 2; + localparam TXD_STATE_DROP_FIFO = 3; + + always @(posedge clk) begin + if (rst) begin; + txd_state <= TXD_STATE_RECV_CHDR; + rxd_enable <= 1'b0; + end + if (i_tvalid && i_tready) case (txd_state) + + TXD_STATE_RECV_CHDR: begin + txd_state <= (i_tdata[61])? TXD_STATE_RECV_TIME : TXD_STATE_RECV_BODY; + sid <= i_tdata[31:0]; + end + + TXD_STATE_RECV_TIME: begin + txd_state <= TXD_STATE_RECV_BODY; + end + + TXD_STATE_RECV_BODY: begin + txd_state <= (i_tlast)? TXD_STATE_RECV_CHDR : TXD_STATE_DROP_FIFO; + clkdiv <= i_tdata[47:32]; + rxd_enable <= 1'b1; + end + + TXD_STATE_DROP_FIFO: begin + if (i_tlast) txd_state <= TXD_STATE_RECV_CHDR; + end + + endcase //txd_state + end + + assign tx_char = i_tdata[7:0]; + assign fifo_write = (txd_state == TXD_STATE_RECV_BODY) && i_tvalid && i_tready; + assign i_tready = !fifo_full; + +endmodule // cvita_uart diff --git a/fpga/usrp3/lib/control_200/radio_ctrl_proc.v b/fpga/usrp3/lib/control_200/radio_ctrl_proc.v new file mode 100644 index 000000000..069ea5d81 --- /dev/null +++ b/fpga/usrp3/lib/control_200/radio_ctrl_proc.v @@ -0,0 +1,151 @@ +// +// Copyright 2014 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// Radio Control Processor +// Accepts compressed vita extension context packets of the following form: +// { VITA Compressed Header, Stream ID } +// { Optional 64 bit time } +// { 16'h0, setting bus address [15:0], setting [31:0] } +// +// If there is a timestamp, packet is held until that time comes. +// Goes immediately if there is no timestamp or if time has passed. +// Sends out setting to setting bus, and then generates a response packet +// with the same sequence number, the src/dest swapped streamid, and the actual time +// the setting was sent. +// +// Note -- if t0 is the requested time, the actual send time on the setting bus is t0 + 1 cycle. + +module radio_ctrl_proc + (input clk, input reset, input clear, + + input [63:0] ctrl_tdata, input ctrl_tlast, input ctrl_tvalid, output reg ctrl_tready, + output reg [63:0] resp_tdata, output reg resp_tlast, output resp_tvalid, input resp_tready, + + input [63:0] vita_time, + + output set_stb, output [7:0] set_addr, output [31:0] set_data, + input ready, + + input [63:0] readback, + + output [31:0] debug); + + localparam RC_HEAD = 4'd0; + localparam RC_TIME = 4'd1; + localparam RC_DATA = 4'd2; + localparam RC_DUMP = 4'd3; + localparam RC_RESP_HEAD = 4'd4; + localparam RC_RESP_TIME = 4'd5; + localparam RC_RESP_DATA = 4'd6; + + wire IS_EC = ctrl_tdata[63]; + wire HAS_TIME = ctrl_tdata[61]; + reg HAS_TIME_reg; + + reg [3:0] rc_state; + reg [63:0] cmd_time; + + wire now, late, go; + reg [11:0] seqnum; + reg [31:0] sid; + + always @(posedge clk) + if(reset) + begin + rc_state <= RC_HEAD; + HAS_TIME_reg <= 1'b0; + sid <= 32'd0; + seqnum <= 12'd0; + end + else + case(rc_state) + RC_HEAD : + if(ctrl_tvalid) + begin + sid <= ctrl_tdata[31:0]; + seqnum <= ctrl_tdata[59:48]; + HAS_TIME_reg <= HAS_TIME; + if(IS_EC) + if(HAS_TIME) + rc_state <= RC_TIME; + else + rc_state <= RC_DATA; + else + if(~ctrl_tlast) + rc_state <= RC_DUMP; + end + + RC_TIME : + if(ctrl_tvalid) + if(ctrl_tlast) + rc_state <= RC_RESP_HEAD; + else if(go) + rc_state <= RC_DATA; + + RC_DATA : + if(ctrl_tvalid) + if(ready) + if(ctrl_tlast) + rc_state <= RC_RESP_HEAD; + else + rc_state <= RC_DUMP; + + RC_DUMP : + if(ctrl_tvalid) + if(ctrl_tlast) + rc_state <= RC_RESP_HEAD; + + RC_RESP_HEAD : + if(resp_tready) + rc_state <= RC_RESP_TIME; + + RC_RESP_TIME : + if(resp_tready) + rc_state <= RC_RESP_DATA; + + RC_RESP_DATA: + if(resp_tready) + rc_state <= RC_HEAD; + + default : + rc_state <= RC_HEAD; + endcase // case (rc_state) + + always @* + case (rc_state) + RC_HEAD : ctrl_tready <= 1'b1; + RC_TIME : ctrl_tready <= ctrl_tlast | go; + RC_DATA : ctrl_tready <= ready; + RC_DUMP : ctrl_tready <= 1'b1; + default : ctrl_tready <= 1'b0; + endcase // case (rc_state) + + time_compare time_compare + (.clk(clk), .reset(reset), .time_now(vita_time), .trigger_time(ctrl_tdata), .now(now), .early(), .late(late), .too_early()); + + assign go = now | late; + + assign set_stb = (rc_state == RC_DATA) & ready & ctrl_tvalid; + assign set_addr = ctrl_tdata[39:32]; + assign set_data = ctrl_tdata[31:0]; + + always @(posedge clk) + if (set_stb) + cmd_time <= vita_time; + + always @* + case (rc_state) + RC_RESP_HEAD : { resp_tlast, resp_tdata } <= {1'b0, 4'hA, seqnum, 16'd24, sid[15:0], sid[31:16] }; + RC_RESP_TIME : { resp_tlast, resp_tdata } <= {1'b0, cmd_time}; + RC_RESP_DATA : { resp_tlast, resp_tdata } <= {1'b1, readback}; + default : { resp_tlast, resp_tdata } <= 65'h0; + endcase // case (rc_state) + + assign resp_tvalid = (rc_state == RC_RESP_HEAD) | (rc_state == RC_RESP_TIME) | (rc_state == RC_RESP_DATA); + +endmodule // radio_ctrl_proc + diff --git a/fpga/usrp3/lib/control_200/radio_ctrl_proc_tb.v b/fpga/usrp3/lib/control_200/radio_ctrl_proc_tb.v new file mode 100644 index 000000000..18d822e27 --- /dev/null +++ b/fpga/usrp3/lib/control_200/radio_ctrl_proc_tb.v @@ -0,0 +1,110 @@ +// +// Copyright 2014 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +`timescale 1ns/1ps + +module radio_ctrl_proc_tb(); + + reg clk = 0; + reg reset = 1; + + always #10 clk = ~clk; + + initial $dumpfile("radio_ctrl_proc_tb.vcd"); + initial $dumpvars(0,radio_ctrl_proc_tb); + + initial + begin + #1000 reset = 0; + #20000; + $finish; + end + + reg [63:0] vita_time = 64'd0; + always @(posedge clk) + if(reset) vita_time <= 64'd0; + else vita_time <= vita_time + 64'd1; + + reg [63:0] tdata; + wire [63:0] tdata_int; + reg tlast; + wire tlast_int; + reg tvalid = 1'b0; + wire tvalid_int; + wire tready, tready_int; + + wire [7:0] set_addr; + wire [31:0] set_data; + wire set_stb; + wire ready = 1'b1; + + task send_packet; + input ec; + input timed; + input [11:0] seqnum; + input [31:0] sid; + input [63:0] vtime; + input [15:0] addr; + input [31:0] data; + + begin + // Send a packet + @(posedge clk); + tlast <= 1'b0; + tdata <= { ec, 1'b0, timed, 1'b0, seqnum, timed ? 16'd6 : 16'd4, sid }; + tvalid <= 1; + @(posedge clk); + if(timed) + begin + tdata <= vtime; + @(posedge clk); + end + tlast <= 1'b1; + tdata <= { 16'h0, addr, data }; + @(posedge clk); + tvalid <= 0; + @(posedge clk); + end + endtask // send_packet + + initial + begin + tvalid <= 1'b0; + while(reset) + @(posedge clk); + send_packet(1'b1,1'b0,12'h5,32'hDEAD_BEEF,64'h0,16'hB,32'hF00D_1234); + send_packet(1'b1,1'b1,12'h6,32'hDEAD_6789,64'h20,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h7,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321); + //send_packet(.ec(1), .timed(0), .seqnum(5), .sid(32'hDEAD_BEEF), .vtime(0), .addr(16'hB), .data(32'hF00D_1234)); + end + + axi_fifo_short #(.WIDTH(65)) axi_fifo_short + (.clk(clk), .reset(reset), .clear(1'b0), + .i_tdata({tlast,tdata}), .i_tvalid(tvalid), .i_tready(tready), + .o_tdata({tlast_int,tdata_int}), .o_tvalid(tvalid_int), .o_tready(tready_int)); + + wire [63:0] resp_tdata; + wire resp_tlast, resp_tvalid, resp_tready; + + radio_ctrl_proc radio_ctrl_proc + (.clk(clk), .reset(reset), .clear(1'b0), + .ctrl_tdata(tdata_int), .ctrl_tlast(tlast_int), .ctrl_tvalid(tvalid_int), .ctrl_tready(tready_int), + .resp_tdata(resp_tdata), .resp_tlast(resp_tlast), .resp_tvalid(resp_tvalid), .resp_tready(resp_tready), + .vita_time(vita_time), .ready(ready), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .debug() + ); + + assign resp_tready = 1'b1; + + always @(posedge clk) + if(resp_tvalid & resp_tready) + begin + $display("%x",resp_tdata); + if(resp_tlast) + $display("TLAST"); + end +endmodule // radio_ctrl_proc_tb |