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] ];