RISCOS.com

www.riscos.com Technical Support:
Programmer's Reference Manual

 

Program Environment


Introduction

The program environment refers to the conditions under which a program or module executes. There are three aspects to this environment.

  • The memory used by the code and allocated for transient workspace.
  • The handlers used by a program or module.

    A handler is a piece of code called when certain conditions occur. RISC OS provides a set of default handlers, so that a sensible default action will occur under such conditions. Here is a brief list of the kinds of conditions that we are talking about:

    • an error
    • an escape condition
    • an event
    • certain hardware exceptions, such as an undefined instruction
    • a break point
    • an unknown SWI being called
    • a program or module terminating.
  • The system variables are a textual way of finding information about various aspects of the system. There are several kinds of variables:
    • string variables which contain characters only
    • integer variables which contain an integer
    • macro variables which are like string variables, except that they can contain references to special characters and other system variables.

Overview and Technical Details

Executing code

There are several ways of executing a piece of code. You can:

  • *RMRun a module
  • OS_Module 'Enter' a module
  • *Run a program
  • *Go, to execute a program in memory
Modules

The first two are described in the chapter entitled Modules. They are really the same thing. When a file is *RMRun, it is loaded into the relocatable module area. Its initialisation code is called, so that it can claim workspace etc, then its start code is called.

A module can also cause its own start entry point to be called if it wants to become the current application, using OS_Module. BASIC is an example of this. The *BASIC command is recognised by the OS using the BASIC module's * Command table. The OS calls the routine which handles the *BASIC command, and this routine calls OS_Module with the reason code 'enter'. For details on calling modules see the chapter entitled Modules.

Programs on file

The third case applies to files which have no file type, or have type &FF8. In the first case, the file is loaded at its load address, then it is started as an application through its execution address. If the file type is &FF8, the file is loaded at &8000 and started as an application there. See also the Transient programs below.

Programs in memory

Finally, if you call a machine code program using the *Go command, it becomes the current application. (This implies that you shouldn't use *Go to call RAM-based routines from a language, as the routine can't return - R14 contains no return address at this point.)

In all of these cases, the program is called in user mode, with interrupts enabled. Where a module is called, R12 points to the module's private word.

Transient programs

A file with type &FFC (Utility) must contain position independent code. When such a file is *Run, it is loaded into the RMA and executed. This is used when you want to run a utility and then return to the program environment that you were in before running it. On entry to a transient program, registers are as follows:

    R0 = pointer to command line
    R1 = pointer to command tail
    R12 = pointer to workspace
    R13 = pointer to workspace end (stack)
    R14 = return address
    User mode, interrupts enabled

The workspace is 1024 bytes long, in the location given by R12 and R13 on entry. If more is required, it may be allocated from the RMA. The utility should return using MOV PC,R14 (freeing any extra workspace first). It does not become the current application and must not call OS_Exit; see the chapter entitled Ending a task below.

Note that R0 points to the first character of the command name, and R1 points to the first character of the command tail (with spaces skipped). This will be a control character if there were no parameters.

When a utility returns, the space it occupies is freed. Utilities are nestable - you can execute one utility from within another.

Note that utilities are viewed as system extensions. This means that they must only use the X form SWIs, so that the error handler is not called by their actions. A utility can return with an error by setting V and pointing R0 at an error block as usual.

Ending a task

Before describing the calls which control the application program's environment, it is worth explaining how to leave an application. In general, a simple 'return from subroutine' using MOV PC,R14 won't suffice. Instead, you should use a routine called OS_Exit. This passes control back to a well-defined place, which defaults to the supervisor * prompt, but could equally be a location in the previous application.

*Quit is equivalent to a call to OS_Exit.

OS_ExitAndDie is like OS_Exit, but will kill a named module as well. This may be used, for example, when a module is specific to a particular application and you wish to kill the module when the application exits.

System variables

The system variables, maintained by the operating system in the system heap, provide a convenient way by which programs can communicate. Variables are accessed by their textual name. The name may contain any non-space, non-control character. When a variable is created, the case of the letters is preserved. However, when names are looked up the case is ignored, and you can use the characters '#' and '*' - just like looking up filenames.

Naming

You should avoid the use of wholly numeric names for system variables, such as 123, as this causes difficulties when the GS string operations are used to look up a variable's contents. In particular, they will always take <123> to mean the ASCII code 123, and will not attempt to look up the name as a variable. See the chapter entitled Conversions for details of the GS calls, specifically OS_GSRead and OS_GSTrans.

Types

There are several types of system variable:

  • String variables can contain any characters you like; these are returned when the string is read. They can be set with *Set.
  • Integer variables are four-byte signed integers. They can be set with *SetEval.
  • Macros are strings that are passed through OS_GSTrans when the string is read. This means that if the macro contains references to variables or other OS_GSReadable items, the appropriate translation takes place whenever the variable is accessed. They can be set with *SetMacro.

A classic example of using a macro is to set the command line prompt CLI$Prompt to the current time using:

*SetMacro CLI$prompt <Sys$Time><&20>

Every time the prompt is displayed, it shows the current time, followed by a space.

  • The final type of variable is machine code routines. A routine is called whenever the variable is to be read, and another when it is set. This allows great flexibility in the way in which such variables behave. For example, you could make a variable directly control a CMOS RAM location using this technique. Sys$Time is a good example of a code variable.

All the above types can be set with OS_SetVarVal and read with OS_ReadVarVal.

Any non-code variable can be removed using *Unset. *Show will list the setting of one or more variables.

Miscellaneous environment features

OS_GetEnv is a multi-purpose SWI that provides three useful pieces of information:

  1. The address of the * Command string used to run the program.

    This can be processed with OS_ReadArgs, which is described on OS_ReadArgs of the Conversions.

  2. The real time that the program was started.
  3. The maximum amount of memory available to the program.

    This can be altered with reason code 0 of OS_ChangeEnvironment; see OS_ChangeEnvironment for more details.

OS_WriteEnv allows you to set the program start time and the command string.

Handlers

