Difference between revisions of "CALL"

From BeebWiki
Jump to: navigation, search
m (1 revision)
m (32000 BASIC)
 
(13 intermediate revisions by 3 users not shown)
Line 10: Line 10:
 
|+ CALL
 
|+ CALL
 
| Availability
 
| Availability
| colspan="2" | Present in all versions of BBC BASIC.
+
| Present in all versions of BBC BASIC.
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
 
| [[BASIC metasyntax|Syntax]]
 
| [[BASIC metasyntax|Syntax]]
|
 
 
| <code>CALL</code> <numeric>{<code>,</code><num-var>&#124;<string-var>}
 
| <code>CALL</code> <numeric>{<code>,</code><num-var>&#124;<string-var>}
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
 
| Token (hex)
 
| Token (hex)
|
 
 
| <code>D6</code> (statement)
 
| <code>D6</code> (statement)
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
 
| Description
 
| Description
|
+
| Sets up a structure in memory representing the given argument variables
|
+
(if any), sets certain CPU registers to the values of the
Sets up a structure in memory representing the given argument variables (if any),
+
''resident integer variables'', and jumps into a machine code routine at
sets certain CPU registers to the values of the ''resident integer variables'',
+
the address given in the <numeric>. The routine is permitted to read and
and jumps into a machine code routine at the address given in
+
write to the BASIC variables described in the table, and should exit with
the <numeric>. The routine is permitted to read and write to the BASIC
+
the normal subroutine return instruction. After the routine exits, BASIC
variables described in the table, and should exit with the normal subroutine
+
continues executing the current program or command line.
return instruction. After the routine exits, BASIC continues executing the
 
current program or command line.
 
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
 
| Associated keywords
 
| Associated keywords
| colspan="2" | <code>[[?]]</code>, <code>[[!]]</code>, <code>[[$]]</code>, <code>[[USR]]</code>
+
| <code>[[?]]</code>, <code>[[!]]</code>, <code>[[$]]</code>, <code>[[USR]]</code>
 
|}
 
|}
  
Line 51: Line 47:
 
=== 6502 BASIC ===
 
=== 6502 BASIC ===
 
BASIC sets up a data structure in its workspace, starting from location
 
BASIC sets up a data structure in its workspace, starting from location
&600. Apart from the <numeric> call address, this structure contains
+
&600. Apart from the <numeric> call address, this structure contains details
details of all the variables listed after the <code>CALL</code> keyword, if
+
of all the variables listed after the <code>CALL</code> keyword, if any. The
any. The routine may not change this structure, but can alter the variables
+
routine may not change this structure, but can alter the variables it
it references:
+
references:
  
 
{| class="wikitable"
 
{| class="wikitable"
! Location !! Meaning
+
! Location !! colspan="2" | Meaning
 
|-
 
|-
 
| &600 || colspan="2" | Number of variables
 
| &600 || colspan="2" | Number of variables
Line 69: Line 65:
 
| &606 || Type
 
| &606 || Type
 
|-
 
|-
| ... || ...
+
| ... || colspan="2" | ...
 
|}
 
|}
  
Line 92: Line 88:
 
|}
 
|}
  
Finally BASIC sets the state of the CPU as follows, and jumps into the user's routine:
+
Finally BASIC sets the state of the CPU as follows, and jumps into the
 +
