RISCOS.com

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

 

Software vectors


Introduction

We have already seen that one of the most important features of RISC OS is the ease with which it can be altered and extended. Most of RISC OS is written as modules; these can be replaced, and extra ones can be added.

The exception to this is the kernel, which provides the central core of functions necessary for RISC OS to work. You cannot replace the entire kernel. Instead, you can change or replace how certain fundamental routines of the RISC OS kernel work. You do this by using software vectors, or vectors for short. These are held in the computer's RAM; RISC OS uses them to record where it can find these routines.

Many of these routines perform all the functions of a given SWI. The corresponding SWI is then known as a vectored SWI.

Claiming vectors

When you call a SWI, RISC OS uses the SWI number to decide which routine in the RISC OS ROMs you want. For an ordinary SWI, RISC OS looks up the address of the SWI routine and then branches to it. However, if you call a vectored SWI, it instead gets the address from the corresponding vector that is held in RAM. Normally this would be the address of the standard routine held in ROM.

You can change this address by using the SWI OS_Claim, documented later in this chapter. RISC OS will then instead branch to your own routine, held at the address you pass to OS_Claim.

Your own routine can do one of the following:

  • replace the original routine, passing control directly back to the caller
  • do some processing before calling the standard routine, which then passes control back to the caller
  • call the standard routine, process some of the results it returns, and then pass control back to the caller.

If your routine completely replaces the standard one, it is said to intercept the call; otherwise it is said to pass on the call.

An example

As an example, let's look at the OS_WriteC routine. When RISC OS decodes a SWI with SWI number &00, it knows that you are requesting a write character operation. RISC OS gets an address from a vector - in this case called WrchV - and passes control to the routine.

Now by default, the WrchV contains the address of the standard write character routine in ROM. If you claim the vector using OS_Claim, whenever an OS_WriteC is executed, your own routine will be called first.

Vector chains

So far, we've deliberately been vague about how vectors store the addresses of the routine. In fact, the vector is the head of a chain of structures, which point to the next claimant on the vector, and to both the code and the workspace associated with this claimant. Consequently:

  • there may be more than one routine on a given vector
  • no claimant has to remember what the previous owner of the vector was
  • vectors can be claimed and released by many different pieces of software in any order, not just in a stack-like order.

The routines are called in the reverse order to the order in which they called OS_Claim. The last routine to OS_Claim the vector will be the first one called. If that routine passes the call on, the next most recent claimant will get the call, and so on. If any of the routines on the vector intercept the call, the earlier claimants will not be called.

When not to intercept a vector

There are some vectors which should not be intercepted; they must always be passed on to other claimants. This is because the default owner, ie the routine which is called if no one has claimed the vector, might perform some important action. The error vector, ErrorV, is a good example. The default owner of this vector is a routine which calls the error handler. If you intercept ErrorV, the error handler will never be called, and errors won't be dealt with properly.

Multiply installing the same routine

When OS_Claim adds a routine to a vector, it automatically removes any identical earlier instances of the routine from the chain (ie instances having the same pointer to code, and the same pointer to workspace). If you don't want this to happen, use the SWI OS_AddToVector instead.

Desktop applications

Under an environment such as the desktop, multiple applications are run concurrently. The currently running application is mapped into memory at &8000. Desktop applications periodically return control to the Window Manager (or Wimp) by calling the SWI Wimp_Poll; at this point the Wimp may decide to swap to another application. In doing so, it maps the current application out of the application space, and maps the new application into that space. Thus every application is given the illusion that it is the only one in the system.

If your application has claimed a vector using a routine in its own space, it must obviously release that vector each time it (and the claiming routine) may be swapped out of application space. Before each call your application makes to Wimp_Poll (which is when it may be swapped out), it must call OS_DelinkApplication to remove any claiming routines in application space. When its call to Wimp_Poll returns (and hence it is swapped back in), it must then call OS_RelinkApplication to reclaim those vectors.

SWI Calls


OS_Claim
(SWI &1F)

Adds a routine to the list of those that claim a vector

On entry

R0 = vector number (see List of software vectors)
R1 = address of claiming routine that is to be added to vector
R2 = value to be passed in R12 when the routine is called

On exit

R0 - R2 preserved

Interrupts

Interrupts are disabled
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

SWI cannot be re-entered as it disables IRQ

Use

This call adds the routine whose address is given in R1 to the list of routines claiming the vector. This becomes the first routine to be used when the vector is called.

Any identical earlier instances of the routine are removed. Routines are defined to be identical if the values passed in R0, R1 and R2 are identical.

The R2 value enables the routine to have a workspace pointer set up in R12 when it is called. If the routine using the vector is in a module (as will often be the case), this pointer will usually be the same as its module workspace pointer.

Example

MOV R0, #ByteV
ADR R1, MyByteHandler
MOV R2, #0
SWI "OS_Claim"

Related SWIs

OS_Release, OS_CallAVector, OS_AddToVector

Related vectors

All


OS_Release
(SWI &20)

Removes a routine from the list of those that claim a vector

On entry

R0 = vector number (see List of software vectors)
R1 = address of routine that is to be released from vector
R2 = value given in R2 when claimed

On exit

R0 - R2 preserved

Interrupts

Interrupts are disabled
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

SWI cannot be re-entered as it disables IRQ

Use

This call removes the routine, which is identified by both its address and workspace pointer, from the list for the specified vector. The routine will no longer be called. If more than one copy of the routine is claiming the vector, only the first one to be called is removed.

Example

MOV R0, #ByteV
ADR R1, MyByteHandler
MOV R2, #0
SWI "OS_Release"

Related SWIs

OS_Claim, OS_CallAVector, OS_AddToVector

Related vectors

All


OS_CallAVector
(SWI &34)

Calls a vector directly

On entry

R0 - R8 = vector routine parameters
R9 = vector number (see List of software vectors)
V and C flags in R15 = flags to pass to vector

On exit

Dependent on vector called

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

SWI is re-entrant - but not all vectors it calls are re-entrant

