fpga: lib: Clean up and document lib files
Clean-up and document axi_tag_time, dds_freq_tune, and axi_sync. Original-commit: 8edd13e6eba61ef2bfd96c7dc88b2642decbaa7a
This commit is contained in:
+74
-29
@@ -1,14 +1,32 @@
|
||||
//
|
||||
// Copyright 2016 Ettus Research
|
||||
// Copyright 2018 Ettus Research, a National Instruments Company
|
||||
// Copyright 2021 Ettus Research, a National Instruments Brand
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Synchronizes AXI stream buses so data is released on every port simultaneously.
|
||||
// Module: axi_sync
|
||||
//
|
||||
// Note: If inputs have inequal bitwidths, use WIDTH_VEC instead of WIDTH to define
|
||||
// the individual bit widths. Each bit width is defined with 8-bits stuffed
|
||||
// into a vector of width 8*SIZE.
|
||||
// Description:
|
||||
//
|
||||
// Synchronizes AXI stream buses so data is released on every port
|
||||
// simultaneously. Multiple inputs/outputs are supported by concatenating the
|
||||
// bus signals together. The number and size of each input/output bus is
|
||||
// controlled using parameters.
|
||||
//
|
||||
// **WARNING**: This module violates the AXI4-Stream specification by not
|
||||
// asserting TVALID until it receives TREADY. This will not
|
||||
// work if downstream logic waits for TVALID before asserting
|
||||
// TREADY, which is common. Use with care.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// SIZE : The number of inputs streams to synchronize.
|
||||
// WIDTH : The width of TDATA on the input streams, if they are all the
|
||||
// same width. If they are different widths, then use WIDTH_VEC
|
||||
// instead.
|
||||
// WIDTH_VEC : A vector of widths corresponding to each stream's TDATA width.
|
||||
// Each number in this vector must be 32 bits wide. This defaults
|
||||
// to WIDTH bits for all inputs.
|
||||
// FIFO_SIZE : Log2 the size of the FIFO to use internally for each stream.
|
||||
//
|
||||
|
||||
module axi_sync #(
|
||||
@@ -16,48 +34,75 @@ module axi_sync #(
|
||||
parameter WIDTH = 32,
|
||||
parameter [32*SIZE-1:0] WIDTH_VEC = {SIZE{WIDTH[31:0]}},
|
||||
parameter FIFO_SIZE = 0
|
||||
)(
|
||||
input clk, input reset, input clear,
|
||||
input [msb(SIZE,WIDTH_VEC)-1:0] i_tdata, input [SIZE-1:0] i_tlast, input [SIZE-1:0] i_tvalid, output [SIZE-1:0] i_tready,
|
||||
output [msb(SIZE,WIDTH_VEC)-1:0] o_tdata, output [SIZE-1:0] o_tlast, output [SIZE-1:0] o_tvalid, input [SIZE-1:0] o_tready
|
||||
) (
|
||||
input clk,
|
||||
input reset,
|
||||
input clear,
|
||||
|
||||
// Input streams
|
||||
input [len(SIZE)-1:0] i_tdata,
|
||||
input [ SIZE-1:0] i_tlast,
|
||||
input [ SIZE-1:0] i_tvalid,
|
||||
output [ SIZE-1:0] i_tready,
|
||||
|
||||
// Output streams
|
||||
output [len(SIZE)-1:0] o_tdata,
|
||||
output [ SIZE-1:0] o_tlast,
|
||||
output [ SIZE-1:0] o_tvalid,
|
||||
input [ SIZE-1:0] o_tready
|
||||
);
|
||||
|
||||
// Helper function to calculate the MSB index based on widths stored in WIDTH_VEC.
|
||||
// Note: If n is negative, returns 0
|
||||
function automatic integer msb(input integer n, input [SIZE*32-1:0] bit_vec);
|
||||
// Helper function to calculate the combined length of the lower 'n' ports
|
||||
// based on widths stored in WIDTH_VEC. Note: If n is negative, returns 0.
|
||||
function automatic integer len(input integer n);
|
||||
integer i, total;
|
||||
begin
|
||||
total = 0;
|
||||
if (n >= 0) begin
|
||||
for (i = 0; i <= n; i = i + 1) begin
|
||||
total = total + ((bit_vec >> 32*i) & 32'hFF);
|
||||
total = total + ((WIDTH_VEC >> 32*i) & 32'hFFFF);
|
||||
end
|
||||
end
|
||||
msb = total;
|
||||
len = total;
|
||||
end
|
||||
endfunction
|
||||
|
||||
wire [msb(SIZE,WIDTH_VEC)-1:0] int_tdata;
|
||||
wire [SIZE-1:0] int_tlast, int_tvalid, int_tready;
|
||||
wire [len(SIZE)-1:0] int_tdata;
|
||||
wire [ SIZE-1:0] int_tlast;
|
||||
wire [ SIZE-1:0] int_tvalid;
|
||||
wire [ SIZE-1:0] int_tready;
|
||||
|
||||
// Generate a FIFO for each stream
|
||||
genvar i;
|
||||
generate
|
||||
for (i = 0; i < SIZE; i = i + 1) begin
|
||||
axi_fifo #(.WIDTH(msb(i,WIDTH_VEC)-msb(i-1,WIDTH_VEC)+1), .SIZE(FIFO_SIZE)) axi_fifo (
|
||||
.clk(clk), .reset(reset), .clear(clear),
|
||||
.i_tdata({i_tlast[i],i_tdata[msb(i,WIDTH_VEC)-1:msb(i-1,WIDTH_VEC)]}),
|
||||
.i_tvalid(i_tvalid[i]), .i_tready(i_tready[i]),
|
||||
.o_tdata({int_tlast[i],int_tdata[msb(i,WIDTH_VEC)-1:msb(i-1,WIDTH_VEC)]}),
|
||||
.o_tvalid(int_tvalid[i]), .o_tready(int_tready[i]),
|
||||
.space(), .occupied());
|
||||
axi_fifo #(
|
||||
.WIDTH (len(i)-len(i-1)+1),
|
||||
.SIZE (FIFO_SIZE)
|
||||
) axi_fifo (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.clear (clear),
|
||||
.i_tdata ({ i_tlast[i], i_tdata[len(i)-1 : len(i-1)] }),
|
||||
.i_tvalid (i_tvalid[i]),
|
||||
.i_tready (i_tready[i]),
|
||||
.o_tdata ({ int_tlast[i], int_tdata[len(i)-1 : len(i-1)] }),
|
||||
.o_tvalid (int_tvalid[i]),
|
||||
.o_tready (int_tready[i]),
|
||||
.space (),
|
||||
.occupied ()
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// We allow a transfer and consume the outputs of the FIFOs when all
|
||||
// downstream blocks are ready to accept a transfer (o_tready is true for all
|
||||
// streams) and all FIFOs have data ready (int_tvalid is true for all FIFOs).
|
||||
wire consume = (&int_tvalid) & (&o_tready);
|
||||
|
||||
assign int_tready = {SIZE{consume}};
|
||||
assign o_tvalid = {SIZE{consume}};
|
||||
assign o_tdata = int_tdata;
|
||||
assign o_tlast = int_tlast;
|
||||
|
||||
wire consume = (&int_tvalid) & (&o_tready);
|
||||
assign int_tready = {SIZE{consume}};
|
||||
assign o_tvalid = {SIZE{consume}};
|
||||
|
||||
endmodule
|
||||
endmodule
|
||||
|
||||
+138
-69
@@ -1,79 +1,115 @@
|
||||
//
|
||||
// Copyright 2016 Ettus Research
|
||||
// Copyright 2018 Ettus Research, a National Instruments Company
|
||||
// Copyright 2021 Ettus Research, a National Instruments Brand
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// - When the user executes a timed settings bus command,
|
||||
// this module will tag the sample (on m_axis_data_tuser)
|
||||
// that the command should apply on.
|
||||
// - Order of operation:
|
||||
// 1) Receives settings bus command
|
||||
// a) If time != 0, output on non-timed settings bus
|
||||
// b) If time != 0, output on timed settings bus and store time in FIFO
|
||||
// It is assumed the user will use timed_settings_bus.v implementation.
|
||||
// 2)
|
||||
// Module: axi_tag_time
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// This module accepts samples on s_axis_data_* and outputs them on
|
||||
// m_axis_data_*. When the user executes a timed settings bus command to a
|
||||
// register, this module will tag the sample that the command should apply on
|
||||
// by asserting the bit corresponding to that register in m_axis_data_tag.
|
||||
//
|
||||
// The order of operations is as follows:
|
||||
//
|
||||
// 1) Receives settings bus command on in_set_*.
|
||||
//
|
||||
// a) If in_set_has_time == 0, output on non-timed settings bus (out_set_*).
|
||||
//
|
||||
// b) If in_set_has_time == 1, output on timed settings bus (timed_set_*)
|
||||
// and store the time in a FIFO. It is assumed the user will use
|
||||
// timed_settings_bus.v implementation.
|
||||
//
|
||||
// 2) When the sample corresponding to the time stored in the FIFO arrives on
|
||||
// s_axis_data_*, assert the corresponding bit in m_axis_data_tag at the
|
||||
// same time the sample is output on m_axis_data_*.
|
||||
//
|
||||
// The TUSER port contains the packet header information:
|
||||
//
|
||||
// tuser[125] : Has timestamp
|
||||
// tuser[63:0] : Timestamp
|
||||
//
|
||||
// This field should be valid for the duration of the packet, although in
|
||||
// reality the timestamp is only read during the first sample of each packet.
|
||||
// The "has time" bit will be read at various points depending on the
|
||||
// requested time.
|
||||
//
|
||||
|
||||
module axi_tag_time #(
|
||||
parameter WIDTH = 32,
|
||||
parameter HEADER_WIDTH = 128,
|
||||
parameter SR_AWIDTH = 8,
|
||||
parameter SR_DWIDTH = 32,
|
||||
parameter SR_TWIDTH = 64,
|
||||
parameter NUM_TAGS = 1,
|
||||
parameter [NUM_TAGS*SR_AWIDTH-1:0] SR_TAG_ADDRS = 0,
|
||||
parameter CMD_FIFO_SIZE = 5,
|
||||
parameter MAX_TICK_RATE = 2**16-1
|
||||
)(
|
||||
parameter WIDTH = 32,
|
||||
parameter HEADER_WIDTH = 128,
|
||||
parameter SR_AWIDTH = 8,
|
||||
parameter SR_DWIDTH = 32,
|
||||
parameter SR_TWIDTH = 64,
|
||||
parameter NUM_TAGS = 1,
|
||||
parameter [NUM_TAGS*SR_AWIDTH-1:0] SR_TAG_ADDRS = 0,
|
||||
parameter CMD_FIFO_SIZE = 5,
|
||||
parameter MAX_TICK_RATE = 2**16-1
|
||||
) (
|
||||
input clk,
|
||||
input reset,
|
||||
input clear,
|
||||
input [$clog2(MAX_TICK_RATE)-1:0] tick_rate,
|
||||
output timed_cmd_fifo_full,
|
||||
// From AXI Wrapper
|
||||
input [WIDTH-1:0] s_axis_data_tdata,
|
||||
input [HEADER_WIDTH-1:0] s_axis_data_tuser,
|
||||
input s_axis_data_tlast,
|
||||
input s_axis_data_tvalid,
|
||||
output s_axis_data_tready,
|
||||
// To user
|
||||
output [WIDTH-1:0] m_axis_data_tdata,
|
||||
|
||||
input [$clog2(MAX_TICK_RATE)-1:0] tick_rate,
|
||||
output timed_cmd_fifo_full,
|
||||
|
||||
// Input sample stream
|
||||
input [ WIDTH-1:0] s_axis_data_tdata,
|
||||
input [HEADER_WIDTH-1:0] s_axis_data_tuser,
|
||||
input s_axis_data_tlast,
|
||||
input s_axis_data_tvalid,
|
||||
output s_axis_data_tready,
|
||||
|
||||
// Output sample string, with tag
|
||||
output [ WIDTH-1:0] m_axis_data_tdata,
|
||||
output [HEADER_WIDTH-1:0] m_axis_data_tuser,
|
||||
output [NUM_TAGS-1:0] m_axis_data_tag,
|
||||
output m_axis_data_tlast,
|
||||
output m_axis_data_tvalid,
|
||||
input m_axis_data_tready,
|
||||
// Settings bus from Noc Shell
|
||||
input in_set_stb,
|
||||
output [ NUM_TAGS-1:0] m_axis_data_tag,
|
||||
output m_axis_data_tlast,
|
||||
output m_axis_data_tvalid,
|
||||
input m_axis_data_tready,
|
||||
|
||||
// Settings bus
|
||||
input in_set_stb,
|
||||
input [SR_AWIDTH-1:0] in_set_addr,
|
||||
input [SR_DWIDTH-1:0] in_set_data,
|
||||
input [SR_TWIDTH-1:0] in_set_time,
|
||||
input in_set_has_time,
|
||||
input in_set_has_time,
|
||||
|
||||
// Non-timed settings bus to user
|
||||
output out_set_stb,
|
||||
output out_set_stb,
|
||||
output [SR_AWIDTH-1:0] out_set_addr,
|
||||
output [SR_DWIDTH-1:0] out_set_data,
|
||||
|
||||
// Timed settings bus to user
|
||||
output timed_set_stb,
|
||||
output timed_set_stb,
|
||||
output [SR_AWIDTH-1:0] timed_set_addr,
|
||||
output [SR_DWIDTH-1:0] timed_set_data
|
||||
);
|
||||
|
||||
assign out_set_addr = in_set_addr;
|
||||
assign out_set_data = in_set_data;
|
||||
assign out_set_stb = in_set_stb & ~in_set_has_time;
|
||||
assign out_set_addr = in_set_addr;
|
||||
assign out_set_data = in_set_data;
|
||||
assign out_set_stb = in_set_stb & ~in_set_has_time;
|
||||
|
||||
assign timed_set_addr = in_set_addr;
|
||||
assign timed_set_data = in_set_data;
|
||||
assign timed_set_stb = in_set_stb & in_set_has_time;
|
||||
|
||||
// Extract vita time from tuser
|
||||
// Extract vita time from s_axis_data_tuser
|
||||
wire [63:0] vita_time_in;
|
||||
cvita_hdr_decoder cvita_hdr_decoder_in (
|
||||
.header(s_axis_data_tuser),
|
||||
.pkt_type(), .eob(), .has_time(),
|
||||
.seqnum(), .length(), .payload_length(),
|
||||
.src_sid(), .dst_sid(),
|
||||
.vita_time(vita_time_in));
|
||||
.header (s_axis_data_tuser),
|
||||
.pkt_type (),
|
||||
.eob (),
|
||||
.has_time (),
|
||||
.seqnum (),
|
||||
.length (),
|
||||
.payload_length (),
|
||||
.src_sid (),
|
||||
.dst_sid (),
|
||||
.vita_time (vita_time_in)
|
||||
);
|
||||
|
||||
// Track time
|
||||
reg header_valid = 1'b1;
|
||||
@@ -97,6 +133,8 @@ module axi_tag_time #(
|
||||
end
|
||||
end
|
||||
|
||||
// Create the tags vector by asserting only the tag bit corresponding to the
|
||||
// register being addressed.
|
||||
genvar i;
|
||||
wire [NUM_TAGS-1:0] tags;
|
||||
generate
|
||||
@@ -110,31 +148,62 @@ module axi_tag_time #(
|
||||
wire [NUM_TAGS-1:0] fifo_tags;
|
||||
wire fifo_tvalid, fifo_tready;
|
||||
wire timed_cmd_fifo_full_n;
|
||||
axi_fifo #(.WIDTH(SR_TWIDTH+NUM_TAGS), .SIZE(CMD_FIFO_SIZE)) axi_fifo (
|
||||
.clk(clk), .reset(reset), .clear(clear),
|
||||
.i_tdata({in_set_time,tags}), .i_tvalid(timed_set_stb), .i_tready(timed_cmd_fifo_full_n),
|
||||
.o_tdata({fifo_set_time,fifo_tags}), .o_tvalid(fifo_tvalid), .o_tready(fifo_tready),
|
||||
.space(), .occupied());
|
||||
axi_fifo #(
|
||||
.WIDTH (SR_TWIDTH+NUM_TAGS),
|
||||
.SIZE (CMD_FIFO_SIZE)
|
||||
) axi_fifo (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.clear (clear),
|
||||
.i_tdata ({in_set_time,tags}),
|
||||
.i_tvalid (timed_set_stb),
|
||||
.i_tready (timed_cmd_fifo_full_n),
|
||||
.o_tdata ({fifo_set_time,fifo_tags}),
|
||||
.o_tvalid (fifo_tvalid),
|
||||
.o_tready (fifo_tready),
|
||||
.space (),
|
||||
.occupied ()
|
||||
);
|
||||
|
||||
// Extract has time from tuser
|
||||
// Extract has_time from m_axis_data_tuser
|
||||
wire has_time;
|
||||
cvita_hdr_decoder cvita_hdr_decoder_out (
|
||||
.header(m_axis_data_tuser),
|
||||
.pkt_type(), .eob(), .has_time(has_time),
|
||||
.seqnum(), .length(), .payload_length(),
|
||||
.src_sid(), .dst_sid(),
|
||||
.vita_time());
|
||||
.header (m_axis_data_tuser),
|
||||
.pkt_type (),
|
||||
.eob (),
|
||||
.has_time (has_time),
|
||||
.seqnum (),
|
||||
.length (),
|
||||
.payload_length (),
|
||||
.src_sid (),
|
||||
.dst_sid (),
|
||||
.vita_time ()
|
||||
);
|
||||
|
||||
assign timed_cmd_fifo_full = ~timed_cmd_fifo_full_n;
|
||||
assign fifo_tready = m_axis_data_tvalid & m_axis_data_tready & fifo_tvalid & has_time & (vita_time_now >= fifo_set_time);
|
||||
assign in_rb_stb = fifo_tready;
|
||||
assign fifo_tready = m_axis_data_tvalid &
|
||||
m_axis_data_tready &
|
||||
fifo_tvalid &
|
||||
has_time &
|
||||
(vita_time_now >= fifo_set_time);
|
||||
|
||||
// Need a single cycle delay to allow vita_time_now to update at the start of a new packet
|
||||
axi_fifo_flop #(.WIDTH(WIDTH+HEADER_WIDTH+1)) axi_fifo_flop (
|
||||
.clk(clk), .reset(reset), .clear(clear),
|
||||
.i_tdata({s_axis_data_tdata,s_axis_data_tuser,s_axis_data_tlast}), .i_tvalid(s_axis_data_tvalid), .i_tready(s_axis_data_tready),
|
||||
.o_tdata({m_axis_data_tdata,m_axis_data_tuser,m_axis_data_tlast}), .o_tvalid(m_axis_data_tvalid), .o_tready(m_axis_data_tready));
|
||||
// Need a single cycle delay to allow vita_time_now to update at the start of
|
||||
// a new packet.
|
||||
axi_fifo_flop #(
|
||||
.WIDTH (WIDTH+HEADER_WIDTH+1)
|
||||
) axi_fifo_flop (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.clear (clear),
|
||||
.i_tdata ({ s_axis_data_tdata, s_axis_data_tuser, s_axis_data_tlast }),
|
||||
.i_tvalid (s_axis_data_tvalid),
|
||||
.i_tready (s_axis_data_tready),
|
||||
.o_tdata ({ m_axis_data_tdata, m_axis_data_tuser, m_axis_data_tlast }),
|
||||
.o_tvalid (m_axis_data_tvalid),
|
||||
.o_tready (m_axis_data_tready)
|
||||
);
|
||||
|
||||
assign m_axis_data_tag = ((vita_time_now >= fifo_set_time) & fifo_tvalid & has_time) ? fifo_tags : 'd0;
|
||||
assign m_axis_data_tag =
|
||||
((vita_time_now >= fifo_set_time) & fifo_tvalid & has_time) ? fifo_tags : 'd0;
|
||||
|
||||
endmodule
|
||||
endmodule
|
||||
|
||||
+199
-148
@@ -1,117 +1,139 @@
|
||||
//
|
||||
// Copyright 2018 Ettus Research, a National Instruments Company
|
||||
// Copyright 2021 Ettus Research, a National Instruments Brand
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// DDS frequency shift with complex multiply
|
||||
// Module: dds_freq_tune
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// Performs a frequency shift on a signal by multiplying it with a complex
|
||||
// sinusoid synthesized from a DDS. This module expects samples data to be in
|
||||
// {Q,I} order.
|
||||
//
|
||||
|
||||
module dds_freq_tune #(
|
||||
parameter WIDTH = 24,
|
||||
parameter PHASE_WIDTH = 24,
|
||||
module dds_freq_tune #(
|
||||
parameter WIDTH = 24,
|
||||
parameter PHASE_WIDTH = 24,
|
||||
parameter SIN_COS_WIDTH = 16,
|
||||
parameter OUTPUT_WIDTH = 24
|
||||
)(
|
||||
input clk,
|
||||
input reset,
|
||||
input eob,
|
||||
input rate_changed,
|
||||
input [15:0] dds_input_fifo_occupied,
|
||||
/* IQ input */
|
||||
input [WIDTH*2-1:0] s_axis_din_tdata,
|
||||
input s_axis_din_tlast,
|
||||
input s_axis_din_tvalid,
|
||||
output s_axis_din_tready,
|
||||
/* Phase input from NCO */
|
||||
input [PHASE_WIDTH-1:0] s_axis_phase_tdata,
|
||||
input s_axis_phase_tlast,
|
||||
input s_axis_phase_tvalid,
|
||||
output s_axis_phase_tready,
|
||||
/* IQ output */
|
||||
output [OUTPUT_WIDTH*2-1:0] m_axis_dout_tdata,
|
||||
output m_axis_dout_tlast,
|
||||
output m_axis_dout_tvalid,
|
||||
input m_axis_dout_tready,
|
||||
parameter OUTPUT_WIDTH = 24
|
||||
) (
|
||||
input clk,
|
||||
input reset,
|
||||
|
||||
//debug signals
|
||||
output [2:0] state_out,
|
||||
output phase_valid_hold_out,
|
||||
output [7:0] phase_invalid_wait_count_out,
|
||||
output reset_dds_out,
|
||||
output m_axis_dds_tlast_out,
|
||||
output m_axis_dds_tvalid_out,
|
||||
output m_axis_dds_tready_out,
|
||||
output [SIN_COS_WIDTH*2-1:0] m_axis_dds_tdata_out //[31:16] = sin|q [15:0] cos|i
|
||||
input eob,
|
||||
input rate_changed,
|
||||
|
||||
input [15:0] dds_input_fifo_occupied,
|
||||
|
||||
// IQ input
|
||||
input [WIDTH*2-1:0] s_axis_din_tdata,
|
||||
input s_axis_din_tlast,
|
||||
input s_axis_din_tvalid,
|
||||
output s_axis_din_tready,
|
||||
|
||||
// Phase input from NCO
|
||||
input [PHASE_WIDTH-1:0] s_axis_phase_tdata,
|
||||
input s_axis_phase_tlast,
|
||||
input s_axis_phase_tvalid,
|
||||
output s_axis_phase_tready,
|
||||
|
||||
// IQ output
|
||||
output [OUTPUT_WIDTH*2-1:0] m_axis_dout_tdata,
|
||||
output m_axis_dout_tlast,
|
||||
output m_axis_dout_tvalid,
|
||||
input m_axis_dout_tready,
|
||||
|
||||
// Debug signals
|
||||
output [ 2:0] state_out,
|
||||
output phase_valid_hold_out,
|
||||
output [ 7:0] phase_invalid_wait_count_out,
|
||||
output reset_dds_out,
|
||||
output m_axis_dds_tlast_out,
|
||||
output m_axis_dds_tvalid_out,
|
||||
output m_axis_dds_tready_out,
|
||||
output [SIN_COS_WIDTH*2-1:0] m_axis_dds_tdata_out
|
||||
);
|
||||
|
||||
//wires for dds output
|
||||
wire m_axis_dds_tlast;
|
||||
wire m_axis_dds_tvalid;
|
||||
wire m_axis_dds_tready;
|
||||
wire [SIN_COS_WIDTH*2-1:0] m_axis_dds_tdata; //[31:16] = sin|q [15:0] cos|i
|
||||
reg reset_reg;
|
||||
reg phase_valid_hold;
|
||||
reg [7:0] phase_invalid_wait_count;
|
||||
reg [2:0] state;
|
||||
reg reset_dds = 1'b1; // Init DDS resets to 1, since simulation model
|
||||
reg reset_dds_reg = 1'b1; // requires reset at time 0 to avoid failure.
|
||||
reg phase_ready_wait;
|
||||
wire s_axis_phase_tready_dds;
|
||||
// Wires for DDS output
|
||||
wire m_axis_dds_tlast;
|
||||
wire m_axis_dds_tvalid;
|
||||
wire m_axis_dds_tready;
|
||||
wire [SIN_COS_WIDTH*2-1:0] m_axis_dds_tdata; // [31:16] = sin|q, [15:0]= cos|i
|
||||
|
||||
//when we're holding valid, make ready low so no new data comes in.
|
||||
reg reset_reg;
|
||||
reg phase_valid_hold;
|
||||
reg [7:0] phase_invalid_wait_count;
|
||||
reg [2:0] state;
|
||||
reg phase_ready_wait;
|
||||
wire s_axis_phase_tready_dds;
|
||||
|
||||
// Initialize DDS resets to 1, since simulation model requires reset at time
|
||||
// 0 to avoid failure.
|
||||
reg reset_dds = 1'b1;
|
||||
reg reset_dds_reg = 1'b1;
|
||||
|
||||
// When we're holding valid, make ready low so no new data comes in.
|
||||
assign s_axis_phase_tready = s_axis_phase_tready_dds & ~phase_valid_hold;
|
||||
|
||||
localparam INIT = 3'b000;
|
||||
localparam VALID = 3'b001;
|
||||
localparam WAIT = 3'b010;
|
||||
localparam INIT = 3'b000;
|
||||
localparam VALID = 3'b001;
|
||||
localparam WAIT = 3'b010;
|
||||
localparam HOLD_VALID = 3'b011;
|
||||
|
||||
//reset needs to be 2 clk cycles minimum for Xilinx DDS IP
|
||||
// Reset needs to be 2 clk cycles minimum for Xilinx DDS IP
|
||||
always @(posedge clk) begin
|
||||
reset_reg <= reset;
|
||||
reset_reg <= reset;
|
||||
reset_dds_reg <= reset_dds;
|
||||
end
|
||||
|
||||
//some logic to reset the dds when data is goes from valid to not valid
|
||||
//also holds valid high until the pipeline has passed tlast through.
|
||||
// This state machine resets the DDS when data stops coming and also holds
|
||||
// valid high until the last packet has been flushed through the DDS.
|
||||
always @(posedge clk) begin
|
||||
if(reset) begin
|
||||
state <= INIT;
|
||||
phase_valid_hold <= 1'b0;
|
||||
state <= INIT;
|
||||
phase_valid_hold <= 1'b0;
|
||||
phase_invalid_wait_count <= 16'h00;
|
||||
reset_dds <= 1'b0;
|
||||
end
|
||||
else begin
|
||||
reset_dds <= 1'b0;
|
||||
end else begin
|
||||
case(state)
|
||||
INIT: begin//init case
|
||||
phase_valid_hold <= 1'b0;
|
||||
INIT : begin
|
||||
phase_valid_hold <= 1'b0;
|
||||
phase_invalid_wait_count <= 16'h0000;
|
||||
reset_dds <= 1'b0;
|
||||
reset_dds <= 1'b0;
|
||||
if(s_axis_phase_tvalid) begin
|
||||
state <= VALID;
|
||||
end
|
||||
end
|
||||
VALID: begin //valid data
|
||||
VALID : begin
|
||||
if(~s_axis_phase_tvalid) begin
|
||||
state <= WAIT;
|
||||
end
|
||||
end
|
||||
WAIT: begin //wait until we either get valid data or don't
|
||||
if(m_axis_dds_tready) begin //only increment when the downstream can accept data.
|
||||
WAIT : begin
|
||||
// Wait until we either get valid data or don't.
|
||||
if(m_axis_dds_tready) begin
|
||||
// Only increment when the downstream can accept data.
|
||||
phase_invalid_wait_count <= phase_invalid_wait_count + 4'b1;
|
||||
end
|
||||
if(s_axis_phase_tvalid) begin //if we get valid data shortly after, then don't push data through and reset
|
||||
if(s_axis_phase_tvalid) begin
|
||||
// If we get valid data shortly after, then don't push data through
|
||||
// and reset.
|
||||
state <= INIT;
|
||||
end else begin
|
||||
if(eob | (phase_invalid_wait_count >= 16'h40) | rate_changed ) begin //if a valid never comes, aka eob
|
||||
if(eob | (phase_invalid_wait_count >= 16'h40) | rate_changed) begin
|
||||
// If a valid never comes (EOB)
|
||||
state <= HOLD_VALID;
|
||||
end
|
||||
end
|
||||
end
|
||||
HOLD_VALID: begin//hold valid to finish pipeline. Apparently the dds IP won't empty without additional valids.
|
||||
HOLD_VALID : begin
|
||||
// Hold valid to flush data through the DDS. The DDS IP won't empty
|
||||
// without additional transfers.
|
||||
phase_valid_hold <= 1'b1;
|
||||
// Wait for input FIFO to be empty
|
||||
if (~s_axis_din_tvalid) begin
|
||||
state <= INIT;
|
||||
state <= INIT;
|
||||
reset_dds <= 1'b1;
|
||||
end
|
||||
end
|
||||
@@ -119,90 +141,119 @@ module dds_freq_tune #(
|
||||
end
|
||||
end
|
||||
|
||||
//dds to generate sin/cos data from phase
|
||||
dds_sin_cos_lut_only dds_inst (
|
||||
.aclk(clk), // input wire aclk
|
||||
.aresetn(~(reset | reset_reg | reset_dds | reset_dds_reg)), // input wire aresetn active low rst
|
||||
.s_axis_phase_tvalid(s_axis_phase_tvalid | phase_valid_hold), // input wire s_axis_phase_tvalid
|
||||
.s_axis_phase_tready(s_axis_phase_tready_dds), // output wire s_axis_phase_tready
|
||||
.s_axis_phase_tlast(s_axis_phase_tlast), //tlast
|
||||
.s_axis_phase_tdata(s_axis_phase_tdata), // input wire [23 : 0] s_axis_phase_tdata
|
||||
.m_axis_data_tvalid(m_axis_dds_tvalid), // output wire m_axis_data_tvalid
|
||||
.m_axis_data_tready(m_axis_dds_tready), // input wire m_axis_data_tready
|
||||
.m_axis_data_tlast(m_axis_dds_tlast), // input wire m_axis_data_tready
|
||||
.m_axis_data_tdata(m_axis_dds_tdata) // output wire [31 : 0] m_axis_data_tdata
|
||||
// DDS to generate sin/cos data from phase. It takes in a 24-bit phase value
|
||||
// and outputs two 16-bit values, with the sine value in the upper 16 bits
|
||||
// and the cosine value in the lower 16-bits.
|
||||
//
|
||||
// The phase input can be thought of as a 24-bit unsigned fixed-point value
|
||||
// with 24 fractional bits. In other words, the integer range of the input
|
||||
// maps to the the range [0, 2*pi) in radians.
|
||||
//
|
||||
// The output consists of two 16-bit signed fixed-point values with 14
|
||||
// fractional bits.
|
||||
//
|
||||
// This IP effectively computes Euler's formula, e^(j*2*pi*x) = cos(2*pi*x) +
|
||||
// j*sin(2*pi*x), where x is the phase value, and the output has the real
|
||||
// component in the lower bits and the imaginary component in the upper bits.
|
||||
dds_sin_cos_lut_only dds_sin_cos_lut_only_i (
|
||||
.aclk (clk),
|
||||
.aresetn (~(reset | reset_reg | reset_dds | reset_dds_reg)),
|
||||
.s_axis_phase_tvalid (s_axis_phase_tvalid | phase_valid_hold),
|
||||
.s_axis_phase_tready (s_axis_phase_tready_dds),
|
||||
.s_axis_phase_tlast (s_axis_phase_tlast),
|
||||
.s_axis_phase_tdata (s_axis_phase_tdata), // [23 : 0]
|
||||
.m_axis_data_tvalid (m_axis_dds_tvalid),
|
||||
.m_axis_data_tready (m_axis_dds_tready),
|
||||
.m_axis_data_tlast (m_axis_dds_tlast),
|
||||
.m_axis_data_tdata (m_axis_dds_tdata) // [31 : 0]
|
||||
);
|
||||
|
||||
wire [WIDTH*2-1:0] mult_in_a_tdata;
|
||||
wire mult_in_a_tvalid;
|
||||
wire mult_in_a_tready;
|
||||
wire mult_in_a_tlast;
|
||||
wire [ WIDTH*2-1:0] mult_in_a_tdata;
|
||||
wire mult_in_a_tvalid;
|
||||
wire mult_in_a_tready;
|
||||
wire mult_in_a_tlast;
|
||||
wire [SIN_COS_WIDTH*2-1:0] mult_in_b_tdata;
|
||||
wire mult_in_b_tvalid;
|
||||
wire mult_in_b_tready;
|
||||
wire mult_in_b_tlast; //no connect
|
||||
wire [2*32-1:0] mult_out_tdata;
|
||||
wire mult_out_tvalid;
|
||||
wire mult_out_tready;
|
||||
wire mult_out_tlast;
|
||||
wire mult_in_b_tvalid;
|
||||
wire mult_in_b_tready;
|
||||
wire mult_in_b_tlast;
|
||||
wire [ 2*32-1:0] mult_out_tdata;
|
||||
wire mult_out_tvalid;
|
||||
wire mult_out_tready;
|
||||
wire mult_out_tlast;
|
||||
|
||||
axi_sync #(
|
||||
.SIZE(2),
|
||||
.WIDTH_VEC({SIN_COS_WIDTH*2, WIDTH*2}),
|
||||
.FIFO_SIZE(0))
|
||||
axi_sync (
|
||||
.clk(clk), .reset(reset), .clear(),
|
||||
.i_tdata({m_axis_dds_tdata,s_axis_din_tdata}),
|
||||
.i_tlast({m_axis_dds_tlast,s_axis_din_tlast}),
|
||||
.i_tvalid({m_axis_dds_tvalid,s_axis_din_tvalid}),
|
||||
.i_tready({m_axis_dds_tready,s_axis_din_tready}),
|
||||
.o_tdata({mult_in_b_tdata,mult_in_a_tdata}),
|
||||
.o_tlast({mult_in_b_tlast,mult_in_a_tlast}),
|
||||
.o_tvalid({mult_in_b_tvalid,mult_in_a_tvalid}),
|
||||
.o_tready({mult_in_b_tready,mult_in_a_tready}));
|
||||
|
||||
//a = input i/q data stream 48 bit i/q lower bits i, upper bits q
|
||||
//b = output of dds 32 bit cos/sin. lower cos, upper sin
|
||||
complex_multiplier_dds complex_mult_inst (
|
||||
.aclk(clk), // input wire aclk
|
||||
.aresetn(~(reset | reset_reg)), // input wire aresetn
|
||||
.s_axis_a_tvalid(mult_in_a_tvalid), // input wire s_axis_a_tvalid
|
||||
.s_axis_a_tready(mult_in_a_tready), // output wire s_axis_a_tready
|
||||
.s_axis_a_tlast(mult_in_a_tlast), // input wire s_axis_a_tlast
|
||||
.s_axis_a_tdata({mult_in_a_tdata}), // input wire [47 : 0] s_axis_a_tdata
|
||||
.s_axis_b_tvalid(mult_in_b_tvalid), // input wire s_axis_b_tvalid
|
||||
.s_axis_b_tready(mult_in_b_tready), // output wire s_axis_b_tready
|
||||
.s_axis_b_tlast(mult_in_b_tlast), // output wire s_axis_b_tlast
|
||||
.s_axis_b_tdata(mult_in_b_tdata), // input wire [31 : 0] s_axis_b_tdata
|
||||
.m_axis_dout_tvalid(mult_out_tvalid), // output wire m_axis_dout_tvalid
|
||||
.m_axis_dout_tready(mult_out_tready), // input wire m_axis_dout_tready
|
||||
.m_axis_dout_tlast(mult_out_tlast), // output wire m_axis_dout_tlast
|
||||
.m_axis_dout_tdata(mult_out_tdata) // output wire [63 : 0] m_axis_dout_tdata
|
||||
.SIZE (2),
|
||||
.WIDTH_VEC ({SIN_COS_WIDTH*2, WIDTH*2}),
|
||||
.FIFO_SIZE (0)
|
||||
) axi_sync_i (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.clear (),
|
||||
.i_tdata ({ m_axis_dds_tdata, s_axis_din_tdata }),
|
||||
.i_tlast ({ m_axis_dds_tlast, s_axis_din_tlast }),
|
||||
.i_tvalid ({ m_axis_dds_tvalid, s_axis_din_tvalid }),
|
||||
.i_tready ({ m_axis_dds_tready, s_axis_din_tready }),
|
||||
.o_tdata ({ mult_in_b_tdata, mult_in_a_tdata }),
|
||||
.o_tlast ({ mult_in_b_tlast, mult_in_a_tlast }),
|
||||
.o_tvalid ({ mult_in_b_tvalid, mult_in_a_tvalid }),
|
||||
.o_tready ({ mult_in_b_tready, mult_in_a_tready })
|
||||
);
|
||||
|
||||
axi_round_complex #(
|
||||
.WIDTH_IN(32),
|
||||
.WIDTH_OUT(OUTPUT_WIDTH))
|
||||
axi_round_complex_inst (
|
||||
.clk(clk),
|
||||
.reset(reset | reset_reg),
|
||||
.i_tdata(mult_out_tdata),
|
||||
.i_tlast(mult_out_tlast),
|
||||
.i_tvalid(mult_out_tvalid),
|
||||
.i_tready(mult_out_tready),
|
||||
.o_tdata(m_axis_dout_tdata),
|
||||
.o_tlast(m_axis_dout_tlast),
|
||||
.o_tvalid(m_axis_dout_tvalid),
|
||||
.o_tready(m_axis_dout_tready));
|
||||
// Use a complex multiplier to multiply the input sample (A) by the NCO
|
||||
// output (B). This multiplier has a 21-bit input A, 16-bit input B, and
|
||||
// 32-bit output. Due to AXI-Stream requirements, A is rounded up to 24-bit.
|
||||
//
|
||||
// Assuming default parameters and unchanged IP, The A input (sample) is
|
||||
// 21-bit with 15 fractional bits, and the B input (NCO) is 16-bit with 14
|
||||
// fractional bits. The full result would be 21+16+1 = 38 bits, but the
|
||||
// output is configured for 32, dropping the lower 6 bits. Therefore, the
|
||||
// result has 15+14-6 = 23 fractional bits.
|
||||
//
|
||||
// a = Input IQ data stream as 48-bit, lower bits i, upper bits q.
|
||||
// b = Output of DDS as 32 bit cos/sin, lower bits cos, upper bits sin.
|
||||
complex_multiplier_dds complex_multiplier_dds_i (
|
||||
.aclk (clk),
|
||||
.aresetn (~(reset | reset_reg)),
|
||||
.s_axis_a_tvalid (mult_in_a_tvalid),
|
||||
.s_axis_a_tready (mult_in_a_tready),
|
||||
.s_axis_a_tlast (mult_in_a_tlast),
|
||||
.s_axis_a_tdata ({mult_in_a_tdata}), // [47 : 0]
|
||||
.s_axis_b_tvalid (mult_in_b_tvalid),
|
||||
.s_axis_b_tready (mult_in_b_tready),
|
||||
.s_axis_b_tlast (mult_in_b_tlast),
|
||||
.s_axis_b_tdata (mult_in_b_tdata), // [31 : 0]
|
||||
.m_axis_dout_tvalid (mult_out_tvalid),
|
||||
.m_axis_dout_tready (mult_out_tready),
|
||||
.m_axis_dout_tlast (mult_out_tlast),
|
||||
.m_axis_dout_tdata (mult_out_tdata) // [63 : 0]
|
||||
);
|
||||
|
||||
//debug
|
||||
assign state_out = state;
|
||||
assign phase_valid_hold_out = phase_valid_hold;
|
||||
// Round the 32-bit multiplier result down to 24 bits. This moves the binary
|
||||
// point so that we go from 23 fractional bits down to 15 fractional bits.
|
||||
axi_round_complex #(
|
||||
.WIDTH_IN (32),
|
||||
.WIDTH_OUT (OUTPUT_WIDTH)
|
||||
) axi_round_complex_i (
|
||||
.clk (clk),
|
||||
.reset (reset | reset_reg),
|
||||
.i_tdata (mult_out_tdata),
|
||||
.i_tlast (mult_out_tlast),
|
||||
.i_tvalid (mult_out_tvalid),
|
||||
.i_tready (mult_out_tready),
|
||||
.o_tdata (m_axis_dout_tdata),
|
||||
.o_tlast (m_axis_dout_tlast),
|
||||
.o_tvalid (m_axis_dout_tvalid),
|
||||
.o_tready (m_axis_dout_tready)
|
||||
);
|
||||
|
||||
// Debug
|
||||
assign state_out = state;
|
||||
assign phase_valid_hold_out = phase_valid_hold;
|
||||
assign phase_invalid_wait_count_out = phase_invalid_wait_count;
|
||||
assign reset_dds_out = reset_dds;
|
||||
assign m_axis_dds_tlast_out = m_axis_dds_tlast;
|
||||
assign m_axis_dds_tvalid_out = m_axis_dds_tvalid;
|
||||
assign m_axis_dds_tready_out = m_axis_dds_tready;
|
||||
assign m_axis_dds_tdata_out = m_axis_dds_tdata;
|
||||
assign reset_dds_out = reset_dds;
|
||||
assign m_axis_dds_tlast_out = m_axis_dds_tlast;
|
||||
assign m_axis_dds_tvalid_out = m_axis_dds_tvalid;
|
||||
assign m_axis_dds_tready_out = m_axis_dds_tready;
|
||||
assign m_axis_dds_tdata_out = m_axis_dds_tdata;
|
||||
|
||||
endmodule
|
||||
|
||||
Reference in New Issue
Block a user