Global:
PROC[name: Rope.
ROPE, label: Label]
RETURNS[Label] =
{MakeLabelGlobal[name, label]; RETURN[label]};
StackedStatusToWord:
PROC
[ s: DragOpsCross.StackedStatusWord, sense: {normal, complemented} ← normal ]
RETURNS [ w: DragOpsCross.Word ] = TRUSTED
{w ← LOOPHOLE[s]; IF sense = complemented THEN w ← DragOpsCrossUtils.DragNot[w]};
GenEnableTraps:
PROC
RETURNS [
enableTraps: Label ] = {
enableTraps ← GenLabelHere[];
drLIQB[StackedStatusToWord[[trapsEnabled: TRUE]]];
drLIP[DragOpsCross.ProcessorRegister[ifuYoungestL].ORD];
drOR[];
drSIP[DragOpsCross.ProcessorRegister[ifuYoungestL].ORD];
drRETN[]};
GenLSUnderflowKernel:
PROC
RETURNS [
lsUnderflowKernel: Label ] = {
UnderflowHandler must have been set.
underflowTrap: Label;
lsUnderflowKernel ← GenLabelHere[];
-- one frame on IFU stack
drLIB[sLimitValue];
drSIP[DragOpsCross.ProcessorRegister[ifuSLimit].ORD];
GetEldestPC[]; -- pops IFU stack to EU stack top
drSFC[]; -- Call caller's return PC (underflowTrap pushed onto IFU stack)
underflowTrap ← GenLabelHere[];
-- no frames on stack
drROR[c: pushDst, a: const0, b: underflowHandler];
drSFC[];
drJB[UseLabel8A[underflowTrap]]};
SetSizeForStandardTrapInstr:
PROC[instr: DragOpsCross.Inst] = {
drLIB[InstToBytes[instr]];
drROR[c: instrSize, a: popSrc, b: const0]};
GenStandardTrap:
PROC
RETURNS [ standardTrap: Label ] = {
Returns to successor of faulting instr.
InstrSize must have been set to the faulting instruction size
standardTrap ← GenLabelHere[];
drRADD[c: pushDst, a: const0, b: const0]; -- save carry on stack
GetYoungestPC[];
drRVADD[c: topDst, a: instrSize, b: topSrc];
SetYoungestPC[];
drRUADD[c: topDst, a: popSrc, b: constN1]; -- restore carry, toss result
drRETN[]};
GenCallerTrap:
PROC
RETURNS [
callerTrap: Label ] = {
Enters with faulting instr on ifu stack top and caller of faulting instr underneath.
Object is to replace faulting instr pc with that of ReturnPatch, do a return to ReturnPatch, which then returns to the caller.
ReturnPatch: Label;
callerTrap ← GenLabelHere[];
drLIQB[StackedStatusToWord[[trapsEnabled: TRUE], complemented]];
drLIP[DragOpsCross.ProcessorRegister[ifuYoungestL].ORD];
drAND[]; -- clear trapsEnabled
drSIP[DragOpsCross.ProcessorRegister[ifuYoungestL].ORD];
drLIQB[UseLabel32[ReturnPatch ← GenLabel[]]];
SetYoungestPC[]; -- move caller's PC to within our trap handler
drRETN[];
SetLabel[ReturnPatch];
drRETN[]};
GenXOPTrap:
PROC
RETURNS [ xopTrap: Label ] = {
xopTrap ← GenLabelHere[];
drRETN[]};
GenKFCTrap:
PROC
RETURNS [
kfcTrap: Label ] = {
kfcTrap ← GenLabelHere[];
drLIP[DragOpsCross.ProcessorRegister[ifuYoungestL].ORD];
drSIP[DragOpsCross.ProcessorRegister[ifuYoungestL].
ORD];
.. something innocuous that's illegal in user mode
drRETN[]};
GenReschedTrap:
PROC
RETURNS [
reschedTrap: Label ] = {
reschedTrap ← GenLabelHere[];
drRETN[]};
FillTrap:
PROC [ trap: DragOpsCross.TrapIndex, label: Label ] = {
oldPC: LONG CARDINAL = GetOutputPC[];
SetOutputPC[DragOpsCrossUtils.TrapIndexToBytePC[trap]];
drJDB[UseLabel16[label]]; -- go to trap handler
SetOutputPC[oldPC]};
FillXOP:
PROC [ inst: DragOpsCross.Inst, label: Label ] = {
oldPC: LONG CARDINAL = GetOutputPC[];
SetOutputPC[DragOpsCrossUtils.XopToBytePC[inst]];
drJDB[UseLabel16[label]]; -- go to trap handler
SetOutputPC[oldPC]};
M A I N L I N E C O D E
area: Area = GetCurrentArea[];
curPC: CARD;
sLimitValue: [0..128) = 16;
EnableTraps: Label = Global["EnableTraps", GenEnableTraps[]];
LSUnderflowKernel: Label = Global["LSUnderflowKernel", GenLSUnderflowKernel[]];
StandardTrap: Label = Global["StandardTrap", GenStandardTrap[]];
CallerTrap: Label = Global["CallerTrap", GenCallerTrap[]];
XopTrap: Label = Global["XopTrap", GenXOPTrap[]];
KFCTrap: Label = Global["KFCTrap", GenKFCTrap[]];
ReschedTrap: Label = Global["ReschedTrap", GenReschedTrap[]];
Data: Label = Global["Data", GenLabel[]];
SFCITarget: Label = Global["SFCITarget", GenLabel[]];
SFCITargetLocM4wds: Label = Global["SFCITargetLocM4wds", GenLabel[]];
Start: Label = Global["Start", GenLabel[]];
ALUOverflow: Label = Global["ALUOverflow", GenLabel[]];
ALUOverflowWCry: Label = Global["ALUOverflowWCry", GenLabel[]];
CondJumps: Label = Global["CondJumps", GenLabel[]];
CondJump0: Label = Global["CondJump0", GenLabel[]];
CondJump1: Label = Global["CondJump1", GenLabel[]];
CondJump2: Label = Global["CondJump2", GenLabel[]];
CondJump3: Label = Global["CondJump3", GenLabel[]];
IncompleteLIQB: Label = Global["IncompleteLIQB", GenLabel[]];
EUPageFaultCode: Label = Global["EUPageFaultCode", GenLabel[]];
EUPageFaultContinue: Label = Global["EUPageFaultContinue", GenLabel[]];
SFCITest: Label = Global["SFCITest", GenLabel[]];
SFCIPageFaultContinue: Label = Global["SFCIPageFaultContinue", GenLabel[]];
FaultingLocation: Label = Global["FaultingLocation", GenLabel[]];
CSTProcedure: Label = Global["CSTProcedure", GenLabel[]];
CSTPageFaultReturn: Label = Global["CSTPageFaultReturn", GenLabel[]];
CST0: Label = Global["CST0", GenLabel[]];
CST1: Label = Global["CST1", GenLabel[]];
CST2: Label = Global["CST2", GenLabel[]];
CST3: Label = Global["CST3", GenLabel[]];
SLimitProcedure0: Label = Global["SLimitProcedure0", GenLabel[]];
SLimitProcedure1: Label = Global["SLimitProcedure1", GenLabel[]];
SLimitEnd: Label = Global["SLimitEnd", GenLabel[]];
IFUUnderFlowReturn: Label = Global["IFUUnderFlowReturn", GenLabel[]];
IFUOverExit: Label = Global["IFUOverExit", GenLabel[]];
IFUOverNext: Label;
XOPBegin: Label = Global["XOPBegin", GenLabel[]];
XOPExit: Label = Global["XOPExit", GenLabel[]];
KernalToUserJmp: Label = Global["KernalToUserJmp", GenLabel[]];
KernalToUserMode: Label = Global["KernalToUserMode", GenLabel[]];
FillTrap[IFUPageFaultTrap, CallerTrap ];
FillTrap[EUPageFault, CallerTrap ];
FillTrap[IFUStackOverflowTrap, CallerTrap ];
FillTrap[EUStackOverflowTrap, CallerTrap ];
FillTrap[ALUCondOver, StandardTrap ];
FillTrap[ModeFault, StandardTrap ];
FillTrap[MemAccessFault, StandardTrap ];
FillTrap[IOAccessFault, StandardTrap ];
FillTrap[RescheduleTrap, ReschedTrap ];
FillTrap[ResetTrap, Start ];
FOR inst: DragOpsCross.Inst
IN DragOpsCross.Inst
DO
FillXOP[inst: inst, label: (IF inst=dKFC THEN KFCTrap ELSE XopTrap)];
ENDLOOP;
Data
Set up Data area
WHILE GetOutputPC[area]
MOD 4*DragOpsCross.bytesPerWord # 0
DO
Align to quadword boundary
OutputByte[area, CardToByte[0]];
ENDLOOP;
SetLabel[
Data ];
[] ← ReserveData[words: 16];
SetLabel[
SFCITargetLocM4wds ];
THROUGH [0..3) DO OutputWord[area, IntToWord[0]] ENDLOOP;
THROUGH [0..3) DO OutputByte[area, CardToByte[0]] ENDLOOP;
drLIQB[UseLabel32[ SFCITarget ]];
.. it would be nice if there were a way of generating a byte-address and word-address Data word
Start
SetLabel[ Start ]; -- gets here from reset in kernel mode with traps off
Set up EU SLimit and install IFU stack underflow service routine (kernel mode, traps off)
drLFC[UseLabel16[ LSUnderflowKernel ]];
Set up some constant registers
drRSUB[ c: constN1, a: const0, b: const1];
drRADD[ c: constN2, a: constN1, b: constN1];
drLC1[];
drLIQB[CardToWord[FieldDescriptorToCard[[insert: FALSE, mask: 32, shift: 31]]]];
drFSDB[0]; -- Load field unit control
drRFU[c: constNI, a: popSrc, b: const0]; -- 80000000x
Enable traps
drLFC[UseLabel16[ EnableTraps ]]; -- inst 12
ALU Overflow
SetLabel[
ALUOverflow ];
drRADD[c: pushDst, a: const0, b: const0]; -- clear carry
drDIS[];
drRADD[c: pushDst, a: constNI, b: const0]; -- shouldn't overflow
drDIS[];
SetSizeForStandardTrapInstr[dRADD];
drRADD[c: pushDst, a: constNI, b: constN1]; -- should overflow
drDIS[];
drRADD[c: pushDst, a: const0, b: const0]; -- show carry
drDIS[];
SetLabel[
ALUOverflowWCry ];
drRUADD[c: pushDst, a: constN1, b: constN1]; -- set carry
drDIS[];
drRADD[c: pushDst, a: constNI, b: constN1]; -- shouldn't overflow
drDIS[];
drRUADD[c: pushDst, a: constN1, b: constN1]; -- set carry
drDIS[];
SetSizeForStandardTrapInstr[dRADD];
drRADD[c: pushDst, a: constNI, b: constN2]; -- should fail
drDIS[];
drRADD[c: pushDst, a: const0, b: const0]; -- show carry
drDIS[];
Conditional Jumps
SetLabel[
CondJumps ];
drRJEBJ[ left: const0, right: const0, dist: UseLabel8B[ CondJump1 ]];
drDIS[];
Halt[113];
SetLabel[
CondJump0 ];
drDIS[];
Halt[114];
SetLabel[
CondJump1 ];
drRJNEBJ[ left: const0, right: const0, dist: UseLabel8B[ CondJump0 ]];
drRJEB[ left: const0, right: const0, dist: UseLabel8B[ CondJump3]];
drDIS[];
Halt[115];
SetLabel[
CondJump2 ];
drDIS[];
Halt[116];
SetLabel[
CondJump3 ];
drRJNEB[ left: const0, right: const0, dist: UseLabel8B[ CondJump2]];
drJ1[];
IFU page faulting.
drLFC[UseLabel16[ IncompleteLIQB ]];
EU Page Fault.
drLFC[UseLabel16[ EUPageFaultCode]];
drJDB[UseLabel16[ EUPageFaultContinue]];
SetLabel[
EUPageFaultCode];
drLIB[0];
drSIP[DragOpsCross.ProcessorRegister[euMAR].ORD]; -- clear euMAR
drLIQB[UseLabel32[ IncompleteLIQB ]];
drSHR[FieldDescriptorToCard[[mask: 32-2, shift: 32-2]]]; -- byte to word address
WHILE GetOutputPC[area]
MOD DragOpsCross.bytesPerWord # 3
DO
drJ1[]; -- Align with respect to word boundary
ENDLOOP;
drRB[20]; -- generates page fault, sets euMAR to faulting address
drRADD[c: pushDst, a: constNI, b: constNI]; -- generates arithmetic overflow
Halt[131]; -- should never get here
SetLabel[
EUPageFaultContinue ];
drLIP[DragOpsCross.ProcessorRegister[euMAR].ORD]; -- show euMAR
drDIS[];
Test SFCI with rejects
SetLabel[
SFCITest ];
drLIQB[UseLabel32[ SFCITargetLocM4wds ]];
drSHR[FieldDescriptorToCard[[mask: 32-2, shift: 32-2]]]; -- byte to word address
drDUP[];
drLIB[4];
drWSB[0]; -- force prior reject
drADDB[4];
drSFCI[]; -- force reject within SFCI
drJDB[UseLabel16[ SFCIPageFaultContinue ]];
SetLabel[
SFCITarget ];
drLIQB[UseLabel32[ FaultingLocation ]]; -- as if there were a Data word here
drSHR[FieldDescriptorToCard[[mask: 30, shift: 32-2]]]; -- byte to word address
drSFCI[]; -- generates page fault, sets euMAR to faulting address
drRADD[c: pushDst, a: constNI, b: constNI]; -- generates arithmetic overflow
Halt[134];
SetLabel[
SFCIPageFaultContinue ];
drLIP[DragOpsCross.ProcessorRegister[euMAR].ORD]; -- show euMAR
drDIS[];
Test conditional store
drLFC[UseLabel16[ CSTProcedure ]];
drJDB[UseLabel16[ CSTPageFaultReturn ]];
ProcedureEntry[label:
CSTProcedure, args: 0];
drLIQB[UseLabel32[ Data ]];
drSHR[FieldDescriptorToCard[[mask: 30, shift: 32-2]]]; -- byte to word address
drLIB[1];
drSRIn[reg0, 0];
drLIB[2]; -- proposed new value
drLIB[1]; -- proposed old value
drCST[0]; -- should succeed
drJEBBJ[lit: 1, dist: UseLabel8B[ CST0 ]]; -- sampled value
Halt[141];
SetLabel[
CST0 ];
drLRIn[reg0, 0];
drJEBBJ[lit: 2, dist: UseLabel8B[ CST1 ]];
Halt[143];
SetLabel[
CST1 ];
drDIS[];
drDIS[];
drLIB[3]; -- proposed new value
drLIB[1]; -- proposed old value
drCST[0]; -- should fail
drJEBBJ[lit: 2, dist: UseLabel8B[ CST2 ]]; -- sampled value
Halt[144];
SetLabel[
CST2 ];
drLRIn[reg0, 0];
drJEBBJ[lit: 2, dist: UseLabel8B[ CST3 ]];
Halt[146];
SetLabel[
CST3 ];
drDIS[];
drDIS[];
drDIS[];
Skip over this CST[#0] test until it gets implemented
drLIQB[UseLabel32[ IncompleteLIQB ]];
drSHR[FieldDescriptorToCard[[mask: 30, shift: 32-2]]]; -- byte to word address
drLIB[3]; -- proposed new value
drLIB[1]; -- proposed old value
WHILE GetOutputPC[area]
MOD DragOpsCross.bytesPerWord # DragOpsCross.bytesPerWord-1
DO
drJ1[]; -- Align to last byte in a word
ENDLOOP;
drCST[20]; -- generates page fault
drRADD[c: pushDst, a: constNI, b: constNI]; -- generates arithmetic overflow
Halt[147]; -- should never get here
SetLabel[
CSTPageFaultReturn ];
drLIP[DragOpsCross.ProcessorRegister[euMAR].ORD]; -- show euMAR
drDIS[];
drDIS[];
drDIS[];
drDIS[];
SetLabel[ CSTPageFaultReturn ];
drDIS[];
drDIS[];
drDIS[];
Test S register limiting.
drLFC[UseLabel16[ SLimitProcedure0 ]];
drJDB[UseLabel16[ SLimitEnd ]];
ProcedureEntry[label:
SLimitProcedure0, args: 0];
drLFC[UseLabel16[ SLimitProcedure1 ]];
ProcedureExit[rets: 0];
SetLabel[
SLimitProcedure1 ];
drLIB[0];
FOR i: [0..32)
IN [0..32)
DO
Halt[151]; -- should have trapped on EU overflow by now
Test manual IFU stack entry and underflow.
drLIQB[UseLabel32[ IFUUnderFlowReturn ]];
drROR[c: underflowHandler, a: const0, b: popSrc];
drRETN[];
SetLabel[
IFUUnderFlowReturn ];
drLFC[UseLabel16[ EnableTraps ]]; -- underflow handler sends control w/ traps off
Test IFU stack overflow.
drLFC[UseLabel16[ IFUOverNext ← GenLabel[] ]];
drJDB[UseLabel16[ IFUOverExit ]];
FOR level: [2..11)
IN [2..11)
DO
SetLabel[
IFUOverNext ];
drLFC[UseLabel16[ IFUOverNext ← GenLabel[] ]];
SetLabel[
IFUOverNext ];
drLFC[UseLabel16[ IFUOverNext ← GenLabel[] ]]; -- BOOM! - zzzzzzzzzzzzzzzzzz
Halt[161];
SetLabel[
IFUOverNext ];
Halt[162]; -- too deep
SetLabel[ IFUOverExit ];
XOP
SetLabel[
XOPBegin ];
OutputByte[NIL, CardToByte[1B]]; -- one-byte XOP
OutputByte[NIL, CardToByte[077B]]; -- five-byte XOP
OutputAlphaBetaGammaDelta[NIL, CardToWord[12345678H]]; -- this gets pushed
drLIQB[CardToWord[12345678H]];
drRJEBJ[left: popSrc, right: belowSrcPop, dist: UseLabel8B[ XOPExit ]];
Halt[191];
SetLabel[ XOPExit ];
Switch to user mode
drJDB[UseLabel16[ KernalToUserJmp ]];
SetLabel[
KernalToUserMode ];
-- kernel mode => user mode
drLIQB[StackedStatusToWord[[userMode: TRUE, trapsEnabled: TRUE], complemented]];
drLIP[DragOpsCross.ProcessorRegister[ifuYoungestL].ORD];
drAND[];
drLIQB[StackedStatusToWord[[userMode: TRUE, trapsEnabled: TRUE]]];
drOR[];
drSIP[DragOpsCross.ProcessorRegister[ifuYoungestL].ORD];
drRETN[];
SetLabel[
KernalToUserJmp ];
SetSizeForStandardTrapInstr[ dROR ]; -- 3, LIPs and SIPs need J1 after
drLFC[UseLabel16[ KernalToUserMode ]];
Try several kernel-only instructions from user mode
drLIB[1]; -- for the store, never used
drSIP[07FH]; -- ModeFault
drJ1[]; -- skipped on trap return
drDIS[]; -- the 1 above
drLIP[1];
drDIS[];
drLIP[DragOpsCross.ProcessorRegister[ifuEldestPC].ORD]; -- Mode Fault
drJ1[]; -- skipped on trap return
drROR[c: const1, a: const0, b: const0]; -- Mode Fault
drKFC[]; -- test KFC
drROR[c: [aux[0]], a: const0, b: const0]; -- Mode Fault
drROR[c: [aux[15]], a: const0, b: const0]; -- Mode Fault
End of test
Halt[0FFFFH]; -- end of test
Instruction sequence for IFU page fault test...
{
bpp: NAT ← DragOpsCross.bytesPerPage;
curPC ← GetOutputPC[area];
SetOutputPC[curPC+((2*bpp-4-(curPC MOD bpp)) MOD bpp), area];
SetLabel[
IncompleteLIQB ];
OutputByte[area, CardToByte[DragOpsCross.Inst[dLIQB].ORD]]; -- 4 bytes in this page
OutputByte[area, CardToByte[1]];
OutputByte[area, CardToByte[2]];
OutputByte[area, CardToByte[3]]; -- Aprez moi, le faux page!
SetLabel[ FaultingLocation ]};
};