Skip to content

Latest commit

 

History

History
306 lines (224 loc) · 9.53 KB

File metadata and controls

306 lines (224 loc) · 9.53 KB

Opcode Group 08 - SEQ_CmdF

Float operations (4 bytes).

0800 - f32_debug

Debug sprintf the given parameter using the print format "%4.2f ".

0801 - f32_mov

Move short.

  • Two operands from SEQ_RegCMD2.
  • Stores result in the first operand.
  • Stores result in the conditional register cr.
op1 = op2
cr = op1

0802 - f32_move

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

0803 - f32_add

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

0804 - f32_sub

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

0805 - f32_mul

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

0806 - f32_div

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

0807 - f32_cmp

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
}

0808 - f32_chs

Float change sign.

  • Two operands from SEQ_RegCMD2.
  • Stores result in the first operand.
op1 = -(op2)
cr = op1

0809 - f32_sqrt

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

080A - f32_rsqrt

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

080B - f32_sin

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))

080C - f32_cos

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))

080D - f32_tan

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)))

080E - f32_atan2

Float 2-argument arctangent.

  • Two operands from SEQ_RegCMD2 and pops one value from the stack register sp.
  • Stores result in the first operand.
op1 = MATH_atan2(op2, *sp)
sp++

080F - f32_range

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 register sp.
  • 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++

0810 - f32_rand

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 register sp.
  • 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++

0811 - f32_mod

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

0812 - f32_abs

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