If you were observant in my first article, you may have noticed that I said a pre-Risc PC podule has 4Kwords of address space.  So how, then, do podules exist which have hundreds of K of flash or EPROM on them?  Surely this won't fit?  This time we're going to look at how the Podule Manager supports paging to make this possible.

Paging

The basic principle behind paging is that we don't need to be able to access all of the ROM all at the same time.  A book would be unwieldy if we had it all on one large sheet of paper, and we don't really need to be able to see it all at once.  So for a small amount of extra effort (turning the pages) we can separate it into pages which all appear at the same place.  Each page contains a smaller amount of information and only one (or maybe two) page can be seen at once.

For a ROM, the principle is the same.  We have a window of address space, let's say 2Kwords, into which we can present our data and an external paging register which controls which set of data is presented in our window.  If you remember the BBC Micro, this used 'paged ROMs' in a similar manner - you could use BASIC, a wordprocessor or a spreadsheet ROM, but only one at a time.  The other ROMs weren't even accessible in the memory map at this point.

So how do we build the hardware to do this?  Well, figure 1 shows a 512Kbyte flash ROM attached to the podule bus.

This may look complicated but isn't too bad when you break it down.  If you compare it with the RAM circuit in article 2 you may notice a few differences.  Firstly the flash chip holds more data, so has more address lines.  These are driven from the 74HC273, the paging register.  The address decoding is arranged so that the bottom 2Kwords of podule space are filled by the flash chip, and the top 2Kwords by the paging register.  In fact the paging register only needs one 8-bit-wide memory location but the arrangement depicted saves address decoding logic.  If the podule is going to contain other hardware, it would coexist with the paging register in the upper 2Kwords.

For now, writing to the upper 2Kwords writes to the paging register (whose behaviour is similar to the latch we used to drive the LEDs in the first article).  This supplies the top 8 bits of the address to the flash.  So write 0 to the paging register, and the first 2Kbytes of flash appears at word addresses &0000 to &1FFC in our podule space (if this was podule 0 on a pre-Iyonix machine, this might appear in the memory map as &03340000 to &03341FFC).  Write 1 and the next 2Kbytes appears, and so on.  So we can access the whole of the flash in 2Kbyte chunks.  For any address in the flash we want to access, we take the top 8 bits and write them to the paging register, then use the remaining bits to work out an address in podule space to read from.

One other important thing to worry about is what our paging register holds on power up.  As we described last time, RISC OS expects to find information about the podule in its ROM during booting.  This might be stored in page zero of the podule ROM.  If the paging register is set to something other than zero we'll present the wrong page to RISC OS which means that RISC OS won't correctly identify the podule.  So the Master Reset of the paging register is driven by the podule bus reset, so on power on (and if someone presses the reset button) the paging register will be set to zero.

Loaders

Now the position of the paging register in the memory map, its size and so on are chosen by the podule designer.  But RISC OS needs a uniform way to be able to extract data from a podule without having to worry about the details of the register.  A small ARM code routine known as a loader performs this.

The loader is specified in the page of the podule ROM that is presented on booting, usually the first as we said above, as a chunk with the type RISC OS loader (see last time).  It contains a header with a series of offsets from the start of the loader to different routines - these are shown in figure 2.

The register conditions for the loader are detail in the PRM volume 4, but briefly they are:

R0 = byte to write/byte read from ROM
R1 = address to read/write
R2-R3,R10 may be corrupted
R4-R9,R12 must be preserved
R11 = combined hardware address for this podule
R13 = stack pointer, must be preserved
R14 = return address - to return do MOV pc,r14

Entry points at offsets 0 and 4 are used to read or write a single byte from the podule ROM.  The address supplied is the address in the ROM itself, so in the 512Kbyte ROM above it would be from 0 to 524287.  This address is referred to as 'code space'.

The entry point at offset 8 is a routine that is used to reset the paging register to its initial state - by writing zero in our example.  This is called when the machine is shut down, so clicking on the Desktop's Restart button to reboot (which does not reset the podule bus) will find the register in a state where the podule is correctly identified.

The CallLoader entry point is used by the SWI Podule_CallLoader which you can use to control additional functions in your loader code.  For example if the write entry point was used to write to a flash ROM, you might use the CallLoader entry to provide a write protect function by altering a flag visible to the write entry point.

The word at offset 16 is used to signify the loader is 26/32-bit addressing neutral for RISC OS 5 - set this word to something else to indicate a 26-bit only loader.  Note that it contains the letter O not the numeral 0.

Errors (such as out-of-bounds address, this ROM doesn't support write) are returned in the usual way.  If you are short of space setting r0 to zero will return a default error message (see the PRM for more details).

A simple loader for our example hardware can be seen below:

[insert file Loader here]

More on chunk directories

Now that we have a loader, we can access more than just the first 2Kbytes of our podule ROM.  The loader also provides a few other subtle features.

Remember that the loader was marked as 'RISC OS loader' in the chunk directory?  This allows other operating systems to have their own loaders, which can present a different view of the podule ROM than that seen by RISC OS.  Currently only RISC iX makes use of this, but it is a very powerful feature.

When RISC OS is scanning the chunks on a podule and comes across a loader, it loads it.  Once loaded it then uses the loader to access the rest of the podule ROM.  However, it also checks the code space address 0 for another chunk directory which it also scans.  So if we arrange for the loader to present code space in such a way that another chunk directory can be found, we can supply further code and data in a way that's invisible to other operating systems who haven't run our loader.

The easiest way is to add 1 to the page number as shown by the commented out instruction in the example code.  This means code address 0 is actually stored in page 1 of the ROM so RISC OS will look for another chunk directory starting at page 1.  If the RISC iX loader adds 2, it will look for a separate chunk directory starting at page 2.  Thus each OS is oblivious of the directories for the other.  As well as having different driver software, this means it's possible to store different data - for example an Ethernet card could read a different MAC address from ROM depending on the OS it was in.

Figure 3 shows this more clearly.  Here we can see RISC OS and RISC iX each having their own loader which presents a different view of the code space to each OS.  An OS has a separate chunk directory which is used to point it towards the software and data it requires, whilst ignoring other chunks.

Nowadays most people only use RISC OS, so only the RISC OS loader and additional chunk directory is necessary.  RISC OS only uses the podule ROM to load modules into RAM; they are not executed directly from the podule ROM.  So you can only use the podule ROM as a mean of presenting modules to the machine on startup - they use the same amount of memory when running as if they had been softloaded.  The only difference between a softloaded module and one loaded from a podule is that the podule-loaded module (!) has R11 set to the base of the podule when calling its initialisation code.  This way a module can determine which podule slot it was loaded from.

For an example of how the EcID, loader and chunk directory work together, try using the MkChunkDir program from last time to create a ROM image, then look at it in a hex editor.  To see the code space as presented by the loader for a podule in your machine (which as we've seen is not necessarily the same as the ROM image) try using *PoduleSave to save it to disc.

Next time we'll cover some of the Podule Manager, before returning to some more hardware.  Have fun with chunk directories in the meantime!