Use

OS_CallAVector calls the vector number given in R9. R0 - R8 are parameters to the vectored routine; see the descriptions below for details.

This is used for calling vectored routines which don't have any other entry point, such as some calls to RemV or CnpV. It is also used by system extensions such as the Draw, ColourTrans and Econet modules to call their corresponding vectors.

You must not use this SWI to call ByteV and other such vectors, as the vector handlers expect entry conditions you may not provide.

Related SWIs

OS_Claim, OS_Release, OS_AddToVector

Related vectors

All


OS_AddToVector
(SWI &47)

Adds a routine to the list of those that claim a vector

On entry

R0 = vector number (see List of software vectors)
R1 = address of claiming routine
R2 = value to be passed in R12 when the routine is called

On exit

R0 - R2 preserved

Interrupts

Interrupts are disabled
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

SWI cannot be re-entered as it disables IRQ

Use

This call adds the routine whose address is given in R1 to the list of routines claiming the vector. This becomes the first routine to be used when the vector is called.

Unlike OS_Claim, any earlier instances of the same routine remain on the vector chain.

The R2 value enables the routine to have a workspace pointer set up in R12 when it is called. If the routine using the vector is in a module (as will often be the case), this pointer will usually be the same as its module workspace pointer.

Related SWIs

OS_Claim, OS_Release, OS_CallAVector

Related vectors

All


OS_DelinkApplication
(SWI &4D)

Remove any vectors that an application is using

On entry

R0 = pointer to buffer
R1 = buffer size in bytes

On exit

R0 preserved
R1 = number of bytes left in buffer

Interrupts

Interrupts are disabled
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI cannot be re-entrant because interrupts are disabled

Use

When an application running at &8000 is going to be swapped out, it must remove all vectors that it uses. Otherwise, if they were activated, they would jump into whatever happened to be at that location in the new application running in that space.

R0 on entry points to a buffer. This is used to store details of the vectors used, so that they can be restored afterwards. Each vector requires 12 bytes of storage and the list is terminated by a single byte.

If the space left returned in R1 is zero, then you must allocate another buffer and repeat the call; the buffer you have contains valid information. When you relink you must pass all the buffers returned by this call.

Related SWIs

OS_RelinkApplication

Related vectors

None


OS_RelinkApplication
(SWI &4E)

Restore from a buffer any vectors that an application is using

On entry

R0 = pointer to buffer

On exit

R0 preserved

Interrupts

Interrupt status is not altered
Fast interrupts are enabled

Processor Mode

Processor is in SVC mode

Re-entrancy

SWI is re-entrant

Use

When an application is going to be swapped in, all vectors that it uses must be restored. R0 on entry points to a buffer, which has previously been created by OS_DelinkApplication.

Related SWIs

OS_DelinkApplication

Related vectors

None

Use of registers

If you write a routine that uses a vector, it must obey the same entry and exit conditions as the corresponding RISC OS routine. For example, a routine on WrchV must preserve all registers, just as the SWI OS_WriteC does.

If you pass the call on, you can deliberately alter some of the registers to change the effect of the call. However, if you do so, you must arrange for control to return again to your routine. You must then restore the register values that the old routine would normally have returned, before finally returning control to the calling program. This is because some applications might rely on the returned values being those documented in this manual.

Processor modes

The processor mode in which the routine is entered depends on the vector:

  • Routines vectored through IrqV (Vector &02) are always executed in IRQ mode.
  • Routines vectored through EventV, InsV, RemV, CnpV (Vectors &10 - &16) and TickerV (Vector &1C) are generally executed in IRQ mode, but may be executed in SVC mode if called using OS_CallAVector, and in certain other unspecified circumstances.
  • All other routines are executed in SVC mode - the mode entered when the SWI instruction is executed.
SVC mode

Note that if you call a SWI from a routine that is in SVC mode, you will corrupt the return address held in R14. Consequently, your routine should use the full, descending stack addressed by R13 to save R14 first. See the chapter entitled Important notes for a more complete explanation of this.

IRQ mode

If your routine will be entered in IRQ mode there are other restrictions. These are detailed in full in the Restrictions.

Returning errors

Routines using most of the vectors can return errors by setting the V flag, and storing an error pointer in R0. The routine must not pass on the call, as one of the parameters (R0) has been changed; this would cause problems for the next routine on the vector. The routine must instead intercept the call, returning control back to the calling program.

You can't do this with all the vectors; some of them (those involving IRQ calls in particular) have nowhere to send the error to.

Returning from a vectored routine

You should use one of two methods to return from a vectored routine. These are described immediately below; for an example, see the An example program.

Passing on the call

If you wish to pass on the call (to the previous owner), you should return by copying R14 into the PC. Use the instruction:

MOVS PC,R14

Intercepting the call

If you wish to intercept the call, you should pull an exit address (which has been set up by RISC OS) from the stack and jump to it. Use the instruction:

LDMFD R13!,{PC}

Control will return to the caller of the vector.

List of software vectors

The software vectors are listed below. The following Summary of vectors gives a summary of each vector, and tells you where to find out more about it. A few vectors also merit a more detailed description in the Vector descriptions. Such vectors are indicated in the list below by a dagger '†'. Also, the names of the routines which can cause each vector to be called are in brackets:

