sys7.1-doc-wip/OS/Universal.a

2861 lines
120 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;__________________________________________________________________________________________________
;
; File: Universal.a
;
; Contains: This module provides Data structures and routines to support Universal ROMs.
; It can also be used in Non-Universal ROMs to provide tables for initializing
; base addresses and hardware.
;
; Written by: Gary G. Davidian
;
; Copyright © 1989-1993 by Apple Computer, Inc. All rights reserved.
;
; Change History (most recent first):
;
; <SM62> 12/17/93 PN Fix the test for Pratt decoder
; <SM61> 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ
; machines.
; <SM60> 12/7/93 BG Modified the Frigidaire entries in the djMEMC @MachineTbl to
; properly reflect the VIA PortA values for CPU ID+Speed.
; <SM59> 11/17/93 KW forSTP601 in GetCPUIDReg to or in Risc product to the id.
; <SM58> 11/9/93 KW made some changes for STP machines. changes are conditionalized
; by forSTP601
; <SM57> 9/26/93 KW (H35 BG) Modified the djMEMC memory controller setup so that it
; chooses between Wombats and Speedbumped Wombats and initializes
; the memory controller to use a different set of wait states for
; the Speedbumped machines. This is because the Speedbump'ed
; units do not want to have to use faster-speed DRAM, which
; currently the Quadra 800 (Wombat33inFridge) requires. The
; Speedbumped 650 (Wombat33inLego) will expect 80ns DRAM, just as
; the Centris650 (Wombat25inLego) did.
; <SM56> 8/13/93 KW adding two more smurf wombats
; <SM55> 8/12/93 BG Changed various Cyclone-related boxflags to their official
; names.
; <SM54> 8/11/93 KW made the forSmurf check in GetCPUIDReg dynamic. Currently
; recoginizes Quadra700/900/950 and Centris610/650 quadra800
; <SM53> 7/27/93 GMR Added routine to do a runtime check for BART (on PDM).
; <SM52> 7/2/93 PN Add conditional for export hasCPUIDregs
; <SM51> 6/29/93 SAM (PDW) Added code to check for a cf96 in GetCPUID (for
; PDM/ColdFusion).
; <SM50> 6/14/93 kc Roll in Ludwig.
; <LW7> 4/29/93 fau Updated the Cyclone/Tempest timing to 120ns ROMS for final
; shipment.
; <SM49> 6/3/93 SAM Exporting GetCPUIDReg.
; <SM48> 5/10/93 SAM Added a few nops in the PDM specific CPU ID check.
; <SM46> 4/26/93 RC Get ride of warning due to bra.s
; <SM45> 4/21/93 joe Added hack to GetCPUIDReg for PDM EVT2. (CPUID register doesn't
; work right, so use extra bits in SCSI DMA Ctl reg to check for
; AMIC2.)
; <SM44> 4/20/93 joe Added to PDM-style CPUID reg check. The old
; long-word-access-only code would read the register, write some
; value back, and re-read the register, making sure that the
; second read yielded the same data as the first. The PDM-style,
; byte-access CPUID register read code now does this too.
; <SM43> 4/20/93 jb Fixed up the code to work on either a normal or PDM-style CPUID
; register.
; <SM42> 3/31/93 chp Synchronize SuperMario with changes from <LW5>.
; <LW5> 2/26/93 fau Removed support for Cyclone EVT3 and changed all labels having
; MMC with YMCA.
; <SM41> 2/23/93 RB Fixed a check for djMEMC in InitVIAs where it was depending on
; d3 which wasn't set up. Now checking decoder kind in the low
; byte of d2.
; <SM40> 2/8/93 rab Rolled in the following change from Horror for Wombat: <H30>
; 11/18/92 BG Modified TestForSonic so that instead of just
; reading a register at SonicBase to determine if Sonic is
; present, we actually WRITE a SW Reset command to Sonic. This
; way, not only do we detect it, but we make sure Sonic is always
; reset when booting/restarting.
; <SM39> 1/15/93 PN In case of Quadra 900 which has a Caboose chip, we do not
; execute the DoEgretInit but do a CudaDone otherwise we kill
; Quadra900.
; <SM38> 01/09/93 RM/HY Disable asynchronous messages on Egret based machines. This
; fixes a problem which could potentially causes hangs to occurr
; on restart if enough time elapses before Egret can respond to
; these messages.
; <SM37> 12/23/92 RC Added Support for Smurf on Wombat
; <SM36> 12/17/92 RB Removed some of the LC930 conditionals. Added back other hasXXXX
; conditionals to make it easier to build 1 off 1 Meg ROMs.
; <SM35> 12/11/92 FU Was always checking BoxCyclone33 when programming the YMCA.
; <SM34> 12/4/92 fau Added support for Cyclone40 and Tempest33.
; <SM33> 11/20/92 fau Didn't put a ; on one of my comments.
; <SM32> 11/20/92 fau Added a TestForMUNI to GetExtHardwareInfo so that Tempest can
; check whether the Nubus adapter is there or not. Programmed
; MUNI for Tempest.
; <SM31> 11/7/92 rab Roll in Horror changes. Comments follow:
; <H29> 8/10/92 SWC Fixed the MSC VIA/RBV initialization to disable slot interrupts.
; <H28> 7/2/92 ag Change initial state of the Jaws/dart via2 modemRst bit. It
; should be 0 to insure the modem is in reset when not in use.
; This also avoids current leakage to the modem.
; <H27> 6/25/92 CCH Added conditionalized support for Quadra on RISC-based emulator.
; <H26> 6/4/92 HY Add ptr to sound primitives vector table in LC product info table.
; <H25> 6/3/92 BG Conditionally changed -InitVIAs- temporarily to build the
; correct sequence of code for the BIOS1 chip on Wombat til BIOS
; is revved to have VIA1 work correctly. This change only takes
; effect if you Build -p -WombatEVT1.
; <H24> 5/28/92 NJV Added SoundPlayAndRecord bit to ProductInfo Tables of machines
; that can play and record simultaneously.
; <H22> 05-18-92 jmp Changed the “sRsrcZydecoDir” name to the more generic
; “sRsrcBFBasedDir” (BF=BoxFlag) name.
; <H18> 5/3/92 BG Removed references to hasOrwell2, since it is now superfluous to
; hasOrwell.
; <H17> 4/24/92 HJR Added CheckForNiagra so that we may distinguish from
; Jawsdecoder.
; <SM30> 11/3/92 SWC Changed SlotEqu.a->Slots.a.
; <SM29> 11/2/92 kc Make change to prevent unwanted branch island (to data).
; <SM28> 10/27/92 fau Rolled in a Horror patch for TestForFPU that also works for
; 040's without and FPU. This is to support Tempest. Added the
; necessary changes to the programming of the YMCA for Tempest.
; <SM27> 10/25/92 HY Add code in jumpintoRom to turn on & grey LC/LC II screen early.
; <SM26> 10/20/92 fau Stopped using "MMC/YMCAexists" and replaced by either comparing
; against DecoderKind or by using PSCexists. Also, changed
; YMCAAddr/MMCAddr to use DecoderAddr.
; <SM25> 10/18/92 CCH Added support for PDM and conditionalized support for Smurf.
; <SM24> 10/12/92 RB For the 1 Meg LC930 ROM, exclude all code not related to the LC
; hardware.
; <SM23> 9/30/92 fau Added support for Cyclone EVT4. This involved new DRAM/ROM
; speed values and a modification to GetHardwareInfo so that it
; looks at the CycloneEVT4 product info.
; <SM22> 9/25/92 RB Excluded some functions such as INITVias from executing while
; booting from RAM. Added a ROM base for the LC 2. Hacked
; GetCPUIDReg to return Cyclone when ROMinRAM testing.
; <SM21> 8/27/92 CCH Removed some now obsolete conditionals for Smurf card.
; <SM20> 8/25/92 chp Fix assembler warning.
; <SM19> 8/24/92 PN Take out CycloneboxEVT1
; <SM18> 8/20/92 CCH Don't initialize Orwell when running on a Cub Card.
; <SM17> 8/17/92 CCH Extended Universal support to 96-bits, added GetExtHardwareInfo
; routine to provide dynamic checking for feature existence.
; <SM16> 08-11-92 jmp Fixed a problem in the GetCPUIDReg routine where the CACR was
; being trashed; this caused 030 machines to die before BootBeep.
; <SM15> 8/9/92 CCH Removed uneeded conditionals and temporarily return a CPU ID
; for RISC cards.
; <SM14> 7/28/92 fau Corrected the Cyclone MMC_DRAMspeed0/1 to point to a 25MHz CPU
; with 60ns DRAM, instead of 25MHz with 80ns DRAM.
; <SM13> 7/21/92 kc Fix duplicate lable.
; <SM12> 7/13/92 CCH Added conditionalized support for Cub Card.
; <SM11> 6/30/92 kc Fix bug introduced with last checkin (trashing d0).
; <SM10> 6/26/92 GS (RBM) Add call to CudaInit to perform a SyncAck cycle prior to
; any transaction with Cuda. This will disable all asynchronous
; message sources within Cuda and will prevent any collisions from
; occuring in the low level io primitive routines prior to
; installation of the Cuda manager.
; <SM9> 6/21/92 RB • Added a temporary check for EVT1 Cyclone in InitVIAs and
; CheckBases so that we don't have to support two builds for the
; next few weeks.
; <SM8> 6/9/92 kc Roll in Horror change from UniversalPatch.a,14.
; <H16> 5/28/92 BG Fixed a bug in GetHardwareInfoPatch. If you have the -Ext- bit
; set in your CPU ID register, -GetVIAInputs- gets called to read
; VIA1 to see what machine you really are. However, A1 was a bad
; register to save the A6 return value in. A3 is better.
; <SM7> 5/25/92 RB Changed a couple of branch longs to short branches since the
; code is not in patches anymore. Some VIA1 init code got lost in
; pass <SM5>, so it has been restored now.
; <SM6> 5/22/92 RB Removed an ENDIF
; <SM5> 5/22/92 RB Forgot to add comments in the previous checkin. Added tables for
; Cyclone, checks for MMC which identify a a Cyclone machine (for
; now I think) and got rid of the IF forCyclone changes previously
; made. Added VIA init stuff for Cyclone, its decoder table and
; video info.
; <SM4> 5/22/92 RB Making changes for Cyclone
; <SM3> 5/17/92 kc Roll the Horror changes. Comments follow: • From
; UniversalPatch.a:
; <H14> 4/20/92 NJV Adding changes needed to support Patch ROMs
; <H13> 4/13/92 JC Remove dynamic speed determination from Sonora setup code.
; <H12> 2/20/92 JC Fix register trashing bug in test for Sonic code and remove
; temporary branch around Sonic test.
; <H11> 2/14/92 JC Clean up Sonora Memory controller initialization, dynamically
; determine clock speed, and add TestforSonic code.
; <T13> 4/26/91 ag Relocate the stack pointer after we jump into rom, otherwise a
; berr will cause ram to be written to!
; <T12> 4/22/91 ag added patch to reinitialize berr handler after jump into rom.
; removed aux wait state initialization in jaws.
; <T11> 2/16/91 BG Changed the Orwell initialization to understand 33MHz.
; <T10> 1/15/91 HJR Added new code in memoryCtrlInitPatch for Jaws initialization.
; <T7> 11/7/90 BG Made changes for new rev. of Orwell (2) permanent.
; <T4> 10/30/90 BG Added changes for new rev. of Orwell (2).
; <T3> 10/25/90 CCH Added support for ReAnimator when forRomulator equate is set.
; • From Univeral.a:
; <H9> 12/16/91 HJR Export some symbols and introduce Decoder Niagra and Product
; Dartanian into product list. Temporarily use the same routine
; for CheckForJaws and CheckForNiagra until Niagra has some
; distinguishing characteristic.
; <H8> 12/12/91 SWC Don't touch RvMonP in InitVIAs if we're running on an MSC since
; that register offset is used for, among other things, RAM
; sizing.
; <T9> 12/7/90 BG (actually JMA) Added support for dual SCSI buses used on
; Eclipse. Also - merged CheckForRPU with new CheckForSCSI96
; routine into new patch.
; <T6> 1/18/90 SWC Fixed an alignment problem where code grew by 2 bytes in
; TestForIOP. Also changed FMCInit to FMCRPUInit since we don't
; know if we have parity yet.
; <T6> 10/29/90 CCH Fixed forRomulator conditional statement.
; <T5> 10/25/90 CCH Added support for ReAnimator when forRomulator equate is set.
; <SM2> 4/7/92 JSM Roll-in revision <63> from Reality:
; <63> 3/24/92 JSM Nuke more code names: boxAuroraCX25 is boxMacIIci, boxF19 is
; boxMacIIfx.
; <62> 1/27/92 KC Move Allign 16 macro above rombase table.
; <61> 1/23/92 RB Changed the order of items in the Decoder lookup table. Changed
; the Eclipse VIA info record.
; <60> 1/20/92 RB Backed out to the revision <58>. For some reason making the code
; that sets up a bus error handler a procedure would freeze the
; machine upon startup. Very weird because the problem is not
; obvious. If only that 040 emulator worked...added an ALIGN for
; the 040 emulator. Got rid of the padForOverpatch at the end of
; the file.
; <59> 1/15/92 RB Revisited terror changes. Added a forRomulator change. Made code
; that sets up the buss error handler a subroutine since it gets
; called twice.
; <58> 12/29/91 RB Added Terror changes and rolled in patches to support Quadras
; and PowerBooks.
; <57> 12/21/91 RB Need to change boxTim and boxEclipse to the release names.
; <56> 10/17/91 JSM Get rid of all the stupid conditionals.
; <55> 10/1/91 JSM Dont use onMvMac conditional, Modern Victorian never existed.
; <54> 10/1/91 JSM Dont use eclipseDebug.
; <53> 9/10/91 JSM Cleanup header.
; <52> 1/18/91 KIP <JDR> Add Sound8BitMono bit to the Universal ROM flags for TIM,
; since it has built-in sound input.
; <51> 10/24/90 JJ Rex V8: Roll in changes from Rex V8 splitoffs.
; <50> 10/22/90 JJ Rex V8: Change VISAChipBit to V8ChipBit.
; <49> 9/25/90 SAM Changed boxElsie/boxErickson to boxMacLC/boxMacIIsi
; <48> 9/13/90 MSH Converted Waimea to TIM. This involved the boxflag, names, and
; clock/PRAM implementation.
; <47> 9/1/90 BG Updated Eclipse-related information to reflect the EVT1 boards.
; <46> 8/15/90 BG Fixed an error in the conditionals at the bottom of JumpIntoROM.
; <45> 8/14/90 BG Added an address map definition for SONIC on Eclipse. This uses
; the previously unused Address23 in the I/O map tables.
; <44> 8/14/90 BG Saved the original bus error vector for the NUB on Eclipse.
; <43> 8/2/90 CCH Temporarily cleared hwCfgFPU on Eclipse.
; <42> 6/25/90 BG Modified the EclipseNuBus information to correctly reflect the
; fact that slot E is not available on the current prototypes.
; <41> 6/18/90 CCH Added eclipse-specific changes, and removed occurences of the
; onEclipse equate.
; <40> 6/11/90 GA Correct VideoInfo 24-bit base address for Erickson. Somehow, it
; seemed to get lost from <39>.
; <39> 6/7/90 HJR Changes the 24 Bit Address in MDU and Erickson to 32 Bit
; Addresses since the video stuff pulls that address and Quickdraw
; requires it to be a 32 bit address.
; <38> 5/25/90 MSH JAWS check was all wrong. Changed logical 24 Bit address in MDU
; and Erickson to reflect actual 24 Bit address.
; <37> 5/17/90 JJ Change address of diagnostic ROM for VISA decoder.
; <36> 5/14/90 MSH Moved built in video to logical slot E and the PDS connector to
; slot B.
; <35> 5/2/90 CV Updating nuBus slot info to reflect change in the video slot for
; Erickson.
; <34> 5/1/90 DAF Updating Erickson VideoInfo for Built-in Video in Slot $E.
; <33> 4/24/90 DAF Reordered Elsie VideoInfo records to match new RBVPrimaryInit.a
; <32> 4/21/90 GMR Reversed order of entries in RamInfo tables.
; <31> 4/20/90 JJ Removed support for VISA 1 from Elsie RAM Info Table.
; <30> 4/20/90 JJ Change initial sound volume value for Elsie and Erickson from 2
; to 6.
; <29> 4/12/90 MSH Fixed the Waimea clock/PRAM info in tables.
; <28> 4/11/90 JJ Change sound volume initilization value from 1 to 2 on Erickson
; and Elsie to avoid BURNIN rack problem.
; <27> 4/11/90 JJ Change VIA1Init table for Erickson and Elsie to set DDRA bits
; 0:2 to be outputs.
; <26> 4/4/90 JJ Modified Elsie Video Information Tables.
; <25> 4/4/90 MSH Added Waimea to the tables. Made the pad bytes at the bottom
; conditional for overpatching only.
; <24> 4/2/90 djw Fixup universal NuBusInfo tables for Elsie, Erickson, and
; Eclipse.
; <23> 3/26/90 CCH Added sound input to external feature flags for Erickson, Elsie,
; and Eclipse.
; <22> 3/23/90 JJ Made RAMInforElsie tables conditional on hasVISA2.
; <21> 3/22/90 JJ Fixed bug in JumpIntoROM. Now relocates pointers to Decoder
; Info and Product Info before "jmp @intoROM(d3.l)".
; <20> 3/9/90 JJ Changed RAMInfoElsie table to conform to VISA2 memory
; configurations.
; <19> 2/23/90 BG Moved reference to Orwell to before the Glue DecoderTable entry
; since Eclipse/Orwell will pass the GLUE test, but a MacII will
; fail the Orwell test.
; <18> 2/21/90 BG Fixed off-by-one error in Orwell setup code.
; <17> 2/20/90 CCH Set Eclipse smallest bank size to 4 meg.
; <16> 2/16/90 BG Modified TestForFPU to check if we're running on an 040 before
; the SFC check. Running on an 040 implies you have an FPU. The
; SFC check will fail on an 040 because it does not support
; coprocessor communications. Also modified OrwellDecoderTable to
; include the possibility of a DiagROM, etc.
; <15> 2/13/90 JJ Stupid mistake in Version <14>.
; <14> 2/13/90 JJ Added VISA chip indicator to External Feature flags in VISA
; decoder table and Elsie information table.
; <13> 2/9/90 BG Adding Eclipse-specific hardware information. Also added a
; *CheckForOrwell* routine to determine if we're dealing with
; Orwell decoder. Also added Orwell initialization code in
; JumpIntoROM.
; <12> 2/7/90 OR Add CheckForVISADecoder routine and all information tables for
; Elsie.
; <11> 2/7/90 CV Rearranged order of CheckFeatures & CheckOptionals to use d1,
; not d3 in TestForFPU. d3 contains warmstart value. Sorry!
; <10> 2/4/90 GMR Fixed VIA init table for Erickson, so it properly initializes
; the vACR reg for Egret.
; <9> 2/4/90 CV Removed isUniversal conditional on TestForFPU. Caused HcMac &
; Macpp to fail.
; <8> 2/3/90 CV Added TestForFPU to check for an optional FPU.
; <7> 2/1/90 CV Adding a table for via1 initialization for Erickson. Erickson
; was using the IIci table, but EGRET requires different
; initialization. On Erickson, three lines are used to communicate
; with EGRET and five lines are unconnected.
; <6> 1/25/90 GMR Renamed the ADB/Clock types so they don't conflict with assembly
; conditionals (like iopADB).
; <5> 1/15/90 GMR Added ADB and Clock/Pram bits to External Features longword, to
; help support Erickson/Elsie which use the Egret chip.
; <4> 1/11/90 CCH Added include of “HardwarePrivateEqu.a”.
; <3> 1/8/90 CV Adding table information to allow recognition of Erickson as a
; new CPU. Changing the via1 id value for AuroraSE25 to 0. The
; value it was set to ($16) conflicts with Erickson's cpu id.
; <2> 1/2/90 SWC Changed CheckForOSSFMC to work with TI as well as NCR parts.
; <2.5> 11/15/89 GMR Added TestForRPU to check for the optional RPU chip on OSS/FMC,
; changed the decoder table for OSS/FMC and the InfoF19 table.
; Fixed bug in TestForIOP when setting increment mode.
; <2.4> 8/22/89 BBM UGLY HACK. made a quick patch to the bbu table just to get emacs
; working.
; <2.3> 7/25/89 CCH Changed JumpIntoROM to preserve the value in the VBR if
; forRomulator is true.
; <2.2> 7/16/89 GGD Changed the product info for the former Aurora 16 to be the same
; as Aurora 25, but without the PGC option. Added a flag to the
; ExtValid flags of Aurora 25 to indicate that it has the PGC
; option installed. Renamed AuroraCX25 to be MacIIciPGC and
; AuroraCX16 to be MacIIci.
; <2.0> 6/30/89 GGD Initialized the new DefaultRSRCs field in the ProductInfo
; record. Added some padding to allow for overpatching. Added
; NuBus Slot Info.
; <•2.1> 6/30/89 GGD Changed resource combos from 0,1 to 1,2
; <2.1> 6/30/89 GGD Changed the DefaultRSRCs from {0,1} to {1,2}
; <2.0> 6/30/89 GGD Initialized the new DefaultRSRCs field in the ProductInfo record.
; Added some padding to allow for overpatching. Added NuBus Slot Info.
; <1.9> 6/12/89 djw Added slot video pram addr to video table
; <1.8> 6/11/89 GGD Added Video, Ram Bank, hwCfgFlags, and ROM85 info to tables.
; Updated GetHwInfo to also return the hwCfgFlags. Updated VIA2
; initialization values.
; <1.7> 6/10/89 GGD Added info for new aurora boxes. GetHwInfo now clears the beok
; bit when done.
; <1.6> 5/29/89 GGD Fixed wrong register bug in FMC initialization. Removed the Test
; in Ram checks.
; <1.5> 5/20/89 GGD Updated to use new IOP equates from HardwareEqu, deleted local
; IOP equates.
; <1.4> 5/16/89 rwh separated out Mac II Via 2 info to set MMU control bit as an
; output.
; <1.3> 5/15/89 GGD Changed RBV BufB initialization to disable Par.Test~ so that
; correct parity will be generated.
; <1.2> 5/10/89 CCH Added a test that will make the vFC3 bit an output when running
; in RAM.
; <1.1> 5/1/89 GGD Fixed conditionals in CheckForGLUE so that NuMac will work
; again.
; <1.0> 4/30/89 GGD Adding to EASE for the first time. Support for Universal ROM.
;__________________________________________________________________________________________________
print off
LOAD 'StandardEqu.d'
INCLUDE 'HardwarePrivateEqu.a'
INCLUDE 'UniversalEqu.a'
INCLUDE 'PowerPrivEqu.a'
INCLUDE 'STEqu.a'
INCLUDE 'Slots.a'
INCLUDE 'DepVideoEqu.a' ; <58> rb
INCLUDE 'EgretEqu.a' ; <SM38>
print on
print nomdir
machine mc68030
mc68881 ; needed for TestForFPU <SM28>
Universal proc export
import CPUIDProductLookup,ProductLookup,DecoderLookup
import BaseOfRom, CudaInit
import SendEgretCmd ; <SM38>
EXPORT CheckForUnknown
export GetHardwareInfo
export GetExtHardwareInfo ; <SM17>
export JumpIntoROM
export InitVIAs
EXPORT CheckNextMap,MapFound ;<SM31> ; <H2>
IF hasCPUIDRegister THEN ; ; <SM24> rb <SM36> rb
EXPORT GetCPUIDReg ;<SM49>
ENDIF
;_______________________________________________________________________
;
; Routine: JumpIntoROM
; Inputs: A6 - return address
;
; Outputs: A0 - Pointer to DecoderInfo record for this machine
; A1 - Pointer to ProductInfo record for this machine
; D0 - Flags indicating which base addresses are valid
; D1 - Flags indicating which external features are valid
; D2 - Bits 31..16, hwCfgFlags info (possibly unknown)
; D2 - Bits 15..8, BoxFlag info (possibly unknown)
; D2 - Bits 7..0, Address Decoder Kind (zero if unknown)
;
; Destroys: A2,A3,SP,D3,D4,D5
; Called by: BSR6
;
; Function: Locates the System ROM, which we are executing out of,
; but which may be mapped down to zero (overlay mode).
; We will jump into the ROM at its normal base address,
; and then initialize the VIAs to disable overlay.
;
;_______________________________________________________________________
with DecoderInfo,ProductInfo,DecoderKinds
JumpIntoROM
move.l #aStack,sp ; set stack pointer value
movea.l a6,a4 ; save the return address
; Setup VBR to point to a temporary Bus Error handler, because we need to use
; Bus Errors to destinguish the address decoders on the 68020/030 machines.
lea GotBusError,a0 ; get the handler address
move.l a0,d0 ; value to search for
@loop cmp.l -(a0),d0 ; check for a match
beq.s @found ; use the entry if it matches
tst.l (a0) ; check for end of list
bne.s @loop ; if not, keep searching
lea BusErrVct,a0 ; set it up in RAM
move.l d0,(a0) ; assume ram based, insert entry
@found subq.w #BusErrVct,a0 ; make it the bus error vector
IF forRomulator THEN ; <T5>
TestInRAM a3 ; are we in RAM?
beq.s @notInRAM ;
movec vbr,d5 ; save contents of vbr <T5>
movec vbr,a3 ; get vbr address in a1
move.l BusErrVct(a3),d2 ; save original (read: NUB) buserr vect
movec d2,USP ; ... in an out-of-the-way place
move.l BusErrVct(a0),BusErrVct(a3) ; copy old vector to new table
@notInRAM
ELSE ; <T6>
movec.l a0,vbr ; install the vector table
ENDIF
@TryAgain moveq.l #0,d2 ; figure it out from scratch
bsr6 GetHardwareInfo ; figure out what we are running on
btst.l #ROMExists,d0 ; see if we have a ROM
beq.s @TryAgain ; if not, we're screwed, but try again anyway
; Now figure out what the new base of ROM should be,
IF forRomulator THEN ; <T5>
TestInRam A2 ; running in RAM? <T5>
bne.s intoROM ; yep, skip this.. <T5>
endif
biglea BaseOfRom,a2 ; where we currently start
move.l ROMAddr(a0),d3 ; where we want to start (from savepatch) <3> <cv>
sub.l a2,d3 ; offset we need to add to relocate <3> <cv>
adda.l d3,a0 ; relocate decoder info pointer <3> <cv>
adda.l d3,a1 ; relocate product info pointer <3> <cv>
; if not forRamRom then ; ••• need to make this a runtime check •••
adda.l d3,a4 ; relocate the return address
jmp intoROM(d3.l) ; relocate our program counter
; endif
intoROM ; now we are in ROM
; Setup VBR to point to a temporary Bus Error handler, because we need to use
; Bus Errors to destinguish the address decoders on the 68020/030 machines.
adda.l d3,sp ; relocate the stack to rom addresses <T13>
lea GotBusError,a0 ; get the handler address <T12>
move.l a0,d0 ; value to search for <T12>
@loop cmp.l -(a0),d0 ; check for a match <T12>
beq.s @found ; use the entry if it matches <T12>
tst.l (a0) ; check for end of list <T12>
bne.s @loop ; if not, keep searching <T12>
lea BusErrVct,a0 ; set it up in RAM <T12>
move.l d0,(a0) ; assume ram based, insert entry <T12>
@found subq.w #BusErrVct,a0 ; make it the bus error vector <T12>
IF forRomulator THEN ; <T12>
TestInRAM a3 ; are we in RAM? <T12>
beq.s @notInRAM ; <T12>
movec vbr,d5 ; save contents of vbr <T12>
movec vbr,a3 ; get vbr address in a1 <T12>
move.l BusErrVct(a3),d2 ; save original (read: NUB) buserr vect <T12>
movec d2,USP ; ... in an out-of-the-way place <T12>
move.l BusErrVct(a0),BusErrVct(a3) ; copy old vector to new table <T12>
@notInRAM
ELSE ; <T12>
movec.l a0,vbr ; install the vector table <T12>
ENDIF
@TryAgain moveq.l #0,d2 ; figure it out from scratch <T12>
bsr6 GetHardwareInfo ; figure out what we are running on <T12>
btst.l #ROMExists,d0 ; see if we have a ROM <T12>
beq.s @TryAgain ; if not, we're screwed, but try again anyway <T12>
IF NOT ROMinRAM THEN ; <SM22> rb
bsr6 InitVIAs ; initialize the VIAs (turns off vOverlay) <T12>
ENDIF ; <SM22> rb
; Here, after running GetHardwareInfo we have: <SM10>{rbm}<2>
; <SM10>{rbm}<2>
; a0 - Pointer to table of base addresses <SM10>{rbm}<2>
; a1 - Pointer to ProductInfo record for this machine <SM10>{rbm}<2>
; d0 - Flags indicating which base addresses are valid <SM10>{rbm}<2>
; d1 - Flags indicating which external features are valid <SM10>{rbm}<2>
; d2 - Bits 31..16, hwCfgFlags info (possibly unknown) <SM10>{rbm}<2>
; d2 - Bits 15..8, BoxFlag info (possibly unknown) <SM10>{rbm}<2>
; d2 - Bits 7..0, Address Decoder Kind (zero if unknown) <SM10>{rbm}<2>
; <SM10>{rbm}<2>
; CudaInit implies a SyncAck cycle which synchronizes Cuda to the system and disables <SM10>{rbm}<2>
; all asynchronous messages sources (Auto Poll, RTC, Power Messages, Unknown). No further <SM10>{rbm}<2>
; individual disabling of asynchronous message sources is required. (R. Montagne 5/25/92) <SM10>{rbm}<2>
; <SM10>{rbm}<2>
move.l d0,d3 ; save a copy of d0 <SM11>
move.l #EgretFWMask,d0 ; mask for Egret Firmware <SM10>{rbm}<2>
and.l d1,d0 ; isolate the field <SM10>{rbm}<2>
sub.l #Egret8,d0 ; see if we have Egret FW <SM10>{rbm}<2>
beq.w @DoEgretInit ; do Egret 8 FW INIT, LC/si <SM10>{rbm}<2> <SM38>
sub.l #Egret8,d0 ; see if we have Caboose FW <SM10>{rbm}<2>
beq.s @CudaDone ; just exit Quadra900 <SM10>{rbm}<2> <SM39> PN
sub.l #Egret8,d0 ; see if we have Cuda FW <SM10>{rbm}<2>
bne.s @CudaDone ; if not, just exit <SM10>{rbm}<2>
IF NOT ROMinRAM THEN ; <SM22> rb
BigBSR6 CudaInit ;Setup Cuda Sysnc Ack with System <SM10>{rbm}<2>
bra.s @CudaDone ; <SM38>
ENDIF ; <SM22> rb
@DoEgretInit ; <SM38>
movea.l DecoderInfo.VIA1Addr(a0),a1 ; get VIA 1 base address <SM38>
move.w #4000,d0 ; <SM38>
@wait
eieioSTP
tst.b (a1) ; sync to hardware for 1.2µS per access <SM38>
dbra d0,@wait ; Egret must see idle before command, it's busy <SM38>
; doing ADB reset for 3mSec so delay in idle state <SM38>
eieioSTP
move.l #(NopCmd<<16)|pseudoPkt,d0 ; <SM38>
moveq #0,d2 ; no bytes to send <SM38>
bsr6 SendEgretCmd ; send the command to disable async. messages <SM38>
moveq.l #0,d2 ; figure it out from scratch <SM38>
bsr6 GetHardwareInfo ; restore all the registers we trashed <SM38>
move.l d0,d3 ; by calling SendEgretCmd <SM38>
@CudaDone
move.l d3,d0 ; restore d0 <SM11>
IF forSTP601 THEN
jmp (a4) ; Orwell,djmec already inited...return
ENDIF
IF hasOSS THEN ; <SM36> rb
btst.l #OSSExists,d0 ; see if we have an OSS
beq.s @noOSS ; if not, don't need to init it
movea.l OSSAddr(a0),a3 ; get the OSS base address
move.b #OSSRomInit,OSSRomCntl(a3) ;overlay off, 2 ROM wait states
@noOSS
ENDIF ; <SM36> rb
IF hasFMC THEN ; <SM36> rb
btst.l #FMCExists,d0 ; see if we have a FMC
beq.s @noFMC ; if not, don't need to init it
movea.l FMCAddr(a0),a3 ; get the FMC base address
move.w #FMCRPUInit,d3 ; initial value for config register <T6>
moveq.l #16-1,d4 ; loop counter to load 16 bits
@FMCload move.b d3,FMCConfig(a3) ; load in a bit <1.6>
lsr.w #1,d3 ; put next bit into position
dbra d4,@FMCload ; repeat till all bits loaded
move.b d3,FMCLatch(a3) ; latch the config data
@noFMC
ENDIF ; <SM36> rb
IF hasSonora THEN ; begin hasSonora <H11>.Start <SM36> rb
move.l ExtValid(a1),d3 ; get External Flags
btst.l #SonoraExistsBit,d3 ; see if we have an Sonora ASIC
beq @noSonora ; IF we have a Sonora THEN
lea CPUIDReg,A2 ;get value in CPU ID Reg <H13>.Start
move.l (a2),d3
and.l #$0000ff00,d3 ; only look at CPU ID reg Design Center Value
movea.l RBVAddr(a0),a2 ; get base of RBV/VIA2 Registers
move.b #0,SonoraVRAMSize(a2) ;force VRAM to 256k for now
move.b #$40,SonoraRAMSize(a2) ;force to 25 Mhz PDS slot speed <SM4> rb
move.b #3,SonoraSpeedReg(a2) ;Set up for 33Mhz timing
cmpi.w #cpuIDHiEnd,d3 ; check if we are a high end box
bge.s @noSonora ; branch if high end box
lea CPUIDReg,A2 ;get value in CPU ID Reg <H27><SM31>
move.l (a2),d3 ; <H27><SM31>
and.w #cpuIDFieldMask,d3 ; d3 = ID field of CPU ID Register <H26><SM31>
cmpi.w #Vail33IDField,d3 ; is it a 33 MHz Vail ?? <H26><SM31>
beq.s @noSonora ; yep, don't change the timing <H26><SM31>
movea.l RBVAddr(a0),a2 ; get base of RBV/VIA2 Registers <H29><SM31>
move.b #2,SonoraSpeedReg(a2) ;Set up for 25Mhz or less timing <H13>.End
@noSonora ; end hasSonora <H11>.End
ENDIF ; <SM36> rb
IF hasOrwell THEN ; <SM36> rb
; Eclipse/040 Memory Controller INIT
cmp.b #OrwellDecoder,DecoderKind(a1) ; see if we have an Orwell Mem. Cntrlr
bne.s @noOrwell ; NOPE ... we don't need to init. it
cmp.b #boxRiscQuadra700,ProductKind(a1) ; see if we're on a RISC Quadra <SM54>
beq.s @noOrwell ; don't reset orwell then <SM54>
cmp.b #boxRiscQuadra900,ProductKind(a1) ; see if we're on a RISC Quadra <SM54>
beq.s @noOrwell ; don't reset orwell then <SM54>
cmp.b #boxRiscQuadra950,ProductKind(a1) ; see if we're on a RISC Quadra <SM54>
beq.s @noOrwell ; don't reset orwell then
; Set up various Orwell configuration registers to useable values.
movea.l DecoderAddr(a0),a3 ; get base address of Orwell regs <SM17>
move.l #ORWELL_INIT25,d4 ; get Orwell 25MHz initialization value <T11>
moveq.l #OrCfgRegSize-3,d3 ; (34-3 = 34-1-2) -1 for DBRA, <T4><T7>
; -2 because 32-bit max constant size <T4>
movea.l VIA2Addr(a0),a2 ; get base of VIA2 to check for 33 MHz <T11>
bclr #v2Speed,VDirB(a2) ; make sure the 25/33MHz direction=input<T11>
btst #v2Speed,VBufB(a2) ; are we running at 25 MHz or 33 MHz? <T11>
beq.s @25MHz ; IF CPU_Speed == 33MHz THEN <T11>
move.l #ORWELL_INIT33,d4 ; get Orwell 33MHz init. value <T11>
@25MHz ; ENDIF <T11>
; Note - the above configuration constants are ONLY accurate for non-parity <T11>
; operation. <T11>
lea OrBankBCfgAddr(a3),a2; get address of config regs. <T11>
@OrwellINIT move.l d4,(a2)+ ; send that bit out there
lsr.l #1,d4 ; get the next bit in position
dbra d3,@OrwellINIT ; repeat til all bits loaded
; now move in the last two bits that didnt fit in the original 32-bit constant<T4><T7>
moveq #ORINITWaitWr1,d4 ; get initial value of optional write wait state<T4><T7>
move.l d4,(a2)+ ; ... and send that bit out <T4><T7>
; RAS precharge (the last bit) is done separately below because it too relies <T11>
; on the clock speed the processor is running at. <T11>
; Now hit the associated latch registers to actually store the values
move.l d3,OrLoadBanks(a3) ; initialize DRAM bank starting addrs
move.l d3,OrLoadSpeeds(a3) ; initialize Clock/DRAM/ROM speeds
move.l d3,OrLoadRefresh(a3); initialize refresh rate
move.l d3,OrLoadParity(a3) ; initialize parity on/off + type
move.l d3,OrLoadMode(a3) ; initialize page mode (on/off) <T4><T7>
move.l d3,OrLoadWaitStates(a3); initialize optional wait states <T4><T7>
; RAS Precharge timing is different depending on 25/33 MHz.
move.l OrClkSpeedAddr(a3),d4; now that clock speed is set, get it <T11>
btst #0,d4 ; only LSBit is valid from each reg addr<T11>
beq.s @use33MHzvalue ; IF Clock_Speed == 25MHz THEN <T11>
moveq #ORINITRAS25,d4 ; get value of 25 MHz RAS precharge <T4><T7><T11>
bra.s @initRAS ; and get on with it <T11>
@use33MHzvalue ; ELSE <T11>
moveq #ORINITRAS33,d4 ; get value of 33 MHz RAS precharge <T4><T7><T11>
@initRAS ; ENDIF
move.l d4,(a2) ; ... and finish init of config reg <T4><T7>
move.l d3,OrLoadPrecharge(a3); initialize RAS precharge (on/off) <T4><T7>
@noOrwell
ENDIF ; <SM36> rb
IF hasJaws THEN ; <SM36> rb
btst.l #JAWSExists,d0 ; see if we have a JAWS <T10> HJR
beq.s @noJAWS ; if not, don't need to init it
movea.l JAWSAddr(a0),a2 ; get base address of Jaws regs
movea.l a2,a3 ; copy the register
adda.l #JAWSGetCPUClock,a3 ; get address of CPU clock register
move.b (a3),d3 ; read CPU clock register
andi.b #1,d3 ; clear the top bits
move.b d3,JAWSRAMWaitS(a2) ; set ram wait states according to the speed register
@noJAWS
ENDIF ; <SM36> rb
IF hasYMCA THEN ; <SM36> rb
cmp.b #YMCADecoder,DecoderKind(a1) ; Do we have a YMCA <SM26> fau start
bne @noYMCA ; Not a YMCA <SM26> fau end
Move.l DecoderAddr(a0),A2 ; Get Base of YMCA. <SM23> <SM26> <SM34>
Cmp.b #BoxQuadra840AV,ProductKind(a1) ; Are we running on a Cyclone40 <SM34> <LW2><SM55>
Beq.s @DoCyclone40 ; if so, go program it <SM34>
Cmp.b #BoxCyclone33,ProductKind(a1) ; Are we running on a Cyclone33 <SM34>
Beq.s @DoCyclone33 ; if so, go program it <SM34>
Cmp.b #BoxTempest33,ProductKind(a1) ; Are we running on a Tempest25 <SM34> <LW2>
Beq.s @DoTempest33 ; if so, go program it <SM34>
Cmp.b #BoxCentris660AV,ProductKind(a1) ; Are we running on a Tempest25 <SM34> <LW2><SM55>
Beq @DoTempest25 ; if so, go program it <SM34>
Bra @noYMCA ; Not a Cyclone Type Machine
@DoCyclone40
Move.l #0,YMCA_DRAMspeed0(A2) ; Set DRAM speed to 60ns with a 40MHz CPU <SM34><LW7>
Move.l #-1,YMCA_DRAMspeed1(A2) ; <SM34><LW7
Move.l #0,YMCA_CPUspeed0(A2) ; Set CPU Speed to 40 MHz <SM34><LW7
Move.l #-1,YMCA_CPUspeed1(A2)
Move.l #0,YMCA_ROMspeed0(A2) ; Set ROM speed to 127ns (7 cycles). <SM34><LW7>
Move.l #0,YMCA_ROMspeed1(A2) ; <SM34><LW7>
Move.l #-1,YMCA_ROMspeed2(A2) ; <SM34>
; Program MUNI if it exists
bsr6 GetExtHardwareInfo ; Get the bits for extended features 32-63 <SM34>
beq @NoYMCA ; No MUNI here <SM34>
Move.l #$1c,MUNIBase+MUNI_Control ; Set MUNI for 33MHz. <SM34>
Bra.s @noYMCA ; Skip over Tempest programming <SM34>
@DoCyclone33
@DoTempest33 ; <SM34>
Move.l #-1,YMCA_DRAMspeed0(A2) ; Set DRAM speed to 60ns with a 33MHz CPU <SM23>
Move.l #0,YMCA_DRAMspeed1(A2) ; <SM23>
Move.l #-1,YMCA_CPUspeed0(A2) ; Set CPU Speed to 33 MHz <SM23>
Move.l #0,YMCA_CPUspeed1(A2)
Move.l #-1,YMCA_ROMspeed0(A2) ; Set ROM speed to 125 (6 cycles). <SM23> <LW7>
Move.l #-1,YMCA_ROMspeed1(A2) ; <SM23> <LW7>
Move.l #0,YMCA_ROMspeed2(A2) ; <SM23> <LW7>
; Program MUNI if it exists
bsr6 GetExtHardwareInfo ; Get the bits for extended features 32-63 <SM32>
beq.s @NoYMCA ; No MUNI here <SM32>
Move.l #$18,MUNIBase+MUNI_Control ; Set MUNI for 33MHz. <SM23>
Bra.s @NoYMCA ; Skip over Tempest programming <SM26>
@DoTempest25
Move.l #0,YMCA_DRAMspeed0(A2) ; Set DRAM speed to 60ns with a 25MHz CPU <SM26><LW7>
Move.l #0,YMCA_DRAMspeed1(A2) ; <SM26><LW7>
Move.l #0,YMCA_CPUspeed0(A2) ; Set CPU Speed to 25 MHz <SM26><LW7>
Move.l #0,YMCA_CPUspeed1(A2)
Move.l #0,YMCA_ROMspeed0(A2) ; Set ROM speed to 140ns (5 cycles). <SM26><LW7
Move.l #-1,YMCA_ROMspeed1(A2) ; <SM26>
Move.l #0,YMCA_ROMspeed2(A2) ; <SM26>
; Program MUNI if it exists
bsr6 GetExtHardwareInfo ; Get the bits for extended features 32-63 <SM32>
btst.l #MUNIExists-32,d0 ; Normalize MUNIExists since it's in 32-63 <SM32>
beq.s @NoYMCA ; No MUNI here <SM32>
Move.l #$14,MUNIBase+MUNI_Control ; Set MUNI for 25MHz. <SM32>
@NoYMCA
ENDIF ; <SM36> rb
IF hasVisaDecoder THEN ; <SM36> rb
cmp.b #VISADecoder,DecoderKind(a1) ; do we have a VISA <SM27>
bne.s @noVISA ; if not don't do anything <SM27>
; <SM27>
; VISA machines need there screens greyed out earlier than primary init time <SM27>
; to avoid garbage being left over on the screen from a previous reboot <SM27>
move.l VDACAddr(a0),a2 ; get base address of Color Table chip <SM27>
move.l a2,a3 ; save base address in a3 <SM27>
clr.b V8DACwCntlReg(a2) ; clears the overlay enable bit and puts ariel in slave mode <SM27>
; ; to insure all outputs are off while CLUT is being filled <SM27>
adda #V8DACwDataReg,a2 ; point to data register <SM27>
clr.b V8DACwAddReg-V8DACwDataReg(a2) ; start at the beginning of CLUT, 4-bit mode <SM27>
move.b #$7F,d3 ; get a 50% value <SM27>
move #$FF,d4 ; get count <SM27>
@Repeat move.b d3,(a2) ; put red (CLUT autoincrements destination address) <SM27>
move.b d3,(a2) ; put green <SM27>
move.b d3,(a2) ; put blue <SM27>
dbra d4,@Repeat ; <SM27>
ori.b #$08,V8DACwCntlReg(a3) ; turn video on by putting machine in master mode <SM27>
@noVISA
ENDIF ; <SM36> rb
IF hasDJMEMC THEN ; <SM36> rb
; djMEMC Configuration Register initialization <H18> thru next <H18>
; (Done here so that it isn't done multiple times in SizeMemPatch) <SM30> begin
move.l ExtValid(a1),d3 ; get External Flags
btst.l #djMEMCChipBit,d3 ; see if we have a djMEMC
beq @nodjMEMC ; IF we have a djMEM THEN
cmp.b #boxRiscCentris650,ProductKind(a1) ; see if we're on a RISC Wombat Centris650 <SM54>
beq @nodjMEMC ; don't reset djMEMC then <SM54>
cmp.b #boxRiscQuadra800,ProductKind(a1) ; see if we're on a RISC Wombat Quadra800 <SM54>
beq @nodjMEMC ; don't reset djMEMC then <SM54>
cmp.b #boxRiscCentris610,ProductKind(a1) ; see if we're on a RISC Wombat Centris610 <SM54>
beq @nodjMEMC ; don't reset djMEMC then <SM54>
; Set up djMEMC+BIOS Configuration Registers:
; -------------------------------------------
;
; Get machine type + CPU speed information from VIA1
;
; Useful VIA1 PortA bits to read: PA6, PA4, PA2, PA1 ($56)
;
; PA6 = Lego (1), or Frigidaire (0) plastics for Wombat
; PA4, PA2 = CPU Speed. 0=20MHz, 1=25MHz, 2=33MHz, 3=40MHz
; PA1 = WLCD (0) or NOT! [Reserved] (1)
;
; Retrieve CPU Speed information from VIA1 Port A
move.l VIA1Addr(a0),a2 ; get VIA1 address to get machine/cpu_speed info
moveq #%00101000,d3 ; force VIA1 VDirA to have the correct directions
eieioSTP
move.b d3,VDirA(a2) ; ... so we can read the CPU ID extension info
moveq #%00010100,d3 ; get VBufA, bits PA4, PA2 (dont need PA6, PA1)
eieioSTP
and.b VBufA(a2),d3 ; get plastics_type/cpu_speed information
@hasValue lsr.b #2,d3 ; shift over to get PA2 in LSBit
btst #4-2,d3 ; test PA4. remember it's been shifted from bit pos. 4->2
beq.s @PA4IsZero ; if its already zero, don't do anything
bset #1,d3 ; otherwise move it down to correct place for indexing
@PA4IsZero andi.b #$03,d3 ; make sure ONLY bottom 2 bits are set
moveq.l #-1,d4 ; initial offset into @MachineTbl-one_entry <H35> thru next <H35> <SM57>
@nextEntry addq.l #1,d4 ; get next entry
tst.w (@MachineTbl,d4.w*2) ; if entry is zero, you've hit EndOfTable
beq.s @unknownMachine ; deal with unknown machine
moveq.l #%01010110,d0 ; CPU ID mask value for VIA
eieioSTP
and.b VBufA(a2),d0 ; get CPU ID value
cmp.b (@MachineTbl+1,d4.w*2),d0 ; is it this machine?
bne.s @nextEntry ; no, try again
LEA @djConfigTable,A3 ; assume original table
move.b (@MachineTbl,d4.w*2),d0 ; check whether we're an Original or a Bumped machine
beq.s @doIt ; 0=Original, use @djConfigTable.
@unknownMachine ; SpeedBump or Unknown machine, assume SpeedBump
LEA @BumpConfigTable,A3 ; use SpeedBump configuration table
@doIt
LEA MEMCAddr,A2 ; Get djMEMC base
move.w (a3,d3.w*2),d0 ; use CPU speed as index into table for config value <H35> <SM57>
MOVE.L D0,MEMCconfig(A2) ; set up configuration register
move.w (@djRefreshTable,d3.w*2),d0 ; also use CPU speed as index into refresh period table
MOVE.L D0,MEMCRefresh(A2) ; set up refresh period
LEA BIOSAddr,A2 ; get base of BIOS
MOVE.L BIOS_Config(A2),d0 ; get Config register value
andi.b #$F7,d0 ; drop old D0{0:0} value
or.b (@BIOS_Config,d3.w),d0 ; only change bit 0 of this register
MOVE.L d0,BIOS_Config(A2) ; and write it out (only bottom 8-bits "stick")
move.w (@BIOS_Timeout,d3.w*2),d0 ; get watchdog timer timeout count-down value
MOVE.L d0,BIOS_Timeout(A2) ; and and write this out
bra.s @nodjMEMC ; finished with memory controller initialization
; djMEMC Configuration register initialization values for different CPU speeds
;
; [ See the djMEMC ERS for a full description of the Configuration Register ]
align 4 ; longword align
; djMEMC Configuration Register initialization values
@djConfigTable
@dj20Config dc.w %0000000100000001 ; fastwr=1, ROMspeed=1
@dj25Config dc.w %0000000000011010 ; drpchg=1, drpw=1, ROMspeed=2
@dj33Config dc.w %0000000010100011 ; mhz33=1, cyc23ta=1, ROMspeed=3 <H24>
@dj40Config dc.w %0000001011110100 ; dwcpw=1, mhz33=1, drcpw=1, cyc2ta=1, drpchg=1, ROMspeed=4 <H22>
; DRAM refresh cycle times assuming a 15.6µs refresh period <H25>
; (Refresh = (MHz * 15.6 ) - 27). Fractional parts are rounded DOWN <H25>
@djRefreshTable
@dj20Refresh dc.w 285 ; (20MHz * 15.6µs) - 27 <H25>
@dj25Refresh dc.w 363 ; (25MHz * 15.6µs) - 27 <H25>
@dj33Refresh dc.w 487 ; (33MHz * 15.6µs) - 27 <H25>
@dj40Refresh dc.w 597 ; (40MHz * 15.6µs) - 27 <H25>
; BIOS Configuration Register initialization values <h28>
@BIOS_Config
@BIOS_Config20 dc.b %00000001 ; BCLK_25 = 1 <H28>
@BIOS_Config25 dc.b %00000001 ; BCLK_25 = 1 <H28>
@BIOS_Config33 dc.b 0 ; BCLK_25 = 0 <H28>
@BIOS_Config40 dc.b 0 ; BCLK_25 = 0 <H28>
; BIOS watchdog timer timeout count-down value <H28>
@BIOS_Timeout
@BIOS_Timeout20 dc.w $0280 ; <H28>
@BIOS_Timeout25 dc.w $01E0 ; <H28>
@BIOS_Timeout33 dc.w $00D5 ; <H28>
@BIOS_Timeout40 dc.w 0 ; <H28>
; Table for determining whether or not to use "SpeedBump"ed Config values <H35> thru next <H35> <SM57>
@DJ_ORIG EQU 0
@DJ_BUMP EQU 1
@MachineTbl ; Type CPU VIA ID
dc.b @DJ_ORIG,%00010010 ; 33MHz Frigidaire package (Quadra 800) <SM60>
dc.b @DJ_BUMP,%00010110 ; 40MHz Frigidaire package (unreleased) <SM60>
dc.b @DJ_ORIG,%01000000 ; 20MHz WLCD (Centris 610)
dc.b @DJ_BUMP,%01000100 ; 25MHz WLCD (Quadra 610)
dc.b @DJ_BUMP,%01010000 ; 33MHz WLCD (unreleased) <SM60>
dc.b @DJ_ORIG,%01000110 ; 25MHz Lego package (Centris 650)
dc.b @DJ_BUMP,%01010010 ; 33MHz Lego package (Quadra 650)
dc.b @DJ_BUMP,%01010110 ; 40MHz Lego package (Quadra 650 SpeedBump, unreleased) <SM60>
dc.b @DJ_ORIG,0 ; if here, this is EndOfTable
; VIA CPUID of 0 is a reserved (unused) machine.
; Configuration register values for SpeedBumped machines (by clock speed)
@BumpConfigTable
@bump20Config dc.w %0000000100000001 ; fastwr=1, ROMspeed=1
@bump25Config dc.w %0000000000011010 ; drpchg=1, drpw=1, ROMspeed=2
@bump33Config dc.w %0000000011111011 ; mhz33=1, drcpw=1, cyc2ta=1, drpchg=1 drpw=1, ROMspeed=4 <H24>
@bump40Config dc.w %0000001011111100 ; dwcpw=1, mhz33=1, drcpw=1, cyc2ta=1, drpchg=1, drpw=1, ROMspeed=5 <H22>
; <H35> <SM57>
@nodjMEMC ; <SM30> end
ENDIF ; <SM36> rb
; =======================================================================================================
; Pratt Configuration Register initialization <K4> thru next <K4>
; (Done here so that it isn't done multiple times in SizeMemPatch)
IF hasPratt THEN
IF isUniversal THEN ;
cmp.b #PrattDecoder,DecoderKind(a1) ; do we have a Pratt <SM27>
BNE.S @NotPratt ; IF we have a Pratt THEN
ENDIF ; { isUniversal }
MOVE.B #(1<<WhitneySWIMReset)|\; Clear the reset line to swim
(1<<WhitneyEnetReset)\ ; Clear the reset line to Sonic
,WhitneyPwrCtl ;
@NotPratt
ENDIF ; { hasPratt } <K4>
; =======================================================================================================
IF forRomulator THEN ; <T3>
TestInRAM a3 ; are we in RAM?
beq.s @notInRAM2 ;
movea.l d5,a3 ; get location of original VBR <T3>
movec USP,d5 ; retrieve original buserr value <T3>
move.l d5,BusErrVct(a3) ; and restore it in the exception table <T3>
movec a3,vbr ; restore vbr <T3>
@notInRAM2
ENDIF ; { forRomulator } <T3>
jmp (a4) ; all inited, return
ALIGN 16 ; <60><62> rb, for the 040 emulator...
dc.l 0,0,0,0 ; end of list
dc.l (GotBusError-BaseOfRom)+$40A00000 ; base of Elsie II ROM <SM22> rb
dc.l (GotBusError-BaseOfRom)+$00A00000 ; base of Elsie ROM <51>
dc.l (GotBusError-BaseOfRom)+$40000000 ; alternate base of normal ROM <58> rb
dc.l (GotBusError-BaseOfRom)+$40800000 ; base of normal ROM
dc.l (GotBusError-BaseOfRom)+$00000000 ; base of overlay ROM
GotBusError btst.l #beok,d7 ; indicate that bus error occured
move.l a5,a7 ; restore stack
rts6 ; return
;_______________________________________________________________________
;
; Routine: InitVIAs
; Inputs: A0 - Pointer to table of base addresses
; A1 - Pointer to ProductInfo record for this machine
; D0 - Flags indicating which base addresses are valid
; D1 - Flags indicating which external features are valid
; D2 - Bits 15..8, BoxFlag info (possibly unknown)
; D2 - Bits 7..0, Address Decoder Kind (zero if unknown)
; A6 - return address
;
; Outputs: None
;
; Destroys: A2,A3,D3
; Called by: BSR6
;
; Function: Initializes the VIA1/VIA2/RBV direction, output and interrupt
; registers as well as general initialization of the VIAs.
;
;_______________________________________________________________________
with DecoderInfo,ProductInfo
InitVIAs
btst.l #VIA1Exists,d0 ; see if we have VIA1
beq @VIA1done ; if not, skip it
movea.l VIA1Addr(a0),a2 ; get VIA base address <SM5> rb
movea.l a1,a3 ; get product info ptr <SM5> rb
adda.l VIA1InitPtr(a3),a3 ; point to the init info <SM5> rb
btst.l #PSCExists,d0 ; is this a Cyclone ? <SM5> rb<SM4> rb, start <SM26>
beq.s @WombatVIAInit ; if not, check if we're a Wombat
;
; This change is valid only for the Cyclone VIA1 Info Table...
; The other machine tables will have to be updated to follow this initialization
; or there will be problems. The DirA, BufA, and DirB, BufB regs have been Inited
; in a different order than in previous ROMS... THIS MUST BE UPDATED!!!!
; gjs ????
;
eieioSTP
move.b (a3)+,vDirA(a2) ; init direction for port A <P9> gjs
eieioSTP
move.b (a3)+,vBufA(a2) ; init output port A <P9> gjs
eieioSTP
move.b (a3)+,vDirB(a2) ; init direction for port B <P9> gjs
eieioSTP
move.b (a3)+,vBufB(a2) ; init output port B <P9> gjs
eieioSTP
move.b (a3)+,vPCR(a2) ; init peripheral control reg <SM7> rb
eieioSTP
move.b (a3)+,vACR(a2) ; init auxiliary control reg <SM7> rb
eieioSTP
move.b #$7F,vIER(a2) ; Disable all VIA interrupts. <SM7> rb
eieioSTP
bra.s @VIA1done ; cool, keep going <SM5> rb
@WombatVIAInit ; <SM31>
IF hasDJMEMC THEN ; <SM36> rb
cmpi.b #djMEMCDecoder,d2 ; are we on a Wombat? <SM31><SM41>
bne.s @doOldVIAInit ; if not, initialize VIAs the old way <SM31><SM41>
eieioSTP
move.b (a3)+,vBufA(a2) ; init output port A <SM31>
eieioSTP
move.b (a3)+,vDirA(a2) ; init direction for port A <SM31>
eieioSTP
move.b #$1C,vACR(a2) ; enable shift-out on ACR <H25><SM31>
eieioSTP
move.b #0,vSR(a2) ; preset shift register with an ADB resetCmd <H25><SM31>
eieioSTP
move.b (a3)+,vBufB(a2) ; init output port B <SM31>
eieioSTP
move.b (a3)+,vDirB(a2) ; init direction for port B <SM31>
eieioSTP
move.b -2(a3),vBufB(a2) ; (re-)init output port B <H25><SM31>
eieioSTP
move.b (a3)+,vPCR(a2) ; init peripheral control reg <SM31>
eieioSTP
move.b (a3)+,vACR(a2) ; init auxiliary control reg <SM31>
eieioSTP
move.b #$7F,vIER(a2) ; Disable all VIA interrupts. <SM31>
eieioSTP
bra.s @VIA1done ; cool, keep going <SM31>
ENDIF ; <SM36> rb
@doOldVIAInit ; <SM4> rb, start
eieioSTP
move.b (a3)+,vBufA(a2) ; init output port A
eieioSTP
move.b (a3)+,vDirA(a2) ; init direction for port A
eieioSTP
move.b (a3)+,vBufB(a2) ; init output port B
eieioSTP
move.b (a3)+,vDirB(a2) ; init direction for port B
eieioSTP
move.b (a3)+,vPCR(a2) ; init peripheral control reg
eieioSTP
move.b (a3)+,vACR(a2) ; init auxiliary control reg
eieioSTP
move.b #$7F,vIER(a2) ; Disable all VIA interrupts.
eieioSTP
@VIA1done
btst.l #VIA2Exists,d0 ; see if we have VIA2
beq.s @VIA2done ; if not, skip it
movea.l VIA2Addr(a0),a2 ; get VIA2 base address <SM4> rb, start
movea.l a1,a3 ; get product info ptr
adda.l VIA2InitPtr(a3),a3 ; point to the init info
IF hasPSC THEN ; <SM36> rb
btst.l #PSCExists,D0 ; Make sure we're on a Cyclone. <SM26>
Beq.s @NonPSC ; Not? Then do conventional init. <SM26>
Move.b PSCVIA2SInt(A2), D3 ; get PortA (slots) current values
eieioSTP
Or.b (A3)+, D3 ; or in via2 init info values
eieioSTP
Move.b D3, PSCVIA2SInt(A2) ; save new values
eieioSTP
Move.b #$7F, PSCVIA2IER(A2) ; disable all VIA2 interrupts.
eieioSTP
Move.b #$40, PSCVIA2IFR(A2) ; clear sound frame int.
eieioSTP
Bra.s @VIA2done ; this takes care of Cyclones
@NonPSC ; <SM4> rb, end <SM26>
ENDIF ; <SM36> rb
eieioSTP
move.b vBufA(a2),d3 ; get current values
eieioSTP
or.b (a3)+,d3 ; or in the default values
eieioSTP
move.b d3,vBufA(a2) ; init output port A
eieioSTP
move.b (a3)+,vDirA(a2) ; init direction for port A
eieioSTP
move.b (a3)+,vBufB(a2) ; init output port B
eieioSTP
move.b (a3)+,vDirB(a2) ; init direction for port B
eieioSTP
move.b (a3)+,vPCR(a2) ; init peripheral control reg
eieioSTP
move.b (a3)+,vACR(a2) ; init auxiliary control reg
eieioSTP
move.b #$7F,vIER(a2) ; Disable all VIA2 interrupts.
eieioSTP
; Simulate the Macintosh VBL interrupt by using timer 1 to output a square wave on PB7 of VIA #2.
; On NuMac, this output is tied to the CA1 pin of VIA #1 which is used for VBL on a Mac.
; Timer 1 causes the PB7 output to invert each time the counter reaches 0.
; There is an additional 2 tick delay while the VIA resets the counter. We get 783360 ticks/sec
; (Which is C16M/20). Mac VBL interrupt is 60.15 (C16M/(704*370)). The VIA responds on the
; negative edges only. So:
; timer 1 = (ticks/rate)/2 - 2
; = ((C16M/20)/(C16M/(704*370)))/2 - 2
; Note: VIA2 PB7 is not tied to anything on Waimea. JAWS generates this clock for us.
@T2Count equ ((704*370)/20)/2-2 ; VIA ticks per half-cycle
eieioSTP
move.b #@T2Count**$FF,vT1C(a2) ; Load low byte into counter/latch.
eieioSTP
move.b #@T2Count>>8,vT1CH(a2) ; Load high byte and off we go!
eieioSTP
@VIA2done
btst.l #RBVExists,d0 ; see if we have an RBV
beq.s @RBVdone ; if not, skip it
movea.l RBVAddr(a0),a2 ; get RBV base address
eieioSTP
move.b #$7F,RvIER(a2) ; disable all interrupts
eieioSTP
move.b #$8F,RvDataB(a2) ; initialize data reg. B <1.3>
eieioSTP
BTST #MSCChipBit,D1 ; are we using an MSC variant? <H8>
BEQ.S @NoMSC ; -> no, continue on <H29><SM31>
; This is the point where we check to see if an external FPU is attached to <H31>
; the system. In the case of Escher, the onboard FPU will power up disabled, <H31>
; but we want to enable it here if we don't detect anything else sitting on <H31>
; the coprocessor bus. <H31>
;
; The idea is to move VBR DOWN the difference between the F-Line and
; BusError, so that if you were to execute an F-Line instruction and
; couldn't handle it, you would end up fetching the address of the
; BusErrVector and going thru the BusErrVector. The BusErr handler
; expects A6 to contain the address of where it should return TO.
movec VBR,d3 ; retrieve VBR
sub.l #Line1111-BusErrVct,d3 ; temporarily move VBR down
movec d3,VBR ; shuffle VBR for F-Line test
moveq #1,d3 ; non-zero value in D3 for later comparison
move.l a7,a5 ; sp to restore if you dont have an FPU
move.l a6,a3 ; save return address
bset #beok,d7 ; set bus error expected flag
lea @noFPU,a6 ; where to come back to if you dont have an FPU
FNOP ; execute suspect command
clr.l d3 ; if you got here, you already have an FPU
@noFPU tst.b d3 ;
beq.s @ignore ; already using an FPU so ignore internal
bclr #MSCEnableFPU,RvDataB(a2);enable onboard FPU
@ignore
movec VBR,d3 ; return VBR to it's old value
add.l #Line1111-BusErrVct,d3
movec d3,VBR ; ... so everyone is happy
bclr #beok,d7 ; release bus error expected flag
move.l a3,a6 ; restore return address <H31>
MOVE.B #$7F,RvSEnb(A2) ; disable all slot interrupts <H29><SM31>
eieioSTP
RTS6 ; <H29><SM31>
@NoMSC ; <H29><SM31>
eieioSTP
move.b #1<<RvVIDOff,RvMonP(a2) ; turn off onboard video <SM31>
eieioSTP
move.b #$FF,RvSEnb(a2) ; set all slots to be interrupt enabled <SM31>
eieioSTP
@RBVdone
rts6
;_______________________________________________________________________
;
; Routine: GetHardwareInfo
; Inputs: D2 - Bits 15..8, BoxFlag info (only if decoder kind <> 0)
; D2 - Bits 7..0, Address Decoder Kind (zero if unknown)
; A6 - return address
; A7, D7, VBR - setup for bus error handler
;
; Outputs: A0 - Pointer to DecoderInfo record for this machine
; A1 - Pointer to ProductInfo record for this machine
; D0 - Flags indicating which base addresses are valid 0-31
; D1 - Flags indicating which external features are valid 0-31
; D2 - Bits 31..16, hwCfgFlags info (possibly unknown)
; D2 - Bits 15..8, BoxFlag info (possibly unknown)
; D2 - Bits 7..0, Address Decoder Kind (zero if unknown)
;
; Destroys: A2, A5
; Called by: BSR6
;
; Function: Determines the hardware configuration of this machine.
;
; NOTE: The 'beok' bit in D7 will always be cleared when this routine exits.
;
;_______________________________________________________________________
EXPORT FoundMatch ; <SM31>
with DecoderKinds,DecoderInfo,ProductInfo
GetHardwareInfo
; Use the new CPUID register scheme if supported on this CPU. (from GetHardwareInfoPatch)
bset.l #beok,d7 ; allow bus errors
movea.l a7,a5 ; mark the stack for bus error handler
IF hasCPUIDRegister THEN ; ; <SM24> rb <SM36> rb
movea.l a6,a1 ; save return address for GetHardwareInfo in a1
bsr6 GetCPUIDReg ; get CPUID register if it exists
movea.l a1,a6 ; restore return address for GetHardwareInfo
beq.s @foundCPUIDReg ; IF we don't have a CPUID register THEN
bra HasNoCPUIDReg ; ->CONTINUE in GetHardwareInfo using old recognition method <SM7> rb
@foundCPUIDReg ; ENDIF
biglea CPUIDProductLookup-4,a2 ; get address of CPUID product lookup table
@MatchLoop ; LOOP (through product info entries to match CPU ID)
addq.w #4,a2 ; bump to next entry
move.l (a2),d1 ; see if end of list reached
beq UnknownCPU ; if we got to the end, we're severely hosed.
lea (a2,d1.l),a1 ; a1 := pointer to ProductInfo record
cmp.w CPUIDValue(a1),d0 ; see if product and CPU ID match
bne.s @MatchLoop ; if not, keep searching
btst #11,d0 ; is the complete CPU ID in the CPUID register?
beq Matched ; -> yes, we've got it
cmpi.b #PrattDecoder,\ ; IF Decoder is a Pratt THEN <K4>
DecoderKind(a1) ; Found Match <K4>
beq Matched ; { For Now just handle one case } <K4>
movea.l DecoderInfoPtr(a1),a0 ; get the pointer to this machine's decoder table
adda.l a1,a0
move.l DefaultBases(a0),d0 ; and get the default bases flags
IF hasYMCA THEN ; <SM36> rb
cmp.b #YMCADecoder,DecoderKind(a1) ; Do we have a YMCA controller <SM26> fau start
bne.s @GetVia ; No, go do the regular kind <SM26> fau end
Move.l DecoderAddr(a0),A1 ; Base of YMCA. <SM23> <SM26>
Move.l YMCA_CPUID0(A1),D0 ; Bit 0 of CPU ID. <SM23>
Move.l YMCA_CPUID1(A1),D1 ; Bit 1 of CPU ID. <SM23>
Rol.l #1,D0 ; Move to bit 0. <SM23>
And.b #1,D0 ; Only care about bit 0. <SM23>
Rol.l #2,D1 ; Move to bit 1. <SM23>
And.b #2,D1 ; Only care about bit 1. <SM23>
Or.b D1,D0 ; Complete ID. <SM23>
Move.l YMCA_CPUID2(A1),D1 ; Bit 2 of CPU ID. <SM23>
Rol.l #3,D1 ; Move to bit 1. <SM23>
And.b #4,D1 ; Only care about bit 1. <SM23>
Or.b D1,D0 ; Complete ID. <SM23>
Move.l YMCA_CPUID3(A1),D1 ; Bit 3 of CPU ID. <SM23>
Rol.l #4,D1 ; Move to bit 1. <SM23>
And.b #8,D1 ; Only care about bit 1. <SM23>
Or.b D1,D0 ; Complete ID. <SM23>
move.l (a2),d1 ; Get the relative offset to the ProductInfo record
lea (a2,d1.l),a1 ; and make it absolute
Cmp.b YMCAIdMatch(A1),D0 ; Do they match? <SM23>
Beq.s Matched ; Yes? Then let's get outta here. <P2>
Move.w CPUIDValue(a1),d0 ; Ack!!! We blew away D0 and it's needed in the MatchLoop loop, so
; we go and restore it. We are out of registers here.
Bra.s @MatchLoop ; No? Then try next product. <P2>
ENDIF ; hasYMCA <SM36> rb
@GetVia ; <SM4> rb, end
movea.l a6,a3 ; save return address for GetHardwareInfo in a1 <H16>
bsr6 GetVIAInputs ; read all of the VIA input lines into D1
movea.l a3,a6 ; restore return address for GetHardwareInfo <H16>
move.l (a2),d0 ; get the relative offset to the ProductInfo record
lea (a2,d0.l),a1 ; and make it absolute
and.l VIAIdMask(a1),d1 ; mask the VIA inputs
cmp.l VIAIdMatch(a1),d1 ; see if they match
beq.s Matched ; if so, you're done. else ... <H17><SM31>
movea.l a2,a3 ; save your place in the table in A3 <H17><SM31>
movea.l a6,a1 ; save return address for GetHardwareInfo in A1 <H17><SM31>
BSR6 GetCPUIDReg ; get CPU ID register value (again) <H17><SM31>
movea.l a1,a6 ; restore return address <H17><SM31>
movea.l a3,a2 ; restore our place in the table <H17><SM31>
bra.s @MatchLoop ; go look for another candidate to check <H17><SM31>
Matched ; END
bra.s FoundMatch ; yea!!! <SM7> rb
UnknownCPU bra.s UnknownCPU ; Ack!
ENDIF ; hasCPUIDRegister <SM24> rb <SM36> rb
HasNoCPUIDReg ; fall through to @MatchLoop
tst.b d2 ; check address decoder kind
beq.s FindDecoder ; if unknown decoder, search for it.
; The ProductKind and DecoderKind are setup in D2, find the matching ProductInfo record.
biglea ProductLookup-4,a0 ; point before the first product to check for
@MatchLoop addq.w #4,a0 ; point to next product to check for
move.l (a0),d0 ; see if end of list reached
beq.s FindDecoder ; if end, look start over, looking for decoder first
lea (a0,d0.l),a1 ; a1 := pointer to ProductInfo record
cmp.w ProductKind(a1),d2 ; see if product and decoder match
bne.s @MatchLoop ; if not, keep searching
FoundMatch
movea.l DecoderInfoPtr(a1),a0 ; get offset to DecoderInfo record
adda.l a1,a0 ; make it absolute
move.l BasesValid(a1),d0 ; get the base address valid flags
beq.s CheckBases ; we don't know for sure, so sniff around
bra CheckOptionals ; check for optional features (FPU) <8>
FindDecoder
move.l a6,d0 ; save return address in D0 for now
biglea DecoderLookup,a1 ; point to first table entry
CheckNextMap
movea.l a1,a0 ; get address of table entry
adda.l (a1)+,a0 ; a0 := pointer to DecoderInfo
movea.l CheckForProc(a0),a2 ; get offset to proc to check for this decoder
jmp (a0,a2.l) ; check for a this decoder
MapFound movea.l d0,a2 ; now save return address in A2
move.l DefaultBases(a0),d0 ; d0 := default bases valid flags
; an address decoder was found, now get all of the VIA inputs, to check for
; a match when multiple products share an address decoder.
bsr6 GetVIAInputs ; read all of the VIA input lines
movea.l a2,a6 ; restore the return address to A6
; The VIA inputs have been read into D1, now look for a matching product.
move.b AddrMap(a0),d2 ; get the address map to search for
biglea ProductLookup,a0 ; point before the first product to check for
@MatchLoop move.l (a0)+,d0 ; see if end of list reached
beq.s FindDecoder ; something is very wrong, and we don't have a clue
lea -4(a0,d0.l),a1 ; a1 := pointer to ProductInfo record
cmp.b DecoderKind(a1),d2 ; see if address decoders match
bne.s @MatchLoop ; if not, keep searching
move.l d1,d0 ; get the VIA inputs
and.l VIAIdMask(a1),d0 ; mask them
cmp.l VIAIdMatch(a1),d0 ; see if they match
bne.s @MatchLoop ; if not, try the next product
bra.s FoundMatch ; if found, return the info
CheckBases
move.l DefaultBases(a0),d0 ; get the default base flags
movea.l a6,a0 ; save return address
btst.l #RBVExists,d0 ; see if RBV might be allowed
beq.s @RBVDone ; if not, don't test for one
movea.l DecoderInfoPtr(a1),a2 ; get offset to decoder info
movea.l RBVAddr(a1,a2.l),a2
lea RvIER(a2),a2 ; base address of RBV VIER register
bsr6 TestForRvIER ; see if RBV exists
beq.s @RBVDone ; if found, has RBV and VDAC
bclr.l #RBVExists,d0 ; no RBV, clear the bit
bclr.l #VDACExists,d0 ; if no RBV, then assume no VDAC either
@RBVDone
bclr.l #VIA2Exists,d0 ; see if VIA2 might be allowed
beq.s @VIA2Done ; if not, don't test for one
movea.l DecoderInfoPtr(a1),a2 ; get offset to decoder info
movea.l VIA2Addr(a1,a2.l),a2 ; get VIA2 base address
IF hasPSC THEN ; <SM36> rb
btst.l #PSCExists, D0 ; do we have PSC? <SM4> rb, start <SM26>
Beq.s @noPSC ; no, do horror style VIA2 init <SM26>
lea PSCVIA2IER(a2),a2 ; base address of PSC VIA2 VIER register
Bra.s @gotVIA2
@noPSC ; <SM26>
ENDIF ; <SM36> rb
lea VIER(a2),a2 ; base address of VIA2 VIER register
@gotVIA2 ; <SM4> rb, end
bsr6 TestForVIER ; see if VIA2 exists
bne.s @VIA2Done ; if not found, no VIA2
bset.l #VIA2Exists,d0 ; has VIA2, set the bit
@VIA2Done
IF hasIopSwim THEN ; <SM36> rb
bclr.l #SWIMIOPExists,d0 ; see if SWIMIOP might be allowed
beq.s @SWIMIOPDone ; if not, don't test for one
movea.l DecoderInfoPtr(a1),a2 ; get offset to decoder info
movea.l SWIMIOPAddr(a1,a2.l),a2
bsr6 TestForIOP ; see if SWIM IOP exists
bne.s @SWIMIOPDone ; if not found, has regular IWM
bclr.l #IWMExists,d0 ; no regular IWM, clear the bit
bset.l #SWIMIOPExists,d0 ; has SWIMIOP, set the bit
@SWIMIOPDone
ENDIF ; <SM36> rb
IF hasIopScc THEN ; <SM36> rb
bclr.l #SCCIOPExists,d0 ; see if SCCIOP might be allowed
beq.s @SCCIOPDone ; if not, don't test for one
movea.l DecoderInfoPtr(a1),a2 ; get offset to decoder info
movea.l SCCIOPAddr(a1,a2.l),a2
bsr6 TestForIOP ; see if SCC IOP exists
bne.s @SCCIOPDone ; if not found, has regular SCC
bset.l #SCCIOPExists,d0 ; has SCCIOP, set the bit
bclr.l #SCCrdExists,d0 ; no regular SCC, clear the bit
bclr.l #SCCwrExists,d0 ; no regular SCC, clear the bit
@SCCIOPDone
ENDIF ; <SM36> rb
bclr.l #SCSIDMAExists,d0 ; see if SCSIDMA might be allowed
beq.s @SCSIDMADone ; if not, don't test for one
movea.l DecoderInfoPtr(a1),a2 ; get offset to decoder info
movea.l SCSIDMAAddr(a1,a2.l),a2
bsr6 TestForSCSIDMA ; see if SCSI DMA exists
bne.s @SCSIDMADone ; if not found, has regular SCSI
bset.l #SCSIDMAExists,d0 ; has SCSI DMA, set the bit
bclr.l #SCSIExists,d0 ; no regular SCSI
bclr.l #SCSIDackExists,d0 ; no SCSI DACK either
bclr.l #SCSIHskExists,d0 ; no SCSI Hardware Handshake either
@SCSIDMADone
; <58> rb, from Terror SCSI96AndRPUPatch <T9>
IF hasSCSI96 THEN ; <SM36> rb
bclr.l #SCSI96_1Exists, d0 ; see if 1st SCSI96 chip might be allowed
beq.s @SCSI96Done ; if not, don't test for one
movea.l DecoderInfoPtr(a1), a2 ; get offset to decoder info
movea.l SCSI96Addr1(a1,a2.l), a2 ; a2 <- SCSI96 base address
bsr6 TestForSCSI96 ; see if SCSI96 exists
bne.s @SCSI96Done ; if not found then some other SCSI hw
bset.l #SCSI96_1Exists, d0 ; has 1st SCSI96, set exists bit
bclr.l #SCSIDMAExists,d0 ; no SCSI DMA
bclr.l #SCSIExists,d0 ; no regular SCSI (5380)
bclr.l #SCSIDackExists,d0 ; no SCSI DACK
bclr.l #SCSIHskExists,d0 ; no SCSI Hardware Handshake
; Maybe we'll get lucky and fish another...
bclr.l #SCSI96_2Exists, d0 ; see if 2nd SCSI96 chip might be allowed
beq.s @SCSI96Done ; if not, don't test for one
movea.l DecoderInfoPtr(a1), a2 ; get offset to decoder info
movea.l SCSI96Addr2(a1,a2.l), a2 ; a2 <- SCSI96 base address
bsr6 TestForSCSI96 ; see if SCSI96 exists
bne.s @SCSI96Done ; if not found then some other SCSI hw
bset.l #SCSI96_2Exists, d0 ; has 1st SCSI96, set exists bit
@SCSI96Done
ENDIF ; <SM36> rb
bclr.l #RPUExists,d0 ; see if RPU might be allowed
beq.s @RPUDone ; if not, don't test for one
movea.l DecoderInfoPtr(a1),a2 ; get offset to decoder info
movea.l RPUAddr(a1,a2.l),a2
bsr6 TestForRPU ; see if SCSI DMA exists
bne.s @RPUDone ; if not found, no parity chip
bset.l #RPUExists,d0 ; has SCSI DMA, set the bit
@RPUDone
movea.l a0,a6 ; restore return address
movea.l a1,a0 ; get product info pointer
adda.l DecoderInfoPtr(a0),a0 ; get decoder info pointer
CheckOptionals
move.l HwCfgWord(a1),d2 ; access hardware cfg flags <8>
btst.l #hwCbFPU+16,d2 ; should FPU be installed
beq.s FPUDone ; branch if it shouldn't be installed <SM28>
movea.l a6,a2 ; save return address
bra TestForFPU ; see if FPU installed
FPUReturn movea.l a2,a6 ; restore return address <SM28>
beq.s FPUDone ; branch if FPU found
bclr.l #hwCbFPU+16,d2 ; otherwise,clear FPU installed flag
FPUDone
bset.l #beok,d7 ; allow bus errors <H12><H11 begin>
movea.l a7,a5 ; mark the stack for bus error handler <H12>
bclr.l #SonicExists,d0 ; see if Sonic might be allowed
beq.s @SonicDone ; if not, don't test for one
move.l a1,d1 ; save a1 <H12>
move.l SonicAddr(a0),a1 ; get Sonic Base Address <H12>
movea.l a6,a2 ; save return address
bsr6 TestForSonic ; see if Sonic exists
movea.l a2,a6 ; restore return address
move.l d1,a1 ; restore a1 <H12>
bne.s @SonicDone ; if not found, no Sonic chip
bset.l #SonicExists,d0 ; has Sonic, set the bit <H11 end>
@SonicDone
bclr.l #PatchROMExists,d0 ; see if PatchRom might be allowed <H14>.start
beq.s @PatchROMDone ; if not, don't test for one
move.l a1,d1 ; save a1 <H12>
move.l PatchRomAddr(a0),a1 ; get PatchRom Base Address <H12>
movea.l a6,a2 ; save return address
bsr6 TestForPatchRom ; see if PatchRom exists
movea.l a2,a6 ; restore return address
move.l d1,a1 ; restore a1 <H12>
bne.s @PatchRomDone ; if not found, no PatchRom chip
bset.l #PatchRomExists,d0 ; has PatchRom, set the bit <H14>.end
@PatchROMDone
; External features checked after CheckOptionals so that d1 can be used as a scratch register
CheckFeatures ; <11>
move.l ExtValid(a1),d1 ; get the external features valid flags <11>
bne.s @allDone ; know features, check for optional features <11>
move.l DefExtFeatures(a0),d1 ; get the default external features flags <11>
@allDone
bclr.l #beok,d7 ; disallow bus errors <1.7/8>
rts6 ; all done <8>
;_______________________________________________________________________ <SM17>
;
; Routine: GetExtHardwareInfo
;
; Inputs: A0 - Pointer to DecoderInfo record for this machine
; A1 - Pointer to ProductInfo record for this machine
; D2 - Bits 15..8, BoxFlag info (only if decoder kind <> 0)
; D2 - Bits 7..0, Address Decoder Kind (zero if unknown)
; A6 - return address
; A7, D7, VBR - setup for bus error handler
;
; Outputs: A0 - Pointer to DecoderInfo record for this machine
; A1 - Pointer to ProductInfo record for this machine
; D0 - Flags indicating which base addresses are valid #32-63
; D1 - Flags indicating which external features are valid #32-63
; D2 - Bits 31..16, hwCfgFlags info (possibly unknown)
; D2 - Bits 15..8, BoxFlag info (possibly unknown)
; D2 - Bits 7..0, Address Decoder Kind (zero if unknown)
; D3 - Flags indicating which base addresses are valid #64-95
; D4 - Flags indicating which external features are valid #64-95
;
; Destroys: A2, A5
; Called by: BSR6
;
; Function: Returns extended hardware information about the machine.
;
; NOTE: The 'beok' bit in D7 will always be cleared when this routine exits.
;
;_______________________________________________________________________
GetExtHardwareInfo
bset.l #beok,d7 ; allow bus errors
movea.l a7,a5 ; mark the stack for bus error handler
move.l BasesValid1(a1),d0 ; get the base address valid flags for #32-63
bne.s CheckExtOptionals1 ; IF we don't know what bases are valid THEN
CheckExtBases1
move.l DefaultBases1(a0),d0 ; get the default base flags for #32-63
movea.l a6,a0 ; save return address
;---------------
; Call "TestFor…" routines here to verify devices for #32-63 <SM17>
;---------------
; begin <SM32> fau
; See if we have a Muni
btst.l #MuniExists-32,d0 ; see if MUNI might be allowed
beq.s @MuniDone ; if not, don't test for one
movea.l DecoderInfoPtr(a1),a2 ; get offset to decoder info
movea.l (MUNIAddr,a1,a2.l),a2 ; get MUNI's base addresses
bsr6 TestForMUNI ; and go test for it
beq.s @MUNIDone ; if found, has MUNI
bclr.l #MUNIExists-32,d0 ; no MUNI, clear the bit
@MUNIDone
; See if we have a BART <SM53>
btst.l #BartExists-32,d0 ; see if BART might be allowed
beq.s @BartDone ; if not, don't test for one
movea.l DecoderInfoPtr(a1),a2 ; get offset to decoder info
movea.l (BartAddr,a1,a2.l),a2 ; get BART's base addresses
bsr6 TestForBART ; and go test for it
beq.s @BartDone ; if found, has BART
bclr.l #BartExists-32,d0 ; no BART, clear the bit
@BartDone
; end <SM32> fau
movea.l a0,a6 ; restore return address
movea.l a1,a0 ; get product info pointer
adda.l DecoderInfoPtr(a0),a0 ; get decoder info pointer
CheckExtOptionals1
;---------------
; Check for optional hardware devices for #32-63 here <SM17>
;---------------
move.l BasesValid2(a1),d3 ; get the base address valid flags for #64-95
bne.s CheckExtOptionals2 ; IF we don't know what bases are valid THEN
CheckExtBases2
move.l DefaultBases2(a0),d3 ; get the default base flags for #32-63
movea.l a6,a0 ; save return address
;---------------
; Call "TestFor…" routines here to verify devices for #64-95 <SM17>
;---------------
movea.l a0,a6 ; restore return address
movea.l a1,a0 ; get product info pointer
adda.l DecoderInfoPtr(a0),a0 ; get decoder info pointer
CheckExtOptionals2
;---------------
; Check for optional hardware devices for #64-95 here <SM17>
;---------------
;----------------------------------------------------------------------------------------
; Check external features
;----------------------------------------------------------------------------------------
CheckExtFeatures ; <11>
move.l ExtValid1(a1),d1 ; get the external features valid flags <11>
bne.s @chkFeatures1 ; know features, check for optional features <11>
move.l DefExtFeatures1(a0),d1 ; get the default external features flags <11>
@chkFeatures1
;---------------
; Check for external features here for #32-63 <SM17>
;---------------
move.l ExtValid2(a1),d4 ; get the external features valid flags <11>
bne.s @chkFeatures2 ; know features, check for optional features <11>
move.l DefExtFeatures2(a0),d4 ; get the default external features flags <11>
@chkFeatures2
;---------------
; Check for external features here for #64-95 <SM17>
;---------------
@allDone
bclr.l #beok,d7 ; disallow bus errors <1.7/8>
rts6 ; all done <8>
IF hasGlue THEN ; <SM24> rb <SM36> rb
;_______________________________________________________________________
;
; Routine: CheckForGLUE
; Inputs: A0 - Pointer to DecoderInfo record for this decoder
; A1 - Pointer to next entry in DecoderLookup table
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: Jumps to MapFound if GLUE is detected
; Jumps to CheckNextMap if not a GLUE Decoder
;
; Destroys: D1, D2, A2, A6
; Called by: BSR6
;
; Function: Checks to see a Mac II GLUE chip address decoder is present.
; A unique property of the GLUE chip is that it has a smaller
; I/O space, which repeats sooner than the other decoders in
; its class. So we check for VIA1 in it's normal place, and
; at the location that it will only wrap around with a GLUE
; decoder. If it is found in both places, then we assume that
; it is the GLUE chip decoder.
;
;_______________________________________________________________________
EXPORT CheckForGLUE ; <SM36> rb
CheckForGLUE
movea.l VIA1Addr(a0),a2
lea vIER(a2),a2
move.l #$00020000,d2 ; GLUE chip wrap offset
bsr6 TestVIERWrap ; see if it is a VIA IER register
bne.w CheckNextMap ; if not, keep searching
bra.w MapFound ; it's a Mac II GLUE decoder
ENDIF ; <SM36> rb
IF hasMDU THEN ; <SM36> rb
;_______________________________________________________________________
;
; Routine: CheckForMDU
; Inputs: A0 - Pointer to DecoderInfo record for this decoder
; A1 - Pointer to next entry in DecoderLookup table
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: Jumps to MapFound if MDU is detected
; Jumps to CheckNextMap if not a MDU Decoder
;
; Destroys: D1, D2, A2, A6
; Called by: BSR6
;
; Function: Checks to see a MDU chip address decoder is present.
; We check to see that the VIA wraps at the correct place,
; and that it doesn't wrap earlier, where the GLUE chip would
; wrap. We also check to see if the RBV and VDAC can be accessed
; without a bus error, since the MDU generates the DSACK for them
; and they shouldn't bus error, even if they don't exist. An
; OSS decoder will bus error in MDUs RBV and VDAC address ranges.
;
;_______________________________________________________________________
EXPORT CheckForMDU ; <SM36> rb
CheckForMDU
movea.l VIA1Addr(a0),a2
lea vIER(a2),a2
move.l #$00040000,d2 ; MDU chip wrap offset
bsr6 TestVIERWrap ; see if it is a VIA IER register
bne.w CheckNextMap ; if not, keep searching
sub.l #$00020000,d2 ; MDU VIA does not wrap at $20000
bsr6 TestVIERWrap ; see if it is a VIA IER register
beq.w CheckNextMap ; if so, keep searching
lea CheckNextMap,a6 ; if bus errors, not an MDU
movea.l RBVAddr(a0),a2
eieioSTP
tst.b (a2) ; RBV should never bus error
movea.l VDACAddr(a0),a2
eieioSTP
tst.b (a2) ; VDAC should never bus error
eieioSTP
bra.w MapFound ; it's a MDU decoder
ENDIF ; <SM36> rb
IF hasOss OR hasFMC THEN ; <SM36> rb
;_______________________________________________________________________
;
; Routine: CheckForOSSFMC
; Inputs: A0 - Pointer to DecoderInfo record for this decoder
; A1 - Pointer to next entry in DecoderLookup table
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: Jumps to MapFound if OSS/FMC is detected
; Jumps to CheckNextMap if not a OSS/FMC Decoder
;
; Destroys: D1, D2, A2, A6
; Called by: BSR6
;
; Function: Checks to see a OSS/FMC address decoder is present.
; We check to see that the VIA wraps at the correct place,
; and that it doesn't wrap earlier, where the GLUE chip would
; wrap. We also check to see if an OSS mask register exists,
; by trying to load it with priorities 1..6 (don't use 7, since
; if may cause a NMI to be generated).
;
;_______________________________________________________________________
EXPORT CheckForOSSFMC ; <SM36> rb
CheckForOSSFMC
movea.l VIA1Addr(a0),a2
lea vIER(a2),a2
move.l #$00040000,d2 ; OSS chip wrap offset
bsr6 TestVIERWrap ; see if it is a VIA IER register
bne.w CheckNextMap ; if not, keep searching
sub.l #$00020000,d2 ; OSS VIA does not wrap at $20000
bsr6 TestVIERWrap ; see if it is a VIA IER register
beq.w CheckNextMap ; if so, keep searching
lea CheckNextMap,a6 ; if bus errors, not an OSS
movea.l OSSAddr(a0),a2
move.b OSSMskFirst(a2),d1 ; save the old contents
lsl.w #8,d1 ; make room for temp use of low byte
moveq.l #6,d2 ; loop counter / data pattern
@OssLoop move.b d2,OSSMskFirst(a2) ; store a value (don't allow NMI=7)
TST.L AllOnes ; put $FFFFFFFF on the bus to scramble it <2>
move.b OSSMskFirst(a2),d1 ; read it back
andi.b #$07,d1 ; expect low bits to change
cmp.b d1,d2 ; see if they did
dbne d2,@OssLoop ; loop through all patterns
@Done lsr.w #8,d1 ; get saved value
move.b d1,OSSMskFirst(a2) ; restore it
tst.w d2 ; see if all patterns compared
bpl.w CheckNextMap ; if not, it's not an OSS chip
bra.w MapFound ; otherwise it's an OSS decoder
AllOnes dc.l $FFFFFFFF ; <2>
ENDIF ; <SM24> rb
IF hasVISADecoder THEN ; <SM36> rb
;_______________________________________________________________________
;
; Routine: CheckForVISADecoder
; Inputs: A0 - Pointer to DecoderInfo record for this decoder
; A1 - Pointer to next entry in DecoderLookup table
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: Jumps to MapFound if VISA decoder is detected
; Jumps to CheckNextMap if not a VISA Decoder
;
; Destroys: D1, D2, A2, A6
; Called by: BSR6
;
; Function: Checks to see if a VISA address decoder is present.
; First, we check for a VIA IER at the correct address.
; If it is there, we check that it does not appear again
; at an offset of $00040000 in order to eliminate GLUE, MDU,
; and OSS, all of which wrap at this offset. We also check
; to see if the VISA (RBV) and VDAC can be accessed
; without a bus error, since the VISA generates the DSACK for them
; and they shouldn't bus error, even if they don't exist. An
; OSS decoder will bus error in VISAs RBV and VDAC address ranges.
;
;_______________________________________________________________________
EXPORT CheckForVISADecoder ; <SM36> rb
CheckForVISADecoder
movea.l VIA1Addr(a0),a2 ; look for a VIA IER
lea vIER(a2),a2
bsr6 TestForVIER
bne.w CheckNextMap ; not found means can't be a VISA
move.l #$00040000,d2 ; other decoders wrap at this offset
bsr6 TestVIERWrap
beq.w CheckNextMap ; if it wraps, it's not a VISA
lea CheckNextMap,a6 ; if bus errors, not an MDU
movea.l RBVAddr(a0),a2
eieioSTP
tst.b (a2) ; VISA should never bus error
movea.l VDACAddr(a0),a2
eieioSTP
tst.b (a2) ; VDAC should never bus error
eieioSTP
bra.w MapFound ; if not, it's a VISA decoder
ENDIF ; <SM36> rb
IF hasOrwell THEN ; <SM24> rb <SM36> rb
;_______________________________________________________________________
;
; Routine: CheckForOrwell <13>
; Inputs: A0 - Pointer to DecoderInfo record for this decoder <13>
; A1 - Pointer to next entry in DecoderLookup table <13>
; A5, A7, D7, VBR - setup for bus error handler <13>
;
; Outputs: Jumps to MapFound if Orwell is detected <13>
; Jumps to CheckNextMap if not an Orwell Decoder <13>
;
; Destroys: D2, A2 <13>
; Called by: BSR6 <13>
;
; Function: Checks to see an Orwell address decoder is present. We check to see<13>
; if we get a bus error when trying to access Orwell's I/O control <13>
; register I/O space. Orwell is the only decoder that doesn't bus <13>
; error in that part of I/O space. <13>
;
;_______________________________________________________________________
EXPORT CheckForOrwell ; <SM36> rb
CheckForOrwell
lea CheckNextMap,a6 ; return to decoder search if we bus error <19>
movea.l DecoderAddr(a0),a2 ; look for an Orwell <SM17>
move.l (a2),d2 ; Orwell won't bus error <13>
bra.w MapFound ; otherwise it is an Orwell decoder <13>
ENDIF ; <SM36> rb
IF hasJaws THEN ; <SM36> rb
;_______________________________________________________________________ <SM4> rb, start
;
; Routine: CheckForJAWS
; Inputs: A0 - Pointer to DecoderInfo record for this decoder
; A1 - Pointer to next entry in DecoderLookup table
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: Jumps to MapFound if JAWS is detected
; Jumps to CheckNextMap if not a JAWS Decoder
;
; Destroys: D1, D2, A2, A6
; Called by: BSR6
;
; Function: Checks to see a JAWS chip address decoder is present.
; By the time we get here we already know that the VIA does not
; wrap at $40000 or $20000, and that the RBV and VDAC addresses
; cause a bus error. Just to be safe though, we do some of the
; same VIA checks that were done before.
;
;_______________________________________________________________________
EXPORT CheckForJAWS ; <SM36> rb
CheckForJAWS
movea.l VIA1Addr(a0),a2 ; Look for VIA wrap a various places
lea vIER(a2),a2
move.l #$00100000,d2 ; JAWS does wrap at $100000 <8> HJR
bsr6 TestVIERWrap ; see if it is a VIA IER register <8> HJR
bne.w CheckNextMap ; if so, keep searching <8> HJR
lsr.l #1,d2 ; JAWS doesn't wrap at $80000 <8> HJR
bsr6 TestVIERWrap ; see if it is a VIA IER register <8> HJR
beq.w CheckNextMap ; if not, keep searching <8> HJR
lsr.l #1,d2 ; JAWS doesn't wrap at $40000 <8> HJR
bsr6 TestVIERWrap ; see if it is a VIA IER register <8> HJR
beq.w CheckNextMap ; if so, keep searching
lea CheckNextMap,a6 ; now try the JAWS registers
movea.l JAWSAddr(a0),a2
tst.b (a2) ; JAWS should never bus error
bra.w MapFound ; it's a JAWS decoder
ENDIF ; <SM36> rb
IF hasNiagra THEN ; <SM36> rb
;_______________________________________________________________________ <H17> thru next
; <H17>
; Routine: CheckForNiagra
; Inputs: A0 - Pointer to DecoderInfo record for this decoder
; A1 - Pointer to next entry in DecoderLookup table
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: Jumps to MapFound if Niagra is detected
; Jumps to CheckNextMap if not a Niagra Decoder
;
; Destroys: D1, D2, A2, A6
; Called by: BSR6
;
; Function: Checks to see a Niagra chip address decoder is present.
; By the time we get here we already know that the VIA does not
; wrap at $40000 or $20000, and that the RBV and VDAC addresses
; cause a bus error. Just to be safe though, we do some of the
; same VIA checks that were done before.
;
;_______________________________________________________________________
Export CheckForNiagra
CheckForNiagra
movea.l VIA1Addr(a0),a2 ; Look for VIA wrap a various places
lea vIER(a2),a2
move.l #$FF200000,d2 ; Niagra doesn't wrap at $50100000
bsr6 TestVIERWrap ; see if it is a VIA IER register
beq.w CheckNextMap ; if not, keep searching
move.l #$00080000,d2 ; Niagra doesn't wrap at $00080000
bsr6 TestVIERWrap ; see if it is a VIA IER register
beq.w CheckNextMap ; if not, keep searching
lsr.l #1,d2 ; Niagra doesn't wrap at $40000
bsr6 TestVIERWrap ; Niagra if it is a VIA IER register
beq.w CheckNextMap ; if so, keep searching
lea CheckNextMap,a6 ; now try the Niagra registers
movea.l JAWSAddr(a0),a2
tst.b (a2) ; Niagra should never bus error
bra.w MapFound ; it's a Niagra decoder
; <H17> <SM4> rb,end
ENDIF ; <SM24> rb
;_______________________________________________________________________
;
; Routine: CheckForUnknown
; Inputs: A0 - Pointer to DecoderInfo record for this decoder
; A1 - Pointer to next entry in DecoderLookup table
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: Jumps to MapFound always.
;
; Destroys: D1, D2, A2, A6
; Called by: BSR6
;
; Function: This is the last decoder on the list of decoders to search,
; so if we get here, we can't identify the address decoder.
; We return to MapFound to indicate that this unknown decoder
; exists, but if we get here, we are really dead, and can't
; figure out enough to even try to tell someone about it.
;
;_______________________________________________________________________
CheckForUnknown
bra.w MapFound
;_______________________________________________________________________
;
; Routine: TestForVIER, TestVIERWrap
; Inputs: A2 - Address of the VIER register to test
; D2 - offset of alternate address to check for (wrap around)
; Used by TestVIERWrap, set to zero for TestForVIER.
; A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if not a valid VIER register, or bus error.
; - 1 (beq) if valid VIER register found.
;
; Destroys: D1
; Called by: BSR6
;
; Function: Checks to see if the specified I/O register is a VIA IER
; (interrupt enable) register, by first setting all bits of
; the register, and then clearing each bit individually.
; Also checks to see if the same register also exists at an
; alternate address in I/O space, to detect specific address
; wrap around characteristics of some address decoders.
;
;_______________________________________________________________________
TestForVIER ; A2 := address of VIER register to test
moveq.l #0,d2 ; D2 := wrap offset to test
TestVIERWrap ; A2 := address of VIER register to test
eieioSTP
tst.b (a2,d2.l) ; make sure wrap address can be accessed
eieioSTP
move.b (a2),d1 ; save old VIER value
eieioSTP
rol.w #8,d1 ; save it in the next byte
st.b d1 ; test pattern := $FF
move.b d1,(a2) ; set all bits of VIER
eieioSTP
@loop neg.b d1 ; pattern of bit to clear
eieioSTP
move.b d1,(a2) ; clear the lowest order bit
add.b d1,d1 ; shift the test pattern
beq.s @exit ; exit when all bits shifted out
neg.b d1 ; convert to mask of bits that should be set
eieioSTP
cmp.b (a2,d2.l),d1 ; see if they are set at the wrap address
eieioSTP
bne.s @exit ; if not, exit
cmp.b (a2),d1 ; see if they are set at the standard address
eieioSTP
beq.s @loop ; if so, keep testing
@exit ror.w #8,d1 ; get saved VIER value
eieioSTP
move.b #$7F,(a2) ; prepare to restore (clear all bits)
eieioSTP
move.b d1,(a2) ; restore original VIER value
eieioSTP
lsr.w #8,d1 ; 0 if VIER found
rts6
;_______________________________________________________________________
;
; Routine: TestForRvIER
; Inputs: A2 - Address of the RvIER register to test
; A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if not a valid RvIER register, or bus error.
; - 1 (beq) if valid RvIER register found.
;
; Destroys: D1, D2
; Called by: BSR6
;
; Function: Checks to see if the specified I/O register is a RBV IER
; (interrupt enable) register, by first setting all bits of
; the register, and then clearing each bit individually.
; There are some reserved bits in the RvIER register, which
; are ignored by this test.
;
;_______________________________________________________________________
TestForRvIER ; A2 := address of RvIER register to test
move.b (a2),d1 ; save old RvIER value
rol.w #8,d1 ; save it in the next byte
st.b d1 ; test pattern := $FF
eieioSTP
move.b d1,(a2) ; set all bits of RvIER
@loop
neg.b d1 ; pattern of bit to clear
eieioSTP
move.b d1,(a2) ; clear the lowest order bit
add.b d1,d1 ; shift the test pattern
beq.s @exit ; exit when all bits shifted out
neg.b d1 ; convert to mask of bits that should be set
eieioSTP
move.b (a2),d2 ; get the RvIER value
eor.b d1,d2 ; compare them
andi.b #$9F,d2 ; ignore the reserved bits
beq.s @loop ; if match found, keep testing
@exit ror.w #8,d1 ; get saved RvIER value
eieioSTP
move.b #$7F,(a2) ; prepare to restore (clear all bits)
eieioSTP
move.b d1,(a2) ; restore original RvIER value
eieioSTP
lsr.w #8,d1 ; 0 if RvIER found
rts6
;_______________________________________________________________________
;
; Routine: TestForSCC
; Inputs: A2 - Base write address of the SCC to test for.
; D2 - offset to SCC read base address from write base
; A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if SCC not found, or bus error.
; - 1 (beq) if valid SCC found.
;
; Destroys: D1
; Called by: BSR6
;
; Function: Checks to see if the specified I/O registers point to an
; SCC. The read and write addresses may be specified separatly
; since some address decoders require this. An SCC is detected
; by writing a two byte signature to the time constant register
; and reading it back. The old value is saved and restored to
; make this test non-destructive. In order to meet SCC timing
; requirements on systems like the Mac Plus that do not provide
; a hardware holdoff, extra delays are introduced between SCC
; accesses.
;
;_______________________________________________________________________
TestForSCC ; A2 := address of SCCrd
; D2 := offset of SCCwr-SCCrd
eieioSTP
tst.b bCtl(a2,d2.l) ; reset register pointer to reg 0
ror.b #8,d1 ; kill some time, non-destructive
eieioSTP
move.b #13,bCtl(a2) ; point to register 13, time const high
ror.b #8,d1 ; kill some time, non-destructive
eieioSTP
move.b bCtl(a2,d2.l),d1 ; save old time const high byte
ror.b #8,d1 ; kill some time, non-destructive
eieioSTP
move.b #12,bCtl(a2) ; point to register 12, time const low
lsl.l #8,d1 ; make room for low byte, kill time
eieioSTP
move.b bCtl(a2,d2.l),d1 ; save old time const low byte
ror.b #8,d1 ; kill some time, non-destructive
eieioSTP
move.b #13,bCtl(a2) ; point to register 13, time const high
ror.b #8,d1 ; kill some time, non-destructive
eieioSTP
move.b #'G',bCtl(a2) ; load in signature high byte
ror.b #8,d1 ; kill some time, non-destructive
eieioSTP
move.b #12,bCtl(a2) ; point to register 12, time const low
ror.b #8,d1 ; kill some time, non-destructive
eieioSTP
move.b #'D',bCtl(a2) ; load in signature low byte
ror.b #8,d1 ; kill some time, non-destructive
eieioSTP
move.b #13,bCtl(a2) ; point to register 13, time const high
lsl.l #8,d1 ; make room for byte, kill time
eieioSTP
move.b bCtl(a2,d2.l),d1 ; read back signature high byte
ror.b #8,d1 ; kill some time, non-destructive
eieioSTP
move.b #12,bCtl(a2) ; point to register 12, time const low
lsl.l #8,d1 ; make room for byte, kill time
eieioSTP
move.b bCtl(a2,d2.l),d1 ; read back signature low byte
subi.w #'GD',d1 ; see if signature matched
ror.l #8,d1 ; setup to restore, kill some time
eieioSTP
move.b #12,bCtl(a2) ; point to register 12, time const low
ror.l #8,d1 ; position saved low byte of time const
eieioSTP
move.b d1,bCtl(a2) ; restore original time const low byte
ror.b #8,d1 ; kill some time, non-destructive
eieioSTP
move.b #13,bCtl(a2) ; point to register 13, time const high
lsr.l #8,d1 ; get the high byte
eieioSTP
move.b d1,bCtl(a2) ; restore original time const high byte
lsr.l #8,d1 ; test signature for match
rts6 ; all done
;_______________________________________________________________________
;
; Routine: TestForIOP
; Inputs: A2 - Base address of IOP to test for.
; A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if IOP not found, or bus error.
; - 1 (beq) if valid IOP found.
;
; Destroys: D1, D2
; Called by: BSR6
;
; Function: Checks to see if the specified I/O registers point to an
; IOP. Since the IOP chip generates it's own DSACK, a Bus
; Error may occur if it doesn't exist, which would cause this
; routine to return through the bus error handler, indicating
; that an IOP doesn't exist. If no bus errors occur, we
; verify that a long word read from the IOPRamData register
; causes the IOPRamAddr register to incement by 4. All of the
; IOP registers used are saved and restored, making this test
; non-destructive.
;
;_______________________________________________________________________
TestForIOP ; A2 := Base address of IOP to test
eieioSTP
move.b iopStatCtl(a2),d1 ; save status/ctl register value
moveq.l #(1<<iopIncEnable)+(1<<iopRun),d2 ; mask for bits to save
and.b d1,d2 ; get those bits
swap d1 ; save old status ctl reg
eieioSTP
move.w iopRamAddr(a2),d1 ; save Ram Address register value
ori.b #(1<<iopIncEnable),d2 ; enable increment <2.5>
eieioSTP
move.b d2,iopStatCtl(a2) ; enable register pointer incrementing
eieioSTP
tst.l iopRamData(a2) ; read and ignore 4 bytes of Ram
eieioSTP
move.w iopRamAddr(a2),d2 ; save updated Ram Address register value
eieioSTP
move.w d1,iopRamAddr(a2) ; restore Ram Address register value
subq.w #4,d2 ; back off the 4 byte increment
sub.w d1,d2 ; check for increment
swap d1 ; get status ctl reg
andi.b #-1-(1<<iopInt0Active)-(1<<iopInt1Active),d1
eieioSTP
move.b d1,iopStatCtl(a2) ; restore status/ctl register
tst.w d2 ; d2 = 0 if IOP found
eieioSTP
rts6
;_______________________________________________________________________
;
; Routine: TestForSCSIDMA
; Inputs: A2 - Base address of SCSI DMA to test for.
; A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if SCSI DMA not found, or bus error.
; - 1 (beq) if valid SCSI DMA found.
;
; Destroys: none
; Called by: BSR6
;
; Function: Checks to see if the specified I/O registers point to a
; SCSI DMA chip. Since the SCSI DMA chip generates it's own
; DSACK, a Bus Error may occur if it doesn't exist, which would
; cause this routine to return through the bus error handler,
; indicating that it doesn't exist. For now we just simply test
; to see if we can read the control register without getting
; a bus error. If we are successful, we assume that the chip
; exists. This test may need to be improved in the future.
;
;_______________________________________________________________________
TestForSCSIDMA ; A2 := Base address of SCSI DMA to test
eieioSTP
tst.l $80(a2) ; try to read the control register
eieioSTP
cmp.b d1,d1 ; if no bus error, assume that it exists
rts6
; <58> rb, from Terror...
;_______________________________________________________________________ thru matching <T8>
;
; Routine: TestForSCSI96
; Inputs: A2 - Base address of SCSI Port to test.
; A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if SCSI 5380 not found, or bus error.
; - 1 (beq) if SCSI 5396 found.
;
; Destroys: none
; Called by: BSR6
;
; Function: Checks to see if we have a SCSI 5380 chip or the more advance
; SCSI 5394/5396 controller. The test is to access a register
; the 5394/5396 has that the 53c80 does not. An access to a non-existent
; address would cause us to BusError. Unfortunately, there is a possibility <T14>
; that a non-existent address is decoded by HW anyway so if we pass bus-err <T14>
; test we verify the contents of the regr with expected value for safety. <T14>
;
;_______________________________________________________________________
; the CMPI will be .NE. if the address we write to does not bus error, but is in <T14>
; reality, not there. So the CMPI above actually checks to see if the data stuck. <T14>
TestForSCSI96 ; A2 = Base address of SCSI port to test
eieioSTP
tst.b $c0(a2) ; try to read configuration #3 register (r/w)
eieioSTP
cmpi.b #$04, $c0(a2) ; ...verify data written in config. regr 3 <T14>
eieioSTP
rts6
;_______________________________________________________________________
;
; Routine: TestForRPU
; Inputs: A2 - Base address of RPU to test for.
; A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if RPU not found, or bus error.
; - 1 (beq) if valid RPU found.
;
; Destroys: D1,D2
; Called by: BSR6
;
; Function: Checks to see if the RPU (Ram Parity Unit) is present by writing
; to the WWP bit of the chip (the only r/w bit) and reading back,
; making sure bus capacitance doesn't make it look valid.
;
;_______________________________________________________________________
TestForRPU ;
eieioSTP
tst.b (a2) ; x First 4 reads are unique
eieioSTP
tst.b (a2) ; x
eieioSTP
tst.b (a2) ; PDCA Read out the parity daisy chain bits
eieioSTP
tst.b (a2) ; PDCB and toss them (no where to save them)
eieioSTP
st.b rpuReset(a2) ;reset the RPU serial pointer
eieioSTP
move.b (a2),d2 ;save the WWP bit
eieioSTP
st.b rpuReset(a2) ;reset the RPU serial pointer
eieioSTP
st.b (a2) ;set the WWP bit
eieioSTP
clr.b rpuReset(a2) ;force bus low, reset pointer
moveq #1,d1 ;check bit 0
eieioSTP
and.b (a2),d1 ;read WWP bit
seq.b d1 ;d1=FF if WWP bit was 0
beq.s @exit ;exit if WWP bit=0
eieioSTP
st.b rpuReset(a2) ;reset the RPU serial pointer
clr.b (a2) ;clear the WWP bit
eieioSTP
st.b rpuReset(a2) ;force bus high, reset pointer
moveq #1,d1 ;check bit 0
eieioSTP
and.b (a2),d1 ;read WWP bit
@exit
eieioSTP
st.b rpuReset(a2) ;reset pointer for exit
move.b d2,(a2) ;restore WWP bit
tst.b d1 ;test result
eieioSTP
rts6
;_______________________________________________________________________ <SM32>
;
; Routine: TestForMUNI
; Inputs: A2 - Address of the MUNI Control register to test
; A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if not a valid MUNI Control register, or bus error.
; - 1 (beq) if valid MUNI Control register found.
;
; Destroys: D1, D2
; Called by: BSR6
;
; Function: Checks to see if the specified MUNI Control register
; exists by writing to it and seeing if we get a bus error.
; If we do, then we have no MUNI.
; Since the MUNI chip generates it's own
; DSACK, a Bus Error may occur if it doesn't exist, which would
; cause this routine to return through the bus error handler,
; indicating that it doesn't exist. For now we just simply test
; to see if we can read the control register without getting
; a bus error. If we are successful, we assume that the chip
; exists. This test may need to be improved in the future.
;
;
;_______________________________________________________________________
TestForMUNI ; A2 := address of MUNI register to test
eieioSTP
tst.l MUNI_Control(a2) ; try to read the control register
eieioSTP
cmp.b d1,d1 ; if no bus error, assume that it exists
rts6
;_______________________________________________________________________ <SM53>
;
; Routine: TestForBart
; Inputs: A2 - Address of BART
; A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if no BART, or bus error.
; - 1 (beq) if BART found.
;
; Destroys: D1, D2
; Called by: BSR6
;
; Function: Checks to see if BART exists by accessing it and seeing if
; we get a bus error. If we do, then we don't have a BART. This
; test should be extended in the future to check the version register
; in BART.
;
;
;_______________________________________________________________________
TestForBart ; A2 := address of BART register to test
eieioSTP
tst.b (a2) ; try to read BART
cmp.b d1,d1 ; if no bus error, assume that it exists
eieioSTP
rts6
; <SM28> fau start
;_______________________________________________________________________
;
; Routine: TestForFPU
; Inputs: A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if FPU not found.
; - 1 (beq) if FPU available.
;
; Destroys: A6, D1, sfc
; Called by: BRA
;
; Function: Checks to see if an FPU is installed.
;
; NOTE: this routine is BRA'nched to, not BSR6'ed, so that A6 is
; available for trashing in this routine.
;
; NOTE2: this needed to be changed because with an 040LC you're
; no longer guaranteed to have an on-board FPU.
;_______________________________________________________________________
TestForFPU
IF ROMinRAM THEN ; <SM22> rb
movec CACR,d1 ; MacsBug does not like the fpu <SM22> rb
cmp.b d1,d1 ; code when booting from RAM <SM22> rb
bra FPUReturn ; <SM22> rb
ELSE ; <SM22> rb
; New, Improved method of on-the-fly checking for and FPU
movec VBR,d1 ; retrieve VBR
; The idea is to move VBR DOWN the difference between the F-Line and
; BusError, so that if you were to execute an F-Line instruction and
; couldn't handle it, you would end up fetching the address of the
; BusErrVector and going thru the BusErrVector. The BusErr handler
; expects A6 to contain the address of where it should return TO.
sub.l #Line1111-BusErrVct,d1; temporarily move VBR down
movec d1,VBR ; shuffle VBR for F-Line test
moveq #1,d1 ; non-zero value in D1 for later comparison
lea @noFPU,a6 ; where to come back to if you dont have an FPU
eieioSTP
FNOP ; execute suspect command
eieioSTP
clr.l d1 ; if you got here, you have an FPU
@noFPU move.l d1,a6 ; save D1
movec VBR,d1 ; return VBR to it's old value
add.l #Line1111-BusErrVct,d1
movec d1,VBR ; ... so everyone is happy
move.l a6,d1 ; restore D1
tst.b d1 ; return CCR.Z to CheckOptionals
@exit bra FPUReturn ; and return to CheckOptionals <SM28> fau end
ENDIF ; <SM22> rb
;_______________________________________________________________________
;
; Routine: GetVIAInputs
; Inputs: A0 - Pointer to Decoder Info record for this decoder
; D0 - DefaultBases flags for this decoder
; A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: D1 - Bits 31..24, inputs from VIA1, port A
; D1 - Bits 23..16, inputs from VIA1, port B
; D1 - Bits 15.. 8, inputs from VIA2, port A
; D1 - Bits 7.. 0, inputs from VIA2, port B
;
; Destroys: D2, A1
; Called by: BSR6
;
; Function: Reads the input ports for VIA 1 and 2 if they are supported
; by the current address decoder (which does not imply that
; they actually exist). If the are not supported, zeros will
; be returned, if they are supported, but do not exist, the results
; are unpredictable, but are most likely the value of a floating
; data bus. The values of the data direction registers are saved
; and restored, which makes this non-destructive.
;
;_______________________________________________________________________
GetVIAInputs
moveq.l #0,d1 ; initialize via info result
btst.l #VIA1Exists,d0 ; see if VIA1 exists
beq.s @noVIA1 ; if not, skip it
movea.l VIA1Addr(a0),a1 ; get the VIA1 base address
eieioSTP
move.b vBufA(a1),d2 ; save port A
eieioSTP
lsl.w #8,d2 ; make room for direction bits
move.b vDirA(a1),d2 ; save direction bits
move.b d2,d1 ; get prior direction bits
eieioSTP
and.b AvoidVIA1A(a0),d1 ; if we need to avoid any output, don't make them input
eieioSTP
move.b d1,vDirA(a1) ; change bits to inputs
eieioSTP
move.b vBufA(a1),d1 ; get port A inputs
eieioSTP
move.b d2,vDirA(a1) ; restore direction bits
lsr.w #8,d2 ; get saved port A
eieioSTP
move.b d2,vBufA(a1) ; restore port A
lsl.w #8,d1 ; make room for port B bits
eieioSTP
move.b vBufB(a1),d2 ; save port B
lsl.w #8,d2 ; make room for direction bits
eieioSTP
move.b vDirB(a1),d2 ; save direction bits
eieioSTP
move.b d2,d1 ; get prior direction bits
and.b AvoidVIA1B(a0),d1 ; if we need to avoid any output, don't make them input
eieioSTP
move.b d1,vDirB(a1) ; change bits to inputs
eieioSTP
move.b vBufB(a1),d1 ; get port B inputs
eieioSTP
move.b d2,vDirB(a1) ; restore direction bits
eieioSTP
lsr.w #8,d2 ; get saved port B
move.b d2,vBufB(a1) ; restore port B
eieioSTP
@noVIA1
swap d1 ; VIA1 info to high word
btst.l #VIA2Exists,d0 ; see if VIA2 exists
beq.s @noVIA2 ; if not, skip it
eieioSTP
movea.l VIA2Addr(a0),a1 ; get the VIA2 base address
eieioSTP
move.b vBufA(a1),d2 ; save port A
eieioSTP
lsl.w #8,d2 ; make room for direction bits
move.b vDirA(a1),d2 ; save direction bits
eieioSTP
move.b d2,d1 ; get prior direction bits
and.b AvoidVIA2A(a0),d1 ; if we need to avoid any output, don't make them input
eieioSTP
move.b d1,vDirA(a1) ; change bits to inputs
eieioSTP
move.b vBufA(a1),d1 ; get port A inputs
eieioSTP
move.b d2,vDirA(a1) ; restore direction bits
eieioSTP
lsr.w #8,d2 ; get saved port A
move.b d2,vBufA(a1) ; restore port A
eieioSTP
lsl.w #8,d1 ; make room for port B bits
move.b vBufB(a1),d2 ; save port B
eieioSTP
lsl.w #8,d2 ; make room for direction bits
move.b vDirB(a1),d2 ; save direction bits
eieioSTP
move.b d2,d1 ; get prior direction bits
and.b AvoidVIA2B(a0),d1 ; if we need to avoid any output, don't make them input
eieioSTP
move.b d1,vDirB(a1) ; change bits to inputs
eieioSTP
move.b vBufB(a1),d1 ; get port B inputs
eieioSTP
move.b d2,vDirB(a1) ; restore direction bits
eieioSTP
lsr.w #8,d2 ; get saved port B
move.b d2,vBufB(a1) ; restore port B
eieioSTP
@noVIA2
rts6 ; all done
;_______________________________________________________________________
;
; Routine: TestForSonic
; Inputs: A1 - Base address of Sonic to test.
; A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if Sonic not found, or bus error.
; - 1 (beq) if Sonic found.
;
; Destroys: none
; Called by: BSR6
;
; Function: Checks to see if we have a Sonic Ethernet chip. An access to a non-existent
; address MUST cause us to BusError.
;
;_______________________________________________________________________
TestForSonic ; A1 = Base address of Sonic Chip to test <H12 begin>
eieioSTP
tst.b (a1) ; try to read the Command Register
eieioSTP
bset #7,(a1) ; send a SW Reset to Sonic <H30><SM40>
eieioSTP
cmp d1,d1 ; set ccr.z because no bus error if we made it here
rts6 ; return with flags set
;_______________________________________________________________________
;
; Routine: TestForPatchROM
; Inputs: A1 - Base address of PatchROM to test.
; A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if PatchROM not found, or bus error.
; - 1 (beq) if PatchROM found.
;
; Destroys: a1
; Called by: BSR6
;
; Function: Checks to see if we have a PatchROM. An access to a non-existent
; address MUST cause us to BusError.
;
;_______________________________________________________________________
TestForPatchROM ; A1 = Base address of PatchROM to test <H12 begin>
eieioSTP
tst.b (a1) ; try to read the first byte
eieioSTP
movea.l $4(a1),a1 ; load signature into a1
eieioSTP
exg a1,d1 ; because we have no free registers
cmpi.l #'romp',d1 ; set ccr.z if signtures match
exg a1,d1 ; because we have no free registers
rts6 ; return with flags set
;__________________________________________________________________________________________________
;
; Routine: GetCPUIDReg
;
; Inputs: A6 - return address
; A5, A7, D7, VBR - setup for bus error handler
;
; Outputs: ccr.z - 0 (bne) if CPUID reg not found or bus error.
; - 1 (beq) if CPUID reg found.
; D0.w - CPUID if CPUID reg found.
;
; Destroys: D0, D1, A2
;
; Function: Checks for the existance of a CPU ID register. If one is found, it checks to see
; if the value in the register matches the expected value for the current decoder
; type. The register is a long word located at $5FFFFFFC, and contains the following
; information.
;
; bits 31-16: signature $A55A
; 15-12: design center
; 0 = high volume
; 1 = portables
; 2 = high end Macintosh
; 3 = RISC
; 11: extension
; 0=complete ID appears in this register
; 1=supplemental ID appears in VIA or equivalent
; 10- 0: ID
;__________________________________________________________________________________________________
IF hasCPUIDRegister THEN ; <SM24> rb <SM36> rb
GetCPUIDReg
IF ROMinRAM THEN ; <SM22> rb
move.l #$A55A2830,d0 ; ••• HACK, force Cyclone, make your <SM22> rb
cmp.w d0,d0 ; ModifyReadOnly hack here. Cyclone <SM22> rb
jmp (a6) ; needs this because the MMU is <SM22> rb
ENDIF ; hiding the CPUIDReg one we booted <SM22> rb
IF forSmurf THEN
; Read the CPUID bits from the via register. Orwells/djmemc both have
; via addrs at $50F0000 (but for smurfs, use $50000000)
movea.l #$50000000,a2 ; get the VIA1 base address
;now get the cpuid bits from the via register
move.b vBufA(a2),d2 ; save port A
lsl.w #8,d2 ; make room for direction bits
move.b vDirA(a2),d2 ; save direction bits
move.b d2,d1 ; get prior direction bits
move.b #0,vDirA(a2) ; change bits to inputs
move.b vBufA(a2),d1 ; get port A inputs
move.b d2,vDirA(a2) ; restore direction bits
lsr.w #8,d2 ; get saved port A
move.b d2,vBufA(a2) ; restore port A
; d1.b now contains the cpuid bits. so use $56 to mask out leaving us with the
; cpuid bits PA6, PA4, PA2, PA1
andi.b #$56,d1 ; d1.b now contains the cpu id bits from the via
; now find out if we are on a machine with a djmemc decoder or and orwell.
; djmec have a 12 bit register, bits 11..9 contain the version number for the djmemc...
; Game Plan: read from the 12 bit register. if bits 11..9 = 010 then djmec
lea #MEMCAddr,a2 ; Orwell or djmec decoder addr.
move.l MEMCIntleaveEnable(a2),d0 ; read the 12 bit register at the base of DJMEMC/Orwell
andi.w #$0E00,d0 ; mask out all bits except version bits at bit 11..9
cmpi.w #$0200,d0 ; the version number for djmec is 010 for bits 11..9
beq.s @tryCentris610 ; if equal than on djmec machine..via id bits will match
; those for wombat machines
@tryQ700
cmpi.b #$40,d1 ; is it a quadra700
bne.s @tryQ900
MOVE.W #(cpuIDRISC)|\ ; CPU ID: RISC design center
$1235,D0 ; return emulator CPU ID
BRA @success
@tryQ900
cmpi.b #$50,d1 ; is it a quadra900
bne.s @tryQ950
MOVE.W #(cpuIDRISC)|\ ; CPU ID: RISC design center
$1236,D0 ; return emulator CPU ID
BRA @success
@tryQ950 ; if here it must be Q950
MOVE.W #(cpuIDRISC)|\ ; CPU ID: RISC design center
$1237,D0 ; return emulator CPU ID
BRA @success
@tryCentris610
cmpi.b #$40,d1 ; is it a Centris610?
bne.s @tryCentris650
MOVE.W #(cpuIDRISC)|\ ; CPU ID: RISC design center
$1204,D0 ; return emulator CPU ID
BRA @success
@tryCentris650
cmpi.b #$46,d1 ; is it a Centris650?
bne.s @tryQ800
MOVE.W #(cpuIDRISC)|\ ; CPU ID: RISC design center
$1200,D0 ; return emulator CPU ID
BRA @success
@tryQ800
cmpi.b #$12,d1 ; is it a Quadra800?
bne.s @tryQ610
MOVE.W #(cpuIDRISC)|\ ; CPU ID: RISC design center
$1201,D0 ; return emulator CPU ID
BRA @success
@tryQ610
cmpi.b #$44,d1 ; is it a Quadra610?
bne.s @tryQ650
MOVE.W #(cpuIDRISC)|\ ; CPU ID: RISC design center
$1202,D0 ; return emulator CPU ID
BRA @success
@tryQ650 ;if here assume Smurf card is in Q650
MOVE.W #(cpuIDRISC)|\ ; CPU ID: RISC design center
$1203,D0 ; return emulator CPU ID
BRA @success
ENDIF ; forSmurf
LEA CPUIDReg,A2 ; Get CPU ID reg address
; FIRST - try to read it as a LONG. <SM43>,<SM44>
MOVE.L (A2),D0 ; read the register (bus err if it doesn't exist)
MOVEQ #0,D1 ; clear pattern register
@FlipBits ; LOOP (to write different patterns in CPUID reg)
MOVE.L D1,(A2) ; write next pattern to CPUID register location
CMP.L (A2),D0 ; does it read back the same as the first time?
BNE.S @tryPDMIDReg ; -> no. try reading it the other way.
NOT.L D1 ; flip the bits in the write pattern
BNE.S @FlipBits ; -> try the next write pattern
SWAP D0 ; look at the signature
CMPI.W #cpuIDSig,D0 ; is it a valid signature?
BNE.S @tryPDMIDReg ; -> no. try reading it the other way.
SWAP D0 ; look at the decoder-specific stuff
bra @success ; yay, we're done.
@tryPDMIDReg ; SECOND - see if it's a byte-wide only reg (like on PDM)
move.b (a2), d0 ; read high byte (bus err if it doesn't exist)
move.b #$6a, (a2) ; write/read to be sure it's really there
cmp.b (a2), d0 ; match previous read?
bne @noCPUIDReg ; no. must not really be the CPUID reg.
lsl.l #8, d0 ; shift high byte over
move.b 1(a2), d0 ; read next byte
move.b #$6f, 1(a2) ; write/read to be sure it's really there
cmp.b 1(a2), d0 ; match previous read?
bne @noCPUIDReg ; no. must not really be the CPUID reg.
lsl.l #8, d0 ; shift next byte over
move.b 2(a2), d0 ; read next byte
move.b #$65, 2(a2) ; write/read to be sure it's really there
cmp.b 2(a2), d0 ; match previous read?
bne @noCPUIDReg ; no. must not really be the CPUID reg.
lsl.l #8, d0 ; shift next byte over
move.b 3(a2), d0 ; read last byte
move.b #$20, 3(a2) ; write/read to be sure it's really there
cmp.b 3(a2), d0 ; match previous read?
bne @noCPUIDReg ; no. must not really be the CPUID reg.
swap d0 ; check the signature
cmpi.w #cpuIDSig, d0 ; is it valid?
bne @noCPUIDReg ; nope, exit with Z cleared.
swap d0 ; yay! we're probably a PDM! (how cool if we are.)
cmpi.w #$3010, d0 ; could we be an EVT2 but don't know it? <SM45>
bne @success ; nope
move.b $50F32008, d1 ; read SCSI DMA ctl reg
movea.w d1, a2 ; remember the original setting
ori.b #$0C, d1 ; poke the extra bits
move.b d1, $50F32008 ; save the updated value
nop
move.b $50F32008, d1 ; read SCSI DMA ctl reg again
andi.b #$0C, d1 ; did they stick?
beq.s @success ; nope, don't dick with the CPUID
move.w a2, d1 ; restore the original setting
move.b d1, $50F32008
nop
@ck4FastSCSI
move.b #$02, $50f11030 ; do cResetChip cmd
nop
move.b #$00, $50f11030 ; cNOP required after HW or SW reset
move.b #$40, $50f110b0 ; turn on Features enable then,
move.b #$80, $50f11030 ; send a DMA NOP command then,
nop
cmp.b #$A2, $50f110e0 ; read the SCSI chip ID - an FC96?
beq.s @isFastSCSI ; yes -> we have Fast SCSI (i.e. we're on a Cold Fusion)
@noFastSCSI
move.b #$02, $50f11030 ; cResetChip again
nop
move.b #$00, $50f11030 ; cNOP required after HW or SW reset
move.b #$11, d0 ; we're an AMIC2 - change CPUID to $3011
bra.s @success ;
@isFastSCSI
move.b #$02, $50f11030 ; cResetChip again
nop
move.b #$00, $50f11030 ; cNOP required after HW or SW reset
move.b #$13, d0 ; we're a Cold Fusion - change CPUID to $3013
@success
IF forSTP601 THEN
ori.w #(cpuIDRISC),d0
ENDIF
CMP.W D0,D0 ; set ccr.z to indicate success
@noCPUIDReg JMP (A6) ; END
ENDIF ; <SM24> rb
end