Handlers are short routines used to cope with special conditions that can occur under RISC OS. Here is a complete list of the handlers:

    Handler
    Undefined instruction
    Prefetch abort
    Data abort
    Address exception
    Error
    CallBack
    BreakPoint
    Escape
    Event
    Exit
    Unused SWI
    UpCall

All of the calls that install user handlers pass through ChangeEnvironmentV. This can be intercepted to stop a subprogram changing parts of the environment that its parent wants to keep: for example, a debugger.

Before reading this section, you should be familiar with the chapters entitled Software vectors and Hardware vectors, since many of these handlers are directly called from these vectors.

SWIs

OS_ChangeEnvironment is the central SWI for handlers. There are several other routines that perform subsets of its actions. You are strongly recommended to use OS_ChangeEnvironment in any new applications as the others are only provided for compatibility.

The other calls are OS_Control, OS_SetEnv, OS_CallBack, OS_BreakCtrl and OS_UnusedSWI.

OS_ReadDefaultHandler allows you to get the address and details of any of the default handlers. This would be used if you wished to set up a well-defined state before running a subprogram: for example, the Desktop does so.

Details of Handlers

When a handler is called, you should not expect to be able to see the foreground application's registers. You should only rely on those registers explicitly defined in each handler as being meaningful on entry.

You should take care not to corrupt R14_SVC during handler code. This implies saving it on the stack if you use SWIs; see the chapter entitled Interrupts and handling them for details. The details of each of the handlers follows:

Undefined instruction, Prefetch abort, Data abort and Address exception

These handlers are all called from hardware vectors. For a description of them see the chapter entitled Hardware vectors. These handlers are all entered with the processor in SVC mode.

All of the default handlers simply generate errors, which are passed to the current error handler.

Error

The error handler is called after any error has been generated. It is called by the default routine on the error vector; thus any routines using this vector should always 'pass it on'. Continuing after an error is not generally recommended. You should always use the X form SWIs if you wish to stay in control even when an error occurs.

The error handler is entered in User mode with interrupts enabled. Note that if the error handler is set up using OS_ChangeEnvironment, the workspace pointer is passed in R0, not R12 as is usual for other handlers.

The error handler must provide an error buffer of size 256 bytes, the address of which should be set along with the handler address. On an error the buffer will be set to contain the following:

    Offset Contents
    0 - 3 PC when error occurred
    4 - 7 Error number provided with the error.
    8... Error string, terminated with a 0

The default error handler reports the error message and number - although applications frequently set up their own error handlers. BASIC is one such example.

BreakPoint

This handler is called when the SWI OS_BreakPt is called. All the user mode registers are dumped into a buffer (the register save block), and then the handler is entered in SVC mode.

When setting the address of a replacement break point handler you must also specify the address of the register save block, which must be word aligned and 16 words long. You can also specify a pointer to workspace to pass in R12 when your handler is called.

The following code is suitable to restore the user registers and return:

ADR    R14, saveblock          ; get address of saved registers
LDMIA  R14, {R0-R14}^          ; load user registers from block;
                               ; note that user R13,R14 are altered
