gary/experiments/timing_generator/contrib/Top.bsv

153 lines
3.4 KiB
Plaintext

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