Rita en cirkel på Commodore 64

Det finns ett meme som visar hur omständligt det är att programmera BASIC på Commodore 64 (C64). Bilden visar den kod som krävs för att rita en cirkel på skärmen på en C64, jämfört med den kod som krävs för att rita en cirkel på skärmen på Sinclair Spectrum.

Om du skummar igenom koden i bilderna, så noterar du säkert två saker: C64-versionen är onödigt pratig och Spectrum-versionen lider lite av att skärmupplösningen är aningen lägre än C64-versionen (256*192 pixlar jämfört med 320*200 pixlar).

Denna kod är galet långsam, men det är det kortaste jag har lyckats åstadkomma för att rita en cirkel på C64:

10 POKE 56,32:POKE 52,32
20 CLR:POKE 53272,25
30 POKE 53265,PEEK(53265) OR 32
40 PRINT "{CLEAR}"
50 POKE 88,0:POKE 89,63
60 POKE 113,64:POKE 114,31
70 POKE 12,1:SYS 45760
80 FOR A=1 TO 7.3 STEP 0.01
90 X=COS(A)*20
100 Y=SIN(A)*22
110 XX=159+4*X:YY=99+3*Y
120 ROW=INT(YY/8):CH=INT(XX/8)
130 LINE=YY AND 7:BIT=7-(XX AND 7)
140 BYTE=8192+ROW*320+CH*8+LINE
150 POKE BYTE,PEEK(BYTE) OR 2^BIT
160 NEXT
170 GOTO 170

Detta är resultatet:

Jag skulle tro att orsaken till denna skillnad är att C64 egentligen är en spelkonsol, utklädd till dator. C64 var vid lansering utrustad med extra allt inom ljud och grafik, och för att spara minne slängde man in en äldre version av Commodore BASIC, nämligen 2.0 (second release). Samma som VIC-20, men ett par versioner lägre än den PET. Den enda anledningen till att C64 faktiskt hade en BASIC och ett tangentbord var att man behövde ett säljargument, som tyvärr inte är mer sofistikerat än Annika Strandhälls försvar för iPads i skolan – man blir ett datageni! En skillnad är möjligtvis att det var lägre hängande frukt att lära sig programmering på en hemdator 1982 än det är att lära sig programmering på en kontemporär Facebook-maskin från Apple. Sinclair Spectrum (också 1982) däremot, var en ytterst begränsad dator. Att de barn som fick den skulle lära sig programmering, var på allvar ett viktigt skäl att köpa datorn. Den behövde ha en seriös BASIC! (Jag själv lärde mig BASIC på föregångaren Sinclair ZX81.)

Commodore 128 hade all den kapacitet ljud- och grafikkapacitet som C64 hade, men till skillnad från C64 hade den även kommandon och verktyg som lät användaren dra nytta av den kapaciteten, utan att behöva programmera maskinkod. 128-användaren fick tillgång till en bra BASIC och en drös inbyggda verktyg. Programmet som ritar en cirkel på Commodore 128 är inte helt olikt Spectrum-programmet i memen ovan:

10 GRAPHIC 1,1
20 CIRCLE 1,159,99,60,60

Och även om vi inte hade CIRCLE-kommandot, så blir koden betydligt kortare än C64-versionen, eftersom vi kan ändra grafikläge och sätta individuella bildelement direkt från BASIC. Så uppgiften är inte särskilt svår ändå. Man betalar för lyxen genom högre minneskrav, men denna lyx ansåg man inte att målgruppen för C64 var intresserad av.

Två nya SID-låtar

Jag har slängt ihop två nya SID-låtar som kan avnjutas på din Commodore 64.

Den ena (the_roger_boogie.sid) är ett resultat från ett demo-jam på jobbet tillsammans med Klas Dahlén, Roger Johansson och Erik Sandberg. Den är egenkomponerad och använder en samtida playerrutin (SID 8580). Förhandsgranskning finns på YouTube.

Den andra, som är en cover på låten I Touch Myself av Divinyls, slände jag ihop igår kväll. Den körs på en rutin som är anpassad till den gamla brödburken (SID 6582).

Ladda gärna hem filerna här!

Plotting graphics

The Commodore 128 has a nice API for setting graphics mode and plotting graphics, that can be used in 40 column mode. The GRAPHIC command takes a mode (0 to 5) and a “clear screen flag”, and changes the current graphics mode. 0 is the 40 column text mode and 1 is the high resolution monochrome graphics mode. This program sets a few random pixels on the screen using the DRAW command:

10 GRAPHIC 1, 1
20 FOR A = 1 TO 100
30 DRAW 1, RND(1) * 320, RND(1) * 200
40 NEXT A

When the program is run, the text is hidden, so to retain the text cursor, just type GRAPHIC 0 and hit Enter. If you like, you can add this to your program.

The Commodore 64 does not provide any API for graphics, so on the C64 this task is accomplished by manipulating bits in a memory area. You can jump to graphics mode by setting the bit 6 on byte 53265 to 1 and return to text mode by setting it to 0. While plotting, you must make sure you know how to handle bit patterns. The screen area can be located at 8192 if we set a flag for this (bit 4 at byte 53272), like so:

10 POKE 53272, PEEK(53272) OR 8

The screen consist of 8000 bytes, so in this case from 8192 to 9191. Then, enter graphics mode:

20 POKE 53265, PEEK(53265) OR 32

Now we don’t have the service to get a clean color map (that is Commodore 128 luxury), so random boxes (8×8 pixels) will have strange colors. No worries, this is expected.

Finally, these lines of code will draw a few horizontal lines in the upper left 8×8 pixel area:

Set graphics mode

