LizardHeart.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) February 27, 1986 5:47:18 pm PST
McCreight, January 14, 1986 11:10:48 am PST
DIRECTORY
DragOpsCross USING [FieldDescriptor, IFUStackSize, Inst, ProcessorRegister, TrapIndex, Word, ZerosWord],
DragOpsCrossUtils USING [CardToWord, HalvesToWord, TrapIndexToBytePC, WordToBytes, WordToHalves],
LizardCache USING [CacheBase],
Rope USING [ROPE];
LizardHeart: CEDAR DEFINITIONS
IMPORTS DragOpsCrossUtils
= BEGIN OPEN DragOpsCross, DragOpsCrossUtils;
LizardIFUStackSize: NAT = MIN[
MAX[IFUStackSize+7, 16],
MAX[IFUStackSize+7, 32],
MAX[IFUStackSize+7, 64],
MAX[IFUStackSize+7, 128],
MAX[IFUStackSize+7, 256]];
A power of two that is significantly larger than the real stack size.
LizardIFUStackIndex: TYPE = [0..LizardIFUStackSize);
CacheBase: TYPE = LizardCache.CacheBase;
Processor: TYPE = REF ProcessorRep; -- eventually something else
ProcessorRep: TYPE = RECORD [
logger: ChangeLogger ← NIL,
youngest: LizardIFUStackIndex ← 0,
eldest: LizardIFUStackIndex ← 0,
stackEntries: LizardIFUStackIndex ← 0,
euBusyReg: ProcessorRegister ← euJunk,
euCarry: BOOLFALSE,
resetRequested: BOOLTRUE,
stats: ProcessorStats ← [],
lastCallRtn: INT ← 0, -- inst count of last call/return
instBuffer: InstBuffer ← NIL,
ifuCache: CacheBase ← NIL,
euCache: CacheBase ← NIL,
regs: ARRAY ProcessorRegister OF Word ← ALL[ZerosWord],
regsGood: ARRAY ProcessorRegister OF BOOLALL[FALSE],
ifuStack: ARRAY LizardIFUStackIndex OF IFUStackEntry ← ALL[[ZerosWord, euStack]]
];
InstBuffer: TYPE = REF InstBufferRep;
InstBufferRep: TYPE = RECORD [
basePC: Word ← ZerosWord, -- PC corresponding to startValid
nextPC: Word ← ZerosWord, -- next PC in straightline code
validWords: CARDINAL ← 0, -- # of words in buffer
bytesDiscarded: INT ← 0, -- # of bytes ahead of PC discarded
forcedEmpty: INT ← 0, -- # of times forced empty
busyUntil: INT ← 0, -- cycle # the ifu cache is busy until
words: SEQUENCE max: NAT OF Word
];
ProcessorStats: TYPE = RECORD [
instructions: INT ← 0,
cycles: INT ← 0,
euFetches: INT ← 0,
euStores: INT ← 0,
instBytes: INT ← 0,
fallThruGood, fallThruBad: INT ← 0,
jumpGood, jumpBad: INT ← 0,
jumps: INT ← 0,
Number of unconditional jump instructions
calls: INT ← 0,
Number of call instructions
stackOver: INT ← 0,
Stack overflows
instBufferCycles: INT ← 0,
Cycles spent waiting for instructions
lookaheadRejects: INT ← 0,
Reject cycles due to instruction buffer lookahead
returnInterlockCycles: INT ← 0
Cycles spent waiting for returns too close together
];
ChangeLogger: TYPE = REF ChangeLoggerRep;
ChangeLoggerRep: TYPE = RECORD [
data: REFNIL,
regChange: RegChangeProc ← NIL,
memChange: MemChangeProc ← NIL,
ioChange: IOChangeProc ← NIL,
instStart: InstStartProc ← NIL,
instDone: InstDoneProc ← NIL
];
RegChangeProc: TYPE =
PROC [data: REF, processor: Processor, reg: ProcessorRegister, old,new: Word];
MemChangeProc: TYPE =
PROC [data: REF, processor: Processor, addr: Word, old,new: Word];
IOChangeProc: TYPE =
PROC [data: REF, processor: Processor, addr: Word, old,new: Word];
InstStartProc: TYPE =
PROC [data: REF, processor: Processor, thisPC: Word, inst: Inst, rest: Word];
InstDoneProc: TYPE =
PROC [data: REF, processor: Processor, newPC, rtnPC: Word, control: Control, cycles: INT];
IFUStackEntry: TYPE = RECORD[pc: Word, regL: ProcessorRegister];
Control: TYPE = {nextInst, doCall, doReturn, doSwitch, doAbort};
ALUOps: TYPE = MACHINE DEPENDENT {
Copied from /Indigo/Dragon/Rosemary/Dragon.mesa
SAdd(0), SSub(1), UAdd(2), USub(3), VAdd(4), VSub(5), LAdd(6), LSub(7), FOP(8), FOPK(9), And(10), Or(11), Xor(12), BndChk(13), Reserve14(14), Reserve15(15), Reserve16(16), Reserve17(17), Reserve18(18), Reserve19(19), Reserve20(20), Reserve21(21), Reserve22(22), Reserve23(23), Reserve24(24), Reserve25(25), Reserve26(26), Reserve27(27), Reserve28(28), Reserve29(29), Reserve30(30), Reserve31(31)};
EUPageFault: TrapIndex = EUPageFault;
Used to indicate page fault from cache, even for IFU fetches.
EUWriteFault: TrapIndex = EUWriteFault;
Used to indicate write protect fault from EU cache.
NoFault: TrapIndex = ALUCondFalse;
Any unused code will do. But we need a state to indicate that everything is OK.
NewProcessor: PROC [ifuCache,euCache: CacheBase, logger: ChangeLogger] RETURNS [Processor];
InstructionExecute: PROC [processor: Processor];
FlushInstBuffer: PROC [processor: Processor];
This routine flushes the instruction buffer. This occurs on a bad jump prediction, a trap, or an xop.
INLINE routines for picking apart various pieces of the input
Signs: TYPE = MACHINE DEPENDENT {
a0b0c0 (0), a0b0c1 (1), a0b1c0 (2), a0b1c1 (3),
a1b0c0 (4), a1b0c1 (5), a1b1c0 (6), a1b1c1 (7)};
ALUHelper: PROC [a,b,c: BOOL] RETURNS [Signs] = INLINE {
RETURN [LOOPHOLE[
4*LOOPHOLE[a, CARDINAL] + 2*LOOPHOLE[b, CARDINAL] + LOOPHOLE[c, CARDINAL]]];
};
InstBytes: PROC [inst: Inst] RETURNS [bytes: [1..5]] = INLINE {
SELECT LOOPHOLE[inst, CARDINAL] FROM
< 40B => bytes ← 1;
< 100B => bytes ← 5;
ENDCASE => bytes ← LOOPHOLE[inst, CARDINAL] / 64;
};
RegPlus: PROC [reg: ProcessorRegister, delta: INTEGER] RETURNS [ProcessorRegister] = INLINE {
RETURN [LOOPHOLE[(LOOPHOLE[reg, CARDINAL] + LOOPHOLE[delta, CARDINAL]) MOD 256]];
};
StackPlus: PROC
[reg: ProcessorRegister, delta: INTEGER] RETURNS [ProcessorRegister] = INLINE {
RETURN [LOOPHOLE[(LOOPHOLE[reg, CARDINAL] + LOOPHOLE[delta, CARDINAL]) MOD 128]];
};
AlphaZ: PROC [rest: Word] RETURNS [CARDINAL] = INLINE {
RETURN [LOOPHOLE[WordToBytes[rest][3]]];
};
AlphaBetaZ: PROC [rest: Word] RETURNS [CARDINAL] = INLINE {
RETURN [LOOPHOLE[WordToHalves[rest][1]]];
};
AlphaS: PROC [rest: Word] RETURNS [INTEGER] = INLINE {
i: INTEGERLOOPHOLE[WordToBytes[rest][3], CARDINAL];
RETURN [IF i > 127 THEN i ← i - 256 ELSE i];
};
AlphaBetaS: PROC [rest: Word] RETURNS [INTEGER] = INLINE {
RETURN [LOOPHOLE[WordToHalves[rest][1]]];
};
BetaZ: PROC [rest: Word] RETURNS [CARDINAL] = INLINE {
RETURN [LOOPHOLE[WordToBytes[rest][2]]];
};
BetaS: PROC [rest: Word] RETURNS [INTEGER] = INLINE {
i: INTEGERLOOPHOLE[WordToBytes[rest][2], CARDINAL];
RETURN [IF i > 127 THEN i ← i - 256 ELSE i];
};
WordToReg: PROC [word: Word] RETURNS [ProcessorRegister] = INLINE {
RETURN [LOOPHOLE[WordToBytes[word][3]]];
};
RegToWord: PROC [reg: ProcessorRegister] RETURNS [Word] = INLINE {
RETURN [HalvesToWord[[LOOPHOLE[0], LOOPHOLE[reg]]]];
};
Utility Routines for manipulating data (incomplete)
TrapPC: PUBLIC PROC [tx: DragOpsCross.TrapIndex] RETURNS [Word] = INLINE {
Turns a trap index into a byte PC. This is a full routine to keep from making the compiler unhappy with excessive INLINEs.
RETURN [CardToWord[DragOpsCrossUtils.TrapIndexToBytePC[tx]]];
};
DoALUOp: PUBLIC PROC
[processor: Processor, wordA,wordB: Word, op: ALUOps, trap: TrapIndex]
RETURNS
[res: Word, resCode: TrapIndex ← NoFault];
FieldUnit: PUBLIC PROC [Left,Right: Word, fd: FieldDescriptor] RETURNS [out: Word];
WillPushOverflow: PUBLIC PROC [processor: Processor] RETURNS [BOOL];
... returns TRUE if the next push will overflow the IFU stack. Signals OutsideEnvelope in illegal cases.
OutsideEnvelope: PUBLIC SIGNAL [explanation: Rope.ROPE];
The program has been caught red-handed doing something that no reasonable Dragon program should do; something for which the hardware response needn't be defined.
END.