Files
b210-k7-fpga/lib/rfnoc/sine_tone.v
T
Wade Fife 2e9f7b96ee siggen: Fix direction of rotation
The I and Q were swapped in sine_tone, which caused confusion and made
the rotation of REG_CARTESIAN clockwise by default. This effectively
made the resulting frequency negative. This PR makes the I and Q order
consistent with RFNoC and fixes the direction of rotation so that a
positive value for REG_PHASE_INC (phase increment) results in a
counter-clockwise rotation, which yields a positive frequency.


Original-commit: 4e6531f30648ede5be8f93fa49fdcd4973b73813
2021-10-27 07:56:09 -07:00

166 lines
5.2 KiB
Verilog

//
// Copyright 2020 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: sine_tone
//
// Description:
//
// Sine tone generator. This block uses the Xilinx CORDIC IP configured to
// perform the rotate function in units of scaled radians. See the CORDIC IP
// Product Guide (PG105) for details.
//
// This block outputs the X/I/real component in the most-significant bits and
// the Y/Q/imaginary component in the least-significant bits. This is
// opposite from the Xilinx IP but matches RFNoC.
//
// The SR_PHASE_INC register controls the phase increment, in scaled radians,
// for the sine waveform generator. It is a 16-bit signed fixed-point phase
// value with 3 integer bits and 13 fractional bits. This is the amount by
// which REG_CARTESIAN is rotated counter-clockwise each clock cycle. In
// other words, it controls the rate of rotation, or the frequency, of the
// sine wave. In scaled radians, the phase value range -1 to +1 corresponds
// to -Pi to Pi in radians.
//
// The SR_CARTESIAN register sets the sets the (X,Y) Cartesian coordinate
// that will be rotated to generate the sine output. Both X and Y are 16-bit
// signed fixed-point values with 2 integer bits and 14 fractional bits.
// X/I/real is in the upper 16-bits and Y/Q/imaginary is in the lower 16-bits.
//
// In addition to rotation, the SR_CARTESIAN input vector is also scaled by
// a "CORDIC scale factor" that equals about 1.1644 (that is, the product of
// sqrt(1 + 2^(-2i)) for i = 1 to n, where n = 14, the number of fractional
// bits).
//
// Parameters:
//
// SR_PHASE_INC_ADDR : The address to use for SR_PHASE_INC.
// SR_CARTESIAN_ADDR : The address to use for SR_CARTESIAN.
//
module sine_tone #(
parameter WIDTH = 32,
parameter SR_PHASE_INC_ADDR = 129,
parameter SR_CARTESIAN_ADDR = 130
) (
input clk,
input reset,
input clear,
input enable,
// Settings bus
input set_stb,
input [WIDTH-1:0] set_data,
input [ 7:0] set_addr,
// Output sinusoid
output [WIDTH-1:0] o_tdata,
output o_tlast,
output o_tvalid,
input o_tready
);
wire [15:0] phase_in_tdata;
wire phase_in_tlast;
wire phase_in_tvalid;
wire phase_in_tready;
wire [15:0] phase_out_tdata;
wire phase_out_tlast;
wire phase_out_tvalid;
wire phase_out_tready;
wire [WIDTH-1:0] cartesian_tdata;
wire cartesian_tlast;
wire cartesian_tvalid;
wire cartesian_tready;
wire [WIDTH-1:0] sine_out_tdata;
wire sine_out_tlast;
wire sine_out_tvalid;
wire sine_out_tready;
// AXI settings bus for phase values
axi_setting_reg #(
.ADDR (SR_PHASE_INC_ADDR),
.AWIDTH (8),
.WIDTH (16),
.STROBE_LAST (1),
.REPEATS (1)
) set_phase_acc (
.clk (clk),
.reset (reset),
.error_stb (),
.set_stb (set_stb),
.set_addr (set_addr),
.set_data (set_data),
.o_tdata (phase_in_tdata),
.o_tlast (phase_in_tlast),
.o_tvalid (phase_in_tvalid),
.o_tready (phase_in_tready & enable)
);
// AXI settings bus for Cartesian values
axi_setting_reg #(
.ADDR (SR_CARTESIAN_ADDR),
.AWIDTH (8),
.WIDTH (32),
.REPEATS (1)
) set_axis_cartesian (
.clk (clk),
.reset (reset),
.error_stb (),
.set_stb (set_stb),
.set_addr (set_addr),
.set_data (set_data),
.o_tdata (cartesian_tdata),
.o_tlast (),
.o_tvalid (cartesian_tvalid),
.o_tready (cartesian_tready & enable)
);
assign cartesian_tlast = 1;
// Phase accumulator
phase_accum phase_acc (
.clk (clk),
.reset (reset),
.clear (clear),
.i_tdata (phase_in_tdata),
.i_tlast (phase_in_tlast),
.i_tvalid (1'b1),
.i_tready (phase_in_tready),
.o_tdata (phase_out_tdata),
.o_tlast (phase_out_tlast),
.o_tvalid (phase_out_tvalid),
.o_tready (phase_out_tready & enable)
);
// CORDIC. Swap I and Q to match what the Xilinx IP expects.
cordic_rotator cordic_inst (
.aclk (clk),
.aresetn (~(reset|clear)),
.s_axis_phase_tdata (phase_out_tdata),
.s_axis_phase_tvalid (phase_out_tvalid & cartesian_tvalid & enable),
.s_axis_phase_tready (phase_out_tready),
.s_axis_cartesian_tdata ({cartesian_tdata[ 0 +: WIDTH/2], // Q
cartesian_tdata[WIDTH/2 +: WIDTH/2]}), // I
.s_axis_cartesian_tlast (cartesian_tlast),
.s_axis_cartesian_tvalid (phase_out_tvalid & cartesian_tvalid & enable),
.s_axis_cartesian_tready (cartesian_tready),
.m_axis_dout_tdata ({sine_out_tdata[ 0 +: WIDTH/2], // Q
sine_out_tdata[WIDTH/2 +: WIDTH/2]}), // I
.m_axis_dout_tlast (sine_out_tlast),
.m_axis_dout_tvalid (sine_out_tvalid),
.m_axis_dout_tready (sine_out_tready & enable)
);
assign o_tdata = sine_out_tdata;
assign o_tlast = sine_out_tlast;
assign o_tvalid = sine_out_tvalid;
assign sine_out_tready = o_tready;
endmodule // sine_tone