// // 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