EarthBound/ASM/Math Routines

From Data Crystal
Jump to navigation Jump to search

This is a sub-page of EarthBound/ASM.

$C08FE6-$C08FF6: Unsigned 8-bit multiplication

accumulator[0] = accumulator[0] * y[0]

Multiplies two 8-bit multiplicands and truncates the product into an 8-bit result. Implemented using a simple application of the SNES's hardware support for unsigned multiplication.

Note: This routine does not appear to be used anywhere in an unmodified EarthBound ROM.

Inputs

  • accumulator[0]: 8-bit multiplicand1
  • y[0]: 8-bit multiplicand2

Outputs

  • accumulator[0]: 8-bit product

Note: The accumulator is set to 8-bit mode before returning because somebody was trying way too hard to stick to the principle that an 8-bit math operation should always return an 8-bit result. But if you clear flag #$20 after the routine returns, the upper byte of the accumulator should contain the upper byte of the product for a full 16-bit result.

$C08FF7-$C09031: Unsigned 16-bit * 8-bit multiplication

accumulator = accumulator * y[0]

Multiplies a 16-bit multiplicand by an 8-bit multiplicand and truncates the product into a 16-bit result. Implemented by combining together the results of up to two applications of the SNES hardware multiplier.

Inputs

  • accumulator: 16-bit multiplicand1
  • y[0]: 8-bit multiplicand2

Outputs

  • accumulator: 16-bit product

Note: Due to how the result is processed, if the input accumulator[1] is not zero, on output, y[1] will contain the upper third byte of the product, making it possible to use this routine to calculate a 24-bit product. But if the input accumulator[1] is zero, y[1] will not be modified, and will contain whatever it contained before calling the routine.

$C09032-$C09085: Unsigned 16-bit multiplication

accumulator = accumulator * y

Multiplies a 16-bit multiplicand by a 16-bit multiplicand and truncates the product into a 16-bit result. Implemented by combining together the results of three applications of the SNES hardware multiplier.

Inputs

  • accumulator: 16-bit multiplicand1
  • y: 16-bit multiplicand2

Outputs

  • accumulator: 16-bit product

Note: On return, $00B2 will contain the upper two bytes from 0x100 * m1[1] * m2[0] + 0x100 * m1[0] * m2[1]. This is not the full upper two bytes to create a full 32-bit output because it is still missing 0x10000 * m1[1] * m2[1].

$C09086-$C090CD: Unsigned 32-bit multiplication

$06,$09 = $06,$09 * $0a,$0d

Multiplies a 32-bit multiplicand by a 32-bit multiplicand and truncates the product into a 32-bit result. Implemented by combining together 3 calls to the 16-bit multiplication routine and one application of the SNES hardware multiplier to complete the partial 32-bit result that the 16-bit routine stores in $00B2

Inputs

  • $06,$09: 32-bit multiplicand1
  • $0a,$0d: 32-bit multiplicand2

Outputs

  • $06,$09: 32-bit product

$C090CE-$C090E5: Signed 8-bit division

a[0] = a[0] / y[0]

Divides a signed 8-bit numerator by a signed 8-bit denominator to determine a signed 8-bit quotient. Per normal arithmetic rules for division, quotient will be positive if inputs have the same sign (both positive or both negative) and negative if inputs have different signs.

