1//
2// Copyright 2020 Ettus Research, a National Instruments Brand
3//
4// SPDX-License-Identifier: LGPL-3.0-or-later
5//
6// Module: rfnoc_siggen_core
7//
8// Description:
9//
10//   This module contains the registers and core logic for a single RFNoC
11//   Signal Generator module instance.
12//
13
14
15module rfnoc_siggen_core (
16  input wire clk,
17  input wire rst,
18
19  // CtrlPort Slave
20  input  wire        s_ctrlport_req_wr,
21  input  wire        s_ctrlport_req_rd,
22  input  wire [19:0] s_ctrlport_req_addr,
23  input  wire [31:0] s_ctrlport_req_data,
24  output reg         s_ctrlport_resp_ack,
25  output reg  [31:0] s_ctrlport_resp_data,
26
27  // Output data stream
28  output wire [31:0] m_tdata,
29  output wire        m_tlast,
30  output wire        m_tvalid,
31  input  wire        m_tready,
32  output wire [15:0] m_tlength
33);
34
35  `include "rfnoc_block_siggen_regs.vh"
36
37
38  //---------------------------------------------------------------------------
39  // Registers
40  //---------------------------------------------------------------------------
41
42  // Define maximum fixed point value for the gain, equal to about 0.9999
43  localparam MAX_GAIN = {REG_GAIN_LEN-1{1'b1}};
44
45  reg [   REG_ENABLE_LEN-1:0] reg_enable    = 0;
46  reg [      REG_SPP_LEN-1:0] reg_spp       = 16;
47  reg [ REG_WAVEFORM_LEN-1:0] reg_waveform  = WAVE_CONST;
48  reg [     REG_GAIN_LEN-1:0] reg_gain      = MAX_GAIN;
49  reg [ REG_CONSTANT_LEN-1:0] reg_constant  = 0;
50  reg [REG_PHASE_INC_LEN-1:0] reg_phase_inc;
51  reg [REG_CARTESIAN_LEN-1:0] reg_cartesian;
52
53  reg reg_phase_inc_stb;
54  reg reg_cartesian_stb;
55
56  always @(posedge clk) begin
57    if (rst) begin
58      reg_enable           <= 0;
59      reg_spp              <= 16;
60      reg_waveform         <= WAVE_CONST;
61      reg_gain             <= MAX_GAIN;
62      reg_constant         <= 0;
63      reg_phase_inc        <= 'bX;
64      reg_cartesian        <= 'bX;
65      s_ctrlport_resp_ack  <= 1'b0;
66      s_ctrlport_resp_data <= 'bX;
67      reg_phase_inc_stb    <= 1'b0;
68      reg_cartesian_stb    <= 1'b0;
69    end else begin
70
71      // Default assignments
72      s_ctrlport_resp_ack  <= 1'b0;
73      s_ctrlport_resp_data <= 0;
74      reg_phase_inc_stb    <= 1'b0;
75      reg_cartesian_stb    <= 1'b0;
76
77      // Handle register writes
78      if (s_ctrlport_req_wr) begin
79        s_ctrlport_resp_ack <= 1;
80        case (s_ctrlport_req_addr)
81          REG_ENABLE    : reg_enable    <= s_ctrlport_req_data[REG_ENABLE_LEN-1:0];
82          REG_SPP       : reg_spp       <= s_ctrlport_req_data[REG_SPP_LEN-1:0];
83          REG_WAVEFORM  : reg_waveform  <= s_ctrlport_req_data[REG_WAVEFORM_LEN-1:0];
84          REG_GAIN      : reg_gain      <= s_ctrlport_req_data[REG_GAIN_LEN-1:0];
85          REG_CONSTANT  : reg_constant  <= s_ctrlport_req_data[REG_CONSTANT_LEN-1:0];
86          REG_PHASE_INC : begin
87            reg_phase_inc     <= s_ctrlport_req_data[REG_PHASE_INC_LEN-1:0];
88            reg_phase_inc_stb <= 1'b1;
89          end
90          REG_CARTESIAN : begin
91            reg_cartesian     <= s_ctrlport_req_data[REG_CARTESIAN_LEN-1:0];
92            reg_cartesian_stb <= 1'b1;
93          end
94        endcase
95      end
96
97      // Handle register reads
98      if (s_ctrlport_req_rd) begin
99        s_ctrlport_resp_ack <= 1;
100        case (s_ctrlport_req_addr)
101          REG_ENABLE    : s_ctrlport_resp_data[REG_ENABLE_LEN-1:0]     <= reg_enable;
102          REG_SPP       : s_ctrlport_resp_data[REG_SPP_LEN-1:0]        <= reg_spp;
103          REG_WAVEFORM  : s_ctrlport_resp_data[REG_WAVEFORM_LEN-1:0]   <= reg_waveform;
104          REG_GAIN      : s_ctrlport_resp_data[REG_GAIN_LEN-1:0]       <= reg_gain;
105          REG_CONSTANT  : s_ctrlport_resp_data[REG_CONSTANT_LEN-1:0]   <= reg_constant;
106          REG_PHASE_INC : s_ctrlport_resp_data[REG_PHASE_INC_LEN-1:0]  <= reg_phase_inc;
107          REG_CARTESIAN : s_ctrlport_resp_data[REG_CARTESIAN_LEN-1:0]  <= reg_cartesian;
108        endcase
109      end
110    end
111  end
112
113
114  //---------------------------------------------------------------------------
115  // Waveform Generation
116  //---------------------------------------------------------------------------
117
118  wire [31:0]  axis_sine_tdata;
119  wire         axis_sine_tvalid;
120  wire         axis_sine_tready;
121  wire [31:0]  axis_const_tdata;
122  wire         axis_const_tvalid;
123  wire         axis_const_tready;
124  wire [31:0]  axis_noise_tdata;
125  wire         axis_noise_tvalid;
126  wire         axis_noise_tready;
127
128  //------------------------------------
129  // Sine waveform generation
130  //------------------------------------
131
132  // Convert the registers writes to settings bus transactions. Only one
133  // register strobe will assert at a time.
134  wire        sine_set_stb  = reg_cartesian_stb | reg_phase_inc_stb;
135  wire [31:0] sine_set_data = reg_cartesian_stb ? reg_cartesian : reg_phase_inc;
136  wire [ 7:0] sine_set_addr = reg_cartesian_stb;
137
138  sine_tone #(
139    .WIDTH             (32),
140    .SR_PHASE_INC_ADDR (0),
141    .SR_CARTESIAN_ADDR (1)
142  ) sine_tone_i (
143    .clk      (clk),
144    .reset    (rst),
145    .clear    (1'b0),
146    .enable   (1'b1),
147    .set_stb  (sine_set_stb),
148    .set_data (sine_set_data),
149    .set_addr (sine_set_addr),
150    .o_tdata  (axis_sine_tdata),
151    .o_tlast  (),
152    .o_tvalid (axis_sine_tvalid),
153    .o_tready (axis_sine_tready)
154  );
155
156  //------------------------------------
157  // Constant waveform generation
158  //------------------------------------
159
160  assign axis_const_tdata  = reg_constant;
161  assign axis_const_tvalid = 1'b1;
162
163  //------------------------------------
164  // Noise waveform generation
165  //------------------------------------
166
167  assign axis_noise_tvalid = 1'b1;
168
169  // Random number generator
170  rng rng_i (
171    .clk (clk),
172    .rst (rst),
173    .out (axis_noise_tdata)
174  );
175
176
177  //---------------------------------------------------------------------------
178  // Waveform Selection
179  //---------------------------------------------------------------------------
180
181  wire [31:0]  axis_mux_tdata;
182  wire         axis_mux_tvalid;
183  wire         axis_mux_tready;
184
185  axi_mux_select #(
186    .WIDTH          (32),
187    .SIZE           (3),
188    .SWITCH_ON_LAST (0)
189  ) axi_mux_select_i (
190    .clk      (clk),
191    .reset    (rst),
192    .clear    (1'b0),
193    .select   (reg_waveform),
194    .i_tdata  ({axis_noise_tdata, axis_sine_tdata, axis_const_tdata}),
195    .i_tlast  ({3'd0}),   // Length controlled by SPP register
196    .i_tvalid ({axis_noise_tvalid, axis_sine_tvalid, axis_const_tvalid}),
197    .i_tready ({axis_noise_tready, axis_sine_tready, axis_const_tready}),
198    .o_tdata  (axis_mux_tdata),
199    .o_tlast  (),
200    .o_tvalid (axis_mux_tvalid),
201    .o_tready (axis_mux_tready)
202  );
203
204
205  //---------------------------------------------------------------------------
206  // Gain
207  //---------------------------------------------------------------------------
208
209  wire [63:0]  axis_gain_tdata;
210  wire         axis_gain_tvalid;
211  wire         axis_gain_tready;
212  wire [31:0]  axis_round_tdata;
213  wire         axis_round_tvalid;
214  wire         axis_round_tready;
215
216  mult_rc #(
217    .WIDTH_REAL (16),
218    .WIDTH_CPLX (16),
219    .WIDTH_P    (32),
220    .DROP_TOP_P (5),
221    .LATENCY    (4)
222  ) mult_rc_i (
223    .clk         (clk),
224    .reset       (rst),
225    .real_tdata  (reg_gain),
226    .real_tlast  (1'b0),
227    .real_tvalid (1'b1),
228    .real_tready (),
229    .cplx_tdata  (axis_mux_tdata),
230    .cplx_tlast  (1'b0),
231    .cplx_tvalid (axis_mux_tvalid),
232    .cplx_tready (axis_mux_tready),
233    .p_tdata     (axis_gain_tdata),
234    .p_tlast     (),
235    .p_tvalid    (axis_gain_tvalid),
236    .p_tready    (axis_gain_tready)
237  );
238
239  axi_round_and_clip_complex #(
240    .WIDTH_IN  (32),
241    .WIDTH_OUT (16),
242    .CLIP_BITS (1)
243  ) axi_round_and_clip_complex_i (
244    .clk      (clk),
245    .reset    (rst),
246    .i_tdata  (axis_gain_tdata),
247    .i_tlast  (1'b0),
248    .i_tvalid (axis_gain_tvalid),
249    .i_tready (axis_gain_tready),
250    .o_tdata  (axis_round_tdata),
251    .o_tlast  (),
252    .o_tvalid (axis_round_tvalid),
253    .o_tready (axis_round_tready)
254  );
255
256
257  //---------------------------------------------------------------------------
258  // Packet Length Control
259  //---------------------------------------------------------------------------
260
261  wire [REG_SPP_LEN-1:0] m_tlength_samples;
262
263  assign m_tlength = { m_tlength_samples, 2'b0 };   // 4 bytes per sample
264
265  axis_packetize #(
266    .DATA_W  (32),
267    .SIZE_W  (REG_SPP_LEN),
268    .FLUSH   (1)
269  ) axis_packetize_i (
270    .clk      (clk),
271    .rst      (rst),
272    .gate     (~reg_enable),
273    .size     (reg_spp),
274    .i_tdata  (axis_round_tdata),
275    .i_tvalid (axis_round_tvalid),
276    .i_tready (axis_round_tready),
277    .o_tdata  (m_tdata),
278    .o_tlast  (m_tlast),
279    .o_tvalid (m_tvalid),
280    .o_tready (m_tready),
281    .o_tuser  (m_tlength_samples)
282  );
283
284endmodule
285