mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-21 13:31:15 +00:00
2192 lines
77 KiB
Plaintext
2192 lines
77 KiB
Plaintext
;
|
||
; File: HwPriv.a
|
||
;
|
||
; Contains: This file holds the implementation of the HwPriv trap.
|
||
;
|
||
; Copyright: © 1987-1994 by Apple Computer, Inc. All rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <SM32> 2/7/94 chp Extensive housecleaning in the HwPriv implementations, including
|
||
; the elimination of separate RISC and 68K dispatch tables.
|
||
; <SM31> 12/23/93 PN Take out overpatches on LockMemoryproc, LockMemoryContigousProc
|
||
; and also take out IsUniversal conditionals.
|
||
; <SM30> 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ
|
||
; machines.
|
||
; <SM29> 11/9/93 KW added some eieioSTP macros. Only expands for CygnusX1 ROM
|
||
; <SM28> 10/14/93 pdw <MC3><MC4>.
|
||
; <MC4> 10/11/93 CCH Separated Edisk protect routine into one for PowerPC and one for
|
||
; 68k.
|
||
; <MC3> 10/10/93 CCH Turned on EDisk support for PowerPC machines.
|
||
; <SM27> 9/13/93 SAM Replaced the alternate dispatch table that was inadvertently
|
||
; removed in the last rev.
|
||
; <SM26> 9/1/93 chp DMADispatch is no more. This eliminates the _DMAIntInstall and
|
||
; frees up selector 11. All clients have been modified to use more
|
||
; efficient inline code instead.
|
||
; <SM25> 8/19/93 chp Fix the dispatcher so it won’t barf on a selector of 13. (BHI ->
|
||
; BHS)
|
||
; <SM24> 8/4/93 GMR <RC> Added code to SlotBlockXferCtl to support block transfers
|
||
; for BART machines (PDM,CF).
|
||
; <SM23> 6/14/93 SAM Reenabled the "DMADispatch" selector for PDM.
|
||
; <SM22> 6/14/93 kc Roll in Ludwig.
|
||
; <LW6> 3/24/93 mal Added SlotBlockXferCtl to rom build. For system builds, updated
|
||
; LastVec, changed dispatch to BHS, and added cacheflushes to the
|
||
; self-modifying code.
|
||
; <SM21> 4/22/93 CSS Changed emDMADispGlobs to emDMADispatchGlobals which matches
|
||
; Reality.
|
||
; <SM20> 4/8/93 KW (LW7 KW) fixing Radar bug #1073805 and Radar bug #1075450. If
|
||
; RAM disk was on and using up lots of memory, Finder duplication
|
||
; would hang the System. MacWrite Pro would not install very well
|
||
; either. Routine chkContig was not initializing local var
|
||
; physAddr before use. Also calls to GetRealProc would trash A2
|
||
; which was holding a pointer to Memory Dispatch Globals.
|
||
; <SM19> 4/2/93 GMR Changed the parameters to _DMAIntInstall for PDM, to take a
|
||
; param block ptr in A0. This fixes the problem where a2 was used
|
||
; to pass in the refCon and was getting trashed.
|
||
; <SM18> 3/11/93 SAM Added a refCon field to the PDM DMA irq handler installer.
|
||
; <SM17> 2/20/93 SAM Changed every Page Table Entry/MMU whacking routine to work with
|
||
; EMMUs. Removed a few more slow things from GetPhysical - it
|
||
; shouldn't call any traps any more (rah!). Removed all the TST.W
|
||
; that followed every call to GetRealProc. Updated
|
||
; InitMemoryDispatch to know about EMMUs. Removed the separate
|
||
; code that Unimplements memorydispatch and put its functionality
|
||
; into InitMemDispatch.
|
||
; <LW3> 2/11/93 PW Added passing of drivers' "don't munge heaps" bit into SCSILoad.
|
||
; <SM15> 2/9/93 rab Sync up with Horror. Comments follow.
|
||
; <H2> 7/13/92 NJV <SES> Fixed bug in LockMemory and LockMemoryContiguous that
|
||
; crashed when the page containing the current stack was locked.
|
||
; Fixed it by turning off the data cache between modifying page
|
||
; descriptors and flushing the ATC.
|
||
; <SM14> 2/6/93 RC Fixed last fix (sorry)
|
||
; <SM13> 2/6/93 RC Fixed InitMemDispatchTrap for Quadra
|
||
; <SM12> 2/5/93 SAM Added PDM build specific vectors for MemoryDispatch and have
|
||
; changed the code that unimplements MemDisp if you don't have a
|
||
; known MMU type.
|
||
; <SM11> 12/11/92 SWC Moved the code to disable the MemoryDispatch trap here from
|
||
; StartInit. Put a hasMDU conditional around the EnableExtCache
|
||
; code.
|
||
; <SM10> 11/3/92 SWC Changed SCSIEqu.a->SCSI.a.
|
||
; <SM9> 10/30/92 chp I universalized DMADispatch by making it appear to be
|
||
; unimplemented (return paramErr) on machines with no PSC.
|
||
; DMADispatchNub should not be link patched for non-universal ROMs
|
||
; because it makes a TestFor. SwapSerialClock is broken on
|
||
; non-universal ROMs for exactly this reason.
|
||
; <SM8> 6/19/92 RB Added the selector for the DMADispatch code.
|
||
; <SM7> 5/17/92 kc Roll in Horror changes. Comments follow.
|
||
; <SM6> 4/22/92 kc Changed MemoryDispatch to use word offsets instead of long
|
||
; offsets. Stubed out the routine LockMemoryContiguousProc in
|
||
; order to get the flasher to work.
|
||
; <H11> 7/11/91 CCH Fixed a bug in GetPhysical.
|
||
; <H10> 6/27/91 djw (pdw) Add new selector _WaitForSCSIDevs to wait for SCSI devices
|
||
; and load their drivers. Just added nub code here.
|
||
; <H9> 6/14/91 RP Changed length parameter for FlushCacheRange to be passed in A1
|
||
; instead of D1.
|
||
; <H8> 5/10/91 RP Added selector to HwPriv for flush cache range.
|
||
; <H7> 5/10/91 CCH Added selector to HwPriv for Edisk protection.
|
||
; <H6> 2/18/91 JK Added WriteProtect selectors to MemoryDispatch
|
||
; <H5> 1/24/91 JK Added LockMemory calls that use a page-lock table.
|
||
; <H4> 1/24/91 CCH Moved LastEnt label to include new selectors.
|
||
; <H3> 1/24/91 CCH Significantly modified MemoryDispatch code. Removed translate
|
||
; routine in favor of _GetReal call, modified _GetPhysical to use
|
||
; GetRealProc instead. Added _GetReal and _GetPageDesc selectors.
|
||
; Removed _LockMemory code since it will change anyway. Also added
|
||
; padding at end of file.
|
||
; <H2> 10/2/90 CCH Patched out cache manipulation routines to HwPrivPatch.a.
|
||
; • from HwPrivPatch.a
|
||
; <13> 7/11/91 HJR Change return result from SCSIDrvrs to success/failed.
|
||
; <12> 7/10/91 RP Changed FlushCacheRange to round count to be quad-word aligned.
|
||
; <11> 6/27/91 djw (pdw) Add WaitForSCSIDevs to wait for SCSI devices and load
|
||
; their drivers.
|
||
; <10> 6/25/91 CCH Fixed _SwapDataCache to flush the data cache before disabling it
|
||
; on 68040's. Also jump through jCacheFlush instead of using a
|
||
; CPUSH instruction in _FlushInstructionCache and
|
||
; _SwapInstructionCache.
|
||
; <9> 6/14/91 RP Changed length parameter for FlushCacheRange to be passed in A1
|
||
; instead of D1.
|
||
; <8> 5/10/91 RP Added support to flush a range of cache lines from the 040
|
||
; cache.
|
||
; <7> 5/10/91 CCH Made _ProtectMemory and _UnProtectMemory use the CacheFlush
|
||
; low-mem.
|
||
; <6> 4/22/91 BG Modified 040 cache flushing routines to add a NOP before the
|
||
; CPUSHA <cache(s)>. This is required because of Motorola's xD43B
|
||
; errata item E19. This should be removed when the 040 processor
|
||
; base is D50D. Changed _FlushInstructionCache to jump to
|
||
; ([jCacheFlush]) so that if/when we have to fix/unfix flushing
|
||
; ALL caches, we only have to do it in one place.
|
||
; <5> 4/18/91 BG Changed the 040 part of _FlushInstructionCache to flush both
|
||
; caches. People are probably calling this becasuse they just
|
||
; read in some code/resource/driver/whatever that they want to
|
||
; execute and they want to make sure whatever it is in memory and
|
||
; the instruction cache is synchronized with memory. On the 040,
|
||
; the best way to do this is to flush both caches.
|
||
; <4> 2/18/91 JK Added WriteProtect and UnWriteProtect code
|
||
; <3> 1/24/91 JK MMUSetCacheMode whacks page descriptor in 32-bit mode.
|
||
; <2> 1/24/91 JK Added LockMemory calls that use a page-lock table.
|
||
; <1> 10/3/90 CCH first checked in
|
||
;
|
||
; <4> 3/31/92 FM Merged in <SMN29> changes from Reality.
|
||
; <3> 3/31/92 FM Rolled changes into reality.
|
||
; <2> 2/13/92 RB When I rolled in the new HWPriv selector for Flush cache range,
|
||
; I put the wrong label in the table. That label is used only by
|
||
; the 040 Blockmove, which passes parameters in the stack.
|
||
; Correcting the label will fix the stack.
|
||
; <29> 2/20/92 DTY #1021830: The Regatta version of _HWPriv totally breaks
|
||
; accelerators for 68000 CPUs because a selector number is not put
|
||
; in place for these machines. What winds up happening is on
|
||
; accelerated 68000s, every selector returns an error because
|
||
; _HWPriv thinks it’s an invalid selector. Add a new InstallProc
|
||
; which initializes the valid selector range for the Plus, SE, and
|
||
; Portable ROMs if CPUFlag is a 68020 or 68030.
|
||
; <28> 1/24/92 KC Fix bug introduced in last revision (replace missing semicolon).
|
||
; <27> 1/23/92 KC Added InitMemoryDispatch from Zydeco:HWPrivPatch.a.
|
||
; <26> 1/3/92 RB Added the Flush cache range routine for 68040's from Terror to
|
||
; the ROM build. The system table is unchanged (uses Flush
|
||
; instruction cache instead).
|
||
; <25> 1/3/92 RB Added the EDiskProtection routine to the ROM hwPriv table.
|
||
; Terror changes in HWPrivPatch.a (Terror file) need to be looked
|
||
; at before modifying this file.
|
||
; <24> 11/16/91 DTY More BandAids® to get the ROM build working again. Re-export
|
||
; EnableExtCache (called by StartInit), put back MemoryDispatch
|
||
; code (referenced from DispTable), and add the HWPriv label back
|
||
; (also referenced from DispTable).
|
||
; <23> 10/29/91 SAM This file will now generate the correct code for the ROM build
|
||
; (it even works and doesnt change the System build code - rah).
|
||
; Everything changed in this rev is enclosed in forROM
|
||
; conditionals.
|
||
; <22> 10/29/91 SAM Removed the ‘stupid conditionals’ again. Sorry about that Jeff.
|
||
; <21> 10/28/91 SAM/KSM Rolled in Regatta file. Undid Changes <17>-<20>.
|
||
;
|
||
; 7.0.1 Change History:
|
||
;
|
||
; <6> 7/17/91 SAM Removed the commented out MemoryDispatch patch stuff. Added
|
||
; Paul Wolf's WaitForSCSI to hwPriv's list o' routines.
|
||
; <5> 6/14/91 SAM The hwPriv install procs that set up the ExpandMem set of
|
||
; vectors now only load on II ROMs or IIci ROMs.
|
||
; <3> 5/28/91 SAM Rewrote all of the HwPriv patcher/dispatcher. Now we have
|
||
; relocatable tables of vectors to the hwPriv routines that get
|
||
; installed by the LinkedPatch Loader. Non-TERROR ROM 020/030
|
||
; Machines get their own table (that includes all of the routines
|
||
; in this file) and TERROR machines get a table of zeroes (which
|
||
; means call the ROM). This way all the code in this file is not
|
||
; loaded when not needed and also there is now an easy way to
|
||
; patch the vectors via expandMem.
|
||
; <2> 5/23/91 SAM Rewrote the hwPriv dispatcher. Now more LinkedPatch friendly
|
||
; than ever! Will now jump to ROM on a selector that is out of
|
||
; range. Made the table of hwPrivSelectors a separate resident
|
||
; proc. Added a new macro for the table of selectors called
|
||
; HwPrivSelectorInROM that acts as a placeholder for selectors
|
||
; that are implemented in ROM.
|
||
; <1> 5/22/91 SAM Split off from 7.0 GM sources. Changed hwPriv to call the ROM hwPriv
|
||
; for all selectors that this file doesnt know about.
|
||
;
|
||
; 7.0 Change History:
|
||
;
|
||
; <20> 10/18/91 JSM Get rid of all the stupid conditionals.
|
||
; <19> 9/30/91 JSM Cleanup header, don’t use is32BitClean conditional - all future
|
||
; ROMs will be.
|
||
; <18> 8/30/91 DTY Define isUniversal here since it’s no longer an available
|
||
; feature in BBSStartup.
|
||
; <17> 6/12/91 LN removed #include 'HardwareEqu.a'
|
||
; <16> 3/11/91 gbm stb, bbm: Take out the bogus GetPhysical patch, in preparation
|
||
; of loading the new one.
|
||
; <15> 2/6/91 eh (djw) Fix SwapSerialClock routine to wait for IOP request
|
||
; completion before returning.
|
||
; <14> 1/3/91 gbm (dnf) Fix last addition made by SAM. One of these days, he'll
|
||
; actually build the files he checks in.
|
||
; <13> 1/3/91 SAM Changed the LinkedPatch install conditional so that the patch to
|
||
; _MemoryDispatch for getPhysical is not installed if VM is
|
||
; running.
|
||
; <12> 12/14/90 dba <JDR> get rid of include of VMCalls.a
|
||
; <11> 8/22/90 SAM Adding fixes to GetPhysical so it works correctly with the
|
||
; 8•24•GC.
|
||
; <10> 8/21/90 csd Changed the condition for the MemoryDispatch patch so that it
|
||
; doesn’t install where MemoryDispatch is not implemented. (Elsie)
|
||
; <9> 7/30/90 BG Fixed 040 CACR-related problems.
|
||
; <8> 7/24/90 EMT NEEDED FOR SIXPACK: Fixed 68000 code and eliminated unecessary
|
||
; table.
|
||
; <7> 7/23/90 CCH NEEDED FOR SIXPACK: Patched the GetPhysical selector on
|
||
; _MemoryDispatch on $67c based ROMs to return physical addresses
|
||
; for non-RAM logical addrs.
|
||
; <6> 7/21/90 BG Removed unnecessary EclipseNOPs. Also changed <xyz>s to <5>s
|
||
; (yer welcome, Carl).
|
||
; <5> 7/19/90 CCH NEEDED FOR SIXPACK: Rolled in SwapSerialClock selector from PTCH
|
||
; file and converted to linked patches.
|
||
; <4> 6/19/90 CCH Changed two occurences of CINVA IC to CPUSHA BC to hopefully
|
||
; prevent incompatibility problems with the 68040 copyback cache
|
||
; mode. Also added some NOPs for flaky 68040's.
|
||
; <3> 2/18/90 BG Added 040 versions of the machine-dependent routines for
|
||
; manipulating the I&D caches.
|
||
; <2> 1/11/90 CCH Added include of “HardwarePrivateEqu.a”.
|
||
; <2.1> 7/16/89 CSL cleaned up lockMemoryCont, GetPhysical, Translate.
|
||
; <2.0> 6/30/89 CSL disable data cache and increment LockMemCt when LockMemory and
|
||
; LockMemoryContiguous is performed successfully, increment
|
||
; lockMemCt when UnLockMemory is called, if LockMemCt becomes
|
||
; zero, enable data cache. Also removed selector for
|
||
; GetSystemMemoryInfo.
|
||
; <1.9> 6/15/89 CSL Added FlushExtCache selector.
|
||
; <1.8> 5/31/89 CSL Use register D2 for error code for chkcontiguous.
|
||
; <1.7> 5/30/89 GGD Added missing ".b" to DisableExtCache RBV access. Added code to
|
||
; return noErr for EnableExtCache and DisableExtCache.
|
||
; <1.6> 5/30/89 CSL For getPhysical and LockMemoryContiguous, always switched to 32
|
||
; bit
|
||
; <1.5> 5/24/89 GGD Converted to feature based conditionals, No code changes.
|
||
; <1.4> 5/16/89 CSL changed using EQU Frmbufbase to lowMem Phys2log.
|
||
; <1.3> 4/28/89 CSL Changed Interface for GetPhysical.
|
||
; <1.2> 4/17/89 CSL update _MemoryDispatch with VM spec.
|
||
; <1.1> 2/28/89 CSL Added MemoryDispatch trap for address translation for hafmac.
|
||
; <1.0> 2/24/89 rwh rolled in today from Mac IIx ROM
|
||
;
|
||
|
||
|
||
MACHINE MC68030
|
||
|
||
PRINT PUSH,OFF
|
||
LOAD 'StandardEqu.d'
|
||
INCLUDE 'hardwarePrivateEqu.a'
|
||
INCLUDE 'GestaltEqu.a'
|
||
INCLUDE 'InternalMacros.a'
|
||
INCLUDE 'UniversalEqu.a'
|
||
INCLUDE 'MMUEqu.a'
|
||
INCLUDE 'IOPEqu.a'
|
||
INCLUDE 'LinkedPatchMacros.a'
|
||
INCLUDE 'SCSI.a'
|
||
INCLUDE 'PowerPrivEqu.a'
|
||
INCLUDE 'DockingEqu.a'
|
||
PRINT POP
|
||
|
||
|
||
|
||
;----------
|
||
;
|
||
; HwPrivSelector Macro
|
||
;
|
||
;----------
|
||
|
||
MACRO
|
||
HwPrivSelector &addr
|
||
IMPORT &addr
|
||
dc.w &addr-Vects ; OFFSET of routine
|
||
ENDM
|
||
HwVecSize EQU 2
|
||
|
||
|
||
;----------
|
||
;
|
||
; HWPriv (_HWPriv trap)
|
||
;
|
||
; The _HWPriv trap was created to export some low level hardware control capabilites to
|
||
; the (user mode) world at large. A selector passed in D0 determines which specific
|
||
; transistor to twiddle.
|
||
;
|
||
; The selector mechanism makes the trap expandable - as we add more strange hardware,
|
||
; we can define new selectors (and write new routines) to control it. Each selector
|
||
; is almost like a new trap. If we want to be really gross, the parameter passing
|
||
; conventions can be different for each selector. At the expense of a non-uniform
|
||
; interface to the trap, this avoids having to invent some cumbersome huge extendable
|
||
; parameter block that covers all present and future possibilities.
|
||
;
|
||
; The selectors currently defined are:
|
||
;
|
||
; 0 - SwapInstructionCache (turn off/on the 020/030/... instruction cache)
|
||
; 1 - FlushInstructionCache
|
||
; 2 - SwapDataCache (turn off/on the 030/... data cache)
|
||
; 3 - FlushDataCache
|
||
; 4 - EnableExtCache
|
||
; 5 - DisableExtCache
|
||
; 6 - FlushExtCache
|
||
; 7 - SwapSerialClock
|
||
; 8 - EDiskProtect (in TERROR ROM)
|
||
; 9 - FlushRange (in TERROR ROM)
|
||
; 10 - WaitForSCSIDevs (in TERROR ROM)
|
||
; 11 - UnusedSelector (in SuperMario)
|
||
; 12 - SlotBlockXferCtl (in SuperMario)
|
||
; 13 - GetENetID (in SuperMario/KAOS ROM)
|
||
;
|
||
; Entry:
|
||
; D0 (low order word) holds routine selector
|
||
; A0 holds parameter (optional for some selectors)
|
||
; D1-D2/A1 saved by trap dispatcher
|
||
;
|
||
; Exit:
|
||
; D0 (long) zero if all went well, non-zero if selector out of range
|
||
; A0 (long) returned value (optional for some selectors)
|
||
;
|
||
; Destroys: D0, plus whatever registers the selector routines use
|
||
;
|
||
;----------
|
||
|
||
HWPriv PROC EXPORT ; KISS (Keep it simple and easy to patch)
|
||
|
||
bra.b HWPrivSwitch
|
||
|
||
ALIGN 8
|
||
Vects ;table of offsets to selector routines
|
||
HwPrivSelector SwapICache ; 0 SwapICache
|
||
HwPrivSelector FlushICache ; 1 FlushICache
|
||
HwPrivSelector SwapDCache ; 2 SwapDCache
|
||
HwPrivSelector FlushDCache ; 3 FlushDCache
|
||
HwPrivSelector EnableExtCache ; 4 EnableExtCache
|
||
HwPrivSelector DisableExtCache ; 5 DisableExtCache
|
||
HwPrivSelector FlushExtCache ; 6 FlushExtCache
|
||
HwPrivSelector SwapSerialClock ; 7 SwapSerialClock
|
||
HwPrivSelector ProtectEDisk ; 8 Protect/Unprotect EDisk
|
||
HwPrivSelector FlushCRange ; 9 FlushCRange
|
||
HwPrivSelector WaitForSCSIDevs ; 10 WaitForSCSIDevs
|
||
HwPrivSelector ReturnErr ; 11 Unused
|
||
HwPrivSelector SlotBlockXferCtl ; 12 - enable block xfers to a slot
|
||
HwPrivSelector GetENetID ; 13 - Get Ethernet ID from serial ROM
|
||
LastVec
|
||
|
||
ALIGN 8
|
||
HWPrivSwitch
|
||
cmpi.w #(LastVec-Vects)/HwVecSize,d0 ; check if selector in range
|
||
bhs ReturnErr ; abort if it’s not a valid selector
|
||
move.w Vects(d0*HwVecSize),d0 ; get offset to selector’s routine
|
||
jmp Vects(d0) ; go to the routine
|
||
|
||
ENDPROC
|
||
|
||
|
||
ReturnErr PROC ENTRY
|
||
|
||
move.l #hwParamErr,d0 ; abort: return error code
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; SwapICache (_HWPriv Selector 0)
|
||
;
|
||
; This routine turns the 020/030/040 instruction cache off or on. If the cache is being
|
||
; turned on, it is also flushed.
|
||
;
|
||
; Entry:
|
||
;
|
||
; A0 (long) - zero to turn instruction cache off, non-zero to turn it on
|
||
;
|
||
; Exit:
|
||
;
|
||
; A0 (long) - has previous state of instruction cache (zero = off, non-zero = on)
|
||
;
|
||
; Destroys: D1, D2
|
||
;
|
||
;----------
|
||
|
||
SwapICache PROC EXPORT
|
||
|
||
TestFor has68kEmulator ; are we on a PPC-based machine?
|
||
bnz.b @EmuFake
|
||
|
||
cmp.b #cpu68040,CpuFlag ; are we on an 040-based machine?
|
||
bhs.s @handle040
|
||
|
||
@handle030
|
||
movec CACR,d0 ; get current cache state
|
||
bfextu d0{31:1},d1 ; get cache enable bit into LSbit of d1
|
||
bclr #CACR_EI_020_030,d0 ; assume we're disabling (clear enable flag)
|
||
move.l a0,d2 ; see what we want to do
|
||
beq.s @SetCACR ; if we want to turn it on
|
||
ori.b #((1<<CACR_EI_020_030)|\ ; set enable,
|
||
(1<<CACR_CI_020_030)),d0 ; flush I-Cache flags
|
||
bra.s @SetCACR ; go set the desired cache state
|
||
|
||
@handle040
|
||
movec CACR,d0 ; get current cache state
|
||
bfextu d0{16:1},d1 ; get cache enable bit into LSbit of d1
|
||
bclr #CACR_IE_040,d0 ; assume we're disabling
|
||
move.l a0,d2 ; are we enabling the I-Cache?
|
||
beq.s @SetCACR ; NO ... go turn in OFF
|
||
jsr ([jCacheFlush]) ; invalidate both caches
|
||
bset #CACR_IE_040,d0 ; set IE=1 to enable I-Cache
|
||
|
||
@SetCACR
|
||
move.l d1,a0 ; save the previous I-Cache state
|
||
movec d0,CACR ; set the Cache to desired state
|
||
moveq #noErr,d0 ; signal all's well
|
||
rts
|
||
|
||
@EmuFake lea 1,a0 ; do nothing and report that caches were enabled
|
||
moveq #noErr,d0
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; FlushICache (_HWPriv Selector 1)
|
||
;
|
||
; This routine flushes the 020/030/040...'s instruction cache.
|
||
;
|
||
; On 040s, it also causes a flush of the data cache. This is because previous uses
|
||
; of _FlushInstructionCache were to make sure that memory and caches were in sync if
|
||
; either self-modifying or newly read-in code (from wherever).
|
||
;
|
||
; Destroys: none
|
||
;
|
||
;----------
|
||
|
||
FlushICache PROC EXPORT
|
||
|
||
TestFor has68kEmulator
|
||
bnz.b @Coherent
|
||
|
||
jsr ([jCacheFlush]) ; invalidate both caches
|
||
|
||
@Coherent
|
||
moveq #noErr,d0 ; signal all's well
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; SwapDCache (_HWPriv Selector 2)
|
||
;
|
||
; This routine turns the 020/030/040... data cache off or on. If the cache is being
|
||
; turned on, it is also flushed.
|
||
;
|
||
; Entry:
|
||
;
|
||
; A0 (long) - zero to turn data cache off, non-zero to turn it on
|
||
;
|
||
; Exit:
|
||
;
|
||
; A0 (long) - has previous state of data cache (zero = off, non-zero = on)
|
||
;
|
||
; Destroys: D1, D2
|
||
;
|
||
;----------
|
||
|
||
SwapDCache PROC EXPORT
|
||
|
||
TestFor has68kEmulator ; are we on a PPC-based machine?
|
||
bnz.b @EmuFake
|
||
|
||
cmp.b #cpu68040,CpuFlag ; are we on an 040-based machine?
|
||
bhs.s @handle040
|
||
|
||
@handle030
|
||
movec CACR,d0 ; get current cache state
|
||
bfextu d0{23:1},d1 ; get cache enable bit into LSbit of d1.l
|
||
bclr #CACR_ED_030,d0 ; assume we're disabling (clear enable flag)
|
||
move.l a0,d2 ; see what we want to do
|
||
beq.s @SetCACR ; if we want to turn it on
|
||
ori.w #((1<<CACR_ED_030)|\ ; set enable,
|
||
(1<<CACR_CD_030)),d0 ; flush D-Cache flags
|
||
bra.s @SetCACR ; set cache to the desired state
|
||
|
||
@handle040
|
||
movec CACR,d0 ; get current D-Cache state
|
||
bfextu d0{0:1},d1 ; put cache enable bit into LSbit of d1.l
|
||
bset #CACR_DE_040,d0 ; assume we're enabling
|
||
move.l a0,d2 ; check what we are really doing
|
||
bne.s @SetCACR ; if we are disabling the caches
|
||
MACHINE MC68040 ;
|
||
nop ; required by D43B CPUSHA DC errata item
|
||
cpusha dc ; push dirty D-Cache data items to memory
|
||
MACHINE MC68030 ;
|
||
bclr #CACR_DE_040,d0 ; set DE=0 to disable D-Cache
|
||
|
||
@SetCACR
|
||
move.l d1,a0 ; save the previous D-Cache state
|
||
movec d0,CACR ; update D-Cache status value
|
||
moveq #noErr,d0 ; signal all's well
|
||
rts
|
||
|
||
@EmuFake lea 1,a0 ; do nothing and report that caches were enabled
|
||
moveq #noErr,d0
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; FlushDCache (_HWPriv Selector 3)
|
||
;
|
||
; This routine flushes the 030/040...'s data cache. It has no effect on an 020.
|
||
;
|
||
; Destroys: none
|
||
;
|
||
;----------
|
||
|
||
FlushDCache PROC EXPORT
|
||
|
||
TestFor has68kEmulator ; are we on a PPC-based machine?
|
||
bnz.b @flushDCacheExit
|
||
|
||
cmp.b #cpu68040,CpuFlag ; are we on an 040-based machine?
|
||
bhs.s @handle040
|
||
|
||
@handle030
|
||
movec CACR,d0 ; get current cache state
|
||
bset #CACR_CD_030,d0 ; set 'clear data cache' flag
|
||
movec d0,CACR ; set cache state
|
||
bra.s @flushDCacheExit
|
||
|
||
@handle040
|
||
MACHINE MC68040
|
||
nop ; required by DD43B CPUSHA DC errata item
|
||
cpusha dc ; flush the D-Cache
|
||
MACHINE MC68030
|
||
|
||
@flushDCacheExit
|
||
moveq #noErr,d0 ; signal all's well
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; EnableExtCache (_HWPriv Selector 4)
|
||
;
|
||
; This routine turns the external Cache on.
|
||
; Entry: none
|
||
; EXit: none
|
||
;
|
||
;----------
|
||
|
||
EnableExtCache PROC EXPORT
|
||
|
||
tst.l DockingGlobals ; have traps been initialized yet?
|
||
beq.s @noDockMgr ; -> nope, just blow it all off
|
||
subq #4,sp ; make room for result
|
||
move.l #dockCacheControl,-(sp) ; cache control selector
|
||
move.l #dockCacheOn,-(sp) ; indicate the cache should be turned on
|
||
_DockingDispatch
|
||
addq #4,sp ; remove the result (assume success)
|
||
|
||
IF hasMDU THEN
|
||
bra.s @extCacheDone
|
||
@noDockMgr
|
||
|
||
movea.l UnivInfoPtr,a0 ; point to the product info
|
||
cmpi.b #DecoderKinds.MDUDecoder,\
|
||
ProductInfo.DecoderKind(a0) ; see if we have an MDU
|
||
bne.s @noMDU ; if not, nothing to enable
|
||
|
||
; enable the external MDU cache as follows:
|
||
; Toggle the RvCFlush bit 1 - 0 - 1, to flush the cache
|
||
; set the RvCDis bit to 0, to enable the cache (special restriction, can't access cacheable
|
||
; memory for some amount of time after enableing the cache. By executing this code in
|
||
; a loop, it will be executing out of the instruction cache, and not accessing memory)
|
||
|
||
movea.l VIA2RBV,a0 ; get the VIA2 or RBV base address
|
||
lea vBufB|RvDataB(a0),a0 ; point to the cache register
|
||
|
||
move.w sr,-(sp) ; save int mask
|
||
ori.w #HiIntMask,sr ; disable all interrupts
|
||
|
||
moveq.l #~(1<<RvCFlush),d0 ; mask to clear flush bit (active low)
|
||
and.b (a0),d0 ; get the register, clear flush
|
||
btst.l #RvCDis,d0 ; test the cache disable bit (active high)
|
||
beq.s @flushDone ; if already enabled, nothing to do
|
||
move.b d0,(a0) ; flush the cache
|
||
bset.l #RvCFlush,d0 ; setup to un-flush the cache
|
||
|
||
@loop move.b d0,(a0) ; 1st time, un-flush, 2nd time, enable cache
|
||
move.b (a0),(a0) ; kill time accessing the RBV/VIA2
|
||
move.b (a0),(a0) ; kill some more time
|
||
bclr.l #RvCDis,d0 ; enable the cache (active high)
|
||
bne.s @loop ; loop if first time through
|
||
|
||
@flushDone move.w (sp)+,sr ; restore int mask
|
||
@noMDU
|
||
|
||
ELSE
|
||
@noDockMgr
|
||
|
||
ENDIF
|
||
|
||
@extCacheDone
|
||
moveq #noErr,d0 ; signal all's well
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; DisableExtCache (_HWPriv Selector 5)
|
||
;
|
||
; This routine turns the external Cache off.
|
||
; Entry: none
|
||
; EXit: none
|
||
;
|
||
;----------
|
||
|
||
DisableExtCache PROC EXPORT
|
||
|
||
tst.l DockingGlobals ; have traps been initialized yet?
|
||
beq.s @noDockMgr ; -> nope, just blow it all off
|
||
subq #4, sp ; make room for result
|
||
move.l #dockCacheControl, -(sp) ; cache control selector
|
||
move.l #dockCacheOff, -(sp) ; indicate the cache should be turned on
|
||
_DockingDispatch
|
||
addq #4,sp ; remove the result (assume success)
|
||
|
||
IF hasMDU THEN
|
||
bra.s @extCacheDone
|
||
@noDockMgr
|
||
|
||
movea.l UnivInfoPtr,a0 ; point to the product info
|
||
cmpi.b #DecoderKinds.MDUDecoder,\
|
||
ProductInfo.DecoderKind(a0) ; see if we have an MDU
|
||
bne.s @noMDU ; if not, nothing to enable
|
||
|
||
movea.l VIA2RBV,a0 ; get the VIA2 or RBV base address
|
||
lea vBufB|RvDataB(a0),a0 ; point to the cache register
|
||
ori.b #(1<<RvCDis),(a0) ; disable cache
|
||
@noMDU
|
||
|
||
ELSE
|
||
@noDockMgr
|
||
|
||
ENDIF
|
||
|
||
@extCacheDone
|
||
moveq #noErr,d0 ; signal all's well
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; FlushExtCache (_HWPriv Selector 6)
|
||
;
|
||
; This routine flushes the external Cache by disabling external Cache and
|
||
; enabling external cache.
|
||
; Entry: none
|
||
; EXit: none
|
||
;
|
||
;----------
|
||
|
||
FlushExtCache PROC EXPORT
|
||
|
||
JSR DisableExtCache ; call routine directly
|
||
JSR EnableExtCache ; call routine directly
|
||
RTS
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; SwapSerialClock (_HWPriv Selector 7)
|
||
;
|
||
; This routine enables or disables external clocking to the SCC. The external clock
|
||
; comes to the SCC through the RTxC signal, which is connected to the GPi pin on the
|
||
; serial port connector. External clocking is currently switched by the vSync bit
|
||
; on VIA 1, or through a call to the SCC IOP. The interface is left open-ended to
|
||
; allow external clock control on any number of SCC's or serial ports. Current CPU's
|
||
; only support one SCC and port A external clocking.
|
||
;
|
||
; NOTE: this call is supported for the fx in BYPASS mode only. (although we still call
|
||
; the IOP to execute the call)
|
||
;
|
||
; Entry:
|
||
; D0.L = routine selector
|
||
; A0.L = <SCC number>.B <port number>.B <enable/disable ext clock>.W
|
||
; bits 31-24: SCC number currently 0 for future expansion
|
||
; 23-16: port number 0=port A, 1=port B,... for future expansion
|
||
; 15-0 : 0=internal clocking, 1=external clocking
|
||
; Exit:
|
||
; D0.L = zero if good, -1 if error
|
||
; A0.L = <SCC number>.B <port number>.B <last state of external clock>.W
|
||
;
|
||
;----------
|
||
|
||
SwapSerialClock PROC EXPORT
|
||
|
||
moveq #-1,d0 ; assume an error return
|
||
move.l a0,d1 ; d1 will hold the return value
|
||
move.l d1,d2
|
||
swap d2 ; d2 = <external clk value>.w <scc>.b <port>.b
|
||
tst.w d2 ; check SCC and port number
|
||
bne ReturnErr ; only port A supported
|
||
|
||
TestFor SCCIOPExists
|
||
beq.w @BuiltinSCC ; no IOP hardware
|
||
btst.b #0,SCCIOPFlag ; are we in bypass mode ?
|
||
beq @Done ; no, so can't make the call, so exit
|
||
|
||
; Call SCC IOP kernel to set the external clock mode.
|
||
|
||
WITH IOPRequestInfo, SCCCtlMsg, SCCCtlReply
|
||
|
||
@IOPSCC
|
||
suba.w #irReqInfoSize+SCCCtlMsgSize,sp ; SP = ptr to request msg
|
||
|
||
lea irIOPNumber(sp),a0
|
||
move.b #SCCIOPNum,(a0)+ ; set iop number
|
||
assert irRequestKind=(irIOPNumber+1)
|
||
move.b #irSendXmtMessage,(a0)+ ; a send xmit message kind
|
||
assert irMsgNumber=(irRequestKind+1)
|
||
assert irMessageLen=(irMsgNumber+1)
|
||
assert irReplyLen=(irMessageLen+1)
|
||
assert irReqActive=(irReplyLen+1)
|
||
move.l #(1<<24)+\ ; irMsgNumber = 1
|
||
(SCCCtlMsgSize<<16)+\ ; irMessageLen = SCCCtlMsgSize
|
||
(SCCCtlMsgSize<<8)+\ ; irReplyLen = SCCCtlMsgSize
|
||
(0),(a0)+ ; irReqActive = 0
|
||
|
||
movea.l sp,a1
|
||
adda.w #irReqInfoSize,a1 ; point to SCCCtlMsg
|
||
assert irMessagePtr=(irReqActive+1)
|
||
move.l a1,(a0)+ ; irMessagePtr = SCCCtlMsg
|
||
assert irReplyPtr=(irMessagePtr+4)
|
||
move.l a1,(a0)+ ; irReplyPtr = SCCCtlMsg
|
||
assert irHandler=(irReplyPtr+4)
|
||
clr.l (a0) ; irHandler = nil (no completion routine)
|
||
move.b #6,msgNum(a1) ; message to change external clocking
|
||
move.b d2,Driver(a1) ; set port to change
|
||
swap d2 ; get ext clk state in low word
|
||
move.b d2,GPI(a1) ; set state of external clocking
|
||
|
||
movea.l sp,a0 ; a0 = ptr IOPRequestInfo
|
||
_IOPMsgRequest
|
||
bne.s @1 ; error in request
|
||
|
||
@waitloop tst.b irReqActive(a0) ; wait for request to complete
|
||
bne.s @waitloop
|
||
|
||
movea.l irReplyPtr(a0),a0 ; get reply
|
||
move.b errNum(a0),d0 ; error code from reply
|
||
@1 adda.w #irReqInfoSize+SCCCtlMsgSize,sp
|
||
bra.s @Done
|
||
|
||
ENDWITH
|
||
|
||
; Bang on the VIA vSync bit directly.
|
||
|
||
@BuiltinSCC
|
||
TestFor VIA1Exists
|
||
beq.s @Done ; no via - nothing to do now
|
||
|
||
tst.w d1 ; get state to set from low word
|
||
snz d2 ; set or clear D2.B accordingly
|
||
|
||
movea.l VIA,a1
|
||
clr.w d1
|
||
btst #vSync,vBufA(a1) ; test current value
|
||
snz d1 ; set or clear D1.B accordingly
|
||
|
||
eor.b d1,d2 ; setting already the same as old ?
|
||
beq.s @FixResult ; already set to correct state - done
|
||
bchg #vSync,vBufA(a1) ; change the clock setting
|
||
|
||
@FixResult neg.b d1
|
||
moveq #noErr,d0 ; set good error return
|
||
|
||
; Done - return the old external clock state.
|
||
; To do: This does not return valid information in the IOP case!
|
||
; To do: This does not return valid information when VIA1 is missing!
|
||
|
||
@Done movea.l d1,a0 ; return previous state in A0
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; ProtectEDisk (_HWPriv Selector 8)
|
||
;
|
||
; This stub merely selects what version of the primitive routine to use.
|
||
; EDisk protection is handled differently on 68K Macs than it is on PPC Macs.
|
||
;
|
||
;----------
|
||
|
||
ProtectEDisk PROC EXPORT
|
||
|
||
IMPORT EDiskProtect, EDiskProtectPPC
|
||
|
||
TestFor has68kEmulator ; are we on a PPC-based machine?
|
||
bnz.b @UsePPCVersion
|
||
|
||
@Use68KVersion
|
||
bra EDiskProtect
|
||
|
||
@UsePPCVersion
|
||
bra EDiskProtectPPC
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; FlushCRange (_HWPriv Selector 9)
|
||
;
|
||
; This routine flushes a range of addresses from the 040 caches
|
||
; (or the whole cache on non 040 machines).
|
||
;
|
||
; Entry:
|
||
;
|
||
; A0 (long) - Starting logical address.
|
||
; A1 (long) - Count.
|
||
;
|
||
; Exit:
|
||
;
|
||
; Destroys: D1, D2
|
||
;
|
||
; FlushCRangeForBM is glue for BlockMove
|
||
;
|
||
;----------
|
||
|
||
FlushCRangeForBM PROC EXPORT
|
||
EXPORT FlushCRange
|
||
|
||
Move.l (Sp)+,A0 ; Address.
|
||
Move.l (Sp)+,A1 ; Count.
|
||
|
||
FlushCRange
|
||
TestFor has68kEmulator ; are we on a PPC-based machine?
|
||
bnz @EmuFake
|
||
|
||
Cmpi.b #cpu68040,CPUFlag ; Are we less than an 040?
|
||
Blo @Non040 ; Yes? Then do an 030 style flush.
|
||
|
||
MACHINE MC68040
|
||
Adda.w #15,A1 ; Round length.
|
||
Move.l A1,D1 ; Length in D1
|
||
And.w #$FFF0,D1 ; Round to nearest cache line.
|
||
|
||
Move SR,D0 ; Get and save the SR.
|
||
Btst #13,D0 ; Are we in Supervisor mode?
|
||
Bne.s @CheckCnt ; Yes? Then don't call _EnterSupervisorMode.
|
||
Moveq #8,D0 ; Selector for "EnterSupervisorMode".
|
||
_DebugUtil ; Must be in supervisor mode (SR returned in D0).
|
||
|
||
@CheckCnt Cmpi.l #$0C00,D1 ; Less than 3/4 the size of the cache? ***Tune***
|
||
Blo.s @KillInterrupts ; Yes? Then flush line by line.
|
||
@0 Nop ; Sync up pipeline. ***TEMP***
|
||
Cpusha BC ; No? Then flush everything and be done with it.
|
||
Bra.s @Exit1 ; Outta here.
|
||
|
||
@KillInterrupts
|
||
Movem.l D3-D5/A0-A1,-(Sp) ; Save registers.
|
||
Ori.w #$0700,SR ; Disable interrupts till we exit.
|
||
Moveq #5,D2 ; Set the DFC value.
|
||
Movec D2,DFC ; Set the Destination Function Code to 5.
|
||
|
||
Move.w #$D000,D4 ; Build a mask based on the page size from bit #14 of TC.
|
||
Movec TC,D2 ; Get Translation Control (Bit 14 set:8K, clear:4K).
|
||
Lsr.w #2,D2 ; Move the TC bits (enable/page size) over 2
|
||
Eor.w D2,D4 ; Eor in the bits to make the mask ($F000 for 4K, $E000 for 8K).
|
||
Move.w D4,D5 ; Copy physical mask.
|
||
Not.w D5 ; Make 1's complement mask for logical address.
|
||
|
||
@LetsGetPhysical
|
||
Move.l A0,A1 ; Set scratch register (A1) with logical address.
|
||
Ptestr (A1) ; Get translated physical address.
|
||
Movec MMUSR,D3 ; Address is in high 19 or 20 bits of MMUSR.
|
||
|
||
And.w D4,D3 ; Clear off bottom n bits.
|
||
Move.w A1,D2 ; Logical address in D2.
|
||
And.w D5,D2 ; Grab low n bits of original address.
|
||
Or.w D2,D3 ; Build complete physical address.
|
||
Move.l D3,A1 ; Physical address.
|
||
|
||
Eor.w D5,D2 ; Calculate number of bytes left in this page.
|
||
Addq.w #1,D2
|
||
Sub.w D2,D1 ; Subtract from total buffer size.
|
||
Bpl.s @FlushIt ; Still pos? Then D2 has correct byte count.
|
||
Add.w D1,D2 ; No? Then almost done…correct the count.
|
||
|
||
@FlushIt Adda.w D2,A0 ; Logical address of next page.
|
||
Asr.w #4,D2 ; Lines to flush.
|
||
Cmp.w #16,D2 ; More than 16 lines? ***TUNE***
|
||
Blt.s @LineByLine ; No? Then do it line by line.
|
||
|
||
Nop ; Sync up pipeline. ***TEMP***
|
||
Cpushp BC,(A1) ; Invalidate the whole page.
|
||
Bra.s @NextPage ; Do next page.
|
||
|
||
@LineByLine Cpushl BC,(A1) ; Invalidate the cache line.
|
||
Add.w #$10,A1 ; Bump logical address to the next cache line.
|
||
Dbra D2,@LineByLine ; Loop till page is done.
|
||
|
||
@NextPage Tst.w D1 ; Are we done?
|
||
Bgt.s @LetsGetPhysical ; No? Then do next page.
|
||
|
||
@Exit Movem.l (Sp)+,D3-D5/A0-A1 ; Restore registers.
|
||
@Exit1 Move D0,SR ; Restore status register (interrupts and user/supervisor mode).
|
||
Moveq #noErr,D0 ; No Error.
|
||
Rts ; Adios.
|
||
MACHINE MC68030
|
||
|
||
@Non040 Movec CACR,D0 ; Cache control register.
|
||
Bset #3,D0 ; Set flag to flush instruction cache.
|
||
Movec D0,CACR ; Flush it.
|
||
Moveq #noErr,D0 ; No Error.
|
||
Rts ; Adios.
|
||
|
||
@EmuFake moveq #noErr,d0
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; WaitForSCSIDevs (_HWPriv Selector 10)
|
||
;
|
||
; On Entry:
|
||
; -> A0[7-0] = bit map of SCSI IDs to wait for
|
||
; -> A0[23-16] = bit map of SCSI IDs to search for
|
||
;
|
||
; On Exit:
|
||
; <- A0 = result (0=found wait_for drives, -1=didn't find them)
|
||
;
|
||
; Register Usage:
|
||
; D0 = temp
|
||
; D1 = bitmap of devices to wait for
|
||
; D2 = bitmap of devices to search for
|
||
; D3 = OS Type (for SCSILoad)
|
||
; D4 = Ticks at timeout
|
||
;
|
||
;----------
|
||
|
||
WaitForSCSIDevs PROC EXPORT
|
||
|
||
IMPORT SCSILoad
|
||
|
||
trashedRegs REG D2-D4/D6
|
||
|
||
DefaultTimeOut EQU 20 ; Number of seconds timeout if PRAM is pristine
|
||
PollDelay EQU 15 ; Delay (in ticks) between SCSILoads
|
||
|
||
movem.l trashedRegs, -(sp) ; save registers that we're going to trash
|
||
|
||
; Get bitmap parameters into D1 and D2
|
||
move.l A0, D1 ; D1 = bitmap of devices to wait for
|
||
move.l D1, D2 ;
|
||
swap D2 ; D2 = bitmap of devices to search for
|
||
or.b D1, D2 ; make sure that we search for the drive(s)
|
||
; that we are waiting for
|
||
|
||
; SCSILoad expects OS type in high word of D3
|
||
subq.w #2, sp ; Make room for parameters.
|
||
move.l sp, A0 ; Point to the parameter block.
|
||
_GetOSDefault ; Get info about the default device.
|
||
; leave OS results on stack for a second
|
||
|
||
; Get PRAM time out value and convert it to ticks and keep in D4
|
||
_GetTimeOut ; Get the timeout parameter.
|
||
bne.s @UseGivenTime ; Branch if not using default.
|
||
moveq.l #DefaultTimeOut, D0 ; Use default timeout.
|
||
@UseGivenTime
|
||
mulu #60, D0 ; Convert timeout to ticks.
|
||
move.l D0, D4 ; Save timeout in our final reg.
|
||
|
||
move.w (sp)+, D3 ; Get OS type off of stack
|
||
swap D3 ; put in high word (where SCSILoad expects it)
|
||
|
||
moveq.l #0, D6
|
||
bset #31, D6 ; tell drivers not to munge the blasted heap
|
||
|
||
; SCSILoad polling loop -------
|
||
|
||
@TopO_TheLoop
|
||
move.l D2, D0 ; Try to load drivers for the "search" disks
|
||
bsr.l SCSILoad
|
||
|
||
move.b SCSIDrvrs, D0
|
||
and.b D1, D0 ; look only at bits we are waiting for
|
||
cmp.b D1, D0 ; if all are 1 then
|
||
beq.s @goodexit ; we got what we were waiting for - exit
|
||
|
||
; Check for timeout, wait for PollDelay more ticks, check timeout again, then do the SCSILoad again
|
||
move.l Ticks, D0
|
||
cmp.l D4, D0 ; is current ticks higher than our time_out ticks?
|
||
bhi @fldexit ; yes - timed out, exit
|
||
|
||
add.l #PollDelay, D0 ; wait till Ticks+PollDelay before polling
|
||
@1 cmp.l Ticks, D0 ; if polldelay timeout is higher than current ticks,
|
||
bhi @1 ; then loop
|
||
|
||
cmp.l D4, D0 ; is current ticks higher than our time_out ticks?
|
||
blo @TopO_TheLoop ; no - repeat SCSILoad
|
||
; yes - timed out, exit
|
||
@fldexit
|
||
move.w #-1, A0
|
||
bra.s @exit
|
||
|
||
@goodexit
|
||
move.w #0, A0
|
||
@exit
|
||
movem.l (sp)+, trashedRegs ; restore registers that we trashed
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; SlotBlockXferCtl (_HWPriv Selector 12)
|
||
;
|
||
; This routine enables/disables MUNI's, Cyclone/Tempest Nubus Controller, ability to
|
||
; block xfer TO a Nubus slot. Note: MUNI is always able to recv a block xfer FROM a
|
||
; Nubus slot.
|
||
;
|
||
; Entry:
|
||
; A0 (long) - (bits 31-9) reserved
|
||
; - (bit 8) zero to disable block xfer to a slot , one to turn it on
|
||
; - (bits 7-0) slot number, 1 - 14
|
||
;
|
||
; Exit:
|
||
; D0 (long) - 0 if we're on a MUNI-based system & good slot value, paramErr if not
|
||
; A0 (long) - if noerr, previous state of block xfer for each slot (1=on, 0=off)
|
||
; (Bits 31-15 reserved, Bit 14 = slot 14, ... bit 1 = slot 1, bit 0 reserved)
|
||
;
|
||
; Destroys: D1, D2, A1
|
||
;
|
||
;----------
|
||
|
||
SlotBlockXferCtl PROC EXPORT
|
||
|
||
MoveQ.l #paramErr, D0 ; assume don't have MUNI or bad slot value passed
|
||
Testfor BARTExists ; are we on a ColdFusion or PDM
|
||
bne.s @bart
|
||
TestFor MUNIExists ; Do we have the MUNI Nubus controller
|
||
Beq.s @exit ; No, we're done.
|
||
|
||
MoveA.l UnivInfoPtr, A1 ; point to the product info
|
||
Add.l ProductInfo.DecoderInfoPtr(A1), A1 ; get decoder info ptr
|
||
MoveA.l DecoderInfo.MUNIAddr(A1), A1 ; get MUNI base address
|
||
|
||
Move.l A0, D1 ; get user parm
|
||
MoveQ #0, D2
|
||
Move.l MUNI_BlkAttmpt(A1), D2 ; get previous state of slots 1-14
|
||
Lsl.w #1, D2 ; make bit x match slot x, bit 1 = slot 1
|
||
MoveA.l D2, A0 ; return previous state bit mask in A0
|
||
|
||
MoveQ #0, D2
|
||
Move.b D1, D2 ; Get slot #
|
||
SubQ.b #1, D2 ; adjust slot # for bit offset
|
||
Bmi.s @exit ; bad slot value, < 1
|
||
Cmp.b #14, D2
|
||
Bhs.s @exit ; bad slot value, > 14
|
||
Move.l MUNI_BlkAttmpt(A1), D0 ; get current state of slots 1-14
|
||
BTst #8, D1 ; Turn blk xfer on or off?
|
||
Bne.s @on
|
||
BClr D2, D0 ; turn if off
|
||
Bra.s @doit
|
||
@on BSet D2, D0 ; turn if on
|
||
@doit Move.l D0, MUNI_BlkAttmpt(A1) ; setup block xfers for slot # in D2
|
||
bra.s @done
|
||
|
||
@bart
|
||
MoveA.l UnivInfoPtr, A1 ; point to the product info
|
||
Add.l ProductInfo.DecoderInfoPtr(A1),A1 ; get decoder info ptr
|
||
MoveA.l DecoderInfo.BARTAddr(A1),A1 ; get Bart base address
|
||
|
||
Move.l A0, D1 ; get user parm
|
||
MoveQ #0, D2
|
||
Move.b D1, D2 ; Get slot #
|
||
SubQ.b #1, D2 ; adjust slot # for bit offset
|
||
Bmi.s @exit ; bad slot value, < 1
|
||
Cmp.b #14, D2
|
||
Bhs.s @exit ; bad slot value, > 14
|
||
BTst #8, D1 ; Turn blk xfer on or off?
|
||
Bne.s @Bon
|
||
|
||
moveq #BARTBurstRegOff, d0
|
||
mulu.l d2, d0
|
||
adda.l #BARTBurstReg,a1
|
||
suba.l d0, a1
|
||
bclr.b #BARTBurstBit, (A1) ; turn off block xfers for slot # in D2
|
||
Bra.s @done
|
||
|
||
@Bon moveq #BARTBurstRegOff, d0
|
||
mulu.l d2, d0
|
||
adda.l #BARTBurstReg,a1
|
||
suba.l d0, a1
|
||
bset.b #BARTBurstBit, (A1) ; turn on block xfers for slot # in D2
|
||
|
||
@done MoveQ #noErr,D0 ; signal all's well
|
||
|
||
@exit Rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
;----------
|
||
;
|
||
; GetENetID (_HWPriv Selector 13)
|
||
;
|
||
; This routine gets the EtherNet ID from a serial-interface EtherNet ID ROM.
|
||
; On all machines except Blackbird (so far), the Ethernet ID is in a memory-mapped
|
||
; parallel ROM. When this routine runs on those machines, a0 should already
|
||
; contain a valid address at which to read the ethernet ID, so this routine
|
||
; will just exit for those machines. If there is no address in a0, we double check
|
||
; here to make sure we are on a Blackbird (by checking for Pratt), and then
|
||
; go ahead and try to get the Ethernet ID from the serial ROM.
|
||
;
|
||
; Entry:
|
||
;
|
||
; A0.l - ENetPROM field of the EtherNet Driver (address of ID ROM, or
|
||
; zero for an ID ROM that is not memory-mapped).
|
||
;
|
||
; Exit:
|
||
;
|
||
; A0.l - non-zero pointer to EtherNet ID
|
||
; - ID = 0 if we can't get address from ID ROM
|
||
;
|
||
; Destroys: D1, D2, A1
|
||
;
|
||
;----------
|
||
|
||
GetENetID PROC EXPORT
|
||
|
||
IMPORT X24c01aGetID
|
||
|
||
WITH PMgrRec, PmgrPrimitivesRec
|
||
|
||
IF hasPratt THEN
|
||
TestFor PrattExists ; do we have a Pratt?
|
||
beq.s @exit ; no, so exit
|
||
|
||
move.l a4, -(sp) ; save our macro register
|
||
bigjsr X24c01aGetID,a4 ; get the ID from the serial ROM
|
||
move.l (sp)+, a4 ; restore our macro register
|
||
ENDIF
|
||
|
||
@exit moveq #noErr,d0 ; everything always fine
|
||
rts
|
||
|
||
ENDWITH
|
||
ENDPROC
|
||
|
||
|
||
;====================================================================================================
|
||
;
|
||
; Everything above was HwPriv. Everything below is MemoryDispatch.
|
||
;
|
||
; It’s not exactly clear why all this got thrown into one file.
|
||
;
|
||
;====================================================================================================
|
||
|
||
|
||
;-----
|
||
; Adding new MemoryDispatch routines that work on a page basis. <T2>
|
||
; This to provide support for Sonic onboard Ethernet. <start>
|
||
;
|
||
; To support write-protect, the lock counter behavior has been altered to include <T4>
|
||
; a write-protect bit. The high bit in each lock counter indicates that the page <T4>
|
||
; is write-protected. No count is kept of the number of lock/unlock calls that <T4>
|
||
; have been made. <T4>
|
||
;-----
|
||
|
||
;----------
|
||
;
|
||
; MemDispSelector Macro - This macro allows us to build the selector jump table correctly,
|
||
; regardless of whether compiling for ROM or System. When compiling
|
||
; as a System patch, absolute addresses are generated, and offsets are
|
||
; used when compiling for ROM.
|
||
;
|
||
;-----
|
||
|
||
IF ForROM THEN ; <5>
|
||
MACRO
|
||
MemDispSelector &addr
|
||
import &addr
|
||
dc.w &addr-Vects ; OFFSET of routine <SM6>
|
||
ENDM
|
||
MdVecSize EQU 2
|
||
ELSE
|
||
MACRO
|
||
MemDispSelector &addr
|
||
dcImportResident &addr ; ADDRESS of routine
|
||
ENDM
|
||
MdVecSize EQU 4
|
||
ENDIF
|
||
|
||
;---------------
|
||
;
|
||
; MemoryDispatch
|
||
;
|
||
; Provides services for Virtual Memory access to the hardware
|
||
;
|
||
;-------------------
|
||
|
||
MemoryDispatch PROC Export
|
||
|
||
bra.s MemoryDispatchCode
|
||
|
||
Vects ;table of offset to selector routines
|
||
MemDispSelector HoldMemoryProc ; 0
|
||
MemDispSelector UnHoldMemoryProc ; 1
|
||
MemDispSelector LockMemoryProc ; 2
|
||
MemDispSelector UnLockMemoryProc ; 3
|
||
MemDispSelector LockMemoryContiguousProc ; 4
|
||
MemDispSelector GetPhysicalProc ; 5
|
||
MemDispSelector WriteProtectProc ; 6 <T6>
|
||
LastVec MemDispSelector UnWriteProtectProc ; 7 <T6>
|
||
|
||
|
||
MemoryDispatchCode
|
||
cmp.w #(LastVec-Vects)/MdVecSize,d0 ; check if selector in range
|
||
bhi.s @badSelect ; abort if its not a valid selector
|
||
move.w Vects(d0.w*MdVecSize),d0 ; get offset to selector's routine
|
||
jmp Vects(d0) ; go to the routine
|
||
|
||
@badSelect move.l #hwParamErr,d0 ; abort: return error code
|
||
rts
|
||
|
||
EndProc
|
||
|
||
|
||
;-----
|
||
;
|
||
; HoldMemoryProc (_MemoryDispatch Selector 0)
|
||
;
|
||
; This routine makes the address space resident in real memory and ineligible for paging.
|
||
;
|
||
; Destroys: none
|
||
;
|
||
;-----
|
||
HoldMemoryProc PROC Export
|
||
|
||
Moveq #0,D0 ; no error
|
||
Rts
|
||
|
||
EndProc
|
||
;-----
|
||
;
|
||
; UnHoldMemoryProc (_MemoryDispatch Selector 1)
|
||
;
|
||
; This routine makes the address space eligible for paging.
|
||
;
|
||
; Destroys: none
|
||
;
|
||
;-----
|
||
UnHoldMemoryProc PROC Export
|
||
|
||
Moveq #0,D0 ; no error
|
||
Rts
|
||
|
||
EndProc
|
||
|
||
;-----
|
||
;
|
||
; LockMemoryProc (_MemoryDispatch Selector 2)
|
||
;
|
||
; This routine makes the address space immovable in real memory and ineligible for paging.
|
||
; It also marks the corresponding page frames as non-cacheable, and increments the <T2>
|
||
; lock count for the page. <T2>
|
||
;
|
||
; After calling GetPageRange, d1 contains the page number of the first logical page,
|
||
; and d2 contains the page count.
|
||
;
|
||
; Destroys: none
|
||
;
|
||
; Calls: GetPageRange, MMUMakePageNonCacheable, MMUFlushATC, MMUFlushDataCache
|
||
;
|
||
;-----
|
||
|
||
LockMemoryProc PROC Export
|
||
Import GetPageRange,MMUFlushATC,MMUSetCacheInhibit
|
||
WITH MemDispGlobals
|
||
|
||
@saveRegs REG d1-d4/a0-a2
|
||
|
||
movem.l @saveRegs,-(sp) ; save registers
|
||
movea.l LockMemCt,a2 ; point to MemoryDispatch globals
|
||
bsr GetPageRange ; check input arguments
|
||
bne.s @error ; get out
|
||
lea.l mdLockTable(a2,d1*2),a1 ; point to lock counter for first page
|
||
moveq.l #1,d0 ; flag to MMUSetCacheInhibit to inhibit caching
|
||
@loop
|
||
addq.w #1,(a1)+ ; bump the lock count
|
||
bsr MMUSetCacheInhibit ; mark page as noncacheable
|
||
addq.l #1,d1 ; increment page number
|
||
subq.l #1,d2 ; one less page to go <T4>
|
||
bhi.s @loop ; keep looping <T4>
|
||
|
||
cmpi.b #EMMU1,MMUType ; is this an Emulated MMU? <SM17>
|
||
beq.s @done ; -> Yes, no need to flush anything <SM17>
|
||
bsr MMUFlushATC ; flush ATC's
|
||
_FlushDataCache ; flush data cache
|
||
@done moveq.l #noErr,d0 ; no error
|
||
@error
|
||
movem.l (sp)+,@saveRegs ; restore registers
|
||
rts
|
||
EndWith
|
||
EndProc
|
||
|
||
;-----
|
||
;
|
||
; UnLockMemoryProc (_MemoryDispatch Selector 3)
|
||
;
|
||
; This routine makes the address space movable in real memory and eligible for paging again.
|
||
; It also decrements the lock count for the corresponding page frames, and if the <T2>
|
||
; count is zero, markd the page as cacheable. <T2>
|
||
;
|
||
; Destroys: none
|
||
;
|
||
;-----
|
||
UnLockMemoryProc PROC Export
|
||
Import GetPageRange,MMUSetCacheInhibit,MMUFlushATC
|
||
With MemDispGlobals
|
||
|
||
@saveRegs REG d1-d4/a0-a2
|
||
|
||
movem.l @saveRegs,-(sp) ; save registers
|
||
movea.l LockMemCt,a2 ; point to MemoryDispatch globals
|
||
bsr GetPageRange ; check input arguments
|
||
bne.s @error ; get out
|
||
lea.l mdLockTable(a2,d1*2),a1 ; point to lock counter for first page
|
||
move.l d2,d3 ; copy of the count
|
||
move.w #notLockedErr,d0 ; assume a nonlocked page
|
||
@lockCheckLoop
|
||
tst.w (a1)+ ; check the page lock counter
|
||
beq.s @error ; if zero, page was not locked previously
|
||
subq.l #1,d3 ; one less page to go <T4>
|
||
bhi.s @lockCheckLoop ; keep looping <T4>
|
||
|
||
lea.l mdLockTable(a2,d1*2),a1 ; point to lock counter for first page
|
||
move.l d2,d3 ; copy of the count
|
||
moveq.l #0,d0 ; flag to MMUSetCacheInhibit to enable caching
|
||
moveq.l #0,d4 ; assume ATC will not need to be cleared
|
||
@unlockLoop
|
||
subq.w #1,(a1)+ ; decrement the lock count for this page
|
||
bne.s @stillLocked ; if count != 0, page will remain locked
|
||
bsr MMUSetCacheInhibit ; mark page as cacheable
|
||
moveq.l #1,d4 ; ATC will need to be cleared (a PTE changed)
|
||
@stillLocked
|
||
addq.l #1,d1 ; move on to next page
|
||
subq.l #1,d3 ; one less page to go <T4>
|
||
bhi.s @unlockLoop ; keep looping <T4>
|
||
|
||
tst.l d4 ; do we need to flush the ATC
|
||
beq.s @noFlush ; if not, don't do it
|
||
bsr MMUFlushATC ; flush ATC's
|
||
@noFlush
|
||
moveq.l #noErr,d0 ; return noErr
|
||
@error
|
||
movem.l (sp)+,@saveRegs ; restore registers
|
||
rts
|
||
|
||
EndWith
|
||
EndProc
|
||
|
||
|
||
;-------------------------------------------------------------------
|
||
;
|
||
; LockMemoryContiguousProc (_MemoryDispatch Selector 4)
|
||
;
|
||
; This routine provides the service of making a virtual address range contiguous in
|
||
; physical address space.
|
||
;
|
||
; Destroys: none
|
||
; on Entry:
|
||
; A0.L = start of logical address
|
||
; D0.W = 4, selector
|
||
; A1.L = number of bytes in buffer
|
||
;
|
||
; on Exit:
|
||
; D0.W = error code
|
||
;
|
||
;-------------------------------------------------------------------
|
||
|
||
LockMemoryContiguousProc PROC Export
|
||
Import GetPageRange,GetRealProc,MMUSetCacheInhibit,MMUFlushATC
|
||
With MemDispGlobals
|
||
|
||
@saveRegs REG a0-a3/d1-d4
|
||
@moreRegs REG d1/a1-a2
|
||
|
||
movem.l @saveRegs,-(sp) ; save registers
|
||
movea.l LockMemCt,a2 ; point to MemoryDispatch globals
|
||
bsr GetPageRange ; check input arguments
|
||
bne.s @error ; get out (returns paramErr)
|
||
movea.l a0,a3 ; copy starting logical address
|
||
|
||
movem.l @moreRegs,-(sp) ; save registers that GetReal destroys
|
||
bsr GetRealProc ; get the starting physical address
|
||
movem.l (sp)+,@moreRegs ; restore registers that GetReal destroys
|
||
exg.l a0,a3 ; hold on to starting physical address
|
||
adda.l a1,a0 ; add length of buffer - 1
|
||
subq.l #1,a0
|
||
movem.l @moreRegs,-(sp) ; save registers that GetReal destroys
|
||
bsr GetRealProc ; get the ending physical address
|
||
movem.l (sp)+,@moreRegs ; restore registers that GetReal destroys
|
||
suba.l a3,a0 ; get the distance between the addresses
|
||
addq.l #1,a0 ; adjust calculation
|
||
cmpa.l a1,a0 ; compare the results
|
||
bne.s @notContigError ; range crosses a non-contiguous bank boundary
|
||
|
||
lea.l mdLockTable(a2,d1*2),a1 ; point to lock counter for first page
|
||
moveq.l #1,d0 ; flag to MMUSetCacheInhibit to inhibit caching
|
||
@loop
|
||
addq.w #1,(a1)+ ; bump the lock count
|
||
bsr MMUSetCacheInhibit ; mark page as noncacheable
|
||
addq.l #1,d1 ; increment page number
|
||
subq.l #1,d2 ; one less page to go <T4>
|
||
bhi.s @loop ; keep looping <T4>
|
||
|
||
cmpi.b #EMMU1,MMUType ; is this an Emulated MMU? <SM17> <SM17>
|
||
beq.s @done ; -> Yes, no ATC or Data cache to flush <SM17>
|
||
bsr MMUFlushATC ; flush ATC's
|
||
_FlushDataCache ; flush data cache
|
||
@done moveq.l #noErr,d0 ; no error
|
||
@error
|
||
movem.l (sp)+,@saveRegs ; restore registers
|
||
rts
|
||
@notContigError
|
||
move.w #cannotMakeContiguousErr,d0 ; addresses are not contiguous
|
||
bra.s @error
|
||
|
||
EndWith
|
||
EndProc
|
||
|
||
;-------------------------------------------------------------------
|
||
;
|
||
; GetPhysicalProc (_MemoryDispatch Selector 5)
|
||
;
|
||
; This routine translates virtual addressess to corresponding physical addresses.
|
||
;
|
||
; Destroys: none
|
||
;
|
||
; on Entry:
|
||
; A0.L = pointer to translation table
|
||
; D0.W = 5, selector
|
||
; A1.L = number of entries in table
|
||
; A1.L = 0, if caller want to get number of entries required
|
||
;
|
||
; on Exit:
|
||
; D0.W = error code
|
||
; A0.L = number of pairs returned/required
|
||
; A1.L = pointer to translation table
|
||
;
|
||
;-------------------------------------------------------------------
|
||
VAddr EQU -8 ; offset to virtual address from A0
|
||
BuffSize EQU -4 ; offset to buffer size
|
||
SavedPtr EQU 2 ; offset to saved ptr in stack
|
||
|
||
GetPhysicalProc PROC Export
|
||
Import GetRealProc,ChkContig
|
||
|
||
GetPhysRegs REG d3/a3-a4
|
||
|
||
|
||
MOVEM.L GetPhysRegs,-(SP) ; save register <v2.1>
|
||
move.l a0,-(sp) ; save pointer to table on stack
|
||
move.l a0,a4 ; get table entry pointer in a4 <T3>
|
||
Move.L A1,D3 ; get table entry number <T3>
|
||
MOVE.L (A4)+,D2 ; get virtual address in d2 <T3>
|
||
@NoSwap
|
||
move.l d2,a0 ; put virtual address in a0 <T3>
|
||
ADD.L (A4),D2 ; get end of buffer <T3>
|
||
CMP.L realMemtop,D2 ; does it exceed available RAM <v1.3>
|
||
BHI.S @BadAddress ; >>EXIT if it exceeds top of RAM <v2.1>
|
||
|
||
BSR.L GetRealProc ; get physical address in a0 <T3>
|
||
BMI.S @BadAddress ; branch if bad address
|
||
|
||
MOVE.L A0,A3 ; save physical address in A3
|
||
MOVE.L D2,A0 ; get end of buffer <T3>
|
||
SUBQ.L #1,A0 ; convert to end address <T3>
|
||
BSR.L GetRealProc ; get physical address in a0 <T3>
|
||
BMI.S @BadAddress ; branch if bad address
|
||
|
||
SUB.L A3,A0 ; calculate distance between addresses <T3>
|
||
ADDQ.L #1,A0 ; convert to byte count <T3>
|
||
CMP.L (A4),A0 ; are they the same size <T3>
|
||
BNE.S @NonContig ; branch, if memory is not contiguous
|
||
|
||
TST.L d3 ; d3 = 0?? <T3>
|
||
BEQ.S @return1 ; branch, if yes
|
||
MOVE.L (A4)+,D0 ; save buffer size <T3>
|
||
ADD.L D0,VAddr(A4) ; update virtual address <T3>
|
||
MOVE.L #0,BuffSize(A4) ; update buffer size <T3>
|
||
MOVE.L A3,(A4)+ ; save physcial address in table <T3>
|
||
MOVE.L D0,(A4) ; save size in table <T3>
|
||
@return1
|
||
MOVE.L #1,A0 ; return with 1 entry <v1.3>
|
||
MOVE.W #0,D2 ; and with no error
|
||
@GPEXit
|
||
MOVE.L D2,D0 ; set final error code <v1.6>
|
||
MOVE.L (SP)+,A1 ; restore pointer <v1.3>
|
||
MOVEM.L (SP)+,GetPhysRegs ; restore registers <v2.1>
|
||
RTS
|
||
@BadAddress
|
||
MOVEQ #0,A0 ; when error, return zero entry <v1.3>
|
||
MOVE.W #paramErr,D2 ; return paramErr
|
||
BRA.S @GPExit
|
||
|
||
@NonContig
|
||
MOVE.L (SP),A4 ; A0 gets pointer to table <T3>
|
||
MOVE.L (A4),A0 ; get logical address in A0 <v2.1>
|
||
|
||
ADD.L #8,A4 ; A4 = points to table entry
|
||
MOVE.L D3,D1 ; D1 = number of table entry or 0 <T11>
|
||
BSR ChkContig ; check contiguous physical
|
||
TST.W D2 ; are there error
|
||
BMI.S @BadAddress
|
||
MOVE.L D1,A0 ; get number of entries in A0 <v1.3>
|
||
BRA.S @GPEXit
|
||
|
||
EndProc
|
||
|
||
|
||
;-------------------------------------------------------------------
|
||
;
|
||
; ChkContig:-
|
||
; Check for contiguous address space for buffer
|
||
; This code is written in a rush, and should be rewritten
|
||
; in the future.
|
||
;
|
||
; on entry:
|
||
; A0 = logical address
|
||
; A4 = pointer to table
|
||
; D1 = number of table entries or 0
|
||
; on exit:
|
||
; D1 = number of table entries
|
||
; D2 = error code
|
||
;
|
||
; destroys: A3
|
||
;-------------------------------------------------------------------
|
||
|
||
StkFrame record {a6link},decr
|
||
a6link DS.L 1 ; old link pointer
|
||
PhysAddr DS.L 1 ; physical address
|
||
PageAddr DS.L 1 ; physical page address
|
||
ContigSize DS.L 1 ; contiguous memory size
|
||
EntryNum DS.L 1 ; number of entry
|
||
EntryReq DS.L 1 ; entry required
|
||
EntryIndex DS.L 1 ; current entry Index
|
||
OVAddr DS.L 1 ; original virtual address
|
||
OSize DS.L 1 ; original size
|
||
StkSize equ * ; size of locals
|
||
endr
|
||
|
||
ChkContig PROC Export
|
||
Import GetRealProc
|
||
With MemDispGlobals
|
||
|
||
WITH StkFrame
|
||
LINK A6,#StkSize ; define a stack frame for local variable
|
||
Movem.L D3-D7,-(SP) ; save registers <v2.1>
|
||
MOVE.L D1,EntryNum(A6) ; save number of entry
|
||
|
||
MOVE.L #1,EntryReq(A6) ; initialize entry required to 1
|
||
MOVE.L #0,EntryIndex(A6) ; initialize current entry index to 0
|
||
MOVE.L VAddr(a4),OVaddr(A6) ; save original virtual address <T3>
|
||
MOVE.L Buffsize(a4),OSize(A6) ; save original size <T3>
|
||
|
||
BSR.L GetRealProc ; convert addr in a0 to physical addr <T3>
|
||
BMI @BadAddress ; branch if bad address
|
||
|
||
MOVE.L A0,PhysAddr(A6) ; save physical address <LW7>
|
||
|
||
MOVE.L LockMemCt,A2 ; point to MemoryDispatch globals <LW7>
|
||
move.l mdPageSize(A2),D2 ; point to MemoryDispatch globals
|
||
; Removed a •Gestalt• call to get the page size! Sheeze! <SM17>
|
||
|
||
; to calculate amount of memory in the first page
|
||
SUBQ #1,d2 ; create mask to get bytes in 1st page <T3>
|
||
MOVE.L PhysAddr(A6),D3 ; get physical address <T11>
|
||
NEG.L D3 ; negate the address <T11>
|
||
AND.L D3,D2 ; get remaining bytes in first page <T11>
|
||
|
||
MOVE.L D2,ContigSize(A6) ; save memory size
|
||
MOVE.L OVaddr(A6),A3 ; get original logical address <T11>
|
||
ADD.L D2,A3 ; get logical address on page boundary <T11>
|
||
@loop
|
||
MOVE.L A3,A0 ; get logical address into A0 <T11>
|
||
BSR.L GetRealProc ; convert addr in A0 to physical addr <T3>
|
||
BMI @BadAddress ; branch if bad address
|
||
|
||
MOVE.L LockMemCt,A2 ; restore A2,points toMemoryDispatch globals <LW7>
|
||
|
||
MOVE.L PhysAddr(A6),D3 ; get saved start physical address
|
||
Add.L ContigSize(A6),D3 ; added length of contiguous address
|
||
CMP.L D3,a0 ; Does it match the new physical address<T3>
|
||
BNE.S @NotContig ; branch if not contiguous
|
||
MOVE.L ContigSize(A6),D3 ; get contiguous size
|
||
@common
|
||
ADD.L mdPageSize(a2),D3 ; update Contiguous memory size <SM17>
|
||
CMP.L BuffSize(a4),D3 ; is it end yet? <T3>
|
||
BCC.S @Done ; yes, branch
|
||
MOVE.L D3,ContigSize(A6) ; update contiguous size
|
||
ADD.L mdPageSize(a2),A3 ; get new virtual address <T11><SM17>
|
||
BRA.S @loop
|
||
|
||
@NotContig
|
||
TST.L EntryNum(A6) ; test number of entries
|
||
BEQ.S @justCount ; just count
|
||
|
||
MOVE.L EntryIndex(A6),D3 ; get entry index
|
||
MOVE.L PhysAddr(A6),(0,a4,D3.L*8) ; store physical address <T3>
|
||
MOVE.L ContigSize(A6),(4,a4,D3.L*8); store contiguous size <T3>
|
||
|
||
Add.L #1,D3 ; advance current entry
|
||
CMP.L EntryNum(A6),D3 ; end of table yet?
|
||
BCC.S @ExitA ; if yes, done
|
||
MOVE.L D3,EntryIndex(A6) ; update index
|
||
@justCount
|
||
ADDQ.L #1,EntryReq(A6) ; update entry required
|
||
|
||
MOVE.L ContigSize(A6),D3 ; get ContigSize
|
||
ADD.L D3,VAddr(a4) ; update virtual address <T3>
|
||
SUB.L D3,BuffSize(a4) ; update buffer size <T3>
|
||
|
||
Move.L A0,PhysAddr(A6) ; update new physical address <T11>
|
||
|
||
MOVEQ #0,D3 ; initial to zero memory
|
||
BRA.S @common ; branch back inside loop
|
||
@Done
|
||
TST.L EntryNum(A6) ; test number of entries
|
||
BNE.S @GetResult ; branch, if not zero
|
||
|
||
Move.L EntryReq(A6),D1 ; get entry required
|
||
MOVE.L OVaddr(A6),VAddr(a4) ; restore original virtual address <T3>
|
||
MOVE.L OSize(A6),BuffSize(a4) ; restore original size <T3>
|
||
BRA.S @ExitB
|
||
@GetResult
|
||
MOVE.L EntryIndex(A6),D3 ; get entry index
|
||
MOVE.L PhysAddr(A6),(0,a4,D3.L*8) ; store physical address <T3>
|
||
MOVE.L BuffSize(a4),(4,a4,D3.L*8) ; store size <T3>
|
||
MOVE.L BuffSize(a4),D2 ; save remaining buffsize <T3>
|
||
Add.L D2,VAddr(a4) ; update virtual address <T3>
|
||
MOVE.L #0,BuffSize(a4) ; indicate complete translation <T3>
|
||
AddQ.L #1,D3 ; convert index to entry count
|
||
@ExitA
|
||
MOVE.L D3,D1 ; return entry count
|
||
@ExitB
|
||
MOVEQ #0,D2 ; no error <v1.6>
|
||
@ExitC
|
||
MOVEM.L (SP)+,D3-D7 ; restore registers <v2.1>
|
||
UNLK A6
|
||
ENDWITH
|
||
RTS
|
||
@BadAddress
|
||
MOVE.W #-1,D2 ; return paramErr <v1.6>
|
||
BRA.S @ExitC
|
||
|
||
EndWith
|
||
EndProc
|
||
|
||
|
||
;-----
|
||
;
|
||
; WriteProtectProc (_MemoryDispatch Selector 6) <T4>
|
||
; <start>
|
||
; This routine protects the address space from write accesses.
|
||
; It also sets the high bit in the lock counter for each page in the range.
|
||
;
|
||
; The address range must start at a page boundary, and must be a multiple of
|
||
; page size in length. If either of these conditions are not true, then
|
||
; the call returns "paramErr".
|
||
;
|
||
; After calling GetPageRange, d1 contains the page number of the first logical page,
|
||
; and d2 contains the page count.
|
||
;
|
||
; Destroys: none
|
||
;
|
||
; Entry: A0.L = logical start address (must be at the start of a page)
|
||
; A1.L = number of bytes (must be a multiple of page size)
|
||
; D0.W = 6, selector
|
||
;
|
||
; Exit: D0.W = error code
|
||
;
|
||
; Calls: GetPageRange, MMUSetWriteProtect, MMUFlushATC, MMUFlushDataCache
|
||
;
|
||
;-----
|
||
WriteProtectProc Proc Export
|
||
Import GetRealProc,GetPageRange,MMUSetWriteProtect,MMUFlushATC
|
||
With MemDispGlobals
|
||
@saveRegs REG d1/d2/a0-a2
|
||
@setW EQU (1<<2) ; set Write protect mask (used as a flag)
|
||
@setWMask EQU $8000 ; mask to set write-protect bit at top of lock count
|
||
|
||
movem.l @saveRegs,-(sp) ; save registers
|
||
movea.l LockMemCt,a2 ; point to MemoryDispatch globals
|
||
moveq.l #paramErr,d0 ; assume it won't work
|
||
move.l mdPageSize(a2),d2 ; get the page size
|
||
subq.l #1,d2 ; mask for page boundary alignment check
|
||
move.l a0,d1 ; get the start address
|
||
and.l d2,d1 ; is the start address page-aligned ?
|
||
bne.s @error ; start address must be page-aligned
|
||
move.l a1,d1 ; is the range a multiple of page size ?
|
||
and.l d2,d1 ; is the range a multiple of page size ?
|
||
bne.s @error ; range must be a multiple of page size
|
||
|
||
bsr GetPageRange ; check input arguments
|
||
bne.s @error ; get out
|
||
cmpi.b #EMMU1,MMUType ; do we have an EMMU? <SM17>
|
||
beq.s @NoFlush ; -> Yes, no need for this crap
|
||
_FlushDataCache ; flush data cache (flush data before write protecting)
|
||
_FlushInstructionCache ; flush instruction cache (just for grins)
|
||
bsr MMUFlushATC ; flush ATC's
|
||
@NoFlush lea.l mdLockTable(a2,d1*2),a1 ; point to lock counter for first page
|
||
moveq.l #@setW,d0 ; flag to MMUSetWriteProtect to write-protect
|
||
@loop
|
||
ori.w #@setWMask,(a1)+ ; set the write-protect flag
|
||
bsr MMUSetWriteProtect ; mark page as write-protected
|
||
addq.l #1,d1 ; increment page number
|
||
subq.l #1,d2 ; one less page to go
|
||
bhi.s @loop ; keep looping
|
||
|
||
moveq.l #noErr,d0 ; no error
|
||
@error
|
||
movem.l (sp)+,@saveRegs ; restore registers <end>
|
||
rts ; <T4>
|
||
EndWith
|
||
EndProc
|
||
|
||
;-----
|
||
;
|
||
; UnWriteProtectProc (_MemoryDispatch Selector 7) <T4>
|
||
; <start>
|
||
; This routine allows write accesses to the address space.
|
||
; It also clears the high bit in the lock counter for each page in the range.
|
||
;
|
||
; The address range must start at a page boundary, and must be a multiple of
|
||
; page size in length. If either of these conditions are not true, then
|
||
; the call returns "paramErr".
|
||
;
|
||
; After calling GetPageRange, d1 contains the page number of the first logical page,
|
||
; and d2 contains the page count.
|
||
;
|
||
; Destroys: none
|
||
;
|
||
; Entry: A0.L = logical start address (must be at the start of a page)
|
||
; A1.L = number of bytes (must be a multiple of page size)
|
||
; D0.W = 7, selector
|
||
;
|
||
; Exit: D0.W = error code
|
||
;
|
||
; Calls: GetPageRange, MMUMakePageNonCacheable, MMUFlushATC, MMUFlushDataCache
|
||
;
|
||
;-----
|
||
UnWriteProtectProc Proc Export
|
||
Import GetPageRange,MMUSetWriteProtect,MMUFlushATC
|
||
With MemDispGlobals
|
||
@saveRegs REG d1/d2/a0-a2
|
||
@clearW EQU (0<<2) ; clear Write protect mask (used as a flag)
|
||
@clearWMask EQU $7fff ; mask to clear write-protect bit at top of lock count
|
||
|
||
movem.l @saveRegs,-(sp) ; save registers
|
||
movea.l LockMemCt,a2 ; point to MemoryDispatch globals
|
||
moveq.l #paramErr,d0 ; assume it won't work
|
||
move.l mdPageSize(a2),d2 ; get the page size
|
||
subq.l #1,d2 ; mask for page boundary alignment check
|
||
move.l a0,d1 ; get the start address
|
||
and.l d2,d1 ; is the start address page-aligned ?
|
||
bne.s @error ; start address must be page-aligned
|
||
move.l a1,d1 ; is the range a multiple of page size ?
|
||
and.l d2,d1 ; is the range a multiple of page size ?
|
||
bne.s @error ; range must be a multiple of page size
|
||
|
||
bsr GetPageRange ; check input arguments
|
||
bne.s @error ; get out
|
||
lea.l mdLockTable(a2,d1*2),a1 ; point to lock counter for first page
|
||
moveq.l #@clearW,d0 ; flag to MMUSetWriteProtect to clear write-protect
|
||
@loop
|
||
andi.w #@clearWMask,(a1)+ ; clear the write-protect flag
|
||
bsr MMUSetWriteProtect ; mark page as writeable
|
||
addq.l #1,d1 ; increment page number
|
||
subq.l #1,d2 ; one less page to go
|
||
bhi.s @loop ; keep looping
|
||
|
||
bsr MMUFlushATC ; flush ATC's (to allow writes to previously protected pages)
|
||
moveq.l #noErr,d0 ; no error
|
||
@error
|
||
movem.l (sp)+,@saveRegs ; restore registers <end>
|
||
rts ; <T4>
|
||
EndWith
|
||
EndProc
|
||
|
||
|
||
;-------------------------------------------------------------------
|
||
;
|
||
; InitMemoryDispatch
|
||
;
|
||
; This routine allocates and initializes the MemoryDispatch globals.
|
||
;
|
||
;-------------------------------------------------------------------
|
||
InitMemoryDispatch Proc Export
|
||
With MemDispGlobals
|
||
@UnimplementedTrap EQU $A89F
|
||
@MemoryDispatchTrap EQU $A05C
|
||
@saveRegs REG a0-a3/d0-d4
|
||
@localSize EQU -4 ; storage for the TC register
|
||
@cm0bit EQU 5 ; CM[0] bit in 040 page descriptor
|
||
|
||
link a6,#@localSize ; allocate space for the TC register
|
||
movem.l @saveRegs,-(sp) ; save registers
|
||
|
||
clr.l LockMemCt ; clear ptr to globals (assume failure)
|
||
|
||
cmpi.b #HMMU,MMUType ; Do we have an MMU? <SM17>
|
||
bhi.s @hasMMU ; -> Yes, do the init!
|
||
|
||
MOVE.W #@UnimplementedTrap,d0 ; _Unimplemented <SM17>
|
||
_GetTrapAddress ,newTool ; Get its address
|
||
MOVE.W #@MemoryDispatchTrap,d0 ; Select MemoryDispatch trap
|
||
_SetTrapAddress ,newOS ; Set it to point to Unimplemented
|
||
bra @NoPages ; -> All done
|
||
|
||
@hasMMU move.b CPUFlag,d1 ; get the CPU type
|
||
moveq.l #0,d2 ; assume no page size
|
||
move.l PhysMemTop,d3 ; get actual amount of physical RAM
|
||
|
||
cmpi.b #cpu68040,d1 ; are we on an '040 ?
|
||
bne.s @not040 ; if not, handle its MMU differently
|
||
|
||
MACHINE MC68040
|
||
moveq.l #12,d1 ; assume 4K pages ( 12 = log2(4096) )
|
||
movec TC,d0 ; get the TC register
|
||
btst.l #14,d0 ; are we in 8K page mode ?
|
||
beq.s @gotPageSize ; if not, we have the page size
|
||
addq.l #1,d1 ; page size is 8K ( 13 = log2(8192) )
|
||
bra.s @gotPageSize ; continue
|
||
MACHINE MC68030
|
||
@not040
|
||
cmpi.b #cpu68020,d1 ; are we at least an '020 ?
|
||
blo.w @noPages ; bail without allocating globals ??? (Use old code ?)
|
||
cmpi.b #PMMU851,MMUType ; do we have a real MMU ?
|
||
blo.w @noPages ; bail without allocating globals ??? (Use old code ?)
|
||
cmpi.b #EMMU1,MMUType ; do we have an emulated MMU?
|
||
bne.s @mustbe030 ; -> No, must be an 030 <SM17>
|
||
|
||
moveq #0,D1 ; clear D1
|
||
move.l ([ProcessorInfoPtr],ProcessorInfo.PageSize),D0 ; Get the Page size from the nano-k
|
||
beq.w @NoPages ; 0 Page size. Can't happen. <SM17>
|
||
@countBits asr.l #1,D0 ; Shift bit zero into the carry. <SM17>
|
||
bcs.s @gotPageSize ; -> Bail out at the first bit set w/bit # in d1 <SM17>
|
||
addq #1,d1
|
||
bra.s @countBits ; Keep shifting till we find one <SM17>
|
||
|
||
@mustbe030 pmove.l TC,-4(a6) ; get the '030 TC register contents
|
||
bfextu -4(a6){8,4},d1 ; get log2 of page size
|
||
@gotPageSize
|
||
bset.l d1,d2 ; get the page size
|
||
lsr.l d1,d3 ; get number of page frames
|
||
move.l d3,d4 ; remember number of page frames
|
||
move.l d3,d0 ; set up to allocate page lock table
|
||
asl.l #1,d0 ; each lock counter is a word
|
||
addi.w #mdGlobalSize,d0 ; size of additional globals
|
||
move.l d0,d3 ; remember size of globals
|
||
_NewPtr ,Sys ,Clear ; allocate MemoryDispatch globals
|
||
bne.w @noPages ; we're dead (bail, or use old code ???)
|
||
move.l a0,LockMemCt ; save ptr to MemoryDispatch globals
|
||
move.l d3,mdSize(a0) ; size of entire MemoryDispatch globals
|
||
move.l d2,mdPageSize(a0) ; save page size
|
||
move.l d1,mdLog2PageSize(a0) ; save log2 of page size
|
||
move.l d4,mdPages32(a0) ; save number of logical pages in 32-bit mode
|
||
move.l d4,mdPageFrames(a0) ; save number of page frames
|
||
move.l #$800000,d3 ; max of 8MB addressable in 24-bit mode
|
||
cmp.l PhysMemTop,d3 ; check amount of physical memory
|
||
blo.s @use8meg ; if physical memory > 8MB, only 8MB available
|
||
move.l PhysMemTop,d3 ; else use physical memory
|
||
@use8meg
|
||
lsr.l d1,d3 ; get number of logical pages in 24-bit mode
|
||
move.l d3,mdPages24(a0) ; save number of pages in 24-bit mode
|
||
@noPages
|
||
movem.l (sp)+,@saveRegs ; restore registers
|
||
unlk a6
|
||
rts
|
||
EndWith
|
||
EndProc
|
||
|
||
|
||
;-------------------------------------------------------------------
|
||
; GetPageRange - Sanity check on the logical address and count
|
||
;
|
||
; Destroys: a0/d1/d2
|
||
;
|
||
; On entry:
|
||
; a0.l = logical address
|
||
; a1.l = logical count
|
||
; a2.l = ptr to MemoryDispatch globals
|
||
;
|
||
; On exit:
|
||
; d0.w = error code
|
||
; d1.l = first page
|
||
; d2.l = number of pages in range
|
||
; a0.l = clean logical address
|
||
; a1.l = logical count (unchanged)
|
||
; a2.l = ptr to MemoryDispatch globals (unchanged)
|
||
;
|
||
;-------------------------------------------------------------------
|
||
GetPageRange Proc Export
|
||
With MemDispGlobals
|
||
@saveRegs REG a1/a2
|
||
movem.l @saveRegs,-(sp) ; save registers
|
||
move.l a0,d0 ; get logical address
|
||
IF Supports24Bit THEN ; <SM17>
|
||
tst.b MMU32Bit ; check if in 32-bit mode
|
||
bne.s @noStrip ; if 32-bit mode, assume clean address
|
||
_StripAddress ; clean the address
|
||
@noStrip
|
||
ENDIF
|
||
movea.l d0,a0 ; save clean logical address
|
||
|
||
cmpa.w #0,a1 ; check the count
|
||
beq.s @error ; if zero count, return paramErr
|
||
|
||
move.l d0,d1 ; copy the start address
|
||
move.l d0,d2 ; copy the start address
|
||
|
||
add.l a1,d2 ; get end of buffer
|
||
subq.l #1,d2 ; last = start + count - 1
|
||
cmp.l realMemtop,d2 ; check against available RAM
|
||
bhs.s @error ; if last >= realMemTop, return paramErr
|
||
|
||
move.l mdLog2PageSize(a2),d0 ; get log2 of page size
|
||
lsr.l d0,d1 ; get page number of start address
|
||
lsr.l d0,d2 ; get page number of last address
|
||
sub.l d1,d2 ; page count = lastPage - firstPage + 1
|
||
addq.l #1,d2
|
||
moveq.l #noErr,d0 ; it worked
|
||
@exit
|
||
movem.l (sp)+,@saveRegs ; restore registers
|
||
rts
|
||
@error
|
||
moveq.l #paramErr,d0 ; it failed
|
||
bra.s @exit
|
||
EndWith
|
||
EndProc
|
||
|
||
;-------------------------------------------------------------------
|
||
; MMUSetWriteProtect - Set W (Write Protect) bit for a page <T4>
|
||
; <start>
|
||
; Destroys: none.
|
||
;
|
||
; On entry: d0.l = write protect mask: 0=clear write protect bit
|
||
; 4=set write protect bit (bit 2)
|
||
; d1.l = logical page number
|
||
; a2.l = ptr to MemoryDispatch globals
|
||
;
|
||
; Calls: GetPageDescProc
|
||
;
|
||
;-------------------------------------------------------------------
|
||
MMUSetWriteProtect Proc Export
|
||
Import GetPageDescProc
|
||
With MemDispGlobals
|
||
@saveRegs REG d0-d4/a0/a1
|
||
@moreRegs REG d1/a1/a2
|
||
@wBit EQU 2 ; write protect bit in all page descriptors
|
||
|
||
cmp.b #PMMU851,MMUType ; do we have at least a 68851 PMMU ?
|
||
blo.w @noPages ; if not, no pages to write protect (020 or less)
|
||
@hasPages
|
||
movem.l @saveRegs,-(sp) ; save registers
|
||
move.l d0,d4 ; remember write-protect mask
|
||
|
||
CMPI.B #EMMU1,MMUType ; Do we have an EMMU? <SM17>
|
||
BNE.S @RealMMU ; -> Nope, sorry
|
||
|
||
MOVE.L D1,A0 ; Put the page number in A0
|
||
_nkGetPTEntryGivenPage ; Get the 030+ PTE from the nk
|
||
|
||
BCLR #@wBit,D0 ; Clear the W bit
|
||
OR.L D4,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
|
||
|
||
BRA.S @RegDone ; -> Exit
|
||
|
||
@RealMMU move.l mdLog2PageSize(a2),d0 ; get the log2 of the page size
|
||
asl.l d0,d1 ; turn logical page number into a logical address
|
||
|
||
IF Supports24Bit THEN ; <SM17>
|
||
cmp.l mdPages24(a2),d1 ; check if page is in the 24-bit address space
|
||
slo d3 ; if it is, be sure to whack the 24-bit table
|
||
|
||
moveq.l #false32b,d0 ; first go to 24-bit mode
|
||
_SwapMMUMode ; go to 24-bit mode
|
||
move.l d0,d2 ; remember the caller's MMU mode
|
||
|
||
movea.l d1,a0 ; set up logical address to get page descriptor
|
||
movem.l @moreRegs,-(sp) ; save registers that GetPageDesc destroys
|
||
bsr GetPageDescProc ; ptr to page descriptor given logical address
|
||
movem.l (sp)+,@moreRegs ; restore registers that GetPageDesc destroys
|
||
movea.l a0,a1 ; save ptr to 24-bit page descriptor
|
||
|
||
moveq.l #true32b,d0 ; go to 32-bit mode
|
||
_SwapMMUMode ; go to 32-bit, return caller's MMU mode
|
||
ENDIF
|
||
|
||
movea.l d1,a0 ; set up logical address to get page descriptor
|
||
movem.l @moreRegs,-(sp) ; save registers that GetPageDesc destroys
|
||
bsr GetPageDescProc ; ptr to page descriptor given logical address
|
||
movem.l (sp)+,@moreRegs ; restore registers that GetPageDesc destroys
|
||
|
||
bclr.b #@wBit,3(a0) ; clear the W bit
|
||
or.l d4,(a0) ; clear/set the write-protect flag
|
||
|
||
IF Supports24Bit THEN ; <SM17>
|
||
tst.b d3 ; should we whack the 24-bit table ?
|
||
beq.s @exit ; if not, we're done
|
||
|
||
bclr.b #@wBit,3(a1) ; clear the W bit
|
||
or.l d4,(a1) ; clear/set the write-protect flag
|
||
@exit
|
||
move.l d2,d0 ; caller's MMU mode
|
||
_SwapMMUMode ; restore the MMU mode <end>
|
||
ENDIF
|
||
@regDone movem.l (sp)+,@saveRegs ; restore registers <T4>
|
||
@noPages
|
||
rts
|
||
EndWith
|
||
EndProc
|
||
|
||
;-------------------------------------------------------------------
|
||
; MMUSetCacheInhibit - Set CI (Cache Inhibit) bit for a page
|
||
;
|
||
; NOTE: On the 040, it is assumed that bit 5 of the page descriptor (CM[0]) is
|
||
; meaningful, since it is used to select write-through/copyback when
|
||
; caching is enabled. For this reason, only bit 6 (CM[1]) is set to
|
||
; disable caching. This will cause some pages to be marked noncachable
|
||
; serialized, and some to be non-serialized. Eventually, we need to
|
||
; maintain globally what the overall caching mode is so that the cache
|
||
; enabling code can set the CM[1:0] bits appropriately.
|
||
;
|
||
; Changed to get both page descriptors first, then whack them in 32-bit mode. <T4>
|
||
;
|
||
; Destroys: none.
|
||
;
|
||
; On entry: d0.l = cache inhibit flag: 0=clear cache inhibit bit(s)
|
||
; 1=set cache inhibit bit(s)
|
||
; d1.l = logical page number
|
||
; a2.l = ptr to MemoryDispatch globals
|
||
;
|
||
; Calls: GetPageDescProc
|
||
;-------------------------------------------------------------------
|
||
MMUSetCacheInhibit Proc Export
|
||
Import GetPageDescProc,MMUSetCacheMode
|
||
With MemDispGlobals
|
||
@saveRegs REG d0-d4/a0/a1
|
||
@moreRegs REG d1/a1/a2
|
||
|
||
cmp.b #PMMU851,MMUType ; do we have at least a 68851 PMMU ?
|
||
blo.w @noPages ; if not, we can't control data caching (020 or less)
|
||
@hasPages
|
||
movem.l @saveRegs,-(sp) ; save registers
|
||
|
||
cmpi.b #EMMU1,MMUType ; Do we have an EMMU?
|
||
bne.s @RealMMU ; -> Nope, sorry
|
||
|
||
MOVE.L D1,A0 ; Put the page number in A0
|
||
ADDI.W #mmuMakePageCacheable,D0 ; Turn the cache mode flag into a nKernel selector
|
||
_KernelVMDispatch ; Set the cache status & flush the ATC
|
||
BRA.S @RegDone ; -> Exit
|
||
|
||
@RealMMU move.l d0,d4 ; remember inhibit flag
|
||
|
||
move.l mdLog2PageSize(a2),d0 ; get the log2 of the page size
|
||
asl.l d0,d1 ; turn logical page number into a logical address
|
||
|
||
IF Supports24Bit THEN ; <SM17>
|
||
cmp.l mdPages24(a2),d1 ; check if page is in the 24-bit address space
|
||
slo d3 ; if it is, be sure to whack the 24-bit table
|
||
|
||
moveq.l #false32b,d0 ; first go to 24-bit mode <T4>
|
||
_SwapMMUMode ; go to 24-bit mode
|
||
move.l d0,d2 ; remember the caller's MMU mode
|
||
|
||
movea.l d1,a0 ; set up logical address to get page descriptor
|
||
movem.l @moreRegs,-(sp) ; save registers that GetPageDesc destroys
|
||
bsr GetPageDescProc ; ptr to page descriptor given logical address
|
||
movem.l (sp)+,@moreRegs ; restore registers that GetPageDesc destroys
|
||
movea.l a0,a1 ; save ptr to 24-bit page descriptor <T4>
|
||
|
||
moveq.l #true32b,d0 ; go to 32-bit mode <T4>
|
||
_SwapMMUMode
|
||
ENDIF
|
||
movea.l d1,a0 ; set up logical address to get page descriptor
|
||
movem.l @moreRegs,-(sp) ; save registers that GetPageDesc destroys
|
||
bsr GetPageDescProc ; ptr to page descriptor given logical address
|
||
movem.l (sp)+,@moreRegs ; restore registers that GetPageDesc destroys
|
||
bsr.s MMUSetCacheMode ; go whack the page descriptor <T3>
|
||
|
||
IF Supports24Bit THEN ; <SM17>
|
||
tst.b d3 ; should we whack the 24-bit table ?
|
||
beq.s @exit ; if not, we're done
|
||
|
||
movea.l a1,a0 ; point to the 24-bit page descriptor <T4>
|
||
bsr.s MMUSetCacheMode ; go whack the page descriptor <T3>
|
||
@exit
|
||
move.l d2,d0 ; caller's MMU mode
|
||
_SwapMMUMode ; restore the MMU mode
|
||
ENDIF
|
||
@RegDone movem.l (sp)+,@saveRegs ; restore registers
|
||
@noPages
|
||
rts
|
||
EndWith
|
||
EndProc
|
||
|
||
;-------------------------------------------------------------------
|
||
; MMUSetCacheMode - code to actually whack the page table entry (Called in 32-bit mode) <T4>
|
||
; <T3>
|
||
; Destroys: None. <start>
|
||
;
|
||
; On entry: d4.l = cache inhibit flag: 0=clear cache inhibit bit(s)
|
||
; 1=set cache inhibit bit(s)
|
||
; a0.l = logical address of page descriptor
|
||
; a2.l = ptr to MemoryDispatch globals
|
||
;-------------------------------------------------------------------
|
||
MMUSetCacheMode Proc Export
|
||
@saveRegs REG d0/d1
|
||
@cacheBit EQU 6 ; C bit for 851/030, CM[1] for 040 (CM[0] untouched)
|
||
@cm0bit EQU 5 ; CM[0] bit in 040 page descriptor
|
||
|
||
movem.l @saveRegs,-(sp) ; save registers
|
||
tst.b d4 ; check the cache inhibit flag
|
||
beq.s @enableCaching ; if clear, enable caching for the page
|
||
move.l (a0),d1 ; get page desc (forces serialization on 040) <T7>
|
||
bset.l #@cacheBit,d1 ; inhibit caching
|
||
bclr.l #@cm0bit,d1 ; make it non-serialized <T7>
|
||
move.l d1,(a0) ; update page descriptor
|
||
bra.s @exit
|
||
@enableCaching
|
||
clr.l d1 ; clear 68040 mask <T7>
|
||
bfextu CacheFlags{31-bCopybackMode:1},d1 ; get current cache mode <T7>
|
||
lsl.l #@cm0bit,d1 ; make a mask for a 68040 page descriptor <T7>
|
||
or.l (a0),d1 ; get page descriptor (forces copyback on 040)
|
||
bclr.l #@cacheBit,d1 ; enable caching
|
||
move.l d1,(a0) ; update page descriptor
|
||
@exit
|
||
movem.l (sp)+,@saveRegs ; restore registers <T3>
|
||
rts
|
||
EndProc
|
||
|
||
|
||
;-------------------------------------------------------------------
|
||
;
|
||
; MMUFlushATC - Flush all entries in the MMU's Address Translation Cache
|
||
;
|
||
;-------------------------------------------------------------------
|
||
MMUFlushATC Proc Export
|
||
cmpi.b #EMMU1,MMUType ; do we have an Emulated MMU?
|
||
beq.s @exit ; -> Yes, do nothing <SM17>
|
||
cmp.b #PMMU851,MMUType ; do we have at least a 68851 PMMU ?
|
||
blo.s @exit ; if not, we're done
|
||
cmp.b #PMMU040,MMUType ; do we have an 040 PMMU?
|
||
beq.s @handle040 ; if so, use 040 PFLUSHA
|
||
pflusha ; use 851 & 030 PFLUSHA
|
||
@exit
|
||
rts ; done
|
||
@handle040
|
||
MACHINE MC68040
|
||
pflusha ; flush the ATC
|
||
MACHINE MC68030
|
||
rts
|
||
EndProc
|
||
|
||
|
||
END
|