CoCo bouncing BASIC ball, part 5

See also: part 1, part 2, part 3, part 4 and part 5.

It seems any time I touch BASIC these days, it turns into a benchmarking session to see if I can do something faster.My Jim Gerrie-inspired bouncing ball program has taken quite a tangent, and today it not going to change that.

MC-10 has its advantages

As previously discussed, PRINT@ seems to be the fastest way to put characters on the screen. But what if you want something that’s not just text? In Jim’s MC-10 demo, he uses the semi graphics characters in his ball. The MC-10’s BASIC allowed you to type those characters similarly to how Commodore computers let you type in their PETASCII characters. The excellent MC-10 Javascript Emulator has this image showing the keyboard layout:

MC-10 keyboard layout (image from

If you look at the keys, you will see some contain graphics blocks next to the letter (Q and a solid block, F and checkerboard, etc.). You can generate them with SHIFT-Letter. You also see some keywords above the keys which you could generate by doing CONTROL-Letter. This let them type in graphics characters in a PRINT statement: emulator showing how to “type” demographics characters.

Advantage MC-10. We have no way to do that on the CoCo.


So how do we print the graphics characters? We use CHR$() which will print whatever character we tell it to. For example, letter “A” is ASCII 65. We could type:


…and it would print the letter A.

Our graphics characters start at 128 and go to 255, looping the same basic shapes through the 8 available colors (color + black). We can see them all by typing:

Using PRINT CHR$() to print the CoCo semi graphics characters.

If I knew which characters to use to draw a ball, I could print them using CHR$(). Unfortunately, I don’t. I have no idea where my old CoCo “quick guide” is from the 1980s that listed them all. Fortunately, Simon Jonassen has a website that lets us design semi graphics:

Using my previous text ball for reference, I want to make a semi graphics ball that is 10×7 characters (so it appears round on the 32×16 4:3 aspect ratio display…). Using Simon’s tool, I came up with this:

It’s not a great ball, but it gives me something to start with.

On the bottom right of this web page are buttons to spit out the assembly, BASIC or CSV “code” to display this. But, it’s the whole screen, and looks like this:

100 A$=INKEY$:IFA$="" THEN100
1000 DATA 128,161,166,172,172,172,172,169,162,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1010 DATA 161,168,128,128,128,128,128,128,164,162,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1020 DATA 170,128,128,128,128,128,128,128,128,165,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1030 DATA 170,128,128,128,128,128,128,128,128,165,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1040 DATA 170,128,128,128,128,128,128,128,128,165,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1050 DATA 164,162,128,128,128,128,128,128,161,168,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1060 DATA 128,164,169,163,163,163,163,166,168,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1070 DATA 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1080 DATA 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1090 DATA 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1100 DATA 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1110 DATA 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1120 DATA 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1130 DATA 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1140 DATA 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
1150 DATA 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128

That program, when ran, would draw the VDG semi graphics screen. But I only want the ball at the top left, so I should be able to find the values for that.

Side Note: Hey, Simon! I don’t think the CLEAR 2000 is necessary. That’s only used for strings. And since you aren’t using A$ for anything (you don’t DIM it either, I notice), you could do 100 IF INKEY$=”” THEN 100 instead and eliminate that variable. Also, generating the values as HEX would make it draw the screen faster. (Heh, force-of-habit when I write these articles. Simon is one of the most amazing CoCo programmers out there, and in one of my earlier articles, he contributed enhancements to my attempts at assembly code. This is about as “helpful” as I could ever be for someone as talented as Simon.)

There seems to be 16 DATA statements, each containing 32 values. Thus, the first seven DATAs look to be the first seven lines of the screen, and the first 10 values of each of those should be the 10 values for my ball. This gives me the following values:

1000 DATA 128,161,166,172,172,172,172,169,162,128
1010 DATA 161,168,128,128,128,128,128,128,164,162
1020 DATA 170,128,128,128,128,128,128,128,128,165
1030 DATA 170,128,128,128,128,128,128,128,128,165
1040 DATA 170,128,128,128,128,128,128,128,128,165
1050 DATA 164,162,128,128,128,128,128,128,161,168
1060 DATA 128,164,169,163,163,163,163,166,168,128

Those are the numbers I’d use to PRINT CHR$() that ball. I’ll first try it like this:

30 PRINT@P+0,CHR$(128);CHR$(161);CHR$(166);CHR$(172);CHR$(172);CHR$(172);CHR$(172);CHR$(169);CHR$(162);CHR$(128);
31 PRINT@P+32,CHR$(161);CHR$(168);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(164);CHR$(162);
32 PRINT@P+64,CHR$(170);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(165);
33 PRINT@P+96,CHR$(170);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(165);
34 PRINT@P+128,CHR$(170);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(165);
35 PRINT@P+160,CHR$(164);CHR$(162);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(161);CHR$(168);
36 PRINT@P+192,CHR$(128);CHR$(164);CHR$(169);CHR$(163);CHR$(163);CHR$(163);CHR$(163);CHR$(166);CHR$(168);CHR$(128);

Using P as the starting PRINT@ (0 for the top left of the screen), each line will print the ten CHR$() values of the ball, then the next line will print at “P+32”, making it the next line down, and so on.

20 FORB=0TO1000
30 PRINT@P+0,CHR$(128);CHR$(161);CHR$(166);CHR$(172);CHR$(172);CHR$(172);CHR$(172);CHR$(169);CHR$(162);CHR$(128);
31 PRINT@P+32,CHR$(161);CHR$(168);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(164);CHR$(162);
32 PRINT@P+64,CHR$(170);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(165);
33 PRINT@P+96,CHR$(170);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(165);
34 PRINT@P+128,CHR$(170);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(165);
35 PRINT@P+160,CHR$(164);CHR$(162);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(128);CHR$(161);CHR$(168);
36 PRINT@P+192,CHR$(128);CHR$(164);CHR$(169);CHR$(163);CHR$(163);CHR$(163);CHR$(163);CHR$(166);CHR$(168);CHR$(128);

When this runs, you can SEE it PRINT the ball character-by-character! This is very slow. My benchmark took “forever” to run, reporting 26133 (at 60 ticks per second, that’s over 7 minutes to draw that 1001 times). If you take 26133 / 1001 (I really need to change that loop to be 0 to 999) you get 26.10 “ticks” per time. Divide that by 60 (per tick) you get .43. So it’s taking almost half a second to draw seven lines of ten characters each using CHR$() for each character. (Plus overhead of PRINT@ and such).

We need our ball to bounce faster than that.

We have discussed how switching from decimal to hex will speed things up, so let’s try that:

30 PRINT@P+&H0,CHR$(&H80);CHR$(&HA1);CHR$(&HA6);CHR$(&HAC);CHR$(&HAC);CHR$(&HAC);CHR$(&HAC);CHR$(&HA9);CHR$(&HA2);CHR$(&H80);
31 PRINT@P+&H20,CHR$(&HA1);CHR$(&HA8);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&HA4);CHR$(&HA2);
32 PRINT@P+&H40,CHR$(&HAA);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&HA5);
33 PRINT@P+&H60,CHR$(&HAA);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&HA5);
34 PRINT@P+&H80,CHR$(&HAA);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&HA5);
35 PRINT@P+&HA0,CHR$(&HA4);CHR$(&HA2);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&H80);CHR$(&HA1);CHR$(&HA8);
36 PRINT@P+&HC0,CHR$(&H80);CHR$(&HA4);CHR$(&HA9);CHR$(&HA3);CHR$(&HA3);CHR$(&HA3);CHR$(&HA3);CHR$(&HA6);CHR$(&HA8);CHR$(&H80);

