Skip to content

Commit 2f50eb6

Browse files
committed
Merge branch 'freq_count_rejigger' into 'master'
rejigger boundary between freq_count and freq_gcount See merge request hdl-libraries/bedrock!214
2 parents 484dfbd + f4977bf commit 2f50eb6

File tree

4 files changed

+83
-59
lines changed

4 files changed

+83
-59
lines changed

dsp/freq_count.gtkw

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,27 @@
33
[pos] -1 -1
44
*-6.533834 3870 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
55
[treeopen] freq_count_tb.
6-
[sst_width] 210
6+
[sst_width] 213
77
[signals_width] 174
88
[sst_expanded] 1
99
[sst_vpaned_height] 154
1010
@28
11+
freq_count_tb.clk
1112
freq_count_tb.f_in
1213
@22
1314
freq_count_tb.diff_stream[15:0]
1415
@28
1516
freq_count_tb.diff_stream_strobe
1617
@24
1718
freq_count_tb.frequency[27:0]
19+
@28
20+
freq_count_tb.mut.freq_strobe
1821
@22
1922
freq_count_tb.mut.work.gray1[3:0]
2023
freq_count_tb.mut.work.gray3[3:0]
2124
@24
2225
freq_count_tb.mut.work.diff1[3:0]
23-
freq_count_tb.mut.work.refcnt[5:0]
26+
freq_count_tb.mut.refcnt[5:0]
2427
freq_count_tb.mut.work.accum[27:0]
2528
[pattern_trace] 1
2629
[pattern_trace] 0

dsp/freq_count.v

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
`timescale 1ns / 1ns
55

66
module freq_count #(
7-
// Default configuration useful for input frequencies < 96 MHz
7+
// Default configuration useful for input frequencies < 2*sysclk
88
parameter glitch_thresh=2,
99
parameter refcnt_width=24,
1010
parameter freq_width=28,
@@ -15,26 +15,65 @@ module freq_count #(
1515
input f_in, // unknown input
1616

1717
// outputs in sysclk domain
18-
output [freq_width-1:0] frequency,
18+
output reg [freq_width-1:0] frequency,
1919
output freq_strobe,
20-
output [15:0] diff_stream,
21-
output diff_stream_strobe,
20+
output reg [15:0] diff_stream, // stream of last 4 4-bit counts of f_in
21+
output reg diff_stream_strobe, // strobe at f_sysclk/4
2222
// glitch_catcher can be routed to a physical pin to trigger
2323
// a 'scope; see glitch_thresh parameter above
24-
output glitch_catcher
24+
output reg glitch_catcher
2525
);
2626

27+
initial begin
28+
frequency=initv;
29+
diff_stream=0;
30+
diff_stream_strobe=0;
31+
glitch_catcher=0;
32+
end
33+
34+
// Reference counter
35+
// may or may not be synchronized between instances
36+
reg [refcnt_width-1:0] refcnt=0;
37+
reg ref_strobe=0, stream_strobe=0;
38+
always @(posedge sysclk) begin
39+
{ref_strobe, refcnt} <= refcnt + 1;
40+
stream_strobe <= refcnt[1:0] == 0;
41+
end
42+
43+
wire [3:0] xcount; // per-sysclk count of f_in edges
44+
wire [freq_width-1:0] frequency_w;
2745
freq_gcount #(
28-
.glitch_thresh(glitch_thresh),
29-
.refcnt_width(refcnt_width),
46+
.gw(4),
3047
.freq_width(freq_width),
3148
.initv(initv)
3249
) work (
3350
.sysclk(sysclk), .f_in(f_in),
3451
.g_in(1'b1), // this is the whole point!
35-
.frequency(frequency), .freq_strobe(freq_strobe),
36-
.diff_stream(diff_stream), .diff_stream_strobe(diff_stream_strobe),
37-
.glitch_catcher(glitch_catcher)
52+
.ref_strobe(ref_strobe),
53+
.frequency(frequency_w), .freq_strobe(freq_strobe),
54+
.xcount(xcount)
3855
);
3956

57+
// Nobody except some ancient USB debugging ever used this.
58+
// It's harmless; if you don't attach to the diff_stream,
59+
// diff_stream_strobe, or glitch_catcher ports, it will all
60+
// just disappear in synthesis.
61+
//
62+
// Make xcount available to stream to host at 24 MByte/sec, which was
63+
// especially interesting when reprogramming a AD9512 clock divider
64+
// on a LLRF4 board.
65+
// It might also be possible to histogram xcount.
66+
reg [15:0] stream=0;
67+
always @(posedge sysclk) begin
68+
if (xcount > glitch_thresh) glitch_catcher <= ~glitch_catcher;
69+
stream <= {stream[11:0], xcount}; // assumes freq_gcount gw=4
70+
end
71+
72+
// Latch/pipeline one more time to perimeter of this module
73+
always @(posedge sysclk) begin
74+
diff_stream <= stream;
75+
diff_stream_strobe <= stream_strobe;
76+
frequency <= frequency_w;
77+
end
78+
4079
endmodule

dsp/freq_count_tb.v

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ initial begin
1616
end
1717
// Simulated accumulation interval is 20*64 = 1280 ns
1818
// Should catch an average of 1280/6 = 213.33 f_in edges in that time
19-
if (frequency>212 && frequency < 215) begin
19+
$display("frequency = %d", frequency);
20+
if (frequency > 212 && frequency < 215) begin
2021
$display("PASS");
2122
$finish(0);
2223
end else begin

dsp/freq_gcount.v

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,39 @@
11
// Copied from the old freq_count, but with new g_in (gate) input added
22
// 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.
311

412
`timescale 1ns / 1ns
513

614
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
1016
parameter freq_width=28,
11-
parameter initv=0
17+
parameter initv=0 // output value for frequency at start-up
1218
) (
1319
// input clocks
1420
input sysclk, // timespec 8.0 ns
1521
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
1728

1829
// outputs in sysclk domain
19-
output reg [freq_width-1:0] frequency,
30+
output [freq_width-1:0] frequency,
2031
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
2633
);
2734

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
3636
// https://en.wikipedia.org/wiki/Gray_code
37-
localparam gw=4;
3837
reg [gw-1:0] gray1=0;
3938

4039
// The following three expressions compute the next Gray code based on
@@ -57,45 +56,27 @@ end
5756

5857
// verilator lint_save
5958
// 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
6160
// verilator lint_restore
6261

6362
reg [gw-1:0] bin4=0, bin5=0, diff1=0;
6463
always @(posedge sysclk) begin
6564
bin4 <= bin3;
6665
bin5 <= bin4;
6766
diff1 <= bin4-bin5;
68-
if (diff1 > glitch_thresh) glitch_catcher <= ~glitch_catcher;
6967
end
7068

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
7770
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
9271
reg freq_strobe_r=0;
9372
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
9876
end
77+
78+
assign frequency = result; // Don't over-register
9979
assign freq_strobe = freq_strobe_r;
80+
assign xcount = diff1;
10081

10182
endmodule

0 commit comments

Comments
 (0)