GENERAL ======= RISC OS will either be running 26-bit, or 32-bit, with no in-between state. When running 32-bit, it will make no use of 26-bit modes, and will call all routines in a 32-bit mode. There will be no support for 26-bit code, as this would entail run-time selection of whether to call entry points in 26 or 32 bit mode, an added complication. When running 26-bit, it will make no more use of 32-bit modes than it does currently, and the same restrictions on 32-bit code will apply as now. Desktop systems will probably always be 26-bit. NCs may be 32-bit, as they have little or no requirement to run external software, but could just as well be 26-bit. Anything running on an ARM 9/10 etc will have to be 32-bit. Standard (non-Kernel) software should be modified to work whether it is called in a 26-bit or a 32-bit mode. For pure C applications and modules, this can just be a recompile; the compiled code will then run on both existing 26-bit systems, back to RISC OS 3.1, and 32-bit systems. A new Shared C Library will be required to support 32-bit programs on old systems. Assembler modules should also run on either 26 or 32-bit systems; however to achieve this use of MSR and MRS instructions will often be required to manipulate the PSR - if this cannot be avoided the module will become RISC OS 3.1 incompatible. In our build system we will hide most of the differences inside macros - use macros like SETPSR instead of using TEQP directly, and 26/32-bit forms will be selected on compile time by build switches. You will either have a module that uses TEQP that will work on ARM2-ARM8, or a module that uses MSR which will work on ARM6 onwards. This way we will continue to be able to test software on our desktop systems - it can be the same 32-bit binary - it will just run in a 26-bit mode. RISC OS is initially largely unmodified - almost all binary APIs will act the same in a 32-bit system as they do now, except that they will be called in a 32-bit version of the documented processor mode. One side-effect of this is that R14 on entry to routines will contain just the return address, with no flags. Hence to preserve flags, the CPSR must be stacked on entry, and restored on exit. This is cumbersome, but can be hidden inside EntryS and EXITS macros. Note that this behaviour is then slightly different - you are preserving flags across the call, not restoring the flags passed in in R14. Most of the time this doesn't matter, as the API is documented in terms of preserving flags. There are exceptions to this rule, notably SWI handling. On a 32-bit system, SWIs are no longer expected to preserve the N Z and C flags. They may still set/clear them to return results. 32-bit code should not assume that SWIs preserve flags. Requiring flag preservation would impose an unacceptable burden on SWI dispatch. This effectively respecifies *all* SWIs by changing the default rule in PRM 1-29. Also, it becomes impossible for SWIs outside the Kernel to depend on the NZCV flags on entry. SWIs inside the Kernel, such as OS_CallAVector, can still manipulate flags freely. This should not be an onerous restriction; it is impossible to specify entry flags for SWIs in C or BASIC, for example. Many existing APIs do not actually require flag preservation, such as service call entries. In this case, simply changing MOVS PC... to MOV PC... and LDM {}^ to LDM {} is sufficient to achieve 32-bit compatibility. NASTY HACKY BITS ================ To just set and clear NZCV flags you can use the SETV etc macros, which will do the right thing (TM) for the different processor types. To actually preserve flags, you will probably be forced to use MRS and MSR instructions. These are NOPs on pre-ARM 6 ARMs, so you may be able to do clever stuff to keep ARM2 compatibility. For example, the recommended general-purpose code to check whether you're in a 26-bit mode is: MOV R0, #0 ; for ARM 2+3 compatibility only MRS R0, CPSR ; NOP on 26-bit only ARMs TST R0, #2_11100 ; EQ if in a 26-bit mode, NE if 32-bit If you know you are in a privileged mode, then you can use: TEQ PC, PC ; EQ if in a 32-bit mode, NE if 26-bit Sometimes you may be forced to play with the SPSR registers. Beware: interrupt code will corrupt SPSR_svc if it calls a SWI. Existing interrupt handlers know to preserve R14_svc before calling a SWI, but not SPSR_svc. Hence you must disable interrupts around SPSR manipulations. MODULE ENTRIES ============== Most module entries are treated the same in the 32-bit world, except they will be entered in a 32-bit mode, and hence R14 will be a return address with no flags. Init,Final ---------- Unchanged. Flag preservation not required - only V on exit is looked at. Service ------- Unchanged. Flags on exit ignored. Help/command ------------ Unchanged. Flag preservation not required - only V on exit is looked at. SWI decoding code ----------------- Unchanged. Flag preservation not required - V on exit is looked at in number to text case. SWI handler ----------- On 26 bit systems, R14 is a return address (inside the Kernel) with the user's NZCIF flags in it, V clear, mode set to SVC. The CPSR NZCV flags on exit are then passed back to the SWI caller. Hence MOVS PC,R14 preserves the SWI caller's NZC flags and clears V. The NZ and C flags in the current PSR on entry are undefined, and are NOT the caller's (but V is clear). Thus you can simply read, modify and preserve the caller's flags. On 32 bit systems, R14 is a return address only. There is no way of determining the caller's flags, so you are not expected to preserve them. The NZC and V flags you exit with will be returned to the caller. If writing a new module, simply specify that all your SWIs corrupt flags, then your SWI dispatchers can return with MOV PC,R14, regardless of whether running on a 26 or 32 bit system. If converting an existing module to run on 32-bit, it is highly recommended that the same binary continue to work on 26-bit systems. You should therefore take steps to preserve flags when running in a 26-bit mode, if the module did before. When running on a 32-bit system, you needn't preserve flags. The following wrapper around the original SWI entry (converted to be 32-bit safe) achieves this, assuming you always want NZ preserved on a 26-bit system. Push R14 BL Original_SWI_Code Pull R14 TEQ PC,PC ; are we in a 32-bit mode? MOVEQ PC,R14 ; 32-bit exit: NZ corrupted, CV passed back [ PassBackC BICCC R14,R14,#C_bit ; Extra guff to pass back C as well ORRCS R14,R14,#C_bit ] MOVVCS PC,R14 ; 26-bit exit: NZC preserved, V clear ORRVSS PC,R14,#V_bit ; 26-bit exit: NZC preserved, V set Yes, this is cumbersome, but it can be removed when backwards compatibility is no longer desired. The alternative, which would be to pass in caller flags in R14, would impose a permanent carbuncle on the 32-bit API. Module flags ------------ This is a new module header entry at &30. It is an offset to the module flags word(s). The first module flag word looks like: Bit 0 Module is 32-bit compatible Bits 1-31 Reserved (0) Non 32-bit compatible modules will not be loaded by a 32-bit RISC OS. If no flags word is present, the module is assumed to be 26-bit compatible. ENVIRONMENT HANDLERS ==================== Undefined instruction handler ----------------------------- 32 bit system: Now called in UND32 mode. No preveneer. 26 bit: as before Prefetch abort, data abort -------------------------- 32 bit system: Now called in ABT32 mode. No preveneer. 26 bit: as before Error ----- 32 bit system: USR32 mode. PC contains no PSR flags. 26 bit: as before - PC contains PSR flags, but may not be reliable. BreakPoint ---------- 32 bit system: register block must be 17 words long. contains R0-R15,CPSR. entered in SVC32 mode 26 bit: as before Handlers can check format by looking at mode on entry to handler. The following code is suitable to restore the user registers and return in the 32-bit case: ADR R14, saveblock ; get address of saved registers LDR R0, [R14, #16*4] ; get user PSR MRS R1, CPSR ; get current PSR ORR R1, R1, #&80 ; disable interrupts to prevent MSR CPSR_c, R1 ; SPSR_SVC corruption by IRQ code (yuck) MSR SPSR_cxsf, R0 ; put it into SPSR_SVC LDMIA R14, {R0-R14}^ ; load user registers MOV R0, R0 ; no-op after forcing user mode LDR R14, [R14, #15*4] ; load user PC into R14_SVC MOVS PC, R14 ; return to correct address and mode Escape ------ 32 bit system: as before, but called in SVC32 Event ---- 32 bit system: as before, but in IRQ32 or SVC32 Exit ---- 32 bit system: as before, but in USR32 Unused SWI ---------- 26 bit system: called in SVC26 mode. R14 = a return address in the Kernel, with NZCVIF flags the same as the caller's (except V clear). PSR flags undefined (except I+F as caller) 32 bit system: called in SVC32 mode. R14 = return address in the Kernel No way to determine caller condition flags PSR flags undefined (except I+F as caller) UpCall ------ 32 bit system: as before, but SVC32 mode CallBack -------- 32 bit system: register block must be 17 words long. contains R0-R15,CPSR. entered in SVC32 mode, IRQs disabled 26 bit: as before Handlers can check format by looking at mode on entry to handler. The following code is suitable to restore the user registers and return in the 32-bit case: ADR R14, saveblock ; get address of saved registers LDR R0, [R14, #16*4] ; get user PSR MSR SPSR_cxsf, R0 ; put it into SPSR_SVC/IRQ LDMIA R14, {R0-R14}^ ; load user registers MOV R0, R0 ; no-op after forcing user mode LDR R14, [R14, #15*4] ; load user PC into R14_SVC/IRQ MOVS PC, R14 ; return to correct address and mode Exception registers ------------------- 32 bit system: block must be 17 words long. will contain R0-R15,PSR Exception handlers can determine block format by looking at mode on entry to handler. SOFTWARE VECTORS ================ Software vectors have a number of different properties. They can be called under a variety of conditions, and the flags they exit with may or may not be significant. When called using OS_CallAVector, the caller's NZCV flags always used to be passed in in R14, and the claimant's flags on exit would be passed back. In a 32-bit system, the caller's flags are not passed in R14. Their C and V flags are visible in the PSR though, just as in a 26-bit system. N and Z are not visible. Again, exit flags are passed back. Most vectors are not intended to be called with OS_CallAVector, and their exit flags have never had significance, for example KeyV, EventV and TickerV. Others are vectored SWIs, such as ByteV and ReadLineV. These pass back C and V flags only. A few vectors, like RemV, attach significance to entry flags. If not claiming, you mustn't change those flags for the next callee. In 26-bit mode this might have been achieved by: CMP R1,#mybuffer MOVNES PC,LR In the 32-bit world, you could change the CMP to a TEQ to preserve C and V, or you could use something like: Push R14 MRS R14, CPSR CMP R1, #maxbuffers BLS handleit MSR CPSR_f, R14 Pull PC handleit ... INSIDE THE KERNEL ================= The 32-bit Kernel will stay in 32-bit modes, and pass out to apps/modules in 32-bit modes. Hardware vectors will save R14+SPSR separately to allow return to any mode/address. The 26-bit Kernel will switch into 26-bit modes fairly early, but still save R14+SPSR separately to simplify the state of assembly switches. It will switch back to 32-bit mode to execute the return, and will munge fake 26-bit R14s when about to call environment handlers. When the Kernel dispatches an internal SWI, the stack currently looks like: SVCSTK-4 Caller's R12 -8 Caller's R11 -12 Caller's R10 -16 SWI number R11 is the SWI number with the X bit clear, R14 is the return address with caller's flags. This will be changed to look like: SVCSTK-4 Caller's R12 -8 Caller's R11 -12 Caller's R10 -16 Return R14 (32-bit - no flags) -20 SWI number R11 will still be the SWI number with the X bit clear, but R14 actually will be the caller's PSR. This minimises changes to the Kernel, as most routines only actually interpret R14 as holding the flags. For example, they might exit with: ORRVS lr, lr, #V_bit B SLVK Such code will not need altering between 26 and 32-bit versions. A similar change will be made to the structure of the stack during ErrorV: SVCSTK-4 Caller's R12 -8 Caller's R11 -12 Caller's R10 -16 Return R14 (26-bit - including flags) will become: SVCSTK-4 Caller's R12 -8 Caller's R11 -12 Caller's R10 -16 Return R14 (32-bit - no flags) -20 Return PSR (32-bit) MEMORY MAP ========== The "Shadow ROM" at FF800000-FFFFFFFF has been removed. This was originally intended to allow hardware vectors to branch "down" to the ROM, but this scheme was replaced by LDR PC,xxx hardware vectors. The only place that used it was the Kernel's start-up "Ctrl-or-R" keyboard interrupt handler. This has been modified, as it is technically unpredictable to branch around the ends of the address space. With abort handlers now being called in Abort mode, an Abort stack is required. This has been positioned at 02002000, in the area currently "reserved for fake screen" (VIDC1 compatibility). The stacks are now: Limit Base IRQ: 01F00000 01F01xxx SVC: 01C00000 01C02000 UND: 01E00000 01E02000 ABT: 02000000 02002000 All are defined to be on a 1MB boundary. The area beyond the limit is usually unmapped, to cause an abort. Their actual locations and sizes are subject to change. In particular, they may not be in the lower 64MB in future. MISCELLANEOUS SWIS ================== OS_EnterOS ---------- If called in a 26-bit mode, takes you into SVC26, else into SVC32.