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.

Kom igång med C128 Assembler

Idag finns en hel del produkter för att utveckla program till Commodore 64 eller 128 på en modern PC, vilket är betydligt enklare än att göra det direkt på målmaskinen. Följ dessa steg för att komma igång med Assembler i Commodore 128.

1. Ladda hem Vice. Vice emulerar de flesta Commodore-maskinerna, vilket förutom C64/C128 även innefattar Pet, Vic 20 och Commodore +4.

2. Ladda hem CBM .prg Studio. Detta är en fullfjädrad integrerad utvecklingsmiljö för valfri Commodore-maskin.

3. Starta CBM .prg Studio. Välj Tools -> Options. Klicka på fliken Emulator Control. Bocka för C128 och peka C128-emulatorn från Vice (filen x128.exe).

4. Välj File -> New Project. Kryssa i C128, klicka Next. Vid Project Location, klicka Browse och välj var du vill spara din källkod. Därefter, klicka Next och Create.

5. I fönstret Project Explorer, högerklicka på Assembly Files och välj Add New File. Tillhandahåll ett filnamn med filändelsen .asm.

6. Det sista du måste göra för att komma igång, är att ange ditt programs startadress. Först i din .asm-fil, skriv:

*=$2000

Symbolen * representerar programmets start och $2000 är den hexadecimala representationen av 8192. Detta betyder alltså att ditt program startas med SYS 8192. När du väl börjar koda ditt program måste du tänka på att CBM .prg Studio antar att en indragning betyder att du vill göra en programsats. Låt säga att du vill förändra borderfärgen vars minnesadress är 53280 (D020 i hex), kan du skriva följande program (och notera indragningarna):

*=$2000
        inc $D020
        brk

Instruktionen inc ökar värdet med 1 på angiven minnesadress och brk avbryter programmet. Nu har du ett fungerande program. Öppna programmet genom att trycka på F5. Stäng fönstret som visar disassemblyn (Assembly Dump) och notera hur Vice visar en C128 med ditt program inläst i minnet. Om du vill kontrollera värdet av $D020, skriv:

PRINT PEEK(53280)

Notera värdet som står där, t.ex. 253. Starta ditt program genom att skriva:

SYS 8192

Och direkt därefter, tryck X följt av Enter för att lämna Commodore 128:ans maskinkodsmonitor. Eftersom programmet ökar värdet av 53280 med 1, borde borderfärgen nu vara ljusblå, eftersom ljusblå ligger som nästa färg efter ljusgrön. Och mycket riktigt, upprepa PRINT PEEK(53280) och konstatera att värdet har ökat med 1, till t.ex. 254.

bild1

Kör programmet igen genom att skriva SYS 8192 igen. Nu har vi ökat 53280 med 1 igen, vilket ger ljusgrå borderfärg. Om du vill kan du titta på disassemblyn innan du lämnar monitorn genom att skriva D2000 och sedan X.

bild2

När du är färdig kan du stänga emulatorn (eller emulatorerna) – en ny öppnas varje gång du kör programmet.

Linjär interpolering

Jag använder min Commodore 128 för detta exempel, eftersom jag vill komma åt den höga upplösningen i 80-kolumnsläget, men koden är körbar även på C64, Vic 20 och Pet, med reservation för radbryten och annat. Jag använder alltså en skärm som rymmer 80 tecken per rad, och kan representera talen 0 till och med 80 grafiskt med ett tecken. Denna kod kan representera talen 1 till 80 och här får 70 minustecken representera talet 70:

När helst ett värde måste skalas om, kan linjär interpolering användas. Låt säga att du vill presentera värden mellan, säg 50 och 550 under förutsättningen att du bara får plats med 80 tecken på en rad. Här laddar jag tio tal mellan 50 och 550 i vektorn A:

Algoritmen för att interpolera ett värde måste veta vad som ska interpoleras, vilken skala värdet ligger på (min och max) och vilken skala som värdet ska presenteras i (min och max). Själva formeln ser ut så här: NyttVärde = NyMin + (Värde – GammalMin) * (NyMax – NyMin) / (GammalMax – GammalMin).

Om vi sätter ihop nummerserien med presentationen får vi detta:

Vilket ger:

Om vi inte skriver ut det nya numret i klartext, utan använder iterationen från första bilden, enligt följande:

…så får vi detta resultat:

Commodore 128 bitmap graphics 2/2

Part 1. Part 2.

On the Commodore 128, the screen is divided into characters.

1

Each character consists of eight eight-pixel lines (bytes), which make a total of 64 pixels per character.

2

