// This code is derived from the video sync generator at // https://github.com/B-Lang-org/bsc-contrib/blob/main/Libraries/FPGA/Misc/Video.bsv, // simplified down to serve as an experiment/comparison of synthesis // efficiency with the sibling directory that has a more imperative // construction (and also worse, it tursn out). package Top; import Counter::*; import StmtFSM::*; typedef struct { Integer active; Integer fporch; Integer sync; Integer bporch; } SyncDescriptor; SyncDescriptor horizontal = SyncDescriptor{ active: 640, fporch: 16, sync: 96, bporch: 48 }; SyncDescriptor vertical = SyncDescriptor{ active: 480, fporch: 10, sync: 2, bporch: 33 }; interface SyncGenerator; method Action tick(); method Bool preedge(); method Bool out_n(); method Bool out(); method Bool active(); endinterface module mkSyncGenerator#(SyncDescriptor info)(SyncGenerator); let maxActive = fromInteger(info.active - 1); let maxFPorch = fromInteger(info.fporch - 1); let maxSync = fromInteger(info.sync - 1); let maxBPorch = fromInteger(info.bporch - 1); ///////////////////// /// Design Elements ///////////////////// Counter#(16) rCounter <- mkCounter(0); PulseWire pwTick <- mkPulseWire; PulseWire pwPreSyncEdge <- mkPulseWire; Reg#(Bool) rSyncOut <- mkReg(True); Reg#(Bool) rActive <- mkReg(False); ///////////////////// /// Rules ///////////////////// Stmt machine = seq while(True) seq // Front Porch while(rCounter.value < maxFPorch) action rCounter.up; endaction action rCounter.clear; pwPreSyncEdge.send; rSyncOut <= False; rActive <= False; endaction // Sync Pulse while(rCounter.value < maxSync) action rCounter.up; endaction action rCounter.clear; rSyncOut <= True; rActive <= False; endaction // Back Porch while(rCounter.value < maxBPorch) action rCounter.up; endaction action rCounter.clear; rSyncOut <= True; rActive <= True; endaction // Active while(rCounter.value < maxActive) action rCounter.up; endaction action rCounter.clear; rSyncOut <= True; rActive <= False; endaction endseq endseq; FSM fsmSyncGen <- mkFSMWithPred(machine, pwTick); rule start_sync_generator(fsmSyncGen.done); fsmSyncGen.start; endrule method Action tick = pwTick.send; method Bool preedge = pwPreSyncEdge; method Bool out_n = rSyncOut; method Bool out = !rSyncOut; method Bool active = rActive; endmodule: mkSyncGenerator interface ITop; (* always_ready *) method Bool paint(); (* always_ready *) method Bool hsync(); (* always_ready *) method Bool vsync(); endinterface (* synthesize *) module mkTop (ITop); let horiz <- mkSyncGenerator(horizontal); let vert <- mkSyncGenerator(vertical); (* no_implicit_conditions, fire_when_enabled *) rule advance_horizontal; horiz.tick; endrule (* no_implicit_conditions, fire_when_enabled *) rule advance_vertical (horiz.preedge); vert.tick; endrule method Bool paint = horiz.active && vert.active; method Bool hsync = horiz.out; method Bool vsync = vert.out; endmodule endpackage