30 POKE 8192, 255
40 POKE 8193, 0
50 POKE 8194, 255
60 POKE 8195, 0
70 POKE 8196, 255
80 POKE 8197, 0
90 POKE 8198, 255
100 POKE 8199, 0

Click to view

When the program has run, you will not see the text cursor, but to restore everything, type:

POKE 53272, 21
POKE 53265, 27

…and our horizontal lines will be gone and the text cursor is back.

Restoring.

Let’s make the screen flash!

This program will make the screen flash on the Commodore 128, and it will also run on the Commodore 64. The background color of the screen is stored at D021 (53281), so this effect is accomplished by manipulating the value at that address, multiple times. This program cannot be written in Basic, because the Basic interpreter is too slow.

Remember that the machine code monitor expects code in one format, and displays it in another, so what I show here, is what I actually type in. I will write my program at location 1000 (4096) in the memory. Type MONITOR to enter the machine code monitor, and type F 1000 1100 0 to create some free space.

To begin writing code, type . directly followed by the address you want to add an instruction to, followed by the instruction and the desired parameters. This stores what you just typed in, and expects you to type in the next command, or just hit Enter to exit the edit mode.

.1000 LDA #$01
STA $D021
NOP
NOP
NOP
LDA #$0B
STA $D021
NOP
NOP
NOP

(and so on…)

Let the final command in your program be JMP $1000.

Press Enter to exit edit mode, type X and Enter to exit the monitor. Start your program by typing SYS 4096. Your screen should now be flashing hysterically!

On the first row, .1000 tells the Commodore 128 machine code monitor that I want my program to start at address 1000 (4096). LDA loads a value to the accumulator, and STA stores current value in the accumulator to the given memory address, D021 (53281). The specific memory address D021 controls the background color. NOP means “no operation” and is used only to make the effect less hysterical. Finally, JMP jumps to the given address, creating an infinite loop. Who needs fireworks now?

Positioning sprites on the Commodore 64

The task of positioning sprites on the C64 holds one particular oddity that I want to show. To be able to position a sprite on screen, you must master binary logic on the C64, and binary logic works in the same way as on the Commodore PET, shown here. Also, you need a visible sprite. The following code does the trick. If you don’t own a Commodore 64 and don’t have an emulator, the code also works in JaC64, an on-line C64 emulator implemented as an Java Applet. However, I can’t get the cursor keys to work in JaC64, so don’t mistype anything! 😉

10 FOR I=0 TO 62
20 POKE 704+I, 255
30 NEXT I
40 POKE 2040, 11
50 POKE 53287, 1
60 POKE 53248, 200
70 POKE 53249, 200
80 POKE 53269, 1

The Y position of the sprite is stored at D001 (53249). You have 256 possible Y positions, but the visible area of the screen is only 200 pixels high. All you need to make the sprite cycle over the screen is some iteration that copies the values 0 to 255 to the D001 address.

The X position however, is a bit more tricky. The X coordinate is stored at D000 (53248). But we need more than 256 possible positions to be able to place the sprite on the right side on the screen. Commodore did not waste a whole byte on solving this problem. At D010 (53264), the first bit keeps track on if D000 holds a value that represent the left part of the screen, or the right part of the screen for the first sprite (sprite 0). We have eight sprites and eight available bits at D010, so the second bit keeps track on if D002 (53250) holds a value that represent the left part of the screen, or the right part of the screen for the second sprite (sprite 1), and so on. So this is what we must do to make the sprite we displayed in the above program run over the screen:

Iterate from 0 to 255, set the value to D000 (line 10-30). Set the first bit at D010 to 1 (line 40). Iterate from 0 to 255, set the value to D000 (line 50-70). Restore the first bit at D010 to 0 (line 80). Repeat from the beginning (line 90).

Type NEW to delete your current program.

10 FOR I=0 TO 255
20 POKE 53248, I
30 NEXT
40 POKE 53264, PEEK(53264) OR 1
50 FOR I=0 TO 255
60 POKE 53248, I
70 NEXT
80 POKE 53264, PEEK(53264) AND 254
90 GOTO 10

If you ran the first program, and typed in this program correctly, you should see a sprite that flies from the left to the right across your screen.

Sprites on the Commodore 64

Things gets a bit tougher on the Commodore 64, because this excellent piece of hardware did not come with Basic equipped with sprite commands. Nor has it a sprite editor or a machine code monitor. However, if we have access to a Commodore 128, sprites can be edited when in C128 mode, and then used in C64 mode. If we want, we can also use the machine code monitor in C128 mode and then execute the program in C64 mode. I am going to display a sprite without using the C128 mode.

The bit pattern at D015 gets and sets what sprites are enabled, just as it does on the Commodore 128, but on the Commodore 128 we also have Basic commands for this. This means that the first sprite (sprite 0) is activated using:

POKE 53269, 1

Still, you might not see anything on the screen. You can position the sprite (sprite 0) by writing the desired X coordinate in D000 and the desired Y coordinate in D001. This will position it at 100, 100:

POKE 53248, 100
POKE 53249, 100

The 0, 0 position is just above and to the left of the visible area, so if it is located at its home position, the sprite is still invisible. Also, the sprite might be empty. Run this program to make the sprite (still sprite 0) totally filled with pixels and displayed in red color. Note that the first line of code (10) tells the Commodore 64 that we want to use 02C0 to 02D7 (704 to 727) for sprite 0 data.

10 POKE 2040, 11
20 FOR I=0 TO 62
30 POKE 704+I, 255
40 NEXT I
50 POKE 53287, 2

Your screen should now look something like this:

When taking this further, it is nice to have a Commodore 64 memory map available.