;__________________________________________________________________________________________________ ; ; 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): ; ; 12/17/93 PN Fix the test for Pratt decoder ; 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ ; machines. ; 12/7/93 BG Modified the Frigidaire entries in the djMEMC @MachineTbl to ; properly reflect the VIA PortA values for CPU ID+Speed. ; 11/17/93 KW forSTP601 in GetCPUIDReg to or in Risc product to the id. ; 11/9/93 KW made some changes for STP machines. changes are conditionalized ; by forSTP601 ; 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. ; 8/13/93 KW adding two more smurf wombats ; 8/12/93 BG Changed various Cyclone-related boxflags to their official ; names. ; 8/11/93 KW made the forSmurf check in GetCPUIDReg dynamic. Currently ; recoginizes Quadra700/900/950 and Centris610/650 quadra800 ; 7/27/93 GMR Added routine to do a runtime check for BART (on PDM). ; 7/2/93 PN Add conditional for export hasCPUIDregs ; 6/29/93 SAM (PDW) Added code to check for a cf96 in GetCPUID (for ; PDM/ColdFusion). ; 6/14/93 kc Roll in Ludwig. ; 4/29/93 fau Updated the Cyclone/Tempest timing to 120ns ROMS for final ; shipment. ; 6/3/93 SAM Exporting GetCPUIDReg. ; 5/10/93 SAM Added a few nops in the PDM specific CPU ID check. ; 4/26/93 RC Get ride of warning due to bra.s ; 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.) ; 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. ; 4/20/93 jb Fixed up the code to work on either a normal or PDM-style CPUID ; register. ; 3/31/93 chp Synchronize SuperMario with changes from . ; 2/26/93 fau Removed support for Cyclone EVT3 and changed all labels having ; MMC with YMCA. ; 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. ; 2/8/93 rab Rolled in the following change from Horror for Wombat: ; 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. ; 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. ; 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. ; 12/23/92 RC Added Support for Smurf on Wombat ; 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. ; 12/11/92 FU Was always checking BoxCyclone33 when programming the YMCA. ; 12/4/92 fau Added support for Cyclone40 and Tempest33. ; 11/20/92 fau Didn't put a ; on one of my comments. ; 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. ; 11/7/92 rab Roll in Horror changes. Comments follow: ; 8/10/92 SWC Fixed the MSC VIA/RBV initialization to disable slot interrupts. ; 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. ; 6/25/92 CCH Added conditionalized support for Quadra on RISC-based emulator. ; 6/4/92 HY Add ptr to sound primitives vector table in LC product info table. ; 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. ; 5/28/92 NJV Added SoundPlayAndRecord bit to ProductInfo Tables of machines ; that can play and record simultaneously. ; 05-18-92 jmp Changed the “sRsrcZydecoDir” name to the more generic ; “sRsrcBFBasedDir” (BF=BoxFlag) name. ; 5/3/92 BG Removed references to hasOrwell2, since it is now superfluous to ; hasOrwell. ; 4/24/92 HJR Added CheckForNiagra so that we may distinguish from ; Jawsdecoder. ; 11/3/92 SWC Changed SlotEqu.a->Slots.a. ; 11/2/92 kc Make change to prevent unwanted branch island (to data). ; 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. ; 10/25/92 HY Add code in jumpintoRom to turn on & grey LC/LC II screen early. ; 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. ; 10/18/92 CCH Added support for PDM and conditionalized support for Smurf. ; 10/12/92 RB For the 1 Meg LC930 ROM, exclude all code not related to the LC ; hardware. ; 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. ; 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. ; 8/27/92 CCH Removed some now obsolete conditionals for Smurf card. ; 8/25/92 chp Fix assembler warning. ; 8/24/92 PN Take out CycloneboxEVT1 ; 8/20/92 CCH Don't initialize Orwell when running on a Cub Card. ; 8/17/92 CCH Extended Universal support to 96-bits, added GetExtHardwareInfo ; routine to provide dynamic checking for feature existence. ; 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. ; 8/9/92 CCH Removed uneeded conditionals and temporarily return a CPU ID ; for RISC cards. ; 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. ; 7/21/92 kc Fix duplicate lable. ; 7/13/92 CCH Added conditionalized support for Cub Card. ; 6/30/92 kc Fix bug introduced with last checkin (trashing d0). ; 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. ; 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. ; 6/9/92 kc Roll in Horror change from UniversalPatch.a,14. ; 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. ; 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 , so it has been restored now. ; 5/22/92 RB Removed an ENDIF ; 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. ; 5/22/92 RB Making changes for Cyclone ; 5/17/92 kc Roll the Horror changes. Comments follow: • From ; UniversalPatch.a: ; 4/20/92 NJV Adding changes needed to support Patch ROMs ; 4/13/92 JC Remove dynamic speed determination from Sonora setup code. ; 2/20/92 JC Fix register trashing bug in test for Sonic code and remove ; temporary branch around Sonic test. ; 2/14/92 JC Clean up Sonora Memory controller initialization, dynamically ; determine clock speed, and add TestforSonic code. ; 4/26/91 ag Relocate the stack pointer after we jump into rom, otherwise a ; berr will cause ram to be written to! ; 4/22/91 ag added patch to reinitialize berr handler after jump into rom. ; removed aux wait state initialization in jaws. ; 2/16/91 BG Changed the Orwell initialization to understand 33MHz. ; 1/15/91 HJR Added new code in memoryCtrlInitPatch for Jaws initialization. ; 11/7/90 BG Made changes for new rev. of Orwell (2) permanent. ; 10/30/90 BG Added changes for new rev. of Orwell (2). ; 10/25/90 CCH Added support for ReAnimator when forRomulator equate is set. ; • From Univeral.a: ; 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. ; 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. ; 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. ; 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. ; 10/29/90 CCH Fixed forRomulator conditional statement. ; 10/25/90 CCH Added support for ReAnimator when forRomulator equate is set. ; 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 Don’t use onMvMac conditional, Modern Victorian never existed. ; <54> 10/1/91 JSM Don’t use eclipseDebug. ; <53> 9/10/91 JSM Cleanup header. ; <52> 1/18/91 KIP 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' ; print on print nomdir machine mc68030 mc68881 ; needed for TestForFPU Universal proc export import CPUIDProductLookup,ProductLookup,DecoderLookup import BaseOfRom, CudaInit import SendEgretCmd ; EXPORT CheckForUnknown export GetHardwareInfo export GetExtHardwareInfo ; export JumpIntoROM export InitVIAs EXPORT CheckNextMap,MapFound ; ;

