DIRECTORY BitOps, Core, CoreClasses, CoreCreate, CoreProperties, DynaBusInterface, FIFOQueue, Ports, MapCacheChecker, Rosemary, RosemaryUser; MapCacheCheckerImpl: CEDAR PROGRAM IMPORTS BitOps, CoreClasses, CoreCreate, DynaBusInterface, FIFOQueue, Ports, Rosemary EXPORTS MapCacheChecker = BEGIN OPEN MapCacheChecker; Grant, Clock, Data, HeaderCycle: NAT _ LAST[NAT]; ROPE: TYPE = Core.ROPE; Port: TYPE = Ports.Port; Quad: TYPE = DynaBusInterface.Quad; Cmd: TYPE = DynaBusInterface.Cmd; qZero: Quad = BitOps.BitQWordZero; mapCache: MC; defaultFlags: [0..16)=12; MC: TYPE = REF MCRec; MCRec: TYPE = RECORD [ queue: FIFOQueue.Queue _ NIL, regs: ARRAY Reg OF CARD, table: ARRAY Byte OF Entry ]; Entry: TYPE = RECORD [valid: BOOL _ FALSE, vp, aid, rp, flags: CARD]; Byte: TYPE = [0..256); WriteReg: PUBLIC PROC [reg: Reg, data: CARD] ~ { mapCache.regs[reg] _ data; }; ReadReg: PUBLIC PROC [reg: Reg] RETURNS [data: CARD] ~ { data _ mapCache.regs[reg]; }; WriteEntry: PUBLIC PROC [valid: BOOL, vp, rp: CARD, f: [0..16)] RETURNS [ignored: BOOL _ FALSE] ~ { h: Byte; IF ~InSubset[vp] THEN RETURN[TRUE]; IF mapCache.regs[aidR]=0FFFFH OR InBypass[vp] THEN RETURN[]; h _ H[mapCache.regs[aidR], vp]; mapCache.table[h] _ [valid, vp, mapCache.regs[aidR], rp, f]; -- write in Cache }; ReadEntry: PUBLIC PROC [vp: CARD] RETURNS [ignored, error: BOOL _ FALSE, rp: CARD, f: [0..16)] ~ { [ignored, error, rp, f] _ Map[vp, mapCache.regs[aidR]]; }; Map: PUBLIC PROC [vp, aid: CARD] RETURNS [ignored, error: BOOL _ FALSE, rp: CARD, f: [0..16)] ~ { h: Byte; IF ~InSubset[vp] THEN RETURN[TRUE, FALSE, 0, 0]; SELECT TRUE FROM aid=0FFFFH => RETURN[FALSE, FALSE, vp, defaultFlags]; InBypass[vp] => RETURN[FALSE, FALSE, Translated[vp], defaultFlags]; ENDCASE => { entry: Entry; aid _ IF InShared[vp] THEN 0 ELSE aid; h _ H[aid, vp]; entry _ mapCache.table[h]; IF ~entry.valid OR aid#entry.aid THEN RETURN[FALSE, TRUE, 0, 0]; RETURN[FALSE, FALSE, entry.rp, entry.flags]; }; }; Translated: PROC [vp: CARD] RETURNS [rp: CARD] ~ { RETURN[BitOps.DOR[ BitOps.DAND[mapCache.regs[byB], mapCache.regs[byM]], BitOps.DAND[vp, BitOps.DNOT[mapCache.regs[byM]]]] ]; }; InSubset: PROC [vp: CARD] RETURNS [BOOL] ~ { RETURN[ BitOps.DAND[vp, mapCache.regs[vpM]]= BitOps.DAND[mapCache.regs[vpP], mapCache.regs[vpM]]]; }; InBypass: PROC [vp: CARD] RETURNS [BOOL] ~ { RETURN[ BitOps.DAND[vp, mapCache.regs[byM]]= BitOps.DAND[mapCache.regs[byP], mapCache.regs[byM]]]; }; InShared: PROC [vp: CARD] RETURNS [BOOL] ~ { RETURN[ BitOps.DAND[vp, mapCache.regs[shM]]= BitOps.DAND[mapCache.regs[shP], mapCache.regs[shM]]]; }; H: PROC [aid, vp: CARD] RETURNS [h: Byte] ~ { w: CARD _ BitOps.DXOR[aid, vp]; h _ BitOps.WXOR[BitOps.ECFD[w, 16, 8], BitOps.ECFD[w, 24, 8]]; }; State: TYPE = REF StateRec; StateRec: TYPE = RECORD [ thisCmd: Cmd, thisResponse: ResponseRec, cycleCount: CARDINAL _ 0, grantM, grantS: BOOL, alreadyChecked: BOOL ]; ResponseRec: TYPE = RECORD [header, data: Quad, ignoreData: BOOL _ FALSE]; checkerName: ROPE = Rosemary.Register[roseClassName: "MapCacheChecker", init: Init, evalSimple: Simple, scheduleIfClockEval: TRUE]; Create: PUBLIC PROC RETURNS [ct: Core.CellType] = { ct _ CoreClasses.CreateUnspecified[ name: checkerName, public: CoreCreate.WireList[ name: "MapCacheChecker", wrs: LIST["Grant", CoreCreate.Seq["Data", 64], "HeaderCycle", "Clock"]] ]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: checkerName]; [] _ Ports.InitPorts[ct, b, none, "Grant", "Clock"]; [] _ Ports.InitPorts[ct, l, none, "HeaderCycle"]; [] _ Ports.InitPorts[ct, ls, none, "Data"]; }; Init: Rosemary.InitProc = { state: State _ IF oldStateAny=NIL THEN NEW[StateRec] ELSE NARROW[oldStateAny]; InitPortIndicies[cellType]; mapCache _ NEW[MCRec]; mapCache.queue _ FIFOQueue.Create[]; state.cycleCount _ 0; state.grantM _ FALSE; state.grantS _ FALSE; state.alreadyChecked _ FALSE; stateAny _ state; }; Simple: Rosemary.EvalProc = { state: State _ NARROW[stateAny]; header: BOOL _ p[HeaderCycle].l=H; IF ~clockEval THEN { SELECT p[Clock].b FROM FALSE => state.grantM _ p[Grant].b; TRUE => state.grantS _ state.grantM; ENDCASE => ERROR; }; IF clockEval THEN state.alreadyChecked _ FALSE; IF clockEval OR p[Clock].b OR state.alreadyChecked THEN RETURN ELSE state.alreadyChecked _ TRUE; IF state.cycleCount#0 AND ~state.grantS THEN ERROR; --Grant disappeared in middle of packet IF header AND state.grantS THEN { --begin new packet IF state.cycleCount#0 THEN ERROR; --bogus HeaderCycle in middle of packet state.thisResponse _ NARROW[FIFOQueue.Remove[mapCache.queue], REF ResponseRec]^; state.thisCmd _ DynaBusInterface.ExtractCmd[LSToQ[p[Data].ls]]; state.cycleCount _ 2; SELECT state.thisCmd FROM MapRply, IORRply, IOWRply => { IF NOT QuadEqual[LSToQ[p[Data].ls], state.thisResponse.header] THEN ERROR; }; ENDCASE => ERROR; }; IF state.cycleCount#0 AND NOT header THEN { SELECT state.thisCmd FROM MapRply, IORRply, IOWRply => { IF ~(state.thisResponse.ignoreData OR QuadEqual[state.thisResponse.data, LSToQ[p[Data].ls]]) THEN ERROR; }; ENDCASE => ERROR; }; IF state.cycleCount#0 THEN state.cycleCount _ state.cycleCount-1; }; LSToQ: PROC [ls: Ports.LevelSequence] RETURNS [q: Quad] ~ { q _ IF Ports.HasX[ls] THEN qZero ELSE Ports.LSToQ[ls]; }; InitPortIndicies: PROC [ct: Core.CellType] = { [Grant, Data, HeaderCycle, Clock] _ Ports.PortIndexes[ct.public, "Grant", "Data", "HeaderCycle", "Clock"]; }; ExpectReply: PUBLIC PROC [header, data: Quad, ignoreData: BOOL _ FALSE] ~ { FIFOQueue.Include[mapCache.queue, NEW[ResponseRec _ [header, data, ignoreData]]]; }; IsEmpty: PUBLIC PROC RETURNS [BOOL] ~ { RETURN[FIFOQueue.IsEmpty[mapCache.queue]]; }; QuadEqual: PROC [q1, q2: Quad] RETURNS [BOOL _ TRUE] ~ { FOR i: INT IN[0..4) DO IF q1[i]#q2[i] THEN RETURN[FALSE]; ENDLOOP; }; END. PadRef: TYPE = REF PadRec; PadRec: TYPE = RECORD [enableOut, enableIn, dataOut, dataIn, pad: NAT _ LAST[NAT]]; PadRoseClass: ROPE = RoseClass["Pad", PadInit, PadSimple]; Pad: PUBLIC PROC RETURNS [ct: CellType] = { ct _ Extract["PadAll.sch"]; Ports.InitPorts[ct, l, none, "pad"]; -- bidirectionnal Ports.InitPorts[ct, l, none, "enableOut", "enableIn", "dataIn"]; -- input Ports.InitPorts[ct, l, none, "dataOut"]; -- output tristate }; PadInit: Rosemary.InitProc = { state: PadRef _ IF oldStateAny=NIL THEN NEW[PadRec] ELSE NARROW[oldStateAny]; [state.enableOut, state.enableIn, state.dataOut, state.dataIn, state.pad] _ Ports.PortIndexes[cellType.public, "enableOut", "enableIn", "dataOut", "dataIn", "pad"]; stateAny _ state; }; PadSimple: Rosemary.EvalProc = { state: PadRef _ NARROW[stateAny]; p[pad].d _ none; SELECT p[enableOut].l FROM H => {p[pad].l _ p[dataOut].l; p[pad].d _ drive}; L => p[pad].d _ none; ENDCASE => {p[pad].l _ X; p[pad].d _ drive}; SELECT p[enableIn].l FROM H => {p[dataIn].l _ p[pad].l; p[dataIn].d _ drive}; L => p[dataIn].d _ none; ENDCASE => {p[dataIn].l _ X; p[dataIn].d _ drive}; }; |MapCacheCheckerImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Louis Monier December 22, 1987 11:42:06 am PST --PROC [cellType: Core.CellType, p: Ports.Port] RETURNS [stateAny: REF ANY _ NIL]-- --PROC [p: Ports.Port, stateAny: REF ANY]-- --delay Grant one clock cycle to make it easier to compare with header and data cycles -- bind to roseClass!!! Κ ”˜codešœ™Kšœ Οmœ1™K˜—K˜Kšœžœžœ ˜šœ žœžœ˜Kšœ ˜ Kšœ˜Kšœ žœ˜Kšœž˜Kšœž˜K˜K˜—Kš œ žœžœ"žœžœ˜JK˜šœ žœlžœ˜ƒK˜—šŸœžœžœžœ˜3šœ#˜#Kšœ˜šœ˜Kšœ˜Kšœžœ>˜G—Kšœ˜—KšœE˜EKšœ4˜4Kšœ1˜1Kšœ+˜+Kšœ˜K˜—šŸœ˜KšœS™SKš œžœ ž œ žœžœ ž˜NKšœ˜Kšœ žœ˜Kšœ$˜$Kšœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœ˜Kšœ˜K˜—šŸœ˜Kšœ+™+Kšœžœ ˜ Kšœžœ˜"KšœV™Všžœ žœ˜šžœ ž˜Kšžœ˜#Kšžœ ˜$Kšžœžœ˜—K˜K˜—Kšžœ žœžœ˜/Kš žœ žœ žœžœž œžœ˜`Kš žœžœžœžœ '˜\šžœžœžœ ˜4Kšžœžœžœ '˜IKšœžœ#žœ˜PKšœ?˜?Kšœ˜šžœž˜šœ˜Kšžœžœ9žœžœ˜JK˜—Kšžœžœ˜—K˜—šžœžœžœžœ˜+šžœž˜šœ˜Kšžœ!žœ8žœžœ˜hK˜—Kšžœžœ˜—K˜—Kšžœžœ'˜AKšœ˜—K˜šŸœžœžœ˜;Kšœžœžœžœ˜6K˜—šŸœžœ˜.šœA˜AKšœ)˜)—K˜K˜—š Ÿ œžœžœ"žœžœ˜KJšœ"žœ,˜QK˜K˜—š Ÿœžœžœžœžœ˜'Jšžœ$˜*K˜K˜—š Ÿ œžœžœžœžœ˜8šžœžœžœž˜Kšžœ žœžœžœ˜"Kšžœ˜—K˜K˜—Kšžœ˜K˜Kšœžœžœ˜Kš œžœžœ-žœžœžœ˜SKšŸ œžœ(˜:šŸœžœžœžœ˜+Kšœ˜KšΟb™Kšœ' ˜8KšœA ˜IKšœ+ ˜=Kšœ˜K˜—šŸœ˜Kš œžœ žœžœžœ žœžœ˜MKšœ€˜€Kšœ˜Kšœ˜—šŸ œ˜ Kšœžœ ˜!Kšœ˜šžœž˜Kšœ1˜1Kšœ˜Kšžœ%˜,—šžœž˜Kšœ3˜3Kšœ˜Kšžœ+˜2—Kšœ˜—J˜—…—ά%μ