Category Archives: Color BASIC

What you PSET is not always what you PPOINT

Let’s consider this a part 2 for this 2024 post:

The 9 colors of the CoCo’s high resolution screens…

Read that first, then come back. I’ll wait.

Ready… PSET… GO!

In Microsoft Extended Color BASIC on the Radio Shack Color Computer, high resolution graphics command were added. There were fancy commands like DRAW for drawing complex designs, then simpler command like LINE and CIRCLE.

Even simpler was the PSET command which would set an individual pixel on the screen. This was the high resolution equivalent of SET in Color BASIC for the text screen (64×32 blocks).

I had a Commodore VIC-20 at the time, but remember getting a call from my Radio Shack sales guy, Don, to tell me they had just gotten in a new Extended BASIC that I should come out. I did, and fell instantly in love with being able to do things with simple commands versus confusing POKEs on my VIC.

I read through the manual in the store, and created programs on their CoCo. One of them used PSET to randomly place dots on the screen:

0 'RNDPSET.BAS
10 PMODE 3,1:PCLS:SCREEN 1,1
20 PSET(RND(256)-1,RND(192)-1,RND(4)-1)
30 GOTO 20

Oh the fun we had back then.

Use the SCREEN 1,0 color set and you get different colors:

The PMODE 4 screen (256×192) was only two colors, white and black, but TV set (composite video, NTSC) created artifact colors that made it look weird. The emulators try to simulate this effect:

Depending on the mode the CoCo power up, even column pixels would be red and odd would be blue, or the reverse. While the CoCo 3’s video hardware could control this, on the CoCo 1 and 2 it was “random.” You could keep hitting the rest button until the colors flipped. Thus, many CoCo 1/2 games started up to a solid red (or blue) screen, expecting you to know what to do to get it the color the game wanted, or, if the programmer was fancy, it might even tell you what to do:

Paper Route by Diecom

And if the programmer was really fancy they could just handle it in software based on what you told it you saw (“Press 1 if the screen is RED, 2 if it is blue” kind of thing.)

NOTE: I wanted to include a screenshot of this but I cannot remember which games worked like that. If you know, leave a comment and I’ll update this post.

Get to the PPOINT!

PSET would put a pixel on the screen using a specific color:

The syntax is:

PSET (X, Y, C)

The C was the color, and it accepted a value of 0-8. But, you did not get nine colors on any of the high resolution screens. You got either 2 (black/green or black/buff or using the alternate color set), or 4 (green/yellow/blue/red or buff/cyan/magenta/orange using the alternate color set). You had to know the range of the 4 color values to use for the mode you were using.

Or did you?

No. The C value could be 0-8 on any graphics screen, so most programs I saw used 0-1 for two color, or 0-3 for four color. And that’s not at all how Radio Shack described it in the manual… but it worked and kept us from having to memory color ranges based on modes. (See my 2024 article, link at the top of this one, for a table showing how this worked.)

And my point is … PPOINT returns the value that “should” be used — not the value you PSET there! If you were using a screen that wanted colors 5-6-7-8 and you used colors 1-2-3-4, you could PSET color 1, but when you would PPOINT that pixel, you got back a 5 — the same color, but the value you were supposed to be using.

Thus, anyone who made use of PPOINT learned this. I did not use it, and I never learned it until 2024 in the comments to that earlier post.

So for fun, I wrote this program that cycles through each PMODE (0 to 4) and then PSETs each color value (0-8) to a pixel and then reads the pixel color back using PPOINT. It prints it out so we can see this:

The first value of the column is the C value that was used in PSET. The number after it is the return value from PPOINT. So “1) 5” means PSET(0,0,5) and P=PPOINT(0,0).

PMODE 0, PMODE 2 and PMODE 4 are a two color modes, so the range of colors you can use (0-8) are just the same two colors over and over – 0 and 5. PMODE 1 and PMODE 3 are four color modes, so you see the range repeating the same four color values over and over, different depending on the mode.

And, if you used the alternate color set (SCREEN 1,1), you got a different set of color values:

Here is the code:

10 'PPOINT0.BAS
20 'SET PIXEL USING COLOR
30 'THEN PPOINT THE COLOR
40 CLS
50 PRINT@6,"PMODES - SCREEN 1,0:"
60 PRINT STRING$(32,"-");
70 FOR M=0 TO 4
80 PMODE M,1:PCLS:SCREEN 1,0
90 PRINT:PRINT@64+M*7+1,M;
100 FOR C=0 TO 8
110 GOSUB 160
120 NEXT:NEXT

130 GOTO 130

140 'SET PIXEL WITH PSET
150 'GET PIXEL COLOR
160 PSET(0,0,C):P=PPOINT(0,0)
170 PRINT@96+M*7+32*C,USING "#) #";C;P;
180 RETURN

And slight changes for the other color set:

10 'PPOINT1.BAS
20 'SET PIXEL USING COLOR
30 'THEN PPOINT THE COLOR
40 CLS
50 PRINT@6,"PMODES - SCREEN 1,1:"
60 PRINT STRING$(32,"-");
70 FOR M=0 TO 4
80 PMODE M,1:PCLS:SCREEN 1,1
90 PRINT:PRINT@64+M*7+1,M;
100 FOR C=0 TO 8
110 GOSUB 160
120 NEXT:NEXT

130 GOTO 130

140 'SET PIXEL WITH PSET
150 'GET PIXEL COLOR
160 PSET(0,0,C):P=PPOINT(0,0)
170 PRINT@96+M*7+32*C,USING "#) #";C;P;
180 RETURN

It dawns on me now that a BASIC program could detect what screen was being used by PSETting something and then reading it back with PPOINT. Based on the number that returned, you could tell which PMODE and SCREEN was being used.

But that’s a program for a different time.

Until then…

A slightly faster MID$ using VARPTR

TL:DNR – This is stupid. Don’t bother trying it :)


Here is another stupid thing I had to try in Color BASIC. See also my Stupid VARPTR tricks post.

Suppose you want to horizontally scroll a string across the CoCo’s 32-column text screen. You can build a long string (up to 255 characters) and then use a FOR/NEXT loop and MID$ to print 32 characters from within that longer string.