MOV    R0, R0                  ; no-op after forcing User mode
LDR    R14, [R14,#15*4]        ; load user PC into SVC R14
MOVS   PC, R14                 ; return to correct address and mode

The default handler displays the message 'Break point at &xxxxx' and calls OS_Exit.

Escape

This handler is called when an escape condition is detected. See the chapter entitled Character Input for details of this. You can specify a pointer to workspace to pass in R12 when this handler is called.

When the handler is entered, registers have the following values:

    R11 bit 6 set, implying escape condition
    R12 pointer to workspace, if set up - should never be 1
    R13 a full, descending stack pointer

To continue after an escape, the handler should reload the PC with the contents of R14. If R12 contains 1 on return then the CallBack flag is set; for details of the action this causes, see the chapter entitled CallBack. Typically (eg for BASIC), the handler will set an internal flag which is checked by the foreground program.

Event

This handler is called by the default owner of EventV when an event occurs. You can specify a pointer to workspace to pass in R12 when this handler is called.

When the handler is entered the processor is in either SVC or IRQ mode, with the following register values:

    R0 event reason code
    R1... parameters according to event code
    R12 pointer to workspace, if set up - should never be 1
    R13 a full, descending stack pointer

To continue after an event, the handler should reload the PC with the contents of R14. Again, if R12 contains 1 on return then the CallBack flag is set; for details of the action this causes, see the chapter entitled CallBack.

Exit

This handler is called when the SWIs OS_Exit or OS_ExitAndDie are called. It is entered with the processor in user mode. You can specify a pointer to workspace to pass in R12 when this handler is called.

Unused SWI

This handler is called by the default owner of the UKSWIV. (When a SWI is called, RISC OS first checks if it is a kernel SWI; it then checks if it is a module SWI by looking at its hash table constructed from the headers of initialised modules. It then calls UKSWIV; this allows a user routine on that vector to try to deal with the SWI. If there is no such routine, or the one(s) that is present passes the call on, then the default owner of the vector - which is the kernel - calls the Unused SWI handler).

The default handler returns the error 'SWI &xxxxxxxx not known', or just 'SWI not known' if the SWI was called from an IRQ process.

You can specify a pointer to workspace to pass in R12 when this handler is called.

When the handler is entered the processor is in SVC mode, with interrupts in the same state as the caller. The registers have the following values:

R11 SWI number (Bit 17 clear)
R13 SVC stack pointer
R14 user PC with V cleared

R10, R11 and R12 are stacked and are free for your own use.

UpCall

This handler is called by the default owner of UpCallV when OS_UpCall is called. OS_UpCall is used to warn your program of errors and situations that you may be able to recover from. See the chapters entitled Software vectors and Communications within RISC OS. You can specify a pointer to workspace to pass in R12 when this handler is called.

CallBack

This handler is called whenever RISC OS's internal CallBack flag is set, and the system next exits to User mode with interrupts enabled. It uses a register save block (the address of which should be set along with the handler address) in which all the registers are dumped when the handler is called. This must be word-aligned and 16 words long. You can specify a pointer to workspace to pass in R12 when this handler is called. A more detailed description follows.

CallBacks in more detail

There are two types of CallBack usage under RISC OS:

  • Transient CallBacks are placed in a list by calling OS_AddCallBack. They are used to deal with a specific case, and are called once before being removed.
  • The CallBack handler is permanent and takes all CallBacks that are not intercepted by transients. These CallBacks are explicitly requested by calling OS_SetCallBack. They can also be implicitly requested by setting R12 to 1 on exit from either an escape or event handler. There is a system default CallBack handler, but you can of course replace it using OS_ChangeEnvironment.
Transient CallBacks

Transient CallBacks may be called on the system being threaded out of - that is, when it enters User mode with interrupts enabled. They can also be called when RISC OS is idling; for example, while it is waiting in OS_ReadC.

Transient CallBacks are usually set up by an interrupt routine that needs to do complex processing that would take too long in an interrupt, or that needs to call a non-re-entrant SWI. OS_AddCallBack tells RISC OS that the interrupt routine wishes to be 'called back' when the machine is in a state that no longer imposes the restrictions associated with an interrupt routine. OS_RemoveCallBack removes a transient CallBack; this is most useful if the module is being killed before the transient CallBack has been serviced.

Transient CallBacks can safely be used by many clients.

You must not rely on any relationship between the order in which Transient CallBacks are added and the order in which they are called.

Transient CallBacks are not calle between successive lines of an Obey file, nor when the screen scrolling is disabled by the Scroll Lock or Ctrl-Shift keys.

Other CallBacks

The CallBack handler is only ever called on the system being threaded out of - that is, when it enters User mode with interrupts enabled. Unlike transient CallBacks, it is not called when RISC OS is idle. This means that you cannot rely on being called back within any given time. You must take this into consideration before using a CallBack handler.

Also, you must not allow a second CallBack before your first one has completed; see the chapter entitled Application Notes for an example of how to implement a semaphore to prevent this.

The CallBack code is called in IRQ or supervisor mode with interrupts disabled. The PC stored in the save block will be a user mode PC with interrupts enabled. Note that if the currently active program has interrupts disabled or is running in supervisor mode, CallBack is not used.

In the simple case the CallBack routine should be exited by:

ADR     R14, saveblock          ; get address of saved registers
LDMIA   R14, {R0-R14}^          ; load user registers from block -
                                ; note that user R13,R14 are altered
MOV     R0, R0                  ; no-op after forcing User mode
LDR     R14, [R14,#15*4]        ; load user PC into SVC R14
MOVS    PC, R14                 ; return to correct address and mode

In RISC OS 3 (version 3.10) or later, the supervisor stack must also be empty when the CallBack handler is called. This ensures that certain module SWIs that temporarily enter User mode (so that transient CallBacks are called) do not cause the CallBack handler to be called.

Currently active object pointer

This is a pointer to the address of: the last application started, or the last error handler called, or the last exit handler called. It is used by OS_Module to determine whether a module can be killed.

Setting up and restoring the environment

In order to deal correctly with the various ways in which applications can be run, and killed off, the following approach has been developed for setting up the program environment when an application starts, and restoring it when it is killed. The basic problems are:

  • if a new application is started 'on top' of the currently active one, it should completely replace the first, and should therefore have the same 'parent' environment as the first application.
  • if the currently active application is killed off, it must restore its 'parent' environment.
Using high level languages

Typically these are handled for you by run-time language libraries, and so if you are writing in a high-level language you do not need to worry.

Using machine code or writing a run-time language library

However, if you are yourself writing a run-time language library, or if you are writing your application in machine code (for example as a module which runs as a Wimp task) you must take one of these two possible approaches:

  • Do not set up any handlers at all, and always call the 'X' form of SWIs, to avoid calling the error handler. If the error handler is called, the application will be terminated, as the parent error handler will be invoked.
  • Set up Error, Exit and UpCall handlers as described below, so that the program environment can be restored correctly when the program terminates. You must provide all three of these handlers if you use any handlers at all, otherwise there will be some circumstances in which your application can be replaced or killed without restoring its 'parent' environment.
Starting an application

When you start an application, you must:

  1. Check that there is sufficient memory to do so - if not, call OS_GenerateError ('Not enough application memory')
  2. Set up your handlers using the SWI XOS_ChangeEnvironment; store the values returned in R1-R3 so you can later restore the old handlers.

Note that you must store the previous values not only for Exit, Error and UpCall handlers, but also for any other handlers that are set up.

If your Error handler is called

If your error handler is called and you want to call the 'external' error handler (eg BASIC if '-quit' was on the command line), you should:

  1. restore all handlers to their original values (R1 - R3 for each)
  2. call OS_GenerateError.
If your Exit handler is called

If your exit handler is called you should:

  1. restore all handlers to their original values (R1 - R3 for each)
  2. call OS_Exit.
If your UpCall handler is called

If your UpCall handler is called and R0 = UpCall_NewApplication (256), you should:

  1. restore all handlers to their original values (R1 - R3 for each)
  2. return to the caller, preserving all registers (ie carry on and start the new application).
Summary

The approach described above ensures that it is not possible for your application to be terminated without it first restoring all handlers to their original values.

SWI Calls


OS_Control
(SWI &0F)

Read/write handler addresses

On entry

R0 = pointer to error handler, or 0 to read
R1 = pointer to error buffer, or 0 to read
R2 = pointer to escape handler, or 0 to read
R3 = pointer to event handler, or 0 to read

On exit

R0 = pointer to previous error handler
R1 = pointer to previous error buffer
R2 = pointer to previous escape handler
R3 = pointer to previous event handler

Interrupts

Interrupts are not enabled
Fast interrupts are enabled

Processor Mode

Processor is in IRQ or SVC mode

Re-entrancy

SWI cannot be re-entered as interrupts are disabled

Use

OS_Control sets some of the exception handlers. The addresses of the error handler, error handler buffer, escape handler and event handler are passed in R0 - R3. Zero for any of these means no change - hence you can read the current value. The error buffer must be 256 bytes long.

Note that the call OS_ChangeEnvironment provides all of the facilities that this call provides, and should be used in preference. In fact, this call uses OS_ChangeEnvironment.

Related SWIs

OS_ChangeEnvironment

Related vectors

ChangeEnvironmentV


OS_GetEnv
(SWI &10)

Read environment parameters

On entry

--

On exit

R0 = pointer to environment string
R1 = permitted RAM limit (ie highest address available + 1)
R2 = pointer to real time the program was started (5 bytes)

Interrupts

Interrupt status is unaltered
Fast interrupt status is unaltered

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is re-entrant

Use

This SWI reads some information about the program environment.

The environment string pointed to by R0 is normally a copy of the command line used to start the program. However, there may be some circumstances where a command line was not used to start the program; in such cases a meaningful string is still passed. For example, if a module is started using OS_Module 2, the string passed will be '<module title> <parameter string passed in R2 on entry to OS_Module>'.

R1 returns the address of the byte above the last one available to the application. You can alter this using reason code 0 of OS_ChangeEnvironment.

The five bytes pointed to by R2 give the real time the program was started: ie centiseconds since 00:00:00 01-Jan-1900.

You can set these values using OS_WriteEnv.

Related SWIs

OS_ChangeEnvironment, OS_WriteEnv

Related vectors

None


OS_Exit
(SWI &11)

Pass control to the most recent exit handler

On entry

R0 = pointer to error buffer
R1 = 'ABEX' (&58454241) if return code is to be set
R2 = return code

On exit

Never returns

Interrupts

Interrupt status is unaltered
Fast interrupt status is unaltered

Processor Mode

Processor is in USR mode

Re-entrancy

SWI is not re-entrant

Use

When OS_Exit is called, control returns to the most recent exit handler. The BASIC statement QUIT performs an OS_Exit. Before executing OS_Exit, however, you must restore any of the handlers changed in starting the application.

If the exiting program wishes to return with a return code, it must set R1 to the hex value shown above, and R2 to the desired value. The value should be zero to indicate no error; otherwise the value should indicate the severity of the error, so 1, for example might indicate a trivial error or warning. The return value is assigned to the variable Sys$ReturnCode, which can be interrogated by any program using OS_ReadVarVal.

If the returned value is greater than the value of the system variable Sys$RCLimit, RISC OS also gives the error 'Return code limit exceeded' (&1E2). The user can alter the value of Sys$RCLimit to control which errors are returned; your application should not itself alter the variable.

Related SWIs

OS_ExitAndDie

Related vectors

None


OS_SetEnv
(SWI &12)

Set environment parameters

On entry

R0 = pointer to exit handler, or 0 to read
R1 = permitted RAM limit (ie highest address available + 1), or 0 to read
R4 = pointer to undefined instruction handler, or 0 to read
R5 = pointer to prefetch abort handler, or 0 to read
R6 = pointer to data abort handler, or 0 to read
R7 = pointer to address exception handler, or 0 to read

On exit

R0 = pointer to previous exit handler
R1 = previous permitted RAM limit (ie highest address available + 1)
R4 = pointer to previous undefined instruction handler
R5 = pointer to previous prefetch abort handler
R6 = pointer to previous data abort handler
R7 = pointer to previous address exception handler

Interrupts

Interrupts are disabled
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is not re-entrant

Use

OS_SetEnv sets several of the handlers for a program.

Note that the call OS_ChangeEnvironment provides all of the facilities that this call provides, and should be used in preference. In fact, this call uses OS_ChangeEnvironment.

Related SWIs

OS_ChangeEnvironment

Related vectors

ChangeEnvironmentV


OS_CallBack
(SWI &15)

Set up the CallBack handler

On entry

R0 = pointer to CallBack register save block, or 0 to read
R1 = pointer to CallBack handler, or 0 to read

On exit

R0 = pointer to previous CallBack register save block
R1 = pointer to previous CallBack handler

Interrupts

Interrupt status is unaltered
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is re-entrant

Use

OS_CallBack sets up the address of the CallBack handler and the register save block, zero for either value meaning no change - hence you can read the current value. The register save block must be word-aligned and 16 words long.

Note that the call OS_ChangeEnvironment provides all of the facilities that this call provides, and should be used in preference. In fact, this call uses OS_ChangeEnvironment.

Related SWIs

OS_ChangeEnvironment

Related vectors

ChangeEnvironmentV


OS_BreakPt
(SWI &17)

Cause a break point trap to occur and the BreakPoint handler to be entered

On entry

--

On exit

--

Interrupts

Interrupt status is unaltered
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

Not defined

Use

When OS_BreakPt is executed, all the user mode registers are saved in a block and the BreakPoint handler is called. The saved registers are only guaranteed to be correct for user mode.

The default handler displays the message 'Break point at &xxxxx' and calls OS_Exit.

This SWI would be placed in code by the debugger at required breakpoints.

Related SWIs

OS_BreakCtrl

Related vectors

None


OS_BreakCtrl
(SWI &18)

Set up the BreakPoint handler

On entry

R0 = pointer to BreakPoint register save block, or 0 to read
R1 = pointer to BreakPoint handler, or 0 to read

On exit

R0 = pointer to previous BreakPoint register save block
R1 = pointer to previous BreakPoint handler

Interrupts

Interrupt status is unaltered
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is re-entrant

Use

OS_BreakCtrl sets up the address of the BreakPoint handler and the BreakPoint register save block, zero for either value meaning no change - hence you can read the current value. The register save block must be word-aligned and 16 words long.

Note that the call OS_ChangeEnvironment provides all of the facilities that this call provides, and should be used in preference. In fact, this call uses OS_ChangeEnvironment.

Related SWIs

OS_BreakPt, OS_ChangeEnvironment

Related vectors

ChangeEnvironmentV


OS_UnusedSWI
(SWI &19)

Set up the handler for unused SWIs

On entry

R0 = pointer to unused SWI handler; or 0 to read

On exit

R0 = pointer to previous unused SWI handler

Interrupts

Interrupt status is unaltered
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is not enabled

Use

OS_UnusedSWI sets up the address of the unused SWI handler, zero meaning no change - hence you can read the current value.

Note that the call OS_ChangeEnvironment provides all of the facilities that this call provides, and should be used in preference. In fact, this call uses OS_ChangeEnvironment.

Related SWIs

OS_ChangeEnvironment

Related vectors

ChangeEnvironmentV


OS_SetCallBack
(SWI &1B)

Cause a call to the CallBack handler

On entry

--

On exit

--

Interrupts

Interrupts are disabled
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI cannot be re-entered because interrupts are disabled

Use

OS_SetCallBack sets the CallBack flag and so causes entry to the CallBack handler when the system next exits to user mode code with interrupts enabled (apart, of course, from the exit from this SWI). This SWI may be used if the code linked into the system (via a vector or as a SWI handler, etc) is required to do things on exit from the system.

Related SWIs

OS_CallBack

Related vectors

None


OS_ReadVarVal
(SWI &23)

Read a variable value

On entry

R0 = pointer to variable name, which may be wildcarded (using '*' and '#')
R1 = pointer to buffer to hold variable value
R2 = maximum length of buffer, or bit 31 set to check existence/length of variable
R3 = context pointer (used with wildcarded names), or 0 for first call
R4 = 3 if an expanded string is to be converted on return

On exit

R0 preserved; or corrupted if R2 bit 31 was set on entry
R1 preserved
R2 = number of bytes read
R3 = new context pointer (null-terminated)
R4 = variable type

Interrupts

Interrupts are enabled
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is re-entrant

Use

OS_ReadVarVal reads a variable and returns its value and its type.

Before reading a variable you must check the length of the data that will be returned. To do so, call XOS_ReadVarVal with R2 set to a value less than zero (bit 31 set) on entry. You can also use this to check for the existence of a variable.

  • If the variable exists, R2 will still be negative on exit; furthermore, if R4 [NOT EQUAL] 3 on entry (ie the variable is not an expanded string) the value of R2 is NOT (length of value).
  • If the variable does not exist R2 will be zero on exit.

When using the call in this manner, you may get an error on exit, which you should ignore. This feature is not available under RISC OS 2; in this case you may assume that the length of the variable will be at most 256 bytes.

For a wildcarded name R3 should be 0 on entry the first time the call is made, and thereafter preserved from the previous call. On exit, R3 points to the name of the variable found. This enables all matches to be found. The XOS_ReadVarVal form of the call should be used if you don't want an error to occur after the last name has been found.

R4, if set to 3 on entry, indicates that a suitable conversion to a string should be performed. String variables are unaltered, numbers are converted to (signed) decimal strings, and macros are OS_GSTrans'd.

If R4 isn't 3 on entry, the un-OS_GSTrans'd version of a macro is returned, and the four-byte binary of a number is returned.

The type of the variable read is returned in R4 as follows:

    Value Type
    VarType_String (0) String
    VarType_Number (1) 4 byte (signed) integer
    VarType_Macro (2) Macro

Returned strings are not terminated, and you should use the length returned in R2 when reading them.

See the chapter entitled Application Notes for an example of reading a variable.

Related SWIs

OS_SetVarVal

Related vectors

None


OS_SetVarVal
(SWI &24)

Write a variable value

On entry

R0 = pointer to variable name, which may be wildcarded (* and #) if updating/deleting
R1 = pointer to variable value
R2 = length of value, or negative to delete the variable
R3 = context pointer (used with wildcarded names), or 0 for first call
R4 = variable type

On exit

R0 - R2 preserved
R3 = new context pointer (null-terminated)
R4 = variable type created if expression is evaluated

Interrupts

Interrupts are enabled
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is not re-entrant

Use

OS_SetVarVal either creates, updates or deletes a variable. The variable's name is pointed to by R0, and may be terminated by any character whose ASCII value is 32 or less. It may be wildcarded if the variable is to be updated or deleted (ie if it already exists).

To delete a variable, R2 must be negative on entry; if the variable is a code variable (see below), the variable type in R4 must be set (ie R4 = 16).

When creating or updating a variable, R1 must point to the value to be assigned. The interpretation of this value depends on the type given in R4 as follows:

    Value Type
    VarType_String (0) Value is a string which will be OS_GSTrans'd immediately
    VarType_Number (1) Value is a 4 byte (signed) integer
    VarType_Macro (2) Value is a string which will be OS_GSTrans'd each time it is used
    VarType_Expanded (3) Value is a string which will be evaluated as an expression using OS_EvaluateExpression, and assigned to a number or string variable, depending on the expression type
    VarType_LiteralString (4) Value is a literal string (ie it will not be OS_GSTrans'd)
    VarType_Code (16) Special case (see below)

With the exception of a literal string, all strings must be terminated by a linefeed (ASCII 10) or carriage return (ASCII 13) or null (ASCII 0).

If the call is successful, R3 is updated to point to the new context so allowing the next match of a wildcarded name to be obtained on a subsequent call. R4 returns the type created if an expression was evaluated (ie if R4 was 3 on entry).

VarType_Code

When R4 is set to 16 on entry (and R2 >= 0) a code variable may be created. In this case R1 is the pointer to the code fragment associated with the variable, and R2 is the length of the code fragment. This code must be word-aligned and takes the following format:

    Offset Contents
    0 Branch instruction to entry point for write operation
    4 Entry point for read operation
    8... Body of code...

Values are always written to (and read from) code variables as strings. The entry for the write operation is called whenever the variable is to be set, as follows:

    On entry

    R1 = pointer to the value to be used
    R2 = length of value

    On exit

    R1, R2, R4, R10 - R12 may be corrupted

The entry for the read operation is called whenever the variable is to be read by a call to OS_ReadVarVal, as follows:

    On entry

    --

    On exit

    R0 = pointer to value
    R1 = corrupted
    R2 = length of value

Both entries are called in SVC mode, therefore if any SWIs are used, R14 must be saved on the stack so that it does not become corrupted. The SVC stack is used, and no workspace is reserved. You can return errors by setting the V flag as usual.

See the chapter entitled Application Notes for an example of a code variable.

Note that when a function key is input, the appropriate variable Key$n is read using OS_ReadVarVal. Therefore by creating your own code variables with these names, you can cause the reading of a function key to cause a routine to be called instead of just a string being read.

Errors

OS_SetVarVal can return the following errors:

  • Bad name - Wildcards/control characters in name when creating
  • Bad string - OS_GSTrans unable to translate string
  • Bad macro value - Control characters in the value string (R1)
  • Bad expression - Expression cannot be evaluated
  • Variable not found - For deletion or update
  • No room for variable - Not enough room to create/update it (system heap full)
  • Variable value too long - Variables are limited to 256 bytes in RISC OS 2 and RISC OS 3 (version 3.00)
  • Bad variable type
<54>Related SWIs

OS_ReadVarVal

Related vectors

None


OS_ChangeEnvironment
(SWI &40)

Install a handler

On entry

R0 = handler number
R1 = pointer to new handler, or 0 to read
R2 = value of R12 with which to call the handler, or 0 to read
R3 = pointer to buffer (if appropriate), or 0 to read

On exit

R0 preserved
R1 = pointer to previous handler
R2 = previous value of R12 with which to call the handler
R3 = pointer to previous buffer

Interrupts

Interrupt status is unaltered
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is re-entrant

Use

OS_ChangeEnvironment is a single routine which performs the actions of OS_Control, OS_SetEnv, OS_CallBack, OS_BreakCtrl, and OS_UnusedSWI. In fact, all of those routines use this call. In new programs, you should always use this call in preference to the earlier ones.

For full details of the handlers, see the section earlier in this chapter.

On entry, R0 contains a code which determines which particular handler's address is to be set up. The new address is passed in R1. R0 also determines whether R2 and R3 are relevant or not. This is summarised in the table below:

R0 Handler R2 R3
0 MemoryLimit Ignored Ignored
1 Undefined instruction Ignored Ignored
2 Prefetch abort Ignored Ignored
3 Data abort Ignored Ignored
4 Address exception Ignored Ignored
5 Other exceptions Ignored Ignored
6 Error R0 when called Error buffer address
7 CallBack R12 when called Register buffer address
8 BreakPoint R12 when called Register buffer address
9 Escape R12 when called Ignored
10 Event R12 when called Ignored
11 Exit R12 when called Ignored
12 Unused SWI R12 when called Ignored
13 Exception registers Ignored Ignored
14 Application space Ignored Ignored
15 Currently active object Ignored Ignored
16 UpCall R12 when called Ignored

The 'Memory limit' (handler 0) is the permitted RAM limit, as used by OS_GetEnv. The 'Application space' (handler 14) is the amount of read/write memory in application space. Consequently it should always be the case that Application space >= Memory limit.

'Other exceptions' (handler 5) is for future expansion.

The error buffer (handler 6) must be 256 bytes long.

The register buffers (handlers 7 and 8) must be word-aligned and 16 words long.

Handler 13 sets the address of the area in memory where the registers are dumped when one of the exceptions (1 - 5) occurs, if the default handlers are used. Again, this must be word-aligned and 16 words long.

Note that in order to perform its function, OS_ChangeEnvironment vectors through ChangeEnvironmentV. A routine linked onto this vector can stop the change from happening by setting R1 (and if appropriate R2, R3) to zero and passing the call on; see the chapter entitled Software vectors.

Related SWIs

OS_Control, OS_SetEnv, OS_CallBack
OS_BreakCtrl, OS_UnusedSWI

Related vectors

ChangeEnvironmentV


OS_WriteEnv
(SWI &48)

Set the program environment command string and start time

On entry

R0 = pointer to environment string
R1 = pointer to real time the program was started (5 bytes)

On exit

R0, R1 preserved

Interrupts

Interrupt status is unaltered
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is re-entrant

Use

This call sets the environment string and start time for an application, as returned by OS_GetEnv. For more details see OS_GetEnv on OS_GetEnv.

This SWI is mainly used by debuggers.

Related SWIs

OS_GetEnv

Related vectors

None


OS_ExitAndDie
(SWI &50)

Kill a module and pass control to the most recent exit handler

On entry

R0 = pointer to error buffer
R1 = 'ABEX' (&58454241) if return code is to be set
R2 = return code
R3 = pointer to module name

On exit

never returns

Interrupts

Interrupt status is unaltered
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is not re-entrant

Use

This SWI is like OS_Exit, except that it will kill a module before exiting. R3 points to a string containing the module's name. For more details, see OS_Exit on OS_Exit.

Related SWIs

OS_Exit

Related vectors

None


OS_AddCallBack
(SWI &54)

Add a transient CallBack to the list

On entry

R0 = address to call
R1 = value of R12 to be called with

On exit

R0 = preserved
R1 = preserved

Interrupts

Interrupts are disabled
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is re-entrant

Use

This call places a transient CallBack on a list of tasks who want to be called as soon as RISC OS is not busy. Usually, this will be just before returning from a SWI or while waiting for a key and so on.

This SWI is usually called from an interrupt routine that needs to do complex processing that would take too long in an interrupt, or that needs to call a non-re-entrant SWI. Note that you don't also need to call OS_SetCallBack, which is only needed when using the CallBack handler.

A routine called by this mechanism must preserve all registers and return by

MOV PC, R14

Related SWIs

OS_RemoveCallBack

Related vectors

None


OS_ReadDefaultHandler
(SWI &55)

Get the address of the default handler

On entry

R0 = reason code (0 - 16)

On exit

R0 preserved
R1 = pointer to default handler
R2 = pointer to workspace
R3 = pointer to buffer

Interrupts

Interrupt status is unaltered
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is re-entrant

Use

Using the same handler number in R0 as those in OS_ChangeEnvironment (see R0 Handler R2 R3), this SWI returns details about the default handler.

Zero in R1, R2 or R3 on exit means that it is not relevant.

Related SWIs

OS_ChangeEnvironment

Related vectors

None


OS_RemoveCallBack
(SWI &5F)

Removes a transient CallBack from the list

On entry

R0 = address that was to be called
R1 = value of R12 that the routine was to be called with

On exit

R0, R1 preserved

Interrupts

Interrupts are disabled
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is re-entrant

Use

This call removes a transient CallBack from the list. You should do so if your module has an outstanding CallBack request, but will not be able to service the request when it is granted - for example if the module is being killed.

This call is not available in RISC OS 2, which can cause problems. For example, if a module is being killed and it has outstanding CallBack requests, it must refuse to die, otherwise the CallBack may be granted after that memory has been reused for something else.

Related SWIs

OS_AddCallBack

Related vectors

None

* Commands


*Go

Calls machine code at the given address

Syntax

*Go [hexadecimal_address] [ ; environment]

Parameters

hexadecimal_address address of machine code to call
environment environment string to pass to machine code

Use

*Go calls machine code at the given address, passing it an optional environment string. If the address is omitted, it defaults to &8000, which is where application programs (such as the C compiler) are loaded.

*Go enters an application, and you cannot use it to run machine code subroutines.

Example

*Go 9000 ; SrcList
Call machine code at &9000, passing it the string 'SrcList'

Related commands

None

Related SWIs

None

Related vectors

None


*Quit

Exits from the current application

Syntax

*Quit

Parameters

None

Use

*Quit exits from the current application - that is, it returns to the previous context.

Related commands

*GOS

Related SWIs

OS_Exit

Related vectors

None


*Set

Assigns a string value to a system variable

Syntax

*Set varname value

Parameters

varnamea variable name, or a wildcard specification for a single variable name
valuestring value to GSTrans and then assign to the system variable varname

Use

*Set assigns a string value to a system variable, like an assignment statement in a programming language. For example:

*Set varname text

assigns the string 'text' to the variable varname. The string is OS_GSTrans'd before it is assigned.

Aliases

Another use for the *Set command is to change the name of a command to one which is more convenient for the user:

*Set Alias$name cname

establishes name as an alternative name for the command cname; for example after:

*Set Alias$Aid Help

the command *Aid is now a synonym for *Help; both commands access the help system. Another example is:

*Set Alias$Mode Echo |<22>|<%0>

*Mode 12

The command implements a new command *Mode, which sets the screen to mode 12 (in the above case). The Echo command reflects the string which follows it; |<22> generates the ASCII character 22, Ctrl V, which is equivalent to the VDU command to change mode. |<%0> reads the first parameter from the command line, and generates the corresponding ASCII code.

The command *Show Alias$* lists all aliases.

Example

*Set Sys$Year 1992

Related commands

*SetEval, *SetMacro, *Unset

Related SWIs

OS_SetVarVal, OS_GSTrans

Related vectors

None


*SetEval

Evaluates an expression and assigns its value to a system variable

Syntax

*SetEval varname expression

Parameters

varname a valid variable name
expression a valid Command Line expression

Use

*SetEval evaluates an expression and assigns its value to a system variable.

See the chapter entitled Evaluation operators for a description of the operators that you can use.

Example

*Set rate 12
*SetEval rate rate + 1
*Show rate

rate (Number) : 13

*SetEval fred "jim"+"sheila"
*Show Fred

fred : jimsheila

Related commands

*Set, *SetMacro, *Unset, *Eval

Related SWIs

OS_SetVarVal

Related vectors

None


*SetMacro

Assigns a string macro to a system variable

Syntax

*SetMacro varname macro

Parameters

varname a variable name, or a wildcard specification for a single variable name
macro string value to assign to the system variable varname, which is GSTrans'd each time it is read

Use

*SetMacro assigns a string value to a system variable, like function definition in a programming language. For example:

*Set varname text

assigns the string 'text' to the variable varname. The string is not OS_GSTrans'd before it is assigned; instead it is OS_GSTrans'd each time the variable is read.

Example

*SetMacro CLI$Prompt "<Sys$Time> "
13:43:17
system time replaces existing prompt
Return
Return key pressed two seconds later
13:43:19
new system time displayed as prompt

This resets the Command Line prompt, which appears as the first item on each line, to be the current time whenever the prompt is given. Compare this with using the *Set command:

*Set fred <Sys$Time>
*Show fred
FRED : 13:43:59

the *Show command issued five minutes later will still produce:

*Show fred
FRED : 13:43:59

Notice that the time is fixed at the time the *Set command was performed, in contrast to the *SetMacro command.

Related commands

*Set, *SetEval, *Unset

Related SWIs

OS_SetVarVal, OS_GSTrans

Related vectors

None


*Show

Displays the list of system variables

Syntax

*Show [variable_spec]

Parameters

variable_spec a variable name or a wildcard specification for a set of variable names

Use

*Show displays the name, type and current value of any system variables matching the name given as a parameter. These include the 'special' system variables, which may be altered, but which cannot be deleted.

If no name is given, all system variables are displayed.

Example

*Show
lists all system variables
*Show CLI$Prompt
*Show Alias$*
lists all aliases

Related commands

*Set, *SetEval, *SetMacro

Related SWIs

OS_ReadVarVal

Related vectors

None


*Unset

Deletes a system variable

Syntax

*Unset variable_spec

Parameters

variable_spec a variable name or a wildcard specification for a variable name

Use

*Unset deletes a system variable, which may be specified using wildcards.

Example

*Unset My_var

Related commands

*Set, *SetEval, *SetMacro

Related SWIs

OS_SetVarVal

Related vectors

None

Application Notes

Reading a variable

Here is a short example of reading a variable using OS_ReadVarVal:

;Print all sys$ variable names
        ADR     R1, valBuffer           ;Buffer to place value
        MOV     R3, #0                  ;Initial context
.loop
        ADR     R0, strName             ;Wildcarded name to find
        MOV     R2, #bufferLen          ;Length of value buffer
        SWI     "XOS_ReadVarVal"        ;Non-error reporting one
        MOVVSS  PC,R14                  ;Return and clear V
        MOV     R0, R3                  ;Get address of name
        SWI     "OS_Write0"             ;Print it
        SWI     "OS_NewLine"            ;and new line
        B       loop                    ;again
        ....
.strName                EQUS    "SYS$*" + CHR$0

Checking the value of a variable

The short code fragment below checks if a variable has a particular value, without giving an error if it does not exist or contains quotes.

*SetMacro App$Temp <Variable>
If App$Temp = "desired_value" Then commands...

Don't forget to *Unset the App$Temp macro when you have finished using it.

Code variable

Below is a complete example of a program to create a variable called Mode. The read action is to return the current display mode, and the write action to set the mode.

.start  ADR     R0, varName             ;Pointer to the name
        ADR     R1, code                ;Start of code body
        MOV     R2, #endCode-code       ;Length of code body
        MOV     R3, #0                  ;Context pointer
        MOV     R4, #&10                ;'special' type
        SWI     "OS_SetVarVal"          ;Create it
        MOV     PC, R14                 ;Return
.code   
        B       writeCode               ;Branch to write code
.readCode
        STMFD   R13!, {R14}             ;Save return address
        MOV     R0, #&87                ;OS_Byte read mode number
        SWI     "XOS_Byte"
        MOV     R0, R2                  ;Mode in R0 for conversion
        ADR     R1, buffer              ;Buffer for ASCII conversion
        MOV     R2, #4                  ;Max len of buffer
        SWI     "XOS_BinaryToDecimal"
        MOV     R0, R1                  ;Pointer in R0
                                        ;length already in R2
        LDMFD   R13!, {PC}              ;Return
.writeCode
        STMFD   R13!, {R0,R14}          ;Save registers
        SWI     "XOS_ReadUnsigned"       ;R1 set correctly already
        SWIVC   &20100+22               ;VDU mode change
        MOVVC   R0,R2                   ;Get integer read in R0
        SWIVC   "XOS_WriteC"            ;Do mode change
        LDMVCFD R13!, {R0,PC}           ;Return without error
        ADD     R13, R13, #4            ;Move stack pointer past R0, so we
        LDMFD   R13!, {R1,PC}           ;don't overwrite error pointer
.buffer
        EQUD    0                       ;Buffer for string conversion
.endCode
.varName
        EQUS    "Mode "                   ;Name of variable

The routine at 'start' creates the variable. Obviously as the code body is copied into the system heap, it must be position independent. The two routines readCode and writeCode are called whenever an access to the variable is made. For example, a *Set Mode command will call the write code entry, and *Show Sys$Mode or *Echo Mode will call the read entry.

Notice that in the body of the code variable, only XOS_ SWIs are used. This is because it is important that errors are not generated when the read or write code executes. A more rigorous version of the code above would check V after each SWI and return if it was set.

OS_AddCallBack

The next example shows the use of OS_AddCallBack; it prints 'Run away!' after 2 seconds:

DIM code 100
P%=code
[
.alarm STMFD R13!, {R14}
        SWI "XOS_WriteS"
        EQUS "Run away!"
        EQUB 10:EQUB 13:EQUB 0
        ALIGN
        LDMFD R13!, {PC}
.timer  STMFD R13!, {R0,R14}
        MOV R0, R12                 ; set up for us by BASIC bit
                                    ; R12 is not used in alarm,
                                    ; so R1 here is don't-care
        SWI "XOS_AddCallBack"
        LDMFD R13!, {R0, PC}
]
SYS "OS_CallAfter",200,timer,alarm

A CallBack handler

The final example shows a CallBack handler, with a semaphore to prevent recursive CallBack; it prints 'Run away!' when mouse buttons are pressed.

DIM code 200
P%=code
[
.sema   EQUB 1
        ALIGN
.saveblock :]:P%=P%+16*4:[
.callback                               ; entered here in a privileged mode,
                                        ; with interrupts disabled
                                        ; first thing to do is enable IRQs
        TEQP PC, #3                     ; force SVC mode, IRQs on.
        SWI "XOS_WriteS"
        EQUS   "Run away!"
        EQUB 10:EQUB 13:EQUB 0
        ALIGN
        ADR R14, saveblock
        LDMIA R14, {R0-R14}^            ; most registers reloaded
        MOV R0, R0
        TEQP PC, #3+(1<<27)             ; disable IRQs for sema update
        MOV R14, #1                     ; and return
        STRB R14, sema
        LDR  R14, saveblock+15*4        ; must not allow another CallBack 
                                        ; request until the stashed PC is safe
        MOVS PC, R14                    ; return, enableing IRQs etc
.events
        CMP R0, #10                     ; mouse button state change?
        MOVNES PC, R14                  ; no - run away
        STMFD R13!, {R14}
        LDRB R12, sema                  ; possibly request CallBack
        MOV R14, #0
        STRB R14, sema                  ; and disable any futher requests
        LDMFD R13!, {PC}                ; until that one serviced.
]
SYS "OS_ChangeEnvironment",7,callback,0,saveblock,0 TO ,ocall,,osave
REM Note that we aren't using R12 in the CallBack handler;
REM if this was in a module, for example, sema would be in the workspace,
REM and we would have to access it R12-relative; R12 would therefore be
REM set to be the workspace pointer on entry.
SYS "OS_ChangeEnvironment",10,events,0 TO ,oldev
*FX 14,10
REPEAT UNTILINKEY -1: REM loop until shift
*FX 13,10
SYS "OS_ChangeEnvironment",10,oldev,0
SYS"OS_ChangeEnvironment",7,ocall,,osave
REM Note that in both the above calls, the R12 values are explicitly left
REM alone, because we didn't use them earlier.

This edition Copyright © 3QD Developments Ltd 2015
Last Edit: Tue,03 Nov 2015