Vector No Description
UserV (&00) User vector (reserved)
ErrorV (&01) Error vector (OS_GenerateError)
IrqV † (&02) Interrupt vector
WrchV (&03) Write character vector (OS_WriteC)
RdchV (&04) Read character vector (OS_ReadC)
CLIV (&05) Command line interpreter vector (OS_CLI)
ByteV (&06) OS_Byte indirection vector (OS_Byte)
WordV (&07) OS_Word indirection vector (OS_Word)
FileV (&08) File read/write vector (OS_File)
ArgsV (&09) File arguments read/write vector (OS_Args)
BGetV (&0A) File byte read vector (OS_BGet)
BPutV (&0B) File byte put vector (OS_BPut)
GBPBV (&0C) File byte block get/put vector (OS_GBPB)
FindV (&0D) File open vector (OS_Find)
ReadLineV (&0E) Read a line of text vector (OS_ReadLine)
FSCV (&0F) Filing system control vector (OS_FSControl)
EventV (&10) Event vector (OS_GenerateEvent)
InsV † (&14) Buffer insert vector (OS_Byte)
RemV † (&15) Buffer remove vector (OS_Byte)
CnpV † (&16) Count/Flush Buffer vector (OS_Byte)
UKVDU23V † (&17) Unknown VDU23 vector (OS_WriteC)
UKSWIV † (&18) Unknown SWI vector (SWI)
UKPLOTV † (&19) Unknown VDU25 vector (OS_WriteC)
MouseV (&1A) Mouse vector (OS_Mouse)
VDUXV † (&1B) VDU vector (OS_WriteC)
TickerV † (&1C) 100Hz vector
UpcallV (&1D) Warning vector (OS_UpCall)
ChangeEnvironmentV (&1E) Environment change vector (OS_ChangeEnvironment)
SpriteV (&1F) OS_SpriteOp indirection vector (OS_SpriteOp)
DrawV † (&20) Draw SWI vector (Draw_...)
EconetV † (&21) Econet activity vector (Econet_...)
ColourV † (&22) ColourTrans SWI vector (ColourTrans_...)
PaletteV † (&23) Read/write palette vector
SerialV (&24) OS_SerialOp indirection vector

All other vectors are reserved by Acorn.

Summary of vectors

Brief details of these vectors are given below.

Many of them are by default used to indirect calls of SWIs, and so the routine they call is the same as that the SWI calls. In these cases, you should see the description of the SWI for details of entry and exit conditions. Vectors which do not have corresponding SWIs are instead documented in more detail later in this chapter.

As an example, the default routine called by WrchV is the same as that used by OS_WriteC, and so you should see the description of OS_WriteC for details of it.

About the filing system vectors

Note that the filing system vectors FileV (Vector &08) to FindV (Vector &0D) have 'no default action', ie they return immediately. However, the FileSwitch module (described in the chapter of the same name) OS_Claims the vectors whenever the machine is reset, so effectively the default action is to perform the appropriate filing system routine.

Other vectors and resets

Vectors are freed on any kind of reset, and system extension modules must claim them again if they need to - just as FileSwitch does.

UserV

UserV is a reserved vector, and you must not use it. Its default action is to do nothing.

ErrorV

ErrorV is used to indirect all errors from error-generating SWIs and from OS_GenerateError - see OS_GenerateError for full details. The default action is to call the error handler.

See also the rest of the chapter entitled Generating and handling errors; and the chapter entitled Program Environment for more about handlers.

IrqV

IrqV is called when an unknown IRQ is detected. It was provided in earlier versions of RISC OS to enable you to add interrupt generating devices of your own to the computer, but is now considered obsolete. The default action is to disable the interrupting device. See IrqV (Vector &02) later in this chapter for full details.

See also the chapter entitled Interrupts and handling them, and the chapter entitled Program Environment for more about handlers.

WrchV

WrchV is used to indirect all calls to OS_WriteC - see OS_WriteC for full details. The default action is to call the ROM write character routine.

RdchV

RdchV is used to indirect all calls to OS_ReadC - see OS_ReadC for full details. The default action is to call the ROM read character routine.

CLIV

CLIV is used to indirect all calls to OS_CLI - see OS_CLI for full details. The default action is to call the ROM command line interpreter.

ByteV

ByteV is used to indirect all calls to OS_Byte - see OS_Byte for full details. The default action is to call the ROM OS_Byte routine.

Note that interrupts are disabled when an OS_Byte is called. If you claim this vector, your routine must enable interrupts if its processing takes a long time (over 100[MU]s), and be prepared to be re-entered.

WordV

WordV is used to indirect all calls to OS_Word - see OS_Word for full details. The default action is to call the ROM OS_Word routine.

Note that interrupts are disabled when an OS_Word is called. If you claim this vector, your routine must enable interrupts if its processing takes a long time (over 100[MU]s), and be prepared to be re-entered.

FileV

FileV is used to indirect all calls to OS_File - see OS_File for full details. The default action is to call the ROM OS_File routine (see the note above).

ArgsV

ArgsV is used to indirect all calls to OS_Args - see OS_Args for full details. The default action is to call the ROM OS_Args routine (see the note above).

BGetV

BGetV is used to indirect all calls to OS_BGet - see OS_BGet for full details. The default action is to call the ROM OS_BGet routine (see the note above).

BPutV

BPutV is used to indirect all calls to OS_BPut - see OS_BPut for full details. The default action is to call the ROM OS_BPut routine (see the note above).

GBPBV

GBPBV is used to indirect all calls to OS_GBPB - see OS_GBPB for full details. The default action is to call the ROM OS_GBPB routine (see the note above).

FindV

FindV is used to indirect all calls to OS_Find - see OS_Find for full details. The default action is to call the ROM OS_Find routine (see the note above).

ReadLineV

ReadLineV is used to indirect all calls to OS_ReadLine - see OS_ReadLine for full details. The default action is to call the ROM OS_ReadLine routine.

FSCV

FSCV is used to indirect calls to OS_FSControl - see OS_FSControl for full details. The default action is to call the ROM OS_FSControl routine.

EventV

EventV is used to indirect all calls to OS_GenerateEvent - see OS_GenerateEvent for full details. The default action is to call the event handler.

See also the rest of the chapter entitled Events; and the chapter entitled Program Environment for more about handlers.

InsV

InsV is called to place one or more bytes in a buffer. See InsV (Vector &14) later in this chapter for full details.

See also the chapter entitled Buffers.

RemV

RemV is called to remove one or more bytes from a buffer. See RemV (Vector &15) later in this chapter for full details.

See also the chapter entitled Buffers.

CnpV

CnpV is called to count the number of entries or spaces in a buffer, or to flush the contents of a buffer. See CnpV (Vector &16) later in this chapter for full details.

