BETTA BASIC for Sinclair ZX-81
by Jason Judge
from Your Computer, April 1984

John [sic] Judge adds 14 Basic commands to the ZX-81.

[The author's correct name was given in a letter in the June 1984]
[issue, together with some corrections to the article.       JimG]


This set of machine-code routines provides the 16K ZX-81 with 14 new
Basic statements and commands usually found only on much larger and
more expensive machines. The routines take up 1,336 bytes in a REM
statement and are designed for ease of use with full error codes. Two
of the routines are interrupt driven and allow you to add your own
interrupt driven routines.

To enter the program, a 16K ZX-81 with the NEW run has to be used; it
may be possible to use less memory, but some of the routines will
crash if the display file is collapsed; ie. RAM is less than 3.25K.

First, line 1 REM followed by 128 zeroes - four lines - is entered.
This is then duplicated as line 2 and so on up to line 10. When this
has been done, the following are entered as direct commands:
	POKE 16511,56
	POKE 16512,5
	POKE 16509,0
	POKE 16510,0
	POKE 16514,118
	POKE 16515,118
	1 REM BETTA BASIC
	POKE 16419,1
	NEWLINE
You should now have:
	1 REM BETTA BASIC
on the screen. Anything else means that you have probably done
something wrong and it is best to start again.

If all is well then enter the hex-loader Program 1, ignoring line 0 as
this should already be in memory. Type RUN N/L then enter the start
address for the machine code data, which will be 16514 if you are just
starting or another number if you are continuing from another day or
after saving partly completed data. You can now enter the hexadecimal
data, as many of the numbers as you like before pressing Newline, but
remembering not to enter any of the spaces. There is a checksum number
after each line which you can compare with the checksum number on the
screen; if it is different then press S N/L and you can enter the line
that is wrong. By pressing Q N/L you can break out of the program to
save it.


Looking through data

Program 2 is for looking through the data for any that is wrong. To
use it, type RUN 200 then enter the start address. Type CONT after
each screenful.

If all the data is entered and correct, then delete lines 5 onwards
and enter Program 3. Do not use NEW to delete the lines. The program
is now finished and ready to use, unless some bugs have escaped
detection.

You must have Betta Basic present in the computer before you start
typing in your program. In this way the machine code routines are
saved as you save your program that uses them. Now, whenever you type
RUN the variables are initialised ready for use.


INT: Switches on the interrupt routine by RAND USR INT to give the
following features:

TRACE ON by POKE TRN,1 or by pressing N/L and 1 together.

MEMORY ON by POKE TRN,2 or pressing N/L and 5.

MEM/TRACE OFF by POKE TRN,0 or pressing N/L and 2.

ROUTINE OFF by pressing N/L and 3 or FAST then SLOW.

Break out of any program - even machine code - by pressing N/L and 4;
this also switches routine off.

TRACE SPEED by POKE LEN,n where n is the length of the pause at each
interrupt - initially 3.

USER ROUTINE: Three bytes - USE, USE+1 and USE+2 - are set aside to
add to call to your own interrupt driven routine; initially all are
NOPs. Make sure the routine is OFF by using FAST followed by SLOW
before you start POKEing or a crash will occur as soon as you POKE in
the first number.

When using the Trace or Memory Left features, the number will take up
the first five characters in the top left corner of the screen. These
numbers are only printed up during the interrupt and the original text
or graphics are put back into the screen before control is handed back
to the ROM; so, as far as the ROM is concerned, the numbers do not
even exist on the screen and so will not be "in the way"; but it is
important not to use the Sinclair SCROLL command as this will cause a
crash after 23 SCROLLs.

Pressing N/L and 4 will break out of any machine code programs as long
as the routine is switched on by RAND USR INT.

The Trace and Memory Left routines will automatically switch off when
program execution ends or any error occurs, though they can operate in
command mode by using N/L and the function keys 1 to 5.

The interrupt routine will be switched off by any of the following:
FAST, COPY, LPRINT, LLIST, SAVE, LOAD, PAUSE, NEW or by entering a
line. If any of these are used then do not forget to switch on again
by using RAND USR INT before using Trace or Memory Left.


LOC: This moves VARS up to E_LINE so that all the variables tempo-
rarily disappear and "load variables" can be used instead; ie.
variable names can be used for a second time without altering any of
the original variables of [sic] values; eg.
	[The next line was not printed in the magazine. JimG]


VAR: Restores original variables after using LOC. Do not use unless
LOC has been used first. For example:
	RAND USR VAR


SCL: Stands for SCROLL. Do not use the SCROLL provided by Sinclair as
it will cause some of the routines to crash. For example:
	RAND USR SCL


In the following, X and Y can be any numerical argument in the range 0
to 65535, V any numeric variable, I any numerical dummy variable that
is not used for anything else, anything surrounded by [] is optional,
all PRINT statements will be changed to REM by the routine, and should
be changed back to PRINT if ever the line is edited. The PRINT lines
after the USR lines hold the arguments for each routine.


Function has three uses

PRT: This has three uses, two of which are concerned with ports.

a) OUT (port), byte. For example:
10 LET I=USR PRT
20 PRINT X,Y [;X,Y ...]