user's routine:
  
 
{| class="wikitable"
 
{| class="wikitable"
Line 109: Line 106:
 
| C || Set to the lowest bit of <code>C%</code>.
 
| C || Set to the lowest bit of <code>C%</code>.
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| S || Points to the top of the 6502 stack (in use by BASIC.)  On top of the stack is
+
| S || Points to the top of the 6502 stack (in use by BASIC.)  On top of the stack is a return address (suitable for <code>[[RTS]]</code>) to continue with the current BASIC statement or program.
a return address (suitable for <code>[[RTS]]</code>) to continue with the current BASIC
+
|- style="vertical-align:top"
statement or program.
+
| PC || Set to the low 16 bits of the first, <numeric> argument to <code>CALL</code>.
 +
|- style="vertical-align:top"
 +
| N,V,B,Z || Undefined.
 +
|}
 +
 
 +
=== 6809 BASIC ===
 +
 
 +
BASIC sets the state of the CPU as follows, and jumps into the
 +
user's routine:
 +
 
 +
{| class="wikitable"
 +
! Register !! Value
 +
|- style="vertical-align:top"
 +
| A || Set to the low 8 bits of <code>A%</code>.
 +
|- style="vertical-align:top"
 +
| B || Set to the low 8 bits of <code>B%</code>.
 +
|- style="vertical-align:top"
 +
| U || Set to the low 16 bits of <code>U%</code>.
 +
|- style="vertical-align:top"
 +
| X || Set to the low 16 bits of <code>X%</code>.
 +
|- style="vertical-align:top"
 +
| Y || Set to the low 16 bits of <code>Y%</code>.
 +
|- style="vertical-align:top"
 +
| I || Left in its current state.
 +
|- style="vertical-align:top"
 +
| C || Set to the lowest bit of <code>C%</code>.
 +
|- style="vertical-align:top"
 +
| S || Points to the top of the 6809 stack. On top of the stack is a return address (suitable for <code>[[RTS]]</code>) to continue with the current BASIC statement or program.
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
 
| PC || Set to the low 16 bits of the first, <numeric> argument to <code>CALL</code>.
 
| PC || Set to the low 16 bits of the first, <numeric> argument to <code>CALL</code>.
Line 125: Line 149:
  
 
{| class="wikitable"
 
{| class="wikitable"
! Location !! Meaning
+
! Location !! colspan="2" | Meaning
 
|-
 
|-
 
| IX+0 || colspan="2" | Number of variables
 
| IX+0 || colspan="2" | Number of variables
 
|-
 
|-
| IX+1 || Type
+
| IX+1 || rowspan="2" | First variable || Type
 
|-
 
|-
| IX+2..3 || rowspan="2" | First variable || Address
+
| IX+2..3 || Address
 
|-
 
|-
| IX+4 || Type
+
| IX+4 || rowspan="2" | Second variable || Type
 
|-
 
|-
| IX+5..6 || rowspan="2" | Second variable || Address
+
| IX+5..6 || Address
 
|-
 
|-
| ... || ...
+
| ... || colspan="2" | ...
 
|}
 
|}
  
Line 160: Line 184:
 
|}
 
|}
  
Finally BASIC sets the state of the CPU as follows, and jumps into the user's routine:
+
Finally BASIC sets the state of the CPU as follows, and jumps into the
 +
user's routine:
  
 
{| class="wikitable"
 
{| class="wikitable"
Line 188: Line 213:
 
|}
 
|}
  
If the call address is in the range &FF00 to &FFFF, and there is no parameter block passed, the CPU registers are set as follows:
+
If the call address is in the range &FF00 to &FFFF, and there is no
 +
parameter block passed, the CPU registers are set as follows:
  
 
{| class="wikitable"
 
{| class="wikitable"
Line 203: Line 229:
 
| IY || Set to address of machine code routine (=PC).
 
| IY || Set to address of machine code routine (=PC).
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| SP || Points to a return address on the Z80 stack (suitable for <code>[[RET]]</code>)
+
| SP || Points to a return address on the Z80 stack (suitable for <code>[[RET]]</code>) to continue with the current BASIC statement or program.
to continue with the current BASIC statement or program.
 
 
|}
 
|}
  
Line 216: Line 241:
 
     EXX
 
     EXX
 
     RET
 
     RET
 
  
 
=== 32000 BASIC ===
 
=== 32000 BASIC ===
 
BASIC sets up a data structure in the string buffer pointed to by R1 and R2
 
BASIC sets up a data structure in the string buffer pointed to by R1 and R2
holding the number of parameters. Apart
+
holding the number of parameters. Apart from the <numeric> call address,
from the <numeric> call address, this structure contains details of all the
+
this structure contains details of all the variables listed after the
variables listed after the <code>CALL</code> keyword, if any. The routine
+
<code>CALL</code> keyword, if any. The routine may not change this
may not change this structure, but can alter the variables it references:
+
structure, but can alter the variables it references:
  
 
{| class="wikitable"
 
{| class="wikitable"
! Location !! Meaning
+
! Location !! colspan="2" | Meaning
 
|-
 
|-
 
| R1+0..3 || rowspan="2" | First variable || Address
 
| R1+0..3 || rowspan="2" | First variable || Address
Line 236: Line 260:
 
| R1+9 || Type
 
| R1+9 || Type
 
|-
 
|-
| ... || ...
+
| ... || colspan="2" | ...
 
|}
 
|}
  