Each pixel pair represent one of four available colors in multicolor mode. This can be demonstrated using this simple code:

10 GRAPHIC 3, 1 : REM CREATE CLEAN MULTICOLOR DISPLAY
20 DRAW 1, 0, 0 : REM DRAW USING COLOR 1
30 DRAW 2, 0, 1 : REM DRAW USING COLOR 2
40 DRAW 3, 0, 2 : REM DRAW USING COLOR 3

Now, this pattern is shown:

3

If you add a line of code to change to high resolution graphics without clearing, we can see that two turned off pixels represent the first color, one off and one on represent color 2, one on and one off represent color 3 and two turned on pixels represent color 4.

50 GRAPHIC 1, 0 : REM CHANGE TO HIGH RESOLUTION WITHOUT CLEARING

4

The graphics memory is movable. This command places the graphics memory at 2000 (8192 in decimal):

POKE 53272, (PEEK(53272) AND 240) OR 8

The eight pixel pattern of each row in a character can be described using binary 00000000 for all off to 11111111 for all on (0 to 255 in decimal). Placing the number 00011011 (27) will draw one multicolor pixel of each color on the first line. 00 is color 0 (background), 01 is color 1, 10 is color 2 and 11 is color 3.

10 GRAPHICS 3, 1
20 POKE 53272, (PEEK(53272) AND 240) OR 8
30 POKE 8192, 27

5

Commodore 128 bitmap graphics 1/2

Part 1. Part 2.

When Commodore 128 vector graphics can’t provide the desired details, there is an option to do bitmap graphics. The 128 have a built in command for creating pixel perfect graphics called SPRSAV. You can create a pattern using the built-in editor (SPRDEF)…

01

…and transfer the data into a string variable, and then copy that data to the screen, like so:

10 COLOR 0, 13
20 COLOR 4, 13
30 COLOR 1, 1
40 COLOR 2, 8
50 COLOR 3, 12
60 GRAPHIC 3, 1
70 SPRSAV 1, A$
80 GSHAPE A$, 10, 10, 2 : REM DRAW SPRITE AT 10, 10
90 GSHAPE A$, 20, 11, 2
100 GSHAPE A$, 30, 12, 2

02

This should be enough for anyone, but if you like, you can also access the graphics memory directly.

Commodore 128 vector graphics

The Commodore 128 have a rich API for making colorful vector graphics. The low resolution (160×200) color mode allows you to make the classic “Forrest Gump” smiley using these five lines of code:

10 COLOR 0, 13 : REM GREY BACKGROUND
20 COLOR 4, 13 : REM GREY BORDER
30 COLOR 1, 1 : REM COLOR 1 IS BLACK
40 COLOR 2, 8 : REM COLOR 2 IS YELLOW
50 COLOR 3, 12 : REM COLOR 3 IS SHADOW (DARK GREY)
60 GRAPHIC 3, 1 : REM LOWRES MULTICOLOR MODE
70 CIRCLE 3, 80, 101, 49, 99 : REM SHADOW OUTLINE
80 PAINT 3, 80, 101 : REM SHADOW FILL
90 CIRCLE 2, 97, 99, 49, 99 : REM SMILEY SIZE
100 PAINT 2, 79, 99 : REM SMILEY FILL
110 CIRCLE 1, 79, 99, 49, 99 : REM SMILEY CONTOUR
120 CIRCLE 1, 65, 70, 8, 22 : REM LEFT EYE
130 PAINT 1, 65, 70 : REM LEFT EYE COLOR
140 CIRCLE 1, 92, 70, 8, 22 : REM RIGHT EYE
150 PAINT 1, 92, 70 : REM RIGHT EYE COLOR
160 CIRCLE 1, 79, 99, 39, 85, 90, 280 :REM MOUTH

smile

To exit the program on a real 128, press Runstop + Restore. On the Vice emulator, press Caps Lock + Page Up. However, the Commodore 128 API is not very suitable for bitmap graphics. For that, other Commodore Basic strategies are more suitable.

Skalning av vektorgrafik på Commodore 128

Genom kommandot SCALE kan man skala vektorgrafiken, alltså den grafik som skapas med kommandon som DRAW, CIRCLE och BOX – inte sprite-grafik eller text. När man arbetar med högupplöst grafik utan skalning är skärmen 320 pixlar bred och 200 pixlar hög. Detta program skapar en stor ellips som tar upp nästan hela skärmen.

