Plotting a function in hi-res graphics mode on a Commodore 64

I wrote a program to plot a function in hi-res graphics mode on the C64. It is entirely in BASIC, so it is mind-numbingly slow, but it works, and can be used to plot some fairly interesting functions.

This mode only allows one background color and one foreground color for each 8×8 block of pixels. It would, I suppose, be possible to plot multiple functions in multiple colors, but the intersections would be strange, as each 8×8 block can only have two colors, including the background. An obvious next step is to use the multi-color bitmap mode, but which this would allow four colors in any given 8×8 block, it would reduce the resolution from 320×200 down to 160×200. I will try this soon.

Another obvious improvement will be to move much of the setup stuff (like erasing the graphics ram (\$2000-\$3fff)) down into machine language, which would speed things up significantly.

The Graphics Book for the Commodore 64 was indispensable.

Here is the plot of f(x) = sin(x) + sin(1.5*x + pi/2)

And here is the code:

``` 10 rem *** funcplot
20 rem
30 pi = 3.141592653
40 yu = 2.2 : yd = -2.2
50 xu = 6pi : xd = -6pi
60 xr = xu - xd : yr = yu - yd
70 xs = xr/320 : ys = yr/200
80 def fn f(x) = sin(x) + sin(1.5*x + pi/2)
110 v = 53248
120 rem set graphic ram address
130 ga = 8192
140 rem set video ram address
150 vr = 1024
160 rem set border to black
170 poke v+32,0
500 gosub 20000 : rem turn on hires
510 gosub 21000 : rem graphic ram area
520 gosub 22000 : rem set color ram
530 gosub 23000 : rem clr graphic ram
1000 rem draw x axis
1005 y=0 : yc=int(200-(y-yd)*(200/yr))
1010 for xc = 0 to 319
1020 gosub 30000 : rem set (xc,yc)
1030 next xc
1100 rem draw y axis
1110 x = 0
1120 for yc = 1 to 200
1130 xc = int((x-xd)*(320/xr))
1140 gosub 30000 : rem set (xc,yc)
1150 next yc
1300 rem plot function
1310 for x = xd to xu step xs
1320 y = fn f(x)
1330 xc = int((x-xd)*(320/xr))
1340 yc = int(200-(y-yd)*(200/yr))
1350 gosub 30000 : rem set (xc,yc)
1360 next x
1400 poke 198,0 : wait 198,1
1450 gosub 24000
1500 end
20000 rem turn on hi res graphics
20010 rem   1. set bits 5/6 of v+17
20020 rem   2. clr bit 4 of v+22
20030 poke v+17,peek(v+17) or (11*16)
20040 poke v+22,peek(v+22) and (255-16)
20050 return
21000 rem set graphic ram area
21010 rem   1. set bit 3 of v+24
21020 poke v+24, peek(v+24) or 8
21030 return
22000 rem set color ram
22010 rem   1. color ram is 1024-2023
22020 rem   2. set background 1 - white
22030 rem   3. set foreground 0 - black
22040 co = 0*16 + 1
22050 for i = vr to vr+1000
22060 poke i,co
22070 next i
22080 return
23000 rem clear graphic ram
23010 rem   1. graphic ram is ga to
23020 rem        ga + 8000
23030 for i = ga to ga +8000
23040 poke i,0
23050 next i
23060 return
24000 rem turn graphics off
24010 rem   1. clr bits 5/6 of v+17
24020 rem   2. clr bit 4 of v+22
24030 rem   3. clr bit 3 of v+24
24040 poke v+17,peek(v+17) and (255-96)
24050 poke v+22,peek(v+22) and (255-16)
24060 poke v+24,peek(v+24) and (255-8)
24070 return
30000 rem set pixel
30010 ra = 320*int(yc/8)+(yc and 7)
30020 ba = 8*int(xc/8)
30030 ma = 2^(7-(xc and 7))
30040 ad = ga + ra + ba
30060 return
31000 rem clr pixel
31010 ra = 320*int(yc/8)+(yc and 7)
31020 ba = 8*int(xc/8)
31030 ma = 255-2^(7-(xc and 7))
31040 ad = ga + ra + ba
31060 return
```

