32bit 15.1 KB
Newer Older
Kevin Bracey's avatar
Kevin Bracey committed
1 2 3
                                  GENERAL
                                  =======

4
RISC OS will either be running 26-bit, or 32-bit, with no in-between state.
Kevin Bracey's avatar
Kevin Bracey committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

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.

36
RISC OS is initially largely unmodified - almost all binary APIs will act the same
Kevin Bracey's avatar
Kevin Bracey committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
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.

73 74
For example, the recommended general-purpose code to check whether you're in
a 26-bit mode is:
Kevin Bracey's avatar
Kevin Bracey committed
75

76
        MOV     R0, #0          ; for ARM 2+3 compatibility only
Kevin Bracey's avatar
Kevin Bracey committed
77
        MRS     R0, CPSR        ; NOP on 26-bit only ARMs
78 79 80 81 82
        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
Kevin Bracey's avatar
Kevin Bracey committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136

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.

137 138 139 140 141
        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
Kevin Bracey's avatar
Kevin Bracey committed
142
      [ PassBackC
143 144
        BICCC   R14,R14,#C_bit          ; Extra guff to pass back C as well
        ORRCS   R14,R14,#C_bit
Kevin Bracey's avatar
Kevin Bracey committed
145
      ]
146 147
        MOVVCS  PC,R14                  ; 26-bit exit: NZC preserved, V clear
        ORRVSS  PC,R14,#V_bit           ; 26-bit exit: NZC preserved, V set
Kevin Bracey's avatar
Kevin Bracey committed
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286

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:

287 288
        CMP     R1,#mybuffer
        MOVNES  PC,LR
Kevin Bracey's avatar
Kevin Bracey committed
289 290 291 292

In the 32-bit world, you could change the CMP to a TEQ to preserve C and V, or
you could use something like:

293 294 295 296 297 298
        Push    R14
        MRS     R14, CPSR
        CMP     R1, #maxbuffers
        BLS     handleit
        MSR     CPSR_f, R14
        Pull    PC
Kevin Bracey's avatar
Kevin Bracey committed
299
handleit
300 301
        ...

Kevin Bracey's avatar
Kevin Bracey committed
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342

                     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.

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
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)

Kevin Bracey's avatar
Kevin Bracey committed
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384

                               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.

385

Kevin Bracey's avatar
Kevin Bracey committed
386 387 388 389 390 391 392
                           MISCELLANEOUS SWIS
                           ==================

OS_EnterOS
----------
If called in a 26-bit mode, takes you into SVC26, else into SVC32.