aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/control_200
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/control_200')
-rw-r--r--fpga/usrp3/lib/control_200/Makefile.srcs14
-rw-r--r--fpga/usrp3/lib/control_200/cvita_uart.v167
-rw-r--r--fpga/usrp3/lib/control_200/radio_ctrl_proc.v151
-rw-r--r--fpga/usrp3/lib/control_200/radio_ctrl_proc_tb.v110
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