20 CLS:CLEAR 510:DIM A$
30 A$="":FORA=32TO255:A$=A$+CHR$(A):NEXT:A$=A$+STRING$(31,128)
40 TIMER=0
50 FORA=1TO224:PRINT@256,MID$(A$,A,32);:NEXT
60 PRINTTIMER

On a CoCo 3, you get a timer result of around 330-335. On a CoCo 1/2, it is slightly faster showing around 295. (There are less BASIC keyword tokens to look for so Color BASIC is faster than Exended BASIC which is faster than Super BASIC.)

When I first started benchmarking BASIC here years ago, I was using an emulator that only ran CoCo 1/2, and it never occurred to me it would be different on the CoCo 3. #TheMoreYouKnow

As I have discussed in earlier string theory articles (quite a few relating to this topic), MID$, LEFT$ and RIGHT$ all need to create a new string containing data from the original. Suppose you have this:

A$="THIS IS A TEST"

If you trim the string to the first four characters, like this:

A$=LEFT$(A$,4)

…BASIC is basically doing this:

  1. Allocate new string space for a 4 character string.
  2. Copy the first four characters from A$ into the new string.
  3. Make A$ point to the new string, which leaves the original A$ string memory available for cleanup.

This is why you need extra string memory to use these functions. If you clear JUST enough memory to hold a ten character string, you can’t do any MID$, LEFT$ or RIGHT$ with that string.

In order to make that work, you need at least 4 extra bytes reserved for string memory so LEFT$ can make the new string before deallocating the original. And if you add 4 bytes but try to use 5, you get that ?OS ERROR (out of string space) still.

So if you have a 255 character string and you use MID$(A$,0,32) to get 32 characters from that string into a new string (or use it directly with PRINT, which will directly access that string memory without a variable needed), it has to allocate 32 bytes from the reserved string memory and copy those 32 bytes over, then you can use it (PRINT or assign to a variable or whatever).

As my sample program runs, it is allocating 32 byte strings and copying 32 bytes over each time through the loop.

VARPTR, can you help?

After recently learning a weird trick involving changing where a string variable points to for its string data, that made me wonder if you could just manipulate the string address using VARPTR and then PRINT it, and be faster than the overhead of MID$.

I just had to try this…

Here is my test program. It first builds A$ to contain character 32 (space) to character 255 (end of semigraphics characters) and then pads that with 31 black blocks to be the full 255 character string size.

Starting at line 40 is a loop that will PRINT a substring of 32 characters in a loop, starting at the first character and going to the end, making the line scroll to the left.

When done, it prints how many TIMER ticks it took to do this.

Next, starting in line 70, it makes a new B$ that is a clone of A$. (No, it doesn’t need to clone it. I could have just manipulated A$ and saved a few lines.)

It then gets the address of that string descriptor using VARPTR, and saves the size (at the first byte) and the address of the string data (third and fourth byte). This allows restoring the string after the test, since manipulating strings this way could cause problems with strings and garbage collection.

For this specific example I know that the MSB and LSB of the new string are 126 and 1 on my emulated CoCo. That means I could make the string’s starting address be one higher in that memory by incrementing the second value. Had that second value been 250, once I incremented it 5 times to 255, I’d have to increment the first one and reset the second one to 0. (Clear as mud?)

Let’s just say I got lucky enough for this test, but even if this approach DID work, it would not work on all strings based on where they are in memory. It would need extra code for that, which would slow it down even further.

I POKE to change the size of B$ to 32. Then I can go in a loop POKEing the second byte of the start address up by one each time, and simply PRINTing the string. It will print 32 bytes from wherever it thinks the string data begins. It has no idea those values are being manipulated.

When done, I print the time it took and restore the original B$ values back.

10 'VARMID.BAS
20 CLS:CLEAR 510:DIM A$
30 A$="":FORA=32TO255:A$=A$+CHR$(A):NEXT:A$=A$+STRING$(31,128)
40 TIMER=0
50 FORA=1TO224:PRINT@256,MID$(A$,A,32);:NEXT
60 PRINTTIMER
70 DIM B$,V,O2,O3,S1,S2,SS
80 ' CLONE A$. GET VARPTR OF B$.
90 ' V POINTS TO SIZE
100 ' O2-O3 POINTS TO START
110 B$=A$:V=VARPTR(B$):O2=V+2:O3=V+3
120 ' SS - SAVE SIZE
130 ' S1-S2 - SAVE START
140 SS=PEEK(V):S1=PEEK(O2):S2=PEEK(O3)
150 ' CHANGE SIZE TO 32
160 POKE V,32
170 ' CHANGE START ADDR THEN
180 ' PRINT.
190 TIMER=0
200 FORA=0TO223:POKEO3,S2+A:PRINT@256,B$;:NEXT
210 PRINTTIMER
220 ' RESTORE ORIGINAL STRING
230 POKE V,SS:POKE O2,S1:POKE O3,S2

Sadly, it is only a tiny bit faster, and if I had to take care of both address bytes in the VARPTR memory, it would be slower and, without testing this, I assume slower than just using MID$.

It was a fun experiment, but “sometimes the juice is not worth the squeeze.”

Until next time…

The CHANGE command on PDP8 BASIC is weird. And neat.

Recently, Rick “Shanghai” Adams pointed me to a BASIC program he was working on for a PDP-8. Much like I now spend my time playing with BASIC from 1980 on a CoCo 1 emulator, Rick is going even further back and playing with a version of BASIC from a machine created in the 1960s.

And its a bit different.

I have previously posted about this machine (well, PDP systems in general) when I was trying to find the origins of the INSTR command in BASIC. Then I was able to dig up a 1971 PDP-11 manual that referenced this function for that BASIC.

Rick sent me a link to a two-player game called CHOMP. I was unfamiliar with it, but see it has its own wiki page.

https://en.wikipedia.org/wiki/Chomp

On that entry, it is presented as a chocolate bar made up of squares you can break off. The top left square is poison, so whoever takes that final piece loses.

By Lord Belbury – Own work, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=86379139

This helps me understand why the came is called CHOMP.

But I digress… This really has nothing to do with that game, though CHOMP will likely return in a future blog post here.

