Category Archives: Uncategorized

I cannot recommend FASTMAIL.com

In 1995, I signed up with an e-mail forwarding service called pobox.com. They would give you e-mail aliases that would then forward to whatever real e-mail account you were using at the time. The basic plan came with three aliases, and at one point I was using six. Super convienient!

They also added the ability to use those aliases to redirect to a webpage. Back then, your web address might be something long like www.geocities.com/SiliconValley/1842 (my original home page at GeoPages) or be something with a “~” in it like http://www.mcs.net/~werner/yester.html (the original location of www.yesterland.com before it had a domain). Pobox allows aliasing those so users only had to know www.pobox.com/~disneyparks and it would redirect to whatever service I was using to host my theme park photos at the time. Super convenient!

Over the years, my e-mail has moved from service to service to service, yet I never had to change any e-mail addresses with any services, or notify any of my contacts about a new address. They just used the same e-mail address I had since 1995. Super convenient!

But in 2015, Fastmail acquired Pobox.com:

https://en.wikipedia.org/wiki/Fastmail

The way they handle spam filtering is much worse (no e-mail summary, no one-click way to look at items in a web page and release/white list them, etc.). E-mails from my Softaculus (WordPress) service ALWAYS get spam filtered and they have been unable to fix this. E-mails I send to folks bounce back at the Fastmail level due to reasons I haven’t figured out. It’s a mess.

So, while I told everyone about how great POBOX.COM was for 30 years… I cannot recommend FASTMAIL.COM

But they own the e-mail I have had since 1995 so I guess I am sticking with them. At least for now…

My Sandisk Extreme USB-C drive keeps ejecting itself…

I have a 2TB Sandisk Exterme USB-C drive:

https://www.bestbuy.com/product/sandisk-extreme-portable-2tb-external-usb-c-nvme-ssd-black/JXJ62C9ZSV

Though, when I bought it, it was significantly cheaper than today’s price.

For “some time now” (many months) I have been seeing this popup on my computer:

Sandisk ejection notice.

Until recently, I had assumed Apple changed something and when I “eject” and the icon disappears from the desktop it really was not ejected yet. Perhaps some background cleanup was being done that didn’t use to happen. I would then eject using Disk Utility instead, and wait for the item to become grey, indicating fully un-mounted.

However, now that I am watching for this, I will see multiple alerts like this piled up in my Notification Center in the morning. This one, for example, was after I cleared all my notifications yesterday. I have not touched the drive or intentionally ejected it. Meanwhile, the four other drives plugged up are behaving fine.

And this drive is plugged directly into my computer versus the others going into a Caldigit TS3 thunderbolt dock. I would have expected more issues from going though a dock than connecting directly.

I am posting this to get it into the search engines. Anyone else ran into this?

BASIC INSTR revisited with special guest C strstr

In a recent post about BASIC INSTR, a few comments were left trying to clarify or justify or explain the behavior of why “” is reported as matching the first character in the search string.

PRINT INSTR("ABC","A")
1

PRINT INSTR("ABC","C")
3

PRINT INSTR("ABC","X")
0

PRINT INSTR("ABC","")
1

Copilot AI at least pretends to know the actual reason, which involves saving a few precious bytes in the early 4K Microsoft ROM. The behavior was then retained for backwards compatibility as Microsoft BASIC expanded. Copilot even reports the behavior continued into VB.NET, though I did not fact check this answer.

LuisCOCO commented:

This is logical, if you search for three letters it searches for that piece but when searching for nothing it starts in the first position and searches for zero characters in the destination since it is useless to search for more letters if you search for fewer letters, that brings a null string as the first data found and compares it with the null to search and gives true

– LuisCOCO

Indeed, without a check for an empty string, the search would stop there. “Compare an X byte string to a Y byte string”. As the scan is performed, I suspect the moment a character does not match, it sets the return value to 0. Without looking at the code (yet), my assumption is that it starts with 1 as the return value and just exits when no more bytes are available to compare (immediately with a zero byte target string) leaving the 1 there. Since code exists to flag it with a zero if it a mismatch is encountered, perhaps they did just want to save a few instructions rather than doing a check then branch to that zero return.

Unless there truly is an intentional reason it works this way.

