It currently works with DOS XL by just entering TCL and hitting return.
It should work with other DOS systems but it may be necessary to specify
the run address yourself. The run address is 0x2600.
There are probably many errors in this document, since it was last update
a long time before my last version of the compiler (1986). I have just
update a few areas I knew were wrong but memories fade and I have probably
missed some bits.
If you have any problems or queries regarding this documentation send an
Email message to me and I'll find the answer and update this guide.
E-Mail: david@signus.demon.co.uk
Test Computer Language, Version 2.2
Table of Contents
- Introduction
- System requirements
- Syntax conventions
- Editor Commands
- BOOT
- COMPILE
- DOS
- ENTER
- LIST
- LOAD
- NEW
- RENUMBER
- RUN
- SAVE
- SIZE
- Compiler Commands
- AFTER
- ASCII
- BEGIN
- CLOSE
- COLOUR
- CODE
- DO
- DPOKE
- DRAWTO
- ELSE
- ELSE IF
- END
- END DO
- END IF
- END WHILE
- ERROR
- EVERY
- FAST
- FILL
- FLOAT
- FUNCTION
- GET
- GOSUB
- GOTO
- GRAPHICS
- IF
- INCLUDE
- INPUT
- IRQ OFF
- IRQ ON
- LOCAL
- MOVE
- OPEN
- PLOT
- POINTER
- POKE
- POP
- PRINT
- PROCEDURE
- PULL
- PUSH
- PUT
- REPEAT
- RESERVE
- RETURN
- SETCOLOUR
- SLOW
- SOUND
- TRAP
- WHILE
- WRITE
- UNTIL
- VARIABLE
- Assembler Commands
- JMP
- JSR
- PHA
- PHP
- PLA
- PLP
- RTI
- TAX
- TAY
- TSX
- TXA
- TXS
- TYA
- Compiler Directives
- ;
- .LIST
- .NOLIST
- .MAP
- .NOMAP
- Compiler Expressions
- Operators
- Operator Precedence
- Memory Usage
- Limitations
- Depth of Stack
- DO and WRITE
- AFTER and EVERY
- Some useful Functions
- DPEEK
- LOCATE
- NOT
- PADDLE
- PEEK
- PTRIG
- RND
- STICK
- STRIG
- VAL
- Floating point procedures
- ADD
- DIV
- EQUALS
- EXP
- EXPe
- LOG
- LOGe
- MULT
- SUB
- FP Library Code
- Error Codes
- Known Bugs
Introduction
This language has been designed for the programmer with an in-depth knowledge
of ATARI's 8 bit computers, also it may be useful to know a little 6502
machine code, to help extend the language via user defined functions and
procedures.
This language will also be of use for somebody starting to learn 6502 machine
code as small ( or large ) routines can be included within the main program.
NOTE: Since it will not be clear where in memory your machine code will go,
any machine code must be re-locatable. It is possible to locate the
code by preceding it with a pointer definition, the defined variable
will contain the address of the code.
System requirements
This language requires an ATARI 8 bit computer with at least 24K of memory
and a disk drive.
Syntax Conventions
The following conventions are used in this manual when defining the syntax
of a command :-
1. Capital letters designate the names of the procedures or functions and
must be typed in exactly as shown ( eg. LIST, COMPILE, AND, GOTO etc).
2. Lower case letters specify the type of argument to the commands :
lno - A label number between 1 and 65535, inclusive.
hxnum - A string of hexedecimal numbers.
dcnum - A positive decimal number.
exp - Any valid expression.
string - A string of ASCII characters enclosed in double quotes ( eg.
"String of Characters").
adr - The address of some data, adr may be an expression.
3. Items enclosed within square brackets denote an optional part of the syntax
( eg. exp [,exp...] ). When an optional item is followed by ... the item
may be repeated as many times as needed.
Editor Commands
BOOT
Purpose: To compile the source program directly to a BOOT Disk
Syntax: BOOT
Before pressing return insert a blank formatted disk in D1: the compiled
program will be written to the disk as a single part boot disk. The
disk image can then be copied onto a standard multiboot type menu.
COMPILE
Purpose: To compile the source program.
Syntax: COMPILE [ #file1 ] [ ,#file2 ]
This command will call the compiler which will go through the program line
by line, converting it into machine code. If file1 is specified the object
code will be created and sent to file1, together with a small runtime
package ( about 1.5K ). If file2 is specified the listing will be produced
and sent to this file2.
In the process the compiler will check the syntax of the commands in the
source code, and check that labels have not been defined twice or
referenced when they don't exist. Note that this is a two pass compiler
and therefore it will not matter where the labels are defined.
After the program has been compiled, an address map will be produced if
file2 has been specified.
If an error has been detected the compiler will issue an error message and
will then continue to create the object code. If after receiving an error
you run the program, the results may be unpredictable.
The compiled program should be given a file extender of '.COM' then the
program can be run from dos just by entering the name of the program. The
run address of the Program will always be $260E.
DOS
Purpose: To return to the disk operating system.
Syntax: DOS
This command will return you to the disk operating system. The compiler may
be re-entered by simply typing RUN in a memory resident dos, such as
Sparta Dos or Dos XL, or by typing RUN 2600.
ENTER
Purpose: To merge source code from file with loaded source code
Syntax: ENTER #filespec
LIST
Purpose: To list a program to a device.
Syntax: LIST [ #filespec, ][ dcnum1 [ ,dcnum2 ] ]
This command will list the source program to the specified device. If a
device is not specified, the screen editor will be used as default. If only
dcnum1 is specified, then only that line will be displayed, but if both
dcnum1 and dcnum2 are specified, all the lines between and including dcnum1
and dcnum2 will be listed. When dcnum1 and dcnum2 are not specified, the
complete source program will be listed out to the required device.
Example: LIST #P:,2000,2050
This will list all the lines between 2000 and 2050 inclusive to the printer.
LOAD
Purpose: To reload a stored source program into memory.
Syntax: LOAD #filespec
This command will first clear the program that currently resides in memory,
and will then load the previously saved source file into memory, from the
specified filespec.
NEW
Purpose: To erase program in editors memory.
Syntax: NEW
This command is used to clear an old program out of memory, before starting
to enter a new program. Once this command has been issued, the program
cannot be retrieved, and therefore it must be saved to disk if it will be
needed again.
RENUMBER
Purpose: To renumber all line numbers ( not labels )
Syntax: RENUMBER [ dcnum1 ] [ ,dcnum2 ]
Used to renumber all the editors line numbers (not label numbers).
If no dcnums are specified the source program will be renumbered starting
from line 10 in increments of 10. If dcnum1 is specified, this will be
taken as the start lines number, and if dcnum2 is specified, this will be
taken as the increment. The renumber command is mainly used to insert
spaces between line numbers, so that lines can be inserted between them.
Example: RENUMBER 1000,10
This will renumber the current program from line 1000 in increments of 10.
RUN
Purpose: To execute the program without creating an object file.
Syntax: RUN
This command is similar to the COMPILE command, except that no files may be
given. When the compile is in run mode it must perform a third pass on the
sourc program to determine a safe place to store the object code.
NOTE: If any errors are detected, the compile program will not be run.
SAVE
Purpose: To save a source program.
Syntax: SAVE #filespec
Used to save a program so that you can resume editing it at a later stage.
SIZE
Purpose: To display remaining memory
Syntax: SIZE
Used to find out how much memory is left for use with the COMPILER. If you
start to run out of memory you can save the current file, and INCLUDE it
in the main program, this will give more memory for the compiler to build
the symbol tables.
Compiler Commands
AFTER
Purpose: After time period, go to address
Syntax: AFTER ( exp, adr )
When this command is executed it sets up one of the count down timers to
count down from the value of exp. When the timer reaches zero control will
be passed to 'adr' which is an address of some machine code, or commands
in this language. The called routine must execute a RETURN command to
resume normal proccessing. If a return is not used the stack could quickly
overflow causing the program to crash. To avoid this you could reset the
stack pointer to $FF ( LDX #$FF : TXS ), but if this is done, it is the
same as the program, being totally restarted from the current point (all
return address will have been lost). The time may range from 1 to 65535
where 1 is 1/50th Second.
Example: SOUND (0,100,10,10)
AFTER (10,SOUNDOFF)
REST OF PROGRAM
POINTER SOUNDOFF
SOUND (0,0,0,0)
RETURN
This will switch on the sound channel and continue to process the rest of
the program. Then after 10/50th of a second the program will call 'SOUNDOFF'
which switches the sound off, and returns back to the main program.
ASCII
Purpose: To include ASCII text in program.
Syntax: ASCII string
This command enables ASCII text to be placed in the code, which can be used
for filenames etc. The command must be positioned so that it will never be
executed as this will make the program crash. If necessary jump over the
text with a GOTO command.
Example: GOTO 10
POINTER FILENAME
ASCII "D:DISKFILE.DAT"
10 OPEN (1,FILENAME,4,0)
This will store the characters "D:DISKFILE.DAT" in memory. These characters
are accessed by defining a pointer just before them. The program opens
the disk file with via the pointer.
BEGIN
Purpose: To define the start of the program
Syntax: BEGIN
This command allows you to start the program execution from any point in the
source code. There must be one, and only one BEGIN statement in the program.
If at runtime the program reaches the associated END statement the program
will either 1. Return to the language (if RUN command was used), 2. Return
to DOS (if loaded from DOS) or 3. REBOOT (If booted from disk).
CLOSE
Purpose: To close an IOCB channel.
Syntax: CLOSE (exp)
This command will close the specified IOCB, which will allow it to be used
again at a later time. The exp must evaluate to between 0 and 7 although
if it is out of range it will be truncated & no error will be issued.
Example: CLOSE (1)
OPEN (1,FILENAME,4,0)
This ensures that channel one is closed before you try to re-open it.
COLOUR
Purpose: To select a new colour
Syntax: COLOUR (exp)
This command (note the ENGLISH spelling) is used to select a new colour
register. The colour is used to select what value will be stored on the
screen. The graphics hardware will interpret this value differently from
one graphics mode to another. In text modes it will select a character,
and in graphics mode it will select a colour for each screen pixel. The
pen colours may be changed by the SETCOLOUR command.
CODE
Purpose: To enter hexedecimal data.
Syntax: CODE hxnum [ hxnum... ]
This command will enable you to enter hexedecimal data into memory at the
current memory location (at compile time). This command enables you to
include machine language directly in the program. Values can be passed to
and from the routine using the PUSH & PULL commands.
Example: CODE A9008DC602
; LDA #0
; STA $2C6
This places the code to change the screen colour to black in memory. The
comments after give the assembler source code (not required).
DO
Purpose: Repeat some code a given number of times
Syntax: DO var = exp1, exp2, exp3
This command is used to repeat a loop a given number of times. The exp1
is the initial value, exp2 is the termination number, and exp3 is the
increment the control variable takes each time round the loop.
Note that an increment of 65535 is equal to -1 allowing you to count down.
Example: DO X=1,10,1
WRITE (X)
END DO
This will cause the 'X' variable ( control variable ), to take the values
1 through 10, and write them to the screen.
DPOKE
Purpose: To store values in memory
Syntax: DPOKE (adr,exp)
This command will store a 16 bit number denoted by the values of exp, into
the specified memory address. The 16 bit number will be stored low byte
first and high byte at adr+1.
Example: POINTER RESET
DPOKE (2,RESET)
POKE (9,2)
This will store the address of reset at memory address 2 and then change
memory address 9 to indicate cassette boot. This will cause execution
begining again at RESET when the reset key is pressed.
DRAWTO
Purpose: To draw a line on the screen
Syntax: DRAWTO (exp1,exp2)
This command will draw a line from the current graphics cursor position,
using the last colour selected to the location of exp1 and exp2. exp1 is
the 'X' coordinate and exp2 is the 'Y' coordinate.
Example: GRAPHICS (8+16)
COLOUR (1)
DO X=0,319,1
PLOT (X,0)
DRAWTO (X,191)
END DO
This selects graphic mode 8 without a text window using colour 1. Then
the program will fill the screen going from left to right.
ELSE
This command is used within a conditional IF block, and will cause all the
code after it up to the END IF statement, to be executed, if the IF or
all ELSE IF conditions evaluated to FALSE.
ELSE IF
This command is used within a conditional IF block, and will cause all the
code following it, up to the next ELSE IF, ELSE or END IF (at the same
level of nesting) to be executed, if the expression evaluates to TRUE,
and the expression in the IF, and any preceding ELSE IF statements
evaluated to FALSE. There must be a space between ELSE and IF.
END
Purpose: To execute a cold start/Terminate Function
Syntax: END
This command is used to terminate a block of instructions. If it terminates
a function, the function returns to the calling statement. If it is used
outside a function (terminating the BEGIN statement) it will perform
a coldstart.
END DO
Purpose: To define end of DO loop.
Syntax: END DO
This command terminates the current DO loop. It must always be lower down
the source program than its associated DO command. There must be a space
between END and DO.
Example: DO X=1,10,1
WRITE (X)
END DO
This will loop round and take the values of X from 1 up to and including 10.
Note that the loop will not be terminated until the X variable has had the
value of ten when the END DO is reached. If the X increment was 2, the X
variable would never reach 10 & therefore the loop would NEVER terminate.
END IF
This command is used to terminate a conditional IF block. There must be
a space between END and IF.
END WHILE
This command is used to terminate a WHILE exp DO block. When the expression
in the WHILE command evaluates to FALSE the program continue after the
END WHILE command. There must be a space between END and WHILE.
ERROR
Purpose: To force a runtime error
Syntax: ERROR exp
This command will allow a your programs to generate a runtime error.
This error is trapable in the normal way.
EVERY
Purpose: Every time period gosub address
Syntax: EVERY ( exp, adr)
This command is identical to the AFTER command exept that the interupt will
occur every x/50ths of a second. The interrupt can be disabled by issuing
the command with a time of zero.
FAST
Purpose: To increase the execution speed
Syntax: FAST
This command will increase the execution speed of the program. It does this
by disabling all interupts and by switching the screen display off. This
should be used while the screen display is not required, and then by
executing a SLOW command at the end.
Example: FAST
Y=0
DO X=1,5000,1
Y=Y+1
END DO
SLOW
WRITE (Y)
This program first switches the screen and interupts off. Sets the 'Y'
variable to 0, and then adds 1 to 'Y' 5000 times. The screen and interupts
are then re-enabled and the value of 'Y' is displayed on the screen.
FILL
Purpose: Fill an area of memory with a value.
Syntax: FILL (adr, exp1, exp2)
This command fills an area of memory from memory location adr for exp1
consecutive locations with the low byte value of exp2.
Example: FILL (1636,256,0)
This fills page 6 (memory locations 1536 to 1791 inclusive) with a value
of zero.
FLOAT
Purpose: To place a floating point number into memory
Syntax: FLOAT const [ ,const ... ]
Allow you to place a floating point number into memory at the current
memory address. The number can be located by placing a pointer variable
directly before the FLOAT command. Although the compiler does not support
floating point numbers, they can be implemented through the use of
procedures and functions (see section on floating point procedures), but
they cannot be used in expressions. ie. you could define an add command
(ADD (destination,source)) which could add the floating point number at
the address pointed to by source to the number pointed to by destination,
with the result stored at destination.
FUNCTION
Purpose: User defined functions with arguments
Syntax: FUNCTION lblnm (var1 [ ,var2....] )
Since their are no inbuilt functions in the language, this command enable
you to define your own. The function will be called lblnm and a variable of
the same name will also be automaticaly set up to contain the result.
The arguments will be given values when the routine is called. The result
of the function is passed back to the calling routine by assigning the value
to the functions name. The function is terminated by executing an END
command.
Example: VARIABLE X
FUNCTION TEST (X)
TEST=X*2
END
;
VARIABLE Y
BEGIN
Y=TEST(5)
WRITE (Y)
END
This will cause the value of 10 to be printed on the screen.
GET
Purpose: To get recieve some data from an IOCB
Syntax: GET (exp1, adr, exp2)
This command is used to receive some data from the IOCB specified by exp1,
this may be in the range of 0-7 but will be truncated if required. The
command will recieve exp2 bytes from the IOCB and store them in consecutive
memory locations starting with adr.
Example: POINTER KEYBRD
ASCII "K:"
POINTER KEYPRESS
RESERVE 5
;
BEGIN
OPEN (1,KEYBRD,4,0)
GET (1,KEYPRESS,5)
PRINT (0,KEYPRESS,5)
CLOSE (1)
END
This program inputs 5 characters from the keyboard, and store them at
'KEYPRESS'. The characters will then be printed out via the screen editor.
GOSUB
Purpose: To call a subroutine.
Syntax: GOSUB lblnm
Argh not GOSUB. I wouldn't even it in a language today!
Anyway it enable you to call a label number directly. To return from the
subroutine a RETURN command must be executed. This command can be useful
to save rewriting similar pieces of code more than once.
Example: VARIABLE X
BEGIN
X=1
GOSUB 10
X=2
10 WRITE ("X = ",X)
END
This program will first write out the value 1 followed by the value 2. In
this case the END has the same effect as a return statement.
GOTO
Purpose: To change flow of program
Syntax: GOTO lbl
Oh no! another one!
This command executes in the same way as the GOSUB command, exept that it
does not expect a RETURN command.
Example: VARIABLE X
BEGIN
X=0
10 IF X<>5 THEN
X=X+1
GOTO 10
END IF
WRITE (X)
END
This program loops until X is equal to 5, and then it goes to label 20 and
write out the current value of 'X' (5) before returning control to DOS.
GRAPHICS
Purpose: To change screen mode
Syntax: GRAPHICS (exp)
This command will call the operating system to set up the required graphics
mode using IOCB 6. Normaly the screen will be set up in a split screen mode,
but by adding 16 to exp, the screen will be set up without a split screen.
Adding 32 to the exp will cause the screen to be set up without clearing
the screen memory.
Example: GRAPHICS (8+16)
This command will set up the high resolution one colour mode (320 by 192)
without a text window using IOCB 6.
IF
Purpose: To make decisions
Syntax: IF exp THEN (or DO)
This command starts a conditional block of code. The first block will be
executed if the expression is TRUE (non zero low byte value), otherwise
the program will resume after the ELSE, ELSE IF (if exp true) or END IF
Example: VARIABLE X
BEGIN
X=0
WHILE X<3 DO
X=X+1
IF (X=1) THEN
WRITE ("ONE")
ELSE IF X=2 THEN
WRITE ("TWO")
ELSE
WRITE ("THREE")
END IF
END WHILE
END
INCLUDE
Purpose: To include source programs from a file
Syntax: INCLUDE #filespec
This command will INCLUDE the specified file name in with the code as it
is being compiled. This can be used to bring in library routines, or it
may be used to build large programs, where it is not all resident at the
same time.
Example: VARIABLE X
INCLUDE #D:PEEK.FUN
BEGIN
X=PEEK (20)
WRITE (X)
END
This program includes the file D:PEEK.FUN into the main program at compile
time (if it exists on the disk).
INPUT
Purpose: To input records terminated with an end of file.
Syntax: INPUT (exp1, adr, exp2)
This command is used to input records terminated with an end of file marker.
exp1 is the IOCB to use, adr is the address where the recieved data is to
be stored and exp2 is the maximum number of bytes that can be in the record.
Any extra bytes will be ignored.
Example: POINTER TEXT
RESERVE 10
BEGIN
INPUT (0,TEXT,10)
PRINT (0,TEXT,10)
END
This program enters up to ten bytes from IOCB 0 (screen editor) and store
them at TEXT. The program then PRINTs it out.
IRQ OFF
Purpose: Disable interupt requests
Syntax: IRQ OFF
This command ensures that no interrupts can occur. It disable both the
EVERY and the AFTER interrupts. The non maskable interupts are not be
affected.
IRQ ON
Purpose: Enable interput requests
Syntax: IRQ ON
This command enables all the interrupt requests again.
LOCAL
Purpose: Define a new local variable region
Syntax: LOCAL
This command defines the start of a new local variable region. A variable
defined as being local is only available for use in the local region it
was defined in. Up to 250 local regions may be used. Local variables are
defined by preceding the variable name with a '?' character.
Example: LOCAL
VARIABLE ?X
BEGIN
?X=2
GOSUB 10
WRITE (?X)
END
LOCAL
VARIABLE ?X
10 ?X=6
RETURN
This program defines two local regions both with the variable 'X' defined.
In the first it is set to 2, and in the second it is set to 6. While the
program is executing in the first local region 'X' will have the value of
2. Therefore the number 2 will be written to the screen by the WRITE
statement.
MOVE
Purpose: To move blocks of memory around
Syntax: MOVE (adr1, adr2, exp)
This command moves exp bytes from adr1 to adr2. Care must be taken so that
an overlap of adr1 and adr2 does not occur.
Example: MOVE (1536,1792,256)
The above command will move all of page 6 into page 7, leaving page 6
un-change.
OPEN
Purpose: Open a input / output file
Syntax: OPEN (exp1, adr, exp2, exp3)
This commands opens an input or output file. exp1 is the IOCB to use,
adr is an address that contains the name of the file to open, exp2 holds
the input/output operation and exp3 holds a device dependent auxiliary code.
Valid values for exp2 are:-
4 = Input operation
6 = Disk directory operation
8 = Output operation
9 = End of file append (output)
12 = Input and output operations ( together )
Example: LOCAL
VARIABLE ?IOCHAN
POINTER ?FSPEC
ASCII "D:*.*"
POINTER ?TEXT
RESERVE 20
PROCEDURE DIR (?IOCHAN)
CLOSE (?IOCHAN)
OPEN (?IOCHAN,?FSPEC,6,0)
TRAP 65532
65530 INPUT (?IOCHAN,?TEXT,20)
PRINT (0,?TEXT,20)
GOTO 65530
65532 CLOSE (?IOCHAN)
POP
TRAP -1
END
This procedure displays the disk directory on the screen using the supplied
IOCB.
PLOT
Purpose: To plot a single point on the screen
Syntax: PLOT (exp1, exp2)
This plots a single point on the screen using the last selected colour.
exp1 holds the 'X' coordinates and exp2 holds the 'Y' coordinates.
Example: VARIABLE X
BEGIN
GRAPHICS (11)
DO X=0,79,1
COLOUR (X MOD 16)
PLOT (X,0)
DRAWTO (X,191)
END DO
10 GOTO 10
END
This program set up graphics mode 16 and then draw bands of colour going
from the top to the bottom of the screen.
POINTER
Purpose: To locate a section of the compiled code.
Syntax: POINTER lblnm
This command defines a variable, but instead of the variable being
initialised to zero, it is initialised to the value of the next address.
This allows you to locate parts of the compiled code (text, data and buffers
etc).
Example: POINTER Filename
ASCII "D:FILE.DAT"
BEGIN
OPEN (1,Filename,4,0)
Rest of program
CLOSE (1)
END
This program will open a file called D:FILE.DAT, and then continue and
execute the rest of program.
POKE
Purpose: To store values in memory
Syntax: POKE (adr,exp)
This command stores an 8 bit number denoted by the low byte of exp at
memory address adr.
Example: POKE (710,0)
This stores a zero at memory address 710, which in this case turns the
screen black.
POP
Purpose: To clear values off stack
Syntax: POP
This command pops a 16 bit number off the stack. This can be used to remove
unwanted return addresses or parameters from stack.
Example: GOSUB 10
rest of program
10 IF (EXIT) THEN
RETURN
END IF
POP
continue program here
In this case the POP command has the effect of turning the GOSUB 10 into
a GOTO 10 (ie. once it has been POPed off the stack you cannot return ).
PRINT
Purpose: To print out a buffer
Syntax: PRINT (exp1, adr, exp2)
This command prints a buffer to a given device. The buffer is considered
to be empty when either an end of file is found in the data or when the
maximum number of bytes has been sent. exp1 holds the number of the IOCB
to use, adr holds the address of the data buffer, and exp2 holds the
maximum number of bytes in the buffer.
Example: POINTER BUFFER
RESERVE 10
BEGIN
INPUT (0,BUFFER,10)
PRINT (0,BUFFER,10)
END
This program enters up to 10 characters from the screen editor, and output
up to 10 characters to the screen editor.
PROCEDURE
Purpose: To add new commands to the language
Syntax: PROCEDURE lblnm (var1 [,var2...] )
Defines the start of a new command. The new command may be called just like
any of the resident commands (ie. by typing its name followed by correct
number of arguments). A procedure is terminated by an END statement.
Example: LOCAL
VARIABLE ?EXP
PROCEDURE WriteEXP (?EXP)
WRITE (?EXP)
END
;
BEGIN
WriteEXP (5+6*7*100/2)
END
This procedure allows you to directly write an expression to the screen.
Normally you would have to calculate the value in a tempoary variable
before writing it out.
PULL
Purpose: To obtain values off the stack
Syntax: PULL (var1 [,var2...] )
This command causes a number of 16 bit values to be pulled off the stack
(one for each variable specified). The first number pulled off the stack
will be used as the high byte and the second byte as the low byte.
Example: PUSH (A,B)
PULL (A,B)
This has the effect of swapping the values of 'A' and 'B'. (since 'A' is
pushed on First and 'B' is pushed on second, 'B' is the first one pulled off,
and it is stored in 'A' )
PUSH
Purpose: To place 16 bit values on stack
Syntax: PUSH (exp1 [,exp2...] )
This command will allow you to be able to push values onto the 6502 stack
for use by your machine language routines etc. The low byte will be stored
on the stack first followed by the high byte of the expression. For an
example see the previous command ( PULL ).
PUT
Purpose: To send some data to a file
Syntax: PUT (exp1, adr, exp2)
This command will put the data starting at memory address adr for exp2
consecutive memory locations to the IOCB specified by exp1.
Example: POINTER Return
CODE 9B
BEGIN
PUT (0,Return,1)
END
This will send an EOL ( End of line ) character to the editor.
REPEAT
Purpose: Repeats a loop until a condition is met.
Syntax: REPEAT
This command is used in conjunction with the UNTIL command, and allows you
to repeat all the lines between the 'REPEAT' command and the 'UNTIL' command
until a given condition evaluates to true (1).
Example: REPEAT
X=X+1
WRITE (X)
UNTIL X=10
This causes the loop to be repeated until the 'X' variable has a value of 10.
RESERVE
Purpose: To reserve some memory
Syntax: RESERVE dcnum
This reserves a specified number of bytes within the compiled program for
use as buffers etc.
Example: RESERVE 10
This will reserve 10 bytes in memory, there are no restrictions as to what
this space is to be used for, but the program must never execute this
statement, unless you know there is a machine langauge file stored there.
Usually this command will be preceded with a POINTER definition so that you
can locate the reserved memory.
RETURN
Purpose: Return from a routine
Syntax: RETURN
From inside the main program (not in a subroutine etc) this command will
return you to DOS. This command is also used to return from a GOSUB.
SETCOLOUR
Purpose: Change a colour registers value
Syntax: SETCOLOUR (exp1, exp2, exp3)
This command is used to define a new colour for the specified colour
register. exp1 holds the colour register ( 0 to 8 ) where register 0 is
address 704, 1 is address 705 etc. exp2 holds the new colour and exp3 holds
the luminance of the colour. Only the lower 4 bits of both exp2 and exp3
have any significace.
SLOW
Purpose: Enables screen display and interupts
Syntax: SLOW
This command is used to bring the computer out of fast mode. (ie. switch
the display and interupts on again). For an example see the FAST command.
SOUND
Purpose: Control sound voices
Syntax: SOUND (exp1, exp2, exp3, exp4)
This enables you to use the ATARI's sound registers. exp1 holds the voice
number (0 to 4), exp2 holds the frequency (0 to 255), exp3 holds the
distortion level (0 to 15) and exp4 holds the volume (0 to 15)
TRAP
Purpose: To trap input / output errors
Syntax: TRAP (lno)
This command re-direct the program to your error handling routine should
an error be detected. The error code will be stored at location 195
(as in basic). If the supplied label number is invalid or missing, the
default error routine is used. This default handler outputs a message
giving the error number and the approximate address where the error
occured. With reference to the compilation address map you should be able
to identify the approximatly line in error. A user defined error handler
may return to the source line after the error by executing a RETURN
command. If the program should continue without returning to the line
after the error, you must execute a POP command to clear the stack
(as in the definition of the DIR procedure). The only statement that you
can't return to is after it has happend in a WRITE statement.
WHILE
Purpose: Execute a block of code while the expression is TRUE
Syntax: WHILE exp DO
This commad will first evaluate the expression, if the result is TRUE
(low byte of result is non zero) the following code up to the END WHILE
at the same nesting level will be executed, the program will then loop
round and test the expression again. If the expression is FALSE, the
program will continue on te line following the END WHILE command.
eg. VARIABLE 53279=CONSOL
BEGIN
WHILE (CONSOL.AND.255)=7 DO
WRITE ("PRESS OPTION, SELECT OR START")
END WHILE
END
WRITE
Purpose: Write data and variables to device
Syntax: WRITE [ dcnum, ] (string/var/const[,string/var/const...]) [ ; ]
This command will write out the data to the IOCB specified by dcnum. If
dcnum is not given the default IOCB is zero (screen editor). All items to
be printed must be seperated by commas. If there is a ';' character
following the close bracket, no end of line will be written to the
device. Normally when writting the value of a variable, the value will be
integer but by preceding the write statement with a F (FWRITE) all the
following variables will be taken as pointers to floating point numbers,
and the floating point number will be printed out instead.
Example: VARIABLE A
POINTER PI
FLOAT 3.142
BEGIN
A=25
WRITE ("The value of 'A' is ",A)
WRITE ("The value of 'A' is ");
WRITE (A)
FWRITE ("PI = ",PI)
END
This short program will write out 'The value of 'A' is 25' twice to the
default device (screen editor). Note the use of the ';' for the second
WRITE command. Then the program then prints 3.142.
UNTIL
Purpose: Terminate REPEAT UNTIL loop
Syntax: UNTIL exp
This command is used to terminate a REPEAT UNTIL loop structure, and can
be used so that a loop will REPEAT, UNTIL a condition is true (1).
Example: VARIABLE 53279=CONSOL
BEGIN
REPEAT
rest of loop
UNTIL (CONSOL .AND. 255)=6
END
This loop will be repeated until the low byte value of CONSOL is equal to 6
(ie. the start key has been pressed)
VARIABLE
Purpose: To manipulate numeric data.
Syntax: VARIABLE [ dcnum= ]lblnm [ ,[ dcnum= ]lblnm...]
This command is used to define some variables. A variable is a name that
represents a numeric value. This numeric value may be changed by an
assignment statement. If the lblnm (label name) is preceded by 'dcnum='
then this dcnum will be taken as the address of the variable. If dcnum is
not specified, then the compiler will select its own memory address.
Defining your own memory locations for the variable will give you the
ability to manipulate these locations. Care must be taken when using these
variables as you must take into consideration the other half of the word
(if you are only using a byte). A local variable is defined by the first
character of the variable name being a '?' character.
Example: VARIABLE 53279=CONSOL, 53248=HPOSP0
To access low byte of CONSOL you must mask out the high byte with a bitwise
'.AND.'opperation.
VALUE = CONSOL .AND. 255
To access the high of CONSOL you must divide divide by 256.
VALUE = CONSOL / 256
To change the low byte (only) of HPOSP0 (53248), their is a special character that
you place in from of the variable that is about to be assigned.
the high byte is change in the same way but with a different character
preceding the variable name. In this case address 53249.
>HPOSP0=25
In addition, the result of the expression may be stored at the addressxi
pointed to by the value of the variable by preceding the variable name with
an '@' character, you may still use the '<' or '>' character as well, to
change only the low byte or high byte of the address pointed to by the
variable.
eg. to fill a block of memory without the fill command you may use any of
the following examples.
VARIABLE ADR
BEGIN
DO ADR=1536,1791,1
<@ADR=0
END DO
DO ADR=1536,1790,2
@ADR=0
END
END
Assembler Commands
Inside the language there are several assembler instructions defined, these
commands were added to make it easier to interface with a machine code
program.
Example: JSR $E456 ( in decimal )
TYA
PHA
PHA
PULL (STATUS)
IF (STATUS .AND. 255)<>136 THEN
RETURN
END IF
ERROR 136
This would call address $E456 and push the status onto the stack. The pull
command then places it in the variabe 'STATUS' and test the low byte for
being 136 (end of file). If the end of file has been reached a runtime
error will be generated. These commands are exactly the same as the
assembler commands of the same names. Reference 6502 manual for further
details.
JMP
Purpose: Jump to a machine language routine
Syntax: JMP dcnum
JSR
Purpose: Jumps to a machine language subroutine
Syntax: JSR dcnum
PHA
Purpose: Pushes accumulator onto stack
Syntax: PHA
PHP
Purpose: Pushes status register onto stack
Syntax: PHP
PLA
Purpose: Pulls accumulator off stack
Syntax: PLA
PLP
Purpose: Pulls status register off stack
Syntax: PLP
RTI
Purpose: Return from non-maskable interupt
Syntax: RTI
TAX
Purpose: Transfers 'A' into 'X'
Syntax: TAX
TAY
Purpose: Transfers 'A' into 'Y'
Syntax: TAY
TSX
Purpose: Transfers stack pointer into 'X'
Syntax: TSX
TXA
Purpose: Transfers 'X' into 'A'
Syntax: TXA
TXS
Purpose: Transfers 'X' into stack pointer
Syntax: TXS
TYA
Purpose: Transfers 'Y' into 'A'
Syntax: TYA
Compiler Directives
;
Purpose: To place comments within the program
Syntax: ;Any characters
This directive will enable you to place comments within your source program.
These comments will be ignored when the program is compiled, and will not
be included in the object code.
.LIST
Purpose: To enable listing during compilation
Syntax: .LIST
This directive tells the compiler to generate a listing. If a list device
is specified in the COMPILE statement. This is the default condition.
.NOLIST
Purpose: To stop a listing from being produced.
Syntax: .NOLIST
This directive stops the listing from being produced. It can be turned
back on by using the .LIST directive.
.MAP
Purpose: To produce a memory map of program
Syntax: .MAP
This directive tells the compiler to produce a memory map. A memory map
will list the names of global variables, functions, procedures and line
labels together with the address in memory. The labels will be listed
in the order they where defined.
.NOMAP
Purpose: To stop the memory map from being produced.
Syntax: .NOMAP
This command will stop the memory map from being produced at the end of
the compilation. The option can be switched back on by a .MAP instruction
anywhere else up to the end of the program.
Compiler Expressions
An expression is a valid combination of operands and operators which the
compiled object code will evaluate to a 16 bit unsigned integer number.
No error detection is made for an overflow. Since each variable is a 2 byte
word (16 bits) each variable can hold a number from 0 to 65535 inclusive.
Operator: ( )
These operators will force everything inside the brackets to be evaluated
before anything outside them. This will enable you to force the expressions
into being evaluated in a different order.
Operator: [ ]
These operators will force everything in the brackets to be executed in the
order they are given. The brackets may not be nested, and there may only be
the '+' and '-' operator's included in the brackets, along with constants
and variables, in addition there are no function calls allowed. These
operators where added to provide a facility for very fast addition and
subtraction of numbers. The stack is not used at all resulting in
very fast code.
Operators: * / MOD + -
These operators are the normal arithmetic operators.
'*' Multiplication
'/' Division
'MOD' Returns remainder
'+' Addition
'-' Subtraction)
They perform 16-bit unsigned integer arithmetic, and will ignore overflows.
Operators: = =< < <> > >=
These operators are used for comparisons and will return one if the result
is true, and zero if the result is false.
'=' .EQ. is equal to.
'=<' '<=' .LE. is less than or equal to
'<' .LT. is less than
'<>' .NE. is not equal to
'>' .GT. is greater than
'>=' '=>' .GE. is greater than or equal to
Operators: AND OR EOR
AND will return a value of 1 if both operators are not equal to zero.
OR will return a value of 1 if either of the operators is not zero.
EOR will return a value of 1 if only one of the operators is not zero
Example: 0 AND 0 0
0 AND 1 0
1 AND 0 0
1 AND 1 1
0 OR 0 0
0 OR 1 1
1 OR 1 1
1 OR 1 1
0 EOR 0 0
0 EOR 1 1
1 EOR 0 1
1 EOR 1 0
Operators: .AND. .OR. .EOR.
These operators work in the same way as AND OR & EOR but they work on each
bit in the operands.
Example: %0011 AND %0101 %0001
%0011 OR %0101 %0111
%0011 EOR %0101 %0110
Note that the % means that the numbers following are in binary. The compiler
does NOT support binary.
Order of precedence
The following are the precedence levels of each of the opperators. These
are used to decide which operator should be executed first.
( ) [ ]
* / MOD
+ -
= =< < <> >= > etc.
AND OR EOR
.AND. .OR. .EOR.
Memory Usage
This compiler generates a non relocatable object file, the code is also
generated in a way where the variables are embeded within the object
program, therefore it will not be possible to place the code into a
ROM or EPROM. The first thing the compiler will do is to write a 1.8K
run time package to the file before the object code for the program is
generated. The following tables will give a description of memory usage at
run time.
Page Zero
$0000 to $007F Used by Operating system
$0080 to $0097 Used by Compiled program
$0098 to $00AF Used if Every or After is used
$00BO to $00C2 Free memory ( COMPILE MODE )
$00C0 to $00C2 Free memory ( RUN MODE )
$00C3 Last error number
$00C4 to $00FF Free memory
$0100 to $01FF Stack for everything ( Return addresses & arguments etc )
$0200 to $05FF Used by Operating system
$0600 to $06FF Free memory ( COMPILE MODE )
$0680 to $06FF Free memory ( RUN MODE )
$0700 to APPMHI DOS & Compiled program
APPMHI to MEMTOP Screen displays
Note that if you use the resident floating point package, some extra page
zero addresses will be used (See Atari's Operating System manuals for more
details).
Limitations
Depth of Stack
Since this program uses the 6502 hardware stack for virtualy all data
movements and control transfers, it is advisable not to nest procedures
and functions to deep as the stack will quickly fill up. If the stack does
overflow, the program cannot detect it. Therefore it is VERY important that
if you jump out of a subroutine you pop off the return address or addresses.
The stack is used for evaluation of expression, passing parameters to
procedures or functions & holding return addresses, as well as any data
you may have PUSHed on. In general if you don't jump out of a subroutine,
procedure or function you should not have any problems.
WRITE command
In this commands the arguments may not be an expression. They may only be
constants or variables.
AFTER & EVERY
Although you may use any of the predefined procedures in this language
within the portion of code called by the EVERY and AFTER commands, you
should not use any that are not resident, unless you can be sure that the
called function or procedure was not in use when the interrupt occured.
If you use a FUNCTION in both the main code and in the EVERY or AFTER
routine, then the FUNCTION will probably return incorrect results. This is
because the functions use statically allocated variables. When the interrupt
routine calls the FUNCTION, the FUNCTION will lose all its previous values
that it was in the middle of calculating.
Some Useful Functions
DPEEK
Purpose: To look at a word address (2 bytes)
External: PEEK Function
Syntax: var = DPEEK (adr)
This function will return the value of the memory address. The value will be
the 16 bits found in the specified address and the following address.
Address holds low byte and address+1 holds high byte.
LOCAL
VARIABLE ?ADR
FUNCTION DPEEK (?ADR)
DPEEK = PEEK(?ADR)+256*PEEK(?ADR+1)
RETURN
LOCATE
Purpose: To return contents of screen location
External: None
Syntax: var = LOCATE (exp1,exp2)
This function will return the contents of the screen location specified by
exp1 and exp2. Exp1 is the 'X' position and exp2 is the 'Y' position
LOCAL
VARIABLE ?XPOS,?YPOS
FUNCTION LOCATE (?XPOS,?YPOS)
PUSH (?XPOS,?YPOS)
CODE 686885546885
CODE 56688555A260
CODE A9009D48039D
CODE 4903A9079D42
CODE 032056E448A9
CODE 0048
PULL (LOCATE)
END
NOT
Purpose: To return the logical NOT of an expression.
Syntax: var = NOT (exp)
This function returns the logical NOT of exp, (ie. non zero returns TRUE
(1) and zero returns FALSE (0)).
LOCAL
VARIABLE ?NUM
FUNCTION NOT (?NUM)
NOT=1*(?NUM<>0)
END
PADDLE
Purpose: To return the position of a paddle
External: PEEK Function
Syntax: var = PADDLE (exp)
This function will return the value of one of the paddles specified by the
lowest 3 bits of exp.
LOCAL
VARIABLE ?NUM
FUNCTION PADDLE (?NUM)
PADDLE = PEEK(624+(?NUM .AND. 7))
END
PEEK
Purpose: To look at a byte address
External: None
Syntax: var = PEEK (adr)
This function will return the 8 bit value that is stored at memory location
specified by adr.
LOCAL
FUNCTION PEEK (?ADR)
CODE AD
VARIABLE ?ADR
PHA
CODE A900
PHA
PULL (PEEK)
END
Note the trick used by defining the variable after the LDA opcode. The
variable is assigned before the LDA instruction which then loads the
value from the address specified by the variable.
PTRIG
Purpose: To return the status of a paddle trigger
External: PEEK Function
Syntax: var = PTRIG (exp)
This function will return a 0 if the specified trigger is pressed and a 1
if it is not pressed. The required trigger is specified by the lower 3
bits of exp.
LOCAL
VARIABLE ?NUM
FUNCTION PTRIG (?NUM)
PTRIG = PEEK(636+(?NUM .AND. 7))
END
RND
Purpose: To generate a random number
External: None
Syntax: var = RND (exp)
This function will return a random number between 0 and the value of exp-1.
LOCAL
VARIABLE ?NUM,53770=?RANDOM
FUNCTION RND (?NUM)
RND=(?RANDOM*256+(?RANDOM .AND. 255)) MOD ?NUM
END
STICK
Purpose: Return joystick position
External: PEEK Function
Syntax: var = STICK (exp)
This function will read the position of one of the joysticks. The joystick
to be read is specified by the lowest 2 bits of exp.
LOCAL
VARIABLE ?NUM
FUNCTION STICK (?NUM)
STICK = PEEK(632+(?NUM .AND. 3))
END
STRIG
Purpose: To return the status of a joystick trigger
External: PEEK Function
Syntax: var = STRIG (exp)
This function will return the status of the specified joystick trigger,
0 means trigger is pressed and 1 means trigger is not pressed. The trigger
number is specified by the lower 2 bits of exp.
LOCAL
VARIABLE ?NUM
FUNCTION STRIG (?NUM)
STRIG = PEEK(644+(?NUM .AND. 3))
END
VAL
Purpose: Returns numeric value of text data
External: None
Syntax: var = VAL (adr)
This function returns the numeric value of the characters pointed to by adr.
LOCAL
VARIABLE ?ADR
FUNCTION VAL (?ADR)
PUSH (?ADR)
CODE 6885F46885F3
CODE A90085F22000
CODE D8B00520D2D9
CODE 9006A90085D4
CODE 85D5A5D448A5
CODE D548
PULL (VAL)
END
Example: POINTER NUMBER
ASCII "45"
CODE 9B
VARIABLE A
BEGIN
A=VAL(NUMBER)
WRITE (A)
RETURN
This would set the variable 'A' equal to 45 and then write it out onto the
screen.
Floating point support procedures
Since the language does not have any inbuilt floating point procedures, here
is a short program that will allow you to do limited calculations with
floating point numbers. The number can only be operated on by one opperation
at a time using the following procedures. If an error is detected by the
floating point routines then an error number of 1 will be issued.
Note that FR1 & FR2 are both pointers to a floating point numbers, these
numbers are printed out by using the 'FWRITE' command.
ADD
Purpose: To add 2 floating point numbers together
Syntax: ADD (FR1,FR2)
This procedure will add FR2 to FR1 and store the result in FR1.
DIV
Purpose: To divide 2 floating point numbers
Syntax: DIV (FR1,FR2)
This procedure will divide FR1 by FR2 and store the result in FR1.
EQUALS
Purpose: To set a floating point number equal to another
Syntax: EQUALS (FR1,FR2)
This procedure will set FR1 equal to the value of FR2.
EXP
Purpose: To return the base 10 exponential
Syntax: EXP (FR1)
This procedure will return the base 10 exponential and store the result in
FR1.
EXPe
Purpose: To return the natural exponential
Syntax: EXPe (FR1)
This procedure will return the natural exponential and store the result in FR1.
LOG
Purpose: To return the base 10 logarithm
Syntax: LOG (FR1)
This procedure will take the base 10 logarithm of FR1 and store the result
back into FR1.
LOGe
Purpose: To return the natural logarithm.
Syntax: LOGe (FR1)
This procedure will take the natural logarithm of FR1 and store the result
back into FR1.
MULT
Purpose: To multiply 2 floating point numbers together
Syntax: MULT (FR1,FR2)
This procedure will multiply FR1 by FR2 and store the result in FR1.
SUB
Purpose: To subtract 2 floating point numbers
Syntax: SUB (FR1,FR2)
This procedure will subtract FR2 from FR1 and store the result in FR1.
Listing of floating point support package
;
; ================
; Floating point
; support routines
; (c) 8th May 1986
; ================
;
LOCAL
VARIABLE ?FP1,?FP2,2=?ADR,?NUM,?STATUS
;
; =======================
; Floating point addition
; =======================
;
PROCEDURE ADD (?FP1,?FP2)
FP (2,55910)
END
;
; ==========================
; Floating point subtraction
; ==========================
;
PROCEDURE SUB (?FP1,?FP2)
FP (2,55904)
END
;
; =============================
; Floating point multiplication
; =============================
;
PROCEDURE MULT (?FP1,?FP2)
FP (2,56027)
END
;
; =======================
; Floating point division
; =======================
;
PROCEDURE DIV (?FP1,?FP2)
FP (2,56104)
END
;
; =========
; FP1 = FP2
; =========
;
PROCEDURE EQUALS (?FP1,?FP2)
MOVE (?FP2,?FP1,6)
END
;
; ===================
; Floating point LOGe
; ===================
;
PROCEDURE LOGe (?FP1)
FP (1,57037)
END
;
; ==================
; Floating point LOG
; ==================
;
PROCEDURE LOG (?FP1)
FP (1,57041)
END
;
; ===================
; Floating point EXPe
; ===================
;
PROCEDURE EXPe (?FP1)
FP (1,56768)
END
;
; ===================
; Floating point EXPe
; ===================
;
PROCEDURE EXP (?FP1)
FP (1,56780)
END
;
; ===========================
; Call floating point package
; ===========================
;
PROCEDURE FP (?NUM,?ADR)
MOVE (?FP1,212,6)
IF (?NUM<>1) THEN
MOVE (?FP2,224,6)
END IF
GOSUB 65020
PHP
PHP
PULL (?STATUS)
IF (?STATUS .AND. 1)<>0 THEN
ERROR 1
END IF
MOVE (212,?FP1,6)
END
65020 CODE 6C0200
Error Codes
1 - Start of program (BEGIN) not defined
2 - Out of memory
3 - Number out of range (less than 0 or greater than 65535)
4 - Label not defined
5 - Variable not defined
6 - Incorrect number of parameters
7 - Quatation marks missing
8 - Error in expression
9 - Invalid expression
10 - Invalid character
11 - Constant expected
12 - Requested line number missing
13 - Syntax error in line
14 - Procedure not defined
15 - Duplicate label
16 - Construct nested to deep
17 - To many local regions ( greater than 250)
18 - Nested INCLUDE requested
19 - Begin already defined
20 - Duplicate label number
21 - Function not defined
22 - Operators expected
23 - Variable or Constant expected
24 - Invalid nesting of IF and WHILE commands. eg IF exp THEN ... END WHILE
Known Bugs
No checking is made for running out of memory when building symbol tables,
if characters start to appear on screen this has probably occured. In this
case save the source program to disk and write a small routine to INCLUDE
it in. This will give more memory for use as a symbol table.
No checking is made for passing the correct number of arguments to a function
or procedure, and if these are incorrect it could crash the program from
either filling the stack up or pulling the return address off stack.
Author: David Firth: david@signus.demon.co.uk