BASIC may have been cooler in the 1960s…

Rick has a BASIC preprocessor that allows him to write easy to read source code, then convert it into messy BASIC code with line numbers later. Here is a Guest The Number game from Rick’s GitHub:

https://github.com/yggdrasilradio/b8pp/blob/master/guess.txt

	' Generate random number
randomize
x = int(100 * rnd(0)) + 1

' Intro
print "I'VE THOUGHT OF A NUMBER BETWEEN 1 AND 100."
print "CAN YOU GUESS WHAT IT IS?"

n = 0
60 n = n + 1
print
print "YOUR GUESS";
input g
if g <> x then 130

' Player wins!
print
print "YOU GUESSED IT IN"; n; "GUESSES!"

if n <= 7 then 120
print "BUT IT SHOULD HAVE ONLY TAKEN YOU 7 GUESSES."

120 stop

130 if g > x then 160
print "TOO LOW."
goto 60

160 print "TOO HIGH."
goto 60

end

That text is processed by his script and becomes this:

https://github.com/yggdrasilradio/b8pp/blob/master/guess.bas

1RANDOM\X=INT(100*RND(0))+1
2PRINT"I'VE THOUGHT OF A NUMBER BETWEEN 1 AND 100."
3PRINT"CAN YOU GUESS WHAT IT IS?"\N=0
60N=N+1\PRINT\PRINT"YOUR GUESS";\INPUTG\IFG<>XTHEN130\PRINT
61PRINT"YOU GUESSED IT IN";N;"GUESSES!"\IFN<=7THEN120
62PRINT"BUT IT SHOULD HAVE ONLY TAKEN YOU 7 GUESSES."
120STOP
130IFG>XTHEN160\PRINT"TOO LOW."\GOTO60
160PRINT"TOO HIGH."\GOTO60\END

…and that is the code that he loads and runs on the PDP emulator.

The first thing you will notice is the use of a backslash. Initially, I thought this was just in place of a colon. For example, I see things like:

PRINT "TOO HIGH"\GOTO 60

…and that looks like it is just…

PRINT "TOO HIGH":GOTO 60

…but once I started converting PDP CHOMP to work on the CoCo, I realized that was not the intent of the backslash there. It appears to be a way to have multiple lines without line numbers. The logic does not continue to flow through those slashes:

60N=N+1\PRINT\PRINT"YOUR GUESS";\INPUTG\IFG<>XTHEN130\PRINT

Above, if G is not equal to X, it goes to line 130. There is a PRINT after that which would NEVER be reached if these were just colons:

60N=N+1:PRINT:PRINT"YOUR GUESS";:INPUTG:IFG<>XTHEN130:PRINT

To port this to Microsoft Color BASIC, I would have to do something like this:

60 N=N+1:PRINT:PRINT"YOUR GUESS";:INPUTG:IFG<>XTHEN130
61 PRINT

And guess what? That is also not important to this blog post. But might be later to a follow up blog post about porting PDP BASIC CHOMP to CoCo BASIC CHOMP.

CHANGE is … good?

Rick has entered the Logiker Christmas Challenge in the past with entries done in this much earlier BASIC. I have seen him comment on the far more limited STRING handling in that version of BASIC which required some very different approaches to the challenges.

Now I understand what he means.

While looking at his CHOMP source code, there is a keyword I had never seen before – CHANGE. He explained it to me:

“The CHANGE statement converts strings to and from an array, and the zeroth element of the array is the length of the string”

– Rick Adams

I saw it used like this:

40	print
print "YOUR MOVE";
input m$
change m$ to m

Or, in the converted BASIC:

40PRINT\PRINT"YOUR MOVE";\INPUTM$\CHANGEM$TOM

So if you did something like this:

M$="ABC"
CHANGE M$ TO M

…then you would get this:

FOR I=0 TO M(0):PRINT M(I):NEXT
3
65
66
67
  • M(0) is the length of the converted string.
  • M(1) is the first character of the string (“A”)
  • M(2) is the second character of the string (“B)”
  • M(3) is the third character of the string (“C”)

That’s kinda neat. To do the same thing on Color BASIC, we could make subroutines like this:

2000 'M TO M$
2010 M$="":FORZ=1TOM(0):M$=M$+CHR$(M(Z)):NEXT:RETURN

3000 'M$ TO M
3010 M(0)=LEN(M$):FORZ=1TOM(0):M(Z)=ASC(MID$(M$,Z)):NEXT:RETURN

And then we could change “CHANGE M$ TO M” to “GOSUB 3000” and “CHANGE M TO M$” to GOSUB 2000.

10 INPUT M$:GOSUB 3000
20 FOR I=0 TO M(0):PRINT M(I):NEXT:END

Or reverse it, if we created one manually:

10 M(0)=3:M(1)=65:M(2)=66:M(3)=67:GOSUB 2000
20 PRINT M$:END

Though Rick pointed out with MID$() and such available, there would be far easier ways to do this. But those subroutines are what I will be using so I can more directly run his PDP BASIC code with minimal changes.

Have you ever worked on a BASIC that used the CHANGE command? If so, what was it? Leave a comment, please.

Until next time…

Revisiting PUT defined by ASCII strings

This is a followup (and correction) to my PUT defined by ASCII strings article. That article, itself, was a followup to my Extended Color BASIC PUT from DATA article. They both discuss a method to use the GET/PUT graphics commands with pre-loaded data to PUT on the screen, rather than having to render/draw something first and then GET it so you could PUT it later.

I post such articles for two main reasons:

  1. So I can learn from all the much-smarter programmers who leave comments with advice/suggestions/corrections.
  2. So I can find it again when I’ve forgotten how it worked.

#2 is what led me to my article as I wanted to use the code for another experiment. And that’s when I realized my original PUTDATA.BAS program had a bug: it PUTs the tanks flipped vertically!

The program defined 8×8 characters as ASCII strings. I used a tank with four versions – one for each direction. They looked like this:

580 'TANK UP
590 DATA " XX "
600 DATA " XX "
610 DATA "XX XX XX"
620 DATA "XXXXXXXX"
630 DATA "XXXXXXXX"
640 DATA "XXXXXXXX"
650 DATA "XXXXXXXX"
660 DATA "XX XX"

