1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
//
// Copyright 2015 Ettus Research
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Converts AXI-Stream sample data to a strobed data interface for the radio frontend
// Outputs an error packet if an underrun or late timed command occurs.
module tx_control_gen3 #(
parameter SR_ERROR_POLICY = 0, // What to do when errors occur -- wait for next packet or next burst
parameter WIDTH = 32 // Can be 32 or 64
)(
input clk, input reset, input clear,
input [63:0] vita_time, input [31:0] resp_sid,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
// Data packets
input [WIDTH-1:0] tx_tdata, input [127:0] tx_tuser, input tx_tlast, input tx_tvalid, output tx_tready,
// Error packets
output reg [63:0] resp_tdata, output reg [127:0] resp_tuser, output reg resp_tlast, output reg resp_tvalid, input resp_tready,
// To radio frontend
output run, output [WIDTH-1:0] sample, input strobe
);
wire [63:0] send_time = tx_tuser[63:0];
wire [11:0] seqnum = tx_tuser[123:112];
wire eob = tx_tuser[124];
wire send_at = tx_tuser[125];
wire now, early, late, too_early;
wire policy_next_burst, policy_next_packet;
setting_reg #(.my_addr(SR_ERROR_POLICY), .width(2), .at_reset(2'b01)) sr_error_policy (
.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({policy_next_burst,policy_next_packet}),.changed());
time_compare time_compare (
.clk(clk), .reset(reset),
.time_now(vita_time), .trigger_time(send_time),
.now(now), .early(early), .late(late), .too_early(too_early));
reg [2:0] state;
localparam ST_IDLE = 0;
localparam ST_SAMP = 1;
localparam ST_ERROR_WAIT = 2;
assign run = (state == ST_SAMP) & ~(strobe & ~tx_tvalid); // Immediately drops run signal on underrun
wire [63:0] CODE_EOB_ACK = {32'd1,20'd0,seqnum};
wire [63:0] CODE_UNDERRUN = {32'd2,20'd0,seqnum};
wire [63:0] CODE_TIME_ERROR = {32'd8,20'd0,seqnum};
wire [127:0] error_header = {2'b11, 1'b1, 1'b1, 12'd0 /* don't care */, 16'd0 /* don't care */, resp_sid, vita_time};
wire [127:0] resp_header = {2'b11, 1'b1, 1'b0, 12'd0 /* don't care */, 16'd0 /* don't care */, resp_sid, vita_time};
reg sop, eob_reg;
always @(posedge clk) begin
if (reset | clear) begin
state <= ST_IDLE;
resp_tvalid <= 1'b0;
resp_tlast <= 1'b0;
resp_tuser <= 'd0;
resp_tdata <= 'd0;
sop <= 1'b1;
eob_reg <= 1'b0;
end else begin
// Deassert tvalid after response packet is consumed
if (resp_tvalid & resp_tlast & resp_tready) begin
resp_tvalid <= 1'b0;
resp_tlast <= 1'b0;
end
// Track start of packet
if (tx_tvalid & tx_tready) begin
if (tx_tlast) begin
sop <= 1'b1;
end else if (sop) begin
eob_reg <= eob;
sop <= 1'b0;
end
end
case (state)
ST_IDLE : begin
if (tx_tvalid) begin
if (~send_at | now) begin
state <= ST_SAMP;
end else if (late) begin
resp_tvalid <= 1'b1;
resp_tlast <= 1'b1;
resp_tuser <= error_header;
resp_tdata <= CODE_TIME_ERROR;
state <= ST_ERROR_WAIT;
end
end
end
ST_SAMP : begin
if (strobe) begin
if (~tx_tvalid) begin
resp_tvalid <= 1'b1;
resp_tlast <= 1'b1;
resp_tuser <= error_header;
resp_tdata <= CODE_UNDERRUN;
state <= ST_ERROR_WAIT;
end else begin
if (tx_tlast & eob) begin
resp_tvalid <= 1'b1;
resp_tlast <= 1'b1;
resp_tuser <= resp_header;
resp_tdata <= CODE_EOB_ACK;
state <= ST_IDLE;
end
end
end
end
// Wait until end of packet or burst depending on the policy
ST_ERROR_WAIT : begin
// Two valid times to transition back to IDLE:
// 1. We are at the end of a packet OR
// 2. We are not currently receiving a packet
if ((tx_tvalid & tx_tlast) | (~tx_tvalid & sop)) begin
// Use eob_reg as eob may not be valid when tx_tvalid=0
if (policy_next_packet | (policy_next_burst & eob_reg)) begin
state <= ST_IDLE;
end
end
end
default : state <= ST_IDLE;
endcase // case (state)
end
end
// Read packet in 'sample' state or dump it in error state
assign tx_tready = (state == ST_ERROR_WAIT) | (strobe & (state == ST_SAMP));
assign sample = tx_tdata;
endmodule // tx_control_gen3
|