Welcome to Data Crystal's new home! Data Crystal is now part of the TCRF family (sort of).
The wiki has recently moved; please report any issues in Discord. Pardon the dust.

EarthBound/ASM/Math Routines

From Data Crystal
< EarthBound
Revision as of 02:27, 22 May 2023 by Esorth (talk | contribs) (Finish documenting all the multiplication and division routines)
Jump to navigation Jump to search

This is a sub-page of EarthBound/ASM.

$C08FE8-$C08FF6: Unsigned 8-bit multiplication

accumulator[0] = accumulator[0] * accumulator[1]

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
  • accumulator[1]: 8-bit multiplicand2

Outputs

  • accumulator: 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

$C091F4-$C09205: Signed 16-bit modulo

$C09206-$C0922A: Signed 32-bit modulo

$C0922B-$C09230: Unsigned 8-bit modulo

$C09231-$C09236: Unsigned 16-bit modulo

$C09237-$C0923C: Unsigned 32-bit modulo

$C0923D-$C09241: Repeated left bit shift

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

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

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

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

So very stubbly.
This page is rather stubbly and could use some expansion.
Are you a bad enough dude to rescue this article?