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: BOOL ← FALSE,
resetRequested: BOOL ← TRUE,
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 BOOL ← ALL[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: REF ← NIL,
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: INTEGER ← LOOPHOLE[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: INTEGER ← LOOPHOLE[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.