*-----------------------------------------------------------
Title[DMesaDefs.mc...February 13, 1984  2:38 PM...Willie-Sue];
*-----------------------------------------------------------

*-----------------------------------------------------------
* Assembly options
*-----------------------------------------------------------
* Compile the Alto-Mesa emulator unless AltoMode is previously set to 0.
IfDef[AltoMode, , Set[AltoMode, 177777]];

* nEntryPoints may be either 1 or 3 in Alto mode, only 1 in PrincOps mode.
* Note that 1 entry point => restart opcode after page fault.
IfDef[nEntryPoints, , Set[nEntryPoints, 1]];

*-----------------------------------------------------------
* RM registers
*-----------------------------------------------------------

SetRMRegion[RMforIFU];	*RM region 0
:If[AltoMode];		********** Alto version **********
	RVN[DLink];		* Xfer destination link
	RVN[SLink];		* Xfer source link
	RVN[ATPReg];		* Allocation trap parameter
	RVN[OTPReg];		* Other trap parameter
	RVN[Sticky];		* Sticky flags for floating point
:Else;			******** PrincOps version ********
	Reserve[1];		* NWW: defined in RegisterDefs.mc
	RVN[CurrentPSB];	* PDA-relative address of current PSB
	RVN[CurrentTime];	* Current process time, in ~50 ms ticks
	RVN[XferFlags];		* Xfer control and state flags
	RVN[TrapParam];		* Xfer trap parameter
:EndIf;			**********************************
	RVN[XTSReg];		* Xfer trap state
	RVN[WDC];		* Wakeup disable counter
	RVN[MDSHi];		* Main data space -- high part
*	Reserve[1];		* An unused register -- wow!
	RVN[RTempX];		* Not any more!
	RVN[RTemp0];		* General temporaries
	RVN[RTemp1];
	RVN[RTemp2];
	RVN[RTemp3];
	RVN[RTemp4];
	RVN[RTemp5];		* RVRel 16 and 17 must be temps, for
	RVN[RTemp6];		*  multiply and divide subroutines

:If[Not[AltoMode]];	******** PrincOps version ********
SetRMRegion[AEmRegs];	* RM region 1 (overlay Alto Emulator registers)
	Reserve[1];		* Skip over R400
	RVN[TickCount];		* Divides down 17-ms interrupts to make ticks
	RVN[Sticky];		* Sticky flags for floating point
	RVN[MaintPanel];	* Maintenance panel code
:EndIf;			**********************************

