SUBT System wide macro definitions => &.Hdr.Macros OldOpt SETA {OPT} OPT OptNoList+OptNoP1List ; *********************************** ; *** C h a n g e L i s t *** ; *********************************** ; Date Name Description ; ---- ---- ----------- ; 28-Sep-87 TMD Modified CallAVector, VDWS for new soft-load version ; 29-Sep-87 TMD Modified CallAVector again ; 05-Sep-87 SKS Removed $hat option from Push ; 22-Oct-87 TMD Modified CallAVector yet again ; 17-Dec-87 NDR Modified Swap macro (conditional added) ; 15-Jan-88 BC Fixed Byte and Word so that the actual parms may be expr. ; 04-Feb-88 SKS Fixed BYTEWS macro. AAsm thinks :LOR is ok ?! ; 10-Mar-88 NDR Implemented XError macro ; 11-Mar-88 NDR Improved XError macro ; 19-Apr-88 SKS Fixed BYTEWS macro. Added Immediate macro ; 21-Apr-88 SKS Took debugging out of Immediate macro!. Fixed it to produce ; less rubbish in error cases ; 11-May-88 SKS Added Command_LastName to Command macro ; 16-May-88 SKS Added optimising addr macro. My apologies to anyone it ; screws up! Removed pre-OS 1.20 changes from list. ; 24-May-88 TMD Added offset to AlignSpace. ; 31-May-88 SKS addr now does register relative symbols too (need AAsm 1.48) ; 01-Jun-88 SKS addr now understands different amounts of verbosity ; 03-Jun-88 SKS make wsaddr to get round absolute problems ; 11-Jun-88 SKS tweaked |#| ; 18-Jul-88 BC Made PHPSEI & PLP use a register argument ; ============================================= ; Macros should be kept in ALPHABETICAL order ! ; ============================================= MACRO AddError $name,$text,$value [ "$value" = "" ErrorNumber_$name # 1 | ErrorNumber_$name * $value ] GBLS ErrorString_$name ErrorString_$name SETS "$text" MEND ; *************************************************** ; *** Put address of $dest in $reg; $dest > . *** ; *** !!! Please use addr wherever possible !!! *** ; *************************************************** MACRO $label ADDR $reg, $dest, $cond $label ADR$cond.L $reg, $dest MEND ; ***************************************************************************** ; *** Optimising ADR/ADRL for addressing object backwards from current pc *** ; *** or register relative symbol. Symbol MUST be defined on first pass *** ; ***************************************************************************** GBLA addr_verbose addr_verbose SETA 0 MACRO $label addr $reg, $object, $cc LCLA value value SETA .-$object+8 Immediate &$value [ immediate $label ADR$cc $reg, $object [ addr_verbose :AND: 1 <> 0 ! 0,"addr saved a word" ] | $label ADR$cc.L $reg, $object [ addr_verbose :AND: 2 <> 0 ! 0,"addr didn't save a word" ] ] MEND MACRO $label wsaddr $reg, $object, $cc LCLA value value SETA :INDEX: $object Immediate &$value [ immediate $label ADR$cc $reg, $object [ addr_verbose :AND: 1 <> 0 ! 0,"wsaddr saved a word" ] | $label ADR$cc.L $reg, $object [ addr_verbose :AND: 2 <> 0 ! 0,"wsaddr didn't save a word" ] ] MEND ; *************************************************** ; *** Generate SWI labels assuming ^ type defs *** ; *** Also assumes the global variable SWIClass *** ; *************************************************** GBLS SWIClass MACRO AddSWI $SWIName,$value [ "$value" = "" $SWIClass._$SWIName # 1 | $SWIClass._$SWIName * $value ] X$SWIClass._$SWIName * $SWIClass._$SWIName + Auto_Error_SWI_bit MEND ; ******************************************************************* ; *** Align workspace to given power-of-two boundary and offset *** ; ******************************************************************* MACRO $label AlignSpace $value, $offset [ "$value" = "" $label # 3 :AND: ($offset-:INDEX: @) | $label # (($value)-1) :AND: ($offset-:INDEX: @) ] MEND MACRO $label ASL $reg, $val, $cc $label MOV$cc $reg, $reg, ASL #$val MEND MACRO $label ASR $reg, $val, $cc $label MOV$cc $reg, $reg, ASR #$val MEND ; ************************************************* ; *** Put address of $dest in $reg; $dest < . *** ; ************************************************* MACRO $label BADDR $reg, $dest, $cond $label ADR$cond.L $reg, $dest MEND ; **************************************************** ; *** Macro BSR - Branch to subroutine saving R14 *** ; **************************************************** MACRO $label BSR $dest $label Push R14 BL $dest Pull R14 MEND ; ******************************* ; *** Add byte to workspace *** ; ******************************* MACRO $label Byte $value, $count [ "$label" = "" [ "$count" = "" $value # 1 | $value # ($count) ] | [ "$value" = "" $label # 1 | $label # ($value) ] ] MEND ; ******************************************** ; *** Macro BYTEWS - Point to OsbyteVars *** ; ******************************************** MACRO BYTEWS $reg Immediate OsbyteVars [ immediate MOV $reg, #OsbyteVars | MOV $reg, #(OsbyteVars :AND: &FF) ORR $reg, $reg, #(OsbyteVars :AND: :NOT: &FF) ] MEND MACRO $label CallAVector $cond [ AssemblingArthur $label B$cond CallVector | [ Module $label B$cond %FT10 Push "R8,R9" MOV R8, PC AND R8, R8, #3 ; just get mode bits EOR R8, R8, #SVC_mode ; eored with SVC mode TEQP R8, PC MOVNV R0, R0 Push R14 MOV R9, R10 SWI XOS_CallAVector Pull R14 TEQP R8, PC MOVNV R0, R0 Pull "R8,R9" MOV PC, R14 10 | $label LDR$cond PC, =CallVecAddr [ "$cond" = "" LTORG ; Can't conditionally execute constants ! Use your own LTORG ] ] ] MEND ; ****************************************** ; *** Clear carry flag - will set nzcv *** ; ****************************************** MACRO $label CLC $cond $label CMN$cond pc, #0 MEND ; ************************************************************************** ; *** Clear bits in PSR from the mask in $bits, using register $regtmp *** ; ************************************************************************** MACRO $label CLRPSR $bits, $regtmp, $cond $label MVN$cond $regtmp, #$bits TST$cond.P $regtmp, pc MEND ; ******************************************* ; *** Clear overflow flag - will set nzCv *** ; ******************************************* MACRO $label CLRV $cond $label CMP$cond pc, #0 MEND ; ********************************************* ; *** Generates a help/syntax/command block *** ; *** for a Module star command table *** ; *** Needs a variable Module_BaseAddr set *** ; ********************************************* GBLA Command_LastName ; Offset to command string within module MACRO Command $cmd, $max, $min, $optbits, $cmdlabel LCLA temp LCLS cmdlab [ "$optbits" = "" temp SETA 0 | temp SETA $optbits ] [ "$cmdlabel" = "" cmdlab SETS "$cmd" | cmdlab SETS "$cmdlabel" ] Command_LastName SETA .-Module_BaseAddr DCB "$cmd", 0 ALIGN DCD $cmdlab._Code -Module_BaseAddr DCD ($min) + (($max) :SHL: 16) + temp DCD $cmdlab._Syntax-Module_BaseAddr DCD $cmdlab._Help -Module_BaseAddr MEND MACRO $label DEC $reg,$by [ "$by" = "" $label SUB $reg,$reg,#1 | $label SUB $reg,$reg,#$by ] MEND MACRO $label DECS $reg,$by [ "$by" = "" $label SUBS $reg,$reg,#1 | $label SUBS $reg,$reg,#$by ] MEND ; ********************************************************** ; *** Macro DIVREM - rc := ra DIV rb; ra := ra REM rb *** ; *** rb preserved, rtemp corrupt *** ; *** Now up to 37% faster *** ; ********************************************************** MACRO $label DivRem $rc, $ra, $rb, $rtemp $label MOV $rtemp, $rb CMP $rtemp, $ra, LSR #1 01 MOVLS $rtemp, $rtemp, LSL #1 CMPLS $rtemp, $ra, LSR #1 BLS %BT01 MOV $rc, #0 02 CMP $ra, $rtemp SUBCS $ra, $ra, $rtemp ADC $rc, $rc, $rc MOV $rtemp, $rtemp, LSR #1 CMP $rtemp, $rb BCS %BT02 MEND ; ********************************************************** ; *** Macro DIVREM - rc := ra DIV rb; ra := ra REM rb *** ; *** OLD version NB. rb, rtemp corrupt *** ; ********************************************************** ; MACRO ;$label DivRem $rc, $ra, $rb, $rtemp ;$label MOV $rtemp, #1 ;01 CMP $rb, #&80000000 ; CMPCC $rb, $ra ; MOVCC $rb, $rb, ASL #1 ; MOVCC $rtemp, $rtemp, ASL #1 ; BCC %BT01 ; MOV $rc, #0 ;02 CMP $ra, $rb ; SUBCS $ra, $ra, $rb ; ADDCS $rc, $rc, $rtemp ; MOVS $rtemp, $rtemp, LSR #1 ; MOVNE $rb, $rb, LSR #1 ; BNE %BT02 ; MEND MACRO $label DoCallTable $jumpreg, $tablename, $work $label Push "$work, pc" ADR $work, $tablename LDR lr, [$work, $jumpreg, LSL #2] ADD $work, $work, lr STR $work, [stack, #4] MOV lr, pc ; ADR lr, %FT99 with correct mode bits Pull "$work, pc" ; 0 4 ASSERT $jumpreg <> $work ASSERT $jumpreg <> lr ASSERT $jumpreg <> pc 99 ; Return here from called routine MEND ; **************************************************************************** ; *** Probably the fastest jump table mechanism for PIC - a mere 4S + 2N *** ; *** cycles. Jump table directly follows the macro, and is a list of *** ; *** offsets done by eg. DCD routine_address-table-4. Needs only one *** ; *** register temp (Use lr mostly). *** ; **************************************************************************** MACRO $label DoFastJumpTable $jumpreg, $trash $label LDR $trash, [pc, $jumpreg, LSL #2] ADD pc, pc, $trash MEND ; ********************************************* ; *** Jump table preserving all registers *** ; ********************************************* MACRO $label DoJumpTable $jumpreg, $tablename, $work1, $work2 $label Push "$work1, $work2, pc" ; pc is just a dummy reg here ADR $work1, $tablename LDR $work2, [$work1, $jumpreg, LSL #2] ADD $work1, $work1, $work2 STR $work1, [stack, #8] Pull "$work1, $work2, pc" ; 0 4 8 ASSERT $jumpreg <> $work1 ASSERT $jumpreg <> $work2 ASSERT $jumpreg <> pc MEND MACRO $label DoSVCCallTable $jumpreg, $tablename $label ADR SVCWK1, $tablename LDR SVCWK0, [SVCWK1, $jumpreg, LSL #2] MOV lr, pc ; ADR lr, %FT99 with correct mode bits ADD pc, SVCWK1, SVCWK0 ASSERT $jumpreg <> lr ASSERT $jumpreg <> pc 99 ; Return here from called routine MEND ; *************************************************************************** ; *** Jump table using SVC mode temporary registers. Use with caution ! *** ; *************************************************************************** MACRO $label DoSVCJumpTable $jumpreg, $tablename $label ADR SVCWK1, $tablename LDR SVCWK0, [SVCWK1, $jumpreg, LSL #2] ADD pc, SVCWK1, SVCWK0 ASSERT $jumpreg <> lr ASSERT $jumpreg <> pc MEND MACRO $label Error $errno, $errstr $label ADR R0, %FT01 SWI OS_GenerateError 01 & $errno = "$errstr", 0 ALIGN MEND MACRO $label XError $errsym, $c1, $c2 $label ADR$c1$c2 R0,ErrorBlock_$errsym SETV $c1 MEND ; *********************************************************************** ; *** Exit macro for SWI handlers. *** ; *** Jump to 17M in the Sam-hacked Brazil, for installed handlers. *** ; *** Do it directly if really in system *** ; *********************************************************************** SWIHandlerExit * 17*1024*1024 CallVecAddr * SWIHandlerExit+4 MACRO $label ExitSWIHandler $cond [ AssemblingArthur $label B$cond SLVK | [ Module $label LDR$cond PC, =BranchToSWIExit | $label MOV$cond PC, #SWIHandlerExit ] ] MEND MACRO $label GRAB $reglist, $cond, $hat $label LDM$cond.FD r13!, {$reglist}$hat MEND ; ***************************************************************************** ; *** Pull registers and restore PSR (if R15 loaded). Use with extreme *** ; *** caution : there are bugs in 3um ARM with PSR update in non-USR modes.*** ; ***************************************************************************** MACRO $label GRABS $reglist, $cond $label LDM$cond.FD r13!, {$reglist}^ [ :LEN: "$reglist" <= 3 ! 0,"GRABS used dangerously - check your code !" ] MEND MACRO $label INC $reg,$by [ "$by" = "" $label ADD $reg,$reg,#1 | $label ADD $reg,$reg,#$by ] MEND MACRO $label INCS $reg,$by [ "$by" = "" $label ADDS $reg,$reg,#1 | $label ADDS $reg,$reg,#$by ] MEND ; **************************************************** ; *** Generates the InfoWord for a command table *** ; **************************************************** MACRO InfoWord $max, $min, $optbits [ "$optbits" = "" DCD ($min) + (($max) :SHL: 16) | DCD ($min) + (($max) :SHL: 16) + $optbits ] MEND ; ********************************************************** ; *** Macro Immediate - set flag if value is immediate *** ; ********************************************************** GBLL immediate MACRO Immediate $var immediate SETL {FALSE} LCLA count LCLA varcopy varcopy SETA $var WHILE count <= 30 [ ((varcopy:SHL:count) + (varcopy:SHR:(32-count))) :AND: (:NOT: &FF) = 0 immediate SETL {TRUE} MEXIT ] count SETA count + 2 WEND MEND ; ********************************************* ; *** Macro LDROSB - Load Osbyte variable *** ; ********************************************* MACRO $label LDROSB $reg, $var, $cond $label MOV$cond $reg, #0 LDR$cond.B $reg, [$reg, #OsbyteVars+$var-OSBYTEFirstVar] MEND ; ****************************************************** ; *** Macro LDW - Load word from unknown alignment *** ; ****************************************************** MACRO $label LDW $dest, $addr, $temp1, $temp2 ASSERT $dest < $temp2 $label BIC $temp1, $addr, #3 LDMIA $temp1, {$dest, $temp2} AND $temp1, $addr, #3 MOVS $temp1, $temp1, LSL #3 MOVNE $dest, $dest, LSR $temp1 RSBNE $temp1, $temp1, #32 ORRNE $dest, $dest, $temp2, LSL $temp1 MEND ; *********************************************************************** ; *** Lowercasing macro. Needs temp register; only lowercases A-Z ! *** ; *********************************************************************** MACRO $label LowerCase $reg, $wrk $label CMP $reg, #"A" RSBGES $wrk, $reg, #"Z" ; inverse compare ADDGE $reg, $reg, #"a"-"A" MEND MACRO $label LSL $reg, $val, $cc $label MOV$cc $reg, $reg, LSL #$val MEND MACRO $label LSR $reg, $val, $cc $label MOV$cc $reg, $reg, LSR #$val MEND MACRO $label MakeErrorBlock $name, $noalign ALIGN $label ErrorBlock_$name DCD ErrorNumber_$name DCB ErrorString_$name DCB 0 [ "$noalign" = "" ALIGN ] MEND ; **************************************** ; *** Macro MULTIPLY - rc := ra * rb *** ; *** NB. ra, rb corrupt *** ; **************************************** MACRO $label MULTIPLY $rc, $ra, $rb [ {FALSE} ; old boring one $label MOV $rc, #0 01 MOVS $ra, $ra, LSR #1 ADDCS $rc, $rc, $rb ADD $rb, $rb, $rb BNE %BT01 | $label MUL $rc, $rb, $ra ; sexy 2u version with regs in the right order ] MEND ; ******************************************************* ; *** Sweet FA macro to keep Tutu out of mischief ! *** ; ******************************************************* MACRO $label NOP $label MOVNV R0, R0 MEND MACRO $label Overlap $master, $slave [ "$label" = "" ^ :INDEX:$master, wp $slave # ?$master | ! 0, "You what?" ] MEND ; ********************************************************************** ; *** Disable IRQs, saving an old interrupt state indicator in R14 *** ; *** NB This macro preserves the C and V flags *** ; ********************************************************************** MACRO $lab PHPSEI $register [ "$register" = "" $lab MOV R14, #I_bit TST R14, PC ; is I_bit set ? TEQEQP R14, PC ; no, then set it (and R14 = I_bit) MOVNE R14, #0 ; yes, then leave alone (and R14=0) | $lab MOV $register, #I_bit TST $register, PC ; is I_bit set ? TEQEQP $register, PC ; no, then set it (and $reg. = I_bit) MOVNE $register, #0 ; yes, then leave alone (and R14=0) ] MEND ; ************************************************************************ ; *** Restore IRQ state from the indicator in R14 (set up by PHPSEI) *** ; *** NB This macro preserves the C and V flags *** ; ************************************************************************ MACRO $lab PLP $register [ "$register" = "" $lab TEQP R14, PC | $lab TEQP $register, PC ] MEND ; ***************************************** ; *** Pull registers given in reglist *** ; ***************************************** MACRO $label Pull $reglist, $cond, $hat $label LDM$cond.FD r13!, {$reglist}$hat MEND ; ***************************************** ; *** Push registers given in reglist *** ; ***************************************** MACRO $label Push $reglist, $cond $label STM$cond.FD r13!, {$reglist} MEND MACRO $label RETURN $cond $label MOV$cond pc, lr MEND MACRO $label RETURNS $cond $label MOV$cond.S pc, lr MEND MACRO $label ROR $reg, $val, $cc $label MOV$cc $reg, $reg, ROR #$val MEND ; ************************************************** ; *** Set and clear bits in PSR from the masks *** ; *** $set, $clr, using register $regtmp *** ; ************************************************** MACRO $label SCPSR $set, $clr, $regtmp, $cond $label MOV$cond $regtmp, pc ORR$cond $regtmp, $regtmp, #($set) :OR: ($clr) TEQ$cond.P $regtmp, #$clr MEND ; **************************************** ; *** Set carry flag - will set nzCv *** ; **************************************** MACRO $label SEC $cond $label CMP$cond pc, #0 MEND ; ************************************************************************ ; *** Set bits in PSR from the mask in $bits, using register $regtmp *** ; ************************************************************************ MACRO $label SETPSR $bits, $regtmp, $cond $label MOV$cond $regtmp, pc ORR$cond $regtmp, $regtmp, #$bits TEQ$cond.P $regtmp, #0 MEND ; ******************************************* ; *** Set overflow flag - will set NzcV *** ; ******************************************* MACRO $label SETV $cond $label CMP$cond pc, #&80000000 MEND MACRO $label STASH $reglist, $cond, $hat $label STM$cond.FD r13!, {$reglist}$hat MEND ; ******************************* ; *** String immediate out. *** ; ******************************* MACRO $label STRIM $string [ :LEN: "$string" = 1 $label SWI XOS_WriteI+"$string" | $label SWI XOS_WriteS DCB "$string", 0 ALIGN ] MEND ; ********************************************** ; *** Macro STROSB - Store Osbyte variable *** ; ********************************************** MACRO $label STROSB $reg, $var, $temp, $cond $label MOV$cond $temp, #0 STR$cond.B $reg, [$temp, #OsbyteVars+$var-OSBYTEFirstVar] MEND ; ***************************************** ; *** Macro Swap - Swap two registers *** ; ***************************************** MACRO $label Swap $ra, $rb, $cc $label EOR$cc $ra, $ra, $rb EOR$cc $rb, $ra, $rb EOR$cc $ra, $ra, $rb MEND ; *************************************************************************** ; *** Toggle bits in PSR from the mask in $bits, using register $regtmp *** ; *************************************************************************** MACRO $label TOGPSR $bits, $regtmp, $cond $label MOV$cond $regtmp, pc TEQ$cond.P $regtmp, #$bits MEND ; *********************************************************************** ; *** Uppercasing macro. Needs temp register; only uppercases a-z ! *** ; *********************************************************************** MACRO $label UpperCase $reg, $wrk $label CMP $reg, #"a" RSBGES $wrk, $reg, #"z" ; inverse compare SUBGE $reg, $reg, #"a"-"A" MEND ; ********************************************************** ; *** Macro VDWS - Point to our new VduDriverWorkSpace *** ; ********************************************************** MACRO VDWS $reg [ AssemblingArthur :LOR: Module MOV $reg, #VduDriverWorkSpace | ! 0, "This is a real waste if using Hdr.NewSpace" MOV $reg, #(VduDriverWorkSpace :AND: &FF000000) ORR $reg, $reg, #(VduDriverWorkSpace :AND: &00FF0000) ORR $reg, $reg, #(VduDriverWorkSpace :AND: &0000FFFF) ] MEND ; ******************************* ; *** Add word to workspace *** ; ******************************* MACRO $label Word $value, $count [ ( ( :INDEX: @ ) :AND: 3 ) <> 0 # 4 - ( ( :INDEX: @ ) :AND: 3 ) ] [ "$label" = "" [ "$count" = "" [ "$value" = "" | $value # 4 ] | $value # ($count) * 4 ] | [ "$value" = "" $label # 4 | $label # ($value) * 4 ] ] MEND ; ************************* ; *** WriteLn a string *** ; ************************* MACRO $label WRLN $string $label SWI XOS_WriteS DCB "$string", 10,13, 0 ALIGN MEND ; **************************************************************************** ; *** |#| - macro for allocating workspace downwards rather than upwards *** ; **************************************************************************** MACRO $var |#| $bytes [ "$bytes" = "" ! 1, "Syntax: [] |#| " MEXIT ] # -($bytes) [ "$var" <> "" $var # $bytes ; Declare correct size # -($bytes) ] MEND OPT OldOpt END