;*************************************************************************
;** 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: 68060 specific routines                                      **
;*************************************************************************

;FOLD Includes
        include mu_lib.i
        include mu_context.i
        include mu_alerts.i
;ENDFOLD
;FOLD External references
        xref SubSuper
        xref Parse060
        xref MUAlert
        xref AddTransparentTranslation
;ENDFOLD

        section main_code,code

        machine mc68060

;FOLD Init060
;*************************************************
;** Init060                                     **
;** Initialize internal vectors of the library  **
;** base for the use of the 68060 MMU           **
;**                                             **
;** *a1 = vectors to be filled out              **
;** *a6 = library base                          **
;** returns success/failure in d0               **
;*************************************************
        xdef Init060
Init060:
        lea ReadConfig(pc),a0
        move.l a0,2+mulib_ReadConfig(a6)        ;no need to flush the cache, that's done by the library anyways
        lea WriteConfig(pc),a0
        move.l a0,2+mulib_WriteConfig(a6)
        lea SetLibrary(pc),a0
        move.l a0,2+mulib_SetLibrary(a6)
        lea Parse060(pc),a0
        move.l a0,2+mulib_ParseMMU(a6)
        lea ParseTT(pc),a0
        move.l a0,2+mulib_ParseTT(a6)
        moveq #1,d0
        rts
;ENDFOLD
;FOLD ReadConfig
;*************************************************
;** ReadConfig                                  **
;** Read the MMU configuration                  **
;** to *a0 struct MMUConfig                     **
;*************************************************
ReadConfig:
        pea _ReadConfig(pc)
        bsr SubSuper
        rts
_ReadConfig:
        moveq #0,d0
        movec tc,d0                             ;read the translation control
        move d0,mcf_translationctrl(a0)         ;keep it
        tst.w d0
        bpl.s .disabled                         ;if disabled, ignore it
        movec.l urp,d0
        movec.l srp,d1
        clr.b d0
        clr.b d1                                ;avoid trouble and clear unused bits
        bclr #8,d0
        bclr #8,d1
        move.l d0,mcf_userrootpointer(a0)
        move.l d1,mcf_superrootpointer(a0)
.disabled:
        movec.l dtt0,d0
        movec.l dtt1,d1
        movem.l d0-d1,mcf_dtt0(a0)
        movec.l itt0,d0
        movec.l itt1,d1
        movem.l d0-d1,mcf_itt0(a0)              ;keep the translation registers
        rte
;ENDFOLD
;FOLD WriteConfig
;*************************************************
;** WriteConfig                                 **
;** install the MMU configuration in *a0        **
;*************************************************
WriteConfig:
        pea _WriteConfig(pc)
        bsr SubSuper
        rts
_WriteConfig:
        ori.w #$0700,sr                         ;all interrupts off
                                                ;here: enable it
        cpusha bc                               ;flush the caches, write back
        moveq #0,d1
        movec.l d1,tc
        movec.l d1,itt0
        movec.l d1,itt1
        movec.l d1,dtt0
        movec.l d1,dtt1                         ;clear this mess

        tst.w 2+mcf_translationctrl(a0)         ;MMU disabled ?
        bpl.s .disableme
        move.l mcf_userrootpointer(a0),d0
        move.l mcf_superrootpointer(a0),d1
        movec.l d0,urp
        movec.l d1,srp                          ;set the URP and SRP
        pflusha                                 ;flush the ATC
.disableme:
        tst.w 2+mcf_dtt0(a0)                    ;enabled ?
        bpl.s .isdisabled0
        move.l mcf_dtt0(a0),d0
        movec.l d0,dtt0
.isdisabled0:
        tst.w 2+mcf_dtt1(a0)
        bpl.s .isdisabled1
        move.l mcf_dtt1(a0),d0
        movec.l d0,dtt1
.isdisabled1:
        tst.w 2+mcf_itt0(a0)                    ;enabled ?
        bpl.s .isdisabledi0
        move.l mcf_itt0(a0),d0
        movec.l d0,itt0
.isdisabledi0:
        tst.w 2+mcf_itt1(a0)
        bpl.s .isdisabledi1
        move.l mcf_itt1(a0),d0
        movec.l d0,itt1
.isdisabledi1:
        cpusha bc                               ;again!

        rte
;ENDFOLD
;FOLD SetLibrary
;*************************************************
;** SetLibrary                                  **
;** set the data in the library base from       **
;** the MMUConfig *a0                           **
;*************************************************
SetLibrary:
        move.w 2+mcf_translationctrl(a0),d0     ;get TC
        bpl.s .disabled                         ;is it enabled ?
                                                ;here yes: Read the values and life with them
        btst #14,d0                             ;which page size ?
        beq.s .fourKpages                       ;if clear, pages are 4K large
        move.b #13,mulib_PageBits(a6)           ;8K pages
        move.b #5,mulib_LevelCBits(a6)          ;5 Bits in the page index
        move.l #$2000,d0                        ;Pages must be on 8K boundaries
        bra.s .setremaining
.fourKpages:                                    ;default: 4K
.disabled:
        move.b #12,mulib_PageBits(a6)           ;4K pages
        move.b #6,mulib_LevelCBits(a6)          ;Level C Bits
        move.l #$1000,d0                        ;Pages must be on 4K boundaries
