FastTrigOpsHow to implement fast trig ops Right now the syscall() function gets passed the contents of a few registers (v0,a0-a3,t0-t1 I think). None of these are floating point regs. We could add some floating point regs to the list but it'll just make other syscalls slower for the sake of speeding up sin and friends and you'll still have a problem returning a floating point value. I'd rather just pass and return the floating point stuff in the standard GPRs and shuffle stuff around in user code (user code being support.s). This of course means the floating point stuff is passed as ints instead of doubles, and the syscall code would need to do doubleToLongBits, etc, but this would've happened anyway as NestedVM always stores doubles as ints. Now to make matters even more complex... a double can't fit in the int returned by syscall. We could of course come up with some method for syscall to return two values but again that is just adding more complexity just for sin and friends. So... you'll have to pass a memory address that the syscall will write the return to (the pipe syscall does this). The code for the SYSCALL_MONADIC_DOUBLE macro should be something like this: (I'm sure this isn't working code. It has been a while since I've written MIPS asm.) li v0, SYSCALL_NUMBER ; move the syscall no to v0 move a0, f0 ; move first half of double to a0 move a1, f1 ; second half to a1 addu a2, sp, -8 ; put sp-8 into a2 syscall ; we can skip the errno checking stuff here because these syscalls ; can't fail lw f0, sp(-8) ; copy the result back into the fp regs from the stack lw f1, sp(-4) j ra ; return nop ; delay slot and the java code for the syscall would be:
int sys_sin(int xlow, int xhi, int retaddr) {
long l = (xhi&0xffffffffL << 32) | (xlow&0xffffffffL)
double d = Double.longBitsToDouble(l);
d = Math.sin(d);
l = Double.doubleToLongBits(d);
memWrite(retaddr,(int)(l>>32));
memWrite(retaddr+4,(int)l);
return 0;
}
Again, this code certainly isn't tested but that is the idea. But once you implement the macro for a function in MIPS assembler
taking a double argument and returning a double, the rest of the
libm functions will all be basically the same.
Yep. You'd just do: SYSCALL_MONADIC_DOUBLE(sin) SYSCALL_MONADIC_DOUBLE(cos) ... atan2 and power will be a little different though since they take two args. You'll want a SYSCALL_DYADIC_DOUBLE macro for them. (Or you could just skip them if they aren't important for your app.) |