A couple of months ago, I bought a working Commodore 64 from a little website you may have heard of, eBay. Having regretted throwing my childhood machine away pretty much since the day I got rid of it, years and years ago, I thought it would be a worthy purchase that would bring me hours of rose tinted joy. Just shows you how wrong you can be, doesn't it? It sat in the box it was delivered in until about a week ago, when I unpacked it, and thanks to the joys of modern technology, got it working with my desktop PC.
One of the best things about the Commodore is that when you turn it on, it boots instantly into a BASIC interpreter; it practically begs to be tinkered and hacked away at. I spent far, far too many hours sat in front of a garish blue screen, fiddling away. I also made notes, in notebooks, on printed off screen dumps of code on a screechy old dot matrix printer, and thoroughly annotated my Commodore's BASIC programming reference guide. Boy, was I lacking a social life.
Hurry up man! I have seizures to afflict on infirm people!
Yes, quite. On to the point of this write up. When I got my Commodore, I dug through some of my old stuff, and found some of those notes, and so I can present you with the following code. It flashes coloured bars in the border of the screen at a speed that would cause the average person to have a seizure, until a key is pressed. Unfortunately, I no longer have much of a clue as to how or why it works. But I'll make some educated guesses in a moment.
The source code in question
10 FOR I = 0 TO 23
12 READ A
14 POKE I+49152,A
16 NEXT I
18 DATA 162, 000, 142, 032, 200, 232, 160, 000, 200
20 DATA 192, 035, 208, 251, 032, 228, 255, 201, 000
22 DATA 208, 002, 076, 192, 096
24 SYS 49152
How it works: some idle speculation
As with all the really cool stuff you can do with a Commodore 64, it works by using the POKE command to manually manipulate memory addresses. The main portion of the code is located in lines 10 to 16, which is a loop that runs twenty-four times. Each time the loop is run through, the following occurs:
- The READ command reads the next unread value from the block of DATA stored within lines 18-22, and stores it in the variable A.
- The value of A is then POKEd (put into) the memory address at the location numbered 49152 + I that is to say 49152 to 49176, in sequential order.
- The loop's iteration counter, I is incremented.
The lines at 18 to 22 contain DATA
statements, which are just that - blocks of data that are read back in order by the READ
command. It is these values that get placed into memory addresses by the loop. The SYS
command on line 24 tells the computer to start executing whatever it finds at the given memory address
, namely 49152, which you may have noticed is the first address we placed some data into.
How all this relates to making hallucinogenic light shows, I can only guess. Normally, you can only assign the border to be one solid colour, and yet this programme places multiple colours in the border. From this bit of evidence, I would speculate that the memory addresses we modified are actually the addresses that correspond to the colour values used by the onboard graphics card, and so by setting these screen output values manually, we are placing things on the screen that the Commodore has no control over.
Now, that seems to take care of the flashing bars - I'm reasonably confident that by manipulating the graphics portions of memory we can achieve that effect, most likely by modifying the palette with an interrupt register that's tracking the video output. What I'm less sure about is the fact that the programme runs until you press a key, and then stops. This could be a side effect of the SYS command, but I don't think so. I'm truly stumped, so if anyone knows, I'd appreciate a /msg.
An inbox full of /msgs later...
Well, it looks like I was half right, and indeed half wrong. Whilst I thought we were POKEing values straight into the graphics part of memory, the consensus seems to be that we are actually writing a little assemby language programme that is going to play with the colours for us:
gn0sis says Unless I'm very much mistaken, the data is in fact a program in 6502 assembly language, which is just poked into memory and then executed by calling SYS.
had the same idea, as did the fantastic lj
, who even went as far as to decompile
it for fun and profit:
lj saysThis is what I think it disassembles to:
LDX #00 / STX c820 / inx / ldy 00 / iny / cpy 23 / bne fb / jsr e4, ff / cmp 00 / bne 02/ JMP c0 60
LDX#00 / STX C820 / inx seems to write to the pallette, ldy 00 / iny / cpy 23 / bne fb is a delay loop, and jsr e4, ff / cmp 00 / bne 02/ JMP c0 60 is the 'press a key to quit'.
The bne 02 may be a bit of a hack, as it appears to be jumping halfway into the middle of the next instruction - if the jump is taken, the pc jumps to the 60 from JMP c0 60, which is interpreted as RTS, which should return execution to says the start of the program? (My 6502 is very rusty indeed). If the jump isn't taken, execution progresses to JMP c0 60, which jumps to c060, which is presumably full of 00s, which the processor interprets as a break (BRK), and returns to the basic interpreter. I think.
If I'm right, changing the 035 should alter the rate at which the colours change. Removing 032, 228, 255, 201, 000, 208, 002 should cause it to either quit immediately or not quit at all (I haven't quite figured out if the final jump instruction loops or quits. If pressed, my money would be on loops, so removing. Those seven bytes will make it display trippy colours forever.
Phew! What a guy! Much hacking kudos to lj there! And finally, I'll leave you with jasstrong and koala, who are going to explain why the border is broken up into those mind bending stripes. It's all about rasters, y'see:
jasstrong says Your commodore code puts more than one colour in the border because it changes the colour while the screen is still being drawn. Remember that the CRT face is scanned from the top left downwards, 50 times a second.
koala says the code is just assembler code which checks the keyboard buffer, if there is a key, stops. If not, it changes the color of the border of the screen (memory position 53280/1 IIRC) and loops. The thing is that the screen is refreshed in a sweep, so the change happens anywhere in the sweep. If it happens a lot of times during one frame, there you have it, multiple colors on the border. The sys command just jumps to the assembly code at 49152.
Thanks guys! See? It's easy when you know how. Perhaps I should learn 6502 assembly language for my next little project...