<> <> <> <<>> 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; queue: FIFOQueue.Queue _ NIL; thisCmd: Cmd; thisResponse: ResponseRec; cycleCount: CARDINAL _ 0; dataIndex: CARDINAL _ 0; prevClock: BOOL _ FALSE; 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]; InitPortIndicies[ct]; [] _ 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]-->> queue _ FIFOQueue.Create[]; cycleCount _ 0; dataIndex _ 0; prevClock _ FALSE; }; Simple: Rosemary.EvalProc = { <<--PROC [p: Ports.Port, stateAny: REF ANY]-->> IF prevClock=p[Clock].b THEN RETURN; --edge sensitive prevClock _ p[Clock].b; IF NOT p[Clock].b THEN RETURN; --filter falling edge IF cycleCount#0 AND ~p[DGrant].b THEN ERROR; --DGrant disappeared in middle of packet IF p[HeaderCycle].b AND p[DGrant].b THEN { --begin new packet IF cycleCount#0 THEN ERROR; --bogus HeaderCycle in middle of packet thisResponse _ NARROW[FIFOQueue.Remove[queue], REF ResponseRec]^; thisCmd _ DynaBusInterface.ExtractCmd[p[DataOut].q]; cycleCount _ IF thisCmd=RBRply OR thisCmd=CWSRply THEN 5 ELSE 2; dataIndex _ 0; IF NOT QuadEqual[p[DataOut].q, thisResponse.header] THEN ERROR; --bad header }; IF cycleCount#0 AND NOT p[HeaderCycle].b THEN { SELECT thisCmd FROM RBRply => { IF thisResponse.doubleError[dataIndex] THEN {IF NOT p[ErrorOut].b THEN ERROR} ELSE IF NOT QuadEqual[thisResponse.data[dataIndex], p[DataOut].q] THEN ERROR; }; WBRply, FBRply, WSRply, BIOWRply, DeMapRply, IOWRply, IORRply => { IF p[ErrorOut].b THEN ERROR; IF NOT QuadEqual[thisResponse.data[dataIndex], p[DataOut].q] THEN ERROR; }; CWSRply => { IF p[ErrorOut].b THEN ERROR; IF NOT QuadEqual[thisResponse.data[0], p[DataOut].q] THEN ERROR; }; ENDCASE => ERROR; dataIndex _ dataIndex+1; }; IF cycleCount#0 THEN cycleCount _ 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 [header: Quad, data: ARRAY[0..4) OF Quad, doubleError: ARRAY [0..4) OF BOOL _ ALL[FALSE]] ~ { FIFOQueue.Include[queue, NEW[ResponseRec _ [header, data, doubleError]]]; }; IsEmpty: PUBLIC PROC RETURNS [empty: BOOL] ~ { RETURN[FIFOQueue.IsEmpty[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]; END.