Implemented by storing the xor of both input signs, calling the routine for division of absolute values of inputs, and then flipping the result to negative (a = a xor #$ff + 1) if the stored xor was one.

Inputs

  • a[0]: Signed 8-bit numerator
  • y[0]: Signed 8-bit denominator

Outputs

  • a[0]: Signed 8-bit quotient
  • y[0]: Unsigned 8-bit remainder

$C090E6-$C090FE: Signed 16-bit division

a = a / y

Divides a signed 16-bit numerator by a signed 16-bit denominator to determine a signed 16-bit quotient. Per normal arithmetic rules for division, quotient will be positive if inputs have the same sign (both positive or both negative) and negative if inputs have different signs.

Implemented by storing the xor of both input signs, calling the routine for division of absolute values of inputs, and then flipping the result to negative (a = a xor #$ffff + 1) if the stored xor was one.

Inputs

  • a: Signed 16-bit numerator
  • y: Signed 16-bit denominator

Outputs

  • a: Signed 16-bit quotient
  • y: Unsigned 16-bit remainder

$C090FF-$C0911D: Signed 32-bit division

$06,$09 = $06,$09 / $0a,$0d

Divides a signed 32-bit numerator by a signed 32-bit denominator to determine a signed 32-bit quotient. Per normal arithmetic rules for division, quotient will be positive if inputs have the same sign (both positive or both negative) and negative if inputs have different signs.

Implemented by storing the xor of both input signs, calling the routine for division of absolute values of inputs, and then subtracting both shorts from 0 if the stored xor was one.

Inputs

  • $06,$09: Signed 32-bit numerator
  • $0a-$0d: Signed 32-bit denominator

Outputs

  • $06,$09: Signed 32-bit quotient
  • $0a,$0d: Unsigned 32-bit remainder

$C0911E-$C0912B: 8-bit division of absolute values of inputs

a[0] = |a[0]| / |y[0]|

Divides the absolute value of a signed 8-bit numerator by the absolute value of a signed 8-bit denominator to determine an unsigned 8-bit quotient. Implemented by comparing both inputs to zero, flipping to positive if less than zero (input = input xor #$ff + 1) and then falling through to the start of the unsigned 8-bit division routine.

Inputs

  • a[0]: Signed 8-bit numerator
  • y[0]: Signed 8-bit denominator

Outputs

  • a[0]: Unsigned 8-bit quotient
  • y[0]: Unsigned 8-bit remainder

$C0912C-$C0914A: Unsigned 8-bit division

a[0] = a[0] / y[0]

Divides an unsigned 8-bit numerator by an unsigned 8-bit denominator to determine an 8-bit quotient. Implemented using a simple application of the SNES's hardware support for unsigned division.

Inputs

  • a[0]: Unsigned 8-bit numerator
  • y[0]: Unsigned 8-bit denominator

Outputs

  • a[0]: Unsigned 8-bit quotient
  • y[0]: Unsigned 8-bit remainder

$C0914B-$C0915A: 16-bit division of absolute values of inputs

a = |a| / |y|

Divides the absolute value of a signed 16-bit numerator by the absolute value of a signed 16-bit denominator to determine an unsigned 16-bit quotient. Implemented by comparing both inputs to zero, flipping to positive if less than zero (input = input xor #$ffff + 1) and then falling through to the start of the unsigned 16-bit division routine.

Inputs

  • a: Signed 16-bit numerator
  • y: Signed 16-bit denominator

Outputs

  • a: Unsigned 16-bit quotient
  • y: Unsigned 16-bit remainder

$C0915B-$C0917B: Unsigned 16-bit division

a = a / y

Divides an unsigned 16-bit numerator by an unsigned 16-bit denominator to determine a 16-bit quotient. Implemented using bit-by-bit long division.

Inputs

  • a: Unsigned 16-bit numerator
  • y: Unsigned 16-bit denominator

Outputs

  • a: Unsigned 16-bit quotient
  • y: Unsigned 16-bit remainder

$C0917C-$C091A5: 32-bit division of absolute values of inputs

$06,$09 = |$06,$09| / |$0a,$0d|

Divides the absolute value of a signed 32-bit numerator by the absolute value of a signed 32-bit denominator to determine an unsigned 32-bit quotient. Implemented by comparing both inputs to zero, flipping to positive if less than zero and then falling through to the start of the unsigned 32-bit division routine.

Inputs

  • $06,$09: Signed 32-bit numerator
  • $0a,$0d: Signed 32-bit denominator

Outputs

  • $06,$09: Unsigned 32-bit quotient
  • $0a,$0d: Unsigned 32-bit remainder

$C091A6-$C091E2: Unsigned 32-bit division

$06,$09 = $06,$09 / $0a,$0d

Divides an unsigned 32-bit numerator by an unsigned 32-bit denominator to determine a 32-bit quotient. Implemented using bit-by-bit long division.

Inputs

  • $06,$09: Unsigned 32-bit numerator
  • $0a,$0d: Unsigned 32-bit denominator

Outputs

  • $06,$09: Unsigned 32-bit quotient
  • $0a,$0d: Unsigned 32-bit remainder

$C091E3-$C091F3: Signed 8-bit modulo

a[0] = a[0] % y[0]

Finds the signed 8-bit remainder of the division of a signed 8-bit numerator by a signed 8-bit denominator. The sign of the remainder always matches the sign of the numerator. Implemented by storing the input numerator, calling the routine for 8-bit division of absolute values of inputs, and flipping the result to negative (a = a xor #$ff + 1) if the stored input is negative.

Inputs

  • a[0]: Signed 8-bit numerator
  • y[0]: Signed 8-bit denominator

Outputs

  • a[0]: Signed 8-bit remainder

$C091F4-$C09205: Signed 16-bit modulo

a = a % y

Finds the signed 16-bit remainder of the division of a signed 16-bit numerator by a signed 16-bit denominator. The sign of the remainder always matches the sign of the numerator. Implemented by storing the input numerator, calling the routine for 16-bit division of absolute values of inputs, and flipping the result to negative (a = a xor #$ffff + 1) if the stored input is negative.

Inputs

  • a: Signed 16-bit numerator
  • y: Signed 16-bit denominator

Outputs

  • a: Signed 16-bit remainder

$C09206-$C0922A: Signed 32-bit modulo

$06,$09 = $06,$09 % $0a,$0d

Finds the signed 32-bit remainder of the division of a signed 32-bit numerator by a signed 32-bit denominator. The sign of the remainder always matches the sign of the numerator. Implemented by storing the input numerator, calling the routine for 32-bit division of absolute values of inputs, and then subtracting both shorts from 0 if the stored input is negative.

Inputs

  • $06,$09: Signed 32-bit numerator
  • $0a,$0d: Signed 32-bit denominator

Outputs

  • $06,$09: Signed 32-bit remainder

$C0922B-$C09230: Unsigned 8-bit modulo

a[0] = a[0] % y[0]

Finds the unsigned 8-bit remainder of the division of an unsigned 8-bit numerator by an unsigned 8-bit denominator. Implemented calling the routine for unsigned 8-bit division and copying the result to the accumulator.

Inputs

  • a[0]: Unsigned 8-bit numerator
  • y[0]: Unsigned 8-bit denominator

Outputs

  • a[0]: Unsigned 8-bit remainder

$C09231-$C09236: Unsigned 16-bit modulo

a = a % y

Finds the unsigned 16-bit remainder of the division of an unsigned 16-bit numerator by an unsigned 16-bit denominator. Implemented calling the routine for unsigned 16-bit division and copying the result to the accumulator.

Inputs

  • a: Unsigned 16-bit numerator
  • y: Unsigned 16-bit denominator

Outputs

  • a: Unsigned 16-bit remainder

$C09237-$C0923C: Unsigned 32-bit modulo

$06,$09 = $06,$09 % $0a,$0d

Finds the unsigned 32-bit remainder of the division of an unsigned 32-bit numerator by an unsigned 32-bit denominator. Implemented calling the routine for unsigned 32-bit division and then jumping to the code at the end of the signed 32-bit module routine that handles copying the remainder over if the input numerator is positive.

Inputs

  • $06,$09: Unsigned 32-bit numerator
  • $0a,$0d: Unsigned 32-bit denominator

Outputs

  • $06,$09: Unsigned 32-bit remainder

$C0923D-$C09241: Repeated left bit shift

a = a << y

Finds the result of repeated left bit shifts on an 8-bit or 16-bit (depending on accumulator mode) input. Trivially implemented using repeated calls to ASL.

Note: The entry address for this routine is $C0923E rather than the first address of the routine.

Inputs

  • a: Value
  • y: Num shifts

Outputs

  • a: Shifted value

$C09242-$C09249: Repeated 32-bit left bit shift

$06,$09 = $06,$09 << y

Finds the result of repeated left bit shifts on a 32-bit input. Trivially implemented using repeated calls to ASL and ROL.

Note: The entry address for this routine is $C09246 rather than the first address of the routine.

Inputs

  • $06,$09: 32-bit value
  • y: Num shifts

Outputs

  • $06,$09: 32-bit shifted value

$C0924A-$C0925A: Repeated 8-bit right bit shift

a[0] = a[0] >> y

Finds the result of repeated right bit shifts on a signed 8-bit input, filling in with the value of the most significant bit of the input, that is zeroes for a positive input and ones for a negative input. Implemented for positive inputs with a trivial repeated call to LSR and for negative inputs with repeated calls to ROR with the carry bit set.

Alternative entry points

  • $C09251: Unsigned 8-bit or 16-bit right bit shift, filling in always with zeroes.
  • $C09257: Negative number 8-bit or 16-bit right bit shift, filling in always with ones.

Inputs

  • a[0]: Signed 8-bit value
  • y: Num shifts

Outputs

  • a[0]: Signed 8-bit shifted value

$C0925B-$C09261: Repeated 16-bit right bit shift

a = a >> y

Finds the result of repeated right bit shifts on a signed 16-bit input, filling in with the value of the most significant bit of the input, that is zeroes for a positive input and ones for a negative input. Implemented with jumps to the relevant positive or negative shift logic in the repeated 8-bit right bit shift routine.

Inputs

  • a: Signed 16-bit value
  • y: Num shifts

Outputs

  • a: Signed 16-bit shifted value

$C09262-$C09278: Repeated 32-bit right bit shift

$06,$09 = $06,$09 >> y

Finds the result of repeated right bit shifts on a signed 32-bit input, filling in with the value of the most significant bit of the input, that is zeroes for a positive input and ones for a negative input. Implemented for positive inputs with a trivial repeated call to LSR and for negative inputs with repeated calls to ROR with the carry bit set.

Alternative entry points

  • $C0926C: Unsigned 32-bit right bit shift, filling in always with zeroes.
  • $C09275: Negative number 32-bit right bit shift, filling in always with ones.

Inputs

  • $06,$09: Signed 32-bit value
  • y: Num shifts

Outputs

  • $06,$09: Signed 32-bit shifted value