* 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