See also the chapter entitled Buffers.

UKVDU23V

UKVDU23V is called when a VDU 23,n command is issued with an unknown value of n. The default action is to do nothing - unknown VDU 23s are usually ignored. See UKVDU23V (Vector &17) later in this chapter for full details.

UKSWIV

UKSWIV is called when a SWI is issued with an unknown SWI number. The default action is to call the unknown SWI handler, which by default generates a 'No such SWI' error. See UKSWIV (Vector &18) later in this chapter for full details.

See also the chapter entitled An introduction to SWIs; and the chapter entitled Program Environment for more about handlers.

UKPLOTV

UKPLOTV is called when a VDU 25,n (Plot) or a SWI OS_Plot n command is issued with an unknown value of n. The default action is to do nothing - unknown VDU 25s (Plots) are usually ignored. See UKPLOTV (Vector &19) later in this chapter for full details.

MouseV

MouseV is used to indirect all calls to OS_Mouse - see OS_Mouse for full details. The default action is to call the ROM OS_Mouse routine.

VDUXV

VDUXV is called when VDU output has been redirected by setting bit 5 of the OS_WriteC destination flag. This vector is normally claimed by the Font manager, to implement the Font system (see the chapter entitled The Font Manager). If the Font module is disabled, the default action is to do nothing - no output is sent to the VDU. See VDUXV (Vector &1B) later in this chapter for full details.

See also the chapter entitled Character Output, and the chapter entitled VDU Drivers.

TickerV

TickerV is called every centisecond. It must never be intercepted. See TickerV (Vector &1C) later in this chapter for full details.

UpCallV

UpCallV is used to indirect all calls to OS_UpCall - see the chapter entitled Communications within RISC OS for full details. The default action is to call the UpCall handler.

ChangeEnvironmentV

ChangeEnvironmentV is used to indirect all calls to OS_ChangeEnvironment - see OS_ChangeEnvironment for full details. The default action is to call the ROM OS_ChangeEnvironment routine.

SpriteV

