*
*   mmu.s - 68040/68060 MMU control functions
*   Copyright (C) 1997 Aki Laukkanen
*
*   This program is free software; you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation; either version 2 of the License, or
*   (at your option) any later version.
*
*   This program is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License
*   along with this program; if not, write to the Free Software Foundation,
*   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*

	XDEF    _MakeDescriptors
	XDEF    @MakeDescriptors
	XDEF    _mmu_mark
	XDEF    @mmu_mark

	include "exec/types.i"
	include "exec/memory.i"
	include "lvo/exec_lib.i"
	include "mmu.i"

	IFND    TRUE
TRUE EQU    1
	ENDC

	IFND    FALSE
FALSE EQU   0
	ENDC

*
*   FUNCTION
*       void * __asm MakeDescriptors(register __a0 UBYTE *start,
*                                    register __d0 ULONG length,
*                                    register __a6 struct ExecBase *SysBase);
*
*   SYNOPSIS
*       Allocates space for a pointer table which holds pointers
*       to the page descriptors. Then fills in the pointers.
*

_MakeDescriptors
@MakeDescriptors
	movem.l d2-d4/d7/a2,-(sp)
	move.l  a0,a2
	move.l  d0,d4
	jsr     (_LVOSuperState,a6)
	movec   tc,d3                                   ; translation code register
	movec   urp,d2                                  ; user root pointer
	jsr     (_LVOUserState,a6)

	btst    #TCB_E,d3
	beq     .error
	btst    #TCB_P,d3
	bne     .error

	move.l  d4,d1

	lsr.l   #8,d4
	lsr.l   #4,d4

	and.w   #$fff,d1
	beq.s   .skip_a
	addq.l  #1,d4
.skip_a

	move.l  d4,d0
	lsl.l   #2,d0
	move.l  #MEMF_ANY|MEMF_PUBLIC,d1
	jsr     (_LVOAllocVec,a6)
	tst.l   d0
	beq     .error
	move.l  d0,a0

	subq.l  #1,d4
	move.l  d4,d7

	move.l  a0,d4
	move.l  a2,a1
; a1 - chunkybuffer
; a0 - page descriptors
; d7 - counter
; d2 - urp

.loop
	move.l  d2,-(sp)
	move.l  a1,d0
	rol.l   #8,d0
	lsl.l   #1,d0
	and.w   #%1111111000000000,d2
	and.w   #%0000000111111100,d0
	or.w    d0,d2
	move.l  d2,a2
	move.l  (a2),d2
	btst    #TDB_UDT0,d2
	beq     .skip                   ; if 0
	btst    #TDB_UDT1,d2            ; if 1
	beq     .end
	bra     .skip2
.skip
	btst    #TDB_UDT1,d2
	bne     .end
.skip2
	move.l  a1,d0
	lsr.l   #8,d0
	lsr.l   #8,d0
	and.w   #%1111111000000000,d2
	and.w   #%0000000111111100,d0
	or.w    d0,d2
	move.l  d2,a2
	move.l  (a2),d2
	btst    #TDB_UDT0,d2
	beq     .skip1                  ; if 0
	btst    #TDB_UDT1,d2            ; if 1
	beq     .end
	bra     .skip3
.skip1
	btst    #TDB_UDT1,d2
	bne     .end
.skip3
	move.l  a1,d0
	lsr.l   #8,d0
	lsr.l   #2,d0
	and.w   #%1111111100000000,d2
	and.w   #%0000000011111100,d0
	or.w    d0,d2

	move.l  d2,a2
	btst    #PDB_PDT0,(3,a2)
	beq     .end

	move.l  d2,(a0)+
	adda.l  #4096,a1
	move.l  (sp)+,d2
	dbf     d7,.loop
	move.l  d4,d0
	movem.l (sp)+,d2-d4/d7/a2
	rts
.end
	move.l  (sp)+,d2
.error
	movem.l (sp)+,d2-d4/d7/a2
	moveq   #0,d0
	rts


