Imported Upstream version 3.0
[debian/gnuradio] / usrp / fpga / sdr_lib / hb / halfband_decim.v
1 /* -*- verilog -*-
2  * 
3  *  USRP - Universal Software Radio Peripheral
4  * 
5  *  Copyright (C) 2005 Matt Ettus
6  * 
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  * 
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  * 
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA
20  */
21
22 /*
23  * This implements a 31-tap halfband filter that decimates by two.
24  * The coefficients are symmetric, and with the exception of the middle tap,
25  * every other coefficient is zero.  The middle section of taps looks like this:
26  *
27  *  ..., -1468, 0, 2950, 0, -6158, 0, 20585, 32768, 20585, 0, -6158, 0, 2950, 0, -1468, ...
28  *                                             |
29  *                           middle tap -------+
30  *
31  * See coeff_rom.v for the full set.  The taps are scaled relative to 32768,
32  * thus the middle tap equals 1.0.  Not counting the middle tap, there are 8
33  * non-zero taps on each side, and they are symmetric.  A naive implementation
34  * requires a mulitply for each non-zero tap.  Because of symmetry, we can
35  * replace 2 multiplies with 1 add and 1 multiply.  Thus, to compute each output
36  * sample, we need to perform 8 multiplications.  Since the middle tap is 1.0,
37  * we just add the corresponding delay line value.
38  *
39  * About timing: We implement this with a single multiplier, so it takes
40  * 8 cycles to compute a single output.  However, since we're decimating by two 
41  * we can accept a new input value every 4 cycles.  strobe_in is asserted when
42  * there's a new input sample available.  Depending on the overall decimation
43  * rate, strobe_in may be asserted less frequently than once every 4 clocks.
44  * On the output side, we assert strobe_out when output contains a new sample.
45  *
46  * Implementation: Every time strobe_in is asserted we store the new data into
47  * the delay line.  We split the delay line into two components, one for the
48  * even samples, and one for the odd samples.  ram16_odd is the delay line for
49  * the odd samples.  This ram is written on each odd assertion of strobe_in, and
50  * is read on each clock when we're computing the dot product.  ram16_even is
51  * similar, although because it holds the even samples we must be able to read
52  * two samples from different addresses at the same time, while writing the incoming
53  * even samples. Thus it's "triple-ported".
54  */
55
56 module halfband_decim
57   (input clock, input reset, input enable, input strobe_in, output wire strobe_out,
58    input wire [15:0] data_in, output reg [15:0] data_out,output wire [15:0] debugctrl);
59
60    reg [3:0] rd_addr1;
61    reg [3:0] rd_addr2;
62    reg [3:0] phase;
63    reg [3:0] base_addr;
64
65    wire      signed [15:0] mac_out,middle_data, sum, coeff;
66    wire      signed [30:0] product;
67    wire      signed [33:0] sum_even;
68    wire      clear;
69    reg       store_odd;
70    
71    always @(posedge clock)
72      if(reset)
73        store_odd <= #1 1'b0;
74      else
75        if(strobe_in)
76          store_odd <= #1 ~store_odd;
77
78    wire      start = strobe_in & store_odd;
79    always @(posedge clock)
80      if(reset)
81        base_addr <= #1 4'd0;
82      else if(start)
83        base_addr <= #1 base_addr + 4'd1;
84
85    always @(posedge clock)
86      if(reset)
87        phase <= #1 4'd8;
88      else if (start)
89        phase <= #1 4'd0;
90      else if(phase != 4'd8)
91        phase <= #1 phase + 4'd1;
92
93    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;
94    always @(posedge clock)
95      begin
96         start_d1 <= #1 start;
97         start_d2 <= #1 start_d1;
98         start_d3 <= #1 start_d2;
99         start_d4 <= #1 start_d3;
100         start_d5 <= #1 start_d4;
101         start_d6 <= #1 start_d5;
102         start_d7 <= #1 start_d6;
103         start_d8 <= #1 start_d7;
104         start_d9 <= #1 start_d8;
105         start_dA <= #1 start_d9;
106         start_dB <= #1 start_dA;
107         start_dC <= #1 start_dB;
108         start_dD <= #1 start_dC;
109      end // always @ (posedge clock)
110    
111    reg    mult_en, mult_en_pre;
112    always @(posedge clock)
113      begin
114         mult_en_pre <= #1 phase!=8;
115         mult_en <= #1 mult_en_pre;
116      end
117    
118    assign clear = start_d4; // was dC
119    wire   latch_result = start_d4; // was dC
120    assign strobe_out = start_d5; // was dD
121    wire   acc_en;
122    
123    always @*
124      case(phase[2:0])
125        3'd0 : begin rd_addr1 = base_addr + 4'd0; rd_addr2 = base_addr + 4'd15; end
126        3'd1 : begin rd_addr1 = base_addr + 4'd1; rd_addr2 = base_addr + 4'd14; end
127        3'd2 : begin rd_addr1 = base_addr + 4'd2; rd_addr2 = base_addr + 4'd13; end
128        3'd3 : begin rd_addr1 = base_addr + 4'd3; rd_addr2 = base_addr + 4'd12; end
129        3'd4 : begin rd_addr1 = base_addr + 4'd4; rd_addr2 = base_addr + 4'd11; end
130        3'd5 : begin rd_addr1 = base_addr + 4'd5; rd_addr2 = base_addr + 4'd10; end
131        3'd6 : begin rd_addr1 = base_addr + 4'd6; rd_addr2 = base_addr + 4'd9; end
132        3'd7 : begin rd_addr1 = base_addr + 4'd7; rd_addr2 = base_addr + 4'd8; end
133        default: begin rd_addr1 = base_addr + 4'd0; rd_addr2 = base_addr + 4'd15; end
134      endcase // case(phase)
135    
136    coeff_rom coeff_rom (.clock(clock),.addr(phase[2:0]-3'd1),.data(coeff));
137    
138    ram16_2sum ram16_even (.clock(clock),.write(strobe_in & ~store_odd),
139                           .wr_addr(base_addr),.wr_data(data_in),
140                           .rd_addr1(rd_addr1),.rd_addr2(rd_addr2),
141                           .sum(sum));
142
143    ram16 ram16_odd (.clock(clock),.write(strobe_in & store_odd),  // Holds middle items
144                     .wr_addr(base_addr),.wr_data(data_in),
145                     //.rd_addr(base_addr+4'd7),.rd_data(middle_data));
146                     .rd_addr(base_addr+4'd6),.rd_data(middle_data));
147
148    mult mult(.clock(clock),.x(coeff),.y(sum),.product(product),.enable_in(mult_en),.enable_out(acc_en));
149
150    acc acc(.clock(clock),.reset(reset),.enable_in(acc_en),.enable_out(),
151            .clear(clear),.addend(product),.sum(sum_even));
152
153    wire signed [33:0] dout = sum_even + {{4{middle_data[15]}},middle_data,14'b0}; // We already divided product by 2!!!!
154
155    always @(posedge clock)
156      if(reset)
157        data_out <= #1 16'd0;
158      else if(latch_result)
159        data_out <= #1 dout[30:15] + (dout[33]& |dout[14:0]);
160
161    assign  debugctrl = { clock,reset,acc_en,mult_en,clear,latch_result,store_odd,strobe_in,strobe_out,phase};
162    
163 endmodule // halfband_decim