www.riscos.com Technical Support: |
|
This chapter describes the memory management in RISC OS. This covers memory allocation by a program or module as well as using the MEMC chip to handle how memory is mapped.
In many environments, such as BASIC and C, you can use the language's intrinsic memory allocation routines, which use the calls described in this chapter transparently. For example, refer to Wimp_SlotSize on Wimp_SlotSize of the chapter entitled The Window Manager.
Similarly, small, transiently loaded utilities may not require any memory over the 1024 bytes they are automatically allocated. Some programs and modules, however, will require arbitrary amounts of memory, which can be freed after use. For example, filing systems, specialised VDU drivers such as the font manager and so on. The memory manager provides simple allocation and deallocation facilities. Relocatable modules can use this manager either directly, to manipulate their own private heap, or indirectly using the module support calls.
A block of memory can be set up as a heap. This is a structure that allows arbitrary parts of the block to be allocated and freed. A program simply requests a block of a given size and is given a pointer to it by the heap manager. This block can be expanded or contracted or freed by using this pointer as a reference.
The part of the screen RAM that is not visible on the screen is also available as a temporary buffer. This memory is temporarily available because of the way that vertical scrolling is done.
One of the other memory resources available is the battery-backed CMOS RAM. This is used to hold default system parameters while the power is off. Some spare locations in CMOS RAM are reserved for users' own purposes, and for the use of expansion cards; application authors wishing to use CMOS RAM should ask Acorn for an allocation (although this will not be given if options can instead be saved to file).
The MEMC chip controls how logical addresses (those used by programs or modules) are mapped into the physical memory location to use. Numerous calls are used to control how it does this, though generally this is something that most programs would not want to do.
RISC OS contains a heap management system. This is used by the operating system to allocate space within the relocatable module area and also to maintain the system heap. A heap is just an area of memory from which bytes may be allocated, then deallocated for later use. An area can also be reallocated, meaning that its size changes.
The heap manager is also available to the user. You provide an area of memory which is to be used for the heap, which can be any size you require. If you are a module, then the heap would be a block within the RMA, and if you are a program, then it would be within the application space.
Thus, it would be a heap within a heap; for example a block in the RMA would be allocated by a module, and then declared as a heap. In theory, this process could continue indefinitely, but in practice this is as far as you need to go.
At the start of a heap, the heap manager sets up the heap descriptor, which is a block containing information on the limits of the heap, etc. This descriptor is updated by the heap manager when necessary.
When a block within this heap is required, a request is made to the heap manager, which returns a pointer to a suitable block of memory. The heap manager keeps a record of the total amount of memory which is free in the heap and the largest individual block which is available.
The heap management system does not provide free-space collation. This is the technique of moving blocks of allocated memory around so as to maximise the contiguous free space and avoiding excessive fragmentation of the heap.
Also, the heap management system will never attempt to move a block within the heap, since it has no knowledge of whether the block contains pointers that need to be relocated, or whether there are any pointers to the block which need updating. Hence, unless an area of contiguous free space of the size requested is available, a request for a block will fail.
The MEMC chip maps logical onto physical addresses. To do this, it maintains a table of entries that map a given memory block to a particular address. Generally, the system will take care of the operation of this mapping for you. Calls are provided to allow you to read this mapping and alter it, but you should have a very good reason to do so, and be certain of what you are doing.
The vertical scrolling technique used under RISC OS is to change the memory location that the screen starts at. This means that part of the screen memory may be unused, depending on the screen mode and the amount of memory reserved. You can use this memory temporarily, as long as you don't cause any output that may scroll the screen. Also remember that this memory is limited to one program using it at a time, so it may not be available every time you request it. Consequently, you cannot rely on it being there when writing a module or application.
A block of 240 bytes of battery-backed CMOS RAM is available under RISC OS. Each location has a specific meaning and should not be directly modified unless you are sure of the meaning of the value. Many of these locations are changed indirectly using the *Configure commands. These can be found throughout this manual, in the chapter appropriate to their function.
Some bytes are not allocated, and are reserved for users and applications to use. If you want to use one or more of the application bytes, you should request a location in writing from Acorn Computers. This is so that different applications don't accidentally use the same location.
This section provides basic information on memory management by RISC OS applications. It is intended to provide some specialist knowledge to help you write efficient programs for RISC OS, and to provide some practical hints and tips.
All the information in this chapter relating to programs written in C refers to Acorn's Desktop C product.
You should follow the guidelines in this section to make the best use of available memory. The guidelines are explained in more detail on the following pages.
An important consideration when designing programs for RISC OS is the recovery process, not just from user errors, but also from lack of system resources.
An example of a technique that can be designed into an application is to make an algorithm more disc-based and less RAM-based on detection of lack of memory. This could allow you to continue using an application on a small machine (especially one with a hard disc) at the expense of some speed.
When implementing your code, expect the unexpected and program defensively. Be sure that when the system resources you need (memory, windows, files etc) are not available, your program can cope. Make sure that, when a document managed by your program expands and memory runs out, the document is still valid and can be saved. Don't just check that your main document expansion routines work; check that all routines which require memory (or in fact any system resource) fail gracefully when there is no more.
Centralising access to system resources can help: write your program as if every operating system interface is likely to return an error.
Permanent loss of memory is mainly a problem for applications or modules written entirely in assembly language. When interworking assembler routines with C or another high level language you should use memory handed to you by the high level language library (eg use malloc to get a memory area from C and pass a pointer to it as an argument to your assembler routine). The language library automatically returns such areas to RISC OS on program exit. Additional types of program requiring care to avoid memory loss are those expected to run for a long time (eg a printer spooler) and those making use of RMA directly through SWI calls.
When using the RMA for storage directly through SWI calls, especially for items in linked lists, consider using the first word as a check word containing four characters of text to identify it as belonging to your program. When a block of RMA is deallocated, the heap manager puts it back into a list of free blocks, and in so doing overwrites the first word of the block.
This technique therefore serves two purposes:
A typical problem of referencing deallocated blocks results from using the first word as a pointer to your program's next block, then accidentally referencing a wild pointer when it is overwritten.
You can use the following BASIC routine to search for any lost blocks:
100 REM > LostMemory checks for un-released blocks 110 SYS "OS_ReadDynamicArea",1 TO RMA%: RMAEnd% = RMA% + (RMA%!12) 120 FOR PossibleBlock% = RMA%+20 TO RMAEnd%-12 STEP 16 130 REM Now loop looking for "Prog" 140 IF PossibleBlock%!0 = &676F7250 THEN 150 PRINT "Block found at &";~PossibleBlock% 160 ENDIF 170 NEXT PossibleBlock% 180 END
When writing relocatable module initialisation code you should check that memory and other system resources are returned if initialisation is unable to complete and is going to return with V set. It is often useful to construct module finalisation code as a mirror image of initialisation code so that it can be jumped to when initialisation is going to return an error and cleaned up. A typical algorithm is:
Initialisation | |
---|---|
Claim main workspace: If error then keep this error and goto Exit3 | |
Claim secondary workspace: If error then keep this error and goto Exit2 | |
Claim tertiary workspace: If error then keep this error and goto Exit1 | |
Return | |
Finalisation | |
Set kept error to null | |
Release tertiary workspace | |
Exit1 | Release secondary workspace |
Exit2 | Release main workspace |
Exit3 | Get kept error (if there was one) |
Return |
The key factor in writing programs that use memory efficiently and don't waste it is understanding the following:
This understanding will lead you to writing programs that will work in harmony with the storage allocator. See the following section for a description of C memory allocation.
Understanding the C storage manager is obviously useful to writers of C. But it may also be useful to writers of assembly language for two reasons: to assist in constructing part C and part assembler programs; to assist in constructing their own memory allocation routines, both as an example algorithm and as an allocator that may be running for other applications at the same time as their own.
Normal C applications (ie those not running as modules) claim memory blocks in two main ways:
The malloc heap storage manager is the standard interface from which to claim small areas of memory. It is tuned to give good performance to the widest variety of programs.
In the following sections, the word heap refers to the section of memory currently under the control of the storage manager (usually referred to as malloc, or the malloc heap).
The flex facility is available as part of RISC_OSLib, and can be useful for claiming large areas of data space. It manages a shifting set of areas, so its operation can be slow, and address-dependent data cannot be stored in it. However, it has the following advantages:
All block sizes allocated are in bytes and are rounded up to a multiple of four bytes. All blocks returned to the user are word-aligned. All blocks have an overhead of eight bytes (two words). One word is used to hold the block's length and status, the other contains a guard constant which is used to detect heap corruptions. The guard word may not be present in future releases of the ANSI C library. When the stack needs to be extended, blocks are allocated from the malloc heap.
When an allocation request is received by the storage manager, it is categorised into one of three sizes of blocks
The storage manager keeps track of the free sections of the heap in two ways. The medium and large sized blocks are chained together into a linked list (overflow list) and small blocks of the same size are chained together into linked lists (bins). The overflow list is ordered by ascending block address, while the bins have the most recently freed block at the start of the list.
When a small block is requested, the bin which contains the blocks of the required size is checked, and, if the bin is not empty, the first block in the list is returned to the user. If there was not a block of the exact size available, the bin containing blocks of the next size up is checked, and so on until a block is found. If a block is not found in the bins, the last block (highest address) on the overflow list is taken. If the block is large enough to be split into two blocks, and the remainder is a usable size (> 12 including the overhead) then the block is split, the top section returned to the user and the remainder, depending on its size, is either put in the relevant bin at the front of the list or left in the overflow list.
When a medium block is requested, the search ignores the bins and starts with the overflow list. This is searched in reverse order for a block of usable size, in the same way as for small blocks.
When a large block is requested, the overflow list is searched in increasing address order, and the first block in the list which is large enough is taken. If the block is large enough to be split into two blocks, and the size of the remainder is larger than a small block (> 64) then the block is split, the top section is returned to the overflow list, and bottom section given to the user.
Should there not be a block of the right size available, the C storage manager has two options:
The heap will only be coalesced if there is at least enough free memory in it to make it worthwhile (ie four times the size of the requested block, and at least one sixth of the total heap size) or if the request for more heap was denied. Coalescing causes the following:
When a block is freed, if it will fit in a bin then it is put at the start of the relevant bin list, otherwise it is just marked as being free and effectively taken out of the heap until the next coalesce phase, when it will be put in the overflow list. This is done because the overflow list is in ascending block address order, and it would have to be scanned to be able to insert the freed block at the correct position. Fragmentation is also reduced if the block is not reusable until after the next coalesce phase. It is worth noting that deallocating a block and then reallocating a block of the same size can not be relied upon to deliver the original block.
You should be cautious when using realloc. Reallocating a block to a larger size will usually require another block of memory to be used and the data to be copied into it. This means that you cannot use the whole of the heap as both blocks need to be present at the same time.
If consecutive calls keep increasing the block size until all memory is used up, then only about a third of the heap is likely to be available in one block. A typical course of events is:
A typical C application running under the Wimp has a single contiguous application area (wimp slot) into which are placed the following:
The initial wimp slot size is set by the size of the Next slot (in the Task display window) when the application is started, or by *WimpSlot commands in the !Run file associated with the C application. If the malloc heap is full and the operating system has free memory, the wimp slot grows, raising its highest address. Once enlarged by malloc, the wimp slot never reduces again until program termination.
The application area is used as follows:
low memory: | the application image |
the static data | |
high memory: | the malloc heap |
The stack is allocated on the heap, in 4K (or as big as needed) chunks: the ARM procedure call standard means that disjoint extension of the stack is possible. The only other use that the ANSI C library makes of the malloc heap is in allocating file buffers, but even this usage can be prevented by making the appropriate calls to the ANSI C library buffer handling facilities (setvbuf). The operation of the malloc heap is described above and is designed to provide good performance under heavy use. Its design is such that small blocks can be allocated and freed rapidly.
Any malloc heap tends to fragment over time. This is particularly serious in the following circumstances:
These are just the conditions under which a desktop application operates!
Because of this, the flex facilities are available as part of RISC_OSLib (the RISC OS-specific C library provided with Desktop C). These provide a shifting heap, intended for the allocation of large blocks of memory which might otherwise destroy the structure of a malloc-style heap.
Flex works by increasing the size of the application area, using space above that reserved for use by malloc. When the malloc heap grows, flex areas are shifted. The benefits of using flex can be seen in Draw, Paint and Edit, which are all written in C using early versions of RISC_OSLib. Their application areas expand when new files are added, contract when files are discarded, and do not suffer from needless incremental application area growth over time.
The implementation of flex is quite simple. There is no free list as memory is shifted whenever a block is destroyed or changed in size. New blocks are always allocated at the top. When blocks are deallocated or resized, those above are moved. This means that deallocating or changing the size of a block can take quite a long time (proportional to the sum of the sizes of the blocks above it in memory). Flex is also not recommended for allocation of small blocks. Its other limitation is that as flex blocks can be shifted, you should not use them for address-dependent data (eg pointers or indirected icon data).
In addition to the facilities described above, RISC_OSLib also provides an obsolete malloc-like allocator of non-shifting blocks called heap.
Two facilities are provided, because no one storage manager can solve all problems in the absence of Virtual Memory. A program which works adequately with malloc should feel no compulsion to use anything else. The use of flex, however, particularly in desktop applications such as editors (which are likely to be resident on the desktop for a long period of time) can go a long way towards improving their memory usage.
Relocatable modules should use memory from three sources: the supervisor stack; the RMA; and application workspace. Use of pc-relative written data should be avoided as it makes a module unsuitable to ROM, unsuitable for multiple instantiation, and permanently reserves space, possibly only for occasional use.
The supervisor stack is small and not extendable, so care must be taken to use this resource very economically.
The RMA is the standard source of workspace for any of the non-user mode routines contained in a module. Care must be taken to deallocate unwanted blocks - the marker word hint described earlier in this chapter may be useful. C malloc uses RMA when called from non-user mode.
Application workspace only belongs to a module when referenced from module user mode code running as the sole current application (with RISC OS desktop multitasking halted) or when running as a RISC OS application having dealt with the Service_Memory (&11) service call (sent round by the wimp when your program issues SWI Wimp_Initialise) to keep application workspace.
Never access your application's workspace from an interrupt routine. During interrupts, the state of the application area is effectively random. Since your interrupt routine could execute at any time, it could happen while some other application is switched in. If this did happen, and the interrupt routine updated application space, then some other application could be affected. To get around this problem, allocate some RMA space for your interrupt routine to use when it needs to; this memory will be visible when your application is running. Remember to free up the RMA space when you've finished with it.
There are additional points you should note if you are writing modules in C (although most of the points made above apply equally well - particularly the preceding paragraph).
All memory allocated by malloc comes from the RMA when your program is executing in non-user mode. So remember to free it up when you've finished with it. If your module allocates any RMA blocks by calling SWI XOS_Module directly, the C run-time system does not clear them out when your module finalises, so make sure you do!
There are two sets of atexit() routines, the ones which you registered during initialisation ie before your module was entered via the main() entry point (because the module was RMRun for instance), and the ones you registered after. The ones registered before will be executed when your module is finalised - this is how to clear up after yourself; the ones after will be called when your module exits from being run, ie when main() terminates.
When you are writing a C module, use exit(), not SWI XOS_Exit.
When executing as C module SVC mode code (during initialisation, finalisation, service or interrupt entry) your stack will be small. Also, your stack, unlike when in USR mode (ie running as an application) will not extend dynamically. It is therefore very important to be extremely economical with stack space; eg avoiding large auto arrays, using malloc where larger spaces are required, and freeing claimed memory at the routine end.
Static variables (and arrays etc.) in a C module are extant for the lifetime of the module, ie the entire time it is loaded. If they are only needed when it is running as an application, then they should be claimed using malloc instead.
The heap is controlled by a single SWI, OS_Heap OS_Heap 0 onwards). This has a reason code and can perform the following operations:
Reason code | Meaning |
---|---|
0 | Initialise heap |
1 | Describe heap |
2 | Allocate a block from a heap |
3 | Free a block |
4 | Change the size of a block |
5 | Change the size of a heap |
6 | Read the size of a block |
A description of the structure used by the heap manager is given below. It should be noted that this structure is not guaranteed to be preserved between releases of the software and should not be relied upon. It is given purely for advanced programmers who may want to interpret the current state of the heap when testing and debugging their own code.
The heap descriptor is a block of four words:
The 'special' heap word contains a pattern which distinguishes correct heap descriptors. The pattern is made up of the characters 'Heap' - which is &70616548 in hex.
All other words are offsets into the heap. This means that the heap is relocatable unless you place non-relocatable information in it.
The free list offset is an offset to the first free block in the heap, or zero if there are no free blocks. If the word is non-zero, the first free block is at address:
The other entries are offsets from the start of the heap which refer to boundaries within the heap structure. The heap is delimited as follows:
Blocks in the free list have information in the first two words as follows:
Allocated blocks start with a word which holds the size of the allocated block. The pointer returned by SWI OS_Heap when a block is allocated actually points to the second word which is the start of the memory available.
Allocation forces the block size to be a multiple of eight, to ensure that no matter what you do, the fragments can always be freed. Therefore, the minimum size of area that can be initialised is 24 bytes (16 for the fixed information and 8 for a block).
The organisation of the logical address space is currently as follows:
You must not assume that any of the above addresses will remain fixed (save for the base of application workspace). There are defined calls to read any addresses you need, and you must use them.
The memory map is set up on hard reset as follows:
Here is an example of how memory might be allocated given some typical RAM size allocations on an A310 (8K page size):
Area | Pages | Page size | Total | ||
---|---|---|---|---|---|
FontSize | 20 | 4K | 80K | ||
RamFsSize | 0 | 8K | 0 | ||
RMASize | 16 | 8K | 128K | ||
ScreenSize | 20 | 8K | 160K | ||
SpriteSize | 10 | 8K | 80K | ||
SystemSize | 4 | 8K | 32K+32K | ||
System workspace | 32K | ||||
Cursor etc. workspace | 32K | ||||
Total | 576K | ||||
Application area | 1024K - 576K = 448K |
Note that although the FontSize is configured in units of 4K, it is always allocated in multiples of the MEMC page size. A configured screen size of 0 means 'default for this machine', which is 160K on an A310 (see *Configure ScreenSize).
As outlined above, the size of the system area (at 28M) is shrunk as far as possible after all module initialisation and then 'n' extra pages are added. 8K of this is used for the system stack. The rest is for OS variable storage (eg alias variables) and module information. The configured amount is added to the 32K initially allocated.
While no application is running (ie in the supervisor prompt), the memory map can be altered as required. For example, if you load a module from disc and the RMA isn't big enough to hold it, the size of the RMA will be increased by an appropriate amount. The OS can only do this when there is no application active, as the extra memory has to be taken from the application workspace. Most programs don't react too kindly to large areas of their memory allocation disappearing.
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 out the current application, and maps the new application into that space. Thus every application is given the illusion that it is the only one in the system.
The SWI OS_ReadMemMapInfo returns the page size used in the system and the number of pages present. For more details of page sizes, see the chapter entitled Page size.
OS_ChangeDynamicArea allows control of the space allocated to the system heap, RMA, screen, sprite area, font cache and RAM filing system. Any space left over is the application space by default. Any of these settings can be read with OS_ReadDynamicArea. OS_ReadRAMFsLimits will read the range of bytes used by the RAM filing system. The size of it can be set in CMOS RAM using *Configure RamFsSize. See also *Configure RMASize and *Configure SystemSize.
You have read/write access to much of the logically mapped RAM. There are exceptions, such as the 32K system workspace at &1F00000 (31M), the RAM disc, and the font cache. More areas may become protected in future releases of RISC OS. The only areas normal applications should directly access are the application workspace and the RMA. Specialist programs may access other areas of memory; for example a set of extension graphics primitives may write directly to the screen (of course reading the screen's base address using a defined call: in this case OS_ReadVduVariables). In general, though, it is very dangerous to write to these other areas, or rely on certain locations containing given information, as these are subject to change. You should always use OS routines to access operating system workspace.
OS_ValidateAddress will check a range of logical addresses to see if they are mapped into physical memory.
The mapping that MEMC maintains from logical to physical address space can be read with OS_ReadMemMapEntries. This gives a list of physical addresses for a matching set of logical page numbers.
The reverse operation, OS_SetMemMapEntries will write the mapping inside MEMC. Note that this is an extremely dangerous operation if you are not sure what you are doing.
OS_UpdateMEMC is a lower level operation that alters the bits in the MEMC control register.
The screen workspace is at the end of logical memory, adjacent to the physical RAM which is mapped onto those addresses. This means that there are two adjacent copies of the screen memory.
The display is normally set up by RISC OS's VDU drivers, which write to the logical memory.
You can read various VDU and mode variables to find the addresses used for this. In particular, the ScreenStart VDU variable give the logical address of the base of screen memory, the ScreenSize mode variable gives the amount of memory used by the current mode (and hence the logical address of the top of screen memory), and the TotalScreenSize VDU variable gives the amount of memory allocated to the display.
The screen-size is configurable in units of one page. Hence for a 20K screen on a 400 series machine, 32K will have to be used since it is the next highest multiple of 32K. For an 80K screen, 96K would be used, etc. In addition, if you want to use multiple banks of screen memory (eg for animation), enough memory must be reserved for each bank.
Because the total screen memory is often much more than is required at a given time, the SWI OS_ClaimScreenMemory is provided so you can claim the 'extra' RAM for short periods. It can be used as a buffer, in a data transfer operation, for example.
The display is output by MEMC using DMA to access the area of physical memory corresponding to the logical area used by the VDU drivers, and passing this area's contents to VIDC for conversion to a video signal. The area is treated as a circular buffer.
Video DMA is controlled by the physical addresses in various MEMC registers. At the start of a frame the Vptr register (ie the video DMA pointer) is set to the address in the Vinit register - which normally corresponds to the logical address in the ScreenStart VDU variable. Each read Vptr is incremented, unless it has reached the end of the buffer (as delimited by the Vend register), in which case Vptr is reset to the start of the buffer (given by the Vstart register).
This section gives two diagrams to illustrate the above; they also show how hardware scrolling is implemented.
For an unscrolled screen, access to screen memory takes place as follows:
Vertical hardware scrolling is implemented by altering MEMC's Vinit register. At the same time the ScreenStart VDU variable must be altered so that the VDU drivers write to the corresponding location in logical memory. This means that with larger amounts of scrolling, a part of the logical area to which the VDU drivers are writing is in fact an area of physical memory:
Screen memory after hardware scrolling
Normally hardware scrolling is performed automatically, and you don't have to concern yourself with it. However, if you need to implement it yourself - for a game, for instance - you should be in a privileged processor mode, so you can both alter MEMC's Vinit register and write to physical memory.
240 bytes of non-volatile memory are provided. The majority of these bytes are reserved for, or used by Acorn. Some bytes are reserved for each expansion card; before using these, see the chapter entitled CMOS RAM. There are also bytes reserved for the user; you must not use these in any distributed product. Finally, there are bytes reserved for applications; for an allocation, contact Acorn in writing, but see first the CMOS RAM bytes.
CMOS usage is subject to change in different versions of RISC OS, and your application should not assume the location of any particular information.
OS_Byte 161 allows you to read the CMOS memory directly, while OS_Byte 162 can write to it.
The full usage of CMOS RAM in RISC OS 3 is given below. Locations marked '†' are unused in RISC OS 2, and are therefore reserved for Acorn use. Locations marked '‡' have differing usage in RISC OS 2, and you should see RISC OS 2 for details:
Location | Function | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Econet station number (not directly configurable) | ||||||||||||||||
1 | Econet file server station id (0 name configured) | ||||||||||||||||
2 | Econet file server net number (or first char of name - rest in bytes 153 - 157) | ||||||||||||||||
3 | Econet printer server station id (0 name configured) | ||||||||||||||||
4 | Econet printer server net number (or first char of name - rest in bytes 158 - 172) | ||||||||||||||||
5 | Default filing system number | ||||||||||||||||
6 - 7 † | *Unplug for ROM modules: 16 bits for up to 16 modules | ||||||||||||||||
8 - 9 | Reserved for Acorn use | ||||||||||||||||
10 | Screen info:
| ||||||||||||||||
11 | Shift, Caps mode:
| ||||||||||||||||
12 | Keyboard auto-repeat delay | ||||||||||||||||
13 | Keyboard auto-repeat rate | ||||||||||||||||
14 | Printer ignore character | ||||||||||||||||
15 | Printer information:
| ||||||||||||||||
16 | Miscellaneous flags:
| ||||||||||||||||
17 | NetFiler:
| ||||||||||||||||
18 - 19 † | *Unplug for ROM modules: 16 bits for up to 16 modules | ||||||||||||||||
20 - 21 † | *Unplug for extension ROM modules: 16 bits for up to 16 modules | ||||||||||||||||
22 † | Wimp double-click move limit | ||||||||||||||||
23 † | Wimp auto-menu delay | ||||||||||||||||
24 † | Territory | ||||||||||||||||
25 † | Printer buffer size | ||||||||||||||||
26 † | IDE disc auto-spindown delay | ||||||||||||||||
27 † | Wimp menu drag delay | ||||||||||||||||
28 † | FileSwitch options:
| ||||||||||||||||
29 | Reserved for Acorn use | ||||||||||||||||
30 - 45 | Reserved for the user | ||||||||||||||||
46 - 79 | Reserved for applications | ||||||||||||||||
80 - 111 | Reserved for RISC iX | ||||||||||||||||
112 - 127 | Reserved for expansion card use | ||||||||||||||||
128 - 129 | Current year | ||||||||||||||||
130 - 131 | Reserved for Acorn use | ||||||||||||||||
132 | DumpFormat and Tube expansion card:
| ||||||||||||||||
133 ‡ | Sync, monitor type, some mode information:
| ||||||||||||||||
134 | FontSize in units of 4K | ||||||||||||||||
135 - 137 | ADFS use | ||||||||||||||||
138 | Allocated to CDROMFS | ||||||||||||||||
139 † | TimeZone in 15min offsets from UTC, stored as signed 2's complement number (RISC OS 3 version 3.10 onwards) | ||||||||||||||||
140 ‡ | Desktop features:
| ||||||||||||||||
141 † | Currently selected printer, stored as printer number within current PrData file | ||||||||||||||||
142 | Allocated to Twin | ||||||||||||||||
143 | Screen size, in pages | ||||||||||||||||
144 | RAM disc size, in pages | ||||||||||||||||
145 | System heap size to add after initialisation, in pages | ||||||||||||||||
146 | RMA size to add after initialisation, in pages | ||||||||||||||||
147 | Sprite size, in pages | ||||||||||||||||
148 | SoundDefault parameters:
| ||||||||||||||||
149 - 152 | Allocated to BASIC Editor | ||||||||||||||||
153 - 157 | Printer server name | ||||||||||||||||
158 - 172 | File server name | ||||||||||||||||
173 - 176 | *Unplug for ROM modules: 32 bits for up to 32 modules | ||||||||||||||||
177 - 180 | *Unplug for expansion card modules: 4 × 8 bits for up to 8 modules per card | ||||||||||||||||
181 - 184 | Wild card for BASIC editor | ||||||||||||||||
185 | Configured language | ||||||||||||||||
186 | Configured country | ||||||||||||||||
187 | VFS | ||||||||||||||||
188 | Miscellaneous:
| ||||||||||||||||
189 - 192 | Winchester size | ||||||||||||||||
193 | Protection state:
| ||||||||||||||||
194 | Mouse multiplier | ||||||||||||||||
195 † | Miscellaneous:
| ||||||||||||||||
196 ‡ | Mode and Wimp mode | ||||||||||||||||
197 | Wimp flags | ||||||||||||||||
198 | Desktop state:
| ||||||||||||||||
199 | ADFS directory cache size | ||||||||||||||||
200 - 207 | FontMax, FontMax1 - FontMax7 | ||||||||||||||||
208 † | SCSIFS flags :
| ||||||||||||||||
209 † | SCSIFS file cache buffers (must be 0) | ||||||||||||||||
210 † | SCSIFS directory cache size | ||||||||||||||||
211 - 214 † | SCSIFS disc sizes (their maps' sizes / 256) | ||||||||||||||||
224 - 238 | Reserved for RISC iX | ||||||||||||||||
239 † | CMOS RAM checksum |
The checksum must be correct for some of the above locations to have effect. See the documentation of OS_Byte 162 on OS_Byte 162 for more details.
Locations marked '†' above are unused in RISC OS 2, and are therefore reserved for Acorn use. Locations marked '‡' above have this differing usage in RISC OS 2:
R1 = &4E (reason code)
R1 preserved to pass on (do not claim)
This call is made whenever OS_ChangeDynamicArea has just finished. It is used by the Wimp to tidy up and should never be claimed.
OS_ValidateAddress has been called with an unrecognised area
R1 = &6D (reason code)
R2 = start of area (value passed in R0 on entry to OS_ValidateAddress)
R3 = end of area + 1 (value passed in R1 on entry to OS_ValidateAddress)
R1 = 0 to indicate area is valid; else preserved to pass on
This call is intended for internal use only. Application modules should not need to claim or issue this service.
R0 = 161
R1 = RAM location
R0, R1 preserved
R2 = contents of location
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
This call provides read access to any of the locations in the battery-backed CMOS RAM. For example, this call may be used by a module to read a default configuration parameter. Moreover, this parameter could be examined by the user using the *Status command, if the module provides a suitable entry in its command decoding table. See the chapter entitled Help and command keyword table for more details.
ByteV
R0 = 162
R1 = RAM location
R2 = value to be written
R0, R1 preserved
R2 corrupted
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
This call writes to any of the locations in the battery backed RAM with the exception of location zero, which is protected. In doing so the CMOS RAM checksum is maintained but not recalculated; ie it will remain in the same state of correctness as before this call. To keep the checksum correct, you should always use this call to write to the CMOS RAM, and never write to the checksum location. This call can take a comparatively long time to return (eg 20ms).
ByteV
R0 = new bits in field
R1 = field mask
R0 = previous bits in field
R1 = previous field mask
Interrupts are disabled
Fast interrupts are disabled
Processor is in SVC mode
SWI cannot be re-entered because interrupts are disabled
The memory controller (MEMC) chip is a write-only device. The operating system maintains a software copy of the current state of the control register and OS_UpdateMEMC updates MEMC from the software state. To allow the programming of individual bits the call takes a field and a mask. The new MEMC value is:
newMemC | = (oldMEMC AND NOT R1) OR (R0 AND R1) |
R0 | = oldMEMC |
So to read the contents without altering them, R0 and R1 should both be zero. To set them to n, R0 = n and R1=&FFFFFFFF.
None
None
Perform various operations on the heap
R0 = reason code
R1 = pointer to heap
R2 = pointer to block (if relevant to reason code)
R3 is reason code dependent
R0, R1 preserved
R2 and R3 are reason code dependent
Interrupt status is not altered
Fast interrupts are enabled
Processor is in SVC mode
SWI is re-entrant
This call performs various operations on the heap, depending on the reason code passed in R0:
R0 | Meaning | Page |
---|---|---|
0 | Initialise heap | OS_Heap 0 |
1 | Describe heap | OS_Heap 1 |
2 | Get heap block | OS_Heap 2 |
3 | Free heap block | OS_Heap 3 |
4 | Extend or shrink heap block | OS_Heap 4 |
5 | Extend or shrink heap | OS_Heap 5 |
6 | Read block size | OS_Heap 6 |
None
None
R0 = 0 (reason code)
R1 = pointer to heap to initialise
R3 = size of heap
R0, R1, R3 preserved
This call checks the given heap pointer, and then writes a valid descriptor into the heap it points at. The heap is then ready for use. The value given for R1 must be word-aligned and less than 32Mbytes (ie must point to an area of logical RAM). R3 must be a multiple of four and less than 16Mbytes.
R0 = 1 (reason code)
R1 = pointer to heap
R0, R1 preserved
R2 = largest available block size
R3 = total free
This call returns information on the space available in the heap. An error is returned if the heap is invalid. This may be for any of the following reasons:
R0 = 2 (reason code)
R1 = pointer to heap
R3 = size required in bytes
R0, R1 preserved
R2 = pointer to claimed block or zero if allocation failed
R3 preserved
This allocates a block from the heap. An error is returned if the allocation failed for any of the following reasons:
R0 = 3 (reason code)
R1 = pointer to heap
R2 = pointer to block
R0 - R2 preserved
This checks that the pointer given refers to an allocated block in the heap, and deallocates it. Deallocation tries to join free blocks together if at all possible, but if the block being freed is not adjacent to any other free block it is just added to the list of free blocks. An error is returned if the deallocation failed which may be because:
R0 = 4 (reason code)
R1 = pointer to heap
R2 = pointer to block
R3 = required size change in bytes (signed integer)
R0, R1 preserved
R2 = new block pointer, or -1 if heap block extended to size 0 (or less)
R3 preserved
This attempts to enlarge or shrink the given block in its current position if possible, or, if this is not possible, by reallocating and copying it. Note that if the block has to be moved, it is your responsibility to note this (by the fact that R2 has been altered), and to perform any necessary relocation of data within the block.
R0 = 5 (reason code)
R1 = pointer to heap
R3 = required size change in bytes (signed integer)
R0, R1 preserved
R3 preserved, or amount of bytes heap shrunk by if requested shrink failed
This updates the heap size information to take account of the new size. If the heap cannot shrink as far as requested - because of data that has already been allocated - it will shrink as far as possible, set R3 to the amount by which it shrank, and return an error.
R0 = 6 (reason code)
R1 = pointer to heap
R2 = pointer to block
R0 - R2 preserved
R3 = current block size
This reads the size of a block in the specified heap. This includes any overheads associated with the block, and so will be larger, for example, than the required size of a block newly created with OS_Heap 2. An error is returned if the heap or the block could not be found.
R0 = area to alter
R1 = amount to move in bytes (signed integer)
R0 = preserved
R1 = number of bytes moved (unsigned integer)
Interrupts are disabled in critical periods, but otherwise in the caller's state
(Under RISC OS 2 interrupts are disabled throughout the call)
Fast interrupts are enabled
Processor is in SVC mode
SWI is re-entrant
OS_ChangeDynamicArea allows the space allocated to an area to be altered in size by removing or adding workspace from the application workspace.
The area to be altered depends on R0 as follows:
Value of R0 | Area to alter |
---|---|
0 | system heap |
1 | RMA |
2 | screen area |
3 | sprite area |
4 | font cache |
5 | RAM filing system |
The amount to move is given by the sign and magnitude of R1:
+ve | means enlarge the selected area by at least the given amount |
-ve | means shrink the selected area by no more than the given amount |
If the amount to be moved is not an exact number of pages, it is rounded up (ie in the +ve direction) to the next number of pages.
Note that normally, this cannot be used while the application work area is being used; for example when BASIC is active outside the RISC OS desktop. An attempt to do so will result in a 'Memory in use' error. (In fact, when this call is made, the OS passes a service call round to modules, which can veto the change if they can't handle it correctly. See Service_Memory (Service Call &11) and Service_MemoryMoved (Service Call &4E) for more details.
Any area size change will fail if the new size is smaller than the current requirements, but will shrink the area as far as it can. If you need to release as much space as possible from an area, try to reduce its size by 16 Mbytes.
Expanding, on the other hand, does nothing if it can't move enough. In this case, if you asked for the extra space you probably need it all; RISC OS assumes that half the job is no use to you.
This SWI also does an UpCall, to enable programs running in application workspace to allow movement of memory. If the UpCall is claimed when the application is running in application workspace, the memory movement is allowed to proceed. For full details see OS_UpCall 257.
An error is returned if not all the bytes were moved, or if application workspace is being used - ie an application is active.
None
R0 = minimum address
R1 = maximum address
R0, R1 preserved
C flag is clear if the range is OK, set otherwise
Interrupt status is not altered
Fast interrupts are enabled
Processor is in SVC mode
SWI is re-entrant
This SWI checks the address range between R0 and (R1 - 1) inclusive to see if they are valid. If they are equal, then that single address is checked. Valid addresses are those in logical RAM (0 - 32M) which have memory mapped to them, and also the second mapping of screen RAM at the start of physical memory (32M). From RISC OS 3 onwards, if the area is not recognised as valid Service_ValidateAddress is issued, which if claimed indicates the area is valid, and results in the C flag being cleared on exit from the SWI. See Service_ValidateAddress (Service Call &6D).
None
None
Use spare screen memory
R0 = 0 for release, 1 for claim
R1 = length required in bytes (if R0 = 1)
R0 preserved
if the C flag is 0, then memory was claimed successfully
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
SWI is not re-entrant
There are several restrictions to the use of screen memory. It can only be claimed by one 'client' at a time, who gets all of it. It can only be claimed if no bank other than bank 1 has been used. You can't claim it, for example, if the shadow bank has been used.
While you have claimed the screen memory, you must not perform any action which might causes the screen to scroll. This means avoiding the use of routines which might cause screen output.
It is important to release the memory after it has been used.
This call is mainly intended for internal use; you should not need to use it.
None
None
--
R0 = start address
R1 = end address + 1 byte
Interrupt status is not altered
Fast interrupts are enabled
Processor is in SVC mode
SWI is re-entrant
This reads the start and end addresses of the RAM filing system. This information can also be read from OS_ReadDynamicArea.
If the RamFS is configured to zero size then R0 and R1 have the same value on exit.
The size of the RamFS after a hard reset (ie the difference between the two return values) can be configured using *Configure RamFsSize.
None
--
R0 = page size in bytes
R1 = number of pages
Interrupt status is not altered
Fast interrupts are enabled
Processor is in SVC mode
SWI is re-entrant
This call reads the page size used by MEMC and the number of pages in use. The valid page numbers are 0 to R1 - 1, and the total memory size is R0 × R1 bytes.
None
None
Read by page number the logical to physical memory mapping used by MEMC
R0 = pointer to buffer to receive request list
R0 preserved
Interrupt status is not altered
Fast interrupts are enabled
Processor is in SVC mode
SWI is re-entrant
This call reads the logical to physical memory mapping used by MEMC. For given page numbers, it finds the corresponding logical address and protection level.
The returned request list is a series of entries three words long, terminated by a -1 in the first word. The three words are used for:
Word | Meaning | ||||||||
---|---|---|---|---|---|---|---|---|---|
1 | page number (from 0 upwards) | ||||||||
2 | logical address that it is mapped to | ||||||||
3 | protection level:
|
On entry, the page number fields must be set; on exit, all fields are set.
None
R0 = pointer to request list
R0 preserved
Interrupt status is not altered
Fast interrupts are enabled
Processor is in SVC mode
SWI is re-entrant
This call writes the logical to physical memory mapping used by MEMC.
The request list is a series of entries three words long, terminated by a -1 in the first word. The three words are used for:
Word | Meaning | ||||||||
---|---|---|---|---|---|---|---|---|---|
1 | page number (from 0 upwards) | ||||||||
2 | logical address that it is mapped to | ||||||||
3 | protection level:
|
All fields must be set on entry.
Any address above 32Mbyte (&2000000) makes that page inaccessible. This also sets the protection level to minimum accessibility. For future compatibility, you should use an address of -1 (&FFFFFFFF) for this.
This SWI assumes you know what you are doing. It will set any page to any address, with no checks at all.
If you are using this call, then you can only use OS_ChangeDynamicArea if the kernel's limits are maintained, and all appropriate areas contain continuous memory.
OS_ChangeDynamicArea, OS_ReadMemMapEntries, OS_FindMemMapEntries
None
R0 = area to read
R0 = pointer to start of area
R1 = current number of bytes in area
R2 = maximum size of area, if bit 7 of R0 was set on entry; preserved otherwise
Interrupt status is not altered
Fast interrupts are enabled
Processor is in SVC mode
SWI is not re-entrant
This SWI reads the size and - optionally - the maximum size of an area. The area read depends on R0 as follows:
Value of R0 | Area to read |
---|---|
0 | system heap |
1 | RMA |
2 | screen area |
3 | sprite area |
4 | font cache |
5 | RAM filing system |
RISC OS 2 ignores bit 7 of R2, and always preserves R2.
None
Read by logical address the logical to physical memory mapping used by MEMC
R0 = pointer to request list
R0 preserved
Interrupt status is not altered
Fast interrupts are enabled
Processor is in SVC mode
SWI is re-entrant
This call reads the logical to physical memory mapping used by MEMC. For a given logical address, it finds the corresponding page number and protection level.
The request list is a series of entries three words long, terminated by a -1 in the first word. The three words are used for:
Word | Meaning | ||||||||
---|---|---|---|---|---|---|---|---|---|
1 | page number (from 0 upwards) | ||||||||
2 | logical address that it is mapped to | ||||||||
3 | protection level:
|
On entry, the logical address fields must be set. You may supply probable page numbers, which (if correct) will make this call return more quickly than it might otherwise. If you have no idea what the page number might be, you should set the page number to zero on entry. The protection level is ignored on entry.
If the page number is -1 on exit, then the memory map entry was not found; in this case, the protection level will always be 3. Otherwise the request list has been updated with the page number and protection level for the given logical address.
This call is not available in RISC OS 2.
None
Sets the value of a configuration option in the CMOS RAM
option | the name of a configuration option |
value | its new value(s) |
*Configure sets the value of a configuration option in the CMOS RAM. These are used to permanently store the configuration (or set-up) of the computer. The time they take effect differs; some take effect immediately, whereas some are only made current on initial power-on or after a hard break (Ctrl-Reset).
If no parameters are specified, the available configuration options are listed.
If parameters are specified, the given value is stored in the location in CMOS RAM appropriate for the given option. Some options require more than one value, and some require none at all.
Where a number is required, you may give it in decimal, as a hex number preceded by &, or a number of the form base_num, where base is the base of the number in decimal in the range 2 to 36. For example 2_1010 is another way of saying 10.
Here is a list of the available configuration options, the details of which can be found on the appropriate pages:
User Preferences | Chapter | Page |
---|---|---|
*Configure Boot | FileSwitch | *Configure Boot |
*Configure Caps | Character Input | *Configure Caps |
*Configure Delay | Character Input | *Configure Delay |
*Configure Dir | FileCore | *Configure Dir |
*Configure DumpFormat | FileSwitch | *Configure DumpFormat |
*Configure FileSystem | FileSwitch | *Configure FileSystem |
*Configure FontMax1 | The Font Manager | *Configure FontMax1 |
*Configure FontMax2 | The Font Manager | *Configure FontMax2 |
*Configure FontMax3 | The Font Manager | *Configure FontMax3 |
*Configure FontMax4 | The Font Manager | *Configure FontMax4 |
*Configure FontMax5 | The Font Manager | *Configure FontMax4 |
*Configure Language | The rest of the kernel | *Configure Language |
*Configure Lib | NetFS | *Configure Lib |
*Configure Loud | VDU Drivers | *Configure Loud |
*Configure Mode | VDU Drivers | *Configure Mode |
*Configure MouseStep | VDU Drivers | *Configure MouseStep |
*Configure NoBoot | FileSwitch | *Configure NoBoot |
*Configure NoCaps | Character Input | *Configure NoCaps |
*Configure NoDir | FileCore | *Configure NoDir |
*Configure NoScroll | VDU Drivers | *Configure NoScroll |
*Configure Quiet | VDU Drivers | *Configure Quiet |
*Configure Repeat | Character Input | *Configure Repeat |
*Configure Scroll | VDU Drivers | *Configure Scroll |
*Configure ShCaps | Character Input | *Configure ShCaps |
*Configure SoundDefault | The Sound system | *Configure SoundDefault |
*Configure Truncate | FileSwitch | *Configure Truncate |
*Configure WimpAutoMenuDelay | The Window Manager | *Configure WimpAutoMenuDelay |
*Configure WimpDoubleClickDelay | The Window Manager | *Configure WimpDoubleClickDelay |
*Configure WimpDoubleClickMove | The Window Manager | *Configure WimpDoubleClickMove |
*Configure WimpDragDelay | The Window Manager | *Configure WimpDragDelay |
*Configure WimpDragMove | The Window Manager | *Configure WimpDragMove |
*Configure WimpFlags | The Window Manager | *Configure WimpFlags |
*Configure WimpMenuDragDelay | The Window Manager | *Configure WimpMenuDragDelay |
*Configure WimpMode | The Window Manager | *Configure WimpMode |
Hardware configuration | Chapter | Page |
*Configure Baud | Serial device | *Configure Baud |
*Configure Country | International module | *Configure Country |
*Configure Data | Serial device | *Configure Data |
*Configure Drive | ADFS | *Configure Drive |
*Configure DST | The Territory Manager | *Configure DST |
*Configure Floppies | ADFS | *Configure Floppies |
*Configure FS | NetFS | *Configure FS |
*Configure HardDiscs | ADFS | *Configure HardDiscs |
*Configure IDEDiscs | ADFS | *Configure HardDiscs |
*Configure Ignore | Character Output | *Configure Ignore |
*Configure MonitorType | VDU Drivers | *Configure MonitorType |
*Configure NoDST | The Territory Manager | *Configure NoDST |
*Configure Print | Character Output | *Configure Print |
*Configure PS | NetPrint | *Configure PS |
*Configure Step | ADFS | *Configure Step |
*Configure Sync | VDU Drivers | *Configure Sync |
*Configure Territory | The Territory Manager | *Configure Territory |
*Configure TimeZone | The Territory Manager | *Configure TimeZone |
*Configure TV | VDU Drivers | *Configure TV |
Memory allocation | Chapter | Page |
*Configure ADFSbuffers | ADFS | *Configure ADFSbuffers |
*Configure ADFSDirCache | ADFS | *Configure ADFSDirCache |
*Configure FontMax | The Font Manager | *Configure FontMax |
*Configure FontSize | The Font Manager | *Configure FontSize |
*Configure PrinterBufferSize | Memory Management | *Configure PrinterBufferSize |
*Configure RamFsSize | RamFS | *Configure RamFsSize |
*Configure RMASize | Memory Management | *Configure RMASize |
*Configure ScreenSize | VDU Drivers | *Configure ScreenSize |
*Configure SpriteSize | Sprites | *Configure SpriteSize |
*Configure SystemSize | Memory Management | *Configure SystemSize |
*Configure Baud 7
*Status
None
Sets the configured amount of memory reserved for printer buffering
mK | number of kilobytes of memory reserved |
n | number of pages of memory reserved; n 127 |
*Configure PrinterBufferSize sets the configured amount of memory reserved for printer buffering after the next hard reset.
If the parameter is 0, a default amount of memory is reserved.
*Configure PrinterBufferSize 32K
None
None
None
Sets the configured extra area of memory reserved for relocatable modules
mK | number of kilobytes of memory reserved |
n | number of pages of memory reserved; n 127 |
*Configure RMASize sets the configured extra area of memory reserved in the relocatable module area (RMA) after all modules have been initialised.
If the parameter is 0, no extra memory is reserved.
*Configure RMASize 128K
None
None
Sets the configured extra area of memory reserved for the system heap
mK | number of kilobytes of memory reserved |
n | number of pages of memory reserved; n 63 |
*Configure SystemSize sets the configured extra area of memory reserved for the system heap after all modules have been initialised.
If the parameter is 0, no extra memory is reserved.
*Configure SystemSize 32K
None
None
option | the name of a configuration option |
*Status displays the value of a configuration option in the CMOS RAM. If no option is specified, the values of all configuration options are shown.
Because the values of these configuration options are held in non-volatile memory (the battery-backed CMOS RAM) they are preserved even when the computer is switched off, until reset by using either the Configure application from the desktop or the *Configure command from the command line.
*Status TV
*Configure