mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-29 20:49:19 +00:00
772 lines
31 KiB
Plaintext
772 lines
31 KiB
Plaintext
;-----------------------------------------------------------------------------------
|
|
;
|
|
; File: GetReal.a
|
|
;
|
|
; Written by: Carl C. Hewitt
|
|
;
|
|
; Copyright: © 1991-1993 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM10> 10/14/93 pdw (CCH) Split PowerPC EDiskProtect code into seperate routine.
|
|
; Added EDisk support for PDM.
|
|
; <SM9> 6/21/93 kc Fix vm test in GetMMUInfo.
|
|
; <SM8> 6/14/93 SAM Clarified the comments related to the isVMRunnning check in
|
|
; GetMMUInfo.
|
|
; <SM7> 6/14/93 kc Roll in Ludwig.
|
|
; <LW5> 4/23/93 MR Add code to check VMInstalled flag inside VM's globals. This
|
|
; fixes bug #1076279. Reviewed by Clinton Bauder
|
|
; <LW4> 3/25/93 MR Remove GetMMUInfoQ. Instead put a hack inside VM to set
|
|
; VMGlobals($B78) to -1 when calling GetPhysical at VM
|
|
; initialization time.
|
|
; <LW3> 3/16/93 MR Created GetMMUInfoQ which is identical to GetMMUInfo except it
|
|
; does not check for VM. This is an EMERGENCY FIX for the
|
|
; RAMDISK/VM bug that broke Ludwig B3. Will be merged in the
|
|
; future with GetMMUInfo. GetMMUInfoQ is only called by
|
|
; MemoryDispatch routines (i.e. LockMemory,GetPhysical etc).
|
|
; <SM6> 2/23/93 kc Fix bug introduced in last check in.
|
|
; <SM5> 2/20/93 SAM Added LogicalToPhysical code for EMMU machines. Placed a few
|
|
; Supports24Bit's around some things. Removed a trap call or two
|
|
; where possible. If it works at all, it should be faster for
|
|
; everyone.
|
|
; <SM4> 2/5/93 SAM Adjusted PDMs temporary Log2Phys. Removed several Gestalt calls
|
|
; from GetReal. Removed all the 24bit stuff for ROM builds of
|
|
; this file in GetReal.
|
|
; <SM3> 10/18/92 CCH Fixed EDiskProtect to abort if an MMU is not present.
|
|
; <SM2> 5/17/92 kc Roll in Horror sources.
|
|
; <SM0> 5/17/92 kc Fix bug in translate040. We were puting phisical address into the wrong register.
|
|
; <H3> 12/12/91 CCH Changed method of checking for VM in GetMMUInfo, since VM calls
|
|
; GetPageDesc after it sets up it's globals, but before taking
|
|
; over the MMU.
|
|
; <H2> 11/14/91 jmp (CCH) Removed redundant physical-to-logical conversion in
|
|
; translate030 routine. Made EDiskProtect return a result. Also
|
|
; removed Gestalt calls in favor of checks of lo-mem. This is
|
|
; necessary since, in ROM, this routine can get called before
|
|
; Gestalt is.
|
|
; <SM2> 2/12/92 JSM Moved this file to MMU folder, keeping all the old revisions;
|
|
; remove some unused equates.
|
|
; <SM1> 12/31/91 RB first checked in
|
|
; <T10> 7/11/91 CCH Fixed a bug in translate040, and saved D1 in GetReal.
|
|
; <T9> 7/9/91 HJR Added overpatch space
|
|
; <T8> 5/29/91 CCH Moved the call to getMMUInfo to ensure it will always be called
|
|
; in 32-bit mode.
|
|
; <T7> 5/24/91 CCH Added call to enter supervisor mode, if necessary, and flushed
|
|
; the ATC in the EDiskProtect routine.
|
|
; <T6> 5/10/91 CCH Added the EDiskProtect routine.
|
|
; <T5> 4/2/91 djw fixed GetRealProc trashing reg D4. This is crashing A/ROSE on
|
|
; Tim.
|
|
; <T4> 3/18/91 CCH Changed check for Gestalt to check for existence of ExpandMem
|
|
; instead of trap address.
|
|
; <T3> 3/18/91 CCH Fixed to not call Gestalt if it's not around. Also made 040
|
|
; translation routine aware of non logical = physical memory.
|
|
; <T2> 1/24/91 CCH Ensured a logical 32-bit mode address for page descriptors on
|
|
; 030's.
|
|
; <T1> 1/24/91 CCH first checked in
|
|
;
|
|
;----------------------------------------------------------------------------------
|
|
|
|
MACHINE MC68030
|
|
PRINT OFF
|
|
LOAD 'StandardEqu.d'
|
|
INCLUDE 'HardwareEqu.a'
|
|
INCLUDE 'MMUEqu.a'
|
|
INCLUDE 'GestaltEqu.a'
|
|
PRINT ON
|
|
|
|
;----------------
|
|
; Misc Equates
|
|
;----------------
|
|
TTEnable EQU 15 ; transparent translation enable bit
|
|
VMTrap EQU $A05C ; VM trap number
|
|
VMGlobals EQU $0B78 ; VM globals ptr
|
|
VMInstalled equ $0101 ; VMInstalled offset inside VM's globals <LW5>
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; GetReal - Translates a logical address into a physical address. The address
|
|
; translation is performed in the MMU mode at the time of the call.
|
|
;
|
|
; input: a0.l = logical address to be translated
|
|
;
|
|
; output: a0.l = corresponding physical address
|
|
; d0.w = result code
|
|
;
|
|
; destroys: a1-a2
|
|
;----------------------------------------------------------------------------------
|
|
GetRealRegs REG d1-d4 ; <t5> djw <t10> cch
|
|
|
|
GetRealVars RECORD 0,decrement
|
|
oldA6 ds.l 1 ; old A6 value
|
|
theTC ds.l 1 ; TC reg (32-bit for 851/030, 16-bit for 040)
|
|
theSRP ds.l 1 ; root pointer of tables to use
|
|
theCRP ds.l 1 ; limit and flags long for 68851 and 68030 MMUs
|
|
myPhys2Log ds.l 1 ; offset to convert root ptr to logical addr
|
|
initShift ds.b 1 ; initial shift bits (IS)
|
|
levelFour ds.b 1 ; width of fourth level offset field (TID)
|
|
levelThree ds.b 1 ; width of third level offset field (TIC)
|
|
levelTwo ds.b 1 ; width of second level offset field (TIB)
|
|
levelOne ds.b 1 ; width of first level offset field (TIA)
|
|
ds.b 1 ; padding
|
|
GetRealSize equ *
|
|
ENDR
|
|
|
|
GetRealProc PROC EXPORT
|
|
WITH GetRealVars,MemDispGlobals
|
|
EXPORT GetPageDescProc
|
|
EXPORT GetMMUInfo
|
|
EXPORT checkTTRegs
|
|
|
|
; Note: We dont support "GetPageDesc Address"
|
|
cmpi.b #EMMU1,MMUType ; Do we have an Emulated MMU?
|
|
bne.s GetRealAddr ; -> No, OSW (old slow way).
|
|
|
|
; Do Logical to Physical Translation for machines with EMMUs. <SM5> SAM
|
|
|
|
MOVEM.L A2/D1/D2,-(SP) ; Save some regs
|
|
|
|
MOVE.L LockMemCt,A2 ; Get the MemDispatch globals
|
|
MOVE.L mdLog2PageSize(A2),D1 ; Get the Log2 page size
|
|
|
|
MOVE.L A0,D0 ; Copy the log addr
|
|
MOVE.L A0,D2 ; Make another copy (Shitty addressing modes)
|
|
|
|
LSR.L D1,D0 ; Turn the Addr into a logical page number
|
|
MOVE.L D0,A0 ; Put the page number back into A0
|
|
|
|
_nkMMUGetPhysicalPage ; Get the physical page in D0
|
|
|
|
LSL.L D1,D0 ; Turn the Phys page number into an Address
|
|
MOVE.L mdPageSize(A2),D1 ; Get the page size
|
|
SUBQ.L #1,D1 ; Turn the log2 page size into a mask
|
|
AND.L D1,D2 ; Mask out the upper 12 bits of the logical addr
|
|
OR.L D2,D0 ; Combine the phys page & logcal offset to make phys addr
|
|
|
|
MOVE.L D0,A0 ; Put the physical address into A0
|
|
MOVEQ #0,D0 ; Signal no error
|
|
|
|
MOVEM.L (SP)+,A2/D1/D2 ; Restore regs
|
|
* BRA.S @Done ; -> Exit
|
|
RTS
|
|
|
|
GetRealAddr
|
|
move.w #getReal,-(sp) ; indicate we want physical address in a0
|
|
bra.s walkTable ; go walk table <SM6>
|
|
|
|
GetPageDescProc
|
|
move.w #getpageDesc,-(sp) ; indicate we want page descriptor ptr in a0
|
|
|
|
walkTable movem.l GetRealRegs,-(sp) ; save working registers
|
|
link a6,#GetRealSize ; allocate some room for our locals
|
|
cmpi.b #PMMU851,MMUType ; check to see if we have an MMU
|
|
bhs.s @haveAnMMU ; IF we do not have an MMU THEN
|
|
move.w #noMMUErr,d0 ; return an error
|
|
bra.s @exitGetReal ; >>EXIT routine
|
|
@haveAnMMU ; ENDIF
|
|
move.l a0,d2 ; get logical address into d2
|
|
jsr GetMMUInfo ; fill our globals with MMU info
|
|
IF Supports24Bit THEN
|
|
move.b MMU32Bit,-(sp) ; save current MMU mode
|
|
bne.s @in32BitMode ; IF we're in 24-bit mode THEN
|
|
moveq #true32b,d0 ; we want to go to 32 bit addressing
|
|
_SwapMMUMode ; switch the MMU mode
|
|
and.l Lo3Bytes,d2 ; clean up the 24-bit address
|
|
bra.s @doTranslation ; go do the translation
|
|
ENDIF
|
|
@in32BitMode ; ELSE
|
|
jsr checkTTRegs ; check transparent translation regs
|
|
bne.s @doTranslation ; IF we matched a TT register THEN
|
|
move.l d2,a0 ; put the original address into a0
|
|
move.l #0,a2 ; return null for page descriptor address
|
|
moveq #noErr,d3 ; return good status
|
|
bra.s @cleanupGetReal ; >>EXIT with easy translation
|
|
; ENDIF
|
|
@doTranslation ; ENDIF
|
|
cmp.b #PMMU040,MMUType ; check MMU type
|
|
beq.s @trans68040 ; IF we're on a 68030 THEN
|
|
jsr translate030 ; do the translation for an 851/030
|
|
bra.s @cleanupGetReal ; ELSE
|
|
@trans68040 jsr translate040 ; do the translation for a 68040
|
|
; ENDIF
|
|
|
|
;------------
|
|
; a2.w = address of page descriptor, if any
|
|
; d3.w = result code
|
|
; a0.l = physical address if successful
|
|
;------------
|
|
@cleanupGetReal
|
|
IF Supports24Bit THEN ; SM is always in 32 bit mode <SM4>
|
|
move.b (sp)+,d0 ; get original MMU mode
|
|
bne.s @returnResult ; IF we were originally in 24-bit mode THEN
|
|
_SwapMMUMode ; swap back to it
|
|
ENDIF
|
|
@returnResult ; ENDIF
|
|
move.w d3,d0 ; return result in d0
|
|
@exitGetReal
|
|
unlk a6 ; restore registers
|
|
movem.l (sp)+,GetRealRegs ; save working registers
|
|
cmp.w #getpageDesc,(sp)+ ; check for page getPageDesc call
|
|
bne.s @getRealDone ; IF this is the getPageDesc call THEN
|
|
move.l a2,a0 ; return page descriptor pointer
|
|
@getRealDone ; ENDIF
|
|
tst.w d3
|
|
@done rts
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; GetMMUInfo - Fills the global area with MMU-specific table information.
|
|
;
|
|
; input: a6.l = pointer to global area
|
|
;
|
|
; output: none (globals are set up)
|
|
;
|
|
; destroys: a0-a1/d0/d3-d4
|
|
;----------------------------------------------------------------------------------
|
|
ISOffset equ 12 ; bit offset into 851/030 TC of IS field
|
|
pageSizeBit equ 14 ; bit number of page size bit in 68040 TC
|
|
|
|
GetMMUInfo
|
|
cmpi.b #EMMU1,MMUType ; Do we have an Emulated MMU
|
|
beq @VMisOn ; -> Yes, just clear the Log2Phys field & Exit
|
|
cmp.b #PMMU040,MMUType ; check MMU type
|
|
beq.s @get040Info ; IF the MMU is an 851/030 THEN
|
|
pmove crp,theCRP(a6) ; get the 64-bit CRP value
|
|
pmove tc,theTc(a6) ; get TC value
|
|
move.l theTc(a6),d4 ; put TC into d4
|
|
move.l #ISOffset,d3 ; get offset into TC of IS field
|
|
bfextu d4{d3:4},d0 ; get IS value
|
|
move.b d0,initShift(a6) ; save IS value in globals
|
|
add.l #4,d3 ; get offset into TC of TIA field
|
|
bfextu d4{d3:4},d0 ; get TIA value
|
|
move.b d0,levelOne(a6) ; save level one index width in globals
|
|
add.l #4,d3 ; get offset into TC of TIB field
|
|
bfextu d4{d3:4},d0 ; get TIB value
|
|
move.b d0,levelTwo(a6) ; save level one index width in globals
|
|
add.l #4,d3 ; get offset into TC of TIC field
|
|
bfextu d4{d3:4},d0 ; get TIC value
|
|
move.b d0,levelThree(a6) ; save level one index width in globals
|
|
add.l #4,d3 ; get offset into TC of TID field
|
|
bfextu d4{d3:4},d0 ; get TID value
|
|
move.b d0,levelFour(a6) ; save level one index width in globals
|
|
bra.s @gotInfo ; go check for log2Phys offset
|
|
@get040Info ; ELSE
|
|
MACHINE MC68040 ; use 68040 instructions
|
|
movec srp,d0 ; get 68040 srp
|
|
move.l d0,theSRP(a6) ; save the root ptr
|
|
move.l #0,theCRP(a6) ; 68040 only has a 32-bit root pointer <T6>
|
|
move.b #7,levelOne(a6) ; 68040 always uses 7 bits for first level
|
|
move.b #7,levelTwo(a6) ; 68040 always uses 7 bits for second level
|
|
move.b #5,levelThree(a6) ; assume 5 bits for 8k pages in third level
|
|
movec tc,d0 ; get 68040 tc
|
|
move.w d0,theTC(a6) ; store it in globals
|
|
btst #pageSizeBit,d0 ; check which page size we're using
|
|
bne.s @not4kPages ; IF we're using 4k pages
|
|
move.b #6,levelThree(a6) ; use 6 bits for 4k pages in third level
|
|
@not4kPages ; ENDIF
|
|
move.b #0,levelFour(a6) ; 68040 never has a fourth level
|
|
move.b #0,initShift(a6) ; 68040 never has an initial shift
|
|
MACHINE MC68030 ; switch back to 68030 instructions
|
|
@gotInfo ; ENDIF
|
|
move.l phys2log,myPhys2Log(a6) ; get our phys2log translation offset (Assume no vm) <SM4>
|
|
|
|
IF not forROM THEN ; Supermario is always 32bit capable <SM4>
|
|
cmp.l #-1,ExpandMem ; is gestalt unimplemented? <T3>
|
|
beq.s @done ; IF gestalt is implemented THEN <T3>
|
|
move.l #gestaltAddressingModeAttr,d0 ; we need to find out 32-bit cleanliness
|
|
_Gestalt ; call Gestalt
|
|
tst.w d0 ; check for errors
|
|
bne.s @VMisOn ; >>EXIT on error
|
|
move.l a0,d0 ; get response in d0
|
|
btst #gestalt32BitCapable,d0 ; check if phys2Log globals exists
|
|
beq.s @VMisOn ; >>EXIT on error
|
|
ENDIF
|
|
|
|
; Some history: Since GetMMUInfo cannot be making lengthy Gestalt calls to determine if VM is on
|
|
; we would (previously) test the lomem where VM puts its globals to see it it had been initialized.
|
|
; A problem arises when VM has saved its globals ptr in VMGlobals but has not yet whacked the MMU
|
|
; tables and someone (VM) calls GetPhysical. An additional flag inside the VMGlobals has been added
|
|
; that is set at the very end of VMs initalization. We now check it to determine if the MMU world
|
|
; has been changed on us. <SM8> SAM
|
|
;
|
|
|
|
; Determine if VM is installed an running <LW5>
|
|
|
|
move.l VMGlobals,d0 ; Has VM installed its globals ptr (is it installed?) <SM4>
|
|
ble.s @done ; -> No. Leave with Phys2Log offset set.
|
|
|
|
move.l d0,a0 ; Globals in. Is VM actually running yet?
|
|
tst.b VMInstalled(a0) ; VM's Gestalt inited? <LW5>
|
|
beq.s @done ; -> Nope, leave the offset alone <LW5>
|
|
|
|
@VMisOn clr.l myPhys2log(a6) ; VM is on. No phys2log translation
|
|
@done rts ; return
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; checkTTRegs - Checks a logical address against the MMU's transparent
|
|
; translation registers. This routine assumes that the
|
|
; instruction and data TT registers contain identical information
|
|
; on the 68040.
|
|
;
|
|
; input: d2.l = logical address to check
|
|
;
|
|
; output: ccr.z is set if the address would be transparently translated
|
|
;
|
|
; destroys: d0-d1/d3-d4
|
|
;----------------------------------------------------------------------------------
|
|
checkTTRegs
|
|
cmp.b #PMMU040,MMUType ; check MMU type
|
|
beq.s @get040Regs ; IF the MMU is an 851/030 THEN
|
|
subq #4,sp ; create room on stack for tt values
|
|
pmove tt0,(sp) ; get tt0 value
|
|
move.l (sp),d0 ; store in d0
|
|
pmove tt1,(sp) ; get tt1 value
|
|
move.l (sp),d1 ; store in d1
|
|
addq #4,sp ; restore stack
|
|
bra.s @checkTTs ; continue with check
|
|
@get040Regs ; ELSE
|
|
MACHINE MC68040 ; use 68040 instructions
|
|
movec dtt0,d0 ; store tt0 in d0
|
|
movec dtt1,d1 ; store tt1 in d1
|
|
MACHINE MC68030 ; switch back to 68030
|
|
@checkTTs ; ENDIF
|
|
btst #TTEnable,d0 ; see if tt0 is on
|
|
beq.s @checkTT1 ; IF tt0 is enabled THEN
|
|
move.l d2,d3 ; make a copy of the logical address
|
|
eor.l d0,d3 ; exclusive OR to leave ones in different bits
|
|
rol.l #8,d3 ; move upper 8-bits into low byte
|
|
swap d0 ; put logical address mask in low byte
|
|
not.b d0 ; invert logical address mask
|
|
and.b d0,d3 ; isolate bits we care about
|
|
beq.s @checkDone ; >>EXIT if we found a match
|
|
@checkTT1 ; ENDIF
|
|
btst #TTEnable,d1 ; see if tt1 is on
|
|
beq.s @notEnabled ; IF tt1 is enabled THEN
|
|
move.l d2,d3 ; make a copy of the logical address
|
|
eor.l d1,d3 ; exclusive OR to leave ones in different bits
|
|
rol.l #8,d3 ; move upper 8-bits into low byte
|
|
swap d1 ; put logical address mask in low byte
|
|
not.b d1 ; invert logical address mask
|
|
and.b d1,d3 ; isolate bits we care about
|
|
bra.s @checkDone ; go exit
|
|
; ELSE
|
|
@notEnabled andi #$fffb,sr ; clear zero bit
|
|
@checkDone ; ENDIF
|
|
rts
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; translate030 - Translates a logical address to its corresponding physical
|
|
; address on a 68030.
|
|
;
|
|
; input: a6.l = pointer to globals
|
|
; d2.l = logical address to translate
|
|
;
|
|
; output: a0.l = physical address
|
|
; a2.l = ptr to page descriptor for translated address
|
|
; d3.w = result code
|
|
;
|
|
; destroys: d0-d1
|
|
;----------------------------------------------------------------------------------
|
|
tcSRE EQU 25 ; SRP Enable in TC for 851/030
|
|
tcFCL EQU 24 ; Function code Lookup in TC for 851/030
|
|
tcEnable030 EQU 31 ; MMU enable bit in TC on 851/030
|
|
pageDesc EQU 1 ; page descriptor
|
|
valid4 EQU 2 ; valid 4 byte
|
|
valid8 EQU 3 ; valid 8 byte
|
|
|
|
transRegs REG d4-d7
|
|
|
|
translate030
|
|
movem.l transRegs,-(sp) ; save working registers
|
|
move.l theSRP(a6),d1 ; get root ptr
|
|
move.l theCRP(a6),d7 ; get limit in d7
|
|
move.b d7,d3 ; get descriptor type in d3
|
|
and.b #3,d3 ; isolate it
|
|
move.l theTC(a6),d0 ; get a copy of the TC in d0
|
|
btst #tcSRE,d0 ; check for SRP mode
|
|
bne @paramErr ; >>EXIT if on
|
|
btst #tcFCL,d0 ; check for FCL mode
|
|
bne @paramErr ; >>EXIT if on
|
|
btst #tcEnable030,d0 ; check if MMU is on
|
|
bne.s @startTranslate ; IF MMU is off THEN
|
|
move.l d2,a1 ; return logical address unchanged
|
|
clr.l d1 ; return null for page descriptor addr
|
|
moveq #noErr,d3 ; return good status
|
|
bra.s @xlatDone ; >>EXIT with physical address
|
|
@startTranslate ; ENDIF
|
|
clr.l d4 ; clear offset into logical address
|
|
move.b initShift(a6),d4 ; add in initial shift
|
|
lea levelOne(a6),a1 ; point a1 at width of first field
|
|
clr.l d5 ; get a clear longword
|
|
move.b (a1)+,d5 ; get width of next field
|
|
|
|
;-----------------
|
|
; a1.l = pointer to width of next field
|
|
; d1.l = current descriptor entry
|
|
; d2.l = logical address to translate
|
|
; d3.b = descriptor type of current descriptor
|
|
; d4.l = offset into logical address of index field
|
|
; d5.l = width of index field
|
|
; d7.l = limit of current descriptor
|
|
;-----------------
|
|
@xlatLoop ; LOOP (to walk an MMU table)
|
|
cmp.b #pageDesc,d3 ; is this a page descriptor?
|
|
beq.s @getPage ; >>BREAK on page descriptor
|
|
bfextu d2{d4:d5},d6 ; get index into next table
|
|
tst.l d7 ; is there a limit for this table?
|
|
beq.s @noLimit ; IF there is a limit THEN
|
|
jsr checkLimit ; check the index against the limit
|
|
bcs.s @paramErr ; >>EXIT on a limit overflow
|
|
@noLimit ; ENDIF
|
|
and.l #$fffffff0,d1 ; remove unused bottom byte
|
|
cmp.b #valid4,d3 ; check for 4-byte descriptor
|
|
bne.s @not4byte ; IF this is a four byte descriptor THEN
|
|
add.l myPhys2Log(a6),d1 ; convert current descriptor to logical addr
|
|
move.l d1,a2 ; get pointer to next table
|
|
lsl.w #2,d6 ; multiple index by four
|
|
add.l d6,a2 ; get address of next descriptor
|
|
move.l (a2),d1 ; get next descriptor
|
|
clr.l d7 ; no limit on this descriptor
|
|
move.b d1,d3 ; get a copy of descriptor
|
|
bra.s @doNext ; look at next descriptor
|
|
@not4byte ; ELSE
|
|
cmp.b #valid8,d3 ; check for 8-byte descriptor
|
|
bne.s @paramErr ; >>EXITLOOP on invalid descriptors
|
|
add.l myPhys2Log(a6),d1 ; convert current descriptor to logical addr
|
|
move.l d1,a2 ; get pointer to next table
|
|
lsl.w #3,d6 ; multiple index by eight
|
|
add.l d6,a2 ; get address of next descriptor
|
|
move.l 4(a2),d1 ; get lower word of next descriptor
|
|
move.l 0(a2),d7 ; get upper word of next descriptor
|
|
move.b d7,d3 ; get a copy of descriptor
|
|
|
|
@doNext ; ENDIF
|
|
add.l d5,d4 ; update d4 to contain number of bytes decoded
|
|
move.b (a1)+,d5 ; get width of next field
|
|
and.b #3,d3 ; isolate descriptor type
|
|
bra.s @xlatLoop ; ENDLOOP
|
|
@getPage
|
|
move.l #32,d5 ; total number of bits in address
|
|
sub.l d4,d5 ; get number of bits not yet decoded
|
|
bfextu d1{0:d4},d0 ; get top bits of address of physical page
|
|
bfextu d2{d4:d5},d6 ; get offset into physical page
|
|
lsl.l d5,d0 ; make a base address out of it
|
|
add.l d6,d0 ; get physical address
|
|
move.l d0,a0 ; put address into a1
|
|
moveq #noErr,d3 ; return no error
|
|
@xlatDone
|
|
movem.l (sp)+,transRegs ; restore registers
|
|
rts
|
|
|
|
@paramErr
|
|
move.w #paramErr,d3
|
|
bra.s @xlatDone
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; translate040 - Translates a logical address to its corresponding physical
|
|
; address on a 68040.
|
|
;
|
|
; input: a6.l = pointer to globals
|
|
; d2.l = logical address to translate
|
|
;
|
|
; output: a0.l = physical address
|
|
; a2.l = ptr to page descriptor for translated address
|
|
; d3.w = result code
|
|
;
|
|
; destroys: d0-d1
|
|
;----------------------------------------------------------------------------------
|
|
tcEnable040 EQU 15 ; MMU enable bit in TC on 68040
|
|
UDTResident EQU 1 ; UDT resident bit in table descriptor
|
|
PDTResident EQU 1 ; PDT field value for a resident page
|
|
PDTIndirect EQU 2 ; PDT field value for an indirect page desc
|
|
|
|
translate040
|
|
movem.l transRegs,-(sp) ; save working registers
|
|
move.l theSRP(a6),d1 ; get root ptr in a2
|
|
move.w theTC(a6),d0 ; get a copy of the TC in d0
|
|
btst #tcEnable040,d0 ; check if MMU is on
|
|
bne.s @startTranslate ; IF MMU is off THEN
|
|
move.l d2,a0 ; return logical address unchanged <SM0>
|
|
clr.l d1 ; return null for page descriptor addr
|
|
moveq #noErr,d3 ; return good status
|
|
bra.s @xlatDone ; >>EXIT with physical address
|
|
; ENDIF
|
|
@startTranslate
|
|
clr.l d4 ; clear offset into logical address
|
|
clr.w d3 ; clear level counter
|
|
clr.l d5 ; get a clear longword
|
|
lea levelOne(a6),a1 ; init pointer to field widths
|
|
;-----------------
|
|
; a1.l = pointer to field width info
|
|
; d1.l = current descriptor entry
|
|
; d2.l = logical address to translate
|
|
; d3.w = level counter
|
|
; d4.l = offset into logical address of index field
|
|
;-----------------
|
|
@walkLoop ; LOOP (to walk 68040 table)
|
|
move.b (a1)+,d5 ; get width of first index field
|
|
move.l #(32-2),d0 ; get total bits in descriptor (table pointer/4)
|
|
sub.l d5,d0 ; get number of significant bits in table ptr
|
|
bfextu d1{0:d0},d1 ; get pointer to next table
|
|
lsl.l d5,d1 ; almost make a base address out of it
|
|
lsl.l #2,d1 ; make a base address out of it
|
|
bfextu d2{d4:d5},d6 ; get index into next table
|
|
lsl.w #2,d6 ; multiple index by four
|
|
add.l d6,d1 ; get address of next descriptor
|
|
add.l myPhys2Log(a6),d1 ; convert pointer to logical addr <T3>
|
|
move.l d1,a2 ; put into an address register
|
|
move.l (a2),d1 ; get next descriptor
|
|
cmp.w #2,d3 ; is this the third level
|
|
beq.s @getPage ; >>EXITLOOP if so
|
|
btst #UDTResident,d1 ; is it resident?
|
|
beq.s @paramErr ; >>EXIT if not
|
|
add.l d5,d4 ; update d4 to contain number of bytes decoded
|
|
add.w #1,d3 ; bump level count
|
|
bra.s @walkLoop ; ENDLOOP
|
|
@getPage
|
|
move.b d1,d0 ; get a copy of the page descriptor
|
|
and.b #3,d0 ; isolate PDT field
|
|
cmp.b #PDTResident,d0 ; is this page resident?
|
|
beq.s @residentPage ; IF it is not resident THEN
|
|
cmp.b #PDTIndirect,d0 ; check for indirect pointer
|
|
bne.s @paramErr ; >>EXIT if invalid
|
|
and.l #$fffffffc,d1 ; clear PDT field from indirect descriptor
|
|
add.l myPhys2Log(a6),d1 ; convert pointer to logical addr <T3>
|
|
move.l d1,a2 ; get address of page descriptor
|
|
move.l (a2),d1 ; get page descriptor
|
|
@residentPage ; ENDIF
|
|
add.l d5,d4 ; update d4 to contain number of bytes decoded <t10> cch
|
|
move.l #32,d5 ; total number of bits in address
|
|
sub.l d4,d5 ; get number of bits not yet decoded
|
|
bfextu d1{0:d4},d0 ; get address of physical page
|
|
bfextu d2{d4:d5},d6 ; get offset into physical page
|
|
lsl.l d5,d0 ; make a base address out of it
|
|
add.l d6,d0 ; get physical address
|
|
move.l d0,a0 ; put address into a0
|
|
moveq #noErr,d3 ; return no error
|
|
@xlatDone
|
|
movem.l (sp)+,transRegs ; restore registers
|
|
rts
|
|
|
|
@paramErr
|
|
move.w #paramErr,d3
|
|
bra.s @xlatDone
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; checkLimit - Checks an index against a limit for an 8-byte descriptor.
|
|
;
|
|
; input: d6.l = index to be checked
|
|
; d7.l = upper word of descriptor
|
|
;
|
|
; output: ccr.c set on invalid index
|
|
; ccr.c clear on valid index
|
|
;
|
|
; destroys: d7
|
|
;----------------------------------------------------------------------------------
|
|
|
|
checkLimit swap d7 ; get limit into low word
|
|
btst #15,d7 ; check type of limit
|
|
bne.s @lower ; IF it is an upper limit THEN
|
|
cmp.w d6,d7 ; compare upper limit
|
|
bra.s @limitExit ; ELSE
|
|
@lower and.w #$7fff,d7 ; remove l/u bit
|
|
cmp.w d7,d6 ; compare lower limit
|
|
@limitExit ; ENDIF
|
|
rts
|
|
|
|
|
|
ENDWITH
|
|
ENDP
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; EDiskProtectPPC - Protects or unprotects the EDisk as specified for PowerPC.
|
|
;
|
|
; input: d0[15:0] = HwPriv selector #8
|
|
; d0[16] = set to protect specified area, clear to unprotect it
|
|
; a0.l = 32-bit base address of area to protect/unprotect
|
|
; a1.l = length of area to protext/unprotect
|
|
;
|
|
; output: a0.l = pointer to the 1st-level table descriptor for the eDisk
|
|
; d0.w = result code
|
|
;
|
|
; destroys: d1/a1
|
|
;----------------------------------------------------------------------------------
|
|
EMMUWrProtBit EQU 16
|
|
EMMUWrProtMask EQU $00010000
|
|
wrBit EQU 2
|
|
|
|
ProtectRegsPPC REG d2-d4
|
|
|
|
EDiskProtectPPC PROC EXPORT
|
|
WITH GetRealVars
|
|
|
|
cmp.b #EMMU1,MMUType ; check to see if we have a PowerPC MMU
|
|
bne @paramErr ; >>EXIT if not
|
|
|
|
movem.l ProtectRegsPPC,-(sp) ; save working registers
|
|
|
|
;——————————————————————————————————
|
|
; PowerPC EDisk Write Protect Code
|
|
;——————————————————————————————————
|
|
move.l #12,d4 ; number of bits in page size
|
|
move.l a1,d2 ; get byte length in d2
|
|
lsr.l d4,d2 ; convert byte length to page count
|
|
addq.l #1,d2 ; always round up by one
|
|
|
|
move.l a0,d1 ; get the base address in d1
|
|
lsr.l d4,d1 ; convert base address to page number
|
|
|
|
move.l d0,d3 ; get a copy of the protect bit into d3
|
|
and.l #EMMUWrProtMask,d3 ; isolate write protect flag
|
|
move.l #EMMUWrProtBit-wrBit,d4 ; number of bits to shift protect bit
|
|
lsr.l d4,d3 ; shift the bit into place so we can OR.L it in
|
|
|
|
@protectLoop ; LOOP (to protect/unprotect pages in Edisk)
|
|
move.l d1,a0 ; Put the page number in A0
|
|
_nkGetPTEntryGivenPage ; Get the 030+ PTE from the nk
|
|
|
|
bclr #wrBit,d0 ; Clear the W bit
|
|
or.l d3,d0 ; Clear/set the write-protect flag
|
|
|
|
move.l d0,a0 ; Move the PTE to A0
|
|
move.l d1,a1 ; Put the page number in A1
|
|
_nkSetPTEntryGivenPage ; Set the 030+ PTE
|
|
|
|
addq.l #1,d1 ; bump the page number by 1
|
|
dbra d2,@protectLoop ; END
|
|
|
|
moveq #noErr,d0 ; return successful
|
|
movem.l (sp)+,ProtectRegsPPC ; restore working registers
|
|
@return rts
|
|
|
|
@paramErr move.w #paramErr,d0 ; return paramErr
|
|
bra.s @return
|
|
|
|
ENDWITH
|
|
|
|
ENDP
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; EDiskProtect - Protects or unprotects the EDisk as specified.
|
|
;
|
|
; NOTE: This algorithm assumes that the Edisk space is the only space
|
|
; mapped by it's 1st level descriptor.
|
|
;
|
|
; input: d0.w = HwPriv selector #8
|
|
; a0.l = 32-bit base address of EDisk
|
|
; a1.w = flag to protect or unprotect Edisk (1=protect)
|
|
;
|
|
; output: a0.l = pointer to the 1st-level table descriptor for the eDisk
|
|
; d0.w = result code
|
|
;
|
|
; destroys: d1/a1
|
|
;----------------------------------------------------------------------------------
|
|
ProtectRegs REG d2-d4/a2
|
|
|
|
EDiskProtect PROC EXPORT
|
|
IMPORT GetMMUInfo
|
|
IMPORT checkTTRegs
|
|
WITH GetRealVars
|
|
|
|
cmp.b #PMMU851,MMUType ; check to see if we have an MMU <SM3>
|
|
blo @bailNoMMU ; >>EXIT if not <SM3>
|
|
|
|
movem.l ProtectRegs,-(sp) ; save working registers
|
|
link a6,#GetRealSize ; allocate some room for our locals
|
|
|
|
;——————————————————————————————————
|
|
; 68K EDisk Write Protect Code
|
|
;——————————————————————————————————
|
|
@noEMMU move.l a0,d2 ; get base address of Edisk
|
|
move.w a1,a2 ; save protect flag in a2
|
|
|
|
Move SR,D0 ; Get and save the SR. <T7>
|
|
Btst #13,D0 ; Are we in Supervisor mode?
|
|
Bne.s @noVM ; Yes? Then don't call _EnterSupervisorMode.
|
|
_EnterSupervisorMode ; Must be in supervisor mode (SR returned in D0).
|
|
@noVM
|
|
move.w d0,-(sp) ; save status register value <T7>
|
|
IF Supports24Bit THEN
|
|
move.b MMU32Bit,-(sp) ; save current MMU mode
|
|
bne.s @in32BitMode ; IF we're in 24-bit mode THEN
|
|
moveq #true32b,d0 ; we want to go to 32 bit addressing
|
|
_SwapMMUMode ; switch the MMU mode
|
|
bra.s @doTranslation ; go do the translation
|
|
@in32BitMode ; ELSE
|
|
ENDIF
|
|
jsr checkTTRegs ; check transparent translation regs
|
|
bne.s @doTranslation ; IF we matched a TT register THEN
|
|
move.l d2,a0 ; put the original address into a0
|
|
moveq #paramErr,d3 ; return bad status
|
|
bra.s @cleanup ; >>EXIT with easy translation
|
|
; ENDIF
|
|
@doTranslation ; ENDIF
|
|
jsr GetMMUInfo ; set up globals <T8>
|
|
clr.l d0 ; clear starting bit value
|
|
clr.l d1 ; clear bit field length
|
|
move.b initShift(a6),d0 ; get bit to start at, with initial shift, if any
|
|
move.b levelOne(a6),d1 ; get bit field length
|
|
bfextu d2{d0:d1},d0 ; get index into 1st-level table
|
|
lsl.l #2,d0 ; convert to a 4-byte entry pointer index
|
|
btst.b #0,theCRP+3(a6) ; is this an 8-byte table?
|
|
beq.s @is4Byte ; IF this is a 8-byte entry table THEN
|
|
lsl.l #1,d0 ; convert to an 8-byte entry pointer index
|
|
@is4Byte ; ENDIF
|
|
add.l theSRP(a6),d0 ; get the physical address of the 1st-level entry
|
|
add.l myPhys2Log(a6),d0 ; convert to a logical address
|
|
move.l d0,a0 ; save in a0
|
|
|
|
;------------
|
|
; Change RAM disk protection
|
|
;------------
|
|
|
|
move.w #noErr,d3 ; return good result if we get here. <Z11><H2>
|
|
bset #writeProtectBit,3(a0) ; set the write-protect bit
|
|
tst.w a2 ; check if protect flag is set
|
|
bne.s @protect ; IF we want to unprotect THEN
|
|
bclr #writeProtectBit,3(a0) ; clear the write-protect bit
|
|
@protect ; ENDIF
|
|
cmp.b #cpu68040,CPUFlag ; check for processor type <T7>
|
|
bne.s @not040 ; IF on a 68040 THEN
|
|
MACHINE MC68040 ;
|
|
pflusha ; flush the ATC regs
|
|
bra.s @cleanup ; ELSE
|
|
MACHINE MC68030 ;
|
|
@not040 jsr ([jCacheFlush]) ; flush caches since they're logical <Z11><H2>
|
|
pflusha ; flush the ATC regs
|
|
; ENDIF <T7>
|
|
|
|
;------------
|
|
; d3.w = result code
|
|
; a0.l = physical address if successful
|
|
;------------
|
|
@cleanup
|
|
IF Supports24Bit THEN
|
|
move.b (sp)+,d0 ; get original MMU mode
|
|
bne.s @skipMMUSwap ; IF we were originally in 24-bit mode THEN
|
|
_SwapMMUMode ; swap back to it
|
|
@skipMMUSwap ; ENDIF
|
|
ENDIF
|
|
move.w (sp)+,d0 ; get status register value <T7>
|
|
move d0,sr ; restore status register <T7>
|
|
move.w d3,d0 ; return result in d0
|
|
@return unlk a6
|
|
movem.l (sp)+,ProtectRegs ; restore working registers
|
|
@bailNoMMU
|
|
rts
|
|
|
|
ENDWITH
|
|
;———————————————————————————————————————————————————————————————————————
|
|
; That's all folks.
|
|
;———————————————————————————————————————————————————————————————————————
|
|
|
|
|
|
ENDP
|
|
|
|
|
|
END
|