XBusImpl:
CEDAR
PROGRAM
IMPORTS Basics, CountedVM, XBus, PrincOpsUtils
EXPORTS XBus = BEGIN OPEN XOps, XBus;
mBusCtl: POINTER = LOOPHOLE[2];
lBusOutData: POINTER = LOOPHOLE[2];
lBusInData: POINTER = LOOPHOLE[2];
mBusAddr: POINTER = LOOPHOLE[3];
lBusAddr: POINTER = LOOPHOLE[3];
timer: LONG POINTER = LOOPHOLE[LONG[64]];
masterClear: LONG POINTER = LOOPHOLE[LONG[13]];
MBusTimeout: PUBLIC SIGNAL = CODE;
MBusHung trap handler; this trap occurs when the MBus acknowledgment is not received for 10 microseconds in the ReadMBus, WriteMBus, ReadIBMBus, and WriteIBMBus opcodes. The trap occurs with the return PC pointing at the opcode which trapped and with the opcode arguments on the stack; the wordcount argument reflects the progress of the opcode, so it gives the 16-bit words remaining to be transferred. The code here advances the PC across the opcode and flushes the arguments from the stack. A descriptor for this procedure is put in the MISC opcode trap table entries which have indices corresponding to the alpha bytes of the four opcodes by the initialization code.
MBusTimeoutTrap:
PROC =
TRUSTED {
frame: PrincOps.FrameHandle;
state: RECORD [a: WORD, v: PrincOps.StateVector];
state.v ← STATE;
state.v.dest ← PrincOps.ControlLink[frame[frame ← PrincOpsUtils.GetReturnFrame[]]];
frame.pc ← [frame.pc + 2]; -- Advance PC over the 2 bytes of the trapping opcode
state.v.stkptr ← state.v.stkptr - 6; --Clear args from the stack
MBusTimeout[];
RETURN WITH state.v;
};
PCRefreshOn:
PUBLIC
PROC =
{
BusMasterWrite[timer+3, 84];
BusMasterWrite[timer+1, 18];
BusMasterWrite[masterClear, 0];
BusMasterWrite[LOOPHOLE[LONG[12]], 0];
BusMasterWrite[LOOPHOLE[LONG[1]], Basics.BITAND[8191, 255]];
BusMasterWrite[LOOPHOLE[LONG[1]], Basics.BITSHIFT[8191, -8]];
BusMasterWrite[LOOPHOLE[LONG[11]], 88];
BusMasterWrite[LOOPHOLE[LONG[10]], 0];
};
These are here so that you can get at ReadL, ReadM, etc. from the interpreter
XReadL:
PROC [add:
POINTER]
RETURNS [
WORD] =
{
RETURN[XBus.ReadL[LOOPHOLE[add]]];
};
XReadM:
PROC [add:
POINTER]
RETURNS [
WORD] =
{
RETURN[XBus.ReadM[LOOPHOLE[add]]];
};
XWriteL:
PROC [add:
POINTER, data:
WORD] =
{
XBus.WriteL[LOOPHOLE[add], data];
};
XWriteM:
PROC [add:
POINTER, data:
WORD] =
{
XBus.WriteM[LOOPHOLE[add], data];
};
XWriteMBus:
PROC [controlData:
WORD, from, to:
LONG
POINTER, byteInterval, wordCnt:
CARDINAL] = {
XBus.WriteMBus[controlData, from, to, byteInterval, wordCnt];
};
XReadMBus:
PROC [controlData:
WORD, to, from:
LONG
POINTER, byteInterval, wordCnt:
CARDINAL] = {
XBus.ReadMBus[controlData, to, from, byteInterval, wordCnt];
};
XWriteIBMBus:
PROC [controlData:
WORD, from, to:
LONG
POINTER, byteInterval, wordCnt:
CARDINAL] = {
XBus.WriteIBMBus[controlData, from, to, byteInterval, wordCnt];
};
XReadIBMBus:
PROC [controlData:
WORD, to, from:
LONG
POINTER, byteInterval, wordCnt:
CARDINAL] = {
XBus.ReadIBMBus[controlData, to, from, byteInterval, wordCnt];
};
These procedures test the ReadMBus, WriteMBus, ReadPCBus, and WritePCBus opcodes
TestWriteSignal: SIGNAL = CODE;
TestReadSignal: SIGNAL = CODE;
When nSeconds was 14,400 and the inner loop was J in [0..(nSeconds + 1)/2, the program took 23,247 seconds.
MTest:
PROC [nSeconds:
LONG
CARDINAL ← 10] =
TRUSTED {
vm1, vm2, vm3: CountedVM.Handle ← NIL;
writeDataArray: LONG POINTER TO ARRAY [0..32767) OF WORD;
readDataArray: LONG POINTER TO ARRAY [0..32767) OF WORD;
readDataArrayX: LONG POINTER TO ARRAY [0..1) OF WORD; --extra array for reread
writeControlData: CARDINAL ← 8902H;
readControlData: CARDINAL ← 8A01H;
loopEnd: LONG CARDINAL ← (nSeconds + 1) * 3097 / 10000; --empirical value
vm1 ← CountedVM.Allocate[LONG[32767]];
vm2 ← CountedVM.Allocate[LONG[32767]];
vm3 ← CountedVM.Allocate[LONG[1]];
writeDataArray ← vm1.pointer;
readDataArray ← vm2.pointer;
readDataArrayX ← vm3.pointer; --Breakpoint place
FOR
I:
CARDINAL
IN [0..32767)
DO
writeDataArray[I] ← I; --Initialize the write array
readDataArray[I] ← 125252B; --Put benign value in read array
ENDLOOP;
At 6 microseconds/word, each WriteMBus or ReadMBus instruction below takes 0.2 seconds, so each iteration of the main loop should take 0.8 seconds plus the time to initialize the writeDataArray and execute the compare loop; altogether, this should take about 2 seconds per iteration of the outer loop.
FOR
J:
LONG
CARDINAL
IN [0..loopEnd)
DO
WriteMBus[writeControlData, writeDataArray, LOOPHOLE[10000h], 2, 32767];
ReadMBus[readControlData, readDataArray, LOOPHOLE[10000h], 2, 32767];
FOR
I:
CARDINAL
IN [0..32767)
DO
writeDataArray[I] ← 0 - I;
IF readDataArray[I] # I
THEN {
Reread the data to descriminate write errors from read errors; obtaining a different value on the reread indicates a flakey read problem; obtaining the same wrong value as the first read could indicate either a write problem or a solid read problem.
ReadMBus[readControlData, readDataArrayX, LOOPHOLE[10000h + I + I], 2, 1];
IF readDataArrayX[0] # readDataArray[I] THEN TestReadSignal[] ELSE TestWriteSignal[];
};
ENDLOOP;
WriteMBus[writeControlData, writeDataArray, LOOPHOLE[10000h], 2, 32767];
ReadMBus[readControlData, readDataArray, LOOPHOLE[10000h], 2, 32767];
FOR
I:
CARDINAL
IN [0..32767)
DO
writeDataArray[I] ← I;
IF readDataArray[I] # (0 - I)
THEN {
ReadMBus[readControlData, readDataArrayX, LOOPHOLE[10000h + I + I], 2, 1];
IF readDataArrayX[0] # readDataArray[I] THEN TestReadSignal[] ELSE TestWriteSignal[];
};
ENDLOOP;
ENDLOOP;
CountedVM.Free[vm1];
CountedVM.Free[vm2];
CountedVM.Free[vm3];
};
PCTest:
PROC [nSeconds:
LONG
CARDINAL ← 10] =
TRUSTED {
vm1, vm2, vm3: CountedVM.Handle ← NIL;
writeDataArray: LONG POINTER TO ARRAY [0..4096) OF WORD;
readDataArray: LONG POINTER TO ARRAY [0..4096) OF WORD;
readDataArrayX: LONG POINTER TO ARRAY [0..1) OF WORD; --extra array for reread
writeControlData: CARDINAL ← 2H;
readControlData: CARDINAL ← 1H;
loopEnd: LONG CARDINAL ← (nSeconds + 1) * 2; --guess; verify this
vm1 ← CountedVM.Allocate[LONG[4096]];
vm2 ← CountedVM.Allocate[LONG[4096]];
vm3 ← CountedVM.Allocate[LONG[1]];
writeDataArray ← vm1.pointer;
readDataArray ← vm2.pointer;
readDataArrayX ← vm3.pointer; --Breakpoint place
FOR
I:
CARDINAL
IN [0..4096)
DO
readDataArray[I] ← 125252B;
writeDataArray[I] ← I;
ENDLOOP;
At 9 microseconds/word, each WriteIBMBus or ReadIBMBus instruction below takes 0.04 seconds, so each iteration of the main loop should take 0.16 seconds plus the time to initialize the writeDataArray and execute the compare loop; altogether, this should take about 0.4 seconds per iteration of the outer loop.
FOR
J:
LONG
CARDINAL
IN [0..loopEnd)
DO
WriteIBMBus[writeControlData, writeDataArray, LOOPHOLE[0A0000], 1, 4096];
ReadIBMBus[readControlData, readDataArray, LOOPHOLE[0A0000], 1, 4096];
FOR
I:
CARDINAL
IN [0..4096)
DO
writeDataArray[I] ← 0 - I; --Setup for the loop below
IF readDataArray[I] # I
THEN {
ReadIBMBus[readControlData, readDataArrayX, LOOPHOLE[0A0000 + I + I], 1, 1];
IF readDataArrayX[0] # readDataArray[I] THEN TestReadSignal[] ELSE TestWriteSignal[];
};
ENDLOOP;
WriteIBMBus[writeControlData, writeDataArray, LOOPHOLE[0A0000], 1, 4096];
ReadIBMBus[readControlData, readDataArray, LOOPHOLE[0A0000], 1, 4096];
FOR
I:
CARDINAL
IN [0..4096)
DO
writeDataArray[I] ← I; --Setup for the loop above
IF readDataArray[I] # (0 - I)
THEN {
ReadIBMBus[readControlData, readDataArrayX, LOOPHOLE[0A0000 + I + I], 1, 1];
IF readDataArrayX[0] # readDataArray[I] THEN TestReadSignal[] ELSE TestWriteSignal[];
};
ENDLOOP;
ENDLOOP;
CountedVM.Free[vm1];
CountedVM.Free[vm2];
CountedVM.Free[vm3];
};
MWriteTest:
PROC ~ {
first: LONG POINTER = LOOPHOLE[LONG[0]];
last: LONG POINTER = LOOPHOLE[0FFFFEh];
data: WORD;
FOR i:
LONG
POINTER ← first, i+2
WHILE i#last
DO
XBus.MemWrite[i, 0];
ENDLOOP;
FOR i:
LONG
POINTER ← first, i+2
WHILE i#last
DO
IF (data ← XBus.MemRead[i])#0 THEN TestWriteSignal;
XBus.MemWrite[i, 0FFFFh];
ENDLOOP;
FOR i:
LONG
POINTER ← first, i+2
WHILE i#last
DO
IF (data ← XBus.MemRead[i])#0FFFFh THEN TestWriteSignal[];
ENDLOOP;
};
Initialization of the opcode traps for MBus and IBMPCBus timeout.
Initialize:
PROC =
TRUSTED {
TrapSupport.opTrapTable.misc[aWriteMBus] ← LOOPHOLE[MBusTimeoutTrap];
TrapSupport.opTrapTable.misc[aReadMBus] ← LOOPHOLE[MBusTimeoutTrap];
TrapSupport.opTrapTable.misc[aWriteIBMBus] ← LOOPHOLE[MBusTimeoutTrap];
TrapSupport.opTrapTable.misc[aReadIBMBus] ← LOOPHOLE[MBusTimeoutTrap];
Initialize[];
END.