GenBasics.mesa
Copyright © 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) June 2, 1987 3:57:55 pm PDT
McCreight, January 8, 1986 4:52:12 pm PST
GenBasics provides the following utilities:
Register initialization at processor reset.
Basics.SetStatus []
Sets the status & L (provided that one is in kernel mode).
Basics.SetVectorConstant [addr: PTR, len: INT, word: Word]
Fills a vector (starts at addr for len words) with a constant word.
Basics.MoveVector [src: PTR, len: INT, dst: PTR]
Moves words in increasing order.
Basics.AllocVector [len: INT]
Permanently allocates a vector in kernel space.
Basics.MixedMultiply [X: CARD, Y: INT] RETURNS [INT]
Basics.IntMultiply [X,Y: INT] RETURNS [INT]
Basics.FatCardMultiply [X,Y: CARD] RETURNS [hi,lo: CARD]
Basics.CardMultiply [X,Y: CARD] RETURNS [hi,lo: CARD]
Basics.CardDivide [X,Y: CARD] RETURNS [CARD]
DIRECTORY
DragOpsCross,
DragOpsCrossUtils,
HandCoding,
HandCodingPseudos,
HandCodingSupport;
GenBasics: CEDAR PROGRAM
IMPORTS DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport
= BEGIN OPEN DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport;
Word: TYPE = DragOpsCross.Word;
ZerosWord: Word = DragOpsCross.ZerosWord;
bytesPerWord: CARDINAL = DragOpsCross.bytesPerWord;
wordsPerPage: CARDINAL = DragOpsCross.wordsPerPage;
globalBase: LONG CARDINAL;
globalBaseWord: Word;
initialPages: INT ← 64;
gAllocPtr: NAT = 2;
onlyROM0: BOOLFALSE;
All: PROC = {
FillTrap: PROC [tx: DragOpsCross.TrapIndex, dest: Label] = {
oldPC: LONG CARDINAL = GetOutputPC[area];
SetOutputPC[DragOpsCrossUtils.TrapIndexToBytePC[tx]];
drJDB[UseLabel16[dest]];
SetOutputPC[oldPC];
};
FillXop: PROC [inst: DragOpsCross.Inst, dest: Label] = {
oldPC: LONG CARDINAL = GetOutputPC[area];
SetOutputPC[DragOpsCrossUtils.XopToBytePC[inst]];
drJDB[UseLabel16[dest]];
SetOutputPC[oldPC];
};
area: Area = GetCurrentArea[];
start: Label = GenLabel[];
dummy: Label = GenLabel[];
startUser: Label = GenLabel[];
initL: Label = GenLabel[];
procSetVectorConstant: Label = GenLabel[];
procMoveVector: Label = GenLabel[];
procAllocVector: Label = GenLabel[];
globalBase ← ReserveData[initialPages*wordsPerPage] / bytesPerWord;
globalBaseWord ← CardToWord[globalBase];
SetLabel[start];
This is the location where Reset comes to. The registers need initialization.
IF onlyROM0 THEN {
early versions of the EU only had const0 in ROM
drLIB[1]; drROR[c: const1, a: const0, b: popSrc];
drRVADD[c: const2, a: const1, b: const1];
drRVADD[c: const3, a: const2, b: const1];
};
drRVADD[c: const4, a: const3, b: const1];
drRVSUB[c: constN2, a: const0, b: const2];
drRVSUB[c: constN1, a: const0, b: const1];
drLIDB[100000B]; drROR[c: constNSI, a: const0, b: popSrc];
drLC1[]; drSHL[FieldDescriptorToCard[[insert: FALSE, mask: 32, shift: 31]]];
drROR[c: constNI, a: const0, b: popSrc];
drLIQB[globalBaseWord];
drROR[c: global, a: const0, b: topSrc]; -- the base of global data
drDUP[];
drADDDB[wordsPerPage]; -- don't allocate in the first page
drWSB[gAllocPtr];  -- set the allocation pointer
FOR i: NAT IN [1..15] DO
drROR[c: [aux[i]], a: const0, b: const0];
ENDLOOP;
drLFC[UseLabel16[initL]];
We use this method to initialize L to 1
drASL[255];
When there is nothing on the stack, S should be at L-1
drLIB[16]; drLFC[UseLabel16[procAllocVector]]; drROR[process, const0, popSrc];
Allocate a dummy (non-NIL) process object
drLIB[16]; drLFC[UseLabel16[procAllocVector]]; drROR[processor, const0, popSrc];
Allocate a dummy (non-NIL) processor object
drJDB[UseLabel16[startUser]];
GenStatusHacks[];
GenSetVectorConstant[procSetVectorConstant];
GenMoveVector[procMoveVector];
GenAllocVector[procAllocVector];
GenMultiply[];
GenFindShift[];
GenDivide[];
ProcedureEntry[initL, 0];
drLC1[];
SetYoungestStatus[]; -- L ← 1 on return
drLIB[128-16-1]; -- spLimit is set with room for 17 overflow words (just in case)
SetSPLimit[];
ProcedureExit[0];
WordAlign[area];
SetLabel[startUser];
Control flow falls through to the next file that gets generated. Typically, GenStack follows GenBasics, and other programs follow GenStack. Note that there should be no frames on the IFU stack when we fall through.
MakeLabelGlobal["Basics.ExitToGenStack", startUser];
FillTrap[ResetTrap, start];
};
GenStatusHacks: PROC = {
Enables traps, provided the caller was in kernel mode. Minimum cost: 16 cycles.
entryLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 1];
MakeLabelGlobal["Basics.SetStatus", entryLabel];
SetYoungestStatus[];
ProcedureExit[0];
};
GenSetVectorConstant: PROC [entryLabel: Label] = {
addrLocal: RegSpec = reg0;
lenLocal: RegSpec = reg1;
wordLocal: RegSpec = reg2;
finishLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 3];
MakeLabelGlobal["Basics.SetVectorConstant", entryLabel];
drLRn[lenLocal];
drRJLBJ[left: topSrc, right: const4, dist: UseLabel8B[finishLabel]];
{loopLabel: Label = GenLabelHere[];
exitLabel: Label = GenLabel[];
drSUBB[4];
drWRI[wordLocal, addrLocal, 0];
drWRI[wordLocal, addrLocal, 1];
drWRI[wordLocal, addrLocal, 2];
drWRI[wordLocal, addrLocal, 3];
drRVADD[c: addrLocal, a: addrLocal, b: const4];
drRJGEBJ[left: topSrc, right: const4, dist: UseLabel8B[loopLabel]];
SetLabel[finishLabel];
drRJLEB[left: topSrc, right: const0, dist: UseLabel8B[exitLabel]];
drWRI[wordLocal, addrLocal, 0];
drRJLEB[left: topSrc, right: const1, dist: UseLabel8B[exitLabel]];
drWRI[wordLocal, addrLocal, 1];
drRJLEB[left: topSrc, right: const2, dist: UseLabel8B[exitLabel]];
drWRI[wordLocal, addrLocal, 2];
SetLabel[exitLabel];
};
ProcedureExit[0];
};
GenMoveVector: PROC [entryLabel: Label] = {
srcLocal: RegSpec = reg0;
lenLocal: RegSpec = reg1;
dstLocal: RegSpec = reg2;
finishLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 3];
MakeLabelGlobal["Basics.MoveVector", entryLabel];
drLRn[lenLocal];
drRJLBJ[left: topSrc, right: const4, dist: UseLabel8B[finishLabel]];
{loopLabel: Label = GenLabelHere[];
exitLabel: Label = GenLabel[];
drSUBB[4];
drLRIn[srcLocal, 0];
drLRIn[srcLocal, 1];
drLRIn[srcLocal, 2];
drLRIn[srcLocal, 3];
drRVADD[c: srcLocal, a: srcLocal, b: const4];
drSRIn[dstLocal, 3];
drSRIn[dstLocal, 2];
drSRIn[dstLocal, 1];
drSRIn[dstLocal, 0];
drRVADD[c: dstLocal, a: dstLocal, b: const4];
drRJGEBJ[left: topSrc, right: const4, dist: UseLabel8B[loopLabel]];
SetLabel[finishLabel];
drRJLEB[left: topSrc, right: const0, dist: UseLabel8B[exitLabel]];
drLRIn[srcLocal, 0];
drSRIn[dstLocal, 0];
drRJLEB[left: topSrc, right: const1, dist: UseLabel8B[exitLabel]];
drLRIn[srcLocal, 1];
drSRIn[dstLocal, 1];
drRJLEB[left: topSrc, right: const2, dist: UseLabel8B[exitLabel]];
drLRIn[srcLocal, 2];
drSRIn[dstLocal, 2];
SetLabel[exitLabel];
};
ProcedureExit[0];
};
GenAllocVector: PROC [entryLabel: Label] = {
lenLocal: RegSpec = reg0;
G: RegSpec = reg1;
ProcedureEntry[entryLabel, 1];
MakeLabelGlobal["Basics.AllocVector", entryLabel];
drLIQB[globalBaseWord];
drLRIn[G, gAllocPtr];
drRVADD[pushDst, lenLocal, topSrc];
drSRIn[G, gAllocPtr];
drSRn[lenLocal];
ProcedureExit[1];
};
Multiply & Divide routines
GenMultiply: PROC [] = {
accum: RegSpec = reg0; -- initially holds X, will hold return value
entryLabel: Label = GenLabel[];
exitLabel: Label = GenLabel[];
exit0Label: Label = GenLabel[];
positiveLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 2];
MakeLabelGlobal["Basics.MixedMultiply", entryLabel];
MixedMultiply: PROC [X: CARD, Y: INT] RETURNS [INT];
SetLabel[positiveLabel];
drLIB[17B];
drLIB[3*15+1];
drLRn[accum];
drROR[accum, const0, const0];
{
localY: RegSpec = reg1; -- holds Y
mask: RegSpec = reg2; -- holds 17B as a mask
width: RegSpec = reg3; -- holds 3*15+1 as the table width
localX: RegSpec = reg4; -- holds X
loopEntry: Label = GenLabel[];
loopTop: Label = GenLabel[];
drJB[UseLabel8A[loopEntry]];
SetLabel[loopTop];
drRADD[localY, localY, localY];
drRADD[localY, localY, localY];
drRADD[localY, localY, localY];
drRADD[localY, localY, localY];
SetLabel[loopEntry];
drRAND[pushDst, mask, localX];
drRSUB[pushDst, width, topSrc];
drQSUB[topAtop, belowSrc];
drRSUB[belowDst, popSrc, belowSrc];
drJSR[];
THROUGH [0..15) DO
drRADD[accum, accum, localY];
ENDLOOP;
ExtractField[first: 0, bits: 32-4];
drRJNEBJ[left: topSrc, right: const0, dist: UseLabel8B[loopTop]];
ProcedureExit[1];
};
{
This is the routine for full signed multiply. For non-negative X we just join the HalfSignedMultiply routine. For negative X > FIRST[INT] we negate X, multiply, and negate the result. For X = FIRST[INT] we test for Y = 0 (return 0) and Y = 1 (return X), otherwise we always overflow. NOTE: we also make sure that if both numbers are positive that we place the smaller number in X and the larger number in Y.
otherLabel: Label = GenLabel[];
specialLabel: Label = GenLabel[];
negateLabel: Label = GenLabel[];
negXlabel: Label = GenLabel[];
ProcedureEntry[otherLabel, 2];
MakeLabelGlobal["Basics.IntMultiply", otherLabel];
IntMultiply: PROC [X: INT, Y: INT] RETURNS [INT];
drRJGB[left: const0, right: reg0, dist: UseLabel8B[negXlabel]];
For X < 0, go handle it the hard way
drRJGB[left: const0, right: reg1, dist: UseLabel8B[positiveLabel]];
For X >= 0 & Y < 0, just branch to the positive entry
drRJGEB[left: topSrc, right: belowSrc, dist: UseLabel8B[positiveLabel]];
For X >= 0 & Y >= 0 & X <= Y, just branch to the positive entry
Exchange X and Y, then branch to the positive entry
drRXOR[topDst, topSrc, belowSrc];
drRXOR[belowDst, topSrc, belowSrc];
drRXOR[topDst, topSrc, belowSrc];
drJB[UseLabel8A[positiveLabel]];
SetLabel[negXlabel];
drLRn[reg0];
drRJEB[left: popSrc, right: constNI, dist: UseLabel8B[specialLabel]];
For special X (FIRST[INT]), go do some more tests
drRSUB[reg0, const0, reg0];
negate X to get a positive number
drLFC[UseLabel16[entryLabel]];
Call the multiply routine with -X and Y
SetLabel[negateLabel];
drRSUB[reg0, const0, reg0];
Negate (may get overflow) the result
ProcedureExit[1];
SetLabel[specialLabel];
At this point we know that X = LAST[INT], so the only thing that can't overflow is Y = 0 or Y = 1. Note that Y is on top of the stack, which makes testing easier.
drRJEB[left: topSrc, right: const1, dist: UseLabel8B[exitLabel]];
Y = 1 => the identity
drRJNEB[left: topSrc, right: const0, dist: UseLabel8B[negateLabel]];
Y # 0 => negate (to get overflow) & return
};
SetLabel[exit0Label];
drROR[reg0, const0, const0];
Return 0
SetLabel[exitLabel];
ProcedureExit[1];
{
thinCardLabel: Label = GenLabel[];
fatCardLabel: Label = GenLabel[];
lo: RegSpec = reg0; -- holds lo-order result word
hi: RegSpec = reg1; -- holds hi-order result word
yLo: RegSpec = reg2; -- holds lo-order part of Y
yHi: RegSpec = reg3; -- holds hi-order part of Y
localX: RegSpec = reg4; -- holds X
ProcedureEntry[fatCardLabel, 2];
MakeLabelGlobal["Basics.FatCardMultiply", fatCardLabel];
FatCardMultiply: PROC [X: CARD, Y: CARD] RETURNS [hi,lo: CARD];
drLRn[reg1];  -- push Y
drLC0[];   -- init hi-order part of Y
drLRn[reg0];  -- push X
drROR[hi, const0, const0];
drROR[lo, const0, const0];
{
loopEntry: Label = GenLabel[];
loopTop: Label = GenLabel[];
noAddLabel: Label = GenLabel[];
drRJNEBJ[left: topSrc, right: const0, dist: UseLabel8B[loopEntry]];
ProcedureExit[1];
SetLabel[loopTop];
drRUADD[yLo, yLo, yLo];
drRUADD[yHi, yHi, yHi];
SetLabel[loopEntry];
drQAND[pushA1, localX];
drJEBB[0, UseLabel8B[noAddLabel]];
drRUADD[lo, lo, yLo];
drRUADD[hi, hi, yHi];
SetLabel[noAddLabel];
ExtractField[first: 0, bits: 31];
drRJNEBJ[left: topSrc, right: const0, dist: UseLabel8B[loopTop]];
};
ProcedureExit[2];
CardMultiply: PROC [X: CARD, Y: CARD] RETURNS [CARD];
ProcedureEntry[thinCardLabel, 2];
MakeLabelGlobal["Basics.CardMultiply", thinCardLabel];
drLFC[UseLabel16[fatCardLabel]];
drRJEBJ[left: topSrc, right: const0, dist: UseLabel8B[exitLabel]];
Test for overflow by testing the high-order word
At this point we have an overflow, so force the trap
drRADD[pushDst, constNI, constNI];
ProcedureExit[1];
};
};
GenFindShift: PROC = {
X: CARD ← ...;
shift: NAT ← 0;
probe: NAT ← 32;
WHILE probe # 0 DO
bits: NAT ← shift + (probe ← probe / 2);
IF DoubleShiftLeft[0, ln, bits] # 0 THEN {
shift ← shift + probe;
IF LOOPHOLE[DoubleShiftLeft[ln, 0, shift], INT] < 0 THEN EXIT;
};
ENDLOOP;
RETURN [shift];
entryLabel: Label = GenLabel[];
exitLabel: Label = GenLabel[];
loopLabel: Label = GenLabel[];
rX: RegSpec = reg0;
rShift: RegSpec = reg1;
rProbe: RegSpec = reg2;
ProcedureEntry[entryLabel, 1];
MakeLabelGlobal["Basics.FindShift", entryLabel];
drLC0[];
drLIB[32];
SetLabel[loopLabel];
drRJEB[const0, topSrc, UseLabel8B[exitLabel]];
ExtractField[first: 0, bits: 31];
drQADD[pushAtop, rShift];
drFSDB[FieldDescriptorToCard[ [mask: 32, shift: 0] ]];
drRFU[pushDst, const0, rX];
drRJNEB[popSrc, const0, UseLabel8B[loopLabel]];
drRADD[rShift, rShift, topSrc];
drRFU[pushDst, const0, rX];
drRJGEBJ[popSrc, const0, UseLabel8B[loopLabel]];
SetLabel[exitLabel];
drROR[reg0, rShift, const0];
ProcedureExit[1];
};
InlineFindShift: PROC [rX: RegSpec] = {
exitLabel: Label = GenLabel[];
loopLabel: Label = GenLabel[];
drLC0[];
We will leave the shift distance on the stack
drLIB[32];
The probe starts out at 32, then keeps halving
SetLabel[loopLabel];
drRJEB[const0, topSrc, UseLabel8B[exitLabel]];
ExtractField[first: 0, bits: 31];
drQADD[pushAtop, belowSrc];
drFSDB[FieldDescriptorToCard[ [mask: 32, shift: 0] ]];
drRFU[pushDst, const0, rX];
drRJNEB[popSrc, const0, UseLabel8B[loopLabel]];
drRADD[belowDst, belowSrc, topSrc];
drRFU[pushDst, const0, rX];
drRJGEBJ[popSrc, const0, UseLabel8B[loopLabel]];
SetLabel[exitLabel];
drDIS[];
Discard the probe
};
GenDivide: PROC = {
CardDivide: PROC [x: CARD, y: CARD] RETURNS [quotient: CARD]
entryLabel: Label = GenLabel[];
exitLabel: Label = GenLabel[];
faultLabel: Label = GenLabel[];
quotient: RegSpec = reg0; -- initially holds X, will hold return value
localY: RegSpec = reg1;
localX: RegSpec = reg2;
compY: RegSpec = reg3;
temp: RegSpec = reg4;
mask: RegSpec = reg5;
ProcedureEntry[entryLabel, 2];
MakeLabelGlobal["Basics.CardDivide", entryLabel];
Quick tests for Y=0 & Y=1
drRJEB[left: topSrc, right: const0, dist: UseLabel8B[faultLabel]];
drRJEB[left: topSrc, right: const1, dist: UseLabel8B[exitLabel]];
Push X into the "right" position and init the other variables
drLRn[quotient];
drROR[quotient, const0, const0];
drRXOR[pushDst, localY, constNI];
drRXOR[pushDst, localX, constNI];
drRJLB[left: popSrc, right: belowSrc, dist: UseLabel8B[exitLabel]];
Quick exit for X < Y
drLC1[];
drRXOR[pushDst, const0, constNI];
{
Scan over the zero bits in X by 4 bits, adjusting the mask appropriately.
WHILE x <= LAST[CARD]/16 DO
mask ← mask/16;
x ← x * 16;
ENDLOOP;
label0: Label = GenLabel[];
label1: Label = GenLabel[];
drLC0[];
drFSDB[FieldDescriptorToCard[ [mask: 32, shift: 4] ]];
drRFU[pushDst, const0, localX];
drJNEBB[0, UseLabel8B[label1]];
SetLabel[label0];
ExtractField[first: 0, bits: 32-4];
drRFU[localX, localX, const0];
drRFU[pushDst, const0, localX];
drJEBBJ[0, UseLabel8B[label0]];
SetLabel[label1];
};
{
Scan over the zero bits in X, adjusting the mask appropriately.
DO
mask ← mask/2;
carry ← (x/hiBit); x ← x + x;
IF carry = 1 THEN EXIT;
ENDLOOP;
setupLabel: Label = GenLabelHere[];
ExtractField[first: 0, bits: 31];
drRUADD[localX, localX, localX];
drRUADD[pushDst, const0, const0];
drJEBB[0, UseLabel8B[setupLabel]];
};
{
Perform division step.
DO
temp ← temp + temp + (x/hiBit);
x ← x + x;
IF temp >= y THEN {
temp ← temp - y;
quotient ← quotient + mask;
};
mask ← mask/2;
IF mask = 0 THEN EXIT;
ENDLOOP;
noSubLabel: Label = GenLabel[];
loopLabel: Label = GenLabelHere[];
drRUADD[localX, localX, localX];
drRUADD[temp, temp, temp];
drRXOR[pushDst, temp, constNI];
drRJLB[left: popSrc, right: compY, dist: UseLabel8B[noSubLabel]];
drRVSUB[temp, temp, localY];
drRVADD[quotient, quotient, mask];
SetLabel[noSubLabel];
ExtractField[first: 0, bits: 31];
drRJNEBJ[left: topSrc, right: const0, dist: UseLabel8B[loopLabel]];
};
SetLabel[exitLabel];
ProcedureExit[1];
SetLabel[faultLabel];
Halt[277B];
ProcedureExit[1];
};
END.