10 GRAPHIC 1, 1 : REM AKTIVERA HÖGUPPLÖST GRAFIK
20 CIRCLE 1, 159, 99, 130, 80 : REM RITA EN ELLIPS ÖVER NÄSTAN HELA
30 INPUT A$ : REM TRYCK PÅ ENTER FÖR ATT AVSLUTA
40 GRAPHIC 0 : REM ÅTERGÅ TILL TEXT-LÄGET

01

Genom att infoga SCALE-kommandot efter GRAPHIC-kommandot påverkar man skalan på det som ritas efter anropet på SCALE. SCALE har ingen effekt om det anropas innan man gått in i grafikläget (före GRAPHIC-anropet) och påverkar det som ritas därefter. Det första argumentet som skickas till SCALE är 1 för att aktivera skalning. Det andra är den antalet virtuella pixlar du vill ha i X-led, och det tredje är antalet virtuella pixlar du vill ha i Y-led.

Här infogar jag ett anrop på SCALE på rad 15 (efter GRAPHIC på rad 10) och anropar sedan RENUMBER för att få tillbaka jämna mellanrum mellan raderna. Även om pixlarna fortfarande är lika stora, ritas nu bilden med den virtuella upplösningen av 640 * 400 pixlar.

10 GRAPHIC 1, 1 : REM AKTIVERA HÖGUPPLÖST GRAFIK
20 SCALE 1, 640, 400
30 CIRCLE 1, 159, 99, 130, 80 : REM RITA SAMMA ELLIPS
40 INPUT A$ : REM TRYCK PÅ ENTER FÖR ATT AVSLUTA
50 GRAPHIC 0 : REM ÅTERGÅ TILL TEXT-LÄGET

02

Detta är användbart när man tänker på att flerfärgsläget innehåller väldigt breda pixlar. När flerfärgsgrafik används består skärmen (som är i 4:3-format) av 160 * 200 pixlar. Om vi kör ursprungsprogrammet, utan SCALE-anropet, i flerfärgsläge (läge 3).

10 GRAPHIC 3, 1 : REM AKTIVERA FLERFÄRGSGRAFIK
20 CIRCLE 1, 159, 99, 130, 80 : REM RITA SAMMA ELLIPS
30 INPUT A$ : REM TRYCK PÅ ENTER FÖR ATT AVSLUTA
40 GRAPHIC 0 : REM ÅTERGÅ TILL TEXT-LÄGET

03

Men trots pixlarnas storlek, kan man alltså behålla den virtuella upplösningen av 320 * 200 genom att anropa SCALE. Nu blir det dock lite lustigt. SCALE kompenserar inte för pixlarnas bredd, så de virtuella 320 * 200 pixlarna får vi när vi ber om 640 * 200 pixlar.

10 GRAPHIC 3, 1 : REM AKTIVERA FLERFÄRGSGRAFIK
20 SCALE 1, 640, 200
30 CIRCLE 1, 159, 99, 130, 80 : REM RITA SAMMA ELLIPS
40 INPUT A$ : REM TRYCK PÅ ENTER FÖR ATT AVSLUTA
50 GRAPHIC 0 : REM ÅTERGÅ TILL TEXT-LÄGET

04

För att stänga av skalning, anropa SCALE med argumentet 0.

Making music in Basic 7.0 part 5

You can add pitch bending using the SOUND command. By itself, you cannot use envelopes, just flat sounds in any given pitch. The arguments are voice (1, 2 or 3), frequency (0 to 65535), duration (16 = one second), pitch bend direction (0 = up, 1 = down, 2 sine up and down), minimum frequency, pitch bend speed, waveform (0 = triangle, 1 = saw tooth, 2 = square, 3 = noise) and finally pulse width (if waveform is 2).

This will make a straight beep, that will play for two seconds:

SOUND 1, 4000, 32

And now for something completely different, a hysterical vibrato!

SOUND 1, 5000, 32, 2, 3000, 800, 1

To add an envelope to the sound, you use what you know on the PLAY command, and add the SOUND command immediatly before. Make sure you trigger them on the same voice.

Both the SOUND command and the PLAY command (in combination with the ENVELOPE command and the T synthesize control character) allows you to control the waveform that is being used. When combining them, PLAY decides, not SOUND. Type in this in your Commodore 128. You might want to reset your machine first, to set all parameters to default.

10 SOUND 1, 5000, 32, 2, 3000, 800, 1
20 PLAY "V1T5C"

Cool, right? Click here to listen.

Making music in Basic 7.0 part 4

Apart from PLAY, the commands that are available for making sounds and music are TEMPO, ENVELOPE, SOUND and FILTER.

TEMPO lets you control playback speed. The slowest is 1 and the fastest is 255.

