UNL *---------------------------------------------------------- * TMS9995 Assembler Macros for structured programming *========================================================== * * This macro library contains macros providing simple * programming structures like if..then..else clauses, * loops, and a stack. Objective is to improve readability * and maintainability of simple control applications. * * Copyright (C) 2002 Erland Muller * This is free software with ABSOLUTELY NO WARRANTY. The * GNU General Public License as published by Free Software * Foundation (http://www.fsf.org) applies. * * URL of this file: * http://adweb.desy.de/~erlandm/tms/strcmacr.asm * * Maintained by: Erland Muller (erland.mueller@desy.de) * * (next paragraph will apear in the assembler listing) LIST * * Assembled with macro library for structured programming * $Id: strcmacr.asm,v 2.3 2003-03-05 11:25:00+00 erlandm Exp $ * * Note: - Macros may be fully listed by defining a * symbol debug level: DEBUGL EQU 1 * * Warning: - Macros may alter register R9 * - Macros require stack memory area * and stackpointer register RSTACK setup * - Function calls require a register RX * - A RESMAC (reset macro symbol values) * statement must be placed before the END * directive * *----------------------------------------------------------- * UNL * * Stack Operations * ---------------- * * PUSH register ... POP register * * The stack opeartion macros PUSH and POP provide a means * to call multilevel subroutines without having to resort * to multiple workspace switches. PUSH and POP require a * stack area in RAM and a register RSTACK pointing to its * top, usually the start address of the program. The PUSH * operation decrements RSTACK, which points to the last * value pushed. POP is the reverse operation. * * * Conditional statements and loops * -------------------------------- * * IF condition ... [ELSE] ... ENDIF * * WHILE condition ... ENDLP * * FOR register,init_value,step,final_value ... ENDLP * * Conditional statements IF and WHILE take an operand of * Boolean type, which is defined as a byte (8-bit) long * value, 0 meaning "false", 0xff meaning "true". Either * a value is passed by any addressing mode, or a statement * with Boolean result is given as an operand. * * The FOR statement needs a counting register as operand, * initial and final value are of type unsigned int (1 word) * and can be any addressing mode. The step size of type * int (1 word) must be a (symbolic) constant. The Symbol * must have a value asigned before used in a FOR statement. * * Conditional statements can be nested. They automatically * create labels starting with semicolon ';'. Symbols * starting with ';' should not be used, therefore. The * internal symbols used by these macros require to be * reset. The RESMAC statement at the end of the assembler * program does that. * * * Algebraic Comparison * -------------------- * * CP a,comparison_operator,b * * This is just a wrapper to the comparison C opcode of * the assembler. The comparison_operator is one of the * conditions of the J instructions, a and b are values * to be compared in any addressing mode. The result of * this operation is of type boolean and stored in register * R0, referred to as register RVKE. * * * A Note of Caution * ----------------- * * Mind, a macro assembler does not replace a compiler. * There is no syntax checking on macros and you may * receive unpredictable errors on assembly or just * unpredictable behavior of your program caused by * unforseen macro usage or macro assembler errors. * You may find the macros for Boolean functions * (controlmacro_05.asm) useful too. * * Please send any comment to the author and maintainer. * *----------------------------------------------------------- * * General Register Usage * RVKE EQU 0 ; Result of Logical Operat. RLINK EQU 11 ; Dedicated Return Addr. Reg. * * Internal Register Usage * ;RDREF EQU 9 ; Dereferencing register * * Internal macro * -------------- * * List according to debug level * ;LIST $MACRO L $VAR DL $ASG 'DEBUGL' TO DL.S $IF DL.SA&$UNDF=0 if DEBUGL is defined $IF DL.SV>L.V LIST $ENDIF $ENDIF $END ;LIST * *----------------------------------------------------------- * * Macro Definition: PUSH register onto stack * * Stackpointer RSTACK allways points to last pushed value * and is decremented by PUSH operations * PUSH $MACRO R R register to be pushed UNL ;LIST $IF R.A&$PCALL=0 $ASG 'RVKE' TO R.S $ENDIF DECT RSTACK ; RSTACK--; MOV :R:,*RSTACK ; *RSTACK = R; LIST $END PUSH * *----------------------------------------------------------- * * Macro Definition: POP fetch value from stack * POP $MACRO R R register to be restored UNL ;LIST $IF R.A&$PCALL=0 $ASG 'RVKE' TO R.S $ENDIF MOV *RSTACK+,:R: ; R = *RSTACK; RSTACK++; LIST $END POP * *----------------------------------------------------------- * * Internal symbols used by macros only * ;LCNT EQU 0 LabelCounter ;LCPP EQU 0 LabelCounterPopped ;LSP EQU 0 LabelStackPointer ;LSV1 EQU 0 LabelStackVariable(i) ;LSV2 EQU 0 LabelStackVariable(i) ;LSV3 EQU 0 LabelStackVariable(i) ;LSV4 EQU 0 LabelStackVariable(i) ;LSV5 EQU 0 LabelStackVariable(i) ;LSV6 EQU 0 LabelStackVariable(i) ;LSV7 EQU 0 LabelStackVariable(i) ;LSV8 EQU 0 LabelStackVariable(i) ;LSV9 EQU 0 LabelStackVariable(i) ;LSV10 EQU 0 LabelStackVariable(i) ;LSV11 EQU 0 LabelStackVariable(i) ;LSV12 EQU 0 LabelStackVariable(i) ;LSV13 EQU 0 LabelStackVariable(i) ;LSV14 EQU 0 LabelStackVariable(i) * * * more internal macros * -------------------- * * PushIncrementLabelCounter * ;PUILC $MACRO $VAR SP,SV,LC $ASG ';LSP' TO SP.S StackPointer $ASG SP.SV+1 TO SP.SV Increment StackPointer $ASG ';LSV':SP.SV: TO SV.S Next StackVariable $ASG ';LCNT' TO LC.S LabelCounter $ASG LC.SV TO SV.SV Push $ASG LC.SV+1 TO LC.SV Increment LabelCounter $END ;PUILC * * PopLabelCounter * ;POPLC $MACRO $VAR SP,SV,LP $ASG ';LCPP' TO LP.S LabelCounterPopped $ASG ';LSP' TO SP.S StackPointer $ASG ';LSV':SP.SV: TO SV.S Current StackVariable $ASG SV.SV TO LP.SV Pop $ASG 0 TO SV.SV Clear StackVariable $ASG SP.SV-1 TO SP.SV Decrement StackPointer $END ;POPLC * *---------------------------------------------------------- * * Macro Definiton: IF * IF $MACRO C,CC UNL ;LIST $VAR LC LabelCounter $ASG ';LCNT' TO LC.S $IF CC.A&$PCALL=0 MOVB :C:,;RDREF ; set status flags $ELSE $IF C.S=' *' MOV :CC:,;RDREF ; derefence MOVB *;RDREF,;RDREF ; set staus flags $ELSE :C.S: :CC.S: UNL ;LIST $ENDIF $ENDIF JEQ ;E:LC.SV: ; if false jump to else ;PUILC push and inc LabelCounter LIST $END IF * * Macro Definiton: ENDIF * ENDIF $MACRO UNL ;LIST $VAR LP $ASG ';LCPP' TO LP.S ;POPLC pop LabelCounter ;E:LP.SV: LIST $END ENDIF * * Macro Definiton: ELSE * ELSE $MACRO UNL ;LIST $VAR LC,LP $ASG ';LCNT' TO LC.S $ASG ';LCPP' TO LP.S JMP ;E:LC.SV: ; end of then part ;POPLC pop LabelCounter ;E:LP.SV: ;PUILC push and inc LabelCounter LIST $END ELSE * *---------------------------------------------------------- * * Macro Definition: RESMAC for resetting LabelCounterSymbols * RESMAC $MACRO $VAR LC,LP,E $ASG ';LCNT' TO LC.S $ASG ';LCPP' TO LP.S $ASG 0 TO LC.SV $ASG 0 TO LP.SV $END RESMAC * *---------------------------------------------------------- * * Macro Definiton: WHILE * WHILE $MACRO C,CC UNL ;LIST $VAR LC LabelCounter $ASG ';LCNT' TO LC.S ;B:LC.SV: $IF CC.A&$PCALL=0 MOVB :C:,;RDREF ; set status flags $ELSE $IF C.S=' *' MOV :CC:,;RDREF ; derefence MOVB *;RDREF,;RDREF ; set staus flags $ELSE :C.S: :CC.S: $ENDIF $ENDIF JEQ ;E:LC.SV: ; if false exit loop ;PUILC push and inc LabelCounter LIST $END WHILE * * Macro Definiton: ENDLP * ENDLP $MACRO UNL ;LIST $VAR LP $ASG ';LCPP' TO LP.S ;POPLC pop LabelCounter JMP ;B:LP.SV: ; continue while loop ;E:LP.SV: LIST $END ENDLP * *---------------------------------------------------------- * * Macro Definition: FOR * * Arguments R: Register name * I: Initial value (a Register must be parenthesized) * S: Stepsize (must be a constant) * F: Final value (a Register must be parenthesized) * I, F - values unsigned integer * S - signed integer * FOR $MACRO R,I,S,F UNL ;LIST $VAR LC $ASG ';LCNT' TO LC.S * * laod InitialValue into Register * $IF (I.A&$POPL)++(I.A&$PSYM)++(I.A&$PIND) MOV :I:,:R: $ELSE $IF (I.A&$PNDX)++(I.A&$PATO) MOV :I:,:R: $ELSE LI :R:,:I: $ENDIF $ENDIF * * skip register incrementation * $IF (S.V<-2)++(S.V>2)++(S.V=0) JMP $+6 $ELSE JMP $+4 $ENDIF * * loop begin label * ;B:LC.SV: * * increment register by stepsize * $IF S.V=1 INC :R: $ELSE $IF S.V=2 INCT :R: $ELSE $IF S.V=-1 DEC :R: $ELSE $IF S.V=-2 DECT :R: $ELSE AI :R:,:S: $ENDIF $ENDIF $ENDIF $ENDIF * * compare register to FinalValue and jump accordingly * $IF (F.A&$POPL)++(F.A&$PSYM)++(F.A&$PIND) C :R:,:F: $ELSE $IF (F.A&$PNDX)++(F.A&$PATO) C :R:,:F: $ELSE CI :R:,:F: $ENDIF $ENDIF * $IF S.V<0 JL ;E:LC.SV: $ELSE JH ;E:LC.SV: $ENDIF * * save looplabel onto stack * ;PUILC LIST $END FOR * *----------------------------------------------------------- * * Macro Definition: Algebraic Comparison (two variables) * CP $MACRO A,B,C,D,E UNL ;LIST $IF A.S=' *' MOV :B:,;RDREF $IF D.S=' *' MOV :E:,RLINK C *;RDREF,*RLINK $ELSE C *;RDREF,:D: $ENDIF J:C: $+6 $ELSE $IF C.S=' *' MOV :D:,;RDREF C :A:,*;RDREF $ELSE C :A:,:C: $ENDIF J:B: $+6 $ENDIF SZCB RVKE,RVKE ; false JMP $+6 ORI RVKE,>FF00 ; true LIST $END CP * *----------------------------------------------------------- * * Macro Definition: Algebraic Comparison (variable to constant) * CPI $MACRO A,B,C,D UNL ;LIST $IF A.S=' *' MOV :B:,;RDREF MOV *;RDREF,;RDREF CI ;RDREF,:D: J:C: $+6 $ELSE MOV :A:,;RDREF CI ;RDREF,:C: J:B: $+6 $ENDIF SZCB RVKE,RVKE ; false JMP $+6 ORI RVKE,>FF00 ; true LIST $END CPI * *----------------------------------------------------------- * * Macro Definition: String Comparison (quick and dirty) * * A and B are pointers to zero terminated strings * A must be a Register, A will be changed after call * If B ist a Register, it must be in parenthesis * STRCMP $MACRO A,B UNL ;LIST MOV :B:,;RDREF CB *:A:,*;RDREF+ ;compare characters JNE $+12 ;-> false MOVB *:A:+,RVKE ;NULL (termination) JNE $-6 ;-> next comparison ORI RVKE,>FF00 ;true JMP $+4 ;-> end SZCB RVKE,RVKE ;false LIST $END STRCMP * *----------------------------------------------------------- * * Macro Definition: Funktionsaufruf * (parameter pointer based call by reference) * Beispiel: CALLF SUMME,(PSMD1,PSMD2) * CALLF $MACRO F,PL Function identifier, Parameter List UNL ;LIST BL @:F: ; DATA :PL: ; return address must be adjusted * ; by the subroutine called LIST $END CALLF * *----------------------------------------------------------- * * Macro Definition: Funktions-Header * (pointer based parameter call by reference) * korrigiert Returnadresse, sichert RX, RLINK * und definiert Konstanten fuer indezierte * Parameteraddressierung gemaess Parameterliste * Beispiel: FUNCTN SUMME,(KS1,KS2) * FUNCTN $MACRO F,PL Function identifier, Parameter List UNL ;LIST $VAR C,I I counts parameters $ASG '*' TO C.S $ASG ';IPARA' TO I.S Symbol to hold value of I $IF I.SA&$UNDF :I: EQU 0 ; Symbol to temp macro value $ENDIF $IF PL.A&$PCALL ;PARDF :PL: Define Parameter Constants $ENDIF * :F: PUSH RX ; Function head UNL MOV RLINK,RX ; Index register RX: data base address $IF I.SV=2 INCT RLINK ; adjust return address for 1 parameter $ELSE $IF I.SV AI RLINK,:I.SV: ; adjust return address for n parameters $ENDIF $ENDIF PUSH RLINK ; $ASG 0 TO I.SV restore value initially equated :C: RX = &ParameterPointerList $END FUNCTN * * Macro Definition: Return Bool in RVKE von Funktion definiert * mit dem Macro FUNCTN * als Parameter kann eine symbolische Adresse, * indizierte oder indirekte Register-Adresse * oder eine indirekte symbolische Adresse * uebergeben werden * RETB $MACRO V,P UNL ;LIST $IF V.A&$PCALL $IF V.S=' *' MOV :P:,RDREF ; dereference MOVB *RDREF,RVKE ; $ELSE MOVB :V:,RVKE ; $ENDIF $ENDIF POP RLINK UNL POP RX UNL MOVB RVKE,RVKE ; set status flags RT LIST $END RETB * * Macro Definition: ;PARDF Defines Parameter Constants * (for internal use by FUNCTN Macro only) * ;PARDF $MACRO A,B $VAR I counts parameters $ASG ';IPARA' TO I.S :A: EQU :I.SV: ; parameter offset $ASG I.SV+2 TO I.SV 2 bytes per parameter $IF B.A&$PCALL PARDF; :B: $ENDIF $END ;PARDF * *---------------------------------------------------------- * LIST