HX-20 Technical Note

Extending the BASIC Interpreter


1. BASIC Token Address

The following program will list the token number and execution address of the BASIC commands and functions:

100 DEFDBL A-Z:OPEN "O",1,"LPT0:"
110 T=&H80:PRINT #1,"COMMANDS":PRINT #1:N%=0:GOSUB 120
115 T+&HFF80:PRINT #1,"FUNCTIONS":PRINT #1:N%=1:GOSUB 120
117 END
120 X=&H5A6+5*N%:CNT=PEEK(X):M=PEEK(X+1)*256+PEEK(X+2)
122 A=PEEK(X+3)*256+PEEK(X+4):M1=M
124 IF CNT>0 THEN PRINT #1,"TOKEN";TAB(16);"ADDR"
130 IF M=0 THEN 190 ELSE IF (PEEK(M)=0) OR (CNT=0) THEN 190
140 CNT=CNT-1:PRINT #1,HEX$(T);TAB(6);
150 IF PEEK(M) < 128 THEN PRINT #1,CHR$(PEEK(M));:M=M+1:GOTO 150
160 PRINT #1,CHR$(PEEK(M) AND 127);TAB(16);:M=M+1
170 IF(A<>M1) THEN PRINT #1,HEX$(PEEK(A)*256+PEEK(A+1));:A=A+2
180 PRINT #1:T=T+1:GOTO 130<
190 PRINT #1:RETURN

Note that function tokens all start with a byte of &HFF. The BASIC programs are stored as follows:

Bytes Contents
0,1 Program Area Size
-9 Program Title
10 Protection Byte:
0 = Unprotected
-1 = Protected
11 Zero
12- Program Lines

Each line is formatted as follows:

Bytes Contents

0,1

Size of line in bytes (not the current program area)

Address of next line (current program area, or previously logged program area when not in BASIC)

2,3 Line Number (Binary)
4- Program Line, terminated by 0

Note that the program text is held at MEMSET when BASIC is running, but is copied into the application file when any other application is used.

2. Memory locations

Location Contents
&H80-4Temporaries
&H85,6Size of result in FPACC
&H87-ETemporaries
&H8F,91Destination address used by block copy at &HB3A4
&H92-9Temporaries
&H9A,BUsed to store stack pointer to check for OM error
&H9C,DAddress of current area. Points at Area size
&H9E,F Start of simple variables
&HA0,1 End+1 of simple variables/Start of arrays
&HA2,3 End+1 of arrays
&HA4,5Top of stack/First free string space-1 (Used from high -> low)
&HA6,7 Last free string space (Used from high -> low)
&HA8,9 First used address in string
&HAA,B Last used address in string
&HAC,D Line no of current BASIC line
&HAE,F Purpose unknown
&HBO,1 Line number for line search
&HB2,3 Address for TKN on RESUME; 0=CAN'T CONTINUE
 
&HD1-8 Floating point accumulator (integers in &HD7,D8)
 
&HF4 Device channel
&HF5 End of file flag: 0=Not EOF, -l=EOF
 
&HF6 TKNGET Routine (self modifying code)
 
&HFB,C TKN Pointer
 
&H4BO,1 Address of first non BASIC Application file
&H4B2,3 Address of start of DISK BASIC, DISK Assembler etc
&H4B4 Current Program number
 
&H4F6,7 RAM file Offset
&H4F8RAM file Record length
&H4F9-B Warm start Hook (Copy actually executed)
&H4FC,D Basic Text area size
&H4FE,F RAM file size
&H500,1 MEMSET value
&H502-A1 PF Key text (16 bytes per key)
&H5A2,3 RAM file start address
&H5A4,5 Purpose unknown
&H5A6

Command vector table 0:

Byte 0 = No of commands
Bytes 1,2 = Address of Command name table
bytes 3,4 = Address of command address table

The command name table contains the ASCII text of commands Each command is terminated by the most significant bit of the last character set to 1. The entire table is terminated by a null byte

&H5AB

Function table 0

This table is in the same format as command table 0

&H5B0

Command table 1

This table is in the same format as command table 0, except that bytes 3 & 4 contain the command routine address for all the commands in the table

&H5B5

Function table 1

This table is in the same format as command table 0, except that bytes 3 & 4 contain the command routine address for all the functions in the table

&H5BACommand table 2 (see Command table 1)
&H5BFFunction table 2 (see Function table 1)
&H5C4Command table 3 (see Command table 1)
&H5C9Function table 3 (see Function table 1)
&H5CECommand table 4 (see Command table 1)
&H5D3Function table 4 (see Function table 1)
&5D8,9Purpose unknown
&H5E2,3Address of routine for LOAD from device
&H5E5-7Jump vector for LOADM
&H5E8-AJump vector for SAVEM
&H5EB-DJump vector for Disk Open
A=status byte, B=channel number, X=status address
&H5EE-F0Jump vector for Disk Close
A=status byte, B=channel number, X=status address
&H5FI-3Jump vector for put byte to Disk
A=Byte, B=status byte, X=Status Address
Call by PSH X:PSH B:PSH A:JMP &H5F1
&H5F4-6Jump vector for get byte from disk
Registers & calling sequence as Put byte
&H5F7-9Print string
&H609-BJump vector for command intercept
&H615-7Jump vector for line tokenize
&H621-3Jump vector for function intercept
&H633Default device number
&H636Vector for mode check
A=mode, $F4=channel number (1..15)
&H63C,DAddress of routine to Abort IO to a device after BREAK
&H63EDevice number
&H651-3Jump vector for WHILE command
&H654-6Jump vector for WEND command
&H657-76Device control block address table
&H678-87Channel status table (1 byte per channel):

