diff options
Diffstat (limited to 'fpga/usrp2/sdr_lib/small_hb_dec.v')
-rw-r--r-- | fpga/usrp2/sdr_lib/small_hb_dec.v | 136 |
1 files changed, 136 insertions, 0 deletions
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..c05a48b81 --- /dev/null +++ b/fpga/usrp2/sdr_lib/small_hb_dec.v @@ -0,0 +1,136 @@ +// +// Copyright 2011 Ettus Research LLC +// +// 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 3 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, see <http://www.gnu.org/licenses/>. +// + +// 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 reg [WIDTH-1:0] data_out); + + // Round off inputs to 17 bits because of 18 bit multipliers + localparam INTWIDTH = 17; + wire [INTWIDTH-1:0] data_rnd; + wire stb_rnd; + + round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(INTWIDTH)) round_in + (.clk(clk),.reset(rst),.in(data_in),.strobe_in(stb_in),.out(data_rnd),.strobe_out(stb_rnd)); + + + reg stb_rnd_d1; + reg [INTWIDTH-1:0] data_rnd_d1; + always @(posedge clk) stb_rnd_d1 <= stb_rnd; + always @(posedge clk) data_rnd_d1 <= data_rnd; + + wire go; + reg phase, go_d1, go_d2, go_d3, go_d4; + always @(posedge clk) + if(rst | ~run) + phase <= 0; + else if(stb_rnd_d1) + phase <= ~phase; + assign go = stb_rnd_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 [INTWIDTH-1:0] d1, d2, d3, d4 , d5, d6; + always @(posedge clk) + if(stb_rnd_d1 | rst) + begin + d1 <= data_rnd_d1; + d2 <= d1; + d3 <= d2; + d4 <= d3; + d5 <= d4; + d6 <= d5; + end + + reg [17:0] sum_a, sum_b, middle, middle_d1; + + always @(posedge clk) + if(go) + begin + sum_a <= {data_rnd_d1[INTWIDTH-1],data_rnd_d1} + {d6[INTWIDTH-1],d6}; + sum_b <= {d2[INTWIDTH-1],d2} + {d4[INTWIDTH-1],d4}; + //middle <= {d3[INTWIDTH-1],d3}; + middle <= {d3,1'b0}; + end + + always @(posedge clk) + 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) ); + + localparam ACCWIDTH = 30; + reg [ACCWIDTH-1:0] accum; + + always @(posedge clk) + if(rst) + accum <= 0; + else if(go_d2) + accum <= {middle_d1[17],middle_d1[17],middle_d1,{(16+ACCWIDTH-36){1'b0}}} + {prod[35:36-ACCWIDTH]}; + else if(go_d3) + accum <= accum + {prod[35:36-ACCWIDTH]}; + + wire [WIDTH:0] accum_rnd; + wire [WIDTH-1:0] accum_rnd_clip; + + wire stb_round; + + round_sd #(.WIDTH_IN(ACCWIDTH),.WIDTH_OUT(WIDTH+1)) round_acc + (.clk(clk), .reset(rst), .in(accum), .strobe_in(go_d4), .out(accum_rnd), .strobe_out(stb_round)); + + clip #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip (.in(accum_rnd), .out(accum_rnd_clip)); + + // Output + always @(posedge clk) + begin + stb_out <= bypass ? stb_in : stb_round; + data_out <= bypass ? data_in : accum_rnd_clip; + end + + +endmodule // small_hb_dec |