|
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-4 | Temporaries |
&H85,6 | Size of result in FPACC |
&H87-E | Temporaries |
&H8F,91 | Destination address used by block copy at
&HB3A4 |
&H92-9 | Temporaries |
&H9A,B | Used to store stack pointer to check for OM error |
&H9C,D | Address 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,5 | Top 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 |
&H4F8 | RAM 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
|
&H5BA | Command table 2 (see Command table 1) |
&H5BF | Function table 2 (see Function table 1) |
&H5C4 | Command table 3 (see Command table 1) |
&H5C9 | Function table 3 (see Function table 1) |
&H5CE | Command table 4 (see Command table 1) |
&H5D3 | Function table 4 (see Function table 1) |
&5D8,9 | Purpose unknown |
&H5E2,3 | Address of routine for LOAD from device |
&H5E5-7 | Jump vector for LOADM |
&H5E8-A | Jump vector for SAVEM |
&H5EB-D | Jump vector for Disk Open
A=status byte, B=channel number, X=status address |
&H5EE-F0 | Jump vector for Disk Close
A=status byte, B=channel number, X=status address |
&H5FI-3 | Jump 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-6 | Jump vector for get byte from disk
Registers & calling sequence as Put byte |
&H5F7-9 | Print string |
&H609-B | Jump vector for command intercept |
&H615-7 | Jump vector for line tokenize |
&H621-3 | Jump vector for function intercept |
&H633 | Default device number |
&H636 | Vector for mode check
A=mode, $F4=channel number (1..15)
|
&H63C,D | Address of routine to Abort IO to a device after
BREAK |
&H63E | Device number |
&H651-3 | Jump vector for WHILE command |
&H654-6 | Jump vector for WEND command |
&H657-76 | Device control block address table |
&H678-87 | Channel status table (1 byte per channel):
0 | Not open |
MS Nibble | mode: 1="I"
2="O"
9="I" for disk
10="O" for disk
12="R" for disk
|
|
LS Nibble | device no (non disk)
file no (disk) |
|
&H68C | ASCFLG: 0=Binary, -1=ASCII
|
&H68F- | OPTBUFF |
&H698,9 | EXEC Address |
&H69C-&H751 | DCB0-DCB6 Tables |
&H8CF-&H8E2 | USR0-USR9 Addresses |
&H8EB- | FIDBUF Filename (8 bytes) |
&H8F3 | FTBUF Filetype (3 bytes) |
&H91C-D | Default RS232 Mode
Value is passed to RSMST at &HFF88 |
3. Entry Points
Entry Point | Description |
&H8433 | Error Entry (B)=Error No (1—255) |
&HA3B5 | Resume at main loop |
&HA9D8 | Abort (Usually after Break) |
&H9035 | Evaluate expression
(A)=Current token, &HFB,&HFC point at expression
On exit (X) contains the integer value of the expression
|
&H917E | Print message
(X)=Message address-1 |
&HA6D0 | Load continue |
&H800F | Save 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:
Bytes | Description |
0 | RTS |
1,2 | FCB 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 Log—on 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:
”
Bytes | Contents |
0-3 | NAME, eg "SPTO" |
4 | IO 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,8 | Close address
&H68A contains close mode |
9,10 | Get Byte address
(A) = Byte
At end of file place &HFF in &HOOF5 |
11,12 | Put Byte address
(A) = Byte |
13,14 | Test EOF routine Address
(B) = 0 if not EOF, -1 if EOF |
15,16 | LOF routine address
(D) = LOF return value |
17-20 | Spare - used by device driver |
21 | Next 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 |
22 | Line width, 1-254 or 0=infinite |
23 | Comma print zone, default = 14 |
24 | Last 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 (&H63C—E;
contains a JMP instruction).
If you want to load a program from an input device, you must link
in code to HKLOAD (&H5E2—5). 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:
Byte | Contents |
2 | Integer in FPACC+6,7 |
3 | String descriptor in FPACC+5 - FPACC+7 |
4 | Real in FPACC+4 - FPACC+7 |
8 | Double 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.
Copyright © Julian Wald 1997-2002
Most recent revision August 2002
|