SpriteV is used to indirect all calls to OS_SpriteOp - see OS_SpriteOp for full details. The default action is to call the relevant ROM OS_SpriteOp routine. (In fact there are two claimants for this vector: one intercepts those calls handled by the kernel's sprite routines, the another intercepts those handled by the SpriteExtend module.)

DrawV

DrawV is used to indirect all SWI calls made to the Draw module. The default action is to call the ROM routine in the Draw module that decodes and executes SWIs. See DrawV (Vector &20) later in this chapter for full details.

See also the Draw module.

EconetV

EconetV is called whenever there is activity on the Econet. The default action is to display the Hourglass on the screen. See EconetV (Vector &21) later in this chapter for full details.

See also chapters on Econet, the Hourglass, and the NetStatus.

ColourV

ColourV is used to indirect all SWI calls made to the ColourTrans module. The default action is to call the routine in the ColourTrans module that decodes and executes SWIs. See ColourV (Vector &22) later in this chapter for full details.

See also the chapter entitled ColourTrans.

PaletteV

PaletteV is called whenever a call is made to read or write the palette. The default action is to call the ROM routine to read or write the palette. See PaletteV (Vector &23) later in this chapter for full details.

This vector has no default owner under RISC OS 2.

SerialV

SerialV is used to indirect all calls to OS_SerialOp - see OS_SerialOp for full details. The default action is to call the ROM OS_SerialOp routine.

This vector has no default owner under RISC OS 2.

Vector descriptions

The next section describes in detail those vectors which do more than indirecting a single RISC OS SWI.

In most cases, the interrupt status is given as undefined. This is because the vectors may be called either by the SWI(s) which normally use them, many of which ensure a given interrupt status, or by OS_CallAVector, which does not alter the interrupt status.


IrqV
(Vector &02)

Called when an unknown IRQ is detected

On entry

No parameters passed in registers

On exit

--

Interrupts

Interrupts are disabled
Fast interrupts are enabled

Processor mode

Processor is in IRQ mode

Use

This vector is called when an unknown IRQ is detected.

It was provided in the Arthur operating system so you could add interrupt generating devices of your own to the computer. RISC OS provides a new method of doing so that is more efficient, which you should use in preference. This vector has been kept for compatibility.

The default action is to disable the interrupt generating device by masking it out in the IOC chip.

Routines that claim this vector must not corrupt any registers. You must not call this vector using OS_CallAVector.

You must intercept calls to this vector and service the interrupt if the device is yours. You must pass them on to earlier claimants if the device is not yours, so that interrupt handlers written to run under Arthur can still trap interrupts they recognise.

Old software that handled Sound interrupts using this vector will no longer work, as the new Sound module exclusively uses the RISC OS SoundIRQ device handler.

See the chapter entitled Interrupts and handling them for details of how to add interrupt generating devices to your computer, and the chapter entitled Program Environment for more about handlers.

Related SWIs

None


InsV
(Vector &14)

Called to place a byte or block in a buffer

On entry
Byte insertion

R0 = byte to be inserted
R1 = buffer number (bits 0 - 30), with bit 31 clear (=> byte operation)

Block insertion

R1 = buffer number (bits 0 - 30), with bit 31 set (=> block operation)
R2 = pointer to first byte of data to be inserted
R3 = number of bytes to insert

On exit
Byte insertion

R0, R1 preserved
R2 corrupted
C flag = 1 implies insertion failed

Block insertion

R0, R1 preserved
R2 = pointer to remaining data to be inserted
R3 = number of bytes still to be inserted
C flag = 1 implies insertion failed

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in IRQ or SVC mode

Use

This vector is called by OS_Byte 138 and OS_Byte 153. The default action is to call the ROM routine to insert byte(s) into a buffer from the system buffers.

It may also be called using OS_CallAVector. It must be called with interrupts disabled (the OS_Bytes do this automatically), therefore code on the vector can only be entered with interrupts disabled and is not re-entrant.

From RISC OS 3 onwards, the default owner of the vector is the buffer manager, which disables interrupts itself. Calling code need no longer disable interrupts, and code claiming the vector should no longer assume that interrupts are disabled on entry.

The C flag is used to indicate if the insertion failed; if C=1 then it was not possible to insert all the specified data, or the specified byte.

Block operations are not available in RISC OS 2, nor are they available for buffers that are not handled by the buffer manager.

To use different sized system buffers under RISC OS 2, you must provide handlers for all of InsV, RemV and CnpV. Under later versions of RISC OS you must instead use the buffer manager SWIs Buffer_Create or Buffer_Register.

See also the chapter entitled Buffers, and the chapter entitled The Buffer Manager.

Related SWIs

OS_Byte 138, OS_Byte 153


RemV
(Vector &15)

Called to remove a byte or block from a buffer

On entry
Byte removal

R1 = buffer number (bits 0 - 30), with bit 31 clear (=> byte operation)
V flag = 1 if buffer to be examined only, or 0 if data should actually be removed

Block removal

R1 = buffer number (bits 0 - 30), with bit 31 set (=> block operation)
R2 = pointer to block to be filled
R3 = number of bytes to place into block
V flag = 1 if buffer to be examined only, or 0 if data should actually be removed

On exit
Byte removal

R0 = next byte to be removed (examine option), or corrupted (remove option)
R1 preserved
R2 = byte removed (remove option), or corrupted (examine option)
C flag = 1 if buffer was empty on entry

Block removal

R0, R1 preserved
R2 = pointer to updated buffer position
R3 = number of bytes still to be removed
C flag = 1 if buffer was empty on entry

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in IRQ or SVC mode

Use

This vector is called by OS_Byte 145 and OS_Byte 152. The default action is to call the ROM routine to examine or remove byte(s) from the system buffers.

It may also be called using OS_CallAVector. It must be called with interrupts disabled (the OS_Bytes do this automatically), therefore code on the vector can only be entered with interrupts disabled and is not re-entrant.

From RISC OS 3 onwards, the default owner of the vector is the buffer manager, which disables interrupts itself. Calling code need no longer disable interrupts, and code claiming the vector should no longer assume that interrupts are disabled on entry.

The C flag is used to indicate if the operation failed; if C=1 then it was not possible to remove/examine all the specified data, or the specified byte.

Block operations are not available in RISC OS 2, nor are they available for buffers that are not handled by the buffer manager.

To use different sized system buffers under RISC OS 2, you must provide handlers for all of InsV, RemV and CnpV. Under later versions of RISC OS you must instead use the buffer manager SWIs Buffer_Create or Buffer_Register.

See also the chapter entitled Buffers and the chapter entitled The Buffer Manager.

Related SWIs

OS_Byte 145, OS_Byte 152


CnpV
(Vector &16)

Called to count the number of entries/amount of space left in a buffer, or to flush the contents of a buffer

On entry

R1 = buffer number
V flag and C flag encode the action:

    V flag = 0, C flag = 0 => return number of entries
    V flag = 0, C flag = 1 => return amount of free space
    V flag = 1 => flush buffer

On exit

R0 corrupted
R1, bits 0 - 7 = least significant 8 bits of count, if V flag = 0 on entry; else preserved
R2, bits 0 - 23 = most significant 24 bits of count, if V flag = 0 on entry; else preserved

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in IRQ or SVC mode

Use

This vector is called by OS_Byte 15, OS_Byte 21 and OS_Byte 128. The default action is to call the ROM routine to count the number of entries in a buffer, or to flush the contents of a buffer.

It may also be called using OS_CallAVector. It must be called with interrupts disabled (the OS_Bytes do this automatically), therefore code on the vector can only be entered with interrupts disabled and is not re-entrant.

From RISC OS 3 onwards, the default owner of the vector is the buffer manager, which disables interrupts itself. Calling code need no longer disable interrupts, and code claiming the vector should no longer assume that interrupts are disabled on entry.

The V flag gives a reason code that determines the operation:

V flag = 0 count the entries in a buffer
V flag = 1 flush the buffer

If the entries are to be counted then the result returned depends on the C flag on entry as follows:

C flag = 0 return the number of entries in the buffer
C flag = 1 return the amount of space left in the buffer

This call also copes with buffer manager buffers.

To use different sized system buffers under RISC OS 2, you must provide handlers for all of InsV, RemV and CnpV. Under later versions of RISC OS you must instead use the buffer manager SWIs Buffer_Create or Buffer_Register.

See also the chapter entitled Buffers and the chapter entitled The Buffer Manager.

Related SWIs

OS_Byte 15, OS_Byte 21, OS_Byte 128


UKVDU23V
(Vector &17)

Called when an unrecognised VDU 23 command is issued

On entry

R0 = VDU 23 option requested
R1 = pointer to VDU queue

On exit

R0, R1 preserved

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Use

This vector is called when a VDU 23,n command is issued with an unknown value of n, ie it is in the range 18 - 25 or 28 - 31.

The nine parameters sent after the VDU 23 command are stored in the VDU queue. R1 points to the byte holding n, and R0 also contains n.

The default action is to do nothing - unknown VDU 23s are ignored.

Related SWIs

OS_WriteC


UKSWIV
(Vector &18)

Called when an unknown SWI instruction is issued

On entry

R0 - R8 as set up by the caller
R11 = SWI number

On exit

Generates an error by default

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Use

This vector is called when a SWI is issued with an unknown SWI number. Before this vector is called, the OS tries to pass the call to any modules which have SWI table entries in their header.

The default action is to call the Unused SWI handler, which by default returns a 'No such SWI' error. See the chapter entitled Unused SWI for full details.

This vector can be used to add large numbers of SWIs to the system from a single module. Normally only 64 SWIs can be added by a module; if you claim this vector, you can then trap any additional SWIs you wish to add. (You should always use the module mechanism to add the first 64 SWIs that a module adds, as it is more efficient than using this vector.) Note that you must get an allocation of SWI numbers from Acorn before adding any to commercially available software. This will avoid clashes between your own software and other software.

See also the chapter entitled An introduction to SWIs; and the chapter entitled Program Environment for more about handlers.

Related SWIs

OS_UnusedSWI


UKPLOTV
(Vector &19)

Called when an unknown PLOT command is issued

On entry

R0 = PLOT number

On exit

R0 preserved

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Use

This vector is called by the VDU drivers when a VDU 25,n (PLOT) or SWI OS_Plot command is issued with an unknown value of n.

By using OS_ReadVduVariables you can read the co-ordinates of the last three points that have been visited, and the one specified in the unknown PLOT command. These are held in the VDU variables 140 - 147. See the entry for OS_ReadVduVariables for full details.

When the call returns to the VDU drivers they update the variables, so that the point given in the unknown plot becomes the graphics cursor position. The previous graphics cursor becomes the last point but one, the previous last point but one becomes the last point but two, and the previous last point but two is lost.

The default action is to do nothing - unknown VDU 25s (Plots) are ignored.

Related SWIs

OS_WriteC, OS_ReadVduVariables, OS_Plot


VDUXV
(Vector &1B)

Called when VDU output has been redirected

On entry

R0 = byte sent to the VDU

On exit

R0 preserved

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Use

This vector is called when VDU output has been redirected by setting bit 5 of the OS_WriteC destination flag. When this bit is set, all characters sent to the VDU driver are routed through this vector instead. Note that this only affects the display driver: other output streams such as the printer and *Spool file are called as usual, even when VDUXV is used for screen updating.

It is up to the owner of the vector to perform the usual queuing of parameter bytes etc. The default owner of this vector does nothing, so issuing a *FX3,32 call is much the same as disabling the VDU using ASCII 21.

This vector is normally claimed by the Font Manager, to implement the Font system (see the chapter entitled The Font Manager). If the Font module is disabled, the default action is to do nothing - no output is sent to the VDU.

See also the chapter entitled Character Output, and the chapter entitled VDU Drivers.

Related SWIs

OS_WriteC


TickerV
(Vector &1C)

Called every centisecond

On entry

No parameters passed in registers

On exit

--

Interrupts

Interrupts are disabled
Fast interrupts are enabled

Processor mode

Processor is in IRQ or SVC mode

Use

This vector is called every centisecond. It must never be intercepted, as this would prevent other clients from being called.

Routines that take a long time (say > 100[MU]s) may re-enable IRQ so long as they disable it again before passing the call on. If you do so, other calls may be made to TickerV in the meantime. Your routine needs to prevent or cope with re-entrancy. One way of ensuring that the code is single threaded is:

  • to use a flag in its workspace to note that it is currently threaded, and:
  • to keep a count of how many calls to TickerV have been missed while it was threaded, so the count can be examined on exit and corrected for.
Related SWIs

None


DrawV
(Vector &20)

Used to indirect all SWI calls made to the Draw module

On entry

R0 - R7 dependent on SWI issued
R8 = index of SWI within the Draw module SWI chunk

On exit

Dependent on SWI issued

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Use

This vector is used to indirect all SWI calls made to the Draw module. The default action is to call the ROM routine in the Draw module that decodes and executes SWIs.

The index held in R8 is decoded as follows:

    0 Draw_ProcessPath
    2 Draw_Fill
    4 Draw_Stroke
    6 Draw_StrokePath
    8 Draw_FlattenPath
    10 Draw_TransformPath

See also the chapter entitled Draw module.

Related SWIs

Draw_... Draw_ProcessPath onwards)


