;*************************************************************************
;** 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: Memory pool operations                                       **
;** Because the exec memory pool functions are bugged and it is not     **
;** clear whether SetPatch is installed to fix it, we use our own.      **
;*************************************************************************

;FOLD Include
        include INC:macros.asm
        include inc:exec_lib.asm
        include mu_lib.i
        include mu_alerts.i
;ENDFOLD
;FOLD External references
        xref MMUName
;ENDFOLD

        section main_code,code

;FOLD MUCreatePool
;*************************************************
;** MUCreatePool                                **
;** d0=ReqMents,d1=puddleSize,d2=puddleThresh   **
;*************************************************
        xdef MUCreatePool
MUCreatePool:
        saveregs a6

        move.l mulib_SysBase(a6),a6

        sub.l a0,a0
        cmp.l d2,d1
        bcs.s .failexit         ;puddlesize must be larger
        move.l d0,-(sp)
        moveq #7,d0
        add.l d0,d1
        not.b d0
        and.b d0,d1             ;round puddleSize
        move.l d1,-(sp)
        moveq #1,d1             ;public memory
        moveq #$18,d0
        jsr AllocMem(a6)        ;AllocMem
        move.l (sp)+,d1         ;puddleSize
        move.l (sp)+,a0         ;ReqMents
        tst.l d0
        beq.s .failexitd0
        exg.l d0,a0             ;ReqMents->d0,Ptr->a0
        move.l a0,8(a0)
        addq.l #4,a0
        clr.l (a0)
        move.l a0,-(a0)         ;NewList
        movem.l d0-d2,$c(a0)
.failexit:
        move.l a0,d0
.failexitd0:
        loadregs
        rts
;ENDFOLD
;FOLD MUDeletePool
;*************************************************
;** MUDeletePool                                **
;** delete the pool *a0                         **
;*************************************************
        xdef MUDeletePool
MUDeletePool:
        saveregs a2/a6

        move.l mulib_SysBase(a6),a6

        move.l a0,d0
        beq.s .nopoolexit
        move.l (a0),a2                  ;get first
        do
         move.l (a2),d2                 ;next entry?
         break.s eq
         move.l a2,a1                   ;if so, take it
         move.l d2,a2                   ;remember next
         jsr FreeVec(a6)                ;release it
        loop.s
        lea -4(a2),a1                   ;get pointer to head
        moveq #$18,d0
        jsr FreeMem(a6)                 ;release head
.nopoolexit:

        loadregs
        rts
;ENDFOLD
;FOLD MUAllocPooled
;*************************************************
;** MUAllocPooled                               **
;** d0=MemSize                                  **
;** a0=PoolHeader                               **
;** d1=ReqMents                                 **
;*************************************************
        xdef MUAllocPooled
MUAllocPooled:
        saveregs d2-d4/a2-a3/a6

        move.l mulib_SysBase(a6),a6

        move.l d1,d4                    ;keep ReqMents
        move.l d0,d2                    ;ByteSize->d2
        beq .exit
        move.l a0,d0                    ;Header available ?
        beq .exit
        move.l a0,a2                    ;keep it

        cmp.l $14(a2),d2                ;compare with puddlesthres
        bhs.s .allocdirect              ;too big, get directly
        cmp.b 3+$c(a2),d4               ;right type ?
        bne.s .allocdirect              ;no, so get directly
                                        ;allocate pool
.tryagain:
        move.l (a2),d3                  ;*first node
        do
         move.l d3,a3
         move.l (a3),d3                 ;available ?
         beq.s .addpool                 ;no, so add new pool
         tst.l 8(a3)                    ;is this a private memory piece ?
         beq.s .addpool                 ;no, so allocate new

         move.l a3,a0
         move.l d2,d0                   ;size to d0
         addq.l #4,d0
         jsr Allocate(a6)               ;allocate private
         tst.l d0
        while.s eq                      ;if not, try next
        move.l d0,a0                    ;*Mem->a0
        addq.l #4,d2                    ;one additional long
                                        ;clear it ?
        btst #$10,d4
        beq.s .noclear
        move.l a0,a1
        move.l d2,d1                    ;size -> d1
        addq.l #7,d1
        lsr.l #3,d1
        subq.l #1,d1                    ;size in double long words
        move.w d1,d0
        swap d1
        moveq #0,d3
.swp1:  move.l d3,(a1)+
        move.l d3,(a1)+
        dbra d0,.swp1
        dbra d1,.swp1
.noclear:
        move.l d2,(a0)+                 ;enter length
        move.l a0,d0
        bra .exit
.allocdirect:
        move.l d2,d0                    ;size -> d0
        addq.l #8,d0
        addq.l #4,d0                    ;+$c
        move.l d4,d1                    ;get length
        jsr AllocVec(a6)                ;get as vector
        tst.l d0
        beq .exit                       ;exit if no memory
        move.l d0,a1                    ;*Mem->a1
        move.l a2,a0                    ;Liste->a0
        addq.l #4,a0
        move.l 4(a0),d0
        move.l a1,4(a0)
        exg.l d0,a0
        movem.l d0/a0,(a1)
        move.l a1,(a0)                  ;AddTail
        addq.l #8,a1                    ;length of the node structure
        clr.l (a1)+                     ;erase it. Private, no pool
        move.l a1,d0                    ;return pointer
        bra.s .exit