Line 255: Line 279:
 
|}
 
|}
  
If there are no parameters to the CALL, BASIC sets the state of the CPU as follows:
+
32016 BASIC does not pass the integer variables to the called code. If not calling a
 +
BBC MOS API, the state of the CPU is set as follows:
  
 
{| class="wikitable"
 
{| class="wikitable"
 
! Register !! Value
 
! Register !! Value
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| R1 || Set to the low 8 bits of <code>A%</code>.
+
| R1 || Address of parameter block.
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| R2 || Set to the low 8 bits of <code>F%</code>.
+
| R2 || Number of parameters.
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| R3 || Set to the low 8 bits of <code>B%</code>.
+
| R3 || undefined.
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| R4 || Set to the low 8 bits of <code>C%</code>.
+
| R4 || undefined.
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| R5 || Set to the low 8 bits of <code>D%</code>.
+
| R5 || undefined.
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| R6 || Set to the low 8 bits of <code>E%</code>.
+
| R6 || undefined.
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| R7 || The ''program counter''. Set to the first, <numeric> argument to <code>CALL</code>.
+
| R7 || undefined.
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
 
| SP || Points to a return address on the user stack (suitable for <code>[[RET]]</code>) to continue with the current BASIC statement or program.
 
| SP || Points to a return address on the user stack (suitable for <code>[[RET]]</code>) to continue with the current BASIC statement or program.
 
|}
 
|}
  
If the call address is in the range &FF00 to &FFFF, and there is no parameter block passed, the CPU registers are set as follows:
+
If the call address is in the range &FF00 to &FFFF, and there is no
 +
parameter block passed, the CPU registers are set as follows:
  
 
{| class="wikitable"
 
{| class="wikitable"
Line 288: Line 314:
 
| R3 || Set to the low 8 bits of <code>Y%</code>.
 
| R3 || Set to the low 8 bits of <code>Y%</code>.
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| SP || Points to a return address on the user stack (suitable for <code>[[RET]]</code>)
+
| SP || Points to a return address on the user stack (suitable for <code>[[RET]]</code>) to continue with the current BASIC statement or program.
to continue with the current BASIC statement or program.
 
 
|}
 
|}
  
 +
From examination of code, it appears that CALL to a non-API address with no parameters
 +
erroneously jumps to the parameter buffer instead of to the destination address. To force
 +
a correct call at least one parameter must be passed, eg <code>CALL dest,A%</code>.
 +
This can be fixed in by patching one byte:
 +
* v1.04 no patch needed
 +
* v1.09 offset=&4F63, change &67 to &A7
 +
* v1.13 offset=&543D, change &67 to &A7
 +
This is equivalent to ?&5163=&A7 (v1.09) or ?&563D=&A7 (v1.13) in the running code.
  
 
=== ARM BASIC ===
 
=== ARM BASIC ===
Line 301: Line 334:
  
 
{| class="wikitable"
 
{| class="wikitable"
! Location !! Meaning
+
! Location !! colspan="2" | Meaning
 
|-
 
|-
 
| R9 + 0..3 || rowspan="2" | Last variable || Address
 
| R9 + 0..3 || rowspan="2" | Last variable || Address
Line 311: Line 344:
 
| R9 + 12..15 || Type
 
| R9 + 12..15 || Type
 
|-
 
|-
| ... || ...
+
| ... || colspan="2" | ...
 
|}
 
|}
  
Line 335: Line 368:
 
|}
 
|}
  
Finally BASIC sets the state of the CPU as follows, and jumps into the user's routine:
+
Finally BASIC sets the state of the CPU as follows, and jumps into the
 +
