VIC-20-CUSTOM-CHARACTERS-WORLD-{GFX-ELEMENTS} -------------------------------------------------------------------------------------------------- TOOL: COMMODORE VIC-20 - BASIC 2 Language: BASIC Extra: - Author: Misel Zivanovic Note: (C) 2nd JAN 2026 - www.lived.ch, mzretro.ch --------------------------------------------------------------------------------------------------- VIC-20 obviously has no hardware sprites in 1981! Even if those existed already in 1977! {I bet many managers were driven by just one sentence back then: to avoid the cost of the...!} Well, VIC-20 sold over a million times! Imagine it with the hardware sprites and 16KB RAM in 1981! 10 million sold VIC-20! What the hell, NO! 50 million would have been a minimum number! Imagine our life would be a game with a restart button, haha... Okay, down to reality and to what we came for: CHARACTERS! Usually, all characters are in ROM, which is Read Only Memory. To be able to modify it, we have to transfer them to RAM area and then also set the pointers properly so the system can see the new location and be able to put those characters on the screen instead of those in ROM. As long as things are located in RAM area, they can be modified and the is actually the whole point of this characters-transfer game. Now imagine following dilema back in 1981! You bought VIC-20 and want to transfer all characters to RAM because you saw in one of computer magazines how it can be done. ...and then you notice: ROM characters are 4KB and your VIC-20 had just 3.5KB! OH YEAH! Now you have 2 options: 1. buy expensive RAM update {cartridge} 2. limit the transfer to 2KB and therefore also have less freedom in creativity {you need the alphabet, numbers and what's left is then 'freedom} Because there were no sprites, you had to use characters for animations. The less characters you have, the less you can do. Not to mention the 1KB free RAM... Was enough for Hello World, that's for sure! That is why I say the Commodore Management did a shitty job with just 3.5KB memory Especially because not everyone was willing to spend money on extra RAM and then people were facing the 'freedom' & creativity problems back in the days. Well, it is close to 45 years later and thanks to emulators, RAM is quickly added within seconds. However, we won't stretch it to full size of 48KB. We will just add 3KB RAM to existing {free} 3.5KB {Well, it's actually 5 + 3 = 8 x 1024 bytes = 8192 bytes. However the system is taking from and also the screen} RESULT IS 6655 BYTES FREE {FOR BASIC PROGRAMMING} In case you want to know where is this number coming from, it's easy to explain: BASIC END { PRINT PEEL(55)+PEEK(56)*256 = 7680 } BASIC START { PRINT PEEK(43)+PEEK(44)*256 = 1025 } { TOTAL = 6655 BYTES } I was wondering why this numbers were coming, because 7680 is actually the first SCREEN address! As it looks, the Mr. Kernal is setting its pointers 1 Byte lower, which makes it then compatible {7679} and is not interfering with the SCREEN content! Now we will transfer 128 characters from ROM to RAM. That makes exactly 1024 bytes, or 1KB. Or it can also be called 4 pages. And because 1 page is 256 bytes, 4 are 1024 bytes or again 1KB. That is the space we need to keep our characters safe from BASIC. We will grab this 1KB memory below 7680, lowering the default value HIGH BYTE {56} down to 24 which is then 4 pages or 1KB. {In fact the first possible location is 7168 for custom characters, however only for 64 of them} {Because we need 128 characters, we must go down to the next possible address, which is 6144} {Check COMPUTE! Mapping the VIC-20, page 154 for more details} LOCATIONS OF THE ROM Characters: : |----------------------------------------------------------| | Default POINTER to ROM CHARACTERS : POKE 36869,240 | | WHEN AVAILABLE MEMORY IS BELOW 8KB! | | IF IT IS ABOVE 8KB = POKE 36869,192 | | CHARACTER ROM IS 4KB BIG and divided in 4 zones: | |----------------------------------------------------------| | CHARACTER SET 1 & GRAPHIC SET | |----------------------------------------------------------| | Uppercase and graphics non-reversed screen character map | -> RVS OFF -> { NO } SHIFT/COMMODORE KEY |----------------------------------------------------------| | Decimal | Hexadecimal | | 32768 - 33791 | $8000 - $83ff | |----------------------------------------------------------| |----------------------------------------------------------| | Reversed uppercase and graphics screen character map | -> RVS ON -> { NO } SHIFT/COMMODORE KEY |----------------------------------------------------------| | Decimal | Hexadecimal | | 33792 - 34815 | $8400 - $87ff | |----------------------------------------------------------| |//////////////////////////////////////////////////////////| |//////////////////////////////////////////////////////////| |----------------------------------------------------------| | CHARACTER SET 2 & TEXT SET | |----------------------------------------------------------| | Lowercase and uppercase non-reversed screen character map| -> RVS OFF -> SHIFT/COMMODORE KEY |----------------------------------------------------------| | Decimal | Hexadecimal | | 34816 - 35839 | $8800 - $8bff | |----------------------------------------------------------| |----------------------------------------------------------| | Reversed lowercase and uppercase screen character map | -> RVS ON -> SHIFT/COMMODORE KEY |----------------------------------------------------------| | Decimal | Hexadecimal | | 35840 - 36863 | $8c00 - $8fff | |----------------------------------------------------------| --------------------------------------------------------------------------------------------------- LEGEND: --------------------------------------------------------------------------------------------------- Comment: I had no idea if this part is 100% correct, but it is working! And showing the end of available RAM is 6144 and not 7680! Can be checked with this 2 lines: print peek(641)+peek(642)*256 print peek(643)+peek(644)*256 POKE 51/52,X : Pointer to the bottom of BASIC active strings {Low-High-Byte} POKE 55/56,X : Pointer to the end of BASIC memory {Low-High-Byte} POKE 643/644,X : Pointer to the end of user RAM memory plus one. X = Page{s} : 1 Page is 256 bytes! {I think we now that by now, Haha} We made room 4 Pages! OLD CHAR-SET : POKE 36869,240 --------------------------------------------------------------------------------------------------- This is what we are doing: --------------------------------------------------------------------------------------------------- RAM TOP is 6144 <, FONT START IS 6144 > 128 CHARACTERS, 1024 KB -> 7168 REMAINING RAM : 5KB SCREEN START/END : 7680 - 8186 CURSOR start/END : 7424 - 7431 {Position 160 = 160x8+6144 } FREE MEM START/END : 7169 - 7679 {512 bytes for e.g. assembly code, but also 64 characters! } {if you don't need more. That gives you 1KB more BASIC memory! } --------------------------------------------------------------------------------------------------- Alright, after many months of theory, here is the code! It will secure the space from 6144 until 7168 and set the correct pointer {which is 254} = POKE 36869,254 POKE 36869,PEEK(36869) AND 240 or 14 {240 is default value, 14 is added to existing value = 254} You know that it is 14 because decimal value for the location 6144 is 14. {Check COMPUTE! Mapping the VIC-20, page 154 for more details} I actually find it very strange how VIC-20 has only 4 locations reserved for the custom characters. And that you cannot take the full advantage of 48KB of RAM to write a BASIC program. Maximum is 24KB and the rest you can use for other things like Assembler code or data in general, like game level data etc. 1. $1000, dec 4096 {12} 2. $1400, dec 5120 {13} 3. $1800, dec 6144 {14} -> what we are using {and it leaves us 512 byte from address 7168 until 7680! 4. $1c00, dec 7168 {15} -> only 512 byte free! Enough for 64 characters until 7680 = Screen matrix 506 bytes Accordingly this is how we got the number 254: POKE 36869,PEEK(36869) AND 240 or 14 Next, We jump over @ {+8} and start with the following 6 characters {ABCDEF} to make some gfx {AB,CD, E, E} Additionally, also the Cursor was slightly modified because we didn't load it from ROM {position 160 and we imported from ROM just 128 characters} Not to see it as a garbage {representing whatever information there was}, the meaningful information was added to that locations and we have a little sweet cursor! Have fun! --------------------------------------------------------------------------------------------------- SOURCE CODE {can be copy/pasted into VICE VIC-20 Emulator} - GRAPHICS ELEMENTS --------------------------------------------------------------------------------------------------- 10 a=643:b=644 11 poke51,0:poke52,24 12 poke55,0:poke56,24 13 poke a,0:poke b,24 14 clr 15 sys 58719:rem cls 16 poke 36869,254 17 poke 646,7 18 poke 36879,8 19 t=6144:s=32768 20 for a=0 to 1023 21 poket+a,peek(a+s) 22 next 23 forc=0 to 47:readd 24 poket+8+(c),d:next 25 data 127,144,255,128,136,255,132,127 26 data 254,33,255,137,129,255,17,254 27 data 255,192,191,181,170,191,192,255 28 data 255,3,253,85,173,253,3,255 29 data 126,195,165,153,153,165,195,126 30 data 126,171,213,171,213,171,213,126 31 rem cursor 32 poke 7424,129 33 poke 7425,129 34 poke 7426,129 35 poke 7427,255 36 poke 7428,126 37 poke 7429,126 38 poke 7430,255 39 poke 7431,126 40 print "ab ab ab" 41 print " cd cd" 42 print "eeeecdffff" --------------------------------------------------------------------------------------------------- NOTE THE USAGE OF VARIABLES and CLR command! CLR is DELETING variables! don't set any variables BEFORE CLR which you attend to use AFTER the execution of CLR because the values will be gone and your program won't work! --------------------------------------------------------------------------------------------------- 10 a=100 20 b=100+a 30 clr 40 print b RESULT is 0, but you would probably expect 200! So pay attention here! ---------------------------------------------------------------------------------------------------