EconetV
(Vector &21)

Called whenever there is activity on the Econet

On entry

R0 = reason code
R1 = total size of data, or amount of data transferred, or no parameter passed

On exit

R0, R1 preserved

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Use

EconetV is called whenever there is activity on the Econet. The reason code tells you what the activity is.

The bottom nibble of the reason code indicates whether the activity has started (0), is part way through (1) or finished (2). The next nibble gives the type of operation.

The table below shows the reason codes that are passed. The right hand column shows what is passed in R1, or (for the less obvious cases) when the reason code is passed:

&10 NetFS_StartLoad R1 = total size of data
&11 NetFS_PartLoad R1 = amount of data transferred
&12 NetFS_FinishLoad
&20 NetFS_StartSave R1 = total size of data
&21 NetFS_PartSave R1 = amount of data transferred
&22 NetFS_FinishSave
&30 NetFS_StartCreate R1 = total size of data
&31 NetFS_PartCreate R1 = amount of data transferred
&32 NetFS_FinishCreate
&40 NetFS_StartGetBytes R1 = total size of data
&41 NetFS_PartGetBytes R1 = amount of data transferred
&42 NetFS_FinishGetBytes
&50 NetFS_StartPutBytes R1 = total size of data
&51 NetFS_PartPutBytes R1 = amount of data transferred
&52 NetFS_FinishPutBytes
&60 NetFS_StartWait start of a Broadcast_Wait
&62 NetFS_FinishWait end of a Broadcast_Wait
&70 NetFS_StartBroadcastLoad R1 = total size of data
&71 NetFS_PartBroadcastLoad R1 = amount of data transferred
&72 NetFS_FinishBroadcastLoad
&80 NetFS_StartBroadcastSave R1 = total size of data
&81 NetFS_PartBroadcastSave R1 = amount of data transferred
&82 NetFS_FinishBroadcastSave
&C0 Econet_StartTransmission start to wait for a transmission to end
&C2 Econet_FinishTransmission DoTransmit returns
&D0 Econet_StartReception start to wait for a reception to end
&D2 Econet_FinishReception WaitForReception returns

This vector is normally claimed by the NetStatus module, which uses the Hourglass module to display an hourglass while the Econet is busy. It passes on the call. If the Hourglass module is disabled, the default action is to do nothing. See the chapter entitled Hourglass, and the NetStatus.

See also the chapter entitled NetFS, the chapter entitled NetPrint, and the chapter entitled Econet.

Related SWIs

