1 // Final halfband decimator
2 // Implements impulse responses of the form [A 0 B 0 C .. 0 H 0.5 H 0 .. C 0 B 0 A]
3 // Strobe in cannot come faster than every 2nd clock cycle
4 // These taps designed by halfgen4 from ldoolittle
5 // myfilt = round(2^18 * halfgen4(.7/4,8))
8 #(parameter IWIDTH=18, OWIDTH=18, CWIDTH=18, ACCWIDTH=24)
13 input [8:0] cpi, // Clocks per input -- equal to the decimation ratio ahead of this block
15 input [IWIDTH-1:0] data_in,
17 output reg [OWIDTH-1:0] data_out);
20 reg [3:0] addr_odd_a, addr_odd_b, addr_odd_c, addr_odd_d;
21 wire write_odd, write_even, do_mult;
23 reg [2:0] phase, phase_d1;
34 assign write_odd = stb_in & odd;
35 assign write_even = stb_in & ~odd;
50 reg [15:0] stb_out_pre;
55 stb_out_pre <= {stb_out_pre[14:0],(stb_in & odd)};
59 1 : begin addr_odd_a = 0; addr_odd_b = 15; end
60 2 : begin addr_odd_a = 1; addr_odd_b = 14; end
61 3 : begin addr_odd_a = 2; addr_odd_b = 13; end
62 4 : begin addr_odd_a = 3; addr_odd_b = 12; end
63 default : begin addr_odd_a = 0; addr_odd_b = 15; end
64 endcase // case(phase)
68 1 : begin addr_odd_c = 4; addr_odd_d = 11; end
69 2 : begin addr_odd_c = 5; addr_odd_d = 10; end
70 3 : begin addr_odd_c = 6; addr_odd_d = 9; end
71 4 : begin addr_odd_c = 7; addr_odd_d = 8; end
72 default : begin addr_odd_c = 4; addr_odd_d = 11; end
73 endcase // case(phase)
75 assign do_acc = |stb_out_pre[6:3];
76 assign clear = stb_out_pre[3];
79 wire [IWIDTH-1:0] data_odd_a, data_odd_b, data_odd_c, data_odd_d;
80 wire [IWIDTH-1:0] sum1, sum2;
81 wire [OWIDTH-1:0] final_sum;
82 reg [CWIDTH-1:0] coeff1, coeff2;
83 wire [35:0] prod1, prod2;
85 always @* // Outer coeffs
91 default : coeff1 = -107;
92 endcase // case(phase)
94 always @* // Inner coeffs
100 default : coeff2 = -6107;
101 endcase // case(phase)
103 srl #(.WIDTH(IWIDTH)) srl_odd_a
104 (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_a),.out(data_odd_a));
105 srl #(.WIDTH(IWIDTH)) srl_odd_b
106 (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_b),.out(data_odd_b));
107 srl #(.WIDTH(IWIDTH)) srl_odd_c
108 (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_c),.out(data_odd_c));
109 srl #(.WIDTH(IWIDTH)) srl_odd_d
110 (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_d),.out(data_odd_d));
112 add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add1 (.clk(clk),.in1(data_odd_a),.in2(data_odd_b),.sum(sum1));
113 add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add2 (.clk(clk),.in1(data_odd_c),.in2(data_odd_d),.sum(sum2));
115 wire [IWIDTH-1:0] data_even;
118 always @(posedge clk)
121 2 : addr_even <= 9; // Maximum speed (overall decim by 4)
122 3, 4, 5, 6, 7 : addr_even <= 8;
123 default : addr_even <= 7;
126 srl #(.WIDTH(IWIDTH)) srl_even
127 (.clk(clk),.write(write_even),.in(data_in),.addr(addr_even),.out(data_even));
129 localparam MWIDTH = ACCWIDTH-2;
130 wire [MWIDTH-1:0] sum_of_prod;
132 MULT18X18S mult1(.C(clk), .CE(do_mult), .R(rst), .P(prod1), .A(coeff1), .B(sum1) );
133 MULT18X18S mult2(.C(clk), .CE(do_mult), .R(rst), .P(prod2), .A(coeff2), .B(sum2) );
134 add2_and_round_reg #(.WIDTH(MWIDTH))
135 add3 (.clk(clk),.in1(prod1[35:36-MWIDTH]),.in2(prod2[35:36-MWIDTH]),.sum(sum_of_prod));
137 wire [ACCWIDTH-1:0] acc_out;
139 acc #(.IWIDTH(MWIDTH),.OWIDTH(ACCWIDTH))
140 acc (.clk(clk),.clear(clear),.acc(do_acc),.in(sum_of_prod),.out(acc_out));
142 localparam SHIFT_FACTOR = ACCWIDTH-IWIDTH-5;
143 wire [ACCWIDTH-1:0] data_even_signext;
144 wire [ACCWIDTH:0] final_sum_unrounded;
146 sign_extend #(.bits_in(IWIDTH),.bits_out(ACCWIDTH-SHIFT_FACTOR))
147 signext_data_even (.in(data_even),.out(data_even_signext[ACCWIDTH-1:SHIFT_FACTOR]));
148 assign data_even_signext[SHIFT_FACTOR-1:0] = 0;
150 add2_reg /* add2_and_round_reg */ #(.WIDTH(ACCWIDTH+1))
151 final_adder (.clk(clk), .in1({acc_out,1'b0}), .in2({data_even_signext,1'b0}), .sum(final_sum_unrounded));
153 round_reg #(.bits_in(ACCWIDTH-4),.bits_out(OWIDTH))
154 final_round (.clk(clk),.in(final_sum_unrounded[ACCWIDTH-5:0]),.out(final_sum));
157 always @(posedge clk)
160 else if(stb_out_pre[9])
161 data_out <= final_sum;
163 always @(posedge clk)
169 stb_out <= stb_out_pre[9];