XilinxFlipFlop:
PUBLIC
PROC
RETURNS [ct: Core.CellType] = {
name: Rope.ROPE = "DFF";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← CoreClasses.CreateUnspecified[CoreOps.CreateWire[
LIST[
CoreOps.CreateWire[name: "D"],
CoreOps.CreateWire[name: "Q"],
CoreOps.CreateWire[name: "CK"],
CoreOps.CreateWire[name: "ar"],
CoreOps.CreateWire[name: "ap"]]], name];
SimulateGate[ct, XilinxFlipFlopRoseClass];
Ports.InitPorts[ct, l, none, "D", "CK", "ar", "ap"]; Ports.InitPorts[ct, l, drive, "Q"];
CacheStore[name, ct];
};
XilinxFFRec:
TYPE =
RECORD [
ffD, ffQ, ffClock, ffR, ffP: NAT ← LAST[NAT],
master, slave: Ports.Level];
XilinxFFInit: Rosemary.InitProc = {
state: XilinxFFRef ← IF oldStateAny=NIL THEN NEW[XilinxFFRec] ELSE NARROW[oldStateAny];
state.master ← state.slave ← L;
[state.ffD, state.ffQ, state.ffClock, state.ffR, state.ffP] ← Ports.PortIndexes[cellType.public, "D", "Q", "CK", "ar", "ap"];
p[state.ffQ].l ← L;
stateAny ← state;
};
XilinxFFSimple: Rosemary.EvalProc = {
state: XilinxFFRef ← NARROW[stateAny];
SELECT
TRUE
FROM
p[state.ffR].l=L
AND p[state.ffP].l=L =>
IF ~clockEval
THEN
SELECT p[state.ffClock].l
FROM
-- normal mode of operation
L => state.master ← p[state.ffD].l; -- load master bit
H => state.slave ← state.master; -- load slave bit
ENDCASE => state.slave ← state.master ← X; -- random clock
p[state.ffR].l=H => state.slave ← state.master ← L; -- asynchronous reset
p[state.ffP].l=H => state.slave ← state.master ← H; -- asynchronous preset
ENDCASE => state.slave ← state.master ← X; -- mushy reset
p[state.ffQ].l ← state.slave;
};
FlipFlopRoseClass: Rope.ROPE = RoseClass["FlipFlop", FFInit, FFSimple, TRUE];
FlipFlop:
PUBLIC
PROC [metaStableResistant:
BOOL ←
FALSE]
RETURNS [ct: Core.CellType] = {
name: Rope.ROPE = IF metaStableResistant THEN "FlipFlopMR" ELSE "FlipFlop";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← IF metaStableResistant THEN SCBlock[Extract["ffMR.sch"]] ELSE MakeSC["ff"];
SimulateGate[ct, FlipFlopRoseClass];
Ports.InitPorts[ct, l, none, "D", "CK"]; Ports.InitPorts[ct, l, drive, "Q", "NQ"];
CacheStore[name, ct];
};
FFRef: TYPE = REF FFRec;
FFRec:
TYPE =
RECORD [
ffD, ffQ, ffNQ, ffClock: NAT ← LAST[NAT],
master, slave: Ports.Level];
FFInit: Rosemary.InitProc = {
state: FFRef ← IF oldStateAny=NIL THEN NEW[FFRec] ELSE NARROW[oldStateAny];
state.master ← state.slave ← L;
[state.ffD, state.ffQ, state.ffNQ, state.ffClock] ← Ports.PortIndexes[cellType.public, "D", "Q", "NQ", "CK"];
p[state.ffQ].l ← p[state.ffNQ].l ← L;
stateAny ← state;
};
FFSimple: Rosemary.EvalProc = {
-- of course state.master is the inverse of the physical master level in the current CMosB implementation, but nobody has access to the real value, so let's keep things simple...
state: FFRef ← NARROW[stateAny];
IF ~clockEval
THEN
SELECT p[state.ffClock].l
FROM
L => state.master ← p[state.ffD].l; -- load master bit
H => state.slave ← state.master; -- load slave bit
ENDCASE => state.slave ← state.master ← X; -- random clock
p[state.ffQ].l ← state.slave; p[state.ffNQ].l ← Ports.NotL[state.slave];
};