153 lines
3.4 KiB
Plaintext
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
|