ENVELOPE lets you modify the ten predefined instruments. You set the instruments using the T control character (0 to 9). The arguments are:

– The instrument you want to overwrite (0 to 9)
– Attack rate (0 to 15)
– Decay rate (0 to 15)
– Sustain level (0 to 15)
– Release rate (0 to 15)
– Waveform (0=triangle, 1=sawtooth, 2=square with adjustable pulse width, 3=noise, 4=ring modulation)
– Pulse width (0 to 4095) – only relevant if waveform is set to 2.

This program creates 5 similar instruments that differ in pulse width, and uses them in a simple riff.

10 ENVELOPE 0,0,5,0,0,2,100
20 ENVELOPE 1,0,5,0,0,2,300
30 ENVELOPE 2,0,5,0,0,2,500
40 ENVELOPE 3,0,5,0,0,2,700
50 ENVELOPE 4,0,5,0,0,2,900
60 TEMPO 40
70 PLAY "V1O2Q"
80 FOR I=1 TO 2
90 PLAY "T0CCT1CCT2CCT3CCT4CCT3CCT2CCT1CC"
100 NEXT

Click here to listen.

Making music in Basic 7.0 part 3

When you use the other synthesizer control characters (O, T, U and X), they apply no matter of what voice (V) you have chosen. So when you for example use O to set the octave (0 to 6), all the following notes, regardless of voice, will be played in that octave. This example will play the notes C, D and E in voice 1, octave one. C, D E in voice 1, octave 2, and finally C (at the same time as the previous E), D and E in voice 2, octave 2.

PLAY "V1O1 CDE O2 CDE V2 CDE"

T (0 to 9) lets you chose from 10 predefined envelopes. The predefined envelopes emulates different instruments (0 is piano, 1 is accordion and so on). Envelopes differ in attack rate, decay rate, sustain level, release rate and waveform. This song uses a harpsichord bass (T6), a drum (T3) and some xylophone (T9).

10 FOR I=1 TO 4
20 PLAY "V1O2T6QCCT3O5CO2T6C"
30 PLAY "V2O5T9CV3G"
40 NEXT

U (0 to 15) controls the volume, but not on the next note, but also on any playing note. This will therefore play both C notes using volume 2.

PLAY "U15 C U2 C"

Finally, X (0 or 1) is used to turn the frequency filter on (1) or off (0).

Making music in Basic 7.0 part 2

The synthesizer control characters (V, O, T, U and X) always take one integer argument and always affect all the rest of the notes that are played. V stands for Voice and is the key to polyphonic music. Since polyphonic music is achieved by playing notes in different voices, you will use V a lot.

Each note will be played when the previous note is done, but if you switch voices, the next note will be played immediately (if the voice you switch to is free). This will play the C note, followed by E and G at the same time. There are three voices available: 1, 2 and 3.

PLAY "V1 CE V2 G"

This program gives you a nice riff:

10 FOR A=1 TO 4
20 PLAY "V1 CE CV2EV3G"
30 PLAY "V1 CGCC V2EV3G"
40 PLAY "V1CV2EV3G"
50 NEXT

Making music in Basic 7.0 part 1

In Commodore Basic 7, music is made using the PLAY command. PLAY takes one string, and that string contains the notations that you want the Commodore 128 to play. The string “CDE” will play the note C, and then the note D and finally then note E.

PLAY "CDE"

Possible notes are C, D, E, F, G, A and B. R is for Rest. Rests take up time, but does not make any sound. Spaces are ignored, so you can add spaces to make your string more readable. When you add a note control character to your note, this might be of interest. There are three note control characters that you can use. Control characters operates only on the note immediately to the right, spaces ignored.

