It is currently Mon Oct 22, 2018 8:32 pm

All times are UTC - 7 hours

Post new topic Reply to topic  [ 18 posts ]  Go to page Previous  1, 2
Author Message
PostPosted: Wed Aug 02, 2017 11:00 am 
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6899
Location: Canada
Jarhmander wrote:
His version is not very complicated, in fact it's pretty much standard...

It does seem to be the standard for commercial era games to initialize memory with an indirect Y addressed loop. Here's the memory clear from Super Mario Bros. (doppelganger's disassembly):
;$06 - RAM address low
;$07 - RAM address high

              ldx #$07          ;set initial high byte to $0700-$07ff
              lda #$00          ;set initial low byte to start of page (at $00 of page)
              sta $06
InitPageLoop: stx $07
InitByteLoop: cpx #$01          ;check to see if we're on the stack ($0100-$01ff)
              bne InitByte      ;if not, go ahead anyway
              cpy #$60          ;otherwise, check to see if we're at $0160-$01ff
              bcs SkipByte      ;if so, skip write
InitByte:     sta ($06),y       ;otherwise, initialize byte with current low byte in Y
SkipByte:     dey
              cpy #$ff          ;do this until all bytes in page have been erased
              bne InitByteLoop
              dex               ;go onto the next page
              bpl InitPageLoop  ;do this until all pages of memory have been erased

Do any commercial games do the "list of absolute X" style initialization? I see it all the time in homebrew ROMs, but we have kind of an insular code culture here, and a lot of our popular examples are not derived from commercial games at all.

Jarhmander wrote:
your algorithm takes 27 bytes, his takes 22 bytes

Tiny nitpick, but technically 26 on ca65, 27 on NESASM as written (i.e. whether that STA $000, X gets turned into a ZP or ABS instruction... though you can force it with < on NESASM).

PostPosted: Wed Aug 02, 2017 11:30 am 
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 3132
Location: Tampere, Finland
dougeff wrote:
I have no idea what your last question is asking.

How about this...the memory persistent area is zeropage 00-03

Start your loop with LDY #4.

EDIT-Alternatively, you could use $7fc-7ff as the memory persistent area, and reverse your loop, starting at $7fb, going down to $000

Yet alternative way would be to start the memory clearing loop from the end of the persistent area, and loop for 2048 bytes minus the size of the persistent area. Mirrored memory at $800..$FFF makes this possible. Might not be very convenient to implement though because of the non-page-aligned start/end addresses.

Download STREEMERZ for NES from! — Some other stuff I've done:

PostPosted: Wed Aug 02, 2017 1:06 pm 
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1708
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):
   __STACKSIZE__  = $0100;
   __RAMSTART__   = $0200;
   __RAMSIZE__    = $0800 - __RAMSTART__ - __STACKSIZE__;

   RAM:     type = rw, start = __RAMSTART__,   size = __RAMSIZE__,   file = "";
   STACK:   type = rw, start = __STACKSTART__, size = __STACKSIZE__, file = "", define = yes;

   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.
   ; 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.

   ; 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.


   ; 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.
   BNE @noNoResetSkip

   ; The low byte is checked.
   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.
   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.


   ; 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.

   ; 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

   ; 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.

Available now: My game "City Trouble".
German Retro Gamer article:

Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 18 posts ]  Go to page Previous  1, 2

All times are UTC - 7 hours

Who is online

Users browsing this forum: No registered users and 2 guests

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group