See also: part 1, part 2, part 3, part 4, part 5, part 6, part 7 and part 8.
UPDATE: After I wrote this up, Sean Connor replied on the CoCo mailing list about his extensive website article diving into how all the DEF USR stuff works. If you really want to know how this works, you should read his writeup. Unlike me, he actually seems to understand I! I am just playing around trying to make stuff work: https://boston.conman.org/2024/11/26.2-3
Also, he has summarized some things I missed (in this article) in a post so I will have to do a Part 8 to this article and tie everything together. Kudos to Sean Connor for figuring all this out and sharing it with all of us! Wish I had remembered he was the one who did this before I wrote all this up. BUT, I had fun, and I learned (including stuff that is wrong). To be continued…
Meanwhile, back in 2017 (!) I shared some posts about how to use DEF USR to call assembly language routines from Color BASIC. Today I present something new I learned, mostly thanks to folks like William “Lost Wizard” Astle pointing me in useful directions.
First, here is a refresher on calling assembly language from BASIC.
Method 1 – EXEC
You can load (or POKE) some assembly into memory at some address and run that code using the EXEC command. Even CoCo folks who don’t program assembly probably have used the EXEC command. It is used to start a machine language program you loaded from tape (using CLOADM) or disk (using LOADM). Those load commands set the EXEC address to be wherever the program loaded to run so you just type “EXEC” and go.
You can also specific a memory location after the EXEC command, such as “EXEC 40999”. That will execute whatever code is in memory at 40999. You may recognize that one, since 40999 is the address of the “reset” routine in Color BASIC. Typing “EXEC 40999” is like hitting the hardware RESET button on the back of the CoCo.
But I digress.
You could create a set of assembly routines that start at different locations in memory, then run those routines using EXEC and the address of the routine. This is cumbersome, since you have to know where each routine starts. For example, here are some stupid routines that change the screen color to red, green, or blue:
* lwasm cls.asm -fbasic -ocls.bas --map
* Test of EXEC
ORGADDR equ $3f00
VIDRAM equ $400 VIDEO DISPLAY AREA
org ORGADDR
clsred
lda #191 * Red block.
bsr clear
rts
clsgreen
lda #223 * Green block.
bsr clear
rts
clsblue
lda #175 * Blue block
bsr clear
rts
clear
ldx #VIDRAM * Top left of 32 column screen.
loop
sta ,x+ * Store at X and increment X.
cmpx #VIDRAM+512 * Compare X to bottom right of screen
bne loop
rts
end
This cheesy program has three routines at the start – clsred, clsgreen and clsblue. If I compile this and load it into memory, I could then EXEC the startling location of each of those routines to see the screen clear to those colors. But how do I know where they start?
One way is to use an assembler that tells you. I am using the Lost Wizard lwasm assembler. It has an option that shows the locations of stuff in the program. When I build, it shows me this output:
allenh@Mac asm % lwasm cls.asm -fbasic -ocls.bas --map
Symbol: clear (cls.bas) = 3F0F
Symbol: clsblue (cls.bas) = 3F0A
Symbol: clsgreen (cls.bas) = 3F05
Symbol: clsred (cls.bas) = 3F00
Symbol: loop (cls.bas) = 3F12
Symbol: ORGADDR (cls.bas) = 3F00
Symbol: VIDRAM (cls.bas) = 0400
This tells me I can EXEC &H3F00 to run the clsred code, EXEC &H3F05 to run clsgreen, and EXEC &H3F0A to run clsblue. To test, I use the compile option that generates a BASIC program that loads the code into memory using POKE commands. I built it and then loaded that .bas into the XRoar emulator to try it out, and it works. I’d show a screen shot, but since it clears the screen when I run it, it wouldn’t really show anything useful.
But the problem is any changes to the routines that alter their size can change the locations of any routines after them. If I made the first routine, clsred, five bytes longer than it is now, the addresses of the following routines clsgreen and clsblue would now be five bytes higher in memory.
I’d have to keep making notes of all the locations I wanted to use in my BASIC program and update the BASIC program each time things changed in the assembly code.
Yuck.
One solution to this problem is to make some entries at the top of the assembly code that will never change. They could just jump to the specific routines, and nothing else. For example:
* lwasm cls2.asm -fbasic -ocls2.bas --map
* Test of EXEC
ORGADDR equ $3f00
VIDRAM equ $400 VIDEO DISPLAY AREA
org ORGADDR
clsred bra clearred
clsgreen bra cleargreen
clsblue bra clearblue
clearred
lda #191 * Red block.
bsr clear
rts
cleargreen
lda #223 * Green block.
bsr clear
rts
clearblue
lda #175 * Blue block
bsr clear
rts
clear
ldx #VIDRAM * Top left of 32 column screen.
loop
sta ,x+ * Store at X and increment X.
cmpx #VIDRAM+512 * Compare X to bottom right of screen
bne loop
rts
end
I added some stuff at the top of the program that branch to the actual routines later in the code. Now the routines later in the code can grow, shrink, or move, but those initial branch instructions will not need to change:
lwasm cls.asm -fbasic -ocls.bas --map
Symbol: clear (cls.bas) = 3F0F
Symbol: clsblue (cls.bas) = 3F0A
Symbol: clsgreen (cls.bas) = 3F05
Symbol: clsred (cls.bas) = 3F00
Symbol: loop (cls.bas) = 3F12
Symbol: ORGADDR (cls.bas) = 3F00
Symbol: VIDRAM (cls.bas) = 0400
I suppose we would call this a “dispatch table.” This also has the advantage of being able to add new entries at the end as more routines are added. Only if you add something new would the BASIC program using it have to change:
clsred bra clearred
clsgreen bra cleargreen
clsblue bra clearblue
clswhite bra clearwhite
You could have a program with routines to clear the screen, or scroll the screen Up, Down, Left and Right (ah, a callback to the earlier parts of this article series) and use EXEC to get to each one.
NOTE: I used the “bra” branch op code, which can only “get to” nearby code. As the program grows, it may not be able to reach all the routines. Using “lbra” (long branch always) instead may be a better approach if your code might grow in the future.
EXEC might be enough to get the job done, but that is not what this series is about.
Method 2 – DEF USR