One thought on “Plotting a function in hi-res graphics mode on a Commodore 64”

1. Hi Paul! I ported your code for the subroutines to machine language routines to be used by all the gosubs. Interestingly, plotting a point isn’t faster. But the setup definitely is as you already suspected. If one was drawing lines, then that’s the probably the next recommended enhancement.

1 REM ORIGINALLY FROM
2 REM PAULNOTEBOOK.NET/2019/06/08
3 REM /PLOTTING-A-FUNCTION-IN-HI-RES-
4 REM GRAPHICS-MODE-ON-A-COMMODORE-64/
5 REM
6 REM MACHINE LANGUAGE ROUTINES PORTED
7 REM BY DAVE@DAVEVW.COM
8 REM TECHWITHDAVE.DAVEVW.COM
9 REM
10 REM *** FUNCPLOT
20 REM
30 PI = 3.141592653
40 YU = 2.2 : YD = -2.2
50 XU = 6*PI : XD = -6*PI
60 XR = XU – XD : YR = YU – YD
70 XS = XR/320 : YS = YR/200
80 DEF FN F(X) = SIN(X) + SIN(1.5*X + PI/2)
90 ML=7922:FOR I=ML TO 8191:READ B:POKE I,B:NEXT
110 V = 53248
120 REM SET GRAPHIC RAM ADDRESS
130 GA = 8192
140 REM SET VIDEO RAM ADDRESS
150 VR = 1024
160 REM SET BORDER TO BLACK
170 POKE V+32,0
500 GOSUB 20000 : REM TURN ON HIRES
510 GOSUB 21000 : REM GRAPHIC RAM AREA
520 GOSUB 22000 : REM SET COLOR RAM
530 GOSUB 23000 : REM CLR GRAPHIC RAM
1000 REM DRAW X AXIS
1005 Y=0 : YC=INT(200-(Y-YD)*(200/YR))
1010 FOR XC = 0 TO 319
1020 GOSUB 30000 : REM SET (XC,YC)
1030 NEXT XC
1100 REM DRAW Y AXIS
1110 X = 0
1120 FOR YC = 1 TO 200
1130 XC = INT((X-XD)*(320/XR))
1140 GOSUB 30000 : REM SET (XC,YC)
1150 NEXT YC
1300 REM PLOT FUNCTION
1310 FOR X = XD TO XU STEP XS
1320 Y = FN F(X)
1330 XC = INT((X-XD)*(320/XR))
1340 YC = INT(200-(Y-YD)*(200/YR))
1350 GOSUB 30000 : REM SET (XC,YC)
1360 NEXT X
1400 POKE 198,0 : WAIT 198,1
1450 GOSUB 24000
1500 END
20000 REM TURN ON HI RES GRAPHICS
20001 POKE 251,1:SYS ML:RETURN
20010 REM 1. SET BITS 5/6 OF V+17
20020 REM 2. CLR BIT 4 OF V+22
20030 POKE V+17,PEEK(V+17) OR (11*16)
20040 POKE V+22,PEEK(V+22) AND (255-16)
20050 RETURN
21000 REM SET GRAPHIC RAM AREA
21001 POKE 251,2:SYS ML:RETURN
21010 REM 1. SET BIT 3 OF V+24
21020 POKE V+24, PEEK(V+24) OR 8
21030 RETURN
22000 REM SET COLOR RAM
22001 POKE 251,3:POKE 252,1:SYS ML:RETURN
22010 REM 1. COLOR RAM IS 1024-2023
22020 REM 2. SET BACKGROUND 1 – WHITE
22030 REM 3. SET FOREGROUND 0 – BLACK
22040 CO = 0*16 + 1
22050 FOR I = VR TO VR+1000
22060 POKE I,CO
22070 NEXT I
22080 RETURN
23000 REM CLEAR GRAPHIC RAM
23001 POKE 251,4:SYS ML:RETURN
23010 REM 1. GRAPHIC RAM IS GA TO
23020 REM GA + 8000
23030 FOR I = GA TO GA +8000
23040 POKE I,0
23050 NEXT I
23060 RETURN
24000 REM TURN GRAPHICS OFF
24001 POKE 251,5:SYS ML:RETURN
24010 REM 1. CLR BITS 5/6 OF V+17
24020 REM 2. CLR BIT 4 OF V+22
24030 REM 3. CLR BIT 3 OF V+24
24040 POKE V+17,PEEK(V+17) AND (255-96)
24050 POKE V+22,PEEK(V+22) AND (255-16)
24060 POKE V+24,PEEK(V+24) AND (255-8)
24070 RETURN
30000 REM SET PIXEL
30001 POKE 251,6
30002 POKE 252,XC AND 255
30003 POKE 253,YC
30004 POKE 254,XC/256
30005 SYS ML
30006 RETURN
30010 RA = 320*INT(YC/8)+(YC AND 7)
30020 BA = 8*INT(XC/8)
30030 MA = 2^(7-(XC AND 7))
30040 AD = GA + RA + BA
30060 RETURN
31000 REM CLR PIXEL
31001 POKE 251,6
31002 POKE 252,XC AND 255
31003 POKE 253,YC
31004 POKE 254,(XC/256) OR 2
31005 SYS ML
31006 RETURN
31010 RA = 320*INT(YC/8)+(YC AND 7)
31020 BA = 8*INT(XC/8)
31030 MA = 255-2^(7-(XC AND 7))
31040 AD = GA + RA + BA
31060 RETURN
50000 DATA 165, 251, 201, 1, 208, 17, 173, 17, 208, 9, 176, 141, 17
50001 DATA 208, 173, 22, 208, 41, 239, 141, 22, 208, 96, 201, 2, 208
50002 DATA 9, 173, 24, 208, 9, 8, 141, 24, 208, 96, 201, 3, 208
50003 DATA 20, 165, 252, 162, 0, 157, 0, 4, 157, 0, 5, 157, 0
50004 DATA 6, 157, 0, 7, 232, 208, 241, 96, 201, 4, 208, 24, 169
50005 DATA 0, 133, 254, 169, 32, 133, 255, 162, 32, 160, 0, 152, 145
50006 DATA 254, 200, 208, 251, 230, 255, 202, 208, 246, 96, 201, 5, 208
50007 DATA 25, 173, 17, 208, 41, 159, 141, 17, 208, 173, 22, 208, 41
50008 DATA 239, 141, 22, 208, 173, 24, 208, 41, 247, 141, 24, 208, 96
50009 DATA 201, 6, 240, 1, 96, 165, 252, 72, 165, 254, 72, 165, 253
50010 DATA 72, 41, 248, 133, 251, 165, 254, 169, 0, 133, 252, 6, 251
50011 DATA 38, 252, 6, 251, 38, 252, 162, 10, 169, 0, 133, 254, 133
50012 DATA 255, 24, 165, 254, 101, 251, 133, 254, 165, 255, 101, 252, 133
50013 DATA 255, 202, 208, 240, 104, 133, 252, 41, 7, 24, 101, 254, 133
50014 DATA 254, 165, 255, 105, 0, 133, 255, 104, 133, 253, 104, 133, 251
50015 DATA 41, 248, 24, 101, 254, 133, 254, 165, 253, 41, 1, 101, 255
50016 DATA 133, 255, 165, 251, 41, 7, 133, 251, 169, 7, 162, 1, 56
50017 DATA 229, 251, 134, 251, 168, 192, 0, 240, 5, 6, 251, 136, 208
50018 DATA 251, 24, 165, 254, 105, 0, 133, 254, 165, 255, 105, 32, 133
50019 DATA 255, 165, 253, 41, 2, 208, 7, 177, 254, 5, 251, 145, 254
50020 DATA 96, 177, 254, 5, 251, 69, 251, 145, 254, 96, -1

Like