Econet_... Econet_CreateReceive onwards), NetFS_... NetFS_ReadFSNumber onwards), NetPrint_... NetPrint_ReadPSNumber onwards) and Hourglass_... Hourglass_On onwards)


ColourV
(Vector &22)

Used to indirect all SWI calls made to the ColourTrans module

On entry

R0 - R7 dependent on SWI issued
R8 = index of SWI within the ColourTrans module SWI chunk

On exit

Dependent on SWI issued

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Use

This vector is used to indirect all SWI calls made to the ColourTrans module. The default action is to call the routine in the ColourTrans module that decodes and executes SWIs.

The index held in R8 is decoded as follows:

    0 ColourTrans_SelectTable
    1 ColourTrans_SelectGCOLTable
    2 ColourTrans_ReturnGCOL
    3 ColourTrans_SetGCOL
    4 ColourTrans_ReturnColourNumber
    5 ColourTrans_ReturnGCOLForMode
    6 ColourTrans_ReturnColourNumberForMode
    7 ColourTrans_ReturnOppGCOL
    8 ColourTrans_SetOppGCOL
    9 ColourTrans_ReturnOppColourNumber
    10 ColourTrans_ReturnOppGCOLForMode
    11 ColourTrans_ReturnOppColourNumberForMode
    12 ColourTrans_GCOLToColourNumber
    13 ColourTrans_ColourNumberToGCOL
    14 ColourTrans_ReturnFontColours
    15 ColourTrans_SetFontColours
    16 ColourTrans_InvalidateCache
    17 ColourTrans_SetCalibration
    18 ColourTrans_ReadCalibration
    19 ColourTrans_ConvertDeviceColour
    20 ColourTrans_ConvertDevicePalette
    21 ColourTrans_ConvertRGBToCIE
    22 ColourTrans_ConvertCIEToRGB
    23 ColourTrans_WriteCalibrationToFile
    24 ColourTrans_ConvertRGBToHSV
    25 ColourTrans_ConvertHSVToRGB
    26 ColourTrans_ConvertRGBToCMYK
    27 ColourTrans_ConvertCMYKToRGB
    28 ColourTrans_ReadPalette
    29 ColourTrans_WritePalette
    30 ColourTrans_SetColour
    31 ColourTrans_MiscOp
    32 ColourTrans_WriteLoadingsToFile
    32 ColourTrans_SetTextColour
    32 ColourTrans_SetOppTextColour
    32 ColourTrans_GenerateTable

See also the chapter entitled ColourTrans.

Related SWIs

ColourTrans_... ColourTrans_SelectTable onwards)


PaletteV
(Vector &23)

Called whenever the palette is to be read or written

On entry

Register usage is dependent on a reason code held in R4:

Read palette

R0 = logical colour
R1 = type of colour (16,17,18,24,25)
R4 = 1 (reason code)

Set palette

R0 = logical colour
R1 = type of colour (16,17,18,24,25)
R2 = 1st flash colour (&BBGGRRxx) - device colour
R3 = 2nd flash colour (&BBGGRRxx) - device colour
R4 = 2 (reason code)

Set first flash state

R4 = 3 (reason code)

Set second flash state

R4 = 4 (reason code)

Set default palette

R4 = 5 (reason code)

Reserved

R4 = 6 (reason code)

On exit
Read palette

R2 = 1st flash colour (&BBGGRRxx) - device colour
R3 = 2nd flash colour (&BBGGRRxx) - device colour
R4 = 0 => operation complete

Other reason codes

R4 = 0 => operation complete

Use

This vector is called whenever the palette is to be read or written. Calls this applies to include:

By claiming this vector, you can get replacement graphics hardware to intercept such calls, and perform the operation using their own palette. On completion, you should set R4 to zero on exit; RISC OS then knows not to perform the operation itself.

By default, this vector calls the ROM routines to read/write the computer's own palette; they likewise set R4 to zero on exit to notify the caller that the operation was completed.

This vector has no default owner under RISC OS 2 or RISC OS 3 (version 3.00). However, you can write software that calls this vector - and that works correctly under all versions of RISC OS - by checking the value of R4 on exit to see if the operation is complete. If it is not complete, you then need to use your own code to read or write the palette. For more information and example code fragments, see the chapter entitled Application notes.

More complex uses of vectors

Sometimes, you may want to do more complex things with a vector, such as:

  • preprocessing registers to alter the effect of a standard routine
  • postprocessing to change the effect of future calls
  • repeatedly calling a routine or group of routines.

There are a number of important things to remember if you are doing so. You must make sure that:

  • the vector still looks exactly the same to a program that is calling it, even if it now does different things
  • your routine will cope with being called in all the processor modes that its vector uses (for example, SVC or IRQ mode for a routine on InsV)
  • the values of R10 and R11 are preserved when earlier claimants of the vector are repeatedly called.

An example program

The example program below illustrates all these important points. You can adapt it to write your own routines.

The program claims WrchV, adding a routine that:

  • changes the case of the character depending on the state of a flag (preprocessing)
  • calls the remaining routines on the vector to write the altered character
  • toggles the flag (postprocessing)
  • ensures that all registers are set to the values that would be returned by the default write character routine
  • returns control to the calling program.

Note that the program releases the vector before ending, even if an error occurs.

