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?
AI on the CoCo? This is a simple language experiment that I think can be done on the coco if anyone would like to try the code. I asked Grok to write a basic program to read a 10MB corpus of sentences from a dictionary and then build a simple Markov graph db to predict the next word in a sequence.
– Youngstown Ken, via Facebook CoCo group
The attached link went to a Grok-generated conversation about the subject. You can read the short interaction here, and see the generated Python and BASIC-ish code:
So naturally, someone needs to try this and see if it would even work. AI is terrible at BASIC, though I did have some success talking it through some simple 32-column text screen game code when ChatGPT first made a big public splash a few years ago.
Let’s look at the second code variation it produced:
10 REM Two-Level Markov Chain Predictor for TRS-80 CoCo
20 REM Vocabulary: 1000 words, Trigram model fits in 512KB
30 DIM V$(999): REM Vocabulary array (1000 words)
40 DIM F(999): REM Frequency array for vocab building
50 DIM M(499,3): REM Model: 500 trigrams max (w1,w2,w3,prob)
60 N=0: REM Number of trigrams loaded
70 REM Pass 1: Build vocabulary from corpus.txt
80 OPEN "I",#1,"CORPUS.TXT"
90 FOR I=0 TO 999: F(I)=0: NEXT I: REM Initialize frequency
100 IF EOF(1) THEN 140
110 LINE INPUT #1,L$: REM Read line
120 GOSUB 500: REM Process line for word frequencies
130 GOTO 100
140 CLOSE #1
150 REM Sort top 1000 words by frequency (simplified)
160 FOR I=0 TO 999: V$(I)="<UNK>": NEXT I: REM Default to <UNK>
170 W$="":C=0: REM Temp word and count
180 OPEN "I",#1,"CORPUS.TXT" : REM Reopen for word assignment
190 IF EOF(1) THEN 230
200 LINE INPUT #1,L$
210 GOSUB 600: REM Assign top 1000 words
220 GOTO 190
230 CLOSE #1
240 REM Pass 2: Build trigram model
250 OPEN "I",#1,"CORPUS.TXT"
260 IF EOF(1) THEN 300
270 LINE INPUT #1,L$
280 GOSUB 700: REM Build trigrams
290 GOTO 260
300 CLOSE #1
310 REM Input sequence and predict
320 PRINT "Enter two-word sequence (e.g., 'the quick'):"
330 INPUT S$
340 GOSUB 800: REM Extract last two words and predict
350 PRINT "Next word:";W3$
360 GOTO 320: REM Loop for more predictions
500 REM Subroutine: Count word frequencies
510 W$="":P=1
520 IF P>LEN(L$) THEN RETURN
530 C$=MID$(L$,P,1)
540 IF C$=" " OR P=LEN(L$) THEN GOSUB 550: GOTO 570
550 IF W$<>"" THEN FOR I=0 TO 999: IF V$(I)=W$ THEN F(I)=F(I)+1: GOTO 560: NEXT I
560 W$="":P=P+1:GOTO 520
570 W$=W$+C$:P=P+1:GOTO 520
600 REM Subroutine: Assign top 1000 words (simplified)
610 W$="":P=1
620 IF P>LEN(L$) THEN RETURN
630 C$=MID$(L$,P,1)
640 IF C$=" " OR P=LEN(L$) THEN GOSUB 650: GOTO 670
650 IF W$<>"" THEN FOR I=0 TO 999: IF V$(I)="" AND F(I)>C THEN V$(I)=W$:C=F(I): GOTO 660: NEXT I
660 W$="":P=P+1:GOTO 620
670 W$=W$+C$:P=P+1:GOTO 620
700 REM Subroutine: Build trigrams
710 W1$="":W2$="":W3$="":P=1:W=0
720 IF P>LEN(L$) THEN RETURN
730 C$=MID$(L$,P,1)
740 IF C$=" " OR P=LEN(L$) THEN GOSUB 750: GOTO 770
750 IF W$<>"" THEN W=W+1:IF W=1 THEN W1$=W$ ELSE IF W=2 THEN W2$=W$ ELSE IF W=3 THEN W3$=W$:GOSUB 900
760 W$="":P=P+1:GOTO 720
770 W$=W$+C$:P=P+1:GOTO 720
900 REM Subroutine: Add trigram to model
910 IF N>=500 THEN RETURN: REM Limit to 500 trigrams
920 FOR I=0 TO 999: IF V$(I)=W1$ THEN W1=I:GOTO 930: NEXT I:W1=999
930 FOR I=0 TO 999: IF V$(I)=W2$ THEN W2=I:GOTO 940: NEXT I:W2=999
940 FOR I=0 TO 999: IF V$(I)=W3$ THEN W3=I:GOTO 950: NEXT I:W3=999
950 FOR I=0 TO N-1: IF M(I,0)=W1 AND M(I,1)=W2 THEN M(I,3)=M(I,3)+1:RETURN
960 M(N,0)=W1:M(N,1)=W2:M(N,2)=W3:M(N,3)=1:N=N+1
970 RETURN
800 REM Subroutine: Predict next word
810 W1$="":W2$="":P=1
820 IF P>LEN(S$) THEN GOTO 850
830 C$=MID$(S$,P,1)
840 IF C$=" " THEN W1$=W2$:W2$="":P=P+1:GOTO 820 ELSE W2$=W2$+C$:P=P+1:GOTO 820
850 IF W1$="" THEN W1$=W2$:W2$="": REM Handle single word
860 FOR I=0 TO 999: IF V$(I)=W1$ THEN W1=I:GOTO 870: NEXT I:W1=999
870 FOR I=0 TO 999: IF V$(I)=W2$ THEN W2=I:GOTO 880: NEXT I:W2=999
880 W3$="<UNK>":P=0
890 FOR I=0 TO N-1: IF M(I,0)=W1 AND M(I,1)=W2 AND M(I,3)>P THEN W3$=V$(M(I,2)):P=M(I,3)
900 NEXT I
910 RETURN
This is surprising to me, since it does appear to be honoring the 2-character limit of Color BASIC variables, which is something my early interactions with ChatGPT would not do.
The original prompt told it to do something that could run on a CoCo within 512K. Even Super Extended Color BASIC on a 512K CoCo 3 still only gives you 24K of program space on startup. And, as I recently learned, if you try to use a CoCo 3’s 40 or 80 column screen and clear more than about 16K of string space, you get a crash.
I think I may give this a go. I do not understand how any of this works, so I do not expect good results, BUT I do want to at least try to see if I can make the program functional. If it expects to use 512K of RAM for string storage, this program is doomed to fail. But, 24K would be room for 1000 24-byte words, at least.
To be continued … maybe.
In the meantime, check out that Grok link and see what you can come up with. And let me know in the comments.
Waybackwhen, I wrote this proposal for a very simple BBS networking protocol. There were several in existence, but the specs were always complicated. I wanted something someone could implement without a Phd ;-)
The following is a proposal for a new CoCo BBS message networking protocol created by Allen Huffman at Sub-Etha Software. This protocol was designed to easily allow the CoCo community to link BBSs together for mass communication within this network.
Background:
Several successful BBS networking protocols are already in existence such as FidoNet and WWIVNet. Although very powerful, these systems require large amounts of disk space to operate and have so far been limited only to systems with hard drives.
Introducing the Sub-Etha Net:
The proposed “Sub-Etha Net”, henceforth known as SENet, will be a low-hardware CoCo specific network designed for the sole purpose of linking the online CoCo community together with one massive public message base.
At this time, no private messages between systems will be supported. This will greatly limit the amount of overhead required by each system. Current protocols have required each system within the net to store a “net list” containing information on ALL systems within the network. SENet will not require such a list and no “hub” systems are needed.
How it Will Work:
In order to link with the network, the Sysop will simply insert the phone number of the system it wishes to net with and configure a few settings which control when and what it will transfer. The system you plan to net with will also add your number to its listing. Once this has been done, no further configuration will be required. A simple message pointer flag stored for each system is all that is required to keep track of messages.
An Example: System A will call System B and transfer messages.
At the specified time, System A dials a number stored in it’s net list.
Upon connection, System A waits for a prompt (such as “Press Return:”) then sends an escape code and it’s phone number (in the form ###-###-####) to System B.
System B will look up that number in it’s net list and either ACKnowledge or request the number to be resent (in case of line noise).
If several unsuccessful attempts are made, System B will disconnect. (If this was caused by line noise, this forces System A to redial and try for a better connection.)
After a successful connection, System A sends a four byte number stored in it’s net list which instructs System B to send all messages it has from that number on.
System B then sends messages (with appropriate error checking).
System A will ACKnowledge the transfer (or request data to be resent).
Depending on System B’s configuration, System B will either send a final ACKnowledgement and disconnect, OR it will send it’s four byte number for a message request.
System A then sends messages (with appropriate error checking).
System B will ACKnowledge the transfer (or request data to be resent).
System A will send a final ACKnowledgemend and disconnect.
Message base structure:
To keep things a simple as possible, the message base will contain only the following information…
From: Name of poster (30 characters)
Subj: Message subject (40 characters)
Date: Date/time posted (6 character packet)
This allows the message “header” to fit in one 80 column line of information. Any other information such as “To:” or “Reply to:” will be contained in the actual message text portion of the file. This allows excellent flexibility for future expansion.
I wonder what else I will find in my archives. I still think something like this was a good idea — low overhead, simple to implement even in BASIC (though requiring an assembly language remote terminal driver), and “just enough to get the basic stuff done.”
Maybe one day we’ll do something like that using a CoCo and a $10 WiFi Modem for it ;-)
I have been going through all my OS-9 hard drive images trying to get everything compiled into one place. During this project I ran across a folder called DECB (Disk Extended Color BASIC). It contained the following files:
I had no recollection of what this was, nor why filenames were in lowercase. That was not normally how files were done from Disk BASIC on a CoCo due to the 32-column screen showing lowercase as inverted video.
The “microwar.txt” was an e-mail response to an inquiry I made to Microware in 1993 about the history of OS-9:
INTERNET# Document Id: UX00f.BUX0039573
Item 6352278 93/08/24 06:03
From: STEVES@MICROWARE.COM@INTERNET# Internet Gateway II
To: COCO-SYSOP Allen C. Huffman
Sub: Re: The History of OS-9
From mcrware!microware.com!steves@uunet.UU.NET Tue Aug 24 17:24:36 1993 Received: from relay1.UU.NET by relay2.geis.com with SMTP (1.37.109.4 /15.6) id AA23578; Tue, 24 Aug 93 17:24:36 +0100 Received: from spool.uu.net (via LOCALHOST) by relay1.UU.NET with SMTP (5T.61/UUNET-internet-primary) id AA11760; Tue, 24 Aug 93 12:24:35 -0400 Received: from mcrware.UUCP by uucp2.uu.net with UUCP/RMAIL (queuweing-rmail) id 122237.10246; Tue, 24 Aug 1993 12:22:37 EDT Received: from yme by microware.com with SMTP id AA00775 (5.67a8/IDA-1.5 for <coco-sysop@genie.geis.com>); Tue, 24 Aug 1993 10:03:08 -0500 From: Steve Simpson <steves@microware.com> Received: by yme id <AA00684@yme>; Tue, 24 Aug 93 10:03:04 CDT Date: Tue, 24 Aug 93 10:03:04 CDT Message-Id: <9308241503.AA00684@yme> To: coco-sysop@genie.geis.com Subject: Re: The History of OS-9
The “Steve” there was Steve “Homer” Simpson, who I would later know when I went to work for Microware two years later. He provide me with a Microware history article, and a Ken Kaplan interview about Microware’s first 15 years. (Note to self: Get this archived somewhere.)
The “TEST.TXT” file was a 300 line text file, obviously created by a program, that was just this:
This is a file of 300 lines or so, and this is line number * 0*... This is a file of 300 lines or so, and this is line number * 1*... This is a file of 300 lines or so, and this is line number * 2*... ...snip... This is a file of 300 lines or so, and this is line number * 298*... This is a file of 300 lines or so, and this is line number * 299*... This is a file of 300 lines or so, and this is line number * 300*...
I was a bit confused at the purpose of these two files. Fortunately, “contents.txt” cleared things up a bit.
Jan '95 #01 Demonstration Issue 1. All About This Program Allen C. Huffman INFO
2. REALLY *BIG* FILE Bob's Big Boy TEST
3. Microware Information Microware Staff MICROWAR
4. Stuff For Sale Various FORSALE
5. Useless File Bob USELESS
6. Nothing Dan NOTHING
7. Something Bob & Dan SOMETHIN
8. Movie Reviews Sis Kehl MOVIES
9. Spam Recipes Mr. Cook SPAMSPAM
F. Another File Another Writer ANOTHER
G. Nothin' Nobody NOTHING
H. Nothin' Again Nobody Again NOTHING
I. More About Flies Spider-Man FLYFILE
J. Jump Text Jumpman Bob JUMPTEXT
K. KeepThisSecret Spy SPYFILE
*. Use Star for This StarMan STAR
Seeing my name in there let me know that this was indeed something I was involved in. But what was it? I needed to move those BAS files over to an emulator and take a look.
Fortunately, one of them was already in ASCII – “reader.asc” – and it was indeed a BASIC program that apparently I wrote back in 1995.
0 REM * 1 REM * Text Viewing Program Thingy V1.00 by Allen C. Huffman 2 REM * Copyright (C) 1995 by Sub-Etha Software 3 REM * Written for Terry Simons and the MI&CC Upgrade Diskletter 4 REM * 5 PALETTE0,0:PALETTE8,63:WIDTH80:CLS1
I had zero recollection of writing this, but I remember the Mid-Iowa & Country CoCo Club (MI&CC) and its organizer, Terry Simons. Sub-Etha Software attended their Middle America Fest held in Des Moines in 1993. Somewhere, I am pretty sure I have photos from this even, but they are not in my online CoCoFest photo gallery for some reason.
I could tell this was something I wrote, since that line 5 of doing the background black, foreground white, width 80, CLS1 line was how I started all my CoCo 3 BASIC programs.
A quick scan of this program, which I will include in full, reveals it would read the “contents.txt” file and display a directory of text files (articles) on the disk and let the user select one. It would then load the file and let them read it, with options to go page to page through the file. A text file reader with a menu system – neat!
0 REM *
1 REM * Text Viewing Program Thingy V1.00 by Allen C. Huffman
2 REM * Copyright (C) 1995 by Sub-Etha Software
3 REM * Written for Terry Simons and the MI&CC Upgrade Diskletter
4 REM *
5 PALETTE0,0:PALETTE8,63:WIDTH80:CLS1
10 CLEAR17000:DIMFL$(15,3),A$(200)
50 REM * Read Index File
55 OPEN"I",#1,"contents.txt":LINEINPUT#1,IS$:LINEINPUT#1,SB$:FL=0
60 FORA=0TO3:LINEINPUT#1,FL$(FL,A):NEXT:IFEOF(1)=0THENFL=FL+1:IFFL<30THEN60
65 CLOSE
100 REM * Table of Contents
105 CLS:LOCATE28,0:PRINT"Mid Iowa & Country CoCo":LOCATE40-LEN(IS$)/2,1:PRINTIS$;:LOCATE0,3:ATTR0,7:PRINT:ATTR0,0:LOCATE0,22:ATTR0,7:PRINT:ATTR0,0
110 GOSUB1155:LOCATE35,2:PRINT"Main Menu";:GOSUB1130:LOCATE23,23:PRINT"Select File to View or [Q] to Quit";
115 FORA=0TOFL:LOCATE40*ABS(A>7)+5,(A AND7)*2+5:PRINTFL$(A,0):LOCATE40*ABS(A>7)+23,(A AND7)*2+6:PRINTFL$(A,1):NEXT
120 GOSUB1055:A=0:IFA$="Q"THEN450
125 IFA$=LEFT$(FL$(A,0),1)THENFL$=FL$(A,2):A$=FL$(A,0)+" by "+FL$(A,1):GOTO205ELSEA=A+1:IFA<16THEN125
130 SOUND100,1:GOTO120
200 REM * View a File (FL$)
205 LOCATE40-LEN(A$)/2,2:PRINTA$;:GOSUB1130:LOCATE2,23:PRINT"[UP] Next Page [DN] Prev Page [J]ump to Page [P]rint File [Q]uit to Menu";:LN=0:
210 GOSUB1105:ONERR GOTO245:OPEN"I",#1,FL$+".TXT":ONERR GOTO
215 LOCATE32,13:ATTR0,0,B:PRINT"Loading File ...":ATTR0,0:MX=0
220 IFEOF(1)=0THENLINEINPUT#1,A$:A$(MX)=LEFT$(A$,65):MX=MX+1:IFMX<200THEN220
225 CLOSE:LOCATE68,2:PRINT"Lines:";MX;:LN=0:LOCATE0,12:PRINT
230 LOCATE0,2:PRINT"Page"INT(LN/18)+1"of"INT(MX/18)+1" ";:FORA=0TO17:LOCATE8,A+4:IFLN+A<MX THENPRINTA$(LN+A)ELSEPRINT
235 NEXT
240 GOSUB1055:A=INSTR(CHR$(94)+CHR$(10)+"JPQ",A$):IFA<1ORA>5THENSOUND100,1:GOTO240 ELSEONA GOTO255,305,355,405,430
245 FORA=12TO14:LOCATE15,A:PRINT"* File Not Found - Press Any Key for Main Menu *":NEXT:GOSUB1055:GOSUB1105:GOTO110
250 REM * [UP] Next Page
255 IFLN+18<MX THENLN=LN+18
260 GOTO230
300 REM * [DN] Prev Page
305 IFLN-18=>0THENLN=LN-18
310 GOTO230
350 REM * [J]ump to Page
355 LOCATE0,11:PRINT:PRINT:PRINT:LOCATE29,12:PRINT"Jump to Page 1 -"INT(MX/18)+1":";:GOSUB1005:A=VAL(A$)-1:IFA<0ORA>INT(MX/18)THENSOUND100,1:GOTO230ELSELN=A*18:GOTO230
360 IFPG>1THENPG=PG-1
365 GOTO230
400 REM * [P]rint Article
405 LOCATE0,11:PRINT:PRINT:PRINT:LOCATE13,12:PRINT"Ready Printer. Press [ENTER] to Print or [Q] to Quit";
410 GOSUB1055:IFA$="Q"THEN230ELSEIFA$=CHR$(13)THEN415ELSESOUND100,1:GOTO410
415 REM --- if printer is not online, beep and go back to 201... <- check here
420 A=0
425 PRINT#-2,TAB(8)A$(A):A=A+1:IFA<MX THEN425ELSE230
430 GOTO110
450 REM * Quit
455 CLOSE:CLS:STOP
460 END
1000 REM * Line Input
1005 LINEINPUTA$:RETURN
1050 REM * Inkey$
1055 A$=INKEY$:IFA$=""THEN1055
1060 CH=ASC(A$):IFCH>95THENA$=CHR$(CH-32)
1065 RETURN
1100 REM * Clear Text Area
1105 FORA=4TO21:LOCATE0,A:PRINT:NEXT:RETURN
1125 REM * Clear Bottom Line
1130 LOCATE0,23:PRINTSTRING$(79,32);:RETURN
1150 REM * Clear Top Line (well, third one actually...)
1155 LOCATE0,2:PRINTSTRING$(79,32);:RETURN
I used the Toolshed (new GitHub home) decb command line tool to create a blank 32-track DSK image, and then then copy the “reader.BAS” file over to it. I also copied the “contents.txt” file, since that was needed.
I booted up the Xroar emulator, mounted my new disk image, and loaded the program. When I ran it, it went to a black screen momentarily, then I saw this:
I assumed the file might be corrupted, so I then tried to CLOAD the ASCII file in Xroar. That is a neat feature that lets you “Load” a text file, then when you type CLOAD it simulates loading an ASCII file form tape, using the input text file as that ASCII file.
Same problem.
I visually inspected the program. Maybe there was some EXEC to an assembly routine that needed to loaded before RUNing this BASIC.
Nothing.
Was Xroar defective? I went to the Xroar Online Emulator and tried it there, loading my DSK image through the web page.
Crash.
I then posted to the CoCo e-mail list sharing a Dropbox link to a folder containing these files, as well as the DSK image. I asked if anyone could test it and see if it crashed for them, as well. Michael Kline was the first to respond:
Alan,
I tested all BASIC programmes on a CC3. They all lock up.
Michael
This at least let me know it was not an Xroar-specific issue. But what was this issue?
I experimented with the TRON command to see how far the program would get before locking up. It would print some quick values [0][1][2][3][4][5] before the screen cleared and things crashed, but this time to a blank green screen. The output to the 32-column screen was changing behavior.
I commented out line 5 so it would stay on the 32 column screen, and ran it again. I saw it spew out line numbers, before clearing the screen and printing an “?HP ERROR IN 105”. That is the error you get when you do CoCo 3 40/80 column screen commands on the 32 column screen. From the looks of things, removing the WIDTH80 line allowed it to get to around line 60 or so before one of those commands was used and it errored out.
Why would WIDTH 80 crash a program? I did more experiments. After this error, with the system not locked up, I typed “5 WIDTH 40” just to add a screen width, but no PALLETEs or CLS command.
According to TRON, the program was crashing at WIDTH 40… Huh???
Each time a crash like this happened, the virtual CoCo had to be restarted (power cycle). Just a virtual reset would not work. You might get “OK” back but things were not working.
Very, very odd.
I finally got my program to run by changing the value of the CLEAR command in line 10. (Initially, I deleted the whole line after the WIDTH line just to see what happened, and narrowed it down to something to do with the CLEAR.)
I shared my results on the CoCo list, and William “Lost Wizard” Astle, one of the great minds at understanding how the BASIC ROMs operate, replied with this tidbit:
It won’t be a string space bug – handling that didn’t change in the Coco3.
Have you been running it from the 40 or 80 column screen? If so, that’s probably why. The driver for handling output to the 40/80 column screen doesn’t properly manage the memory map and if the stack ends up too low in memory, it gets swapped out while the 40/80 column screen is mapped in, leading to a system crash. String space and the address parameter to CLEAR are both above the stack.
This crash happens if the stack ends up below $4000 if memory serves.
If you aren’t running from the 40/80 column screen, it may be some other weirdness triggering it.
– William Astle, via the CoCo List
Light has been shedded, and I knew all I would have to do is look up the Super Color BASIC Unraveled book to find a clear and concise explanation of this bug. But, before I got there, William added more details:
The only solution as far as I can tell is do no output on the 40/80 column screen or clear less string space. Given that a lot of the numbers used for CLEAR for string space are effectively random with no real understanding of how big they need to be, it’s entirely possible that 17000 is way more than it needs to be. Something most programmers don’t know is that a string constant in the program that is never modified doesn’t use up any string space so often the CLEAR number is massively larger than it needs to be.
Having the WIDTH before the CLEAR should prevent WIDTH from crashing but any subsequent PRINT, LOCATE, INPUT (from keyboard), or HSTAT probably would crash.
– William Astle, via the CoCo List
My confusion continued, and finally a third response form him added this:
It’s not that straight forward and unravelled doesn’t mention it. I only know because I tripped on it hard back in “the day” and it left me scratching my head for quite a while.
Basically, the stack has to stay above $4000 (the screen gets mapped in the $2000 to $3FFF range) so that would probably put the absolute limit somewhere just under 16K (16384). You’d want 200 bytes or so room for the stack so 16000 would be a nice round number. On the other hand, if you reserve any memory with the second parameter for CLEAR, that number goes down.
Perversely, if you could get the stack to be *below* $2000, it would also not crash, but that means a very small program with no PMODE graphics, probably.
The size of scalar variables, arrays, or program text doesn’t actually matter for this calculation because the screen is not mapped in except when doing I/O on the screen.
– William Astle, via the CoCo List
A bug the Unraveled folks didn’t know about? William stumbled upon it back then, and if this code was a version I tried to run, I must have, as well. But, why would I have left it in this non-working version? I expect I may find a “fixed” version of this program in my Disk BASIC disk archives, eventually. For all I know, maybe I kept this one around as a “what is wrong with this program” example, copying it to my OS-9 hard drive so I could post it on a BBS or online service (or even to the original CoCo List back then).
Hmm, I wonder if the old Princeton CoCo list archives still exist. Maybe I posted about this 30 years ago (1995!) when I was writing this program? (Note to self: Look that up…)
But I digress.
If you CLEAR a big enough number, then do a WIDTH 40 or 80, the CoCo 3 crashes hard. I toyed with that value, and you can get to a spot where it works, then a bit higher and you get some different types of crashes with the screen freaking out in different ways, but all end up the same way: crashed CoCo, must hard-reset/power cycle to recover.
Have you ever run into this bug on your CoCo 3? Please leave a comment with your story…
Until next time…
One more thing…
Oh yeah… Here is what the program looks like when it runs.
2025-02-27 – Corrected use of “hard links” to be “symbolic,” per William A. in the comments. Thanks!
NOTE: I am posting this as a plea for help. If you understand this problem, and know of solution, please leave a comment. I would really appreciate some input and clarification on my “understanding” of this issue.
TL:DNR: Symbolic links are a workaround.
The year is 2025, and open source projects can still be broken by having a space in a path name.
According to a robot, “Windows has allowed spaces in filenames and directory names since Windows NT 3.1, which was released in 1993.”
I have not fact checked this. My first PC was a Toshiba laptop I purchased at the end of 1995. (Not counting my DOS-based Tandy 1400LT I had years earlier.) At that point, it was Windows 3.1 that followed the 8.3 filename format that CP/M used.
FILENAME.TXT
It was the late Steve Bjork that convinced me to upgrade to the new Windows 95 when it came out. This upgrade allowed filenames up to 255 characters, if my quick web search is correct. I recall having a DOS C compiler (“Power C” – wow, they still sell this???) and it did not support the long filenames. Windows did provide some level of backwards compatibility by having any long filename still represented by a short name, which would have the first part of the filename then a “~1”, so something like “really long filename.txt” might also exist as “REALLY~1.TXT”.
Side note: There was a quirk with this implementation. Even filenames that could have fit in the 8 characters seemed to get this “~1” added to them. BUT, you could rename those to the normal 8 characters and is till worked. i.e. “filename.txt” would create “FILENA~1.TXT” but you could then “RENAME FILENA~1.TXT FILENAME.TXT” and it would show up as FILENAME.TXT. I actually wrote a C program that would go through the directory and rename any files like this. Fun times. And yikes, that was 30 years ago!?!?!
So basically, for three decades we could have spaces in filenames and directories on Windows.
Unix, back when it started, had short filenames and did not allow spaces initially. But, as long as I have been using it (my first exposure was 1995 on SunOS) I believe it did.
In the late 1980s I began using Microware’s OS-9 for the 6809 (on a Radio Shack Color Computer 3). While it had longer filenames than DOS (28 characters?), it did not allow spaces in filenames or directory names. I am unsure if the modern OS-9000 (renamed to just “OS-9 for x86” or whatever architecture, waybackwhen) has ever updated to allow spaces.
But I digress.
I still run across open source projects that fail if they are built from a path that has a space anywhere in it. For example, if you have this:
/usr/allenh/github downloads/
…and you “git” your project there, the build might break because of that space. Scripts may just see it as “/usr/allenh/github” and fail. This seems to be the case for the NitrOS9 Project, a fantastic effort to recreate OS-9/6809 with tons of enhancements.
From my experience, I think these problems can be solved by simply adding quotes around paths in the build scripts. For example, if you have this:
DISCLAIMER: Just examples. I know about escaping spaces as “\ ” in *nix filesystems, and maybe something like that exists for Windows (let me know in the comment).
But, again, this is 2025. I run into projects that fail with spaces in the path multiple times a year.
Just don’t put spaces, duh.
“Hey doctor, it hurts when I do this.”
“Then don’t do that.”
Why not just remove the spaces? In olden days, you were in control of directories because you made them. I came from a “no spaces allowed” OS background so I never used spaces. “SOURCECODE” or, if underscore was allowed, maybe “SOURCE_CODE” to be more readable (but I hate typing two extra keypresses to generate that underscore).
But, Windows may not agree. Once I did a fresh Windows install, and let it do all the defaults (Microsoft account to login, enable OneDrive, etc.) and the path it created had a space in it. Anything that I put in “my” home folder (Documents, etc.) had a space somewhere earlier in the path.
Likewise, on macOS, if you use iCloud, some default directories get links that make them look “normal”:
…but if you decide to make your own directory on your “iCloud Drive”, you see the true long path — which has a space in it!
allenh@Mac Development % pwd /Users/allenh/Library/Mobile Documents/com~apple~CloudDocs/Others/Development
That “Mobile Documents” path is the cause of so many problems.
My workaround was to simply move these folders outside of my self-created directory and put them into one of the defaults, like “~/Documents/Development”.
Symbolic links, anyone?
On macOS (a Unix-type operating system), and Linux (if such a problem exists there?), you can create symbolic-links to folders. You create a new name and then tell it where it points to.
Now in my home folder, I have a directory called “Development-iCloud” that has no space in it, but points to the real spot with a space:
allenh@Mac ~ % cd Development-iCloud allenh@Mac Development-iCloud % pwd /Users/allenh/Development-iCloud
Now I can change into that folder and build scripts that were failing will work. Nice.
But what about Windows?
I have not tried it myself, mostly because I didn’t have A.I. to ask for a solution the last time I ran into this on Windows, but there is a “mklink.exe” command that appears similar, and may solve the problem there:
mklink /D "C:\path\to\link" "D:\path\to\actual"
It feels like this workaround should work there.
But is this what developers do? Most smart computer folks I know run away from anything cloud (and for good reason). I have been drinking the Kool-Aid for awhile and love having access to non-private files on all my devices, via syncing on Dropbox (mostly) or iCloud or OneDrive or Google Drive. I use all of them, for different purposes.
There is something wonderful about having a poor memory. Whether I knew something before or not, I do not remember it now, so I get the pleasure of “learning something new” even if I previously knew the new thing.
In a reply to my Color BASIC and octal post, Juan Castro mentioned another quirk about how BASIC sees numbers represented as decimals versus hex or octal.
AND, OR, AND NOT demand signed 16-bit integers as input, whereas the &H/&O expressions (and consequantly my &B extension) return UNsigneded integers. That is VERY annoying:
PRINT &H8001 AND &H0007 ?FC ERROR OK
Come the %#&*£ ON!
– Juan Castro
I am unsure about this, since after the parser reads through the code, it turns any hex or octal or decimal value intothe internal 5-byte floating point representation of the value. “A=65535” turns into exactly the same type of variable as “A=&HFFFF”.
AND and OR should deal with them exactly the same way. In Juan’s example, decimal values will generate the same ?FC ERROR. But there is a workaround…
I stumbled upon this when playing around with using AND and OR to set or test bits. My Color BASIC and 16-bits and AND and OR and NOT article explains what I was trying to do, and how I ultimately ended up achieving it.
In Juan’s example, &H8001 is 32769 in decimal. &H0007 is 7. Having the “high bit” (bit 15) set of the first value effectively makes it a negative number:
1000000000000001 = &H8001 (32769) ^ ^ bit15 bit0
Any value with that bit set will not work with AND or OR, regardless if you represented it in decimal, hex or octal. You can go up to &H7FFF (32767) using AND or OR, but past that, you get the ?FC ERROR:
Juan has been working on some BASIC enhancements, adding new features (like a method of representing values in binary — which I would find quite useful). But seeing numbers in binary not work would be even more frustrating:
PRINT &B100000000000000 AND &H1 ?FC ERROR
…at least, that is my assumption about what is “&B” binary representation would do.
Here is how to make Juan’s code work:
PRINT (&H8007-65536) AND &H0007 1
Any value that has that high bit set needs to have 65536 subtracted from it, then you get the results you would expect.
But unfortunately, you cannot use AND to test for that high bit to be set ;-) so instead you have to do silly things like this:
V=&H8007 IF V>&H7FFF THEN V=V-65536 PRINT V AND &H0001
And it’s just that easy!
Though, if you print V, you will see it is a negative number, as you might have guessed. If you don’t need to PRINT V, doing something as simple as this will let you AND and/or OR on values that have the high bit set.
A followup from my previous post… This box, which appeared in Rainbow magazine, was called Rainbow Check Plus:
Rainbow Magazine checksums
It first appeared in the February 1984 issue, and was even featured on the cover:
The article “Rainbow Check Plus for the CoCo and MC-10” appears on page 21, and was written by H. Allen Curtis. (Why is that name so familiar?) I did not realize it was available for the MC-10 as well. Here is the listing for the CoCo version:
10 CLS:X=256*PEEK(35)+178
20 CLEAR25,X-1
30 X=256*PEEK(35)+178
40 FOR Z=X TOX+77
50 READ Y:W=W+Y:PRINT Z,Y;W
60 POKE Z,Y:NEXT
70 IFW=7985THEN80ELSEPRINT"DATA ERROR":STOP
80 EXEC X:END
90 DATA 182,1,106,167,140,60,134
100 DATA 126,183,1,106,190,1,107
110 DATA 175,140,50,48,140,4,191
120 DATA 1,107,57,129,10,38,38
130 DATA 52,22,79,158,25,230,129
140 DATA 39,12,171,128,171,128
150 DATA 230,132,38,250,48,1,32
160 DATA 240,183,2,222,48,140,14
170 DATA 159,166,166,132,28,254
180 DATA 189,173,198,53,22,126,0
190 DATA 0,135,255,134,40,55
200 DATA 51,52,41,0
But wait … there’s more. As I was looking into this, I learned that “Rainbow Check Plus” was a follow-up to “Rainbow Check” which appeared in January 1983. It seems the original “Rainbow Check” would not catch some key items:
Incorrect line numbers. “300 CLS” and “390 CLS” would provide the same check value.
Incorrect variables. It would not catch a wrong variable. The example given is that “F” would be the same as “E”.
Incorrect command words. SGN or SIN would provide the same checksum.
Now I really wonder what it was doing to generate the numbers, if it wasn’t looking at the actual line data ;-)
The original version appeared on page 95 as part of the “Assembly Corner” column by Dennis L. Lewandoski. The column was called “Let’s End Those Typing Errors Once and For All.” This version appeared in the form of an assembly language program listing, as well as a BASIC loader with DATA statements.
Here is the BASIC program listing for the original 1983 “Rainbow Check” version:
10 CLS:IFPEEK(116)=127 THEN X=32688 ELSE X=16304
20 CLEAR25,X-1
30 IFPEEK(116)=127 THENX=32688 ELSE X=16304
40 FORZ=X TO X+77
50 READY:W=W+Y:PRINTZ,Y;W
60 POKE Z,Y : NEXT
70 IFW=5718 THEN80 ELSE PRINT"DATA ERROR":STOP
80 EXEC X:END
90 DATA 182,1,106,167,141,0,68
100 DATA 134,126,183,1,106,190
110 DATA 1,107,175,141,0,57,48
120 DATA 141,0,4,191,1,107,57
130 DATA 129,10,38,44,52,22,220
140 DATA 27,147,25,142,4,0,141
150 DATA 6,31,152,141,2,32,25
160 DATA 52,2,68,68,68,68
170 DATA 141,4,53,2,132
180 DATA 15,129,9,46,4,139,112
190 DATA 32,2,139,55,167,128,57
200 DATA 53,22,126,0,0
Unfortunately, the assembly was not provided on Rainbow on Tape, so I would have to type it all in by hand.
I suspect I will have to do just that, as well as disassemble the 1984 version and see how both worked, which might explain the limitations of the original.
Over on YouTube, user @ms-ex8em pointed me to the November 1988 issue of Dragon User magazine and a little program that helps you type in machine code program listings accurately.
I recall spending countless hours typing in machine code programs from Rainbow Magazine “back in the day”. These programs would be a few lines of BASIC followed by dozens or hundreds of lines of DATA statements with numbers that represented the bytes of the machine language program.
One such program I specifically remember was Zonx, a cool game with background sound effects. It appeared in the October 1985 issue. You can see what I typed in by checking out page 65. And page 67. And page 68. And page 70. And page 71.
And, somehow, I managed to type all of those numbers in and get a working program!
Rainbow did have one thing to help — and perhaps I used it. They had a small program you could run, then as you typed in your program listing, when you got to specific lines you could hit a key and it would spit out a number (a checksum?) and see if it matched their numbers:
Above, you can see what number should be expected when you got to line 150, 310, 440 and so on. After all the code was typed in, the final number it should give you was 238. This required you to type in the program exactly as it appeared including spaces and any other formatting.
It was not optimal, but it was better than nothing.
I also saw some BASIC loaders for machine language that took matters into their own hands, and had built-in checksum values in their DATA statements. For example, they would put a specific amount of numbers on each line, with a checksum of those numbers at the end. Say that amount of numbers was five. A line might look like this:
1500 DATA 1,1,1,1,1,5
In that silly example, you could add up ever five bytes you READ and then compare that to the 6th byte in each line. If it matched, continue. If it didn’t, the loader code would print some kind of message, hopefully indicating what line had a mismatch.
I always appreciated program listings that did that.
Now, back to @ms-ex8em… The code they shared was quite different. You can find it on page 12:
10 REM HEX LOADER
20 CLEAR 200,31599
30 INPUT"START";ST
40 INPUT"END";ED
50 FOR J=ST to ED STEP 8
60 PRINT USING"##### : ";J;
70 INPUT A$
80 CS=0
90 FOR K=1 TO LEN(A$)
100 CS=CS+K*VAL("&H"+MID$(A$,K,1))
110 NEXT K
120 INPUT" = ";C
130 IF S<>CS THEN PRINT"CHECKSUM ERROR-TRY AGAIN":SOUND 1,1:GOTO 60
140 FOR K=0 TO 7
150 POKE J+K,VAL("&H"+MID$(K*2+1,2)
160 NEXT K,J
First comment… There appears to be a mistake in line 150. It should have two closing parens at the end of the line.
Now let’s see what this code is doing.
In line 10, the CLEAR reserves memory (so BASIC cannot use it) starting at 31599. This is because the machine language program will load starting at 31600.
In line 40, the user is asked to input the start and end of the program they will be typing in.
In line 50, there is a FOR/NEXT that goes from start to end, stepping by 8. This tells me they expect 8 bytes of data on each line the user types in. The first input should be at 31600, then the next at 31608 and so on.
The user types in the 16 characters (representing 8 hex bytes) shown in the box below. They look like this:
31600 : 8E7B6F9F74Be012B = 1016
In line 80, a checksum is calculated by adding up the value of each character typed in that line.
In line 120, the user is asked to type in the checksum shown in the data listing.
In line 130, if the number the user typed in (from the data listing) does not match value the program calculated, an error message prints and it goes back to let the user retype the entire line.
If it matched, line 140 will then go through those 16 characters and create the byte value for each of the 8 data bytes and POKE them into memory at the proper place.
This repeats until the end address is reached. At that point, some new assembly language program has been loaded into memory starting at 31600.
Pretty cool!
The problem @ms-ex8em was seeing with this program was a ?TM ERROR. That is most likely showing up in line 150 because of the missing paren. Fix that, then maybe the rest will work ;-)
I thought this was a neat way to enter in machine code. What other neat ways did you see back then?
Many years ago, I played with drawing a 3-D maze under OS-9 on my Radio Shack CoCo 3. That demo is on the NitrOS-9 “Ease of Use” release under the name “semaze“. It lets you wander around a simple line maze:
There is even a map you can bring up with “?”:
As I mentioned years ago on this site, I had played with turning that into an OS-9 version of the classic Phantom Slayer 3-D game on the CoCo 1. I got as far as having my maze with a “phantom” in it that would wander around:
An unfinished CoCo 3 OS-9 3-D maze game inspired by the old “Phantom Slayer” by MED SYSTEMS.
But the oddest version was probably me putting the Pac-Man maze into my 3-D “engine” and then deciding to put dots around it, and make it refresh every half second or so, making it a “real time” game. With a prototype ghost (which appeared just as a large circle) wandering around!
And bringing up the map showed the Pac-Man maze:
In the days before the Internet, the only way I would have been able to recreate this map is if I had access to an accurate home port (I did not), or a picture in a magazine (maybe). I am guessing I based it on some CoCo Pac-Man clone with a fairly accurate maze.
How well did I do? Here is my CoCo version, then the actual arcade game, and the Arduino TV-Out version I was working on a decade ago (very accurate, down to the tiles).
Pac-ManArduino Pac-Man!
I can see a few errors, like the bottom walls under the power pellets going into the maze an extra tile. And the dots are off. Today, I understand how the Pac-Man maze is laid out with tiles so it would be much easier to recreate my 3-D “DotMaze” game with an accurate map.
2025-02-19 – Thanks to a comment from William Astle, the term “decimal” number has replaced my incorrect use of “integer.” And per a comment from James Jones, a clarification that all values you input are still stored internally as the same type of numeric floating point – the parsing converts them all to this floating point representation.
Color BASIC had one type of number you could use: decimal. These are the normal numbers we use every day like 1, 50392 or 42.
A=42 PRINT "A IS";A
When Extended Color BASIC was added, the CoCo accepted the following notations for numeric constants: integer, hexadecimal and octal. (Internally, BASIC converts them all to the same numeric representation of a floating point value.)
Getting Started with Extended Color BASIC describes hex and octal as follows:
Extended Color BASIC lets you use both hexadecimal and octal constants.
Hexadecimal numbers are quantities represented in Base 16 notation, composed of the numerals 0 to 9 and the “numerals” A to F. Hexadecimal constants must be in the range 0 to FFFF, corresponding to the decimal range 0 to 65535.
To indicate that a number is an octal constant, precede it with the symbol &H, as shown here:
&HA010 &HFE &HDl &HC &H4000
Octal numbers are quantities represented in Base 8 notation, composed of the numerals 0 to 7. Octal constants must be in the range 0 to 177777. The computer stores them as two-byte integers that correspond to the decimal range 0 to 65535.
To indicate that a number is an octal constant, precede it with the symbol &0 or &, as shown here:
&070 &044 U1777 &7170 &17 &01234
The use of “hex” and octal constants is convenient in programs that reference memory locations and contents. For further information, read a book on machine-language programming.
– Getting Started With Extended Color BASIC (p. 195, 1984 revision)
I most likely learned hexadecimal when I was learning assembly language. Today, I use hex values often in C programming. But octal? I do not think I have ever used it for anything. Have you?
I do believe I have seen it used “in the real world.” In the late 1980s (possibly early 1990s) I had a Kawai K1 synthesizer keyboard. It organized its instrument settings (called “patches” in reference to early synthesizers using “patch cables” to route signals do different processors) into two groups of Internal (onboard storage, uppercase “I” and lowercase “I”) and two groups of External (memory card, uppercase “E” and lowercase “e”). Each section had eight patches.
My first commercial CoCo program was a MIDI Librarian that could read the patches from the synthesizer and save them to disk, or load patches from disk into the keyboard. The patch screen in question looked like this:
You will see that each area had four banks (A-D) and each of those had eight patches (1-8). Uppercase “I” was A(1-8), B(1-8), C(1-8) and D(1-8), and lowercase “i” was the same. This was also the same for the External banks.
Thus, octal. I could have used octal in my program — but I do not know if I even realized this was octal at the time. I’d have to think about how I would have even done that. Maybe something like this:
0 'OCTALIN.BAS (2-15-2025) 10 LINE INPUT "BANK (0-7):";B$ 20 LINE INPUT "PATCH(0-7):";P$ 30 NM=VAL("&O"+B$+P$) 40 PRINT "THAT IS PATCH #";NM
…though I do not recall how the MIDI messages. It could have just been a user interface thing and internally the patches were still 1-whatever.
But I digress.
Juan Castro posted to the Color Computer e-mail list about a bug in the octal routines:
Octal constant (Ex.: &O14 = 12 decimal)
It accepts 8 as a digit. D’oh. Try “PRINT &O18” in a CoCo 1 or CoCo 2.
Without having a CoCo3 at hand to check I’ll wager it patches that bug. All it has to do is replace a LBHI with a LBHS.
Since an octal value should only be 0-7, a value of 8 is not valid octal.
10 CLS:PRINT"DEC","OCT" 20 FOR A=0 TO 10 30 PRINT A,VAL("&O"+STR$(A)) 40 NEXT
This should print 0-7 then error out. Yet…
And is there really no better error than SYNTAX for this type of problem?
And naturally, I had to see what HEX values do. A valid hex digit is 0-9 and A-F, representing 0 to 15. Will it do a syntax error as well if I go past the letter F?
It appears it does not. It seems to bail on the parsing and print them as two variables. Which is a neat trick, since you have to put a space or semicolon between two variables if you want to print them otherwise.
To confirm that is what it is doing, I tried this:
Ah, so it is not treating this as variables “H” and “G”. And I just learned something new (and probably useless).
Something new (and probably useless)…
Integer values are things like 1, 2, or 152032. They are floating point values, so you can also have things like 1.2 or 33.5. Though, not always. Floating point values cannot represent every decimal value accurately, but that’s a story for another article…
Somewhere, someone learned that a decimal (period) by itself would be treated as zero. The fastest way to assign 0 to a variable in Color BASIC is like this:
A=.
Weird, but it works. It seems the parser starts looking for a fractional amount, like “.25” or whatever, so it processes the period and then there is nothing else so the code returns with 0 (the initialization value when the function is called). It is still weird, though.
I found out tonight that the same thing applies to hex. You can do this:
A=&H
…and you get a zero. Try “PRINT &H” to see for yourself.
Of course, I had to try a quick benchmark, sitting in a loop doing something like “Z=.” and another run doing “Z=&H”. 1000 times through with “Z=.” used 140 timer ticks. The “Z=&H” used 154. I guess that is the overhead of parsing two characters instead of one.
But I digress. Again.
I have not looked up what BASIC is doing (see the excellent “BASIC Unravelled” books for the disassembly of the BASIC ROMs), but I suspect the parser starts looking and finds the “&” followed by the “H” and is ready to parse… it then hits an invalid character, so the parsing is over and 0 is there. Then it sees the G, which is not a command so it is treated like a variable.
Using “PRINT” was deceiving. Had I just tried this:
A=&HG
…I would have got what I was expecting:
?SN ERROR
Thanks, Juan, for sharing this. I learned about a bug, and in writing this, discovered another odd thing, which is less odd now that I understand what happened.