mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 01:29:20 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
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
|