CoCo bouncing BASIC ball, part 3

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

Math versus DATA: FIGHT!

In the previous post, I showed the simple way I would bounce a ball around the screen by using X and Y coordinates and converting them to PRINT@ screen position, and then using an X Movement and Y Movement variable to control where the ball went next.

But, since this is a demo, we don’t actually need to calculate anything realtime. We could have all the positions stored in DATA statements, and just READ them as the program ran. This would also allow fancier movement patterns, such as bouncing with gravity.

Yes, it’s cheating. But is it faster? Let’s find out. Here is some code that repeatedly reads a location from DATA statements then displays an “*” at that position.

6 P=0
30 READP:IFP=&HFFF THENRESTORE:GOTO30
31 PRINT@P,"*";
1000 DATA&H1,&H2,&H3,&H4,&H5,&H6,&H7,&H8,&HFFFF

The above code is inserted in to my BENCH.BAS program.

In line 30, we read a value from the DATA statements. If that value is &HFFFF (65535), RESTORE is used to rewind the READ so the next time it happens it looks for the first DATA statement. The GOTO causes it to try the READ again (thus, restarting with the first bit of data when it runs out of DATA).

Line 31 just prints our ball at whatever position was in the DATA statement.

Pretty simple.

Running this shows that reading 8 data values then rewinding over and over again (1000 times total) takes about 768. That’s a huge improvement of calculating the X and Y each time (1842). Thus, we should be able to pre-calculate the ball positions and go from there.

Writing code that generates code

We can write some code that writes an ASCII (text) file to disk (or tape) that contains numbers lines of BASIC which could be loaded (or MERGED from disk) later. Let’s start by just PRINTing out the lines we’d want to generate:

5 X=0:Y=0:XM=1:YM=1
10 LN=1000
20 LN$=STR$(LN)+" DATA"
30 P=X+Y*32
40 IF LEN(LN$)<240 THEN LN$=LN$+"&H"+HEX$(P)
50 IF LEN(LN$)<239 THEN LN$=LN$+"," ELSE PRINTLN$:LN=LN+10:GOTO 20
60 X=X+XM:IFX<1ORX>30THENXM=-XM
70 Y=Y+YM:IFY<1ORY>14THENYM=-YM
80 GOTO30

When you run that, it starts printing out lines of DATA statements containing hex values:

1000 DATA&H0,&H21,&H42,&H63,&H84,&HA5,&HC6,
   &HE7,&H108,&H129,&H14A,&H16B,&H18C,&H1AD,
   &H1CE,&H1EF,&H1D0,&H1B1,&H192,&H173,&H154,
   &H135,&H116,&HF7,&HD8,&HB9,&H9A,&H7B,&H5C,
   &H3D,&H1E,&H3F,&H5E,&H7D,&H9C,&HBB,&HDA,
   &HF9,&H118,&H137,&H156,&H175,&H194

1010 DATA&H194,&H1B3,&H1D2,&H1F1,&H1D0,&H1AF,
   &H18E,&H16D,&H14C,&H12B,&H10A,&HE9,&HC8,
   &HA7,&H86,&H65,&H44,&H23,&H2,&H21,&H40,
   &H61,&H82,&HA3,&HC4,&HE5,&H106,&H127,
   &H148,&H169,&H18A,&H1AB,&H1CC,&H1ED,
   &H1CE,&H1AF,&H190,&H171,&H152,&H133,&H114

All we’d have to do is figure out how many positions we want, and then print these lines to an ASCII file on disk or tape instead of to the screen. For instance, if we start at position 0, maybe we generate values until we bounce back to position 0. (To make things easier, I’m going to start at 1,1 and end when it gets back to 0).

