<> <> <> <<>> DIRECTORY BitOps, Core, CoreClasses, CoreCreate, CoreProperties, DynaBusInterface, FIFOQueue, Ports, ResponseChecker, Rosemary, RosemaryUser; ResponseCheckerImpl: CEDAR PROGRAM IMPORTS CoreClasses, CoreCreate, DynaBusInterface, FIFOQueue, Ports, Rosemary EXPORTS ResponseChecker = BEGIN DGrant, ErrorOut, DataOut, HeaderCycle, Reset, Clock, Vdd, Gnd: NAT _ LAST[NAT]; ROPE: TYPE = Core.ROPE; Port: TYPE = Ports.Port; Quad: TYPE = DynaBusInterface.Quad; Cmd: TYPE = DynaBusInterface.Cmd; dataBits: CARDINAL = 64; qZero: Quad = BitOps.BitQWordZero; State: TYPE = REF StateRec; StateRec: TYPE = RECORD [ queue: FIFOQueue.Queue _ NIL, thisCmd: Cmd, thisResponse: ResponseRec, cycleCount: CARDINAL _ 0, dataIndex: CARDINAL _ 0, grantM, grantS: BOOL, alreadyChecked: BOOL ]; ResponseRec: TYPE = RECORD [header: Quad, data: ARRAY[0..4) OF Quad, doubleError: ARRAY[0..4) OF BOOL]; Create: PUBLIC PROC RETURNS [ct: Core.CellType] = { ct _ CoreClasses.CreateUnspecified[ public: CoreCreate.WireList[LIST["DGrant", "ErrorOut", CoreCreate.Seq["DataOut", dataBits], "HeaderCycle", "Reset", "Clock", "Vdd", "Gnd"], "ResponseChecker", NIL], name: checkerName ]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: checkerName]; [] _ Ports.InitPorts[ct, b, none, "DGrant", "ErrorOut", "HeaderCycle", "Reset", "Clock"]; [] _ Ports.InitPorts[ct, q, none, "DataOut"]; }; Init: Rosemary.InitProc = { <<--PROC [cellType: Core.CellType, p: Ports.Port] RETURNS [stateAny: REF ANY _ NIL]-->> state: State _ IF oldStateAny=NIL THEN NEW[StateRec] ELSE NARROW[oldStateAny]; InitPortIndicies[cellType]; state.queue _ FIFOQueue.Create[]; state.cycleCount _ 0; state.dataIndex _ 0; state.grantM _ FALSE; state.grantS _ FALSE; state.alreadyChecked _ FALSE; stateAny _ state; }; Simple: Rosemary.EvalProc = { <<--PROC [p: Ports.Port, stateAny: REF ANY]-->> state: State _ NARROW[stateAny]; <<--delay DGrant one clock cycle to make it easier to compare with header and data cycles>> IF ~clockEval THEN { SELECT p[Clock].b FROM FALSE => state.grantM _ p[DGrant].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; --DGrant disappeared in middle of packet IF p[HeaderCycle].b AND state.grantS THEN { --begin new packet IF state.cycleCount#0 THEN ERROR; --bogus HeaderCycle in middle of packet state.thisResponse _ NARROW[FIFOQueue.Remove[state.queue], REF ResponseRec]^; state.thisCmd _ DynaBusInterface.ExtractCmd[p[DataOut].q]; state.cycleCount _ IF state.thisCmd=RBRply OR state.thisCmd=CWSRply THEN 5 ELSE 2; state.dataIndex _ 0; IF NOT QuadEqual[p[DataOut].q, state.thisResponse.header] THEN ERROR; --bad header }; IF state.cycleCount#0 AND NOT p[HeaderCycle].b THEN { SELECT state.thisCmd FROM RBRply => { IF state.thisResponse.doubleError[state.dataIndex] THEN {IF NOT p[ErrorOut].b THEN ERROR} ELSE IF NOT QuadEqual[state.thisResponse.data[state.dataIndex], p[DataOut].q] THEN ERROR; }; WBRply, FBRply, WSRply, BIOWRply, DeMapRply, IOWRply, IORRply => { IF p[ErrorOut].b THEN ERROR; IF NOT QuadEqual[state.thisResponse.data[state.dataIndex], p[DataOut].q] THEN ERROR; }; CWSRply => { IF p[ErrorOut].b THEN ERROR; IF NOT QuadEqual[state.thisResponse.data[0], p[DataOut].q] THEN ERROR; }; ENDCASE => ERROR; state.dataIndex _ state.dataIndex+1; }; IF state.cycleCount#0 THEN state.cycleCount _ state.cycleCount-1; }; InitPortIndicies: PROC [ct: Core.CellType] = { [DGrant, ErrorOut, DataOut, HeaderCycle, Reset, Clock, Vdd, Gnd] _ Ports.PortIndexes[ct.public, "DGrant", "ErrorOut", "DataOut", "HeaderCycle", "Reset", "Clock", "Vdd", "Gnd"]; }; ExpectReply: PUBLIC PROC [rcState: REF ANY, header: Quad, data: ARRAY[0..4) OF Quad, doubleError: ARRAY [0..4) OF BOOL _ ALL[FALSE]] ~ { state: State _ NARROW[rcState]; FIFOQueue.Include[state.queue, NEW[ResponseRec _ [header, data, doubleError]]]; }; IsEmpty: PUBLIC PROC [rcState: REF ANY] RETURNS [empty: BOOL] ~ { state: State _ NARROW[rcState]; RETURN[FIFOQueue.IsEmpty[state.queue]]; }; QuadEqual: PROC [q1, q2: Quad] RETURNS [BOOL] ~ { FOR i: INT IN[0..4) DO IF q1[i]#q2[i] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; checkerName: ROPE = Rosemary.Register[roseClassName: "ResponseChecker", init: Init, evalSimple: Simple, scheduleIfClockEval: TRUE]; END.