DragOpsCross.mesa
Copyright © 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) September 10, 1986 11:16:42 pm PDT
Curry, September 12, 1985 10:46:26 pm PDT
McCreight, January 8, 1986 3:37:59 pm PST
This interface consists exclusively of type definitions for the architectural data structures of the Dragon Mesa processor. A prose description of the instruction set is kept as DragOps.tioga. A companion interface, DragOpsCrossUtils, provides convenient operations (usually inline) for manipulating Dragon values on PrincOps machines.
These definitions are tentative, and are largely analogous to the Cedar PrincOps. Especially tentative definitions are marked by (??). Where LONG POINTER appears, it should be taken as a comment, and Word values should be used to actually build such structures for Dragon.
DragOpsCross: CEDAR DEFINITIONS = BEGIN
Basic Types and Associated Values
Word: TYPE = PACKED ARRAY FiveBitIndex OF BOOL;
ZerosWord: Word = LOOPHOLE[LONG[0]];
We would like to use ALL[FALSE], but the compiler is really stupid
OnesWord: Word = LOOPHOLE[LONG[-1]];
We would like to use ALL[TRUE], but the compiler is really stupid
wordsPerPage: CARDINAL = 1024;
bytesPerWord: CARDINAL = 4;
charsPerWord: CARDINAL = 4;
bitsPerByte: CARDINAL = 8;
bitsPerCharacter: CARDINAL = 8;
bitsPerWord: CARDINAL = bitsPerByte*bytesPerWord;
bytesPerPage: CARDINAL = wordsPerPage*bytesPerWord;
logWordsPerPage: CARDINAL = 10; -- LogBase2[wordsPerPage]
logBitsPerByte: CARDINAL = 3; --LogBase2[bitsPerByte]
logBitsPerChar: CARDINAL = 3; --LogBase2[bitsPerCharacter]
logBytesPerWord: CARDINAL = 1; --LogBase2[bytesPerWord]
logCharsPerWord: CARDINAL = 1; --LogBase2[bytesPerWord]
logBitsPerWord: CARDINAL = logBitsPerByte + logBytesPerWord;
logBytesPerPage: CARDINAL = logBytesPerWord + logWordsPerPage;
PageCount: TYPE = INT;
actually, [0..maxPagesInVM]; intended for use by VM
PageNumber: TYPE = INT;
actually, [0..maxPagesInVM); intended for use by VM
maxPagesInVM: PageCount = LONG[4]*LONG[1024]*LONG[1024];
22-bit page index
SixBitIndex: TYPE = [0..64);
FiveBitIndex: TYPE = [0..32);
TwoWords: TYPE = ARRAY [0..1] OF Word;
FourBitIndex: TYPE = [0..16);
Half: TYPE = PACKED ARRAY FourBitIndex OF BOOL;
ZerosHalf: Half = LOOPHOLE[0];
OnesHalf: Half = LOOPHOLE[-1];
ThreeBitIndex: TYPE = [0..7];
FourHalves: TYPE = ARRAY [0..3] OF Half;
TwoHalves: TYPE = ARRAY [0..1] OF Half;
Byte: TYPE = PACKED ARRAY ThreeBitIndex OF BOOL;
ZerosByte: Byte = LOOPHOLE[0];
OnesByte: Byte = LOOPHOLE[377B];
EightBytes: TYPE = PACKED ARRAY [0..7] OF Byte;
FourBytes: TYPE = PACKED ARRAY ByteIndex OF Byte;
ByteIndex: TYPE = [0..bytesPerWord);
BytesPerWord: NAT = 4;
TwoBytes: TYPE = PACKED ARRAY [0..1] OF Byte;
Comparison: TYPE = MACHINE DEPENDENT {less(0), equal(1), greater(2)};
This type is the type to be returned from comparison operations.
ByteAddress: TYPE = RECORD [Word];
To be used to denote byte addresses, when the difference between bytes addresses and other words needs to be indicated.
WordAddress: TYPE = RECORD [Word];
To be used to denote word addresses, when the difference between addresses and other words needs to be indicated.
Field descriptor formats
A field descriptor is a special interpretation of a 16-bit quantity used to control the Field Unit. In the Field Unit, the shifter takes two words in and produces one word appropriately shifted to the left. The mask is used as a multiplexor to select bits from either the shifter output or the background word.
FieldDescriptor: TYPE = MACHINE DEPENDENT RECORD [
reserved: [0..7] ← 0,
reserved bits, not currently used, but must be 0s
insert: BOOLFALSE,
governs choice of background and low bits of mask
mask: [0..32] ← 32,
# of right-justified 1s in the mask (mask = 0 => no 1s)
shift: [0..32] ← 0
gives # of bits to left-shift the double word
];
Instruction Set
(wizards only, current opcode assignments are probably wrong)
Instruction formats are padded to 16 bit boundary to keep the compiler happy.
RegIndex: TYPE = [0..16);
valid register index for locals, aux, etc.
PadByte: TYPE = [0..255];
padding byte
Lit8: TYPE = [0..255];
8-bit literal or displacement
Op4: TYPE = [0..15];
4-bit opcode
Op8: TYPE = [0..255];
8-bit opcode
JDist8: TYPE = [0..255];
jump distance interpreted as signed byte
Inst: TYPE = MACHINE DEPENDENT {
Leftmost bits of opcode determine length of instruction.
000 => 1 byte [000B..037B]
001 => 5 bytes [040B..077B]
01- => 1 byte [100B..177B]
10- => 2 bytes [200B..277B]
11- => 3 bytes [300B..377B]
Leftmost bits of opcode determine possible PC displacement selection.
0------- PC + stack  JSR
10------ PC + alphaS  JB
110----- PC + alphaBetaS  JDB and LFC
111----- PC + betaS  RJB's and JBB's
OIformat (1 byte)
x000b (000B), x001b, x002b, x003b, x004b, x005b, x006b, x007b,
x010b (010B), x011b, x012b, x013b, x014b, x015b, x016b, x017b,
dLC0 (020B), dLC1, dLC2, dLC3, dLC4, dLC5, dLC6, dLC7,
dLC8 (030B), dLC9, dLC10, dLC11, x034b, x035b, x036b, x037b,
OQBformat (5 bytes)
x040b (040B), x041b, x042b, x043b, x044b, x045b, x046b, x047b,
x050b (050B), x051b, x052b, x053b, x054b, x055b, x056b, x057b,
x060b (060B), dDFC, dLIQB, x063b, dADDQB, dSUBQB, dJ5, dJQB,
x070b (070B), x071b, x072b, x073b, x074b, x075b, x076b, x077b,
OIformat (1 byte)
dOR (100B), dAND, dRX, dBC, dADD, dSUB, dLADD, dLSUB,
dDUP (110B), dDIS, x112b, dEXDIS, dSFC, dSFCI, dRETN, dJSD,
x120b (120B), x121b, x122b, x123b, dKFC, x125b, dJ1, dJSR,
x130b (130B), x131b, x132b, x133b, x134b, x135b, x136b, x137b,
LRformat (1 byte)
dLR0 (140B), dLR1, dLR2, dLR3, dLR4, dLR5, dLR6, dLR7,
dLR8 (150B), dLR9, dLR10, dLR11, dLR12, dLR13, dLR14, dLR15,
dSR0 (160B), dSR1, dSR2, dSR3, dSR4, dSR5, dSR6, dSR7,
dSR8 (170B), dSR9, dSR10, dSR11, dSR12, dSR13, dSR14, dSR15,
QRformat (2 bytes)
dQOR (200B), dQAND, dQRX, dQBC, dQADD, dQSUB, dQLADD, dQLSUB,
OBformat (2 bytes)
dALS (210B), dAL, dASL, dAS, dCST, x215b, dRET, x217b,
dLIP (220B), dSIP, dLIB, x223b, dADDB, dSUBB, dJ2, dJB,
dRB (230B), dWB, dRSB, dWSB, x234b, x235b, x236b, dPSB,
LRBformat (2 bytes)
dLRI0 (240B), dLRI1, dLRI2, dLRI3, dLRI4, dLRI5, dLRI6, dLRI7,
dLRI8 (250B), dLRI9, dLRI10, dLRI11, dLRI12, dLRI13, dLRI14, dLRI15,
dSRI0 (260B), dSRI1, dSRI2, dSRI3, dSRI4, dSRI5, dSRI6, dSRI7,
dSRI8 (270B), dSRI9, dSRI10, dSRI11, dSRI12, dSRI13, dSRI14, dSRI15,
RRformat (3 bytes)
dROR (300B), dRAND, dRRX, dRBC, dRADD, dRSUB, dRLADD, dRLSUB,
dRXOR (310B), x311b, dRFU, x313b, dRVADD, dRVSUB, dRUADD, dRUSUB,
ODBformat and LRRBformat (3 bytes)
dLGF (320B), dLFC, dLIDB, dFSDB, dADDDB, dSUBDB, dJ3, dJDB,
dRAI (330B), dWAI, dRRI, dWRI, dIODA,  dIOD, dION, x337b,
RJBformat (3 bytes)
x340b (340B), dRJEB, dRJLB, dRJLEB, x344b, dRJNEB, dRJGEB, dRJGB,
x350b (350B), dRJNEBJ, dRJGEBJ, dRJGBJ, x354b, dRJEBJ, dRJLBJ, dRJLEBJ,
JBBformat (3 bytes)
dJEBB (360B), dJNEBB, dJEBBJ, dJNEBBJ, x364b, x365b, x366b, x367b,
ODBformat (3 bytes)
dSHL (370B), dSHR, dSHDL, dSHDR, x374b, x375b, x376b, x377b};
dFirst: Inst = FIRST[Inst];
dLast: Inst = LAST[Inst];
OIformat (1 byte)
OIformat: TYPE = MACHINE DEPENDENT RECORD [
op: Inst,
pad: PadByte ← 0
];
OQBformat (5 bytes)
OQBformat: TYPE = MACHINE DEPENDENT RECORD [
op: Inst,
b0,b1,b2,b3: Lit8,
pad: PadByte ← 0
];
LRformat (1 byte)
LRformat: TYPE = MACHINE DEPENDENT RECORD [
op: Op4, reg: RegIndex,
pad: PadByte ← 0
];
QRformat (2 bytes)
QRformat: TYPE = MACHINE DEPENDENT RECORD [
op: Inst,
aOp: ShortRegQR,
opt,aux: BOOL, reg: RegIndex
];
ShortRegQR: TYPE = MACHINE DEPENDENT {
topAtop(0), -- C: [S], A: [S], B: general
pushAtop(1), -- C: [S+1]+, A: [S], B: general
pushA0(2), -- C: [S+1]+, A: c0, B: general
pushA1(3)}; -- C: [S+1]+, A: c1, B: general
Short encoding for C and A operands of the QR format instructions. The B operand is always a general operand.
OBformat (2 bytes)
OBformat: TYPE = MACHINE DEPENDENT RECORD [
op: Inst,
lit: Lit8
];
LRBformat (2 bytes)
LRBformat: TYPE = MACHINE DEPENDENT RECORD [
op: Op4, reg: RegIndex,
lit: Lit8
];
RRformat (3 bytes)
RRformat: TYPE = MACHINE DEPENDENT RECORD [
op: Inst,
aOpt,cOpt,bOpt,aux: BOOL, b: RegIndex,
c,a: RegIndex,
pad: PadByte ← 0
];
ODBformat (3 bytes)
ODBformat: TYPE = MACHINE DEPENDENT RECORD [
op: Inst,
lit0: Lit8,
lit1: Lit8,
pad: PadByte ← 0
];
LRRBformat (3 bytes)
LRRBformat: TYPE = MACHINE DEPENDENT RECORD [
op: Inst,
disp: Lit8,
reg1,reg2: RegIndex,
pad: PadByte ← 0
];
RJBformat (3 bytes)
RJBformat: TYPE = MACHINE DEPENDENT RECORD [
op: Inst,
aOp: ShortRegRJB,
opt,aux: BOOL, reg: RegIndex,
dist: JDist8,
pad: PadByte ← 0
];
ShortRegRJB: TYPE = MACHINE DEPENDENT {
c0(0), -- constant 0
c1(1), -- constant 1
top(2), -- [S]
popTop(3)}; -- [S]-
Short encoding for A operand of RJB instruction.
JBBformat (3 bytes)
JBBformat: TYPE = MACHINE DEPENDENT RECORD [
op: Inst,
lit: Lit8,
dist: JDist8,
pad: PadByte ← 0
];
Trap Assignments
These declarations are made with LONG CARDINAL to permit the compiler to do arithmetic with them. The compiler is not bright enough to do arithmetic with type Word.
TrapWidthWords: NAT = 4;
each trap is TrapWidthWords words from the previous trap
TrapWidthBytes: NAT = TrapWidthWords*bytesPerWord;
each trap is TrapWidthBytes words from the previous trap
XopBase: LONG CARDINAL = 1000000B;
base word addr of Xop traps. There is space for 256 of them, although most are unused.
TrapBase: LONG CARDINAL = XopBase+256*TrapWidthWords;
base word addr of other traps. There is one for each trap in TrapIndex.
KernalLimit: LONG CARDINAL = 100000000B;
tentative limit for Kernel addressing
TrapIndex: TYPE = MACHINE DEPENDENT {
There are 4 trap quadrants of 16 traps each (last quad not currently used). Note that not all trap indexes can occur through use of the instruction set. The assignments are chosen to make the IFU simpler. The word address of transfer for trap X is TrapBase+TrapWidthWords*X.
TrapQuad0:
The 6 Traps in TrapQuad0 cause further maskable traps to be disabled. Only the second eight trap locations in TrapQuad0 are maskable.
StackUnderflowTrap (00B), -- called if RET* or ALS and IFU stack is empty
IFUPageFaultTrap (01B), -- called when IFU gets a page fault
ResetTrap (07B), -- transfered to (no call) when RESET is asserted
IFUStackOverflowTrap (10B), -- called when IFU stack fills
EUStackOverflowTrap (11B), -- called when SP goes beyond SPlim
RescheduleTrap (12B), -- called when RESCHEDULE is acknowledged
TrapQuad1: ALU Condition Test Traps
ALU traps correspond to ALU Dragon.CondSelects in [Indigo]<Dragon>Rosemary>Dragon.mesa. The traps that the current instruction set sees are starred (**). Most of the other conditions are used to influence conditional jumps. These traps are not maskable.
ALUCondFalse (20B), -- ALU fault FALSE
ALUCondEZ (21B), -- ALU fault = (zero)
ALUCondLZ (22B), -- ALU fault < (zero)
ALUCondLE (23B), -- ALU fault <= (zero)
ALUCondSpare (24B), -- unused condition/fault
ALUCondNE (25B), -- ALU fault = (zero)
ALUCondGE (26B), -- ALU fault >= (zero)
ALUCondGZ (27B), -- ALU fault > (zero)
ALUCondOver (30B), -- ALU fault overflow **
ALUCondBC (31B), -- ALU fault bounds check **
ALUCondIL (32B), -- ALU fault illegal Lisp number **
ALUCondDO (33B), -- ALU Division Overflow **
ALUCondNotOver (34B), -- ALU fault NOT overflow
ALUCondNB (35B), -- ALU fault NOT bounds check
ALUCondNI (36B), -- ALU fault NOT illegal Lisp number
ModeFault (37B), -- Kernel instruction attempted in user mode
  (must be 37B, see McCreight)
TrapQuad2: DPBus Cache and Arithmetic Unit Faults
EU Cache PBus fault traps: Only page fault and write protect fault are visible at the instruction set level. These traps are not maskable.
MemAccessFault (40B), -- Mem access fault (insufficient rights)
IOAccessFault (41B), -- IO access fault (insufficient rights)
EUPageFault (42B), -- EU Cache page fault
EUWriteFault (43B), -- EU Cache write protect fault
AUFault (44B)}; -- AU (external Arithmetic Unit) fault
Processor Register Numbers (tentative)
These assignments are to be used with the LIP, and SIP instructions. We use the ProcessorRegister declarations for both IFU and EU parts.
There are actually more assignments than are accessible through these instructions. These are marked by (NA), which indicates that the decode is reserved for the register, but that the data paths to allow the register to be used are not present.
ProcessorRegister: TYPE = MACHINE DEPENDENT {
euStack (0), -- beginning of EU Stack
euJunk (128), -- the non-matching EU register
euToKBus (129), -- send result on K bus to IFU
euMAR (130), -- MemoryAddressRegister
euField (131), -- Field register
euConstant (132), -- Base of EU constant registers (12 regs)
euAux (144), -- Base of EU aux registers (16 regs)
euBogus (160), -- [euBogus..euLast] not legal (NA) (80 regs)
euLast (239), -- last possible EU reg (NA)
These IFU register addresses are noticed within the IFU. Destinations are changed to references to the "toKBus" register. Sources are changed so that ALURightSource (an EU control input) = kBus.
ifuYoungestL (240), -- youngest L in IFU stack
ifuYoungestPC (241), -- youngest PC in IFU stack
ifuEldestL (242), -- eldest L in IFU stack
ifuEldestPC (243), -- eldest PC in IFU stack (rd removes, wt adds)
ifuSLimit (244), -- stack limit register
The rest of these registers, if they exist, aren't accessible at these addresses.
ifuBogus (245), -- [ifuBogus..ifuLast] are not legal (NA)
ifuL (252), -- current L register (NA)
ifuS (253), -- current S register (NA)
ifuPC (254), -- current program counter (NA)
ifuLast (255) -- last possible IFU reg (NA)
};
EURegs: TYPE = ProcessorRegister[euStack..euLast];
EULegalRegs: TYPE = ProcessorRegister[euStack..euBogus);
unfortunately includes illegal cases: [euSpare0..euUseK]
IFURegs: TYPE = ProcessorRegister[ifuYoungestL..ifuLast];
IFULegalRegs: TYPE = ProcessorRegister[ifuYoungestL..ifuBogus);
StackedStatusWord: TYPE = MACHINE DEPENDENT RECORD [
version (0: 00..07): [0..255] ← 0,
padBits (0: 08..13): [0..63] ← 0,
userMode (0: 14..14): BOOLFALSE, -- TRUE => user, FALSE => kernel
trapsEnabled (0: 15..15): BOOLFALSE,
padByte (0: 16..23): [0..255] ← 0,
lBase (0: 24..31): [0..255] ← 0 ]; -- EU local frame base
IFU register stack
IFUStackIndex: TYPE = [0..IFUStackSize);
IFUStackSize: NAT = 15;
The number of frames in the stack is IN [0..IFUStackSize]
IFUOverflow: NAT = 12;
If traps are enabled then control arrives at the IFU stack overflow handler with exactly IFUOverflow frames on the stack.
EU register stack
EUStackIndex: TYPE = [0..EUStackSize);
EUStackSize: NAT = 128;
EU local variable register
EULocalIndex: TYPE = [0..EULocals);
EULocals: NAT = 16;
EU auxilliary register stack
EUAuxIndex: TYPE = [0..EUAuxRegs);
EUAuxRegs: NAT = 16;
EU constant register stack
EUConstIndex: TYPE = [0..EUConstants);
EUConstants: NAT = 12;
Special I/O locations
These assignments are to be used with the IO* instructions. All of these locations are quite speculative right now. All IO locations are declared as if they were word addresses, but are expressed in terms that make it easy to declare constants. Just remember to translate them to type Word when necessary.
IOLocation: TYPE = LONG CARDINAL;
a word address
Reschedule request location. Writing anything into this location requests a reschedule interrupt. The exact mechanism is undefined.
ioRescheduleRequest: IOLocation = 1000000B;
Reset request location. Writing anything into this location requests a system reset. The exact mechanism is undefined.
ioResetRequest: IOLocation = 1000001B;
IO operand types
IOOperand: TYPE = MACHINE DEPENDENT RECORD [
pDataA: Byte ← ZerosByte, -- IO address or address offset
pCmd: PCmdFormat ← [cache[]] -- PBus command
];
PCmdFormat: TYPE = MACHINE DEPENDENT RECORD [
SELECT tag: PCmdClass FROM
other => [pad: [0..128) ← 0],
pad = 0 => Noop
pad # 0 => Reserved for non-cache operations
cache => [
byteSelect: PCmdByteSelect ← ALL[TRUE],
not used for memory reads or IO
selects byte(s) written for memory writes
space: PCmdSpace ← memory,
special: BOOLFALSE,
for IO writes, TRUE forces broadcast
for memory reads, TRUE forces special read (for CST)
otherwise, TRUE is reserved
direction: PCmdDirection ← read],
ENDCASE];
PCmdByteSelect: TYPE = PACKED ARRAY [0..3] OF BOOL;
PCmdClass: TYPE = MACHINE DEPENDENT {other (0), cache (1)};
PCmdSpace: TYPE = MACHINE DEPENDENT {memory (0), io (1)};
PCmdDirection: TYPE = MACHINE DEPENDENT {read(0), write(1)};
END.