
 GET hdr.BuildOpts
; local labels use label$l to get a local label and LOCAL to start a new
; area

    GBLA    LocalCount
    GBLS    l
LocalCount  SETA 1
l   SETS    "x$LocalCount"

; increment local variable number

    MACRO
    _LOCAL
LocalCount  SETA LocalCount+1
l   SETS    "x$LocalCount"
    MEND

; modules definition

    MACRO
$la _MODNAME $name,$version,$date,$info,$copyright
    LCLS lname
    LCLS lvers
    LCLS ldate
    LCLS linfo
    LCLS lcopy
lname   SETS "$name"
lvers   SETS "$version"
ldate   SETS "$date"
linfo   SETS "$info"
lcopy   SETS "$copyright"
    ASSERT :LEN:lname > 0
    ASSERT :LEN:lvers = 3
    ASSERT :LEN:ldate = 11
RM_Version   * $version
RM_TitleStr  = lname,0
RM_HelpStr   = lname,9
             = lvers:LEFT:1,"."
             = lvers:RIGHT:2," ("
             = ldate,") "
  [ :LEN:linfo <> 0
             = linfo," "
  ]
  [ :LEN:lcopy <> 0
             = " ",lcopy
  ]
             = 0
    MEND

; processor mode changes

    GBLS    SVC_PCStatus

    MACRO
$la _TOSVC  $a,$b
    ASSERT  $a <> $b
