Changes
[[Category:Cpctech.org]]
'''''This artikel article originally came from Kevin Thackers' archive at [http://www.cpctech.org.uk http://www.cpctech.org.uk].'''''
= Technical information about Locomotive BASIC =
The are two versions of Locomotive BASIC used in the Amstrad CPC and CPC+ computers. v1.0 is used by the CPC464, and v1.1 is used by the CPC664, CPC6128, CPC464+ and CPC6128+.
== BASIC v1.0 only ==
There is a region of memory between AC00-AC1B which is filled with RET instructions. The BASIC ROM calls the following locations:
AC01,AC04,AC07,AC0A,AC0D,AC10,AC13,AC16,AC19
It almost looks like these were used for debugging the ROM but were left in.
They can be used to implement new BASIC commands.
== Passing parameters to a RSX (Resident System Extension) command or binary function ==
A RSX (Resident System Extension) command is accessed through BASIC with a "|" character prefix. e.g. The "DIR" RSX, is accessed by "|DIR". A binary function is accessed through BASIC using the "CALL" command.
Both RSX and CALL commands works work (are!) similar from the BASIC command line and invokes a invoke machine code - the only difference is: with the help of a RSX command you don't need to know the exact access address. You can pass up to 32 parameters with a CALL or RSX command. Possible parameters could be integer, floating points and strings. Just store the parameter into a variable:
Passing for integer:
<pre>
or
<pre>
CALL or |RSX-command,@b$
</pre>
...
MSB PARAMn
IX+2 0 ------> LSB PARAMn
</pre>
with the help of that assembly code is it possible to find the parameters:
<pre>
ROUT1: CP "x" ;test register A if "x" parameters were hand-overedgiven, e.g. "x" = 2 RET NZ ; if no > failure and returnnot exactly x parameters then do not execute RSX. LD L,(IX+20) LD H,(IX+31) ; HL = value of last parameter LD E,(IX+42) LD D,(IX+53) ; DE = value of next to last parameter
...
</pre>
A register holds the number of parameters. IX points to each parameter. IX+0/IX+1 is the last parameter. This happens because each parameter in order is pushed onto the stack and IX then points to the last parameter pushed. Each parameter is a 16-bit value.
If you hand-over a parameter is a string than , then IX holds the address of the string descriptor which point to a 3 byte block. The first two bytes holds byte of the string descriptor is the length of . The next 2 bytes are an address that point to the stringin memory.
With the help of the variable container "@" it is also possible to get a result from an invoked mc-code back to basic.
In this case the parameter contains the address of the integer, floating point or string. You can modify these to give the result.
BASIC allocates the strings, so when you modify a string, do not write more characters than the original string.
Hint: the first two bytes at the end of stack shows the internal return address from BASIC interpreter where it was executed.
== Additional keywords and variables in BASIC v1.1 ==
<br> <br>
== Entering BASIC programs ==
A maximum of 255 characters can be entered for a single BASIC line.
There are some rules for assigning names for variables:
: - it is not allowed to define a variable starting with a figure (the system expect then programming mode and interpret it as a programm program line number)
: - no space (or 'under' as it is common today) between variable names are allowed
: - BASIC keywords can't be used
: - use % for defining a INTEGER value variable (like the function DEFINT but only for the assigned variable)
: - use $ for defining a STRING variable (like the function DEFSTR but only for the assigned variable)
: - Minimum line number is 1. Maximum line number is 65535.
This is converted into the tokenised BASIC program which is more compact than the line entered. The BASIC keywords are converted into "tokens", or 1-2 byte sequences which uniquely identify each keyword.
<br>
== Speeding up BASIC programs ==
To speed up BASIC programs following rules could help:
: - Avoid loops or a branching program structure if possible. Internally the operating system searches for the right line number always from the beginning of the program 'listing'. Often recurring subroutines (if necessary) should be at the beginning of RAM to speed up things.
: - Avoid the index variable after the <code>NEXT</code> command/statement (although it isn't a good program style)
: - Avoid spaces inside program code or remarks
: - Put lots of statements as possible in ONE line
: - Use variables instead of constants. A constant has always to be converted in a binary/digital format. A variable is already converted.
: - Dimensioning at the beginning of the program
: - Dimensioning your variables & pre-calculate
: - Avoid AND/OR/XOR in IF-THEN statements. It's faster to write IF ... THEN (statement 1).. IF ... THEN (statement 2).
: - Minimise string/char manipulation as this often requires memory allocations. (e.g. joining strings with +, use of MID$, LEFT$, RIGHT$, SPACE$)
== Minimizing memory usage ==
To minimize memory usage in BASIC here are some things to consider.
The size of the tokenized program:
: - Difficult to measure without looking at the data in memory.
: - Use short variable names. The names are stored in the tokenized BASIC program as-is.
: - Minimize the number of variables. The names are stored in the tokenized BASIC program everywhere they are used.
: - Use as few lines as possible. It's a small saving of about 5 bytes per line.
: - Consider using numbers vs strings and potentially 8-bit or 16-bit values.
Minimising memory usage when the program is running:
: - Minimize string operations. (e.g. A$=SPACE$(30)+CHR$(28) in memory this first allocates a string of length 30 containing spaces, then it allocates a new string of length 31 with spaces and char 28 at the end and assigns it to A$. In this line at least 30 bytes have been wasted. So consider if you need strings or perhaps if possible pre-define them).
== Structure of a BASIC program ==
<br> Notes:
#*This 16-bit value has two functions: #**if "0" it signals the end of the BASIC program. In this case, there is no furthur BASIC program lines or data. #**, otherwise, this value defines the length of the tokenised BASIC program line in bytes, and includes the 2 bytes defining this value, the 2 bytes defining the program line number, and the end of line marker. This number is stored in little endian notation with low byte followed by high byte. #*This 16-bit value defines the line number and exists if the length of line data in bytes is not "0". A line number is a integer number in the range 1-65535. This number is stored in little endian notation with low byte followed by high byte. #*This data defines the tokenised BASIC program line and exists if the length of line data in bytes is not "0". The length is dependant on the BASIC program line contents. #*This value defines the end of the tokenised BASIC line data and exists if the length of line data in bytes is not "0". The BASIC interpreter looks for this token during the processing of this line, and if found, will stop execution and continue to the next line. == BASIC GOSUB Subroutines == When Subroutines are used through the use of GOSUB, it's very important for that Subroutine to exit through the use of RETURN or if a Subroutine needs to GOTO somewhere else that, that place can RETURN. When a RETURN isn't found though, an area located at &AE8C in BASIC 1.0 or &AE70 in BASIC 1.1 then proceeds to fill with data from GOSUB calls and grows to the point over &1FF bytes have been used causing a MEMORY FULL error. The Following example demonstrates how to Trap this error: <pre>100 DEFINT a-z:MODE 2110 GOSUB 130120 c=1:GOSUB 130:c=0:GOTO 110130 IF c=0 THEN PRINT"*";:GOTO 120140 RETURN</pre> When the MEMORY FULL is reached and MEMORY FULL occurs, the user can reveal the situation by executing a RETURN immediately following MEMORY FULL, in the example from above instead of getting Unexpected RETURN, the Code Prints a Star before returning to a MEMORY FULL state. In that example it doesn't take very long to reach a MEMORY FULL, though more substancial may take longer to reveal this error. If a BASIC game should issue a MEMORY FULL error, the easiest test is to say RETURN. If Unexpected RETURN doesn't occur and the code tries to continue, it will be a sign of Subroutines not being able to RETURN after a GOSUB ia issued. The easiest course is to remove Subroutines. A game for example may have a series of GOSUBs going to a line checking IF something is true, and if so GOTO somewhere else where a RETURN may not be found. In those situations a GOSUB should be replaced with an IF...THEN..[line number] thus removing the Subroutine. IF you wish to konw more about this please see my ammended correction of the [[Amstrad Action December 1990 Type-Ins|Amstrad Action Issue 63 Type-Ins Game Madballs]]. The original game which was nicely coded, eventually ran into the problem of MEMORY FULL, though to fully reveal this error the game needed to be played for over 20 minutes. Another way to test for this error is to inspect the area of &AE8C to &B08B or &AE70 to &B06F depending on which version of BASIC is used.
== BASIC tokens ==
|-
| &1d
| 16-bit BASIC program line memory address pointer(see notes)
|-
| &1e
| INPUT
|-
| &a4
| KEY
|-
|-
| &b5
| ON SQ
|-
| &b6
<br> Notes:
{| border="1"
|}
{| border="1"
|}
{| border="1"
<br> The 16-bit byte offset is initially set to 0, but is setup when the program is RUN. The offset is stored in little-endian format, with low byte followed by high byte.
<br> This table list the BASIC tokens with a &ff prefix byte.
<br> NOTES:
== Floating Point data definition ==
The sign is represented by bit 7 of byte 3. The value of the sign bit indicates the sign of the floating point number.
=== Mantissa ===
The exponent is 8-bit and is stored in byte 4. It is stored with a bias of 128.
=== floating point example in RAM by MaV ===
== BASIC floating-point/real variables ==
A floating point (real) variable describes a number with integer and fractional parts. The biggest figure which can be stored correctly in RAM by a variable is 2^32-1 = 4294967295.
e.g.
<pre>a! = 3.141592654
</pre>
</pre>
Where "a" should be replaced with the name of the variable.
<br>
== BASIC integer variables ==
<br> NOTES:
e.g.
<pre>a% = 3
</pre>
{| border="1"
|}
</pre>
where "a" should be replaced with the name of the variable.
== BASIC string variables ==
<br> NOTES:
e.g.
<pre>a$ = "hello"
</pre>
{| border="1"
|}
</pre>
replacing "a$" with the name of the string variable.