;*************************************************************************
;** mmu.library                                                         **
;**                                                                     **
;** a system library for arbitration and control of the MC68K MMUs      **
;**                                                                     **
;** © 1998 THOR-Software, Thomas Richter                                **
;** No commercial use, reassembly, modification without prior, written  **
;** permission of the authors.                                          **
;** Including this library in any commercial software REQUIRES a        **
;** written permission and the payment of a small fee.                  **
;**                                                                     **
;** This is an internal header file, do not depend on anything here.    **
;** Use the official include files.                                     **
;** Distributed only for the mmu.library development group for private  **
;** use.                                                                **
;**                                                                     **
;**---------------------------------------------------------------------**
;** Block: MMU Table Parser for 68040 and 68060                         **
;*************************************************************************

;FOLD Includes
        include inc:macros.asm
        include mu_lib.i
        include mu_context.i
;ENDFOLD
;FOLD External references
        xref DefineMapping
;ENDFOLD

        section main_code,code

        machine mc68020

;FOLD Parse060
;*************************************************
;** Parse060                                    **
;** The parser for the 060 MMU tables           **
;** *a0=the Context to fill out                 **
;** *a1=the pointer to MMUConfig                **
;**                                             **
;** Returns:                                    **
;** d0 =0 if out of memory.                     **
;** d0 =1 if O.K., including if no useful       **
;**                table is available           **
;*************************************************
        xdef Parse060
Parse060:
        saveregs d2-d7/a2-a5

        move.l a0,a2                            ;keep context

        btst #7,2+mcf_translationctrl(a1)       ;MMU enabled?
        beq .okexit                             ;if not, ignore that anyways

        sub.l a4,a4                             ;address to make a table search for
        do
         move.l a4,d3                           ;keep the address
         moveq #-1,d4                           ;current level in the tree: read the initial shift the first time
         move.l d2,d5                           ;Descriptor type
         swap d4
         moveq #1,d6                            ;address range described by this level
         clr.w d4
         moveq #0,d7                            ;accumulated flags
         swap d4
         move.l a3,a5
         do
          moveq #0,d1
          cmp.w #4,d4                           ;already at page level ?
          bge.s .indirect                       ;if so, we're examining an indirect descriptor. Stop shifting

          move.b mulib_LevelABits(a6,d4.w),d0
          beq.s .noshift
          lsl.l d0,d3                           ;ignore these bits, shift levels from last level off the word
          ror.l d0,d6                           ;calculate address range
.noshift:

          addq.w #1,d4                          ;next level of the tree
          move.b mulib_LevelABits(a6,d4.w),d0   ;read the size of the next level
          bne.s .isthere
          move.w #4,d4                          ;empty, so use the page level and abort
          move.b mulib_PageBits(a6),d0
.isthere:
          bfextu d3{0:d0},d1                    ;get the index from the address
.indirect:
          swap d4
          move.w d4,d0                          ;page index to d0
          move.w d1,d4                          ;save new page index: keep for next iteration
          swap d4

          lea (a5,d0.w*4),a5
          btst #2,3(a5)                         ;write protected ?
          beq.s .nowriteprot
          bset #mapp_writeprotected,d7          ;accumulate write protection
                                                ;this MUST be zero at the root level
.nowriteprot:
          bfextu (a5){30:2},d0                  ;get descriptor type for this level of the tree
          tst.b d0                              ;which type
          beq.s .invalidpage                    ;this descriptor type is invalid
          cmp.b #1,d0                           ;page descriptor = early termination ?
          beq.s .termination
          cmp.b #2,d0
          beq.s .resident                       ;page is indirect (or resident)
          cmp.w #4,d4                           ;are we at page level ?
          beq.s .termination                    ;if so, this means resident, too
.resident:

          move.l (a5),d1
          and.l mulib_LevelAMask(a6,d4.w*4),d1  ;mask out bits
         loop

.invalidpage:
         move.l a4,a0
         lea (a4,d6.l),a1                       ;upper and lower address to exclude
         move.l #(1<<mapp_invalid),d0
         moveq #0,d1
         bsr _SetDescriptor
         beq.s .exit                            ;exit on error
         bra.s .endloop

.termination:
         cmp.w #4,d4                            ;termination is only possible at page level
         bne.s .invalidpage

         bfextu (a5){25:2},d0                   ;get cache mode
         tst.b d0
         beq.s .writethrough
         subq.b #1,d0
         beq.s .copyback
         subq.b #1,d0
         beq.s .precise
         bset #mapp_imprecise,d7                ;imprecise exception model
.precise:
         bset #mapp_cacheinhibit,d7
         bra.s .setnow
.copyback:
         bset #mapp_copyback,d7                 ;the '030 doesn't know this, but this avoids rebuilding the complete default mapping
.writethrough:                                  ;this is the default
.setnow:
         move.l (a5),d0
         move.l a4,a0
         and.l #(1<<mapp_supervisoronly)!(1<<mapp_writeprotected)!(1<<mapp_userpage0)!(1<<mapp_userpage1)!(1<<mapp_shared),d0
         lea (a4,d6.l),a1
         move.l (a5),d1                         ;get page address
         or.l d7,d0                             ;set some more relevant flags
         and.l mulib_PageMask(a6),d1            ;remove bits from this level
         sub.l a0,d1                            ;get difference
         beq.s .noindirect
         bset #mapp_indirect,d0                 ;will be relocated elsewhere
.noindirect:
         bsr _SetDescriptor
         beq.s .exit
.endloop:
         add.l d6,a4                            ;next address
         cmp.l mulib_UpperEnd(a6),a4
        while ne
.okexit:
        moveq #1,d0
.exit:
        loadregs
        rts

_SetDescriptor:
        reserve map_len

        subq.l #1,a1
        movem.l d0-d1,map_properties(a7)
        movem.l a0-a1,map_lower(a7)             ;upper, lower
        moveq #-1,d0
        clr.l map_flags(a7)
        move.l d0,map_mask(a7)                  ;mask in everything
        move.l a2,a0
        move.l a7,a1
        bsr DefineMapping
        restore
        rts
;ENDFOLD

