; ; File: SizeMem.a ; ; Written by: Gary Rensberger ; ; Copyright: © 1989-1993 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ ; machines. ; 11/19/93 KW copied HMCMerge EDisk calculations and put in OrwellMerge. Only ; effects the CygnusX1 ROM ; 11/17/93 chp Put back TNT code inadvertantly removed by a previous checkin. ; 11/17/93 KW added some forSTP601 conditionals. Only effects CygnusX1 ROM ; 11/13/93 SAM Roll in from mc900ftjesus. ; 11/13/93 SAM In the EDisk calculation from the previous revision, I was not ; anticipating the result going negative. It does. I now check for ; it.; 11/12/93 SAM Roll in from mc900ftjesus. ; 11/12/93 SAM When allocating an EDisk, make sure there is KminHeap (or ; somesuch) free or don't allocate. The ammount of RAM ; allocated for the edisk is stored beyond the diagnostic longs at ; the end of the chunk table. InitMMU uses this size for eMMU ; machines. ; 11/9/93 fau Added the TNT Decoder support (HammerHead) ; 11/9/93 KW added some conditional forSTP601. Only used for CygnusX1 ROM ; 11/7/93 SAM Roll in from mc900ftjesus. ; 11/7/93 SAM Keep a running total of RAM allocated by the nanokernel in the ; chunk table. ; 11/6/93 SAM Roll in from mc900ftjesus. ; 11/6/93 SAM Disable Sonora video before mucking with the NanoKernel memory ; allocation. ; 11/1/93 SAM Roll in from mc900ftjesus. ; 11/1/93 SAM (RC) HMCMerge now checks PRAM for the diag burn-in sig as well ; as reading the monitor sense lines for the RBV to determine if a ; DRAM based frame buffer should be allocated. ; 10/16/93 SAM Roll in from mc900ftjesus. ; 10/16/93 SAM Add some slop to the RBV buffer for PDM to account for QD ; writing past the end of the buffer. (Doesn't this seem like a ; problem to you? Does to me...) ; 10/15/93 SAM Roll in from mc900ftjesus. ; 10/15/93 SAM Ok, I fixed the boot beep code, so the RBV size is now set to a ; max of 600k (not 768). Removed the 3 extra longs allocated in ; the chunk table (for debugging). ; 9/29/93 SAM For PDM: from mc900ftjesus. ; 9/25/93 SAM For PDM: Loose Evt1 support. ; 9/13/93 SAM For PDM (HMC): Removed the Edisk hack for the nanokernel. ; Marked all the DMA buffers noncacheable. ; 9/9/93 pdw Added 'nk' onto front of MakePageWriteThrough. ; 8/23/93 SAM Added a temp hack to increase the amount of RAM allocated for ; the RAM disk by 1 page (nk bug) ; 8/23/93 SAM Changed the alignment restriction for the EDisk allocation to be ; 4k. ; 8/23/93 SAM Added some space in the HMC chunk table for a couple of ; warmstart longs. ; 8/12/93 KW adding two more smurf wombats ; 8/11/93 KW added some branches based on new smurf boxes ; 6/14/93 kc Roll in Ludwig. ; 6/4/93 fau In sizing memory in Cyclone, there was a bug when a Wide Mode ; SIMM was in bank 5, no SIMM in bank 7, and a Standard Mode SIMM ; in Bank 0. Bug #1088829. ; 6/3/93 SAM For HMC machines (PDM) if an evt2 or better is found, the floppy ; and serial DMA buffers are marked noncacheable in order fix a ; data path snooping during DMA bug. ; 5/9/93 SAM Added a couple lines of crucial code to the PDM physical buffer ; allocation code. Grin. ; 5/6/93 SAM For PDM. Changed the HMC entry in the sizemem "split" table to ; point directly at the HMCMerge routine (we don't have to size ; anything, really). Addded allocation of the DMA and video frame ; physical buffers to HMCMerge. Added code to make the frame ; buffer write-through cacheable. ; 4/30/93 SAM Removed non-functional non-universal forRomulator code in ; SizeBanks (). Added one more forSmurf condo. ; 4/19/93 SAM Added forSmurf conditionals around RiscWombat boxflag check ; (ugh). ; 3/31/93 chp Synchronize SuperMario with changes from . ; 3/11/93 SAM Added EDisk allocation to HMC merge code. ; 2/26/93 fau Removed Cyclone EVT3 (MMC) support. ; 2/25/93 RC Fixed Merge code for Smurf. Old code did not do what we thought ; it did, but now it correctly sizes memory by using the same code ; and PDM uses. ; 2/20/93 SAM Added emuWarmStartConst to the chunk table build for HMC ; machines. ; 2/5/93 SAM Added HMC "merge" code that conconcts a fake chunk table and ; generally does the right thing. (for PDM). ; 12/23/92 RC Added Support for Smurf ; 12/1/92 EH Changed PrattAddr reference to DecoderAddr reference for ; PrattMerge. ; 12/1/92 EH Added code for Pratt memory controller. ; 11/12/92 rab Added djMEMCSplit to the split table (had added the code but ; forgot the entry). Also exported SizeSoundBuffer for MMUTable.a. ; 11/10/92 GD Fixed some "forRomulator" issues from latest Horror roll-in. ; 11/3/92 rab Roll in Horror changes. 10/13/92 BG Modified various ; comments in the djMEMCSplit code to indicate that both WLCD and ; Primus need to set the OneBufferedBus bit. 9/28/92 BG ; Changed the djMEMCMerge code so that if you are trying to create ; a ReAnimator type ROM, don't turn on memory interleaving. ; 8/4/92 SWC Fixed a bug in MSCMerge: we were only allocating ; enough space for 5 RAM banks (we support 8), so the end of the ; RAM chunk table was going into write-only RAM. ; 7/13/92 SWC Added some code to the end of MergeDone to move the RAM chunk ; table below a sound buffer in high RAM. This was moved here from ; MMUTables.a because (1) since the chunk table was moved down ; after running StartTest, we'd lose the warmstart flag (causes ; the RAM disk to get trashed on Restart, and (2) diagnostics seem ; to call SizeMem in several places, so I figured it was better to ; get everything set up once. ; 6/16/92 BG Added back in the interleave initialization for djMEMC. ; However, a precursor check has been added to only allow that ; code to be executed if the version number of djMEMC is greater ; than 0, since version 0 parts will cause Wombat/WLCD to die ; shortly after enabling interleaving. ; 6/12/92 BG Added support for sizing up to 16 banks of memory. This is ; needed because Wombat can support up to 10 banks. Also - removed ; the djMEMC configuration register initialization from here and ; moved it to UniversalPatch.a so that it is not executed multiple ; times (since SizeMemory gets called multiple times). ; 6/9/92 BG Added djMEMC memory controller to split and merge tables, as ; well as the split and merge code. However, changes to SizeBanks ; are also required that have not been fully tested on all ; machines yet, so that did _not_ get rolled in. ;
5/20/92 NJV Fixed register-trashing bug in SonoraMerge. ;
5/19/92 SWC Modified @MSCSplit and MSCMerge to temporarily support both MSC2 ; and MSC3 while we make the transition. ;

5/12/92 HY Roll-in LC II changes. Change the sizing routine for VISA ; decoders to support 2 or 4MB on PCB. ;

5/4/92 JC Change Sonora split so that Bank 0 has 4 Megs of RAM installed. ;

4/13/92 JC Remove references to SonoraAddr (is going away) and replaced ; with references to RBVAddr for Sonora based machines. ; 10/22/92 fau Added support for the YMCA Decoder in standard and wide mode. ; This involved adding a new YMCASize banks. Added a check to ; SizeBank to make sure we didn't spin forever if the ram bank end ; is not a multiple of 2^(n-1) * chunksize. (This will occur when ; sizing wide memory as standard memory). Also, changed the use ; of MMC/YMCAExists and MMC/YMCAAddr to use the decoder info. ; 10/18/92 CCH Added support for HMC decoder. ; 9/30/92 fau Incorporated support for the YMCA decoder that is found in ; Cyclone EVT4. This included the YMCA split routine and the ; YMCAMerge routine. Left the support for the MMC in there. ; Eventually, the MMC (used in previous Cyclone EVT's, should go ; away.) ; 8/19/92 CSS Update from Reality: ; <23> 8/18/92 DTY Change the name of BootGlobs to StartGlobals to avoid confusion ; with BootGlobals, which is used by the boot code in Boot[1-3].a. ; 8/17/92 CCH Changed orwell stitch code to use DecoderAddr field instead of ; OrwellAddr. ; 8/11/92 kc Don't split memory while running the ROM image in RAM on ; Cyclone. Use A3 instead of A7 in SizeMem to make ReAnimator ; happy. ; 8/9/92 CCH Don't attempt to stitch memory when running on a RISC processor ; in a Quadra. ; 7/13/92 CCH Added conditionalized support for Cub Card on Quadras. ; 5/25/92 RB Making Cyclone changes...Pandora/Horror comments follow: ; 5/13/92 KW (HV,H4) Roll-in LC II changes. Change the sizing ; routine for VISA decoders to support 2 or 4MB on PCB. (JC,H3) ; Change Sonora split so that Bank 0 has 4 Megs of RAM installed. ; 3/4/92 RMP Changed MMCMerge to configure Bank B correctly. ;
5/19/92 SWC Modified @MSCSplit and MSCMerge to temporarily ; support both MSC2 and MSC3 while we make the transition. ; 5/16/92 kc Roll in Horror and Terror Changes. Comments follow: ; 01/27/92 jmp The original contents of this file have been moved to the ; SizeMemPatch.a file. ; 12/9/91 SAM Added a read to ROM in SizeBank between the RAM write and compare ; to prevent a floating bus from fooling us into thinking that ; there are 4 gigabytes of RAM built-in. ; 12/5/91 SAM Removing all special cases for built-in RAM for Vail machines ; cuz the hardware folks decided that their klude was a kludge. ;
12/3/91 SAM Changed Sonora split/merge code to use the new SonoraVIA2 ; base address equate. ;

11/25/91 SAM First attempt at the Sonora sitch routine for Vail and ; Carnation. ;

10/22/91 SWC Changed MSCAddr references to RBVAddr since MSC is just a ; variant of the RBV. ;

8/5/91 SWC Added a fix to MSCMerge so that it works correctly if all RAM ; banks are not filled. ; 6/21/91 BG Swapped the order of the case table in SizeMemory to match the ; (new) order of the DecoderKinds table in UniversalEqu.a. ; 5/1/91 HJR SWC - Added support for the MSC for DB-Lite. ; 11/7/90 BG Made changes for new rev. of Orwell (2) permanent. ; <22> 12/29/91 RB Added Terror changes. ; <21> 9/16/91 JSM Cleanup header. ; <20> 6/12/91 LN removed #include 'HardwareEqu.a' ; <19> 3/5/91 dba put in an align directive so that we donÕt get a warning ; <18> 3/5/91 PN Fix the warning by putting the END statement at the end ; <17> 9/24/90 GMR Added special case to JAWS merge code to deal with 2 meg bank A, ; 0 meg bank B and vice versa when the 2 meg is in a single chunk ; (as in TIM). ; <16> 9/19/90 BG Removed 040-related kludges (EclipseNOPs). ; <15> 8/2/90 CCH Clear D6 error flag after chunk table is written. ; <14> 7/10/90 CCH Fixed bug in orwell merge, and modified it to create a separate ; chunk table entry for each chunk listed in universal.a. ; <13> 5/10/90 GMR Preserved reg d2 inside FMCMerge. ; <12> 5/3/90 GMR Fixed file contents- ROMLister corrupted the file before ; check-in. ; <11> 5/3/90 GMR The chunk table now contains separate, contiguous chunks for ; each bank of RAM. ; <10> 4/25/90 GMR Made previous change save register A4, as before. ; <9> 4/21/90 GMR Moved ConfigureRAM functionality from StartInit.a to this file, ; to fix problems associated with writing the chunk table before ; the memory is stitched together. The sizing code now can size up ; to 8 banks before storing the info in the chunk table. Added ; Waimea splitting/stitching code to deal with it's 8 banks of ; RAM. ; <8> 4/2/90 JJ Correct memory address used to distinguish between Elsies with 1 ; MB vs 2 MB on main logic board. ; <7> 3/23/90 JJ Added code to handle Elsie VISA 2 setting of size bits. ; <6> 2/28/90 JJ Added code to initialize memory size bits for machines with VISA ; decoders. ; <5> 2/21/90 BG The Orwell configuration code needed a small bit of tweaking. ; <4> 2/16/90 BG Added code to initialize Orwell bank addresses to the known ; default power-on state. ; <3> 1/11/90 CCH Added include of ŅHardwarePrivateEqu.aÓ. ; <2.9> 10/9/89 GMR NEEDED FOR ZONE5: Return bit mask for bad byte lanes, supporting ; up to 8 banks of 4 byte lanes each. Initialize FMC to put bank B ; on 64 Meg boundary. ; <2.8> 6/30/89 GMR Put FF's on bus between byte compare write/read cycles, to ; eliminate stray capacitance problems when no RAM present on ; access. ; <2.7> 6/26/89 GMR Changed to exit with a real stack pointer near low memory, top ; element on stack contains pointer to memory chunk table at top ; of last bank. ; <2.6> 6/11/89 GGD Converted to use RamInfo in rom tables. ; <2.5> 6/11/89 GMR Changed call to GetHardwareInfo to be a BigBSR6 so it'll reach. ; <2.4> 5/30/89 GMR Added comment describing error code returned in D6 ; <2.3> 5/26/89 GMR Return error, instead of ignoring bank, if only some SIMMs in a ; bank are present. This should make Service happy. ; <2.2> 5/26/89 rwh changed to new improved BootGlobs field names. ; <2.1> 5/22/89 GMR Corrected prep of d2 before GetHardwareInfo call, optimized a ; few things, terminated tables with 1 long instead of 2 longs. ; <2.0> 5/16/89 GMR Rewrote entire file, returning a7 pointing to table of bank ; entries (start,length,...,$FFFF) on all machines. It's now ; non-destructive. ; ---------------Below doesn't apply now--------------- ;============================================================================================== ; <1.9> 4/28/89 rle check startup code (now in d5) upon entry to determine if stack ; is valid or memory needs to be tested ; <1.8> 3/28/89 SES Cleaned up code to run a bit more efficiently. Added an initial ; browse through memory so that we can run out of Bank B only for ; HafMac. ; <1.7> 3/7/89 SES Added code to check for warm start and PwrMgr reset before ; running Ram test. ; <1.6> 2/24/89 SES Added code to ensure screen is clean for RBV-based machines. ; <1.5> 2/23/89 SES Mixed conditional for EXPORT BankASize to reflect what's in the ; body of routine. ; <1.4> 2/22/89 SES Added non-destructive code back in. Added check for startup or ; entry from booted system. Changed stack and table setup to be a ; bit more flexible. Still need to add a search for where first ; RAM is. ; <1.3> 2/16/89 rwh Added support for Fitch Memory Controller rev 1. When FMC2 ; arrives, may need to change these for a contiguous physical ; memory model. Removed MvMac hack in SizeMem. ; <1.2> 2/16/89 SES Removed non-destructive code because restored values end up ; writing via wrap into locations that haven't been checked yet. ; <1.1> 2/15/89 SES Fixed routine so that it is non-destructive. On exit, stack will ; be set to the top of tested memory. ; <1.0> 2/13/89 SES Adding to EASE for the first time. ; ;_____________________________________________________________________________________________ PRINT OFF LOAD 'StandardEqu.d' INCLUDE 'HardwarePrivateEqu.a' INCLUDE 'UniversalEqu.a' INCLUDE 'STEqu.a' INCLUDE 'MmuEqu.a' INCLUDE 'BootEqu.a' INCLUDE 'EDiskEqu.a' INCLUDE 'DepVideoEqu.a' PRINT ON STRING ASIS PROC IMPORT GetHardwareInfo, RdXByte,RamInfoPrattFlash EXPORT SizeMemory EXPORT SizeSoundBuffer ; MACHINE MC68020 ;_____________________________________________________________________________________________ ; Routine: SizeMemory ; ; Inputs: none ; ; Outputs: a7 - initialized stack pointer (if RAM found), top element points to ; memory table of size blocks found. ; d6 - result code, 1 nibble/bank, 1 bit set for each SIMM bad in bank: ; = 00000000 if RAM sized ok ; = 00000001 if SIMM 0 in bank A is bad ; = 0000000F if SIMMs 0,1,2,3 in bank A are bad ; = 00000020 if SIMM 1 in bank B is bad ; ; NOTE!! D6 only holds error information for the first 8 banks! ; ; Uses: a0 - Ptr to table of base addresses ; a1 - Ptr to product info record ; d0 ; ; Destroys: d0-d5,a0-a3,a5 ; ; This file contains the universal size memory routine, which sizes memory banks ; for all machines and returns a table of start/size records for each bank found. ; It assumes data cache is off, and no MMU translation. ; The table is located at the top of the last bank of RAM found, and the entries ; have the following format: ; ; A7 --> (pointer to chunk table) ----- ; | ; | ; ChunkTable: start.L,length.L { bank A } <---- ; start.L,length.L { bank B } ; ... { bank n } ; $FFFFFFFF ;_____________________________________________________________________________________________ WITH DecoderInfo,DecoderKinds,StartGlobals, RAMBankInfo ; rb CSS SizeMemory move.l a6,d3 ; save return address moveq #0,d2 ; don't know anything about machine BigBSR6 GetHardwareInfo,a0 move.l d3,a2 ; now keep return address in a2 moveq #0,d3 ; clear a reg move.b d2,d3 ; get memory controller type add.w d3,d3 ; adjust for word table index move.w @splitTbl(d3.w),d3 ; get offset to splitter routine jmp @splitTbl(d3.w) ; SWITCH(controller type) @splitTbl ; This table should match the DecoderKinds record in UniversalEqu.a dc.w SizeBanks -@splitTbl ; unknown dc.w SizeBanks -@splitTbl ; Mac Pal (no splitting required) dc.w SizeBanks -@splitTbl ; BBU (no splitting required) dc.w SizeBanks -@splitTbl ; Normandy (no splitting required) dc.w @GlueSplit -@splitTbl ; Mac2Glue dc.w SizeBanks -@splitTbl ; MDU (no splitting required) dc.w @FMCSplit -@splitTbl ; OSS FMC dc.w @VisaSplit -@splitTbl ; VISA dc.w @OrwellSplit -@splitTbl ; Orwell dc.w @JAWSSplit -@splitTbl ; JAWS dc.w @MSCSplit -@splitTbl ; MSC <7> HJR dc.w @SonoraSplit -@splitTbl ; Sonora

