ARM600 73.3 KB
Newer Older
Neil Turton's avatar
Neil Turton committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; > ARM600

        GBLL    DebugAborts
DebugAborts SETL {FALSE}

Jeffrey Lee's avatar
Jeffrey Lee committed
20 21 22
        GBLL    UseProcessTransfer
UseProcessTransfer SETL :LNOT: HiProcVecs ; Needs updating to cope with HiProcVecs (for proc. vector protection)

Neil Turton's avatar
Neil Turton committed
23 24 25 26 27 28

; MMU interface file - ARM600 version

; Created by TMD 15-Jul-92
; Comments updated by TMD 04-Aug-93

29 30 31
;24-01-96 MJS  now effectively codes for ARM 6 onwards (6,7,8,A, where A = StrongARM)
;              but ARM8 not properly supported (not needed for RO 3.70)
;07-10-96 MJS  proper support for ARM810 added
Neil Turton's avatar
Neil Turton committed
32 33


Neil Turton's avatar
Neil Turton committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
; Workspace needed for ARM600 work is as follows:
;
; * Level 2 page tables for a contiguous logical area starting at zero
;     This consists of:
;       a) a fixed size bit covering 0 to 192M (currently)
;       b) a variable size bit covering the free pool - 192M to 192M + (memsize rounded up to 4M)
;     Note that the 192M value is sufficient to cover all the fixed size areas at present.
;     As more areas switch to new world, this limit will come down and down, but free pool must always
;      start at the end of the fixed areas.
;     (Level 2 for areas outside this region are allocated dynamically afterwards)
;
; * Level 1 page table (16K, stored in the middle of L2PT, where the I/O + ROM would be if it wasn't section mapped)
;
; * Undefined32 mode stack (8K)
;
Kevin Bracey's avatar
Kevin Bracey committed
49 50
; * Abort32 mode stack (8K)
;
Neil Turton's avatar
Neil Turton committed
51 52 53 54 55 56 57 58 59 60 61 62 63
; * Soft CAM map (variable size = memsize/4K*8, rounded up to 4K)
;
; In order to make the memory models for MEMC1 and IOMD harmonious, the MEMC1 system is considered as a section of
; video RAM starting at &02000000 size 480K, and an area of "non-video RAM" starting at &02078000, size (totalRAM-480K)
; IOMD has 1 area of video RAM and up to 4 areas of non-video RAM.
;
; (Note: when OS is soft-loaded, a 2 Mbyte chunk of DRAM is removed from the RAM map, therefore the model allows for
;  1 area of video RAM and up to 5 areas of non-video RAM)
;
; The fixed system pages (which include those described above) start at the base of the first bank of non-video RAM
; (on IOMD we allow this to be in any of the 4 RAM sites, ie you don't have to have RAM in any particular SIMM site)
; Consequently the base of the fixed system pages is not known at assembly time, so has to be passed in a register
; to the generic code.
Neil Turton's avatar
Neil Turton committed
64 65 66 67
;
; amg 7/12/96 Renaissance, import changes below from Spinner tree, but this is fundamentally the
; 3.70 file.

68
; 17-Jun-96     BAR     Change speed settings for the second bank of ROM space.
Neil Turton's avatar
Neil Turton committed
69 70
; 09-Jul-96     BAR     Improve IOMD ID vsn code - two places.
;                       Change ROM Speed settings for 7500FE and non-7500FE parts.
71 72 73 74 75 76 77
; 25-Jul-96     BAR     Correct bug in video bandwidth code, wrong label used.
; 16-Aug-96     JRH     Programming of 2nd ROM bank (IOMD ROMCR1 register):
;                               reinstated ExtROMSupport code, added CanLiveOnROMCard code
;                       MemInitTable:
;                               If ExtROMSupport: added assertion that ImageSize <= 4096
;                               and maps 4MB of each ROM bank.
;                               Otherwise: always maps 8MB of ROM space independant of ImageSize
Neil Turton's avatar
Neil Turton committed
78 79


80
 [ :LNOT: HAL
Neil Turton's avatar
Neil Turton committed
81 82 83 84 85 86
; Fixed page allocation is as follows

        ^       0
DRAMOffset_CursorChunk  #       32*1024         ; ie on MEMC1 this is the last 32K of DAG-addressable memory
DRAMOffset_PageZero     #       32*1024         ; 32K at location zero
DRAMOffset_SystemHeap   #       32*1024         ; system heap/svc stack
Kevin Bracey's avatar
Kevin Bracey committed
87 88 89 90
 [ No26bitCode
DRAMOffset_AbortStack   #        8*1024
 ]
        AlignSpace      16*1024                 ; L1PT (and hence L2PT) must be 16K-aligned
Neil Turton's avatar
Neil Turton committed
91 92 93 94 95 96 97 98 99 100 101
DRAMOffset_L2PT         #       0               ; static L2PT (variable size, with embedded L1PT)
DRAMOffset_L1PT         *       DRAMOffset_L2PT + 48*1024

; Undefined stack memory (size 8K) starts immediately after end of L2PT (which is variable size)
; Soft CAM map (variable size) starts immediately after end of UndStack

StaticPagesSize         *       @

; Logical addresses are as follows


Neil Turton's avatar
Neil Turton committed
102
FixedAreasL2Size        *       96*1024        ; amount of L2 to cover fixed areas, excluding free pool
Neil Turton's avatar
Neil Turton committed
103 104 105

UndStackSoftCamChunk    *       &01E00000
UndStackSize            *       8*1024
Kevin Bracey's avatar
Kevin Bracey committed
106
CamEntriesForVicky      *       UndStackSoftCamChunk + UndStackSize
Neil Turton's avatar
Neil Turton committed
107

Neil Turton's avatar
Neil Turton committed
108 109 110 111 112

; - address for virtual area for StrongARM data cache cleaning (32k, for two 16k areas)
; - the two areas are used in strict rotation for each full clean, so that we can do a full
;   clean (and not flush) with interrupts on
; - the address must be aligned such that EOR with 16*1024 flipflops between the two addresses
Kevin Bracey's avatar
Kevin Bracey committed
113
ARMA_Cleaners_address  * &01F10000
114
 ] ; :LNOT: HAL
Neil Turton's avatar
Neil Turton committed
115 116


117 118
        KEEP

Neil Turton's avatar
Neil Turton committed
119 120 121 122
; **************** CAM manipulation utility routines ***********************************

; **************************************************************************************
;
123
;       BangCamUpdate - Update CAM, MMU for page move, coping with page currently mapped in
Neil Turton's avatar
Neil Turton committed
124
;
125 126
; mjs Oct 2000
; reworked to use generic ARM ops (vectored to appropriate routines during boot)
Neil Turton's avatar
Neil Turton committed
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
;
; First look in the CamEntries table to find the logical address L this physical page is
; currently allocated to. Then check in the Level 2 page tables to see if page L is currently
; at page R2. If it is, then map page L to be inaccessible, otherwise leave page L alone.
; Then map logical page R3 to physical page R2.
;
; in:   r2 = physical page number
;       r3 = logical address (2nd copy if doubly mapped area)
;       r9 = offset from 1st to 2nd copy of doubly mapped area (either source or dest, but not both)
;       r11 = PPL + CB bits
;
; out:  r0, r1, r4, r6 corrupted
;       r2, r3, r5, r7-r12 preserved
;
; NB Use of stack is allowed in this routine

BangCamUpdate ROUT
        TST     r11, #DynAreaFlags_DoublyMapped ; if moving page to doubly mapped area
        SUBNE   r3, r3, r9                      ; then CAM soft copy holds ptr to 1st copy

Jeffrey Lee's avatar
Jeffrey Lee committed
147
        LDR     r1, =ZeroPage
Neil Turton's avatar
Neil Turton committed
148 149 150
        LDR     r1, [r1, #CamEntriesPointer]
        ADD     r1, r1, r2, LSL #3              ; point at cam entry (logaddr, PPL)
        LDMIA   r1, {r0, r6}                    ; r0 = current logaddress, r6 = current PPL
151 152
        BIC     r4, r11, #PageFlags_Unsafe
        STMIA   r1, {r3, r4}                    ; store new address, PPL
Neil Turton's avatar
Neil Turton committed
153
        Push    "r0, r6"                        ; save old logical address, PPL
Jeffrey Lee's avatar
Jeffrey Lee committed
154
        LDR     r1, =ZeroPage+PhysRamTable      ; go through phys RAM table
Neil Turton's avatar
Neil Turton committed
155 156 157 158 159 160 161 162
        MOV     r6, r2                          ; make copy of r2 (since that must be preserved)
10
        LDMIA   r1!, {r0, r4}                   ; load next address, size
        SUBS    r6, r6, r4, LSR #12             ; subtract off that many pages
        BCS     %BT10                           ; if more than that, go onto next bank

        ADD     r6, r6, r4, LSR #12             ; put back the ones which were too many
        ADD     r0, r0, r6, LSL #12             ; move on address by the number of pages left
Robert Sprowson's avatar
Robert Sprowson committed
163
        LDR     r6, [sp]                        ; reload old logical address
Neil Turton's avatar
Neil Turton committed
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181

; now we have r6 = old logical address, r2 = physical page number, r0 = physical address

        TEQ     r6, r3                          ; TMD 19-Jan-94: if old logaddr = new logaddr, then
        BEQ     %FT20                           ; don't remove page from where it is, to avoid window
                                                ; where page is nowhere.
        LDR     r1, =L2PT
        ADD     r6, r1, r6, LSR #10             ; r6 -> L2PT entry for old log.addr
        MOV     r4, r6, LSR #12                 ; r4 = word offset into L2 for address r6
        LDR     r4, [r1, r4, LSL #2]            ; r4 = L2PT entry for L2PT entry for old log.addr
        TST     r4, #3                          ; if page not there
        BEQ     %FT20                           ; then no point in trying to remove it

        LDR     r4, [r6]                        ; r4 = L2PT entry for old log.addr
        MOV     r4, r4, LSR #12                 ; r4 = physical address for old log.addr
        TEQ     r4, r0, LSR #12                 ; if equal to physical address of page being moved
        BNE     %FT20                           ; if not there, then just put in new page

182
        AND     r4, r11, #PageFlags_Unsafe
Neil Turton's avatar
Neil Turton committed
183 184 185
        Push    "r0, r3, r11, r14"              ; save phys.addr, new log.addr, new PPL, lr
        ADD     r3, sp, #4*4
        LDMIA   r3, {r3, r11}                   ; reload old logical address, old PPL
186 187 188
        LDR     r0, =DuffEntry                  ; Nothing to do if wasn't mapped in
        ORR     r11, r11, r4
        TEQ     r3, r0
Neil Turton's avatar
Neil Turton committed
189
        MOV     r0, #0                          ; cause translation fault
190
        BLNE    BangL2PT                        ; map page out
Neil Turton's avatar
Neil Turton committed
191 192 193 194 195 196 197
        Pull    "r0, r3, r11, r14"
20
        ADD     sp, sp, #8                      ; junk old logical address, PPL
        B       BangCamAltEntry                 ; and branch into BangCam code

; **************************************************************************************
;
198
;       BangCam - Update CAM, MMU for page move, assuming page currently mapped out
Neil Turton's avatar
Neil Turton committed
199 200
;
; This routine maps a physical page to a given logical address
201
; It is assumed that the physical page is currently not mapped anywhere else
Neil Turton's avatar
Neil Turton committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
;
; in:   r2 = physical page number
;       r3 = logical address (2nd copy if doubly mapped)
;       r9 = offset from 1st to 2nd copy of doubly mapped area (either source or dest, but not both)
;       r11 = PPL
;
; out:  r0, r1, r4, r6 corrupted
;       r2, r3, r5, r7-r12 preserved
;
; NB Can't use stack - there might not be one!
;
; NB Also - the physical page number MUST be in range.

; This routine must work in 32-bit mode

BangCam ROUT
        TST     r11, #DynAreaFlags_DoublyMapped ; if area doubly mapped
        SUBNE   r3, r3, r9              ; then move ptr to 1st copy

Jeffrey Lee's avatar
Jeffrey Lee committed
221
        LDR     r1, =ZeroPage+PhysRamTable ; go through phys RAM table
Neil Turton's avatar
Neil Turton committed
222 223 224 225 226 227 228 229 230
        MOV     r6, r2                  ; make copy of r2 (since that must be preserved)
10
        LDMIA   r1!, {r0, r4}           ; load next address, size
        SUBS    r6, r6, r4, LSR #12     ; subtract off that many pages
        BCS     %BT10                   ; if more than that, go onto next bank

        ADD     r6, r6, r4, LSR #12     ; put back the ones which were too many
        ADD     r0, r0, r6, LSL #12     ; move on address by the number of pages left
BangCamAltEntry
231
        LDR     r4, =DuffEntry          ; check for requests to map a page to nowhere
Neil Turton's avatar
Neil Turton committed
232
        ADR     r1, PPLTrans
233 234
        TEQ     r4, r3                  ; don't actually map anything to nowhere
        MOVEQ   pc, lr
Neil Turton's avatar
Neil Turton committed
235 236
        AND     r4, r11, #3             ; first use PPL bits
        LDR     r1, [r1, r4, LSL #2]    ; get PPL bits and SmallPage indicator
237

Kevin Bracey's avatar
Kevin Bracey committed
238
 [ {FALSE}
Neil Turton's avatar
Neil Turton committed
239 240 241 242 243
        TST     r11, #DynAreaFlags_NotCacheable
        TSTEQ   r11, #PageFlags_TempUncacheableBits
        ORREQ   r1, r1, #L2_C           ; if cacheable (area bit CLEAR + temp count zero), then OR in C bit
        TST     r11, #DynAreaFlags_NotBufferable
        ORREQ   r1, r1, #L2_B           ; if bufferable (area bit CLEAR), then OR in B bit
244

Neil Turton's avatar
Neil Turton committed
245
        ORR     r0, r0, r1
Kevin Bracey's avatar
Kevin Bracey committed
246 247 248 249 250 251 252
 |
        ASSERT  DynAreaFlags_CPBits = 7 :SHL: 12
        ASSERT  DynAreaFlags_NotCacheable = 1 :SHL: 5
        ASSERT  DynAreaFlags_NotBufferable = 1 :SHL: 4

        ORR     r0, r0, r1

Jeffrey Lee's avatar
Jeffrey Lee committed
253
        LDR     r6, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
254 255 256 257 258 259 260 261 262
        LDR     r6, [r6, #MMU_PCBTrans]
        AND     r4, r11, #DynAreaFlags_CPBits
        AND     r1, r11, #DynAreaFlags_NotCacheable + DynAreaFlags_NotBufferable
        TST     r11, #PageFlags_TempUncacheableBits
        ORRNE   r1, r1, #DynAreaFlags_NotCacheable      ; if temp uncache, set NC bit, ignore P
        ORREQ   r1, r1, r4, LSR #6                      ; else use NC, NB and P bits
        LDRB    r1, [r6, r1, LSR #4]                    ; convert to X, C and B bits for this CPU
        ORR     r0, r0, r1
 ]
Neil Turton's avatar
Neil Turton committed
263 264 265

        LDR     r1, =L2PT               ; point to level 2 page tables

266 267
        ;fall through to BangL2PT

Neil Turton's avatar
Neil Turton committed
268 269 270 271 272 273 274
;internal entry point for updating L2PT entry
;
; entry: r0 = new L2PT value, r1 -> L2PT, r3 = logical address (4k aligned), r11 = PPL
;
; exit: r0,r1,r4,r6 corrupted
;
BangL2PT                                        ; internal entry point used only by BangCamUpdate
275 276 277
        Push    "lr"
        MOV     r6, r0

278 279 280
        TST     r11, #PageFlags_Unsafe
        BNE     %FT30

Neil Turton's avatar
Neil Turton committed
281 282 283
        TST     r11, #DynAreaFlags_DoublyMapped
        BNE     BangL2PT_sledgehammer           ;if doubly mapped, don't try to be clever

284 285 286 287 288
        ;we sort out cache coherency _before_ remapping, because some ARMs might insist on
        ;that order (write back cache doing write backs to logical addresses)
        ;we need to worry about cache only if mapping out a cacheable page
        ;
        TEQ     r6, #0                          ;EQ if mapping out
Kevin Bracey's avatar
Kevin Bracey committed
289
        TSTEQ   r11, #DynAreaFlags_NotCacheable ;EQ if also cacheable (overcautious for temp uncache+illegal PCB combos)
290 291
        MOV     r0, r3                          ;MMU page entry address
        ADR     lr, %FT20
Jeffrey Lee's avatar
Jeffrey Lee committed
292
        LDR     r4, =ZeroPage
293 294
        ARMop   MMU_ChangingEntry, EQ, tailcall, r4
        ARMop   MMU_ChangingUncachedEntry, NE, tailcall, r4
Neil Turton's avatar
Neil Turton committed
295

296 297 298
20      STR     r6, [r1, r3, LSR #10]           ;update L2PT entry

        Pull    "pc"
Neil Turton's avatar
Neil Turton committed
299 300

BangL2PT_sledgehammer
301 302 303 304 305

        ;sledgehammer is super cautious and does cache/TLB coherency on a global basis
        ;should only be used for awkward cases
        ;
        TEQ     r6, #0                          ;EQ if mapping out
Kevin Bracey's avatar
Kevin Bracey committed
306
        TSTEQ   r11, #DynAreaFlags_NotCacheable ;EQ if also cacheable (overcautious for temp uncache+illegal PCB combos)
307
        ADR     lr, %FT30
Jeffrey Lee's avatar
Jeffrey Lee committed
308
        LDR     r4, =ZeroPage
309 310 311 312
        ARMop   MMU_Changing, EQ, tailcall, r4
        ARMop   MMU_ChangingUncached, NE, tailcall, r4

30      STR     r6, [r1, r3, LSR #10]!          ; update level 2 page table (and update pointer so we can use bank-to-bank offset
Neil Turton's avatar
Neil Turton committed
313
        TST     r11, #DynAreaFlags_DoublyMapped ; if area doubly mapped
314 315
        STRNE   r6, [r1, r9, LSR #10]           ; then store entry for 2nd copy as well
        ADDNE   r3, r3, r9                      ; and point logical address back at 2nd copy
Neil Turton's avatar
Neil Turton committed
316

317
        Pull    "pc"
Neil Turton's avatar
Neil Turton committed
318

Neil Turton's avatar
Neil Turton committed
319

320 321 322 323 324 325
PPLTransL1
        &       (AP_Full * L1_APMult) + L1_Section        ; R any W any
        &       (AP_Read * L1_APMult) + L1_Section        ; R any W sup
        &       (AP_None * L1_APMult) + L1_Section        ; R sup W sup
        &       (AP_ROM  * L1_APMult) + L1_Section        ; R any W none

Neil Turton's avatar
Neil Turton committed
326 327 328 329
PPLTrans
        &       (AP_Full * L2_APMult) + L2_SmallPage      ; R any W any
        &       (AP_Read * L2_APMult) + L2_SmallPage      ; R any W sup
        &       (AP_None * L2_APMult) + L2_SmallPage      ; R sup W sup
330
        &       (AP_ROM  * L2_APMult) + L2_SmallPage      ; R any W none
Neil Turton's avatar
Neil Turton committed
331

Kevin Bracey's avatar
Kevin Bracey committed
332 333 334 335 336 337
PPLTransX
        &       (AP_Full * L2X_APMult) + L2_ExtPage       ; R any W any
        &       (AP_Read * L2X_APMult) + L2_ExtPage       ; R any W sup
        &       (AP_None * L2X_APMult) + L2_ExtPage       ; R sup W sup
        &       (AP_ROM  * L2X_APMult) + L2_ExtPage       ; R any W none

Neil Turton's avatar
Neil Turton committed
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
PageSizes
        &       4*1024                  ; 0 is 4K
        &       8*1024                  ; 4 is 8K
        &       16*1024                 ; 8 is 16
        &       32*1024                 ; C is 32

PageShifts
        =       12, 13, 0, 14           ; 1 2 3 4
        =       0,  0,  0, 15           ; 5 6 7 8

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_UpdateMEMC: Read/write MEMC1 control register

SSETMEMC ROUT

        AND     r10, r0, r1
Jeffrey Lee's avatar
Jeffrey Lee committed
354
        LDR     r12, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
355
        WritePSRc SVC_mode+I_bit+F_bit, r0
Neil Turton's avatar
Neil Turton committed
356 357 358 359 360 361 362 363
        LDR     r0, [r12, #MEMC_CR_SoftCopy] ; return old value
        BIC     r11, r0, r1
        ORR     r11, r11, R10
        BIC     r11, r11, #&FF000000
        BIC     r11, r11, #&00F00000
        ORR     r11, r11, #MEMCADR
        STR     r11, [r12, #MEMC_CR_SoftCopy]

364 365 366 367 368 369 370 371 372 373
; mjs Oct 2000 kernel/HAL split
;
; The kernel itself should now never call this SWI, but grudgingly has
; to maintain at least bit 10 of soft copy
;
; Here, we only mimic action of bit 10 to control video/cursor DMA (eg. for ADFS)
; The whole OS_UpdateMEMC thing would ideally be withdrawn as archaic, but
; unfortunately has not even been deprecated up to now

; for reference, the bits of the MEMC1 control register are:
Neil Turton's avatar
Neil Turton committed
374 375 376 377 378 379 380 381 382 383
;
; bits 0,1 => unused
; bits 2,3 => page size, irrelevant since always 4K
; bits 4,5 => low ROM access time (mostly irrelevant but set it up anyway)
; bits 6,7 => hi  ROM access time (definitely irrelevant but set it up anyway)
; bits 8,9 => DRAM refresh control
; bit 10   => Video/cursor DMA enable
; bit 11   => Sound DMA enable
; bit 12   => OS mode

Kevin Bracey's avatar
Kevin Bracey committed
384 385 386 387 388
        Push  "r0,r1,r4, r14"
        TST   r11, #(1 :SHL: 10)
        MOVEQ r0, #1             ; blank (video DMA disable)
        MOVNE r0, #0             ; unblank (video DMA enable)
        MOV   r1, #0             ; no funny business with DPMS
Jeffrey Lee's avatar
Jeffrey Lee committed
389 390 391 392
        ADD   r4, r12, #VduDriverWorkSpace
        LDR   r4, [r4, #CurrentGraphicsVDriver]
        MOV   r4, r4, LSL #24
        ORR   r4, r4, #GraphicsV_SetBlank
Kevin Bracey's avatar
Kevin Bracey committed
393 394
        BL    CallGraphicsV
        Pull  "r0,r1,r4, r14"
Neil Turton's avatar
Neil Turton committed
395

Kevin Bracey's avatar
Kevin Bracey committed
396
        WritePSRc SVC_mode+I_bit, r11
Neil Turton's avatar
Neil Turton committed
397 398 399 400 401 402
        ExitSWIHandler

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       SWI OS_MMUControl
;
Neil Turton's avatar
Neil Turton committed
403
; in:   r0 = 0 (reason code 0, for modify control register)
Neil Turton's avatar
Neil Turton committed
404 405 406 407 408 409 410
;       r1 = EOR mask
;       r2 = AND mask
;
;       new control = ((old control AND r2) EOR r1)
;
; out:  r1 = old value
;       r2 = new value
Neil Turton's avatar
Neil Turton committed
411 412 413 414 415
;
; in:   r0 bits 1 to 28 = 0, bit 0 = 1  (reason code 1, for flush request)
;          r0 bit 31 set if cache(s) to be flushed
;          r0 bit 30 set if TLB(s) to be flushed
;          r0 bit 29 set if flush of entry only (else whole flush)
Kevin Bracey's avatar
Kevin Bracey committed
416
;          r0 bit 28 set if write buffer to be flushed (implied by bit 31)
Neil Turton's avatar
Neil Turton committed
417 418 419
;       r1 = entry specifier, if r0 bit 29 set
;       (currently, flushing by entry is ignored, and just does full flush)
;
Neil Turton's avatar
Neil Turton committed
420 421

        ^       0
Neil Turton's avatar
Neil Turton committed
422 423
MMUCReason_ModifyControl        # 1    ; reason code 0
MMUCReason_Flush                # 1    ; reason code 1
Neil Turton's avatar
Neil Turton committed
424 425
MMUCReason_Unknown              # 0

426
MMUControlSWI   Entry
Neil Turton's avatar
Neil Turton committed
427 428 429 430 431 432
        BL      MMUControlSub
        PullEnv
        ORRVS   lr, lr, #V_bit
        ExitSWIHandler

MMUControlSub
Neil Turton's avatar
Neil Turton committed
433 434 435 436
        Push    lr
        AND     lr,r0,#&FF
        CMP     lr, #MMUCReason_Unknown
        ADDCC   pc, pc, lr, LSL #2
Neil Turton's avatar
Neil Turton committed
437 438
        B       MMUControl_Unknown
        B       MMUControl_ModifyControl
Neil Turton's avatar
Neil Turton committed
439
        B       MMUControl_Flush
Neil Turton's avatar
Neil Turton committed
440 441 442 443 444

MMUControl_Unknown
        ADRL    r0, ErrorBlock_HeapBadReason
 [ International
        BL      TranslateError
Robert Sprowson's avatar
Robert Sprowson committed
445
 |
Neil Turton's avatar
Neil Turton committed
446
        SETV
Robert Sprowson's avatar
Robert Sprowson committed
447 448
 ]
        Pull    "pc"
Neil Turton's avatar
Neil Turton committed
449

450

Neil Turton's avatar
Neil Turton committed
451 452 453 454 455
MMUControl_ModifyControl ROUT
        Push    "r3,r4,r5"
        CMP     r1,#0
        CMPEQ   r2,#&FFFFFFFF
        BEQ     MMUC_modcon_readonly
Jeffrey Lee's avatar
Jeffrey Lee committed
456
        LDR     r3,=ZeroPage
457 458 459 460
        LDRB    r5,[r3, #ProcessorArch]
        PHPSEI  r4                      ; disable IRQs while we modify soft copy (and possibly switch caches off/on)

        CMP     r5,#ARMv4
461
        LDRLO   lr, [r3, #MMUControlSoftCopy]
462
        ARM_read_control lr,HS
463 464
;        MOVHS   lr,lr,LSL #19
;        MOVHS   lr,lr,LSR #19           ; if ARMv4 or later, we can read control reg. - trust this more than soft copy
Neil Turton's avatar
Neil Turton committed
465 466 467
        AND     r2, r2, lr
        EOR     r2, r2, r1
        MOV     r1, lr
468 469 470
        LDR     r5, [r3, #ProcessorFlags]
        TST     r5, #CPUFlag_SplitCache
        BEQ     %FT05
471 472 473 474 475
 [ {FALSE}
        TST     r2,#MMUC_C              ; if split caches, then I bit mirrors C bit
        ORRNE   r2,r2,#MMUC_I
        BICEQ   r2,r2,#MMUC_I
 ]
Neil Turton's avatar
Neil Turton committed
476
05
Neil Turton's avatar
Neil Turton committed
477 478
        STR     r2, [r3, #MMUControlSoftCopy]
        BIC     lr, r2, r1              ; lr = bits going from 0->1
Neil Turton's avatar
Neil Turton committed
479
        TST     lr, #MMUC_C             ; if cache turning on then flush cache before we do it
480
        TSTEQ   lr, #MMUC_I
Neil Turton's avatar
Neil Turton committed
481
        BEQ     %FT10
482

483
        Push    "r0"
Jeffrey Lee's avatar
Jeffrey Lee committed
484
        ARMop   Cache_InvalidateAll,,,r3
485
        Pull    "r0"
Neil Turton's avatar
Neil Turton committed
486
10
487
        BIC     lr, r1, r2              ; lr = bits going from 1->0
488 489
        TST     lr, #MMUC_C             ; if cache turning off then clean data cache first
        BEQ     %FT15
490
        Push    "r0"
Jeffrey Lee's avatar
Jeffrey Lee committed
491
        ARMop   Cache_CleanAll,,,r3
492
        Pull    "r0"
Neil Turton's avatar
Neil Turton committed
493 494 495 496
15
        ARM_write_control r2
        BIC     lr, r1, r2              ; lr = bits going from 1->0
        TST     lr, #MMUC_C             ; if cache turning off then flush cache afterwards
497
        TSTNE   lr, #MMUC_I
Neil Turton's avatar
Neil Turton committed
498
        BEQ     %FT20
499
        Push    "r0"
Jeffrey Lee's avatar
Jeffrey Lee committed
500
        ARMop   Cache_InvalidateAll,,,r3
501
        Pull    "r0"
Neil Turton's avatar
Neil Turton committed
502
20
Kevin Bracey's avatar
Kevin Bracey committed
503
        PLP     r4                      ; restore IRQ state
Neil Turton's avatar
Neil Turton committed
504 505 506
        Pull    "r3,r4,r5,pc"

MMUC_modcon_readonly
Jeffrey Lee's avatar
Jeffrey Lee committed
507
        LDR     r3, =ZeroPage
508 509
        LDRB    r5, [r3, #ProcessorArch]
        CMP     r5, #ARMv4
510
        LDRLO   lr, [r3, #MMUControlSoftCopy]
511
        ARM_read_control lr,HS
512 513
;        MOVHS   lr,lr,LSL #19
;        MOVHS   lr,lr,LSR #19           ; if ARMv4 or later, we can read control reg. - trust this more than soft copy
514
        STRHS   lr, [r3, #MMUControlSoftCopy]
Neil Turton's avatar
Neil Turton committed
515 516 517 518 519
        MOV     r1, lr
        MOV     r2, lr
        Pull    "r3,r4,r5,pc"

MMUControl_Flush
Kevin Bracey's avatar
Kevin Bracey committed
520
       MOVS     r10, r0
Jeffrey Lee's avatar
Jeffrey Lee committed
521
       LDR      r12, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
522 523 524 525 526 527 528
       ARMop    Cache_CleanInvalidateAll,MI,,r12
       TST      r10,#&40000000
       ARMop    TLB_InvalidateAll,NE,,r12
       TST      r10,#&10000000
       ARMop    WriteBuffer_Drain,NE,,r12
       ADDS     r0,r10,#0
       Pull     "pc"
Neil Turton's avatar
Neil Turton committed
529 530 531 532 533

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       Exception veneers

Kevin Bracey's avatar
Kevin Bracey committed
534
 [ :LNOT:No26bitCode
Neil Turton's avatar
Neil Turton committed
535 536 537 538 539 540 541 542 543 544 545 546
; Undefined instruction trap pre-veneer
; in:   r13_undef -> a FD stack
;       r14_undef -> undefined instruction +4
;       psr_undef = PSR at time of undef'd instruction

UndPreVeneer    ROUT

        Push    "r0-r7,r14"             ; push r0-r7 on undef stack, and make room for return address
        MOV     r0, r13_undef

; for the time being just merge lr and psr

547
        MRS     r1, SPSR                                ; r1 = saved PSR
Neil Turton's avatar
Neil Turton committed
548 549 550 551 552
        AND     r2, r1, #&F0000003                      ; get saved NZCV and 26 bit modes
        ORR     lr_undef, lr_undef, r2
        AND     r2, r1, #I32_bit + F32_bit              ; extract I and F from new place
        ORR     r1, lr_undef, r2, LSL #IF32_26Shift     ; r1 = combined lr and psr

553
        MRS     r2, CPSR                ; now switch into SVC26
Neil Turton's avatar
Neil Turton committed
554 555
        BIC     r3, r2, #&1F
        ORR     r3, r3, #SVC26_mode
556 557
        MSR     SPSR_cxsf, r3           ; set SPSR_undef to be CPSR but with SVC26
        MSR     CPSR_c, r3              ; and select this mode now
Neil Turton's avatar
Neil Turton committed
558 559 560

        MOV     lr_svc, r1              ; lr_svc = PC + PSR from exception

561
        MSR     CPSR_c, r2              ; go back into undef mode
Neil Turton's avatar
Neil Turton committed
562 563 564 565 566

        LDR     r1, =UndHan             ; work out address of undefined instruction handler
        LDR     r1, [r1]
        STR     r1, [r0, #8*4]          ; and store it as return address
        Pull    "r0-r7, pc",,^          ; exit to handler, restoring sp_undef and entering SVC26 mode
Kevin Bracey's avatar
Kevin Bracey committed
567
 ]
Neil Turton's avatar
Neil Turton committed
568

569 570 571 572 573 574
 [ No26bitCode :LAND: ChocolateAMB
;  Instruction fetch abort pre-veneer, just to field possible lazy AMB aborts
;
PAbPreVeneer    ROUT
        Push    "r0-r7, lr"               ; wahey, we have an abort stack
        SUB     r0, lr_abort, #4          ; aborting address
575
        MOV     r2, #1
576 577 578 579
        BL      AMB_LazyFixUp             ; can trash r0-r7, returns NE status if claimed and fixed up
        Pull    "r0-r7, lr", NE           ; restore regs and
        SUBNES  pc, lr_abort, #4          ; restart aborting instruction if fixed up
        LDR     lr, [sp, #8*4]            ; (not a lazy abort) restore lr
Jeffrey Lee's avatar
Jeffrey Lee committed
580
        LDR     r0, =ZeroPage+PAbHan      ; we want to jump to PAb handler, in abort mode
581 582 583 584 585
        LDR     r0, [r0]
        STR     r0, [sp, #8*4]
        Pull    "r0-r7, pc"
 ]

Kevin Bracey's avatar
Kevin Bracey committed
586
 [ :LNOT:No26bitCode
Neil Turton's avatar
Neil Turton committed
587 588 589 590 591 592 593 594 595 596
; Instruction fetch abort pre-veneer

PAbPreVeneer    ROUT

        LDR     r13_abort, =PreVeneerRegDump
        STMIA   r13_abort, {r0-r7}
        MOV     r0, r13_abort

; for the time being just merge lr and psr

597
        MRS     r1, SPSR                                ; r1 = saved PSR
598 599 600 601 602

        LDR     r2, =Abort32_dumparea
        STMIA   r2, {r1,lr_abort}                       ;dump 32-bit PSR, fault address (PC)
        STR     lr_abort,[r2,#2*4]                      ;dump 32-bit PC

Neil Turton's avatar
Neil Turton committed
603 604 605 606 607
        AND     r2, r1, #&F0000003                      ; get saved NZCV and 26 bit modes
        ORR     lr_abort, lr_abort, r2
        AND     r2, r1, #I32_bit + F32_bit              ; extract I and F from new place
        ORR     r1, lr_abort, r2, LSL #IF32_26Shift     ; r1 = combined lr and psr

608
        MRS     r2, CPSR                ; now switch into SVC26
Neil Turton's avatar
Neil Turton committed
609 610
        BIC     r2, r2, #&1F
        ORR     r2, r2, #SVC26_mode
611
        MSR     CPSR_c, r2
Neil Turton's avatar
Neil Turton committed
612 613 614 615 616 617

        MOV     lr_svc, r1              ; lr_svc = PC + PSR from exception
        LDR     r1, =PAbHan
        LDR     r1, [r1]
        STR     r1, [r0, #8*4]
        LDMIA   r0, {r0-r7, pc}         ; jump to prefetch abort handler
Kevin Bracey's avatar
Kevin Bracey committed
618
 ]
Neil Turton's avatar
Neil Turton committed
619 620 621 622 623 624 625 626 627 628

; Preliminary layout of abort indirection nodes

        ^       0
AI_Link #       4
AI_Low  #       4
AI_High #       4
AI_WS   #       4
AI_Addr #       4

629 630
        EXPORT DAbPreVeneer

Neil Turton's avatar
Neil Turton committed
631 632
DAbPreVeneer    ROUT

Kevin Bracey's avatar
Kevin Bracey committed
633 634 635
 [ No26bitCode
        SUB     r13_abort, r13_abort, #17*4     ; we use stacks, dontcherknow
 |
Neil Turton's avatar
Neil Turton committed
636
        LDR     r13_abort, =PreVeneerRegDump
Kevin Bracey's avatar
Kevin Bracey committed
637
 ]
Neil Turton's avatar
Neil Turton committed
638 639 640
        STMIA   r13_abort, {r0-r7}              ; save unbanked registers anyway
        STR     lr_abort, [r13_abort, #15*4]    ; save old PC, ie instruction address

641 642
  [ ChocolateAMB
        ARM_read_FAR r0                         ; aborting address
643
        MOV     r2, #0
644 645 646 647 648 649 650
        BL      AMB_LazyFixUp                   ; can trash r0-r7, returns NE status if claimed and fixed up
        LDR     lr_abort, [r13_abort, #15*4]    ; restore lr_abort
        LDMIA   r13_abort, {r0-r7}              ; restore regs
        ADDNE   r13_abort, r13_abort, #17*4     ; if fixed up, restore r13_abort
        SUBNES  pc, lr_abort, #8                ; and restart aborting instruction
  ]

651 652
        MRS     r0, SPSR                        ; r0 = PSR when we aborted
        MRS     r1, CPSR                        ; r1 = CPSR
Neil Turton's avatar
Neil Turton committed
653 654
        ADD     r2, r13_abort, #8*4             ; r2 -> saved register bank for r8 onwards

Jeffrey Lee's avatar
Jeffrey Lee committed
655
        LDR     r4, =ZeroPage+Abort32_dumparea+3*4 ;use temp area (avoid overwriting main area for expected aborts)
656 657 658
        ARM_read_FAR r3
        STMIA   r4, {r0,r3,lr_abort}            ; dump 32-bit PSR, fault address, 32-bit PC

Neil Turton's avatar
Neil Turton committed
659 660 661 662
        MOV     r4, lr_abort                    ; move address of aborting instruction into an unbanked register
        BIC     r1, r1, #&1F                    ; knock out current mode bits
        ANDS    r3, r0, #&1F                    ; extract old mode bits (and test for USR26_mode (=0))
        TEQNE   r3, #USR32_mode                 ; if usr26 or usr32 then use ^ to store registers
663 664 665 666 667
  [ SASTMhatbroken
        STMEQIA r2!,{r8-r12}
        STMEQIA r2 ,{r13,r14}^
        SUBEQ   r2, r2, #5*4
  |
Neil Turton's avatar
Neil Turton committed
668
        STMEQIA r2, {r8-r14}^
669
  ]
Neil Turton's avatar
Neil Turton committed
670 671 672
        BEQ     %FT05

        ORR     r3, r3, r1                      ; and put in user's
673
        MSR     CPSR_c, r3                      ; switch to user's mode
Neil Turton's avatar
Neil Turton committed
674 675 676

        STMIA   r2, {r8-r14}                    ; save the banked registers

677
        MRS     r5, SPSR                        ; get the SPSR for the aborter's mode
Neil Turton's avatar
Neil Turton committed
678 679
        STR     r5, [r2, #8*4]                  ; and store away in the spare slot on the end
                                                ; (this is needed for LDM with PC and ^)
Kevin Bracey's avatar
Kevin Bracey committed
680 681
  [ No26bitCode
        ORR     r1, r1, #ABT32_mode
682
        MSR     CPSR_c, r1                      ; back to abort mode for the rest of this
Neil Turton's avatar
Neil Turton committed
683
05
Kevin Bracey's avatar
Kevin Bracey committed
684 685 686 687
        Push    "r0"                            ; save SPSR_abort
  |
05
        ORR     r1, r1, #SVC26_mode             ; then switch to SVC for the rest of this
688
        MSR     CPSR_c, r1
Neil Turton's avatar
Neil Turton committed
689
        Push    "r0, lr_svc"                    ; save SPSR_abort and lr_svc
Kevin Bracey's avatar
Kevin Bracey committed
690 691
  ]

692
  [ SASTMhatbroken
Kevin Bracey's avatar
Kevin Bracey committed
693 694
        SUB     sp, sp, #3*4
        STMIA   sp, {r13,r14}^                  ; save USR bank in case STM ^, and also so we can corrupt them
695
        NOP
Kevin Bracey's avatar
Kevin Bracey committed
696
        STMDB   sp!, {r8-r12}
697
  |
Kevin Bracey's avatar
Kevin Bracey committed
698 699
        SUB     sp, sp, #8*4                    ; make room for r8_usr to r14_usr and PC
        STMIA   sp, {r8-r15}^                   ; save USR bank in case STM ^, and also so we can corrupt them
700
  ]
Neil Turton's avatar
Neil Turton committed
701 702

        SUB     r11, r2, #8*4                   ; r11 -> register bank
Kevin Bracey's avatar
Kevin Bracey committed
703
        STR     r4, [sp, #7*4]                  ; store aborter's PC in user register bank
Neil Turton's avatar
Neil Turton committed
704

Jeffrey Lee's avatar
Jeffrey Lee committed
705
 [ UseProcessTransfer
Kevin Bracey's avatar
Kevin Bracey committed
706 707 708
        TST     r0, #T32_bit                    ; were they in Thumb mode? if so, give up now
        BNE     %FT90

709 710 711
;ARMv4+ allow half-word load/stores - not supported at present
;ARMv5TE+ allow double-word load/stores - not supported at present
;ARMv6 allow load/store exclusive - not supported at present
Neil Turton's avatar
Neil Turton committed
712
        LDR     r10, [r4, #-8]!                 ; r10 = actual instruction that aborted, and r4 points to it
713 714
        AND     r9, r10, #2_1110 :SHL: 24
        TEQ     r9, #2_1000 :SHL: 24            ; test for LDM/STM
Neil Turton's avatar
Neil Turton committed
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
        BNE     %FT50                           ; if not LDM/STM, then it's an "easy" LDR/STR

 [ DebugAborts
        DLINE   "It's an LDM/STM"
 ]

; First count the number of transferred registers, and undo any writeback

        MOV     r9, #0                          ; r9 = no. of registers in list
        MOVS    r8, r10, LSL #16
        BEQ     %FT20
10
        MOVS    r8, r8, LSL #1
        ADDCS   r9, r9, #1
        BNE     %BT10
20
        MOV     r8, r10, LSR #16
        AND     r8, r8, #&0F                    ; base register number
        LDR     r7, [r11, r8, LSL #2]           ; ------""----- value

        TST     r10, #1 :SHL: 23                ; test up/down
Neil Turton's avatar
Neil Turton committed
736 737 738 739 740
        MOVNE   r1, r9                          ; if up, r1 = +ve no. of regs
        RSBEQ   r1, r9, #0                      ; if down, r1 = -ve no. of regs

;initially assume writeback
;we want r6 = base reg value before assumed writeback (r7 is base reg value after abort)
741 742
;writeback will have been performed for ARMs with CPUFlag_BaseRestored clear
;
Jeffrey Lee's avatar
Jeffrey Lee committed
743
        LDR     r6, =ZeroPage
744 745 746 747
        LDR     r6, [r6, #ProcessorFlags]
        TST     r6, #CPUFlag_BaseRestored
        MOVNE   r6, r7
        SUBEQ   r6, r7, r1, ASL #2
Neil Turton's avatar
Neil Turton committed
748 749 750

;now we want r6 to be the base register value before the abort, so we will discard
;our adjusted value and take r7, if the instruction in fact had no writeback
751
;
Neil Turton's avatar
Neil Turton committed
752 753
        TST     r10, #1 :SHL: 21                ; test if write-back bit set
        TEQNE   r8, #15                         ; (if base is PC then write-back not allowed)
Neil Turton's avatar
Neil Turton committed
754
        MOVEQ   r6, r7                          ; if not wb, reg after abort is correct
Neil Turton's avatar
Neil Turton committed
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803

        MOV     r1, sp                          ; r1 -> end of stack frame, and start of user-mode register bank
        SUB     sp, sp, r9, LSL #2              ; make stack frame for registers
        TST     r10, #1 :SHL: 20                ; if its an STM, we have to load up the stack frame
        BNE     %FT30                           ; but if it's an LDM, we call trap routine first

        STR     r6, [r11, r8, LSL #2]           ; store original base in register list, to be overwritten after 1st transfer

; now go through registers, storing them into frame

        MOV     r5, sp                          ; pointer to position in stack frame
        MOV     lr, r10, LSL #16                ; extract bottom 16 bits
        MOVS    lr, lr, LSR #16                 ; ie bitmask of which registers r0-r15 stored
        BEQ     %FT30                           ; this shouldn't happen (it's illegal)

        MOV     r3, r11                         ; current pointer into register bank
21
        TST     r10, #1 :SHL: 22                ; is it STM with ^
        ANDNE   lr, lr, #&FF                    ; if so then extract bottom 8 bits (r0-r7 on 1st pass, r8-r15 on 2nd)
22
        MOVS    lr, lr, LSR #1                  ; shift bit into carry
        LDRCS   r2, [r3], #4                    ; if set bit then transfer word from register bank
        STRCS   r2, [r5], #4                    ; into stack frame
        STRCS   r7, [r11, r8, LSL #2]           ; and after 1st transfer, store updated base into register bank
        ADDCC   r3, r3, #4                      ; else just increment register bank pointer
        BNE     %BT22                           ; if more bits to do, then loop

        TEQ     r5, r1                          ; have we done all registers?
        MOVNE   lr, r10, LSR #8                 ; no, then must have been doing STM with ^, and have some user-bank regs to store
        MOVNE   r3, r1                          ; so point r3 at user-mode register bank
        BNE     %BT21                           ; and go back into loop

30

; now work out address of 1st transfer

        ANDS    r5, r10, #(3 :SHL: 23)          ; bit 24 set => pre, bit 23 set => inc
        SUBEQ   r2, r6, r9, LSL #2              ; if post-dec, then 1st address = initial-nregs*4+4
        ADDEQ   r2, r2, #4
        BEQ     %FT32

        CMP     r5, #2 :SHL: 23
        MOVCC   r2, r6                          ; CC => post-inc, so 1st address = initial
        SUBEQ   r2, r6, r9, LSL #2              ; EQ => pre-dec,  so 1st address = initial-nregs*4
        ADDHI   r2, r6, #4                      ; HI => pre-inc,  so 1st address = initial+4
32
        ANDS    r0, r10, #1 :SHL: 20            ; r0 = 0 => STM
        MOVNE   r0, #1                          ;    = 1 => LDM
        LDR     r1, [r1, #8*4]                  ; get SPSR_abort
804
        TST     r1, #&F                         ; test if transfer took place in USR mode
Neil Turton's avatar
Neil Turton committed
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
        ORRNE   r0, r0, #2                      ; if not then set bit 1 of flags word in r0
        MOV     r1, sp                          ; block to transfer from/into
        BIC     r2, r2, #3                      ; LDM/STM always present word-aligned address
        MOV     r3, r9, LSL #2                  ; length of transfer in bytes, and r4 still points to aborting instruction
        BL      ProcessTransfer
        ADDVS   sp, sp, r9, LSL #2              ; if invalid transfer then junk stack frame
        BVS     %FT90                           ; and generate an exception

; we transferred successfully, so now check if LDM and load up register bank from block

        TST     r10, #1 :SHL: 20
        ADDEQ   sp, sp, r9, LSL #2              ; it's an STM, so junk stack frame and tidy up
        BEQ     %FT70

; now go through registers, loading them from frame

        ADD     r1, sp, r9, LSL #2              ; r1 -> end of stack frame, and start of user-mode bank registers
        MOV     r5, sp                          ; pointer to position in stack frame
        MOV     r4, r10, LSL #16                ; extract bottom 16 bits
        MOVS    r4, r4, LSR #16                 ; ie bitmask of which registers r0-r15 stored
        BEQ     %FT40                           ; this shouldn't happen (it's illegal)

        SUB     r3, r1, #8*4                    ; r3 -> notional start of user bank, if it began at r0 (it actually starts at r8)
        MOV     r0, #0                          ; assume no user registers by default
        TST     r10, #1 :SHL: 15                ; is PC in list
        BNE     %FT34                           ; then can't be LDM of user bank
        TST     r10, #1 :SHL: 22                ; is it LDM with ^
        BEQ     %FT34                           ; no, then use main bank for all registers
        LDR     r2, [r1, #8*4]                  ; get SPSR
Kevin Bracey's avatar
Kevin Bracey committed
834
        ANDS    r2, r2, #15                     ; get bottom 4 bits of mode (EQ => USR26 or USR32)
Neil Turton's avatar
Neil Turton committed
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
        BEQ     %FT34                           ; if USR mode then use main bank for all
        TEQ     r2, #FIQ26_mode                 ; if FIQ mode then put r8-r14 in user bank
        LDREQ   lr, =&7F00                      ; then put r8-r14 in user bank
        LDRNE   lr, =&6000                      ; else put r13,r14 in user bank
        AND     r0, r4, lr                      ; r0 = mask of registers to put into user bank
        BIC     r4, r4, lr                      ; r4 = mask of registers to put into main bank
        MOV     lr, #0
34
        MOVS    r4, r4, LSR #1                  ; shift bit into carry
        LDRCS   r2, [r5], #4                    ; if set bit then transfer word from stack frame
        STRCS   r2, [r11, lr, LSL #2]           ; into main register bank
        MOVS    r0, r0, LSR #1                  ; shift bit into carry
        LDRCS   r2, [r5], #4                    ; if set bit then transfer word from stack frame
        STRCS   r2, [r3, lr, LSL #2]            ; into user register bank
        ADD     lr, lr, #1
        ORRS    r6, r0, r4                      ; have we finished both banks?
        BNE     %BT34                           ; no, then loop

; If LDM with PC in list, then add 4 to it, so the exit procedure is the same as if PC not loaded
; Also, if it was an LDM with PC and ^, then we have to update the stacked SPSR

40
        MOV     sp, r1                          ; junk frame

        TST     r10, #1 :SHL: 15                ; check PC in list
        ADDNE   r2, r2, #4                      ; since PC is last, r2 will still hold the value loaded
        STRNE   r2, [r11, #15*4]                ; store back into main register bank
        TSTNE   r10, #1 :SHL: 22                ; now check LDM ^
        BEQ     %FT70                           ; [not LDM with PC in list]

        LDR     r9, [sp, #8*4]                  ; get SPSR_abort
        AND     r8, r9, #&1F                    ; r8 = aborter's mode
        TEQ     r8, #USR32_mode                 ; if in USR32
        BEQ     %FT70                           ; then the ^ has no effect (actually uses CPSR)
Kevin Bracey's avatar
Kevin Bracey committed
869
        TST     r8, #&1C                        ; if 32-bit mode
Neil Turton's avatar
Neil Turton committed
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
        LDRNE   r7, [r11, #16*4]                ; then use SPSR for the aborter's mode else use updated r15 in r2 (26-bit format)
        ANDEQ   r7, r2, #&F0000003              ; flag and mode bits in same place
        ANDEQ   r2, r2, #&0C000000              ; but I and F have to move to bits 7 and 6
        ORREQ   r7, r7, r2, LSR #(26-6)

; r7 is now desired PSR (in 32-bit format) to update to
; now check which bits can actually be updated

        TEQ     r8, #USR26_mode
        BICEQ   r9, r9, #&F0000000              ; if USR26 then we can only update NZCV
        ANDEQ   r7, r7, #&F0000000
        ORREQ   r9, r9, r7
        MOVNE   r9, r7                          ; else can update all bits
        STR     r9, [sp, #8*4]                  ; store back updated SPSR_abort (to become CPSR)
        B       %FT70                           ; now tidy up

50

888
; it's an LDR/STR
Neil Turton's avatar
Neil Turton committed
889

890 891
        TEQ     r9, #2_0000 :SHL: 24            ; is it the extra load/store family?
        BNE     %FT55                           ; no, plain LDR[B]
Neil Turton's avatar
Neil Turton committed
892
 [ DebugAborts
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916
        DLINE   "It's LDR[EX|SB|H|SH|D]/STR[EX|H|D]"
 ]
        AND     r9, r10, #2_1111 :SHL: 4
        TEQ     r9, #2_1101 :SHL: 4
        BNE     %FT90                           ; Abort if LDR[EX|H|SH]/STR[EX|H|D]
        TST     r10, #1 :SHL: 20
        BEQ     %FT90                           ; Abort if LDRD (encoded where STRSB would be)

        TST     r10, #1 :SHL: 22                ; if immediate
        BICNE   r9, r10, 2_1111 :SHL: 4
        ORRNE   r9, r9, r9, LSR #4
        ANDNE   r9, r9, #&FF                    ; then extract imm8 bits
        ANDEQ   r8, r10, #&0F                   ; register offset
        LDREQ   r9, [r11, r8, LSL #2]           ; get actual value of register
        ORR     r10, r10, #1 :SHL: 22           ; ensure it looks like a byte access
        B       %FT60
        ; We've effectively reencoded the weird load/stores to look like
        ; cccc 0zxp ubwl nnnn tttt xxxx xxxx xxxx
        ; z = zero/sign extend     b = byte/word
        ; p = pre/post             l = load/store
        ; u = up/down              x = don't care from here on
55
 [ DebugAborts
        DLINE   "It's an LDR[B]/STR[B]"
Neil Turton's avatar
Neil Turton committed
917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
 ]
        TST     r10, #1 :SHL: 25                ; if immediate
        MOVEQ   r9, r10, LSL #(31-11)           ; then extract bottom 12 bits
        MOVEQ   r9, r9, LSR #(31-11)
        BEQ     %FT60

        AND     r8, r10, #&0F                   ; register to shift
        LDR     r9, [r11, r8, LSL #2]           ; get actual value of register

        MOV     r8, r10, LSR #7                 ; extract shift amount
        ANDS    r8, r8, #&1F                    ; (bits 7..11)
        MOVEQ   r8, #32                         ; if zero then make 32

        ANDS    r7, r10, #&60
        ANDEQ   r8, r8, #&1F                    ; LSL 0 is really zero
        MOVEQ   r9, r9, LSL r8
        TEQ     r7, #&20
        MOVEQ   r9, r9, LSR r8
        TEQ     r7, #&40
        MOVEQ   r9, r9, ASR r8
        TEQ     r7, #&60
        MOVEQ   r9, r9, ROR r8                  ; if 32 then we haven't spoilt it!
        TEQEQ   r8, #32                         ; if ROR #32 then really RRX
        BNE     %FT60
        LDR     r7, [sp, #8*4]                  ; get SPSR
        AND     r7, r7, #C_bit
        CMP     r7, #1                          ; set carry from original user
        MOV     r9, r9, RRX
60
        TST     r10, #1 :SHL: 23                ; test for up/down
        RSBEQ   r9, r9, #0                      ; if down then negate

Jeffrey Lee's avatar
Jeffrey Lee committed
949
        LDR     r8, =ZeroPage
950 951 952 953
        LDR     r8, [r8, #ProcessorFlags]
        TST     r8, #CPUFlag_BaseRestored
        BNE     %FT62
;not base restored
Neil Turton's avatar
Neil Turton committed
954 955 956 957 958 959 960 961 962
        TST     r10, #1 :SHL: 21                ; if write-back
        MOVNE   r8, #0                          ; then no post-inc
        RSBEQ   r8, r9, #0                      ; else post-inc = - pre-inc
        ADD     r0, r8, r9                      ; amount to subtract off base register for correction

        TST     r10, #1 :SHL: 24                ; however, if we're doing post-increment
        MOVEQ   r8, r9                          ; then post-inc = what was pre-inc
        MOVEQ   r0, r9                          ; and adjustment is what was added on
        RSB     r9, r8, #0                      ; and pre-inc = -post-inc
Neil Turton's avatar
Neil Turton committed
963 964
        B       %FT63
62
965
;base restored
Neil Turton's avatar
Neil Turton committed
966 967 968 969 970 971 972 973
        TST     r10, #1 :SHL: 21                ; if write-back
        MOVNE   r8, #0                          ; then no post-inc
        RSBEQ   r8, r9, #0                      ; else post-inc = - pre-inc

        TST     r10, #1 :SHL: 24                ; however, if we're doing post-increment
        MOVEQ   r8, r9                          ; then post-inc = what was pre-inc
        MOVEQ   r9, #0                          ; and pre-inc = 0

Neil Turton's avatar
Neil Turton committed
974
63
Neil Turton's avatar
Neil Turton committed
975 976 977 978
        MOV     r7, r10, LSL #31-19
        MOV     r7, r7, LSR #28                 ; r7 = base register number
        LDR     r6, [r11, r7, LSL #2]           ; r6 = base register value

Jeffrey Lee's avatar
Jeffrey Lee committed
979
        LDR     r1, =ZeroPage
980 981 982 983
        LDR     r1, [r1, #ProcessorFlags]
        TST     r1, #CPUFlag_BaseRestored
        SUBEQ   r0, r6, r0                      ; compute adjusted base register (if not base restored)
        STREQ   r0, [r11, r7, LSL #2]           ; and store back in case we decide to abort after all
Neil Turton's avatar
Neil Turton committed
984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008

; no need to clear PSR bits out of R15, because PSR is separate

        ADD     r9, r9, r6                      ; r2 = offset+base = illegal address

 [ DebugAborts
        DREG    r9, "Aborting address = "
        DREG    r8, "Post-increment = "
        DREG    r4, "Instruction where abort happened = "
 ]

        ANDS    r0, r10, #1 :SHL: 20            ; if an LDR then bit 20 set
        MOVNE   r0, #1                          ; so make 1
        SUBNE   sp, sp, #4                      ; then just create 1 word stack frame
        BNE     %FT65

        MOV     r5, r10, LSR #12                ; else it's an STR (r0 = 0)
        AND     r5, r5, #&0F                    ; r5 = source register number
        LDR     r5, [r11, r5, LSL #2]           ; r5 = value of source register
 [ DebugAborts
        DREG    r5, "Data value to store = "
 ]
        Push    "r5"                            ; create stack frame with this value in it
65
        LDR     r1, [sp, #(1+8)*4]              ; get SPSR_abort
1009
        TST     r1, #&F                         ; test if transfer took place in USR mode
Neil Turton's avatar
Neil Turton committed
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
        ORRNE   r0, r0, #2                      ; if not then set bit 1 of flags word in r0

        MOV     r1, sp                          ; r1 -> data block
        TST     r10, #1 :SHL: 22                ; if byte transfer
        MOVNE   r3, #1                          ; then length of transfer = 1
        MOVNE   r2, r9                          ; and use unmolested address
        MOVEQ   r3, #4                          ; else length = 4
        BICEQ   r2, r9, #3                      ; and mask out bottom 2 bits of address

        BL      ProcessTransfer
        ADDVS   sp, sp, #4                      ; if illegal transfer, junk stack frame
        BVS     %FT90                           ; and cause exception

        ADD     r6, r9, r8                      ; update base register with offset
        STR     r6, [r11, r7, LSL #2]           ; and store back (NB if LDR and dest=base, the load overwrites the updated base)

        TST     r10, #1 :SHL: 20                ; if it's STR (not LDR)
        ADDEQ   sp, sp, #4                      ; then junk stack frame
        BEQ     %FT70                           ; and tidy up

1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
        Pull    "r6"                            ; LDR/LDRB/LDRSB: get value to load into register
        TST     r10, #1 :SHL: 22
        BEQ     %FT67
        TST     r10, #1 :SHL: 26                ; LDRB: see if zero fill or sign extend is needed
        MOVEQ   r6, r6, LSL #24
        MOVEQ   r6, r6, ASR #24                 ; fill with b7
        ANDNE   r6, r6, #&FF                    ; fill with zero
        B       %FT69
67
        AND     r9, r9, #3                      ; LDR: rotate word to correct position - r9 = bottom 2 bits of address
        MOV     r9, r9, LSL #3                  ; multiply by 8 to get rotation factor
        MOV     r6, r6, ROR r9                  ; rotate to correct position in register
69
Neil Turton's avatar
Neil Turton committed
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
        MOV     r5, r10, LSR #12                ; test for LDR PC
        AND     r5, r5, #&0F                    ; r5 = dest register number
        TEQ     r5, #15                         ; if PC
        ADDEQ   r6, r6, #4                      ; then adjust for abort exit
        STR     r6, [r11, r5, LSL #2]           ; store into register bank

70

; Tidy up routine, common to LDR/STR and LDM/STM

        ADD     r2, r11, #8*4                   ; point r2 at 2nd half of main register bank
        LDMIA   sp, {r8-r14}^                   ; reload user bank registers
        NOP                                     ; don't access banked registers after LDM^
        ADD     sp, sp, #8*4                    ; junk user bank stack frame

Kevin Bracey's avatar
Kevin Bracey committed
1058 1059
 [ No26bitCode
        Pull    "r0"                            ; r0 = (possibly updated) SPSR_abort
1060
        MRS     r1, CPSR
Kevin Bracey's avatar
Kevin Bracey committed
1061
 |
Neil Turton's avatar
Neil Turton committed
1062 1063 1064
        Pull    "r0, lr"                        ; r0 = (possibly updated) SPSR_abort, restore lr_svc

        SetMode ABT32_mode, r1                  ; leaves r1 = current PSR
Kevin Bracey's avatar
Kevin Bracey committed
1065
 ]
Neil Turton's avatar
Neil Turton committed
1066

1067
        MRS     r6, SPSR                        ; get original SPSR, with aborter's original mode
Kevin Bracey's avatar
Kevin Bracey committed
1068 1069
        AND     r7, r6, #&0F
        TEQ     r7, #USR26_mode                 ; also matches USR32
Neil Turton's avatar
Neil Turton committed
1070 1071 1072 1073 1074
        LDMEQIA r2, {r8-r14}^                   ; if user mode then just use ^ to reload registers
        NOP
        BEQ     %FT80

        ORR     r6, r6, #I32_bit                ; use aborter's flags and mode but set I
Kevin Bracey's avatar
Kevin Bracey committed
1075
        BIC     r6, r6, #T32_bit                ; and don't set Thumb bit
1076
        MSR     CPSR_c, r6                      ; switch to aborter's mode
Neil Turton's avatar
Neil Turton committed
1077
        LDMIA   r2, {r8-r14}                    ; reload banked registers
1078
        MSR     CPSR_c, r1                      ; switch back to ABT32
Neil Turton's avatar
Neil Turton committed
1079 1080 1081

80
        LDR     lr_abort, [r13_abort, #15*4]    ; get PC to return to
1082
        MSR     SPSR_cxsf, r0                   ; set up new SPSR (may have changed for LDM {PC}^)
Neil Turton's avatar
Neil Turton committed
1083 1084

        LDMIA   r13_abort, {r0-r7}              ; reload r0-r7
Kevin Bracey's avatar
Kevin Bracey committed
1085 1086 1087
 [ No26bitCode
        ADD     r13_abort, r13_abort, #17*4     ; we use stacks, dontcherknow
 ]
Neil Turton's avatar
Neil Turton committed
1088 1089 1090
        SUBS    pc, lr_abort, #4                ; go back 8 to adjust for PC being 2 words out,
                                                ; then forward 4 to skip instruction we've just executed

Jeffrey Lee's avatar
Jeffrey Lee committed
1091 1092
 ] ; UseProcessTransfer

Neil Turton's avatar
Neil Turton committed
1093 1094 1095 1096
; Call normal exception handler

90

1097 1098
; copy temp area to real area (we believe this is an unexpected data abort now)

Jeffrey Lee's avatar
Jeffrey Lee committed
1099
        LDR     r0, =ZeroPage+Abort32_dumparea
1100 1101 1102 1103 1104 1105 1106
        LDR     r1, [r0,#3*4]
        STR     r1, [r0]
        LDR     r1, [r0,#4*4]
        STR     r1, [r0,#4]
        LDR     r1, [r0,#5*4]
        STR     r1, [r0,#2*4]

Kevin Bracey's avatar
Kevin Bracey committed
1107
 [ No26bitCode
Jeffrey Lee's avatar
Jeffrey Lee committed
1108 1109
        LDR     r0, =ZeroPage                           ; we're going to call abort handler
      [ ZeroPage = 0
Kevin Bracey's avatar
Kevin Bracey committed
1110
        STR     r0, [r0, #CDASemaphore]                 ; so allow recovery if we were in CDA
Jeffrey Lee's avatar
Jeffrey Lee committed
1111 1112 1113 1114
      |
        MOV     r2, #0
        STR     r2, [r0, #CDASemaphore]                 ; so allow recovery if we were in CDA
      ]
Kevin Bracey's avatar
Kevin Bracey committed
1115

Jeffrey Lee's avatar
Jeffrey Lee committed
1116
        LDR     r0, [r0, #DAbHan]                       ; get address of data abort handler
Kevin Bracey's avatar
Kevin Bracey committed
1117 1118