.addpool:                               ;add a new pool here
        move.l $10(a2),d0               ;PuddleSize->d0
        moveq #$24,d1
        add.l d1,d0                     ;+Headersize
        move.l $c(a2),d1                ;ReqMents
        jsr AllocVec(a6)
        tst.l d0
        beq.s .exit                     ;exit if no memory

        move.l d0,a3                    ;head->a3
        move.l d0,a1
        move.l a2,a0

        move.l (a0),d0
        move.l a1,(a0)
        movem.l d0/a0,(a1)
        move.l d0,a0
        move.l a1,4(a0)         ;AddHead

        moveq #$a,d0
        move.b d0,8(a3)         ;Type,Pri: auf jeden Fall nicht 0
        move.b d0,9(a3)
        move.l #MMUName,$a(a3)  ;set name: mmu.library
        move.l $c(a2),d1        ;ReqMents
        move.l d1,$e(a3)        ;save as reqments of the pool
        lea $24(a3),a0          ;start of the memory list
        moveq #~7,d1
        move.l a0,d0            ;address ->a0
        and.l d0,d1             ;divisible by 8
        move.l d1,a0
        move.l $10(a2),d0       ;PuddleSize->d0
        move.l a0,$10(a3)       ;*First
        move.l a0,$14(a3)       ;*Lower
        move.l d0,$1c(a3)       ;Free
        clr.l (a0)              ;clear *NextHunk
        move.l d0,4(a0)         ;length
        add.l d0,a0             ;end
        move.l a0,$18(a3)       ;*High
        bra .tryagain
.exit:
        loadregs
        rts
;ENDFOLD
;FOLD MUFreePooled
;*************************************************
;** MUFreePooled                                **
;** memory *a1, pool *a0                        **
;*************************************************
        xdef MUFreePooled
MUFreePooled:
        saveregs a2-a3/a6

        move.l a1,d1                    ;no memory, freepooled
        beq .exit

        move.l mulib_SysBase(a6),a6

        move.l a0,d1
        beq .alert                      ;no pool -> alert

        lea -$c(a1),a2                  ;pointer to begin

                                        ;get the responsible header
        move.l (a0),d1                  ;*First
        do
         move.l d1,a3
         move.l (a3),d1                 ;*next
         beq.s .alert                   ;not found -> alert
         cmp.l a2,a3                    ;our block ?
         beq.s .freeprivate
         tst.l 8(a3)                    ;do we have a private one ?
         reloop.s eq
         cmp.l $14(a3),a1               ;compare with lower
         reloop.s lo                    ;continue if too small
         cmp.l $18(a3),a1
        while.s hs                      ;or too large

        move.l a3,a0
        move.l -(a1),d0                 ;get length
        jsr Deallocate(a6)              ;release

        move.l 4(a3),a1                 ;*Pred
        move.l 4(a1),d1                 ;exists ?
        beq.s .nopred
        move.l d1,a0                    ;PredPred->a0
        move.l a3,(a0)                  ;insert me as predicessor of predpred
        move.l a0,4(a3)                 ;my pred is predpred
        move.l a3,4(a1)                 ;I'm pred of my old pred
        move.l (a3),a0                  ;get succ
        move.l a0,(a1)                  ;this is succ of my old succ
        move.l a1,4(a0)                 ;pred is pred of my succ
        move.l a1,(a3)                  ;that's my succ
                                        ;or, in other words, move this
                                        ;node towards the head of the list
.nopred:
        move.l a3,a2                    ;*head -> a2

        move.l $1c(a2),d0               ;get free mem
        add.l $14(a2),d0                ;plus lower
        cmp.l $18(a2),d0                ;-Upper =0 -> this block is FREE
        bne.s .exit
.freeprivate:                           ;release a complete pool
        move.l a2,a1                    ;to a1
        move.l a1,d0
        move.l (a1)+,a0                 ;next->a0
        move.l (a1),a1                  ;pred->a1
        move.l a0,(a1)
        move.l a1,4(a0)                 ;remove
        move.l a2,a1
        jsr FreeVec(a6)                 ;and release
        bra.s .exit
.alert:
        saveregs a5/d7
        move.l #AN_BadFreePool,d7
        sub.l a5,a5
        jsr Alert(a6)                   ;and alert
        loadregs
.exit:
        moveq #0,d0
        loadregs
        rts
;ENDFOLD

;FOLD AllocContextMem
;*************************************************
;** AllocContextMem                             **
;** allocate from the context pool d0 bytes     **
;*************************************************
        xdef AllocContextMem
AllocContextMem:
        move.l a6,a1
        move.l mulib_SysBase(a6),a6
        lea mulib_PoolSemaphore(a1),a0
        jsr ObtainSemaphore(a6)                 ;does not alter registers

        move.l a1,a6
        move.l #$10001,d1                       ;Clear it
        move.l mulib_ContextPool(a6),a0
        bsr MUAllocPooled

        move.l a6,a1
        move.l mulib_SysBase(a6),a6
        lea mulib_PoolSemaphore(a1),a0
        jsr ReleaseSemaphore(a6)

        move.l a1,a6
        tst.l d0
        rts
;ENDFOLD
;FOLD FreeContextMem
;*************************************************
;** FreeContextMem                              **
;** release the allocated memory at *a1         **
;** size is implicit                            **
;*************************************************
        xdef FreeContextMem
FreeContextMem:
        move.l a1,d0
        move.l a6,a1
        move.l mulib_SysBase(a6),a6
        lea mulib_PoolSemaphore(a1),a0
        jsr ObtainSemaphore(a6)                 ;does not alter registers

        move.l a1,a6
        move.l mulib_ContextPool(a6),a0
        move.l d0,a1
        bsr MUFreePooled

        move.l a6,a1
        move.l mulib_SysBase(a6),a6
        lea mulib_PoolSemaphore(a1),a0
        jsr ReleaseSemaphore(a6)

        move.l a1,a6
        rts
;ENDFOLD