.setremaining:
        move.l d0,mulib_PageAlign(a6)           ;this is the page size, too
        subq.l #1,d0
        not.l d0
        move.l d0,mulib_PageMask(a6)
        move.b #7,mulib_LevelABits(a6)          ;this is fixed.
        move.b #7,mulib_LevelBBits(a6)
        move.l #$0200,d0
        clr.b mulib_InitialShift(a6)            ;no initial shift
        move.l d0,mulib_LevelAAlign(a6)
        move.l d0,mulib_LevelBAlign(a6)
        move.l d0,mulib_LevelCAlign(a6)         ;even though more bits should be available, the '060 differs here from the '040
        subq.l #1,d0
        not.l d0
        clr.b mulib_LevelDBits(a6)              ;no level D
        move.l d0,mulib_LevelAMask(a6)
        move.l d0,mulib_LevelBMask(a6)
        move.l d0,mulib_LevelCMask(a6)
        move.l #~3,mulib_IndirectMask(a6)

        clr.l mulib_UpperEnd(a6)                ;the MMU maps
        rts
;ENDFOLD
;FOLD ParseTT
;*************************************************
;** ParseTT                                     **
;** Add the modifications made thru the         **
;** transparent translation registers           **
;** *a1=MMUConfig                               **
;** *a0=Context                                 **
;*************************************************
ParseTT:
        move.l mcf_dtt0(a0),d0          ;get the data transparent translation
        tst.w d0                        ;used, or not?
        bpl.s .nodtt0
                                        ;there MUST be match in one of the ittx
                                        ;registers or the data and instruction
                                        ;address space differs. This is not
                                        ;supported by the amiga programming model
                                        ;and considered to be illegal
        move.l mcf_itt0(a0),d1
        bsr _CheckTTMatch
        beq.s .foundmatch0              ;if so, map in dtt0

        move.l mcf_dtt0(a0),d0
        move.l mcf_itt1(a0),d1          ;check itt1 instead
        bsr _CheckTTMatch
        beq.s .foundmatch0

        pea AN_IllegalTT
        bsr MUAlert                     ;generate alert if unsupported
        moveq #0,d0
        bra.s .exit
.foundmatch0:
        move.l mcf_dtt0(a0),d0          ;map in
        bsr _AddTT                      ;the dtt0. We don't use the itt0
        beq.s .exit
                                        ;because the cache bits must be
                                        ;correct in the dtt0 whereas
                                        ;copyback/writethrough makes no
                                        ;difference for instructions
.nodtt0:
        move.l mcf_dtt1(a0),d0          ;quite the same for dtt1
        tst.w d0
        bpl.s .nodtt1

        move.l mcf_itt0(a0),d1
        bsr _CheckTTMatch
        beq.s .foundmatch1              ;if so, map in dtt0

        move.l mcf_dtt1(a0),d0
        move.l mcf_itt1(a0),d1          ;check itt1 instead
        bsr _CheckTTMatch
        beq.s .foundmatch1

        pea AN_IllegalTT
        bsr MUAlert                     ;generate alert if unsupported
        moveq #0,d0
        bra.s .exit
.foundmatch1:
        move.l mcf_dtt1(a0),d0          ;map in
        bsr _AddTT                      ;the dtt1.
        bra.s .exit
.nodtt1:
        moveq #1,d0                     ;fine, too
.exit:
        rts

;**
;** Check whether the translation control registers d0,d1 describe the
;** same memory mapping
;** returns eq if so.
;**
_CheckTTMatch:
        eor.l d0,d1                     ;calculate difference
        lsl.l #8,d0                     ;shift logical address mask to the bits 31..24
        not.l d0                        ;set all DO-NOT-CARE bits in this mask to zero
        or.l #$00ffffff,d0              ;set all other bits
        and.l d0,d1                     ;ignore address base bits not in the mask
        bclr #5,d1                      ;we ignore the precise cache mode since
                                        ;this need not to be set up correctly for the
                                        ;instruction translation
        tst.l d1                        ;if this is zero, we've a match
        rts
;**
;** Add the mapping of the transparent translation register in d0
;** to the mapping of the cache
;** The enable bit will not be checked; this should be called only
;** if the corresponding TT register is active anyways
;**
_AddTT:
        movem.l a0-a1,-(a7)             ;saveback the context and the mmuconfig

        bfextu d0{18:2},d1              ;extract the supervisor field
        cmp.b #1,d1                     ;if this is supervisor only, we
                                        ;do not care
                                        ;we build ONLY the user table
        beq.s .ignore
        bfextu d0{25:2},d1              ;extract cache modes
        swap d0
        move.l d0,a1                    ;move address mask and base to a1
        swap d0

        and.l #(1<<mapp_userpage0)!(1<<mapp_userpage1)!(1<<mapp_writeprotected),d0      ;extract user page attributes and write protection

        tst.b d1                        ;set cache mode
        beq.s .writethrough
        subq.b #1,d1
        beq.s .copyback
        subq.b #1,d1
        beq.s .precise

        bset #mapp_imprecise,d0         ;cache inhibited, imprecise exception model
.precise:
        bset #mapp_cacheinhibit,d0      ;no cache
        bra.s .gotit
.copyback:
        bset #mapp_copyback,d0          ;copyback mode enabled
.gotit:
.writethrough:                          ;this is default
        move.l #(1<<mapp_userpage0)!(1<<mapp_userpage1)!(1<<mapp_writeprotected)!(1<<mapp_imprecise)!(1<<mapp_cacheinhibit)!(1<<mapp_copyback),d1      ;select the bits to alter
        bsr AddTransparentTranslation   ;modify the context to reflect this
        bra.s .exit
.ignore:
        moveq #1,d0
.exit:
        movem.l (a7)+,a0-a1
        rts
;ENDFOLD