user's routine:
  
 
{| class="wikitable"
 
{| class="wikitable"
Line 341: Line 375:
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
 
| R0..R7
 
| R0..R7
| Set to the resident integer variables. R0 is set to <code>A%</code>, R1 to <code>B%</code>, and so on until R7 is set to <code>H%</code>.
+
| Set to the resident integer variables.
 +
R0=A%, R1=B%, R2=C%, R3=D%, R4=E%, R5=F%, R6=G%, R7=H%.
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
 
| R8
 
| R8
Line 367: Line 402:
 
| The ''program counter''.  Set to the first, <numeric> argument to <code>CALL</code>.
 
| The ''program counter''.  Set to the first, <numeric> argument to <code>CALL</code>.
 
|}
 
|}
 
  
 
== BBC MOS API Access ==
 
== BBC MOS API Access ==
 
To ensure cross-platform compatibility, most non-6502 implementations of BBC
 
To ensure cross-platform compatibility, most non-6502 implementations of BBC
BASIC translate <code>CALL</code>s to an equivalent call to the underlying
+
BASIC translate <code>CALL</code>s to MOS API entries to an equivalent call
MOS. The only address that are supported by this are those listed below. The
+
to the underlying MOS. The only address that are supported by this are those
values in A%, X% and Y%, or the data or control block pointed to by X%, are
+
listed below. The values in A%, X% and Y%, or the data or control block
passed in an appropriate manner to the underlying system.
+
pointed to by X%, are passed in an appropriate manner to the underlying
 +
system.
  
 
{| class="wikitable" cellpadding="0"
 
{| class="wikitable" cellpadding="0"
Line 410: Line 445:
 
! CPU || Registers on entry || Result returned by [[USR]]
 
! CPU || Registers on entry || Result returned by [[USR]]
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| 6502 || A=A%, X=X%, Y=Y%, Cy=b0 of C% || b0-7=A, b8-15=X<br>b16-23=Y, b24-31=P
+
| 6502 || A=A%, X=X%, Y=Y%, Cy=b0 of C% || b0-7=A<br>b8-15=X<br>b16-23=Y<br>b24-31=P
 +
|- style="vertical-align:top"
 +
| 6809 || A=A%, B=B%, U=U%, X=X%, Y=Y%, Cy=b0 of C% || b0-7=A, b8-15=X<br>b16-23=Y, b24-31=CC
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
 
| Z80  || A=A%, B=B%, C=C%, D=D%, E=E%, H=H%, L=L% || b0-b15=HL'<br>b16-b31=HL
 
| Z80  || A=A%, B=B%, C=C%, D=D%, E=E%, H=H%, L=L% || b0-b15=HL'<br>b16-b31=HL
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| Z80<br>BBC API call || A=A%, L=X%, H=H%, E=E% || b0-b7=A, b8-b23=HL, b24-31=F
+
| Z80<br>BBC API call || A=A%, L=X%, H=H%, E=E% || b0-b7=A<br>b8-b23=HL<br>b24-31=F
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| 32016 || R1=A%, R2=B%, R3=C%, R4=D%, R5=E%, R6=F%, R7=G% || b0-b31=R1
+
| 32000 || R1=A%, R2=B%, R3=C%, R4=D%, R5=E%, R6=F%, R7=G% || b0-b31=R1
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| 32016<br>BBC API call || R1=A%, R2=X%,<br>R3..R7=contents of control block at X% || b0-b7=R1, b8-b23=R2
+
| 32000<br>BBC API call || R1=A%, R2=X%,<br>R3..R7=contents of control block at X% || b0-b7=R1<br>b8-b23=R2
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| PDP-11 || R0=A%, R1=B%, R2=C%, R3=D%, R4=E%, R5=F% || b0-b15=R0, b16-b31=R1
+
| PDP-11 || R0=A%, R1=B%, R2=C%, R3=D%, R4=E%, R5=F% || b0-b15=R0<br>b16-b31=R1
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| PDP-11<br>BBC API call || R0=A%, R1=X%, R2=Y% || b0-b7=R0, b8-b23=R1
+
| PDP-11<br>BBC API call || R0=A%, R1=X%, R2=Y% || b0-b7=R0<br>b8-b23=R1
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
 
| ARM || R0=A%, R1=B%, R2=C%, R3=D%,<br> R4=E%, R5=F%, R6=G%, R7=H% || b0-b31=R0
 
| ARM || R0=A%, R1=B%, R2=C%, R3=D%,<br> R4=E%, R5=F%, R6=G%, R7=H% || b0-b31=R0
 
|- style="vertical-align:top"
 
|- style="vertical-align:top"
| ARM<br>BBC API call || R0=A%, R1=X%, R2=Y%, or<br>R1..R5=contents of control block at X% || b0-b7=R0, b8-b31=R1
+
| ARM<br>BBC API call || R0=A%, R1=X%, R2=Y%, or<br>R1..R5=contents of control block at X% || b0-b7=R0<br>b8-b31=R1
 
|}
 
|}
  
