ARM600 158 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 20 21 22 23 24 25
; 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}


; MMU interface file - ARM600 version

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

26 27 28
;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
29 30


Neil Turton's avatar
Neil Turton committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
; 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
46 47
; * Abort32 mode stack (8K)
;
Neil Turton's avatar
Neil Turton committed
48 49 50 51 52 53 54 55 56 57 58 59 60
; * 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
61 62 63 64
;
; amg 7/12/96 Renaissance, import changes below from Spinner tree, but this is fundamentally the
; 3.70 file.

65
; 17-Jun-96     BAR     Change speed settings for the second bank of ROM space.
Neil Turton's avatar
Neil Turton committed
66 67
; 09-Jul-96     BAR     Improve IOMD ID vsn code - two places.
;                       Change ROM Speed settings for 7500FE and non-7500FE parts.
68 69 70 71 72 73 74
; 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
75 76


Neil Turton's avatar
Neil Turton committed
77 78 79 80

; Fixed page allocation is as follows

        ^       0
81
 [ :LNOT: HAL
Neil Turton's avatar
Neil Turton committed
82 83 84
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
85 86 87 88
 [ No26bitCode
DRAMOffset_AbortStack   #        8*1024
 ]
        AlignSpace      16*1024                 ; L1PT (and hence L2PT) must be 16K-aligned
Neil Turton's avatar
Neil Turton committed
89 90
DRAMOffset_L2PT         #       0               ; static L2PT (variable size, with embedded L1PT)
DRAMOffset_L1PT         *       DRAMOffset_L2PT + 48*1024
91
 ]
Neil Turton's avatar
Neil Turton committed
92 93 94 95 96 97 98 99

; 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

100
 [ :LNOT: HAL
Neil Turton's avatar
Neil Turton committed
101 102
L2PT                    *       &02C00000       ; size 256K
L1PT                    *       &02C0C000       ; in the middle of L2PT, where the mapping for 03000000 to 03FFFFFF would be
103
 ]
Neil Turton's avatar
Neil Turton committed
104

Neil Turton's avatar
Neil Turton committed
105
FixedAreasL2Size        *       96*1024        ; amount of L2 to cover fixed areas, excluding free pool
Neil Turton's avatar
Neil Turton committed
106 107 108

UndStackSoftCamChunk    *       &01E00000
UndStackSize            *       8*1024
Kevin Bracey's avatar
Kevin Bracey committed
109
CamEntriesForVicky      *       UndStackSoftCamChunk + UndStackSize
110
 [ :LNOT: HAL
Neil Turton's avatar
Neil Turton committed
111
UNDSTK                  *       CamEntriesForVicky ; points to end of stack
Kevin Bracey's avatar
Kevin Bracey committed
112 113 114 115 116
 [ No26bitCode
AbtStack                *       &02000000
AbtStackSize            *       8*1024
ABTSTK                  *       AbtStack + AbtStackSize
 ]
Neil Turton's avatar
Neil Turton committed
117
PhysSpace               *       &80000000       ; Map of MEMC/IOMD physical space (64M/512M in size)
118
 ]
Neil Turton's avatar
Neil Turton committed
119

Neil Turton's avatar
Neil Turton committed
120 121 122 123 124

; - 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
125
ARMA_Cleaners_address  * &01F10000
Neil Turton's avatar
Neil Turton committed
126 127


Kevin Bracey's avatar
Kevin Bracey committed
128
 [ {FALSE}
Neil Turton's avatar
Neil Turton committed
129 130 131 132 133
arm600stuff_before_align
         ALIGN   4096     ;align to page boundary to allow for easy ROMpatch

arm600stuff_startofstuff
  ! 0, "-- start of (4k aligned) ARM600+ stuff at ":CC::STR:(arm600stuff_startofstuff)
Kevin Bracey's avatar
Kevin Bracey committed
134
 ]
Neil Turton's avatar
Neil Turton committed
135

136
 [ :LNOT: HAL
Neil Turton's avatar
Neil Turton committed
137 138 139
;note that we use the R bit if supported (not 610), so that we can write protect ROM space
;fully (user and supervisor)
;
140
  [ :LNOT: CacheOff
Neil Turton's avatar
Neil Turton committed
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
ARM_default_MMU_CR_table
;
;ARM 6              SBLDPWCAM
         DCD  2_0000001111101
;
;ARM 7            FRSB1DPWCAM
         DCD  2_0011001111101
;
;ARM 8           Z0RSB111WCAM
         DCD  2_0101001111101
;
;ARM 9 ??
         DCD  0
;
;StrongARM      I00RSB111WCAM
         DCD  2_1001001111101
157 158 159
;
  |
ARM_default_MMU_CR_table      ; if CacheOff true, same as cacheoff table
Neil Turton's avatar
Neil Turton committed
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
  ]
;
ARM_cacheoff_MMU_CR_table
;
;ARM 6              SBLDPWCAM
         DCD  2_0000001110001
;
;ARM 7            FRSB1DPWCAM
         DCD  2_0011001110001
;
;ARM 8           Z0RSB111WCAM
         DCD  2_0001001110001
;
;ARM 9 ??
         DCD  0
;
;StrongARM      I00RSB111WCAM
         DCD  2_0001001110001
;

180
 ]
Neil Turton's avatar
Neil Turton committed
181 182 183 184

OneMByte                EQU     (1024*1024)
SixteenMByte            EQU     (1024*1024 * 16)

185 186
        KEEP

Neil Turton's avatar
Neil Turton committed
187 188
; *****************************************************************************

189 190 191
; mjs Oct 2000 kernel/HAL split
; SetDAG stuff is no more, routines like SetVinit now call equivalent HAL
; routine
Neil Turton's avatar
Neil Turton committed
192 193 194 195 196

; **************** CAM manipulation utility routines ***********************************

; **************************************************************************************
;
197
;       BangCamUpdate - Update CAM, MMU for page move, coping with page currently mapped in
Neil Turton's avatar
Neil Turton committed
198
;
199 200
; mjs Oct 2000
; reworked to use generic ARM ops (vectored to appropriate routines during boot)
Neil Turton's avatar
Neil Turton committed
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
;
; 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

        MOV     r1, #0
        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
        STMIA   r1, {r3, r11}                   ; store new address, PPL
        Push    "r0, r6"                        ; save old logical address, PPL
        MOV     r1, #PhysRamTable               ; go through phys RAM table
        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
        LDMFD   r13, {r6}                       ; reload old logical address

; 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

        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
        MOV     r0, #0                          ; cause translation fault
        BL      BangL2PT                        ; map page out
        Pull    "r0, r3, r11, r14"
20
        ADD     sp, sp, #8                      ; junk old logical address, PPL
        B       BangCamAltEntry                 ; and branch into BangCam code

; **************************************************************************************
;
267
;       BangCam - Update CAM, MMU for page move, assuming page currently mapped out
Neil Turton's avatar
Neil Turton committed
268 269
;
; This routine maps a physical page to a given logical address
270
; It is assumed that the physical page is currently not mapped anywhere else
Neil Turton's avatar
Neil Turton committed
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
;
; 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

        MOV     r1, #PhysRamTable       ; go through phys RAM table
        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
300
        LDR     r4, =DuffEntry          ; check for requests to map a page to nowhere
Neil Turton's avatar
Neil Turton committed
301
        ADR     r1, PPLTrans
302 303
        TEQ     r4, r3                  ; don't actually map anything to nowhere
        MOVEQ   pc, lr
