aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/vita_200/chdr_16s_to_8s.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/vita_200/chdr_16s_to_8s.v')
-rw-r--r--fpga/usrp3/lib/vita_200/chdr_16s_to_8s.v204
1 files changed, 204 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/vita_200/chdr_16s_to_8s.v b/fpga/usrp3/lib/vita_200/chdr_16s_to_8s.v
new file mode 100644
index 000000000..70507b2a9
--- /dev/null
+++ b/fpga/usrp3/lib/vita_200/chdr_16s_to_8s.v
@@ -0,0 +1,204 @@
+//
+// Copyright 2013, 2014 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+module chdr_16s_to_8s
+#(
+ parameter BASE=0
+)
+(
+ input clk,
+ input rst,
+
+ // axi4 stream slave interface
+ input [63:0] i_tdata,
+ input i_tlast,
+ input i_tvalid,
+ output i_tready,
+
+ // axi4 stream master interface
+ output reg [63:0] o_tdata,
+ output o_tlast,
+ output o_tvalid,
+ input o_tready,
+
+ // settings bus slave interface
+ input set_stb,
+ input [7:0] set_addr,
+ input [31:0] set_data,
+
+ output [31:0] debug
+);
+
+ // split up for lazyness reasons
+ wire [15:0] fixed0 = i_tdata[63:48];
+ wire [15:0] fixed1 = i_tdata[47:32];
+ wire [15:0] fixed2 = i_tdata[31:16];
+ wire [15:0] fixed3 = i_tdata[15:0];
+
+ wire [7:0] rounded_cur0;
+ wire [7:0] rounded_cur1;
+ wire [7:0] rounded_cur2;
+ wire [7:0] rounded_cur3;
+
+ // Parse CHDR info
+ wire chdr_has_time = i_tdata[61];
+ // CHDR has either 8 bytes of header or 16 if VITA time is included.
+ wire [15:0] chdr_header_bytes = chdr_has_time ? 16 : 8;
+ // Calculate size of samples input in bytes by taking CHDR size filed
+ // and subtracting header length.
+ wire [15:0] sample_byte_count_in = i_tdata[47:32] - chdr_header_bytes;
+ // Calculate size of samples to be output by taking input size
+ // and dividing by two as sizeof(Q15) = 2*sizeof(Q7)
+ wire [15:0] sample_byte_count_out = sample_byte_count_in >> 1;
+ // Calculate size of output CHDR packet by adding back header size to new
+ // payload size.
+ wire [15:0] output_chdr_pkt_size = sample_byte_count_out + chdr_header_bytes;
+
+ // Make routing (SID) available via settings bus
+ wire set_sid;
+ wire [15:0] new_sid_dst;
+
+ setting_reg #
+ (
+ .my_addr(BASE),
+ .width(17)
+ )
+ new_destination
+ (
+ .clk(clk),
+ .rst(rst),
+ .strobe(set_stb),
+ .addr(set_addr),
+ .in(set_data),
+ .out({set_sid, new_sid_dst[15:0]}),
+ .changed()
+ );
+
+ wire handshake_ok = o_tready & i_tvalid;
+
+ reg [7:0] rounded_old0;
+ reg [7:0] rounded_old1;
+ reg [7:0] rounded_old2;
+ reg [7:0] rounded_old3;
+
+ // respect your elders, yo
+ always @ (posedge clk)
+ if (rst)
+ {rounded_old0, rounded_old1, rounded_old2, rounded_old3} <= 32'h0;
+ else if (handshake_ok) begin
+ {rounded_old0, rounded_old1} <= {rounded_cur0, rounded_cur1};
+ {rounded_old2, rounded_old3} <= {rounded_cur2, rounded_cur3};
+ end
+
+ localparam HEADER = 2'd0;
+ localparam TIME = 2'd1;
+ localparam PREPARE = 2'd2;
+ localparam OUTPUT = 2'd3;
+
+ reg [1:0] state;
+
+ always @(posedge clk) begin
+ if (rst)
+ state <= HEADER;
+ else case(state)
+ HEADER:
+ // In case we see a i_last we just wait for the
+ // next header here, otherwise move on to the next states
+ if (handshake_ok & !i_tlast)
+ state <= chdr_has_time ? TIME : PREPARE;
+
+ TIME:
+ // If we get a premature end of burst go back
+ // to searching for the start of a new packet
+ if (handshake_ok)
+ state <= i_tlast ? HEADER: PREPARE;
+
+ PREPARE:
+ if (handshake_ok)
+ state <= i_tlast ? HEADER: OUTPUT;
+
+ OUTPUT:
+ if (handshake_ok)
+ state <= i_tlast ? HEADER: PREPARE;
+
+ default:
+ state <= HEADER;
+
+ endcase
+ end
+
+ round #
+ (
+ .bits_in(16),
+ .bits_out(8)
+ )
+ round0
+ (
+ .in(fixed0),
+ .out(rounded_cur0),
+ .err()
+ );
+
+ round #
+ (
+ .bits_in(16),
+ .bits_out(8)
+ )
+ round1
+ (
+ .in(fixed1),
+ .out(rounded_cur1),
+ .err()
+ );
+
+ round #
+ (
+ .bits_in(16),
+ .bits_out(8)
+ )
+ round2
+ (
+ .in(fixed2),
+ .out(rounded_cur2),
+ .err()
+ );
+
+ round #
+ (
+ .bits_in(16),
+ .bits_out(8))
+ round3
+ (
+ .in(fixed3),
+ .out(rounded_cur3),
+ .err()
+ );
+
+ always @(*)
+ case(state)
+ HEADER:
+ o_tdata = {i_tdata[63:48], output_chdr_pkt_size,
+ set_sid ? {i_tdata[15:0], new_sid_dst[15:0]} : i_tdata[31:0]};
+ TIME:
+ o_tdata = i_tdata;
+ PREPARE:
+ // Here the second half of this stuff is invalid, as the header will
+ // take care of that by setting the correct length field,
+ // we assign the same to simplify the mux
+ o_tdata = {rounded_cur0, rounded_cur1, rounded_cur2, rounded_cur3,
+ rounded_cur0, rounded_cur1, rounded_cur2, rounded_cur3};
+ OUTPUT:
+ o_tdata = {rounded_old0, rounded_old1, rounded_old2, rounded_old3,
+ rounded_cur0, rounded_cur1, rounded_cur2, rounded_cur3};
+ default:
+ o_tdata = i_tdata;
+ endcase
+
+ assign o_tvalid = i_tvalid && (state != PREPARE || i_tlast);
+ assign i_tready = o_tready || (state == PREPARE && !i_tlast);
+ assign o_tlast = i_tlast;
+
+endmodule