Line 437: Line 474:
  
 
On 8-bit platforms the high 24 bits of X% and Y% are ignored, and the
 
On 8-bit platforms the high 24 bits of X% and Y% are ignored, and the
control block is found with X%+256*Y%. On larger memory platforms, the
+
control block is found with X%+256*Y%. On platforms with larger registers,
control block is found at X%, ignoring Y% completely. Some platforms will
+
the control block is found at X%, ignoring Y% completely. Some platforms
check if X%<256 and use X%+256*Y%, though this should not be relied on.
+
will check if X%<256 and use X%+256*Y%, though this should not be relied on.
  
 
An additional advantage is that the control block is easily accessed with
 
An additional advantage is that the control block is easily accessed with
 
X%, for example, X%!2=load%, etc.
 
X%, for example, X%!2=load%, etc.
  
When calling &FFCE with A%=0 to close a file, 6502 BASIC requires the channel
+
===Notes===
to be passed in Y% but in ARM BASIC the channel must be passed in X%.
+
32000 passes A%=R1, etc., '''not''' R0.
Whan calling from BASIC, the <code>[[CLOSE|CLOSE#]]</code> statement should be used.
+
 
 +
When calling &FFCE with A%=0 to close a file, 6502 BASIC requires the
 +
channel to be passed in Y% but in ARM BASIC the channel must be passed in
 +
X%. When calling from BASIC, the <code>[[CLOSE|CLOSE#]]</code> statement
 +
should be used.
  
 
== References ==
 
== References ==
 
* [http://developer.riscos.com/PRM/BBCBASIC.PDF BBC BASIC] RISC OS 3 Programmer's Reference Manual: BBC BASIC (PDF)
 
* [http://developer.riscos.com/PRM/BBCBASIC.PDF BBC BASIC] RISC OS 3 Programmer's Reference Manual: BBC BASIC (PDF)
* [http://mdfs.net/bbcbasic/Arc/basic-1.04 Usenet post] Roger Wilson's Usenet post of changes in BASIC V 1.04
+
* [http://mdfs.net/Software/BBCBasic/RISCOS/basic-1.04 Usenet post] Roger Wilson's Usenet post of changes in BASIC V 1.04
  
 
-- [[User:Beardo|beardo]] 22:50, 25 June 2007 (BST)
 
-- [[User:Beardo|beardo]] 22:50, 25 June 2007 (BST)

Latest revision as of 14:38, 7 September 2023


CALL is a BASIC statement to call (execute) a machine code routine in memory or a BBC MOS API entry. The routine can be given access to certain named BASIC variables, and may change their values. On most non-6502 platforms, BBC BASIC intercepts calls to the standard BBC MOS API entries and translates them to an equivalent action.

CALL
Availability Present in all versions of BBC BASIC.
Syntax CALL <numeric>{,<num-var>|<string-var>}
Token (hex) D6 (statement)
Description Sets up a structure in memory representing the given argument variables

(if any), sets certain CPU registers to the values of the resident integer variables, and jumps into a machine code routine at the address given in the <numeric>. The routine is permitted to read and write to the BASIC variables described in the table, and should exit with the normal subroutine return instruction. After the routine exits, BASIC continues executing the current program or command line.

Associated keywords ?, !, $, USR

Description

CALL allows a BASIC program to use a piece of machine code as part of its operation. Machine code is a program in the form of binary data that can be run directly by the central processing unit (CPU).

CALL is one of the ways to access functions of the MOS (its Application Programming Interface, or API.) Advanced programmers can also use CALL to improve the performance of a BASIC program by rewriting the most time-consuming parts in machine code, as it runs much, much faster than the equivalent BASIC code.

Because CALL is involved with the low level architecture of the computer, its precise function depends on which CPU is running BASIC:

6502 BASIC

BASIC sets up a data structure in its workspace, starting from location &600. Apart from the <numeric> call address, this structure contains details of all the variables listed after the CALL keyword, if any. The routine may not change this structure, but can alter the variables it references:

Location Meaning
&600 Number of variables
&601..2 First variable Address
&603 Type
&604..5 Second variable Address
&606 Type
... ...

The Type byte may be one of the following:

Type Object at the given Address
&00 An unsigned, 8-bit byte.
&04 A signed, little-endian, 32-bit integer.
&05 A 40-bit float in 6502 BASIC format.
&80 A CR-terminated ASCII string.
&81 A string descriptor block, consisting of:

1 × 16-bit address of the start of the string;
1 × byte giving the memory allocation (its maximum length);
1 × byte giving the actual length of the string.
The routine may change the string and its length, but not its start address or memory allocation.

Finally BASIC sets the state of the CPU as follows, and jumps into the user's routine:

Register Value
A Set to the low 8 bits of A%.
X Set to the low 8 bits of X%.
Y Set to the low 8 bits of Y%.
D Reset to 0, meaning decimal mode is off.
I Left in its current state.
C Set to the lowest bit of C%.
S Points to the top of the 6502 stack (in use by BASIC.) On top of the stack is a return address (suitable for RTS) to continue with the current BASIC statement or program.
PC Set to the low 16 bits of the first, <numeric> argument to CALL.
N,V,B,Z Undefined.

6809 BASIC

BASIC sets the state of the CPU as follows, and jumps into the user's routine:

Register Value
A Set to the low 8 bits of A%.
B Set to the low 8 bits of B%.
U Set to the low 16 bits of U%.
X Set to the low 16 bits of X%.
Y Set to the low 16 bits of Y%.
I Left in its current state.
C Set to the lowest bit of C%.
S Points to the top of the 6809 stack. On top of the stack is a return address (suitable for RTS) to continue with the current BASIC statement or program.
PC Set to the low 16 bits of the first, <numeric> argument to CALL.
N,V,B,Z Undefined.

Z80 BASIC

BASIC sets up a data structure in the string buffer pointed to by IX. Apart from the <numeric> call address, this structure contains details of all the variables listed after the CALL keyword, if any. The routine may not change this structure, but can alter the variables it references:

Location Meaning
IX+0 Number of variables
IX+1 First variable Type
IX+2..3 Address
IX+4 Second variable Type
IX+5..6 Address
... ...

The Type byte may be one of the following:

Type Object at the given Address
&00 An unsigned, 8-bit byte, eg ?X.
&04 A signed, little-endian, 32-bit integer, eg !X or X%.
&05 A 40-bit float, eg V.
&80 A CR-terminated ASCII string, eg $X.
&81 A string variable, eg A$. The address points to a String Descriptor Block, consisting of:

1 × 16-bit address of the start of the string;
1 × byte giving the current length of the string;
1 × byte giving the memory allocation (its maximum length).
The routine may change the string and its length, but not its start address or memory allocation.

Finally BASIC sets the state of the CPU as follows, and jumps into the user's routine:

Register Value
A Set to the low 8 bits of A%.
F Set to the low 8 bits of F%.
B Set to the low 8 bits of B%.
C Set to the low 8 bits of C%.
D Set to the low 8 bits of D%.
E Set to the low 8 bits of E%.
H Set to the low 8 bits of H%.
L Set to the low 8 bits of L%.
IX Set to address of parameter block.
IY Set to address of machine code routine (=PC).
SP Points to a return address on the Z80 stack (suitable for RET) to continue with the current BASIC statement or program.

If the call address is in the range &FF00 to &FFFF, and there is no parameter block passed, the CPU registers are set as follows:

Register Value
A Set to the low 8 bits of A%.
E Set to the low 8 bits of E%.
H Set to the low 8 bits of Y%.
L Set to the low 8 bits of X%.
IY Set to address of machine code routine (=PC).
SP Points to a return address on the Z80 stack (suitable for RET) to continue with the current BASIC statement or program.

In Z80 BASIC the string buffer is in different locations in different versions. Consequently, the only way for code such as Tokeniser can find the string buffer is to call some machine code and return the value in IX with:

   PUSH IX
   POP HL
   EXX
   RET

32000 BASIC

BASIC sets up a data structure in the string buffer pointed to by R1 and R2 holding the number of parameters. Apart from the <numeric> call address, this structure contains details of all the variables listed after the CALL keyword, if any. The routine may not change this structure, but can alter the variables it references:

Location Meaning
R1+0..3 First variable Address
R1+4 Type
R1+5..8 Second variable Address
R1+9 Type
... ...

The Type byte may be one of the following:

Type Object at the given Address
&00 An unsigned, 8-bit byte, eg ?X.
&01 A signed, little-endian, 32-bit integer, eg !X or X%.
&02 A 40-bit float, eg V.
&03 A string variable, eg A$. The address points to a String Descriptor Block.
&04 A CR-terminated ASCII string, eg $X.

32016 BASIC does not pass the integer variables to the called code. If not calling a BBC MOS API, the state of the CPU is set as follows:

Register Value
R1 Address of parameter block.
R2 Number of parameters.
R3 undefined.
R4 undefined.
R5 undefined.
R6 undefined.
R7 undefined.
SP Points to a return address on the user stack (suitable for RET) to continue with the current BASIC statement or program.

If the call address is in the range &FF00 to &FFFF, and there is no parameter block passed, the CPU registers are set as follows:

Register Value
R1 Set to the low 8 bits of A%.
R2 Set to all 32 bits of X%.
R3 Set to the low 8 bits of Y%.
SP Points to a return address on the user stack (suitable for RET) to continue with the current BASIC statement or program.

From examination of code, it appears that CALL to a non-API address with no parameters erroneously jumps to the parameter buffer instead of to the destination address. To force a correct call at least one parameter must be passed, eg CALL dest,A%. This can be fixed in by patching one byte:

  • v1.04 no patch needed
  • v1.09 offset=&4F63, change &67 to &A7
  • v1.13 offset=&543D, change &67 to &A7

This is equivalent to ?&5163=&A7 (v1.09) or ?&563D=&A7 (v1.13) in the running code.

ARM BASIC

BASIC sets up a data structure in the stack, passing to the routine its location in R9, and the number of records in R10. Apart from the <numeric> call address, this structure contains details of all the variables listed after the CALL keyword, if any. The routine may not change this structure, but can alter the variables it references:

Location Meaning
R9 + 0..3 Last variable Address
R9 + 4..7 Type
R9 + 8..11 Second-to-last variable Address
R9 + 12..15 Type
... ...

The Type value may be one of the following:

Type Object at the given Address (unaligned)
&00 An unsigned, 8-bit byte.
&04 A signed, little-endian, 32-bit integer.
&05 A 40-bit float in 6502 BASIC format.
&08 A 64-bit float in BASIC V format.
&80 A CR-terminated ASCII string.
&81 A string descriptor block, consisting of:

1 × 32-bit address of the start of the string;
1 × byte giving the actual length of the string.
The routine may change and/or shorten the string, but not increase its length.

Finally BASIC sets the state of the CPU as follows, and jumps into the user's routine:

Register Value
R0..R7 Set to the resident integer variables.

R0=A%, R1=B%, R2=C%, R3=D%, R4=E%, R5=F%, R6=G%, R7=H%.

R8 Set to ARGP, a pointer to the BASIC workspace.
R9 Points to a structure representing the variables following the <numeric> (if any).
R10 Set to the number of variables following the <numeric>.
R11 Points to 256 bytes of workspace, used by BASIC to receive text input and compute strings.
R12 Points to within a few bytes of the CALL or USR token that called this routine.
R13 The stack pointer. Points to the top of the BASIC stack (FD type.)
R14 The link register. Contains a return address (suitable for copying to R15) to continue with the current BASIC statement or program.
At the return address is a B instruction to jump into BASIC proper, followed by a list of offsets to internal BASIC variables (to be added to ARGP in R8), and B instructions to jump to BASIC routines. In this way the variables and routines are made officially available to the user's machine code routine.
R15 The program counter. Set to the first, <numeric> argument to CALL.

BBC MOS API Access

To ensure cross-platform compatibility, most non-6502 implementations of BBC BASIC translate CALLs to MOS API entries to an equivalent call to the underlying MOS. The only address that are supported by this are those listed below. The values in A%, X% and Y%, or the data or control block pointed to by X%, are passed in an appropriate manner to the underlying system.

Address MOS call Action
&FFF7 OSCLI Execute *command.
&FFF4 OSBYTE Various byte-wide functions.
&FFF1 OSWORD Various control block functions.
&FFEE OSWRCH Write character to output stream.
&FFE7 OSNEWL Write NewLine to output stream.
&FFE3 OSASCI Write character or NewLine to output stream.
&FFE0 OSRDCH Wait for character from input stream.
&FFDD OSFILE Perform actions on whole files or directories.
&FFDA OSARGS Read and write information on open files or filing systems.
&FFD7 OSBGET Read a byte from an a channel.
&FFD4 OSBPUT Write a byte to a channel.
&FFD1 OSGBPB Read and write blocks of data.
&FFCE OSFIND Open or close a file.

Register usage

CPU Registers on entry Result returned by USR
6502 A=A%, X=X%, Y=Y%, Cy=b0 of C% b0-7=A
b8-15=X
b16-23=Y
b24-31=P
6809 A=A%, B=B%, U=U%, X=X%, Y=Y%, Cy=b0 of C% b0-7=A, b8-15=X
b16-23=Y, b24-31=CC
Z80 A=A%, B=B%, C=C%, D=D%, E=E%, H=H%, L=L% b0-b15=HL'
b16-b31=HL
Z80
BBC API call
A=A%, L=X%, H=H%, E=E% b0-b7=A
b8-b23=HL
b24-31=F
32000 R1=A%, R2=B%, R3=C%, R4=D%, R5=E%, R6=F%, R7=G% b0-b31=R1
32000
BBC API call
R1=A%, R2=X%,
R3..R7=contents of control block at X%
b0-b7=R1
b8-b23=R2
PDP-11 R0=A%, R1=B%, R2=C%, R3=D%, R4=E%, R5=F% b0-b15=R0
b16-b31=R1
PDP-11
BBC API call
R0=A%, R1=X%, R2=Y% b0-b7=R0
b8-b23=R1
ARM R0=A%, R1=B%, R2=C%, R3=D%,
R4=E%, R5=F%, R6=G%, R7=H%
b0-b31=R0
ARM
BBC API call
R0=A%, R1=X%, R2=Y%, or
R1..R5=contents of control block at X%
b0-b7=R0
b8-b31=R1

When passing the address of a data structure or control block, code similar to the following should be used.

   DIM ctrl% 31      :REM Control block, may be anywhere in 32-bit memory space
   X% = ctrl%        :REM X% holds full 32-bit address
   Y% = X% DIV 256   :REM Y% holds 32-bit address, shifted right 8 bits

On 8-bit platforms the high 24 bits of X% and Y% are ignored, and the control block is found with X%+256*Y%. On platforms with larger registers, the control block is found at X%, ignoring Y% completely. Some platforms will check if X%<256 and use X%+256*Y%, though this should not be relied on.

An additional advantage is that the control block is easily accessed with X%, for example, X%!2=load%, etc.

Notes

32000 passes A%=R1, etc., not R0.

When calling &FFCE with A%=0 to close a file, 6502 BASIC requires the channel to be passed in Y% but in ARM BASIC the channel must be passed in X%. When calling from BASIC, the CLOSE# statement should be used.

References

  • BBC BASIC RISC OS 3 Programmer's Reference Manual: BBC BASIC (PDF)
  • Usenet post Roger Wilson's Usenet post of changes in BASIC V 1.04

-- beardo 22:50, 25 June 2007 (BST)