William “Lost Wizard” Astle, who wrote the 6809 assembly (LWasm) I use quite often, explained some math stuff:

Put another way, the empty string is self-evidently a valid substring of every string at every position within that string so it will naturally match the position where the search starts. This is also mathematically correct when you look at set theory. The null set is a subset of all sets.

– William Astle

It seems math folks are fine with how INSTR works. Though math set theory is not where my mind would have been as a child learning BASIC back in junior high school.

William Astle then sends me on a side quest with this comment…

Incidentally, strstr() in C does exactly the same thing with an empty target string.

– William Astle

Let me C what I can find…

strstr() works similarly to BASIC’s INSTR, except it returns a pointer to where the match was found in memory. If no match was found, it returns a NULL pointer (which is 0, matching INSTR).

const char * strstr ( const char * str1, const char * str2 );

BASIC gives back a base-1 index, so 1 for a match at the first character of the search string, or 5 for a match starting at the 5th character of the search string. Strings in MS BASIC used “normal” base-1 counting numbers for the index. If you use MID$(), LEFT$(), RIGHT$() and similar string functions, they all use 1 for the first character in a string.

C uses base-0 for indexes, so if you have a string in C:

char *st = "ABC";

…the first character would be index 0, st[0], while in BASIC:

ST$="ABC"

…the first character would be index 1, MID$(ST$,1,1).

strstr

A quick test program to confirm…

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (int argc, char **argv)
{
char *search = "ABC";
char *target = NULL;
char *ptr = NULL;

// const char * strstr ( const char * str1, const char * str2 );
// A pointer to the first occurrence in str1 of the entire sequence of
// characters specified in str2, or a null pointer if the sequence is
// not present in str1.

printf ("search = '%s' (%p)\n", search, search);

target = "A";
ptr = strstr (search, target);
if (NULL == ptr)
{
printf ("target '%s' not found in '%s'\n", target, search);
}
else
{
printf ("target '%s' found in '%s' at index %d\n", target, search,
(ptr - search));
}

target = "C";
ptr = strstr (search, target);
if (NULL == ptr)
{
printf ("target '%s' not found in '%s'\n", target, search);
}
else
{
printf ("target '%s' found in '%s' at index %d\n", target, search,
(ptr - search));
}

target = "X";
ptr = strstr (search, target);
if (NULL == ptr)
{
printf ("target '%s' not found in '%s'\n", target, search);
}
else
{
printf ("target '%s' found in '%s' at index %d\n", target, search,
(ptr - search));
}

target = "";
ptr = strstr (search, target);
if (NULL == ptr)
{
printf ("target '%s' not found in '%s'\n", target, search);
}
else
{
printf ("target '%s' found in '%s' at index %d\n", target, search,
(ptr - search));
}

return EXIT_SUCCESS;
}

Yuck. I should have made a function… This produces:

search = 'ABC' (0x58a8ed9ba008)
target 'A' found in 'ABC' at index 0
target 'C' found in 'ABC' at index 2
target 'X' not found in 'ABC'
target '' found in 'ABC' at index 0

I realize my example is … not optimal. strstr() is returning a pointer to memory, and my example is subtracting the pointer where the target string was found from the pointer where the search string is. If they are the same, the math is 0 for the first character. But if the function actually returns a 0 (NULL), that means it was not found. I should have considered that before writing this example ;-)

But I digress…

Which came first?

A quick (and non fact-checked) web search about when strstr was added to C reveals:

The strstr function was added to the C standard library as part of the ANSI C standard (C89/C90), which was approved in 1989 and published in 1990.

Well, at least it worked the same way BASIC programmers would have been used to. But I do wonder if there was an earlier implementation of BASIC that introduced INSTR, or similar.

Another quick (and non fact-checked) web search says DEC BASIC-PLUS for the PDP-11 had a similar function and was introduced in 1970.

If I can figure out how to use the PDP-11 online emulator, maybe I can figure this out:

https://www.pcjs.org/software/dec/pdp11/tapes/basic

But here is the manual, which specifically documents this behavior:

The next-to-last entry:

“If only the substring is null, and if int-exp is equal to zero, INSTR returns a value of 1.”

https://www.dmv.net/dec/pdf/bp2v27rm.pdf

