This document describes the enhancements to RISC OS to support extension (or "5th column") ROMs.
Extension ROMs are ROMs fitted in addition to the main ROM set, which provide software modules which are automatically loaded by RISC OS on power-on.
The availability, size and number of extension ROM sockets depends on which type of RISC OS computer you are using.
In general, however, RISC OS recognises extension ROMs or ROM sets which are 8, 16 or 32 bits wide, provided the ROM adheres to the specification below.
32 bit wide extension ROM sets are directly executable in place, saving on user RAM. 8 or 16 bit wide sets have to be copied into RAM to execute.
Extension ROMs appear in the ROM area of the memory map, ie between &03400000 and &03FFFFFF. An extension ROM set must end on a 64K boundary or at the start of another extension ROM. This is normally not a problem as it is unlikely you would want to use a ROM smaller than a 27128 (16K), and the normal way of addressing this would mean that the ROM would be visible in 1 byte out of each word, ie within a 64K addressable area.
Extension ROMs have a header at the end of the ROM image which indicates the presence of a valid extension ROM. The header is at the end because RISC OS scans the ROM area downwards from the top.
At the end of each ROM set of size 'n' bytes must be a 16-byte header as follows:-
Byte address Contents
n-16 1-word size field containing n n-12 1-word checksum (bottom 32 bits of the sum of all words from addresses 0 to n-16 inclusive) n-8 2-word id "ExtnROM0" indicating a valid extension ROM, ie
n-8 &45 ; "E" n-7 &78 ; "x" n-6 &74 ; "t" n-5 &6E ; "n" n-4 &52 ; "R" n-3 &4F ; "O" n-2 &4D ; "M" n-1 &30 ; "0"
Note that the ROM header will not necessarily appear in the memory map in the last 16 bytes if the ROM set is 8 or 16 bits wide. In the 8-bit case, the header will appear in one of the four byte positions of the last 16 words, and in the 16-bit case, in one of the two half-word positions of the last 8 words. However, RISC OS copes with this.
Extension ROMs also have a header at the *start* of the ROM set, which is identical to the format of an expansion card's identity space. This is because the Podule manager module handles much of the extension ROM processing.
The format of the header at the start is as follows:-
Byte address Contents Meaning
0 &00 Extended expansion card identity, not requesting IRQ or FIQ 1 &03 bit 0 set => there is a chunk directory bit 1 set => interrupt status pointers defined (necessary because bit 0 is set) bits 2,3 = 0 => 8-bits wide (NB this should be set to 0 irrespective of the actual width of the ROM set) 2 &00 Reserved, must be zero 3 &87 Product type (lo-byte) 4 &00 Product type (hi-byte) See below 5 Manuf(lo) Manufacturer code (lo-byte) 6 Manuf(hi) Manufacturer code (hi-byte) See below 7 Country Country code See below 8 to 15 &00 Interrupt status pointers (extension ROMs do not generate interrupts!) 16 onwards Chunk directory - see below
Product type code: Note that &0087 has been allocated as a product type code for all extension ROMs.
Manufacturer code: All manufacturers of expansion cards and/or extension ROMs should have a code for manufacturer. If you have not already been allocated one, you should consult Acorn.
Country code: Every extension ROM should have a code for the country of origin. These match those used by the International module, except that the UK has a country code of 0 for expansion cards and extension ROMs. If you do not already know the correct country code for your country, you should consult Acorn.
The chunk directory in an extension ROM is identical to that in an expansion card - see the chapter "Expansion Cards: Technical Details" in the RISC OS Programmer's Reference Manual.
In extension ROMs which are directly executable (ie which are 32 bits wide), the word immediately preceding the start of each module must contain (size of module +4), ie an offset from itself to the first word after the module. It is recommended that all extension ROMs be created like this, irrespective of whether they are directly executable.
The Podule manager module is responsible for recognising extension ROMs, although it is the kernel which is responsible for loading modules contained in them.
The numbering scheme for expansion card slots has been extended to include extension ROMs. The numbers for extension ROMs are -2, -3, -4... (-1 is reserved for the main ROM, although the Podule manager itself does not accept -1 for any of its SWI calls).
All Podule manager SWIs which take an expansion card slot number as a parameter allow an extension ROM specifier instead.
The SWIs Podule_ReadID, Podule_ReadHeader, Podule_EnumerateChunks, Podule_ReadChunk operate as one would expect when presented with an extension ROM specifier.
The SWIs Podule_ReadBytes, Podule_WriteBytes, Podule_CallLoader will normally fail because extension ROMs have no code space or loader.
SWI Podule_RawRead will read successive bytes out of the extension ROM, taking the ROM width into account.
SWI Podule_RawWrite must not be used with an extension ROM specifier, as writing to the ROM area can reprogram the memory and video controllers.
SWI Podule_HardwareAddress returns the base address of the specified extension ROM, although this is not in general useful as the ROM width can vary.
SWI Podule_EnumerateChunksWithInfo
in: R0 = chunk number (zero to start)
R3 = expansion card slot number or extension ROM number
out: R0 = next chunk number (zero if final chunk enumerated)
R1 = size (in bytes) if R0<>0 on exit R2 = operating system identity byte if R0<>0 on exit R4 = pointer to a copy of the module name if the chunk is a relocatable module, else preserved R5 = pointer to a copy of the module's help string if the chunk is a relocatable module, else preserved R6 = address of module if the chunk is a directly executable relocatable module or 0 if the chunk is a non-directly-executable relocatable module else preserved
SWI Podule_HardwareAddresses
in: R3 = expansion card slot number or extension ROM number
out: R0 = raw hardware address
R1 = combined hardware address
For an expansion card, the "raw hardware address" is the base address of the expansion card, and the "combined hardware address" is the raw hardware address (in bits 12-25) combined with the base address of the expansion card's private CMOS RAM (in bits 0-11) (as returned by SWI Podule_HardwareAddress).
For an extension ROM, the two addresses are the same, and are the start address of the extension ROM (ie the address of the first byte of the ROM).
*Podules now displays the extension ROMs in the system as well as expansion cards.
OS_Module 17 (Add expansion card module) - This call now allows R3 to be either an expansion card slot number or an extension ROM number.
OS_Module 19 (Enumerate ROM modules) - This call now enumerates over all ROM sections, ie extension ROM modules as well as main ROM and expansion card modules. R2 on entry now specifies the ROM section number to start scanning from, with the order of enumeration as follows:-
-1 (main ROM), 0, 1, 2, 3 (expansion cards), -2, -3, -4,... (extension ROMs)
Edition 1 of the PRM is incorrect when it states that on exit R1 (the module number to scan from) is incremented and R2 (the expansion card number to scan from) is preserved.
In fact R1 returns the module number of the found module plus one, where modules are numbered from zero within each ROM section, and R2 returns the ROM section number of the found module, which may be in a different ROM section from the value passed in R2 on entry, if there are insufficient modules in the specified section.
The values returned in R1 and R2 are therefore set up for the next call to OS_Module 19.
The call returns the error "No more modules" (error number &107) if there are no more modules from the point specified in the ordering.
OS_Module 20 (Enumerate ROM modules with version)
This call is identical to OS_Module 19, except that on exit R6 holds a BCD (binary coded decimal) form of the module's version number, as derived from the module's help string. The top 16 bits of this value hold the integer part of the version number, and the bottom 16 bits hold the fractional part, eg if the version number of the module is "3.14" then the value returned would be &00031400.
The way in which the kernel initialises modules has been changed. If there is more than one version of the same module present in the ROM (which includes all ROM sections) then only the newest version of the module is initialised, where newest means the version with the highest version number. (If there are two copies of the same version, then directly executable versions (ie in main ROM or in a 32-bit wide extension ROM) are considered "newer". If they are equal in this respect, then the later one in scanning order is considered to be newer.)
The kernel first scans down the list of modules in the main ROM. For each module in this list, the kernel initialises the newest version of that module.
If an extension ROM contains a newer version of a module in the main ROM, then the newer version will be initialised at the point in the initialisation sequence where the main ROM version would have been initialised. This allows main ROM modules to be replaced without the problems associated with initialisation order.
The kernel then applies the same rule to all of the expansion cards in turn. In each case the newest version of the module is initialised, but with the hardware address (in R11) corresponding to that of the expansion card.
The kernel finally initialises any extension ROM modules that are the newest versions, but which have not already been initialised in lieu of a module in the main ROM or on an expansion card.
*ROMModules now displays the version number of each module, as well as the other information. Extension ROM modules are now included in the list. Note that extension ROMs are numbered 1, 2, 3... in this command - these correspond to ROM section numbers -2, -3, -4... respectively.
*Unplug can now unplug extension ROM modules, as well as modules in the main ROM or in expansion cards. The syntax is now
*Unplug [<moduletitle> [<ROM section number>]]
*Unplug with no parameters does the same as it used to, ie display any unplugged modules.
*Unplug with a module name but no ROM section number specified unplugs all versions of that module in the system, and kills off any active module of that name.
If a ROM section number is specified then only versions of that module in that ROM section are unplugged.
The action of *RMReInit has changed slightly. If the specified module is active, then the effect is as before, ie the module is killed and then re-initialised.
If the specified module is not active, but is in the ROM, then the unplug bit in CMOS RAM is cleared for all versions of the specified module, and then the newest version of the module is initialised.
*RMInsert <moduletitle> [<ROM section number>]
If no ROM section number is specified, then this command clears the unplug bit for all versions of the specified module, without reinitialising any of them.
If a ROM section number is specified, then this command clears the unplug bit for all versions of the specified module present in the given section, without reinitialising any of them.