This looks a tiny bit faster. The benchmark reports 14790 (which breaks down to .24 seconds each time). That’s almost twice as fast (well, .24 to .44) but still not fast enough.

The only other thing we could do would be to remove all the in-between semicolons, since they aren’t actually needed to print the characters side-by-side (except for the last one, since we don’t want it to clear the rest of the screen line):

31 PRINT@P+&H20,CHR$(&HA1)CHR$(&HA8)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&HA4)CHR$(&HA2);
32 PRINT@P+&H40,CHR$(&HAA)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&HA5);
33 PRINT@P+&H60,CHR$(&HAA)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&HA5);
34 PRINT@P+&H80,CHR$(&HAA)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&HA5);
35 PRINT@P+&HA0,CHR$(&HA4)CHR$(&HA2)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&H80)CHR$(&HA1)CHR$(&HA8);
36 PRINT@P+&HC0,CHR$(&H80)CHR$(&HA4)CHR$(&HA9)CHR$(&HA3)CHR$(&HA3)CHR$(&HA3)CHR$(&HA3)CHR$(&HA6)CHR$(&HA8)CHR$(&H80);

This removes the extra time it takes BASIC to parse (and skip) NINE semicolons on each line (times ten lines). That adds up, but removing them only increases the benchmark to 14542 — barely measurable.

I don’t see a faster way to do this using PRINT CHR$() over and over and over and over again.

Definition of insanity…

To avoid all the time it takes for BASIC to parse each CHR$() over and over and over and over, we can do that just once and store the result in a string and print that string instead. I’ll use one-letter string names, unique for each line, for speed. It would be “easier” to use an array (like BL$(7) or something) but I’ve previously explored that and found array access to be slower.

Since this is a demo, we’ll do it the silly way, like this:








Now we can just print those strings and, instead of BASIC having to parse and generate seventy CHR$()s each time, it will just have to look up and print seven strings. This should be much faster!

I made some room in my BENCH.BAS program to fit this strings in at the top, and it now looks like this:

2 A$=CHR$(&H80)+CHR$(&HA1)+CHR$(&HA6)+CHR$(&HAC)+CHR$(&HAC)+CHR$(&HAC)+CHR$(&HAC)+CHR$(&HA9)+CHR$(&HA2)+CHR$(&H80)
3 B$=CHR$(&HA1)+CHR$(&HA8)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&HA4)+CHR$(&HA2)
4 C$=CHR$(&HAA)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&HA5)
5 D$=CHR$(&HAA)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&HA5)
6 E$=CHR$(&HAA)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&HA5)
7 F$=CHR$(&HA4)+CHR$(&HA2)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&H80)+CHR$(&HA1)+CHR$(&HA8)
8 G$=CHR$(&H80)+CHR$(&HA4)+CHR$(&HA9)+CHR$(&HA3)+CHR$(&HA3)+CHR$(&HA3)+CHR$(&HA3)+CHR$(&HA6)+CHR$(&HA8)+CHR$(&H80)

20 FORB=0TO1000

30 PRINT@P+&H0,A$;
31 PRINT@P+&H20,B$;
32 PRINT@P+&H40,C$;
33 PRINT@P+&H60,D$;
34 PRINT@P+&H80,E$;
35 PRINT@P+&HA0,F$;
36 PRINT@P+&HC0,G$;


The benchmark now reports 3200! That’s a huge improvement from the original 26133. I think this is about as fast as we can get… at least using strings.

But, for this demo, I wanted to have several frames of animation. If I make a bunch of strings, that’s going to slow things down since there will be more strings to search through. Also, I’ll run out of single-character variables names and might have to do things like A1$, A2$, A3$, etc. for the first frame, and B1$, B2$, B3$, etc. for the second frame, and so on. While this would STILL be faster than doing a bunch of PRINT CHR$(), and I expect still faster than using arrays like F$(0) through F$(6).

If I was less impatient, I’d test that, and even try a double dimension array like F$(frame, line) which would be really easy and look really nice … but would probably be be slower than anything but PRINT CHR$()s…

Note to Self: Write an article about using multi-dimensioned arrays to do simple animation in BASIC.

But I’m impatient, so now let’s circle back to the start of this post where I mentioned the MC-10 being able to embed characters in its PRINT statements directly without needing variables.

We can’t type those graphics characters on the CoCo, but if we don’t mind cheating a bit, we can modify the contents of a program so that the quoted string contains special graphic characters. It makes lines that do that impossible to edit, and print (on most printers), but if it’s just a demo (or some program you write for people to JUST run and not mess with), it works.

Self-modifying BASIC code

Suppose we had a print statement like this:

10 PRINT "**********";

…and we wanted to change those ten asterisks to be a graphics character. If we knew where they were located in BASIC memory, we could POKE the values and change them from a 42 (ASCII for ‘*’) to something else, like a 128 for the solid black block graphics character.

As a kid, I did this in a pretty brute-force way, blindly PEEKing through program memory and changing values to what I wanted them to be. This sometimes had dangerous side effects if the value I was PEEKing for (like 42) appeared as part of a BASIC keyword token or something not inside the quoted string.

So, let’s try to be a bit smarter and scan through the program memory but only look for values between quotes.

If I recall, memory locations 25 and 26 contain the start of the BASIC program. You can get that address like this:

PRINT PEEK(25)*256+PEEK(26)

The end of the program is at 27 and 28:

PRINT PEEK(27)*256+PEEK(28)

It should be super easy (barely an inconvenience) to make a program that PEEKs memory between that range and looks for a 34 (the quote character) and then will start substituting our source character (42, the asterisk) for our target character (128, a black block).

10 PRINT "**********"
20 END
100 ST=PEEK(25)*256+PEEK(26)
110 EN=PEEK(27)*256+PEEK(28)
160 NEXT

If you load this program and RUN it, it will print a line of ten asterisks.

Then if you RUN 100, it will do the search/replace looking for asterisks between quotes and changing them to 128s (black block).

One that is done, RUN again and you see it now prints a row of ten black blocks!

A self-modifying CoCo BASIC program.

From this point on, that line 10 has been forever changed. If you LIST it, you will see weirdness. In this case, line 10 says:


…because apparently that byte of 128 is the token for the keyword FOR.

If you try to EDIT LINE 10, BASIC turns the tokens back into ASCII text for you to edit. Thus, as soon as you edit, you are changing that line to say “FORFORFORFOR…” instead of the graphics characters.

Thus, don’t edit a line after you do this trick!

