So, from my previous post, I decide to tackle the problem doing the following steps:
- Set the VIC chip to use bank #2 instead – I’m choosing bank two because the standard character set is already available there, and since I’m not creating my own, I will have only to take care of the video memory and sprites.
- Tell the computer that my video is now in the new memory location
- Change my program to put the sprites in the new memory bank
1. Changing the VIC bank to be used.
To give you a better idea, here is the four VIC banks:
Bank #0: $0000-$3fff (0-16383) Bank #1: $4000-$7fff (16384-32767) Bank #2: $8000-$bfff (32768-49151) Bank #3: $c000-$ffff (49152-65535)
Banks #0 and #2 have the ROM characters set already defined at addresses 4096–8192 and 36864–40959 respectively , and since I’m won’t need a new one, the only choice I have is the Bank #2. If I had to use #1 or #3, I would have to copy the characters set from one of the other bank. Since the Bank #2 is good enough for me, I can save myself all the trouble of copying them.
This setting is controlled by the address $DD00 (or 56576 decimal). Depending on the bit mask set to this address, a different bank will be selected. The following bits have to be set in order to select the desired bank:
xxxxxx11 selects bank #0
xxxxxx10 selects bank #1
xxxxxx01 selects bank #2
xxxxxx00 selects bank #3
Some authors seem to use the banks numbering inverted, where bank from addresses $c000 to $ffff is called bank #0, $8000 to $bfff as bank #1 and so on. This actually makes sense based on the bit mask used to select the bank, but here I’m referring to them based on the memory address they are placed.
So, to select the VIC bank #2, I have to issue this command:
poke 56576,peek(56576) or 1
The next immediate step is to set the character set to be used as well as the one present at the address 36864–40959, which is in the same bank we are using now. To do that, we need to set bit #3 of the address 53272:
2. Tell the computer that my video is now in the new memory location
Although these two commands changes the VIC configuration, we still need to tell the KERNAL where is the new screen memory so it can do the screen input/output properly. For that, we need to change the content of the address 648 ($288), which hold the high-byte of the address of the screen memory (or its most significant 8 bits). In other words, the screen address is calculated like this:
screen_address = peek(648) * 256
By default, 648 holds the value 4, which multiplied by 256 gives the address 1024 ($400) which is the default screen memory address. Since we are using the bank #2, the screen memory address has to be moved to the same bank, at the address 32768 or 128*256. Therefore, we have to set the pointer to 128:
If you typed these commands one by one, the screen is probably all dirty now, since the kernal is using the new address, but this memory chunk has garbage. Just clear the screen and you’re good to go.
3. Change my program to put the sprites in the new memory bank
In my previous post, I was loading my sprites and setting its addresses considering the first bank (from 0 to 16383), but now I’m using another bank, and the sprites always have to be placed in the same VIC bank you are using for everything else. Here are the new places:
sprite #0 : address 48640 to 48702 sprite #1 : address 48704 to 48766 sprite #2 : address 48768 to 48830 sprite #3 : address 48832 to 48894 sprite #4 : address 48896 to 48958 sprite #5 : address 48960 to 49022 sprite #6 : address 49024 to 49086 sprite #7 : address 49088 to 49150
Remember when I said in the previous post that the last 8 addresses of the screen memory were actually the addresses telling where the sprites are? Because we moved from bank #0 to bank #2, I have also to update that. My screen memory starts at address 32768, therefore my sprite configuration starts at the address 33784 (32768+1024-8). These are the new values:
poke 33784,248 poke 33785,249 poke 33786,250 poke 33787,251 poke 33788,252 poke 33789,253 poke 33790,254 poke 33791,255
Also remember that the value to be set is relative to the bank we are using and must be divisible with 64. If we put the first sprite at the address 48640, we have to subtract the start of the bank #2 address (32768) and then divide the offset value with 64.
48640 (sprite #0 addr) - 32768 (start of the VIC bank #2) = 15872
15872 / 64 = 248
After this is set, all other VIC register to control the sprites will behave the same.
With this maneuver I could free a lot of RAM for the BASIC, but one more important step has to be taken. I have to tell the KERNAL where is the top of memory for the BASIC to use. This is important due to the way BASIC manages its variables. If we don’t tell that, the top will be somewhere in the middle of our bank #2, and as the memory usage for BASIC variables increases backwards, soon enough we gonna see our sprites being overwritten or other unpredictable effects.
For this particular program, I decided to set the top of RAM at the address 20479. To tell the computer this value, I have to set the addresses 55 and 56:
poke 55,255:poke 56,79 (where 79*256 + 255 = 20479)
If you set these values on direct mode, the top of the ram will be updated and the variables will allocate memory accordingly, but if the commands are issued from within a BASIC program, you also have to call the function CLR to clear all the variables. Doing so will make the KERNAL to start creating the new variables using the new top of RAM value. My program then, looks like this:
poke 55,255:poke 56,79: clr
I love how versatile the C64 is, but all this flexibility has its price, as we could see her.
Don’t forget to leave a comment!