Neil Turton's avatar
Neil Turton committed
304 305
        AND     r4, r11, #3             ; first use PPL bits
        LDR     r1, [r1, r4, LSL #2]    ; get PPL bits and SmallPage indicator
306

Neil Turton's avatar
Neil Turton committed
307 308 309 310 311
        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
312

Neil Turton's avatar
Neil Turton committed
313 314 315 316
        ORR     r0, r0, r1

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

317 318
        ;fall through to BangL2PT

Neil Turton's avatar
Neil Turton committed
319 320 321 322 323 324 325
;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
326 327 328
        Push    "lr"
        MOV     r6, r0

Neil Turton's avatar
Neil Turton committed
329 330 331
        TST     r11, #DynAreaFlags_DoublyMapped
        BNE     BangL2PT_sledgehammer           ;if doubly mapped, don't try to be clever

332 333 334 335 336 337 338 339 340 341 342
        ;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
        TSTEQ   r11, #DynAreaFlags_NotCacheable ;EQ if also cacheable
        MOV     r0, r3                          ;MMU page entry address
        ADR     lr, %FT20
        MOV     r4, #0
        ARMop   MMU_ChangingEntry, EQ, tailcall, r4
        ARMop   MMU_ChangingUncachedEntry, NE, tailcall, r4
Neil Turton's avatar
Neil Turton committed
343

344 345 346
20      STR     r6, [r1, r3, LSR #10]           ;update L2PT entry

        Pull    "pc"
Neil Turton's avatar
Neil Turton committed
347 348

BangL2PT_sledgehammer
349 350 351 352 353 354 355 356 357 358 359 360

        ;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
        TSTEQ   r11, #DynAreaFlags_NotCacheable ;EQ if also cacheable
        ADR     lr, %FT30
        MOV     r4, #0
        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
361
        TST     r11, #DynAreaFlags_DoublyMapped ; if area doubly mapped
362 363
        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
364

365
        Pull    "pc"
Neil Turton's avatar
Neil Turton committed
366

Neil Turton's avatar
Neil Turton committed
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390

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
        &       (AP_None * L2_APMult) + L2_SmallPage      ; R sup W sup

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
        MOV     r12, #0
Kevin Bracey's avatar
Kevin Bracey committed
391
        WritePSRc SVC_mode+I_bit+F_bit, r0
Neil Turton's avatar
Neil Turton committed
392 393 394 395 396 397 398 399
        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]

400 401 402 403 404 405 406 407 408 409
; 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
410 411 412 413 414 415 416 417 418 419
;
; 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

420 421 422 423 424
        Push  "r0-r3, r9, r14"   ; can corrupt r12
        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
425 426
        mjsAddressHAL
        mjsCallHAL    HAL_Video_SetBlank
427
        Pull  "r0-r3, r9, r14"
Neil Turton's avatar
Neil Turton committed
428

Kevin Bracey's avatar
Kevin Bracey committed
429
        WritePSRc SVC_mode+I_bit, r11
Neil Turton's avatar
Neil Turton committed
430 431
        ExitSWIHandler

432
  [ :LNOT: HAL
Neil Turton's avatar
Neil Turton committed
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       ClearPhysRAM - Routine to clear "all" memory
;
; While this routine is running, keyboard IRQs may happen. For this reason
; it avoids LogRAM 0..31 (where hardware IRQ vector is) and PhysRAM
; 0..31 where the IRQ workspace is.
;
; We also have to avoid the L2PT (inc L1PT) and the PhysRamTable.
; The latter is also used to tell us which areas of memory we should clear.

; We don't have to worry about trampling on the ROM image as it's
; already been excluded from PhysRamTable.

; This routine must work in 32-bit mode.

; in:   r7 = memory speed
;       r8 = page size
;       r9 = MEMC control register
;       r13 = total RAM size
;
; None of the above are actually used by this routine
;
; out:  r7-r9, r13 preserved
;

Neil Turton's avatar
Neil Turton committed
459 460 461
     GBLL ClearPhysRAMspeedup
ClearPhysRAMspeedup SETL {TRUE}

Neil Turton's avatar
Neil Turton committed
462
ClearPhysRAM ROUT
Neil Turton's avatar
Neil Turton committed
463

464 465 466 467
      [ EmulatorSupport
        ARM_on_emulator r0
        BEQ     CPR_skipped
      ]
Neil Turton's avatar
Neil Turton committed
468 469

;StrongARM - We will make the logical representation of physical space for RAM temporarily bufferable
470
;            (on any ARM). This is small boost for ARM 6,7,8 but a big speed benefit for StrongARM (which
Neil Turton's avatar
Neil Turton committed
471 472 473 474 475 476 477 478 479 480
;            won't burst write in non bufferable areas).

        LDR     r0,  =L1PT
        LDR     r12, =PhysRamTable
        ADD     r4, r12, #PhysRamTableEnd-PhysRamTable  ; r4 -> end of table
02
        LDMIA   r12!, {r10, r11}                        ; load next address, size
        SUB     r11,r11,#&100000                        ; 1 Mb will be done on first L1PT update
        ORR     r10, r10, #PhysSpace                    ; point to logical representation of physical space
        ADD     r1,r0,r10,LSR #(20-2)                   ; L1PT address for same
481 482 483
;MJS bug fix (since 3.70) for memory fragments not necessarily 1Mb aligned (eg 2 Mb Kryten)
        BIC     r1,r1,#3
;
Neil Turton's avatar
Neil Turton committed
484 485 486 487 488 489 490 491 492 493 494
04
        LDR     r2,[r1]
        ORR     r2,r2,#4                                ; bufferable bit
        STR     r2,[r1],#4
        SUBS    r11,r11,#&100000                        ; another 1 Mb done
        BPL     %BT04
        TEQ     r12, r4                                 ; have we done all areas?
        BNE     %BT02

;now let us do the clear
  [ ClearPhysRAMspeedup
495
        MOV     r0,#ZeroPage+InitClearRamWs             ;we can preserve r7-r9,r13 at logical address 52..67
Neil Turton's avatar
Neil Turton committed
496 497 498 499 500 501
        STMIA   r0,{r7-r9,r13}
        MOV     r7,  #0
        MOV     r8,  #0
        MOV     r9,  #0
        MOV     r13, #0
  ]
Neil Turton's avatar
Neil Turton committed
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
        MOV     r0, #0
        MOV     r1, #0
        MOV     r2, #0
        MOV     r3, #0
        LDR     r12, =PhysRamTable                      ; point to 5 lots of (physaddr,size)
        ADR     r6, RamSkipTable
        ADD     r4, r12, #PhysRamTableEnd-PhysRamTable  ; r4 -> end of table
10
        LDR     r5, [r6], #4                            ; load first skip offset

        LDMIA   r12!, {r10, r11}                        ; load next address, size

        ORR     r10, r10, #PhysSpace                    ; point to logical representation of physical space
        ADD     r11, r11, r10                           ; r11 -> end address of this area
15
        ADD     r5, r5, r10                             ; r5 -> skip address if any
20
        TEQ     r10, r11                                ; test for end of this area?
        BEQ     %FT30
        TEQ     r10, r5                                 ; test for the start of a skipped region
Neil Turton's avatar
Neil Turton committed
522 523 524
  [ ClearPhysRAMspeedup
        STMNEIA r10!, {r0-r3,r7-r9,r13}
  |
Neil Turton's avatar
Neil Turton committed
525
        STMNEIA r10!, {r0-r3}
Neil Turton's avatar
Neil Turton committed
526
  ]
Neil Turton's avatar
Neil Turton committed
527 528 529 530 531 532 533 534 535 536 537 538 539
        BNE     %BT20

        LDR     r5, [r6], #4                            ; load skip amount
        CMP     r5, #0                                  ; if negative, then it's an offset from start of skipped bit
        LDRLT   r5, [r10, r5]                           ; to address of word holding skip amount
        ADD     r10, r10, r5                            ; and skip it
        LDR     r5, [r6], #4                            ; load next skip offset (NB relative to end of last skip)
        B       %BT15

30
        TEQ     r12, r4                                 ; have we done all areas?
        BNE     %BT10

Neil Turton's avatar
Neil Turton committed
540
  [ ClearPhysRAMspeedup
541 542 543 544 545 546 547 548 549 550 551 552
        MOV     r0, #ZeroPage+InitClearRamWs
        LDMIA   r0, {r7-r9,r13}                         ;restore

        MOV     r0, #ZeroPage+InitUsedStart             ;clear our speed up workspace
        ASSERT  InitUsedStart < InitUsedEnd
        ASSERT  InitUsedEnd < InitClearRamWs
        GBLA    finalclear
finalclear      SETA InitUsedStart
        WHILE   finalclear < InitWsEnd
        STMIA   r0!,{r1-r3}
finalclear      SETA finalclear + 12
        WEND
Neil Turton's avatar
Neil Turton committed
553 554 555 556 557 558 559 560 561 562 563 564 565
  ]

;StrongARM - now let us remove bufferable status of logical representation of physical space (perhaps we could
;            leave it? not sure at the mo.)

        LDR     r0,  =L1PT
        LDR     r12, =PhysRamTable
        ADD     r4, r12, #PhysRamTableEnd-PhysRamTable  ; r4 -> end of table
32
        LDMIA   r12!, {r10, r11}                        ; load next address, size
        SUB     r11,r11,#&100000                        ; 1 Mb will be done on first L1PT update
        ORR     r10, r10, #PhysSpace                    ; point to logical representation of physical space
        ADD     r1,r0,r10,LSR #(20-2)                   ; L1PT address for same
566 567 568
;MJS bug fix (since 3.70) for memory fragments not necessarily 1Mb aligned (eg 2 Mb Kryten)
        BIC     r1,r1,#3
;
Neil Turton's avatar
Neil Turton committed
569 570 571 572 573 574 575 576 577
34
        LDR     r2,[r1]
        BIC     r2,r2,#4                                ; bufferable bit
        STR     r2,[r1],#4
        SUBS    r11,r11,#&100000                        ; another 1 Mb done
        BPL     %BT34
        TEQ     r12, r4                                 ; have we done all areas?
        BNE     %BT32

578
CPR_skipped
Neil Turton's avatar
Neil Turton committed
579

Neil Turton's avatar
Neil Turton committed
580
        LDR     r0, =OsbyteVars + :INDEX: LastBREAK
Neil Turton's avatar
Neil Turton committed
581

Neil Turton's avatar
Neil Turton committed
582 583 584
        MOV     r1, #&80
        STRB    r1, [r0]                                ; flag the fact that RAM cleared

Neil Turton's avatar
Neil Turton committed
585 586 587 588
        ARM_number r0
        SUB     r0,r0,#6
        ADRL    r1,ARM_default_MMU_CR_table
        LDR     r1,[r1,r0,LSL #2]
Neil Turton's avatar
Neil Turton committed
589
        MOV     r0, #0
Neil Turton's avatar
Neil Turton committed
590
        STR     r1, [r0, #MMUControlSoftCopy]           ; set up MMU soft copy
Neil Turton's avatar
Neil Turton committed
591 592 593

        MOV     pc, lr

Neil Turton's avatar
Neil Turton committed
594 595
        LTORG

Neil Turton's avatar
Neil Turton committed
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
        GBLA    lastaddr
lastaddr SETA   0
        GBLA    lastregion
lastregion SETA 0

        MACRO
        MakeSkipTable $region, $addr, $size
 [ ($region)<>lastregion
        &       -1
lastaddr SETA   0
 ]
        &       ($addr)-lastaddr, $size
lastaddr SETA   ($addr)+($size)
lastregion SETA $region
        MEND

        MACRO
        EndSkipTables
        WHILE   lastregion < (PhysRamTableEnd-PhysRamTable)/8
        &       -1
lastregion SETA   lastregion +1
        WEND
        MEND

; Note (TMD 04-Aug-93): Special bodge put in here to allow variable size skip for L2PT.
; If skip size field is negative, then it's an offset from the start of this skipped bit to a word holding
; the size of the skip. This relies on the L2PTSize being in page zero, which is at a lower physical address than
; the L2 itself. Also assumes that there are no more skips in the 1st DRAM chunk after the L2PT, since the offset
; to the next skip is relative to the end of the previous one, which isn't known at assembly time!

; Tim says "Yuk, yuk, yuk!!"

RamSkipTable
629
        MakeSkipTable   1, DRAMOffset_PageZero + 0, InitWsEnd - ZeroPage  ; skip 1st n bytes of LogRAM, so IRQs work!
Neil Turton's avatar
Neil Turton committed
630 631 632 633 634
        MakeSkipTable   1, DRAMOffset_PageZero + SkippedTables, SkippedTablesEnd-SkippedTables
        MakeSkipTable   1, DRAMOffset_L2PT, DRAMOffset_PageZero + L2PTSize - DRAMOffset_L2PT
        EndSkipTables

        ASSERT  DRAMOffset_PageZero + L2PTSize < DRAMOffset_L2PT
635
 ]
Neil Turton's avatar
Neil Turton committed
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653


; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       InitMEMC - Initialise memory controller
;
; in:   If ResetIndirection assembly flag set, then
;         r1 = 0 if reset, 1 if break
;       else
;         r1 undefined
;       endif

InitMEMC ROUT

; Note: On IOMD, all accesses go to ROM until the first write cycle.

        MOV     r12, #IOMD_Base

Neil Turton's avatar
Neil Turton committed
654 655 656
; amg: drop in FE-aware routine, leave old one here for reference

  [ MorrisSupport
Neil Turton's avatar
Neil Turton committed
657 658 659 660 661 662 663 664
; Perform a dummy write to IOMD (some harmless register) to get it out of ROM force mode.
; Reads from IOMD will return garbage before this has happened. If we're actually running out
; of 32-bit wide ROMs on MORRIS, a write will already have happened, to get ROMCR0 from
; 16 to 32-bit wide mode, but we can't yet determine for sure (by reading it back), so do it
; anyway.

        STRB    r12, [r12, #IOMD_DMAREQ]              ; writes to DMAREQ are ignored

665 666 667 668
        LDRB    r2,[r12,#IOMD_ID1]      ; load r2 with IOMD ID high byte
        LDRB    r0,[r12,#IOMD_ID0]      ; load r0 with IOMD ID low byte
        ORR     r0,r0,r2, LSL #8        ; Or r0 and r2 - shifted left 8, put in r0
        LDR     r2,=IOMD_7500           ; get Ref IOMD ID code for IOMD in a 7500
Neil Turton's avatar
Neil Turton committed
669
        CMPS    r0,r2                   ; check for IOMD ID Code for IOMD in a 7500
670
        BEQ     init7500cpu             ; If equal, got to init7500cpu
Neil Turton's avatar
Neil Turton committed
671

672 673
        LDRNE   r2,=IOMD_7500FE         ; If not, get ID code for IOMD in a 7500FE
        CMPNES  r0,r2                   ; If not, check for IOMD ID Code for IOMD in a 7500FE
Neil Turton's avatar
Neil Turton committed
674 675 676 677 678 679 680
        BNE     MedusaInit              ; NOT MORRIS assume Medusa hardware


init7500FEcpu
; Here bceause its an ARM7500 'FE' variant
; Program the CPU, Memory and IO clock prescalers
; Set the prescalers to :-
681 682

  [ RO371Timings
683 684 685
;       CPUCLK divide by 1
;       MEMCLK divide by 2
;       IOCLK  divide by 2
686
;
687
        MOV     r0, #IOMD_CLKCTL_CpuclkNormal + IOMD_CLKCTL_MemclkHalf + IOMD_CLKCTL_IOclkHalf
688
  |
689 690 691
;       CPUCLK divide by 2 unless FECPUSpeedNormal set
;       MEMCLK divide by 1
;       IOCLK  divide by 1
Neil Turton's avatar
Neil Turton committed
692
;
Kevin Bracey's avatar
Kevin Bracey committed
693
   [ FECPUSpeedNormal
694
     [ FEIOSpeedHalf
695
        MOV     r0, #IOMD_CLKCTL_CpuclkNormal + IOMD_CLKCTL_MemclkNormal + IOMD_CLKCTL_IOclkHalf
696
     |
697
        MOV     r0, #IOMD_CLKCTL_CpuclkNormal + IOMD_CLKCTL_MemclkNormal + IOMD_CLKCTL_IOclkNormal
698
     ]
Kevin Bracey's avatar
Kevin Bracey committed
699
   |
700
     [ FEIOSpeedHalf
701
        MOV     r0, #IOMD_CLKCTL_CpuclkHalf + IOMD_CLKCTL_MemclkNormal + IOMD_CLKCTL_IOclkHalf
702
     |
703
        MOV     r0, #IOMD_CLKCTL_CpuclkHalf + IOMD_CLKCTL_MemclkNormal + IOMD_CLKCTL_IOclkNormal
704
     ]
Kevin Bracey's avatar
Kevin Bracey committed
705
   ]
706
  ]
Neil Turton's avatar
Neil Turton committed
707
        STRB    r0, [r12, #IOMD_CLKCTL] ; initialise all the prescalers.
Neil Turton's avatar
Neil Turton committed
708
;
Neil Turton's avatar
Neil Turton committed
709
; Set ROM speed, take care to preserve 16-bit mode bit...
Neil Turton's avatar
Neil Turton committed
710
;
Neil Turton's avatar
Neil Turton committed
711 712 713 714 715 716 717 718 719 720 721
; According to BSiddle on the 15-May-96, Omega will use burst mode roms: use 93nS burst, 156nS initial.
; According to TDobson on the 09-Jul-96, Omega will handle ROMS up to 120nS and 70nS.
; Thus the ROM speed should be initilised to :-
; Half Speed or H bit, clear, which is ON ! : Half the delays, thus DOUBLE all clock ticks.
; Non-Sequental delay : 10 Ticks : Half speed on, so select 5 ticks (5*2)
; Burst delay         :  8 Ticks : Half speed on, so select 4 ticks (4*2)
; Remember the Memory clock on Omega is faster than on previous products.
; The fast flash devices used for Omega testing should be able to cope even
; though they aren't burst devices.
        LDRB    r0, [r12, #IOMD_ROMCR0]         ; Get contents of ROMCR0 in to r0
        AND     r0, r0, #&40                    ; clear all but the 16-bit mode flag
722 723 724
  [ RO371Timings
        ORR     r0, r0, #IOMD_ROMCR_HalfSpeed + IOMD_ROMCR_NSTicks_5 + IOMD_ROMCR_BTicks_3
  |
Kevin Bracey's avatar
Kevin Bracey committed
725
    [ ROMSpeedNormal
726
        ORR     r0, r0, #IOMD_ROMCR_Normal :OR: IOMD_ROMCR_NSTicks_$ROMSpeedNSTicks :OR: IOMD_ROMCR_BTicks_$ROMSpeedBurstTicks
Kevin Bracey's avatar
Kevin Bracey committed
727
    |
728
        ORR     r0, r0, #IOMD_ROMCR_HalfSpeed :OR: IOMD_ROMCR_NSTicks_$ROMSpeedNSTicks :OR: IOMD_ROMCR_BTicks_$ROMSpeedBurstTicks
Kevin Bracey's avatar
Kevin Bracey committed
729
    ]
730
  ]
Neil Turton's avatar
Neil Turton committed
731 732 733 734
        STRB    r0, [r12, #IOMD_ROMCR0]         ; Prog. the reg.s

; Program the 2nd ROM bank
  [ ExtROMSupport
Kevin Bracey's avatar
Kevin Bracey committed
735

Neil Turton's avatar
Neil Turton committed
736 737 738
;   Unless we're actually running from the 2nd ROM bank (CanLiveOnROMCard), we don't know how fast
;   the extension ROM in the 2nd bank goes, so program it for a slow default speed
    [ CanLiveOnROMCard
739 740
        TST     pc, #PhysExtROM                 ; are we running out of the 2nd ROM bank? Program the 2nd bank the same as the 1st if so
        STRNE   r0, [r12, #IOMD_ROMCR1]
Kevin Bracey's avatar
Kevin Bracey committed
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
    ]
    [ ExtROMis16bit
     [ ROMSpeedNormal
        MOV     r0, #IOMD_ROMCR_Normal :OR: IOMD_ROMCR_16bit :OR: IOMD_ROMCR_NSTicks_7 :OR: IOMD_ROMCR_BurstOff
     |
        MOV     r0, #IOMD_ROMCR_HalfSpeed :OR: IOMD_ROMCR_16bit :OR: IOMD_ROMCR_NSTicks_7 :OR: IOMD_ROMCR_BurstOff
     ]
    |
     [ ROMSpeedNormal
        MOV     r0, #IOMD_ROMCR_Normal :OR: IOMD_ROMCR_32bit :OR: IOMD_ROMCR_NSTicks_7 :OR: IOMD_ROMCR_BurstOff
     |
        MOV     r0, #IOMD_ROMCR_HalfSpeed :OR: IOMD_ROMCR_32bit :OR: IOMD_ROMCR_NSTicks_7 :OR: IOMD_ROMCR_BurstOff
     ]
    ]
    [ CanLiveOnROMCard
756
        STREQB  r0, [r12, #IOMD_ROMCR1]
Kevin Bracey's avatar
Kevin Bracey committed
757
    |
758
        STRB    r0, [r12, #IOMD_ROMCR1]
Kevin Bracey's avatar
Kevin Bracey committed
759
    ]
Neil Turton's avatar
Neil Turton committed
760 761

  |;ExtROMSupport
Kevin Bracey's avatar
Kevin Bracey committed
762

Neil Turton's avatar
Neil Turton committed
763
    [ CanLiveOnROMCard
764
        STRB    r0, [r12, #IOMD_ROMCR1]         ; Program the 2nd bank the same as the 1st
Neil Turton's avatar
Neil Turton committed
765
    |
766
        STRB    r0, [r12, #IOMD_ROMCR1]         ; 2nd bank unused: program it the same anyway
Neil Turton's avatar
Neil Turton committed
767
    ]
Kevin Bracey's avatar
Kevin Bracey committed
768

Neil Turton's avatar
Neil Turton committed
769 770 771 772
  ];ExtROMSupport

; Now program ASTCR to add wait states, since MEMCLK is fast relative to IOCLK

773 774
        MOV     r0, #IOMD_ASTCR_WaitStates
        STRB    r0, [r12, #IOMD_ASTCR]
Neil Turton's avatar
Neil Turton committed
775

776
        B       init7500cpu_common              ; branch to common init code.
Neil Turton's avatar
Neil Turton committed
777 778 779 780 781 782
;

init7500cpu
; Here because its an ARM7500 variant - NON 'FE' device.
; Program the CPU, Memory and IO clock prescalers
; Set the prescalers to :-
783 784 785
;       CPUCLK divide by 1
;       MEMCLK divide by 1
;       IOCLK  divide by 1
Neil Turton's avatar
Neil Turton committed
786 787 788 789 790 791 792
;
        MOV     r0, #IOMD_CLKCTL_CpuclkNormal + IOMD_CLKCTL_MemclkNormal + IOMD_CLKCTL_IOclkNormal
        STRB    r0, [r12, #IOMD_CLKCTL] ; initialise all prescalers to div1
;
; Set ROM speed, take care to preserve 16-bit mode bit...
;
; According to RJKing on 6/5/94, Kryten will use burst mode roms: use 93nS burst, 156nS initial.
Neil Turton's avatar
Neil Turton committed
793 794 795 796 797 798 799 800 801 802
; According to BSiddle on 09-Jul-96 - Omenga will need to set the burst speed to 4 ticks from 3 ticks.
; Thus the ROM speed should be initilised to :-
; Half Speed or H bit, Set, which is OFF ! : Don't half the delays.
; Non-Sequental delay :  5 Ticks : Half speed off, so select 5 ticks
; Burst delay         :  4 Ticks : Half speed off, so select 4 ticks
; The fast EPROMS used for Kryten testing should be able to cope even though
; they aren't burst devices

        LDRB    r0, [r12, #IOMD_ROMCR0]          ; Get contents of ROMCR0 in to r0
        AND     r0, r0, #&40                    ; clear all but the 16-bit mode flag
803 804 805
  [ RO371Timings
        ORR     r0, r0, #IOMD_ROMCR_Normal + IOMD_ROMCR_NSTicks_5 + IOMD_ROMCR_BTicks_3
  |
Kevin Bracey's avatar
Kevin Bracey committed
806
    [ ROMSpeedNormal
807
        ORR     r0, r0, #IOMD_ROMCR_Normal :OR: IOMD_ROMCR_NSTicks_$ROMSpeedNSTicks :OR: IOMD_ROMCR_BTicks_$ROMSpeedBurstTicks
Kevin Bracey's avatar
Kevin Bracey committed
808
    |
809
        ORR     r0, r0, #IOMD_ROMCR_HalfSpeed :OR: IOMD_ROMCR_NSTicks_$ROMSpeedNSTicks :OR: IOMD_ROMCR_BTicks_$ROMSpeedBurstTicks
Kevin Bracey's avatar
Kevin Bracey committed
810
    ]
811
  ]
Neil Turton's avatar
Neil Turton committed
812 813 814 815
        STRB    r0, [r12, #IOMD_ROMCR0]          ; Prog. the reg.s

; Program the 2nd ROM bank
  [ ExtROMSupport
Kevin Bracey's avatar
Kevin Bracey committed
816

Neil Turton's avatar
Neil Turton committed
817 818 819
;   Unless we're actually running from the 2nd ROM bank (CanLiveOnROMCard), we don't know how fast
;   the extension ROM in the 2nd bank goes, so program it for a slow default speed
    [ CanLiveOnROMCard
820 821
        TST     pc, #PhysExtROM                 ; are we running out of the 2nd ROM bank? Program the 2nd bank the same as the 1st if so
        STRNE   r0, [r12, #IOMD_ROMCR1]
Kevin Bracey's avatar
Kevin Bracey committed
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
    ]
    [ ExtROMis16bit
     [ ROMSpeedNormal
        MOV     r0, #IOMD_ROMCR_Normal :OR: IOMD_ROMCR_16bit :OR: IOMD_ROMCR_NSTicks_7 :OR: IOMD_ROMCR_BurstOff
     |
        MOV     r0, #IOMD_ROMCR_HalfSpeed :OR: IOMD_ROMCR_16bit :OR: IOMD_ROMCR_NSTicks_7 :OR: IOMD_ROMCR_BurstOff
     ]
    |
     [ ROMSpeedNormal
        MOV     r0, #IOMD_ROMCR_Normal :OR: IOMD_ROMCR_32bit :OR: IOMD_ROMCR_NSTicks_7 :OR: IOMD_ROMCR_BurstOff
     |
        MOV     r0, #IOMD_ROMCR_HalfSpeed :OR: IOMD_ROMCR_32bit :OR: IOMD_ROMCR_NSTicks_7 :OR: IOMD_ROMCR_BurstOff
     ]
    ]
    [ CanLiveOnROMCard
837
        STREQB  r0, [r12, #IOMD_ROMCR1]
Kevin Bracey's avatar
Kevin Bracey committed
838
    |
839
        STRB    r0, [r12, #IOMD_ROMCR1]
Kevin Bracey's avatar
Kevin Bracey committed
840
    ]
Neil Turton's avatar
Neil Turton committed
841 842

  |;ExtROMSupport
Kevin Bracey's avatar
Kevin Bracey committed
843

Neil Turton's avatar
Neil Turton committed
844
    [ CanLiveOnROMCard
845
        STRB    r0, [r12, #IOMD_ROMCR1]         ; Program the 2nd bank the same as the 1st
Neil Turton's avatar
Neil Turton committed
846
    |
847
        STRB    r0, [r12, #IOMD_ROMCR1]         ; 2nd bank unused: program it the same anyway
Neil Turton's avatar
Neil Turton committed
848
    ]
Kevin Bracey's avatar
Kevin Bracey committed
849

Neil Turton's avatar
Neil Turton committed
850 851 852 853
  ];ExtROMSupport

; Now program ASTCR to *NOT* add wait states, since MEMCLK is slow relative to IOCLK

854 855
        MOV     r0, #IOMD_ASTCR_Minimal
        STRB    r0, [r12, #IOMD_ASTCR]
Neil Turton's avatar
Neil Turton committed
856 857 858 859 860

;
;
init7500cpu_common
; Common setup requirments for BOTH 7500 and 7500FE.
Neil Turton's avatar
Neil Turton committed
861 862 863 864 865 866 867 868 869 870 871 872
;
; MORRIS doesn't support VRAM. Kryten has same DRAM speed as Medusa
;
        MOV     r0, #IOMD_VREFCR_REF_16                         ; select 16µs refresh
        STRB    r0, [r12, #IOMD_VREFCR]

        MOV     r0, #IOMD_IOTCR_Network_TypeA :OR: IOMD_IOTCR_Combo_TypeB :OR: IOMD_IOTCR_Sound_TypeB :OR: IOMD_IOTCR_Sound_Word
        STRB    r0, [r12, #IOMD_IOTCR]

        MOV     r0, #0                          ; Podule manager wants TypeA setting by default for all podules
        STRB    r0, [r12, #IOMD_ECTCR]

Neil Turton's avatar
Neil Turton committed
873
   [ Japanese16BitSound :LAND: STB
Neil Turton's avatar
Neil Turton committed
874 875
        MOV     r0, #2_10
        STRB    r0, [r12, #IOMD_VIDMUX]
Neil Turton's avatar
Neil Turton committed
876
   ]
Neil Turton's avatar
Neil Turton committed
877 878 879
        B       CommonInit

MedusaInit
Neil Turton's avatar
Neil Turton committed
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 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 949 950 951 952 953
  ] ; MorrisSupport

; amg renaissance ->  [ MorrisSupport
; amg renaissance -> ; Perform a dummy write to IOMD (some harmless register) to get it out of ROM force mode.
; amg renaissance -> ; Reads from IOMD will return garbage before this has happened. If we're actually running out
; amg renaissance -> ; of 32-bit wide ROMs on MORRIS, a write will already have happened, to get ROMCR0 from
; amg renaissance -> ; 16 to 32-bit wide mode, but we can't yet determine for sure (by reading it back), so do it
; amg renaissance -> ; anyway.
; amg renaissance ->
; amg renaissance ->         STRB    r12, [r12, #IOMD_DMAREQ]              ; writes to DMAREQ are ignored
; amg renaissance ->
; amg renaissance ->         LDRB    r0, [r12, #IOMD_ID0]
; amg renaissance ->         CMP     r0, #&98
; amg renaissance ->         LDRB    r0, [r12, #IOMD_ID1]
; amg renaissance ->         CMPEQ   r0, #&5B
; amg renaissance ->        ;MOVEQ   r3, #xxxx
; amg renaissance ->         BNE     MedusaInit                            ; NOT MORRIS assume Medusa hardware
; amg renaissance -> ;
; amg renaissance -> ; MORRIS contains IOMD equivalant circuitry. Due to lack of VRAM, presence of 16/32 bit support
; amg renaissance -> ; and a different ROM speed register, we program it slightly differently.
; amg renaissance -> ;
; amg renaissance ->
; amg renaissance -> ;
; amg renaissance -> ; PSwindell wants all prescalers set to divide by 1
; amg renaissance -> ;
; amg renaissance ->         MOV     r0, #IOMD_CLKCTL_CpuclkNormal + IOMD_CLKCTL_MemclkNormal + IOMD_CLKCTL_IOclkNormal
; amg renaissance ->         STRB    r0, [r12, #IOMD_CLKCTL] ; initialise all prescalers to div1
; amg renaissance ->
; amg renaissance -> ;
; amg renaissance -> ; Set ROM speed, take care to preserve 16-bit mode bit...
; amg renaissance -> ;
; amg renaissance -> ; According to RJKing on 6/5/94, Kryten will use burst mode roms: use 93nS burst, 156nS initial.
; amg renaissance -> ;
; amg renaissance -> ; We assume that the extension ROMs are the same access time and width as the main OS ROMS.
; amg renaissance -> ;
; amg renaissance ->         LDRB    r0, [r12, #IOMD_ROMCR0]
; amg renaissance ->         AND     r0, r0, #&40            ; clear all but 16-bit mode bit, giving us the slowest ROMs possible
; amg renaissance ->  [ :LNOT: AutoSpeedROMS
; amg renaissance ->   [ NormalSpeedROMS
; amg renaissance ->    ;Normal code
; amg renaissance ->         ORR     r0, r0, #IOMD_ROMCR_Normal + IOMD_ROMCR_156 + IOMD_ROMCR_Burst93
; amg renaissance ->                                                                 ; initialise ROM speed to 156.25nS, 93.75nS burst
; amg renaissance ->         ; the fast EPROMS used for Kryten testing should be able to cope even though they aren't
; amg renaissance ->         ; burst devices
; amg renaissance ->   |
; amg renaissance ->    ;Slow ROM access for PSwindells test EPROMS. Paul requested 156nS (or slower), burst off.
; amg renaissance ->         ORR     r0, r0, #IOMD_ROMCR_Normal + IOMD_ROMCR_187 + IOMD_ROMCR_BurstOff
; amg renaissance ->
; amg renaissance ->         ! 0, "*** WARNING *** Slow ROM version ment for PSwindell"
; amg renaissance ->   ]
; amg renaissance ->  ]
; amg renaissance ->         STRB    r0, [r12, #IOMD_ROMCR0]
; amg renaissance ->         STRB    r0, [r12, #IOMD_ROMCR1]         ; and do the same for extension ROMs (just in case)
; amg renaissance -> ;
; amg renaissance -> ; MORRIS doesn't support VRAM. Kryten has same DRAM speed as Medusa
; amg renaissance -> ;
; amg renaissance ->         MOV     r0, #IOMD_VREFCR_REF_16                         ; select 16µs refresh
; amg renaissance ->         STRB    r0, [r12, #IOMD_VREFCR]
; amg renaissance ->
; amg renaissance ->         MOV     r0, #IOMD_IOTCR_Network_TypeA :OR: IOMD_IOTCR_Combo_TypeB :OR: IOMD_IOTCR_Sound_TypeB :OR: IOMD_IOTCR_Sound_Word
; amg renaissance ->         STRB    r0, [r12, #IOMD_IOTCR]
; amg renaissance ->
; amg renaissance ->         MOV     r0, #0                          ; Podule manager wants TypeA setting by default for all podules
; amg renaissance ->         STRB    r0, [r12, #IOMD_ECTCR]
; amg renaissance ->
; amg renaissance ->  [ Select16BitSound
; amg renaissance -> ; All MORRIS based machines have 16bit 'Japanese' format sound DAC's
; amg renaissance ->         MOV     r0, #2_10
; amg renaissance ->         STRB    r0, [r12, #IOMD_VIDMUX]
; amg renaissance ->  ]
; amg renaissance ->         B       CommonInit
; amg renaissance ->
; amg renaissance -> MedusaInit
; amg renaissance ->  ]
Neil Turton's avatar
Neil Turton committed
954

955 956 957 958 959

  [ RO371Timings
        MOV     r0, #&12    ; 5-3 cycle ROM access
  |

Neil Turton's avatar
Neil Turton committed
960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
  [ RISCPCBurstMode
   [ 1 = 1
        ReadCop r0, CR_ID
        BIC     r0, r0, #&F     ;ignore 4 bit revision field
        LDR     r2, =&41007100                                  ;Test for early 710's
        CMP     r0, r2                                          ;
        MOVEQ   r0, #IOMD_ROMCR_156 + IOMD_ROMCR_BurstOff       ;cos they can't work in burst mode!
        MOVNE   r0, #IOMD_ROMCR_156 + IOMD_ROMCR_Burst93        ;610's 710A's and beyond can
        ! 0, "*** WARNING *** Burst mode enabled on RISC PC iff processor can cope"
   |
        MOV     r0, #IOMD_ROMCR_156 + IOMD_ROMCR_Burst93
        ! 0, "*** WARNING *** Burst mode enabled on RISC PC"
   ]
  |
        MOV     r0, #IOMD_ROMCR_156 + IOMD_ROMCR_BurstOff       ; initialise ROM speed to 156.25ns (changed from 187ns 21-Jan-94)
  ]
976 977 978

  ] ;RO371Timings conditional

Neil Turton's avatar
Neil Turton committed
979
        STRB    r0, [r12, #IOMD_ROMCR0]
Neil Turton's avatar
Neil Turton committed
980 981
 [ STB
  [ :LNOT: ExtROMis16bit
Neil Turton's avatar
Neil Turton committed
982
        STRB    r0, [r12, #IOMD_ROMCR1]         ; and do the same for extension ROMs (just in case)
Neil Turton's avatar
Neil Turton committed
983
  |
984 985
        MOV     r0, #IOMD_ROMCR_16bit + IOMD_ROMCR_Normal + IOMD_ROMCR_156 + IOMD_ROMCR_BurstOff
        STRB    r0, [r12, #IOMD_ROMCR1]         ; 16bit 156.25nS noburst (Lowest common denominator)
Neil Turton's avatar
Neil Turton committed
986 987 988 989
  ]
 |
        STRB    r0, [r12, #IOMD_ROMCR1]         ; and do the same for extension ROMs (just in case)
 ]
Neil Turton's avatar
Neil Turton committed
990 991 992 993 994 995 996 997 998 999 1000 1001 1002
        MOV     r0, #IOMD_VREFCR_VRAM_256Kx64 :OR: IOMD_VREFCR_REF_16   ; select 16µs refresh, assume 2 banks of VRAM
        STRB    r0, [r12, #IOMD_VREFCR]

        MOV     r0, #IOMD_IOTCR_Network_TypeA :OR: IOMD_IOTCR_Combo_TypeB :OR: IOMD_IOTCR_Sound_TypeB :OR: IOMD_IOTCR_Sound_Word
        STRB    r0, [r12, #IOMD_IOTCR]

        MOV     r0, #0                          ; Podule manager wants TypeA setting by default for all podules
        STRB    r0, [r12, #IOMD_ECTCR]

CommonInit
; On breaks (ie software resets) we have to turn the MMU off.
; This is slightly tricky if we've been soft-loaded!

Neil Turton's avatar
Neil Turton committed
1003 1004 1005
;mjs - must now (if not before) be true, since 26 bit configuration does not exist in Architecture 4 (ARM 810/StrongARM)
        ASSERT ResetIndirected

Neil Turton's avatar
Neil Turton committed
1006 1007 1008 1009 1010 1011 1012 1013
 [ ResetIndirected
        TEQ     r1, #0                  ; r1 = 0 if reset, 1 if break
        BEQ     %FT03                   ; [it's a reset]

        SetMode SVC32_mode, r0          ; select 32-bit mode (we know we're in 32-bit config)
        B       %FT05
03
 |
Neil Turton's avatar
Neil Turton committed
1014

Neil Turton's avatar
Neil Turton committed
1015 1016 1017 1018 1019 1020 1021
; We check for breaks by testing if we're in 32-bit configuration:
;  - on reset we'll be put into 26-bit config, MMU off, 26-bit mode
;  - on breaks we'll be left in 32-bit config, MMU on,  26-bit mode

; In both cases we want to end up in 32-bit config with MMU off, in 32-bit mode

        SetMode SVC32_mode, r1, r0      ; try to select SVC32 mode
1022
        MRS     r2, CPSR                ; read back PSR
Neil Turton's avatar
Neil Turton committed
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
        AND     r2, r2, #&1F            ; extract mode bits from PSR we tried to modify
        TEQ     r2, #SVC32_mode         ; and see if we made it into SVC32
        BEQ     %FT05                   ; [we made it so must be a Break]
 ]

; It's a reset, so select 32-bit config, MMU off

 [ LateAborts
        MOV     r2, #MMUC_P :OR: MMUC_D :OR: MMUC_L ; select 32-bit config, MMU off, late aborts
 |
        MOV     r2, #MMUC_P :OR: MMUC_D ; select 32-bit config, MMU off
 ]
        SetCop  r2, CR_Control
        SetMode SVC32_mode, r1, r0      ; and re-select 32-bit mode (this time it'll work)
        AND     r0, r0, #&1F            ; check original mode
        TEQ     r0, #SVC26_mode         ; if we were in a 26-bit mode,
        BICEQ   lr, lr, #&FC000003      ; then knock off 26-bit style PSR bits from link register
                                        ; don't knock them off otherwise, since we may be soft-loaded above 64M
        MOV     pc, lr                  ; and exit

; It's a Break

; The MMU is on and we want it off: whether we're executing out of ROM or RAM, we
; have to jump to the physical location of our image, which means paging it in at its
; own physical address.

; On MEMC1 systems it's possible that the L1/L2 logical address is the same as the image's physical
; address, which causes a headache, so we'd best use the physical mapping of the page tables (this
; can't clash as IOMD only goes up to 2000 0000 and our physical mapping is above that).

05
1054 1055 1056
 [ HAL
        ! 0, "Sort out Break"
 |
Neil Turton's avatar
Neil Turton committed
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
        MOV     r0, #0
        LDR     r0, [r0, #DRAMPhysAddrA]        ; get address of 1st DRAM bank
        LDR     r1, =PhysSpace + DRAMOffset_L1PT ; offset to start of L1
        ADD     r0, r0, r1                      ; r0 -> L1 in physical mapped logical space

        LDR     r1, [r0, #ROM :SHR: (20-2)]     ; load L1 entry for 1st Mbyte of ROM
        MOV     r1, r1, LSR #20                 ; knock off other bits
        LDR     r2, =(AP_None * L1_APMult) + L1_Section
                                                ; (svc-only access) + ~ucb + section mapped
        ORR     r2, r2, r1, LSL #20             ; merge in address
        STR     r2, [r0, r1, LSL #2]!           ; store in L1PT for 1st Mbyte
        ADD     r2, r2, #1 :SHL: 20             ; move on to 2nd Mbyte
        STR     r2, [r0, #4]                    ; and store in next entry

Neil Turton's avatar
Neil Turton committed
1071
        ARM_flush_cacheandTLB r0
Neil Turton's avatar
Neil Turton committed
1072 1073 1074 1075 1076

        MOV     r0, r1, LSL #20
        SUB     r0, r0, #ROM                    ; form RAM-ROM offset
        ADD     pc, pc, r0                      ; jump to RAM code (when we get onto IOMD, we'll have to be in 32-bit mode)
        NOP                                     ; this instruction will be skipped
1077
 ]
Neil Turton's avatar
Neil Turton committed
1078 1079 1080

; we're now in RAM, so it's safe to turn the MMU off, but leave us in 32-bit config (and 32-bit mode)

Kevin Bracey's avatar
Kevin Bracey committed
1081
 [ :LNOT:No26bitCode
Neil Turton's avatar
Neil Turton committed
1082 1083
        BIC     lr, lr, #&FC000003              ; knock out PSR bits from return address
                                                ; (we know we were in 32-bit config, 26-bit mode on entry)
Kevin Bracey's avatar
Kevin Bracey committed
1084
 ]
Neil Turton's avatar
Neil Turton committed
1085
        ADD     lr, lr, r0                      ; and add on offset - NB this may now be above 64MB (on IOMD)
Neil Turton's avatar
Neil Turton committed
1086 1087

;mjs - the MMU off values are ok for all ARMs; some will ignore P,D,L bits
Neil Turton's avatar
Neil Turton committed
1088 1089 1090 1091 1092
 [ LateAborts
        MOV     r0, #MMUC_P :OR: MMUC_D :OR: MMUC_L ; turn MMU off, but leave us in 32-bit config, late aborts
 |
        MOV     r0, #MMUC_P :OR: MMUC_D         ; turn MMU off, but leave us in 32-bit config
 ]
Neil Turton's avatar
Neil Turton committed
1093
        ARM_write_control r0
Neil Turton's avatar
Neil Turton committed
1094 1095 1096

        MOV     pc, lr                          ; return to caller, but in physical address space

Neil Turton's avatar
Neil Turton committed
1097
        LTORG
Neil Turton's avatar
Neil Turton committed
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
; -> MemSize

; (non-destructive) algorithm to determine MEMC RAM configuration
;
; Dave Flynn and Alasdair Thomas
; 17-March-87
;
; Spooling checkered by NRaine and SSwales !
; 8MByte check bodged in by APT
;
; NOTE: Routines MemSize and TimeCPU are called by the power-on test software,
; so their specifications MUST not change.
;
; Set MEMC for 32-k page then analyse signature of possible
; external RAM configurations...
; The configurations are:
;
; Ram Size    Page Size    Configuration    (Phys RAM) Signature
;--------------------------------------------------------------------
;  16MByte      32k        4*32*1Mx1         A13,A20,A21,A22,A23,A23.5 distinct
;  16MByte      32k        16*8*256kx4       A13,A20,A21,A22,A23,A23.5 distinct
;
;  12MByte      32k        3*32*1Mx1         A13,A20,A21,A22,A23 OK, A23.5 fail
;  12MByte      32k        12*8*256kx4       A13,A20,A21,A22,A23 OK, A23.5 fail
;
;   8MByte      32k        2*32*1Mx1         A13,A20,A21,A22 distinct, A23 fail
;   8MByte      32k         8*8*256kx4       A13,A20,A21,A22 distinct, A23 fail
;
;   4Mbyte      32k          32*1Mx1         A13,A21,A20 distinct, A22,A23 fail
;   4Mbyte      32k         4*8*256kx4       A13,A21,A20 distinct, A22,A23 fail
;
;   2Mbyte      32k    expandable 2*8*256kx4 A13,A20 distinct, A21 fails
;   2Mbyte ???  16k      fixed 2*8*256kx4    A13,A21 distinct, A20 fails
;
;   1Mbyte       8k          32*256kx1       A13,A20 fail, A19,A18,A12 distinct
;   1Mbyte       8k           8*256kx1       A13,A20 fail, A19,A18,A12 distinct
;   1Mbyte       8k          4*8*64kx4       A13,A20 fail, A19,A18,A12 distinct
;
; 512Kbyte       8k    expandable 2*8*64kx4  A13,A20,A19 fail, A12,A18 distinct
; 512Kbyte       4k      fixed 2*8*64kx4     A13,A20,A12 fail, A19,A18 distinct
;
; 256Kbyte       4K           8*64kx4        A13,A20,A12,A18 fail, A21,A19 ok
; 256Kbyte       4K          32*64kx1        A13,A20,A12,A18 fail, A21,A19 ok
;

; MemSize routine... enter with 32K pagesize set
; R0 returns page size
; R1 returns memory size
; R2 returns value set in MEMC
; Can corrupt R3-R14

; Note that on a soft-loaded system, the 1st word of the image may be
; temporarily overwritten, but this is just the reset branch so it's OK.

; MMU is always off at this point, so we must use the physical address of PhysRAM
; Also we are entered in 32-bit config, 32-bit mode,
; but we exit in 32-bit config, 26-bit mode

 [ MorrisSupport
funnypatterns
        &       &66CC9933   ; 0110 1100 1001 0011
        &       &CC993366   ; 1100 1001 0011 0110
 ]

MemSize ROUT
        MOV     r13, lr                                 ;save in a register, cos we've got no stack

        MOV     r12, #IOMD_Base

 [ MorrisSupport
;
1169 1170 1171
        LDRB    r0, [r12, #IOMD_ID0]    ; load r1 with IOMD ID high byte
        LDRB    r1, [r12, #IOMD_ID1]    ; load r0 with IOMD ID low byte
        ORR     r0,r0,r1,LSL#8          ; Or r0 and r1, shifted left 8, put in r0
Neil Turton's avatar
Neil Turton committed
1172 1173 1174 1175 1176
        LDR     r1,=IOMD_Original       ; get Ref IOMD ID code - original
        CMP     r0,r1                   ; check for IOMD ID Code - original
        BEQ     MemSizeIOMD             ; Not ID Code - original,
                                        ;    therefore jump to Medusa hardware code
                                        ;    else fall through to Morris code.
Neil Turton's avatar
Neil Turton committed
1177 1178 1179
;
; MemSize for Morris
;
1180 1181 1182
  [ RO371Timings
        MOV     r11, #&70     ;all 4 banks assumed 32 bit - EDO and timing bits set in case 7500FE (don't care bits otherwise)
  |
Neil Turton's avatar
Neil Turton committed
1183
        MOV     r11, #IOMD_DRAMWID_DRAM_32bit * &0F     ;set all 4 banks to be 32bit initially
1184 1185 1186 1187
        LDR     r1, =IOMD_7500FE
        TEQ     r0, r1                                  ; are we on FE part?
        ORREQ   r11, r11, #IOMD_DRAMWID_EDO_Enable :OR: IOMD_DRAMWID_RASCAS_3 :OR: IOMD_DRAMWID_RASPre_3
                                                        ; if so, then enable EDO and slower RASCAS and RASPre times
Neil Turton's avatar
Neil Turton committed
1188
        ! 0,"7500FE support expects EDO memory in s.ARM600"
1189
  ]
Neil Turton's avatar
Neil Turton committed
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
        MOV     r14, #IOMD_Base
        STRB    r11, [r14, #IOMD_DRAMWID]
        MOV     r10, #0                                 ;indicate no RAM found yet
        MOV     r9, #IOMD_DRAMWID_DRAM_16bit            ;bit to OR into DRAMWID to set 16bit
        MOV     r0, #DRAM0PhysRam
;
; r0    DRAM address
; r9    IOMD_DRAMWID_DRAM_16bit for current DRAM bank
; r11   current IOMD_DRAMWID register contents
;
ExamineDRAMBank                                         ;examine first/next DRAM bank
;
        LDMIA   r0, {r1, r2}                            ;Preserve the two locations that we widdle on

        ADR     r3, funnypatterns                       ;We write different values to two locations
        LDMIA   r3, {r3, r4}                            ; incase bus capacitance holds our value
        STMIA   r0, {r3, r4}
        LDMIA   r0, {r5, r6}                            ;Reread test locations
        EORS    r5, r5, r3                              ;Both locations should read correctly
        EOR     r6, r6, r4                              ; if memory is 32bits wide
       ;TEQ     r5, #0
        TEQEQ   r6, #0
1212
        BEQ     %FT05                                   ;32bit wide memory
Neil Turton's avatar
Neil Turton committed
1213 1214 1215 1216 1217

        TST     r5, #&00FF                              ;If the bottom 16bits of each location
        TSTEQ   r5, #&FF00                              ; are correct, the memory is 16bits wide
        TSTEQ   r6, #&00FF
        TSTEQ   r6, #&FF00
1218
        ADDNE   r0, r0, #DRAM1PhysRam-DRAM0PhysRam      ; move onto next bank
Neil Turton's avatar
Neil Turton committed
1219 1220 1221
        BNE     NoRamInBank                             ;No memory in this bank

        ORR     r11, r11, r9                            ;Bank is 16bits wide
1222
05
Neil Turton's avatar
Neil Turton committed
1223 1224 1225 1226 1227
        STMIA   r0, {r1, r2}                            ;Restore the two locations we widdled on
                                                        ;Must do BEFORE poking the DRAMWID register
        MOV     r14, #IOMD_Base                         ;
        STRB    r11, [r14, #IOMD_DRAMWID]               ;

1228
        BL      Add_DRAM_bank
Neil Turton's avatar
Neil Turton committed
1229 1230 1231 1232 1233 1234

NoRamInBank
        MOV     r9, r9, LSL #1                          ; shunt up position in DRAMWID
        CMP     r9, #&0010                              ; if more banks to do
        BLT     ExamineDRAMBank                         ; then loop

1235 1236
        MOV     r6, #0                                  ; No VRAM
        MOV     r0, #0
Neil Turton's avatar
Neil Turton committed
1237 1238
        MOV     r14, #IOMD_Base

1239 1240 1241 1242 1243 1244
        LDRB    r4, [r14, #IOMD_ID0]
        LDRB    r7, [r14, #IOMD_ID1]
        ORR     r4, r4, r7, LSL #8
        LDR     r7, =IOMD_7500FE                        ; if FE part, then assume EDO DRAM
        TEQ     r4, r7
        LDREQ   r2, =80000000                           ; so allow 80E6 bytes/s
Neil Turton's avatar
Neil Turton committed
1245
 [ STB
1246
        LDRNE   r2, =44000000                           ; else only allow 44E6 bytes/s
Neil Turton's avatar
Neil Turton committed
1247
 |
1248
        LDRNE   r2, =46500000                           ; if no VRAM, then 46.5E6 bytes/sec bandwidth
Neil Turton's avatar
Neil Turton committed
1249
 ]
1250
        MOV     r1, #IOMD_VIDCR_DRAMMode :OR: &10       ; if no VRAM, then turn on DRAM mode, and set increment to &10
Neil Turton's avatar
Neil Turton committed
1251

1252
        B       Allocate_DRAM
Neil Turton's avatar
Neil Turton committed
1253 1254 1255 1256 1257 1258

MemSizeIOMD
 ]

; Right, let's find out where our memory is

Neil Turton's avatar
Neil Turton committed
1259 1260 1261 1262 1263 1264 1265 1266
; StrongARM - aha! but we still have no nice MMU, nor even fast core clock, and this memory sizing type
; stuff is going to be very slow for large memory. So turn on I cache (allowed with MMU off), and fast
; core clock now - this is then ok until MMU etc comes on (near CritStart)

        ARM_read_ID r2
        AND     r2,r2,#&F000
        CMP     r2,#&A000
        BNE     MemSizeIOMD_notSA
1267
    [ :LNOT: CacheOff
Neil Turton's avatar
Neil Turton committed
1268 1269 1270
        ARM_read_control r2
        ORR     r2,r2,#&1000     ;I cache bit is bit 12
        ARM_write_control r2
1271
    ]
Neil Turton's avatar
Neil Turton committed
1272
        ARMA_fastcoreclock
1273 1274 1275
  [ ARM810fastclock
        B       MemSizeIOMD_not810
  ]
Neil Turton's avatar
Neil Turton committed
1276
MemSizeIOMD_notSA
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
  [ ARM810fastclock
    ;fast clock for ARM 810 now
        ARM_read_ID r2
        AND     r2,r2,#&F000
        CMP     r2,#&8000
        BNE     MemSizeIOMD_not810
    [ ARM810usePLL
        ARM8_pll_fclk r2
    |
        ARM8_refclk_fclk r2
    ]
MemSizeIOMD_not810
  ]
Neil Turton's avatar
Neil Turton committed
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300

        MOV     r11, #IOMD_DRAMCR_DRAM_Large * &55      ; set all banks to be large initially
        MOV     r14, #IOMD_Base
        STRB    r11, [r14, #IOMD_DRAMCR]

        MOV     r10, #0                                 ; indicate no RAM found yet
        MOV     r9, #IOMD_DRAMCR_DRAM_Small             ; bit to OR into DRAMCR
        MOV     r0, #DRAM0PhysRam
10
        ADD     r1, r0, #A10                            ; this should be OK for both configurations
        BL      DistinctAddresses
1301 1302
        ADDNE   r0, r0, #DRAM1PhysRam-DRAM0PhysRam      ; move onto next bank
        BNE     %FT15                                   ; [no RAM in this bank at all]
Neil Turton's avatar
Neil Turton committed
1303 1304 1305 1306 1307 1308 1309

        ADD     r1, r0, #A11                            ; test for 256K DRAM
        BL      DistinctAddresses
        ORRNE   r11, r11, r9                            ; it is, so select small multiplexing
        MOVNE   r14, #IOMD_Base
        STRNEB  r11, [r14, #IOMD_DRAMCR]                ; store new value of DRAMCR, so we can use memory immediately

1310
        BL      Add_DRAM_bank
Neil Turton's avatar
Neil Turton committed
1311

1312
; Now, we have to find a bank of DRAM, so we've got somewhere to store our results!
Neil Turton's avatar
Neil Turton committed
1313 1314 1315 1316 1317
15
        MOV     r9, r9, LSL #2                          ; shunt up position in DRAMCR
        CMP     r9, #&100                               ; if more banks to do
        BCC     %BT10                                   ; then loop

1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
; Now, we check out the VRAM.
; Don't bother checking for more than 2M of VRAM, because we don't know what the 1/2 SAM length is for larger sizes

        MOV     r2, #IOMD_VREFCR_VRAM_256Kx64 :OR: IOMD_VREFCR_REF_16 ; assume 2 banks of VRAM by default
        STRB    r2, [r12, #IOMD_VREFCR]

        MOV     r0, #VideoPhysRam                       ; point at VRAM
        ADD     r1, r0, #A2                             ; test A2
        BL      DistinctAddresses
        MOVEQ   r6, #2                                  ; we've got 2M of VRAM
        BEQ     %FT20

        MOV     r2, #IOMD_VREFCR_VRAM_256Kx32 :OR: IOMD_VREFCR_REF_16
        STRB    r2, [r12, #IOMD_VREFCR]
        ADD     r1, r0, #A2                             ; check for any VRAM at all
        BL      DistinctAddresses
        MOVEQ   r6, #1                                  ; we've got 1M of VRAM
        MOVNE   r6, #0                                  ; no VRAM
20
 [ IgnoreVRAM
        MOV     r6, #0                                  ; pretend there's no VRAM
 ]
        CMP     r6, #1
        MOVCC   r1, #IOMD_VIDCR_DRAMMode :OR: &10       ; if no VRAM, then turn on DRAM mode, and set increment to &10
        MOVEQ   r1, #SAMLength/2/256                    ; if 1M VRAM, then use VRAM mode, and set increment for 1/2 SAM
        MOVHI   r1, #SAMLength/2/256*2                  ; if 2M VRAM, then use VRAM mode, and set increment for 2*1/2 SAM
        LDRCC   r2, =46500000                           ; if no VRAM, then 46.5E6 bytes/sec bandwidth
        LDREQ   r2, =80000000                           ; if 1M VRAM, then 80E6   ---------""--------
        LDRHI   r2, =160000000                          ; if 2M VRAM, then 160E6  ---------""--------
1347
        MOVCC   r0, #0                                  ; Clear VRAM base if there is no VRAM
1348 1349 1350 1351 1352 1353 1354 1355 1356

; Allocate_DRAM
;   r0  = Video base if r6!=0
;   r1  = Value for IOMD VIDCR
;   r2  = Bandwidth limit
;   r6  = VRAM size in Mb
;   r10 = End of DRAM list
Allocate_DRAM

Neil Turton's avatar
Neil Turton committed
1357
NoDRAMPanic
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389
        TST     r10, r10
        BEQ     NoDRAMPanic                             ; Stop here if there is no DRAM (we could use VRAM I suppose...)

        MOV     r7, r6, LSL #20                         ; r7 = size of video memory
        LDR     r8, [r10]                               ; r8 = the number of DRAM blocks.
        SUB     r11, r10, r8, LSL #3                    ; Jump back to the start of the list

        LDMIA   r11!, {r4, r5}                          ; Get a block from the list. (r4,r5) = (base,size)
        CMP     r6, #0                                  ; Did we find any VRAM?
        BNE     %FT30                                   ; Skip this bit if we did.
        MOV     r0, r4                                  ; Allocate this block as video memory
        MOV     r7, r5
        CMP     r10, r11                                ; Was this the only block?  If so, leave 1M
        SUBEQS  r7, r7, #1024*1024
        MOVCC   r7, r5, ASR #1                          ; If that overflowed, take half the bank.
        CMP     r7, #8*1024*1024
        MOVCS   r7, #8*1024*1024                        ; Limit allocation to 8M - the size of the logical space

        ADD     r4, r4, r7                              ; Adjust the DRAM block base...
        SUBS    r5, r5, r7                              ; ... and the size.
        LDMEQIA r11!, {r4, r5}                          ; Fetch the next block if we claimed it all.

30      ADD     r12, r4, #DRAMOffset_PageZero           ; Use the first block for kernel workspace.
        ADD     r3, r12, #DRAMPhysAddrA                 ; Set the table address as well

        CMP     r8, #5
        ADDCS   r10, r11, #3:SHL:3                      ; Limit to 4 blocks of DRAM (3 + this one)

35      STMIA   r3!, {r4, r5}                           ; Put the DRAM block into the table
        TEQ     r10, r11
        LDMNEIA r11!, {r4, r5}                          ; Get the next block if there is one.
        BNE     %BT35
Neil Turton's avatar
Neil Turton committed
1390 1391 1392

; Now go back and put the VRAM information in, and also program VIDCR and VIDCUR

1393 1394
 [ :LNOT:HAL
        STRB    r6, [r12, #VRAMWidth]                   ; store width of VRAM (0,1 or 2)
Neil Turton's avatar
Neil Turton committed
1395
        MOV     r14, #IOMD_Base
1396 1397 1398 1399
        STRB    r1, [r14, #IOMD_VIDCR]
        STR     r0, [r14, #IOMD_VIDCUR]                 ; set up VIDCUR to start of video RAM
        STR     r0, [r14, #IOMD_VIDSTART]               ; do same for VIDSTART
        STR     r0, [r14, #IOMD_VIDINIT]                ; and for VIDINIT
Neil Turton's avatar
Neil Turton committed
1400
                                                        ; so we don't get a mess when we turn video DMA on later
1401
        STR     r2, [r12, #VideoBandwidth]              ; store video bandwidth
Neil Turton's avatar
Neil Turton committed
1402

1403 1404
        ADD     r4, r0, #1024*1024-4096                 ; add on a bit to form VIDEND (will be on mult. of SAM)
        STR     r4, [r14, #IOMD_VIDEND]                 ; yes I know it's a bit of a bodge
Neil Turton's avatar
Neil Turton committed
1405

1406 1407
        MOV     r4, r6, LSL #20                         ; convert amount of VRAM to bytes
        STR     r4, [r12, #VRAMSize]                    ; and store
1408
  ]
Neil Turton's avatar
Neil Turton committed
1409

1410
        ADD     r2, r12, #VideoPhysAddr                 ; r2 -> Start of PhysRamTable
1411
        STMIA   r2, {r0, r7}                            ; store video memory block
Neil Turton's avatar
Neil Turton committed
1412 1413 1414 1415
MemSizeTotalRAM
; Now we have to work out the total RAM size

        MOV     r1, #0
1416 1417
        MOV     r7, r2
40
Neil Turton's avatar
Neil Turton committed
1418 1419
        LDMIA   r7!, {r4, r5}                           ; get address, size
        ADD     r1, r1, r5                              ; add on size
1420 1421
        TEQ     r7, r3
        BNE     %BT40
Neil Turton's avatar
Neil Turton committed
1422 1423 1424

        MOV     r0, #Page4K                             ; something to put in MEMC CR soft copy
                                                        ; (it's probably irrelevant)
1425
        ADRL    r4, ROM
1426 1427 1428 1429 1430 1431 1432

; r0 = Page size
; r1 = Total memory size (bytes)
; r2 = PhysRamTable
; r3 = After last used entry in PhysRamTable
; r4 = Address of ROM

Neil Turton's avatar
Neil Turton committed
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
; now store zeros to fill out table

55
        ADD     r5, r2, #PhysRamTableEnd-PhysRamTable
        MOV     r6, #0
        MOV     r7, #0
57
        CMP     r3, r5
        STMCCIA r3!, {r6, r7}
        BCC     %BT57

1444
 [ :LNOT: HAL
Neil Turton's avatar
Neil Turton committed
1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594
; Now set up L1 + L2
; - first work out how big static L2 needs to be
; - then zero L1 + L2 (L1 is actually inside L2)

        MOV     r3, r1, LSR #22                 ; r3 = memsize / 4M
        TEQ     r1, r3, LSL #22                 ; if any remainder
        ADDNE   r3, r3, #1                      ; then round up (r3 is now how many pages of L2 needed for free pool)
        MOV     r3, r3, LSL #12                 ; convert to bytes
        ADD     r3, r3, #FixedAreasL2Size       ; add on size of L2 for other fixed areas
        STR     r3, [r2, #L2PTSize-PhysRamTable] ; save away for future reference

        LDR     r2, [r2, #DRAMPhysAddrA-PhysRamTable]   ; get address of 1st DRAM bank
        LDR     r5, =DRAMOffset_L2PT
        ADD     r2, r2, r5                              ; make r2 -> L2PT
        MOV     r5, #0                          ; value to initialise L1 and L2 to (translation faults)
        MOV     r6, r5
        MOV     r7, r5
        MOV     r8, r5
        MOV     r9, r5
        MOV     r10, r5
        MOV     r11, r5
        MOV     r12, r5
        ADD     r2, r2, r3                      ; start at end and work back
60
        STMDB   r2!, {r5-r12}
        SUBS    r3, r3, #8*4
        BNE     %BT60

; r2 ends up pointing at L2

        ADD     r3, r2, #DRAMOffset_L1PT-DRAMOffset_L2PT        ; r3 -> L1Phys

; now initialise all the L1 for the area covered by the static L2, as if it were all page mapped
; - the section mapped stuff will be overwritten when we go thru MemInitTable shortly

        ORR     r5, r2, #L1_Page + L1_U         ; take phys base of L2, and or in other bits to form an L1 entry
        LDR     r6, =L2PTSize+DRAMOffset_PageZero-DRAMOffset_L2PT
        LDR     r10, [r2, r6]                   ; r10 = size of L2 (used after this loop, too)
        ADD     r6, r5, r10                     ; r6 = value in r5 when we've finished
        MOV     r7, r3                          ; r7 -> where we're storing L1 entries
61
        STR     r5, [r7], #4                    ; store L1 entry
        ADD     r5, r5, #1024                   ; advance L2 pointer
        TEQ     r5, r6
        BNE     %BT61

; now go through memory initialisation table, setting up entries

        ADR     r5, MemInitTable
65
        LDMIA   r5!, {r6-r8}                    ; load size, logaddr, indicator
        TEQ     r6, #0                          ; if size field is zero
        BEQ     %FT90                           ; then we've finished going through table

        TST     r8, #1                          ; if bit 0 of indicator is set, then it's page mapped
        BNE     %FT75

        TST     r8, #2                          ; is it abort?
        BNE     %FT68                           ; [no]

; it's a section abort (r8=0)

66
        STR     r8, [r3, r7, LSR #20-2]         ; store zero in L1 table
        ADD     r7, r7, #&00100000              ; increment logical address by 1M
        SUBS    r6, r6, #&00100000              ; and decrement size by 1M
        BNE     %BT66                           ; loop until done
        B       %BT65


68
; it's section mapped

        TST     r8, #ROMbit                     ; is it a ROM image offset
        ADDNE   r8, r8, r4                      ; if so, then add in image offset
        BICNE   r8, r8, #ROMbit                 ; and knock out the dodgy bit

        TST     r8, #Vidbit                     ; is it a video memory offset
        LDRNE   r9, =VideoPhysAddr+DRAMOffset_PageZero-DRAMOffset_L2PT
        LDRNE   r9, [r2, r9]                    ; get physical address of video RAM
        ADDNE   r8, r8, r9                      ; add on offset
        BICNE   r8, r8, #Vidbit                 ; and knock out the dodgy bit
70
        STR     r8, [r3, r7, LSR #20-2]         ; store entry in L1 table (assumes bits 18, 19 are clear!)
        ADD     r7, r7, #&00100000              ; increment logical address by 1M
        ADD     r8, r8, #&00100000              ; and physical address by 1M
        SUBS    r6, r6, #&00100000              ; and decrement size by 1M
        BNE     %BT70                           ; if we've not finished then loop
        B       %BT65                           ; else go back to main loop

; explicit L2 setup

75
        CMP     r6, #-1                         ; if size <> -1
        BNE     %FT80                           ; then normal

; size = -1 => this is the chunk with the soft CAM map in it,
; so we must work out a suitable size (and store it in SoftCamMapSize)
; we also have to work out the correct offset in the DRAM bank, since this is
; after variable size L2PT

        MOV     r6, r1, LSR #24-3               ; number of pages for cam map
        CMP     r1, r6, LSL #24-3               ; if bits dropped off
        ADDNE   r6, r6, #1                      ; then need one more page
        MOV     r6, r6, LSL #12
        LDR     r9, =DRAMOffset_PageZero-DRAMOffset_L2PT+SoftCamMapSize
        STR     r6, [r2, r9]                    ; store size used
        ADD     r6, r6, #UndStackSize           ; chunk also includes undstack
        ADD     r9, r10, #DRAMOffset_L2PT       ; undstack/cammap starts at offset L2PT + L2PTSize
        ORR     r8, r8, r9                      ; OR in other misc bits from table
80
        LDR     r9, =DRAMOffset_PageZero-DRAMOffset_L2PT+DRAMPhysAddrA
                                                ; offset from L2 to word containing physical address of 1st DRAM bank
        LDR     r9, [r2, r9]                    ; r9 = address of 1st DRAM bank
        ADD     r8, r8, r9                      ; convert offset to address
        EOR     r8, r8, #L2_SmallPage :EOR: 1   ; make bottom 2 bits correct for L2
        ADD     r9, r2, r7, LSR #10             ; r9 -> L2 for this page
85
        STR     r8, [r9], #4                    ; store entry in L2
        ADD     r8, r8, #4*1024                 ; advance physical page address
        SUBS    r6, r6, #4*1024                 ; one less page to do
        BNE     %BT85
        B       %BT65

; L1 is now set up correctly, and L2 has the correct CB bits, but no accessible pages
; Put in the L2 entries for the logical area we are going to access the L2 (and L1) at
; r10 still holds L2PT size

90
        ADD     r5, r2, #(L2PT :SHR: 10)        ; r5 -> start of L2PT for L2 logical address
        LDR     r6, =(AP_None * L2_APMult) + L2_SmallPage ; r6 = other gubbins to put in L2 entries (not C or B)
        ORR     r6, r6, r2                      ; OR in physical address of L2
        MOV     r7, r10                         ; amount to put in (L2PTSize)
95
        STR     r6, [r5], #4                    ; store entry
        ADD     r6, r6, #4096                   ; move onto next page
        SUBS    r7, r7, #4096                   ; one less page to do
        BNE     %BT95                           ; loop until done

; But before we turn on, we have to temporarily make the addresses we are currently executing out of
; into a section mapped area straight through, so we don't crash before we can jump up into ROM area

        ASSERT ((CritStart :EOR: CritEnd) :AND: &FFF00000)=0    ; make sure start and end are in the same MB chunk

        ADR     r5, CritStart                   ; point at critical region start
        MOV     r5, r5, LSR #20                 ; divide by 1MB
        LDR     r6, [r3, r5, LSL #2]            ; get current L1 entry to put back later
        MOV     r7, r5, LSL #20                 ; r7 = physical address of base of section
        ORR     r7, r7, #(AP_None * L1_APMult)
        ORR     r7, r7, #L1_Section
Neil Turton's avatar
Neil Turton committed
1595
        STR     r7, [r3, r5, LSL #2]            ; store replacement entry in L1 (not U,C or B)
Neil Turton's avatar
Neil Turton committed
1596

Neil Turton's avatar
Neil Turton committed
1597
        ARM_MMU_transbase r3                    ; set up MMU pointer to L1
Neil Turton's avatar
Neil Turton committed
1598 1599 1600
        ADD     r3, r3, #PhysSpace              ; when we put L1 entry back later, we need to use the copy in PhysSpace area

        MOV     r7, #1
Neil Turton's avatar
Neil Turton committed
1601 1602 1603
        ARM_MMU_domain r7                       ; only use domain 0

        ARM_flush_cacheandTLB r7                ; flush cache + TLB just in case
Neil Turton's avatar
Neil Turton committed
1604

Neil Turton's avatar
Neil Turton committed
1605
        ARM_number r2                           ;should be 6,7,8 or &A
1606 1607 1608
 [ ARM810support
   ;ARM810 has already had fast clock selected (MemSizeIOMD) - so has StrongARM, therefore code below removed
 |
Neil Turton's avatar
Neil Turton committed
1609 1610
        CMP     r2,#&A
        ARMA_fastcoreclock EQ                   ;otherwise StrongARM is going to have a limp wrist
1611
 ]
Neil Turton's avatar
Neil Turton committed
1612 1613 1614
        SUB     r2,r2,#6                        ; r2 := 0..4 for ARM 6,7,8,(9),&A
        ADRL    r7,ARM_default_MMU_CR_table
        LDR     r7,[r7,r2,LSL #2]               ;get appropriate default value for MMU control reg
Neil Turton's avatar
Neil Turton committed
1615 1616

CritStart
Neil Turton's avatar
Neil Turton committed
1617
        ARM_write_control r7
Neil Turton's avatar
Neil Turton committed
1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628

; now we can jump into the ROM space (if we're not already there)

        RSB     r4, r4, #ROM                    ; make offset from current address to ROM
        ADD     pc, pc, r4                      ; jump up into ROM area
        NOP                                     ; this instruction will be skipped

; now put back the L1 entry we messed up

        STR     r6, [r3, r5, LSL #2]
CritEnd                                         ; 2 words after we go up into ROM
Neil Turton's avatar
Neil Turton committed
1629
        ARM_flush_TLB r2                        ; flush TLB (no need to flush cache, as there's nothing in it)
Neil Turton's avatar
Neil Turton committed
1630 1631 1632 1633

        SetMode UND32_mode, r7
        LDR     r13_undef, =UNDSTK              ; set up undefined mode stack pointer

Kevin Bracey's avatar
Kevin Bracey committed
1634 1635 1636 1637 1638 1639
 [ No26bitCode
        SetMode ABT32_mode, r7
        LDR     r13_abort, =ABTSTK              ; set up abort mode stack pointer

        SetMode SVC32_mode, r7                  ; RISC OS is 32 bit now. yay!
 |
Neil Turton's avatar
Neil Turton committed
1640
        SetMode SVC26_mode, r7                  ; switch into 26-bit mode
Kevin Bracey's avatar
Kevin Bracey committed
1641
 ]
Neil Turton's avatar
Neil Turton committed
1642 1643 1644 1645 1646 1647 1648 1649 1650
        ADD     r13, r13, r4                    ; adjust return address

        LDR     r2, ResetMemC_Value
        BIC     r2, r2, #&C
        ORR     r2, r2, r0
        MOV     r0, #4*1024                     ; r0 = true page size (now split off
                                                ; from MEMC control register)
        MOV     pc, r13

1651 1652
 ] ; :LNOT: HAL

1653 1654 1655 1656 1657 1658 1659 1660
; add_dram_bank
;   Entry: r10 -> workspace (initially 0)
;          r0  =  bank address
;   Exit:  r10 -> workspace (allocated if 0 on entry)
;          r0  =  next bank address
;          r9, r11, r13 preserved
;   Probe a DRAM bank, and add any DRAM found to the workspace
Add_DRAM_bank
1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700
        ROUT
        MOV     r12, lr                 ; r12 = return address
        EOR     r1, r0, #A16            ; Check there is some RAM in the bank
        BL      DistinctAddresses
        ADDNE   r0, r0, #DRAM1PhysRam-DRAM0PhysRam
        MOVNE   pc, r12                 ; Return if no RAM in the bank

        ; Only some address lines are decoded by the SIMM.  For example, a 4M SIMM may be split
        ; into 2 banks, with A2-A20 decoded on each, or A2-A19,A21 decoded.  First we need to
        ; find out which address lines are decoded, and which are ignored.
        MOV     r6, #DRAM1PhysRam-DRAM0PhysRam
        MOV     r7, #A17
        SUB     r6, r6, #1              ; Get address lines which select address within bank.

        ; Loop through the address lines, finding out which are decoded.  We clear the bits in r6
        ; which correspond to non-decoded address lines.
        ; r6 = address line mask
        ; r7 = current address line
10      EOR     r1, r0, r7              ; Toggle the address line
        BL      DistinctAddresses       ; Check if address line has any effect.
        BICNE   r6, r6, r7              ; Clear the bit if the address line fails.
        MOV     r7, r7, LSL #1          ; Move onto the next address line.
        TST     r6, r7                  ; Have we reached the limit?
        BNE     %BT10                   ; Repeat if not.

        ; r6 = decoded address lines in bank. (ie in A0-A25)
        ; r7 = The size of the DRAM bank
        ; Since the DRAM bank may not be contiguous, we now split the bank up into contiguous
        ; blocks.  We make these as large as possible to save work.  Here we set r8 to the
        ; size of the smallest contiguous block(s) of RAM.  (There will also be some contiguous
        ; blocks which are twice this size in some cases.)
        ADD     r8, r6, #A17
        BIC     r8, r8, r6              ; r8 = First clear bit in r6 from A17 up.

        RSB     r4, r8, #0              ; r4 = All bits at or above r8 set since r8 is a power of 2.

        RSB     r7, r7, #0              ; r7 = address bits which select the bank since r7 was a
                                        ;      power of 2.
        ORR     r3, r7, r6              ; r3 = All decoded address lines.
        AND     r7, r4, r3              ; r7 = All decoded bits at or above r8.
1701 1702 1703 1704

; Make sure that the dram bank may not be contained within the image.  The code below fails
; to work correctly if a dram bank is contained within an OS image.  Currently this would
; require an image larger than 64M.
1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754
                ASSERT  OSROM_ImageSize*1024 <= DRAM1PhysRam-DRAM0PhysRam

15      MOV     r1, r0                  ; r1 = Address of start of block (inclusive).
        ADD     r2, r1, r8              ; r2 = End of the block (exclusive).

        ; Move the end of the block if the OS image begins in this block.
        ADRL    r4, ROM                 ; r4 = Start of the OS image (which may be in RAM).
        EOR     r5, r4, r1              ; r5 = Difference between image and memory block.
        TST     r5, r7                  ; Check if the image begins in this block of RAM.
        ANDEQ   r2, r4, r3              ; Set end of block to start of image.

        ; Move the start of the block if the OS image ends in this block.
        ADD     r4, r4, #OSROM_ImageSize*1024
        SUB     r4, r4, #1              ; r4 = Last byte of the OS image.
        EOR     r5, r4, r1              ; r5 = Difference between end of image and block.
        TST     r5, r7                  ; Check if the image ends in this block of RAM.
        ANDEQ   r5, r4, r3              ; r5 = Address of last byte of the image within this block.
        ADDEQ   r1, r5, #1              ; Set start of block to the byte after the image.

        ; If the image is contained in the block, we will have swapped the start and end
        ; addresses.  This means that the block is split into two parts.  The bit below
        ; the image and the bit above the image.
        CMP     r1, r2
        BLS     %FT20                   ; If start <= end, then block is not fragmented.
        CMP     r2, r0                  ; Check the size of the fragment before the image.
        MOV     r0, r1                  ; Store old start address
        AND     r1, r1, r7              ; Get the start of the block
        BLNE    Allocate_DRAM_fragment  ; Allocate it if it's non-zero.
        MOV     r1, r0                  ; Restore the old start of fragment
        AND     r0, r0, r7              ; Get the start of the block again.
        ADD     r2, r0, r8              ; End of next fragment is the end of the block.

        CMP     r1, r2                  ; Compare start and (modified) end.
20      BLNE    Allocate_DRAM_fragment

        ; Now move onto the next block.  We add the non-decoded address lines to cause the
        ; carry to be propagated across them.  Then we mask them out.
        MVN     r4, r7                  ; Add the non-connected address lines to ...
        ADD     r4, r4, r0              ; ... the block address ...
        ADD     r4, r4, r8              ; ... and the block size.
;       EOR     r5, r0, r4              ; Compare with old address
        AND     r0, r4, r7              ; Leave only the decoded lines set.
;       BIC     r5, r5, r6              ; Clear decoded lines within the bank.
;       TST     r5, r7                  ; Check only the bank lines.
;       BEQ     %BT15                   ; Repeat for next block.

        TST     r0, r6
        BNE     %BT15

        MOV     pc, r12                 ; Done for this bank.
1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770

; Allocate_DRAM_block
;   Entry:
;     r1 = block start (inclusive)
;     r2 = block end (exclusive)
;     r3 = All decoded address lines
;     r7 = All decoded bits at or above r8
;     r8 = Size of largest contiguous block
;     block length is assumed to be at least the size of the static data - ie. 160k
;     The maximum block list size is then 4k, which fits easily into the cursor chunk
;   Exit:
;     r10 updated
;     r0, r3, r6-r9, r11-r13 preserved
;     r10 points to a word containing the number of blocks stored.
;     The pairs of words before
Allocate_DRAM_fragment
1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
        ROUT
        CMP     r10, #0
        BEQ     %FT20

        ; We are not dealing with the first block since r10 != 0.  Make an attempt to merge this block
        ; with the previous block.
        LDMDB   r10, {r4, r5}           ; Get details of the previous block
        ADD     r5, r4, r5              ; Get the end address
        EOR     r5, r5, r1              ; Compare with the current block start address...
        TST     r5, r3                  ; ... but only check the decoded bits.
        EOR     r5, r5, r1              ; Restore the previous block end address.
        BNE     %FT10                   ; We can't merge it after the previous block

        ; r4 = previous start
        ; r5 = previous end
        ; The block is just after the previous block.  That means the start address is unchanged, but
        ; the length is increased.
        SUB     r5, r5, r4              ; Calculate the previous block length.
        SUB     r2, r2, r1              ; Find the length of the new block.
        ; r2 = length of block
        ADD     r5, r5, r2              ; Add it to the previous length.
        STR     r5, [r10, #-4]          ; Update the block size in memory.
        MOV     pc, lr

        ; The block is not just after the previous block, but it may be just before.  This may be the
        ; case if we are softloaded.
10      SUB     r4, r4, #1              ; Compare the address before the previous block start ...
        SUB     r2, r2, #1              ; ... with the address of the last byte in this block ...
        EOR     r4, r4, r2
        TST     r4, r3                  ; ... but check only the decoded bits.
        ADD     r2, r2, #1              ; Restore the end address.
        BNE     %FT20                   ; Skip if we cannot merge the block.

        ; The block is just before the previous block.  The start address and length both change.
        LDR     r4, [r10, #-8]          ; Get the previous block start again.

        SUB     r2, r2, r1              ; Calculate the current block size.
        SUB     r4, r4, r2              ; Subtract from the previous block start address.
        SUB     r5, r5, r4              ; Calculate the new length=end-start
        STMDB   r10, {r4, r5}           ; Update the block info in memory.
        MOV     pc, lr

        ; We now have a region which does not merge with a previous region.  We move it up to the
        ; highest address we can in the hope that this block will merge with the next block.
20      SUB     r2, r2, r1              ; Calculate the block size
        MVN     r4, r3                  ; Get the non-decoded address lines.
        ORR     r1, r4, r1              ; Set the non-decoded address bit in the start address.

30      CMP     r10, #0                 ; If the workspace has not been allocated...
        MOVEQ   r10, r1                 ; ... use this block.
        MOVEQ   r4, #0                  ; Initialise the counter.

        ; The block/fragment to be added is between r1 and r1+r2.
        LDRNE   r4, [r10]               ; Get the old counter if there was one.
        STMIA   r10!, {r1, r2}          ; Store address and size.
        ADD     r4, r4, #1              ; Increment the counter.
        STR     r4, [r10]               ; Store the counter.

        MOV     pc, lr                  ; We've done with this block now.
1830 1831 1832



Neil Turton's avatar
Neil Turton committed
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899
; Memory map initialisation table
; Consists of word triplets (size,logaddr,type)
; where size    is size in bytes of area (size=0 terminates list)
;       logaddr is the base logical address of area
;       type is one of 5 formats:
;       a) a standard section-mapped L1 entry (physical address gets incremented for each MB in size)
;       b) like a section-mapped L1 entry, but with bit 12 set (address field holds base offset from "ROM" image)
;       c) like a section-mapped L1 entry, but with bit 13 set (address field holds base offset from start of video RAM)
;       d) like a page-mapped L1 entry, which indicates a page-mapped area to fill in
;          the L2 for. In this case the other bits are as follows:-
;               Bits 3,2   - CB respectively
;               Bits (11,10),(9,8),(7,6),(5,4) - access privileges
;               Bits 31-12 - offset in 1st DRAM bank to start of these pages (in units of pages)
;          If the size field contains -1, then it is the SoftCAMMap, and the appropriate size should be worked out,
;           and stored in SoftCamMapSize. Also, since the size of the L2 is variable the offset into the DRAM bank
;           of the SoftCamMap is unknown at assembly time, so the offset bits in table are zero.
;       e) zero - indicating that this area should abort (only necessary for section mapped bits in 48M-64M, cause they
;           have no level 2, therefore section must abort) - used for VIDC1 emulation area.
;       Note in case d), the L1 is not actually touched (it should have already been set up to point to the right L2)
;

ROMbit  *       1 :SHL: 12
Vidbit  *       1 :SHL: 13
PSS     *       PhysSpaceSize           :SHR: 20  ; Number of megabytes in physical space (used in table generation)

        MACRO
        MemInitSection  $size, $U, $C, $B, $logaddr, $ap, $physaddr
        &       ($size)*&00100000
        &       $logaddr
        &       (($U)*L1_U):OR:(($C)*L1_C):OR:(($B)*L1_B):OR:(($ap)*L1_APMult):OR:$physaddr:OR:L1_Section
        MEND

        MACRO
        MemInitROMs     $size, $U, $C, $B, $logaddr, $ap
        &       ($size)*&00100000
        &       $logaddr
        &       (($U)*L1_U):OR:(($C)*L1_C):OR:(($B)*L1_B):OR:(($ap)*L1_APMult):OR:ROMbit:OR:L1_Section
        MEND

        MACRO
        MemInitVideo    $size, $U, $C, $B, $logaddr, $ap
        &       ($size)*&00100000
        &       $logaddr
        &       (($U)*L1_U):OR:(($C)*L1_C):OR:(($B)*L1_B):OR:(($ap)*L1_APMult):OR:Vidbit:OR:L1_Section
        MEND

        MACRO
        MemInitAbort    $size, $logaddr
        &       ($size)*&00100000
        &       $logaddr
        &       0
        MEND

        MACRO
        MemInitPagesL2  $size, $C, $B, $logaddr, $ap, $dramoffset
        &       ($size)
        &       $logaddr
        &       (($C)*L1_C):OR:(($B)*L1_B):OR:(($ap)*L2_APMult):OR:$dramoffset:OR:L1_Page
        MEND

MemInitTable    ;       sz, U, C, B, logaddr,   (ap,     (physaddr))
        MemInitSection   4, 1, 0, 0, &03000000, AP_None, &03000000      ; I/O

        MemInitAbort     1,          &03400000                          ; VIDC1 emulation zone
        MemInitSection   1, 1, 0, 0, &03500000, AP_None, &03400000      ; VIDC20 space
        MemInitSection   2, 1, 0, 0, &03600000, AP_None, &03600000      ; LAGs

1900 1901 1902 1903 1904 1905 1906 1907
 [ OSROM_ImageSize >= 8192
        ; We will map in the whole ROM, but only the first 8M will fall in the 26-bit
        ; address space, and be available for modules.
        MemInitROMs      (OSROM_ImageSize / 1024), 1, 1, 1, &03800000, AP_Read
 |
  [ STB
   [ ExtROMSupport                                                      ; System build option
        ASSERT (OSROM_ImageSize <= 4096)                                ; No room for extension ROMs with an 8MB OS image
Neil Turton's avatar
Neil Turton committed
1908 1909
        MemInitROMs      4, 1, 1, 1, &03800000, AP_Read                 ; ROM
        MemInitSection   4, 1, 1, 1, &03C00000, AP_Read, &01000000      ; Extension ROM
1910 1911 1912
   |
        MemInitROMs      8, 1, 1, 1, &03800000, AP_Read                 ; ROM (1st or 2nd bank)
   ]
Neil Turton's avatar
Neil Turton committed
1913
  |
Neil Turton's avatar
Neil Turton committed
1914 1915 1916 1917 1918 1919 1920 1921 1922
        [ OSROM_ImageSize = 4096
        MemInitROMs      4, 1, 1, 1, &03800000, AP_Read                 ; ROM
        MemInitROMs      4, 1, 1, 1, &03C00000, AP_Read                 ; ROM
        |
        MemInitROMs      2, 1, 1, 1, &03800000, AP_Read                 ; ROM
        MemInitROMs      2, 1, 1, 1, &03A00000, AP_Read                 ; ROM
        MemInitROMs      2, 1, 1, 1, &03C00000, AP_Read                 ; ROM
        MemInitROMs      2, 1, 1, 1, &03E00000, AP_Read                 ; ROM
        ]
Neil Turton's avatar
Neil Turton committed
1923
  ]
1924
 ]
Neil Turton's avatar
Neil Turton committed
1925

1926
 [ :LNOT: HAL
Neil Turton's avatar
Neil Turton committed
1927
        MemInitSection PSS, 1, 0, 0, PhysSpace, AP_None, &00000000      ; map of physical space
1928
 ]
Neil Turton's avatar
Neil Turton committed
1929

Kevin Bracey's avatar
Kevin Bracey committed
1930
 [ ShadowROM
Neil Turton's avatar
Neil Turton committed
1931 1932 1933 1934
        MemInitROMs      2, 1, 1, 1, &FF800000, AP_Read                 ; ROM
        MemInitROMs      2, 1, 1, 1, &FFA00000, AP_Read                 ; ROM
        MemInitROMs      2, 1, 1, 1, &FFC00000, AP_Read                 ; ROM
        MemInitROMs      2, 1, 1, 1, &FFE00000, AP_Read                 ; ROM
Kevin Bracey's avatar
Kevin Bracey committed
1935
 ]
Neil Turton's avatar
Neil Turton committed
1936 1937 1938

; Now explicit initialisation of L2 for static pages

1939
 [ :LNOT: HAL
Neil Turton's avatar
Neil Turton committed
1940
        MemInitPagesL2  &8000, 0, 0, CursorChunkAddress, AP_Read, DRAMOffset_CursorChunk  ;but see L1L2PTenhancements
Neil Turton's avatar
Neil Turton committed
1941 1942
        MemInitPagesL2  &8000, 1, 1, &00000000, AP_Full, DRAMOffset_PageZero
        MemInitPagesL2  &8000, 1, 1, SysHeapChunkAddress, AP_Full, DRAMOffset_SystemHeap
Neil Turton's avatar
Neil Turton committed
1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953

  [ StrongARM
;StrongARM requires 2*16k of private logical space (used for absolutely nothing else), which is
;readable and cacheable, for data cache cleaning purposes. We want to map the space to
;start of ROM bank 1 (physical target), so that IOMD timings can be poked for maximum read speed
;(only requirement of physical space is that it is readable without h/w abort). Here, though,
;we have to conform to format for MemInitPagesL2, so we just point to some convenient RAM,
;and fix things up later (see L1L2PTenhancements)
;
        MemInitPagesL2  &8000, 1, 1, ARMA_Cleaners_address, AP_Read, DRAMOffset_PageZero
  ]
Kevin Bracey's avatar
Kevin Bracey committed
1954 1955 1956
  [ No26bitCode
        MemInitPagesL2  AbtStackSize, 1, 1, AbtStack, AP_Read, DRAMOffset_AbortStack
  ]
Neil Turton's avatar
Neil Turton committed
1957

Neil Turton's avatar
Neil Turton committed
1958
        MemInitPagesL2     -1, 1, 1, UndStackSoftCamChunk, AP_Full, 0   ; variable offset and size
1959
 ]
Neil Turton's avatar
Neil Turton committed
1960 1961 1962

        &       0, 0, 0                                                 ; terminate table

Neil Turton's avatar
Neil Turton committed
1963
        LTORG
Neil Turton's avatar
Neil Turton committed
1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048

; DistinctAddresses routine...
; r0,r1 are the addresses to check
; uses r2-5
; writes interleaved patterns (to prevent dynamic storage...)
; checks writing every bit low and high...
; return Z-flag set if distinct

; This routine must work in 32-bit mode

DistinctAddresses ROUT
        LDR     r2, [r0] ; preserve
        LDR     r3, [r1]
        LDR     r4, Pattern
        STR     r4, [r0] ; mark first
        MOV     r5, r4, ROR #16
        STR     r5, [r1] ; mark second
        LDR     r5, [r0]
        CMP     r5, r4 ; check first
        BNE     %10    ; exit with Z clear
        LDR     r5, [r1] ; check second
        CMP     r5, r4, ROR #16 ; clear Z if not same
        BNE     %10
; now check inverse bit writes
        STR     r4, [r1] ; mark second
        MOV     r5, r4, ROR #16
        STR     r5, [r0] ; mark first
        LDR     r5, [r1]
        CMP     r5, r4 ; check second
        BNE     %10   ; exit with Z clear
        LDR     r5, [r0] ; check first
        CMP     r5, r4, ROR #16 ; clear Z if not same
10      STR     r3, [r1] ; restore
        STR     r2, [r0]
        MOV     pc, lr                  ; Z flag is already set up, and other flags don't matter

Pattern
        &       &AAFF5500 ; shiftable bit check pattern

; init state with masked out page size

ResetMemC_Value
        & &E010C :OR: MEMCADR       ; slugged ROMs + flyback refresh only + 32K page

; Constants
;
A0      *       1 :SHL: 00
A1      *       1 :SHL: 01
A2      *       1 :SHL: 02
A3      *       1 :SHL: 03
A4      *       1 :SHL: 04
A5      *       1 :SHL: 05
A6      *       1 :SHL: 06
A7      *       1 :SHL: 07
A8      *       1 :SHL: 08
A9      *       1 :SHL: 09
A10     *       1 :SHL: 10
A11     *       1 :SHL: 11
A12     *       1 :SHL: 12
A13     *       1 :SHL: 13
A14     *       1 :SHL: 14
A15     *       1 :SHL: 15
A16     *       1 :SHL: 16
A17     *       1 :SHL: 17
A18     *       1 :SHL: 18
A19     *       1 :SHL: 19
A20     *       1 :SHL: 20
A21     *       1 :SHL: 21
A22     *       1 :SHL: 22
A23     *       1 :SHL: 23
A24     *       1 :SHL: 24
A25     *       1 :SHL: 25
A26     *       1 :SHL: 26
A27     *       1 :SHL: 27
A28     *       1 :SHL: 28
A29     *       1 :SHL: 29
A30     *       1 :SHL: 30
A31     *       1 :SHL: 31

Page32K * &C ; in MEMC control reg patterns...
Page16K * &8
Page8K  * &4
Page4K  * &0

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2049
; In    r0=0 -> Coming from the Test routine - no fancy business!
Neil Turton's avatar
Neil Turton committed
2050
;       r1-r6 trashable
2051
;       [[[ r9 = Current MEMC CR (true MEMC value, not fudged to look like 4K page size) ]]]
Neil Turton's avatar
Neil Turton committed
2052

2053
; Out   [[[ r9 MEMC value with slowest ROM speed, correct pagesize ]]]
Neil Turton's avatar
Neil Turton committed
2054 2055
;       r7 processor speed in kHz, bit 16 => can do STM to I/O (ie MEMC1a, MEMC2), bit 17 => MEMC2

Neil Turton's avatar
Neil Turton committed
2056
; This routine must work in 32-bit mode, and should not use any memory!!!!
Neil Turton's avatar
Neil Turton committed
2057

2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098
  [ RO371Timings

TimeCPU ROUT         ;does not actually measure anything - assumes timings (and EDO for 7500FE) according to IOMD id

        MOV     r2, #IOC                ; Address of the IO controller  (IOMD)

        LDRB    r7, [r2, #IOMD_ID0]     ; Is
        CMP     r7, #&E7                ; It
        LDRB    r7, [r2, #IOMD_ID1]     ; A
        CMPEQ   r7, #&D4                ; Risc PC ?
        BEQ     timecpuriscpc
        CMP     r7, #&AA                ; assume 7500 or 7500FE
        BEQ     timecpu7500FE
;7500 then
        MOV     r7, #&32                      ; 5-3 cycle ROM access
        STRB    r7, [r2, #IOMD_ROMCR0]
        STRB    r7, [r2, #IOMD_ROMCR1]
        MOV     r7, #&07                      ; clock dividers: /1 for I/O, /1 for CPU, /1 for memory
        STRB    r7, [r2, #IOMD_CLKCTL]
        LDR     r7, =(1 :SHL: 16) :OR: 16000  ; assumed 16MHz RAM (32 MHz bus)
        MOV     pc, lr

timecpu7500FE
;set memory to 32MHz for early boot (avoid probs with POST and with power-on key detection)
        MOV     r7, #&12                      ; 5-3 cycle ROM access, half speed (ie. 10-6)
        STRB    r7, [r2, #IOMD_ROMCR0]
        STRB    r7, [r2, #IOMD_ROMCR1]
        MOV     r7, #&70                      ; EDO RAM, 32 bit wide, conservative RAS and CAS timing
        STRB    r7, [r2, #IOMD_DRAMWID]       ; DRAM control reg. (more than just width on FE)
        MOV     r7, #&04                      ; clock dividers: /1 for CPU, /2 for memory, /2 for I/O
        STRB    r7, [r2, #IOMD_CLKCTL]
        LDR     r7, =(1 :SHL: 16) :OR: 32000  ; assumed 32MHz RAM (64 MHz bus), even though /2 at the moment
        MOV     pc, lr

timecpuriscpc
        MOV     r7, #&12                      ; 5-3 cycle ROM access
        STR     r7, [r2, #IOMD_ROMCR0]
        STR     r7, [r2, #IOMD_ROMCR1]
        LDR     r7, =(1 :SHL: 16) :OR: 16000  ; assumed 16MHz RAM (32 MHz bus)
        MOV     pc, lr

Kevin Bracey's avatar
Kevin Bracey committed
2099
 [ :LNOT: HAL
2100 2101 2102 2103 2104
;used by NewReset, after main kernel boot
;sets full 64MHz memory if on 7500FE
;preserves registers _and_ flags
;
finalmemoryspeed ROUT
Kevin Bracey's avatar
Kevin Bracey committed
2105
        EntryS  r0
2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117
        MOV     lr, #IOC
        LDRB    r0, [lr, #IOMD_ID0]     ; Is
        CMP     r0, #&E7                ; It
        LDRB    r0, [lr, #IOMD_ID1]     ; A
        CMPEQ   r0, #&D4                ; Risc PC ?
        BEQ     fmspeed_done
        CMP     r0, #&AA                ; EQ if 7500FE
        MOVEQ   r0, #&80
        STREQB  r0, [lr, #&CC]          ; ASTCR register: set i/o asynchronous timing for fast memory clock
        MOVEQ   r0, #&06                ; clock dividers: /1 for CPU, /1 for memory, /2 for I/O
        STREQB  r0, [lr, #IOMD_CLKCTL]
fmspeed_done
Kevin Bracey's avatar
Kevin Bracey committed
2118
        EXITS                           ; ***KJB - flag preservation necessary?
Kevin Bracey's avatar
Kevin Bracey committed
2119
 ]
2120 2121 2122

  | ; else if not RO371Timings

Neil Turton's avatar
Neil Turton committed
2123 2124 2125
ncpuloops * 1024 ; don't go longer than 4ms without refresh !
nmulloops * 128

Neil Turton's avatar
Neil Turton committed
2126 2127
TimeCPU ROUT            ;ONLY WORKS FOR IOMD(L) machines - this shouldn't be a problem though
 [ :LNOT: AutoSpeedROMS
Neil Turton's avatar
Neil Turton committed
2128 2129
        LDR     r7, =(1 :SHL: 16) :OR: 16000    ; indicate 16MHz RAM
 |
Neil Turton's avatar
Neil Turton committed
2130 2131 2132

   [ {TRUE}
;don't do timing for Risc PC
2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144
;
;MJS bug fix (since 3.70) - setup r3 properly, and don't corrupt r0 you fool
;
        MOV     r3, #IOC                ; Address of the IO controller
        LDRB    r7, [r3, #IOMD_ID0]     ; Is
        CMP     r7, #&E7                ; It
        LDRB    r7, [r3, #IOMD_ID1]     ; A
        CMPEQ   r7, #&D4                ; Medusa?
        MOVEQ   r7,#&3e00               ;for non-Morris force 16MHz timing, assumed Risc PC
        ORREQ   r7,r7,#&80
        ORREQ   r7,r7,#&10000           ;and note we're on IOMD
        MOVEQ   pc,lr
Neil Turton's avatar
Neil Turton committed
2145 2146
  ]

Neil Turton's avatar
Neil Turton committed
2147 2148
; Time CPU/Memory speed
        LDR     r1, =&7FFE              ; 32K @ 2MHz = ~16ms limit
Neil Turton's avatar
Neil Turton committed
2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173
        MOV     r3, #IOC                ; Address of the IO controller

        CMP     r0, #0
        LDREQ   r7, =(1 :SHL: 16) :OR: 16000    ; indicate 16MHz RAM - a little lie :-)
        MOVEQ   pc, lr                          ; Quick, leg it while they're not looking!

        ;Turn off the CPU cache
        ARM_number r4
        SUB     r4,r4,#6
        ADRL    r2,ARM_cacheoff_MMU_CR_table
        LDR     r2,[r2,r4,LSL #2]                 ;get appropriate cache-off value for MMU control reg
        ARM_write_control r2

        ;And don't forget to flush afterwards :-)
        ;SetCop r0, CR_IDCFlush
        ;SetCop  r0, CR_TLBFlush

        ;Turn off DMA/refreshes, but keep the reg contents for future restoration
        LDRB    r4, [r3, #IOMD_VREFCR]  ;Refresh
        LDRB    r5, [r3, #IOMD_SD0CR]   ;Sound
        LDRB    r6, [r3, #IOMD_VIDCR]   ;Video
        MOV     r2, #0
        STRB    r2, [r3, #IOMD_VREFCR]  ;Refresh off
        STRB    r2, [r3, #IOMD_SD0CR]   ;Sound off
        STRB    r2, [r3, #IOMD_VIDCR]   ;Video off
Neil Turton's avatar
Neil Turton committed
2174

Neil Turton's avatar
Neil Turton committed
2175
        MOV     r2, r1, LSR #8
Neil Turton's avatar
Neil Turton committed
2176
        STRB    r1, [r3, #Timer1LL]
Neil Turton's avatar
Neil Turton committed
2177 2178 2179
        STRB    r2, [r3, #Timer1LH]
        LDR     r2, =ncpuloops
        STRB    r2, [r3, #Timer1GO]     ; start the timer NOW
Neil Turton's avatar
Neil Turton committed
2180 2181 2182
        B       %FT10                   ; Looks superfluous, but is required
                                        ; to get ncpuloops pipeline breaks
10
Neil Turton's avatar
Neil Turton committed
2183
        SUBS    r2, r2, #1              ; 1S
Neil Turton's avatar
Neil Turton committed
2184 2185
        BNE     %BT10                   ; 1N + 2S

Neil Turton's avatar
Neil Turton committed
2186
        STRB    r2, [r3, #Timer1LR]     ; latch count NOW
Neil Turton's avatar
Neil Turton committed
2187
        LDRB    r2, [r3, #Timer1CL]
Neil Turton's avatar
Neil Turton committed
2188 2189
        LDRB    r7, [r3, #Timer1CH]
        ADD     r2, r2, r7, LSL #8      ; count after looping is ...
Neil Turton's avatar
Neil Turton committed
2190 2191

        SUB     r2, r1, r2              ; decrements !
Neil Turton's avatar
Neil Turton committed
2192
        MOV     r7, r2, LSR #1          ; IOC clock decrements at 2MHz, so we now have ticks in 1MHz
Neil Turton's avatar
Neil Turton committed
2193

Neil Turton's avatar
Neil Turton committed
2194 2195 2196 2197
        ;Put DMA/refreshes back to what they were
        STRB    r4, [r3, #IOMD_VREFCR]  ;Refresh back
        STRB    r5, [r3, #IOMD_SD0CR]   ;Sound back
        STRB    r6, [r3, #IOMD_VIDCR]   ;Video back
Neil Turton's avatar
Neil Turton committed
2198

Neil Turton's avatar
Neil Turton committed
2199 2200 2201
        ;And don't forget to flush first
        ;SetCop r0, CR_IDCFlush
        ;SetCop r0, CR_TLBFlush
Neil Turton's avatar
Neil Turton committed
2202

Neil Turton's avatar
Neil Turton committed
2203 2204 2205 2206 2207 2208
        ;Turn on the CPU cache
        ARM_number r4
        SUB     r4,r4,#6
        ADRL    r2,ARM_default_MMU_CR_table
        LDR     r2,[r2,r4,LSL #2]                 ;get appropriate default value for MMU control reg
        ARM_write_control r2
Neil Turton's avatar
Neil Turton committed
2209

Neil Turton's avatar
Neil Turton committed
2210 2211 2212 2213 2214
        MOV     r2, r7
; In ROM - each cpu loop took 4R cycles @ [MEMCLK cycles+1]/f*500ns/cycle

 [ MorrisSupport
        LDRB    r0, [r3, #IOMD_ID0]     ; Is
2215
        CMP     r0, #&E7                ; It
Neil Turton's avatar
Neil Turton committed
2216
        LDRB    r0, [r3, #IOMD_ID1]     ; A
2217 2218
        CMPEQ   r0, #&D4                ; Medusa?
        LDRNE   r0, =(4*15*500*ncpuloops)               ;Morris timing values [reordered to prevent miscalculation
Neil Turton's avatar
Neil Turton committed
2219
                                                        ;due to Aasm integering mid-calculation] (30720000)
2220
        LDREQ   r0, =(4*(8*500/1000)*ncpuloops*1000)    ;RiscPC/IOMD timing values      (16384000)
Neil Turton's avatar
Neil Turton committed
2221 2222 2223 2224
        DivRem  r7, r0, r2, r1          ; r2 preserved,   R7=memory speed in kHz (MEMCLK/2)
 |
        LDR     r0, =(4*(8*500/1000)*ncpuloops*1000)    ;RiscPC/IOMD timing values      (16384000)
        DivRem  r7, r0, r2, r1          ; r2 preserved,   R7=memory speed in kHz (MEMCLK/2)
Neil Turton's avatar
Neil Turton committed
2225 2226
 ]

Neil Turton's avatar
Neil Turton committed
2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265
        ;Set the ROM speeds appropriately here, including Burst/NoBurst
        MOV     r4, #SystemROMspeed     ;
        MUL     r0, r7, r4              ; r0 = number of cycles/ROM access *500000
        LDR     r1, =500000
        DivRem  r2, r0, r1, r4          ; r2 = divisor, r0 = remainder, r4 is trashed
        CMP     r0, #0
        ADDGT   r2, r2, #1              ; Always round _UPWARDS_
        CMP     r2, #14
        MOVGT   r2, #14                 ; Top out at 14 cycles

        MOV     r5, #BurstROMspeed      ;
        MUL     r0, r7, r5              ; r0 = number of cycles/ROM burst access *500000
        DivRem  r3, r0, r1, r4          ; r3 = divisor, r0 = remainder, r4 is trashed
        CMP     r0, #0
        ADDGT   r3, r3, #1              ; Always round _upwards_
        CMP     r3, #4
        MOVGT   r3, #4                  ; Top out at 4 cycles

  [ :LNOT: NormalSpeedROMS
    ;limit speeds to 4 cycles minimum (125 ns) - eg. for StrongARM with EPROM
    CMP   r2,#4
    MOVLT r2,#4
    CMP   r3,#4
    MOVLT r3,#4
    ! 0, "*** WARNING Autospeed ROM speed limited to 4 cycles (125 ns) minimum ***"
  ]
        ;So we have R2=cycles for normal access, R3=cycles for burst access
        ;Load the iomd reg into R1, clear the bits we're messing with
        MOV     r4, #IOC
        LDRB    r1, [r4, #IOMD_ROMCR0]  ; Read ROMCR0
        AND     r1, r1, #2_11000000     ; Only preserve bits 6 & 7

        ADR     r0, MemClkTable
        LDRB    r5, [r0, r2]            ; Grab the relevant byte
        ORR     r1, r1, r5

        ADR     r0, BurstTable
        LDRB    r5, [r0, r3]            ; Grab the relevant info
        ORR     r1, r1, r5
Neil Turton's avatar
Neil Turton committed
2266

Neil Turton's avatar
Neil Turton committed
2267 2268
        STRB    r1, [r4, #IOMD_ROMCR0]  ; Write ROMCR0
        STRB    r1, [r4, #IOMD_ROMCR1]  ; Write ROMCR1
Neil Turton's avatar
Neil Turton committed
2269

Neil Turton's avatar
Neil Turton committed
2270 2271 2272 2273 2274
        ORR     r7, r7, #1 :SHL: 16     ; Note MEMC1a presence (we're on IOMD)
  ]
timecpu_sodthefancytimingstuff
        MOV     pc, lr

2275 2276
  ] ;RO371Timings conditional

Neil Turton's avatar
Neil Turton committed
2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304
        LTORG

MemClkTable
        DCB     2_100101                ; 0 cycles (set to min which is 2)
        DCB     2_100101                ; 1 cycle (set to min. which is 2)
        DCB     2_100101                ; 2 cycles
        DCB     2_100100                ; 3 cycles
        DCB     2_100011                ; 4 cycles
        DCB     2_100010                ; 5 cycles
        DCB     2_100001                ; 6 cycles
        DCB     2_100000                ; 7 cycles
        DCB     2_000011                ; 8 cycles (2x4)
        DCB     2_000010                ; 9 cycles (same as 10)
        DCB     2_000010                ; 10 cycles (2x5)
        DCB     2_000001                ; 11 cycles (same as 12)
        DCB     2_000001                ; 12 cycles (2x6)
        DCB     2_000000                ; 13 cycles (same as 14)
        DCB     2_000000                ; 14 cycles (2x7)

        ALIGN
BurstTable
        DCB     2_000000                ; 0 cycles (no burst)
        DCB     2_011000                ; 1 cycle
        DCB     2_011000                ; 2 cycles
        DCB     2_010000                ; 3 cycles
        DCB     2_001000                ; 4 cycles

        ALIGN
Neil Turton's avatar
Neil Turton committed
2305 2306 2307 2308 2309

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       SWI OS_MMUControl
;
Neil Turton's avatar
Neil Turton committed
2310
; in:   r0 = 0 (reason code 0, for modify control register)
Neil Turton's avatar
Neil Turton committed
2311 2312 2313 2314 2315 2316 2317
;       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
2318 2319 2320 2321 2322 2323 2324 2325
;
; 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)
;       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
2326 2327

        ^       0
Neil Turton's avatar
Neil Turton committed
2328 2329
MMUCReason_ModifyControl        # 1    ; reason code 0
MMUCReason_Flush                # 1    ; reason code 1
Neil Turton's avatar
Neil Turton committed
2330 2331
MMUCReason_Unknown              # 0

2332
MMUControlSWI   Entry
Neil Turton's avatar
Neil Turton committed
2333 2334 2335 2336 2337 2338
        BL      MMUControlSub
        PullEnv
        ORRVS   lr, lr, #V_bit
        ExitSWIHandler

MMUControlSub
Neil Turton's avatar
Neil Turton committed
2339 2340 2341 2342
        Push    lr
        AND     lr,r0,#&FF
        CMP     lr, #MMUCReason_Unknown
        ADDCC   pc, pc, lr, LSL #2
Neil Turton's avatar
Neil Turton committed
2343 2344
        B       MMUControl_Unknown
        B       MMUControl_ModifyControl
Neil Turton's avatar
Neil Turton committed
2345
        B       MMUControl_Flush
Neil Turton's avatar
Neil Turton committed
2346 2347 2348 2349 2350 2351

MMUControl_Unknown
        ADRL    r0, ErrorBlock_HeapBadReason
 [ International
        BL      TranslateError
 ]
Neil Turton's avatar
Neil Turton committed
2352
        Pull    lr
Neil Turton's avatar
Neil Turton committed
2353 2354 2355
        SETV
        MOV     pc, lr

Neil Turton's avatar
Neil Turton committed
2356 2357 2358 2359 2360
MMUControl_ModifyControl ROUT
        Push    "r3,r4,r5"
        CMP     r1,#0
        CMPEQ   r2,#&FFFFFFFF
        BEQ     MMUC_modcon_readonly
Kevin Bracey's avatar
Kevin Bracey committed
2361
        PHPSEI  r4                      ; disable IRQs while we modify soft copy
Neil Turton's avatar
Neil Turton committed
2362
        ARM_number r5
Neil Turton's avatar
Neil Turton committed
2363 2364
        MOV     r3, #0
        LDR     lr, [r3, #MMUControlSoftCopy]
Neil Turton's avatar
Neil Turton committed
2365
        CMP     r5,#&A
2366 2367 2368
  [ ARM810support
        CMPNE   r5,#8                   ; can read control reg on ARM 810 too
  ]
Neil Turton's avatar
Neil Turton committed
2369 2370 2371
        ARM_read_control lr,EQ
        MOVEQ   lr,lr,LSL #19
        MOVEQ   lr,lr,LSR #19           ; if StrongARM then we can read control reg. - trust this more than soft copy
Neil Turton's avatar
Neil Turton committed
2372 2373 2374
        AND     r2, r2, lr
        EOR     r2, r2, r1
        MOV     r1, lr
2375 2376 2377 2378 2379 2380 2381 2382
  [ ARM810support
        CMP     r5,#8
        BNE     %FT03
        TST     r2,#4
        ORRNE   r2,r2,#&800            ; if ARM810 then Z bit (branch prediction) mirrors C bit
        BICEQ   r2,r2,#&800
03
  ]
Neil Turton's avatar
Neil Turton committed
2383 2384 2385 2386 2387 2388
        CMP     r5,#&A
        BNE     %FT05
        TST     r2,#&4                  ; if StrongARM, then I bit mirrors C bit
        ORRNE   r2,r2,#&1000
        BICEQ   r2,r2,#&1000
05
Neil Turton's avatar
Neil Turton committed
2389 2390
        STR     r2, [r3, #MMUControlSoftCopy]
        BIC     lr, r2, r1              ; lr = bits going from 0->1
Neil Turton's avatar
Neil Turton committed
2391 2392
        TST     lr, #MMUC_C             ; if cache turning on then flush cache before we do it
        BEQ     %FT10
2393

2394 2395 2396 2397
        Push    "r0"
        MOV     r0, #0
        ARMop   Cache_InvalidateAll,,,r0
        Pull    "r0"
Neil Turton's avatar
Neil Turton committed
2398
10
2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417
  [ ARM810support
        CMP     r5,#8
        BNE     %FT12
        BIC     lr, r1, r2              ; lr = bits going from 1->0
        TST     lr, #MMUC_C             ; if cache turning off then clean/flush cache first
        BEQ     %FT12
    [ ARM810cleanflushbroken
        Push    "r0,r1"
        ARM8_cleanflush_IDC r0,r1
        ARM8_branchpredict_off r0       ; and turn off branch predict cleanly (must go off with cache)
        Pull    "r0,r1"
    |
        Push    "r0"
        ARM8_cleanflush_IDC r0
        ARM8_branchpredict_off r0       ; and turn off branch predict cleanly (must go off with cache)
        Pull    "r0"
    ]
12
  ]
Neil Turton's avatar
Neil Turton committed
2418 2419
        CMP     r5,#&A
        BNE     %FT15
Neil Turton's avatar
Neil Turton committed
2420
        BIC     lr, r1, r2              ; lr = bits going from 1->0
Neil Turton's avatar
Neil Turton committed
2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436
        TST     lr, #MMUC_C             ; if cache turning off then clean StrongARM data cache first
        BEQ     %FT15
        Push    "r0-r2"
        MOV     r1,#ARMA_Cleaner_flipflop
        LDR     r0,[r1]
        EOR     r0,r0,#16*1024
        STR     r0,[r1]
        ARMA_clean_DC r0,r1,r2
        Pull    "r0-r2"
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
        BEQ     %FT20
        ARM_flush_cache r3
20
Kevin Bracey's avatar
Kevin Bracey committed
2437
        PLP     r4                      ; restore IRQ state
Neil Turton's avatar
Neil Turton committed
2438 2439 2440 2441 2442 2443 2444
        Pull    "r3,r4,r5,pc"

MMUC_modcon_readonly
        ARM_number r5
        MOV     r3, #0
        LDR     lr, [r3, #MMUControlSoftCopy]
        CMP     r5,#&A
2445 2446 2447
  [ ARM810support
        CMPNE   r5,#8                   ; can read control reg on ARM 810 too
  ]
Neil Turton's avatar
Neil Turton committed
2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463
        ARM_read_control lr,EQ
        MOVEQ   lr,lr,LSL #19
        MOVEQ   lr,lr,LSR #19           ; if StrongARM then we can read control reg. - trust this more than soft copy
        STREQ   lr, [r3, #MMUControlSoftCopy]
        MOV     r1, lr
        MOV     r2, lr
        Pull    "r3,r4,r5,pc"

MMUControl_Flush
       Push     "r0-r4"
       ARM_read_ID r4
       AND      r4,r4,#&F000
       TST      r0,#&80000000
       BEQ      MMUC_flush_flushT
;flush cache
       CMP      r4,#&A000
2464 2465 2466 2467
  [ ARM810support
       CMPNE    r4,#&8000
  ]
       ARM67_flush_cache NE       ;if not StrongARM or ARM810, assume 6,7
Neil Turton's avatar
Neil Turton committed
2468
       BNE      MMUC_flush_flushT
2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481
  [ ARM810support
       CMP      r4,#&A000
       BEQ      MMUC_flush_SA
;ARM810 then
    [ ARM810cleanflushbroken
       ARM8_cleanflush_IDC r1,r4
       MOV      r4,#&8000
    |
       ARM8_cleanflush_IDC r1
    ]
       B        MMUC_flush_flushT
MMUC_flush_SA
  ]
Neil Turton's avatar
Neil Turton committed
2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492
;StrongARM then
       MOV     r2,#ARMA_Cleaner_flipflop
       LDR     r1,[r2]
       EOR     r1,r1,#16*1024
       STR     r1,[r2]
       ARMA_clean_DC r1,r2,r3     ;effectively, fully clean/flush wrt non-interrupt stuff
       ARMA_drain_WB
       ARMA_flush_IC              ;do *not* flush DC - may be interrupt stuff in it
MMUC_flush_flushT
       TST     r0,#&40000000
       BEQ     MMUC_flush_done
2493 2494 2495 2496
  [ ARM810support
    ;there is a general macro, should have used this before anyway
       ARM_flush_TLB r1
  |
Neil Turton's avatar
Neil Turton committed
2497 2498 2499
       CMP     r4,#&A000
       ARMA_flush_TLBs EQ
       ARM67_flush_TLB NE         ;if not StrongARM, assume 6,7
2500
  ]
Neil Turton's avatar
Neil Turton committed
2501 2502
MMUC_flush_done
       Pull     "r0-r4,pc"
Neil Turton's avatar
Neil Turton committed
2503 2504 2505 2506 2507

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

Kevin Bracey's avatar
Kevin Bracey committed
2508
 [ :LNOT:No26bitCode
Neil Turton's avatar
Neil Turton committed
2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520
; 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

2521
        MRS     r1, SPSR                                ; r1 = saved PSR
Neil Turton's avatar
Neil Turton committed
2522 2523 2524 2525 2526
        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

2527
        MRS     r2, CPSR                ; now switch into SVC26
Neil Turton's avatar
Neil Turton committed
2528 2529
        BIC     r3, r2, #&1F
        ORR     r3, r3, #SVC26_mode
2530 2531
        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
2532 2533 2534

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

2535
        MSR     CPSR_c, r2              ; go back into undef mode
Neil Turton's avatar
Neil Turton committed
2536 2537 2538 2539 2540

        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
2541
 ]
Neil Turton's avatar
Neil Turton committed
2542

Kevin Bracey's avatar
Kevin Bracey committed
2543
 [ :LNOT:No26bitCode
Neil Turton's avatar
Neil Turton committed
2544 2545 2546 2547 2548 2549 2550 2551 2552 2553
; 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

2554
        MRS     r1, SPSR                                ; r1 = saved PSR
2555 2556 2557 2558 2559

        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
2560 2561 2562 2563 2564
        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

2565
        MRS     r2, CPSR                ; now switch into SVC26
Neil Turton's avatar
Neil Turton committed
2566 2567
        BIC     r2, r2, #&1F
        ORR     r2, r2, #SVC26_mode
2568
        MSR     CPSR_c, r2
Neil Turton's avatar
Neil Turton committed
2569 2570 2571 2572 2573 2574

        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
2575
 ]
Neil Turton's avatar
Neil Turton committed
2576 2577 2578 2579 2580 2581 2582 2583 2584 2585

; Preliminary layout of abort indirection nodes

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

2586 2587
        EXPORT DAbPreVeneer

Neil Turton's avatar
Neil Turton committed
2588 2589
DAbPreVeneer    ROUT

Kevin Bracey's avatar
Kevin Bracey committed
2590 2591 2592
 [ No26bitCode
        SUB     r13_abort, r13_abort, #17*4     ; we use stacks, dontcherknow
 |
Neil Turton's avatar
Neil Turton committed
2593
        LDR     r13_abort, =PreVeneerRegDump
Kevin Bracey's avatar
Kevin Bracey committed
2594
 ]
Neil Turton's avatar
Neil Turton committed
2595 2596 2597
        STMIA   r13_abort, {r0-r7}              ; save unbanked registers anyway
        STR     lr_abort, [r13_abort, #15*4]    ; save old PC, ie instruction address

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

2602 2603 2604 2605
        LDR     r4, =Abort32_dumparea+3*4       ;use temp area (avoid overwriting main area for expected aborts)
        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
2606 2607 2608 2609
        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
2610 2611 2612 2613 2614
  [ SASTMhatbroken
        STMEQIA r2!,{r8-r12}
        STMEQIA r2 ,{r13,r14}^
        SUBEQ   r2, r2, #5*4
  |
Neil Turton's avatar
Neil Turton committed
2615
        STMEQIA r2, {r8-r14}^
2616
  ]
Neil Turton's avatar
Neil Turton committed
2617 2618 2619
        BEQ     %FT05

        ORR     r3, r3, r1                      ; and put in user's
2620
        MSR     CPSR_c, r3                      ; switch to user's mode
Neil Turton's avatar
Neil Turton committed
2621 2622 2623

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

2624
        MRS     r5, SPSR                        ; get the SPSR for the aborter's mode
Neil Turton's avatar
Neil Turton committed
2625 2626
        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
2627 2628
  [ No26bitCode
        ORR     r1, r1, #ABT32_mode
2629
        MSR     CPSR_c, r1                      ; back to abort mode for the rest of this
Neil Turton's avatar
Neil Turton committed
2630
05
Kevin Bracey's avatar
Kevin Bracey committed
2631 2632 2633 2634
        Push    "r0"                            ; save SPSR_abort
  |
05
        ORR     r1, r1, #SVC26_mode             ; then switch to SVC for the rest of this
2635
        MSR     CPSR_c, r1
Neil Turton's avatar
Neil Turton committed
2636
        Push    "r0, lr_svc"                    ; save SPSR_abort and lr_svc
Kevin Bracey's avatar
Kevin Bracey committed
2637 2638
  ]

2639
  [ SASTMhatbroken
Kevin Bracey's avatar
Kevin Bracey committed
2640 2641
        SUB     sp, sp, #3*4
        STMIA   sp, {r13,r14}^                  ; save USR bank in case STM ^, and also so we can corrupt them
2642
        NOP
Kevin Bracey's avatar
Kevin Bracey committed
2643
        STMDB   sp!, {r8-r12}
2644
  |
Kevin Bracey's avatar
Kevin Bracey committed
2645 2646
        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
2647
  ]
Neil Turton's avatar
Neil Turton committed
2648 2649

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

Neil Turton's avatar
Neil Turton committed
2652
;ARM 810 or StrongARM allow signed byte load or half-word load/stores - not supported at present
Kevin Bracey's avatar
Kevin Bracey committed
2653
;***KJB - need to think about LDRH family
Neil Turton's avatar
Neil Turton committed
2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679
        LDR     r10, [r4, #-8]!                 ; r10 = actual instruction that aborted, and r4 points to it
        AND     r9, r10, #&0E000000
        TEQ     r9, #&08000000                  ; test for LDM/STM
        BNE     %FT50                           ; if not LDM/STM, then it's an "easy" LDR/STR

;        Write   "It's an LDM/STM"

 [ 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
2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695
        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)
;ARM 6/7 will have performed any writeback, ARM 8,StrongARM will not

        ARM_read_ID r6
        AND     r6, r6, #&F000
        CMP     r6, #&8000                      ;ARM 8 or
        CMPNE   r6, #&A000                      ;StrongARM
        MOVEQ   r6, r7
        SUBNE   r6, r7, r1, ASL #2

;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
Neil Turton's avatar
Neil Turton committed
2696 2697 2698

        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
2699
        MOVEQ   r6, r7                          ; if not wb, reg after abort is correct
Neil Turton's avatar
Neil Turton committed
2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778

        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
        TST     r1, #3                          ; test if transfer took place in USR mode
        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
2779
        ANDS    r2, r2, #15                     ; get bottom 4 bits of mode (EQ => USR26 or USR32)
Neil Turton's avatar
Neil Turton committed
2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813
        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
2814
        TST     r8, #&1C                        ; if 32-bit mode
Neil Turton's avatar
Neil Turton committed
2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869
        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

; it's an LDR/STR - first work out offset

 [ DebugAborts
        DLINE   "It's an LDR/STR"
 ]

        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

Neil Turton's avatar
Neil Turton committed
2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898
;;;assume ARM 6 configured for LateAbort - others cannot be configured
;;;so, at run time, ARM 6 or 7 means late, ARM 8 or StrongARM means early
;;;
;;; [ LateAborts
;;;        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
;;; |
;;;        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
;;; ]

        ARM_read_ID r8
        AND     r8, r8, #&F000
        CMP     r8, #&8000
        CMPNE   r8, #&A000
        BEQ     %FT62
;ARM 6 or 7 (late)
Neil Turton's avatar
Neil Turton committed
2899 2900 2901 2902 2903 2904 2905 2906 2907
        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
2908 2909 2910
        B       %FT63
62
;ARM 8 or StrongARM (early)
Neil Turton's avatar
Neil Turton committed
2911 2912 2913 2914 2915 2916 2917 2918
        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
2919
63
Neil Turton's avatar
Neil Turton committed
2920 2921 2922 2923
        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

Neil Turton's avatar
Neil Turton committed
2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934
;;; [ LateAborts
;;;        SUB     r0, r6, r0                      ; compute adjusted base register
;;;        STR     r0, [r11, r7, LSL #2]           ; and store back in case we decide to abort after all
;;; ]

        ARM_read_ID r1
        AND     r1, r1, #&F000
        CMP     r1, #&8000
        CMPNE   r1, #&A000
        SUBNE   r0, r6, r0                      ; compute adjusted base register (if late)
        STRNE   r0, [r11, r7, LSL #2]           ; and store back in case we decide to abort after all
Neil Turton's avatar
Neil Turton committed
2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002

; 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
        TST     r1, #3                          ; test if transfer took place in USR mode
        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

        Pull    "r6"                            ; LDR/LDRB, so get value to load into register
        TST     r10, #1 :SHL: 22                ; if LDRB
        ANDNE   r6, r6, #&FF                    ; then put zero in top 3 bytes of word
        ANDEQ   r9, r9, #3                      ; else rotate word to correct position - r9 = bottom 2 bits of address
        MOVEQ   r9, r9, LSL #3                  ; multiply by 8 to get rotation factor
        MOVEQ   r6, r6, ROR r9                  ; rotate to correct position in register

        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
3003 3004
 [ No26bitCode
        Pull    "r0"                            ; r0 = (possibly updated) SPSR_abort
3005
        MRS     r1, CPSR
Kevin Bracey's avatar
Kevin Bracey committed
3006
 |
Neil Turton's avatar
Neil Turton committed
3007 3008 3009
        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
3010
 ]
Neil Turton's avatar
Neil Turton committed
3011

3012
        MRS     r6, SPSR                        ; get original SPSR, with aborter's original mode
Kevin Bracey's avatar
Kevin Bracey committed
3013 3014
        AND     r7, r6, #&0F
        TEQ     r7, #USR26_mode                 ; also matches USR32
Neil Turton's avatar
Neil Turton committed
3015 3016 3017 3018 3019
        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
3020
        BIC     r6, r6, #T32_bit                ; and don't set Thumb bit
3021
        MSR     CPSR_c, r6                      ; switch to aborter's mode
Neil Turton's avatar
Neil Turton committed
3022
        LDMIA   r2, {r8-r14}                    ; reload banked registers
3023
        MSR     CPSR_c, r1                      ; switch back to ABT32
Neil Turton's avatar
Neil Turton committed
3024 3025 3026

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

        LDMIA   r13_abort, {r0-r7}              ; reload r0-r7
Kevin Bracey's avatar
Kevin Bracey committed
3030 3031 3032
 [ No26bitCode
        ADD     r13_abort, r13_abort, #17*4     ; we use stacks, dontcherknow
 ]
Neil Turton's avatar
Neil Turton committed
3033 3034 3035 3036 3037 3038 3039
        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

; Call normal exception handler

90

3040 3041 3042 3043 3044 3045 3046 3047 3048 3049
; copy temp area to real area (we believe this is an unexpected data abort now)

        LDR     r0, =Abort32_dumparea
        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
3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064
 [ No26bitCode
        MOV     r0, #0                                  ; we're going to call abort handler
        STR     r0, [r0, #CDASemaphore]                 ; so allow recovery if we were in CDA

        LDR     r0, =DAbHan
        LDR     r0, [r0]                                ; get address of data abort handler
 [ DebugAborts
        DREG    r0, "Handler address = "
 ]

        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, #9*4                    ; junk user bank stack frame + saved SPSR

3065
        MRS     r1, CPSR
Kevin Bracey's avatar
Kevin Bracey committed
3066

3067
        MRS     r6, SPSR                        ; get original SPSR, with aborter's original mode
Kevin Bracey's avatar
Kevin Bracey committed
3068 3069 3070 3071 3072 3073 3074 3075
        AND     r7, r6, #&0F
        TEQ     r7, #USR26_mode                 ; also matches USR32
        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
        BIC     r6, r6, #T32_bit                ; and don't set Thumb
3076
        MSR     CPSR_c, r6                      ; switch to aborter's mode
Kevin Bracey's avatar
Kevin Bracey committed
3077
        LDMIA   r2, {r8-r14}                    ; reload banked registers
3078
        MSR     CPSR_c, r1                      ; switch back to ABT32
Kevin Bracey's avatar
Kevin Bracey committed
3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089

80
        STR     r0, [r13_abort, #16*4]          ; save handler address at top of stack
        LDR     lr_abort, [r13_abort, #15*4]    ; get abort address back in R14

        LDMIA   r13_abort, {r0-r7}              ; reload r0-r7
        ADD     r13_abort, r13_abort, #16*4     ; we use stacks, dontcherknow

        Pull    pc

 |
Neil Turton's avatar
Neil Turton committed
3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112
; for the time being just merge lr and psr

        LDR     r0, [sp, #8*4]                          ; r0 = original SPSR (can't have been modified)

        LDR     lr, [r11, #15*4]                        ; get PC of aborter
        AND     r1, r0, #&F0000000                      ; get saved NZCV
        ORR     lr, lr, r1
        AND     r1, r0, #I32_bit + F32_bit              ; extract I and F from new place
        ORR     lr, lr, r1, LSL #IF32_26Shift           ; and merge
        AND     r1, r0, #3                              ; get old mode bits (have to assume a 26-bit mode!)
        ORR     lr, lr, r1                              ; lr = combined lr and psr
        STR     lr, [sp, #9*4]                          ; overwrite stacked lr_svc
        TEQ     r1, #SVC26_mode                         ; if aborter was in SVC mode
        STREQ   lr, [r11, #14*4]                        ; then also overwrite r14 in aborter's register bank

        BIC     r0, r0, #&1F                            ; clear mode bits in SPSR
        ORR     r0, r0, #SVC26_mode :OR: I32_bit        ; and force SVC26 with I set
 [ DebugAborts
        DLINE   "Going to call data abort handler"
        DREG    lr, "lr_svc will be "
        DREG    r0, "PSR going to exit with = "
 ]
        STR     r0, [sp, #8*4]                          ; overwrite stacked SPSR
Kevin Bracey's avatar
Kevin Bracey committed
3113
 ]
Neil Turton's avatar
Neil Turton committed
3114 3115 3116 3117

        MOV     r0, #0                                  ; we're going to call abort handler
        STR     r0, [r0, #CDASemaphore]                 ; so allow recovery if we were in CDA

Kevin Bracey's avatar
Kevin Bracey committed
3118 3119
        LDR     r0, =DAbHan
        LDR     r0, [r0]                                ; get address of data abort handler
Neil Turton's avatar
Neil Turton committed
3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139
 [ DebugAborts
        DREG    r0, "Handler address = "
 ]
        ADD     r0, r0, #4                              ; add on 4 to adjust for abort exit
        STR     r0, [r11, #15*4]                        ; and store in pc in register bank
        B       %BT70                                   ; then junk to normal tidy-up routine

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       ProcessTransfer - Process an abort transfer
;
; in:   r0 = flags
;               bit 0 = 0 => Store to memory
;                       1 => Load from memory
;               bit 1 = 0 => Transfer executed in user mode
;                       1 => Transfer executed in non-user mode
;       r1 = block of data to transfer from/into
;       r2 = illegal address
;       r3 = length of transfer in bytes
;       r4 -> instruction which aborted
Kevin Bracey's avatar
Kevin Bracey committed
3140
;       SVC26/32 mode
Neil Turton's avatar
Neil Turton committed
3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155
;
; out:  V=0 => transfer accomplished
;       V=1 => transfer not accomplished
;       All registers preserved
;

SectionSizeShift *      20
SectionSize     *       1 :SHL: SectionSizeShift

LargePageSizeShift *    16
LargePageSize   *       1 :SHL: LargePageSizeShift

SmallPageSizeShift *    12
SmallPageSize   *       1 :SHL: SmallPageSizeShift

3156
ProcessTransfer Entry "r1-r7,r12"
Neil Turton's avatar
Neil Turton committed
3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208

 [ DebugAborts
        DLINE   "ProcessTransfer entered"
        DREG    r2, "Illegal address = "
        DREG    r3, "Length of transfer = "
        DREG    r4, "Abort happened at address "
        DREG    r0, "Flags = "
        DLINE   "Data = ",cc

        MOV     r5, r3
        MOV     r6, r1
01
        LDR     r7, [r6], #4
        DREG    r7," ",cc
        SUBS    r5, r5, #4
        BHI     %BT01
        DLINE   ""
 ]


; First identify if start address should have aborted

10
        LDR     r7, =L1PT
        MOV     lr, r2, LSR #SectionSizeShift           ; r2 as a multiple of 1Mb
        EOR     r5, r2, lr, LSL #SectionSizeShift       ; r5 = offset within section
        SUB     r5, r2, r5                              ; r5 -> start of section containing r2
        ADD     r5, r5, #SectionSize                    ; r5 -> start of section after r2

        LDR     lr, [r7, lr, LSL #2]                    ; get L1PT entry
        ANDS    r7, lr, #3                              ; 00 => trans.fault, 01 => page, 10 => section, 11 => reserved (fault)
        TEQNE   r7, #3
        BEQ     Fault
        TEQ     r7, #1
        BEQ     CheckPage

; it's section mapped - check section access privileges

15
        ANDS    r7, lr, #3 :SHL: 10                     ; extract ap
        BEQ     Fault                                   ; 00 => no access for anyone (at the moment)
        TST     r0, #2                                  ; test for non-usr access
        BNE     %FT20                                   ; if non-usr then OK to access here
        CMP     r7, #2 :SHL: 10
        BCC     Fault                                   ; 01 => no usr access
        BHI     %FT20                                   ; 11 => full user access, so OK
        TST     r0, #1
        BEQ     Fault                                   ; 10 => usr read-only, so stores not allowed

; access OK, so copy up to end of section/sub-page

20
Neil Turton's avatar
Neil Turton committed
3209 3210
;ARM 8 and StrongARM will abort for vector reads (as well as writes) in 26bit mode, so we must
;handle vector reads properly as well now
3211
;In fact, StrongARM does not abort (optional in architecture 4), but ARM 8 does - MJS 08-10-96
Neil Turton's avatar
Neil Turton committed
3212
  [ {FALSE}
Neil Turton's avatar
Neil Turton committed
3213 3214
        TST     r0, #1                                  ; if load from memory
        BNE     %FT60                                   ; then skip
Neil Turton's avatar
Neil Turton committed
3215
  ]
Neil Turton's avatar
Neil Turton committed
3216

Neil Turton's avatar
Neil Turton committed
3217
; it's a store to memory (may be a vector write), or a read from memory (may be a vector read)
Neil Turton's avatar
Neil Turton committed
3218 3219 3220 3221
; do it in words if >= 4 bytes, so word writes to VIDC work for example

25
        CMP     r2, #&1C                                ; if in abort area (but allow any access to &1C)
3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233
  [ OnlyKernelCanAccessHardwareVectors
        BHS     %FT22
        CMP     r4, #ROM                                ; and executing outside the kernel
        BLO     %FT23
        ADRL    lr, EndOfKernel
        CMP     r4, lr
        BLO     %FT22
23
        MOV     r5, #&20                                ; then set end-of-section = 32
        B       Fault                                   ; and check user list
22
  |
Neil Turton's avatar
Neil Turton committed
3234 3235 3236
        CMPCC   r4, #ROM                                ; and executing out of RAM
        MOVCC   r5, #&20                                ; then set end-of-section = 32
        BCC     Fault                                   ; and check user list
3237
  ]
Neil Turton's avatar
Neil Turton committed
3238

Kevin Bracey's avatar
Kevin Bracey committed
3239
  [ :LNOT:No26bitCode
Neil Turton's avatar
Neil Turton committed
3240
        SetMode SVC32_mode, lr                          ; go into SVC32 so we can poke or peek vector area
Kevin Bracey's avatar
Kevin Bracey committed
3241
  ]
Neil Turton's avatar
Neil Turton committed
3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264

        TST     r0, #1                                  ; test for peek/poke
        BEQ     %FT30
26
;peeking
        TEQ     r2, r5                                  ; have we gone onto a new block?
        BEQ     %FT50                                   ; if so then exit if finished else go back to outer loop
        SUBS    r3, r3, #4                              ; have we got at least a word to do?
        LDRCS   lr, [r2], #4                            ; if so then copy word
        STRCS   lr, [r1], #4
        BHI     %BT26                                   ; and if not all done then loop
        BEQ     %FT50                                   ; if all done then switch back to SVC26 and exit

        ADDS    r3, r3, #4
27
        LDRB    lr, [r2], #1                            ; read byte from register bank
        STRB    lr, [r1], #1                            ; and store to memory
        SUBS    r3, r3, #1                              ; decrement byte count
        BEQ     %FT50                                   ; if finished then switch back to SVC26 and exit
        TEQ     r2, r5                                  ; have we gone onto a new block?
        BNE     %BT27                                   ; no, then loop
        B       %FT50

Neil Turton's avatar
Neil Turton committed
3265
30
Neil Turton's avatar
Neil Turton committed
3266
;poking
Neil Turton's avatar
Neil Turton committed
3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284
        TEQ     r2, r5                                  ; have we gone onto a new block?
        BEQ     %FT50                                   ; if so then exit if finished else go back to outer loop
        SUBS    r3, r3, #4                              ; have we got at least a word to do?
        LDRCS   lr, [r1], #4                            ; if so then copy word
        STRCS   lr, [r2], #4
        BHI     %BT30                                   ; and if not all done then loop
        BEQ     %FT50                                   ; if all done then switch back to SVC26 and exit

        ADDS    r3, r3, #4
40
        LDRB    lr, [r1], #1                            ; read byte from register bank
        STRB    lr, [r2], #1                            ; and store to memory
        SUBS    r3, r3, #1                              ; decrement byte count
        BEQ     %FT50                                   ; if finished then switch back to SVC26 and exit
        TEQ     r2, r5                                  ; have we gone onto a new block?
        BNE     %BT40                                   ; no, then loop

50
Kevin Bracey's avatar
Kevin Bracey committed
3285
  [ :LNOT:No26bitCode
Neil Turton's avatar
Neil Turton committed
3286
        SetMode SVC26_mode, lr
Kevin Bracey's avatar
Kevin Bracey committed
3287
  ]
Neil Turton's avatar
Neil Turton committed
3288 3289 3290 3291
        CMP     r3, #0
        BNE     %BT10
        EXIT                                            ; exit (VC from CMP)

Neil Turton's avatar
Neil Turton committed
3292
  [ {FALSE}
Neil Turton's avatar
Neil Turton committed
3293 3294 3295 3296 3297 3298 3299 3300 3301
; it's a load from memory
60
        LDRB    lr, [r2], #1                            ; read byte from memory
        STRB    lr, [r1], #1                            ; and store to memory bank
        SUBS    r3, r3, #1                              ; decrement byte count
        EXIT    EQ                                      ; if finished then exit (VC from SUBS)
        TEQ     r2, r5                                  ; have we gone onto a new block?
        BNE     %BT60                                   ; no, then loop
        B       %BT10                                   ; yes, then go back to start
Neil Turton's avatar
Neil Turton committed
3302
  ]
Neil Turton's avatar
Neil Turton committed
3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314

; it's page mapped, so check L2PT
; lr = L1 table entry
; We use the logical copy of physical space here, in order to access the entry pointed to by the L1 entry

CheckPage
        MOV     r5, r2, LSR #SmallPageSizeShift         ; r2 as a multiple of 4K
        MOV     r5, r5, LSL #SmallPageSizeShift
        ADD     r5, r5, #SmallPageSize                  ; if translation fault, then it applies to small page

        MOV     lr, lr, LSR #10                         ; remove domain and U bits
        MOV     lr, lr, LSL #10
3315 3316 3317 3318 3319 3320 3321 3322 3323 3324
 [ HAL
        SUB     sp, sp, #4
        Push    "r0-r3,r12"
        MOV     r0, #0
        MOV     r1, lr
        ADD     r2, sp, #5*4
        BL      RISCOS_AccessPhysicalAddress
        MOV     lr, r0
        Pull    "r0-r3,r12"
 |
Neil Turton's avatar
Neil Turton committed
3325
        ORR     lr, lr, #PhysSpace                      ; now physical address is converted to a logical one (in physspace)
3326
 ]
Neil Turton's avatar
Neil Turton committed
3327 3328 3329 3330 3331
        AND     r7, r2, #&000FF000                      ; extract bits which are to form L2 offset

        LDR     lr, [lr, r7, LSR #10]                   ; lr = L2PT entry
        ANDS    r7, lr, #3                              ; 00 => trans.fault, 01 => large page
                                                        ; 10 => small page, 11 => reserved (fault)
3332 3333 3334 3335 3336 3337 3338
 [ HAL
        Push    "r0-r3,r12,lr"
        LDR     r0, [sp, #6*4]
        BL      RISCOS_ReleasePhysicalAddress
        Pull    "r0-r3,r12,lr"
        ADD     sp, sp, #4
 ]
Neil Turton's avatar
Neil Turton committed
3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415
        TEQNE   r7, #3
        BEQ     Fault
        TEQ     r7, #2                          ; if small page
        MOVEQ   r7, #SmallPageSizeShift-2       ; then sub-page size = 1<<10
        MOVNE   r7, #LargePageSizeShift-2       ; else sub-page size = 1<<14

        MOV     r5, r2, LSR r7                  ; round down to start of sub-page
        MOV     r5, r5, LSL r7
        MOV     r6, #1
        ADD     r5, r5, r6, LSL r7              ; then move on to start of next sub-page

        MOV     r7, r2, LSR r7                  ; put sub-page number in bits 1,2
        AND     r7, r7, #3                      ; and junk other bits
        RSB     r7, r7, #3                      ; invert sub-page ordering
        MOV     r7, r7, LSL #1                  ; and double it
        MOV     lr, lr, LSL r7                  ; then shift up access privileges so that correct ones appear in bits 10,11
        B       %BT15                           ; re-use code to check access privileges

Fault
        SUB     r5, r5, r2                      ; r5 = number of bytes we can do in this section/page/sub-page
        Push    "r3"                            ; save number of bytes to do
        CMP     r3, r5                          ; if more bytes than there are in this block
        MOVHI   r3, r5

; Now scan list of user abort addresses

        MOV     r6, #0
        LDR     r6, [r6, #AbortIndirection]
        TEQ     r6, #0
        BEQ     %FT85                           ; address not in any abort node
75
        LDR     r5, [r6, #AI_Low]
        CMP     r2, r5
        BCC     %FT80
        LDR     r5, [r6, #AI_High]
        CMP     r2, r5
        BCS     %FT80

        Push    "r3"                            ; save number of bytes we can do in this section/page/sub-page
        SUB     r5, r5, r2                      ; number of bytes we can do for this node
        CMP     r3, r5                          ; if bigger than the size of this node
        MOVHI   r3, r5                          ; then restrict number of bytes

        ADD     r5, r6, #AI_WS
        MOV     lr, pc
        LDMIA   r5, {r12, pc}

; returns to here

        ADDVS   sp, sp, #8                      ; if user abort failed, then junk both pushed r3's
        EXIT    VS                              ; and exit

        ADD     r1, r1, r3                      ; advance register block
        ADD     r2, r2, r3                      ; and illegal address pointer

        LDR     r5, [sp, #4]                    ; subtract amount done from stacked total amount to do
        SUBS    r5, r5, r3
        STR     r5, [sp, #4]                    ; and store back

        Pull    "r5"
        SUBS    r3, r5, r3                      ; is there more to do in this section/page/sub-page?
        BEQ     %FT90                           ; no then skip
80
        LDR     r6, [r6, #AI_Link]              ; else try next node
        TEQ     r6, #0
        BNE     %BT75
85
        ADD     sp, sp, #4                      ; junk pushed r3
        SETV                                    ; indicate access invalid
        EXIT                                    ; and exit

90
        Pull    "r3"                            ; restore total amount left to do
        TEQ     r3, #0
        BNE     %BT10                           ; yes, then loop
        EXIT                                    ; no, then exit (V=0 from SUBS)

Neil Turton's avatar
Neil Turton committed
3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428

;some tricks to improve performance, looking at MMU level 1 and level 2 page tables
L1L2PTenhancements ROUT
        Push    "r0-r5,lr"

;if the MMU control reg (soft copy) has R bit set (bit 9), then adjust the L1 entries for ROM
;space to give full write protection (user and supervisor)
        MOV     r0,#0
        LDR     r1,[r0,#MMUControlSoftCopy]
        TST     r1,#&200
        BEQ     L1L2PTe_WPROMdone              ;ARM 610 has no R bit, for example
        LDR     r0,=L1PT
        ADD     r0,r0,#ROM :SHR: (20-2)        ;address of first L1PT entry for ROM space
3429 3430 3431
  [ OSROM_ImageSize > 8192
        MOV     r1,#OSROM_ImageSize / 1024
  |
Neil Turton's avatar
Neil Turton committed
3432
        MOV     r1,#8                          ;8 entries (8 Mbytes)
3433
  ]
Neil Turton's avatar
Neil Turton committed
3434 3435 3436 3437 3438 3439 3440 3441
L1L2PTe_WPROMloop
        LDR     r2,[r0]
        BIC     r2,r2,#&C00                    ;set AP (access permission) bits to 00
        STR     r2,[r0],#4
        SUBS    r1,r1,#1
        BNE     L1L2PTe_WPROMloop
L1L2PTe_WPROMdone

Kevin Bracey's avatar
Kevin Bracey committed
3442 3443
   [ :LNOT: (CanLiveOnROMCard :LOR: ROMCardSupport :LOR: ExtROMSupport)

Neil Turton's avatar
Neil Turton committed
3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457
;go for best available memory speed for data cache cleaner area (StrongARM)
        LDR     r0,=L2PT :OR: (ARMA_Cleaners_address :SHR: 10)  ;address of 1st L2PT word for cleaner area
        LDR     r1,[r0]
        MOV     r1,r1,LSL #20
        MOV     r1,r1,LSR #20                   ;zap physical address field
        ORR     r1,r1,#&01000000                ; = physical address of start of ROM bank 1
        MOV     r2,#8                           ;8 L2PT entries to fiddle
00
        STR     r1,[r0],#4
        SUBS    r2,r2,#1
        BNE     %BT00
        MOV     r0,#IOC
        MOV     r1,#5
        STRB    r1,[r0, #IOMD_ROMCR1]           ;ROM bank 1 speed = fastest (62.5 ns)
Kevin Bracey's avatar
Kevin Bracey committed
3458
    ]
Neil Turton's avatar
Neil Turton committed
3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504

;make first 5 pages of cursor chunk cacheable and bufferable - this is rather handy, 'coz things
;like the SWI dispatcher, IRQ dispatcher are here. May be a slight worry over cursor data
;being write-back cached (StrongARM) - should strictly clean,drain write buffer or whatever for shape change.
        LDR     r0,=L2PT :OR: (CursorChunkAddress :SHR: 10)  ;address of 1st L2PT word for CursorChunk
        MOV     R2,#5                           ;5 entries to adjust
01
        LDR     r1,[r0]
        ORR     r1,r1,#&C                       ;make page cacheable and bufferable
        STR     r1,[r0],#4
        SUBS    r2,r2,#1
        BNE     %BT01

;make other 3 pages of chunk bufferable
        MOV     R2,#3
02
        LDR     r1,[r0]
        ORR     r1,r1,#&4                       ;make page bufferable
        STR     r1,[r0],#4
        SUBS    r2,r2,#1
        BNE     %BT02

;if we are on StrongARM, make the pages of the L2PT itself (for AppSpace only), bufferable (improves task swap speed)
;AppSpace is 0-28M
        ARM_read_ID r0
        AND     r0,r0,#&F000
        CMP     r0,#&A000
        BNE     %FT04
        MOV     r0,#L2PT
        ADD     r0,r0,#(L2PT :SHR: 10) ;the L2PT of the L2PT (and first 7 entries are for App Space)
        ADD     r1,r0,#7*4             ;7 L2PT-of-L2PT entries for 28M of space
03
        LDR     r2,[r0]
        ORR     r2,r2,#4               ;bufferable bit
        STR     r2,[r0],#4
        CMP     r0,r1
        BNE     %BT03
        ARMA_drain_WB                  ;let us be paranoid
04

;try to rescue some pages from the L2PT itself, in the AppSpace region - ie. AppSpace max size can really
;be total RAM size, if that is less than 28 Mb, and for every 4Mb less that is we can rescue a 4k page
;and return it to the free pool - handy on a 2Mb Kryten for instance!

        LDR     r0,=MaxCamEntry
        LDR     r0,[r0]
3505 3506 3507 3508
        ADD     r0,r0,#1+255+768                ; = no. of 4k RAM pages in machine + 255 + 3*256
        MOV     r0,r0,LSR #8                    ; = no. of Mbytes in machine rounded up + 3
        BIC     r0,r0,#3                        ; round up to next 4 Mb
        CMP     r0,#28                          ; if 28Mb or more, no pages to be rescued from L2PT AppSpace
Neil Turton's avatar
Neil Turton committed
3509 3510 3511
        BHS     %FT09
        LDR     r1,=AppSpaceDANode
        MOV     r2,r0,LSL #20
3512 3513
        STR     r2,[r1,#DANode_MaxSize]         ; update AppSpace max size
        MOV     r0,r0,LSR #2                    ; no. of L2PT AppSpace pages which cannot be rescued
Neil Turton's avatar
Neil Turton committed
3514
        MOV     r1,#L2PT
3515 3516 3517 3518
        ADD     r4, r1, #L1PT-L2PT
        ADD     r4, r4, r0, LSL #4              ;the L1PT entry to blank out (4 L1 entries per L2 entry)
        ADD     r1,r1,#(L2PT :SHR: (12-2))      ;the L2PT of the L2PT (and first 7 entries are for App Space)
        ADD     r1,r1,r0,LSL #2                 ;first entry for rescue
Neil Turton's avatar
Neil Turton committed
3519 3520
        LDR     r3,=FreePoolDANode
        LDR     r2,[r3,#DANode_Base]
3521 3522
        LDR     r5,[r3,#DANode_Size]            ; FreePool size so far
        ADD     r2,r2,r5                        ; r2 -> next logical address for a rescued page
Neil Turton's avatar
Neil Turton committed
3523

3524
        SUB     sp,sp,#16                       ; room for 1 page block entry + terminator
Neil Turton's avatar
Neil Turton committed
3525 3526
        MOV     r3,sp
05
3527
        Push    "r0"
3528
        LDR     r0,[r1],#4                      ; pick up the L2PT entry
3529
        BIC     r0,r0,#&0FF
3530 3531
        BIC     r0,r0,#&F00                     ; mask to leave physical address only
        STR     r0,[r3,#8]                      ; store physical address in word 2 of page block entry
3532 3533

        Push    "r1-r2"
Neil Turton's avatar
Neil Turton committed
3534 3535 3536
        MOV     r0,#&0C00
        MOV     r1,r3
        MOV     r2,#1
3537
        SWI     XOS_Memory                      ; fill in page number, given physical address
3538

3539
        MOV     r0,#2                           ; means inaccessible in user mode (destined for FreePool)
3540 3541
        STR     r0,[r3,#8]
        MOV     r0,#-1
3542
        STR     r0,[r3,#12]                     ; terminator
3543 3544
        Pull    "r1-r2"

3545
        STR     r2,[r3,#4]                      ; new logical address for page
Neil Turton's avatar
Neil Turton committed
3546 3547
        MOV     r0,r3
        SWI     XOS_SetMemMapEntries
3548

3549 3550 3551 3552 3553
        MOV     r0, #0                          ; Blank out the L1PT entries for the page table we just removed
        STR     r0, [r4], #4
        STR     r0, [r4], #4
        STR     r0, [r4], #4
        STR     r0, [r4], #4
3554

Neil Turton's avatar
Neil Turton committed
3555 3556
        Pull    "r0"
        ADD     r2,r2,#4096
3557
        ADD     r5,r5,#4096                     ; next page
Neil Turton's avatar
Neil Turton committed
3558
        ADD     r0,r0,#1
3559
        CMP     r0,#7                           ;7 entries in total for full 28Mb AppSpace
Neil Turton's avatar
Neil Turton committed
3560
        BNE     %BT05
3561
        ADD     sp,sp,#16                       ;drop the workspace
Neil Turton's avatar
Neil Turton committed
3562

3563
        LDR     r0,=FreePoolDANode
3564
        STR     r5,[r0,#DANode_Size]            ;update FreePoolSize
Neil Turton's avatar
Neil Turton committed
3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598

09
        Pull    "r0-r5,pc"
  [ StrongARM
;
; ---------------- XOS_SynchroniseCodeAreas implementation ---------------
;

;this SWI effectively implements IMB and IMBrange (Instruction Memory Barrier)
;for newer ARMs

;max address range before IMBrange is treated as IMB (performance issue,
;since range clean can only specify entries by virtual address)
ARMA_IMBrange_threshold * 128*1024

;entry:
;   R0 = flags
;        bit 0 set ->  R1,R2 specify virtual address range to synchronise
;                      R1 = start address (word aligned, inclusive)
;                      R2 = end address (word aligned, inclusive)
;        bit 0 clear   synchronise entire virtual space
;        bits 1..31    reserved
;
;exit:
;   R0-R2 preserved
;
;method:
;  ARMs 6,7 need do nothing (no IMB consideration)
;  ARM 8 need do nothing (SWI call itself flushes prefetch unit)
;  StrongARM must:
;    (1) clean data cache, (2) drain write buffer, (3) flush instruction cache
;    - the clean is either whole cache or range as appropriate
;
SyncCodeAreasSWI ROUT
3599 3600 3601 3602 3603 3604 3605 3606 3607 3608
        Push    "lr"
        BL      SyncCodeAreas
        Pull    "lr"                    ; no error return possible
        B       SLVK

SyncCodeAreas
        TST     R0,#1                   ; range variant of SWI?
        BEQ     SyncCodeAreasFull

SyncCodeAreasRange
Neil Turton's avatar
Neil Turton committed
3609 3610 3611
        ARM_read_ID R10
        AND     R10,R10,#&F000
        CMP     R10,#&A000
3612 3613
        MOVNE   PC,LR                        ;not StrongARM

Neil Turton's avatar
Neil Turton committed
3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625
        MOV     R11,R1                       ;R11 := low address (inclusive)
        ADD     R12,R2,#4                    ;R12 := high address (exclusive)
        SUB     R12,R12,R11
        CMP     R12,#ARMA_IMBrange_threshold
        BHS     %FT01                        ;do full IMB
        ADD     R12,R12,R11
        ARMA_clean_DCrange R11,R12
        ARMA_drain_WB
        ARMA_flush_IC WithoutNOPs
        MOV     R0,R0                  ;NOPs to ensure 4 instructions after IC flush before return
        MOV     R0,R0
        MOV     R0,R0
3626 3627 3628 3629 3630 3631 3632 3633 3634
        MOV     PC,LR

SyncCodeAreasFull
        ARM_read_ID R10
        AND     R10,R10,#&F000
        CMP     R10,#&A000
        MOVNE   PC,LR                        ;not StrongARM

01      LDR     R12,=SyncCodeA_sema
Kevin Bracey's avatar
Kevin Bracey committed
3635 3636 3637
        MOV     R10,#1                  ;set semaphore
        SWPB    R11,R10,[R12]
        CMP     R11,#0                  ;was it already set?
3638
        MOVNE   PC,LR                   ;semaphore set, avoid reentrancy, let first call do it
Neil Turton's avatar
Neil Turton committed
3639 3640 3641 3642 3643 3644 3645 3646 3647 3648
        MOV     R12,#ARMA_Cleaner_flipflop
        LDR     R11,[R12]
        EOR     R11,R11,#16*1024
        STR     R11,[R12]
        ARMA_clean_DC R11,R12,R10  ;fully clean/flush DC wrt non-interrupt stuff
        ARMA_drain_WB
        ARMA_flush_IC WithoutNOPs  ;do *not* flush DC - may be stuff from interrupt routines
        MOV     R12,#0
        STRB    R12,[R12,#SyncCodeA_sema]  ;reset semaphore
        MOV     R0,R0              ;NOP to ensure 4 instructions after IC flush before return
3649
        MOV     PC,LR
Neil Turton's avatar
Neil Turton committed
3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695

        LTORG

;
;some service routines here for easy patchability
        ALIGN

dtgps_SAcleanflush  ; used during pages_unsafe/safe in ChangeDyn
    ADR     r0,PageBlock1
    ADD     r0,r0,#4        ; r0 -> page block (logical addresses)
    LDR     r1,NumEntries
dtgps_SAloop0
    LDR     r2,[r0],#12
    ADD     r3,r2,#4096     ; 4k page
dtgps_SAloop1
 [ SAcleanflushbroken         ; 2 separate instructions 'coz SA110 cleanflush (1 instruction) seems ineffective
    ARMA_clean_DCentry r2
    ARMA_flush_DCentry r2
    ADD     r2,r2,#32
    ARMA_clean_DCentry r2
    ARMA_flush_DCentry r2
    ADD     r2,r2,#32
    ARMA_clean_DCentry r2
    ARMA_flush_DCentry r2
    ADD     r2,r2,#32
    ARMA_clean_DCentry r2
    ARMA_flush_DCentry r2
    ADD     r2,r2,#32
 |
    ARMA_cleanflush_DCentry r2
    ADD     r2,r2,#32
    ARMA_cleanflush_DCentry r2
    ADD     r2,r2,#32
    ARMA_cleanflush_DCentry r2
    ADD     r2,r2,#32
    ARMA_cleanflush_DCentry r2
    ADD     r2,r2,#32
  ]
    CMP     r2,r3
    BLO     dtgps_SAloop1
    SUBS    r1,r1,#1
    BNE     dtgps_SAloop0
    ARMA_drain_WB           ; squeeze out those last drops
    MOV     pc,lr

 ]
3696 3697 3698 3699

;ARM810 equiv of dtgps_SAcleanflush must clean/flush whole cache (cannot clean/flush by virtual address)
;and is shared with code in meminfo_flushplease, below

Neil Turton's avatar
Neil Turton committed
3700 3701 3702 3703 3704
meminfo_flushplease         ; used by MemInfo
        ARM_read_ID r0
        AND     r0,r0,#&F000
        CMP     r0,#&A000
        BEQ     mifp_SA
3705 3706 3707 3708
  [ ARM810support
        CMP     r0,#&8000
        BEQ     mifp_810
  ]
Neil Turton's avatar
Neil Turton committed
3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720
;assume ARM 6 or 7 - simple!
        ARM67_flush_cache
        MOV     pc,lr
mifp_SA
;StrongARM - this could take a while...
        MOV     r1,#ARMA_Cleaner_flipflop
        LDR     r0,[r1]
        EOR     r0,r0,#16*1024
        STR     r0,[r1]
        ARMA_clean_DC r0,r1,r2          ;clean/flush data cache wrt non-interrupt stuff (trashes r0,r1,r2)
        ARMA_flush_IC                   ;do *not* flush DC - may be interrupt stuff
        MOV     pc,lr
3721 3722 3723 3724 3725 3726 3727 3728 3729 3730
  [ ARM810support
mifp_810
dtgps_810cleanflush                     ;entry point also used during pages_unsafe/safe in ChangeDyn
    [ ARM810cleanflushbroken
        ARM8_cleanflush_IDC r0,r1
    |
        ARM8_cleanflush_IDC r0
    ]
        MOV     pc,lr
  ]
Neil Turton's avatar
Neil Turton committed
3731 3732
;

Kevin Bracey's avatar
Kevin Bracey committed
3733
 [ {FALSE}
Neil Turton's avatar
Neil Turton committed
3734 3735 3736 3737
        DCB     "GROT"                  ;spare words marker
        ALIGN   4096                    ;align to page boundary for easy ROMpatch
arm600stuff_endofstuff
  ! 0,"-- size of ARM600+ stuff (4k aligned) is ":CC::STR:(arm600stuff_endofstuff - arm600stuff_startofstuff)
Kevin Bracey's avatar
Kevin Bracey committed
3738
 ]
Neil Turton's avatar
Neil Turton committed
3739 3740


Neil Turton's avatar
Neil Turton committed
3741 3742 3743 3744
 [ DebugAborts
        InsertDebugRoutines
 ]
        END