0 CLEAR1000
5 X=1:Y=1:XM=1:YM=1
10 LN=1000
15 OPEN "O",#1,"DATA.ASC"
20 LN$=STR$(LN)+" DATA"
30 P=X+Y*32
31 PRINTP;
35 IF P=0 THEN CLOSE#1:END
40 IF LEN(LN$)<240 THEN LN$=LN$+"&H"+HEX$(P)
50 IF LEN(LN$)<239 THEN LN$=LN$+"," ELSE PRINT#1,LN$:LN=LN+10:GOTO 20 60 X=X+XM:IFX<1ORX>30THENXM=-XM
70 Y=Y+YM:IFY<1ORY>14THENYM=-YM
80 GOTO30

This program will produce a text file called DATA.ASC containing all the positions the ball will be in until it loops back to the top left corner of the screen. This can then be loaded (LOAD”DATA.ASC”) into BASIC. (Disk BASIC allows MERGE”DATA.ASC” to merge those lines in with whatever BASIC program is already there, just as if they were typed in by hand.)

With this pre-calculated data, all we have to do is just read a position, then display the ball there.

10 CLS
20 READP:IFP=&HFFFF THENRESTORE:GOTO20
30 PRINT@P,"*";:GOTO20
5000 DATA&HFFFF

Note I needed to add the final &HFFFF, but I should have made the DATA generator program add that before closing the file.

Those lines and all the generated DATA statements make a blazing fast bouncing ball with no math involved – just the time it takes to READ a value from DATA statements.

With this proof-of-concept, the next step will be seeing if this can speed up printing a large block of text for a huge ball.

To be continued…

CoCo bouncing BASIC ball, part 2

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

Math is hard, but some is easier.

Since it seems we might be needing math to move the ball around, let’s revisit some benchmarks on math to see which is faster. Using my BENCH.BAS program:

0 REM BENCH.BAS
5 DIM TE,TM,B,A,TT
10 FORA=0TO3:TIMER=0:TM=TIMER
20 FORB=0TO1000
70 NEXT
80 TE=TIMER-TM:PRINTA,TE
90 TT=TT+TE:NEXT:PRINTTT/A:END

…let’s declare a temporary variable, and then see how fast it is to add different values.

6 Z=0
30 Z=Z+1

Adding decimal 1 gives us about 280.

Changing that to hex 1 (Z=Z+&H1) is basically the same.

BUT, adding 1 would just be moving on byte to the right. If we were moving down and to the right, that would be adding 33.

Z=Z+33 produces 355. It’s having to do much more work to convert two decimal digits.

Changing that to Z=Z+&H21 results in 278. It seems adding two hex digits is faster than adding one decimal digit :-)

Obviously, any math we want to do should be done using hex. But what math do we need?

Let’s start with a simple example that tries to “bounce” a single character around the screen.

Bounce this

As a kid, I would do this with an X and Y, which I would then convert to a screen position like this:

PRINT@X+Y*32,"*";

I would then use variables for “X Movement” (XM) and “Y Movement” (YM) and add them to X and Y each time:

X=X+XM:IF X<1 OR X>30 THEN XM=-XM
Y=Y+YM:IF Y<1 OR Y>14 THEN YM=-YM

There are problems with this approach (like, when it hits the bottom right of the screen, it scrolls up, and I’m also not erasing the “*”), but it’s good enough for a benchmark test:

6 X=0:Y=0:XM=1:YM=1
30 PRINT@X+Y*32,"*";
31 X=X+XM:IFX<1ORX>30THENXM=-XM
32 Y=Y+YM:IFY<1ORY>14THENYM=-YM

This produces 2047. If we change all the values to hex:

6 X=0:Y=0:XM=1:YM=1
30 PRINT@X+Y*&H20,"*";
31 X=X+XM:IFX<&H1ORX>&H1E THENXM=-XM
32 Y=Y+YM:IFY<&H1ORY>&HE THENYM=-YM

Note I had to add spaces after the &H1E and &HE since BASIC can’t tell that’s the end of a value before parsing the next keyword (“THEN”).

This one change improves the speed to 1842. A better way would be to eliminate the X and Y conversion completely, and just track one position (say, the top left corner). But without an X and Y, how do you know when you’ve hit the edge?

Since this is a demo, perhaps we don’t have to.