I think this is a good stopping point for today. My goal here is to switch from my ball print ASCII “X” characters to graphics blocks, and retain the speed of raw PRINTs rather than using a ton of variables that have to be looked up each time — and the more variables, the slower that lookup gets.

But there’s more ASCII fun to be had before I start doing this.

To be continued…

4 thoughts on “CoCo bouncing BASIC ball, part 5

  1. MiaM

    Is it possible to add the “graphics characters” directly to the file that gets loaded? If so you might be able to just type whatever 8-bit characters that corresponds to those chars and have them in place directly in the editor on your modern computer. Maybe there is a font for modern computers that is compatible with the CoCo ascii/screen codes?

    Btw re self modifying code: It would be a bit more cumbersome but also safer to actually partially parse the program in memory. If the 6809 basic is similar to the 6502 basic the content would be like pointer to next line (16 bit), line number (binary integer, 16 bit) and then the line with iirc a null terminator. Skipping the line number and pointer to the next line and parsing the print token would probably be a good idea. Otherwise you would have bugs when you use line a line number where any 8 bit part of the number equals to the ascii code of the quotation mark, and also where any of the 8-bit parts of the pointer to the next line equals to the ascii code of the quotation mark.

    Btw I would really recommend moving the initializations to the end of the program (for performance reasons).

    Side track: Not sure if this applies to the 6809 basic, but it turns out that in the 6502 basic you can use GOTO without a line number and it will jump to line 0, if there is a line 0. It will be cumbersome to require the user to start the program with for example RUN 1000 or so, but by doing this you will gain a minor speedup.

    P.S. if you achieve a decent speed, you might want to check if the 6809 has the WAIT statement and if that can be used to sync up to the display frame rate. On a VIC 20 you can use the WAIT statement, combined with variables instead of constants, to be able to display a few raster bars (by changing the background/border color) rock steady on screen, using just basic.

    1. Allen Huffman Post author

      I do think GOTO by itself does that on the CoCo. I seem to recall discovering that as a kid.

      My scan code will only try to convert items between quotes. Of course, if someone did…

      10 REM Here is one quote ”

      …that would be a problem, but since the code is modifying itself it should be fine. AND, once it’s converted, it can be SAVEd out and when it reloads it will be intact. You could have it self modify, delete the lines that do that, then save out an updated copy. :)

      The init at the end makes sense. I’ll try to remember to include that tip.

      I never knew what WAIT did on my VIC. I do not think we have any way to do that in our BASIC, but there might be something in the ROM code that we could EXEC that would be at a 6809 SYNC instruction with a return after it. Not sure. (I think that’s what SYNC does. It’s been a long time!)

      Great stuff!

      Have you seen my VIC-20 page here

      1. MiaM

        There is still a risk of a “false trigger” though, as a byte in the line number integer or next-line pointer might have the same value as the ascii code of a quotation mark. I haven’t tried your code but assume that it would malfunction if you have the PRINT ” statement on line number 34, or if the next line happens to start at memory location 22xxh or xx22h. At least setting the line number to 34 is easy enough to test when you already have your program.

        But, as it seems possible to SAVE the changed program contents, you might as I said be able to produce that content directly on the cross platform editor you use. If you set the editor to use Windows-1252 rather than UTF-8 (if that is possible) you can enter all but five of the codes 128-255. If you are stuck with (the otherwise superior) UTF-8 this might not work though.

        Haven’t tried it but it seems like there is a coco compatible font for modern computers. Some kind of simple converter could be written to take UTF-8 files using that font and output a binary with CoCo encoding. (Not sure if there is already any such converters, I would guess that there is a reasonable chance of there being one that does the same thing but converting unicode representation of PETSCII graphics to Commodores 8-bit PETSCII file format. That would be super simple to change for usage with the CoCo).

        I never used the WAIT statement or even knew much about it back in the 80’s either. I vaguely recall some magazine or book showing that it could be used to wait for a character to be entered by WAITing for the keyboard buffer counter to change. I don’t think I ever used that, as you could just do a GET and check what you got. As you’d anyway would want to read the keyboard buffer there isn’t much use just waiting for it to change without reading it.

        I think I’ve read most or maybe even all your blog post at some time in the past!

        1. Allen Huffman Post author

          I *think* looking for the quote and end-quote would get past a false trigger, since there should be nothing but ASCII between them. I think my demo program does this, thus it skips line numbers, etc.

          The ability to enter these characters in an editor is a great idea! I don’t know if the fonts have the high-end graphics characters — can a font even have multiple colors?

          I was tinkering with my old VIC-20 stuff (see my post from yesterday) and found:

          WAIT 535,1,1,1

          …or something. No clue what that did, but I must have read it in Compute’s GAZETTE! since that’s where I got all my VIC-20 knowledge.


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.