ResponseCheckerImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Gasbarro April 3, 1987 9:43:46 am PST
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.