Hexadecimal values are used frequently for addressing
because hardware boundaries often occur on even hex addresses.
Unsigned integers between 0 and 65536 may be entered to address
memory locations.
However, only values in the range of +32767
to -32768 are printed normally at the terminal. A method for
printing values beyond the range is presented in Section 2.5.
The machine language subroutine must conform to the
following requirements:
it must end with a RET (hex AF)
instruction, it must leave the value to be returned in R18-19,
and it may use any of the free registers listed in the Memory
Map in Section 6. The register pointer is set to point to
R16-31 on entry to the routine, so the arguments may be fetched
from working registers r2-r3 and r4-r5 and the return value
left in r2-r3 (for a discussion of the working register feature
of the Z8671 refer to the Z8 Microcomputer Preliminary Technical
Manual, part number 03-3047-02).
3.1 Introduction
Basic/Debug recognizes fifteen command keywords. The two
most commonly used keywords, LET and PRINT, may be omitted when
their arguments imply them.
For example, a character string
enclosed in quotation marks can only be processed by a PRINT
command, so a quotation mark following a line number implies
the PRINT keyword.
The first section of each of the following command
descriptions defines command syntax.
The meta-language used to
define the syntax follows the rules below:
Syntactic constructs are denoted by lower case English
words or phrases not enclosed in any special characters.
Examples are command, stmnt, and gosub_stmnt.
The basic symbols of the language are keywords, written in
upper case, and special characters, enclosed in quote
marks. Examples are',' LET '^' NEW.
Possible repetition of a construct is indicated by
appending either a '+' indicating one or more occurrences,
or a '*', indicating zero or more occurrences. For
example, the definition of number as digit+ means that a
number consists of one or more digits.
Parentheses group a number of constructs together So that
a repetition symbol (+ or *) may be applied to the group.
Square brackets denote optional items. The construct
within the brackets may appear either zero or one time.
The vertical bar '|' signifies that one of several
alternate constructs may be specified.
Curly brackets, '{' and '}', surround an English
description of an otherwise indescribable construct.
The second section of each description lists sample
statements which demonstrate the variety of commands possible
within the syntax. The third section describes any special
features of the command.
The commands are listed in
alphabetical order for easy reference.
Statement syntax is
summarized in Appendix A.
GO@
Syntax
go_stmnt => GO '@' address [',' arg_1 [',' arg_2]]
address => expression
arg_1 => expression
arg_2 => expression
Examples:
GO@%E000, A, B
GO@%700
The GO@ command unconditionally branches to a machine
language subroutine.
It may only be used when the subroutine
returns no value.
The first argument is the address of the first byte of the
subroutine. The last two optional arguments are used to pass
values to the subroutine.
Unlike the USR function defined in
Section 2.7.2, the contents of R18-19 are discarded and no
value is returned. Otherwise, GO@ passes arguments to the
subroutine in the same way USR does, according to the following
table:
Table 3-1.
GO Arguments and Registers
call R18-19 contains R20-21 contains
GO @%700, A, B B A
GO @%700, A B A A
GOSUB
Syntax:
gosub_stmnt => GOSUB expression
Examples:
GOSUB 50
GOSUB C
GOSUB B*100
Often an application requires that a few lines of code be
executed at several points in the program.
Rather than repeat
these lines at each location, isolate them at the beginning of
the code.
This subroutine may be called at any time during the
program run by the GOSUB command.
Unlike Dartmouth Basic, the item following the keyword
GOSUB may be either the number of the first line of subroutine
or an expression which evaluates to the subrbutine line number.
The subroutine must be terminated with a RETURN
instruction. GOSUB stores the number of the next line to be
executed where RETURN can find it to restart normal sequential
execution. GOSUB must be the last instruction on its line.
One subroutine may call another.
The RETURN instruction
at the end of the second subroutine returns execution to the
first subroutine.
In this way, subroutines may be nested to
the depth allowed by the memory available to the GOSUB stack.
GOTO
Syntax:
goto_stmnt => GOTO expression
Examples:
GOTO 100
GOTO %FF
GOTO B*100
GOTO unconditionally changes the sequence of program
execution. Unlike the Dartmouth Basic, Basic/Debug accepts
expressions following the keyword GOTO. This feature allows a
variable to be used to select a line number.
For example, if
the variable G will equal 1, 2 or 3 when line 100, 200 or 300
respectively is to be executed, use the following instruction:
GOTO G*100
GOTO is often used in the immediate mode for interactive
debugging because GOTO enters the run mode. Unlike the RUN
command, GOTO can specify the line number where execution is to
begin. For example, when an error occurs and the following
message appears at the terminal:
!ERROR AT LINE 4096
Line 4096 may be retried by entering the following command in
the immediate mode:
GOTO 4096
Because GOTO unconditionally changes the sequence of
execution, any statements that follow it on a program line can
not be executed. Therefore GOTO must always be the last
statement on a line.
IF/THEN
Syntax:
if_stmnt => IF expression relational_op expression
[THEN] apodosis
relational op
=> '<' | '>' | '<>' | '= ' | '<=' | '>= '
apodosis => number | statement line
Examples:
IF A>B THEN PRINT "A>B"
IF A>B "A>B"
IF X=Y IF Y=Z PRINT "X=Z"
IF A<>B I=0:J=K+2:GOTO 100
IF 1=2 THEN this part never matters
The IF/THEN command is used for conditional operations and
branches.
The apodosis may be another statement, a line number
indicating another statement, or a list of statements separated
by colons.
Any of these statements may be another IF.
The
keyword THEN may be omitted to conserve memory space.
IF compares the value of the first expression to the value
of the second.
If the relationship indicated by the relational
operator is true, then the apodosis of the instruction is
executed.
If the relationship is not true, then the next
sequential instruction is executed.
There are only two conditions in which the keyword THEN
may not be eliminated.
It may not be omitted if the second
expression ends with a decimal or hexadecimal constant and the
line number of a statement is used.
For example:
IF X <1 THEN 1000
The above statement requires a THEN to separate the numeric
second expression from the line number.
However, THEN may be
eliminated from the statement by reordering the expressions:
IF 1 > X 1000
The second condition in which THEN may not be omitted is
when the second expression ends with a hexadecimal constant,
and the statement part is a LET statement in which the keyword
has been omitted and the variable is between A and F. For
example:
IF Z > %1000 THEN A = Z
No number of spaces in place of the THEN will prevent the
interpretation of the variable letter as a hexadecimal value
because spaces are ignored.
THEN must be included to separate
the expression from the apodosis.
INPUT/IN
Syntax:
input_stmnt => INPUT variable (',' variable)*
in_stmnt => IN variable (',' variable)*
Examples:
IN C, E, G
INPUT A
These statements first request information from the
operator with the prompt "?", then read the input values from
the keyboard and store them in the indicated variables. They
are two of the three commands which assign an expression to a
variable.
Either command accepts values for a list of one or more
variables.
If the user does not input as many values as are
needed, both commands repeat the prompt until the required
number of values are entered.
The commands differ in the way
they handle extra values entered by the operator.
INPUT discards any values remaining in the buffer from
previous IN, INPUT, or RUN statements, and requests new data
from the operator.
IN uses any values left in the buffer
first, then requests new data.
Unlike Dartmouth Basic, Basic/Debug accepts completely
general expressions as input.
It also accepts variables which
have already been assigned a value. A variable assigned a
value early in the list may be used to define a variable later
in the list. For example, the statement INPUT C,A can process
10,C*5 as valid input.
When a program requires the operator to input a list of
values, he may need to separate each item by a comma.
Commas
may be omitted if they are not needed to direct interpretation.
Spaces are ignored.
The following examples show how delimiters
may be used to change the interpretation of input values:
? %123,A,ND(56) (hex 123, variables A,N,D, decimal 56)
? %12 3AND(56) (hex 123A, variables N, D, decimal 56)
? %123, AND(56) (hex 123, value of 56 ANDed to itself)
Basic/Debug has only one input line buffer, INPUT
IN execute differently in the immediate and run mode.
In
the immediate mode, the user response overlays and destroys the
INPUT or IN command that requested it.
Consequently, no matter
how many variables are listed after the keyword INPUT, only the
first one is assigned to the input data.
However, IN may assign lists of variables and expressions
in the immediate mode if both lists are alternately included in
the command line.
For example:
IN A, 10, B , 1 5, C, 20
When the above line is executed in the immediate mode,
Basic/Debug fetches the first variable, A, from the keyboard
buffer, and advances the buffer pointer.
INPUT at this point
would request a new input line from the keyboard, but IN, which
uses all values in the buffer before issuing the "?" prompt,
will return to the buffer and assign the value 10 to A.
The
process continues until all variables and values are used up.
If the command line is closed with a variable, the "?" prompt
is issued.
Generally, it is easier to use LET to assign values to
variables in the immediate mode.
To help the operator enter the correct number and kinds of
values, IN and INPUT are usually preceded by a PRINT statement
describing the requirements. When the PRINT statement is
terminated with a semicolon, the INPUT prompt "?" will be
listed on the same line and appear to punctuate the message.
Although Basic/Debug does not support character string
functions, the INPUT command may be used to accept a single
letter as a user response, as shown below:
100 PRINT "PLEASE TYPE YES OR NO"
110 LET N=Y-1
120 PRINT "DO YOU UNDERSTAND";
130 INPUT N
140 IF N=Y THEN PRINT "GOOD!"
In this example, the value of Y does not matter.
If the
operator types Y, YES, YEAH, or YAH, then the variable N equals
Y.
If the operator type N, NO, or NOT YET, then variable N is
unchanged and not equal to Y.
To check for letters other than
Y or N, use an unusual value for Y, such as -32323, and check
both Y and Y+1 after input.
LET
Syntax:
let stmnt => [LET] left_part '=' expression'
left_part => variable I '@' factor I 'f' factor
Examples:
LET A = A+1
@ 1020 = 100
^8 = %100*C
LET assigns the value of an expression to a variable or
memory location.
The left portion of the statement may be any
alphabetic character A-Z, a memory reference, or a register
reference.
The value of the expression is either stored in the
memory location, or placed in the variable's storage location,
to be used at any subsequent appearance of the variable.
Because the equal sign makes the syntax of this command unique,
the LET keyword may be omitted.
A variable's value may be re-calculated by using the same
variable on both sides of the LET assignment, as in the
incrementing statement below:
LETB=B+1
LET may be used to store values in memory by using a
memory reference on the left side of the LET assignment, as
shown below:
LET@1024=B/2
When this statement is executed, the memory reference is
calculated first, then the expression is evaluated and its
value stored. A word memory reference stores the most
significant byte in the location addressed.
The least
significant byte is stored in the next higher address. Take
care when modifying internal registers or the area where the
program is stored in memory because improper changes could have
catastrophic results.
LIST
Syntax:
list stmnt => LIST [starting_line[',' ending_line]]
starting_line => expression
ending_line => expression
Examples:
LIST
LIST 200, 1000
This command is used in the interactive mode to generate n
listing of program lines stored in memory on the terminal
device. The optional line numbers specify the range of lines
to be listed.
If only one number is given, only that line will
be listed.
If ending line is included, only starting line
through ending line inclusive will be listed. A LIST-command
without arguments lists all the lines in the program.
The LIST command is generally used in the immediate mode,
however, it may be used in the run mode for simple text
processing. Because Basic/Debug does not examine program lines
after the line number until runtime, it can process text, as
shown in the following program:
100 REM THIS PROGRAM PRINTS A MESSAGE N TIMES
110 IF N>O THEN 200
120 : PRINT "HOW MANY TIMES";
130 : INPUT N
200 REM BEGIN LOOP
210 LET N=N-1
220 : LIST 1000, 1070
230 : IF N>O THEN 210
240 STOP
1000| This is a message saved in memory. It will be
1010|printed when the program is RUN. If you tried to
1020|execute lines 1000 to 1070 you would get an error
1030|message. But in this program, lines 1000+ are not
1040|executed, just LISTed.
1050|
1060| (Signed)
1070|
Five lines of this program are indented to show program
structure and make it easy to read. The colon prevents
Basic/Debug from removing the spaces before the statement
portion of the line. When the program is executed, the message
will be printed exactly as it appears in lines 1000-1070,
including the vertical bars along the left edge. The vertical
bar is needed to indent line 1000; the others are included for
consistency.
In summary, use a colon to indent an instruction
because Basic/Debug recognizes it as a statement delimiter, and
use the vertical bar to indent text lines because it is the
least distracting character to have printed down the left side
of a page.
NEW
Syntax:
new stmnt => NEW
Example:
NEW
The NEW command resets pointer R10-11 to the beginning of
user memory, thereby marking the space as empty and ready to
store a new program.
If this command is entered in error, take
heart, the stored program is not really gone.
Although it may
not be modified, it may at least be listed by setting the line
number of the first line back to a very small number.
Use a
LET statement in the immediate mode, as shown in the example
below:
LET ^^8=1
Although an attempt to run the program after this kind of
recovery may appear to work, there is no longer any memory
over-run protection, and the program may be destroyed.
PRINT
Syntax:
print_stmnt => PRINT [item (delimiter item)*] [delimiter]
=> initial_item (delimiter item)* [delimiter]
delimiter => ',' | ';'
item => quoted_string expression | HEX '('expression')'
initial_item => quoted_string signed_expression, | ('expression')'
quoted_string => '"' { any character sequence, not containing
nulls, deletes, linefeeds, carriage returns,
escapes, backspaces or quotes} '"'
Examples:
PRINT HEX (255)
"THE ANSWER IS ";X
(A*100)
+%800 + Z
PRINT A, B, C, D, E
The PRINT command lists its arguments, which may be text
messages or numerical values, on the output terminal. The
delimiters used in the argument specify how the items are to be
printed on the screen.
Characters and spaces enclosed in quotation marks are
listed exactly as they are typed.
Quotation marks are
unprintable.
If a message must be punctuated with a quotation
mark, use the single quote or apostrophe instead. As mentioned
above, a character string enclosed in quotation marks implies
the PRINT command, so the keyword may be omitted.
The PRINT
keyword without an argument or termInating delimiter generates
a blank line. Any PRINT instruction can be followed by a colon
and another statement.
When an expression is entered as the argument to the PRINT
command, Basic/Debug evaluates it and lists its decimal value
at the terminal. Only the significant digits are printedi
leading zeros and divisional remainders are not. PRINT treats
numbers as signed integers. A method for printing unsigned
values is presented in Section 2.5.
To PRINT a hexadecimal value, use the syntax:
PRINT HEX (expression)
Basic/Debug evaluates the expression, and prints its
positive hexadecimal equivalent. The PRINT command cannot list
a negative hexadecimal number.
Unlike character strings, the HEX function must be
preceded by the PRINT keyword, as must any expression beginning
with a variable. However, the keyword may be omitted before an
expression if the expression is preceded by a "+" or "_no For
example, -10 + 20 or +20 - 10 entered as statements print a
value of 10, but 20 - 10 results in an error message.
When a comma is used to delimit items in a PRINT
statement, a tab is generated between each item.
The tab stops
are located at eight-space intervals across the screen. To
print left-justified columns, simply put all the items to be
printed on one line in one PRINT statement, and separate them
by commas. The first character of the data item will appear in
the column containing the tab stop.
If the item is longer than
eight characters, Basic/Debug tabs to the next available stop
to print the next item.
To print one item directly after another without any
spacing, use a semicolon as a delimiter.
For example, the
command:
PRINT"OUTPUT=";X
will print the value of variable X immediately after the equal
sign.
If a PRINT statement is ended by a semicolon, no
carriage-return-linefeed is generated. The next item printed
py a subsequent statement will appear on the same line as the
item that preceded the semicolon. A comma at the end of a
PRINT statement will also suppress the carriage return
sequence, however, the next item to be printed appears at the
next eight column tab stop.
To print right-justified columns, as is necessary with
lists of figures, leading spaces must be added. Basic/Debug
can only print spaces enclosed in quotation marks. The
following example program adds leading spaces to N:
200 IF N<1000O THEN PRINT " ";
210 IF N<1000 THEN PRINT " ";
220 IF N<100 THEN PRINT " ";
230 IF N<10 THEN PRINT " ";
240 PRINT N
Basic/Debug can print most control characters such as the
bell if they are contained in a quoted character string. The
following control characters cannot be printed:
back space (^H)
escape or cancel (ESC)
carriage return (CR)
linefeed (LF)
delete (DEL)
null (NUL)
The circumflex, "^", indicates that the control key is
held down while the specified key is pressed.
Although control characters can be printed, most terminals
do not advance the cursor when the control character is
received. Therefore, Basic/Debug's cursor pointer may not
indicate the true position of the cursor after control
characters are printed. When this is the case, any attempt to
print in columns using the comma delimiter will fail.
For
example:
5 X=0
10 PRINT "X^G", X
20 PRINT "X", X
When the above program is executed, the following output
appears at the terminal:
X 0
X 0
The statement at line 10 inserts only seven spaces because
the control-G character pushed the cursor pointer one place to
the right of the cursor's actual position.
REM
Syntax:
rem_stmnt => REM {all following characters to the end of the line}
Examples:
REM CONTROL LOOP
REM SUBROUTINE NAME
REM CODE EXPLANATION
The REM command is used to insert comments, remarks, or
other explanatory messages into the code.
Basic/Debug ignores
anything following the REM keyword, therefore, REM and its
comment must be the last command on a line.
The liberal use of
remarks throughout a program makes it easier to read and
maintain.
However, remarks take space in memory, and should be
omitted for maximum space utilization.
RETURN
Syntax:
return stmnt => RETURN | RET
Examples:
RETURN
RET
RETURN is always the last instruction of a subroutine, and
may be abbreviated as RET.
It does not require an argument
because GOSUB stores the next line number where RETURN can find
it to restart normal sequential execution. RETURN must be the
last instruction on a line.
If one subroutine calls another, the RETURN instruction at
the end of the second subroutine returns execution to the first
subroutine.
In this way, subroutines may be nested to the
depth allowed by the memory available to the GOSUB stack.
RUN
Syntax:
run_stmnt => RUN [expression (''' expression)*]
Examples:
RUN
RUN 17, %200, 23
This command initiates sequential execution of all
instructions stored in memory. RUN is used only in the
immediate mode. Data values for the first IN command may be
entered, separated by commas, between the keyword RUN and the
terminating carriage return, as shown below:
RUN 45,-583
STOP
Syntax:
stop_stmnt => STOP
Example:
STOP
STOP gracefully ends program execution, and clears the
GOSUB stack. A STOP instruction is implied after the last
program line in memory, so a terminating STOP command may be
omitted from the program to save memory space.
Program execution is often ended abruptly by an error.
After altering the errant statement in the immediate mode, the
user may restart the run by using GOTO with the appropriate
line number, or reset the program with a STOP instruction, and
RUN the program again from the beginning.
Pointers R4‑5 and R6‑7 track the progress of the GOSUB
stack and the user program as they grow towards each other.
R4‑5 marks the top of the user program, plus a reserve that
buffers any potential collision with the stack. The NEW
command sets this pointer back to the beginning of the user
memory as indicated by pointer R8‑9, plus the stack reserve
indicated in the control block. The default size of the stack
reserve is 32 bytes, which should be enough for normal
operations. However, extended machine language programming or
deeply nested interrupts may require an increased reserve.
Section 7.1 contains instructions for altering the control
block.
Pointer R6‑7 marks the lowest address used for GOSUB,
which is the top of the stack.
It is also the base of the
machine-language/interrupt stack. These elements build down
from the GOSUB stack towards the program. However, because
there is no pointer register for the top of the machine
language stack, no error is generated if it overflows into
program area. An overflow error is only signaled when R6‑R7
crosses R8‑9.
This is why there is a stack reserve at the end
of the user program, and why an expanded reserve may be
necessary for extensive machine language subroutines and
interrupts.
Occasionally a page or more of memory may be needed for a
special application such as an I/O buffer. Once R8‑9, R10‑11,
and R12‑13 are set during the intialization procedure,
Basic/Debug never alters them. Therefore, areas of memory may
be reserved by changing these pointers with a LET statement.
For example, to save a block at the bottom of user memory, add
the desired length of the block to R8‑9.
The user program is
stored beginning at the address stored in R8‑9, leaving the
lower addresses for the application. To reserve an area
between the GOSUB stack and the variables, move R10‑11 down by
the desired amount.
To reserve a space above the variables, move R12 down.
R112 must be moved in multiples of 256 bytes. Changing R12 also
redefines all the variables so that none of them contain their
previous value. This characteristic may be used to make more
variables available, if used with caution. Whenever R12 is
changed, R10 must also be moved to keep the GOSUB stack clear
of the variables.
When the pointers at R8 or R10 are changed, a NEW command
must be entered to initialize all the other pointers that
depend on the altered values.
The pointer registers have the register number in the
least significant or odd-numbered byte, and the page number 00
in the most significant byte.
The GOSUB stack starts at R-103 and grows to R-58 before
signaling a stack overflow.
By the time the overflow occurs, variables M-Z will already be destroyed.
If deeply nested subroutines are used, it is safest to use only the first eight variables, A-H.
However, even these can be destroyed by machine language code.
Of course, if the program contains only simple expressions and few subroutines, all the variables are available.
To test if variables are being destroyed, set the last variable used to a known value, run the program, and see if it changes.
The first two bytes of the constant block must contain hex
0650.
The third byte of the constant block sets the size of the
stack reserve at the end of the user program in memory.
The
default value is 32 (hex 20), but an application using deeply
nested interrupts and many machine language subroutines may
require a larger reserve.
Basic/Debug compares every input character to the next two
bytes of the constant block because they are editing codes. The
code in the fourth byte causes Basic/Debug to adjust buffer pointer
R12-R13 to delete the previous character. Nothing is echoed except
the input character.
In immediate mode, the code in the fifth byte causes Basic/Debug
to cancel the content of the line buffer. When an input character
matches the content of xxx4, the pointer is reset to the beginning
of the line buffer.
In run mode, this code escapes the program by
returning error 0.
The last ten bytes of the block define the line separator
sequence. However, a maximum of only nine bytes can be sent to
the terminal at the end of each line because the line separator
must be followed by a hexadecimal FE before the sixteenth byte of
the block.
If a terminal requires more than seven pad
characters, a special data rate or other unusual format,
alternate I/O drivers must be supplied.
Instructions for using
external I/O drivers are given in Section 7.3.
To initialize the constant block, place its address in the
constant block pointer register R28-29. Use a simple LET
statement, for example, if the block is at 2000-200F (hex):
When the constant block and an auto-start program are stored in
ROM, include a statement early in the program to initialize the
constant block.
Basic/Debug uses the internal UART for all program and
data I/O. Applications programs may use other I/O, but
independently of Basic/Debug.
Figure 7-1. Interrupt Mask Register
External I/O drivers must conform to the following
requirements: They must pass a single ASCII input or output
character in R19 with the register pointer set to R16-3l.
Registers R4-R15 and R22-32 must be preserved. Location %1012
must contain a jump to the character input driver, and %1015 a
jump to the character output driver. The input routine must do
any necessary echoing, and the parity bit (bit 7) of all input
characters must be set to 0.
Drivers return to Basic/Debug with
a RETURN instruction (hex AF).
Whether or not external I/O drivers are enabled, though it
is of primary use when they are, the program execution can be
halted by setting user flag 1, which is the least significant bit
of the flag register (R252), to 1. Normally an interrupt-driven
input routine would be looking for an escape character in the
incoming data; if one comes up, the low bit in the flag register
would be set to one. Note that user flag 2 should not be altered
by the I/O routines.