; ;================================================================================================== ; HBIOS ;================================================================================================== ; ; THIS FILE CONTAINS THE HBIOS IMAGE THAT IS INTENDED TO RUN IN A DEDICATED RAM BANK. THE CODE IS ; CONSTRUCTED SUCH THAT IT CAN BE LAUNCHED IN A VARIETY OF MODES AND INSTALL ITSELF. A SMALL 512 ; BYTE PROXY IS PLACED AT THE TOP OF CPU MEMORY (FE00H-FFFFH). THIS PROXY CODE ALLOWS CODE ; RUNNING FROM ANY BANK TO INVOKE HBIOS FUNCTIONS. NORMALLY, ANY BANK THAT RUNS CODE WOULD SETUP ; THE RST 8 VECTOR TO POINT TO THE PROXY INVOKE ENTRY POINT AT FFF0H. CALLS VIA THE PROXY INVOKE ; ENTRY POINT TRANSPARENTLY SWAP IN THE HBIOS BANK, PERFORM THE REQUESTED FUNCTION, AND RETURN ; WITH THE ORIGINAL BANK ACTIVE. THE CODE USING HBIOS FUNCTIONS DOES NOT NEED TO BE AWARE OF ; THE BANK SWITCHING THAT OCCURS. ; ; THIS FILE CAN BE COMPILED TO BOOT IN ONE OF 3 MODES (ROM, APPLICATION, OR IMAGE) AS DESCRIBED ; BELOW. WHEN COMPILED, YOU MUST DEFINE EXACTLY ONE OF THE FOLLOWING MACROS: ; ; - ROMBOOT: BOOT FROM A ROM BANK ; ; WHEN ROMBOOT IS DEFINED, THE FILE IS ASSEMBLED TO BE IMBEDDED AT THE START OF A ROM ; ASSUMING THAT THE CPU WILL START EXECUTION AT ADDRESS 0. AFTER PERFORMING MINIMAL ; SYSTEM INITIALIZATION, THE IMAGE OF THE RUNNING ROM BANK IS COPIED TO A RAM BANK ; CREATING A SHADOW COPY IN RAM. EXECUTION IS THAN TRANSFERRED TO THE RAM SHADOW COPY. ; THIS IS ESSENTIAL BECAUSE THE HBIOS CODE DOES NOT SUPPORT RUNNING IN READ ONLY MEMORY ; (EXCEPT FOR THE INITIAL LAUNCHING CODE). IN THIS MODE, THE HBIOS INITIALIZATION WILL ; ALSO COPY THE OS IMAGES BANK IN ROM TO THE USER RAM BANK AND LAUNCH IT AFTER HBIOS ; IS INSTALLED. ; ; - APPBOOT: BOOT FROM A CP/M STYLE APPLICATION FILE ; ; WHEN APPBOOT IS DEFINED, THE FILE IS ASSEMBLED AS A CP/M APPLICATION ASSUMING ; THAT IT WILL BE LOADED AT 100H BY THE CP/M (OR COMPATIBLE) OS. NOTE THAT IN ; THIS CASE IT IS ASSUMED THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE ; HBIOS APPLICATION BINARY. THE APPENDED OS IMAGES ARE COPIED TO THE USER RAM ; BANK AND LAUNCHED AFTER HBIOS HAS INSTALLED ITSELF. ; ; - IMGBOOT: BOOT FROM AN IMAGE FILE THAT HAS BEEN PLACED IN THE USER BANK ; ; WHEN IMGBOOT IS DEFINED, THE FILE IS ASSEMBLED SUCH THAT IT CAN BE PRELOADED ; INTO THE RAM USER BANK BY AN EXTERNAL PROCESS THAT SUBSEQUENTLY LAUNCHES ; THE CODE AT ADDRESS 0. THE MOST COMMON EXAMPLE OF THIS IS THE UNA FSFAT ; TOOL WHICH CAN LOAD AN IMAGE FROM A DOS FAT FILESYSTEM PROVIDING A SIMPLE ; WAY TO LOAD A TEST COPY OF HBIOS. AS IS THE CASE WITH APPBOOT, IT IS ASSUMED ; THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE IMAGE AND IS LAUNCHED ; AFTER HBIOS IS INSTALLED. ; ; INCLUDE FILE NESTING: ; ; hbios.asm ; - std.asm ; - ver.inc ; - hbios.inc ; - build.inc ; - config/_.asm ; - cfg_.asm ; - .asm ; - .asm ; - util.asm ; - time.asm ; - bcd.asm ; - decode.asm ; - encode.asm ; - [xio|mio].asm ; - dsky.asm ; - unlzsa2s.asm ; ; ; INCLUDE GENERIC STUFF ; #INCLUDE "std.asm" ; ; MAKE SURE EXACTLY ONE OF ROMBOOT, APPBOOT, IMGBOOT IS DEFINED. ; MODCNT .EQU 0 #IFDEF ROMBOOT MODCNT .SET MODCNT + 1 #ENDIF #IFDEF APPBOOT MODCNT .SET MODCNT + 1 #ENDIF #IFDEF IMGBOOT MODCNT .SET MODCNT + 1 #ENDIF #IF (MODCNT != 1) .ECHO "*** ERROR: PLEASE DEFINE ONE AND ONLY ONE OF ROMBOOT, APPBOOT, IMGBOOT!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF ; ; ; #IF (DIAGENABLE) #DEFINE DIAG(N) PUSH AF #DEFCONT \ LD A,N #DEFCONT \ OUT (DIAGPORT),A #DEFCONT \ POP AF #ELSE #DEFINE DIAG(N) \; #ENDIF ; #IF (LEDENABLE) #DEFINE LED(N) PUSH AF #DEFCONT \ LD A,~N #DEFCONT \ OUT (LEDPORT),A #DEFCONT \ POP AF #ELSE #DEFINE LED(N) \; #ENDIF ; ; ; #IF (INTMODE == 0) ; NO INTERRUPT HANDLING #DEFINE HB_DI ; #DEFINE HB_EI ; #ENDIF #IF ((INTMODE == 1) | (INTMODE == 2)) ; MODE 1 OR 2 INTERRUPT HANDLING #DEFINE HB_DI DI #DEFINE HB_EI EI #ENDIF #IF (INTMODE > 2) .ECHO "*** ERROR: INVALID INTMODE SETTING!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF ; ; ; #IF (CTCENABLE) CTCA .EQU CTCBASE + 0 ; CTC: CHANNEL A REGISTER ADR CTCB .EQU CTCBASE + 1 ; CTC: CHANNEL B REGISTER ADR CTCC .EQU CTCBASE + 2 ; CTC: CHANNEL C REGISTER ADR CTCD .EQU CTCBASE + 3 ; CTC: CHANNEL D REGISTER ADR #ENDIF ; ; ; #IFNDEF APPBOOT ; .ORG 0 ; ;================================================================================================== ; NORMAL PAGE ZERO SETUP, RET/RETI/RETN AS APPROPRIATE, LEAVE INTERRUPTS DISABLED ;================================================================================================== ; .FILL (000H - $),0FFH ; RST 0 JP HB_START .DW ROM_SIG .FILL (008H - $),0FFH ; RST 8 JP HB_INVOKE ; INVOKE HBIOS FUNCTION .FILL (010H - $),0FFH ; RST 10 RET .FILL (018H - $),0FFH ; RST 18 RET .FILL (020H - $),0FFH ; RST 20 RET .FILL (028H - $),0FFH ; RST 28 RET .FILL (030H - $),0FFH ; RST 30 RET .FILL (038H - $),0FFH ; RST 38 / IM1 INT #IF (INTMODE == 1) JP INT_IM1 ; JP TO INTERRUPT HANDLER IN HI MEM #ELSE RETI ; RETURN W/ INTS DISABLED #ENDIF .FILL (066H - $),0FFH ; NMI RETN ; .FILL (070H - $),0FFH ; SIG STARTS AT $80 ; ROM_SIG: .DB $76, $B5 ; 2 SIGNATURE BYTES .DB 1 ; STRUCTURE VERSION NUMBER .DB 7 ; ROM SIZE (IN MULTIPLES OF 4KB, MINUS ONE) .DW NAME ; POINTER TO HUMAN-READABLE ROM NAME .DW AUTH ; POINTER TO AUTHOR INITIALS .DW DESC ; POINTER TO LONGER DESCRIPTION OF ROM .DB 0, 0, 0, 0, 0, 0 ; RESERVED FOR FUTURE USE; MUST BE ZERO ; NAME .DB "ROMWBW v", BIOSVER, ", ", TIMESTAMP, 0 AUTH .DB "WBW",0 DESC .DB "ROMWBW v", BIOSVER, ", Copyright (C) 2019, Wayne Warthen, GNU GPL v3", 0 ; .FILL ($100 - $),$FF ; PAD REMAINDER OF PAGE ZERO ; #ENDIF ; ;================================================================================================== ; HBIOS CONFIGURATION BLOCK (HCB) ;================================================================================================== ; .ORG HCB_LOC HCB: JP HB_START ; CB_MARKER .DB 'W',~'W' ; MARKER CB_VERSION .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO .DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO ; CB_PLATFORM .DB PLATFORM CB_CPUMHZ .DB CPUMHZ CB_CPUKHZ .DW CPUKHZ CB_RAMBANKS .DB RAMSIZE / 32 CB_ROMBANKS .DB ROMSIZE / 32 ; CB_BOOTVOL .DW 0 ; BOOT VOLUME IS UNIT/SLICE, SET BY LOADER CB_BOOTBID .DB 0 ; BOOT BANK ID, SET BY LOADER CB_SERDEV .DB 0 ; PRIMARY SERIAL UNIT IS UNIT #0 BY FIAT CB_CRTDEV .DB $FF ; PRIMARY CRT UNIT, $FF UNTIL AFTER HBIOS INIT CB_CONDEV .DB $FF ; CONSOLE UNIT, $FF UNTIL AFTER HBIOS INIT ; ; MEMORY MANAGEMENT VARIABLES START AT $20 ; .FILL (HCB + $20 - $),0 ; CB_HEAP .DW 0 CB_HEAPTOP .DW 0 ; ; STANDARD BANK ID'S START AT $D8 ; .FILL (HCB + $D8 - $),0 ; CB_BIDCOM .DB BID_COM CB_BIDUSR .DB BID_USR CB_BIDBIOS .DB BID_BIOS CB_BIDAUX .DB BID_AUX CB_BIDRAMD0 .DB BID_RAMD0 CB_BIDRAMDN .DB BID_RAMDN CB_BIDROMD0 .DB BID_ROMD0 CB_BIDROMDN .DB BID_ROMDN ; .FILL (HCB + HCB_SIZ - $),0 ; PAD REMAINDER OF HCB ; ;================================================================================================== ; HBIOS UPPER MEMORY PROXY (RELOCATED TO RUN IN TOP 2 PAGES OF CPU RAM) ;================================================================================================== ; ; THE FOLLOWING CODE IS RELOCATED TO THE TOP OF MEMORY TO HANDLE INVOCATION DISPATCHING ; .FILL (HBX_IMG - $) ; FILL TO START OF PROXY IMAGE START .ORG HBX_LOC ; ADJUST FOR RELOCATION ; ; MEMORY LAYOUT: ; ; HBIOS PROXY CODE $FE00 (256 BYTES) ; INTERRUPT VECTORS $FF00 (32 BYTES, 16 ENTRIES) ; INTERRUPT HANDLER STUBS $FF20 (128 BYTES) ; HBIOS PROXY COPY BUFFER $FF80 (64 BYTES) ; HBIOS PROXY MGMT BLOCK $FFE0 (32 BYTES) ; ; DEFINITIONS ; HBX_BUFSIZ .EQU $40 ; INTERBANK COPY BUFFER SIZE ; ; HBIOS IDENTIFICATION DATA BLOCK ; HBX_IDENT: .DB 'W',~'W' ; MARKER .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO .DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO ; ;================================================================================================== ; HBIOS ENTRY FOR RST 08 PROCESSING ;================================================================================================== ; HBX_INVOKE: LD (HBX_INVSP),SP ; SAVE ORIGINAL STACK FRAME LD A,(HB_CURBNK) ; GET CURRENT BANK LD (HB_INVBNK),A ; SAVE INVOCATION BANK LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM FOR BANK SWITCH LD A,BID_BIOS ; HBIOS BANK CALL HBX_BNKSEL ; SELECT IT LD SP,HB_STACK ; NOW USE FULL HBIOS STACK IN HBIOS BANK CALL HB_DISPATCH ; CALL HBIOS FUNCTION DISPATCHER LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM FOR BANK SWITCH PUSH AF ; SAVE AF (FUNCTION RETURN) LD A,(HB_INVBNK) ; LOAD ORIGINAL BANK CALL HBX_BNKSEL ; SELECT IT POP AF ; RESTORE AF LD SP,0 ; RESTORE ORIGINAL STACK FRAME HBX_INVSP .EQU $ - 2 RET ; RETURN TO CALLER ; ;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ;; BNKSEL - Switch Memory Bank to Bank in A. ;; Preserve all Registers including Flags. ;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ; HBX_BNKSEL: ; IF AN INTERRUPT OCCURS DURING THE BANK SWITCH CODE, ; THE BANK WILL BE SET TO (CURBNK) AS THE INTERRUPT ; RETURNS. SO, IT IS IMPORTANT THAT (HB_CURBNK) BE ; SET AS THE FIRST STEP TO AVOID ISSUES IF AN INTERRUPT ; OCCURS DURING PROCESSING. LD (HB_CURBNK),A ; RECORD NEW CURRENT BANK ; HBX_BNKSEL_INT: ; #IF (MEMMGR == MM_SBC) #IF (INTMODE == 1) ; THIS BIT OF ABSURDITY HANDLES A RARE (BUT FATAL) SITUATION ; WHERE AN IM1 INTERRUPT OCCURS BETWEEN SETTING THE RAM AND ; ROM SELECTORS. BRACKETING THE INSTRUCTIONS WITH DI/EI ; IS CONTRAINDICATED BECAUSE THIS ROUTINE IS CALLED BY ; OTHER ROUTINES THAT MUST CONTROL INT ENABLE AT A HIGHER ; LEVEL. THE FOLLOWING TECHNIQUE ENSURES THAT YOU ALWAYS ; SWITCH DIRECTLY FROM THE PREVIOUS BANK TO THE TARGET BANK ; WITHOUT AN "ERRANT" BANK BEING ACTIVE BETWEEN THE TWO ; BANK SELECTION I/O INSTRUCTIONS. THE TECHNIQUE IS ONLY ; NEEDED WHEN USING INT MODE 1 BECAUSE THAT MODE REQUIRES ; PAGE ONE TO HAVE A VALID INT HANDLER WHENEVER INTS ARE ; ENABLED. ;BIT 7,A ; [8] TEST RAM BIT ;JR Z,HBX_ROM ; [12/7] IF NOT SET, JUST DO ROM OR A ; [4] SET FLAGS JP P,HBX_ROM ; [10] BIT 7 INDICATES RAM #ENDIF OUT (MPCL_RAM),A ; SET RAM PAGE SELECTOR HBX_ROM: OUT (MPCL_ROM),A ; SET ROM PAGE SELECTOR RET ; DONE #ENDIF #IF (MEMMGR == MM_Z2) BIT 7,A ; BIT 7 SET REQUESTS RAM PAGE JR Z,HBX_ROM ; NOT SET, SELECT ROM PAGE RES 7,A ; RAM PAGE REQUESTED: CLEAR ROM BIT ADD A,16 ; ADD 16 x 32K - RAM STARTS FROM 512K ; HBX_ROM: RLCA ; TIMES 2 - GET 16K PAGE INSTEAD OF 32K OUT (MPGSEL_0),A ; BANK_0: 0K - 16K ;OUT (DIAGPORT),A ; *DEBUG* INC A ; OUT (MPGSEL_1),A ; BANK_1: 16K - 32K RET ; DONE #ENDIF #IF (MEMMGR == MM_N8) BIT 7,A ; TEST BIT 7 FOR RAM VS. ROM JR Z,HBX_ROM ; IF NOT SET, SELECT ROM PAGE ; HBX_RAM: RES 7,A ; CLEAR BIT 7 FROM ABOVE RLCA ; SCALE SELECTOR TO RLCA ; ... GO FROM Z180 4K PAGE SIZE RLCA ; ... TO DESIRED 32K PAGE SIZE OUT0 (Z180_BBR),A ; WRITE TO BANK BASE LD A,N8_DEFACR | 80H ; SELECT RAM BY SETTING BIT 7 OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER RET ; DONE ; HBX_ROM: OUT0 (N8_RMAP),A ; BANK INDEX TO N8 RMAP REGISTER XOR A ; ZERO ACCUM OUT0 (Z180_BBR),A ; ZERO BANK BASE LD A,N8_DEFACR ; SELECT ROM BY CLEARING BIT 7 OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER RET ; DONE ; #ENDIF #IF (MEMMGR == MM_Z180) RLCA ; RAM FLAG TO CARRY FLAG AND BIT 0 JR NC,HBX_BNKSEL1 ; IF NC, WANT ROM PAGE, SKIP AHEAD XOR %00100001 ; SET BIT FOR HI 512K, CLR BIT 0 HBX_BNKSEL1: RLCA ; CONTINUE SHIFTING TO SCALE SELECTOR RLCA ; FOR Z180 4K PAGE -> DESIRED 32K PAGE OUT0 (Z180_BBR),A ; WRITE TO BANK BASE RET ; DONE #ENDIF ; ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ; Copy Data - Possibly between banks. This resembles CP/M 3, but ; usage of the HL and DE registers is reversed. ; Caller MUST ensure stack is already in high memory. ; Caller MUST preset HBX_SRCBNK and HBX_DSTBNK. ; Caller MUST disable ints if IM1 active ; Enter: ; HL = Source Address ; DE = Destination Address ; BC = Number of bytes to copy ; Exit : None ; Uses : AF,BC,DE,HL ; ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ; HBX_BNKCPY: LD (HBX_BC_SP),SP ; PUT STACK LD SP,HBX_TMPSTK ; ... IN HI MEM LD A,(HB_CURBNK) ; GET CURRENT BANK PUSH AF ; AND SAVE TO RESTORE LATER PUSH BC ; CUR LEN -> (SP) ; HBX_BC_LOOP: EX (SP),HL ; HL := CUR LEN, (SP) := CUR SRC LD BC,HBX_BUFSIZ ; SET BC TO BOUNCE BUFFER SIZE OR A ; CLEAR CARRY FLAG SBC HL,BC ; CUR LEN := CUR LEN - BBUF SIZE JR C,HBX_BC_LAST ; END GAME, LESS THAN BBUF BYTES LEFT EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN CALL HBX_BC_ITER ; DO A FULL BBUF SIZE CHUNK JR HBX_BC_LOOP ; AND REPEAT TILL DONE ; HBX_BC_LAST: ; HL IS BETWEEN -(BBUF SIZE) AND -1, BC = BBUF SIZE OR A ; CLEAR CARRY ADC HL,BC ; HL := REM LEN (0 - 127) EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN POP BC ; BC := REM LEN CALL NZ,HBX_BC_ITER ; DO FINAL CHUNK, IFF > 0 BYTES POP AF ; RECOVER ORIGINAL BANK CALL HBX_BNKSEL ; SWITCH LD SP,$FFFF ; RESTORE STACK HBX_BC_SP .EQU $ - 2 ; ... TO ORIGINAL VALUE RET ; HBX_BC_ITER: ; HL = SRC ADR, DE = DEST ADR, BC = LEN PUSH BC ; SAVE COPY LEN PUSH DE ; FINAL DEST ON STACK LD DE,HBX_BUF ; SET DEST TO BUF LD A,(HB_SRCBNK) ; GET SOURCE BANK CALL HBX_BNKSEL ; SWITCH TO SOURCE BANK LDIR ; HL -> BUF (DE), BC BYTES, HL UPDATED SRC ADR POP DE ; DE := FINAL DEST POP BC ; GET LEN BACK IN BC PUSH HL ; SAVE UPDATED SRC ADR LD HL,HBX_BUF ; SET SRC ADR TO BUF LD A,(HB_DSTBNK) ; GET DEST BANK CALL HBX_BNKSEL ; SWITCH TO DEST BANK LDIR ; BUF (HL) -> DE, BC BYTES, DE UPDATED DEST ADR POP HL ; RECOVER UPDATED SRC ADR ; HL = UPDATED SRC, DE = UPDATED DEST, BC = 0 RET ; ; CALL A ROUTINE IN ANOTHER BANK. ; CALLER MUST ENSURE STACK IS ALREADY IN HIGH MEMORY AND HAS ADEQUATE SPACE. ; IF IM1 INTERRUPTS ARE POSSIBLE, CALLER MUST EITHER DISABLE THEM PRIOR TO ; BNKCALL OR MAKE SURE THAT PAGE ZERO IN TARGET BANK IS PREPARED FOR THEM. ; ON INPUT A=TARGET BANK, HL=TARGET ADDRESS ; HBX_BNKCALL: LD (HBX_TGTBNK),A ; STUFF TARGET BANK TO CALL INTO CODE BELOW LD (HBX_TGTADR),HL ; STUFF ADDRESS TO CALL INTO CODE BELOW LD A,(HB_CURBNK) ; GET CURRENT BANK PUSH AF ; SAVE FOR RETURN HBX_TGTBNK .EQU $ + 1 LD A,$FF ; LOAD BANK TO CALL ($FF OVERLAID AT ENTRY) CALL HBX_BNKSEL ; ACTIVATE THE NEW BANK HBX_TGTADR .EQU $ + 1 CALL $FFFF ; CALL ROUTINE ($FFFF IS OVERLAID ABOVE) EX (SP),HL ; SAVE HL AND GET BANK TO RESTORE IN HL PUSH AF ; SAVE AF LD A,H ; BANK TO RESTORE TO A CALL HBX_BNKSEL ; RESTORE IT POP AF ; RECOVER AF POP HL ; RECOVER HL RET ; ; PEEK & POKE ROUTINES ; ADDRESS IN HL, BANK IN D, VALUE IN/OUT IN E, A IS TRASHED ; CALLER MUST DISABLE INTS IF IM1 AND ACCESSING PAGE W/O IM1 INT VECTOR ; HBX_PEEK: LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM LD A,(HB_CURBNK) PUSH AF LD A,D CALL HBX_BNKSEL LD E,(HL) JR HBX_PPRET ; HBX_POKE: LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM LD A,(HB_CURBNK) PUSH AF LD A,D CALL HBX_BNKSEL LD (HL),E ; HBX_PPRET: POP AF CALL HBX_BNKSEL LD SP,0 ; RESTORE ORIGINAL STACK FRAME HBX_PPSP .EQU $ - 2 RET ; ; SMALL TEMPORARY STACK FOR USE BY INVOKE, PEEK, AND POKE ; .FILL 20,$CC ; 10 LEVEL STACK HBX_TMPSTK .EQU $ ; ; PRIVATE STACK AT END OF HBIOS CODE ; OCCUPIES SPACE BEFORE IVT ; HBX_STKSIZ .EQU $FF00 - $ .ECHO "HBIOS PROXY STACK space: " .ECHO HBX_STKSIZ .ECHO " bytes.\n" .FILL HBX_STKSIZ,$FF HBX_STACK .EQU $ ; #IF (INTMODE == 2) ; ; HBIOS INTERRUPT SLOT ASSIGNMENTS ; ; # Z80 Z180 ; --- -------------- -------------- ; 0 CTC0A INT1 -+ ; 1 CTC0B INT2 | ; 2 CTC0C TIM0 | ; 3 CTC0D TIM1 | ; 4 DMA0 +- Z180 INTERNAL ; 5 DMA1 | ; 6 CSIO | ; 7 SIO0 SER0 | ; 8 SIO1 SER1 -+ ; 9 PIO0A PIO0A ; 10 PIO0B PIO0B ; 11 PIO1A PIO1A ; 12 PIO1B PIO1B ; 13 SIO0 ; 14 SIO1 ; 15 ; HBX_IVT: .DW HBX_IV00 .DW HBX_IV01 .DW HBX_IV02 .DW HBX_IV03 .DW HBX_IV04 .DW HBX_IV05 .DW HBX_IV06 .DW HBX_IV07 .DW HBX_IV08 .DW HBX_IV09 .DW HBX_IV0A .DW HBX_IV0B .DW HBX_IV0C .DW HBX_IV0D .DW HBX_IV0E .DW HBX_IV0F ; HBX_IVTCNT .EQU ($ - HBX_IVT) / 2 ; HBX_IV00: CALL HBX_INT \ .DB $00 << 2 HBX_IV01: CALL HBX_INT \ .DB $01 << 2 HBX_IV02: CALL HBX_INT \ .DB $02 << 2 HBX_IV03: CALL HBX_INT \ .DB $03 << 2 HBX_IV04: CALL HBX_INT \ .DB $04 << 2 HBX_IV05: CALL HBX_INT \ .DB $05 << 2 HBX_IV06: CALL HBX_INT \ .DB $06 << 2 HBX_IV07: CALL HBX_INT \ .DB $07 << 2 HBX_IV08: CALL HBX_INT \ .DB $08 << 2 HBX_IV09: CALL HBX_INT \ .DB $09 << 2 HBX_IV0A: CALL HBX_INT \ .DB $0A << 2 HBX_IV0B: CALL HBX_INT \ .DB $0B << 2 HBX_IV0C: CALL HBX_INT \ .DB $0C << 2 HBX_IV0D: CALL HBX_INT \ .DB $0D << 2 HBX_IV0E: CALL HBX_INT \ .DB $0E << 2 HBX_IV0F: CALL HBX_INT \ .DB $0F << 2 ; #ENDIF ; INT_IM1: #IF (INTMODE == 1) CALL HBX_INT .DB $00 #ELSE RETI ; UNEXPECTED INT, RET W/ INTS LEFT DISABLED #ENDIF ; #IF (INTMODE > 0) ; ; COMMON INTERRUPT DISPATCHING CODE ; SETUP AND CALL HANDLER IN BIOS BANK ; HBX_INT: ; COMMON INTERRUPT ROUTING CODE ; EX (SP),HL ; SAVE HL AND GET INT JP TABLE OFFSET LD (HBX_INT_SP),SP ; SAVE ORIGINAL STACK FRAME LD SP,HBX_STACK ; USE STACK FRAME IN HI MEM ; SAVE STATE (HL SAVED PREVIOUSLY ON ORIGINAL STACK FRAME) PUSH AF ; SAVE AF PUSH BC ; SAVE BC PUSH DE ; SAVE DE PUSH IY ; SAVE IY LD A,BID_BIOS ; HBIOS BANK CALL HBX_BNKSEL_INT ; SELECT IT LD L,(HL) ; OFFSET INTO JP TABLE FOR THIS INT LD H,HB_IVT >> 8 ; MSB OF HBIOS INT JP TABLE CALL JPHL ; CALL HANDLER VIA INT JP TABLE LD A,(HB_CURBNK) ; GET PRE-INT BANK CALL HBX_BNKSEL ; SELECT IT ; RESTORE STATE POP IY ; RESTORE IY POP DE ; RESTORE DE POP BC ; RESTORE BC POP AF ; RESTORE AF LD SP,$FFFF ; RESTORE ORIGINAL STACK FRAME HBX_INT_SP .EQU $ - 2 POP HL ; RESTORE HL HB_EI ; ENABLE INTERRUPTS RETI ; AND RETURN ; #ENDIF ; ; FILL TO START OF BOUNCE BUFFER ; HBX_INTFILL .EQU (HBX_XFC - HBX_BUFSIZ - $) .ECHO "HBIOS INT space remaining: " .ECHO HBX_INTFILL .ECHO " bytes.\n" .FILL HBX_INTFILL,$FF ; ; INTERBANK COPY BUFFER (64 BYTES) ; HBX_BUF .FILL HBX_BUFSIZ,0 ; ; HBIOS PROXY MGMT BLOCK (TOP 32 BYTES) ; #IFDEF ROMBOOT .DB BID_BOOT ; CURRENTLY ACTIVE LOW MEMORY BANK ID #ELSE .DB BID_USR ; CURRENTLY ACTIVE LOW MEMORY BANK ID #ENDIF .DB 0 ; BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION .DW 0 ; BNKCPY SOURCE ADDRESS .DB BID_USR ; BNKCPY SOURCE BANK ID .DW 0 ; BNKCPY DESTINATION ADDRESS .DB BID_USR ; BNKCPY DESTINATION BANK ID .DW 0 ; BNKCPY LENGTH .FILL 6,0 ; FILLER, RESERVED FOR FUTURE HBIOS USE JP HBX_INVOKE ; FIXED ADR ENTRY FOR HBX_INVOKE (ALT FOR RST 08) JP HBX_BNKSEL ; FIXED ADR ENTRY FOR HBX_BNKSEL JP HBX_BNKCPY ; FIXED ADR ENTRY FOR HBX_BNKCPY JP HBX_BNKCALL ; FIXED ADR ENTRY FOR HBX_BNKCALL .DW HBX_IDENT ; ADDRESS OF HBIOS PROXY START (DEPRECATED) .DW HBX_IDENT ; ADDRESS OF HBIOS IDENT INFO DATA BLOCK ; .FILL $MEMTOP - $ ; FILL TO END OF MEMORY (AS NEEDED) .ORG HBX_IMG + HBX_SIZ ; RESET ORG ; ;================================================================================================== ; HBIOS CORE ;================================================================================================== ; ;================================================================================================== ; ENTRY VECTORS (JUMP TABLE) AND INTERNAL PROCESSING STACK ;================================================================================================== ; HB_ENTRYTBL .EQU $ ; JP HB_START ; HBIOS INITIALIZATION JP HB_DISPATCH ; VECTOR TO DISPATCHER ; HB_STKSIZ .EQU HB_ENTRYTBL + 256 - $ ; .FILL HB_STKSIZ,$FF ; USE REMAINDER OF PAGE FOR HBIOS STACK HB_STACK .EQU $ ; TOP OF HBIOS STACK ; ;================================================================================================== ; INTERRUPT VECTOR TABLE (MUST START AT PAGE BOUNDARY!!!) ;================================================================================================== ; ; IM1 INTERRUPTS ARRIVE HERE AFTER BANK SWITCH TO HBIOS BANK ; LIST OF IM1 INT CALLS IS BUILT DYNAMICALLY BELOW ; SEE HB_ADDIM1 ROUTINE ; EACH ENTRY WILL LOOK LIKE: ; CALL XXXX ; CALL INT HANDLER ; RET NZ ; RETURN IF HANDLED ; ; NOTE THAT THE LIST IS INITIALLY FILLED WITH CALLS TO HB_BADINT. ; AS THE TABLE IS POPULATED, THE ADDRESS OF HB_BADINT IS OVERLAID ; WITH THE ADDRESS OF A REAL INTERRUPT HANDLER. ; ; THERE IS ROOM FOR 8 ENTRIES PLUS A FINAL CALL TO HB_BADINT. ; #IF (INTMODE < 2) ; HB_IVT: CALL HB_BADINT \ RET NZ CALL HB_BADINT \ RET NZ CALL HB_BADINT \ RET NZ CALL HB_BADINT \ RET NZ CALL HB_BADINT \ RET NZ CALL HB_BADINT \ RET NZ CALL HB_BADINT \ RET NZ CALL HB_BADINT \ RET NZ CALL HB_BADINT \ RET NZ ; #ENDIF ; ; IM2 INTERRUPTS ARRIVE HERE AFTER BANK SWITCH TO HBIOS BANK ; THE LIST OF JP TABLE ENTRIES MATCHES THE IM2 VECTORS ONE FOR ; ONE. ANY CALL TO THE PRIMARY IVT (HBX_IVT) WILL BE MAPPED TO ; THE CORRESPONDING JP TABLE ENTRY BELOW AFTER THE BANK SWITCH. ; ; NOTE THAT THE LIST IS INITIALLY FILLED WITH CALLS TO HB_BADINT. ; IT IS INTENDED THAT HARDWARE DRIVERS WILL DYNAMICALLY OVERLAY ; THE ADDRESS PORTION OF THE APPROPRIATE JP TO POINT TO THE ; DESIRED INTERRUPT HANDLER DURING THE DRIVERS INITIALIZATION. ; ; NOTE THAT EACH ENTRY HAS A FILLER BYTE OF VALUE ZERO. THIS BYTE ; HAS NO FUNCTION. IT IS JUST USED TO MAKE ENTRIES AN EVEN 4 BYTES. ; #IF (INTMODE == 2) ; HB_IVT: HB_IVT00: JP HB_BADINT \ .DB 0 HB_IVT01: JP HB_BADINT \ .DB 0 HB_IVT02: JP HB_BADINT \ .DB 0 HB_IVT03: JP HB_BADINT \ .DB 0 HB_IVT04: JP HB_BADINT \ .DB 0 HB_IVT05: JP HB_BADINT \ .DB 0 HB_IVT06: JP HB_BADINT \ .DB 0 HB_IVT07: JP HB_BADINT \ .DB 0 HB_IVT08: JP HB_BADINT \ .DB 0 HB_IVT09: JP HB_BADINT \ .DB 0 HB_IVT0A: JP HB_BADINT \ .DB 0 HB_IVT0B: JP HB_BADINT \ .DB 0 HB_IVT0C: JP HB_BADINT \ .DB 0 HB_IVT0D: JP HB_BADINT \ .DB 0 HB_IVT0E: JP HB_BADINT \ .DB 0 HB_IVT0F: JP HB_BADINT \ .DB 0 ; #ENDIF ; ;================================================================================================== ; SYSTEM INITIALIZATION ;================================================================================================== ; HB_START: DI ; NO INTERRUPTS IM 1 ; INTERRUPT MODE 1 ; #IF (DIAGENABLE) LD A,%00000001 OUT (DIAGPORT),A #ENDIF ; LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY ; #IF (CPUFAM == CPU_Z180) ; SET BASE FOR CPU IO REGISTERS LD A,Z180_BASE OUT0 (Z180_ICR),A DIAG(%00000010) ; DISABLE REFRESH XOR A OUT0 (Z180_RCR),A ; MASK OFF TIMER INTERRUPTS XOR A OUT0 (Z180_TCR),A ; SET DEFAULT CPU CLOCK MULTIPLIERS (XTAL / 2) ; ; IT HAS BEEN REPORTED THAT CMR NEEDS TO BE SET PRIOR TO CCR ; SEEMS COUNTER-INTUITIVE AND I NEVER EXPERIENCED A PROBLEM ; RELATED TO ORDER, BUT JUST FOR GOOD MEASURE, CMR ; IS SET PRIOR TO CCR BELOW. ; https://www.retrobrewcomputers.org/forum/index.php?t=msg&th=316&#msg_5045 XOR A OUT0 (Z180_CMR),A OUT0 (Z180_CCR),A ; SET DEFAULT WAIT STATES LD A,$F0 OUT0 (Z180_DCNTL),A #IF ((MEMMGR == MM_Z180) | (MEMMGR == MM_N8)) ; Z180 MMU SETUP LD A,$80 OUT0 (Z180_CBAR),A ; SETUP FOR 32K/32K BANK CONFIG ;#IFDEF ROMBOOT ; XOR A ; OUT0 (Z180_BBR),A ; BANK BASE = 0 ;#ENDIF LD A,(RAMSIZE + RAMBIAS - 64) >> 2 OUT0 (Z180_CBR),A ; COMMON BASE = LAST (TOP) BANK #ENDIF ; #ENDIF ; #IF (MEMMGR == MM_Z2) ; SET PAGING REGISTERS #IFDEF ROMBOOT XOR A OUT (MPGSEL_0),A INC A OUT (MPGSEL_1),A #ENDIF LD A,62 OUT (MPGSEL_2),A INC A OUT (MPGSEL_3),A ; ENABLE PAGING LD A,1 OUT (MPGENA),A #ENDIF ; DIAG(%00000011) LED($00) ; ; CHECK BATTERY BACKUP STATUS BEFORE WE COPY PROXY TO UPPER MEMORY ; ; IF A DS1210 POWER CONTROLLER IS INSTALLED AND BATTERY BACKUP IS NOT INSTALLED ; OR IS LESS THAN 2V THEN THE DS1210 WILL BLOCK THE SECOND RAM ACCESS. ; FAILURE TO COMPLETE TWO RAM ACCESSES BEFORE INSTALLING PROXY WILL RESULT ; IN THE ROM ID BYTES NOT BEING COPIED CORRECTLY AND CP/M APPLICATIONS ; WILL NOT START CORRECTLY WHEN THEY CHECK THE ROM ID VERSION BYTES. ; THE BATTERY CONDITION VALUE IS TEMPORARILY STORED AT HBX_LOC - 1. ; IF THERE IS NO DS1210 IN THE SYSTEM, THE CODE BELOW DOES NO HARM. ; DEC SP ; RESERVE A STACK BYTE XOR A ; ZERO MEANS LOW BAT LD (HBX_LOC - 1),A ; WRITE IT (SHOULD ALWAYS WORK) INC A ; 1 MEANS BAT OK LD (HBX_LOC - 1),A ; OVERWRITE IF NVC ALLOWS IT ; ; INSTALL PROXY IN UPPER MEMORY ; LD DE,HBX_LOC ; AS PER ABOVE LD HL,HBX_IMG LD BC,HBX_SIZ LDIR ; ; IF ALREADY EXECUTING IN RAM, BYPASS RAM BANK INSTALLATION ; LD A,(HB_RAMFLAG) OR A JR NZ,HB_START1 ; ; INSTALL HBIOS IN RAM BANK ; LD A,(HB_CURBNK) LD (HB_SRCBNK),A LD A,BID_BIOS LD (HB_DSTBNK),A LD HL,0 LD DE,0 LD BC,$8000 CALL HBX_BNKCPY ; ; TRANSITION TO HBIOS IN RAM BANK ; LD A,BID_BIOS ; BIOS BANK ID LD HL,HB_START1 ; EXECUTION RESUMES HERE CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN HALT ; WE SHOULD NOT COME BACK HERE! ; HB_RAMFLAG .DB FALSE ; INITIALLY FALSE, SET TO TRUE BELOW AFTER RAM TRANSITION ; ; EXECUTION RESUMES HERE AFTER SWITCH TO RAM BANK ; HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK ; DIAG(%00000111) ; LD A,(HBX_LOC - 1) ; RECALL BATTERY STATE AND SAVE LD (HB_BATCOND),A ; FOR FUTURE REFERENCE ; LD SP,HBX_LOC ; RESET STACK SINCE WE DO NOT RETURN LD A,TRUE ; ACCUM := TRUE LD (HB_RAMFLAG),A ; SET RAMFLAG ; ; IF APPBOOT, WE NEED TO FIX UP A FEW THINGS IN PAGE ZERO ; #IFDEF APPBOOT ; MAKE SURE RST 08 VECTOR IS RIGHT LD A,$C3 LD ($0008),A LD HL,HB_INVOKE LD ($0009),HL ; ; MAKE SURE IM1 INT VECTOR IS RIGHT #IF (INTMODE == 1) ; JP INT_IM1 IF INTERRUPT MODE ACTIVE LD A,$C3 LD ($0038),A LD HL,INT_IM1 LD ($0039),HL #ELSE ; RETI ($ED, $4D) IF NON-INTERRUPT MODE LD HL,($0038) LD (HL),$ED INC HL LD (HL),$4D #ENDIF #ENDIF ; DIAG(%00001111) ; #IF (DSKYENABLE) LD HL,MSG_HBVER + 5 LD A,(DSKY_NUMS + RMJ) AND $7F LD (HL),A INC HL LD A,(DSKY_NUMS + RMN) AND $7F LD (HL),A INC HL LD A,(DSKY_NUMS + RUP) LD (HL),A LD HL,MSG_HBVER CALL DSKY_SHOWSEG #ENDIF ; #IF (WBWDEBUG == USEMIO) ; BUFFER OUTPUT UNTIL CALL MIO_INIT ; WE GET TO BOOT MESSAGE #ENDIF ; #IF 0 ; ; TEST DEBUG *************************************************************************************** ; PRTS("DEBUG-IVT$") LD DE,HB_IVT CALL DUMP_BUFFER CALL NEWLINE ; ; TEST DEBUG *************************************************************************************** ; #ENDIF ; ; DISCOVER CPU TYPE ; ; THIS CODE IS DERIVED FROM UNA BY JOHN COFFMAN ; ; 0: Z80 ; 1: Z80180 - ORIGINAL Z180 (EQUIVALENT TO HD64180) ; 2: Z8S180 - ORIGINAL S-CLASS, REV. K, AKA SL1960, NO ASCI BRG ; 3: Z8S180 - REVISED S-CLASS, REV. N, W/ ASCI BRG ; LD HL,0 ; L = 0 MEANS Z80 ; #IF (CPUFAM == CPU_Z180) ; ; TEST FOR ORIGINAL Z180 USING MLT LD DE,$0506 ; 5 X 6 MLT DE ; DE = 30 IF Z180 LD A,E ; CHECK IF MULTIPLY HAPPENED CP 30 JR NZ,HB_CPU1 ; IT IS A Z80 IF != 30 INC L ; FLAG Z80180 OR BETTER ; ; TEST FOR OLDER S-CLASS (REV K) IN0 A,(Z180_CCR) ; SUPPOSEDLY ONLY ON S-CLASS INC A ; FF -> 0 JR Z,HB_CPU1 INC L ; FLAG Z8S180 REV K (SL1960) OR BETTER ; ; TEST FOR NEWER S-CLASS (REV N) ; ON OLDER S-CLASS, ASCI TIME CONSTANT REG DOES NOT EXIST ; AND WILL ALWYAS READ BACK AS $FF OUT0 (Z180_ASTC1L),D ; D = 0 AT THIS POINT IN0 A,(Z180_ASTC1L) ; ASCI TIME CONSTANT REG INC A ; FF -> 0 JR Z,HB_CPU1 INC L ; FLAG Z8S180 REV N W/ ASCI BRG ; #ENDIF ; HB_CPU1: LD A,L LD (HB_CPUTYPE),A ; #IF (DSRTCENABLE) CALL DSRTC_PREINIT #ENDIF ; #IF (CPUFAM == CPU_Z180) ; ; AT BOOT, Z180 PHI IS OSC / 2 LD C,(CPUOSC / 2) / 1000000 LD DE,(CPUOSC / 2) / 1000 ; #IF (Z180_CLKDIV >= 1) LD A,(HB_CPUTYPE) ; GET CPU TYPE CP 2 ; Z8S180 REV K OR BETTER? JR C,HB_CPU2 ; IF NOT, NOT POSSIBLE! ; SET CLOCK DIVIDE TO 1 RESULTING IN FULL XTAL SPEED LD A,$80 OUT0 (Z180_CCR),A ; REFLECT SPEED CHANGE LD C,CPUOSC / 1000000 LD DE,CPUOSC / 1000 #ENDIF #IF (Z180_CLKDIV >= 2) LD A,(HB_CPUTYPE) ; GET CPU TYPE CP 3 ; Z8S180 REV N OR BETTER? JR C,HB_CPU2 ; IF NOT, NOT POSSIBLE! ; SET CPU MULTIPLIER TO 1 RESULTING IN XTAL * 2 SPEED ; ALSO SET CCR AGAIN BECAUSE OF REPORTS THAT CCR ; *MUST* BE SET AFTER CMR. LD A,$80 OUT0 (Z180_CMR),A ; CPU MULTIPLIER OUT0 (Z180_CCR),A ; CLOCK DIVIDE ; REFLECT SPEED CHANGE LD C,(CPUOSC * 2) / 1000000 LD DE,(CPUOSC * 2) / 1000 #ENDIF ; HB_CPU2: ; SAVE CPU SPEED IN CONFIG BLOCK LD A,C LD (CB_CPUMHZ),A LD (CB_CPUKHZ),DE ; #ENDIF ; DIAG(%00011111) ; ; PERFORM DYNAMIC CPU SPEED DERIVATION ; CALL HB_CPUSPD ; CPU SPEED DETECTION ; CALL DELAY_INIT ; INITIALIZE SPEED COMPENSATED DELAY FUNCTIONS ; #IF (CPUFAM == CPU_Z180) ; ; SET FINAL DESIRED WAIT STATES LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4) OUT0 (Z180_DCNTL),A ; #ENDIF ; #IF (INTMODE == 2) ; SETUP Z80 IVT AND INT MODE 2 LD A,HBX_IVT >> 8 ; SETUP HI BYTE OF IVT ADDRESS LD I,A ; ... AND PLACE IT IN I REGISTER #IF (CPUFAM == CPU_Z180) ; SETUP Z180 IVT XOR A ; SETUP LO BYTE OF IVT ADDRESS OUT0 (Z180_IL),A ; ... AND PLACE IN Z180 IL REGISTER #ENDIF IM 2 ; SWITCH TO INT MODE 2 #ENDIF ; #IF (PLATFORM == PLT_SBC) ; #IF (HTIMENABLE) ; SIMH TIMER ; #IF (INTMODE == 1) LD HL,HB_TIMINT CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST #ENDIF #ENDIF ; #ENDIF ; #IF (KIOENABLE) LD A,%11111001 ; RESET ALL DEVICES, SET DAISYCHAIN OUT (KIOBASE+$0E),A ; DO IT #ENDIF ; #IF (CTCENABLE) CALL CTC_PREINIT #ENDIF ; #IF (CPUFAM == CPU_Z180) ; #IF (INTMODE == 2) ; ; MASK ALL EXTERNAL INTERRUPTS FOR NOW LD A,$01 ; INT0 ENABLED, INT1-2 DISABLED OUT0 (Z180_ITC),A ; WRITE TO INT/TRAP CONTROL REGISTER ; ; SETUP Z180 TIMER0 INTERRUPT VECTOR IN IVT LD HL,HB_TIMINT LD (IVT(INT_TIM0)),HL ; Z180 TIMER 0 ; SETUP PERIODIC TIMER INTERRUPT ON TIMER 0 LD HL,(CB_CPUKHZ) ; 50HZ = 18432000 / 20 / 50 / X, SO X = CPU KHZ OUT0 (Z180_TMDR0L),L ; INITIALIZE TIMER 0 DATA REGISTER OUT0 (Z180_TMDR0H),H DEC HL ; RELOAD OCCURS *AFTER* ZERO OUT0 (Z180_RLDR0L),L ; INITIALIZE TIMER 0 RELOAD REGISTER OUT0 (Z180_RLDR0H),H LD A,%00010001 ; ENABLE TIMER0 INT AND DOWN COUNTING OUT0 (Z180_TCR),A ; #ENDIF ; #ENDIF ; ; INITIALIZE HEAP STORAGE ; ; INITIALIZE POINTERS LD HL,HB_END ; HEAP FOLLOWS HBIOS CODE LD (CB_HEAP),HL ; INIT HEAP BASE ADDRESS LD (CB_HEAPTOP),HL ; INIT HEAP TOP ADDRESS ; CLEAR HEAP LD BC,BNKTOP - HB_END ; MAX SIZE OF HEAP LD A,$FF ; FILL WITH $FF CALL FILL ; DO IT ; DIAG(%00111111) #IF 0 ; ; TEST DEBUG *************************************************************************************** ; CALL NEWLINE CALL REGDMP ; ; TEST DEBUG *************************************************************************************** ; #ENDIF ; ; PRE-CONSOLE INITIALIZATION ; LD A,FORCECON ; CALCULATE PRE-INIT TABLE ; A IS INDEX OF CONSOLE DEVICE ENTRY RLCA ; ENTRY THAT WE WANT TO ; A IS OFFSET OF CONSOLE DEVICE ENTRY LD DE,(PC_INITTBL) ; EXECUTE FIRST ; DE IS VALUE OF TOP ENTRY LD HL,PC_INITTBL ; HL IS ADDRESS OF TOP OF TABLE PUSH HL ; PUSH (1) TOP OF TABLE PUSH DE ; PUSH (2) VALUE OF TOP ENTRY PUSH HL ; PUSH (3) TOP OF TABLE CALL ADDHLA ; HL IS ADDRESS OF DESIRED CONSOLE ENTRY POP DE ; PLACE IT AT THE TOP OF THE ; POP (3) DE IS TOP OF TABLE PUSH HL ; TABLE BY SWAPPING IT ; PUSH (3) ADDRESS OF DESIRED CONSOLE ENTRY LDI ; WITH THE FIRST (DUMMY) ; COPY DESIRED ENTRY LDI ; ENTRY ; ... TO TOP OF TABLE POP HL ; POP (3) HL IS ADDRESS OF DESIRED CONSOLE ENTRY POP DE ; POP (2) DE IS VALUE OF ORIGINAL TOP ENTRY LD (HL),E ; SAVE DE OVER ORIGINAL ENTRY INC HL LD (HL),D LD B,PC_INITTBLLEN POP DE ; POP (1) DE IS ADDRESS OF TOP OF TABLE CALL CALLLIST ; PROCESS THE PRE-INIT CALL TABLE ; #IF 0 ; ; TEST DEBUG *************************************************************************************** ; CALL NEWLINE CALL REGDMP ; ; TEST DEBUG *************************************************************************************** ; #ENDIF ; DIAG(%01111111) LED($FF) ; ; PRIOR TO THIS POINT, CONSOLE I/O WAS NOT AVAILABLE UNLESS DIRECTED TO DEBUG OUTPUT I.E. XIO ; NOW THAT HBIOS IS READY, SET THE CONSOLE UNIT TO ACTIVATE CONSOLE I/O ; VIA HBIOS. ; XOR A ; INITIALLY, FIRST SERIAL UNIT IS CONSOLE LD (CB_CONDEV),A ; SAVE IT, ACTIVATES CONSOLE ON HBIOS #IF (WBWDEBUG == USEMIO) ; OUTPUT ANY CACHED DEBUG TEXT LD HL,MIOOUTPTR LD E,(HL) INC HL LD D,(HL) INC HL NXTMIO: LD A,(HL) CALL COUT INC HL LD A,L CP E JR NZ,NXTMIO LD A,H CP D JR NZ,NXTMIO ; CALL WRITESTR ; WRITESTR WILL WORK WILL ONLY PRINT UP TO FIRST $ #ENDIF ; #IF 0 ; ; TEST DEBUG *************************************************************************************** ; CALL NEWLINE2 PRTS("DEBUG+IVT$") LD DE,HB_IVT CALL DUMP_BUFFER ; ; TEST DEBUG *************************************************************************************** ; #ENDIF ; ; ANNOUNCE HBIOS ; CALL NEWLINE2 PRTX(STR_BANNER) ; DIAG(%11111111) ; ; IO PORT SCAN ; #IF 0 PSCN: LD C,0 ; IO PORT NUMBER LD B,0 ; LOOP COUNTER CALL NEWLINE PSCN1: CALL NEWLINE LD A,C CALL PRTHEXBYTE CALL PC_COLON CALL PC_SPACE CALL DELAY LD A,C LD (PSCNX),A PSCNX .EQU $ + 1 IN A,(0) CALL PRTHEXBYTE CALL PC_COMMA PUSH BC LD B,0 IN A,(C) POP BC CALL PRTHEXBYTE INC C DJNZ PSCN1 #ENDIF ; #IF 0 HB_SPDTST: CALL HB_CPUSPD ; CPU SPEED DETECTION CALL NEWLINE LD HL,(CB_CPUKHZ) CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA JR HB_SPDTST #ENDIF ; HB_EI ; INTERRUPTS SHOULD BE OK NOW ; ; DISPLAY PLATFORM INFORMATION ; CALL NEWLINE2 PRTX(STR_PLATFORM) ; LD A,(HB_CPUTYPE) ; GET CPU TYPE LD DE,HB_CPU_STR ; DISPLAY IT CALL PRTIDXDEA ; PRTS(" @ $") LD HL,(CB_CPUKHZ) CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA PRTS("MHz$") ; #IF (CPUFAM == CPU_Z180) PRTS(" IO=0x$") LD A,Z180_BASE CALL PRTHEXBYTE #ENDIF ; ; DISPLAY CPU CONFIG ; CALL NEWLINE #IF (CPUFAM == CPU_Z180) LD A,Z180_MEMWAIT #ELSE LD A,0 #ENDIF CALL PRTDECB CALL PRTSTRD .TEXT " MEM W/S, $" #IF (CPUFAM == CPU_Z180) LD A,Z180_IOWAIT + 1 #ELSE LD A,1 #ENDIF CALL PRTDECB CALL PRTSTRD .TEXT " I/O W/S$" #IF (INTMODE > 0) CALL PRTSTRD .TEXT ", INT MODE $" LD A,INTMODE CALL PRTDECB #ENDIF ; ; DISPLAY MEMORY CONFIG ; CALL NEWLINE ;CALL PRTSTRD ;.TEXT "MEMORY CONFIG: $" LD HL,ROMSIZE CALL PRTDEC CALL PRTSTRD .TEXT "KB ROM, $" LD HL,RAMSIZE CALL PRTDEC CALL PRTSTRD .TEXT "KB RAM$" ; ; LOW BATTERY DIAGNOSTIC MESSAGE ; #IF (BATCOND) LD A,(HB_BATCOND) OR A LD DE,STR_LOWBAT CALL Z,WRITESTR #ENDIF ; ; PERFORM DEVICE INITIALIZATION ; CALL NEWLINE LD B,HB_INITTBLLEN LD DE,HB_INITTBL CALL CALLLIST ; ; RECORD HEAP CURB AT THE CURRENT VALUE OF HEAP TOP. HEAP CURB ; MARKS THE POINT IN THE HEAP AFTER WHICH MEMORY IS RELEASED ; WHEN AN HBIOS RESET IS PEFORMED. ; LD HL,(CB_HEAPTOP) LD (HEAPCURB),HL ; ; NOW SWITCH TO CRT CONSOLE IF CONFIGURED ; #IF CRTACT ; ; BIOS IS CONFIGURED TO AUTO ACTIVATE CRT DEVICE. FIRST, ; CHECK TO SEE IF WE HAVE A VALID CRT DEVICE TO USE. ; LD A,(CB_CRTDEV) ; GET THE CRT DEVICE INC A ; INCREMENT TO TEST FOR $FF JR Z,INITSYS3 ; IF NO CRT DEVICE, BYPASS CONSOLE SWITCH ; ; IF PLATFORM HAS A CONFIG JUMPER, CHECK TO SEE IF IT IS JUMPERED. ; IF SO, BYPASS SWITCH TO CRT CONSOLE (FAILSAFE MODE) ; #IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2)) IN A,(RTCIO) ; RTC PORT, BIT 6 HAS STATE OF CONFIG JUMPER BIT 6,A ; BIT 6 HAS CONFIG JUMPER STATE JR Z,INITSYS3 ; Z=SHORTED, BYPASS CONSOLE SWITCH #ENDIF ; ; NOTIFY USER OF CONSOLE SWITCH ON BOOT CONSOLE CALL NEWLINE2 PRTX(STR_SWITCH) CALL NEWLINE ; ; SWITCH TO CRT CONSOLE LD A,(CB_CRTDEV) ; GET CRT DISPLAY DEVICE LD (CB_CONDEV),A ; SAVE IT AS ACTIVE CONSOLE DEVICE ; ; DISPLAY HBIOS BANNER ON NEW CONSOLE PRTX(STR_BANNER) #ENDIF ; INITSYS3: ; CALL PRTSUM ; PRINT UNIT/DEVICE SUMMARY TABLE ; ; CHAIN TO OS LOADER ; #IFDEF ROMBOOT ; PERFORM BANK CALL TO OS IMAGES BANK IN ROM LD A,BID_IMG0 ; CHAIN TO OS IMAGES BANK LD HL,0 ; ENTER AT ADDRESS 0 CALL HBX_BNKCALL ; GO THERE HALT ; WE SHOULD NEVER COME BACK! #ELSE ; COPY OS IMAGE: BID_USR: --> BID_USR:0 ;LD A,BID_USR ;LD (HB_SRCBNK),A ;LD (HB_DSTBNK),A ;LD HL,HB_END ;LD DE,0 ;LD BC,$8000 ;CALL HBX_BNKCPY LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY LD D,BID_USR ; D = DEST BANK = USER BANK LD E,BID_USR ; E = SRC BANK = USER BANK LD HL,$8000 ; HL = COPY LEN = ENTIRE BANK RST 08 ; DO IT LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY LD HL,HB_END ; COPY FROM END OF OF HBIOS LD DE,0 ; TO USER ADDRESS 0 RST 08 ; DO IT ; ; PERFORM BANK CALL TO USER BANK LD A,BID_USR ; CHAIN TO OS IMAGES BANK LD HL,0 ; ENTER AT ADDRESS 0 CALL HBX_BNKCALL ; GO THERE HALT ; WE SHOULD NEVER COME BACK! ; #ENDIF ; RET ; ; CALL A LIST OF ROUTINES POINTED TO BY DE OF LENGTH B. ; CALLLIST: LD A,(DE) LD L,A INC DE LD A,(DE) LD H,A INC DE PUSH DE PUSH BC CALL JPHL POP BC POP DE DJNZ CALLLIST CALLDUMMY: RET ; ;================================================================================================== ; TABLE OF PRE-CONSOLE INITIALIZATION ENTRY POINTS ;================================================================================================== PC_INITTBL: .DW CALLDUMMY ; RESERVED FOR FORCING PRIMARY CONSOLE #IF (ASCIENABLE) .DW ASCI_PREINIT #ENDIF #IF (UARTENABLE) .DW UART_PREINIT #ENDIF #IF (SIOENABLE) .DW SIO_PREINIT #ENDIF #IF (ACIAENABLE) .DW ACIA_PREINIT #ENDIF #IF (PIO_4P | PIO_ZP) .DW PIO_PREINIT #ENDIF #IF (UFENABLE) .DW UF_PREINIT #ENDIF PC_INITTBLLEN .EQU (($ - PC_INITTBL) / 2) ;================================================================================================== ; TABLE OF INITIALIZATION ENTRY POINTS ;================================================================================================== ; HB_INITTBL: #IF (CTCENABLE) .DW CTC_INIT #ENDIF #IF (SPKENABLE) .DW SPK_INIT ; AUDIBLE INDICATOR OF BOOT START #ENDIF #IF (AYENABLE) .DW AY_INIT ; AUDIBLE INDICATOR OF BOOT START #ENDIF #IF (ASCIENABLE) .DW ASCI_INIT #ENDIF #IF (UARTENABLE) .DW UART_INIT #ENDIF #IF (SIOENABLE) .DW SIO_INIT #ENDIF #IF (ACIAENABLE) .DW ACIA_INIT #ENDIF #IF (SIMRTCENABLE) .DW SIMRTC_INIT #ENDIF #IF (DSRTCENABLE) .DW DSRTC_INIT #ENDIF #IF (BQRTCENABLE) .DW BQRTC_INIT #ENDIF #IF (VDUENABLE) .DW VDU_INIT #ENDIF #IF (CVDUENABLE) .DW CVDU_INIT #ENDIF #IF (VGAENABLE) .DW VGA_INIT #ENDIF #IF (NECENABLE) .DW NEC_INIT #ENDIF #IF (TMSENABLE) .DW TMS_INIT #ENDIF #IF (DSKYENABLE) .DW DSKY_INIT #ENDIF #IF (MDENABLE) .DW MD_INIT #ENDIF #IF (FDENABLE) .DW FD_INIT #ENDIF #IF (RFENABLE) .DW RF_INIT #ENDIF #IF (IDEENABLE) .DW IDE_INIT #ENDIF #IF (PPIDEENABLE) .DW PPIDE_INIT #ENDIF #IF (SDENABLE) .DW SD_INIT #ENDIF #IF (HDSKENABLE) .DW HDSK_INIT #ENDIF #IF (PRPENABLE) .DW PRP_INIT #ENDIF #IF (PPPENABLE) .DW PPP_INIT #ENDIF #IF (PIO_4P | PIO_ZP) .DW PIO_INIT #ENDIF #IF (UFENABLE) .DW UF_INIT #ENDIF ; HB_INITTBLLEN .EQU (($ - HB_INITTBL) / 2) ; ;================================================================================================== ; IDLE ;================================================================================================== ; ;__________________________________________________________________________________________________ ; IDLE: PUSH AF PUSH BC PUSH DE PUSH HL PUSH IY #IF (FDENABLE) CALL FD_IDLE #ENDIF POP IY POP HL POP DE POP BC POP AF RET ; ;================================================================================================== ; BIOS FUNCTION DISPATCHER ;================================================================================================== ; ; MAIN BIOS FUNCTION ; B: FUNCTION ;__________________________________________________________________________________________________ ; HB_DISPATCH: ; #IF 0 ; *DEBUG* START ; CALL HB_DISPCALL ; DO THE WORK ; ; CHECK STACK INTEGRITY PUSH AF LD A,(HB_STACK - HB_STKSIZ + $08) CP $FF CALL NZ,PANIC LD A,$FF LD (HB_STACK - HB_STKSIZ + $08),A POP AF RET HB_DISPCALL: ; #ENDIF ; *DEBUG* END ; LD A,B ; REQUESTED FUNCTION IS IN B CP BF_CIO + $10 ; $00-$0F: CHARACTER I/O JP C,CIO_DISPATCH CP BF_DIO + $10 ; $10-$1F: DISK I/O JP C,DIO_DISPATCH CP BF_RTC + $10 ; $20-$2F: REAL TIME CLOCK (RTC) JP C,RTC_DISPATCH CP BF_EMU + $10 ; $30-$3F: EMULATION CALL C,PANIC ; OBSOLETE! CP BF_VDA + $10 ; $40-$4F: VIDEO DISPLAY ADAPTER JP C,VDA_DISPATCH CP BF_SYS ; SKIP TO BF_SYS VALUE AT $F0 CALL C,PANIC ; PANIC IF LESS THAN BF_SYS JP SYS_DISPATCH ; OTHERWISE SYS CALL CALL PANIC ; THIS SHOULD NEVER BE REACHED RET ; ;================================================================================================== ; CHARACTER I/O DEVICE FUNCTION DISPATCHER ;================================================================================================== ; ; ROUTE CALL TO SPECIFIED CHARACTER I/O DRIVER ; B: FUNCTION ; C: UNIT NUMBER ; CIO_DISPATCH: BIT 7,C ; CHECK FOR SPECIAL UNIT CODE CALL NZ,CIO_SPECIAL ; IF SO, HANDLE IT PUSH IY ; SAVE INCOMING IY LD IY,CIO_TBL ; POINT IY TO START OF DIO TABLE CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE POP IY ; RESTORE IY RET ; AND DONE ; ; SPECIAL HANDLING FOR DEDICATED UNIT CODES ; CIO_SPECIAL: ; FOR NOW, ONLY SPECIAL CODE IS A CONSOLE REQUEST ; SO JUST SWAP IN ACTIVE CONSOLE UNIT LD A,(CB_CONDEV) ; GET ACTIVE CONSOLE LD C,A ; OVERLAY UNIT CODE IN C RET ; AND REJOIN MAIN DISPATCH FLOW ; ; ADD AN ENTRY TO THE CIO UNIT TABLE (SEE HB_ADDENT FOR DETAILS) ; CIO_ADDENT: LD HL,CIO_TBL ; POINT TO CIO TABLE JP HB_ADDENT ; ... AND GO TO COMMON CODE ; ; HBIOS CHARACTER DEVICE UNIT TABLE ; ; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. ; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT ; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. ; TABLE - 3 CONTAINS THE NUMBER OF CIO FUNCTION IDS ; EACH ENTRY IS DEFINED AS: ; ; WORD DRIVER FUNCTION TABLE ADDRESS ; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) ; CIO_FNCNT .EQU 7 ; NUMBER OF CIO FUNCS (FOR RANGE CHECK) CIO_MAX .EQU 32 ; UP TO 32 UNITS CIO_SIZ .EQU CIO_MAX * 4 ; EACH ENTRY IS 4 BYTES ; .DB CIO_FNCNT ; CIO FUNCTION COUNT (FOR RANGE CHECK) .DB CIO_MAX ; MAX ENTRY COUNT TABLE PREFIX CIO_CNT .DB 0 ; ENTRY COUNT PREFIX CIO_TBL .FILL CIO_SIZ,0 ; SPACE FOR ENTRIES ; ;================================================================================================== ; DISK I/O DEVICE FUNCTION DISPATCHER ;================================================================================================== ; ; ROUTE CALL TO SPECIFIED DISK I/O DRIVER ; B: FUNCTION ; C: UNIT NUMBER ; DIO_DISPATCH: ; #IF 0 ; *DEBUG* START ; ; DUMP INCOMING CALL CALL NEWLINE PRTS("DIO>$") CALL REGDMP ; DUMP REGS, NONE DESTROYED ; ; DO THE ACTUAL DISPATCH PROCESSING CALL DIO_DISPCALL ; ; DUMP CALL RESULTS AND RETURN CALL NEWLINE PRTS("DIO<$") CALL REGDMP ; DUMP REGS, NONE DESTROYED RET ; #ENDIF ; *DEBUG* END ; DIO_DISPCALL: PUSH IY ; SAVE INCOMING IY LD IY,DIO_TBL ; POINT IY TO START OF DIO TABLE CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE POP IY ; RESTORE IY RET ; AND DONE ; ; ADD AN ENTRY TO THE DIO UNIT TABLE ; DIO_ADDENT: LD HL,DIO_TBL ; POINT TO DIO TABLE JP HB_ADDENT ; ... AND GO TO COMMON CODE ; ; HBIOS DISK DEVICE UNIT TABLE ; ; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. ; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT ; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. ; TABLE - 3 CONTAINS THE NUMBER OF DIO FUNCTION IDS ; EACH ENTRY IS DEFINED AS: ; ; WORD DRIVER FUNCTION TABLE ADDRESS ; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) ; DIO_FNCNT .EQU 12 ; NUMBER OF DIO FUNCS (FOR RANGE CHECK) DIO_MAX .EQU 16 ; UP TO 16 UNITS DIO_SIZ .EQU DIO_MAX * 4 ; EACH ENTRY IS 4 BYTES ; .DB DIO_FNCNT ; DIO FUNCTION COUNT (FOR RANGE CHECK) .DB DIO_MAX ; MAX ENTRY COUNT TABLE PREFIX DIO_CNT .DB 0 ; ENTRY COUNT PREFIX DIO_TBL .FILL DIO_SIZ,0 ; SPACE FOR ENTRIES ; ;================================================================================================== ; DISK READ HELPER ;================================================================================================== ; ; IMPLEMENTS MULTI SECTOR READS AND I/O TO/FROM ; BANKED RAM VIA BOUNCE BUFFER ; ; TOS=READ FN ADR ; HL=BUF ADR ; E=SEC COUNT ; D=BUF BANK ID ; HB_DSKREAD: ; ; THE ACTUAL SECTOR READ FUNCTION ADDRESS IS ON TOS, SAVE IT EX (SP),HL ; SAVE HL TO TOS, HL := READ FN ADR LD (HB_DSKFNADR),HL ; IMBED IN CALL OP BELOW POP HL ; RECOVER HL ; #IF (DIAGENABLE) ; SAVE DISK UNIT NUMBER BIT MASK LD A,C ; GET DISK UNIT NUMBER LD B,A ; PUT IN B FOR LOOP COUNTER INC B ; LOOP ONE EXTRA TIME TO HANDLE UNIT=0 XOR A ; START WITH ACCUM ZERO SCF ; ... AND CF SET HB_DSKREAD0: RLA ; ROTATE BIT DJNZ HB_DSKREAD0 ; ... UNTIL IN PROPER LOCATION LD (HB_DSKBIT),A ; SAVE IT FOR DIAGNOSTICS #ENDIF ; #IF 1 ; CHECK TO SEE IF INTER-BANK I/O NEEDED. BIT 7,H ; TGT BUF IN UPPER 32K? JP NZ,HB_DSKIO ; IF SO, NON-BANKED LD A,D ; GET TGT BANK CP BID_BIOS ; BIOS BANK? JP Z,HB_DSKIO ; IF SO, NON-BANKED #ENDIF ; #IF 1 ; RAM BANK RANGE CHECK LD A,D ; GET TGT BANK CP BID_RAMN ; BANK IN RANGE 0-N? CALL NC,PANIC ; IF >N, PANIC #ENDIF ; ; SAVE TGT BUF BNK/ADR LD (HB_IOBUF),HL LD A,D LD (HB_IOBNK),A ; ; SETUP READ AND LOOP COUNT LD B,E ; SEC LOOP COUNTER LD C,0 ; SEC COMPLETE COUNTER ; HB_DSKREAD1: LD HL,HB_WRKBUF ; USE WORK BUF REAL I/O ; ; CALL READ FN CALL HB_DSKFN ; READ ONE SECTOR ; ; IF FAIL, RETURN ERR JR NZ,HB_DSKREADX ; BAIL OUT ON ERROR ; ; BNKCPY SEC DATA TO REAL BANK/BUF & INC BUF ADR PUSH BC ; SAVE COUNTERS LD A,(HB_IOBNK) ; DEST BANK LD (HB_DSTBNK),A ; ... TO PROXY LD A,BID_BIOS ; SRC BANK LD (HB_SRCBNK),A ; ... TO PROXY LD BC,512 ; COPY 512 BYTES (1 SEC) LD DE,(HB_IOBUF) ; TGT BUFFER ADR LD HL,HB_WRKBUF ; SOURCE BUFFER CALL HBX_BNKCPY ; DO BANK COPY LD (HB_IOBUF),DE ; SAVE UPDATED TGT BUF ADR POP BC ; RESTORE COUNTERS ; ; INC READ COUNT INC C ; BUMP SEC READ COUNT DJNZ HB_DSKREAD1 ; LOOP AS NEEDED XOR A ; SIGNAL SUCCESS ; HB_DSKREADX: LD HL,(HB_IOBUF) ; NEXT BUF ADR JR HB_DSKIOX ; DONE ; ;================================================================================================== ; DISK WRITE HELPER ;================================================================================================== ; ; IMPLEMENTS MULTI SECTOR WRITES AND I/O TO/FROM ; BANKED RAM VIA BOUNCE BUFFER ; ; TOS=WRITE FN ADR ; HL=BUF ADR ; E=SEC COUNT ; D=BUF BANK ID ; HB_DSKWRITE: ; ; THE ACTUAL SECTOR READ FUNCTION ADDRESS IS ON TOS, SAVE IT EX (SP),HL ; SAVE HL TO TOS, HL := READ FN ADR LD (HB_DSKFNADR),HL ; IMBED IN CALL OP BELOW POP HL ; RECOVER HL ; #IF (DIAGENABLE) ; SAVE DISK UNIT NUMBER BIT MASK LD A,C ; GET DISK UNIT NUMBER LD B,A ; PUT IN B FOR LOOP COUNTER INC B ; LOOP ONE EXTRA TIME TO HANDLE UNIT=0 XOR A ; START WITH ACCUM ZERO SCF ; ... AND CF SET HB_DSKWRITE0: RLA ; ROTATE BIT DJNZ HB_DSKWRITE0 ; ... UNTIL IN PROPER LOCATION LD (HB_DSKBIT),A ; SAVE IT FOR DIAGNOSTICS #ENDIF ; #IF 1 ; CHECK TO SEE IF INTER-BANK I/O NEEDED. BIT 7,H ; TGT BUF IN UPPER 32K? JP NZ,HB_DSKIO ; IF SO, NON-BANKED LD A,D ; GET TGT BANK CP BID_BIOS ; BIOS BANK? JP Z,HB_DSKIO ; IF SO, NON-BANKED #ENDIF ; #IF 1 ; RAM BANK RANGE CHECK LD A,D ; GET TGT BANK CP BID_RAMN ; BANK IN RANGE 0-N? CALL NC,PANIC ; IF >N, PANIC #ENDIF ; ; SAVE TGT BUF BNK/ADR LD (HB_IOBUF),HL LD A,D LD (HB_IOBNK),A ; ; SETUP WRITE AND LOOP COUNT LD B,E ; SEC LOOP COUNTER LD C,0 ; SEC COMPLETE COUNTER ; HB_DSKWRITE1: ; BNKCPY SEC DATA TO WORK BANK/BUF & INC BUF ADR PUSH BC ; SAVE COUNTERS LD A,BID_BIOS ; DEST BANK LD (HB_DSTBNK),A ; ... TO PROXY LD A,(HB_IOBNK) ; SRC BANK LD (HB_SRCBNK),A ; ... TO PROXY LD BC,512 ; COPY 512 BYTES (1 SEC) LD DE,HB_WRKBUF ; TGT BUFFER ADR LD HL,(HB_IOBUF) ; SOURCE BUFFER CALL HBX_BNKCPY ; DO BANK COPY LD (HB_IOBUF),HL ; SAVE UPDATED SRC BUF ADR POP BC ; RESTORE COUNTERS ; ; CALL WRITE FN LD HL,HB_WRKBUF ; WRITE FROM WORK BUFFER CALL HB_DSKFN ; WRITE ONE SECTOR ; ; IF FAIL, RETURN ERR JR NZ,HB_DSKWRITEX ; BAIL OUT ON ERROR ; ; INC WRITE COUNT INC C ; BUMP SEC WRITE COUNT DJNZ HB_DSKWRITE1 ; LOOP AS NEEDED XOR A ; SIGNAL SUCCESS ; HB_DSKWRITEX: LD HL,(HB_IOBUF) ; NEXT BUF ADR JR HB_DSKIOX ; DONE ; ;================================================================================================== ; NON-BANKED DISK READ/WRITE ;================================================================================================== ; HB_DSKIO: ; ; SETUP LOOP COUNT LD B,E ; SEC LOOP COUNTER LD C,0 ; SEC COMPLETE COUNTER ; HB_DSKIO1: ; CALL READ/WRITE FN CALL HB_DSKFN ; READ/WRITE ONE SECTOR ; ; IF FAIL, RETURN ERR JR NZ,HB_DSKIOX ; BAIL OUT ON ERROR ; ; INC SECTOR COUNT INC C ; BUMP SEC READ/WRITE COUNT DJNZ HB_DSKIO1 ; LOOP AS NEEDED XOR A ; SIGNAL SUCCESS ; HB_DSKIOX: LD E,C ; WRITE COUNT TO E OR A ; SET RESULT FLAGS RET ; DONE ; HB_DSKFN: PUSH BC ; SAVE COUNTERS #IF (DIAGENABLE & DIAGDISKIO) LD A,(HB_DSKBIT) ; LOAD UNIT DISK BIT MASK OUT (DIAGPORT),A ; DISPLAY ON DIAG LEDS #ENDIF #IF (LEDENABLE & LEDDISKIO) LED($FF) #ENDIF LD E,1 ; ONE SECTOR HB_DSKFNADR .EQU $+1 CALL PANIC ; READ ONE SECTOR #IF (DIAGENABLE & DIAGDISKIO) DIAG(0) ; CLEAR DIAG LEDS #ENDIF #IF (LEDENABLE & LEDDISKIO) LED($00) #ENDIF POP BC ; RESTORE COUNTERS RET ; RETURN ; HB_DSKBIT .DB 0 ; ACTIVE DISK UNIT HB_IOBUF .DW 0 ; CURRENT IO BUFFER ADR HB_IOBNK .DB 0 ; CURRENT IO BUFFER BANK ID ; ;================================================================================================== ; REAL TIME CLOCK DEVICE DISPATCHER ;================================================================================================== ; ; ROUTE CALL TO REAL TIME CLOCK DRIVER ; B: FUNCTION ; RTC_DISPATCH: #IF (SIMRTCENABLE) JP SIMRTC_DISPATCH #ENDIF #IF (DSRTCENABLE) JP DSRTC_DISPATCH #ENDIF #IF (BQRTCENABLE) JP BQRTC_DISPATCH #ENDIF ;CALL PANIC OR $FF RET ; ;================================================================================================== ; VIDEO DISPLAY ADAPTER DEVICE DISPATCHER ;================================================================================================== ; ; ROUTE CALL TO SPECIFIED VDA DEVICE DRIVER ; B: FUNCTION ; C: UNIT NUMBER ; VDA_DISPATCH: PUSH IY ; SAVE INCOMING IY LD IY,VDA_TBL ; POINT IY TO START OF DIO TABLE CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE POP IY ; RESTORE IY RET ; AND DONE ; ; ADD AN ENTRY TO THE VDA UNIT TABLE (SEE HB_ADDENT FOR DETAILS) ; VDA_ADDENT: LD HL,VDA_TBL ; POINT TO VDA TABLE JP HB_ADDENT ; ... AND GO TO COMMON CODE ; ; HBIOS VIDEO DEVICE UNIT TABLE ; ; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. ; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT ; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. ; TABLE - 3 CONTAINS THE NUMBER OF CIO FUNCTION IDS ; EACH ENTRY IS DEFINED AS: ; ; WORD DRIVER FUNCTION TABLE ADDRESS ; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) ; VDA_FNCNT .EQU 15 ; NUMBER OF VDA FUNCS (FOR RANGE CHECK) VDA_MAX .EQU 16 ; UP TO 16 UNITS VDA_SIZ .EQU VDA_MAX * 4 ; EACH ENTRY IS 4 BYTES ; .DB VDA_FNCNT ; VDA FUNCTION COUNT (FOR RANGE CHECK) .DB VDA_MAX ; MAX ENTRY COUNT TABLE PREFIX VDA_CNT .DB 0 ; ENTRY COUNT PREFIX VDA_TBL .FILL VDA_SIZ,0 ; SPACE FOR ENTRIES ; ;================================================================================================== ; SYSTEM FUNCTION DISPATCHER ;================================================================================================== ; ; B: FUNCTION ; SYS_DISPATCH: LD A,B ; GET REQUESTED FUNCTION AND $0F ; ISOLATE SUB-FUNCTION JP Z,SYS_RESET ; $F0 DEC A JP Z,SYS_VER ; $F1 DEC A JP Z,SYS_SETBNK ; $F2 DEC A JP Z,SYS_GETBNK ; $F3 DEC A JP Z,SYS_SETCPY ; $F4 DEC A JP Z,SYS_BNKCPY ; $F5 DEC A JP Z,SYS_ALLOC ; $F6 DEC A JP Z,SYS_FREE ; $F7 DEC A JP Z,SYS_GET ; $F8 DEC A JP Z,SYS_SET ; $F9 DEC A JP Z,SYS_PEEK ; $FA DEC A JP Z,SYS_POKE ; $FB DEC A JP Z,SYS_INT ; $FC CALL PANIC ; INVALID ; ; SOFT RESET HBIOS, RELEASE HEAP MEMORY NOT USED BY HBIOS ; SYS_RESET: LD HL,(HEAPCURB) ; GET HBIOS HEAP THRESHOLD LD (CB_HEAPTOP),HL ; RESTORE HEAP TOP XOR A RET ; ; GET THE CURRENT HBIOS VERSION ; ON INPUT, C=0 ; RETURNS VERSION IN DE AS BCD ; D: MAJOR VERION IN TOP 4 BITS, MINOR VERSION IN LOW 4 BITS ; E: UPDATE VERION IN TOP 4 BITS, PATCH VERSION IN LOW 4 BITS ; L: PLATFORM ID ; SYS_VER: LD DE,0 | (RMJ << 12) | (RMN << 8) | (RUP << 4) | RTP LD L,PLATFORM XOR A RET ; ; SET ACTIVE MEMORY BANK AND RETURN PREVIOUSLY ACTIVE MEMORY BANK ; NOTE THAT IT GOES INTO EFFECT AS HBIOS FUNCTION IS EXITED ; HERE, WE JUST SET THE CURRENT BANK ; CALLER MUST EXTABLISH UPPER MEMORY STACK BEFORE INVOKING THIS FUNCTION! ; SYS_SETBNK: PUSH HL ; SAVE INCOMING HL LD HL,HB_INVBNK ; POINT TO HBIOS INVOKE BANK ID ADDRESS LD A,(HL) ; GET EXISTING BANK ID TO A LD (HL),C ; UPDATE INVOKE BANK TO NEW BANK ID LD C,A ; PUT PREVIOUS BANK ID IN C FOR RETURN POP HL ; RESTORE ORIGINAL HL XOR A ; SIGNAL SUCCESS RET ; DONE ; ; GET ACTIVE MEMORY BANK ; SYS_GETBNK: LD A,(HB_INVBNK) ; GET THE ACTIVE MEMORY BANK LD C,A ; MOVE TO C XOR A ; SIGNAL SUCCESS RET ; ; SET BANKS AND LENGTH FOR INTERBANK MEMORY COPY (BNKCPY) ; ENTRY: E=SOURCE BANK ID ; D=DEST BANK ID ; HL=COPY LENGTH (IN BYTES) ; SYS_SETCPY: LD A,E LD (HB_SRCBNK),A ; RECORD THE SOURCE BANK LD A,D LD (HB_DSTBNK),A ; RECORD THE DESTINATION BANK LD (HB_CPYLEN),HL ; RECORD THE COPY LENGTH XOR A RET ; ; PERFORM MEMORY COPY POTENTIALLY ACROSS BANKS ; ENTRY: HL=SOURCE ADDRESS ; DE=DESTINATION ADDRESS ; NOTE: SRC/DEST BANK & COPY LENGTH MUST BE SET VIA SETCPY ; SYS_BNKCPY: PUSH HL ; SAVE INCOMING HL LD HL,(HB_CPYLEN) ; HL := COPY LEN (SAVED IN SETCPY) EX (SP),HL ; RESTORE HL & SET (SP) TO COPY LEN POP BC ; BC := COPY LEN #IF (INTMODE == 1) DI #ENDIF CALL HB_BNKCPY #IF (INTMODE == 1) EI #ENDIF XOR A RET ; ; ALLOCATE HL BYTES OF MEMORY FROM HBIOS HEAP ; RETURNS POINTER TO ALLOCATED MEMORY IN HL ; ON SUCCESS RETURN A == 0, AND Z SET ; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED ; ALL OTHER REGISTERS PRESERVED ; SYS_ALLOC: JP HB_ALLOC ; ; FREE HEAP MEMORY BY SIMPLY RELEASING ALL ; MEMORY BEYOND POINTER IN HL. ; ON SUCCESS RETURN A == 0, AND Z SET ; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED ; ALL OTHER REGISTERS PRESERVED ; SYS_FREE: CALL PANIC ; NOT YET IMPLEMENTED OR $FF RET ; ; GET SYSTEM INFORMATION ; ITEM TO RETURN INDICATED IN C ; SYS_GET: LD A,C ; GET REQUESTED SUB-FUNCTION CP BF_SYSGET_CIOCNT JR Z,SYS_GETCIOCNT CP BF_SYSGET_DIOCNT JR Z,SYS_GETDIOCNT CP BF_SYSGET_VDACNT JR Z,SYS_GETVDACNT CP BF_SYSGET_TIMER JR Z,SYS_GETTIMER CP BF_SYSGET_SECS JR Z,SYS_GETSECS CP BF_SYSGET_BOOTINFO JR Z,SYS_GETBOOTINFO CP BF_SYSGET_CPUINFO JR Z,SYS_GETCPUINFO CP BF_SYSGET_MEMINFO JR Z,SYS_GETMEMINFO CP BF_SYSGET_BNKINFO JR Z,SYS_GETBNKINFO OR $FF ; SIGNAL ERROR RET ; ; GET TIMER ; RETURNS: ; DE:HL: TIMER VALUE (32 BIT) ; SYS_GETTIMER: LD HL,HB_TICKS HB_DI CALL LD32 HB_EI XOR A RET ; ; GET SECONDS ; RETURNS: ; DE:HL: SECONDS VALUE (32 BIT) ; C: NUM TICKS WITHIN CURRENT SECOND ; SYS_GETSECS: LD HL,HB_SECS HB_DI CALL LD32 LD A,(HB_SECTCK) HB_EI NEG ; CONVERT DOWNCOUNTER TO UPCOUNTER ADD A,TICKSPERSEC LD C,A XOR A RET ; ; GET BOOT INFORMATION ; RETURNS: ; L: BOOT BANK ID ; DE: BOOT DISK VOLUME (UNIT/SLICE) ; SYS_GETBOOTINFO: LD A,(CB_BOOTBID) LD L,A LD DE,(CB_BOOTVOL) XOR A RET ; ; GET CPU INFORMATION ; RETURNS: ; H: Z80 CPU VARIANT ; L: CPU SPEED IN MHZ ; DE: CPU SPEED IN KHZ ; SYS_GETCPUINFO: LD A,(HB_CPUTYPE) LD H,A LD A,(CB_CPUMHZ) LD L,A LD DE,(CB_CPUKHZ) XOR A RET ; ; GET MEMORY INFORMATION ; RETURNS: ; D: COUNT OF ROM BANKS ; E: COUNT OF RAM BANKS ; SYS_GETMEMINFO: LD D,ROMSIZE / 32 LD E,RAMSIZE / 32 XOR A RET ; ; GET BANK CONFIGURATION INFORMATION ; RETURNS: ; D: HBIOS BANK ID ; E: USER BANK ID ; SYS_GETBNKINFO: LD A,(CB_BIDBIOS) LD D,A LD A,(CB_BIDUSR) LD E,A XOR A RET ; ; GET SERIAL UNIT COUNT ; SYS_GETCIOCNT: LD A,(CIO_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) LD E,A ; PUT IT IN E XOR A ; SIGNALS SUCCESS RET ; ; GET DISK UNIT COUNT ; SYS_GETDIOCNT: LD A,(DIO_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) LD E,A ; PUT IT IN E XOR A ; SIGNALS SUCCESS RET ; ; GET VIDEO UNIT COUNT ; SYS_GETVDACNT: LD A,(VDA_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) LD E,A ; PUT IT IN E XOR A ; SIGNALS SUCCESS RET ; ; SET SYSTEM PARAMETERS ; PARAMETER(S) TO SET INDICATED IN C ; SYS_SET: LD A,C ; GET REQUESTED SUB-FUNCTION CP BF_SYSSET_TIMER JR Z,SYS_SETTIMER CP BF_SYSSET_SECS JR Z,SYS_SETSECS CP BF_SYSSET_BOOTINFO JR Z,SYS_SETBOOTINFO OR $FF ; SIGNAL ERROR RET ; ; SET BOOT INFORMATION ; ON ENTRY: ; L: BOOT BANK ID ; DE: BOOT DISK VOLUME (UNIT/SLICE) ; SYS_SETBOOTINFO: LD A,L LD (CB_BOOTBID),A LD (CB_BOOTVOL),DE XOR A RET ; ; SET TIMER ; ON ENTRY: ; DE:HL: TIMER VALUE (32 BIT) ; SYS_SETTIMER: LD BC,HB_TICKS HB_DI CALL ST32 HB_EI XOR A RET ; ; SET SECS ; ON ENTRY: ; DE:HL: SECONDS VALUE (32 BIT) ; SYS_SETSECS: LD BC,HB_SECS HB_DI CALL ST32 HB_EI XOR A RET ; ; RETURN A BYTE OF MEMORY FROM SPECIFIED BANK ; ENTRY: D=BANK ID, HL=ADDRESS ; RETURN: E=BYTE VALUE ; SYS_PEEK: #IF (INTMODE == 1) DI #ENDIF CALL HBX_PEEK ; IMPLEMENTED IN PROXY #IF (INTMODE == 1) EI #ENDIF XOR A RET ; ; WRITE A BYTE OF MEMORY TO SPECIFIED BANK ; ENTRY: D=BANK ID, HL=ADDRESS IN HBIOS BANK, E=BYTE VALUE ; SYS_POKE: #IF (INTMODE == 1) DI #ENDIF CALL HBX_POKE ; IMPLEMENTED IN PROXY #IF (INTMODE == 1) EI #ENDIF XOR A RET ; ; INTERRUPT MANAGEMENT FUNCTIONS ; SUBFUNCTION IN C ; SYS_INT: LD A,C ; GET REQUESTED SUB-FUNCTION CP BF_SYSINT_INFO JR Z,SYS_INTINFO CP BF_SYSINT_GET JR Z,SYS_INTGET CP BF_SYSINT_SET JR Z,SYS_INTSET OR $FF ; SIGNAL ERROR RET ; ; GET INTERRUPT SYSTEM INFORMATION ; RETURN D:=INTERRUPT MODE, E:=INT VEC TABLE SIZE ; SYS_INTINFO: LD D,INTMODE ; D := ACTIVE INTERRUPT MODE #IF (INTMODE == 0) LD E,0 ; 0 ENTRIES IF INTERRUPTS DISABLED #ENDIF #IF (INTMODE == 1) LD A,(HB_IM1CNT) ; RETURN IM1 CALL LIST SIZE LD E,A #ENDIF #IF (INTMODE == 2) LD E,HBX_IVTCNT ; RETURN INT VEC TABLE SIZE #ENDIF XOR A ; INDICATE SUCCESS RET ; AND DONE ; ; ROUTINE SHARED BY INT GET/SET. RETURNS ADDRESS OF VECTOR FOR SPECIFIED LIST / TABLE ; POSITION. ZF SET ON RETURN FOR SUCCESS, ELSE ERROR. ; SYS_INTVECADR: #IF (INTMODE == 0) CALL PANIC ; INVALID FOR INT MODE 0 OR $FF RET #ENDIF #IF (INTMODE == 1) LD A,(HB_IM1CNT) ; GET CURRENT ENTRY COUNT INC A ; ALLOW FOR EXTRA ENTRY TO APPEND AT END LD C,A ; SAVE IN C FOR COMPARE #ENDIF #IF (INTMODE == 2) LD C,HBX_IVTCNT ; GET CURRENT ENTRY COUNT #ENDIF LD A,E ; INCOMING INDEX POSITION TO A CP C ; COMPARE TO VECTOR COUNT JR C,SYS_INTGET1 ; CONTINUE IF POSITION IN RANGE CALL PANIC ; ELSE ERROR OR $FF RET SYS_INTGET1: OR A ; CLEAR CARRY RLA ; ADJUST FOR TABLE ENTRY RLA ; SIZE OF 4 BYTES INC A ; BUMP TO ADR FIELD LD H,0 LD L,A LD DE,HB_IVT ; DE := START OF VECTOR TABLE ADD HL,DE ; HL := ADR OF VECTOR XOR A ; INDICATE SUCCESS RET ; ; RETURN THE INTERRUPT VECTOR FOR A SPECIFIED POSITION IN THE INT VECTOR LIST / TABLE ; ENTRY: E=LIST/TABLE POSITION ; RETURN: HL=INTERRUPT VECTOR ; SYS_INTGET: CALL SYS_INTVECADR ; GET VECTOR ADDRESS RET NZ ; BAIL OUT ON ERROR LD A,(HL) ; DEREF HL TO GET VECTOR INC HL LD H,(HL) LD L,A XOR A ; SIGNAL SUCCESS RET ; DONE ; ; SET AN INTERRUPT VECTOR FOR A SPECIFIED POSITION IN THE INT VECTOR LIST / TABLE ; ENTRY: E=LIST/TABLE POSITION, HL=NEW INTERRUPT VECTOR ; RETURN: HL=PREVIOUS INTERRUPT VECTOR, DE=ADR OF INT ROUTING ENGINE FOR IM2 ; SYS_INTSET: PUSH HL ; SAVE NEW VECTOR CALL SYS_INTVECADR ; GET VECTOR ADDRESS JR Z,SYS_INTSET1 ; CONTINUE IF OK POP HL ; FIX STACK RET NZ ; BAIL OUT ON ERROR SYS_INTSET1: PUSH HL ; SAVE VECTOR ADDRESS LD A,(HL) ; DEREF HL TO GET PREV VECTOR INC HL LD H,(HL) LD L,A EX (SP),HL ; (SP) := PREV VEC, HL := VEC ADR POP DE ; DE := PREV VEC POP BC ; BC := NEW VEC LD (HL),C ; SAVE LSB INC HL LD (HL),B ; SAVE MSB EX DE,HL ; HL := PREV VEC ;#IF (INTMODE == 2) ; LD DE,HBX_INT ; DE := IM2 INT ROUTING ENGINE ;#ENDIF XOR A ; SIGNAL SUCCESS RET ; DONE ; ;================================================================================================== ; GLOBAL HBIOS FUNCTIONS ;================================================================================================== ; ; COMMON ROUTINE THAT IS CALLED BY CHARACTER IO DRIVERS WHEN ; AN IDLE CONDITION IS DETECTED (WAIT FOR INPUT/OUTPUT) ; CIO_IDLE: PUSH AF ; PRESERVE AF LD A,(IDLECOUNT) ; GET CURRENT IDLE COUNT DEC A ; DECREMENT LD (IDLECOUNT),A ; SAVE UPDATED VALUE CALL Z,IDLE ; IF ZERO, DO IDLE PROCESSING POP AF ; RECOVER AF RET ; #IF (INTMODE == 1) ; ; ROUTINE BELOW IS USED TO ADD A NEW VECTOR TO THE IM1 ; CALL LIST ABOVE. ENTER WITH HL=VECTOR ADDRESS IN HBIOS ; HB_ADDIM1: EX DE,HL ; VECTOR ADDRESS TO DE LD HL,(HB_IM1PTR) ; GET PTR FOR NEXT ENTRY INC HL ; BUMP PTR TO ADDRESS FIELD OF CALL OPCODE LD (HL),E ; ADD VECTOR ADDRESS INC HL ; ... LD (HL),D ; ... INC HL ; BUMP PTR INC HL ; BUMP PTR LD (HB_IM1PTR),HL ; SAVE UPDATED POINTER LD HL,HB_IM1CNT ; POINT TO ENTRY COUNT INC (HL) ; INCREMENT RET ; DONE ; HB_IM1CNT .DB 0 ; NUMBER OF ENTRIES IN CALL LIST HB_IM1MAX .DB 8 ; MAX ENTRIES IN CALL LIST HB_IM1PTR .DW HB_IVT ; POINTER FOR NEXT IM1 ENTRY ; #ENDIF ; ; TIMER INTERRUPT ; HB_TIMINT: ; INCREMENT TICK COUNTER (32 BIT) LD HL,HB_TICKS ; POINT TO TICK COUNTER CALL INC32HL ; HB_TIMINT1: ; #IF 0 ; LD HL,TEMPCNT DEC (HL) JR NZ,HB_TIMINT2 LD (HL),250 ; LD A,'*' CALL COUT JR HB_TIMINT2 ; TEMPCNT .DB 250 ; #ENDIF ; HB_TIMINT2: LD HL,HB_SECTCK ; POINT TO SECONDS TICK COUNTER DEC (HL) ; COUNTDOWN 50 TICKS JR NZ,HB_TIMINT3 ; NOT ZERO YET, DONE FOR THIS CYCLE ; 50 TICKS HAVE ELAPSED LD A,TICKSPERSEC ; 50 TICKS PER SECOND LD (HL),A ; RESET COUNTDOWN REGISTER ; INCREMENT SECONDS COUNTER LD HL,HB_SECS ; POINT TO SECONDS COUNTER CALL INC32HL ; HB_TIMINT3: ; #IF (CPUFAM == CPU_Z180) ; ACK/RESET Z180 TIMER INTERRUPT IN0 A,(Z180_TCR) IN0 A,(Z180_TMDR0L) #ENDIF ; #IF (PLATFORM == PLT_EZZ80) ; PULSE WATCHDOG OUT (WDOGIO),A ; VALUE IS IRRELEVANT #ENDIF ; OR $FF ; NZ SET TO INDICATE INT HANDLED RET ; ; BAD INTERRUPT HANDLER ; HB_BADINT: #IF 0 ; *DEBUG* LD HL,HB_BADINTCNT INC (HL) LD A,(HL) OUT (DIAGPORT),A OR $FF RET HB_BADINTCNT .DB 0 #ENDIF ; *DEBUG* CALL NEWLINE2 PRTS("+++ BAD INT $") LD A,L RRCA RRCA CALL PRTHEXBYTE PRTS("H: $") CALL XREGDMP ;CALL CONTINUE OR $FF ; SIGNAL INTERRUPT HANDLED RET ; ; COMMON API FUNCTION DISPATCH CODE ; ; ON ENTRY C IS UNIT # (INDEX INTO XXX_TBL OF UNITS) ; AND IY POINTS TO START OF UNIT TABLE. ; USE UNIT # IN C TO LOOKUP XXX_TBL ENTRY. THE XXX_TBL ; ENTRY CONTAINS THE START OF THE DRIVER FUNCTION TABLE AND ; THE DEVICE SPECIFIC INSTANCE DATA (BLOB). SET IY TO BLOB ADDRESS ; AND CALL THE SPECIFIC FUNCTION REQUESTED IN THE DRIVER. ; HB_DISPCALL: ; CHECK INCOMING UNIT INDEX IN C FOR VAILIDITY LD A,C ; A := INCOMING DISK UNIT INDEX CP (IY-1) ; COMPARE TO COUNT JR NC,HB_DISPERR ; HANDLE INVALID UNIT INDEX ; CHECK FUNCTION INDEX FOR VALIDITY LD A,B ; A := INCOMING FUNCTION NUMBER AND $0F ; LOW NIBBLE ONLY FOR FUNC INDEX CP (IY-3) ; CHECK FN NUM AGAINST MAX JR NC,HB_DISPERR ; HANDLE FN NUM OUT OF RANGE ERROR ; BUMP IY TO ACTUAL XXX_TBL ENTRY FOR INCOMING UNIT INDEX PUSH BC ; SAVE BC LD B,0 ; MSB IS ALWAYS ZERO RLC C ; MULTIPLY UNIT INDEX RLC C ; ... BY 4 FOR TABLE ENTRY OFFSET ADD IY,BC ; SET IY TO ENTRY ADDRESS POP BC ; RESTORE BC ; DERIVE DRIVER FUNC ADR TO CALL PUSH HL ; SAVE INCOMING HL LD L,(IY+0) ; COPY DRIVER FUNC TABLE LD H,(IY+1) ; ... START TO HL RLCA ; CONV UNIT (STILL IN A) TO FN ADR OFFSET CALL ADDHLA ; HL NOW HAS DRIVER FUNC TBL START ADR LD A,(HL) ; DEREFERENCE HL INC HL ; ... TO GET LD H,(HL) ; ... ACTUAL LD L,A ; ... TARGET FUNCTION ADDRESS EX (SP),HL ; RESTORE HL, FUNC ADR ON STACK ; GET UNIT INSTANCE DATA BLOB ADDRESS TO IY PUSH HL ; SAVE INCOMING HL LD L,(IY+2) ; HL := DATA BLOB ADDRESS LD H,(IY+3) ; ... EX (SP),HL ; RESTORE HL, BLOB ADR ON TOS POP IY ; IY := BLOB ADR RET ; JUMP TO DRIVER FUNC ADR ON TOS ; HB_DISPERR: CALL PANIC ; PANIC OR $FF ; SIGNAL ERROR RET ; AND RETURN VIA DISPEXIT ; ; ADD AN ENTRY TO THE UNIT TABLE AT ADDRESS IN HL ; BC: DRIVER FUNCTION TABLE ; DE: ADDRESS OF UNIT INSTANCE DATA ; RETURN ; A: UNIT NUMBER ASSIGNED ; HB_ADDENT: DEC HL ; POINT TO ENTRY COUNT LD A,(HL) ; GET ENTRY COUNT PUSH AF ; SAVE VALUE TO RETURN AS ENTRY NUM AT END INC A ; INCREMENT TO ACCOUNT FOR NEW ENTRY DEC HL ; POINT TO ENTRY MAX CP (HL) ; COMPARE MAX TO CURRENT COUNT (COUNT - MAX) CALL NC,PANIC ; OVERFLOW INC HL ; POINT TO COUNT LD (HL),A ; SAVE NEW COUNT INC HL ; POINT TO START OF TABLE DEC A ; CONVERT A FROM ENTRY COUNT TO ENTRY INDEX RLCA ; MULTIPLY BY 4 RLCA ; ... TO GET BYTE OFFSET OF ENTRY CALL ADDHLA ; MAKE HL POINT TO ACTUAL ENTRY ADDRESS PUSH BC ; GET TABLE ENTRY ADDRESS TO BC EX (SP),HL ; ... AND DISPATCH ADDRESS TO HL POP BC ; ... SO THAT DE:HL HAS 32 BIT ENTRY CALL ST32 ; LD (BC),DE:HL STORES THE ENTRY POP AF ; RETURN ENTRY INDEX (UNIT NUMBER ASSIGNED) RET ; ; ALLOCATE HL BYTES OF MEMORY ON THE HEAP ; RETURNS POINTER TO ALLOCATED SPACE IN HL ; ON SUCCESS RETURN A == 0, AND Z SET ; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED ; ALL OTHER REGISTERS PRESERVED ; ; A 4 BYTE HEADER IS PLACED IN FRONT OF THE ALLOCATED MEMORY ; - DWORD: SIZE OF MEMROY ALLOCATED (DOES NOT INCLUDE 4 BYTE HEADER) ; - DWORD: ADDRESS WHERE ALLOC WAS CALLED (VALUE ON TOP OF STACK AT CALL) ; HB_ALLOC: ; SAVE ALLOC SIZE AND REFERENCE ADR FOR SUBSEQUENT HEADER CONSTRUCTION LD (HB_TMPSZ),HL ; SAVE INCOMING SIZE REQUESTED ; USE EX (SP),HL INSTEAD???? POP HL ; GET RETURN ADDRESS LD (HB_TMPREF),HL ; SAVE AS REFERENCE ; USE EX (SP),HL INSTEAD???? PUSH HL ; PUT IT BACK ON STACK LD HL,(HB_TMPSZ) ; RECOVER INCOMING MEM SIZE PARM ; ; CALC NEW HEAP TOP AND HANDLE OUT-OF-SPACE ERROR PUSH DE ; SAVE INCOMING DE LD DE,4 ; SIZE OF HEADER ADD HL,DE ; ADD IT IN JR C,HB_ALLOC1 ; ERROR ON OVERFLOW LD DE,(CB_HEAPTOP) ; CURRENT HEAP TOP ADD HL,DE ; ADD IT IN, HL := NEW HEAP TOP JR C,HB_ALLOC1 ; ERROR ON OVERFLOW BIT 7,H ; TEST PAST END OF BANK (>= 32K) JR NZ,HB_ALLOC1 ; ERROR IF PAST END ; ; SAVE NEW HEAP TOP LD DE,(CB_HEAPTOP) ; GET ORIGINAL HEAP TOP LD (CB_HEAPTOP),HL ; SAVE NEW HEAP TOP ; ; SET HEADER VALUES EX DE,HL ; HEADER ADR TO HL LD DE,(HB_TMPSZ) ; GET THE ORIG SIZE REQUESTED LD (HL),E ; SAVE SIZE (LSB) INC HL ; BUMP HEADER POINTER LD (HL),D ; SAVE SIZE (MSB) INC HL ; BUMP HEADER POINTER LD DE,(HB_TMPREF) ; GET THE REFERENCE ADR LD (HL),E ; SAVE REF ADR (LSB) INC HL ; BUMP HEADER POINTER LD (HL),D ; SAVE REF ADR (MSB) INC HL ; BUMP HEADER POINTER ; ; RETURN SUCCESS, HL POINTS TO START OF ALLOCATED MEMORY (PAST HEADER) POP DE ; RESTORE INCOMING DE XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; HB_ALLOC1: ; ERROR RETURN POP DE ; RESTORE INCOMING DE OR $FF ; SIGNAL ERROR RET ; AND RETURN ; HB_TMPSZ .DW 0 HB_TMPREF .DW 0 ; ;================================================================================================== ; DEVICE DRIVERS ;================================================================================================== ; #IF (SIMRTCENABLE) ORG_SIMRTC .EQU $ #INCLUDE "simrtc.asm" SIZ_SIMRTC .EQU $ - ORG_SIMRTC .ECHO "SIMRTC occupies " .ECHO SIZ_SIMRTC .ECHO " bytes.\n" #ENDIF ; #IF (DSRTCENABLE) ORG_DSRTC .EQU $ #INCLUDE "dsrtc.asm" SIZ_DSRTC .EQU $ - ORG_DSRTC .ECHO "DSRTC occupies " .ECHO SIZ_DSRTC .ECHO " bytes.\n" #ENDIF ; #IF (BQRTCENABLE) ORG_BQRTC .EQU $ #INCLUDE "bqrtc.asm" SIZ_BQRTC .EQU $ - ORG_BQRTC .ECHO "BQRTC occupies " .ECHO SIZ_BQRTC .ECHO " bytes.\n" #ENDIF ; #IF (ASCIENABLE) ORG_ASCI .EQU $ #INCLUDE "asci.asm" SIZ_ASCI .EQU $ - ORG_ASCI .ECHO "ASCI occupies " .ECHO SIZ_ASCI .ECHO " bytes.\n" #ENDIF ; #IF (UARTENABLE) ORG_UART .EQU $ #INCLUDE "uart.asm" SIZ_UART .EQU $ - ORG_UART .ECHO "UART occupies " .ECHO SIZ_UART .ECHO " bytes.\n" #ENDIF ; #IF (SIOENABLE) ORG_SIO .EQU $ #INCLUDE "sio.asm" SIZ_SIO .EQU $ - ORG_SIO .ECHO "SIO occupies " .ECHO SIZ_SIO .ECHO " bytes.\n" #ENDIF ; #IF (ACIAENABLE) ORG_ACIA .EQU $ #INCLUDE "acia.asm" SIZ_ACIA .EQU $ - ORG_ACIA .ECHO "ACIA occupies " .ECHO SIZ_ACIA .ECHO " bytes.\n" #ENDIF ; #IF (VGAENABLE) ORG_VGA .EQU $ #INCLUDE "vga.asm" SIZ_VGA .EQU $ - ORG_VGA .ECHO "VGA occupies " .ECHO SIZ_VGA .ECHO " bytes.\n" #ENDIF ; #IF (CVDUENABLE) ORG_CVDU .EQU $ #INCLUDE "cvdu.asm" SIZ_CVDU .EQU $ - ORG_CVDU .ECHO "CVDU occupies " .ECHO SIZ_CVDU .ECHO " bytes.\n" #ENDIF ; #IF (VDUENABLE) ORG_VDU .EQU $ #INCLUDE "vdu.asm" SIZ_VDU .EQU $ - ORG_VDU .ECHO "VDU occupies " .ECHO SIZ_VDU .ECHO " bytes.\n" #ENDIF ; #IF (TMSENABLE) ORG_TMS .EQU $ #INCLUDE "tms.asm" SIZ_TMS .EQU $ - ORG_TMS .ECHO "TMS occupies " .ECHO SIZ_TMS .ECHO " bytes.\n" #ENDIF ; #IF (NECENABLE) ORG_NEC .EQU $ ;#INCLUDE "nec.asm" SIZ_NEC .EQU $ - ORG_NEC .ECHO "NEC occupies " .ECHO SIZ_NEC .ECHO " bytes.\n" #ENDIF ; ; FONTS AREA ; ORG_FONTHI .EQU $ ; ; DO WE NEED AN 8X16 FONT? ; #IF ((VGAENABLE | CVDUENABLE)) #IF (VGAENABLE & ((VGASIZ=V80X25) | (VGASIZ=V80X30))) VGA_FONT: #ENDIF #IF (CVDUENABLE) CVDU_FONT: #ENDIF #IF USEZLSA2 #INCLUDE "font8x16c.asm" #ELSE #INCLUDE "font8x16u.asm" #ENDIF .ECHO "8X16 " #ENDIF ; ; DO WE NEED AN 8X11 FONT? ; #IF (VGAENABLE) #IF (VGASIZ=V80X43)) VGA_FONT: #IF USEZLSA2 #INCLUDE "font8x11c.asm" #ELSE #INCLUDE "font8x11u.asm" #ENDIF .ECHO "8X11 " #ENDIF #ENDIF ; ; DO WE NEED AN 8X8 FONT? ; #IF (VGAENABLE | TMSENABLE) #IF ((VGAENABLE & (VGASIZ=V80X60))) VGA_FONT: #ENDIF #IF (TMSENABLE) TMS_FONT: #ENDIF #IF USEZLSA2 #INCLUDE "font8x8c.asm" #ELSE #INCLUDE "font8x8u.asm" #ENDIF .ECHO "8X8 " #ENDIF ; SIZ_FONTHI .EQU $ - ORG_FONTHI .ECHO "FONTS occupy " .ECHO SIZ_FONTHI .ECHO " bytes.\n" ; #IF (CVDUENABLE | VGAENABLE) ORG_KBD .EQU $ #INCLUDE "kbd.asm" SIZ_KBD .EQU $ - ORG_KBD .ECHO "KBD occupies " .ECHO SIZ_KBD .ECHO " bytes.\n" #ENDIF ; #IF (VDUENABLE | (TMSENABLE & (PLATFORM == PLT_N8))) ORG_PPK .EQU $ #INCLUDE "ppk.asm" SIZ_PPK .EQU $ - ORG_PPK .ECHO "PPK occupies " .ECHO SIZ_PPK .ECHO " bytes.\n" #ENDIF ; #IF (PRPENABLE) ORG_PRP .EQU $ #INCLUDE "prp.asm" SIZ_PRP .EQU $ - ORG_PRP .ECHO "PRP occupies " .ECHO SIZ_PRP .ECHO " bytes.\n" #ENDIF ; #IF (PPPENABLE) ORG_PPP .EQU $ #INCLUDE "ppp.asm" SIZ_PPP .EQU $ - ORG_PPP .ECHO "PPP occupies " .ECHO SIZ_PPP .ECHO " bytes.\n" #ENDIF ; #IF (MDENABLE) ORG_MD .EQU $ #INCLUDE "md.asm" SIZ_MD .EQU $ - ORG_MD .ECHO "MD occupies " .ECHO SIZ_MD .ECHO " bytes.\n" #ENDIF ; #IF (FDENABLE) ORG_FD .EQU $ #INCLUDE "fd.asm" SIZ_FD .EQU $ - ORG_FD .ECHO "FD occupies " .ECHO SIZ_FD .ECHO " bytes.\n" #ENDIF ; #IF (RFENABLE) ORG_RF .EQU $ #INCLUDE "rf.asm" SIZ_RF .EQU $ - ORG_RF .ECHO "RF occupies " .ECHO SIZ_RF .ECHO " bytes.\n" #ENDIF ; #IF (IDEENABLE) ORG_IDE .EQU $ #INCLUDE "ide.asm" SIZ_IDE .EQU $ - ORG_IDE .ECHO "IDE occupies " .ECHO SIZ_IDE .ECHO " bytes.\n" #ENDIF ; #IF (PPIDEENABLE) ORG_PPIDE .EQU $ #INCLUDE "ppide.asm" SIZ_PPIDE .EQU $ - ORG_PPIDE .ECHO "PPIDE occupies " .ECHO SIZ_PPIDE .ECHO " bytes.\n" #ENDIF ; #IF (SDENABLE) ORG_SD .EQU $ #INCLUDE "sd.asm" SIZ_SD .EQU $ - ORG_SD .ECHO "SD occupies " .ECHO SIZ_SD .ECHO " bytes.\n" #ENDIF ; #IF (HDSKENABLE) ORG_HDSK .EQU $ #INCLUDE "hdsk.asm" SIZ_HDSK .EQU $ - ORG_HDSK .ECHO "HDSK occupies " .ECHO SIZ_HDSK .ECHO " bytes.\n" #ENDIF ; #IF (TERMENABLE) ORG_TERM .EQU $ #INCLUDE "term.asm" SIZ_TERM .EQU $ - ORG_TERM .ECHO "TERM occupies " .ECHO SIZ_TERM .ECHO " bytes.\n" #ENDIF ; ;#IF (SPKENABLE & DSRTCENABLE) #IF (SPKENABLE) ORG_SPK .EQU $ #INCLUDE "spk.asm" SIZ_SPK .EQU $ - ORG_SPK .ECHO "SPK occupies " .ECHO SIZ_SPK .ECHO " bytes.\n" #ENDIF ; #IF (AYENABLE) ORG_AY .EQU $ #INCLUDE "ay.asm" SIZ_AY .EQU $ - ORG_AY .ECHO "AY occupies " .ECHO SIZ_AY .ECHO " bytes.\n" #ENDIF ; #IF (PIO_4P | PIO_ZP | PPI_SBC) ORG_PIO .EQU $ #INCLUDE "pio.asm" SIZ_PIO .EQU $ - ORG_PIO .ECHO "PIO occupies " .ECHO SIZ_PIO .ECHO " bytes.\n" #ENDIF ; #IF (UFENABLE) ORG_UF .EQU $ #INCLUDE "uf.asm" SIZ_UF .EQU $ - ORG_UF .ECHO "UF occupies " .ECHO SIZ_UF .ECHO " bytes.\n" #ENDIF #IF (CTCENABLE) ORG_CTC .EQU $ #INCLUDE "ctc.asm" SIZ_CTC .EQU $ - ORG_CTC .ECHO "CTC occupies " .ECHO SIZ_CTC .ECHO " bytes.\n" #ENDIF ; #DEFINE USEDELAY #INCLUDE "util.asm" #INCLUDE "time.asm" #INCLUDE "bcd.asm" #INCLUDE "decode.asm" #INCLUDE "encode.asm" ; #IF (WBWDEBUG == USEXIO) #INCLUDE "xio.asm" #ENDIF #IF (WBWDEBUG == USEMIO) #INCLUDE "mio.asm" #ENDIF ; #IF (DSKYENABLE) #DEFINE DSKY_KBD #INCLUDE "dsky.asm" #ENDIF ; ; INCLUDE ZLSA2 decompression engine if required. ; #IF ((VGAENABLE | CVDUENABLE | TMSENABLE) & USEZLSA2) #INCLUDE "unlzsa2s.asm" #ENDIF ; ; DETECT CPU SPEED USING DS-1302 RTC ; HB_CPUSPD: ; #IF (DSRTCENABLE) ; LD A,(DSRTC_STAT) ; GET RTC STATUS OR A ; SET FLAGS RET NZ ; NOT ZERO IS ERROR ; HB_CPUSPD1: #IF (CPUFAM == CPU_Z180) ; USE MEM W/S = 2 AND I/O W/S = 3 FOR TEST IN0 A,(Z180_DCNTL) PUSH AF LD A,$B0 ;LD A,$F0 OUT0 (Z180_DCNTL),A #ENDIF ; WAIT FOR AN INITIAL TICK TO ALIGN, THEN WAIT ; FOR SECOND TICK AND TO GET A FULL ONE SECOND LOOP COUNT CALL HB_RDSEC ; GET SECONDS LD (HB_CURSEC),A ; AND INIT CURSEC CALL HB_WAITSEC ; WAIT FOR SECONDS TICK LD (HB_CURSEC),A ; SAVE NEW VALUE CALL HB_WAITSEC ; WAIT FOR SECONDS TICK ; #IF (CPUFAM == CPU_Z180) ; RESTORE W/S SETTINGS FROM BEFORE TEST POP AF OUT0 (Z180_DCNTL),A #ENDIF ; LD A,H OR L RET Z ; FAILURE, USE DEFAULT CPU SPEED ; ; MOVE LOOP COUNT TO HL PUSH DE POP HL ; ; TIMES 4 FOR CPU SPEED IN KHZ ; RES 0,L ; GRANULARITY SLA L RL H SLA L RL H ; LD (CB_CPUKHZ),HL LD DE,1000 CALL DIV16 LD A,C LD (CB_CPUMHZ),A ; RET ; HB_WAITSEC: ; WAIT FOR SECONDS TICK ; RETURN SECS VALUE IN A, LOOP COUNT IN DE LD DE,0 ; INIT LOOP COUNTER HB_WAITSEC1: ; #IF (CPUFAM == CPU_Z80) ; LOOP TARGET IS 4000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 4 CALL DLY32 CALL DLY16 CALL DLY1 ; 27 TSTATES SBC HL,HL ; 15 TSTATES SBC HL,HL ; 15 TSTATES INC HL ; 6 TSTATES INC HL ; 6 TSTATES #ENDIF ; #IF (CPUFAM == CPU_Z180) ; LOOP TARGET IS 4000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 4 CALL DLY2 ADD IX,BC ; 10 + 4 = 14 TSTATES NOP ; 5 TSTATES NOP ; 5 TSTATES NOP ; 5 TSTATES NOP ; 5 TSTATES #ENDIF ; PUSH DE ; SAVE COUNTER CALL HB_RDSEC ; GET SECONDS POP DE ; RESTORE COUNTER INC DE ; BUMP COUNTER LD HL,HB_CURSEC ; POINT TO COMP VALUE CP (HL) ; TEST FOR CHANGE RET NZ ; DONE IF TICK OCCURRED LD A,D ; CHECK DE OR E ; ... FOR OVERFLOW RET Z ; TIMEOUT, SOMETHING IS WRONG JR HB_WAITSEC1 ; LOOP ; HB_RDSEC: ; READ SECONDS BYTE INTO A LD E,$81 ; SECONDS REGISTER CALL DSRTC_CMD ; SEND THE COMMAND CALL DSRTC_GET ; READ THE REGISTER CALL DSRTC_END ; FINISH IT LD A,E ; VALUE TO A RET ; #ELSE ; RET ; NO RTC, ABORT ; #ENDIF ; ; PRINT VALUE OF HL AS THOUSANDTHS, IE. 0.000 ; PRTD3M: PUSH BC PUSH DE PUSH HL LD E,'0' LD BC,-10000 CALL PRTD3M1 LD E,0 LD BC,-1000 CALL PRTD3M1 CALL PC_PERIOD LD BC,-100 CALL PRTD3M1 LD C,-10 CALL PRTD3M1 LD C,-1 CALL PRTD3M1 POP HL POP DE POP BC RET PRTD3M1: LD A,'0' - 1 PRTD3M2: INC A ADD HL,BC JR C,PRTD3M2 SBC HL,BC CP E JR Z,PRTD3M3 LD E,0 CALL COUT PRTD3M3: RET ;================================================================================================== ; DISPLAY SUMMARY OF ATTACHED UNITS/DEVICES ;================================================================================================== ; PRTSUM: CALL NEWLINE2 ; SKIP A LINE LD DE,PS_STRHDR ; POINT TO HEADER CALL WRITESTR ; PRINT IT ; LD C,BF_SYSGET_CIOCNT ; CHARACTER DEVICES LD HL,PS_SERIAL CALL PRT_ALLD ; LD C,BF_SYSGET_DIOCNT ; DISK DRIVES LD HL,PS_DISK CALL PRT_ALLD LD C,BF_SYSGET_VDACNT ; VIDEO DEVICES LD HL,PS_VIDEO CALL PRT_ALLD RET ; PRT_ALLD: LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET RST 08 ; E := UNIT COUNT LD B,E ; MOVE TO B FOR LOOP COUNT LD A,E ; MOVE TO ACCUM OR A ; SET FLAGS RET Z ; IF NONE, JUST RETURN LD C,0 ; C WILL BE UNIT INDEX PRT_ALLD1: PUSH BC ; SAVE LOOP CONTROL PUSH DE PUSH HL CALL JPHL ; CALL THE ROUTINE PASSED IN HL POP HL POP DE POP BC ; RESTORE LOOP CONTROL INC C ; BUMP UNIT INDEX DJNZ PRT_ALLD1 ; LOOP THRU ALL DEVICES RET ; ; PRINT ONE LINE DISK UNIT/DEVICE INFO, DISK UNIT INDEX IN C ; PS_DISK: PUSH BC ; SAVE UNIT INDEX FOR LATER ; ; UNIT COLUMN PRTS("Disk $") LD A,C ; MOVE UNIT NUM TO A CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT PRTS(" $") ; PAD TO NEXT COLUMN ; ; DEVICE COLUMN LD B,BF_DIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES PUSH BC ; SAVE ATTRIBUTES LD HL,PS_DDSTRREF ; POINT TO DISK DEVICE TYPE NAME TABLE CALL PS_PRTDEV ; PRINT DISK DEVICE NMEMONIC PADDED TO FIELD WIDTH POP DE ; RECOVER ATTRIBUTES TO DE PUSH DE ; SAVE ATTRIBUTES AGAIN CALL PS_PRTDT ; PRINT DISK TYPE POP DE ; RESTORE ATTRIBUTES POP BC ; RESTORE UNIT NUM CALL PS_PRTDC ; PRINT DISK CAPACITY ; CALL NEWLINE RET ; ; PRINT DISK TYPE (DISK ATTRIBUTE IN E) ; PS_PRTDT: LD A,E ; ATTRIBUTES TO A BIT 7,A ; FLOPPY BIT SET? LD HL,PS_DTFLOP ; ASSUME FLOPPY JR NZ,PS_PRTDT1 ; IF FLOPPY, JUMP AHEAD RRCA ; SHIFT TYPE BITS RRCA RRCA AND $07 ; AND ISOLATE THEM RLCA ; X2 FOR WORD OFFSET IN STRING TABLE LD HL,PS_DTSTRREF + 2 ; POINT TO STR REF TABLE (SKIP FLOPPY STRING) CALL ADDHLA LD A,(HL) INC HL LD H,(HL) LD L,A ; PS_PRTDT1: CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED LD A,18 ; 18 CHAR FIELD SUB C CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) RET ; ; PRINT DISK CAPACITY (UNIT IN C, ATTRIBUTE IN E) ; PS_PRTDC: ; LD A,E ; ATTRIBUTE TO ACCUM BIT 7,A ; TEST FOR FLOPPY JR NZ,PS_PRTDC2 ; HANDLE FLOPPY RRCA ; ISOLATE TYPE BITS RRCA RRCA AND $07 CP 4 ; ROM DISK? JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB CP 5 ; RAM DISK? JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB ; ; PRINT HARD DISK STORAGE SIZE IN MB LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY RST 08 ; DE:HL := BLOCKS JP NZ,PS_PRTNUL ; MEDIA PROBLEM RES 7,D ; CLEAR LBA BIT LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB CALL SRL32 ; RIGHT SHIFT CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED) PRTS("MB$") ; PRINT SUFFIX CALL PC_COMMA PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA RET ; DONE ; PS_PRTDC1: ; PRINT ROM/ROM DISK CAPACITY IN KB LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY RST 08 ; DE:HL := BLOCKS JP NZ,PS_PRTNUL ; MEDIA PROBLEM RES 7,D ; CLEAR LBA BIT LD B,1 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB CALL SRL32 ; RIGHT SHIFT CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED) PRTS("KB$") ; PRINT SUFFIX CALL PC_COMMA PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA RET ; DONE ; PS_PRTDC2: LD C,E ; ATTRIBUTE TO C FOR SAFE KEEPING ; LD A,01100000B ; DISPLAY FORM FACTOR LD DE,PS_FLP_FSTR ; WHICH IS DEFINED IN CALL PRTIDXMSK ; BITS 5 AND 6. ; LD A,00010000B ; DISPLAY SIDES LD DE,PS_FLP_SSTR ; WHICH IS DEFINED CALL PRTIDXMSK ; IN BIT 4 ; LD A,00001100B ; DISPLAY DENSITY LD DE,PS_FLP_DSTR ; WHICH IS DEFINED IN CALL PRTIDXMSK ; BITS 2 AND 3. ; CALL PC_COMMA PRTS("CHS$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA ; RET ; DONE ; ; PRINT ONE LINE SERIAL UNIT/DEVICE INFO, SERIAL UNIT INDEX IN C ; PS_SERIAL: PUSH BC ; SAVE UNIT INDEX FOR LATER ; ; UNIT COLUMN PRTS("Char $") LD A,C ; MOVE UNIT NUM TO A CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT PRTS(" $") ; PAD TO NEXT COLUMN ; ; DEVICE COLUMN LD B,BF_CIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C RST 08 ; DE:=DEVTYP/NUM, C:=DEVICE ATTRIBUTES PUSH BC ; SAVE ATTRIBUTES LD HL,PS_SDSTRREF ; POINT TO SERIAL DEVICE TYPE NAME TABLE CALL PS_PRTDEV ; PRINT SERIAL DEVICE NMEMONIC PADDED TO FIELD WIDTH POP BC ; RECOVER ATTRIBUTES PUSH BC ; SAVE ATTRIBUTES AGAIN CALL PS_PRTST ; PRINT SERIAL TYPE POP BC ; RESTORE ATTRIBUTES POP DE ; RESTORE UNIT NUM TO E CALL PS_PRTSC ; PRINT SERIAL CONFIG ; CALL NEWLINE RET ; ; PRINT CHARACTER TYPE (SERIAL ATTRIBUTE IN E) ; PS_PRTST: LD HL,PS_STPPT BIT 6,C JR NZ,PS_PRTST1 ; PARALLEL TYPE? LD HL,PS_STRS232 ; ASSUME RS-232 BIT 7,C ; 0=RS-232, 1=TERMINAL JR Z,PS_PRTST1 ; HANDLE TERMINAL TYPE LD HL,PS_STTERM ; TYPE IS TERMINAL ; PS_PRTST1: CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED LD A,18 ; 18 CHAR FIELD SUB C CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) RET ; ; PRINT SERIAL CONFIG (UNIT IN E, ATTRIBUTE IN C) ; PS_PRTSC: BIT 6,C ; PARALLEL TYPE? JR NZ,PSPRTPC0 BIT 7,C ; 0=RS-232, 1=TERMINAL JP NZ,PS_PRTSC1 ; PRINT TERMINAL CONFIG ; ; PRINT RS-232 CONFIG LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG LD C,E ; SET SERIAL UNIT NUM RST 08 ; DE:HL := BAUD RATE LD A,D ; TEST FOR $FF AND E INC A ; SET Z IF DE == $FF JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED ; PS_PRTSC0: ; PRINT BAUD RATE PUSH DE ; PRESERVE DE LD A,D AND $1F ; ISOLATE ENCODED BAUD RATE LD L,A ; PUT IN L LD H,0 ; H IS ALWAYS ZERO LD DE,75 ; BAUD RATE DECODE CONSTANT CALL DECODE ; DE:HL := BAUD RATE LD BC,HB_BCDTMP ; POINT TO TEMP BCD BUF CALL BIN2BCD ; CONVERT TO BCD CALL PRTBCD ; AND PRINT IN DECIMAL POP DE ; RESTORE DE ; ; PRINT DATA BITS PUSH DE ; PRESERVE DE CALL PC_COMMA ; FORMATTING LD A,E ; GET CONFIG BYTE AND $03 ; ISOLATE DATA BITS VALUE ADD A,'5' ; CONVERT TO CHARACTER CALL COUT ; AND PRINT POP DE ; RESTORE DE ; ; PRINT PARITY PUSH DE ; PRESERVE DE CALL PC_COMMA ; FORMATTING LD A,E ; GET CONFIG BYTE RRCA ; SHIFT RELEVANT BITS RRCA ; ... RRCA ; ... AND $07 ; AND ISOLATE DATA BITS VALUE LD HL,PS_STPARMAP ; CHARACTER LOOKUP TABLE CALL ADDHLA ; APPLY OFFSET LD A,(HL) ; GET CHARACTER CALL COUT ; AND PRINT POP DE ; RESTORE DE ; ; PRINT STOP BITS CALL PC_COMMA ; FORMATTING LD A,E ; GET CONFIG BYTE RRCA ; SHIFT RELEVANT BITS RRCA ; ... AND $01 ; AND ISOLATE DATA BITS VALUE ADD A,'1' ; MAKE IT A CHARACTER CALL COUT ; AND PRINT ; RET ; PSPRTPC0: LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG LD C,E ; SET PARALLEL UNIT NUM RST 08 ; DE:HL := I/O SETTING LD A,D ; TEST FOR $FF AND E INC A ; SET Z IF DE == $FF JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED ; PS_PRTPC0: LD C,E ; DISPLAY PIO TYPE LD A,11000000B ; WHICH IS DEFINE BY LD DE,PIO_MODE_STR ; BITS 6 AND 7 JP PRTIDXMSK ; RET ; TRICK RETURN ; PS_PRTSC1: ; PRINT TERMINAL CONFIG LD A,C ; GET ATTRIBUTE VALUE CP $BF ; NO ATTACHED VDA JR Z,PS_PRTSC2 PRTS("Video $") ; FORMATTING AND $0F ; ISOLATE VIDEO UNIT NUM CALL PRTDECB ; PRINT IT CALL PC_COMMA #IF (VDAEMU == EMUTYP_TTY) PRTS("TTY$") #ENDIF #IF (VDAEMU == EMUTYP_ANSI) PRTS("ANSI$") #ENDIF RET ; PS_PRTSC2: PRTS("PropTerm$") ; ASSUME PROPELLER CALL PC_COMMA PRTS("ANSI$") RET ; ; PRINT ONE LINE VIDEO UNIT/DEVICE INFO, VIDEO UNIT INDEX IN C ; PS_VIDEO: PUSH BC ; SAVE UNIT INDEX FOR LATER ; ; UNIT COLUMN PRTS("Video $") LD A,C ; MOVE UNIT NUM TO A CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT PRTS(" $") ; PAD TO NEXT COLUMN ; ; DEVICE COLUMN LD B,BF_VDADEV ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES PUSH BC ; SAVE ATTRIBUTES LD HL,PS_VDSTRREF ; POINT TO VIDEO DEVICE TYPE NAME TABLE CALL PS_PRTDEV ; PRINT VIDEO DEVICE NMEMONIC PADDED TO FIELD WIDTH POP DE ; RECOVER ATTRIBUTES PUSH DE ; SAVE ATTRIBUTES AGAIN CALL PS_PRTVT ; PRINT VIDEO TYPE POP DE ; RESTORE ATTRIBUTES POP BC ; RESTORE UNIT NUM CALL PS_PRTVC ; PRINT VIDEO CONFIG ; CALL NEWLINE RET ; ; PRINT VIDEO TYPE (VIDEO ATTRIBUTE IN E) ; PS_PRTVT: LD HL,PS_VTCRT ; ASSUME CRT CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED LD A,18 ; 18 CHAR FIELD SUB C CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) RET ; ; PRINT VIDEO CONFIG (UNIT IN C, ATTRIBUTE IN E) ; PS_PRTVC: PRTS("Text$") CALL PC_COMMA LD B,BF_VDAQRY ; FUNC: QUERY FOR VDA CONFIG RST 08 ; D:=ROWS, E:=COLS LD A,E CALL PRTDECB LD A,'x' CALL COUT LD A,D CALL PRTDECB RET ; ; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE ; PS_PRTDEV: LD A,D RRCA ; TYPE IS IN UPPER NIBBLE, MOVE TO LOWER NIBBLE RRCA RRCA RRCA RLCA ; X2 FOR WORD OFFSET IN STRING TABLE CALL ADDHLA LD A,(HL) INC HL LD H,(HL) LD L,A CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED LD A,E ; NUM CALL PRTDECB ; PRINT NUM, ASSUME 1 CHAR CALL PC_COLON ; PRINT COLON LD A,12 - 2 ; 12 CHAR FIELD - 1 POS FOR UNIT NUM AND 1 POS FOR COLON SUB C CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) RET ; ; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE ; PS_PRTNUL: LD HL,PS_STRNUL ; FALL THRU TO PS_PRT ; ; ; PS_PRT: ; PRINT STRING AT (HL), $ TERM, RETURN CHARS PRINTED IN C LD C,0 ; INIT CHAR COUNT PS_PRT1: LD A,(HL) ; GET CHAR INC HL ; BUMP INDEX CP '$' ; TERM? RET Z ; IF SO, DONE CALL COUT ; PRINT IT INC C ; BUMP COUNTER JR PS_PRT1 ; AND LOOP ; ; ; PS_PAD: ; PAD N SPACES SPECIFIED IN A LD B,A LD A,' ' PS_PAD1: CALL COUT DJNZ PS_PAD1 RET ; HB_CPU_STR: .TEXT " Z80$" ; HB_STRZ80 .TEXT " Z80180$" ; HB_STRZ180 .TEXT " Z8S180-K$" ; HB_STRZS180K .TEXT " Z8S180-N$" ; HB_STRZS180N ; PS_STRNUL .TEXT "--$" ; DISPLAY STRING FOR NUL VALUE ; ; DISK DEVICE STRINGS ; PS_DDSTRREF: .DW PS_DDMD, PS_DDFD, PS_DDRF, PS_DDIDE, PS_DDATAPI, PS_DDPPIDE .DW PS_DDSD, PS_DDPRPSD, PS_DDPPPSD, PS_DDHDSK ; PS_DDMD .TEXT "MD$" PS_DDFD .TEXT "FD$" PS_DDRF .TEXT "RF$" PS_DDIDE .TEXT "IDE$" PS_DDATAPI .TEXT "ATAPI$" PS_DDPPIDE .TEXT "PPIDE$" PS_DDSD .TEXT "SD$" PS_DDPRPSD .TEXT "PRPSD$" PS_DDPPPSD .TEXT "PPPSD$" PS_DDHDSK .TEXT "HDSK$" ; ; DISK TYPE STRINGS ; PS_DTSTRREF: .DW PS_DTFLOP, PS_DTHARD, PS_DTCF, PS_DTSD .DW PS_DTUSB, PS_DTROM, PS_DTRAM, PS_DTRF ; PS_DTFLOP .TEXT "Floppy Disk$" PS_DTHARD .TEXT "Hard Disk$" PS_DTCF .TEXT "CompactFlash$" PS_DTSD .TEXT "SD Card$" PS_DTUSB .TEXT "USB Drive$" PS_DTROM .TEXT "ROM Disk$" PS_DTRAM .TEXT "RAM Disk$" PS_DTRF .TEXT "RAM Floppy$" PS_DTOTHER .TEXT "???$" ; ; FLOPPY ATTRIBUTE STRINGS ; PS_FLP_FSTR: .TEXT "8\",$" ; PS_FLP8 .TEXT "5.25\",$" ; PS_FLP5 .TEXT "3.5\",$" ; PS_FLP3 .TEXT "???\",$" ; PS_FLPN ; PS_FLP_SSTR: .TEXT "SS/$" ; PS_FLPSS .TEXT "DS/$" ; PS_FLPDS ; PS_FLP_DSTR: .TEXT "SD$" ; PS_FLPSD .TEXT "DD$" ; PS_FLPDD .TEXT "HD$" ; PS_FLPHD .TEXT "ED$" ; PS_FLPED ; ; CHARACTER DEVICE STRINGS ; PS_SDSTRREF: .DW PS_SDUART, PS_SDASCI, PS_SDTERM, .DW PS_SDPRPCON, PS_SDPPPCON, PS_SDSIO, PS_SDACIA, PS_SDPIO,PS_SDUF ; PS_SDUART .TEXT "UART$" PS_SDASCI .TEXT "ASCI$" PS_SDTERM .TEXT "TERM$" PS_SDPRPCON .TEXT "PRPCON$" PS_SDPPPCON .TEXT "PPPCON$" PS_SDSIO .TEXT "SIO$" PS_SDACIA .TEXT "ACIA$" PS_SDPIO .TEXT "PORT$" PS_SDUF .TEXT "UF$" ; ; CHARACTER SUB TYPE STRINGS ; PS_STRS232 .TEXT "RS-232$" PS_STTERM .TEXT "Terminal$" PS_STPPT .TEXT "Parallel$" ; PS_STPARMAP .DB "NONENMNS" ; ; PARALLEL TYPE STRINGS ; PIO_MODE_STR: .TEXT "Output$" .TEXT "Input$" .TEXT "Bidirectional$" .TEXT "BitCtrl$" ; ; VIDEO DEVICE STRINGS ; PS_VDSTRREF: .DW PS_VDVDU, PS_VDCVDU, PS_VDNEC, PS_VDTMS, PS_VDVGA ; PS_VDVDU .TEXT "VDU$" PS_VDCVDU .TEXT "CVDU$" PS_VDNEC .TEXT "NEC$" PS_VDTMS .TEXT "TMS$" PS_VDVGA .TEXT "VGA$" ; ; VIDEO TYPE STRINGS ; PS_VTCRT .TEXT "CRT$" ; ; 0 1 2 3 4 5 6 7 ; 01234567890123456789012345678901234567890123456789012345678901234567890123456789 PS_STRHDR .TEXT "Unit Device Type Capacity/Mode\r\n" .TEXT "---------- ---------- ---------------- --------------------\r\n$" ; ;================================================================================================== ; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED) ;================================================================================================== ; ; OUTPUT CHARACTER FROM A ; COUT: ; SAVE ALL INCOMING REGISTERS PUSH AF PUSH BC PUSH DE PUSH HL ; ; GET CURRENT CONSOLE UNIT LD E,A ; TEMPORARILY STASH OUTPUT CHAR IN E LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE CP $FF ; TEST FOR $FF (HBIOS NOT READY) JR Z,COUT1 ; IF NOT READY, TRY DEBUG OUTPUT ; ; USE HBIOS LD C,A ; CONSOLE UNIT TO C LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY JR COUT2 ; CONTINUE ; COUT1: ; #IF (WBWDEBUG == USEXIO) LD A,E ; GET OUTPUT CHAR BACK TO ACCUM CALL XIO_OUTC ; OUTPUT VIA XIO #ENDIF ; #IF (WBWDEBUG == USEMIO) LD A,E CALL MIO_OUTC ; OUTPUT VIA MIO #ENDIF ; COUT2: ; 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 ; LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE CP $FF ; TEST FOR $FF (HBIOS NOT READY) JR Z,CIN1 ; IF NOT READY, TRY DEBUG INPUT ; ; USE HBIOS LD C,A ; CONSOLE UNIT TO C LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY LD A,E ; RESULTANT CHAR TO A JR CIN2 ; CONTINUE ; CIN1: ; #IF (WBWDEBUG == USEXIO) CALL XIO_INC ; GET CHAR #ENDIF ; #IF (WBWDEBUG == USEMIO) CALL MIO_INC ; GET CHAR #ENDIF ; CIN2: ; ; 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 ; LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE CP $FF ; TEST FOR $FF (HBIOS NOT READY) JR Z,CST1 ; IIF NOT READY, TRY DEBUG DEBUG STATUS ; ; USE HBIOS LD C,A ; CONSOLE UNIT TO C LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY JR CST2 ; CONTINUE ; CST1: ; #IF (WBWDEBUG == USEXIO) CALL XIO_IST ; GET STATUS #ENDIF ; #IF (WBWDEBUG == USEMIO) CALL MIO_IST ; GET STATUS #ENDIF ; CST2: ; RESTORE REGISTERS (AF IS OUTPUT) POP HL POP DE POP BC RET ; ;================================================================================================== ; MISCELLANEOUS UTILITY FUNCTIONS ;================================================================================================== ; ; SET HL TO IY+A, A IS TRASHED ; LDHLIYA: PUSH IY ; COPY INSTANCE DATA PTR POP HL ; ... TO HL ;JP ADDHLA ; APPLY OFFSET TO HL AND RETURN ADD A,L ; ADD OFFSET TO LSB LD L,A ; ... PUT BACK IN L RET NC ; DONE IF CF NOT SET INC H ; IF CF SET, BUMP MSB RET ; ... AND RETURN ; ; CONVERT AN HBIOS STANDARD HARD DISK CHS ADDRESS TO ; AN LBA ADDRESS. A STANDARD HBIOS HARD DISK IS ASSUMED ; TO HAVE 16 SECTORS PER TRACK AND 16 HEADS PER CYLINDER. ; ; INPUT: HL=TRACK, D=HEAD, E=SECTOR ; OUTPUT: DE:HL=32 BIT LBA ADDRESS (D:7 IS NOT SET IN THE RESULT) ; HB_CHS2LBA: ; LD A,D ; HEAD TO A RLCA ; LEFT SHIFT TO HIGH NIBBLE RLCA ; ... DEPENDS ON HIGH RLCA ; ... NIBBLE BEING 0 SINCE RLCA ; ... IT ROTATES INTO LOW NIBBLE OR E ; COMBINE WITH SECTOR (HIGH NIBBLE MUST BE ZERO) LD D,0 LD E,H LD H,L LD L,A XOR A RET ; ;================================================================================================== ; HBIOS GLOBAL DATA ;================================================================================================== ; IDLECOUNT .DB 0 ; HEAPCURB .DW 0 ; MARK HEAP ADDRESS AFTER INITIALIZATION ; HB_TICKS .FILL 4,0 ; 32 BIT TICK COUNTER HB_SECTCK .DB TICKSPERSEC ; TICK COUNTER FOR FRACTIONAL SECONDS HB_SECS .FILL 4,0 ; 32 BIT SECONDS COUNTER ; HB_CPUTYPE .DB 0 ; 0=Z80, 1=80180, 2=SL1960, 3=ASCI BRG ; RTCVAL .DB 0 ; SHADOW VALUE FOR RTC LATCH PORT ; HB_BATCOND .DB 0 ; BATTERY CONDITION (0=LOW, 1=OK) ; STR_BANNER .DB "RetroBrew HBIOS v", BIOSVER, ", ", TIMESTAMP, "$" STR_PLATFORM .DB PLATFORM_NAME, "$" STR_SWITCH .DB "*** Activating CRT Console ***$" STR_BADINT .DB "\r\n*** BAD INT ***\r\n$" STR_LOWBAT .DB "\r\n\r\n+++ LOW BATTERY +++$" ; #IF (DSKYENABLE) ; 'H','B','I','O',' ',' ',' ',' ' MSG_HBVER .DB $BE,$FF,$8A,$FB,$80,$80,$80,$80 ; "HBIO " #ENDIF ; HB_CURSEC .DB 0 ; CURRENT SECOND (TEMP) ; HB_BCDTMP .FILL 5,0 ; BCD NUMBER STORAGE (TEMP) ; HB_WRKBUF .FILL 512,0 ; INTERNAL DISK BUFFER ; HB_END .EQU $ ; SLACK .EQU BNKTOP - $ .ECHO "HBIOS space remaining: " .ECHO SLACK .ECHO " bytes.\n" ; #IFDEF ROMBOOT .FILL SLACK #ENDIF ; .END