A routine READs those strings from the DATA statements, then walks through the characters looking for an “X”. If it finds one, it sets a bit in a number variable. At the end of the scan, it now has a byte value which can be loaded into the PUT data.

However, my routine to scan the strings does it backwards and the image is reversed left-to-right:

380 '
390 'READ DATA AND POKE AT L
400 '
410 PRINT
420 'READ STRINGS AND CONVERT
430 'TO BYTES.
440 FOR Z=0 TO 7:V=0
450 READ Z$:PRINT Z$,;
460 FOR BT=1 TO 8
470 'FASTER WAY
480 IF MID$(Z$,BT,1)="X" THEN V=V+BT(BT-1)
490 'SLOW WAY
500 'IF MID$(Z$,BT,1)="X" THEN V=V+2^(BT-1)
510 NEXT:PRINT INT(V);HEX$(V)
520 POKE L+Z,(NOT V)+256:NEXT:RETURN
530 NEXT:PRINT V;HEX$(V):NEXT
540 RETURN

I did not notice this until I tried to use this code for a new experiment, and it was not PUTting what I expected. But for the tanks, being symmetrical, I did not catch it in my original demo. The UP and DOWN tanks looked correct, and I failed to notice my LEFT and RIGHT tanks were reversed.

The bug is from the loop at line 460 that walks through the bits from 1 to 8, and uses that value as the index into the string using MID$. A bit from 1 to 8 is rightmost to leftmost, but on a string, 1 to 8 is leftmost to rightmost. One of them needs to work backwards.

Since I already do some math to calculate the bit (to base-0 counting, 0-7 instead of 1-8), I just made my change there:

470 'FASTER WAY
480 IF MID$(Z$,BT,1)="X" THEN V=V+BT(8-BT)
490 'SLOW WAY
500 'IF MID$(Z$,BT,1)="X" THEN V=V+2^(8-BT)

Now I get the tanks facing the proper directions my test program PUTs them on the screen: UP, DOWN, LEFT then RIGHT.

I have added this code to my GitHub repository in “CoCo Programs” under “basic”:

https://github.com/allenhuffman/CoCo-Programs/tree/main/basic/tank

And here is the full version with the fix:

0 'PUTDATA2.BAS (FIXED BUG)
1 '2026-05-06
2 'SHOWS HOW TO DO IT USING
3 'STRINGS RATHER THAN #S
4 '

10 'TO SPEED UP STR-TO-BYTE
20 DIM BT(7):FOR BT=0 TO 7:BT(BT)=2^BT:NEXT
30 '
40 'VARIABLES USED IN THE
50 'POKE-TO-ARRAY ROUTINE MUST
60 'BE PRE-ALLOCATED OR THEY
70 'WILL CAUSE ARRAY MEM TO
80 'SHIFT WHEN IT GET USED.
90 '
100 DIM L,V,Z,Z$
110 '
120 'EACH ARRAY ENTRY CAN STORE
130 '5 BYTES. AN 8X8 SINGLE
140 'COLOR CHARACTER IS 8, SO
150 'WE NEED TWO ARRAY ENTRIES
160 '(10 BYTES) TO FIT THE 8
170 'BYTE CHARACTER.
180 '
190 DIM TU(1),TD(1),TL(1),TR(1):GOSUB 320

200 '
210 ' TEST PROGRAM
220 '
230 PMODE 4,1:PCLS 1:SCREEN 1,1
240 PUT (0,0)-(7,7),TU
250 PUT (16,0)-(16+7,7),TD
260 PUT (32,0)-(32+7,7),TL
270 PUT (48,0)-(48+7,7),TR
280 GOTO 280

290 '
300 'LOAD SPRITE CHARACTERS
310 '
320 PRINT "LOADING DATA";
330 L=VARPTR(TU(0)):GOSUB 390
340 L=VARPTR(TD(0)):GOSUB 390
350 L=VARPTR(TL(0)):GOSUB 390
360 L=VARPTR(TR(0)):GOSUB 390
370 RETURN

380 '
390 'READ DATA AND POKE AT L
400 '
410 PRINT
420 'READ STRINGS AND CONVERT
430 'TO BYTES.
440 FOR Z=0 TO 7:V=0
450 READ Z$:PRINT Z$,;
460 FOR BT=1 TO 8
470 'FASTER WAY
480 IF MID$(Z$,BT,1)="X" THEN V=V+BT(8-BT)
490 'SLOW WAY
500 'IF MID$(Z$,BT,1)="X" THEN V=V+2^(8-BT)
510 NEXT:PRINT INT(V);HEX$(V)
520 POKE L+Z,(NOT V)+256:NEXT:RETURN
530 NEXT:PRINT V;HEX$(V):NEXT
540 RETURN

550 '
560 '8X8 SPRITE CHARACTERS
570 '
580 'TANK UP
590 DATA " XX "
600 DATA " XX "
610 DATA "XX XX XX"
620 DATA "XXXXXXXX"
630 DATA "XXXXXXXX"
640 DATA "XXXXXXXX"
650 DATA "XXXXXXXX"
660 DATA "XX XX"

670 'TANK DOWN
680 DATA "XX XX"
690 DATA "XXXXXXXX"
700 DATA "XXXXXXXX"
710 DATA "XXXXXXXX"
720 DATA "XXXXXXXX"
730 DATA "XX XX XX"
740 DATA " XX "
750 DATA " XX "

760 'TANK LEFT
770 DATA " XXXXXX"
780 DATA " XXXXXX"
790 DATA " XXXX "
800 DATA "XXXXXXX "
810 DATA "XXXXXXX "
820 DATA " XXXX "
830 DATA " XXXXXX"
840 DATA " XXXXXX"

850 'TANK RIGHT
860 DATA "XXXXXX "
870 DATA "XXXXXX "
880 DATA " XXXX "
890 DATA " XXXXXXX"
900 DATA " XXXXXXX"
910 DATA " XXXX "
920 DATA "XXXXXX "
930 DATA "XXXXXX "

Until next bug … I mean, time. Until next time…

GFXFLIP2.BAS – scrolling a PMODE 4 screen.