* RM registers (cont'd)

* Special uses of the Mesa RM registers:

:If[AltoMode];		********** Alto version **********
	RME[PDAHi, MDSHi];	* PDA is the same as MDS at present
	RME[XferFlags, RTemp6];	* Xfer control flags

* XferFlags bit assignments.
	MC[xf.trap, 0];		* Not used in Alto mode
	MC[xf.push, 0];		* Not used in Alto mode
	MC[xf.free, 1];		* Free local frame

:Else;			******** PrincOps version ********
* Temporary register assignments, used only inside Xfer and when calling Xfer.
	RME[DLink, RTemp5];	* Xfer destination link
	RME[SLink, RTemp6];	* Xfer source link

* Temporary register assignments, for passing parameters thru fault handler.
* FaultParam0 and FaultParam1 must be preserved across Requeue.
	RME[FaultParam0, TrapParam]; * First or low-order fault parameter
	RME[FaultParam1, RTemp3]; * Second or high-order fault parameter

* XferFlags bit assignments.
* Note: xf.invalidContext must have the appropriate value (usually 0) any
* time a fault or trap may occur.  Other flags are relevant only inside Xfer.
* The low 3 bits are dispatched upon inside Xfer, so be circumspect about
* reassigning them.
	MC[xf.invalidContext, 100000]; * Current context is invalid
	MC[xf.trap, 4];		* Store TrapParam in destination frame
	MC[xf.push, 2];		* Push SLink and DLink onto stack
	MC[xf.free, 1];		* Free local frame
:EndIf;			**********************************

* 16 and 17 must be temporaries (for MulSub and DivSub)
	RM[MulDivArg, Or[!RMforIFU, 17]];

*-----------------------------------------------------------
* Base registers
*-----------------------------------------------------------

* BRs 0-3 are addressable as MemBX-relative registers.
* Of these, 0 and 1 are used as MemBX-relative registers by Mesa,
* thereby consuming registers 4, 5, 10, 11, 14, 15 also.
* The other registers in [0..17] are used as ordinary registers
* and should not be addressed from the IFU.
	BRX[L, 0];		* {mds, L} Local frame, = G xor 1
	BRX[G, 1];		* {mds, G} Global frame, = L xor 1

	BR[SD, 2];		* {mds, SD} System Dispatch table

* BRs 34-37 are addressable from the IFU.
* 36 and 37 are permanently assigned in ADefs.mc (MDS and CODE).
* 34 and 35 are also used in DMesaProcess.mc.
	BR[LPtr, 34];		* Temp for Long Pointer instructions

:If[AltoMode];		********** Alto version **********
	BR[PDA, IP[MDS]];	* PDA is the same as MDS at present
:Else;			******** PrincOps version ********
	BR[PDA, 3];		* Base of Process Data Area
	BR[MapBitsBR, 25];
:EndIf;			**********************************

*-----------------------------------------------------------
* System constants
*-----------------------------------------------------------

	MC[AV, 1000];
	Set[SDLoc, 1100];
	MC[GFT, 1400];

* SD indices for Mesa traps
	MC[sBreak, 0];
	MC[sStackError, 2];
	MC[sWakeupError, 3];
	MC[sXferTrap, 4];
	MC[sUnimplemented, 5];
	MC[sControlFault, 7];
	MC[sSwapTrap, 10];
	MC[sUnbound, 13];
	MC[sZeroDivisor, 14];
	MC[sDivideCheck, 15];
	MC[sHardwareError, 16];
	MC[sProcessTrap, 17];
	MC[sBoundsFault, 20];
	MC[sPointerFault, 21];
	MC[sBoot, 276];

:If[AltoMode];		********** Alto version **********
* SD indices for Mesa faults (handled as traps in Alto Mesa and
* pre-Rubicon Pilot Mesa.
	MC[sAllocListEmpty, 6];
	MC[sPageFault, 11];
	MC[sWriteProtect, 12];
:Else;			******** PrincOps version ********
* Fault queue offsets (2 * corresponding PrincOps FaultQueueIndex)
	MC[qFrameFault, 0];
	MC[qPageFault, 2];
	MC[qWriteProtectFault, 4];
:EndIf;			**********************************

* Miscellaneous definitions
:If[AltoMode];		********** Alto version **********
	MC[MesaStopLoc, 26];	* Communication with the Nova World
	MC[CurrentState, 23];
:Else;			******** PrincOps version ********
	MC[PDAhi, 1];		* PDA starts at VM 200000
	MC[pilotMDSHi, 76];	* MDS initially starts at VM 17400000
:EndIf;			**********************************

* Mesa instruction set number
	Set[MesaInsSet, IfE[AltoMode, 0, 1, 2]];
	InsSet[MesaInsSet, nEntryPoints];

* Stack size (size of StateVector.stk array)
	Set[sizeStack, IfE[AltoMode, 0, 16, 10]];

*-----------------------------------------------------------
* Mesa opcode definitions
*-----------------------------------------------------------

Set[MOpcodeVal, 0];
M[MOp, (IfSE[#1, , UndefOp[MOpcodeVal], Set[MOp#1, MOpcodeVal]]
	Set[MOpcodeVal, Add[MOpcodeVal, 1]])];
M[MesaOps, (MOp[#1] MOp[#2] MOp[#3] MOp[#4] MOp[#5] MOp[#6] MOp[#7] MOp[#8])];
M[UndefOp, IFUPause[#1, 1, L, 0, UnimplOpcodeTrap, 17, 0, 0]];

*       xx0    xx1    xx2    xx3    xx4    xx5    xx6    xx7

MesaOps[NOOP,  ME,    MRE,   MXW,   MXD,   NOTIFY,BCAST, REQUEUE];	* 00x
MesaOps[LL0,   LL1,   LL2,   LL3,   LL4,   LL5,   LL6,   LL7];		* 01x
MesaOps[LLB,   LLDB,  SL0,   SL1,   SL2,   SL3,   SL4,   SL5];		* 02x
MesaOps[SL6,   SL7,   SLB,   PL0,   PL1,   PL2,   PL3,   LG0];		* 03x
MesaOps[LG1,   LG2,   LG3,   LG4,   LG5,   LG6,   LG7,   LGB];		* 04x
MesaOps[LGDB,  SG0,   SG1,   SG2,   SG3,   SGB,   LI0,   LI1];		* 05x
MesaOps[LI2,   LI3,   LI4,   LI5,   LI6,   LIN1,  LINI,  LIB];		* 06x
MesaOps[LIW,   LINB,  LADRB, GADRB, LCO,    ,     ASSIGNREF,ASSIGNREFNEW]; * 07x

MesaOps[R0,    R1,    R2,    R3,    R4,    RB,    W0,    W1];		* 10x
MesaOps[W2,    WB,    RF,    WF,    RDB,   RD0,   WDB,   WD0];		* 11x
MesaOps[RSTR,  WSTR,  RXLP,  WXLP,  RILP,  RIGP,  WILP,  RIL0];		* 12x
MesaOps[WS0,   WSB,   WSF,   WSDB,  RFC,   RFS,   WFS,   RBL];		* 13x
MesaOps[WBL,   RDBL,  WDBL,  RXLPL, WXLPL, RXGPL, WXGPL, RILPL];	* 14x
MesaOps[WILPL, RIGPL, WIGPL, RSTRL, WSTRL, RFL,   WFL,   RFSL];		* 15x
MesaOps[WFSL,  LP,    SLDB,  SGDB,  PUSH,  POP,   EXCH,  LINKB];	* 16x
MesaOps[DUP,   NILCK, NILCKL,BNDCK,  ,      ,      ,      ];		* 17x

MesaOps[J2,    J3,    J4,    J5,    J6,    J7,    J8,    J9];		* 20x
MesaOps[JB,    JW,    JEQ2,  JEQ3,  JEQ4,  JEQ5,  JEQ6,  JEQ7];		* 21x
MesaOps[JEQ8,  JEQ9,  JEQB,  JNE2,  JNE3,  JNE4,  JNE5,  JNE6];		* 22x
MesaOps[JNE7,  JNE8,  JNE9,  JNEB,  JLB,   JGEB,  JGB,   JLEB];		* 23x
MesaOps[JULB,  JUGEB, JUGB,  JULEB, JZEQB, JZNEB, JIB,   JIW];		* 24x
MesaOps[ADD,   SUB,   MUL,   DBL,   DIV,   LDIV,  NEG,   INC];		* 25x
MesaOps[AND,   OR,    XOR,   SHIFT, DADD,  DSUB,  DCOMP, DUCOMP];	* 26x
MesaOps[ADD01,  ,      ,      ,      ,      ,      ,      ];		* 27x

MesaOps[EFC0,  EFC1,  EFC2,  EFC3,  EFC4,  EFC5,  EFC6,  EFC7];		* 30x
MesaOps[EFC8,  EFC9,  EFC10, EFC11, EFC12, EFC13, EFC14, EFC15];	* 31x
MesaOps[EFCB,  LFC1,  LFC2,  LFC3,  LFC4,  LFC5,  LFC6,  LFC7];		* 32x
MesaOps[LFC8,  LFC9,  LFC10, LFC11, LFC12, LFC13, LFC14, LFC15];	* 33x
MesaOps[LFC16, LFCB,  SFC,   RET,   LLKB,  PORTO, PORTI, KFCB];		* 34x
MesaOps[DESCB, DESCBS,BLT,   BLTL,  BLTC,   ,     ALLOC, FREE];		* 35x
MesaOps[IWDC,  DWDC,  STOP,  CATCH, MISC,  BITBLT,STARTIO, ];		* 36x
MesaOps[DST,   LST,   LSTF,   ,     WR,    RR,    BRK,    ];		* 37x

*-----------------------------------------------------------
* IFU entry point macros
*-----------------------------------------------------------
* Call(s) should appear IMMEDIATELY BEFORE the entry vector.
* Each call defines a label "@opcode" at the current IM location, and
* forces the next nEntryPoints instructions to comprise an IFU entry vector.

* Note: due to MicroD symbol table overflow problems, a label "@opcode"
* is defined only for the first opcode in a group of consecutive declarations.

* IFUR[opcode, length, memBase, options];	Regular opcode
* IFUP[opcode, length, memBase, options];	Pause opcode
* IFUJ[opcode, length, memBase, options];	Jump opcode

* opcode = one of the opcode names defined above
* length = 1, 2, or 3
* memBase = defined MemBase name

* Options (zero or more, in any order):
* N[n]		n = 0 to 16 or "noN"
* SignExtend
* PackedAlpha
* RBase[rBase]	rBase = MesaRegs or AEmRegs (Alto mode only -- not PrincOps)
* Disp[n]	n = -40 to 37 (displacement for 1-byte jumps)

M[IFUR, IOpLabel[#1] (IOp#4, IOp#5, IOp#6, IOp#7, IFUDeflt)
  IFUReg[MOp#1, #2, #3, RShift[CRB@, 4], ILC, IValN, IValSign, IValPA]];
M[IFUP, IOpLabel[#1] (IOp#4, IOp#5, IOp#6, IOp#7, IFUDeflt)
  IFUPause[MOp#1, #2, #3, RShift[CRB@, 4], ILC, IValN, IValSign, IValPA]];
M[IFUJ, IOpLabel[#1] (IOp#4, IOp#5, IOp#6, IOp#7, IFUDeflt)
  IFUJmp[MOp#1, #2, #3, RShift[CRB@, 4], ILC, IValSign]];

M[IOp, ];
M[IOpN, Set[IValN, #1]];
M[IOpSignExtend, Set[IValSign, 1]];
M[IOpPackedAlpha, Set[IValPA, 1]];
M[IOpDisp, Set[IValSign, #1]];
:If[AltoMode];		********** Alto version **********
Equate[IOpRBase, KnowRBase];
:EndIf;			**********************************

M[IFUDeflt, TopLevel[] KnowRBase[RMforIFU]
  Set[IValN, 17] Set[IValSign, 0] Set[IValPA, 0]];

Set[LastILC, 177777];
M[IOpLabel, IfE[IP[ILC], LastILC, , @#1: Set[LastILC, IP[ILC]]]];

*-----------------------------------------------------------
* IFU exit macros and top-of-stack conventions
*-----------------------------------------------------------

*	[0]: TOS = Stack[StkP], TOS-1 = Stack[StkP-1]
*	[1]: TOS = MD, TOS-1 = T & Stack[StkP-1]
*	[2]: TOS = T & Stack[StkP+1], TOS-1 = Stack[StkP]

* State 0 is the canonical form, with all values stored in the hardware stack.
* It is the only form if a single entry point is being used.

* IFUNextN = IFUJump[N] if 3 entry points are being used.

* If only 1 entry point, IFUNext0 or IFUNext0CF is the normal exit (IFUNext0CF
* checks for faults first).  IFUNext1 branches to code that puts MD on the
* stack and exits.  IFUNext2 is ordinarily illegal, but can be used with the
* special "StackT" source and destination:
*	StackT← (StackT)+T, IFUNext2;
* is equivalent to:
*	Stack&-1← T← (Stack&-1)+T, IFUJump[2]; * if 3 entry points, but
*	Stack← (Stack)+T, IFUJump[0];	* if 1 entry point.

Set[multEntryPoints, IfE[nEntryPoints, 1, 0, 177777]];
M[IfMEP, If[multEntryPoints]];
M[If1EP, If[Not[multEntryPoints]]];

:IfMEP;
M[IFUNext0, IFUJump[0]];
M[IFUNext1, IFUJump[1]];
M[IFUNext2, IFUJump[2]];
M[IFUNext0CF, IFUJump[0]];
M[StackT←, Stack&-1←T←]; Equate[StackT, Stack&-1];
:Else;
M[IFUNext0, IFUJump[0]];
M[IFUNext1, Branch[PushMD]];
M[IFUNext2, IFUJump[0]];
M[IFUNext0CF, Branch[CheckFault0]];
Equate[StackT←, Stack←]; Equate[StackT, Stack];
:EndIf;


*-----------------------------------------------------------
* MISC opcode entry definition
*-----------------------------------------------------------
* MiscTable[n] places the current instruction at the entry point for
* MISC operation n.

Set[MT0Loc, 4000];	* Base for 000-077 dispatch
Set[MT1Loc, 4400];	* Base for 100-177 dispatch
Set[MT2Loc, 6000];	* Base for 200-277 dispatch
Set[MT3Loc, 6400];	* Base for 300-377 dispatch

M[MiscTable,
  At[Select[RShift[#1, 6], MT0Loc, MT1Loc, MT2Loc, MT3Loc],
    Add[LShift[And[#1, 77], 2], 1]]];

:If[AltoMode];		********** Alto version **********
M[MiscOpcodeUnimplemented,
  (MiscTable[#1], T← sUnimplemented, StkP-1, Branch[SavePCAndTrap])];
:Else;			******** PrincOps version ********
M[MiscOpcodeUnimplemented,
  (MiscTable[#1], Branch[UnimplOpcodeTrap])];
:EndIf;			**********************************

% Dorado Alto-Mesa microcode
Note: most of these conventions currently apply to Pilot Mesa as well,
though the PrincOps says otherwise!

This code is strictly for Mesa 6
	AV=1000C
	SD=1100C
	GFT=1400C

State Block Configuration (Alto Mesa)
	alpha		Stack[1]
	 ...
	alpha+7		Stack[8]
	alpha+10	brkbyte,,skp
	alpha+11	mx (dest)
	alpha+12	my (source)

Local frame
	L	-> global frame
	L+1	PC (Alto: if PC odd then -(PC/2) else PC/2)
	L+2	-> caller's frame
	L+3	Alto: unused; PrincOps: place to store trap parameter
	L+4	local 0
	L+5	...

Global frame configuration
	G-3	...
	G-2	external link 1
	G-1	external link 0
	G	GFI,,code links(1 bit) [code links=0 => links are in 
				the frame, =1 => in the code segment]
	G+1	code base low
	G+2	code base high (Alto XMesa or PrincOps)
	G+3	global 0
	G+4	...

Code segment
	C-3	...
	C-2	external link 1
	C-1	external link 0
	CP	reserved
	CP+1	reserved
	...
	CP+2n+2	word pc offset (n = procedure number, as in LFCn)
	CP+2n+3	frame size index (in lower byte)
	...
%

%
*-----------------------------------------------------------
Alto-Mesa notes:
*-----------------------------------------------------------

Alto-Mesa differs from PrincOps in the following systematic ways:

1. The byte order of code is backwards (right=even, left=odd).
This is true ONLY of code, not of arbitrary byte arrays (e.g., jump tables).

2. All 3-byte instructions are aligned.  This means that if the opcode
is an even byte, the odd byte is ignored and alpha,,beta is taken from
the next full word.  (Note the byte order of alpha,,beta!)
A few 1-byte instructions are also aligned.  This means that if the opcode
is an even byte, the odd byte is ignored and the next opcode is taken from
the even byte of the next word.

3. Jump displacements are measured from the last byte of the instruction,
not from the opcode.

4. Frame displacements are handled inconsistently.  Local 0 is word 4
of the local frame.  In "Byte" instructions (e.g., LLB), the operand byte
already includes the offset, but in "N" and "Pair" instructions it does
not.  That is, the following instructions refer to the same item (local 0):
	LL0
	LLB 4
	RILP <0,,x>

(n.b. at present, Pilot follows this convention also.)

5. Alto-Mesa imposes "minimal stack" requirements in certain instructions.
However, this Mesa implementation requires minimal stack only in the
process/monitor opcodes.
%