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>
...
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 a parameter is a string, then IX holds the 16-bit value is an address of a "the string descriptor which point to a 3 byte block". The first byte of the string description or descriptor is the length. The next 2 bytes are an address that point to the string in 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 param 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.
<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.
: - Avoid spaces inside program code or remarks
: - Put lots of statements as possible in ONE line
: - Use variables instead of constants. A constand 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 ==
#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 2
110 GOSUB 130
120 c=1:GOSUB 130:c=0:GOTO 110
130 IF c=0 THEN PRINT"*";:GOTO 120
140 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 ==
|-
| &amp;1d
| 16-bit BASIC program line memory address pointer(see notes)
|-
| &amp;1e
| INPUT
|-
| &amp;a4
| KEY
|-
|-
| &amp;b5
| ON SQ
|-
| &amp;b6
<br> Notes:
#*The &amp;ff code is used as a prefix for more keywords. See the table below for the list of keywords using this prefix. #*&amp;e2,&amp;e8 and &amp;e9 are not used #*&amp;7c ("|") is a character prefix used to identify a an RSX command. e.g. "|DIR".
e.g. "|DIR". An RSX is encoded in a BASIC program using the following structure:
{| border="1"
|}
#*This token identifies a integer (16-bit) number. The two bytes following this token is the number, stored low byte then high byte. e.g. &amp;191a,&amp;2d,&amp;00 represents the integer number "&amp;002d"="45". #*This token (&amp;0B) is changed at run-time to &amp;0D #*This token identifies a integer variable. 02,00,00,var name offset to number in program setup when program RUN. The variable name is stored directly, with bit 7 of the last character set. #*This token identifies a string variable. offset to string in program string stored AS IS with quotes around it. #*This token identifies a floating point number. Immediatly following the token are 5 bytes which define the number.
{| border="1"
|}
#*#This byte is the BASIC token identifying a floating point number #*#These 5 bytes define the floating point number. #*The space symbol is used as a command seperator #*Variable definitions: #**The variable definition has the following structure:
{| 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.
#**The token byte defines the variable type (i.e. string, floating point, integer) and the suffix ("$", none and "%"). #**The variable name is stored in the program, with bit 7 of the last character set to "1". e.g. The variable named "abc" will be encoded as 'a','b','c'+&amp;80 #*String values: #**Each string value is prefixed with &amp;22 token. #**All strings must be enclosed by double quote symbols (&amp;quot). This symbols define the start and end of the string value. #**The string value can contain any symbol except the quote ("). i.e. 0-&amp;21, and &amp;23-&amp;ff can be used. #*After running a program, Tokens of "1d" with 16-bit BASIC program line pointers are changed to token "1e" with the 16-bit memory address of the BASIC line number in memory.
<br> This table list the BASIC tokens with a &amp;ff prefix byte.
<br> NOTES:
#*These codes are prefixed by &amp;FF. e.g. The keyword "ABS" is stored as the following sequence: <pre>&amp;FF,&amp;00</pre> #*Codes &amp;1e...&amp;3f inclusive are not used #*Codes &amp;4a...&amp;6f inclusive are not used #*Codes &amp;80...&amp;ff inclusive are not used *When a BASIC program is in memory, the BASIC ROM can replace "16-bit BASIC program line number" tokens with "16-bit BASIC program line memory address pointer". When a program is loaded or saved, there will only be "16-bit BASIC program line number" tokens followed by a 16-bit number of the line. When a program is running, BASIC will replace the "16-bit BASIC program line number" with the "16-bit BASIC program line memory address pointer" token, and replace the 16-bit line number with the memory address of the start of that line.  It does this to avoid having to lookup the address of the line each time. * When a REM or ' is seen, the characters following it are output directly (i.e. the bytes are not tokenized) until the end of line or a ':' is seen. * When a BASIC program is listed each line is converted to a string (this includes the line number and the tokens converted to their strings). There is a maximum length for this string of 256 characters. This means that if the BASIC line is LISTed or EDITed, then the line will be displayed incorrectly with missing characters on the end. This is also noticed if you have a "10-liner" program that packs as much BASIC as possible into each line and renumber it so the line number has more digits.
== 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.
#*If the sign bit is "1", then the number is negative. #*If the sign bit is "0", then the number is positive.
=== Mantissa ===
The exponent is 8-bit and is stored in byte 4. It is stored with a bias of 128.
#*128-255 are positive exponents, #*01-127 are negative exponents.*0 means, the number is zero To obtain the signed exponent, you must subtract 128 from the stored exponent. The minimum exponent is 1 and this describes a number of 2^-127. The maximum exponent is 255 and this describes a number of 2^127.A value of 0 just means, that the number is zero (0). === BASIC Display of Floating point numbers === * Numbers are displayed to 9 decimal places.* If the number doesn't have a fractional part (e.g. .0) then the fractional part is not displayed.* Trailing zeros (zero digits after the last digit in the fraction) are not displayed* The value is rounded in the following way for display:
To obtain If the signed exponent10th fractional digit is 5 or above, you must subtract 128 from then the stored exponentnumber is rounded up. The minimum exponent If the 10th fractional digit is 0 and this describes a 4 or below, then the number of 2^-127is rounded down. The maximum exponent e.g. 0.1234567891 is 255 and this describes a number of 2^128displayed as 0.123456789 0.1234567895 is displayed as 0.12345679
=== floating point example in RAM by MaV ===
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.
#*A integer real variable is defined with a "!" character postfix.
e.g.
<pre>a! = 3.141592654
</pre>
#*A real number uses 5 bytes of memory as storage. The format is described above. #*The address of a real variable can be found in BASIC by: <pre>PRINT @a!
</pre>
<br> NOTES:
#*A integer variable is defined with a "%" character postfix.
e.g.
<pre>a% = 3
</pre>
#*A integer variable has a range of -32768 to 32767 #*A integer variable always uses two bytes of memory as storage with the following format:
{| border="1"
|}
#*The address of the integer variable can be found in BASIC by: <pre>PRINT @a%
</pre>
where "a" should be replaced with the name of the variable.
== BASIC string variables ==
<br> NOTES:
#**A string variable is defined in BASIC with a "$" character postfix.
e.g.
<pre>a$ = "hello"
</pre>
#**A string variable is described internally by a "string descriptor block" which has the following structure:
{| border="1"
|}
#**The address of the "string descriptor block" for the string variable can be found in BASIC by typing: <pre>PRINT @a$
</pre>
replacing "a$" with the name of the string variable.
#**A string uses a minimum of 3 bytes of storage (a 0 character length string) and a maximum of 258 bytes of storage. 3 bytes are used by the "string descriptor block") #**A string variable can contain any ASCII character code in the range 0-255. #**A string variable can store a minimum of 0 characters and a maximum of 255 characters. #**The length of the string in characters is defined in the string descriptor block. The string does not have a termination character. [[Category:Programming]][[Category:BASIC| ]][[Category:CPC Internal Components]][[Category:Operating System| ]][[Category:Software]][[Category:Programming software| ]]
431
edits