0Not open
MS Nibblemode:
1="I"
2="O"
9="I" for disk
10="O" for disk
12="R" for disk
LS Nibbledevice no (non disk)
file no (disk)
&H68CASCFLG: 0=Binary, -1=ASCII
&H68F-OPTBUFF
&H698,9EXEC Address
&H69C-&H751DCB0-DCB6 Tables
&H8CF-&H8E2USR0-USR9 Addresses
&H8EB-FIDBUF Filename (8 bytes)
&H8F3FTBUF Filetype (3 bytes)
&H91C-DDefault RS232 Mode
Value is passed to RSMST at &HFF88

3. Entry Points

Entry PointDescription
&H8433Error Entry
(B)=Error No (1255)
&HA3B5Resume at main loop
&HA9D8Abort (Usually after Break)
&H9035

Evaluate expression
(A)=Current token, &HFB,&HFC point at expression

On exit (X) contains the integer value of the expression

&H917EPrint message
(X)=Message address-1
&HA6D0Load continue
&H800FSave D in FPACC as integer

4. Extending BASIC

BASIC can be extended by adding new device drivers, commands or functions, or any combination of these.

The code to implement the new facilities must be located on ROM or be copied to a protected area above all other applications. I have a utility program that performs this function. The code must conform to the following format:

BytesDescription
0RTS
1,2FCB 0,0
3-Start of HOOK routine to link in all new facilities
 Remainder of code

The HOOK routine is executed every time BASIC is warm started. It must link in the new device drive by adding it to the list of drivers. It must also link in the new commands or functions to the next free command/function vector table. On entry to the HOOK routine (X) points at the exissting Logon message. This may be printed using the routine at &H917E, and (X) pointed at a new routine if required. Alternatively (X) should be preserved during the HOOK routine. The HOOK routine must terminate by jumping back to the RTS at the start of the code. The RTS and associated null bytes are replaced by a JMP instruction if any additional extended BASICs are linked in.

5. Device drivers

The simplest extension is to add a new device driver. The device requires a device table, used to inform BASIC of the addresses used by the device. The format of the device table is as follows:

BytesContents
0-3NAME, eg "SPTO"
4IO mode:
&H10 = Input
&H20 = Output
&H30 = Input/Output
5,6

OPEN device address

The options are placed in OPTBUFF, with the parentheses removed. The options are terminated by null. The filename and type are placed in FIDBUF and TYPBUF.

&H68A contains OPEN mode:
&H10 = input, &H20 = output

The OPEN routine must set up ASCFLG on input, or use ASCFLG on output

7,8Close address
&H68A contains close mode
9,10Get Byte address
(A) = Byte
At end of file place &HFF in &HOOF5
11,12Put Byte address
(A) = Byte
13,14Test EOF routine Address
(B) = 0 if not EOF, -1 if EOF
15,16LOF routine address
(D) = LOF return value
17-20Spare - used by device driver
21Next column position. Returned by POS. Set to 0 by CR or LF. Incremented after each byte by PUT byte routine. When the value execeeds line length, PUT byte must generate CR or CR+LF and reset the position to 0
22Line width, 1-254 or 0=infinite
23Comma print zone, default = 14
24Last comma print zone
25&H80 = fixed width
0 = variable width

The DCB address must be placed in the first free location in the DCB address table at &H657. A free entry contains &H0000. Any device intialisation must be performed in the HOOK routine.

If a call to a routine in the DCB results in an error, the routine can either load B with a suitable error number and jump to &H8433. or it can jump to &HA9DB to ABORT (producing the Abort... message).

Note that all devices are closed during an abort. If the device requires initialization as a result of the abort, the address of an initialization routine must be linked in to HOOKABTD (&H63CE; contains a JMP instruction).

If you want to load a program from an input device, you must link in code to HKLOAD (&H5E25). This must compare the value in (A) with the device number (the offset in the DCB address table). If a match occurs, jump to LODCNT (&HA6D0), otherwise return to the ERROR routine at &H8433 with a suitable error number in (B).

Commands

TKN (&HFB,C) points at the command token. You must ensure that the token is valid for the current routine, if not you must either generate an error or execute the command routine for the next command vector table (if in use). Note that if you jump to the command routine for the next table, (B) must contain the command token. If the token is valid you should process the remainder of the command. TKN must be left pointing at a ":" or null byte on return to the interpreter.

Note that if your command spans more than one line you must ensure that you update &HAC,D. You should use TKN to scan over the program.

The command routine must do an RTS to return to the interpreter.

Functions

On entry to the function routine, TKN is pointing at the first character beyond the function token. You must use TKN to scan back to the &HFF byte to locate the function code. If the token is invalid you should either jump to the error routine, or jump to the function routine for the next function vector table (if in use). Note that (B) must contain the function code in this case.

If the token is valid, it may be necessary to process the function parameters before placing the function result in FPACC. &H85 must contain the type of the result:

ByteContents
2Integer in FPACC+6,7
3String descriptor in FPACC+5 - FPACC+7
4Real in FPACC+4 - FPACC+7
8Double in FPACC - FPACC+7

On return to the interpreter TKN must point at the first character beyond the function (normally beyond the closing right parenthesis). The function routine must return using an RTS instruction.

6. User Routines

User routines can, contrary to the BASIC manual, return a result of any type. All that is required is to change the value in FPACC and &H85 to suit the new value.