To be continued…

CoCo Cross Developing with MS Visual Studio Code

I just wanted to post a note here about Microsoft’s Visual Studio Code cross-platform editor. It is available for Windows, Mac and Linux, though I have so-far only used it on Mac and Windows:

https://code.visualstudio.com

It supports extensions and there are several CoCo-related ones available:

  • CoCoTools by Jason Pittman. This provides some level on integration with the Windows-based VCC CoCo emulator, as well as lwasm assembler, Toolshed CoCo disk tools, and cmoc C compiler. I just found this today and have not used it. It says it can do things like RENUM BASIC files, which could be useful.
  • Color BASIC by Tandy. By Tandy, you say? Yes, Tandy UK! This color-codes BASIC program listings. This is what I have been using for my Mac-based BASIC editing.
  • 6809 and 6309 Assembly by Tandy. This one color-codes assembly source.
  • 6×09 Assembly by Blair Leduc. This one also color-codes assembly source.

Visual Studio Code offers some IDE features, allowing extensions to launch compilers/assemblers and even run them. It looks like CoCoTools does this, so I look forward to trying it out soon.

Until next time…

CoCo bouncing BASIC ball, part 1

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

The prolific Jim Gerrie recently posted a video of an MC-10 bouncing ball demo he wrote in BASIC:

Jim Gerrie’s BASIC bouncing ball for the MC-10.

Thanks to Jim, the MC-10 joins a long list of 80’s home computers that thought bouncing a ball around the screen was a good demo.

Seeing his demo inspired me to revisit my Benchmarking BASIC series and see if we can expand on this.

I begin with the excellent (and free) Xroar Emulator. For those that want to play along, there is now a web browser version you can try without installing anything, or you can try the original JS Mocha emulator. Both should be more than enough for this experiment.

First, I load up my BENCH.BAS framework so I can do some speed tests. It looks like this:

0 REM BENCH.BAS
5 DIM TE,TM,B,A,TT
10 FORA=0TO3:TIMER=0:TM=TIMER
20 FORB=0TO1000
70 NEXT
80 TE=TIMER-TM:PRINTA,TE
90 TT=TT+TE:NEXT:PRINTTT/A:END

The above sample code will run four tests (0 to 3) and each time it will do “something” 1001 times (0 to 1000) and report the results in CoCo TIMER values (where each number represents 1/60th of a second, give or take). The benchmark code would go between lines 20 and 70.

Let’s see how big of an object we want to display. Using Jim’s video as a reference (where he shows some of the BASIC source code), it looks like 8 characters wide by 9 characters tall:

Based on him using substrings going up to 6, it looks like he may have 7 frames of animation (0-6). Impressive. But let’s just start with displaying 8×9 characters in various ways to see how fast we can do it.

The fastest way in BASIC is to use a PRINT@ statement, so my first test is to see how long it takes to print these characters 1001 times. I will hard-code the location for each line starting with 0 (the top left of the screen). It looks like this:

30 PRINT@0,"12345678";:
   PRINT@32,"12345678";:
   PRINT@64,"12345678";:
   PRINT@96,"12345678";:
   PRINT@128,"12345678";:
   PRINT@160,"12345678";:
   PRINT@192,"12345678";:
   PRINT@224,"12345678";:
   PRINT@256,"12345678";

Running that in the benchmark program results in 3986.

Using decimal values is slow, so next I changed them to hex:

30 PRINT@&H0,"12345678";:
   PRINT@&H20,"12345678";:
   PRINT@&H40,"12345678";:
   PRINT@&H60,"12345678";:
   PRINT@&H80,"12345678";:
   PRINT@&HA0,"12345678";:
   PRINT@&HC0,"12345678";:
   PRINT@&HE0,"12345678";:
   PRINT@&H100,"12345678";

Parsing a hex value is much faster, so this results in 3018. That’s about 25% faster.