In a post to the CoCo mailing list, Juan Castro said this:

“… I was trying to comment on this post – https://subethasoftware.com/2026/05/19/where-does-cocos-pmode-graphics-memory-start/#comment-42465 – and I was trying to say this:

In GFXFLIP.BAS, instead of the ‘flip through them’ code, try this:

1000 ‘GO DO THE ROTATION
1010 GOTO 1050
1020 FOR P=2 TO 5:GOSUB 1070:PMODE 4,P:SCREEN1:NEXT
1030 IF INKEY$=”” THEN 1030
1040 FOR P=4 TO 1 STEP -1:GOSUB 1070:PMODE 4,P:SCREEN1:NEXT
1050 IF INKEY$=”” THEN 1050
1060 GOTO 1020
1070 FOR TT=0 TO 40:NEXT:RETURN

– Juan Casto via CoCo Mailing list

So let’s take a look and see what it does. Replacing my code from 70-110 with a GOSUB to this routine gives us this:

0 'GFXFLIP2.BAS
1 'Juan Castro
10 PCLEAR 8
15 ' DRAW FIRST SCREEN
20 PMODE 4,1:PCLS:SCREEN 1,1
30 CIRCLE(128,96),50
35 ' DRAW SECOND SCREEN
40 PMODE 4,5:PCLS:SCREEN 1,1
50 LINE (10,10)-(245,171),PSET,B
60 ' FLIP THROUGH THEM
70 GOSUB 1000
110 GOTO 70

1000 'GO DO THE ROTATION
1010 GOTO 1050
1020 FOR P=2 TO 5:GOSUB 1070:PMODE 4,P:SCREEN1:NEXT
1030 IF INKEY$="" THEN 1030
1040 FOR P=4 TO 1 STEP -1:GOSUB 1070:PMODE 4,P:SCREEN1:NEXT
1050 IF INKEY$="" THEN 1050
1060 GOTO 1020
1070 FOR TT=0 TO 40:NEXT:RETURN

…and when you run it, you will see it takes the PMODE 4 screen (which is 4 blocks of graphics memory) then goes in a loop where it starts the displayed screen at block 2, then 3, then 4, then 5. With a small delay in-between each change, it shows (initially) the first PMODE 4 screen (blocks 1-4), then it toggles the memory displayed through each block until the start is block 5. This makes the screen appear to scroll up in chunks (1/4th of the screen each time). The process is then reversed to scroll back down.

Neat trick.

Stupid VARPTR tricks

A recent e-mail exchange with CoCo user Torsten D. inspired me to try something stupid.

The Radio Shack Color Computer gained the VARPTR command in the Extended BASIC ROM. As has been discussed here many times, VARPTR returns the memory location of a 5-byte variable descriptor. There are actually seven bytes total, since the two bytes before the VARPTR address is the two byte variable name.

0 'MAKE42-1.BAS
10 DIM A,B,C:A=42:B=VARPTR(A)
20 FOR C=B-2 TO B+4
30 PRINT C,PEEK(C):NEXT

Running this will show the full seven bytes required to represent the A variable:

VARPTR is returning 9792 as the location of the start of the 5-byte floating point value for the numeric A variable. The two bytes before it are the variable name: 65 (uppercase “A”) and 0 (no second letter). Had the variable name been “AA” that would be 65 65.

The five bytes of 134, 40, 0, 0 and 0 are the floating point representation of 42.0.

If you got the VARPTR address of one numeric variable, and of a second numeric variable, you could just copy those five bytes and clone the variable value:

0 'MAKE42-2.BAS
10 DIM A,B,I
20 A=42:B=0
30 PRINT "A =";A,"B =";B
40 FOR I=0 TO 4:POKE VARPTR(B)+I,PEEK(VARPTR(A)+I):NEXT
50 PRINT "A =";A,"B =";B

If you run this, you will see output showing “A = 42” and “B = 0”, followed by output showing “A = 42” and “B = 42”. The code in line 40 copies the five bytes (offset 0 to 4) from the VARPTR address of variable A into the VARPTR address of variable B.

But why would you want to do that?

B=A is would have been much simpler.

Here’s where it gets more stupid…

And if you can clone a variable, you could also change a variable if you knew what five bytes represented the number you wanted. In the first example, we saw that the five bytes that represent 42.0 are 134, 40, 0, 0 and 0. Knowing that, you could do something like this:

0 'MAKE42-3.BAS
10 DIM A,V
20 PRINT "A =";A
30 V=VARPTR(A):POKE V,134:POKE V+1,40: POKE V+2,0:POKE V+3,0:POKE V+4,0
40 PRINT "A =";A

The “DIM” is not really needed in this example, but it is a good habit to get into if you want to control the order your variables exist in the variable table. Variables that need to be the fastest should be at the front of the list, and variables use infrequently or ones that can be slow can be at the end.

But I digress.

The point of this stupid code is that an “A” variable is created with 0 as its default value, then VARPTR is used to see where that variable is in memory. Five POKE commands put that floating point representation of 42.0 into that variable’s storage… So when you print A, you get a value of 42, even though A=42 (or indeed, A= ANYTHING) was nowhere in the program.

I have no idea why you would want to do that.

Until next time…

Where does CoCo’s PMODE graphics memory start?

When I got my first Radio Shack TRS-80 Color Computer 1 back around 1983, I dove into the Getting Started manuals and learned all the new wonderful commands that EXTENDED COLOR BASIC offered me that my Commodore VIC-20 did not have. Commands like PLAY for music, SOUND for a beep, and graphics commands to draw CIRCLEs, LINEs and even DRAW complex objects were … amazing.

On my original tape based CoCo (EXTENDED COLOR BASIC) the high-resolution graphics memory started just after the memory used for the 32×16 text screen:

DEC     HEX     DESCRIPTION
----- ---- -----------
0 0000 Color BASIC Use
512 0400 Text Screen
1536 0600 Hi-Rez Graphics

Knowing that, as I learned some 6809 assembly language I wrote routines to scroll a PMODE 4 256×192 graphics screen. I used this to do video titles for my dad. I’d create a screen using a graphics program, and load that into the second half of the graphics memory, then let my routine smooth scroll that screen into view.

