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 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
//
// 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
|