Category Archives: 6809 Assembly

Interfacing assembly with BASIC via DEFUSR, part 2

See also: part 1, part 2, part 3, part 4, part 5 and part 6.

Previously, we took a look at using the EXTENDED COLOR BASIC DEFUSR command to interface a bit of assembly language with a BASIC program. The example I gave simply added one to a value passed in:

Using DEFUSR to call assembly from BASIC.

That’s not very useful, so let’s do something a bit more visual.

One of my favorite bits of CoCo 6809 assembly code is this:

      org  $3f00
start ldx  #$400 * load X with start of 32-column screen
loop  inc  ,x+   * increment whatever is at X, then increment X
      cmpx #$600 * compare X with end of screen
      bne  loop  * if not end, go back to loop
      bra  start * go back to start

This endless loop will start incrementing every byte on the screen over and over making a fun display. I ran this code in the Mocha emulator (which has EDTASM available):

http://www.haplessgenius.com/mocha

Then I compiled it (“A/IM/WE/AO” – assemble, in memory, wait for errors, absolute origin – how can I still remember this???), and ran it in the debugger (“Z” for debugger, then “G START” to start it):

Mocha emulator running silly screen code.

This inspired me to make a small assembly routine to do something similar from BASIC. The CLS command can take an optional value (0-8) to specify what color to clear the screen to. Let’s make an assembly routine that will allow specifying ANY character to clear the screen to:

ORGADDR EQU $3f00

GIVABF EQU  $B4F4  * 46324
INTCNV EQU  $B3ED  * 46061

       org  ORGADDR
start  jsr  INTCNV * get passed in value in D
       cmpd #255   * compare passed in value to 255
       bgt  error  * if greater, error
       ldx  #$400  * load X with start of screen
loop   stb  ,x+    * store B register at X and increment X
       cmpx #$600  * compare X to end of screen
       bne  loop   * if not there, keep looping
       bra  return * done
error  ldd  #-1    * load D with -1 for error code
return jmp  GIVABF * return to caller

First, I added a bit of error checking so if the user passed in anything greater than 255, it will return -1 as an error code. Otherwise, it returns back the value passed in (that the screen was cleared to.)

Side Note: Hmmm. Since I know register D is register A and B combined, all I really need to do is make sure A is 0. i.e, “D=00xx”. If anything is in A, it is greater than the one byte value in B. I suppose I could also have done “cmpa #0 / bne error”. Doing something like that might be smaller and/or faster than comparing a 16-bit register. Anyone want to provide me a better way?

Since the 16-bit register D is made up of the two 8-bit registers A and B, I can just use B as the value passed in (0-255).

Here is what it would do with a bad value:

Clear X routine, bad value error.

And here is it with a valid value of 42:

Clear X with a value of 42.

So far so good.

In the next part, we’ll look at how to pass in a string instead of an integer.

Interfacing assembly with BASIC via DEFUSR, part 1

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:

  1. INTCNV will convert the integer passed in the USRx() call and store it in register D.
  2. 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:

Using DEFUSR to call assembly from BASIC.

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.