You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1081 lines
31 KiB

;
;==================================================================================================
; 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 (BIOS == BIOS_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 (BIOS == BIOS_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 (BIOS == BIOS_WBW)
CALL DELAY_INIT ; INIT DELAY FUNCTIONS
#ENDIF
;
#IF (BIOS == BIOS_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)
CALL DSKY_RESET
; DISPLAY DSKY BOOT MESSAGE
LD HL,MSG_SEL ; 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 (BIOS == BIOS_WBW)
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
#IF (DSKYENABLE)
LD HL,MSG_BOOT ; POINT TO BOOT MESSAGE
CALL DSKY_SHOWSEG ; DISPLAY MESSAGE
#ENDIF
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
#IF (DSKYENABLE)
LD HL,MSG_LOAD ; POINT TO LOAD MESSAGE
CALL DSKY_SHOWSEG ; DISPLAY MESSAGE
#ENDIF
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 (BIOS == BIOS_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. AT SOME POINT AN UNA INTERBANK COPY
; SHOULD BE IMPLEMENTED HERE.
;
; 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
;
#IF (DSKYENABLE)
LD HL,MSG_GO ; POINT TO BOOT MESSAGE
CALL DSKY_SHOWSEG ; DISPLAY MESSAGE
#ENDIF
;
; 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("...$")
#IF (DSKYENABLE)
LD HL,MSG_LOAD ; POINT TO LOAD MESSAGE
CALL DSKY_SHOWSEG ; DISPLAY MESSAGE
#ENDIF
;
LD DE,STR_BOOTDISK1 ; DISK BOOT MESSAGE
CALL WRITESTR ; PRINT IT
;
#IF (BIOS == BIOS_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 (BIOS == BIOS_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
;
#IF (DSKYENABLE)
LD HL,MSG_GO ; POINT TO BOOT MESSAGE
CALL DSKY_SHOWSEG ; DISPLAY MESSAGE
#ENDIF
;
; 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 (BIOS == BIOS_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 Selection? $"
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)
MSG_SEL .DB $FF,$9D,$9D,$8F,$EC,$80,$80,$80 ; "Boot? "
MSG_BOOT .DB $FF,$9D,$9D,$8F,$00,$00,$00,$80 ; "Boot... "
MSG_LOAD .DB $8B,$9D,$FD,$BD,$00,$00,$00,$80 ; "Load... "
MSG_GO .DB $DB,$9D,$00,$00,$00,$80,$80,$80 ; "Go... "
#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 (BIOS == BIOS_WBW)
;
; 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 (BIOS == BIOS_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