HAL 110 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
; Copyright 2000 Pace Micro Technology plc
;
; 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.
;
15
        GBLL    MinorL2PThack
Kevin Bracey's avatar
Kevin Bracey committed
16
MinorL2PThack SETL {TRUE}
17 18 19 20 21 22 23 24 25 26

; Fixed page allocation is as follows

                        ^       0
DRAMOffset_FirstFixed   #       0
DRAMOffset_ScratchSpace #       16*1024
DRAMOffset_PageZero     #       16*1024
DRAMOffset_L1PT         #       16*1024         ; L1PT must be 16K-aligned
DRAMOffset_LastFixed    #       0

27 28
;        IMPORT  Init_ARMarch
;        IMPORT  ARM_Analyse
29

30
 [ MEMM_Type = "VMSAv6"
Jeffrey Lee's avatar
Jeffrey Lee committed
31 32 33 34
mmuc_init_new
        ; MMUC initialisation flags for ARMv6/ARMv7
        ; This tries to leave the reserved/unpredictable bits untouched, while initialising everything else to what we want
                ; ARMv7MP (probably) wants SW. ARMv6 wants U+XP (which should both be fixed at 1 on ARMv7)
Ben Avison's avatar
Ben Avison committed
35
        DCD     MMUC_BEN+MMUC_SW+MMUC_U+MMUC_XP
Jeffrey Lee's avatar
Jeffrey Lee committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
                ; M+C+W+Z+I+L2 clear to keep MMU/caches off.
                ; A to keep alignment exceptions off (for now at least)
                ; B+EE clear for little-endian
                ; S+R+RR clear to match mmuc_init_old
                ; V+VE clear to keep processor vectors at &0
                ; FI clear to disable fast FIQs (interruptible LDM/STM)
                ; TRE+AFE clear for our VMSAv6 implementation
                ; TE clear for processor vectors to run in ARM mode
        DCD     MMUC_M+MMUC_A+MMUC_C+MMUC_W+MMUC_B+MMUC_S+MMUC_R+MMUC_Z+MMUC_I+MMUC_V+MMUC_RR+MMUC_FI+MMUC_VE+MMUC_EE+MMUC_L2+MMUC_TRE+MMUC_AFE+MMUC_TE
mmuc_init_old
        ; MMUC initialisation flags for ARMv5 and below, as per ARM600 MMU code
                ; Late abort (ARM6 only), 32-bit Data and Program space. No Write buffer (ARM920T
                ; spec says W bit should be set, but I reckon they're bluffing).
                ;
                ; The F bit's tricky. (1 => CPCLK=FCLK, 0=>CPCLK=FCLK/2). The only chip using it was the
                ; ARM700, it never really reached the customer, and it's always been programmed with
                ; CPCLK=FCLK. Therefore we'll keep it that way, and ignore the layering violation.
        DCD     MMUC_F+MMUC_L+MMUC_D+MMUC_P
                ; All of these bits should be off already, but just in case...
        DCD     MMUC_B+MMUC_W+MMUC_C+MMUC_A+MMUC_M+MMUC_RR+MMUC_V+MMUC_I+MMUC_Z+MMUC_R+MMUC_S
56
 ]
57 58 59 60 61 62 63

; void RISCOS_InitARM(unsigned int flags)
;
RISCOS_InitARM
        MOV     a4, lr
        ; Check if we're architecture 3. If so, don't read the control register.
        BL      Init_ARMarch
64 65
        MOVEQ   a3, #0
        ARM_read_control a3, NE
66
 [ MEMM_Type = "VMSAv6"
Jeffrey Lee's avatar
Jeffrey Lee committed
67 68 69 70 71
        CMP     a1, #ARMv6
        CMPNE   a1, #ARMvF
        ADREQ   a2, mmuc_init_new
        ADRNE   a2, mmuc_init_old
        LDMIA   a2, {a2, lr}
72
        ORR     a3, a3, a2
Jeffrey Lee's avatar
Jeffrey Lee committed
73
        BIC     a3, a3, lr
74
 |
75 76 77 78 79 80
        ; Late abort (ARM6 only), 32-bit Data and Program space. No Write buffer (ARM920T
        ; spec says W bit should be set, but I reckon they're bluffing).
        ;
        ; The F bit's tricky. (1 => CPCLK=FCLK, 0=>CPCLK=FCLK/2). The only chip using it was the
        ; ARM700, it never really reached the customer, and it's always been programmed with
        ; CPCLK=FCLK. Therefore we'll keep it that way, and ignore the layering violation.
81
        ORR     a3, a3, #MMUC_F+MMUC_L+MMUC_D+MMUC_P
82
        ; All of these bits should be off already, but just in case...
83 84
        BIC     a3, a3, #MMUC_B+MMUC_W+MMUC_C+MMUC_A+MMUC_M
        BIC     a3, a3, #MMUC_RR+MMUC_V+MMUC_I+MMUC_Z+MMUC_R+MMUC_S
85
 ]
86 87

        ; Off we go.
88
        ARM_write_control a3
89
        MOV     a2, #0
90
 [ MEMM_Type = "VMSAv6"
91
        myISB   ,a2,,y ; Ensure the update went through
92
 ]
93 94

        ; In case it wasn't a hard reset
95
 [ MEMM_Type = "VMSAv6"
96 97
        CMP     a1, #ARMvF
        ; Assume that all ARMvF ARMs have multi-level caches and thus no single MCR op for invalidating all the caches
Ben Avison's avatar
Ben Avison committed
98 99
        ADREQ   lr, %FT01
        BEQ     HAL_InvalidateCache_ARMvF
100
        MCRNE   ARM_config_cp,0,a2,ARMv4_cache_reg,C7           ; invalidate I+D caches
Ben Avison's avatar
Ben Avison committed
101
01
102
 ]
103
        CMP     a1, #ARMv3
Ben Avison's avatar
Ben Avison committed
104
        BNE     %FT01
105
        MCREQ   ARM_config_cp,0,a2,ARMv3_TLBflush_reg,C0        ; flush TLBs
Ben Avison's avatar
Ben Avison committed
106 107 108
        B       %FT02
01      MCRNE   ARM_config_cp,0,a2,ARMv4_TLB_reg,C7             ; flush TLBs
02
109
 [ MEMM_Type = "VMSAv6"
110 111
        myDSB   ,a2,,y
        myISB   ,a2,,y
112
 ]
113

114 115
        ; We assume that ARMs with an I cache can have it enabled while the MMU is off.
        [ :LNOT:CacheOff
116 117
        ORRNE   a3, a3, #MMUC_I
        ARM_write_control a3, NE                                ; whoosh
118
 [ MEMM_Type = "VMSAv6"
119
        myISB   ,a2,,y ; Ensure the update went through
120
 ]
121 122
        ]

123 124
        ; Check if we are in a 26-bit mode.
        MRS     a2, CPSR
125 126
        ; Keep a soft copy of the CR in a banked register (R13_und)
        MSR     CPSR_c, #F32_bit+I32_bit+UND32_mode
127
        MOV     sp, a3
128 129 130 131 132 133 134 135 136 137 138 139
        ; Switch into SVC32 mode (we may have been in SVC26 before).
        MSR     CPSR_c, #F32_bit+I32_bit+SVC32_mode

        ; If we were in a 26-bit mode, the lr value given to us would have had PSR flags in.
        TST     a2, #2_11100
        MOVNE   pc, a4
        BICEQ   pc, a4, #ARM_CC_Mask


; void *RISCOS_AddRAM(unsigned int flags, void *start, void *end, uintptr_t sigbits, void *ref)
;   Entry:
;     flags   bit 0: video memory (currently only one block permitted)
Kevin Bracey's avatar
Kevin Bracey committed
140
;             bit 1: video memory is not suitable for general use
141
;             bit 2: memory can't be used for DMA (sound, video, or other)
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
;             bits 8-11: speed indicator (arbitrary, higher => faster)
;             other bits reserved (SBZ)
;     start   = start address of RAM (inclusive) (no alignment requirements)
;     end     = end address of RAM (exclusive) (no alignment requirements, but must be >= start)
;     sigbits = significant address bit mask (1 => this bit of addr decoded, 0 => this bit ignored)
;     ref     = reference handle (NULL for first call)

; A table is built up at the head of the first block of memory.
; The table consists of (addr, len, flags) pairs, terminated by a count of those pairs; ref points to that
; counter.
; Twelve bits of flags are stored at the bottom of the length word.

        ROUT
RISCOS_AddRAM
        Push    "v1,v2,v3,v4,lr"
157
        LDR     v4, [sp, #5*4]          ; Get ref
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244

        ; Round to pages. If we were extra sneaky we could not do this and chuck out incomplete
        ; pages after concatanation, but it would be a weird HAL that gave us pages split across
        ; calls.
        ;
        ADD     a2, a2, #4096           ; round start address up
        SUB     a2, a2, #1
        MOV     a2, a2, LSR #12
        MOV     a2, a2, LSL #12
        MOV     a3, a3, LSR #12         ; round end address down
        MOV     a3, a3, LSL #12

        CMP     a3, a2
        BLS     %FT90                   ; check we aren't now null

        CMP     v4, #0
        BEQ     %FT20

        ; We are not dealing with the first block since v4 != 0.  Make an attempt to merge this block
        ; with the previous block.
        LDMDB   v4, {v1, v2}            ; Get details of the previous block
        MOV     v3, v2, LSL #20         ; Isolate flags
        BIC     v2, v2, v3, LSR #20     ; And strip from length
        ADD     v2, v1, v2              ; Get the end address
        EOR     v2, v2, a2              ; Compare with the current block start address...
        TST     v2, a4                  ; ... but only check the decoded bits.
        EOR     v2, v2, a2              ; Restore the previous block end address.
        TEQEQ   v3, a1, LSL #20         ; And are the page flags the same?
        BNE     %FT10                   ; We can't merge it after the previous block

        ; v1 = previous start
        ; v2 = previous end
        ; The block is just after the previous block.  That means the start address is unchanged, but
        ; the length is increased.
        SUB     v2, v2, v1              ; Calculate the previous block length.
        SUB     a3, a3, a2              ; Find the length of the new block.
        ; a3 = length of block
        ADD     v2, v2, a3              ; Add it to the previous length.
        ORR     v2, v2, v3, LSR #20     ; And put the flags back in.
        STR     v2, [v4, #-4]           ; Update the block size in memory.
        MOV     a1,v4
        Pull    "v1,v2,v3,v4,pc"

        ; 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     v1, v1, #1              ; Compare the address before the previous block start ...
        SUB     a3, a3, #1              ; ... with the address of the last byte in this block ...
        EOR     v1, v1, a3
        TST     v1, a4                  ; ... but check only the decoded bits.
        ADD     a3, a3, #1              ; Restore the end address.
        TEQEQ   v3, a1, LSL #20         ; And are the page flags the same?
        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     v1, [v4, #-8]           ; Get the previous block start again.

        SUB     a3, a3, a2              ; Calculate the current block size.
        SUB     v1, v1, a3              ; Subtract from the previous block start address.
        SUB     v2, v2, v1              ; Calculate the new length=end-start
        ORR     v2, v2, v3, LSR #20     ; And put the flags back in.
        STMDB   v4, {v1, v2}            ; Update the block info in memory.
        MOV     a1,v4
        Pull    "v1,v2,v3,v4,pc"

        ; 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     a3, a3, a2              ; Calculate the block size
        MOV     a1, a1, LSL #20
        ORR     a3, a3, a1, LSR #20     ; Put the flags at the bottom
        MVN     v1, a4                  ; Get the non-decoded address lines.
        ORR     a2, v1, a2              ; Set the non-decoded address bit in the start address.

30      CMP     v4, #0                  ; If the workspace has not been allocated...
        MOVEQ   v4, a2                  ; ... use this block.
        MOVEQ   v1, #0                  ; Initialise the counter.

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

90      MOV     a1,v4
        Pull    "v1,v2,v3,v4,pc"        ; We've done with this block now.



Kevin Bracey's avatar
Kevin Bracey committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
; Subtractv1v2fromRAMtable
;
; On entry: v1 = base of memory area
;           v2 = size of memory area
;           a4 = RAM table handle (ie pointer to terminator word containing number of entries)
;
; On exit:  a1-a3 preserved
;           a4 and RAM table updated
;           other registers corrupted
Subtractv1v2fromRAMtable
        ADD     v2, v1, v2              ; v2 = end address
        MOV     v1, v1, LSR #12
        MOV     v1, v1, LSL #12         ; round base down
        ADD     v2, v2, #4096
        SUB     v2, v2, #1
        MOV     v2, v2, LSR #12
        MOV     v2, v2, LSL #12         ; round end up

        LDR     v5, [a4]
        SUB     v8, a4, v5, LSL #3
10      TEQ     v8, a4
        MOVEQ   pc, lr
        LDMIA   v8!, {v3, v4}
        MOV     v6, v4, LSR #12
        ADD     v6, v3, v6, LSL #12     ; v6 = end of RAM block
        CMP     v2, v3                  ; if our end <= RAM block start
        CMPHI   v6, v1                  ; or RAM block end <= our start
        BLS     %BT10                   ; then no intersection

        MOV     v4, v4, LSL #20         ; extract flags

        CMP     v1, v3
        BHI     not_bottom

        ; our area is at the bottom
        CMP     v2, v6
        BHS     remove_block

        SUB     v6, v6, v2              ; v6 = new size
        ORR     v6, v6, v4, LSR #20     ; + flags
        STMDB   v8, {v2, v6}            ; store new base (= our end) and size
        B       %BT10

        ; we've completely covered a block. Remove it.
remove_block
290 291 292 293 294 295
        MOV     v7, v8
20      TEQ     v7, a4                  ; shuffle down subsequent blocks in table
        LDMNEIA v7, {v3, v4}
        STMNEDB v7, {v3, v4}
        ADDNE   v7, v7, #8
        BNE     %BT20
Kevin Bracey's avatar
Kevin Bracey committed
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
        SUB     v5, v5, #1
        SUB     a4, a4, #8
        STR     v5, [a4]
        SUB     v8, v8, #8
        B       %BT10

        ; our area is not at the bottom.
not_bottom
        CMP     v2, v6
        BLO     split_block

        ; our area is at the top
        SUB     v6, v1, v3              ; v6 = new size
        ORR     v6, v6, v4, LSR #20     ; + flags
        STMDB   v8, {v3, v6}            ; store original base and new size
        B       %BT10

split_block
314 315
        MOV     v7, a4
30      TEQ     v7, v8                  ; shuffle up subsequent blocks in table
Robert Sprowson's avatar
Robert Sprowson committed
316
        LDMDB   v7, {v3, v4}
317 318
        STMNEIA v7, {v3, v4}
        SUBNE   v7, v7, #8
Kevin Bracey's avatar
Kevin Bracey committed
319 320 321 322 323
        BNE     %BT30
        ADD     v5, v5, #1
        ADD     a4, a4, #8
        STR     v5, [a4]

Robert Sprowson's avatar
Robert Sprowson committed
324 325
        MOV     v4, v4, LSL #20         ; (re)extract flags

Kevin Bracey's avatar
Kevin Bracey committed
326 327 328 329 330 331 332 333
        SUB     v7, v1, v3              ; v7 = size of first half
        SUB     v6, v6, v2              ; v6 = size of second half
        ORR     v7, v7, v4, LSR #20
        ORR     v6, v6, v4, LSR #20     ; + flags
        STMDB   v8, {v3, v7}
        STMIA   v8!, {v2, v6}
        B       %BT10

334 335 336 337 338 339 340 341 342 343 344 345 346

;void RISCOS_Start(unsigned int flags, int *riscos_header, int *hal_header, void *ref)
;

; We don't return, so no need to obey ATPCS, except for parameter passing.
; register usage:   v4 = location of VRAM
;                   v6 = amount of VRAM

        ROUT
RISCOS_Start
        TEQ     a4, #0
01      BEQ     %BT01                           ; Stop here if no RAM

Kevin Bracey's avatar
Kevin Bracey committed
347 348 349 350 351 352 353 354 355
        ; subtract the HAL and OS from the list of RAM areas
        MOV     v1, a2
        LDR     v2, [a2, #OSHdr_ImageSize]
        BL      Subtractv1v2fromRAMtable
        LDR     v1, [a3, #HALDesc_Start]
        ADD     v1, a3, v1
        LDR     v2, [a3, #HALDesc_Size]
        BL      Subtractv1v2fromRAMtable

356 357 358 359 360
        LDR     v5, [a4]                        ; v5 = the number of RAM blocks
        SUB     v8, a4, v5, LSL #3              ; Jump back to the start of the list.

        ; Search for some VRAM
05      LDMIA   v8!, {v1, v2}                   ; Get a block from the list. (v1,v2)=(addr,size+flags)
361
        TST     v2, #OSAddRAM_IsVRAM            ; Is it VRAM?
362 363 364 365
        BNE     %FT20                           ; If so, deal with it below
        TEQ     v8, a4                          ; Carry on until end of list or we find some.
        BNE     %BT05

366
        ; Extract some pseudo-VRAM from first DMA-capable RAM block
367
        SUB     v8, a4, v5, LSL #3              ; Rewind again.
368 369 370 371
06      LDMIA   v8!, {v1, v2}
        TEQ     v8, a4                          ; End of list?
        TSTNE   v2, #OSAddRAM_NoDMA             ; DMA capable?
        BNE     %BT06
372 373
        MOV     v2, v2, LSR #12                 ; Remove flags
        MOV     v2, v2, LSL #12
374 375 376 377 378 379 380 381 382 383 384 385 386
        ; Is this the only DMA-capable block?
        MOV     v4, v8
        MOV     v6, #OSAddRAM_NoDMA
07      TEQ     v4, a4
        BEQ     %FT08
        LDR     v6, [v4, #4]
        ADD     v4, v4, #8
        TST     v6, #OSAddRAM_NoDMA
        BNE     %BT07
08
        ; v6 has NoDMA set if v8 was the only block
        TST     v6, #OSAddRAM_NoDMA
        MOV     v4, v1                          ; Allocate block as video memory
387
        MOV     v6, v2
388 389
        BEQ     %FT09
        SUBS    v6, v6, #16*1024*1024           ; Leave 16M if it was the only DMA-capable block
390
        MOVLS   v6, v2, LSR #1                  ; If that overflowed, take half the bank.
391
09
Kevin Bracey's avatar
Kevin Bracey committed
392 393
        CMP     v6, #32*1024*1024
        MOVHS   v6, #32*1024*1024               ; Limit allocation to 32M (arbitrary)
394 395 396

        ADD     v1, v1, v6                      ; Adjust the RAM block base...
        SUBS    v2, v2, v6                      ; ... and the size
397 398 399 400 401 402 403
        BEQ     %FT22                           ; pack array tighter if this block is all gone
        STR     v1, [v8, #-8]                   ; update base
        LDR     v1, [v8, #-4]
        MOV     v1, v1, LSL #20
        ORR     v1, v1, v2, LSR #12
        MOV     v1, v1, ROR #20                 ; merge flags back into size
        STR     v1, [v8, #-4]                   ; update size
404 405 406 407 408 409 410 411 412 413 414 415 416
        B       %FT30

        ; Note real VRAM parameters
20      MOV     v6, v2                          ; Remember the size and address
        MOV     v4, v1                          ; of the VRAM
22      TEQ     v8, a4                          ; if not at the end of the array
        LDMNEIA v8, {v1, v2}                    ; pack the array tighter
        STMNEDB v8, {v1, v2}
        ADDNE   v8, v8, #8
        BNE     %BT22
25      SUB     v5, v5, #1                      ; decrease the counter
        STR     v5, [a4, #-8]!                  ; and move the end marker down

417
30      SUB     v8, a4, v5, LSL #3              ; Rewind to start of list
418

419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
        ; Scan forwards to find the fastest block of non-DMAable memory which is at least DRAMOffset_LastFixed size
        LDMIA   v8!, {v1, v2}
31
        TEQ     v8, a4
        BEQ     %FT32
        LDMIA   v8!, {v7, ip}
        CMP     ip, #DRAMOffset_LastFixed
        ANDHS   sp, ip, #&F*OSAddRAM_Speed+OSAddRAM_NoDMA
        ANDHS   lr, v2, #&F*OSAddRAM_Speed+OSAddRAM_NoDMA
        ASSERT  OSAddRAM_Speed = 1:SHL:8
        ASSERT  OSAddRAM_NoDMA < OSAddRAM_Speed
        MOVHS   sp, sp, ROR #8                  ; Give NoDMA flag priority over speed when sorting
        CMPHS   sp, lr, ROR #8
        MOVHI   v1, v7
        MOVHI   v2, ip
        B       %BT31
32
        ; Fill in the Kernel's permanent memory table, sorting by speed and DMA ability
        ; Non-DMAable RAM is preferred over DMAable, as the kernel requires very little DMAable RAM, and we don't want to permanently claim DMAable RAM if we're not actually using it for DMA (in case machine only has a tiny amount available)
        ADD     ip, v1, #DRAMOffset_PageZero
439 440 441 442 443

        ADD     sp, v1, #DRAMOffset_ScratchSpace + ScratchSpaceSize

        Push    "a1,a2,a3"                      ; Remember our arguments

444
        SUB     v8, a4, v5, LSL #3              ; Rewind to start of list
445 446 447
        CMP     v5, #DRAMPhysTableSize          ; Don't overflow our table
        ADDHI   a4, v8, #DRAMPhysTableSize*8 - 8

448 449 450
        ; First put the VRAM information in to free up some regs
        ADD     v7, ip, #VideoPhysAddr
        STMIA   v7!, {v4, v6}
451

452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
        ; Now fill in the rest
        ASSERT  DRAMPhysAddrA = VideoPhysAddr+8
        STMIA   v7!, {v1, v2}                   ; workspace block must be first
33
        TEQ     v8, a4
        BEQ     %FT39
        LDMIA   v8!, {v1, v2}
        CMP     v2, #4096                       ; skip zero-length sections
        BLO     %BT33
        ; Perform insertion sort
        ; a1-a3, v3-v6, ip, lr free
        ADD     a1, ip, #DRAMPhysAddrA
        LDMIA   a1!, {a2, a3}
        TEQ     v1, a2
        BEQ     %BT33                           ; don't duplicate the initial block
        AND     v3, v2, #&F*OSAddRAM_Speed+OSAddRAM_NoDMA
        ASSERT  OSAddRAM_Speed = 1:SHL:8
        ASSERT  OSAddRAM_NoDMA < OSAddRAM_Speed
        MOV     v3, v3, ROR #8                  ; Give NoDMA flag priority over speed when sorting
34
        AND     v4, a3, #&F*OSAddRAM_Speed+OSAddRAM_NoDMA
        CMP     v3, v4, ROR #8
        BHI     %FT35
        TEQ     a1, v7
        LDMNEIA a1!, {a2, a3}
        BNE     %BT34
        ADD     a1, a1, #8
35
        ADD     v7, v7, #8
        ; Insert at a1-8, overwriting {a2, a3}
36
        STMDB   a1, {v1, v2}                   ; store new entry
        TEQ     a1, v7
        MOVNE   v1, a2                         ; if not at end, shuffle
        MOVNE   v2, a3                         ; overwritten entry down one,
        LDMNEIA a1!, {a2, a3}                  ; load next to be overwritten,
        BNE     %BT36                          ; and loop
        B       %BT33

39
492 493
        ; Now we have to work out the total RAM size
        MOV     a2, #0
494 495
        ADD     v6, ip, #PhysRamTable
        MOV     a3, v6
496 497
40
        LDMIA   v6!, {v1, v2}                   ; get address, size
498
        ADD     a2, a2, v2, LSR #12             ; add on size
499 500
        TEQ     v6, v7
        BNE     %BT40
501
        MOV     a2, a2, LSL #12
502

503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
        ; Work out how much DMAable RAM the HAL/kernel needs
        LDR     a1, [sp, #8]
        LDR     a1, [a1, #HALDesc_Flags]
        TST     a1, #HALFlag_NCNBWorkspace              ; do they want uncacheable workspace?
        LDRNE   a1, =SoundDMABuffers-CursorChunkAddress + ?SoundDMABuffers + 32*1024 + DRAMOffset_LastFixed
        LDREQ   a1, =SoundDMABuffers-CursorChunkAddress + ?SoundDMABuffers + DRAMOffset_LastFixed
        ; Scan PhysRamTable for a DMAable block of at least this size, extract it, and stash it in InitDMABlock
        ; Once the initial memory claiming is done we can re-insert it
        ADD     a4, a3, #DRAMPhysAddrA-VideoPhysAddr    ; don't claim VRAM

        ; First block needs special treatment as we've already claimed some of it
        LDMIA   a4!, {v1, v2}
        TST     v2, #OSAddRAM_NoDMA
        BNE     %FT41
        CMP     v2, a1
        BLO     %FT41
        ; Oh crumbs, the first block is a match for our DMA block
        ; Claim it as normal, but set InitDMAEnd to v1+DRAMOffset_LastFixed so
        ; that the already used bit won't get used for DMA
        ; We also need to be careful later on when picking the initial v2 value
        ADD     lr, v1, #DRAMOffset_LastFixed
        STR     lr, [ip, #InitDMAEnd]
        B       %FT43
41
        ; Go on to check the rest of PhysRamTable
        SUB     a1, a1, #DRAMOffset_LastFixed
42
        LDMIA   a4!, {v1, v2}
        TST     v2, #OSAddRAM_NoDMA
        BNE     %BT42
        CMP     v2, a1
        BLO     %BT42
        ; Make a note of this block
        STR     v1, [ip, #InitDMAEnd]
43
        STR     v1, [ip, #InitDMABlock]
        STR     v2, [ip, #InitDMABlock+4]
        SUB     lr, a4, a3
        STR     lr, [ip, #InitDMAOffset]
        ; Now shrink/remove this memory from PhysRamTable
        SUB     v2, v2, a1
        ADD     v1, v1, a1
        CMP     v2, #4096               ; Block all gone?
        STMHSDB a4, {v1, v2}            ; no, just shrink it
        BHS     %FT55
45
        CMP     a4, v7
        LDMNEIA a4, {v1, v2}
        STMNEDB a4, {v1, v2}
        ADDNE   a4, a4, #8
        BNE     %BT45
        SUB     v7, v7, #8
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572

; a2 = Total memory size (bytes)
; a3 = PhysRamTable
; v7 = After last used entry in PhysRamTable

; now store zeros to fill out table

55
        ADD     v2, a3, #PhysRamTableEnd-PhysRamTable
        MOV     v3, #0
        MOV     v4, #0
57
        CMP     v7, v2
        STMLOIA v7!, {v3, v4}
        BLO     %BT57

; Time to set up the L1PT. Just zero it out for now.

573 574
        LDR     a4, =DRAMOffset_L1PT+16*1024-(PhysRamTable+DRAMOffset_PageZero) ; offset from a3 to L1PT end
        ADD     a3, a3, a4
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
        MOV     a4, #16*1024
        MOV     v2, #0
        MOV     v3, #0
        MOV     v4, #0
        MOV     v5, #0
        MOV     v6, #0
        MOV     v7, #0
        MOV     v8, #0
        MOV     ip, #0
60
        STMDB   a3!, {v2-v8,ip}                         ; start at end and work back
        SUBS    a4, a4, #8*4
        BNE     %BT60

        ADD     v1, a3, #DRAMOffset_PageZero - DRAMOffset_L1PT
590
        ADD     v2, a3, #DRAMOffset_LastFixed - DRAMOffset_L1PT
591 592 593 594
        STR     a2, [v1, #RAMLIMIT]                     ; remember the RAM size
        MOV     lr, a2, LSR #12
        SUB     lr, lr, #1
        STR     lr, [v1, #MaxCamEntry]
595 596
        MOV     lr, a2, LSR #12-CAM_EntrySizeLog2+12
        CMP     a2, lr, LSL #12-CAM_EntrySizeLog2+12
597 598 599 600 601 602 603 604
        ADDNE   lr, lr, #1
        MOV     lr, lr, LSL #12
        STR     lr, [v1, #SoftCamMapSize]
        STR     a3, [v1, #InitUsedStart]                ; store start of L1PT

        ADD     v1, v1, #DRAMPhysAddrA
        MOV     v3, a3

605 606 607 608 609 610 611
        ; Detect if the DMA claiming adjusted the first block
        ; If so, we'll need to reset v2 to the start of the block at v1
        LDR     a1, [v1]
        ADD     lr, a1, #DRAMOffset_LastFixed
        TEQ     lr, v2
        MOVNE   v2, a1

612 613 614 615 616
; For the next batch of allocation routines, v1-v3 are treated as globals.
; v1 -> current entry in PhysRamTable
; v2 -> next address to allocate in v1 (may point at end of v1)
; v3 -> L1PT (or 0 if MMU on - not yet)

617
; Set up some temporary PCBTrans and PPLTrans pointers, and the initial page flags used by the page tables
618 619 620
        ADD     a1, v3, #DRAMOffset_PageZero - DRAMOffset_L1PT
        BL      Init_PCBTrans

621 622 623
; Allocate the L2PT backing store for the logical L2PT space, to
; prevent recursion.
        LDR     a1, =L2PT
Kevin Bracey's avatar
Kevin Bracey committed
624
        MOV     a2, #&00400000
625 626
        BL      AllocateL2PT

627 628
; Allocate workspace for the HAL

629 630 631
        ADD     a4, v3, #DRAMOffset_PageZero - DRAMOffset_L1PT
        LDR     a3, [sp, #8]                            ; recover pushed HAL header
        LDR     a1, =HALWorkspace
632
        LDR     a2, =AreaFlags_HALWorkspace
633 634
        LDR     lr, [a3, #HALDesc_Workspace]            ; their workspace
        LDR     ip, [a3, #HALDesc_NumEntries]           ; plus 1 word per entry
635 636
        CMP     ip, #KnownHALEntries
        MOVLO   ip, #KnownHALEntries
637
        ADD     lr, lr, ip, LSL #2
638 639 640 641
        MOV     a3, lr, LSR #12                         ; round workspace up to whole
        MOV     a3, a3, LSL #12                         ; number of pages
        CMP     a3, lr
        ADDNE   a3, a3, #&1000
642 643 644
        STR     a3, [a4, #HAL_WsSize]                   ; Make a note of allocated space
        ADD     ip, a1, ip, LSL #2                      ; Their workspace starts
        STR     ip, [a4, #HAL_Workspace]                ; after our table of entries
645 646
        BL      Init_MapInRAM

647 648 649 650
        LDR     a3, [sp, #8]                            ; recover pushed HAL header
        LDR     lr, [a3, #HALDesc_Flags]
        TST     lr, #HALFlag_NCNBWorkspace              ; do they want uncacheable
        LDRNE   a1, =HALWorkspaceNCNB                   ; workspace?
651
        LDRNE   a2, =AreaFlags_HALWorkspaceNCNB
652
        LDRNE   a3, =32*1024
653
        BLNE    Init_MapInRAM_DMA
654

655 656 657 658 659 660 661 662
; Bootstrap time. We want to get the MMU on ASAP. We also don't want to have to
; clear up too much mess later. So what we'll do is map in the three fixed areas
; (L1PT, scratch space and page zero), the CAM, ourselves, and the HAL,
; then turn on the MMU. The CAM will be filled in once the MMU is on, by
; reverse-engineering the page tables?

        ; Map in page zero
        ADD     a1, v3, #DRAMOffset_PageZero - DRAMOffset_L1PT
Jeffrey Lee's avatar
Jeffrey Lee committed
663
        LDR     a2, =ZeroPage
664
        LDR     a3, =AreaFlags_ZeroPage
665 666 667 668 669 670
        MOV     a4, #16*1024
        BL      Init_MapIn

        ; Map in scratch space
        ADD     a1, v3, #DRAMOffset_ScratchSpace - DRAMOffset_L1PT
        MOV     a2, #ScratchSpace
671
        LDR     a3, =AreaFlags_ScratchSpace
672 673 674 675 676 677
        MOV     a4, #16*1024
        BL      Init_MapIn

        ; Map in L1PT
        MOV     a1, v3
        LDR     a2, =L1PT
678 679 680
        ADD     a3, v3, #DRAMOffset_PageZero - DRAMOffset_L1PT
        LDR     a3, [a3, #PageTable_PageFlags]
        ORR     a3, a3, #PageFlags_Unavailable
681 682 683 684 685 686 687
        MOV     a4, #16*1024
        BL      Init_MapIn

        ; Map in L1PT again in PhysicalAccess (see below)
        MOV     a1, v3, LSR #20
        MOV     a1, a1, LSL #20                 ; megabyte containing L1PT
        LDR     a2, =PhysicalAccess
688 689 690
        ADD     a3, v3, #DRAMOffset_PageZero - DRAMOffset_L1PT
        LDR     a3, [a3, #PageTable_PageFlags]
        ORR     a3, a3, #PageFlags_Unavailable
691 692 693
        MOV     a4, #1024*1024
        BL      Init_MapIn

694

695 696 697 698 699 700 701
        ; Examine HAL and RISC OS locations
        LDMFD   sp, {v4,v5,v6}                  ; v4 = flags, v5 = RO desc, v6 = HAL desc
        LDR     lr, [v6, #HALDesc_Size]
        LDR     v7, [v6, #HALDesc_Start]
        ADD     v6, v6, v7                      ; (v6,v8)=(start,end) of HAL
        ADD     v8, v6, lr

702
        LDR     v7, [v5, #OSHdr_ImageSize]
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
        ADD     v7, v5, v7                      ; (v5,v7)=(start,end) of RISC OS

        TEQ     v8, v5                          ; check contiguity (as in a ROM image)
        BNE     %FT70

        ; HAL and RISC OS are contiguous. Yum.
        MOV     a1, v6
        LDR     a2, =RISCOS_Header
        SUB     a2, a2, lr

        SUB     ip, a2, a1                      ; change physical addresses passed in
        LDMIB   sp, {a3, a4}                    ; into logical addresses
        ADD     a3, a3, ip
        ADD     a4, a4, ip
        STMIB   sp, {a3, a4}
718 719
        LDR     a3, [v5, #OSHdr_DecompressHdr]  ; check if ROM is compressed, and if so, make writeable
        CMP     a3, #0
720 721
        MOVNE   a3, #OSAP_None
        MOVEQ   a3, #OSAP_ROM
722 723
        SUB     a4, v7, v6
        BL      Init_MapIn
724
        MOV     a3, v6
725 726 727
        B       %FT75

70
728 729
        ; HAL is separate. (We should cope with larger images)
        LDR     a2, =ROM
730 731 732 733 734 735
        MOV     a1, v6
        SUB     ip, a2, a1                      ; change physical address passed in
        LDR     a3, [sp, #8]                    ; into logical address
        ADD     a3, a3, ip
        STR     a3, [sp, #8]
        SUB     a4, v8, v6
736
        MOV     a3, #OSAP_ROM
737 738 739 740 741 742 743 744 745 746
        BL      Init_MapIn

        ; And now map in RISC OS
        LDR     a2, =RISCOS_Header              ; Hmm - what if position independent?
        MOV     a1, v5
        SUB     ip, a2, a1                      ; change physical address passed in
        LDR     a3, [sp, #4]                    ; into logical address
        ADD     a3, a3, ip
        STR     a3, [sp, #4]
        SUB     a4, v7, v5
747 748
        LDR     a3, [v5, #OSHdr_DecompressHdr]
        CMP     a3, #0
749
        MOVNE   a3, #OSAP_None
750
        MOVEQ   a3, #OSAP_ROM
751
        BL      Init_MapIn
752
        MOV     a3, v5
753 754 755 756
75
        ; We've now allocated all the pages we're going to before the MMU comes on.
        ; Note the end address (for RAM clear)
        ADD     a1, v3, #DRAMOffset_PageZero - DRAMOffset_L1PT
757
        STR     v1, [a1, #InitUsedBlock]
758
        STR     v2, [a1, #InitUsedEnd]
759
        STR     a3, [a1, #ROMPhysAddr]
760

761 762
        ; Note the HAL flags passed in.
        LDR     a2, [sp, #0]
763
        STR     a2, [a1, #HAL_StartFlags]
764

765
        ; Set up a reset IRQ handler (for IIC CMOS access)
Kevin Bracey's avatar
Kevin Bracey committed
766
        MSR     CPSR_c, #IRQ32_mode + I32_bit + F32_bit
767
        LDR     sp_irq, =ScratchSpace + 1024    ; 1K is plenty since Reset_IRQ_Handler now runs in SVC mode
Kevin Bracey's avatar
Kevin Bracey committed
768 769 770 771
        MSR     CPSR_c, #SVC32_mode + I32_bit + F32_bit
        LDR     a2, =Reset_IRQ_Handler
        STR     a2, [a1, #InitIRQHandler]

772 773 774 775 776 777 778 779 780 781
        ; Fill in some initial processor vectors. These will be used during ARM
        ; analysis, once the MMU is on. We do it here before the data cache is
        ; activated to save any IMB issues.
        ADRL    a2, InitProcVecs
        ADD     a3, a2, #InitProcVecsEnd - InitProcVecs
76      LDR     a4, [a2], #4
        CMP     a2, a3
        STR     a4, [a1], #4
        BLO     %BT76

Kevin Bracey's avatar
Kevin Bracey committed
782
MMU_activation_zone
783 784 785 786 787 788
; The time has come to activate the MMU. Steady now... Due to unpredictability of MMU
; activation, need to ensure that mapped and unmapped addresses are equivalent. To
; do this, we temporarily make the section containing virtual address MMUon_instr map
; to the same physical address. In case the code crosses a section boundary, do the
; next section as well.
;
789 790
        MOV     a1, #4_0000000000000001                         ; domain 0 client only
        ARM_MMU_domain a1
791

Kevin Bracey's avatar
Kevin Bracey committed
792
        ADR     a1, MMU_activation_zone
793 794 795
        MOV     a1, a1, LSR #20                 ; a1 = megabyte number (stays there till end)
        ADD     lr, v3, a1, LSL #2              ; lr -> L1PT entry
        LDMIA   lr, {a2, a3}                    ; remember old mappings
796 797 798
 [ MEMM_Type = "VMSAv6"
        LDR     ip, =(AP_ROM * L1_APMult) + L1_Section
 |
799 800 801 802 803
  [ ARM6support
        LDR     ip, =(AP_None * L1_APMult) + L1_U + L1_Section
  |
        LDR     ip, =(AP_ROM * L1_APMult) + L1_U + L1_Section
  ]
804
 ]
805 806 807 808
        ORR     a4, ip, a1, LSL #20             ; not cacheable, as we don't want
        ADD     v4, a4, #1024*1024              ; to fill the cache with rubbish
        STMIA   lr, {a4, v4}

809
        MOV     a4, a1
810 811 812 813 814
        Push    "a2,lr"
        MOV     a1, v3
        ADD     a2, v3, #DRAMOffset_PageZero-DRAMOffset_L1PT
        BL      SetTTBR
        Pull    "a2,lr"
815
        BL      Init_ARMarch                    ; corrupts a1 and ip
816
        MOV     ip, a1                          ; Remember architecture for later
817
        MOV     a1, a4
818

819
        MSREQ   CPSR_c, #F32_bit+I32_bit+UND32_mode ; Recover the soft copy of the CR
820
        MOVEQ   v5, sp
821
        ARM_read_control v5, NE
822
  [ CacheOff
823
        ORR     v5, v5, #MMUC_M                 ; MMU on
824 825
        ORR     v5, v5, #MMUC_R                 ; ROM mode enable
  |
826
        ORR     v5, v5, #MMUC_W+MMUC_C+MMUC_M   ; Write buffer, data cache, MMU on
827
        ORR     v5, v5, #MMUC_R+MMUC_Z          ; ROM mode enable, branch predict enable
828 829 830 831 832
  ]
  [ MEMM_Type = "VMSAv6"
        ORR     v5, v5, #MMUC_XP ; Extended pages enabled (v6)
        BIC     v5, v5, #MMUC_TRE+MMUC_AFE ; TEX remap, Access Flag disabled
        BIC     v5, v5, #MMUC_EE+MMUC_TE+MMUC_VE ; Exceptions = nonvectored LE ARM
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850
      [ SupportARMv6 :LAND: NoARMv7
        ; Deal with a couple of ARM11 errata
        ARM_read_ID lr
        LDR     a4, =&FFF0
        AND     lr, lr, a4
        LDR     a4, =&B760
        TEQ     lr, a4
        BNE     %FT01
        ORR     v5, v5, #MMUC_FI ; Erratum 716151: Disable hit-under-miss (enable fast interrupt mode) to prevent D-cache corruption from D-cache cleaning (the other workaround, ensuring a DSB exists inbetween the clean op and the next store access to that cache line, feels a bit heavy-handed since we'd probably have to disable IRQs to make it fully safe)
        ; Update the aux control register
        MRC     p15, 0, lr, c1, c0, 1
        ; Bit 28: Erratum 714068: Set PHD bit to prevent deadlock from PLI or I-cache invalidate by MVA
        ; Bit 31: Erratum 716151: Set FIO bit to override some of the behaviour implied by FI bit
        ORR     lr, lr, #(1:SHL:28)+(1:SHL:31)
        MCR     p15, 0, lr, c1, c0, 1
        myISB   ,lr
01
      ]
851
  ]
852 853 854
  [ NoUnaligned
        ORR     v5, v5, #MMUC_A ; Alignment exceptions on
  ]
Jeffrey Lee's avatar
Jeffrey Lee committed
855 856 857
  [ HiProcVecs
        ORR     v5, v5, #MMUC_V ; High processor vectors enabled
  ]
858

859
MMUon_instr
860 861 862
; Note, no RAM access until we've reached MMUon_nol1ptoverlap and the flat
; logical-physical mapping of the ROM has been removed (we can't guarantee that
; the RAM mapping hasn't been clobbered, and SP is currently bogus).
863
        ARM_write_control v5
864
  [ MEMM_Type = "VMSAv6"
865 866
        MOV     lr, #0
        myISB   ,lr,,y ; Just in case
867
  ]
868
        MOVEQ   sp, v5
869 870
        MSREQ   CPSR_c, #F32_bit+I32_bit+SVC32_mode

871
  [ MEMM_Type = "VMSAv6"
872
        CMP     ip, #ARMvF
Ben Avison's avatar
Ben Avison committed
873
        BEQ     %FT01
874
        MCRNE   ARM_config_cp,0,lr,ARMv4_cache_reg,C7           ; junk MMU-off contents of I-cache (works on ARMv3)
Ben Avison's avatar
Ben Avison committed
875 876
        B       %FT02
01      MCREQ   p15, 0, lr, c7, c5, 0           ; invalidate instruction cache
877
        MCREQ   p15, 0, lr, c8, c7, 0           ; invalidate TLBs
878
        MCREQ   p15, 0, lr, c7, c5, 6           ; invalidate branch predictor
879
        myISB   ,lr,,y ; Ensure below branch works
880
        BLEQ    HAL_InvalidateCache_ARMvF       ; invalidate data cache (and instruction+TLBs again!)
Ben Avison's avatar
Ben Avison committed
881
02
882 883 884 885
  |
        MOV     lr, #0                                          ; junk MMU-off contents of I-cache
        MCR     ARM_config_cp,0,lr,ARMv4_cache_reg,C7           ; (works on ARMv3)
  ]
886 887 888 889 890 891 892 893

; MMU now on. Need to jump to logical copy of ourselves. Complication arises if our
; physical address overlaps our logical address - in that case we need to map
; in another disjoint copy of ourselves and branch to that first, then restore the
; original two sections.
        ADRL    a4, RISCOS_Header
        LDR     ip, =RISCOS_Header
        SUB     ip, ip, a4
Kevin Bracey's avatar
Kevin Bracey committed
894
        ADR     a4, MMU_activation_zone
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
        MOV     a4, a4, LSR #20
        MOV     a4, a4, LSL #20                 ; a4 = base of scrambled region
        ADD     v4, a4, #2*1024*1024            ; v4 = top of scrambled region
        SUB     v4, v4, #1                      ;      (inclusive, in case wrapped to 0)
        ADR     v5, MMUon_resume
        ADD     v5, v5, ip                      ; v5 = virtual address of MMUon_resume
        CMP     v5, a4
        BLO     MMUon_nooverlap
        CMP     v5, v4
        BHI     MMUon_nooverlap

        ASSERT  ROM > 3*1024*1024
; Oh dear. We know the ROM lives high up, so we'll mangle 00100000-002FFFFF.
; But as we're overlapping the ROM, we know we're not overlapping the page tables.
        LDR     lr, =L1PT                       ; accessing the L1PT virtually now
910 911 912
 [ MEMM_Type = "VMSAv6"
        LDR     ip, =(AP_ROM * L1_APMult) + L1_Section
 |
913 914 915 916 917
  [ ARM6support
        LDR     ip, =(AP_None * L1_APMult) + L1_U + L1_Section
  |
        LDR     ip, =(AP_ROM * L1_APMult) + L1_U + L1_Section
  ]
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 954 955 956 957 958 959 960 961
        ORR     v6, a4, ip
        ADD     ip, v6, #1024*1024
        LDMIB   lr, {v7, v8}                    ; sections 1 and 2
        STMIB   lr, {v6, ip}
        RSB     ip, a4, #&00100000
        ADD     pc, pc, ip
        NOP
MMUon_overlapresume                             ; now executing from 00100000
        ADD     ip, lr, a4, LSR #18
        STMIA   ip, {a2, a3}                    ; restore original set of mappings
        BL      Init_PageTablesChanged

        MOV     a2, v7                          ; arrange for code below
        MOV     a3, v8                          ; to restore section 1+2 instead
        MOV     a1, #1

MMUon_nooverlap
        ADRL    lr, RISCOS_Header
        LDR     ip, =RISCOS_Header
        SUB     ip, ip, lr
        ADD     pc, pc, ip
        NOP
MMUon_resume
; What if the logical address of the page tables is at the physical address of the code?
; Then we have to access it via PhysicalAccess instead.
        LDR     lr, =L1PT
        CMP     lr, a4
        BLO     MMUon_nol1ptoverlap
        CMP     lr, v4
        BHI     MMUon_nol1ptoverlap
; PhysicalAccess points to the megabyte containing the L1PT. Find the L1PT within it.
        LDR     lr, =PhysicalAccess
        MOV     v6, v3, LSL #12
        ORR     lr, lr, v6, LSR #12
MMUon_nol1ptoverlap
        ADD     lr, lr, a1, LSL #2
        STMIA   lr, {a2, a3}
        BL      Init_PageTablesChanged

; The MMU is now on. Wahey. Let's get allocating.

        LDR     sp, =ScratchSpace + ScratchSpaceSize - 4*3 ; 3 items already on stack :)

962 963
        LDR     a1, =ZeroPage

964 965
        ADD     lr, v3, #DRAMOffset_PageZero-DRAMOffset_L1PT   ; lr = PhysAddr of zero page
        SUB     v1, v1, lr
966 967 968 969 970 971 972
        ADD     v1, v1, a1                              ; turn v1 from PhysAddr to LogAddr

        LDR     a2, [a1, #InitUsedBlock]                ; turn this from Phys to Log too
        SUB     a2, a2, lr
        ADD     a2, a2, a1
        STR     a2, [a1, #InitUsedBlock]

973

974 975 976 977
; Store the logical address of the HAL descriptor
        LDR     a2, [sp, #8]
        STR     a2, [a1, #HAL_Descriptor]

978 979 980 981
        MOV     v3, #0                                  ; "MMU is on" signal

        BL      ARM_Analyse

Kevin Bracey's avatar
Kevin Bracey committed
982 983
        ChangedProcVecs a1

984 985 986 987
        MOV     a1, #L1_Fault
        BL      RISCOS_ReleasePhysicalAddress

        LDR     a1, =HALWorkspace
Jeffrey Lee's avatar
Jeffrey Lee committed
988
        LDR     a2, =ZeroPage
989
        LDR     a3, [a2, #HAL_WsSize]
Jeffrey Lee's avatar
Jeffrey Lee committed
990 991 992
      [ ZeroPage <> 0
        MOV     a2, #0
      ]
993 994
        BL      memset

Jeffrey Lee's avatar
Jeffrey Lee committed
995
        LDR     a2, =ZeroPage
996 997 998
        LDR     a1, =IOLimit
        STR     a1, [a2, #IOAllocLimit]
        LDR     a1, =IO
999 1000 1001 1002
        STR     a1, [a2, #IOAllocPtr]

        BL      SetUpHALEntryTable

1003 1004 1005
; Initialise the HAL. Due to its memory claiming we need to get our v1 and v2 values
; into workspace and out again around it.

Jeffrey Lee's avatar
Jeffrey Lee committed
1006
        LDR     a1, =ZeroPage
1007 1008 1009
        STR     v1, [a1, #InitUsedBlock]
        STR     v2, [a1, #InitUsedEnd]

1010
        LDR     a1, =RISCOS_Header
1011
        LDR     a2, =HALWorkspaceNCNB
1012 1013 1014
        AddressHAL
        CallHAL HAL_Init

1015
        DebugTX "HAL initialised"
1016

1017 1018 1019 1020 1021 1022 1023 1024 1025
        MOV     a1, #64 ; Old limit prior to OMAP3 port
        CallHAL HAL_IRQMax
        CMP     a1, #MaxInterrupts
        MOVHI   a1, #MaxInterrupts ; Avoid catastrophic failure if someone forgot to increase MaxInterrupts
        LDR     a2, =ZeroPage
        STR     a1, [a2, #IRQMax]

        LDR     v1, [a2, #InitUsedBlock]
        LDR     v2, [a2, #InitUsedEnd]
1026

1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
; Start timer zero, at 100 ticks per second
        MOV     a1, #0
        CallHAL HAL_TimerGranularity

        MOV     a2, a1
        MOV     a1, #100
        BL      __rt_udiv

        MOV     a2, a1
        MOV     a1, #0
        CallHAL HAL_TimerSetPeriod
1038

1039 1040
        DebugTX "IICInit"

1041 1042
        BL      IICInit

1043
; Remember some stuff that's about to get zapped
1044 1045 1046 1047 1048
        LDR     ip, =ZeroPage
        LDR     v4, [ip, #ROMPhysAddr]
        LDR     v5, [ip, #RAMLIMIT]
        LDR     v7, [ip, #MaxCamEntry]
        LDR     v8, [ip, #IRQMax]
1049

1050
        LDR     a1, [ip, #HAL_StartFlags]
Kevin Bracey's avatar
Kevin Bracey committed
1051
        TST     a1, #OSStartFlag_RAMCleared
1052
        BLEQ    ClearWkspRAM            ; Only clear the memory if the HAL didn't
1053

1054
; Put it back
1055 1056 1057 1058 1059
        LDR     ip, =ZeroPage
        STR     v4, [ip, #ROMPhysAddr]
        STR     v5, [ip, #RAMLIMIT]
        STR     v7, [ip, #MaxCamEntry]
        STR     v8, [ip, #IRQMax]
1060

1061
; Calculate CPU feature flags
1062 1063
        BL      ReadCPUFeatures

1064
        MOV     v8, ip
Kevin Bracey's avatar
Kevin Bracey committed
1065

1066 1067
        DebugTX "HAL_CleanerSpace"

1068
; Set up the data cache cleaner space if necessary (eg. for StrongARM core)
Kevin Bracey's avatar
Kevin Bracey committed
1069
        MOV     a1, #-1
1070 1071 1072 1073
        CallHAL HAL_CleanerSpace
        CMP     a1, #-1          ;-1 means none needed (HAL only knows this if for specific ARM core eg. system-on-chip)
        BEQ     %FT20
        LDR     a2, =DCacheCleanAddress
1074
        LDR     a3, =AreaFlags_DCacheClean
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
        ASSERT  DCacheCleanSize = 4*&10000                ; 64k of physical space used 4 times (allows large page mapping)
        MOV     a4, #&10000
        MOV     ip, #4
        SUB     sp, sp, #5*4       ;room for a1-a4,ip
10
        STMIA   sp, {a1-a4, ip}
        BL      Init_MapIn
        LDMIA   sp, {a1-a4, ip}
        SUBS    ip, ip, #1
        ADD     a2, a2, #&10000
        BNE     %BT10
        ADD     sp, sp, #5*4
1087

1088
20
1089 1090 1091 1092 1093 1094 1095 1096 1097 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
; Decompress the ROM
        LDR     a1, =RISCOS_Header
        LDR     a2, [a1, #OSHdr_DecompressHdr]
        CMP     a2, #0
        BEQ     %FT30
        ADD     ip, a1, a2
        ASSERT  OSDecompHdr_WSSize = 0
        ASSERT  OSDecompHdr_Code = 4
        LDMIA   ip, {a3-a4}
        ADRL    a2, SyncCodeAreas
        CMP     a3, #0 ; Any workspace required?
        ADD     a4, a4, ip
   [ DebugHALTX
        BNE     %FT25
        DebugTX "Decompressing ROM, no workspace required"
      [ NoARMv5
        MOV     lr, pc
        MOV     pc, a4
      |
        BLX     a4
      ]
        DebugTX "Decompression complete"
        B       %FT27
25
   |
        ADREQ   lr, %FT27
        MOVEQ   pc, a4
   ]
        Push    "a1-a4,v1-v2,v5-v7"
; Allocate workspace for decompression code
; Workspace is located at a 4MB-aligned log addr, and is a multiple of 1MB in
; size. This greatly simplifies the code required to free the workspace, since
; we can guarantee it will have been section-mapped, and won't hit any
; partially-allocated L2PT blocks (where 4 L1PT entries point to subsections of
; the same L2PT page)
; This means all we need to do to free the workspace is zap the L1PT entries
; and rollback v1 & v2
; Note: This is effectively a MB-aligned version of Init_MapInRAM
1127
ROMDecompWSAddr * 4<<20
1128 1129 1130 1131 1132
        DebugTX "Allocating decompression workspace"
        LDR     v5, =(1<<20)-1
        ADD     v7, a3, v5
        BIC     v7, v7, v5 ; MB-aligned size
        STR     v7, [sp, #8] ; Overwrite stacked WS size
1133
        MOV     v6, #ROMDecompWSAddr ; Current log addr
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
26
        ADD     v2, v2, v5
        BIC     v2, v2, v5 ; MB-aligned physram
        LDMIA   v1, {a2, a3}
        SUB     a2, v2, a2 ; Amount of bank used
        SUB     a2, a3, a2 ; Amount of bank remaining
        MOVS    a2, a2, ASR #20 ; Round down to nearest MB
        LDRLE   v2, [v1, #8]! ; Move to next bank if 0MB left
        BLE     %BT26
        CMP     a2, v7, LSR #20
        MOVHS   a4, v7
        MOVLO   a4, a2, LSL #20 ; a4 = amount to take
        MOV     a1, v2 ; set up parameters for MapIn call
        MOV     a2, v6
1148
        MOV     a3, #OSAP_None
1149 1150 1151 1152 1153 1154 1155
        SUB     v7, v7, a4 ; Decrease amount to allocate
        ADD     v2, v2, a4 ; Increase physram ptr
        ADD     v6, v6, a4 ; Increase logram ptr
        BL      Init_MapIn
        CMP     v7, #0
        BNE     %BT26
        Pull    "a1-a2,v1-v2" ; Pull OS header, IMB func ptr, workspace size, decompression code
1156
        MOV     a3, #ROMDecompWSAddr
1157 1158 1159 1160 1161 1162 1163 1164 1165
        DebugTX "Decompressing ROM"
      [ NoARMv5
        MOV     lr, pc
        MOV     pc, v2
      |
        BLX     v2
      ]
        DebugTX "Decompression complete"
; Before we free the workspace, make sure we zero it
1166
        MOV     a1, #ROMDecompWSAddr
1167 1168 1169
        MOV     a2, #0
        MOV     a3, v1
        BL      memset
1170 1171 1172
; Flush the workspace from the cache so we can unmap it
; Really we should make the pages uncacheable first, but for simplicity we do a
; full cache+TLB clean+invalidate later on when changing the ROM permissions
1173
        MOV     a1, #ROMDecompWSAddr
1174 1175
        ADD     a2, a1, v1
        ARMop   Cache_CleanInvalidateRange
1176
; Zero each L1PT entry
1177
        LDR     a1, =L1PT+(ROMDecompWSAddr>>18)
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
        MOV     a2, #0
        MOV     a3, v1, LSR #18
        BL      memset
; Pop our registers and we're done
        Pull    "v1-v2,v5-v7"
        DebugTX "ROM decompression workspace freed"
27
; Now that the ROM is decompressed we need to change the ROM page mapping to
; read-only. The easiest way to do this is to make another call to Init_MapIn.
; But before we can do that we need to work out if the HAL+OS are contiguous in
; physical space. To do this we can just check if the L1PT entry for the OS is a
; section mapping.
        LDR     a1, =L1PT+(ROM>>18)
        LDR     a1, [a1]
        ASSERT  L1_Section = 2
        ASSERT  L1_Page = 1
        TST     a1, #2
; Section mapped, get address from L1PT
        MOVNE   a1, a1, LSR #20
        MOVNE   a1, a1, LSL #20
        MOVNE   a2, #ROM
        MOVNE   a4, #OSROM_ImageSize*1024
        BNE     %FT29
; Page/large page mapped, get address from L2PT
        LDR     a2, =RISCOS_Header
        LDR     a1, =L2PT
        LDR     a1, [a1, a2, LSR #10]
        LDR     a4, [a2, #OSHdr_ImageSize]
        MOV     a1, a1, LSR #12
        MOV     a1, a1, LSL #12
29
1209
        MOV     a3, #OSAP_ROM
1210 1211 1212 1213
        BL      Init_MapIn
; Flush & invalidate cache/TLB to ensure everything respects the new page access
; Putting a flush here also means the decompression code doesn't have to worry
; about IMB'ing the decompressed ROM
Jeffrey Lee's avatar
Jeffrey Lee committed
1214
        ARMop   MMU_Changing ; Perform full clean+invalidate to ensure any lingering cache lines for the decompression workspace are gone
1215 1216
        DebugTX "ROM access changed to read-only"
30
1217 1218
; Allocate the CAM
        LDR     a3, [v8, #SoftCamMapSize]
1219
        LDR     a2, =AreaFlags_CAM
1220 1221 1222 1223 1224
        LDR     a1, =CAM
        BL      Init_MapInRAM

; Allocate the supervisor stack
        LDR     a1, =SVCStackAddress
1225
        LDR     a2, =AreaFlags_SVCStack
1226 1227 1228 1229 1230
        LDR     a3, =SVCStackSize
        BL      Init_MapInRAM

; Allocate the interrupt stack
        LDR     a1, =IRQStackAddress
1231
        LDR     a2, =AreaFlags_IRQStack
1232 1233 1234 1235 1236
        LDR     a3, =IRQStackSize
        BL      Init_MapInRAM

; Allocate the abort stack
        LDR     a1, =ABTStackAddress
1237
        LDR     a2, =AreaFlags_ABTStack
1238 1239 1240 1241 1242
        LDR     a3, =ABTStackSize
        BL      Init_MapInRAM

; Allocate the undefined stack
        LDR     a1, =UNDStackAddress
1243
        LDR     a2, =AreaFlags_UNDStack
1244 1245 1246
        LDR     a3, =UNDStackSize
        BL      Init_MapInRAM

1247
; Allocate the system heap (just 32K for now - will grow as needed)
1248
        LDR     a1, =SysHeapAddress
1249
        LDR     a2, =AreaFlags_SysHeap
1250
        LDR     a3, =32*1024
1251
        BL      Init_MapInRAM_Clear
1252

1253
; Allocate the cursor/system/sound block - first the cached bit
1254
        LDR     a1, =CursorChunkAddress
1255
        LDR     a2, =AreaFlags_CursorChunkCacheable
1256
        LDR     a3, =SoundDMABuffers - CursorChunkAddress
1257
        BL      Init_MapInRAM_DMA
1258 1259
; then the uncached bit
        LDR     a1, =SoundDMABuffers
1260
        LDR     a2, =AreaFlags_CursorChunk
1261
        LDR     a3, =?SoundDMABuffers
1262
        BL      Init_MapInRAM_DMA
1263

1264
        LDR     a1, =KbuffsBaseAddress
1265
        LDR     a2, =AreaFlags_Kbuffs
1266
        LDR     a3, =(KbuffsSize + &FFF) :AND: &FFFFF000  ;(round to 4k)
1267
        BL      Init_MapInRAM_Clear
1268

Jeffrey Lee's avatar
Jeffrey Lee committed
1269 1270 1271
 [ HiProcVecs
        ; Map in DebuggerSpace
        LDR     a1, =DebuggerSpace
1272
        LDR     a2, =AreaFlags_DebuggerSpace
Jeffrey Lee's avatar
Jeffrey Lee committed
1273
        LDR     a3, =(DebuggerSpace_Size + &FFF) :AND: &FFFFF000
1274
        BL      Init_MapInRAM_Clear
Jeffrey Lee's avatar
Jeffrey Lee committed
1275 1276
 ]

1277
 [ MinorL2PThack
1278 1279 1280 1281 1282 1283
; Allocate backing L2PT for application space
; Note that ranges must be 4M aligned, as AllocateL2PT only does individual
; (1M) sections, rather than 4 at a time, corresponding to a L2PT page. The
; following space is available for dynamic areas, and ChangeDyn.s will get
; upset if it sees only some out of a set of 4 section entries pointing to the
; L2PT page.
1284
        MOV     a1, #0
Kevin Bracey's avatar
Kevin Bracey committed
1285
        MOV     a2, #AplWorkMaxSize             ; Not quite right, but the whole thing's wrong anyway
1286
        ASSERT  AplWorkMaxSize :MOD: (4*1024*1024) = 0
1287 1288 1289 1290
        BL      AllocateL2PT
; And for the system heap. Sigh
        LDR     a1, =SysHeapAddress
        LDR     a2, =SysHeapMaxSize
1291 1292
        ASSERT  SysHeapAddress :MOD: (4*1024*1024) = 0
        ASSERT  SysHeapMaxSize :MOD: (4*1024*1024) = 0
1293 1294 1295
        BL      AllocateL2PT
 ]

1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
        STR     v2, [v8, #InitUsedEnd]

        ; Put InitDMABlock back into PhysRamTable
        Push    "v1-v7"
        ASSERT  InitDMAOffset = InitDMABlock+8
        ADD     v1, v8, #InitDMABlock
        LDMIA   v1, {v1-v3}
        ADD     v3, v3, #PhysRamTable
        ADD     v3, v3, v8
        ; Work out whether the block was removed or merely shrunk
        LDMDB   v3, {v4-v5}
        ADD     v6, v1, v2
        ADD     v7, v4, v5
        STMDB   v3, {v1-v2}
        TEQ     v6, v7
        BEQ     %FT40                   ; End addresses match, it was shrunk
35
        LDMIA   v3, {v1-v2}             ; Shuffle following entries down
        STMIA   v3!, {v4-v5}
        MOV     v4, v1
        MOVS    v5, v2
        BNE     %BT35
40
        Pull    "v1-v7"
1320 1321 1322 1323 1324 1325 1326

        MSR     CPSR_c, #F32_bit+I32_bit+IRQ32_mode
        LDR     sp, =IRQSTK
        MSR     CPSR_c, #F32_bit+I32_bit+ABT32_mode
        LDR     sp, =ABTSTK
        MSR     CPSR_c, #F32_bit+I32_bit+UND32_mode
        LDR     sp, =UNDSTK
1327
        MSR     CPSR_c, #F32_bit+SVC2632
1328 1329
        LDR     sp, =SVCSTK

1330
        LDR     ip, =CAM
1331
        STR     ip, [v8, #CamEntriesPointer]
1332

1333 1334 1335 1336 1337
        BL      ConstructCAMfromPageTables

        MOV     a1, #4096
        STR     a1, [v8, #Page_Size]

1338 1339
        BL      CountPageTablePages

1340
        B       Continue_after_HALInit
1341 1342 1343

        LTORG

1344
 [ MEMM_Type = "VMSAv6"
1345 1346 1347 1348 1349 1350
HAL_InvalidateCache_ARMvF
        ; Cache invalidation for ARMs with multiple cache levels, used before ARMop initialisation
        ; This function gets called before we have a stack set up, so we've got to preserve as many registers as possible
        ; The only register we can safely change is ip, but we can switch into FIQ mode with interrupts disabled and use the banked registers there
        MRS     ip, CPSR
        MSR     CPSR_c, #F32_bit+I32_bit+FIQ32_mode
Jeffrey Lee's avatar
Jeffrey Lee committed
1351 1352 1353 1354 1355 1356
        MOV     r9, #0
        MCR     p15, 0, r9, c7, c5, 0           ; invalidate instruction cache
        MCR     p15, 0, r9, c8, c7, 0           ; invalidate TLBs
        MCR     p15, 0, r9, c7, c5, 6           ; invalidate branch target predictor
        myDSB   ,r9,,y                          ; Wait for completion
        myISB   ,r9,,y
Jeffrey Lee's avatar
Jeffrey Lee committed
1357
        ; Check whether we're ARMv7 (and thus multi-level cache) or ARMv6 (and thus single-level cache)
Jeffrey Lee's avatar
Jeffrey Lee committed
1358 1359
        MRC     p15, 0, r8, c0, c0, 1
        TST     r8, #&80000000 ; EQ=ARMv6, NE=ARMv7
Ben Avison's avatar
Ben Avison committed
1360
        BEQ     %FT80
Jeffrey Lee's avatar
Jeffrey Lee committed
1361 1362

        ; This is basically the same algorithm as the MaintainDataCache_WB_CR7_Lx macro, but tweaked to use less registers and to read from CP15 directly
Ben Avison's avatar
Ben Avison committed
1363
        MRC     p15, 1, r8, c0, c0, 1           ; Read CLIDR to r8
Jeffrey Lee's avatar
Jeffrey Lee committed
1364 1365 1366 1367 1368 1369 1370 1371 1372 1373
        TST     r8, #&07000000
        BEQ     %FT50
        MOV     r11, #0 ; Current cache level
10 ; Loop1
        ADD     r10, r11, r11, LSR #1 ; Work out 3 x cachelevel
        MOV     r9, r8, LSR r10 ; bottom 3 bits are the Cache type for this level
        AND     r9, r9, #7 ; get those 3 bits alone
        CMP     r9, #2
        BLT     %FT40 ; no cache or only instruction cache at this level
        MCR     p15, 2, r11, c0, c0, 0 ; write CSSELR from r11
1374
        ISB
Jeffrey Lee's avatar
Jeffrey Lee committed
1375
        MRC     p15, 1, r9, c0, c0, 0 ; read current CSSIDR to r9
1376
        AND     r10, r9, #CCSIDR_LineSize_mask ; extract the line length field
Jeffrey Lee's avatar
Jeffrey Lee committed
1377
        ADD     r10, r10, #4 ; add 4 for the line length offset (log2 16 bytes)
1378 1379
        LDR     r8, =CCSIDR_Associativity_mask:SHR:CCSIDR_Associativity_pos
        AND     r8, r8, r9, LSR #CCSIDR_Associativity_pos ; r8 is the max number on the way size (right aligned)
Jeffrey Lee's avatar
Jeffrey Lee committed
1380
        CLZ     r13, r8 ; r13 is the bit position of the way size increment
1381 1382
        LDR     r12, =CCSIDR_NumSets_mask:SHR:CCSIDR_NumSets_pos
        AND     r12, r12, r9, LSR #CCSIDR_NumSets_pos ; r12 is the max number of the index size (right aligned)
Jeffrey Lee's avatar
Jeffrey Lee committed
1383 1384 1385 1386 1387
20 ; Loop2
        MOV     r9, r12 ; r9 working copy of the max index size (right aligned)
30 ; Loop3
        ORR     r14, r11, r8, LSL r13 ; factor in the way number and cache number into r14
        ORR     r14, r14, r9, LSL r10 ; factor in the index number
1388
        DCISW   r14 ; Invalidate
Jeffrey Lee's avatar
Jeffrey Lee committed
1389 1390 1391 1392
        SUBS    r9, r9, #1 ; decrement the index
        BGE     %BT30
        SUBS    r8, r8, #1 ; decrement the way number
        BGE     %BT20
1393
        DSB                ; Cortex-A7 errata 814220: DSB required when changing cache levels when using set/way operations. This also counts as our end-of-maintenance DSB.
Ben Avison's avatar
Ben Avison committed
1394
        MRC     p15, 1, r8, c0, c0, 1
Jeffrey Lee's avatar
Jeffrey Lee committed
1395 1396 1397 1398 1399 1400 1401
40 ; Skip
        ADD     r11, r11, #2
        AND     r14, r8, #&07000000
        CMP     r14, r11, LSL #23
        BGT     %BT10

50 ; Finished
1402 1403 1404 1405 1406
        ; Wait for clean to complete
        MOV     r8, #0
        MCR     p15, 0, r8, c7, c5, 0           ; invalidate instruction cache
        MCR     p15, 0, r8, c8, c7, 0           ; invalidate TLBs
        MCR     p15, 0, r8, c7, c5, 6           ; invalidate branch target predictor
1407 1408
        myDSB   ,r8,,y                          ; Wait for completion
        myISB   ,r8,,y
1409 1410 1411 1412
        ; All caches clean; switch back to SVC, then recover the stored PSR from ip (although we can be fairly certain we started in SVC anyway)
        MSR     CPSR_c, #F32_bit+I32_bit+SVC32_mode
        MSR     CPSR_cxsf, ip
        MOV     pc, lr
Ben Avison's avatar
Ben Avison committed
1413 1414 1415
80 ; ARMv6 case
        MCR     ARM_config_cp,0,r9,ARMv4_cache_reg,C7 ; ARMv3-ARMv6 I+D cache flush
        B       %BT50
1416
 ] ; MEMM_Type = "VMSAv6"
1417

1418
CountPageTablePages ROUT
1419
        Entry
Jeffrey Lee's avatar
Jeffrey Lee committed
1420
        LDR     a1, =ZeroPage
1421 1422
        LDR     a2, =CAM
        LDR     a3, [a1, #MaxCamEntry]
Jeffrey Lee's avatar
Jeffrey Lee committed
1423
      [ ZeroPage <> 0
1424
        MOV     a1, #0
Jeffrey Lee's avatar
Jeffrey Lee committed
1425
      ]
1426
        ADD     a3, a3, #1
1427
        ADD     a4, a2, a3, LSL #CAM_EntrySizeLog2
1428
        ASSERT  (L2PT :AND: &3FFFFF) = 0
1429 1430 1431
        LDR     lr, =L2PT :SHR: 22
10      LDR     ip, [a4, #CAM_LogAddr-CAM_EntrySize]!
        TEQ     lr, ip, LSR #22
1432 1433 1434
        ADDEQ   a1, a1, #4096
        TEQ     a4, a2
        BNE     %BT10
Jeffrey Lee's avatar
Jeffrey Lee committed
1435
        LDR     a2, =ZeroPage
1436
        STR     a1, [a2, #L2PTUsed]
1437
        EXIT
1438

1439
; int PhysAddrToPageNo(uint64_t addr)
1440 1441 1442 1443 1444
;
; Converts a physical address to the page number of the page containing it.
; Returns -1 if address is not in RAM.

PhysAddrToPageNo
1445 1446
        TEQ     a2, #0
        BNE     %FT90                           ; only handle addresses under 4GB for now
1447 1448 1449
        MOV     a4, #0
        LDR     ip, =ZeroPage + PhysRamTable
10      LDMIA   ip!, {a2, a3}                   ; get phys addr, size
1450
        MOVS    a3, a3, LSR #12                 ; end of list? (size=0)
1451 1452
        BEQ     %FT90                           ;   then it ain't RAM
        SUB     a2, a1, a2                      ; a2 = amount into this bank
1453 1454
        CMP     a2, a3, LSL #12                 ; if more than size
        ADDHS   a4, a4, a3, LSL #12             ;   increase counter by size of bank
1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470
        BHS     %BT10                           ;   and move to next
        ADD     a4, a4, a2                      ; add offset to counter
        MOV     a1, a4, LSR #12                 ; convert counter to a page number
        MOV     pc, lr

90      MOV     a1, #-1
        MOV     pc, lr


; A routine to construct the soft CAM from the page tables. This is used
; after a soft reset, and also on a hard reset as it's an easy way of
; clearing up after the recursive page table allocaton.

        ROUT
ConstructCAMfromPageTables
        Push    "v1-v8, lr"
Jeffrey Lee's avatar
Jeffrey Lee committed
1471
        LDR     a1, =ZeroPage
1472 1473 1474
        LDR     a2, [a1, #MaxCamEntry]
        LDR     v1, =CAM                        ; v1 -> CAM (for whole routine)
        ADD     a2, a2, #1
1475
        ADD     a2, v1, a2, LSL #CAM_EntrySizeLog2
1476 1477

        LDR     a3, =DuffEntry                  ; Clear the whole CAM, from
1478
        MOV     a4, #AreaFlags_Duff             ; the top down.
1479 1480 1481 1482 1483 1484 1485 1486
        ASSERT  CAM_LogAddr=0
        ASSERT  CAM_PageFlags=4
        ASSERT  CAM_PMP=8
        ASSERT  CAM_PMPIndex=12
        ASSERT  CAM_EntrySize=16
        MOV     v2, #0
        MOV     v3, #-1
10      STMDB   a2!, {a3, a4, v2, v3}
1487 1488 1489 1490 1491 1492
        CMP     a2, v1
        BHI     %BT10

        MOV     v2, #0                          ; v2 = logical address
        LDR     v3, =L1PT                       ; v3 -> L1PT (not used much)
        LDR     v4, =L2PT                       ; v4 -> L2PT
1493
30      LDR     a1, [v3, v2, LSR #18]           ; a1 = first level descriptor
1494 1495
        BL      DecodeL1Entry                   ; a1,a2 = phys addr, a3 = page flags/type, a4 = page size (bytes)
        CMP     a3, #-2                         ; Only care about page table pointers
1496
        BEQ     %FT40
1497 1498 1499 1500
        ADDS    v2, v2, #&00100000
        BCC     %BT30
        Pull    "v1-v8, pc"

1501
40      LDR     a1, [v4, v2, LSR #10]           ; a1 = second level descriptor
1502 1503
        BL      DecodeL2Entry                   ; a1,a2 = phys addr, a3 = flags (-1 if fault), a4 = page size (bytes)
        CMP     a3, #-1                         ; move to next page if fault
1504
        BEQ     %FT80
1505 1506 1507
        SUBS    a4, a4, #4096                   ; large pages get bits 12-15 from the virtual address
        ANDNE   lr, v2, a4
        ORR     v6, a3, #PageFlags_Unavailable
1508 1509 1510
        ORRNE   a1, a1, lr
        BL      PhysAddrToPageNo                ; -1 if unknown page
        ADDS    a1, v1, a1, LSL #CAM_EntrySizeLog2 ; a1 -> CAM entry
1511 1512
        ASSERT  CAM_LogAddr=0
        ASSERT  CAM_PageFlags=4
1513
        STMCCIA a1, {v2, v6}                    ; store logical address, PPL
1514

1515
80      ADD     v2, v2, #&00001000
1516 1517
        TST     v2, #&000FF000
        BNE     %BT40
1518 1519
        TEQ     v2, #0                          ; yuck (could use C from ADDS but TST corrupts C
        BNE     %BT30                           ; because of big constant)
1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537

        Pull    "v1-v8, pc"



; Allocate a physical page from DRAM
;
; On entry:
;    v1 -> current entry in PhysRamTable
;    v2 -> end of last used physical page
; On exit:
;    a1 -> next free page
;    v1, v2 updated
;
; No out of memory check...

Init_ClaimPhysicalPage
        MOV     a1, v2
1538
        LDMIA   v1, {a2, a3}
1539 1540
        MOV     a3, a3, LSR #12
        ADD     a2, a2, a3, LSL #12             ; ip = end of this bank
1541
        CMP     v2, a2                          ; advance v2 to next bank if
1542 1543
        LDRHS   a1, [v1, #8]!                   ; this bank is fully used
        ADD     v2, a1, #4096
1544
        MOV     pc, lr
1545 1546 1547 1548 1549

; Allocate and map in some RAM.
;
; On entry:
;    a1 = logical address
Kevin Bracey's avatar
Kevin Bracey committed
1550
;    a2 = access permissions (see Init_MapIn)
1551
;    a3 = length (4K multiple)
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565
;    v1 -> current entry in PhysRamTable
;    v2 = next physical address
;    v3 -> L1PT
;
; On exit:
;    a1 -> physical address of start of RAM (deduce the rest from PhysRamTable)
;
; No out of memory check...
Init_MapInRAM ROUT
        Push    "v4-v8,lr"
        MOV     v8, #-1
        MOV     v5, a3                          ; v5 = amount of memory required
        MOV     v6, a1                          ; v6 = logical address
        MOV     v7, a2                          ; v7 = access permissions
1566 1567
10      LDMIA   v1, {v4, ip}                    ; v4 = addr of bank, ip = len+flags
        MOV     ip, ip, LSR #12
1568
        SUB     v4, v2, v4                      ; v4 = amount of bank used
1569
        RSBS    v4, v4, ip, LSL #12             ; v4 = amount of bank left
1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
        LDREQ   v2, [v1, #8]!                   ; move to next bank if 0 left
        BEQ     %BT10

        CMP     v8, #-1                         ; is this the first bank?
        MOVEQ   v8, v2                          ; remember it

        CMP     v4, v5                          ; sufficient in this bank?
        MOVHS   a4, v5
        MOVLO   a4, v4                          ; a4 = amount to take

        MOV     a1, v2                          ; set up parameters for MapIn call
        MOV     a2, v6                          ; then move globals (in case MapIn
        MOV     a3, v7                          ; needs to allocate for L2PT)
        ADD     v2, v2, a4                      ; advance physaddr
        SUB     v5, v5, a4                      ; decrease wanted
        ADD     v6, v6, a4                      ; advance address pointer
        BL      Init_MapIn                      ; map in the RAM
        TEQ     v5, #0                          ; more memory still required?
        BNE     %BT10

        MOV     a1, v8
        Pull    "v4-v8,pc"

1593 1594 1595 1596 1597 1598 1599 1600 1601 1602
Init_MapInRAM_Clear ROUT                        ; same as Init_MapInRAM but also
        Push    "a1,a3,v5,lr"                   ; clears the mapped in result
        BL      Init_MapInRAM
        MOV     v5, a1
        Pull    "a1,a3"
        MOV     a2, #0
        BL      memset
        MOV     a1, v5
        Pull    "v5,pc"

1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631
; Allocate and map a physically contigous chunk of some DMAable RAM.
;
; On entry:
;    a1 = logical address
;    a2 = access permissions (see Init_MapIn)
;    a3 = length (4K multiple)
;    v1 -> current entry in PhysRamTable
;    v2 = next physical address
;    v3 -> L1PT
;
; On exit:
;    a1 -> physical address of start of RAM (deduce the rest from PhysRamTable)
;
; Use this routine with caution - correct total amount of required DMA memory
; must have been calculated beforehand and stashed in InitDMABlock
Init_MapInRAM_DMA ROUT
        Push    "a1,a3,v4-v5,ip,lr"
        TEQ     v3, #0                          ; MMU on?
        LDREQ   v4, =ZeroPage                   ; get workspace directly
        ADDNE   v4, v3, #DRAMOffset_PageZero-DRAMOffset_L1PT ; deduce from L1PT
        LDR     v5, [v4, #InitDMAEnd]
        ADD     lr, v5, a3                      ; claim the RAM
        STR     lr, [v4, #InitDMAEnd]

        MOV     a4, a3
        MOV     a3, a2
        MOV     a2, a1
        MOV     a1, v5
        BL      Init_MapIn                      ; map it in
1632
        ; DMA regions won't get cleared by ClearWkspRam, so do it manually
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
        ; Could potentially skip this if the HAL says RAM is already clear, but
        ; for now do it anyway (especially since startup flags haven't been set
        ; when we're first called)
        Pull    "a1,a3"
        TEQ     v3, #0
        MOVNE   a1, v5
        MOV     a2, #0
        BL      memset
        MOV     a1, v5
        Pull    "v4-v5,ip,pc"

1644 1645 1646 1647 1648
; Map a range of physical addresses to a range of logical addresses.
;
; On entry:
;    a1 = physical address
;    a2 = logical address
1649
;    a3 = DA flags
1650
;    a4 = area size (4K multiple)
1651 1652 1653 1654 1655
;    v1 -> current entry in PhysRamTable
;    v2 = last used physical address
;    v3 -> L1PT (or 0 if MMU on)

Init_MapIn ROUT
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670
        Entry   "v4-v7"
        MOV     v4, a1                          ; v4 = physaddr
        MOV     v5, a2                          ; v5 = logaddr
        MOV     v6, a3                          ; v6 = page flags
        MOV     v7, a4                          ; v7 = area size
        ; Set up a2-a4 for the Get*PTE functions
        TEQ     v3, #0
        LDREQ   a3, =ZeroPage
        ADDNE   a3, v3, #DRAMOffset_PageZero-DRAMOffset_L1PT
        MOV     a2, v6
        LDR     a4, [a3, #MMU_PCBTrans]
        LDR     a3, [a3, #MMU_PPLTrans]

        ORR     lr, v4, v5                      ; OR together, physaddr, logaddr
        ORR     lr, lr, v7                      ; and size.
1671
        MOVS    ip, lr, LSL #12                 ; If all bottom 20 bits 0
1672 1673 1674
        BEQ     %FT50                           ; it's section mapped

        MOV     a1, #0                          ; We don't want the address in the result
1675

Kevin Bracey's avatar
Kevin Bracey committed
1676
        MOVS    ip, lr, LSL #16                 ; If bottom 16 bits not all 0
1677 1678
        ADR     lr, %FT10
        BNE     Get4KPTE                        ; then small pages (4K)
Kevin Bracey's avatar
Kevin Bracey committed
1679

1680
        BL      Get64KPTE                       ; else large pages (64K)
Kevin Bracey's avatar
Kevin Bracey committed
1681
10
1682
        MOV     v6, a1                          ; v6 = access permissions
1683 1684 1685 1686 1687 1688 1689 1690 1691

20      MOV     a1, v4
        MOV     a2, v5
        MOV     a3, v6
        BL      Init_MapInPage                  ; Loop through mapping in each
        ADD     v4, v4, #4096                   ; page in turn
        ADD     v5, v5, #4096
        SUBS    v7, v7, #4096
        BNE     %BT20
1692
        EXIT
1693

1694 1695
50
        BL      Get1MPTE
1696 1697
        MOVS    ip, v3                          ; is MMU on?
        LDREQ   ip, =L1PT                       ; then use virtual address
1698
        ADD     a2, ip, v5, LSR #18             ; a2 -> L1PT entry
1699 1700
70      STR     a1, [a2], #4                    ; And store in L1PT
        ADD     a1, a1, #1024*1024              ; Advance one megabyte
1701
        SUBS    v7, v7, #1024*1024              ; and loop
1702
        BNE     %BT70
1703
        EXIT
1704 1705 1706 1707 1708 1709

; Map a logical page to a physical page, allocating L2PT as necessary.
;
; On entry:
;    a1 = physical address
;    a2 = logical address
Kevin Bracey's avatar
Kevin Bracey committed
1710
;    a3 = access permissions + C + B bits + size (all non-address bits, of appropriate type)
1711 1712 1713 1714 1715 1716 1717
;    v1 -> current entry in PhysRamTable
;    v2 = last used physical address
;    v3 -> L1PT (or 0 if MMU on)
; On exit:
;    a1 = logical address
;    a2-a4, ip corrupt
;    v1, v2 updated
Kevin Bracey's avatar
Kevin Bracey committed
1718
;
1719

1720 1721
Init_MapInPage  ROUT
        Entry   "v4-v6"
1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736
        MOV     v4, a1                          ; v4 = physical address
        MOV     v5, a2                          ; v5 = logical address
        MOV     v6, a3                          ; v6 = access permissions
        MOV     a1, v5
        MOV     a2, #4096
        BL      AllocateL2PT
        TEQ     v3, #0                          ; if MMU on, access L2PT virtually...
        LDREQ   a1, =L2PT                       ; a1 -> L2PT virtual address
        MOVEQ   ip, v5                          ; index using whole address
        BEQ     %FT40
        MOV     ip, v5, LSR #20
        LDR     a1, [v3, ip, LSL #2]            ; a1 = level one descriptor
        MOV     a1, a1, LSR #10
        MOV     a1, a1, LSL #10                 ; a1 -> L2PT tables for this section
        AND     ip, v5, #&000FF000              ; extract L2 table index bits
Kevin Bracey's avatar
Kevin Bracey committed
1737 1738
40      AND     lr, v6, #3
        TEQ     lr, #L2_LargePage               ; strip out surplus address bits from
1739 1740
        BICEQ   v4, v4, #&0000F000              ; large page descriptors
        ORR     lr, v4, v6                      ; lr = value for L2PT entry
1741 1742
        STR     lr, [a1, ip, LSR #10]           ; update L2PT entry
        MOV     a1, v5
1743
        EXIT
1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755



; On entry:
;    a1 = virtual address L2PT required for
;    a2 = number of bytes of virtual space
;    v1 -> current entry in PhysRamTable
;    v2 = last used physical address
;    v3 -> L1PT (or 0 if MMU on)
; On exit
;    a1-a4,ip corrupt
;    v1, v2 updated
1756 1757
AllocateL2PT ROUT
        Entry   "v4-v8"
1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 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
        MOV     v8, a1, LSR #20                 ; round base address down to 1M
        ADD     lr, a1, a2
        MOV     v7, lr, LSR #20
        TEQ     lr, v7, LSL #20
        ADDNE   v7, v7, #1                      ; round end address up to 1M

        MOVS    v6, v3
        LDREQ   v6, =L1PT                       ; v6->L1PT (whole routine)

05      LDR     v5, [v6, v8, LSL #2]            ; L1PT contains 1 word per M
        TEQ     v5, #0                          ; if non-zero, the L2PT has
                                                ; already been allocated
        BNE     %FT40

        BIC     lr, v8, #3                      ; round down to 4M - each page
        ADD     lr, v6, lr, LSL #2              ; of L2PT maps to 4 sections
        LDMIA   lr, {a3,a4,v5,ip}               ; check if any are page mapped
        ASSERT  L1_Fault = 2_00 :LAND: L1_Page = 2_01 :LAND: L1_Section = 2_10
        TST     a3, #1
        TSTEQ   a4, #1
        TSTEQ   v5, #1
        TSTEQ   ip, #1
        BEQ     %FT20                           ; nothing page mapped - claim a page

        TST     a4, #1                          ; at least one of the sections is page mapped
        SUBNE   a3, a4, #1*1024                 ; find out where it's pointing to and
        TST     v5, #1                          ; derive the corresponding address for our
        SUBNE   a3, v5, #2*1024                 ; section
        TST     ip, #1
        SUBNE   a3, ip, #3*1024

        AND     lr, v8, #3
        ORR     a3, a3, lr, LSL #10
        STR     a3, [v6, v8, LSL #2]            ; fill in the L1PT entry
        B       %FT40                           ; no more to do

20      BL      Init_ClaimPhysicalPage          ; Claim a page to put L2PT in
        MOV     v4, a1

1797
      [ MEMM_Type = "VMSAv6"
1798
        ORR     a3, a1, #L1_Page
1799 1800 1801
      |
        ORR     a3, a1, #L1_Page + L1_U         ; Set the U bit for ARM6 (assume L2 pages will generally be cacheable)
      ]
1802
        AND     lr, v8, #3
1803 1804
        ORR     a3, a3, lr, LSL #10
        STR     a3, [v6, v8, LSL #2]            ; fill in the L1PT
1805

1806 1807 1808 1809 1810 1811 1812 1813 1814
; Need to zero the L2PT. Must do it before calling in MapInPage, as that may well
; want to put something in the thing we are clearing. If the MMU is off, no problem,
; but if the MMU is on, then the L2PT isn't accessible until we've called MapInPage.
; Solution is to use the AccessPhysicalAddress call.

        TEQ     v3, #0                          ; MMU on?
        MOVNE   a1, v4                          ; if not, just access v4
        MOVEQ   a1, #L1_B                       ; if so, map in v4
        MOVEQ   a2, v4
1815
        SUBEQ   sp, sp, #4
1816 1817
        MOVEQ   a3, #0
        MOVEQ   a4, sp
1818 1819 1820 1821 1822
        BLEQ    RISCOS_AccessPhysicalAddress

        MOV     a2, #0
        MOV     a3, #4*1024
        BL      memset
1823

1824 1825 1826 1827
        TEQ     v3, #0
        LDREQ   a1, [sp], #4
        BLEQ    RISCOS_ReleasePhysicalAddress

1828 1829 1830 1831
        ; Get the correct page table entry flags for Init_MapInPage
        TEQ     v3, #0
        LDREQ   a3, =ZeroPage
        ADDNE   a3, v3, #DRAMOffset_PageZero-DRAMOffset_L1PT
1832
        LDR     a2, [a3, #PageTable_PageFlags]
1833 1834 1835 1836 1837 1838
        LDR     a4, [a3, #MMU_PCBTrans]
        LDR     a3, [a3, #MMU_PPLTrans]
        MOV     a1, #0
        BL      Get4KPTE

        MOV     a3, a1
1839
        MOV     a1, v4                          ; Map in the L2PT page itself
1840 1841
        LDR     a2, =L2PT                       ; (can't recurse, because L2PT
        ADD     a2, a2, v8, LSL #10             ; backing for L2PT is preallocated)
1842 1843 1844
        BIC     a2, a2, #&C00
        BL      Init_MapInPage

1845

1846 1847 1848 1849
40      ADD     v8, v8, #1                      ; go back until all
        CMP     v8, v7                          ; pages allocated
        BLO     %BT05

1850
        EXIT
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
        ; in:  ip = ZeroPage
        ; out: v3 = PhysIllegalMask
DeterminePhysIllegalMask
        Push    "lr"
        MOV     v3, #&FFFFFFFF         ; By default any upper bits are illegal
        ARM_read_ID lr
        AND     lr, lr, #&F :SHL: 16
        CMP     lr, #ARMvF :SHL: 16    ; Check that feature registers are implemented
        BNE     %FT01                  ; Some ARMv5 chips supported supersections, but let's not worry about them
        MRC     p15, 0, lr, c0, c1, 7  ; ID_MMFR3
        TST     lr, #&F :SHL: 28
        MOVEQ   v3, #&FFFFFF00
01      STR     v3, [ip, #PhysIllegalMask]
        Pull    "pc"

        MACRO
$lab    ConstructIOPTE $pte, $phys_mb, $flags, $tmp
        ; $pte (output)                L1 page table entry word
        ; $phys_mb (input, preserved)  physical address, in megabytes
        ;   for vanilla sections:
        ;     bits 0..11 go in bits 20..31
        ;   for supersections:
        ;     bits 0..3 assumed zero
        ;     bits 4..11 go in bits 24..31
        ;     bits 12..15 go in bits 20..23
        ;     bits 16..20 go in bits 5..8
        ; $flags (input, preserved)    page table attribute bits
        ;
        ; UBFXNE should be safe pre v6T2, since we won't attempt to use
        ; supersections on such CPUs and they won't trap untaken undefined instructions
        ASSERT  $pte <> $phys_mb
        ASSERT  $pte <> $flags
        ASSERT  $pte <> $tmp
        ASSERT  $tmp <> $phys_mb
        ASSERT  $tmp <> $flags
$lab    ANDS    $tmp, $flags, #L1_SS
        UBFXNE  $tmp, $phys_mb, #32-20, #L1_SSb32Width
        ORR     $pte, $phys_mb, $tmp
        UBFXNE  $tmp, $phys_mb, #36-20, #L1_SSb36Width
        ASSERT  L1_SSb32Shift = 20
        ORR     $pte, $flags, $pte, LSL #L1_SSb32Shift
        ORRNE   $pte, $pte, $tmp, LSL #L1_SSb36Shift
        MEND


1898
; void *RISCOS_AccessPhysicalAddress(unsigned int flags, uint64_t addr, void **oldp)
1899
RISCOS_AccessPhysicalAddress ROUT
1900 1901 1902 1903 1904 1905
        ; Only flag user can ask for is bufferable
        ; Convert to appropriate DA flags
        ; (n.b. since this is an internal routine we should really change it to pass in DA flags directly)
        TST     a1, #L1_B
        LDR     a1, =OSAP_None + DynAreaFlags_NotCacheable ; SVC RW, USR none
        ORREQ   a1, a1, #DynAreaFlags_NotBufferable
1906
RISCOS_AccessPhysicalAddressUnchecked                   ; well OK then, I trust you know what you're doing
1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926
        ; Check physical address is valid on current CPU
        LDR     ip, =ZeroPage
        Push    "a1,v3,lr"
        LDR     v3, [ip, #PhysIllegalMask]
        TEQ     v3, #0
        BLEQ    DeterminePhysIllegalMask
        TST     a3, v3
        BNE     %FT90
        ; Use Get1MPTE to convert DA flags into L1PT section-mapping flags
        MOV     ip, #0
        GetPTE  a1, 1M, ip, a1
        ; Mapping size (section or supersection) depends on address
        MOV     lr, a2, LSR #20
        ORR     lr, lr, a3, LSL #12                     ; lr = physical megabyte number
        TEQ     a3, #0
        ORRNE   a1, a1, #L1_SS                          ; need to use supersection for such addresses
        BIC     a2, a2, #&FF000000                      ; at most, bits 0-23 are used as offsets into section/supersection
        BICNE   lr, lr, #&F                             ; if address >4GB, round mapped address to 16MB (supersection)
        BICEQ   a2, a2, #&00F00000                      ; else no further rounding needed (section) and bits 20-23 are not used as an offset either
        ConstructIOPTE v3, lr, a1, ip
1927
        LDR     ip, =L1PT + (PhysicalAccess:SHR:18)     ; ip -> L1PT entry
1928
 [ MEMM_Type = "VMSAv6"
1929
        ORR     v3, v3, #L1_XN                          ; force non-executable to prevent speculative instruction fetches
Kevin Bracey's avatar
Kevin Bracey committed
1930
 ]
1931 1932 1933 1934 1935 1936 1937 1938 1939 1940
        TEQ     a4, #0
        LDRNE   lr, [ip]                                ; read old value (if necessary)
        STRNE   lr, [a4]                                ; put old one in [oldp]
        MOV     a4, #15
        STR     v3, [ip], #4                            ; store first of 16 new L1PT entries
        TST     v3, #L1_SS
        MOVEQ   v3, #0                                  ; if supersection mapped then use 16 duplicate entries, else remaining entries unmapped
10      SUBS    a4, a4, #1
        STR     v3, [ip], #4
        BNE     %BT10
1941

1942
        LDR     a1, =PhysicalAccess
1943 1944
        ORR     a1, a1, a2
        STR     a1, [sp]
Jeffrey Lee's avatar
Jeffrey Lee committed
1945
        ARMop   MMU_ChangingUncached                    ; sufficient, cause not cacheable
1946 1947 1948 1949 1950 1951
        Pull    "a1,v3,pc"

90      ; Invalid physical address
        ADD     sp, sp, #1*4
        MOV     a1, #0
        Pull    "v3,pc"
1952 1953 1954 1955

; void RISCOS_ReleasePhysicalAddress(void *old)
RISCOS_ReleasePhysicalAddress
        LDR     ip, =L1PT + (PhysicalAccess:SHR:18)     ; ip -> L1PT entry
1956 1957 1958 1959 1960 1961 1962
        MOV     a4, #15
        STR     a1, [ip], #4                            ; restore first of 16 L1PT entries
        TST     a1, #L1_SS
        MOVEQ   a1, #0                                  ; if supersection mapped then use 16 duplicate entries, else remaining entries unmapped
10      SUBS    a4, a4, #1
        STR     a1, [ip], #4
        BNE     %BT10
Jeffrey Lee's avatar
Jeffrey Lee committed
1963
        ARMop   MMU_ChangingUncached,,tailcall          ; sufficient, cause not cacheable
1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977


; void Init_PageTablesChanged(void)
;
; A TLB+cache invalidation that works on all known ARMs. Invalidate all I+D TLB is the _only_ TLB
; op that works on ARM720T, ARM920T and SA110. Ditto invalidate all I+D cache.
;
; DOES NOT CLEAN THE DATA CACHE. This is a helpful simplification, but requires that don't use
; this routine after we've started using normal RAM.
;
Init_PageTablesChanged
        MOV     a3, lr
        BL      Init_ARMarch
        MOV     ip, #0
Ben Avison's avatar
Ben Avison committed
1978
        BNE     %FT01
1979
        MCREQ   ARM_config_cp,0,ip,ARMv3_TLBflush_reg,C0
Ben Avison's avatar
Ben Avison committed
1980 1981 1982
        B       %FT02
01      MCRNE   ARM_config_cp,0,ip,ARMv4_TLB_reg,C7
02
1983
 [ MEMM_Type = "VMSAv6"
1984
        CMP     a1, #ARMvF
Ben Avison's avatar
Ben Avison committed
1985 1986
        ADREQ   lr, %FT01
        BEQ     HAL_InvalidateCache_ARMvF
1987
        MCRNE   ARM_config_cp,0,ip,ARMv4_cache_reg,C7           ; works on ARMv3
Ben Avison's avatar
Ben Avison committed
1988
01
1989 1990 1991
 |
        MCR     ARM_config_cp,0,ip,ARMv4_cache_reg,C7           ; works on ARMv3
 ]
1992 1993 1994 1995 1996 1997 1998
        MOV     pc, a3




;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
1999
;       ClearWkspRAM - Routine to clear "all" workspace
2000
;
2001
; We have to avoid anything between InitUsedStart and InitUsedEnd - i.e.
2002 2003 2004 2005 2006
; the page tables, HAL workspace, etc.
;
; Note that zero page workspace isn't included in InitUsedStart/InitUsedEnd.
; Sensitive areas of it (e.g. PhysRamTable, IRQ vector) are skipped via the
; help of RamSkipTable
2007 2008
;
; The bulk of RAM is cleared during the keyboard scan (ClearFreePoolSection).
2009 2010

;
2011
; out:  r4-r11, r13 preserved
2012 2013
;

2014
ClearWkspRAM ROUT
2015
        MSR     CPSR_c, #F32_bit+FIQ32_mode             ; get some extra registers
2016 2017 2018 2019 2020 2021 2022
        MOV     r8, #0
        MOV     r9, #0
        MOV     r10, #0
        MOV     r11, #0
        MOV     r12, #0
        MOV     r13, #0
        MOV     r14, #0
2023
        MSR     CPSR_c, #F32_bit+SVC32_mode
2024

2025
        LDR     r0,=ZeroPage+InitClearRamWs             ;we can preserve r4-r11,lr in one of the skipped regions
2026
        STMIA   r0,{r4-r11,lr}
2027

2028
        DebugTX "ClearWkspRAM"
2029

2030 2031 2032 2033 2034
        ; Start off by clearing zero page + scratch space, as these:
        ; (a) are already mapped in and
        ; (b) may require the use of the skip table
        LDR     r0, =ZeroPage
        ADD     r1, r0, #16*1024
2035
        ADR     r6, RamSkipTable
2036 2037
        MSR     CPSR_c, #F32_bit+FIQ32_mode             ; switch to our bank o'zeros
        LDR     r5, [r6], #4                            ; load first skip addr
2038
10
2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056
        TEQ     r0, r1
        TEQNE   r0, r5
        STMNEIA r0!, {r8-r11}
        BNE     %BT10
        TEQ     r0, r1
        BEQ     %FT20
        LDR     r5, [r6], #4                            ; load skip amount
        ADD     r0, r0, r5                              ; and skip it
        LDR     r5, [r6], #4                            ; load next skip addr
        B       %BT10
20
        LDR     r0, =ScratchSpace
        ADD     r1, r0, #ScratchSpaceSize
30
        TEQ     r0, r1
        STMNEIA r0!, {r8-r11}
        STMNEIA r0!, {r8-r11}
        BNE     %BT30
2057

2058
        MSR     CPSR_c, #F32_bit+SVC32_mode
2059

Jeffrey Lee's avatar
Jeffrey Lee committed
2060
        LDR     r0, =ZeroPage+InitClearRamWs
2061
        LDMIA   r0, {r4-r11,r14}                        ;restore
2062

2063
      [ {FALSE} ; NewReset sets this later
Jeffrey Lee's avatar
Jeffrey Lee committed
2064
        LDR     r0, =ZeroPage+OsbyteVars + :INDEX: LastBREAK
2065 2066
        MOV     r1, #&80
        STRB    r1, [r0]                                ; flag the fact that RAM cleared
2067
      ]
2068

2069
        MSR     CPSR_c, #F32_bit + UND32_mode           ; retrieve the MMU control register
Jeffrey Lee's avatar
Jeffrey Lee committed
2070
        LDR     r0, =ZeroPage                           ; soft copy
2071
        STR     sp, [r0, #MMUControlSoftCopy]
2072 2073 2074 2075 2076 2077 2078
        MSR     CPSR_c, #F32_bit + SVC32_mode

        MOV     pc, lr

        LTORG

        MACRO
2079
        MakeSkipTable $addr, $size
2080 2081 2082
        ASSERT  ($addr :AND: 15) = 0
        ASSERT  ($size :AND: 15) = 0
        ASSERT  ($addr-ZeroPage) < 16*1024
2083
        &       $addr, $size
2084 2085 2086 2087 2088 2089 2090 2091
        MEND

        MACRO
        EndSkipTables
        &       -1
        MEND

RamSkipTable
2092 2093
        MakeSkipTable   ZeroPage, InitWsEnd
        MakeSkipTable   ZeroPage+SkippedTables, SkippedTablesEnd-SkippedTables
2094 2095
        EndSkipTables

2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       ClearFreePoolSection - Routine to clear a section of the free pool
;
; During keyboard scanning we soak up slack time clearing the bulk of RAM
; by picking a section of the free pool, mapping it in, clearing & flushing.

;
; In:   r0 = CAM entry to continue from
; Out:  r0 = updated
;

ClearFreePoolSection ROUT
        Push    "r1-r3, lr"
        LDR     r1, =ZeroPage
        LDR     r1, [r1, #MaxCamEntry]
        LDR     r2, =ZeroPage+FreePoolDANode
        CMP     r0, r1
        BHI     %FT30

        LDR     r3, =CAM
        ADD     r1, r3, r1, LSL #CAM_EntrySizeLog2      ; top entry (inc)
        ADD     r3, r3, r0, LSL #CAM_EntrySizeLog2      ; starting entry
10
        LDR     r14, [r3, #CAM_PageFlags]
        TST     r14, #DynAreaFlags_PMP
        BEQ     %FT20

        LDR     r14, [r3, #CAM_PMP]
        TEQ     r14, r2
        BEQ     %FT40
20
        ADD     r3, r3, #CAM_EntrySize                  ; next
        CMP     r3, r1
        BLS     %BT10
30
        MOV     r0, #-1
        Pull    "r1-r3, pc"
40
        Push    "r0-r12"

        ; This is a PMP entry in the free pool
        LDR     r14, [r3, #CAM_PMPIndex]                ; list index
        LDR     r9, [r2, #DANode_PMP]                   ; PMP list base
        LDR     r3, [r9, r14, LSL #2]                   ; ppn
        BL      ppn_to_physical                         ; => r5 = PA

      [ MEMM_Type = "ARM600"
        ; Map in this section, cacheable + bufferable to ensure burst writes
        ; are performed (StrongARM will only perform burst writes to CB areas)
        MOV     a1, #OSAP_None
      |
        ; Map in this section with default NCB cache policy. Making it cacheable
        ; is liable to slow things down significantly on some platforms (e.g.
        ; PL310 L2 cache)
        LDR     a1, =OSAP_None + DynAreaFlags_NotCacheable
      ]
        MOV     a2, r5
        MOV     a3, #0
2155
        MOV     a4, #0
2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224
        BL      RISCOS_AccessPhysicalAddressUnchecked

        MOV     r4, #0                                  ; clear to this value
        MOV     r6, r4
        MOV     r7, r4
        MOV     r8, r4
        MOV     r12, r4
45
        MOV     r9, r4
        MOV     r10, r4
        MOV     r11, r4

        ; Fill that page
        ADD     r2, r0, #4096
50
        STMIA   r0!, {r4,r6-r12}
        STMIA   r0!, {r4,r6-r12}
        TEQ     r0, r2
        BNE     %BT50

        ; Step the CAM until there are no more pages in that section
        LDR     r1, [sp, #1*4]
        LDR     r2, [sp, #2*4]
        LDR     r11, [sp, #3*4]
        B       %FT65
60
        LDR     r14, [r11, #CAM_PageFlags]
        TST     r14, #DynAreaFlags_PMP
        BEQ     %FT65

        LDR     r14, [r11, #CAM_PMP]
        TEQ     r14, r2
        BEQ     %FT70
65
        ADD     r11, r11, #CAM_EntrySize                ; next
        CMP     r11, r1
        BLS     %BT60

        MOV     r14, #-1                                ; CAM top, no more
        B       %FT80
70
        MOV     r10, r5                                 ; previous PA

        ; Next PMP entry in the free pool
        LDR     r14, [r11, #CAM_PMPIndex]               ; list index
        LDR     r9, [r2, #DANode_PMP]                   ; PMP list base
        LDR     r3, [r9, r14, LSL #2]                   ; ppn
        BL      ppn_to_physical                         ; => r5 = PA

        MOV     r14, r10, LSR #20
        TEQ     r14, r5, LSR #20                        ; same MB as previous?
        LDRNE   r14, =CAM
        SUBNE   r14, r11, r14
        MOVNE   r14, r14, LSR #CAM_EntrySizeLog2        ; no, so compute continuation point
        LDREQ   r0, =PhysicalAccess
        MOVEQ   r14, r5, LSL #12
        ORREQ   r0, r0, r14, LSR #12
        STREQ   r11, [sp, #3*4]
        BEQ     %BT45                                   ; yes, so clear it
80
        STR     r14, [sp, #0*4]                         ; return value for continuation

 [ MEMM_Type = "ARM600" ; VMSAv6 maps as non-cacheable, so no flush required
        ; Make page uncacheable so the following is safe
        MOV     r4, r0

        MOV     r0, #L1_B
        MOV     r1, r10
        MOV     r2, #0
2225
        MOV     r3, #0
2226 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
        BL      RISCOS_AccessPhysicalAddress

        MOV     r0, r4

        ; Clean & invalidate the cache before the 1MB window closes
      [ CacheCleanerHack
        ; StrongARM requires special clean code, because we haven't mapped in
        ; DCacheCleanAddress yet. Cheat and only perform a clean, not full
        ; clean + invalidate (should be safe as we've only been writing)
        ARM_read_ID r2
        AND     r2, r2, #&F000
        CMP     r2, #&A000
        BNE     %FT90
85
        SUB     r0, r0, #32                             ; rewind 1 cache line
        ARMA_clean_DCentry r0
        MOVS    r1, r0, LSL #12                         ; start of the MB?
        BNE     %BT85
        B       %FT91
90
      ]
        ARMop Cache_CleanInvalidateAll
 ]
91
        MOV     a1, #L1_Fault
        BL      RISCOS_ReleasePhysicalAddress           ; reset to default

        Pull    "r0-r12"

        Pull    "r1-r3, pc"
2256 2257 2258 2259 2260 2261 2262 2263

InitProcVecs
        BKPT    &C000                                   ; Reset
        BKPT    &C004                                   ; Undefined Instruction
        BKPT    &C008                                   ; SWI
        BKPT    &C00C                                   ; Prefetch Abort
        SUBS    pc, lr, #4                              ; ignore data aborts
        BKPT    &C014                                   ; Address Exception
Kevin Bracey's avatar
Kevin Bracey committed
2264
        LDR     pc, InitProcVecs + InitIRQHandler       ; IRQ
2265 2266 2267 2268 2269
        BKPT    &C01C                                   ; FIQ
InitProcVec_FIQ
        DCD     0
InitProcVecsEnd

2270
;
2271 2272 2273
; In:  a1 = flags  (L1_B,L1_C,L1_TEX)
;           bit 20 set if doubly mapped
;           bit 21 set if L1_AP specified (else default to AP_None)
2274 2275 2276 2277
;      a2 = physical address
;      a3 = size
; Out: a1 = assigned logical address, or 0 if failed (no room)
;
2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291
RISCOS_MapInIO ROUT
        MOV     a4, a3
        MOV     a3, #0
        ; drop through...
;
; In:  a1 = flags  (L1_B,L1_C,L1_TEX)
;           bit 20 set if doubly mapped
;           bit 21 set if L1_AP specified (else default to AP_None)
;      a2,a3 = physical address
;      a4 = size
; Out: a1 = assigned logical address, or 0 if failed (no room)
;
RISCOS_MapInIO64 ROUT

2292 2293 2294
; Will detect and return I/O space already mapped appropriately, or map and return new space
; For simplicity and speed of search, works on a section (1Mb) granularity
;
Kevin Bracey's avatar
Kevin Bracey committed
2295 2296

        ASSERT  L1_B = 1:SHL:2
2297
        ASSERT  L1_C = 1:SHL:3
2298 2299
 [ MEMM_Type = "VMSAv6"
        ASSERT  L1_AP = 2_100011 :SHL: 10
2300
        ASSERT  L1_TEX = 2_111 :SHL: 12
2301
 |
2302
        ASSERT  L1_AP = 3:SHL:10
2303
        ASSERT  L1_TEX = 2_1111 :SHL: 12
2304
 ]
2305 2306
MapInFlag_DoublyMapped * 1:SHL:20
MapInFlag_APSpecified * 1:SHL:21
Kevin Bracey's avatar
Kevin Bracey committed
2307

2308
        TST     a1, #MapInFlag_APSpecified
2309
        BICEQ   a1, a1, #L1_AP
2310
        ; For VMSAv6, assume HAL knows what it's doing and requests correct settings for AP_ROM
2311
        ORREQ   a1, a1, #L1_APMult * AP_None
2312 2313 2314 2315 2316 2317 2318
        BIC     a1, a1, #3
 [ MEMM_Type = "VMSAv6"
        ORR     a1, a1, #L1_Section+L1_XN               ; force non-executable to prevent speculative instruction fetches
 |
        ORR     a1, a1, #L1_Section
 ]
RISCOS_MapInIO_PTE ; a1 bits 0-19 = L1 section entry flags, bits 20+ = our extra flags
2319
        Entry   "a2,v1-v8"
2320
        LDR     ip, =ZeroPage
2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355
        SUB     a4, a4, #1                              ; reduce by 1 so end physical address is inclusive
        ADDS    v1, a2, a4
        ADC     v2, a3, #0                              ; v1,v2 = end physical address
        LDR     v3, [ip, #PhysIllegalMask]
        TEQ     v3, #0
        BLEQ    DeterminePhysIllegalMask
        TST     v2, v3
        MOVNE   a1, #0
        BNE     %FT90                                   ; can't map in physical addresses in this range

        MOVS    v3, v2
        MOVNE   v3, #&F                                 ; v3 = number of MB to use in rounding (0 for sections, 15 for supersections)
        MOV     v4, a2, LSR #20
        ORR     v4, v4, a3, LSL #12
        BIC     v4, v4, v3                              ; v4 = physical start MB to map
        MOV     v5, v1, LSR #20
        ORR     v5, v5, v2, LSL #12
        ADD     v5, v5, #1                              ; make exclusive
        ADD     v5, v5, v3
        BIC     v5, v5, v3                              ; v5 = physical end MB to map
        ANDS    a2, a1, #MapInFlag_DoublyMapped
        SUBNE   a2, v5, v4                              ; a2 = offset of second mapping (in MB) or 0
        LDR     v6, =&FFFFF
        AND     a1, a1, v6                              ; mask out our extra flags
        CMP     v5, #&1000
        ORRHI   a1, a1, #L1_SS                          ; set supersection flag if necessary
        LDR     a3, [ip, #IOAllocPtr]
        MOV     a3, a3, LSR #20
        ADD     a3, a3, v3
        BIC     a3, a3, v3                              ; a3 = logical MB that we're checking for a match
        ConstructIOPTE a4, v4, a1, lr                   ; a4 = first PT entry to match
        ADD     v3, v3, #1                              ; v3 = number of MB to step between sections or supersections
        LDR     v1, =L1PT
        LDR     v2, =IO :SHR: 20                        ; v2 = last logical MB to check (exclusive)
        SUB     a3, a3, v3                              ; no increment on first iteration
2356
10
2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370
        ADD     a3, a3, v3                              ; next logical MB to check
        ADD     ip, a3, a2                              ; logical MB of base mapping or second mapping if there is one
        CMP     ip, v2
        BHS     %FT50                                   ; run out of logical addresses to check
        LDR     lr, [v1, a3, LSL #2]                    ; check only or first entry
        TEQ     lr, a4
        LDREQ   lr, [v1, ip, LSL #2]                    ; check only or second entry
        TEQEQ   lr, a4
        BNE     %BT10

        ; Found start of requested IO already mapped, and with required flags
        ; Now check that the remaining secions are all there too
        MOV     v6, v4                                  ; v6 = expected physical MB
        MOV     v7, a3                                  ; v7 = logical MB we expect to find it at
2371
20
2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388
        ADD     v6, v6, v3                              ; next physical MB
        ADD     v7, v7, v3                              ; next logical MB
        ADD     ip, v7, a2                              ; logical MB of base mapping or second mapping if there is one
        CMP     v6, v5
        MOVHS   a4, a3, LSL #20
        BHS     %FT80                                   ; reached end and everything matched
        CMP     ip, v2
        BHS     %FT50                                   ; run out of logical addresses to check
        ConstructIOPTE v8, v6, a1, lr
        LDR     lr, [v1, v7, LSL #2]                    ; check only or first entry
        TEQ     lr, v8
        LDREQ   lr, [v1, ip, LSL #2]                    ; check only or second entry
        TEQEQ   lr, v8
        BEQ     %BT20                                   ; good so far, try next entry
        B       %BT10                                   ; mismatch, continue outer loop

50      ; Request not currently mapped, only partially mapped, or mapped with wrong flags
Jeffrey Lee's avatar
Jeffrey Lee committed
2389
        LDR     ip, =ZeroPage
2390
        SUB     v8, v3, #1                              ; v8 = number of MB to use in rounding (0 for sections, 15 for supersections)
2391 2392 2393 2394 2395 2396 2397 2398 2399 2400
        LDR     a3, [ip, #IOAllocPtr]
        MOV     a3, a3, LSR #20
        BIC     a3, a3, v8                              ; round down to 1MB or 16MB boundary (some memory may remain unmapped above when we map in a supersection)
        SUB     a4, v5, v4
        ADD     a4, a4, a2                              ; a4 = number of MB required
        SUB     a3, a3, a4
        MOV     a4, a3, LSL #20
        LDR     v6, [ip, #IOAllocLimit]
        CMP     a4, v6                                  ; run out of room to allocate IO?
        MOVLS   a1, #0                                  ; LS is to match previous version of the code - perhaps should be LO?
2401
        BLS     %FT90
2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416
        STR     a4, [ip, #IOAllocPtr]
60
        ConstructIOPTE v8, v4, a1, lr                   ; v8 = page table entry for this (super)section
        MOV     v7, v3                                  ; number of consecutive entries to program the same
70
        ADD     v6, a3, a2
        STR     v8, [v1, a3, LSL #2]                    ; write only or first entry
        ADD     a3, a3, #1
        STR     v8, [v1, v6, LSL #2]                    ; write only or second entry
        SUBS    v7, v7, #1
        BNE     %BT70
        ADD     v4, v4, v3
        CMP     v4, v5
        BLO     %BT60

2417 2418 2419
        MOV     a2, a1
        PageTableSync                                   ; corrupts a1
        MOV     a1, a2
2420 2421 2422 2423 2424 2425
80
        LDR     a2, [sp]                                ; retrieve original physical address from stack
        BIC     a2, a2, #&FF000000                      ; distance from 16MB boundary for supersections
        TST     a1, #L1_SS
        BICEQ   a2, a2, #&00F00000                      ; distance from 1MB boundary for sections
        ADD     a1, a4, a2
2426 2427
90
        EXIT
2428 2429


Ben Avison's avatar
Ben Avison committed
2430 2431 2432 2433 2434
; void RISCOS_AddDevice(unsigned int flags, struct device *d)
RISCOS_AddDevice
        ADDS    a1, a2, #0      ; also clears V
        B       HardwareDeviceAdd_Common

2435
; uint64_t RISCOS_LogToPhys(const void *log)
2436
RISCOS_LogToPhys ROUT
2437 2438 2439 2440
        Push    "r4,r5,r8,r9,lr"
        MOV     r4, a1
        LDR     r8, =L2PT
        BL      logical_to_physical
2441
        MOVCC   a2, #0 ; assume L2 page tables only used for bottom 4GB for now
2442
        MOVCC   a1, r5
2443 2444 2445 2446 2447 2448 2449 2450 2451 2452
        BCC     %FT10
        ; Try checking L1PT for any section mappings (logical_to_physical only
        ; deals with regular 4K page mappings)
        ; TODO - Add large page support
        LDR     r9, =L1PT
        MOV     r5, r4, LSR #20
        LDR     a1, [r9, r5, LSL #2]
        ASSERT  L1_Section = 2
        EOR     a1, a1, #2
        TST     a1, #3
2453
        MOVNE   a2, #-1
2454 2455
        MOVNE   a1, #-1
        BNE     %FT10
2456 2457 2458 2459
        ; Check if it's a supersection
        TST     a1, #L1_SS
        BNE     %FT20
        MOV     a2, #0 ; vanilla sections only map bottom 4GB of physical space
2460 2461 2462 2463 2464 2465 2466 2467 2468
        ; Apply offset from bits 0-19 of logical addr
      [ NoARMT2
        MOV     a1, a1, LSR #20
        ORR     a1, a1, r4, LSL #12
        MOV     a1, a1, ROR #12
      |
        BFI     a1, r4, #0, #20
      ]
10
2469 2470
        Pull    "r4,r5,r8,r9,pc"

2471 2472 2473 2474 2475 2476 2477
20      MOV     a3, a1, LSR #L1_SSb36Shift
        UBFX    a2, a1, #L1_SSb32Shift, #L1_SSb32Width
        BFI     a2, a3, #36-32, #L1_SSb36Width
        ; Apply offset from bits 0-23 of logical addr
        BFI     a1, r4, #0, #24
        Pull    "r4,r5,r8,r9,pc"

Robert Sprowson's avatar
Robert Sprowson committed
2478 2479
; int RISCOS_IICOpV(IICDesc *descs, uint32_t ndesc_and_bus)
RISCOS_IICOpV ROUT
2480 2481
        Push    "lr"
        BL      IIC_OpV
Robert Sprowson's avatar
Robert Sprowson committed
2482 2483 2484 2485 2486 2487 2488 2489 2490 2491
        MOVVC   a1, #IICStatus_Completed
        Pull    "pc", VC
        ; Map from RISC OS error numbers to abstract IICStatus return values
        LDR     a1, [a1]
        LDR     lr, =ErrorNumber_IIC_NoAcknowledge
        SUB     a1, a1, lr              ; 0/1/2 = NoAck/Error/Busy
        CMP     a1, #3
        MOVCS   a1, #3                  ; 3+ => unknown, either way it's an Error
        ADR     lr, %FT10
        LDRB    a1, [lr, a1]
2492
        Pull    "pc"
Robert Sprowson's avatar
Robert Sprowson committed
2493 2494 2495 2496 2497
10
        ASSERT    (ErrorNumber_IIC_Error - ErrorNumber_IIC_NoAcknowledge) = 1
        ASSERT    (ErrorNumber_IIC_Busy - ErrorNumber_IIC_NoAcknowledge) = 2
        DCB       IICStatus_NoACK, IICStatus_Error, IICStatus_Busy, IICStatus_Error
        ALIGN
Ben Avison's avatar
Ben Avison committed
2498

2499 2500 2501 2502 2503 2504 2505 2506
SetUpHALEntryTable ROUT
        LDR     a1, =ZeroPage
        LDR     a2, [a1, #HAL_Descriptor]
        LDR     a3, [a1, #HAL_Workspace]
        LDR     a4, [a2, #HALDesc_Entries]
        LDR     ip, [a2, #HALDesc_NumEntries]
        ADD     a4, a2, a4                              ; a4 -> entry table
        MOV     a2, a4                                  ; a2 -> entry table (increments)
2507 2508
10      SUBS    ip, ip, #1                              ; decrement counter
        LDRCS   a1, [a2], #4
2509
        BCC     %FT20
Kevin Bracey's avatar
Kevin Bracey committed
2510 2511 2512
        TEQ     a1, #0
        ADREQ   a1, NullHALEntry
        ADDNE   a1, a4, a1                              ; convert offset to absolute
2513
        STR     a1, [a3, #-4]!                          ; store backwards below HAL workspace
2514
        B       %BT10
2515 2516 2517 2518 2519 2520 2521 2522
20      LDR     a1, =ZeroPage                           ; pad table with NullHALEntries
        LDR     a4, =HALWorkspace                       ; in case where HAL didn't supply enough
        ADR     a1, NullHALEntry
30      CMP     a3, a4
        STRHI   a1, [a3, #-4]!
        BHI     %BT30
        MOV     pc, lr

2523

Kevin Bracey's avatar
Kevin Bracey committed
2524 2525 2526 2527 2528 2529
NullHALEntry
        MOV     pc, lr

; Can freely corrupt r10-r12 (v7,v8,ip).
HardwareSWI
        AND     ip, v5, #&FF
2530 2531 2532 2533 2534 2535 2536 2537

        CMP     ip, #OSHW_LookupRoutine
        ASSERT  OSHW_CallHAL < OSHW_LookupRoutine
        BLO     HardwareCallHAL
        BEQ     HardwareLookupRoutine

        CMP     ip, #OSHW_DeviceRemove
        ASSERT  OSHW_DeviceAdd < OSHW_DeviceRemove
Ben Avison's avatar
Ben Avison committed
2538 2539
        BLO     HardwareDeviceAdd
        BEQ     HardwareDeviceRemove
2540

Ben Avison's avatar
Ben Avison committed
2541 2542 2543
        CMP     ip, #OSHW_DeviceEnumerateChrono
        ASSERT  OSHW_DeviceEnumerate < OSHW_DeviceEnumerateChrono
        ASSERT  OSHW_DeviceEnumerateChrono < OSHW_MaxSubreason
Ben Avison's avatar
Ben Avison committed
2544
        BLO     HardwareDeviceEnumerate
Ben Avison's avatar
Ben Avison committed
2545 2546
        BEQ     HardwareDeviceEnumerateChrono
        BHI     HardwareBadReason
Kevin Bracey's avatar
Kevin Bracey committed
2547

2548
HardwareCallHAL
Kevin Bracey's avatar
Kevin Bracey committed
2549 2550
        Push    "v1-v4,sb,lr"
        ADD     v8, sb, #1                              ; v8 = entry no + 1
Jeffrey Lee's avatar
Jeffrey Lee committed
2551
        LDR     ip, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
2552 2553
        LDR     v7, [ip, #HAL_Descriptor]
        AddressHAL ip                                   ; sb set up
2554
        LDR     v7, [v7, #HALDesc_NumEntries]           ; v7 = number of entries
Kevin Bracey's avatar
Kevin Bracey committed
2555
        CMP     v8, v7                                  ; entryno + 1 must be <= number of entries
2556
        BHI     HardwareBadEntry2
Kevin Bracey's avatar
Kevin Bracey committed
2557 2558 2559
        LDR     ip, [sb, -v8, LSL #2]
        ADR     v7, NullHALEntry
        TEQ     ip, v7
2560
        BEQ     HardwareBadEntry2
2561
      [ NoARMv5
Kevin Bracey's avatar
Kevin Bracey committed
2562 2563
        MOV     lr, pc
        MOV     pc, ip
2564 2565 2566
      |
        BLX     ip
      ]
Kevin Bracey's avatar
Kevin Bracey committed
2567 2568 2569 2570
        ADD     sp, sp, #4*4
        Pull    "sb,lr"
        ExitSWIHandler

2571
HardwareLookupRoutine
Kevin Bracey's avatar
Kevin Bracey committed
2572
        ADD     v8, sb, #1                              ; v8 = entry no + 1
Jeffrey Lee's avatar
Jeffrey Lee committed
2573
        LDR     ip, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
2574 2575
        LDR     v7, [ip, #HAL_Descriptor]
        AddressHAL ip
2576
        LDR     v7, [v7, #HALDesc_NumEntries]
Kevin Bracey's avatar
Kevin Bracey committed
2577 2578 2579 2580 2581 2582 2583 2584 2585
        CMP     v8, v7                                  ; entryno + 1 must be <= number of entries
        BHI     HardwareBadEntry
        LDR     a1, [sb, -v8, LSL #2]
        ADR     v7, NullHALEntry
        TEQ     a1, v7
        BEQ     HardwareBadEntry
        MOV     a2, sb
        ExitSWIHandler

Ben Avison's avatar
Ben Avison committed
2586
HardwareDeviceAdd
2587
        Push    "r1-r3,lr"
Ben Avison's avatar
Ben Avison committed
2588
        BL      HardwareDeviceAdd_Common
2589
        Pull    "r1-r3,lr"
Ben Avison's avatar
Ben Avison committed
2590 2591 2592
        B       SLVK_TestV

HardwareDeviceRemove
2593
        Push    "r1-r3,lr"
Ben Avison's avatar
Ben Avison committed
2594
        BL      HardwareDeviceRemove_Common
2595
        Pull    "r1-r3,lr"
Ben Avison's avatar
Ben Avison committed
2596 2597 2598
        B       SLVK_TestV

HardwareDeviceAdd_Common
2599
        Entry
Ben Avison's avatar
Ben Avison committed
2600 2601
        BL      HardwareDeviceRemove_Common             ; first try to remove any device already at the same address
        EXIT    VS
Jeffrey Lee's avatar
Jeffrey Lee committed
2602
        LDR     lr, =ZeroPage
Ben Avison's avatar
Ben Avison committed
2603 2604 2605 2606
        LDR     r1, [lr, #DeviceCount]
        LDR     r2, [lr, #DeviceTable]
        TEQ     r2, #0
        BEQ     %FT80
2607 2608
        ADD     r1, r1, #1                              ; increment DeviceCount
        LDR     lr, [r2, #-4]                           ; word before heap block is length including length word
Ben Avison's avatar
Ben Avison committed
2609 2610
        TEQ     r1, lr, LSR #2                          ; block already full?
        BEQ     %FT81
Jeffrey Lee's avatar
Jeffrey Lee committed
2611
        LDR     lr, =ZeroPage
2612 2613 2614
10      STR     r1, [lr, #DeviceCount]
        ADD     lr, r2, r1, LSL #2
        SUB     lr, lr, #4
Ben Avison's avatar
Ben Avison committed
2615 2616 2617 2618 2619 2620
11      LDR     r1, [lr, #-4]!                          ; copy existing devices up, so new ones get enumerated first
        STR     r1, [lr, #4]
        CMP     lr, r2
        BHI     %BT11
        STR     r0, [r2]
        MOV     r2, r0
2621
        MOV     r1, #Service_Hardware
Ben Avison's avatar
Ben Avison committed
2622 2623 2624 2625 2626 2627
        MOV     r0, #0
        BL      Issue_Service
        ADDS    r0, r2, #0                              ; exit with V clear
        EXIT

80      ; Claim a system heap block for the device table
2628
        Push    "r0"
Ben Avison's avatar
Ben Avison committed
2629 2630
        MOV     r3, #16
        BL      ClaimSysHeapNode
2631
        ADDVS   sp, sp, #4
Ben Avison's avatar
Ben Avison committed
2632
        EXIT    VS
2633
        Pull    "r0"
Jeffrey Lee's avatar
Jeffrey Lee committed
2634
        LDR     lr, =ZeroPage
2635 2636
        MOV     r1, #1
        STR     r2, [lr, #DeviceTable]
Ben Avison's avatar
Ben Avison committed
2637 2638 2639
        B       %BT10

81      ; Extend the system heap block
2640
        Push    "r0"
Ben Avison's avatar
Ben Avison committed
2641 2642 2643
        MOV     r0, #HeapReason_ExtendBlock
        MOV     r3, #16
        BL      DoSysHeapOpWithExtension
2644
        ADDVS   sp, sp, #4
Ben Avison's avatar
Ben Avison committed
2645
        EXIT    VS
2646
        Pull    "r0"
Jeffrey Lee's avatar
Jeffrey Lee committed
2647
        LDR     lr, =ZeroPage
Ben Avison's avatar
Ben Avison committed
2648 2649
        LDR     r1, [lr, #DeviceCount]
        STR     r2, [lr, #DeviceTable]
2650
        ADD     r1, r1, #1
Ben Avison's avatar
Ben Avison committed
2651 2652
        B       %BT10

2653
HardwareDeviceRemove_Common ROUT
2654
        Entry   "r4"
Jeffrey Lee's avatar
Jeffrey Lee committed
2655
        LDR     lr, =ZeroPage
Ben Avison's avatar
Ben Avison committed
2656 2657 2658 2659
        LDR     r3, [lr, #DeviceCount]
        LDR     r4, [lr, #DeviceTable]
        TEQ     r3, #0
        EXIT    EQ                                      ; no devices registered
2660
10      LDR     r2, [r4], #4
2661 2662
        SUBS    r3, r3, #1
        TEQNE   r2, r0
2663
        BNE     %BT10
Ben Avison's avatar
Ben Avison committed
2664 2665 2666
        TEQ     r2, r0
        EXIT    NE                                      ; this device not registered
        MOV     r0, #1
2667
        MOV     r1, #Service_Hardware
Ben Avison's avatar
Ben Avison committed
2668 2669
        BL      Issue_Service
        CMP     r1, #0                                  ; if service call claimed
2670
        CMPEQ   r1, #1:SHL:31                           ; then set V (r0 already points to error block)
Ben Avison's avatar
Ben Avison committed
2671
        EXIT    VS                                      ; and exit
2672
        ; Search for device again - we may have been re-entered
Ben Avison's avatar
Ben Avison committed
2673
        MOV     r0, r2
2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684
        LDR     lr, =ZeroPage
        LDR     r3, [lr, #DeviceCount]
        LDR     r4, [lr, #DeviceTable]
        TEQ     r3, #0
        EXIT    EQ                                      ; no devices registered
20      LDR     r2, [r4], #4
        SUBS    r3, r3, #1
        TEQNE   r2, r0
        BNE     %BT20
        TEQ     r2, r0
        EXIT    NE                                      ; this device not registered
Ben Avison's avatar
Ben Avison committed
2685
        SUBS    r3, r3, #1
2686
30      LDRCS   r2, [r4], #4                            ; copy down remaining devices
2687 2688
        STRCS   r2, [r4, #-8]
        SUBCSS  r3, r3, #1
2689
        BCS     %BT30
Jeffrey Lee's avatar
Jeffrey Lee committed
2690
        LDR     lr, =ZeroPage
2691 2692 2693
        LDR     r3, [lr, #DeviceCount]
        SUB     r3, r3, #1
        STR     r3, [lr, #DeviceCount]
Ben Avison's avatar
Ben Avison committed
2694 2695 2696 2697
        EXIT

HardwareDeviceEnumerate
        Push    "r3-r4,lr"
Jeffrey Lee's avatar
Jeffrey Lee committed
2698
        LDR     lr, =ZeroPage
Ben Avison's avatar
Ben Avison committed
2699 2700 2701 2702 2703 2704 2705 2706
        LDR     r2, [lr, #DeviceCount]
        LDR     r3, [lr, #DeviceTable]
        SUBS    r4, r2, r1
        MOVLS   r1, #-1
        BLS     %FT90                                   ; if r1 is out of range then exit
        ADD     r3, r3, r1, LSL #2
10      ADD     r1, r1, #1
        LDR     r2, [r3], #4
2707 2708 2709
        LDR     lr, [r2, #HALDevice_Type]
        EOR     lr, lr, r0
        MOVS    lr, lr, LSL #16                         ; EQ if types match
Ben Avison's avatar
Ben Avison committed
2710 2711
        SUBNES  r4, r4, #1
        BNE     %BT10
2712
        TEQ     lr, #0
Ben Avison's avatar
Ben Avison committed
2713
        MOVNE   r1, #-1
2714 2715 2716 2717
        BNE     %FT90
        LDR     lr, [r2, #HALDevice_Version]
        MOV     lr, lr, LSR #16
        CMP     lr, r0, LSR #16                         ; newer than our client understands?
2718 2719
        BLS     %FT90
        SUBS    r4, r4, #1
2720
        BHI     %BT10
2721
        MOV     r1, #-1
Ben Avison's avatar
Ben Avison committed
2722 2723 2724 2725
90
        Pull    "r3-r4,lr"
        ExitSWIHandler

Ben Avison's avatar
Ben Avison committed
2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738
HardwareDeviceEnumerateChrono
        Push    "r3-r4,lr"
        LDR     lr, =ZeroPage
        LDR     r2, [lr, #DeviceCount]
        LDR     r3, [lr, #DeviceTable]
        SUBS    r4, r2, r1
        MOVLS   r1, #-1
        BLS     %FT90                                   ; if r1 is out of range then exit
        ADD     r3, r3, r4, LSL #2
10      ADD     r1, r1, #1
        LDR     r2, [r3, #-4]!
        LDR     lr, [r2, #HALDevice_Type]
        EOR     lr, lr, r0
2739
        MOVS    lr, lr, LSL #16                         ; EQ if types match
Ben Avison's avatar
Ben Avison committed
2740 2741
        SUBNES  r4, r4, #1
        BNE     %BT10
2742
        TEQ     lr, #0
Ben Avison's avatar
Ben Avison committed
2743
        MOVNE   r1, #-1
2744 2745 2746 2747
        BNE     %FT90
        LDR     lr, [r2, #HALDevice_Version]
        MOV     lr, lr, LSR #16
        CMP     lr, r0, LSR #16                         ; newer than our client understands?
2748 2749
        BLS     %FT90
        SUBS    r4, r4, #1
2750
        BHI     %BT10
2751
        MOV     r1, #-1
Ben Avison's avatar
Ben Avison committed
2752 2753 2754 2755
90
        Pull    "r3-r4,lr"
        ExitSWIHandler

Kevin Bracey's avatar
Kevin Bracey committed
2756 2757 2758 2759 2760 2761 2762 2763 2764
HardwareBadReason
        ADR     r0, ErrorBlock_HardwareBadReason
 [ International
        Push    "lr"
        BL      TranslateError
        Pull    "lr"
 ]
        B       SLVK_SetV

2765 2766 2767
HardwareBadEntry2
        ADD     sp, sp, #4*4
        Pull    "sb,lr"
Kevin Bracey's avatar
Kevin Bracey committed
2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779
HardwareBadEntry
        ADR     r0, ErrorBlock_HardwareBadEntry
 [ International
        Push    "lr"
        BL      TranslateError
        Pull    "lr"
 ]
        B       SLVK_SetV

        MakeErrorBlock HardwareBadReason
        MakeErrorBlock HardwareBadEntry

Kevin Bracey's avatar
Kevin Bracey committed
2780 2781 2782 2783 2784
 [ DebugTerminal
DebugTerminal_Rdch
        Push    "a2-a4,sb,ip"
        MOV     sb, ip
20
John Ballance's avatar
John Ballance committed
2785
        WritePSRc SVC_mode, r1
Kevin Bracey's avatar
Kevin Bracey committed
2786 2787 2788
        CallHAL HAL_DebugRX
        CMP     a1, #27
        BNE     %FT25
Jeffrey Lee's avatar
Jeffrey Lee committed
2789
        LDR     a2, =ZeroPage + OsbyteVars + :INDEX: RS423mode
Kevin Bracey's avatar
Kevin Bracey committed
2790 2791 2792
        LDRB    a2, [a2]
        TEQ     a2, #0                  ; is RS423 raw data,or keyb emulator?
        BNE     %FT25
Jeffrey Lee's avatar
Jeffrey Lee committed
2793
        LDR     a2, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
2794 2795 2796 2797 2798 2799 2800 2801 2802
        LDRB    a1, [a2, #ESC_Status]
        ORR     a1, a1, #&40
        STRB    a1, [a2, #ESC_Status]   ; mark escape flag
        MOV     a1, #27
        SEC                             ; tell caller to look carefully at R0
        Pull    "a2-a4,sb,ip,pc"
25
        CMP     a1, #-1
        Pull    "a2-a4,sb,ip,pc",NE     ; claim it
Jeffrey Lee's avatar
Jeffrey Lee committed
2803
        LDR     R0, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
2804 2805
        LDRB    R14, [R0, #CallBack_Flag]
        TST     R14, #CBack_VectorReq
John Ballance's avatar
John Ballance committed
2806
        BLNE    process_callbacks_disableIRQ
Kevin Bracey's avatar
Kevin Bracey committed
2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819
        B       %BT20


DebugTerminal_Wrch
        Push    "a1-a4,sb,ip,lr"
        MOV     sb, ip
        CallHAL HAL_DebugTX
        Pull    "a1-a4,sb,ip,pc"        ; don't claim it
 ]


Reset_IRQ_Handler
        SUB     lr, lr, #4
2820
        Push    "a1-a4,v1-v2,sb,ip,lr"
2821 2822 2823 2824 2825
        MRS     a1, SPSR
        MRS     a2, CPSR
        ORR     a3, a2, #SVC32_mode
        MSR     CPSR_c, a3
        Push    "a1-a2,lr"
2826 2827

        ; If it's not an IIC interrupt, mute it
Jeffrey Lee's avatar
Jeffrey Lee committed
2828
        LDR     v2, =ZeroPage
2829
        AddressHAL v2
Jeffrey Lee's avatar
Jeffrey Lee committed
2830
        CallHAL HAL_IRQSource
Jeffrey Lee's avatar
Jeffrey Lee committed
2831
        ADD     v1, v2, #IICBus_Base
Jeffrey Lee's avatar
Jeffrey Lee committed
2832
        MOV     ip, #0
2833 2834
10
        LDR     a2, [v1, #IICBus_Type]
Kevin Bracey's avatar
Kevin Bracey committed
2835
        TST     a2, #IICFlag_Background
Jeffrey Lee's avatar
Jeffrey Lee committed
2836 2837 2838 2839 2840 2841 2842
        BEQ     %FT20
        LDR     a2, [v1, #IICBus_Device]
        CMP     a2, a1
        ADREQ   lr, Reset_IRQ_Exit
        BEQ     IICIRQ
20
        ADD     ip, ip, #1
2843
        ADD     v1, v1, #IICBus_Size
Jeffrey Lee's avatar
Jeffrey Lee committed
2844
        CMP     ip, #IICBus_Count
2845
        BNE     %BT10
2846 2847 2848

        CallHAL HAL_IRQDisable ; Stop the rogue device from killing us completely

Jeffrey Lee's avatar
Jeffrey Lee committed
2849
Reset_IRQ_Exit
2850
        MyCLREX a1, a2
2851 2852 2853
        Pull    "a1-a2,lr"
        MSR     CPSR_c, a2
        MSR     SPSR_cxsf, a1
2854
        Pull    "a1-a4,v1-v2,sb,ip,pc",,^
Kevin Bracey's avatar
Kevin Bracey committed
2855

2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866
 [ DebugHALTX
DebugHALPrint
        Push    "a1-a4,v1,sb,ip"
        AddressHAL
        MOV     v1, lr
10      LDRB    a1, [v1], #1
        TEQ     a1, #0
        BEQ     %FT20
        CallHAL HAL_DebugTX
        B       %BT10
20      MOV     a1, #13
2867
;        CallHAL HAL_DebugTX
2868
        MOV     a1, #10
2869
;        CallHAL HAL_DebugTX
2870 2871 2872 2873 2874 2875 2876 2877
        ADD     v1, v1, #3
        BIC     lr, v1, #3
        Pull    "a1-a4,v1,sb,ip"
        MOV     pc, lr
 ]


 [ DebugHALTX
2878 2879 2880 2881 2882 2883
DebugHALPrintReg ; Output number on top of stack to the serial port
        Push    "a1-a4,v1-v4,sb,ip,lr"   ; this is 11 regs
        LDR     v2, [sp,#11*4]           ; find TOS value on stack
        ADR     v3, hextab
        MOV     v4, #8
05
2884
       AddressHAL
2885
10      LDRB    a1, [v3, v2, LSR #28]
2886
       CallHAL  HAL_DebugTX
2887 2888 2889 2890
        MOV     v2, v2, LSL #4
        SUBS    v4, v4, #1
        BNE     %BT10
        MOV     a1, #13
2891
       CallHAL  HAL_DebugTX
2892
        MOV     a1, #10
2893 2894
       CallHAL  HAL_DebugTX

2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912
        Pull    "a1-a4,v1-v4,sb,ip,lr"
        ADD     sp, sp, #4
        MOV     pc, lr

hextab  DCB "0123456789abcdef"


 ]
;
;
; [ DebugHALTX
;HALDebugHexTX
;       stmfd    r13!, {r0-r3,sb,ip,lr}
;       AddressHAL
;       b        jbdt1
;HALDebugHexTX2
;       stmfd    r13!, {r0-r3,sb,ip,lr}
;       AddressHAL
2913
;       mov      r0,r0,lsl #16
2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946
;       b        jbdt2
;HALDebugHexTX4
;       stmfd    r13!, {r0-r3,sb,ip,lr}
;       AddressHAL
;       mov      r0,r0,ror #24          ; hi byte
;       bl       jbdtxh
;       mov      r0,r0,ror #24
;       bl       jbdtxh
;jbdt2
;       mov      r0,r0,ror #24
;       bl       jbdtxh
;       mov      r0,r0,ror #24
;jbdt1
;       bl       jbdtxh
;       mov      r0,#' '
;       CallHAL  HAL_DebugTX
;       ldmfd    r13!, {r0-r3,sb,ip,pc}
;
;jbdtxh stmfd    r13!,{a1,v1,lr}        ; print byte as hex. corrupts a2-a4, ip, assumes sb already AddressHAL'd
;       and      v1,a1,#&f              ; get low nibble
;       and      a1,a1,#&f0             ; get hi nibble
;       mov      a1,a1,lsr #4           ; shift to low nibble
;       cmp      a1,#&9                 ; 9?
;       addle    a1,a1,#&30
;       addgt    a1,a1,#&37             ; convert letter if needed
;       CallHAL  HAL_DebugTX
;       cmp      v1,#9
;       addle    a1,v1,#&30
;       addgt    a1,v1,#&37
;       CallHAL  HAL_DebugTX
;       ldmfd    r13!,{a1,v1,pc}
; ]
;
2947 2948
        END