Though, that manual has a copyright of 1987 and 1991, so… maybe not quite where it started.

I found one from 1975:

https://www.bitsavers.org/pdf/dec/pdp11/rsts_e/V06/DEC-11-ORBPB-A-D_BASIC-PLUS_LangMan_Jul75.pdf

“If B$ is a null string (B$ = “”), the INSTR functions returns the value 1. The null string is a proper substring of any string and is treated conventionally as the first element of A$ in null string search operations. In addition, if both A$ and B$ and null strings, the INSTR function returns the value of 1″

https://www.bitsavers.org/pdf/dec/pdp11/rsts_e/V06/DEC-11-ORBPB-A-D_BASIC-PLUS_LangMan_Jul75.pdf

The 1970 manual does not show INSTR in the index:

http://bitsavers.trailing-edge.com/pdf/dec/pdp11/lang/basic/basic_pts/DEC-11-AJPB-D_PDP-11_BASIC_Programming_Manual_Dec70.pdf

But Google AI tells me it was in a 1971 edition:

http://ftpmirror.your.org/pub/misc/bitsavers/pdf/dec/pdp11/rsts/PL-11-71-01-01-A-D_RSTS-11UsersGuide_May71.pdf

In that 1971 manual, I found this:

http://ftpmirror.your.org/pub/misc/bitsavers/pdf/dec/pdp11/rsts/PL-11-71-01-01-A-D_RSTS-11UsersGuide_May71.pdf

Unfortunately, the 1971 manual does not specifically address what happens with a null/empty string, but we can for sure say it was definitively documented to do that in the 1975 manual, and without any mention to it being a change from the earlier releases, likely was there in 1971.

I think we have a winner. As described, it is clear the intent matches William Astle‘s comment about null being a proper substring of any string. Microsoft implemented it the way it

Conclusion

I guess all I have to say is that I’d have preferred is for INSTR to return 0 if an empty string was passed in.

Unless someone can tell me the benefit of having it return 1, that is. I am a big fan of changing my own personal views when I learn new information. Just ask me about politics sometime. . . #independent

Vaughn Cato’s “Toast” 3-D maze engine for CoCo OS-9 Level 2

Wayback in the 1990s, Vaughn Cato and I were corresponding, and somehow some topics came up about rendering a 3-D maze on the CoCo.

Vaughn wrote a demo which was called toast for reasons I no longer remember. It parsed a text file representing the maze, and would let you “walk” through it using the arrow keys. The code was written in C (though there may be some assembly helper routines in there, I haven’t checked) for the Radio Shack Color Computer 3 under the OS-9 operating system.

Here is a quick demo of what toast looked like:

Here is the maze data file:

18 16
# ##########
# #
# #
########### #
# #
# #
# #
# #
# #
# #
##### ######
# #
# #
# #
# #
############

The readme included with this version had the following notes:

Here is the latest version of the maze program.  I think that it now
always displays the walls correctly, but let me know if you find a problem.

I have also included a demo of the bitmap scaling routine. Just run
mapgraph to try it out.

Until Later,
Vaughn Cato ([deleted]@st6000.sct.edu)

I will share what mapgraph does in a future post ;-)

I plan to reach out to Vaughn and ask if he would be okay with sharing the source code for this.

Until then…

Klystronics at the 1994 Atlanta CoCoFest – revealed

At the 1994 Atlanta CoCoFest, the following vendors were present:

Booth 20 was unoccupied, as the vendor did not make it. They did leave a stack of flyers explaining their absence. You can read the text of that flyer in the previous post.

Who was Klystronics? Beyond those that knew about it in 1994, the backstory was explained in my CoCoFest Chronicles book which you can download for free at the Color Computer archive.

First, my fest report text file (included in the book) alluded to it in the opening:

NOTE: Any discrepancies between what is contained in this report and what is real is merely coincidental. This includes, but is not limited to, names, locations, events, and inside jokes (like klystrons).

– Allen Huffman’s 1994 Atlanta CoCoFest report text file

That report also mentioned the booth:

Klystronics — Another new vendor. This group was offering a large supply of “gently used” klystrons, complete with manuals. The minimal water damage their inventory had didn’t seem to effect operation, though the yellow discoloration made them no longer match the CoCo’s case.

