summaryrefslogtreecommitdiffstats
path: root/fpga/usrp2/sdr_lib
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp2/sdr_lib')
-rw-r--r--fpga/usrp2/sdr_lib/.gitignore3
-rw-r--r--fpga/usrp2/sdr_lib/HB.sav56
-rw-r--r--fpga/usrp2/sdr_lib/SMALL_HB.sav40
-rw-r--r--fpga/usrp2/sdr_lib/acc.v28
-rw-r--r--fpga/usrp2/sdr_lib/add2.v11
-rw-r--r--fpga/usrp2/sdr_lib/add2_and_round.v11
-rw-r--r--fpga/usrp2/sdr_lib/add2_and_round_reg.v16
-rw-r--r--fpga/usrp2/sdr_lib/add2_reg.v17
-rw-r--r--fpga/usrp2/sdr_lib/cic_dec_shifter.v106
-rwxr-xr-xfpga/usrp2/sdr_lib/cic_decim.v88
-rw-r--r--fpga/usrp2/sdr_lib/cic_int_shifter.v100
-rwxr-xr-xfpga/usrp2/sdr_lib/cic_interp.v87
-rw-r--r--fpga/usrp2/sdr_lib/cic_strober.v45
-rw-r--r--fpga/usrp2/sdr_lib/clip.v36
-rw-r--r--fpga/usrp2/sdr_lib/clip_and_round.v43
-rw-r--r--fpga/usrp2/sdr_lib/clip_and_round_reg.v40
-rw-r--r--fpga/usrp2/sdr_lib/clip_reg.v38
-rwxr-xr-xfpga/usrp2/sdr_lib/cordic.v109
-rwxr-xr-xfpga/usrp2/sdr_lib/cordic_stage.v60
-rw-r--r--fpga/usrp2/sdr_lib/cordic_z24.v126
-rwxr-xr-xfpga/usrp2/sdr_lib/ddc.v97
-rw-r--r--fpga/usrp2/sdr_lib/dsp_core_rx.v179
-rw-r--r--fpga/usrp2/sdr_lib/dsp_core_tx.v151
-rwxr-xr-xfpga/usrp2/sdr_lib/duc.v95
-rw-r--r--fpga/usrp2/sdr_lib/dummy_rx.v62
-rwxr-xr-xfpga/usrp2/sdr_lib/gen_cordic_consts.py10
-rw-r--r--fpga/usrp2/sdr_lib/halfband_ideal.v84
-rw-r--r--fpga/usrp2/sdr_lib/halfband_tb.v120
-rw-r--r--fpga/usrp2/sdr_lib/hb/acc.v22
-rw-r--r--fpga/usrp2/sdr_lib/hb/coeff_ram.v26
-rw-r--r--fpga/usrp2/sdr_lib/hb/coeff_rom.v19
-rw-r--r--fpga/usrp2/sdr_lib/hb/halfband_decim.v163
-rw-r--r--fpga/usrp2/sdr_lib/hb/halfband_interp.v121
-rw-r--r--fpga/usrp2/sdr_lib/hb/hbd_tb/HBD80
-rw-r--r--fpga/usrp2/sdr_lib/hb/hbd_tb/really_golden142
-rw-r--r--fpga/usrp2/sdr_lib/hb/hbd_tb/regression95
-rwxr-xr-xfpga/usrp2/sdr_lib/hb/hbd_tb/run_hbd4
-rw-r--r--fpga/usrp2/sdr_lib/hb/hbd_tb/test_hbd.v75
-rw-r--r--fpga/usrp2/sdr_lib/hb/mac.v58
-rw-r--r--fpga/usrp2/sdr_lib/hb/mult.v16
-rw-r--r--fpga/usrp2/sdr_lib/hb/ram16_2port.v22
-rw-r--r--fpga/usrp2/sdr_lib/hb/ram16_2sum.v27
-rw-r--r--fpga/usrp2/sdr_lib/hb/ram32_2sum.v22
-rw-r--r--fpga/usrp2/sdr_lib/hb_dec.v171
-rw-r--r--fpga/usrp2/sdr_lib/hb_dec_tb.v140
-rw-r--r--fpga/usrp2/sdr_lib/hb_interp.v157
-rw-r--r--fpga/usrp2/sdr_lib/hb_interp_tb.v132
-rw-r--r--fpga/usrp2/sdr_lib/hb_tb.v155
-rw-r--r--fpga/usrp2/sdr_lib/input.dat341
-rw-r--r--fpga/usrp2/sdr_lib/integrate.v38
-rw-r--r--fpga/usrp2/sdr_lib/med_hb_int.v95
-rw-r--r--fpga/usrp2/sdr_lib/output.dat130
-rw-r--r--fpga/usrp2/sdr_lib/round.v33
-rw-r--r--fpga/usrp2/sdr_lib/round_reg.v39
-rw-r--r--fpga/usrp2/sdr_lib/rssi.v30
-rw-r--r--fpga/usrp2/sdr_lib/rx_control.v180
-rw-r--r--fpga/usrp2/sdr_lib/rx_dcoffset.v43
-rw-r--r--fpga/usrp2/sdr_lib/rx_dcoffset_tb.v25
-rw-r--r--fpga/usrp2/sdr_lib/sign_extend.v35
-rw-r--r--fpga/usrp2/sdr_lib/small_hb_dec.v111
-rw-r--r--fpga/usrp2/sdr_lib/small_hb_dec_tb.v140
-rw-r--r--fpga/usrp2/sdr_lib/small_hb_int.v85
-rw-r--r--fpga/usrp2/sdr_lib/small_hb_int_tb.v132
-rw-r--r--fpga/usrp2/sdr_lib/tx_control.v168
64 files changed, 5130 insertions, 0 deletions
diff --git a/fpga/usrp2/sdr_lib/.gitignore b/fpga/usrp2/sdr_lib/.gitignore
new file mode 100644
index 000000000..3c782d589
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/.gitignore
@@ -0,0 +1,3 @@
+/a.out
+/db
+/*.vcd
diff --git a/fpga/usrp2/sdr_lib/HB.sav b/fpga/usrp2/sdr_lib/HB.sav
new file mode 100644
index 000000000..c5087e8a6
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/HB.sav
@@ -0,0 +1,56 @@
+[size] 1400 967
+[pos] -1 -1
+*-46.395245 2565000000000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] hb_dec_tb.
+@420
+hb_dec_tb.data_in[17:0]
+@28
+hb_dec_tb.strobe_in
+hb_dec_tb.strobe_out
+hb_dec_tb.uut.write_even
+@22
+hb_dec_tb.uut.addr_even[3:0]
+@420
+hb_dec_tb.uut.data_even[17:0]
+hb_dec_tb.uut.data_odd_a[17:0]
+hb_dec_tb.uut.data_odd_b[17:0]
+hb_dec_tb.uut.data_odd_c[17:0]
+hb_dec_tb.uut.data_odd_d[17:0]
+@28
+hb_dec_tb.uut.write_odd
+@420
+hb_dec_tb.uut.prod1[35:0]
+hb_dec_tb.uut.prod2[35:0]
+@24
+hb_dec_tb.uut.phase[2:0]
+@28
+hb_dec_tb.uut.stb_in
+hb_dec_tb.uut.stb_out
+@420
+hb_dec_tb.uut.sum2[17:0]
+hb_dec_tb.uut.stb_out_pre[15:0]
+@28
+hb_dec_tb.uut.do_acc
+hb_dec_tb.uut.clear
+@420
+hb_dec_tb.uut.sum1[17:0]
+hb_dec_tb.uut.coeff1[17:0]
+hb_dec_tb.uut.prod1[35:0]
+hb_dec_tb.uut.prod2[35:0]
+hb_dec_tb.uut.final_sum[17:0]
+hb_dec_tb.uut.coeff2[17:0]
+hb_dec_tb.uut.sum_of_prod[21:0]
+hb_dec_tb.data_out[17:0]
+@28
+hb_dec_tb.uut.do_acc
+hb_dec_tb.uut.clear
+@24
+hb_dec_tb.uut.addr_odd_a[3:0]
+hb_dec_tb.uut.addr_odd_b[3:0]
+hb_dec_tb.uut.addr_odd_c[3:0]
+hb_dec_tb.uut.addr_odd_d[3:0]
+@28
+hb_dec_tb.uut.write_odd
+hb_dec_tb.uut.write_even
+@22
+hb_dec_tb.uut.data_even[17:0]
diff --git a/fpga/usrp2/sdr_lib/SMALL_HB.sav b/fpga/usrp2/sdr_lib/SMALL_HB.sav
new file mode 100644
index 000000000..96ba00636
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/SMALL_HB.sav
@@ -0,0 +1,40 @@
+[size] 1400 967
+[pos] -1 -1
+*-11.608687 1834 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] small_hb_dec_tb.
+[treeopen] small_hb_dec_tb.uut.
+@28
+small_hb_dec_tb.uut.clk
+small_hb_dec_tb.uut.phase
+@10421
+small_hb_dec_tb.uut.data_in[17:0]
+@420
+small_hb_dec_tb.uut.d1[17:0]
+small_hb_dec_tb.uut.d2[17:0]
+small_hb_dec_tb.uut.d3[17:0]
+small_hb_dec_tb.uut.d4[17:0]
+small_hb_dec_tb.uut.d5[17:0]
+small_hb_dec_tb.uut.d6[17:0]
+small_hb_dec_tb.uut.coeff[17:0]
+small_hb_dec_tb.uut.sum[17:0]
+small_hb_dec_tb.uut.prod[35:0]
+small_hb_dec_tb.uut.accum_rnd[17:0]
+@28
+small_hb_dec_tb.uut.stb_in
+@420
+small_hb_dec_tb.uut.final_sum[17:0]
+@28
+small_hb_dec_tb.uut.go
+small_hb_dec_tb.uut.go_d1
+small_hb_dec_tb.uut.go_d2
+small_hb_dec_tb.uut.go_d3
+small_hb_dec_tb.uut.go_d4
+small_hb_dec_tb.uut.stb_out
+@420
+small_hb_dec_tb.uut.data_out[17:0]
+small_hb_dec_tb.uut.prod[35:0]
+small_hb_dec_tb.uut.accum_rnd[17:0]
+small_hb_dec_tb.uut.final_sum[17:0]
+@10421
+small_hb_dec_tb.uut.round_acc.out[17:0]
+small_hb_dec_tb.uut.data_out[17:0]
diff --git a/fpga/usrp2/sdr_lib/acc.v b/fpga/usrp2/sdr_lib/acc.v
new file mode 100644
index 000000000..a2da9c86d
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/acc.v
@@ -0,0 +1,28 @@
+
+module acc
+ #(parameter IWIDTH=16, OWIDTH=30)
+ (input clk,
+ input clear,
+ input acc,
+ input [IWIDTH-1:0] in,
+ output reg [OWIDTH-1:0] out);
+
+ wire [OWIDTH-1:0] in_signext;
+ sign_extend #(.bits_in(IWIDTH),.bits_out(OWIDTH))
+ acc_signext (.in(in),.out(in_signext));
+
+ // CLEAR & ~ACC --> clears the accumulator
+ // CLEAR & ACC --> loads the accumulator
+ // ~CLEAR & ACC --> accumulates
+ // ~CLEAR & ~ACC --> hold
+
+ wire [OWIDTH-1:0] addend1 = clear ? 0 : out;
+ wire [OWIDTH-1:0] addend2 = ~acc ? 0 : in_signext;
+ wire [OWIDTH-1:0] sum_int = addend1 + addend2;
+
+ always @(posedge clk)
+ out <= sum_int;
+
+endmodule // acc
+
+
diff --git a/fpga/usrp2/sdr_lib/add2.v b/fpga/usrp2/sdr_lib/add2.v
new file mode 100644
index 000000000..13fff803e
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/add2.v
@@ -0,0 +1,11 @@
+
+module add2
+ #(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};
+ assign sum = sum_int[WIDTH:1]; // Note -- will have some bias
+
+endmodule // add2
diff --git a/fpga/usrp2/sdr_lib/add2_and_round.v b/fpga/usrp2/sdr_lib/add2_and_round.v
new file mode 100644
index 000000000..146af28da
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/add2_and_round.v
@@ -0,0 +1,11 @@
+
+module add2_and_round
+ #(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};
+ assign sum = sum_int[WIDTH:1] + (sum_int[WIDTH] & sum_int[0]);
+
+endmodule // add2_and_round
diff --git a/fpga/usrp2/sdr_lib/add2_and_round_reg.v b/fpga/usrp2/sdr_lib/add2_and_round_reg.v
new file mode 100644
index 000000000..e7fcbf1a1
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/add2_and_round_reg.v
@@ -0,0 +1,16 @@
+
+module add2_and_round_reg
+ #(parameter WIDTH=16)
+ (input clk,
+ input [WIDTH-1:0] in1,
+ input [WIDTH-1:0] in2,
+ output reg [WIDTH-1:0] sum);
+
+ wire [WIDTH-1:0] sum_int;
+
+ add2_and_round #(.WIDTH(WIDTH)) add2_n_rnd (.in1(in1),.in2(in2),.sum(sum_int));
+
+ always @(posedge clk)
+ sum <= sum_int;
+
+endmodule // add2_and_round_reg
diff --git a/fpga/usrp2/sdr_lib/add2_reg.v b/fpga/usrp2/sdr_lib/add2_reg.v
new file mode 100644
index 000000000..456cf315b
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/add2_reg.v
@@ -0,0 +1,17 @@
+
+module add2_reg
+ #(parameter WIDTH=16)
+ (input clk,
+ input [WIDTH-1:0] in1,
+ input [WIDTH-1:0] in2,
+ output reg [WIDTH-1:0] sum);
+
+ wire [WIDTH-1:0] sum_int;
+
+ add2 #(.WIDTH(WIDTH)) add2 (.in1(in1),.in2(in2),.sum(sum_int));
+
+ always @(posedge clk)
+ sum <= sum_int;
+
+endmodule // add2_reg
+
diff --git a/fpga/usrp2/sdr_lib/cic_dec_shifter.v b/fpga/usrp2/sdr_lib/cic_dec_shifter.v
new file mode 100644
index 000000000..aa5ac895b
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/cic_dec_shifter.v
@@ -0,0 +1,106 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2003 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+
+// NOTE This only works for N=4, max decim rate of 128
+// NOTE signal "rate" is EQUAL TO the actual rate, no more -1 BS
+
+module cic_dec_shifter(rate,signal_in,signal_out);
+ parameter bw = 16;
+ parameter maxbitgain = 28;
+
+ input [7:0] rate;
+ input wire [bw+maxbitgain-1:0] signal_in;
+ output reg [bw-1:0] signal_out;
+
+ function [4:0] bitgain;
+ input [7:0] rate;
+ case(rate)
+ // Exact Cases -- N*log2(rate)
+ 8'd1 : bitgain = 0;
+ 8'd2 : bitgain = 4;
+ 8'd4 : bitgain = 8;
+ 8'd8 : bitgain = 12;
+ 8'd16 : bitgain = 16;
+ 8'd32 : bitgain = 20;
+ 8'd64 : bitgain = 24;
+ 8'd128 : bitgain = 28;
+
+ // Nearest without overflow -- ceil(N*log2(rate))
+ 8'd3 : bitgain = 7;
+ 8'd5 : bitgain = 10;
+ 8'd6 : bitgain = 11;
+ 8'd7 : bitgain = 12;
+ 8'd9 : bitgain = 13;
+ 8'd10,8'd11 : bitgain = 14;
+ 8'd12,8'd13 : bitgain = 15;
+ 8'd14,8'd15 : bitgain = 16;
+ 8'd17,8'd18,8'd19 : bitgain = 17;
+ 8'd20,8'd21,8'd22 : bitgain = 18;
+ 8'd23,8'd24,8'd25,8'd26 : bitgain = 19;
+ 8'd27,8'd28,8'd29,8'd30,8'd31 : bitgain = 20;
+ 8'd33,8'd34,8'd35,8'd36,8'd37,8'd38 : bitgain = 21;
+ 8'd39,8'd40,8'd41,8'd42,8'd43,8'd44,8'd45 : bitgain = 22;
+ 8'd46,8'd47,8'd48,8'd49,8'd50,8'd51,8'd52,8'd53 : bitgain = 23;
+ 8'd54,8'd55,8'd56,8'd57,8'd58,8'd59,8'd60,8'd61,8'd62,8'd63 : bitgain = 24;
+ 8'd65,8'd66,8'd67,8'd68,8'd69,8'd70,8'd71,8'd72,8'd73,8'd74,8'd75,8'd76 : bitgain = 25;
+ 8'd77,8'd78,8'd79,8'd80,8'd81,8'd82,8'd83,8'd84,8'd85,8'd86,8'd87,8'd88,8'd89,8'd90 : bitgain = 26;
+ 8'd91,8'd92,8'd93,8'd94,8'd95,8'd96,8'd97,8'd98,8'd99,8'd100,8'd101,8'd102,8'd103,8'd104,8'd105,8'd106,8'd107 : bitgain = 27;
+ default : bitgain = 28;
+ endcase // case(rate)
+ endfunction // bitgain
+
+ wire [4:0] shift = bitgain(rate);
+
+ // We should be able to do this, but can't ....
+ // assign signal_out = signal_in[shift+bw-1:shift];
+
+ always @*
+ case(shift)
+ 5'd0 : signal_out = signal_in[0+bw-1:0];
+ 5'd4 : signal_out = signal_in[4+bw-1:4];
+ 5'd7 : signal_out = signal_in[7+bw-1:7];
+ 5'd8 : signal_out = signal_in[8+bw-1:8];
+ 5'd10 : signal_out = signal_in[10+bw-1:10];
+ 5'd11 : signal_out = signal_in[11+bw-1:11];
+ 5'd12 : signal_out = signal_in[12+bw-1:12];
+ 5'd13 : signal_out = signal_in[13+bw-1:13];
+ 5'd14 : signal_out = signal_in[14+bw-1:14];
+ 5'd15 : signal_out = signal_in[15+bw-1:15];
+ 5'd16 : signal_out = signal_in[16+bw-1:16];
+ 5'd17 : signal_out = signal_in[17+bw-1:17];
+ 5'd18 : signal_out = signal_in[18+bw-1:18];
+ 5'd19 : signal_out = signal_in[19+bw-1:19];
+ 5'd20 : signal_out = signal_in[20+bw-1:20];
+ 5'd21 : signal_out = signal_in[21+bw-1:21];
+ 5'd22 : signal_out = signal_in[22+bw-1:22];
+ 5'd23 : signal_out = signal_in[23+bw-1:23];
+ 5'd24 : signal_out = signal_in[24+bw-1:24];
+ 5'd25 : signal_out = signal_in[25+bw-1:25];
+ 5'd26 : signal_out = signal_in[26+bw-1:26];
+ 5'd27 : signal_out = signal_in[27+bw-1:27];
+ 5'd28 : signal_out = signal_in[28+bw-1:28];
+
+ default : signal_out = signal_in[28+bw-1:28];
+ endcase // case(shift)
+
+endmodule // cic_dec_shifter
+
diff --git a/fpga/usrp2/sdr_lib/cic_decim.v b/fpga/usrp2/sdr_lib/cic_decim.v
new file mode 100755
index 000000000..9a03081b0
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/cic_decim.v
@@ -0,0 +1,88 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2003 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+
+module cic_decim
+ #(parameter bw = 16, parameter N = 4, parameter log2_of_max_rate = 7)
+ (input clock,
+ input reset,
+ input enable,
+ input [7:0] rate,
+ input strobe_in,
+ input strobe_out,
+ input [bw-1:0] signal_in,
+ output reg [bw-1:0] signal_out);
+
+ localparam maxbitgain = N * log2_of_max_rate;
+
+ wire [bw+maxbitgain-1:0] signal_in_ext;
+ reg [bw+maxbitgain-1:0] integrator [0:N-1];
+ reg [bw+maxbitgain-1:0] differentiator [0:N-1];
+ reg [bw+maxbitgain-1:0] pipeline [0:N-1];
+ reg [bw+maxbitgain-1:0] sampler;
+
+ integer i;
+
+ sign_extend #(bw,bw+maxbitgain)
+ ext_input (.in(signal_in),.out(signal_in_ext));
+
+ always @(posedge clock)
+ if(reset)
+ for(i=0;i<N;i=i+1)
+ integrator[i] <= 0;
+ else if (enable && strobe_in)
+ begin
+ integrator[0] <= integrator[0] + signal_in_ext;
+ for(i=1;i<N;i=i+1)
+ integrator[i] <= integrator[i] + integrator[i-1];
+ end
+
+ always @(posedge clock)
+ if(reset)
+ begin
+ sampler <= 0;
+ for(i=0;i<N;i=i+1)
+ begin
+ pipeline[i] <= 0;
+ differentiator[i] <= 0;
+ end
+ end
+ else if (enable && strobe_out)
+ begin
+ sampler <= integrator[N-1];
+ differentiator[0] <= sampler;
+ pipeline[0] <= sampler - differentiator[0];
+ for(i=1;i<N;i=i+1)
+ begin
+ differentiator[i] <= pipeline[i-1];
+ pipeline[i] <= pipeline[i-1] - differentiator[i];
+ end
+ end // if (enable && strobe_out)
+
+ wire [bw-1:0] signal_out_unreg;
+
+ cic_dec_shifter #(bw)
+ cic_dec_shifter(rate,pipeline[N-1],signal_out_unreg);
+
+ always @(posedge clock)
+ signal_out <= signal_out_unreg;
+
+endmodule // cic_decim
diff --git a/fpga/usrp2/sdr_lib/cic_int_shifter.v b/fpga/usrp2/sdr_lib/cic_int_shifter.v
new file mode 100644
index 000000000..18587fa8b
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/cic_int_shifter.v
@@ -0,0 +1,100 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2003 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+
+// NOTE This only works for N=4, max interp rate of 128
+// NOTE signal "rate" is EQUAL TO the actual rate (no more -1 BS)
+
+module cic_int_shifter(rate,signal_in,signal_out);
+ parameter bw = 16;
+ parameter maxbitgain = 21;
+
+ input [7:0] rate;
+ input wire [bw+maxbitgain-1:0] signal_in;
+ output reg [bw-1:0] signal_out;
+
+ function [4:0] bitgain;
+ input [7:0] rate;
+ case(rate)
+ // Exact Cases
+ 8'd1 : bitgain = 0;
+ 8'd2 : bitgain = 3;
+ 8'd4 : bitgain = 6;
+ 8'd8 : bitgain = 9;
+ 8'd16 : bitgain = 12;
+ 8'd32 : bitgain = 15;
+ 8'd64 : bitgain = 18;
+ 8'd128 : bitgain = 21;
+
+ // Nearest without overflow
+ 8'd3 : bitgain = 5;
+ 8'd5 : bitgain = 7;
+ 8'd6 : bitgain = 8;
+ 8'd7 : bitgain = 9;
+ 8'd9,8'd10 : bitgain = 10;
+ 8'd11,8'd12 : bitgain = 11;
+ 8'd13,8'd14,8'd15 : bitgain = 12;
+ 8'd17,8'd18,8'd19,8'd20 : bitgain = 13;
+ 8'd21,8'd22,8'd23,8'd24,8'd25 : bitgain = 14;
+ 8'd26,8'd27,8'd28,8'd29,8'd30,8'd31 : bitgain = 15;
+ 8'd33,8'd34,8'd35,8'd36,8'd37,8'd38,8'd39,8'd40 : bitgain = 16;
+ 8'd41,8'd42,8'd43,8'd44,8'd45,8'd46,8'd47,8'd48,8'd49,8'd50 : bitgain = 17;
+ 8'd51,8'd52,8'd53,8'd54,8'd55,8'd56,8'd57,8'd58,8'd59,8'd60,8'd61,8'd62,8'd63 : bitgain = 18;
+ 8'd65,8'd66,8'd67,8'd68,8'd69,8'd70,8'd71,8'd72,8'd73,8'd74,8'd75,8'd76,8'd77,8'd78,8'd79,8'd80 : bitgain = 19;
+ 8'd81,8'd82,8'd83,8'd84,8'd85,8'd86,8'd87,8'd88,8'd89,8'd90,8'd91,8'd92,8'd93,8'd94,8'd95,8'd96,8'd97,8'd98,8'd99,8'd100,8'd101 : bitgain = 20;
+
+ default : bitgain = 21;
+ endcase // case(rate)
+ endfunction // bitgain
+
+ wire [4:0] shift = bitgain(rate);
+
+ // We should be able to do this, but can't ....
+ // assign signal_out = signal_in[shift+bw-1:shift];
+
+ always @*
+ case(shift)
+ 5'd0 : signal_out = signal_in[0+bw-1:0];
+ 5'd3 : signal_out = signal_in[3+bw-1:3];
+ 5'd6 : signal_out = signal_in[6+bw-1:6];
+ 5'd9 : signal_out = signal_in[9+bw-1:9];
+ 5'd12 : signal_out = signal_in[12+bw-1:12];
+ 5'd15 : signal_out = signal_in[15+bw-1:15];
+ 5'd18 : signal_out = signal_in[18+bw-1:18];
+ 5'd21 : signal_out = signal_in[21+bw-1:21];
+
+ 5'd5 : signal_out = signal_in[5+bw-1:5];
+ 5'd7 : signal_out = signal_in[7+bw-1:7];
+ 5'd8 : signal_out = signal_in[8+bw-1:8];
+ 5'd10 : signal_out = signal_in[10+bw-1:10];
+ 5'd11 : signal_out = signal_in[11+bw-1:11];
+ 5'd13 : signal_out = signal_in[13+bw-1:13];
+ 5'd14 : signal_out = signal_in[14+bw-1:14];
+ 5'd16 : signal_out = signal_in[16+bw-1:16];
+ 5'd17 : signal_out = signal_in[17+bw-1:17];
+ 5'd19 : signal_out = signal_in[19+bw-1:19];
+ 5'd20 : signal_out = signal_in[20+bw-1:20];
+
+ default : signal_out = signal_in[21+bw-1:21];
+ endcase // case(shift)
+
+endmodule // cic_int_shifter
+
diff --git a/fpga/usrp2/sdr_lib/cic_interp.v b/fpga/usrp2/sdr_lib/cic_interp.v
new file mode 100755
index 000000000..9b6928aa1
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/cic_interp.v
@@ -0,0 +1,87 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2003 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+
+module cic_interp
+ #(parameter bw = 16, parameter N = 4, parameter log2_of_max_rate = 7)
+ (input clock,
+ input reset,
+ input enable,
+ input [7:0] rate,
+ input strobe_in,
+ input strobe_out,
+ input [bw-1:0] signal_in,
+ output reg [bw-1:0] signal_out);
+
+ integer i;
+ localparam maxbitgain = (N-1)*log2_of_max_rate;
+
+ wire [bw+maxbitgain-1:0] signal_in_ext;
+ reg [bw+maxbitgain-1:0] integrator [0:N-1];
+ reg [bw+maxbitgain-1:0] differentiator [0:N-1];
+ reg [bw+maxbitgain-1:0] pipeline [0:N-1];
+
+ sign_extend #(bw,bw+maxbitgain)
+ ext_input (.in(signal_in),.out(signal_in_ext));
+
+ //FIXME Note that this section has pipe and diff reversed
+ // It still works, but is confusing
+ always @(posedge clock)
+ if(reset | ~enable)
+ for(i=0;i<N;i=i+1)
+ integrator[i] <= 0;
+ else if (enable & strobe_out)
+ begin
+ if(strobe_in)
+ integrator[0] <= integrator[0] + pipeline[N-1];
+ for(i=1;i<N;i=i+1)
+ integrator[i] <= integrator[i] + integrator[i-1];
+ end
+
+ always @(posedge clock)
+ if(reset | ~enable)
+ begin
+ for(i=0;i<N;i=i+1)
+ begin
+ differentiator[i] <= 0;
+ pipeline[i] <= 0;
+ end
+ end
+ else if (enable && strobe_in)
+ begin
+ differentiator[0] <= signal_in_ext;
+ pipeline[0] <= signal_in_ext - differentiator[0];
+ for(i=1;i<N;i=i+1)
+ begin
+ differentiator[i] <= pipeline[i-1];
+ pipeline[i] <= pipeline[i-1] - differentiator[i];
+ end
+ end
+
+ wire [bw-1:0] signal_out_unreg;
+ cic_int_shifter #(bw)
+ cic_int_shifter(rate,integrator[N-1],signal_out_unreg);
+
+ always @(posedge clock)
+ signal_out <= signal_out_unreg;
+
+endmodule // cic_interp
+
diff --git a/fpga/usrp2/sdr_lib/cic_strober.v b/fpga/usrp2/sdr_lib/cic_strober.v
new file mode 100644
index 000000000..40d76bdd9
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/cic_strober.v
@@ -0,0 +1,45 @@
+//
+// USRP2 - Universal Software Radio Peripheral Mk II
+//
+// Copyright (C) 2008 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+module cic_strober
+ #(parameter WIDTH=8)
+ ( input clock,
+ input reset,
+ input enable,
+ input [WIDTH-1:0] rate, // Rate should EQUAL to your desired divide ratio, no more -1 BS
+ input strobe_fast,
+ output wire strobe_slow );
+
+ reg [WIDTH-1:0] counter;
+ wire now = (counter==1);
+ assign strobe_slow = now && enable && strobe_fast;
+
+ always @(posedge clock)
+ if(reset)
+ counter <= 0;
+ else if (~enable)
+ counter <= rate;
+ else if(strobe_fast)
+ if(now)
+ counter <= rate;
+ else
+ counter <= counter - 1;
+
+endmodule // cic_strober
diff --git a/fpga/usrp2/sdr_lib/clip.v b/fpga/usrp2/sdr_lib/clip.v
new file mode 100644
index 000000000..3e6b3a2e2
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/clip.v
@@ -0,0 +1,36 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2008 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+// Clipping "macro", keeps the bottom bits
+
+module clip
+ #(parameter bits_in=0,
+ parameter bits_out=0)
+ (input [bits_in-1:0] in,
+ output [bits_out-1:0] out);
+
+ wire overflow = |in[bits_in-1:bits_out-1] & ~(&in[bits_in-1:bits_out-1]);
+ assign out = overflow ?
+ (in[bits_in-1] ? {1'b1,{(bits_out-1){1'b0}}} : {1'b0,{(bits_out-1){1'b1}}}) :
+ in[bits_out-1:0];
+
+endmodule // clip
+
diff --git a/fpga/usrp2/sdr_lib/clip_and_round.v b/fpga/usrp2/sdr_lib/clip_and_round.v
new file mode 100644
index 000000000..4546283a3
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/clip_and_round.v
@@ -0,0 +1,43 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2008 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+// Clipping "macro", keeps the bottom bits
+
+module clip_and_round
+ #(parameter bits_in=0,
+ parameter bits_out=0,
+ parameter clip_bits=0)
+ (input [bits_in-1:0] in,
+ output [bits_out-1:0] out);
+
+ wire [bits_out-1:0] rounded;
+
+ round #(.bits_in(bits_in-clip_bits),.bits_out(bits_out))
+ round (.in(in[bits_in-clip_bits-1:0]),.out(rounded));
+
+ wire overflow = |in[bits_in-1:bits_in-clip_bits-1]
+ & ~(&in[bits_in-1:bits_in-clip_bits-1]);
+
+ assign out = overflow ?
+ (in[bits_in-1] ? {1'b1,{(bits_out-1){1'b0}}} : {1'b0,{(bits_out-1){1'b1}}}) :
+ rounded;
+
+endmodule // clip_and_round
diff --git a/fpga/usrp2/sdr_lib/clip_and_round_reg.v b/fpga/usrp2/sdr_lib/clip_and_round_reg.v
new file mode 100644
index 000000000..66fb155fb
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/clip_and_round_reg.v
@@ -0,0 +1,40 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2008 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+// Clipping "macro", keeps the bottom bits
+
+module clip_and_round_reg
+ #(parameter bits_in=0,
+ parameter bits_out=0,
+ parameter clip_bits=0)
+ (input clk,
+ input [bits_in-1:0] in,
+ output reg [bits_out-1:0] out);
+
+ wire [bits_out-1:0] temp;
+
+ clip_and_round #(.bits_in(bits_in),.bits_out(bits_out),.clip_bits(clip_bits))
+ clip_and_round (.in(in),.out(temp));
+
+ always@(posedge clk)
+ out <= temp;
+
+endmodule // clip_and_round_reg
diff --git a/fpga/usrp2/sdr_lib/clip_reg.v b/fpga/usrp2/sdr_lib/clip_reg.v
new file mode 100644
index 000000000..d5e98d982
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/clip_reg.v
@@ -0,0 +1,38 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2008 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+// Clipping "macro", keeps the bottom bits
+
+module clip_reg
+ #(parameter bits_in=0,
+ parameter bits_out=0)
+ (input clk,
+ input [bits_in-1:0] in,
+ output reg [bits_out-1:0] out);
+
+ wire [bits_out-1:0] temp;
+
+ clip #(.bits_in(bits_in),.bits_out(bits_out)) clip (.in(in),.out(temp));
+ always @(posedge clk)
+ out <= temp;
+
+endmodule // clip_reg
+
diff --git a/fpga/usrp2/sdr_lib/cordic.v b/fpga/usrp2/sdr_lib/cordic.v
new file mode 100755
index 000000000..b73e7acf1
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/cordic.v
@@ -0,0 +1,109 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2003, 2007 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+module cordic(clock, reset, enable, xi, yi, zi, xo, yo, zo );
+ parameter bitwidth = 16;
+ parameter zwidth = 16;
+
+ input clock;
+ input reset;
+ input enable;
+ input [bitwidth-1:0] xi, yi;
+ output [bitwidth-1:0] xo, yo;
+ input [zwidth-1:0] zi;
+ output [zwidth-1:0] zo;
+
+ reg [bitwidth+1:0] x0,y0;
+ reg [zwidth-2:0] z0;
+ wire [bitwidth+1:0] x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12;
+ wire [bitwidth+1:0] y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12;
+ wire [zwidth-2:0] z1,z2,z3,z4,z5,z6,z7,z8,z9,z10,z11,z12;
+
+ wire [bitwidth+1:0] xi_ext = {{2{xi[bitwidth-1]}},xi};
+ wire [bitwidth+1:0] yi_ext = {{2{yi[bitwidth-1]}},yi};
+
+ // Compute consts. Would be easier if vlog had atan...
+ // see gen_cordic_consts.py
+
+ localparam c00 = 15'd8192;
+ localparam c01 = 15'd4836;
+ localparam c02 = 15'd2555;
+ localparam c03 = 15'd1297;
+ localparam c04 = 15'd651;
+ localparam c05 = 15'd326;
+ localparam c06 = 15'd163;
+ localparam c07 = 15'd81;
+ localparam c08 = 15'd41;
+ localparam c09 = 15'd20;
+ localparam c10 = 15'd10;
+ localparam c11 = 15'd5;
+ localparam c12 = 15'd3;
+ localparam c13 = 15'd1;
+ localparam c14 = 15'd1;
+ localparam c15 = 15'd0;
+ localparam c16 = 15'd0;
+
+ always @(posedge clock)
+ if(reset)
+ begin
+ x0 <= 0; y0 <= 0; z0 <= 0;
+ end
+ else// if(enable)
+ begin
+ z0 <= zi[zwidth-2:0];
+ case (zi[zwidth-1:zwidth-2])
+ 2'b00, 2'b11 :
+ begin
+ x0 <= xi_ext;
+ y0 <= yi_ext;
+ end
+ 2'b01, 2'b10 :
+ begin
+ x0 <= -xi_ext;
+ y0 <= -yi_ext;
+ end
+ endcase // case(zi[zwidth-1:zwidth-2])
+ end // else: !if(reset)
+
+ // FIXME need to handle variable number of stages
+ // FIXME should be able to narrow zwidth but quartus makes it bigger...
+ // This would be easier if arrays worked better in vlog...
+ cordic_stage #(bitwidth+2,zwidth-1,0) cordic_stage0 (clock,reset,enable,x0,y0,z0,c00,x1,y1,z1);
+ cordic_stage #(bitwidth+2,zwidth-1,1) cordic_stage1 (clock,reset,enable,x1,y1,z1,c01,x2,y2,z2);
+ cordic_stage #(bitwidth+2,zwidth-1,2) cordic_stage2 (clock,reset,enable,x2,y2,z2,c02,x3,y3,z3);
+ cordic_stage #(bitwidth+2,zwidth-1,3) cordic_stage3 (clock,reset,enable,x3,y3,z3,c03,x4,y4,z4);
+ cordic_stage #(bitwidth+2,zwidth-1,4) cordic_stage4 (clock,reset,enable,x4,y4,z4,c04,x5,y5,z5);
+ cordic_stage #(bitwidth+2,zwidth-1,5) cordic_stage5 (clock,reset,enable,x5,y5,z5,c05,x6,y6,z6);
+ cordic_stage #(bitwidth+2,zwidth-1,6) cordic_stage6 (clock,reset,enable,x6,y6,z6,c06,x7,y7,z7);
+ cordic_stage #(bitwidth+2,zwidth-1,7) cordic_stage7 (clock,reset,enable,x7,y7,z7,c07,x8,y8,z8);
+ cordic_stage #(bitwidth+2,zwidth-1,8) cordic_stage8 (clock,reset,enable,x8,y8,z8,c08,x9,y9,z9);
+ cordic_stage #(bitwidth+2,zwidth-1,9) cordic_stage9 (clock,reset,enable,x9,y9,z9,c09,x10,y10,z10);
+ cordic_stage #(bitwidth+2,zwidth-1,10) cordic_stage10 (clock,reset,enable,x10,y10,z10,c10,x11,y11,z11);
+ cordic_stage #(bitwidth+2,zwidth-1,11) cordic_stage11 (clock,reset,enable,x11,y11,z11,c11,x12,y12,z12);
+
+ assign xo = x12[bitwidth:1];
+ assign yo = y12[bitwidth:1];
+ //assign xo = x12[bitwidth+1:2]; // CORDIC gain is ~1.6, plus gain from rotating vectors
+ //assign yo = y12[bitwidth+1:2];
+ assign zo = z12;
+
+endmodule // cordic
+
diff --git a/fpga/usrp2/sdr_lib/cordic_stage.v b/fpga/usrp2/sdr_lib/cordic_stage.v
new file mode 100755
index 000000000..641ff9108
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/cordic_stage.v
@@ -0,0 +1,60 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2003 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+module cordic_stage( clock, reset, enable, xi,yi,zi,constant,xo,yo,zo);
+ parameter bitwidth = 16;
+ parameter zwidth = 16;
+ parameter shift = 1;
+
+ input clock;
+ input reset;
+ input enable;
+ input [bitwidth-1:0] xi,yi;
+ input [zwidth-1:0] zi;
+ input [zwidth-1:0] constant;
+ output [bitwidth-1:0] xo,yo;
+ output [zwidth-1:0] zo;
+
+ wire z_is_pos = ~zi[zwidth-1];
+
+ reg [bitwidth-1:0] xo,yo;
+ reg [zwidth-1:0] zo;
+
+ always @(posedge clock)
+ if(reset)
+ begin
+ xo <= 0;
+ yo <= 0;
+ zo <= 0;
+ end
+ else //if(enable)
+ begin
+ xo <= z_is_pos ?
+ xi - {{shift+1{yi[bitwidth-1]}},yi[bitwidth-2:shift]} :
+ xi + {{shift+1{yi[bitwidth-1]}},yi[bitwidth-2:shift]};
+ yo <= z_is_pos ?
+ yi + {{shift+1{xi[bitwidth-1]}},xi[bitwidth-2:shift]} :
+ yi - {{shift+1{xi[bitwidth-1]}},xi[bitwidth-2:shift]};
+ zo <= z_is_pos ?
+ zi - constant :
+ zi + constant;
+ end
+endmodule
diff --git a/fpga/usrp2/sdr_lib/cordic_z24.v b/fpga/usrp2/sdr_lib/cordic_z24.v
new file mode 100644
index 000000000..cf668d5ec
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/cordic_z24.v
@@ -0,0 +1,126 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2003, 2007 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+module cordic_z24(clock, reset, enable, xi, yi, zi, xo, yo, zo );
+ parameter bitwidth = 16;
+ parameter stages = 19;
+ localparam zwidth = 24;
+
+ input clock;
+ input reset;
+ input enable;
+ input [bitwidth-1:0] xi, yi;
+ output [bitwidth-1:0] xo, yo;
+ input [zwidth-1:0] zi;
+ output [zwidth-1:0] zo;
+
+ reg [bitwidth+1:0] x0,y0;
+ reg [zwidth-2:0] z0;
+ wire [bitwidth+1:0] x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20;
+ wire [bitwidth+1:0] y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12,y13,y14,y15,y16,y17,y18,y19,y20;
+ wire [zwidth-2:0] z1,z2,z3,z4,z5,z6,z7,z8,z9,z10,z11,z12,z13,z14,z15,z16,z17,z18,z19,z20;
+
+ wire [bitwidth+1:0] xi_ext = {{2{xi[bitwidth-1]}},xi};
+ wire [bitwidth+1:0] yi_ext = {{2{yi[bitwidth-1]}},yi};
+
+ // Compute consts. Would be easier if vlog had atan...
+ // see gen_cordic_consts.py
+
+ // constants for 24 bit wide phase
+ localparam c00 = 24'd2097152;
+ localparam c01 = 24'd1238021;
+ localparam c02 = 24'd654136;
+ localparam c03 = 24'd332050;
+ localparam c04 = 24'd166669;
+ localparam c05 = 24'd83416;
+ localparam c06 = 24'd41718;
+ localparam c07 = 24'd20860;
+ localparam c08 = 24'd10430;
+ localparam c09 = 24'd5215;
+ localparam c10 = 24'd2608;
+ localparam c11 = 24'd1304;
+ localparam c12 = 24'd652;
+ localparam c13 = 24'd326;
+ localparam c14 = 24'd163;
+ localparam c15 = 24'd81;
+ localparam c16 = 24'd41;
+ localparam c17 = 24'd20;
+ localparam c18 = 24'd10;
+ localparam c19 = 24'd5;
+ localparam c20 = 24'd3;
+ localparam c21 = 24'd1;
+ localparam c22 = 24'd1;
+ localparam c23 = 24'd0;
+
+ always @(posedge clock)
+ if(reset)
+ begin
+ x0 <= 0; y0 <= 0; z0 <= 0;
+ end
+ else// if(enable)
+ begin
+ z0 <= zi[zwidth-2:0];
+ case (zi[zwidth-1:zwidth-2])
+ 2'b00, 2'b11 :
+ begin
+ x0 <= xi_ext;
+ y0 <= yi_ext;
+ end
+ 2'b01, 2'b10 :
+ begin
+ x0 <= -xi_ext;
+ y0 <= -yi_ext;
+ end
+ endcase // case(zi[zwidth-1:zwidth-2])
+ end // else: !if(reset)
+
+ // FIXME need to handle variable number of stages
+ // This would be easier if arrays worked better in vlog...
+
+ cordic_stage #(bitwidth+2,zwidth-1,0) cordic_stage0 (clock,reset,enable,x0,y0,z0,c00,x1,y1,z1);
+ cordic_stage #(bitwidth+2,zwidth-1,1) cordic_stage1 (clock,reset,enable,x1,y1,z1,c01,x2,y2,z2);
+ cordic_stage #(bitwidth+2,zwidth-1,2) cordic_stage2 (clock,reset,enable,x2,y2,z2,c02,x3,y3,z3);
+ cordic_stage #(bitwidth+2,zwidth-1,3) cordic_stage3 (clock,reset,enable,x3,y3,z3,c03,x4,y4,z4);
+ cordic_stage #(bitwidth+2,zwidth-1,4) cordic_stage4 (clock,reset,enable,x4,y4,z4,c04,x5,y5,z5);
+ cordic_stage #(bitwidth+2,zwidth-1,5) cordic_stage5 (clock,reset,enable,x5,y5,z5,c05,x6,y6,z6);
+ cordic_stage #(bitwidth+2,zwidth-1,6) cordic_stage6 (clock,reset,enable,x6,y6,z6,c06,x7,y7,z7);
+ cordic_stage #(bitwidth+2,zwidth-1,7) cordic_stage7 (clock,reset,enable,x7,y7,z7,c07,x8,y8,z8);
+ cordic_stage #(bitwidth+2,zwidth-1,8) cordic_stage8 (clock,reset,enable,x8,y8,z8,c08,x9,y9,z9);
+ cordic_stage #(bitwidth+2,zwidth-1,9) cordic_stage9 (clock,reset,enable,x9,y9,z9,c09,x10,y10,z10);
+ cordic_stage #(bitwidth+2,zwidth-1,10) cordic_stage10 (clock,reset,enable,x10,y10,z10,c10,x11,y11,z11);
+ cordic_stage #(bitwidth+2,zwidth-1,11) cordic_stage11 (clock,reset,enable,x11,y11,z11,c11,x12,y12,z12);
+ cordic_stage #(bitwidth+2,zwidth-1,12) cordic_stage12 (clock,reset,enable,x12,y12,z12,c12,x13,y13,z13);
+ cordic_stage #(bitwidth+2,zwidth-1,13) cordic_stage13 (clock,reset,enable,x13,y13,z13,c13,x14,y14,z14);
+ cordic_stage #(bitwidth+2,zwidth-1,14) cordic_stage14 (clock,reset,enable,x14,y14,z14,c14,x15,y15,z15);
+ cordic_stage #(bitwidth+2,zwidth-1,15) cordic_stage15 (clock,reset,enable,x15,y15,z15,c15,x16,y16,z16);
+ cordic_stage #(bitwidth+2,zwidth-1,16) cordic_stage16 (clock,reset,enable,x16,y16,z16,c16,x17,y17,z17);
+ cordic_stage #(bitwidth+2,zwidth-1,17) cordic_stage17 (clock,reset,enable,x17,y17,z17,c17,x18,y18,z18);
+ cordic_stage #(bitwidth+2,zwidth-1,18) cordic_stage18 (clock,reset,enable,x18,y18,z18,c18,x19,y19,z19);
+ cordic_stage #(bitwidth+2,zwidth-1,19) cordic_stage19 (clock,reset,enable,x19,y19,z19,c19,x20,y20,z20);
+
+ assign xo = x20[bitwidth:1];
+ assign yo = y20[bitwidth:1];
+ assign zo = z20;
+ //assign xo = x20[bitwidth+1:2]; // CORDIC gain is ~1.6, plus gain from rotating vectors
+ //assign yo = y20[bitwidth+1:2];
+
+endmodule // cordic
+
diff --git a/fpga/usrp2/sdr_lib/ddc.v b/fpga/usrp2/sdr_lib/ddc.v
new file mode 100755
index 000000000..0d4da9bbc
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/ddc.v
@@ -0,0 +1,97 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2003 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+
+
+// DDC block
+
+module ddc(input clock,
+ input reset,
+ input enable,
+ input [3:0] rate1,
+ input [3:0] rate2,
+ output strobe,
+ input [31:0] freq,
+ input [15:0] i_in,
+ input [15:0] q_in,
+ output [15:0] i_out,
+ output [15:0] q_out
+ );
+ parameter bw = 16;
+ parameter zw = 16;
+
+ wire [15:0] i_cordic_out, q_cordic_out;
+ wire [31:0] phase;
+
+ wire strobe1, strobe2;
+ reg [3:0] strobe_ctr1,strobe_ctr2;
+
+ always @(posedge clock)
+ if(reset | ~enable)
+ strobe_ctr2 <= #1 4'd0;
+ else if(strobe2)
+ strobe_ctr2 <= #1 4'd0;
+ else
+ strobe_ctr2 <= #1 strobe_ctr2 + 4'd1;
+
+ always @(posedge clock)
+ if(reset | ~enable)
+ strobe_ctr1 <= #1 4'd0;
+ else if(strobe1)
+ strobe_ctr1 <= #1 4'd0;
+ else if(strobe2)
+ strobe_ctr1 <= #1 strobe_ctr1 + 4'd1;
+
+
+ assign strobe2 = enable & ( strobe_ctr2 == rate2 );
+ assign strobe1 = strobe2 & ( strobe_ctr1 == rate1 );
+
+ assign strobe = strobe1;
+
+ function [2:0] log_ceil;
+ input [3:0] val;
+
+ log_ceil = val[3] ? 3'd4 : val[2] ? 3'd3 : val[1] ? 3'd2 : 3'd1;
+ endfunction
+
+ wire [2:0] shift1 = log_ceil(rate1);
+ wire [2:0] shift2 = log_ceil(rate2);
+
+ cordic #(.bitwidth(bw),.zwidth(zw),.stages(16))
+ cordic(.clock(clock), .reset(reset), .enable(enable),
+ .xi(i_in), .yi(q_in), .zi(phase[31:32-zw]),
+ .xo(i_cordic_out), .yo(q_cordic_out), .zo() );
+
+ cic_decim_2stage #(.bw(bw),.N(4))
+ decim_i(.clock(clock),.reset(reset),.enable(enable),
+ .strobe1(1'b1),.strobe2(strobe2),.strobe3(strobe1),.shift1(shift2),.shift2(shift1),
+ .signal_in(i_cordic_out),.signal_out(i_out));
+
+ cic_decim_2stage #(.bw(bw),.N(4))
+ decim_q(.clock(clock),.reset(reset),.enable(enable),
+ .strobe1(1'b1),.strobe2(strobe2),.strobe3(strobe1),.shift1(shift2),.shift2(shift1),
+ .signal_in(q_cordic_out),.signal_out(q_out));
+
+ phase_acc #(.resolution(32))
+ nco (.clk(clock),.reset(reset),.enable(enable),
+ .freq(freq),.phase(phase));
+
+endmodule
diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx.v b/fpga/usrp2/sdr_lib/dsp_core_rx.v
new file mode 100644
index 000000000..2ac429630
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/dsp_core_rx.v
@@ -0,0 +1,179 @@
+
+module dsp_core_rx
+ #(parameter BASE = 160)
+ (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 [15:0] io_rx,
+
+ output [31:0] sample,
+ input run,
+ output strobe,
+ 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 [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 strobe_cic, strobe_hb1, strobe_hb2;
+ wire enable_hb1, enable_hb2;
+ wire [7:0] cic_decim_rate;
+
+ 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)) 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 [3:0] muxctrl;
+ setting_reg #(.my_addr(BASE+5)) 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)) sr_9
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(gpio_ena),.changed());
+
+ // The TVRX connects to what is called adc_b, thus A and B are
+ // swapped throughout the design.
+ //
+ // In the interest of expediency and keeping the s/w sane, we just remap them here.
+ // The I & Q fields are mapped the same:
+ // 0 -> "the real A" (as determined by the TVRX)
+ // 1 -> "the real B"
+ // 2 -> const zero
+
+ always @(posedge clk)
+ case(muxctrl[1:0]) // The I mapping
+ 0: adc_i <= adc_b_ofs; // "the real A"
+ 1: adc_i <= adc_a_ofs;
+ 2: adc_i <= 0;
+ default: adc_i <= 0;
+ endcase // case(muxctrl[1:0])
+
+ always @(posedge clk)
+ case(muxctrl[3:2]) // The Q mapping
+ 0: adc_q <= adc_b_ofs; // "the real A"
+ 1: adc_q <= adc_a_ofs;
+ 2: adc_q <= 0;
+ default: adc_q <= 0;
+ endcase // case(muxctrl[3:2])
+
+ always @(posedge clk)
+ if(rst)
+ phase <= 0;
+ else if(~run)
+ phase <= 0;
+ 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(.clock(clk), .reset(rst), .enable(run),
+ .xi(prod_i[23:0]),. yi(prod_q[23:0]), .zi(phase[31:8]),
+ .xo(i_cordic),.yo(q_cordic),.zo() );
+
+ 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));
+
+ 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));
+
+ 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
+ (.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));
+
+ small_hb_dec #(.WIDTH(18)) 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));
+
+ 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
+ (.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
+ (.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));
+
+ // Streaming GPIO
+ //
+ // io_rx[15] => I channel LSB if gpio_ena[0] high
+ // io_rx[14] => Q channel LSB if gpio_ena[1] high
+
+ reg [31:0] sample_reg;
+ always @(posedge clk)
+ begin
+ sample_reg[31:17] <= i_out[15:1];
+ sample_reg[15:1] <= q_out[15:1];
+ sample_reg[16] <= gpio_ena[0] ? io_rx[15] : i_out[0];
+ sample_reg[0] <= gpio_ena[1] ? io_rx[14] : q_out[0];
+ end
+
+ 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};
+
+endmodule // dsp_core_rx
diff --git a/fpga/usrp2/sdr_lib/dsp_core_tx.v b/fpga/usrp2/sdr_lib/dsp_core_tx.v
new file mode 100644
index 000000000..22d3d44a3
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/dsp_core_tx.v
@@ -0,0 +1,151 @@
+
+module dsp_core_tx
+ #(parameter BASE=0)
+ (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,
+
+ // To tx_control
+ input [31:0] sample,
+ input run,
+ output strobe,
+ output [31:0] debug
+ );
+
+ wire [15:0] i, q, scale_i, scale_q;
+ wire [31:0] phase_inc;
+ reg [31:0] phase;
+ wire [7:0] interp_rate;
+ wire [3:0] dacmux_a, dacmux_b;
+ wire enable_hb1, enable_hb2;
+
+ 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)) sr_2
+ (.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)) 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;
+ reg strobe_hb1 = 1;
+ reg strobe_hb2 = 1;
+
+ cic_strober #(.WIDTH(8))
+ cic_strober(.clock(clk),.reset(rst),.enable(run),.rate(interp_rate),
+ .strobe_fast(1),.strobe_slow(strobe_cic_pre) );
+ cic_strober #(.WIDTH(2))
+ hb2_strober(.clock(clk),.reset(rst),.enable(run),.rate(enable_hb2 ? 2 : 1),
+ .strobe_fast(strobe_cic_pre),.strobe_slow(strobe_hb2_pre) );
+ cic_strober #(.WIDTH(2))
+ hb1_strober(.clock(clk),.reset(rst),.enable(run),.rate(enable_hb1 ? 2 : 1),
+ .strobe_fast(strobe_hb2_pre),.strobe_slow(strobe_hb1_pre) );
+
+ always @(posedge clk) strobe_hb1 <= strobe_hb1_pre;
+ always @(posedge clk) strobe_hb2 <= strobe_hb2_pre;
+ always @(posedge clk) strobe_cic <= strobe_cic_pre;
+
+ // NCO
+ always @(posedge clk)
+ if(rst)
+ phase <= 0;
+ else if(~run)
+ phase <= 0;
+ else
+ phase <= phase + phase_inc;
+
+ wire signed [17:0] da, db;
+ wire signed [35:0] prod_i, prod_q;
+
+ wire [17:0] bb_i = {sample[31:16],2'b0};
+ wire [17:0] bb_q = {sample[15:0],2'b0};
+ wire [17:0] i_interp, q_interp;
+
+ wire [17:0] hb1_i, hb1_q, hb2_i, hb2_q;
+
+ wire [7:0] cpo = enable_hb2 ? ({interp_rate,1'b0}) : interp_rate;
+ // Note that max CIC rate is 128, which would give an overflow on cpo if enable_hb2 is true,
+ // but the default case inside hb_interp handles this
+
+ hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(24)) hb_interp_i
+ (.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in(bb_i),.stb_out(strobe_hb2),.data_out(hb1_i));
+ hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(24)) hb_interp_q
+ (.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in(bb_q),.stb_out(strobe_hb2),.data_out(hb1_q));
+
+ small_hb_int #(.WIDTH(18)) small_hb_interp_i
+ (.clk(clk),.rst(rst),.bypass(~enable_hb2),.stb_in(strobe_hb2),.data_in(hb1_i),
+ .output_rate(interp_rate),.stb_out(strobe_cic),.data_out(hb2_i));
+ small_hb_int #(.WIDTH(18)) small_hb_interp_q
+ (.clk(clk),.rst(rst),.bypass(~enable_hb2),.stb_in(strobe_hb2),.data_in(hb1_q),
+ .output_rate(interp_rate),.stb_out(strobe_cic),.data_out(hb2_q));
+
+ cic_interp #(.bw(18),.N(4),.log2_of_max_rate(7))
+ cic_interp_i(.clock(clk),.reset(rst),.enable(run),.rate(interp_rate),
+ .strobe_in(strobe_cic),.strobe_out(1),
+ .signal_in(hb2_i),.signal_out(i_interp));
+
+ cic_interp #(.bw(18),.N(4),.log2_of_max_rate(7))
+ cic_interp_q(.clock(clk),.reset(rst),.enable(run),.rate(interp_rate),
+ .strobe_in(strobe_cic),.strobe_out(1),
+ .signal_in(hb2_q),.signal_out(q_interp));
+
+ assign strobe = strobe_hb1;
+
+ localparam cwidth = 24; // was 18
+ localparam zwidth = 24; // was 16
+
+ wire [cwidth-1:0] da_c, db_c;
+
+ cordic_z24 #(.bitwidth(cwidth))
+ cordic(.clock(clk), .reset(rst), .enable(run),
+ .xi({i_interp,{(cwidth-18){1'b0}}}),.yi({q_interp,{(cwidth-18){1'b0}}}),
+ .zi(phase[31:32-zwidth]),
+ .xo(da_c),.yo(db_c),.zo() );
+
+ MULT18X18S MULT18X18S_inst
+ (.P(prod_i), // 36-bit multiplier output
+ .A(da_c[cwidth-1:cwidth-18]), // 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 MULT18X18S_inst_2
+ (.P(prod_q), // 36-bit multiplier output
+ .A(db_c[cwidth-1:cwidth-18]), // 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
+ );
+
+ 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 debug = {strobe_cic, strobe_hb1, strobe_hb2,run};
+
+endmodule // dsp_core
diff --git a/fpga/usrp2/sdr_lib/duc.v b/fpga/usrp2/sdr_lib/duc.v
new file mode 100755
index 000000000..6dac95b49
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/duc.v
@@ -0,0 +1,95 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2003 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+// DUC block
+
+module duc(input clock,
+ input reset,
+ input enable,
+ input [3:0] rate1,
+ input [3:0] rate2,
+ output strobe,
+ input [31:0] freq,
+ input [15:0] i_in,
+ input [15:0] q_in,
+ output [15:0] i_out,
+ output [15:0] q_out
+ );
+ parameter bw = 16;
+ parameter zw = 16;
+
+ wire [15:0] i_interp_out, q_interp_out;
+ wire [31:0] phase;
+
+ wire strobe1, strobe2;
+ reg [3:0] strobe_ctr1,strobe_ctr2;
+
+ always @(posedge clock)
+ if(reset | ~enable)
+ strobe_ctr2 <= #1 4'd0;
+ else if(strobe2)
+ strobe_ctr2 <= #1 4'd0;
+ else
+ strobe_ctr2 <= #1 strobe_ctr2 + 4'd1;
+
+ always @(posedge clock)
+ if(reset | ~enable)
+ strobe_ctr1 <= #1 4'd0;
+ else if(strobe1)
+ strobe_ctr1 <= #1 4'd0;
+ else if(strobe2)
+ strobe_ctr1 <= #1 strobe_ctr1 + 4'd1;
+
+
+ assign strobe2 = enable & ( strobe_ctr2 == rate2 );
+ assign strobe1 = strobe2 & ( strobe_ctr1 == rate1 );
+
+ assign strobe = strobe1;
+
+ function [2:0] log_ceil;
+ input [3:0] val;
+
+ log_ceil = val[3] ? 3'd4 : val[2] ? 3'd3 : val[1] ? 3'd2 : 3'd1;
+ endfunction
+
+ wire [2:0] shift1 = log_ceil(rate1);
+ wire [2:0] shift2 = log_ceil(rate2);
+
+ cordic #(.bitwidth(bw),.zwidth(zw),.stages(16))
+ cordic(.clock(clock), .reset(reset), .enable(enable),
+ .xi(i_interp_out), .yi(q_interp_out), .zi(phase[31:32-zw]),
+ .xo(i_out), .yo(q_out), .zo() );
+
+ cic_interp_2stage #(.bw(bw),.N(4))
+ interp_i(.clock(clock),.reset(reset),.enable(enable),
+ .strobe1(strobe1),.strobe2(strobe2),.strobe3(1'b1),.shift1(shift1),.shift2(shift2),
+ .signal_in(i_in),.signal_out(i_interp_out));
+
+ cic_interp_2stage #(.bw(bw),.N(4))
+ interp_q(.clock(clock),.reset(reset),.enable(enable),
+ .strobe1(strobe1),.strobe2(strobe2),.strobe3(1'b1),.shift1(shift1),.shift2(shift2),
+ .signal_in(q_in),.signal_out(q_interp_out));
+
+ phase_acc #(.resolution(32))
+ nco (.clk(clock),.reset(reset),.enable(enable),
+ .freq(freq),.phase(phase));
+
+endmodule
diff --git a/fpga/usrp2/sdr_lib/dummy_rx.v b/fpga/usrp2/sdr_lib/dummy_rx.v
new file mode 100644
index 000000000..99290ecec
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/dummy_rx.v
@@ -0,0 +1,62 @@
+
+`define DSP_CORE_RX_BASE 160
+module dummy_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,
+
+ output [31:0] sample,
+ input run,
+ output strobe
+ );
+
+ wire [15:0] scale_i, scale_q;
+ wire [31:0] phase_inc;
+ reg [31:0] phase;
+
+ wire [23:0] i_decim, q_decim;
+ wire [7:0] decim_rate;
+
+ setting_reg #(.my_addr(`DSP_CORE_RX_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(`DSP_CORE_RX_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(`DSP_CORE_RX_BASE+2)) sr_2
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(decim_rate),.changed());
+
+ strobe_gen strobe_gen(.clock(clk),.reset(rst),.enable(run),.rate(decim_rate),
+ .strobe_in(1),.strobe(strobe) );
+
+ reg [15:0] i_out, q_out;
+ assign sample = {i_out,q_out};
+
+ always @(posedge clk)
+ if(rst)
+ i_out <= 0;
+ else if(~run)
+ i_out <= 0;
+ else if(strobe)
+ i_out <= i_out + 1;
+
+ reg run_d1;
+ always @(posedge clk)
+ if(rst)
+ run_d1 <= 0;
+ else
+ run_d1 <= run;
+
+ always @(posedge clk)
+ if(rst)
+ q_out <= 0;
+ else if (run & ~run_d1)
+ q_out <= q_out + 1;
+
+
+endmodule // dsp_core_rx
diff --git a/fpga/usrp2/sdr_lib/gen_cordic_consts.py b/fpga/usrp2/sdr_lib/gen_cordic_consts.py
new file mode 100755
index 000000000..261e8c223
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/gen_cordic_consts.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+import math
+
+zwidth = 24
+
+for i in range(24):
+ c = math.atan (1.0/(2**i)) / (2 * math.pi) * (1 << zwidth)
+ print "localparam c%02d = %d'd%d;" % (i, zwidth, round (c))
+
diff --git a/fpga/usrp2/sdr_lib/halfband_ideal.v b/fpga/usrp2/sdr_lib/halfband_ideal.v
new file mode 100644
index 000000000..484cfff2a
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/halfband_ideal.v
@@ -0,0 +1,84 @@
+module halfband_ideal (
+ input clock,
+ input reset,
+ input enable,
+ input strobe_in,
+ input wire signed [17:0] data_in,
+ output reg strobe_out,
+ output reg signed [17:0] data_out
+) ;
+
+ parameter decim = 1 ;
+ parameter rate = 2 ;
+
+ reg signed [40:0] temp ;
+ reg signed [17:0] delay[30:0] ;
+ reg signed [17:0] coeffs[30:0] ;
+ reg [7:0] count ;
+ integer i ;
+
+ initial begin
+ for( i = 0 ; i < 31 ; i = i + 1 ) begin
+ coeffs[i] = 18'd0 ;
+ end
+ coeffs[0] = -1390 ;
+ coeffs[2] = 1604 ;
+ coeffs[4] = -1896 ;
+ coeffs[6] = 2317 ;
+ coeffs[8] = -2979 ;
+ coeffs[10] = 4172 ;
+ coeffs[12] = -6953 ;
+ coeffs[14] = 20860 ;
+ coeffs[15] = 32768 ;
+ coeffs[16] = 20860 ;
+ coeffs[18] = -6953 ;
+ coeffs[20] = 4172 ;
+ coeffs[22] = -2979 ;
+ coeffs[24] = 2317 ;
+ coeffs[26] = -1896 ;
+ coeffs[28] = 1604 ;
+ coeffs[30] = -1390 ;
+ end
+
+ always @(posedge clock) begin
+ if( reset ) begin
+ count <= 0 ;
+ for( i = 0 ; i < 31 ; i = i + 1 ) begin
+ delay[i] <= 18'd0 ;
+ end
+ temp <= 41'd0 ;
+ data_out <= 18'd0 ;
+ strobe_out <= 1'b0 ;
+ end else if( enable ) begin
+
+ if( (decim && (count == rate-1)) || !decim )
+ strobe_out <= strobe_in ;
+ else
+ strobe_out <= 1'b0 ;
+
+
+ if( strobe_in ) begin
+ // Increment decimation count
+ count <= count + 1 ;
+
+ // Shift the input
+ for( i = 30 ; i > 0 ; i = i - 1 ) begin
+ delay[i] = delay[i-1] ;
+ end
+ delay[0] = data_in ;
+
+ // clear the temp reg
+ temp = 18'd0 ;
+ if( (decim && (count == rate-1)) || !decim ) begin
+ count <= 0 ;
+ for( i = 0 ; i < 31 ; i = i + 1 ) begin
+ // Multiply Accumulate
+ temp = temp + delay[i]*coeffs[i] ;
+ end
+ // Assign data output
+ data_out <= temp >>> 15 ;
+ end
+ end
+ end
+ end
+endmodule
diff --git a/fpga/usrp2/sdr_lib/halfband_tb.v b/fpga/usrp2/sdr_lib/halfband_tb.v
new file mode 100644
index 000000000..231dd00d7
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/halfband_tb.v
@@ -0,0 +1,120 @@
+module halfband_tb( ) ;
+
+ // Parameters for instantiation
+ parameter clocks = 2 ; // Number of clocks per input
+ parameter decim = 0 ; // Sets the filter to decimate
+ parameter rate = 2 ; // Sets the decimation rate
+
+ reg clock ;
+ reg reset ;
+ reg enable ;
+ reg strobe_in ;
+ reg signed [17:0] data_in ;
+ wire strobe_out ;
+ wire signed [17:0] data_out ;
+
+ // Setup the clock
+ initial clock = 1'b0 ;
+ always #5 clock <= ~clock ;
+
+ // Come out of reset after a while
+ initial reset = 1'b1 ;
+ initial #100 reset = 1'b0 ;
+
+ // Enable the entire system
+ initial enable = 1'b1 ;
+
+ // Instantiate UUT
+ halfband_ideal
+ #(
+ .decim ( decim ),
+ .rate ( rate )
+ ) uut(
+ .clock ( clock ),
+ .reset ( reset ),
+ .enable ( enable ),
+ .strobe_in ( strobe_in ),
+ .data_in ( data_in ),
+ .strobe_out ( strobe_out ),
+ .data_out ( data_out )
+ ) ;
+
+ integer i, ri, ro, infile, outfile ;
+
+ // Setup file IO
+ initial begin
+ infile = $fopen("input.dat","r") ;
+ outfile = $fopen("output.dat","r") ;
+ $timeformat(-9, 2, " ns", 10) ;
+ end
+
+ reg endofsim ;
+ reg signed [17:0] compare ;
+ integer noe ;
+ initial noe = 0 ;
+
+ initial begin
+ // Initialize inputs
+ strobe_in <= 1'd0 ;
+ data_in <= 18'd0 ;
+
+ // Wait for reset to go away
+ @(negedge reset) #0 ;
+
+ // While we're still simulating ...
+ while( !endofsim ) begin
+
+ // Write the input from the file or 0 if EOF...
+ @( posedge clock ) begin
+ #1 ;
+ strobe_in <= 1'b1 ;
+ if( !$feof(infile) )
+ ri = $fscanf( infile, "%d", data_in ) ;
+ else
+ data_in <= 18'd0 ;
+ end
+
+ // Clocked in - set the strobe to 0 if the number of
+ // clocks per sample is greater than 1
+ if( clocks > 1 ) begin
+ @(posedge clock) begin
+ strobe_in <= 1'b0 ;
+ end
+
+ // Wait for the specified number of cycles
+ for( i = 0 ; i < (clocks-2) ; i = i + 1 ) begin
+ @(posedge clock) #1 ;
+ end
+ end
+ end
+
+ // Print out the number of errors that occured
+ if( noe )
+ $display( "FAILED: %d errors during simulation", noe ) ;
+ else
+ $display( "PASSED: Simulation successful" ) ;
+
+ $stop ;
+ end
+
+ // Output comparison of simulated values versus known good values
+ always @ (posedge clock) begin
+ if( reset )
+ endofsim <= 1'b0 ;
+ else begin
+ if( !$feof(outfile) ) begin
+ if( strobe_out ) begin
+ ro = $fscanf( outfile, "%d\n", compare ) ;
+ if( compare != data_out ) begin
+ $display( "%t: %d != %d", $realtime, data_out, compare ) ;
+ noe = noe + 1 ;
+ end
+ end
+ end else begin
+ // Signal end of simulation when no more outputs
+ endofsim <= 1'b1 ;
+ end
+ end
+ end
+
+endmodule
diff --git a/fpga/usrp2/sdr_lib/hb/acc.v b/fpga/usrp2/sdr_lib/hb/acc.v
new file mode 100644
index 000000000..195d5ea94
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/acc.v
@@ -0,0 +1,22 @@
+
+
+module acc (input clock, input reset, input clear, input enable_in, output reg enable_out,
+ input signed [30:0] addend, output reg signed [33:0] sum );
+
+ always @(posedge clock)
+ if(reset)
+ sum <= #1 34'd0;
+ //else if(clear & enable_in)
+ // sum <= #1 addend;
+ //else if(clear)
+ // sum <= #1 34'd0;
+ else if(clear)
+ sum <= #1 addend;
+ else if(enable_in)
+ sum <= #1 sum + addend;
+
+ always @(posedge clock)
+ enable_out <= #1 enable_in;
+
+endmodule // acc
+
diff --git a/fpga/usrp2/sdr_lib/hb/coeff_ram.v b/fpga/usrp2/sdr_lib/hb/coeff_ram.v
new file mode 100644
index 000000000..65460822f
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/coeff_ram.v
@@ -0,0 +1,26 @@
+
+
+module coeff_ram (input clock, input [3:0] rd_addr, output reg [15:0] rd_data);
+
+ always @(posedge clock)
+ case (rd_addr)
+ 4'd0 : rd_data <= #1 -16'd16;
+ 4'd1 : rd_data <= #1 16'd74;
+ 4'd2 : rd_data <= #1 -16'd254;
+ 4'd3 : rd_data <= #1 16'd669;
+ 4'd4 : rd_data <= #1 -16'd1468;
+ 4'd5 : rd_data <= #1 16'd2950;
+ 4'd6 : rd_data <= #1 -16'd6158;
+ 4'd7 : rd_data <= #1 16'd20585;
+ 4'd8 : rd_data <= #1 16'd20585;
+ 4'd9 : rd_data <= #1 -16'd6158;
+ 4'd10 : rd_data <= #1 16'd2950;
+ 4'd11 : rd_data <= #1 -16'd1468;
+ 4'd12 : rd_data <= #1 16'd669;
+ 4'd13 : rd_data <= #1 -16'd254;
+ 4'd14 : rd_data <= #1 16'd74;
+ 4'd15 : rd_data <= #1 -16'd16;
+ default : rd_data <= #1 16'd0;
+ endcase // case(rd_addr)
+
+endmodule // ram
diff --git a/fpga/usrp2/sdr_lib/hb/coeff_rom.v b/fpga/usrp2/sdr_lib/hb/coeff_rom.v
new file mode 100644
index 000000000..7f8886b4e
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/coeff_rom.v
@@ -0,0 +1,19 @@
+
+
+module coeff_rom (input clock, input [2:0] addr, output reg [15:0] data);
+
+ always @(posedge clock)
+ case (addr)
+ 3'd0 : data <= #1 -16'd49;
+ 3'd1 : data <= #1 16'd165;
+ 3'd2 : data <= #1 -16'd412;
+ 3'd3 : data <= #1 16'd873;
+ 3'd4 : data <= #1 -16'd1681;
+ 3'd5 : data <= #1 16'd3135;
+ 3'd6 : data <= #1 -16'd6282;
+ 3'd7 : data <= #1 16'd20628;
+ endcase // case(addr)
+
+endmodule // coeff_rom
+
+
diff --git a/fpga/usrp2/sdr_lib/hb/halfband_decim.v b/fpga/usrp2/sdr_lib/hb/halfband_decim.v
new file mode 100644
index 000000000..dff4d902c
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/halfband_decim.v
@@ -0,0 +1,163 @@
+/* -*- verilog -*-
+ *
+ * USRP - Universal Software Radio Peripheral
+ *
+ * Copyright (C) 2005 Matt Ettus
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * This implements a 31-tap halfband filter that decimates by two.
+ * The coefficients are symmetric, and with the exception of the middle tap,
+ * every other coefficient is zero. The middle section of taps looks like this:
+ *
+ * ..., -1468, 0, 2950, 0, -6158, 0, 20585, 32768, 20585, 0, -6158, 0, 2950, 0, -1468, ...
+ * |
+ * middle tap -------+
+ *
+ * See coeff_rom.v for the full set. The taps are scaled relative to 32768,
+ * thus the middle tap equals 1.0. Not counting the middle tap, there are 8
+ * non-zero taps on each side, and they are symmetric. A naive implementation
+ * requires a mulitply for each non-zero tap. Because of symmetry, we can
+ * replace 2 multiplies with 1 add and 1 multiply. Thus, to compute each output
+ * sample, we need to perform 8 multiplications. Since the middle tap is 1.0,
+ * we just add the corresponding delay line value.
+ *
+ * About timing: We implement this with a single multiplier, so it takes
+ * 8 cycles to compute a single output. However, since we're decimating by two
+ * we can accept a new input value every 4 cycles. strobe_in is asserted when
+ * there's a new input sample available. Depending on the overall decimation
+ * rate, strobe_in may be asserted less frequently than once every 4 clocks.
+ * On the output side, we assert strobe_out when output contains a new sample.
+ *
+ * Implementation: Every time strobe_in is asserted we store the new data into
+ * the delay line. We split the delay line into two components, one for the
+ * even samples, and one for the odd samples. ram16_odd is the delay line for
+ * the odd samples. This ram is written on each odd assertion of strobe_in, and
+ * is read on each clock when we're computing the dot product. ram16_even is
+ * similar, although because it holds the even samples we must be able to read
+ * two samples from different addresses at the same time, while writing the incoming
+ * even samples. Thus it's "triple-ported".
+ */
+
+module halfband_decim
+ (input clock, input reset, input enable, input strobe_in, output wire strobe_out,
+ input wire [15:0] data_in, output reg [15:0] data_out,output wire [15:0] debugctrl);
+
+ reg [3:0] rd_addr1;
+ reg [3:0] rd_addr2;
+ reg [3:0] phase;
+ reg [3:0] base_addr;
+
+ wire signed [15:0] mac_out,middle_data, sum, coeff;
+ wire signed [30:0] product;
+ wire signed [33:0] sum_even;
+ wire clear;
+ reg store_odd;
+
+ always @(posedge clock)
+ if(reset)
+ store_odd <= #1 1'b0;
+ else
+ if(strobe_in)
+ store_odd <= #1 ~store_odd;
+
+ wire start = strobe_in & store_odd;
+ always @(posedge clock)
+ if(reset)
+ base_addr <= #1 4'd0;
+ else if(start)
+ base_addr <= #1 base_addr + 4'd1;
+
+ always @(posedge clock)
+ if(reset)
+ phase <= #1 4'd8;
+ else if (start)
+ phase <= #1 4'd0;
+ else if(phase != 4'd8)
+ phase <= #1 phase + 4'd1;
+
+ reg start_d1,start_d2,start_d3,start_d4,start_d5,start_d6,start_d7,start_d8,start_d9,start_dA,start_dB,start_dC,start_dD;
+ always @(posedge clock)
+ begin
+ start_d1 <= #1 start;
+ start_d2 <= #1 start_d1;
+ start_d3 <= #1 start_d2;
+ start_d4 <= #1 start_d3;
+ start_d5 <= #1 start_d4;
+ start_d6 <= #1 start_d5;
+ start_d7 <= #1 start_d6;
+ start_d8 <= #1 start_d7;
+ start_d9 <= #1 start_d8;
+ start_dA <= #1 start_d9;
+ start_dB <= #1 start_dA;
+ start_dC <= #1 start_dB;
+ start_dD <= #1 start_dC;
+ end // always @ (posedge clock)
+
+ reg mult_en, mult_en_pre;
+ always @(posedge clock)
+ begin
+ mult_en_pre <= #1 phase!=8;
+ mult_en <= #1 mult_en_pre;
+ end
+
+ assign clear = start_d4; // was dC
+ wire latch_result = start_d4; // was dC
+ assign strobe_out = start_d5; // was dD
+ wire acc_en;
+
+ always @*
+ case(phase[2:0])
+ 3'd0 : begin rd_addr1 = base_addr + 4'd0; rd_addr2 = base_addr + 4'd15; end
+ 3'd1 : begin rd_addr1 = base_addr + 4'd1; rd_addr2 = base_addr + 4'd14; end
+ 3'd2 : begin rd_addr1 = base_addr + 4'd2; rd_addr2 = base_addr + 4'd13; end
+ 3'd3 : begin rd_addr1 = base_addr + 4'd3; rd_addr2 = base_addr + 4'd12; end
+ 3'd4 : begin rd_addr1 = base_addr + 4'd4; rd_addr2 = base_addr + 4'd11; end
+ 3'd5 : begin rd_addr1 = base_addr + 4'd5; rd_addr2 = base_addr + 4'd10; end
+ 3'd6 : begin rd_addr1 = base_addr + 4'd6; rd_addr2 = base_addr + 4'd9; end
+ 3'd7 : begin rd_addr1 = base_addr + 4'd7; rd_addr2 = base_addr + 4'd8; end
+ default: begin rd_addr1 = base_addr + 4'd0; rd_addr2 = base_addr + 4'd15; end
+ endcase // case(phase)
+
+ coeff_rom coeff_rom (.clock(clock),.addr(phase[2:0]-3'd1),.data(coeff));
+
+ ram16_2sum ram16_even (.clock(clock),.write(strobe_in & ~store_odd),
+ .wr_addr(base_addr),.wr_data(data_in),
+ .rd_addr1(rd_addr1),.rd_addr2(rd_addr2),
+ .sum(sum));
+
+ ram16 ram16_odd (.clock(clock),.write(strobe_in & store_odd), // Holds middle items
+ .wr_addr(base_addr),.wr_data(data_in),
+ //.rd_addr(base_addr+4'd7),.rd_data(middle_data));
+ .rd_addr(base_addr+4'd6),.rd_data(middle_data));
+
+ mult mult(.clock(clock),.x(coeff),.y(sum),.product(product),.enable_in(mult_en),.enable_out(acc_en));
+
+ acc acc(.clock(clock),.reset(reset),.enable_in(acc_en),.enable_out(),
+ .clear(clear),.addend(product),.sum(sum_even));
+
+ wire signed [33:0] dout = sum_even + {{4{middle_data[15]}},middle_data,14'b0}; // We already divided product by 2!!!!
+
+ always @(posedge clock)
+ if(reset)
+ data_out <= #1 16'd0;
+ else if(latch_result)
+ data_out <= #1 dout[30:15] + (dout[33]& |dout[14:0]);
+
+ assign debugctrl = { clock,reset,acc_en,mult_en,clear,latch_result,store_odd,strobe_in,strobe_out,phase};
+
+endmodule // halfband_decim
diff --git a/fpga/usrp2/sdr_lib/hb/halfband_interp.v b/fpga/usrp2/sdr_lib/hb/halfband_interp.v
new file mode 100644
index 000000000..cdb11c1f6
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/halfband_interp.v
@@ -0,0 +1,121 @@
+
+
+module halfband_interp
+ (input clock, input reset, input enable,
+ input strobe_in, input strobe_out,
+ input [15:0] signal_in_i, input [15:0] signal_in_q,
+ output reg [15:0] signal_out_i, output reg [15:0] signal_out_q,
+ output wire [12:0] debug);
+
+ wire [15:0] coeff_ram_out;
+ wire [15:0] data_ram_out_i;
+ wire [15:0] data_ram_out_q;
+
+ wire [3:0] data_rd_addr;
+ reg [3:0] data_wr_addr;
+ reg [2:0] coeff_rd_addr;
+
+ wire filt_done;
+
+ wire [15:0] mac_out_i;
+ wire [15:0] mac_out_q;
+ reg [15:0] delayed_middle_i, delayed_middle_q;
+ wire [7:0] shift = 8'd9;
+
+ reg stb_out_happened;
+
+ wire [15:0] data_ram_out_i_b;
+
+ always @(posedge clock)
+ if(strobe_in)
+ stb_out_happened <= #1 1'b0;
+ else if(strobe_out)
+ stb_out_happened <= #1 1'b1;
+
+assign debug = {filt_done,data_rd_addr,data_wr_addr,coeff_rd_addr};
+
+ wire [15:0] signal_out_i = stb_out_happened ? mac_out_i : delayed_middle_i;
+ wire [15:0] signal_out_q = stb_out_happened ? mac_out_q : delayed_middle_q;
+
+/* always @(posedge clock)
+ if(reset)
+ begin
+ signal_out_i <= #1 16'd0;
+ signal_out_q <= #1 16'd0;
+ end
+ else if(strobe_in)
+ begin
+ signal_out_i <= #1 delayed_middle_i; // Multiply by 1 for middle coeff
+ signal_out_q <= #1 delayed_middle_q;
+ end
+ //else if(filt_done&stb_out_happened)
+ else if(stb_out_happened)
+ begin
+ signal_out_i <= #1 mac_out_i;
+ signal_out_q <= #1 mac_out_q;
+ end
+*/
+
+ always @(posedge clock)
+ if(reset)
+ coeff_rd_addr <= #1 3'd0;
+ else if(coeff_rd_addr != 3'd0)
+ coeff_rd_addr <= #1 coeff_rd_addr + 3'd1;
+ else if(strobe_in)
+ coeff_rd_addr <= #1 3'd1;
+
+ reg filt_done_d1;
+ always@(posedge clock)
+ filt_done_d1 <= #1 filt_done;
+
+ always @(posedge clock)
+ if(reset)
+ data_wr_addr <= #1 4'd0;
+ //else if(strobe_in)
+ else if(filt_done & ~filt_done_d1)
+ data_wr_addr <= #1 data_wr_addr + 4'd1;
+
+ always @(posedge clock)
+ if(coeff_rd_addr == 3'd7)
+ begin
+ delayed_middle_i <= #1 data_ram_out_i_b;
+ // delayed_middle_q <= #1 data_ram_out_q_b;
+ end
+
+// always @(posedge clock)
+// if(reset)
+// data_rd_addr <= #1 4'd0;
+// else if(strobe_in)
+// data_rd_addr <= #1 data_wr_addr + 4'd1;
+// else if(!filt_done)
+// data_rd_addr <= #1 data_rd_addr + 4'd1;
+// else
+// data_rd_addr <= #1 data_wr_addr;
+
+ wire [3:0] data_rd_addr1 = data_wr_addr + {1'b0,coeff_rd_addr};
+ wire [3:0] data_rd_addr2 = data_wr_addr + 15 - {1'b0,coeff_rd_addr};
+// always @(posedge clock)
+// if(reset)
+// filt_done <= #1 1'b1;
+// else if(strobe_in)
+ // filt_done <= #1 1'b0;
+// else if(coeff_rd_addr == 4'd0)
+// filt_done <= #1 1'b1;
+
+ assign filt_done = (coeff_rd_addr == 3'd0);
+
+ coeff_ram coeff_ram ( .clock(clock),.rd_addr({1'b0,coeff_rd_addr}),.rd_data(coeff_ram_out) );
+
+ ram16_2sum data_ram_i ( .clock(clock),.write(strobe_in),.wr_addr(data_wr_addr),.wr_data(signal_in_i),
+ .rd_addr1(data_rd_addr1),.rd_addr2(data_rd_addr2),.rd_data(data_ram_out_i_b),.sum(data_ram_out_i));
+
+ ram16_2sum data_ram_q ( .clock(clock),.write(strobe_in),.wr_addr(data_wr_addr),.wr_data(signal_in_q),
+ .rd_addr1(data_rd_addr1),.rd_addr2(data_rd_addr2),.rd_data(data_ram_out_q));
+
+ mac mac_i (.clock(clock),.reset(reset),.enable(~filt_done),.clear(strobe_in),
+ .x(data_ram_out_i),.y(coeff_ram_out),.shift(shift),.z(mac_out_i) );
+
+ mac mac_q (.clock(clock),.reset(reset),.enable(~filt_done),.clear(strobe_in),
+ .x(data_ram_out_q),.y(coeff_ram_out),.shift(shift),.z(mac_out_q) );
+
+endmodule // halfband_interp
diff --git a/fpga/usrp2/sdr_lib/hb/hbd_tb/HBD b/fpga/usrp2/sdr_lib/hb/hbd_tb/HBD
new file mode 100644
index 000000000..574fbba91
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/hbd_tb/HBD
@@ -0,0 +1,80 @@
+*-6.432683 5736 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+@28
+test_hbd.clock
+test_hbd.reset
+@420
+test_hbd.halfband_decim.middle_data[15:0]
+@22
+test_hbd.halfband_decim.sum_even[33:0]
+test_hbd.halfband_decim.base_addr[3:0]
+@420
+test_hbd.i_in[15:0]
+@24
+test_hbd.halfband_decim.phase[3:0]
+test_hbd.halfband_decim.ram16_even.rd_addr1[3:0]
+test_hbd.halfband_decim.ram16_even.rd_addr2[3:0]
+test_hbd.halfband_decim.ram16_even.wr_addr[3:0]
+test_hbd.halfband_decim.ram16_even.wr_data[15:0]
+@28
+test_hbd.halfband_decim.ram16_even.write
+@420
+test_hbd.halfband_decim.sum[15:0]
+test_hbd.halfband_decim.product[30:0]
+test_hbd.halfband_decim.dout[33:0]
+test_hbd.halfband_decim.sum_even[33:0]
+@22
+test_hbd.halfband_decim.acc.addend[30:0]
+@28
+test_hbd.halfband_decim.acc.reset
+@420
+test_hbd.halfband_decim.acc.sum[33:0]
+test_hbd.halfband_decim.mult.x[15:0]
+test_hbd.halfband_decim.mult.y[15:0]
+@28
+test_hbd.halfband_decim.acc.clear
+test_hbd.strobe_in
+test_hbd.strobe_out
+test_hbd.halfband_decim.acc_en
+@420
+test_hbd.i_out[15:0]
+@28
+test_hbd.halfband_decim.mult_en
+test_hbd.halfband_decim.latch_result
+@420
+test_hbd.halfband_decim.sum[15:0]
+test_hbd.halfband_decim.sum_even[33:0]
+test_hbd.halfband_decim.dout[33:0]
+test_hbd.halfband_decim.data_out[15:0]
+@22
+test_hbd.halfband_decim.data_out[15:0]
+@28
+test_hbd.halfband_decim.dout[33:0]
+@29
+test_hbd.halfband_decim.acc_en
+@22
+test_hbd.halfband_decim.base_addr[3:0]
+@28
+test_hbd.halfband_decim.clear
+test_hbd.halfband_decim.latch_result
+test_hbd.halfband_decim.mult_en
+test_hbd.halfband_decim.mult_en_pre
+@22
+test_hbd.halfband_decim.phase[3:0]
+@28
+test_hbd.halfband_decim.start
+test_hbd.halfband_decim.start_d1
+test_hbd.halfband_decim.start_d2
+test_hbd.halfband_decim.start_d3
+test_hbd.halfband_decim.start_d4
+test_hbd.halfband_decim.start_d5
+test_hbd.halfband_decim.start_d6
+test_hbd.halfband_decim.start_d7
+test_hbd.halfband_decim.start_d8
+test_hbd.halfband_decim.start_d9
+test_hbd.halfband_decim.start_dA
+test_hbd.halfband_decim.start_dB
+test_hbd.halfband_decim.start_dC
+test_hbd.halfband_decim.start_dD
+test_hbd.halfband_decim.store_odd
+test_hbd.halfband_decim.strobe_in
+test_hbd.halfband_decim.strobe_out
diff --git a/fpga/usrp2/sdr_lib/hb/hbd_tb/really_golden b/fpga/usrp2/sdr_lib/hb/hbd_tb/really_golden
new file mode 100644
index 000000000..2d24a9e14
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/hbd_tb/really_golden
@@ -0,0 +1,142 @@
+VCD info: dumpfile test_hbd.vcd opened for output.
+ x
+ x
+ x
+ x
+ x
+ x
+ x
+ x
+ x
+ x
+ x
+ x
+ x
+ x
+ x
+ x
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 8192
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+- 4
+ 18
+- 63
+ 167
+- 367
+ 737
+- 1539
+ 5146
+ 5146
+- 1539
+ 737
+- 367
+ 167
+- 63
+ 18
+- 4
+ 0
+ 0
+ 0
+ 0
+ 0
+- 4
+ 14
+- 49
+ 118
+- 249
+ 488
+ 7141
+12287
+17433
+15894
+16631
+16264
+16432
+16368
+16387
+16383
+16383
+16383
+16383
+16383
+16387
+16368
+16432
+16264
+16631
+15894
+ 9241
+ 4095
+- 1051
+ 488
+- 249
+ 118
+- 49
+ 14
+- 4
+ 0
+ 0
+ 0
+ 0
+ 0
+- 4
+ 14
+- 49
+ 118
+- 249
+ 488
+- 1051
+12287
+17433
+15894
+16631
+16264
+16432
+16368
+16387
+16383
+16383
+16383
+16383
+16383
+16387
+16368
+16432
+16264
+16631
+15894
+17433
+ 4095
+- 1051
+ 488
+- 249
+ 118
+- 49
+ 14
+- 4
+ 0
+ 0
+ 0
+ 0
diff --git a/fpga/usrp2/sdr_lib/hb/hbd_tb/regression b/fpga/usrp2/sdr_lib/hb/hbd_tb/regression
new file mode 100644
index 000000000..fc279c2f2
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/hbd_tb/regression
@@ -0,0 +1,95 @@
+echo "Baseline 1000"
+iverilog -y .. -o test_hbd -DRATE=1000 test_hbd.v ; ./test_hbd >golden
+diff golden really_golden
+
+echo
+echo "Test 100"
+iverilog -y .. -o test_hbd -DRATE=100 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 50"
+iverilog -y .. -o test_hbd -DRATE=50 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 40"
+iverilog -y .. -o test_hbd -DRATE=40 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 30"
+iverilog -y .. -o test_hbd -DRATE=30 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 25"
+iverilog -y .. -o test_hbd -DRATE=25 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 20"
+iverilog -y .. -o test_hbd -DRATE=20 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 19"
+iverilog -y .. -o test_hbd -DRATE=19 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 18"
+iverilog -y .. -o test_hbd -DRATE=18 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 17"
+iverilog -y .. -o test_hbd -DRATE=17 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 16"
+iverilog -y .. -o test_hbd -DRATE=16 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 15"
+iverilog -y .. -o test_hbd -DRATE=15 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 14"
+iverilog -y .. -o test_hbd -DRATE=14 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 13"
+iverilog -y .. -o test_hbd -DRATE=13 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 12"
+iverilog -y .. -o test_hbd -DRATE=12 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 11"
+iverilog -y .. -o test_hbd -DRATE=11 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 10"
+iverilog -y .. -o test_hbd -DRATE=10 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 9"
+iverilog -y .. -o test_hbd -DRATE=9 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 8"
+iverilog -y .. -o test_hbd -DRATE=8 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 7"
+iverilog -y .. -o test_hbd -DRATE=7 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 6"
+iverilog -y .. -o test_hbd -DRATE=6 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 5"
+iverilog -y .. -o test_hbd -DRATE=5 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 4"
+iverilog -y .. -o test_hbd -DRATE=4 test_hbd.v ; ./test_hbd >output ; diff output golden
+
+echo
+echo "Test 3"
+iverilog -y .. -o test_hbd -DRATE=3 test_hbd.v ; ./test_hbd >output ; diff output golden
diff --git a/fpga/usrp2/sdr_lib/hb/hbd_tb/run_hbd b/fpga/usrp2/sdr_lib/hb/hbd_tb/run_hbd
new file mode 100755
index 000000000..b8aec7574
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/hbd_tb/run_hbd
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+iverilog -y .. -o test_hbd test_hbd.v
+./test_hbd
diff --git a/fpga/usrp2/sdr_lib/hb/hbd_tb/test_hbd.v b/fpga/usrp2/sdr_lib/hb/hbd_tb/test_hbd.v
new file mode 100644
index 000000000..01ab5e7e0
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/hbd_tb/test_hbd.v
@@ -0,0 +1,75 @@
+
+
+module test_hbd();
+
+ reg clock;
+ initial clock = 1'b0;
+ always #5 clock <= ~clock;
+
+ reg reset;
+ initial reset = 1'b1;
+ initial #1000 reset = 1'b0;
+
+ initial $dumpfile("test_hbd.vcd");
+ initial $dumpvars(0,test_hbd);
+
+ reg [15:0] i_in, q_in;
+ wire [15:0] i_out, q_out;
+
+ reg strobe_in;
+ wire strobe_out;
+ reg coeff_write;
+ reg [15:0] coeff_data;
+ reg [4:0] coeff_addr;
+
+ halfband_decim halfband_decim
+ ( .clock(clock),.reset(reset),.enable(),.strobe_in(strobe_in),.strobe_out(strobe_out),
+ .data_in(i_in),.data_out(i_out) );
+
+ always @(posedge strobe_out)
+ if(i_out[15])
+ $display("-%d",65536-i_out);
+ else
+ $display("%d",i_out);
+
+ initial
+ begin
+ strobe_in = 1'b0;
+ @(negedge reset);
+ @(posedge clock);
+ while(1)
+ begin
+ strobe_in <= #1 1'b1;
+ @(posedge clock);
+ strobe_in <= #1 1'b0;
+ repeat (`RATE)
+ @(posedge clock);
+ end
+ end
+
+ initial #10000000 $finish; // Just in case...
+
+ initial
+ begin
+ i_in <= #1 16'd0;
+ repeat (40) @(posedge strobe_in);
+ i_in <= #1 16'd16384;
+ @(posedge strobe_in);
+ i_in <= #1 16'd0;
+ repeat (40) @(posedge strobe_in);
+ i_in <= #1 16'd16384;
+ @(posedge strobe_in);
+ i_in <= #1 16'd0;
+ repeat (40) @(posedge strobe_in);
+ i_in <= #1 16'd16384;
+ repeat (40) @(posedge strobe_in);
+ i_in <= #1 16'd0;
+ repeat (41) @(posedge strobe_in);
+ i_in <= #1 16'd16384;
+ repeat (40) @(posedge strobe_in);
+ i_in <= #1 16'd0;
+ repeat (40) @(posedge strobe_in);
+ repeat (7) @(posedge clock);
+ $finish;
+ end // initial begin
+endmodule // test_hb
diff --git a/fpga/usrp2/sdr_lib/hb/mac.v b/fpga/usrp2/sdr_lib/hb/mac.v
new file mode 100644
index 000000000..5a270bc73
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/mac.v
@@ -0,0 +1,58 @@
+
+
+module mac (input clock, input reset, input enable, input clear,
+ input signed [15:0] x, input signed [15:0] y,
+ input [7:0] shift, output [15:0] z );
+
+ reg signed [30:0] product;
+ reg signed [39:0] z_int;
+ reg signed [15:0] z_shift;
+
+ reg enable_d1;
+ always @(posedge clock)
+ enable_d1 <= #1 enable;
+
+ always @(posedge clock)
+ if(reset | clear)
+ z_int <= #1 40'd0;
+ else if(enable_d1)
+ z_int <= #1 z_int + {{9{product[30]}},product};
+
+ always @(posedge clock)
+ product <= #1 x*y;
+
+ always @* // FIXME full case? parallel case?
+ case(shift)
+ //8'd0 : z_shift <= z_int[39:24];
+ //8'd1 : z_shift <= z_int[38:23];
+ //8'd2 : z_shift <= z_int[37:22];
+ //8'd3 : z_shift <= z_int[36:21];
+ //8'd4 : z_shift <= z_int[35:20];
+ //8'd5 : z_shift <= z_int[34:19];
+ 8'd6 : z_shift <= z_int[33:18];
+ 8'd7 : z_shift <= z_int[32:17];
+ 8'd8 : z_shift <= z_int[31:16];
+ 8'd9 : z_shift <= z_int[30:15];
+ 8'd10 : z_shift <= z_int[29:14];
+ 8'd11 : z_shift <= z_int[28:13];
+ //8'd12 : z_shift <= z_int[27:12];
+ //8'd13 : z_shift <= z_int[26:11];
+ //8'd14 : z_shift <= z_int[25:10];
+ //8'd15 : z_shift <= z_int[24:9];
+ //8'd16 : z_shift <= z_int[23:8];
+ //8'd17 : z_shift <= z_int[22:7];
+ //8'd18 : z_shift <= z_int[21:6];
+ //8'd19 : z_shift <= z_int[20:5];
+ //8'd20 : z_shift <= z_int[19:4];
+ //8'd21 : z_shift <= z_int[18:3];
+ //8'd22 : z_shift <= z_int[17:2];
+ //8'd23 : z_shift <= z_int[16:1];
+ //8'd24 : z_shift <= z_int[15:0];
+ default : z_shift <= z_int[15:0];
+ endcase // case(shift)
+
+ // FIXME do we need to saturate?
+ //assign z = z_shift;
+ assign z = z_int[15:0];
+
+endmodule // mac
diff --git a/fpga/usrp2/sdr_lib/hb/mult.v b/fpga/usrp2/sdr_lib/hb/mult.v
new file mode 100644
index 000000000..a8d4cb1b7
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/mult.v
@@ -0,0 +1,16 @@
+
+
+module mult (input clock, input signed [15:0] x, input signed [15:0] y, output reg signed [30:0] product,
+ input enable_in, output reg enable_out );
+
+ always @(posedge clock)
+ if(enable_in)
+ product <= #1 x*y;
+ else
+ product <= #1 31'd0;
+
+ always @(posedge clock)
+ enable_out <= #1 enable_in;
+
+endmodule // mult
+
diff --git a/fpga/usrp2/sdr_lib/hb/ram16_2port.v b/fpga/usrp2/sdr_lib/hb/ram16_2port.v
new file mode 100644
index 000000000..e1761a926
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/ram16_2port.v
@@ -0,0 +1,22 @@
+
+
+module ram16_2port (input clock, input write,
+ input [3:0] wr_addr, input [15:0] wr_data,
+ input [3:0] rd_addr1, output reg [15:0] rd_data1,
+ input [3:0] rd_addr2, output reg [15:0] rd_data2);
+
+ reg [15:0] ram_array [0:31];
+
+ always @(posedge clock)
+ rd_data1 <= #1 ram_array[rd_addr1];
+
+ always @(posedge clock)
+ rd_data2 <= #1 ram_array[rd_addr2];
+
+ always @(posedge clock)
+ if(write)
+ ram_array[wr_addr] <= #1 wr_data;
+
+endmodule // ram16_2port
+
+
diff --git a/fpga/usrp2/sdr_lib/hb/ram16_2sum.v b/fpga/usrp2/sdr_lib/hb/ram16_2sum.v
new file mode 100644
index 000000000..559b06fd5
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/ram16_2sum.v
@@ -0,0 +1,27 @@
+
+
+module ram16_2sum (input clock, input write,
+ input [3:0] wr_addr, input [15:0] wr_data,
+ input [3:0] rd_addr1, input [3:0] rd_addr2,
+ output reg [15:0] sum);
+
+ reg signed [15:0] ram_array [0:15];
+ reg signed [15:0] a,b;
+ wire signed [16:0] sum_int;
+
+ always @(posedge clock)
+ if(write)
+ ram_array[wr_addr] <= #1 wr_data;
+
+ always @(posedge clock)
+ begin
+ a <= #1 ram_array[rd_addr1];
+ b <= #1 ram_array[rd_addr2];
+ end
+
+ assign sum_int = {a[15],a} + {b[15],b};
+
+ always @(posedge clock)
+ sum <= #1 sum_int[16:1] + (sum_int[16]&sum_int[0]);
+
+endmodule // ram16_2sum
diff --git a/fpga/usrp2/sdr_lib/hb/ram32_2sum.v b/fpga/usrp2/sdr_lib/hb/ram32_2sum.v
new file mode 100644
index 000000000..d1f55b7d0
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb/ram32_2sum.v
@@ -0,0 +1,22 @@
+
+
+module ram32_2sum (input clock, input write,
+ input [4:0] wr_addr, input [15:0] wr_data,
+ input [4:0] rd_addr1, input [4:0] rd_addr2,
+ output reg [15:0] sum);
+
+ reg [15:0] ram_array [0:31];
+ wire [16:0] sum_int;
+
+ always @(posedge clock)
+ if(write)
+ ram_array[wr_addr] <= #1 wr_data;
+
+ assign sum_int = ram_array[rd_addr1] + ram_array[rd_addr2];
+
+ always @(posedge clock)
+ sum <= #1 sum_int[16:1] + (sum_int[16]&sum_int[0]);
+
+
+endmodule // ram32_2sum
+
diff --git a/fpga/usrp2/sdr_lib/hb_dec.v b/fpga/usrp2/sdr_lib/hb_dec.v
new file mode 100644
index 000000000..8fb5ba222
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb_dec.v
@@ -0,0 +1,171 @@
+// Final halfband decimator
+// Implements impulse responses of the form [A 0 B 0 C .. 0 H 0.5 H 0 .. C 0 B 0 A]
+// Strobe in cannot come faster than every 2nd clock cycle
+// These taps designed by halfgen4 from ldoolittle
+// myfilt = round(2^18 * halfgen4(.7/4,8))
+
+module hb_dec
+ #(parameter IWIDTH=18, OWIDTH=18, CWIDTH=18, ACCWIDTH=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,
+ output reg stb_out,
+ output reg [OWIDTH-1:0] data_out);
+
+ // Control
+ reg [3:0] addr_odd_a, addr_odd_b, addr_odd_c, addr_odd_d;
+ wire write_odd, write_even, do_mult;
+ reg odd;
+ reg [2:0] phase, phase_d1;
+ reg stb_out_int;
+ wire clear, do_acc;
+ assign do_mult = 1;
+
+ always @(posedge clk)
+ if(rst | ~run)
+ odd <= 0;
+ else if(stb_in)
+ odd <= ~odd;
+
+ assign write_odd = stb_in & odd;
+ assign write_even = stb_in & ~odd;
+
+ always @(posedge clk)
+ if(rst | ~run)
+ phase <= 0;
+ else if(stb_in & odd)
+ phase <= 1;
+ else if(phase == 4)
+ phase <= 0;
+ else if(phase != 0)
+ phase <= phase + 1;
+
+ always @(posedge clk)
+ phase_d1 <= phase;
+
+ reg [15:0] stb_out_pre;
+ always @(posedge clk)
+ if(rst)
+ stb_out_pre <= 0;
+ else
+ stb_out_pre <= {stb_out_pre[14:0],(stb_in & odd)};
+
+ always @*
+ case(phase)
+ 1 : begin addr_odd_a = 0; addr_odd_b = 15; end
+ 2 : begin addr_odd_a = 1; addr_odd_b = 14; end
+ 3 : begin addr_odd_a = 2; addr_odd_b = 13; end
+ 4 : begin addr_odd_a = 3; addr_odd_b = 12; end
+ default : begin addr_odd_a = 0; addr_odd_b = 15; end
+ endcase // case(phase)
+
+ always @*
+ case(phase)
+ 1 : begin addr_odd_c = 4; addr_odd_d = 11; end
+ 2 : begin addr_odd_c = 5; addr_odd_d = 10; end
+ 3 : begin addr_odd_c = 6; addr_odd_d = 9; end
+ 4 : begin addr_odd_c = 7; addr_odd_d = 8; end
+ default : begin addr_odd_c = 4; addr_odd_d = 11; end
+ endcase // case(phase)
+
+ assign do_acc = |stb_out_pre[6:3];
+ 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;
+
+ always @* // Outer coeffs
+ case(phase_d1)
+ 1 : coeff1 = -107;
+ 2 : coeff1 = 445;
+ 3 : coeff1 = -1271;
+ 4 : coeff1 = 2959;
+ default : coeff1 = -107;
+ endcase // case(phase)
+
+ always @* // Inner coeffs
+ case(phase_d1)
+ 1 : coeff2 = -6107;
+ 2 : coeff2 = 11953;
+ 3 : coeff2 = -24706;
+ 4 : coeff2 = 82359;
+ 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;
+ reg [3:0] addr_even;
+
+ always @(posedge clk)
+ case(cpi)
+ // 1 is an error
+ 2 : addr_even <= 9; // Maximum speed (overall decim by 4)
+ 3, 4, 5, 6, 7 : addr_even <= 8;
+ 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;
+
+ 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;
+
+ acc #(.IWIDTH(MWIDTH),.OWIDTH(ACCWIDTH))
+ acc (.clk(clk),.clear(clear),.acc(do_acc),.in(sum_of_prod),.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;
+
+ 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;
+
+ always @(posedge clk)
+ if(rst)
+ stb_out <= 0;
+ else if(bypass)
+ stb_out <= stb_in;
+ else
+ stb_out <= stb_out_pre[9];
+
+endmodule // hb_dec
diff --git a/fpga/usrp2/sdr_lib/hb_dec_tb.v b/fpga/usrp2/sdr_lib/hb_dec_tb.v
new file mode 100644
index 000000000..3e5faa80a
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb_dec_tb.v
@@ -0,0 +1,140 @@
+module hb_dec_tb( ) ;
+
+ // Parameters for instantiation
+ parameter clocks = 9'd2 ; // Number of clocks per input
+ parameter decim = 1 ; // Sets the filter to decimate
+ parameter rate = 2 ; // Sets the decimation rate
+
+ reg clock ;
+ reg reset ;
+ reg enable ;
+ reg strobe_in ;
+ reg signed [17:0] data_in ;
+ wire strobe_out ;
+ wire signed [17:0] data_out ;
+
+ initial
+ begin
+ $dumpfile("hb_dec_tb.vcd");
+ $dumpvars(0,hb_dec_tb);
+ end
+
+ // Setup the clock
+ initial clock = 1'b0 ;
+ always #5 clock <= ~clock ;
+
+ // Come out of reset after a while
+ initial reset = 1'b1 ;
+ initial #1000 reset = 1'b0 ;
+
+ // Enable the entire system
+ initial enable = 1'b1 ;
+
+ // Instantiate UUT
+ /*
+ halfband_ideal
+ #(
+ .decim ( decim ),
+ .rate ( rate )
+ ) uut(
+ .clock ( clock ),
+ .reset ( reset ),
+ .enable ( enable ),
+ .strobe_in ( strobe_in ),
+ .data_in ( data_in ),
+ .strobe_out ( strobe_out ),
+ .data_out ( data_out )
+ ) ;
+ */
+
+
+ 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),
+ .stb_out(strobe_out),.data_out(data_out) );
+
+ integer i, ri, ro, infile, outfile ;
+
+ always @(posedge clock)
+ begin
+ if(strobe_out)
+ $display(data_out);
+ end
+
+ // Setup file IO
+ initial begin
+ infile = $fopen("input.dat","r") ;
+ outfile = $fopen("output.dat","r") ;
+ $timeformat(-9, 2, " ns", 10) ;
+ end
+
+ reg endofsim ;
+ reg signed [17:0] compare ;
+ integer noe ;
+ initial noe = 0 ;
+
+ initial begin
+ // Initialize inputs
+ strobe_in <= 1'd0 ;
+ data_in <= 18'd0 ;
+
+ // Wait for reset to go away
+ @(negedge reset) #0 ;
+
+ // While we're still simulating ...
+ while( !endofsim ) begin
+
+ // Write the input from the file or 0 if EOF...
+ @( posedge clock ) begin
+ //#1 ;
+ strobe_in <= 1'b1 ;
+ if( !$feof(infile) )
+ ri = $fscanf( infile, "%d", data_in ) ;
+ else
+ data_in <= 18'd0 ;
+ end
+
+ // Clocked in - set the strobe to 0 if the number of
+ // clocks per sample is greater than 1
+ if( clocks > 1 ) begin
+ @(posedge clock) begin
+ strobe_in <= 1'b0 ;
+ end
+
+ // Wait for the specified number of cycles
+ for( i = 0 ; i < (clocks-2) ; i = i + 1 ) begin
+ @(posedge clock) #1 ;
+ end
+ end
+ end
+
+ // Print out the number of errors that occured
+ if( noe )
+ $display( "FAILED: %d errors during simulation", noe ) ;
+ else
+ $display( "PASSED: Simulation successful" ) ;
+
+ $finish ;
+ end
+
+ // Output comparison of simulated values versus known good values
+ always @ (posedge clock) begin
+ if( reset )
+ endofsim <= 1'b0 ;
+ else begin
+ if( !$feof(outfile) ) begin
+ if( strobe_out ) begin
+ ro = $fscanf( outfile, "%d\n", compare ) ;
+ if( compare != data_out ) begin
+ //$display( "%t: %d != %d", $realtime, data_out, compare ) ;
+ noe = noe + 1 ;
+ end
+ end
+ end else begin
+ // Signal end of simulation when no more outputs
+ endofsim <= 1'b1 ;
+ end
+ end
+ end
+
+endmodule // hb_dec_tb
+
diff --git a/fpga/usrp2/sdr_lib/hb_interp.v b/fpga/usrp2/sdr_lib/hb_interp.v
new file mode 100644
index 000000000..d16807e15
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb_interp.v
@@ -0,0 +1,157 @@
+// First halfband iterpolator
+// Implements impulse responses of the form [A 0 B 0 C .. 0 H 0.5 H 0 .. C 0 B 0 A]
+// Strobe in cannot come faster than every 4th clock cycle,
+// Strobe out cannot come faster than every 2nd clock cycle
+
+// These taps designed by halfgen4 from ldoolittle
+// myfilt = round(2^18 * halfgen4(.7/4,8))
+
+module hb_interp
+ #(parameter IWIDTH=18, OWIDTH=18, ACCWIDTH=24)
+ (input clk,
+ input rst,
+ input bypass,
+ input [7:0] cpo, // Clocks per output, must be at least 2
+ input stb_in,
+ input [IWIDTH-1:0] data_in,
+ input stb_out,
+ output reg [OWIDTH-1:0] data_out);
+
+ localparam MWIDTH = ACCWIDTH-2;
+ localparam CWIDTH = 18;
+
+ reg [CWIDTH-1:0] coeff1, coeff2;
+ reg [3:0] addr_a, addr_b, addr_c, addr_d, addr_e;
+ wire [IWIDTH-1:0] data_a, data_b, data_c, data_d, data_e, sum1, sum2;
+ wire [35:0] prod1, prod2;
+
+ reg [2:0] phase, phase_d1, phase_d2, phase_d3, phase_d4, phase_d5;
+
+ always @(posedge clk)
+ if(rst)
+ phase <= 0;
+ else
+ if(stb_in)
+ phase <= 1;
+ else if(phase==4)
+ phase <= 0;
+ else if(phase!=0)
+ phase <= phase + 1;
+ always @(posedge clk) phase_d1 <= phase;
+ always @(posedge clk) phase_d2 <= phase_d1;
+ always @(posedge clk) phase_d3 <= phase_d2;
+ always @(posedge clk) phase_d4 <= phase_d3;
+ always @(posedge clk) phase_d5 <= phase_d4;
+
+ srl #(.WIDTH(IWIDTH)) srl_a
+ (.clk(clk),.write(stb_in),.in(data_in),.addr(addr_a),.out(data_a));
+ srl #(.WIDTH(IWIDTH)) srl_b
+ (.clk(clk),.write(stb_in),.in(data_in),.addr(addr_b),.out(data_b));
+ srl #(.WIDTH(IWIDTH)) srl_c
+ (.clk(clk),.write(stb_in),.in(data_in),.addr(addr_c),.out(data_c));
+ srl #(.WIDTH(IWIDTH)) srl_d
+ (.clk(clk),.write(stb_in),.in(data_in),.addr(addr_d),.out(data_d));
+ srl #(.WIDTH(IWIDTH)) srl_e
+ (.clk(clk),.write(stb_in),.in(data_in),.addr(addr_e),.out(data_e));
+
+ always @*
+ case(phase)
+ 1 : begin addr_a = 0; addr_b = 15; end
+ 2 : begin addr_a = 1; addr_b = 14; end
+ 3 : begin addr_a = 2; addr_b = 13; end
+ 4 : begin addr_a = 3; addr_b = 12; end
+ default : begin addr_a = 0; addr_b = 15; end
+ endcase // case(phase)
+
+ always @*
+ case(phase)
+ 1 : begin addr_c = 4; addr_d = 11; end
+ 2 : begin addr_c = 5; addr_d = 10; end
+ 3 : begin addr_c = 6; addr_d = 9; end
+ 4 : begin addr_c = 7; addr_d = 8; end
+ default : begin addr_c = 4; addr_d = 11; end
+ endcase // case(phase)
+
+ always @*
+ case(cpo)
+ 2 : addr_e <= 9;
+ 3,4,5,6,7,8 : addr_e <= 8;
+ default : addr_e <= 7; // This case works for 256, which = 0 due to overflow outside this block
+ endcase // case(cpo)
+
+ always @* // Outer coeffs
+ case(phase_d1)
+ 1 : coeff1 = -107;
+ 2 : coeff1 = 445;
+ 3 : coeff1 = -1271;
+ 4 : coeff1 = 2959;
+ default : coeff1 = -107;
+ endcase // case(phase)
+
+ always @* // Inner coeffs
+ case(phase_d1)
+ 1 : coeff2 = -6107;
+ 2 : coeff2 = 11953;
+ 3 : coeff2 = -24706;
+ 4 : coeff2 = 82359;
+ default : coeff2 = -6107;
+ endcase // case(phase)
+
+ add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add1 (.clk(clk),.in1(data_a),.in2(data_b),.sum(sum1));
+ add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add2 (.clk(clk),.in1(data_c),.in2(data_d),.sum(sum2));
+ // sum1, sum2 available on phase_d1
+
+ wire do_mult = 1;
+ 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) );
+ // prod1, prod2 available on phase_d2
+
+ wire [MWIDTH-1:0] sum_of_prod;
+
+ add2_and_round_reg #(.WIDTH(MWIDTH))
+ add3 (.clk(clk),.in1(prod1[35:36-MWIDTH]),.in2(prod2[35:36-MWIDTH]),.sum(sum_of_prod));
+ // sum_of_prod available on phase_d3
+
+ wire [ACCWIDTH-1:0] acc_out;
+ wire [OWIDTH-1:0] acc_round;
+
+ wire clear = (phase_d3 == 1);
+ wire do_acc = (phase_d3 != 0);
+
+ acc #(.IWIDTH(MWIDTH),.OWIDTH(ACCWIDTH))
+ acc (.clk(clk),.clear(clear),.acc(do_acc),.in(sum_of_prod),.out(acc_out));
+ // acc_out available on phase_d4
+
+ wire [ACCWIDTH-6:0] clipped_acc;
+ clip #(.bits_in(ACCWIDTH),.bits_out(ACCWIDTH-5)) final_clip(.in(acc_out),.out(clipped_acc));
+
+ reg [ACCWIDTH-6:0] clipped_reg;
+ always @(posedge clk)
+ if(phase_d4 == 4)
+ clipped_reg <= clipped_acc;
+ // clipped_reg available on phase_d5
+
+ wire [OWIDTH-1:0] data_out_round;
+ round #(.bits_in(ACCWIDTH-5),.bits_out(OWIDTH)) final_round (.in(clipped_reg),.out(data_out_round));
+
+ reg odd;
+ always @(posedge clk)
+ if(rst)
+ odd <= 0;
+ else if(stb_in)
+ odd <= 0;
+ else if(stb_out)
+ odd <= 1;
+
+ always @(posedge clk)
+ if(bypass)
+ data_out <= data_in;
+ else if(stb_out)
+ if(odd)
+ data_out <= data_e;
+ else
+ data_out <= data_out_round;
+
+ // data_out available on phase_d6
+
+endmodule // hb_interp
diff --git a/fpga/usrp2/sdr_lib/hb_interp_tb.v b/fpga/usrp2/sdr_lib/hb_interp_tb.v
new file mode 100644
index 000000000..52f137f28
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb_interp_tb.v
@@ -0,0 +1,132 @@
+module hb_interp_tb( ) ;
+
+ // Parameters for instantiation
+ parameter clocks = 8'd2 ; // Number of clocks per output
+ parameter decim = 1 ; // Sets the filter to decimate
+ parameter rate = 2 ; // Sets the decimation rate
+
+ reg clock ;
+ reg reset ;
+ reg enable ;
+ wire strobe_in ;
+ reg signed [17:0] data_in ;
+ wire strobe_out ;
+ wire signed [17:0] data_out ;
+
+ initial
+ begin
+ $dumpfile("hb_interp_tb.vcd");
+ $dumpvars(0,hb_interp_tb);
+ end
+
+ // Setup the clock
+ initial clock = 1'b0 ;
+ always #5 clock <= ~clock ;
+
+ // Come out of reset after a while
+ initial reset = 1'b1 ;
+ initial #1000 reset = 1'b0 ;
+
+ always @(posedge clock)
+ enable <= ~reset;
+
+ // Instantiate UUT
+ /*
+ halfband_ideal
+ #(
+ .decim ( decim ),
+ .rate ( rate )
+ ) uut(
+ .clock ( clock ),
+ .reset ( reset ),
+ .enable ( enable ),
+ .strobe_in ( strobe_in ),
+ .data_in ( data_in ),
+ .strobe_out ( strobe_out ),
+ .data_out ( data_out )
+ ) ;
+ */
+
+ cic_strober #(.WIDTH(8))
+ out_strober(.clock(clock),.reset(reset),.enable(enable),.rate(clocks),
+ .strobe_fast(1),.strobe_slow(strobe_out) );
+
+ cic_strober #(.WIDTH(8))
+ in_strober(.clock(clock),.reset(reset),.enable(enable),.rate(2),
+ .strobe_fast(strobe_out),.strobe_slow(strobe_in) );
+
+ hb_interp #() uut
+ (.clk(clock),.rst(reset),.bypass(0),.cpo(clocks),.stb_in(strobe_in),.data_in(data_in),
+ .stb_out(strobe_out),/* .output_rate(clocks), */ .data_out(data_out) );
+
+ integer i, ri, ro, infile, outfile ;
+
+ always @(posedge clock)
+ begin
+ if(strobe_out)
+ $display(data_out);
+ end
+
+ // Setup file IO
+ initial begin
+ infile = $fopen("input.dat","r") ;
+ outfile = $fopen("output.dat","r") ;
+ $timeformat(-9, 2, " ns", 10) ;
+ end
+
+ reg endofsim ;
+ reg signed [17:0] compare ;
+ integer noe ;
+ initial noe = 0 ;
+
+ initial begin
+ // Initialize inputs
+ data_in <= 18'd0 ;
+
+ // Wait for reset to go away
+ @(negedge reset) #0 ;
+
+ // While we're still simulating ...
+ while( !endofsim ) begin
+
+ // Write the input from the file or 0 if EOF...
+ @( negedge clock ) begin
+ if(strobe_in)
+ if( !$feof(infile) )
+ ri <= #1 $fscanf( infile, "%d", data_in ) ;
+ else
+ data_in <= 18'd0 ;
+ end
+ end
+
+ // Print out the number of errors that occured
+ if( noe )
+ $display( "FAILED: %d errors during simulation", noe ) ;
+ else
+ $display( "PASSED: Simulation successful" ) ;
+
+ $finish ;
+ end
+
+ // Output comparison of simulated values versus known good values
+ always @ (posedge clock) begin
+ if( reset )
+ endofsim <= 1'b0 ;
+ else begin
+ if( !$feof(outfile) ) begin
+ if( strobe_out ) begin
+ ro = $fscanf( outfile, "%d\n", compare ) ;
+ if( compare != data_out ) begin
+ //$display( "%t: %d != %d", $realtime, data_out, compare ) ;
+ noe = noe + 1 ;
+ end
+ end
+ end else begin
+ // Signal end of simulation when no more outputs
+ if($feof(infile))
+ endofsim <= 1'b1 ;
+ end
+ end
+ end
+
+endmodule // small_hb_int_tb
diff --git a/fpga/usrp2/sdr_lib/hb_tb.v b/fpga/usrp2/sdr_lib/hb_tb.v
new file mode 100644
index 000000000..7e960fd13
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/hb_tb.v
@@ -0,0 +1,155 @@
+
+module hb_tb();
+
+ localparam SWIDTH = 17;
+ localparam CWIDTH = 18;
+ localparam TWIDTH = 20;
+ localparam ACC_WIDTH = 40;
+
+ reg clk = 0, rst = 1;
+ wire strobe_in, strobe_out;
+ reg [SWIDTH-1:0] sample_in;
+ wire signed [SWIDTH:0] sample_out;
+
+ reg set_stb;
+ reg [7:0] set_addr;
+ reg [31:0] set_data;
+
+ localparam DECIM = 3;
+
+ initial $dumpfile("hb_tb.vcd");
+ initial $dumpvars(0,hb_tb);
+
+ always #5 clk <= ~clk;
+ initial
+ begin
+ @(posedge clk);
+ @(negedge clk);
+ rst <= 0;
+ end
+
+ reg [7:0] stb_counter;
+ always @(posedge clk)
+ if(rst)
+ stb_counter <= 0;
+ else
+ if(stb_counter == 0)
+ stb_counter <= DECIM;
+ else
+ stb_counter <= stb_counter - 1;
+ assign strobe_in = (stb_counter == 0);
+
+ hb_decim #(.SWIDTH(SWIDTH),.CWIDTH(CWIDTH),
+ .TWIDTH(TWIDTH),.ACC_WIDTH(ACC_WIDTH)) hb_decim
+ (.clk(clk), .rst(rst),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .sample_in(sample_in),
+ .strobe_in(strobe_in),
+ .sample_out(sample_out),
+ .strobe_out(strobe_out)
+ );
+
+ initial
+ begin : load_coeffs
+ @(negedge rst);
+ @(posedge clk);
+ set_addr <= 124; // load coeffs
+ set_stb <= 1;
+ set_data <= -18'd49;
+ @(posedge clk);
+ set_data <= 18'd165;
+ @(posedge clk);
+ set_data <= -18'd412;
+ @(posedge clk);
+ set_data <= 18'd873;
+ @(posedge clk);
+ set_data <= -18'd1681;
+ @(posedge clk);
+ set_data <= 18'd3135;
+ @(posedge clk);
+ set_data <= -18'd6282;
+ @(posedge clk);
+ set_data <= 18'd20628;
+ @(posedge clk);
+ set_addr <=125; // load table
+ // { stb_out, accum, load_accum, done, even_addr, odd_addr_a, odd_addr_b, coeff_addr }
+ set_data <= {1'b1,1'b1,1'b0,1'b1,4'd15,4'd15,4'd0,4'd0}; // Phase 8
+ @(posedge clk);
+ set_data <= {1'b0,1'b1,1'b0,1'b0,4'd15,4'd14,4'd1,4'd1}; // Phase 7
+ @(posedge clk);
+ set_data <= {1'b0,1'b1,1'b0,1'b0,4'd15,4'd13,4'd2,4'd2}; // Phase 6
+ @(posedge clk);
+ set_data <= {1'b0,1'b1,1'b0,1'b0,4'd15,4'd12,4'd3,4'd3}; // Phase 5
+ @(posedge clk);
+ set_data <= {1'b0,1'b1,1'b0,1'b0,4'd15,4'd11,4'd4,4'd4}; // Phase 4
+ @(posedge clk);
+ set_data <= {1'b0,1'b1,1'b0,1'b0,4'd15,4'd10,4'd5,4'd5}; // Phase 3
+ @(posedge clk);
+ set_data <= {1'b0,1'b1,1'b0,1'b0,4'd15,4'd9,4'd6,4'd6}; // Phase 2
+ @(posedge clk);
+ set_data <= {1'b0,1'b0,1'b1,1'b0,4'd15,4'd8,4'd7,4'd7}; // Phase 1
+ @(posedge clk);
+ set_data <= {1'b0,1'b0,1'b0,1'b0,4'd15,4'd8,4'd7,4'd7}; // Phase 0
+ @(posedge clk);
+ set_stb <= 0;
+ end // block: load_coeffs
+
+ initial
+ begin
+ sample_in <= 0;
+ repeat(40)
+ @(posedge strobe_in);
+ $display("EVEN");
+ sample_in <= 0;
+ repeat(10)
+ @(posedge strobe_in);
+ sample_in <= 1;
+ @(posedge strobe_in);
+ sample_in <= 0;
+ repeat(40)
+ @(posedge strobe_in);
+ sample_in <= 1;
+ repeat(40)
+ @(posedge strobe_in);
+ sample_in <= 0;
+ repeat(60)
+ @(posedge strobe_in);
+ sample_in <= 1;
+ repeat(2)
+ @(posedge strobe_in);
+ sample_in <= 0;
+ repeat(60)
+ @(posedge strobe_in);
+ $display("ODD");
+ sample_in <= 0;
+ repeat(10)
+ @(posedge strobe_in);
+ sample_in <= 1;
+ @(posedge strobe_in);
+ sample_in <= 0;
+ repeat(40)
+ @(posedge strobe_in);
+ sample_in <= 1;
+ repeat(40)
+ @(posedge strobe_in);
+ sample_in <= 0;
+ repeat(60)
+ @(posedge strobe_in);
+ sample_in <= 1;
+ repeat(2)
+ @(posedge strobe_in);
+ sample_in <= 0;
+ repeat(60)
+ @(posedge strobe_in);
+ $finish;
+ end
+
+ always @(posedge clk)
+ if(strobe_in)
+ $display(sample_in);
+
+ always @(posedge clk)
+ if(strobe_out)
+ $display("\t",sample_out);
+
+endmodule // hb_tb
diff --git a/fpga/usrp2/sdr_lib/input.dat b/fpga/usrp2/sdr_lib/input.dat
new file mode 100644
index 000000000..1e649ac2e
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/input.dat
@@ -0,0 +1,341 @@
+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
+-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
+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
+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
+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
+0
+0
+0
+0
+0
+0
+0
diff --git a/fpga/usrp2/sdr_lib/integrate.v b/fpga/usrp2/sdr_lib/integrate.v
new file mode 100644
index 000000000..db33de979
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/integrate.v
@@ -0,0 +1,38 @@
+module integrate
+ #(parameter INPUTW = 16,
+ parameter ACCUMW = 32,
+ parameter OUTPUTW = 16)
+
+ (input clk_i,
+ input rst_i,
+ input ena_i,
+
+ input dump_i,
+ input [INPUTW-1:0] data_i,
+
+ output reg stb_o,
+ output reg [OUTPUTW-1:0] integ_o
+ );
+
+ wire [ACCUMW-1:0] data_ext = {{ACCUMW-INPUTW{data_i[INPUTW-1]}},data_i};
+ reg [ACCUMW-1:0] accum;
+
+ always @(posedge clk_i)
+ if (rst_i | ~ena_i)
+ begin
+ accum <= 0;
+ integ_o <= 0;
+ end
+ else
+ if (dump_i)
+ begin
+ integ_o <= accum[ACCUMW-1:ACCUMW-OUTPUTW];
+ accum <= data_ext;
+ end
+ else
+ accum <= accum + data_ext;
+
+ always @(posedge clk_i)
+ stb_o <= dump_i;
+
+endmodule // integrate
diff --git a/fpga/usrp2/sdr_lib/med_hb_int.v b/fpga/usrp2/sdr_lib/med_hb_int.v
new file mode 100644
index 000000000..bc8066509
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/med_hb_int.v
@@ -0,0 +1,95 @@
+// Medium halfband decimator (intended to be followed by another stage)
+// Implements impulse responses of the form [A 0 B 0 C 0 D 0.5 D 0 C 0 B 0 A]
+//
+// These taps designed by halfgen_test:
+// 2 * 131072 * halfgen_test(.8/8,4,1)
+// -597, 0, 4283, 0, -17516, 0, 79365, 131072, 79365, 0, -17516, 0, 4283, 0, -597
+
+
+module med_hb_int
+ #(parameter WIDTH=18)
+ (input clk,
+ input rst,
+ input bypass,
+ input stb_in,
+ input [WIDTH-1:0] data_in,
+ input [7:0] output_rate,
+ input stb_out,
+ output reg [WIDTH-1:0] data_out);
+
+ localparam coeff_a = -597;
+ localparam coeff_b = 4283;
+ localparam coeff_c = -17516;
+ localparam coeff_d = 79365;
+
+ reg phase;
+ reg [WIDTH-1:0] d1, d2, d3, d4, d5, d6, d7, d8;
+
+ localparam MWIDTH = 36;
+ wire [MWIDTH-1:0] prod;
+
+ reg [6:0] stbin_d;
+
+ always @(posedge clk)
+ stbin_d <= {stbin_d[5:0],stb_in};
+
+ always @(posedge clk)
+ if(stb_in)
+ begin
+ d1 <= data_in;
+ d2 <= d1;
+ d3 <= d2;
+ d4 <= d3;
+ d5 <= d4;
+ d6 <= d5;
+ d7 <= d6;
+ d8 <= d7;
+ end
+
+ wire [WIDTH-1:0] sum_a, sum_b, sum_c, sum_d;
+ add2_and_round_reg #(.WIDTH(WIDTH)) add_a (.clk(clk),.in1(d1),.in2(d8),.sum(sum_a));
+ add2_and_round_reg #(.WIDTH(WIDTH)) add_b (.clk(clk),.in1(d2),.in2(d7),.sum(sum_b));
+ add2_and_round_reg #(.WIDTH(WIDTH)) add_c (.clk(clk),.in1(d3),.in2(d6),.sum(sum_c));
+ add2_and_round_reg #(.WIDTH(WIDTH)) add_d (.clk(clk),.in1(d4),.in2(d5),.sum(sum_d));
+
+ MULT18X18S mult1(.C(clk), .CE(1), .R(rst), .P(prod1), .A(stbin_d[1] ? coeff_a : coeff_b),
+ .B(stbin_d[1] ? sum_a : sum_b) );
+ MULT18X18S mult2(.C(clk), .CE(1), .R(rst), .P(prod2), .A(stbin_d[1] ? coeff_c : coeff_d),
+ .B(stbin_d[1] ? sum_c : sum_d) );
+
+ wire [MWIDTH:0] accum;
+ acc #(.IWIDTH(MWIDTH),.OWIDTH(MWIDTH+1))
+ acc (.clk(clk),.clear(stbin_d[2]),.acc(|stbin_d[3:2]),.in(prod),.out(accum));
+
+ wire [WIDTH+2:0] accum_rnd;
+ round_reg #(.bits_in(MWIDTH+1),.bits_out(WIDTH+3))
+ final_round (.clk(clk),.in(accum),.out(accum_rnd));
+
+ wire [WIDTH-1:0] clipped;
+ clip_reg #(.bits_in(WIDTH+3),.bits_out(WIDTH))
+ final_clip (.clk(clk),.in(accum_rnd),.out(clipped));
+
+ reg [WIDTH-1:0] saved, saved_d3;
+ always @(posedge clk)
+ if(stbin_d[6])
+ saved <= clipped;
+
+ always @(posedge clk)
+ if(stbin_d[3])
+ saved_d3 <= d3;
+
+ always @(posedge clk)
+ if(bypass)
+ data_out <= data_in;
+ else if(stb_in & stb_out)
+ case(output_rate)
+ 1 : data_out <= d6;
+ 2 : data_out <= d4;
+ 3, 4, 5, 6, 7 : data_out <= d3;
+ default : data_out <= d2;
+ endcase // case(output_rate)
+ else if(stb_out)
+ data_out <= saved;
+
+endmodule // small_hb_int
+
diff --git a/fpga/usrp2/sdr_lib/output.dat b/fpga/usrp2/sdr_lib/output.dat
new file mode 100644
index 000000000..15db3ced4
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/output.dat
@@ -0,0 +1,130 @@
+-1390
+0
+1604
+0
+-1896
+0
+2317
+0
+-2979
+0
+4172
+0
+-6953
+0
+20860
+32768
+20860
+0
+-6953
+0
+4172
+0
+-2979
+0
+2317
+0
+-1896
+0
+1604
+0
+-1390
+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
+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
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+
diff --git a/fpga/usrp2/sdr_lib/round.v b/fpga/usrp2/sdr_lib/round.v
new file mode 100644
index 000000000..c4f9ec9cd
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/round.v
@@ -0,0 +1,33 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2007 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+// Rounding "macro"
+// Keeps the topmost bits, does proper 2s comp round to zero (unbiased truncation)
+
+module round
+ #(parameter bits_in=0,
+ parameter bits_out=0)
+ (input [bits_in-1:0] in,
+ output [bits_out-1:0] out);
+
+ assign out = in[bits_in-1:bits_in-bits_out] + (in[bits_in-1] & |in[bits_in-bits_out-1:0]);
+
+endmodule // round
diff --git a/fpga/usrp2/sdr_lib/round_reg.v b/fpga/usrp2/sdr_lib/round_reg.v
new file mode 100644
index 000000000..aa0972dab
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/round_reg.v
@@ -0,0 +1,39 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2008 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+// Rounding "macro"
+// Keeps the topmost bits, does proper 2s comp rounding (round-to-zero)
+
+module round_reg
+ #(parameter bits_in=0,
+ parameter bits_out=0)
+ (input clk,
+ input [bits_in-1:0] in,
+ output reg [bits_out-1:0] out);
+
+ wire [bits_out-1:0] temp;
+
+ round #(.bits_in(bits_in),.bits_out(bits_out)) round (.in(in),.out(temp));
+
+ always @(posedge clk)
+ out <= temp;
+
+endmodule // round
diff --git a/fpga/usrp2/sdr_lib/rssi.v b/fpga/usrp2/sdr_lib/rssi.v
new file mode 100644
index 000000000..e45e2148c
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/rssi.v
@@ -0,0 +1,30 @@
+
+
+module rssi (input clock, input reset, input enable,
+ input [11:0] adc, output [15:0] rssi, output [15:0] over_count);
+
+ wire over_hi = (adc == 12'h7FF);
+ wire over_lo = (adc == 12'h800);
+ wire over = over_hi | over_lo;
+
+ reg [25:0] over_count_int;
+ always @(posedge clock)
+ if(reset | ~enable)
+ over_count_int <= #1 26'd0;
+ else
+ over_count_int <= #1 over_count_int + (over ? 26'd65535 : 26'd0) - over_count_int[25:10];
+
+ assign over_count = over_count_int[25:10];
+
+ wire [11:0] abs_adc = adc[11] ? ~adc : adc;
+
+ reg [25:0] rssi_int;
+ always @(posedge clock)
+ if(reset | ~enable)
+ rssi_int <= #1 26'd0;
+ else
+ rssi_int <= #1 rssi_int + abs_adc - rssi_int[25:10];
+
+ assign rssi = rssi_int[25:10];
+
+endmodule // rssi
diff --git a/fpga/usrp2/sdr_lib/rx_control.v b/fpga/usrp2/sdr_lib/rx_control.v
new file mode 100644
index 000000000..0adeb0794
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/rx_control.v
@@ -0,0 +1,180 @@
+
+`define DSP_CORE_RX_BASE 160
+
+module rx_control
+ #(parameter FIFOSIZE = 10)
+ (input clk, input rst,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ input [31:0] master_time,
+ output overrun,
+
+ // To FIFO interface of Buffer Pool
+ output [31:0] wr_dat_o,
+ output [3:0] wr_flags_o,
+ input wr_ready_i,
+ output wr_ready_o,
+
+ // From DSP Core
+ input [31:0] sample,
+ output run,
+ input strobe,
+
+ // FIFO Levels
+ output [15:0] fifo_occupied,
+ output fifo_full,
+ output fifo_empty,
+
+ // Debug
+ output [31:0] debug_rx
+ );
+
+ wire [31:0] new_time, new_command;
+ wire sc_pre1, clear_overrun;
+ wire [31:0] rcvtime_pre;
+ reg [31:0] rcvtime;
+ wire [8:0] lines_per_frame;
+ wire [20:0] numlines;
+ wire send_imm_pre, chain_pre;
+ reg send_imm, chain;
+ wire full_ctrl, read_ctrl, empty_ctrl, write_ctrl;
+
+ setting_reg #(.my_addr(`DSP_CORE_RX_BASE+3)) sr_3
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(new_time),.changed(sc_pre1));
+
+ setting_reg #(.my_addr(`DSP_CORE_RX_BASE+4)) sr_4
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(new_command),.changed());
+
+ setting_reg #(.my_addr(`DSP_CORE_RX_BASE+5)) sr_5
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(),.changed(clear_overrun));
+
+ reg sc_pre2;
+ always @(posedge clk)
+ sc_pre2 <= sc_pre1;
+ assign write_ctrl = sc_pre1 & ~sc_pre2;
+
+ shortfifo #(.WIDTH(64)) commandfifo
+ (.clk(clk),.rst(rst),.clear(clear_overrun),
+ .datain({new_command,new_time}), .write(write_ctrl), .full(full_ctrl),
+ .dataout({send_imm_pre,chain_pre,numlines,lines_per_frame,rcvtime_pre}),
+ .read(read_ctrl), .empty(empty_ctrl) );
+
+ // Buffer interface to internal FIFO
+ wire have_space, write;
+ wire [35:0] fifo_line;
+
+ // Internal FIFO, size 9 is 2K, size 10 is 4K
+ fifo_cascade #(.WIDTH(36),.SIZE(FIFOSIZE)) rxfifo
+ (.clk(clk),.reset(rst),.clear(clear_overrun),
+ .datain(fifo_line), .src_rdy_i(write), .dst_rdy_o(have_space),
+ .dataout({wr_flags_o,wr_dat_o}), .src_rdy_o(wr_ready_o), .dst_rdy_i(wr_ready_i),
+ .space(),.occupied(fifo_occupied) );
+ assign fifo_full = ~have_space;
+ assign fifo_empty = ~wr_ready_o;
+
+ // Internal FIFO to DSP interface
+ reg [22:0] lines_left;
+ reg [8:0] lines_left_frame;
+ localparam IBS_IDLE = 0;
+ localparam IBS_WAITING = 1;
+ localparam IBS_FIRSTLINE = 2;
+ localparam IBS_RUNNING = 3;
+ localparam IBS_OVERRUN = 4;
+
+ reg [2:0] ibs_state;
+
+ wire [32:0] delta_time = {1'b0,rcvtime}-{1'b0,master_time};
+ wire too_late = (delta_time[32:31] == 2'b11) & ~send_imm;
+ wire go_now = send_imm | ( master_time == rcvtime );
+
+ always @(posedge clk)
+ if(rst)
+ begin
+ ibs_state <= IBS_IDLE;
+ lines_left <= 0;
+ lines_left_frame <= 0;
+ rcvtime <= 0;
+ send_imm <= 0;
+ chain <= 0;
+ end
+ else
+ if(clear_overrun)
+ begin
+ ibs_state <= IBS_IDLE;
+ lines_left <= 0;
+ lines_left_frame <= 0;
+ rcvtime <= 0;
+ send_imm <= 0;
+ chain <= 0;
+ end
+ else
+ case(ibs_state)
+ IBS_IDLE :
+ if(~empty_ctrl)
+ begin
+ lines_left <= numlines;
+ lines_left_frame <= lines_per_frame;
+ rcvtime <= rcvtime_pre;
+ ibs_state <= IBS_WAITING;
+ send_imm <= send_imm_pre;
+ chain <= chain_pre;
+ end
+ IBS_WAITING :
+ if(go_now)
+ ibs_state <= IBS_FIRSTLINE;
+ else if(too_late)
+ ibs_state <= IBS_OVERRUN;
+ IBS_FIRSTLINE :
+ if(~have_space | strobe)
+ ibs_state <= IBS_OVERRUN;
+ else
+ ibs_state <= IBS_RUNNING;
+ IBS_RUNNING :
+ if(strobe)
+ if(~have_space)
+ ibs_state <= IBS_OVERRUN;
+ else
+ begin
+ lines_left <= lines_left - 1;
+ if(lines_left == 1)
+ if(~chain)
+ ibs_state <= IBS_IDLE;
+ else if(empty_ctrl)
+ ibs_state <= IBS_OVERRUN;
+ else
+ begin
+ lines_left <= numlines;
+ lines_left_frame <= lines_per_frame;
+ rcvtime <= rcvtime_pre;
+ ibs_state <= IBS_FIRSTLINE;
+ send_imm <= send_imm_pre;
+ chain <= chain_pre;
+ end
+ else if(lines_left_frame == 1)
+ begin
+ lines_left_frame <= lines_per_frame;
+ ibs_state <= IBS_FIRSTLINE;
+ end
+ else
+ lines_left_frame <= lines_left_frame - 1;
+ end // else: !if(~have_space)
+ endcase // case(ibs_state)
+
+ assign fifo_line = (ibs_state == IBS_FIRSTLINE) ? {2'b0,1'b0,1'b1,master_time} :
+ {2'b0,((lines_left==1)|(lines_left_frame==1)),1'b0,sample};
+
+ assign write = ((ibs_state == IBS_FIRSTLINE) | strobe) & have_space; // & (ibs_state == IBS_RUNNING) should strobe only when running
+ assign overrun = (ibs_state == IBS_OVERRUN);
+ assign run = (ibs_state == IBS_RUNNING) | (ibs_state == IBS_FIRSTLINE);
+ assign read_ctrl = ( (ibs_state == IBS_IDLE) |
+ ((ibs_state == IBS_RUNNING) & strobe & have_space & (lines_left==1) & chain) )
+ & ~empty_ctrl;
+
+ assign debug_rx = { 8'd0,
+ 1'd0, send_imm, chain, wr_ready_i,wr_ready_o, 2'b0, run,
+ write,have_space,wr_flags_o[1:0],write_ctrl,full_ctrl,read_ctrl,empty_ctrl,
+ sc_pre1, clear_overrun, go_now, too_late, overrun, ibs_state[2:0] };
+endmodule // rx_control
diff --git a/fpga/usrp2/sdr_lib/rx_dcoffset.v b/fpga/usrp2/sdr_lib/rx_dcoffset.v
new file mode 100644
index 000000000..bedbd40e6
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/rx_dcoffset.v
@@ -0,0 +1,43 @@
+
+
+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
+
+ 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;
+
+ always @(posedge clk)
+ if(rst)
+ begin
+ fixed <= 0;
+ integrator <= 32'd0;
+ end
+ else if(set_now)
+ begin
+ integrator <= {set_data[WIDTH-1:0],{(32-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;
+
+ clip_reg #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip_adc
+ (.clk(clk),.in(adc_out_int),.out(adc_out));
+
+
+endmodule // rx_dcoffset
diff --git a/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v b/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v
new file mode 100644
index 000000000..a8b4ec20f
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v
@@ -0,0 +1,25 @@
+
+`timescale 1ns/1ns
+module rx_dcoffset_tb();
+
+ reg clk, rst;
+
+ initial rst = 1;
+ initial #1000 rst = 0;
+ initial clk = 0;
+ always #5 clk = ~clk;
+
+ initial $dumpfile("rx_dcoffset_tb.vcd");
+ initial $dumpvars(0,rx_dcoffset_tb);
+
+ reg [13:0] adc_in = 7;
+ wire [13:0] adc_out;
+
+ always @(posedge clk)
+ $display("%d\t%d",adc_in,adc_out);
+
+ rx_dcoffset #(.WIDTH(14),.ADDR(0))
+ rx_dcoffset(.clk(clk),.rst(rst),.set_stb(0),.set_addr(0),.set_data(0),
+ .adc_in(adc_in),.adc_out(adc_out));
+
+endmodule // longfifo_tb
diff --git a/fpga/usrp2/sdr_lib/sign_extend.v b/fpga/usrp2/sdr_lib/sign_extend.v
new file mode 100644
index 000000000..eae67faf2
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/sign_extend.v
@@ -0,0 +1,35 @@
+// -*- verilog -*-
+//
+// USRP - Universal Software Radio Peripheral
+//
+// Copyright (C) 2003 Matt Ettus
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
+//
+
+
+// Sign extension "macro"
+// bits_out should be greater than bits_in
+
+module sign_extend (in,out);
+ parameter bits_in=0; // FIXME Quartus insists on a default
+ parameter bits_out=0;
+
+ input [bits_in-1:0] in;
+ output [bits_out-1:0] out;
+
+ assign out = {{(bits_out-bits_in){in[bits_in-1]}},in};
+
+endmodule
diff --git a/fpga/usrp2/sdr_lib/small_hb_dec.v b/fpga/usrp2/sdr_lib/small_hb_dec.v
new file mode 100644
index 000000000..8519b628a
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/small_hb_dec.v
@@ -0,0 +1,111 @@
+// Short halfband decimator (intended to be followed by another stage)
+// Implements impulse responses of the form [A 0 B 0.5 B 0 A]
+//
+// These taps designed by halfgen4 from ldoolittle:
+// 2 * 131072 * halfgen4(.75/8,2)
+module small_hb_dec
+ #(parameter WIDTH=18)
+ (input clk,
+ input rst,
+ input bypass,
+ input run,
+ input stb_in,
+ input [WIDTH-1:0] data_in,
+ output reg stb_out,
+ output [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;
+
+ 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)
+ phase <= ~phase;
+ assign go = stb_in_d1 & phase;
+ always @(posedge clk)
+ if(rst | ~run)
+ begin
+ go_d1 <= 0;
+ go_d2 <= 0;
+ go_d3 <= 0;
+ go_d4 <= 0;
+ end
+ else
+ begin
+ go_d1 <= go;
+ go_d2 <= go_d1;
+ go_d3 <= go_d2;
+ go_d4 <= go_d3;
+ end
+
+ wire [17:0] coeff_a = -10690;
+ wire [17:0] coeff_b = 75809;
+
+ reg [WIDTH-1:0] d1, d2, d3, d4 , d5, d6;
+ always @(posedge clk)
+ if(stb_in_d1 | rst)
+ begin
+ d1 <= data_in_d1;
+ d2 <= d1;
+ d3 <= d2;
+ d4 <= d3;
+ d5 <= d4;
+ d6 <= d5;
+ 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;
+ end
+
+ always @(posedge clk)
+ if(go_d1)
+ middle_d1 <= middle;
+
+ wire [17:0] sum = go_d1 ? sum_b : sum_a;
+ wire [17:0] coeff = go_d1 ? coeff_b : coeff_a;
+ wire [35:0] prod;
+ MULT18X18S mult(.C(clk), .CE(go_d1 | go_d2), .R(rst), .P(prod), .A(coeff), .B(sum) );
+
+ reg [35:0] accum;
+ always @(posedge clk)
+ if(rst)
+ accum <= 0;
+ else if(go_d2)
+ accum <= {middle_d1[17],middle_d1[17],middle_d1,16'd0} + {prod};
+ 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));
+
+ reg [17:0] final_sum;
+ always @(posedge clk)
+ if(bypass)
+ final_sum <= data_in_d1;
+ else if(go_d4)
+ final_sum <= accum_rnd;
+
+ 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/small_hb_dec_tb.v b/fpga/usrp2/sdr_lib/small_hb_dec_tb.v
new file mode 100644
index 000000000..0d6a0689e
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/small_hb_dec_tb.v
@@ -0,0 +1,140 @@
+module hb_dec_tb( ) ;
+
+ // Parameters for instantiation
+ parameter clocks = 9'd2 ; // Number of clocks per input
+ parameter decim = 1 ; // Sets the filter to decimate
+ parameter rate = 2 ; // Sets the decimation rate
+
+ reg clock ;
+ reg reset ;
+ reg enable ;
+ reg strobe_in ;
+ reg signed [17:0] data_in ;
+ wire strobe_out ;
+ wire signed [17:0] data_out ;
+
+ initial
+ begin
+ $dumpfile("hb_dec_tb.vcd");
+ $dumpvars(0,hb_dec_tb);
+ end
+
+ // Setup the clock
+ initial clock = 1'b0 ;
+ always #5 clock <= ~clock ;
+
+ // Come out of reset after a while
+ initial reset = 1'b1 ;
+ initial #1000 reset = 1'b0 ;
+
+ // Enable the entire system
+ initial enable = 1'b1 ;
+
+ // Instantiate UUT
+ /*
+ halfband_ideal
+ #(
+ .decim ( decim ),
+ .rate ( rate )
+ ) uut(
+ .clock ( clock ),
+ .reset ( reset ),
+ .enable ( enable ),
+ .strobe_in ( strobe_in ),
+ .data_in ( data_in ),
+ .strobe_out ( strobe_out ),
+ .data_out ( data_out )
+ ) ;
+ */
+
+
+ small_hb_dec #(.WIDTH(18)) uut
+ (.clk(clock),.rst(reset),.bypass(0),.stb_in(strobe_in),.data_in(data_in),
+ .stb_out(strobe_out),.data_out(data_out) );
+
+ integer i, ri, ro, infile, outfile ;
+
+ always @(posedge clock)
+ begin
+ if(strobe_out)
+ $display(data_out);
+ end
+
+ // Setup file IO
+ initial begin
+ infile = $fopen("input.dat","r") ;
+ outfile = $fopen("output.dat","r") ;
+ $timeformat(-9, 2, " ns", 10) ;
+ end
+
+ reg endofsim ;
+ reg signed [17:0] compare ;
+ integer noe ;
+ initial noe = 0 ;
+
+ initial begin
+ // Initialize inputs
+ strobe_in <= 1'd0 ;
+ data_in <= 18'd0 ;
+
+ // Wait for reset to go away
+ @(negedge reset) #0 ;
+
+ // While we're still simulating ...
+ while( !endofsim ) begin
+
+ // Write the input from the file or 0 if EOF...
+ @( posedge clock ) begin
+ //#1 ;
+ strobe_in <= 1'b1 ;
+ if( !$feof(infile) )
+ ri = $fscanf( infile, "%d", data_in ) ;
+ else
+ data_in <= 18'd0 ;
+ end
+
+ // Clocked in - set the strobe to 0 if the number of
+ // clocks per sample is greater than 1
+ if( clocks > 1 ) begin
+ @(posedge clock) begin
+ strobe_in <= 1'b0 ;
+ end
+
+ // Wait for the specified number of cycles
+ for( i = 0 ; i < (clocks-2) ; i = i + 1 ) begin
+ @(posedge clock) #1 ;
+ end
+ end
+ end
+
+ // Print out the number of errors that occured
+ if( noe )
+ $display( "FAILED: %d errors during simulation", noe ) ;
+ else
+ $display( "PASSED: Simulation successful" ) ;
+
+ $finish ;
+ end
+
+ // Output comparison of simulated values versus known good values
+ always @ (posedge clock) begin
+ if( reset )
+ endofsim <= 1'b0 ;
+ else begin
+ if( !$feof(outfile) ) begin
+ if( strobe_out ) begin
+ ro = $fscanf( outfile, "%d\n", compare ) ;
+ if( compare != data_out ) begin
+ //$display( "%t: %d != %d", $realtime, data_out, compare ) ;
+ noe = noe + 1 ;
+ end
+ end
+ end else begin
+ // Signal end of simulation when no more outputs
+ endofsim <= 1'b1 ;
+ end
+ end
+ end
+
+endmodule // hb_dec_tb
+
diff --git a/fpga/usrp2/sdr_lib/small_hb_int.v b/fpga/usrp2/sdr_lib/small_hb_int.v
new file mode 100644
index 000000000..f80d3cac3
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/small_hb_int.v
@@ -0,0 +1,85 @@
+// Short halfband decimator (intended to be followed by another stage)
+// Implements impulse responses of the form [A 0 B 0.5 B 0 A]
+//
+// These taps designed by halfgen4 from ldoolittle:
+// 2 * 131072 * halfgen4(.75/8,2)
+
+module small_hb_int
+ #(parameter WIDTH=18)
+ (input clk,
+ input rst,
+ input bypass,
+ input stb_in,
+ input [WIDTH-1:0] data_in,
+ input [7:0] output_rate,
+ input stb_out,
+ output reg [WIDTH-1:0] data_out);
+
+ reg phase;
+ reg [WIDTH-1:0] d1, d2, d3, d4, d5, d6;
+
+ localparam MWIDTH = 36;
+ wire [MWIDTH-1:0] prod;
+
+ reg [6:0] stbin_d;
+
+ always @(posedge clk)
+ stbin_d <= {stbin_d[5:0],stb_in};
+
+ always @(posedge clk)
+ if(stb_in)
+ begin
+ d1 <= data_in;
+ d2 <= d1;
+ d3 <= d2;
+ d4 <= d3;
+ d5 <= d4;
+ d6 <= d5;
+ end
+
+ wire [WIDTH-1:0] sum_outer, sum_inner;
+ add2_and_round_reg #(.WIDTH(WIDTH)) add_outer (.clk(clk),.in1(d1),.in2(d4),.sum(sum_outer));
+ add2_and_round_reg #(.WIDTH(WIDTH)) add_inner (.clk(clk),.in1(d2),.in2(d3),.sum(sum_inner));
+
+ wire [17:0] coeff_outer = -10690;
+ wire [17:0] coeff_inner = 75809;
+
+ MULT18X18S mult(.C(clk), .CE(1), .R(rst), .P(prod), .A(stbin_d[1] ? coeff_outer : coeff_inner),
+ .B(stbin_d[1] ? sum_outer : sum_inner) );
+
+ wire [MWIDTH:0] accum;
+ acc #(.IWIDTH(MWIDTH),.OWIDTH(MWIDTH+1))
+ acc (.clk(clk),.clear(stbin_d[2]),.acc(|stbin_d[3:2]),.in(prod),.out(accum));
+
+ wire [WIDTH+2:0] accum_rnd;
+ round_reg #(.bits_in(MWIDTH+1),.bits_out(WIDTH+3))
+ final_round (.clk(clk),.in(accum),.out(accum_rnd));
+
+ wire [WIDTH-1:0] clipped;
+ clip_reg #(.bits_in(WIDTH+3),.bits_out(WIDTH))
+ final_clip (.clk(clk),.in(accum_rnd),.out(clipped));
+
+ reg [WIDTH-1:0] saved, saved_d3;
+ always @(posedge clk)
+ if(stbin_d[6])
+ saved <= clipped;
+
+ always @(posedge clk)
+ if(stbin_d[3])
+ saved_d3 <= d3;
+
+ always @(posedge clk)
+ if(bypass)
+ data_out <= data_in;
+ else if(stb_in & stb_out)
+ case(output_rate)
+ 1 : data_out <= d6;
+ 2 : data_out <= d4;
+ 3, 4, 5, 6, 7 : data_out <= d3;
+ default : data_out <= d2;
+ endcase // case(output_rate)
+ else if(stb_out)
+ data_out <= saved;
+
+endmodule // small_hb_int
+
diff --git a/fpga/usrp2/sdr_lib/small_hb_int_tb.v b/fpga/usrp2/sdr_lib/small_hb_int_tb.v
new file mode 100644
index 000000000..71d77f0a8
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/small_hb_int_tb.v
@@ -0,0 +1,132 @@
+module small_hb_int_tb( ) ;
+
+ // Parameters for instantiation
+ parameter clocks = 8'd1 ; // Number of clocks per output
+ parameter decim = 1 ; // Sets the filter to decimate
+ parameter rate = 2 ; // Sets the decimation rate
+
+ reg clock ;
+ reg reset ;
+ reg enable ;
+ wire strobe_in ;
+ reg signed [17:0] data_in ;
+ wire strobe_out ;
+ wire signed [17:0] data_out ;
+
+ initial
+ begin
+ $dumpfile("small_hb_int_tb.vcd");
+ $dumpvars(0,small_hb_int_tb);
+ end
+
+ // Setup the clock
+ initial clock = 1'b0 ;
+ always #5 clock <= ~clock ;
+
+ // Come out of reset after a while
+ initial reset = 1'b1 ;
+ initial #1000 reset = 1'b0 ;
+
+ always @(posedge clock)
+ enable <= ~reset;
+
+ // Instantiate UUT
+ /*
+ halfband_ideal
+ #(
+ .decim ( decim ),
+ .rate ( rate )
+ ) uut(
+ .clock ( clock ),
+ .reset ( reset ),
+ .enable ( enable ),
+ .strobe_in ( strobe_in ),
+ .data_in ( data_in ),
+ .strobe_out ( strobe_out ),
+ .data_out ( data_out )
+ ) ;
+ */
+
+ cic_strober #(.WIDTH(8))
+ out_strober(.clock(clock),.reset(reset),.enable(enable),.rate(clocks),
+ .strobe_fast(1),.strobe_slow(strobe_out) );
+
+ cic_strober #(.WIDTH(8))
+ in_strober(.clock(clock),.reset(reset),.enable(enable),.rate(2),
+ .strobe_fast(strobe_out),.strobe_slow(strobe_in) );
+
+ small_hb_int #(.WIDTH(18)) uut
+ (.clk(clock),.rst(reset),.bypass(0),.stb_in(strobe_in),.data_in(data_in),
+ .stb_out(strobe_out),.output_rate(clocks),.data_out(data_out) );
+
+ integer i, ri, ro, infile, outfile ;
+
+ always @(posedge clock)
+ begin
+ if(strobe_out)
+ $display(data_out);
+ end
+
+ // Setup file IO
+ initial begin
+ infile = $fopen("input.dat","r") ;
+ outfile = $fopen("output.dat","r") ;
+ $timeformat(-9, 2, " ns", 10) ;
+ end
+
+ reg endofsim ;
+ reg signed [17:0] compare ;
+ integer noe ;
+ initial noe = 0 ;
+
+ initial begin
+ // Initialize inputs
+ data_in <= 18'd0 ;
+
+ // Wait for reset to go away
+ @(negedge reset) #0 ;
+
+ // While we're still simulating ...
+ while( !endofsim ) begin
+
+ // Write the input from the file or 0 if EOF...
+ @( negedge clock ) begin
+ if(strobe_in)
+ if( !$feof(infile) )
+ ri <= #1 $fscanf( infile, "%d", data_in ) ;
+ else
+ data_in <= 18'd0 ;
+ end
+ end
+
+ // Print out the number of errors that occured
+ if( noe )
+ $display( "FAILED: %d errors during simulation", noe ) ;
+ else
+ $display( "PASSED: Simulation successful" ) ;
+
+ $finish ;
+ end
+
+ // Output comparison of simulated values versus known good values
+ always @ (posedge clock) begin
+ if( reset )
+ endofsim <= 1'b0 ;
+ else begin
+ if( !$feof(outfile) ) begin
+ if( strobe_out ) begin
+ ro = $fscanf( outfile, "%d\n", compare ) ;
+ if( compare != data_out ) begin
+ //$display( "%t: %d != %d", $realtime, data_out, compare ) ;
+ noe = noe + 1 ;
+ end
+ end
+ end else begin
+ // Signal end of simulation when no more outputs
+ if($feof(infile))
+ endofsim <= 1'b1 ;
+ end
+ end
+ end
+
+endmodule // small_hb_int_tb
diff --git a/fpga/usrp2/sdr_lib/tx_control.v b/fpga/usrp2/sdr_lib/tx_control.v
new file mode 100644
index 000000000..e5fed0b93
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/tx_control.v
@@ -0,0 +1,168 @@
+
+`define DSP_CORE_TX_BASE 128
+
+module tx_control
+ #(parameter FIFOSIZE = 10)
+ (input clk, input rst,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ input [31:0] master_time,
+ output underrun,
+
+ // To FIFO interface from Buffer Pool
+ input [31:0] rd_dat_i,
+ input [3:0] rd_flags_i,
+ input rd_ready_i,
+ output rd_ready_o,
+
+ // To DSP Core
+ output [31:0] sample,
+ output run,
+ input strobe,
+
+ // FIFO Levels
+ output [15:0] fifo_occupied,
+ output fifo_full,
+ output fifo_empty,
+
+ // Debug
+ output [31:0] debug
+ );
+
+ wire rd_sop_i = rd_flags_i[0]; // Unused
+ wire rd_eop_i = rd_flags_i[1];
+ wire rd_occ_i = rd_flags_i[3:2]; // Unused, should always be 0
+
+ // Buffer interface to internal FIFO
+ wire write_data, write_ctrl, full_data, full_ctrl;
+ wire read_data, read_ctrl, empty_data, empty_ctrl;
+ wire clear_state;
+ reg [1:0] xfer_state;
+ reg [2:0] held_flags;
+
+ localparam XFER_IDLE = 0;
+ localparam XFER_CTRL = 1;
+ localparam XFER_PKT = 2;
+ // Add underrun state?
+
+ always @(posedge clk)
+ if(rst)
+ xfer_state <= XFER_IDLE;
+ else if(clear_state)
+ xfer_state <= XFER_IDLE;
+ else
+ if(rd_ready_i & rd_ready_o)
+ case(xfer_state)
+ XFER_IDLE :
+ begin
+ xfer_state <= XFER_CTRL;
+ held_flags <= rd_dat_i[2:0];
+ end
+ XFER_CTRL :
+ xfer_state <= XFER_PKT;
+ XFER_PKT :
+ if(rd_eop_i)
+ xfer_state <= XFER_IDLE;
+ endcase // case(xfer_state)
+
+ wire have_data_space;
+ assign full_data = ~have_data_space;
+
+ assign write_data = (xfer_state == XFER_PKT) & rd_ready_i & rd_ready_o;
+ assign write_ctrl = (xfer_state == XFER_CTRL) & rd_ready_i & rd_ready_o;
+
+ assign rd_ready_o = ~full_data & ~full_ctrl;
+
+ wire [31:0] data_o;
+ wire eop_o, eob, sob, send_imm;
+ wire [31:0] sendtime;
+ wire [4:0] occ_ctrl;
+/*
+ cascadefifo2 #(.WIDTH(33),.SIZE(FIFOSIZE)) txctrlfifo
+ (.clk(clk),.rst(rst),.clear(clear_state),
+ .datain({rd_eop_i,rd_dat_i[31:0]}), .write(write_data), .full(full_data),
+ .dataout({eop_o,data_o}), .read(read_data), .empty(empty_data),
+ .space(), .occupied(fifo_occupied) );
+*/
+ wire have_data;
+ assign empty_data = ~have_data;
+
+ fifo_cascade #(.WIDTH(33),.SIZE(FIFOSIZE)) txctrlfifo
+ (.clk(clk),.reset(rst),.clear(clear_state),
+ .datain({rd_eop_i,rd_dat_i[31:0]}), .src_rdy_i(write_data), .dst_rdy_o(have_data_space),
+ .dataout({eop_o,data_o}), .src_rdy_o(have_data), .dst_rdy_i(read_data),
+ .space(), .occupied(fifo_occupied) );
+ assign fifo_full = full_data;
+ assign fifo_empty = empty_data;
+
+ shortfifo #(.WIDTH(35)) ctrlfifo
+ (.clk(clk),.rst(rst),.clear(clear_state),
+ .datain({held_flags[2:0],rd_dat_i[31:0]}), .write(write_ctrl), .full(full_ctrl),
+ .dataout({send_imm,sob,eob,sendtime}), .read(read_ctrl), .empty(empty_ctrl),
+ .space(), .occupied(occ_ctrl) );
+
+ // Internal FIFO to DSP interface
+ reg [2:0] ibs_state;
+
+ localparam IBS_IDLE = 0;
+ localparam IBS_WAIT = 1;
+ localparam IBS_RUNNING = 2;
+ localparam IBS_CONT_BURST = 3;
+ localparam IBS_UNDERRUN = 7;
+
+ wire [32:0] delta_time = {1'b0,sendtime}-{1'b0,master_time};
+
+ wire too_late = (delta_time[32:31] == 2'b11);
+ wire go_now = ( master_time == sendtime );
+
+ always @(posedge clk)
+ if(rst)
+ ibs_state <= IBS_IDLE;
+ else
+ case(ibs_state)
+ IBS_IDLE :
+ if(~empty_ctrl & ~empty_data)
+ ibs_state <= IBS_WAIT;
+ IBS_WAIT :
+ if(send_imm)
+ ibs_state <= IBS_RUNNING;
+ else if(too_late)
+ ibs_state <= IBS_UNDERRUN;
+ else if(go_now)
+ ibs_state <= IBS_RUNNING;
+ IBS_RUNNING :
+ if(strobe)
+ if(empty_data)
+ ibs_state <= IBS_UNDERRUN;
+ else if(eop_o)
+ if(eob)
+ ibs_state <= IBS_IDLE;
+ else
+ ibs_state <= IBS_CONT_BURST;
+ IBS_CONT_BURST :
+ if(~empty_ctrl) // & ~empty_data)
+ ibs_state <= IBS_RUNNING;
+ else if(strobe)
+ ibs_state <= IBS_UNDERRUN;
+ IBS_UNDERRUN : // FIXME Should probably clean everything out
+ if(clear_state)
+ ibs_state <= IBS_IDLE;
+ endcase // case(ibs_state)
+
+ assign read_ctrl = (ibs_state == IBS_RUNNING) & strobe & eop_o; // & ~empty_ctrl;
+ assign read_data = (ibs_state == IBS_RUNNING) & strobe & ~empty_data;
+ assign run = (ibs_state == IBS_RUNNING) | (ibs_state == IBS_CONT_BURST);
+ assign underrun = (ibs_state == IBS_UNDERRUN);
+
+ wire [7:0] interp_rate;
+ setting_reg #(.my_addr(`DSP_CORE_TX_BASE+3)) sr_3
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(),.changed(clear_state));
+
+ assign sample = data_o;
+
+ assign debug = { {16'b0},
+ { read_data, write_data, read_ctrl, write_ctrl, xfer_state[1:0],full_ctrl,empty_ctrl },
+ { occ_ctrl, eop_o, clear_state, underrun} };
+
+endmodule // tx_control