SVC_PCStatus SETS "$a"
  [ Config_Target=32
$la MRS     $a,CPSR
    ORR     $b,$a,#3
    MSR     CPSR_cxsf,$b
  |
$la TEQ     PC,PC
    MRSEQ   $a,CPSR
    MOVNE   $a,PC
    ORR     $b,$a,#3
    MSREQ   CPSR_cxsf,$b
    TEQNEP  $b,#0
    NOP
  ]
    STR     R14,[R13,#-4]!
    MEND

    MACRO
$la _FROMSVC
    LDR     R14,[R13],#4
  [ Config_Target=32
    MSR     CPSR_cxsf,$SVC_PCStatus
  |
    TEQ     PC,PC
    MSREQ   CPSR_cxsf,$SVC_PCStatus
    TEQNEP  $SVC_PCStatus,#0
    NOP
  ]
    MEND

    MACRO
    _GENRETURNS
    GBLL    _Return_Status
    EXPORT  _Return_VS
    EXPORT  _Return_VC
    EXPORT  _Return_Flags

_Return_VS
  [ Config_Target=32
    MSR     CPSR_f,#Vbit
    MOV     PC,R14
  |
    TEQ     PC,PC
    MSREQ   CPSR_f,#Vbit+Zbit
    MOVEQ   PC,R14
    ORRS    PC,R14,#Vbit
  ]

_Return_VC
  [ Config_Target=32
    MSR     CPSR_f,#0
    MOV     PC,R14
  |
    TEQ     PC,PC
    MSREQ   CPSR_f,#Zbit
    MOVEQ   PC,R14
    BICS    PC,R14,#Vbit
    ]

_Return_Flags
  [ Config_Target=32
    MOV     PC,R14
  |
    TEQ     PC,PC
    MOVEQ   PC,R14
    MOVNES  PC,R14
  ]
    MEND

    MACRO
    _RETURNVS $cc
  [ :LNOT::DEF: _Return_Status
    IMPORT  _Return_VS
  ]
    B$cc    _Return_VS
    MEND

    MACRO
    _RETURNVC $cc
  [ :LNOT::DEF: _Return_Status
    IMPORT  _Return_VC
  ]
    B$cc    _Return_VC
    MEND

    MACRO
    _RETURNFlags $cc
  [ :LNOT::DEF: _Return_Status
    IMPORT  _Return_Flags
  ]
  [ Config_Target=32
    MOV$cc  PC,R14
  |
    B$cc    _Return_Flags
  ]
    MEND

; end of SWI table
    MACRO
$la _ERRSWI $e
    ADRL    R0,$e
    _RETURNVS
    MEND

; start of sub. If you specify a list of registers then these are stored as
; well and will be pulled on an RTS.

    GBLS    PROC_StackedRegs
    GBLS    PROC_ClearV
    GBLS    PROC_SaveFlags

; start of sub, as for C
    MACRO
$la _DEFPROCC $a
PROC_StackedRegs   SETS "$a"
PROC_ClearV        SETS "0"
  [ {CONFIG}=32
PROC_SaveFlags     SETS "0"
  |
PROC_SaveFlags     SETS "1"
  ]
    ALIGN
$la
  [ PROC_StackedRegs=""
    STR     R14,[R13,#-4]!
  |
    STMFD   R13!,{$PROC_StackedRegs,R14}
  ]
    MEND

; start of sub, remember to restore flags
    MACRO
$la _DEFPROCS $a
PROC_StackedRegs   SETS "$a"
PROC_ClearV        SETS "0"
PROC_SaveFlags     SETS "1"
    ALIGN
$la
  [ PROC_StackedRegs=""
    STR     R14,[R13,#-4]!
  |
    STMFD   R13!,{$PROC_StackedRegs,R14}
  ]

    MEND

; start of sub, remember to normally clear V on exit
    MACRO
$la _DEFPROCV $a
PROC_StackedRegs   SETS "$a"
PROC_ClearV        SETS "1"
PROC_SaveFlags     SETS "0"
    ALIGN
$la
  [ PROC_StackedRegs=""
    STR     R14,[R13,#-4]!
  |
    STMFD   R13!,{$PROC_StackedRegs,R14}
  ]
    MEND

; start of sub, no flags to restore, no V to clear
    MACRO
$la _DEFPROC $a
PROC_StackedRegs   SETS "$a"
PROC_ClearV        SETS "0"
PROC_SaveFlags     SETS "0"
    ALIGN
$la
  [ PROC_StackedRegs=""
    STR     R14,[R13,#-4]!
  |
    STMFD   R13!,{$PROC_StackedRegs,R14}
  ]
    MEND

; end of sub, clears V if required unless $cc is VS, restore flags if required

    MACRO
$la _ENDPROC $cc
    LCLS    ClearV
ClearV  SETS PROC_ClearV
  [ "$cc"="VS"
ClearV  SETS    "0"
  ]
$la
  [ ClearV="1"
    [ PROC_StackedRegs=""
    LDR$cc    R14,[R13],#4
    |
    LDM$cc.FD R13!,{$PROC_StackedRegs,R14}
    ]
    _RETURNVC $cc
  |
    [ PROC_SaveFlags="1"
      [ PROC_StackedRegs=""
    LDR$cc    R14,[R13],#4
      |
    LDM$cc.FD R13!,{$PROC_StackedRegs,R14}
      ]
    _RETURNFlags $cc
    |
      [ PROC_StackedRegs=""
    LDR$cc    PC,[R13],#4
      |
    LDM$cc.FD R13!,{$PROC_StackedRegs,PC}
      ]
    ]
  ]
    MEND

; end sub, return with current V setting

    MACRO
$la _RETURNV
    ASSERT  PROC_ClearV="1"
$la
  [ PROC_StackedRegs=""
    LDR     PC,[R13],#4
  |
    LDMFD   R13!,{$PROC_StackedRegs,PC}
  ]
    MEND

; end sub, clears V even if $cc is VS

    MACRO
$la _RETURNOK $cc
    ASSERT    PROC_ClearV="1"
$la
  [ PROC_StackedRegs=""
    LDR$cc    R14,[R13],#4
  |
    LDM$cc.FD R13!,{$PROC_StackedRegs,R14}
  ]
    _RETURNVC $cc
    MEND

; end sub with error and possibly setting of R0

    MACRO
$la _ERROR $cc,$e
    ASSERT    PROC_ClearV="1"
$la
  [ "$e"<>""
    ADR$cc.L R0,$e
  ]
  [ PROC_StackedRegs=""
    LDR$cc    R14,[R13],#4
  |
    LDM$cc.FD R13!,{$PROC_StackedRegs,R14}
  ]
    _RETURNVS $cc
    MEND

; long adds $a=$b+#$c fixed length, $c must be word aligned

    MACRO
$la _LADD $a,$b,$c
$la ADD    $a,$b,#($c:AND:&000003FF)
    ADD    $a,$a,#($c:AND:&FFFFFC00)
    MEND

; long adds $a=$b+#$c fixed length, $c must be word aligned

    MACRO
$la _LMOV $a,$c
$la MOV    $a,   #($c:AND:&000003FF)
    ADD    $a,$a,#($c:AND:&FFFFFC00)
    MEND

; Push a register list $a onto the stack

    MACRO
$la _PUSH $a,$cc
    LCLL    count
    LCLS    left
    LCLS    right
count    SETL    {FALSE}
right    SETS    "$a"
    WHILE    :LEN:right > 0
left     SETS    right:LEFT:1
right    SETS    right:RIGHT:(:LEN:right - 1)
  [ (left = "-") :LOR: (left = ",")
count    SETL    {TRUE}
  ]
    WEND
$la
  [ count
    STM$cc.FD R13!,{$a}
  |
    STR$cc    $a,[R13,#-4]!
  ]
    MEND

; Pull a register list $a from the stack

    MACRO
$la _PULL $a,$cc
    LCLL    count
    LCLS    left
    LCLS    right
count    SETL    {FALSE}
right    SETS    "$a"
    WHILE    :LEN:right > 0
left     SETS    right:LEFT:1
right    SETS    right:RIGHT:(:LEN:right - 1)
  [ (left = "-") :LOR: (left = ",")
count    SETL    {TRUE}
  ]
  WEND
$la
  [ count
    LDM$cc.FD R13!,{$a}
  |
    LDR$cc    $a,[R13],#4
  ]
    MEND

    MACRO
$la _FNAME
    _LOCAL
    ALIGN
fnam1$l
    DCB     "$la",0
    ALIGN
fnam2$l
    DCD    &FF000000 + (fnam2$l-fnam1$l)
    _LOCAL
$la
    MEND

; end of macros

    END
