Friday, May 16, 2014

6502 Pointers

Pointers are one of those programming subjects that tend to confuse people yet once understood is really fairly simple. If you have been following my NES series of articles, the following code is probably easy to understand:

        LDY #0
CopySpriteData:
        LDA SpriteData,Y
        STA $200,Y
        INY
        BEQ CopySpriteData
        RTS

SpriteData:
        ; 256 bytes of sprite data go here

This code simply copies 256 bytes of data from SpriteData to the second page of 6502 memory. The fact that when a byte overflows it wraps around and becomes 0 again is used to terminate the loop. This code seems easy enough. The LDA instruction is using the address SpriteData is at, then adding the Y register to that value to come up with the memory address to grab the byte being copied from. Likewise, the STA is using the memory address $200 and adding the Y register to it to find the address to store the byte.

Pointers work pretty much the same way but instead of directly using an address, the address is stored in a pair of zero page addresses. Why would you want to do this? By having pointers to addresses instead of hard-coding the address you can create general-purpose functions. The caller would simply fill in the pointer with the address the function is suppose to use then call the function. The 6502 expects addresses to be written in a low to high format meaning the low-order byte is followed by the high-order byte. This is known as little-endian format. For NES developers this can be confusing as the PPU uses high/low (big-endian) for specifying addresses. To demonstrate pointers, here is a simple MemCpy function.

MemCpy:
        LDY #0
MemCpy_loop:
        LDA [SOURCE_PTR],Y
        STA [DEST_PTR],Y
        INY
        CPY COPY_LENGTH
        BNE MemCpy_loop
        RTS

The Y register is zeroed out before the loop. The byte at the address pointed to in SOURCE_PTR offset by  Y is loaded into the accumulator. This value is then stored at the address pointed to by DEST_PTR offset by Y.  The Y offset is increased and the loop continues until Y is equal to the value in COPY_LENGTH.

This works, but the amount of effort required to set up the zero-page pointer variables requires more instructions than the actual function. A more complex function, such as a MemCpy function that supported 16-bit copy-lengths would be worth doing. Likewise, when you are dealing with addresses that you may not know beforehand, such as will be the case with the general-purpose prompt routines we will be developing, using pointers to data is incredibly handy.

The use of pointers is something that will be used quite a bit as we progress. Our Trivia game will be needing strings and some type of way of selecting a choice so that is what we will be focusing on next.

No comments: