dDFC => {
Effect: call proc at AlphaBetaGammaDelta
newPC ← rest;
GO TO call;
};
dLIQB => {
Effect: [S]𡤊lphaBetaGammaDelta; S←S+1
resWord ← rest;
GO TO storeReg;
};
dADDQB, dSUBQB => {
Effect: [S] ← [S] ± AlphaBetaGammaDelta ± carry; trap on overflow, clear carry
[resWord, trapCode] ← DoALUOp[
processor,
topOfStack,
rest,
IF inst = dADDQB THEN SAdd ELSE SSub,
ALUCondOver];
GO TO aluDone;
};
dJ5 => {
Effect: noop
GO TO noCheck;
};
dJQB => {
Effect: noop
newPC ← rest;
GO TO jump;
};
dOR, dAND, dRX, dBC, dADD, dSUB, dLADD, dLSUB => {
Effect: [S-1]←[S-1] op [S]; S←S-1;
op: ALUOps;
cond: TrapIndex ← ALUCondFalse;
wordA: Word = RegFetchInline[sM1];
SELECT inst
FROM
dOR => {
Effect: [S-1]←[S-1] OR [S]; S←S-1
op ← Or;
};
dAND => {
Effect: [S-1]←[S-1] AND [S]; S←S-1
op ← And;
};
dRX => {
Effect: [S-1]←([S-1]+[S])^; S←S-1
resAddr ← VanillaAdd[wordA, topOfStack];
GO TO memFetch;
};
dBC => {
Effect: trap if [S-1] < 0 OR [S-1]-[S] >= 0; S←S-1
op ← BndChk;
cond ← ALUCondBC;
};
dADD => {
Effect: [S-1]←[S-1]+[S]+carry; carry𡤀 trap on overflow; S←S-1
op ← SAdd;
cond ← ALUCondOver;
};
dSUB => {
Effect: [S-1]←[S-1]-[S]-carry; carry𡤀 trap on overflow; S←S-1
op ← SSub;
cond ← ALUCondOver;
};
dLADD => {
Effect: [S-1]←[S-1]+[S]; carry𡤀 trap on overflow or Lisp NaN; S←S-1
op ← LAdd;
cond ← ALUCondIL;
};
dLSUB => {
Effect: [S-1]←[S-1]-[S]; carry𡤀 trap on overflow or Lisp NaN; S←S-1
op ← LSub;
cond ← ALUCondIL;
};
ENDCASE => GO TO xop;
[resWord, trapCode] ← DoALUOp[processor, wordA, topOfStack, op, cond];
GO TO aluDone;
};
dDUP =>
GO
TO storeReg;
Effect: [S+1]←[S]; S←S+1
dDIS =>
GO
TO done;
Effect: S←S-1
dEXDIS =>
GO
TO storeReg;
Effect: [S-1]←[S]; S←S-1
dSFC => {
Effect: call proc at [S]; S←S-1
newPC ← topOfStack;
GO TO call;
};
dSFCI => {
Effect: call proc at ([S])^
[newPC, trapCode] ← MemFetch[topOfStack];
IF trapCode # NoFault THEN GO TO memFault;
GO TO call;
};
dRETN =>
GO
TO return;
Effect: return from proc (no stack change)
dKFC => {
Effect: PC←InstTrap[KFC]; set kernel mode; disable traps; S←S+1
IF LizardHeart.WillPushOverflow[processor]
THEN CauseTrap[IFUStackOverflowTrap]
ELSE newPC ← CardToWord[DragOpsCrossUtils.XopToBytePC[inst]];
control ← doAbort;
GO TO done;
};
dJ1 =>
GO
TO noCheck;
Effect: noop
dJSD => {
Effect: PC←[S]; S←S-1
newPC ← topOfStack;
IF WillEUStackOverflow[] THEN GO TO euOverflow;
GO TO jump;
};
dJSR => {
Effect: PC←PC+[S]; S←S-1
newPC ← VanillaAdd[thisPC, topOfStack];
IF WillEUStackOverflow[] THEN GO TO euOverflow;
GO TO jump;
};
dLC0, dLC1, dLC2, dLC3, dLC4, dLC5, dLC6, dLC7, dLC8, dLC9, dLC10, dLC11 => {
Effect: [S+1]𡤌onstants[n]; S←S+1
resReg ← RegPlus[euConstant, ORD[inst] MOD 16];
GO TO pushReg;
};
dLR0 => {
Effect: [S+1]←[L+n]; S←S+1
resReg ← StackPlus[regL, ORD[inst] MOD 16];
GO TO pushReg;
};
dSR0 => {
Effect: [L+n]←[S]; S←S-1
resReg ← StackPlus[regL, ORD[inst] MOD 16];
GO TO storeReg;
};
dQOR, dQAND, dQRX, dQBC, dQADD, dQSUB, dQLADD, dQLSUB => {
OPEN form: LOOPHOLE[formBytes2, QRformat];
wordB: Word ← RegFetchInline[CalcReg[form.aux, form.opt, form.reg]];
op: ALUOps;
cond: TrapIndex ← ALUCondFalse;
sd: [0..1] ← 1;
srcReg: ProcessorRegister ← regS;
SELECT form.aOp
FROM
topAtop => sd ← 0;
C: [S], A: [S], B: general
pushAtop => {};
C: [S+1]+, A: [S], B: general
pushA0 => srcReg ← euConstant;
C: [S+1]+, A: c0, B: general
pushA1 => srcReg ← RegPlus[euConstant, 1];
C: [S+1]+, A: c1, B: general
ENDCASE;
topOfStack ← RegFetchInline[srcReg]; -- the A operand word
resReg ← StackPlus[regS, sd]; -- the C register
stackEffect ← stackEffect + sd; -- the change to stack effect
SELECT inst
FROM
dQOR => {
Effect: [S] ← Rs OR Rb
op ← Or;
};
dQAND => {
Effect: [S] ← Rs AND Rb
op ← And;
};
dQRX => {
Effect: [S] ← (Rs+[Rb])^
resAddr ← VanillaAdd[topOfStack, wordB];
GO TO memFetch;
};
dQBC => {
Effect: [S] ← Rs BC Rb; trap if [S] < 0 OR [S]-Rb >= 0
op ← BndChk;
cond ← ALUCondBC;
};
dQADD => {
Effect: [S] ← Rs+Rb+carry; carry𡤀 trap on overflow
op ← SAdd;
cond ← ALUCondOver;
};
dQSUB => {
Effect: [S] ← Rs-Rb-carry; carry𡤀 trap on overflow
op ← SSub;
cond ← ALUCondOver;
};
dQLADD => {
Effect: [S] ← Rs+Rb; carry𡤀 trap on overflow or Lisp NaN
op ← LAdd;
cond ← ALUCondIL;
};
dQLSUB => {
Effect: [S] ← Rs-Rb; carry𡤀 trap on overflow or Lisp NaN
op ← LSub;
cond ← ALUCondIL;
};
ENDCASE => ERROR;
[resWord, trapCode] ← DoALUOp[processor, topOfStack, wordB, op, cond];
GO TO aluDone;
};
dALS => {
Effect: L ← S + Alpha
[] ← AdjustL[regS];
GO TO noCheck;
};
dAL => {
Effect: L ← L + Alpha
[] ← AdjustL[regL];
GO TO noCheck;
};
dASL => {
Effect: S ← L + Alpha (no stack overflow check)
[] ← AdjustS[regL];
GO TO noCheck;
};
dAS => {
Effect: S ← S + Alpha (no stack overflow check)
[] ← AdjustS[regS];
GO TO noCheck;
};
dCST => {
Effect: atomic
[S+1] ← ([S-2]+AlphaZ)^;
IF [S+1] = [S] THEN [S-2]+AlphaZ)^ ← [S-1] ELSE [] ← ([S-2]+AlphaZ)^;
S←S+1
resAddr ← AddDelta[alphaZ, RegFetch[StackPlus[regS, -2]]];
[resWord, trapCode] ← MemFetch[resAddr];
SELECT
TRUE
FROM
trapCode # NoFault => GO TO memFault;
WillEUStackOverflow[] => GO TO euOverflow;
ENDCASE;
RegStore[resReg, resWord];
IF resWord = topOfStack
THEN {
The conditional store was successful, so store the new word
resWord ← RegFetch[sM1];
GO TO memStore;
};
The conditional store was not successful, so refetch the word (which simulates releasing the bus)
[] ← MemFetch[resAddr];
GO TO noCheck;
};
dRET => {
Effect: S←L+Alpha; return from proc
IF NOT AdjustS[regL] THEN GO TO noCheck;
GO TO return;
};
dLIP => {
Effect: [S+1]←PReg[Alpha]; S←S+1
reg: ProcessorRegister ← LOOPHOLE[alphaZ];
IF reg > euLast
THEN cycles ← cycles + 4;
IFU registers take longer to fetch than EU registers
SELECT reg
FROM
ifuEldestPC => {
Reading from the ifuEldestPC register has the side effect of popping the entry from the IFU stack. We do a check for empty stacks here, but the processor really doesn't.
eldest: NAT ← processor.eldest;
entries: NAT ← processor.stackEntries;
IF processor.userMode THEN GO TO modeFault;
resWord ← processor.ifuStack[eldest].pc;
IF processor.stackEntries = 0
THEN SIGNAL OutsideEnvelope["Empty IFU stack in LIP ifuEldestPC."]
ELSE {
IF WillEUStackOverflow[]
THEN
GO
TO euOverflow;
Check for overflow before altering the state!
processor.eldest ← (eldest + 1) MOD LizardIFUStackSize;
processor.stackEntries ← entries - 1;
};
};
ifuEldestL => {
IF processor.stackEntries = 0
THEN
SIGNAL OutsideEnvelope["Empty IFU stack in LIP ifuEldestL."];
resWord ← LOOPHOLE[processor.ifuStack[processor.eldest].status];
};
ifuYoungestPC => {
IF processor.stackEntries = 0
THEN
SIGNAL OutsideEnvelope["Empty IFU stack in LIP ifuYoungestPC."];
resWord ← processor.ifuStack[processor.youngest].pc;
};
ifuYoungestL => {
IF processor.stackEntries = 0
THEN SIGNAL OutsideEnvelope["Empty IFU stack in LIP ifuYoungestL."];
resWord ← LOOPHOLE[processor.ifuStack[processor.youngest].status];
};
ENDCASE =>
resWord ← RegFetch[reg];
GO TO storeReg
};
dSIP => {
Effect: PReg[Alpha]←[S]; S←S-1
Note: we try to do the EU stack overflow checking after the IFU stack overflow checking in here, even though there is only one register (ifuEldestPC) that really does the overflow checking
reg: ProcessorRegister ← LOOPHOLE[alphaZ];
IF processor.userMode THEN GO TO modeFault;
[] ← WillEUStackOverflow[];
This just checks for bogus oveflows
IF reg > euLast
THEN cycles ← cycles + 4;
IFU registers take longer to store than EU registers
resReg ← reg;
SELECT reg
FROM
ifuEldestPC => {
Setting this register causes a new eldest entry to be created before writing. This is roughly the same as a push, of course, so we use the same IFU stack overflow check.
entries: NAT ← processor.stackEntries+1;
eldest: NAT ← processor.eldest;
IF LizardHeart.WillPushOverflow[processor]
THEN {
CauseTrap[IFUStackOverflowTrap];
GO TO done;
};
processor.stackEntries ← entries;
eldest ← (eldest + (LizardIFUStackSize - 1)) MOD LizardIFUStackSize;
processor.eldest ← eldest;
processor.ifuStack[eldest].pc ← resWord;
GO TO storeRegIFU;
};
ifuEldestL => {
IF processor.stackEntries = 0
THEN
SIGNAL OutsideEnvelope["Empty IFU stack in SIP ifuEldestL."];
processor.ifuStack[processor.eldest].status ← LOOPHOLE[resWord];
GO TO storeRegIFU;
};
ifuYoungestPC => {
IF processor.stackEntries = 0
THEN
SIGNAL OutsideEnvelope["Empty IFU stack in SIP ifuYoungestPC."];
processor.ifuStack[processor.youngest].pc ← resWord;
GO TO storeRegIFU;
};
ifuYoungestL => {
IF processor.stackEntries = 0
THEN
SIGNAL OutsideEnvelope["Empty IFU stack in SIP ifuYoungestL."];
processor.ifuStack[processor.youngest].status ← LOOPHOLE[resWord];
GO TO storeRegIFU;
};
ENDCASE;
GO TO storeReg;
};
dLIB => {
Effect: [S+1]𡤊lphaZ; S←S+1
resWord ← CardToWord[alphaZ];
GO TO storeReg;
};
dADDB, dSUBB => {
Effect: [S] ← [S] ± AlphaZ ± carry; trap on overflow, clear carry
[resWord, trapCode] ← DoALUOp[
processor,
topOfStack,
CardToWord[alphaZ],
IF inst = dADDB THEN SAdd ELSE SSub,
ALUCondOver];
GO TO aluDone;
};
dJ2 =>
GO
TO noCheck;
Effect: noop
dJB => {
Effect: PC←PC+Alpha
alphaS: INT ← alphaZ;
IF alphaZ > 127 THEN alphaS ← alphaS - 256;
newPC ← AddDelta[alphaS, thisPC];
GO TO jump;
};
dRB =>
GO
TO memFetchAlpha;
Effect: [S]←([S]+AlphaZ)^
dWB => {
Effect: ([S]+AlphaZ)^←[S-1]; S←S-2
resWord ← RegFetch[sM1];
GO TO memStoreAlpha;
};
dRSB =>
GO
TO memFetchAlpha;
Effect: [S+1]←([S]+AlphaZ)^; S←S+1
dWSB => {
Effect: ([S-1]+AlphaZ)^←[S]; S←S-2
resAddr ← RegFetch[sM1];
GO TO memStoreAlpha;
};
dIODA, dIOD, dION => {
An incomplete simulation of the IOx instructions. IOFetch & IOStore effects are mostly ignored. However, the stack effect and the other goodies are correct as far as I can tell.
ioOp: IOOperand = [LOOPHOLE[alphaZ], LOOPHOLE[betaZ]];
pDataA: Word ← AddDelta[ByteToCard[ioOp.pDataA], (IF inst = dIODA THEN topOfStack ELSE CardToWord[0])];
WITH ioOp.pCmd
SELECT
FROM
otherCmd: PCmdFormat.other => {};
cacheCmd: PCmdFormat.cache => {
SELECT cacheCmd.direction
FROM
read => {
IF inst = dIOD THEN resReg ← StackPlus[regS, stackEffect ← 1];
[resWord, trapCode] ← IOFetch[ioOp.pCmd, pDataA];
IF trapCode # NoFault THEN GO TO memFault;
IF inst = dION THEN GO TO done;
processor.euBusyReg ← resReg;
GO TO storeReg;
};
write => {
SELECT inst
FROM
dIOD => stackEffect ← -1;
dIODA => {resWord ← RegFetch[sM1]; stackEffect ← -2};
ENDCASE;
trapCode ← IOStore[ioOp.pCmd, pDataA, resWord];
IF trapCode # NoFault THEN GO TO memFault;
GO TO done;
};
ENDCASE => ERROR;
};
ENDCASE => ERROR;
};
dPSB => {
Effect: ([S-1]+AlphaZ)^←[S]; S←S-1
resAddr ← RegFetch[sM1];
GO TO memStoreAlpha;
};
dLRI0 => {
Effect: [S+1]←([L+n]+AlphaZ)^; S←S+1
OPEN form: LOOPHOLE[formBytes2, LRBformat];
resAddr ← RegFetchInline[StackPlus[regL, form.reg]];
GO TO memFetchAlpha;
};
dSRI0 => {
Effect: ([L+n]+AlphaZ)^←[S]; S←S-1
OPEN form: LOOPHOLE[formBytes2, LRBformat];
resAddr ← RegFetchInline[StackPlus[regL, form.reg]];
GO TO memStoreAlpha;
};
dROR, dRAND, dRRX, dRBC, dRADD, dRSUB, dRLADD, dRLSUB, dRXOR, dRFU, dRVADD, dRVSUB, dRUADD, dRUSUB => {
OPEN form: LOOPHOLE[formBytes3, RRformat];
aux: BOOL = form.aux;
regA: ProcessorRegister = CalcReg[aux, form.aOpt, form.a];
wordA: Word = RegFetchInline[regA];
regB: ProcessorRegister = CalcReg[aux, form.bOpt, form.b];
wordB: Word = RegFetchInline[regB];
op: ALUOps;
cond: TrapIndex ← ALUCondFalse;
resReg ← CalcReg[aux, form.cOpt, form.c, TRUE];
{
This code checks for assignments to the constant or auxilliary registers. All constant and the first eight auxiliary registers are protected against being written while in user mode.
firstProtectedAux: ProcessorRegister = euAux;
lastProtectedAux: ProcessorRegister = VAL[ORD[firstProtectedAux]+7];
firstProtectedConst: ProcessorRegister = euConstant;
lastProtectedConst: ProcessorRegister = VAL[ORD[firstProtectedConst]+11];
firstReadonlyConst: ProcessorRegister = euConstant;
lastReadonlyConst: ProcessorRegister = VAL[ORD[firstProtectedConst]+3];
SELECT resReg
FROM
IN [firstProtectedAux..lastProtectedAux] =>
IF processor.userMode THEN GO TO modeFault;
IN [firstProtectedConst..lastProtectedConst] => {
IF processor.userMode THEN GO TO modeFault;
IF resReg
IN [firstReadonlyConst..lastReadonlyConst]
AND checkReadonlyConst
THEN {
IF checkReadonlyConst
THEN
SIGNAL OutsideEnvelope["Storing into readonly register not permited!"];
resReg ← euJunk;
Don't affect the specified register, it's readonly
}
};
ENDCASE;
};
SELECT inst
FROM
dROR => {
Effect: Rc ← Ra OR Rb
op ← Or;
};
dRAND => {
Effect: Rc ← Ra AND Rb
op ← And;
};
dRRX => {
Effect: [Rc]←([Ra]+[Rb])^
resAddr ← VanillaAdd[wordA, wordB];
GO TO memFetch;
};
dRBC => {
Effect: Rc ← Ra; trap if Ra < 0 OR Ra-Rb >= 0
op ← BndChk;
cond ← ALUCondBC;
};
dRADD => {
Effect: Rc ← Ra+Rb+carry; carry𡤀 trap on overflow
op ← SAdd;
cond ← ALUCondOver;
};
dRSUB => {
Effect: Rc ← Ra-Rb-carry; carry𡤀 trap on overflow
op ← SSub;
cond ← ALUCondOver;
};
dRLADD => {
Effect: Rc ← Ra+Rb; carry𡤀 trap on overflow or Lisp NaN
op ← LAdd;
cond ← ALUCondIL;
};
dRLSUB => {
Effect: Rc ← Ra-Rb; carry𡤀 trap on overflow or Lisp NaN
op ← LSub;
cond ← ALUCondIL;
};
dRXOR => {
Effect: Rc ← Ra XOR Rb
op ← Xor;
};
dRFU => {
Effect: [Rc]𡤏ieldUnit[[Ra],[Rb],MDF]
fd: FieldDescriptor = CardToFieldDescriptor[
HalfToCard[WordToHalves[RegFetch[euField]][1]]
];
resWord ← FieldUnit[wordA, wordB, fd];
GO TO storeReg;
};
dRVADD => {
Effect: Rc ← Ra+Rb
resWord ← VanillaAdd[wordA, wordB];
GO TO storeReg;
};
dRVSUB => {
Effect: Rc ← Ra-Rb
resWord ← VanillaSub[wordA, wordB];
GO TO storeReg;
};
dRUADD => {
Effect: Rc ← Ra+Rb+carry; set carry
op ← UAdd;
};
dRUSUB => {
Effect: Rc ← Ra-Rb-carry; set carry
op ← USub;
};
ENDCASE => ERROR;
[resWord, trapCode] ← DoALUOp[processor, wordA, wordB, op, cond];
GO TO aluDone;
};
dLGF => {
Effect: [S+1]←([GB]+AlphaBetaZ)^; S←S+1
resAddr ← AddDelta[alphaBetaZ, RegFetch[euAux]];
GO TO memFetch;
};
dLIDB => {
Effect: [S+1]𡤊lphaBetaZ; S←S+1
resWord ← CardToWord[alphaBetaZ];
GO TO storeReg;
};
dADDDB, dSUBDB => {
Effect: [S] ← [S] ± AlphaBetaZ; trap on overflow
[resWord, trapCode] ← DoALUOp[
processor,
topOfStack,
CardToWord[alphaBetaZ],
IF inst = dADDDB THEN SAdd ELSE SSub,
ALUCondOver];
GO TO aluDone;
};
dJ3 =>
GO
TO noCheck;
Effect: noop
dJDB => {
Effect (dJDB): PC←PC+AlphaBetaS
newPC ← AddDelta[LOOPHOLE[alphaBetaZ, INTEGER], thisPC];
GO TO jump;
};
dLFC => {
Effect (dLFC): call proc at PC+AlphaBetaS
newPC ← AddDelta[LOOPHOLE[alphaBetaZ, INTEGER], thisPC];
GO TO call;
};
dRAI, dRRI, dWAI, dWRI => {
OPEN form: LOOPHOLE[formBytes3, LRRBformat];
baseReg: ProcessorRegister ←
SELECT inst
FROM
dRAI, dWAI => RegPlus[euAux, form.reg2],
ENDCASE => StackPlus[regL, form.reg2];
resReg ← StackPlus[regL, form.reg1];
resAddr ← RegFetchInline[baseReg];
SELECT inst
FROM
dRAI, dRRI => {
Effect (dRAI): [L+BetaL]←(AuxRegs[BetaR]+AlphaZ)^
Effect (dRRI): [L+BetaL]←([L+BetaR]+AlphaZ)^
GO TO memFetchAlpha;
};
dWAI, dWRI => {
Effect (dWAI): (AuxRegs[BetaR]+AlphaZ)^←[L+BetaL]
Effect (dWRI): ([L+BetaR]+AlphaZ)^←[L+BetaL]
resWord ← RegFetchInline[resReg];
GO TO memStoreAlpha;
};
ENDCASE => ERROR;
};
dRJEB, dRJEBJ, dRJGB, dRJGBJ, dRJGEB, dRJGEBJ, dRJLB, dRJLBJ, dRJLEB, dRJLEBJ, dRJNEB, dRJNEBJ => {
Effect: IF Rs cond Rb THEN PC←PC+BetaS
OPEN form: LOOPHOLE[formBytes3, RJBformat];
comparison: Basics.Comparison;
regA: ProcessorRegister ← regS;
SELECT form.aOp
FROM
c0 => regA ← euConstant;
c1 => regA ← SUCC[euConstant];
top => regA ← regS;
popTop => {regA ← regS; stackEffect ← stackEffect - 1};
ENDCASE;
resWord ← RegFetchInline[regA];
comparison ← Basics.CompareInt[
WordToInt[resWord],
WordToInt[RegFetchInline[CalcReg[form.aux, form.opt, form.reg]]]];
IF WillEUStackOverflow[] THEN GO TO euOverflow;
SELECT inst
FROM
dRJEB, dRJEBJ => IF comparison = equal THEN GO TO condJump;
dRJGB, dRJGBJ => IF comparison = greater THEN GO TO condJump;
dRJGEB, dRJGEBJ => IF comparison # less THEN GO TO condJump;
dRJLB, dRJLBJ => IF comparison = less THEN GO TO condJump;
dRJLEB, dRJLEBJ => IF comparison # greater THEN GO TO condJump;
dRJNEB, dRJNEBJ => IF comparison # equal THEN GO TO condJump;
ENDCASE => ERROR;
At this point we should NOT branch.
GO TO condFall;
};
dJEBB, dJEBBJ =>
Effect: AlphaZ = [S] => PC←PC+BetaS; S←S-1
IF topOfStack = CardToWord[alphaZ] THEN GO TO condJump ELSE GO TO condFall;
dJNEBB, dJNEBBJ =>
Effect: AlphaZ # [S] => PC←PC+BetaS; S←S-1
IF topOfStack # CardToWord[alphaZ] THEN GO TO condJump ELSE GO TO condFall;
dSHL => {
Effect: [S]𡤏ieldUnit[[S],0,AlphaBeta]
topOfStack ← ZerosWord;
GO TO storeField;
};
dSHR =>
GO
TO storeField;
Effect: [S]𡤏ieldUnit[[S],[S],AlphaBeta]
dSHDL => {
Effect: [S-1]𡤏ieldUnit[[S-1],[S],AlphaBeta]; S←S-1
resWord ← RegFetch[sM1];
GO TO storeField;
};
dSHDR => {
Effect: [S-1]𡤏ieldUnit[[S],[S-1],AlphaBeta]; S←S-1
resWord ← topOfStack;
topOfStack ← RegFetch[sM1];
GO TO storeField;
};
dFSDB => {
Effect: euField𡤊lphaBeta+[S]; S←S-1
resWord ← VanillaAdd[CardToWord[alphaBetaZ], topOfStack];
resReg ← euField;
GO TO storeReg;
};
x311b, x313b, x337b, x340b, x344b, x350b, x354b => {
SIGNAL OutsideEnvelope[IO.PutFR["Opcode %g has undefined effects", IO.rope[HandCodingUtil.GetInstArray[][inst]]]];
GO TO xop;
};
ENDCASE => NULL;
EXITS
done => {
There is really nothing to do here, we're done.
IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap];
};
noCheck => {
There is really nothing to do here, not even an overflow check.
};
xop => {
Trap. If length # 1 then push AlphaBetaGammaDelta before calling to the trap address. Further traps are permitted - in particular, IFU stack and EU stack overflow even within this instruction.
stackEffect ← 0;
control ← doCall;
newPC ← CardToWord[DragOpsCrossUtils.XopToBytePC[inst]];
SELECT
TRUE
FROM
LizardHeart.WillPushOverflow[processor: processor] =>
CauseTrap[IFUStackOverflowTrap];
bytes > 1 => {
must push the following bytes (can have high-order junk)
cycles ← cycles+1;
stackEffect ← 1;
resWord ← rest;
IF WillEUStackOverflow[]
THEN CauseTrap[EUStackOverflowTrap]
ELSE RegStore[StackPlus[regS, stackEffect], resWord];
};
ENDCASE;
};
condJump => {
A conditional jump branched
betaS: INT ← betaZ;
IF betaZ > 127 THEN betaS ← betaS - 256;
newPC ← AddDelta[betaS, thisPC];
IF flags.predictJump
THEN processor.stats.jumpGood ← processor.stats.jumpGood + 1
ELSE {
control ← doSwitch;
processor.stats.fallThruBad ← processor.stats.fallThruBad + 1;
cycles ← cycles+3;
};
IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap];
};
condFall => {
A conditional jump did NOT branch
IF flags.predictJump
THEN {
control ← doSwitch;
processor.stats.jumpBad ← processor.stats.jumpBad + 1;
cycles ← cycles+3;
}
ELSE processor.stats.fallThruGood ← processor.stats.fallThruGood + 1;
IF WillEUStackOverflow[] THEN CauseTrap[EUStackOverflowTrap];
};
jump => {
There is no need to check for EU overflow here.
processor.stats.jumps ← processor.stats.jumps + 1;
control ← doSwitch;
};
call => {
SELECT
TRUE
FROM
LizardHeart.WillPushOverflow[processor] =>
CauseTrap[IFUStackOverflowTrap];
WillEUStackOverflow[] =>
CauseTrap[EUStackOverflowTrap];
ENDCASE => {
processor.stats.calls ← processor.stats.calls + 1;
control ← doCall;
};
};
return => {
To perform a return. The EU stack checking has already been done.
SELECT processor.stackEntries
FROM
= 0 =>
SIGNAL OutsideEnvelope["IFU control stack is empty during return!"];
> IFUStackSize =>
SIGNAL OutsideEnvelope["IFU control stack is too full during return!"];
> IFUOverflow =>
IF processor.trapsEnabled
THEN
SIGNAL OutsideEnvelope["IFU control stack is too full during return!"];
ENDCASE;
control ← doReturn;
rtnPC ← processor.ifuStack[processor.youngest].pc;
For debugging purposes
};
modeFault => {
This exit is taken if we attempt to execute a protected instruction while in user mode.
CauseTrap[ModeFault];
};
euOverflow => {
This exit is taken if we find that the resulting value of S is bogus.
CauseTrap[EUStackOverflowTrap];
};
pushReg => {
Note: no need to check for stack overflow since we did that earlier
IF WillEUStackOverflow[]
THEN CauseTrap[EUStackOverflowTrap]
ELSE FastRegStore[StackPlus[regS, 1], RegFetchInline[resReg]];
};
storeField => {
resWord holds the "left" word, topOfStack holds the "right" word, regardless of the actual top of stack. This exit is used by SHL, SHR, SHDL, SHDR
IF WillEUStackOverflow[]
THEN CauseTrap[EUStackOverflowTrap]
ELSE FastRegStore[resReg, FieldUnit[resWord, topOfStack, CardToFieldDescriptor[alphaBetaZ]]];
};
storeRegIFU => {
resReg can be an IFU register, so don't use FastRegStore here.
IF WillEUStackOverflow[]
THEN CauseTrap[EUStackOverflowTrap]
ELSE RegStore[resReg, resWord];
};
storeReg => {
resReg must not be a special IFU register, so we use FastRegStore here.
IF WillEUStackOverflow[]
THEN CauseTrap[EUStackOverflowTrap]
ELSE FastRegStore[resReg, resWord];
};
aluDone => {
SELECT
TRUE
FROM
trapCode # NoFault => CauseTrap[trapCode];
WillEUStackOverflow[] => CauseTrap[EUStackOverflowTrap];
ENDCASE => FastRegStore[resReg, resWord];
};
memFault => {
CauseTrap[trapCode];
};
memFetch => {
IF WillEUStackOverflow[]
THEN CauseTrap[EUStackOverflowTrap]
ELSE {
[resWord, trapCode] ← MemFetch[resAddr];
SELECT
TRUE
FROM
trapCode # NoFault => CauseTrap[trapCode];
ENDCASE => {FastRegStore[resReg, resWord]; processor.euBusyReg ← resReg};
};
};
memFetchAlpha => {
IF WillEUStackOverflow[]
THEN CauseTrap[EUStackOverflowTrap]
ELSE {
[resWord, trapCode] ← MemFetch[AddDelta[alphaZ, resAddr]];
SELECT
TRUE
FROM
trapCode # NoFault => CauseTrap[trapCode];
ENDCASE => {FastRegStore[resReg, resWord]; processor.euBusyReg ← resReg};
};
};
memStore => {
SELECT
TRUE
FROM
WillEUStackOverflow[] =>
CauseTrap[EUStackOverflowTrap];
ENDCASE => {
trapCode ← MemStore[resAddr, resWord];
IF trapCode # NoFault THEN CauseTrap[trapCode];
};
};
memStoreAlpha => {
resAddr ← AddDelta[alphaZ, resAddr];
SELECT
TRUE
FROM
WillEUStackOverflow[] =>
CauseTrap[EUStackOverflowTrap];
ENDCASE => {
trapCode ← MemStore[resAddr, resWord];
IF trapCode # NoFault THEN CauseTrap[trapCode];
};
};