b) IN variable, (port) or LET variable=IN (port). For example:
10 LET I=USR PRT
20 PRINT ;X where X = port 0 to 255

c) LD I,X. For example:
10 LET I=USR PRT
20 PRINT ;;X where X = char set 0 to 255
This one changes the character set and can be used for games or with a
graphics ROM - initially 30.


REP: Same as BBC Basic REPEAT. The line numbers are stored in R$. Up
to 15 REPEATs can be nested - inside each other - before an error
occurs. For example:
10 LET I=USR REP
[See note after R error code in Error Codes section below. JimG]


UNT: BBC Basic UNTIL. Jumps back to line after last REP if a testable
condition is not true. For example:
10 LET I=USR UNT
20 PRINT testable condition


ONG: Same as ON ... GO TO ... Jumps to the Xth line number in a list
of numbers. If X = 0 or X > number of numbers in list then the line
after the ONG is executed. For example:
10 LET I=USR ONG
20 PRINT X;line[,line ...]
Up to 255 lines can be put on the list.


PRC: Def Proc. This is a simulation of procedures, using names instead
of line numbers. Each 'procedure' has the following structure:
10 REM PROCNAME
20 Subroutine or Procedure
30 RETURN
where NAME will be the name of the procedure. PRC is called only once
at the beginning of the program. For example:
10 LET I=USR PRC
The routine then searches for all the "REM PROCNAMEs" and puts the
names into the variables area with their line numbers so that a
procedure can be called by:
	GOSUB NAME
The name must be three or more characters long and contain only
characters legal as a variable name; see page 38 of the Sinclair
manual. There is no space between the PROC and the NAME.


DYN: Dynamic Procedure. This routine tells you whether a name held
[in] a string variable is a procedure or not so that it may be used
with VAL without an error occurring if it does not exist; eg.
10 INPUT A$
20 IF USR DYN THEN GOTO VAL A$
30 REM A$
40 GOTO 10

The above example GOTOs a procedure entered in line 10 if it exists,
otherwise it waits for you to enter another. The A$ in lines 10, 20
and 30 can be changed to any other string variable.


LST: This is a fast scrolling LIST with a few extra features. To use:
RAND line to list from
RAND USR LST
In this routine you can press:
Space to break out of the routine;
Z to copy the screen to the printer;
K to "normal list" the last line on the screen in order to edit;
D to list through slowly;
N/L to list through fast.


ERROR CODES
Z variable not found; eg. R$ in REP, PROCNAME, etc.
4 out of memory
B integer out of range; ie. a number less than 0 or greater than 65535
  has been used in a routine.
C number error; ie. a number or expression has been left out or does
  not make sense, so the computer cannot change it to an integer for
  it to use.
D break
Q missing semi-colon
R too many repeats (max. 17)
  [It says max.15 in the description of REP above, but as R$ is 34]
  [characters long 17 is probably correct.                    JimG]
S syntax error; eg. no data or expressions
T missing comma
U Until without Repeat
V R$ error; eg. R$ has been DIMed or is too short so that REP and UNT
  cannot use it.
W RAND too high for LST
X Procname error; eg. too short (min. three characters) or non-existent
Y incorrect string variable in line after DYN


[I haven't checked any of the hexadecimal addresses given below,]
[but with the number of typos in this article, I wouldn't trust ]
[any of them.                                               JimG]


USEFUL ROM ROUTINES USED

08F5h PRINT AT B,C;
0808h PRINT CHR$(A); Chars 0-63 and their inverses
094Bh PRINT CHR$(A); Chars 64-127 and 192-255
0A98h PRINT BC;
0AZAh CLS [sic]
063Eh LIST           Same as pressing Newline
0869h COPY
1520h STK BC         Puts BC on calc. stack as "floating point" number
0EA7h UNSTK BC       Takes BC off calc. stack
111Ch LOOKVARS       Finds variable pointed to by CH_ADD and puts its
                     address into HL


If you wish to disassemble the routines, then here are the addresses
you will need in hexadecimal: 

40A5 INT
40BC LOC
40CD VAR
40DC SCL
40EE System variables
4108 Interrupt routine entry point
420E Routine to check next line is a PRINT line and change it to a REM
     if necessary.
4227 PRT
4270 REP
42BA UNT
430D ONG
436Z DYN [sic]
43EE PRC
44A6 LST
4585 last address

