f33b30ed3c
This fixes the SIGILL (illegal instruction) in startrek when firing phasers. The 32-bit processors in my PowerPC Mac and in QEMU don't have fctid, a 64-bit instruction. I got the idea from mach/proto/fp/fif8.c to extract the exponent, clear some bits to get an integer, then subtract the integer from the original value to get the fraction.
72 lines
1.8 KiB
ArmAsm
72 lines
1.8 KiB
ArmAsm
#include "powerpc.h"
|
|
|
|
.sect .text
|
|
|
|
! Multiplies two double-precision floats, then splits the product into
|
|
! integer and fraction, like modf(3) in C. On entry:
|
|
! f1 = float
|
|
! f2 = other float
|
|
! Yields:
|
|
! f1 = fraction
|
|
! f2 = integer
|
|
! Kills: cr0 f1 f2 r3 r4 r5 r6
|
|
|
|
.define .fif8
|
|
.fif8:
|
|
fmul f1, f1, f2
|
|
stfdu f1, -8(sp) ! push f1 = product
|
|
lwz r3, 0(sp) ! r3 = high word
|
|
lwz r4, 4(sp) ! r4 = low word
|
|
|
|
! IEEE double-precision format:
|
|
! sign exponent fraction
|
|
! 0 1..11 12..63
|
|
! Subtract 1023 from the IEEE exponent. If the result is from
|
|
! 0 to 51, then the IEEE fraction has that many integer bits.
|
|
! (IEEE has an implicit 1 before its fraction. If the IEEE
|
|
! fraction has 0 integer bits, we still have an integer.)
|
|
rlwinm r5, r3, 12, 21, 31 ! r5 = IEEE exponent
|
|
addic. r5, r5, -1023 ! r5 = nr of integer bits
|
|
bc IFTRUE, LT, no_int
|
|
cmpi cr0, 0, r5, 21
|
|
bc IFTRUE, LT, small_int
|
|
cmpi cr0, 0, r5, 52
|
|
bc IFTRUE, LT, big_int
|
|
|
|
! f1 is an integer without fraction. Jump to calculate
|
|
! fraction f1 = f2 - f1. It will be zero (or perhaps NaN).
|
|
fmr f2, f1
|
|
b subtract
|
|
|
|
no_int:
|
|
! f1 is a fraction without integer.
|
|
fsub f2, f1, f1 ! integer = zero
|
|
b done
|
|
|
|
small_int:
|
|
! f1 has r5 = 0 to 20 integer bits in the IEEE fraction.
|
|
! High word has 20 - r5 fraction bits.
|
|
addi r6, r0, 20
|
|
subf r6, r5, r6
|
|
srw r3, r3, r6
|
|
addi r4, r0, 0 ! clear low word
|
|
slw r3, r3, r6 ! clear fraction in high word
|
|
b move_int
|
|
|
|
big_int:
|
|
! f1 has r5 = 21 to 51 to integer bits.
|
|
! Low word has 52 - r5 fraction bits.
|
|
addi r6, r0, 52
|
|
subf r6, r5, r6
|
|
srw r4, r4, r6
|
|
slw r4, r4, r6 ! clear fraction in low word
|
|
move_int:
|
|
stw r3, 0(sp)
|
|
stw r4, 4(sp)
|
|
lfd f2, 0(sp) ! f2 = integer
|
|
subtract:
|
|
fsub f1, f1, f2 ! fraction = value - integer
|
|
done:
|
|
addi sp, sp, 8 ! restore stack pointer
|
|
bclr ALWAYS, 0, 0
|