DIM code% 100
FOR pass%=0 TO 3 STEP 3
P%=code%
[ OPT pass%
.vectorcode%
; save the entry value, the necessary state for the repeated call,
; and our workspace pointer
    STMFD   r13!, {r0, r10-r12, r14}
; do our preprocessing; as a trivial example, convert to the current case
    LDRB    r14, [r12]          ; pick up upper/lowercase flag
    CMP     r14, #0             ; decide which territory manager table to use
    LDREQ   r1, lowercase_table%
    LDRNE   r1, uppercase_table%
    LDRB    r0, [r1, r0]        ; look up character and put back in r0
; now do the call to the rest of the vector. Since this is WrchV, we know that
; we are in SVC mode; however, the code below will correctly call the rest of
; the vector whatever the mode.
    STMFD   r13!, {r15}         ; pushes PC+12, complete with flags and mode
    ADD     r12, r13, #8        ; stack contains pc,r0,r10,r11,r12,r14
                                ; so point at the stacked r10
    LDMIA   r12, {r10-r12, r15} ; and restore the state needed to call the
                                ; rest of the chain (r10 and r11), and
                                ; "return" to the non-vector claiming address.
                                ; The load of r12 wastes one cycle.
; we are now at the pc+12 that we stacked; this is therefore where the
; rest of the vector returns to when it has finished.
    LDR     r12, [r13, #12]     ; reload our workspace pointer
                                ; Note that the offset of #12 - and the earlier
                                ; #8 when we pushed onto the stack - refer to
                                ; this example only and are not general
                                ; Note also that the pc we pushed was
                                ; pulled by the vector claimer.
; we could now do some more processing, set r0 up to another character,
; and loop round to done_preprocess% again; instead, we'll just do some
; example postprocessing; we'll toggle our upper/lowercase flag.
    LDRB    r14, [r12]
    EOR     r14, r14, #1
    STRB    r14, [r12]
; now return; if there was no error then intercept the call to the
; vector, returning the original character.
    LDMVCFD r13!, {r0, r10-r12, r14, r15}
; could pass the call on instead by omitting r14 from the addresses
; to pull - ie use LDMVCFD r13!, {r0, r10-r12, r15}
; there was an error; set up the correct error pointer, flags, and
; claim the vector.
    STR     r0, [r13]           ; save the error pointer
    LDMFD   r13!, {r0, r10-r12, r14, r15}
                                ; return with V still set, and claim the vector
; reserve space to store the addresses of the territory manager case tables
.lowercase_table%
    EQUD    0
.uppercase_table%
    EQUD    0
]
NEXT
REM Get addresses of the territory manager case tables
SYS "Territory_LowerCaseTable",-1 TO !lowercase_table%
SYS "Territory_UpperCaseTable",-1 TO !uppercase_table%
DIM flag% 1
?flag%=0
WrchV%=3
ON ERROR SYS "XOS_Release", WrchV%, vectorcode%, flag%: PRINTREPORT$: END
SYS "OS_Claim", WrchV%, vectorcode%, flag%
REPEAT
  INPUT command$
  OSCLI command$
UNTIL command$=""
SYS "XOS_Release", WrchV%, vectorcode%, flag%
END

Application notes

The PaletteV vector has no default owner under RISC OS 2 or RISC OS 3 (version 3.00), but you may still wish to write software that calls this vector, and can hence interact with (say) a replacement graphics card.

The two pieces of code below work correctly under all current versions of RISC OS. They do so by checking the value of R4 on exit from PaletteV to see if the read/write palette operation is complete. If it is not complete, the code is being run on a RISC OS 2 machine, and there was no PaletteV claimant (such as code downloaded from a graphics card) that was able to complete the operation. In such cases, the code then reads/writes the palette itself.

Reading a palette entry

The following piece of code reads a palette entry:

; In    R0 = logical colour
;       R1 = type of colour (16,17,18,24,25)
; Out   R2 = 1st flash colour (&BBGGRRxx) - device colour
;       R3 = 2nd flash colour (&BBGGRRxx) - device colour
;       VC => flags preserved, VS => R0->error, flags corrupt
;       (mustn't be called with V set)
readpalette Entry "R4,R9"
        MOV R4,#1                ; read palette
        MOV R9,#PaletteV
        SWI XOS_CallAVector      ; returns &BBGGRRxx
        EXIT VS
        TEQ R4,#0
        EXIT EQ
        SWI XOS_ReadPalette      ; returns &B0G0R0xx
        LDRVC R4,=&F0F0F000      ; clears low nibbles and bottom byte
                                 ; (we want to preserve bits 0..7)
        ANDVC R14,R2,R4
        ORRVC R2,R2,R14,LSR #4   ; force to &BBGGRRxx
        ANDVC R14,R3,R4
        ORRVC R3,R3,R14,LSR #4   ; force to &BBGGRRxx
        EXITS VC
        EXIT
        LTORG

Note that if the vector is claimed, the resulting colours must be 24-bit, rather than the restricted versions returned by OS_ReadPalette.

Writing a palette entry

The following piece of code writes a palette entry:

; In    R0 = logical colour
;       R1 = type of colour (16,17,18,24,25)
;       R2 = 1st flash colour (&BBGGRRxx) - device colour
;       R3 = 2nd flash colour (&BBGGRRxx) - device colour
; Out   VC => flags preserved, VS => R0->error, flags corrupt
;       (mustn't be called with V set)
;
; NB:   Doesn't cope with R1=16,R2<>R3 (write different flash states).
;       It is in fact impossible to get R1=24or25,R2<>R3 to work.
setpalette "R4,R9"
        MOV R4,#2                       ; set palette
        MOV R9,#PaletteV
        SWI XOS_CallAVector
        EXIT VS
        TEQ R4,#0
        EXITS EQ
        AND R14,R0,#&FF
        AND R4,R1,#&FF
        ORR R4,R14,R4,LSL #8
        BIC R14,R2,#&FF                 ; R14 = &BBGGRR00
        ORR R4,R4,R14,LSL #8            ; R4 = &GGRRr1r0 (green,red,R1,R0)
        MOV R14,R2,LSR #24              ; R14 = &000000BB (blue)
        Push "R0,R1,R4,R14"
        ADD R1,sp,#2*4                  ; R1 -> block
        MOV R0,#12                      ; write palette
        SWI XOS_Word
        STRVS R0,[sp]
        Pull "R0,R1,R4,R14"
        EXITS VC
        EXIT

Note that when writing the palette, there is no need to alter the parameters when calling VDU 19 or OS_Word 12, since these only look at the top nibbles of each gun.

However, 24-bit palette values can only be received through the vector, since the VDU 19 and OS_Word calls cannot trust the values of the bottom nibbles of the palette values passed to them, and must treat them as being copies of the corresponding top nibbles.

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