1//
2// Copyright 2011-2012 Ettus Research LLC
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16//
17
18//! The USRP digital up-conversion chain
19
20module duc_chain
21  #(
22    parameter BASE = 0,
23    parameter DSPNO = 0,
24    parameter WIDTH = 24
25  )
26  (input clk, input rst, input clr,
27   input set_stb, input [7:0] set_addr, input [31:0] set_data,
28   input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
29
30   // To TX frontend
31   output [WIDTH-1:0] tx_fe_i,
32   output [WIDTH-1:0] tx_fe_q,
33
34   // From TX control
35   input [31:0] sample,
36   input run,
37   output strobe,
38   output [31:0] debug
39   );
40
41   wire duc_enb;
42   wire [17:0] scale_factor;
43   wire [31:0] phase_inc;
44   reg [31:0]  phase;
45   wire [7:0]  interp_rate;
46   wire [3:0]  tx_femux_a, tx_femux_b;
47   wire        enable_hb1, enable_hb2;
48   wire        rate_change;
49
50   setting_reg #(.my_addr(BASE+0)) sr_0
51     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
52      .in(set_data),.out(phase_inc),.changed());
53
54   setting_reg #(.my_addr(BASE+1), .width(18)) sr_1
55     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
56      .in(set_data),.out(scale_factor),.changed());
57
58   setting_reg #(.my_addr(BASE+2), .width(10)) sr_2
59     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
60      .in(set_data),.out({enable_hb1, enable_hb2, interp_rate}),.changed(rate_change));
61
62   // Strobes are all now delayed by 1 cycle for timing reasons
63   wire        strobe_cic_pre, strobe_hb1_pre, strobe_hb2_pre;
64   reg 	       strobe_cic = 1;
65   reg 	       strobe_hb1 = 1;
66   reg 	       strobe_hb2 = 1;
67
68   cic_strober #(.WIDTH(8))
69     cic_strober(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(interp_rate),
70		 .strobe_fast(1),.strobe_slow(strobe_cic_pre) );
71   cic_strober #(.WIDTH(2))
72     hb2_strober(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(enable_hb2 ? 2 : 1),
73		 .strobe_fast(strobe_cic_pre),.strobe_slow(strobe_hb2_pre) );
74   cic_strober #(.WIDTH(2))
75     hb1_strober(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(enable_hb1 ? 2 : 1),
76		 .strobe_fast(strobe_hb2_pre),.strobe_slow(strobe_hb1_pre) );
77
78   always @(posedge clk) strobe_hb1 <= strobe_hb1_pre;
79   always @(posedge clk) strobe_hb2 <= strobe_hb2_pre;
80   always @(posedge clk) strobe_cic <= strobe_cic_pre;
81
82   // NCO
83   always @(posedge clk)
84     if(rst)
85       phase <= 0;
86     else if(~duc_enb)
87       phase <= 0;
88     else
89       phase <= phase + phase_inc;
90
91   wire        signed [17:0] da, db;
92   wire        signed [35:0] prod_i, prod_q;
93
94   wire [15:0] bb_i;
95   wire [15:0] bb_q;
96   wire [17:0] i_interp, q_interp;
97
98   wire [17:0] hb1_i, hb1_q, hb2_i, hb2_q;
99
100   wire [7:0]  cpo = enable_hb2 ? ({interp_rate,1'b0}) : interp_rate;
101   // Note that max CIC rate is 128, which would give an overflow on cpo if enable_hb2 is true,
102   //   but the default case inside hb_interp handles this
103
104   hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(WIDTH)) hb_interp_i
105     (.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in({bb_i, 2'b0}),.stb_out(strobe_hb2),.data_out(hb1_i));
106   hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(WIDTH)) hb_interp_q
107     (.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in({bb_q, 2'b0}),.stb_out(strobe_hb2),.data_out(hb1_q));
108
109   small_hb_int #(.WIDTH(18)) small_hb_interp_i
110     (.clk(clk),.rst(rst),.bypass(~enable_hb2),.stb_in(strobe_hb2),.data_in(hb1_i),
111      .output_rate(interp_rate),.stb_out(strobe_cic),.data_out(hb2_i));
112   small_hb_int #(.WIDTH(18)) small_hb_interp_q
113     (.clk(clk),.rst(rst),.bypass(~enable_hb2),.stb_in(strobe_hb2),.data_in(hb1_q),
114      .output_rate(interp_rate),.stb_out(strobe_cic),.data_out(hb2_q));
115
116   cic_interp  #(.bw(18),.N(4),.log2_of_max_rate(7))
117     cic_interp_i(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(interp_rate),
118		  .strobe_in(strobe_cic),.strobe_out(1),
119		  .signal_in(hb2_i),.signal_out(i_interp));
120
121   cic_interp  #(.bw(18),.N(4),.log2_of_max_rate(7))
122     cic_interp_q(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(interp_rate),
123		  .strobe_in(strobe_cic),.strobe_out(1),
124		  .signal_in(hb2_q),.signal_out(q_interp));
125
126   localparam  cwidth = WIDTH;  // was 18
127   localparam  zwidth = 24;  // was 16
128
129   wire [cwidth-1:0] da_c, db_c;
130
131   cordic_z24 #(.bitwidth(cwidth))
132     cordic(.clock(clk), .reset(rst), .enable(duc_enb),
133	    .xi({i_interp,{(cwidth-18){1'b0}}}),.yi({q_interp,{(cwidth-18){1'b0}}}),
134	    .zi(phase[31:32-zwidth]),
135	    .xo(da_c),.yo(db_c),.zo() );
136
137   MULT18X18S MULT18X18S_inst
138     (.P(prod_i),    // 36-bit multiplier output
139      .A(da_c[cwidth-1:cwidth-18]),    // 18-bit multiplier input
140      .B(scale_factor),    // 18-bit multiplier input
141      .C(clk),    // Clock input
142      .CE(1),  // Clock enable input
143      .R(rst)     // Synchronous reset input
144      );
145
146   MULT18X18S MULT18X18S_inst_2
147     (.P(prod_q),    // 36-bit multiplier output
148      .A(db_c[cwidth-1:cwidth-18]),    // 18-bit multiplier input
149      .B(scale_factor),    // 18-bit multiplier input
150      .C(clk),    // Clock input
151      .CE(1),  // Clock enable input
152      .R(rst)     // Synchronous reset input
153      );
154
155   dsp_tx_glue #(.DSPNO(DSPNO), .WIDTH(WIDTH)) dsp_tx_glue(
156    .clock(clk), .reset(rst), .clear(clr), .enable(run),
157    .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
158    .frontend_i(tx_fe_i), .frontend_q(tx_fe_q),
159    .duc_out_i(prod_i[33:34-WIDTH]), .duc_out_q(prod_q[33:34-WIDTH]),
160    .duc_in_sample({bb_i, bb_q}), .duc_in_strobe(strobe_hb1), .duc_in_enable(duc_enb),
161    .bb_sample(sample), .bb_strobe(strobe));
162
163   assign      debug = {strobe_cic, strobe_hb1, strobe_hb2,run};
164
165endmodule // dsp_core
166