C64 MEMORY MAPS
Written by T.M.R of Cosine
Okay, welcome to part two in an ongoing series to bemuse and confuse would-be C64 coders as to how the machine works!
The C64 is, like all other 8-bits, a unitasking environment; because of this, any program running normally doesn't have to make many special concessions to the system as regards memory use or processing. In fact, as the system becomes more familiar it's possible for a programmer to kick the C64's operating system out and use the memory that the ROM chips sit over.
Quick And Dirty Memory Map
The best way i've found to talk about the memory is to do my virtual tour guide routine; in other words wandering through the RAM, highlighting points of interest on the way. However, this isn't a definitive guide and anybody taking this seriously should by now have a download of the C64 Programmers Reference Guide from Project 64 for more detail.
Before i wander off, the C64 has one unique feature in that the VIC-II video chip sees the RAM in four possible blocks, referred to as banks. i'll highlight the change from bank to bank as it happens, but for easy reference they're called banks 0 to 3 and located at $0000-$3fff, $4000-$7fff, $8000-$bfff and $c000-$ffff respectively.
The zeropage is a common feature of 6502 microprocessors (the C64's 6510 is a variant of the '02) and some people find it very useful. The zeropage's main advantage is that any transaction with it takes one cycle less than the rest of the RAM (since it's possible to use sta $fe as opposed to sta $00fe) but the down side is that the C64 needs most of it for general operation. The most commonly used spaces are at $02, $50 to $57 and $fb to $ff.
The stack, used to store... erm, vectors and stuff. When a program calls a subroutine, the present position in the program is shoved to the stack for later retrieval.
This is all sorts of odds and sods used by the C64's Kernel and BASIC (the operating system essentially); it's a mixture of temporary stores, buffers and pointers to other parts of the system. Amongst other things, the Kernel's IRQ and NMI interrupt pointers are knocking around here.
The tape buffer, two thirds of a page of free space. i've taken to using it for labels in my programs because it's convenient.
The default C64 screen; 1000 bytes are dedicated to the screen itself (40 bytes across by 25 down) and the final 8 bytes of the 1K block are for the sprite pointers. The screen can be relocated in memory (although the system will keep pointing at the $0400 screen until it's told otherwise as well) but always defaults back to $0400 when the machine is warm started in any way.
Free memory, for all your programming needs. BASIC programs start from $0801 and head upwards.
More free RAM but with a difference, there's a shadow of the ROM character set over the top of this space (one character set is 2K and there are two sets for upper and lower case). Although program data can be stored in this space, the C64 can't see graphics placed here because the shadow of the character set always appears instead.
Back to the normal free RAM, running up to the back end of video bank 0.
Video bank 1. This is the most accessible of the video banks, a clear 16K of space with no ROMs shadowed over it and conveniently placed for the shops and railway station. Erm, conveniently placed for use as a graphics store.
The start of bank 2 and a block of 4K all ready for graphics use.
Another shadow of the ROM character set, as before program data will work in this space but graphics will appear as the system's character set.
This RAM can be used for graphics but contains a shadow of the C64's BASIC ROM when the machine is in it's default state so program code can't be run here. It's possible to switch out the BASIC ROM (the lowest bit of $01 controls the banking) and run code in this space if BASIC isn't going to be used. This is also the back end of bank 2's RAM.
A small block of generally free RAM at the start of bank 3.
The registers for the VIC-II, SID, the communication chips and stuff. The VIC-II will be covered in more detail after the main map. This space can, as with the BASIC ROM, be utilised for graphics and it's possible to bank the chips out and run program code in their space too although any writes will be to the RAM rather than the chips themselves.
This is where the Kernel ROM lives; the Kernel is the core of the system (hence the name) and it provides useful routines, for example interrupt handling, disk operations (slow ones, it has to be said) and character output routines. Once more, the Kernel's RAM can be used for graphics data with no trick; the only thing to watch out for is there are some interrupt vectors right at the top of the memory. As with BASIC, this ROM can be banked out to allow program code to run from it's memory but unlike BASIC it's a more complex job; the Kernel handles the system IRQ interrupt so if it's just banked out the system falls on it's bum!
Commonly Used Registers
As a finale, a more indepth coverage of the registers that tend to be used the most, the VIC-II (and one CIA) registers that handle the C64's graphics.
These seventeen registers supply the sprite positions; the first two are X and Y for sprite 0, the next two do sprite 1 and so forth until $D00F. $D010 is the Most Significant Bit (or MSB from here onwards) for the eight sprite X co-ordinates, the lowest bit for sprite 0 and the highest for sprite 7.
This register does a lot of jobs, bits 0 to 2 control the vertical smooth scroll position and has a range of $0 to $7. Then bit 3 is 25/24 row mode (hardware clipping essentially), bit 4 turns the screen off, bit 5 enables bitmap mode, bit 6 enables extended background colour mode and bit 7 is the MSB for $D012, the raster register. One useful quirk is that if extended background colour mode and bitmap mode are turned on at once, the screen goes black; this can be used for masks and so forth since the screen can only be turned off at the very top.
The raster register has two uses; it can be used to check for the position of the raster simply by reading it ($00 is the top of the screen and $32 to $fa is where the text area appears). $D012 is also written to during raster interrupts and becomes a trigger for the IRQ so when it reaches the written value an interrupt occurs. Since the raster passes through more than 256 lines on a PAL machine, the MSB is the highest bit of $D011 to give it that extra range.
$D013 and $D014
Used to read lightpens or light guns; the horizontal register has to be multiplied by two to get the relevant screen position.
Sprite enable register; the eight bits of this register represent the eight hardware sprites, set a bit to enable a sprite.
Another combo register like $D011, the lowest three bits are the horizontal smooth scroll again with a range of $0 to $7. Bit 3 enables 38 or 40 column mode (again, hardware clipping), bit 4 fires up multi-colour character mode for those lovely, chunky pixels, bit 5 should always be zeroed and bits 6 and 7 serve no purpose.
Sprite vertical expansion register, just like the enable register in that each sprite is represented by a bit, setting that bit makes the sprite double in height.
This register controls where the VIC-II looks for character definition and screen data in the current video bank. The lower nybble specifies where the character set is, simply multiply by 1024 and offset into the current bank to work out where it is (since character sets are 2K long, the lowest bit is ignored). The upper nybble points to the screen, once again multiply the value by 1024 and offset by the bank.
Loads of functions under one roof, this time used for saying which VIC-II based event triggers IRQ interrupts; bit 0 is the raster compare flag, bit 1 the sprite top background collision, bit 2 for sprite to sprite collisions, bit 3 looks for the lightpen and finally bit 7 gets set whenever any VIC-II related interrupt occurs.
The IRQ mask register, the lowest bit says if the IRQ is enabled.
Sprite to background priority. As with the enable register, one bit represents one sprite. An odd quirk with this register is that one of the multi-colours never takes priority over sprites so any background detail in that colour always remains behind the sprites.
Another byte that uses a bit per sprite, this time it enables multi-colour mode.
The horizontal sprite expansion register; set the bits to double the width of the sprites.
Generally speaking, the sprite to sprite collision register is a bit of a chocolate teapot because all it does is flag when a collision has occurred. If four sprites collide their relative bits will be set but there's no way to tell which sprites have collided with which; sprite 0 may have collided with sprites 1, 2 or 3 or any combination of the above. Most game coders write their own co-ordinate checks instead.
The sprite to background collision works like the sprite to sprite register; one bit representing each sprite which sets if a collision occurs. As with the priority register there's a quirk in that one of the two multi-colours doesn't register as a collision. This register is, however, a damn sight more useful than the sprite to sprite register.
$D020 and $D021
The lower nybble of these registers set the border and screen colours respectively.
The three multi-colour registers, again the the lower nybble sets the values. $D024 is only ever used in extended background colour mode.
$D025 and $D026
Sprite multi-colours; when the multi-colour mode is enabled, these two registers control the shared colours.
Eight registers controlling the colours for the eight sprites.
Not strictly a C64 register, but it should always be set to $00 because the C128 uses it as a flag to enable 2MHz mode. That may sound a good thing, but the VIC-II gets scrambled when that happens and 2MHz mode takes a little more dealing with than simply setting the register.
This one is actually a register aboard CIA 2 (one of the communications chips) but it's lowest two bits also control which bank the VIC-II is looking into for it's data. The bits are reversed so %11 is the lowest bank and %00 the highest. Because this register has a few other functions, it's best to not write directly to it and instead read the register, AND off the other bits and OR in the ones you're wanting to set before writing back.
The Programmers Reference Guide is kept online by Project 64
The VIC Article is available from Fairlight Tools
This article originally appeared on the UKScene website in October 2002.