gary/lib/Strobe.bsv

58 lines
2.1 KiB
Plaintext

package Strobe;
import Real::*;
import Printf::*;
// A Strobe provides a synchronization signal to other modules, when
// an event happens at a cadence other than the module clock.
(* always_ready *)
interface Strobe;
method Bool _read();
// reset resets the strobe cycle, starting with a strobe on the
// cycle following reset.
method Action reset();
endinterface
// mkStrobe returns a Strobe that triggers at the given
// target_frequency, assuming mkStrobe is being clocked at the given
// higher clock_frequency.
module mkStrobe(Integer clock_frequency, Integer target_frequency, Strobe ifc);
if (target_frequency > clock_frequency)
error("mkStrobe target_frequency must be less than clock_frequency");
let strobe_every = round(fromInteger(clock_frequency)/fromInteger(target_frequency));
// Because we're using integer counters to divide frequencies,
// unless the clock and target frequencies divide cleanly we'll end
// up with a small amount of error.
//
// Strobes like this tend to be used for relatively short
// operations before some other synchronization event happens
// (e.g. sending one byte on UART), so we can allow a small amount
// of frequency error. For now, the target frequency error is fixed
// at <=0.1%.
Real actual_frequency = fromInteger(clock_frequency)/fromInteger(strobe_every);
Real frequency_error_pct = abs(fromInteger(target_frequency)-actual_frequency) / fromInteger(target_frequency) * 100;
if (frequency_error_pct > 0.1)
error(sprintf("mkStrobe actual frequency is %0f, %0f%% error vs. requested %0d. Your clock_frequency and target_frequency are probably too near each other.", actual_frequency, frequency_error_pct, target_frequency));
Reg#(UInt#(32)) cnt[2] <- mkCReg(2, 0);
(* no_implicit_conditions, fire_when_enabled *)
rule increment;
if (cnt[0] == fromInteger(strobe_every-1))
cnt[0] <= 0;
else
cnt[0] <= cnt[0]+1;
endrule
method Bool _read();
return cnt[0] == 0;
endmethod
method Action reset();
cnt[1] <= 0;
endmethod
endmodule
endpackage