And, using variables is even faster, since no parsing is required. A quick test that sets variables I-Q to each value, then does a PRINT@I through PRINT@Q produces 2940. Not a huge gain, but every little bit helps. That’s probably the fastest one can print something like this in BASIC.

The problem with using multiple variables is you have to update each one every time the object moves. If you just use one variable, and do math for all the other lines, you are doing the same math for each line that would have been done for the variable.

At this point, we need to see which way of doing math is faster. Or, perhaps, maybe we can do it without using math. . .

To be continued…

Marc Andreessen (Netscape) was a CoCo user!

Over in the Facebook Color Computer group, Jerry Stratton discovered that Marc Andreessen, co-founder of Netscape, was a CoCo user! Jerry ran across an April 1987 issue where Marc wrote in looking for CoCo pen-pals!

April 1987 Rainbow Magazine.

Here’s that issue, scanned and searchable, if you want to see who else might have been writing in:

http://www.colorcomputerarchive.com/coco/Documents/Magazines/Rainbow%2C%20The%20%28Searchable%20image%29/The%20Rainbow%20Vol.%2006%20No.%2009%20-%20April%201987.pdf

C compiler bugs that make you go hmmm…

There is a PIC compiler from CCS that I use at work. Every now and then we run across a bug (most of which get quickly fixed by CCS). The latest is a rather bizarre issue where strings are getting mixed up.

Attempting to do something like this:

printf("Value %d", value);

…created output like:

XXXXXX42

…because somewhere else in the code was this:

printf("XXXXXXXXXXXXX");

The compiler was using the correct format string (to know where to put the %d variable on output) but was displaying the string from a different bit of code.

And that other bit of code was unused (not being called at all).

This may be a compiler optimizer bug, but I found it amusing. I haven’t seen a mixed up printf() issue before.

Until next time…

Converting two 8-bit values to one 16-bit value in C

This is a follow-up to an earlier article I wrote about converting 8-bit values to 16-bit values.

There are several common ways to convert two byte *8-bit) values into one word (16-bit) value in C. Here are the ones I see often:

Math

This is how we learned to do it in BASIC. “C = A * 256 + B”:

uint8_t byte1;
uint8_t byte2;
uint16_t word;

byte1 = 0x12;
byte2 = 0x32;

word = byte1 * 256 + byte2;

Bit Shifting

This way generally makes less code, making use of the processor’s ability to bit shift and perform an OR.

word = (byte1 << 8) | byte2;

Unions

union {
   // First union element contains two bytes.
   struct {
      uint8_t byte1;
      uint8_t byte2;
   } Bytes;
   // Second union element is a 16-bit value.
   uint16_t word;
} MyUnion;

MyUnion.Bytes.byte1 = byte1;
MyUnion.Bytes.byte2 = byte2;

That one looks like much more source code but it may generate the smallest amount of executable instructions.

Array Access

And here was one I found at a previous job, which I hadn’t seen before, and haven’t seen since:

uint8_t  bytes[2];
uint16_t value;

value = 0x1234;

bytes[0] = *((uint8_t*)&(value)+1); //high byte (0x12)
bytes[1] = *((uint8_t*)&(value)+0); //low byte  (0x34)

That example is backwards from the topic of this post, but hopefully you can see the approach.

The question today is … which would you choose?

Clean Code would say writing it out in the simplest form is the best, since it would take less time for someone to understand what it was doing. But if you needed every last byte of code space, or every last clock cycle, you might want to do something else.

Which do you think is smallest?

Which do you think is fastest?

Which do you think is easiest to understand?

Comments appreciated.

Until next time…

A C tale of two ampersands

Every now and then, I run across a bug in a C program that makes me say “oh, one of those again?” For instance, a very common one is when you want to compare two values using equal (“==”) but you leave one off and do an assignment by mistake (“=”):

if (a = 10)
{
   DoSomething();
}

When you do this, the result is the value, thus “a = 10” resolves to 10, so it’s like saying “if (10) …”. It would work for any non-zero value, since “if (0)” would not run. A fun bug to find!

