; ;================================================================================================== ; ROMWBW LOADER ;================================================================================================== ; ; THE LOADER CODE IS INVOKED IMMEDIATELY AFTER HBIOS COMPLETES SYSTEM INITIALIZATION. ; IT IS RESPONSIBLE FOR LOADING A RUNNABLE IMAGE (OPERATING SYSTEM, ETC.) INTO MEMORY ; AND TRANSFERRING CONTROL TO THAT IMAGE. THE IMAGE MAY COME FROM ROM (ROMBOOT), ; RAM (APPBOOT/IMGBOOT) OR FROM DISK (DISK BOOT). ; ; IN THE CASE OF A ROM BOOT, THE SELECTED EXECUTABLE IMAGE IS COPIED FROM ROM ; INTO A THE DEFAULT RAM AND THEN CONTROL IS PASSED TO THE STARTING ADDRESS ; IN RAM. IN THE CASE OF AN APPBOOT OR IMGBOOT STARTUP (SEE HBIOS.ASM) ; THE SOURCE OF THE IMAGE MAY BE RAM. ; ; IN THE CASE OF A DISK BOOT, SECTOR 2 (THE THIRD SECTOR) OF THE DISK DEVICE WILL ; BE READ -- THIS IS REFERRED TO AS THE BOOT INFO SECTOR AND IS EXPECTED TO HAVE ; THE FORMAT DEFINED AT BL_INFOSEC BELOW. THE LAST THREE WORDS OF DATA IN THIS ; SECTOR DETERMINE THE FINAL DESTINATION STARTING AND ENDING ADDRESS FOR THE DISK ; LOAD OPERATION AS WELL AS THE ENTRY POINT TO TRANSFER CONTROL TO. THE ACTUAL ; IMAGE TO BE LOADED *MUST* BE ON THE DISK IN THE SECTORS IMMEDIATELY FOLLOWING ; THE BOOT INFO SECTOR. THIS MEANS THE IMAGE TO BE LOADED MUST BEGIN IN SECTOR ; 3 (THE FOURTH SECTOR) AND OCCUPY SECTORS CONTIGUOUSLY AFTER THAT. ; ; THE CODE BELOW RELOCATES ITSELF AT STARTUP TO THE START OF COMMON RAM ; AT $8000. THIS MEANS THAT THE CODE, DATA, AND STACK WILL ALL STAY ; WITHIN $8000-$8FFF. SINCE ALL CODE IMAGES LIKE TO BE LOADED EITHER ; HIGH OR LOW (NEVER IN THE MIDDLE), THE $8000-$8FFF LOCATION TENDS ; TO AVOID THE PROBLEM WHERE THE CODE IS OVERLAID DURING THE LOADING ; OF THE DESIRED EXECUTABLE IMAGE. ; ; INCLUDE GENERIC STUFF ; #INCLUDE "std.asm" ; INT_IM1 .EQU $FF00 ; BID_CUR .EQU -1 ; SPECIAL BANK ID VALUE INDICATES CURRENT BANK ; .ORG 0 ; ;================================================================================================== ; NORMAL PAGE ZERO SETUP, RET/RETI/RETN AS APPROPRIATE ;================================================================================================== ; JP $100 ; RST 0: JUMP TO BOOT CODE .FILL (008H - $),0FFH #IF (PLATFORM == PLT_UNA) JP $FFFD ; RST 8: INVOKE UBIOS FUNCTION #ELSE JP HB_INVOKE ; RST 8: INVOKE HBIOS FUNCTION #ENDIF .FILL (010H - $),0FFH RET ; RST 10 .FILL (018H - $),0FFH RET ; RST 18 .FILL (020H - $),0FFH RET ; RST 20 .FILL (028H - $),0FFH RET ; RST 28 .FILL (030H - $),0FFH RET ; RST 30 .FILL (038H - $),0FFH #IF (PLATFORM == PLT_UNA) RETI ; RETURN W/ INTS DISABLED #ELSE #IF (INTMODE == 1) JP INT_IM1 ; JP TO INTERRUPT HANDLER IN HI MEM #ELSE RETI ; RETURN W/ INTS DISABLED #ENDIF #ENDIF .FILL (066H - $),0FFH RETN ; NMI ; .FILL (100H - $),0FFH ; PAD REMAINDER OF PAGE ZERO ; ;================================================================================================== ; STARTUP AND LOADER INITIALIZATION ;================================================================================================== ; DI ; NO INTERRUPTS FOR NOW ; ; RELOCATE TO START OF COMMON RAM AT $8000 LD HL,0 LD DE,$8000 LD BC,LDR_SIZ LDIR JP START ; .ORG $8000 + $ ; START: LD SP,BL_STACK ; SETUP STACK ; #IF (PLATFORM != PLT_UNA) CALL DELAY_INIT ; INIT DELAY FUNCTIONS #ENDIF ; #IF (PLATFORM == PLT_UNA) ; ; COPY UNA BIOS PAGE ZERO TO USER BANK, LEAVE USER BANK ACTIVE ; LD BC,$01FB ; UNA FUNC = SET BANK ; LD DE,BID_BIOS ; UBIOS_PAGE (SEE PAGES.INC) ; CALL $FFFD ; DO IT (RST 08 NOT YET INSTALLED) ; PUSH DE ; SAVE PREVIOUS BANK ;; ; LD HL,0 ; FROM ADDRESS 0 (PAGE ZERO) ; LD DE,$9000 ; USE $9000 AS BOUNCE BUFFER ; LD BC,256 ; ONE PAGE IS 256 BYTES ; LDIR ; DO IT ;; ; LD BC,$01FB ; UNA FUNC = SET BANK ; ;POP DE ; RECOVER OPERATING BANK ; LD DE,BID_USR ; TO USER BANK ; CALL $FFFD ; DO IT (RST 08 NOT YET INSTALLED) ;; ; LD HL,$9000 ; USE $9000 AS BOUNCE BUFFER ; LD DE,0 ; TO PAGE ZERO OF OPERATING BANK ; LD BC,256 ; ONE PAGE IS 256 BYTES ; LDIR ; DO IT ;; ;; ; INSTALL UNA INVOCATION VECTOR FOR RST 08 ;; ; *** IS THIS REDUNDANT? *** ;; LD A,$C3 ; JP INSTRUCTION ;; LD (8),A ; STORE AT 0x0008 ;; LD HL,($FFFE) ; UNA ENTRY VECTOR ;; LD (9),HL ; STORE AT 0x0009 ;; ; LD BC,$01FB ; UNA FUNC = SET BANK ; POP DE ; RECOVER OPERATING BANK ; CALL $FFFD ; DO IT (RST 08 NOT YET INSTALLED) #ELSE ; PREP THE USER BANK (SETUP PAGE ZERO) LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY LD D,BID_USR ; D = DEST BANK = USER BANK LD E,BID_BIOS ; E = SRC BANK = BIOS BANK LD HL,256 ; HL = COPY LEN = 1 PAGE = 256 BYTES RST 08 ; DO IT LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY LD HL,0 ; COPY FROM BIOS ADDRESS 0 LD DE,0 ; TO USER ADDRESS 0 RST 08 ; DO IT #ENDIF EI ; ;================================================================================================== ; BOOT LOADER MENU DISPLAY ;================================================================================================== ; LD DE,STR_BANNER ; DISPLAY BOOT BANNER ; MENU: CALL WRITESTR ; DISPLAY MESSAGE OR ERROR CALL NEWLINE2 ; #IF (DSKYENABLE) ; DISPLAY DSKY BOOT MESSAGE LD HL,BOOT ; POINT TO BOOT MESSAGE CALL DSKY_SHOWSEG ; DISPLAY MESSAGE #ENDIF ; #IF (BOOTTYPE == BT_AUTO) ; INITIALIZE BOOT TIMEOUT DOWNCOUNTER LD BC,100 * BOOT_TIMEOUT LD (BL_TIMEOUT),BC #ENDIF ; ; DISPLAY ROM MENU ENTRIES PRTS("ROM: $") LD B,MENU_N ; B IS LOOP COUNTER, # OF ENTRIES LD HL,MENU_S ; HL POINTS TO START OF ENTRY MENU1: ; PROCESS A TABLE ENTRY PUSH HL ; COPY HL TO POP DE ; ... DE FOR USE AS CHAR PTR MENU2: LD A,(DE) ; GET NEXT CHAR INC DE ; BUMP CHAR PTR FOR FUTURE CP '$' ; TERMINATOR? JR Z,MENU4 ; IF YES, DONE WITH THIS ENTRY CP '~' ; HOT KEY PREFIX? JR NZ,MENU3 ; IF NOT, JUST SKIP AHEAD CALL PC_LPAREN ; L PAREN BEFORE HOT KEY LD A,(DE) ; GET THE ACTUAL HOT KEY INC DE ; BUMP CHAR PTR FOR FUTURE CALL COUT ; OUTPUT HOT KEY LD A,')' ; R PAREN WILL PRINT BELOW MENU3: CALL COUT ; OUTPUT CHAR JR MENU2 ; AND LOOP MENU4: ; END OF AN ENTRY CALL PC_SPACE ; PRINT SEPARATOR LD A,MENU_V ; LOAD ENTRY LENGTH CALL ADDHLA ; BUMP HL TO NEXT ENTRY DJNZ MENU1 ; LOOP UNTIL COUNT EXPIRES ; ; DISPLAY AVAILABLE DISK DRIVES PRTS("\r\nDisk: $") CALL PRTALL ; PRINT DRIVE LIST ; LD DE,STR_BOOTSEL CALL WRITESTR ; ;================================================================================================== ; BOOT SELECTION PROCESSING ;================================================================================================== ; SEL: ; HANDLE SERIAL CONSOLE INPUT CALL CST ; CHECK CONSOLE INPUT OR A ; ZERO? JR Z,SEL1 ; IF NOT, CONTINUE CALL CINUC ; GET THE KEY CALL COUT ; ECHO KEY JR MATS ; AND HANDLE IT ; SEL1: #IF (DSKYENABLE) ; HANDLE DSKY KEY INPUT CALL DSKY_STAT ; CHECK DSKY INPUT OR A ; TEST FOR ZERO JR Z,SEL2 ; IF ZERO, NO KEY PRESSED CALL DSKY_GETKEY ; GET PENDING KEY PRESS JR MATK ; AND HANDLE IT #ENDIF ; SEL2: #IF (BOOTTYPE == BT_AUTO) ; CHECK FOR AUTOBOOT TIMEOUT LD DE,625 ; DELAY FOR 10MS TO MAKE TIMEOUT CALC EASY CALL VDELAY ; 16US * 625 = 10MS LD BC,(BL_TIMEOUT) ; CHECK/INCREMENT TIMEOUT DEC BC LD (BL_TIMEOUT),BC LD A,B OR C JP NZ,SEL3 ; LD A,BOOT_DEFAULT ; TIMEOUT EXPIRED, JR MATS ; PERFORM DEFAULT BOOT ACTION #ENDIF ; SEL3: ; NO USER SELECTION YET JR SEL ; LOOP ; ;================================================================================================== ; ROM MENU TABLE MATCHING ;================================================================================================== ; MATS: ; MATCH SERIAL INPUT TO MENU CP 'R' JP Z,REBOOT LD B,MENU_N LD DE,MENU_S+10-MENU_V LD HL,MENU_V MATS1: EX DE,HL ADD HL,DE CP (HL) EX DE,HL JR Z,MATS2 DJNZ MATS1 ; FALL THRU IF IT DOES NOT MATCH ROM MENU SUB '0' ; CONVERT ASCII TO BINARY JR MATD ; AND TRY DISK BOOT MATS2: INC DE ; SKIP MENU SEL CHAR INC DE ; SKIP DSKY SEL CHAR JP GOROM ; BOOT FROM ROM ; #IF (DSKYENABLE) MATK: ; MATCH DSKY INPUT TO MENU CP KY_BO JP Z,REBOOT LD B,MENU_N LD DE,MENU_S+11-MENU_V LD HL,MENU_V MATK1: EX DE,HL ADD HL,DE CP (HL) EX DE,HL JR Z,MATK2 DJNZ MATK1 ; FALL THRU IF IT DOES NOT MATCH DSKY MENU JR MATD ; TRY DISK BOOT MATK2: INC DE ; SKIP DSKY SEL CHAR JP GOROM ; BOOT FROM ROM #ENDIF ; MATD: ; CHECK FOR DISK BOOT REQUEST CP 10 ; 0-9, DISK DEVICE JR NC,MATX ; NOT VALID, HANDLE IT BELOW JP GOBOOTDISK ; BOOT FROM DISK ; MATX: ; SET ERROR STRING AND LOOP LD DE,STR_INVALID ; INVALID SEL MSG JP MENU ; RESTART MENU LOOP ; ;================================================================================================== ; ROM MENU TABLE ;================================================================================================== ; #DEFINE MENU_L(M1,M2,M3,M4,M5,M6,M7,M8,M9,M10) \ #DEFCONT \ .DB M1 #DEFCONT \ .DB M2 #IF (DSKYENABLE) #DEFCONT \ .DB M3 #ELSE #DEFCONT \ .DB $FF #ENDIF #DEFCONT \ .DW M4 #DEFCONT \ .DW M5 #DEFCONT \ .DW M6 #DEFCONT \ .DW M7 #DEFCONT \ .DB M8 #DEFCONT \ .DB M9 #DEFCONT \ .DB M10 ; ; NOTE: THE FORMATTING OF THE FOLLOWING IS CRITICAL. TASM DOES NOT PASS MACRO ARGUMENTS WELL. ; ENSURE STD.ASM HOLDS THE DEFINITIONS FOR *_LOC, *_SIZ *_END AND ANY CODE GENERATED WHICH DOES NOT ; INCLUDE STD.ASM IS SYNCED. ; ; NOTE: THE LOADABLE ROM IMAGES ARE PLACED IN ROM BANKS BID_IMG0 AND BID_IMG1. HOWEVER, ROMWBW ; SUPPORTS A MECHANISM TO LOAD A COMPLETE NEW SYSTEM DYNAMICALLY AS A RUNNABLE APPLICATION ; (SEE APPBOOT AND IMGBOOT IN HBIOS.ASM). IN THIS CASE, THE CONTENTS OF BID_IMG0 WILL ; PRE-LOADED INTO THE CURRENTLY EXECUTING RAM BANK THEREBY ALLOWING THOSE IMAGES TO BE ; DYNAMICALLY LOADED AS WELL. TO SUPPORT THIS CONCEPT, A PSEUDO-BANK CALLED BID_CUR ; IS USED TO SPECIFY THE IMAGES NORMALLY FOUND IN BID_IMG0. IN GOROM, THIS SPECIAL ; VALUE WILL CAUSE THE ASSOCIATED IMAGE TO BE LOADED FROM THE CURRENTLY EXECUTING BANK ; WHICH WILL BE CORRECT REGARDLESS OF THE LOAD MODE. IMAGES IN OTHER BANKS (BID_IMG1) ; WILL ALWAYS BE LOADED DIRECTLY FROM ROM. ; ; name menu dsky dest-exec source dest-addr img-size source-bank dest desc ; DB DB DB DW DW DW DW DB DB DB MENU_S: MENU_L("~Monitor$ ", "M", KY_CL, MON_SERIAL, 1000h, MON_LOC, MON_SIZ, BID_CUR, BID_USR, "Monitor$ ") MENU_1: MENU_L("~CP/M$ ", "C", KY_BK, CPM_ENT, 2000h, CPM_LOC, CPM_SIZ, BID_CUR, BID_USR, "CP/M 80 v2.2$") MENU_L("~Z-System$", "Z", KY_FW, CPM_ENT, 5000h, CPM_LOC, CPM_SIZ, BID_CUR, BID_USR, "ZSDOS v1.1$ ") #IF (PLATFORM != PLT_UNA) MENU_L("~Forth$ ", "F", KY_EX, FTH_LOC, 0000h, FTH_LOC, FTH_SIZ, BID_IMG1, BID_USR, "Camel Forth$ ") MENU_L("~BASIC$ ", "B", KY_DE, BAS_LOC, 1700h, BAS_LOC, BAS_SIZ, BID_IMG1, BID_USR, "Nascom BASIC$") MENU_L("~T-BASIC$ ", "T", KY_EN, TBC_LOC, 3700h, TBC_LOC, TBC_SIZ, BID_IMG1, BID_USR, "Tasty BASIC$ ") #ENDIF #IF (DSKYENABLE) MENU_L("~DSKY$ ", "D", KY_GO, MON_DSKY, 1000h, MON_LOC, MON_SIZ, BID_CUR, BID_USR, "DSKY Monitor$") #ENDIF MENU_L("$ ", "E", $FF, EGG_LOC, 0E00h, EGG_LOC, EGG_SIZ, BID_CUR, BID_USR, "Easter Egg$ ") ; MENU_E .EQU $ ; END OF TABLE MENU_V .EQU MENU_1 - MENU_S ; LENGTH OF EACH MENU RECORD MENU_N .EQU ((MENU_E - MENU_S) / MENU_V) ; NUMBER OF MENU ITEMS ; ;================================================================================================== ; SYSTEM REBOOT HANDLER ;================================================================================================== ; REBOOT: LD DE,STR_REBOOT ; POINT TO MESSAGE CALL WRITESTR ; PRINT IT LD A,BID_BOOT ; BOOT BANK LD HL,0 ; ADDRESS ZERO CALL HB_BNKCALL ; DOES NOT RETURN ; ;================================================================================================== ; ROM IMAGE LOAD HANDLER ;================================================================================================== ; ; AT ENTRY, DE POINTS TO THE EXEC ADR FIELD OF THE ACTIVE ROM ; TABLE ENTRY ; ; ROM IMAGES MUST NOT OVERLAY THE SPACE OCCUPIED BY THE LOADER WHICH ; IS $8000-$8FFF. ; GOROM: PUSH DE ; SAVE ROM TABLE ENTRY EXEC ADR PTR LD DE,STR_BOOTROM ; ROM LOADING MSG PREFIX CALL WRITESTR ; PRINT IT POP HL ; EXEC ADR TO HL PUSH HL ; AND RESAVE IT LD A,10 ; OFFSET TO IMAGE DESC CALL ADDHLA ; APPLY IT EX DE,HL ; MOVE TO DE, ORIG VALUE TO HL CALL WRITESTR ; AND PRINT IT PRTS("...$") ; ADD SOME DOTS POP HL ; RESTORE EXEC ADR TO HL ; LD B,5 ; PUT NEXT FIVE WORDS ON STACK GOROM1: LD E,(HL) ; (1) EXEC ADR INC HL ; (2) SOURCE ADR LD D,(HL) ; (3) DEST ADR INC HL ; (4) IMAGE SIZE PUSH DE ; (5) SRC/DEST BANKS DJNZ GOROM1 ; LOOP TILL DONE ; #IF (PLATFORM == PLT_UNA) ; ; NOTE: UNA HAS NO INTERBANK MEMORY COPY, SO WE CAN ONLY LOAD ; IMAGES FROM THE CURRENT BANK. A SIMPLE LDIR IS USED TO ; RELOCATE THE IMAGES ; ; COPY IMAGE TO IT'S RUNNING LOCATION POP HL ; POP AND DISCARD BANKS POP BC ; GET IMAGE SIZE TO BC POP DE ; GET DESTINATION ADR TO DE POP HL ; GET SOURCE ADR TO HL LDIR ; MOVE IT ; ; RECORD BOOT INFO LD BC,$00FB ; GET LOWER PAGE ID RST 08 ; DE := LOWER PAGE ID == BOOT ROM PAGE LD L,1 ; BOOT DISK UNIT IS ROM (UNIT ID = 1) LD BC,$01FC ; UNA FUNC: SET BOOTSTRAP HISTORY RST 08 ; CALL UNA ; ; LAUNCH IMAGE W/ USER BANK ACTIVE ; NOTE: UNA EXEC CHAIN CALL USES ADDRESS ON TOS CALL NEWLINE2 LD DE,BID_USR ; TARGET BANK ID PUSH DE ; ... ON STACK DI ; ENTER WITH INTS DISABLED JP $FFF7 ; UNA INTER-PAGE EXEC CHAIN #ELSE ; ; NOTE: CHECK FOR SPECIAL CASE WHERE SOURCE BANK IS BID_CUR. IN THIS CASE ; WE COPY THE IMAGE FROM THE BANK THAT WE ARE CURRENTLY RUNNING IN. THIS ; IS DONE TO SUPPORT THE APPBOOT AND IMGBOOT MODES AS DEFINED IN HBIOS. ; IN THE CASE OF THESE MODES IT IS INTENDED THAT THE IMAGES BE LOADED ; FROM THE CURRENT RAM BANK AND NOT FROM THEIR NORMAL ROM LOCATIONS. ; ; COPY IMAGE TO IT'S RUNNING LOCATION POP DE ; GET BANKS (E=SRC, D=DEST) POP HL ; GET IMAGE SIZE LD A,E ; SOURCE BANK TO A CP BID_CUR ; SPECIAL CASE, BID_CUR? JR NZ,GOROM2 ; IF NOT, GO RIGHT TO COPY LD A,(HB_CURBNK) ; GET CURRENT BANK LD E,A ; AND SUBSTITUE THE VALUE GOROM2: LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY RST 08 ; DO IT POP DE ; GET DEST ADR POP HL ; GER SOURCE ADR LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY RST 08 ; DO IT ; ; RECORD BOOT INFO LD A,(HB_CURBNK) ; GET CURRENT BANK ID FROM PROXY DATA LD B,BF_SYSSET ; HB FUNC: SET HBIOS PARAMETER LD C,BF_SYSSET_BOOTINFO ; HB SUBFUNC: SET BOOT INFO LD L,A ; ... AND SAVE AS BOOT BANK LD DE,$0100 ; BOOT VOLUME (UNIT, SLICE) RST 08 ; ; LAUNCH IMAGE W/ USER BANK ACTIVE CALL NEWLINE2 LD A,BID_USR ; ACTIVATE USER BANK POP HL ; RECOVER EXEC ADDRESS DI ; ENTER WITH INTS DISABLED CALL HB_BNKCALL ; AND GO HALT ; WE SHOULD NEVER RETURN!!! #ENDIF ; ;================================================================================================== ; DISK BOOT HANDLER ;================================================================================================== ; GOBOOTDISK: LD (BL_BOOTID),A LD DE,STR_BOOTDISK CALL WRITESTR CALL PRTHEXBYTE PRTS("...$") ; LD DE,STR_BOOTDISK1 ; DISK BOOT MESSAGE CALL WRITESTR ; PRINT IT ; #IF (PLATFORM == PLT_UNA) LD A,(BL_BOOTID) ; GET BOOT DEVICE ID LD B,A ; MOVE TO B ; ; LOAD SECTOR 2 (BOOT INFO) LD C,$41 ; UNA FUNC: SET LBA LD DE,0 ; HI WORD OF LBA IS ALWAYS ZERO LD HL,2 ; LOAD STARTING INFO SECTOR 2 RST 08 ; SET LBA JP NZ,DB_ERR ; HANDLE ERROR ; LD C,$42 ; UNA FUNC: READ SECTORS LD DE,BL_INFOSEC ; DEST OF CPM IMAGE LD L,1 ; SECTORS TO READ RST 08 ; DO READ JP NZ,DB_ERR ; HANDLE ERROR #ELSE ; CHECK FOR VALID DRIVE LETTER LD A,(BL_BOOTID) ; BOOT DEVICE TO A PUSH AF ; SAVE BOOT DEVICE LD B,BF_SYSGET LD C,BF_SYSGET_DIOCNT RST 08 ; E := DISK UNIT COUNT POP AF ; RESTORE BOOT DEVICE CP E ; CHECK MAX (INDEX - COUNT) JP NC,DB_NODISK ; HANDLE INVALID SELECTION ; ; SET THE BOOT UNIT AND SLICE LD A,(BL_BOOTID) ; GET BOOTID LD (BL_DEVICE),A ; STORE IT XOR A ; LU ALWAYS ZERO LD (BL_LU),A ; STORE IT ; ; SENSE MEDIA LD A,(BL_DEVICE) ; GET DEVICE/UNIT LD C,A ; STORE IN C LD B,BF_DIOMEDIA ; DRIVER FUNCTION = DISK MEDIA LD E,1 ; ENABLE MEDIA CHECK/DISCOVERY RST 08 ; CALL HBIOS JP NZ,DB_ERR ; HANDLE ERROR ; ; SEEK TO SECTOR 2 OF LU LD A,(BL_LU) ; GET LU SPECIFIED LD E,A ; LU INDEX LD H,65 ; 65 TRACKS PER LU CALL MULT8 ; HL := H * E LD DE,$02 ; HEAD 0, SECTOR 2 LD B,BF_DIOSEEK ; SETUP FOR NEW SEEK CALL LD A,(BL_DEVICE) ; GET BOOT DISK UNIT LD C,A ; PUT IN C RST 08 ; DO IT JP NZ,DB_ERR ; HANDLE ERROR ; ; READ LD B,BF_DIOREAD ; FUNCTION IN B LD A,(BL_DEVICE) ; GET BOOT DISK UNIT LD C,A ; PUT IN C LD HL,BL_INFOSEC ; READ INTO INFO SEC BUFFER LD DE,1 ; TRANSFER ONE SECTOR RST 08 ; DO IT JP NZ,DB_ERR ; HANDLE ERROR ; #ENDIF ; ; CHECK SIGNATURE LD DE,(BB_SIG) ; GET THE SIGNATURE LD A,$A5 ; FIRST BYTE SHOULD BE $A5 CP D ; COMPARE JP NZ,DB_NOBOOT ; ERROR IF NOT EQUAL LD A,$5A ; SECOND BYTE SHOULD BE $5A CP E ; COMPARE JP NZ,DB_NOBOOT ; ERROR IS NOT EQUAL ; ; PRINT CPMLOC VALUE PRTS("\r\nLoc=$") LD BC,(BB_CPMLOC) CALL PRTHEXWORD ; ; PRINT CPMEND VALUE PRTS(" End=$") LD BC,(BB_CPMEND) CALL PRTHEXWORD ; ; PRINT CPMENT VALUE PRTS(" Ent=$") LD BC,(BB_CPMENT) CALL PRTHEXWORD ; ; PRINT DISK LABEL PRTS(" Label=$") LD DE,BB_LABEL ; if it is there, then a printable LD A,(BB_TERM) ; Display Disk Label if Present CP '$' ; (dwg 2/7/2012) CALL Z,WRITESTR ; label is there as well even if spaces. ; LD DE,STR_LOADING ; LOADING MESSAGE CALL WRITESTR ; PRINT IT ; ; COMPUTE NUMBER OF SECTORS TO LOAD LD HL,(BB_CPMEND) ; HL := END LD DE,(BB_CPMLOC) ; DE := START OR A ; CLEAR CARRY SBC HL,DE ; HL := LENGTH TO LOAD LD A,H ; DETERMINE 512 BYTE SECTOR COUNT RRCA ; ... BY DIVIDING MSB BY TWO LD (BL_COUNT),A ; ... AND SAVE IT ; #IF (PLATFORM == PLT_UNA) ; ; READ OS IMAGE INTO MEMORY LD C,$42 ; UNA FUNC: READ SECTORS LD A,(BL_BOOTID) ; GET BOOT DEVICE ID LD B,A ; MOVE TO B LD DE,(BB_CPMLOC) ; DEST OF CPM IMAGE LD A,(BL_COUNT) ; GET SECTORS TO READ LD L,A ; SECTORS TO READ RST 08 ; DO READ JP NZ,DB_ERR ; HANDLE ERROR ; ; PASS BOOT DEVICE/UNIT/LU TO CBIOS COLD BOOT LD DE,-1 ; BOOT ROM PAGE, -1 FOR N/A LD A,(BL_BOOTID) ; GET BOOT DISK UNIT ID LD L,A ; PUT IN L LD BC,$01FC ; UNA FUNC: SET BOOTSTRAP HISTORY RST 08 ; CALL UNA JP NZ,DB_ERR ; HANDLE ERROR ; ; JUMP TO COLD BOOT ENTRY LD HL,(BB_CPMENT) ; GET THE ENTRY POINT PUSH HL ; PUT ON STACK FOR UNA CHAIN FUNC LD DE,BID_USR ; TARGET BANK ID IS USER BANK PUSH DE ; PUT ON STACK FOR UNA CHAIN FUNC DI ; ENTER WITH INTS DISABLED JP $FFF7 ; UNA INTER-PAGE EXEC CHAIN ; #ELSE ; ; READ OS IMAGE INTO MEMORY LD B,BF_DIOREAD ; FUNCTION IN B LD A,(BL_DEVICE) ; GET BOOT DISK UNIT LD C,A ; PUT IN C LD HL,(BB_CPMLOC) ; LOAD ADDRESS LD D,0 LD A,(BL_COUNT) ; GET SECTORS TO READ LD E,A ; NUMBER OF SECTORS TO LOAD RST 08 JP NZ,DB_ERR ; HANDLE ERRORS ; ; PASS BOOT DEVICE/UNIT/LU TO CBIOS COLD BOOT LD B,BF_SYSSET ; HB FUNC: SET HBIOS PARAMETER LD C,BF_SYSSET_BOOTINFO ; HB SUBFUNC: SET BOOT INFO LD A,(HB_CURBNK) ; GET CURRENT BANK ID FROM PROXY DATA LD L,A ; ... AND SAVE AS BOOT BANK LD A,(BL_DEVICE) ; LOAD BOOT DEVICE/UNIT LD D,A ; SAVE IN D LD A,(BL_LU) ; LOAD BOOT LU LD E,A ; SAVE IN E RST 08 JP NZ,DB_ERR ; HANDLE ERRORS ; ; JUMP TO COLD BOOT ENTRY LD A,BID_USR ; ACTIVATE USER BANK LD HL,(BB_CPMENT) ; OS ENTRY ADDRESS DI ; ENTER WITH INTS DISABLED CALL HB_BNKCALL ; AND GO HALT ; WE SHOULD NEVER RETURN!!! ; #ENDIF ; DB_NODISK: ; SELDSK DID NOT LIKE DRIVE SELECTION LD DE,STR_NODISK JP MENU ; DB_NOBOOT: ; DISK IS NOT BOOTABLE LD DE,STR_NOBOOT JP MENU ; DB_ERR: ; I/O ERROR DURING BOOT ATTEMPT LD DE,STR_BOOTERR JP MENU ; #IF (PLATFORM == PLT_UNA) ; ; PRINT LIST OF ALL DRIVES UNDER UNA ; PRTALL: LD B,0 ; START WITH UNIT 0 ; PRTALL1: ; LOOP THRU ALL UNITS AVAILABLE LD C,$48 ; UNA FUNC: GET DISK TYPE LD L,0 ; PRESET UNIT COUNT TO ZERO RST 08 ; CALL UNA, B IS ASSUMED TO BE UNTOUCHED!!! LD A,L ; UNIT COUNT TO A OR A ; PAST END? RET Z ; WE ARE DONE PUSH BC ; SAVE UNIT CALL PRTDRV ; PROCESS THE UNIT POP BC ; RESTORE UNIT INC B ; NEXT UNIT JR PRTALL1 ; LOOP ; ; PRINT THE UNA UNIT INFO ; ON INPUT B HAS UNIT ; PRTDRV: PUSH BC ; SAVE UNIT PUSH DE ; SAVE DISK TYPE LD A,'(' ; NEWLINE AND SPACING CALL COUT ; PRINT IT LD A,B ; DRIVE LETTER TO A ADD A,'0' ; MAKE IT DISPLAY NUMERIC CALL COUT ; PRINT IT LD A,')' ; DRIVE LETTER COLON CALL COUT ; PRINT IT POP DE ; RECOVER DISK TYPE LD A,D ; DISK TYPE TO A CP $40 ; RAM/ROM? JR Z,PRTDRV1 ; HANDLE RAM/ROM LD DE,DEVIDE ; ASSUME IDE CP $41 ; IDE? JR Z,PRTDRV2 ; PRINT IT LD DE,DEVPPIDE ; ASSUME PPIDE CP $42 ; PPIDE? JR Z,PRTDRV2 ; PRINT IT LD DE,DEVSD ; ASSUME SD CP $43 ; SD? JR Z,PRTDRV2 ; PRINT IT LD DE,DEVDSD ; ASSUME DSD CP $44 ; DSD? JR Z,PRTDRV2 ; PRINT IT LD DE,DEVUNK ; OTHERWISE UNKNOWN JR PRTDRV2 ; PRTDRV1: ; HANDLE RAM/ROM LD C,$45 ; UNA FUNC: GET DISK INFO LD DE,BL_INFOSEC ; 512 BYTE BUFFER RST 08 ; CALL UNA BIT 7,B ; TEST RAM DRIVE BIT LD DE,DEVROM ; ASSUME ROM JR Z,PRTDRV2 ; IF SO, PRINT IT LD DE,DEVRAM ; OTHERWISE RAM JR PRTDRV2 ; PRINT IT ; PRTDRV2: ; PRINT DEVICE POP BC ; RECOVER UNIT CALL WRITESTR ; PRINT DEVICE NAME LD A,B ; UNIT TO A ADD A,'0' ; MAKE IT PRINTABLE NUMERIC CALL COUT ; PRINT IT LD A,',' ; DEVICE NAME SEPARATOR CALL COUT ; PRINT IT RET ; DONE ; DEVRAM .DB "RAM$" DEVROM .DB "ROM$" DEVIDE .DB "IDE$" DEVPPIDE .DB "PPIDE$" DEVSD .DB "SD$" DEVDSD .DB "DSD$" DEVUNK .DB "UNK$" ; #ELSE ; ; PRINT LIST OF ALL DRIVES ; PRTALL: ; LD B,BF_SYSGET LD C,BF_SYSGET_DIOCNT RST 08 ; E := DISK UNIT COUNT LD B,E ; COUNT TO B LD A,B ; COUNT TO A OR A ; SET FLAGS RET Z ; BAIL OUT IF ZERO LD C,0 ; INIT DEVICE INDEX ; PRTALL1: LD A,'(' ; FORMATTING CALL COUT ; PRINT IT LD A,C ; INDEX TO A ADD A,'0' ; MAKE NUMERIC CHAR CALL COUT ; PRINT IT LD A,')' ; FORMATTING CALL COUT ; PRINT IT PUSH BC ; SAVE LOOP CONTROL LD B,BF_DIODEVICE ; HBIOS FUNC: REPORT DEVICE INFO RST 08 ; CALL HBIOS CALL PRTDRV ; PRINT IT POP BC ; RESTORE LOOP CONTROL INC C ; BUMP INDEX DJNZ PRTALL1 ; LOOP AS NEEDED RET ; DONE ; ; PRINT THE DRIVER DEVICE/UNIT INFO ; ON INPUT D HAS DRIVER ID, E HAS DRIVER MODE/UNIT ; DESTROY NO REGISTERS OTHER THAN A ; PRTDRV: PUSH DE ; PRESERVE DE PUSH HL ; PRESERVE HL LD A,D ; LOAD DEVICE/UNIT RRCA ; ROTATE DEVICE RRCA ; ... BITS RRCA ; ... INTO RRCA ; ... LOWEST 4 BITS AND $0F ; ISOLATE DEVICE BITS ADD A,A ; MULTIPLE BY TWO FOR WORD TABLE LD HL,DEVTBL ; POINT TO START OF DEVICE NAME TABLE CALL ADDHLA ; ADD A TO HL TO POINT TO TABLE ENTRY LD A,(HL) ; DEREFERENCE HL TO LOC OF DEVICE NAME STRING INC HL ; ... LD D,(HL) ; ... LD E,A ; ... CALL WRITESTR ; PRINT THE DEVICE NMEMONIC POP HL ; RECOVER HL POP DE ; RECOVER DE LD A,E ; LOAD DRIVER MODE/UNIT AND $0F ; ISOLATE UNIT CALL PRTDECB ; PRINT IT CALL PC_SPACE ; FORMATTING ;LD A,E ; LOAD LU ;CALL PRTDECB ; PRINT IT RET ; DEVTBL: ; DEVICE TABLE .DW DEV00, DEV01, DEV02, DEV03 .DW DEV04, DEV05, DEV06, DEV07 .DW DEV08, DEV09, DEV10, DEV11 .DW DEV12, DEV13, DEV14, DEV15 ; DEVUNK .DB "???$" DEV00 .DB "MD$" DEV01 .DB "FD$" DEV02 .DB "RAMF$" DEV03 .DB "IDE$" DEV04 .DB "ATAPI$" DEV05 .DB "PPIDE$" DEV06 .DB "SD$" DEV07 .DB "PRPSD$" DEV08 .DB "PPPSD$" DEV09 .DB "HDSK$" DEV10 .EQU DEVUNK DEV11 .EQU DEVUNK DEV12 .EQU DEVUNK DEV13 .EQU DEVUNK DEV14 .EQU DEVUNK DEV15 .EQU DEVUNK ; #ENDIF ; ;================================================================================================== ; STRINGS ;================================================================================================== ; STR_BANNER .DB "\r\n\r\n", PLATFORM_NAME, " Boot Loader$" STR_BOOTSEL .DB "\r\n\r\nBoot? $" STR_BOOTDISK .DB "\r\n\r\nBooting Disk Unit $" STR_BOOTROM .DB "\r\n\r\nLoading $" STR_REBOOT .DB "\r\n\r\nRestarting System...$" STR_INVALID .DB "\r\n\r\n*** Invalid Selection ***$" STR_NODISK .DB "\r\n\r\nNo disk!$" STR_NOBOOT .DB "\r\n\r\nDisk not bootable!$" STR_BOOTERR .DB "\r\n\r\nBoot failure!$" STR_BOOTDISK1 .DB "\r\n\r\nReading disk information...$" STR_LOADING .DB "\r\n\r\nLoading...$" ; #IF (DSKYENABLE) ; b o o t . . BOOT .DB $9F,$9D,$9D,$94,$80,$80,$00,$00 #ENDIF ; ;================================================================================================== ; INCLUDES ;================================================================================================== ; #DEFINE USEDELAY #INCLUDE "util.asm" ; #IF (DSKYENABLE) #DEFINE DSKY_KBD #INCLUDE "dsky.asm" #ENDIF ; ;================================================================================================== ; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED) ;================================================================================================== ; #IF (PLATFORM != PLT_UNA) ; ; OUTPUT CHARACTER FROM A ; COUT: ; SAVE ALL INCOMING REGISTERS PUSH AF PUSH BC PUSH DE PUSH HL ; ; OUTPUT CHARACTER TO CONSOLE VIA HBIOS LD E,A ; OUTPUT CHAR TO E LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR RST 08 ; HBIOS OUTPUTS CHARACTDR ; ; RESTORE ALL REGISTERS POP HL POP DE POP BC POP AF RET ; ; INPUT CHARACTER TO A ; CIN: ; SAVE INCOMING REGISTERS (AF IS OUTPUT) PUSH BC PUSH DE PUSH HL ; ; INPUT CHARACTER FROM CONSOLE VIA HBIOS LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR RST 08 ; HBIOS READS CHARACTDR LD A,E ; MOVE CHARACTER TO A FOR RETURN ; ; RESTORE REGISTERS (AF IS OUTPUT) POP HL POP DE POP BC RET ; ; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING) ; CST: ; SAVE INCOMING REGISTERS (AF IS OUTPUT) PUSH BC PUSH DE PUSH HL ; ; GET CONSOLE INPUT STATUS VIA HBIOS LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS RST 08 ; HBIOS RETURNS STATUS IN A ; ; RESTORE REGISTERS (AF IS OUTPUT) POP HL POP DE POP BC RET ; #ENDIF ; #IF (PLATFORM == PLT_UNA) ; ; OUTPUT CHARACTER FROM A ; COUT: ; SAVE ALL INCOMING REGISTERS PUSH AF PUSH BC PUSH DE PUSH HL ; ; OUTPUT CHARACTER TO CONSOLE VIA UBIOS LD E,A LD BC,$12 RST 08 ; ; RESTORE ALL REGISTERS POP HL POP DE POP BC POP AF RET ; ; INPUT CHARACTER TO A ; CIN: ; SAVE INCOMING REGISTERS (AF IS OUTPUT) PUSH BC PUSH DE PUSH HL ; ; INPUT CHARACTER FROM CONSOLE VIA UBIOS LD BC,$11 RST 08 LD A,E ; ; RESTORE REGISTERS (AF IS OUTPUT) POP HL POP DE POP BC RET ; ; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING) ; CST: ; SAVE INCOMING REGISTERS (AF IS OUTPUT) PUSH BC PUSH DE PUSH HL ; ; GET CONSOLE INPUT STATUS VIA UBIOS LD BC,$13 RST 08 LD A,E ; ; RESTORE REGISTERS (AF IS OUTPUT) POP HL POP DE POP BC RET ; #ENDIF ; ; READ A CONSOLE CHARACTER AND CONVERT TO UPPER CASE ; CINUC: CALL CIN AND 7FH ; STRIP HI BIT CP 'A' ; KEEP NUMBERS, CONTROLS RET C ; AND UPPER CASE CP 7BH ; SEE IF NOT LOWER CASE RET NC AND 5FH ; MAKE UPPER CASE RET ; ;================================================================================================== ; FILL REMAINDER OF BANK ;================================================================================================== ; SLACK: .EQU ($8000 + LDR_SIZ - $) .FILL SLACK ; .ECHO "LOADER space remaining: " .ECHO SLACK .ECHO " bytes.\n" ; ;================================================================================================== ; WORKING DATA STORAGE ;================================================================================================== .ORG $8000 + LDR_SIZ ; .DS 64 ; 32 LEVEL STACK BL_STACK .EQU $ ; ... TOP IS HERE ; BL_COUNT .DS 1 ; LOAD COUNTER BL_TIMEOUT .DS 2 ; AUTOBOOT TIMEOUT COUNTDOWN COUNTER BL_BOOTID .DS 1 ; BOOT DEVICE ID CHOSEN BY USER BL_DEVICE .DS 1 ; DEVICE TO LOAD FROM BL_LU .DS 1 ; LU TO LOAD FROM ; ; BOOT INFO SECTOR IS READ INTO AREA BELOW ; THE THIRD SECTOR OF A DISK DEVICE IS RESERVED FOR BOOT INFO ; BL_INFOSEC .EQU $ .DS (512 - 128) BB_METABUF .EQU $ BB_SIG .DS 2 ; SIGNATURE (WILL BE 0A55AH IF SET) BB_PLATFORM .DS 1 ; FORMATTING PLATFORM BB_DEVICE .DS 1 ; FORMATTING DEVICE BB_FORMATTER .DS 8 ; FORMATTING PROGRAM BB_DRIVE .DS 1 ; PHYSICAL DISK DRIVE # BB_LU .DS 1 ; LOGICAL UNIT (LU) .DS 1 ; MSB OF LU, NOW DEPRECATED .DS (BB_METABUF + 128) - $ - 32 BB_PROTECT .DS 1 ; WRITE PROTECT BOOLEAN BB_UPDATES .DS 2 ; UPDATE COUNTER BB_RMJ .DS 1 ; RMJ MAJOR VERSION NUMBER BB_RMN .DS 1 ; RMN MINOR VERSION NUMBER BB_RUP .DS 1 ; RUP UPDATE NUMBER BB_RTP .DS 1 ; RTP PATCH LEVEL BB_LABEL .DS 16 ; 16 CHARACTER DRIVE LABEL BB_TERM .DS 1 ; LABEL TERMINATOR ('$') BB_BILOC .DS 2 ; LOC TO PATCH BOOT DRIVE INFO TO (IF NOT ZERO) BB_CPMLOC .DS 2 ; FINAL RAM DESTINATION FOR CPM/CBIOS BB_CPMEND .DS 2 ; END ADDRESS FOR LOAD BB_CPMENT .DS 2 ; CP/M ENTRY POINT (CBIOS COLD BOOT) ; .END