Sharp (#) will play the note a half tone higher, flat ($) will play the note a half tone lower and period (.) will increase note duration by 50%. Since note control chars only apply to the next note, this will play 4 C notes, but only the third note will be longer.

PLAY "CC.CC"

The synthesizer control characters and the duration control characters do not just apply to the next note to the right, but to all preceding notes. All synthesizer control characters take numeric arguments, but none of the duration control characters take any arguments. I will get back to the synthesizer control characters, but these are the duration control characters:

W for whole note, H for half note, Q for quarter note (default), I for eight note and S for sixteenth note. This will play two bars. The first bar will consist of two quarter notes and one half note. The next bar will consist of one half note and two quarter notes.

PLAY "QCCHCCQCC"

With this much knowledge, you can do Smoke on the water by Deep Purple. Something like this:

PLAY "QC#D.FC#DI#FHF"

Sequential data on 5.25 inch floppies

If you have an actual 1571 disk drive for your Commodore 128, insert a blank disk, format it using the HEADER command. Something like this:

HEADER "MY DISK", I44, D0

(Formatting a disk takes a while.)

If you are running a virtual Commodore 128 in VICE, click File, Attach disk image, Drive 8. Create a d64 image file and attach that image. To create the file, enter a desired filename, like test.d64, provide a name, click Create Image, then click Attach.

(The commands I use are available Commodore Basic 4.0 on Commodore PET, but I run Commodore Basic 7 on a C128.)

Your disk is now inserted and completely empty. You can check the content using the DIRECTORY command.

As a Commodore user, you know that you sometimes have to refer to your disk drive using its drive number (the first disk drive is 0) and sometimes you have to use the device number (the first disk drive is 8). The OPEN command operates on any device, therefore a device number is required in this case. The first parameter is the logical file number (just a number that identifies the file), the second is the device number (8). The third argument is a channel number – enter 2. Then, in one single string argument, you type in the file name, the file type and the file mode. I want to create a file called TEST.DAT as a sequential file and I want to write to it, so I my string holds “TEST.DAT,SEQ,WRITE”.

10 OPEN 1, 8, 2, "TEST.DAT,SEQ,WRITE"

To fill your file with data, use the PRINT# command. Anything goes here. This will print one string, one integer, and then yet another string. You provide your logical file number so that PRINT# knows what file you are targeting.

20 PRINT#1, "ONE STRING"
30 PRINT#1, 5
40 PRINT#1, "ANOTHER STRING"

If you like, more data can be added in one line.
When you are done writing, close the file using the CLOSE command. Again, provide your logical file number.

50 CLOSE 1

After running this program, you should have a small sequential file called TEST.DAT on your disk. If any disk error occurred, the lamp on your drive is flashing now – it shouldn’t do that.

Continued here.

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.

CP/M on a Commodore machine – online resources

To get started with CP/M, you will need a Commodore 128 with a disk drive or a computer that runs Vice (X128). The disks you need can be downloaded from here. The CP/M boot disk, the additional utilities, “more CP/M additional utilities”, the Assembler utilities and Microsoft Basic 80 (two disks).

If you run this on a physical machine, make sure to insert the boot disk, and to push in the “40/80 display” key on your computer, before turning it on. If you are running this from Vice emulator, start your machine by passing these arguments to the x128 executable (adjust the path if necessary):

x128.exe -80 -autostart "C:\cpm\zpmsys.d64"

This is a text only environment, but pseudo graphics can be used, and a graphics library is available as an add-on.

The basic usage of CP/M is described in the Commodore 128 user guide, chapter 11. If you know DOS, you will probably feel rather at home. You have the concepts of programs and arguments. DIR shows the available commands. The actual Commodore extensions consist of keyboard short cuts and are described in chapter 15 of the Commodore 128 user guide.

What I see as the biggest challenge, is inserting the correct disk. Let’s say that you want to read the content of a file. This requires the TYPE.COM file that is located on the additional utilities disk, so you must insert that disk to be able to run that command. To avoid frustration, use two disk drives – one for the CP/M disks, and one for your files.

To start Microsoft Basic, insert the correct disk and type MBASIC. Then, watch a movie or something. After a while, your Commodore 128 will say:

MBASIC-80 Rev. 5.21
[CP/M Version]
Copyright 1977-1981 (C) by Microsoft
Created: 28-Jul-81
34350 Bytes free
Ok

If you want to write programs, the MBASIC manual can be downloaded from here.

A five minute Turbo Pascal 3.0 demo on the Commodore 128:

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?

Collision detection

A nice and quick way to create two filled sprites (sprite 1 and 2) is to enter the monitor and type:

F 0E00 0E3E FF
F 0E3F 0E7E FF

Of course you can fill both at once, but this the above code nicely declares the two memory areas I am using in this example. Now, let’s write a simple Basic program to fire the two sprites so that they collide now and then. This will make one sprite white and the other cyan, and fire the movements.

10 SPRITE 1, 1, 2, 0
20 MOVSPR 1, 100, 100
30 MOVSPR 1, 90#1
40 SPRITE 2, 1, 2, 0
50 MOVSPR 2, 100, 115
60 MOVSPR 2, 270#1

To detect collision between the two sprites, we can use the BUMP function. BUMP(1) returns a bit pattern telling us what sprites has collided, and BUMP(2) returns a bit pattern that tells us what sprites has collided with static graphics on screen. We would expect BUMP(1) to return 3 if sprite 1 and 2 is colliding, given that no other sprites are colliding as well, because the binary number 00000011 represents the decimal number 3. And indeed. Add these two lines to your program to see what BUMP(1) returns:

70 PRINT BUMP(1)
80 GOTO 70

To interrupt the program, press RunStop. If you are using the VICE emulator, that key might be mapped to the Escape key. BUMP(1) is actually just returning the bit pattern in the byte located at D01E, so BUMP(1) is equivalent to PEEK(53278).

Poking graphics on the C128

The skills of using PEEK, POKE and logical operators that I write about for the Commodore PET here, can be used to create graphics on the Commodore 128, in 40-column mode. Before you begin, you might want to clear the screen using the SCNCLR command. Odd name, I know.

The C128 has a built in sprite engine. A sprite is a 2 dimensional area with its own memory area that can be handled separately from the rest of the screen. The C128 sprite engine supports eight sprites. Use the SPRITE command to activate a sprite. Here, I have activated the first of eight sprites:

SPRITE 1, 1, 1, 0

The first sprite is now activated. The default position is up to the right of the screen. However, the sprite might be invisible. If there is junk data in the address space of the sprite, you will see some obscure pixels. The sprite data is located in the memory at 3584 (0E00). Each sprite is 3 bytes (or 24 pixels) wide and 21 pixels high. Each sprite consumes 63 bytes. This information is enough to clear the sprite. In the machine code monitor, use In the machine code monitor, use M 0E00 0E3E to see the sprite data. Note that the monitor displays eight bytes at a time, so it will actually display 0E00 to 0E3F. To clear the sprite, type:

F 0E00 0E3E 0

Leave the monitor using X. Make sure the sprite is visible by typing in SPRITE 1, 1, 1, 0 again. Now, use the POKE statement to control which pixels should be visible and which should be hidden, according to the rules I demonstrated here.

Accessing individual bits on a Commodore PET

On a Commodore PET, each byte that can be read using the PEEK function, and set using the POKE statement. A byte consist of 8 bits, and represent a number between 0 and 255. This code writes the value 5 to the memory address 1020, and then reads it back. The output is of course 5.

POKE 1024, 5
PRINT PEEK(1024)

The POKE statement affects all eight bits at the given address (1024), but bits can be filtered out using logical operators AND and OR. The first (from right to left) of the eight bits represents the value 1, the second bit represents 2, the third 4, the fourth 8, the fifth 16, the sixth 32, the seventh 64 and the last bit represents the value 128.

Since the value 5 is stored at 1024, you would expect all the bits being 0 except the first and the third, since 1 + 4 equals 5. This code reads the first four bits at 1024, and the output is 1, 0, 4 and 0. 1 because the first bit (representing 1) is set, 0 because the second isn’t set, 4 because the third (representing 4) is set and 0 because the fourth isn’t set.

PRINT PEEK(1024) AND 1 : REM Read bit 1 - (1 if set)
PRINT PEEK(1024) AND 2 : REM Read bit 2 - (2 if set)
PRINT PEEK(1024) AND 4 : REM Read bit 3 - (4 if set)
PRINT PEEK(1024) AND 8 : REM Read bit 4 - (8 if set)

Multiple bits can also be read. This code reads both the first and the third bit on the address 1024:

PRINT PEEK(1024) AND 5

The result will be 0 if neither is set, 1 if the first is set, 4 if the second is set and 5 if both the first and third is set. The bit pattern of the value is 00000101, so the bits that are pointed out are the first and the third (from right to left).

Also, you can set individual bits. OR [n] turns a bit on, where [n] is the value that the bit represents. 1, 2, 4, 8, 16, 32, 64 or 128. This code turns on the last bit at 1024:

POKE 1024, PEEK(1024) OR 128

The bit pattern at 1024 is now 10000101. The value that is stored at 1024 is 133, because 1 + 4 + 128 equals 133. To turn the last bit (128) back to zero, use AND together with bit pattern that contains a one at all positions that you want the existing flag to remain, and 0 at the positions you want to turn bytes off. To turn the last bit from the right off, you would want a bit pattern that looks like this: 01111111. All bytes remains, but the last bit from the right is 0. The number 127 has this pattern.

POKE 1024, PEEK(1024) OR 127

Now, the bit pattern at 1024 is changed back from 10000101 to 00000101. The value that is stored in the byte at 1024 is now 5 again.

What can be done with this knowledge?

Some cool software for the C128: GEOS


So CP/M is the text based disk operating system for the Commodore 128. You could buy a window based operating on disk called GEOS (Graphic Environment Operating System). GEOS was available for some of the Commodore machines and the Apple II. GEOS is not “smashing” either, but it solved some problems that text based systems had at that time. It presented the features of the applications and the system itself, so that the user could point and click on the feature that user wants to use. These screenshots show GEOS in all its glory on an enormous 320 by 200 pixel screen.

At startup, GEOS shows the content of the system disk. To access some of the useful applications, you would insert that disk, and click Disk and Open to refresh the screen. GEOS was delivered with word processor, a painting program, among other things. Not very sophisticated compared to what you could get for your Macintosh or Windows, but a life saver for any C128 user.

GEOS did not multitask very well. Here, when I use the calculator, I can’t move the mouse outside the calculator window. I need to close it, before I can access the applications window behind, and that window cannot be moved around. It can be closed, and reopened from the Disk menu.

GEOS was relesed in 1986 and from what I know, the GEOS disks are not available for download.

Some cool software for the C128: CP/M

CP/M, the disk operating system for the Commodore 128

This is one of the strange things about this machine. Microsoft DOS was around, and Commodore was already making computers running DOS. But the Commodore 128 was supposed to run CP/M. Who used this?

If you want to boot CP/M, download the image from here. In the ctools/x128 folder, attach the “cpm128.d64” image to device 8 and type BOOT (or reset the machine).

Attach the first file to drive 8 and type BOOT (or reset the machine). If you’re doing this from a physical C128, make sure to have the 80 col key pressed down. If you’re doing this from the Vice emulator, send the -80 argument to x128.exe at startup.

X128.exe -80

It takes a while to boot, and watching the prompt is sort of just as fun as watching it boot. What can it do? Most of the operations will require that other disks are inserted to the drive. They were delivered with your machine when you bought it, but you probably reformatted those disks to make room for some pirated games. However, you can show the contents of a disk by typing dir and you can get help by typing help. Hang on, it is working on providing you help. No it didn’t crash, it is working on providing you help! Yes, it is. Ah there you go. Like I said, it can provide help!

In purple and everything!

Some commands worth mentioning are PIP to copy or combine files (PIP can be used without any extra disks), ED to edit a file, DUMP to display a file and FORMAT to format a CP/M disk.

Have fun. Or perhaps: Have “fun“.

Basic data management

If you want to do this on a real Commodore 128, you will need a blank floppy disk, and if you are doing this from an emulator, you will need a blank floppy image. I have created a blank d64 image from the Vice emulator. To do that, click File, Attach disk image, and Drive 8 to display the Attach disk image dialog. There, type in a filename, click Create image, and finally click Attach.

You can make sure that your disk is correctly attached by typing DIRECTORY. This is what you should see:

To create a blank area of memory, enter the machine code monitor and fill a memory area with the value zero. Type:

MONITOR

F 1000 1100 0

To ensure that memory now is blank, type M 1000. Type X to leave the machine code monitor. Note that the monitor is using the hexadecimal, so the area that we have blanked out is from address 4096 to address 4352.

From the Basic parser (that is, outside the machine code monitor) the POKE command is used to set a byte and the PEEK function is used to get a byte. Commodore Basic uses the decimal number system but is equipped with functions to convert between the systems.

So, to set a byte at position 4096 (in this case, the value 5) type:

POKE 4096, 5

To read the same byte, type:

PRINT PEEK(4096)

Also, you can enter the monitor and type M 1000. This is what you should see:

The C128 has built in commands for saving memory to disk and loading memory to disk. Let’s say that we want to save our byte and some following bytes, use the BSAVE command (Binary Save). This will save 4 bytes to a file called TEST.DAT, where the first byte is our value 5. The second argument is the device (B0 is device 8), the third argument is the address range (the character P must occur before the number).

BSAVE "TEST.DAT", B0, P4096 TO P4100

Type DIRECTORY to make sure the file is located there.

To load this file, use BLOAD (Binary Load). This is a test you can do.

Type PRINT PEEK(4110) to ensure address 4110 is empty. Load the file into the address 4110 by typing:

BLOAD "TEST.DAT", B0, P4110

Type PRINT PEEK(4110) again to see that it now holds the value 5, as loaded from the file.

The oddities: GO64 and sound

GO64
In some ways, GO64 behaves as a command (GO) with one argument (64). For example, you can type GO64, GO 64 or even GO 70-6 and all will set the C128 in C64 mode. But in some ways, GO64 behaves as a command on its own. For example, from the fact that GO 60+4 does the job, you would perhaps expect GO 65 to generate a ?ILLEGAL QUANTITY ERROR, but it generates a ?SYNTAX ERROR. The fact that typing GO 8*8 sets the machine in C64 mode is strange enough.

Sound
The PLAY command plays notes and the SOUND command audio in any frequency. PLAY can deal with notes and volume envelopes but not pitch bending. SOUND can pitch bend but not deal with volume envelopes. This plays three notes, C, D and E, with a volume envelope that emulates a piano:

PLAY "CDE"

This plays a C-maj chord:

PLAY "V1 C V2 E V3 G"

This plays a pitch bending sound without a volume envelope:

SOUND 1, 8000, 40, 2, 7000, 100

The arguments are channel, frequency, duration, direction (2 means oscillate) and stepvalue.

If I make a program with a PLAY command that is directly followed by a SOUND command that plays a sound in the same voice channel, they are combined! This gives a pitch bending sound with a volume envelope! T5 means that I use the predefined guitar volume envelope, and HC means half note of C (two quarters long C).

10 SOUND 1, 8000, 50, 7000, 100
20 PLAY "V1 T5 HC"

The sprite engine

One of the built in applications in the C128 is the sprite editor. Enter it by typing SPRDEF. Choose a sprite number, use the cursor keys to move the cursor and numeric keys to draw. 1 will delete a pixel, 2 will draw with the first color. In multicolor mode, you can also use 3 and 4. To save and close the editor, press SHIFT+ENTER followed by ENTER.

The sprite engine in Commodore Basic 7 lets you enable and disable sprites, and control sprite movement. The SPRITE command is used to turn sprites on or off and to set the sprite attributes. The arguments I have used is one-based sprite index (1), on (1), cyan color (4) in front of other graphics (0).

10 SPRITE 1, 1, 4, 0

My next line of code, will tell the sprite to move to the left using the MOVSPR command. The arguments I have used are one-based sprite index (1), 90 degrees at a speed of 4.

20 MOVSPR 1, 90 # 4

Type RUN to start the show.

Manipulate a byte

When you get a tweet like this thrown at you, the only thing to do is to take another visit to the wonderful world of the C128 monitor. Let’s say that we were to make a program using assembler. We will store it at address 4096. Enter the machine code monitor by typing MONITOR, and view the current disassembled instructions at 4096 by typing D 1000.

The command for entering a line of assembly code is called A. You have to keep in mind that the disassembled machine code that D is displaying, has a slightly different format than the assambly you type in. Basically you type A, followed by the target address, the name of the instruction, and an operand (if any).

To simply enter a byte into memory, use the F command. Like the POKE command in Commodore Basic, you use F to set a 8-bit value at a specific address. The difference between POKE and F, is that F takes two addresses, and fills the given range with the given value, while POKE only deals with one address at the time. You would need to make an iteration, perhaps using FOR, to have POKE to fill a range. Type F, followed by the start and end address, and concluded with the byte. This will change one single byte at the address 4096:

F 1000 1000 3

Type M 1000 to see the effect.

The built-in machine code monitor

The Commodore 128 features a few built in applications and one Easter egg. The egg is a list of the engineers that built the machine, with the word “hardware” intentionally misspelled as “herdware” after 8-bit computer designer Bil Herd. To reveal the egg, type this:

SYS 32800,123,45,6

The Commodore 128 tries to boot from floppy at startup. To start the CP/M operating system, you would make sure to have the boot disk inserted at startup. If you want to start the system without resetting the machine, you could just type BOOT and press enter. BOOT tries to load data from the floppy without generating an error if it fails.

The built in machine code monitor gives you the ability to view memory content (ROM and RAM) in binary format or as instructions. You choose the format that is best suited for the type of data you want to view. Also, the monitor lets you type in instructions in the RAM.

You enter the monitor by typing MONITOR.

While in the monitor, type M to dump 96 bytes on the screen. Type M again to dump the next 96 bytes. You can also specify a desired starting address after M.

By typing D, a disassembled version of the machine code is displayed. Just as with M, you can specify a starting address.

Type X to leave the monitor.

Hidden stuff in the C128

Here is some of the hidden stuff in my favorite computer, the Commodore 128.

There is a bug in the Basic interpretation that shows up when you tries to do an arithmetic calculation using a string. This is what’s supposed to happen:

When you add an integer to a string, the interpretator should say that you have mismatching types.

PRINT "10" + 3

The code above should result in an error, not 13 or “103”. So far so good. If you add a negative number to a string, you should get the same error, but instead, the Basic interpretator crashes. The first time, I don’t get any result at all, and when I move the operators together (which is perfectly alright according to the Commodore Basic 7 specification) the CPU goes mental.

You can see from the word BREAK that the Basic interpretator has stopped.

Bare with me, there is more fun to the C128. More posts to come.