SAM dc.w @NiagraSplit -@splitTbl ; Niagra dc.w @YMCASplit -@splitTbl ; Cyclone EVT4 fau dc.w @djMEMCSplit -@splitTbl ; djMEMc dc.w HMCMerge -@splitTbl ; HMC (Go directly to the merge routine) dc.w @PrattSplit -@splitTbl ; Pratt dc.w HHeadMerge -@splitTbl ; HHead (Go directly to the merge routine) Align 4 ;_____________________________________________________________________________________________ @GlueSplit move.l VIA2Addr(a0),a5 ; Yes, get VIA2 base ori.b #$C0,VBufA(a5) ; put bank B on 64 meg boundary bra SizeBanks ; continue with sizing ;_____________________________________________________________________________________________ @FMCSplit movea.l FMCAddr(a0),a5 ; get the FMC base address move.w #FMCInit,d2 ; config reg value to put bank B on 64 meg boundary moveq.l #16-1,d3 ; loop counter to load 16 bits @FMCload move.b d2,FMCConfig(a5) ; load in a bit lsr.w #1,d2 ; put next bit into position dbra d3,@FMCload ; repeat till all bits loaded move.b d2,FMCLatch(a5) ; latch the config data bra SizeBanks ; continue with sizing ;_____________________________________________________________________________________________ ; ; Make sure that the 4 banks are split apart onto their default 64MB boundaries. ; No other changes to the Orwell configuration register are needed because they ; have been set up in Universal.a and shouldn't require any changes or reconfiguration. ; See {IntAIncludes}HardwarePrivateEqu.a for a full description of this register. ;_____________________________________________________________________________________________ WITH ProductInfo @OrwellSplit IF forSTP601 THEN bra OrwellMerge ; sized memory in HardwareInit.s ENDIF IF forSmurf THEN ; SAM cmp.b #boxRiscQuadra700,ProductKind(a1) ; if we're on a Risc card beq SizeBanks ; >>SKIP this cmp.b #boxRiscQuadra900,ProductKind(a1) ; if we're on a Risc card beq SizeBanks ; >>SKIP this cmp.b #boxRiscQuadra950,ProductKind(a1) ; if we're on a Risc card beq SizeBanks ; >>SKIP this ENDIF ; Eclipse/040 Memory Controller INIT <4> movea.l DecoderAddr(a0),a5 ; get base address of Orwell regs lea OrBankBCfgAddr(a5),a0 ; get address of config regs. move.l #((ORINITBankB)|\ ; get default bank-split values (ORINITBankC< (ORINITBankD<<2*OrBankFieldSize)),d3; moveq.l #(3*OrBankFieldSize)-1,d2 ; (18-1) -1 for DBRA, @OrwellLoad move.l d3,(a0)+ ; send that bit out there lsr.l #1,d3 ; get the next bit in position dbra d2,@OrwellLoad ; repeat til all bits loaded move.l d2,OrLoadBanks(a5) ; initialize DRAM bank starting addrs ; bra SizeBanks ; continue with sizing ;_____________________________________________________________________________________________ @VisaSplit move.l RBVAddr(a0),a5 ; Yes, get VISA base <6> rb, start andi.b #%00011111,VsExp(a5) ; clear size bits. Bits now set to 4MB on PCB
; and no memory in SIMMs movea.l #$001FFFFE,a0 ; Figure out whether we have 2/4mb on PCB by ; writing to 2/3 MB boundary. move.l #$50616E44,(a0) ; Write a long word. Low then high byte is written out to bus cmp.l #$50616E44,(a0) ; If what we wrote is what we get back then we have 4MB on PCB. bne.s @got2MB ori.b #%11000000,VsExp(a5) ; push RAM on PCB up to 8MB boundary so we can check how much RAM in SIMMs ;„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„ ; At this point we've determined that there is 4MB on PCB. We must now figure out how much ; RAM is in the SIMM sockets before going on any further. If we have 8Mb in SIMMs then the ; size bits are set correctly (we then lose 2Mb of on board memory), but if we have less than ; 8Mb the size bits are incorrect and if left this way the on board memory will not be sized ; correctly by the routines that follow and the chunk table will be wrong. move.l a5,a7 ; save ptr to VISA base address in a7 move.l a1,a5 ; get product info ptr adda.l ProductInfo.RamInfoPtr(a5),a5 adda.l #RAMInfoSize+4,a5 ; '+4' taking into account the end of table mark move.l #0,a0 ; start of bank A move.l #$00800000,a1 ; end of bank A move.l #0,d0 ; no previous banks sized move.l #$54696e61,d1 ; setup signature move.l #0,d5 ; clear bank size nibbles BSR6 SizeBank ; how much memory do we have in Bank A? cmp.l #$00800000,a0 ; SizeBank returns amount of RAM found in A0 blt.s @notMaxMem ; if less than 8mb found then reset size bits and RAM ranges sub.l #RAMInfoSize+4,a5 bra continue @notMaxMem ori.b #%10000000,VsExp(a7) andi.b #%10011111,VsExp(a7) ; set Bank A to 4mb, since this is the next size if not 8mb bra continue @got2MB ori.b #%11100000,VsExp(a5) ; set size bits to 10mb (i.e. 2mb on PCB and 8mb in SIMMs) ; we set Bank A to 8Mb so PCB RAM is pushed out of the way ; so we can then get an accurate reading of Bank A RAM. rb, end
bra SizeBanks ; and continue with sizing ENDWITH ;_____________________________________________________________________________________________ @NiagraSplit @JAWSSplit moveq #0,d0 movea.l JAWSAddr(a0),a5 ; get ptr to JAWS base adda.l #JAWSMemConfigA,a5 move.b d0,(a5) ; set size reg A adda.w #JAWSMemConfigB-JAWSMemConfigA,a5 move.b d0,(a5) ; set size reg B adda.w #JAWSMemConfigC-JAWSMemConfigB,a5 move.b d0,(a5) ; set size reg C bra SizeBanks ; and continue with sizing <22> rb ;_____________________________________________________________________________________________ @MSCSplit move.l RBVAddr(a0),a5 ; get MSC base (same as RBV's)

begin ori.b #(1< MOVEA.L A1,A5 ; point to ProductInfo table
ADDA.L ProductInfo.RamInfoPtr(A5),A5 ; point to the RAM bank map info
BRA.S @MSCRefresh ;
@MSCNextBank ;
MOVEA.L D2,A0 ; point to the start of this bank
MOVEQ #8-1,D0 ; make enough long word accesses to @RASLoop TST.L (A0)+ ; provide 8 RAS cycles of DBRA D0,@RASLoop ; memory initialization @MSCRefresh ADDQ.L #4,A5 ; skip over the bank end
MOVE.L (A5)+,D2 ; last RAM bank?
BPL.S @MSCNextBank ; -> nope
bra SizeBanks ; and continue with sizing <7> HJR end ;_____________________________________________________________________________________________ @PrattSplit IF forRomulator THEN TestInRAM a3 ; are we in RAM? bne SizeBanks ; yes, then don't split ENDIF MOVEA.L A1,A5 ; point to ProductInfo table ADDA.L ProductInfo.RamInfoPtr(A5),A5 ; point to the RAM bank map info IF BlackBirdDebug THEN PrattFlashSystem ; IF FlashSystem THEN bne.s @Continue1 ; BigLea RamInfoPrattFlash,a5 ; use phony Flash system RamInfoTables @Continue1 ; ENDIF ; movea.l PrattAddr(a0),a0 ; get ptr to Pratt move.b #PrattDefDensity,\ ; PrattRAMDensity(a0) ; set default RAM Density move.b #PrattDefConfig,\ ; (don't worry, Pratt will do the right thing if there is Flash) PrattRAMConfig(a0) ; set default RAM Configuration ;** WARNING ** WARNING ** WARNING ** WARNING ** WARNING ** WARNING ** WARNING ** ;The following line was added to test Pratt timing for OTPs currently in use for EVT's. ;For the final product, we need to decide what this value should really be. ;NOTE: This value does not affect execution speed from Flash. move.b #Pratt150nsROM,\ PrattROMSpeed(a0) ;** WARNING ** WARNING ** WARNING ** WARNING ** WARNING ** WARNING ** WARNING ** ; wait for at least 2mS so that Pratt has time to initialize the RAM banks to meet all ; vendor specs (the HW spec is really ~500 uS, so we have some margin here) move.w #$3000,d2 @stall dbra d2,@stall BRA.S @PrattRefresh ; @PrattNextBank ; MOVEA.L D2,A0 ; point to the start of this bank TST.L (A0)+ ; make 8 accesses to each physical RAM bank (for added confidence) TST.L (A0)+ TST.L (A0)+ TST.L (A0)+ TST.L (A0)+ TST.L (A0)+ TST.L (A0)+ TST.L (A0)+ @PrattRefresh ADDQ.L #4,A5 ; skip over the bank end MOVE.L (A5)+,D2 ; last RAM bank? BPL.S @PrattNextBank ; -> nope bra SizeBanks ; and continue with sizing ;_____________________________________________________________________________________________ @SonoraSplit ;

MOVE.L RBVAddr(A0),A5 ; Get RBV (Sonora VIA2)

ORI.B #%01111111,SonoraRAMSize(A5) ; Make each bank start at 16mg boundary

; and make bank 0 assume 4 megs of RAM

BRA SizeBanks ; and continue with sizing

