From BeebWiki
Jump to: navigation, search

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> = USR(<numeric>)
Token (hex) BASIC I-V BA (function)
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 ?, !, $, CALL



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.

Because 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 CALL, except 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 USR function. The value that is returned is again CPU-dependent:


To ensure cross-platform compatibility, most non-6502 implementations of BBC BASIC translate CALLs and 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.

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'
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%
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
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%
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.


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.

-- beardo 19:06, 5 May 2007 (BST) Jgharston 17:40, 8 October 2007 (BST) Jgharston (talk) 15:02, 19 August 2017 (CEST)