strix/fpga/rtl/ring_osc.v

44 lines
1.5 KiB
Coq
Raw Normal View History

// 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