;_____________________________________________________________________________________________ @YMCASplit ; IF forRomulator THEN TestInRAM a3 ; are we in RAM? bne SizeBanks ; yes, then don't split ENDIF ; Set the width options for all 4-pairs of banks to 0 (Standard Mode) This is necessary because fau start ; SizeMem is called multiple times by diagnostics, so the power-up values for the YMCA might be changed ; by the time the 2nd call is made. Move.l DecoderAddr(A0),A5 ; Get YMCA's Base address Lea YMCA_DRAMwidth0(a5),a5 ; Get the base address for the first bank's width register Clr.l (A5)+ ; Bank's 0,2 Clr.l (A5)+ ; Bank's 1,3 Clr.l (A5)+ ; Bank's 4,6 Clr.l (A5)+ ; Bank's 5,7 fau end ; Write to all 8 bank addresses to set their starting addresses 16 MB apart and to set their size to ; 16 MBytes. Move.l DecoderAddr(A0),A5 ; Get YMCA's Base address Lea YMCA_DRAMBank0_A20(a5),a5 ; Get the base address for the first bank's A20 register Moveq #0,D0 ; D0 Contains the starting address Move.w #8-1,D5 ; No of banks @NextBank Move.w #BankBdryRegSize-1,d2 ; Size of boundary address register (bits A26..A20 starting at 0) @loadBdry Ror.l #1,d0 ; Move bit 0 to bit 31 move.l d0,(a5)+ ; and write it out dbra d2,@loadBdry ; continue for all bits Rol.l #BankBdryRegSize,D0 ; Return the address to it's starting position Add.l #$10,D0 ; Add (16M >> 20) to the address Move.l #%101,D1 ; D1 contains the size bits = 16MB banks Move.w #BankSizeRegSize-1,d2 ; size of memory bank size bits @loadSize Ror.l #1,d1 ; d1 = nibble size = bank size move.l d1,(a5)+ ; and write it out dbra d2,@loadSize ; continue for all bits dbra d5,@NextBank ; go look at the next bank BRA YMCASizeBanks ; and continue with sizing ; fau, end ;_____________________________________________________________________________________________ thru next WITH ProductInfo @djMEMCSplit ; begin IF forSTP601 THEN bra OrwellMerge ; sized memory in HardwareInit.s, so act exactly like STP Orwell machines ENDIF IF forSmurf THEN ; cmp.b #boxRiscCentris610,ProductKind(a1) ; if we're on a Risc card beq SizeBanks ; >>SKIP this cmp.b #boxRiscCentris650,ProductKind(a1) ; if we're on a Risc card beq SizeBanks ; >>SKIP this cmp.b #boxRiscQuadra800,ProductKind(a1) ; if we're on a Risc card beq SizeBanks ; >>SKIP this cmp.b #boxRiscQuadra610,ProductKind(a1) ; if we're on a Risc card beq SizeBanks ; >>SKIP this cmp.b #boxRiscQuadra650,ProductKind(a1) ; if we're on a Risc card beq SizeBanks ; >>SKIP this ENDIF ; SAM ; We need to determine whether this machine is a WLCD or not. Get VIA1 information. ; ; 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 or Primus (0), or NOT! [reserved] (1) ; move.l VIA1Addr(a0),a5 ; get VIA1 address to get machine/cpu_speed info moveq #%00101000,d1 ; force VIA1 VDirA to have the correct directions move.b d1,VDirA(a5) ; ... so we can read the CPU ID extension info ; Preset/Reset the Interleaving Enable register: ; ---------------------------------------------- ; ; To be able to call SizeBanks repeatedly, we need to turn OFF any interleaving we may have ; turned on during previous SizeMemory calls. However, if you are a WLCD, you want to have ; enabled the OneBufferedBus flag in the InterleaveEnable register. _I_ would have put this ; bit in a different register (Configuration Register?) but since it's not, we have to make ; sure it is correctly set. ; ; For WLCD and Primus, the OneBufferedBus bit MUST be set. ; For Wombat(s), the OneBufferedBus bit MUST be CLEARED. moveq #0,d0 ; preset InterleaveEnable to NO interleaving btst.b #1,VBufA(a5) ; PA1: 0 = WLCD, ­0 = NOT WLCD bne.s @writeIntReg ; IF ( machine_type == WLCD ) || ( machine_type == Primus ) bset #dj_OneBufferedBusBit,d0 ; set OneBufferedBus bit @writeIntReg ; ENDIF LEA MEMCAddr,A5 ; Get djMEMC base move.l d0,MEMCIntleaveEnable(a5) ; disable interleaving, set/clear OneBufferedBus bit ; Reset the chip's MemTop MOVEQ #-1,D0 MOVE.L D0,MEMCmemTop(A5) ; Set MemTop reg to $FF ; Reset all bank Cfg Regs so each bank starts on a 64 mb boundary in preparation ; for sizeBanks. (ie put $110 in Cfg1, $120 in Cfg2, etc.) ;_____________________________________________________________________________ thru next ; MEMC DRAM Bank configuration registers look like this: | 11-9 | 8 | 7-0 | ; Bits 11-9 are unused. ; Bit 8 is DRAM addressing mode (0 = 64mb bank, 1 = 4mb or 16mb bank) ; Bits 7-0 are bits 29-22 of the bank's starting physical address. ; (i.e. smallest bank size = 4mb) ; ; Hysterical Note: (BG - 92 June 10) ; The High-End HW team says that it is entirely unlikely that we'll ; see 64MBit parts any time in the near future, and it's unlikely that ; from power/voltage requirements that our boards would be able to ; support them. So instead of writing the Sizing code to make two passes, ; one with bit 8 ZERO to check for 64MB banks, then a second pass for ; non-64MB parts to see whether or not they are there, we simply assume ; they are NOT there and set bit 8 front and make a single pass. ;_____________________________________________________________________________ MOVE.L #$100,D1 ; Default bank start address (bits 29-22 of addr) MOVEQ #dj_MaxBanks-1,D0 ; Loop counter (10 banks) LEA MEMCdRAMCfg0(A5),A5 ; Get starting bank Cfg reg base @Loop MOVE.L D1,(A5)+ ADD.W #$10,D1 ; Bump the start addr by 64 meg (bits 29-22 of addr) DBRA D0,@Loop * BRA.S SizeBanks ; and continue with sizing ; end ENDWITH ;============================================================================================= SizeBanks movea.l a1,a5 ; pointer to product info table <2.6> adda.l ProductInfo.RamInfoPtr(a5),a5 ; point to the ram bank map info <2.6> IF BlackBirdDebug THEN btst #(PrattExists//8),(ProductInfo.BasesValid1+3-(PrattExists/8))(a1) beq.s @noPratt PrattFlashSystem ; IF FlashSystem THEN bne.s continue ; BigLea RamInfoPrattFlash,a5 ; use phony Flash system RamInfoTables @noPratt ENDIF ; Continue ; label needed for VISA memory sizing
rb moveq #0,d0 ; clear total RAM size sub.l a3,a3 ; initialize the "bank 8-15" information subq.l #1,a3 ; ... to an improbable bank config value @SizeBanks2 ; label needed for djMEMC sizing 2nd half of table movea.l a5,a7 ; keep running copy in a7 addq.l #4,a7 ; skip over chunk size moveq #0,d5 ; clear bank size nibbles moveq #0,d6 ; clear error bits move.l #$54696e61,d1 ; setup signature @nextBank ror.l #4,d5 ; make room for next bank size nibble ror.l #4,d6 ; make room for next bank error nibble movea.l (a7)+,a0 ; get start of bank (or terminator) move.l a0,d2 ; end of table? cmpi.l #'SamB',d2 ; at end of 1st table? beq.s @checkErr ; -> yes, check for errs then continue addq.l #1,d2 beq.s @checkErr ; yes, check for any errors and quit movea.l (a7)+,a1 ; get end+1 of bank BSR6 CheckByteLanes ; any byte lanes valid at start? <2.3> moveq #$0F,d3 ; byte lane mask and.b d6,d3 ; all byte lanes good here? beq.s @size ; yes, try next bank <2.3> cmp.b #$0F,d3 ; were all byte lanes bad? bne.s @nextBank ; no, leave mask with bad bits eor.b d3,d6 ; yes, clear out bit mask bra.s @nextBank @size BSR6 SizeBank ; find size of this bank bra.s @nextBank ; now size next bank... @checkErr move.l a7,d2 ; Save A7 sub.l a5,d2 ; (table end + 8) - table start subq.l #8,d2 ; #entries * 8 lsr.w #1,d2 ; / 8 * 4 = # of nibbles to roll rol.l d2,d5 ; d5 = ....dcba rol.l d2,d6 ; d6 = ....dcba tst.l d6 ; any errors? bne.s @badBanks ; -> Yes, return now thru next move.l a0,d2 ; get the terminator or extend flag in D2 cmpi.l #'SamB',d2 ; Extended flag? bne.s @stitchEm ; -> Nope, we're done move.l d5,a3 ; We have more to do, save D5 in A3 move.l a7,a5 ; Point A5 at the 2nd half of RAMInfo bra.s @SizeBanks2 ; -> make the second pass @stitchEm move.l a3,d2 ; have we put anything in A3 yet? addq.l #1,d2 ; if not, it was $FFFFFFFF beq.w Concat ; IF SomethingInA3 THEN move.l a3,d6 ; Put the extended nibbles in D6 exg d6,d5 ; Put low order banks in d5, extended in d6 bra.w Concat ; Sew baby sew! @badBanks jmp (a2) ; yes, return immediately ;============================================================================================= ; fau start YMCASizeBanks ; ; The YMCA has a separate SizeBanks routine because it supports standard and wide mode DRAM SIMMs. (See ; the YMCA ERS). Wide Mode DRAMs have more rows than columns and use less power -- Wombat uses these too. ; But, we're different and we support the standard mode, where the # of rows and columns are the same. What ; this means is that in order to size the banks we have to go through the sizing routine twice: once with ; the memory controller addressing the SIMMS in standard mode, and once in wide mode. (Note: The YMCA ERS ; has this complicated roadmap to follow in order to size the memory. After reviewing and looking at the ; DRAMs we support I determined that we can size the memory by making the two passes (standard and wide) and ; then comparing the nibble sizes for each bank and taking the largest one). One has to be careful because ; the standard/wide mode is programmed by bank pair: 0/2, 1/3, 4/6, and 5/7. Any bank can be populated, thus ; have to watch out for nibble sizes of 0. Well, enough of this. FAU 10/21/92 movea.l a1,a5 ; pointer to product info table movea.l a1,a7 ; save a copy in a7 for the second sizing. adda.l ProductInfo.RamInfoPtr(a5),a5 ; point to the ram bank map info IF forRomulator THEN TestInRAM a3 ; Are we in RAM? beq.s @YMCAnotInRAM ; No? Then carry on. ; Yes? Assume Bank A is 4 MB movea.l a5,A3 ; keep running copy in A3 add.l #$0C,A3 ; skip over chunk size and bank A move.l #$00400000,d0 ; set RAM size for bank A moveq #$01,d5 ; set bank A size nibbles moveq #0,d6 ; clear error bits move.l #$54696e61,d1 ; setup signature bra.s @YMCAnextBank ; start checking at bank B @YMCAnotInRAM ENDIF movea.l a5,A3 ; keep running copy in A3 addq.l #4,A3 ; skip over chunk size moveq #0,d0 ; clear total RAM size moveq #0,d5 ; clear bank size nibbles moveq #0,d6 ; clear error bits move.l #$54696e61,d1 ; setup signature @YMCAnextBank ror.l #4,d5 ; make room for next bank size nibble ror.l #4,d6 ; make room for next bank error nibble movea.l (A3)+,a0 ; get start of bank (or terminator) move.l a0,d2 ; end of table? addq.l #1,d2 beq.s @YMCAcheckErr ; yes, check for any errors movea.l (A3)+,a1 ; get end+1 of bank BSR6 CheckByteLanes ; any byte lanes valid at start? moveq #$0F,d3 ; byte lane mask and.b d6,d3 ; all byte lanes good here? beq.s @YMCAsize ; yes, try next bank cmp.b #$0F,d3 ; were all byte lanes bad? bne.s @YMCAnextBank ; no, leave mask with bad bits eor.b d3,d6 ; yes, clear out bit mask bra.s @YMCAnextBank @YMCAsize BSR6 SizeBank ; find size of this bank bra.s @YMCAnextBank ; now size next bank... @YMCAcheckErr suba.l a5,A3 ; (table end + 8) - table start subq.l #8,A3 ; #entries * 8 move.l A3,d2 lsr.w #1,d2 ; / 8 * 4 = # of nibbles to roll rol.l d2,d5 ; d5 = ....dcba rol.l d2,d6 ; d6 = ....dcba tst.l d6 ; any errors? bne @ExitSizeMem ; if so, don't do the wide banks stuff ; Now, resize the memory in wide mode. ; Save d5 in a7 and do the sizing with the wide mode. Note, d0 has the total size of DRAM, but ; we're going to recalculate this later, once we figure out which bank needs to be in standard mode and ; which one is in wide mode ; Get back the RamInfoPtr and the Address of our Decoder movea.l a7,a5 ; restore the pointer to the product info table adda.l ProductInfo.RamInfoPtr(a5),a5 ; point to the ram bank map info <2.6> movea.l a7,a1 ; restore the pointer to the product info adda.l ProductInfo.DecoderInfoPtr(a1),a1 ; point to the decoder info stuff movea.l DecoderAddr(a1),a1 ; And get the decoder address ; Program the width registers to wide mode now Lea YMCA_DRAMwidth0(a1),a1 ; and get the offset to the width options register Move.l #-1,(a1)+ ; Bank's 0,2 Move.l #-1,(a1)+ ; Bank's 1,3 Move.l #-1,(a1)+ ; Bank's 4,6 Move.l #-1,(a1)+ ; Bank's 5,7 ; Save our nibble sizes for standard mode move.l d5,a7 ; save our standard mode bank sizes IF forRomulator THEN TestInRAM a3 ; Are we in RAM? beq.s @2YMCAnotInRAM ; No? Then carry on. ; Yes? Assume Bank A is 4 MB movea.l a5,A3 ; keep running copy in A3 add.l #$0C,A3 ; skip over chunk size and bank A move.l #$00400000,d0 ; set RAM size for bank A moveq #$01,d5 ; set bank A size nibbles moveq #0,d6 ; clear error bits move.l #$54696e61,d1 ; setup signature bra.s @2YMCAnextBank ; start checking at bank B @2YMCAnotInRAM ENDIF movea.l a5,A3 ; keep running copy in A3 addq.l #4,A3 ; skip over chunk size moveq #0,d0 ; clear total RAM size moveq #0,d5 ; clear bank size nibbles moveq #0,d6 ; clear error bits move.l #$54696e61,d1 ; setup signature @2YMCAnextBank ror.l #4,d5 ; make room for next bank size nibble ror.l #4,d6 ; make room for next bank error nibble movea.l (A3)+,a0 ; get start of bank (or terminator) move.l a0,d2 ; end of table? addq.l #1,d2 beq.s @2YMCAcheckErr ; yes, check for any errors movea.l (A3)+,a1 ; get end+1 of bank BSR6 CheckByteLanes ; any byte lanes valid at start? moveq #$0F,d3 ; byte lane mask and.b d6,d3 ; all byte lanes good here? beq.s @2YMCAsize ; yes, try next bank cmp.b #$0F,d3 ; were all byte lanes bad? bne.s @2YMCAnextBank ; no, leave mask with bad bits eor.b d3,d6 ; yes, clear out bit mask bra.s @2YMCAnextBank @2YMCAsize BSR6 SizeBank ; find size of this bank bra.s @2YMCAnextBank ; now size next bank... @2YMCAcheckErr suba.l a5,A3 ; (table end + 8) - table start subq.l #8,A3 ; #entries * 8 move.l A3,d2 lsr.w #1,d2 ; / 8 * 4 = # of nibbles to roll rol.l d2,d5 ; d5 = ....dcba rol.l d2,d6 ; d6 = ....dcba tst.l d6 ; any errors? bne @ExitSizeMem ; if so, don't do the wide banks stuff ; We have finished sizing the memory in wide mode. a7 has the nibble sizes with standard mode, ; and d5 has the nibble sizes in wide mode. Move.l a7,d4 ; OK, at this point d4 contains the nibble sizes when sized in standard mode and d5 contains the ; nibble sizes when sized in wide mode. We now need to determine, for each bank, which nibble contains ; the largest amount of ram and program the YMCA to the corresponding Std/Wide option. We'll put the ; combined nibble sizes into d0 and then move it to d5, as that's what the Concat routine expects. Move.l #$50f30420,a3 ; YMCA Width Register Lea YMCAWidthOffsets,a0 ; Offset lookup table clr.w d1 ; Use d1 as our loop/bank counter clr.l d0 ; d0 will contain the combined nibbles @LoopBanks move.b d4,d2 ; we need to compare lower nibbles only (d2: std) andi.b #$0f,d2 ; so mask out higher nibble move.b d5,d3 ; we need to compare nibbles only (d3: wide) andi.b #$0f,d3 ; so mask out higher nibble cmp.b d3,d2 ; d3<-wide, d2<-standard bhs.s @StdMode ; if d2 is ³ then program in standard mode or.b d3,d0 ; else, d3 is > so or move nibble into our keeper Tst.b d3 ; Was our bank size 0 beq.s @NextNibble ; Don't set the width register if the size is 0 Move.w (a0,d1.w*2),a1 ; get offset for this bank adda.l a3,a1 ; and add the base of the width registers Move.l #-1,(a1) ; and write it out bra.s @NextNibble ; go look at next nibble @StdMode or.b d2,d0 ; Standard width size into the keeper ; program bank d1 to std mode Tst.b d2 ; Was our bank size 0 beq.s @NextNibble ; Don't set the width register if the size is 0 Move.w (a0,d1.w*2),a1 ; get offset for this bank adda.l a3,a1 ; and add the base Clr.l (a1) ; and write it out @NextNibble lsr.l #4,d4 ; look at next nibble of standard mode lsr.l #4,d5 ; look at next nibble of wide mode ror.l #4,d0 ; make room for next nibble in our keeper addi.w #1,d1 ; increment our loop counter cmpi.w #8,d1 ; have we done all 8 banks? bne.s @LoopBanks ; go loop through the banks move.l d0,d5 ; put the nibble sizes into d5 bra Concat ; no, then stitch banks together (if possible) @ExitSizeMem jmp (a2) ; yes, return immediately ; fau end ;_____________________________________________________________________________________________ ; Routine: SizeBank ; ; Inputs: a0 - points to start of physical bank to size ; a1 - points to end of physical bank to size ; a2 - SizeMem return address ; (a5) - page size to check for aliasing (e.g. 1 meg) ; d0 - total RAM from previous banks sized ; d1 - signature ; d5 - x......., where x = nibble sizes of previous bank(s) sized. ; ; Outputs: d0 - total RAM including this banks size. ; d5 - x......n, where n = nibble size of this bank (0..15) ; a0 - actual size of bank ; ; Destroys: a1,d2-d4 ; ; Given the start and end of a bank of memory, this routine finds the last location ; within the bank which can be written to (including wrap). Then it trims this back, ; checking for wrap. On exit, it sets a0 = actual size of unique RAM found in the bank, ; (0 if no RAM found), and the low nibble of d5 contains n where bank size = 2^(n-1)*chunk size ; for n > 0, and bank size = 0 for n=0. ; ; This routine assumes that the data cache is OFF. The addresses passed in ; must be on page boundaries, where the page size is in D0. ;_____________________________________________________________________________________________ SizeBank move.l a0,d4 ; save start of bank subq.l #4,a1 ; point to end-4 of bank @check move.l (a1),d2 ; save original move.l d1,(a1) ; write signature at top @here tst.l (@here) ; Bus capacitance is a no, no. SAM cmp.l (a1),d1 ; any RAM there? beq.s @foundRAM ; yes, check for wrap suba.l (a5),a1 ; step back to lower block cmpa.l a0,a1 ; stepped below start? bgt.s @check ; no, continue looking for RAM bra.s @exit ; yes, exit @foundRAM subq.l #4,a0 ; go 4 bytes back from start @loop adda.l (a5),a0 ; add in chunk size cmp.l (a0),d1 ; found lowest occurance of signature? bne.s @loop ; no, check a little higher up move.l d2,(a0)+ ; restore last four bytes we wiped out @length suba.l d4,a0 ; leave a0 with size of bank moveq #0,d3 ; n=0 move.l a0,d2 ; any ram? beq.s @stuff ; no, stuff n=0 into size register move.l (a5),d2 ; start with smallest chunk size (e.g. 1M) @next addq #1,d3 ; n=n+1 cmpa.l d2,a0 ; (2^(n-1))*chunk size = bank size? beq.s @stuff ; yes, stuff 'n' into d5 ; If a0 < d2 then something is wrong! Stuff 0 into d3 and exit. fau blt.s @NotAPowerofTwo ; Our loop has gone over a possible match, so better bailout fau add.l d2,d2 ; calculate next power of two bra.s @next @NotAPowerofTwo ; fau moveq #0,d3 ; say no memory. @stuff or.b d3,d5 ; 'OR' in 'n' (size of this bank) add.l a0,d0 ; add this banks RAM to total size @exit RTS6 ;_____________________________________________________________________________________________ ; Routine: CheckByteLanes ; ; Inputs: a0 - location to check ; d1 - signature ; d6 - x......0 where x = running bit mask of previous bank(s) SIMM errors ; a2 - SizeMem return address ; ; Outputs: d6 - x......e where e = bit mask for this banks errors: ; e = 0000 if byte lanes 0-3 seem ok ; e = 0001 if byte lane 0 seems bad ; e = 1111 if byte lanes 0-3 seem bad ; ; Destroys: d2-d4 ; ; This routine checks which byte lanes are valid at location pointed to by ; a0. This helps service identify missing SIMMs, etc. It can be called up ; to 8 times (for 8, 4-byte-wide banks) before overflowing the result register. ;_____________________________________________________________________________________________ CheckByteLanes ; <2.3> move.l (a0),d3 ; preserve original value move.l 4(a0),d4 ; preserve next value <2.8> move.l d1,(a0) ; write signature moveq #4-1,d2 @next move.l #$FFFFFFFF,4(a0) ; take care of stray capacitance on bus <2.8> cmp.b (a0,d2.w),d1 ; did this byte match? bne.s @bad ; no, shift in error bit not.b d1 ; yes, try compliment to make sure not.b (a0,d2.w) ; compliment RAM value cmp.b (a0,d2.w),d1 ; did compliment match? beq.s @shift ; yes, next byte... @bad bset d2,d6 ; set bad bit mask <2.9> @shift ror.l #8,d1 ; next signature byte dbra d2,@next ; do next byte move.l d3,(a0) ; restore original at start move.l d4,4(a0) ; restore next value <2.8> RTS6 ;============================================================================================= ; Routine: Concat ; ; Inputs: d0 - total size of RAM in system ; d5 - nibble sizes for up to 8 banks ; d6 - nibble sizes for up to an additional 8 banks ; a2 - SizeMem return address ; ; This routine vectors to the appropriate 'stitch' routine, after getting the decoder type. ;_____________________________________________________________________________________________ Concat move.l d0,d3 ; save last size <9> moveq #0,d2 ; don't know anything about machine movea.l #aStack,sp ; set stack pointer value move.l a2,d4 ; save return address BigBSR6 GetHardwareInfo,a0 ; get universal info again movea.l d4,a2 ; restore return address IF BlackBirdDebug THEN btst #(PrattExists//8),(ProductInfo.BasesValid1+3-(PrattExists/8))(a1) adda.l ProductInfo.RamInfoPtr(a1),a1 ; point to the ram bank map info beq.s @Continue1 PrattFlashSystem ; IF FlashSystem THEN bne.s @Continue1 ; BigLea RamInfoPrattFlash,a1 ; use phony Flash system RamInfoTables @Continue1 ; ELSE ; adda.l ProductInfo.RamInfoPtr(a1),a1 ; point to the ram bank map info ENDIF add.b d2,d2 ; decoder type adjusted for word table access ext.w d2 move.w @mergTbl(d2.w),d1 ; get offset to merger routine move.l (a1)+,d2 ; get chunk size in d2 now jmp @mergTbl(d1.w) ; call routine (d2=chunk size, a1=1st table entry) @mergTbl ; This table should match the DecoderKinds record in UniversalEqu.a fau dc.w noMerge -@mergTbl ; unknown dc.w noMerge -@mergTbl ; Mac Pal (no merging required) dc.w noMerge -@mergTbl ; BBU (no merging required) dc.w noMerge -@mergTbl ; Normandy (no merging required) dc.w GlueMerge -@mergTbl ; Mac2Glue dc.w MDUMerge -@mergTbl ; MDU (no merging possible) dc.w FMCMerge -@mergTbl ; OSS FMC dc.w VISAMerge -@mergTbl ; VISA dc.w OrwellMerge -@mergTbl ; Orwell dc.w JAWSMerge -@mergTbl ; JAWS dc.w MSCMerge -@mergTbl ; MSC <7> HJR dc.w SonoraMerge -@mergTbl ; Sonora

