blob: 321d2d310cba8b487ba9fe1d7262290296355b22 [file] [log] [blame]
;//
;// Copyright (C) 2007-2008 ARM Limited
;//
;// Licensed under the Apache License, Version 2.0 (the "License");
;// you may not use this file except in compliance with the License.
;// You may obtain a copy of the License at
;//
;// http://www.apache.org/licenses/LICENSE-2.0
;//
;// Unless required by applicable law or agreed to in writing, software
;// distributed under the License is distributed on an "AS IS" BASIS,
;// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;// See the License for the specific language governing permissions and
;// limitations under the License.
;//
;//
;//
;// File Name: armCOMM_s.h
;// OpenMAX DL: v1.0.2
;// Revision: 12290
;// Date: Wednesday, April 9, 2008
;//
;//
;//
;//
;// ARM optimized OpenMAX common header file
;//
;// Protect against multiple inclusion
IF :LNOT::DEF:ARMCOMM_S_H
GBLL ARMCOMM_S_H
REQUIRE8 ;// Requires 8-byte stack alignment
PRESERVE8 ;// Preserves 8-byte stack alignment
GBLL ARM_ERRORCHECK
ARM_ERRORCHECK SETL {FALSE}
;// Globals
GBLS _RRegList ;// R saved register list
GBLS _DRegList ;// D saved register list
GBLS _Variant ;// Selected processor variant
GBLS _CPU ;// CPU name
GBLS _Struct ;// Structure name
GBLL _InFunc ;// Inside function assembly flag
GBLL _SwLong ;// Long switch flag
GBLA _RBytes ;// Number of register bytes on stack
GBLA _SBytes ;// Number of scratch bytes on stack
GBLA _ABytes ;// Stack offset of next argument
GBLA _Workspace ;// Stack offset of scratch workspace
GBLA _F ;// Function number
GBLA _StOff ;// Struct offset
GBLA _SwNum ;// Switch number
GBLS _32 ;// Suffix for 32 byte alignmnet
GBLS _16 ;// Suffix for 16 byte alignmnet
_InFunc SETL {FALSE}
_SBytes SETA 0
_F SETA 0
_SwNum SETA 0
_32 SETS "ALIGN32"
_16 SETS "ALIGN16"
;/////////////////////////////////////////////////////////
;// Override the tools settings of the CPU if the #define
;// USECPU is set, otherwise use the CPU defined by the
;// assembler settings.
;/////////////////////////////////////////////////////////
IF :DEF: OVERRIDECPU
_CPU SETS OVERRIDECPU
ELSE
_CPU SETS {CPU}
ENDIF
;/////////////////////////////////////////////////////////
;// Work out which code to build
;/////////////////////////////////////////////////////////
IF :DEF:ARM1136JS:LOR::DEF:CortexA8:LOR::DEF:ARM_GENERIC
INFO 1,"Please switch to using M_VARIANTS"
ENDIF
;// Define and reset all officially recongnised variants
MACRO
_M_DEF_VARIANTS
_M_DEF_VARIANT ARM926EJS
_M_DEF_VARIANT ARM1136JS
_M_DEF_VARIANT ARM1136JS_U
_M_DEF_VARIANT CortexA8
_M_DEF_VARIANT ARM7TDMI
MEND
MACRO
_M_DEF_VARIANT $var
GBLL $var
GBLL _ok$var
$var SETL {FALSE}
MEND
;// Variant declaration
;//
;// Define a list of code variants supported by this
;// source file. This macro then chooses the most
;// appropriate variant to build for the currently configured
;// core.
;//
MACRO
M_VARIANTS $v0,$v1,$v2,$v3,$v4,$v5,$v6,$v7
;// Set to TRUE variants that are supported
_M_DEF_VARIANTS
_M_VARIANT $v0
_M_VARIANT $v1
_M_VARIANT $v2
_M_VARIANT $v3
_M_VARIANT $v4
_M_VARIANT $v5
_M_VARIANT $v6
_M_VARIANT $v7
;// Look for first available variant to match a CPU
;// _M_TRY cpu, variant fall back list
_Variant SETS ""
_M_TRY ARM926EJ-S, ARM926EJS
_M_TRY ARM1176JZ-S, ARM1136JS
_M_TRY ARM1176JZF-S, ARM1136JS
_M_TRY ARM1156T2-S, ARM1136JS
_M_TRY ARM1156T2F-S, ARM1136JS
_M_TRY ARM1136J-S, ARM1136JS
_M_TRY ARM1136JF-S, ARM1136JS
_M_TRY MPCore, ARM1136JS
_M_TRY falcon-vfp, ARM1136JS
_M_TRY falcon-full-neon, CortexA8
_M_TRY Cortex-A8NoNeon, ARM1136JS
_M_TRY Cortex-A8, CortexA8, ARM1136JS
_M_TRY Cortex-R4, ARM1136JS
_M_TRY ARM7TDMI
;// Select the correct variant
_M_DEF_VARIANTS
IF _Variant=""
INFO 1, "No match found for CPU '$_CPU'"
ELSE
$_Variant SETL {TRUE}
ENDIF
MEND
;// Register a variant as available
MACRO
_M_VARIANT $var
IF "$var"=""
MEXIT
ENDIF
IF :LNOT::DEF:_ok$var
INFO 1, "Unrecognized variant '$var'"
ENDIF
$var SETL {TRUE}
MEND
;// For a given CPU, see if any of the variants supporting
;// this CPU are available. The first available variant is
;// chosen
MACRO
_M_TRY $cpu, $v0,$v1,$v2,$v3,$v4,$v5,$v6,$v7
IF "$cpu"<>_CPU
MEXIT
ENDIF
_M_TRY1 $v0
_M_TRY1 $v1
_M_TRY1 $v2
_M_TRY1 $v3
_M_TRY1 $v4
_M_TRY1 $v5
_M_TRY1 $v6
_M_TRY1 $v7
;// Check a match was found
IF _Variant=""
INFO 1, "No variant match found for CPU '$_CPU'"
ENDIF
MEND
MACRO
_M_TRY1 $var
IF "$var"=""
MEXIT
ENDIF
IF (_Variant=""):LAND:$var
_Variant SETS "$var"
ENDIF
MEND
;////////////////////////////////////////////////////////
;// Structure definition
;////////////////////////////////////////////////////////
;// Declare a structure of given name
MACRO
M_STRUCT $sname
_Struct SETS "$sname"
_StOff SETA 0
MEND
;// Declare a structure field
;// The field is called $sname_$fname
;// $size = the size of each entry, must be power of 2
;// $number = (if provided) the number of entries for an array
MACRO
M_FIELD $fname, $size, $number
IF (_StOff:AND:($size-1))!=0
_StOff SETA _StOff + ($size - (_StOff:AND:($size-1)))
ENDIF
$_Struct._$fname EQU _StOff
IF "$number"<>""
_StOff SETA _StOff + $size*$number
ELSE
_StOff SETA _StOff + $size
ENDIF
MEND
MACRO
M_ENDSTRUCT
sizeof_$_Struct EQU _StOff
_Struct SETS ""
MEND
;//////////////////////////////////////////////////////////
;// Switch and table macros
;//////////////////////////////////////////////////////////
;// Start a relative switch table with register to switch on
;//
;// $v = the register to switch on
;// $s = if specified must be "L" to indicate long
;// this allows a greater range to the case code
MACRO
M_SWITCH $v, $s
ASSERT "$s"="":LOR:"$s"="L"
_SwLong SETL {FALSE}
IF "$s"="L"
_SwLong SETL {TRUE}
ENDIF
_SwNum SETA _SwNum+1
IF {CONFIG}=16
;// Thumb
IF _SwLong
TBH [pc, $v, LSL#1]
ELSE
TBB [pc, $v]
ENDIF
_Switch$_SwNum
ELSE
;// ARM
ADD pc, pc, $v, LSL #2
NOP
ENDIF
MEND
;// Add a case to the switch statement
MACRO
M_CASE $label
IF {CONFIG}=16
;// Thumb
IF _SwLong
DCW ($label - _Switch$_SwNum)/2
ELSE
DCB ($label - _Switch$_SwNum)/2
ENDIF
ELSE
;// ARM
B $label
ENDIF
MEND
;// End of switch statement
MACRO
M_ENDSWITCH
ALIGN 2
MEND
;////////////////////////////////////////////////////////
;// Data area allocation
;////////////////////////////////////////////////////////
;// Constant table allocator macro
;//
;// Creates a new section for each constant table
;// $name is symbol through which the table can be accessed.
;// $align is the optional alignment of the table, log2 of
;// the byte alignment - $align=4 is 16 byte aligned
MACRO
M_TABLE $name, $align
ASSERT :LNOT:_InFunc
IF "$align"=""
AREA |.constdata|, READONLY, DATA
ELSE
;// AREAs inherit the alignment of the first declaration.
;// Therefore for each alignment size we must have an area
;// of a different name.
AREA constdata_a$align, READONLY, DATA, ALIGN=$align
;// We also force alignment incase we are tagging onto
;// an already started area.
ALIGN (1<<$align)
ENDIF
$name
MEND
;/////////////////////////////////////////////////////
;// Macros to allocate space on the stack
;//
;// These all assume that the stack is 8-byte aligned
;// at entry to the function, which means that the
;// 32-byte alignment macro needs to work in a
;// bit more of a special way...
;/////////////////////////////////////////////////////
;// Allocate 1-byte aligned area of name
;// $name size $size bytes.
MACRO
M_ALLOC1 $name, $size
ASSERT :LNOT:_InFunc
$name$_F EQU _SBytes
_SBytes SETA _SBytes + ($size)
MEND
;// Allocate 2-byte aligned area of name
;// $name size $size bytes.
MACRO
M_ALLOC2 $name, $size
ASSERT :LNOT:_InFunc
IF (_SBytes:AND:1)!=0
_SBytes SETA _SBytes + (2 - (_SBytes:AND:1))
ENDIF
$name$_F EQU _SBytes
_SBytes SETA _SBytes + ($size)
MEND
;// Allocate 4-byte aligned area of name
;// $name size $size bytes.
MACRO
M_ALLOC4 $name, $size
ASSERT :LNOT:_InFunc
IF (_SBytes:AND:3)!=0
_SBytes SETA _SBytes + (4 - (_SBytes:AND:3))
ENDIF
$name$_F EQU _SBytes
_SBytes SETA _SBytes + ($size)
MEND
;// Allocate 8-byte aligned area of name
;// $name size $size bytes.
MACRO
M_ALLOC8 $name, $size
ASSERT :LNOT:_InFunc
IF (_SBytes:AND:7)!=0
_SBytes SETA _SBytes + (8 - (_SBytes:AND:7))
ENDIF
$name$_F EQU _SBytes
_SBytes SETA _SBytes + ($size)
MEND
;// Allocate 8-byte aligned area of name
;// $name size ($size+16) bytes.
;// The extra 16 bytes are later used to align the pointer to 16 bytes
MACRO
M_ALLOC16 $name, $size
ASSERT :LNOT:_InFunc
IF (_SBytes:AND:7)!=0
_SBytes SETA _SBytes + (8 - (_SBytes:AND:7))
ENDIF
$name$_F$_16 EQU (_SBytes + 8)
_SBytes SETA _SBytes + ($size) + 8
MEND
;// Allocate 8-byte aligned area of name
;// $name size ($size+32) bytes.
;// The extra 32 bytes are later used to align the pointer to 32 bytes
MACRO
M_ALLOC32 $name, $size
ASSERT :LNOT:_InFunc
IF (_SBytes:AND:7)!=0
_SBytes SETA _SBytes + (8 - (_SBytes:AND:7))
ENDIF
$name$_F$_32 EQU (_SBytes + 24)
_SBytes SETA _SBytes + ($size) + 24
MEND
;// Argument Declaration Macro
;//
;// Allocate an argument name $name
;// size $size bytes
MACRO
M_ARG $name, $size
ASSERT _InFunc
$name$_F EQU _ABytes
_ABytes SETA _ABytes + ($size)
MEND
;///////////////////////////////////////////////
;// Macros to access stacked variables
;///////////////////////////////////////////////
;// Macro to perform a data processing operation
;// with a constant second operand
MACRO
_M_OPC $op,$rd,$rn,$const
LCLA _sh
LCLA _cst
_sh SETA 0
_cst SETA $const
IF _cst=0
$op $rd, $rn, #_cst
MEXIT
ENDIF
WHILE (_cst:AND:3)=0
_cst SETA _cst>>2
_sh SETA _sh+2
WEND
$op $rd, $rn, #(_cst:AND:0x000000FF)<<_sh
IF _cst>=256
$op $rd, $rd, #(_cst:AND:0xFFFFFF00)<<_sh
ENDIF
MEND
;// Macro to perform a data access operation
;// Such as LDR or STR
;// The addressing mode is modified such that
;// 1. If no address is given then the name is taken
;// as a stack offset
;// 2. If the addressing mode is not available for the
;// state being assembled for (eg Thumb) then a suitable
;// addressing mode is substituted.
;//
;// On Entry:
;// $i = Instruction to perform (eg "LDRB")
;// $a = Required byte alignment
;// $r = Register(s) to transfer (eg "r1")
;// $a0,$a1,$a2. Addressing mode and condition. One of:
;// label {,cc}
;// [base] {,,,cc}
;// [base, offset]{!} {,,cc}
;// [base, offset, shift]{!} {,cc}
;// [base], offset {,,cc}
;// [base], offset, shift {,cc}
MACRO
_M_DATA $i,$a,$r,$a0,$a1,$a2,$a3
IF "$a0":LEFT:1="["
IF "$a1"=""
$i$a3 $r, $a0
ELSE
IF "$a0":RIGHT:1="]"
IF "$a2"=""
_M_POSTIND $i$a3, "$r", $a0, $a1
ELSE
_M_POSTIND $i$a3, "$r", $a0, "$a1,$a2"
ENDIF
ELSE
IF "$a2"=""
_M_PREIND $i$a3, "$r", $a0, $a1
ELSE
_M_PREIND $i$a3, "$r", $a0, "$a1,$a2"
ENDIF
ENDIF
ENDIF
ELSE
LCLA _Offset
_Offset SETA _Workspace + $a0$_F
ASSERT (_Offset:AND:($a-1))=0
$i$a1 $r, [sp, #_Offset]
ENDIF
MEND
;// Handle post indexed load/stores
;// op reg, [base], offset
MACRO
_M_POSTIND $i,$r,$a0,$a1
LCLS _base
LCLS _offset
IF {CONFIG}=16 ;// Thumb
_base SETS ("$a0":LEFT:(:LEN:"$a0"-1)):RIGHT:(:LEN:"$a0"-2) ;// remove []
_offset SETS "$a1"
IF _offset:LEFT:1="+"
_offset SETS _offset:RIGHT:(:LEN:_offset-1)
ENDIF
$i $r, $a0
IF _offset:LEFT:1="-"
_offset SETS _offset:RIGHT:(:LEN:_offset-1)
SUB $_base, $_base, $_offset
ELSE
ADD $_base, $_base, $_offset
ENDIF
ELSE ;// ARM
$i $r, $a0, $a1
ENDIF
MEND
;// Handle pre indexed load/store
;// op reg, [base, offset]{!}
MACRO
_M_PREIND $i,$r,$a0,$a1
LCLS _base
LCLS _offset
IF ({CONFIG}=16):LAND:(("$a1":RIGHT:2)="]!")
_base SETS "$a0":RIGHT:(:LEN:("$a0")-1)
_offset SETS "$a1":LEFT:(:LEN:("$a1")-2)
$i $r, [$_base, $_offset]
ADD $_base, $_base, $_offset
ELSE
$i $r, $a0, $a1
ENDIF
MEND
;// Load unsigned byte from stack
MACRO
M_LDRB $r,$a0,$a1,$a2,$a3
_M_DATA "LDRB",1,$r,$a0,$a1,$a2,$a3
MEND
;// Load signed byte from stack
MACRO
M_LDRSB $r,$a0,$a1,$a2,$a3
_M_DATA "LDRSB",1,$r,$a0,$a1,$a2,$a3
MEND
;// Store byte to stack
MACRO
M_STRB $r,$a0,$a1,$a2,$a3
_M_DATA "STRB",1,$r,$a0,$a1,$a2,$a3
MEND
;// Load unsigned half word from stack
MACRO
M_LDRH $r,$a0,$a1,$a2,$a3
_M_DATA "LDRH",2,$r,$a0,$a1,$a2,$a3
MEND
;// Load signed half word from stack
MACRO
M_LDRSH $r,$a0,$a1,$a2,$a3
_M_DATA "LDRSH",2,$r,$a0,$a1,$a2,$a3
MEND
;// Store half word to stack
MACRO
M_STRH $r,$a0,$a1,$a2,$a3
_M_DATA "STRH",2,$r,$a0,$a1,$a2,$a3
MEND
;// Load word from stack
MACRO
M_LDR $r,$a0,$a1,$a2,$a3
_M_DATA "LDR",4,$r,$a0,$a1,$a2,$a3
MEND
;// Store word to stack
MACRO
M_STR $r,$a0,$a1,$a2,$a3
_M_DATA "STR",4,$r,$a0,$a1,$a2,$a3
MEND
;// Load double word from stack
MACRO
M_LDRD $r0,$r1,$a0,$a1,$a2,$a3
_M_DATA "LDRD",8,"$r0,$r1",$a0,$a1,$a2,$a3
MEND
;// Store double word to stack
MACRO
M_STRD $r0,$r1,$a0,$a1,$a2,$a3
_M_DATA "STRD",8,"$r0,$r1",$a0,$a1,$a2,$a3
MEND
;// Get absolute address of stack allocated location
MACRO
M_ADR $a, $b, $cc
_M_OPC ADD$cc, $a, sp, (_Workspace + $b$_F)
MEND
;// Get absolute address of stack allocated location and align the address to 16 bytes
MACRO
M_ADR16 $a, $b, $cc
_M_OPC ADD$cc, $a, sp, (_Workspace + $b$_F$_16)
;// Now align $a to 16 bytes
BIC$cc $a,$a,#0x0F
MEND
;// Get absolute address of stack allocated location and align the address to 32 bytes
MACRO
M_ADR32 $a, $b, $cc
_M_OPC ADD$cc, $a, sp, (_Workspace + $b$_F$_32)
;// Now align $a to 32 bytes
BIC$cc $a,$a,#0x1F
MEND
;//////////////////////////////////////////////////////////
;// Function header and footer macros
;//////////////////////////////////////////////////////////
;// Function Header Macro
;// Generates the function prologue
;// Note that functions should all be "stack-moves-once"
;// The FNSTART and FNEND macros should be the only places
;// where the stack moves.
;//
;// $name = function name
;// $rreg = "" don't stack any registers
;// "lr" stack "lr" only
;// "rN" stack registers "r4-rN,lr"
;// $dreg = "" don't stack any D registers
;// "dN" stack registers "d8-dN"
;//
;// Note: ARM Archicture procedure call standard AAPCS
;// states that r4-r11, sp, d8-d15 must be preserved by
;// a compliant function.
MACRO
M_START $name, $rreg, $dreg
ASSERT :LNOT:_InFunc
ASSERT "$name"!=""
_InFunc SETL {TRUE}
_RBytes SETA 0
_Workspace SETA 0
;// Create an area for the function
AREA |.text|, CODE
EXPORT $name
$name FUNCTION
;// Save R registers
_M_GETRREGLIST $rreg
IF _RRegList<>""
STMFD sp!, {$_RRegList, lr}
ENDIF
;// Save D registers
_M_GETDREGLIST $dreg
IF _DRegList<>""
VSTMFD sp!, {$_DRegList}
ENDIF
;// Ensure size claimed on stack is 8-byte aligned
IF ((_SBytes:AND:7)!=0)
_SBytes SETA _SBytes + (8 - (_SBytes:AND:7))
ENDIF
IF (_SBytes!=0)
_M_OPC SUB, sp, sp, _SBytes
ENDIF
_ABytes SETA _SBytes + _RBytes - _Workspace
;// Print function name if debug enabled
M_PRINTF "$name\n",
MEND
;// Work out a list of R saved registers
MACRO
_M_GETRREGLIST $rreg
IF "$rreg"=""
_RRegList SETS ""
MEXIT
ENDIF
IF "$rreg"="lr":LOR:"$rreg"="r4"
_RRegList SETS "r4"
_RBytes SETA _RBytes+8
MEXIT
ENDIF
IF "$rreg"="r5":LOR:"$rreg"="r6"
_RRegList SETS "r4-r6"
_RBytes SETA _RBytes+16
MEXIT
ENDIF
IF "$rreg"="r7":LOR:"$rreg"="r8"
_RRegList SETS "r4-r8"
_RBytes SETA _RBytes+24
MEXIT
ENDIF
IF "$rreg"="r9":LOR:"$rreg"="r10"
_RRegList SETS "r4-r10"
_RBytes SETA _RBytes+32
MEXIT
ENDIF
IF "$rreg"="r11":LOR:"$rreg"="r12"
_RRegList SETS "r4-r12"
_RBytes SETA _RBytes+40
MEXIT
ENDIF
INFO 1, "Unrecognized saved r register limit '$rreg'"
MEND
;// Work out a list of D saved registers
MACRO
_M_GETDREGLIST $dreg
IF "$dreg"=""
_DRegList SETS ""
MEXIT
ENDIF
IF "$dreg"="d8"
_DRegList SETS "d8"
_RBytes SETA _RBytes+8
MEXIT
ENDIF
IF "$dreg"="d9"
_DRegList SETS "d8-d9"
_RBytes SETA _RBytes+16
MEXIT
ENDIF
IF "$dreg"="d10"
_DRegList SETS "d8-d10"
_RBytes SETA _RBytes+24
MEXIT
ENDIF
IF "$dreg"="d11"
_DRegList SETS "d8-d11"
_RBytes SETA _RBytes+32
MEXIT
ENDIF
IF "$dreg"="d12"
_DRegList SETS "d8-d12"
_RBytes SETA _RBytes+40
MEXIT
ENDIF
IF "$dreg"="d13"
_DRegList SETS "d8-d13"
_RBytes SETA _RBytes+48
MEXIT
ENDIF
IF "$dreg"="d14"
_DRegList SETS "d8-d14"
_RBytes SETA _RBytes+56
MEXIT
ENDIF
IF "$dreg"="d15"
_DRegList SETS "d8-d15"
_RBytes SETA _RBytes+64
MEXIT
ENDIF
INFO 1, "Unrecognized saved d register limit '$dreg'"
MEND
;// Produce function return instructions
MACRO
_M_RET $cc
IF _DRegList<>""
VPOP$cc {$_DRegList}
ENDIF
IF _RRegList=""
BX$cc lr
ELSE
LDM$cc.FD sp!, {$_RRegList, pc}
ENDIF
MEND
;// Early Function Exit Macro
;// $cc = condition to exit with
;// (Example: M_EXIT EQ)
MACRO
M_EXIT $cc
ASSERT _InFunc
IF _SBytes!=0
;// Restore stack frame and exit
B$cc _End$_F
ELSE
;// Can return directly
_M_RET $cc
ENDIF
MEND
;// Function Footer Macro
;// Generates the function epilogue
MACRO
M_END
ASSERT _InFunc
_InFunc SETL {FALSE}
_End$_F
;// Restore the stack pointer to its original value on function entry
IF _SBytes!=0
_M_OPC ADD, sp, sp, _SBytes
ENDIF
_M_RET
ENDFUNC
;// Reset the global stack tracking variables back to their
;// initial values, and increment the function count
_SBytes SETA 0
_F SETA _F+1
MEND
;//==========================================================================
;// Debug Macros
;//==========================================================================
GBLL DEBUG_ON
DEBUG_ON SETL {FALSE}
GBLL DEBUG_STALLS_ON
DEBUG_STALLS_ON SETL {FALSE}
;//==========================================================================
;// Debug call to printf
;// M_PRINTF $format, $val0, $val1, $val2
;//
;// Examples:
;// M_PRINTF "x=%08x\n", r0
;//
;// This macro preserves the value of all registers including the
;// flags.
;//==========================================================================
MACRO
M_PRINTF $format, $val0, $val1, $val2
IF DEBUG_ON
IMPORT printf
LCLA nArgs
nArgs SETA 0
;// save registers so we don't corrupt them
STMFD sp!, {r0-r12, lr}
;// Drop stack to give us some workspace
SUB sp, sp, #16
;// Save registers we need to print to the stack
IF "$val2" <> ""
ASSERT "$val1" <> ""
STR $val2, [sp, #8]
nArgs SETA nArgs+1
ENDIF
IF "$val1" <> ""
ASSERT "$val0" <> ""
STR $val1, [sp, #4]
nArgs SETA nArgs+1
ENDIF
IF "$val0"<>""
STR $val0, [sp]
nArgs SETA nArgs+1
ENDIF
;// Now we are safe to corrupt registers
ADR r0, %FT00
IF nArgs=1
LDR r1, [sp]
ENDIF
IF nArgs=2
LDMIA sp, {r1,r2}
ENDIF
IF nArgs=3
LDMIA sp, {r1,r2,r3}
ENDIF
;// print the values
MRS r4, cpsr ;// preserve flags
BL printf
MSR cpsr_f, r4 ;// restore flags
B %FT01
00 ;// string to print
DCB "$format", 0
ALIGN
01 ;// Finished
ADD sp, sp, #16
;// Restore registers
LDMFD sp!, {r0-r12,lr}
ENDIF ;// DEBUG_ON
MEND
;// Stall Simulation Macro
;// Inserts a given number of NOPs for the currently
;// defined platform
MACRO
M_STALL $plat1stall, $plat2stall, $plat3stall, $plat4stall, $plat5stall, $plat6stall
IF DEBUG_STALLS_ON
_M_STALL_SUB $plat1stall
_M_STALL_SUB $plat2stall
_M_STALL_SUB $plat3stall
_M_STALL_SUB $plat4stall
_M_STALL_SUB $plat5stall
_M_STALL_SUB $plat6stall
ENDIF
MEND
MACRO
_M_STALL_SUB $platstall
IF "$platstall"!=""
LCLA _pllen
LCLS _pl
LCLL _pllog
_pllen SETA :LEN:"$platstall"
_pl SETS "$platstall":LEFT:(_pllen - 2)
IF :DEF:$_pl
IF $_pl
LCLS _st
LCLA _stnum
_st SETS "$platstall":RIGHT:1
_stnum SETA $_st
WHILE _stnum>0
MOV sp, sp
_stnum SETA _stnum - 1
WEND
ENDIF
ENDIF
ENDIF
MEND
;//==========================================================================
;// Endian Invarience Macros
;//
;// The idea behind these macros is that if an array is
;// loaded as words then the SMUL00 macro will multiply
;// array elements 0 regardless of the endianess of the
;// system. For little endian SMUL00=SMULBB, for big
;// endian SMUL00=SMULTT and similarly for other packed operations.
;//
;//==========================================================================
MACRO
LIBI4 $comli, $combi, $a, $b, $c, $d, $cc
IF {ENDIAN}="big"
$combi.$cc $a, $b, $c, $d
ELSE
$comli.$cc $a, $b, $c, $d
ENDIF
MEND
MACRO
LIBI3 $comli, $combi, $a, $b, $c, $cc
IF {ENDIAN}="big"
$combi.$cc $a, $b, $c
ELSE
$comli.$cc $a, $b, $c
ENDIF
MEND
;// SMLAxy macros
MACRO
SMLA00 $a, $b, $c, $d, $cc
LIBI4 SMLABB, SMLATT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLA01 $a, $b, $c, $d, $cc
LIBI4 SMLABT, SMLATB, $a, $b, $c, $d, $cc
MEND
MACRO
SMLA0B $a, $b, $c, $d, $cc
LIBI4 SMLABB, SMLATB, $a, $b, $c, $d, $cc
MEND
MACRO
SMLA0T $a, $b, $c, $d, $cc
LIBI4 SMLABT, SMLATT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLA10 $a, $b, $c, $d, $cc
LIBI4 SMLATB, SMLABT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLA11 $a, $b, $c, $d, $cc
LIBI4 SMLATT, SMLABB, $a, $b, $c, $d, $cc
MEND
MACRO
SMLA1B $a, $b, $c, $d, $cc
LIBI4 SMLATB, SMLABB, $a, $b, $c, $d, $cc
MEND
MACRO
SMLA1T $a, $b, $c, $d, $cc
LIBI4 SMLATT, SMLABT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLAB0 $a, $b, $c, $d, $cc
LIBI4 SMLABB, SMLABT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLAB1 $a, $b, $c, $d, $cc
LIBI4 SMLABT, SMLABB, $a, $b, $c, $d, $cc
MEND
MACRO
SMLAT0 $a, $b, $c, $d, $cc
LIBI4 SMLATB, SMLATT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLAT1 $a, $b, $c, $d, $cc
LIBI4 SMLATT, SMLATB, $a, $b, $c, $d, $cc
MEND
;// SMULxy macros
MACRO
SMUL00 $a, $b, $c, $cc
LIBI3 SMULBB, SMULTT, $a, $b, $c, $cc
MEND
MACRO
SMUL01 $a, $b, $c, $cc
LIBI3 SMULBT, SMULTB, $a, $b, $c, $cc
MEND
MACRO
SMUL0B $a, $b, $c, $cc
LIBI3 SMULBB, SMULTB, $a, $b, $c, $cc
MEND
MACRO
SMUL0T $a, $b, $c, $cc
LIBI3 SMULBT, SMULTT, $a, $b, $c, $cc
MEND
MACRO
SMUL10 $a, $b, $c, $cc
LIBI3 SMULTB, SMULBT, $a, $b, $c, $cc
MEND
MACRO
SMUL11 $a, $b, $c, $cc
LIBI3 SMULTT, SMULBB, $a, $b, $c, $cc
MEND
MACRO
SMUL1B $a, $b, $c, $cc
LIBI3 SMULTB, SMULBB, $a, $b, $c, $cc
MEND
MACRO
SMUL1T $a, $b, $c, $cc
LIBI3 SMULTT, SMULBT, $a, $b, $c, $cc
MEND
MACRO
SMULB0 $a, $b, $c, $cc
LIBI3 SMULBB, SMULBT, $a, $b, $c, $cc
MEND
MACRO
SMULB1 $a, $b, $c, $cc
LIBI3 SMULBT, SMULBB, $a, $b, $c, $cc
MEND
MACRO
SMULT0 $a, $b, $c, $cc
LIBI3 SMULTB, SMULTT, $a, $b, $c, $cc
MEND
MACRO
SMULT1 $a, $b, $c, $cc
LIBI3 SMULTT, SMULTB, $a, $b, $c, $cc
MEND
;// SMLAWx, SMULWx macros
MACRO
SMLAW0 $a, $b, $c, $d, $cc
LIBI4 SMLAWB, SMLAWT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLAW1 $a, $b, $c, $d, $cc
LIBI4 SMLAWT, SMLAWB, $a, $b, $c, $d, $cc
MEND
MACRO
SMULW0 $a, $b, $c, $cc
LIBI3 SMULWB, SMULWT, $a, $b, $c, $cc
MEND
MACRO
SMULW1 $a, $b, $c, $cc
LIBI3 SMULWT, SMULWB, $a, $b, $c, $cc
MEND
;// SMLALxy macros
MACRO
SMLAL00 $a, $b, $c, $d, $cc
LIBI4 SMLALBB, SMLALTT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLAL01 $a, $b, $c, $d, $cc
LIBI4 SMLALBT, SMLALTB, $a, $b, $c, $d, $cc
MEND
MACRO
SMLAL0B $a, $b, $c, $d, $cc
LIBI4 SMLALBB, SMLALTB, $a, $b, $c, $d, $cc
MEND
MACRO
SMLAL0T $a, $b, $c, $d, $cc
LIBI4 SMLALBT, SMLALTT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLAL10 $a, $b, $c, $d, $cc
LIBI4 SMLALTB, SMLALBT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLAL11 $a, $b, $c, $d, $cc
LIBI4 SMLALTT, SMLALBB, $a, $b, $c, $d, $cc
MEND
MACRO
SMLAL1B $a, $b, $c, $d, $cc
LIBI4 SMLALTB, SMLALBB, $a, $b, $c, $d, $cc
MEND
MACRO
SMLAL1T $a, $b, $c, $d, $cc
LIBI4 SMLALTT, SMLALBT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLALB0 $a, $b, $c, $d, $cc
LIBI4 SMLALBB, SMLALBT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLALB1 $a, $b, $c, $d, $cc
LIBI4 SMLALBT, SMLALBB, $a, $b, $c, $d, $cc
MEND
MACRO
SMLALT0 $a, $b, $c, $d, $cc
LIBI4 SMLALTB, SMLALTT, $a, $b, $c, $d, $cc
MEND
MACRO
SMLALT1 $a, $b, $c, $d, $cc
LIBI4 SMLALTT, SMLALTB, $a, $b, $c, $d, $cc
MEND
ENDIF ;// ARMCOMM_S_H
END