þa‹RþwQþ m Z<þhý oPþ nSystem-wide$NOLIST COMPACT ROM OPTIMIZE(3) $LARGE (SomeOtherModule EXPORTS CpSetActiveSlot, CpGetSlotAddress, ConLineOut, ConCharOut, MakeCheckSum) BankSwitch: DO; $INCLUDE (``Incs`PlmLits.Inc~Text~) $INCLUDE (``Incs`OsPlmTypes.Inc~Text~) /* Constants */ DCL romHere LIT '0BB66h'; DCL bankIncrement LIT '2000h'; DCL initialBank LIT '8000h'; DCL thirdQtrAddr LIT '9000h'; DCL maxSystems LIT '3'; DCL numRomSlots LIT '4'; DCL cr LIT '0dh'; DCL lf LIT '0ah'; DCL systemFlag LIT '80h'; DCL readLastKey LIT '2'; DCL firstQtr LIT '8'; DCL secondQtr LIT '0Ah'; DCL thirdQtr LIT '0Ch'; DCL fourthQtr LIT '0Eh'; DCL romHeaderSize LIT '256'; DCL headerSel LIT '9ff0h'; DCL thirtyTwoKMask LIT '80h'; /* Types */ DCL SlotInfoType LIT 'STRUCTURE (waitStateCode BYTE, romId WORD, slotAddress WORD, validRom BOOLEAN, slots BYTE, spare BYTE)'; DCL MoreRomHeaderInfo LIT 'dirSelector WORD, dirLength WORD, numFiles WORD, pageZeroSelector WORD, numPages WORD, romId WORD'; DCL EvenMoreRomHeaderInfo LIT 'copyRight (45) BYTE, time (11) BYTE, partNumber (9) BYTE, partName (15) BYTE, bootMsgLength BYTE, bootMessage (30) BYTE, bootId BYTE, EvenEvenMoreRomHeaderInfo'; DCL EvenEvenMoreRomHeaderInfo LIT 'numRomsInPkg BYTE, romValue (4) WORD, unused (112) BYTE, patchCode BYTE, checksum BYTE'; DCL RomHeaderInfo LIT 'romHereFlag WORD, systemIndicator BYTE, systemRom BYTE, bootSector SELECTOR, romAddr BYTE, romSize BYTE, numWaitStates BYTE, MoreRomHeaderInfo, EvenMoreRomHeaderInfo'; DCL RomHeaderType LIT 'STRUCTURE (RomHeaderInfo)'; DCL BootInfoType LIT 'STRUCTURE (romSlot BYTE, bootSector SELECTOR)'; DCL AddressType LIT 'STRUCTURE (offset WORD, base WORD)'; $EJECT /* Static Variables */ /* External Variables */ DCL gChar BYTE EXTERNAL; DCL numSlots BYTE EXTERNAL; DCL curSlot BYTE EXTERNAL; DCL slotInfo (numRomSlots) SlotInfoType EXTERNAL; /* External procedures */ CpSetActiveSlot: PROCEDURE (slot) BYTE EXTERNAL; DCL slot BYTE; END; CpGetSlotAddress: PROCEDURE (slot) PTR EXTERNAL; DCL slot BYTE; END; ConLineOut: PROCEDURE (pBuf, len) EXTERNAL; DCL pBuf PTR; DCL len WORD; END; ConCharOut: PROCEDURE (char) EXTERNAL; DCL char BYTE; END; MakeCheckSum: PROCEDURE (pBuf, len) WORD EXTERNAL; DCL len WORD; DCL pBuf PTR; END; $EJECT /* CrLf */ CrLf: PROCEDURE REENTRANT; CALL ConLineOut (@(cr, lf), 2); END; /* SetThisSlot */ SetThisSlot: PROCEDURE (where, slot) REENTRANT; DCL where BYTE; DCL slot BYTE; DCL addrSel LIT '0dfe0h'; DCL pInfo PTR; DCL info BASED pInfo BYTE; pInfo = BUILDPTR (addrSel, where); info = slot; /* num wait states = 3 */ END; $EJECT /* CpInitRoms */ CpInitRoms: PROCEDURE CLEAN; DCL activateSel LIT '0dfeah'; DCL activateOff LIT '8'; DCL enableRoms LIT '1'; DCL disableRoms LIT '0'; DCL firstRom BOOLEAN; DCL curTempSlot BYTE; DCL slots BYTE; DCL waitStates BYTE; DCL i WORD; DCL j WORD; DCL k WORD; DCL pRom PTR; DCL pInfo PTR; DCL pThirdArea PTR; DCL info BASED pInfo BYTE; DCL rom BASED pRom RomHeaderType; /* Now enable the Roms */ pInfo = BUILDPTR (activateSel, activateOff); info = enableRoms; /* CALL SETB (0, @slotInfo, SIZE (slotInfo)); */ curTempSlot, curSlot = NULLBYTE; numSlots = numRomSlots; firstRom = TRUE; pRom = BUILDPTR (headerSel, 0); pThirdArea = BUILDPTR (thirdQtrAddr, 0); DO i = 0 to numRomSlots - 1; /* BEGIN */ CALL SetThisSlot (fourthQtr, i); IF rom.romHereFlag = romHere THEN DO; slotInfo(i).slotAddress = initialBank; slotinfo(i).romId = rom.romId; slotInfo(i).validRom = TRUE; slots = 0; waitStates = (3 - rom.numWaitStates) * 4; IF (rom.numRomsInPkg > 1) OR (rom.romSize <= 32) THEN DO; /* high bit of waitstatecode indicates if 32k rom or not */ waitStates = waitStates OR thirtyTwoKMask; END; slotInfo(i).waitStateCode = waitStates; IF rom.numRomsInPkg > 1 THEN DO; slots = SHL (i, 6); /* This code assumes numRomSlots <= 4 */ /* Look for all roms in this package */ DO j = 0 to 2; /* 2 = numRomSlots - 2 */ /* BEGIN */ IF rom.romValue(j) <> 0 THEN DO; k = 0; DO WHILE k <> numRomSlots; /* BEGIN */ CALL SetThisSlot (thirdQtr, k); IF MakeChecksum (pThirdArea, 32768) = rom.romValue(j) THEN DO; slots = slots OR (SHL (k, j * 2)); k = numRomSlots; END; ELSE DO; k = k + 1; IF k = numRomSlots THEN DO; slotInfo(i).validRom = FALSE; slots = NOT slots; /* make different last rom */ END; END; END; END; END; END; ELSE DO; DO j = 0 to 3; /* set all quarters to this slot */ /* BEGIN */ slots = slots OR (SHL (i, j * 2)); END; END; slotInfo(i).slots = slots; IF (firstRom) AND (slotInfo(i).validRom) THEN DO; firstRom = FALSE; curTempSlot = i; END; END; END; IF curTempSlot <> NULLBYTE THEN i = CpSetActiveSlot (curTempSlot); ELSE info = disableRoms; END; $EJECT /* RomBoot */ /* This routine will determine if the roms should be booted */ /* If so, it will return a pointer to the rom that has the */ /* boot code in it. */ RomBoot: PROCEDURE PTR CLEAN; DCL done BOOLEAN; DCL i BYTE; DCL numSystemRoms BYTE; DCL oldSlot BYTE; DCL theSystemRom BYTE; DCL sBootCode SELECTOR; DCL pHeader PTR; DCL systemInfo (maxSystems) BootInfoType; DCL romHeader BASED pHeader RomHeaderType; DCL wBootCode WORD AT (@sBootCode); /* Go to each rom and see if rom is bootable */ CALL SETB (NULLBYTE, @systemInfo, SIZE (systemInfo)); numSystemRoms = 0; pHeader = BUILDPTR (headerSel, 0); DO i = 0 to numRomSlots - 1; /* BEGIN */ oldSlot = CpSetActiveSlot (i); IF (romHeader.romHereFlag = romHere) AND (romHeader.systemRom = systemFlag) AND (oldSlot <> NULLBYTE) THEN DO; theSystemRom = romHeader.bootId - 1; IF systemInfo(theSystemRom).romSlot = NULLBYTE THEN DO; numSystemRoms = numSystemRoms + 1; systemInfo (theSystemRom).romSlot = i; systemInfo (theSystemRom).bootSector = romHeader.bootSector; END; END; END; IF numSystemRoms = 0 THEN RETURN (NULLPTR); /* IF more than 1 rom present, then ask which rom */ IF numSystemRoms > 1 THEN DO; done = FALSE; DO WHILE NOT done; /* BEGIN */ DO i = 0 to maxSystems - 1; /* BEGIN */ IF systemInfo(i).romSlot <> NULLBYTE THEN DO; oldSlot = CpSetActiveSlot (systemInfo(i).romSlot); CALL ConLineOut (@romHeader.bootMessage, romHeader.bootMsgLength); CALL CrLf; END; END; CALL ConLineOut (@('Type number to start system '), 28); /* Get character input */ gChar = NULLBYTE; DO WHILE gChar = NULLBYTE; /* BEGIN */ END; CALL ConCharOut (gChar); CALL CrLf; theSystemRom = gChar - '1'; IF (theSystemRom < maxSystems) AND (theSystemRom >= 0) AND (systemInfo(theSystemRom).romSlot <> NULLBYTE) THEN done = TRUE; ELSE CALL ConLineOut (@('Invalid input.', cr, lf), 16); END; END; /* Now that we have the rom, return a ptr to boot code */ oldSlot = CpSetActiveSlot (systemInfo(theSystemRom).romSlot); sBootCode = systemInfo(theSystemRom).bootSector; IF sBootCode < initialBank THEN wBootCode = wBootCode + initialBank; RETURN (BUILDPTR (sBootCode, 0)); END; END;