Skip to content

Commit

Permalink
Merge branch 'master' into swap_mult_gitid
Browse files Browse the repository at this point in the history
  • Loading branch information
ldoolitt committed Dec 11, 2024
2 parents 87334df + 2f50eb6 commit 6d4c934
Showing 4 changed files with 83 additions and 59 deletions.
7 changes: 5 additions & 2 deletions dsp/freq_count.gtkw
Original file line number Diff line number Diff line change
@@ -3,24 +3,27 @@
[pos] -1 -1
*-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
[treeopen] freq_count_tb.
[sst_width] 210
[sst_width] 213
[signals_width] 174
[sst_expanded] 1
[sst_vpaned_height] 154
@28
freq_count_tb.clk
freq_count_tb.f_in
@22
freq_count_tb.diff_stream[15:0]
@28
freq_count_tb.diff_stream_strobe
@24
freq_count_tb.frequency[27:0]
@28
freq_count_tb.mut.freq_strobe
@22
freq_count_tb.mut.work.gray1[3:0]
freq_count_tb.mut.work.gray3[3:0]
@24
freq_count_tb.mut.work.diff1[3:0]
freq_count_tb.mut.work.refcnt[5:0]
freq_count_tb.mut.refcnt[5:0]
freq_count_tb.mut.work.accum[27:0]
[pattern_trace] 1
[pattern_trace] 0
59 changes: 49 additions & 10 deletions dsp/freq_count.v
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
`timescale 1ns / 1ns

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

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

initial begin
frequency=initv;
diff_stream=0;
diff_stream_strobe=0;
glitch_catcher=0;
end

// Reference counter
// may or may not be synchronized between instances
reg [refcnt_width-1:0] refcnt=0;
reg ref_strobe=0, stream_strobe=0;
always @(posedge sysclk) begin
{ref_strobe, refcnt} <= refcnt + 1;
stream_strobe <= refcnt[1:0] == 0;
end

wire [3:0] xcount; // per-sysclk count of f_in edges
wire [freq_width-1:0] frequency_w;
freq_gcount #(
.glitch_thresh(glitch_thresh),
.refcnt_width(refcnt_width),
.gw(4),
.freq_width(freq_width),
.initv(initv)
) work (
.sysclk(sysclk), .f_in(f_in),
.g_in(1'b1), // this is the whole point!
.frequency(frequency), .freq_strobe(freq_strobe),
.diff_stream(diff_stream), .diff_stream_strobe(diff_stream_strobe),
.glitch_catcher(glitch_catcher)
.ref_strobe(ref_strobe),
.frequency(frequency_w), .freq_strobe(freq_strobe),
.xcount(xcount)
);

// Nobody except some ancient USB debugging ever used this.
// It's harmless; if you don't attach to the diff_stream,
// diff_stream_strobe, or glitch_catcher ports, it will all
// just disappear in synthesis.
//
// Make xcount available to stream to host at 24 MByte/sec, which was
// especially interesting when reprogramming a AD9512 clock divider
// on a LLRF4 board.
// It might also be possible to histogram xcount.
reg [15:0] stream=0;
always @(posedge sysclk) begin
if (xcount > glitch_thresh) glitch_catcher <= ~glitch_catcher;
stream <= {stream[11:0], xcount}; // assumes freq_gcount gw=4
end

// Latch/pipeline one more time to perimeter of this module
always @(posedge sysclk) begin
diff_stream <= stream;
diff_stream_strobe <= stream_strobe;
frequency <= frequency_w;
end

endmodule
3 changes: 2 additions & 1 deletion dsp/freq_count_tb.v
Original file line number Diff line number Diff line change
@@ -16,7 +16,8 @@ initial begin
end
// Simulated accumulation interval is 20*64 = 1280 ns
// Should catch an average of 1280/6 = 213.33 f_in edges in that time
if (frequency>212 && frequency < 215) begin
$display("frequency = %d", frequency);
if (frequency > 212 && frequency < 215) begin
$display("PASS");
$finish(0);
end else begin
73 changes: 27 additions & 46 deletions dsp/freq_gcount.v
Original file line number Diff line number Diff line change
@@ -1,40 +1,39 @@
// Copied from the old freq_count, but with new g_in (gate) input added
// Read the new name as frequency (gated) count.
//
// This version delegates reference counter function to the caller,
// to allow synchronization and resource-sharing across multiple
// freq_gcount instances. Note that if you want a _lot_ of frequency
// counter instances, maybe you should look into multi_counter.v.
//
// It no longer includes the obscure glitch diagnostics. Those are
// still available in freq_count, just in case anyone wants them.

`timescale 1ns / 1ns

module freq_gcount #(
// Default configuration useful for input frequencies < 96 MHz
parameter glitch_thresh=2,
parameter refcnt_width=24,
parameter gw=4, // Gray code counter width
parameter freq_width=28,
parameter initv=0
parameter initv=0 // output value for frequency at start-up
) (
// input clocks
input sysclk, // timespec 8.0 ns
input f_in, // unknown input
input g_in, // gate (f_in clock domain)

// control input in f_in domain
input g_in, // gate (wire to 1 to get a simple frequency counter)

// control input in sysclk domain
input ref_strobe, // typically one pulse every 2^24 sysclk cycles

// outputs in sysclk domain
output reg [freq_width-1:0] frequency,
output [freq_width-1:0] frequency,
output freq_strobe,
output reg [15:0] diff_stream,
output reg diff_stream_strobe,
// glitch_catcher can be routed to a physical pin to trigger
// a 'scope; see glitch_thresh parameter above
output reg glitch_catcher
output [gw-1:0] xcount // cycle-by-cycle gated count of f_in
);

initial begin
frequency=initv;
diff_stream=0;
diff_stream_strobe=0;
glitch_catcher=0;
end

// four-bit Gray code counter on the input signal
// four-bit (nominal) Gray code counter on the input signal
// https://en.wikipedia.org/wiki/Gray_code
localparam gw=4;
reg [gw-1:0] gray1=0;

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

// verilator lint_save
// verilator lint_off UNOPTFLAT
wire [gw-1:0] bin3 = gray3 ^ {1'b0, bin3[gw-1:1]}; // convert Gray to binary
wire [gw-1:0] bin3 = gray3 ^ {1'b0, bin3[gw-1:1]}; // Gray to binary
// verilator lint_restore

reg [gw-1:0] bin4=0, bin5=0, diff1=0;
always @(posedge sysclk) begin
bin4 <= bin3;
bin5 <= bin4;
diff1 <= bin4-bin5;
if (diff1 > glitch_thresh) glitch_catcher <= ~glitch_catcher;
end

// It might also be possible to histogram diff1,
// but for now just accumulate it to get a traditional frequency counter.
// Also make it available to stream to host at 24 MByte/sec, might be
// especially interesting when reprogramming a clock divider like
// the AD9512 on a LLRF4 board.
// In that case a 48 MHz sysclk / 2^24 = 2.861 Hz update
// Accumulate diff1 to get a traditional frequency counter
reg [freq_width-1:0] accum=0, result=initv;
reg [refcnt_width-1:0] refcnt=0;
reg ref_carry=0;
reg [15:0] stream=0;
reg stream_strobe=0;
always @(posedge sysclk) begin
{ref_carry, refcnt} <= refcnt + 1;
if (ref_carry) result <= accum;
accum <= (ref_carry ? 28'b0 : accum) + diff1;
stream <= {stream[11:0],diff1};
stream_strobe <= refcnt[1:0] == 0;
end

// Latch/pipeline one more time to perimeter of this module
// to make routing easier
reg freq_strobe_r=0;
always @(posedge sysclk) begin
frequency <= result;
freq_strobe_r <= ref_carry;
diff_stream <= stream;
diff_stream_strobe <= stream_strobe;
accum <= (ref_strobe ? {freq_width{1'b0}} : accum) + diff1;
if (ref_strobe) result <= accum;
freq_strobe_r <= ref_strobe; // high when new data is valid
end

assign frequency = result; // Don't over-register
assign freq_strobe = freq_strobe_r;
assign xcount = diff1;

endmodule

0 comments on commit 6d4c934

Please sign in to comment.