Most modern C compilers will emit a warning about that, because they know it’s probably not what the programmer intended.

But a lot of crappy small embedded compilers don’t. And since I work with a lot of small embedded compilers, I stumble across bugs like this from time to time.

I found a new one to add to my list, this time using a logical “and” comparison (“&&”) versus an accidental bitwise “and’ (“&”). Consider this:

if ( (a==100) & (b==42) )
{
   DoSomething();
}

The intent of that code was to only DoSomething() if a was 100 AND b was 42. But, there was only one ampersand, so it was actually taking the result of “a==100” (either true or false) and mathematically ANDing it to the result of “b==42” (either true or false).

If a was 100 and b was 42, it was doing this:

if ( (true) and (true) )
{
   DoSomething();
}

And that worked, since “true” resolves to a 1, and “1 & 1” is 1. (My grade school math teacher never taught it that way…)

But, clearly this was a bug and it should have been the logical AND (“&&”).

Which made me look at the generated code and see what the difference is. And the difference is that using the bitwise AND generates far more code because it has to save the results of two comparisons then AND them together and check that result. It was basically doing this:

result1 = (a == 100); // true or false
result2 = (b == 42); // true or false
if (result1 & result2)
{
   DoSomething();
}

So sure, it works, but it generated much larger code and did much more work and thus was both larger and slower than doing the desired logical AND (“&&”).

And that’s all I have to say about that, today.

Until next time…

BASIC REM memory savings

Over in the CoCo Facebook group, Diego Barzio just posted a note about discovering some BASIC program line comments that had left out the REM keyword at the start. Because those lines were never the target of a GOTO, there was no error. This had the side effect of saving a byte (or two, since most do “REM ” at the start) for comment lines.

This made me think about what was going on. BASIC will allow you to type in anything, and will try to parse it (to tokenize the line) and produce an error (?SN ERROR, etc.) if there is a problem. But, when you are typing in a line, this BASIC doesn’t check anything until that line is actually ran in the program. (Other versions of BASIC will check when you hit enter. Didn’t the Apple 2 do that?)

REM

In an earlier article, I mentioned that “REM” tokenized into one byte, and the apostrophe (‘) turned into two bytes because it was “:REM(space)” allowing you do do something like this:

10 REM This is a comment.
20 'This is a comment

Since most folks type “REM(space)”, using the apostrophe without a space after it takes the same room. But if you include the space:

10 REM This is a comment
20 ' This is a comment

…that would make line 10 take one byte less (REM + space is two bytes, versus ‘ + space which is three bytes).

Now, if you do not include REM or apostrophe, you can save a byte or two for each comment. If you program has 50 lines of comments, that’s 50-100 bytes.

BASIC Keywords

However, this made me realize that leaving out the REM would cause it to try to tokenize the line, and turn any BASIC keyword into a token, saving even more memory. If your comment included words like PRINT, OR, ELSE, etc., you’d save even more room!

Leaving our REM can save memory? Thanks, Diego Barizo!

As you can see, because this comment uses the word PRINT (five characters), the version without the REM appears to save six bytes — it saves the apostrophe (two bytes, or would save “REM(space)” for two bytes) plus tokenizes the PRINT keyword down from five bytes to one (saving four more bytes).

Interesting BASIC interpreter abuse, isn’t it? As long as you never run this line, you might save memory by leaving our REM (depending on if you use any keywords). I could imaging comments saying “SHOW THE USER NAME” changed to “PRINT THE USR NAME” to tokenize two words (PRINT and USR).

You would still need REM at the start of the code for any initial comments, and during the code, but for subroutines you could do this:

10 REM THIS IS MY PROGRAM
20 A$="HELLO, WORLD!":GOSUB 1010
999 END
1000 PRINT THE MESSAGE
1010 PRINT A$:RETURN

The GOSUB jumps to 1010 and can find it, and since the program would END before reaching 1000, that would work.

With great power comes great responsibility. Use this wisely :) and thanks, Diego, for noticing this.

Until next time…