I’d love to find that old source code and see how awfully inefficient it was. I bet one of you could really show me a faster way to do it.

But I digress…

DISK EXTENDED BASIC changed everything!

The next major leap in home computing for me was getting a disk drive for my CoCo. Imagine being able to store up to 156K of data on a floppy disk, and load things at such blazing speed (compared to the tape player and it’s 1500 baud rate).

It was nice… but it broke my assembly code! It turned out, when DISK BASIC was added, it used memory after the text screen for its own purposes, and shifted the high resolution graphics memory 2K further down in the memory map:

DEC     HEX     DESCRIPTION
----- ---- -----------
0 0000 Color BASIC Use
512 0400 Text Screen
1536 0600 Disk BASIC Use
3584 0E00 Hi-Rez Graphics

Learning this, I adjusted my assembly routines to work on graphics screens starting at 3584 (disk systems) rather than 1536 (tape systems).

How do we know?

I wondered if there was some programmatic way to tell where the screen started. I don’t think this even dawned on me back in the 1980s, but I asked this question to the new Color Computer mailing list and quickly got an answer:

Word at $BC (GRPRAM) is start of graphics RAM. Word at $BA (BEGGRP) gets you the start of the current view window.

Juan Castro
Enviado do meu Olivetti Programma 101
http://retropolis.com.br

Bonus. Not only can you tell where graphics memory starts, but you can tell which page is displayed. With EXTENDED BASIC, you have 8 1.5K pages of graphics memory you can use. You reserve them with the PCLEAR command (it defaults to 4 pages). You can learn more about PCLEAR in this article.

PMODE 3 (128×192 4-color) and PMODE 4 (256×192 2-color) both need 4 pages, so you can have two screens in those modes. PMODE 0 uses 1 page, so you can have 8 pages in that ode.

  • PMODE 0 – 128×96 2-color (1536 bytes)
  • PMODE 1 – 128×96 4-color (3072 bytes)
  • PMODE 2 – 128×192 2-color (3072 bytes)
  • PMODE 3 – 128×192 4-color (6144 bytes)
  • PMODE 4 – 256×192 2-color (6144 bytes)

When you use PMODE, the first parameter is the graphics mode, and the second is which page for the screen to start on. For PMODE 4 you can do “PMODE 4,1” to get one screen of 4 pages starting at page 1, and “PMODE 4,5” to get a second screen of 4 pages starting at page 5. You can set PMODE to the first screen and draw something, then set it to the second screen and draw something different, then flip back and forth between them using PMODE. Here is a silly example:

0 'GFXFLIP.BAS
10 PCLEAR 8
15 ' DRAW FIRST SCREEN
20 PMODE 4,1:PCLS:SCREEN 1,1
30 CIRCLE(128,96),50
35 ' DRAW SECOND SCREEN
40 PMODE 4,5:PCLS:SCREEN 1,1
50 LINE (10,10)-(245,171),PSET,B
60 ' FLIP THROUGH THEM
70 PMODE 4,1:SCREEN 1,1
80 FOR A=1 TO 100:NEXT
90 PMODE 4,5:SCREEN 1,1
100 FOR A=1 TO 100:NEXT
110 GOTO 70

That program will reserve all 8 pages, then set a PMODE 4 screen starting at page 1. It draws a circle on that page. Then it sets a PMODE 4 screen starting at page 5. It draws a box on that screen. After that it just toggles between showing PMODE 4 starting at page 1, then at page 5, and the image will flicker back and forth between the circle screen and the square screen.

With low-resolution PMODE 0, you can do 8 screens of animation this way.

I wrote a second program that will print out where screen memory starts, and where the current viewed page starts.

0 ' SCRSTART.BAS
1 ' THANK YOU, JUAN CARLOS!
10 PCLEAR 8
20 FOR P=1 TO 8:PMODE 0,P
30 PRINT PEEK(&HBC)*256+PEEK(&HBD),PEEK(&HBA)*256+PEEK(&HBB)
40 NEXT P

When I run this on an tape-based EXTENDED BASIC CoCo (emulator) with no Disk Controller, it shows graphics memory starts at 1536 and then it toggles through each PMODE 0 page to show where each one would start:

And when DISK EXTENDED BASIC is used, the same program shows the memory locations starting 2K higher in memory:

Thank you, Juan Carlos, for telling me this. I wish I had known about this back then. I could have made my assembly program automatically find the start of the graphics screen rather than having to assembly separate versions for tape or disk systems.

Until next time…

Creating ASCII Donkey Kong on a 32×16 CoCo display

Last year, I spent some time fooling around in Color BASIC rendering a Donkey Kong-style screen in ASCII. Since I was not using the CoCo 3 40 or 80 column screen, I was limited to the 32×16 text screen of the CoCo’s MC6847 VDG display chip.

First, here is what the arcade Donkey Kong screen looks like. (Image from Wikipedia.com)

Donkey Kong arcade (image from Wikipedia)

For my first attempt, I counted how many “blocks” across the screen it would take to render this level accurately. I did this by looking at the girder patterns where they change levels. It looked like to of the “/\/\” patterns could be a block, making 14 across the screen. I could then double that to 28, which would fit into the CoCo’s 32×16 screen with some space on each side.

I mapped it out in a text editor, and came up with this rough approximation:

12345678901234567890123456789012
H H BONUS
H H 3900
H HXXXXXXX
OO H H H
OO.....H H H
XXXXXXXXXXXXXXXXXXXXXXXXXX
H
XXXXXXXXXXXXXXXXXXXXXXXXXX
H H
XXXXXXXXXXXXXXXXXXXXXXXXXX
H H H
XXXXXXXXXXXXXXXXXXXXXXXXXX
H H
XXXXXXXXXXXXXXXXXXXXXXXXXX
U H
XXXXXXXXXXXXXXXXXXXXXXXXXXXX
12345678901234567890123456789012

The numbers at the top and bottom were the columns and not part of the screen.

I was then able to use each “block” location to position the ladders (“H”) close to where they should be, as well as where the barrels should go (“U” for the one at the bottom, “O” at the top for the ones next to kong at the top).

