2007-05-13

Progress So Far

Things I’ve learnt about the 6502 so far:

  • Memory in the range $0000-$00FF is called “zero page” memory. This can be accessed much faster than any other memory because the addresses are all 8-bit. This means that the 8-bit CPU can process the address in one go, instead of needing to process the second byte in a 16-bit address.
  • Memory in the range $0100-$01FF is used as the stack (this is why most of the programs I’ve seen so far locate themselves at address $0200 - it puts them past both the valuable zero page RAM and the unpredictable system stack).
  • Memory in the range $FFFA-$FFFF is used by the three interrupt commands.
  • The CPU supports several different addressing types (about 13, I think), all of which are far too tedious to detail here.

One thing I haven’t found out is how to get the memory address of a label. Say we have to following code:

        .ORG $0200      ;Locate asm at $0200

CODE    JSR LOAD        ;Jump to LOAD subroutine
        BRK             ;Stop running

LOAD    LDY #$1         ;Load 1 into Y register
        LDA ($30),Y     ;Load data in 1st byte after address in $30 into acc
        RTS             ;Return from subroutine

LIST    .DB #$20        ;Define a list of bytes
        .DB #$04

At the label “CODE”, before the subroutine jump, I want to load the address of the list into memory address $30. That way, my “LOAD” subroutine is completely generic. I can define as many lists as I like (each with different labels, natch), and I can call the “LOAD” subroutine on any of them as long as I load the list’s start address into $30. I’d expect to be able to do this with the commands:

         LDA LIST       ;Load the address of list into the accumulator
         STA $30        ;Store accumulator into address $30
         LDA LIST+1     ;Load other byte of address into acc
         STA $31        ;Store accumulator into address $31

The bytes are probably the wrong way around as the little-endian-ness hasn’t quite sunk in yet. Anyway, that doesn’t work - what happens here is that LIST is treated as an absolute memory address (a pointer), and the first LDA command loads the first list item into the accumulator (in C terms, it automatically dereferences the pointer and gives me the data). There doesn’t seem to be any way to get at the actual address of the list. So how am I going to make my generic list subroutine? I have no idea. I imagine it involves more reading.

(A few minutes later)

Oh, no - it’s actually quite easy. At least, it is in the “6502 Simulator” Windows program I’m using to code with. The code should look like this:

         LDA #<LIST     ;Load low byte of LIST into acc
         STA $30        ;Store low byte at address $30
         LDA #>LIST     ;Load high byte of LIST into acc
         STA $31        ;Store high byte at address $31

Prefixing a label with a hash turns it into an immediate number instead of an absolute memory address (ie. we can get the memory address instead of treating it as a pointer and retrieving the data pointed to by the label). Using the greater than/less than symbols allows us to extract individual bytes from the 16-bit address.