43 lines
1.5 KiB
Verilog
43 lines
1.5 KiB
Verilog
// Free-running ring oscillator built from LCELL buffers so synthesis keeps every stage.
|
|
// Three evenly spaced taps are XORed into an "enhanced" output at three times the ring
|
|
// frequency, which triples the chance that a sample lands on a jittery edge.
|
|
module ring_osc #(
|
|
parameter LENGTH = 12 // stages in the ring; exactly one of them inverts
|
|
) (
|
|
input wire enable, // low stops the ring (all stages settle high)
|
|
output wire first_tap,
|
|
output wire enhanced
|
|
);
|
|
|
|
`ifdef SIM
|
|
// Behavioural stand-in: independent taps toggling at random intervals, enough to
|
|
// exercise the synchronous logic downstream. It has no physical meaning.
|
|
reg [2:0] taps = 3'b000;
|
|
always begin
|
|
#(1 + {$random} % 7);
|
|
if (enable) taps[{$random} % 3] = ~taps[{$random} % 3];
|
|
else taps = 3'b111;
|
|
end
|
|
assign first_tap = taps[0];
|
|
assign enhanced = ^taps;
|
|
`else
|
|
// No keep attribute here: each lcell is already one logic cell, and keep on these
|
|
// nets makes Quartus insert a second cell per stage.
|
|
wire [LENGTH-1:0] stage;
|
|
|
|
lcell inverting_stage (.in(~(stage[LENGTH-1] & enable)), .out(stage[0]));
|
|
|
|
genvar i;
|
|
generate
|
|
for (i = 1; i < LENGTH; i = i + 1) begin : delay_stage
|
|
lcell buffer (.in(stage[i-1]), .out(stage[i]));
|
|
end
|
|
endgenerate
|
|
|
|
(* keep *) wire tap_xor = stage[0] ^ stage[LENGTH/3] ^ stage[(2*LENGTH)/3];
|
|
|
|
assign first_tap = stage[0];
|
|
assign enhanced = tap_xor;
|
|
`endif
|
|
|
|
endmodule
|