You can have up to ten (DEF USR0 to DEF USR9) assembly routines defined and call them using the USR command. You still have the same problem of needing to know where the functions are. If I wanted to use the three cls routines, I’d have something like:
DEF USR0=&H3F00
DEF USR1=&H3F05
DEF USR2=&H3F0A
…and then I could call them in the program using:
A=USR0(0) 'CLS RED
A=USR1(0) 'CLS GREEN
A=USR2(0) 'CLS BLUE
…but that really is not much better. The real use of DEF USR is that you can pass a parameter into the assembly language (the value in the parens) and return a value back to BASIC (the variable before the equal). Instead of needing separate routines to clear the screen, as mentioned earlier in this series, you could simple have one and pass in the parameter that tells it what to do:
A=USR0(1) '1=RED
A=USR0(2) '2=GREEN
A=USR0(3) '3=BLUE
…or whatever you want to do. Now you just have one DEF USR define and can run many different routines based on the number you pass in to it. One entry point (“DEF USR0=&H3F00”) could have dozens or hundreds of functions which run based on what number is passed in.
And now the reason for this new part…
In part 3 of this series I said this:
Unfortunately, the USRx() command only allows you to pass in a numeric value, and not a string, so we can’t simply do something like:
A$=USR0("Convert this to all uppercase.") 'THIS WILL NOT WORK!
So imagine my surprise when I saw — somewhere — someone post that you actually could do that. I have yet to track down where I saw this, but I stashed it in the back of my mind until I had time to revisit this subject.
And that time is now.
While this is true that Color BASIC cannot do this, Extended BASIC can indeed pass in a string. The code that parses the USR routine confirms this as it checks the variable type being a number or a string:
* PROCESS A USR CALL
L892C BSR L891C GET STORAGE LOC OF EXEC ADDRESS FOR USR N
LDX ,X * GET EXEC ADDRESS AND
PSHS X * PUSH IT ONTO STACK
JSR >LB262 SYNTAX CHECK FOR ‘(‘ & EVALUATE EXPR
LDX #FP0EXP POINT X TO FPA0
LDA VALTYP GET VARIABLE TYPE
BEQ L8943 BRANCH IF NUMERIC, STRING IF <> 0
JSR >LB657 GET LENGTH & ADDRESS OF STRING VARIABLE
LDX FPA0+2 GET POINTER TO STRING DESCRIPTOR
LDA VALTYP GET VARIABLE TYPE
L8943 RTS JUMP TO USR ROUTINE (PSHS X ABOVE)
That code snippet comes from the Toolshed repository on Github where you can find disassemblies of the CoCo ROMs:
https://github.com/n6il/toolshed/blob/master/cocoroms/extbas.asm
Many things once thought impossible start happening once people learn they are not actually impossible.
My mistake. It is possible.
All that is needed is to check the VARTYP at the start of your assembly routine. If it is numeric, you can call the INTCVT routine to convert the passed-in number to register D and use it like before. If it is a string, X will point to the VARPTR location of that string descriptor and you can parse it to get the length of the string and the location of the string data.
See this post about Color BASIC and VARPTR for an explanation
Here is my test code:
* lwasm defusr.asm -fbasic -odefusr.bas --map
* Test of DEF USR.
ORGADDR equ $3f00
VIDRAM equ $400 VIDEO DISPLAY AREA
CHROUT EQU $A002
INTCNV EQU $B3ED * 46061
GIVABF EQU $B4F4 * 46324
REGDOUT EQU $BDCC * convert the value in ACCD into a decimal number
* and send it to CONSOLE OUT.
org ORGADDR
start
checknumber
cmpa #0 * 0=number
beq donumber
cmpa #255 * 255=string
beq dostring
ldx #msgunknown
bsr print
error
ldd #-1 * Return -1 as an error code
return
jmp GIVABF * Value in reg D will be returned to BASIC.
donumber
jsr INTCNV * Load D with number
jsr REGDOUT * Display number
ldd #0 * D=0 (no error code)
bra return
dostring * X will be VARPTR
ldb ,x * B=string length
ldy 2,x * Y=string data address
beq stringdone
loop
lda ,y+ * A=byte of string data, increment Y
jsr [CHROUT] * Output character in A
decb * Decrement B (length of string)
bne loop * If not 0, go back to loop
stringdone
bsr printspace
tfr x,d * Transfer X into D register
jsr printd * Print VARPTR address
bsr printspace
clra * A=0
ldb ,x * B=string len (making D)
bsr printd * Print string length
bsr printspace
ldd 2,X * Load D with string address
bsr printd * Print the number
ldd #0 * D=0 (no error code)
bra return
* PRINT integer in D
printd
pshs a,b,x,u
jsr REGDOUT
puls a,b,x,u
rts
* PRINT space
printspace
pshs a
lda #32
jsr [CHROUT]
puls a
rts
* PRINT subroutine. Prints the string pointed to by X.
lda ,x+
beq printdone
jsr [CHROUT]
bra print
printdone
lda #13
jsr [CHROUT]
rts
msgunknown
fcc "UNKNOWN"
fcb 0
end
And here is it running with some examples:

For this demo, my assembly code detects if the passed-in parameter is a number or a string. If a number, it prints out that number using a ROM routine. If a string, it figures out where the string is in memory then prints that string, followed by the VARPTR address of the string variable, the string size, and the address of the string data in memory (just so you can see how it all works).
I will try to find time to clean this up a bit. I want to use this in my Hacking PRINT series.
Until then…
