home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Kosovo Orphans' Appeal Charity CD
/
KosovoOrphansAppeal.iso
/
archimedesworld_cd2
/
acornanswers
/
aanswers
/
s
/
macros1
next >
Wrap
Text File
|
1996-01-31
|
9KB
|
290 lines
; rbbc
; Reverse Bit Binary Counter.
; A macro to increment a register according to a reverse bit binary count.
; It takes four parameters, each of which should be a register name.
;
; $r: holds value to be rbbc incremented. Will be modified
; $k: k is st k-1=bit # (1 to 31) of msb in register (lsb in rbbc) (thence old w=3*(32-k)).
; $e: scratch register used to hold an address in the code
;
MACRO
$label rbbc $r, $k, $e
ASSERT $r <> $k
ASSERT $r <> $e
ASSERT $k <> $e
LCLA counter
counter SETA 31
$label RSB $k, $k, #32
RSB $k, $k, $k, ASL #2
ADD $e, pc, $k, ASL #2 ;this relys on there being exactly one instruction between here & TST
MOV pc, $e
WHILE counter > 1
TST $r, #1<<counter
EOR $r, $r, #1<<counter
BEQ %ft0
counter SETA counter-1
WEND
TST $r, #1<<1
EOR $r, $r, #1<<1
EORNE $r, $r, #1<<0 ;nb an rbbc carry will automatically cause a wrap around back to zero
0
MEND
; div16
; assumes abs number < 65536 * abs divisor.
; calculates integer part of 65536*number/divisor, as a signed 32 bit number.
; used in matrix inversion routine where it is necessary to divide two fixed point numbers (16 bit fraction).
; if range check on above assumption is required, the caller must perform it.
; It takes 5 parameters - all register names.
;
; $number: number
; $divisor: divisor - sign of divisor may be corrupted
; $num: scratch & result - may be the same as $number
; $sign: scratch
; $rem: scratch
;
MACRO
$label div16 $number, $divisor, $num, $sign, $rem
ASSERT $num <> $divisor
ASSERT $num <> $sign
ASSERT $num <> $rem
ASSERT $number <> $divisor
ASSERT $number <> $sign
ASSERT $number <> $rem
ASSERT $divisor <> $sign
ASSERT $divisor <> $rem
ASSERT $sign <> $rem
LCLA counter
counter SETA 32
$label MOVS $rem, $divisor, LSL #1
RSBCS $divisor, $divisor, #0
ADC $sign, $sign, $sign ;1st 3 instructions allow setting of low bit sign as either 0
;or 1 according to sign of divisor, in only 1 instruction.
TEQ $number, #0
RSBMI $num, $number, #0
[ $num <> $number
MOVPL $num, $number ;only assemble this case if regs different, as is otherwise a nop.
]
EORMI $sign, $sign, #1
MOV $rem, $num, LSR #16
MOV $num, $num, LSL #16
WHILE counter > 0 ;unwound loop uses about 600 bytes extra memory
MOVS $num, $num, ASL #1 ;speed increase (ARM3) from about 1.27e-5 to .75e-5 seconds
ADC $rem, $rem, $rem
CMP $rem, $divisor
SUBHS $rem, $rem, $divisor
ORRHS $num, $num, #1
counter SETA counter-1
WEND
CMP $rem, $divisor, ASR #1
ADDGE $num, $num, #1
TST $sign, #1
RSBNE $num, $num, #0
MEND
; mul16
; multiplication of an integer x by a 16-bit fixed point number a, with no restrictions on x or a
; other than that x*a/65536 must fit into a signed 32-bit representation.
; calculates r=x*a/65536
; It takes 6 parameters - all register names.
;
; $x: x
; $a: a - a will be corrupted
; $r: result - may be the same as $x
; $u: scratch
; $v: scratch
; $w: scratch
;
MACRO
$label mul16 $x, $a, $r, $u, $v, $w
ASSERT $r <> $a
ASSERT $r <> $u
ASSERT $r <> $v
ASSERT $r <> $w
ASSERT $x <> $a
ASSERT $x <> $u
ASSERT $x <> $v
ASSERT $x <> $w
ASSERT $a <> $u
ASSERT $a <> $v
ASSERT $a <> $w
ASSERT $u <> $v
ASSERT $u <> $w
ASSERT $v <> $w
$label MOVS $w, $a, LSL #1
RSBCS $a, $a, #0
TEQ $x, #0
RSBMI $r, $x, #0
[ $r <> $x
MOVPL $r, $x
] ;now have C bit set iff a<0, N bit set iff x<0
MOV $w, pc, LSR #31
MOV $w, $w, LSL #28 ;get w=(2^28)*N {N is b31, V is b28, C is b29 in pc/psr}
TEQP $w, pc, LSR #1 ;EOR w into pc/psr {ie N EOR C is put into V} - this is a way of storing
;sign of result in overflow flag, saving on a register
MOV $w, $r, LSR #16
BIC $r, $r, $w, LSL #16
MOV $v, $a, LSR #16
BIC $a, $a, $v, LSL #16
MUL $u, $a, $r
TST $u, #1<<15 ;notice this is the only operation altering psr & that it will not corrupt V
;note it will corrupt C, as immediate operand 32768 requires a shift
MOV $u, $u, LSR #16
ADDNE $u, $u, #1
MLA $u, $r, $v, $u ;6/9/94 - reverse v & r to optimise for argument a small
MLA $u, $a, $w, $u
MUL $r, $w, $v ;6/9/94 - reverse v & w to optimise for argument a small
ADD $r, $u, $r, LSL #16
RSBVS $r, $r, #0
MEND
; mul16c
; multiplication of an integer x by a 16-bit fixed point number a, where a is a contraction
; ie calculates r=x*a/65536, assuming: abs a < 65536
; if the possibility exists that a>=65536, caller should check this & either not call routine, or set a=65535
; It takes 4 parameters - all register names.
;
; $x: x
; $a: a - require abs a <65536, a will be corrupted
; $r: result - may be the same as $x
; $w: scratch
;
MACRO
$label mul16c $x, $a, $r, $w
ASSERT $r <> $a
ASSERT $r <> $w
ASSERT $x <> $a
ASSERT $x <> $w
ASSERT $a <> $w
$label MOVS $w, $a, LSL #1
RSBCS $a, $a, #0
TEQ $x, #0
RSBMI $r, $x, #0
[ $r <> $x
MOVPL $r, $x
]
MOV $w, pc, LSR #31 ;see mul16 above, for comments re this part
MOV $w, $w, LSL #28
TEQP $w, pc, LSR #1
TST $a, #1<<16 ;bodge to allow code to function if $a is upto 2*65536-1
MOVNE $r, $r, LSL #1 ;can occur in a contractive fn due to change of coordinates to handle 1x2 pixel aspect ratio
MOVNE $a, $a, LSR #1 ;change made 3/4/94 - estimate overhead to ria of upto 3%
MOV $w, $r, LSR #16
BIC $r, $r, $w, LSL #16
MUL $r, $a, $r
TST $r, #1<<15 ;remember, can't use movs r,r,lsr #16, as this would corrupt V, which is storing sign of result
MOV $r, $r, LSR #16
ADDNE $r, $r, #1
MLA $r, $a, $w, $r
RSBVS $r, $r, #0
MEND
; sqrt16
; integer square root returning 16-bit fixed point number, assuming x is 16-bit fixed point
; ie returns sqrt(x<<16)
; It takes 6 parameters - all register names
;
; $x: x
; $r: result - may be the same as x
; $n: copy of x used during calculation
; $t: transient scratch
; $d: remainder
; $o: constant value of 1
;
MACRO
$label sqrt16 $x, $r, $n, $t, $d, $o
ASSERT $x <> $n
ASSERT $x <> $t
ASSERT $x <> $d
ASSERT $x <> $o
ASSERT $n <> $t
ASSERT $n <> $d
ASSERT $n <> $o
ASSERT $t <> $d
ASSERT $t <> $o
ASSERT $d <> $o
LCLA counter
$label MOV $n, $x
MOV $o, #1
MOV $x, #0
MOV $d, #0
AND $t, $n, #(3<<30)
MOV $t, $t, LSR #30
ORR $d, $d, $t
ADD $t, $o, $x, LSL #1
CMP $d, $t
SUBGE $d, $d, $t
ADDGE $x, $x, #1
counter SETA 28
WHILE counter < 32 ;want >= 0, however counter is unsigned, so after 0 it goes high, thus < 32 will catch it!
MOV $x, $x, LSL #1
MOV $d, $d, LSL #2
AND $t, $n, #(3<<counter)
[ counter <> 0
MOV $t, $t, LSR #counter
]
ORR $d, $d, $t
ADD $t, $o, $x, LSL #1
CMP $d, $t
SUBGE $d, $d, $t
ADDGE $x, $x, #1
counter SETA counter-2
WEND
counter SETA 14
WHILE counter < 32
MOV $x, $x, LSL #1
MOV $d, $d, LSL #2
ADD $t, $o, $x, LSL #1
CMP $d, $t
SUBGE $d, $d, $t
ADDGE $x, $x, #1
counter SETA counter-2
WEND
[ $r <> $x
MOV $r, $x
]
MEND
END