BUILTIN[M,2];		*Declare macro
BUILTIN[N,3];		*Declare neutral
BUILTIN[MEMORY,4];	*Declare Memory[NAME,WORDSIZE,LENGTH,SRCMACRO,
			*SINKMACRO]
BUILTIN[TARGET,5];
BUILTIN[DEFAULT,6];
BUILTIN[FLX,7];		*Declare field
BUILTIN[PF,10];		*Preassign value to field
BUILTIN[SET,11];	*Declare integer and set value
BUILTIN[ADD,12];	*Add up to 8 integers
BUILTIN[IP,13];		*Integer part of address
BUILTIN[IFSE,14];	*If string #1 .eq. string #2 then #3, else #4
BUILTIN[IFA,15];	*If any bits of field #1 assigned then #2, else #3
BUILTIN[IFE,16];	*If integer #1 .eq. integer #2 then #3, else #4
BUILTIN[IFG,17];	*If integer #1 .gr. integer #2
BUILTIN[IFDEF,20];	*If string #1 in symbol table and not unbound
			*address then #2, else #3
BUILTIN[IFME,21];	*If memory part of address #1 .eq. string #2 then
			*#3, else #4
BUILTIN[ER,22];		*Error message (ER[STRING,ABORTFLAG,INT])
BUILTIN[LIST,23];	*Set listing mode for memory
*BUILTIN[INSERT,24];	*Insert file
BUILTIN[NOT,25];	*1's complement
BUILTIN[REPEAT,26];	*Repeat the text #2 #1 times
BUILTIN[OR,27];		*Inclusive OR up to 8 integers
BUILTIN[XOR,30];	*Exclusive OR up to 8 integers
BUILTIN[AND,31];	*AND up to 8 integers
BUILTIN[COMCHAR,32];	*Set comment char for conditional assembies
*BUILTIN[BITTABLE,33];	*Makes #1 a bit table of length #2 bits
*BUILTIN[GETBIT,34];	*Is the bit in bittable #1 at pos. #2
*BUILTIN[SETBIT,35];	*SETBIT[table,bit1,nbits,distance,val]
*BUILTIN[FINDBIT,36];	*FINDBIT[table,bit1,nbits,distance,hopdist,nhops]
*BUILTIN[MEMBT,37];	*MEMBT[MEMORY,TABLE] creates a bit table for memory
BUILTIN[LSHIFT,40];	*Shifts the integer #1 left #2 positions
BUILTIN[RSHIFT,41];	*Shifts the integer #1 right #2 positions
BUILTIN[FVAL,42];	*FVAL[field] is an integer whose value is the
			*current contents of the field
BUILTIN[SELECT,43];	*#1 is an integer .ge. 0 and .le. 7.  Evaluates
			*#2 IF #1 = 0, ..., #9 if #1 = 7.  Error if #1 > 7
BUILTIN[SETPOST,44];	*Set post-evaluation macro (SETPOST[mem,macro])
BUILTIN[LISTFIELDS,46];	*LISTFIELDS[mem,word] assembles word as for DEFAULT
			*and the 1-bits denote the right-most bits of
			*fields in the octal listing.
BUILTIN[SETMBEXT,47];	*Set .MB file extension
BUILTIN[SUB,50];	*SUB[a1,a2,...,an] = a1-a2-...-an (16-bit args)

COMCHAR[~];		*Makes "*~" work like "%" at beginning of lines

SETMBEXT[DIB];

%Micro runs faster when tokens used in macros are defined before the macro
definition, and the arrangment of the stuff in this file is partially the
result of this consideration.
%

ER[D1Lang-model1.10/20/78];	*Print release date on .ER file

*IM field definitions in arrangement expected by MicroD
FLX[RSTK,0,3];		*RM address, STKP modification
  FLX[RSTK13,1,3];	*Three low bits (for IM←)
  FLX[RSTK23,2,3];	*Two low bits (for READIM)
FLX[ALUF,4,7];		*ALU function select (address in ALUFM)
FLX[BSEL,10,12];	*Source for B
  FLX[BSEL0,10,10];	*High bit of BSEL (indicates constant selected)
FLX[LC,13,15];		*Controls source and load of R and T
FLX[ASEL,16,20];	*A op select
  FLX[ASEL0,16,16];
FLX[BLK,21,21];		*Block task (non-emulator) -or- stack op (emulator)
FLX[FF,22,31];		*Function
  FLX[FA,22,23];	*FF[0:1] used with mem ops
  FLX[F1,22,25];	*FF[0:3] used with constants and FF shifts
  FLX[F2,26,31];	*FF[4:7] "
  FLX[FBC,24,31];	*FF[2:7] used for FF < 100 decodes
FLX[JCN,32,41];		*Jump control
FLX[BRKP,42,43];	*PE16 and PE17 both 0 (no brkp) or both 1 (brkp)

%Dispatch table stuff isn't ready yet.
FLX[DTAB,44,57];	*Dispatch table applicable to this instruction

*60:63 unused
FLX[BEONES,64,77];	*Additional bits in placement that must be 1's

Interim kludges:
%
FLX[@GPW0,61,77];
FLX[@W0,61,61];
FLX[GLB,62,62];

FLX[RETCL,100,101];	*2 = does a RETURN, CORETURN, or IFUJUMP
			*1 = does a CALL or CORETURN
FLX[JBC,102,102];	*Has a branch condition in JCN
FLX[UFF,103,103];	*FF field unavailable for long GoTo or long Call
  FLX[JUFF,102,103];	*Combination of JBC and UFF fields
FLX[W1,104,117];	*Imaginary address of unconditional or false branch

FLX[BRGO,120,121];	*2 = branches
			*1 = goes
FLX[EMUL,122,122];	*Print as emulator instruction
FLX[ISCOND,123,123];	*Has a branch condition
FLX[W2,124,137];	*Imaginary address of conditional branch when true



