aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/rfnoc/sine_tone.v
blob: f012214ff448b52381a9513395006869c95b99b8 (plain) (blame)
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