– Allen Huffman’s 1994 Atlanta CoCoFest report text file

…but the full backstory was not explained until the book itself came out a few years later. From the book:


MORE BEHIND THE SCENES

The Story About Klystronics

One of the more interesting tales I get to tale is that of the “mysterious” vendor, Klystronics. They were listed in the Fest booklet, and even had a table which was empty except for some flyers and an empty business card holder. To the casual observer (i.e. someone who fell for it) it would appear they just didn’t make it to the show. To the less casual observer, one might have found some of the information on the flyer a bit curious.

Klystronics was a practical joke played for the benefit of one individual, Nick Johnson. At the time, Nick was hanging out on the GEnie online service (thanks to its then-outstanding Star*Services which offered unlimited non-prime access for about five dollars per month). Nick had a macro he would use far too often while in chat sessions which said “PLEASE DO NOT URINATE ON THE KLYSTRON.” Terry Todd and myself found this quite annoying.

At some point, our friend Bob Rutherford got together with us and we came up with the idea of Klystronics. Once the name was created, the joke fell into place. We acquired a booth, printed flyers (using a font I had never used for any Sub-Etha literature), and purchased a business card holder.

At the show, Nick wandered over and said “hey, did you guys know there is a company here called Klystronics?” or something to that effect. We held in laughter. He most likely was suspicious but if so he played along pretty well. The flyer had some meaningless babble about CoCo compatible Klystrons, but embedded in the words were numbers enclosed in brackets. If you put the letter next to the numbers together in numerical order you would decode the hidden message which basically clued one in to the fact that this was just a joke. At first Nick suspected something far more clever for the origin of the numbers, but towards the end of the show I do believe he figured it out. I am not quite sure if we ever told him officially that it really was us.

A few others were in on this joke, most notable Colin McKay. After the Fest, Colin played up the existence of Klystronics on the internet CoCo mailing list after someone wondered just who they were. Even Mike Knudsen chimed in observing that certainly they had nothing to do with the “klystron” tubes he was familiar with! He certainly was right. I have in my possession (thanks to Mike’s archives) a copy of the Klystronics message thread and I must say — it really makes me proud seeing how well this went over.

The following Fest, we planned to do more including having Bob Rutherford build a rather amazing device to attach to a CoCo. We never quire followed through, but Klystronics lived on in my Fest report — even though there was no booth nor mention of them in the official Fest booklet.

And now you know … the rest of the story. Maybe the comment about “water damage” will make a bit more sense.

Or, more likely, it will not.


I decided to post the original Kystronics flyer text on April 1, 2026. This was more involved than I expected. First, the raw text file seemed to use some embedded formatting codes. I could not remember what created them:

.pl1
.lm0
.ll137
.nf

This led me to trying to figure out how to export the document in a formatted version to match what I did back in 1994. I was using the text editor VED under OS-9 at the time, and suspected maybe I was using the companion VPT text formatted. After figuring out how to run it off my old OS-9 hard drive image in an emulator, I learned it did not like these codes.

Eventually, I just decided to feed it into A.I. (Copilot) and let it do it for me. It presented me with an ASCII version of document, correctly figuring out what codes mean blank lines, and what codes meant centered lines. BUT, it was 137 columns wide.

What? That wouldn’t even fit if I printed in landscape mode, which wasn’t even a thing on that printer back then.

A bit more research revealed I likely printed this on my Tandy DMP-132 printer in condensed mode, which would indeed allow 137 characters per line with a bit of margin on each side.

This led me to just simulating it by using a condensed dot matrix font and turning the text into a PDF.

That’s close-ish.

Some things seem obvious now…

As I pointed out, I tried to use a font Sub-Etha Software didn’t use for printing flyers, and change things up so it was not immediately obvious I created this. For instance, it spells “disc” with a C and I never did that. It also uses “Coco” without the second C capitalized. But, as I look at it now, I see a few things that would have tipped folks off.

  • First, back then, I typed DOS as “Dos” as if it was a word. So did Klystronics. (And other folks of that era, but still, a hint.)
  • Also, “S.E.S.” Dos and “B.H.” Dos? I’ve never heard of any RS-DOS replacements with those initials, but there were two companies at the fest that had matching initials.
  • I also misspelled separately the same way I’d be misspelling it today if it wasn’t for auto-correct. And so did Klystronics. My Fest reports were full of that misspelling as well as mixing of where/were.
  • Bored member? “lol”. That misspelling was intentional.

