* * * * *
The definitive guide to writing assembly language subroutines for Extended
Color BASIC
And in keeping with documenting 40 year old technology [1], I'm documenting
how to call assembly language subroutines for Extended Color BASIC
(Beginner's All-purpose Symbolic Instruction Code).
One major difference between Color BASIC and Extended Color BASIC is how to
define the address to call. No longer do you have to poke the address into
memory, but use the BASIC command DEFUSRn (where n is between 0 and 9). And
you can define up to 10 such routines.
From that point on, existing code written for Color BASIC will just work.
VARTYP will still have the value type, FP0 will still be a floating point
value or contain an address to a string descriptor, and all the functions
defined for Color BASIC still function the same.
But there are some major differences. First off, the registers are defined
upon entry now. The A register contains the contents of VARTYP and the
condition codes are set appropriately, so that one can immedately do a
conditional branch to check the type (BEQ (Branch if EQual) for a number, BMI
(Branch if MInus) for a string). The X register either points to FP0
(technically, one byte prior to FP0 for internal reasons) if the parameter is
a number, or it points to the string descriptor if the parameter is a string.
And if the parameter is a string, the B register has the length of the
string. So the chksum function can be rewritten to read:
-----[ Assembly ]-----
CHKSTR equ $B146
GIVBF equ $B4F3
org $7F00
checksum jsr CHKSTR
lda ,x
ldx 2,x
clrb
sum addb ,x+
deca
bne .sum
comb
jmp GIVBF
end
-----[ END OF LINE ]-----
Not a big change, but no longer do we have to load the string descriptor
pointer from memory.
The biggest change however, is the ability to return a string from an
assembly language subroutine. No longer do you have to modify the passed in
string descriptor, you can return a new string. To do so, you call RSVPSTR to
reserve the space, put the length into the BASIC variable STRDES (name from
the Unravelled Series [2] and located at address $0056), the pointer into
STRDES+2, and call GIVSTR (name I came up with since it's not named in the
Unravelled series and located at address $B54C). Here is the revised ROT-13
[3] code for Extended Color BASIC:
-----[ Assembly ]-----
rot13 jsr CHKSTR
tfr x,y ; save string descriptor
jsr RSVPSTR ; B is already set
stb STRDES ; save new string length
stx STRDES + 2 ; and the space for it
ldy 2,y ; get stirng data, which RSVPSTR may have moved
loop lda ,y+ ; ROT-13 blah blah ...
cmpa #'A'
blo .out
cmpa #'Z'
bhi .out
adda #13
cmpa #'Z'
bls .out
suba #26
out sta ,x+
decb
bne .loop
jmp GIVSTR ; return new string to BASIC
end
-----[ END OF LINE ]-----
And this:
-----[ ExtendedColorBASIC ]-----
110 X$ = USR0("ABCXYZ")
120 PRINT X$
-----[ END OF LINE ]-----
will work as expected—X$ will be the ROT-13 version of the string literal.
And with that, we're done. That's all there is to interfacing an assembly
language subroutine to Color BASIC and Extended Color BASIC.
I'm not sure why this wasn't documented in _Getting Started With Extended
Color BASIC_ [4]—perhaps no one talked about the changes to Extended Color
BASIC to the documentation department, or there wasn't time before shipping
the updated BASIC, or what. It's clear from the Unravelled series that the
change was a deliberate change to make it easier to interface with BASIC and
cache useful values in the various registers, but for some reason, it never
got documented. What is documented will work, you can pass in a string as:
-----[ ExtendedColorBASIC ]-----
110 X$="ABCXYZ" : X=USR0(VARPTR(X$))
-----[ END OF LINE ]-----
but it's not needed as I've shown. And here's one last example, defining
multiple subroutines that show handling of various parmaters of strings and
numbers and returning strings or numbers (here are links to basic.i [5] and
basic-fp.i [6]):
-----[ Assembly ]-----
include "basic.i"
include "basic-fp.i"
.opt basic strspace 300
.opt basic defusr0 num2num
.opt basic defusr1 fp2fp
.opt basic defusr2 num2str
.opt basic defusr3 str2num
.opt basic defusr4 str2str
.opt basic defusr5 son2son
.opt basic defusr6 son2nos
org $7F00
;***************************************************************************
num2num jsr CHKNUM ; check for numeric argument
jsr INTCVT ; convert to integer
coma ; 1s complement
comb
jmp GIVABF ; return it to BASIC
;***************************************************************************
fp2fp jsr CHKNUM ; check for numeric argument
ldx #.pi ; * 3.1415926
jmp CB.FMULx
pi .float 3.1415926
;***************************************************************************
num2str jsr CHKNUM ; check for number
jsr INTCVT ; convert to integer
bmi .minus ; if negative, return 'MINUS'
beq .zero ; if zero, return "ZERO"
ldx #.textplus ; else return "PLUS"
bra .return
minusinf ldx #.textminus
bra .return
zero ldx #.textzero
return ldb ,x+ ; get length
stb STRDES + _STRLEN ; save length
stx STRDES + _STRPTR ; save text
jmp GIVSTR ; return string to BASIC
textminus ascii 'MINUS'c ; a "counted" string
textzero ascii 'ZERO'c ; where the first byte is the length
textplus ascii 'PLUS'c ; of the string
;***************************************************************************
str2num jsr CHKSTR ; check for string
lda _STRLEN,x ; get length
ldx _STRPTR,x ; get string data
clrb ; clear checksum
sum addb ,x+ ; add next byte
deca ; if more, do more
bne .sum
comb ; complement checksum
jmp GIVBF ; return it to BASIC
;***************************************************************************
str2str jsr CHKSTR ; check for string
tfr x,y ; save descriptor
jsr RSVPSTR ; reserve space for return string
stb STRDES + _STRLEN ; save length
stx STRDES + _STRPTR ; and allocated space
ldy _STRPTR,y ; get original string
loop lda ,y+ ; get character
cmpa #'A' ; < 'A', just store
blo .store
cmpa #'Z' ; if <= 'Z', convert to lower case
bls .lower
cmpa #'a' ; if between 'a' and 'z',
blo .store ; convert to upper case
cmpa #'z'
bhi .store
anda #$5F
bra .store
lower ora #$20
store sta ,x+ ; save character in new string
decb ; if more, do more
bne .loop
jmp GIVSTR ; return new string to BASIC
;***************************************************************************
son2son beq .num ; if 0, number (string or number to string or number)
lsrb ; cut length in half
stb _STRLEN,x
rts
num ldx #.one ; add 1.0 to number
jmp CB.FADDx ; and return new value to BASIC
one .float 1.0
;***************************************************************************
son2nos bmi .string ; if minus, string (string or number to number or string)
ldb #4 ; return "0" to BASIC, len of 1
ldx #num2str.textzero+1 ; text of "ZERO"
stb STRDES + _STRLEN
stx STRDES + _STRPTR
jmp GIVSTR
string tfr a,b ; transfer type to B
jmp GIVBF ; and return it to BASIC
;***************************************************************************
end
-----[ END OF LINE ]-----
And the resulting BASIC file output from my assembler [7]:
-----[ ExtendedColorBASIC ]-----
10 DATA189,177,67,189,179,237,67,83,126,180,244,189,177,67,142,127,20,126,186,202,130,73,15,218,104,189,177,67,189,179,237,43,7,39,10,142,127,67,32,8,142,127,57,32,3,142,127,62,230,128,215,86,159,88,126,181,76,4,45,73,78,70,4,90,69,82,79,4,43,73,78
20 DATA70,189,177,70,166,132,174,2,95,235,128,74,38,251,83,126,180,243,189,177,70,31,18,189,181,109,215,86,159,88,16,174,34,166,160,129,65,37,18,129,90,35,12,129,97,37,10,129,122,34,6,132,95,32,2,138,32,167,128,90,38,227,126,181,76,39,4,84,231,132
30 DATA57,142,127,148,126,185,194,129,0,0,0,0,43,12,198,4,142,127,63,215,86,159,88,126,181,76,31,137,126,180,243
40 CLEAR300,32511:FORA=32512TO32683:READB:POKEA,B:NEXT:DEFUSR0=32512:DEFUSR1=32523:DEFUSR2=32537:DEFUSR3=32584:DEFUSR4=32601:DEFUSR5=32648:DEFUSR6=32665
-----[ END OF LINE ]-----
[1]
gopher://gopher.conman.org/0Phlog:2024/11/26.2
[2]
https://colorcomputerarchive.com/repo/Documents/Books/Unravelled%20Series/
[3]
https://en.wikipedia.org/wiki/ROT13
[4]
https://archive.org/details/Getting_Started_with_Extended_Color_BASIC_1984_Tandy
[5]
gopher://gopher.conman.org/0Phlog:2024/11/26/basic.i
[6]
gopher://gopher.conman.org/0Phlog:2024/11/26/basic-fp.i
[7]
https://github.com/spc476/a09
---
Discussions about this page
Two Stop Bits | The definitive guide to writing assembly subroutines for Extended Color BASIC
https://twostopbits.com/item?id=4700
Writing assembly language subroutines for Extended Color BASIC | Hacker News
https://news.ycombinator.com/item?id=42253601
Email author at
[email protected]