EarthBound/ASM/Memory And String Util Routines: Difference between revisions

From Data Crystal
Jump to navigation Jump to search
(Describe more routines)
m (Add anchor)
 
(4 intermediate revisions by 2 users not shown)
Line 6: Line 6:
Copy memory similarly to the [https://cplusplus.com/reference/cstring/memcpy/ C memcpy function]. Memory is copied in 16-bit words, ignoring the final byte if an odd length is requested. Implemented using trivial repeated <tt>LDA</tt> and <tt>STA</tt> calls.
Copy memory similarly to the [https://cplusplus.com/reference/cstring/memcpy/ C memcpy function]. Memory is copied in 16-bit words, ignoring the final byte if an odd length is requested. Implemented using trivial repeated <tt>LDA</tt> and <tt>STA</tt> calls.


''Note: Unclear why EarthBound uses this routine instead of using the typically faster <tt>MVN</tt> or <tt>MVP</tt> CPU instructions.''
''Note: Unclear why EarthBound uses this subroutine instead of using the typically faster <tt>MVN</tt> or <tt>MVP</tt> CPU instructions.''


===Inputs===
===Inputs===
* <tt>x</tt>: Num bytes to copy. Because routine only copies in 16-bit words, only copies <tt>x - 1</tt> if <tt>x % 2 == 1</tt>
* <tt>x</tt>: Num bytes to copy. Because the subroutine only copies in 16-bit words, only copies <tt>x - 1</tt> if <tt>x % 2 == 1</tt>
* <tt>accumulator</tt>: Destination immediate pointer
* <tt>accumulator</tt>: Destination immediate pointer
* <tt>$0e..$10</tt>: Source long pointer
* <tt>$0e..$10</tt>: Source long pointer


==<tt>$C08EED-$C08EFB</tt>: 8-bit memcpy==
==<tt>$C08EED-$C08EFB</tt>: 8-bit memcpy<span class="anchor" id="$c08eed"></span>==
<code>memcpy($0e..$10, $12..$15, a)</code>
<code>memcpy($0e..$10, $12..$15, a)</code>


Copy memory similarly to the [https://cplusplus.com/reference/cstring/memcpy/ C memcpy function]. Memory is copied byte-by-byte. Implemented using trivial repeated <tt>LDA</tt> and <tt>STA</tt> calls with the accumulator set to 8-bit mode.
Copy memory similarly to the [https://cplusplus.com/reference/cstring/memcpy/ C memcpy function]. Memory is copied byte-by-byte. Implemented using trivial repeated <tt>LDA</tt> and <tt>STA</tt> calls with the accumulator set to 8-bit mode.


''Note: Unclear why EarthBound uses this routine instead of using the typically faster <tt>MVN</tt> or <tt>MVP</tt> CPU instructions.''
''Note: Unclear why EarthBound uses this subroutine instead of using the typically faster <tt>MVN</tt> or <tt>MVP</tt> CPU instructions.''


===Inputs===
===Inputs===
Line 30: Line 30:
Fill a block of memory with a given 8-bit value, similarly to the [https://cplusplus.com/reference/cstring/memset/ C memset function]. Memory is set in 16-bit words, ignoring the final byte if an odd length is requested. Implemented by filling both bytes of the accumulator with the input byte value and then using trivial repeated <tt>STA</tt> calls.
Fill a block of memory with a given 8-bit value, similarly to the [https://cplusplus.com/reference/cstring/memset/ C memset function]. Memory is set in 16-bit words, ignoring the final byte if an odd length is requested. Implemented by filling both bytes of the accumulator with the input byte value and then using trivial repeated <tt>STA</tt> calls.


''Note: Unclear why EarthBound uses this routine instead of applying the typically faster <tt>MVN</tt> or <tt>MVP</tt> CPU instructions to overlapping memory regions.''
''Note: Unclear why EarthBound uses this subroutine instead of applying the typically faster <tt>MVN</tt> or <tt>MVP</tt> CPU instructions to overlapping memory regions.''


===Inputs===
===Inputs===
* <tt>x</tt>: Num bytes to fill. Because routine only fills in 16-bit words, only fills <tt>x - 1</tt> if <tt>x % 2 == 1</tt>
* <tt>x</tt>: Num bytes to fill. Because the subroutine only fills in 16-bit words, only fills <tt>x - 1</tt> if <tt>x % 2 == 1</tt>
* <tt>accumulator</tt>: Memory start immediate pointer
* <tt>accumulator</tt>: Memory start immediate pointer
* <tt>$0e</tt>: 8-bit value
* <tt>$0e</tt>: 8-bit value


==<tt>$C08F15-$C08F21</tt>: 8-bit memset==
==<tt>$C08F15-$C08F21</tt>: 8-bit memset<span class="anchor" id="$c08f15"></span>==
<code>memset($0e..$10, a, x)</code>
<code>memset($0e..$10, a, x)</code>


Fill a block of memory with a given 8-bit value, similarly to the [https://cplusplus.com/reference/cstring/memset/ C memset function]. Memory is set byte-by-byte. Implemented using trivial repeated <tt>STA</tt> calls with the accumulator set to 8-bit mode.
Fill a block of memory with a given 8-bit value, similarly to the [https://cplusplus.com/reference/cstring/memset/ C memset function]. Memory is set byte-by-byte. Implemented using trivial repeated <tt>STA</tt> calls with the accumulator set to 8-bit mode.


''Note: Unclear why EarthBound uses this routine instead of applying the typically faster <tt>MVN</tt> or <tt>MVP</tt> CPU instructions to overlapping memory regions.''
''Note: Unclear why EarthBound uses this subroutine instead of applying the typically faster <tt>MVN</tt> or <tt>MVP</tt> CPU instructions to overlapping memory regions.''


===Inputs===
===Inputs===
Line 52: Line 52:
<code>strlen($0e..$10)</code>
<code>strlen($0e..$10)</code>


Count number of bytes in a memory block before a <tt>#$00</tt> value, not including the <tt>#$00</tt> byte. Used to find the length of a null-terminated string, similarly to the [https://cplusplus.com/reference/cstring/strlen/ C strlen function]. Implemented trivially by incrementing an index register until <tt>LDA</tt> instructions using the index loads zero.
Count number of bytes in a memory block before a <tt>#$00</tt> value, not including the <tt>#$00</tt> byte. Used to find the length of a null-terminated string, similarly to the [https://cplusplus.com/reference/cstring/strlen/ C strlen function]. Implemented trivially by incrementing an index register until an <tt>LDA</tt> instruction using the index loads zero.


''Warning: Because an 8-bit register is used to count string bytes, will loop and hang if the input string does not contain a zero byte within the first 256 bytes.''
''Warning: Because an 8-bit register is used to count string bytes, will loop and hang if the input string does not contain a zero byte within the first 256 bytes.''
Line 77: Line 77:


==<tt>$C08F42-$C08F67</tt>: Copy CPU state to memory==
==<tt>$C08F42-$C08F67</tt>: Copy CPU state to memory==
Saves the bank register, subroutine return pointer, P register (processor flags), direct page register, and stack register to 8 bytes of memory in the <tt>$00</tt> bank, starting at an input pointer. Used to create a saved state that can be later restored using the subroutine at <tt>$C08F68-$C08F8A</tt>.
===Inputs===
* <tt>accumulator</tt>: Destination memory pointer (in bank <tt>$00</tt>)


==<tt>$C08F68-$C08F8A</tt>: Load CPU state from memory==
==<tt>$C08F68-$C08F8A</tt>: Load CPU state from memory==
Restores the bank register, subroutine return pointer, P register (processor flags), direct page register, and stack register from 8 bytes of memory in the <tt>$00</tt> bank, starting at an input pointer. Used to restore a saved state saved by the subroutine at <tt>$C08F42-$C08F67</tt>.
Because this subroutine overwrites the subroutine return pointer, on completion, on the <tt>RTL</tt> instruction, this subroutine will return to the code location where the save-state subroutine at <tt>$C08F42-$C08F67</tt> was called, not the code location where this subroutine was called. This subroutine therefore acts as a jump to a saved location.
''Warning: Because this subroutine restores the stack register but not stack contents (except the subroutine return pointer), it can create unintended behavior if the call location of the save or restore subroutine makes assumptions about stack contents. Ideally, the restore subroutine should be called from the same context or a context where the stack has only been added to from the context where the save subroutine was called, thus ensuring the stack register restore simply returns the stack to the same contents from when the save subroutine was called.''
===Inputs===
* <tt>accumulator</tt>: Source memory pointer (in bank <tt>$00</tt>)
* <tt>x</tt>: Value to output
===Outputs===
* <tt>accumulator</tt>: Value from the <tt>x</tt> input


[[Category:EarthBound:ASM|Memory And String Util Routines]]
[[Category:EarthBound:ASM|Memory And String Util Routines]]
{{Internal Data|game=EarthBound}}
{{Internal Data|game=EarthBound}}
{{stub}}

Latest revision as of 03:14, 12 June 2024

This is a sub-page of EarthBound/ASM.

$C08ED2-$C08EEC: 16-bit memcpy

memcpy(a, $0e..$10, x)

Copy memory similarly to the C memcpy function. Memory is copied in 16-bit words, ignoring the final byte if an odd length is requested. Implemented using trivial repeated LDA and STA calls.

Note: Unclear why EarthBound uses this subroutine instead of using the typically faster MVN or MVP CPU instructions.

Inputs

  • x: Num bytes to copy. Because the subroutine only copies in 16-bit words, only copies x - 1 if x % 2 == 1
  • accumulator: Destination immediate pointer
  • $0e..$10: Source long pointer

$C08EED-$C08EFB: 8-bit memcpy

memcpy($0e..$10, $12..$15, a)

Copy memory similarly to the C memcpy function. Memory is copied byte-by-byte. Implemented using trivial repeated LDA and STA calls with the accumulator set to 8-bit mode.

Note: Unclear why EarthBound uses this subroutine instead of using the typically faster MVN or MVP CPU instructions.

Inputs

  • accumulator: Num bytes to copy
  • $0e..$10: Destination long pointer
  • $12..$15: Source long pointer

$C08EFC-$C08F14: 16-bit memset

memset(a, $0e, x)

Fill a block of memory with a given 8-bit value, similarly to the C memset function. Memory is set in 16-bit words, ignoring the final byte if an odd length is requested. Implemented by filling both bytes of the accumulator with the input byte value and then using trivial repeated STA calls.

Note: Unclear why EarthBound uses this subroutine instead of applying the typically faster MVN or MVP CPU instructions to overlapping memory regions.

Inputs

  • x: Num bytes to fill. Because the subroutine only fills in 16-bit words, only fills x - 1 if x % 2 == 1
  • accumulator: Memory start immediate pointer
  • $0e: 8-bit value

$C08F15-$C08F21: 8-bit memset

memset($0e..$10, a, x)

Fill a block of memory with a given 8-bit value, similarly to the C memset function. Memory is set byte-by-byte. Implemented using trivial repeated STA calls with the accumulator set to 8-bit mode.

Note: Unclear why EarthBound uses this subroutine instead of applying the typically faster MVN or MVP CPU instructions to overlapping memory regions.

Inputs

  • x: Num bytes to fill
  • $0e..$10: Memory start long pointer
  • accumulator[0]: 8-bit value

$C08F22-$C08F2E: strlen

strlen($0e..$10)

Count number of bytes in a memory block before a #$00 value, not including the #$00 byte. Used to find the length of a null-terminated string, similarly to the C strlen function. Implemented trivially by incrementing an index register until an LDA instruction using the index loads zero.

Warning: Because an 8-bit register is used to count string bytes, will loop and hang if the input string does not contain a zero byte within the first 256 bytes.

Inputs

  • $0e..$10: Memory start long pointer

Outputs

  • accumulator[0]: 8-bit length (num bytes)

$C08F2F-$C08F41: strcmp(ish)

strcmpish($0e..$10, $12..$14)

Determine if one string (s1) is the same as the start to another string (s2). Implementing by comparing the strings byte-by-byte until the end (#$00 byte) of s1 is found or the compared bytes of s1 and s2 are not equal.

Note: Behaves quite differently from the C strcmp function. Only compares input strings for the length of s1 and has different return values.

Inputs

  • $0e..$10: s1 long pointer
  • $12..$14: s2 long pointer

Outputs

  • accumulator[0]: #$00 if s2 begins with s1, otherwise #$01

$C08F42-$C08F67: Copy CPU state to memory

Saves the bank register, subroutine return pointer, P register (processor flags), direct page register, and stack register to 8 bytes of memory in the $00 bank, starting at an input pointer. Used to create a saved state that can be later restored using the subroutine at $C08F68-$C08F8A.

Inputs

  • accumulator: Destination memory pointer (in bank $00)

$C08F68-$C08F8A: Load CPU state from memory

Restores the bank register, subroutine return pointer, P register (processor flags), direct page register, and stack register from 8 bytes of memory in the $00 bank, starting at an input pointer. Used to restore a saved state saved by the subroutine at $C08F42-$C08F67.

Because this subroutine overwrites the subroutine return pointer, on completion, on the RTL instruction, this subroutine will return to the code location where the save-state subroutine at $C08F42-$C08F67 was called, not the code location where this subroutine was called. This subroutine therefore acts as a jump to a saved location.

Warning: Because this subroutine restores the stack register but not stack contents (except the subroutine return pointer), it can create unintended behavior if the call location of the save or restore subroutine makes assumptions about stack contents. Ideally, the restore subroutine should be called from the same context or a context where the stack has only been added to from the context where the save subroutine was called, thus ensuring the stack register restore simply returns the stack to the same contents from when the save subroutine was called.

Inputs

  • accumulator: Source memory pointer (in bank $00)
  • x: Value to output

Outputs

  • accumulator: Value from the x input