summaryrefslogtreecommitdiffstats
path: root/fpga/usrp2/sdr_lib
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2011-07-08 12:17:54 -0700
committerJosh Blum <josh@joshknows.com>2011-07-08 12:17:54 -0700
commit17fabccfe4be79f3a5a0a3d7ab14ea72a791ecd9 (patch)
treee2d0d39d6b44b72c759b8be1380b2024de50bdf6 /fpga/usrp2/sdr_lib
parent60933a242cce0b1ec45e9f948e3da9ab72b2fd90 (diff)
parent4ea6f7431e09d9f27ecaa1c1b187d2c2f613e8f4 (diff)
downloaduhd-17fabccfe4be79f3a5a0a3d7ab14ea72a791ecd9.tar.gz
uhd-17fabccfe4be79f3a5a0a3d7ab14ea72a791ecd9.tar.bz2
uhd-17fabccfe4be79f3a5a0a3d7ab14ea72a791ecd9.zip
Merge branch 'fpga_next' into next
Diffstat (limited to 'fpga/usrp2/sdr_lib')
-rw-r--r--fpga/usrp2/sdr_lib/Makefile.srcs8
-rw-r--r--fpga/usrp2/sdr_lib/add2_and_clip.v12
-rw-r--r--fpga/usrp2/sdr_lib/add2_and_clip_reg.v25
-rw-r--r--fpga/usrp2/sdr_lib/dsp_core_rx.v135
-rw-r--r--fpga/usrp2/sdr_lib/dsp_core_rx_tb.v73
-rw-r--r--fpga/usrp2/sdr_lib/dsp_core_tx.v24
-rw-r--r--fpga/usrp2/sdr_lib/hb_dec.v121
-rw-r--r--fpga/usrp2/sdr_lib/hb_dec_tb.v10
-rw-r--r--fpga/usrp2/sdr_lib/input.dat276
-rw-r--r--fpga/usrp2/sdr_lib/round.v4
-rw-r--r--fpga/usrp2/sdr_lib/round_reg.v13
-rw-r--r--fpga/usrp2/sdr_lib/round_sd.v22
-rw-r--r--fpga/usrp2/sdr_lib/round_sd_tb.v58
-rw-r--r--fpga/usrp2/sdr_lib/rx_dcoffset.v43
-rw-r--r--fpga/usrp2/sdr_lib/rx_dcoffset_tb.v20
-rw-r--r--fpga/usrp2/sdr_lib/rx_frontend.v73
-rw-r--r--fpga/usrp2/sdr_lib/rx_frontend_tb.v45
-rw-r--r--fpga/usrp2/sdr_lib/small_hb_dec.v70
-rw-r--r--fpga/usrp2/sdr_lib/tx_frontend.v86
19 files changed, 659 insertions, 459 deletions
diff --git a/fpga/usrp2/sdr_lib/Makefile.srcs b/fpga/usrp2/sdr_lib/Makefile.srcs
index 90eede20f..defbced17 100644
--- a/fpga/usrp2/sdr_lib/Makefile.srcs
+++ b/fpga/usrp2/sdr_lib/Makefile.srcs
@@ -8,6 +8,8 @@
SDR_LIB_SRCS = $(abspath $(addprefix $(BASE_DIR)/../sdr_lib/, \
acc.v \
add2.v \
+add2_and_clip.v \
+add2_and_clip_reg.v \
add2_and_round.v \
add2_and_round_reg.v \
add2_reg.v \
@@ -22,16 +24,16 @@ cordic.v \
cordic_z24.v \
cordic_stage.v \
dsp_core_rx.v \
-dsp_core_rx_old.v \
dsp_core_tx.v \
hb_dec.v \
hb_interp.v \
round.v \
round_reg.v \
-rx_control.v \
+round_sd.v \
rx_dcoffset.v \
+rx_frontend.v \
sign_extend.v \
small_hb_dec.v \
small_hb_int.v \
-tx_control.v \
+tx_frontend.v \
))
diff --git a/fpga/usrp2/sdr_lib/add2_and_clip.v b/fpga/usrp2/sdr_lib/add2_and_clip.v
new file mode 100644
index 000000000..663f5d004
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/add2_and_clip.v
@@ -0,0 +1,12 @@
+
+module add2_and_clip
+ #(parameter WIDTH=16)
+ (input [WIDTH-1:0] in1,
+ input [WIDTH-1:0] in2,
+ output [WIDTH-1:0] sum);
+
+ wire [WIDTH:0] sum_int = {in1[WIDTH-1],in1} + {in2[WIDTH-1],in2};
+ clip #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip
+ (.in(sum_int),.out(sum));
+
+endmodule // add2_and_clip
diff --git a/fpga/usrp2/sdr_lib/add2_and_clip_reg.v b/fpga/usrp2/sdr_lib/add2_and_clip_reg.v
new file mode 100644
index 000000000..8073b3b54
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/add2_and_clip_reg.v
@@ -0,0 +1,25 @@
+
+module add2_and_clip_reg
+ #(parameter WIDTH=16)
+ (input clk,
+ input rst,
+ input [WIDTH-1:0] in1,
+ input [WIDTH-1:0] in2,
+ input strobe_in,
+ output reg [WIDTH-1:0] sum,
+ output reg strobe_out);
+
+ wire [WIDTH-1:0] sum_int;
+
+ add2_and_clip #(.WIDTH(WIDTH)) add2_and_clip (.in1(in1),.in2(in2),.sum(sum_int));
+
+ always @(posedge clk)
+ if(rst)
+ sum <= 0;
+ else if(strobe_in)
+ sum <= sum_int;
+
+ always @(posedge clk)
+ strobe_out <= strobe_in;
+
+endmodule // add2_and_clip_reg
diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx.v b/fpga/usrp2/sdr_lib/dsp_core_rx.v
index 0e69e53f7..639744de7 100644
--- a/fpga/usrp2/sdr_lib/dsp_core_rx.v
+++ b/fpga/usrp2/sdr_lib/dsp_core_rx.v
@@ -21,8 +21,8 @@ module dsp_core_rx
(input clk, input rst,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
- input [13:0] adc_a, input adc_ovf_a,
- input [13:0] adc_b, input adc_ovf_b,
+ input [23:0] adc_i, input adc_ovf_i,
+ input [23:0] adc_q, input adc_ovf_q,
output [31:0] sample,
input run,
@@ -30,70 +30,56 @@ module dsp_core_rx
output [31:0] debug
);
- wire [15:0] scale_i, scale_q;
- wire [13:0] adc_a_ofs, adc_b_ofs;
- reg [13:0] adc_i, adc_q;
wire [31:0] phase_inc;
reg [31:0] phase;
- wire [35:0] prod_i, prod_q;
- wire [23:0] i_cordic, q_cordic;
+ wire [24:0] i_cordic, q_cordic;
+ wire [23:0] i_cordic_clip, q_cordic_clip;
wire [23:0] i_cic, q_cic;
- wire [17:0] i_cic_scaled, q_cic_scaled;
- wire [17:0] i_hb1, q_hb1;
- wire [17:0] i_hb2, q_hb2;
- wire [15:0] i_out, q_out;
-
+ wire [23:0] i_hb1, q_hb1;
+ wire [23:0] i_hb2, q_hb2;
+
wire strobe_cic, strobe_hb1, strobe_hb2;
wire enable_hb1, enable_hb2;
wire [7:0] cic_decim_rate;
+ reg [23:0] adc_i_mux, adc_q_mux;
+ wire realmode;
+ wire swap_iq;
+
setting_reg #(.my_addr(BASE+0)) sr_0
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(phase_inc),.changed());
+ /*
setting_reg #(.my_addr(BASE+1)) sr_1
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({scale_i,scale_q}),.changed());
+ */
setting_reg #(.my_addr(BASE+2), .width(10)) sr_2
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({enable_hb1, enable_hb2, cic_decim_rate}),.changed());
- rx_dcoffset #(.WIDTH(14),.ADDR(BASE+3)) rx_dcoffset_a
- (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
- .adc_in(adc_a),.adc_out(adc_a_ofs));
-
- rx_dcoffset #(.WIDTH(14),.ADDR(BASE+4)) rx_dcoffset_b
- (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
- .adc_in(adc_b),.adc_out(adc_b_ofs));
-
- wire [7:0] muxctrl;
- setting_reg #(.my_addr(BASE+5), .width(8)) sr_8
- (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out(muxctrl),.changed());
-
- wire [1:0] gpio_ena;
- setting_reg #(.my_addr(BASE+6), .width(2)) sr_9
+ setting_reg #(.my_addr(BASE+3), .width(2)) sr_3
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out(gpio_ena),.changed());
+ .in(set_data),.out({realmode,swap_iq}),.changed());
- always @(posedge clk)
- case(muxctrl[3:0]) // The I mapping
- 0: adc_i <= adc_a_ofs;
- 1: adc_i <= adc_b_ofs;
- 2: adc_i <= 0;
- default: adc_i <= 0;
- endcase // case (muxctrl[3:0])
+ // MUX so we can do realmode signals on either input
always @(posedge clk)
- case(muxctrl[7:4]) // The Q mapping
- 0: adc_q <= adc_a_ofs;
- 1: adc_q <= adc_b_ofs;
- 2: adc_q <= 0;
- default: adc_q <= 0;
- endcase // case (muxctrl[7:4])
-
+ if(swap_iq)
+ begin
+ adc_i_mux <= adc_q;
+ adc_q_mux <= realmode ? 24'd0 : adc_i;
+ end
+ else
+ begin
+ adc_i_mux <= adc_i;
+ adc_q_mux <= realmode ? 24'd0 : adc_q;
+ end
+
+ // NCO
always @(posedge clk)
if(rst)
phase <= 0;
@@ -102,74 +88,55 @@ module dsp_core_rx
else
phase <= phase + phase_inc;
- MULT18X18S mult_i
- (.P(prod_i), // 36-bit multiplier output
- .A({{4{adc_i[13]}},adc_i} ), // 18-bit multiplier input
- .B({{2{scale_i[15]}},scale_i}), // 18-bit multiplier input
- .C(clk), // Clock input
- .CE(1), // Clock enable input
- .R(rst) // Synchronous reset input
- );
-
- MULT18X18S mult_q
- (.P(prod_q), // 36-bit multiplier output
- .A({{4{adc_q[13]}},adc_q} ), // 18-bit multiplier input
- .B({{2{scale_q[15]}},scale_q}), // 18-bit multiplier input
- .C(clk), // Clock input
- .CE(1), // Clock enable input
- .R(rst) // Synchronous reset input
- );
-
-
- cordic_z24 #(.bitwidth(24))
+ // CORDIC 24-bit I/O
+ cordic_z24 #(.bitwidth(25))
cordic(.clock(clk), .reset(rst), .enable(run),
- .xi(prod_i[23:0]),. yi(prod_q[23:0]), .zi(phase[31:8]),
+ .xi({adc_i_mux[23],adc_i_mux}),. yi({adc_q_mux[23],adc_q_mux}), .zi(phase[31:8]),
.xo(i_cordic),.yo(q_cordic),.zo() );
+ clip_reg #(.bits_in(25), .bits_out(24)) clip_i (.clk(clk), .in(i_cordic), .out(i_cordic_clip));
+ clip_reg #(.bits_in(25), .bits_out(24)) clip_q (.clk(clk), .in(q_cordic), .out(q_cordic_clip));
+
+ // CIC decimator 24 bit I/O
cic_strober cic_strober(.clock(clk),.reset(rst),.enable(run),.rate(cic_decim_rate),
.strobe_fast(1),.strobe_slow(strobe_cic) );
cic_decim #(.bw(24))
decim_i (.clock(clk),.reset(rst),.enable(run),
.rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic),
- .signal_in(i_cordic),.signal_out(i_cic));
+ .signal_in(i_cordic_clip),.signal_out(i_cic));
cic_decim #(.bw(24))
decim_q (.clock(clk),.reset(rst),.enable(run),
.rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic),
- .signal_in(q_cordic),.signal_out(q_cic));
+ .signal_in(q_cordic_clip),.signal_out(q_cic));
- round_reg #(.bits_in(24),.bits_out(18)) round_icic (.clk(clk),.in(i_cic),.out(i_cic_scaled));
- round_reg #(.bits_in(24),.bits_out(18)) round_qcic (.clk(clk),.in(q_cic),.out(q_cic_scaled));
- reg strobe_cic_d1;
- always @(posedge clk) strobe_cic_d1 <= strobe_cic;
-
- small_hb_dec #(.WIDTH(18)) small_hb_i
+ // First (small) halfband 24 bit I/O
+ small_hb_dec #(.WIDTH(24)) small_hb_i
(.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run),
- .stb_in(strobe_cic_d1),.data_in(i_cic_scaled),.stb_out(strobe_hb1),.data_out(i_hb1));
+ .stb_in(strobe_cic),.data_in(i_cic),.stb_out(strobe_hb1),.data_out(i_hb1));
- small_hb_dec #(.WIDTH(18)) small_hb_q
+ small_hb_dec #(.WIDTH(24)) small_hb_q
(.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run),
- .stb_in(strobe_cic_d1),.data_in(q_cic_scaled),.stb_out(),.data_out(q_hb1));
+ .stb_in(strobe_cic),.data_in(q_cic),.stb_out(),.data_out(q_hb1));
+ // Second (large) halfband 24 bit I/O
wire [8:0] cpi_hb = enable_hb1 ? {cic_decim_rate,1'b0} : {1'b0,cic_decim_rate};
- hb_dec #(.IWIDTH(18), .OWIDTH(18), .CWIDTH(18), .ACCWIDTH(24)) hb_i
+ hb_dec #(.WIDTH(24)) hb_i
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb),
.stb_in(strobe_hb1),.data_in(i_hb1),.stb_out(strobe_hb2),.data_out(i_hb2));
- hb_dec #(.IWIDTH(18), .OWIDTH(18), .CWIDTH(18), .ACCWIDTH(24)) hb_q
+ hb_dec #(.WIDTH(24)) hb_q
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb),
.stb_in(strobe_hb1),.data_in(q_hb1),.stb_out(),.data_out(q_hb2));
- round #(.bits_in(18),.bits_out(16)) round_iout (.in(i_hb2),.out(i_out));
- round #(.bits_in(18),.bits_out(16)) round_qout (.in(q_hb2),.out(q_out));
+ // Round final answer to 16 bits
+ round_sd #(.WIDTH_IN(24),.WIDTH_OUT(16)) round_i
+ (.clk(clk),.reset(rst), .in(i_hb2),.strobe_in(strobe_hb2), .out(sample[31:16]), .strobe_out(strobe));
- reg [31:0] sample_reg;
- always @(posedge clk)
- sample_reg <= {i_out,q_out};
+ round_sd #(.WIDTH_IN(24),.WIDTH_OUT(16)) round_q
+ (.clk(clk),.reset(rst), .in(q_hb2),.strobe_in(strobe_hb2), .out(sample[15:0]), .strobe_out());
- assign sample = sample_reg;
- assign strobe = strobe_hb2;
- assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_cic_d1, strobe_hb1, strobe_hb2};
+ assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_hb1, strobe_hb2};
endmodule // dsp_core_rx
diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v b/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v
new file mode 100644
index 000000000..271db8cef
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v
@@ -0,0 +1,73 @@
+
+`timescale 1ns/1ns
+module dsp_core_rx_tb();
+
+ reg clk, rst;
+
+ initial rst = 1;
+ initial #1000 rst = 0;
+ initial clk = 0;
+ always #5 clk = ~clk;
+
+ initial $dumpfile("dsp_core_rx_tb.vcd");
+ initial $dumpvars(0,dsp_core_rx_tb);
+
+ reg signed [23:0] adc_in;
+ wire signed [15:0] adc_out_i, adc_out_q;
+
+ always @(posedge clk)
+ begin
+ $display(adc_in);
+ $display(adc_out_i);
+ $display(adc_out_q);
+ end
+
+ reg run;
+ reg set_stb;
+ reg [7:0] set_addr;
+ reg [31:0] set_data;
+
+ dsp_core_rx #(.BASE(0)) dsp_core_rx
+ (.clk(clk),.rst(rst),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .adc_i(adc_in), .adc_ovf_i(0),
+ .adc_q(0), .adc_ovf_q(0),
+ .sample({adc_out_i,adc_out_q}),
+ .run(run), .strobe(), .debug());
+
+ initial
+ begin
+ run <= 0;
+ @(negedge rst);
+ @(posedge clk);
+ set_addr <= 1;
+ set_data <= {16'd64,16'd64}; // set gains
+ set_stb <= 1;
+ @(posedge clk);
+ set_addr <= 2;
+ set_data <= {16'd0,8'd3,8'd1}; // set decim
+ set_stb <= 1;
+ @(posedge clk);
+ set_addr <= 0;
+ //set_data <= {32'h0000_0000};
+ set_data <= {32'h01CA_C083}; // 700 kHz
+ set_stb <= 1;
+ @(posedge clk);
+ set_stb <= 0;
+ @(posedge clk);
+ run <= 1;
+ end
+
+ always @(posedge clk)
+ //adc_in <= 24'd1000000;
+ adc_in <= 24'h80_0000;
+
+ /*
+ always @(posedge clk)
+ if(rst)
+ adc_in <= 0;
+ else
+ adc_in <= adc_in + 4;
+ //adc_in <= (($random % 473) + 23)/4;
+*/
+endmodule // dsp_core_rx_tb
diff --git a/fpga/usrp2/sdr_lib/dsp_core_tx.v b/fpga/usrp2/sdr_lib/dsp_core_tx.v
index 58bd82f6e..f02c63b42 100644
--- a/fpga/usrp2/sdr_lib/dsp_core_tx.v
+++ b/fpga/usrp2/sdr_lib/dsp_core_tx.v
@@ -21,8 +21,7 @@ module dsp_core_tx
(input clk, input rst,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
- output reg [15:0] dac_a,
- output reg [15:0] dac_b,
+ output [23:0] tx_i, output [23:0] tx_q,
// To tx_control
input [31:0] sample,
@@ -50,10 +49,6 @@ module dsp_core_tx
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({enable_hb1, enable_hb2, interp_rate}),.changed());
- setting_reg #(.my_addr(BASE+4), .width(8)) sr_4
- (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out({dacmux_b,dacmux_a}),.changed());
-
// Strobes are all now delayed by 1 cycle for timing reasons
wire strobe_cic_pre, strobe_hb1_pre, strobe_hb2_pre;
reg strobe_cic = 1;
@@ -148,20 +143,9 @@ module dsp_core_tx
.CE(1), // Clock enable input
.R(rst) // Synchronous reset input
);
-
- always @(posedge clk)
- case(dacmux_a)
- 0 : dac_a <= prod_i[28:13];
- 1 : dac_a <= prod_q[28:13];
- default : dac_a <= 0;
- endcase // case(dacmux_a)
-
- always @(posedge clk)
- case(dacmux_b)
- 0 : dac_b <= prod_i[28:13];
- 1 : dac_b <= prod_q[28:13];
- default : dac_b <= 0;
- endcase // case(dacmux_b)
+
+ assign tx_i = prod_i[28:5];
+ assign tx_q = prod_q[28:5];
assign debug = {strobe_cic, strobe_hb1, strobe_hb2,run};
diff --git a/fpga/usrp2/sdr_lib/hb_dec.v b/fpga/usrp2/sdr_lib/hb_dec.v
index 9747f0adb..8d21c21c0 100644
--- a/fpga/usrp2/sdr_lib/hb_dec.v
+++ b/fpga/usrp2/sdr_lib/hb_dec.v
@@ -22,17 +22,27 @@
// myfilt = round(2^18 * halfgen4(.7/4,8))
module hb_dec
- #(parameter IWIDTH=18, OWIDTH=18, CWIDTH=18, ACCWIDTH=24)
+ #(parameter WIDTH=24)
(input clk,
input rst,
input bypass,
input run,
input [8:0] cpi, // Clocks per input -- equal to the decimation ratio ahead of this block
input stb_in,
- input [IWIDTH-1:0] data_in,
+ input [WIDTH-1:0] data_in,
output reg stb_out,
- output reg [OWIDTH-1:0] data_out);
+ output reg [WIDTH-1:0] data_out);
+ localparam INTWIDTH = 17;
+ localparam ACCWIDTH = WIDTH + 3;
+
+ // Round off inputs to 17 bits because of 18 bit multipliers
+ wire [INTWIDTH-1:0] data_rnd;
+ wire stb_rnd;
+
+ round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(INTWIDTH)) round_in
+ (.clk(clk),.reset(rst),.in(data_in),.strobe_in(stb_in),.out(data_rnd),.strobe_out(stb_rnd));
+
// Control
reg [3:0] addr_odd_a, addr_odd_b, addr_odd_c, addr_odd_d;
wire write_odd, write_even, do_mult;
@@ -45,16 +55,16 @@ module hb_dec
always @(posedge clk)
if(rst | ~run)
odd <= 0;
- else if(stb_in)
+ else if(stb_rnd)
odd <= ~odd;
- assign write_odd = stb_in & odd;
- assign write_even = stb_in & ~odd;
+ assign write_odd = stb_rnd & odd;
+ assign write_even = stb_rnd & ~odd;
always @(posedge clk)
if(rst | ~run)
phase <= 0;
- else if(stb_in & odd)
+ else if(stb_rnd & odd)
phase <= 1;
else if(phase == 4)
phase <= 0;
@@ -69,7 +79,7 @@ module hb_dec
if(rst)
stb_out_pre <= 0;
else
- stb_out_pre <= {stb_out_pre[14:0],(stb_in & odd)};
+ stb_out_pre <= {stb_out_pre[14:0],(stb_rnd & odd)};
always @*
case(phase)
@@ -93,11 +103,12 @@ module hb_dec
assign clear = stb_out_pre[3];
// Data
- wire [IWIDTH-1:0] data_odd_a, data_odd_b, data_odd_c, data_odd_d;
- wire [IWIDTH-1:0] sum1, sum2;
- wire [OWIDTH-1:0] final_sum;
- reg [CWIDTH-1:0] coeff1, coeff2;
- wire [35:0] prod1, prod2;
+ wire [INTWIDTH-1:0] data_odd_a, data_odd_b, data_odd_c, data_odd_d;
+ reg [INTWIDTH:0] sum1, sum2; // these are 18-bit inputs to mult
+ reg [WIDTH:0] final_sum;
+ wire [WIDTH-1:0] final_sum_clip;
+ reg [17:0] coeff1, coeff2;
+ wire [35:0] prod1, prod2;
always @* // Outer coeffs
case(phase_d1)
@@ -117,19 +128,19 @@ module hb_dec
default : coeff2 = -6107;
endcase // case(phase)
- srl #(.WIDTH(IWIDTH)) srl_odd_a
- (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_a),.out(data_odd_a));
- srl #(.WIDTH(IWIDTH)) srl_odd_b
- (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_b),.out(data_odd_b));
- srl #(.WIDTH(IWIDTH)) srl_odd_c
- (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_c),.out(data_odd_c));
- srl #(.WIDTH(IWIDTH)) srl_odd_d
- (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_d),.out(data_odd_d));
-
- add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add1 (.clk(clk),.in1(data_odd_a),.in2(data_odd_b),.sum(sum1));
- add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add2 (.clk(clk),.in1(data_odd_c),.in2(data_odd_d),.sum(sum2));
-
- wire [IWIDTH-1:0] data_even;
+ srl #(.WIDTH(INTWIDTH)) srl_odd_a
+ (.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_a),.out(data_odd_a));
+ srl #(.WIDTH(INTWIDTH)) srl_odd_b
+ (.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_b),.out(data_odd_b));
+ srl #(.WIDTH(INTWIDTH)) srl_odd_c
+ (.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_c),.out(data_odd_c));
+ srl #(.WIDTH(INTWIDTH)) srl_odd_d
+ (.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_d),.out(data_odd_d));
+
+ always @(posedge clk) sum1 <= {data_odd_a[INTWIDTH-1],data_odd_a} + {data_odd_b[INTWIDTH-1],data_odd_b};
+ always @(posedge clk) sum2 <= {data_odd_c[INTWIDTH-1],data_odd_c} + {data_odd_d[INTWIDTH-1],data_odd_d};
+
+ wire [INTWIDTH-1:0] data_even;
reg [3:0] addr_even;
always @(posedge clk)
@@ -140,49 +151,39 @@ module hb_dec
default : addr_even <= 7;
endcase // case(cpi)
- srl #(.WIDTH(IWIDTH)) srl_even
- (.clk(clk),.write(write_even),.in(data_in),.addr(addr_even),.out(data_even));
-
- localparam MWIDTH = ACCWIDTH-2;
- wire [MWIDTH-1:0] sum_of_prod;
+ srl #(.WIDTH(INTWIDTH)) srl_even
+ (.clk(clk),.write(write_even),.in(data_rnd),.addr(addr_even),.out(data_even));
MULT18X18S mult1(.C(clk), .CE(do_mult), .R(rst), .P(prod1), .A(coeff1), .B(sum1) );
MULT18X18S mult2(.C(clk), .CE(do_mult), .R(rst), .P(prod2), .A(coeff2), .B(sum2) );
- add2_and_round_reg #(.WIDTH(MWIDTH))
- add3 (.clk(clk),.in1(prod1[35:36-MWIDTH]),.in2(prod2[35:36-MWIDTH]),.sum(sum_of_prod));
- wire [ACCWIDTH-1:0] acc_out;
+ reg [35:0] sum_of_prod;
+ always @(posedge clk) sum_of_prod <= prod1 + prod2; // Can't overflow
- acc #(.IWIDTH(MWIDTH),.OWIDTH(ACCWIDTH))
- acc (.clk(clk),.clear(clear),.acc(do_acc),.in(sum_of_prod),.out(acc_out));
+ wire [ACCWIDTH-1:0] acc_out;
+ acc #(.IWIDTH(ACCWIDTH-2),.OWIDTH(ACCWIDTH))
+ acc (.clk(clk),.clear(clear),.acc(do_acc),.in(sum_of_prod[35:38-ACCWIDTH]),.out(acc_out));
- localparam SHIFT_FACTOR = ACCWIDTH-IWIDTH-5;
wire [ACCWIDTH-1:0] data_even_signext;
- wire [ACCWIDTH:0] final_sum_unrounded;
- sign_extend #(.bits_in(IWIDTH),.bits_out(ACCWIDTH-SHIFT_FACTOR))
- signext_data_even (.in(data_even),.out(data_even_signext[ACCWIDTH-1:SHIFT_FACTOR]));
- assign data_even_signext[SHIFT_FACTOR-1:0] = 0;
+ localparam SHIFT_FACTOR = 6;
- add2_reg /* add2_and_round_reg */ #(.WIDTH(ACCWIDTH+1))
- final_adder (.clk(clk), .in1({acc_out,1'b0}), .in2({data_even_signext,1'b0}), .sum(final_sum_unrounded));
-
- round_reg #(.bits_in(ACCWIDTH-4),.bits_out(OWIDTH))
- final_round (.clk(clk),.in(final_sum_unrounded[ACCWIDTH-5:0]),.out(final_sum));
-
- // Output
- always @(posedge clk)
- if(bypass)
- data_out <= data_in;
- else if(stb_out_pre[9])
- data_out <= final_sum;
+ sign_extend #(.bits_in(INTWIDTH),.bits_out(ACCWIDTH-SHIFT_FACTOR)) signext_data_even
+ (.in(data_even),.out(data_even_signext[ACCWIDTH-1:SHIFT_FACTOR]));
+ assign data_even_signext[SHIFT_FACTOR-1:0] = 0;
+ always @(posedge clk) final_sum <= acc_out + data_even_signext;
+
+ clip #(.bits_in(WIDTH+1), .bits_out(WIDTH)) clip (.in(final_sum), .out(final_sum_clip));
+
+ // Output MUX to allow for bypass
+ wire selected_stb = bypass ? stb_in : stb_out_pre[8];
+
always @(posedge clk)
- if(rst)
- stb_out <= 0;
- else if(bypass)
- stb_out <= stb_in;
- else
- stb_out <= stb_out_pre[9];
-
+ begin
+ stb_out <= selected_stb;
+ if(selected_stb)
+ data_out <= bypass ? data_in : final_sum_clip;
+ end
+
endmodule // hb_dec
diff --git a/fpga/usrp2/sdr_lib/hb_dec_tb.v b/fpga/usrp2/sdr_lib/hb_dec_tb.v
index 256f6085d..153cfba76 100644
--- a/fpga/usrp2/sdr_lib/hb_dec_tb.v
+++ b/fpga/usrp2/sdr_lib/hb_dec_tb.v
@@ -18,7 +18,7 @@
module hb_dec_tb( ) ;
// Parameters for instantiation
- parameter clocks = 9'd2 ; // Number of clocks per input
+ parameter clocks = 9'd12 ; // Number of clocks per input
parameter decim = 1 ; // Sets the filter to decimate
parameter rate = 2 ; // Sets the decimation rate
@@ -26,9 +26,9 @@ module hb_dec_tb( ) ;
reg reset ;
reg enable ;
reg strobe_in ;
- reg signed [17:0] data_in ;
+ reg signed [23:0] data_in ;
wire strobe_out ;
- wire signed [17:0] data_out ;
+ wire signed [23:0] data_out ;
initial
begin
@@ -65,8 +65,8 @@ module hb_dec_tb( ) ;
*/
- hb_dec #(.IWIDTH(18),.OWIDTH(18),.CWIDTH(18),.ACCWIDTH(24)) uut
- (.clk(clock),.rst(reset),.bypass(0),.cpi(clocks),.stb_in(strobe_in),.data_in(data_in),
+ hb_dec #(.WIDTH(24)) uut
+ (.clk(clock),.rst(reset),.bypass(0),.run(1),.cpi(clocks),.stb_in(strobe_in),.data_in(data_in),
.stb_out(strobe_out),.data_out(data_out) );
integer i, ri, ro, infile, outfile ;
diff --git a/fpga/usrp2/sdr_lib/input.dat b/fpga/usrp2/sdr_lib/input.dat
index 1e649ac2e..85b5887e8 100644
--- a/fpga/usrp2/sdr_lib/input.dat
+++ b/fpga/usrp2/sdr_lib/input.dat
@@ -6,7 +6,6 @@
0
0
0
--131072
0
0
0
@@ -16,6 +15,7 @@
0
0
0
+8388607
0
0
0
@@ -38,34 +38,6 @@
0
0
0
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
0
0
0
@@ -82,6 +54,7 @@
0
0
0
+8388607
0
0
0
@@ -96,200 +69,6 @@
0
0
0
-131071
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-100000
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
--131072
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
-0
-0
0
0
0
@@ -313,6 +92,56 @@
0
0
0
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
0
0
0
@@ -339,3 +168,4 @@
0
0
0
+
diff --git a/fpga/usrp2/sdr_lib/round.v b/fpga/usrp2/sdr_lib/round.v
index c4f9ec9cd..7a137d702 100644
--- a/fpga/usrp2/sdr_lib/round.v
+++ b/fpga/usrp2/sdr_lib/round.v
@@ -26,8 +26,10 @@ module round
#(parameter bits_in=0,
parameter bits_out=0)
(input [bits_in-1:0] in,
- output [bits_out-1:0] out);
+ output [bits_out-1:0] out,
+ output [bits_in-bits_out:0] err);
assign out = in[bits_in-1:bits_in-bits_out] + (in[bits_in-1] & |in[bits_in-bits_out-1:0]);
+ assign err = in - {out,{(bits_in-bits_out){1'b0}}};
endmodule // round
diff --git a/fpga/usrp2/sdr_lib/round_reg.v b/fpga/usrp2/sdr_lib/round_reg.v
index aa0972dab..6f2e974d7 100644
--- a/fpga/usrp2/sdr_lib/round_reg.v
+++ b/fpga/usrp2/sdr_lib/round_reg.v
@@ -27,13 +27,18 @@ module round_reg
parameter bits_out=0)
(input clk,
input [bits_in-1:0] in,
- output reg [bits_out-1:0] out);
+ output reg [bits_out-1:0] out,
+ output reg [bits_in-bits_out:0] err);
wire [bits_out-1:0] temp;
-
- round #(.bits_in(bits_in),.bits_out(bits_out)) round (.in(in),.out(temp));
+ wire [bits_in-bits_out:0] err_temp;
+
+ round #(.bits_in(bits_in),.bits_out(bits_out)) round (.in(in),.out(temp), .err(err_temp));
always @(posedge clk)
out <= temp;
+
+ always @(posedge clk)
+ err <= err_temp;
-endmodule // round
+endmodule // round_reg
diff --git a/fpga/usrp2/sdr_lib/round_sd.v b/fpga/usrp2/sdr_lib/round_sd.v
new file mode 100644
index 000000000..aeeb3502f
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/round_sd.v
@@ -0,0 +1,22 @@
+
+
+module round_sd
+ #(parameter WIDTH_IN=18,
+ parameter WIDTH_OUT=16)
+ (input clk, input reset,
+ input [WIDTH_IN-1:0] in, input strobe_in,
+ output [WIDTH_OUT-1:0] out, output strobe_out);
+
+ localparam ERR_WIDTH = WIDTH_IN - WIDTH_OUT + 1;
+
+ wire [ERR_WIDTH-1:0] err;
+ wire [WIDTH_IN-1:0] err_ext, sum;
+
+ sign_extend #(.bits_in(ERR_WIDTH),.bits_out(WIDTH_IN)) ext_err (.in(err), .out(err_ext));
+
+ add2_and_clip_reg #(.WIDTH(WIDTH_IN)) add2_and_clip_reg
+ (.clk(clk), .rst(reset), .in1(in), .in2(err_ext), .strobe_in(strobe_in), .sum(sum), .strobe_out(strobe_out));
+
+ round #(.bits_in(WIDTH_IN),.bits_out(WIDTH_OUT)) round_sum (.in(sum), .out(out), .err(err));
+
+endmodule // round_sd
diff --git a/fpga/usrp2/sdr_lib/round_sd_tb.v b/fpga/usrp2/sdr_lib/round_sd_tb.v
new file mode 100644
index 000000000..1e8e9a323
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/round_sd_tb.v
@@ -0,0 +1,58 @@
+
+module round_sd_tb();
+
+ reg clk, rst;
+
+ initial rst = 1;
+ initial #1000 rst = 0;
+ initial clk = 0;
+ always #5 clk = ~clk;
+
+ initial $dumpfile("round_sd_tb.vcd");
+ initial $dumpvars(0,round_sd_tb);
+
+ localparam WIDTH_IN = 8;
+ localparam WIDTH_OUT = 5;
+
+ reg [WIDTH_IN-1:0] adc_in, adc_in_del;
+ wire [WIDTH_OUT-1:0] adc_out;
+
+ integer factor = 1<<(WIDTH_IN-WIDTH_OUT);
+
+ always @(posedge clk)
+ if(~rst)
+ begin
+ if(adc_in_del[WIDTH_IN-1])
+ $write("-%d\t",-adc_in_del);
+ else
+ $write("%d\t",adc_in_del);
+ if(adc_out[WIDTH_OUT-1])
+ $write("-%d\t",-adc_out);
+ else
+ $write("%d\t",adc_out);
+ $write("\n");
+
+ //$write("%f\t",adc_in_del/factor);
+ //$write("%f\n",adc_in_del/factor-adc_out);
+ end
+
+ round_sd #(.WIDTH_IN(WIDTH_IN),.WIDTH_OUT(WIDTH_OUT))
+ round_sd(.clk(clk),.reset(rst), .in(adc_in), .strobe_in(1'b1), .out(adc_out), .strobe_out());
+
+ reg [5:0] counter = 0;
+
+ always @(posedge clk)
+ counter <= counter+1;
+
+ always @(posedge clk)
+ adc_in_del <= adc_in;
+
+ always @(posedge clk)
+ if(rst)
+ adc_in <= 0;
+ else if(counter == 63)
+ adc_in <= adc_in + 1;
+
+ initial #300000 $finish;
+
+endmodule // longfifo_tb
diff --git a/fpga/usrp2/sdr_lib/rx_dcoffset.v b/fpga/usrp2/sdr_lib/rx_dcoffset.v
index 64ff4110d..e43461261 100644
--- a/fpga/usrp2/sdr_lib/rx_dcoffset.v
+++ b/fpga/usrp2/sdr_lib/rx_dcoffset.v
@@ -18,43 +18,40 @@
module rx_dcoffset
- #(parameter WIDTH=14,
- parameter ADDR=8'd0)
- (input clk, input rst,
- input set_stb, input [7:0] set_addr, input [31:0] set_data,
- input signed [WIDTH-1:0] adc_in, output signed [WIDTH-1:0] adc_out);
-
- // Because of some extra delays to make timing easier, the transfer function is:
- // (z-1)/(z^2-z-alpha) where alpha is 1/2^n
+ #(parameter WIDTH=16,
+ parameter ADDR=8'd0,
+ parameter alpha_shift=16)
+ (input clk, input rst,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ input [WIDTH-1:0] in, output [WIDTH-1:0] out);
- wire set_now = set_stb & (ADDR == set_addr);
+ wire set_now = set_stb & (ADDR == set_addr);
- reg fixed; // uses fixed offset
- wire signed [WIDTH-1:0] fixed_dco;
- reg signed [31:0] integrator;
+ reg fixed; // uses fixed offset
+ wire [WIDTH-1:0] fixed_dco;
+
+ localparam int_width = WIDTH + alpha_shift;
+ reg [int_width-1:0] integrator;
+ wire [WIDTH-1:0] quantized;
always @(posedge clk)
if(rst)
begin
fixed <= 0;
- integrator <= 32'd0;
+ integrator <= {int_width{1'b0}};
end
else if(set_now)
begin
- integrator <= {set_data[WIDTH-1:0],{(32-WIDTH){1'b0}}};
+ //integrator <= {set_data[30:0],{(31-int_width){1'b0}}};
fixed <= set_data[31];
end
else if(~fixed)
- integrator <= integrator + adc_out;
-
- wire [WIDTH:0] scaled_integrator;
-
- round #(.bits_in(33),.bits_out(15)) round (.in({integrator[31],integrator}),.out(scaled_integrator));
-
- wire [WIDTH:0] adc_out_int = {adc_in[WIDTH-1],adc_in} - scaled_integrator;
+ integrator <= integrator + {{(alpha_shift){out[WIDTH-1]}},out};
- clip_reg #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip_adc
- (.clk(clk),.in(adc_out_int),.out(adc_out));
+ round_sd #(.WIDTH_IN(int_width),.WIDTH_OUT(WIDTH)) round_sd
+ (.clk(clk), .reset(rst), .in(integrator), .strobe_in(1'b1), .out(quantized), .strobe_out());
+ add2_and_clip_reg #(.WIDTH(WIDTH)) add2_and_clip_reg
+ (.clk(clk), .rst(rst), .in1(in), .in2(-quantized), .strobe_in(1'b1), .sum(out), .strobe_out());
endmodule // rx_dcoffset
diff --git a/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v b/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v
index b0dd8cb05..b4fb66ad7 100644
--- a/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v
+++ b/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v
@@ -29,14 +29,26 @@ module rx_dcoffset_tb();
initial $dumpfile("rx_dcoffset_tb.vcd");
initial $dumpvars(0,rx_dcoffset_tb);
- reg [13:0] adc_in = 7;
+ reg [13:0] adc_in;
wire [13:0] adc_out;
always @(posedge clk)
- $display("%d\t%d",adc_in,adc_out);
+ begin
+ if(adc_in[13])
+ $write("-%d,",-adc_in);
+ else
+ $write("%d,",adc_in);
+ if(adc_out[13])
+ $write("-%d\n",-adc_out);
+ else
+ $write("%d\n",adc_out);
+ end
- rx_dcoffset #(.WIDTH(14),.ADDR(0))
+ rx_dcoffset #(.WIDTH(14),.ADDR(0), .alpha_shift(8))
rx_dcoffset(.clk(clk),.rst(rst),.set_stb(0),.set_addr(0),.set_data(0),
- .adc_in(adc_in),.adc_out(adc_out));
+ .in(adc_in),.out(adc_out));
+
+ always @(posedge clk)
+ adc_in <= (($random % 473) + 23)/4;
endmodule // longfifo_tb
diff --git a/fpga/usrp2/sdr_lib/rx_frontend.v b/fpga/usrp2/sdr_lib/rx_frontend.v
new file mode 100644
index 000000000..04b14787e
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/rx_frontend.v
@@ -0,0 +1,73 @@
+
+module rx_frontend
+ #(parameter BASE = 0)
+ (input clk, input rst,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ input [15:0] adc_a, input adc_ovf_a,
+ input [15:0] adc_b, input adc_ovf_b,
+
+ output [23:0] i_out, output [23:0] q_out,
+ input run,
+ output [31:0] debug
+ );
+
+ reg [15:0] adc_i, adc_q;
+ wire [17:0] adc_i_ofs, adc_q_ofs;
+ wire [35:0] corr_i, corr_q; wire [17:0] mag_corr,phase_corr;
+ wire swap_iq;
+ wire [23:0] i_final, q_final;
+
+ setting_reg #(.my_addr(BASE), .width(1)) sr_8
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(swap_iq),.changed());
+
+ always @(posedge clk)
+ if(swap_iq) // Swap
+ {adc_i,adc_q} <= {adc_b,adc_a};
+ else
+ {adc_i,adc_q} <= {adc_a,adc_b};
+
+ setting_reg #(.my_addr(BASE+1),.width(18)) sr_1
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(mag_corr),.changed());
+
+ setting_reg #(.my_addr(BASE+2),.width(18)) sr_2
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(phase_corr),.changed());
+
+ rx_dcoffset #(.WIDTH(18),.ADDR(BASE+3)) rx_dcoffset_i
+ (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .in({adc_i,2'b00}),.out(adc_i_ofs));
+
+ rx_dcoffset #(.WIDTH(18),.ADDR(BASE+4)) rx_dcoffset_q
+ (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .in({adc_q,2'b00}),.out(adc_q_ofs));
+
+ MULT18X18S mult_mag_corr
+ (.P(corr_i), .A(adc_i_ofs), .B(mag_corr), .C(clk), .CE(1), .R(rst) );
+
+ MULT18X18S mult_phase_corr
+ (.P(corr_q), .A(adc_i_ofs), .B(phase_corr), .C(clk), .CE(1), .R(rst) );
+
+ add2_and_clip_reg #(.WIDTH(24)) add_clip_i
+ (.clk(clk), .rst(rst),
+ .in1({adc_i_ofs,6'd0}), .in2({{4{corr_i[35]}},corr_i[35:16]}), .strobe_in(1'b1),
+ .sum(i_final), .strobe_out());
+
+ add2_and_clip_reg #(.WIDTH(24)) add_clip_q
+ (.clk(clk), .rst(rst),
+ .in1({adc_q_ofs,6'd0}), .in2({{4{corr_q[35]}},corr_q[35:16]}), .strobe_in(1'b1),
+ .sum(q_final), .strobe_out());
+
+ assign i_out = i_final;
+ assign q_out = q_final;
+
+ /*
+ round_sd #(.WIDTH_IN(24),.WIDTH_OUT(18)) round_i
+ (.clk(clk), .reset(rst), .in(i_final), .strobe_in(1'b1), .out(i_out), .strobe_out());
+
+ round_sd #(.WIDTH_IN(24),.WIDTH_OUT(18)) round_q
+ (.clk(clk), .reset(rst), .in(q_final), .strobe_in(1'b1), .out(q_out), .strobe_out());
+ */
+endmodule // rx_frontend
diff --git a/fpga/usrp2/sdr_lib/rx_frontend_tb.v b/fpga/usrp2/sdr_lib/rx_frontend_tb.v
new file mode 100644
index 000000000..487b72687
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/rx_frontend_tb.v
@@ -0,0 +1,45 @@
+
+`timescale 1ns/1ns
+module rx_frontend_tb();
+
+ reg clk, rst;
+
+ initial rst = 1;
+ initial #1000 rst = 0;
+ initial clk = 0;
+ always #5 clk = ~clk;
+
+ initial $dumpfile("rx_frontend_tb.vcd");
+ initial $dumpvars(0,rx_frontend_tb);
+
+ reg [15:0] adc_in;
+ wire [17:0] adc_out;
+
+ always @(posedge clk)
+ begin
+ if(adc_in[13])
+ $write("-%d,",-adc_in);
+ else
+ $write("%d,",adc_in);
+ if(adc_out[13])
+ $write("-%d\n",-adc_out);
+ else
+ $write("%d\n",adc_out);
+ end
+
+ rx_frontend #(.BASE(0)) rx_frontend
+ (.clk(clk),.rst(rst),
+ .set_stb(0),.set_addr(0),.set_data(0),
+ .adc_a(adc_in), .adc_ovf_a(0),
+ .adc_b(0), .adc_ovf_b(0),
+ .i_out(adc_out),.q_out(),
+ .run(), .debug());
+
+ always @(posedge clk)
+ if(rst)
+ adc_in <= 0;
+ else
+ adc_in <= adc_in + 4;
+ //adc_in <= (($random % 473) + 23)/4;
+
+endmodule // rx_frontend_tb
diff --git a/fpga/usrp2/sdr_lib/small_hb_dec.v b/fpga/usrp2/sdr_lib/small_hb_dec.v
index 151b8c287..a7f93e056 100644
--- a/fpga/usrp2/sdr_lib/small_hb_dec.v
+++ b/fpga/usrp2/sdr_lib/small_hb_dec.v
@@ -29,21 +29,30 @@ module small_hb_dec
input stb_in,
input [WIDTH-1:0] data_in,
output reg stb_out,
- output [WIDTH-1:0] data_out);
+ output reg [WIDTH-1:0] data_out);
- reg stb_in_d1;
- reg [WIDTH-1:0] data_in_d1;
- always @(posedge clk) stb_in_d1 <= stb_in;
- always @(posedge clk) data_in_d1 <= data_in;
+ // Round off inputs to 17 bits because of 18 bit multipliers
+ localparam INTWIDTH = 17;
+ wire [INTWIDTH-1:0] data_rnd;
+ wire stb_rnd;
+
+ round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(INTWIDTH)) round_in
+ (.clk(clk),.reset(rst),.in(data_in),.strobe_in(stb_in),.out(data_rnd),.strobe_out(stb_rnd));
+
+
+ reg stb_rnd_d1;
+ reg [INTWIDTH-1:0] data_rnd_d1;
+ always @(posedge clk) stb_rnd_d1 <= stb_rnd;
+ always @(posedge clk) data_rnd_d1 <= data_rnd;
wire go;
reg phase, go_d1, go_d2, go_d3, go_d4;
always @(posedge clk)
if(rst | ~run)
phase <= 0;
- else if(stb_in_d1)
+ else if(stb_rnd_d1)
phase <= ~phase;
- assign go = stb_in_d1 & phase;
+ assign go = stb_rnd_d1 & phase;
always @(posedge clk)
if(rst | ~run)
begin
@@ -63,11 +72,11 @@ module small_hb_dec
wire [17:0] coeff_a = -10690;
wire [17:0] coeff_b = 75809;
- reg [WIDTH-1:0] d1, d2, d3, d4 , d5, d6;
+ reg [INTWIDTH-1:0] d1, d2, d3, d4 , d5, d6;
always @(posedge clk)
- if(stb_in_d1 | rst)
+ if(stb_rnd_d1 | rst)
begin
- d1 <= data_in_d1;
+ d1 <= data_rnd_d1;
d2 <= d1;
d3 <= d2;
d4 <= d3;
@@ -76,16 +85,14 @@ module small_hb_dec
end
reg [17:0] sum_a, sum_b, middle, middle_d1;
- wire [17:0] sum_a_unreg, sum_b_unreg;
- add2 #(.WIDTH(18)) add2_a (.in1(data_in_d1),.in2(d6),.sum(sum_a_unreg));
- add2 #(.WIDTH(18)) add2_b (.in1(d2),.in2(d4),.sum(sum_b_unreg));
-
+
always @(posedge clk)
if(go)
begin
- sum_a <= sum_a_unreg;
- sum_b <= sum_b_unreg;
- middle <= d3;
+ sum_a <= {data_rnd_d1[INTWIDTH-1],data_rnd_d1} + {d6[INTWIDTH-1],d6};
+ sum_b <= {d2[INTWIDTH-1],d2} + {d4[INTWIDTH-1],d4};
+ //middle <= {d3[INTWIDTH-1],d3};
+ middle <= {d3,1'b0};
end
always @(posedge clk)
@@ -106,23 +113,22 @@ module small_hb_dec
else if(go_d3)
accum <= accum + {prod};
- wire [17:0] accum_rnd;
- round #(.bits_in(36),.bits_out(18)) round_acc (.in(accum),.out(accum_rnd));
+ wire [WIDTH:0] accum_rnd;
+ wire [WIDTH-1:0] accum_rnd_clip;
+
+ wire stb_round;
+
+ round_sd #(.WIDTH_IN(36),.WIDTH_OUT(WIDTH+1)) round_acc
+ (.clk(clk), .reset(rst), .in(accum), .strobe_in(go_d4), .out(accum_rnd), .strobe_out(stb_round));
- reg [17:0] final_sum;
+ clip #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip (.in(accum_rnd), .out(accum_rnd_clip));
+
+ // Output
always @(posedge clk)
- if(bypass)
- final_sum <= data_in_d1;
- else if(go_d4)
- final_sum <= accum_rnd;
+ begin
+ stb_out <= bypass ? stb_in : stb_round;
+ data_out <= bypass ? data_in : accum_rnd_clip;
+ end
- assign data_out = final_sum;
- always @(posedge clk)
- if(rst)
- stb_out <= 0;
- else if(bypass)
- stb_out <= stb_in_d1;
- else
- stb_out <= go_d4;
endmodule // small_hb_dec
diff --git a/fpga/usrp2/sdr_lib/tx_frontend.v b/fpga/usrp2/sdr_lib/tx_frontend.v
new file mode 100644
index 000000000..d8525dd25
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/tx_frontend.v
@@ -0,0 +1,86 @@
+
+module tx_frontend
+ #(parameter BASE=0,
+ parameter WIDTH_OUT=16)
+ (input clk, input rst,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ input [23:0] tx_i, input [23:0] tx_q, input run,
+ output reg [WIDTH_OUT-1:0] dac_a, output reg [WIDTH_OUT-1:0] dac_b
+ );
+
+ // IQ balance --> DC offset --> rounding --> mux
+
+ wire [23:0] i_dco, q_dco, i_ofs, q_ofs;
+ wire [WIDTH_OUT-1:0] i_final, q_final;
+ wire [7:0] mux_ctrl;
+ wire [35:0] corr_i, corr_q;
+ wire [23:0] i_bal, q_bal;
+ wire [17:0] mag_corr, phase_corr;
+
+ setting_reg #(.my_addr(BASE+0), .width(24)) sr_0
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(i_dco),.changed());
+
+ setting_reg #(.my_addr(BASE+1), .width(24)) sr_1
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(q_dco),.changed());
+
+ setting_reg #(.my_addr(BASE+2),.width(18)) sr_2
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(mag_corr),.changed());
+
+ setting_reg #(.my_addr(BASE+3),.width(18)) sr_3
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(phase_corr),.changed());
+
+ setting_reg #(.my_addr(BASE+4), .width(8)) sr_4
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(mux_ctrl),.changed());
+
+ // IQ Balance
+ MULT18X18S mult_mag_corr
+ (.P(corr_i), .A(tx_i[23:6]), .B(mag_corr), .C(clk), .CE(1), .R(rst) );
+
+ MULT18X18S mult_phase_corr
+ (.P(corr_q), .A(tx_i[23:6]), .B(phase_corr), .C(clk), .CE(1), .R(rst) );
+
+ add2_and_clip_reg #(.WIDTH(24)) add_clip_i
+ (.clk(clk), .rst(rst),
+ .in1(tx_i), .in2({{4{corr_i[35]}},corr_i[35:16]}), .strobe_in(1'b1),
+ .sum(i_bal), .strobe_out());
+
+ add2_and_clip_reg #(.WIDTH(24)) add_clip_q
+ (.clk(clk), .rst(rst),
+ .in1(tx_q), .in2({{4{corr_q[35]}},corr_q[35:16]}), .strobe_in(1'b1),
+ .sum(q_bal), .strobe_out());
+
+ // DC Offset
+ add2_and_clip_reg #(.WIDTH(24)) add_dco_i
+ (.clk(clk), .rst(rst), .in1(i_dco), .in2(i_bal), .strobe_in(1'b1), .sum(i_ofs), .strobe_out());
+
+ add2_and_clip_reg #(.WIDTH(24)) add_dco_q
+ (.clk(clk), .rst(rst), .in1(q_dco), .in2(q_bal), .strobe_in(1'b1), .sum(q_ofs), .strobe_out());
+
+ // Rounding
+ round_sd #(.WIDTH_IN(24),.WIDTH_OUT(WIDTH_OUT)) round_i
+ (.clk(clk), .reset(rst), .in(i_ofs),.strobe_in(1'b1), .out(i_final), .strobe_out());
+
+ round_sd #(.WIDTH_IN(24),.WIDTH_OUT(WIDTH_OUT)) round_q
+ (.clk(clk), .reset(rst), .in(q_ofs),.strobe_in(1'b1), .out(q_final), .strobe_out());
+
+ // Mux
+ always @(posedge clk)
+ case(mux_ctrl[3:0])
+ 0 : dac_a <= i_final;
+ 1 : dac_a <= q_final;
+ default : dac_a <= 0;
+ endcase // case (mux_ctrl[3:0])
+
+ always @(posedge clk)
+ case(mux_ctrl[7:4])
+ 0 : dac_b <= i_final;
+ 1 : dac_b <= q_final;
+ default : dac_b <= 0;
+ endcase // case (mux_ctrl[7:4])
+
+endmodule // tx_frontend