TestMC.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Gasbarro October 12, 1988 10:31:41 am PDT
DIRECTORY
Basics, BitOps, CD, Core, CoreFlat, DRam, DynaBusInterface, IO, MCUtils, MTSVector, Ports, Random, Rope, Rosemary, RosemaryUser, ResponseChecker, TerminalIO;
TestMC: CEDAR PROGRAM
IMPORTS Basics, BitOps, CoreFlat, DRam, DynaBusInterface, IO, MCUtils, MTSVector, Ports, Random, Rosemary, RosemaryUser, ResponseChecker, TerminalIO
~ BEGIN
nSStopIn, DReqTP, DGrantTP, SharedIn, OwnerIn, HeaderCycleIn, Clock, DataIn, DBus, TestIn, Vdd, Gnd: NAT;
dSerialOut: NAT ← 0;
dSerialIn: NAT ← 1;
nDReset: NAT ← 2;
nDFreeze: NAT ← 3;
dExecute: NAT ← 4;
dAddress: NAT ← 5;
dShiftCK: NAT ← 6;
ROPE: TYPE = Core.ROPE;
Port: TYPE = Ports.Port;
Quad: TYPE = DynaBusInterface.Quad;
Cmd: TYPE = DynaBusInterface.Cmd;
ModeError: TYPE = DynaBusInterface.ModeError;
Shared: TYPE = DynaBusInterface.Shared;
DeviceID: TYPE = DynaBusInterface.DeviceID;
Address: TYPE = DynaBusInterface.Address;
qZero: Quad = BitOps.BitQWordZero;
REProc: TYPE = RosemaryUser.TestEvalProc;
--PROC [memory: BOOL ← TRUE, clockEval: BOOL ← FALSE, checkPorts: BOOL ← TRUE]--
TProc: TYPE = PROC [h: Handle, Eval: REProc];
ownerDelay: CARDINAL = 7;
SHIFT: PROC [value: WORD, count: INTEGER] RETURNS [WORD] = Basics.BITSHIFT;
BITAND: Basics.BitOp = Basics.BITAND;
BITNOT: PROC [WORD] RETURNS [WORD] = Basics.BITNOT;
Log2: PROC [n: INT] RETURNS [INT] = BitOps.Log2;
dBusPrefix: NAT = 20h;
dBusPrefixBits: NAT = 13;
dBusRegAddBits: NAT = 3;
dBusWidth: NAT = 9;
dBusRegAdd: TYPE = [0..8);
arbiterTimeout: CARDINAL ← 200;
ownerDelayBuf: ARRAY [0..ownerDelay] OF RECORD [owner, shared: BOOL];
cmdCount: INT ← 0;
seed: INT ← 1234;
ramdomOps: INT ← 100;
cutSet : LIST OF ROPELIST["Logic", "LogicMacro", "DPMacro", "FSM"];
logOn: BOOLTRUE;
CallIOWrite: TProc ~ {IOWrite0[h, Eval, 7, TRUE, TRUE, 0, 28, 28, 28, 22, 30]};
CallWB: TProc ~ {WriteBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]]};
CallRB: TProc ~ {ReadBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]]};
CallRBSh: TProc ~ {ReadBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0], FALSE, TRUE]};
CallRBOwn: TProc ~ {ReadBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0], TRUE, FALSE]};
CallRBOwnSh: TProc ~ {ReadBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0], TRUE, TRUE]};
CallFB: TProc ~ {FlushBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]]};
CallWS: TProc ~ {WriteSingleRqst[h, Eval, [0,0,0,0], [0,0,0,0Ah]]};
CallWSSh: TProc ~ {WriteSingleRqst[h, Eval, [0,0,0,0], [0,0,0,0Ah], TRUE]};
CallCWS: TProc ~ {CondWriteSingleRqst[h, Eval, [0,0,0,0], [0,0,0,0Ah]]};
CallCWSSh: TProc ~ {CondWriteSingleRqst[h, Eval, [0,0,0,0], [0,0,0,0Ah], TRUE]};
CallIOR: TProc ~ {IORRqst[h, Eval, [0,0,30h, 0], 0]};
CallBIOW: TProc ~ {BIOWRqst[h, Eval, [0,0,0,0], [0,0,0,0Bh]]};
CallDeMap: TProc ~ {DeMapRqst[h, Eval, [0,0,0,0], [0,0,0,0Ch]]};
opProcs: INT = 13;
op: ARRAY [0..opProcs) OF TProc ← [CallIOWrite, CallWB, CallRB, CallRBSh, CallRBOwn, CallRBOwnSh, CallFB, CallWS, CallWSSh, CallCWS, CallCWSSh, CallBIOW, CallDeMap];
Handle: TYPE = REF HandleRec;
HandleRec: TYPE = RECORD[
capture: MTSVector.Capture ← NIL,
rootCT: Core.CellType ← NIL,
captureVectors: BOOLFALSE,
port: Port ← NIL,
rcState: REF ANY --state record of the response checker
];
MCTest: RosemaryUser.TestProc = {
DoSimpleTest: TProc ~ {
InitPortIndicies[cellType];
h.rcState ← GetState[h, "/ResponseChecker"];
cmdCount ← 0;
Reset[h, Eval];
ReadID[h, Eval];
CircularAccessTest[h, Eval];
CmdTest[h, Eval];
BankTest[h, Eval];
OwnerTest[h, Eval];
AddressTest[h, Eval];
SingleErrorTest[h, Eval];
DoubleErrorTest[h, Eval];
SingleErrorTestExtended[h, Eval];
CrossProdTest[h, Eval];
RandomTest[h, Eval, ramdomOps];
FlushPipe[h, Eval];
};
h: Handle ← NEW[HandleRec];
h.rootCT ← cellType;
h.port ← p;
h.capture ← MTSVector.CreateCapture[h.rootCT];
h.captureVectors ← TRUE;
DoSimpleTest[h, Eval];
MTSVector.CloseCapture[h.capture];
};
ReadID: TProc ~ {
ENABLE Rosemary.Stop => IF reason = $BoolWireHasX THEN RESUME;
DBusRegRead[h, Eval, 0, [0, 0, 0, 5180h], 16]; --header=5, type=6, version=0
};
Reset: TProc ~ {
ENABLE Rosemary.Stop => IF reason = $BoolWireHasX THEN RESUME;
p: Port ← h.port;
TerminalIO.PutRope["***Reset***\n"];
p[DBus].bs[nDReset] ← FALSE;
p[DBus].ds[dSerialIn] ← drive;
p[DBus].ds[nDReset] ← drive;
p[DBus].ds[nDFreeze] ← drive;
p[DBus].ds[dExecute] ← drive;
p[DBus].ds[dAddress] ← drive;
p[DBus].ds[dShiftCK] ← drive;
p[TestIn].b ← FALSE;
p[TestIn].d ← drive;
p[nSStopIn].b ← TRUE;
p[nSStopIn].d ← drive;
p[DBus].bs[dShiftCK] ← FALSE;
p[dShiftCK].d ← drive;
Cycle[h, Eval, 1];
DBusRegWrite[h, Eval, 1, 0, 10];
p[SharedIn].b ← FALSE;
p[SharedIn].d ← drive;
p[OwnerIn].b ← FALSE;
p[OwnerIn].d ← drive;
p[HeaderCycleIn].b ← FALSE;
p[HeaderCycleIn].d ← drive;
p[DataIn].q ← qZero;
p[DataIn].d ← drive;
p[DReqTP].c ← 0; -- no request
p[DReqTP].d ← drive;
Cycle[h, Eval, 7];
p[nSStopIn].b ← FALSE;
Cycle[h, Eval, 5];
p[DBus].bs[nDReset] ← TRUE;
Cycle[h, Eval, 5];
p[nSStopIn].b ← TRUE;
Cycle[h, Eval, 5];
p[DGrantTP].d ← expect;
p[DGrantTP].b ← FALSE;
IOWrite0[h, Eval, 7, TRUE, TRUE, 0, 28, 28, 28, 22, 30];
IOWrite1[h, Eval, 1, 10];
IOWrite2[h, Eval, 1, 10];
FlushPipe[h, Eval];
WriteBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
WriteBlockRqst[h, Eval, [0,0,0,0], [0,0,0,0], [1,1,1,1], [2,2,2,2], [3,3,3,3]];
FlushPipe[h, Eval];
};
CircularAccessTest: TProc ~ {
Checks that the four data cycles of a block are cyclically permuted such that the cycle containing the addressed word always appears on the bus first.
TerminalIO.PutRope["***Circular Access Test***\n"];
WriteBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
ReadBlockRqst[h, Eval, [0,0,0,2], [2,2,2,2], [1,1,1,1], [0,0,0,0], [3,3,3,3]];
ReadBlockRqst[h, Eval, [0,0,0,4], [1,1,1,1], [0,0,0,0], [3,3,3,3], [2,2,2,2]];
ReadBlockRqst[h, Eval, [0,0,0,6], [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1]];
ReadBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
};
BankTest: TProc ~ {
Sets up a dual bank configuration and checks that the controller only responds to the commands which it is responsible for.
TerminalIO.PutRope["***Bank Test***\n"];
IOWrite1[h, Eval, 2, 10, 1]; --two banks, one megabit drams, bank add=1,
IOWrite2[h, Eval, 2, 10, 1];
FlushPipe[h, Eval];
WriteSingleRqst[h, Eval, [0,0,0,0], [0,0,0,0Ah], FALSE, TRUE];
WriteSingleRqst[h, Eval, [0,0,0,8], [0,0,0,0Ah], FALSE, FALSE];
CondWriteSingleRqst[h, Eval, [0,0,0,0], [0,0,0,0Ah], FALSE, TRUE];
CondWriteSingleRqst[h, Eval, [0,0,0,8], [0,0,0,0Ah], FALSE, FALSE];
BIOWRqst[h, Eval, [0,0,0,0], [0,0,0,0Bh], TRUE];
BIOWRqst[h, Eval, [0,0,0,8], [0,0,0,0Bh], FALSE];
DeMapRqst[h, Eval, [0,0,0,0], [0,0,0,0Ch], TRUE];
DeMapRqst[h, Eval, [0,0,0,8], [0,0,0,0Ch], FALSE];
IOWrite1[h, Eval, 1, 10]; --single bank, one megabit drams
IOWrite2[h, Eval, 1, 10];
Cycle[h, Eval, 10];
};
AddressTest: TProc ~ {
Cycles a single bit through the address field writing a unique data word for each bit position. Then reads back the data. Checks for holes in the address space.
quad: Quad;
TerminalIO.PutRope["***Address Test***\n"];
IOWrite1[h, Eval, 1, 10]; --single bank, one megabit drams
IOWrite2[h, Eval, 1, 10];
Cycle[h, Eval, 10];
WriteBlockRqst[h, Eval, [0,0,0,00h], [0,0,0,00h], [0,0,0,00h], [0,0,0,00h], [0,0,0,00h]];
--Ignore the low order bit: it signifies the 32-bit address
--Don't test the next two low order bits: they signify the nibble rotatation address
--Test the next 18 bits
FOR i: NAT DECREASING IN [43..60] DO
quad ← BitOps.BitQWordZero;
quad ← BitOps.IBIQ[TRUE, quad, i];
WriteBlockRqst[h, Eval, quad, quad, quad, quad, quad];
ENDLOOP;
ReadBlockRqst[h, Eval, [0,0,0,00h], [0,0,0,00h], [0,0,0,00h], [0,0,0,00h], [0,0,0,00h]];
FOR i: NAT DECREASING IN [43..60] DO
quad ← BitOps.BitQWordZero;
quad ← BitOps.IBIQ[TRUE, quad, i];
ReadBlockRqst[h, Eval, quad, quad, quad, quad, quad];
ENDLOOP;
};
GetState: PROC [h: Handle, rope: Rope.ROPE] RETURNS [REF] ~ {
display: RosemaryUser.RoseDisplay ← RosemaryUser.RoseDisplayFor[h.rootCT];
RETURN[Rosemary.GetState[display.simulation, NEW[CoreFlat.FlatCellTypeRec ← CoreFlat.ParseCellTypePath[display.cellType, rope, NIL]]]];
};
SingleErrorTest: TProc ~ {
Writes a single word in memory, introduces a single error in that word, then reads it back, checking to see if word is corrected. Also checks IO and DBus error and status registers.
lowBitsState: REF ← GetState[h,"/Ram/Bits63to71"];
TerminalIO.PutRope["***Single Error Test***\n"];
IOWrite3[h, Eval]; --clear error status
WriteBlockRqst[h, Eval, [0,0,0,0f0h], [9,9,9,9], [8,8,8,8], [7,7,7,7], [6,6,6,6]];
WriteBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
FlushPipe[h, Eval];
DRam.SingleBitError[lowBitsState, 03Ch, 8];
ReadBlockRqst[h, Eval, [0,0,0,0f0h], [9,9,9,9], [8,8,8,8], [7,7,7,7], [6,6,6,6]];
ReadBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
FlushPipe[h, Eval];
IORRqst[h, Eval, [0, 0, 30h, 0], 0f0h];
IORRqst[h, Eval, [0, 0, 30h, 1], 2 + SHIFT[62,5]]; --single bit error, bit 62
ReadBlockRqst[h, Eval, [0,0,0,0f0h], [9,9,9,9], [8,8,8,8], [7,7,7,7], [6,6,6,6]];
FlushPipe[h, Eval];
IORRqst[h, Eval, [0, 0, 30h, 0], 0f0h];
IORRqst[h, Eval, [0, 0, 30h, 1], 3 + SHIFT[62,5]]; --single bit error, mult. mem errors, bit 62
FlushPipe[h, Eval];
-- syndrome is XOR[62], error reg is 3 (One Bit, Mult. Mem Err), add is 0f0h
DBusRegRead[h, Eval, 2, [0, SHIFT[62,5] + 3, 0, 0f0h], 44];
};
DoubleErrorTest: TProc ~ {
Writes a single word in memory, introduces a double error in that word, then reads it back, checking to see if ErrorOut is asserted. Also checks IO and DBus error and status registers.
lowBitsState: REF ← GetState[h,"/Ram/Bits63to71"];
TerminalIO.PutRope["***Double Error Test***\n"];
IOWrite3[h, Eval]; --clear error status
WriteBlockRqst[h, Eval, [0,0,0,0f0h], [9,9,9,9], [8,8,8,8], [7,7,7,7], [6,6,6,6]];
WriteBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
FlushPipe[h, Eval];
DRam.DoubleBitError[lowBitsState, 03Ch, 6, 8];
ReadBlockRqst[h, Eval, [0,0,0,0f0h], [9,9,9,9], [8,8,8,8], [7,7,7,7], [6,6,6,6], FALSE, FALSE, [TRUE, FALSE, FALSE, FALSE]];
ReadBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
FlushPipe[h, Eval];
IORRqst[h, Eval, [0, 0, 30h, 0], 0f0h];
IORRqst[h, Eval, [0, 0, 30h, 1], 8 + SHIFT[Basics.BITXOR[62, 66], 5]]; --two bit error, bits 62, 66
ReadBlockRqst[h, Eval, [0,0,0,0f0h], [9,9,9,9], [8,8,8,8], [7,7,7,7], [6,6,6,6], FALSE, FALSE, [TRUE, FALSE, FALSE, FALSE]];
FlushPipe[h, Eval];
IORRqst[h, Eval, [0, 0, 30h, 0], 0f0h];
IORRqst[h, Eval, [0, 0, 30h, 1], 9 + SHIFT[Basics.BITXOR[62, 66], 5]]; --two bit error, mult. mem errors, bits 62, 66
FlushPipe[h, Eval];
-- syndrome is XOR[62, 66], error reg is 9 (Two Bit, Mult. Mem Err), add is 0f0h
DBusRegRead[h, Eval, 2, [0, SHIFT[Basics.BITXOR[62, 66], 5] + 9, 0, 0f0h], 44];
};
wordSize: NAT = 72;
SingleErrorTestExtended: TProc ~ {
Checks the functionality of the generator and corrector logic. Writes 72 unique words in memory, causing a single error in a different bit position of each word (including the check bits), then reads back the corrected data and checks for errors.
ramState: ARRAY [0..8) OF REF;
TerminalIO.PutRope["***Single Error Test Extended***\n"];
ramState[0] ← GetState[h, "/Ram/Bits63to71"];
ramState[1] ← GetState[h, "/Ram/Bits54to62"];
ramState[2] ← GetState[h, "/Ram/Bits45to53"];
ramState[3] ← GetState[h, "/Ram/Bits36to44"];
ramState[4] ← GetState[h, "/Ram/Bits27to35"];
ramState[5] ← GetState[h, "/Ram/Bits18to26"];
ramState[6] ← GetState[h, "/Ram/Bits9to17"];
ramState[7] ← GetState[h, "/Ram/Bits0to8"];
FOR i: NAT ← 0, i+4 WHILE i<wordSize DO
WriteBlockRqst[h, Eval,
[0,0,0,0100h+(i*2)], [i,i,i,i], [i+1,i+1,i+1,i+1], [i+2,i+2,i+2,i+2], [i+3,i+3,i+3,i+3]];
ENDLOOP;
FlushPipe[h, Eval];
Cycle[h, Eval, 5];
FOR i: NAT IN [0..wordSize) DO
DRam.SingleBitError[
state: ramState[i/9],
-- low nibble bit + base add + high nibble bit + address increment
a: (i MOD 2 * 400h) + 040h + (IF i MOD 4 >1 THEN 1 ELSE 0) + (i/4)*2,
d: 8-(i MOD 9)
];
ENDLOOP;
FOR i: NAT ← 0, i+4 WHILE i<wordSize DO
ReadBlockRqst[h, Eval,
[0,0,0,0100h+(i*2)], [i,i,i,i], [i+1,i+1,i+1,i+1], [i+2,i+2,i+2,i+2], [i+3,i+3,i+3,i+3]];
ENDLOOP;
};
RandomTest: PROC [h: Handle, Eval: REProc, count: INTLAST[INT]] ~ {
Generates a sequence of random command operations.
rs: Random.RandomStream ← Random.Create[opProcs, seed];
TerminalIO.PutRope["***Random Test***\n"];
WriteBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
FOR i: INT IN [0..count) DO
op[Random.NextInt[rs]][h, Eval];
ENDLOOP;
FlushPipe[h, Eval];
};
CrossProdTest: TProc ~ {
Generates a sequence of commands such that every command is followed at least once by every other command.
TerminalIO.PutRope["***Cross Product Test***\n"];
WriteBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
FOR i: INT IN [0..opProcs) DO
FOR j: INT IN [0..opProcs) DO
op[i][h, Eval];
op[j][h, Eval];
ENDLOOP;
ENDLOOP;
FlushPipe[h, Eval];
};
OwnerTest: TProc ~ {
Checks that shared is returned properly and that Owner causes a RBRqst to abort its reply.
TerminalIO.PutRope["***Owner Test***\n"];
WriteBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
ReadBlockRqst[h, Eval, [0,0,0,0], qZero, qZero, qZero, qZero, TRUE, FALSE];
WriteSingleRqst[h, Eval, [0,0,0,0], [0,0,0,0Ah], TRUE];
CondWriteSingleRqst[h, Eval, [0,0,0,0], [0,0,0,0Ah], TRUE];
ReadBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0], FALSE, TRUE];
};
CmdTest: TProc ~ {
A simple test which executes each command operation once.
TerminalIO.PutRope["***Command Test***\n"];
IOWrite0[h, Eval, 7, TRUE, TRUE, 0, 28, 28, 28, 22, 30];
IOWrite1[h, Eval, 1, 10];
IOWrite2[h, Eval, 1, 10];
WriteBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
ReadBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
FlushPipe[h, Eval];
FlushBlockRqst[h, Eval, [0,0,0,0], [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0]];
WriteSingleRqst[h, Eval, [0,0,0,0], [0,0,0,0Ah]];
CondWriteSingleRqst[h, Eval, [0,0,0,0], [0,0,0,0Ah]];
IORRqst[h, Eval, [0,0,30h,0], 0]; --data read is address of previous cmd
BIOWRqst[h, Eval, [0,0,0,0], [0,0,0,0Bh]];
DeMapRqst[h, Eval, [0,0,0,0], [0,0,0,0Ch]];
};
TestModeTest: TProc ~ {
Puts the device is Test Mode. Checks that DataIn is a copy of DataOut.
p[TestIn].b ← TRUE;
p[DataIn].d ← inspect;
p[DataOut].d ← drive;
p[DataOut].q ← [3,3,3,3], [2,2,2,2], [1,1,1,1], [0,0,0,0];
Cycle[h, Eval, 1];
IF p[DataIn].q # p[DataOut].q THEN ERROR;
p[DataOut].q ← [0,0,0,0], [1,1,1,1], [2,2,2,2], [3,3,3,3];
Cycle[h, Eval, 1];
IF p[DataIn].q # p[DataOut].q THEN ERROR;
p[TestIn].b ← FALSE;
p[DataOut].d ← expect;
p[DataIn].d ← drive;
Cycle[h, Eval, 1];
};
ReadBlockRqst: PROC [h: Handle, Eval: REProc, add: Address, data0, data1, data2, data3: Quad, owner, shared: BOOLFALSE, doubleError: ARRAY [0..4) OF BOOLALL[FALSE], noReply: BOOLFALSE] ~ {
p: Port ← h.port;
AcquireBus[h, Eval];
TerminalIO.PutRope[IO.PutFR["%g) RBRqst, owner: %g, shared: %g\n", IO.int[cmdCount], IO.bool[owner], IO.bool[shared]]];
p[DataIn].q ← MakeHeader[cmd: RBRqst, add: add];
p[HeaderCycleIn].b ← TRUE;
ownerDelayBuf[ownerDelay] ← [owner, shared];
Cycle[h, Eval, 1];
p[HeaderCycleIn].b ← FALSE;
FinalCycle[h, Eval];
IF ~owner AND ~noReply THEN ResponseChecker.ExpectReply[h.rcState, MakeHeader[cmd: RBRply, add: add, sh: shared], [data0, data1, data2, data3], doubleError];
};
WriteBlockRqst: PROC [h: Handle, Eval: REProc, add: Address, data0, data1, data2, data3: Quad, noReply: BOOLFALSE] ~ {
WBorFBRqst[h, Eval, WBRqst, add, data0, data1, data2, data3, noReply];
};
FlushBlockRqst: PROC [h: Handle, Eval: REProc, add: Address, data0, data1, data2, data3: Quad, noReply: BOOLFALSE] ~ {
WBorFBRqst[h, Eval, FBRqst, add, data0, data1, data2, data3, noReply];
};
WBorFBRqst: PROC [h: Handle, Eval: REProc, cmd: Cmd, add: Address, data0, data1, data2, data3: Quad, noReply: BOOLFALSE] ~ {
reqHeader: Quad ← MakeHeader[cmd: cmd, add: add];
p: Port ← h.port;
AcquireBus[h, Eval, 5];
TerminalIO.PutRope[IO.PutFR["%g) %g\n", IO.int[cmdCount], IO.rope[IF cmd=WBRqst THEN "WBRqst" ELSE "FBRqst"]]];
p[DataIn].q ← reqHeader;
p[HeaderCycleIn].b ← TRUE;
Cycle[h, Eval, 1];
p[HeaderCycleIn].b ← FALSE;
p[DataIn].q ← data0;
Cycle[h, Eval, 1];
p[DataIn].q ← data1;
Cycle[h, Eval, 1];
p[DataIn].q ← data2;
Cycle[h, Eval, 1];
p[DataIn].q ← data3;
FinalCycle[h, Eval];
p[DataIn].q ← qZero;
IF ~noReply THEN ResponseChecker.ExpectReply[h.rcState, MakeHeader[cmd: SUCC[cmd], add: add], [reqHeader, qZero, qZero, qZero]];
};
WriteSingleRqst: PROC [h: Handle, Eval: REProc, add: Address, data0: Quad, shared: BOOLFALSE, noReply: BOOLFALSE] ~ {
p: Port ← h.port;
AcquireBus[h, Eval];
TerminalIO.PutRope[IO.PutFR["%g) WSRqst, shared: %g\n", IO.int[cmdCount], IO.bool[shared]]];
p[DataIn].q ← MakeHeader[cmd: WSRqst, add: add];
p[HeaderCycleIn].b ← TRUE;
ownerDelayBuf[ownerDelay] ← [FALSE, shared];
Cycle[h, Eval, 1];
p[DataIn].q ← data0;
p[HeaderCycleIn].b ← FALSE;
FinalCycle[h, Eval];
IF ~noReply THEN ResponseChecker.ExpectReply[h.rcState, MakeHeader[cmd: WSRply, add: add, sh: shared], [data0, qZero, qZero, qZero]];
};
CondWriteSingleRqst: PROC [h: Handle, Eval: REProc, add: Address, data0: Quad, shared: BOOLFALSE, noReply: BOOLFALSE] ~ {
p: Port ← h.port;
AcquireBus[h, Eval];
TerminalIO.PutRope[IO.PutFR["%g) CWSRqst, shared: %g\n", IO.int[cmdCount], IO.bool[shared]]];
p[DataIn].q ← MakeHeader[cmd: CWSRqst, add: add];
p[HeaderCycleIn].b ← TRUE;
ownerDelayBuf[ownerDelay] ← [FALSE, shared];
Cycle[h, Eval, 1];
p[DataIn].q ← data0;
p[HeaderCycleIn].b ← FALSE;
FinalCycle[h, Eval];
IF ~noReply THEN ResponseChecker.ExpectReply[h.rcState, MakeHeader[cmd: CWSRply, add: add, sh: shared], [data0, data0, data0, data0]];
};
IORRqst: PROC [h: Handle, Eval: REProc, add: Address, data: LONG CARDINAL] ~ {
p: Port ← h.port;
AcquireBus[h, Eval];
TerminalIO.PutRope[IO.PutFR["%g) IORRqst\n", IO.int[cmdCount]]];
p[DataIn].q ← MakeHeader[cmd: IORRqst, add: add];
p[HeaderCycleIn].b ← TRUE;
Cycle[h, Eval, 1];
p[HeaderCycleIn].b ← FALSE;
FinalCycle[h, Eval];
ResponseChecker.ExpectReply[h.rcState, MakeHeader[cmd: IORRply, add: add], [[0, 0, Basics.HighHalf[data], Basics.LowHalf[data]], qZero, qZero, qZero]];
};
IOWrite0: PROC [h: Handle, Eval: REProc, ownerFifoDelay: [0..8), enbCorr: BOOL, enbOpReflect: BOOLTRUE, selRefCk: [0..4), gntDelay, pchgDelay, refDelay, wrDelay, rdDelay: [0..32)] ~ {
data: LONG CARDINAL ← MCUtils.ComposeIOWrite0[ownerFifoDelay, enbCorr, enbOpReflect, selRefCk, gntDelay, pchgDelay, refDelay, wrDelay, rdDelay];
address: Quad ← [0,0,30h,0];
p: Port ← h.port;
reqHeader: Quad ← MakeHeader[cmd: IOWRqst, add: address, mode: FALSE];
AcquireBus[h, Eval];
TerminalIO.PutRope[IO.PutFR["%g) IOW0Rqst\n", IO.int[cmdCount]]];
p[DataIn].q ← reqHeader;
p[HeaderCycleIn].b ← TRUE;
Cycle[h, Eval, 1];
p[HeaderCycleIn].b ← FALSE;
p[DataIn].q ← [0, 0, Basics.HighHalf[data], Basics.LowHalf[data]];
FinalCycle[h, Eval];
p[DataIn].q ← qZero;
ResponseChecker.ExpectReply[h.rcState, MakeHeader[cmd: IOWRply, add: address, mode: FALSE], [reqHeader, qZero, qZero, qZero]];
};
IOWrite1: PROC [h: Handle, Eval: REProc, banks: [1..16], ramAddWires: [9..14], bankAdd: [0..16) ← 0, pageAdd: CARDINAL ← 0] ~ {
data: LONG CARDINAL ← MCUtils.ComposeIOWrite1[banks, ramAddWires, bankAdd, pageAdd];
address: Quad ← [0,0,30h,1];
p: Port ← h.port;
reqHeader: Quad ← MakeHeader[cmd: IOWRqst, add: address, mode: FALSE];
AcquireBus[h, Eval];
TerminalIO.PutRope[IO.PutFR["%g) IOW1Rqst\n", IO.int[cmdCount]]];
p[DataIn].q ← reqHeader;
p[HeaderCycleIn].b ← TRUE;
Cycle[h, Eval, 1];
p[HeaderCycleIn].b ← FALSE;
p[DataIn].q ← [0, 0, Basics.HighHalf[data], Basics.LowHalf[data]];
FinalCycle[h, Eval];
p[DataIn].q ← qZero;
ResponseChecker.ExpectReply[h.rcState, MakeHeader[cmd: IOWRply, add: address, mode: FALSE], [reqHeader, qZero, qZero, qZero]];
};
IOWrite2: PROC [h: Handle, Eval: REProc, banks: [1..16], ramAddWires: [9..14], bankAdd: [0..16) ← 0] ~ {
data: LONG CARDINAL ← MCUtils.ComposeIOWrite2[banks, ramAddWires, bankAdd];
address: Quad ← [0,0,30h,2];
p: Port ← h.port;
reqHeader: Quad ← MakeHeader[cmd: IOWRqst, add: address, mode: FALSE];
AcquireBus[h, Eval];
TerminalIO.PutRope[IO.PutFR["%g) IOW2Rqst\n", IO.int[cmdCount]]];
p[DataIn].q ← reqHeader;
p[HeaderCycleIn].b ← TRUE;
Cycle[h, Eval, 1];
p[HeaderCycleIn].b ← FALSE;
p[DataIn].q ← [0, 0, Basics.HighHalf[data], Basics.LowHalf[data]];
FinalCycle[h, Eval];
p[DataIn].q ← qZero;
ResponseChecker.ExpectReply[h.rcState, MakeHeader[cmd: IOWRply, add: address, mode: FALSE], [reqHeader, qZero, qZero, qZero]];
};
IOWrite3: TProc ~ {
p: Port ← h.port;
address: Quad ← [0,0,30h,3];
reqHeader: Quad ← MakeHeader[cmd: IOWRqst, add: address, mode: FALSE];
AcquireBus[h, Eval];
TerminalIO.PutRope[IO.PutFR["%g) IOW3Rqst\n", IO.int[cmdCount]]];
p[DataIn].q ← reqHeader;
p[HeaderCycleIn].b ← TRUE;
Cycle[h, Eval, 1];
p[HeaderCycleIn].b ← FALSE;
p[DataIn].q ← qZero;
FinalCycle[h, Eval];
p[DataIn].q ← qZero;
ResponseChecker.ExpectReply[h.rcState, MakeHeader[cmd: IOWRply, add: address, mode: FALSE], [reqHeader, qZero, qZero, qZero]];
};
BIOWRqst: PROC [h: Handle, Eval: REProc, add: Address, data0: Quad, noReply: BOOLFALSE] ~ {
p: Port ← h.port;
AcquireBus[h, Eval];
TerminalIO.PutRope[IO.PutFR["%g) BIOWRqst\n", IO.int[cmdCount]]];
p[DataIn].q ← MakeHeader[cmd: BIOWRqst, add: add];
p[HeaderCycleIn].b ← TRUE;
Cycle[h, Eval, 1];
p[DataIn].q ← data0;
p[HeaderCycleIn].b ← FALSE;
FinalCycle[h, Eval];
IF ~noReply THEN ResponseChecker.ExpectReply[h.rcState, MakeHeader[cmd: BIOWRply, add: add], [data0, qZero, qZero, qZero]];
};
DeMapRqst: PROC [h: Handle, Eval: REProc, add: Address, data0: Quad, noReply: BOOLFALSE] ~ {
p: Port ← h.port;
AcquireBus[h, Eval];
TerminalIO.PutRope[IO.PutFR["%g) DeMapRqst\n", IO.int[cmdCount]]];
p[DataIn].q ← MakeHeader[cmd: DeMapRqst, add: add];
p[HeaderCycleIn].b ← TRUE;
Cycle[h, Eval, 1];
p[DataIn].q ← data0;
p[HeaderCycleIn].b ← FALSE;
FinalCycle[h, Eval];
IF ~noReply THEN ResponseChecker.ExpectReply[h.rcState, MakeHeader[cmd: DeMapRply, add: add], [data0, qZero, qZero, qZero]];
};
DBusRegSel: PROC [h: Handle, Eval: REProc, add: dBusRegAdd] ~ {
bits: CARDINAL ← dBusPrefix;
p: Port ← h.port;
p[DBus].bs[dAddress] ← TRUE;
FOR i: NAT IN [0..dBusPrefixBits) DO
p[DBus].bs[dSerialIn] ← Basics.BITAND[bits, Basics.BITSHIFT[1, dBusPrefixBits-1]]#0; --send MSB first
bits ← Basics.BITSHIFT[bits, 1];
DBusCycle[h, Eval];
ENDLOOP;
bits ← add;
FOR i: NAT IN [0..dBusRegAddBits) DO
p[DBus].bs[dSerialIn] ← Basics.BITAND[bits, Basics.BITSHIFT[1, dBusRegAddBits-1]]#0; --send MSB first
bits ← Basics.BITSHIFT[bits, 1];
DBusCycle[h, Eval];
ENDLOOP;
p[DBus].bs[dAddress] ← FALSE;
};
DBusRegRead: PROC [h: Handle, Eval: REProc, add: dBusRegAdd, data: BitOps.BitQWord, regWidth: [1..BitOps.bitsPerQWord]] ~ {
p: Port ← h.port;
DBusRegSel[h, Eval, add];
p[DBus].bs[dExecute] ← TRUE;
p[DBus].ds[dSerialOut] ← expect;
p[DBus].bs[dSerialOut] ← BitOps.EBFQ[data, 0, regWidth];
DBusCycle[h, Eval];
p[DBus].bs[dExecute] ← FALSE;
FOR i: NAT IN [1..regWidth) DO
p[DBus].bs[dSerialOut] ← BitOps.EBFQ[data, i, regWidth];
DBusCycle[h, Eval];
ENDLOOP;
p[DBus].ds[dSerialOut] ← none;
};
DBusRegWrite: PROC [h: Handle, Eval: REProc, add: dBusRegAdd, data: BitOps.BitDWord, regWidth: [1..BitOps.bitsPerDWord]] ~ {
p: Port ← h.port;
DBusRegSel[h, Eval, add];
FOR i: NAT IN [0..regWidth) DO
p[DBus].bs[dSerialIn] ← BitOps.EBFD[data, i, regWidth];
DBusCycle[h, Eval];
ENDLOOP;
};
Cycle: PROC [h: Handle, Eval: REProc, n: CARDINAL ← 1] ~ {
p: Port ← h.port;
THROUGH [0..n) DO
p[OwnerIn].b ← ownerDelayBuf[0].owner;
p[SharedIn].b ← ownerDelayBuf[0].shared;
FOR i: NAT IN [0..ownerDelay) DO
ownerDelayBuf[i] ← ownerDelayBuf[i+1];
ENDLOOP;
ownerDelayBuf[ownerDelay] ← [FALSE, FALSE];
p[Clock].b ← FALSE;
MTSVector.EvalAndCapture[capture: h.capture, Eval: Eval, memory: TRUE, useClockEval: TRUE, checkPorts: FALSE];
p[Clock].b ← TRUE;
MTSVector.EvalAndCapture[capture: h.capture, Eval: Eval, memory: TRUE, useClockEval: TRUE, checkPorts: TRUE];
ENDLOOP;
};
DBusCycle: TProc ~ {
p: Port ← h.port;
p[DBus].bs[dShiftCK] ← FALSE;
MTSVector.EvalAndCapture[capture: h.capture, Eval: Eval, memory: TRUE, useClockEval: TRUE, checkPorts: FALSE];
p[DBus].bs[dShiftCK] ← TRUE;
MTSVector.EvalAndCapture[capture: h.capture, Eval: Eval, memory: TRUE, useClockEval: TRUE, checkPorts: TRUE];
};
FlushPipe: TProc ~ {
WHILE ~ResponseChecker.IsEmpty[h.rcState] DO
Cycle[h, Eval, 1];
ENDLOOP;
};
AcquireBus: PROC [h: Handle, Eval: REProc, cycles: NAT ← 2 ] ~ {
timer: CARDINAL ← arbiterTimeout;
p: Port ← h.port;
p[DReqTP].c ← (SELECT cycles FROM
2 => 2,
5 => 3,
ENDCASE => ERROR);
Cycle[h, Eval, 1];
p[DReqTP].c ← 0; -- no further request
p[DGrantTP].d ← inspect; -- p[DGrantTP].b = FALSE
WHILE NOT p[DGrantTP].b DO
Cycle[h, Eval, 1];
timer ← timer-1;
IF timer=0 THEN ERROR; --bus timeout
ENDLOOP;
p[DGrantTP].d ← expect; -- p[DGrantTP].b = TRUE
};
FinalCycle: TProc ~ {
p: Port ← h.port;
p[DGrantTP].b ← FALSE;
Cycle[h, Eval, 1];
cmdCount ← cmdCount+1;
};
MakeHeader: PROC [cmd: Cmd, mode: ModeError ← FALSE, sh: Shared ← FALSE, id: DeviceID ← 0, add: Address ← qZero] RETURNS [header: Quad] ~ {
header ← qZero;
header ← DynaBusInterface.InsertCmd[header, cmd];
header ← DynaBusInterface.InsertModeError[header, mode];
header ← DynaBusInterface.InsertShared[header, sh];
header ← DynaBusInterface.InsertDeviceID[header, id];
header ← DynaBusInterface.InsertAddress[header, add];
};
InitPortIndicies: PROC [ct: Core.CellType] ~ {
[nSStopIn, SharedIn, OwnerIn, DBus, DReqTP, DGrantTP, TestIn] ← Ports.PortIndexes[ct.public, "nSStopIn", "SharedIn", "OwnerIn", "DBus", "DReqTP", "DGrantTP", "TestIn"];
[HeaderCycleIn, Clock, DataIn] ← Ports.PortIndexes[ct.public, "HeaderCycleIn", "Clock", "DataIn"];
Vdd ← Ports.PortIndex[ct.public, "Vdd"];
Gnd ← Ports.PortIndex[ct.public, "Gnd"];
};
RosemaryUser.RegisterTestProc["MCTest", MCTest];
END.