The document also has some things that could further tip off the joke.

  • 16K RAM, but also supporting the Hi-Res Joystick Interface? Seems unlikely.
  • Color Computer 2 but NOT Color Computer 1? Why would that be?
  • Also, the name “Graham Cain” alluded to the two individuals behind it. One may be obvious, the other not at all.

But … the biggest tip was that there is also an encoded message hidden in this document. Look at the full text and see if you can decode it. That was the actual reveal.

Until next time…

Klystronics at the 1994 Atlanta CoCoFest

Fine Klystrones Since 1989

HELLO! We are[14] sorry that we were unable to personally attend this[1] year’s CocoFest. We had some commercial accounts we needed to attend to and thus were unavailable. We hope to see you[9] next year at the 1995 Chicago CocoFest or at the upcoming Klystrone Con[4] ’95 in Aneheim.

WHAT IS KLYSTRONICS?

Klystronics, Inc. is an independent organization dealing in the sale and service of both new and used Klystrones.

WHAT IS A KLYSTRONE?

Klystronics, Inc. is an independent organization dealing in the sale and service of both new and used Klystrones.

WHY IS KLYSTRONICS AT A COCOFEST?

One of our[11] bored members, Graham Cain, got his start in the electronics field with a[3] TRS-80 Color Computer which was part of an in-home study course. His projects led him into P.C. interfacing and, along with other business partners, the formation of Klystronics in 1989. Most of the projects were industrial in nature and involved the usage of Klystrone units with commercial grade P.C. components, but Graham, remembering his roots with the Coco, used his knowledge and spare time to create a Coco Klystrone interface. Thus, Klystronics offers it’s services to both industrial users and Color Computer users.

HOW CAN I ORDER A KLYSTRONE FROM KLYSTRONICS?

Since we are[6] unable to take orders personally, you[13] can mail in your order or use our toll free 1-800 telephone ordering service. We accept personal and business checks, credit cards (Visa, MasterCard, Diner’s Club, Discover[10]), money orders, international postage, and C.O.D.s.

KLYSTRONE SYSTEM REQUIREMENTS:

o Color Computer 2 or 3
o Y-Cable of Multi-Pak Interface
o Cassette Cable (if[8] sound desired)
o Floppy Disc Drive (S.E.S./B.H.[5] Dos)

o 16K of R.A.M. or greater
o Hi-Res Joystick Interface
o Color Monitor recommended
o OS-9 Drivers Sold Seperately

TECHNICAL SUPPORT FOR KLYSTRONE QUESTIONS:

Support is[2] provided 24 hours a day via long distance phone calls, or use our free computer bulletin board service (300-1200 baud). We may also be contacted via Prodigy, though response time may be slow. We are not responsible[7] if the message[12] is lost.

CONTACT

Please use the latest address and phone information as listed on our business cards.

FEST SPECIAL[15]!!!!! USED KLYSTRONES (SLIGHT WATER DAMAGE) 37% OFF!!!!!

Hacking the Color BASIC PRINT command – part 6

See Also: part 1, part 2, part 3, part 4, part 5, part 6 and part 7 (and maybe more to come…)

In part 5, I presented an update to the “PRINT can move the cursor” hack which would turn that off when you were typing from outside a running program. It did this by checking a Color BASIC “variable” that contained the current line being processed. When the program is not running, that value is set to 65535 (&HFFFF in hex). My simple check should have been enough to skip processing the special characters when in this direct mode:

* Do this only if NOT in Direct mode. Problem: After a BREAK, CURLIN
* has not been updated yet, so the very first line you type will be
* processing the special characters. Lines after that will not. Trying
* to find a different way to detect this.
pshs a save A
lda CURLIN GET CURRENT LINE NUMBER (CURLIN)
inca TEST FOR DIRECT MODE
puls a restore A
beq continue if 0, in direct mode.

I quickly learned that when a program stops running, this value is not updated to &HFFFF until AFTER the next line is entered. This snippet is from the Github archive of tomctomc:

https://github.com/tomctomc/coco_roms/blob/master/bas.asm

; THIS IS THE MAIN LOOP OF BASIC WHEN IN DIRECT MODE
LAC73 JSR >LB95C ; MOVE CURSOR TO START OF LINE
LAC76 LDX #LABEE-1 ; POINT X TO OK, CR MESSAGE
JSR >LB99C ; PRINT OK, CR
LAC7C JSR >LA390 ; GO GET AN INPUT LINE
LDU #$FFFF ; THE LINE NUMBER FOR DIRECT MODE IS $FFFF
STU CURLIN ; SAVE IT IN CURLIN

BASIC does not update the value until after the first line is entered, which means my attempt to ignore cursor movements when typing would not work for the first line you typed after a program stopped (BREAK, END, STOP, ?SN ERROR, etc.).

William “Lost Wizard” Astle pointed me to another vector I could use to determine when a program stopped running: RVEC12. This is called the “line input” routine, which confused me at first since LINE INPUT did not exist until Extended Color BASIC ROMs were added. But, the naming intent appears to just be “input a line” versus “for the LINE INPUT command”.

It looks like this (again, from the tomctomc disassembly):

; THIS IS THE ROUTINE THAT GETS AN INPUT LINE FOR BASIC
; EXIT WITH BREAK KEY: CARRY = 1
; EXIT WITH ENTER KEY: CARRY = 0
LA38D JSR >CLRSCRN ; CLEAR SCREEN
LA390 JSR >RVEC12 ; HOOK INTO RAM
CLR IKEYIM ; RESET BREAK CHECK KEY TEMP KEY STORAGE
LDX #LINBUF+1 ; INPUT LINE BUFFER
LDB #1 ; ACCB CHAR COUNTER: SET TO 1 TO ALLOW A
; BACKSPACE AS FIRST CHARACTER
LA39A JSR >LA171 ; GO GET A CHARACTER FROM CONSOLE IN

The code at LA390 is called when BASIC wants to input a line. That code jumps out to a RAM hook RVEC12 so that code could run anything it needed to first, such as new code that changes CURLIN to FFFF right then.

I added a new bit of code to my program to save whatever is in RVEC12, then make it point to my new code:

* Hijack the BASIC line input routine.
lda RVEC12 get op code
sta savedrvec12 save it
ldx RVEC12+1 get address
stx savedrvec12+1 save it

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

Then, in my program, I added a “newcode2” routine:

* William Astle:
* "RVEC12 would be right. You can clobber X in this case. You would check 4,s
* to see if it's $AC7F. If it is, you just set CURLIN to $FFFF. This works
* around the unfortunate ordering of the instructions in the immediate mode
* loop."
newcode2
ldx 2,s get what called us
cmpx #$ac7f
bne continue2
ldx #$ffff
stx CURLIN

continue2
savedrvec12 rmb 3 call regular RAM hook
rts just in case...

The “lda 2,s” retrieves whatever is on the stack which would be the return address we go back to at an rts. (I think the 4 in William’s comment may be a typo; I checked there and did not get an address match, but I do at 2,s.)

AC7F is this bit in BASIC:

; THIS IS THE MAIN LOOP OF BASIC WHEN IN DIRECT MODE
LAC73 JSR >LB95C ; MOVE CURSOR TO START OF LINE
LAC76 LDX #LABEE-1 ; POINT X TO OK, CR MESSAGE
JSR >LB99C ; PRINT OK, CR
LAC7C JSR >LA390 ; GO GET AN INPUT LINE
LDU #$FFFF ; THE LINE NUMBER FOR DIRECT MODE IS $FFFF
STU CURLIN ; SAVE IT IN CURLIN
BCS LAC7C ; BRANCH IF LINE INPUT TERMINATED BY BREAK
TST CINBFL ; CHECK CONSOLE INPUT BUFFER STATUS

At label LAC7C is “jsr >LA390”. This does a jump subroutine to code that calls the RAM hook:

