See also: part 1, part 2, part 3, part 4, part 5 and part 6.
This article series will demonstrate how to interface some 6809 assembly code with Microsoft BASIC on a Tandy/Radio Shack TRS-80 Color Computer.
BASIC on the Color Computer is easy, but not fast. 6809 assembly language is fast, but not easy. Fortunately, it’s easy (and fast?) to combine them, allowing you to write a BASIC program that makes use of some assembly language to speed things up.
Assembly code can be loaded (or POKEd) in to memory at a specific address and then invoked by the EXEC command. This is fine for a “go do this” type of routine. But, if you want the assembly code to interact with BASIC by returning values or modifying a variable or string, you can use a special BASIC command designed for this purpose.
The Color Computer’s original 1980 COLOR BASIC had a USR command which could be used to call an assembly language routine via a BASIC interface. From the Wikipedia entry:
USR(num) calls a machine language subroutine whose address is stored in memory locations 275 and 276. num is passed to the routine, and a return value is assigned when the routine is done
This allowed passing a numeric parameter in to the assembly routine, and getting back a status value.
When EXTENDED COLOR BASIC came out, USR was enhanced to allow defining multiple routines. It looks like this:
DEFUSR0=&H3F00 A=USR0(42)
That code would define USR0 to call an assembly routine starting at memory location &H3F00 and pass it the value of 42. That routine could then return a value back to the caller which would end up in the variable A.
There are two ROM routines that enable receiving a value from BASIC, and returning one back:
- INTCNV will convert the integer passed in the USRx() call and store it in register D.
- GIVABF will take whatever is in register D and return it to the USR0() call.
Here is a very simple assembly routine that would receive a value, add one to it, and return it.
ORGADDR EQU $3f00 GIVABF EQU $B4F4 * 46324 INTCNV EQU $B3ED * 46061 org ORGADDR start jsr INTCNV * get passed in value in D tfr d,x * transfer D to X so we can manipulate it leax 1,x * add 1 to X tfr x,d * transfer X back to D return jmp GIVABF * return to caller
Using the lwtools 6809 cross compiler, I can compile it in to a .BIN file that is loadable in DISK BASIC:
lwasm --decb -o addone.bin addone.asm
I could then use the toolshed decb command to copy the binary to a .DSK image to run in an amulator such as Xroar. In my case, I have an image called DRIVE0.DSK I want to copy it to:
decb copy -2 -r addone.bin ../Xroar/dsk/DRIVE0.DSK,ADDONE.BIN
Now I can run the Xroar emulator and mount this disk image and test it:
It works! Of course, I could have just done…
A=A+1
…so maybe this isn’t the best use of assembly language. ;-)
Up next … a look at doing something actually useful.
Pingback: Interfacing assembly with BASIC via DEFUSR, part 2 | Sub-Etha Software
Pingback: Interfacing assembly with BASIC via DEFUSR, part 4 | Sub-Etha Software
Pingback: Optimizing Color BASIC, part 3 | Sub-Etha Software
Random passing comment: of course, you could just use “addd #1” instead of bothering with X.
You say “of course” because you know stuff. :) Simon J pointed that out to me, and I revisited the code sample later. At the time, I forgot there was ADDD, and knew about LEA being how you did it with X and Y and figured that must be what I needed for 16-bit registers. When LEAD wasn’t a thing I, well, you get the idea.
Pingback: Optimizing Color BASIC, part 6 | Sub-Etha Software
Pingback: CoCo Cross Development, part 1 – Vintage is the New Old
Pingback: CoCo Cross Development, part 2 – Vintage is the New Old
Pingback: Interfacing assembly with BASIC via DEFUSR, part 6 | Sub-Etha Software
Pingback: CoCo Cross Development, part 3 – Vintage is the New Old
Pingback: CoCo bouncing BASIC ball, part 5 | Sub-Etha Software
Pingback: Compressing BASIC DATA with Base-64 – part 1 | Sub-Etha Software