SAM dc.w NiagraMerge -@mergTbl ; Niagra dc.w YMCAMerge -@mergTbl ; YMCA fau dc.w djMEMCMerge -@mergTbl ; djMEMC (djMEMC has a max of 10 banks) dc.w HMCMerge -@mergTbl ; HMC SAM dc.w PrattMerge -@mergTbl ; Pratt dc.w HHeadMerge -@mergTbl ; HHead Align 4 ;_____________________________________________________________________________________________ ; Routine: noMerge ; ; Inputs: d0 - bases valid bits ; d2 - chunk size for this decoder ; d3 - total size of RAM in system ; d5 - nibble sizes for up to 8 banks ; a0 - ptr to universal base addresses table ; a1 - ptr to universal RAMInfo table (first entry) ; a2 - SizeMem return address ; ; Outputs: a5 - points to the chunk table ; ; Destroys: d1,a1 ; ; This routine simply writes the chunk table at the top of the bank (pointed to by a1), given ; the banks size in d0. Used ONLY for single bank systems (like MacPlus, SE, Portable). ;_____________________________________________________________________________________________ noMerge ; <9> moveq #(3*4)+(1*8),d1 ; size of chunk table for this decoder bra writeChunkTable ; write chunk table and exit... ;_____________________________________________________________________________________________ ; Routine: HMCMerge (emulated system fake stitch and fake chunk table creation) Sam ; ; Inputs: none ; ; Outputs: a5 - points to the chunk table ; a1 - Ptr to product info record ; ; Destroys: D0-D3/D6,A0-A2 ; ; This routine creates a fixed size chunk table at the end of logical RAM. The emulator provides ; us with the size of logical and physical RAM. The logical size accounts for the RAM stolen by ; the emu for DMA buffers, video, EDisk, etc. The Physical size is useful only for display at the ; Finder, etc. Oh, yes, by the time we get run (68k code, that is) the native hardware init has ; already sized and stitched memory together. ; ; The fake table looks like this: ; ; 1st bank start addr: $00000000 ; Length (log ram size returned from the emu) 0 < X <= 256mb ; Chunk table terminator $FFFFFFFF ; Std diagnostic long #1 $00000000 ; Std diagnostic long #2 $00000000 ; Std diagnostic long #3 $00000000 ; Total bytes allocated for an EDisk $xxxxxxxx ; Total RAM allocated by the nanokernel $xxxxxxxx ; The end of "Physical RAM" ; ; Table size: $20 bytes fixed. ; ; D7 is used as a flag register for the size of the RAM Disk and whether or not to allocate Video RAM ; bit 31: high = allocate Video RAM (bit is cleared when testing to turn on video or not) ;_____________________________________________________________________________________________ export HMCMerge HMCMerge ; Sam With NKSystemInfo, ProductInfo, VideoInfo MOVE.L A2,D6 ; Save SizeMem's return address LongBSR6 GetHardwareInfo ; Get universal info again MOVE.L DecoderInfo.VIA1Addr(A0),A2 ; Get VIA1's base address for RdXByte ; Read PRAM locations (FC through FF) and test for one of several factory settings that ; tell us to allocate a frame buffer (even if no monitor is connected) MOVEQ.L #0,D7 ; Clear the fb allocation flag MOVE.W #burnInLoc,D1 ; 1st burn in byte BSR6 RdXByte ; Read the Factory data MOVE.B D1,D3 ; Save hi byte SWAP D3 LSL.L #8,D3 ; Shift to high byte MOVEQ #0,D1 ; Prep D1 for PRAM data MOVE.W #burnInLoc+1,D1 ; 2nd burn in byte BSR6 RdXByte ; Read the Factory data SWAP D1 ; Save second hi byte OR.L D1,D3 ; MOVEQ #0,D1 ; Prep D1 for PRAM data MOVE.W #burnInLoc+2,D1 ; 3rd burn in byte BSR6 RdXByte ; Read the Factory data LSL.W #8,D1 ; Shift byte to second low byte OR.L D1,D3 ; MOVEQ #0,D1 ; Prep D1 for PRAM data MOVE.W #burnInLoc+3,D1 ; 4th burn in byte BSR6 RdXByte ; Read the Factory data OR.L D3,D1 ; OR in the result CMP.L #burninSig,D1 ; Is this one of the factory settings? BEQ @GetFB ; -> Yes, allocate the frame buffer CMP.L #burnInSigAlt,D1 ; Is this one of the factory settings? BEQ @GetFB ; -> Yes, allocate the frame buffer CMP.L #burnInSig12,D1 ; Is this one of the factory settings? BEQ @GetFB ; -> Yes, allocate the frame buffer CMP.L #burnInSig13,D1 ; Is this one of the factory settings? BEQ @GetFB ; -> Yes, allocate the frame buffer CMP.L #burnInSig15,D1 ; Is this one of the factory settings? BEQ @GetFB ; -> Yes, allocate the frame buffer CMP.L #burnInSig16,D1 ; Is this one of the factory settings? BEQ @GetFB ; -> Yes, allocate the frame buffer ; No factory enable. Check to see what's connected. If nothing is connected, do not ; allocate the frame buffer. MOVE.L #SonoraVdCtlBase,A0 ; Offset from VIA1 base to Sonora Control Regs ADD.L A2,A0 ; Add in VIA1 base. A0 points to SonoraCtrlRegs MOVE.B #$9F,SonoraVdModeReg(A0) ; Disable video (if it was on) MOVE.B #tristateSonoraSense,SonoraVdSenseRg(A0) ; Tristate the sense lines. BSR6 CheckVidSense CMP.B #indexedNoConnect,D3 ; If Sense == No Connect, check Extended Sense BNE @GetFB ; Otherwise turn of Video RAM MOVEQ #0,D1 ; prep D1 for Extended sense data MOVEQ #0,D3 ; prep D2 for Extended sense data ; Sense lines indicate something might be connected. Check the extended sense. ; Drive a, Read bc @DriveA MOVE.B #sonoraEnableAMask,SonoraVdSenseRg(A0) ; abc <- 011 BSR6 CheckVidSense ANDI.B #sonoraAMask,D3 ; 0BC MOVE.B D3,D1 ; 00 00 BC LSL.B #2,D1 ; 00 BC 00 ; Drive b, Read ac @DriveB MOVE.B #sonoraEnableBMask,SonoraVdSenseRg(A0) ; abc <- 101 BSR6 CheckVidSense ANDI.B #sonoraBMask,D3 ; A0C BCLR #sonoraSenseLineA,D3 ; A0C becomes BEQ.S @OrIn ; A0C or BSET #sonoraSenseLineB,D3 ; A1C @OrIn OR.B D3,D1 ; 00 BC AC LSL.B #2,D1 ; BC AC 00 ; Drive c, Read ab @DriveC MOVE.B #sonoraEnableCMask,SonoraVdSenseRg(A0) ; abc -> 110 BSR6 CheckVidSense ANDI.B #sonoraCMask,D3 ; AB0 LSR.B #1,D3 ; 0AB OR.B D3,D1 ; BC AC AB CMP.B #extendedNoConnect,D1 ; Is anything connected? BEQ.S @NoFB ; -> Nope, leave D7 alone. Don't allocate the frame buffer @GetFB BSET.L #31,D7 ; Set the "Allocate a DRAM frame buffer" flag @NoFB ; Read PRAM to see if the user wants an EDisk. If the size is > MinRamDiskSize then ask the SAM ; nanokernel for some RAM. LongBSR6 GetHardwareInfo ; Get universal info again MOVE.L DecoderInfo.VIA1Addr(A0),A2 ; Get VIA1's base address for RdXByte MOVE.W #ramDiskPramAddr,D1 ; Get the EDisk PRAM byte constant BSR6 RdXByte ; Read the EDisk size (in % of total RAM) in D1 MOVE.L D6,A2 ; Restore the return address ADD.L VideoInfoPtr(A1),A1 ; Point A1 to the VideoInfo record for this machine MOVE.L VRAMLogAddr32(A1),D6 ; Get the Logical Frame Buffer base address ; Get the MMU page size from the nanokernel. Count bits in the result to get a shift factor MOVEQ #0,D3 ; Clear D3 MOVE.L ([ProcessorInfoPtr],ProcessorInfo.PageSize),D0 ; Get the Page size from the nano-k BFFFO D0{15:15},D3 ; Get the shift factor (Find First One) NOT.B D3 ; Flip the order (BF instr start at bit 32 -> ) ADD.B #32,D3 ; Get the bit number (lsb based) MOVEQ #0,D5 ; Clear the EDisk allocation size MOVE.L (NKSystemInfoPtr),A5 ; Point to the nanokernel SystemInfo record ANDI.L #$FF,D1 ; Clear upper bytes of pram byte BEQ.S @DMABuffer ; -> No EDisk, check DMA Buffer MOVE.L PhysicalMemorySize(A5),D2 ; Get physical RAM size LSR.L #8,D2 ; Scale the size by 256k chunks MULU.L D1,D2 ; Mult Chunks by ChunkCount from PRAM = EDisk size ADD.L #$7FFF,D2 ; Add an extra 32k to the size AND.W #$8000,D2 ; Round down to 32k boundary CMPI.L #MinRamDiskSize,D2 ; Is this size too small? (user pulled some SIMMs) BLO.S @DMABuffer ; -> Yes, too small. No EDisk CMPI.L #MaxRamDiskSize,D2 ; Is it too big? BHI.S @DMABuffer ; -> Yes, too big. No EDisk MOVE.L LogicalMemorySize(A5),D0 ; Get the logical size (Phys - nk private stuff) till next SUB.L #PDMDMAbufSize,D0 ; Subtract the DAM buffer size from Log RAM size TST.L D7 ; Are we going to allocate 614k for a frame buffer? BPL.S @CheckMinHeap ; -> Nope, SUB.L #604*1024,D0 ; Subtract the frame buffer size if enabled @CheckMinHeap SUB.L D2,D0 ; Subtract the EDisk size CMP.L #MinHeapSize,D0 ; Will we have at least MinHeapSize free after the EDisk? BLT.S @DMABuffer ; -> No, do not allocate the EDisk (signed) MOVE.L D2,D5 ; Save the number of bytes used by the EDisk in the chunk table. ADD.L D2,D7 ; Add the size to our running allocation counter MOVE.L #bRamDisk,D0 ; Get the EDisk logical base address LSR.L D3,D0 ; Turn the address into a page number MOVE.L D0,A0 ; Put the logical page number in A0 LSR.L D3,D2 ; Turn the size into a page count MOVE.L D2,A1 ; Put page count in A1 MOVEQ #0,D1 ; Indicate no special alignment necessary _nkAllocateMemory ; Get the RAM and map it where we asked ; Allocate space for the DMA buffer @DMABuffer MOVE.L #PDMDMAbufSize,D0 ; Get the hard coded DMA buffer size (160k) ADD.L D0,D7 ; Add the DMA buffer size to our counter LSR.L D3,D0 ; Turn the byte count into a page count MOVE.L D0,A1 ; Put page count in A1 MOVE.L #PDMDMAlogAddr,D0 ; Get the desired logical address LSR.L D3,D0 ; Turn it into a page number MOVE.L D0,A0 ; Put the logical page number in A0 MOVE.L #(256*1024)-1,D1 ; Align physical address to 256k boundary (AMIC Requirement) LSR.L D3,D1 ; Make that a page alignment _nkAllocateMemory ; Get the DMA buffer RAM. ; Due to a DataPath bug, all byte-assembled buffers need to be marked noncacheable (floppy & serial). ; Due to an IBM bug, all the rest of the DMA buffers need to be marked noncacheable (marginal parts ; don't like Global/ARty being asserted). MOVE.L #PDMDMAbufSize,D2 ; Get the number of bytes to mark noncacheable (all of them) LSR.L D3,D2 ; Convert that to a page count SUBQ #1,D2 ; Make it zero based for DBRA MOVE.L #PDMDMAlogAddr,D0 ; Start of non cacheable range LSR.L D3,D0 ; Turn it into a logical page number MOVE.L D0,A0 ; Put the page number in A0 @NoCacheLup _nkMMUMakePageNonCacheable ; Disable the cache for this page LEA 1(A0),A0 ; PageNumber++ DBRA D2,@NoCacheLup ; -> Do this for each page ; Allocate RAM for the RAM Based Video (NQD writes *past* the end of the buffer. Get some slop for sloppy...) BCLR.L #31,D7 ; If zero don't allocate the frame buffer BEQ.S @Chunky ; -> Do not allocate the frame buffer MOVE.L #604*1024,D2 ; Get 618496 (604k) bytes (max RBV can support w/slop) ADD.L D2,D7 ; Add the frame buffer size to our counter LSR.L D3,D2 ; Turn the byte count into a page count MOVE.L D2,A1 ; Page Count -> A1 LSR.L D3,D6 ; Turn the logical video base into page number MOVE.L D6,A0 ; Logical Page # -> A0 MOVEQ #-1,D1 ; Force the allocation to start at phys 0 (HMC Requirement) LSR.L D3,D1 ; Make that a page alignment _nkAllocateMemory ; Get the RAM and map it where we asked ; Make the frame buffer RAM cache mode WriteThrough SUBQ #1,D2 ; Make the RBV page count zero based @CacheLupe _nkMakePageWriteThrough LEA 1(A0),A0 ; PageNumber++ DBRA D2,@CacheLupe ; -> Do this for „every„ page ; Now that RAM has been adjusted by the possible allocation of an EDisk, Video frame buffer ; and/or DMA buffer, we can construct the RAM chunk table that sits at the top of logical RAM. ; At this point A5 should be pointing to the nanokernel SystemInfo record. @Chunky MOVE.L UsableMemorySize(A5),D1 ; Get the Useable RAM size from NK MOVE.L D1,A5 ; Put the size (our Memtop) in A5 ; Start from the Top down MOVE.L D7,-(A5) ; Put our total allocation at the top of L RAM (Inc edisk). MOVE.L D5,-(A5) ; Num bytes used by the EDisk MOVE.L #$68657265,-(A5) ; Old Unused Diag long #3 MOVE.L #$77617320,-(A5) ; Old Unused Diag long #2 MOVE.L #$53616D20,-(A5) ; Old Unused Diag long #1 MOVE.L #-1,-(A5) ; Chunk table terminator MOVE.L D1,-(A5) ; Top of usable RAM CLR.L -(A5) ; Logical start of RAM MOVE.L A5,A1 ; Put Ptr to chunk table in A1 for MergeDone MOVEQ #0,D6 ; Signal no RAM test errors. BRA MergeDone ; Set the stack and leave EndWith CheckVidSense MOVE.W #550,D0 ; 550 iterations @WaitLupe TST.B vIER(A2) ; Wait ~1.2µs DBRA D0,@WaitLupe ; -> Keep looping for ~550µs MOVEQ #0,D3 ; D2 used as senseline scratch. MOVE.B SonoraVdSenseRg(A0),D3 ; Read the lines into scratch. LSR.B #4,D3 ; Get inputs out of upper nybble. MOVE.W #550,D0 ; 550 iterations @WaitLupe2 TST.B vIER(A2) ; Wait ~1.2µs DBRA D0,@WaitLupe2 ; -> Keep looping for ~550µs RTS6 ;_____________________________________________________________________________________________ ; Routine: HHEadMerge (emulated system fake stitch and fake chunk table creation) Sam ; ; Inputs: none ; ; Outputs: a5 - points to the chunk table ; a1 - points to the chunk table ; ; Destroys: D0-D3,A0-A2 ; ; This routine creates a fixed size chunk table at the end of logical RAM. The emulator provides ; us with the size of logical and physical RAM. The logical size accounts for the RAM stolen by ; the emu for DMA buffers, video, EDisk, etc. The Physical size is useful only for display at the ; Finder, etc. Oh, yes, by the time we get run (68k code, that is) the native hardware init has ; already sized and stitched memory together. ; ; The fake table looks like this: ; ; 1st bank start addr: $00000000 ; Length (log ram size returned from the emu) 0 < X <= 256mb ; Chunk table terminator $FFFFFFFF ; Std diagnostic long #1 $00000000 ; Std diagnostic long #2 $00000000 ; Std diagnostic long #3 $00000000 ; The end of "Physical RAM" ; ; Table size: $24 bytes fixed. ; ;_____________________________________________________________________________________________ export HHEADMerge HHEadMerge ; Sam With NKSystemInfo, ProductInfo, VideoInfo ; Read PRAM to see if the user wants an EDisk. If the size is > MinRamDiskSize then ask the SAM ; nanokernel for some RAM. MOVE.L A2,D3 ; Save SizeMem's return address LongBSR6 GetHardwareInfo ; Get universal info again MOVE.L DecoderInfo.VIA1Addr(A0),A2 ; Get VIA1's base address for RdXByte LSR.W #8,D2 ; Get the boxflag in the low byte MOVE.B D2,D7 ; Save it in D7 MOVE.W #ramDiskPramAddr,D1 ; Get the EDisk PRAM byte constant BSR6 RdXByte ; Read the EDisk size (in % of total RAM) in D1 MOVE.L D3,A2 ; Restore the return address ; Get the MMU page size from the nanokernel. Count bits in the result to get a shift factor MOVEQ #0,D3 ; Clear D3 MOVE.L ([ProcessorInfoPtr],ProcessorInfo.PageSize),D0 ; Get the Page size from the nano-k BFFFO D0{15:15},D3 ; Get the shift factor (Find First One) NOT.B D3 ; Flip the order (BF instr start at bit 32 -> ) ADD.B #32,D3 ; Get the bit number (lsb based) MOVE.L (NKSystemInfoPtr),A5 ; Point to the nanokernel SystemInfo record ANDI.L #$FF,D1 ; Clear upper bytes of pram byte BEQ.S @Chunky ; -> No EDisk MOVE.L PhysicalMemorySize(A5),D2 ; Get physical RAM size LSR.L #8,D2 ; Scale the size by 256k chunks MULU.L D1,D2 ; Mult Chunks by ChunkCount from PRAM = EDisk size ADD.L #$7FFF,D2 ; Add an extra 32k to the size AND.W #$8000,D2 ; Round down to 32k boundary CMPI.L #MinRamDiskSize,D2 ; Is this size too small? (user pulled some SIMMs) BLO.S @Chunky ; -> Yes, too small. No EDisk MOVE.L #bRamDisk,D0 ; Get the EDisk logical base address LSR.L D3,D0 ; Turn the address into a page number MOVE.L D0,A0 ; Put the logical page number in A0 LSR.L D3,D2 ; Turn the size into a page count MOVE.L D2,A1 ; Put page count in A1 ADD.W #1,A1 ; (Temp Hack bump up by one to work around nk bug) ;MOVEQ #0,D1 ; Indicate no special alignment necessary MOVE.L #16,D1 ; (Temp Hack to get around a nk bug) _nkAllocateMemory ; Get the RAM and map it where we asked ; Now that RAM has been adjusted by the possible allocation of an EDisk, Video frame buffer ; and/or DMA buffer, we can construct the RAM chunk table that sits at the top of logical RAM. ; At this point A5 should be pointing to the nanokernel SystemInfo record. @Chunky MOVE.L UsableMemorySize(A5),D1 ; Get the Useable RAM size from NK MOVE.L D1,A5 ; Put the size (our Memtop) in A5 ; Start from the Top down LEA -8(A5),A5 ; Leave room for two temp warm start flags CLR.L -(A5) ; Old Diag long #3 CLR.L -(A5) ; Old Diag long #2 CLR.L -(A5) ; Old Diag long #1 MOVE.L #-1,-(A5) ; Chunk table terminator MOVE.L D1,-(A5) ; Top of usable RAM CLR.L -(A5) ; Logical start of RAM MOVE.L A5,A1 ; Put Ptr to chunk table in A1 for MergeDone MOVEQ #0,D6 ; Signal no RAM test errors. BRA MergeDone ; Set the stack and leave EndWith ;_____________________________________________________________________________________________ ; Routine: GlueMerge ; ; Inputs: d0 - bases valid bits ; d2 - chunk size for this decoder ; d3 - total size of RAM in system ; d5 - nibble sizes for up to 8 banks ; a0 - ptr to table of base addresses ; a1 - ptr to universal RAMInfo table (first entry) ; a2 - SizeMem return address ; ; Outputs: a5 - points to the chunk table ; ; Destroys: d0-d1,d3,a1,a5 ; ; This routine stitches banks A,B together for the MacII's glue chip decoder. It then writes ; the chunk table at the top of RAM. ;_____________________________________________________________________________________________ GlueMerge ; <9> moveq #$0F,d1 ; prepare to mask for size A nibble and.b d5,d1 ; get bank A size nibble bne.s @sizeBits ; RAM in bank A, leave a1 pointing to bank A start addq #8,a1 ; else, advance to bank B's start lsr.l #4,d5 ; and move bank B's nibble into lsn @sizeBits move.b @VIASizeTable(d1),d0 ; get VIA value movea.l VIA2Addr(a0),a5 ; get VIA 2 base and.b d0,VBufA(a5) ; stuff in new size bits moveq #(3*4)+(2*8),d1 ; size of chunk table for this decoder bra writeChunkTable ; write chunk table and exit... @VIASizeTable dc.b $FF ; [0] A size = 0Mb: Start bank B on 64Mb boundary dc.b $3F ; [1] A size = 1Mb: Start bank B on 1Mb boundary dc.b $FF ; [2] A size = 2Mb: ---- dc.b $7F ; [3] A size = 4Mb: Start bank B on 4Mb boundary dc.b $FF ; [4] A size = 8Mb: ---- dc.b $BF ; [5] A size =16Mb: Start bank B on 16Mb boundary dc.b $FF ; [6] A size =32Mb: ---- dc.b $FF ; [7] A size =64Mb: Start bank B on 64Mb boundary ;_____________________________________________________________________________________________ ; Routine: MDUMerge ; ; Inputs: d0 - bases valid bits ; d2 - chunk size for this decoder ; d3 - total size of RAM in system ; d5 - nibble sizes for up to 8 banks ; a0 - ptr to table of base addresses ; a1 - ptr to universal RAMInfo table (first entry) ; a2 - SizeMem return address ; ; Outputs: a5 - points to the chunk table ; ; Destroys: d0-d3,a1,a5 ; ; This routine writes the chunk table (containing 1 or 2 entries) at the top of the highest bank, ; for the Mac IIci's MDU decoder (no stitching possible with this one). ;_____________________________________________________________________________________________ MDUMerge ; <9> moveq #0,a5 ; no chunk table started yet adda.w #16,a1 ; point to end of bank info table @bankLoop tst.b d5 ; any banks left? beq MergeDone ; no, exit subq #8,a1 ; point to previous bank lsl.l #4,d5 ; yes, shift over next bank move.w d5,d1 lsr.w #8,d1 ; get bank nibble andi.b #$0F,d1 ; mask it beq.s @bankLoop ; no bank, try next BSR6 expandSize ; convert nibble size (in d1) --> real size (in d0) move.l a5,d1 ; already started table? bne.s @writeChunk ; yes, then don't write tail move.l (a1),a5 ; get base of bank adda.l d0,a5 ; point to end of bank clr.l -(a5) ; clear test space clr.l -(a5) ; clear test space move.l #-1,-(a5) ; write FFFFFFFF @writeChunk move.l d0,-(a5) ; write size (0nn00000) move.l (a1),-(a5) ; write start (0x000000) bra.s @bankLoop ;_____________________________________________________________________________________________ ; Routine: FMCMerge ; ; Inputs: d0 - bases valid bits ; d2 - chunk size for this decoder ; d3 - total size of RAM in system ; d5 - nibble sizes for up to 8 banks ; a0 - ptr to table of base addresses ; a1 - ptr to universal RAMInfo table (first entry) ; a2 - SizeMem return address ; ; Outputs: a5 - points to the chunk table ; ; Destroys: d0-d2,a1,a5 ; ; This routine stitches banks A,B together for the Mac IIfx's FMC decoder. It then writes ; the chunk table at the top of RAM. ;_____________________________________________________________________________________________ FMCMerge ; <9> move.w #FMCInit,d1 ; get initial FMC value (assuming no Parity) btst.l #RPUExists,d0 ; do we have parity? beq.s @cont ; no, we're ok move.w #FMCRPUInit,d1 @cont move.w d1,d0 moveq #$0F,d1 ; prepare to mask for size A nibble and.b d5,d1 ; get A size nibble bne.s @sizeBits ; yes, leave a1 pointing to bank A start addq #8,a1 ; else, advance to bank B's start lsr.l #4,d5 ; and move bank B's nibble into lsn @sizeBits and.b @FMCSizeTable(d1),d0 ; 'or' in FMC size bits movea.l FMCAddr(a0),a5 ; get the FMC base address moveq.l #16-1,d1 ; loop counter to load 16 bits <13> @FMCload move.b d0,FMCConfig(a5) ; load in a bit lsr.w #1,d0 ; put next bit into position dbra d1,@FMCload ; repeat till all bits loaded <13> st.b FMCLatch(a5) ; latch the config data @writeTable moveq #(3*4)+(2*8),d1 ; max size of chunk table for this decoder bra writeChunkTable ; write chunk table and exit... @FMCSizeTable dc.b $FF ; [0] A size = 0Mb: Start bank B on 64Mb boundary dc.b $FF ; [1] A size = 1Mb: ---- dc.b $FF ; [2] A size = 2Mb: ---- dc.b $3F ; [3] A size = 4Mb: Start bank B on 4Mb boundary dc.b $7F ; [4] A size = 8Mb: Start bank B on 8Mb boundary dc.b $BF ; [5] A size =16Mb: Start bank B on 16Mb boundary dc.b $FF ; [6] A size =32Mb: ---- dc.b $FF ; [7] A size =64Mb: Start bank B on 64Mb boundary ;_____________________________________________________________________________________________ ; Routine: OrwellMerge ; ; Inputs: d0 - bases valid bits ; d2 - chunk size for this decoder ; d3 - total size of RAM in system ; d5 - nibble sizes for up to 8 banks (we only use the lower 4) ; a0 - ptr to table of base addresses ; a1 - ptr to universal RAMInfo table (first entry) ; a2 - SizeMem return address ; ; Outputs: a5 - points to the chunk table ; ; Destroys: d0-d4,d6,a3,a5 ; ; This routine stitches banks A,B,C,D together for Eclipse's Orwell decoder. It then writes ; the chunk table at the top of RAM. ;_____________________________________________________________________________________________ WITH ProductInfo OrwellMerge ; IF forSTP601 THEN ; WITH NKSystemInfo ; ; Start ; Read PRAM to see if the user wants an EDisk. If the size is > MinRamDiskSize ; then ask thenanokernel for some RAM. MOVE.L A2,D6 ; Save SizeMem's return address MOVEQ.L #0,D7 ; Memory that might get used for RAM disk LongBSR6 GetHardwareInfo ; Get universal info again MOVE.L DecoderInfo.VIA1Addr(A0),A2 ; Get VIA1's base address for RdXByte MOVE.W #ramDiskPramAddr,D1 ; Get the EDisk PRAM byte constant BSR6 RdXByte ; Read the EDisk size (in % of total RAM) in D1 MOVE.L D6,A2 ; Restore the return address> ; Get the MMU page size from the nanokernel.Count bits in the result to get a shift factor MOVEQ #0,D3 ; Clear D3 MOVE.L ([ProcessorInfoPtr],ProcessorInfo.PageSize),D0 ; Get the Page size from the nano-k BFFFO D0{15:15},D3 ; Get the shift factor (Find First One) NOT.B D3 ; Flip the order (BF instr start at bit 32 -> ) ADD.B #32,D3 ; Get the bit number (lsb based) MOVEQ #0,D5 ; Clear the EDisk allocation size MOVE.L (NKSystemInfoPtr),A5 ; Point to the nanokernel SystemInfo record ANDI.L #$FF,D1 ; Clear upper bytes of pram byte BEQ.S @AfterRAMDiskCheck ; -> No EDisk MOVE.L PhysicalMemorySize(A5),D2 ; Get physical RAM size LSR.L #8,D2 ; Scale the size by 256k chunks MULU.L D1,D2 ; Mult Chunks by ChunkCount from PRAM = EDisk size ADD.L #$7FFF,D2 ; Add an extra 32k to the size AND.W #$8000,D2 ; Round down to 32k boundary CMPI.L #MinRamDiskSize,D2 ; Is this size too small? (user pulled some SIMMs) BLO.S @AfterRAMDiskCheck ; -> Yes, too small. No EDisk CMPI.L #MaxRamDiskSize,D2 ; Is it too big?> BHI.S @AfterRAMDiskCheck ; -> Yes, too big. No EDisk MOVE.L LogicalMemorySize(A5),D0 ; Get the logical size (Phys - nk private stuff) @CheckMinHeap SUB.L D2,D0 ; Subtract the EDisk size CMP.L #MinHeapSize,D0 ; Will we have at least MinHeapSize free after the EDisk? BLT.S @AfterRAMDiskCheck ; -> No, do not allocate the EDisk (signed) MOVE.L D2,D5 ; Save the number of bytes used by the EDisk in the chunk table. ADD.L D2,D7 ; Add the size to our running allocation counter MOVE.L #bRamDisk,D0 ; Get the EDisk logical base address LSR.L D3,D0 ; Turn the address into a page number MOVE.L D0,A0 ; Put the logical page number in A0 LSR.L D3,D2 ; Turn the size into a page count MOVE.L D2,A1 ; Put page count in A1 MOVEQ #0,D1 ; Indicate no special alignment necessary _nkAllocateMemory ; Get the RAM and map it where we asked @AfterRAMDiskCheck ; End MOVE.L (NKSystemInfoPtr),A5 ; Point to the nanokernel SystemInfo record MOVE.L UsableMemorySize(A5),D1 ; Get the Useable RAM size from NK MOVE.L D1,A5 ; Put the size (our Memtop) in A5 ; Start from the Top down MOVE.L D7,-(A5) ; Put total allocation at the top of L RAM. MOVE.L #$52555348,-(A5) ; Old Unused Diag long #3 MOVE.L #$6E757320,-(A5) ; Old Unused Diag long #2 MOVE.L #$4379676E,-(A5) ; Old Unused Diag long #1 MOVE.L #-1,-(A5) ; Chunk table terminator MOVE.L D1,-(A5) ; Top of usable RAM CLR.L -(A5) ; Logical start of RAM MOVE.L A5,A1 ; Put Ptr to chunk table in A1 for MergeDone MOVEQ #0,D6 ; Signal no RAM test errors. BRA MergeDone ; Set the stack and leave ENDWITH ; ENDIF ; IF forSmurf THEN bra HMCMerge ; >>SKIP this ENDIF move.w d5,d1 ; get a copy of the size for 4 banks swap d5 ; put a copy in msw of d5 move.w d1,d5 ; and put a copy in the lsw of d5 too move.l a1,d6 ; save productinfo ptr for later movea.l #0,a3 ; clear memory counter move.l #0,d3 ; start with bank 0 (bank A) bra.s @bankMapped ; no need to map bank A ; ; This code maps the current bank to begin immediately after the previous bank. ; It loads Orwell's bank configuration registers, but does not latch them in. ; ; a3.l - offset to map current bank at ; d3.l - bank which we are currently mapping ; @mergeLoop ; LOOP move.l d3,d1 ; get current bank number subq.l #1,d1 ; adjust so Bank 1 has zero offset mulu.l #OrBankFieldSize,d1 ; get bit position in register for this bank move.l DecoderAddr(a0),a5 ; get base addr of Orwell lea (OrBankBCfgAddr,a5,d1.w*4),a5 ; get base address of bank field for this bank move.l a3,d1 ; get addr to map this bank to move.l #22,d4 ; bits to shift to get Orwell config value lsr.l d4,d1 ; d1 contains config value for this bank move.w #OrBankFieldSize-1,d4 ; size of field to load @loadCfgReg move.l d1,(a5)+ ; load a bit lsr.l #1,d1 ; get next bit into position dbra d4,@loadCfgReg ; continue until entire field is loaded ; ; Latch the value we just put into Orwell in. ; movea.l DecoderAddr(a0),a5 ; get base address of Orwell lea OrLoadBanks(a5),a5 ; get address of latch location move.b #$ff,(a5) ; latch bank config values in <14> ; ; Increment offset to map next bank to and point to next chunk. Continue loop if not finished. ; @bankMapped move.l #$0F,d1 ; mask for size nibble of current bank and.b d5,d1 ; get size nibble for current bank lsr.l #4,d5 ; shift size of next bank into low nibble <14> BSR6 expandSize ; nibble size (in d1) --> real size (in d0) adda.l d0,a3 ; calc total amount of memory so far @contLoop tst.l 8(a1) ; are we at the last bank? bmi.s @mergeDone ; >>EXITLOOP if so adda.l #8,a1 ; bump chunk pointer to next entry addq.l #1,d3 ; bump bank number bra.s @mergeLoop ; ENDLOOP ; ; Write chunk table at the end of RAM. After merging, RAM looks like one big chunk starting at zero. ; @mergeDone move.l a3,d3 ; get a copy of total amount of memory <14> move.l d6,a1 ; restore productinfo ptr <14> @endMerge moveq #(3*4)+(4*8),d1 ; size of chunk table for this decoder <14> bra writeChunkTable ; and exit <14> ENDWITH ;_____________________________________________________________________________________________ ; Routine: SonoraMerge ; ; Inputs: D0 - bases valid bits ; D2 - chunk size for this decoder ; D3 - total size of RAM in system ; D5 - nibble sizes for up to 8 banks ; A0 - ptr to table of base addresses ; A1 - ptr to universal RAMInfo table (first entry) ; A2 - SizeMem return address ; ; Outputs: A5 - points to the chunk table ; ; Destroys: D0-D4,D6,A3,A5 ; ; This routine stitches banks A,B,C,D and E together and sets the SIMM size ; bits for the two SIMM sockets for the Sonora decoder. ; It then writes the chunk table at the top of RAM. ;__________________ ; ; Weirdness Notes: ; ; Supports two SIMMs. Each with at most two banks of RAM. ; ; Carnation/Vail machines that have any RAM in bank 0/A (built-in) must have the "Bank0Size" bit ; in the RAM Config register set to 1. ; ; Assumptions: ; If there is no RAM in the first bank of each SIMM, then the other bank is assumed empty as well. ; If RAM is found in the second bank of a SIMM it is assumed to be the same size as ; the first bank. ; ;_____________________________________________________________________________________________ RAMCfgBank0Size EQU 6 ; Sonora RAMConfig Bank0Size Bit. 1=Onboard RAM for Carnation SonoraMerge MOVE.L D2,A5 ; Save D2 for later
MOVEQ #1,D4 ; SIMM loop counter