; THIS IS THE ROUTINE THAT GETS AN INPUT LINE FOR BASIC
; EXIT WITH BREAK KEY: CARRY = 1
; EXIT WITH ENTER KEY: CARRY = 0
LA38D JSR >CLRSCRN ; CLEAR SCREEN
LA390 JSR >RVEC12 ; HOOK INTO RAM
CLR IKEYIM ; RESET BREAK CHECK KEY TEMP KEY STORAGE
LDX #LINBUF+1 ; INPUT LINE BUFFER
LDB #1 ; ACCB CHAR COUNTER: SET TO 1 TO ALLOW A

My “newcode2” at RVEC12 looks like it should expect the rts value on the stack of be after LA390, which I think would be at “2,s” on the stack (?), making the “2,s” be the address that called LA390, matching William’s “4,s” to get to it. Not sure if I understand this, but that didn’t work so I did some debug code to put the stack values on the 32 column screen bytes and PEEKed them out to see what was there. That is how I found it at “2,s”.

But I digress… The point seems to be when I am running my code, IF I can tell it was called from this block:

LAC7C           JSR         >LA390          ; GO GET AN INPUT LINE
LDU #$FFFF ; THE LINE NUMBER FOR DIRECT MODE IS
STU CURLIN ; SAVE IT IN CURLIN

…then I know it is the correct spot where I can safely (?) store FFFF in CURLIN, then call whatever code was in the original RAM hook to do the actual line input (which is now running with FFFF in CURLIN). Then it returns from that and sets CURLIN to FFFF in the ROM (which has already been done by my newcode2).

This seems to work, but perhaps William can chime in and explain what I missed with my stack stuff.

Here is the new version of my program:

* lwasm consmove4.asm -fbasic -oconsmove4.bas --map

* Allow embedded characters to move the cursor in a PRINT.

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

CURLIN equ $68 *PV CURRENT LINE # OF BASIC PROGRAM, $FFFF = DIRECT
DEVNUM equ $6f device number being used for I/O
CURPOS equ $88 location of cursor position in RAM
RVEC3 equ $167 console out RAM hook
RVEC12 equ $182 inputting a BASIC line
VIDRAM equ $400 VIDEO DISPLAY AREA

org $7f00

init
* Hijack the CONOUT routine.
lda RVEC3 get op code
sta savedrvec save it
ldx RVEC3+1 get address
stx savedrvec+1 save it

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

* Hijack the BASIC line input routine.
lda RVEC12 get op code
sta savedrvec12 save it
ldx RVEC12+1 get address
stx savedrvec12+1 save it

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

rts done

uninstall
* TODO

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

* Do this only if NOT in Direct mode. Problem: After a BREAK, CURLIN
* has not been updated yet, so the very first line you type will be
* processing the special characters. Lines after that will not. Trying
* to find a different way to detect this.
pshs a save A
lda CURLIN GET CURRENT LINE NUMBER (CURLIN)
inca TEST FOR DIRECT MODE
puls a restore A
beq continue if 0, in direct mode.

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

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

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

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

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

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

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

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

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


* William Astle:
* "RVEC12 would be right. You can clobber X in this case. You would check 4,s
* to see if it's $AC7F. If it is, you just set CURLIN to $FFFF. This works
* around the unfortunate ordering of the instructions in the immediate mode
* loop."
newcode2
ldx 2,s get what called us
cmpx #$ac7f
bne continue2
ldx #$ffff
stx CURLIN

continue2
savedrvec12 rmb 3 call regular RAM hook
rts just in case...

end

And this now lets me hit BREAK (or whatever) in my program and then type those “u”, “d”, “l” and “r” characters and see them as lowercase as I type them:

But there are still issues…

But there are still issues. One thing I did not consider is that now I cannot “test” an embedded PRINT from the command line. Typing this:

PRINT "XXXlllYYY";

…should print “XXX” then move left three times and print “YYY” so it only shows YYY. But with the PRINT hack not displaying cursor moves in direct mode, you just get:

So, depending on your preference, you may want to NOT have this extra code active so you just see cursor movements even when you are typing in the program.

Thoughts? Let me know in the comments.

Here is the current BASIC loader:

