* D0Lang.mc
	*Last edited:  July 4, 1979 by CPT - eliminated LANGVERSION
	*Last edited:  June 27, 1979  10:52 AM by Johnsson
	* edited:  April 23, 1979  3:05 PM by Jarvis
	* edited:  December 16, 1978  2:16 PM by CPT
BUILTIN[M@,2];	*Declare macro
BUILTIN[N@,3];	*Declare neutral
BUILTIN[MEMORY@,4];	*Declare Memory[name,wordsize,length,srcmacro,
		*sinkmacro,tagmacro,postmacro]
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 equal (IFSE@[s1,s2,true,false])
BUILTIN[IFA@,15];	*If field assigned (IFA@[field,true,false])
BUILTIN[IFE@,16];	*If integers equal
BUILTIN[IFG@,17];	*If integer 1 > integer 2
BUILTIN[IDF@,20];	*If symbol in symbol table and not unbound address
*BUILTIN[IFME@,21];	*If memory part of address equals string
BUILTIN[ER@,22];	*Error message (ER@[string,abortflag,integer])
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 10 integers
BUILTIN[XOR@,30];	*Exclusive or up to 10 integers
BUILTIN[AND@,31];	*And up to 10 integers
BUILTIN[COMCHAR@,32];	*Set comment char for conditional assemblies
*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,1stbit,nbits,distance,value]
*BUILTIN[FINDBIT@,36];	*FINDBIT[TABLE@,1STBIT,NBITS,DISTANCE,HOPDISTANCE,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[SETMBEXT@,47];	*Set .mb file extension

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

SETMBEXT@[DIB];

M@[SUB,ADD[#1,NOT@[#2],1]];

%Memory declarations must have names and sizes agreeing with those in
Midas, except that IM must agree with the form expected by MicroD.
%
MEMORY@[IM,124,10000,W@,W@];
MEMORY@[RM,20,400,RSRC@,RSINK@];
MEMORY@[IMLOCK,1,10000,W@,W@];
MEMORY@[VERSION,20,1,W@,W@];

M@[W@,];			*Dummy macro required for memory definitions
IM[ILC@,0];		*Location counter for IM

%Memory lock Control macro
IMRESERVE[page #,first address,number of addresses]
 Will not allocate in the reserved locations
%
FLX@[LOCK@,0,0];

M@[IMRESERVE,IMLOCK[Z@,ADD[LSHIFT[#1,10],#2]]
   REPEAT@[#3,Z@[(LOCK@[1])]]
  ]

VERSION[VLC@,0];
FLX@[VERS@,0,17];

%Second arg of LIST controls listing of memories 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
%
LIST@[IM,7]; LIST@[RM,5]; LIST@[,17];

%Three macros define parameters from which 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
addresses.
   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 paramter.  However, it is illegal
to define constants, addresses, etc. with identical names.

"Literal" constants such as "322C", "177622C", or "32400C" may be
inserted in microinstructions without previous definition.

Alternatively, constants may be constructed from parameters, integers, and
addresses 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.

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

*Fields for initializing 16-bit wide memories
FLX@[E0@,0,3]; FLX@[E1@,4,17];

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

M@[MP@,SET[#1!,#2]];
M@[SP@,IFG@[#0,11,ER@[Too.many.args.for.#1],
  SET[#1!,DPS@[#2,#3,#4,#5,#6,#7,#8,#9]]]];
M@[NSP@,IFG@[#0,11,ER@[Too.many.args.for.#1],
  SET[#1!,NOT@[DPS@[#2,#3,#4,#5,#6,#7,#8,#9]]]]];
M@[DPS@,ADD[PX@[#1],PX@[#2],PX@[#3],PX@[#4],PX@[#5],PX@[#6],PX@[#7],PX@[#8]]];
M@[!,0];
M@[PX@,IDF@[#1!,#1!,#1]];


M@[C,IFA@[F1@,ER@[F1.used.twice],
      IFA@[F2@,ER@[F2.used.twice],
       IFE@[AND@[#3#2,177760],0,
                 SET[!T1@,ADD[LSHIFT[#2,4],RSHIFT[#1,10]]]
                 SET[!T2@,AND@[#1,377]]
         IFE@[!T2@,0,BS@[1] FF@[!T1@],
           BS@[0] FF@[!T2@]
             ] B,ER@[Constant.too.big]
           ]
          ]
         ]
  ];

M@[MC,IFG@[#0,11,ER@[Too.many.args.for.#1],
  SP@[#1,DPS@[#2,#3,#4,#5,#6,#7,#8,#9]]
  M@[#1,ADD[#1!]C]]];

M@[NMC,IFG@[#0,11,ER@[Too.many.args.for.#1],
  SP@[#1,NOT@[DPS@[#2,#3,#4,#5,#6,#7,#8,#9]]]
  M@[#1,ADD[#1!]C]]];

%RM stuff

RM constants and variables are allocated in two steps.  First, the
group of 100 registers that must contain the ones being allocated is
declared by SETTASK, which binds the integer RMBASE to the top two
bits of the selected task times 100.

Then registers in that group of 100 are allocated as follows:
	RV[FOO,23,p1,...,p7];	*Creates FOO = RM 23, value sum of params
	RV[FOO,23];		*Creates FOO = RM 23, no value
	RV[FOO];		*Creates FOO at last location + 1
	RV[FOO,,17575];		*Creates address FOO at location after
				*last one allocated with value 17575
These macros leave the integer RLi, where i = 0 to 3 (the region)
bound to the last displacement allocated, and the integer RL is always
equal to RLi for the current region.
%

M@[SETTASK,IFG@[#1,17,ER@[Illegal.SETTASK],
  SELECT@[QTASK@,SET[RL0@,RL@],SET[RL1@,RL@],SET[RL2@,RL@],SET[RL3@,RL@]]
  SET[QTASK@,RSHIFT[#1,2]] SET[CURTSK@,#1]
  SET[RMBASE@,LSHIFT[QTASK@,6]]		*For reg. instructions
  SET[BRBASE@,LSHIFT[CURTSK@,4]]		*For mem. ref instructions
  SET[RL@,SELECT@[QTASK@,RL0@,RL1@,RL2@,RL3@]]
]];

SET[RL0@,177777]; SET[RL1@,177777];
SET[RL2@,177777]; SET[RL3@,177777];
SET[RMBASE@,0]; SET[QTASK@,0]; SET[CURTSK@,0]; SET[RL@,177777];

M@[RV,SET[RL@,IFSE@[#2,,ADD[1,RL@],#2]]
  IFG@[RL@,77,ER@[RM.ovf]]
  RM[#1,ADD[RMBASE@,RL@]] RM[RLC@,IP[#1]]
  IFG@[#0,2,RLC@[DPS@[#3,#4,#5,#6,#7,#8,#9]V]]
];

*RM addresses used as sources/destinations execute following macros.
M@[RSINK@,CKRMA@[#1] RB←];
M@[RSRC@,CKRMA@[#1] RB];

M@[CKRMA@, SET[ZOT@,IP[#1]] MRS@[AND@[ZOT@,77]]
  IFE@[RSHIFT[ZOT@,6],QTASK@,
    IFE@[AND@[ZOT@,60],0,
      IFE@[AND@[CURTSK@,3],0,,ER@[#1.unaddressable]]
    ],ER@[#1.unaddressable]]
];

*PCF[RMADDR], SB[RMADDR], and DB[RMADDR] are also A sources
M@[PCF,QRS@[#1,0,PCF]];
M@[SB,QRS@[#1,1,SB]];
M@[DB,QRS@[#1,2,DB]];

M@[QRS@,SET[ZOT@,IP[#1]]
  IFE@[AND@[ZOT@,3],0,IFE@[RSHIFT[ZOT@,6],QTASK@,MRS@[ADD[100,ZOT@,#2]]RB,
      ER@[#1.in.illegal.RM.region]],ER@[#1.not.quadaligned]]];

*other register sources
M@[ALURESULT,IFA@[MRS1X@,MRS1ER@,
  MRS@[107] LDF[RB,4,4]]];	*aluresult = ovf,car,=0,<0
M@[SALUF,IFA@[MRS1X@,MRS1ER@,
  MRS@[107] LDF[RB,10,10]]];
M@[SSTKP,IFA@[MRS1X@,MRS1ER@,
  MRS@[103] LDF[RB,0,10]]];
M@[NSTKP,IFA@[MRS1X@,MRS1ER@,
  MRS@[103] LDF[RB,10,10]]];
M@[STKP,IFA@[MRS1X@,MRS1ER@,
  MRS@[103] LDF[RB,10,10]]];
M@[MEMERROR,IFA@[MRS1X@,MRS1ER@,
  MRS@[117] RB]];
M@[MEMSYNDROME,IFA@[MRS1X@,MRS1ER@,
  MRS@[113] RB]];
M@[DBXREG,IFA@[MRS1X@,MRS1ER@,
  MRS@[127] LDF[RB,0,4]]];
M@[MWXREG,IFA@[MRS1X@,MRS1ER@,
  MRS@[127] LDF[RB,4,4]]];
M@[CYCLECONTROL,IFA@[MRS1X@,MRS1ER@,
  MRS@[127] LDF[RB,0,10]]];
M@[PCXREG,IFA@[MRS1X@,MRS1ER@,
  MRS@[127] LDF[RB,10,4]]];
M@[PCFREG,IFA@[MRS1X@,MRS1ER@,
  MRS@[127] LDF[RB,14,4]]];
M@[PRINTER,IFA@[MRS1X@,MRS1ER@,
  REGSHIFT[] MRS@[127] RB]];
M@[DBSB,IFA@[MRS1X@,MRS1ER@,
  REGSHIFT[] MRS@[133] RB]];
M@[TIMER,IFA@[MRS1X@,MRS1ER@,
  MRS@[133] RB]];
M@[RS232,IFA@[MRS1X@,MRS1ER@,
  MRS@[137] RB]];
M@[MNBR,IFA@[MRS1X@,MRS1ER@,
  REGSHIFT[] MRS@[137] RB]];
M@[APCTASK,IFA@[MRS1X@,MRS1ER@,
  MRS@[143] LDF[RB,0,4]]];
M@[APC,IFA@[MRS1X@,MRS1ER@,
  MRS@[143] LZERO[RB,4]]];
M@[APCTASK&APC,IFA@[MRS1X@,MRS1ER@,
  MRS@[143] RB]];
M@[APC&APCTASK,IFA@[MRS1X@,MRS1ER@,
  MRS@[143] RB]];
M@[CTASK,IFA@[MRS1X@,MRS1ER@,
  MRS@[147] LDF[RB,0,4]]];
M@[NCIA,IFA@[MRS1X@,MRS1ER@,
  MRS@[147] LZERO[RB,4]]];
M@[CSDATA,IFA@[MRS1X@,MRS1ER@,
  MRS@[153] RB]];
M@[PAGE,IFA@[MRS1X@,MRS1ER@,
  MRS@[157] LDF[RB,0,4]]];
M@[PARITY,IFA@[MRS1X@,MRS1ER@,
  MRS@[157] LDF[RB,4,4]]];
M@[BOOTREASON,IFA@[MRS1X@,MRS1ER@,
  MRS@[157] LDF[RB,10,10]]];
M@[MRS1ER@,ER@[MRS1.used.twice]];

*To get a multi-field word using only one specification , use 
*GETRSPEC[mrs address] .  Thus to load T with APCTASK and APC, use *the following syntax:
*		T ← GETRSPEC[143];

M@[GETRSPEC,IFA@[MRS1X@,ER@[MRS1.used.twice],
  MRS@[#1] RB]];

*StkP sources/destinations and other RB sources are defined with the
*following macros:
*MKRSRC@[name,rselvalue] defines the source -or-
*MKRDEST@[name,rselvalue] defines the destination
M@[MKRSRC@,M@[#1,(MRS@[#2] #3) RB]];
M@[MKRDEST@,M@[#1,(MRS@[#2] #3) RB←]];

*STACKSHIFT (StackShift) is F2
MKRSRC@[STACK,163,]; MKRSRC@[STACK&+1,167,];
MKRSRC@[STACK&-1,173,]; MKRSRC@[STACK&-2,177,];
MKRSRC@[STACK&+2,163,STACKSHIFT]; MKRSRC@[STACK&+3,167,STACKSHIFT];
MKRSRC@[STACK&-3,177,STACKSHIFT];
MKRDEST@[STACK←,163,]; MKRDEST@[STACK&+1←,167,];
MKRDEST@[STACK&-1←,173,]; MKRDEST@[STACK&-2←,177,];
MKRDEST@[STACK&+2←,163,STACKSHIFT]; MKRDEST@[STACK&+3←,167,STACKSHIFT];
MKRDEST@[STACK&-3←,177,STACKSHIFT];

%IM used as data stuff

IM words can be assembled as data using the "LH" (left-half) and "RH"
(right-half) macros defined below.  Each of these takes up to 8 arguments
which are either parameters, addresses, or integers.  These are summed
to form the value stored.

The way to assemble data is:
	DATA[(LH[...] RH[...] AT[...])];
%

FLX@[V0@,0,17]; FLX@[V1@,20,37];

M@[LH,IFG@[#0,10,ER@[Too.many.args.for.LH]]
  V0@[DPS@[#1,#2,#3,#4,#5,#6,#7,#8]]];

M@[RH,IFG@[#0,10,ER@[Too.many.args.for.RH]]
  V1@[DPS@[#1,#2,#3,#4,#5,#6,#7,#8]]];

M@[DATA,ILC@[RETCL@[2] #1]];	*Indicate "Return" so no MicroD fixup


*IM field definitions
M@[MRS@,MRS1@[RSHIFT[#1,2]] RSEL2@[AND@[#1,3]]];	*MEMINS@, RMOD@, and RSEL@
M@[MRS1@,MRS1X@[XOR@[#1,14]]];
FLX@[MRS1X@,0,5];
M@[RSMOD@,RSMOD1@[RSHIFT[#1,2]] RSEL2@[AND@[#1,3]]];	*RMOD@ and RSEL@
M@[RSMOD1@,RSMOD1X@[XOR@[#1,14]]];
FLX@[RSMOD1X@,1,5];
FLX@[F2@,22,25];		*FF[4:7]
FLX@[JC@,26,30];		*Jump control
M@[JA@,JA1@[RSHIFT[#1,2]] JA2@[AND@[#1,77]]];
FLX@[JA1@,122,123];
FLX@[JA2@,31,36];
FLX@[JA7@,36,36];
FLX@[RSEL2@,120,121];

*Fields in regular instructions
FLX@[AF0@,6,6];	*Sign bit for constants
FLX@[ALF@,6,11];		*Entire ALUF field
FLX@[BS@,12,13];		*Source for BMux
FLX@[LR@,20,20];		*Load RM
FLX@[LT@,21,21];		*Load T
FLX@[IMPARITY@,37,37];	*Parity bit
M@[FF@,F1@[RSHIFT[#1,4]] F2@[AND@[#1,17]]];	*Function field
FLX@[F1@,14,17];		*FF[0:3]

*Fields in memory reference instructions
FLX@[TYPE@,6,11];	*Type of memory reference
*Source/destination
FLX@[SRCDES@,12,21];
*Extra stuff for MicroD
FLX@[BRKP@,40,40];	*Instruction has a breakpoint
FLX@[W0@,44,57];
*FLX@[@GW0@,41,57];	*@W0, GLB, and PW0
FLX@[@W0@,41,41];	*Place at absolute loc. W0
*FLX@[GLB@,42,42];	*Place at global call loc.
FLX@[PW0@,43,43];	*Bit 43=1 tells MicroD that 44:47 contain the page
		*on which the instruction should be placed
FLX@[PGE@,44,47];	*contains page for mi placement

FLX@[RETCL@,60,61];	*2 = does a Return 
		*1 = does a Call 
FLX@[ODDCALL@,62,62];*Does a call from an odd location
FLX@[SWPAGE@,63,63];	*This instruction loads the PAGE register
FLX@[W1@,64,77];	*Imaginary address of unconditional or false
		*branch address
FLX@[CHPAGE@,101,101];*Indicates F-field is LOADPAGE, new page in F2
*FLX@[EMUL@,102,102];*Presently unused
FLX@[CND@,103,103];	*Has a branch condition
FLX@[W2@,104,117];	*Imaginary address of conditional branch when true


M@[FZ@,IFA@[F1@,ER@[F1.used.twice],IFA@[F2@,ER@[F2.used.twice],FF@[#1] ]]];
M@[FF1@,IFA@[F1@,ER@[F1.used.twice],F1@[#1] ]];
M@[FF2@,IFA@[F2@,ER@[F2.used.twice],F2@[#1] ]];

M@[BREAKPOINT,BRKP@[1]?];

*Neutrals and connection macros
N@[RB←]; N@[RB]; N@[A]; N@[B←]; N@[B]; N@[?]; N@[T←]; N@[T]; N@[LU]; N@[LU←];

M@[A←A,A←]; M@[B←B,B]; M@[LU←LU,LU];

M@[A←,PF@[ALF@,1]SET[REGIFLAG@,1]];

M@[A←RB,A←];
M@[RB←LU,LR@[1] LU];
M@[RB←A,RB←(LU←A)];
M@[RB←B,RB←(LU←B)];
M@[RB←T,RB←(LU←T)];
M@[RB←RB,RB←(LU←RB)];

M@[B←T,B];
M@[T←LU,LT@[1] LU];
M@[T←A,T←(LU←A)];
M@[T←B,T←(LU←B)];
M@[T←T,T←(LU←T)];
M@[T←RB,T←(LU←RB)];

%Cycler-masker stuff:

The arguments to the LDF and DISPATCH macros are POS and SIZE, where
POS is the left bit of the field and SIZE the number of bits in the
field.  This is identical to Mesa read-field and write-field
descriptors.


LDF[RBsource,POS,SIZE] is used to right-justify any field.

   0	- 17	20  1-bit fields starting at bit 0, 1, ..., 17
  20	- 36	17  2-bit fields starting at bit 0, 1, ..., 16
  37	- 54	16  3-bit fields starting at bit 0, 1, ..., 15
  55	- 71	15  4-bit fields starting at bit 0, 1, ..., 14
  72	-105	14  5-bit fields starting at bit 0, 1, ..., 13
 106	-120	13  6-bit fields starting at bit 0, 1, ..., 12
 121	-132	12  7-bit fields starting at bit 0, 1, ..., 11
 133	-143	11 10-bit fields starting at bit 0, 1, ..., 10
 144	-153	10 11-bit fields starting at bit 0, 1, ...,  7
 154	-162	 7 12-bit fields starting at bit 0, 1, ...,  6
 163	-170	 6 13-bit fields starting at bit 0, 1, ...,  5
 171	-175	 5 14-bit fields starting at bit 0, 1, ...,  4
 176	-201	 4 15-bit fields starting at bit 0, 1, 2, 3
 202	-204	 3 16-bit fields starting at bit 0, 1, 2
 205	-206	 2 17-bit fields starting at bit 0, 1

DISPATCH[RBsource,POS,SIZE] is used to load APC with the selected
field with SIZE =< 4 bits.

 207	-226	20  1-bit fields starting at bit 0, 1, ..., 17
 227	-245	17  2-bit fields starting at bit 0, 1, ..., 16
 246	-263	16  3-bit fields starting at bit 0, 1, ..., 15
 264	-300	15  4-bit fields starting at bit 0, 1, ..., 14

RSH[RBsource,shiftcount] right-shifts RBsource by shiftcount 1 to 17.

 uses LDF[RBsource,0,(20 - shiftcount)]  codes

LSH[RBsource,shiftcount] left-shifts RBsource by shiftcount 1 to 17.

 301	-317	17 left shifts of 1, ..., 17 bits

LCY[RBsource,shiftcount] left-cycles RBsource by shiftcount 1 to 17.

 320	-336	17 left cycles of 1, ..., 17 bits

RCY[RBsource,shiftcount] right-cycles RBsource by shiftcount 1 to 17.

 uses LCY[RBsource,(20 - shiftcount)]  codes

RHMASK[RBsource] is RBsource & 377

 uses LDF[RBsource,10,10]  code

LHMASK[RBsource] is RBsource & 177400

 337	-337	RBsource & 177400

ZERO is zero

 340	-340   zero
%

M@[LDF,BS@[3]
IFG@[ADD[#2,#3],20,ER@[Illegal.POS+SIZE],IFG@[1,#3,ER@[Illegal.SIZE],
  FZ@[ADD[#2,IFG@[#3,7,
   SELECT@[SUB[#3,10],133,144,154,163,171,176,202,205],
   SELECT@[#3,100000,0,20,37,55,72,106,121]]]]
  #1]]];

M@[DISPATCH,BS@[3]ALF@[1]SET[RETNOGOOD@,1]
IFG@[#3,4,ER@[Illegal.SIZE],IFG@[ADD[#2,#3],20,ER@[Illegal.POS+SIZE],
  FZ@[ADD[#2,SELECT@[#3,100000,207,227,246,264]]]
  #1]]];

M@[RSH,BS@[3]
IFG@[#2,17,ER@[RSH.count.too.big],IFG@[1,#2,ER@[RSH.count.too.small],
  FZ@[IFG@[#2,7,SELECT@[SUB[#2,10],133,121,106,72,55,37,20,0],
              SELECT@[#2,100000,205,202,176,171,163,154,144]]]
  #1]]];

M@[LSH,BS@[3]
IFG@[#2,17,ER@[LSH.count.too.big],IFG@[1,#2,ER@[LSH.count.too.small],
  FZ@[ADD[#2,300]]
  #1]]];

M@[RCY,BS@[3]
IFG@[#2,17,ER@[RCY.count.too.big],IFG@[1,#2,ER@[RCY.count.too.small],
  FZ@[SUB[337,#2]]
  #1]]];

M@[LCY,BS@[3]
IFG@[#2,17,ER@[LCY.count.too.big],IFG@[1,#2,ER@[LCY.count.too.small],
  FZ@[ADD[#2,317]]
  #1]]];

M@[RHMASK,BS@[3] FZ@[143] #1 ];

M@[LHMASK,BS@[3] FZ@[337] #1 ];

M@[ZERO,BS@[3] FZ@[340] RB];

%Functions:

Functions are divided into the following classes:

1.  Group A and Group B--only in regular instructions, use F1 and F2.
2.  F1 only--only in regular instructions.
3.  F2 only--either memory reference or regular instructions.
%

*Group A functions are currently unused

*Group B functions
M@[SPAREFUNCTION,FZ@[160] ?];
M@[RESETERRORS,FZ@[161] ?];
M@[INCMPANEL,FZ@[162] ?];
M@[CLEARMPANEL,FZ@[163] ?];
M@[GENSRCLOCK,FZ@[164] ?];
M@[RESETWDT,FZ@[165] ?];
M@[BOOT,FZ@[166] ?];
M@[SETFAULT,FZ@[167] ?];
M@[APCTASK&APC←,FZ@[170]SET[RETNOGOOD@,1] A←];
M@[APC&APCTASK←,FZ@[170]SET[RETNOGOOD@,1] A←];
M@[RESTORE,FZ@[171] A←];
M@[RESETFAULT,FZ@[172] ?];
M@[USECTASK,FZ@[173] ];
M@[WRITECS0&2,FZ@[174] CSX@];
M@[WRITECS1,FZ@[175] CSX@];
M@[READCS,FZ@[176] CSX@];
  M@[CSX@,JC@[6] SET[CSFLG@,1] ER@[CSOp...]];
M@[D0OFF,FZ@[177] ?];

*F1 only
*00 take an RM address as argument
M@[BBFA,REGSHIFT[]PF@[ALF@,3]FF1@[00] #1];	*This is a dispatch
*F1 = 5  is load page
*F1 = 6  is Group A is unused
*F1 = 7  is Group B
M@[RS232←,FF1@[1] B← ];
*02-03 take an RM address as argument
M@[LOADTIMER,FF1@[2] A←#1 ];
M@[ADDTOTIMER,FF1@[3] A←#1 ];
*4 is unused
M@[LOADPAGE,FF1@[5] FF2@[#1] SWPAGE@[1]];
*F1 = 6  is Group A
*F1 = 7  is Group B
*11-14 take an RM address as argument
*F1 = 10  is no-op
M@[WFA,FF1@[11] #1];
M@[BBFB,FF1@[12] #1];
M@[WFB,FF1@[13] #1];
M@[RF,FF1@[14] #1];
M@[BBFBX,FF1@[15] #1];
M@[NEXTINST,FF1@[16] RETCL@[1] ODDCALL@[1] JC@[5] PCF[#1]];	*This is a dispatch
M@[NEXTDATA,FF1@[17] RETCL@[1] ODDCALL@[1] JC@[5] PCF[#1]];
M@[CNEXTDATA,FF1@[17] PCF[#1]]; *Like NextData, but known to be a call, and is to be placed as a call by MicroD

*F2 only
M@[REGSHIFT,FF2@[0] ];
M@[STKP←,FF2@[1] A← ];
M@[FREEZERESULT,FF2@[2]?];
*STACKSHIFT is invisible (used only by STACK, STACK&+1, STACK←, etc.)
M@[STACKSHIFT,FF2@[3]];
M@[IOSTROBE,FF2@[3]]; *same as STACKSHIFT
M@[CYCLECONTROL←,FF2@[4] A← ];
M@[SB←,FF2@[5] A← ];
M@[DB←,FF2@[6] A← ];
M@[NEWINST,ER@[NewInstIsNowByLocation]];
M@[BRANCHSHIFT,FF2@[10]SET[BRSHFLG@,1]];
M@[SALUF←,FF2@[11] B← ];
*12 is a no-op
M@[MNBR←,FF2@[13] A← ];
M@[PCF←,FF2@[14] A← ];
M@[RESETMEMERRS,FF2@[15]];
M@[USECOUTASCIN,FF2@[16]];
M@[PRINTER←,FF2@[17] A← ];



%Memory reference instructions:

Memory reference clauses are encoded in one of the following forms:
PFETCHn[basereg,raddr,F2];	*n = 1, 2, 4
PSTOREn[basereg,raddr,F2];	*n = 1, 2, 4
IOFETCHn[basereg,device,F2];	*n = 4, 20
IOSTOREn[basereg,device,F2];	*n = 4, 20
XMAP[basereg,raddr,F2];
INPUT[raddr,F2];	*deviceaddr is H2[10,13]orCTASK[0,3],,H2[14,17]
OUTPUT[raddr,F2];	*deviceaddr is H2[10,13]orCTASK[0,3],,H2[14,17]
READPIPE[raddr];
REFRESH[raddr];
The F2 argument is optional.  If given, it causes the displacement to
come from F2 rather than T.

The base register RM address is legal if:
	RAddr is even
	RAddr eq OR@[RAddr,BRBASE]
%
M@[MEM@,SET[ZOT@,IP[#1]]
 IFG@[20,ZOT@,SET[ZOZ@,OR@[ZOT@,BRBASE@]],SET[ZOZ@,ZOT@]]
  IFE@[OR@[ZOZ@,BRBASE@],ZOZ@,
    IFE@[AND@[ZOT@,1],1,ER@[#1.is.an.odd.base.register],]
    IFG@[#2,2,F2@[#3] MRS@[ADD[300,AND@[ZOT@,77]]],
      MRS@[ADD[200,AND@[ZOT@,77]]]],
    ER@[#1.not.addressable.by.task]]];

M@[MEMR@,IFSE@[#1,STACK,SRCDES@[0],SET[ZOT@,IP[#1]]
 IFG@[20,ZOT@,SET[ZOZ@,OR@[ZOT@,BRBASE@]],SET[ZOZ@,ZOT@]]
IFE@[OR@[ZOZ@,BRBASE@],ZOZ@,
IFE@[AND@[ZOT@,#2],0,IFE@[ZOT@,0,ER@[#1.equal.zero..stack.will.be.used.,]]
SRCDES@[ZOT@],ER@[#1.not.even.or.not.quadaligned]],
  ER@[#1.not.addressable.by.task]]]];

M@[IODV@,IFE@[OR@[#1,BRBASE@],#1,SRCDES@[#1],ER@[#1.is.unaddressable.device]]];

*type 0 is unused
M@[IOFETCH4,MEM@[#1,#0,#3] TYPE@[1] IODV@[#2] ?];
M@[READPIPE,MRS@[200] TYPE@[2] MEMR@[#1,0] ?];
M@[REFRESH,TYPE@[3] MRS@[ADD[300,AND@[77,IP[#1]]]]F2@[0] ?];
M@[PFETCH1,MEM@[#1,#0,#3] TYPE@[4] MEMR@[#2,0] ?];
M@[PFETCH2,MEM@[#1,#0,#3] TYPE@[5] MEMR@[#2,1] ?];
M@[PFETCH4,MEM@[#1,#0,#3] TYPE@[6] MEMR@[#2,3] ?];
M@[INPUT,IFG@[#0,1,MRS@[300] F2@[#2],MRS@[200]]
 TYPE@[7] MEMR@[#1] ?];
M@[PSTORE1,MEM@[#1,#0,#3] TYPE@[10] MEMR@[#2,0] ?];
M@[PSTORE2,MEM@[#1,#0,#3] TYPE@[11] MEMR@[#2,1] ?];
M@[PSTORE4,MEM@[#1,#0,#3] TYPE@[12] MEMR@[#2,3] ?];
M@[OUTPUT,IFG@[#0,1,MRS@[300] F2@[#2],MRS@[200]]
 TYPE@[13] MEMR@[#1] ?];
M@[IOFETCH16,MEM@[#1,#0,#3] TYPE@[14] IODV@[#2] ?];
M@[IOFETCH20,MEM@[#1,#0,#3] TYPE@[14] IODV@[#2] ?];
M@[IOSTORE4,MEM@[#1,#0,#3] TYPE@[15] IODV@[#2] ?];
M@[XMAP,MEM@[#1,#0,#3] TYPE@[16] MEMR@[#2,0] ?];
M@[IOSTORE16,MEM@[#1,#0,#3] TYPE@[17] IODV@[#2] ?];
M@[IOSTORE20,MEM@[#1,#0,#3] TYPE@[17] IODV@[#2] ?];


%Control stuff:
%
*Force absolute location and change default page
M@[AT,@W0@[1] W0@[ADD[#1,#2]] ONPAGE[RSHIFT[ADD[#1,#2],10]]];

*The default micro-instruction

DEFAULT@[IM,(BS@[2] F1@[10] F2@[12] JC@[4] W1@[7777] W2@[7777] PW0@[1])];

*Micro-instructions which are no-ops use the following macro:
M@[NOP,PF@[BS@,2]];

*The ONPAGE macro changes the default page number which is used
*for address assignment.
M@[ONPAGE,DEFAULT@[IM,PGE@[#1]]];

%Branch macros
"~@" and "~" in front of branch condition names are for type checks.
Macros insert these noise characters in front of names supplied by the
program.
%
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@];

*Regular BC'S:  These conditions result in odd addresses
M@[~ALU#0,CND@[1] JC@[0] JA7@[0] SET[ALUTESTFLG@,1]];
M@[~CARRY,CND@[1] JC@[0] JA7@[1] SET[ALUTESTFLG@,1]];
M@[~ALU<0,CND@[1] JC@[1] JA7@[0] SET[ALUTESTFLG@,1]];
M@[~NOH2BIT8,CND@[1] JC@[1] JA7@[1]];
M@[~R<0,CND@[1] JC@[2] JA7@[0]];
M@[~R ODD,CND@[1] JC@[2] JA7@[1]];
M@[~NOATTEN,CND@[1] JC@[3] JA7@[0]];
M@[~MB,CND@[1] JC@[3] JA7@[1]];

M@[~INTPENDING,CND@[1] JC@[0] JA7@[0] BRANCHSHIFT];
M@[~NOOVF,CND@[1] JC@[0] JA7@[1] SET[ALUTESTFLG@,1] BRANCHSHIFT];
M@[~BPCCHK,CND@[1] JC@[1] JA7@[0] BRANCHSHIFT];
M@[~SPAREBRANCH,CND@[1] JC@[1] JA7@[1] BRANCHSHIFT];
M@[~QUADOVF,CND@[1] JC@[2] JA7@[0] BRANCHSHIFT];
M@[~TIMEOUT,CND@[1] JC@[2] JA7@[1] BRANCHSHIFT];
M@[~,];


*Complementary BC's:  These conditions result in even addressed
M@[~@ALU=0,CND@[1] JC@[0] JA7@[0] SET[ALUTESTFLG@,1]];
M@[~@NOCARRY,CND@[1] JC@[0] JA7@[1] SET[ALUTESTFLG@,1]];
M@[~@ALU>=0,CND@[1] JC@[1] JA7@[0] SET[ALUTESTFLG@,1]];
M@[~@H2BIT8,CND@[1] JC@[1] JA7@[1]];
M@[~@R>=0,CND@[1] JC@[2] JA7@[0]];
M@[~@R EVEN,CND@[1] JC@[2] JA7@[1]];
M@[~@IOATTEN,CND@[1] JC@[3] JA7@[0]];
M@[~@NOMB,CND@[1] JC@[3] JA7@[1]];

M@[~@NOINTPENDING,CND@[1] JC@[0] JA7@[0] BRANCHSHIFT];
M@[~@OVF,CND@[1] JC@[0] JA7@[1] SET[ALUTESTFLG@,1]BRANCHSHIFT];
M@[~@BPCNOCHK,CND@[1] JC@[1] JA7@[0] BRANCHSHIFT];
M@[~@SPARENOBRANCH,CND@[1] JC@[1] JA7@[1] BRANCHSHIFT];
M@[~@INQUAD,CND@[1] JC@[2] JA7@[0] BRANCHSHIFT];
M@[~@NOTIMEOUT,CND@[1] JC@[2] JA7@[1] BRANCHSHIFT];
M@[~@,];

M@[DBAT@,IDF@[~@#3,W1@[#1] W2@[#2](~@#3,~@#4),W2@[#1] W1@[#2](~#3,~#4)]];
M@[BAT@,IDF@[~@#2,W1@[#1] (~@#2,~@#3),W2@[#1] (~#2,~#3)]];
M@[GOTOX@,W1@[#1] IFE@[CSFLG@,1,JC@[6],JC@[4]]];

%Branch and Goto
The branch and goto macros are now identical and are
interchangeable.  If the next micro-instruction to be executed
is in a different page, the macro must have a P following it.
Thus GOTOP[xyz] is used when xyz is in a different page from
the current micro-instruction.   This occurs only when the m-i
preceding the current one does a LOADPAGE.
%

M@[DBLGOTO,DBAT@[#1,#2,#3,#4]];
M@[DBLGOTOP,CHPAGE@[1] DBAT@[#1,#2,#3,#4]];
M@[DBLBRANCH,DBAT@[#1,#2,#3,#4]];
M@[DBLBRANCHP,CHPAGE@[1] DBAT@[#1,#2,#3,#4]];

M@[GOTO,IFSE@[#2#3,,GOTOX@[#1],
 BAT@[#1,#2,#3]]?];
M@[GOTOP,IFSE@[#2#3,,GOTOX@[#1] CHPAGE@[1],
 BAT@[#1,#2,#3]]?];
M@[BRANCH,IFSE@[#2#3,,GOTOX@[#1],
 BAT@[#1,#2,#3]]?];
M@[BRANCHP,IFSE@[#2#3,,GOTOX@[#1] CHPAGE@[1],
 BAT@[#1,#2,#3]]?];
M@[SKIP,GOTO[.+2,#1]];

%Calls must normally be executed from even locations, because
the return is to the caller's address or 1.  MicroD will only place calls at even word locations.  The NEXTINST, NEXTop, and NEXTDATA 
macros are required to be calls from odd locations to aid the
instruction buffer refill micro-code in re-execution following
loading of the buffer.  The macro RCALL[label] or RCALL will
cause a call to be assigned to an odd location.
%

M@[CALL,IFSE@[#2#3,,RETCL@[1] JC@[5] W1@[#1] W2@[.+1],
ER@[no.args.allowed.in.call's]]?];
M@[CALLP,IFSE@[#2#3,,RETCL@[1] CHPAGE@[1] JC@[5] W1@[#1] W2@[.+1],
ER@[no.args.allowed.in.callp's]]?];
M@[RCALL,IFSE@[#2#3,,RETCL@[1] ODDCALL@[1] JC@[5] IFSE@[#1,,W1@[.+1],W1@[#1]],
ER@[no.args.allowed.in.rcall's]]?];
M@[RCALLP,IFSE@[#2#3,,RETCL@[1] ODDCALL@[1] CHPAGE@[1] JC@[5] IFSE@[#1,,W1@[.+1],W1@[#1]],
ER@[no.args.allowed.in.rcallp's]]?];

M@[TASK,W1@[.+1] W2@[.+2] SET[TSKFLG@,1] JC@[5] RETCL@[1]];

M@[RETURN,IFSE@[#1#2,,RETCL@[2] JC@[6] JA7@[0],
ER@[no.args.allowed.in.return's]]?];

M@[NOTASKRTN,IFSE@[#1#2,,RETCL@[2] JC@[6] JA7@[0],
ER@[no.args.allowed.in.notaskrtn's]]?];

M@[NIRET,IFSE@[#1#2,,RETCL@[2] JC@[6] JA7@[1],
ER@[no.args.allowed.in.return's]]?];

M@[DISP,IFSE@[#2#3,,JC@[7] W1@[#1],
ER@[no.args.allowed.in.disp's]]?];

M@[DISPP,IFSE@[#2#3,,JC@[7] CHPAGE@[1] W1@[#1],
ER@[no.args.allowed.in.dispp's]]?];


%ALU stuff:

Alu operations must be defined for (A, RB) op (B,T)
%

M@[LU←B,ALF@[0]LU];
M@[LU←T,ALF@[0]LU];
M@[LU←RB,ALF@[1]LU];
M@[LU←A,ALF@[1]LU];
M@[RBANDB,ALF@[2]LU];
M@[AANDB,ALF@[2]LU];
M@[RBANDT,ALF@[2]LU];
M@[AANDT,ALF@[2]LU];
M@[RBORB,ALF@[3]LU];
M@[AORB,ALF@[3]LU];
M@[RBORT,ALF@[3]LU];
M@[AORT,ALF@[3]LU];
M@[RBXORB,ALF@[4]LU];
M@[AXORB,ALF@[4]LU];
M@[RBXORT,ALF@[4]LU];
M@[AXORT,ALF@[4]LU];
M@[RB#B,ALF@[4]LU];
M@[A#B,ALF@[4]LU];
M@[RB#T,ALF@[4]LU];
M@[A#T,ALF@[4]LU];
M@[RBANDNOTB,ALF@[5]LU];
M@[AANDNOTB,ALF@[5]LU];
M@[RBANDNOTT,ALF@[5]LU];
M@[AANDNOTT,ALF@[5]LU];
M@[RBORNOTB,ALF@[6]LU];
M@[AORNOTB,ALF@[6]LU];
M@[RBORNOTT,ALF@[6]LU];
M@[AORNOTT,ALF@[6]LU];
M@[RBXNORB,ALF@[7]LU];
M@[AXNORB,ALF@[7]LU];
M@[RBXNORT,ALF@[7]LU];
M@[AXNORT,ALF@[7]LU];
M@[RB=B,ALF@[7]LU];
M@[A=B,ALF@[7]LU];
M@[RB=T,ALF@[7]LU];
M@[A=T,ALF@[7]LU];
M@[RB+1,ALF@[10]LU];
M@[A+1,ALF@[10]LU];
M@[RB+B,ALF@[11]LU];
M@[A+B,ALF@[11]LU];
M@[RB+T,ALF@[11]LU];
M@[A+T,ALF@[11]LU];
M@[RB+B+1,ALF@[12]LU];
M@[A+B+1,ALF@[12]LU];
M@[RB+T+1,ALF@[12]LU];
M@[A+T+1,ALF@[12]LU];
M@[RB-1,ALF@[13]LU];
M@[A-1,ALF@[13]LU];
M@[RB-B,ALF@[14]LU];
M@[A-B,ALF@[14]LU];
M@[RB-T,ALF@[14]LU];
M@[A-T,ALF@[14]LU];
M@[RB-B-1,ALF@[15]LU];
M@[A-B-1,ALF@[15]LU];
M@[RB-T-1,ALF@[15]LU];
M@[A-T-1,ALF@[15]LU];

*ALUF[16] UNASSIGNED

M@[RBSALUFOPB,ALF@[17]LU];
M@[ASALUFOPB,ALF@[17]LU];
M@[RBSALUFOPT,ALF@[17]LU];
M@[ASALUFOPT,ALF@[17]LU];

*Macro executed after assembling instruction to default W1
SETPOST@[IM,IMX@];
M@[IMX@,SET[CSFLG@,0]
  IFE@[CHPGFLG@,1,CHPAGE@[1] SET[CHPGFLG@,0]]
  IFE@[RTNFLG@,1,XX1@[]]
  IFE@[TSKFLG@,1,XX2@[]]
  IFA@[SWPAGE@,IFA@[W1@,,SET[CHPGFLG@,1]]]
  IFE@[REGIFLAG@,1,XX3@[]]
  IFE@[RETNOGOOD@,1,XX4@[]]
  IFE@[RTNTOFLG@,1,XX5@[]]
  SET[BRSHFLG@,0]SET[ALUTESTFLG@,0] ];
M@[XX1@,JC@[6] JA7@[0] RETCL@[2] SET[RTNFLG@,0]
   SET[RTNTOFLG@,1]];
M@[XX2@,SET[RTNFLG@,1] SET[TSKFLG@,0]];
M@[XX3@,IFE@[NOILKOKFLG@,0,IFE@[FVAL@[ALF@],0,
 ER@[WARNING:..no.register.interlock]]SET[REGIFLAG@,0]SET[NOILKOKFLG@,0]]];
M@[XX4@,IFE@[FVAL@[JC@],6,
   ER@[ERROR:..apc.loaded.during.return]] SET[RETNOGOOD@,0]];
M@[XX5@,IFE@[ALUTESTFLG@,1,
   ER@[ERROR:..alu.results.tested.following.return]] SET[RTNTOFLG@,0]];
M@[NOREGILOCKOK,SET[NOILKOKFLG@,1]];

%"TITLE" outputs the file name and the value of ILC on the .ER file
to help correlate error messages with source statements.  It alse resets
various assembly flags to standard states.
%
M@[TITLE,(SETTASK[0] DIB@[] TARGET@[ILC@]
  SET[TSKFLG@,0] SET[RTNFLG@,0] SET[CSFLG@,0] SET[CHPGFLG@,0]
  SET[REGIFLAG@,0] SET[RTNTOFLG@,0] SET[RETNOGOOD@,0]
  SET[NOILKOKFLG@,0] MIDASINIT[])];

M@[MIDASINIT,IFE@[INITFLG@,0,SET[INITFLG@,1]
  IMRESERVE[0,0,2]IMRESERVE[0,100,21]IMRESERVE[17,0,400],]];

M@[DIB@,IFE@[MULTDIBFLG@,0,SET[MULTDIBFLG@,1]
  VERSION[V@,0] V@[(VERS@[1])]]];

M@[NOMIDASINIT,SET[INITFLG@,1]];


M@[MULTDIB,SET[MULTDIBFLG@,1]];

M@[END,ER@[END...ILC=,0,IP[ILC@]]];

M@[LANGVERSION, ];

SET[INITFLG@,0];

SET[MULTDIBFLG@,0];

ER@[10/3/78--D0Lang.version.3];	*Print release date on .ER file