MOVEQ #(1< No RAM in bank 0/A BCLR.L #RAMCfgBank0Size,D6 ; If no RAM in bank 0 clear the Bank0Size Bit @noBank0 LSR.L #4,D1 ; Look at next bank @SIMMLupe MOVE.B D1,D0 ; Copy two nibbles AND.B #$0F,D0 ; Strip the upper nibble BEQ.S @noRAMBank1 ; -> branch if no RAM in the first bank of this SIMM MOVE.B D1,D2 ; Copy two nibbles AND.B #$F0,D2 ; Strip the lower nibble BEQ.S @NoRAMbank2 ; -> No RAM in the second bank of this SIMM ADDQ #1,D0 ; Both banks filled. Assume both same size. Bump the SIMM size @noRAMbank2 OR.B D0,D6 ; Put this SIMM size in the Cfg reg @noRAMbank1 ROR.B #3,D6 ; Rotate the Cfg reg to prep for setting SIMM1 size LSR.L #4*2,D1 ; Shift the Bank sizes reg two banks right DBRA D4,@SIMMLupe ; Do this twice (once for each SIMM) ROR.B #2,D6 ; Put the config reg back where it belongs @Done MOVE.L A5,D2 ; restore D2
MOVE.L RBVAddr(A0),A5 ; Get RBV (Sonora's VIA2) Base Addr

MOVE.B SonoraRAMSize(A5),D0 ; Get the Cfg Reg AND.B #$80,D0 ; Mask out all but the HiBit (Slot16MHz) OR.B D0,D6 ; Put the Slot16MHz into our SIMM size and Bank0Size byte MOVE.B D6,SonoraRAMSize(A5) ; Set the SIMM size & Stich the banks together (magic) MOVEQ #(3*4)+(5*8),D1 ; size of chunk table for this decoder (3 longs + 5 banks) BRA writeChunkTable ; write chunk table and exit... ;_____________________________________________________________________________________________ ; Routine: YMCAMerge fau, start ; ; Inputs: D0 - bases valid bits ; D2 - chunk size for this decoder ; D3 - total size of RAM in system ; D5 - nibble sizes for up to 8 banks ; A0 - ptr to table of base addresses ; A1 - ptr to universal RAMInfo table (first entry) ; A2 - SizeMem return address ; ; Outputs: A5 - points to the chunk table ; ; Destroys: D0-D4,D6,A3,A5 ; ; This routine stitches banks 0 through 7 and sets the SIMM size ; bits for the eight banks for the YMCA decoder. ; It then writes the chunk table at the top of RAM. ; ;__________________ ; ; Weirdness Notes: ; TBD ;_____________________________________________________________________________________________ YMCAMerge Move.w #YMCAMaxSize,d6 ; Max bank size supported by the YMCA in 2^(n-1)* chunksize movea.l #0,a3 ; clear memory counter Move.l DecoderAddr(A0),A5 ; Get YMCA's Base address Move.l d5,YMCA_DRAMBank0_A20(a5) ; get the base address for the first bank's A20 register ; d6.w will loop through the supported sizes,from largest to smallest ; d4.w will have the bank the size is in @NextSize ; LOOP (thru memory sizes) Move.l d5,d3 ; Get a running copy of the nibble sizes rol.l #4,d3 ; adjust it for the 1st time thru nibble loop Moveq #0,d4 ; Counter to loop through 8 nibbles Move.l DecoderAddr(A0),A5 ; Get YMCA's Base address Lea YMCA_DRAMBank0_A20(a5),a5 ; get the base address for the first bank's A20 register @NextNibble ; LOOP (thru banks) ror.l #4,d3 ; Get the nibble move.w d3,d1 ; we will trash d1 Andi.w #$000f,d1 ; We only want the lowest nibble Cmp.w d6,d1 ; Is this the size we're looking for Bne.s @NoSzMatch ; nope Swap d4 ; save our counter and use the other word for the shift count & size counter Move.w #20,d4 ; # of bits to shift the address to get at the bit we need to program Move.l A3,D0 ; get the current amount of memory lsr.l d4,D0 ; the boundary reg's consist of A20 thru A26 Move.w #BankBdryRegSize-1,d4 ; size of boundary address register @loadBdry Ror.l #1,d0 ; Move bit 0 to bit 31 move.l d0,(a5)+ ; and write it out dbra d4,@loadBdry ; continue for all bits Move.w #BankSizeRegSize-1,d4 ; size of memory bank Move.w d1,d0 ; Get a copy of nibble size in the msw of d1 Swap d1 ; expand size will trash d1 Move.w d0,d1 ; both words of d1 contain the nibble size BSR6 expandSize ; nibble size (in d1) --> real size (in d0) adda.l d0,a3 ; calc total amount of memory so far swap d1 ; get d1.w with the nibble size @loadSize Ror.l #1,d1 ; d1 = nibble size = bank size move.l d1,(a5)+ ; and write it out dbra d4,@loadSize ; continue for all bits Swap D4 ; return our bank counter bra.s @NextBank ; go look at the next bank @NoSzMatch Adda.l #40,a5 ; if we didn't match get the base address of the next bank @NextBank Addq.w #1,d4 ; increment our counter Cmpi.w #8,d4 ; Did we loop through the 8 nibbles yet bne.s @NextNibble ; ENDLOOP (through banks) Dbra d6,@NextSize ; ENDLOOP (through memory sizes) move.l a3,d3 ; get a copy of total amount of memory <14> @Done MOVEQ #(3*4)+(8*8),D1 ; size of chunk table for this decoder (3 longs + 8 banks) BRA writeChunkTable ; write chunk table and exit... ; fau, end ALIGN 4 ; fau, start YMCAWidthOffsets ; This table lists the offsets to the YMCA Width base address from the Base Address of the Width Register. ; It is indexed by bank and provides the offset from YMCA_DRAMwidth0 dc.w $0 ; Bank 0's offset dc.w $4 ; Bank 1's offset dc.w $0 ; Bank 2's offset dc.w $4 ; Bank 3's offset dc.w $8 ; Bank 4's offset dc.w $c ; Bank 5's offset dc.w $8 ; Bank 6's offset dc.w $c ; Bank 7's offset ; fau, end ;_____________________________________________________________________________________________ ; Routine: VISAMerge ; ; Inputs: d0 - bases valid bits ; d2 - chunk size for this decoder ; d3 - total size of RAM in system ; d5 - nibble sizes for up to 8 banks ; a0 - ptr to table of base addresses ; a1 - ptr to universal RAMInfo table (first entry) ; a2 - SizeMem return address ; ; Outputs: a5 - points to the chunk table ; ; Destroys: d0-d1,a5 ; ; This routine stitches banks A,B together for Elsie's VISA decoder. It then writes ; the chunk table at the top of RAM. ; ; Rewritten 5/12/92 (

) to work with LC and LCII. This routine now assumes that the rb, start ; @VISASplit code has set the size bits correctly for bank B. All we have to do here ; is set the size bits for bank A only. Couldn't use old routine because on LC II its ; possible to have the same total RAM configuration but different size bit settings ; (i.e. 6MB total = 2 MB on PCB + 2-2 MB SIMMs in bank A OR 4 MB on PCB and 2-1 MB SIMMs). ;_____________________________________________________________________________________________ VISAMerge ; <9> move.b d5,d1 ;
and.w #$000F,d1 ; get Bank A size nibble move.b (@VISASizeTable,d1.w),d1 ; use size as index into table for "real" size movea.l RBVAddr(a0),a5 ; get size bits and.b #%00111111,VsExp(a5) ; zero out bank A size or.b d1,VsExp(a5) ; OR in bank A size we just got from table btst #5,VsExp(a5) ; test size bits to see if 2/4mb in bank B bne.s @done ; if 4mb then we need to change RAM info tables adda.l #RAMInfoSize+4,a1 ; set a1 to 4mb RAM info table @done moveq #(3*4)+(2*8),d1 ; size of chunk table for this decoder bra writeChunkTable ; write chunk table and exit... @VISASizeTable dc.b $00 ; [0] A size = 0MB dc.b -1 ; [1] A size = 1MB illegal dc.b $40 ; [2] A size = 2MB dc.b $80 ; [3] A size = 4MB dc.b $C0 ; [4] A size = 8MB
rb, end ALIGN ;_____________________________________________________________________________________________ ; Routine: JAWSMerge/NiagraMerge ; ; Inputs: d0 - bases valid bits ; d2 - chunk size for this decoder ; d3 - total size of RAM in system ; d5 - nibble sizes for up to 8 banks ; a0 - ptr to table of base addresses ; a1 - ptr to universal RAMInfo table (first entry) ; a2 - SizeMem return address ; ; Outputs: a5 - points to the chunk table ; ; Destroys: d0-d1,d4,a5 ; ; This routine stitches banks A-B-C-D,E-F-G-H together for Waimea's JAWS decoder. It then writes ; the chunk table at the top of RAM. ;_____________________________________________________________________________________________ NiagraMerge JAWSMerge ; <9> moveq #0,d4 ; init card size reg moveq #3,d1 ; get our special-case value (2 Meg, 1 chunk) <4> cmp.l d1,d5 ; does bank A have it (with bank B=0)? <4> bne.s @checkSpec2 ; no, see if bank B is special (with bank A=0) <4> moveq #0,d4 ; B-A = 0-2 meg, use the 0 table entry <4> bra.s @getTable ; <4> @checkSpec2 swap d1 ; now check bank B for 2 Meg in lowest chunk <4> cmp.l d1,d5 ; with bank A=0 <4> bne.s @notSpec ; no, use standard lookup <4> moveq #$20,d4 ; yes, use B-A = 4-0 meg table entry <4> bra.s @getTable ; <4> @notSpec BSR6 @calcSize ; calc bank B size BSR6 @calcSize ; calc bank A size moveq #16-3,d0 ; prepare to shift bank A size code into high 3 bits lsl.w d0,d4 ; 00000000 00000bbb aaa00000 00000000 lsr.l d0,d4 ; 00000000 00000000 00000000 00bbbaaa @getTable move.b @JAWSSizeTable(d4.w),d0 ; get JAWS size config value movea.l JAWSAddr(a0),a5 ; get ptr to JAWS base adda.l #JAWSMemConfigA,a5 move.b d0,(a5) ; set size reg A lsr.b #2,d0 ; move in next 2 bits adda.w #JAWSMemConfigB-JAWSMemConfigA,a5 move.b d0,(a5) ; set size reg B lsr.b #2,d0 ; move in last 2 bits adda.w #JAWSMemConfigC-JAWSMemConfigB,a5 move.b d0,(a5) ; set size reg C moveq #(3*4)+(8*8),d1 ; size of chunk table for this decoder bra writeChunkTable ; write chunk table and exit... ;............................................................................................ @calcSize movea.l a6,a5 ; keep return address in a5 moveq #4-1,d1 ; count 4 banks @nextNib swap d1 ; keep count in d1.hw move.w #$0F,d1 rol.l #4,d5 ; and.b d5,d1 ; get next size nibble BSR6 expandSize ; nibble size (in d1) --> real size (in d0) add.l d0,d4 ; add to total for this bank swap d1 ; get count back dbra d1,@nextNib swap d4 ; 000x00n0 lsr.w #4,d4 ; 000x000n cmpi.b #8,d4 ; was it 8? bne.s @done ; no, then we're done subq.b #1,d4 ; yes, make it a 7. @done jmp (a5) ; and exit @JAWSSizeTable dc.b %00000 ;[000 000] B:0, A:0 dc.b %00001 ;[000 001] B:0, A:1 dc.b %00001 ;[000 010] B:0, A:2 dc.b %00010 ;[000 011] B:0, A:3 dc.b %00000 ;[000 100] B:0, A:4 dc.b %00000 ;[000 101] -------- dc.b %00000 ;[000 110] B:0, A:6 dc.b %00000 ;[000 111] B:0, A:8 dc.b %11111 ;[001 000] B:1, A:0 dc.b %10011 ;[001 001] B:1, A:1 dc.b %00011 ;[001 010] B:1, A:2 dc.b %01010 ;[001 011] B:1, A:3 dc.b %01001 ;[001 100] B:1, A:4 dc.b %00000 ;[001 101] -------- dc.b %00110 ;[001 110] B:1, A:6 dc.b %01000 ;[001 111] B:1, A:8 dc.b %11111 ;[010 000] B:2, A:0 dc.b %00111 ;[010 001] B:2, A:1 dc.b %00011 ;[010 010] B:2, A:2 dc.b %10010 ;[010 011] B:2, A:3 dc.b %01001 ;[010 100] B:2, A:4 dc.b %00000 ;[010 101] -------- dc.b %00110 ;[010 110] B:2, A:6 dc.b %01000 ;[010 111] B:2, A:8 dc.b %11101 ;[011 000] B:3, A:0 dc.b %00100 ;[011 001] B:3, A:1 dc.b %00100 ;[011 010] B:3, A:2 dc.b %11001 ;[011 011] B:3, A:3 dc.b %10001 ;[011 100] B:3, A:4 dc.b %00000 ;[011 101] -------- dc.b %01110 ;[011 110] B:3, A:6 dc.b %11000 ;[011 111] B:3, A:8 dc.b %10111 ;[100 000] B:4, A:0 dc.b %01001 ;[100 001] B:4, A:1 dc.b %00101 ;[100 010] B:4, A:2 dc.b %01111 ;[100 011] B:4, A:3 dc.b %11011 ;[100 100] B:4, A:4 dc.b %00000 ;[100 101] -------- dc.b %10110 ;[100 110] B:4, A:6 dc.b %00000 ;[100 111] B:4, A:8 dc.b %00000 ;[101 000] -------- dc.b %00000 ;[101 001] -------- dc.b %00000 ;[101 010] -------- dc.b %00000 ;[101 011] -------- dc.b %00000 ;[101 100] -------- dc.b %00000 ;[101 101] -------- dc.b %00000 ;[101 110] -------- dc.b %00000 ;[101 111] -------- dc.b %10111 ;[110 000] B:6, A:0 dc.b %01011 ;[110 001] B:6, A:1 dc.b %01011 ;[110 010] B:6, A:2 dc.b %01100 ;[110 011] B:6, A:3 dc.b %10100 ;[110 100] B:6, A:4 dc.b %00000 ;[110 101] -------- dc.b %11010 ;[110 110] B:6, A:6 dc.b %00000 ;[110 111] B:6, A:8 dc.b %10111 ;[111 000] B:8, A:0 dc.b %01101 ;[111 001] B:8, A:1 dc.b %01101 ;[111 010] B:8, A:2 dc.b %10101 ;[111 011] B:8, A:3 dc.b %10111 ;[111 100] B:8, A:4 dc.b %00000 ;[111 101] -------- dc.b %10111 ;[111 110] B:8, A:6 dc.b %00000 ;[111 111] B:8, A:8 ; <22> rb, from Terror for DBLite ;_____________________________________________________________________________________________ ; Routine: MSCMerge ; ; Inputs: d0 - bases valid bits ; d2 - chunk size for this decoder ; d3 - total size of RAM in system ; d5 - nibble sizes for up to 8 banks ; a0 - ptr to table of base addresses ; a1 - ptr to universal RAMInfo table (first entry) ; a2 - SizeMem return address ; ; Outputs: a5 - points to the chunk table ; ; Destroys: d0-d1,a5 ; ; This routine stitches banks A-H together for DB-Lite's MSC controller. It then writes ; the chunk table at the top of RAM. RAM banks 4-7 can either contain 2MB or 8MB of RAM. ; If bank 4 doesn't have 8MB of RAM, we'll assume the rest don't and clear the MSCBank8M ; bit in the MSC configuration register. ; ; Bank A is always 2MB ; Bank B is always 2MB ; Bank C can be 0 or 2 ; Bank D can be 0 or 2 ; Bank E can be 0 or 2 or 8 ; Bank F can be 0 or 2 or 8 ; Bank G can be 0 or 2 or 8 ; Bank H can be 0 or 2 or 8 ;_____________________________________________________________________________________________ MSCMerge ; bfffo d5{0:31},d1 ; find the highest bit (bank) set
neg.b d1 ;
add.b #32,d1 ;
asl.b #MSCSize0-2,d1 ; / bank size = highest bank # (upper 3 bits)
ori.b #(1< moveq #$0F,d0 ; find out how much in bank 4
swap d0 ;
and.l d5,d0 ;
swap d0 ; nibble size in low byte
subq.b #$03,d0 ; check for 8 MB
beq.s @TwoMegBanks ;
bclr #MSCBank8M,d1 ; not 8 MB, clear our Bank8M enable
@TwoMegBanks movea.l RBVAddr(a0),a5 ; get ptr to MSC (same as RBV's)

and.b d1,MSCConfig(a5) ; set MSC size bits

@done moveq #(3*4)+(8*8),d1 ; size of chunk table for this decoder bra writeChunkTable ; write chunk table and exit... ;_____________________________________________________________________________________________ ; Routine: PrattMerge ; ; Inputs: d0 - bases valid bits ; d2 - chunk size for this decoder ; d3 - total size of RAM in system ; d5 - nibble sizes for up to 8 banks ; a0 - ptr to table of base addresses ; a1 - ptr to universal RAMInfo table (first entry) ; a2 - SizeMem return address ; ; Outputs: a5 - points to the chunk table ; ; Destroys: d0-d1,d4,a5 ; ; This routine stitches banks A-F together for the Pratt controller. It then writes ; the chunk table at the top of RAM. ; ; Onboard RAM: ; Bank A can be 0,2,4,or 8MB ; Bank B can be 0,2,4,or 8MB ; If 2MB banks, then there must be two banks, for a total of 4MB ; If 4MB banks, then one or two banks allowed, for either 4MB or 8MB ; If 8MB bank, then one or two banks allowed, for either 8MB or 16MB ; ; Expansion RAM: ; Banks C,D,E,F can have 0,2,4,or 8MB. ; All expansion banks with RAM in them must be the same size. Banks must be loaded in order. ; ;_____________________________________________________________________________________________ PrattMerge ; ; find out which banks have memory ; input: d5.l -- each non-zero nibble means corresponding bank has memory ; output: d4.b -- each non-zero bit means corresponding bank has memory, bits 0-5 ; movea.l d5,a5 ; save a copy of nibble sizes moveq #0,d0 ; initialize count move.b #PrattBankBits,d4 ; load initial mask for RAM Configuration Register (in Pratt) @bankloop move.b d5,d1 ; get copy of nibble sizes andi.b #$0F,d1 ; look at low nibble bne.s @next ; nibble non-zero -> memory in bank, so leave bit set bclr d0,d4 ; no memory in this bank, so clear bit @next lsr.l #4,d5 ; look at next nibble addq #1,d0 ; inc nibble count cmpi.b #PrattNumbanks-1,d0 ; have we looked at all the banks? ble.s @bankloop move.l a5,d5 ; restore copy of nibble sizes ; figure out the onboard configuration (Banks A and B) ; output: d1 has the onboard memory bank bit configuration bits configured ; move.b #PrattDensBits,d1 ; load initial mask for RAM Density Register (in Pratt) move.l d5,d0 ; get copy of nibble sizes andi.l #$0000000F,d0 ; find out how much in bank 0 bne.s @check2 ; more than 0 MB, go check for 2 andi.b #Pratt0MBbank,d1 ; there is no RAM on the daughter card bra.s @getExpMem @check2 cmpi.l #1,d0 ; check for 2 MB (nibble size = 1 for 2MB chunksize) bne.s @check4 ; more than 2MB, go check for 4 andi.b #Pratt2MBbank,d1 ; there are 2MB bra.s @getExpMem ; @check4 cmpi.l #2,d0 ; check for 4MB (nibble size = 2 for 2MB chunksize) bne.s @set8 ; more than 4MB, must be 8 andi.b #Pratt4MBbank,d1 ; there are 4 MB bra.s @getExpMem @set8 andi.b #Pratt8MBbank,d1 ; set 8 MB bank size ; find out size of expansion memory banks ; output: d1 has the expansion memory bank size bit configured ; @getExpMem move.l #$00000F00,d0 ; find out how much in bank C (D,E,F must be the same size) and.l d5,d0 ; the formula is (2^(n-1) * 2) MB where "n" is the nibble value bne.s @check2e andi.b #Pratt0MBExBank,d1 bra.s @writeConfigRegs @check2e cmpi.l #$00000100,d0 ; check for 2 MB (nibble size = 1) bne.s @check4e andi.b #Pratt2MBExBank,d1 bra.s @writeConfigRegs @check4e cmpi.l #$00000200,d0 ; check for 4 MB (nibble size = 2) bne.s @set8e andi.b #Pratt4MBExBank,d1 bra.s @writeConfigRegs @set8e andi.b #Pratt8MBExBank,d1 ; set config for 8MB banks on the expansion card @writeConfigRegs movea.l PrattAddr(a0),a5 ; get ptr to Pratt IF forRomulator THEN TestInRAM a0 ; are we in RAM? bne.s @done ; yes, then don't really muck with RAM Config registers ENDIF move.b d1,PrattRAMDensity(a5) ; set Pratt RAM density register value move.b d4,PrattRAMConfig(a5) ; set Pratt RAM config register value bset.b #0,PrattRefresh(a5) ; set Pratt Refresh rate to be generated every 33 clocks. @done moveq #(3*4)+(6*8),d1 ; size of chunk table for this decoder bra writeChunkTable ; write chunk table and exit... ;_____________________________________________________________________________________________ thru next ; Routine: djMEMCMerge begin ; ; Inputs: d0 - bases valid bits ; d2 - chunk size for this decoder ; d3 - total size of RAM in system ; d5 - nibble sizes for up to 8 banks (Banks 0 thru 7) ; d6 - nibble sizes for an additional 8 banks (Banks 8 thru 15) ; a0 - ptr to table of base addresses ; a1 - ptr to universal RAMInfo table (first entry) ; a2 - SizeMem return address ; ; Outputs: a5 - points to the chunk table ; ; Destroys: d0-d1,a5 ; ; NOTE: If you made it here, then D6 should be zero (no errors encountered during SizeBanks). ; If that's true, then if D6 EXITS this code also being zero, then we should be able ; to abuse it during this part of the code. ;_____________________________________________________________________________________________ WITH ProductInfo djMEMCMerge IF forSmurf THEN bra HMCMerge ; >>SKIP this ENDIF LEA MEMCAddr+MEMCDRAMCfg0,A0 ; Point A0 to the first bank's Cfg reg MOVEQ #0,D0 SUBA.L A3,A3 ; A3 = 0 MOVEQ #dj_MaxBanks-1,D1 ; # of banks minus 1 @Loop MOVE.L A3,D4 ; Get running size in D4 SWAP D4 ; Poor man's BFEXTU D4{22:8},D4 LSR.W #6,D4 MOVE.L (A0),D0 MOVE.B D4,D0 ; Move bits 22-29 of addrs into bits 7-0 of cfg reg MOVE.L D0,(A0)+ MOVEQ #$0F,D4 ; Nibble mask CMPI.B #2-1,D1 ; Are we on the first set of 8 banks? BHI.S @D5 ; -> Yes, use D5 for the first 8 @D6 AND.B D6,D4 ; Get the nibble (banks 8 thru 15) ROR.L #4,D6 ; prep for next time BRA.S @Comm @D5 AND.B D5,D4 ; Get the nibble (banks 0 thru 7) ROR.L #4,D5 ; Roll around for next time @Comm TST.B D4 ; Any RAM in this bank? BEQ.S @NextOne ; -> Nope, lupe sum more SUBQ #1,D4 ; Multiplying by powers of 2 (start at 2^1) MOVE.L D2,D0 ; chunkSize LSL.L D4,D0 ; This bank's size in bytes ADD.L D0,A3 ; Add this bank's size to the running total @NextOne DBRA D1,@Loop ROL.L #8,D6 ; Fix D6 (contains only 2 banks, but should be in LSB) MOVE.L A3,D0 ; Get total RAM in d0 SWAP D0 ; Poor man's BFEXTU D4{22:8},D4 LSR.W #6,D0 MOVE.L D0,MEMCAddr+MEMCmemTop ; Move bits 22-29 of addrs into bits 7-0 of MemTop reg ; ----------------------------------------------------------------------------------------- ; ; Put in interleave enabling code HERE. ; ; It must go here because if you turn it on after the chunk table is built, interleaving ; "scrambles" the banks and the chunk table would get scrambled as well. ; ; At this point, we can thrash A0 ; ; Bank information is stored in D5 & D6. D5 = banks 0-7, D6 = banks 8&9 ; Organization of D5 and D6 is: ; ; +-------------------------------------------------------+ ; | bank | bank | bank | bank | bank | bank | bank | bank | ; | 7 | 6 | 5 | 4 | 3 | 2 | 1/9 | 0/8 | D5/D6 bank value positions ; +-------------------------------------------------------+ ; ----------------------------------------------------------------------------------------- IF forRomulator THEN ; if you're running a ROM in RAM, you dont EVER bra @skipInterleave ; want to turn on interleaving. it could make your day ENDIF ; very unhappy ; Only allow interleave enable on djMEMC versions > 0. thru next ; Version 0 parts cause the machine to lock up if interleaving is enabled. lea MEMCAddr+MEMCIntleaveEnable,a0; get interleave enable reg. address moveq #$0E,d0 ; mask for djMEMC version number, shifted 1 bit to the left rol.l #8,d0 ; shift mask to correct location and.l (a0),d0 ; check djMEMC version beq.s @skipInterleave ; IF djMEMC_Version != 0 THEN ; make sure banks are the same size first move.l d5,d1 ; get 1st 8 banks info move.l d1,d0 ror.l #4,d0 ; such that d0 = (d1 >> 4), or bank pairs in same bit positions eor.l d0,d1 ; XOR them to see if they're the same andi.l #$0F0F0F0F,d1 ; AND to get only bottom nibble of each byte moveq.l #1,d0 ; starting bit of bank 0&1 in interleave reg. move.l (a0),d4 ; get current OneBufferedBit value from interleave reg. andi.w #$FFE0,d4 ; force the Interleaved bank bits to be unset @chkNextPair tst.b d5 ; test this bank PAIR beq.s @nextpair ; BRIF both banks empty tst.b d1 ; test if both banks EQUAL bne.s @nextpair ; IF BankX == BankX+1 THEN or.w d0,d4 ; set appropriate bit @nextpair ; ENDIF ror.l #8,d5 ; point to next bank pair ror.l #8,d1 ; point to next XORed bank-pair results rol.l #1,d0 ; rotate bit to next interleave bit cmpi.b #%10000,d0 ; checking banks 8&9 yet? bne.s @chkNextPair ; if still working with banks 0-7 ; if you're here, then we need to test banks 8&9, found in D6. tst.b d6 ; are both banks empty? beq.s @setInterleave ; IF Bank8&9 != EMPTY move.b d6,d1 ; get info for bank 8 move.b d1,d0 ; &9 andi.b #$0F,d1 ; isolate bank 8 ror.b #4,d0 ; align them so nibbles for 8&9 are the same andi.b #$0F,d0 ; isolate bank 9 cmp.b d0,d1 ; check if bank 8 is same size as bank 9 bne.s @setInterleave ; IF Bank8 == Bank9 THEN ori.b #%10000,d4 ; set bit for banks 8&9 @setInterleave ; ENDIF move.l d4,(a0) ; and write it out to the interleave config reg. @skipInterleave ; ENDIF MOVEQ #(3*4)+(10*8),D1 ; size of chunk table for this decoder (3 longs + 10 banks) BRA newWriteChunkTable ; write chunk table and exit... (ext nibbles in D6) ENDWITH ; ----------------------------------------------------------------------------------------- align 2 ; ;_____________________________________________________________________________________________ ; Routine: expandSize ; ; Inputs: d1.w - nibble size of this bank ; d2 - chunk size ; ; Outputs: d0 - .nnn...., where n = size in bytes of this bank ; ; Destroys: d1 ; ; This routine converts the nibble size in d1 to a real size (in bytes) in d0, based on a ; chunk size in d2. ;_____________________________________________________________________________________________ expandSize moveq #0,d0 ; assume no RAM tst.w d1 ; any RAM? beq.s @exit ; no, exit move.l d2,d0 ; yes, get chunk size subq.w #1,d1 ; count it lsl.l d1,d0 ; multiply by correct power of 2 @exit RTS6 ;============================================================================================= ;_____________________________________________________________________________________________ ; Routine: writeChunkTable ; ; Inputs: a1 - ptr to universal RAMInfo table (first entry) ; d1 - size of chunk table (including 2 test longs and end of table longword) ; d2 - chunk size for this decoder ; d3 - total size of RAM in system ; d5 - nibble sizes for up to 8 banks ; d6 - nibble sizes for up to another 8 banks (newWriteChunkTable) ; ; Outputs: d0 - .nnn...., where n = size in bytes of this bank ; ; Destroys: d1/d5/d6/a7 ; ; Writes the chunk table at the end of RAM, based on the values passed in. This routine ; creates a separate entry for each chunk that contains RAM. ; ; „„ New Mod „„ - If you have more than 8 banks, then you should call newWriteChunkTable ; with the first 8 banks of nibbles in D5 (as usual) and the second (up to) 8 banks of nibbles ; in D6. The total size of the chuck table should be in D1 (1 entry for each bank plus the ; test longs at the end of the table - same as always). ;_____________________________________________________________________________________________ writeChunkTable ; <11> moveq #0,d6 ; clear the extended nibble count for the old guys newWriteChunkTable ; new entry point for machines with > 8 banks of memory movea.l (a1),a5 ; get start of bank move.l a5,a0 ; running bank start ptr adda.l d3,a5 ; point to end of bank suba.l d1,a5 ; allocate space for test space/chunk table move.l a5,a7 ; remember start of chunk table @loop moveq #$0F,d1 ; prepare to mask for size nibble and.b d5,d1 ; get bank size nibble beq.s @next ; skip if no RAM in this bank BSR6 expandSize ; convert nibble size (in d1) --> real size (in d0) move.l a0,(a7)+ ; write start move.l d0,(a7)+ ; write length add.l d0,a0 ; calculate next start @next lsr.l #4,d5 ; shift in next bank nibble bne.s @loop ; continue if more banks move.l d6,d5 ; do we have more banks to do? ( > 8) beq.s @finishup ; -> Nope, no more clr.l d6 ; clr the extended nibble sizes (so we only do this once) bra.s @loop ; do more banks @finishup subq.l #1,d5 ; = FFFFFFFF move.l d5,(a7)+ ; write FFFFFFFF (terminator) @fill clr.l (a7)+ ; clear test space move.w a7,d0 ; at end of bank bne.s @fill ; no, keep clearing ;............................................................................................. MergeDone movea.l (a1),sp ; sp := base of RAM adda.l #$8000,sp ; sp := base of RAM + 32K move.l a5,-(sp) ; push ptr to chunk table on stack ;_____________________________________________________________________________________________ begin ; ; For machines with a sound buffer in high RAM (i.e., ASC-based machines), we'll move the ; RAM chunk table below the sound buffer. This will avoid collisions with large MMU tables. ; We need to do this here because SizeMem gets called more than once (by diagnostics), so ; that, for example, the warmstart flag will be valid across boots. ; ; BEFORE AFTER ; ; +-------------------+ <-- top of memory --> +-------------------+ ; | RAM chunks | | | ; |-------------------| | | ; | | | | ; | BootGlobs & +-------------------+ +-------------------+ ; | MMU tables | | | | ; | will grow dow| Sound Buffer | | Sound Buffer | ; | | | | | | ; | V +-------------------+ +-------------------+ ; | | | RAM chunks | ; +-------------------+ |-------------------| ; | | ; | BootGlobs & | ; | MMU tables | ; | will grow down | ; | | | ; | V | ; | | ; +-------------------+ ;_____________________________________________________________________________________________ MOVE.L A2,D3 ; save the return address MOVEQ #0,D2 ; get the decoder type BigBSR6 GetHardwareInfo,a0 ; MOVEA.L (SP),A6 ; point to the chunk table LEA @Resume,A2 ; (BSR2) BRA.S SizeSoundBuffer ; get the size of a sound buffer in high RAM (if any) @Resume BEQ.S @Done ; -> no sound buffer SUB.L D0,(SP) ; adjust the address of the new chunk table SUB.L A6,D1 ; calculate the size of the chunk table @MoveChunks MOVE.B -(A1),-(A0) ; move the RAM chunk table to its new home SUBQ.L #1,D1 ; BGT.S @MoveChunks ; @Done MOVEA.L D3,A2 ; restore the return address moveq #0,d6 ; Z flag set to indicate no error(s) <15> jmp (a2) ;_____________________________________________________________________________________________ ; ; Routine: SizeSoundBuffer ; ; Inputs: D2.B- decoder type (from Universal) ; A2 - return address ; A6 - physical address of RAM chunk table ; ; Outputs: D0 - size of sound buffer (zero if none) ; A0 - pointer to start of sound buffer ; A1 - pointer to end of RAM ; A6 - physical address of RAM chunk table ; ; Trashes: none ; ; Function: returns the starting address and size of a sound buffer in high RAM. ;_____________________________________________________________________________________________ SizeSoundBuffer ; LEA @bufSizeTbl-4,A1 MOVEQ #0,D0 ; assume no sound buffer in high RAM @FindDecoder ADDQ.W #4,A1 ; skip over the previous routine offset MOVE.W (A1)+,D0 ; get the next decoder type BEQ.S @Done ; -> end of list CMP.B D2,D0 ; does the decoder match? BNE.S @FindDecoder ; -> no, try the next one MOVE.L (A1)+,D0 ; yes, get offset from top of RAM to start of sound buffer MOVEA.L A6,A1 ; point to the start of the chunk table BRA.S @FirstChunk ; and start looking @FindLastChunk ADDQ.W #8,A1 ; skip over the previous chunk start/size @FirstChunk TST.L (A1) ; are we at the end of the table? BPL.S @FindLastChunk ; -> nope, keep going MOVE.L -(A1),D1 ; calculate the address of the end of the last chunk ADD.L -(A1),D1 MOVEA.L D1,A1 ; and save it MOVEA.L D1,A0 ; calculate where the end of the moved chunk table will be SUBA.L D0,A0 ; (this is also the start of the sound buffer) @Done TST.L D0 ; set the CCR JMP (A2) ; IMPORTANT: Because of the way that ConfigureRAM works (in StartInit), the following table sizes must be ; multiples of 1024. @bufSizeTbl DC.W DecoderKinds.MSCDecoder ; MSC DC.L (8*1024) DC.W DecoderKinds.PrattDecoder ; Pratt (for Blackbird) DC.L (32*1024) ; Sound can use a FIFO size up to 32K (includes modem sound buffer) DC.W 0 ; end of list end END