XBusImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Gasbarro, October 24, 1986 10:03:36 am PDT
Tim Diebert: July 15, 1986 12:31:12 pm PDT
Ed Fiala: August 21, 1986 3:22:03 pm PDT
Ed Fiala: October 13, 1986 3:05:10 pm PDT
Ed Fiala: October 24, 1986 10:03:32 am PDT
The opcode trap here are modeled after stuff in TrapsImpl.mesa and StorageTrapsImpl.mesa.
Changes needed:
1) The definitions in XOps.mesa maybe should be moved to PrincOps.mesa. The Misc alpha definitions in CedarMicrocode.mesa should also be moved to PrincOps.mesa
DIRECTORY
Basics USING [BITAND, BITSHIFT],
CountedVM USING [Handle, Allocate, Free],
PrincOps USING [ControlLink, FrameHandle, StateVector],
PrincOpsUtils USING [GetReturnFrame],
XBus,
XOps,
TrapSupport USING [opTrapTable];
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.