*
*   FUNCTION
*       UBYTE __asm mmu_mark(register __a0 UBYTE *start,
*                            register __d0 ULONG length,
*                            register __d1 ULONG cm,
*                            register __a6 struct ExecBase *SysBase);
*
*   SYNOPSIS
*       Changes the cache mode for the specified memory area. This
*       area  must be aligned by 4kB and be multiple of 4kB in size.
*
*   RESULT
*       Returns the old cache mode for the memory area.
*
*   NOTES
*       Works only after setpatch has been issued and in such
*       systems where 68040.library/68060.library is correctly
*       installed.
*

_mmu_mark
@mmu_mark
	movem.l d2/d3/d7/a2/a4/a6,-(sp)

	move.l  a1,a4
	movem.l d0/d1/a0,-(sp)
	jsr     (_LVOSuperState,a6)
	movec   tc,d3                                   ; translation code register
	movec   urp,d2                                  ; user root pointer
	jsr     (_LVOUserState,a6)
	movem.l (sp)+,d0/d1/a0

	btst    #TCB_E,d3
	beq     .error
	btst    #TCB_P,d3
	bne     .error

	move.l  d1,-(sp)
	move.l  d0,d1

	lsr.l   #8,d0
	lsr.l   #4,d0

	move.l  a0,a1

	and.w   #$fff,d1
	beq.s   .skip_a
	addq.l  #1,d0
.skip_a
	move.l  (sp)+,d1
	subq.l  #1,d0
	move.l  d0,d7

; a1 - chunkybuffer
; d7 - counter
; d2 - urp
; d1 - cache mode

.loop
	move.l  d2,-(sp)
	move.l  a1,d0
	rol.l   #8,d0
	lsl.l   #1,d0
	and.w   #%1111111000000000,d2
	and.w   #%0000000111111100,d0
	or.w    d0,d2
	move.l  d2,a2
	move.l  (a2),d2
	btst    #TDB_UDT0,d2
	beq     .skip                   ; if 0
	btst    #TDB_UDT1,d2            ; if 1
	beq     .end
	bra     .skip2
.skip
	btst    #TDB_UDT1,d2
	bne     .end
.skip2
	move.l  a1,d0
	lsr.l   #8,d0
	lsr.l   #8,d0
	and.w   #%1111111000000000,d2
	and.w   #%0000000111111100,d0
	or.w    d0,d2
	move.l  d2,a2
	move.l  (a2),d2
	btst    #TDB_UDT0,d2
	beq     .skip1                  ; if 0
	btst    #TDB_UDT1,d2            ; if 1
	beq     .end
	bra     .skip3
.skip1
	btst    #TDB_UDT1,d2
	bne     .end
.skip3
	move.l  a1,d0
	lsr.l   #8,d0
	lsr.l   #2,d0
	and.w   #%1111111100000000,d2
	and.w   #%0000000011111100,d0
	or.w    d0,d2

	move.l  d2,a2
	btst    #PDB_PDT1,(3,a2)
	bne     .skip4
	btst    #PDB_PDT0,(3,a2)
	beq     .end
	bra     .skip5
.skip4
	btst    #PDB_PDT0,(3,a2)
	beq     .indirect
.skip5
	move.b  (3,a2),d3
	and.b   #~CM_MASK,(3,a2)
	or.b    d1,(3,a2)

.indirect
	lea     (4096,a1),a1

	move.l  (sp)+,d2
	dbf     d7,.loop

	and.b   #CM_MASK,d3
	jsr     (_LVOSuperState,a6)
	pflusha
	jsr     (_LVOUserState,a6)

	moveq   #0,d0
	move.b  d3,d0

	movem.l (sp)+,d2/d3/d7/a2/a4/a6
	rts
.end
	move.l  (sp)+,d2
.error
	movem.l (sp)+,d2/d3/d7/a2/a4/a6
	moveq   #0,d0
	rts
