Recently, I shared this way to crash a CoCo 3 in three easy steps:
Turn it on.
Type in “CLEAR 16500:WIDTH 40”
There is no step three.
I expected to do a follow-up once I had time to look at the Super Extended Color BASIC Unraveled book and try to figure out what was causing this crash. I also planned to figure out what value triggered the first crash. I discovered this in a program that did a “CLEAR 17000” and I just went up and down trying to find a threshold where it crashed, and gave up at 16500.
But I am lazy.
And sometimes dense. It didn’t dawn on me that I might have been able to have the computer try to figure out when it crashed. But it did to Juan Castro. In the comments, Juan wrote:
First thing I thought was to increase the value of CLEAR in a loop to see exactly when it crashes… oops, you can’t, you nuked your loop counter with the CLEAR.
No problem, let’s use fixed memory for the counter. &H400, the start of the (now unused) text screen. We’ll start with 16000 (=&H3E80) and increment by one.
It locks up at 16356 — suspiciously close to 16384. Only 28 bytes off. That’s probably close to how much the stack occupies. (Modulo some buffer headers, variable descriptors, and maybe some non-fatal stack corruption.)
– Juan Castro
Brilliant!
And I bet once we dig in (I believe William Astle has done this work in the past) we will find that location is where an 8K MMU block gets mapped in/out for manipulating the high res text screens. Or some other words to that affect that I do not know how to properly articulate.
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 ;-)
It seems I started running a BBS in Lufkin, Texas around 1989 or so. It ran under OS-9 which allowed me to still be programming on my computer and such while a caller was online. Fun times.
Delta, meaning change, was significant here. The BBS would change themes! (This idea came from, I believe, an MC-10 buddy of mine I knew in Houston. Hello, Paul, wherever you are!)
I recently found a few of the themes and thought I’d share them here… Welcome screen, bad password screen, login screen, and goodbye screen.
DeltaBoard (native theme)
____ ____ _____ | \ | | | /\ | ) |--- | | / \ Online Since December, 1991! |___/ |____ |____ | /____\ Originally Online in 1989!
/) The DeltaBoard (\ 3/12/2400 Baud - MNP5 - 8/N/1
Co-SysOps: Axel and OSIRIS
"Online Home for Sub-Etha Software!"
To request a password, press [Return] at the UserName prompt.
Special Login Accounts (type at the UserName prompt):
Special \\ Guest - Forget your password? Login >> OldDelta - To login to the ORIGINAL DeltaBoard circa 1990. Account // PKZip - To download the latest version of PKZip (2.04G)
---
The password you have entered is invalid.
Please check your password then try your call again.
If you need assistance, or have forgotten your password, you may call back and logon as "guest" then leave feedback to the SysOp and tell him what you want for a new password that you can remember...
---
Access granted to Allen's Half-Meg 6809 Based Multi-Tasking Timesharing System. ___ ___ ___ ___ ___ / / /__ _ /__/ The DeltaBoard - Lufkin, Texas \___ _\__ \ _ /__/ ___/ ___/ Area (409) Hub for StG Net International __\ \__ \__\
---
[Y)es - End call.\ [N)o - Return to main menu.\ [F)eedback - Leave mail to SysOp.\
King: Allen Huffman of Nothingham Surf: Sire Axel of Oile Chief Peon: Osiris
"It has been a long fortnight for you, I see," says the Greeter. "Well, come inside and chat with the King, or have a tankard of our finest ale. All is well here!" he finishes.
To request a password, press [Return] at the UserName prompt.
Special \\ Guest - Forget your password? Login >> OldDelta - To login to the ORIGINAL DeltaBoard circa 1990. Account // PKZip - To download the latest version of PKZip (2.04G)
---
"Halt!" screams the greeter, suddenly not beeing so greetful. "I do not recognize you! Are you the imposter we have heard of in the village? Please call back and knock again when you can remember who you are lest the guards throw you in the dungeon! If you still need help, you may pretend to be "GUEST" and the castle helper will help you...
The doors shut.
Click. ---
The old wooden doors creak open slowly. Inside, you can see that there is a ball in progress with ladies dressed in their finest and gentlemen laughing boisterously. A sense of excitment fills the room as the ladies pause to glance at you and the gentlemen rush to shake your hand.
"Welcome back! So glad to see that the battles have left you none the worse for wear!" someone says.
King Allen himself is here, and is waiting to speak with you about your journeys. But first, you must meet with your beloved mate.
"Tell me about it," your mate requests. "Tell me everything...!"
Of course, your mate cannot hear you over the party so you must write everything down. For your convenience, Castle Delta has a list of options for you to use. Enjoy all we have - all one needs to do is ask, and it shall be given. Enjoy your stay!
---
The time has come for you to depart. Beware the many pitfalls in your path\ and remember: when you need a break from the world, come to Castle Delta.\ We will always welcome you as our most important guest. If you would like\ to leave word with King Allen about your stay, feel free to do so...\ \ [Y)es - Leave the castle.\ [N)o - I forgot something. I gotta go back and get it!\ [F)eedback - Leave the King mail. {Not chain mail, though...}\ [O)ptional - Talk with, or leave a message to, a peon...\
---
As you exit, the castle door slams shut, leaving you to wonder just what lies ahead in this dark, sinister world. But, you take solice in the fact that you may return at your next opportunity. After all...your mate is here behind the walls of Castle Delta!
Manager: Allen Huffman Clerk: Axel Bellhop: Hopsing
[.. VACANCY]
To request a password, press [Return] at the UserName prompt.
Special \\ Guest - Forget your password? Login >> OldDelta - To login to the ORIGINAL DeltaBoard circa 1990. Account // PKZip - To download the latest version of PKZip (2.04G)
"Please sign the register..." the clerk requests.
---
"Are you sure this is your credit card?" the clerk asks.
"Please come back again when you have proper identification and sign in {and make it legible next time, buddy!} or, if you have never stayed with us before or cannot remember if you have, register as a "GUEST" and someone from management will be happy to help you with your luggage...
The clerk dissappears into the back room. No amount of bell ringing will bring him back so you decide to leave...
Click.
---
"Welcome to 'zee Hotel" the clerk says. "Hopsing will take your baggage, not to worry. In the main lobby you will find a comprehensive directory of our services. Since you are a Valued Guest, all services are free of charge! You also have a listing in your room, if you are weary. The hotel manager is at your service. Press the 'C' button at the elevator and you will belifted to his suite! If he is not there, just leave him a message. He will have Hopsing hand deliver it to your door" finished the clerk. {whew!}
"It is encouraged that you talk with other guests and staff so that we all may be to know each other better," starts the clerk again, "therefore making your visit more enjoyable! There are many activities to choose from, and the conversations run from docile to very lively! If you ever need me, just press the 'H' button at any elevator and I will assist you in any way. Thank you for checking into Delta Hotel..." stops the clerk.
---
We hope you have enjoyed your stay at Delta Hotel. If you care to, leave\ comments to the manager!\ \ [Y)es - I gotta run! I have to catch a plane and BOY are my arms gonna\ be tired!\ [N)o - I left something in the room! I'll be back shortly...\ [F)eedback - Leave word with the hotel manager.\ [O)ptional - Express sympathy to Hopsing {he never gets mail}...\
---
Thank you for sleeping with us! Tell your friends! Tell your neighbors! Tell your Uncle Fred in Idaho! The Delta Hotel is open 24 hours a day to serve you, so feel free to drop by any time. Hopsing has loaded your baggage and you are all set to go...
{And bring back those two towels in your suitcase when you return, eh?}
(Hotel Delta script/ideas by Osiris)
Click.
From the way these are numbered, there was at least one more theme but the files were not with the others (odd, that).
Meanwhile, in Iowa…
In 1995, I moved to Iowa. I put my BBS online here, with a set of new themes:
DeltaBoard – “Online in Iowa since last week!”
Star Dreck – The Lost Generation
Castle Delta – with a new look
Hotel Delta
Haunted Mansion – Disney, eh?
Phone # – just showed the phone number, and seemed to have snarky menus
Al’s Den of Iniquity – “Beware: No Furniture”
I had forgotten about most of these. I’ll have to share those sometime. And a few more I have also found (or at least partially found).
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.
Juan Castro strikes again, this time providing a short program for me to try on a CoCo 3 (I used the Xroar Online emulator) that shows another quirk in the handling of 16-bit values on the CoCo.
The reason this requires a CoCo 3 is because it makes use of the ONERR GOTO command that was added for Super Extended Color BASIC.
“Goes to the line number if an error occurs during program execution.”
There are two special variables that get set when an error is trapped by “ON ERR”.
ERNO
“Returns an error number that corresponds to the error that occurred.”
ERLIN
“Returns the line number where the error occurred.”
So in this simple program, with a mis-spelled “PRINT” command…
10 ON ERR GOTO 50000 20 PRUNT "I TYPE POORLY" 30 END 50000 PRINT "ERROR";ERNO;"IN LINE";ERLIN
When I run that, I see:
ERROR 1 IN LINE 20
1 must be the value of ?SN ERROR. The manual says to look for “BASIC Error Messages” in the back of this book, but the page is titled ERROR CODES. It is on page 321. It lists errors 1 to 39.
But that is not important for this post.
ERLIN, which you see reported the error was in line 20, has a problem.
If the line number with the error has the high bit set (higher than 32767), it gets reported as a negative number! Changing the program to make the PRUNT typo happen on a later line shows this:
10 ON ERR GOTO 50000 32768 PRUNT "I TYPE POORLY" 32769 END 50000 PRINT "ERROR";ERNO;"IN LINE";ERLIN
If I run this version, I see:
ERROR 1 IN LINE-32768
If the error line is moved to 32767, you will it it report properly.
The book Super Extended BASIC Unraveled II mentions this bug on page 33:
“The ERLIN function will return a negative number if the line number in which the error occurred is greater than 32767. This is caused by the fact that the ERLIN function returns the line number as a two-byte integer instead of a floating point number, as it should.”
– Super Extended BASIC Unraveled II, page 33
I did not know there was a 2-byte integer routine in the ROMs. Always learning something new! (Or, re-learning in case I actually did learn this decades ago.)
Thanks, Juan, for getting my dusty brain thinking.
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?