Attention
This documentation is a work in progress. Expect to see errors and unfinished things.
ccfilt Source File
1`timescale 1ns / 1ns
2// Cascaded Differentiator and post-filter
3// also includes a barrel shifter to adjust scale to compensate
4// for changing decimation intervals
5module ccfilt #(
6 parameter dw=32, // data width of mon_chan output:
7 // should be CIC input data width (18),
8 // plus 2 * log2(max sample period)
9 parameter outw=20, // output data width
10 // comments below assume outw == 20
11 // outw must be 20 if using half-band filter
12 parameter shift_wi=4,
13 parameter shift_base=0,
14 parameter dsr_len = 12, // expected length of strobe pattern
15 parameter use_hb = 1, // compile-time conditional half-band code
16 parameter use_delay = 0 // match pipeline length with use_hb case
17) (
18 input clk,
19 // unprocessed double-integrator output
20 input [dw-1:0] sr_in,
21 input sr_valid,
22
23 // semi-static configuration
24 input [shift_wi-1:0] shift, // controls scaling of result
25
26 // filtered and scaled result, ready for storage
27 output signed [outw-1:0] result,
28 input reset,
29 output strobe
30);
31
32// Two stages of differentiator
33wire valid2;
34wire signed [dw-1:0] d2;
35doublediff #(.dw(dw), .dsr_len(dsr_len)) diff(.clk(clk),
36 .d_in(sr_in), .g_in(sr_valid), .d_out(d2), .g_out(valid2));
37
38// Reduce bit width for entry to half-band filter
39// First get 21 bits, then see below
40reg signed [outw:0] d3=0;
41reg ovf=0;
42`define UNIFORM(x) ((~|(x)) | &(x)) // All 0's or all 1's
43// Lowest supported filter is R=4 (for which we set shift=0), and N=2 always.
44// Input to CIC is 18 bits, so maximum 22 bits come out.
45// Check for overflow is a simulation-only feature to check for bugs.
46
47// Invent some extra bits, just so the case statement is all legal Verilog,
48// even if dw is less than 36.
49// This construction should not result in any actual extra hardware.
50localparam dwmax = outw+16+shift_base;
51wire signed [dwmax:0] d2e = {{dwmax+1-dw{d2[dw-1]}},d2};
52wire [shift_wi:0] full_shift = shift + shift_base;
53wire [dwmax:0] d2es = d2e >>> full_shift;
54always @(posedge clk) begin
55 d3 <= d2es;
56 ovf <= ~ `UNIFORM(d2es[dwmax:outw]);
57end
58reg valid3=0;
59always @(posedge clk) valid3 <= valid2;
60`undef UNIFORM
61
62`ifdef SIMULATE
63reg [3:0] ch_id=0;
64reg signed [dw-1:0] d2_prev;
65wire print_overflow = ovf & valid3;
66always @(posedge clk) begin
67 ch_id <= valid3 ? (ch_id+1) : 0;
68 d2_prev <= d2;
69end
70always @(negedge clk) if (print_overflow) $display("overflow %d %x %x %d %d", shift, d2_prev, d3, ch_id, $time);
71`endif
72
73// Universal definition; note: old and new are msb numbers, not bit widths.
74`define SAT(x,old,new) ((~|x[old:new] | &x[old:new]) ? x[new:0] : {x[old],{new{~x[old]}}})
75
76// Factor of two scaling of output by virtue of the LO table construction.
77// When properly set up, saturation will only occur with pathological LO choices and/or ADC clipping.
78reg signed [outw-1:0] d4=0;
79reg valid4=0;
80always @(posedge clk) begin
81 d4 <= `SAT(d3, outw, outw-1);
82 valid4 <= valid3;
83end
84
85`undef SAT
86
87// Instantiate half-band filter .. or not
88wire [outw-1:0] d5;
89wire valid5;
90reg [4-1:0] delay_v45=0; // seems half_filter take 4 cycles?
91reg [outw*4-1:0] delay_d45=0;
92generate
93if (use_hb) begin: g_use_hb
94 half_filt #(.len(dsr_len))
95 hb(.clk(clk), .ind(d4), .ing(valid4), .outd(d5), .outg(valid5), .reset(reset));
96end
97else if (use_delay) begin: g_use_delay
98 always@(posedge clk) begin
99 delay_v45 <= {delay_v45[4-2:0],valid4};
100 delay_d45 <= {delay_d45[outw*(4-1)-1:0],d4};
101
102 end
103 assign d5 = delay_d45[outw*4-1:outw*(4-1)];
104 assign valid5 = delay_v45[4-1];
105end
106else begin: g_use_short
107 assign d5 = d4;
108 assign valid5 = valid4;
109end
110endgenerate
111
112assign strobe=valid5;
113assign result=d5;
114endmodule