Here are the 3 procs
PBusDef: PUBLIC PROC [] RETURNS [ct: CellType] ~ {
Here is where the name and the size of public wires must be given
public: Wire ← CoreCreate.WireList[
LIST[
"PMode",
CoreCreate.Seq["PByteSel",4],
CoreCreate.Seq["PCmd",4],
CoreCreate.Seq["PFaultCode",3],
"PFault",
"PReject",
"PhB",
"PhA",
CoreCreate.Seq["PData",32],
"PReschedule",
"PReset",
"CkIn"
]];
This creates a celltype
ct ← CoreClasses.CreateUnspecified[public: public];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: PBusConnexion];
Now the type of each pins
Ports.InitPorts[ct, l, drive,"PMode"];
Ports.InitPorts[ct, ls, drive,"PByteSel"];
Ports.InitPorts[ct, ls, drive,"PCmd"];
Ports.InitPorts[ct, ls, none,"PFaultCode"];
Ports.InitPorts[ct, l, none,"PFault"];
Ports.InitPorts[ct, l, none,"PReject"];
Ports.InitPorts[ct, l, drive,"PhB"];
Ports.InitPorts[ct, l, drive,"PhA"];
Ports.InitPorts[ct, ls, drive,"PData"];
Ports.InitPorts[ct, l, none,"PReschedule"];
Ports.InitPorts[ct, l, none,"PReset"];
Ports.InitPorts[ct, l, none,"CkIn"];
};
PBusInit: PUBLIC Rosemary.InitProc = {
--PROC [cellType: Core.CellType, p: Ports.Port, oldStateAny: REF ANY ← NIL] RETURNS [stateAny: REF ANY ← NIL]--
Init the state
pbusemul: PBusEmulState← IF oldStateAny=NIL THEN NEW[PBusEmulRec]
ELSE NARROW[oldStateAny, PBusEmulState];
Create the pointers on different sequences
pbusemul.PByteSel ← NEW[Ports.LevelSequenceRec[4]];
pbusemul.PCmd ← NEW[Ports.LevelSequenceRec[4]];
pbusemul.PFaultCode ← NEW[Ports.LevelSequenceRec[3]];
pbusemul.PDataIn ← NEW[Ports.LevelSequenceRec[32]];
pbusemul.PDataOut ← NEW[Ports.LevelSequenceRec[32]];
Init the value of the outputs
pbusemul.PMode ← L;
Ports.SetLS[pbusemul.PByteSel, L];
Ports.SetLS[pbusemul.PCmd, L];
Ports.SetLS[pbusemul.PDataIn, L];
Ports.SetLS[pbusemul.PDataOut, L];
pbusemul.PhB ← L;
pbusemul.PhA ← L;
Take the indice of each pins
[pbusemul.PMODE] ← Ports.PortIndexes[cellType.public,"PMode"];
[pbusemul.PBYTESEL] ← Ports.PortIndexes[cellType.public,"PByteSel"];
[pbusemul.PCMD] ← Ports.PortIndexes[cellType.public,"PCmd"];
[pbusemul.PFAULTCODE] ← Ports.PortIndexes[cellType.public,"PFaultCode"];
[pbusemul.PFAULT] ← Ports.PortIndexes[cellType.public,"PFault"];
[pbusemul.PREJECT] ← Ports.PortIndexes[cellType.public,"PReject"];
[pbusemul.PHB] ← Ports.PortIndexes[cellType.public,"PhB"];
[pbusemul.PHA] ← Ports.PortIndexes[cellType.public,"PhA"];
[pbusemul.PDATA] ← Ports.PortIndexes[cellType.public,"PData"];
[pbusemul.PRESCHEDULE] ← Ports.PortIndexes[cellType.public,"PReschedule"];
[pbusemul.PRESET] ← Ports.PortIndexes[cellType.public,"PReset"];
[pbusemul.CKIN] ← Ports.PortIndexes[cellType.public,"CkIn"];
pbusemul.numClockEdges ← 2; --number of clock edges since beginning
pbusemul.cycleCount ← 0; --is used for loops inside procs
pbusemul.prevClock ← L; --is used for detecting clock edges
pbusemul.testProcList ← NIL;
stateAny← pbusemul;
};
PBusEval:
PUBLIC Rosemary.EvalProc = {
--PROC [p: Ports.Port, stateAny: REF ANY, clockEval: BOOL]--
pbusemul: PBusEmulState ← NARROW[stateAny];
Falling edges of PhA, PhB are treated like clocks; rising edges like normal signals.
IF clockEval
AND pbusemul.prevClock=L
AND p[pbusemul.
CKIN].l=H
THEN {
SELECT (pbusemul.numClockEdges+1)
MOD 4
FROM
0 => pbusemul.PhB ← L;
2 => pbusemul.PhA ← L;
ENDCASE;
};
IF ~clockEval
THEN {
On Clock high capture inputs in internal state
IF p[pbusemul.
CKIN].l=H
THEN {
Ports.CopyLS[from: p[pbusemul.PFAULTCODE].ls, to: pbusemul.PFaultCode];
pbusemul.PFault ← p[pbusemul.PFAULT].l;
pbusemul.PReject ← p[pbusemul.PREJECT].l;
Ports.CopyLS[from: p[pbusemul.PDATA].ls, to: pbusemul.PDataIn];
pbusemul.PReschedule ← p[pbusemul.PRESCHEDULE].l;
pbusemul.PReset ← p[pbusemul.PRESET].l;
};
On Clock high to low check the data
IF pbusemul.prevClock=H
AND p[pbusemul.
CKIN].l=L
AND pbusemul.cycle3ForRead
THEN {
PBusEmul.Emul[pbusemul];
pbusemul.cycle3ForRead ← FALSE };
On Clock low to high do the computation
IF pbusemul.prevClock=L
AND p[pbusemul.
CKIN].l=H
THEN {
pbusemul.cycle3ForRead ← pbusemul.cycleCount=3; -- AND pbusemul.PCmd[3]=L;
pbusemul.numClockEdges ← pbusemul.numClockEdges+1;
SELECT pbusemul.numClockEdges
MOD 4
FROM
0 => pbusemul.PhA ← H;
2 => pbusemul.PhB ← H;
ENDCASE;
p[pbusemul.PDATA].d ← none;
IF (pbusemul.PhA=H)
OR (pbusemul.PhB=H
AND pbusemul.PCmd[3]=H)
THEN {
p[pbusemul.PDATA].d ← drive;
};
IF NOT pbusemul.cycle3ForRead THEN PBusEmul.Emul[pbusemul]
};
Advance clock
pbusemul.prevClock ← p[pbusemul.CKIN].l
};
p[pbusemul.PMODE].l ← pbusemul.PMode;
Ports.CopyLS[from: pbusemul.PByteSel, to: p[pbusemul.PBYTESEL].ls];
Ports.CopyLS[from: pbusemul.PCmd, to: p[pbusemul.PCMD].ls];
p[pbusemul.PHB].l ← pbusemul.PhB;
p[pbusemul.PHA].l ← pbusemul.PhA;
IF (pbusemul.PhA=H)
OR (pbusemul.PhB=H
AND pbusemul.PCmd[3]=H)
THEN {
Ports.CopyLS[from: pbusemul.PDataOut, to: p[pbusemul.PDATA].ls];
};
};
PBusConnexion: Core.ROPE = Rosemary.Register[roseClassName: "PBusDef", init: PBusInit, evalSimple: PBusEval, scheduleIfClockEval: TRUE];