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