GenField.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) April 1, 1986 1:21:15 am PST
DIRECTORY
DragOpsCross,
DragOpsCrossUtils,
HandCoding,
HandCodingPseudos,
HandCodingSupport;
GenField: CEDAR PROGRAM
IMPORTS DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport
= BEGIN OPEN DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport;
Word: TYPE = DragOpsCross.Word;
ZerosWord: Word = DragOpsCross.ZerosWord;
All: PROC = {
area: Area = GetCurrentArea[];
startNext: Label = GenLabel[];
drJDB[UseLabel16[startNext]];
GenTextFetch[];
GenByteFetchUnchecked[];
GenBytePtrFetch[];
GenTextStore[];
GenByteStoreUnchecked[];
GenBytePtrStore[];
GenExtractField[];
GenExtractFieldSingle[];
GenDepositField[];
GenDepositFieldSingle[];
WordAlign[area];
SetLabel[startNext];
Control flow falls through to the next file that gets generated.
MakeLabelGlobal["GenField.startNext", startNext];
};
Byte Fetch and Store routines
GenTextFetch: PROC = {
(if open coded: 9 instructions, 9 cycles min)
rR: RegSpec = reg0;
rI: RegSpec = reg1;
entryLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 2];
MakeLabelGlobal["Basics.TextFetch", entryLabel];
drLRIn[rR, 1];
push the bound (at (rR+1)^)
drLRn[rI];
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 30, shift: 30]]];
drRADD[rR, rR, popSrc];
drRRI[rR, rR, 2];
read the word containing the byte
rR ← (rR + (rI / 4))^
drBC[];
bounds check [S-1] (which is rI) against [S] (which is the bound)
drSHL[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 5, shift: 3]]];
make it into a byte index ([S] = (rI * 8) MOD 32)
drFSDB[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 8, shift: 8]]];
setup Field ← FD[0, 8, 8]+[S]; S←S-1
drRFU[rR, const0, rR];
isolate the byte (into the return value)
ProcedureExit[1];
};
GenByteFetchUnchecked: PROC = {
(if open coded: 6 instructions, 6 cycles min)
rR: RegSpec = reg0;
rI: RegSpec = reg1;
entryLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 2];
MakeLabelGlobal["Basics.ByteFetchUnchecked", entryLabel];
drDUP[];
push the index (rI)
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 30, shift: 30]]];
make the index a word index (rI←rI/4; [S] = rI) {overwrites rI}
drRRX[rR, rR, popSrc];
fetch the word into rR (no overhead words)
drSHL[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 5, shift: 3]]];
make rI into a byte index ([S] = (rI * 8) MOD 32)
drFSDB[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 8, shift: 8]]];
setup Field ← FD[0, 8, 8]+[S]; S←S-1
drRFU[rR, const0, rR];
isolate the byte (into the return value)
ProcedureExit[1];
};
GenBytePtrFetch: PROC = {
(if open coded: 6 instructions, 7 cycles min)
rBA: RegSpec = reg0;
entryLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 1];
MakeLabelGlobal["Basics.BytePtrFetch", entryLabel];
drDUP[];
byte addr in [S], [S-1]
drSHL[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 5, shift: 3]]];
make it into a byte index ([S] = (rI * 8) MOD 32)
drFSDB[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 8, shift: 8]]];
setup Field ← FD[0, 8, 8]+[S]; S←S-1
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 30, shift: 30]]];
drRB[0];
fetch the word (no overhead)
drRFU[rBA, const0, popSrc];
isolate the byte (into the return value)
ProcedureExit[1];
};
GenTextStore: PROC = {
(if open coded: 11 instructions, 12 cycles min)
rR: RegSpec = reg0;
rI: RegSpec = reg1;
rB: RegSpec = reg2;
entryLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 3];
MakeLabelGlobal["Basics.TextStore", entryLabel];
drLRIn[rR, 1];
push the bound
drRVSUB[pushDst, const3, rI];
push 3 - i
drSHL[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 5, shift: 3]]];
make it into a byte index ([S] = ((3-i) * 8) MOD 32)
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 12, shift: 6]]];
[S] ← [S] + [S]*64
drFSDB[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 8, shift: 0]]];
setup Field ← FD[1, 8, 0]+[S]; S←S-1
drRBC[topDst, rI, topSrc];
bounds check rI against [S] (the bound)
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 30, shift: 30]]];
make the index a word index ([S] = rI / 4)
drQADD[topAtop, rR];
add in the base address
drRSB[2];
fetch the word (2 words of overhead)
drRFU[topDst, rB, topSrc];
insert the byte
drWSB[2];
store the changed word
ProcedureExit[0];
};
GenByteStoreUnchecked: PROC = {
(if open coded: 9 instructions, 9 cycles min)
rB: RegSpec = reg0; -- the byte (B: BYTE)
rP: RegSpec = reg1; -- the base pointer (P: LONG POINTER)
rI: RegSpec = reg2; -- the byte index (I: INT)
entryLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 3];
MakeLabelGlobal["Basics.ByteStoreUnchecked", entryLabel];
drRVSUB[pushDst, const3, rI];
push (3-I)
drSHL[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 5, shift: 3]]];
make it into a byte index ([S] = ((3-P) * 8) MOD 32)
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 12, shift: 6]]];
[S] ← [S] + [S]*64
drFSDB[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 8, shift: 0]]];
setup Field ← FD[1, 8, 0]+[S]; S←S-1
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 30, shift: 30]]];
make the index a word index ([S] = rI / 4)
drRRX[pushDst, topSrc, rP];
fetch the word (no overhead)
drRVADD[belowDst, belowSrc, rP];
adjust the dest address in the dead cycle
drRFU[topDst, rB, topSrc];
insert the byte
drWSB[0];
store the changed word
ProcedureExit[0];
};
GenBytePtrStore: PROC = {
(if open coded: 8 instructions, 9 cycles min)
rC: RegSpec = reg0;
rP: RegSpec = reg1;
entryLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 2];
MakeLabelGlobal["Basics.BytePtrStore", entryLabel];
drRVSUB[pushDst, const3, rP];
push (3-P)
drSHL[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 5, shift: 3]]];
make it into a byte index ([S] = ((3-P) * 8) MOD 32)
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 12, shift: 6]]];
[S] ← [S] + [S]*64
drFSDB[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 8, shift: 0]]];
setup Field ← FD[1, 8, 0]+[S]; S←S-1
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 30, shift: 30]]];
make the index a word index ([S] = rI / 4)
drRSB[0];
fetch the word (2 words of overhead)
drRFU[topDst, rC, topSrc];
insert the byte
drWSB[0];
store the changed word
ProcedureExit[0];
};
Field Extract & Deposit routines
In these routines a bit field is described by (P, I, B), where P is a word pointer, I is a bit index (unsigned), and B is a number of bits (in [0..32], but unchecked). We follow the convention that bit 0 is the most-significant bit in a binary number (aka Big-Endian). In the general case fields are allowed to cross word boundaries, in the single case fields must stay within a word.
GenExtractField: PROC = {
(if open coded: 13 instructions, 14 cycles min)
Arguments
rP: RegSpec = reg0; -- the base pointer
rI: RegSpec = reg1; -- the offset (in bits)
rB: RegSpec = reg2; -- the field size [0..32]
Locals
rBI: RegSpec = reg3; -- B+I
entryLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 3];
MakeLabelGlobal["Basics.ExtractField", entryLabel];
drRVADD[pushDst, rI, rB]; -- BI: WORD ← B+I
drLRn[rB];
drLRn[rBI];
drSHL[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 5, shift: 0]]];
[S] = (B+I) MOD 32 {the # of bits to shift left}
drSHD[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 6+6, shift: 6]]];
drFSDB[0];
setup the field descriptor (no constant part, unfortunately)
FD = [mask: B, shift: (B+I) MOD 32]
drRVSUB[pushDst, rBI, const1];
[S] = B+I-1 {to give offset of rightmost bit}
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 32-5, shift: 32-5]]];
drQRX[topAtop, rP];
[S] = right word
drLRn[rI];
[S] = B {to give offset of leftmost bit}
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 32-5, shift: 32-5]]];
drQRX[topAtop, rP];
[S] = left word, [S-1] = right word
drRFU[reg0, topSrc, belowSrc];
Extract the field & put it into the return reg
ProcedureExit[1];
};
GenExtractFieldSingle: PROC = {
(if open coded: 7 instructions, 8 cycles min)
rP: RegSpec = reg0; -- the base pointer
rI: RegSpec = reg1; -- the offset (in bits)
rB: RegSpec = reg2; -- the field size [0..32]
entryLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 3];
MakeLabelGlobal["Basics.ExtractFieldSingle", entryLabel];
drRVADD[pushDst, rI, rB];
drSHL[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 5, shift: 0]]];
[S] = (B+I) MOD 32 {the # of bits to shift left}
drSHD[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 6+6, shift: 6]]];
drFSDB[0];
setup the field descriptor (no constant part, unfortunately)
FD = [mask: B, shift: (B+I) MOD 32]
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 32-5, shift: 32-5]]];
[S] = (I / 32) {to give offset of lst bit}
drRX[];
[S] = word containing field
drRFU[reg0, topSrc, topSrc];
Extract the field & put it into the return reg
ProcedureExit[1];
};
GenDepositField: PROC = {
(if open coded (with plenty of spare regs):
single word => 16 instructions, 21 cycles min,
double word => 26 instructions, 27 cycles min)
Arguments
rP: RegSpec = reg0; -- the base pointer
rI: RegSpec = reg1; -- the offset (in bits)
rB: RegSpec = reg2; -- the field size [0..32]
rF: RegSpec = reg3; -- the field to insert
Locals
c32: RegSpec = reg4; -- 32
rBI: RegSpec = reg5; -- B+I
rSH: RegSpec = reg6; -- 31&(-B-I) {bits to shift left}
rMSK: RegSpec = reg7; -- SH+B {bits to mask}
entryLabel: Label = GenLabel[];
exitLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 4];
MakeLabelGlobal["Basics.DepositField", entryLabel];
drLIB[32];
c32: WORD ← 32
drRVADD[pushDst, rI, rB];
BI: WORD ← B+I
drRVSUB[pushDst, const0, rBI];
drSHL[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 5, shift: 0]]];
SH: WORD = (-B-I) MOD 32
drRVADD[pushDst, rSH, rB];
MSK: WORD = SH+B
{
This part stores the right part of the field, which is the only part for single-word stores.
drLRn[rMSK];
drLRn[rSH];
[S] = SH
[S-1] = MSK
drSHD[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 6+6, shift: 6]]];
[S] holds the new field descriptor (without the insert bit)
= FD[insert: FALSE, mask: MSK, shift: SH]
drFSDB[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 0, shift: 0]]];
setup the field descriptor (with the insert bit)
= FD[insert: TRUE, mask: MSK, shift: SH]
drRVSUB[pushDst, rBI, const1];
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 32-5, shift: 32-5]]];
drRVADD[rP, popSrc, rP];
form the address of the word to modify
drLRIn[rP, 0];
Fetch the word to modify
drRFU[topDst, rF, topSrc];
Insert the field
drSRIn[rP, 0];
Store the modified word back
drRJLEB[topSrc, c32, UseLabel8B[exitLabel]];
IF MSK <= 32 THEN GO TO exitLabel;
};
At this point the right part has been done, so we try to do the left part
drLRn[rSH];
drFSDB[DragOpsCrossUtils.FieldDescriptorToCard[[insert: FALSE, mask: 32, shift: 0]]];
setup the field descriptor to shift F right
drRVSUB[pushDst, rMSK, c32];
drSHL[DragOpsCrossUtils.FieldDescriptorToCard[[insert: FALSE, mask: 6+6, shift: 6]]];
[S] holds the new field descriptor (without the insert bit)
= FD[insert: FALSE, mask: MSK-32, shift: 0]
drRFU[rF, const0, rF];
Shift the field to get the remainder
drFSDB[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 0, shift: 0]]];
setup the field descriptor to insert the remaining F
= FD[insert: TRUE, mask: MSK-32, shift: 0]
drRRX[pushDst, rP, constN1];
Fetch the word to modify
drRVSUB[rP, rP, const1];
Adjust rP while twiddling our thumbs
drRFU[topDst, rF, topSrc];
Insert the field
drSRIn[rP, 0];
Store the modified word back
SetLabel[exitLabel];
ProcedureExit[0];
};
GenDepositFieldSingle: PROC = {
DepositFieldSingle: PROC [P: PTR, I: WORD, B: [0..32], F: WORD]
deposits F into the field described by (P, I, B)
(the caller promises to not cross a word boundary)
(if open coded: 13 instructions, 14 cycles min)
Arguments
rP: RegSpec = reg0; -- the base pointer
rI: RegSpec = reg1; -- the offset (in bits)
rB: RegSpec = reg2; -- the field size [0..32]
rF: RegSpec = reg3; -- the field to insert
Locals
rBI: RegSpec = reg4; -- B+I
rSH: RegSpec = reg5; -- 31&(-B-I) {bits to shift left}
rMSK: RegSpec = reg6; -- SH+B {bits to mask}
entryLabel: Label = GenLabel[];
ProcedureEntry[entryLabel, 4];
MakeLabelGlobal["Basics.DepositFieldSingle", entryLabel];
drRVADD[pushDst, rI, rB];
BI: WORD ← B+I
drRVSUB[pushDst, const0, rBI];
drSHL[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 5, shift: 0]]];
SH: WORD = (-B-I) MOD 32
drRVADD[pushDst, rSH, rB];
MSK: WORD = SH+B
[S] = MSK
[S-1] = SH
drLRn[rSH];
[S] = SH
[S-1] = MSK
drSHD[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 6+6, shift: 6]]];
[S] holds the new field descriptor (without the insert bit)
= FD[insert: FALSE, mask: MSK, shift: SH]
drFSDB[DragOpsCrossUtils.FieldDescriptorToCard[[insert: TRUE, mask: 0, shift: 0]]];
setup the field descriptor (with the insert bit)
= FD[insert: TRUE, mask: MSK, shift: SH]
drLRn[rI];
drSHR[DragOpsCrossUtils.FieldDescriptorToCard[[mask: 32-5, shift: 32-5]]];
drRVADD[rP, popSrc, rP];
form the address of the word to modify
drLRIn[rP, 0];
Fetch the word to modify
drRFU[topDst, rF, topSrc];
Insert the field
drSRIn[rP, 0];
Store the modified word back
ProcedureExit[0];
};
END.