Category Archives: Color BASIC

Hacking the Color BASIC PRINT command – part 3

See Also: part 1, part 2, part 3, part 4 and more to come…

Just because it works, doesn’t mean it’s correct.

Keep this in mind as I continue my exploration of using Color BASIC RAM hooks to change how the PRINT output works.

Previously, I created a small assembly language routine that would intercept BASIC’s output to the 32 column screen and then treat a lowercase “r” (as in “right”) as a transparent space. My proof-of-concept seemed to work.

Today, I present updated code that now supports “u” for up, “d” for down, “l” for left, and “r” for right, semi-simulating how you can embed cursor movements in a PRINT command on a VIC-20 (and, I assume, the C64 and maybe even the PET before it).

Let me walk you through what I came up with:

* lwasm consmove2.asm -fbasic -oconsmove2.bas --map

* Convert any lowercase characters written to the
* screen (device #0) to uppercase.

UP      equ     'u      character for up
DOWN    equ     'd      character for down
LEFT    equ     'l      character for left
RIGHT   equ     'r      character for right

I start with some definitions of the characters I want to use to move the cursor UP, DOWN, LEFT or RIGHT. I wanted to be able to easily change these characters. In a future installment, I may try to implement this using “DEF USR” so you could do something like X=USR0(“abcd”) and pass in a string containing four characters to use for up, down, left and right. For now, hard-coded.

DEVNUM  equ     $6f     device number being used for I/O
CURPOS  equ     $88     location of cursor position in RAM
RVEC3   equ     $167    console out RAM hook
VIDRAM  equ     $400    VIDEO DISPLAY AREA

These next defines are things that the Color BASIC Unravelled disassembly listings had defined. The first is the memory location that contains the current device number for output (0 for screen, -2 to printer, etc.). After that is where BASIC tracks the cursor position on the 32 column screen. Neat is the address of the RAM Vector for the console out routine. Lastly, VIDRAM is the start of the 32-column screen in memory (1024, or &H400 in hex).

    org $7f00

init
    lda RVEC3       get op code
    sta savedrvec   save it
    ldx RVEC3+1     get address
    stx savedrvec+1 save it

    lda #$7e        op code for JMP
    sta RVEC3       store it in RAM hook
    ldx #newcode    address of new code
    stx RVEC3+1     store it in RAM hook

    rts             done

uninstall
    * TODO

Here, I changed the start address of this program to &H7F00 instead of &H3F00. If trying this on a 16K machine, you would have to change it back. Once I know how big the final assembly code is, I’ll probably move it as close as possible to the end of the 32K RAM used by BASIC so it can leave as much RAM for the BASIC program as possible.

This init routine pulls out the three bytes at RVEC3 (which are either “rts” three times for Color BASIC, or patched to be a “JMP xxxx” 3-byte instruction if other BASIC ROMs (Extended, Disk, CoCo 3) are installed I save those to 3-bytes of reserved memory at the end of the program.

I then replace it with a JMP (&H73) instruction followed by the two byte address of my “newcode” that I want to run any time a character is output.

For now, there is no way to uninstall this routine, but I left myself a reminder I should create an uninstall routine. I think I may just make it so if you EXEC the first time, it installs, and if you EXEC again, it uninstalls, rather than using two different memory locations the user would need to know. We shall see.

newcode
    * Do this only if DEVNUM is 0 (console)
    tst     DEVNUM      is DEVNUM 0?          
    bne     continue    not device #0 (console)

    leas    2,s         remove PC from stack since we won't be returning there.

* Now this is the start of what Color BASIC ROM does for PUTCHR:
* PUT A CHARACTER ON THE SCREEN
LA30A
    PSHS    X,B,A       SAVE REGISTERS
    LDX     CURPOS      POINT X TO CURRENT CHARACTER POSITION

When BASIC needs to output a character, it ends up at the PUTCHR routine in the ROM, starting at address A282. The very first thing it does is “jsr RVEC3” which means it will now jump to this “newcode” routine. The character to output will be in register A.

The first thing I do is check the DEVNUM value to see which device number is being used. I use “tst” to check for zero. If the device is not zero (screen), I branch to a “continue” routine which will be the code that was originally in the RVEC3. (Thus, on Color BASIC it will just branch to an “rts” return, or it will branch to whatever “jmp xxxx” was in the vector before I hijacked it. More on this in a moment.

If I get past that, I will be doing some work and then jumping back into the ROM so the rest of BASICs output routine can run. In that situation, I will not be doing an “rts” from my custom code. I may be wrong on this, but my understanding is that I need to remove the return address off the stack (since I will not be returning), which I do by moving the S stack pointer up by 2. Is this what I need to be doing?

Since BASIC already checks for special characters like backspace and ENTER, I was able to pattern my code after what the ROM does for those and leave out the part where it puts a character on the screen. I take the first two line that BASIC would have done (from LA30A in the Unravelled listing) and put them into my code. This then lets me have my custom blocks checking for special characters the same way BASIC does for the ones it handles.

checkup
    cmpa    #UP
    bne     checkdown
    CMPX    #VIDRAM+32  second line or lower?
    blt     goLA35D     disallow if on top line.
    leax    -32,x       move up one line
    bra     done

The first check is for the UP character. If not seen, we branch to the “checkdown” routine just after this one. If it was UP, then we check to see if X is 32 bytes past the start of screen memory — the start of the second line. If you are on the top line, moving UP is ignored and we branch to a label that will then JMP back into the Color BASIC ROM to finish the normal checks that BASIC does.

Else, decrement X (cursor position) by 32 to move up one line, then branch to the “done” routine which will get us back into BASIC ROM code.

checkdown
    cmpa    #DOWN
    bne     checkleft
    cmpx    #VIDRAM+512-32
    bge     goLA35D     disallow if on bottom line.
    leax    32,X        move down one line
    bra     done

The check for DOWN follows a similar pattern, this time disallowing down if you are on the bottom line of the screen. This is different than how Commodore handles it, since down on the Commodore will cause the screen to scroll up. I plan to fix this later to make it act more like the VIC-20 does.

If we cannot move down, we branch to a label that will then JMP back into the Color BASIC ROM to finish the normal checks that BASIC does. If we can move down, the cursor position in X is increased by 32.

NOTE: During my testing, I found a VIC-20 bug. If you cursor to the bottom right of the screen then press RIGHT, the first time you do this is scrolls up and then the cursor appears one line before the last line. If you then cursor to the bottom right position again and go RIGHT, it scrolls up and now the cursor is on the bottom left position. Odd. I should find a VIC-20 BASIC disassembly and see if I can figure out what causes it do misbehave, but only the first time.

checkleft
    cmpa    #LEFT
    bne     checkright
    cmpx    #VIDRAM     top left of screen?
    beq     goLA35D
    leax    -1,X        move left one character
    bra     done

The process repeats again for LEFT. This is much like what BASIC does with backspace (BS) where it disallows it if you are in the top left position of the screen. If we cannot move left, we branch to a label that will then JMP back into the Color BASIC ROM to finish the normal checks that BASIC does. If we can, the cursor position is decremented by 1.

checkright
    cmpa    #RIGHT
    bne     goLA30E
    cmpx    #VIDRAM+511 bottom right of screen
    beq     goLA35D
    leax    1,x         increment X, skipping that location.
    bra     done

Lather, rinse, repeat. For RIGHT, I disallow moving right from the bottom right character position. This is another difference from VIC-20 which I plan to fix later. If we cannot, we branch to the same label that gets us back into the BASIC ROM routine. If we can move right, the cursor position is incremented by 1.

And now some of the labels…

goLA30E
    jmp     $A30E       jump back into Color BASIC ROM code.

done
    stx     CURPOS      update cursor position
goLA35D
    jmp     $A35D       jump back into Color BASIC ROM code.

A30E in the disassembly is the first instruction right after the two lines I cloned into my routine at my LA30A label. Thus, I start out with those first two lines, then do my code and either jump back in to let the ROM code continue, OR I modify the cursor position then jump to DONE so it can finish up.

“done” will update the saved cursor position that is in the X register, then jump to A35D which is the final line of the output ROM routine where the registers that were pushed/saved at the top of the routine are pulled/restored (including PC which acts as an rts to whoever called the routine).

continue
savedrvec rmb 3         call regular RAM hook
    rts                 just in case...

    end

Lastly, if the original check for console (device 0) was not true, that code jumps to this end part so it can continue on to whatever the vector was pointing to before we hijacked it.

Here is a BASIC loader for this program. I added LINE 5 to reserve memory for the assembly, else BASIC will clobber it with string storage;

5 CLEAR 200,&H7F00
10 READ A,B
20 IF A=-1 THEN 70
30 FOR C = A TO B
40 READ D:POKE C,D
50 NEXT C
60 GOTO 10
70 END
80 DATA 32512,32607,182,1,103,183,127,96,190,1,104,191,127,97,134,126,183,1,103,142,127,24,191,1,104,57,13,111,38,68,50,98,52,22,158,136,129,117,38,10,140,4,32,45,50,48,136,224,32,43,129,100,38,10,140,5,224,44,36,48,136,32,32,29,129,108,38,9
90 DATA 140,4,0,39,22,48,31,32,16,129,114,38,9,140,5,255,39,9,48,1,32,3,126,163,14,159,136,126,163,93,32611,32611,57,-1,-1

And here is the complete assembly listing:

* lwasm consmove2.asm -fbasic -oconsmove2.bas --map

* Convert any lowercase characters written to the
* screen (device #0) to uppercase.

UP      equ     'u      character for up
DOWN    equ     'd      character for down
LEFT    equ     'l      character for left
RIGHT   equ     'r      character for right

DEVNUM  equ     $6f     device number being used for I/O
CURPOS  equ     $88     location of cursor position in RAM
RVEC3   equ     $167    console out RAM hook
VIDRAM  equ     $400    VIDEO DISPLAY AREA

    org $7f00

init
    lda RVEC3       get op code
    sta savedrvec   save it
    ldx RVEC3+1     get address
    stx savedrvec+1 save it

    lda #$7e        op code for JMP
    sta RVEC3       store it in RAM hook
    ldx #newcode    address of new code
    stx RVEC3+1     store it in RAM hook

    rts             done

uninstall
    * TODO

newcode
    * Do this only if DEVNUM is 0 (console)
    tst     DEVNUM      is DEVNUM 0?          
    bne     continue    not device #0 (console)

    leas    2,s         remove PC from stack since we won't be returning there.

* Now this is the start of what Color BASIC ROM does for PUTCHR:
* PUT A CHARACTER ON THE SCREEN
LA30A
    PSHS    X,B,A       SAVE REGISTERS
    LDX     CURPOS      POINT X TO CURRENT CHARACTER POSITION
    
checkup
    cmpa    #UP
    bne     checkdown
    CMPX    #VIDRAM+32  second line or lower?
    blt     goLA35D     disallow if on top line.
    leax    -32,x       move up one line
    bra     done

checkdown
    cmpa    #DOWN
    bne     checkleft
    cmpx    #VIDRAM+512-32
    bge     goLA35D     disallow if on bottom line.
    leax    32,X        move down one line
    bra     done

checkleft
    cmpa    #LEFT
    bne     checkright
    cmpx    #VIDRAM     top left of screen?
    beq     goLA35D
    leax    -1,X        move left one character
    bra     done

checkright
    cmpa    #RIGHT
    bne     goLA30E
    cmpx    #VIDRAM+511 bottom right of screen
    beq     goLA35D
    leax    1,x         increment X, skipping that location.
    bra     done

goLA30E
    jmp     $A30E       jump back into Color BASIC ROM code.

done
    stx     CURPOS      update cursor position
goLA35D
    jmp     $A35D       jump back into Color BASIC ROM code.

continue
savedrvec rmb 3         call regular RAM hook
    rts                 just in case...

    end

And now I can write a program like this:

As I typed that in, after the four Xs I typed a lowercase “d” for down, then four lowercase “l” for left, then X and two “r” then another X, then “dlll” followed by the four Xs again. It looks weird as it moves the cursor around as I type, but I will be fixing that with more additions to this routine in a future installment.

For now, it lets me put this 4×3 thing on the screen without erasing stuff around or behind it:

Progress!

Please, folks, let me know in the comments if you see something I am doing wrong. Am I handling the stack pointer thing properly? I am just experimenting and … well, “it works for me.”

To be continued…

Hacking the Color BASIC PRINT command – part 2

See Also: part 1, part 2, part 3, part 4 and more to come…

Here is what I have learned so far…

When BASIC wants to output a character, it jumps to a ROM routine called CHROUT. This is one of a few documented ROM calls in Color BASIC. Here is how it is documented in the EDTASM+ manual:

I have used this ROM call in previous blog posts, showing how to output “HELLO WORLD” or whatever using assembly:

That small program makes the X register point to the first byte of the MSG data. It then loads that byte into register A and increments X. If A is 0 (the end of string marker), it branches to DONE. If not, it jumps to the subroutine pointed to at $A002 which outputs whatever is in A. It then goes back to do it again.

I wrote a two-part post about Color BASIC RAM hooks awhile ago. There I explored these extra spots where later BASIC ROMs (like Extended, DISK, and the CoCo 3 ROM) can patch in and make the original Color BASIC call new code first. That new code did things like add support for DISK devices or the (gone in CoCo 3) DLOAD command. I assume it is also used to patch in the CoCo 3’s high resolution 40/80 column text screens, as well.

The idea is before Color BASIC does its thing with the CHROUT routine, it will jump to “new code” and let it run first, and that code may then return back to let the normal code process. When disk devices were added as device #1 to device #15, this jump goes to code in Disk Extended BASIC which checks the incoming device number. If it is 1-15, new code is called that takes care of writing data to a disk file. If not, it returns back and Color BASIC handles the devices it knows about (device 0 for console, device -1 is the cassette, and device -2 if the serial/printer port).

For the task Erico was inquiring about, I thought I could patch in a new routine that would check for device 0 (writing to the screen) and then if it was, look for a special character that now means “transparent”. Instead of putting the character on the screen then moving the cursor position over by one, it would just move the cursor position and leave the screen alone.

Here is what I came up with in a quick and dirty hack:

* lwasm consmove.asm -fbasic -oconsmove.bas --map

* Convert any lowercase characters written to the
* screen (device #0) to uppercase.

DEVNUM equ $6f      device number being used for I/O
CURPOS equ $88      location of cursor position in RAM
RVEC3 equ $167      console out RAM hook

    org $3f00

init
    lda RVEC3       get op code
    sta savedrvec   save it
    ldx RVEC3+1     get address
    stx savedrvec+1 save it

    lda #$7e        op code for JMP
    sta RVEC3       store it in RAM hook
    ldx #newcode    address of new code
    stx RVEC3+1     store it in RAM hook

    rts             done

newcode
    * Do this only if DEVNUM is 0 (console)
    tst DEVNUM      is DEVNUM 0?          
    bne continue    not device #0 (console)

    * If here, device #0 (console)
    cmpa #'r        compare A to lowercase 'r'
    bne continue    if not, continue

    leas 2,s        remove PC from stack since we won't be returning there.

    * Now this is the start of what Color BASIC ROM does for PUTCHR:
LA30A
    pshs x,b,a
    ldx CURPOS      X points to current cursor position
    leax 1,x        increment X, skipping that location.
    jmp $a344       jump back into Color BASIC ROM code.

continue
savedrvec rmb 3     call regular RAM hook
    rts             just in case...

    end

The “init” code saves out whatever is in the console out RAM hook (three bytes, either “rts” if not being used, or “jmp abcd” to jump to new code). It then patches in a “jmp” to the new code in this program, then returns back. This installs the new code into the RAM hook.

Now when anything tries to print through CHROUT, BASIC first calls whatever the RAM hook points to. That will be the “newcode” here.

This new code first checks if the device is 0, indicating we are printing to the screen. If it is not, it branches to the “continue” spot where the original RAM hook jump was copied, allowing it to jump there and proceed as normal.

Next it checks to see if the character to print is a lowercase ‘r’ (I chose ‘r’ for “right”). If not, it returns.

Now things get weird. This is not a normal RAM hook because I can’t just “do stuff” then return to the original ROM code. That original code would still want to output whatever is in register A to the screen. To make mine work, I need to take over some of the functions of the ROM and then jump back into the normal ROM code so it can continue after I have done my thing.

In a normal RAM hook, BASIC would use a JSR (jump subroutine) to get there, then have that code return back. But for this hack to work, my new code has to jump directly back into Color BASIC. Because of this, there is a return address (where RTS will return to) on the stack that we won’t be using. Doing “leas 2,s” moves the stack pointer so it skips that. This allows me to jump directly out of this new code back into the ROM.

Now we have to do whatever code the ROM would have done before processing the character. I looked at the disassembly and see it pushes three registers to save them, then at the end it will pull them back off the stack to restore them.

So I do that in my code.

Next, all I need to do is increment the cursor position then jump back into the Color BASIC ROM just past where it would normally put the character on the screen. From there on, everything will be normal.

I may not have explained this very well, but I am sure someone can help me in the comments.

Patching BASIC with BASIC

Thanks to LWTools, here is a simple BASIC loader for this test code:

10 READ A,B
20 IF A=-1 THEN 70
30 FOR C = A TO B
40 READ D:POKE C,D
50 NEXT C
60 GOTO 10
70 END
80 DATA 16128,16170,182,1,103,183,63,43,190,1,104,191,63,44,134,126,183,1,103,142,63,24,191,1,104,57,13,111,38,15,129,114,38,11,50,98,52,22,158,136,48,1,126,163,68,16174,16174,57,-1,-1

If you load this into a CoCo or emulator, then RUN it, the code will be loaded at address &H3F00. Type “EXEC &H3F00” to install the new RAM hook and now any print of lowercase ‘r’ skips to the right without erasing anything.

10 CLS0
20 PRINT@0,"THISrrrrWILLrrrrWORK"
30 GOTO 30

That simple program will clear to a black screen, then you will see “THIS” then four blocks to the right “WILL” then four blocks past that “WORK”. Normally it would erase those blocks with spaces, but the lowercase ‘r’ now means “just skip to the right”.

It’s not perfect, but it does prove the concept.

More to come…

Hacking the Color BASIC PRINT command – part 1

Over in the CoCo Facebook group, Erico Patricio Monteiro asked an interesting question:

“Would it be possible to PRINT a transparent character?”

– Erico Patricio Monteiro

His idea was for putting stuff on the CoCo’s text screen without wiping out the background. He used an example of PRINT”OOOOX” where “O” represented the transparent character. The way I see it, if you had the first line printed like this:

PRINT @0,"ABCDEFG";

…and you had such a transparent character and did this:

PRINT @0,"OOOXOOO";

…your top line would then look like this:

ABCXEFG

This reminded me of how my Commodore VIC-20 had cursor movement characters you could embed in a PRINT statement. Once you typed the quote, you could now embed typeable escape codes to change colors, clear the screen, home the cursor, insert or delete characters, or just move the cursor up, down, left or right. This made VIC-20 program listings require a graphical printer to represent those characters. Here is something from the VIC-20 manual:

This is many pages into the manual, after it had explained how you can embed things like color changes or reverse video. The program listings in the VIC-20 manual had graphical characters in them, and you had to learn what to type to recreate them:

Program listings for the VIC looked weird ;-)

At some point, Commodore BASIC listings were represented with text strings instead of the graphical characters, making a modern listing look like this:

25 print"{home}{down}{right}{black}abc{down}{left*3}def{down}{left*3}ghi{down}{left*3}jkl"

Then you just had to know what key was “black” or “left” (three times, as the “left*3” indicates).

But I digress…

Since there was no PRINT@ or LOCATE on the VIC-20, any time you wanted to print something in a particular spot on the screen you had to print the HOME (move cursor to top left of the screen) character then use a bunch of cursor controls to move to where you wanted to print.

This was … not optimal. And thus, most BASIC VIC-20 programs would print their information (lives left, etc.) on the top of the screen since it was shorter code just to home and print there:

VIC-20 Sky-Ape-Er, screen 3.

My Sky-Ape-Er VIC-20 game had a timer, and I got it in that top corner like this:

105 print"{home}{blue}{reverse on}{right}time:";t:t=t+1

You will notice the above snipped says “reverse on” and has “time” in lowercase, but on my screenshot it is uppercase without being reversed. That is due to the character sets of the VIC-20 where some modes were upper and lower, some were upper with reverse, and other combinations. For the mode I was in, reverse was getting the uppercase characters (and uppercase characters typed with SHIFT would be the graphical characters for those keys).

“But that’s really not important to this story…”

If you look at the Color BASIC Unraveled book you can find the Console Out routine (PUTCHR) on page 84. I did not want to type it all in here, but I did find this GitHub repository by tomctomc that has this already in a text file:

coco_roms/bas.asm at master · tomctomc/coco_roms

From the “bas.asm”, here is the code in question:

; CONSOLE OUT
PUTCHR          JSR         >RVEC3          ; HOOK INTO RAM
                PSHS        B               ; SAVE ACCB
                LDB         DEVNUM          ; GET DEVICE NUMBER
                INCB                        ;  SET FLAGS
                PULS        B               ; RESTORE ACCB
                BMI         LA2BF           ; SEND TO LINE PRINTER
                BNE         LA30A           ; SEND TO SCREEN

                ...snip...

; PUT A CHARACTER ON THE SCREEN
LA30A           PSHS        X,B,A           ; SAVE REGISTERS
                LDX         CURPOS          ; POINT X TO CURRENT CHARACTER POSITION
LA30E           CMPA        #BS             ; IS IT BACKSPACE?
                BNE         LA31D           ; NO
                CMPX        #VIDRAM         ; AT TOP OF SCREEN?
                BEQ         LA35D           ; YES - DO NOT ALLOW BACKSPACE
                LDA         #$60            ; BLANK
                STA         ,-X             ; PUT IN PREVIOUS POSITION
                BRA         LA344           ; SAVE NEW CURPOS
LA31D           CMPA        #CR             ; ENTER KEY?
                BNE         LA32F           ; BRANCH IF NOT
                LDX         CURPOS          ; GET CURRENT CHAR POSITION
LA323           LDA         #$60            ; BLANK
                STA         ,X+             ; PUT IT ON SCREEN
                TFR         X,D
                BITB        #$1F            ; TEST FOR BEGINNING OF NEW LINE
                BNE         LA323           ; PUT OUT BLANKS TILL NEW LINE
                BRA         LA344           ; CHECK FOR SCROLLING
LA32F           CMPA        #SPACE
                BCS         LA35D           ; BRANCH IF CONTROL CHARACTER
                TSTA                        ;  SET FLAGS
                BMI         LA342           ; IT IS GRAPHIC CHARACTER
                CMPA        #$40
                BCS         LA340           ; BRANCH IF NUMBER OR SPECIAL CHARACTER
                CMPA        #$60            ; UPPER/LOWER CASE?
                BCS         LA342           ; BRANCH IF UPPER CASE ALPHA
                ANDA        #$DF            ; CLEAR BIT 5, FORCE ASCII LOWER CASE TO BE UPPER CASE
LA340           EORA        #$40            ; INVERT BIT 6, CHANGE UPPER CASE TO LOWER & VICE VERSA
LA342           STA         ,X+             ; STORE CHARACTER TO SCREEN
LA344           STX         CURPOS          ; SAVE CURRENT CHAR POSITION
                CMPX        #VIDRAM+511     ; END OF SCREEN BUFFER?
                BLS         LA35D           ; RETURN IF NO NEED TO SCROLL

You can see at LA30A the code begins checking for things like backspace and enter. Eventually at LA342 it puts the character on the screen an increments X which is the current screen location. It then has code (not shown) that detects being at the bottom of the screen and scrolling up a line if needed.

To patch this CHROUT routine to support a “transparent” character, I think we’d just have to intercept the code at LA342 and decide if it should put a character on the screen (STA ,X+) or just increment X (LEAX 1,X or something) without putting anything there.

And that would be a real simply patch. A CoCo 1/2 with 64K could run the program that copies the ROM into RAM then switches over, then this could code easily be patched.

And while we were there, maybe it could be extended to support cursor movements as well, replicating how the VIC-20 output works.

But I am getting ahead of myself…

To be continued…

UnderColor’s spiral challenge from 1984 – part 3

ALERT! ALERT! We are doing this wrong. It has been pointed out in a comment to an earlier installment that we missed an important part about what this contest was supposed to produce!

More on that in a moment… But first, let’s look at a faster version of the challenge, created by Dillon Teagan:

10 TIMER=0
20 PMODE4,1:PCLS1:SCREEN1,1
30 L=&HFF:I=-3:DIMR,L,U,D
40 D$="D=D;R=R;U=U;L=L;
50 DRAW"BM0,191C0R=L;U191L=L;
60 FORD=188TO3STEP-6:R=L+I:U=D+I:L=R+I:DRAWD$:NEXT
70 PRINTTIMER/60

This one clocks in at 2.7 seconds, and does some wonderful optimizations!

First, Dillon clearly understands how the BASIC interpreter works. He is doing things like using hex &HFF instead of decimal 255 which makes that bit parse a tad faster. Next, you see him declare a variable, followed by a DIM which pre-declared R, L, U and D. In this example, that DIM probably does not help, but in a real program, you can declare your variables up front and do them in the order of “most accessed” to least. This sets their order in the variable table, so when you try to access one, the one you access the most can be at the top of the list. I’ve posted about this before, but consider this:

10 DIM A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
20 PRINT Z
30 Z=Z+1
40 IF Z<100 THEN 20

If we truly did have 26 variables in use, and declared them like this, Z would be at the end of the variable table. EVERY time Z is needed, BASIC has to scan through all 26 variables trying to match Z so it can be used. This would be MUCH slower than, if you knew Z was being used the most often, you did this:

10 DIM Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y
20 PRINT Z
30 Z=Z+1
40 IF Z<100 THEN 20

With that one minor change (declaring Z first), Z is now the first variable in the table and will be found much quicker. Try it sometime.

But I digress…

The next cool optimization Dillon does is by drawing the initial bottom line (bottom left to bottom right, 256 pixels wide) and right side (bottom right to top right, 192 pixels tall) in line 50, along with the first left (top right to top left, 256 pixels wide) before entering the loop.

The loop itself is using a FOR/NEXT loop which is faster than using GOTO since no line scanning has to be done. BASIC stores where the FOR is, and when NEXT is encountered it pops back to that location rather than scanning forward to find the target line, or starting at the first line and scanning forward from there. Nice.

With the first three “full width/height” lines out of the way, the loop is just doing the “minus 3” size of all four lines. That’s clever. The entire draw string is in a string (D$) and I am unsure if this speeds things up versus having it directly in the line itself (line 60).

Impressive. I wish I’d thought of that!

However… we have been doing it wrong, so far, it seems.

We’ve been doing it wrong so far, it seems.

In a comment left on part 1 of this series, Paul Fiscarelli pointed out something that I completely got wrong:

Hello Allen – I sent you a DM on FB, but I don’t think you’ve seen it yet. What you have posted above is not exactly an accurate reproduction of what is being asked in the challenge question. You are using an offset decrease of 3 in each of your iterations, which produces a gap of only 2-pixels in both height and width. The challenge is indicating a gap of 3-pixels between lines, which requires an offset decrease of 4 in each iteration. This is further evident in the challenge’s diagram of the spiral, which indicates a line-length of 188-pixels for the line on the far left-hand side of the screen. If you perform a screen grab in XRoar (pixel perfect geometry of 640×480 window and 512×384 screen resolution), you will find your code generates a line length of 189 pixels (scale the 512×384 in half).

If you change the offset decrease in your code to 4 instead of 3, you will achieve a render time of roughly 2.43 seconds. This is due to the fact that you are rendering about 23% fewer lines with the DRAW statement.

You can reduce this time even further if you were to use only a single offset variable for drawing both the horizontal and vertical lines, and by adding a separate width to the horizontal lines with a value of 64 = (256w – 192v). This method will shave roughly 0.10 seconds off your render time, down to approximately 2.33 seconds.

10 TIMER=0
20 PMODE4,1:PCLS:SCREEN1,1
30 OF=191:DRAW”BM0,191″
40 DRAW”R=OF;R64″
50 DRAW”U=OF;L=OF;L64;”
60 OF=OF-4
70 DRAW”D=OF;R=OF;R64;”
80 OF=OF-4
90 IF OF>0 THEN 50
100 TM=TIMER
110 IF INKEY$=”” THEN 110
120 PRINT TM/60

As an additional optimization step, you can replace the IF/THEN boundary check with a FOR/NEXT loop, to shave another 0.05 seconds from your render time – getting it down to roughly 2.28 seconds.

10 TIMER=0
20 PMODE4,1:PCLS:SCREEN1,1
30 OF=191:DRAW”BM0,191″
40 DRAW”R=OF;R64″
50 FOR N=0 TO 23
60 DRAW”U=OF;L=OF;L64;”
70 OF=OF-4
80 DRAW”D=OF;R=OF;R64;”
90 OF=OF-4
100 NEXT
110 TM=TIMER
120 IF INKEY$=”” THEN 120
130 PRINT TM/60

There are probably some other optimizations that can be done here – but it’s a start. Oh, I also tested these examples with VCC 2.1.9.2-pre2. I’m sure there will be slight variations in timing with the different emulators, and probably even with different versions of VCC.

Paul Fiscarelli

So, uh … oops. It seems obvious now:

Let’s regroup, and take a look at Paul’s versions in the next installment.

Until then… RTFM!

UnderColor’s spiral challenge from 1984 – part 2

See Also: part 1, part 2, with part 3 and part 4 coming (and maybe more).

These types of posts are probably my favorite. Someone posts something with a coding challenge, and folks start submitting their ideas, and I get to play collector and just repost without doing any work… (Well, except I am submitting ideas as well, this time.)

This all kicked off when Michael Pittsley shared a contest he found in a 1984 issue of UnderColor magazine that challenged BASIC programmers to draw a specific spiral pattern:

Michael tackled it with this code:

10 ' SPIRAL THING
20 '
30 XL=3:YT=0:XR=252:YB=188:PX=3
40 PMODE 4,1
50 PCLS
60 SCREEN 1,1
65 LINE (XL,YB) - (XR-PX,YB),PSET
200 ' RIGHT
210 XR=XR-PX
220 LINE - (XR,YB),PSET
300 ' UP
306 YT=YT+PX
307 IF YT=96 THEN 600
310 LINE - (XR,YT), PSET
400 ' LEFT
410 XL=XL+PX
420 LINE - (XL,YT),PSET
500 ' DOWN
510 YB=YB-PX
520 LINE - (XL,YB),PSET
550 GOTO 200
600 GOTO 600

A nicely formatted and documented (with REMmarks) example of the power BASIC. He was even aware that LINE does not need both a start and end point each time you use it. If you just do “LINE-(x,y),PSET” it will draw from the last point to the new coordinates. This greatly reduces the amount of parsing BASIC has to do versus if you wrote the program always having a pair of start/end points.

Let’s modify it with some timing stuff.

10 ' SPIRAL THING
20 '
25 TIMER=0
30 XL=3:YT=0:XR=252:YB=188:PX=3
40 PMODE 4,1
50 PCLS
60 SCREEN 1,1
65 LINE (XL,YB) - (XR-PX,YB),PSET
200 ' RIGHT
210 XR=XR-PX
220 LINE - (XR,YB),PSET
300 ' UP
306 YT=YT+PX
307 IF YT=96 THEN 600
310 LINE - (XR,YT), PSET
400 ' LEFT
410 XL=XL+PX
420 LINE - (XL,YT),PSET
500 ' DOWN
510 YB=YB-PX
520 LINE - (XL,YB),PSET
550 GOTO 200
600 PRINT TIMER/60

Running it reports 3.16666667 seconds at the end, so really close to the time my version using DRAW got. AND, that is with REMs and spaces and multiple lines to parse. Let’s see what tricks we can do to speed it up by removing spaces, REMs, and packing lines together:

25 TIMER=0:XL=3:YT=0:XR=252:YB=188:PX=3::PMODE4,1:PCLS:SCREEN1,1:LINE(XL,YB)-(XR-PX,YB),PSET
200 XR=XR-PX:LINE-(XR,YB),PSET:YT=YT+PX:IFYT=96THEN600
310 LINE-(XR,YT),PSET:XL=XL+PX:LINE-(XL,YT),PSET:YB=YB-PX:LINE-(XL,YB),PSET:GOTO200
600 PRINT TIMER/60

This drops it down to 3.03333334! Parsing LINE may be faster than parsing a DRAW string. Also, longer line numbers take longer to parse, so we could RENUM0,0,1:

0 TIMER=0:XL=3:YT=0:XR=252:YB=188:PX=3:PMODE4,1:PCLS:SCREEN1,1:LINE(XL,YB)-(XR-PX,YB),PSET
1 XR=XR-PX:LINE-(XR,YB),PSET:YT=YT+PX:IFYT=96THEN3
2 LINE-(XR,YT),PSET:XL=XL+PX:LINE-(XL,YT),PSET:YB=YB-PX:LINE-(XL,YB),PSET:GOTO1
3 PRINTTIMER/60

However, this did not seem to make any consistent measurable difference.

A further optimization could be done by changing the 2-letter variables to 1-letter. But, beyond that, it would take adjusting the logic to find more improvements. Parsing integers is slow, such as “IF YT=96” as is parsing line numbers (thus, lines 1, 2 and 3 should be faster to “GOTO 1” than 100, 200, 300 and “GOTO 100”).

And, one question:: Michael started in from the corner of the screen. Here is a screen shot done in the Xroar emulator with artifact colors turned off so we can see the actual lines better:

This means this version is drawing a few lines less than the version I made. I need to go back and re-read the article and see if I got the details wrong, or if Michael is just keeping the 3-pixel border more consistent. I like the 3-pixel padding, but perhaps the first line to the right on the bottom should have gone further (3 pixel padding) and then at the top left a bit more (3 pixel padding).

Meanwhile, in response to Michael Pittsley‘s post. Andrew Ayers took the version I did and modifies it to work on the CoCo 3. The original contest was a few years before the CoCo 3 even existed, but one would imagine if the article had appeared later it might have had a contest for fastest CoCo 1/2 version, and fastest CoCo 3 version:

A couple more slightly improved CoCo 3 versions of Allen’s code above:

Both of these take longer to run than the original Allen posted, even with the high-speed poke…at least, running on XRoar Online (no idea about real hardware).

– Andres Ayers

CoCo 3 RGB b/w 320×192:

5 POKE65497,0
10 TIMER=0
20 HSCREEN2:PALETTE0,0:PALETTE1,63:HCOLOR1
30 W=320:H=191:HDRAW"BM0,191"
40 HDRAW"R=W;"
50 HDRAW"U=H;L=W;"
60 H=H-3:W=W-3
70 HDRAW"D=H;R=W;"
80 H=H-3:W=W-3
90 IF H>0 THEN 50
100 TM=TIMER
110 IF INKEY$="" THEN 110
120 PRINT TM/60
130 POKE65496,0

CoCo 3 RGB b/w 640×192:

5 POKE65497,0
10 TIMER=0
20 HSCREEN4:PALETTE0,0:PALETTE1,63:HCOLOR1
30 W=640:H=191:HDRAW"BM0,191"
40 HDRAW"R=W;"
50 HDRAW"U=H;L=W;"
60 H=H-3:W=W-3
70 HDRAW"D=H;R=W;"
80 H=H-3:W=W-3
90 IF H>0 THEN 50
100 TM=TIMER
110 IF INKEY$="" THEN 110
120 PRINT TM/60
130 POKE65496,0

It has been so long since I worked in BASIC on the CoCo 3 that I had forgotten about HDRAW and such being there. And, as expected, it takes longer to draw 320 or 640 pixel lines than it would to draw the 256 pixel lines on the CoCo 1/2 PMODE 4 display.

This does make me wonder how it would compare if limited to the same 256×192 resolution of PMODE 4. I expect the overhead of banking in and out the CoCo 3 high resolution graphics screens will add some extra time, and likely working with a screen with more than just 1-bit color (on/off pixels) is more memory to plot through.

Anyone want to work on that experiment?

Make it faster!

Revisiting my version from part 1, I changed the screen to PCLS1 (to make it white) and set COLOR 0 (to make the drawing black) so it would look like the printout in the magazine. This looks nice, but now we cannot tell how close to the original border of the image my results are:

I also see that because of the 256×191, the very last line does not appear to have a 3 pixel padding. Maybe we can look at the math later.

I simply took my version and combined lines and removed any spaces:

0 'SPIRAL2.BAS
5 FORA=1TO1000:NEXT
10 TIMER=0:PMODE4,1:PCLS1:SCREEN1,1:COLOR0:W=255:H=191:DRAW"BM0,191R=W;"
50 DRAW"U=H;L=W;":H=H-3:W=W-3:DRAW"D=H;R=W;":H=H-3:W=W-3:IFH>0THEN50
100 TM=TIMER
110 IF INKEY$="" THEN 110
120 PRINT TM/60

I could also do the “RENUM0,0,1” trick, but all of this only gets me to 3.016666667 seconds.

NOTE: I put a FOR/NEXT at the start so when I type “RUN” I have a moment to release the ENTER key before the timing starts. If you hit a key during the drawing, BASIC tries to handle that key and it will slow down the program. Run it and pound on the keyboard while it is drawing and you can see it slow down quite a bit (I got 3.7 seconds doing that).

But I digress…

Let’s collect some more examples, and see what other methods folks come up with. Now I want to get the same logic, just DRAW versus LINE to draw the lines, and see which one is faster.

To be continued…

UnderColor’s spiral challenge from 1984 – part 1

See Also: part 1, part 2, with part 3 and part 4 coming (and maybe more).

And now back to CoCo …

– Michael Pittsley posted in the TRS-80 Color Computer (CoCo) group on Facebook:

Many of us have our CoCos and have memories or how good we once were writing basic programs on it. Including myself. I found this article in the first UnderColor magazine. It was a contest to see who could write an ECB program that created a spiral. — Write an Extended Basic program that draws a spiral figure on graphics screen 0 on PMODE 4. The figure, when done should look like the picture. Use any combination of Basic commands, but no assembly language. The winner will be the person whose program executes in the shortest possible time. (Entries that simply list a series of LINE commands will be disqualified). I took a stab at it and realized how much I had forgotten about basic, so this was fun for me. I put my results as the first comment. Feel free to try your hand at it, post a screen shot and the time it took to complete.

– Michael Pittsley

This caught my attention.

UnderColor magazine (1984-1985) was one I never saw, though the name sounds familiar so I may have at least read a reference to it, or seen an ad for it somewhere. You can find the issues preserved here:

Search – TRS-80 Color Computer Archive

The article in question appeared in the first issue, which you can read here:

UNDERCOLOR Vol1 No 1 Dec 10, 1984

The article, by Bill Barden, presented a contest to see who could write a program in BASIC (no assembly allowed) that would generate a spiral as demonstrated by this graphic:

The winner would be the program that could do this in the least amount of time.

I have discussed drawing spirals on the CoCo in the past, but not like this. I also wrote about spirals for a text mode attract screen, but not like this.

So now let’s spiral like this.

LINE versus DRAW

The most obvious approach would be to use the LINE command. It takes a set of X and Y coordinates and draws a line between them, like this:

LINE (0,0)-(255,191),PSET

However, with what I know about BASIC these days (and wish I knew back then), that is alot of parsing of numbers and characters and such. That makes it slower than it might need to be.

One shortcut is that LINE remembers where it left off, so you can start a new line just by specifying the destination:

LINE-(127,0),PSET

Doing this trick should speed up a spiral program, since you only need to give the starting point once, then you can just “draw to the next spot” from then on out.

But I did not attempt this. Instead, I thought about DRAW.

The DRAW command is very powerful, and does allow you to draw to specific coordinates. You can do a “blank” draw just to move the starting point, like this:

DRAW"BM0,191"

That will do a Blank Move to (0,191), which is the lower left corner of the screen and the location where the spiral is supposed to start.

You can then do things like…

DRAW"R10"

…and that will draw a line 10 pixels to the right. (Well, the coordinates are scaled, I think, so it is 10 pixels on a PMODE 4 screen, but at other lower resolutions, that number of pixels will be scaled down.)

How can we spiral like that? One way would be to build a string and append it:

X=100
X$=STR$(X)
DRAW"R"+X$

That works, but all that parsing and creating strings and such would certainly be slower than using a built-in feature of DRAW which lets you use a variable inside the quotes! You just put “=” before the variable name, and a “;” after it.

X=100
DRAW"R=X;"

That will draw to the right however many pixels X is set to!

Could this be faster than line?

Here is what I came up with:

0 'SPIRAL1.BAS
10 TIMER=0
20 PMODE4,1:PCLS:SCREEN1,1
30 W=255:H=191:DRAW"BM0,191"
40 DRAW"R=W;"
50 DRAW"U=H;L=W;"
60 H=H-3:W=W-3
70 DRAW"D=H;R=W;"
80 H=H-3:W=W-3
90 IF H>0 THEN 50
100 TM=TIMER
110 IF INKEY$="" THEN 110
120 PRINT TM/60

This sets a TIMER variable at the start, draws the spiral, then reads the value of the TIMER again. When you press any key, the program exits and prints the time (TIMER/60) it took to run the main code.

Here is what I get:

And pressing a key shows me:

3.03333334

Three seconds.

I expect I can optimize my program to speed it up. In the meantime, what can you come up with? Is there a faster way?

Let’s play!

Ciaran “Xroar” Anscomb’s PCLEAR 0 without assembly!

On the CoCo mailing list, Ciaran (author of the Xroar emulator), said this:

FWIW this is the bodge I have saved out for doing PCLEAR0 without such
ROM patching:

POKE183,PEEK(183)-6:POKE188,PEEK(188)-6:PCLEAR1:POKE183,PEEK(183)+6:POKE188,PEEK(188)+6

Annoyingly verbose, but should account for DOS, and works on the
Dragon too.

..ciaran

https://pairlist5.pair.net/mailman/listinfo/coco

This topic came up because of Juan Castro‘s experiments with updating HDB-DOS to add new functionality on a CoCo 1 and 2 (but that is a discussion for a dedicated blog post sometime). Juan had recently “fixed” Extended Color BASIC to allow using “PCLEAR 0” to remove all graphics memory and give more RAM to BASIC. I have discussed PCLEAR 0 in the past

This mysterious line performs a PCLEAR 0 without needing to load and run program of assembly code!

POKE183,PEEK(183)-6:POKE188,PEEK(188)-6:PCLEAR1:POKE183,PEEK(183)+6:POKE188,PEEK(188)+6

And it works!

But … how does it work!?!

Ciaran, you’ve got some ‘splainin’ to do…

Until then…

A BASIC coin flip…

Us humans (this is not an A.I. post, bleep bloop) have a tendency to try to find patterns in randomness. For example, when asked to pick a number between 1 and 10, a magician/mentalist will know that statistically humans are more likely to choose certain numbers. There is alot of “human nature” that makes us somewhat predictable.

In a deck of 52 playing cards, if you were asked to predict what card is on the top of a shuffled deck, you probably wouldn’t say Ace of Diamonds, but that card is just as likely to be there as any other. No matter which card you guess, you have a 1 in 52 chance of being correct.

Call it in the air…

When it comes to a coin toss, do you always call heads? Always tails? Or do you alternate?

When a gambling casino game presents a grid of squares and asks you to pick four squares, do you “randomly” pick various squares, or do you just click the first four on the top row?

If it is random, either should have the same outcome.

And don’t get me started on picking lottery numbers. While we do not often see the picked numbers be “1, 2, 3, 4, 5 and 6”, that sequence should be just as likely as any other.

If it is random.

So let’s play a game in BASIC with a coin toss. Heads or tails will be represented using CoCo’s Color Basic RND() command. Doing RND(2) will produce either a 1 or 2 result.

NOTE: This is not random. This is psuedo random. I have discussed this previously, but for the sake of this blog post we will pretend it truly is random.

Would calling heads every time produce a better result than calling tails? Or would randomly choosing heads or tails each flip be better?

Let’s try…

0 'COINFLIP.BAS
5 'POKE 65495,0
10 W1=0:W2=0
20 FOR A=1 TO 1000
30 V=RND(2)
40 IF V=1 THEN W1=W1+1
50 IF V=RND(2) THEN W2=W2+1
60 NEXT
70 PRINT "ALWAYS GUESSING 1:";W1
80 PRINT "GUESSING RAND 1-2:";W2

This program will “randomly” flip a coin 1000 times and count how many times it landed on heads (1) versus how many times it matched a randomly (1-2) chosen value. At the end, it will print the results:

As you can see, in this “random” test, neither method really proved to be that different. We could also alter the output to print how many times guessing tails (2) would have worked (1000 clips minus how many times it was heads, 511 in this example, so 489 if my math is correct).

But it still feels better thinking we have some “control” over things and guessing rather than always choosing the same guess.

Alphabetically speaking…

Let’s modify the program to select a random letter, A-Z (represented by 1-26). We will now always guess A, versus randomly guess a letter (1-26):

0 'COINFLP2.BAS
5 'POKE 65495,0
10 W1=0:W2=0
20 FORA=1TO1000
30 V=RND(26)
40 IF V=1 THEN W1=W1+1
50 IF V=RND(26) THEN W2=W2+1
60 NEXT
70 PRINT"ALWAYS GUESSING 1:";W1
80 PRINT"GUESSING RND 1-26:";W2

And here is what I get…

Maybe this perspective will help you “always choose tails” or “always guess Aces of Spades” in the future.

And speaking of the future, there is another “random” test I want to experiment with, coming soon.

Until then…

Using BASIC to prove a (dumb) point.

I recently got lured in to downloading some casual game for my phone. (Thank you, gas station rewards program, for telling me I could earn a bonus from you if I downloaded this stupid game.)

I gave up these time wasters years ago when I realized how much time they wasted.

But with this addictive substance back on my phone, I was thrown back in and realized… nothing has changed. It’s even worse. These games are not games. They are ad platforms. Every few minutes you get an ad. Or, you have to watch an ad to get something you need.

I will repeat… These games are not games. They are ad platforms.

But, once new trend is how many ads for other games I see that offer “real cash” for playing them. They show folks who are broke pulling out their phone and then playing to get the money they need. “It’s just that easy!”

Obviously, if you could easily make hundreds of dollars playing a game, you wouldn’t need to pay to advertise that game. People would all know about it from word-of-mouth and we’d all be doing that.

What is even more amusing (at least to me) is how many ads warn you about “scam games” … while basically being the same game they are warning you to avoid.

But one thing caught my attention… These ads will claim to be “skill based” games. Many of them are card games like Solitaire.

While it is true there is skill to know how to play a certain set of random cards you have been dealt, there is zero skill that can prevent you from losing if you get enough bad hands. Likewise, any “skill” game that uses a roll of the dice you can 100% be guaranteed to lose if you had enough random bad rolls of the dice and your opponent had enough random good rolls.

And that gave me a (dumb) idea…

The house always wins.

As a kid, I remember playing Battleship with friends. In case you are unfamiliar, here is the wiki page for this game:

Battleship (game) – Wikipedia

Basically, you place your ships on a grid, aligned vertically or horizontally, and your opponent does the same. You then call out the coordinate you want to “bomb” on your opponent’s grid, and they tell you if you had a “hit” or a “miss.”

Some of us cheated.

Since there was no way to verify where the ships were, if your opponent called a shot that was a “hit,” you could easily move your piece out of the way to a new spot and report “miss.” Evil. But fun. This caused LONG games, playing until you basically got down to where the ships had no other place to be.

Because of this, I never trusted the Battleship clone I played on my Radio Shack Color Computer. How could I ever trust that computer wouldn’t “cheat” the same way?

But hey, Battleship is a game of skill — after all, it does not use any random roll of the dice or deal of a card.

But the card and dice games are completely “random” and no matter how skilled you are, you can have a hard time winning against bad randomness ;-)

I thought it would be fun to write a simple BASIC Blackjack (or 21) card game, except the computer would cheat. It would have a list of all un-dealt cards, and ensure it always gives the best card to the dealer, and the worst to the opponent. If things were truly random, this is a possibility with a truly random outcome.

The same cheating computer could be done for any random game — just as Monopoly. Imagine ALWAYS getting a roll that makes you pay rent or Go To Jail, while the computer always got a roll that got them to a safe property, or one they could buy.

Shall we play a game?

I will not present code for this yet. I have not written it. But, perhaps one of you will beat me to it.

My idea:

  1. The cards are in a random array of 52.
  2. The computer dealer will always get the best cards. Initially a face card and an ace, then as those cards are depleted, two cards totaling ten. At that point, there is no way the player can ever get two cards at 21. And, if the player got 20, the “house always wins” so even if that happened, the computer wins.
  3. After the player receives its cards, any request to “hit” would be a card just enough to make them bust.
  4. This process would continue through the rest of the deck.

I am unsure if, at some point, it would ever turn into a “fair” game. And this is why I want to write this dumb idea.

Thoughts?

Color BASIC supports two letter variables, except when it doesn’t.

Over on the CoCo Facebook group, in a discussion about “why is I always used for loops”, Rob R. left a comment that caught my interest:

“… I have a vague memory that (at least on the Mod I) there were one or two letters that weren’t usable since they could be tokenized to a command. At least some two letter variables would be verboten, like ‘TO.'”

– Rob R. on Facebook

This made me wonder: how many are there? Here are the ones that I think would be problematic:

  • AS – in Disk BASIC, there is an “AS” keyword used for the file system. “FIELD #1, 10 AS A$”
  • FN – as in “DEF FNA(B)=B*42”
  • IF – as in “IF A=1”
  • ON – as in “ON X GOTO/GOSUB” or on the CoCo 3, “ON BRK GOTO” or “ON ERR GOTO”
  • OR – as in “IF A=1 OR A=2”
  • TO – as in “FOR I=1 TO 10”

Using any of these such as “TO=1” or “FN=3” will create a ?SN ERROR.

Are there others?

Also, some of these will work in Color BASIC that will not work if you have Extended or Disk BASIC:

  • “DEF FN” was added in Extended, so on a Color BASIC machine you should be able to use FN as a variable.
  • “AS” was added in Disk BASIC, so you should be able to use AS on Color and Extended BASIC.

I wonder how many folks wrote BASIC programs using variables that were not allowed when they later added the Extended BASIC ROM and/or Disk BASIC, and wondered why they stopped working?

Until next time…