|
|
|
@ -1,13 +1,41 @@ |
|
|
|
; |
|
|
|
;================================================================================================== |
|
|
|
; LOADER |
|
|
|
; 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 |
|
|
|
; |
|
|
|
@ -47,68 +75,22 @@ INT_IM1 .EQU $FF00 |
|
|
|
; |
|
|
|
.FILL (100H - $),0FFH ; PAD REMAINDER OF PAGE ZERO |
|
|
|
; |
|
|
|
; |
|
|
|
;================================================================================================== |
|
|
|
; LOADER |
|
|
|
; STARTUP AND LOADER INITIALIZATION |
|
|
|
;================================================================================================== |
|
|
|
; |
|
|
|
JP START |
|
|
|
DI ; NO INTERRUPTS FOR NOW |
|
|
|
; |
|
|
|
; BOOT OPTION PROCESSING - IN LOW MEMORY SO ~200H-7FFFH UPWARDS CAN BE OVERWRITTEN WHEN LOADING ROMS |
|
|
|
; STACK IS AT 8000H+ SO WE CANT OVERWRITE THAT - MAYBE WE CAN MOVE THAT LATER. |
|
|
|
; |
|
|
|
GOROM: EX DE,HL |
|
|
|
LD B,5 ; PUT NEXT FIVE ADDRESSES ON STACK |
|
|
|
GOROMB1:INC HL |
|
|
|
LD E,(HL) ; EXEC |
|
|
|
INC HL ; SOURCE |
|
|
|
LD D,(HL) ; DEST |
|
|
|
PUSH DE ; SIZE |
|
|
|
DJNZ GOROMB1 ; BANKS |
|
|
|
|
|
|
|
POP DE ; BANKS |
|
|
|
POP HL ; SIZE |
|
|
|
LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY |
|
|
|
RST 08 ; DO IT |
|
|
|
|
|
|
|
POP DE ; DEST |
|
|
|
POP HL ; SOURCE |
|
|
|
LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY |
|
|
|
RST 08 ; DO IT |
|
|
|
; |
|
|
|
; EXEC ADDRESS ON TOP OF STACK |
|
|
|
; RELOCATE TO START OF COMMON RAM AT $8000 |
|
|
|
LD HL,0 |
|
|
|
LD DE,$8000 |
|
|
|
LD BC,LDR_SIZ |
|
|
|
LDIR |
|
|
|
JP START |
|
|
|
; |
|
|
|
#IF (PLATFORM == PLT_UNA) |
|
|
|
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 |
|
|
|
|
|
|
|
; HL IS ALREADY ON STACK AS REQUIRED BY UNA EXEC CHAIN CALL |
|
|
|
|
|
|
|
LD DE,BID_USR ; TARGET BANK ID |
|
|
|
PUSH DE ; ... ON STACK |
|
|
|
DI ; ENTER WITH INTS DISABLED |
|
|
|
JP $FFF7 ; UNA INTER-PAGE EXEC CHAIN |
|
|
|
#ELSE |
|
|
|
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 |
|
|
|
.ORG $8000 + $ |
|
|
|
; |
|
|
|
LD A,BID_USR ; ACTIVATE USER BANK |
|
|
|
POP HL ; RECOVER ENTRY ADDRESS |
|
|
|
DI ; ENTER WITH INTS DISABLED |
|
|
|
CALL HB_BNKCALL ; AND GO |
|
|
|
HALT ; WE SHOULD NEVER RETURN!!! |
|
|
|
#ENDIF |
|
|
|
|
|
|
|
START: DI ; NO INTERRUPTS |
|
|
|
LD SP,BL_STACK ; SETUP STACK |
|
|
|
|
|
|
|
START: LD SP,BL_STACK ; SETUP STACK |
|
|
|
; |
|
|
|
#IF (PLATFORM != PLT_UNA) |
|
|
|
CALL DELAY_INIT ; INIT DELAY FUNCTIONS |
|
|
|
@ -160,83 +142,91 @@ START: DI ; NO INTERRUPTS |
|
|
|
#ENDIF |
|
|
|
EI |
|
|
|
; |
|
|
|
; RUN THE BOOT LOADER MENU |
|
|
|
;================================================================================================== |
|
|
|
; BOOT LOADER MENU DISPLAY |
|
|
|
;================================================================================================== |
|
|
|
; |
|
|
|
LD DE,STR_BANNER ; DISPLAY BOOT BANNER |
|
|
|
|
|
|
|
DOBOOTMENU: |
|
|
|
; |
|
|
|
MENU: |
|
|
|
CALL WRITESTR ; DISPLAY MESSAGE OR ERROR |
|
|
|
CALL NEWLINE |
|
|
|
CALL NEWLINE2 |
|
|
|
; |
|
|
|
#IF (DSKYENABLE) |
|
|
|
; DISPLAY DSKY BOOT MESSAGE |
|
|
|
LD HL,BOOT ; POINT TO BOOT MESSAGE |
|
|
|
CALL DSKY_SHOWRAW ; DISPLAY MESSAGE |
|
|
|
#ENDIF |
|
|
|
; |
|
|
|
#IF (BOOTTYPE == BT_AUTO) |
|
|
|
; INITIALIZE BOOT TIMEOUT DOWNCOUNTER |
|
|
|
LD BC,100 * BOOT_TIMEOUT |
|
|
|
LD (BL_TIMEOUT),BC |
|
|
|
#ENDIF |
|
|
|
; |
|
|
|
LD B,MENU_N ; DISPLAY ALL ROM MENU ENTRIES |
|
|
|
LD HL,MENU_S ; DE POINTS TO START RECORD |
|
|
|
|
|
|
|
MENU_L: PUSH HL ; SAVE CURRENT RECORD POSITION |
|
|
|
|
|
|
|
PUSH HL ; PUT CURRENT ROM RECORD IN HL |
|
|
|
POP DE |
|
|
|
|
|
|
|
PUSH BC ; POINT HL TO THE MENU KEY |
|
|
|
LD BC,MENU_O |
|
|
|
ADD HL,BC |
|
|
|
POP BC |
|
|
|
|
|
|
|
WRITEM1:LD A,(DE) ; DE STEPS THROUGH THE MENU NAMES |
|
|
|
CP '$' ; TEST FOR STRING TERMINATOR |
|
|
|
JR Z,WRITEM2 |
|
|
|
|
|
|
|
CP (HL) ; DO WE HAVE A MATCH WITH MENU |
|
|
|
JR NZ,WRITEM3 |
|
|
|
|
|
|
|
LD A,'(' |
|
|
|
CALL COUT |
|
|
|
LD A,(DE) |
|
|
|
CALL COUT |
|
|
|
LD A,')' |
|
|
|
WRITEM3:CALL COUT |
|
|
|
INC DE |
|
|
|
JR WRITEM1 |
|
|
|
WRITEM2:POP HL ; RECALL THE PREVIOUS RECORD |
|
|
|
LD DE,MENU_V ; SAVED AT MENU_L |
|
|
|
ADD HL,DE ; MOVE TO NEXT RECORD |
|
|
|
|
|
|
|
LD A,' ' |
|
|
|
CALL COUT |
|
|
|
|
|
|
|
DJNZ MENU_L ; NEXT MENU ITEM |
|
|
|
|
|
|
|
CALL NEWLINE ; DISPLAY AVAILABLE DRIVES |
|
|
|
CALL PRTALL |
|
|
|
CALL PC_COLON |
|
|
|
|
|
|
|
DB_BOOTLOOP: |
|
|
|
|
|
|
|
; 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 |
|
|
|
JR NZ,GOTK1 |
|
|
|
|
|
|
|
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) |
|
|
|
CALL KY_STAT ; CHECK DSKY INPUR |
|
|
|
OR A |
|
|
|
JR Z,GOTNK |
|
|
|
|
|
|
|
CALL KY_GET |
|
|
|
JR MENU_A |
|
|
|
; HANDLE DSKY KEY INPUT |
|
|
|
CALL KY_STAT ; CHECK DSKY INPUT |
|
|
|
OR A ; TEST FOR ZERO |
|
|
|
JR Z,SEL2 ; IF ZERO, NO KEY PRESSED |
|
|
|
CALL KY_GET ; GET PENDING KEY PRESS |
|
|
|
JR MATK ; AND HANDLE IT |
|
|
|
#ENDIF |
|
|
|
|
|
|
|
GOTNK: ; CHECK AUTOBOOT TIMEOUT |
|
|
|
|
|
|
|
; |
|
|
|
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 |
|
|
|
@ -244,55 +234,78 @@ GOTNK: ; CHECK AUTOBOOT TIMEOUT |
|
|
|
LD (BL_TIMEOUT),BC |
|
|
|
LD A,B |
|
|
|
OR C |
|
|
|
JP NZ,DB_BOOTLOOP |
|
|
|
|
|
|
|
JP NZ,SEL3 |
|
|
|
; |
|
|
|
LD A,BOOT_DEFAULT ; TIMEOUT EXPIRED, |
|
|
|
JR MENU_A ; PERFORM DEFAULT BOOT ACTION |
|
|
|
#ENDIF |
|
|
|
JR DB_BOOTLOOP |
|
|
|
|
|
|
|
GOTK1: CALL CINUC |
|
|
|
|
|
|
|
MENU_A: LD B,MENU_N |
|
|
|
; |
|
|
|
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 |
|
|
|
MENU_C: EX DE,HL |
|
|
|
MATS1: EX DE,HL |
|
|
|
ADD HL,DE |
|
|
|
CP (HL) |
|
|
|
EX DE,HL |
|
|
|
JR Z,MENU_X |
|
|
|
DJNZ MENU_C ; FALL THRU IF IT DOES NOT MATCH ROM MENU |
|
|
|
|
|
|
|
; CHECK FOR DRIVE EXECUTION |
|
|
|
|
|
|
|
CP '0' ; 0-9, DISK DEVICE |
|
|
|
JR C,DB_INVALID |
|
|
|
CP '9' + 1 |
|
|
|
JR NC,DB_INVALID |
|
|
|
SUB '0' |
|
|
|
JP GOBOOTDISK |
|
|
|
|
|
|
|
MENU_X: CALL NEWLINE |
|
|
|
|
|
|
|
; DE CONTAIN POINTER TO MENU RECORD |
|
|
|
|
|
|
|
EX DE,HL |
|
|
|
INC HL ; WE HAVE A VALID ROM MENU OPTION |
|
|
|
LD E,(HL) |
|
|
|
INC HL |
|
|
|
LD D,(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 |
|
|
|
|
|
|
|
JP (HL) ; JUMP TO THE ROUTINE TO EXECUTE IT |
|
|
|
|
|
|
|
DB_INVALID: |
|
|
|
LD DE,STR_INVALID |
|
|
|
JP DOBOOTMENU |
|
|
|
|
|
|
|
#DEFINE MENU_L(M1,M2,M3,M4,M5,M6,M7,M8,M9,M10) \ |
|
|
|
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 |
|
|
|
#DEFCONT \ .DW M3 |
|
|
|
#IF (DSKYENABLE) |
|
|
|
#DEFCONT \ .DB M3 |
|
|
|
#ELSE |
|
|
|
#DEFCONT \ .DB $FF |
|
|
|
#ENDIF |
|
|
|
#DEFCONT \ .DW M4 |
|
|
|
#DEFCONT \ .DW M5 |
|
|
|
#DEFCONT \ .DW M6 |
|
|
|
@ -301,57 +314,164 @@ DB_INVALID: |
|
|
|
#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. |
|
|
|
|
|
|
|
; name menu exec dest-exec source dest-addr img-size source-bank dest desc |
|
|
|
; DB DB DW DW DW DW DW DB DB DB |
|
|
|
MENU_S: MENU_L("MONITOR$ $", "M", GOROM, MON_SERIAL, 1000h, MON_LOC, MON_SIZ, BID_BIOSIMG, BID_USR, "Monitor$12345") |
|
|
|
MENU_1: MENU_L("CP/M$ $", "C", GOROM, CPM_ENT, 2000h, CPM_LOC, CPM_SIZ, BID_BIOSIMG, BID_USR, "CP/M 80 2.2$ ") |
|
|
|
MENU_L("Z-SYSTEM$$", "Z", GOROM, CPM_ENT, 5000h, CPM_LOC, CPM_SIZ, BID_BIOSIMG, BID_USR, "ZSDOS V1.1$ ") |
|
|
|
MENU_L("$ $", "E", GOROM, EGG_LOC, 0E00h, EGG_LOC, EGG_SIZ, BID_BIOSIMG, BID_USR, "Easter Egg$ ") |
|
|
|
MENU_L("FORTH$ $", "F", GOROM, FTH_LOC, 0000h, FTH_LOC, FTH_SIZ, BID_OSIMG, BID_USR, "Camel Forth$ ") |
|
|
|
MENU_L("BASIC$ $", "B", GOROM, BAS_LOC, 1700h, BAS_LOC, BAS_SIZ, BID_OSIMG, BID_USR, "Nascom BASIC$") |
|
|
|
MENU_L("T-BASIC$ $", "T", GOROM, TBC_LOC, 3700h, TBC_LOC, TBC_SIZ, BID_OSIMG, BID_USR, "Tasty BASIC$ ") |
|
|
|
|
|
|
|
; 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-MON $", "D", GOROM, MON_DSKY, 1000h, MON_LOC, MON_SIZ, BID_BIOSIMG, BID_USR, "DSKY Monitor$") |
|
|
|
MENU_L("~DSKY$ ", "D", KY_GO, MON_DSKY, 1000h, MON_LOC, MON_SIZ, BID_CUR, BID_USR, "DSKY Monitor$") |
|
|
|
#ENDIF |
|
|
|
|
|
|
|
.DB "REBOOT$ ", "R" |
|
|
|
.DW REBOOT |
|
|
|
|
|
|
|
MENU_E: |
|
|
|
MENU_V .EQU MENU_1-MENU_S ; LENGTH OF EACH MENU RECORD |
|
|
|
MENU_N .EQU ((MENU_E-MENU_S)/MENU_V)+1 ; NUMBER OF MENU ITEMS |
|
|
|
MENU_O .EQU 10 ; OFFSET TO MENU KEY FROM NAME |
|
|
|
|
|
|
|
; |
|
|
|
; REBOOT ROMLDR |
|
|
|
; |
|
|
|
REBOOT: LD A,BID_BOOT ; BOOT BANK |
|
|
|
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("...$") |
|
|
|
; |
|
|
|
; BOOT FROM DISK DRIVE |
|
|
|
; |
|
|
|
BOOTDISK: |
|
|
|
LD DE,STR_BOOTDISK1 ; DISK BOOT MESSAGE |
|
|
|
CALL WRITESTR ; PRINT IT |
|
|
|
|
|
|
|
; |
|
|
|
#IF (PLATFORM == PLT_UNA) |
|
|
|
; |
|
|
|
; BOOT FROM UNA DISK DRIVE |
|
|
|
; |
|
|
|
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 |
|
|
|
@ -364,7 +484,6 @@ BOOTDISK: |
|
|
|
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 |
|
|
|
@ -375,13 +494,13 @@ BOOTDISK: |
|
|
|
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 |
|
|
|
@ -389,7 +508,7 @@ BOOTDISK: |
|
|
|
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 |
|
|
|
@ -401,7 +520,7 @@ BOOTDISK: |
|
|
|
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 |
|
|
|
@ -414,7 +533,6 @@ BOOTDISK: |
|
|
|
#ENDIF |
|
|
|
; |
|
|
|
; CHECK SIGNATURE |
|
|
|
CALL NEWLINE ; FORMATTING |
|
|
|
LD DE,(BB_SIG) ; GET THE SIGNATURE |
|
|
|
LD A,$A5 ; FIRST BYTE SHOULD BE $A5 |
|
|
|
CP D ; COMPARE |
|
|
|
@ -422,32 +540,24 @@ BOOTDISK: |
|
|
|
LD A,$5A ; SECOND BYTE SHOULD BE $5A |
|
|
|
CP E ; COMPARE |
|
|
|
JP NZ,DB_NOBOOT ; ERROR IS NOT EQUAL |
|
|
|
|
|
|
|
; |
|
|
|
; PRINT CPMLOC VALUE |
|
|
|
CALL NEWLINE |
|
|
|
LD DE,STR_CPMLOC |
|
|
|
CALL WRITESTR |
|
|
|
PRTS("\r\nLoc=$") |
|
|
|
LD BC,(BB_CPMLOC) |
|
|
|
CALL PRTHEXWORD |
|
|
|
|
|
|
|
; |
|
|
|
; PRINT CPMEND VALUE |
|
|
|
CALL PC_SPACE |
|
|
|
LD DE,STR_CPMEND |
|
|
|
CALL WRITESTR |
|
|
|
PRTS(" End=$") |
|
|
|
LD BC,(BB_CPMEND) |
|
|
|
CALL PRTHEXWORD |
|
|
|
|
|
|
|
; |
|
|
|
; PRINT CPMENT VALUE |
|
|
|
CALL PC_SPACE |
|
|
|
LD DE,STR_CPMENT |
|
|
|
CALL WRITESTR |
|
|
|
PRTS(" Ent=$") |
|
|
|
LD BC,(BB_CPMENT) |
|
|
|
CALL PRTHEXWORD |
|
|
|
CALL PC_SPACE |
|
|
|
|
|
|
|
; |
|
|
|
; PRINT DISK LABEL |
|
|
|
LD DE,STR_LABEL |
|
|
|
CALL WRITESTR |
|
|
|
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) |
|
|
|
@ -505,7 +615,7 @@ BOOTDISK: |
|
|
|
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 |
|
|
|
@ -517,7 +627,7 @@ BOOTDISK: |
|
|
|
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 |
|
|
|
@ -530,21 +640,20 @@ BOOTDISK: |
|
|
|
DB_NODISK: |
|
|
|
; SELDSK DID NOT LIKE DRIVE SELECTION |
|
|
|
LD DE,STR_NODISK |
|
|
|
JP DOBOOTMENU |
|
|
|
|
|
|
|
JP MENU |
|
|
|
; |
|
|
|
DB_NOBOOT: |
|
|
|
; DISK IS NOT BOOTABLE |
|
|
|
LD DE,STR_NOBOOT |
|
|
|
JP DOBOOTMENU |
|
|
|
|
|
|
|
JP MENU |
|
|
|
; |
|
|
|
DB_ERR: |
|
|
|
; I/O ERROR DURING BOOT ATTEMPT |
|
|
|
LD DE,STR_BOOTERR |
|
|
|
JP DOBOOTMENU |
|
|
|
JP MENU |
|
|
|
; |
|
|
|
#IF (PLATFORM == PLT_UNA) |
|
|
|
; |
|
|
|
; |
|
|
|
; PRINT LIST OF ALL DRIVES UNDER UNA |
|
|
|
; |
|
|
|
PRTALL: |
|
|
|
@ -712,31 +821,31 @@ DEV15 .EQU DEVUNK |
|
|
|
; |
|
|
|
#ENDIF |
|
|
|
; |
|
|
|
;__TEXT_STRINGS_________________________________________________________________________________________________________________ |
|
|
|
; |
|
|
|
; STRINGS |
|
|
|
;_____________________________________________________________________________________________________________________________ |
|
|
|
; |
|
|
|
STR_BOOTDISK .DB "BOOT FROM DISK\r\n$" |
|
|
|
STR_BOOTDISK1 .DB "\r\nReading disk information...$" |
|
|
|
STR_INVALID .DB "INVALID SELECTION\r\n$" |
|
|
|
STR_SETUP .DB "SYSTEM SETUP\r\n$" |
|
|
|
STR_SIG .DB "SIGNATURE=$" |
|
|
|
STR_CPMLOC .DB "LOC=$" |
|
|
|
STR_CPMEND .DB "END=$" |
|
|
|
STR_CPMENT .DB "ENT=$" |
|
|
|
STR_LABEL .DB "LABEL=$" |
|
|
|
STR_LOADING .DB "\r\nLoading...$" |
|
|
|
STR_NODISK .DB "\r\nNo disk!$" |
|
|
|
STR_NOBOOT .DB "\r\nDisk not bootable!$" |
|
|
|
STR_BOOTERR .DB "\r\nBoot failure!$" |
|
|
|
STR_BANNER .DB "\r\n", PLATFORM_NAME, " Boot Loader\r\n$" |
|
|
|
;================================================================================================== |
|
|
|
; 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" |
|
|
|
; |
|
|
|
@ -893,7 +1002,7 @@ CINUC: |
|
|
|
; FILL REMAINDER OF BANK |
|
|
|
;================================================================================================== |
|
|
|
; |
|
|
|
SLACK: .EQU ($LDR_SIZ - $) |
|
|
|
SLACK: .EQU ($8000 + LDR_SIZ - $) |
|
|
|
.FILL SLACK |
|
|
|
; |
|
|
|
.ECHO "LOADER space remaining: " |
|
|
|
@ -903,8 +1012,7 @@ SLACK: .EQU ($LDR_SIZ - $) |
|
|
|
;================================================================================================== |
|
|
|
; WORKING DATA STORAGE |
|
|
|
;================================================================================================== |
|
|
|
; |
|
|
|
.ORG $8000 |
|
|
|
.ORG $8000 + LDR_SIZ |
|
|
|
; |
|
|
|
.DS 64 ; 32 LEVEL STACK |
|
|
|
BL_STACK .EQU $ ; ... TOP IS HERE |
|
|
|
|