If I take that original arcade screen shot and grid it out to be 28×16, it looks like this:

This is when I learned something interesting. Look at how the “1UP”, “HIGH SCORE” and numbers line up to the blocks. Donkey Kong likely is using a 28x?? tile system. This website breaks apart the tiles that make up the game screens:

https://www.spriters-resource.com/arcade/dk/asset/106602

Indeed, 28 across by what looks like 32 down. As long as the screen could be done with half as many rows, it could be fairly close to the arcade. Here is what my ASCII version looks like on a CoCo emulator:

And let’s see if I can do side-by-side in WordPress:

With 32 rows in the arcade version, Mario and Pauline’s characters would be two blocks high. Since I had to half the rows to fit on the 16 row text screen, they would need to be one character block in height. A similar adjustment would have to be done for Donkey Kong.

In the arcade, Kong looks to be made up of 5×5 blocks and placed on the screen a bit lower in the grid so he stands on the top girder. From looking at arcade sprite resources, they don’t show the girder as part of the Kong graphic, so I will assume 5×5 is correct. When he is facing forward, he is centered, but when he is rolling the barrels, he extends all the way to the left or right boundary.

That is a problem, since at half height, a 5×2 row couldn’t represent Kong very well. This will be one of the major things that has to change to represent Kong on this screen. Looking at the arcade sprites, turned into the 5×4 grid, looks like this:

For my initial ASCII experiment, I came up with these:

-----
@
/=
|\
-----
@
<=>
/ \
-----
@
=\
/|
-----

I kept the area 5 blocks wide, but made it 3 tall and just tried to get something close to the animation the graphical version had. Since I see Kong actually reaches down to the ground, perhaps something like this might be better:

-----
(@
/=
/ |\
-----
@
<=>
/ \
-----
@)
=\
/| \
-----

…but I think I prefer the simplicity of the first attempt.

With every row being half the size of the arcade, instead of a rolling barrel being a full block tall, it now is half a block. I could use something like an ASCII period (“.”) I guess. And for the fireball, I could use something like an “*” or maybe “&” or “@”. It gets ugly real fast.

I am going to go think on this a bit… Comments if you have them.

Until next time…

POKE versus PRINT

See Also: part 1 and part 2 (coming soon).

This is a followup to a recent post I made about making a string in Color BASIC contain data from the text screen memory.

ASCII me no questions…

Color BASIC deals with a version of ASCII where specific numbers represent specific characters/letters:

https://en.wikipedia.org/wiki/ASCII

On the old school 8-bit home computers, not all of them used ASCII. Commodore used a variation called PETSCII, and the Atari 8-bits used ATASCII. While the trick discussed in this article might work on other systems that have a VARPTR or similar command, this discussion will be specifically about the character set in the Radio Shack Color Computer.

ASCII 65 is the uppercase letter ‘A’

PRINT CHR$(65)
A

If you POKE the value of 65 to the first position on the 32×16 text screen (location 1024), you will also see an uppercase 65.

POKE 1024,65

However, the embedded font data in the MC6847 VDG video generator chip does not follow ASCII for all of its characters. For example, CHR$(0) to CHR(31) are non printable characters. On the CoCo, two of them do something special — CHR$(8) will print a backspace and CHR$(13) will print an ENTER:

PRINT "HELLO";CHR$(8);"THERE";CHR$(13);"HOWDY"
HELLTHERE
HOWDY

It would have been nice if the CoCo could have done a beep for CHR$(7) like Apple 2s did, or clear the screen with CHR$(12) like many other systems did, but those are the only two that do anything other than “print nothing” on the CoCo.

If you POKE around a bit…

While you will not see anything if you PRINT those characters, if you POKE those values to the screen memory you will see something. For example, you could POKE characters 0 to 31 to the first row of the 32 column text screen like this:

FOR A=0 TO 31:POKE 1024+A,A:NEXT

The character set in the video chip has 0-31 representing reverse video characters “@” (AT sign) to “<-” (left arrow). We can expand that loop to POKE the first 128 characters onto the video screen:

FOR A=0 TO 127:POKE 1024+A,A:NEXT

But for PRINTing the ASCII characters, we have already established nothing shows up for characters 0-31, but things do PRINT when for 32-128:

FOR A=32 TO 127:PRINT CHR$(A);:NEXT

I put together this sloppy program that will show the differences, 32 characters at a time, of what you get when you PRINT the character values versus POKE the character values:

0 'POKEPRNT.BAS
10 CLS

20 PRINT@0,"PRINT 0-31:"
30 FOR A=0 TO 31:PRINT CHR$(A);:NEXT
40 PRINT@64,"POKE 0-31:"
50 FOR A=0 TO 31:POKE 1120+A,A:NEXT

60 PRINT@128,"PRINT 32-63:"
70 FOR A=32 TO 63:PRINT CHR$(A);:NEXT
80 PRINT@192,"POKE 32-63:"
90 FOR A=0 TO 31:POKE 1248+A,32+A:NEXT

100 PRINT@256,"PRINT 64-95:"
110 FOR A=64 TO 95:PRINT CHR$(A);:NEXT
120 PRINT@320,"POKE 64-95:"
130 FOR A=0 TO 31:POKE 1376+A,64+A:NEXT

140 PRINT@384,"PRINT 96-127:"
150 FOR A=96 TO 127:PRINT CHR$(A);:NEXT
160 PRINT@448,"POKE 96-127:"
170 FOR A=0 TO 31:POKE 1504+A,96+A:NEXT

999 GOTO 999

Looking at this, you can see only the characters 64-95 match between PRINT and POKE.

This means that the “copy screen to a string” concept from my earlier post doesn’t really do what we might expect. It does copy the data, but if we PRINT it back, we do not get back exactly what we started with.

This is the same thing that would happen if you tried to build a string by using PEEK from screen memory. This example prints stuff on the first line of the screen, then builds a string made of up characters using the PEEK value of that first line:

0 'PEEK2STR.BAS
10 CLS
20 PRINT "HELLO, WORLD! THIS IS A TEST."
30 FOR A=1024 TO 1024+31
40 A$=A$+CHR$(PEEK(A))
50 NEXT
60 PRINT "PEEKED STRING:"
70 PRINT A$

