Attention
This documentation is a work in progress. Expect to see errors and unfinished things.
half_filt Source File
1`timescale 1ns / 1ns
2// Multiplier-free half-band filter and decimator.
3// See http://recycle.lbl.gov/~ldoolitt/halfband/
4
5// This is an FIR filter
6// https://en.wikipedia.org/wiki/Finite_impulse_response
7// with 7 non-zero taps, categorized as an order-3 half-band filter.
8// The taps are
9// 2 0 -9 0 39 64 39 0 -9 0 2
10
11// The filter has a nominal low-frequency gain of unity. But since
12// the gain peaks at +0.074 dB (at an input frequency of 0.12 of the input
13// sample rate), the output can clip. The module correctly saturates
14// its arithmetic.
15
16// This filter is linear-phase (note the symmetric tap coefficients),
17// with an essential DSP group delay of 5 samples.
18// Additional pipeline delay is added by the implementation; see below.
19
20// The input can consist of a fixed (set by the parameter len at
21// build-time) number of interleaved signal data streams.
22// The half-band filter is applied to each stream independently.
23
24// half_filt() can accept 20-bit data at the full clock rate.
25// The output stream is decimated by two; blocks of len cycles of 20-bit
26// output data are interleaved with len silent cycles. The input data
27// and ing control are pipelined four cycles before getting to the output.
28
29// There are no restrictions on the ing pattern. The len-way
30// interleaving of the input data ignores cycles with ing low.
31
32// Synthesizes to 251 slices at 116 MHz in XC3Sxxx-4 using XST-8.2i
33
34module half_filt(
35 input clk, // Rising edge clock input; all logic is synchronous in this domain
36 input signed [19:0] ind, // Input data
37 input ing, // Active high gate marking input data as valid
38 output signed [19:0] outd, // Output data
39 output outg, // Active high gate marking output data as valid
40 input reset // manually reset counter
41);
42
43parameter len = 4; // number of interleaved data streams
44wire signed [19:0] d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
45
46assign d0 = ind;
47reg_delay #(.dw(20),.len(len)) h0(clk, 1'b0, ing, d0, d1);
48reg_delay #(.dw(20),.len(len)) h1(clk, 1'b0, ing, d1, d2);
49reg_delay #(.dw(20),.len(len)) h2(clk, 1'b0, ing, d2, d3);
50reg_delay #(.dw(20),.len(len)) h3(clk, 1'b0, ing, d3, d4);
51reg_delay #(.dw(20),.len(len)) h4(clk, 1'b0, ing, d4, d5);
52reg_delay #(.dw(20),.len(len)) h5(clk, 1'b0, ing, d5, d6);
53reg_delay #(.dw(20),.len(len)) h6(clk, 1'b0, ing, d6, d7);
54reg_delay #(.dw(20),.len(len)) h7(clk, 1'b0, ing, d7, d8);
55reg_delay #(.dw(20),.len(len)) h8(clk, 1'b0, ing, d8, d9);
56reg_delay #(.dw(20),.len(len)) h9(clk, 1'b0, ing, d9, d10);
57
58reg signed [20:0] s1=0, s2=0, s3=0, s4=0;
59reg sg=0;
60always @(posedge clk) begin
61 if (reset) begin
62 sg <= 0;
63 end else begin
64 sg <= ing;
65 end
66 s1 <= d0 + d10;
67 s2 <= d2 + d8;
68 s3 <= d4 + d6;
69 s4 <= d5 + 0; // {d5[19],d5};
70end
71
72// FIR filter coefficients:
73// 2*(1/32 0 -1/8-1/64 0 1/2+1/8-1/64 1 1/2+1/8-1/64 0 -1/8-1/64 0 1/32)/4
74// see lowp3.m
75
76reg signed [21:0] a1=0, a2=0, a3=0, a4=0;
77reg ag=0;
78always @(posedge clk) begin
79 if (reset) begin
80 ag <= 0;
81 end else begin
82 ag <= sg;
83 end
84`ifdef TRUST_VERILOG_DIVISION
85 a1 <= s1/16 + 0;
86 a2 <= s2/4 + s2/32;
87 a3 <= s3/4 - s3/32;
88 a4 <= s3 + 2*s4;
89`else
90 a1 <= {{5{s1[20]}},s1[20:4]};
91 a2 <= {{3{s2[20]}},s2[20:2]} + {{6{s2[20]}},s2[20:5]};
92 a3 <= {{3{s3[20]}},s3[20:2]} - {{6{s3[20]}},s3[20:5]};
93 a4 <= {{1{s3[20]}},s3[20:0]} + { s4[20:0],1'b0};
94`endif
95end
96
97reg signed [22:0] b1=0, b2=0;
98reg bg=0;
99reg [8:0] samp=0;
100reg show=0;
101always @(posedge clk) begin
102 b1 <= a1 - a2;
103 b2 <= a3 + a4 + 1;
104 if (reset) begin
105 bg <= 0;
106 samp <= 0;
107 show <= 0;
108 end else begin
109 bg <= ag;
110 if (bg) begin
111 samp <= (samp==len-1'b1) ? 0 : samp+1'b1;
112 if (samp==len-1) show <= ~show;
113 end
114 end
115end
116
117wire signed [21:0] c1;
118sat_add #(23,22) finals(clk,b1,b2,c1);
119reg cg=0;
120always @(posedge clk) begin
121 if (reset) cg <= 0;
122 else cg <= bg & show;
123end
124
125assign outd = c1[21:2];
126assign outg = cg;
127
128endmodule