Float operations (4 bytes).
- 0800 - f32_debug
- 0801 - f32_mov
- 0802 - f32_move
- 0803 - f32_add
- 0804 - f32_sub
- 0805 - f32_mul
- 0806 - f32_div
- 0807 - f32_cmp
- 0808 - f32_chs
- 0809 - f32_sqrt
- 080A - f32_rsqrt
- 080B - f32_sin
- 080C - f32_cos
- 080D - f32_tan
- 080E - f32_atan2
- 080F - f32_range
- 0810 - f32_rand
- 0811 - f32_mod
- 0812 - f32_abs
Debug sprintf
the given parameter using the print format "%4.2f "
.
Move short.
- Two operands from
SEQ_RegCMD2
. - Stores result in the first operand.
- Stores result in the conditional register
cr
.
op1 = op2
cr = op1
Move float (ephemeral). Ephemeral in this case means it does not store to cr
.
- Two operands from
SEQ_RegCMD2
. - Stores result in the first operand.
op1 = op2
Float addition.
- Two operands from
SEQ_RegCMD2
. - Stores result in the first operand.
- Stores result in the conditional register
cr
.
op1 = op1 + op2
cr = op1
Float subtraction.
- Two operands from
SEQ_RegCMD2
. - Stores result in the first operand.
- Stores result in the conditional register
cr
.
op1 = op1 - op2
cr = op1
Float multiply.
- Two operands from
SEQ_RegCMD2
. - Stores result in the first operand.
- Stores result in the conditional register
cr
.
op1 = op1 * op2
cr = op1
Float divide.
- Two operands from
SEQ_RegCMD2
. - Stores result in the first operand.
- Stores result in the conditional register
cr
.
op1 = op1 / op2
cr = op1
Float compare. Set cr
to 1 is op1
is larger than op2
. Set cr
to -1 is op2
is larger than op1
. Set cr
to 0 if op1
and op2
are roughly equal.
- Two operands from
SEQ_RegCMD2
. - Stores result in the conditional register
cr
.
epsilon = 0.0001 // to handle rounding error
if (op1 - op2 <= epsilon) {
if (op2 - op1 <= epsilon) {
cr = 0 // op1 and op2 are roughly equal
}
else {
cr = -1 // op2 is larger
}
}
else {
cr = 1 // op1 is larger
}
Float change sign.
- Two operands from
SEQ_RegCMD2
. - Stores result in the first operand.
op1 = -(op2)
cr = op1
Float square root.
Performs a Reciprocal Square Root Estimate. The frsqrte
PowerPC instruction generates an estimate of the reciprocal square root, accurate to 1 part in 32. Greater accuracy is desired, so this result serves as the initial seed for a Newton-Raphson approximation algorithm.
- Two operands from
SEQ_RegCMD2
. - Stores result in the first operand.
temp = 0
temp2 = op2
if (0 < temp2) {
asm (
"frsqrte %[temp], %[temp2]\n\t" // Floating Reciprocal Square Root Estimate, i.e. 1.0 / sqrt(temp2)
)
temp = 0.5 * temp * -(temp2 * temp * temp - 3)
temp = 0.5 * temp * -(temp2 * temp * temp - 3)
temp2 = (temp2 * 0.5 * temp * -(temp2 * temp * temp - 3))
}
op1 = temp2
Float reciprocal (inverse) square root.
Performs a Reciprocal Square Root Estimate. The frsqrte
PowerPC instruction generates an estimate of the reciprocal square root, accurate to 1 part in 32. Greater accuracy is desired, so this result serves as the initial seed for a Newton-Raphson approximation algorithm.
- Two operands from
SEQ_RegCMD2
. - Stores result in the first operand.
temp = 0
temp2 = 1 / op2
if (0 < temp2) {
asm (
"frsqrte %[temp], %[temp2]\n\t" // Floating Reciprocal Square Root Estimate, i.e. 1.0 / sqrt(temp2)
)
temp = 0.5 * temp * -(temp2 * temp * temp - 3)
temp = 0.5 * temp * -(temp2 * temp * temp - 3)
temp2 = (temp2 * 0.5 * temp * -(temp2 * temp * temp - 3))
}
op1 = temp2
Float sine.
Calculated by referencing a sine lookup table SINE_TABLE
at address 0x8027703c, such as this one in SunOS. The lookup table is populated on game start at address 0x80012b74 using the formula sin(PI/180 * (360.0 * (i) / 16384.0))
where i
is values from 0 to 16384. In this formula, (360.0 * (uVar1) / 16384.0
returns degrees, which we multiple by PI/180
to get radians. This creates a sine wave from 0 to 16384 on the x-coordinate. Each float value is 4-bytes and the granularity is 16384 values, therefore the lookup table is of size 4 * 16384 = 65536
. Values in the table are looked up a short
2-byte offset; therefore the maximum offset that can be used is 65536, hence why a granularity of 16384 was chosen.
- Two operands from
SEQ_RegCMD2
. - Stores result in the first operand.
op1 = *(SINE_TABLE + (op2 + 2 & 0xfffc))
Float cosine.
Calculated by referencing a sine lookup table SINE_TABLE
at address 0x8027703c, such as this one in SunOS. The lookup table is populated on game start at address 0x80012b74 using the formula sin(PI/180 * (360.0 * (i) / 16384.0))
where i
is values from 0 to 16384. In this formula, (360.0 * (uVar1) / 16384.0
returns degrees, which we multiple by PI/180
to get radians. This creates a sine wave from 0 to 16384 on the x-coordinate. Each float value is 4-bytes and the granularity is 16384 values, therefore the lookup table is of size 4 * 16384 = 65536
. Values in the table are looked up a short
2-byte offset; therefore the maximum offset that can be used is 65536, hence why a granularity of 16384 was chosen.
- Two operands from
SEQ_RegCMD2
. - Stores result in the first operand.
op1 = *(SINE_TABLE + (((op2 + 2 >> 2) + 0x1000) * 4 & 0xfffc))
Float tangent.
Calculated by referencing a sine lookup table SINE_TABLE
at address 0x8027703c, such as this one in SunOS. The lookup table is populated on game start at address 0x80012b74 using the formula sin(PI/180 * (360.0 * (i) / 16384.0))
where i
is values from 0 to 16384. In this formula, (360.0 * (uVar1) / 16384.0
returns degrees, which we multiple by PI/180
to get radians. This creates a sine wave from 0 to 16384 on the x-coordinate. Each float value is 4-bytes and the granularity is 16384 values, therefore the lookup table is of size 4 * 16384 = 65536
. Values in the table are looked up a short
2-byte offset; therefore the maximum offset that can be used is 65536, hence why a granularity of 16384 was chosen.
Appears to use the formula tan = sin/cos to obtain tangent.
- Two operands from
SEQ_RegCMD2
. - Stores result in the first operand.
temp = op2 + 2 >> 2;
op1 = *((SINE_TABLE + (temp & 0x3fff) * 4) / (SINE_TABLE + ((temp + 0x1000) * 4 & 0xfffc)))
Float 2-argument arctangent.
- Two operands from
SEQ_RegCMD2
and pops one value from the stack registersp
. - Stores result in the first operand.
op1 = MATH_atan2(op2, *sp)
sp++
Enforce a range on a float. Value is op1
. Range start is op2
and range end is sp
.
- Two operands from
SEQ_RegCMD2
and pops one value from the stack registersp
. - Stores result in the first operand.
- Stores result in the conditional register
cr
.
val = op1
min = op2
max = *sp
result = min // if under min, use min
if (min <= val) {
result = val // keep value as-is
if (max < val) {
result = max // if over max, use max
}
}
op1 = result
cr = op1
sp++
Get a random float. Range start op2
is inclusive and range end sp
is exclusive, that is, [op2, sp)
.
- Two operands from
SEQ_RegCMD2
and pops one value from the stack registersp
. - Stores result in the first operand.
- Stores result in the conditional register
cr
.
rand = hsdbase::HSD_Rand()
rand = (*sp - op2) * (rand & 0xffff)
op1 = (op2 + (rand >> 0x10) + (rand < 0 && (rand & 0xffff) != 0))
cr = op1
sp++
Divide two floats and calculate the fractional component (part after the decimal) of the result. In C is equivalent to modf(op1 / op2, unused)
.
e.g. f32_mod 6.5, 2.5 = 0.6
and f32_mod 6.0, 3.0 = 0.0
op1 = op1 / op2
temp = Runtime.PPCEABI.H::__cvt_fp2unsigned((double) op1) // convert floating-point to 32-bit unsigned integer
temp2 = (double) temp
op1 = op1 - (float)temp2
Float absolute value.
- One operand from
SEQ_RegCMD1
. - Stores result in the first operand.
temp = *op1
asm (
"fabs %[temp], %[temp]\n\t" // Floating Absolute Value
"frsp %[temp], %[temp]\n\t" // Floating Round to Single Precision
)
*op1 = temp