.ENABL LC YES=1 NO=0 .TITLE MCMD ;MCMD.MAC .IDENT /12DEC7/ .PSECT MCMD .LIST TTM DIM=0 .MACRO MC A .NCHR U$ .BYTE U$ .ASCII ~A~ DIM=DIM+1 .ENDM ; ----------------------------------------------------------------------- ; the following table is in the format of an mp string. ; That is, it has 6 header words followed by the strings (each string ; is preceded by the count of characters - no word allignment) ; ; The table can be expanded simply by entering a new command in the ; any slot. the labels size, dim, and dimen are ; computed by the assembler and need not be of concern when adding entries. ; ; This string is loaded into a separate overlay and then "read" as though ; it were coming from a file except that it is faster. note that these are ; not loaded until the macro library is read. ; ; ----------------------------------------------------------------------- mcmd:: .word size ;length (used when dynamic strings - But necessary) .word dimen ;dimension (number of entries) .word size-30. ;current length used by xstring to check overflow .word 255. ;string size overflow (checked by xstrin) .word 0 ;not used but allocated .word dimen ;dimension used by xstring ;------------------------------------------------------------------------ ; 1ST-- change to mc form: 5,$c-^-MC <- c-$->-3y ; change back: 5,$g;mc <;c/mc $;; ; find comments and fix: 5,$g/mc <;/c/mc <;/;/c/>$// ; This shortens up $macro lines but is not reversible ~5,$g/\$macro/c3/ /> ;/ ; This library supports the c calls to the Conroy's runtime system ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - ; currently defined symbols ; $top$ set to relative zero of a file (for odt use) ; $auto$ counts local storage ; $auto. for local storage counting ; $type$ routine in main lib to type out a line to lun 5 ; $buf$ a 140. byte scratch buffer i main (for printf usage ) ; ; ; The stack is used as follows: ; ; If (stack 1) ; tos branch to on false ; nos go here one done (after elseif's etc) ; ; case (stack 2) ; tos break to label ; nos variable to test ; 3os skip over to next case test label ; 4os case or label ; ; Do while/forever (stack 2) ; tos break to ; nos jmp back to test or continue in loop label ; ; loop (stack 2) ; tos break to ; nos jmp back to test for more looping label ; 3os loop index ; 4os step amount ; ; Note!!! all of these macros which test strings test for them in ; upper case only. Thus you must use upper case for everything in ; the program that is significant to these expansions. This makes ; the program more readable if everything else is in lower case. ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - MC <$MACRO IF> ;A = B > MC MC MC MC ; ; Note that the below causes right to left evaluation of ; relations. IF a = b and c = d or d = f ; is ; equiv to IF (a = b and (c =d and (d = f))) ; in a paren'd expression (not permitted of course) ; MC MC >> MC MC < B#@G #@J> MC > MC >> MC <$ENDM> ; - - - - - - - - - - - - - - - - - - - - - - - - - - - MC <$MACRO IFB> ;A = B > MC MC MC MC ; ; Note that the below causes right to left evaluation of ; relations. IFB a = b and c = d or d = f ; is ; equiv to IFB (a = b and (c =d and (d = f))) ; in a paren'd expression (not permitted of course) ; MC MC >> MC MC < B#@G #@J> MC > MC >> MC <$ENDM> ; - - - - - - - - - - - - - - - - - - - - - - - - - - - ; - - - - - - - - - - - - - - - - - - - - - - - - - - - MC <$MACRO O%R> ;BR.TO > MC <#@2> MC < BR #@1> MC MC <#@G=.> MC MC <$ENDM> ; - - - - - - - - - - - - - - - - - - - - - - - - - - - MC <$MACRO A%ND> ;A = B ...> MC <#@2> MC MC < BR #@F> MC MC <#@G=.> MC MC < BR #@1> MC <#@F=.> MC <$ENDM> ; - - - - - - - - - - - - - - - - - - - - - - - - - - - MC <$MACRO FI> ; COMMENT> MC MC <#@2=. ; #@1> MC MC <#@2=.> MC <$ENDM> ; - - - - - - - - - - - - - - - - - - - - - - - - - - - MC <$MACRO ELSE> ;COMMENT> MC MC MC MC < JMP #@6> MC <#@5=. ; #@1> MC <$ENDM> ; - - - - - - - - - - - - - - - - - - - - - - - - - - - MC <$MACRO ELSEIF> ;...> ;get nos MC MC < JMP #@H> MC MC <#@F=.> MC MC MC MC <$ENDM> ; - - - - - - - - - - - - - - - - - - - - - - - - - - - MC <$MACRO ELSEIFB> ;...> ;get nos MC MC < JMP #@H> MC MC <#@F=.> MC MC MC MC <$ENDM> ; ------------------------------------------ MC <$MACRO .> ;just a short way to do functions> MC > MC <$ENDM> ; ------------------------------------------ MC <$MACRO $NOP> MC <$ENDM> ; ------------------------------------------ ;specialized add and sub macros, they test for #1 and do increments ; note they only check parameter 2 (i.e. sub* a,b is backwards to ; what the sub machine code is (I can't remember why). ; at any rate, the Let statement knows this. ; MC <$MACRO SUB*> MC <#1> << DEC #@1>> < SUB #@2,#@1>> MC <$ENDM> ; ------------------------------------------ MC <$MACRO ADD*> MC <#1> << INC #@1>> < ADD #@2,#@1>> MC <$ENDM> ; ------------------------------------------ ; NEW let macro, allows functions, & operator, and . array operator ; for example: ; LET a = b[d,e] + f[g,h] / #20. * g[i,j,k] - .array[index] ; note that a function must have at least 1 parm for this to work ; MC <$MACRO LET> ;1 = 3 * 5> ; MC <#@5> >> MC >> MC <#@3> < M%OV #@{1},#@{3}>> MC <+ * - / <>> < > >> MC MC < $%% #@E #@{1},#@{5}> MC >> MC <$ENDM> ; ------------------------------------------ MC <$MACRO $"> MC MC < BR #@6> MC <#@5=.> MC < .ASCIZ _#@1_> MC < .EVEN> MC MC <#@6=.> MC <$ENDM> ; ------------------------------------------ MC <$MACRO $&> MC MC < MOV ##@1,-(SP) ;push offset> MC < ADD R5,(SP) ;and compute address of #@1> MC <$ENDM> ; ------------------------------------------ MC <$MACRO $%%> MC <** <> <#@1 #@2,#@3> >> MC >> MC <#@1 #@2,R0>> MC <$ENDM> ; ------------------------------------------ MC <$MACRO M%OV> MC MC MC MC MC <> << MOV #@2,#@1>> ]>> MC <$ENDM> ; ------------------------------------------ MC <$MACRO END> MC MC <#@2> >>> MC <$ENDM> ; ------------------------------------------ MC <$MACRO BEGIN> ; name> MC
> MC > ; ; allow for a name here. This is only here ; to check mismatched begin/ends ; MC <$ENDM> ; ------------------------------------------ MC <$MACRO BEGIN$$> MC MC < BR #@1> MC MC > MC <#@2: JMP #@3> MC <#@1:> MC <$ENDM> ; ------------------------------------------ MC <$MACRO PROGRAM> ;NAME> MC <$top$=.> MC MC <$auto$=-4> MC <.enabl lc> MC > MC > MC <$ENDM> ; ------------------------------------------ MC <$MACRO POP> MC < MOV (SP)+,#@{1}> MC <$ENDM> MC <$MACRO PUSH> MC MC MC MC <(SP)+> < MOV #@1,-(SP)>> MC MC <$ENDM> ; ------------------------------------------ MC <$MACRO call> MC < JSR PC,#@1> MC <$ENDM> ; ------------------------------------------ MC <$MACRO LOOP> ;FOR I = FROM TO "TO"> ; watch out for which portions of the statement is lower case ; and the loop index must match in case with the next statement also. MC <> <> > MC MC MC MC MC MC MC < MOV #@{4},#@{2} ;Init loop index> MC <#@A=.> MC < CMP #@{2},#@{6} ;done loop?> MC < > >> MC MC < B#@C #@B ;yes if #@C> MC <$ENDM> ; ------------------------------------------ ; New do macro, recurs with if(b) macro - needs lots of stack space. MC <$MACRO DO> ;WHILE(B) THIS IS THAT> ; 1 2 3 4 MC MC ; push the two labels such that the top is the place to break to ; and the next on stack is the loop back place MC ; This is the loop back label MC <#@G=.> ; test the condition MC > MC > MC FOREVER > MC FOREVER < JMP #@H ;else end while loop>> MC FOREVER > MC <$ENDM> ; ------------------------------------------ MC <$MACRO OD> ;end of do loop (while or forever)> ; Get next to tos (nos) MC MC < JMP #@1 ;Repeat loop> MC MC <#@1=.> MC MC <$ENDM> ; ------------------------------------------ MC <$MACRO NEXT> ;INDEX> MC MC MC MC < JMP #@2 ;back to top> MC MC MC MC <#@2=.> MC MC <#@2> >> MC MC <$ENDM> ; ------------------------------------------ MC <$MACRO BR.> ;sets str 25 to inverse branch> MC <= EQ NE LT GT GE LE CC CS><>> MC <>> MC <$ENDM> ; ------------------------------------------ MC <$MACRO !> ;Simply sets str 25 to its first parm so the above fits on 2 lines.> MC MC <$ENDM> ; ------------------------------------------ ; special case compare, checks for second arg being #0 and gens a test ; MC <$MACRO CMP.> ;A,B> MC >< CMP #@1,#@2>>> MC <$ENDM> ; ------------------------------------------ MC <$MACRO CMPB.> ;A,B> MC >< CMPB #@1,#@2>>> MC <$ENDM> ; ------------------------------------------ ; 1 2 3 MC <$MACRO SELECT> ;case var of ...> ;Make 2 labels MC ;Put no or indicator onto stack MC MC MC MC MC <$ENDM> ; ------------------------------------------ ; 1 from stack MC <$MACRO CASE> ;var (label newlabel)> ; ; Case construct is as follows: ; ; Multiple cases going to the same code is by using the OR parameter ; of the case statement. example: ; ; CASE 1 OR ; CASE 2 OR ; ... ; CASE N ; ; if an "or" ; if -nor- ; if label ; if not "or" ; if -nor- do nothing ; if label ; ; ; ; MC ;put string in 3os (3rd from top of stack) into parm-4 MC MC <#@4=.> ;place new label into 3os MC ;get var into parm4 MC MC > MC < BNE #@3> ;get -nor- or label if present into parm4 from 4os MC MC MC OR -nor- >> MC MC MC OR < BR #@4>> ;I%SW 20 MC MC -nor- >> MC > MC MC <$ENDM> ; ------------------------------------------ ; 1 from stack MC <$MACRO DEFAULT> ; var (label newlabel)> MC ;put string in 3os into parm-2 MC MC <#@2=.> ;place new label into 3os MC ;get var into parm-2 MC MC <$ENDM> ; ------------------------------------------ ; 1 from stack MC <$MACRO CASEB> ;var (label newlabel)> ; ; Case construct is as follows: ; ; Multiple cases going to the same code is by using the OR parameter ; of the case statement. example: ; ; CASEB 1 OR ; CASEB 2 OR ; ... ; CASEB N ; ; if an "or" ; if -nor- ; if label ; if not "or" ; if -nor- do nothing ; if label ; ; ; ; MC ;put string in 3os (3rd from top of stack) into parm-4 MC MC <#@4=.> ;place new label into 3os MC ;get var into parm4 MC MC > MC < BNE #@3> ;get -nor- or label if present into parm4 from 4os MC MC MC OR -nor- >> MC MC MC OR < BR #@4>> ;I%SW 20 MC MC -nor- >> MC > MC MC <$ENDM> ; ------------------------------------------ MC <$MACRO ESAC> ;VAR1> MC MC MC MC ;XXXXX -#@1-1 -#@2-2 -#@3-3 -#@4-4 MC ,#@3,>>> MC <#@2=.> MC <#@4=.> MC <$ENDM> ; ------------------------------------------ MC <$MACRO BREAK> ;get top string into parm-15 MC MC < I%NB <#@1> <#@1 #@*(2,C)>> MC < JMP #@F ;break> MC < I%NB <#@1> FI> MC <$ENDM> ; ------------------------------------------ MC <$MACRO P%SH> MC MC MC MC MC MC MC <(SP)+> < M%-OV <#@*(1"Z)>>> MC <$ENDM> MC <$MACRO M%-OV> MC <** <> > MC <- + / * <>> <>> MC >> MC > MC >>> MC < MOV -2(R5),-(SP)>> MC <$ENDM> ; - - - - - MC <$MACRO PEEK> MC MC <[#@1]> MC <$ENDM> ; - - - - - MC <$MACRO CL> ;ARRAY/FUN P1 P2 P3...> MC . <> >> MC MC <$ENDM> ; ------------------------------------------ MC <$MACRO CL@> ;ARRAY P1 P2 P3> MC < M%OV R1,#@{2}> MC B < ASL R1>> MC < T%YP T #@1 25> MC MC <0 1 2> << ADD ##@1,R1> < ADD ##@1,R1> < ADD #@1(R5),R1>>> MC 1 < ADD R5,R1>> MC < MOV#@3 (R1),R0> MC <$ENDM> ; ------------------------------------------ MC <$MACRO CL%> ;NAME P1 P2...> MC MC <** P%SH <#@A>,<#@9>,<#@8>,<#@7>,<#@6>,<#@5>,<#@4>,<#@3>,<#@2>> MC < JSR PC,#@1> MC MC < ADD ##@1,SP ;Clean up stack> MC <$ENDM> ; - - - - - ; uses the xxx[yyy] feature and permits calls to either c routines ; or routines set up via a func/ret macro pair. ; MC <$MACRO C> ;Call a c prog as: C var = name[abc]> MC MC < mov r0,#@1>> MC <$ENDM> ; - - - - - ; Function sets up offsets according to how the Conroy save and restore ; routines allocate storage off the stack ; it also allocates storage for locals. Then it clears ; the local (auto) storage counter for the next function later on. ; ; Usage of C function compatible routines ; ; program lab |used once ; |------------ ; auto l1 l2 l3 ... | Function 1 ;FUNCTION entry[p1,p2 ...] | ; ... | code is here ; ret [value] | ; | ; |------------- ; auto l1 l2 l3 ... | Function 2 ;FUNCTION entry2[p1,p2 ...] | ; ... | code is here ; ret [value] | ; |------------- ; ; ; All variables are referenced as xxx(r5) ; and are call by value as in C. ; ; MC <$MACRO FUNCTION> ;A[B,C,D] > ; trace will cause the function name and argument values to be printed ; on entry. The top of the file (for odt use) is also output. The odt ; option will cause an iot trap to odt. ; trace is switch 17, (x7) odt entry is 18 (x8) MC MC > MC > MC MC <$ENDM> ; ------------------------------------------ MC <$MACRO T%%> MC MC MC <$ENDM> ; ------------------------------------------ MC <$MACRO F%UNC> ;A,B,C,D...> MC <#@1::> MC MC <$ENDM> ; ------------------------------------------ ; func used to be the only macro (i.e. no Function) ; some older programs specify this macro instead - so it remains. ; it also is the only way to have a function without the name being ; declared global. MC <$MACRO FUNC> ;P1 P2 P3... Use Conroys runtime here.> MC <#@1= 12>> MC <#@2= 14>> MC <#@3= 16>> MC <#@4= 20>> MC <#@5= 22>> MC <#@6= 24>> MC <#@7= 26>> MC <#@8= 30>> MC <** E%%S <#@*(1"Z)>> MC >> ;note that $auto$ is negative, thus we ADD to sub from stack ; save current $auto$ in $auto. for the return ; but re-init $auto$ in case there is no return statement ; MC < jsr r0,$$csav ;get stack frame> MC < add #$auto$,sp ;allocate space on stack for autos> MC < $auto.=$auto$> MC < $auto$=-4 ;re-init> MC <$ENDM> ; - - - - - MC <$MACRO E%%S> MC MC <$ENDM> ; - - - - - MC <$MACRO RET> ; The below does not < > the parameters so that any function references ; will cause an error (since they would clobber r0 and we accumulate ; into r0). MC > MC > MC < sub #$auto.,sp ;de-allocate locals> MC < jmp $$cret> MC <$ENDM> ; - - - - - ;$MACRO RET > ; This version will have to wait till we have better temp alloc ;I%NB <#@1> > ;I%NB <#@1> < MOV -2(R5),R0> ; sub #$auto.,sp ;de-allocate locals ; jmp $$cret ;$ENDM ; - - - - - ; Auto is used to generate offsets which are applied to labels and ; compute how much local storage is needed to allocate from the stack ; ; Usage: AUTO a,b,c... if [n] not specified, then its 2 ; AUTO a[n],b[n],c,d... if odd values are supplied, user ; must do the allignment ; The Program statement must appear first (at least once in the program) ; it initializes $auto$. Multiple Autos are permitted. The auto's must ; be followed by a Func statement which allocates (and must be the entry) ; storage. After it allocates storage it also re-initializes $auto$ ; so a subsuquent function can re use it properly. Note that variables ; defined in this manner can be reused locally in another function with ; diffenent offsets, but nuthing is going to detect using a variable ; defined locally to another function which is intended to be redefined ; and is inadvertantly left out of a Auto statement ; MC <$MACRO AUTO> ;var1 var2 ...> MC <** AUTO% <#@*(1"N)>> MC <$ENDM> ;- - - - - MC <$MACRO AUTO%> ;var [size] (size defaults to 2)> MC <> <> > MC MC < $auto$=$auto$-#@2> MC <#@1= $auto$> MC 1> MC <$ENDM> ; - - - - - ;+ ; These macros are used when writing privel'd tasks (or ones which ; simply must be small - can't afford the overhead of the C library). ; ; type buf-addr [car-control] ;qiow to lun5 buffer (no jsr) ; len buf-addr ;sets r0=len of str ; tty bufaddr [car-control] ;like type, but jsr's to $type$ ; ; All assume that r0 and r1 are available to be ; destroyed without saving. (all c callable stuff is like this) ; car-control defaults to #40 ;- ; - - - - - MC <$MACRO LEN> ;string> MC MC < mov #@{1},r0> MC <#@2=.> MC < tstb (r0)+> MC < bne #@2> MC < sub #@{1},r0> MC < dec r0> MC <$ENDM> ; - - - - - MC <$MACRO TYPE> ;string-addr types asciz string> MC MC <> <> > MC ;qiow$s #io.wvb,#5,#5,,,,<#BUF,r0,#40> THIS IS TOO DAMN SLOW MC < CLR -(SP)> MC < CLR -(SP)> MC < CLR -(SP)> MC < MOV #@{2},-(SP)> MC < MOV r0,-(SP)> MC < MOV #@{1},-(SP)> MC < CLR -(SP)> MC < CLR -(SP)> MC < CLR -(SP)> MC < MOVB #5,(SP)> MC < MOV #5,-(SP)> MC < MOV #io.wvb,-(SP)> MC < MOV (PC)+,-(SP)> MC < .BYTE 3,12.> MC < EMT ^O<377>> MC <$ENDM> ; - - - - - MC <$MACRO TTY> ; quoted string or address of asciz string> MC < mov #@1,-(sp)> MC < jsr pc,$type$> MC <$ENDM> ; - - - - - ; Printf Like the unix or C routine. It does not understand \x type ; of stuff and allways assumes a \n at the end of the string. ; Usage: printf "string" p1 p2 p3 ... ; String may be literal or just a variable which points to a string. ; Pn may be functions[arg] registers strings etc. ; basically anything in the LET statement. ; To just format the buffer, use the sprint function directly. ; note that $buf$ is used for formatting and if an argument ; is a function which recursively calls printf it will clobber ; $buf$. MC <$MACRO PRINTF> MC < mov r0,-(sp)> MC < mov r1,-(sp)> MC ]> MC < mov #$buf$,-(sp)> MC < jsr pc,$type$> MC < mov (sp)+,r1> MC < mov (sp)+,r0> MC <$ENDM> ; - - - - - ; Finally these are defined. They clobber r0 and/or r1 (mul uses r1 ; div uses both) ; BE careful with these. MC <$MACRO MUL45> ;A * B A = A * B> MC < mov #@2,r1> MC < mul #@1,r1> MC < mov r1,#@1> MC <$ENDM> ; MC <$MACRO DIV45> ;A B A = A / B> MC < clr r0> MC < mov #@1,r1> MC < div #@2,r0> MC < mov r0,#@1> MC <$ENDM> ; MC <$MACRO FOR> ;INIT-1 CONDITION-2 REINIT-3> ; This is a for loop like C or ratfor ; MC <> <> >> MC MC <#@1> MC MC > MC <$ENDM> ; MC <$MACRO ROF> ; the ending statement in a for loop MC MC <#@1> MC MC <$ENDM> ; ------------------------------------------ ; ------------------------------------------ MC <$MACRO DMPSTR> MC > MC > MC MC MC <** $%D 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 25 29> MC <** $%D2 30 31 32 33 34 35 36 37 38 39 > MC <** $%D2 40 41 42 43 44 > MC > MC > MC MC MC <$ENDM> ; MC <$MACRO $%D> MC MC > MC <$ENDM> ; MC <$MACRO $%D2> MC MC > MC <$ENDM> ; MC <$MACRO DMPSW> MC <** S%%W 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15> MC <** S%%W 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31> MC <$ENDM> ; MC <$MACRO S%%W> MC > MC <$ENDM> ; MC <$MACRO DUMP> MC MC MC MC < >> MC <$ENDM> ; MC <$MACRO POKE> ;STACK STRING> MC ,,#@1> MC <$ENDM> ;------------------------------------------------------------------------ MC <$MACRO SETLAB> ;LAB> ;This allows one to set the label used for generating labels MC MC <$ENDM> ; - - - - - ; The following trap the .end statement and verify all constructs ; have been terminated. It checks the current level of the stack ; by pushing .end and verifying that they are in position 1 of ; both stacks. MC <$MACRO .end> MC <.END #@1> MC <$ENDM> MC <$MACRO .END> MC MC MC MC MC <.END.END> >> MC MC MC > MC <$ENDM> ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - MC <$MACRO STRUCT> ;name> MC MC < #@1=0> MC <$ENDM> ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - MC <$MACRO END-STRUCT> MC MC >>> MC <$ENDM> ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - MC <$MACRO FIELD> ;name1,name2...> MC <** F%%D <#@*(1"N)>> MC <$ENDM> ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - MC <$MACRO F%%D> MC MC <#@1=#@A> MC <> << #@A=#@A+2>> < #@A=#@A+#@2>> MC <$ENDM> ; LST-- ;------------------------------------------------------------------------ $$sda==dim ;index of first debugger macro (not implemented) .even size = .-mcmd+50. dimen = dim .end