;
;	File:		PatchIIciROM.a
;
;	Contains:	patches for the ROMs first shipped in a Macintosh IIci ($067C)
;
;	Copyright:	© 1985-1991 by Apple Computer, Inc., all rights reserved.
;
;	Change History (most recent first):
;
;	   <146>	 12/2/91	SAM		Using official boxflag equates now.
;	   <145>	 12/2/91	pvh		Added cache flushing to fixup patch table code.
;	   <144>	10/28/91	SAM/KSM	Rolled in Regatta Changes.
;
;	Regatta Change History:
;
;		<15>	 8/30/91	SAM		Added a check for Tim boxFlag to the code that changes boxFlag
;									from boxTim to BoxTimLC.  This prevents non-Tim/TimLC machines
;									using the TERROR ROM with power mgrs and no-FPU being identified
;									as a TimLC.
;		<14>	 8/30/91	SAM		Added a check for an FPU in the previous backpatch patch so it
;									will not install on machines without one.
;		<13>	 8/29/91	SAM		Added a check for Zydeco to the "should we remove (ie override)
;									the PACK 4 & 5 SANE rsrcs in ROM" check.  (CCH) Added a patch to
;									_FP68k for 030 TERROR machines that will not allow _FP68k calls
;									made from ROM to be backpatched.
;		<12>	 8/15/91	SAM		(RMP) Added v32SetHandleSize patch. SetHandleSize calls the same
;									common routine that v32SetPtrSize calls, a32SetSize.  SetPtrSize
;									was patched earlier to fix a bug in a32SetSize <121> but
;									SetHandleSize was never patched.
;		<11>	  8/9/91	SAM		Moved the disposal of the Gestalt tables made by ROM to after
;									the reinstallation of Gestalt from disk.  This prevents crashes
;									caused by someone calling gestalt after the old tables have been
;									trashed prior to the new table's creation.
;		<10>	  8/8/91	SAM		(eva) patch level 4 autovector pointed to by vbr, not just the
;									zero-offset cuz when VM is running VBR ­ 0.This routine is a
;									patch to the _VM trap.  It fixes a bug in the Terror ROM which
;									occurs when the page the stack is marked uncacheable in the MMU
;									tables, then a subsequent PFLUSH'd is executed with data still
;									in the cache.
;		 <9>	  8/7/91	SAM		Moved the boxFlag slam before Gestalt. Brainfade.
;		 <8>	  8/6/91	SAM		Added a check for TIM LC that will stuff the correct boxFlag
;									into BoxFlag if we're running on a TIm LC.  Gestalt's private
;									storage allocated by the ROM version is disposed of prior to
;									reinstalling gestalt from the disk.
;		 <7>	  8/5/91	SAM		(eva) fix patch <6>: Port B dispatcher fixed to call serial
;									service routines and to have same number of bytes before the rts
;									so that async serial driver Rx and SCx patches (which fiddle
;									with return address on stack) return to the proper place.
;		 <6>	 7/30/91	SAM		(eva) fix the Farallon MacRecorder bug by modifing patch to test
;									for port A RxChar and loop back only if we are servicing a channel
;									A interrupt. For port B we just jump to service routine like ROM
;									code.
;		 <5>	 7/29/91	SAM		(eva) patched SCx interrupt handler to fix the StyleWriter bug.
;									On faster machines we are able to send out a byte fast enough
;									after the TBE bit in RR0 gets set that the byte gets written
;									before the TBE interrupt is generated. Instead of just not
;									generating the interrupt, the SCC goes ahead and generates it,
;									but changes the interrupt source code to read 'no interrupt'
;									instead of 'TBE'. This 'no interrupt' code is identical to the
;									'Special Condition on port B' code, which was the source of our
;									problem. Fix is to just exit SCIntHnd if no special condition
;									bits are set.
;		 <4>	 7/17/91	SAM		(EH) Added Lvl4 irq patch to improve serial performance.
;		 <3>	 6/30/91	SAM		Conditionalizing the SCSI Chaining Bus Error handler for non
;									C96.
;		 <2>	 6/14/91	SAM		Removed the GestaltHardware patch in favor of the real code in
;									GestaltFunction.a. Fixed a check for an unallocated Palette Mgr
;									handle in the InitPalettes Patch. (RMP) Added the IIfx IOP irq
;									MPW fix to the set of Eclipse fixes. (bg) Changed the Egret
;									"CheckPacket()" patch to allow the full
;									range check of possible pseudo-commands.
;		 <1>	 5/15/91	SAM		Split off from 7.0 GM sources. Added code to use PACK 4 & 5 from
;									disk on IIciROM machines that are not TERROR A7 or newer.  Do
;									not save GestaltÕs old Logical mem size across PtchInst 5
;									(which is Gestalt) cuz the old number is wrong.
;	7.0 Change History:
;
;	   <143>	 9/18/91	JSM		Cleanup header, donÕt include InternalOnlyEqu.a (already in dump
;									file).
;	   <142>	 8/30/91	DTY		Define isUniversal here since itÕs no longer defined in
;									BBSStartup.  This file used to use {Defs32}, so isUniversal is
;									defined to be 1.
;	   <141>	 6/12/91	LN		added #include 'ROMPrivateEqu.a'
;	   <140>	 6/12/91	LN		removed #include 'HardwareEqu.a'
;	   <139>	 4/12/91	dba		ewa: add magic signature to Time Manager task used to implement
;									VBLs; the signature will prevent VM from deferring the task
;	   <138>	  4/8/91	eh		Fixed bug in iop serial driver that was causing bad printing to
;									Imagewriter. Actually, it was two bugs. CTS interrupt disable
;									code had a bad branch and the IOP timer never got kickstarted.
;	   <137>	  4/5/91	eh		Fix to Serial driver SerSetbuf call. Missed one place in <135>
;									that sign extended a register.
;	   <136>	 3/28/91	SAM		As per DarinÕs request, I have added a TestFor	SCSI96_1Exists
;									before the Quantum 7.9 ROM fix from the Regatta deltas (without
;									forRegattaCPUs).
;	   <135>	 3/17/91	eh		Serial driver status calls 9 and $8000 now return hardcoded
;									driver version instead of getting it from DCE. This obviates the
;									need for the linked patch to _Open to patch the version number
;									in the DCE, a fix which was causing FileShare to crash.  Also
;									fixed bug in IOP SerSetBuff (control 9) call -- was sign
;									extending a register unintentionally.
;	   <134>	  3/8/91	DFH		VL,WS#DFH-910308a: Fixed SetEntries patch to not chew on a2.
;									This led to crashes, such as in AfterDark.
;	   <133>	  3/4/91	dba		dty: get rid of SysVers checks
;	   <132>	 2/26/91	DFH		csd,WS#910226a: Fixed bug in ptchPMgrExit where it assumed that
;									graphics has been initialized.  Bug introduced by change <124>.
;	   <131>	 2/25/91	gbm		csd, #83338: Fix the fix to Gestalt. Save the original Gestalt
;									globals pointer, and put some important (but hard to figure out)
;									data back in it after the RAM copy installs
;	   <130>	 2/21/91	gbm		csd, #83338: Start including the Gestalt ptch even on ci ROMs.
;	   <129>	 2/21/91	eh		(djw) Fixed bug in serial driver that was preventing use of one
;									port when Nike was printing on the other.
;	   <128>	 2/19/91	gbm		csd, #Go5 approved: Make sure _MemoryDispatch is NOT implemented
;									on machines without PMMUs.
;	   <127>	 1/29/91	eh		(djw) Fixed a bug in the External Status interrupt handler. On
;									port A we crashed on receiving a break if a read was pending
;									because we weren't getting the .Ain DCE ptr properly. Now we get
;									the DCE ptr directly from the Unit table, just like for port B.
;	   <126>	 1/25/91	eh		Fix iop serial driver to: time out an waiting for all-sent in
;									the close, and to disable HWHS properly when external clocking
;									is set.
;	   <125>	 1/19/91	eh		(djw) Patch async serial bypass driver headers to insert
;									signature longword used by linked patch to Open in Serial
;									Patches.a . Added signature longword before already patch IOP
;									driver headers.
;	   <124>	 1/18/91	dvb		Don't restore color environment if it hasn't been changed.
;									Modify SetEntries to mark flag in QDSpare.
;	   <123>	 1/14/91	eh		(djw) Added external clocking support for the NIke printer to
;									the Async Serial Driver.
;	   <122>	12/19/90	djw		(ewa) Patch ROM SCSIDispatch to the ROM SCSIDispatch to resolve
;									a VM patch conflict.
;	   <121>	12/19/90	TL		Fixed an old bug in setptrsize for old time sake, in calls
;									between relocRel, the tag is restored in the old block, instead
;									of the new block location. And also discard flag when two block
;									sizes are identical.
;	   <120>	12/19/90	dvb		Don't draw windowframes after InitGDevice. Removed some
;									duplicate code between PatchIIciROM.a and PaletteMgr.a.
;	   <119>	12/15/90	djw		(jwk) Add SCSI Mgr support for Quantum 7.9 ROM problem by
;									replacing blind write routine
;	   <118>	12/14/90	dnf		(jsm) Turn all patches on ExtFSHook off for 7.0 since they have
;									been moved to LaterFileMgrPatches.a
;	   <117>	12/14/90	SMC		Patched DisposeAppPalettes via PMgrExit to use ApplZone->bklim
;									instead of HeapEnd to determine if palette is in the application
;									heap.  Also, patched PMgrExit to only throw away palettes if app
;									is front process.  With DFH.
;	   <116>	12/14/90	dba		<JDR> get rid of VMCalls.a
;	   <115>	 12/6/90	BBM		(dba) Protect the Come-from patches. Eleminate TextFont patch to
;									the MDEF, as the MDEF in ROM is not used anymore, RomOverride at
;									its best.
;	   <114>	11/15/90	JSM		<bbm> Move come-from patch on _OpenCPort inside NewGWorld to
;									QuickDrawPatches.a.
;	   <113>	10/31/90	dba		& csd; kill 8¥24 GC loading code for 7.0 (StartSystem.a does it
;									now)
;	   <112>	10/22/90	JJ		Rex V8: Change VISAChipBit to V8ChipBit.
;	   <111>	10/22/90	JJ		Rex V8: Change all box flag references to use boxMacLC. Get rid
;									of boxElsie and boxElsieV8.
;	   <110>	 10/9/90	SAM		Updated the AppleTalk _Open patch so that it stuffs PortNotCf
;									into ioResult if SPConfig >= 2.
;	   <109>	 9/26/90	SAM		Redoing the patch to Open that fixes the .MPP crash.
;	   <108>	 9/25/90	KIP		Change Sound Mgr. to a linked patch.
;	   <107>	 9/18/90	SAM		Added changes from SixPack code review (search for <107>).
;									Removed EclipseNOPs (as per BGs request). Fixed the last of the
;									build warnings for this file (rah).
;	   <106>	 9/15/90	DC		added GetGray
;	   <105>	 9/15/90	GMR		Fixed Gestalt parity routine to set good parity before testing
;									the byte with bad parity, so the RPU interrupt would not cause
;									bad data to be stacked.
;	   <104>	  9/5/90	EH		Removed duplicate declarations for PollProc, Pollstack, and
;									HiIntMask from EgretMgr patch <101>.
;	   <103>	 8/31/90	SAM		Adding fix to ReallocHandle patch that checks to see if SysZone
;									= AppZone and if so it only checks the current heap then jumps
;									back to ROM. Added a patch to open so that it clears out the low
;									nibble of SPConfig when the .MPP driver is opened. Made
;									GestaltHardwareAttr recognize Visa/V8.
;	   <102>	 8/29/90	GMR		Fixed Gestalt parity check on FX so it does not destroy A4 (this
;									reg needs to be preserved throughout patches and inits!)
;	   <101>	 8/22/90	SAM		Adding a series of REgret patches & a SANE ptch (search for
;									<101> for more explicit descriptions).
;	   <100>	 8/20/90	dvb		Remove "DrawGrayishText"
;		<99>	 8/19/90	SAM		Adding changes to make sound (MACE) work on ci ROMs
;		<98>	 8/18/90	dba		get rid of ptchInst 7 and 8 (Sony Format and Eject patches) as
;									they are now linked patches
;		<97>	 8/17/90	gbm		start loading soundmgr patch 23 on erickson and elsie, cause
;									BigBang don't work otherwise
;		<96>	 8/14/90	DTY		Removed TextEditPatchIIciROM since itÕs a linked patch now. (For
;									real this time.) Also deleted an INIT 18 patch for Darin.
;		<95>	 8/13/90	JWK		NEEDED FOR SIXPACK: Added NuBus and Serial Gestalt selectors.
;		<94>	 8/11/90	PKE		NEEDED FOR SIXPACK: Fixed bug in previous revision - (per KIP)
;									ptch 3 must load before ptch 23 so SoundMgr globals are
;									initialized!! Was causing ci & fx to hang during boot.
;		<93>	 8/10/90	SAM		Made ptch 3 (7.0 Sound Mgr) load on all IIciROM machines. It
;									used to *not* load on Erickson/Elsie.
;		<92>	  8/8/90	SAM		Changing DispatchHelper & ProcHelper into an old style ptch.
;									¥¥¥--> Temporary <--¥¥¥ Remove when the Sound ptch get converted
;									into an Lptch.
;		<91>	  8/7/90	PKE		Fixed the SixPack build by adding an eclipseDebug conditional
;									around a BRA.S. Build was broken because BG changed BBSStartup
;									to turn on eclipseDebug for Mac32 (which applies to this file),
;									so EclipseNOPs are expanded and a branch went out of range.
;									Also, altered the previous comment to say needed for SixPack.
;		<90>	  8/5/90	PKE		NEEDED FOR SIXPACK: Moved installation of Script Mgr ptch 39 and
;									27 to Mac and A/UX section of install code (was formerly for Mac
;									OS only). Search for <90> to see changes.
;		<89>	 7/30/90	SAM		Added Egret TickHandler patch so it doesnt loose time while IRQs
;									are off.
;		<88>	 7/30/90	dnf		Remove installation of ptch 18 (File Manager) and ptch 6 (Btree
;									Manager), now linked patches
;		<87>	 7/23/90	dba		get rid of ptch 25 for 7.0; it is covered by DialogMgrPatches;
;									get rid of extraneous pre-6.0.6 SysVers conditionals; removed
;									ptchInst 16 since PrGlue is a linked patch
;		<86>	 7/21/90	BG		Added EclipseNOPs for flakey 040s.
;		<85>	 7/20/90	CSL		Needed for SIXPACK: Totally replaced Memory manager routine
;									a32SetSize, patch <68> only replaced part of a32SetSize and is
;									not sufficient.
;		<84>	 7/20/90	DTY		Removed Bass patches since itÕs a linked patch now.
;		<83>	 7/20/90	gbm		Get rid of some warnings
;		<82>	 7/19/90	CCH		NEEDED FOR SIXPACK: Removed HwPriv patch since it is now a
;									linked patch.
;		<81>	 7/19/90	EH		Add VM support for async.a, SetSerBuf control call
;		<80>	 7/19/90	GMR		Install ptch 7 to change eject track from 79 to 40.
;		<79>	 7/18/90	DDG		NEEDED FOR SIXPACK: Fixed previous comment.
;		<78>	 7/18/90	DDG		NEEDED FOR SIXPACK: clean up lomem $B50 after the netbooting socket
;									listener.
;		<77>	 7/17/90	DVB		Fix DrawGrayishText, and include PaletteMgr.a
;		<76>	 7/14/90	DVB		Add in new PMgr dispatches
;		<75>	 7/11/90	gbm		get rid of a few duplicate symbols
;		<74>	 7/11/90	DDG		NEEDED FOR SIXPACK: Fixed a bug in our new ReadDateTime call. We
;									now return an error code of zero, instead of garbage.
;		<73>	  7/2/90	DTY		Remove ptchInst 21 since Resource Manager extensions are now in
;									a linked patch.
;		<72>	 6/28/90	DDG		NEEDED FOR SIXPACK: Put in a fix for egret. Now the
;									_ReadDateTime call does not actually call the clock chip. It
;									simply reads the low mem global (Time) and returns that. This is
;									OK, since Time is automatically updated. This fix only happens
;									on Elsie and Erickson.
;		<71>	 6/25/90	DTY		Removed ptchInst 9.
;		<70>	 6/25/90	KON		Remove rSwapMMUMode macro 'cause it's in QDHooks.
;		<69>	 6/19/90	VL		Remove ptchinst 29 since MiscPatches is a linked patch now.
;		<68>	 6/14/90	CSL		Needed for Six-Pack.  Fixed _setptrsize problem in memory
;									mananger for 32 bit mode only.  It will not de-reference from
;									address $0 now.
;		<67>	 6/12/90	JSM		Remove PtchInst 33 since PPC Toolbox is a linked patch now.
;		<66>	  6/7/90	EMT		Remove PtchInst 17 since Layer Manager is a linked patch now.
;		<65>	  6/7/90	VL		Remove PtchInst 28 since HelpMgr is a linked patch now.
;		<64>	 5/31/90	DDG		Adding a special system error for machines that donÕt have an
;									FPU.
;		<63>	 5/31/90	DDG		Added the extFS patch from the PatchIIROM.a file. This will fix
;									a strange bug where the wrong error code is being returned from
;									the MountVol call.
;		<62>	 5/29/90	DDG		NEEDED FOR SIXPACK: Changed all the sixpack conditionals from
;									six-point-oh-seven to six-point-oh-six.
;		<61>	 5/17/90	KON		Clear high word of d3 and d4 so compare is done as a word in
;									ResizePalette.
;		<60>	 5/10/90	JSM		AliasMgr now a linked patch, don't install it here anymore.
;		<59>	  5/2/90	CCH		Fixed bug in parity routine for pre-IIci machines with IIci
;									ROMs.
;		<58>	  5/1/90	CCH		Added Scrolling throttle and Square menus to misc selector.
;		<57>	 4/22/90	csd		commented out the installation of SCSI DMA so we stop trashing
;									hard disks on the IIfx.
;		<56>	 4/19/90	NB		Add PrGlue to the PtchInst list (#16). It's already on all other
;									machines
;		<55>	 4/18/90	DDG		Rolling in the ReallocHandle patches from the sys6 sources.
;		<54>	 4/16/90	DDG		Rolled over changes from the split off sources including: a
;									patch to hwPriv, an IOP serial driver fix, SCSI DMA is now
;									disabled on the IIfx due to bugs, added an init (18) to fix the
;									comm toolbox, added the patch for tiburon video cards, added
;									patch 25 (generic system fixes), and finally changed the equate
;									for spline fonts to use the build variable hasSplineFonts.
;		<53>	 4/11/90	dba		move PPC after B-Tree Manager; get rid of old AppleShare patch
;									for 7.0
;		<52>	 3/30/90	DVB		Add "WhatPal" PmgrDispatch
;		<51>	 3/27/90	PKE		Deleted import (currently conditionalized out) of NewSwapIcon,
;									which no longer exists in this PTCH.
;		<50>	 3/26/90	PKE		Moved definition of symbols that control Script Mgr patch and
;									'ptch' installation into ScriptPriv.a. Renamed symbols and added
;									some.
;		<49>	 3/23/90	NC		Added ptch 43 for System 6.0.6 on up. This is for Sound.
;		<48>	 3/20/90	DDG		Added code to not install patch 3 on Ericksons and above for
;									Sys607 and above.
;		<47>	 3/12/90	DVB		Fix PMgrExit so that ExitToShell doesn't crash!
;		<46>	  3/8/90	JAL		Took out include of QuickEqu.a because it is already in
;									StandardEqu.d.
;		<45>	  3/4/90	PKE		Changed _UprText to _UpperText to match new Traps.a.
;		<44>	  3/1/90	GMR		Fixed bug in Gestalt parity check for Zone-5, where longword was
;									not being written back with good parity after each SIMM check.
;		<43>	 2/28/90	GMR		Added include of EgretEqu.a to fix system disk build.
;		<42>	 2/28/90	PKE		For 7.0, moved Script Mgr ROM patches into ÔptchÕ 39: patches to
;									_Pack6 and _GetIndADB, fixes to String2Date/InitDateCache,
;									installation of some new vectors, and the change to SwapIcon.
;									For all of these except the SwapIcon change, the code is still
;									here but conditionalized differently (in case we need it for
;									6.1).
;		<41>	 2/26/90	EH		Rewrote <8.7> to use patch macros. Added on patch for 68000 IOP
;									Serial Driver read bug.
;		<40>	 2/23/90	DVB		PMgrExit no longer clears the windowlist.
;		<39>	 2/22/90	PKE		Replaced obsolete _LwrStringToUpr opword with _UprText. Removed
;									setting of temporary sVectFixSpExtra vector (see <12>); we no
;									longer need it.
;		<38>	 2/21/90	JS		NEEDED FOR 6.0.5: SetDepth also takes a mode
;		<37>	 2/16/90	EH		Fixed CTS status bug and low baud rate bug in IOP Serial Driver.
;									Fixed <27> to use the patch macros properly.
;		<36>	 2/15/90	EMT		Moved <1.9> before <1.2> - both patch SetWinColor, SetCtlColor.
;		<35>	 2/15/90	DVB		Change SetDepth's return to OSErr
;		<34>	 2/14/90	DVB		Fix SetDepth's register trashage
;		<33>	 2/14/90	EH		NEEDED FOR 6.0.5: 'Come from' patched IOPMoveData trap to fix
;									IOP Serial Driver DMA hang bug.
;		<32>	 2/14/90	CCH		NEEDED FOR 6.0.5 - Made sure external cache on Zone 5 does not
;									interfere with the check to see if parity RAM is installed.
;		<31>	 2/13/90	SMB		NEEDED for 6.0.5 - Added installation code for ptchGetLRPosition
;									and ptchPixelWidths for TextEdit.
;		<30>	  2/9/90	EH		NEEDED FOR 6.0.5: Patched Level4SccIopInt to set flags such that
;									all the IOP completion routines be called immediately from the
;									IOP Manager, rather than be run as deferred tasks. This, so we
;									don't break Timbuktu/Remote.
;		<29>	  2/2/90	JWK		NEEDED FOR 6.0.5: Changed SCSI Mgr bus error handler to allow
;									chaining to previously installed handler if a non-SCSI bus error
;									occurs.
;		<28>	  2/2/90	GGD		NEEDED FOR 6.0.5: Modified the Deferred Task Manager to enable
;									interrupts when returning just so QuickMail servers will
;									continue to work (their bug, but we'll fix them for now).
;		<27>	 1/31/90	EH		NEEDED FOR 6.0.5: 'Come from' patched IOPMsgRequest trap to fix
;									IOP serial driver control call bug
;		<26>	 1/30/90	CCH		NEEDED FOR 6.0.5: Modified gestaltHardwareAttr patch to set
;									gestaltHasSCC bit in result if in IOP bypass mode.
;		<25>	 1/29/90	GGD		NEEDED FOR 6.0.5, Adding a temporary patch to make cmd-period
;									not hang the MPW shell on Zone-5, until the shell can be reved
;									to fix the real problem.
;		<24>	 1/29/90	DVB		NEEDED FOR 605 - Add PMgrVersion call
;		<23>	 1/25/90	KON		NEEDED FOR 6.0.5: QDversion is offscreenVersion + $100, not
;									$200.
;		<22>	 1/23/90	KON		NEEDED FOR 6.0.5: Gestalt now gets the Quickdraw version from
;									GWorld Offscreen version and adds 200.
;		<21>	 1/23/90	DVB		NEEDED FOR 6.0.5 - Add HasDepth and SetDepth PMgr Dispatches
;		<20>	 1/22/90	CCH		NEEDED FOR 6.0.5 - Added notification mgr selector.
;		<19>	 1/19/90	JWK		NEEDED FOR 6.0.5 - Turn on SCSI DMA code in Zone5 final ROM's.
;		<18>	 1/18/90	DVB		Include PalettePriv.a
;		<17>	 1/17/90	CCH		NEEDED FOR 6.0.5: moved restoration of cache register in parity
;									check routine.
;		<16>	 1/16/90	SMB		NEEDED FOR 6.0.5: added install code for         TENew and
;									TEStylNew	patch and included TextEditPriv.a.
;		<15>	 1/16/90	CCH		NEEDED FOR 6.0.5:  Turn off cache when checking RPU for parity.
;		<14>	 1/16/90	KON		NEEDED FOR 6.0.5: Added ptch 26
;		<13>	 1/12/90	CCH		Added include of ÒHardwarePrivateEqu.aÓ.
;		<12>	 1/11/90	PKE		Initialize Script Manager's new sVectFixSpExtra vector.
;		<11>	 1/11/90	DVB		Remove _Zaplinks macro.
;		<10>	  1/8/90	CCH		Added gestaltMiscAttr selector.
;		 <9>	  1/5/90	GMR		Added ptchInst 8; Sony Format patch is now in it's own patch
;									file (FormatPatch.a).
;		 <8>	  1/5/90	CCH		NEEDED FOR 6.0.5.  Added parity support for Zone 5, removed base
;									address selectors.
;		 <7>	  1/4/90	BBM		NEEDED FOR 6.0.5.  Make the new sound manager patch out the rom
;									on all machines.
;		 <6>	  1/4/90	PKE		NEEDED FOR 6.0.5 (smb's changes from SS-6.0.4b23 to SS-6.0.4f1):
;									¥ Add install code for TEFindLine patch. ALSO: Updated
;									conditionals so SS-6.0.4 changes go in 6.0.5 as well as 7.0.
;									Cleaned up the BBS header and eliminated the EASE header.
;		 <5>	  1/3/90	BAL		NEEDED FOR 6.0.5: Fixed Zero width character problem in
;									drawtext.
;		 <4>	12/19/89	EH		REALLY fix the pound signs!
;		 <3>	12/19/89	EH		try to fix the pound signs!
;		 <2>	12/19/89	EH		NEEDED FOR 6.0.5: Fix bug in 7.1 async patch; switched registers
;		 <1>	12/17/89	CCH		Adding for the first time into BBS.
;	   <8.8>	12/14/89	SWC		NEEDED FOR 6.0.5: Added RecoverHandle patch to also check if the
;									pointer points to a ROM resource. Removed the NewSCSI trap
;									initialization since async SCSI will not be in Zone 5 until 7.0
;									or later.
;	   <8.7>	12/14/89	EVA		NEEDED FOR 6.0.5 Fix SerialDriver.a patch to check SCCIOPFlag
;									instead of PRAM to see which driver to load
;	   <8.6>	12/11/89	smb		NEEDED FOR Scripts 604 AND (6.0.5 <= SysVers < 7.0): added
;									installation code for TE routines CaretInsideRun,
;									InvrtRectangle, SetKeyboard2Font.
;	   <8.5>	 12/8/89	PKE		NEEDED FOR Scripts604 AND FOR (6.0.5 <= SysVers < 7.0): Patch
;									LwrString to handle 2-byte chars via Transliterate (yuck). For
;									7.0, we do this elsewhere.
;	   <8.4>	11/29/89	GGD		NEEDED FOR 6.0.5: Re-Enabled the SANE optimization to bypass the
;									Package Manager which never made it into 6.0.4. Fixed bug
;									StripAddress that caused it to sometimes not strip when in a
;									interrupt handler. Modified ADB auto/srq polling to not poll
;									device addresses that are not in the device table. On OSS based
;									machines, install a time manager task to simulate a 60.15Hz
;									pseudo VBL because the OSS generates a 60.00Hz interrupt which
;									is the wrong frequency.
;	   <8.3>	11/28/89	dvb		Fixed bug in PMgr Zaplinks by working over pmgrDispatch. Also
;									fixed bug in dispatch.
;	   <8.2>	11/22/89	EMT		NEEDED FOR 6.0.5: Added humane scrolling.
;	   <8.1>	11/21/89	smb		Added installation code for TE routines ptchGetWidth and
;									ptchGetRLPosition.
;	   <8.0>	11/17/89	PKE		Tail patch on _GetIndADB to fix Script Mgr SwapKybd routine,
;									which cleared ADB keyboard driver dead state as a word: should
;									be a long.
;	   <7.9>	11/10/89	KON		PTCH'ed GetNewCWindow so when a palette with the same ID as the
;									window exists in the resource file, the palette is attached to
;									the window.
;	   <7.8>	 11/6/89	PKE		NEEDED FOR 6.0.5!! Bug fixes for InitDateCache and String2Date
;									needed for HyperCard. InitDateCache: Fixed CopyArray to use
;									correct register (A4) for source pointer, and to initialize all
;									relevant bytes of length register (D0). String2Date: if first
;									relevant (i.e., day or month name) alpha token is a month name,
;									we now search the day name list if we find another alpha token
;									(fixes BRC #54946). Rearranged Cache structure to fix invalid
;									use of month/day name index.
;	   <7.7>	10/12/89	smb		Moved TextEdit patches to TextEditPatchIIciROM.a. Fixed bug in
;									old highlighting code that I introduced accidently (changed
;									move.w -> move.l).
;	   <7.6>	10/11/89	CCH		Added INCLUDE of "MMUEqu.a"
;	   <7.5>	10/11/89	CCH		Set up MMUType if not already initialized.
;	   <7.4>	 10/6/89	JSM		Removed SnarfMan 'ptch', now PACK 13.
;	   <7.3>	 10/5/89	CCH		Changed an ORI to a BSET in gestaltAddressingModeAttr patch, and
;									added installation of it.
;	   <7.2>	 10/5/89	smb		Added old highlighting code for TextEdit for HyperCard
;									outlining.
;	   <7.1>	 10/5/89	EVA		NEEDED FOR 6.0.5!!! Fixed bug in async serial driver Ext/Stat
;									int handler
;	   <7.0>	 10/4/89	smb		Fixed 6.0.4 build by moving around some of my conditionals due
;									to dependencies! Fixed TEInit to set TEDoText like it used to.
;									Cleaned up TEOutlineHilite. Fixed caret display for outline
;									highlighting.
;	   <6.9>	 9/29/89	CCH		Added patch for gestaltAddressingModeAttr selector to add
;									gestalt32BitCapable attribute. (version 6.8 breaks 6.0.4 builds,
;									so I just tested on bigbang - because alpha 0 is in two days,
;									thats why)
;	   <6.8>	 9/29/89	smb		Added patches for TextEdit for TEFeatureFlag, SetFont2Keyboard,
;									and fixed CursorMovement for double-byte characters.
;	   <6.7>	 9/27/89	EMT		Fixed 6.2 to use Lea rather than LeaROM for RAM address.
;	   <6.6>	 9/26/89	CVC		Added PPC Toolbox as a 'ptch'.
;	   <6.5>	 9/25/89	EMT		Added ptchs 18, 6, 29.
;	   <6.4>	 9/19/89	RLC		Add Balloon Help (ptch 28) to this file.
;	   <6.3>	 9/18/89	BBM		Install resource manager extensions, ptch 21
;	   <6.2>	 9/18/89	PKE		For 7.0, patch Script Manager internal routine SwapIcon to use
;									new 'kscn' resource type instead of 'SICN'.
;	   <6.1>	 9/17/89	PKE		Decided to patch out GetScript/SetScript entirely in ptch 27, so
;									we no longer patch them here (see 5.9). Also, for 7.0 we now
;									install the Script Manager's Gestalt function in ptch 27 instead
;									of here (see 2.5).
;	   <6.0>	 9/12/89	EMT		PaintOne patch (3.7) nukes the layer manager. Only use on pre
;									7.0 systems.
;	   <5.9>	  9/6/89	PKE		Patch Script Manager GetScript/SetScript routines to support
;									additional font info verbs for 7.0, and set up this font info in
;									Roman ScriptRecord. Set new sVectCallInterface vector. Redo
;									Script Manager version setup, using new smgrVersPTCHRom equate.
;	   <5.8>	  9/5/89	jwk		NEEDED FOR 6.0.5: Turn on NewSCSI in ROM if on F19.
;	   <5.7>	  9/4/89	PKE		Install Script Manager 7.0 extensions, ptch 27. Set Script Mgr
;									version for 7.0.
;	   <5.6>	 8/31/89	JSM		Added SnarfMan support.
;	   <5.5>	 8/30/89	smb		NEEDED FOR Scripts604 and Big Bang! Bug fix in ptchTEFindWord
;									(fixed word dragging bug and now uses old FindWord code when
;									RecalLines calls. Also added ptchMeasureWidth to fix a
;									hilighting bug at line ends when the line direction is RL on a
;									system that is normally LR (ie - Roman, Kanji, etc.)
;	   <5.4>	 8/28/89	PKE		For 7.0, initialize additional Script Mgr vectors for
;									SMgrCalcRect and SMgrInitFonts.
;	   <5.3>	 8/27/89	PKE		NEEDED FOR Scripts604, 6.0.5: Bump Script Manager version for
;									Scripts604 or SysVers > $604, since IntlForce bug fix (4.5) is
;									installed.
;	   <5.2>	 8/22/89	PKE		NEEDED FOR 6.0.4: (really dba) Tail patch to TextFont which
;									fixes an MDEF bug in calculating the icon height. Replaces
;									GetResource patch in 3.7 which attempted to fix the same
;									problem.
;	   <5.1>	 8/21/89	PKE		NEEDED FOR 6.0.4: Really put in 4.1, which was only present as a
;									comment until now (although it existed on Fiction sources).
;	   <5.0>	 8/21/89	PKE		NEEDED FOR 6.0.4: (really CSD) Fixed MDEF 3.7 patch (again. Last
;									time, right?) to load #$00200020 into D1 when appropriate
;									instead of jumping back into ROM at the same place for both
;									cases cicn found and cicn not found.
;	   <4.9>	 8/21/89	PKE		NEEDED FOR 6.0.4: (really dba) Changed MDEF patch 3.7 to load A0
;									with the right value instead of preserving its value.
;	   <4.8>	 8/21/89	PKE		NEEDED FOR 6.0.4: (Per CSD) Correct ROMNoColor address in MDEF
;									patch (part of 3.7).
;	   <4.7>	 8/21/89	PKE		NEEDED FOR 6.0.4:
;								¥	(per dba) Only re-load the standard clut into QDColors if
;									QDColors exists; this is so that A/UX will work
;								¥	Conditionalize 4.5 for Scripts604 OR (SysVers > $604)
;	   <4.6>	 8/21/89	PKE		NEEDED FOR 6.0.4!: Patch RelString,UprString,CmpString to
;									re-introduce the bug in which "`" is converted to uppercase as
;									"a". This is necessary to prevent HFS problems, since existing
;									disk catalogs use the old, buggy sorting. Also remove SANE
;									optimization (2.0); breaks Excel.
;	   <4.5>	 8/21/89	PKE		NEEDED FOR 6.0.4 SCRIPTS BUILD, 6.0.5: Extend Pack6 patch to fix
;									a problem in LwrString,CharType,Transliterate,FindWord. These
;									routines should save the IntlForce flags then clear them before
;									the IUGetIntl call, restoring the flags afterward. This is so we
;									get the itl2 tables for the correct script (instead of the
;									tables for the system script).
;	   <4.4>	 8/21/89	PKE		NEEDED FOR 6.0.4!: Fixed accidental deletion of INCLUDE
;									'VideoPatch.a' in (4.3).
;	   <4.3>	 8/21/89	PKE		NEEDED FOR 6.0.4!!: Patch Pack6 to fix me-too problem with
;									pointer to unlocked handle in Transliterate; affects Roman
;									system (this problem looks familiar; did I dream that I already
;									fixed this one?).
;	   <4.2>	 8/18/89	smb		NEEDED FOR 6.0.4: Another unlocked handle problem!
;									AAAARRRRRGGGGHHHHHH! (See ptchOnSameLine below)
;	   <4.1>	 8/18/89	DAF		FOR 6.0.4 BUILD - Fixed a bug on non-CLUT devices in the
;									SaveEntries trap on Aurora
;	   <4.0>	 8/16/89	dba		NEEDED FOR 6.0.4: InitProcMenu bug fixed: MBDF ID was not put in
;									MenuList if MenuList was already allocated (InitMenus already
;									called)
;	   <3.9>	 8/15/89	prp		Added Alias Manager and Folder Manager support.
;	   <3.8>	 8/15/89	smb		NEEDED FOR 6.0.4: Fixed some problems in my patch code for the
;									bad pointer bug.
;	   <3.7>	 8/15/89	dba		NEEDED FOR 6.0.4:
;								¥	Shortened the SetWin/CtlColor patch by returning to ROM earlier.
;								¥	Patch PaintOne to do nothing if WWExist is non-0.
;								¥	Patch OpenCPort so that the current port is saved across
;									NewGWorld.
;								¥	Patch GetResource so that GetIconSize in MDEF does not trash A0.
;								¥	Moved VideoPatch.a so that it does not happen on A/UX.
;								¥	Re-load the standard clut into QDColors so that the green channel
;									is fixed
;	   <3.6>	 8/14/89	djw		NEEDED FOR 6.0.4: Fixed bug in slot mgr in pInitEntry routine.
;									When calling _InsertSRTRec, and the sRsrc has a refnum
;									associated with it, _sFindDevBase has bad spId.
;	   <3.5>	 8/13/89	BAL		NEEDED FOR 6.0.4: Added tail patch to InitPalettes to defeat
;									spurious ExitToShell patching code (leftover from JP builds).
;									(dvb really)
;	   <3.4>	 8/11/89	smb		Finally rolled in patches for a bad pointer bug (#51602) and an
;									up & down arrow keys bug (#51961). See comments below.
;	   <3.3>	 8/11/89	djw		NEEDED FOR 6.0.4: Cleaned up file by deleting old comments,
;									adding new comments, laying out patches in a "prettier" and more
;									orderly format. Added A/UX runtime conditional check for
;									Mac-only patches. Moved patches <2.4> and <2.7> to Mac OS only.
;									Modified slot manager calls in patche <2.1> as per code review.
;	   <3.2>	  8/9/89	CCH		NEEDED FOR 6.0.4: Added patch to gestaltQuickdrawVersion to
;									return two digit versions.
;	   <3.1>	  8/8/89	smb		NEEDED FOR 6.0.4: Reverted TEFindWord patch since the previous
;									patch introduces an uglier bug that won't be fixed now. Also
;									added gestalt function for TE.
;	  <¥3.0>	  8/8/89	dba		RealityÕs hard disk was full! Try submitting again.
;	   <3.0>	  8/8/89	dba		NEEDED FOR 6.0.4: added Menu Manager patches; InitProcMenu patch
;									because it simply didnÕt work; MenuSelect patch to reinstate
;									WaitMouseUp check
;	   <2.9>	  8/8/89	PKE		NEEDED FOR 6.0.4: In gestaltScriptMgr function, if gestalt
;									selector is undefined, just leave gestalt result alone.
;	   <2.8>	  8/8/89	smb		NEEDED FOR 604: Added more TE patches for Aurora!
;	   <2.7>	  8/7/89	GGD		Changed SIntInstall again, to leave $FF as highest priority, but
;									reverse handling of equal priorities. Modified to use less
;									space. Changed GetBoardROM from <2.4> to be a ROM Offset,
;									instead of absolute ROM address.
;	   <2.6>	  8/6/89	DAF		FOR 6.0.4 BUILD - Added TFB video card driver override for boot
;									screen. This is the same code as is included in PatchIIROM.a
;									(VideoPatch.a)
;	   <2.5>	  8/5/89	PKE		NEEDED FOR 6.0.4: Add Gestalt function for Script Manager,
;									install corresponding Gestalt selectors.
;	   <2.4>	  8/4/89	djw		NEEDED FOR 6.0.4: Deleted patch <1.3> (no longer needed). Added
;									code to re-init board id's in slot pram (fixes a bug in Aurora
;									in InitPRAMRecs).
;	   <2.3>	  8/2/89	EVA		(forgot to) include hardwareEqu.a and SlotMgrEqu.a
;	   <2.2>	  8/2/89	EVA		FOR 6.0.4 (and above) Patched _SIntInstall to reverse slot
;									interrupt queueing order
;	   <2.1>	  8/1/89	CSD		FOR 6.0.4: Added patch to suppress appleshare arrows on 32-bit
;									video cards.
;	   <2.0>	 7/26/89	GGD		NEEDED FOR 6.0.4 Added SANE optimization to bypass the package
;									manager
;	   <1.9>	 7/25/89	DAF		FOR 6.0.4 BUILD - Fixes for SetWinColor, SetCtlColor in 32-bit
;									mode
;	   <1.8>	 7/25/89	smb		NEEDED FOR 6.0.4: Added TextEdit patches for Aurora.
;	   <1.7>	  7/3/89	NJC		Sound Manager Extensions (ptch 23) rolled in for real.
;	   <1.6>	 6/21/89	NJC		Added a ptchinst 3 to if it wasn't already there and added in a
;									commented-out ptchinst 23 for the sound dispatcher,DJ, and S.M.
;									enhancements.
;	   <1.5>	 5/31/89	CEL		Only defined Spline_Font variable if it is undefined - makes it
;									easier to build test 6.0.4 systems
;	   <1.4>	 5/22/89	AG		Fixed my mistake in gettrapaddress call
;	   <1.3>	 5/21/89	AG		Remove NEW SCSI manager trap (A089)
;	   <1.2>	 5/13/89	EMT		Added Window Manager extensions (Layers).
;	   <1.1>	  5/3/89	CEL		Rolling in Bass for the first time into EASEÉ
;	   <1.0>	  3/6/89	CCH		Adding to EASE for first time.
;___________________________________________________________________________________________________
;	To Do:
;
;___________________________________________________________________________________________________

	IF (&TYPE('SPLINE_FONT') = 'UNDEFINED') THEN
SPLINE_FONT		EQU		hasSplineFonts			;<1.1-4april89-CEL>  <DDG>
	ENDIF

	IF (&TYPE('Scripts604') = 'UNDEFINED') THEN
Scripts604		EQU		0						;<4.7><08/21/89 pke>
	ENDIF

	if (&type('isUniversal') = 'UNDEFINED') then
		isUniversal:	equ	1					; <142> Define isUniversal here instead of BBSStartup
	endif
	
			BLANKS  ON
			STRING  ASIS
			MACHINE	MC68020						; changed from MC68000 to MC68020 <24July89smb>
			MC68881

			LOAD 		'StandardEqu.d'			;
			INCLUDE		'PatchMacros.a'
			INCLUDE		'SlotMgrEqu.a'			;<2.3>
			INCLUDE		'HardwarePrivateEqu.a'
			INCLUDE		'UniversalEqu.a'		;<7.1>
			INCLUDE 	'VideoEqu.a'
			INCLUDE 	'ROMEqu.a'
			INCLUDE		'MMUEqu.a'				;<7.6>
			Include		'ScriptPriv.a'			;
			INCLUDE		'GestaltEqu.a'			;
			INCLUDE		'GestaltPrivateEqu.a'	;
			INCLUDE		'TextEditPriv.a'		; <1/16/90smb> <16>
			INCLUDE		'PackMacs.a'			;
			INCLUDE		'InternalMacros.a'		; <54>

			INCLUDE		'PaletteEqu.a'			;
			INCLUDE		'PalettePriv.a'
			INCLUDE 	'ApplDeskBus.a'			; <8.0>
			INCLUDE		'EgretEqu.a'			; <43>
			INCLUDE		'IOPEqu.a'				; <8.4>
			INCLUDE		'AppleDeskBusPriv.a'	; <8.4>
			INCLUDE		'SCSIEqu.a'				; <19>
			INCLUDE		'SCSIPriv.a'			; <19>

			include		'ColorEqu.a'
			INCLUDE		'QDHooks.a'

TERRORmajorVers	EQU		$067C					; TERROR major ROM version
TERRORminorVers	EQU		$15						; TERROR ROM minor version number
ZYDECOminorVers	EQU		$17						; Zydeco ROM minor version number

; The following symbols are defined in ScriptPriv.a. They control whether			<50>
; various Script Mgr patches are resident and installed here (since many
; are also included in 'ptch' 39 or 27), and also control installation of
; Script Mgr 'ptch' resources.
;
;	doScriptMgrGestalt			; in ptch 27
;	doScriptMgrPack6Fix			; in ptch 39
;	doScriptMgrStr2DatFix		; in ptch 39
;	doScriptMgrRstKCHRFix		; in ptch 39
;	doScriptMgrLwrString2		; in ptch 27
;	doScriptMgrSetROMVers		; in ptch 39
;	doScriptMgrNewVectors		; in ptch 39
;	installScriptMgrPtch27
;	installScriptMgrPtch39
;
;-------------------------------------------------------------------------------

ROM67CFix	PROC    	EXPORT
			IMPORT		PatchInit
			EXPORT		StartPatch,CutBack

; Cut back Code:
;
; StartPatch is the entry point for ROM67CFix.  Upon entry D1.L contains our handle.
;

StartPatch
            Bra	    PatchInit	; Carry out the patches			<1.1-4april89-CEL>
			DC.B    'PTCH'		; resource type
            DC.W    $67C		; patch ID $67C.
            DC.W    1			; current version number.

; cut back the ram-based system code to exclude this initialization code
; d0 = size to cut patch down to (EndOfPatch - StartPatch)
; a0 = handle to this PTCH resource (passed into StartPatch in D1 from SysPatch)

CutBack
			_SetHandleSize		; adjust our size				<1.1-4april89-CEL>
            MOVEQ   #$7F,D0	    ; a soon to be large number
            SWAP    D0
            _CompactMem	,SYS	; of course there must be a comma!
            RTS					; all done
			ENDPROC				; <24July89smb>



;=========================================================================================
;=========================================================================================
;=																						 =
;=					RESIDENT PATCH INSTALL CODE IS BELOW THIS POINT						 =
;=																						 =
;=	Add patch code which remains resident in the system in the following section.  The	 =
;=	installation code for the resident patches are further down in the file.  Please	 =
;=	begin your patch code with a header which serves to delimit your code from the		 =
;=	previous person's patch code.  Use another patches header as an example.  Leave at	 =
;=	least 2 or 3 blank lines between your code and the next code.  Be sure to be careful =
;=	about your conditionals.  The safest thing to do is to make your code self-contained =
;=	and not depend on someone elses conditionals encompassing your code.				 =
;=																						 =
;=	To find a place to insert your resident patch code, search for 'EndOfPatch'			 =
;=																						 =
;=						Please be neat and follow the format							 =
;=									Drive safely										 =
;=																						 =
;=========================================================================================
;=========================================================================================

;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
;********************** PaletteMgr Patches Start Here ************************
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
			INCLUDE		'paletteMgr.a'


ptchInitPalettes	PROC	EXPORT
RomInitPalettes		EQU		$3E1F0
; <dvb 8 August 1989> 3.5
; This neutralizes some spurious code in InitPalettes that patches ExitToShell
; the first time [InitPalettes is called and MultiFinder is active]. We depend
; on getting at least one InitPalettes before MultiFinder (from INIT 31).
			JSRRom	RomInitPalettes			; Call the old one.
			MOVE.L	PMgrHandle,A0			; A0 = handle to pm globals
			MOVE.L	A0,D0					; Are we a pmgr?
			BEQ.S	ptchIPEnd				; No=>bye.
			CMPI.L	#-1,D0					; Is it -1?								<2>
			BEQ.S	ptchIPEnd				; -> Yes, bail out.						<2>
			MOVE.L	(A0),A0					; A0->pm globals
			TST.L	OldExitToShell(A0)		; Has it been patched yet?
			BNE.S	ptchIPEnd				; Yes => do nothing
			MOVE	#1,OldExitToShell(A0)	; Put something there; pretend its patched

ptchIPEnd	RTS
			ENDPROC


;-------------- Start of PMgrDispatch patch added by dvb 28Nov89 <8.3> --------------------


							PROC
							EXPORT	ptchPMgrDispatch,pMgrProcs,pMgrProcsEnd
							IMPORT	SetDepth,HasDepth,PMgrVersion
							IMPORT	SetPaletteUpdates,GetPaletteUpdates,CheckColors
							IMPORT	GetGray

RomEntry2Index				EQU		$3E8C0
RomIndex2Entries			EQU		$3E9A0
RomDeltaRGB					EQU		$3CBF0
RomNewHiliteColor			EQU		$3F8D0
RomPMgrExit					EQU		$3DAA0
RomSaveFore					EQU		$3F910
RomSaveBack					EQU		$3F914
RomRestoreFore				EQU		$3F970
RomRestoreBack				EQU		$3F98E
RomReinstantiateColors		EQU		$3F9B0		;this routine should do something heh heh
RomReleaseList				EQU		$3F9C0
RomPMgrDispatch				EQU		$3FA36
RomPMgrFinalError			EQU		$3FA4A
RomRestoreDeviceClut		EQU		$3F8A0
RomResizePaletteplusEight	EQU		$3F818
RomFindLink					EQU		$3E460
RomUnhookAfterZapLinks		EQU		$3F61E
RomUnhookGoHome				EQU		$3F642

RomZapLinksAtA				EQU		$3F70A

;ctReserveBit	EQU	6

ptchResizePalette
;---------------------------------------------------
;
; PROCEDURE ResizePalette(srcPalette:PaletteHandle; dstSize:INTEGER); AAA2/3;
;
; Set the number of entries in the palette, and properly dispose of some
; of them if the palette is shrinking.

;ResizePalette	PROC	EXPORT
RPVars		RECORD		{A6Link},DECREMENT
result		DS.B		0						; Result: none
srcPal		DS.B		4						; input: palette handle
dstSize		DS.B		2						; input: new size for palette
return		DS.B		4
A6Link		DS.B		4						; old contents of A6

linkSize	DS.B		0						;linky number
			ENDR

			WITH	RPVars
			LINK	A6,#linkSize
			MOVEM.L	A2/D3-D4,-(SP)				; save 'em.
			moveq	#0,d3						;<KON 17May90>
			move.l	d3,d4						;<KON 17May90>
			JMPRom	RomResizePaletteplusEight

ptchZapLinks
; Following code is spliced out of CQD:PaletteMgr.a		<dvb>
; ROM67C: Zaplinks bug is that it doesn't clear the ctReserve bit if its
; not on the main screen. Zaplinks is called by Pillage, UnreserveDevices,
; and ReleaseList. Pillage and UnreserveDevices end up clearing the bit
; themselves, so only ReleaseList must be patched here.
;

ZLVars		RECORD		{A6Link},DECREMENT
result		DS.B		0						;Result length: none
myIndex		DS.B		2						;Input: device number and index to unlink
return		DS.B		4
A6Link		DS.B		4						;old contents of A6

linkSize	DS.B		0						;linky number
			ENDR

			WITH		ZLVars

			LINK		A6,#linkSize
			MOVEM.L		A0-A2/D0-D4,-(SP)

			MOVE.L	PMgrHandle,A1
			MOVE.L	(A1),A1					; A1->PMgrData
			LEA		LinkTabs(A1),A0			; A0->Link Tables
			MOVE.L	PListHandle(A1),A2		; A2 = palette list handle
			MOVE.L	(A2),A2					; A2 -> palette info list
			MOVE	myIndex(A6),D0			; D0 = tricky link
			AND		#$1FFF,D0				; clear key bits

			MOVE	D0,D1
			LSR		#8,D1					; D1 = device number
			MOVE.L	DevHandles(A1,D1*8),A1	; A1 = device handle
			MOVE.L	(A1),A1					; A1->device
			MOVE.L	gdPMap(A1),A1			; A1 = pixmap handle
			MOVE.L	(A1),A1					; A1->pixmap
			MOVE.L	pmTable(A1),D1			; D0 = color table for this device
			BEQ.S	@a						; Skip this if none
			MOVE.L	D1,A1					; A1 = color table handle
			MOVE.L	(A1),A1					; A1 -> color table
			CLR		D1
			MOVE.B	D0,D1					; We need to clear the upper bits
			CMP		ctSize(A1),D1							; Index in range?		<fixed>
			BHI.S	@a										; No=>skip this
			BCLR	#ctReserveBit,ctTable+value(A1,D1*8)	; unreserve!

@a			JMPRom	RomZapLinksAtA			; return to ROM code



;---------------------------------------------------
;
; PROCEDURE PMgrExit; AAA2/12;
;
; Someone should call here when an application quits. Please.
;
ptchPMgrExit

PXVars		RECORD		{A6Link},DECREMENT
result		DS.B		0						;Result: nothing
return		DS.B		4
A6Link		DS.B		4						; old contents of A6
frontPSN	DS.B		8						; a 64-bit process serial number
myPSN		DS.B		8						; likewise
inFront		DS.B		2						; a boolean
linkSize	DS.B		0						; linky number
			ENDR

ROMINTOPMGREXIT	EQU		$3DAB2

			WITH	PXVars
			MOVE.L	WindowList,-(SP)			; Save the windowlist value
			LINK	A6,#linkSize

			TST.B	QDExist					; if InitGraf has not been called yetÉ
			BNE.S	@doNothing				; (a5) not valid and there is nothing to do
			CMP.L	#PMgrNil,PMgrHandle		; If the palette manager doesnt exist...
			BEQ.S	@doNothing
			CLR.L	AppPalette
			BSR.S	DisposeAppPalettes

			MOVE.L	(A5),A0 				;							< 124 >
			BTST	#3,QDSpare0(A0)			; Any change to color env?  < 124 >
			BEQ.S	@doNothing				;							< 124 >

			BSR.S	CheckForProcessMgr
			BEQ.S	@front					; if no process mgr, assume we're in front
			MOVE	#$0100,inFront(A6)		; default inFront to true
			SUBQ	#2,SP					; space for result
			PEA		frontPSN(A6)
			_GetFrontProcess
			TST		(SP)+					; problem getting front psn?
			BNE.S	@front					; YES => just zap the cluts
			CLR.L	myPSN(A6)
			MOVE.L	#kCurrentProcess,myPSN+4(A6)
			SUBQ	#2,SP					; space for OSErr result
			PEA		frontPSN(A6)
			PEA		myPSN(A6)
			PEA		inFront(A6)
			_SameProcess					; are we the front process?
			ADDQ	#2,SP					; OSErr leaves inFront true from above
			TST		inFront(A6)
			BEQ.S	@doNothing
@front
			JSRROM	ROMINTOPMGREXIT
;			JSR		CheckAllDeviceCluts		; A pretty simple patch, really.
;			CLR		-(SP)					; No Setentries on Scatter
;			JSR		ScatterDevices
;			BSR.S	CheckForJuggler			; Is Jugglertm active?
;			BNE.S	@doNothing				; No=>WMgr is void, next line dangerous
;			JSR		UpdateDevices
;			MOVE.L	mainDevice,theGDevice
@doNothing
			UNLK	A6
			MOVE.L	(SP)+,WindowList
			RTS


;---------------------------------------------------
;
; FUNCTION CheckForProcessMgr:Boolean;
;
; Determine if the process mgr is present using Gestalt.
; (we assume that gestaltLaunchControl iff processMgr is here)
; Affect only A0/D0, since Gestalt is an OS trap.
; return Z-flag Clear if the process mgr is here (BNE ProcMgrTrue)

CheckForProcessMgr
			MOVE.L	#'os  ',D0				; type of question
			_Gestalt
			TST		D0						; OSErr from Gestalt?
			BEQ.S	@a						; No=>test result
			SUBA	A0,A0					; Yes=>assume there's no procMgr
@a
			MOVE.L	A0,D0
			BTST	#gestaltLaunchControl,D0	; clear the Z-flag if procmgr here
			RTS


;---------------------------------------------------
;
; PROCEDURE	DisposeAppPalettes();
;
; Look through the palette list and dispose of any in the current App heap.

DisposeAppPalettes

			MOVEM.L	A0-A3/D0-D3,-(SP)		; save all registers
			MOVE.L	PMgrHandle,A2			; get paletteMgr handle
			CMP.L	MinusOne,A2				; is it there?
			BEQ		GoHome					; => no, just return
			MOVE.L	(A2),A1					; point to data structure
			MOVE.L	PListHandle(A1),A0		; get handle to palette list
			_HLock							; and lock it down
			MOVE.L	(A0),A3					; point to palette list

			Move	APalettes(A1),D3		; get number of active handles
			Beq.s	NoPals					; no friends => go home
			Add		FreeSpaces(A1),D3		; calculate total number of entries
	;<13>		Clr.L	WindowList				; clear the list of windows for FrontWindow		AWC.PB506
			BRA.S	FindEnd					; => check for no entries

FindLoop	Move.L	PaletteRef(A3),D1		; get first entry
			BEQ.S	FindNext				; => no palette in entry
			MOVE.L	ApplZone,A0				; get application heap zone		<117>
			CMP.L	A0,D1					; Are we before the heap zone?	<117>
			BLO.S	FindNext				; Yes => not in app heap
			CMP.L	bklim(A0),D1			; Are we past the heap zone		<117>
			BHS.S	FindNext				; => not in app heap
			MOVE.L	D1,-(SP)				; push palette handle
			_DisposePalette					; and dispose it in place
FindNext	AddQ	#PLstEntrySz,A3			; bump to the next entry
FindEnd		DBra	D3,FindLoop				; repeat for all spaces

NoPals		MOVE.L	(A2),A1					; point to palette stuff
			MOVE.L	PListHandle(A1),A0		; get handle to palette list
			_HUnlock						; and unlock it

GoHome		Clr.L	AppPalette				; set us up for the next guy				AWC.PB508

			MOVEM.L	(SP)+,A0-A3/D0-D3
			RTS

; This is the Palette Manager's dispatch table. ROM routines
; which work are included with DcRom to give absolute
; addresses. New routines are offsets from the table base, with
; the low bit set, just for clarity.

ptchPMgrError	JMPRom	RomPMgrFinalError

pMgrProcs
switch00	DcRom	RomEntry2Index
switch01	DcRom	RomIndex2Entries

switch02	DC.L	RestoreDeviceClut-pMgrProcs+1
switch03	DC.L	ptchResizePalette-pMgrProcs+1
switch04	DC.L	ptchZapLinks-pMgrProcs+1
switch05	DC.L	WhatPal-pMgrProcs+1

switch06	DC.L	ptchPMgrError-pMgrProcs+1			; Some unused dispatchs
switch07	DC.L	ptchPMgrError-pMgrProcs+1
switch08	DC.L	ptchPMgrError-pMgrProcs+1
switch09	DC.L	ptchPMgrError-pMgrProcs+1

switch10	DcRom	RomDeltaRGB
switch11	DcRom	RomNewHiliteColor
switch12	DC.L	ptchPMgrExit-pMgrProcs+1
switch13	DcRom	RomSaveFore
switch14	DcRom	RomSaveBack
switch15	DcRom	RomRestoreFore
switch16	DcRom	RomRestoreBack
switch17	DcRom	RomReinstantiateColors
switch18	DC.L	ReleaseList-pMgrProcs+1
switch19	DC.L	SetDepth-pMgrProcs+1
switch20	DC.L	HasDepth-pMgrProcs+1
switch21	DC.L	PMgrVersion-pMgrProcs+1
switch22	DC.L	SetPaletteUpdates-pMgrProcs+1
switch23	DC.L	GetPaletteUpdates-pMgrProcs+1
switch24	DC.L	CheckColors-pMgrProcs+1
switch25	DC.L	GetGray-pMgrProcs+1
pMgrProcsEnd


ptchPMgrDispatch
			CMP.B	#(PMgrProcsEnd-PMgrProcs)/4,D0
			BHS.S	ptchPMgrError				; Too high a dispatch
			MOVE.L	A0,-(SP)				; Preserve A0
			LEA		pMgrProcs,A0			; A0->absolute table of dispatchs
			AND		#$00FF,D0				; Kill arg count from dispatch
			MOVE.L	(A0,D0*4),-(SP)			; Push target as return address
			MOVE.L	4(SP),A0				; Restore A0
			RTD		#4						; And go to routine.

			ENDPROC							; 										<107>

;--- This equate must be kept outside of code/data modules ---			;			<107>
pMgrProcsSize	EQU		pMgrProcsEnd-pMgrProcs							;			<107>


;-------------- Start of GetNewCWindow patch added by KON 10Nov89 --------------------

ptchGetNewCWindow		PROC	EXPORT
RomGetNewCWindow		EQU		$21c90
;
; First we call the existing routine to get a CWindow. Then we add a palette if one
; with the same ID exists in the resource file.
;
result			EQU		18					; parameter equates
winID			EQU		16
wStor			EQU		12
behind			EQU		8

			link	a6, #0					;no local parameters					<10Nov89 KON>
			clr.l	-(sp)					;room for result from ROM GetNewCWindow	<10Nov89 KON>
			move.w	winID(a6),-(sp)			;do same call as requested				<10Nov89 KON>
			move.l	wStor(a6),-(sp)
			move.l	behind(a6),-(sp)
			JSRRom	RomGetNewCWindow		;call the old one						<10Nov89 KON>
			move.l	(sp)+,result(a6)		;return result							<10Nov89 KON>
;
; Check if palette with same ID as window exists (taken from getmgr.a)
;
			clr.l	-(sp)				; make room for palette handle		<erich>
			move	winID(a6),-(SP)		; push window ID					<erich>
			_GetNewPalette				; fetchez la palette				<erich>
			move.l	(sp)+,d0			; well?								<erich>

			beq.s	NoWindowPltt		; sorry, no automatic palette today			AWC.PB459
			move.l	D0,A0				; get the palette							AWC.PB459
			move.l	(A0),A0				; dereference it							AWC.PB459
			move	PmPrivate(A0),D1	; grab the update bits						AWC.PB459
			lsr		#1,D1				; put them in position						AWC.PB459
			bset	#NNewBit,D1			; use the new CUpdates format				AWC.PB459
			bset	#DisposeBit,PmPrivate(A0)	; set for automatic disposal		AWC.PB459

			move.l	result(a6),-(sp)	; push the window				<10Nov89 KON>
			move.l	d0,-(sp)			; push the palette					<erich>
			move	D1,-(sp)			; push cUpdates								AWC.PB459
			_SetPalette					;									<erich>

NoWindowPltt								;											AWC.PB459
			unlk	a6
			move.l	(sp)+,a0			;return address
			add		#10,sp				;strip parameters, leave result
			jmp		(a0)
			ENDPROC

;-------------- End of GetNewCWindow patch added by KON 10Nov89 ----------------------


;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
;********************** End Of PaletteMgr Patches? ************************
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ


;____________________________________________________________________________	DAF	<2.6>
;	Window manager patch
;
;	This patch corrects a bug in SetWin/CtlColor in 32-bit addressing mode.  These routines
;	(which operate on identical data structures) can accept a colortable whose ctSize=-1
;	which allows an application to specify that the wcTable be set to the default color
;	set (via a copy of the color table handle).  In 32-bit mode it is important that there
;	be exactly one auxWinRec per window.  This routine has a bug where -1 color tables can
;	cause extra auxWinRecs to be allocated in 32-bit mode.
;

;
; procedure SetWinColor ( theWindow:windowPtr; newColorTable:CTabHandle );
;
;	This procedure changes the awCTable field of the theWindow's auxWinRec.
;	If newColorTable is equal to the default record's CTabHandle, then
;	the auxWinRec is deallocated.  If this window does not have an
;	auxWinRec, then one is allocated at the head of the list.  If theWindow
;	is NIL, then the default colors are changed.  If a record gets deallocated,
;	it's colorTable is disposed unless it has it's resource bit set (then the
;	app must take responsibility)
;
;	Most of this code is shared with the control manager.  Since the auxRec
;	offsets are the same for both types of auxrecs, the code should be OK,
;	even though the code uses the auxWinRec names.
;

NewSetWinColor	PROC	EXPORT
				EXPORT	NewSetCtlColor

ROMSetWinColorAfterSetGutsCall	EQU		$19744
ROMSetCtlColorAfterSetGutsCall	EQU		$1979C
ROMGetAuxGuts	EQU		$19888				; GetAuxGuts in Aurora ROM
ROMSetGutsAfterSpecAlloc32Call	EQU		$197F6
ROMDeAlAux		EQU		$1983A
ROMSpecAlloc	EQU		$1981A
ROMSWCDone		EQU		$19816

				MOVEM.L	A2/A3,-(SP)			;get some address registers
				MOVE.L	AuxWinHead,A2		;get the list head
				LEA		AuxWinHead,A3		;in case we need to deallocate
				BSR.S	SetGuts				;bsr so that we can redraw on return
				JMPROM	ROMSetWinColorAfterSetGutsCall

NewSetCtlColor
				MOVEM.L	A2/A3,-(SP)			;get some address registers
				MOVE.L	AuxCtlHead,A2		;get the list head
				LEA		AuxCtlHead,A3		;in case we need to deallocate
				BSR.S	SetGuts				;
				JMPROM	ROMSetCtlColorAfterSetGutsCall

SetGuts

tWind			EQU		$18					;some equates for parameters
nCTab			EQU		$14					; 	after LINK (don't forget the movem above!)

				LINK	A6,#0				;no globals
				CLR.L	-(SP)				;return AuxWinHandle here
				CLR.W	-(SP)				;function return here
				CLR.L	-(SP)				;NIL for default
				PEA		6(SP)				;pointer to the placeholder
				MOVE.L	A2,A1				;set up list head for GetAuxGuts
				JSRROM	ROMGetAuxGuts		;get the default record
				ADDQ	#2,SP				;ignore boolean result
				MOVE.L	(SP)+,A0			;get the default handle
				MOVE.L	(A0),A0				;get a pointer
				MOVE.L	awCTable(A0),A0		;get the cTabHandle
				CMP.L	nCTab(A6),A0 		;if the same then deallocate
				BEQ 	DeAlAux				;
				CMP.L	#-1,nCTab(A6) 		;if -1, then allocate a rec with default table
				BEQ.S	SpecAlloc			;
				MOVE.L	A0,-(SP)			;save a reg (yuck, but registers are tight!)
				MOVE.L	nCTab(A6),A0		;get the new color table handle
				MOVE.L	(A0),A0				;get a pointer
				CMP.W	#-1,ctSize(A0)		;is ctSize -1?
				MOVE.L	(SP)+,A0			;get the register back (don't change flags)
				BEQ.S	SpecAlloc32			;If so, alloc a rec with default table
				JMPROM	ROMSetGutsAfterSpecAlloc32Call

DeAlAux			JMPROM	ROMDeAlAux
SpecAlloc		JMPROM	ROMSpecAlloc

; if this routine is called in 24-bit mode, then it falls through to SpecAlloc and makes
;	a new auxWinRec with a copy of the default colortable.  If it is called in 32-bit
;	mode, then it finds the window's pre-existing auxWinRec (one is always guaranteed to
;	exist) and sets it's colortable to be a copy of the default colortable handle.

SpecAlloc32

				TST.B	MMU32Bit			; are we in 32-bit mode?
				BEQ.S	SpecAlloc			; no, so allocate a new record with a copy of the default colors
				MOVE.L	A0,nCTab(A6)		; stick the default colors in the stack frame
				CLR.L	-(SP)				; return AuxWinHandle here
				CLR.W	-(SP)				; leave room for return value here
				MOVE.L	tWind(A6),-(SP)		; find this window
				PEA		6(SP)				; point to placeholder
				MOVE.L	A2,A1				; set up list head for GetAuxGuts (windows or controls)
				JSRROM	ROMGetAuxGuts		; get it (it will always be here in 32-bit mode)
				ADDQ	#2,SP				; the result should have always returned true
				MOVE.L	(SP)+,A0			; get the win/ctl rec handle>
				MOVE.L	(A0),A0				; get a pointer
				MOVE.L	nCTab(A6),awCTable(A0) ;and set the default colortable (in nCTab) field
				JMPROM	ROMSWCDone


;____________________________________________________________________________	GGD	<2.7>
;	Slot interrupt patch for _sIntInstall
;
;	<2.2/2.7> Slot Interrupt patch: patches _SIntInstall, and reverses Slot
;	interrupt queue order
;
;	Change the treatment of Equal Priorities to match the Mac II, which ran the most
;	recently installed element soonest when priorities were equal.  This code matches
;	Inside Mac Vol 5, and treats $FF as highest priority.  The Mac II has a bug and
;	treats $FF as LOWEST priority within the slot, but as HIGHEST priority across slots.
;	Most cards seemed to beleive the documentation, and none have multiple handlers per slot,
;	One developer figured out that the Mac II was backwards within the slot, and wanted to
;	insert an element ahead of a priority zero (highest with Mac II bug) element.  To do
;	this, he took advantage of the was that equal priorities were treated on the Mac II,
;	which is why we are now patching this to match.
;

SIntCorePtch	proc 	export
			WITH	SlotIntQElement,slotIntGlobals

			EXPORT	SIntINSTALL

ROMGetSlotIntQHead	equ	$00006E30		; offset to GetSlotIntQHead

;_______________________________________________________________________
;
; Routine:		SIntINSTALL
;
; Arguments:	D0 (input) :	slot number for routine ($0..$E possible)
;				A0 (input) :	ptr to queue element
;				D0 (output):	error code -	0  no error
;
; Function: 	Installs a slot interrupt poll routine which is called when
;				a slot interrupt occurs. The queue element is installed in
;				in priority order, $FF highest (first), $00 lowest (last).
;
;				When elements with EQUAL priorities exist, the most recently
;				installed one is run sooner.
;
;				<2.7> changes the treatment of Equal priorities to match Mac II.
;
;				Only low byte of priority word is used (0-255 range).
;				Priorities 200-255 are reserved by Apple.]
;
;				The Mac II used to maintain priority across slots, which was
;				used when multiple slots interrupted AT THE SAME TIME.
;				We no longer support this, and prioritize by slot number instead.
;				This will be removed from the Mac II in system 7.0
;
;				The Mac II had a bug in SIntInstall, which had $FF as the highest
;				priority across slots, but had $FF as the lowest within a slot.
;				Most cards used the priority order as documented, ($FF highest), so
;				we will retain that ordering.
;				This will be fixed in the Mac II in System 7.0.
;
; Registers Used: D0,D1,D2,A0,A1
;_______________________________________________________________________

SIntINSTALL	JsrROM	ROMGetSlotIntQHead	; a1 := pointer to qheader
			move.b	SQPrio+1(a0),d0		; get the priority (low byte of word)
			move.w	sr,-(sp)			; save interrupt level
			ori.w	#HiIntMask,sr		; disable interrupts
@PrioritySearch
			move.l	SQLink(a1),d1		; get next queue element to check
			beq.s	@insert				; if end of list, insert before this
			exg.l	a1,d1				; swap previous and current pointers
			cmp.b	SQPrio+1(a1),d0		; compare priorities
			blo.s	@PrioritySearch		; loop until lower priority found (was BLS.S)	<2.7>
										; if equal, insert newer in front of older		<2.7>
			exg.l	d1,a1				; a1 points to previous, d1 points to current
@insert									; insert before the lower priority element
			move.l	d1,SQLink(a0)		; remainder of queue goes after new element
			move.l	a0,SQLink(a1)		; new element goes after previous element
			move.w	(sp)+,sr			; restore interrupt level
			moveq.l	#noErr,d0			; return success
			rts							; all done

			ENDP

;____________________________________________________________________________	<20>
;	Patches to Gestalt Functions
;____________________________________________________________________________
;	The following gestalt selectors are patched or added in this file:
;		-	gestaltHardwareAttr
;		-	gestaltParityAttr
;		-	gestaltMiscAttr
;		-	gestaltVersion
;		-	gesaltNotificationMgrAttr
;		-	gestaltQuickdrawVersion
;		-	gestaltAddressingModeAttr
;		-	gestaltNuBusConnectors													<95>
;		-	gestaltSerialAttr														<95>
;
;	The following gestalt selectors are removed in this file:
;		-	gestaltRBVAddr
;		-	gestaltSCCReadAddr
;		-	gestaltSCCWriteAddr
;		-	gestaltVIA1Addr
;		-	gestaltVIA2Addr
;		-	gestaltSlotAttr															<95>
;		-	gestaltFirstSlot														<95>
;		-	gestaltSlotCount														<95>
;



;-----------------------------------------------------------------------------------------
;
;	Record to describe gestalt function parameters
;
;-----------------------------------------------------------------------------------------

gestaltParmFrame record	{oldA6},decrement
result			ds.w	1	; OSErr
argSize			equ	*-8
gestaltSelector	ds.l	1	; packed array [1..4] of char
gestaltResult	ds.l	1	; addr of longint result
return			ds.l	1
oldA6			ds.l	1
localFrame		equ	*
				endR




;____________________________________________________________________________	CCH	<8>
;	Gestalt function to effectively remove a selector
;
; The following is a gestalt function that will return an error as if the
; selector were undefined.
;
; Routine	gestaltUndef (
;		    	gestaltSelector: 	OSType;		= PACKED ARRAY [1..4] OF CHAR;
;			VAR gestaltResult:		Longint;
;			):						OSErr;		= Integer;
;

gestaltUndef	PROC	EXPORT

				with	gestaltParmFrame
				link	a6,#localFrame

				move.w	#gestaltUndefSelectorErr,result(a6)	; return an error

				unlk	a6
				move.l	(sp)+,a0					; get return value
				add.l	#argSize,sp					; restore stack pointer
				jmp		(a0)						; return

				ENDP


;____________________________________________________________________________	CCH	<10>
;	Gestalt function for gestaltMiscAttr
;
; The following is a patch to the gestaltMiscAttr selector.   It returns
; miscellaneous information about things.
;
; Routine	gestaltMisc (
;		    	gestaltSelector: 	OSType;		= PACKED ARRAY [1..4] OF CHAR;
;			VAR gestaltResult:		Longint;
;			):						OSErr;		= Integer;
;

UserDelayTrap	EQU			$A84C		; user delay trap							<17>

gestaltMisc		PROC	EXPORT

				with	gestaltParmFrame
				link	a6,#localFrame

				clr.l	d3						; clear result
@hasBootGlobs	bset	#gestaltBootGlobals,d3	; we have boot globals

@userDelay		move.w	#UnimplementedTrap,D0	; get loc of unimplemented trap				<58>
				_GetTrapAddress ,newTool		; get the address into A0
				Move.l	A0,D2					; save it for a sec
				Move.l	#UserDelayTrap,D0		; trap ID to check for scrolling throttle
				_GetTrapAddress ,newTool		; get the address of it
				cmp.l	a0,d2					; is it unimplemented?
				beq.s	@squareMenus			; nope..									<58>
				bset	#gestaltScrollingThrottle,d3	;									<58>

@squareMenus	move.b	NTSC,d0					; get a copy of the NTSC byte				<58>
				andi.b	#$0F,d0					; only look at bottom nibble				<58>
				bne.s	@next					; if it's non-zero, menus aren't square		<58>
				bset	#gestaltSquareMenuBar,d3 ; otherwise, it is!						<58>

@next
				move.l	d3,d0					; put result into d0						<58>

				move.l	gestaltResult(a6),a0	; get address to place result
				move.l	d0,(a0) 				;
				move.w	#noErr,result(a6)		; return no error

				unlk	a6
				move.l	(sp)+,a0				; get return value
				add.l	#argSize,sp				; restore stack pointer
				jmp		(a0)					; return

				ENDP


;____________________________________________________________________________	CCH	<20>
;	Gestalt function for gestaltNotificationMgrAttr
;
; The following is a patch to the gestaltNotificationMgrAttr selector.
; It indicates existence of the notification manager trap.
;
; Routine	gestaltNMgr (
;		    	gestaltSelector: 	OSType;		= PACKED ARRAY [1..4] OF CHAR;
;			VAR gestaltResult:		Longint;
;			):						OSErr;		= Integer;
;
NMInstallTrap	EQU			$A05E		; notification manager install trap			<20>


gestaltNMgr		PROC	EXPORT

				with	gestaltParmFrame
				link	a6,#localFrame

				clr.l	d0						; clear result
				Move.w	#UnimplementedTrap,D0	; get loc of unimplemented trap
				_GetTrapAddress ,newTool		; get the address into A0
				Move.l	A0,D2					; save it for a sec
				Move.l	#NMInstallTrap,D0		; trap ID to check for notification mgr
				_GetTrapAddress ,newTool		; get the address of it
				Cmp.l	A0,D2					; is it unimplemented?
				Beq.s	@noNMgr					; it is?!
				bset	#gestaltNotificationPresent,d0	; otherwise it exists

@noNMgr			move.l	gestaltResult(a6),a0		; get address to place result
				move.l	d0,(a0) 					;
				move.w	#noErr,result(a6)			; return no error

				unlk	a6
				move.l	(sp)+,a0					; get return value
				add.l	#argSize,sp					; restore stack pointer
				jmp		(a0)						; return

				ENDP


;____________________________________________________________________________	CCH	<8>
;	Gestalt function for gestaltVersion
;
; The following is a patch to the gestaltVersion selector.   It returns the
; correct version number.
;
; Routine	getGestaltVers (
;		    	gestaltSelector: 	OSType;		= PACKED ARRAY [1..4] OF CHAR;
;			VAR gestaltResult:		Longint;
;			):						OSErr;		= Integer;
;

getGestaltVers	PROC	EXPORT

				with	gestaltParmFrame
				link	a6,#localFrame

				move.l	gestaltResult(a6),a0		; get address to place result
				move.l	#1,(a0) 					; return response determined at install time
				move.w	#noErr,result(a6)			; return no error

				unlk	a6
				move.l	(sp)+,a0					; get return value
				add.l	#argSize,sp					; restore stack pointer
				jmp		(a0)						; return

				ENDP


;____________________________________________________________________________	jwk	<95>
;	Gestalt function for gestaltNuBusConnectors
;
; The following returns a bitmap of slots with NuBus connectors.
;

gestaltNBCon	PROC	EXPORT

MaxSlots		EQU		16							; max number of slots possible

				with	gestaltParmFrame, NuBusInfo, ProductInfo
				link	a6,#localFrame
				movea.l	UnivInfoPtr,a0				; get universal info ptr
				adda.l	NuBusInfoPtr(a0),a0			; add in offset to NuBus info
				clr.l	d0							; clear index
				clr.l	d1							; clear bitmap of NuBus connectors
@slotLoop		btst	#hasConnector,(a0,d0.w)		; does this slot have a connector?
				beq.s	@next						; if not, go look at next slot
				bset.l	d0,d1						; note that this slot has a NuBus connector
@next			addq	#1,d0						; bump up to next slot
				cmpi.l	#MaxSlots,d0				; have we gone through all slots?
				bne.s	@slotLoop					; if not, keep going

				move.l	gestaltResult(a6),a0		; get address to place result
				move.l	d1,(a0)						; return the bitmap of NuBus connectors
				move.w	#noErr,result(a6)			; return no error

				unlk	a6
				move.l	(sp)+,a0					; get return value
				add.l	#argSize,sp					; restore stack pointer
				jmp		(a0)						; return

				ENDP

;____________________________________________________________________________	EH	<95>
;	Gestalt function for gestaltSerialAttr
;
; The following is a patch to the gestaltSerialAttr selector.
; It indicates existence of serial attributes on the machine.
;

gestaltSerial	PROC	EXPORT

				with	gestaltParmFrame,ExpandMemRec,GestaltGlobals
				link	a6,#localFrame

				movea.l	ExpandMem,a0					; get ptr to expandmem rec
				movea.l	emGestalt(a0),a0				; get gestalt global ptr
				moveq.l #0,d0							; assume no GPI connections
				cmpi.w	#gestaltMacLC,machType(a0)		; <107> use real machine name now...
				beq.s	@noGPI
														; IIci and IIsi have GPI connected
				moveq.l	#(1<<gestaltHasGPIaToDCDa)|\	;	GPIa connected to DCDa
						(1<<gestaltHasGPIaToRTxCa)|\	;	GPIa connected to RTxCa clock input)
						(1<<gestaltHasGPIbToDCDb),d0	; 	GPIb connected to DCDb

@noGPI			move.l	gestaltResult(a6),a0			; get address to place result
				move.l	d0,(a0) 						;
				move.w	#noErr,result(a6)				; return no error

				unlk	a6
				move.l	(sp)+,a0						; get return value
				add.l	#argSize,sp						; restore stack pointer
				jmp		(a0)							; return

				ENDP

;____________________________________________________________________________	CCH	<8>
;	Gestalt function for gestaltParityAttr
;
; The following is a patch to the gestaltParityAttr selector.  It correctly
; handles parity on Zone 5, as well as the IIci.
;
; Routine	gestaltParity (
;		    	gestaltSelector: 	OSType;		= PACKED ARRAY [1..4] OF CHAR;
;			VAR gestaltResult:		Longint;
;			):						OSErr;		= Integer;
;

gestaltParity	PROC	EXPORT
				EXPORT	parityValue

				with	gestaltParmFrame
				link	a6,#localFrame

				move.l	gestaltResult(a6),a0		; get address to place result
				move.l	parityValue,(a0) 			; return response determined at install time
				move.w	#noErr,result(a6)			; return no error

				unlk	a6
				move.l	(sp)+,a0					; get return value
				add.l	#argSize,sp					; restore stack pointer
				jmp		(a0)						; return

parityValue		dc.l	0							; response for parity selector

				ENDP


;____________________________________________________________________________	CCH	<3.2>
;	Gestalt function for gestaltQuickdrawVersion
;
; The following is a patch to the gestaltQuickdrawVersion selector.
;
; Routine	gestaltQDVers (
;		    	gestaltSelector: 	OSType;		= PACKED ARRAY [1..4] OF CHAR;
;			VAR gestaltResult:		Longint;
;			):						OSErr;		= Integer;
;

gestaltQDVers	PROC	EXPORT

				with	gestaltParmFrame
				link	a6,#localFrame

				clr.l	-(sp)						;make room for result
				_OffScreenVersion
				move.l	gestaltResult(a6),a0		; get address to place result
				move.l	(sp)+, d0					; get QD version from GWorld
				add.w	#$100, d0

				move.l	d0, (a0) 					; return version number for ci
				move.w	#noErr,result(a6)			; return no error

				unlk	a6
				move.l	(sp)+,a0					; get return value
				add.l	#argSize,sp					; restore stack pointer
				jmp		(a0)						; return

				ENDP


;____________________________________________________________________________	CCH	<6.9>
;	Gestalt function for gestaltAddressingModeAttr
;
;	The following is a patch to the gestaltAddressingModeAttr selector to add the
;	gestalt32BitCapable bit to this selector.
;
; Routine	gestaltAddrMode (
;		    	gestaltSelector: 	OSType;		= PACKED ARRAY [1..4] OF CHAR;
;			VAR gestaltResult:		Longint;
;			):						OSErr;		= Integer;
;

gestaltAddrMode	PROC	EXPORT

				with	gestaltParmFrame
				link	a6,#localFrame

				clr.l	d0							; clear result value				<6.9>
				move.b	SystemInfo,d0				; get status byte into d1			<6.9>
				not.b	d0							; invert status bits				<6.9>
				and.l	#3,d0						; only want bit 0 and bit 1			<6.9>
				bset	#gestalt32BitCapable,d0		; return that ROM is 32-bit clean	<6.9>
				move.l	gestaltResult(a6),a0		; get address to place result
				move.l	d0,(a0) 					; save result						<6.9>
				move.w	#noErr,result(a6)			; return no error

				unlk	a6
				move.l	(sp)+,a0					; get return value
				add.l	#argSize,sp					; restore stack pointer
				jmp		(a0)						; return

				ENDP


		IF doScriptMgrGestalt AND (NOT installScriptMgrPtch27) THEN		; <6.1><50>
;____________________________________________________________________________	pke	<2.5>
;	Gestalt function for Script Mgr								<08/05/89 pke>
;
; The following Gestalt Function is an interface between the Gestalt mechanism
; and the Script Manager's GetEnvirons routine. Currently, it only supports two
; Gestalt selectors: gestaltScriptMgrVersion and gestaltScriptCount.
;
; Routine	gestaltScriptMgr (
;		    	gestaltSelector: 	OSType;		= PACKED ARRAY [1..4] OF CHAR;
;			VAR gestaltResult:		Longint;
;			):						OSErr;		= Integer;
;
; <08/05/89 pke>	New today
;


gestaltScriptMgr proc export

		export	gestaltSMgrTable			; table for installation <8/05/89 pke>


		with	gestaltParmFrame			;									<3.2>
		link	a6,#localFrame

; initialize loop, set up default return values
		move.l	gestaltSelector(a6),d0		; selector value
;;		move.l	gestaltResult(a6),a0		; addr for result
;;		clr.l	(a0)						; initially set result to 0
		move.l	#gestaltUndefSelectorErr,result(a6) ; assume unknown selector
		lea		gestaltSMgrTable,a1

; loop to find Gestalt selector in table
@gestaltLoop
		move.l	(a1)+,d1					; get next table entry
		beq.s	@gestaltDone				; end of list, quit
		move.w	(a1)+,d2					; now get GetEnvirons verb
		cmp.l	d0,d1						; is selector correct?
		bne.s	@gestaltLoop				; no, get next one

; ok, we found the Gestalt selector. Now call GetEnvirons with correct verb
		clr.l	-(sp)						; space for result
		move.w	d2,-(sp)					; push verb
		_GetEnvirons
		move.l	gestaltResult(a6),a0		; addr for result
		move.l	(sp)+,(a0)					; pop result into Gestalt
		move.w	#noErr,result(a6)			; return no error
; all done
@gestaltDone

		unlk	a6
		move.l	(sp)+,a0
		add.l	#argSize,sp
		jmp	(a0)

		endWith

; Table for converting between gestalt selectors and GetEnvirons verbs. Each pair
; consists of a long with the gestalt selector, followed by a word with the
; GetEnvirons verb. This table and the equate files where the Gestalt selectors
; are defined are the only things that need to change to add new Gestalt selectors
; for the Script Manager.

gestaltSMgrTable
		dc.l	gestaltScriptMgrVersion
		dc.w	smVersion

		dc.l	gestaltScriptCount
		dc.w	smEnabled

		dc.l	0			; terminator

		endProc
		ENDIF								; <6.1>





		IF NOT SPLINE_FONT THEN					; <6.0.5>
;____________________________________________________________________________	CEL <5>
;	NewRSect (fixes DrawText)
;
;	DrText had a check to see if the advance width of a character was zero.  If so,
;	it would skip the character.  This was bad since International uses zero width
;	characters to lay out certain kanji or vertical text.  only one line needed to
;	be taken out.  The patch is big but the change is small.
;
NewRSect	proc	export
;-------------------------------------------
;
;  KERNED STRIKE FONT FORMAT OFFSETS:
;
FORMAT			EQU 	0				;WORD
MINCHAR 		EQU 	2				;WORD
MAXCHAR 		EQU 	4				;WORD
MAXWD			EQU 	6				;WORD
FBBOX			EQU 	8				;WORD fKernMax
FBBOY			EQU 	10				;WORD save as nDescent; unused except as high owTLoc
FBBDX			EQU 	12				;WORD fRectWidth
FBBDY			EQU 	14				;WORD fRectHeight
LENGTH			EQU 	16				;WORD owTLoc
locASCENT		EQU 	18				;WORD		Conflict with other Ascent and Descent defines
locDESCENT 		EQU 	20				;WORD
XOFFSET 		EQU 	22				;WORD leading
RASTER			EQU 	24				;WORD rowWords


;------------------------------------------------------
;
;  A6 OFFSETS OF PARAMETERS AFTER LINK:
;
PARAMSIZE		EQU 	14					;SIZE OF PARAMETERS
COUNT			EQU 	PARAMSIZE+8-2		;WORD
TEXTADDR		EQU 	COUNT-4 			;LONG
NUMER			EQU 	TEXTADDR-4			;LONG, POINT
DENOM			EQU 	NUMER-4 			;LONG, POINT


;-----------------------------------------------------------
;
;  A6 OFFSETS OF LOCAL VARIABLES AFTER LINK:
;
SAVESTK			EQU		-4					;long stack before allocating buffers
TEXTRECT		EQU 	SAVESTK-8			;RECT original bounding rect
TEXTR2			EQU 	TEXTRECT-8			;RECT copy of textRext used by maprect
SRCRECT			EQU		TEXTR2-8			;RECT original shadow bounding rect
DSTRECT			EQU		SRCRECT-8			;RECT copy of srcRect used by maprect
MINRECT 		EQU 	DSTRECT-8			;RECT minimum rect for clipping
BUFEND			EQU 	MINRECT-4			;LONG where the offscreen buffer ends
BUFSIZE 		EQU 	BUFEND-2			;WORD the size of the offscreen buffer
BUFROW			EQU 	BUFSIZE-2			;WORD the rowBytes for the offscreen buffer
BUF2START		EQU 	BUFROW-4			;LONG second buffer used for shadow
BUF2END 		EQU 	BUF2START-4 		;LONG where shadow buffer ends
BUFLEFT 		EQU 	BUF2END-2			;WORD output left edge
HEIGHT			EQU 	BUFLEFT-2			;WORD font fRectHeight copy
SRCPTR			EQU 	HEIGHT-4			;LONG used only in wide character case as temp
DSTPTR			EQU 	SRCPTR-4			;LONG used only in wide character case as temp
BUFSTART		EQU 	DSTPTR-4			;LONG \						start of bits buffer
SRCADDR 		EQU 	BUFSTART-4			;LONG  >- these 3 grouped:  address of font bits
SRCROW			EQU 	SRCADDR-4			;LONG /						rowbytes of font bits
maskStart		EQU		SRCROW-4			;LONG \						start of mask buffer
maskAddr		EQU		maskStart-4			;LONG  >- these 3 grouped:	address of mask bits
mSrcRow			EQU		maskAddr-4			;LONG /						rowbytes of mask bits
FROMRECT		EQU 	mSrcRow-8			;RECT mapRect parameter
TORECT			EQU 	FROMRECT-8			;RECT mapRect parameter
PENLOC			EQU 	TORECT-4			;POINT copy of original pnLoc
SPWIDTH 		EQU 	PENLOC-4			;FIXED POINT width of space
CHARLOC 		EQU 	SPWIDTH-4			;FIXED POINT fractional pen position
HEIGHTAB		EQU 	CHARLOC-4			;LONG pointer to font height table
WIDTAB			EQU 	HEIGHTAB-4			;LONG pointer to font offset/width table
LOCTAB			EQU 	WIDTAB-4			;LONG pointer to font location table
SAVEA5			EQU 	LOCTAB-4 			;LONG register saved so can be reused
characterExtra	EQU		SAVEA5-4			;LONG fixed point extra added to each character
maskBitsPtr		EQU		characterExtra-4	;LONG pointer to maskBits, sourcePix, or 0
bkCol			EQU		maskBitsPtr-4		;LONG full of the background color
leftBack		EQU		bkCol-4				;LONG bkCol masked to the left part of the character
rightBack		EQU		leftBack-4			;LONG bkCol masked to the right part of the character
REALBOUNDS		EQU		rightBack-4			;LONG USED FOR SHIELDCURSOR
leftOffset		EQU		REALBOUNDS-8		;2 LONGs offset used by bit field instructions in charblt
maskSize		EQU		leftOffset-2		;WORD size of mask buffer
mBufRow			EQU		maskSize-2			;WORD    \	these 2		mask buffer row size
maskBlts		EQU		mBufRow-6			;3 WORDS /  grouped:	saved state for mask blit
FAKERGN 		EQU 	maskBlts-10			;RECTANGULAR REGION
FAKEPTR 		EQU 	FAKERGN-4			;LONG, FAKE MASTER POINTER
INFO			EQU 	FAKEPTR-8			;4 WORDS font info record returned by txMeasure (unused)
NUMER2			EQU		INFO-4				;Point copy of numer for iterative case
DENOM2			EQU		NUMER2-4			;Point copy of denom for iterative case
charsRemain		EQU		DENOM2-2			;word remaining characters to draw in iterative case
SRCBITS			EQU		charsRemain-14		;bitMap input to shadow stretchBits, bitsToPix
SRCPIX	 		EQU 	SRCBITS-(PMREC+CTREC+20)	;pixMap input to normal stretchbits
maskBits		EQU		SRCPIX-14			;bitMap input to bitsToPix for font mask
DSTPIX			EQU 	maskBits-(PMREC+CTREC+20)	;pixMap destination
FASTFLAG		EQU 	DSTPIX-1			;BYTE flag set if source ORing to screen is OK
maskFont		EQU		FASTFLAG-1			;byte flag set if a maskFont is available + requested
STRETCH 		EQU 	maskFont-1			;BOOLEAN flag set if numerator not equal denominator
HEIGHTFLAG		EQU 	STRETCH-1 			;byte flag set if font has a height table
TOPHT			EQU 	HEIGHTFLAG-2		;word character top & height from font or clip
MAXMIN			EQU 	TOPHT-2				;word number of characters in font
MINCH			EQU 	MAXMIN-2			;word first character in font
bitDepth        EQU     MINCH-2       	    ;word \ These two	bits per pixel in font
bkCol1			EQU		bitDepth-2			;word / grouped.	1 pixel worth of background color
italicSlop		EQU		bkCol1-2			;word extra width due to italic, bold, outline, shadow
kernAdjust		EQU		italicSlop-2		;word left kerning due to kerning and italic
penLocHFrac		EQU		kernAdjust-2		;word fractional pen position for recursive calls
longCount		EQU		penLocHFrac-2		;word loop counter for doMove
charWidth		EQU		longCount-2			;word width in pixels of current character blt
stackOffset		EQU		charWidth-2			;word 2 if stack was word aligned before link
countCopy		EQU		stackOffset-2		;word copy of character count, decremented as drawn
CRSRFLAG		EQU		countCopy-1			;BYTE set if crsr is shielded (to screen)
MMUSave			EQU		CRSRFLAG-1			;BYTE MMU mode on entry to drawText
locMode			EQU		MMUSave-2			;word copy of text mode, adjusted if arith. + 1 bit
bitShift		EQU		locMode-2			;word how far to shift to multiply by bitDepth
orNotOK			EQU		bitShift-1			;Boolean true if bit extract/insert must be used instead
notMaskPass		EQU		orNotOK-1			;Boolean true if blit is not creating font mask
textCopyMode	EQU		notMaskPass-1		;Boolean true if blit must use extract/insert
orMode			EQU		textCopyMode-1		;Boolean true if mode is srcOr & forecolor is black
colorSource		EQU		orMode-1			;Boolean true if font contains colors (nonblack/white)
saveHilite		EQU		colorSource-1		;byte	saved hilite flag for iterative state
run32bit		EQU		saveHilite-1		;byte flag to run 32 bit
VARSIZE         EQU     (((run32bit+1)/4)-1)*4  ;SIZE OF VARIABLES long aligned

FromDrText		EQU		$28468
ROMRSect		EQU		$2C6D4
RomIterate		EQU		$281AA

		cmpRA	FromDrText,(sp)			; is this called from DrText?
		beq.s	@doDrTextPatch			; yes, go fix the patch
		jmpROM	ROMRSect				; call back to the ROM
@doDrTextPatch
		ADDQ	#4, sp					; Pop off return addr and come back here
		jsrROM	ROMRSect				; call back to the ROM

;---------------------------------------------------------------------------------------
; < BELOW COPIED VERBATIM FROM THE ROM UNTIL FURTHER NOTICE >
;
		BEQ 	GOHOME						;QUIT IF NO INTERSECTION
		MOVE	(SP)+,textR2+right(A6)		;restore text right
;
;	Test to see if spline:
;	If spline set up clipping variables
;

;
;  Set up srcAddr, srcRow, and height
;
		LEA 	26(A2),a0					;GET START OF FONT BITMAP
		MOVE.L	a0,SRCADDR(A6)				;SAVE FOR LATER

		MOVEQ	#0,D1						;zero high word
		MOVE	RASTER(A2),D1				;GET WORDS PER ROW IN FONT
	    MOVE    bitShift(A6),D0
		LSL.L	D0,D1         			    ;scale up font rowWords
		ADD.L 	D1,D1						;DOUBLE FOR BYTES PER ROW
		MOVE.L	D1,SRCROW(A6)				;REMEMBER FOR LATER
		MOVE	FBBDY(A2),HEIGHT(A6)		;SETUP HEIGHT FOR LATER
;
;  Test for fast case:
;  not stretched, no color mapping, txMode = srcOr, same bits per pixel
;  not bold, italic, underlined, outlined or shadowed,
;  visRgn and clipRgn both rectangular.
;
		TST.B	fmOutItalic(A4)				;TEST BOLD $$$
		BNE 	NOTFAST 					;NOT FAST UNLESS BOTH ZERO
		TST.B	fmOutBold(A4)				;TEST BOLD
		BNE 	NOTFAST 					;NOT FAST
		TST.B	orMode(A6)					;IS TEXT MODE SRCOR ? (or srcCopy + mask, see above)
		BEQ 	NOTFAST 					;NO, NOT FAST
		TST.W	10(A4)						;TEST ULTHICK AND SHADOW
		BNE 	NOTFAST 					;NOT FAST UNLESS BOTH ZERO
		TST.B	STRETCH(A6) 				;IS TEXT STRETCHED ?
		BNE 	NOTFAST 					;YES, NOT FAST
		MOVE.L	([CLIPRGN,A3]),A0			;GET CLIPRGN HANDLE, dereferenced
		MOVEQ	#10,D0
		CMP 	RGNSIZE(A0),D0				;IS CLIPRGN RECTANGULAR ?
		BNE		NOTFAST 					;NO, NOT FAST
		MOVEQ	#1,D0
        MOVE    bitShift(A6),D1             ;get the depth of the source map
		LSL		D1,D0						;turn into 1 ÉÊ8
        CMP     DSTPIX+PIXELSIZE(A6),D0     ;same depth per pixel?
		BNE		NOTFAST						;=>NOPE
		cmp		#16,dstPix+pixelType(A6)	;is it a direct device? 	@@@@ BAL 16Jun88
		bne.s	@modeok
		seq		textCopyMode(a6)			;yes, can't go fast for now	@@@@ BAL 16Jun88
		clr		locmode(a6)					;this essentially alters mode to srcCopy
		bra		NotFast

@modeok	MOVE.L	VISRGN(A3),A1				;GET VISRGN HANDLE
		MOVE.L	(A1),A0 					;DE-REFERENCE IT
		CMP 	#10,RGNSIZE(A0)				;IS VISRGN RECTANGULAR ?
		BEQ.S	FAST						;YES, TAKE FAST OPTIMIZATION
;
;  All systems go except for VisRgn not rectangular.
;  Check if visRgn sect minRect is rectangular.
;  IF TrimRect(visRgn,minRect) THEN take the fast way.
;
		MOVE.L	A1,-(SP)					;PUSH VISRGN
		PEA 	MINRECT(A6) 				;PUSH MINRECT
		MOVE.W	#-1,-(SP)					;pass Trim = True
		_TRIMRECT							;CALL TRIMRECT
		BLT 	GOHOME						;quit if intersection empty
		BGT		NOTFAST 					;continue if non-rectangular
;
;  Fast case, go directly to screen.
;  If text is clipped vertically, then clear heightflag and update TOPHT
;
FAST
		ST		FASTFLAG(A6)				;REMEMBER WE'RE GOING FAST
		CLR.B	maskFont(A6)				;no need for second mask pass in fast case
		CLR.L	bkCol(A6)					;zero out back color long
		MOVE	MINRECT+TOP(A6),D0			;GET MINRECT.TOP
		MOVE	MINRECT+BOTTOM(A6),D1		;GET MINRECT.BOTTOM
		SUB 	TEXTRECT+TOP(A6),D0 		;was top clipped ?
		BNE.S	VCLIP						;yes, handle clip
		CMP 	TEXTRECT+BOTTOM(A6),D1		;was bottom clipped ?
		BEQ.S	VCLIPOK 					;no, continue

VCLIP	CLR.B	HEIGHTFLAG(A6)				;can't use height table
		MOVE.B	D0,TOPHT(A6)				;use adjusted top
		SUB 	MINRECT+TOP(A6),D1			;calc clipped height
		MOVE.B	D1,TOPHT+1(A6)				;replace TOPHT

VCLIPOK MOVE	TEXTRECT+TOP(A6),D0 		;GET DST TOP
		SUB 	DSTPIX+BOUNDS+TOP(A6),D0	;CONVERT TO GLOBAL COORDINATES
		MOVE	DSTPIX+ROWBYTES(A6),D1		;GET ROWBYTES
		AND		#nuRBMask,D1					;CLEAR OFF FLAG BITS
		MULS	D1,D0						;MULT BY ROWBYTES
		ADD.L	DSTPIX+BASEADDR(A6),D0		;ADD START OF DST BITMAP
		MOVE.L	D0,BUFSTART(A6) 			;SET UP BUFSTART FOR LATER
		MOVE	D1,BUFROW(A6)						;SET UP BUFROW FOR LATER
		MOVE	DSTPIX+BOUNDS+LEFT(A6),BUFLEFT(A6)	;REMEMBER BUFLEFT

		TST.B	CRSRFLAG(A6)					;IS DST TO A SCREEN?				<BAL 19Sep88>
		BEQ		GETPTRS							;=>NO
		PEA 	MINRECT(A6) 		  			;PUSH SHIELD RECT
		MOVE.L	REALBOUNDS(A6),-(SP)			;PUSH DELTA FOR GLOBAL
		_SHIELDCURSOR					  		;HIDE CURSOR IF IT INTERSECTS
;-----------------------------------------------------------
;
; 	Clean pointers and then
;	Switch to 32 bit addressing mode
;
		MOVE.L	SRCADDR(A6),d0				;get 24 bit base addr
		_Translate24To32					;mask off high byte		BAL/MCF 03Dec88
		MOVE.L	d0,SRCADDR(A6)				;SAVE FOR LATER

		move.l	a2,d0						;get FontPtr
		_Translate24To32					;mask off high byte		BAL/MCF	03Dec88
		move.l	d0,a2						;clean font ptr

@setMMUMode
		MOVE	stackOffset(A6),D1
		MOVE.L	TEXTADDR(A6,D1),D0 			;GET TEXTPTR
		_Translate24To32					;mask off high byte		BAL/MCF	03Dec88
		MOVE.L	d0,TEXTADDR(A6,D1)			;SAVE FOR LATER

		moveq	#true32b,d0					;switch to 32 bit addressing
		move.l	a2,-(sp)					;save FontPtr
		_rSwapMMUMode						;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2)
		move.l	(sp)+,a2					;restore FontPtr
		move.b	d0,MMUsave(a6)				;save previous state for later

		MOVE.B	#1, run32bit(A6)			; Set flag to state running 32 bit clean
		BRA 	GETPTRS

NOTSCREEN
;
;  Slow case: Setup for an off-screen buffer.
;
;  Calc bufLeft:  (LONG-align to avoid shift)
;
NOTFAST SF		FASTFLAG(A6)				;NOT GOING DIRECTLY TO SCREEN
		SF		CRSRFLAG(A6)				;CRSR HAS NOT BEEN SHIELDED			<BAL 19Sep88>
		MOVE	TEXTRECT+LEFT(A6),D0		;GET TEXTRECT LEFT
		SUB 	DSTPIX+BOUNDS+LEFT(A6),D0	;CONVERT TO GLOBAL
		AND 	#$FFE0,D0					;TRUNC TO LONG BOUND
		ADD 	DSTPIX+BOUNDS+LEFT(A6),D0	;RETURN TO LOCAL COORDS
		MOVE	D0,BUFLEFT(A6)				;REMEMBER FOR LATER
;
;  Calculate buffer size
;
		MOVEQ	#0,D1						;clear high word
		MOVE	TEXTRECT+RIGHT(A6),D1		;BUFRIGHT := TEXTRECT RIGHT
		SUB 	D0,D1						;WIDTH:=BUFRIGHT-BUFLEFT
		MOVE	D1,D2						;mask depth as well
		MOVE	bitShift(A6),D4				;convenient constant
    	LSL.L   D4,D1     			 	    ;scale up by pixel size + 1 for mask
	    LSR.L   #5,D1                       ;CONVERT DOTS TO LONGS
		ADD 	#2,D1						;ROUND UP PLUS EXTRA LONG
		MOVE	HEIGHT(A6),D3				;GET HEIGHT
		MULU	D1,D3						;BUFSIZE:=HEIGHT*BUFROW LONGS

; if the intermediate result is too big, stop before going any further

		CMP.L	#$1C00,D3					;is it bigger than 28K? (unit is longs)
		BGT.S	DoSubDivide					;if so, draw fewer characters at a time
		MOVE	D3,BUFSIZE(A6)				;SAVE FOR LATER
		ADD		D1,D3						;add for stretch srcBuf
		LSL 	#2,D1						;QUAD BUFROW FOR BYTES
		MOVE	D1,BUFROW(A6)				;SAVE FOR LATER
		MOVE	TEXTR2+RIGHT(A6),D5
		SUB		TEXTR2+LEFT(A6),D5
		LSR		#5,D5						;convert to longs
		ADDQ	#2,D5						;account for slop
		MOVE	D5,D0
		ADD		D0,D3						;in case clip is nonrectangular
		ADD		D0,D3						;in case vis is nonrectangular
		LSL		D4,D0						;scale up by source depth
		ADD		D0,D3						;add stretch destination buffer size
		MULU	dstPix+pixelSize(A6),D5		;size of composite mask
		ADD		D5,D3						;include it

;if srcDepth not equal to dstDepth, add stretch dest. buf. again

		ADD		D5,D3						;include space for scale buffer

;set up maskSize, maskRow

		TST.B	maskFont(A6)				;do we need a mask to pass to stretchBits?
		BEQ.S	@noMask
	    LSR		#5,D2                       ;CONVERT DOTS TO LONGS
		ADD 	#2,D2						;ROUND UP PLUS EXTRA LONG
		ADD		D2,D1						;total number of longs
		MOVE	HEIGHT(A6),D0				;GET HEIGHT
		MULU	D2,D0						;BUFSIZE:=HEIGHT*BUFROW LONGS
		MOVE	D0,maskSize(A6)				;SAVE FOR LATER
		LSL 	#2,D2						;QUAD BUFROW FOR BYTES
		MOVE	D2,mBufRow(A6)				;SAVE FOR LATER
		ADD		D0,D3						;add for stack check calculation
		ADD		D2,D3						;add for stretch srcMaskBuf
		MOVE	TEXTR2+RIGHT(A6),D0
		SUB		TEXTR2+LEFT(A6),D0
		LSR		#5,D0						;convert from dots to longs
		ADD		D0,D3						;add stretch mask destination buffer size
@noMask

;
;  Calculate total stack requirements for off-screen buffers.
;
		TST.B	11(A4)						;ARE WE SHADOWING ?
		BEQ.S	@1							;NO, CONTINUE
		ADD		bufSize(A6),D3				;YES, CALC 2*BUFSIZE
		ADD		D1,D3						;add in 4 * source rows for shadow
@1		LSL.L	#2,D3						;CALC TOTAL STACK BYTES NEEDED

; how much slop? size of scale table (256 bytes maximum)
; size of stretch stack frame (750 bytes for parameters, local stack frame, saved regs),
; and about 1K for interrupts.

		ADD.L	#2048,D3					;ADD 2 KBYTE SLOP
;
;  If stack is too small to allocate buffer(s), then draw half as many characters at a time.
;
		_StackAvail 						;Get StackAvail IN D0
		CMP.L	D0,D3						;IS stackNeeded > stackAvail ?
		BLE.S	StackAlmost 				;NO, CONTINUE

DoSubDivide
		MOVE	stackOffset(A6),D6			;2 if stack was not aligned, otherwise, 0
		MOVE	count(A6,D6),D0				;how many characters to draw
		MOVE	D0,D7						;figure half
		LSR		#1,D7
		BNE.S	@subDivide					;if more than 1 left, can subdivide problem
		SUBQ	#1,charsRemain(A6)			;pretend the one character was drawn
		BRA		GoHome						;if only 1 character, punt

@subDivide
; *** look for space character?  Could adjust D7 to coincide with a space if any, making
; *** drawing look better (for italics, kerns)

		TST		charsRemain(A6)				;if zero, this is the first time through
		BNE.S	@notFirst
		MOVE.B	HiliteMode,saveHilite(A6)	;save original in case stretch is called multiple times
		MOVE	D0,charsRemain(A6)			;initialize partial count drawing location
@notFirst
		MOVE.L	PENLOC(A6),PNLOC(A3)		;RESTORE PNLOC TO ORIGINAL
		TST		PORTBITS+ROWBYTES(A3)		; is it a new port?
		BPL.S	@useOld						; no, no fraction to restore
		MOVE	PenLocHFrac(A6),pnLocHFrac(A3) ;restore fraction if applicable
@useOld
		MOVE	D7,count(A6,D6)				;reset count to draw
doIterate
		MOVE.L	grafGlobals(A5),A4			;set up grafGlobals pointer for getting real width
		MOVE.L	numer2(A6),numer(A6,D6)		;restore numerator
		MOVE.L	denom2(A6),denom(A6,D6)		;restore denominator
		MOVE.B	saveHilite(A6),HiliteMode	;restore hilite bit
;
; < ABOVE COPIED VERBATIM FROM THE ROM >
;---------------------------------------------------------------------------------------
;		JMP		Iterate						;draw first half of string
		JMPRom	RomIterate					;
;---------------------------------------------------------------------------------------
; < BELOW COPIED VERBATIM FROM THE ROM >
;
; draw the second half of the string, but drawing no more characters than could be successfully
; drawn by the first half.

secondHalf
		MOVEQ	#0,D7						;zero high word
		MOVE	stackOffset(A6),D6			;2 if stack was not aligned, otherwise, 0
		MOVE	count(A6,D6),D7				;number of characters drawn last
		MOVE	charsRemain(A6),D0			;how many characters remain?
		CMP		D0,D7						;donÕt try to draw more than worked last
		BLE.S	@ok
		MOVE	D0,count(A6,D6) 			;draw what remains for the second half
@ok
		ADD.L	D7,textAddr(A6,D6)			;bump source address by half already drawn
		BRA.S	doIterate

; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
;
;  Allocate and clear an off-screen buffer
;
; If the source font is only 1 bit deep, clear the screen to white.  Also, if the transfer
; mode is xor, bic, or, clear the screen to white.  If an arithmetic mode or copy and
; source is multibits deep, assume depth of source font is equal to destination depth.
; Also assume that background of buffer must be colored the same as the port background color.

StackAlmost
		MOVEQ	#0,D0						;get a long of white
		TST		bitShift(A6)				;is source 1 bit?
		BEQ.S	@whiteBackCol
		CMP		#srcXor,locMode(A6)			;srcXor?
		BEQ.S	@whiteBackCol				;even if font contains colors, leave background white
		TST.B	colorSource(A6)				;font contains color?
		BNE.S	@useBackCol					;if so, must color the buffer
		CMP		#$32,locMode(A6)			;hilite?
		BEQ.S	@whiteBackCol				;leave background white if so
		BTST	#5,locMode+1(A6)			;arithmetic?
		BEQ.S	@whiteBackCol				;if copy, or leave background white
@useBackCol
		SUBQ	#6,SP						;allocate VAR RGBColor
		MOVE.L	SP,-(SP)					;point to VAR RGBColor
		_GetBackColor						;ask for the background color
		CLR.L	-(SP)						;make room for function result
		PEA		4(SP)						;point to VAR RGBColor
		_Color2Index
		MOVEQ	#0,D0
		MOVEQ	#32,D1						;
		MOVE	bitDepth(A6),D2				;get destination bits per pixel
@nxtPixel
		ASL.L	D2,D0
		OR.l	(SP),D0						;or in result of color2Index	<BAL 04July88>
		SUB		D2,D1
		BGT.S	@nxtPixel
		ADD		#10,SP						;strip RGBColor and long result

@whiteBackCol
		MOVE.L	D0,bkCol(A6)				;save for comparing with background, later

STACKOK	MOVE	bufSize(A6),D3
		SUBQ 	#1,D3						;INIT DBRA LOOP COUNT
		MOVE.L	D0,-(SP)					;PAD BUFFER WITH AN EXTRA ZERO
		MOVE.L	SP,BUFEND(A6)				;REMEMBER WHERE BUFFER ENDS
CLRLOOP MOVE.L	D0,-(SP)
		DBRA	D3,CLRLOOP					;ALLOCATE AND CLEAR BUFFER
		MOVE.L	SP,BUFSTART(A6) 			;REMEMBER START OF BUFFER
		MOVE.L	D0,-(SP)					;PAD BUFFER WITH AN EXTRA ZERO

		TST.B	maskFont(A6)
		BEQ.S	@noMask
		MOVE	maskSize(A6),D3
		SUBQ	#1,D3
		CLR.L	-(SP)
@clrMask
		CLR.L	-(SP)
		DBRA	D3,@clrMask
		MOVE.L	SP,maskStart(A6)
@noMask
		CLR.L	-(SP)
;
;  Get pointers to location table, width table, and height table in font
;
GETPTRS
		LEA 	26(A2),A0					;GET START OF FONT BITMAP
		MOVEQ	#0,D0						;zero high word
		MOVE	FBBDY(A2),D0				;GET HEIGHT OF FONT BITMAP
		MULU.L	SRCROW(A6),D0				;CALC TOTAL SIZE OF STRIKE
		ADD.L	D0,A0						;A1 := START OF LOC TABLE
		MOVE.L	A0,LOCTAB(A6)				;SAVE FOR LATER

; *** could test bitShift first and only check fNDescent if bitDepth > 1 É

		MOVE.W	fNDescent(A2),D0			;possibly the high word of owTLoc
		SWAP	D0							;put it in the high word
		BPL.S	@notNegative
		MOVEQ	#0,D0						;old fonts have negative of ascent here
@notNegative
		MOVE	LENGTH(A2),D0				;HOW MANY WORDS IN STRIKE BODY
		LEA 	16(A2,D0.L*2),A1			;GET START OF WIDTH TABLE
		MOVE.L	A1,WIDTAB(A6)				;SAVE FOR LATER

		MOVE	MAXCHAR(A2),D0				;GET MAXCHAR
		MOVE	MINCHAR(A2),D1				;GET MINCHAR
		MOVE	D1,MINCH(A6)				;STASH MINCHAR FOR LATER
		SUB 	D1,D0						;CALC MAXCHAR-MINCHAR
		MOVE	D0,MAXMIN(A6)				;SAVE FOR LATER

		ADD 	#3,D0						;CALC MAXMIN+3
		BTST	#1,1(A2)					;DOES FONT HAVE WIDTH TABLE ?
		BEQ.S	NOWID						;NO, CONTINUE
        ADD     D0,D0                       ;SKIP WIDTH TABLE
NOWID	LEA 	0(A1,D0*2),A0 				;POINT TO HEIGHT TABLE
		MOVE.L	A0,HEIGHTAB(A6) 			;SAVE FOR LATER

;
;  Set up space width
;
	    MOVE.L  widthTabHandle,A0           ;point to width table
        MOVE.L  (A0),A0
		MOVE.L	128(A0),SPWIDTH(A6) 		;get width of the space char
;
;  Setup misc stuff in registers for speed
;
		MOVE	BUFLEFT(A6),D1				;GET BUFLEFT
		MOVE	PENLOC+H(A6),D0 			;GET PEN LOCATION
		ADD 	kernAdjust(A6),D0			;ADJUST FOR KERNING
		SUB 	D1,D0						;MAKE CHARLOC RELATIVE TO BUFLEFT
		MOVE.W	D0,CHARLOC(A6)				;INIT INT PART OF CHARLOC
		TST		PORTBITS+ROWBYTES(A3)		;is it a new port?
		BPL.S	@useOld						;no, set fraction to 1/2

		MOVE	penLocHFrac(A6),CHARLOC+2(A6) ;set up fractional part		<PB362> BAL
		BRA.S	@goOn
@useOld
		MOVE	#$8000,CHARLOC+2(A6)
@goOn
		SUB 	D1,MINRECT+LEFT(A6) 		;MAKE MINRECT.LEFT AND
		SUB 	D1,MINRECT+RIGHT(A6)		;MINRECT.RIGHT BUFFER RELATIVE
		MOVE	stackOffset(A6),D0
		MOVE.L	TEXTADDR(A6,D0),A1 			;GET TEXTPTR
		BRA.S	NEXTCH						;GO TO LOOP START


;---------------------------------------------------
;
;  Here's the main character drawing loop:
;
MISSING
		MOVE	MAXMIN(A6),D0				;NO, USE MISSING SYMBOL
		ADD 	#1,D0						;WHICH IS ONE PAST MAXCHAR
		MOVE.L	WIDTAB(A6),A0				;POINT TO WIDTH TABLE
		MOVE	0(A0,D0*2),D3 				;GET OFFSET AND WIDTH BYTES
     	CMP     #-1,D3                      ;missing?
        BNE		NOTMISS                     ;IS MISSING CHAR MISSING ?
        BRA.S   NEXTCH                      ;YES, SKIP THIS CHAR

SPACECH MOVE.L	SPWIDTH(A6),D1				;GET SPACE WIDTH
		ADD.L	D1,CHARLOC(A6)				;BUMP CHARLOC
SKIPCH	SUB		#1,charsRemain(A6)			;decrement total character count
		SUB 	#1,countCopy(A6)			;decrement partial draw character count
		BLE 	STRDONE 					;QUIT IF CHARCOUNT <= 0
NEXTCH	CLR 	D0							;get ready for byte
		MOVE.B	(A1)+,D0					;GET NEXT CHAR
		CMP.B	#32,D0						;IS IT A SPACE ?
		BEQ.S	SPACECH 					;YES, HANDLE IT

	    MOVE.L  WidthTabHandle,A0           ;POINT TO WIDTH TABLE
        MOVE.L  (A0),A0
		MOVE	D0,D4						;COPY CHARACTER
		MOVE.L	0(A0,D4*4),D4 				;GET FIXED POINT WIDTH
		ADD.L	characterExtra(A6),D4		;add in character extra, if any

;
; < ABOVE COPIED VERBATIM FROM THE ROM >
;
;---------------------------------------------------------------------------------------
;
;		BLE.S	SKIPCH						;SKIP CharBlt if Advance width <= 0 	<1.6-11april89-CEL>
;
;---------------------------------------------------------------------------------------
;
; < BELOW COPIED VERBATIM FROM THE ROM UNTIL FURTHER NOTICE >
;
		SUB 	MINCH(A6),D0				;SUBTRACT SAVED MINCHAR
		CMP 	MAXMIN(A6),D0				;IS CH BETWEEN MINCHAR AND MAXCHAR ?
		BHI		MISSING						;Missing so skip it

OKCHAR	MOVE.L	WIDTAB(A6),A0				;POINT TO WIDTH TABLE
		MOVE	0(A0,D0*2),D3 				;GET OFFSET AND WIDTH BYTES
        CMP     #-1,D3                      ;missing?
        BEQ		MISSING                     ;OFFSET NEG = MISSING CHAR

NOTMISS LSR 	#8,D3						;GET OFFSET BYTE
		ADD.W	CHARLOC(A6),D3				;DSTLEFT := CHARLOC.INT + OFFSET
		ADD.L	D4,CHARLOC(A6)				;ADD FIXED POINT WIDTH TO CHARLOC

		MOVE.L	LOCTAB(A6),A0				;POINT TO LOCATION TABLE
		MOVEQ	#0,D1						; *** clear top word
		MOVE	0(A0,D0*2),D1 				;GET SRCLEFT
		MOVE	2(A0,D0*2),D2 				;GET SRCRIGHT
		SUB 	D1,D2						;CALC WIDTH OF BITS
		BLE		SKIPCH						;SKIP CHARBLT IF WIDTH <= 0
		MOVE	D2,charWidth(A6)			;save for later
		ADD 	D3,D2						;DSTRIGHT := DSTLEFT + WIDTH

		TST.B	HEIGHTFLAG(A6)				;does font have height table ?
		BEQ.S	NOHEIGHT					;no, continue
		MOVE.L	HEIGHTAB(A6),A0 			;get height table
		MOVE	0(A0,D0*2),TOPHT(A6)		;get this char's top and height
NOHEIGHT

;-----------------------------------------------------------------------
;
;  Horizontal clip only if FastFlag:   (else stretch,outline,shadow,italic die)
;
;  skip if hidden on left, string done if hidden on right.
;
;  at this point:	D1: srcLeft
;			D2: dstRight
;			D3: dstLeft
;
		TST.B	FastFlag(A6)				;ARE WE GOING FAST ?
		BEQ.S	HORIZOK 					;NO, DON'T CLIP
		CMP 	MINRECT+LEFT(A6),D3 		;IS DSTLEFT < MINRECT.LEFT ?
		BGE.S	LEFTOK						;NO, CONTINUE
		CMP 	MINRECT+LEFT(A6),D2 		;IS DSTRIGHT <= MINRECT.LEFT ?
		BLE 	SKIPCH						;YES, SKIP THIS CHAR
TRIMLFT MOVE	MINRECT+LEFT(A6),D0 		;NO, GET MINRECT.LEFT
		SUB 	D3,D0						;DISCARD:=MINRECT.LEFT-DSTLEFT
		ADD 	D0,D1						;SRCLEFT:=SRCLEFT+DISCARD
		ADD 	D0,D3						;DSTLEFT:=DSTLEFT+DISCARD
		CMP 	MINRECT+RIGHT(A6),D2		;IS DSTRIGHT > MINRECT.RIGHT ?
		BLE.S	fixCharWidth 				;NO, CONTINUE
		BRA.S	TRIMRT						;YES, TRIM RIGHT
LEFTOK	CMP 	MINRECT+RIGHT(A6),D2		;IS DSTRIGHT <= MINRECT.RIGHT ?
		BLE.S	HORIZOK		 				;YES, CONTINUE
		CMP 	MINRECT+RIGHT(A6),D3		;IS DSTLEFT >= MINRECT.RIGHT ?
		BGE 	STRDONE 					;YES, IGNORE REST OF STRING
TRIMRT	MOVE	MINRECT+RIGHT(A6),D2		;NO, TRIM DSTRIGHT
fixCharWidth
		MOVE	D2,D0						;char width has been trimmed left, right, or both
		SUB		D3,D0						;so recalculate char width to draw
		MOVE	D0,charWidth(A6)			;and save this tidbit of info. for later
HORIZOK

;--------------------------------------------------------------
;
;  Inputs to local block CharBlt:
;
;	  srcAddr(A6)
;	  srcRow(A6)
;	  bufStart(A6) = dstAddr
;	  bufRow(A6) = dstRow
;	  D1 = srcLeft
;	  D2 = dstRight 		relative to buffer, > dstLeft
;	  D3 = dstLeft			relative to buffer
;	  TOPHT(A6) 			top and height
;
;	  CLOBBERS:  D0,D1,D2,D3,D4,D5,D6,D7,A0,A2,A3,A4,A5
;	  PRESERVES: A1,A6,A7
;
;
;  Setup shift count in D5 (relative shift between src and dst)
;

		MOVEM	D1-D3,maskBlts(A6)
		MOVE.B	textCopyMode(A6),orNotOK(A6) ;if copy or if mask mode, do bit moves instead of OR

		ST		notMaskPass(A6)				;use the bitDepth this pass
		MOVE	bitShift(A6),D0				;get font scale factor
		LSL		D0,D1
		LSL		D0,D2
		LSL		D0,D3						;scale up all three
		MOVE	BUFROW(A6),A3
		MOVEM.L	SRCROW(A6),A2/A4-A5			;srcRow, srcAddr (src bitmap), bufStart (dst bitmap)
maskBlt
;
;  Get char height into D7
;
		MOVE.W	#255,D7 			 		;GET -1 BYTE, CLEAR HI BYTE
		ADD.B	TOPHT+1(A6),D7				;CALC HEIGHT-1 FOR DBRA LOOP
		BMI 	SKIPCH						;OOPS HEIGHT WAS ZERO !
;
;  Adjust srcPtr and dstPtr for charTop
;
		MOVEQ	#0,D0						;get ready for byte
		MOVE.B	TOPHT(A6),D0				;get char top
		MOVE.L	A2,D4						;get srcRow in D-reg
		MULU.L	D0,D4						;calc charTop * srcRow
		ADD.L	D4,A4						;add to srcPtr
		MOVE	A3,D4						;get dstRow in D-reg
		MULU	D0,D4						;calc charTop * dstRow
		ADD.L	D4,A5						;add to dstPtr
;
;  figure alignment offset in source so that dest is long aligned
;
		MOVEQ	#$1F,D0						;get a 5 bit mask, needed later
		MOVE.L	D1,D5
;
;  Setup dstPtr in A5, address of leftmost dst word
;
		MOVE	D3,D6						;GET A COPY OF DSTLEFT
		ASR 	#5,D6						;CONVERT FROM DOTS TO LONGS
		MOVE	D6,D4						;copy dest left in longs for later
		LSL		#2,D6						;quad for bytes
		ADD 	D6,A5						;move dest pointer to top of character

;
;  figure number of longs to move
;
		MOVE	D2,D6						;copy dstRight
		ASR		#5,D6
		SUB		D4,D6						;if same, it fits into a single long
		BEQ		fitsInLong					;most 1 bit deep characters fit into a long

;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
;
; Character spans long in destination, so it must be moved in pieces
; Registers used at this point:
; D0 = 5 bit mask		D1 = src offset		D2 = dstRight		D3 = dstLeft
; D4 = --				D5 = src offset		D6 = longs to move	D7 = character height
; A0 = --				A1 = character ptr	A2 = source row sz	A3 = dest row size
; A4 = source row ptr	A5 = dest row ptr	A6 = locals			A7 = stack

		NEG		D3							;negate for bit counting
		AND 	D0,D3						;get bottom 5 bits of dstLeft
		BNE.S	@skip32
		MOVEQ	#32,D3						;if 0, make it 32
@skip32

		MOVE	D6,D4						;total longs (not including left part)
		LSL		#2,D4						;make it a byte count
		SUB		D4,A2						;adjust source bump count
		SUB		D4,A3						;adjust dest. bump count
		SUBQ	#1,D6						;number of whole longs, less left & right parts
		ADD		D3,D1						;the right hand start
		MOVEQ	#32,D4
		SUB.L	D4,D1

;
;  if not 1 bit font & mode is not srcOr, do moves instead
;
		TST.B	orNotOK(A6)
		BNE.S	DoMove

;
; OR words to the screen; set up right mask
;
		AND		D0,D2						;get bottom 5 bits of dstRight
		MOVEQ	#1,D4
		ROR.L	#1,D4						;set the high bit
		ASR.L	D2,D4						;$80000000 to $FFFFFFFF
		ASL.L	#1,D4						;$00000000 to $FFFFFFFE

		MOVE	D6,D2						;initialize whole long count
		MOVE	D6,A0						;save long count for later
		MOVE.L	D5,D6
		ADD		D3,D6
		MOVEQ	#32,D0
		SUB.L	D0,D6
;
;  Slow loop only taken in wierd cases where dst wider than a long.
;  Or the more common case that the font is more than 1 bit deep
;

MAIN1
		BFEXTU	(A4){D5:D3},D0 				;GET SRC FROM BITMAP
		BRA.S	@checkLong					;see if there is some number of longs to do
@main2
		BFEXTU	(A4){D6:0},D0 				;GET SRC FROM BITMAP
@checkLong
		OR.L	D0,(A5)+					;OR SRC INTO DST
		ADDQ 	#4,A4						;BUMP SRCPTR RIGHT
		DBRA	D2,@main2					;LOOP TILL LAST long

		BFEXTU	(A4){D1:0},D0 				;GET SRC FROM BITMAP
		AND.L	D4,D0
		OR.L	D0,(A5) 					;OR SRC INTO DST
		ADD.L 	A2,A4						;BUMP TO NEXT ROW
		ADD.L	A3,A5						;BUMP DST TO NEXT ROW
WIDE1	MOVE	A0,D2						;GET long count
		DBRA	D7,MAIN1					;LOOP ALL ROWS
		BRA		decCount					;skip mask blt part

;
; Handle case of drawing into the offscreen bit map in color separately
;
DoMove
		MOVE	D2,D4						;copy dstRight
		AND 	D0,D4						;get bottom 5 bits of dstRight

		MOVE	D6,longCount(A6)			;save # of whole longs
		MOVE	D6,D2						;set up first loop count
		MOVE.L	bkCol(A6),D6				;get a long full of the background color
		BFEXTU	D6{0:D3},D0					;background color & left mask
		MOVE.L	D0,leftBack(A6)				;save for quick compare
		BFEXTU	D6{0:D4},D0					;background color & right mask
		MOVE.L	D0,rightBack(A6)			;right mask color compare
		MOVE	bitDepth(A6),D0				;bits in a single pixel
		BFEXTU	D6{0:D0},D0					;get a single pixel of the background color
		MOVE	D0,bkCol1(A6)				;a single background color for quick compare
		MOVEQ	#32,D6						;
		SUB		D3,D6						;
		MOVE.L	D5,A0
		ADD		D3,A0
		SUB		#32,A0						;set up center move offset

;
;  Slow loop taken in cases where dst wider than a long (common for fonts more than 1 bit
;  deep.)  Need to move only the pixels that are not colored same as background.
;
MoveLeft
		BFEXTU	(A5){D6:D3},D0 				;get current background of destination
		CMP.L	leftBack(A6),D0				;compare it against the background color AND leftMask
		BNE.S	leftOnePix					;if different, must move 1 pixel at a time
;
; Here the destination has only background color pixels, so the whole thing can be moved
;
		BFEXTU	(A4){D5:D3},D0 				;GET SRC FROM BITMAP
		BFINS	D0,(A5){D6:D3}
checkLong
		EXG		A0,D5						;set up center move offset
midChkLong
		ADDQ	#4,A5						;bump destination
		BRA.S	checkMLong					;see if there is some number of longs to do

MoveMid
		MOVE.L	bkCol(A6),D0
		CMP.L	(A5),D0						;same as background color?
		BNE.S	midOnePix					;if different, move 1 at a time
		BFEXTU	(A4){D5:0},D0 				;GET SRC FROM BITMAP
		MOVE.L	D0,(A5)+					;OR SRC INTO DST
checkMLong
		ADDQ 	#4,A4						;BUMP SRCPTR RIGHT
		DBRA	D2,MoveMid					;LOOP TILL LAST WORD

MoveRight
		EXG		A0,D5						;set up left move offset
		TST		D4
		BEQ.S	nextRow
		BFEXTU	(A5){0:D4},D0 				;look at the destination
		CMP.L	rightBack(A6),D0			;compare it against the background AND rightMask
		BNE.S	rightOnePix					;if different, must move 1 pixel at a time
;
; Here the destination has only background color pixels, so the whole thing can be moved
;
		BFEXTU	(A4){D1:D4},D0 				;get the right part of the character
		BFINS	D0,(A5){0:D4} 				;move it to the destination
nextRow
		ADD.L 	A2,A4						;BUMP TO NEXT ROW
		ADD.L	A3,A5						;BUMP DST TO NEXT ROW
offMove
		MOVE	longCount(A6),D2			;GET long count
		DBRA	D7,MoveLeft					;LOOP ALL ROWS
		BRA		checkMask

;
; need to move only the pixels that are not colored same as background
;

leftOnePix
		MOVEM.L	D1/D3-D6,-(SP)				;save temporary registers
		MOVEM	bkCol1(A6),D0/D1			;D0 = back color   D1 = pixel width
@nxtPixel
		BFEXTU	(A4){D5:D1},D4				;pick up a source pixel
		CMP		D4,D0						;is it the same as the back color?
		BEQ.S	@skipInsert					;if so, donÕt add to destination
		BFINS	D4,(A5){D6:D1}				;if not, copy it to the destination
@skipInsert
		ADD.L	D1,D5						;move to next source pixel
		ADD		D1,D6						;move to next destination pixel
		SUB		D1,D3						;decrement count
		BGT.S	@nxtPixel					;do until weÕre done
		MOVEM.L	(SP)+,D1/D3-D6				;restore bkCol, left & right widths, src & dest offsets
		BRA.S	checkLong

midOnePix
		MOVEQ	#32,D0						;full long size in bits
		MOVEM.L	D1/D3-D6,-(SP)				;save temporary registers
		MOVEQ	#0,D6
		MOVEM	bkCol1(A6),D1/D3			;D1 = back color   D3 = pixel width
@nxtPixel
		BFEXTU	(A4){D5:D3},D4				;pick up a source pixel
		CMP		D4,D1						;is it the same as the back color?
		BEQ.S	@skipInsert					;if so, donÕt add to destination
		BFINS	D4,(A5){D6:D3}				;if not, copy it to the destination
@skipInsert
		ADD.L	D3,D5						;move to next source pixel
		ADD		D3,D6						;move to next destination pixel
		SUB		D3,D0						;decrement count
		BGT.S	@nxtPixel					;do until weÕre done
		MOVEM.L	(SP)+,D1/D3-D6				;restore bkCol, left & right widths, src & dest offsets
		BRA		midChkLong

rightOnePix
		MOVEM.L	D1/D3-D6,-(SP)				;save temporary registers
		MOVEQ	#0,D6
		MOVEM	bkCol1(A6),D3/D5			;D3 = back color   D5 = pixel width
@nxtPixel
		BFEXTU	(A4){D1:D5},D0				;pick up a source pixel
		CMP		D0,D3						;is it the same as the back color?
		BEQ.S	@skipInsert					;if so, donÕt add to destination
		BFINS	D0,(A5){D6:D5}				;if not, copy it to the destination
@skipInsert
		ADD.L	D5,D1						;move to next source pixel
		ADD		D5,D6						;move to next destination pixel
		SUB		D5,D4						;decrement count
		BGT.S	@nxtPixel					;do until weÕre done
		MOVEM.L	(SP)+,D1/D3-D6				;restore bkCol, left & right widths, src & dest offsets
		BRA		nextRow

;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
; Here, the character does not cross a long boundary, so faster loops are in order.
;

fitsInLong
		MOVE	charWidth(A6),D3			;set up character width in bits
		TST.B	notMaskPass(A6)				;if dest is 1 bit, or this is the mask,
		BEQ.S	@skipMul					;then skip the mul scale
		MOVE	bitShift(A6),D4				;set up bit depth
		LSL		D4,D3
@skipMul
		TST.B	orNotOK(A6)					;can we OR?
		BNE.S	offLong						;if not, bit extract/insert instead
;
;  Optimize if dst fits in one long.   (most 1 bit deep characters do)
;
LONG1
;
; OR words to the screen; set up right mask

		MOVE	D2,D1						;copy dest right
		NEG		D1							;figure not bits from left but bits from right
		AND		D0,D1						;but only from 0 to 31
		ADD		D1,D3						;add right mask to extract width

		AND		D0,D2						;get bottom 5 bits of dstRight
		MOVEQ	#1,D4
		ROR.L	#1,D4						;set the high bit
		ASR.L	D2,D4						;$80000000 to $FFFFFFFF
		ASL.L	#1,D4						;$00000000 to $FFFFFFFE

; if D5 + D3 < 32, use a faster set of code:

longLoop
		BFEXTU	(A4){D5:D3},D0				;GET SRC DATA
		AND.L	D4,D0
		OR.L	D0,(A5)						;OR RESULT INTO DST
		ADD.L 	A2,A4						;BUMP SRCPTR TO NEXT ROW
		ADD.L 	A3,A5						;BUMP DSTPTR TO NEXT ROW
		DBRA	D7,longLoop					;LOOP ALL ROWS
		BRA.S	decCount
;
;  Optimize if dst fits in one long.   (most normal characters do)
;
offLong
		MOVE	D2,D6
		AND.L	D0,D6
		SUB		D3,D6
		BFEXTU	bkCol(A6){0:D3},D2
		MOVEM.L	D5/D6,leftOffset(A6)		;save source left, destination left offsets
		MOVE	D5,D0						;source left offset less
		ADD		D3,D0						; width of pixels to be moved
		MOVE	D0,longCount(A6)			; determines inner loop bounds
		MOVE	bitDepth(A6),D4				;get source depth
		BFEXTU	D2{0:D4},D1					;set up 1 pixel of background color

offLongLoop

; check to see if existing destination is untouched (equal to background) so that there is no
; concern about obliterating over a part of a character that kerns into this space.

		BFEXTU	(A5){D6:D3},D0				;get the existing background
		CMP.L	D2,D0						;is it background colored?
		BEQ.S	@okToBlast					;if so, it is safe to cut and fill

; inner loop taken if some kerning has occured so that bits can not be moved directly over bkground

@nxtPixel
		BFEXTU	(A4){D5:D4},D0
		CMP		D0,D1
		BEQ.S	@skipInsert
		BFINS	D0,(A5){D6:D4}
@skipInsert
		ADD		D4,D6
		ADD		D4,D5
		CMP		longCount(A6),D5			;where to stop with the mask
		BLT.S	@nxtPixel
		MOVEM.L	leftOffset(A6),D5/D6		;restore source left, destination left offsets
		BRA.S	@nextRow

; if no kerning, data can be moved without concern for what is already there.

@okToBlast
		BFEXTU	(A4){D5:D3},D0				;GET SRC DATA
		BFINS	D0,(A5){D6:D3}				;move to destination
@nextRow
		ADD.L 	A2,A4						;BUMP SRCPTR TO NEXT ROW
		ADD.L 	A3,A5						;BUMP DSTPTR TO NEXT ROW
		DBRA	D7,offLongLoop				;LOOP ALL ROWS

;
; here, set up things for mask blt
;
checkMask
		TST		bitShift(A6)				;is source depth 1?
		BEQ.S	decCount					;if so, skip mask (just copy result to mask later)
		TST.B	maskFont(A6)
		BEQ.S	decCount
		SF		orNotOK(A6)					;next time through, can OR the mask
		SF		notMaskPass(A6)				;force bitDepth to 1 this pass
		MOVEM	maskBlts(A6),D1-D3/A3		;set up words
		MOVEM.L	mSrcROW(A6),A2/A4/A5		;set up longs
		BRA		maskBlt						;then blt mask

decCount
		SUB		#1,charsRemain(A6)			;decrement total character count
		SUB 	#1,countCopy(A6)			;decrement partial draw character count
		BGT 	NEXTCH						;LOOP IF MORE CHARS LEFT

;------

STRDONE MOVE.L	SAVEA5(A6),A5				;RESTORE GLOBAL PTR
		TST.B	FASTFLAG(A6)				;WERE WE GOING DIRECT TO SCREEN ?
		BEQ.S	@1							;NO, CONTINUE
		TST.B	CRSRFLAG(A6)				;DRAWING TO SCREEN?
		BEQ.S	@0							;=>IF NOT, JUST RETURN
		move.b	MMUsave(a6),d0				;get previous MMU state in d0
		_rSwapMMUMode						;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2)
@32bitNot
		_SHOWCURSOR							;YES, RESTORE CURSOR
@0		BRA 	GOHOME						;AND QUIT
@1		MOVE.L	GRAFGLOBALS(A5),A0			;POINT TO QUICKDRAW GLOBALS
		MOVE.L	THEPORT(A0),A3				;GET CURRENT GRAFPORT
		MOVE.L	FONTPTR(A0),A4				;POINT TO FMOUTPUT
		MOVE.L	2(A4),A2					;GET FONT HANDLE
		MOVE.L	(A2),A2 					;DE-REFERENCE IT
		MOVE	CHARLOC(A6),D7				;GET FINAL CHARLOC INT PART
		SUB 	fKernMax(A2),D7				;UN-ADJUST FROM KERNING, but not italic
;
;  Make buffer bold if necessary:
;
CKBOLD	CLR 	D2							;GET READY FOR BYTE
		MOVE.B	6(A4),D2					;GET NUMBER OF OVERSTRIKES
		BRA.S	NXTBOLD 					;BOLD BUFFER IF ANY
BOLDIT	MOVE.L	BUFSTART(A6),A0 			;POINT TO START OF BUFFER
		MOVE	BUFSIZE(A6),D1				;HOW MANY LONGS IN BUF
		SUB 	D0,D0						;CLEAR X-BIT
BOLDLP	MOVE.L	(A0),D0 					;GET ONE LONG
		ROXR.L	#1,D0						;ROTATE RIGHT WITH EXTEND
		OR.L	D0,(A0)+					;OR BACK INTO BUFFER
		DBRA	D1,BOLDLP					;LOOP ENTIRE BUFFER
NXTBOLD DBRA	D2,BOLDIT					;LOOP FOR EACH OVERSTRIKE


;
;  Slant the buffer if necessary:
;  Work from bottom of buffer up, shifting each row right.
;  Work right to left to avoid clobbering src.
;
		MOVEQ	#0,D2						;GET READY FOR BYTE
		MOVE.B	7(A4),D2					;DO WE NEED ITALIC ?
		BEQ.S	CHECKUL 					;NO, CONTINUE

		MOVE.L	BUFEND(A6),A1				;DSTPTR:=END OF BUFFER
		MOVE	BUFROW(A6),D3				;GET BUFFER ROWBYTES
		SUB 	D3,A1						;BACK UP DSTPTR TO END OF 2ND ROW
		LSR 	#2,D3						;LONGCNT:=ROWBYTES DIV 4
		SUB 	#1,D3						;LONGCOUNT-1 FOR DBRA LOOP

		MOVE	HEIGHT(A6),D6				;INIT ROW COUNTER
		MOVEQ	#0,D4						;INIT OFFSET
		BRA.S	DOSLANT 					;GO TO LOOP START
NXTROW	ADD.L	D2,D4						;OFFSET:=OFFSET+ITALIC
		MOVE.L	D4,D5						;COPY OFFSET
		LSR.L 	#4,D5						;DELTA := OFFSET SCALED BY 16
		NEG.L	D5							;make negative for BFEXTU
		MOVE.L	A1,A0						;SRCPTR:=DSTPTR
		SUB 	#4,A0						;POINT TO LAST LONG

		MOVE	D3,D1						;INIT LOOP TO LONGCNT
NXTLONG BFEXTU	(A0){D5:0},D0 				;GET A SHIFTED LONG OF SRC
		SUB 	#4,A0						;BUMP SRCPTR LEFT ONE LONG
		MOVE.L	D0,-(A1)					;STORE IN DST AND BUMP DSTPTR
		DBRA	D1,NXTLONG					;LOOP ALL LONG THIS ROW
DOSLANT DBRA	D6,NXTROW					;LOOP FOR ALL ROWS IN BUFFER


;
;  Underline characters in buffer if necessary.
;
;  Use characters in buffer to hide parts of the underline.
;
CHECKUL TST.B	10(A4)						;IS ULTHICK ZERO ?
		BEQ.S	NOTUL						;YES, CONTINUE
		MOVE.L	BUFSTART(A6),A0 			;POINT TO BUFFER START
		MOVE	BUFROW(A6),D1				;GET BYTES PER ROW OF BUFFER
		MOVE	locASCENT(A2),D0			;GET ASCENT
		MOVE	locDESCENT(A2),D2			;GET DESCENT
		MULU	D1,D0
		ADD.L	D0,A0						;POINT TO BASELINE ROW
		MOVE.L	A0,A1
		MOVE.L	A0,A2
		ADD 	D1,A1						;POINT TO BASELINE+1
		CMP 	#2,D2						;IS DESCENT AT LEAST 2 ?
		BLT.S	NOTUL						;NO, SKIP UNDERLINE
		BEQ.S	ONLY2						;ONLY USE 2 IF DESCENT=2
		ADD 	D1,A2
		ADD 	D1,A2						;POINT TO BASELINE+2
ONLY2	SUB 	D1,SP						;ALLOCATE TEMP SCANBUF
		MOVE.L	A3,-(SP)					;SAVE GRAFPORT
		LEA 	4(SP),A3					;POINT TO START OF TEMP
		LSR 	#2,D1						;CONVERT BYTES TO LONGS
		SUB 	#1,D1						;INIT DBRA LOOP COUNT
		MOVE	D1,D2						;COPY LOOP COUNT
		SUB 	D0,D0						;CLEAR X-BIT
UL1 	MOVE.L	(A0)+,D0					;GET FROM BASELINE
		OR.L	(A1)+,D0					;OR WITH BASELINE+1
		OR.L	(A2)+,D0					;OR WITH BASELINE+2
		MOVE.L	D0,(A3) 					;PUT RESULT TO TEMP
		ROXR.L	#1,D0						;SHIFT WITH CARRY
		OR.L	D0,(A3)+					;OR INTO TEMP
		DBRA	D1,UL1						;LOOP ALL LONGS IN ROW

		MOVE.L	A1,A0						;COPY END PTR
		SUB 	D0,D0						;CLEAR X-BIT
UL2 	MOVE.L	-(A3),D0					;GET FROM TEMP
		ROXL.L	#1,D0						;SHIFT LEFT WITH CARRY
		OR.L	(A3),D0 					;OR WITH TEMP
		NOT.L	D0							;INVERT
		OR.L	D0,-(A1)					;DRAW SOME UNDERLINE
		DBRA	D2,UL2						;LOOP ALL LONGS IN ROW
		MOVE.L	(SP)+,A3					;RESTORE GRAFPORT
;
;  Setup fakeRgn, a dummy rectangular region
;
NOTUL	MOVE	#10,FAKERGN+RGNSIZE(A6) 	;SIZE=10 BYTES FOR RECT RGN
		MOVE.L	DSTPIX+BOUNDS(A6),FAKERGN+RGNBBOX(A6)
		MOVE.L	DSTPIX+BOUNDS+4(A6),FAKERGN+RGNBBOX+4(A6)
		LEA 	FAKERGN(A6),A0				;GET ADDR OF FAKERGN
		MOVE.L	A0,FAKEPTR(A6)				;POINT FAKE MASTERPTR TO IT


;
;  SET UP SOURCE BITMAP TO TRANSFER TO SCREEN
;
;  SRCPIX := buffer
;

		LEA 	SRCBITS(A6),A0				;POINT TO source bits
		MOVE.L	A0,A1
		MOVE.L	BUFSTART(A6),(A0)+			;SET UP BASEADDR
		MOVE	BUFROW(A6),(A0)+			;SET UP ROWBYTES
		MOVE	TEXTRECT+TOP(A6),(A0)+		;SET UP BOUNDS TOP
		MOVE	BUFLEFT(A6),(A0)+			;SET UP BOUNDS LEFT
		MOVE.L	TEXTRECT+BOTRIGHT(A6),(A0)+	;SET UP BOTTOM RIGHT
		LEA		SRCPIX(A6),A2
		_BitsToPix
		TST.B	maskFont(A6)
		BEQ.S	@finishSrcPix
		LEA 	maskBits(A6),A0				;POINT TO mask bits
		MOVE.L	maskStart(A6),(A0)+			;SET UP BASEADDR
		MOVE	mBufRow(A6),(A0)+			;SET UP ROWBYTES
		MOVE	TEXTRECT+TOP(A6),(A0)+		;SET UP BOUNDS TOP
		MOVE	BUFLEFT(A6),(A0)+			;SET UP BOUNDS LEFT
		MOVE.L	TEXTRECT+BOTRIGHT(A6),(A0)+	;SET UP BOTTOM RIGHT
@finishSrcPix
		TST		bitShift(A6)				;is the bit depth 1?
		BEQ.S	@skipColorJam
		MOVE	bitDepth(A6),srcPix+pixelSize(A6)		;set up bit depth
		MOVE.L	dstPix+pmTable(A6),srcPix+pmTable(A6) ;set up color table
@skipColorJam

;
;  check if any shadowing:
;
		CLR 	D3							;GET READY FOR BYTE
		MOVE.B	11(A4),D3					;GET SHADOW COUNT
		BEQ 	NOSHAD						;SKIP IF NO SHADOWING

;
;  Shadowing will be used. Allocate buf2, 4 scans taller than BUF1.
;  Clear out new 4 scanlines, and copy BUF1 into the rest.
;
		MOVE	BUFROW(A6),D0				;GET 4 * NUMBER OF LONGS PER ROW
		SUB 	#1,D0						;INIT LOOP COUNTER
		CLR.L	-(SP)						;ALLOW ONE LONG OF SLOP
		MOVE.L	SP,BUF2END(A6)				;REMEMBER END OF BUF2
CLR2	CLR.L	-(SP)						;ALLOCATE AND CLEAR A LONG
		DBRA	D0,CLR2 					;CLEAR 4 SCANLINES WORTH
		MOVE	BUFSIZE(A6),D0				;GET NUMBER OF LONGS IN BUF1
		SUB 	#1,D0						;INIT DBRA COUNTER
		MOVE.L	BUFEND(A6),A0				;POINT TO END OF BUF1
COPYLP	MOVE.L	-(A0),-(SP) 				;COPY FROM BUF1 TO NEW BUF2
		DBRA	D0,COPYLP					;COPY ALL OF BUF1
		MOVE.L	SP,BUF2START(A6)			;REMEMBER START OF BUF2
		CLR.L	-(SP)						;ALLOW ONE LONG OF SLOP

;
;  Bold buf2 across to the right enough for shadow.
;
		AND 	#3,D3						;RESTRICT SHADOW COUNT TO 1..3
		MOVE	D3,D2						;INIT BOLD COUNTER
ACROSS1 MOVE.L	BUF2START(A6),A0			;POINT TO START OF BUFFER2
		MOVE	BUFSIZE(A6),D1				;INIT COUNT OF LONGS
		SUB 	D0,D0						;CLEAR X-BIT
ACROSS2 MOVE.L	(A0),D0 					;GET A LONG FROM BUF2
		ROXR.L	#1,D0						;SHIFT IT RIGHT EXTENDED
		OR.L	D0,(A0)+					;OR IT BACK INTO BUFFER
		DBRA	D1,ACROSS2					;LOOP FOR ALL LONGS
		DBRA	D2,ACROSS1					;BOLD RIGHT 2,3, OR 4 TIMES

;
;  Bold BUF2 down enough for shadow.
;
		MOVE.L	BUF2START(A6),A2			;GET LIMIT POINTER
DOWN1	MOVE.L	BUF2END(A6),A1				;DSTPTR:=END OF BUF2
		MOVE.L	A1,A0
		MOVE	SRCBITS+ROWBYTES(A6),D2		;GET SRC ROWBYTES
		SUB 	D2,A0 						;SRCPTR:=END - 1 SCANLINE
DOWN2	MOVE.L	-(A0),D0					;GET A LONG FROM LINE ABOVE
		OR.L	D0,-(A1)					;OR INTO THIS LINE
		CMP.L	A2,A0						;IS SRCPTR <= BUF2START ?
		BGT.S	DOWN2						;NO, LOOP ALL LONGS
		DBRA	D3,DOWN1					;BOLD DOWN 2,3, OR 4 TIMES

; XOR the plain text into the shadow buffer

		MOVE	bufSize(A6),D1				;size of buffers in longs
		MOVE.L	bufStart(A6),A0				;start of plain text
		MOVE.L	A2,A1						;start of shadowed text
		ADD		D2,A1						;bump down a line in the shadowed text
		SUB		D0,D0						;clear x bit
@xor
		MOVE.L	(A0)+,D0					;a line of plain text
		ROXR.L	#1,D0						;shift it right, extended
		EOR.L	D0,(A1)+					;combine with shadowed text
		DBRA	D1,@xor						;repeat for all longs

;
;  Alter SRCBITS to use BUF2
;
		MOVE.L	A2,SRCBITS+BASEADDR(A6) 		;SRC BASEADDR:=BUF2START
		ADD 	#4,SRCBITS+BOUNDS+BOTTOM(A6)	;4 SCANS TALLER
;
;  Push params and call StretchBits to transfer shadow to screen
;
		MOVE.L	TEXTRECT(A6),SRCRECT(A6) 	;DSTRECT := SRCRECT
		MOVE.L	TEXTRECT+4(A6),SRCRECT+4(A6)
		ADD		#4,SRCRECT+BOTTOM(A6)		;PLUS 4 SCANS TALLER
		MOVE.L	SRCRECT(A6),DSTRECT(A6)
		MOVE.L	SRCRECT+4(A6),DSTRECT+4(A6)
		LEA 	DSTRECT+TOP(A6),A0			;OFFSET BY (-1,-1)
		SUB 	#1,(A0)+					;TOP
		SUB 	#1,(A0)+					;LEFT
		SUB 	#1,(A0)+					;BOTTOM
		SUB 	#1,(A0)+					;RIGHT

		TST.B	STRETCH(A6)
		BEQ.S	@1
		PEA 	DSTRECT(A6)
		PEA 	FROMRECT(A6)
		PEA 	TORECT(A6)
		_MAPRECT 							;THEN MAPPED FOR SCALING
@1

		PEA 	SRCBITS(A6) 				;PUSH SRCPIX
		MOVE.L	maskBitsPtr(A6),-(SP)		;a mask?
		BEQ.S	@noMask
		MOVE.L 	4(SP),(SP)					;replace mask with copy of source
@noMask
		PEA		PORTBITS(A3)				;TRANSFER TO SCREEN
		PEA 	SRCRECT(A6)					;PUSH SRCRECT = TEXTRECT
		PEA		SRCRECT(A6)					;maskRect same as source rect
		PEA 	DSTRECT(A6)					;PUSH DSTRECT = TEXTR2
		MOVE	locMode(A6),-(SP)			;PUSH TEXTMODE
		CLR.L	-(SP)						;NO PATTERN FOR NOW
		MOVE.L	CLIPRGN(A3),-(SP)			;PUSH CLIPRGN HANDLE
		MOVE.L	VISRGN(A3),-(SP)			;PUSH VISRGN HANDLE
		PEA 	FAKEPTR(A6) 				;PUSH FAKE HANDLE
		CLR		-(SP)						;pass multicolor flag false
		_StretchBits 						;TRANSFER BUFFER TO SCREEN

; if old port, srcOr, draw center part in bic; if bic, in srcOr
; (This is done for compatibility with older applications like MacProject and MacDraw that
; expect to put text on an arbitrary background, relying on the center of the shadow to show.)

		TST		portBits+rowBytes(A3)		;a new port?
		BMI.S	GOHOME
		MOVE	locMode(A6),D0
		CMP		#srcOr,D0
		BEQ.S	@useBic
		CMP		#srcBic,D0
		BNE.S	GOHOME
@useBic

; restored altered srcBits

		MOVE.L	bufStart(A6),srcBits+baseAddr(A6)
		SUB		#4,srcBits+bounds+bottom(A6)

; adjust params for center portion StretchBits

		CLR.L	maskBitsPtr(A6)				;no mask
		EOR		#2,D0						;change or to bic, bic to or
		MOVE	D0,locMode(A6)				;adjust textmode

;
;  Push params and call StretchBits to transfer buffer to screen
;
NOSHAD
		PEA 	SRCPIX(A6) 					;PUSH SRCBITS
		MOVE.L	maskBitsPtr(A6),-(SP)		;may be 0 if no mask bitmap
		PEA		PORTBITS(A3)				;TRANSFER TO SCREEN
		PEA 	TEXTRECT(A6)				;PUSH SRCRECT = TEXTRECT
		PEA		TEXTRECT(A6)				;maskRect same as source rect
		PEA 	TEXTR2(A6)					;PUSH DSTRECT = TEXTR2
		MOVE	locMode(A6),-(SP)			;PUSH TEXTMODE
		CLR.L	-(SP)						;NO PATTERN FOR NOW
		MOVE.L	CLIPRGN(A3),-(SP)			;PUSH CLIPRGN HANDLE
		MOVE.L	VISRGN(A3),-(SP)			;PUSH VISRGN HANDLE
		PEA 	FAKEPTR(A6) 				;PUSH FAKE HANDLE
		MOVE.B	colorSource(A6),-(SP)		;pass multicolor flag true if source is multibit
		_StretchBits 						;TRANSFER BUFFER TO SCREEN

GOHOME
		MOVE.L	saveStk(A6),SP				;throw away the buffers
		MOVE	charsRemain(A6),D0
		SUB		countCopy(A6),D0
		MOVE	D0,charsRemain(A6)			;if iterative, this will be greater than zero
		BGT		secondHalf					;so there are more characters to draw
		BSET	#hiliteBit,HiliteMode		;reset hilite override, in case colormap was skipped
		TST		stackOffset(A6)				;was the stack aligned?
		MOVEM.L (SP)+,D0-D7/A1-A4			;RESTORE REGS
		UNLK	A6
		BEQ.S	@skipAlign
		ADDQ	#2,SP
@skipAlign
		RTD		#PARAMSIZE					;Return and pop the stack		<1.6-11april89-CEL>

		ENDPROC
;
; < ABOVE COPIED VERBATIM FROM THE ROM >
;
;---------------------------------------------------------------------------------------
		ENDIF								; <6.0.5> <CEL>







;____________________________________________________________________________	dba	<3.0>
;	Menu manager patch
;
;	The following patch fixes the head of InitProcMenu. The wrong version was
;	rolled into the ROM, so we replace the head with this.

NewInitProcMenu	proc	export

ROMIMCommon				equ		$16D52			; place to rejoin ROM in InitMenus

				; the following code is copied out of the Menu Manager

				move.l	(sp)+,a0				; get the return address
				move.w	(sp)+,d1				; get the MBDF resource ID
				move.l	a0,-(sp)				; put return address back on the stack
				jsrROM	ROMIMCommon				; call InitMenus					<4.0>
				move.l	MenuList,a0				; get the menu list					<4.0>
				move.l	(a0),a0					; dereference the menu list			<4.0>
				move.w	d1,mbResID(a0)			; store MBDF ID						<4.0>
				rts								; return to InitProcMenu caller		<4.0>

				endproc

; The following patch reinstates the WaitMouseUp in MenuSelect. It was removed as part
; of the tear-off menu stuff (in an attempt to support double-clicking in the menu bar),
; but that change was probably not a good idea, even for the tear-off menu case.

NewMenuSelect	proc	export

ROMContinueMenuSelect	equ		$171A2			; place to rejoin ROM in MenuSelect
ROMDoneMenuSelect		equ		$17296			; place to rejoin ROM in MenuSelect

				; the following code is copied out of the Menu Manager

;-----------------------------------------------
; MenuSelect stack frame definitions
;-----------------------------------------------

STARTPT			EQU		8						; 1st parameter is 8, and is 4 bytes long
FUNCRESULT		EQU		12						; longword function result (menu,item)
ITEMRESULT		EQU		14						; item portion of funcResult

MENURECT		EQU		-8						; rectangle (8 bytes)
MSavePort		EQU		MENURECT-4				; saved grafPort

msLastMenu		EQU		MSavePort-2				; how many menus are on the screen
DelayTicks		EQU		msLastMenu - 4			; how long mouse in HItem
DragTicks		EQU		DelayTicks - 4			; how long mouse moving towards HMenu
menuDelaySave	EQU		DragTicks - 1			; store menuDelay from pRAM
menuDragSave	EQU		menuDelaySave - 1		; store menuDrag from pRAM
lastFuncResult	EQU		menuDragSave - 2		; funcResult last time thru MSLoop
lastItemResult	EQU		lastFuncResult - 2		; itemResult last time thru MSLoop
firstMenuID		EQU		lastItemResult - 2		; ID of REGULAR menu up
NewHMenuOffset	EQU		firstMenuID - 2			; offset into MenuList of new HMenu
tRect1			EQU		NewHMenuOffset - 8		; temp rectangle
SelectFrame		EQU		tRect1					; number of bytes to save

;-----------------------------------------------

				link	a6,#SelectFrame			; set up a stack frame
				movem.l	d2-d7/a2-a4,-(sp)		; save work registers

				clr.w	-(sp)					; push zero for this
				_HiliteMenu						; make sure no menu is hilited
				clr.l	funcResult(a6)			; assume nothing will be selected
				clr.l	MenuDisable				; clear the low-memory location MenuDisable

				clr.w	-(sp)					; push zero for this
				_WaitMouseUp					; is the mouse still down?
				tst.b	(sp)+					; examine result
				beq.s	DoneMenuSelect			; if not still down, donÕt bother
				jmpROM	ROMContinueMenuSelect	; continue in ROM
DoneMenuSelect	jmpROM	ROMDoneMenuSelect		; continue in ROM

				endproc


;____________________________________________________________________________	djw	<3.6>
;	Slot Manager pInitEntry patch
;
;	Fixes a bug when calling _InsertSRTRec, inserting a ROM sRsrc with a valid
;	refnum, pInitEntry is called.  pInitEntry calls _sFindDevBase to calc a base
;	addr to place in the DCE.  The bug is _sFindDevBase is called with a bad
;	sRsrc id.  The fix is one line to restore the spId before calling
;	_sFindDevBase.
;

pInitEntry	Proc	Export
			With	spBlock,srrBlock,SlotRsrcType

ROMpInitEntry	Equ	$00006904						; addr to continue to in ROM
ROMpInitError	Equ	$0000691c						; addr of @Error label in ROM
ROMpInitDone	Equ	$00006920						; addr of @Done label in ROM
ROMMapUnit		Equ	$00006930						; addr of MapUnit routine in ROM

			MOVEM.L	D1/A2,-(SP)						; save regs
			SUBA.W	#SRSize,SP						; alloc size to read sRsrc sType field
			MOVEA.L	SP,A2							; save A2 = ptr to buffer

;	Fill in the fields of a new SRT entry

			MOVE.B	spSlot(A0),srrSlot(A1)			; slot number
			MOVE.B	spId(A0),srrId(A1)				; sRsrc id
			MOVE.B	spExtDev(A0),srrExtDev(A1)		; external device id
			CLR.B	srrHWDev(A1)					; clear hardware device id
			MOVE.W	spRefNum(A0),srrRefNum(A1)		; driver reference number
			MOVE.W	spIOReserved(A0),srrIOReserved(A1)	; IO reserved field (good for nothin?)
			MOVE.L	spsPointer(A0),srrsRsrcPtr(A1)	; set the ptr to the RAM or ROM sRsrc
			CLR.L	srrFlags(A1)					; clear flag field
			MOVE.L	spParamData(A0),D0				; test state of enable/disable value
			BEQ.S	@ReadStuff						; zero - sRsrc is marked as enabled
			BSET.B	#srDisable,srrFlags+3(A1)		; set flag to indicate disabled

;	Read the hardware sRsrc id

@ReadStuff	MOVE.B	#sRsrcHWDevId,spId(A0)			; get hardware id (if present)
			_sReadByte								; no error if not present
			BNE.S	@Continue
			MOVE.B	spResult+3(A0),srrHWDev(A1)		; only a byte value

;	Find and read the sRsrc type field <category><type><drvrSW><drveHW>

@Continue	MOVE.B	#sRsrcType,spId(A0)				; get ptr to sRsrc type
			_sFindStruct
			BNE.S	@Error							; error - sRsrc type field is required
			MOVE.L	#SRSize,spSize(A0)				; set size to read
			MOVE.L	A2,spResult(A0)					; set buffer ptr
			_sReadStruct
			BNE.S	@Error							; error - found but can't read ?
			MOVE.L	sCategory(A2),srrCategory(A1)	; copy <cat><type>
			MOVE.L	sDrvrSw(A2),srrDrvrSw(A1)		; copy <drvrSW><drvrHW>

;	If there is a valid reference number, then find the DCE and calculate the dCtlDevBase

			MOVEQ	#0,D0							; set a good return
			MOVE.W	spRefNum(A0),D1					; get ref num
			BEQ.S	@Done							; no ref num - done
			jsrROM	ROMMapUnit						; return reg A2 = ptr to DCE
			BNE.S	@Error							; some error with ref num or DCE

;	Read a 24 or 32 bit base address from the sResource

			move.b	srrId(a1),spId(a0)				; set spId of sRsrc to get base addr (the fix)
			jmpROM	ROMpInitEntry					; continue in ROM

;	Jump points back into ROM

@Error		jmpROM	ROMpInitError					; jump to @Error label
@Done		jmpROM	ROMpInitDone					; jump to @Done label

			EndProc


;____________________________________________________________________________	DAF	<4.1>
; This patch really didn't get in until <5.1>
;
;  	SaveEntries Patch
;
; OK, I blew it on a patch roll-in from ROM78Fix into the Aurora ROM.  In SaveEntries
;	the a test was added for non-CLUT devices, but when I rolled it inline, I jumped
;	back to the wrong place.  This patch head patches the routine just like ROM78Fix
;	so that it never hits the ROM routine if there is an error.
;

mySaveEntries	PROC	EXPORT

ROMSaveEntries		EQU		$3C920

			MOVE.L		([theGDevice]),A0	; get a pointer to the current device
			CMP.W		#CLUTType,GDType(A0)	; is it a clut device?
			BNE.S		SEDevErr			; nope, so report an error
			JMPRom		ROMSaveEntries		; OK, so execute normal saveEntries
SEDevErr
			MOVE.W		#cDevErr,QDErr		; post error code
			RTD			#12					; and return

;____________________________________________________________________________
; SetEntries, dvb < 124 > 1991
; Mark bit 3 of QDSpare0 when the color environment changes, so pmgrexit
; only cleans up if bit was set for that layer.

mySetEntries	PROC	EXPORT
ROMSetEntries	EQU		$3C6C0

; Mark QDSpare that the color environment has changed, but only if
; QD exists
		TST.B		QDExist				; is QD around?
		BNE.S		@noQDE				; no, skip this next
		MOVE.L		(A5),A0
		BSET		#3,QDSpare0(A0)		; Tell PMgrExit to do color cleaning
@noQDE
		JMPRom		ROMSetEntries		; and on with our regularly scheduled program. < 124 >

;____________________________________________________________________________
;	Script Manager patch to Pack6, fixes problem with pointer to unlocked
;	handle in Transliterate.									<4.3><08/21/89 pke>
;	Also fixes another problem in LwrString, CharType, Transliterate, FindWord:
;	These routines need to have the Script Manager IntlForce flag cleared
;	before calling IUGetIntl (this flag must be saved beforehand and restored
;	afterward). This ensures that the itl2 tables used by these routines apply
;	to the current script.										<4.5><08/21/89 pke>
;	Only do the second fix for Scripts604 OR (SysVers > $604)	<4.7><08/21/89 pke>
;
;	This patch is not installed for A/UX, since A/UX doesn't support the Script
;	Manager.
;

	IF doScriptMgrPack6Fix AND (NOT installScriptMgrPtch39) THEN	; <42><50>

ptchPack6	PROC	Export

fromROMLwrString	EQU		$0C0B2
fromROMCharType		EQU		$1D986
fromROMFindWord		EQU		$1DBE0

fromROMTranslit		EQU		$1DB34
toROMTranslit		EQU		$1DB3A
ROMPack6			EQU		$262B2

tlRecord	record	{a6link},decr
result		ds.w	1						; function result.
tlArgs		equ	*-8							; size of arguments.
srcHandle	ds.l	1						; srcHandle.
dstHandle	ds.l	1						; dstHandle.
target		ds.w	1						; target.
srcMask		ds.l	1						; srcMask.
selector	ds.l	1						; selector
return		ds.l	1						; return address.
a6link		ds.l	1						; old a6 register.
tlLocals	equ	*							; size of local variables.
			endr

			cmp.w	#iuGetIntl,4(sp)		; is it an IUGetIntl call?
			bne.s	@NoPatch				;   skip if not (optimization)
			CmpRA	fromROMLwrString,(sp)
			beq.s	@PatchOther
			CmpRA	fromROMCharType,(sp)
			beq.s	@PatchOther
			CmpRA	fromROMFindWord,(sp)
			beq.s	@PatchOther
			CmpRA	fromROMTranslit,(sp)
			beq.s	@PatchTrans				; Translit is special - 2 bugs
@NoPatch
			JmpROM	ROMPack6				; nothing interesting to do

@PatchTrans
; We get here if we came from the _IUGetIntl in Transliterate (IUGetIntl is a
; macro that pushes a selector and then does a _Pack6 trap). A few instructions
; before the _IUgetIntl, we had handles in a1 and a2 which were then dereferenced
; into the same registers. We want to postpone this dereferencing till after
; _Pack6. Fortunately, the original handles are still available in Transliterate's
; a6 frame, so we can get them after the Pack6 call, dereference them again, and
; stuff them where they belong. We also need to clear the IntlForce flag around
; Pack6 if it is set.

			WITH	tlRecord, SMgrRecord
			addq	#4,sp					; kill old return address

			GetSMgrCore a0					; get pointer to SMgrRecord
			tst.b	smgrIntlForce(a0)		; check IntlForce flag
			bne.s	@fixFlag				; if set, go fix it

			JsrROM	ROMPack6
			bra.s	@doDeref
@fixFlag
			clr.b	smgrIntlForce(a0)		; now force it to 0
			JsrROM	ROMPack6
			GetSMgrCore a0					; get pointer to SMgrRecord
			st		smgrIntlForce(a0)		; restore IntlForce
@doDeref
; The next two lines are what follow the _IUGetIntl in the ROM Transliterate
			move.l	(sp)+,a4				;
			movem.l	(sp)+,a1/d1-d2			;
; Now we expect to have pointers in a1 and a2, so set them up again (this is
; the fix) and jump back into ROM:
			move.l	srcHandle(a6),a1		; get source handle.
			move.l	dstHandle(a6),a2		; get destination handle.
			move.l	(a1),a1					; get source pointer.
			move.l	(a2),a2					; get destination pointer.
			JmpROM	toROMTranslit
			ENDWITH

@PatchOther
; We get here if we came from the _IUGetIntl in LwrString, CharType, or
; FindWord. If IntlForce is currently zero, we just JMP to the old Pack6.
; Otherwise, we copy part of the stack in order to save the return address,
; then JSR to Pack6, then fix up the stack.

			WITH	SMgrRecord
			GetSMgrCore a0					; get pointer to SMgrRecord
			tst.b	smgrIntlForce(a0)		; check IntlForce flag
			beq.s	@NoPatch				; if already 0, nothing to do
			clr.b	smgrIntlForce(a0)		; now force it to 0

; At this point the stack has 12 bytes that are significant for Pack6:
;	8(sp).L = space for returned handle
;	6(sp).W = argument, specifies which itlx
;	4(sp).W = Pack6 routine selector = #iuGetIntl
;	0(sp).L	= return address
; We now copy the selector, argument, and return space below the return address.
; This sets up the stack correctly for the JsrROM (which will add a new return
; address) while preserving our original return address.

			clr.l	-(sp)					; new place for returned handle
			move.l	8(sp),-(sp)				; copy selector and arguments

; Now this piece of stack has changed as follows:
;	16(sp).L = old space for returned handle
;	14(sp).W = old copy of argument (unnecessary)
;	12(sp).W = old copy of selector (unnecessary)
;	8(sp).L	= old return address
;	4(sp).L = new space for returned handle
;	2(sp).W = new copy of argument, specifies which itlx
;	0(sp).W = new copy of Pack6 routine selector = #iuGetIntl
; We are now set up to call Pack6:

			JsrROM	ROMPack6

; The last stack picture:
;	12(sp).L = old space for returned handle
;	10(sp).W = nothing useful
;	8(sp).W = nothing useful
;	4(sp).L	= old return address
;	0(sp).L = returned handle
; We need to copy the returned handle to where it should go, clean up the stack,
; set IntlForce, and return.

			move.l	(sp)+,8(sp)				; copy returned handle to its place
			move.l	(sp)+,a1				; get return address
			addq	#4,sp					; finish cleaning up stack
			GetSMgrCore a0					; get pointer to SMgrRecord
			st		smgrIntlForce(a0)		; restore IntlForce

; Now we just have the returned handle on the stack (see, no picture).

			jmp		(a1)					; go home (I'm about to).

			ENDWITH
			ENDPROC

		ENDIF								; <42>

;============================================================================	pke	<4.6>
; Patch UprString,RelString,CmpString to reintroduce the bug in which "`" is
; converted to uppercase as "a". This is necessary to prevent HFS problems,
; since existing disk catalogs use the old, buggy sorting. All we need to do
; is patch them up to the point where they access the UpperTab table, which
; does not have the necessary bug in ROM.
;
; A/UX uses the ROM versions of these routines, so we can install them for
; A/UX.
;
			PROC
			EXPORT	NewUprString,NewCmpString,NewRelString

ROMUprStringAfterEntString		equ		$0C10C
ROMRelStringAfterEntString		equ		$0C136
ROMEntStringAfterLEAUpperTab	equ		$0C196

;______________________________________________________________________
;
; Routine:		  UprString
; Arguments:		D0.W (input)  --  string length
;					A0.L (input)  --  pointer to string to canonize
;					Opcode bit 10 --  0 - map to upper case; 1 - case sensitive
;					Opcode bit	9 --  0 - diacritical sensitive; 1 - strip diacrits
;					All registers are preserved.
; Function: 	  UprString is a utility routine which, according to
;				  a pair of input booleans, strips diacritical marks
;				  and/or maps all characters to upper case.
;
;______________________________________________________________________

NewUprString
				BSR				EntString				; changed
				jmpRom			ROMUprStringAfterEntString

;______________________________________________________________________
;
; Routine:		  CmpString, RelString
; Arguments:		D0.L (input)  --  high-order word = string 0 length
;									   low-order word = string 1 length
;					A0.L (input)  --  pointer to string 0
;					A1.L (input)  --  pointer to string 1
;					D0.W (output) --
;						CmpString --  result code = 0, 1 for equal, unequal.
;						RelString --  result code = -1, 0, 1 according as string 0
;										is <, =, > than string 1, respectively.
;					Opcode bit 10 --  0 - map to upper case; 1 - case sensitive
;					Opcode bit	9 --  0 - diacritical sensitive; 1 - strip diacrits
;					Pascal register conventions are observed.
;
; Calling Sequence for Pascal strings:
;					LEA 	  str0,A0
;					LEA 	  str1,A1
;					MOVEQ	  #0,D0
;					MOVE.B	  (A0)+,D0
;					SWAP	  D0
;					MOVE.B	  (A1)+,D0
;					_CmpString
;
; Function: 	  CmpString is a utility routine to compare two strings for
;				  equality.  The strings are pointed to by A0 and A1
;				  on entry; the result is returned in D0.
;				  Two booleans determine the flavor of the compare:
;					Marks --
;						if set, all diacritical marks are ignored.
;					Case --
;						if set, all characters are mapped to upper case.
;______________________________________________________________________

;
; To expedite CmpString, test for length differences first.  If they're the same,
; use the absolute value of RelString's return.
;

NewCmpString
				MOVE.W			D0,D2					; str 1 length
				SWAP			D0						; str 0 length
				CMP.W			D0,D2
				BNE.S			CSQuickNE
				SWAP			D0						; realign for fresh start in RelString
				BSR.S			NewRelString			; count on CCR from last D0 store <4.6>
				BPL.S			@1
				NEG.L			D0						; -1 ---> 1
@1
				RTS
CSQuickNE
				MOVEQ			#1,D0					; must differ since lengths do
				RTS


;
; Register usage:
;		D0 = shorter string length = loop index
;		D1 = trap opcode, with embedded booleans
;		D2 = string 0 input buffer
;		D3 = string 1 input buffer
;		D4 = -1, 0, 1 according to string lengths
;
;		A0 = string 0 pointer
;		A1 = string 1 pointer
;
; Output:
;		D0 = -1, 0, 1
;		CCR reflects D0
;		D1-D2/A0-A1 trash
;

NewRelString
				BSR.S			EntString
				jmpROM			ROMRelStringAfterEntString		; <4.6>

;______________________________________________________________________
;
; Utility EntString saves regs D3-D4/A2-A3, sets up opword for quick
; test in Canonizer, and primes A2 with UpperTab and A3 with CmpTab.
; D2 is cleared for use by Canonizer.
;
; Utility ExtString cleans up and returns, leaving CCR.  It is jumped to...
;______________________________________________________________________
EntString
				MOVE.L			(SP)+,D2						; return address
				MOVEM.L 		D2-D4/A2-A3,-(SP)				; return on top
				LEA 			UpperTab,A2
				jmpROM			ROMEntStringAfterLEAUpperTab	; <4.6>



;
; Handy macro allows for ease in building big, regular tables.
; ASSEMBLER WON'T ALLOW EIGHTH ARGUMENT ON SAME LINE!!!!!!!!!!!!!!
;
		MACRO
		crow
		DC.B	(&Syslst[1]),( &Syslst[1]+1),( &Syslst[1]+2),( &Syslst[1]+3),( &Syslst[1]+4),( &Syslst[1]+5),( &Syslst[1]+6)
		DC.B	(&Syslst[1]+7)
		ENDM

		MACRO
		dcrow
		crow	&Syslst[1]
		crow	&Syslst[1]+8
		ENDM


;_________________________________________________________________________________________________________
;
; <4.6> <08/21/89 dba/pke>
;
; Note the $61 at the beginning of the lower-case letters. In Feb. 89 for the ROMs, Peter E. fixed the
; upper casing of the "`" (backquote) character. Previously, it would turn into "a" (ASCII $61).
; Unfortunately, to our dismay, all of our old HFS disks require that this bug be perpetuated forever,
; at least for the ordering of HFS names in the B-Tree, which use RelString. We also realized that
; others may be using the string traps to order internal data structure. Because of all of this, we
; are reintroducing the bug. The uppercase version of backquote is hereby declared to be lower-case a.
;

UpperTab
; Special chars, punctuation, digits, upper-case letters.
		dcrow	$00
		dcrow	$10
		dcrow	$20
		dcrow	$30
		dcrow	$40
		dcrow	$50

; Lower-case letters and some symbols.
		DC.B	$61,( 'A'),( 'B'),( 'C'),( 'D'),( 'E'),( 'F'),( 'G')	; fixed ` <02/29/89 pke> unfixed <4.6>
		crow	$48
		crow	$50
		DC.B	('X'),( 'Y'),( 'Z'), $7B, $7C, $7D, $7E, $7F

; Accented characters.
		crow	$80
		DC.B	$CB, $89, $80, $CC, $81, $82, $83, $8F
		DC.B	$90, $91, $92, $93, $94, $95, $84, $97
		DC.B	$98, $99, $85, $CD, $9C, $9D, $9E, $86

; Symbols and upper-case AE and O-slash
		dcrow	$A0

; Symbols and ae, o-slash
		crow	$B0
		DC.B	$B8, $B9, $BA, $BB, $BC, $BD, $AE, $AF

; Symbols, upper A-acute, A-tilde, O-tilde, OE, and oe
		crow	$C0
		DC.B	$C8, $C9, $CA, $CB, $CC, $CD, $CE, $CE

; Symbols and undefineds.  y-umlaut cannot map up.
		dcrow	$D0
		dcrow	$E0
		dcrow	$F0

; End of UpperTab
;_________________________________________________________________________________________________________

		ENDPROC


		IF doScriptMgrStr2DatFix AND (NOT installScriptMgrPtch39) THEN		; <7.8><42><50>
;============================================================================	pke	<7.8>
; Patch Script Manager routines InitDateCache and String2Date for bug fixes
; needed by HyperCard.
; ----------------------------------------------------------------------------

				proc
				export	NewInitDateCache,NewString2Date

ROMValidLong			equ		$1EE60		; <7.8>
ROMBlock2String			equ		$1EEA0		; <7.8>
ROMMatchString			equ		$1EF20		; <7.8>
; in InitDateCache ($1EF80):
ROMAfter2ndJSRCopyArray	equ		$1F0E8		; <7.8>
ROMExit					equ		$1F160		; <7.8>
; in/after String2Date ($1F190):
ROMAfterDBNE			equ		$1F2D6		; <7.8>
ROMDTComExit			equ		$1F426		; <7.8>
ROMFixValue				equ		$1F46E		; <7.8>
ROMDateTimeEntry		equ		$1F47E		; <7.8>

WhiteSpace		EQU	1	; token number for white space
AlphaToken		EQU	4	; token number for string
NumericToken	EQU	5	; token number for number
AltNumericToken equ	$B	; alternate token type for numbers
NonAlphNumToken EQU	16	; token numbers starting here correspond to non-alpha numeric tokens
MaxTokens		EQU	32	; number of tokens for which there is space

omdy			EQU	0	; date order constants
odmy			EQU	1
oymd			EQU	2

Str15			EQU		16					; length of string[15]
DayMonthLen		equ		15					; length of days and months
NumDays 		EQU		7					; length of various arrays
NumMonths		EQU		12
DayList 		EQU		NumDays*Str15
MonthList		EQU		NumMonths*Str15
NumStrBytes		EQU		300

Cache			RECORD	0
version			ds.w	1
CurrentDate		DS		LongDateRec
BaseDate		DS		LongDateRec
theDays 		DS.B	DayList				; <7.8>
theMonths		DS.B	MonthList			; <7.8>
theEveStr		DS.B	Str15
theMornStr		DS.B	Str15
the24hrStr		DS.B	Str15
theTimeSep		DS.W	1
theDateSep		DS.W	1
theDateOrder	DS.b	1
longDateOrder	ds.b	1
theAbbrLen		DS.W	1
TBlock			DS		tokenBlock
CacheSize		equ		*
theTimeStrings	equ		theEveStr
				ENDR

; ----------------------------------------------------------------------------
; function InitDateCache(theCache: CachePtr): OSErr;
;
; InitDateCache will initialize the items in the DateCacheRecord pointed to by theCache^
; and set the initialized item to true
;
; The bug fixes are in the CopyArray subroutine <7.8>.
; ----------------------------------------------------------------------------

idcSaveRegs		REG	A2-A4/D3/d4

InitCacheRec	RECORD	{A6link},decr
Result			DS.W	1						; offset to function result (integer)
paramBegin		EQU		*
theCache		DS.L	1						; pointer to the cache record
selector		ds.l	1						; added for resource
paramEnd		EQU		*
return			DS.L	1
A6link			DS.L	1
theTokens		DS.B	2*TokenRec.tokenRecSize
Intl0			DS.L	1						; handle, not pointer
Intl1			DS.L	1						; handle, not pointer
altSpace		ds.w	1						; use top byte
aLongDate		ds		LongDateTime			;
localsize		EQU		*
				ENDR

				WITH	InitCacheRec,LongDateField

NewInitDateCache
			LINK	A6,#localsize			; Establish local frame and variables
			MOVEM.L	idcSaveRegs,-(SP)		; saved used registers
			CLR.W	Result(A6)				; clear function result

			MOVE.L	theCache(A6),A2			; cache addr

			move.b	#' ',altSpace(a6)		; assume no alt space

			sub.l	#6,sp					; reserve returns
			_IntlScript						; get the script
			move.w	#smScriptRight,-(sp)	; get flag
			_GetScript						; get value
			tst.l	(sp)+					; got it?
			beq.s	@NoAltSpace 			; no
			move.b	#' '+$80,altSpace(a6)	; use alt space.
@NoAltSpace

			WITH	Cache

			lea		aLongDate(a6),a0		; @temp
			clr.l	(a0)+					; no high
			move.l	Time,(a0)+				; low = current
			pea		aLongDate(a6)			; extended
			pea		CurrentDate(A2)			; get current date from system global time and convert to date
			_LongSecs2Date

			lea		aLongDate(a6),a0		; @temp
			clr.l	(a0)+					; no high
			clr.l	(a0)+					; low = current
			pea		aLongDate(a6)			; extended
			pea		BaseDate(A2)			; get base date and convert to date
			_LongSecs2Date

; IUGetIntl(0): Handle

			CLR.L	-(SP)
			CLR.W	-(SP)
			_IUGetIntl
			MOVE.L	(SP)+,Intl0(A6)

			move.w	ResErr,d0				; did intl0 load in all right
			BEQ.S	GotIntl0Ok				; if so, go on

			MOVE.W	d0,Result(A6)
			BRA		Exit

GotIntl0Ok
; IUGetIntl(1): Handle

			CLR.L	-(SP)
			MOVE.W	#1,-(SP)
			_IUGetIntl
			MOVE.L	(SP)+,Intl1(A6)

			TST.W	ResErr					; did intl0 load in all right
			BEQ.S	GetSeparators			; if so, go on

			MOVE.W	ResErr,Result(A6)
			BRA		Exit

GetSeparators
			MOVE.L	Intl0(A6),A3
; Lock itl0 across Block2String calls (which can now move memory)
			move.l	a3,a0
			_MoveHHi
			move.l	a3,a0
			_HLock

			MOVE.L	(A3),A3					; now a3 is pointer to itl0

; Block2String(eveStr,theEveStr,4,true)

			LEA		eveStr(A3),A0			; get international 0 record for evening string
			LEA		theEveStr(A2),A1
			MOVEQ	#4,D0
			MOVE.B	#1,D1
			move.b	altSpace(a6),d2			; pass alt string
			JsrROM	ROMBlock2String			; convert packed array of char into string	<7.8>
											;	with no leading spaces
; Block2String(mornStr,theMornStr,4,true)

			LEA		mornStr(A3),A0			; get international 0 record for morning string
			LEA		theMornStr(A2),A1
			MOVEQ	#4,D0
			MOVE.B	#1,D1
			move.b	altSpace(a6),d2			; pass alt string
			JsrROM	ROMBlock2String			; convert packed array of char into string	<7.8>
											;	with no leading spaces
; Block2String(time1Stuff,the24hrStr,1,true)

			LEA		timeSuff(A3),A0			; get international 0 record for 24 hour string
			LEA		the24hrStr(A2),A1
			MOVEQ	#1,D0
			MOVE.B	#1,D1
			move.b	altSpace(a6),d2			; pass alt string
			JsrROM	ROMBlock2String			; convert packed array of char into string	<7.8>
											;	with no leading spaces

			MOVE.B	timeSep(A3),theTimeSep(A2)	; get time separator from intl 0
			MOVE.B	dateOrder(A3),theDateOrder(A2)
			MOVE.B	dateSep(A3),(theTimeSep + 1)(A2)

; Now unlock itl0
			move.l	Intl0(A6),a0
			_HUnlock

			MOVE.L	Intl1(A6),A3

; Lock itl1 across Copy Array calls; it calls Block2String, which can now move memory
			move.l	a3,a0
			_MoveHHi
			move.l	a3,a0
			_HLock

			MOVE.L	(A3),A3					; now a3 is pointer to itl1

; Get the long date order and convert
; false => dmy, true => mdy; otherwise fancy stuff

			move.l	#omdy,d1				; assume false
			clr.w	d0						; wordize
			move.b	lngDateFmt(a3),d0		; get long format
			beq.s	@GotLong				; done
			move.l	#odmy,d1				; assume true
			cmp.b	#$FF,d0					; true?
			beq.s	@GotLong				; yes, got it

; if we are looking at the long date, only the day and year are important,
; since the dayOfWeek and month are both strings. Walk through the format until
; we find either one or the other

@LongFmtLoop
			move.b	d0,d2					; get bottom half-nybble
			and.b	#3,d2					; got it
			cmp.b	#longDay,d2 			; day?
			beq.s	@GotLong				; yes, return #odmy
			cmp.b	#longYear,d2			; year?
			beq.s	@LongYearFirst			; go for it
			lsr.b	#2,d0					; strip bottom
			bne.s	@LongFmtLoop			; repeat until done
@LongYearFirst
			move.l	#oymd,d1				; year first (also if none found)

@GotLong
			move.b	d1,longDateOrder(a2)	; set it

; continue
			MOVE.B	abbrLen(A3),theAbbrLen(A2)	; get abbrLen

; changed order for more convenience in the later routine
			lea		months(a3),a4			; source of days
			LEA		theMonths(A2),a1		; destination names of the day and months
			MOVE.L	#(numMonths - 1),D3   	; load day and months from intl 1 rec into space
			jsr		CopyArray				; copy days

			lea		days(a3),a4				; source of days
			LEA		theDays(A2),a1			; destination names of the day and months
			MOVE.L	#(numDays - 1),D3   	; load day and months from intl 1 rec into space
			jsr		CopyArray				; copy days

; Now continue with ROM code
			JmpROM	ROMAfter2ndJSRCopyArray	;									<7.8>
Exit
			JmpROM	ROMExit					;									<7.8>

; little subroutine for code savings
; a4 is source pointer
; a1 is dest pointer
; d3 is byte length

CopyArray
			move.l	a1,d4					; dest ptr

@LOOP		MOVE.L	A4,A0					; move string from intl 1 rec		<7.8>
			MOVE.L	d4,A1					; into local frame
			moveq	#0,d0					; Block2String wants a long!		<7.8>
			MOVE.B	(A0)+,D0				; with length from first byte of string
			MOVEQ	#1,D1					; with no local frame
			move.b	altSpace(a6),d2			; pass alt string
			JsrROM	ROMBlock2String			; search							<7.8>
			ADD.L	#Str15,d4				; get next string to transfer
			ADD.w	#Str15,A4				; into next string in local frame	<7.8>
			DBRA	D3,@LOOP
			rts

			ENDWITH     ; Cache
			ENDWITH

; ----------------------------------------------------------------------------
;function String2Date(	textPtr:	 	Ptr;
;						textLen:		longint;
;						theCache:		DateCachePtr;
;						var lengthUsed: longint;
;						var DateTime:	LongDateRec): Integer;
;
; String2Date will look for a date in the text given it according to the international
; resource format.  Using the Tokenizer routine it will look for a dayofWeek (which will
; be a string), a month (either a string or a number) and a day and year (both numbers).
; If the month is a number, order is decided by the ShortDate format in INTL 0; otherwise
; String2Date uses a table.  Note if only two numbers are found they are assumed to be day
; and month.  If one number is found it is assumed to be a date.  Missing fields are
; filled in by the current date and time
;
; Register Usage
;
;	A2  - Work register		D3	- loop control register
;	A3  - Work register		D4	- MonthFound
;	A4  - Cache Addr		D5	- ResultNum
;							D6	- AbbrLen
;							D7	- NumDelimsFound
;
; The bug fixes are: É <7.8>
; ----------------------------------------------------------------------------

s2dSaveRegs		REG	D3-D7/A2-a4 		; removed a5

DateFrame 		RECORD	{A6link},decr
Result			DS.W	1				; offset to function result (integer)
paramBegin		EQU		*
textPtr 		DS.L	1				; offset to Date2Time's paramters
textLen 		DS.L	1
theCache		DS.L	1				; @DateCacheRecord
RestofText		DS.L	1				; @Longint
DateTime		DS.L	1				; @LongDateRec
selector		ds.l	1				; added for resource
paramEnd		EQU		*
return			DS.L	1
A6link			DS.L	1
theTokens		DS.B	MaxTokens*TokenRec.tokenRecSize	; storage for tokens found by tokenizer
theDate 		DS		LongDateRec 	; date time rec
results 		DS.W	3				; three temporary results
myDateOrder		DS.W	1
DayFound		DS.W	1
lastItemSep		DS.W	1
lastToken		DS.W	1
lastTokenAddr	DS.L	1
lastExToken		DS.W	1
dummyLongDate	ds		LongDateTime
stringStorage	DS.B	NumStrBytes
localsize		EQU		*
				ENDR

				WITH	DateFrame
				With	Cache,LongDateField

NewString2Date
			LINK	A6,#localsize		; Establish local frame and variables
			MOVEM.L	s2dSaveRegs,-(SP)		; saved used registers
			JsrROM	ROMDateTimeEntry	; initialize & call _IntlTokenize

; Note that DateTimeEntry also does the following:
; 1. moves theCache(a6) into a4
; 2. moves TheTokens(a6) into a3
; 3. sets result(a6)
; 4. clears D7,D6; sets D5.L = -1
; 5. after IntlTokenize, sets D3= number of tokens - 1

			tst.w	result(a6)			; entry failed?
			bne		DTComExit			; bail if so

; specific stuff

			MOVEQ	#-1,D4				; initialize MonthFound to -1
			CLR.W	DayFound(A6)
			LEA		CurrentDate(A4),A1	; source
			LEA		theDate(A6),A0		;
			MOVE.L	(A1)+,(A0)+			; era, year
			MOVE.L	(A1)+,(A0)+			; month, day
			MOVE.L	(A1)+,(A0)+			; hour, minute
			move.w	(a1)+,(a0)+			; second
			CLR.W	(A0)+				; clear out dayOfWeek.  Will either be set by user or be set
										;   in the course of the validity check of the date
			MOVE.B	theAbbrLen(A4),D6

			WITH	TokenRec

@TokenLoop
			MOVE.W	theToken(A3),D1			; get token code from TokenRec record at (A3)
			CMP.W	#NonAlphNumToken,D1 	; is it a separator
			BGE.S	@FoundSeparator
			SUB.W	#WhiteSpace,D1			; was it a white space?
			BEQ		@TokenLoopEnd			; ignore
			SUBQ.W	#(AlphaToken - WhiteSpace),D1	; is it an alpha token?
			beq.s	@FoundAlpha
			SUBQ.W	#(NumericToken - AlphaToken),D1	; is it a number token?
			BEQ.S	@NumberToken
			SUBQ.W	#(AltNumericToken - NumericToken),D1	; is it a number token?
			BEQ.S	@NumberToken 			;
			BRA		@TokenLoopEnd			; ignore any other characters

@FoundSeparator
			TST.B	D7						; possible separator.  Has a separator already been found
			BEQ.S	@OneDelimFound			; no, so no error yet
			OR.W	#TooManySeps,Result(A6)	; yes, so now we have too many separators

@OneDelimFound
			ADDQ.B	#1,D7					; record separator found
			TST.w	D5						; is this after the first number loaded? (.w) <1/5/88med>
			BMI		@TokenLoopEnd			; if we have not reached a number yet go on
			BNE.S	@CheckDateSep			; if we loaded in a number then check consistency

			MOVE.W	D1,lastItemSep(A6)		; otherwise update lastItemSep with just found separator
			BRA		@TokenLoopEnd

@CheckDateSep
			CMP.W	lastItemSep(A6),D1		; are they consistent
			BEQ		@TokenLoopEnd			; if yes, than go on

			OR.W	#SepNotIntlSep+sepNotConsistent,Result(A6)	; record warning
			BRA		@TokenLoopEnd

@NumberToken
; check for numbers separated only by white space
			tst.w	d7						; got a separator?
			bne.s	@1						; yes
			tst.w	d5						; first number?
			blt.s	@1						; yes, skip
			bne.s	@0						; have 1 number
			move.w	#WhiteSpace,lastItemSep(A6)     ; set separator
			bra.s	@1						; continue
@0
			cmp.w	#WhiteSpace,lastItemSep(a6)     ; same?
			beq.s	@1						; yes, continue
			or.w	#SepNotIntlSep+sepNotConsistent,Result(A6)	; record warning
@1
; end of white space check

			CLR.L	D7						; clear out past separators
			CMP.W	#2,D5					; make sure that results array is not full
			BGE		@ExtrnsToken 			; if full, record warning and search		<7.8>
											;	for final string (remove .s)

;	ValidLong(position,textLength): longint

			MOVE.L	stringPosition(A3),A0
			JsrROM	ROMValidLong			; get number in text at TokenRec.position	<7.8>
			BMI		DTComExit

			JsrROM	ROMFixValue				;											<7.8>
			bra		@TokenRecognized		; get next token (remove .s)				<7.8>

@FoundAlpha
			CLR.L	D7						; clear out past separators

; UprString(newTextPtr,AbbrLen)				; and make it uppercase for case insensitive search

			MOVE.L	stringPosition(A3),A2
			ADDQ.L	#1,A2
			MOVE.L	A2,A0
			MOVE.L	length(A3),D0			; use real length

			_UpperText						; _LwrString with uppercase function	<39><45>

			TST.W	D4
			BPL.S	@SearchForDay			;										<7.8>

; MatchString(newTextPtr,AbbrLen,@months,15,12): integer

			CLR.W	-(SP)					; attempt to find a day/month string which matches alpha token
			MOVE.L	A2,-(SP)
			MOVE.W	length+2(a3),-(SP)		; push length as integer
			MOVE.W	D6,-(SP)				; push minlen as integer
			PEA		theDays(A4)				;										<7.8>
			MOVE.W	#DayMonthLen,-(SP)
			MOVE.W	#NumMonths+NumDays,-(SP)	; check for both at once
			JsrROM	ROMMatchString			;										<7.8>
			MOVE.W	(SP)+,D2				; save in D2
			BLE.S	@ExtrnsToken			; checking both

; decide between days and months

			sub.w	#NumDays,d2				; months?
			ble.s	@CheckForDay			; no, do days

; got a month
			CMP.W	#2,D5					; is result array already full?
			BGE.S	@ExtrnsToken 			; if so, then its not a needed token

			ADDQ.W	#1,D5					; is in range, result is not full and string
			MOVE.W	D5,D1					; did not match as a day
			ADD.W	D1,D1					; double index for integer array
			LEA		results(A6),A1			; ResultNum:= ResultNum + 1
			MOVE.W	D2,(A1,D1.W)			; results[ResultNum]:= match result
			MOVE.W	D5,D4					; MonthFound:= resultNum
			BRA.S	@TokenRecognized

; if day not found yet, we need to see if current string matches a day				<7.8>
@SearchForDay
			TST.B	DayFound(a6)			; have we found one yet?
			BNE.S	@ExtrnsToken 			; day already found, record warning

			CLR.W	-(SP)					; attempt to find a day string which matches alpha token
			MOVE.L	A2,-(SP)
			MOVE.W	length+2(a3),-(SP)		; push length as integer
			MOVE.W	D6,-(SP)				; push minlen as integer
			PEA		theDays(A4)
			MOVE.W	#DayMonthLen,-(SP)
			MOVE.W	#NumDays,-(SP)			; just check days this time
			JsrROM	ROMMatchString			;										<7.8>
			MOVE.W	(SP)+,D2				; save in D2
			BLE.S	@ExtrnsToken			; checking both

			BRA.S	@HaveDay

@CheckForDay
			TST.B	DayFound(a6)			; off of a6!
			BNE.S	@ExtrnsToken 			; day already found, record warning

			add.w	#NumDays,d2				; restore days							<7.8>
@HaveDay									;										<7.8>
			ST		DayFound(A6)			; record that day was found				<7.8>

			MOVE.W	D2,theDate.dayOfWeek(A6) ; otherwise, load dayOfWeek into date time record

			TST.W	D5						; is dayOfWeek between two numbers (.w)
			BMI.S	@NoWarning				; if no number has been found yet, go on
			OR.W	#fieldOrderNotIntl,Result(A6)	; record warning
@NoWarning
			BRA.S	@TokenRecognized

@ExtrnsToken
			TST.W	lastExToken(A6)			; is this the first extraneous token found?
			BPL.S	@TokenLoopEnd			; no, go on

			MOVE.W	D3,lastExToken(A6)		; a string which we don't recognize has been found
			BRA.S	@TokenLoopEnd			; record warning and go on

@TokenRecognized
			MOVE.W	D3,lastToken(A6)
			MOVE.L	A3,lastTokenAddr(A6)	; save loop and token addr for later use

@TokenLoopEnd
			ADD.L	#tokenRecSize,A3 		; add size of TokenRec record to A3 to get next token
			CMP.W	#2,D5					; if the result array full (.w)
			SGE		D0
			AND.B	DayFound(A6),D0			; and dayofWeek string been found
			DBNE	D3,@TokenLoop			; then stop loop, otherwise go until all tokens are looked at

			JmpROM	ROMAfterDBNE

DTComExit
			JmpROM	ROMDTComExit

			endproc

		ENDIF

		IF doScriptMgrRstKCHRFix AND (NOT installScriptMgrPtch39) THEN	; <8.0><42><50>
;============================================================================	pke	<8.0>
; Tail patch on _GetIndADB to fix bug in Script Manager ResetKCHR routine
; called by SwapKybd: it clears ADB keyboard driver dead state as a word,
; should be a long.
; ----------------------------------------------------------------------------

			proc
			export	ptchGetIndADB

ROMAfterGetIndADB	equ		$1E048
ROMAfterClrDeadKey	equ		$1E058
ROM@1dbra			equ		$1E064


ptchGetIndADB
			CmpRA	ROMAfterGetIndADB,OSTrapReturnAddressDepth(sp)	; From ResetKCHR?
			bne.s	@0								; if not, just continue with trap
			lea		ptchResetKCHR,a1				; a1 is not a param for GetIndADB
			move.l	a1,OSTrapReturnAddressDepth(sp)	; so trap returns to patch, not ROM
@0			BackToTrap	oldGetIndADB				; now get on with the trap


; When we reach the patch below, we are in ResetKCHR just after the _GetIndADB

rkRecord	record	{a6link},decr
rkArgs		equ	*-8									; size of arguments.
pointer		ds.l	1								; new KCHR pointer.
return		ds.l	1								; return address.
a6link		ds.l	1								; old a6 register.
adb			ds		ADBDataBlock					; ADB data structure.
oldKeyboard	ds.l	1								; old keyboard pointer
rkLocals	equ	*									; size of local variables.
			endr

ptchResetKCHR
			with	rkRecord

			cmp.b	#kybdADBAddr,adb.origADBAddr(a6)	; is it a keyboard?
			bne.s	@1								; no -> skip it.
			move.l	adb.dbDataAreaAddr(a6),a0		; load data area pointer.
			clr.l	KybdDriverData.deadKey(a0)		; clear dead state - long!		<8.0>
			JmpROM	ROMAfterClrDeadKey				;								<8.0>

@1			JmpROM	ROM@1dbra						;								<8.0>

			endwith
			endproc

		ENDIF

		IF doScriptMgrLwrString2 AND (NOT installScriptMgrPtch27) THEN		; <8.5><50>
;============================================================================	pke	<8.5>
; Patch LwrString to handle 2-byte chars via Transliterate.
; ----------------------------------------------------------------------------
; routine:	LwrString
; input:	a0		textPtr
;			d0.w	length
;			d1.w	trap word; the following bits are significant in 7.0 only:
;					Opcode bits
;						10	9		Function
;						--	--		--------
;						0	0		convert to lower-case
;						0	1		strip diacritics
;						1	0		convert to upper-case
;						1	1		convert to upper-case and strip diacritics
; output:	d0.w	error
; function:	Change text pointed to by a0 according to opcode bits. Before 7.0, we
;			just assume that these bits are 0 and act accordingly.
; ----------------------------------------------------------------------------

			proc
			export	ptchLwrString

lwrTrFrame	record	{a6link},decr
return		ds.l	1					; return address
a6link		ds.l	1					; link pointer
sourcePtr	ds.l	1					; orig source ptr
sourceLen	ds.l	1					; orig source len
sourceHndl	ds.l	1					; new handle with copy of source
destHndl	ds.l	1					; new handle for transliterate result
errCode		ds.w	1					; err code to be returned in d0
lwrTrLocals	equ	*						; size of locals
			endr

; ----------------------------------------------------------------------------
; NOTE: For 2-byte scripts, we need to call Transliterate. So, the first thing to
; do is figure out what script we're in. We also test for length <= 0 (tests >32K).
; ----------------------------------------------------------------------------

ptchLwrString
			ext.l	d0						; as fast as tst.w and we need ext.l later
			ble		lwrRTS					; if bad length, quit
			movem.l	a0/d0/d1,-(sp)			; save important registers
			subq.l	#2,sp					; make room for return
			_FontScript						; find script of port
			move.w	(sp)+,d2				; pop it into d2
			movem.l	(sp)+,a0/d0/d1			; restore important registers

; ----------------------------------------------------------------------------
; Here we make use of the fact that a word redraw flag of 1 (or anything >0)
; indicates a 2-byte script.
; ----------------------------------------------------------------------------

			with	SMgrRecord,ScriptRecord
			lsl.w	#2,d2					; make script code a long offset
			move.l	IntlSpec,a1				; get SMgrRecord pointer
			move.l	smgrEntry(a1,d2.w),d2	; get ScriptRecord pointer
			beq		lwrRTS					; if nil (script not installed), do nothing
			move.l	d2,a1
			tst.b	scriptEnabled(a1)		; is script enabled?
			beq		lwrRTS					; if not, do nothing
			tst.b	scriptRedraw(a1)		; is it a 2-byte script?
			ble		not2Byte				; if not, go use normal LwrString
			endwith

; ----------------------------------------------------------------------------
; OK, we need to set up for Transliterate: set up source & dest handles
; ----------------------------------------------------------------------------

			with	lwrTrFrame
			link	a6,#lwrTrLocals			; create local storage
			move.l	a0,sourcePtr(a6)		; save source ptr
			move.l	d0,sourceLen(a6)		; save length
			_PtrToHand						; make new handle containing copy of text
			move.w	d0,errCode(a6)			; save err code
			bne.s	lwrTrUnlk				; if error in PtrToHand, quit
			move.l	a0,sourceHndl(a6)		; save new source handle
			move.l	sourceLen(a6),d0		; get length again
			_NewHandle						; make new handle with random contents
			move.w	d0,errCode(a6)			; save err code
			bne.s	lwrTrDisp1Hndl			; if error in NewHandle, quit

; ----------------------------------------------------------------------------
; Now do Transliterate and check result: dest length should equal source length
; ----------------------------------------------------------------------------

			move.l	a0,destHndl(a6)			; save new dest handle
			subq.l	#2,sp					; space for Transliterate error code
			move.l	sourceHndl(a6),-(sp)	; push source handle
			move.l	a0,-(sp)				; push dest handle (still in a0)
			move.w	#smTransLower+smTransAscii,-(sp) ; lower-case conversion, target=Roman
			move.l	#smMaskAscii,-(sp)		; convert Roman only
			_Transliterate
			move.w	(sp)+,errCode(a6)		; save error code
			bne.s	lwrTrDisp2Hndl			; if error in Transliterate, quit
			move.l	destHndl(a6),a0			; now check resultÉ
			_GetHandleSize
			move.w	d0,errCode(a6)			; save err code
			tst.l	d0						; .l, because the result is really a long
			blt.s	lwrTrDisp2Hndl			; if error in GetHandleSize, quit
			move.w	#-1,errCode(a6)			; assume len err; need a better err code!
			cmp.l	sourceLen(a6),d0		; should be same as source len
			bne.s	lwrTrDisp2Hndl			; if not, set err and bail

; ----------------------------------------------------------------------------
; Copy result (destHndl) to original text buffer (sourcePtr).
; NOTE: For large text blocks, _BlockMove might be faster than this loop.
; ----------------------------------------------------------------------------

			move.l	destHndl(a6),a0			; get dest handle andÉ
			move.l	(a0),a0					; deref it to get source ptr for this copy
			move.l	sourcePtr(a6),a1		; old source ptr is dest for this copy
			move.l	sourceLen(a6),d0		; length for copy (we know it is >= 1)
			subq.l	#1,d0					; set up for dbra
@1			move.b	(a0)+,(a1)+				; copy a byte
			dbra	d0,@1					; loop till done
			clr.w	errCode(a6)				; no errors!

; ----------------------------------------------------------------------------
; Exits - need to dispose of handles we created
; ----------------------------------------------------------------------------

lwrTrDisp2Hndl
			move.l	destHndl(a6),a0			;
			_DisposHandle					;
lwrTrDisp1Hndl
			move.l	sourceHndl(a6),a0		;
			_DisposHandle					;
lwrTrUnlk
			move.w	errCode(a6),d0			; set err code
			unlk	a6						;
			rts
			endwith

lwrRTS
			clr.w	d0
			rts

; ----------------------------------------------------------------------------
; This is not a 2-byte script, just use old LwrString.
; ----------------------------------------------------------------------------
not2Byte
			BackToTrap	oldLwrString		;
			endproc

		ENDIF

;_______________________________________________________________________
;	<7.1><8.7><41><81><123><125><126><128><135><137> Async Serial Driver Patch
;	<4><5>
;
;	Start of patch code for fix of bugs in the serial driver
;	introduced into the aurora ROM (and hence the F19 overpatch ROM) by the
;	port arbitration code, which was accidently included in those ROMS.
;
;	The patch is installed in a patch vector for the async driver.
;	Note the 'simple' come-from patching mechanism has been really hosed by the
;	addition of the pic chip code; now we have to include all that code in the
; 	patch. Something to watch for when fixing the ROM driver.
;
;	Needed to include all code which jumped TO the ExtSts interrupt handler.
;
;	Traps patched: -- The AsyncVector, which is in the middle of the OS ToolTable
;					is patched, Trap number = $A0BE
;				   -- all the PIC driver headers patched.							<41>
;
;
;	HISTORY:
;	<7.1> 10/2/89	patch ExtAIntHnd and ExtBIntHnd
;	<8.7> check SCCIOPFlag now instead of PRAM to determine which driver to load.
;		  changed sense of bypass bit to agree with new ROM definition.
;	<41> fixed <8.7> to use the patch macros. Also added in patch for the
;		  IOPSerialDriver for the prime code. As a result, had to patch ALL
;		  the IOP driver headers. yuck.
;	<81>  added VM support for the SerSetBuf control call.
;	<123> added nike printer support:
;		  patched control call 16 in bypass driver to use bit 6 for setting
;		  external/internal clocking modes.
;		  Patched both bypass and IOP code to add status call to return version.
;		  Patched InitSCC routine in bypass driver to use this RAM-based table so
;		  that clocking mode is now variable instead of hard-wired to internal only.
;			-- set clock divide to 1 instead of 16 for external clocking
;			-- clear HWHS enable since we can't clock and handshake on same line
;		  Patched bypass mode driver to set bit 3 of AsyncErr if break rcvd.
;	<125> We patch all the bypass driver headers (iop headers are already patched)
;		  so that we can put a signature word before each header that we can use
;		  to identify ourselves as the Apple async serial driver. We do this
;		  right now so that that our linked patch on Open (in Serialpatches.a) will
;		  not stomp the version number of some third party driver that sticks them-
;		  selves into our spot in the unit table. I think this idea will come in
;		  handy later as well.
;		  I think i'll use the signature word 'wong'.
;	<126>	fixed a bug in EXTSTS interrupt handler for port A. Because of the BAP
;		  stuff, AInDCE no longer has a valid ptr the .Ain driver's DCE. We solve
;		  the problem the same way we did in the port B code, by getting the DCE
;		  ptr straight from the unit table.
;	<127> Fixed a bug in the External Status interrupt handler. On
;		  port A we crashed on receiving a break if a read was pending
;		  because we weren't getting the .Ain DCE ptr properly. Now we get
;		  the DCE ptr directly from the Unit table, just like for port B.
;	<129> Fixed bug in external clock stuff that was causing us to disable
;		  internal clocking on both ports if we were trying to do external
;	  	  clocking on just one. So Nike would print but Tabasco would just
;		  sit there. The fix was to set clocking params at each time we go
;		  thru InitSCC, rather than just once during the external clocking
;		  control call. This way even tho the ports share the InitSCCTable,
;		  we set the Table properly by keying off of the value in CtlOptions
;		  variable, which they don't share.
;	<135> Status call 9 and $8000 return fixed version equate instead of
;		  what's in the DCE. Fixed SerSetBuff (control call 9) to not sign
;		  extend the buffer count.
;	<137> Fixed bug in IOP code that caused SerSetBuff to fail for zero size 
;		  buffer. Wasn't clearing upper word of count passed to UnholdMemory.
;	<4>	  patched Rx and SCx interrupt handlers to help thruput on Apollo and TIM LC
;	<5>	  patched SCx interrupt handler to fix the StyleWriter bug. On faster
;		  machines we are able to send out a byte fast enough after the TBE bit 
;		  in RR0 gets set that the byte gets written before the TBE interrupt 
;		  is generated. Instead of just not generating the interrupt, the SCC goes
;		  ahead and generates it, but changes the interrupt source code to read
;		  'no interrupt' instead of 'TBE'. This 'no interrupt' code is identical
;		  to the 'Special Condition on port B' code, which was the source of our
;		  problem. Fix is to just exit SCIntHnd if no special condition bits are
;		  set.
;		  
;_______________________________________________________________________

AsyncPatch	proc
					export SerialPatch
;
;	equates
;
PortAVars	EQU 	SerialVars			; serial chan A variables and buffer
SerialVers	EQU		5					; current version 3/91	 		<135>

;
;	Bypass driver var offsets
;

OutDCE		EQU 	0					;(4) long DCE pointer for output driver
SCCOffset	EQU 	4					;(2) word of SCC offset . . .

InBufPtr	EQU 	6					;(4) pointer to local input buffer
BufSize 	EQU 	10					;(2) size of local input buffer
BufLow		EQU 	12					;(2) low buf byte count to send XOn
BufHigh 	EQU 	14					;(2) bytes from end of buffer to send XOff

SWHS		EQU 	16					;(1) software handshake enable
HWHS		EQU 	17					;(1) hardware handshake enable
XONChar 	EQU 	18					;(1) input char which continues output (SWHS)
XOFFChar	EQU 	19					;(1) input char which stops output

Options 	EQU 	20					;(1) bit 4 = abort on parity error
										;	 bit 5 = abort on overrun
										;	 bit 6 = abort on framing error
PostOptions EQU 	21					;(1) bit 7=1 enables posting break changes
										;	 bit 5=1 enables posting handshake changes
InSWHS		EQU 	22					;(1) input XOn/XOff flow control enable
InHWHS		EQU 	23					;(1) input RTS (DTR) flow ctl enb	<14Oct85>

AsyncErr	EQU 	24					;(1) error indications (cumulative)
SoftOR		EQU 	0					;		bit 0 = soft overrun
										;		bit 4 = parity error
										;		bit 5 = overrun error
										;		bit 6 = framing error

FlowOff 	EQU 	25					;(1) $80 = input flow shut off by XOff, $40 by DTR
ReadCmd 	EQU 	26					;(1) FF = read command pending
WriteCmd	EQU 	27					;(1) FF = write command pending
CTSFlag 	EQU 	28					;(1) FF = CTS asserted
XOFFlag 	EQU 	29					;(1) FF = XOFF pending
LastWR5 	EQU 	30					;(1) WR5 value with last DTR state	<14Oct85>
DTRNegVal	EQU 	31					;(1) WR5 value used to negate DTR	<14Oct85>

SCCReset	EQU 	32					;(1) WR9 value for reset

StopBits	EQU 	33					;(1) stop bits/parity option (WR4 value)
WR1AVal 	EQU 	34					;(1) first WR1 value to write
WR3AVal 	EQU 	35					;(1) first WR3 value to write
WR5AVal 	EQU 	36					;(1) first WR5 value to write
BaudLoCnst	EQU 	37					;(2) 2 byte baud rate constant (WR12-13)
BaudHiCnst	EQU 	38
RcvrBits	EQU 	39					;(1) 1 byte receiver bits/char (WR3 value)
XmitBits	EQU 	40					;(1) 1 byte xmitter bits/char (WR5 value)
WReqPin 	EQU 	41					;(1) w/req pin state (WR1 value)
lastSetup	EQU 	42					;(2) last SCC init values . . .

BufIndex	EQU 	44					;(2) index into local buffer (insert)
BufOutdex	EQU 	46					;(2) index into local buffer (remove)
LocalBuf	EQU 	48					;(64) local buffer for input chars

LclBufSize	EQU 	64					; default input buffer size = 64 bytes
HSCount 	EQU 	112 				;(2) count of CTS pulses in VBL time (clk detect) <14Oct85>
LastTime	EQU 	114 				;(4) ticks time of last CTS pulse (clk detect)	<14Oct85>

SendXOnff	EQU 	118 				;(1) flag to xmit logic to send XOn/XOff		<14Oct85>
CharMask	EQU 	119 				;(1) $1F,$3F,$7F, or $FF mask for input chars	<14Oct85>

PEChar		EQU 	120 				;(1) char to change incoming parity errors to	<14Oct85>
AltChar 	EQU 	121 				;(1) char to change incoming PEChars to 		<14Oct85>

InSWHS1 	EQU 	122 				;(1) saved InSWHS state 						<14Oct85>
CtlOptions	EQU 	123 				;(1) bits 0-6=0 (reserved). bit 7=1 to leave	<14Oct85>
										;  DTR state unchanged at close.
SaveExInt	EQU 	124 				;(4) saved Ext int vector						<14Oct85>
SaveTxInt	EQU 	128 				;(4) saved TxD int vector						<14Oct85>
SaveRxInt	EQU 	132 				;(4) saved RxD int vector						<14Oct85>
SaveSxInt	EQU 	136 				;(4) saved Special Rx int vector				<14Oct85>
InDCE		EQU		140

VarSize		EQU		144					; output driver storage size
LclVarSize	EQU 	144 				; output driver storage size

;
;	PIC driver var offsets and misc equ
;
PICOpenFlag	EQU		0					; marks if driver is open
OpenMsgPB	EQU		22
EventMsgPB	EQU		106
OpenMsg		EQU		270
PICInBufPtr	EQU		368					; ptr to current input buffer
PICBufSize	EQU		372					; size of current input buffer
PICBufIndex	EQU		374					; index for putting bytes into input buffer
PICBufOutdex EQU	376					; index for taking bytes out of input buffer
PICLocalBuf	EQU		378					; ptr to driver's local buffer

; General Equates for message fields
Results			Equ	0		;(1) Message return code
OpCode			Equ	Results+1	;(1) Some messages slots are shared
CloseOpCode		Equ	2;	Close

;____________________________________________________________________
;
;	ROM address offsets
;
;____________________________________________________________________

; bypass driver ROM entrypoint addresses 			<125>
;port A
ROM_AInEntryOpen		EQU		$6ac2a
ROM_AInEntryClose		EQU		$6af82
ROM_AInEntryPrime		EQU		$6b2a8

ROM_AOutEntryOpen		EQU		$6acf2
ROM_AOutEntryClose		EQU		$6af0e
ROM_AOutEntryPrime		EQU		$6b1ec

ROM_AEntryControl		EQU		$6b002
ROM_AEntryStatus		EQU		$6afac

;Port B
ROM_BInEntryOpen		EQU		$6ac30
ROM_BInEntryClose		EQU		$6af82
ROM_BInEntryPrime		EQU		$6b2ae

ROM_BOutEntryOpen		EQU		$6ad22
ROM_BOutEntryClose		EQU		$6af22
ROM_BOutEntryPrime		EQU		$6b1f2

ROM_BEntryControl		EQU		$6b008
ROM_BEntryStatus		EQU		$6afb2


; Open patch equates for bypass driver

fromAOutOpen	EQU		$0006B542		; at end of drvr, in IOP stuff (ChkConfig called there)
fromBOutOpen	EQU		$0006B550
fromAInOpen		EQU		$0006B55E
fromBInOpen		EQU		$0006B56C
fromControl		EQU		$6B01a
fromClose		EQU		$6af3e
fromStatus		EQU		$6afc4
fromInitSCC		EQU		$6aeb8

backToAOutOpen	EQU		$0006AD12		; returning to finish up Open routines in ROM
backToBOutOpen	EQU		$0006AD44
PlugInDrvr		EQU		$0006B594		; plug header addr into DCE and continue
backToInOpen	EQU		$0006ac34		; finish In Open routines in ROM

ROM_PollDtain	EQU		$0006B372		; rom routines addresses we must push on the stack
ROM_SCAIntHnd	EQU		$0006B466
ROM_SCBIntHnd	EQU		$0006B45C
ROM_RAIntHnd	EQU		$0006B3B0
ROM_RBIntHnd	EQU		$0006B3A6
ROM_TAIntHnd	EQU		$0006B276
ROM_TBIntHnd	EQU		$0006B26C


ROM_AsyncAIn	EQU		$0006abca		; ROM header addresses for byass drivers
ROM_AsyncAOut	EQU		$0006ABE2
ROM_AsyncBIn	EQU		$0006abfa
ROM_AsyncBOut	EQU		$0006AC12

; Control patch equates for bypass driver

backToControl	EQU		$6b02c			; for fixing control calls
ROM_CtlGood		EQU		$6b062
ROM_CtlExit		EQU		$6b064
FinishCall9		EQU		$6b0c0
InitSCC			EQU		$6aea8

; Close patch equates for bypass driver
SyncOutput		EQU		$6af86
InitSCC1		EQU		$6aeae
backToClose		EQU		$6af64
ResetData		EQU		$6aefe
ResetLth		EQU		$10

; InitSCC patch equates for bypass driver
backToInitSCC	EQU		$6aeb8
initData		EQU		$6ae74

; Status patch equates for bypass driver
backToStatus	EQU		$6afde


; Interrupt Handler equates for the bypass driver

; External/Status interrupt handler equates 
ToContOut1		EQU		$0006B29C		; return to finish up interrupt routines in ROM
ToRdReqDone		EQU		$0006B4B6
ToCtlSet		EQU		$0006B14C

; Rx interrupt handler equates
ROM_PutInOurBuf	EQU		$6b400
ROM_toStash		EQU		$6b312
ROM_GoodFinish	EQU		$6b234

; SC interrupt handler equates
ROM_abortReq	EQU		$6b4ae

; PIC driver ROM entrypoint addresses
; (note some are here for documentation purposes only)

ROM_PICAInOpen			EQU		$0006B60A		; .AIn
ROM_PICAInPrime			EQU		$0006BA7C
ROM_PICAInControl		EQU		$0006B870
ROM_PICAInStatus		EQU		$0006B7B8
ROM_PICAInClose			EQU		$0006B7AC

ROM_PICAOutOpen			EQU		$0006B618		; .Aout
ROM_PICAOutPrime		EQU		$0006B9DC
ROM_PICAOutControl		EQU		$0006B868
ROM_PICAOutStatus		EQU		$0006B7B0
ROM_PICAOutClose		EQU		$0006B72C

ROM_PICBInOpen			EQU		$0006B60A		; .BIn
ROM_PICBInPrime			EQU		$0006BA82
ROM_PICBInControl		EQU		$0006B876
ROM_PICBInStatus		EQU		$0006B7BE
ROM_PICBInClose			EQU		$0006B7AC

ROM_PICBOutOpen			EQU		$0006B648		; .BOut
ROM_PICBOutPrime		EQU		$0006B9DC
ROM_PICBOutControl		EQU		$0006B868
ROM_PICBOutStatus		EQU		$0006B7B0
ROM_PICBoutClose		EQU		$0006B72C

; equates for PIC patches
IntoChkAConfig			EQU		$0006AC8A		; for the Open patches
IntoChkBConfig			EQU		$0006AC4E

ROM_BufferShuffle		EQU		$0006BD1E		; for the Input Prime patches


backToPICControl		EQU		$6b898			; for Control patches
backToPICKillIO			EQU		$6b884
ROM_PICCtlExit			EQU		$6b8d4

backToPICClose			EQU		$6b764			; for Close patch

StatusErrExit			EQU		$6b85a			; for Status patch
BacktoPICStatus			EQU		$6b7d8
PICStatusOkExit			EQU		$6b858

;_______________________________________;
;
; IOP Driver Headers
;
;_______________________________________;

		DC.b	'wong'						; our personal signature
PICAsyncAIn
		DC.W	$4D00						; read, control, status, lock
		DC.W	0,0 						; not an ornament
		DC.W	0							; no menu

		DC.W	PICAInOpen-PICAsyncAIn		; Initialization routine
		DC.W	PICAInPrime-PICAsyncAIn		; input Prime routine
		DC.W	PICAInControl-PICAsyncAIn	; shared Control routine
		DC.W	PICAInStatus-PICAsyncAIn	; shared Status routine
		DC.W	PICAInClose-PICAsyncAIn		; Close routine

		DC.B	4							; channel A input driver
		DC.B	'.AIn '


		DC.b	'wong'						; our personal signature
PICAsyncAOut
		DC.W	$4E00						; write, control, status, lock
		DC.W	0,0 						; not an ornament
		DC.W	0							; no menu

		DC.W	PICAOutOpen-PICAsyncAOut	; Initialization routine
		DC.W	PICAOutPrime-PICAsyncAOut 	; output Prime routine
		DC.W	PICAOutControl-PICAsyncAOut	; Control routine
		DC.W	PICAOutStatus-PICAsyncAOut	; Status routine
		DC.W	PICAOutClose-PICAsyncAOut 	; Close routine

		DC.B	5							; channel A output driver
		DC.B	'.AOut'

		DC.b	'wong'						; our personal signature
PICAsyncBIn
		DC.W	$4D00						; read, control, status, lock
		DC.W	0,0 						; not an ornament
		DC.W	0							; no menu

		DC.W	PICBInOpen-PICAsyncBIn		; Initialization routine
		DC.W	PICBInPrime-PICAsyncBIn		; input Prime routine
		DC.W	PICBInControl-PICAsyncBIn	; Control routine
		DC.W	PICBInStatus-PICAsyncBIn	; Status routine
		DC.W	PICBInClose-PICAsyncBIn		; Close routine

		DC.B	4							; channel B input driver
		DC.B	'.BIn '

		DC.b	'wong'						; our personal signature
PICAsyncBOut
		DC.W	$4E00						; write, control, status, lock
		DC.W	0,0 						; not an ornament
		DC.W	0							; no menu
		DC.W	PICBOutOpen-PICAsyncBOut	; Initialization routine
		DC.W	PICBOutPrime-PICAsyncBOut 	; output Prime routine
		DC.W	PICBOutControl-PICAsyncBOut	; Control routine
		DC.W	PICBOutStatus-PICAsyncBOut	; Status routine
		DC.W	PICBOutClose-PICAsyncBOut 	; Close routine

		DC.B	5							; channel B output driver
		DC.B	'.BOut'

;_______________________________________;
;
; IOP Driver Stubs -- routines that are
; just along for the ride, and jump back
; directly to ROM
;
;_______________________________________;

PICAInClose			jmpROM		ROM_PICAInClose			; input Close routine

;__________________________________

PICAOutPrime		jmpROM		ROM_PICAOutPrime		; output Prime routine

;__________________________________

PICBInClose			jmpROM		ROM_PICBInClose			; input Close routine

;__________________________________

PICBOutPrime		jmpROM		ROM_PICBoutPrime		; output Prime routine

;__________________________________
;
; Patched PIC Routines
;
;__________________________________

; Open Routines
; We patch out the Open routines because if we jump into ROM Open
; we'll stuff the ROM PIC driver into the DCE instead of this patched one.
; So instead we load up the value we want in the DCE ourselves, and
; then jump into the open patch for the Bypass driver below.

; Also note for the Open calls, that because of the way PICChkXXXDrvr
; is written in ROM, we must the SAME instruction exactly 4 bytes
; into our Open patch as is in ROM. Else PICChkXXXDrvr would try
; to jump back to some weird place it wasn't meant to.

PICAInOpen			jmp			@10						; need 4 bytes here to correspond to ROM driver
					jmpROM		ROM_PICAInOpen			; finish up in ROM
@10					leaROM		ROM_AsyncAIn,a2			; load up the inputs
					lea			PICAsyncAIn,a3
toAOpenPatch		leaROM		IntoChkAConfig,a0		; continue on in ChkAConfig
					moveq		#4,d1					; use hyigh 4 bits in SPConfig
					moveq		#8,d2					; and PortAUse
					bra.w		OpnFx1					; go to our byPass driver patch

PICAOutOpen			jmp			@10						; need 4 bytes here to correspond to ROM driver
					jmpROM		ROM_PICAOutOpen			; finish up in ROM
@10					leaROM		ROM_AsyncAOut,a2		; load up the inputs
					lea			PICAsyncAOut,a3
					bra.s		toAOpenPatch

PICBInOpen			jmp			@10						; need 4 bytes here to correspond to ROM driver
					jmpROM		ROM_PICBInOpen			; finish up in ROM
@10					leaROM		ROM_AsyncBIn,a2			; load up the inputs
					lea			PICAsyncBIn,a3
toBOpenPatch		leaROM		IntoChkBConfig,a0		; continue on in ChkBConfig
					bra.w		OpnFx1

PICBOutOpen			jmp			@10						; need 4 bytes here to correspond to ROM driver
					jmpROM		ROM_PICBOutOpen			; finish up in ROM
@10					leaROM		ROM_AsyncBOut,a2		; load up the inputs
					lea			PICAsyncBOut,a3
					bra.s		toBOpenPatch
;
; Prime Routines
;
; We patch the input prime routines because they're trashing the error code
; value thru one thread.

PICAInPrime			move.l	SerialVars,d0		;Port A uses serial vars
					bra.s	InPrime

PICBInPrime
					move.l	ExpandMem,a2		;Port B uses expand mem
					move.l	ExpandMemRec.emSerdVars(a2),d0

InPrime
					move.l	d0,a2				;a2 = serial storage ptr (assume ok)
					bgt.s	@10					;output driver is open
					move.w	#ReadErr,d0
					move.l	JIODone,-(sp)		;output side not open
					rts
@10
					clr.l	ioActCount(a0)		;get ready for read
					move.l	a1,10(a2)			;save dce showing cmd active into ReadCmdDCE variable

					moveq.l	#NoErr,d0			;clear out the error code!!!   		<41>
					jmpROM	ROM_BufferShuffle	;return to the twisted code in ROM

;
; Close Routines
;
; So far we only need to patch control for 7.0 VM to unhold the buffer
; we may have held durning ctl call #9.
;

PICAOutClose
PICBOutClose

	with IOPRequestInfo

		move.l	a1,-(sp)				; save dce on stack
		MOVE.L	DCtlStorage(A1),a2		; a2 = handle to local storage
		MOVE.L	(A2),A2 				; a2=local storage pointer

		clr.b	PICOpenFlag(a2)		;mark driver as closed

;kill the waiters on the event message
; fixed rmv to use same pb.

		lea		EventMsgPB(a2),a0		; get address of the waiter
		move.l	a0,d0
		_StripAddress					; and strip it
		move.l	d0,a0
		move.b	#irRemoveRcvWaiter,irRequestKind(a0)		;remove a wait for msg
		_IOPMsgRequest										;remove it

;send a close msg to pic

		move.b	#CloseOpCode,OpenMsg+OpCode(a2)	;close opcode
		lea	OpenMsgPB(a2),a0					;send msg to pic
		_IOPMsgRequest
@10
		tst.b	OpenMsgPB+irReqActive(a2)	;is it done yet?
		bne.s	@10							;no, wait some more

; and finally do what we came here for...
		jsr UnHoldPICBuf			; unhold the buffer
		jmpROM	backToPICClose		; and go back to the ROM

	endwith
;
; UnHoldPICBuf -- unholds the the buffer that may have been held
; Called by: control, close
; Inputs: a2 -- ptr to the serial vars

UnHoldPICBuf
	; if old buffer was held, we better unhold it. it will have been held
	; if it was not our LocalBuf, i.e. was not in the system heap
	; first time thru this loop InBufPtr is 0.
			move.l	#gestaltVMAttr,d0	; is VM installed?
			_Gestalt
			move.w	a0,d0
			beq.s	@goodEnd			; if not, we're outta here

			lea		PICLocalBuf(a2),a0	; inBufPtr = LocalBufPtr?
			move.l	a0,d0
			_StripAddress				; being careful
		 	movea.l	PICInBufPtr(a2),a0	; addr of old buffer
			cmp.l	a0,d0
			beq.s	@goodEnd			; yes, then don't need to unhold
			cmpa.l	#0,a0				; inBufPtr = 0? (for first time thru)
			beq.s	@goodEnd			; yes, then don't need to unhold
			clr.l	d0					; load count.l into a1 					<137>
			move.w	PICBufSize(a2),d0	;										<137>
			move.l	d0,a1				;										<137>
			_UnHoldMemory				; unhold the old buffer
			rts

@goodEnd	moveq	#0,d0				; everything a-ok
			rts
;
; Control Routines
;
; So far we only need to patch control for 7.0 VM to hold the buffer in
; ctl call #9 in memory.
;

PICAOutControl
PICBOutControl
		move.l	DCtlStorage(a1),a2	;recover handle from DCE
		move.l	(a2),a2			;recover pointer
		bra.s	Control_1

PICAInControl						;Requires output driver open
		move.l	SerialVars,d0		;Port A uses serial Vars
		bra.s	Control
PICBInControl						;Requires output driver open
		move.l	ExpandMem,a2		;Port B uses expand mem area
		move.l	ExpandMemRec.emSerdVars(a2),d0

Control

						;a0 = iopb
						;a1 = dce
						;d0 = address of serial storage (maybe)
		move.l	d0,a2				;a2 = address of serial storage -- assume it is ok
		bgt	Control_1				;is ok if not zero or < 0
		jmpROM	backToPICKillIO		;we don't want to be here unless storage ptr is ok

Control_1
		move.w	CSCode(a0),d1		;
		cmpi	#9,d1				; opcode 9?
		beq.s	Ctl9OpCode			; if so, handle here in the patch

		jmpROM	backToPICControl	; if not, let ROM handle it


;-------------------------------------------------
; Ctl9OpCode - install/remove user supplied buffers
;	a0 = iopb
;	a1 = dce
;	a2 = output driver local storage
;-------------------------------------------------
Ctl9OpCode
			movem.l	a0-a1,-(sp)			; save out PB ptr and DCE ptr

			clr.w	PICBufIndex(a2)		;clear input and output indexes
			clr.w	PICBufOutdex(a2)

			move.l	CSParam(a0),a4		; nubuf ptr
			clr.l	d1					; clear out buffer count			<135>
			move.w	CSParam+4(a0),d1	;is nubuf being supplied (cnt)
			beq.s	@10					;no, use our own

;::::::::::::::::::::::VM STUFF START::::::::::::::::::::::::::
	; hold the new non-local buffer so VM doesn't page it out
			move.l	#gestaltVMAttr,d0	; is VM installed? not on a mac II w/o MMU
			_Gestalt
			move.w	a0,d0
			beq.s	@15					; if not, skip the hold

			movea.l	a4,a0				; hold buffer addr
			movea.l	#0,a1				; clear out count
			movea.l	d1,a1				; hold buffer count					<135>

	; since VM won't let us call _holdmemory with interrupts
	; masked, we return the error that VM spits at us.
	; note that PIC driver does not set interrupt mask at all
			_HoldMemory					; hold the new buffer in memory
			tst.w	d0					; did we get our physical buffer?
			beq.s	@15					; yes, go on
			bra.s	toPicCtlExit		; no, punt with a VM error
@10
	;install our own buffers
			lea		PICLocalBuf(a2),a4
			move.w	#LclBufSize,d1

@15			jsr		UnHoldPICBuf		; unhold the old buffer if necessary
			tst.w	d0					; did we release the old buffer?
			bne.s	toPicCtlExit		; no, punt with VM error
;::::::::::::::::::::::VM STUFF STOP:::::::::::::::::::::::::::

			move.l	a4,PICInBufPtr(a2)	; actually install the buffer
			move.w	d1,PICBufSize(a2)

			clr.w	d0					;all done

toPicCtlExit	movem.l	(sp)+,a0-a1			; restore PB ptr and DCE ptr
			jmpROM	ROM_PICCtlExit

;
; Status Routines
;
; We patch the status routines in order to provide a new Version number
; status call (9 and $8000 csCodes).  We are adding negative csCodes for
;	system required codes (see David Wong).
;

PICAOutStatus
PICBOutStatus
		move.l	DCtlStorage(a1),a2	;recover storage ptr from our own DCE
		move.l	(a2),a2
		bra.s	Status_1
PICAInStatus
		move.l	SerialVars,d0		;Port A uses serial Vars
		bra.s	Status
PICBInStatus
		move.l	ExpandMem,a2		;Port B uses expand mem area
		move.l	ExpandMemRec.emSerdVars(a2),d0
Status
						;a0 = iopb
						;a1 = dce
						;d0 = address of serial storage (maybe)
		move.l	d0,a2			;a2 = address of serial storage -- assume it is ok
		bne	Status_1		;is ok if not zero or < 0
		move.w	#StatusErr,d0		;mark as status error
		jmpROM	StatusErrExit		;error output driver not open
Status_1


;process the status call always will complete immediately
						;a0 = iopb
						;a1 = dce
						;a2 = output driver storage

		MOVE.W	CSCode(A0),D1		; get opcode
		cmpi.w	#9,d1				; do we care?
		beq.s	@version			; yes
		cmpi.w	#$8000,d1			; largest negative number csCode for Version
		beq.s	@version			; yes
		jmpROM	BacktoPICStatus

@version
		move.b	#SerialVers,CSParam(a0); return the version							<135>
		jmpROM	PICStatusOkExit;
;	end of patched PIC routines
;_______________________________________

;_______________________________________
;
;	Bypass Patch Code Entry Point
;	(Patched Bypass mode routines here)
;
;	Called By:	we get here via the async serial patch vector ($a0be)
;

SerialPatch
		movem.l		d0/a2-a3,-(SP)					; save reg d0,a2,a3						<PMAB401>
		move.l		16(SP),D0						; get D0 = return address				<PMAB401>

		lea			AsyncAIn,a2						; assume we are coming from AIn
		lea			PICAsyncAIn,a3					;
		cmpRA		fromAInOpen,D0					; test for ChkAConfig call from AInOpen
		beq.w		OpenFix

		lea			AsyncAOut,a2					; assume we are coming from Aout
		lea			PICAsyncAOut,a3					;
		cmpRA		fromAOutOpen,D0					; test for ChkAConfig call from AOutOpen
		beq.w		OpenFix

		lea			AsyncBIn,a2						; assume we are coming from BIn
		lea			PICAsyncBIn,a3					;
		cmpRA		fromBInOpen,D0					; test for ChkBConfig call from BBInOpen
		beq.w		OpenFix

		lea			AsyncBOut,a2					; assume we are coming from Bout
		lea			PICAsyncBOut,a3					;
		cmpRA		fromBOutOpen,D0					; test for ChkBConfig call from BOutOpen
		beq.w		OpenFix

		move.l		12(sp),d0						; one less level indirection for non-open calls

		cmpRA		fromControl,d0					; to fix bypass control calls
		beq.w		ControlFix

		cmpRA		fromStatus,d0					; to fix bypass control calls
		beq.w		StatusFix

		cmpRA		fromClose,d0					; to fix bypass close calls
		beq.w		CloseFix

		cmpRA		fromInitSCC,d0					; to fix initSCC routine
		beq.w		InitSCCFix

		movem.l		(sp)+,d0/a2-a3					; restore regs					<PMAB401>
		RTS											; back to ROM

;
;	Close fixes-- so far we only need to do it for 7.0 VM to unhold
; 	the buffer we may have held in control call #9.
;
CloseFix
			ADD.L	#16,SP				; pop save reg d0, for some reason the driver saved
										; out ptr to globals in a6
			move.l	a1,-(sp)			; save out the DCE ptr
		 	MOVE.L	(A6),A2 			; get locals pointer				<14Oct85>
			TST.B	CtlOptions(A2)		; leave DTR unchanged?				<14Oct85>
			bmi.s	@1					;									<C216/16oct86>
			bclr	#7,XmitBits(A2)		; no, clear the DTR bit				<C216/16oct86>
			bclr	#7,WR5AVal(A2)		;									<C216/16oct86>
@1			bclr	#3,XmitBits(A2)		; always clear Tx enable			<C216/16oct86>

			jsrROM	SyncOutput			; delay until last char has cleared	<14Oct85>
										;  output buffer
			LeaROM 	ResetData,A3
			MOVEQ	#ResetLth,D1
			jsrROM 	InitSCC1			; shut down the channel

	; now that we've shut down the channel it should be safe to unhold
	; the input buffer. we won't check for error since we can't do much
	; about it anyway.
			jsr		UnHoldInputBuf		; unhold the buffer if necessary
			move.l	(sp)+, a1			; restore the DCE ptr
			jmpROM	backToClose

;::::::::::::::::::::::VM STUFF START::::::::::::::::::::::::::
;
; UnHoldInputBuf -- unholds the the buffer that may have been held
; Called by: control, close
; Inputs: a2 -- ptr to the serial vars

; if old buffer was held, we better unhold it. it will have been held
; if it was not our LocalBuf, i.e. was not in the system heap
; first time thru this loop InBufPtr is 0.
UnHoldInputBuf
			move.l	#gestaltVMAttr,d0	; is VM installed?
			_Gestalt
			move.w	a0,d0
			beq.s	@goodEnd			; if not, we're outta here

	; check usual case...is inBufPtr equal to LocalBufPtr?
			move.l	d1,-(sp)			; save a reg
			lea		LocalBuf(a2),a0		;inBufPtr = LocalBufPtr?
			move.l	a0,d1
		 	move.l	InBufPtr(a2),d0
			eor.l	d1,d0
			_StripAddress				; ignore differences in the high bits
			move.l	(sp)+,d1			; restore a reg
			tst.l	d0					;
			beq.s	@goodEnd			; same, so don't need to unhold

	; check first time thru case, when InBufPtr
	; would equal zero
		 	move.l	InBufPtr(a2),d0		; for first time thru, is InBufPtr zero?
			beq.s	@goodEnd			; yes, then don't need to unhold

	; unhold the puppy
			movea.l	d0,a0				; a0 <- ptr
			moveq	#0,d0				; clear out count
			move.w	BufSize(a2),d0		;
			movea.l	d0,a1				; a1<- cnt
			_UnHoldMemory				; unhold the old buffer
			rts

@goodEnd	moveq	#0,d0				; everything a-ok
			rts

;::::::::::::::::::::::VM STUFF STOP:::::::::::::::::::::::::::

;
;	Routine:	InitSCC
;	Patch:		--We patch this routine to use the InitData table here in RAM
;				instead of the one in ROM. We do this so that the values in
;				WR11 and WR14 aren't hardcoded, so that we can support external
;				clocking.
;				--We also fix the value of StopBits (WR4) here to have the clock
;				divide bits correspond to the the external/internal clock state
;				indicated in CtlOptions. We do this here so that CtlConfig calls
;				won't stomp StopBits in the ToSCCInit routine.
;				--We also disable HWHS so we don't try to use CTS line for both
;				clocking and handshaking.
clkBit		equ		6					; bit 6 in CtlOptions controls ext/int SCC clk
clkDvdBit	equ		6					; divide clock bit in WR4
clkMask		equ		%01000000			; mask for getting at clkBit						<129>
extClkSrc	equ		%00101000			; SCC clk src is TRxC (CTS) pin (WR11)				<129>
intClkSrc	equ		%01010000			; SCC clk src is baud rate generator (WR11)			<129>
BRGEnbl		equ		%00000001			; enable baud rate generator (WR14)					<129>
BRGDsbl		equ		%00000000			; disable baud rate generator (WR14)				<129>

SCCDataTable
			DC.B	$02,9				; status in low bits, MIE disabled
clkDvd		DC.B	4,$FF				; x16 clk, stop bits, parity options
			DC.B	1,$FF				; WR1 reg, first write
			DC.B	3,$FF				; bits/char option rcvr
			DC.B	5,$FF				; bits/char option xmitter
			DC.B	$00,2				; zero interrupt vector
			DC.B	$00,10				; NRZ encoding
ClkMode		DC.B	$50,11				; brgen/TRxC clk to rcvr, xmitter--default to internal
			DC.B	12,$FF				; set baud rate low byte
			DC.B	13,$FF				; set baud rate high byte

			DC.B	3,$FF				; enable rcvr
			DC.B	5,$FF				; enable xmitter
BRGEnable	DC.B	$01,14				; enb/disable baud rate generator from RTxC pin --default to on
			dc.b	$A0,15				; Break, CTS external ints (dcd not needed)			<2.3>
			DC.B	$10,0				; reset ext/status twice
			DC.B	$10,0
			DC.B	1,$FF				; w/req pin configuration
			DC.B	$0A,9				; enable interrupts, status in low bits

SCCDataTableLth 	EQU 	*-SCCDataTable	;

InitSCCFix
			movem.l	(sp)+,d0/a2-a3		; restore drvr storage ptr in a2, InitSCC table in a3
			add.l	#4,sp				; pop saved rtrn addr--we jump back

			move.l	a3,d0
			cmpRA	InitData,d0			; are we initializing SCC?
			bne		@done

			lea		SCCDataTable,a3		; use our RAM table instead of the ROM one
			moveq	#SCCDataTableLth,d1

			movem.l	d1/a0,-(sp)				; save out reg's								<129>

	; default to internally clocked state													<129>
			bset.b	#clkDvdBit,StopBits(a2) ; default to a divide-by-16 clock				<129>
			moveq	#intClkSrc,d0			; internal clocking source						<129>
			moveq	#BRGEnbl,d1				; enable baud rate generator					<129>

			btst.b	#clkBit,CtlOptions(a2)	; are we externally clocked?
			beq.s	@load					; not externally clocked, so load

	; set to externally clocked state
			bclr.b	#clkDvdBit,StopBits(a2)	; set to a divide-by-one clock					<129>
			moveq	#extClkSrc,d0			; external clock source							<129>
			moveq	#BRGDsbl,d1				; disable baud rate generator					<129>
			clr.b	HWHS(a2)				; make sure we're not trying to do HWHS			<129>

@load		lea		ClkMode,a0				; load params into InitSCC data table			<129>
			move.b	d0,(a0)					;												<129>
			lea		BRGEnable,a0			;												<129>
			move.b	d1,(a0)					;												<129>

			movem.l	(sp)+,d1/a0				; restore reg's									<129>
@done		jmpROM	backToInitSCC			; finish up in ROM







;
;	Routine:	Status
;	Patch:		We patch status to add a call to return the driver's version.
StatusFix
			movem.l	(sp)+,d0/a2-a3		; restore drvr storage ptr in a2
			add.l	#4,sp				; pop saved rtrn addr--we jump back

			MOVE.W	IOTrap(A0),-(SP)	; save trap to distinguish immed calls<14Oct85>
			MOVE.L	A1,-(SP)			; save passed DCE for in/out		<14Oct85>
			MOVE.W	SR,-(SP)			; disable interrupts for ctl call	<14Oct85>
			ORI 	#HiIntMask,SR		;									<A357/06nov86>
			LEA 	CSCode(A0),A0		; get pointer to return parameters
			MOVEQ	#StatusErr,D0		; assume status error
			MOVE.L	A2,D1				; have our variables been set up?	<14Oct85>
			Bgt		@stat1 				; exit if not (only input side open)
			jmpROM	ROM_CtlExit			; just like ROM

@stat1		MOVE.W	(A0)+,D1			; get opcode

			cmpi.w	#9,d1				; do we care?
			beq.s	@version			; yes
			cmpi.w	#$8000,d1			; largest negative number csCode for Version
			beq.s	@version			; yes
			jmpROM	BackToStatus		; no

@version	move.b	#SerialVers,(a0)	; return the version				<135>
			jmpROM	ROM_CtlGood

;
;	Routine:	Control
;	Patch:		We patch control for the following reasons:
;				1) to add VM support for control call 9--lock/unlock the buffer
;				2) to add external clock support in  control call 16
;
ControlFix
			movem.l	(sp)+,d0/a2-a3		; restore drvr storage ptr in a2
			add.l	#4,sp				; pop saved rtrn addr--we jump back

			MOVE.W	IOTrap(A0),-(SP)	; save trap to distinguish immed calls<14Oct85>
			MOVE.L	A1,-(SP)			; save passed DCE for in/out		<14Oct85>
			MOVE.W	SR,-(SP)			; disable interrupts for ctl call	<14Oct85>
			ORI 	#HiIntMask,SR		;									<A357/06nov86>

			moveq	#0,d0				; for the killIO call
			LEA 	CSCode(A0),A0		; get parameters
			MOVE.W	(A0)+,D1			; get opcode

			cmpi.w	#9,d1				; opcode 9?  (buffer)
			beq		CtlBuffer			; if so, handle here in the patch
			cmpi.w	#16,d1				; opcode 16? (ctlOptions)		<extClk>
			beq		CtlSwitchCTSClock		; 							<extClk>
			jmpROM	backToControl		; if not, let ROM handle it



;_______________________________________;
;
; Install a new input buffer.
;
; The patch is needed for 7.0 VM. We must 'hold' the buffer in memory
; so that there is no possibility it is paged out at interrupt time (which
; would have the potential for causing a double page fault).
;_______________________________________;

CtlBuffer	CLR.L	BufIndex(A2)		; clear in and out indices

			MOVE.L	(A0)+,A4			; buffer pointer
			moveq	#0,d1				; clear out length reg
			MOVE.W	(A0),D1 			; length of buffer?
			BEQ.S	InstllLBuf			; if zero, revert to our own buffer

	; hold the new non-local buffer so VM doesn't page it out
			move.l	#gestaltVMAttr,d0	; is VM installed? not on a mac II w/o MMU
			_Gestalt
			move.w	a0,d0
			beq.s	InstllABuf			; if not, skip the hold

			movea.l	a4,a0				; hold buffer addr
			movea.l	d1,a1				; hold buffer count
	; since VM won't let us call _holdmemory with interrupts
	; masked, we set the interrupt level back to that app's
	; interrupt level, which hopefully was zero. If so, then
	; everything should be peachy. If not, then we return the
	; error that VM spits at us.
			move.w	sr,-(sp)			; save our int lvl
			move.w	2(sp),d0			; get app's int lvl
			and.w	(sp),d0 			; and set us to that
			move.w	d0,sr

			_HoldMemory					; hold the new buffer in memory
			move.w	(sp)+,sr			; and restore our int lvl

			tst.w	d0					; did we get our physical buffer?
			beq.s	InstllABuf			; yes, go on
Ctl_Err		jmpROM	ROM_CtlExit	; no, then pass back VM error

	; InstllLBuf is also called from OpenInstall!

InstllLBuf	LEA 	LocalBuf(A2),A4 	; use our meager local buffer for now
			MOVEQ	#LclBufSize,D1		;

InstllABuf
	; since VM won't let us call _holdmemory with interrupts
	; masked, we set the interrupt level back to that app's
	; interrupt level, which hopefully was zero. If so, then
	; everything should be peachy. If not, then we return the
	; error that VM spits at us.
			move.w	sr,-(sp)			; save our int lvl
			move.w	2(sp),d0			; get app's int lvl
			and.w	(sp),d0 			; and set us to that
			move.w	d0,sr

			jsr		UnHoldInputBuf		; unhold the buffer if necessary

			move.w	(sp)+,sr			; restore our int lvl
			tst.w	d0					; did we release old buffer?
			bne.s	Ctl_Err				; no, pass back VM error

			jsrROM	FinishCall9			; and finish up the call in ROM
			jmpROM	ROM_CtlGood			; and go back to ctl call dispatcher
;::::::::::::::::::::::VM STUFF STOP:::::::::::::::::::::::::::


; 	Routine:	SetCtlOptions  -- Opcode 16
;	Patch:		We patch this routine so that bit 6 of CtlOptions variable now
;				controls a switch to internal/external clocking on the CTS (HSIn) line.
;				We must call InitSCC to get the clocking option to kick in.
;	Inputs:		byte number in IOPB			value
;				(26) 						[$0010] opcode
;				(28)						bit 7 = 0 for drop DTR at close
;											bit 7 = 1 for leave DTR unchanged at close
;											bit	6 = 0 for internal clocking
;											bit 6 = 1 for external clocking
;											bits 0-5 reserved for future use
; 	Notes:		We will not put control for the GPI internal/external
;				clocking switch here, as that requires the control of
;				HW external to the SCC (namely, the VIA vSync pin). Control
;				of the GPIa line is in _HWPriv.
;

CtlSwitchCTSClock
			move.b	(a0),CtlOptions(a2)	; store new value						<129>
			jsrROM	InitSCC				; set up the SCC according to new value	<129>
			jmpROM	ROM_CtlGood			; finish up in ROM						<129>


;
;	Open Fixes
;
;
; note that no stack fiddling is allowed, as the chkConfigure EXPECTS to be called directly
; from the open routine, and will not go to IOCore with error properly should one occur.

; Common code for open patches

OpenFix	move.l		d0,a4							; save where we came from w/o use of the stack
		ADD.L		#12,SP							; pop save reg d0,a2,a3 - not needed		<PMAB401>
		MOVE.L		(SP)+,A0						; pop A0 = addr to continue ChkConfig
		addq		#4,SP							; pop async open ret addr - will jmp back
OpnFx1	jsr			(a0)							; finish ChkConfig (A1,D1,D2 params)


	; check to see whether we are in IOP or Bypass mode
	if isUniversal then								;											<2.1>
		TestFor		SCCIOPExists					;check to see if we even have an IOP		<2.1>
		beq.s		@05								;if not, just use bypass mode driver		<2.1>
	endif											;											<2.1>

		btst		#0,SCCIOPFlag					;are we in bypass mode?						<8.7> test low mem, not PRAM
		bne.s		@05								;yes, in bypass mode; use SCC driver 		<8.7> change bit sense

		move.l		a3,a2							; plug in PIC driver header address
@goback	jmpROM		PlugInDrvr						; go finish open call


; install our RAM-based bypass driver header into DCE											<125>
; a2 has pointer to RAM driver header
; a1 has pointer to DCE
@05
		move.l		a2,(a1)							; install ourselves into the DCE

; check again where we came from to see if which open fix to branch off to.
		move.l		a4,d0							; restore where we came from
		cmpRA		fromAOutOpen,d0					; test for ChkAConfig call from AOutOpen
		beq.s		FixAout

		cmpRA		fromBOutOpen,d0					; test for ChkAConfig call from AOutOpen
		beq.s		FixBout

		jmpROM		backToInOpen					; for In driver just go finish open call	<125>

FixAout
;	replace receive routine vectors installed by async open
		LEA			PortAVars,A2					; local variables address
		peaROM 		ROM_PollDtaIn,-(sp)				; ROM--this proc handles disk poll data		<20Oct85>
		pea	 		NewSCAIntHnd					; Special RxD int handler			<4>	<20Oct85>
		pea	 		NewRAIntHnd						; int handler						<4>	<20Oct85>
		peaROM 		ROM_TAIntHnd,-(sp)				; ROM--TxD int handler						<20Oct85>
		PEA 		Lvl2DT+16						; SCC interrupt dispatch table, chan A	<20Oct85>
		PEA 		NewExtAIntHnd					; External int handler					<20Oct85>
		jmpROM		backToAOutOpen					; JUMP BACK INTO ROM

FixBout
;	replace receive routine vectors installed by async open
		move.l		ExpandMem,a2					; local variable address in is	<2.0>
		lea			ExpandMemRec.emSerdVars(a2),a2	; expandmem						<2.0>
		CLR.L		-(SP)							; no disk poll routine
		pea	 		NewSCBIntHnd					; Special RxD int handler			<4>	<20Oct85>
		pea	 		NewRBIntHnd						; RxD int handler					<4>	<20Oct85>
		peaROM 		ROM_TBIntHnd,-(sp)				; ROM--TxD int handler						<20Oct85>
		PEA 		Lvl2DT							; SCC interrupt dispatch table, chan B	<20Oct85>
		PEA 		NewExtBIntHnd					; External int handler					<20Oct85>
		jmpROM		backToBOutOpen					; JUMP BACK INTO ROM


;-----------------------------------------------------------------------		
;
;		Interrupt Handlers
;
;-----------------------------------------------------------------------
;________________________________________________________________________
;
; Routine:		RXIntHnd
;
; Arguments:	  A0 (input)   --  chan A/B control read address
;				  A1 (input)   --  chan A/B control write address
;
; Function: 	This routine handles SCC receiver interrupts for
;				both channels; the data is read and stashed, IODone called
;				if necessary.
;
; Patches:		Patched to fix the serial thruput problem on Apollo and TimLC.				<4>
;				If we complete a device manager request we change the return
;				address on the stack to return to the primary 
;				level 4 interrupt dispatcher, rather than to the code in the
;				secondary dispatcher that checks to see if there is another 
;				RxChar available (and loops to process the next interrupt if so).
;				This way we guarantee that we return all the way out of the interrupt
;				handlers at least once per device manager request, allowing
;				things like deferred tasks a chance to run.
;________________________________________________________________________

Lvl4IntPatchSize 	equ		10			; size of interrupt patch code

NewRBIntHnd	
			move.l	ExpandMem,a3		; get appropriate variables (chan B) <2.0>
			lea		ExpandMemRec.emSerdVars(a3),a3	;						<2.0>
			
			BRA.S	RXIntHnd			; go to shared code

NewRAIntHnd	LEA 	PortAVars,A3		; get appropriate variables (chan A)

RXIntHnd	MOVE.B	SCCData(A0),D0		; get the data byte

PollStash	MOVE.L	(A3)+,A2			; get pointer to local variables
			move.l	InDCE(a2),a3		; and DCE pointer					<2.0>

			AND.B	CharMask(A2),D0 	; zero unused high bits 			<14Oct85>

			MOVE.B	PEChar(A2),D1		; Are we translating PE Characters?
			BEQ.S	@1					; No, just save the char.
			CMP.B	D1,D0				; Is the new char a PEChar?
			BNE.S	@1					; No, just do normal stuff
			MOVE.B	AltChar(A2),D0		; Make sure that a good char		<14Oct85>
										;  doesn't look like PEChar.
@1			TST.B	SWHS(A2)			; software handshake enabled?
			BEQ.S	StashIt 			; branch if not
			CMP.B	XONChar(A2),D0		; was this an XON?					<14Oct85>
			bne.s	chkXoff 			; not an XOn										<4>
ContOut 	CLR.B	XOFFlag(A2) 		; we got an XON, so clear Xoff-received flag		<4>
			jmpROM	ToContOut1			; XOn, so start output again						<4>

chkXoff		CMP.B	XOFFChar(A2),D0 	; how about an XOFF?				<14Oct85><4>
			BNE.S	StashIt 			; if not, then stash the character
			ST		XOFFlag(A2) 		; if so, then note it
InputRTS	rts							; and exit											<4>

; stash byte in the user's buffer if a request is pending, otherwise use our own

StashIt 	TST.B	ReadCmd(A2) 		; read request pending?
			bne.s	PutInUserBuf 		; request pending, so stash byte in user buffer		<4>
			jmpROM	ROM_PutInOurBuf		; no request pending, so stash byte in our buffer	<4>

PutInUserBuf
			MOVE.L	A3,A1				; get DCE pointer
			jsrROM	ROM_toStash 		; use utility routine to save code					<4>
			BPL.S	InputRTS			; if request isn't finished, just RTS
			CLR.B	ReadCmd(A2) 		; no longer a read request pending
			add.l	#Lvl4IntPatchSize,(sp); return to rts at end of int dispatcher <patch><4>
											; so we return out of Interrupt handler completely
											; since we have finished a request
			jmpROM	ROM_GoodFinish		; we have a good finish

;________________________________________________________________________
;
; Routine:		SCIntHnd
;
; Arguments:	  A0 (input)   --  channel A/B control read address
;				  A1 (input)   --  channel A/B control write address
;
; Function: 	This routine handles SCC special condition interrupts:
;				these occur when an input character is received that has
;				a parity error, framing error, or causes an overrun.
;				If the option is set to abort on the error, the character
;				is discarded and the input request (if any) aborted; otherwise,
;				the error is noted and the character buffered as usual.
;
; Patch:		Must patch this rtn because we patch the RxIntHnd which						<4>
;				includes the 'Stashit' label called here.
;
;				If there are no special condition bits set, then this is NOT				<5>
;				a special-condition interrupt, but an interrupt for which
;				the cause has already been removed. This occured with the
;				Stylewriter on faster machines, when we wrote out a byte
;				faster than the TBE interrupt could be generated (after
;				the TBE bit was set in RR0).
;________________________________________________________________________

NewSCBIntHnd	
			move.l	ExpandMem,a3		; get appropriate variables (chan B)	<2.0>
			lea		ExpandMemRec.emSerdVars(a3),a3	;							<2.0>
			BRA.S	SCIntHnd			; go to shared code

NewSCAIntHnd	LEA 	PortAVars,A3		; get appropriate variables (chan A)

SCIntHnd	MOVE.B	#1,(A1) 			; point to error reg
			MOVE.L	(A3)+,A2			; get local variables pointer
			move.l	InDCE(a2),A3		; and DCE pointer (delay, too)			<2.0>
			
			MOVE.B	(A0),D1 			; read the error condition

			MOVEQ	#$70,D3 			; form $70 mask
			AND.B	D3,D1				; isolate error bits
			beq.s	InputRTS			; no errors posted, then this is not a SC interrupt <5>
			OR.B	D1,AsyncErr(A2) 	; accumulate errors (delay, too)
			MOVE.B	SCCData(A0),D0		; get the data byte
			AND.B	CharMask(A2),D0 	; zero unused high-order bits		<14Oct85>

			MOVE.B	Options(A2),D2		; get abort options
			AND.B	D1,D2				; should we abort?
			MOVE.B	#$30,(A1)			; reset the error flag
			AND.B	D3,D2
			beq.s	@dontAbort			; options say we should NOT abort request	<4>
			jmpROM	ROM_abortReq		; options say we should abort request		<4>

@dontAbort	MOVE.B	PEChar(A2),D3		; alternate char for parity errors?			<4>
			BEQ.S	@1					; br if not
			CMP.B	D0,D3				; Is the incoming char equal to the PEChar?
			BNE.S	@0					; No, no substitution needed.
			MOVE.B	AltChar(A2),D0		; Make sure that a good char		<14Oct85>
										;  doesn't look like PEChar.
@0			BTST	#4,D1				; parity error?
			BEQ.S	@1					; br if not
			MOVE.B	D3,D0				; replace it

@1			bra.s	StashIt 			; go stash it . . .<StashIt is IN RAM NOW>	<4>

;________________________________________________________________________
;
; Routine:		ExtIntHnd
;
; Arguments:	  A0 (input)   --  channel A/B control read address
;				  A1 (input)   --  channel A/B control write address
;				  D0 (input)   --  SCC read reg 0 value
;				  D1 (input)   --  SCC read reg 0 changed bits
;
; Function: 	This routine handles SCC external/status interrupts for
;				both channels; mouse (DCD) interrupts are passed along to the
;				mouse interrupt handler in CrsrCore.  Only Break/Abort and CTS
;				external interrupts are enabled (besides DCD).
;
;				Note that CTS low in read reg 0 currently means that the
;				hardware handshake line is asserted which means 'ok to transmit'.
;________________________________________________________________________


NewExtBIntHnd
			move.l	ExpandMem,a3		; get appropriate variables - chan B	<2.0>
			move.l	ExpandMemRec.emSerdVars(a3),a2	;							<2.0>
			move.w	#28,d2				; .Bin is offset 28 into unit table		<126>
			bra.s	ExtIntHnd

NewExtAIntHnd
			LEA 	PortAVars,A3		; get appropriate variables - chan A
			MOVE.L	(A3)+,A2			; get pointer to local variables
			move.w	#20,d2				; Ain is offset 20 in the unit table	<126>

ExtIntHnd
			movea.l	UTableBase,a3		; get addr of Utable		 			<126>
			movea.l	0(a3,d2.w),a3		; get DCE handle	(d2 has offset)		<126>
			movea.l	(a3),a3				; get DCE ptr							<126>

			MOVE.B	D1,D2				; changed bits
			AND.B	postOptions(A2),D2	; post this change?
			BEQ.S	@0					; br if not

			MOVEM.L D0/A0,-(SP) 		; preserve these registers
			MOVE.W	#IODrvrEvt,A0
			ASL.W	#8,D0				; make room for 'changed' values
			MOVE.B	D1,D0
			SWAP	D0					; make room for driver refnum
			MOVE.W	DCtlRefnum(A3),D0

			_PostEvent					; and post the event
			MOVEM.L (SP)+,D0/A0

@0			TST.B	D1					; see if it's a change in break status
			BMI.S	extBreak			; branch if it was a break interrupt
			LSL.B	#2,D0				; must be CTS change

			SMI 	CTSFlag(A2) 		; set flags according to CTS

; This piece of code is used to detect a clock into the HWHS line
;  and shut off the ext/sts interrupt for the handshake line.

			CMP.W	#80,HSCount(A2) 	; exceeded 80 transitions in 16 MS? <14Oct85>
			BCS.S	@2					; br if not 						<14Oct85>

			MOVEQ	#-128,D0			; ($80) leave break ints enabled	<14Oct85>
			MOVEQ	#15,D1				; write register 15 				<14Oct85>
			jsrROM	ToCtlSet			; <patch>


@2			MOVE.L	Ticks,D2			; get current tick time 			<14Oct85>
			CMP.L	LastTime(A2),D2 	; same as last? 					<14Oct85>
			BEQ.S	@3					; br if so							<14Oct85>
			MOVE.L	D2,LastTime(A2) 	; new last time 					<14Oct85>
			CLR.W	HSCount(A2) 		; restart count for new time		<14Oct85>

@3			ADDQ	#1,HSCount(A2)		; update count						<14Oct85>
			jmpROM	toContOut1			;<patch> BRA ContOut1--if freshly asserted, continue output<14Oct85>

extBreak	TST.B	D0					; check break level
			BMI.S	@1					; if it's asserted, terminate any input
			MOVE.B	SCCData(A0),D0		; otherwise (end of break), discard null
@0			RTS 						; and return

@1			MOVEQ	#BreakRecd,D0		; note the break
			bset.b	#3,AsyncErr(a2)		; we now note break level in status
			TST.B	ReadCmd(A2) 		; read request pending?
			beq.s	@0					; just return if done 				<7.1>

			jmpROM	ToRdReqDone			; return to ROM code

;_______________________________________________________________________
;
;	Patched Driver headers (with signature long word before each header)
;
			DC.b	'wong'				; our personal signature
AsyncAIn
			DC.W	$4D00				; read, control, status, lock
			DC.W	0,0 				; not an ornament
			DC.W	0					; no menu

			DC.W	AInOpen-AsyncAIn	; Initialization routine
			DC.W	AInPrime-AsyncAIn	; input Prime routine
			DC.W	AControl-AsyncAIn	; shared Control routine
			DC.W	AStatus-AsyncAIn	; shared Status routine
			DC.W	AInClose-AsyncAIn	; Close routine

			DC.B	4					; channel A input driver
			DC.B	'.AIn '


			DC.b	'wong'				; our personal signature
AsyncAOut
			DC.W	$4E00				; write, control, status, lock
			DC.W	0,0 				; not an ornament
			DC.W	0					; no menu

			DC.W	AOutOpen-AsyncAOut	; Initialization routine
			DC.W	AOutPrime-AsyncAOut ; output Prime routine
			DC.W	AControl-AsyncAOut	; shared Control routine
			DC.W	AStatus-AsyncAOut	; shared Status routine
			DC.W	AOutClose-AsyncAOut ; Close routine

			DC.B	5					; channel A output driver
			DC.B	'.AOut'

			DC.b	'wong'				; our personal signature
AsyncBIn
			DC.W	$4D00				; read, control, status, lock
			DC.W	0,0 				; not an ornament
			DC.W	0					; no menu

			DC.W	BInOpen-AsyncBIn	; Initialization routine
			DC.W	BInPrime-AsyncBIn	; input Prime routine
			DC.W	BControl-AsyncBIn	; shared Control routine
			DC.W	BStatus-AsyncBIn	; shared Status routine
			DC.W	BInClose-AsyncBIn	; Close routine

			DC.B	4					; channel B input driver
			DC.B	'.BIn '

			DC.b	'wong'				; our personal signature
AsyncBOut
			DC.W	$4E00				; write, control, status, lock
			DC.W	0,0 				; not an ornament
			DC.W	0					; no menu
			DC.W	BOutOpen-AsyncBOut	; Initialization routine
			DC.W	BOutPrime-AsyncBOut ; output Prime routine
			DC.W	BControl-AsyncBOut	; shared Control routine
			DC.W	BStatus-AsyncBOut	; shared Status routine
			DC.W	BOutClose-AsyncBOut ; Close routine

			DC.B	5					; channel B output driver
			DC.B	'.BOut'

;_______________________________________________________________________
;
;	jumping to ROM from our patched entry points
;
AInOpen			jmpROM		ROM_AInEntryOpen		;port a				<125>
AInClose		jmpROM		ROM_AInEntryClose
AInPrime		jmpROM		ROM_AInEntryPrime

AOutOpen		jmpROM		ROM_AOutEntryOpen
AOutClose		jmpROM		ROM_AOutEntryClose
AOutPrime		jmpROM		ROM_AOutEntryPrime

AControl		jmpROM		ROM_AEntryControl
AStatus			jmpROM		ROM_AEntryStatus

BInOpen			jmpROM		ROM_BInEntryOpen		;port b
BInClose		jmpROM		ROM_BInEntryClose
BInPrime		jmpROM		ROM_BInEntryPrime

BOutOpen		jmpROM		ROM_BOutEntryOpen
BOutClose		jmpROM		ROM_BOutEntryClose
BOutPrime		jmpROM		ROM_BOutEntryPrime

BControl		jmpROM		ROM_BEntryControl
BStatus			jmpROM		ROM_BEntryStatus

			endproc
;_______________________________________________________________________
;	<7.1><8.7><81><123><125> Async Serial Driver Patch
;
;	End of patch code for fix of bugs in the serial driver
;	introduced into the aurora ROM (and hence the F19 overpatch ROM) by the
;	port arbitration code, which was accidently included in those ROMS.
;_______________________________________________________________________
;_______________________________________________________________________





;________________________________________________________________________________
;	<8.8> RecoverHandle() patch for 32-bit Memory Manager
;
;	This patch fixes RecoverHandle so that if the passed block pointer isn't in
;	either the system or app heaps, it makes a last-ditch pass and sees if the
;	pointer points to a ROM resource.  If so, great, else it bails with an error.
;	This is especially useful since several new AppleTalk resources are in ROM
;	and their users have a tendency to do RecoverHandles on them because they
;	don't know any better (and shouldn't have to).
;
;	No traps are patched.  These routines are patched into the 32-bit Memory Manager's
;	vector tables in lo-mem at JMemMgr24 ($1E00) and JMemMgr32 ($1F00).
;________________________________________________________________________________

			PROC
			EXPORT	v24RecoverHandle,v32RecoverHandle

;________________________________________________________________________________
;
; Routine:	v24RecoverHandle,v32RecoverHandle
;
; Inputs:	A0 -- pointer to block
;			A6 -- pointer to current heap zone
;
; Outputs:	A0 -- handle to block
;			D0 -- unchanged from input
;			MemErr contains the error code
;
; Function:	Given a pointer to an alleged heap block, it returns the block's handle.
;________________________________________________________________________________

v24RecoverHandle							; 24 bit version of RecoverHandle
			MOVE.L	Lo3Bytes,D2				; mask to strip extraneous bits
			BRA.S	vRecoverHandle

v32RecoverHandle							; 32 bit version of RecoverHandle
			MOVEQ	#-1,D2					; no extraneous address bits in 32-bit mode

vRecoverHandle
			Move.L	BusErrVct,A2			; save current bus error handler
			LEA		RHBusErrHandler,A3		; our ZC version
			Move.L	A3,BusErrVct

			Move.L	-4(A0),A1				; Handle, or ROMBase on bus error

			Move.L	A2,BusErrVct			;restore old one after danger

			Add.L	A6,A1

; The following code tests for bad mp, but can only set MemErr

			Move.L	A0,D1					; original pointer
			And.L	D2,D1 					;  stripped to RAW address
			AND.L	(A1),D2 				; master pointer value stripped to RAW address
			Sub.L	D1,D2					; if equal, have required error code!
			Beq.S	RecoverExit

; If we get here, the pointer either didn't point to a block in the suspected
; heap or is a bogus block pointer.  We'll assume it's the first case and try
; looking in the ROZ created for the ROM resource map before giving up completely.
; This will not affect the performance of RecoverHandle() since this code is only
; executed as part of the error path (which shouldn't be taken most of the time).

			MOVEA.L	A6,A3					; save the previous zone start pointer
			MOVEA.L	RomMapHndl,A6			; get the handle to the ROM resource map
			MOVEA.L	(A6),A2					;  and de-reference it
			SUBA.L	-4(A2),A6				; calculate heap start based on rel hdl in MP

			CMPA.L	A3,A6					; have we been here before?
			BNE.S	v32RecoverHandle		; -> no, try again with the ROZ

			MoveQ	#memBCErr,D2			; block check failure
RecoverExit
			Move.W	D2,MemErr				; stuff global error code (is anybody out there?)
			MoveA.L A1,A0					; restore A0=handle

			Move.L	vMMNoErrEpilogue,-(SP)	; get MMNoErrEpilogue vector
			RTS


;________________________________________________________________________________
;
; RHBusErr -- bus error handler for RecoverHandle
; A bus error in RecoverHandle causes ROMBase to be jammed for
; the relative handle.
; Clear DF bit in frame to inhibit retry of failed read from RAM, and force
; ROMBase into result, i.e. A1.
; Input: none
; Output: potentially forces ROMBase to result field (ultimately A1)
; Regs: A3
; Triggered by bus errors in Move.L	-4(A0),A1 in RecoverHandle.
;________________________________________________________________________________

RHBusErrHandler
			AndI.W	#$FEFF,$A(SP)			;clear DF bits
			Move.L	ROMBase,$2C(SP)			;fake Nil value in DIB
			RtE

			ENDPROC
;________________________________________________________________________________
;
;	<8.8> End of RecoverHandle() patch
;________________________________________________________________________________


;________________________________________________________________________________
;	RMP <12>
;
;	 SetHandleSize() patch for 32-bit Memory Manager
;
;	This patch fixes A32SetSize not to de-reference off from a nil handle (i.e. A1)
;	when it is called by v32SetHandleSize.
;
;	No traps are patched.  These routines are patched into the 32-bit Memory Manager's
;	vector tables in lo-mem at JMemMgr32+jsetHandleSize ($1F64).
;________________________________________________________________________________


			PROC
			EXPORT	v32SetHandleSize
			IMPORT	a32SetSize

;----------------------------------------------------------------------
;
; FUNCTION SetHandleSize(h: Handle; cb: LongInt): result;
;
; This routine is used to change the size of a relocatable memory block.
; The block handle remains the same; the Master Pointer is unchanged if
; the new length is less than or equal to the old.
;
; Arguments:
;		D0 - cb:		new block size
;		A0 - handle:	pointer to master pointer
;
; Result:
;		D0 - 0 => success; memFullErr => failure
;
; Registers:
;
;		A0 - next free block
;		A1 - handle
;

v32SetHandleSize
				BNE.S	SHSOk

SHSNil
				MoveQ	#nilHandleErr,D0		;return error code
				BrA.S	SHSExit
SHSOk
				BSR.S 	a32SetSize 				;Set size as specified in D0
SHSExit
				Move.L	A1,A0					;restore A0 for RecoverHandle
				Move.L	vMMEpilogue,-(SP)		; get vector to MMEpilogue				<v1.9>
				RTS								; jump to it							<v1.9>

			ENDPROC
;________________________________________________________________________________
;
;	<12> End of SetHandleSize() patch
;________________________________________________________________________________



;________________________________________________________________________________
;	<68> <85>
;
;	 SetPtrSize() patch for 32-bit Memory Manager
;
;	This patch fixes A32SetSize not to de-reference off from a nil handle (i.e. A1)
;	when it is called by v32SetPtrSize.
;
;	No traps are patched.  These routines are patched into the 32-bit Memory Manager's
;	vector tables in lo-mem at JMemMgr32+jsetptrSize ($1F4C).
;________________________________________________________________________________

			PROC
			EXPORT	v32SetPtrSize,a32SetSize

; addresses in ROM
a32ActualS		EQU		$E5A2
a32GetSize		EQU		$E5D2
HBlockMove		EQU		$E334
a32MakeSpace	EQU		$EB40
ClearGZStuff	EQU		$E5F2
SubtractFree	EQU		$E92A
A32MakeBkF		EQU		$DDF4
AdjustFree		EQU		$E91C
A32SetLogSize	EQU		$E2A0
a32RelocRel		EQU		$EC66
a32SetSizePatch	EQU		$87996

SmartSetSize		EQU		1


;----------------------------------------------------------------------
;
; FUNCTION SetPtrSize(blk: Ptr; cb: Size): result;
;
; This routine is used to set the size of non-relocatable memory blocks
;
; Arguments:
;		D0 - cb:		new block size
;		A0 - blk:		pointer to block data
;		A1 - h: 		NIL, set up by MMPPrologue
;
; Result:
;		D0 - 0 => success; memFullErr => failure
;
; Registers:
;
;		A0 - next free block
;		A1 - current free block
;		A2 - theZone
;		D0 - number of bytes needed
;		D1 - number of bytes in current free block
;		D2 - new block length (temporary)
;
v32SetPtrSize
				BSR.S 	a32SetSize				; set its size							<v1.1>
				Move.L	vMMEpilogue,-(SP)		; get vector to MMEpilogue				<v1.9>
				RTS								; jump to it							<v1.9>


; ----- 32 bit version -----
a32SetSize
				MoveM.L D1-D6/A0-A3,-(SP)		;Save registers.								<18Apr85>
				Move.L	A0,A2					;Points to block text.						<v1.4>
				Move.B	MPtag32-BlkData32(A2),-(SP)	;save flags of block							<v1.1>
				Move.L	D0,D1					;Save desired logical size.

				JSRROM		a32ActualS				;

				Move.L	D0,D3					;New physical size.

				JSRROM.S	a32GetSize 				;Get current logical size in D0.

				Cmp.L	D0,D1					;sNew = sCur?
				BEq 	@SSEqual				;Yes, return to caller.							<121>

				Move.L	A0,A2					;Points to block text.
				Sub.L	#BlkData32,A2 			;Point to block header.							<v1.1>
				Move.L	BlkSize32(A2),D2		;Get physical size.								<v1.1>

				Move.L	D2,D4					;Old physical size.

				Cmp.L	D2,D3					;sNAct = sCAct?

				BEq 	@SSLogical				;Yes, just set logical size.
				BCS 	@SSShrink				;sNAct < sCAct, shrink the block.

******************************** Start conditional block. ******************************** <18Apr85>

				IF		SmartSetSize THEN

; The block must be grown.																	<18Apr85>
; Registers: D0=D3=new phys size; D1=new log size; D2=D4=phys size; D5=??					<18Apr85>
;			 A0=text ptr; A1=handle; A2=block ptr; A3=??									<18Apr85>
; Across the code use registers:															<18Apr85>
;			 D0=tmp; D1=new log size; D2=D4=phys size; D3=new phys size; D5=delta size		<18Apr85>
;			 A0=tmp; A1=handle; 	  A2=block ptr;    A3=tmp								<18Apr85>
;																							<18Apr85>
; First, set up some registers and the GZ's.                                                <18Apr85>
				Move.L	D3,D5
				Sub.L	D2,D5					;delta physical size
				Move.L	A1,GZRootHnd			;record handle being sized
				Move.L	A0,GZRootPtr			;record pointer  "	   "

; In this loop, A3 steps across the blocks and D6 accumulates free space.					<18Apr85>
				MoveA.L A2,A3
				AddA.L	D4,A3					;next block after growing
				MoveQ	#0,D6					;initial accumulation
@SSAftFree
				CmpA.L	bkLim(A6),A3			;have we reached the heap end?
				BCC.S	@SSAFEnd 				;Carry Clear => beyond the end

				Tst.B	(A3)					;Eq => free block
				BNE.S	@SSAFEnd
				Add.L	BlkSize32(A3),D6		;accumulate free space						<v1.1>
				AddA.L	BlkSize32(A3),A3		;bump on to next block						<v1.1>
				BrA.S	@SSAftFree				;and continue looping
@SSAFEnd
; Detail: be sure to go on if exactly enough space is there -- for no sliding will be done! <18Apr85>
				Sub.L	D6,D5					;D5 := amount unrequited by free space at end
				BLS 	@SSAsUsual				;Lower or Same => enough space for easy growth!

; Provided the block is unlocked, relocatable, try coalescing free space from below, remembering	<18Apr85>
; the 'last' block to give a backward peek when A2 is reached.	The logic follows BFindS farily 	<18Apr85>
; closely.	Starting at the heap's beginning, outer loop skips over allocated blocks (watching      <18Apr85>
; for the one being grown);  when a free block is hit, the inner loop starts coalescing until		<18Apr85>
; allocated block (or growing one) is found.  The loop terminates with A0 pointing to the last		<18Apr85>
; free block found, and D0 equal to the amount of free space immmediately before the growing block. <18Apr85>
				Move.L	A1,D0
				BEq 	@SSAsUsual				;Eq => it's a ptr, cannot move
				Tst.B	(SP)					;remember, the flags were saved earlier
				BMi 	@SSAsUsual				;Mi => locked, cannot move

				LEA 	heapData(A6),A3 		;start with the first block
@CoalLoop
				CmpA.L	A2,A3
				BCC.S	@CoalFini				;Carry Clear => beyond growing pointer

				Tst.B	TagBC32(A3)				;												<v1.1>
				BEq.S	@CoalFree				;Eq => free block found							<v1.1>
				Move.L	BlkSize32(A3),D0		;get block size									<v1.1>
				AddA.L	D0,A3					;bump up to next block
				MoveQ	#0,D0					;mark 'no immediately preceeding free space'
				BrA.S	@CoalLoop
@CoalFree
				MoveA.L A3,A0					;start of free space
				MoveQ	#0,D0					;init accumulated free space
@CoalFLoop
				CmpA.L	allocPtr(A6),A3 		;is the rover at a disappearing block?			<23Apr85>
				BNE.S	@1						;NotEqual => no...								<23Apr85>
				Move.L	A0,allocPtr(A6) 		;don't let allocptr pt to nonexistent block     <23Apr85>
@1												;												<23Apr85>
				Add.L	BlkSize32(A3),D0		;accumulate free space							<v1.1>
				AddA.L	BlkSize32(A3),A3		;bump on to next block							<v1.1>
				Tst.B	TagBC32(A3)
				BEq.S	@CoalFLoop				;Eq => more free space!

				Clr.L	TagBC32(A0)				;clear 1st long word of block					<v1.1>
				Move.L	D0,BlkSize32(A0)			;update size of coalesced block				<v1.1>
				BrA.S	@CoalLoop				;continue with this non-free block
@CoalFini

; We exit the above loop with D0=free space immediately below growing block, A0 pointing	<18Apr85>
; to it.  If at least 1/4 of the unrequited space can be made up by sliding, DO IT. 		<18Apr85>
; In case of a slide: if the free space is within a few minFree's of the needed space,      <18Apr85>
; go the whole way, otherwise slide just enough to meet the needs.							<18Apr85>
; A special case arises: when D5 is tiny, a fourth is zero, and this is BAD news if D0 is	<18Apr85>
; also zero!  The test BLS (as opposed to BCS) catches this case along with tinies. 		<18Apr85>
; Yet another goof -- must bound unrequited size by minFree, since that's the size of block <18Apr85>
; of free block we'll make at the end.                                                      <18Apr85>
				Move.L	D5,D6					;unrequited space
				LSR.L	#2,D6					;1/4 of it
				Cmp.L	D6,D0
				BLS.S	@SSNoSlide				;Lower or Same => too little space free (or none available)


				MoveQ	#minFree32,D6 			;Lower bound for unrequited					<v1.2>
				Cmp.L	D5,D6
				BLS.S	@5						;Lower or Same => D5 big enough for slide
				Move.L	D6,D5					;Make at least minFree space...
@5
				MoveQ	#minFree32+minFree32,D6 ;unscientific slop							<v1.2>
				Add.L	D5,D6					;unrequited space + slop
				Cmp.L	D6,D0
				BCS.S	@SSFullSlide 			;Carry Set => not enough extra to split free space

; To do a partial slide, decrement the size of the lower block by the amount we'll slide.   <18Apr85>
				Sub.L	D5,D0					;Size minus amount of slide					<v1.1>
				Clr.L	TagBC32(A0)				;set free block								<v1.1>
				Move.L	D0,BlkSize32(A0)		;Force size of free block (don't need A0 now)<C883>
				AddA.L	D0,A0					;Target slot for growing block
				Move.L	D5,D0					;Size of slide, for 'sliding' into FullSlide

; Full slide code: D0=amt of slide; D4=size of sliding block; D6=tmp; A0=dst of slide;		<18Apr85>
; A1=handle to sliding block; A2=ptr to sliding block.	Be sure to update the handle!		<18Apr85>
; And after the block is moved, update GZRootPtr and allocPtr, since the latter may point	<18Apr85>
; to a nonexistent free block.																<18Apr85>
@SSFullSlide
				Move.L	A0,(A1) 				;new location for sliding/growing block
				Add.L	#blkData32,(A1)			;be sure handle points to text of block!!!! <v1.1>
				Move.B	(SP),MPtag32(A0)		;restore the tags from home on the stack	<v1.1>
				MoveM.L D0/A1,-(SP) 			;save amt of slide and handle

				CmpA.L	allocPtr(A6),A2 		;is the rover at the block we're moving?    <23Apr85>
				BNE.S	@10						;NotEqual => rover is elsewhere...			<23Apr85>
				Move.L	A0,allocPtr(A6) 		;point rover at new location				<23Apr85>
@10												;											<23Apr85>
				Exg 	A0,A2					;A0=src of growing block, A1=dst
				MoveA.L A2,A1					;dst, for blockmove
				Move.L	D4,D0					;current phys length is length of move!
;+++				BSr 	HBlockMove
				JSRROM 	HBlockMove

				MoveA.L A2,A0					;ptr to moved block
				AddA.L	D4,A0					;ptr just beyond -- to new free block
				Move.L	(SP)+,BlkSize32(A0) 	;stuff size of new free block				<v1.1>
				Clr.L	TagBC32(A0)				;free block									<v1.1>
				MoveA.L (SP)+,A1				;restore handle

				LEA 	blkData32(A2),A0			;text ptr to growing block
				Move.L	A0,GZRootPtr
				BrA.S	@SSAsUsual

; Our last resort: check the block following ours; if it's larger and allocated, don't even 	<18Apr85>
; bother trying to move it. 																	<18Apr85>
@SSNoSlide
				MoveA.L A2,A0
				AddA.L	D4,A0					;ptr to following block
				Move.L	BlkSize32(A0),D0		;get size										<v1.1>
				Cmp.L	D0,D3
				BCC.S	@SSAsUsual				;Carry Clear => new size is large, so go the normal route
				Tst.B	TagBC32(A0)
				BNE.S	@SSDoReloc				;Not Equal => larger, alloc block following

********************************* End conditional block. ******************************** <18Apr85>
				ENDIF	  ; SmartSetSize

; This resumes the original SetSize growth code.  The register setup must be adjusted to:		<18Apr85>
;		 D0=??; D1=new log size; D2=D4=phys size; D3=new phys size; D4=phy size; D5=??; D6=??	<18Apr85>
;		 A0=??; A1=handle;		 A2=block ptr;	  A3=?? 										<18Apr85>
@SSAsUsual
				Move.L	A2,A0					;Points to block header.
				Move.L	D3,D0					;New physical size.
				Sub.L	D2,D0					;Compute delta bytes.
				Add.L	D2,A2					;Point to where space is needed

												;  doesn't move it by accident.
				BSet	#Lock,MPtag32(A0)		;lock block									<v1.1>

				JSRROM 	a32MakeSpace			;Try making room after this block.

				BClr	#Lock,MPtag32(A0)		;Unlock block								<v1.1>
@200			Move.L	A2,D4					;Did we succeed?
				BNE.S	@SSEnough				;Yes, keep going

; New entry point to bypass MakeSpace when following block is bigger than one we're growing.    <18Apr85>
@SSDoReloc
				Move.L	A1,D4					;No, maybe we can relocate block.
				BEq.S	@SSFail					;No, block is Non-Relocatable.
				Tst.B	(SP)					;Can we move the growing block?
				BMi.S	@SSFail					;No, block is locked.
				Move.L	D1,D0					;Desired new logical size.


; Try to grow the (unlocked) block by relocating&growing simultaneously.  Across the call	<10Apr85>
; mark it nonpurgeable, since we WANT it!  Note must retrieve previous state from stack 	<10Apr85>
; unlike the BSet/BClr pair bracketing MakeSpace above.  To get here, the Lock bit must be	<10Apr85>
; clear, so the blithe BClr above jibes with our restoration from the stack.				<10Apr85>
				Move.L	(A1),A3					;dereference handle							<v1.1>
				BClr	#Purge,MPtag32-BlkData32(A3);Unlock block							<v1.1>
				JSRROM 	a32RelocRel				;Relocate the old block into a new.

				Move.L	(A1),A0					; get new address of block header			<121>
				Sub.L	#BlkData32,A0 			;Point to block header.						<121>

;				MOVE.B	(SP),MPtag32-BlkData32(A3)	;Restore previous state.				<v1.1>
				JSRROM	ClearGZStuff			;mark gz stuff as done
				BrA.S	@SSExit					;Return to caller.
@SSFail											;Unable to find space.
				JSRROM	ClearGZStuff			;mark gz stuff as done
				MoveQ	#memFullErr,D0			;Not enough room to reloc. block.
				BrA.S	@SSExit					;Return to caller.
@SSEnough										;Enough room has been found.
				JSRROM	ClearGZStuff			;mark gz stuff as done
				Move.L	BlkSize32(A2),D0		;Length of free space after.				<v1.1>
				Move.L	D0,D4					;Physical size of free space.
				Add.L	D2,D4					;Physical size of new combined blk.
				Move.L	A0,A2					;Points to block.
				Move.L	D4,BlkSize32(A2)			;set block physical size.				<v1.1>
;				Neg.L	D0						;Minus size of new space.
;				BSR.S	AdjustFree				;Account for less free space.
				JSRROM	SubtractFree			;Account for less free space.	<v1.7>
@SSShrink										;Shrink the block.
				Sub.L	D3,D4					;Number of bytes to shrink block.
				Cmp.L	#MinFree32,D4 			;sFree < MinFree?							<v1.2>
				BCS.S	@SSLogical				;Yes, set logical size only.
				BTST	#ROZ,flags(A6)			;don't shrink ROZ blocks                    <04Mar85>
				BNE.S	@SSSkip					;											<04Mar85>

				Move.L	A2,A0					;Points to block.
				Add.L	D3,A0					;Point to new free block.
				Move.L	D3,BlkSize32(A2)		;set block physical size.					<v1.1>
				Move.L	D4,D0					;Size of new free block.
				JSRROM	a32MakeBkF 				;Release free space.
				JSRROM	AdjustFree				;And account for new free space.
@SSLogical										;Set the logical size of the block.
				Move.L	A2,A0					;Points to block.
				Move.L	D1,D0					;New logical size.
				JSRROM	a32SetLogSize				;Set logical size.
@SSDone
				MoveQ	#0,D0					;Success result code.
@SSExit

;				Move.L	(A1),A3					;dereference handle							<v1.1>
;				Move.B	(SP)+,MPtag32-BlkData32(A3)	;Restore MP flag byte.					<v1.1>

				Move.B	(SP)+,MPtag32(A0)		;Restore MP flag byte.					<v1.1>
@SSFin
				MoveM.L (SP)+,D1-D6/A0-A3		;Restore registers. 						<18Apr85>
				RTS 							;Return to caller.
@SSSkip
				MoveQ	#memROZWarn,D0			;											<04Mar85>
				BRA.S	@SSExit					;											<04Mar85>
@SSEqual
				Move.B	(SP)+,D0				; Don't care about saved MP flag			<121>
				MoveQ	#0,D0					;Success result code.						<121>
				Bra.S	@SSFin					;											<121>

			ENDPROC
;________________________________________________________________________________
;
;	<68><85>  End of SetPtrSize() patch
;________________________________________________________________________________




;________________________________________________________________________
;
;	<54>	Rolled over changes from split-off sources on 4/16/90 by DDG
;
;	Patch To IOPMsgRequest Trap to Fix IOP Serial Driver Control Call Bug
;
;	Traps Patched:	IOPMsgRequest
;
;	The problem: IOP Serial Driver calls are being mis-queued because
;	the control rtn is jumping to IODone before the control calls are
;	actually completed on the 6502 side.
;
;	The fix: to make the patch small, and because the control calls call
;	the IOPMsgRequest trap, we do a come-from patch on that trap. If the
;	'come from' addresses match any of those in the driver, then the patch
;	code is exectued. Else the ROM code (or previous patch) is jumped to.
;	All the patch code does is jsr to the ROM code, then wait around for
;	the IOP request to have completed before returning.
;
;________________________________________________________________________
			proc
			export 	IOPMsgRequest
;offsets to ROM addresses
IOPControlNormal	EQU		$6B932
IOPControl08		EQU		$6B95A
IOPControl13		EQU		$6B9C2

			with	IOPRequestInfo
IOPMsgRequest

; We can use the new protection scheme, if the first two instructions in the	<115>
; patch are a bra.s followed by the jump to the old rom address.

			bra.s	@protection
@toRom
			BackToTrap	OldIOPMsgRequest					; no, then just execute ROM Code
@protection

			cmpRA	IOPControlNormal,OSTrapReturnAddressDepth(sp)	; from IOP serial drvr ctl call?
			beq.s	@doPatch										; yes, then come back here
			cmpRA	IOPControl08,OSTrapReturnAddressDepth(sp)
			beq.s	@doPatch
			cmpRA	IOPControl13,OSTrapReturnAddressDepth(sp)
			bne.s	@toRom

@doPatch	move.l	a0,-(sp)				; ROM IOPMsgRequest does not save a0
			bsr.s	@toRom					; bsr to IOPMsgRequest in ROM
			move.l	(sp)+,a0

@syncLoop	tst.b	irReqActive(a0)
			bne.s	@syncLoop
			rts

			endwith
			endproc

;_______________________________________________________________________________
;
;	<54>	End of Patch To IOPMsgRequest Trap to Fix IOP Serial Driver Control Call Bug
;_______________________________________________________________________________




;____________________________________________________________________________	GGD <28>
;	Patch the Deferred Task Manager Task Dispatcher to re-enable interrupts upon
;	exiting to fix QuickMail servers (for now at least), because they call through
;	jDisptch at application level and wind up with all interrupts being masked,
;	and the Task Dispatcher expects to only be called from then end of an interrupt
;	handler, which will restore the interrupt level via an RTE.  Note that Applications
;	should NOT be calling through this UNDOCUMENTED LOW MEMORY VECTOR, and we are
;	changing this just so QuickMail servers don't hang with interrupts disabled,
;	until CE Software can fix their bug.

NewvDisptch	proc	export
			JsrTrap	ROMvDisptch				; call the existing ROM code
			andi.w	#$F8FF,sr				; enable all interrupts
			rts								; all done
			endproc

;	End of Deferred Task Manager Task Dispatcher Patch Installation
;____________________________________________________________________________	GGD <28>

;____________________________________________________________________________	jwk <29>
;
;	BusErrHandler -- New and improved chaining SCSI bus error handler.
;		When the SCSI Mgr is performing a blind data transfer, it patches
;		out the bus error vector.  The old SCSI Mgr bus error handler
;		assumed that if it got called, it must be handling a SCSI bus error.
;		Unfortunately, NuBus cards could bus error while the SCSI Mgr is
;		installed.  To be a better bus error citizen, the SCSI bus error
;		handler now checks for a SCSI address as the fault address, and
;		chains to the bus error handler that it replaced.
;
BusErrHandler:	PROC	EXPORT

ROMBusErrRecovery	EQU		$00008a6c			; recovery delay routine in ROM				<29>

			move.l	d0,-(sp)					; save d0									<29>
			moveq.l	#$ffffff9c,d0				; mask = $ffffff9c							<start>
			and.l	4+$10(sp),d0				; clear variable bits of the fault address
			cmp.l	SCSIHsk,d0					; was it a SCSI chip access ?
			beq.s	@start						; if so, start processing the bus error

			move.l	(sp)+,d0					; restore d0
			move.l	OldBusErrVct(a6),-(sp)		; put old bus error handler addr on stack	<end>
			rts									; jump to old handler, assuming it'll RTE	<29>

@start

			subq.w	#1,BusErrCount(a6)			; retry until we get tired
			beq.s	CleanUp

			jmpROM	ROMBusErrRecovery			; back off and try again (RTE)				<29>

Cleanup
			addq.l	#4,sp						; throw away copy of d0 on stack			<29>

			move.w	(sp),d0						; get sr from stack
			bfextu	6(sp){0:4},d1				; get format code from stack
			cmp.b	#$0A,d1						; short exception frame?
			bne.s	Drop46w						; no, so use larger frame
			adda.w	#16*2,sp					; dispose of the 16-word frame
			bra.s	DummyFrame					;  and finish up
Drop46w
			add.w	#46*2,sp					; size of exception frame
DummyFrame
			;
			; Fake a format code 0 exception frame (4 words) to finish cleaning up
			;
			move.w	zeroReg,-(sp)				; format code 0
			pea		FinishErr					; PC value
			move.w	d0,-(sp)					; sr value
			rte									; 'return' from the fake exception

FinishErr
			moveq.l	#scBusTOErr,d0				; assume slow peripheral
			btst.b	#bPM,sBSR(a3)				; phase change?	<C478/10Dec86>		<v1.5><29>
			bne.s	@ErrorDone					; phase matches: slow peripheral
			moveq.l	#scPhaseErr,d0				; return phase change error
@ErrorDone
			rts

;
;	End of chaining SCSI bus error handler patch
;____________________________________________________________________________	jwk <29>

;_________________________________________________________________________________________	<119> djw
;	Beginning code for Quantum 7.9 ROM fix
;
;	Detailed description of the Quantum problem and solution:
;
;	Quantum drives with the firmware version 7.9, has a problem with loosing the last byte
;	of a block during a multi-block write.  The problem occurs when the time between blocks
;	written to the SCSI bus on the CPU side, is greater than 482 microseconds.  This may
;	occur in situations where there are a lot of interrupts.  When conditions are right and
;	the problem happens, the last byte of the previous block (in a multi-block transaction),
;	is "eaten" by the drive.  Any checksum or CRC calculated by the drive is correct,
;	because the drive calculates it after the byte has been corrupted.  This problem is
;	especially frequent when email packages are installed on the Mac, since they generate
;	a lot of interrupts which take a long time.  This problem only occurs during fast
;	writes in the SCSI manager (pseudo-dma mode).
;
;	The way the SCSI manager currently works is it gets a TIB packet which contains the
;	instructions on how to talk to a particular device.  Included in the TIB is when to
;	re-synchronize with the drive by waiting for a *REQ.  When we see *REQ, the SCSI
;	manager then begins the next TIB data transfer instruction and loads a byte of data
;	into the 53C80's output register.  After the first byte is "manually" sent, the
;	hardware handshaking automatically takes care of the *REQ and *ACK handshaking.  When
;	the TIB write transfer is complete, pseudo-dma is disable, which releases *ACK,
;	completing the handshake.  This allows the target to assert *REQ when it is ready.
;
;	The window of vulnerability is between the last byte of the previous block and the
;	first byte of the next block.  More correctly, it is between the rising edge of *ACK
;	and the falling edge of the next *ACK.  Because we release *ACK to synchronize, an
;	interrupt may come in and delay the next transfer.
;
;	The solution to the problem is to pre-load a data byte into the 53C80's data output
;	register before we release *ACK.  There are two ways of releasing *ACK: disable pseudo
;	dma, and write a byte to the data output register.  Leaving pseudo-dma enabled through
;	the entire TIB will mean that whenever a *REQ occurs, there will be data available in
;	the output register.  This means there will be no delay between bytes because the
;	hardware is not subject to interrupt delays.
;
;	This patch therefore involves patching the TIB interpreter and the fast write routine
;	in the SCSI manager.  There are five versions of the SCSI manager to patch: Mac Plus,
;	SE, Mac II, Portable, and IIci.
;
;_________________________________________________________________________________________
;	QuantumWBlindIIci  -  patch to NewSCSIWBlind
;
;	This code replaces the original NewSCSIWBlind entry point.  The new entry for blind
;	writes enables pseudo-dma on a per-transaction basis.  Pseudo-dma was previously
;	enabled only on a per-TIB-instruction basis.  We jump back into the ROM to the original
;	entry point to continue executing the TIB.
;
;	Input:	reg a3 = base of SCSI read addr
;				a6 = SCSI stack frame
;				d7 = zero
;
			Export	QuantumWBlindIIci
			Export	FastWriteFix

QuantumWBlindIIci

romNewSCSIWBlind	Equ		$07574				; rom offset to NewSCSIWBlind entry point

			move.b	d7,sTCR+WrOffs(a3)			; set to match data out phase (to zero)
			move.b	#iDMA,sMR+WrOffs(a3)		; enable DMA in mode register
			move.b	#iDB,sICR+WrOffs(a3)		; assert data bus in initiator command reg
			move.b	d7,sDMAtx+WrOffs(a3)		; start write DMA

;	Do I need to test for DRQ or *REQ at this point?

			jmp		([RomBase],romNewSCSIWBlind); continue at original entry pt in ROM



;_________________________________________________________________________________________
;	FastWriteFix  -  patch to FastWrite
;
;	This code replaces the low level data transfer routine for fast writes in the SCSI
;	manager.  It is rewritten to assume psuedo-dma is always on, and to do the device
;	synchronization (looking for *REQ and DRQ), after loading a data byte into the
;	output register of the 5380.  We don't have to worry about zero-byte transfers.  They
;	are filtered out in the calling routine (Transfer).
;
;	Entry:	d2	=	number of bytes to transfer
;			a1	=	addr of sBSR(a3) - by convention, and used by bus error handler
;			a2	=	ptr to data buffer to transfer
;			a3	=	base addr of NCR 53C80
;			a4	=	ptr to SCSI globals
;
;	Exit:	d1	=	number of bytes actually transfered.  This value is only good if
;					the transfer was good with no errors.  It is inaccurate when an
;					error aborts the transfer.

			With	scsiGlobalRecord

FastWriteFix

			move.l	hhsk5380(a4),a0			; point to addr for hardware handshaking
			adda.w	wrOffset(a4),a0			; add in write offset
			move.l	d2,d1					; save to return number of bytes transfered

;	Pre-load the NCR 53C80's output register with a byte of data.  If we are in
;	the middle of a multi-block write, *ACK is currently asserted.  Writing a byte
;	to the output register will release *ACK, completing the handshaking, allowing
;	the target to assert *REQ.  Is there a chance We do not need to check for DRQ at this point (to see
;	if the chip is ready for the next byte), because all data out routines always
;	wait to make sure the last byte got out.

			sub.l	#1,d2					; dec number of bytes to xfer
			move.b	(a2)+,(a0)				; write data byte to output register

;	With *ACK released, determine if the target is in sync.  We cannot look for
;	*REQ to be asserted, because the target may have already accepted the data byte
;	and released *REQ at this point.  We can sync on DRQ which will signal when
;	the NCR 53C80 is ready to accept a data byte, meaning a *REQ from the target
;	must have already occurred and our data byte was taken.

@syncWait
			btst.b	#bDMAR,(a1)				; check bus & status reg for DRQ
			bne.s	@doWrite				; DRQ present - sync-ed up so proceed
			btst.b	#bREQ,sCSR(a3)			; no DRQ - is *REQ present ?
			beq.s	@syncWait				; no *REQ yet - wait for sync
			btst.b	#bPM,(a1)				; with *REQ, check phase lines
			bne.s	@syncWait				; still in data out phase - wait
			moveq.l	#0,d1					; out of phase - did not xfer any bytes
			moveq.l	#scPhaseErr,d0			; return error
			bra.s	@Done					; exit

;	Perform the write to the SCSI chip.  First align the bytes to longs, then
;	align them to 32 byte chunks.  Transfer the bulk of the data in 32 byte
;	blocks.
;	Reg d2.l = number of bytes to move

@doWrite
			cmpi.l	#3,d2					; check for very short copy
			bls.s	@veryShort				; skip alignment if very short

			move.l	a2,d0					; get addr of data buffer
			andi.l	#$00000003,d0			; check for long word alignment
			beq.s	@Aligned				; if no alignment needed
			subq.l	#4,d0					; bias by 4 to get correct index
			jmp		@Aligned(d0.w*2)		; do the alignment
			move.b	(a2)+,(a0)				; move a byte
			move.b	(a2)+,(a0)				; move a byte
			move.b	(a2)+,(a0)				; move a byte
@Aligned
			add.l	d0,d2					; adjust the byte count (d0 = neg)
			move.l	d2,d4					; save tail byte count
			lsr.w	#2,d2					; adjust to number of longs to move
			moveq.l	#7,d0					; mask for starting index
			and.l	d2,d0					; number of long words to move first
			neg.w	d0						; negate to index backwards
			lsr.l	#3,d2					; number of 32 byte blocks to move
			move.l	d2,d3					; get number of 32*64K byte blks to move
			swap	d3						; count in low word
			jmp		@CopyStart(d0.w*2)		; jump into the loop

@CopyLoop	move.l	(a2)+,(a0)				; move a 32 byte block of data....
			move.l	(a2)+,(a0)				; ... 4 bytes at a time
			move.l	(a2)+,(a0)
			move.l	(a2)+,(a0)
			move.l	(a2)+,(a0)
			move.l	(a2)+,(a0)
			move.l	(a2)+,(a0)
			move.l	(a2)+,(a0)
@CopyStart	dbra	d2,@CopyLoop			; loop in chunks of 32 bytes
			dbra	d3,@CopyLoop			; loop in chunks of 32*64K bytes

			andi.l	#$00000003,d4			; check for tail alignment
			move.l	d4,d2					; d2 = number of bytes remaining

@veryShort
			neg.w	d2						; negate to index backwards
			jmp		@Remaining(d2.w*2)		; write remaining bytes
			move.b	(a2)+,(a0)				; move a byte
			move.b	(a2)+,(a0)				; move a byte
			move.b	(a2)+,(a0)				; move a byte
@Remaining

;	Before exiting this routine, make sure that the peripheral has actually accepted
;	the data byte.  Wait for a DRQ (meaning the SCSI chip is ready for another byte)
;	before exiting.

@DoneWait
			moveq.l	#0,d0					; set good return

			btst.b	#bDMAR,(a1)				; check for DRQ (a1 = sBSR(a3))
			bne.s	@Done					; if DRQ, peripheral got the byte
			btst.b	#bREQ,sCSR(a3)			; no DRQ - is *REQ present ?
			beq.s	@DoneWait				; no *REQ yet - wait for it
			btst.b	#bPM,(a1)				; are we still in phase ?
			bne.s	@DoneWait				; if so, keep waiting

@Done
			rts								; we're done

			Endp							; end scsi patches


;____________________________________________________________________________	 EH <33><37>
;
;	Patch To IOPMoveData Trap to Fix IOP Serial Driver DMA Hang Bug
;
;	Traps Patched:	IOPMoveData
;
;	The problem: the iop serial DMA hangs at if more than one byte
;	accumulates in the SCC fifo. This is really a problem with the
;	timing in the DMA hardware, but we'll work around it in software.
;
;	The fix: In the main driver loop, we'll manually remove extra
;	bytes from SCC fifo to DMA buffer before restarting the DMA.
;
;	Note:If one of these manually moved bytes is in error, it will be
;	bucketed (not moved to DMA buffer), as will subsequent bytes in the
;	fifo.
;
;	MECHANISM: To make the patch small, we do a come-from on IOPMoveData.
;	We use the ROM IOPMove Data to download the patches to the 6502 code
;	after we've already downloaded the unpatched image.
;
;	<37> added in two fixes.
;	Fix slow baud rate chars getting munched if a control call is made to
;	change the baud rate. Now we wait for an ALL SENT from the SCC before
;	dispatching all control calls.
;
;	Fix CTS status on open to be reported properly back to 68000 side.
;	We now properly set CTSFlag value during the open call, which is the
;	value that gets reported in the status call.
;
;	<123> added in external control call feature
;	--	Use bit 6 now of the CtlOptions byte in control call 16
;		bit 6 = 0 means internal clocking
;		bit 6 = 1 means external clocking
;	--	Incidentally, fixed bug in break handling code such that the null
;		char is now discarded when break is de-asserted.
;	--	changed ExtStatInt handler code to set bit 3 of Async Err if break is rcv'd.
;	--	changed InitSCC rtn to check for ext clocking in setting WR4 clock divide bits.
;		we also disable HWHS for the external clock case so we won't try to use the
;		CTS line for clocking AND handshaking.
;	--	changed the EXTInt handler to disable CTS interrupts if we receive them
;	   	too quickly. This was never implemented in the IOP driver.
; 		Note we are doing a slime-bucket thing here by using ZP addresses that the ROM
;		 driver isn't using. But it doesn't look like anybody's using it, so hey, what
; 		the living heck. ZPSize is 32, so we'll start our stuff at offset $33.
;			CTSCount = ZPBase+$33	 the count of CTS transitions we started timing
;			LastTime = ZPBase+$34	 the last timer value (low byte) for a CTS interrupt
;	--	Modify the Zero Page initialization to clear all $55 bytes we have
;
;	<126>
;	--	fix disable to HWHS for external clocking. it now gets disabled write before
;		CtlOptions (#16) calls DoInitSCC instead of in the InitSCC routine.
;	--	rolled in a fix to close that i had meant to add in <123>. We time out now
;		on waiting for the all-sent on the close.
;
;	<138>
;	--	fix the IOP timer to actually count! i think the code to disable CTS interrupts
;		was just working by chance, since i'm also fixing a branch instruction in
;		that code to fix the bug with printing to the imagewriter.
;________________________________________________________________________
IOPMoveDataPatch	proc
					export 	IOPMoveData

;offsets to ROM addresses
From_IOPOpenCall	EQU		$0006bC48		;return addr of IOPMoveData call in IOP Serial Open
ROM_IOPMoveData		EQU		$00004ed2		;rom addr for the trap

;Pic RAM addresses
DrvrAPicAddr		EQU		$2d55			; driver A start addr for Pic RAM
DrvrBPicAddr		EQU		$56aa			; driver B start addr for Pic RAM

numPatches			EQU		24				; number of times thru loop
PatchDrvrSize		EQU		$09ae			; size of the patched driver

;__________________________________________________________
;
; 6502 IOP Driver Patches -- code to fix in downloaded image.
; Patches are in order by offset from beginning of driver.
; Each set of patch bytes is preceded by a word offset to
; start of patch, and a byte for size of patch.
;
; There is one set of patches for Driver A and one for Driver B.
;__________________________________________________________
DrvrAFix

; changes zero page init to clear all $55 bytes
; this one-byte change is inline.
		dc.b	$00,$09				; offset to this patch
		dc.b	@a20end-@a20		; number patchbytes

@a20	dc.b	$55					; y<-$55, the index to clear out z-page

; fixes the new location of the driver buffers
; new buffer start addr is $3703 = $2d55(base) + $9ae(new offset)
@a20end	dc.b	$00,$46				; offset to this patch
		dc.b	@a1end-@a1			; number patchbytes

@a1		dc.b	$a9,$37				; lda #>Buffers (new high byte)
		dc.b	$a2,$03				; lda #>Buffers (new low byte)

; fix one byte to load into DMA count
@a1end	dc.b	$00,$94				; offset to this patch
		dc.b	@a2end-@a2			; number patchbytes

@a2		dc.b	$FB					; put FB in the DMA count instead of FF

; calls the fix to start the IOP timer since
; patch wouldn't fit inline
@a2end	dc.b	$00,$98				; offset to this patch									<138>
		dc.b	@a23end-@a23		; number patchbytes										<138>
									;														<138>
@a23	dc.b	$4C,$f8,$36			; jmp to fix at addr $36f8 = $2d55(base) +$9a3(offset)	<138>

; calls the fix to CTSFlag on Open (see patch at $8D5) since the
; patch wouldn't fit inline
@a23end	dc.b	$01,$00				; offset to this patch									<37>
		dc.b	@a3end-@a3			; number patchbytes										<37>
									;														<37>
@a3		dc.b	$4C,$2b,$36			; jmp to fix at addr $362B = $2d55(base) +$8D6(offset)	<37>

; calls the fix to DoPollEvent (see patch at $880) since the
; patch wouldn't fit inline
@a3end	dc.b	$01,$2F				; offset to this patch
		dc.b	@a4end-@a4			; number patchbytes

@a4		dc.b	$20,$D5,$35			; jsr to fix at address $2d55(base) +$880(offset)

; calls the fix to DMA code (see patch at $886) since the
; patch wouldn't fit inline
@a4end	dc.b	$01,$46				; offset to this patch
		dc.b	@a5end-@a5			; number patchbytes

@a5		dc.b	$F0,$03				; beq to just below
		dc.b	$4C,$db,$35			; jmp here if DMA was NOT stopped by interrupt rtn $2d55(base)+$886(offset)
		dc.b	$4C,$02,$36			; jmp here if DMA was stopped by interrupt rtn $2d55(base)+$8ad(offset)


; fix one byte to load into DMA count
@a5end	dc.b	$01,$6E				; offset to this patch
		dc.b	@a6end-@a6			; number patchbytes

@a6		dc.b	$FB					; put FB in the DMA count instead of FF

; calls patch to close to time-out on the all sent loop since the
; patch wouldn't fit inline
@a6end	dc.b	$02,$6F				; offset to this patch
		dc.b	@a21end-@a21		; number patchbytes

@a21	dc.b	$4C,$e0,$36			; jmp to fix at address $36e0 = $2d55(base) +$98b(offset)	<37>

; calls the fix to all sent in control calls (see patch at 8C6) since the						<37>
; patch wouldn't fit inline																		<37>
@a21end	dc.b	$03,$39				; offset to this patch										<37>
		dc.b	@a7end-@a7			; number patchbytes											<37>
									;															<37>
@a7		dc.b	$4C,$1b,$36			; jmp to fix at address $361b = $2d55(base) +$8C6(offset)	<37>

; calls patch to add ext clking to control call 16 since the
; patch wouldn't fit inline
@a7end	dc.b	$4,$4a			; offset to this patch
		dc.b	@a12end-@a12

@a12	dc.b	$4c,$38,$36		; jump to fix at address $3638= $2d55(base) + $8e3(offset)

; calls patch to disable CTS interrupts if we get them too fast since
; patch wouldn't fit inline
@a12end	dc.b	$07,$36			; offset to this patch
		dc.b	@a18end-@a18

@a18	dc.b	$4c,$b5,$36		; jump to fix at address $36b5= $2d55(base) + $960(offset)

; calls patch to set bit 3 of AsyncErr if break received since
; patch wouldn't fit inline
@a18end	dc.b	$07,$55			; offset to this patch
		dc.b	@a14end-@a14

@a14	dc.b	$4c,$82,$36		; jump to fix at address $3682= $2d55(base) + $92d(offset)		<126>

; calls patch to set clock divide bits for WR4 since
; patch wouldn't fit inline
@a14end	dc.b	$07,$79			; offset to this patch
		dc.b	@a16end-@a16

@a16	dc.b	$4c,$a1,$36		; jump to fix at address $36a1= $2d55(base) + $94c(offset)		<126>

; fixes the code at DoPollEvent to compare to DMA count,
; not the DMA address.
@a16end	dc.b	$08,$80				; offset to this patch
		dc.b	@a8end-@a8			; number patchbytes

@a8		dc.b	$AD,$23,$F0			; lda	DMACntLo
		dc.b	$C9,$FB				; cmp	#$FB
		dc.b	$60					; rts

; fixes DMA code to check for bytes left over in the SCC fifo
@a8end	dc.b	$08,$86				; offset to this patch
		dc.b	@a9end-@a9			; number patchbytes

@a9		dc.b	$AD,$22,$F0			;	lda DMA_AddrHi		Set up temp pointer
		dc.b	$85,$5A				;	sta TempBufPtr+1	into the DMA buffer. $55(base)+$05(offset)
		dc.b	$64,$59				;	stz TempBufPtr							 $55(base)+$04(offset)
		dc.b	$AC,$21,$F0			;	ldy DMA_AddrLo		Get the byte offset into buffer
									;@NxtChar
		dc.b	$AD,$41,$F0			;	lda SCC_Ctl			Read RRO
		dc.b	$29,$01				;	and #Rx_CharAvail	is there a receive char?
		dc.b	$F0,$2B				;	beq @Done			no chars, then we are done
		dc.b	$AD,$43,$F0			;	lda SCC_Data		get the data char
		dc.b	$91,$59				; 	sta (TempBufPtr),y	store char in buffer $55(base)+$04(offset)
		dc.b	$84,$7F				;	Sty	HoldDMACount						 $55(base)+$2a(offset)
		dc.b	$C8					;	iny
									; if any errors reset the scc
		dc.b	$A9,$01				;	lda #1				read RR1
		dc.b	$8D,$41,$F0			;	sta SCC_Ctl
		dc.b	$AD,$41,$F0			;	lda SCC_Ctl
		dc.b	$29,$70				;	and	#$70			parity, overrun, framing err?
		dc.b	$85,$5E				;	sta HoldRR1			save errors			 $55(base)+$09(offset)
		dc.b	$F0,$E3				; 	beq @NxtChar		no get the next char
									; Suppose Special Rx Int has turned off DMA.
									; There could be chars in FIFO after interrupt.
									; Driver only flags errors on last byte DMAd in.
									; To insure this, drop all bytes after error.
									; SHOULD BE FIXED WHEN DRIVER REVVED
									;@ResetSCC
		dc.b	$A9,$30				;	lda	#$30			send err reset to SCC
		dc.b	$8D,$41,$F0			;	sta	SCC_Ctl
		dc.b	$AD,$43,$F0			; 	lda	SCC_Data		flush SCC FIFO
		dc.b	$A9,$30				;	lda	#$30			send err reset to SCC
		dc.b	$8D,$41,$F0			;	sta	SCC_Ctl
		dc.b	$AD,$43,$F0			; 	lda	SCC_Data		flush SCC FIFO
		dc.b	$A9,$30				;	lda	#$30			send err reset to SCC
		dc.b	$8D,$41,$F0			;	sta	SCC_Ctl
									;@Done
		dc.b	$4C,$b0,$2E			;	jump back to our regularly scheduled code $2d55(base) +$15b(offset)

; fixes ctrl calls to wait for all sent from SCC before executing
@a9end	dc.b	$08,$C6				; offset to this patch
		dc.b	@a10end-@a10			; number patchbytes

									;@wait_more													<37>
@a10	dc.b	$78					;	sei					turn off interrupts					<37>
		dc.b	$A9,$01				;	lda	#$01			read RR1							<37>
		dc.b	$8D,$41,$F0			;	sta	SCC_Ctl												<37>
		dc.b	$AD,$41,$F0			; 	lda	SCC_Ctl												<37>
		dc.b	$58					;	cli					turn on interrupts					<37>
		dc.b	$6A					;	ror a				test the all sent bit, bit 0		<37>
		dc.b	$90,$F3				;	bcc	@wait_more											<37>
		dc.b	$7C,$33,$35			;	jmp	(ControlDispatch,x)									<37>
									;	ControlDispatch at $3533 = $2d55(base) + $7DE(offset)	<37>

; fixes ctrl calls to wait for all sent from SCC before executing								<37>
@a10end	dc.b	$08,$D6				; offset to this patch										<37>
		dc.b	@a11end-@a11		; number patchbytes											<37>
									;															<37>
									; ctsFlag = 0 on input. Acc holds RRO value 				<37>
@a11	dc.b	$29,$A0				;	and #$A0			isolate DTR and break bits			<37>
		dc.b	$85,$58				;	sta	holdRR0			$55(base) + $17(offset)				<37>
		dc.b	$29,$20				;	and	#$20			is DTR asserted?					<37>
		dc.b	$F0,$02				; 	beq	@1				yes, then CTSFlag stays 0			<37>
		dc.b	$C6,$6C				;	dec CTSFlag			no, then CTSFlag goes to $FF CTSFlag at $55(base) + $17(offset)
		dc.b	$4C,$59,$2E			;@1	jmp backToCode at 	$2e59 = $2d55(base) + $104 offset	<37>

; adds external clocking control into bit 6 of the
; CtlOptions byte for control call 16
@a11end	dc.b	$08,$e3			; offset to this patch
		dc.b	@a13end-@a13	; number of patchbytes

@a13	dc.b	$a5,$73			;lda CtlOptions		 get old clk bit				$55(base)+$1e(offset)
		dc.b	$29,$40			;and #clkMsk         bit 6
		dc.b	$aa				;tax
		dc.b	$ad,$84,$02		;lda C16_CtlOptions	 get new byte					$200(base)+$80(msg#)+$4(offset)
		dc.b	$a8				;tay
		dc.b	$29,$40			;and #clkMsk         bit 6
		dc.b	$85,$73			;sta CtlOptions										$55(base)+$1e(offset)
		dc.b	$8a				;txa
		dc.b	$c5,$73			;cmp CtlOptions		 is old clock bit same as new?	$55(base)+$1e(offset)
		dc.b	$d0,$05			;bne @switchIt		 nope, switch clk mode
		dc.b	$84,$73			;@out sty CtlOptions		 store new byte			$55(base)+$1e(offset)
		dc.b	$4c,$7f,$30		;jmp DoControlEvent_Return							$2d55(base) +$32a(offset)

		dc.b	$98				;@switchIt  tya
		dc.b	$0a				;asl 				 shift into minus bit
		dc.b	$30,$14			;bmi @ext

		dc.b	$a9,$50			;@int lda #intClkSrc  set int clk params
		dc.b	$8d,$17,$35		;sta WR11_Data										$2d55(base) +$7c2(offset)
		dc.b	$a9,$01			;lda #BRGEnbl
		dc.b	$8d,$1d,$35		;sta WR14_Data										$2d55(base) +$7c8(offset)
		dc.b	$ad,$0d,$35		;lda WR4_data	  	  set clock divide to 16		$2d55(base) +$7b8(offset)
		dc.b	$09,$40			;ora #dvd16Msk		  clock divide bit is bit 6
		dc.b	$8d,$0d,$35		;sta WR4_data		  in WR4						$2d55(base) +$7b8(offset)
		dc.b	$80,$12			;bra @load

		dc.b	$a9,$28			;@ext lda #extClkSrc  set ext clk params
		dc.b	$8d,$17,$35		;sta WR11_Data										$2d55(base) +$7c2(offset)
		dc.b	$a9,$00			;lda #BRGDsbl
		dc.b	$8d,$1d,$35		;sta WR14_Data										$2d55(base) +$7c8(offset)
		dc.b	$ad,$0d,$35		;lda WR4_data	  	  set clock divide to one		$2d55(base) +$7b8(offset)
		dc.b	$29,$BF			;and #dvdOneMsk		  clock divide bit is bit 6
		dc.b	$8d,$0d,$35		;sta WR4_data		  in WR4						$2d55(base) +$7b8(offset)

		dc.b	$5a				;@load	phy				; save the control byte
		dc.b	$64,$63			;stz HWHSenable		disable hardware handshaking 	$55(base)+$0e(offset) <126>
		dc.b	$20,$f4,$34		;jsr DoInitSCC										$2d55(base) +$79f(offset)
		dc.b	$7a				;ply
		dc.b	$80,$c8			;bra @out											<126>

; patch to set bit 3 of AsyncErr if break received
@a13end	dc.b	$09,$2d			; offset to this patch								<126>
		dc.b	@a15end-@a15	; number of patchbytes

@a15	dc.b	$8a				;txa				a=changed bits
		dc.b	$30,$03			;bmi @change		break changed
		dc.b	$4c,$ad,$34		;@done	jmp	ExtStatEnd								$2d55(base) +$758(offset)
		dc.b	$a5,$58			;@change lda LastRRO get break value				$55(base)+$03(offset)
		dc.b	$30,$05			;bmi @post			break was set
		dc.b	$ad,$43,$f0		;lda SCC_data		break unset, discard null
		dc.b	$80,$f4			;bra @done
		dc.b	$a9,$08			;@post	lda #$08	set bit 3
		dc.b	$24,$67			;bit ResetAsyncErr	has host read stats				$55(base)+$12(offset)
		dc.b	$10,$04			;bpl @unread
		dc.b	$64,$68			;stz AsyncErr										$55(base)+$13(offset)
		dc.b	$64,$67			;stz ResetAsyncErr									$55(base)+$12(offset)
		dc.b	$05,$68			;@unread ora AsyncErr								$55(base)+$13(offset)
		dc.b	$85,$68			;sta AsyncErr										$55(base)+$13(offset)
		dc.b	$80,$e4			;bra @done

; patch to set clock divide bits for WR4 and disable HWHS for ext clock
@a15end	dc.b	$09,$4c			; offset to this patch								<126>
		dc.b	@a17end-@a17	; number of patchbytes

								;acc=%0400xxxx default to divide-by-16
@a17	dc.b	$da				;phx				save reg
		dc.b	$aa				;tax 				save acc
		dc.b	$a5,$73			;lda CtlOptions		are we ext clk'd? $55(base)+$1e(offset)
		dc.b	$0a				;asl				shift ext clk bit into minus bit
		dc.b	$30,$03			;bmi @ext			yes, go fix clk dvd bits and disable HWHS
		dc.b	$8a				;@int txa			no, just restore acc
		dc.b	$80,$03			;bra @done											<126>
		dc.b	$8a				;@ext txa			restore acc
		dc.b	$29,$0f			;and #$0f			fix clk dvd bits to div-by-one
;		dc.b	$64,$63			;stz HWHSenable		disable hardware handshaking 	$55(base)+$0e(offset)<126>
		dc.b	$fa				;@done plx			restore reg
		dc.b	$8d,$0d,$35		;sta WR4_Data		and write out WR4 value			$2d55(base) +$7b8(offset)
		dc.b	$4c,$d1,$34		;jmp FinishInitSCC	and finish up					$2d55(base) +$77c(offset)

; patch to disable CTS interrupts if we get them too fast
@a17end	dc.b	$09,$60			; offset to this patch
		dc.b	@a19end-@a19	; number of patchbytes

@a19	dc.b	$a5,$88			;lda CTSCount		 exceeded 5 transitions in 1 ms? $55(base)+$33(offset)
		dc.b	$c9,$05			;cmp #5
		dc.b	$90,$0c			;bcc @fixTime		 no, then fix the time

		dc.b	$a9,$0f			;lda #15			 yes, then disable CTS interrupts
		dc.b	$8d,$41,$f0		;sta SCC_Ctl		 write to WR15
		dc.b	$a9,$80			;lda #$80			 bit 5 clear to disable CTS ints
		dc.b	$8d,$41,$f0		;sta SCC_Ctl

		dc.b	$80,$12			;bra @out			 go finish in ROM

								;@fixTime
		dc.b	$a5,$89			;lda LastTime	 	 get last count (remember it's a countdown timer)
		dc.b	$ed,$11,$f0		;sbc TimerCounterH	 time elasped > threshold?			$55(base)+$34(offset)
		dc.b	$c9,$08			;cmp #threshold		 threshold is 1 msÅ 8 ticks
		dc.b	$90,$07			;bcc @update		 no, just increment					<138>

		dc.b	$ad,$11,$f0		;lda TimerCounterH	 yes, set new last time
		dc.b	$85,$89			;sta LastTime											$55(base)+$34(offset)
		dc.b	$64,$88			;stz CTSCount		 and restart count					$55(base)+$33(offset)

								;@update			 inc the transition count
		dc.b	$e6,$88			;inc CTSCount											$55(base)+$33(offset)

								;@out
		dc.b	$64,$6c			;stz CTSFlag		 do stuff we stomped on in overpatch $55(base)+$17(offset)
		dc.b	$a5,$58			;lda RRO												 $55(base)+$03(offset)
		dc.b	$4c,$8f,$34		;jmp BackToROM		 finish up in ROM					 $2d55(base) +$73a(offset)

; patch to close to time-out on the all sent loop
@a19end	dc.b	$09,$8b			; offset to this patch
		dc.b	@a22end-@a22	; number of patchbytes

@a22	dc.b	$a5,$FF			;ldx #$FF		 	load up $FFFF for timeout loop
		dc.b	$c9,$FF			;ldy #$FF			24 cycles * .5 us/cycle * 64K Å .8 seconds

		dc.b	$a9,$01			;@loop lda #1		read from RR1
		dc.b	$8d,$41,$f0		;sta SCC_Ctl
		dc.b	$ad,$41,$f0		;lda SCC_Ctl
		dc.b	$6a				;ror				get all sent bit in carry
		dc.b	$b0,$06			;bcs @done			if allsent, then outta here

		dc.b	$ca				;dex				not allsent, so keep waiting
		dc.b	$d0,$f2			;bne @loop
		dc.b	$88				;dey
		dc.b	$d0,$ef			;bne @loop
		dc.b	$4c,$cf,$2f		;@done jumpBacktoClose 				$2d55(base) +$27a(offset)

; patch to start the IOP timer
@a22end	dc.b	$09,$a3			; offset to this patch
		dc.b	@a24end-@a24	; number of patchbytes

@a24	dc.b	$9c,$24,$f0		;stz DMA_CntHi		do code we stomped with patch
		dc.b	$a9,$ff			;lda #$FF
		dc.b	$8d,$11,$f0		;sta TimerCounterH	get the timer started (just need to write to it)
		dc.b	$4c,$f0,$2d		;@done jumpBacktoOpen 				$2d55(base) +$09b(offset)


@a24end	dc.w	0				; filler


DrvrBFix


; changes zero page init to clear all $55 bytes
; this one-byte change is inline.
		dc.b	$00,$09				; offset to this patch
		dc.b	@b20end-@b20		; number patchbytes

@b20	dc.b	$55					; y<-$55, the index to clear out z-page

; fixes the new location of the driver buffers
; new buffer start addr is $604d = $56aa(base) + $9a3(new offset)
@b20end	dc.b	$00,$46				; offset to this patch
		dc.b	@b1end-@b1			; number patchbytes

@b1		dc.b	$a9,$60				; lda #>Buffers (new high byte)
		dc.b	$a2,$4d				; lda #>Buffers (new low byte)

; fix one byte to load into DMA count
@b1end	dc.b	$00,$94				; offset to this patch
		dc.b	@b2end-@b2			; number patchbytes

@b2		dc.b	$FB					; put FB in the DMA count instead of FF

; calls the fix to start the IOP timer since
; patch wouldn't fit inline
@b2end	dc.b	$00,$98				; offset to this patch									<138>
		dc.b	@b23end-@b23		; number patchbytes										<138>
									;														<138>
@b23	dc.b	$4C,$4d,$60			; jmp to fix at addr $604d = $56aa(base) +$9a3(offset)	<138>

; calls the fix to CTSFlag on Open (see patch at $8D5) since the
; patch wouldn't fit inline
@b23end	dc.b	$01,$00				; offset to this patch										<37>
		dc.b	@b3end-@b3			; number patchbytes											<37>
									;															<37>
@b3		dc.b	$4c,$80,$5F			; jmp to fix at addr $5F80 = $56aa(base) +$8D6(offset)		<37>

; calls the fix to DoPollEvent (see patch at $880) since the
; patch wouldn't fit inline
@b3end	dc.b	$01,$2F				; offset to this patch
		dc.b	@b4end-@b4			; number patchbytes

@b4		dc.b	$20,$2a,$5F			; jsr to fix at address $56aa(base) +$880(offset)

; calls the fix to DMA code (see patch at 886) since the
; patch wouldn't fit inline
@b4end	dc.b	$01,$46				; offset to this patch
		dc.b	@b5end-@b5			; number patchbytes

@b5		dc.b	$F0,$03				; beq to just below
		dc.b	$4C,$30,$5F			; jmp here if DMA was NOT stopped by interrupt rtn $56aa(base)+$886(offset)
		dc.b	$4C,$57,$5F			; jmp here if DMA was stopped by interrupt rtn $56aa(base)+$8ad(offset)

; fix one byte to load into DMA count
@b5end	dc.b	$01,$6E				; offset to this patch
		dc.b	@b6end-@b6			; number patchbytes

@b6		dc.b	$FB					; put FB in the DMA count instead of FF

; calls patch to close to time-out on the all sent loop since the
; patch wouldn't fit inline
@b6end	dc.b	$02,$6F				; offset to this patch
		dc.b	@b21end-@b21		; number patchbytes

@b21	dc.b	$4C,$35,$60			; jmp to fix at address $6035 = $56aa(base) +$98b(offset)	<37>

; calls the fix to all sent in control calls (see patch at 8C6) since the						<37>
; patch wouldn't fit inline																		<37>
@b21end	dc.b	$03,$39				; offset to this patch										<37>
		dc.b	@b7end-@b7			; number patchbytes											<37>
									;															<37>
@b7		dc.b	$4C,$70,$5F			; jmp to fix at address $5F70 = $56aa(base) +$8C6(offset)	<37>

; calls patch to add ext clking to control call 16 since the
; patch wouldn't fit inline
@b7end	dc.b	$4,$4a			; offset to this patch
		dc.b	@b12end-@b12

@b12	dc.b	$4c,$8d,$5f		; jump to fix at address $5f8d= $56aa(base) + $8e3(offset)

; calls patch to disable CTS interrupts if we get them too fast since
; patch wouldn't fit inline
@b12end	dc.b	$07,$36			; offset to this patch
		dc.b	@b18end-@b18

@b18	dc.b	$4c,$0a,$60		; jump to fix at address $600a= $56aa(base) + $960(offset)

; calls patch to set bit 3 of AsyncErr if break received since
; patch wouldn't fit inline
@b18end	dc.b	$07,$55			; offset to this patch
		dc.b	@b14end-@b14

@b14	dc.b	$4c,$d7,$5f		; jump to fix at address $5fd7= $56aa(base) + $92d(offset)

; calls patch to set clock divide bits for WR4 since
; patch wouldn't fit inline
@b14end	dc.b	$07,$79			; offset to this patch
		dc.b	@b16end-@b16

@b16	dc.b	$4c,$f6,$5f		; jump to fix at address $5ff6= $56aa(base) + $94c(offset)

; fixes the code at DoPollEvent to compare to DMA count,
; not the DMA address.
@b16end	dc.b	$08,$80				; offset to this patch
		dc.b	@b8end-@b8			; number patchbytes


@b8		dc.b	$AD,$2B,$F0			; lda	DMACntLo
		dc.b	$C9,$FB				; cmp	#$FB
		dc.b	$60					; rts

; fixes DMA code to check for bytes left over in the SCC fifo
@b8end	dc.b	$08,$86				; offset to this patch
		dc.b	@b9end-@b9			; number patchbytes

@b9		dc.b	$AD,$2A,$F0			;	lda DMA_AddrHi		Set up temp pointer
		dc.b	$85,$AF				;	sta TempBufPtr+1	into the DMA buffer.		$aa(base)+$05(offset)
		dc.b	$64,$AE				;	stz TempBufPtr									$aa(base)+$04(offset)
		dc.b	$AC,$29,$F0			;	ldy DMA_AddrLo		Get the byte offset into buffer
									;@NxtChar
		dc.b	$AD,$40,$F0			;	lda SCC_Ctl			Read RRO
		dc.b	$29,$01				;	and #Rx_CharAvail	is there a receive char?
		dc.b	$F0,$2B				;	beq @Done			no chars, then we are done
		dc.b	$AD,$42,$F0			;	lda SCC_Data		get the data char
		dc.b	$91,$AE				; 	sta (TempBufPtr),y	store char in buffer		$aa(base)+$04(offset)
		dc.b	$84,$D4				;	Sty	HoldDMACount								$aa(base)+$2a(offset)
		dc.b	$C8					;	iny
									; if any errors reset the scc
		dc.b	$A9,$01				;	lda #1				read RR1
		dc.b	$8D,$40,$F0			;	sta SCC_Ctl
		dc.b	$AD,$40,$F0			;	lda SCC_Ctl
		dc.b	$29,$70				;	and	#$70			parity, overrun, framing err?
		dc.b	$85,$B3				;	sta HoldRR1			save errors					$aa(base)+$09(offset)
		dc.b	$F0,$E3				; 	beq @NxtChar		no get the next char
									; Suppose Special Rx Int has turned off DMA.
									; There could be chars in FIFO after interrupt.
									; Driver only flags errors on last byte DMAd in.
									; To insure this, drop all bytes after error.
									; SHOULD BE FIXED WHEN DRIVER REVVED
									;@ResetSCC
		dc.b	$A9,$30				;	lda	#$30			send err reset to SCC
		dc.b	$8D,$40,$F0			;	sta	SCC_Ctl
		dc.b	$AD,$42,$F0			; 	lda	SCC_Data		flush SCC FIFO
		dc.b	$A9,$30				;	lda	#$30			send err reset to SCC
		dc.b	$8D,$40,$F0			;	sta	SCC_Ctl
		dc.b	$AD,$42,$F0			; 	lda	SCC_Data		flush SCC FIFO
		dc.b	$A9,$30				;	lda	#$30			send err reset to SCC
		dc.b	$8D,$40,$F0			;	sta	SCC_Ctl
									;@Done
		dc.b	$4C,$05,$58			;	jump back to our regularly scheduled code $56aa(base) +$15B(offset)

; fixes ctrl calls to wait for all sent from SCC before executing								<37>
@b9end	dc.b	$08,$C6				; offset to this patch										<37>
		dc.b	@b10end-@b10		; number patchbytes											<37>
									;															<37>
									;@wait_more													<37>
@b10	dc.b	$78					;	sei					turn off interrupts					<37>
		dc.b	$A9,$01				;	lda	#$01			read RR1							<37>
		dc.b	$8D,$40,$F0			;	sta	SCC_Ctl												<37>
		dc.b	$AD,$40,$F0			; 	lda	SCC_Ctl												<37>
		dc.b	$58					;	cli					turn on interrupts					<37>
		dc.b	$6A					;	ror a				test the all sent bit, bit 0		<37>
		dc.b	$90,$F3				;	bcc	@wait_more											<37>
		dc.b	$7C,$88,$5E			;	jmp	(ControlDispatch,x)									<37>
									;	ControlDispatch at $5E88 = $56aa(base) + $7DE(offset)	<37>

; fixes ctrl calls to wait for all sent from SCC before executing								<37>
@b10end	dc.b	$08,$D6				; offset to this patch										<37>
		dc.b	@b11end-@b11		; number patchbytes											<37>
									;															<37>
									; ctsFlag = 0 on input. Acc holds RRO value 				<37>
@b11	dc.b	$29,$A0				;	and #$A0			isolate DTR and break bits			<37>
		dc.b	$85,$AD				;	sta	holdRR0			$aa(base) + $17(offset)				<37>
		dc.b	$29,$20				;	and	#$20			is DTR asserted?					<37>
		dc.b	$F0,$02				; 	beq	@1				yes, then CTSFlag stays 0			<37>
		dc.b	$C6,$C1				;	dec CTSFlag			no, then CTSFlag goes to $FF CTSFlag at $aa(base) + $17(offset)
		dc.b	$4C,$AE,$57			;@1	jmp backToCode at 	$57AE = $56aa(base) + $104 offset	<37>

; adds external clocking control into bit 6 of the
; CtlOptions byte for control call 16
@b11end	dc.b	$08,$e3			; offset to this patch
		dc.b	@b13end-@b13	; number of patchbytes

@b13	dc.b	$a5,$c8			;lda CtlOptions		 get old clk bit				$aa(base)+$1e(offset)
		dc.b	$29,$40			;and #clkMsk         bit 6
		dc.b	$aa				;tax
		dc.b	$ad,$e4,$02		;lda C16_CtlOptions	 get new byte					$200(base)+$e0(msg#)+$04
		dc.b	$a8				;tay
		dc.b	$29,$40			;and #clkMsk         bit 6
		dc.b	$85,$c8			;sta CtlOptions										$aa(base)+$1e(offset)
		dc.b	$8a				;txa
		dc.b	$c5,$c8			;cmp CtlOptions		 is old clock bit same as new?	$aa(base)+$1e(offset)
		dc.b	$d0,$05			;bne @switchIt		 nope, switch clk mode
		dc.b	$84,$c8			;@out sty CtlOptions		 store new byte			$aa(base)+$1e(offset)
		dc.b	$4c,$d4,$59		;jmp DoControlEvent_Return							$56aa(base) +$32a(offset)

		dc.b	$98				;@switchIt  tya
		dc.b	$0a				;asl 				 shift into minus bit
		dc.b	$30,$14			;bmi @ext

		dc.b	$a9,$50			;@int lda #intClkSrc  set int clk params
		dc.b	$8d,$6c,$5e		;sta WR11_Data										$56aa(base) +$7c2(offset)
		dc.b	$a9,$01			;lda #BRGEnbl
		dc.b	$8d,$72,$5e		;sta WR14_Data										$56aa(base) +$7c8(offset)
		dc.b	$ad,$62,$5e		;lda WR4_data	  	  set clock divide to 16		$56aa(base) +$7b8(offset)
		dc.b	$09,$40			;ora #dvd16Msk		  clock divide bit is bit 6
		dc.b	$8d,$62,$5e		;sta WR4_data		  in WR4						$56aa(base) +$7b8(offset)
		dc.b	$80,$12			;bra @load

		dc.b	$a9,$28			;@ext lda #extClkSrc  set ext clk params
		dc.b	$8d,$6c,$5e		;sta WR11_Data										$56aa(base) +$7c2(offset)
		dc.b	$a9,$00			;lda #BRGDsbl
		dc.b	$8d,$72,$5e		;sta WR14_Data										$56aa(base) +$7c8(offset)
		dc.b	$ad,$62,$5e		;lda WR4_data	  	  set clock divide to one		$56aa(base) +$7b8(offset)
		dc.b	$29,$BF			;and #dvdOneMsk		  clock divide bit is bit 6
		dc.b	$8d,$62,$5e		;sta WR4_data		  in WR4						$56aa(base) +$7b8(offset)

		dc.b	$5a				;@load	phy				; save the control byte
		dc.b	$64,$b8			;stz HWHSenable		disable hardware handshaking 	$aa(base)+$0e(offset)
		dc.b	$20,$49,$5e		;jsr DoInitSCC										$56aa(base) +$79f(offset)
		dc.b	$7a				;ply
		dc.b	$80,$c8			;bra @out

; patch to set bit 3 of AsyncErr if break received
@b13end	dc.b	$09,$2d			; offset to this patch
		dc.b	@b15end-@b15	; number of patchbytes

@b15	dc.b	$8a				;txa				a=changed bits
		dc.b	$30,$03			;bmi @change		break changed
		dc.b	$4c,$02,$5e		;@done	jmp	ExtStatEnd								$56aa(base) +$758(offset)
		dc.b	$a5,$ad			;@change lda LastRRO get break value				$aa(base)+$03(offset)
		dc.b	$30,$05			;bmi @post			break was set
		dc.b	$ad,$42,$f0		;lda SCC_Data		break unset, discard null
		dc.b	$80,$f4			;bra @done
		dc.b	$a9,$08			;@post	lda #$08	set bit 3
		dc.b	$24,$bc			;bit ResetAsyncErr	has host read stats				$aa(base)+$12(offset)
		dc.b	$10,$04			;bpl @unread
		dc.b	$64,$bd			;stz AsyncErr										$aa(base)+$13(offset)
		dc.b	$64,$bc			;stz ResetAsyncErr									$aa(base)+$12(offset)
		dc.b	$05,$bd			;@unread ora AsyncErr								$aa(base)+$13(offset)
		dc.b	$85,$bd			;sta AsyncErr										$aa(base)+$13(offset)
		dc.b	$80,$e4			;bra @done

; patch to set clock divide bits for WR4 and disable HWHS for external clocking
@b15end	dc.b	$09,$4c			; offset to this patch
		dc.b	@b17end-@b17	; number of patchbytes

								;acc=%0400xxxx default to divide-by-16
@b17	dc.b	$da				;phx				save reg
		dc.b	$aa				;tax 				save acc
		dc.b	$a5,$c8			;lda CtlOptions		are we ext clk'd? 				$aa(base)+$1e(offset)
		dc.b	$0a				;asl				shift ext clk bit into minus bit
		dc.b	$30,$03			;bmi @ext			yes, go fix clk dvd bits
		dc.b	$8a				;@int txa			no, just restore acc
		dc.b	$80,$03			;bra @done
		dc.b	$8a				;@ext txa			restore acc
		dc.b	$29,$0f			;and #$0f			fix clk dvd bits to div-by-one
;		dc.b	$64,$b8			;stz HWHSenable		disable hardware handshaking 	$aa(base)+$0e(offset)
		dc.b	$fa				;@done plx			restore reg
		dc.b	$8d,$62,$5e		;sta WR4_Data		and write out WR4 value			$56aa(base) +$7b8(offset)
		dc.b	$4c,$26,$5e		;jmp FinishInitSCC	and finish up					$56aa(base) +$77c(offset)


; patch to disable CTS interrupts if we get them too fast
@b17end	dc.b	$09,$60			; offset to this patch
		dc.b	@b19end-@b19	; number of patchbytes

@b19	dc.b	$a5,$dd			;lda CTSCount		 exceeded 5 transitions in 1 ms? $aa(base)+$33(offset)
		dc.b	$c9,$05			;cmp #5
		dc.b	$90,$0c			;bcc @fixTime		 no, then fix the time

		dc.b	$a9,$0f			;lda #15			 yes, then disable CTS interrupts
		dc.b	$8d,$40,$f0		;sta SCC_Ctl		 write to WR15
		dc.b	$a9,$80			;lda #$80			 bit 5 clear to disable CTS ints
		dc.b	$8d,$40,$f0		;sta SCC_Ctl

		dc.b	$80,$12			;bra @out			 go finish in ROM

								;@fixTime
		dc.b	$a5,$de			;lda LastTime	 	 get last count (remember it's a countdown timer) $aa(base)+$34(offset)
		dc.b	$ed,$11,$f0		;sbc TimerCounterH	 time elasped > threshold?
		dc.b	$c9,$08			;cmp #threshold		 threshold is 1 msÅ 8 ticks
		dc.b	$90,$07			;bcc @update		 no, just increment					<138>

		dc.b	$ad,$11,$f0		;lda TimerCounterH	 yes, set new last time
		dc.b	$85,$de			;sta LastTime											$aa(base)+$34(offset)
		dc.b	$64,$dd			;stz CTSCount		 and restart count					$aa(base)+$33(offset)

								;@update			 inc the transition count
		dc.b	$e6,$dd			;inc CTSCount											$aa(base)+$33(offset)

								;@out
		dc.b	$64,$c1			;stz CTSFlag		 do stuff we stomped on in overpatch $aa(base)+$17(offset)
		dc.b	$a5,$ad			;lda RRO												 $aa(base)+$03(offset)
		dc.b	$4c,$e4,$5d		;jmp BackToROM		 finish up in ROM					 $56aa(base) +$73a(offset)

; patch to close to time-out on the all sent loop
@b19end	dc.b	$09,$8b			; offset to this patch
		dc.b	@b22end-@b22	; number of patchbytes

@b22	dc.b	$a5,$FF			;ldx #$FF		 	load up $FFFF for timeout loop
		dc.b	$c9,$FF			;ldy #$FF			24 cycles * .5 us/cycle * 64K Å .8 seconds

		dc.b	$a9,$01			;@loop lda #1		read from RR1
		dc.b	$8d,$40,$f0		;sta SCC_Ctl
		dc.b	$ad,$40,$f0		;lda SCC_Ctl
		dc.b	$6a				;ror				get all sent bit in carry
		dc.b	$b0,$06			;bcs @done			if allsent, then outta here

		dc.b	$ca				;dex				not allsent, so keep waiting
		dc.b	$d0,$f2			;bne @loop
		dc.b	$88				;dey
		dc.b	$d0,$ef			;bne @loop
		dc.b	$4c,$24,$59		;@done jumpBacktoClose 									$56aa(base) +$27a(offset)


; patch to start the IOP timer
@b22end	dc.b	$09,$a3			; offset to this patch
		dc.b	@b24end-@b24	; number of patchbytes

@b24	dc.b	$9c,$2c,$f0		;stz DMA_CntHi		do code we stomped with patch
		dc.b	$a9,$ff			;lda #$FF
		dc.b	$8d,$11,$f0		;sta TimerCounterH	get the timer started (just need to write to it)
		dc.b	$4c,$45,$57		;@done jumpBacktoOpen 				$56aa(base) +$09b(offset)


@b24end	dc.w	0				; filler

;_______________________________________________________________________
;
;  Routine:		IOPMoveData
;  Inputs:		A0 - pointer to IOPMoveInfo paramater block
;  Outputs:		D0 - Result Code (NoErr/paramErr)
;  Destroys:	A0, A1, D0, D1, D2
;  Calls:		CopyToIOP, CopyFromIOP, CompareWithIop
;  Called by:	OsTrap Dispatch Table
;
;  Function:	Moves, or compares data between the IOP and the Host
;				memories, using the parameters inthe IOPMoveInfo parameter
;				block.  Also has a special mode to apply patches to IOP
;				memory as an atomic operation.
;
;_______________________________________________________________________

			with	IOPMoveInfo
IOPMoveData

; We can use the new protection scheme, if the first two instructions in the	<115>
; patch are a bra.s followed by the jump to the old rom address.

			bra.s	@protection
@NoPatch
			BackToTrap	oldIOPMoveData					; no, then just execute ROM Code
@protection


	; are we coming from the IOP serial driver open call?
			cmpRA	From_IOPOpenCall,OSTrapReturnAddressDepth(sp)
			bne.s	@NoPatch



@chkA		lea		DrvrAFix,a1							; get address of our patchbytes
			cmpi.w	#DrvrAPicAddr,imIOPAddr(a0)
			beq.s	@doPatch
@chkB		lea		DrvrBFix,a1							; get address of our patchbytes
			cmpi.w	#DrvrBPicAddr,imIOPAddr(a0)
			bne.s	@noPatch							; not our drivers? well, don't patch then

@doPatch
	; Call the ROM to download the unpatched image
			_IOPMoveData

	; now patch the downloaded driver. Each section of patch bytes
	; is preceded by an offset word and a count byte.
	; a2 has start addr of our patch bytes.

			moveq	#numpatches-1,d1					; number of patches (minus 1 for dbra)
			move.w	imIOPAddr(a0),d2					; get base addr of downloaded driver
			moveq	#0,d0								; for additions
			move.w	d0,imByteCount(a0)					; clear out high byte of count
@patchloop
			move.w	d2,d0								; get base addr of downloaded driver
			add.w	(a1)+,d0							; add in offset to patch start
			move.w	d0,imIOPAddr(a0)					; set dest addr for patchbytes
			move.b	(a1)+,imByteCount+1(a0)				; number patchbytes
			move.l	a1,imHostAddr(a0)					; set source addr of patchbytes
			adda.w	imByteCount(a0),a1					; increment ptr past patchbytes

			_IOPMoveData								; download the patch bytes
			dbra	d1,@patchloop						; go on to next patch

	; note that when dbra expires, d0 will contain output for last IOPMove data
	; performed, which is an approximation of what should be in d0

	; note also that we've trashed the IOPMgr PB fields, but since the driver
	; never refers to them again, and in the interest of STAYING SMALL, we'll
	; ignore it.
			rts
			endwith
			endproc

;
;
;	End of Patch To IOPMoveData Trap to Fix IOP Serial Driver Control Call Bug
;____________________________________________________________________________	 EH <33>

;____________________________________________________________________________
NewFLineRoutine		PROC	EXPORT

					EXPORT  OldFLineRoutine

					cmp.w	#$002C,6(sp)				;make sure that this is our stack frame. If not
					bne.s	OldFLineRoutine				;..then jump thru the old exception vector

					MOVEM.L	A0/D0,-(SP)					; Save these two registers					<107>

					move.l	8+2(sp),a0					;get the address of the instruction word that caused
					move.w	(a0),d0						;..this exception. Then copy the word into DO
					and.w	#%0000111000000000,d0		;get just the co-processor ID from the instruction
					cmp.w	#%0000001000000000,d0		;if itÕs not one, then it isnÕt a FPU instruction
					bne.s	stackError					;..so return thru the old FPU replacement routine
					lea		continue,a0					;change the saved return address to our continuation
					move.l	a0,8+2(sp)					;..point and return out of exception mode.

					MOVEM.L	(SP)+,A0/D0					; Restore the regs							<107>
					rte

continue			move.w	#dsNoFPU,d0					;this displays the dialog that lets the user
					_SysError							;..return to the finder (FPU type)

stackError			MOVEM.L	(SP)+,A0/D0					; Restore the regs							<107>

OldFLineRoutine		JMP		$12345678					; This gets filled in at install time 		<107>

					ENDP
;____________________________________________________________________________



;----------------------------------------------------------------------------------------------------
;	This routine will read the Time LowMem global without
;	issuing the call to Egret.  Egret will keep the time updated
;	in the background without needing system intervention.  The
;	Egret will post a unsolicited time packet which will update the
;	LowMem global when it is not able to post the Tick packet
;	within one second.
;----------------------------------------------------------------------------------------------------

RdDateTimePtch	PROC  EXPORT

				move.l	Time,(a0)			; return the time to the caller
				clr.w	d0					; return no error <74>
				rts

				ENDP

;----------------------------------------------------------------------------------------------------



;----------------------------------------------------------------------------------------------------
;	This patch fixes a bug in Egret Manager TickHandler routine.						<89><101>
;	The routine will store the 32 bit time passed by Egret to the
;	system if the packet is a ReadRealTime into TIME lowmen.
;	Decrements the lowmem Time by one to compensate for the interrupt
;	Handler incrementing it by one and then calls the LVL1DT interrupt
;	handler.
;	If the packet is a tick packet then it calls LVL1DT to increment the
;	time setting and check the alarm state.
;
;	Entry:
;		A1.l = Points at Response data buffer At Flags byte:
;
;			+---------+----------+---------+---------+---------//-------+
;			| Attn    | Pkt Type | Flags   | Pkt Cmd | 8 Bytes data Max |
;			+---------+----------+---------+---------+---------//-------+
;
;		A2.l = Points at Egret Manager Globals
;
;----------------------------------------------------------------------------------------------------


TickHandler	PROC	EXPORT
			WITH	respPacket,EgretGlobals

			subq.l	#2,a1						; point to the beginning of the Response data buffer
			cmpi.b	#TickPkt,RespType(a1)		; Check the Packet type
			beq.s	@CallLVL1DT					; If tick packet just call LVL1DT handler
;
;	The packet was a readTime packet from Egret.  Update the Time lowmem and
;	adjust it to compensate for the increment in the LVL1DT handler.
;
			move.l	RespData(a1),Time			; write the new time in lowmem TIME
			subq.l	#1,Time						; adjust to compensate for increment in LVL1DT
;
;	JUMP to routine pointed to by the Contents of LVL1DT
;

@CallLVL1DT
			move.l	VIA,a1						; point to the VIA
			move.l	LVL1DT,a0					; get vector
			jmp		(a0)


			ENDWITH
			ENDP

;----------------------------------------------------------------------------------------------------
;	This patch saves the processor status register, calls the		<101> SAM
;	ShiftRegIrq routine in Egret Manager and then restore the
;	status register and exits.
;----------------------------------------------------------------------------------------------------


EgretIRQPtch	PROC	Export
				EXPORT	Vector_Hold

				move.w	sr,-(sp)				; save the status register
@IrqJmp			jsr		$10000000				; this JSR will call the routine pointed to by the old
												; contents of LVL1DT+8 vector (ShiftRegIrq)
				move.w	(sp)+,sr				; restore the status register
				rts

Vector_hold		equ		@IrqJmp+2				; point to the operand field

				ENDP


;----------------------------------------------------------------------------------------------------
;	This patch fixes possible loss of data to the SCC by calling		<101> SAM
;	the Poll Proc when SCC data is available.
;----------------------------------------------------------------------------------------------------

EgretDispatchPtch	PROC	Export

EMJmpAddr	equ		$14868						; Offset added to Contents of Rombase for jmp back to Rom Egret Manager
												; <104> removed declarations for Pollstack,PollProc, and HiIntMsk
			with	EgretPB, EgretGlobals

			bsr		CheckPacket					; Validate the Packet type & command byte
			bne		@done						; Exit if Error packet
			movea.l	EgretBase,a2				; a2 gets ptr to globals
			movea.l	VIA,a1						; a1 points to VIA base

			cmpi.b	#specialPkt,pbCmdType(a0)	; is this a special command?
			bne.s	@EgretRestart

			move.l	a0,ADBpb(a2)				; yes, is to set the ADB param block (for autopoll data).
			bra		@done

@EgretRestart
			move.w	sr,-(sp)					; save SR
			ori.w	#hiIntMask,sr				; mask interrupts
			btst.b	#xcvrSes,vBufB(a1)			; does Egret want to abort?
			beq.s	@abort						; yes, wait for it to go away
			bset.b	#busy,flags(a2)				; not an abort, mark that we're busy.
			beq.s	@sendPackType				; we were not busy before, so try to send the first byte

@abort		move.w	(sp)+,sr					; we were busy, enable interrupts
			bsr		pollByte					; poll shift reg, calling handler if interrupts masked
			bra.s	@EgretRestart				; and keep waiting for busy to go away...

@sendPackType									; interrupts masked here
			bset.b	#sysSes,vBufB(a1)			; assert System Session (we're starting command packet)
			bset.b	#SRdir,vACR(a1)				; switch to output
			move.b	pbCmdType(a0),vSR(a1)		; send command packet to shift reg
			bset.b	#viaFull,vBufB(a1)			; tell Egret we sent it
;_________________________
;		If PollProc exists, Poll the SCC and save any available data
;		When the shift register irq comes in call the PollProc
;		then process the shift register irq data
;
			movem.l	d0/d1/a0-a4/a6,-(sp)		; save some registers

			lea		@zero, a3
			move.l	sp,PollStack				; Pointer to buffer for polled bytes

			btst.b	#0,SccIopFlag				; Check if we are in IOP mode (On Eclipse...)
			beq.s	@wait

			tst.l	PollProc					; Check for a Poll Proc available
			beq.s	@wait						;

			movea.l	SccRd,a3					; SCC may have data to get
			movea.l	a3,a6
			addq.l	#Actl,a3					; Point to data available register (RR0)
			addq.l	#AData,a6					; Point to the SCC data register


@wait		btst.b	#RxCa,(a3)					; Test for SCC data available
			beq.s	@2
			move.b	(a6),-(sp)					; Push the data on the stack
@2			btst.b	#vShift,vIFR(a1)			; now wait for shift reg IRQ
			beq.s	@wait

			cmpa.l	PollStack,SP				; Is there any poll data
			beq.s	@NoSCCData
;
;		We have SCC data and a Poll Proc to call.  Go call it
;
			pea		@NoSCCData					; Return addr for PollProc
			move.l	PollProc,-(SP)				; Point to the PollProc
			rts									; Call the PollProc

@zero		dc.w	0


@NoSCCData	movem.l	(sp)+,d0/d1/a0-a4/a6		; restore work registers

@VsrIrq
			btst.b	#xcvrSes,vBufB(a1)			; did Egret abort?
			bne.s	@accepted					; no, then it will accept our packet
			bclr.b	#SRdir,vACR(a1)				; yes, switch back to input
			bclr.b	#sysSes,vBufB(a1)			; ack the abort
			bsr.s	CallShiftRegIRQ				; handle it
			bra.s		@abort						; and wait

@accepted
			JmpROM	EMJmpAddr					; Jump back into Rom Egret Manager			<107>

@done		moveq	#0,d0						; no errors for now
			rts

;________________________________________________________________________________________________
CallShiftRegIRQ
			movem.l	a0-a3/d0-d3,-(sp)			; save regs like interrupt handler does
			movea.l  Lvl1DT+8,a0	        	; get the shift reg IRQ handler
			jsr		(a0)						; call it
			movem.l	(sp)+,a0-a3/d0-d3			; restore regs
			rts

;________________________________________________________________________________________________
;	Routine:	PollByte
;
;	Function:	This routine checks to see if level 1 interrupts are masked, exits if not.
;				If masked, it polls the flag register for a shift reg interrupt, and
;				calls the handler if found.
;
;	Inputs:		a1	-	VIA base ptr
;				a2	-	globals pointer
;
;	Outputs:	none
;
;	Destroys:	d0,d1
;________________________________________________________________________________________________
PollByte
			move.w	sr,d0						; get 68xxx interrupt mask
			andi.w	#hiIntMask,d0				; are we at interrupt level?
			beq.s	@exit						; no, just exit
			btst.b	#vShift,vIFR(a1)			; yes, poll the shift reg
			beq.s	@exit						; no shift reg interrupt, return
			bsr.s	CallShiftRegIRQ				; yes, handle it
@exit		rts

;________________________________________________________________________________________________
;
;		Validate the Packet type and Command if Pseudo Pkt.
;
;		If an error is encountered with the packet a error packet will be
;		built in the pbParam area of the parameter block as if Egret had
;		returned the packet.  Also, the pbResult field will contain a System
;		error code for bad parameter block format.
;
;		Entry: A0 = Parameter block pointer
;
;		Exit:	sr.Z = 0 if valid  packet/pseudocmd nonzero otherwise
;
_________________________________________________________________________________________________

CheckPacket
			cmp.b	#SpecialPkt,pbCmdType(a0)	; could be an ADB initialization packet
			beq.s	@OkExit

			cmp.b	#ErrorPkt,pbCmdType(a0)		; ADB ($00) and Pseudo ($01) only
			bhi.s	@BadPkt						; Invalid packet

			cmp.b	#PseudoPkt,pbCmdType(a0)	; Check for pseudo commands
			bne.s	@OkExit						; On Pseudo Packets check the command

			cmp.b	#MaxPseudoCmd,pbCmd(a0)		; Validate the Pseudo command number				<bg>
			bls.s	@OkExit

@BadPseudo	move.w	#InvPseudo,pbParam(a0)		; report a pseudo command error
			move.w	pbCmdType(a0),pbParam+2(a0)	; we are faking an error packet
			bra.s	@ErrorExit

@BadPkt		move.w	#InvPkt,pbParam(a0)			; report invalid packet error
			move.w	pbCmdType(a0),pbParam+2(a0)	; we are faking an error packet

@ErrorExit	move.w	#paramErr,pbResult(a0)		; parameter error in result field
			bra.s	@Exit

@OkExit		move.w	#0,pbResult(a0)				; So far packet OK
@Exit		rts

			ENDWITH
			ENDPROC

;------------------------------------------------------------------

;__________________________________________________________________________	<101> <BEGIN>
; PACK 4 overpatch code for MC68020 software SANE to correct binary-to
; decimal conversion bug which may cause an extra byte to be written to
; the destination decimal record.
;
; Copyright © 1990 Apple Computer, Inc.  All rights reserved.
; Written by:  Jon Okada.
;
; The overpatch code intercepts every PACK 4 call and determines if the SANE
; operation requested is a binary-to-decimal conversion.  If it is not,
; control is passed to the original, underlying SANE engine.  If it is,
; the SANE engine is called with output directed to a local decimal record,
; which is copied to the user's destination decimal record, taking care not
; to exceed the desired precision.
;
; Entry point is FP020PATCH.  Upon entry, the stack is as follows:
;
;	&return < SANE opword (2 bytes) < &dst < &src < &src2,
;
; where &src and &src2 may not be present, depending on the SANE operation
; requested by the caller.

PACK4inROM	equ		$73940			;Offset from ROMBase to non-fpu PACK4.

FP020Patch	PROC

			MOVE.L	D0,-(SP)		; STACK:  D0sv < &ret < opcode < etc.
			MOVEQ	#$1F,D0			; D0 <- opcode mask
			AND.W	8(SP),D0		; isolate opcode
			CMPI.B	#$0B,D0			; binary-to-decimal conversion?
			MOVEM.L	(SP)+,D0		; (restore register)
			BEQ.S	@DOBINDEC		; yes

			jmpROM	PACK4inROM		; Let PACK4 handle call.

;
; Binary-to-decimal conversion is accomplished via the underlying PACK 4
; implementation, but the result is directed to an intermediate buffer
;
@DOBINDEC:
			LINK	A6,#-28			; reserve space for decimal record
			MOVEM.L	D0/A0-A1,-(SP)	; save registers

			LEA		-28(A6),A0		; A0 <- addr of local decimal record

			MOVE.L	18(A6),-(SP)	; push &src2
			MOVE.L	14(A6),-(SP)	; push &src
			MOVE.L	A0,-(SP)		; push local decimal record addr
			MOVE.W	8(A6),-(SP)		; push opword

			jsrROM	PACK4inROM		; call pack4.

			MOVEA.L	10(A6),A1		; A1 <- &dst
			MOVE.L	(A0)+,(A1)+		; copy sign/exp to dst record
			CLR.W	D0				; clear counter
			MOVE.B	(A0)+,D0		; read decimal string length
			MOVE.B	D0,(A1)+		; write it to dst record
			SUBQ	#1,D0			; initialize loop counter

@1:
			MOVE.B	(A0)+,(A1)+		; copy string to dst record
			DBRA	D0,@1

			MOVEM.L	(SP)+,D0/A0-A1	; restore registers
			UNLK	A6				; unlink
			MOVE.L	(SP),14(SP)		; move return addr up
			ADDA.W	#14,SP			; kill arguments on stack

			RTS						; return to caller

			ENDP
;__________________________________________________________________________	<101> <END>


;__________________________________________________________________________	<xyz> <cch 8/6/91>
;	Routine:	GetPageDescPatch
;
;	Function:	This routine is a patch to the GetPageDescPatch, which is
;				an internal routine called by LockMemory and WriteProtectMemory.
;				The bug it fixes is that the page descriptor pointer is 
;				converted from physical to logical twice in GetPageDesc.
;				This patch is only needed on 68030 machines with ROM version $67C, 
;				sub-version 1.5 without VM.  
;
;	How:		This is a come-from patch to the _Gestalt trap, which is
;				called by the GetMMUInfo routine in GetReal.a.  If the
;				come-from patch is triggered, and the GetPageProc flag on
;				the stack is set, the return address from GetPageDescProc is
;				replaced with the address of a routine which fixes the
;				result and returns to the original caller.
;
;	Note:		This patch is NOT reentrant.  This is OK, however, since 
;				_LockMemory may not be called at interrupt level, which is
;				the only way reentrancy could occur with this routine.
;
;	Inputs:		A0/D0	-	parameters to gestalt
;				(sp).L	-	address routine was called from plus 2
;
;	Outputs:	none
;
;	Destroys:	a1
;__________________________________________________________________________
GetMMUInfoPatchAddr	EQU		$40886d1e				; return address when Gestalt is called
SetCacheInhibitAddr	EQU		$408873a2				; return address when correct swapMMUMode is called
getPageDesc			EQU		7						; getPageDesc selector

GetPageDescPatch	PROC
			EXPORT	MemDispPatch

			cmp.l	#GetMMUInfoPatchAddr,$18(sp)	; check addr _Gestalt was called from
			bne.s	@skipPatch						; IF we had a match THEN
			cmp.w	#getPageDesc,$4e(sp)			;	check if user wants the page descriptor
			bne.s	@skipPatch						;	IF user wants a page descriptor THEN
			lea		GetPageDescRetAddr,a1			;	  where to save getPageDesc return addr
			move.l	$50(sp),(a1)					;	  save return address to getMMUInfo
			lea		fixResult,a1					;	  get address of routine to fix result
			move.l	a1,$50(sp)						;	  stuff it in the stack frame
													;	ENDIF
													; ENDIF
@skipPatch	BackToTrap	origGestalt					; jump to original Gestalt trap

;-----------------
; getPageDesc fix up routine
;-----------------
fixResult
			sub.l	Phys2Log,a0						; fix up result
			jmp		([GetPageDescRetAddr])			; jump back into normal code stream

GetPageDescRetAddr									; return address for getMMUInfo
			dc.l	$87654321

;__________________________________________________________________________	<10> <cch 8/6/91>
;	Routine:	MemDispPatch
;
;	Function:	This routine is a patch to the _VM trap.  It fixes a bug
;				in the Terror ROM which occurs when the page the stack is
;				is is marked uncacheable in the MMU tables, then a subsequent
;				PFLUSH'd is executed with data still in the cache.
;
;	How:		This is a simple patch which is installed only on 68030's when
;				VM is not installed on Terror ROMs, version $67C, sub-version 1.5.
;				It disables the data cache during all _VM calls with the exception
;				of _GetPhysical.  
;
;	Inputs:		A0-A1/D0	-	parameters to _VM call
;
;	Outputs:	none
;
;	Destroys:	d1
;__________________________________________________________________________
GetPhysSel	EQU		5

MemDispPatch
			cmp.b	#GetPhysSel,d0					; check for get physical selector
			beq.s	@skipPatch						; IF this is anything but getPhysical THEN
			movec	cacr,d1							;	get cache value
			move.w	d1,-(sp)						;	save cache state on stack
			andi.w	#$001f,d1						;	we want to save current instruction cache bits
			addi.w	#$0800,d1						;	value to flush data cache
			movec	d1,cacr							;	flush and disable data cache
			jsrTrap	origMemDisp						;	do original call
			move.w	(sp)+,d1						;	get original cache state
			movec	d1,cacr							;	reenable caches
			rts										;	return to caller
@skipPatch											; ELSE
			BackToTrap	origMemDisp1				;	do original call
													; ENDIF

			ENDP
;__________________________________________________________________________ <10> <end>

;__________________________________________________________________________	<13><cch 8/28/91>
;	Routine:	FP68k patch for Terror-based 030 machines
;
;	Inputs:		stack has:	<RET> <OPWORD> <ADRS1> <ADRS2> <ADRS3>
;
;	Destroys:	d1
;__________________________________________________________________________
QADDX			EQU		$408EC1E4
FP881CASE		EQU		$408EB50C
OMEGA881BASE	EQU		$408EB1FC
OPERRHANDLER	EQU		$408EDCE6

FP68kPatch	PROC	EXPORT	
			
			tst.b	MMU32bit						; Are we in 24 bit mode?
			beq.s	@inMode24						; -> Yes

@inMode32	cmp.l	#$40800000,(SP)					; check address we're patching
			bhs.s	@dontBackpatch					; IF we're being called from ROM THEN
@CallOld	BackToTrap	origFP68k					;	do original call

@inMode24	move.l	D0,-(SP)						; save D0
			move.l	4(SP),D0						; get Return address in D0

			and.l	MaskBC,D0						; poor man's strip address
			cmp.l	#$00800000,D0					; Is the PC less than ROM?
			movem.l	(SP)+,D0						; Restore D0
			blo.s	@CallOld						; -> Yes, Call the old Backpatch routine
													; No. Fall into DontBackPatch
													
@dontBackpatch										; ELSE
			SUBQ	#2,SP							;	MAKE A HOLE
			MOVEM.L	D0/A0,-(SP)						;	SAVE 2 REGISTERS

			LEA		QADDX,A0						;	ALWAYS STORE &QADDX INTO ITS JUMP ISLAND
			MOVE.L	A0,$0B6E						;	HOME SO TRAPS HAVE A POINT OF REFERENCE

			MOVE.W	14(SP),D0						;	GET OPWORD INTO D0
			ROL.W	#8,D0							;	XXXX383F --> XXXX3F38  ... SWAP BYTES
			LSL.B	#2,D0							;	XXXX3F38 --> XXXX3FE0  ... SCRUNCH TOGETHER
			BFEXTS	D0{18:9},D0						;	D0 ::= INDEX := 8 * OPCODE + FORMAT
			MOVE	(FP881CASE,D0*2),D0				;	DO := OFFSET AT INDEX IN TABLE
			LEA		OMEGA881BASE,A0					;	GET OMEGABASE
			ADD.L	D0,A0							;	GO DO IT
			MOVE.L	10(SP),12(SP)					;	SLIDE RETURN ADDRESS ON TOP OF OPWORD
			MOVE.L	A0,8(SP)						;	FILL RTS HOLE PROVIDED ABOVE

			LEA		OPERRHANDLER,A0					;	INSTALL OPERR TRAP HANDLER INTO
			MOVE.L	A0,$0D0							;	LOW-MEM VECTOR (SEE TABLE 7-6 882 MAN)

			FMOVE.L	FPCR,D0							;	ENABLE OPERAND ERROR TRAPPING
			BSET	#13,D0
			FMOVE.L	D0,FPCR
			
			MOVEM.L	(SP)+,D0/A0						;	RESTORE 2 REGISTERS
			RTS										;	DISPATCH

													;	ENDIF

			ENDP
;__________________________________________________________________________ <13>


;----------------------------------------------------------------------------------------------------




;=========================================================================================
;=========================================================================================
;=																						 =
;=						END OF RESIDENT PATCH CODE SECTION								 =
;=																						 =
;=========================================================================================
;=========================================================================================

EndOfPatch		PROC	EXPORT

;=========================================================================================
;=========================================================================================
;=																						 =
;=						PATCH INSTALL CODE IS BELOW THIS POINT							 =
;=																						 =
;=	Patches may fall into two different categories:										 =
;=		1.	Required for both the Mac OS and A/UX										 =
;=		2.	Required only for the Mac OS												 =
;=																						 =
;=	Macintosh OS-only patches are usually characterized by code which touches hardware	 =
;=	directly, or patches for traps not supported by A/UX.  The safest thing to do when	 =
;=	in doubt is to check with your friendly A/UX representative (only a phone call		 =
;=	away!).  A/UX loads all patches, but conditionalizes the installation code.  The	 =
;=	first section of installation code which follows, is for patches required on both	 =
;=	Mac OS and A/UX.  The second section (further down), is for Mac OS-only patch		 =
;=	installation code.																	 =
;=																						 =
;=	To find a place to add your Mac OS and A/UX patch, search for 'EndBothSection'		 =
;=																						 =
;=	To find a place to add your Mac OS only patch, search for 'EndMacSection'			 =
;=																						 =
;=========================================================================================
;=========================================================================================

PatchInit	MAIN	Export
			Import	EndOfPatch
			Import	StartPatch
			Import	Cutback
			Import	FixupTbl				; added FixupTbl 				<24July89smb>

			MOVE.L	D1,-(SP)				; Save our handle				<1.1-4april89-CEL>

;____________________________________________________________________________
;	Fixup patch addresses
;
;	The Fixing up of addresses generated by the CMPRA, JSRROM & JMPROM
;	Breaks down as follows:
;
;	Addressing		High Byte in		Action
;	mode:			instruction:
;	----------		------------		------
;	24 bit				NZ				Do not alter the address in the instruction.
;										Used with CMPRA to a ROM Resource.
;	32 bit				NZ				Mask out 12 high bits from the address
;										in the instruction, leaving a ROM offset
;										Then add in ROMBase.
;	either				Zero			Normal Case.  Add ROMBase to the address
;										in the instruction.
;
;	Registers:
;			D0:		Address Size Flag.  Pos: 24 bit mode;   Neg: 32 bit Mode
;			D1:		Entry from table of offsets of locations to be fixed up
;			D2:		(RomBase)
;			A0:		Pointer into table of offsets of locations to be fixed up.
;			A1:		Base of fixup table; also location from which offsets are computed.

			move.l		RomBase, D2
			moveq		#-1, D0
			_StripAddress
			lea			FixupTbl, A0
			move.l		A0, A1
FixUpLooP	move.l		(A0)+, D1
			beq.s		@1
			tst.b		0(A1, D1.L)
			beq.s		@AddIt
			tst.l		D0				;	If Address has any high bits set
			bpl.s		FixUpLoop		;		24 Bit mode; Dont alter this one.
			and.w		#$f, 0(A1, D1.L);		32 Bit Mode; Clear High 12 bits.

@AddIt		add.l		D2, 0(A1, D1.L)	;	Normal Case: Add in ROMBase
			bra.s		FixUpLoop
@1
			move.l		jCacheFlush, a0	; 	flush caches (make sure tables are consistent)
			jsr			(a0)



;=========================================================================================
;=========================================================================================
;=																						 =
;=				PATCH INSTALLATION CODE FOR BOTH MAC OS AND A/UX STARTS HERE			 =
;=																						 =
;=							Please be neat and follow the format						 =
;=																						 =
;=========================================================================================
;=========================================================================================


;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ	GGD <8.4>
;	Fix _StripAddress to not check the MMStartMode bit of MMFlags at runtime,
;	because the memory manager changes that bit when accessing ROM resources,
;	and if an interrupt occurs while the bit is changed, calling _StripAddress
;	from an interrupt routine (eg VBL task) might not work correctly.  To correct
;	this, we will install either a 24 or 32 bit version of _StripAddress once
;	and eliminate the runtime check, making the code both faster and correct.
;	NOTE: This is installed early in the patch file to reduce the chances of
;	encountering this bug while installing the remaining patches.

StripAddressOld		equ		$0000D764					; ROM offset of old StripAddress
StripAddress24		equ		$0000D76C					; ROM offset of new 24 bit mode version
StripAddress32		equ		$0000D770					; ROM offset of new 32 bit mode version

FixStripAddress
			lea		OsTable+($55*4),a0					; point to dispatch table entry (trap A055)
			CmpRA	StripAddressOld,(a0)				; see if it already patched (by A/UX maybe?)
			bne.s	@Done								; if already patched, don't patch again
			moveq.l	#StripAddress24-StripAddressOld,d0	; get adjustment for 24 bit mode
			btst.b	#Systemis24bit,SystemInfo			; what kind of OS are we running
			bne.s	@patchIt							; if 24 bit OS, change it to 24 bit StripAddress
			addq.l	#StripAddress32-StripAddress24,d0	; if 32 bit, adjust offset to 32 bit entry
@patchIt	add.l	d0,(a0)								; update the dispatch table entry
@done													; all done					 <8.4>


;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ	<8>
; The TERROR ROM does not distinguish between a Tim and a Tim LC.  We have to.
; We need to fix boxFlag if we're running on a Tim LC (a Tim w/o an FPU)
;
			MOVE.L	ROMBase,A0							; Get Bas o ROM
			CMPI.B	#TERRORMinorVers,18(A0)				; Is this a TERROR 67C ROM?
			BNE.S	@DoneTimLC							; -> Nope, don't futz with anything
			
			CMPI.B	#boxPowerBook170,boxFlag			; Does the ROM think this is a Tim?					<146>
			BNE.S	@DoneTimLC							; -> No, don't assume anything. Bail out.
		
			MOVE.W	HwCfgFlags,D0						; Get them Hardware Config Flags
			BTST.L	#hwCbFPU,D0							; Does we gots an FPU?
			BNE.S	@DoneTimLC							; -> Yes, we're not on a Tim LC.  Exit.
			BTST.L	#hwCbPwrMgr,D0						; Do we have a PowerMgr?
			BEQ.S	@DoneTimLC							; -> No.  This is not a Portable of any kind
														; We're on a TERROR $67C ROM with a PwrMgr and no FPU.
			MOVE.B	#boxPowerBook140,boxFlag			; We're on a Tim LC.  Stuff the right boxFlag		<146>			
@DoneTimLC

;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ	<130><131><8><9>
;	The GestaltFuction.a file is used to build a ptch for machines without
;	Gestalt in ROM, but it also contains fixes and improvements that are not
;	in the ci ROMs OR in the GestaltPatches.a file...  The changes are not
;	trivial, so weÕre punting and loading the Gestalt ptch on ci ROMs, too...
;
;	Before we do, though, we throw away any storage that Gestalt has allocated.
;
			
			
			move.l	ExpandMem,A1
			move.l	ExpandMemRec.emGestalt(A1),A0		; Get the ROM GestaltÕs Storage pointer
			move.l	A0,-(SP)							; Save the Ptr on the Stack
			move.l	(A0),-(SP)							; Save Gestalt's Selector table handle
			
			PtchInst	5								; Reinstall all of Gestalt ptch

			move.l	(SP)+,A0							; Get the old Selector Table Handle
			_DisposHandle								; Throw the storage away!
			move.l	(SP)+,A0							; Get the storage Ptr
			_DisposPtr									; Make it go away too!


;____________________________________________________________________________	NJC	<1.6>
;	ci Quickdraw ptch added 1/16/90 KON
;

			PtchInst		26			; ci Quickdraw patches

;____________________________________________________________________________	DAF	<1.9>
;	Install window manager fixes
;

			InstToolTp	newSetWinColor,$241
			InstToolTp	NewSetCtlColor,$243

;____________________________________________________________________________	dvb <3.5>
; Palette Mgr Patches
;

				InstToolTp	ptchInitPalettes,$290
				InstToolTp	ptchGetNewCWindow,$246							;<10Nov89 KON>
				InstToolTp	ptchPMgrDispatch,$2A2	; Changed a couple of dispatches	dvb <8.3>
													; Next, fix up the dispatch table
				LEA			pMgrProcs,A0
				MOVE.L		A0,D1					; D1-> base of table
				SUBQ.L		#1,D1					; Less 1, 'coz lobit = patched flag
				MOVE		#((pMgrProcsSize)/4)-1,D0	; we'll loop for this many fields 	<107> (pMgrProcsSize)
@FixPMLoop		MOVE.L		(A0),D2					; pull entry from table
				BTST		#0,D2
				BEQ.S		@FixPMLoopEnd
				ADD.L		D1,D2
@FixPMLoopEnd	MOVE.L		D2,(A0)+				; stash correct address, bump A0
				DBRA		D0,@FixPMLoop			; and count down, including zero.	dvb <8.3> end

;__________________________________________________________________________
;__________________________________________________________________________

FixBackSANE	MOVE.L	#'fpu ',D0			; Gestalt FPU selector
			_Gestalt					; Do it
			MOVE.L	A0,D0				; Do we have an FPU?
			BEQ		@ReallyDone			; -> No, do nothing
						
			MOVE.L	ROMBase,A0				; Get ROM base			
			CMPI.B	#TERRORminorVers,18(A0)	; Is this TERROR 067C ROM?
			BEQ		@ReallyDone				; -> Yes, leave the ROM SANE enabled!
			CMPI.B	#ZYDECOminorVers,18(A0)	; Is this Zydeco 067C ROM?
			BEQ		@ReallyDone				; -> Yes, leave the ROM SANE enabled!
			
@DisableSANEinROM
			MOVE.B	ResLoad,-(SP)			; Save current resLoad state
			MOVE.W	CurMap,-(SP)			; Save Current Rsrc Map refNum
			CLR.W	CurMap					; Make the System the current Map (CurMap = 0)
			
			SF		ResLoad					; Don't actually read the rsrc
			CLR.L	-(SP)					; Result
			MOVE.L	#'PACK',-(SP)			; Type
			MOVE.W	#4,-(SP)				; Id 4
			_Get1Resource			
			MOVE.L	(SP)+,D0				; Did we get it?
			BEQ		@Done					; -> No, PACK 4 is not on the disk.  Exit Now! (Use the ROM SANE)
			MOVE.L	D0,-(SP)
			_ReleaseResource				; Make the System SANE handle go away. (or we'll get it at the _RmveRsrc)
			
			SF		ResLoad					; Don't actually read the rsrc
			CLR.L	-(SP)					; Result
			MOVE.L	#'PACK',-(SP)			; Type
			MOVE.W	#5,-(SP)				; Id 5
			_Get1Resource			
			MOVE.L	(SP)+,D0				; Did we get it?
			BEQ		@Done					; -> No, PACK 5 is not on the disk.  Exit Now! (Use the ROM SANE)
			MOVE.L	D0,-(SP)
			_ReleaseResource				; Make the System SANE handle go away. (or we'll get it at the _RmveRsrc)
			
			ST		RomMapInsert			;  Put the ROM map in first
			MOVE.W	#1,CurMap				; Make the ROM map current
			
			CLR.L	-(SP)					; Result
			MOVE.L	#'PACK',-(SP)			; Type
			MOVE.W	#4,-(SP)				; Id 4
			_Get1Resource			
			MOVE.L	(SP)+,D0				; Did we get it?
			BEQ.S	@Try45					; -> No, try 4 five.
			
			MOVE.L	D0,-(SP)				; The Handle (save a copy of it)
			MOVE.L	ROMMapHndl,-(SP)		; Save this
			MOVE.L	#-1,ROMMapHndl			; To fool SetResAttr into letting use change ROM rsrc attrs
			
			MOVE.L	D0,-(SP)				; The Handle (push it. Push it good)
			MOVE.W	#$50,-(SP)				; A good value (Unprotected)
			_SetResAttrs
			MOVE.L	(SP)+,ROMMapHndl

			MOVE.W	#1,CurMap				; Set CurMap to the ROM rsrc map
			ST		RomMapInsert			; Dont load the rsrc into memory						
			_RmveResource

@Try45		ST		RomMapInsert			;  Put the ROM map in first

			CLR.L	-(SP)					; Result
			MOVE.L	#'PACK',-(SP)			; Type
			MOVE.W	#5,-(SP)				; Id 5
			_Get1Resource			
			MOVE.L	(SP)+,D0				; Did we get it?
			BEQ.S	@Done					; -> No, exit
			
			MOVE.L	D0,-(SP)				; The Handle (save a copy of it)
			MOVE.L	ROMMapHndl,-(SP)		; Save this
			MOVE.L	#-1,ROMMapHndl			; To fool SetResAttr into letting use change ROM rsrc attrs

			MOVE.L	D0,-(SP)				; The Handle (push it. Push it good)
			MOVE.W	#$50,-(SP)				; A good value (Unprotected)
			_SetResAttrs
			MOVE.L	(SP)+,ROMMapHndl
			
			MOVE.W	#1,CurMap				; Set CurMap to the ROM rsrc map
			ST		RomMapInsert			; Dont load the rsrc into memory						
			_RmveResource

@Done		MOVE.W	(SP)+,CurMap			; Restore the current res map
			MOVE.B	(SP)+,resLoad			; Restore ResLoad
@ReallyDone		
;__________________________________________________________________________
;__________________________________________________________________________



;____________________________________________________________________________		<2> RMP
;	This patch is used to fix a problem in the MPW Shell on Eclipse.  See above.

ROMVIA2DT	equ		$00009D70				; ROM offset of old IOP interrupt handler

			bra.s	EclipseMPWPatchEnd		; skip over patch body into install code

EclipseMPWPatchStart

			move.b	#1<<ifCA2,VIFR(A1)		; reset the VIA2 interrupt flag	
			move.l	#(%00001000<<24)+\		; allow xmt msg 3 (ADB)
					(%00001000<<16)+\		; allow rcv msg 3 (ADB)
					(0<<8)+\				; this byte must be zero
					1,d0					; ADB is on SWIM IOP (IOP 1)
			jmpROM	IOPInterrupt			; handle the interrupt and return

EclipseMPWPatchEnd
@EclipseMPWPatchSize	equ		EclipseMPWPatchEnd-EclipseMPWPatchStart


			cmpRA	ROMVIA2DT,(VIA2DT+4*ifCA2) ; see if we have an IOP interrupt handler
			bne.s	@done					; if not, don't need to install it

			moveq.l	#@EclipseMPWPatchSize,d0; space needed
			_NewPtr	,Sys,Clear				; allocate it
			bne.s	@done					; if can't allocate, don't install
			movea.l	a0,a1					; dest address
			lea		EclipseMPWPatchStart,a0	; source address
			moveq.l	#@EclipseMPWPatchSize,d0 ; byte count
			_BlockMove						; copy the code

			move.w	sr,-(sp)				; save old int level
			ori.w	#HiIntMask,sr			; disable all ints

			move.l	a1,(Via2DT+4*ifCA2)		; install the new VIA2 interrupt handler

			move.w	(sp)+,sr				; restore the interrupt level

@done

;	End of Eclipse Cmd-Shift-Esc patch
;____________________________________________________________________________		<2> RMP


;____________________________________________________________________________	GGD	<2.0>
;	SANE Package Optimization
;
;	Optimize the SANE packages which are ROM Resources, by having the dispatch
;	table entry point right to the first instruction of the package, instead
;	of going through the Package Manager which finds the package by de-referencing
;	a handle.
;

			IF 1 THEN				; removed <4.6> <08/21/89 pke> re-enabled 11/29/89	<8.4>
OptimizePACKs
			lea		@PackOptTable,a3; point to the optimization table
@optLoop	move.w	(a3)+,d0		; get the package number
			bmi.s	@done			; exit at end of list
			move.w	d0,-(sp)		; push the package number
			_InitPack				; get the ROM resource, update AppPacks table
			move.w	(a3)+,d1		; get the trap word
			move.w	(a3)+,a0		; get the low mem address
			move.l	(a0),d0			; get the handle
			beq.s	@optLoop		; if null, skip it
			movea.l	d0,a0			; setup to de-reference it
			move.l	(a0),d0			; get a pointer to the routine
			beq.s	@optLoop		; if null, skip it
			movea.l	d0,a0			; setup pointer to code
			cmpi.b	#$60,(a0)		; see if first instruction is a BRA.S
			bne.s	@branchOptDone	; if not, don't optimize it
			move.w	(a0)+,d0		; get the BRA.S instruction
			ext.w	d0				; extend the branch displacement
			adda.w	d0,a0			; update the entry point address
@branchOptDone
			move.w	d1,d0			; setup the trap word
			_SetTrapAddress			; go directly to the first instr of the package
			bra.s	@optLoop		; optimize the next package

@PackOptTable
			dc.w	4				; package number 4
			_FP68K					; trap name for PACK 4
			dc.w	AppPacks+4*4	; low mem address of handle to PACK 4

			dc.w	5				; package number 5
			_Elems68K				; trap name for PACK 5
			dc.w	AppPacks+5*4	; low mem address of handle to PACK 5

			dc.w	-1				; package number -1, end of list
@done
			ENDIF

;__________________________________________________________________________	<101> <BEGIN>
;
; Install PACK 4 patch if:
;
;		- BoxFlag = 13 (//si - Erickson), or 14 (Mac LC - Elsie)
;  and	- No FPU present
;  and	- Current non-fpu PACK 4 lives at ROMBase + $73940
;
; NOTE:  This code MUST execute after OptimizePACKs!
;

FP68KTrap		equ  	$A9EB					;Trap number.
PACK4Handle		equ		AppPacks+16				;Lomem contains PACK4 handle.
PACKID			equ		4						;Resource ID.

PACK4Patch
;
; Are we running on IIsi or LC?
;

		;	Commented out boxFlag check.  Its not really needed.			 <107> SAM
		;		cmpi.b	#boxMacLC,BoxFlag		;Is this an LC?
		;		beq.s	@doPatch 				;Yep, so install patch.
		;		cmpi.b	#boxErickson,BoxFlag 	;No, is it a IIsi?
		;		bne		@endPACK4Patch			;Nope, so skip install.
;
; Yes, is there an FPU?
;
@doPatch		move.l	#gestaltFPUType,d0		;Do we have an FPU?
				_Gestalt
				cmp.w	#gestaltNoFPU,a0
				bne		@endPACK4Patch			;Yes, so don't install.
;
; Nope, does the current PACK4 live at ROMBase + $73940?
;
				move.w	#FP68KTrap,d0			;Get trap number.
				_GetTrapAddress					;Get current vector in a0.
				cmpra	PACK4inROM,a0			;Matching address?
				bne.s	@endPACK4Patch			;Nope, so don't install.
;
; Yes, so install the patch...
;
				move.w	#FP68KTrap,d0			;Get trap number.
				lea		FP020Patch,a0			;Get address of our patch code.
				_SetTrapAddress					;Patch it.

@endPACK4Patch

;__________________________________________________________________________	<101> <END>

;____________________________________________________________________________
;	Gestalt parity calculation
;
;	This code figures out if the board has parity capability, and if so,
;	if there are parity SIMMs installed.  It stores the result in the
;	gestalt parity function in the resident portion of the patch above.
;
				IMPORT	parityValue
				WITH	DecoderInfo,ExpandMemRec,GestaltGlobals,ProductInfo
				MACHINE	MC68030

				movem.l	a3/a4/d3/d4,-(sp)		; save registers!						<102>

				movea.l	ExpandMem,a0			; get ptr to expandmem rec
				movea.l	emGestalt(a0),a0		; get gestalt global ptr
				clr.l	d0						; assume no parity, clear result		<59>
				cmpi.w	#gestaltMacIIci,machType(a0)	; Mac IIci is first parity machine
				blt		@parityExit				; if before ci, definitely no parity
				move.l	UnivROMFlags,d1			; get external feature bits
				btst	#PGCInstalled,d1		; check if a parity chip exists
				bne.s	@checkPGC				; yep, go see if parity is enabled
				move.l	AddrMapFlags,d1			; get universal info attributes
				btst	#RPUExists,d1			; do we have an RPU chip?
				bne.s	@checkRPU				; then go check RPU
				bra		@parityExit				; if not, return zero as result

; checkPGC - check the parity VIA bit to see if it is enabled.

@checkPGC		move.l	VIA,a0					; load up Via base address
				btst	#6,VBufB(a0)			; check if parity enabled
				beq		@parityOn				; if clear, parity is enabled
				bra		@parityOff				; otherwise, it's off

; checkRPU - First set RPU to generate bad parity, then access all four SIMMs in
; both banks by accessing location 0 and the last longword in memory.
; Parity is only fully active if all four SIMMs generate a parity interrupt.
;	trashes a0/a1/a3/a4/d1-d4

@checkRPU		movec	cacr,d3					; get contents of cache
				move.l	d3,-(sp)				; save them
				move.l	#$1111,d3				; enable caches with bursting			<32>
				movec	d3,cacr					; write into cache register				<32>
				move.l	RomBase,a0				; point to base of rom					<32>
				move.l	#$2000,d3				; cache size/long = 32k/4 = 8k			<32>
@fillLoop		tst.l	(a0)+					; load a long							<32>
				dbra	d3,@fillLoop			; keep doing it for 8k					<32>
				move.l	#$0808,d3				; disable and freeze caches (bursting off)
				movec	d3,cacr					; write into cache register
				move.l	UnivInfoPtr,a0			; get pointer to universal information
				add.l	(a0),a0					; point to decoderInfo record
				move.l	RPUAddr(a0),a1			; get RPU base address
				move.l	sp,d3					; save our stack pointer
				move.l	AutoInt7,d4				; save NMI vector
				lea		@parityInt,a4			; address to return to from parity intrpt
				lea		@nmiHandler,a0			; get address of our NMI handler
				move	#$2700,sr				; turn all interrupts off
				move.l	a0,AutoInt7				; point vector to our handler
				moveq	#0,a3					; check first bank (0 is in first bank)

@checkBank		moveq	#4-1,d2					; check all four SIMMs
				move.l	(a3),d1					; get contents of longword
@nextByte		clr.l	(a3)					; write a long with correct parity		<44>
				st.b	rpuReset(a1)			; reset serial ptr
				st.b	(a1)					; write wrong parity mode
				clr.b	(a3,d2.w)				; write one SIMM with bad parity

				st.b	rpuReset(a1)			; reset serial ptr						<105>
				clr.b	(a1)					; write good parity mode				<105>

				tst.l	(a3)					; parity error if it's a parity SIMM
				nop								; wait for an interrupt
				nop

				move.l	d1,(a3)					; restore contents of longword
				move	#$2000,sr				; turn interrupts back on
				move.l	d4,AutoInt7				; restore NMI vector
				move.l	(sp)+,d3				; get original state of cache		<17>
				movec	d3,cacr					; restore original state of cache	<17>
				bra.s	@parityOff				; if we get here, it's a non-parity SIMM

@parityInt		st.b	rpuReset(a1)			; sync up RPU serial line
				clr.b	(a1)					; write good parity mode
				dbra	d2,@nextByte			; go check next SIMM

@allParityBank	move.l	d1,(a3)					; restore contents of longword
				move.l	a3,d1					; did we just check location 0?
				bne.s	@restoreNMI				; if not, we're done and parity is on
				movea.l	ExpandMem,a0			; get ptr to expandmem rec
				movea.l	emGestalt(a0),a0		; get gestalt global ptr
				movea.l	memSize(a0),a3			; total amount of memory
				subq	#4,a3					; point to last longword in memory
				bra.s	@checkBank				; go check bank B

@restoreNMI		move	#$2000,sr				; turn interrupts back on
				move.l	d4,AutoInt7				; restore NMI vector
				move.l	(sp)+,d3				; get original state of cache		<17>
				movec	d3,cacr					; restore original state of cache	<17>
				bra.s	@parityOn				; go return that parity is on

; Interrupt handler for checkRPU routine.  It is assumed that the NMI button is
; not pressed during this routine.
;	d3 = stack pointer of routine
;	a1 = RPU base address
;	a4 = return address

@nmiHandler		st.b	rpuReset(a1)			; reset serial ptr
				clr.b	(a1)					; write good parity mode
				st.b	(a1)					; clear the parity error
				move.l	d3,sp					; restore the stack pointer
				jmp		(a4)					; return to the checkRPU routine

@parityOn		bset	#gestaltParityEnabled,d0	; by here it is

@parityOff		bset	#gestaltHasParityCapability,d0	; set parity capability bit

@parityExit		lea		parityValue,a0			; get address of variable in gestalt function
				move.l	d0,(a0)					; save response in gestalt function
				movem.l	(sp)+,a3/a4/d3/d4		; restore registers!							<102>

				ENDWITH


;____________________________________________________________________________
;	Gestalt function patch installation
;
;	These functions either did not make it in the Portable ROM, or changed
;	between ROM final and System Disk final.
;
gestaltRBVAddr		EQU		'rbv '
gestaltSCCReadAddr	EQU		'sccr'
gestaltSCCWriteAddr	EQU		'sccw'
gestaltVIA1Addr		EQU		'via1'
gestaltVIA2Addr		EQU		'via2'
gestaltSlotAttr		EQU		'slot'				; removed in favor of gestaltNuBusConnectors	<95>
gestaltFirstSlot	EQU		'slt1'				; removed in favor of gestaltNuBusConnectors	<95>
gestaltSlotCount	EQU		'nubs'				; removed in favor of gestaltNuBusConnectors	<95>

				lea		gestaltQDVers,a0		; address of gestaltQDVersion patch
				move.l	#gestaltQuickdrawVersion,d0	; selector to REPLACE
				_ReplaceGestalt

				lea		gestaltAddrMode,a0		; addr of gestaltAddressingModeAttr patch
				move.l	#gestaltAddressingModeAttr,d0	; selector to REPLACE
				_ReplaceGestalt

				lea		gestaltParity,a0		; addr of gestaltParityAttr patch
				move.l	#gestaltParityAttr,d0	; selector to REPLACE
				_ReplaceGestalt

				lea		getGestaltVers,a0		; addr of getGestaltVersion patch
				move.l	#gestaltVersion,d0		; selector to REPLACE
				_ReplaceGestalt

				lea		gestaltMisc,a0			; addr of gestaltMisc patch
				move.l	#gestaltMiscAttr,d0		; selector to ADD
				_NewGestalt

				lea		gestaltNBCon,a0			; addr of gestaltNuBusConnectors patch		<95>
				move.l	#gestaltNuBusConnectors,d0	; selector to ADD
				_NewGestalt

				lea		gestaltUndef,a0			; addr of gestaltUndef patch				<95>
				move.l	#gestaltSlotAttr,d0		; selector to REPLACE
				_ReplaceGestalt

				lea		gestaltUndef,a0			; addr of gestaltUndef patch				<95>
				move.l	#gestaltFirstSlot,d0	; selector to REPLACE
				_ReplaceGestalt

				lea		gestaltUndef,a0			; addr of gestaltUndef patch				<95>
				move.l	#gestaltSlotCount,d0	; selector to REPLACE
				_ReplaceGestalt

				lea		gestaltNMgr,a0			; addr of gestaltNotificationMgrAttr patch
				move.l	#gestaltNotificationMgrAttr,d0	; selector to ADD
				_NewGestalt

				lea		gestaltSerial,a0		; addr of gestaltSerialAttr patch			<95>
				move.l	#gestaltSerialAttr,d0	; selector to ADD
				_NewGestalt

				lea		gestaltUndef,a0			; addr of gestaltUndef patch
				move.l	#gestaltRBVAddr,d0		; selector to REPLACE
				_ReplaceGestalt

				lea		gestaltUndef,a0			; addr of gestaltUndef patch
				move.l	#gestaltSCCReadAddr,d0	; selector to REPLACE
				_ReplaceGestalt

				lea		gestaltUndef,a0			; addr of gestaltUndef patch
				move.l	#gestaltSCCWriteAddr,d0	; selector to REPLACE
				_ReplaceGestalt

				lea		gestaltUndef,a0			; addr of gestaltUndef patch
				move.l	#gestaltVIA1Addr,d0		; selector to REPLACE
				_ReplaceGestalt

				lea		gestaltUndef,a0			; addr of gestaltUndef patch
				move.l	#gestaltVIA2Addr,d0		; selector to REPLACE
				_ReplaceGestalt


		IF doScriptMgrGestalt AND (NOT installScriptMgrPtch27) THEN		; <6.1><50>
;____________________________________________________________________________	pke	<2.5>
;	Gestalt install for Script Mgr <2.5> <08/05/89 pke>
;

	import	gestaltScriptMgr,gestaltSMgrTable

	lea	gestaltSMgrTable,a3						; table of Gestalt selectors
												;   and GetEnvirons verbs
@loopInstallGestalt
	move.l	(a3)+,d0							; get next Gestalt selector
	beq.s	@doneInstallGestalt					; 0 means we're done
	addq.l	#2,a3								; skip GetEnvirons verb
	lea		gestaltScriptMgr,a0					; push gestaltFunction ProcPtr
	_NewGestalt
												; ignore OSErr in d0 (what can
												;   we do if it is not noErr?)
	bra.s	@loopInstallGestalt
@doneInstallGestalt

		ENDIF									; <6.1>


;____________________________________________________________________________	dba <3.7>
;	Install default colors 'clut' from System file
;	Since the first InitGraf was before the ROvr code, the ROM 'clut' is
;	always used. We want to use a better 'clut' from the System file.
;	NOTE: This code is straight out of GrafAsm.a.

FixQDColors										;								<4.7>
			cmp.l	#-1,QDColors				; is QDColors initialized?		<4.7>
			beq.s	@done						; no, no need to fix it up		<4.7>

			SUBQ	#4,SP						; make room for function result
			MOVE	#DefQDColors,-(SP)			; push resource ID
			_GetCTable							; get default colors

			MOVE.L	QDColors,a0					; get pointer to QDColors

			MOVE.L	(SP),A1						; get handle to default colors
			MOVE.L	(A1),A1						; point to default colors
			ADD		#CTTable,A1					; skip over header
			MOVEQ	#15,D0						; need to move 16 longs
@nextLong	MOVE.L	(A1)+,(A0)+					; move a long
			DBRA	D0,@nextLong				; => repeat for all longs

			_DisposCTable						; dispose of color table
@done											;								<4.7>


;____________________________________________________________________________	dba	<3.0>
;	Install Menu Manager patches
;

			InstToolTp	NewInitProcMenu,$8
			InstToolTp	NewMenuSelect,$13D


		IF NOT SPLINE_FONT THEN
;____________________________________________________________________________	cel	<5>
;	Install NewRSect Patch for DrawText zero width chars
;
			setTrap	NewRSect,$AB21
		ENDIF


;____________________________________________________________________________	DAF <4.1>
;	This really didn't get in until <5.1>
;
;	Install SetEntries patch


			InstToolTp	mySaveEntries,$249
			InstToolTp	mySetEntries,$23F	; < 124 >

;____________________________________________________________________________	pke <4.6>
;	Install patches to UprString,CmpString,RelString (OK for A/UX)

			InstOSTp	NewUprString,$54
			InstOSTp	NewCmpString,$3C
			InstOSTp	NewRelString,$50

;____________________________________________________________________________	DDG <58>
;	Install vector for the ÒFPU not installedÓ dialog box if we donÕt have an
;	FPU or an MMU

					move.l	#gestaltFPUType,d0			;do we have an FPU ?
					_Gestalt
					cmp.w	#gestaltNoFPU,a0			;if this is NOT noFPU, then we skip
					bne.s	@skipInstall				;..the installation of this patch

					lea		NewFLineRoutine,a0			;get the address of our F-Line routine into A0
					lea		OldFLineRoutine,a1			;get the address of the JMP to the old F-Line routine

					lea		Line1111,A2
					move.l	(A2),2(A1)					; Save the old Vector					<107> SAM
					move.l	A0,(A2)						; Make 1111 traps come to us first		<107> SAM

@skipInstall
;----------------------------------------------------------------------------------------------------


;__________*** This set of routines gets run only if we have a REgret chip ***_________________

			WITH		ProductInfo
														; 							<101> SAM
			MOVE.L		UnivROMFlags,D0					; Do we have a REgret?
			AND.B		#ClockMask,D0					; (bits 4-6)				<107> SAM (Use ClockMask!)
			CMP.B		#ClockEgret,D0					; Is bit 5 on?
			BNE.S		@EndOfEgretOnly					; -> Nope, skip this install code

;----------------------------------------------------------------------------------------------------
; 	This patch bypasses the physical read of egret when reading the time. The time is automatically
;	updated in the background, therefore the low mem global always reflects the acurate time.
;	(REgret only)
;----------------------------------------------------------------------------------------------------

			InstOSTp	RdDateTimePtch,$39

;----------------------------------------------------------------------------------------------------
;	Install the TickHandler Patch into the TickComp vector kept in				<89><101>
;	the Egret Manager Global variables.
;	(REgret only)
;----------------------------------------------------------------------------------------------------

			WITH		EgretGlobals

														; Dont need to turn off IRQs here. 	<107> SAM
		;	move.w		sr,-(sp)						; no interruptions
		;	ori.w		#LVL7IRQ,sr
			lea			TickHandler,a0					; get TickHandler address
			move.l		EgretBase,a1					; point to EgretManager Globals
			move.l		a0,tickComp(a1)					; setup vector to new tick handler
		;	move.w		(sp)+,sr						; restore interrupt state

			ENDWITH
;----------------------------------------------------------------------------------------------------
;	This patch will save the processor status register, call the				<101> SAM
;	ShiftRegIrq routine in Egret Manager and then restore the
;	status register and exits.
;	(REgret only)
;----------------------------------------------------------------------------------------------------

			lea		Vector_hold,a1						; point to the interrupt vector placeholder
			move.l	LVL1DT+8,(a1)						; shift register interrupt handler
			lea		EgretIRQPtch,a1						; Point to the patch
			move.l	a1,LVL1DT+8


;----------------------------------------------------------------------------------------------------
;	This patch fixes possible loss of data to the SCC by calling				<101> SAM
;	the Poll Proc when SCC data is available.
;	(REgret only)
;----------------------------------------------------------------------------------------------------

			InstOSTp	EgretDispatchPtch, $92


@EndOfEgretOnly
			ENDWITH
;__________________________ End of REgret Only Section ______________________________________



;----------------------------------------------------------------------------------------------------
			move.l		MinusOne, $B50					; clean up after netbooting socket listener.<78>
;----------------------------------------------------------------------------------------------------


;____________________________________________________________________________	pke <90>
;	Move Script Mgr patches here so they are installed for A/UX.					<90>
;	Currently assumes that installScriptMgrPtch39 and installScriptMgrPtch27 are
;	true, but this may be changed, so the inner conditionals are being left in.

		IF doScriptMgrForAUX THEN				; <90>

		  IF installScriptMgrPtch39 THEN		; <50>
			PtchInst	39						; <42>
		  ENDIF
		  IF installScriptMgrPtch27 THEN		; <50>
			PtchInst	27						; <5.7>
		  ENDIF

		ENDIF									; <90>


EndBothSection
;=========================================================================================
;=========================================================================================
;=																						 =
;=	ALL PATCHES BELOW THIS POINT ARE INSTALLED ON THE MACINTOSH OS ONLY.  ALL PATCHES	 =
;=	ABOVE THIS POINT ARE INSTALLED BOTH THE MAC OS AND A/UX.							 =
;=																						 =
;=========================================================================================
;=========================================================================================

;	Runtime check to determine whether we are running A/UX.  If so, skip this section
;	of patch install code.

			move.w	HwCfgFlags,d0			; check Ôem the compulsive way
			btst.l	#hwCbAUX,d0				; is it A/UX time?
			bne		skipMacOnlyPatches		; if so skip the mac-only patches



;=========================================================================================
;=========================================================================================
;=																						 =
;=				PATCH INSTALLATION CODE FOR THE MAC OS ONLY STARTS HERE					 =
;=																						 =
;=							Please be neat and follow the format						 =
;=																						 =
;=========================================================================================
;=========================================================================================



;____________________________________________________________________________	ggd	<2.2/2.7>
;	Slot Interrupt patch
;
;	Patches _SIntInstall, and reverses Slot interrupt queue order
;

PatchSIntInstall
			Import	SIntInstall
			With	SlotIntQElement,slotIntGlobals

; We reverse the order of equal priority elements in the queue for Aurora, such that
; they again blissfully agree with what the Mac II does for Equal Priorities

	; turn off interrupts since we are mucking with a queue
			move.w	SR, -(sp)
			ori.w	#HiIntMask,SR		; disable all ints
			InstOSTp SIntInstall,$A075	; install the new trap

	; cycle thru the slots for reversing queue order
			moveq	#TotalSlots-1,d1	; set up for dbra

@nextQueue	lea		([SlotQDT],d1.w*4,slotIntQHeads),a0	; get address of queue header
			movea.l	(a0),a1				; get ptr to first queue element
			clr.l	(a0)				; destroy old queue
			bra.s	@start				; re-install the elements

@loop		movea.l	a1,a0				; set up for SIntinstall
			movea.l	SQLink(a1),a1		; save out ptr to next queue element
			move.l	d1,d0				; set up for call
			_SIntInstall				; re-install the queue element
@start		move.l	a1,d0				; test for end of queue
			bne.s	@loop				; loop until end of queue

@queueDone	dbra	d1,@nextQueue

	; re-enable interrupts now that we are finished mucking
			move.w	(sp)+, SR



;____________________________________________________________________________	djw	<2.4>
;	Slot manager PRAM patch
;
;	Fixes a problem in InitPRAMRecs where when initializing slot PRAM from a
;	PRAM initialization record from the declaration ROM, the board id would
;	not be set correctly.  This code writes the correct board id to the slot
;	PRAM for all good cards.

GetBoardROM	Equ		$0000636E			; addr of GetBoard routine in ROM		<2.7>

			With	spBlock,sInfoRecord
FixSlotPRAM
			suba.w	#spBlockSize,sp		; alloc spBlock
			movea.l	sp,a0				; a0 = ptr to spBlock
			subq.l	#8,sp				; alloc space for pram buffer
			movea.l	sp,a1				; a1 = ptr to pram read/write buffer
			clr.l	(a1)				; clr pram buffer (8 bytes)
			clr.l	4(a1)
			clr.b	spSlot(a0)			; start from slot zero

;	Loop through the slots and check if the board id in PRAM matches the
;	board id on the declaration ROM.  If not, then write the correct one
;	to PRAM.

			move.w	sr,-(sp)			; save status reg
			ori.w	#HiIntMask,sr		; disable interrupts
@Loop
			jsrROM	GetBoardROM			; jsr into ROM to GetBoard routine to get board sRsrc
			bne.s	@EndLoop			; no board sRsrc - skip this slot
			movea.l	spResult(a0),a2		; a2 = ptr to sInfo record
			tst.w	siInitStatusA(a2)	; test card status
			bmi.s	@EndLoop			; bad slot - skip it
			move.b	#Boardid,spId(a0)	; read board id field from board sRsrc
			_sReadWord
			bne.s	@EndLoop			; board id is gone - must be a bad slot
			move.w	spResult+2(a0),d1	; reg d1 = board id from decl rom

			move.l	a1,spResult(a0)		; pass ptr to buffer
			_sReadPRAMRec
			bne.s	@EndLoop			; cannot read PRAM - bad slot

;	Compare PRAM board id with declaration ROM board id.  If different, update
;	the PRAM board id.

			cmp.w	(a1),d1				; same board id's?
			beq.s	@EndLoop			; same - go to next slot
			move.w	d1,(a1)				; update board id in buffer
			move.l	a1,spsPointer(a0)	; set pointer to write buffer
			_InitSlotPRAM

@EndLoop
			addq.b	#1,spSlot(a0)		; inc to next slot
			cmp.b	#sLastSlot,spSlot(a0)
			ble.s	@Loop				; continue till all slots are done

			move.w	(sp)+,sr			; restore interrupts
			adda.w	#spBlockSize+8,sp

			Endwith



;____________________________________________________________________________	djw	<3.6>
;	Slot manager pInitEntry patch
;
;	Install the pInitEntry patch which corrects the spId passed to _sFindDevBase
;	from _InsertSRTRec.
;
			Import	pInitEntry
			lea		pInitEntry,a0						; entry point for resident patch
			move.l	a0,([SDMJmpTblPtr],InitEntry*4)		; insert addr in slot mgr tbl


;____________________________________________________________________________	DAF	<2.6>
;	TFB Video Driver Override
;
			INCLUDE	'VideoPatch.a'

;________________________________________________________________	<4.3><08/21/89 pke>
;	Patch to Pack6 to fix Script Manager routines (which are not
;	supported by A/UX).
;
		IF doScriptMgrPack6Fix AND (NOT installScriptMgrPtch39) THEN			; <42><50>
			InstToolTp	ptchPack6,$1ED
		ENDIF

;____________________________________________________________________________
;	Bump Script Manager version number for IntlForce bug fix (SysVers < $700)	pke <5.3>
;	Set Script Manager version (SysVers >= $700)								pke <5.7>
;	redo using new symbol smgrVersPTCHRom										pke <5.9>

		IF doScriptMgrSetROMVers AND (NOT installScriptMgrPtch39) THEN			; <42><50>
			With		SMgrRecord
			GetSMgrCore	a0
			move.w		#smgrVersPTCHRom,smgrVersion(a0)
			EndWith
		ENDIF

;____________________________________________________________________________
;	Initialize additional Script Manager vectors								pke <5.4>
;	Add CallInterface															pke <5.9>
;	Add NewSwapIcon (7.0 only, moved to ptch 39)								pke <6.2>

		IF doScriptMgrNewVectors AND (NOT installScriptMgrPtch27) THEN			; <42><50>

ROMSMgrCalcRect		EQU		$1E1C2
ROMSMgrInitFonts	EQU		$1E21C
ROMCallInterface	EQU		$1E3B0				; <5.9>

			With		SMgrRecord
			GetSMgrCore	a0
			leaRom	ROMSMgrCalcRect,a1
			move.l	a1,sVectSMgrCalcRect(a0)
			leaRom	ROMSMgrInitFonts,a1
			move.l	a1,sVectSMgrInitFonts(a0)
			leaRom	ROMCallInterface,a1			; <5.9>
			move.l	a1,sVectCallInterface(a0)	; <5.9>
			EndWith
		ENDIF

;____________________________________________________________________________	pke <5.7>
;	Install Script Manager 7.0 extensions, ROM patches
;	Moved these installs up if doScriptMgrForAUX is true.						<90>

		IF NOT doScriptMgrForAUX THEN			; <90>

		  IF installScriptMgrPtch39 THEN		; <50>
			PtchInst	39						; <42>
		  ENDIF
		  IF installScriptMgrPtch27 THEN		; <50>
			PtchInst	27						; <5.7>
		  ENDIF

		ENDIF									; <90>

;____________________________________________________________________________	pke <7.8>
;	Install patches for Script Manager routines InitDateCache, String2Date

		IF doScriptMgrStr2DatFix AND (NOT installScriptMgrPtch39) THEN			; <42><50>
smInitDateCacheOff	equ		-16					; DispTable offset for InitDateCache
smString2DateOff	equ		-20					; DispTable offset for String2Date

			With	SMgrRecord
			GetSMgrCore	a1
			move.l	smgrDispTable(a1),a1

			lea		NewInitDateCache,a0
			move.l	a0,smInitDateCacheOff(a1)
			lea		NewString2Date,a0
			move.l	a0,smString2DateOff(a1)

			EndWith
		ENDIF

;____________________________________________________________________________	pke <8.0>
;	Install Script Manager tail patch to _GetIndADB, fixes the way SwapKybd
;	clears dead key state in ADB keyboard driver data structure

		IF doScriptMgrRstKCHRFix AND (NOT installScriptMgrPtch39) THEN			; <42><50>
			PatchOSJump	oldGetIndADB,$78		; set addr for BackToTrap
			InstOSTp	ptchGetIndADB,$78		; Éand then install patch
		ENDIF


;____________________________________________________________________________	pke <8.5>
;	Install Script Manager patch to LwrString so it handles 2-byte chars

		IF doScriptMgrLwrString2 AND (NOT installScriptMgrPtch27) THEN			; <8.5><50>
			PatchOSJump	oldLwrString,$56		; set addr for BackToTrap
			InstOSTp	ptchLwrString,$56		; Éand then install patch
		ENDIF

;____________________________________________________________________________	EVA <7.1><123>
;	Install Async Serial Driver Vector Address
			Import	SerialPatch
			InstOSTp	SerialPatch,$A0BE

SERDVersion		equ		5
		; install new version number
			move.l	#5*4,d0							; first serial DCE is 5th entry in Utbl
			moveq	#4-1,d1							; index through 4 dce's (adjusted for dbra)
@next		movea.l	UTableBase,a0					; get ptr to the unit table
			movea.l	0(a0,d0.w),a0					; get DCE handle
			movea.l	(a0),a0							; get DCE ptr
			move.w	#SERDVersion,dCtlQueue(a0)		; post new version
			addq	#4,d0							; get next DCE
			dbra	d1,@next


;____________________________________________________________________________	GGD <8.4>
;	Install ADB Polling patch for ViaADB implementations only
;
;	If we are running on a machine with ViaADB (ie. No IOPs), then we allocate a
;	block for this patch, copy the code into it, and install it (saving heap space
;	on machines that don't need it).
;
;	This patch changes Auto/SRQ polling to only poll device addresses which have entries
;	in the device table.

OldFDBShiftInt		equ		$0000a700		; ROM offset of old FDBShiftInt
SendByte2Rtn		equ		$0000A6D0		; ROM offset of return from second @sendNextByte call
GetByte2Rtn			equ		$0000A63C		; ROM offset of return from second @getNextByte call
ROM@sendNextByte	equ		$0000A6E6		; ROM offset of @sendNextByte label
ROM@fetchLoop		equ		$0000A63A		; ROM offset of @fetchLoop label
ROM@handleSRQ		equ		$0000A724		; ROM offset of SRQ handling code
ROM@skipUpdate		equ		$0000A738		; ROM offset of ReqDoneVIA exit without updating ADDR

InstallADBPollPatch
			cmpRA	OldFDBShiftInt,Lvl1dt+8	; see if correct shift int handler to patch
			bne.s	@exit					; if not, don't patch it (might not be VIA based ADB)

			lea		ADBPollPatchStart,a1	; get address of code to copy
			move.l	(a1),d0					; length of code
			_NewPtr	,SYS					; allocate space for the code
			bne.s	@exit					; if couldn't allocate, don't install it

			move.l	(a1)+,d0				; length of code
			exg.l	a0,a1					; setup src/dst for block move
			_BlockMove						; copy the code
			move.l  a1,Lvl1DT+8	       		; install new shift int handler
@exit		bra.w	ADBPollPatchEnd			; jump around patch body


ADBPollPatchStart
			dc.l	ADBPollPatchEnd-ADBPollPatchStart-4
			with	ADBVars
;_______________________________________________________________________
;  Routine:		FDBShiftInt
;  Inputs:		A1 - base address of VIA1 (setup by IntHnd)
;  Outputs:		A1 - base address of VIA1
;				A3 - pointer to ADBBase
;				ccr.z - result of BTST #vFDBInt,vBufB(a1)
;
;  Function:	handles shift interrupt, resumes asynchronous processing
;_______________________________________________________________________

FDBShiftInt	movea.l	ADBBase,a3			; point to ADB globals in low memory
			movea.l	ShiftIntResume(a3),a0	; get address to resume at
			cmpRA	SendByte2Rtn,a0		; see if resuming from sending second byte
			beq.s	SendPatch			; if so, use the patched code
			cmpRA	GetByte2Rtn,a0		; see if resuming from fetching second byte
			beq.s	FetchPatch			; if so, use the patched code
			btst.b	#vFDBInt,vBufB(a1)	; test the FDBInt~ status
			jmp		(a0)				; resume async processing


SendPatch	btst.b	#vFDBInt,vBufB(a1)	; test the FDBInt~ status
			bne.s	@sendLoop			; if no SRQ, send the data
			bset.b	#fDBSRQ,FDBAuFlag(a3)	; remember that a service request was returned

@sendLoop	tst.b	fDBCnt(a3)			; see if end of buffer reached
			beq.s	ReqDoneVIA			; leave when count is zero, no reply data
			jsrROM	ROM@sendNextByte	; send another byte
			bra.s	@sendLoop			; loop until count exhausted


FetchPatch	btst.b	#vFDBInt,vBufB(a1)	; test the FDBInt~ status
			beq.s	@fetchDone			; exit if end of data reached
			cmpi.b	#8,fDBCnt(a3)		; see if end of buffer reached
			bhs.s	@fetchDone			; keep fetching until end of data
			jmpROM	ROM@fetchLoop
@fetchDone	btst.b	#fDBNoReply,FDBAuFlag(a3)	; see if buffer data is valid
			seq.b	d0					; $FF if data is valid, $00 if no reply
			and.b	d0,fDBCnt(a3)		; set count to zero if timeout
*			bra.s	ReqDoneVIA


ReqDoneVIA	move.b	FDBAuFlag(a3),d0	; get the flags
			move.b	fDBCmd(a3),d1		; get the command
			moveq.l	#(1<<fDBSRQ),d3		; mask to test for SRQ pending
			and.b	d0,d3				; isolate the bit
			neg.l	d3					; set bit 31 if SRQ pending
			move.b	d1,d3				; insert the command byte

			lsr.b	#4,d1				; isolate the device address
			tst.l	d3					; was there an SRQ?
			bpl.s	@noSRQ				; if not, don't advance poll address
			jmpROM	ROM@handleSRQ		; otherwise, go handle the SRQ
@noSRQ		move.w	DevMap(a3),d2		; list of possible address to search
			btst.l	d1,d2				; see if it is in the table
			beq.s	@skipUpdate			; if not, don't switch to that address
			move.b	d1,PollAddr(a3)		; remember where to auto/SRQ poll next
@skipUpdate	jmpROM	ROM@skipUpdate		; back to ROM, just past the update
ADBPollPatchEnd

;	End of ADB Polling patch for ViaADB implementations
;____________________________________________________________________________	GGD <8.4>


;____________________________________________________________________________	GGD <8.4>
;	Install a Time Manager Task to simulate the 60.15Hz pseudo VBL for OSS based systems.
;
;	If we are running on a machine with an OSS, then we allocate a block for this patch,
;	copy the code into it, and install it (saving heap space on machines that don't need it).
;
;	This patch corrects the pseudo VBL frequency on OSS based systems, the OSS generates
;	a 60.00Hz interrupt, but the Macintosh Pseudo VBL rate should be 60.14742 Hz.
;	To correct this, we simply ignore and disable the OSS interrupt, and use the
;	Time Manager to generate interrupts at the correct rate.

FixMPWShell				equ		1			; Temporarily fix CMD-Period 					<25>
;	This same patch is also modified to fix a problem in the MPW Shell on Zone-5.
;	The real bug is in the MPW Shell, but we will temporarily fix it here until they
;	have a chance to rev, so that we don't hear bitching from developers.
;	The MPW Shell will sometimes cut back the stack from within a patch they make to
;	PostEvent, when CMD-Period is pressed.  Therefore, it may never return back to the
;	keyboard driver, which never returns to the ADBManager, which never returns to the
;	IOP Manager, which never returns to the Deferred Task Manager, which never returns
;	to the Interrupt Handler, which never returns to whatever code was running at the
;	time of the interrupt (which may have been another interrupt).  This causes data
;	structures to be left in inconsistent states, such as the deferred task manager thinks
;	that a deferred task is still running, and won't run any new tasks.
;	The work around is to not run ADB as a deferred task, and instead run it at level 1		<25>

ROMLevel1OSSInt			equ		$00009B50	; ROM offset of old Level1OSSInt
ServiceIntMMU			equ		$00009B68	; ROM offset of ServiceIntMMU
	if FixMPWShell then						;												<25>
IOPInterrupt			equ		$00005036	; ROM offset of IOP Manager interrupt handler	<25>
ContinueOssLevel1Decode	equ		$00009D8E	; ROM offset of continuation of OssLevel1Decode	<25>
	else									;												<25>
ContinueOssLevel1Decode	equ		$00009D88	; ROM offset of continuation of OssLevel1Decode
	endif									;												<25>
OssVBL60HzInt			equ		$00009DF0	; ROM offset of OssVBL60HzInt

IntRegs		reg		a0-a3/d0-d3				; registers saved by all interrupt handlers

			bra.s	Oss60HzPatchEnd			; skip over patch body into install code

Oss60HzPatchStart

Oss60HzTimeHandler
			movea.l	a1,a0					; point to the TMTask
			move.l	#-16626,d0				; 16.626 ms, 60.14742 Hz (pseudo VBL rate)
			movea.l	jPrimeTime,a1			; point to the routine
			jsr		(a1)					; initiate the delay
			movea.l	OSS,a1					; get OSS chip base address
			jmpROM	OssVBL60HzInt			; run the VBL interrupt

OssLevel1Decode
			movea.l	OSS,a1					; get OSS chip base address
			move.w	OSSIntStat(a1),d0		; see who is interrupting
			bclr.l	#OSSIntVBL60Hz,d0		; ignore OSS 60Hz pseudo VBL interrupt
	if FixMPWShell then						;												<25>
			btst	#OSSIntIOPSWIM,d0		; check SWIM IOP first							<25>
			beq.s	OSSPSwmMasked			; if no SWIM IOP Interrupt, skip it				<25>
			moveq.l	#7,d1					; mask for int level							<25>
			and.b	OSSMskPSwm(a1),d1		; see if SWIM IOP was disabled					<25>
			beq.s	OSSPSwmMasked			; if disabled, ignore it						<25>
			move.l	#(%00001000<<24)+\		; allow xmt msg 3 (ADB)							<25>
					(%00001000<<16)+\		; allow rcv msg 3 (ADB)							<25>
					(0<<8)+\				; this byte must be zero						<25>
					1,d0					; ADB is on SWIM IOP (IOP 1)					<25>
			jmpROM	IOPInterrupt			; handle the interrupt and return				<25>
OSSPSwmMasked								;												<25>
	endif									;												<25>
			jmpROM	ContinueOssLevel1Decode	; resume with the ROM code


Level1OSSInt
			movem.l IntRegs,-(SP)			; preserve registers
			lea		OssLevel1Decode,a3		; use the OSS level 1 dispatcher
			jmpROM	ServiceIntMMU			; call primary interrupt dispatcher

Oss60HzPatchEnd
@PatchSize	equ		Oss60HzPatchEnd-Oss60HzPatchStart

			cmpRA	ROMLevel1OSSInt,AutoInt1; see if we have an OSS interrupt handler
			bne.s	@done					; if not, don't need to install it

			moveq.l	#tmXQSize+@PatchSize,d0	; space needed
			_NewPtr	,Sys,Clear				; allocate it
			bne.s	@done					; if can't allocate, don't install
			movea.l	a0,a2					; save a copy
			lea		Oss60HzPatchStart,a0	; source address
			lea		tmXQSize(a2),a1			; dest address
			moveq.l	#@PatchSize,d0			; byte count
			_BlockMove						; copy the code

			lea		Oss60HzTimeHandler-Oss60HzPatchStart(a1),a0	; point to the handler
			move.l	a0,tmAddr(a2)			; initialize the task address
			movea.l	a2,a0					; get the time manager task address
			move.l	#'eada',(a0)			; put in magic signature (see VM for details)	<139>
			_InsXTime						; install the task (fixed frequency)

			move.l	#-16626,d0				; 60.14742 Hz (pseudo VBL rate)
			movea.l	jPrimeTime,a2			; point to the routine
			lea		Level1OSSInt-Oss60HzPatchStart(a1),a1

			move.l	Ticks,d1				; get the current time
@sync		cmp.l	Ticks,d1				; sync with the VBL manager
			beq.s	@sync					; wait for it to change

			move.w	sr,-(sp)				; save old int level
			ori.w	#HiIntMask,sr			; disable all ints

			move.l	a1,AutoInt1				; install the new level 1 handler

			movea.l	OSS,a1					; get the OSS base
			clr.b	OSSMsk60Hz(a1)			; disable the OSS 60Hz interrupt source
			move.w	(sp)+,sr				; restore the interrupt level

			jsr		(a2)					; start the pseudo VBL timer
@done

;	End of OSS VBL frequency patch
;____________________________________________________________________________	GGD <8.4>


;____________________________________________________________________________	SWC <8.8>
;	RecoverHandle() patch for 32-bit Memory Manager

			IMPORT	v24RecoverHandle,v32RecoverHandle

JRecoverHandle EQU	$6C						;offset into 32-bit Memory Manager's vector table

			LEA		v24RecoverHandle,A0		;patch in the 24-bit version of RecoverHandle
			MOVE.L	A0,JMemMgr24+JRecoverHandle
			LEA		v32RecoverHandle,A0		;patch in the 32-bit version of RecoverHandle
			MOVE.L	A0,JMemMgr32+JRecoverHandle

;	End of RecoverHandle() patch install
;____________________________________________________________________________	SWC <8.8>


;____________________________________________________________________________	RMP <12>
;	SetHandleSize() patch for 32-bit Memory Manager

			IMPORT	v32SetHandleSize

JSetHandleSize EQU	$64						;offset into 32-bit Memory Manager's vector table

			LEA		v32SetHandleSize,A0		;patch in the 32-bit version of SetHandleSize
			MOVE.L	A0,JMemMgr32+JSetHandleSize


;	End of SetHandleSize() patch install
;____________________________________________________________________________	RMP <12>



;____________________________________________________________________________	CSL
;	SetPtrSize() patch for 32-bit Memory Manager

			IMPORT	v32SetPtrSize

JSetPtrSize EQU	$4C							;offset into 32-bit Memory Manager's vector table

			LEA		v32SetPtrSize,A0		;patch in the 32-bit version of SetPtrSize
			MOVE.L	A0,JMemMgr32+JSetPtrSize


;	End of SetPtrSize() patch install
;____________________________________________________________________________	CSL

	IF	0 THEN
;____________________________________________________________________________	jwk <19>
;
;	Patch in FastReadOSS() and FastWriteOSS() ROM routines to use the SCSIDMA chip.
;
			WITH	ROMHeader, scsiGlobalRecord

ROMFastWriteOSS		EQU		$00009042
ROMFastReadOSS		EQU		$000092ea

			cmpi.b	#boxF19,BoxFlag				; is it an F19 ?
			bne.s	@jwkNoInstall				; only applies to F19's
			move.w	#$11f0,d0					; check for any final F19 ROM
			movea.l	ROMBase,a1					; point to the base of the ROM
			and.w	ROMRelease(a1),d0			; we'll take 1.1f1, 1.1f2, etc.
			cmpi.w	#$11f0,d0					; is it a 1.1fÉ ROM ?
			bne.s	@jwkNoInstall				; only install on a Zone5 with 1.1fÉ ROM's

; <57> 04-22-90 csd
; commented out the installation of SCSI DMA so we stop trashing
; hard disks on the IIfx.

			movea.l	SCSIGlobals,a1				; point to SCSI Manager globals
			move.l	#250*10000,G_Reserved1(a1)	; set up 250ms byte-to-byte timeout
			leaROM	ROMFastWriteOSS,a0
;			move.l	a0,jvVFWO(a1)				; use DMA code for SCSIWBlind
			leaROM	ROMFastReadOSS,a0
;			move.l	a0,jvVFRO(a1)				; use DMA code for SCSIRBlind
@jwkNoInstall

			ENDWITH
;
;	End of FastReadOSS() and FastWriteOSS() patch install
;____________________________________________________________________________	jwk <19>
	ENDIF

;____________________________________________________________________________	jwk <29>
;
;	Patch in chaining SCSI bus error handler
;
			TestFor	SCSI96_1Exists			; check universal tables for C96 SCSI Chip		<3>
			bne.s	@ChaningBErrDone		; has C96 - do not install patch (or die)		<3>

			WITH	scsiGlobalRecord

			movea.l	SCSIGlobals,a1				; point to SCSI Manager globals
			lea.l	BusErrHandler,a0			; point to bus error handler patch
			move.l	a0,jvBusErr(a1)				; patch vector in the globals

			ENDWITH
@ChaningBErrDone

;_________________________________________________________________________________________	<119> djw
;	Install SCSI fix for Quantum 7.9 rom fix

			with	scsiGlobalRecord

;	Check the universal tables in this ROM version for a SCSI DMA chip (the GDU).  If
;	the GDU exist, then we must be on a Mac IIfx (dammed overpatch ROM's).  The Quantum
;	fix cannot be applied to the IIfx because on the GDU, *ACK cannot be controlled.

			TestFor	SCSIDMAExists			; check universal tables for SCSI DMA
			bne.s	@noSCSIpatch			; has SCSI DMA - do not install patch

			TestFor	SCSI96_1Exists			; check universal tables for C96 SCSI Chip		<136>
			bne.s	@noSCSIpatch			; has C96 - do not install patch (or die)		<136>
				
;	Apply the patch to this Mac IIci family ROM

			lea		QuantumWBlindIIci,a0		; a0 = TIB interpreter patch
			move.l	a0,jvWBlind(a1)				; replace vector

			lea		FastWriteFix,a0				; patch to FastWrite data xfer routine
			move.l	a0,jvVFWO(a1)				; virtual fast writes (hhsk)
			move.l	a0,jvVFW(a1)				; virtual fast writes (hhsk)
@noSCSIpatch

;_________________________________________________________________________________________	<122> djw
;	Install SCSIDispatch patch for VM conflict
;
;	Patch SCSIDispatch back to ROM to avoid the situation where VM patches SCSIDispatch
;	before patches, and after patches.  VM will be in the chain of patches twice.  This
;	coupled with the SCSI mgr calling the file system gets into a circular calling sequence
;	of the SCSI mgr calling VM and VM calling the SCSI mgr.

@ROMSCSIDispatch	Equ		$00007460			; offset to SCSIDispatch in ROM

			movea.l	RomBase,a0					; get base of ROM
			adda.l	#@ROMSCSIDispatch,a0		; add offset to SCSIDispatch in ROM
			setTrapA0	$a815					; patch SCSIDispatch to ROM

;____________________________________________________________________________
;
;	<54> Install patch to IOPMsgRequest to fix IOP Serial Driver Ctrl Call bug
;____________________________________________________________________________
		IMPORT 	IOPMsgRequest

			move.w	sr, -(sp)				; disable interrupts while we patch
			ori.w	#HiIntMask,sr

;
; Install the patch only if IOPMsgRequest trap already exists
;
			gettrapA0	$A087				; get IOPMsgRequest trap addr
			move.l		a0,a1				; set it aside
			gettrapA0	$A89F				; get unimplemented trap addr
			cmpa.l		a0,a1				; check 'em
			beq.s	@noTrap					; nope, so don't install patch

			PatchOSJump	oldIOPMsgRequest,$87	; Stash original IOPMsgRequest routine					<12>
			InstOSTp	IOPMsgRequest,$87		; replace IOPMsgRequest trap							<12>
@noTrap

; restore state
			move.w	(sp)+,sr				; disable interrupts while we patch

;____________________________________________________________________________
;
;	<54> End Install patch to IOPMsgRequest to fix IOP Serial Driver Ctrl Call bug
;____________________________________________________________________________


;____________________________________________________________________________	GGD <28>
;	Patch the Deferred Task Manager Task Dispatcher to re-enable interrupts upon
;	exiting to fix QuickMail servers (for now at least), because they call through
;	jDisptch at application level and wind up with all interrupts being masked,
;	and the Task Dispatcher expects to only be called from then end of an interrupt
;	handler, which will restore the interrupt level via an RTE.

			PatchOSJump	ROMvDisptch,$B9		; set addr for BackToTrap
			InstOSTp	NewvDisptch,$B9		; Éand then install patch

;	End of Deferred Task Manager Task Dispatcher Patch Installation
;____________________________________________________________________________	GGD <28>

;____________________________________________________________________________	EH <4>
;	Patch the secondary dispatcher for the Level 4 IOP interrupt handler
;
;	This patch fixes some of the serial thruput problems encountered on Apollo
;	and the TimLC when the CPUs are running in 24 bit mode. These are the first (slow)
;	machines to run in 32 bit mode a good portion of the time. Every time we 
; 	take an interrupt the primary interrupt handler switches the CPU into 24 bit
;	mode, forcing cache flushes and generally incurring a lot of overhead. At high
;	serial baud rates, this overhead interferes with our ability to keep pace.
;
;	The solution is to NOT take an interrupt for each received character, but 
;	rather to empty out the SCC FIFO before returning to the primary interrupt
;	dispatch. So we patch the secondary dispatcher to call the serial driver's
;	interrupt routines, rather than jumping to them. The service routine then
;	returns to the secondary dispatcher, with checks to see if there is another
;	character available on either port. If there is another character pending,
;	the secondary dispatch routine loops to dispatch to the new interrupt (that
;	must be pending) rather than returning to the primary dispatcher (and incurring
;	the overhead).
;
;	we do this ONLY FOR CHANNEL A, since it's the only one that's documented to be
;	fast, and also so that appletalk won't pound us at its 230Kbaud rate.
;	
;	The Serial Driver Rx and SC interrupt service routines are patched in conjuction
;	with this so that if a device manager request completes, we exit to the primary
;	dispatcher regardless of whether a character is pending. This way we exit the
;	interrupt handlers completely at least once per device manager request, allowing
;	things like deferred tasks to run more in sequence.
;
;	<6> fix the Farallon MacRecorder bug
;	modified patch to test for port A RxChar and loop back only if we are servicing
;	a channel A interrupt. For port B we just jump to service routine like ROM code.
;	
;	<7> fix patch <6>
;	Port B dispatcher fixed to call serial service routines and to have same number
;	of bytes before the rts so that async serial driver Rx and SCx patches (which
;	fiddle with return address on stack) return to the proper place.
;
;	<10> for VM, patch level 4 autovector pointed to by vbr, not just the zero-offset.
			
			
ROMLevel4SccInt		equ		$00009b20				; ROM offset of old SCCIOPBypassInt
IntRegsSize			equ		8*4						; size of IntRegs in bytes, must change if IntRegs changes
SccDT				equ		Lvl2DT					; Dispatch table for SCC interrupts

					bra.s	SCCPatchEnd				; branch to install code
SCCPatchStart

;
; this is the secondary dispatcher code we are patching
;
SCCIOPBypassInt
SccDecode	MOVE.L	SCCRd,A0						; get SCC read address
			MOVE.B	(A0),D0 						; read to sync up SCC (just to be safe)
			MOVE.L	SCCWr,A1						; get SCC channel B write control address
SccDecodeCommon
			MOVE.B	#2,(A1) 						; point to SCC register 2, B channel
			LEA 	SccDT,A2						; point to dispatch table and delay
			MOVEQ	#$0E,D0 						; 'and mask' and extra delay
			AND.B	(A0),D0 						; read the modified interrupt vector
			CMPI.B	#8,D0							; channel A interrupt?

			bge.S	@GoChannelA						; branch if for A						<6>					
			MOVE.L	0(A2,D0.W*2),A2					; get dispatch vector					<6>
			jsr 	(A2)							; call service routine					<6>	<7>
			bra.s	@fixedRTS						; fill in the 10 bytes as for port	A 		<7>
			dcb.b	8,0								; so that Rx,SCx handlers return properly	<7>
@fixedRTS	rts

@GoChannelA											;										<6>
			ADDQ	#2,A0							; adjust SCC addresses for port A
			ADDQ	#2,A1
@GoLvl2
			MOVE.L	0(A2,D0.W*2),A2					; get dispatch vector
			jsr 	(A2)							; call service routine					<6>
; note we return here UNLESS we finish a device manager request
; note this is 10 bytes-- CHANGE THE SCC RxIntHnd patch equate if this changes!!!!!
			movea.l	SCCRd,a0						; point to SCC read base address		<6>				
			btst.b	#RxCA,2(a0)						; SCC data available on channel A?		<6>
			bne.s	SCCDecode						; data available, so dispatch again		<6>
; note we return here if we are finishing a device manager request
			rts										; return to primary dispatcher			<6>

SCCIOPBypassIntEnd									; for IOP patch below					<7>
SCCIOPBypassIntSize	equ	SCCIOPBypassIntEnd-SCCIOPBypassInt;									<7>
;
;
; this is the primary  dispatch code we patch in order to get to the secondary dispatcher
;
Level4SccInt
			movem.l IntRegs,-(SP)					; preserve registers
			lea		SCCIOPBypassInt,a3				; use the SCC IOP interrupt dispatcher
			jmpROM	ServiceIntMMU					; call primary interrupt dispatcher

SccPatchEnd
@SccPatchSize	equ		SccPatchEnd-SccPatchStart

;
; this is the install code for the patch
;
			cmpRA	ROMLevel4SccInt,AutoInt4		; see if we have an SCC bypass interrupt handler
			bne.s	@done							; if not, don't need to install it

			moveq.l	#@SccPatchSize,d0				; space needed
			_NewPtr	,Sys,Clear						; allocate it
			bne.s	@done							; if can't allocate, don't install
			movea.l	a0,a1							; dest address
			lea		SccPatchStart,a0				; source address
			moveq.l	#@SccPatchSize,d0				; byte count
			_BlockMove								; copy the code

			move.w	sr,-(sp)						; save old int level
			ori.w	#HiIntMask,sr					; disable all ints
			lea		Level4SccInt-SccPatchStart(a1),a1 ; get offset to primary dispatcher code
			move.l	a1,AutoInt4						; install the new level 4 handler
			movec	vbr,a0							; get the vbr in case VM moved it		<10>
			move.l	a1,AutoInt4(a0)					; install the new level 4 handler		<10>
			move.w	(sp)+,sr						; restore the interrupt level
@done

;	End of Lvl4Int secondary dispatcher patch
;____________________________________________________________________________	EH <4>

;____________________________________________________________________________	EH <30>
;	Patch the SCCIOP interrupt handler to set all completion flags to immediate.
;
;	If we are running on a machine with an OSS, then we allocate a block for this patch,
;	copy the code into it, and install it (saving heap space on machines that don't need it).
;
;	This patch fixes things so that TIMBUKTU/REMOTE, slime code that it is, will
;	run on a Zone 5 in IOP mode. Timbuktu/Remote makes SYNCHRONOUS read calls to
;	the IOP Serial driver FROM A VBL TASK. Sometimes the VBL gets called when the
;	IOP Manager completion routine (for a call from the serial driver) is waiting
;	to run (as a deferred task).
;	The result is that the synchronous call waits in the Device Manager for IODone
;	to be called, but IODone is called by the serial driver, which is returned to
;	from the IOP Manager completion routine, which is NEVER returned to because we
;	made a synchronous call from an elevated interrupt level and are now just sitting
;	in a loop in the device manager: DEADLOCK.
;
;	The reason Timbuktu/Remote worked on previous Macs is that the bypass driver
;	does NOT use a deferred task to call IODone.
;
;	The work around is to not call the IOP Manager completion routines for the SCC
;	as deferred tasks, but instead call them at level 1 (immediately).
;
;	<10> for VM, patch level 4 autovector pointed to by vbr, not just the zero-offset.

ROMLevel4SccIopInt		equ		$00009B10	; ROM offset of old Level4SccIopInt

			bra.s	SccIopPatchEnd				; skip over patch body into install code

SCCIopPatchStart
SCCIopInt
			move.l	#(%11111111<<24)+\		; complete xmt msgs 0..7 immediate
					 (%11111111<<16)+\		; complete rcv msg 0..7 immediate
					 (0<<8)+\				; this byte must be zero
					 0,d0					; SCC IOP number 0
			jmpROM	IOPInterrupt			; handle the interrupt and return

Level4SccIopInt
			movem.l IntRegs,-(SP)		; preserve registers
			lea		SccIopInt,a3		; use the SCC IOP interrupt dispatcher
			jmpROM	ServiceIntMMU		; call primary interrupt dispatcher

SccIopPatchEnd
@SccIopPatchSize	equ		SccIopPatchEnd-SccIopPatchStart


			cmpRA	ROMLevel4SccIopInt,AutoInt4; see if we have an SCC IOP interrupt handler
			bne.s	@done					; if not, don't need to install it

			moveq.l	#@SccIopPatchSize,d0			; space needed
			_NewPtr	,Sys,Clear						; allocate it
			bne.s	@done							; if can't allocate, don't install
			movea.l	a0,a1							; dest address
			movea.l	a0,a2							; save dest addr					<7>
			lea		SccIopPatchStart,a0				; source address
			moveq.l	#@SccIopPatchSize,d0			; byte count
			_BlockMove								; copy the code

;patch the bypass interrupt handler
			moveq.l	#SCCIOPBypassIntSize,d0			; space needed
			_NewPtr	,Sys,Clear						; allocate it
			bne.s	@done							; if can't allocate, don't install
			movea.l	a0,a1							; dest address
			lea		SCCIOPBypassInt,a0				; source address
			moveq.l	#SCCIOPBypassIntSize,d0			; byte count
			_BlockMove								; copy the code

; install the patches			
			move.w	sr,-(sp)						; save old int level
			ori.w	#HiIntMask,sr					; disable all ints

			movea.l	IOPmgrVars,a0					; get IOP mgr globals				<7>
			move.w	#SccIopNum,d0					; get SCC IOP number as index		<7>
; fortunately the IOPInfoPtrs are declared at offset zero to IOPMgrVars					<7>
; as shown here below																	<7>
; IOPMgrGlobals	record	{IOPInfoPtrs},increment		; globals used by the IOP manager	<7>
			move.l	(a0,d0.w*4),d0					; get SCCIOP info pointer			<7>
			move.l	d0,a0							;									<7>
		with IOPInfo								;									<7>
			move.l	a1,BypassHandler(a0)			; a1-> secondary SCC dispatcher		<7>
		endwith										;									<7>

			lea		Level4SccIOPInt-SccIopPatchStart(a2),a1	;a2-> primary handler		<7>
			move.l	a1,AutoInt4						; install the new level 4 handler
			movec	vbr,a0							; get the vbr in case VM moved it	<10>
			move.l	a1,AutoInt4(a0)					; install the new level 4 handler	<10>
			move.w	(sp)+,sr				; restore the interrupt level

@done

;	End of SccIopInt patch
;____________________________________________________________________________	EH <30>

;____________________________________________________________________________	 EH <33>
;
;	Install patch to IOPMoveData to fix IOP Serial Driver DMA Hang bug
;
			IMPORT 	IOPMoveData
	;save state
			move.w	sr, -(sp)				; disable interrupts while we patch
			ori.w	#HiIntMask,sr
			movem.l	a0/d0-d1,-(sp)			; save some registers

	; Install patch only if IOPMoveData trap already exists
			clr.l	d0						; clear result
			move.w	#UnimplementedTrap,d0	; get loc of unimplemented trap
			_GetTrapAddress ,newTool		; get the address into A0
			move.l	a0,d1					; save it for a sec
			move.l	#$A088,d0				; trap ID to check for IOPMoveData
			_GetTrapAddress ,NewOS			; get the address of it
			cmp.l	a0,d1					; is it implemented?
			beq.s	@noTrap					; nope, so don't install patch


			PatchOSJump	oldIOPMoveData,$88	; set addr for BackToTrap
			InstOSTp	IOPMoveData,$88		; implemented, so install new trap addr

@noTrap

	; restore state
			movem.l	(sp)+,a0/d0-d1			; restore saved registers
			move.w	(sp)+,sr				; disable interrupts while we patch

;
;
;	End Install patch to IOPMoveData to fix IOP Serial Driver DMA Hang bug
;____________________________________________________________________________	 EH <33>


;____________________________________________________________________________	 <10> <cch 8/6/91>
;
;	Install patch to getPageDesc and _VM.  These patches take effect only on
;	68030 machines with the Terror ROM, version $67c, sub-version 1.5 when VM
;	is disabled.
;
ROMVers			EQU		$08
ROMSubVers		EQU		$12
VMGlobals		EQU		$b78

			IMPORT 	GetPageDescPatch
			
	; check to see if we're on the Terror ROM, subversion 1.5.
	
			cmp.b	#cpu68030,CPUFlag			; check if we're on an 030
			bne.s	@skipPatch					; ignore if not
			move.l	RomBase,a0					; get base of ROM
			cmp.w	#TERRORmajorVers,ROMVers(a0); check major version
			bne.s	@skipPatch					; ignore if incorrect version
			cmp.b	#TERRORminorVers,ROMSubvers(a0); check subversion
			bne.s	@skipPatch					; ignore if incorrect version
			tst.l	VMGlobals					; check if VM is running
			bpl.s	@skipPatch					; ignore if VM is on
	
	; patch _Gestalt		
			PatchOSJump	origGestalt,$AD			; set addr for BackToTrap to orig _Gestalt
			InstOSTp	GetPageDescPatch,$AD	; implemented, so install new trap addr

			PatchOSJump	origMemDisp,$5C			; set addr for JsrTrap back to orig _VM
			PatchOSJump	origMemDisp1,$5C		; set addr for BackToTrap back to orig _VM
			InstOSTp	MemDispPatch,$5C		; implemented, so install new trap addr

@skipPatch
;
;
;	End Install patch to getPageDesc proc
;____________________________________________________________________________	 <10> <cch 8/6/91>


;____________________________________________________________________________	 <13> <cch 8/28/91>
;
;	Install patch to flush after backpatching fp68k calls made from ROM on 
;	68030 running Terror.
;
FP68kPatchInstall
	; check to see if we're on the Terror ROM, subversion 1.5.
			cmp.b	#cpu68030,CPUFlag				; check if we're on an 030
			bne.s	@skipPatch						; ignore if not
			move.l	RomBase,a0						; get base of ROM
			cmp.w	#TERRORmajorVers,ROMVers(a0)	; check major version
			bne.s	@skipPatch						; ignore if incorrect version
			cmp.b	#TERRORminorVers,ROMSubvers(a0)	; check subversion
			bne.s	@skipPatch						; ignore if incorrect version
	
			MOVE.W	HwCfgFlags,D0					; Get them Hardware Config Flags	<14> SAM
			BTST.L	#hwCbFPU,D0						; Does we gots an FPU?				<14>
			BEQ.S	@skipPatch						; -> No, don't patch				<14>

	; patch _FP68k ($A9EB)		
			PatchToolJump	origFP68k,$1EB			; set addr for BackToTrap to orig _Gestalt
			InstToolTp		FP68kPatch,$1EB			; implemented, so install new trap addr

@skipPatch
;
;
;	End Install patch to fp68k
;____________________________________________________________________________	 <13> <cch 8/28/91>

EndMacSection
;=========================================================================================
;=========================================================================================
;=																						 =
;=						END OF MAC-ONLY INSTALL CODE SECTION							 =
;=																						 =
;=========================================================================================
;=========================================================================================

skipMacOnlyPatches							; above code is for Mac OS only

;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
;############################### END PATCH INSTALL CODE #################################
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

CalcPatchSize
			Lea		StartPatch,A1			; start of patch code
			Lea		EndOfPatch,A0			; end of patch code
			Sub.l	A1,A0					; calc size of resident code
			Move.l	A0,D0					; SetHandleSize takes new size in D0
			Move.l	(SP)+,A0				; restore the handle passed by SysPatch

			Bra		CutBack					; go cut the install code off and exit

			ENDPROC

			UsesPtchInst					; Patchinstll code Macro		<1.1-4april89-CEL>

; added Proc FixupTbl from PatchIIROM.a <24July89smb>
		Proc
		Export		FixupTbl

;################## TABLE OF LOCATIONS TO BE OFFSET BY [ROMBase]  ####################
;
;	Table contains one entry for each reference to a ROM address from the
;	JmpROM, JsrROM, and CmpRA macros.  &RomFixIndex is a count of the total
;	number of these references, and is also used to synthesize the label
;	names for them.  The reference labels have the form
;		RXXX000, RXXX001, RXXX002, ...
;	See the Macro definitions for JmpROM, JsrROM and CmpRA (near the top of
;	this file) for more info.
;
;	MkTbl is a macro only because assembler while loops will not work
;	outside of macros.
;
				MACRO
				MkTbl
				gbla		&RomFixIndex
				while		&RomFixIndex <> 0 do
&RomFIxIndex 		seta	&RomFixIndex - 1
					dc.l	RXXX&I2S(&ROMFIXINDEX,-3) - FixUpTbl
				endwhile
				dc.l		0			; Zero entry marks end of table
				ENDM

FixupTbl		MkTbl

;########################### END PATCHES CUT BACK CODE ################################

		EndProc
		END