USR is a BASIC function to call (execute) a machine code routine in memory or BBC MOS API entry. It returns a numerical result back to BASIC. 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||BASIC I-V|| <num-var> = |
|Token (hex)||BASIC I-V|| |
|Description||BASIC I-V|| Sets the main CPU registers to the values of the resident integer
variables, and calls a machine code routine at the address given in the <numeric>. The routine should exit with the normal subroutine return instruction. After the routine exits, USR returns an integer holding values returned in CPU registers.
|Associated keywords|| |
USR 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).
USR is one of the ways to access functions of the MOS (its
Application Programming Interface, or API.) Advanced programmers
can also use
USR 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.
USR is involved with the low level architecture of the
computer, its precise function depends on which CPU is running BASIC. The
CPU-specific preparation is the same as in
that there is no table of variables as
USR's only argument
is the <numeric> address. In general,
USR 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>.
After the routine exits, BASIC captures a certain portion of the CPU's
state, and returns it as the numeric result of the
function. The value that is returned is again CPU-dependent:
BBC MOS API Access
To ensure cross-platform compatibility, most non-6502 implementations of BBC
USR to MOS API entries
to an equivalent call to the underlying MOS. The only addresses 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.
|&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.|
|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|
|6809||A=A%, B=B%, U=U%, X=X%, Y=Y%, Cy=b0 of C%|| b0-7=A, b8-15=X|
|Z80||A=A%, B=B%, C=C%, D=D%, E=E%, H=H%, L=L%|| b0-b15=HL'|
BBC API call
|A=A%, L=X%, H=H%, E=E%||b0-b7=A, b8-b23=HL, b24-31=F|
|32016||R1=A%, R2=B%, R3=C%, R4=D%, R5=E%, R6=F%, R7=G%||b0-b31=R1|
BBC API call
| R1=A%, R2=X%,
R3..R7=contents of control block at X%
|PDP-11||R0=A%, R1=B%, R2=C%, R3=D%, R4=E%, R5=F%||b0-b15=R0, b16-b31=R1|
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%, R8=I%, R9=J%
BBC API call
| R0=A%, R1=X%, R2=Y%, or
R1..R5=contents of control block at X%
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.
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
should be used.