|
1 | 1 | // Copied from the old freq_count, but with new g_in (gate) input added
|
2 | 2 | // Read the new name as frequency (gated) count.
|
| 3 | +// |
| 4 | +// This version delegates reference counter function to the caller, |
| 5 | +// to allow synchronization and resource-sharing across multiple |
| 6 | +// freq_gcount instances. Note that if you want a _lot_ of frequency |
| 7 | +// counter instances, maybe you should look into multi_counter.v. |
| 8 | +// |
| 9 | +// It no longer includes the obscure glitch diagnostics. Those are |
| 10 | +// still available in freq_count, just in case anyone wants them. |
3 | 11 |
|
4 | 12 | `timescale 1ns / 1ns
|
5 | 13 |
|
6 | 14 | module freq_gcount #(
|
7 |
| - // Default configuration useful for input frequencies < 96 MHz |
8 |
| - parameter glitch_thresh=2, |
9 |
| - parameter refcnt_width=24, |
| 15 | + parameter gw=4, // Gray code counter width |
10 | 16 | parameter freq_width=28,
|
11 |
| - parameter initv=0 |
| 17 | + parameter initv=0 // output value for frequency at start-up |
12 | 18 | ) (
|
13 | 19 | // input clocks
|
14 | 20 | input sysclk, // timespec 8.0 ns
|
15 | 21 | input f_in, // unknown input
|
16 |
| - input g_in, // gate (f_in clock domain) |
| 22 | + |
| 23 | + // control input in f_in domain |
| 24 | + input g_in, // gate (wire to 1 to get a simple frequency counter) |
| 25 | + |
| 26 | + // control input in sysclk domain |
| 27 | + input ref_strobe, // typically one pulse every 2^24 sysclk cycles |
17 | 28 |
|
18 | 29 | // outputs in sysclk domain
|
19 |
| - output reg [freq_width-1:0] frequency, |
| 30 | + output [freq_width-1:0] frequency, |
20 | 31 | output freq_strobe,
|
21 |
| - output reg [15:0] diff_stream, |
22 |
| - output reg diff_stream_strobe, |
23 |
| - // glitch_catcher can be routed to a physical pin to trigger |
24 |
| - // a 'scope; see glitch_thresh parameter above |
25 |
| - output reg glitch_catcher |
| 32 | + output [gw-1:0] xcount // cycle-by-cycle gated count of f_in |
26 | 33 | );
|
27 | 34 |
|
28 |
| -initial begin |
29 |
| - frequency=initv; |
30 |
| - diff_stream=0; |
31 |
| - diff_stream_strobe=0; |
32 |
| - glitch_catcher=0; |
33 |
| -end |
34 |
| - |
35 |
| -// four-bit Gray code counter on the input signal |
| 35 | +// four-bit (nominal) Gray code counter on the input signal |
36 | 36 | // https://en.wikipedia.org/wiki/Gray_code
|
37 |
| -localparam gw=4; |
38 | 37 | reg [gw-1:0] gray1=0;
|
39 | 38 |
|
40 | 39 | // The following three expressions compute the next Gray code based on
|
|
57 | 56 |
|
58 | 57 | // verilator lint_save
|
59 | 58 | // verilator lint_off UNOPTFLAT
|
60 |
| -wire [gw-1:0] bin3 = gray3 ^ {1'b0, bin3[gw-1:1]}; // convert Gray to binary |
| 59 | +wire [gw-1:0] bin3 = gray3 ^ {1'b0, bin3[gw-1:1]}; // Gray to binary |
61 | 60 | // verilator lint_restore
|
62 | 61 |
|
63 | 62 | reg [gw-1:0] bin4=0, bin5=0, diff1=0;
|
64 | 63 | always @(posedge sysclk) begin
|
65 | 64 | bin4 <= bin3;
|
66 | 65 | bin5 <= bin4;
|
67 | 66 | diff1 <= bin4-bin5;
|
68 |
| - if (diff1 > glitch_thresh) glitch_catcher <= ~glitch_catcher; |
69 | 67 | end
|
70 | 68 |
|
71 |
| -// It might also be possible to histogram diff1, |
72 |
| -// but for now just accumulate it to get a traditional frequency counter. |
73 |
| -// Also make it available to stream to host at 24 MByte/sec, might be |
74 |
| -// especially interesting when reprogramming a clock divider like |
75 |
| -// the AD9512 on a LLRF4 board. |
76 |
| -// In that case a 48 MHz sysclk / 2^24 = 2.861 Hz update |
| 69 | +// Accumulate diff1 to get a traditional frequency counter |
77 | 70 | reg [freq_width-1:0] accum=0, result=initv;
|
78 |
| -reg [refcnt_width-1:0] refcnt=0; |
79 |
| -reg ref_carry=0; |
80 |
| -reg [15:0] stream=0; |
81 |
| -reg stream_strobe=0; |
82 |
| -always @(posedge sysclk) begin |
83 |
| - {ref_carry, refcnt} <= refcnt + 1; |
84 |
| - if (ref_carry) result <= accum; |
85 |
| - accum <= (ref_carry ? 28'b0 : accum) + diff1; |
86 |
| - stream <= {stream[11:0],diff1}; |
87 |
| - stream_strobe <= refcnt[1:0] == 0; |
88 |
| -end |
89 |
| - |
90 |
| -// Latch/pipeline one more time to perimeter of this module |
91 |
| -// to make routing easier |
92 | 71 | reg freq_strobe_r=0;
|
93 | 72 | always @(posedge sysclk) begin
|
94 |
| - frequency <= result; |
95 |
| - freq_strobe_r <= ref_carry; |
96 |
| - diff_stream <= stream; |
97 |
| - diff_stream_strobe <= stream_strobe; |
| 73 | + accum <= (ref_strobe ? {freq_width{1'b0}} : accum) + diff1; |
| 74 | + if (ref_strobe) result <= accum; |
| 75 | + freq_strobe_r <= ref_strobe; // high when new data is valid |
98 | 76 | end
|
| 77 | + |
| 78 | +assign frequency = result; // Don't over-register |
99 | 79 | assign freq_strobe = freq_strobe_r;
|
| 80 | +assign xcount = diff1; |
100 | 81 |
|
101 | 82 | endmodule
|
0 commit comments