IF hasCPUIDRegister THEN ; ; rb rb EXPORT GetCPUIDReg ; 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 ; TestInRAM a3 ; are we in RAM? beq.s @notInRAM ; movec vbr,d5 ; save contents of vbr 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 ; 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 ; TestInRam A2 ; running in RAM? bne.s intoROM ; yep, skip this.. endif biglea BaseOfRom,a2 ; where we currently start move.l ROMAddr(a0),d3 ; where we want to start (from savepatch) <3> sub.l a2,d3 ; offset we need to add to relocate <3> adda.l d3,a0 ; relocate decoder info pointer <3> adda.l d3,a1 ; relocate product info pointer <3> ; 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 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 ; TestInRAM a3 ; are we in RAM? beq.s @notInRAM ; movec vbr,d5 ; save contents of vbr 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 ; 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 IF NOT ROMinRAM THEN ; rb bsr6 InitVIAs ; initialize the VIAs (turns off vOverlay) ENDIF ; rb ; Here, after running GetHardwareInfo we have: {rbm}<2> ; {rbm}<2> ; a0 - Pointer to table of base addresses {rbm}<2> ; a1 - Pointer to ProductInfo record for this machine {rbm}<2> ; d0 - Flags indicating which base addresses are valid {rbm}<2> ; d1 - Flags indicating which external features are valid {rbm}<2> ; d2 - Bits 31..16, hwCfgFlags info (possibly unknown) {rbm}<2> ; d2 - Bits 15..8, BoxFlag info (possibly unknown) {rbm}<2> ; d2 - Bits 7..0, Address Decoder Kind (zero if unknown) {rbm}<2> ; {rbm}<2> ; CudaInit implies a SyncAck cycle which synchronizes Cuda to the system and disables {rbm}<2> ; all asynchronous messages sources (Auto Poll, RTC, Power Messages, Unknown). No further {rbm}<2> ; individual disabling of asynchronous message sources is required. (R. Montagne 5/25/92) {rbm}<2> ; {rbm}<2> move.l d0,d3 ; save a copy of d0 move.l #EgretFWMask,d0 ; mask for Egret Firmware {rbm}<2> and.l d1,d0 ; isolate the field {rbm}<2> sub.l #Egret8,d0 ; see if we have Egret FW {rbm}<2> beq.w @DoEgretInit ; do Egret 8 FW INIT, LC/si {rbm}<2> sub.l #Egret8,d0 ; see if we have Caboose FW {rbm}<2> beq.s @CudaDone ; just exit Quadra900 {rbm}<2> PN sub.l #Egret8,d0 ; see if we have Cuda FW {rbm}<2> bne.s @CudaDone ; if not, just exit {rbm}<2> IF NOT ROMinRAM THEN ; rb BigBSR6 CudaInit ;Setup Cuda Sysnc Ack with System {rbm}<2> bra.s @CudaDone ; ENDIF ; rb @DoEgretInit ; movea.l DecoderInfo.VIA1Addr(a0),a1 ; get VIA 1 base address move.w #4000,d0 ; @wait eieioSTP tst.b (a1) ; sync to hardware for 1.2µS per access dbra d0,@wait ; Egret must see idle before command, it's busy ; doing ADB reset for 3mSec so delay in idle state eieioSTP move.l #(NopCmd<<16)|pseudoPkt,d0 ; moveq #0,d2 ; no bytes to send bsr6 SendEgretCmd ; send the command to disable async. messages moveq.l #0,d2 ; figure it out from scratch bsr6 GetHardwareInfo ; restore all the registers we trashed move.l d0,d3 ; by calling SendEgretCmd @CudaDone move.l d3,d0 ; restore d0 IF forSTP601 THEN jmp (a4) ; Orwell,djmec already inited...return ENDIF IF hasOSS THEN ; 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 ; rb IF hasFMC THEN ; 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 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 ; rb IF hasSonora THEN ; begin hasSonora .Start 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 .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 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 move.l (a2),d3 ; and.w #cpuIDFieldMask,d3 ; d3 = ID field of CPU ID Register cmpi.w #Vail33IDField,d3 ; is it a 33 MHz Vail ?? beq.s @noSonora ; yep, don't change the timing movea.l RBVAddr(a0),a2 ; get base of RBV/VIA2 Registers move.b #2,SonoraSpeedReg(a2) ;Set up for 25Mhz or less timing .End @noSonora ; end hasSonora .End ENDIF ; rb IF hasOrwell THEN ; 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 beq.s @noOrwell ; don't reset orwell then cmp.b #boxRiscQuadra900,ProductKind(a1) ; see if we're on a RISC Quadra beq.s @noOrwell ; don't reset orwell then cmp.b #boxRiscQuadra950,ProductKind(a1) ; see if we're on a RISC Quadra 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 move.l #ORWELL_INIT25,d4 ; get Orwell 25MHz initialization value moveq.l #OrCfgRegSize-3,d3 ; (34-3 = 34-1-2) -1 for DBRA, ; -2 because 32-bit max constant size movea.l VIA2Addr(a0),a2 ; get base of VIA2 to check for 33 MHz bclr #v2Speed,VDirB(a2) ; make sure the 25/33MHz direction=input btst #v2Speed,VBufB(a2) ; are we running at 25 MHz or 33 MHz? beq.s @25MHz ; IF CPU_Speed == 33MHz THEN move.l #ORWELL_INIT33,d4 ; get Orwell 33MHz init. value @25MHz ; ENDIF ; Note - the above configuration constants are ONLY accurate for non-parity ; operation. lea OrBankBCfgAddr(a3),a2; get address of config regs. @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 moveq #ORINITWaitWr1,d4 ; get initial value of optional write wait state move.l d4,(a2)+ ; ... and send that bit out ; RAS precharge (the last bit) is done separately below because it too relies ; on the clock speed the processor is running at. ; 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) move.l d3,OrLoadWaitStates(a3); initialize optional wait states ; RAS Precharge timing is different depending on 25/33 MHz. move.l OrClkSpeedAddr(a3),d4; now that clock speed is set, get it btst #0,d4 ; only LSBit is valid from each reg addr beq.s @use33MHzvalue ; IF Clock_Speed == 25MHz THEN moveq #ORINITRAS25,d4 ; get value of 25 MHz RAS precharge bra.s @initRAS ; and get on with it @use33MHzvalue ; ELSE moveq #ORINITRAS33,d4 ; get value of 33 MHz RAS precharge @initRAS ; ENDIF move.l d4,(a2) ; ... and finish init of config reg move.l d3,OrLoadPrecharge(a3); initialize RAS precharge (on/off) @noOrwell ENDIF ; rb IF hasJaws THEN ; rb btst.l #JAWSExists,d0 ; see if we have a JAWS 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 ; rb IF hasYMCA THEN ; rb cmp.b #YMCADecoder,DecoderKind(a1) ; Do we have a YMCA fau start bne @noYMCA ; Not a YMCA fau end Move.l DecoderAddr(a0),A2 ; Get Base of YMCA. Cmp.b #BoxQuadra840AV,ProductKind(a1) ; Are we running on a Cyclone40 Beq.s @DoCyclone40 ; if so, go program it Cmp.b #BoxCyclone33,ProductKind(a1) ; Are we running on a Cyclone33 Beq.s @DoCyclone33 ; if so, go program it Cmp.b #BoxTempest33,ProductKind(a1) ; Are we running on a Tempest25 Beq.s @DoTempest33 ; if so, go program it Cmp.b #BoxCentris660AV,ProductKind(a1) ; Are we running on a Tempest25 Beq @DoTempest25 ; if so, go program it Bra @noYMCA ; Not a Cyclone Type Machine @DoCyclone40 Move.l #0,YMCA_DRAMspeed0(A2) ; Set DRAM speed to 60ns with a 40MHz CPU Move.l #-1,YMCA_DRAMspeed1(A2) ; Move.l #0,YMCA_ROMspeed1(A2) ; Move.l #-1,YMCA_ROMspeed2(A2) ; ; Program MUNI if it exists bsr6 GetExtHardwareInfo ; Get the bits for extended features 32-63 beq @NoYMCA ; No MUNI here Move.l #$1c,MUNIBase+MUNI_Control ; Set MUNI for 33MHz. Bra.s @noYMCA ; Skip over Tempest programming @DoCyclone33 @DoTempest33 ; Move.l #-1,YMCA_DRAMspeed0(A2) ; Set DRAM speed to 60ns with a 33MHz CPU Move.l #0,YMCA_DRAMspeed1(A2) ; Move.l #-1,YMCA_CPUspeed0(A2) ; Set CPU Speed to 33 MHz Move.l #0,YMCA_CPUspeed1(A2) Move.l #-1,YMCA_ROMspeed0(A2) ; Set ROM speed to 125 (6 cycles). Move.l #-1,YMCA_ROMspeed1(A2) ; Move.l #0,YMCA_ROMspeed2(A2) ; ; Program MUNI if it exists bsr6 GetExtHardwareInfo ; Get the bits for extended features 32-63 beq.s @NoYMCA ; No MUNI here Move.l #$18,MUNIBase+MUNI_Control ; Set MUNI for 33MHz. Bra.s @NoYMCA ; Skip over Tempest programming @DoTempest25 Move.l #0,YMCA_DRAMspeed0(A2) ; Set DRAM speed to 60ns with a 25MHz CPU Move.l #0,YMCA_DRAMspeed1(A2) ; Move.l #0,YMCA_CPUspeed0(A2) ; Set CPU Speed to 25 MHz Move.l #0,YMCA_CPUspeed1(A2) Move.l #0,YMCA_ROMspeed0(A2) ; Set ROM speed to 140ns (5 cycles). Move.l #0,YMCA_ROMspeed2(A2) ; ; Program MUNI if it exists bsr6 GetExtHardwareInfo ; Get the bits for extended features 32-63 btst.l #MUNIExists-32,d0 ; Normalize MUNIExists since it's in 32-63 beq.s @NoYMCA ; No MUNI here Move.l #$14,MUNIBase+MUNI_Control ; Set MUNI for 25MHz. @NoYMCA ENDIF ; rb IF hasVisaDecoder THEN ; rb cmp.b #VISADecoder,DecoderKind(a1) ; do we have a VISA bne.s @noVISA ; if not don't do anything ; ; VISA machines need there screens greyed out earlier than primary init time ; to avoid garbage being left over on the screen from a previous reboot move.l VDACAddr(a0),a2 ; get base address of Color Table chip move.l a2,a3 ; save base address in a3 clr.b V8DACwCntlReg(a2) ; clears the overlay enable bit and puts ariel in slave mode ; ; to insure all outputs are off while CLUT is being filled adda #V8DACwDataReg,a2 ; point to data register clr.b V8DACwAddReg-V8DACwDataReg(a2) ; start at the beginning of CLUT, 4-bit mode move.b #$7F,d3 ; get a 50% value move #$FF,d4 ; get count @Repeat move.b d3,(a2) ; put red (CLUT autoincrements destination address) move.b d3,(a2) ; put green move.b d3,(a2) ; put blue dbra d4,@Repeat ; ori.b #$08,V8DACwCntlReg(a3) ; turn video on by putting machine in master mode @noVISA ENDIF ; rb IF hasDJMEMC THEN ; rb ; djMEMC Configuration Register initialization thru next ; (Done here so that it isn't done multiple times in SizeMemPatch) 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 beq @nodjMEMC ; don't reset djMEMC then cmp.b #boxRiscQuadra800,ProductKind(a1) ; see if we're on a RISC Wombat Quadra800 beq @nodjMEMC ; don't reset djMEMC then cmp.b #boxRiscCentris610,ProductKind(a1) ; see if we're on a RISC Wombat Centris610 beq @nodjMEMC ; don't reset djMEMC then ; 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 thru next @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 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 @dj40Config dc.w %0000001011110100 ; dwcpw=1, mhz33=1, drcpw=1, cyc2ta=1, drpchg=1, ROMspeed=4 ; DRAM refresh cycle times assuming a 15.6µs refresh period ; (Refresh = (MHz * 15.6 ) - 27). Fractional parts are rounded DOWN @djRefreshTable @dj20Refresh dc.w 285 ; (20MHz * 15.6µs) - 27 @dj25Refresh dc.w 363 ; (25MHz * 15.6µs) - 27 @dj33Refresh dc.w 487 ; (33MHz * 15.6µs) - 27 @dj40Refresh dc.w 597 ; (40MHz * 15.6µs) - 27 ; BIOS Configuration Register initialization values @BIOS_Config @BIOS_Config20 dc.b %00000001 ; BCLK_25 = 1 @BIOS_Config25 dc.b %00000001 ; BCLK_25 = 1 @BIOS_Config33 dc.b 0 ; BCLK_25 = 0 @BIOS_Config40 dc.b 0 ; BCLK_25 = 0 ; BIOS watchdog timer timeout count-down value @BIOS_Timeout @BIOS_Timeout20 dc.w $0280 ; @BIOS_Timeout25 dc.w $01E0 ; @BIOS_Timeout33 dc.w $00D5 ; @BIOS_Timeout40 dc.w 0 ; ; Table for determining whether or not to use "SpeedBump"ed Config values thru next @DJ_ORIG EQU 0 @DJ_BUMP EQU 1 @MachineTbl ; Type CPU VIA ID dc.b @DJ_ORIG,%00010010 ; 33MHz Frigidaire package (Quadra 800) dc.b @DJ_BUMP,%00010110 ; 40MHz Frigidaire package (unreleased) 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) 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) 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 @bump40Config dc.w %0000001011111100 ; dwcpw=1, mhz33=1, drcpw=1, cyc2ta=1, drpchg=1, drpw=1, ROMspeed=5 ; @nodjMEMC ; end ENDIF ; rb ; ======================================================================================================= ; Pratt Configuration Register initialization thru next ; (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 BNE.S @NotPratt ; IF we have a Pratt THEN ENDIF ; { isUniversal } MOVE.B #(1< ; ======================================================================================================= IF forRomulator THEN ; TestInRAM a3 ; are we in RAM? beq.s @notInRAM2 ; movea.l d5,a3 ; get location of original VBR movec USP,d5 ; retrieve original buserr value move.l d5,BusErrVct(a3) ; and restore it in the exception table movec a3,vbr ; restore vbr @notInRAM2 ENDIF ; { forRomulator } 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 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 rb movea.l a1,a3 ; get product info ptr rb adda.l VIA1InitPtr(a3),a3 ; point to the init info rb btst.l #PSCExists,d0 ; is this a Cyclone ? rb rb, start 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 gjs eieioSTP move.b (a3)+,vBufA(a2) ; init output port A gjs eieioSTP move.b (a3)+,vDirB(a2) ; init direction for port B gjs eieioSTP move.b (a3)+,vBufB(a2) ; init output port B gjs eieioSTP move.b (a3)+,vPCR(a2) ; init peripheral control reg rb eieioSTP move.b (a3)+,vACR(a2) ; init auxiliary control reg rb eieioSTP move.b #$7F,vIER(a2) ; Disable all VIA interrupts. rb eieioSTP bra.s @VIA1done ; cool, keep going rb @WombatVIAInit ; IF hasDJMEMC THEN ; rb cmpi.b #djMEMCDecoder,d2 ; are we on a Wombat? bne.s @doOldVIAInit ; if not, initialize VIAs the old way eieioSTP move.b (a3)+,vBufA(a2) ; init output port A eieioSTP move.b (a3)+,vDirA(a2) ; init direction for port A eieioSTP move.b #$1C,vACR(a2) ; enable shift-out on ACR eieioSTP move.b #0,vSR(a2) ; preset shift register with an ADB resetCmd eieioSTP move.b (a3)+,vBufB(a2) ; init output port B eieioSTP move.b (a3)+,vDirB(a2) ; init direction for port B eieioSTP move.b -2(a3),vBufB(a2) ; (re-)init output 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 bra.s @VIA1done ; cool, keep going ENDIF ; rb @doOldVIAInit ; 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 rb, start movea.l a1,a3 ; get product info ptr adda.l VIA2InitPtr(a3),a3 ; point to the init info IF hasPSC THEN ; rb btst.l #PSCExists,D0 ; Make sure we're on a Cyclone. Beq.s @NonPSC ; Not? Then do conventional init. 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 ; rb, end ENDIF ; 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? BEQ.S @NoMSC ; -> no, continue on ; This is the point where we check to see if an external FPU is attached to ; the system. In the case of Escher, the onboard FPU will power up disabled, ; but we want to enable it here if we don't detect anything else sitting on ; the coprocessor bus. ; ; 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 MOVE.B #$7F,RvSEnb(A2) ; disable all slot interrupts eieioSTP RTS6 ; @NoMSC ; eieioSTP move.b #1< eieioSTP move.b #$FF,RvSEnb(a2) ; set all slots to be interrupt enabled 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 ; 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 ; ; rb 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 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 DecoderKind(a1) ; Found Match beq Matched ; { For Now just handle one case } 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 ; rb cmp.b #YMCADecoder,DecoderKind(a1) ; Do we have a YMCA controller fau start bne.s @GetVia ; No, go do the regular kind fau end Move.l DecoderAddr(a0),A1 ; Base of YMCA. Move.l YMCA_CPUID0(A1),D0 ; Bit 0 of CPU ID. Move.l YMCA_CPUID1(A1),D1 ; Bit 1 of CPU ID. Rol.l #1,D0 ; Move to bit 0. And.b #1,D0 ; Only care about bit 0. Rol.l #2,D1 ; Move to bit 1. And.b #2,D1 ; Only care about bit 1. Or.b D1,D0 ; Complete ID. Move.l YMCA_CPUID2(A1),D1 ; Bit 2 of CPU ID. Rol.l #3,D1 ; Move to bit 1. And.b #4,D1 ; Only care about bit 1. Or.b D1,D0 ; Complete ID. Move.l YMCA_CPUID3(A1),D1 ; Bit 3 of CPU ID. Rol.l #4,D1 ; Move to bit 1. And.b #8,D1 ; Only care about bit 1. Or.b D1,D0 ; Complete ID. 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? Beq.s Matched ; Yes? Then let's get outta here. 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. ENDIF ; hasYMCA rb @GetVia ; rb, end movea.l a6,a3 ; save return address for GetHardwareInfo in a1 bsr6 GetVIAInputs ; read all of the VIA input lines into D1 movea.l a3,a6 ; restore return address for GetHardwareInfo 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 ... movea.l a2,a3 ; save your place in the table in A3 movea.l a6,a1 ; save return address for GetHardwareInfo in A1 BSR6 GetCPUIDReg ; get CPU ID register value (again) movea.l a1,a6 ; restore return address movea.l a3,a2 ; restore our place in the table bra.s @MatchLoop ; go look for another candidate to check Matched ; END bra.s FoundMatch ; yea!!! rb UnknownCPU bra.s UnknownCPU ; Ack! ENDIF ; hasCPUIDRegister rb 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 ; rb btst.l #PSCExists, D0 ; do we have PSC? rb, start Beq.s @noPSC ; no, do horror style VIA2 init lea PSCVIA2IER(a2),a2 ; base address of PSC VIA2 VIER register Bra.s @gotVIA2 @noPSC ; ENDIF ; rb lea VIER(a2),a2 ; base address of VIA2 VIER register @gotVIA2 ; 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 ; 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 ; rb IF hasIopScc THEN ; 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 ; 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 IF hasSCSI96 THEN ; 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 ; 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 movea.l a6,a2 ; save return address bra TestForFPU ; see if FPU installed FPUReturn movea.l a2,a6 ; restore return address 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 movea.l a7,a5 ; mark the stack for bus error handler 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 move.l SonicAddr(a0),a1 ; get Sonic Base Address 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 bne.s @SonicDone ; if not found, no Sonic chip bset.l #SonicExists,d0 ; has Sonic, set the bit @SonicDone bclr.l #PatchROMExists,d0 ; see if PatchRom might be allowed .start beq.s @PatchROMDone ; if not, don't test for one move.l a1,d1 ; save a1 move.l PatchRomAddr(a0),a1 ; get PatchRom Base Address 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 bne.s @PatchRomDone ; if not found, no PatchRom chip bset.l #PatchRomExists,d0 ; has PatchRom, set the bit .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> ;_______________________________________________________________________ ; ; 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 ;--------------- ; begin 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 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 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 ;--------------- 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 ;--------------- 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 ;--------------- ;---------------------------------------------------------------------------------------- ; 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 ;--------------- 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 ;--------------- @allDone bclr.l #beok,d7 ; disallow bus errors <1.7/8> rts6 ; all done <8> IF hasGlue THEN ; rb 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 ; 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 ; rb IF hasMDU THEN ; 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 ; 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 ; rb IF hasOss OR hasFMC THEN ; 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 ; 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 ; rb IF hasVISADecoder THEN ; 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 ; 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 ; rb IF hasOrwell THEN ; rb 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 ; rb CheckForOrwell lea CheckNextMap,a6 ; return to decoder search if we bus error <19> movea.l DecoderAddr(a0),a2 ; look for an Orwell move.l (a2),d2 ; Orwell won't bus error <13> bra.w MapFound ; otherwise it is an Orwell decoder <13> ENDIF ; rb IF hasJaws THEN ; rb ;_______________________________________________________________________ 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 ; 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 ; rb IF hasNiagra THEN ; rb ;_______________________________________________________________________ thru next ; ; 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 ; rb,end ENDIF ; 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< 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< rb, from Terror... ;_______________________________________________________________________ thru matching ; ; 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 ; that a non-existent address is decoded by HW anyway so if we pass bus-err ; test we verify the contents of the regr with expected value for safety. ; ;_______________________________________________________________________ ; the CMPI will be .NE. if the address we write to does not bus error, but is in ; reality, not there. So the CMPI above actually checks to see if the data stuck. 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 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 ;_______________________________________________________________________ ; ; 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 ;_______________________________________________________________________ ; ; 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 ; 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 ; rb movec CACR,d1 ; MacsBug does not like the fpu rb cmp.b d1,d1 ; code when booting from RAM rb bra FPUReturn ; rb ELSE ; 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 fau end ENDIF ; 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 eieioSTP tst.b (a1) ; try to read the Command Register eieioSTP bset #7,(a1) ; send a SW Reset to Sonic 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 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 ; rb rb GetCPUIDReg IF ROMinRAM THEN ; rb move.l #$A55A2830,d0 ; ••• HACK, force Cyclone, make your rb cmp.w d0,d0 ; ModifyReadOnly hack here. Cyclone rb jmp (a6) ; needs this because the MMU is rb ENDIF ; hiding the CPUIDReg one we booted 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. , 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? 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 ; rb end