I'm posting my final version of the function for completeness.
I decided against putting the reset-persistent area at the end of RAM after the C stack. Because in this case, I would have to declare an absolute size for it in the cfg file. But I prefer the reset-persistent area to be just a RAM segment that grows and shrinks according to the global variables I actually declared in the program.
Of course, if you can suggest me a way to declare the NO_RESET part after the stack, but without manually declaring a size for it (i.e. the stack location automatically gets shifted to the left when I declare more variables in NO_RESET), I might change it.
This is the relevant part of my config file (I removed all the ROM- and zeropage-related stuff):
Code: Select all
SYMBOLS
{
__STACKSIZE__ = $0100;
__RAMSTART__ = $0200;
__RAMSIZE__ = $0800 - __RAMSTART__ - __STACKSIZE__;
__STACKSTART__ = __RAMSTART__ + __RAMSIZE__;
}
MEMORY
{
RAM: type = rw, start = __RAMSTART__, size = __RAMSIZE__, file = "";
STACK: type = rw, start = __STACKSTART__, size = __STACKSIZE__, file = "", define = yes;
}
SEGMENTS
{
SPRITES: load = RAM, type = bss, align = $0100;
FAMITONE: load = RAM, type = bss, align = $0100;
BSS: load = RAM, type = bss;
NO_RESET: load = RAM, type = bss, define = yes;
}
Alright, and here the actual code.
The code is put between the two wait for vblank calls.
X was already set to 0 before.
Code: Select all
; In the meantime, set the
; whole RAM memory (i.e. all
; variables) to 0.
; The RAM goes from address
; $0000 to $07FF.
; The current address value
; goes into a two bytes pointer.
; The values are set in two loops.
; The X and Y registers are
; used as counters for the
; loops. A is used for
; overwriting the RAM values.
; X is still 0 from above.
; A and Y are set to 0 now.
TXA
TAY
; A, X and Y all have
; the value 0 now.
; Pointer + 0
; always remains 0.
; The address is calculated
; by Pointer + 1
; and by Y.
; X, which acts as a
; counter, always has to be
; kept in sync with
; Pointer + 1.
STY Pointer + 0
STX Pointer + 1
; The fact that the pointer
; will overwrite itself in
; the following process is
; not an issue:
; Pointer + 0 is
; always 0 anyway, so overwriting
; it with 0 makes no problems.
; And since the pointer is in the
; zeropage, Pointer + 1
; only gets overwritten with 0
; when it's still 0 anyway.
@initializeRamLoop:
; There is a certain RAM area that
; shall not be initialized with zeroes
; because this area shall be persistent
; when the Reset button is pressed.
; We check if we reached that RAM area.
; The high byte of the
; address is checked.
CPX #>__NO_RESET_LOAD__
BNE @noNoResetSkip
; The low byte is checked.
CPY #<__NO_RESET_LOAD__
BNE @noNoResetSkip
; If we reach the reset-
; persistent area, we change
; the address and our counters
; (Pointer + 1, X and Y)
; to the first value after the area.
; This way, the reset-persistent
; area doesn't get overwritten.
LDY #<(__NO_RESET_LOAD__ + __NO_RESET_SIZE__)
LDX #>(__NO_RESET_LOAD__ + __NO_RESET_SIZE__)
STX Pointer + 1
; Since the C stack always comes
; after the regular RAM variables,
; no global variables will ever
; be right at the end of the RAM.
; So, we don't need to check here
; whether writing to the next
; memory location is even allowed
; anymore. We can be sure that we
; haven't reached $0800 yet.
@noNoResetSkip:
; Set the value of 0,
; which is still in A,
; to the current address.
STA (Pointer), Y
; Increment the low byte
; part of the address.
INY
; If it is set back to 0,
; increment the high byte
; part in the pointer and
; in the counter.
; Otherwise, continue
; with the inner loop.
BNE @initializeRamLoop
INC Pointer + 1
INX
; The outer loop ends
; just before address
; $0800.
CPX #$08
BNE @initializeRamLoop
; Set the pointer itself
; to 0 as well.
; Pointer + 0
; is always 0. So, we only
; need to set
; Pointer + 1.
; A is still 0 from above.
STA Pointer + 1
; The RAM has now been
; initialized with all zeroes.