Difference between revisions of "CALL"
m (Added 6809.) |
(Added 6809 BASIC details.) |
||
Line 23: | Line 23: | ||
| | | | ||
| | | | ||
− | Sets up a structure in memory representing the given argument variables (if any), | + | Sets up a structure in memory representing the given argument variables (if |
− | sets certain CPU registers to the values of the ''resident integer variables'', | + | any), sets certain CPU registers to the values of the ''resident integer |
− | and jumps into a machine code routine at the address given in | + | 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 | 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 | variables described in the table, and should exit with the normal subroutine | ||
Line 51: | Line 51: | ||
=== 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. | + | &600. Apart from the <numeric> call address, this structure contains details |
− | + | 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 |
− | + | references: | |
{| class="wikitable" | {| class="wikitable" | ||
Line 92: | Line 92: | ||
|} | |} | ||
− | 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 119: | Line 120: | ||
=== 6809 BASIC === | === 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" | ||
+ | | 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. | ||
+ | |} | ||
=== Z80 BASIC === | === Z80 BASIC === | ||
Line 162: | Line 190: | ||
|} | |} | ||
− | 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 190: | Line 219: | ||
|} | |} | ||
− | 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 221: | Line 251: | ||
=== 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: |
(note: some of this information is incorrect) | (note: some of this information is incorrect) | ||
Line 258: | Line 288: | ||
|} | |} | ||
− | If there are no parameters to the CALL, BASIC sets the state of the CPU as follows: | + | If there are no parameters to the CALL, BASIC sets the state of the CPU as |
+ | follows: | ||
{| class="wikitable" | {| class="wikitable" | ||
Line 280: | Line 311: | ||
|} | |} | ||
− | 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 337: | Line 369: | ||
|} | |} | ||
− | 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 372: | Line 405: | ||
== 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 MOS API entries to an equivalent call to the | + | BASIC translate <code>CALL</code>s to MOS API entries to an equivalent call |
− | underlying MOS. The only address that are supported by this are those listed | + | to the underlying MOS. The only address that are supported by this are those |
− | below. The values in A%, X% and Y%, or the data or control block pointed to by | + | listed below. The values in A%, X% and Y%, or the data or control block |
− | X%, are 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 440: | 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 platforms with larger registers, 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 | ||
Line 450: | Line 484: | ||
Yes, 32000 passes A%=R1, etc., '''not''' R0. | Yes, 32000 passes A%=R1, etc., '''not''' R0. | ||
− | When calling &FFCE with A%=0 to close a file, 6502 BASIC requires the channel | + | When calling &FFCE with A%=0 to close a file, 6502 BASIC requires the |
− | to be passed in Y% but in ARM BASIC the channel must be passed in X%. | + | channel to be passed in Y% but in ARM BASIC the channel must be passed in |
− | When calling from BASIC, the <code>[[CLOSE|CLOSE#]]</code> statement should be used. | + | X%. When calling from BASIC, the <code>[[CLOSE|CLOSE#]]</code> statement |
+ | should be used. | ||
== References == | == References == |
Revision as of 16:54, 12 November 2017
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.
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; |
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 |
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 | Type | |
IX+2..3 | First variable | Address |
IX+4 | Type | |
IX+5..6 | Second variable | 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; |
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:
(note: some of this information is incorrect)
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. |
If there are no parameters to the CALL, BASIC sets the state of the CPU as follows:
Register | Value |
---|---|
R1 | Set to the low 8 bits of A% .
|
R2 | Set to the low 8 bits of F% .
|
R3 | Set to the low 8 bits of B% .
|
R4 | Set to the low 8 bits of C% .
|
R5 | Set to the low 8 bits of D% .
|
R6 | Set to the low 8 bits of E% .
|
R7 | The program counter. Set to the first, <numeric> argument to CALL .
|
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. |
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; |
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 is set to A% , R1 to B% , and so on until R7 is set to 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 CALL
s 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
Yes, 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)