*Fields for IFUM assembly
FLX[PA,0,0];		*Packed alpha (shifted to bit 5 by MicroD)
FLX[NENT,1,2];		*No. instructions in entry vectors-1
FLX[IFD,4,17];		*IM address (transformed by MicroD and put in 6:17)
FLX[SGN,20,20];		*Sign
*Three parity bits filled in by Midas
FLX[LEN',24,25];	*Length'
FLX[LEN,26,27];		*Length (1, 2, or 3 bytes)
FLX[MEMB,30,31];	*MemBase init
FLX[TPAUSE,32,32];	*Pause opcode
FLX[TJUMP,33,33];	*Jump opcode
FLX[OP,34,37];		*N

*The ? neutral is used with expressions not intended for connection
*to other expressions.
N[?];

%The various sources and destinations connected by "←" reduce to the
following source and destination classes:
%
N[RB];	*Feed A, B, or shifter
N[T];	*Feed A or B
N[MD];	*Feed R, T, B, or A (unspecific about immediate or deferred)
N[MDDEF];	*Deferred MD reference
N[B];	*B
N[XB];	*Slow B
N[A];	*A
N[Q];	*Feeds B (BSEL) or A (FF64, FETCH←, or STORE←)
N[ID];	*A, FETCH←, or STORE←
N[PD];	*ALU ops, INPUT function, or ALUFM read
N[SC];	*Small constants

*Destinations expecting small constant as source (also RBASE←B, MEMBASE←B,
*and CNT←B)
N[RBASE←]; N[CNT←]; N[MEMBASEX←]; N[MEMBASE←]; N[MEMBX←];

N[RB←];		N[T←];		N[B←];		N[PD←];		N[A←];
N[FETCH←];	N[STORE←];	N[MM←];

*Connection macros
M[B←B,B];	M[B←XB,XB];
M[MAPBUF←,B←];	M[DBUF←,B←];
M[A←A,A];	M[PD←PD,PD];


*Define integers here before they are used for faster assembly
SET[ZOT,0];	SET[ZOT1,0];	SET[SCONS,0];	SET[RBOUND,0];
SET[!T1,0];	SET[!T2,0];	SET[TSD,1];	SET[CRB,0];

SET[XTASK,0];		*Task for which instructions are being assembled
			*(affects STK stuff, references)

M[TMARGS,ER[Too.many.args.for.#1]];
M[FFT,ER[FF.used.twice]];
M[FAT,ER[FA.used.twice]];
M[IMPB,ER[Impossible.B←]];

M[ILLIO,IFE[XTASK,0,EMUL[1],ER[#1.ill.in.io.task]]];
M[ILLEM,IFE[XTASK,0,ER[#1.ill.in.emu]]];
M[ILL1-16,IFE[XTASK,0,EMUL[1],IFE[XTASK,17,EMUL[1],ER[#1.ill.in.io.task]]]];
M[ILL0&17,IFE[XTASK,0,ER[#1.ill.in.emu],IFE[XTASK,17,ER[#1.ill.in.flt]]]];

M[FF64,IFA[FBC,(FFT),IFA[ISCOND,JUFF[3],UFF[1]]FBC[#1]]];
M[FF256,IFA[FF,(FFT),IFA[ISCOND,JUFF[3],UFF[1]]FF[#1]]];

*The following macros define B destinations encodable as either
*FF64's or, if FF encodes an external B source, in BSEL.
*#1 is the value for FF, #2 for BSEL
M[FFBSL1,IFG[FVAL[FF],177,(IMPB),IFG[FVAL[FF],157,BSEL[#1],(IMPB)]]];
M[FFBSEL,IFA[FBC,IFE[FVAL[ASEL0],1,FFBSL1[#2],(IMPB)],FF64[#1]]];
M[FFBSEL256,IFA[FF,IFE[FVAL[ASEL0],1,FFBSL1[#2],(IMPB)],FF256[#1]]];

*Source and sink macros invoked when address symbols in the text appear
*as sources or destinations in "←" clauses.

**Macros for real RM addresses
M[RSA,IFA[RSTK,IFE[FVAL[RSTK],ZOT1,,FF64[ADD[40,ZOT1]]],RSTK[ZOT1]]];
M[RSINK,(SET[ZOT,IP[#1]] SET[ZOT1,AND[ZOT,17]]
  IFE[AND[360,ZOT],CRB,
    IFG[XTASK,0,RSA,IFE[FVAL[BLK],1,FF64[ADD[40,ZOT1]],BLK[0] RSA]],
    RSTK[ZOT1] FF256[ADD[220,RSHIFT[ZOT,4]]]
  ])
RB←];

*Cleverly generate "value-won't-fit" error on read outside region
M[RSRC,RSTK[XOR[CRB,IP[#1]]] IFE[XTASK,0,BLK[0]] RB];

**Macros for RBASE-relative addresses
M[RDSRC,RSTK[#1]IFE[XTASK,0,BLK[0]]RB];
M[RDSINK,IFA[RSTK,
  IFE[FVAL[RSTK],IP[#1],,FF64[ADD[40,IP[#1]]]],RSTK[#1]]RB←];

M[W,];				*Dummy macro required for memory def.
M[TSRC,IP[#1]C];		*Make constant from TASKN address
M[DVSRC,LSHIFT[IP[#1],10]C];	*Make constant from DEVICE address
M[BRSRC,IP[#1]S];

%Memory names and sizes must agree with those in Midas, except that IM and
IFUM must agree with the form expected by MicroD.  Also, MicroD consumes
VERSION, RVREL, IMLOCK, and DISP, which are not passed through to Midas.
%
MEMORY[IM,140,10000,W,W];
MEMORY[RM,20,200,RSRC,RSINK];
MEMORY[IFUM,40,2000,W,W];
MEMORY[ALUFM,10,20,W,W];
MEMORY[BR,40,40,BRSRC,W];	*Fake to show MemBase contents symbolically
MEMORY[DEVICE,20,400,DVSRC,W];	*Fake to show TIOA contents symbolically
MEMORY[TASKN,20,20,TSRC,W];	*Fake to show tasks symbolically
MEMORY[VERSION,20,1,W,W];	*Fake to tell MicroD this is Dorado model 1
MEMORY[RVREL,0,20,RDSRC,RDSINK]; *Fake memory for RM stuff
MEMORY[IMLOCK,1,10000,W,W];	*Fake memory for MicroD word reservations
MEMORY[DISP,40,10000,W,W];	*Dispatch table info passed to MicroD

%2nd arg of LIST controls output as follows:
1 = (TAG) nnnn nnnn nnnn ...
2 = (TAG) F1←3, F2←4, ...
4 = numerically-ordered list of address symbols
10 = alphabetically-ordered list of address symbols
20 = (TAG) 1nnnnn 1nnnnn ... (16-bit printout iff 1 set also)
LISTFIELDS overrules the 1 and 20 numeric printout modes
%
LISTFIELDS[IM,RSTK[1] ALUF[1] BSEL[1] LC[1] ASEL[1] BLK[1] FF[1] JCN[1]
*  DTAB[1] BEONES[1]
  @GPW0[1]
  RETCL[1] JBC[1] UFF[1] W1[1]
  BRGO[1] EMUL[1] ISCOND[1] W2[1] ];
LISTFIELDS[IFUM,PA[1] NENT[1] IFD[1] SGN[1] LEN'[1] LEN[1] MEMB[1]
  TPAUSE[1] TJUMP[1] OP[1] ];
LIST[IM,25]; LIST[RM,25]; LIST[IFUM,21]; LIST[ALUFM,21];
LIST[BR,4]; LIST[DEVICE,4]; LIST[TASKN,4];
LIST[VERSION,0]; LIST[IMLOCK,0]; LIST[DISP,0]; LIST[RVREL,4]; LIST[,25];

IM[ILC,0];		*Location counter for IM
DISP[DLC,0];		*Location counter for DISP
VERSION[VERLC,0]; VERLC[1000];	*Indicate Dorado model 1

TASKN[EMU,0];	TASKN[FLT,17];

%Three macros define parameters from which constants, small constants,
RM values, or IM data can be constructed:
   MP[NAME,octalstring] makes a parameter of name;
   SP[NAME,P1,P2,P3,P4,P5,P6,P7,P8] makes a parameter NAME equal to the sum
of P1, P2, P3, P4, P5, P6, P7, and P8, where the Pn may be parameters or
integers.
   NSP[NAME,P1,P2,P3,P4,P5,P6,P7,P8] is ones complement of SP.

The parameter "NAME" is defined by the integer "NAME!", so it is ok to
use "NAME" for a constant as well as a parameter.  However, it is illegal
to define constants, small constants, addresses, etc. with identical names.

"Literal" constants such as "322C", "177422C", "32400C", or "32377C"
or literal small constants such as "14S", etc. may be inserted in
microinstructions without previous definition.

Alternatively, constants may be constructed from parameters and integers
using the following macros:
   MC[NAME,P1,P2,P3,P4,P5,P6,P7,P8] defines name as a constant with value =
sum of parameters P1, P2, P3, P4, P5, P6, P7, and P8;
   NMC[NAME,P1,P2,P3,P4,P5,P6,P7,P8] is the ones complement of MC;
   MSC[NAME,P1,P2,P3,P4] defines a small constant.

Note:  MC, NMC, and MSC also define NAME as a parameter.
%

*fields for initializing 20-bit wide memories
FLX[E0,0,3]; FLX[E1,4,17];

*Macro to initialize 20-bit variables in the target memory.  This is done
*by writing 32100V (i.e., as a literal).
M[V,E1[#1] E0[#2]];

M[!,0];
M[MP,SET[#1!,#2]];
M[PX,IFDEF[#1!,#1!,#1]];
M[DPS,ADD[PX[#1],PX[#2],PX[#3],PX[#4],PX[#5],PX[#6],PX[#7],PX[#8]]];
M[SP,IFG[#0,11,TMARGS[#1],SET[#1!,DPS[#2,#3,#4,#5,#6,#7,#8,#9]]]];
M[NSP,IFG[#0,11,TMARGS[#1],SET[#1!,NOT[DPS[#2,#3,#4,#5,#6,#7,#8,#9]]]]];


M[C,IFE[AND[#3#2,177760],0,
  SET[!T1,ADD[LSHIFT[#2,4],RSHIFT[#1,10]]] SET[!T2,AND[#1,377]]
  IFE[!T1,0,BSEL[4]FF256[!T2],
    IFE[!T2,0,BSEL[6]FF256[!T1],
      IFE[!T1,377,BSEL[5]FF256[!T2],
        IFE[!T2,377,BSEL[7]FF256[!T1],ER[Illegal.constant]]
      ]
    ]
  ],ER[Constant.too.big]]B
];

M[-C,SUB[0,#3#2#1]C];

M[MC,IFG[#0,11,TMARGS[#1],
  SP[#1,DPS[#2,#3,#4,#5,#6,#7,#8,#9]] M[#1,ADD[#1!]C]]];

M[NMC,IFG[#0,11,TMARGS[#1],
  SP[#1,NOT[DPS[#2,#3,#4,#5,#6,#7,#8,#9]]] M[#1,ADD[#1!]C]]];

M[S,SET[SCONS,#2#1] SC];

M[MSC,IFG[#0,5,TMARGS[#1],SP[#1,DPS[#2,#3,#4,#5]] M[#1,ADD[#1!]S]]];

%RM stuff

RM constants and variables are allocated in regions defined by:
  RMREGION[RGNNAME]	20-long region

Subsequently, storage can be assigned in that region as follows:
  RV[NAME,P1,...,P8];	defines name as an address with initial value
			sum-of-parameters.
  32333R		in a microinstruction creates (if undefined)
			and references a literal.  Duplicating literals
			in other regions is illegal.
  RVN[NAME]		creates name without initial value;
  RVREL[NAME,DISP]	defines a regionless address for references
			relative to the current RBASE.
  RESERVE[N]		skips N (an integer) locations in the current region
			(presumably because RVREL addresses will refer to them)

The assembler checks that the base for an RM address agrees with the value
believed to be in the RBASE register.  This can be declared by:
  KNOWRBASE[RGNNAME]	declares RGNNAME to be in RBASE

RBASE can be loaded by:
  RBASE←RBASE[RADDR] -or-	loads RBASE with a small constant whose value
  RBASE←RBASE[RGNNAME]		is the top four bits of RADDR or RGNNAME and
				declares this the current region.
%

*The new RBASE NRB is propagated to CRB by the IM post-macro
SET[NRB,0]; *Init for NRB
M[FIXRBASE,SET[NRB,AND[#1,177760]]];
M[KNOWRBASE,SET[ZOT,IFDEF[!#1,!#1,IP[#1]]] FIXRBASE[ZOT] SET[CRB,NRB]];
M[RBASE,SET[ZOT,IFDEF[!#1,!#1,IP[#1]]] FIXRBASE[ZOT] RSHIFT[ZOT,4]S];

%A region is defined by a location counter "!NAME" (an integer).
%
SET[NRGN,177760];		*address for next region
M[RMREGION,IFDEF[!#1,ER[#1.already.defined],
  IFE[NRGN,360,ER[Too.many.RM.regions.at.#1],
    SET[NRGN,ADD[NRGN,20]] SET[!#1,NRGN]
    SET[RBOUND,OR[!#1,17]] RM[RLC,!#1]]]];

M[RBCHK,IFG[IP[RLC],RBOUND,ER[RM.region.overflow.at.#1]]];
M[RV,IFG[#0,11,TMARGS[#1],
  RBCHK[#1] RLC[#1: DPS[#2,#3,#4,#5,#6,#7,#8,#9]V]]];
M[R,#2#1R(RLC[#2#1R: E1[#1] E0[#2]],
  IFSE[#3,,,ER[#3#2#1R???]] RBCHK[#1])];
M[RVN,RBCHK[#1] RM[#1,IP[RLC]] RM[RLC,ADD[IP[RLC],1]]];
M[RESERVE,RM[RLC,ADD[IP[RLC],#1]]];

*Stack stuff
M[EMCHK,BLK[1]RSTK13[#1]ILLIO[Stack.op]];
M[UEMCHK,BLK[1]RSTK[#1]ILLIO[Stack.op]];

*No StkP=0 underflow check on read because pointer will go negative.
*If also writing STK, write macro will impose the StkP←0 underflow check.
M[STACK&-4,RB(EMCHK[4])];
M[STACK&-3,RB(EMCHK[5])];
M[STACK&-2,RB(EMCHK[6])];
M[STACK&-1,RB(EMCHK[7])];

*StkP=0 underflow check is required
M[STACK,RB(UEMCHK[10])];
M[STACK&+1,RB(UEMCHK[11])];
M[STACK&+2,RB(UEMCHK[12])];
M[STACK&+3,RB(UEMCHK[13])];

*These modify the stack pointer after writing, so no check for StkP←0
*is required.
M[STACK&-4←,RB←(EMCHK[4])];
M[STACK&-3←,RB←(EMCHK[5])];
M[STACK&-2←,RB←(EMCHK[6])];
M[STACK&-1←,RB←(EMCHK[7])];
M[STACK&+1←,RB←(EMCHK[1])];
M[STACK&+2←,RB←(EMCHK[2])];
M[STACK&+3←,RB←(EMCHK[3])];

*These modify the stack pointer before writing, so must check for StkP←0
*when decrementing the pointer and must use the ModStkPBeforeW function.
M[STACK-4←,RB←(UEMCHK[14],FF64[27])];
M[STACK-3←,RB←(UEMCHK[15],FF64[27])];
M[STACK-2←,RB←(UEMCHK[16],FF64[27])];
M[STACK-1←,RB←(UEMCHK[17],FF64[27])];
M[STACK←,RB←(UEMCHK[10])];

M[STACK+1←,RB←(EMCHK[1],FF64[27])];
M[STACK+2←,RB←(EMCHK[2],FF64[27])];
M[STACK+3←,RB←(EMCHK[3],FF64[27])];

*For STKP change without reference
N[STKP←];  N[STKP+3]; N[STKP+2]; N[STKP+1];
N[STKP-4]; N[STKP-3]; N[STKP-2]; N[STKP-1];
M[STKP←STKP-4,?(EMCHK[4])];
M[STKP←STKP-3,?(EMCHK[5])];
M[STKP←STKP-2,?(EMCHK[6])];
M[STKP←STKP-1,?(EMCHK[7])];
M[STKP←STKP+1,?(EMCHK[1])];
M[STKP←STKP+2,?(EMCHK[2])];
M[STKP←STKP+3,?(EMCHK[3])];

M[BLOCK,ILLEM[BLOCK]BLK[1]];

M[BREAKPOINT,BRKP[3]];

%Shifter stuff:

Macro to build an RM value that is a shifter descriptor:
  RVSH[name,LMask,RMask,TR,shiftcount] makes an RB constant.
where TR is 0 to 3 to select RR, RT, TR, or TT as left-right
shifter inputs.
%
FLX[LMSK,14,17]; FLX[RMSK,10,13]; FLX[TRSL,2,3]; FLX[SCNT,4,7];
M[RVSH,RBCHK[#1] RLC[(#1: LMSK[#2]RMSK[#3]TRSL[#4]SCNT[#5])]];

%Compound shift expressions of the forms:
  LSH[X,shiftcount,Y]
  RSH[X,shiftcount,Y]
  LDF[X,size,pos,Y]
  DPF[X,size,pos,Y]
  RCY[U,V,cyclecount]
  LCY[U,V,cyclecount]
where X may be an RM address or T, shiftcount an integer in the range 0 to
17, Y either MD or 0 (defaulted to 0 if omitted), U and V are an RM address
and T in either order.
%
M[DOSF,(ASEL[7]BSEL[#1] PD,IFA[FF,(FFT),F1[#2] F2[#3]])];

M[DOLDF,(DOSF[IFSE[#1,T,7,4],SUB[20,#2],AND[17,SUB[20,#3]]],#1)];
M[DORSH,(DOSF[IFSE[#1,T,7,4],#2,AND[17,SUB[20,#2]]],#1)];
M[DODPF,(DOSF[IFSE[#1,T,7,4],SUB[20,#2,#3],#3],#1)];
M[DOLCY,IFSE[#1,T,
  (IFSE[#2,T,DOSF[7,0,#3],(DOSF[6,0,#3],#2)]),
  (IFSE[#2,T,DOSF[5,0,#3],(DOSF[4,0,#3],#2)],#1)
]];

*RCY reverses args of left cycle unless count = 0
M[RCY,ALUF[0] IFE[#3,0,DOLCY[#1,#2,0],DOLCY[#2,#1,SUB[20,#3]]]];
M[LCY,ALUF[0] DOLCY[#1,#2,#3]];
M[RSH,ALUF[IFSE[#3,MD,12,2]] DORSH[#1,#2]];
M[LDF,ALUF[IFSE[#4,MD,12,2]] DOLDF[#1,#2,#3]];
M[LSH,ALUF[IFSE[#3,MD,14,4]] (DOSF[IFSE[#1,T,7,4],0,#2],#1)];
M[DPF,ALUF[IFSE[#4,MD,16,6]] DODPF[#1,#2,#3]];

M[XRCY,ALUF[1] IFE[#3,0,DOLCY[#1,#2,0],DOLCY[#2,#1,SUB[20,#3]]]];
M[XLCY,ALUF[1] DOLCY[#1,#2,#3]];
M[XRSH,ALUF[IFSE[#3,MD,13,3]] DORSH[#1,#2]];
M[XLDF,ALUF[IFSE[#4,MD,13,3]] DOLDF[#1,#2,#3]];
M[XLSH,ALUF[IFSE[#3,MD,15,5]] (DOSF[IFSE[#1,T,7,4],0,#2],#1)];
M[XDPF,ALUF[IFSE[#4,MD,17,7]] DODPF[#1,#2,#3]];

*Shifter ops assembled as ALU outputs
M[SHFTOP,(ALUF[#1] ASEL[7] PD, #2)];

M[SHIFTNOMASK,SHFTOP[0,#1]];
M[SHIFTLMASK,SHFTOP[2,#1]];
M[SHIFTRMASK,SHFTOP[4,#1]];
M[SHIFTBOTHMASKS,SHFTOP[6,#1]];
M[SHMDNOMASK,SHFTOP[10,#1]];	*Pretty useless--same as SHIFTNOMASK
M[SHMDLMASK,SHFTOP[12,#1]];
M[SHMDRMASK,SHFTOP[14,#1]];
M[SHMDBOTHMASKS,SHFTOP[16,#1]];

M[XSHIFTNOMASK,SHFTOP[1,#1]];
M[XSHIFTLMASK,SHFTOP[3,#1]];
M[XSHIFTRMASK,SHFTOP[5,#1]];
M[XSHIFTBOTHMASKS,SHFTOP[7,#1]];
M[XSHMDNOMASK,SHFTOP[11,#1]];
M[XSHMDLMASK,SHFTOP[13,#1]];
M[XSHMDRMASK,SHFTOP[15,#1]];
M[XSHMDBOTHMASKS,SHFTOP[17,#1]];

%Stuff for ASEL field and memory references
%

M[AGRB,IFE[FVAL[ASEL],7,FF64[20],ASEL[4]] A];
M[AGID,ASEL[5] ILLIO[ID] A];
M[AGT,IFE[FVAL[ASEL],7,FF64[21],ASEL[6]] A];
*ASEL=7 is shifts, defined earlier and below
M[AGMD,FF64[22] A];
M[AGQ,FF64[23] A];
M[AGSC,IFG[20,SCONS,FF64[SCONS],ER[Illegal.A←SC]] A];

M[A←Q,AGQ]; M[A←MD,AGMD]; M[A←T,AGT]; M[A←ID,AGID]; M[A←RB,AGRB]; M[A←SC,AGSC];

M[PRISRC,IFE[FVAL[BSEL0],1,,IFA[FA,(FAT),PF[FA,3]]] A];
M[SECSRC,IFA[FA,(FAT),FA[#1]]];
M[SREF0,ASEL[0] IFA[FA,(FAT),FA[#1]] MM←];
M[SREF1,ASEL[1] IFA[FA,(FAT),FA[#1]] MM←];

*Illegal use of an FF>77 to the left of a FETCH←/STORE←RM/T is
*not detected as an error.
M[FETCH←RB,ASEL[1] PRISRC];
M[FETCH←T,ASEL[3] PRISRC];
M[FETCH←MD,ASEL[3] SECSRC[0] A];
M[FETCH←ID,ASEL[3] SECSRC[1] A];
M[FETCH←Q,ASEL[3] SECSRC[2] A];
M[FETCH←SC,ASEL[1] SECSRC[3] AGSC];

M[STORE←RB,ASEL[0] PRISRC];
M[STORE←T,ASEL[2] PRISRC];
M[STORE←MD,ASEL[2] SECSRC[0] A];
M[STORE←ID,ASEL[2] SECSRC[1] A];
M[STORE←Q, ASEL[2] SECSRC[2] A];
M[STORE←SC,ASEL[0] SECSRC[3] AGSC];

M[PREFETCH←,SREF0[0]];
M[LONGFETCH←,SREF0[1]];
M[MAP←,ILL1-16[MAP←] SREF0[2]];
M[IOFETCH←,ILL0&17[IOFETCH←] SREF0[2]];

M[DUMMYREF←,SREF1[0]];
M[IFETCH←,ILLIO[IFETCH←] SREF1[1]];
M[FLUSH←,ILL1-16[FLUSH←] SREF1[2]];
M[IOSTORE←,ILL0&17[IOSTORE←] SREF1[2]];

M[MM←A,A];
M[MM←RB,A];
M[MM←T,FF64[21] A];
M[MM←MD,FF64[22] A];
M[MM←Q,FF64[23] A];
M[MM←SC,AGSC];


%Stuff for BSEL
%
M[BGMD,BSEL[0]B];	M[B←MD,BSEL[0]B];
M[BGRB,BSEL[1]B];	M[B←RB,BSEL[1]B];
M[BGT,BSEL[2]B];	M[B←T,BSEL[2]B];
*With FF-controlled shifts the B←Q clause (if any) must be to the left of
*the FF-controlled shift clause.  Haven't thought of an efficient way to
*do this any better.
M[BGQ,IFG[FVAL[BSEL],3,IFE[FVAL[ASEL],7,,ER[BSEL.already.set]],BSEL[3]]B];
M[B←Q,BGQ];
*BSEL = 4,5,6,7 are (0,,FF), (377,FF), (FF,,0), and (FF,,377)

%The following macros fix up the LC field according to the R← and T←
selections:
%
M[RERR,ER[Illegal.R←]];
M[RMD,SELECT[FVAL[LC],PF[LC,4],LC[5],RERR,LC[5]FF64[75],,,RERR,RERR]];
M[RH3,SELECT[FVAL[LC],PF[LC,6],LC[7],,LC[2],RERR,RERR,,]];

M[RB←MD,MDDEF(RMD)];	M[RB←MDDEF,MDDEF(RMD)];
M[RB←B,PD←B(RH3)];	M[RB←XB,PD←XB(RH3)];
M[RB←T,PD←T(RH3)];
M[RB←RB,PD←RB(RH3)];
M[RB←A,PD←A(RH3)];
M[RB←ID,PD←AGID(RH3)];
M[RB←PD,PD(RH3)];
M[RB←Q,PD←Q(RH3)];
M[RB←SC,PD←AGSC(RH3)];

M[TERR,ER[Illegal.T←]];
M[TMD,SELECT[FVAL[LC],PF[LC,3],TERR,,,LC[5]FF64[75],TERR,LC[2],TERR]];
M[TH3,SELECT[FVAL[LC],PF[LC,1],,TERR,TERR,LC[5],,LC[7],]];

M[T←MD,MDDEF(TMD)];	M[T←MDDEF,MDDEF(TMD)];
M[T←B,PD←B(TH3)];	M[T←XB,PD←XB(TH3)];
M[T←T,PD←T(TH3)];
M[T←RB,PD←RB(TH3)];
M[T←A,PD←A(TH3)];
M[T←ID,PD←AGID(TH3)];
M[T←PD,PD(TH3)];
M[T←Q,PD←Q(TH3)];
M[T←SC,PD←AGSC(TH3)];

%Stuff for FF decodes 0 to 77:
%

*FF = 0 to 17 are A←small constants, given earlier
*FF= 20 to 23 select A sources, defined with ASEL stuff

M[XORCARRY,FF64[24] ?];
M[XORSAVEDCARRY,FF64[25]?];
M[CARRY20,FF64[26] ?];
*27 is ModStkPBeforeWrite, used implicitly
*30-31 undefined
M[INPUT,FF64[32] PD];
M[INPUTNOPE,FF64[33] PD];
*Makes A←RM/STK, B←RM/STK, and shifter use ID rather than RM/STK
M[RISID,FF64[34]ILLIO[RISID] ?];
M[TISID,FF64[35]ILLIO[TISID] ?];
M[OUTPUT←,FF64[36] B←];
M[FLIPMEMBASE,FF64[37]?];

*FF = 40 to 57 supply RSTK for write, used implicitly
*FF = 60 to 67 are branch conditions defined with control stuff

M[BIGBDISPATCH←,FF64[70] B←];	*B 256-way dispatch
M[BDISPATCH←,FF64[71] B←];	*B 8-way dispatch
M[MULTIPLY,FF64[72] ?];
M[Q←,FFBSEL[73,3] B←];
*74 undefined
*75 is TGETSMD, used implicitly
M[FREEZEBC,FF64[76]?];
M[NOFF,FF[77] ?];	*No operation--only used in default for IM


%Stuff for FF decodes 100 to 377 (unavailable with memory references)
%
M[PCF←,FF256[100] B←];		*PCF←B and start IFU
M[IFUTEST←,FF256[101] B←];
M[IFUTICK,FF256[102] ?];
*103-104 undefined
M[MEMBASE←B,FF256[105] B];	M[MEMBASE←RB,MEMBASE←BGRB];
  M[MEMBASE←T,MEMBASE←BGT];	M[MEMBASE←MD,MEMBASE←BGMD];
  M[MEMBASE←Q,MEMBASE←BGQ];
M[RBASE←B,FF256[106] B];	M[RBASE←RB,RBASE←BGRB];
  M[RBASE←T,RBASE←BGT];		M[RBASE←MD,RBASE←BGMD];
  M[RBASE←Q,RBASE←BGQ];
M[POINTERS←,FF256[107] B←];
*110-117 undefined

M[LOADTESTSYNDROME,FF256[120] ?];	*Loads from DBuf, ties up Mar
M[LOADMCR,(FF256[121] A←#1,B←#2)];	*Some bits from Mar, some from B
M[BRLO←,FF256[122] A←];
M[BRHI←,FF256[123] A←];
M[PROCSRN←,FF256[124] B←];		*Loads from MapBuf, ties up Mar
M[CFLAGS←,FF256[125] A←];		*Source stable on Mar during
					*preceding cycle
*126-127 undefined Mar sources

M[MOS←,FF256[130] B←];
M[GENOUT←,FF256[131] B←];
M[RESCHEDULE,FF256[132] ?];
M[NORESCHEDULE,FF256[133] ?];

M[IFUMRH←,FF256[134] B←];
M[IFUMLH←,FF256[135] B←];
M[IFURESET,FF256[136] ?];
M[BRKINS←,FF256[137] B←];	*BRKINS←B & set BrkPending

M[USEDMD,FF256[140] ?];
M[MIDASSTROBE←,FF256[141] B←];
M[TASKINGOFF,FF256[142] ?];
M[TASKINGON,FF256[143] ?];
M[STKP←B,FF256[144] B];	M[STKP←RB,STKP←BGRB];	M[STKP←T,STKP←BGT];
  M[STKP←MD,STKP←BGMD]; M[STKP←Q,STKP←BGQ];
M[RESTORESTKP,FF256[145]?];
M[CNT←B,FF256[146] B];	M[CNT←RB,CNT←BGRB];
  M[CNT←T,CNT←BGT];	M[CNT←MD,CNT←BGMD]; M[CNT←Q,CNT←BGQ];
M[LINK←,FF256[147] B←];
M[Q LSH 1,FF256[150] ?];
M[Q RSH 1,FF256[151] ?];
M[TIOA←,FF256[152] B←];
*153 undefined
M[HOLD&TASKSIM←,FFBSEL256[154,2] B←];
M[WF←,FF256[155] A←];
M[RF←,FF256[156] A←];
M[SHC←,FF256[157] B←];

*External B
M[XBOK,IFA[BSEL,ER[Multiple.B.sources],FF256[#1]]];

*From memory external B
M[FAULTINFO',XBOK[160] XB];
M[PIPE0,XBOK[161] XB];		M[VAHI,XBOK[161] XB];
M[PIPE1,XBOK[162] XB];		M[VALO,XBOK[162] XB];
M[PIPE2',XBOK[163] XB];
M[PIPE3',XBOK[164] XB];		M[MAP',XBOK[164] XB];
M[PIPE4',XBOK[165] XB];		M[ERRORS',XBOK[165] XB];
M[CONFIG',XBOK[166] XB];
M[PIPE5',XBOK[167] XB];

*From IFU external BMux
*170 unused
M[JUNK',XBOK[171] XB];
M[IFUMRH',XBOK[172] XB];
M[IFUMLH',XBOK[173] XB];
M[PCX',XBOK[174] B];

M[DBUF,XBOK[175] XB];	*From memory external B

*From Control external BMux
M[RWCPREG,XBOK[176] XB];
M[LINK,XBOK[177] XB];

%Stuff for small constant functions
%
M[SCFN,IFG[#1,SCONS,FF256[ADD[#2,SCONS]],ER[Illegal.arg.for.#3]] ?];

M[RBASE←SC,SCFN[20,200,RBASE←]];
*220-237 are change-RBase-for-write, used implicitly
M[TIOA,IFME[#1,DEVICE,FF256[ADD[AND[IP[#1],7],240]] ?,
  ER[TIOA.arg.not.DEVICE]]];
M[MEMBASEX←SC,SCFN[4,250,MEMBASEX←]];
M[MEMBX←SC,SCFN[4,254,MEMBX←]];

*260-261 undefined
N[ALUFMRW←]; M[ALUFMRW←B,FF256[262] PD];
  M[ALUFMRW←MD,ALUFMRW←BGMD]; M[ALUFMRW←T,ALUFMRW←BGT];
  M[ALUFMRW←RB,ALUFMRW←BGRB]; M[ALUFMRW←Q,ALUFMRW←BGQ];
M[ALUFMEM,FF256[263] PD];
M[CNT,FF256[264] PD];
M[POINTERS,FF256[265] PD];
M[TIOA&STKP,FF256[266] PD];
M[SHC,FF256[267] PD];

M[PD RSH 1,FF256[270] PD];	*PD[0]←0
  M[T RSH 1,FF256[270] PD←T];
  M[RB RSH 1,FF256[270] PD←RB];
  M[A RSH 1,FF256[270] PD←A];
  M[ID RSH 1,FF256[270] PD←AGID];
  M[B RSH 1,FF256[270] PD←B];
  M[MD RSH 1,FF256[270] PD←BGMD];
  *Q RSH 1 through the ALU has to be written (B←Q) LSH 1

M[PD RCY 1,FF256[271] PD];	*PD[0]←ALU[17]
  M[T RCY 1,FF256[271] PD←T];
  M[RB RCY 1,FF256[271] PD←RB];
  M[A RCY 1,FF256[271] PD←A];
  M[ID RCY 1,FF256[271] PD←AGID];
  M[B RCY 1,FF256[271] PD←B];
  M[MD RCY 1,FF256[271] PD←BGMD];
  M[Q RCY 1,FF256[271] PD←BGQ];

M[PD BRSH 1,FF256[272] PD];	*PD[0]←ALUcarry
  M[T BRSH 1,FF256[272] PD←T];
  M[RB BRSH 1,FF256[272] PD←RB];
  M[A BRSH 1,FF256[272] PD←A];
  M[ID BRSH 1,FF256[272] PD←AGID];
  M[B BRSH 1,FF256[272] PD←B];
  M[MD BRSH 1,FF256[272] PD←BGMD];
  M[Q BRSH 1,FF256[272] PD←BGQ];

M[PD ARSH 1,FF256[273] PD];	*PD[0] unchanged
  M[T ARSH 1,FF256[273] PD←T];
  M[RB ARSH 1,FF256[273] PD←RB];
  M[A ARSH 1,FF256[273] PD←A];
  M[ID ARSH 1,FF256[273] PD←AGID];
  M[B ARSH 1,FF256[273] PD←B];
  M[MD ARSH 1,FF256[273] PD←BGMD];
  M[Q ARSH 1,FF256[273] PD←BGQ];

M[PD LSH 1,FF256[274] PD];	*PD[17]←0
  M[T LSH 1,FF256[274] PD←T];
  M[RB LSH 1,FF256[274] PD←RB];
  M[A LSH 1,FF256[274] PD←A];
  M[ID LSH 1,FF256[274] PD←AGID];
  M[B LSH 1,FF256[274] PD←B];
  M[MD LSH 1,FF256[274] PD←BGMD];
  *Q LSH 1 through the ALU has to be written as (B←Q) LSH 1

M[PD LCY 1,FF256[275] PD];	*PD[17]←ALU[0]
  M[T LCY 1,FF256[275] PD←T];
  M[RB LCY 1,FF256[275] PD←RB];
  M[A LCY 1,FF256[275] PD←A];
  M[ID LCY 1,FF256[275] PD←AGID];
  M[B LCY 1,FF256[275] PD←B];
  M[MD LCY 1,FF256[275] PD←BGMD];
  M[Q LCY 1,FF256[275] PD←BGQ];

M[DIVIDE,FF256[276] ?];		*Q[15]←ALUcarry
M[CDIVIDE,FF256[277] ?];	*Q[15]←ALUcarry'

M[MEMBASE←SC,SCFN[40,300,MEMBASE←]];
M[CNT←SC,IFE[SCONS,20,FF256[340] ?,IFE[SCONS,0,ER[Illegal.CNT←],
  SCFN[20,340,CNT←]]]];
M[WAKEUP,IFME[#1,TASKN,FF256[ADD[360,IP[#1]]] ?,ER[Bad.arg.for.WAKEUP]]];

%Placement stuff:

"TOPLEVEL" sets the default branch clause to BRANCH[.+1].
"SUBROUTINE" sets the default to GOTO[.+1].
%
M[TOPLEVEL,SET[TSD,2] DEFAULT[IM,(NOFF,ASEL[4]
  W1[7777] W2[7777] BRGO[2])]];
M[SUBROUTINE,SET[TSD,1] DEFAULT[IM,(NOFF,ASEL[4]
  W1[7777] W2[7777] BRGO[1])]];

%For dispatch tables, DISP[4:17] hold a bit pattern whose 1's constrain
the 0th item in the table to an absolute location with 1's in those
positions.  DISP[24:37] contain a mask of flexible bits in the 0th item
placement.  These must correspond to 0's in DISP[4:17] (Micro checks this).
MicroD will choose an arbitrary value for the flexible bits.  The bits
which may vary in the body of the dispatch table are
	NOR[DISP[4:17],DISP[24:37]].
Each instruction in the dispatch table must specify the value for these
bits using the DAT macro defined below.  MicroD checks that the bits
forced to 1 using DAT were allowed to vary in the body.

Note that each GLOBAL is constrained by a dispatch table with DISP[4:17]
containing 0, and DISP[24:37] containing 7700.  An absolute placement is
constrained by a dispatch table with DISP[4:17] containing the location
and DISP[24:37] containing 0.

**NOT READY YET**

FLX[WRD0,0,17]; FLX[WRD1,20,37];
M[DTABLE,IFE[AND[#3,#2],0,
  DLC[#1: WRD0[#2] WRD1[#3]],ER[Bad.DTABLE.call]]?];
DTABLE[ABS,0,7777];		*Default dispatch table 0 is unconstrained

M[DAT,DTAB[#1] BEONES[#2] ?];
M[GLOBAL,DTAB[DLC] BEONES[0] DLC[WRD0[0] WRD1[7700]] ?];
M[AT,DTAB[DLC] BEONES[0] DLC[WRD0[ADD[#1,#2]] WRD1[0]] ?];

**INTERIM KLUDGE**
%

M[GLOBAL,GLB[1]];
M[AT,@GPW0[ADD[IFE[AND[ADD[#1,#2],176077],0,60000,40000],#1,#2]]];

*Macro executed after assembling instruction.
*Propagate RBASE change to the next instruction.
M[IMX,SET[CRB,NRB]];	SETPOST[IM,IMX];

%Branch macros

FBC will be used for the branch condition, if it is available after the
instruction is assembled, else JCN.  JCN is set at call to BRC either
when two BC's are given or when IFUJUMP, RETURN, or CORETURN are used.
%
M[BRC,IFA[JCN,FF64[#1],PF[FBC,#1]UFF[1]JCN[#2]] ISCOND[1]];

%"@" and "~" precede branch condition names for type checking.

Regular BC's		Complementary BC's
%
M[~,];			M[@,];
M[~ALU=0,BRC[60,0]];	M[@ALU#0,BRC[60,0]];
M[~ALU<0,BRC[61,1]];	M[@ALU>=0,BRC[61,1]];
M[~CARRY',BRC[62,2]];	M[@CARRY,BRC[62,2]];
M[~CNT=0&-1,BRC[63,3]];	M[@CNT#0&-1,BRC[63,3]];
M[~R<0,BRC[64,4]];	M[@R>=0,BRC[64,4]];
M[~R ODD,BRC[65,5]];	M[@R EVEN,BRC[65,5]];

M[~IOATTEN',ILLEM[IOATTEN]BRC[66,6]];
  M[@IOATTEN,ILLEM[IOATTEN]BRC[66,6]];
M[~RESCHEDULE,ILLIO[RESCHEDULE]BRC[66,6]];
  M[@RESCHEDULE',ILLIO[RESCHEDULE]BRC[66,6]];

*OVERFLOW only implemented as a function.
M[~OVERFLOW,FF64[67] ISCOND[1]];  M[@OVERFLOW',FF64[67] ISCOND[1]];

*Combination branch conditions
M[~ALU<=0,FF64[60] JCN[1] ISCOND[1]];
M[@ALU>0,FF64[60] JCN[1] ISCOND[1]];

M[.-3,ADD[IP[ILC],-3]];	M[.+3,ADD[IP[ILC],3]];
M[.-2,ADD[IP[ILC],-2]];	M[.+2,ADD[IP[ILC],2]];
M[.-1,ADD[IP[ILC],-1]];	M[.+1,ADD[IP[ILC],1]];
M[.,ILC];

M[SUBRC,IFE[TSD,1,ER[#1.illegal.in.subroutine]]];
M[TOPLVC,IFE[TSD,2,ER[#1.illegal.at.top.level]]];

M[DBAT,IFDEF[@#3,W1[#1] W2[#2](@#3,@#4),W2[#1] W1[#2](~#3,~#4)]];

M[DBLBRANCH,BRGO[TSD] DBAT[#1,#2,#3,#4]];
M[DBLGOTO,BRGO[1] DBAT[#1,#2,#3,#4]];
M[DBLCALL,BRGO[0] RETCL[1] SUBRC[DBLCALL] DBAT[#1,#2,#3,#4]];
*Constrain DBLSCALL to be at odd location
*M[DBLSCALL,DTAB[DLC] BEONES[0] DLC[WRD0[1] WRD1[7776]]
*  DBLCALL[#1,#2,#3,#4]];

M[BAT,IFDEF[@#2,W1[#1](@#2,@#3),W2[#1](~#2,~#3)]];

M[BRANCH,BRGO[TSD] BAT[#1,#2,#3]];
M[GOTO,BRGO[1] BAT[#1,#2,#3]];
*Complementary BC's illegal on CALL, IFUJUMP, and RETURN.
M[RETURN,(~#1, ~#2, BRGO[0] RETCL[2] JCN[107] TOPLVC[RETURN])];
M[CORETURN,(~#1, ~#2, BRGO[0] RETCL[3] JCN[107] TOPLVC[CORETURN])];
*The 2nd BC for IFUJUMP is illegal but detects errors.
M[IFUJUMP,ILLIO[IFUJUMP] IFG[4,#1,BRGO[0] JCN[ADD[47,LSHIFT[#1,3]]]
  IFSE[#2#3,,RETCL[2],RETCL[3](~#2,~#3)],
  ER[Ill.arg.for.IFUJUMP]] ];
M[CALL,BRGO[0] RETCL[1] SUBRC[CALL] IFSE[#2#3,,W1[#1],W2[#1](~#2,~#3)]];
*SCALL and SCORETURN must be placed at odd locations
*M[SCALL,DTAB[DLC] BEONES[0] DLC[WRD0[1] WRD1[7776]] CALL[#1,#2,#3]];
*M[SCORETURN,DTAB[DLC] BEONES[0] DLC[WRD0[1] WRD1[7776]] CORETURN[#1,#2]];

%IM used as data stuff:

IM words can be assembled as data using the BYT0, BYT1, BYT2, and BYT3
macros defined below.  Each of these sums up to 8 args which are either
parameters or integers, to form the value stored.  BYT0 and BYT2 each
assemble 9 bits into positions that correspond to READIM[0] and READIM[2].
The 9th bits for ReadIM[1] and ReadIM[3] are parity bits which must be
loaded with 0, so these operations only accept an 8-bit arg.

The way to assemble data is:
	DATA[(BYT0[...] BYT1[...] BYT2[...] BYT3[...] AT[...])];
%

FLX[XB0,0,10];	*RSTK[0:3], ALUF[0:3], BSEL[0]
FLX[XB1,11,20];	*BSEL[1:2], LC[0:2], ASEL[0:2]
FLX[XB2,21,31];	*BLOCK[0], FF[0:7]
FLX[XB3,32,41];	*JCN[0:7]

M[BYT0,IFG[#0,10,TMARGS[B0]] XB0[DPS[#1,#2,#3,#4,#5,#6,#7,#8]]];
M[BYT1,IFG[#0,10,TMARGS[B1]] XB1[DPS[#1,#2,#3,#4,#5,#6,#7,#8]]];
M[BYT2,IFG[#0,10,TMARGS[B2]] XB2[DPS[#1,#2,#3,#4,#5,#6,#7,#8]]];
M[BYT3,IFG[#0,10,TMARGS[B3]] XB3[DPS[#1,#2,#3,#4,#5,#6,#7,#8]]];

M[DATA,ILC[BRGO[0] RETCL[2] #1]];	*Indicate RETURN so no MicroD fixup


%IM read/write to/from Link.
"W2" and "ISCOND" are set so next instruction will be at . xor 1.
"RETURNS" is set so JCN won't be tampered with by MicroD.
%
M[IMWR,JCN[177] BRGO[0] RETCL[3] RSTK13[#1] SUBRC[IM←] B←];

M[IMLHR0POK←,IMWR[3]];	M[IMLHR0PBAD←,IMWR[7]];
M[IMLHR0'POK←,IMWR[1]];	M[IMLHR0'PBAD←,IMWR[5]];
M[IMRHBPOK←,IMWR[2]];	M[IMRHBPBAD←,IMWR[6]];
M[IMRHB'POK←,IMWR[0]];	M[IMRHB'PBAD←,IMWR[4]];

M[READIM,JCN[167] BRGO[0] RETCL[3] RSTK23[#1] SUBRC[READIM] ?];


%TPC read/write from Link, address from BMux[14:17]
%
M[LDTPC←,JCN[157] BRGO[0] RETCL[3] SUBRC[LDTPC←] B←];
M[RDTPC←,JCN[147] BRGO[0] RETCL[3] SUBRC[RDTPC←] B←];



%"TITLE" outputs the file name and the value of ILC on the .ER file
to help correlate errors with source statements.  It also resets various
assembly flags to standard states.
%
M[TITLE,(ER[#1...ILC=,0,IP[ILC]] SET[XTASK,0] TARGET[ILC] SUBROUTINE)];
M[END,(ER[Last.location...ILC=,0,IP[ILC]],
  ILC[(MIDASBREAK: BREAKPOINT, RETURN, AT[7776])],
  SUBROUTINE)];

%IFUM assembly:

INSSET[i,n] declares i (0 to 3) to be the current instruction set
with n (1 to 4) instructions in each IFU entry vector.
Then the following macros are used to define opcodes:

	IFUREG[OPCODE,LEN,MEMB,IFAD,N,SIGN,PA];
	IFUJMP[OPCODE,LEN,MEMB,IFAD,DISP/SIGN];
	IFUPAUSE[OPCODE,LEN,MEMB,IFAD,N,SIGN,PA];

MEMB may be a BR address symbol at location 0 to 3, interpreted as
initializing MEMBASE to 0.MEMBX[0:1].MEMB at the start of an opcode.
For IFUJMP, if LEN is 1, then the 5th arg is the displacement of the
jump (177740 to 37); if LEN is 2, then it is the sign-extend bit.
%

SET[INSSETN,0];
M[INSSET,IFG[PX[#1],3,ER[Instruction.set.index.>.3],
    SET[INSSETN,LSHIFT[PX[#1],10]]]
  IFG[5,PX[#2],IFG[#2,0,
        DEFAULT[IFUM,IFD[7777] NENT[SUB[PX[#2],1]]],
    ER[Bad.INSSET.call]],ER[Bad.INSSET.call]]];

M[IFUCK,IFE[#1,#2,IFG[#3,377,ER[Bad.opcode],IFUM[IFULC,ADD[INSSETN,#3]]],
  ER[Wrong.no.args]] SET[!T1,PX[#4]] SET[!T2,AND[3,NOT[!T1]]]
  IFE[!T1,0,ER[Bad.length]]];
M[MBIA,IFME[#1,BR,MEMB[#1],ER[Bad.MemBase]]];

M[IFUREG,IFUCK[#0,7,#1,#2] IFULC[LEN[!T1] LEN'[!T2]
  MBIA[#3] IFD[#4] OP[PX[#5]] SGN[PX[#6]] PA[#7]]];
M[IFUJMP,IFUCK[#0,5,#1,#2] IFE[!T1,3,ER[Bad.length]]
  IFULC[TJUMP[1] LEN[!T1] LEN'[!T2]
    MBIA[#3] IFD[#4] SET[!T2,PX[#5]]
    IFE[!T1,1,SGN[AND[1,RSHIFT[!T2,5]]] PA[AND[1,RSHIFT[!T2,4]]]
      OP[AND[!T2,17]], OP[17] SGN[!T2]]
  ]
];
M[IFUPAUSE,IFUCK[#0,7,#1,#2] IFULC[TPAUSE[1] LEN[!T1] LEN'[!T2]
  MBIA[#3] IFD[#4] OP[PX[#5]] SGN[PX[#6]] PA[#7]]];

%ALU stuff

ALU operations are defined as follows:

	No arg operations (A0 and A1):	ZALUOP
	A-only (A+1, A-1, 2A, 2A+1):	AOP
	Alternative A or B routing:	ABOPA and ABOPB
	Non-arithmetic of two args:	ALUOP
		Synonyms:		XALUOP
	Arithmetic of two args:		SALUOP

Two arg definitions consist of 38 macros which are the product of
	<RB, T, ID, MD, Q, SC, A> OP <RB, T, MD, Q, XB, B>.
Some A and B sources convert immediately into neutrals "A", "B", or "XB".
However, RB, T, MD, Q, and SC cannot be converted because the routing
is ambiguous, and ID cannot be converted because the instruction
encoding is ambiguous.  This is why so many macros have to be defined.
%

*For emulator-only ALU operations.
M[EPD,ILLIO[aluop]PD];

FLX[AFLD,0,7];

%Sub-macros used below
 #1 = before A between,
 #2 = after B,
 #3 = ALUF value,
 #4 = text to get A source selected
 #5 = "E" if emulator-only, else blank
%
*Arithmetic (slow) ALU ops use this one
M[SDEFOP,M[#1RB#2,(ALUF[#3]#5PD,#4,BGRB)]
	M[#1T#2,(ALUF[#3]#5PD,#4,BGT)]
	M[#1B#2,(ALUF[#3]#5PD,#4)]
	M[#1MD#2,(ALUF[#3]#5PD,#4,BGMD)]
	M[#1Q#2,(ALUF[#3]#5PD,#4,BGQ)]
];
*Logical (fast) ALU ops use this one
M[DEFOP,M[#1XB#2,(ALUF[#3]#5PD,#4)]
	SDEFOP[#1,#2,#3,#4,#5]
];

*XALUOP is the same as ALUOP--used for synonyms
M[XALUOP,DEFOP[#1RB#2,#3,#4,AGRB,#5]
	DEFOP[#1T#2,#3,#4,AGT,#5]
	DEFOP[#1ID#2,#3,#4,AGID]
	SDEFOP[#1MD#2,#3,#4,AGMD,#5]
	SDEFOP[#1Q#2,#3,#4,AGQ,#5]
	SDEFOP[#1SC#2,#3,#4,AGSC,#5]
	DEFOP[#1A#2,#3,#4,#5]
]

%#1 = before A
 #2 = between
 #3 = after B
 #4 = ALUF value
 #5 = "E" if emulator only, else omitted
 #6 = value for ALUFM RAM
%
*This one for logical (fast) ALU ops
M[ALUOP,ALUFM[ALC,#4] ALC[AFLD[#6]]
	M[#6H,ALUF[#4]ALUFMEM]
	XALUOP[#1,#2,#3,#4,#5]
];
*This one for arithmetic (slow) ALU ops
M[SALUOP,ALUFM[ALC,#4] ALC[AFLD[#6]]
	M[#6H,ALUF[#4] ALUFMEM]
	SDEFOP[#1RB#2,#3,#4,AGRB,#5]
	SDEFOP[#1T#2,#3,#4,AGT,#5]
	SDEFOP[#1ID#2,#3,#4,AGID]
	SDEFOP[#1MD#2,#3,#4,AGMD,#5]
	SDEFOP[#1Q#2,#3,#4,AGQ,#5]
	SDEFOP[#1SC#2,#3,#4,AGSC,#5]
	SDEFOP[#1A#2,#3,#4,,#5]
];

%#1 = name of no-arg op
 #2 = ALUF value
 #3 = value for ALUFM RAM
 #4 = "E" if emulator-only else omitted
%
M[ZALUOP,M[#1,ALUF[#2]#4PD] M[#3H,ALUF[#2]ALUFMEM]
	ALUFM[ALC,#2] ALC[AFLD[#3]]];

%Operations of one arg which can use either A or B are defined
by both ABOPA and ABOPB.  They prefer B for RB, T, MD, and Q.
  #1 = before "A"
  #2 = after "A"
  #3 = ALUF value
  #4 = value for ALUFM #3
***BUG: The "A" operation is arithmetic but used with XORCARRY, cannot
guarantee that the source is not routed over B instead.
%
M[ABOPA,M[#1T#2,#1(IFA[BSEL,A,B]GT)#2]
	M[#1ID#2,#1(AGID)#2]
	M[#1SC#2,#1(AGSC)#2]
	M[#1A#2,ALUF[#3]PD]
	ALUFM[ALC,#3] ALC[AFLD[#4]]
	M[#4H,ALUF[#3]ALUFMEM]
];

M[ABOPB,M[#1RB#2,#1(IFA[BSEL,A,B]GRB)#2]
	M[#1MD#2,#1(IFA[BSEL,A,B]GMD)#2]
	M[#1Q#2,#1(IFA[BSEL,A,B]GQ)#2]
	M[#1B#2,ALUF[#3] PD]
	M[#1XB#2,ALUF[#3] PD]
	ALUFM[ALC,#3] ALC[AFLD[#4]]
	M[#4H,ALUF[#3]ALUFMEM]
];

%A-only operations
  #1 = before
  #2 = after
  #3 = ALUF value
  #4 = value for ALUFM #3
  #5 = "E" if emulator-only, else omitted
%
M[AOP,	M[#1T#2,#1(AGT)#2]
	M[#1RB#2,#1(AGRB)#2]
	M[#1ID#2,#1(AGID)#2]
	M[#1MD#2,#1(AGMD)#2]
	M[#1Q#2,#1(AGQ)#2]
	M[#1SC#2,#1(AGSC)#2]
	M[#1A#2,ALUF[#3]#5PD]
	ALUFM[ALC,#3] ALC[AFLD[#4]]
	M[#4H,ALUF[#3]ALUFMEM]
];