Index


RISC World

Modules for Beginners

Part 7: Summary and 32 bit issues - Brian Pickard

This part brings the series to a close. I will summarise all the features covered in the previous parts and introduce the changes required for compatible 32 bit coding.

Module Structure

The module has a header which is 48 bytes long. The structure of the header is as follows each section of the header is 4 bytes ( 1 word) long.

Notes:

  • For RISC OS 3.1 to 3.7 then the number of entries in the header can be reduced to a minimum of 7 i.e. up to *command table at offset &1C.
  • For 32 bit CPUs (XScale, ARM7 etc) with RiscOS 4 and 5 ALL the header must be present.
  • The header at &2C is an offset to the start of the full filepath string of the messages file for the module in the ResourceFS (if it has one). This does not seem to be used much in practice.
  • The header at &30 is an offset to a module flags word. The only bit used at the moment is bit 0 all other bits must be zero.

  • Bit0 is set if the module is 32 bit compatible. If bit0 is not set then your module is assumed to be 26 bit compatible and will not be loaded under RiscOS 5!

Remember that unused headers have a value of zero. What does this mean for the SWI chunk number if no SWI"s are required? We cannot put this as zero since the Operating system has SWI OS_WriteC which is SWI 0!

The Main Differences between 26 bit and 32bit code

All the following results from the change in CPU design from the program counter register having 26 bits devoted for memory adressing to the full 32 bits. This had to happen since 26 bits restricts the CPU to addressing a maximum of bytes of memory (without the use of memory paging as used in the early BBC Master computers).

Memory paging slows down a computer and the circuitry is needlessly complicated so using 32 bits for memory addressing is the most sensible way ahead. This change does mean the status register (the one that contains the VZ etc. flags) is a completely separate 32 bit register.

In the 26 bit case the flags used the remaining bits of the PC register.

Two extra commands are available to store and load the status register to and from registers:

     MRS Rx,CPSR   ;copy status register into Rx.
     MSR CPSR,Rx   ;load contents of Rx into status register.

It is beyond the scope of this article to delve into full 32 bit CPU architecture but I will just outline the dos and don"ts in the production of 26/32bit compatible code for modules.

The most common problem is the MOVS PC,R14 code used to return from subroutines. In 26bit R14 contained the return address and staus flags, but in 32 bit code it will only contain the return address. This means that

     MOVS PC,R14

is illegal in 32bit code but

     MOV PC,R14

is OK.

Ask yourself do I really need to restore the flags on return. The answer will probably be NO, so just change the MOVS command to MOV.

Another way of returning used in 26bit is the

     LDMFD R13!,{r0-rx ,R14}

this should still work in 32bit. However

     LDMFD R13!,{r0-rx ,R14}^

does not!

Writing 26/32bit compatible code.

How can we get round these problems? One way would be to write two versions of every module then at run time use RMEnsure commands to load the correct module for the machine. A better way would be to write code that would work on any machine. This is not as difficult as it might first seem. First we need a way of testing which architecture is being used.

Consider the following:

     TEQ PC,PC

What will the answer be? Will the equality flag be set or clear? Using PC register as operand one means only its memory address value bits are used. Using PC register as operand two means all 32 bits are used. The TEQ command does an EOR (exclusive OR). Under 26 bit architecture TEQ PC,PC cannot be zero but under 32bits it is always zero. The command always alters the status flags so conditional commands can be used after such a test.

In certain modes (in User mode) it is best to set the Z flag first by using TEQ R0,R0 so using.

     TEQ R0,R0
     TEQ PC,PC

will result in non equality in 26 bit mode and equality in 32 bit mode. The architecture can be tested in the modules Initialisation code thus:

     STMFD R13!,{r0-rx ,R14}
     TEQ R0,R0
     TEQ PC,PC
     MOVNE R0,#1
     MOVEQ R0,#0
     STR R0,archtecture%
     .
     .
     .
     .
     LDMFD R13!,{r0-rx ,PC}

This will store at the memory location labelled architecture% zero if in 32bit mode and one if in 26bit mode. The programmer can then test to see if this memory location is zero or not when ever the code has to be different in the 32 bit and 26 bit modes.

For Example

When branching to a subroutine that requires the status flags to be preserved at the start of the subroutine use.

     .subroutine%
     LDR Rx,architecture%
     TEQ Rx,#0
     MRSEQ Rx,CPSR  ;only if 32 bit code
     STMFD R13!,{r0-rx ,R14}

Then in the subroutines return code use:

     LDR R0,architecture%
     TEQ R0,#0
     LDMFD R13!,{r0-rx ,R14}
     MOVNES PC,R14  ;26 bit code returns here with status flags preserved
     MSR CPSR,Rx    ;32 bit code restores CPSR
     MOV PC,R14     ;32 bit code returns

Assembling MSR and MRS commands

Pre 32 bit RISC OS users cannot directly assemble the MSR and MRS commands since the BASIC assembler does not recognise them. To get round this there is a neat program by Darren Salt called ExtBasAsm which can be downloaded from his website (click on the sofware button top right).

This patches the BASIC assembler and the user can then include MSR and MRS together with other ARM architecture 3 commands (and floating point). Another useful utility is ARMalyser which is found at www.armclub.org.uk/free. This app will disassemble a modules code and report any non 32 bit friendly commands.

32 bit coding in SWI routines The easiest way round this is to state your SWI's corrupt all flags. You can then use the legal MOV PC , R14 or LDM R13!{r0-rx,PC} return commands. Do not use the ORRS PC style of command!

General Rules for 32 bit friendly code

Dont use any commands with the suffix S which use the PC register (MOVS PC,R14 ORRS PC.... etc.).

Dont use any STM or LDM with the ^ extension (LDMFD R13!,{r0-rx ,r14}^ etc.).

Replace both of these without the offending S or ^ if possible (usually the case since 32 bit routines seem less likely to require the Status flags to be preserved).

The Final Bit

All the above has been gleaned form various sources such as Castles website and Richard Murrays web pages on Assembler processing. Since I do not have a 32 bit machine I cannot verify the above code. I apologise in advance if any of the above is incorrect, perhaps someone will let me know!

Thats concludes this series on Modules for Beginners I hope the articles have given an insight into the use and structure of RISC OS modules.


Brian Pickard

 Index