And running that shows this awfulness…

Yuck!

But that’s okay since there is not much use to copying TEXT data and then putting it back with PRINT. PRINT is fast, and we can easily PRINT that text data. Sure, there could be benefits if stuff being PRINTed is doing calculations and such to generate the output, but this trick won’t help there.

However, the semi graphics characters (128-256) are the same between PRINT and POKE.

0 'POKEPRT2.BAS
10 CLS
20 FOR A=0 TO 255
30 PRINT@A,CHR$(A);
40 POKE 1280+A,A
50 NEXT
60 GOTO 60

The top half is the PRINT CHR$ and the bottom half is the POKE:

Since there is no way on the CoCo to type those semi graphics characters into a string (pity, the later MC-10 could do this), we are forced to PRINT them like this:

PRINT CHR$(128);CHR$(128);CHR$(128)

That would print three black blocks. To speed things up, we could pre-generate a string of those three black blocks then we can PRINT that string very fast later:

A$=CHR$(128);CHR$(128);CHR$(128)
PRINT A$

And now you know why I chose to do a “splash screen” example for my demo in part 1. I initially tried it using the TEXT characters and quickly remembered why that can’t work (as explained here).

But it’s still a neat trick.

Bonus: This is stupid

For dumb fun, here is a program that makes A$ be whatever is on the first 32 character line of the screen.

0 'DUMBSTRN.BAS
10 A$="":A=VARPTR(A$):POKEA,32:POKEA+2,4:POKEA+3,0

When you RUN that, doing a PRINT A$ will show a 32 character line that is whatever was on the first line of the screen. If you do a “CLS” to clear the screen and show “OK” on the top line, then PRINT A$, you will see “OK” followed by 30 reverse @ symbols, which is CHR$(96) — but in video memory, a 96 is an empty block (space).

And with that, I’m going to stop now.

Unit next time…

Why is Microsoft BASIC INSTR like this?

UPDATE: I believe I have found the answer, and will share it in an upcoming post. Until then, keep those comments coming. I learn so much from all of you!


This topic has been discussed here years ago, but every time something reminds me about it, I get annoyed. While my annoyance is triggered by how it works in the CoCo’s Extended Color BASIC, past research showed the behavior was the same even in much later Microsoft Visual BASIC. But why?

INSTR is a command to return the index where a target string is found in a search string. From one of the Getting Started with Extended Color BASIC manuals, it is shown as this:

What the manual did not mention is that it can also return 1 when there is no match. See this example:

Looking for “B” in “ABC”? That’s at position 2. Good.

Looking for “X” in “ABC”? It is not there, so it returns 0. Good.

Looking for “A” in “ABC”? That’s at position 1. Good.

Looking for “” in “ABC”? Apparently “” is found at position 1. Don’t tell that to the “A” there.

Callbacks

I ran into this years ago when I was experimenting with various ways to handle key presses. You could have code block until a key was pressed, and then pass the key to INST and then use ON GOTO/GOSUB to get to the routine. Like this:

0 'INSTR.BAS
10 PRINT "A)BORT, R)ETRY, C)ONTINUE:";
20 A$=INKEY$:IF A$="" THEN 20
30 LN=INSTR("ARC",A$)
40 IF LN>0 THEN ON LN GOSUB 1000,2000,3000
50 GOTO 10

1000 ' ABORT
1010 PRINT"ABORT":STOP

2000 ' RETRY
2010 PRINT "RETRY":RETURN

3000 ' CONTINUE
3010 PRINT "CONT":RETURN

This was a great technique when dealing with a long list of menu options.

I had tried to optimize this by eliminating the A$ and embedding it inside the INSTR (someone in the comments may have suggested this to me; not sure if I am clever enough to have thought that up):

ON INSTR("ARC",INKEY$) GOSUB 1000,2000,3000

…but if I put that in my code replacing lines 20-40, running it immediately shows me “ABORT” as if INSTR returned 1.

Because INSTR returned 1.

The workaround suggested to me (again, from smart folks in the comments) was maybe to add a bogus value as the first search string character, and have that routine do nothing.

ON INSTR("*ARC",INKEY$) GOSUB 999,1000,2000,3000

However, for my example where I show the prompt again after it returns, it sticks in a loop printing the prompt over and over again. The code thinks the first option is being selected, then calls that routine (the empty routine that is just a RETURN in line 60) and then prints the prompt again.

0 'INSTR2.BAS
10 PRINT "A)BORT, R)ETRY, C)ONTINUE:";
20 ON INSTR("*ARC",INKEY$) GOSUB 60,1000,2000,3000
50 GOTO 10
60 RETURN

1000 ' ABORT
1010 PRINT"ABORT":STOP

2000 ' RETRY
2010 PRINT "RETRY":RETURN

3000 ' CONTINUE
3010 PRINT "CONT":RETURN

SO … it works, but the logic needs to be updated.

One quick solution is to not use RETURN and let each function decide where to go back to. When you GOSUB, BASIC has to scan forward (possibly starting at the top of the program if the line number is before the current line being parsed) to find the target. RETURN lets it “pop” back to right after the GOSUB, so that part is faster.

Also, GOSUB routines can be called from different places in the main code and they will return back to where they were called.

If these routines are never called from anywhere but the menu code, and the extra speed to GOTO back is not a problem, this this change makes it work. And, as a bonus, the fake first GOTO line can just be back to the ON INSTR again since it doesn’t need to do anything:

0 'INSTR3.BAS
10 PRINT "A)BORT, R)ETRY, C)ONTINUE:";
20 ON INSTR("*ARC",INKEY$) GOTO 20,1000,2000,3000

1000 ' ABORT
1010 PRINT"ABORT":STOP

2000 ' RETRY
2010 PRINT "RETRY":GOTO 10

3000 ' CONTINUE
3010 PRINT "CONT":GOTO 10

I am sure there are many other ways to solve this problem.

But why do we have to?

Why does INSTR behave like this? What is the benefit of not returning 0?

Hmmm, A.I. did not exist when I was first exploring this. Maybe I’ll ask one of the ‘bots and see what it knows.

Until next time…