Category Archives: Uncategorized

Crashing with VR360 video in Final Cut Pro on macOS 26

Updates:

  • 2026-06-11 – I have an active support ticket with Apple and it has been escalated to engineering. They requested me send them a generic (none of my content) project that crashes as well as diagnostic logs. I was able to create a brand new Library and then a new 360 project then add things to it — a few titles, some FCP sound effects, a Generator item and a background, and even that crashes. I also did a short project that was non-360 and had no issues with that. Let’s hope they can figure this out!

I am posting this to get this into the search engines. I am hoping to hear from others that have had this same issue, and might have a solution.

I recorded 360 video (7680×3840) using Insta360 X5 and a DJI Osmo 360 cameras. I export the 360 video out to a flat video file using Insta360 Studio or DJI Studio desktop apps. I then bring this in to Final Cut Pro for editing. I have been doing this for years with no problems.

A few months ago, I went to make a new video. I found my project, that worked fine last year, now crashes Final Cut Pro. Sometimes it crashes on opening the project, sometimes when clicking around, sometimes it works for 15 minutes then crashes when I click on a view icon, etc. Very random.

I tried making brand new empty projects and recreating my template manually. Still crashes.

I eventually reset my macOS and then restored from a Time Machine backup. Even this “clean” reinstall still crashed.

I spent an hour or so on with Apple Support and we never figured out what was causing it, but we could even make it crash using only template items built in to Final Cut Pro — none of my graphics, video, or audio files.

The next test was to install a fresh copy of macOS with nothing else on it. I logged in to my Apple Store account and downloaded Final Cut Pro — the only app on this install of macOS.

And I can still get that to crash.

It looks like some bug with 360 video and the current Final Cut Pro, or some issue with the current macOS version.

Anyone encountered 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…

C has its limits. If you know where to look.

Thank you, Bing Copilot (ChatGPT), for giving me another “thing I just learned” to blog about.

In the early days of “K&R C”, things were quite a bit different. C was not nearly as portable as it is today. While the ANSI-C standard helped quite a bit, once it became a standard, there were still issues when moving C code from machines of different architectures — for example:

int x;

What is x? According to the C standard, and “int” is “at least 16 bits.” On my Radio Shack Color Computer, and int was 16-bits (0-65535). I expect on my friend’s Commodore Amiga, the int was 32-bits, though I really don’t know. And even when you “know”, assuming that to be the case is a “bad thing.”

I used a K&R C compiler on my CoCo, and later on my 68000-based MM/1 computer. That is when I became aware that an “int” was different. Code that worked on my CoCo would port fine to the MM/1, since it was written assuming an int was 16-bits. But trying to port anything from the MM/1 to the CoCo was problematic if the code had assumed an int was 32-bits.

When I got a job at Microware in 1995, I saw my first ANSI-C compiler: Ultra C. To deal with “what size is an int” issues, Microware created their own header file, types.h, which included their definitions for variables of specific sizes:

u_int32 x;
int32 y;

All the OS library calls were prototyped to use these special types, though if you know an “unsigned long” was the same as an “u_int32” or a “short” was the same as an “int16” you could still use those.

But probably shouldn’t.

In those years, I saw other compilers do similar things, such as “U32 x;” and “I16 y”. I expect there were many variations of folks trying to solve this problem.

Some years later, I used the GCC compiler for the first time and learned that the ANSI-C specification now had it’s own types.h — called stdint.h. That gave us things like:

uint32_t x;
int32_t y;

It was easy to adopt these new standard definitions, and I have tried to use them ever since.

I was also introduced in to the defines that specified the largest value that would fit in an “int” or “long” on a system – limits.h:

...
#define CHAR_MAX 255 /*unsigned integer maximum*/
#define CHAR_MIN 0 /*unsigned integer minimum*/

/* signed int properties */
#define INT_MAX 32767 /* signed integer minimum*/
#define INT_MIN (-32767-_C2) /*signed integer maximum*/

/* signed long properties */
#define LONG_MAX 2147483647 /* signed long maximum*/
#define LONG_MIN (-2147483647-_C2) /* signed long minimum*/
...

The values would vary based on if your system was 16-bits, 32-bits or 64-bits. It allowed you to do this:

int x = INT_MAX;
unsigned int y = UINT_MAX;

…and have code that would compile on a 16-bit or 64-bit system. If you had tried something like this:

unsigned int y = 4294967295; // Max 32-bit value.

…that code would NOT work as expected when compiled on a 16-bit system (like my old CoCo, or an Arduino UNO or the PIC24 processors I use at work).

I learned to use limits.h.

But this week, I was working on code that needed to find the highest and lowest values in a 32-bit number range. I had code like this:

uint32_t EarliestSequenceNumber = 4294967295;
uint32_t LatestSequenceNumber = 0;

And that works fine, and should work fine on any system where an int can hold a 32-bit value. (Though I used hex, since I know 0xffffffff is the max value, and always have to look up or use a calculator to find out the decimal version.)

Had I been using signed integers, I would be doing this:

int32_t LargestSignedInt = 2147483647;

Or I’d use 0x7fffffff.

As I looked at my code, I wondered if C provided similar defines for the stdint.h types.

stdint.h also has stdsizes!

And it does! Since all of this changed/happened after I already “learned” C, I never got the memo about new features being added. Inside stdint.h are also defines like this:

#define INT8_MAX  (127)
#define INT8_MIN (-128)
#define UINT8_MAX (255)

#define INT16_MAX (32767)
#define INT16_MIN (-32768)
#define UINT16_MAX (65535)

#define INT32_MAX (2147483647)
#define INT32_MIN (-2147483648)
#define UINT32_MAX (4294967295)

#define INT64_MAX (9223372036854775807)
#define INT64_MIN (-9223372036854775808)
#define UINT64_MAX (18446744073709551615)

…very similar to what limits.h offers for standard ints, etc. Neat!

Now modern code can do:

uint32_t EarliestSequenceNumber = UINT32_MAX;
uint32_t LatestSequenceNumber = 0;

…and that’s the new C thing I learned today.

And it may have even been there when I first learned about stdint.h and I just did not know.

And knowing is half the battle.