5 CLEAR 200,&H7F00
10 READ A,B
20 IF A=-1 THEN 70
30 FOR C = A TO B
40 READ D:POKE C,D
50 NEXT C
60 GOTO 10
70 END
80 DATA 32512,32639,182,1,103,183,127,128,190,1,104,191,127,129,134,126,183,1,103,142,127,47,191,1,104,182,1,130,183,127,144,190,1,131,191,127,145,134,126,183,1,130,142,127,132,191,1,131,57,13,111,38,77,52,2,150,104,76,53,2,39,68,50,98,52,22
90 DATA 158,136,129,117,38,10,140,4,32,45,50,48,136,224,32,43,129,100,38,10,140,5,224,44,36,48,136,32,32,29,129,108,38,9,140,4,0,39,22,48,31,32,16,129,114,38,9,140,5,255,39,9,48,1,32,3,126,163,14,159,136,126,163,93,32643,32655,57,174,98,140,172
100 DATA 127,38,5,142,255,255,159,104,32659,32659,57,-1,-1

I added the CLEAR 200,&H7F00 at the top. Just load this, RUN it, then EXEC &H7F00 and then you have the new PRINT stuff with cursor movements.

What next? I’d like to add the ability to assign which characters it uses by making the routine work with DEF USR so you could do something like:

X=USR0("udlr")

Then you could pass in whatever four characters you wanted for the cursor movements. Maybe this could also be used to disable it with something like X=USR0(“”) that did not specify anything to use.

Again, thoughts?

Until next time…

UnderColor’s spiral challenge from 1984 – part 1

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

And now back to CoCo …

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

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

– Michael Pittsley

This caught my attention.

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

Search – TRS-80 Color Computer Archive

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

UNDERCOLOR Vol1 No 1 Dec 10, 1984

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

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

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

So now let’s spiral like this.

LINE versus DRAW

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

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

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

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

LINE-(127,0),PSET

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

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

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

DRAW"BM0,191"

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

You can then do things like…

DRAW"R10"

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

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

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

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

X=100
DRAW"R=X;"

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

Could this be faster than line?

Here is what I came up with:

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

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

Here is what I get:

And pressing a key shows me:

3.03333334

Three seconds.

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

Let’s play!

A life changing letter…

In 1995, I sent this cover letter out with my resume. I managed to get the job, and that forever changed the direction of my career…


Allen C. Huffman
110 Champions Dr. #XXX
Lufkin, TX 75901

Microware Systems Corp.
1900 N.W. 114th St.
Des Moines, IA 50325-7077
Attn: Human Resources

May 7th, 1995

Dear Sir;

I am writing in regards to your Technical Training Engineer position. After learning of it’s availability I immediately wanted to express my interest. I possess a working knowledge of OS-9 which comes from daily use over the past six years and I believe this would be beneficial to your company.

I have programmed under OS-9 Level Two and OS-9/68K with several commercially marketed utilities and applications available. My creations include a sound driver, machine language space game, menu driven user interface library, and various file and printer utilities. Since 1990 I have owned and operated a company which creates and markets OS-9 products. I regularly attend annual conventions as a vendor and also give seminars dealing with OS-9 support and programming.

I have an active interest in Microware’s past, present and future and attempt to follow media coverage of developments such as the use of DAVID in set-top converters and OS-9 in places like Treasure Island in Las Vegas.

I am eager to provide further information about myself and my accomplishments either through an interview or additional correspondence. Feel free to contact me by mail, by telephone at (409) 637-XXXX, or by the internet at “coco-sysop@genie.geis.com”. Thank you for your consideration and I look forward to hearing from you.

Sincerely,

Allen C. Huffman


Almost exactly one month later, I received this e-mail:


INET00# Document Id: UX012.BUX0687704
Item 7490898 95/06/05 04:15
From: XXX@MICROWARE.COM@INET00# Internet Gateway
To: COCO-SYSOP Allen C. Huffman
Sub: Technical Training Engineer

Dear Allen,

I would like to discuss the technical training position Microware has open
with you on the telephone. Please call me at Microware, (515) 224-1929 at
your convenience, or email me a time I can reach you.

Sincerely,

XXX
Manager, Technical Training

=END=


It was (and still is) pretty amazing to me that a kid (well, early 20s) who had mostly worked retail was given a shot like this. And all because I went with a CoCo instead of a Commodore 64… Though, who knows, maybe I would have ended up working for Commodore in that universe…

Until next time…