diff options
Diffstat (limited to 'fpga/usrp3/lib/rfnoc')
| -rw-r--r-- | fpga/usrp3/lib/rfnoc/axi_sync.v | 101 | ||||
| -rw-r--r-- | fpga/usrp3/lib/rfnoc/axi_tag_time.v | 207 | ||||
| -rw-r--r-- | fpga/usrp3/lib/rfnoc/dds_freq_tune.v | 349 | 
3 files changed, 411 insertions, 246 deletions
diff --git a/fpga/usrp3/lib/rfnoc/axi_sync.v b/fpga/usrp3/lib/rfnoc/axi_sync.v index a881a5556..25b43d55b 100644 --- a/fpga/usrp3/lib/rfnoc/axi_sync.v +++ b/fpga/usrp3/lib/rfnoc/axi_sync.v @@ -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 -  assign o_tdata    = int_tdata; -  assign o_tlast    = int_tlast; - +  // 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; -endmodule
\ No newline at end of file +endmodule diff --git a/fpga/usrp3/lib/rfnoc/axi_tag_time.v b/fpga/usrp3/lib/rfnoc/axi_tag_time.v index 35698ef72..0e49df76f 100644 --- a/fpga/usrp3/lib/rfnoc/axi_tag_time.v +++ b/fpga/usrp3/lib/rfnoc/axi_tag_time.v @@ -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
\ No newline at end of file +endmodule diff --git a/fpga/usrp3/lib/rfnoc/dds_freq_tune.v b/fpga/usrp3/lib/rfnoc/dds_freq_tune.v index 2491c01a1..f1dc44b17 100644 --- a/fpga/usrp3/lib/rfnoc/dds_freq_tune.v +++ b/fpga/usrp3/lib/rfnoc/dds_freq_tune.v @@ -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 */ +  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, - -  //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 +  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; - -  //when we're holding valid, make ready low so no new data comes in. +  // 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        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  })    ); +  // 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] +  ); + +  // 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_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)); - -  //debug -  assign state_out = state; -  assign phase_valid_hold_out = phase_valid_hold; +    .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  | 
