memory map

To make everything work correctly I need to design and implement a memory map. A memory map is an organisation of addresses for different parts of the computer to use, such as the CPU, ROM, RAM and I/O.

The 6502 treats I/O and memory as the same, it doesn’t see them as different! This is in contrast to some other microprocessors (such as the Z80), that separate I/O and memory space. This is both an advantage and a disadvantage! The disadvantage is that the amount of space set aside for I/O reduces the amount of space for memory. The advantage is that you can have almost as many I/O devices as you want.

The 6502 can address a total of 64K of space. This means that there are 65536 locations, calculated by 2 ^ 16, as the 6502 has 16 address lines and therefore all addresses are 16 bits in size. Therefore it is up to the designer to decide how to divide up the 64K of address space. Therefore I need to decide how my RAM, ROM and I/O that my computer needs, will fit into that space. Without any I/O, the space could be split up with 32K of RAM and 32K of ROM. However, I definitely want plenty of I/O in my computer, therefore I will need to decide how to split the remaining space up for the RAM and ROM.

The address space that the 6502 uses is split into pages. There are 256 pages and each page is 256 bytes in size, ranging from page 0 to page 255. There are some special qualities of some of these pages, which will determine the placing of the RAM and ROM, with the rest free to do as I please with.

page 0

I will need some RAM space in the region of $0000 – $00FF. This is known as page 0 (also zero page and ZP). Some applications will need to use this space. Used for single-byte addressing.

page 1

I will need some RAM space in the region of $0100 – $01FF. Some applications will need to use this space. This page is needed for interrupts and subroutines. It will also be needed for saving to the stack, so that OpCodes for pushing to the stack (PHA, PHX, PHY), pulling from the stack (PLA, PLX, PLY, PHP) PLP, jumping to subroutines (JSR), returning from subroutines (RTS) and return from interrupt (RTI) can be used.

stack

The stack is a storage area that is used to store and retrieve values. The stack is used to track subroutine calls. The stack supports two operations: push and pull. Pushing a value takes it from one location and moving it to the stack. Pulling a value takes it from the stack and moves it to another location. The stack is hardcoded to the address range of $0100 – $01ff. Likes some other CPUs (Z80, 65816 and PowerPC), the 6502 uses a descending stack. A good way of understanding this is to imagine a stack of plates. If you need to remove a plate, you would remove the top one. This is the last plate that was placed onto the stack and is therefore known as a last-in-first-out (LIFO) stack.

Because the computer will start in an unknown state, one of the things that is a good idea is to set the stack to a known position. A good idea is to set the stack pointer to $01ff. Doing this means that we known that the stack will then start at the top and move towards $0100. The way to do this is to write code that stores the address that we want ($01ff) and move it to the stack, using an opcode that can transfer a value from a register to the stack (txs):

ldx #$ff
txs

you may have been expecting to see ldx #$01ff. This would work the same but is not necessary. This is because all stack values begin with 01 and can therefore be omitted.

accessing the stack

In 6502 parlence we say that we are pulling from the stack. Some microprocessors, such as the Z80 have a pop instead of a pull, so they say they are popping.

stack pointer

The 6502 has a register that is called the stack pointer. This is an 8 bit register and only needs to be 8 bits in size because the stack always resides in the address space of $0100 – $01ff. Since the stack will always begin with 01, we only need to store the least significant bit of the address that the stack points to.

reset and interrupts

Need $fffa – $ffff. These addresses contain the addresses of the reset routine and the IRQ and NMI ISR (interrupt service routine).

When the RST of the 6502 is pulled low and then brought back high, the 6502 starts its reset process, by getting the address to begin executing the program instructions from $fffc – $fffd.

When the NMI of the 6502 experiences a high to low transition, the processor will finish the instruction that is currently being executed and then retrieve the beginning address of the NMI ISR, $fffa – $fffb.

When the IRQ of the 6502 goes low and the I (interrupt disable) bit in the data register is clear, the 6502 finishes the instruction that is currently being executed and then gets to the beginning address of the IRQ ISR, $fffe – $ffff.

I want the memory map to have address decoding for the ROM to be in high memory, as addresses $F000 – $FFF. This is because the reset and interrupts are vectored through addresses at the top of memory.

I want the memory map to have address decoding for the RAM to be in low memory, at addresses $0000 – $7FFFF (32K). This is because zero page, index-addressing modes and the stack. This is because zero page and index-addressing modes need RAM at $0000 – $00FF and the stack is at addresses $0100 -$01FF.

The code for user programs usually starts in page 2.

page 255

The last 6 bytes of the last page of memory is used by hardware to contain special addresses. Two of these addresses are for interrupts (IRQ and NMI) and one if for the reset function.

conclusion

As can be seen, it is imperative that have RAM available for the zero page and page one. Taking this into account, I will place my RAM at the bottom of the address space.

I will place the ROM at the top of the address space. I see ROM as the most space-critical as I need enough space for my programs. Therefore I Would like to dedicate 32K to ROM and then split the remaining space between RAM and I/O. I have already decided that the ROM should be at the top of the address space, therefore the ROM needs to cover the 32K of space up to $ffff. This means $8000 – $ffff.

I now have the address spaces covering $0000 – $7FFF. RAM is critical for parts of my programs, such as routines. However, the space used would not be anywhere as large as the code needed for programs running in RAM. Therefore, I would like to dedicate 16K of space to RAM, which should be plenty. Since I have already determined that the RAM needs to be at the bottom of the address space, starting at $0000, I will place RAM at the address space of $0000 – $3fff.

What remains, I will use for I/O. There is 16k of space remaining, which I can use for I/O, at the address space of $4000 – $7fff.

As the computer design evolves, I may change some of this. For now, it gives a plan of what to design around this memory map.

My computer will use addresses within the range of 0000 – FFFF. This has been split up as follows:

RAM: 0000-3FFF
I/O:    4000-7FFF
ROM: 8000-FFFF