; ;================================================================================================== ; 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). ; ; - 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 AUX RAM ; BANK AND LAUNCHED AFTER HBIOS HAS INSTALLED ITSELF. ; ; - IMGBOOT: BOOT FROM AN IMAGE FILE THAT HAS BEEN PLACED IN THE USER BANK ; ; NOTE: THIS BOOT MODE IS DEPRECATED. ; ; 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: ; ; - std.asm ; - ../ver.inc ; - build.inc ; - Config/_std.asm ; - cfg_.asm ; - cfg_MASTER.asm ; - hbios.inc ; - [z180.inc] ; - [z280.inc] ; - [eipc.inc] ; - util.asm ; - time.asm ; - bcd.asm ; - decode.asm ; - encode.asm ; - [xio.asm] ; - [mio.asm] ; - [unlzsa2s.asm] ; - .asm ; - .asm ; ; MEMORY LAYOUT: ; ; DESCRIPTION START LENGTH ; ----------------------------- ------- ------- ; Page Zero 0x0000 0x0100 ; HBIOS Control Block 0x0100 0x0100 ; Proxy Image 0x0200 0x0200 ; Entry Vectors / Stack 0x0400 0x0100 ; Interrupt Vector Table 0x0500 Varies ; System Initialization Varies Varies ; Function Dispatching Varies Varies ; Z280 Int Vector Table Varies Varies ; System API Varies Varies ; Internal Functions Varies Varies ; Utility Functions Varies Varies ; Print Summary Function Varies Varies ; Hardware Drivers Varies Varies ; Font Data Varies Varies ; HBIOS Data Varies Varies ; ; AUXILIARY CONTROL REGISTER ; -------------------------- ; ; SBC/MK4 N8 MBC VDP MBC PSG RPH DUO ; ------------ ------------ ------------ ------------ ------------ ------------ ; D7 ~ROM_ENABLE ~ROM_ENABLE ; D6 TTL1_RTS TTL1_RTS ; D5 PSG_GPIO PSG_GPIO PSG_GPIO ~STATUS_LED PSG_GPIO ; D4 ~PSG_RES ~PSG_RES ~PSG_RES ROM_A19 ~PSG_RES ; D3 STATUS_LED STATUS_LED VDP_LED PSG_LED ROM_A18 PSG_LED ; D2 VDP_A14 VDP_A14 ROM_A17 VDP_LED ; D1 ~VDP_SYN ~VDP_SYN ROM_A16 ; D0 ~VDP_RES ~VDP_RES VDP_RES ROM_A15 VDP_RES ; ; PORT SCG:0x9C 0x94 VDP:0x92 PSG:0xA2 0x80 MEDIA:0xA6 ; #DEFINE HBIOS ; ; INCLUDE GENERIC STUFF ; #INCLUDE "std.asm" ; ; MAKE SURE EXACTLY ONE OF ROMBOOT, APPBOOT, IMGBOOT IS DEFINED. ; MODCNT .EQU 0 BOOTMODE .EQU 0 ; #IFDEF ROMBOOT BOOTMODE .SET BM_ROMBOOT MODCNT .SET MODCNT + 1 ; #DEFINE BNKINFO #DEFINE MEMINFO #DEFINE DEVINFO #DEFINE SYSINFO ; #ENDIF ; #IFDEF APPBOOT BOOTMODE .SET BM_APPBOOT MODCNT .SET MODCNT + 1 #ENDIF ; #IFDEF IMGBOOT ; *** DEPRECATED *** BOOTMODE .SET BM_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 ; ; CONTROLS PRINTING OF DEVICE INFORMATION IN ASSEMBLY OUTPUT ; #IFDEF DEVINFO #DEFINE DEVECHO .ECHO #ELSE #DEFINE DEVECHO \; #ENDIF ; ; CONTROLS PRINTING OF MEMORY USAGE INFORMATION IN ASSEMBLY OUTPUT ; #IFDEF MEMINFO #DEFINE MEMECHO .ECHO #ELSE #DEFINE MEMECHO \; #ENDIF ; SUPCTS .EQU FALSE ; SUPPRESS CTS DURING HBIOS BOOT ; ; HELPER MACROS ; ; SET FRONT PANEL LEDS ; #IF (FPLED_ENABLE) #DEFINE FPLEDS(N) PUSH AF #DEFCONT \ LD A,N #IF (FPLED_INV) #DEFCONT \ XOR $FF ; INVERT BITS IF NEEDED #ENDIF #DEFCONT \ EZ80_IO #DEFCONT \ OUT (FPLED_IO),A #DEFCONT \ POP AF #ELSE #DEFINE FPLEDS(N) \; #ENDIF ; ; SET DIAGNOSTIC LEDS ; ; SCxxx: LED Port=0x0E, bit 2, inverted, dedicated port (LEDMODE_SC) ; SC7xx/SC5xx: LED Port=0x0E, bit 0, inverted, dedicated port (LEDMODE_STD) ; TinyZ80: LED Port=0x6E, bit 0, inverted, dedicated port (LEDMODE_STD) ; Z80-512K: LED Port=0x6E, bit 0, inverted, dedicated port (LEDMODE_STD) ; MBC: LED Port=0x70, bits 1-0, normal, shared w/ RTC port (LEDMODE_RTC) ; DUO: LED Port=0x94, bits 1-0, normal, shared w/ RTC port (LEDMODE_RTC) ; S100: LED Port = $0E, bit 2, inverted, dedicated port (LEDMODE_SC) ; NABU: LED Port = $00, bits 5-3, normal, shared w/ control port (LEDMODE_NABU) ; #IF (LEDENABLE) #IF (LEDMODE == LEDMODE_STD) #DEFINE DIAG(N) PUSH AF #DEFCONT \ LD A,~N #DEFCONT \ OUT (LEDPORT),A #DEFCONT \ POP AF #ENDIF #IF (LEDMODE == LEDMODE_SC) #DEFINE DIAG(N) PUSH AF #DEFCONT \ LD A,+(((~N) << 2) & %00000100) #DEFCONT \ OUT (LEDPORT),A #DEFCONT \ POP AF #ENDIF #IF (LEDMODE == LEDMODE_RTC) #DEFINE DIAG(N) PUSH AF #DEFCONT \ LD A,(HB_RTCVAL) #DEFCONT \ AND %11111100 #DEFCONT \ OR (N & %00000011) #DEFCONT \ LD (HB_RTCVAL),A #DEFCONT \ OUT (LEDPORT),A #DEFCONT \ POP AF #ENDIF #IF (LEDMODE == LEDMODE_NABU) #DEFINE DIAG(N) PUSH AF ;#DEFCONT \ LD A,+((N << 3) & %00011000) #DEFCONT \ LD A,+((N << 3) & %00111000) #DEFCONT \ OUT (LEDPORT),A #DEFCONT \ POP AF #ENDIF #ELSE #DEFINE DIAG(N) \; #ENDIF ; ; HANDLE SYSTEM CHECK ERRORS ; #DEFINE SYSCHKERR(HB_ERR) \ #DEFCONT \ CALL SYSCHKA #DEFCONT \ LD A,HB_ERR #DEFCONT \ OR A ; ; THE HB_EI AND HB_DI MACROS ARE USED TO GENERATE THE APPROPRIATE ; INTERRUPT ENABLE/DISABLE CODE DEPENDING ON THE INTERRUPT MODE ; BEING USED. ; #IF (INTMODE == 0) ; NO INTERRUPT HANDLING #DEFINE HB_DI ; #DEFINE HB_EI ; #ELSE #IF (CPUFAM == CPU_Z280) #IF (INTMODE == 3) ; Z280 MODE 3 INTERRUPT HANDLING (INTA, C/T 0, & UART RCVR ENABLED) #DEFINE HB_DI DI #DEFINE HB_EI EI $0B #ELSE ; Z280 MODE 1/2 INTERRUPT HANDLING #DEFINE HB_DI DI #DEFINE HB_EI EI #ENDIF #ELSE #DEFINE HB_DI DI #DEFINE HB_EI EI #ENDIF #ENDIF ; ; CONSISTENCY CHECKS ; #IF (INTMODE > 3) .ECHO "*** ERROR: INVALID INTMODE SETTING!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF ; #IF (INTMODE == 3) #IF (CPUFAM != CPU_Z280) .ECHO "*** ERROR: INTMODE 3 REQUIRES Z280 FAMILY CPU!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF #IF (MEMMGR != MM_Z280) .ECHO "*** ERROR: INTMODE 3 REQUIRES Z280 MEMORY MANAGER!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF #ENDIF ; #IF (MEMMGR == MM_Z280) #IF (INTMODE != 3) .ECHO "*** ERROR: Z280 MEMORY MANAGER REQUIRES INTMODE 3!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF #IF (CPUFAM != CPU_Z280) .ECHO "*** ERROR: Z280 MEMORY MANAGER REQUIRES Z280 FAMILY CPU!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF #ENDIF ; ; CONVERT ROMWBW LOGICAL BANK ID TO PHYSICAL 32K BANK OFFSET ; #DEFINE PBANK(X) (((X >> 7) * (RAMBIAS / 32)) + (X & $7F)) ; ; CONVERT ROMWBW LOGICAL BANK ID TO Z280 PHYSICAL BANK (4K) OFFSET ; #DEFINE Z2_BANK(X) (PBANK(X) << 3) ; ; RTC LATCH ; ; MANY OF THE ROMWBW SYSTEMS USE A LATCH PORT PRIMARILY FOR BIT ; BANGING A DS-1302 RTC. HOWEVER, SINCE THE RTC ONLY NEEDS A COUPLE ; BITS, THE OTHER BITS OF THE LATCH ARE FREQUENTY USED FOR OTHER ; PURPOSES (LEDS, SD CARD BIT BANGING, ETC.). SEE DSRTC.ASM FOR ; A SUMMARY OF THE WAY THE RTC LATCH BITS ARE USED IN THE VARIOUS ; ROMWBW SYSTEMS. IT IS CRITICAL THAT WHEN MANIPULATING THE RTC ; LATCH THAT BITS ARE NOT FLIPPED INADVERTENTLY. THE RTC LATCH IS ; TYPICALLY WRITE-ONLY, SO WE NEED TO MAINTAIN A SHADOW COPY. ; THE SHADOW COPY IS CALLED HB_RTCVAL AND IS DECLARED AT THE END OF ; THIS FILE IN THE DATA AREA. ; ; INITIALIZING THE HB_RTCVAL SHADOW IS TRICKY BECAUSE DIFFERENT BITS ; ARE MANAGED IN DIFFERENT DRIVERS. TO HANDLE THIS, ; THE RTCDEF EQUATE IS INITIALIZED HERE AND UPDATED BY DRIVER INCLUDES ; THAT SHARE THE RTC LATCH. AS EACH DRIVER FILE IS INCLUDED, IT CAN ; USE .SET TO MODIFY THE DEFAULT VALUE OF ANY BITS THEY OWN. ; SINCE RTCDEF IS CHANGED *AFTER* IT NEEDS TO BE USED BY THE CODE, IT ; SHOULD NOT BE USED DIRECTLY TO SET THE LATCH. INSTEAD, THE FINAL VALUE ; OF RTCDEF IS USED TO INITIALIZE A STORAGE BYTE CALLED RTCDEFVAL AT ; THE END OF THIS FILE. SO (RTCDEFVAL) CAN BE USED ANYWHERE IN ; HBIOS.ASM TO ACCESS THE FINAL RTCDEF VALUE. IN MOST PLACES, THE ; SHADOW COPY (RTCVAL) SHOULD BE USED TO GET THE CURRENT VALUE OF THE ; LATCH AND MAINTAIN ALL BIT CHANGES. ; RTCDEF .EQU 0 ; INIT DEF RTC LATCH VALUE ; ; THE SC126 HAS AN I2C CIRCUIT AND THERE IS NO ASSOCAITED ; DRIVER, SO WE SET THAT BIT HERE. IT IS SET FOR ALL OF THE SCXXX ; SYSTEMS, BUT IS UNUSED ON ALL BUT THE SC126. IT DOES NO HARM. ; #IF (PLATFORM == PLT_SCZ180) RTCDEF .SET RTCDEF | %00000001 ; SC128 I2C SCL BIT #ENDIF ; ; MBC PLATFORM IMPLEMENTS DYNAMIC SPEED SWITCH ON RTC LATCH ; BIT 3. SET THE BIT TO LOW SPEED AS DEFAULT HERE. ; #IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_MBC)) RTCDEF .SET RTCDEF & ~%00001000 ; INITIAL SPEED LOW #ENDIF ; ; DUODYNE PLATFORM IMPLEMENTS DYNAMIC SPEED SWITCH ON RTC LATCH ; BIT 3. SET THE BIT TO LOW SPEED AS DEFAULT HERE. ; #IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_SBC)) RTCDEF .SET RTCDEF | %00001000 ; INITIAL SPEED LOW #ENDIF ; ; EMIT FRONT PANEL CONFIGURATION TO ASSEMBLY OUTPUT ; #IF (FPLED_ENABLE | FPSW_ENABLE) DEVECHO "FP: " #IF (FPLED_ENABLE) DEVECHO "LEDIO=" DEVECHO FPLED_IO #ENDIF #IF (FPLED_ENABLE & FPSW_ENABLE) DEVECHO ", " #ENDIF #IF (FPSW_ENABLE) DEVECHO "SWIO=" DEVECHO FPSW_IO #ENDIF DEVECHO "\n" #ENDIF #INCLUDE "ez80instr.inc" ; ;================================================================================================== ; Z80 PAGE ZERO, VECTORS, ETC. ;================================================================================================== ; .ORG 0 ; HB_PGZERO_BEG .EQU $ ; #IFNDEF APPBOOT ; .FILL (000H - $),0FFH ; RST 0 JP HB_START .DB 0 ; SIG PTR STARTS AT $0004 .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) CALL HBX_INT ; HANDLE IM1 INTERRUPTS .DB $10 << 2 ; USE SPECIAL VECTOR #16 #ELSE RET ; 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, ", ", CONFIG, ", ", TIMESTAMP, 0 AUTH .DB "WBW",0 DESC .DB "Copyright (C) 2024, Wayne Warthen, GNU GPL v3", 0 ; .FILL ($100 - $),$FF ; PAD REMAINDER OF PAGE ZERO ; #ENDIF ; .ORG $100 ; HB_PGZERO_END .EQU $ ; ;================================================================================================== ; HBIOS CONFIGURATION BLOCK (HCB) ;================================================================================================== ; .ORG HCB_LOC ; HB_HCB_BEG .EQU $ ; 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 ; CB_DIAGLVL .DB DIAGLVL ; ROMWBW HBIOS DIAGNOSTIC LEVEL CB_BOOTMODE .DB BOOTMODE ; HBIOS BOOTMODE ; ; 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. DEFAULT VALUES FOR 512KB SYSTEM WITH NO RESERVED BANKS ; .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_RAMD_BNKS .DB RAMD_BNKS CB_BIDROMD0 .DB BID_ROMD0 CB_ROMD_BNKS .DB ROMD_BNKS CB_BIDAPP0 .DB BID_APP0 CB_APP_BNKS .DB APP_BNKS ; .FILL (HCB + HCB_SIZ - $),0 ; PAD REMAINDER OF HCB ; HB_HCB_END .EQU $ ; ;================================================================================================== ; 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 ; HB_PROXY_BEG .EQU $ ; .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 (64 BYTES) ; HBIOS PROXY CODE $FF60 (64 BYTES) ; HBIOS PROXY COPY BUFFER $FFA0 (64 BYTES) ; HBIOS PROXY MGMT BLOCK $FFE0 (32 BYTES) ; ; DEFINITIONS ; HBX_BUFSIZ .EQU $40 ; INTERBANK COPY BOUNCE 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 ; ; NOTE: THE SIZE OF HBX_TMPSTK (TYPICALLY 20 BYTES) IS INSUFFICIENT FOR ; FREERTOS IF AN INTERRUPT STRIKES WHILE THE TEMPORARY STACK IS ACTIVE. ; BELOW, HBX_BUF HAS BEEN USURPED TO PROVIDE A LARGER TEMP STACK TO ; ACCOMMODATE FREERTOS. HBX_BUF IS ONLY USED AS A BOUNCE BUFFER, SO IT'S ; USE WILL NEVER OVERLAP WITH BELOW. ; ; WARNING: HBX_INVOKE IS *NOT* REENTRANT! ; HBX_INVOKE: ; #IF (INTMODE == 0) ; IF SOMETHING IN USERLAND ENABLES INTERRUPTS AND WE ARE NOT ; CONFIGURED TO USE THEM, THEN SHUT THEM BACK OFF AGAIN FOR ; SAFETY. DI #ENDIF ; #IF (HBIOS_MUTEX == TRUE) PUSH HL ; SAVE HL LD HL,HB_LOCK ; POINT TO LOCK SRA (HL) ; TEST/ACQUIRE MUTEX LOCK JR C,$-2 ; KEEP TRYING ON FAILURE POP HL ; RESTORE HL #ENDIF ; #IF (MEMMGR == MM_Z280) ; LD A,(HB_CURBNK) ; GET CURRENT BANK LD (HB_INVBNK),A ; SAVE INVOCATION BANK ; LD A,BID_BIOS ; HBIOS BANK LD (HB_CURBNK),A ; SET AS CURRENT BANK ; SC HB_DISPATCH ; PUSH AF LD A,(HB_INVBNK) LD (HB_CURBNK),A POP AF ; #ELSE ; LD (HBX_INVSP),SP ; SAVE ORIGINAL STACK FRAME LD SP,HBX_BUF_END ; BORROW HBX_BUF FOR TEMP STACK ; LD A,(HB_CURBNK) ; GET CURRENT BANK LD (HB_INVBNK),A ; SAVE INVOCATION BANK ; 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_BUF_END ; BORROW HBX_BUF FOR TEMP STACK 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 ; #ENDIF ; #IF (HBIOS_MUTEX == TRUE) PUSH HL ; SAVE HL LD HL,HB_LOCK ; POINT TO LOCK LD (HL),$FE ; RELEASE MUTEX LOCK POP HL ; RESTORE HL #ENDIF ; RET ; RETURN TO CALLER ; ;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ;; BNKSEL - Switch Memory Bank to Bank in A. ;; AF is destroyed, all other registers are preserved. ;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ; 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. OR A ; SET FLAGS JP P,HBX_ROM ; 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) #IF (CPUFAM == CPU_EZ80) 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_NN_A(MPGSEL_0) ; BANK_0: 0K - 16K INC A ; OUT_NN_A(MPGSEL_1) ; BANK_1: 16K - 32K RET ; DONE #ELSE 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 #IF (PLATFORM == PLT_DUO) ADD A,64 ; ADD 64 x 32K - RAM STARTS FROM 2048K #ELSE ADD A,ROMSIZE / 32 ; STARTING RAM BANK NUMBER OFFSET #ENDIF ; HBX_ROM: RLCA ; TIMES 2 - GET 16K PAGE INSTEAD OF 32K EZ80_IO() OUT (MPGSEL_0),A ; BANK_0: 0K - 16K INC A ; EZ80_IO() OUT (MPGSEL_1),A ; BANK_1: 16K - 32K #IF (CPUFAM == CPU_Z280) PCACHE #ENDIF RET ; DONE #ENDIF #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: AND %00011111 ; AVOID WRAPPING BITS 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: AND %00111111 ; AVOID WRAPPING BITS 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 ; #IF (MEMMGR == MM_Z280) PUSH BC ; SAVE BC PUSH HL ; SAVE HL LD B,$00 ; FIRST USER PDR SC Z280_BNKSEL ; SYSCALL POP HL ; RESTORE HL POP BC ; RESTORE BC RET ; DONE #ENDIF ; #IF (MEMMGR == MM_ZRC) 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,ROMSIZE / 32 ; STARTING RAM BANK NUMBER OFFSET ; HBX_ROM: OUT ($1F),A ; HCS WRITE TO THE BANK CONTROL REGISTER RET ; DONE #ENDIF ; #IF (MEMMGR == MM_MBC) ; #IF (INTMODE == 1) LD (HBX_MMA),A ; SAVE ACCUM LD A,I ; GET INT CTL REG HB_DI ; DISABLE INTS PUSH AF ; SAVE INT CTL REG LD A,(HBX_MMA) ; RESTORE ACCUM #ENDIF ; OR A ; SET FLAGS JP P,HBX_ROM ; BIT 7 INDICATES RAM OUT (MPCL_ROM),A ; ENSURE ROM PAGE OUT OF MEMORY BEFORE SWITCH ; SEE MBC BANK SELECT MASK SETUP ROUTINE ABOVE HBX_MBCMSK .EQU $+1 ; FORCE TOP 32K ; MASK POPULATED XOR %00000000 ; TO BE IN FIRST CHIP ; DURING INITIALIZATION OUT (MPCL_RAM),A ; SET RAM PAGE SELECTOR JR HBX_RAMX HBX_ROM: OUT (MPCL_RAM),A ; ENSURE RAM PAGE OUT OF MEMORY BEFORE SWITCH OUT (MPCL_ROM),A ; SET ROM PAGE SELECTOR ; HBX_RAMX: ; #IF (INTMODE == 1) POP AF ; RESTORE INT CTL REG JP PO,$+4 ; WERE INTS DISABLED AT ENTRY? EI ; *** DO NOT USE HB_EI HERE *** LD A,(HBX_MMA) ; RESTORE INCOMING ACCUM #ENDIF ; RET ; HBX_MMA .DB 0 ; TEMPORARY STORAGE FOR REG A #ENDIF ; #IF (MEMMGR == MM_RPH) BIT 7,A ; TEST BIT 7 FOR RAM VS. ROM JR Z,HBX_ROM ; IF NOT SET, SELECT ROM PAGE ; HBX_RAM: AND %00011111 ; AVOID WRAPPING BITS 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,RPH_DEFACR | 80H ; SELECT RAM BY SETTING BIT 7 OUT0 (RPH_ACR),A ; ... IN RPH ACR REGISTER RET ; DONE ; HBX_ROM: OR RPH_DEFACR ; COMBINE WITH DEFAULT BITS OUT0 (RPH_ACR),A ; BANK INDEX TO RPH ACR REGISTER XOR A ; ZERO ACCUM OUT0 (Z180_BBR),A ; ZERO BANK BASE RET ; DONE #ENDIF ; #IF (MEMMGR == MM_MON) ; ; CURRENTLY ASSUMES FIRST 16 PAGES ARE RAM FOLLOWED BY 16 PAGES OF ROM. ; SO, WE MAP HBIOS BANKS $00-$0F (ROM SELECT) TO $10-$%1F AND HBIOS ; BANKS $80-$8F (RAM SELECT) TO $00-$0F. ; 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 OUT ($FF),A ; DO IT RET ; AND DONE ; HBX_ROM: ADD A,$10 ; OFFSET INTO ROM BANKS OUT ($FF),A ; DO IT RET ; DONE #ENDIF ; #IF (MEMMGR == MM_Z280) ; ; REG A HAS BANK ID, REG B HAS INITIAL PDR TO PROGRAM ; REGISTERS AF, BC, HL DESTROYED ; Z280_BNKSEL: ;; *DEBUG* ;CALL PC_LBKT ;CALL PRTHEXBYTE ;CALL PC_RBKT ; SELECT I/O PAGE $FE (SAVING PREVIOUS VALUE) LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER LDCTL HL,(C) ; GET CURRENT I/O PAGE PUSH HL ; SAVE IT LD L,$FF ; NEW I/O PAGE LDCTL (C),HL ; IMPLEMENT ; ; CONVERT BANK ID TO TOP 12 BITS OF PHYSICAL ADDRESS ; WITH $0A IN THE LOW ORDER NIBBLE: ; BANK ID: R000 BBBB ; PDR: R000 0BBB B000 1010 (RCBUS) ; PDR: 0000 RBBB B000 1010 (ZZ80MB) ; MULTU A,$80 ; HL=0R00 0BBB B000 0000 BIT 6,H ; RAM BIT SET? JR Z,Z280_BNKSEL2 ; IF NOT, ALL DONE RES 6,H ; OTHERWISE, REMOVE RAM BIT LD A,RAMBIAS >> 6 ; RAM OFFSET (TOP 8 BITS) OR H ; RECOMBINE LD H,A ; AND PUT BACK IN H ; Z280_BNKSEL2: ; ; SET LOW NIBBLE LD A,$0A ; VALUE FOR LOW NIBBLE ADD HL,A ; ADD HL,A ; HL=0000 RBBB B000 1010 ; ; POINT TO FIRST PDR TO PROGRAM LD A,B ; INITIAL PDR TO PROG OUT (Z280_MMUPDRPTR),A ; SET THE PDR POINTER ; ; PROGRAM 8 PDRS LD C,Z280_MMUBLKMOV ; PDR BLOCK MOVE PORT ;LD B,8 ; PROGRAM 8 PDRS LD A,$10 ; PDR VALUE INCREMENT Z280_BNKSEL3: ; PROGRAM 8 PDR VALUES ; LOOP UNROLLED FOR SPEED OUTW (C),HL ; WRITE VALUE ADD HL,A ; BUMP VALUE OUTW (C),HL ; WRITE VALUE ADD HL,A ; BUMP VALUE OUTW (C),HL ; WRITE VALUE ADD HL,A ; BUMP VALUE OUTW (C),HL ; WRITE VALUE ADD HL,A ; BUMP VALUE OUTW (C),HL ; WRITE VALUE ADD HL,A ; BUMP VALUE OUTW (C),HL ; WRITE VALUE ADD HL,A ; BUMP VALUE OUTW (C),HL ; WRITE VALUE ADD HL,A ; BUMP VALUE OUTW (C),HL ; WRITE VALUE ADD HL,A ; BUMP VALUE ;DJNZ Z280_BNKSEL3 ; DO ALL PDRS ; ; RESTORE I/O PAGE LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER POP HL ; RECOVER ORIGINAL I/O PAGE LDCTL (C),HL ; RET ; Z280_BNKSEL_LEN .EQU $ - Z280_BNKSEL ; #ENDIF ; ; Z280 SYSCALL VECTOR ENTRY POINT. TAKES STACK PARAMETER AS A BRANCH ; ADDRESS AND CALLS IT. ALLOWS ANY USER MODE CODE TO CALL INTO AN ; ARBITRARY LOCATION OF SYSTEM MODE CODE. ; #IF (MEMMGR == MM_Z280) Z280_SYSCALL: EX (SP),HL LD (Z280_SYSCALL_GO + 1),HL POP HL Z280_SYSCALL_GO: CALL $FFFF ; PARM SET ABOVE RETIL ; RETURN FROM INT #ENDIF ; ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ; Copy Data - Possibly between banks. This resembles CP/M 3, but ; usage of the HL and DE registers is reversed. ; Caller MUST preset HBX_SRCBNK and HBX_DSTBNK. ; IM1/IM2 interrupts are disabled during HBX_BNKCPY. ; Enter: ; HL = Source Address ; DE = Destination Address ; BC = Number of bytes to copy ; Exit : None ; Uses : AF,BC,DE,HL ; ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ; HBX_BNKCPY: #IF (MEMMGR == MM_Z280) SC Z280_BNKCPYX ; SYSCALL TO BNKCPYX RET ; IOPRSAV .DW 0 ; TEMP STORAGE FOR IOPR ; #ELSE #IF (CPUFAM == CPU_Z280) PUSH HL PUSH BC LD C,Z280_MSR LDCTL HL,(C) POP BC EX (SP),HL HB_DI #ELSE LD A,I HB_DI PUSH AF #ENDIF 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 #IF (CPUFAM == CPU_Z280) EX (SP),HL ; SAVE HL, RECOVER MSR PUSH BC ; SAVE BC LD C,Z280_MSR LDCTL (C),HL POP BC ; RECOVER BC POP HL ; RECOVER HL #ELSE POP AF JP PO,$+4 EI ; *** DO NOT USE HB_EI HERE *** #ENDIF 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 #ENDIF ; ; 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, IX=TARGET ADDRESS ; HBX_BNKCALL: ; #IF (MEMMGR == MM_Z280) CP BID_BIOS ; CALLING HBIOS? JR NZ,HBX_BNKCALL3 ; NOPE, DO NORMAL PROCESSING SC HBX_BNKCALL2 ; SYSCALL TO BNKCALL2 RET ; THEN RETURN ; HBX_BNKCALL2: HB_EI ; INTS ARE OK LD (HBX_BNKCALL_GO+1),IX ; SETUP DEST ADR PCACHE ; CRITICAL!!! HBX_BNKCALL_GO: JP $FFFF ; DO THE REAL WORK AND RETURN #ENDIF ; HBX_BNKCALL3: LD (HBX_BNKCALL_BNK+1),A ; STUFF TARGET BANK TO CALL INTO CODE BELOW LD (HBX_BNKCALL_ADR+1),IX ; STUFF ADDRESS TO CALL INTO CODE BELOW LD A,(HB_CURBNK) ; GET CURRENT BANK PUSH AF ; SAVE FOR RETURN HBX_BNKCALL_BNK: LD A,$FF ; LOAD BANK TO CALL ($FF OVERLAID AT ENTRY) CALL HBX_BNKSEL ; ACTIVATE THE NEW BANK HBX_BNKCALL_ADR: 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 ; ; THESE ROUTINES ARE NOT INTENDED TO BE CALLED DIRECTLY -- THEY ARE ; HELPERS FOR THE HBIOS API AND ARE CALLED BY HBIOS BANK CODE. THE ; HBIOS BANK CODE BRACKETS THE USE OF THESE ROUTINES WITH DI/EI IF ; NECESSARY FOR THE CURRENT INTERRUPT MODE. ; ; NOTE: THE SIZE OF HBX_TMPSTK (TYPICALLY 20 BYTES) IS INSUFFICIENT FOR ; FREERTOS IF AN INTERRUPT STRIKES WHILE THE TEMPORARY STACK IS ACTIVE. ; BELOW, HBX_BUF HAS BEEN USURPED TO PROVIDE A LARGER TEMP STACK TO ; ACCOMMODATE FREERTOS. HBX_BUF IS ONLY USED AS A BOUNCE BUFFER, SO IT'S ; USE WILL NEVER OVERLAP WITH BELOW. ; HBX_PEEK: LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME ;;;LD SP,HBX_BUF_END ; BORROW HBX_BUF FOR TEMP STACK LD SP,HBX_BUF_END - $20 ; BORROW HBX_BUF FOR TEMP STACK 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_BUF_END ; BORROW HBX_BUF FOR TEMP STACK LD SP,HBX_BUF_END - $20 ; BORROW HBX_BUF FOR TEMP STACK LD A,(HB_CURBNK) PUSH AF LD A,D CALL HBX_BNKSEL LD (HL),E ; HBX_PPRET: POP AF #IF (MEMMGR == MM_Z280) LD A,(HB_INVBNK) ; SPECIAL CASE FOR Z280 MEM MGR #ENDIF CALL HBX_BNKSEL LD SP,0 ; RESTORE ORIGINAL STACK FRAME HBX_PPSP .EQU $ - 2 RET ; ; PRIVATE STACK AT END OF HBIOS CODE ; OCCUPIES SPACE BEFORE IVT ; #IF (MEMMGR != MM_Z280) ; ; HEATH FRONT PANEL WORK SPACE (4 BYTES) ; #IF (H8PENABLE) H8P_MEMLOC: .DW 0 H8P_MEMVAL: .DB 0 H8P_MEMCPY: LD HL,(H8P_TICCNT) LD ($000B),HL LD HL,(H8P_MEMLOC) LD A,(HL) LD (H8P_MEMVAL),A RET #ENDIF ; HBX_INTSTKSIZ .EQU $FF00 - $ MEMECHO "HBIOS INT STACK space: " MEMECHO HBX_INTSTKSIZ MEMECHO " bytes.\n" .FILL HBX_INTSTKSIZ,$FF HBX_INTSTK .EQU $ ; #IF (HBX_INTSTKSIZ < 22) .ECHO "*** ERROR: INTERRUPT STACK IS TOO SMALL!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF ; #ENDIF ; ; HBIOS INTERRUPT MODE 2 SLOT ASSIGNMENTS (SEE STD.ASM) ; ; # Z80/Z280 Z180 MBC DUO NABU ; --- -------------- -------------- -------------- -------------- -------------- ; 0 CTC0A INT1 -+ -+ -+ HCCARCV -+ ; 1 CTC0B INT2 | | | HCCASND | ; 2 CTC0C TIM0 | | IM2 | IM2 NABUKB | IM2 ; 3 CTC0D TIM1 | | INT | INT VDP | INT ; 4 UART0 DMA0 | Z180 UART0 | VEC UART0 | VEC OPTCRD0 | VEC ; 5 UART1 DMA1 | CPU UART1 | GEN UART1 | GEN OPTCRD1 | GEN ; 6 CSIO | | | OPTCRD2 | ; 7 SIO0 SER0 | -+ -+ OPTCRD3 -+ ; 8 SIO1 SER1 -+ SIO0 SIO0 ; 9 PIO0A PIO0A SIO1 SIO1 ; 10 PIO0B PIO0B PIO0A PIO0A ; 11 PIO1A PIO1A PIO0B PIO0B ; 12 PIO1B PIO1B CTC0A CTC0A ; 13 SIO0 CTC0B CTC0B ; 14 SIO1 CTC0C CTC0C ; 15 CTC0D CTC0D ; ; IVT MUST START AT PAGE BOUNDARY ALIGN($100) ; 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 ; HBX_INT: ; COMMON INTERRUPT ROUTING CODE ; #IF (INTMODE > 0) ; #IF (MEMMGR == MM_Z280) ; ; THIS CODE ASSUMES Z280 IM 3. IM 1 AND IM 2 ON Z280 ; DO NOT SAVE MSR AT INTERRUPT MAKING IT VIRTUALLY IMPOSSIBLE ; TO RETURN FROM THE INTERRUPT TO THE CORRECT MODE (SYSTEM ; OR USER). THIS IS BECAUSE THERE IS NO WAY TO KNOW WHETHER ; SYSTEM OR USER MODE WAS ACTIVE AT THE TIME OF THE INTERRUPT. ; EX (SP),HL ; SAVE HL AND GET INT JP TABLE OFFSET ; 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 ; ; HANDLE INT VIA JP TABLE IN HBIOS 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 ; ; RESTORE STATE POP IY ; RESTORE IY POP DE ; RESTORE DE POP BC ; RESTORE BC POP AF ; RESTORE AF POP HL ; RESTORE HL ; ; BURN THE REASON CODE EX (SP),HL ; HL TO STK, RC TO HL POP HL ; RESTORE HL ; CALL HBX_RETI ; RETI FOR Z80 PERIPHERALS RETIL ; HBX_RETI: RETI ; #ELSE ; ; COMMON INTERRUPT DISPATCHING CODE ; SETUP AND CALL HANDLER IN BIOS BANK ; EX (SP),HL ; SAVE HL AND GET INT JP TABLE OFFSET ; LD (HBX_INT_SP),SP ; SAVE ORIGINAL STACK FRAME LD SP,HBX_INTSTK ; USE DEDICATED INT 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 ; #IF (H8PENABLE) CALL H8P_MEMCPY #ENDIF ; ; 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 ; #IF (CPUFAM == CPU_EZ80) RET.L ; INTERRUPTS WILL BE ENABLED BY BY EZ80 FIRMWARE ; CAN THEY BE ENABLED HERE - DOES THAT RISK RE-ENTRANT OF THE HANDLER? #ELSE HB_EI ; ENABLE INTERRUPTS RETI ; AND RETURN #ENDIF ; #ENDIF ; #ELSE ; RET ; #ENDIF ; ; SMALL TEMPORARY STACK FOR USE BY HBX_BNKCPY ; HBX_TMPSTKSIZ .EQU (HBX_XFC - HBX_BUFSIZ - $) MEMECHO "HBIOS TEMP STACK space: " MEMECHO HBX_TMPSTKSIZ MEMECHO " bytes.\n" .FILL HBX_TMPSTKSIZ,$CC HBX_TMPSTK .EQU $ ; ; INTERBANK COPY BOUNCE BUFFER (64 BYTES) ; ; N.B., THIS BUFFER IS ALSO USED AS A TEMPORARY STACK BY INVOKE, PEEK, AND POKE. ; THEREFORE, THIS BUFFER *CANNOT* BE USED TO PASS DATA OUTSIDE OF ; HBIOS FUNCTION CALLS. ; HBX_BUF .FILL HBX_BUFSIZ,0 HBX_BUF_END .EQU $ ; ; HBIOS PROXY MGMT BLOCK (TOP 32 BYTES) ; .DB BID_BOOT ; (+0) HB_CURBNK: CURRENTLY ACTIVE LOW MEMORY BANK ID .DB $FF ; (+1) HB_INVBNK: BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION .DW 0 ; (+2) HB_SRCADR: BNKCPY SOURCE ADDRESS .DB BID_USR ; (+4) HB_SRCBNK: BNKCPY SOURCE BANK ID .DW 0 ; (+5) HB_DSTADR: BNKCPY DESTINATION ADDRESS .DB BID_USR ; (+7) HB_DSTBNK: BNKCPY DESTINATION BANK ID .DW 0 ; (+8) HB_CPYLEN: BNKCPY LENGTH .DW 0 ; (+10) RESERVED FOR OPTIONAL TICK CTR, PLATFORM DEPENDENT .DW 0 ; (+12) RESERVED FOR FUTURE HBIOS USE .DB 0 ; (+14) SHADOW VALUE FOR RTC LATCH PORT .DB $FE ; (+15) HB_LOCK: HBIOS MUTEX LOCK JP HBX_INVOKE ; (+16) HB_INVOKE: FIXED ADR ENTRY FOR HBX_INVOKE (ALT FOR RST 08) JP HBX_BNKSEL ; (+19) HB_BNKSEL: FIXED ADR ENTRY FOR HBX_BNKSEL JP HBX_BNKCPY ; (+22) HB_BNKCPY: FIXED ADR ENTRY FOR HBX_BNKCPY JP HBX_BNKCALL ; (+25) HB_BNKCALL: FIXED ADR ENTRY FOR HBX_BNKCALL .DW HBX_IDENT ; (+28) ADDRESS OF HBIOS PROXY START (DEPRECATED) .DW HBX_IDENT ; (+30) HB_IDENT: ADDRESS OF HBIOS IDENT INFO DATA BLOCK ; .FILL MEMTOP - $ ; FILL TO END OF MEMORY (AS NEEDED) .ORG HBX_IMG + HBX_SIZ ; RESTORE ORG ; HB_PROXY_END .EQU $ ; ;================================================================================================== ; ENTRY VECTORS (JUMP TABLE) AND INTERNAL PROCESSING STACK ;================================================================================================== ; HB_ENTRY_BEG .EQU $ HB_ENTRYTBL .EQU $ ; JP HB_START ; HBIOS INITIALIZATION JP HB_DISPATCH ; VECTOR TO DISPATCHER JP PRTSUM ; !!! DO NOT ADD ADDTIONAL VECTORS HERE WITHOUT ; CHECKING W/ WAYNE !!! ; HB_STKSIZ .EQU $100 - ($ & $FF) ; .FILL HB_STKSIZ,$FF ; USE REMAINDER OF PAGE FOR HBIOS STACK HB_STACK .EQU $ ; TOP OF HBIOS STACK HB_ENTRY_END .EQU $ ; ;================================================================================================== ; INTERRUPT VECTOR TABLE (MUST START AT PAGE BOUNDARY!!!) ;================================================================================================== ; ; 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. ; HB_INTVEC_BEG .EQU $ ; 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 HB_IVT10: JP HB_IM1INT \ .DB 0 ; ; 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. ; HB_IM1INT: 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 ; HB_IM1CNT .DB 0 ; NUMBER OF ENTRIES IN CALL LIST HB_IM1MAX .DB 8 ; MAX ENTRIES IN CALL LIST HB_IM1PTR .DW HB_IM1INT ; POINTER FOR NEXT IM1 ENTRY ; HB_INTVEC_END .EQU $ ; ;================================================================================================== ; SYSTEM INITIALIZATION ;================================================================================================== ; HB_SYSINIT_BEG .EQU $ ; HB_START: ; #IFDEF APPBOOT ; THE CODE TO PREPARE FOR AN APPBOOT IS "HIDDEN" IN HB_WRKBUF. ; WE ARE OPERATING ON THE (MINIMAL) BDOS STACK, BUT THAT ; SHOULD BE FINE FOR THIS LIMITED ACTIVITY. CALL HB_APPBOOT ; PREPARE APP BOOT RET NZ ; RETURN ON ERROR ; #ENDIF ; HB_RESTART: ; DI ; NO INTERRUPTS #IF (CPUFAM != CPU_EZ80) IM 1 ; INTERRUPT MODE 1 #ENDIF ; #IFDEF APPBOOT ; ; IF THIS IS AN APPLICATION BOOT, WE CAPTURE THE CURRENT BANK ID ; AND UPDATE THE PROXY IMAGE. LATER, WHEN THE PROXY IMAGE IS COPIED ; TO IT'S RUNNING LOCATION AT TOP OF RAM, THE CORRECT HB_CURBNK ; VALUE WILL BE INSTALLED. NOTE: THE ADDRESSES IN THE PROXY ; IMAGE ARE FOR IT'S RUNNING LOCATION, SO WE NEED TO USE *MATH* ; TO DERIVE THE LOCATION OF HB_CURBNK IN THE IMAGE. LD A,(HB_CURBNK) LD (HB_CURBNK - HBX_LOC + HBX_IMG),A ; #ENDIF ; #IF ((PLATFORM == PLT_DUO) & TRUE) ; THIS ARBITRARY DELAY SEEMS TO HELP DUODYNE CPU V1.0 SYSTEMS ; STARTUP CLEANLY. DOUDYNE CPU V1.1 INTRODUCES A RESET ; SUPERVISOR AND THIS DELAY IS UNNECESSARY. WE DON'T KNOW ; IF WE ARE ON A V1.1 THOUGH, SO WE ALWAYS DO THE DELAY. LD HL,0 BOOTWAIT: DEC HL LD A,H OR L JR NZ,BOOTWAIT #ENDIF ; ; EARLY RTC LATCH BYTE INITIALIZATION ; FOR SOME PLATFORMS THIS CONTROLS HI/LO SPEED CIRCUIT ; NOTE: WE WANT TO USE (RTCDEFVAL) HERE, BUT THE Z2 MEMORY ; MANAGER STARTS UP WITH THE FIRST 16K OF ROM MAPPED TO ALL ; 4 16K BANKS OF CPU SPACE. SO, IF RTCDEVFAL IS LOCATED AFTER ; PAST 16K, WE DON'T HAVE ACCESS TO IT. FOR NOW, WE JUST USE ; RTCDEF WHICH IS SUBOPTIMAL, BUT PROBABLY DOES NOT CAUSE ANY ; PROBLEMS. ; ;LD A,(RTCDEFVAL) ; GET DEFAULT VALUE LD A,RTCDEF ; DEFAULT VALUE EZ80_IO() OUT (RTCIO),A ; SET IT ; #IF (PLATFORM == PLT_N8) LD A,N8_DEFACR ; ENSURE N8 ACR OUT0 (N8_ACR),A ; ... REGISTER IS INITIALIZED #ENDIF ; #IF (PLATFORM == PLT_RPH) LD A,RPH_DEFACR ; ENSURE RPH ACR OUT0 (RPH_ACR),A ; ... REGISTER IS INITIALIZED #ENDIF ; ; INITIALIZE DIAGNOSTIC AND/OR FRONT PANEL LED(S) TO INDICATE THE ; SYSTEM IS ALIVE. WE HAVE NO RAM AT THIS TIME, SO WE CANNOT USE ; THE NORMAL DIAG() OR FPLEDS() MACROS WHICH DEPEND UPON A STACK. ; SO, JUST HACK THE VALUES IN PLACE. ; #IF (FPLED_ENABLE) #IF (FPLED_INV) LD A,~DIAG_01 #ELSE LD A,DIAG_01 #ENDIF ; EZ80_IO() OUT (FPLED_IO),A #ENDIF ; #IF (LEDENABLE) #IF ((LEDMODE == LEDMODE_STD) | (LEDMODE == LEDMODE_SC)) XOR A ; LED IS INVERTED, TURN IT ON #ENDIF #IF (LEDMODE == LEDMODE_RTC) ; CAN'T USE (RTCDEFVAL) YET, SEE COMMENTS ABOVE ;LD A,(RTCDEFVAL) ; DEFAULT LATCH VALUE LD A,RTCDEF | %00000001 ; LED 0 ON #ENDIF #IF (LEDMODE == LEDMODE_NABU) LD A,%00001000 ; LOW LED BIT ONLY #ENDIF OUT (LEDPORT),A #ENDIF ; ; INITIALIZE SP ; ; WARNING: ALTHOUGH WE ARE INITIALIZING SP HERE, IT IS NOT YET ; SAFE TO PUSH VALUES TO THE STACK BECAUSE SOME PLATFORMS WILL ; NOT YET HAVE RAM MAPPED TO THE UPPER 32K YET! ; LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY ; ; Z280 BARE METAL INIT ; #IF (CPUFAM == CPU_Z280) ; CLEAR THE MASTER STATUS REGISTER LD C,Z280_MSR ; MASTER STATUS REGISTER LD HL,$0000 ; SYS MODE, NO INTERRUPTS LDCTL (C),HL ; DO IT ; ; SET MAXIMUM I/O WAIT STATES FOR NOW LD C,Z280_BTCR ; BUS TIMING AND CONTROL REGISTER LD HL,$0033 ; 3 I/O WAIT STATES ADDED LDCTL (C),HL ; DO IT ; ; SELECT I/O PAGE $FF FOR INTERNAL SYSTEM REGISTER ACCESS LD L,$FF ; MMU AND DMA PAGE I/O REG IS $FF LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER LDCTL (C),HL ; DO IT ; ; DISABLE MEMORY REFRESH CYCLES LD A,$08 ; REFRESH DISABLED OUT (Z280_RRR),A ; DO IT ; ; INITIALIZE CACHE CONTROL REGISTER LD A,$20 ; CACHE INSTRUCTIONS, NOT DATA OUT (Z280_CCR),A ; DO IT ; ; INITIALIZE TRAP CONTROL REGISTER LD A,$00 ; ALLOW USER I/O, NO EPU, NO STK WARN OUT (Z280_TCR),A ; DO IT ; #IF (MEMMGR == MM_Z280) ; ; BEFORE ENABLING MMU W/ USER & SYSTEM PAGE TRANSLATION, ; WE INITIALIZE ALL PDRS. HOWEVER, FOR AN APP ; BOOT, THE LOW RAM PDRS ARE ALREADY CORRECT AND SHOULD BE ; LEFT ALONE. ; ; INITIALIZE ALL OF THE USER PAGE DESCRIPTORS WITH BLOCK MOVE #IFDEF APPBOOT LD A,$08 ; FIRST USER PDR IN HI MEM #ELSE LD A,$00 ; FIRST USER PDR #ENDIF OUT (Z280_MMUPDRPTR),A ; SET THE PDR POINTER LD HL,Z280_BOOTPDRTBL ; START OF PDR VALUES TABLE LD C,Z280_MMUBLKMOV ; PDR BLOCK MOVE PORT LD B,Z280_PDRCNT ; NUMBER OF PDR ENTRIES TO PROG OTIRW ; OTIRW PROGS PDRS SEQUENTIALLY ; ; INITIALIZE ALL OF THE SYSTEM PAGE DESCRIPTORS WITH BLOCK MOVE #IFDEF APPBOOT LD A,$18 ; FIRST SYSTEM PDR IN HI MEM #ELSE LD A,$10 ; FIRST SYSTEM PDR #ENDIF OUT (Z280_MMUPDRPTR),A ; SET THE PDR POINTER LD HL,Z280_BOOTPDRTBL ; START OF PDR VALUES TABLE LD C,Z280_MMUBLKMOV ; PDR BLOCK MOVE PORT LD B,Z280_PDRCNT ; NUMBER OF PDR ENTRIES TO PROG OTIRW ; OTIRW PROGS PDRS SEQUENTIALLY ; ; ENABLE MMU (SYSTEM AND USER TRANSLATION) LD C,Z280_MMUMCR ; MMU MASTER CONTROL REGISTER LD HL,$BBFF ; ENABLE USER & SYSTEM TRANSLATE OUTW (C),HL ; JR Z280_INITZ ; JUMP TO CODE CONTINUATION ; ALIGN(2) ; WORD ALIGN THE PDR TABLE ; Z280_BOOTPDRTBL: #IFNDEF APPBOOT ; LOWER 32 K (BANKED) .DW ((Z2_BANK(BID_BOOT) + 0) << 4) | $A .DW ((Z2_BANK(BID_BOOT) + 1) << 4) | $A .DW ((Z2_BANK(BID_BOOT) + 2) << 4) | $A .DW ((Z2_BANK(BID_BOOT) + 3) << 4) | $A .DW ((Z2_BANK(BID_BOOT) + 4) << 4) | $A .DW ((Z2_BANK(BID_BOOT) + 5) << 4) | $A .DW ((Z2_BANK(BID_BOOT) + 6) << 4) | $A .DW ((Z2_BANK(BID_BOOT) + 7) << 4) | $A #ENDIF ; UPPER 32 K (COMMON) .DW ((Z2_BANK(BID_COM) + 0) << 4) | $A .DW ((Z2_BANK(BID_COM) + 1) << 4) | $A .DW ((Z2_BANK(BID_COM) + 2) << 4) | $A .DW ((Z2_BANK(BID_COM) + 3) << 4) | $A .DW ((Z2_BANK(BID_COM) + 4) << 4) | $A .DW ((Z2_BANK(BID_COM) + 5) << 4) | $A .DW ((Z2_BANK(BID_COM) + 6) << 4) | $A .DW ((Z2_BANK(BID_COM) + 7) << 4) | $A ; Z280_PDRCNT .EQU ($ - Z280_BOOTPDRTBL) / 2 ; Z280_INITZ: ; #ENDIF ; ; RESTORE I/O PAGE TO $00 FOR NORMAL USER I/O SPACE LD L,$00 ; NORMAL I/O REG IS $00 LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER LDCTL (C),HL ; #ENDIF ; ; Z180 BARE METAL INIT ; #IF (CPUFAM == CPU_Z180) ; SET BASE FOR CPU IO REGISTERS ; DO NOT USE Z180_ICR FROM Z180.INC BECAUSE THE ICR ; IS NOT YET AT THE RUNNING LOCATION. AT RESET, THE Z180 ; REGISTER BASE I/O ADDRESS IS ZERO, SO INITIALLY, ICR IS ; AT $3F. LD A,Z180_BASE OUT0 ($3F),A ; AT RESET, ICR IS AT $3F ; DISABLE REFRESH XOR A OUT0 (Z180_RCR),A ; MASK OFF TIMER INTERRUPTS XOR A OUT0 (Z180_TCR),A OUT0 (Z180_ITC),A ; SET DEFAULT CPU CLOCK MULTIPLIERS (XTAL / 2) ; ; BILL MCMULLEN REPORTED THAT CMR NEEDS TO BE SET PRIOR TO CCR ; WHEN USING A CPU FREQUENCY (PHI) THAT IS XTAL * 2. ; HERE WE ARE SETTING CPU FREQUENCY TO XTAL / 2, BUT JUST ; FOR GOOD MEASURE, CMR IS SET PRIOR TO CCR BELOW. ; https://www.retrobrewcomputers.org/forum/index.php?t=msg&th=316&goto=5045&#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) | (MEMMGR == MM_RPH)) ; 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 ; ; SET DEFAULT CSIO SPEED (INTERNAL CLOCK, SLOW AS POSSIBLE) LD A,Z180_CNTR_DEF ; DIV 1280, 14KHZ @ 18MHZ CLK OUT0 (Z180_CNTR),A #ENDIF ; #ENDIF ; ; EIPC BARE METAL INIT ; #IF (EIPCENABLE) LD A,(EIPC_WDT_CONST | EIPC_HALT_RUN | EIPC_WDT_P2_22) OUT (EIPC_WDTMR),A ; CLEAR WDTE BIT (DISABLE WATCHDOG) LD A,EIPC_DIS_WDT ; DISABLE WDT - SECOND KEY OUT (EIPC_WDTCR),A LD A,EIPC_WCR ; SET SYSTEM CONTROL REGISTER POINTER ; (SCRP) TO POINT TO WAIT STATE OUT (EIPC_SCRP),A ; CONTROL REGISTER (WCR) LD A,(EIPC_IO_0WS | EIPC_MEM_OWS | EIPC_OCF_0WS | EIPC_INT_0WS | EIPC_CHAIN_0WS) OUT (EIPC_SCDP),A ; NO WAIT STATES LD A,EIPC_MCR ; SET SCRP TO POINT TO MISCELLANEOUS OUT (EIPC_SCRP),A ; CONTROL REGISTER (MCR) LD A,EIPC_CLKDIV1 ; DIVIDE CLOCK BY 1, /CS0 DISABLE OUT (EIPC_SCDP),A ; SET SYSTEM CONTROL DATA PORT (SCDP) #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; PLATFORM MEMORY MANAGEMENT INITIALIZATION ;-------------------------------------------------------------------------------------------------- ; ; INITIALIZE MEMORY MANAGERS AS NEEDED TO ADDRESS BOOT ROM IN LOW 32K ; AND COMMON RAM IN HIGH 32K. SETUP MMU FOR BANKING IN LOWER 32K. ; ; Z180 MINI-ITX MADNESS TO INITIALIZE THE PPIO. WE HAVE THE MAIN RAM AT ; $8000 AND ROM AT $0 AT THIS POINT AND THE Z180 MMU SET UP. NOW ; GET THE 82C55 PROGRAMMED. ; #IF (PLATFORM == PLT_EPITX) ; THE 82C55 IS BRAINDEAD AND FLIPS OUTPUT LINES TO 0 WHEN WE SET ; THE MODE. WE BOOT WITH THE ROM ENABLED BUT THE RESET WILL ENABLE ; LOW RAM. SOME MENTAL BACKFLIPS REQUIRED TO MAKE THIS WORK LD HL,BOOTFLIP LD DE,$8000 LD BC,$10 LDIR JP $8000 ; BOOTFLIP: ; SET THE MODE. ALSO CLEARS ALL THE OUTPUT BITS SO WE BLIP THE ; I2C, KEYBOARD ETC BUT NOBODY WILL CARE. HOWEVER WE ALSO FLIP ; TO ALL RAM MODE HENCE THIS IS EXECUTED HIGH ; A OUT B IN C HIGH IN C LOW IN LD A,$8B OUT ($43),A LD A,$FF OUT ($40),A JP ROMRESUME ; ROMRESUME: ; THIS WILL GLITCH EXTRAM ON SO WE MUST NOW BE IN ROM LD A,$8A ; C LOW NOW OUTPUT OUT ($43),A LD A,$FF OUT ($42),A ; EXTRAM OFF, RAM BACK IN, SPI 7 ; AND DONE. MODE REMAINS THIS WAY FOREVER ; #ENDIF ; ; SBC AND MBC MMU INITIALIZATION ; #IF ((MEMMGR == MM_SBC) | (MEMMGR == MM_MBC)) ; SET PAGING REGISTERS #IFDEF ROMBOOT XOR A OUT (MPCL_RAM),A ; REMOVE RAM FIRST! OUT (MPCL_ROM),A ; SELECT ROM PAGE 0 #ENDIF #ENDIF ; ; ZETA 2 AND DUO MMU INITIALIZATION ; ; ZETA 2 MMU USES 4 16K PAGES TO MAP PHYSICAL MEMORY TO CPU MEMORY. ; HBIOS USES THE LOWER 2 16K PAGES FOR BANKING AND UPPER 2 16K PAGES ; FOR COMMON. NORMALLY, A ZETA 2 BASED SYSTEM WILL CONTAIN 512K OF ; PHYSICAL ROM FOLLOWED BY 512K OF PHYSICAL RAM. DUO USES A PHYSICAL ; ADDRESS SPACE OF 4096K WITH THE FIRST 2048K AS ROM AND THE FOLLOWING ; 2048K AS RAM. THE SIZE OF ROM AND RAM CAN VARY FOR DUO, BUT THE ; RAM BOUNDARY IS ALWAYS AT 2048K. ; #IF (MEMMGR == MM_Z2) ; #IFDEF ROMBOOT ; IF THIS IS A ROM BOOT, SETUP THE FIRST 2 16K MMU REGISTERS ; TO MAP THE LOWEST 32K OF PHYSICAL ROM TO THE LOW 32K OF ; CPU ADDRESS SPACE (BANKING AREA). THE FIRST 16K MAPPING IS ; REDUNDANT BECAUSE WE ARE ALREADY RUNNING IN THIS AREA. THE ; MAPPING OF THE SECOND 16K IS CRITICAL BECAUSE ALL ZETA 2 ; MMU REGISTERS WILL BE 0 AT RESET! XOR A EZ80_IO() OUT (MPGSEL_0),A ; PROG FIRST 16K MMU REGISTER INC A EZ80_IO() OUT (MPGSEL_1),A ; PROG SECOND 16K MMU REGISTER #ENDIF ; #IF (PLATFORM == PLT_DUO) ; DUO HAS VARIABLE RAM SIZE. RAM ALWAYS STARTS AT 2048K. ; SETUP COMMON RAM FOR HIGHEST 32K OF RAM BASED ON TOTAL RAM. LD A,128 + (RAMSIZE / 16) - 2 #ELSE ; NORMAL ZETA 2 SYSTEM HAS FIXED 512K OF RAM. SETUP COMMON ; FOR TOP 32K OF THIS. ;LD A,64 - 2 LD A,((ROMSIZE + RAMSIZE) / 16) - 2 #ENDIF ; EZ80_IO() OUT (MPGSEL_2),A ; PROG THIRD 16K MMU REGISTER INC A EZ80_IO() OUT (MPGSEL_3),A ; PROG FOURTH 16K MMU REGISTER ; ENABLE PAGING LD A,1 EZ80_IO() OUT (MPGENA),A ; ENABLE MMU NOW ; #IF (PLATFORM == PLT_FZ80) ; REMOVE FPGA ROM MONITOR FROM THE CPU ADDRESS SPACE LD A,%00000010 OUT ($07),A #ENDIF #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; PROXY INSTALLATION ;-------------------------------------------------------------------------------------------------- ; ; AT THIS POINT, RAM SHOULD BE AVAILABLE IN THE COMMON BANK ; (TOP 32K). ; ; WE USE THE TWO BYTES IMMEDIATELY BELOW THE PROXY TO STORE A COUPLE ; VALUES TEMPORARILY BECAUSE WE MAY BE OPERATING IN ROM AT THIS POINT. ; (HBX_LOC - 1) = BATCOND, (HBX_LOC - 2) = LOADBANK ; THERE IS NOTHING ON THE STACK AT THIS POINT SO, HERE, WE JUST RESET ; THE STACK TO HBX_LOC - 2. ; LD SP,HBX_LOC - 2 ; ; CHECK BATTERY BACKUP STATUS BEFORE WE TOUCH RAM (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 ; BECAUSE WE ARE CURRENTLY RUNNING IN ROM. AFTER WE TRANSITION HBIOS ; TO RAM, THE VALUE IS MOVED TO IT'S REAL LOCATION AT HB_BATCOND. ; IF THERE IS NO DS1210 IN THE SYSTEM, THE CODE BELOW DOES NO HARM. ; LD HL,HBX_LOC - 1 ; POINT TO BYTE XOR A ; ZERO MEANS LOW BAT LD (HL),A ; FIRST RAM ACCESS INC A ; 1 MEANS BAT OK LD (HL),A ; SECOND RAM ACCESS (BLOCKED IF BATTERY ISSUE) ; ; INSTALL PROXY IN UPPER MEMORY ; LD DE,HBX_LOC ; RUNNING LOCATION OF PROXY LD HL,HBX_IMG ; LOCATION OF PROXY IMAGE LD BC,HBX_SIZ ; SIZE OF PROXY LDIR ; COPY IT ; ; NOTIFICATION THAT WE HAVE COMPLETED HARDWARE INIT. ; FPLEDS(DIAG_02) ; ;-------------------------------------------------------------------------------------------------- ; S100 MONITOR LAUNCH ;-------------------------------------------------------------------------------------------------- ; ; S100 ROM CONTAINS A HARDWARE LEVEL MONITOR IN BANK ID 3 OF ROM. ; IF PORT $75 BIT 1 IS SET (SET IS ZERO), THEN WE IMMEDIATELY ; TRANSITION TO THIS MONITOR. PRIOR TO THE TRANSITION, WE ALSO ; CHECK THE VALUE IN THE Z180 RELOAD REGISTER LOW. IF IT IS ASCII 'W', ; THEN IT MEANS THE S100 MONITOR IS ATTEMPTING TO REBOOT INTO ROMWBW ; HBIOS AND WE ABORT THE TRANSITION TO THE S100 MONITOR. ; #IF ((PLATFORM == PLT_S100) & TRUE) ; CHECK S100 BOARD DIP SWITCH, BIT 1 IN A,($75) ; READ SWITCHES BIT 1,A ; CHECK BIT 1 JR NZ,S100MON_SKIP ; IF NOT SET, CONT ROMWBW BOOT ; ; CHECK RELOAD REGISTER LOW FOR SPECIAL VALUE IN0 A,(Z180_RLDR1L) ; GET RELOAD REG 1 LOW CP 'W' ; CHECK FOR SPECIAL VALUE JR Z,S100MON_SKIP ; IF SO, DO ROMWBW BOOT ; ; LAUNCH S100 MONITOR FROM ROM BANK 3 LD A,BID_IMG2 ; S100 MONITOR BANK LD IX,0 ; EXECUTION RESUMES HERE CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN HALT ; WE SHOULD NOT COME BACK HERE! ; S100MON_SKIP: ; RESTORE DEFAULT RELOAD REGISTER VALUE (PROBABLY NOT NEEDED) XOR A OUT0 (Z180_RLDR1L),A #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; RTC LATCH INITIALIZATION ;-------------------------------------------------------------------------------------------------- ; ; WE CAN NOW DO THE REAL INITIALIZATION OF THE RTC LATCH BASED ON ; (RTCDEFVAL). AT THIS POINT WE SHOULD HAVE ACCESS TO THE ROM LOCATION ; WHERE RTCDEFVAL IS STORED AND THE PROXY IS INSTALLED IN UPPER RAM ; WHERE WE WILL STORE THE WORKING SHADOW COPY (HB_RTCVAL). ; SEE COMMENTS ABOVE REGARDING THE FUNKY WAY THAT THE RTCDEFVAL IS ; CREATED. ; LD A,(RTCDEFVAL) LD (HB_RTCVAL),A EZ80_IO() OUT (RTCIO),A ; SET IT DIAG(1) ; REAPPLY CURRENT DIAG LED SETUP ; ;-------------------------------------------------------------------------------------------------- ; DYNAMIC RAM SIZER (IN DEVELOPMENT) ;-------------------------------------------------------------------------------------------------- ; #IFDEF SIZERAM ; ; THIS IS WHERE WE PROBE FOR THE ACTUAL NUMBER OF RAM ; BANKS AVAILABLE IN THE SYSTEM. THE PROBE CODE NEEDS ; TO BE COPIED TO AND RUN FROM THE COMMON RAM BANK. ; #IF (MEMMGR == MM_MBC) ; MBC REQUIRES A BANK SELECT MASK TO BE SETUP IN THE MBC ; BANK SELECT ROUTINE. HOWEVER, THE MASK IS DERIVED FROM THE ; TOTAL SIZE OF THE RAM IN THE SYSTEM (SEE MBC BANK SELECT ; MASK SETUP BELOW). SO, WE HAVE A CATCH-22 ; HERE FOR MBC. THE DYNAMIC RAM SIZING REQUIRES THE THE MASK ; AND THE MASK SETUP REQUIRES THE TOTAL RAM SIZE. SO, FOR MBC, ; WE CAN'T DO DYNAMIC RAM SIZING. ; .ECHO "*** ERROR: DYNAMIC RAM SIZING NOT POSSIBLE FOR MBC!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF ; LD DE,$F000 LD HL,RS_IMAGE LD BC,RS_LEN LDIR CALL RS_START LD ($FFEA),A ; STASH HERE TO PRINT LATER ; #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; MBC BANK SELECT MASK SETUP ;-------------------------------------------------------------------------------------------------- ; ; THE MBC RAM BOARD CAN CONTAIN 1 OR 2 RAM CHIPS. THE COMMON RAM BANK IS ; FIXED BY HARDWARE TO BE THE TOP 32K OF THE *FIRST* RAM CHIP. WHEN THERE ; ARE 2 RAM CHIPS INSTALLED, THE HARDWARE WILL THUS PLACE THE COMMON RAM IN ; THE MIDDLE OF PHYSICAL RAM. HBIOS REQUIRES THAT THE COMMON RAM BANK BE ; MAPPED TO THE VERY LAST 32K OF PHYSICAL RAM. THIS IS REQUIRED SO THAT ; THE RAM DISK BANKS CAN BE SEQUENTIAL. TO WORK AROUND THIS, WE USE AN ; XOR MASK THAT IS APPLIED DURING BANK SELECT. THIS MASK WILL FLIP THE ; HIGH ORDER BANK SELECT BIT (WHEN 2 RAM CHIPS ARE USED) SO THAT THE TWO ; RAM CHIPS WIND UP "REVERSED" AND THE FIXED COMMON BANK WINDS UP AT THE ; END OF THE RAM BANKS. THE MASK IS SETUP HERE BASED ON THE NUMBER OF RAM ; CHIPS AND THEIR SIZE. NOTE THAT THE NUMBER OF RAM CHIPS IS INFERRED BY ; THE TOTAL RAM SIZE. A SINGLE CHIP WILL BE EITHER 128K OR 512K. IF THE ; TOTAL RAM SIZE OF THE SYSTEM IS 256K OR 1M, THEN THERE MUST BE TWO CH ; IPS. THE RESULTING BANK SELECT MASK IS INSERTED INTO THE MBC BANK ; SELECT ROUTINE. ; #IF (MEMMGR == MM_MBC) ; ; ALTHOUGH DYNAMIC SYSTEM RAM SIZING IS NOT POSSIBLE FOR MBC ; (SEE COMMENTS ABOVE), WE ARE STILL DOING THE MASK SETUP ; DYNAMICALLY. THIS IS SIMPLY IN CASE WE EVER FIND A WAY TO ; DYNAMICALLY SIZE THE RAM IN AN MBC SYSTEM. ; ; 128K: %00000000 ; 1 CHIP, FLIP NO BITS ; 256K: %00000100 ; 2 CHIPS, 8 BANKS, FLIP BIT 2 ; 512K: %00000000 ; 1 CHIP, FLIP NO BITS ; 1024K: %00010000 ; 2 CHIPS, 32 BANKS, FLIP BIT 4 ; ; IF NUMBER OF RAMBANKS DETECTED FOR MBC IS 4 (128KB) OR ; 16 (512KB) THEN ZERO THE BANK MASK, OTHERWISE CALCULATE ; THE BANK MASK AS BANKS/2. ; LD A,(CB_RAMBANKS) LD E,A LD A,%11101011 AND E JR Z,MBC_SINGLE RRA MBC_SINGLE: LD (HBX_MBCMSK),A ; #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; HBIOS TRANSITION TO RAM ;-------------------------------------------------------------------------------------------------- ; ; COPY OURSELVES TO HBIOS BANK IN RAM ; LD A,(HB_CURBNK) ; GET CURRENT BANK ID LD (HBX_LOC - 2),A ; SAVE THE LOAD BANK ; ; CHECK TO SEE IF WE ARE ALREADY RUNNING IN THE HBIOS RAM ; BANK AND SKIP THE COPY IF SO (DON'T COPY OVER OURSELVES). ; THIS SITUATION OCCURS ON A ROMLESS STARTUP OR WHEN DOING A ; FULL RESTART OF A SYSTEM USING THE EXISTING HBIOS COPY. ; NOTE THAT THIS TEST WORKS BECAUSE BID_BIOS == BID_BOOT ; IN THESE SCENARIOS. CP BID_BIOS ; SAME AS BIOS BANK? JR Z,HB_START1 ; IF SO, SKIP ; LD (HB_SRCBNK),A ; CURRENT BANK IS SOURCE LD A,BID_BIOS ; GET BIOS BANK ID LD (HB_DSTBNK),A ; ... AND MAKE IT THE DESTINATION LD HL,0 ; START FROM ADDRESS ZERO LD DE,0 ; SAME FOR DESTINATION LD BC,$8000 ; COPY ENTIRE 32KB BANK #IF (MEMMGR == MM_Z280) ; WE CANNOT USE HBX_BNKCPY FOR Z280 BECAUSE HBX_BNKCPY WILL ; SYSCALL Z280_BNKCPY. SYSCALL IS NOT SAFE YET BECAUSE THE ; Z280 IVT ADDRESS HAS NOT BEEN SETUP. CALL Z280_BNKCPY ; HANDLE Z280 SPECIAL #ELSE CALL HBX_BNKCPY ; ELSE NORMAL BANK COPY #ENDIF ; ; TRANSITION TO HBIOS IN RAM BANK ; #IF (MEMMGR == MM_Z280) ; Z280 NEEDS TO BE HANDLED SPECIAL BECAUSE WE ARE SWITCHING ; THE SYSTEM MODE BANK, NOT THE NORMAL USER MODE BANK. LD A,BID_BIOS LD B,$10 ; FIRST SYSTEM PDR CALL Z280_BNKSEL JR HB_START1 #ELSE ; JUST DOING A BANK CALL TO THE RAM BANK BANK. IF THIS IS A ; ROMLESS BOOT OR AN IN-PLACE HBIOS RESTART, WE ARE ALREADY ; RUNNING IN BID_BIOS BANK. HOWEVER, THIS WILL DO NO HARM. LD A,BID_BIOS ; BIOS BANK ID LD IX,HB_START1 ; EXECUTION RESUMES HERE CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN HALT ; WE SHOULD NOT COME BACK HERE! #ENDIF ; ; EXECUTION RESUMES HERE AFTER SWITCH TO RAM BANK ; HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK ; ; WE RESET THE STACK HERE BECAUSE WE ARE NOT GOING TO RETURN ; FROM THE BNKCALL. REMEMBER THAT WE STORED A COUPLE BYTES ; RIGHT BELOW HBX_LOC, SO THE STACK IS SET TO START JUST BELOW ; THAT. LD SP,HBX_LOC - 2 ; RESET STACK ; ; NOTIFY THAT WE MADE THE TRANSITION! FPLEDS(DIAG_03) DIAG(2) ; ; RECOVER DATA PASSED PRIOR TO RAM TRANSITION ; (HBX_LOC - 1) = BATCOND POP HL ; POP 2 BYTES LD A,H ; GET FIRST BYTE PUSHED LD (HB_BATCOND),A ; ... AND SAVE AS BAT COND ; #IF FALSE ; ; POPULATE THE CRITICAL RAM BANK NUMBERS. ; ; ASSUME THAT CB_RAMBANKS IS THE NUMBER OF 32K RAM BANKS THAT HAS BEEN SET EITHER ; AT ASSEMBLY TIME OR BY PROBING THE ACTUAL AVAILABLE MEMORY (NOT IMPLEMENTED YET). ; LD A,(CB_RAMBANKS) ; CALCULATE TOP RAMBANK ADD A,BID_RAM0 ; AS FIRST RAMBANK + DEC A ; #RAMBANKS - 1 ; LD HL,CB_BIDCOM LD B,4 CB_IDS: LD (HL),A ; POPULATE CB_BIDCOM INC HL ; POPULATE CB_BIDUSR DEC A ; POPULATE CB_BIDBIOS DJNZ CB_IDS ; POPULATE CB_BIDAUX ; LD A,(CB_BIDUSR) LD (HB_SRCBNK),A ; POPULATE HB_SRCBNK LD (HB_DSTBNK),A ; POPULATE HB_DSTBNK ; LD A,BID_RAM0 ; POPULATE CB_BIDRAMD0 ; START RAMBANK LD (HL),A INC HL ; LD A,(CB_RAMBANKS) ; POPULATE CB_BIDRAMDN ; END RAMBANK DEC A SUB TOT_RAM_RB LD (HL),A ; #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; INTERRUPT MANAGEMENT SETUP ;-------------------------------------------------------------------------------------------------- ; ; SETUP INTERRUPT VECTOR TABLE ADDRESS(ES) AND TRANSITION TO ; OPERATING INTERRUPT MODE. NOTE THAT INTERRUPTS REMAIN ; DISABLED AT THIS POINT. ; #IF (CPUFAM != CPU_EZ80) #IF ((INTMODE == 2) | ((INTMODE == 1) & (CPUFAM == CPU_Z180))) ; 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 #IF (INTMODE == 2) IM 2 ; SWITCH TO INT MODE 2 #ENDIF #ENDIF ; #IF (MEMMGR == MM_Z280) ; NOW POINT TO RAM COPY OF Z280 INT/TRAP TABLE ; HL IS TOP 16 BITS OF PHYSICAL ADDRESS OF IVT ; IVT *MUST* BE ON A 4K BOUNDARY LD C,Z280_VPR LD HL,0 + (((PBANK(BID_BIOS) << 15) + Z280_IVT) >> 8) LDCTL (C),HL #ENDIF ; #IF (INTMODE == 3) ; ; SETUP Z280 INT A FOR VECTORED INTERRUPTS LD HL,%0010000000000000 LD C,Z280_ISR LDCTL (C),HL ; ; TRANSITION TO INTERRUPT MODE 3 IM 3 ; #ENDIF #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; APPLICATION BOOT INITIALIZATION ;-------------------------------------------------------------------------------------------------- ; ; IF APPBOOT, WE NEED TO FIX UP A FEW THINGS IN PAGE ZERO AND ; COPY THE PAYLOAD CONTAINING ROMLDR, MONITOR, AND ZSDOS TO AUX BANK. ; #IFDEF APPBOOT ; ;;; SHOULD THIS BE DONE FOR AN HBIOS RESTART IN PLACE??? ; 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) ; CALL HBX_INT ; HANDLE IM1 INTERRUPTS ; .DB $10 << 2 ; USE SPECIAL VECTOR #16 LD A,$CD ; CALL OPCODE LD ($0038),A LD HL,HBX_INT ; ADDRESS LD ($0039),HL LD A,$10 << 2 ; IM1 VECTOR LD ($003B),A #ELSE ; RETI ($ED, $4D) IF NON-INTERRUPT MODE LD HL,$0038 LD (HL),$ED INC HL LD (HL),$4D #ENDIF ; ; CHECK TO SEE IF THIS IS AN IN-PLACE RESTART. IF SO, ; WE NEED TO SKIP THE COPY OF THE CONCATENATED OS IMAGES BELOW. LD A,(HB_RAMFLAG) ; GET THE FLAG OR A ; TEST IT JR NZ,HB_START2 ; IF SET, SKIP DEC A ; SET FLAG LD (HB_RAMFLAG),A ; SAVE IT ; ; FOR AN APPLICATION BOOT, WE ALSO COPY THE CONCATENATED OS ; IMAGES TO THE AUX BANK WHERE WE WILL JUMP TO ROMLDR LATER. LD A,(HB_CURBNK) ; GET CURRENT BANK ID LD (HB_SRCBNK),A ; SETUP SOURCE BANK LD A,BID_AUX ; DEST BANK IS AUX BANK LD (HB_DSTBNK),A ; SETUP DESTINATION BANK LD HL,HB_END ; COPY FROM END OF HBIOS LD DE,0 ; TO START OF TARGET BANK LD BC,$8000 ; COPY ENTIRE 32KB BANK CALL HBX_BNKCPY ; ELSE NORMAL BANK COPY JR HB_START2 ; CONTINUE ; ;;; RELOCATE THIS DATA FIELD HB_RAMFLAG .DB $00 ; #ENDIF ; HB_START2: ; ;-------------------------------------------------------------------------------------------------- ; GENERAL HBIOS INITIALIZATION ;-------------------------------------------------------------------------------------------------- ; ; CLEAR DISPATCH TABLE ENTRIES ; XOR A ; ZERO LD (CIO_CNT),A ; CIO DEVICES LD (DIO_CNT),A ; DIO DEVICES LD (VDA_CNT),A ; VDA DEVICES LD (SND_CNT),A ; SND DEVICES LD (RTC_DISPACT),A ; RTC DEVICE LD (DSKY_DISPACT),A ; DSKY DEVICE LD HL,RTC_DISPERR ; DEFAULT RTC DISPADR LD (RTC_DISPADR),HL ; SET IT LD HL,DSKY_DISPERR ; DEFAULT DSKY DISPADR LD (DSKY_DISPADR),HL ; SET IT ; ; INITIALIZE SOME HCB ENTRIES ; OR $FF ; $FF TO ACCUM LD (CB_CRTDEV),A ; RESET CRT DEVICE ; ; CLEAR INTERRUPT VECTOR TABLES ; ; THIS IS REALLY ONLY REQUIRED ON A RESTART, BUT IT DOESN'T HURT TO ; DO IT ALL THE TIME. ; LD HL,HB_IVT + 1 ; FIRST VECTOR (IM2) LD B,16 ; CLEAR 16 VECTORS CALL HB_CLRIVT ; DO IT LD HL,HB_IM1INT + 1 ; FIRST VECTOR (IM1) LD B,8 ; CLEAR 8 VECTORS CALL HB_CLRIVT ; DO IT XOR A ; ZERO ACCUM LD (HB_IM1CNT),A ; ... TO CLEAR IM1 VECTOR CNT LD HL,HB_IM1INT ; POINTER TO START OF IM1 IVT LD (HB_IM1PTR),HL ; ... TO CLEAR IM1 PTR LD HL,HB_TICK LD (VEC_TICK + 1),HL LD HL,HB_SECOND LD (VEC_SECOND + 1),HL JR HB_CLRIVT_Z ; DONE, JUMP OVER SUBROUTINE ; HB_CLRIVT: LD (HL),HB_BADINT & $FF INC HL LD (HL),HB_BADINT >> 8 INC HL INC HL INC HL DJNZ HB_CLRIVT RET ; HB_CLRIVT_Z: ; ; 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 ; FPLEDS(DIAG_04) ; ;-------------------------------------------------------------------------------------------------- ; CPU TYPE DISCOVERY ;-------------------------------------------------------------------------------------------------- ; ; SOME OF 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 ; 4: Z8280 ; 5: eZ80 ; 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 ; #IF (CPUFAM == CPU_Z280) ; ; TEST FOR Z280 PER ZILOG DOC LD A,$40 ; INITIALIZE THE OPERAND .DB $CB,$37 ; THIS INSTRUCTION WILL SET THE S FLAG ; ON THE Z80 CPU AND CLEAR THE S FLAG ; ON THE Z280 MPU. JP M,HB_CPU1 ; IF Z80, SKIP AHEAD LD L,4 ; WE ARE Z280 ; #ENDIF ; HB_CPU1: LD A,L LD (HB_CPUTYPE),A ; ;-------------------------------------------------------------------------------------------------- ; EARLY DRIVER INITIALIZATION ;-------------------------------------------------------------------------------------------------- ; ; SOME DRIVERS NEED TO BE CALLED AS EARLY AS WE CAN ONE AN OPERATING ; ENVIRONMENT IS ESTABLISHED. ; #IF (CPUFAM == CPU_EZ80) ; THIS WILL RE-ASSIGN HB_CPUTYPE CALL EZ80_PREINIT #ENDIF #IF (SN76489ENABLE) ; SN76489 CHIP GENERATES UGLY NOISE AFTER HARDWARE RESET. ; WE CALL THIS DRIVER'S PREINIT ASAP TO SHUT OFF THE NOISE. CALL SN76489_PREINIT #ENDIF #IF (DSRTCENABLE) ; THE DSRTC NEEDS TO BE INITIALIZED IN ORDER TO PERFROM THE ; CPU SPEED DETECTION BELOW. CALL DSRTC_PREINIT #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; DSKY INITIALIZATION AND ANNOUNCEMENT ;-------------------------------------------------------------------------------------------------- ; ;;;#IF (DSKYENABLE) #IF (ICMENABLE) CALL ICM_PREINIT #ENDIF #IF (PKDENABLE) CALL PKD_PREINIT #ENDIF ; ;;;; ANNOUNCE OURSELVES ON DSKY ;;;LD HL,MSG_HBVER + 5 ;;;LD A,(DSKY_HEXMAP + RMJ) ;;;OR $80 ;;;LD (HL),A ;;;INC HL ;;;LD A,(DSKY_HEXMAP + RMN) ;;;OR $80 ;;;LD (HL),A ;;;INC HL ;;;LD A,(DSKY_HEXMAP + RUP) ;;;LD (HL),A ;;;LD HL,MSG_HBVER ;;;LD B,BF_DSKYSHOWSEG ;;;CALL DSKY_DISPATCH ;;;#ENDIF #IF (LCDENABLE) CALL LCD_PREINIT #ENDIF #IF (H8PENABLE) CALL H8P_PREINIT #ENDIF #IF (GM7303ENABLE) CALL GM7303_PREINIT #ENDIF ; FPLEDS(DIAG_05) ; ; INIT OSCILLATOR SPEED FROM CONFIG ; #IF (CPUFAM != CPU_EZ80) LD HL,CPUOSC / 1000 ; OSC SPD IN KHZ LD (HB_CPUOSC),HL ; INIT HB_CPUOSC DEFAULT ; ; ATTEMPT DYNAMIC CPU SPEED DERIVATION ; NOTE THAT FOR PLATFORMS WITH SOFTWARE SELECTABLE CPU SPEED, ; THIS IS BEING DONE WITH THE CPU SPEED SET TO THE LOWEST ; POSSIBLE SETTING. THE FINAL CPU SPEED WILL BE ADJUSTED ; LATER. ; CALL HB_CPUSPD ; DYNAMIC CPU SPEED DETECTION JR NZ,HB_CPU2 ; SKIP AHEAD IF FAILED ; ; RECORD THE UPDATED CPU OSCILLATOR SPEED ; #IF ((CPUFAM == CPU_Z180) | (CPUSPDCAP == SPD_HILO) | (PLATFORM=PLT_HEATH)) ; SPEED MEASURED WILL BE HALF OSCILLATOR SPEED ; SO RECORD DOUBLE THE MEASURED VALUE ; FOR HEATH, WE ARE ASSUMING THAT THE CPU SPEED DIVISOR WAS ; PREVIOUSLY SET TO $01 MEANING HALF OF OSCILLATOR SPEED. SLA L RL H #ENDIF ; LD (HB_CPUOSC),HL ; RECORD MEASURED SPEED ; HB_CPU2: #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; FINALIZE OPERATING CPU SPEED ;-------------------------------------------------------------------------------------------------- ; ; TRANSITION TO FINAL DESIRED CPU SPEED FOR THOSE PLATFORMS ; THAT SUPPORT SOFTWARE SELECTABLE CPU SPEED. UPDATE CB_CPUKHZ ; IN HCB AS WE DO THIS. ; LD HL,(HB_CPUOSC) #IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_MBC)) #IF (CPUSPDDEF==SPD_HIGH) ; SET HIGH SPEED VIA RTC LATCH LD A,(HB_RTCVAL) OR %00001000 ; SET HI SPEED BIT LD (HB_RTCVAL),A ; SAVE SHADOW OUT (RTCIO),A ; IMPLEMENT ; HL IS ALREADY CORRECT FOR FULL SPEED OPERATION #ELSE ; ADJUST HL TO REFLECT HALF SPEED OPERATION SRL H ; ADJUST HL ASSUMING RR L ; HALF SPEED OPERATION #ENDIF #ENDIF ; #IF (PLATFORM == PLT_HEATH) ; ADJUST HL TO REFLECT HALF SPEED OPERATION SRL H ; ADJUST HL ASSUMING RR L ; HALF SPEED OPERATION #ENDIF ; #IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_SBC)) #IF (CPUSPDDEF==SPD_HIGH) ; SET HIGH SPEED VIA RTC LATCH LD A,(HB_RTCVAL) AND ~%00001000 ; CLEAR HI SPEED BIT LD (HB_RTCVAL),A ; SAVE SHADOW OUT (RTCIO),A ; IMPLEMENT ; HL IS ALREADY CORRECT FOR FULL SPEED OPERATION #ELSE ; ADJUST HL TO REFLECT HALF SPEED OPERATION SRL H ; ADJUST HL ASSUMING RR L ; HALF SPEED OPERATION #ENDIF #ENDIF ; #IF (CPUFAM == CPU_Z180) ; LD HL,(HB_CPUOSC) ; INIT HL TO CPU OSC FREQ (KHZ) ; ; ADJUST HL TO REFLECT HALF SPEED OPERATION SRL H ; ADJUST HL ASSUMING RR L ; HALF SPEED OPERATION ; #IF (Z180_CLKDIV >= 1) LD A,(HB_CPUTYPE) ; GET CPU TYPE CP 2 ; Z8S180 REV K OR BETTER? JR C,HB_CPU3 ; IF NOT, NOT POSSIBLE! ; SET CLOCK DIVIDE TO 1 RESULTING IN FULL XTAL SPEED LD A,$80 OUT0 (Z180_CCR),A ; ADJUST HL TO REFLECT FULL SPEED OPERATION SLA L RL H #ENDIF ; #IF (Z180_CLKDIV >= 2) LD A,(HB_CPUTYPE) ; GET CPU TYPE CP 3 ; Z8S180 REV N OR BETTER? JR C,HB_CPU3 ; 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 ; ADJUST HL TO REFLECT DOUBLE SPEED OPERATION SLA L RL H #ENDIF ; HB_CPU3: #ENDIF ; #IF (CPUFAM == CPU_Z280) ; ; Z280 ALWAYS HALVES THE INPUT OSCILLATOR TO DERIVE ; ACTUAL CPU SPEED. ; ADJUST HL TO REFLECT HALF SPEED OPERATION SRL H ; ADJUST HL ASSUMING RR L ; HALF SPEED OPERATION #ENDIF ; ; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ. ; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE. ; LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER LD DE,500 ; SET UP TO ROUND UP XOR A ; IF WITHIN 500 KHZ SBC HL,DE ; REMAINDER - 500 CCF ; COMPLEMENT CF ADC A,C ; C -> A; ADD CF FOR ROUNDING LD (CB_CPUMHZ),A ; SAVE IT ; ;-------------------------------------------------------------------------------------------------- ; FINALIZE OPERATING WAIT STATES ;-------------------------------------------------------------------------------------------------- ; ; SET OPERATING WAIT STATE CONFIGURATION ON SYSTEMS THAT SUPPORT IT ; #IF (CPUFAM == CPU_Z180) ; ; SET FINAL DESIRED WAIT STATES PER CONFIG LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4) OUT0 (Z180_DCNTL),A ; #ENDIF ; #IF (CPUFAM == CPU_Z280) ; ; SET FINAL DESIRED WAIT STATES PER CONFIG ; BUS TIMING AND CONFIGURATION REGISTER LD C,Z280_BTCR ; BUS TIMING AND CONTROL REG LDCTL HL,(C) LD A,L ; PUT IN A AND %00111100 ; CLEAR DC,HM, AND IO FIELDS OR Z280_INTWAIT << 6 ; SET INT ACK WAIT STATE BITS (DC) OR Z280_MEMHIWAIT << 2 ; SET HIGH 8MB WAIT STATE BITS (HM) OR Z280_IOWAIT ; SET I/O WAIT STATE BITS LD L,A ; BACK TO L LDCTL (C),HL ; DO IT ; ; BUS TIMING AND INITIALIZATION REGISTER LD C,Z280_BTIR ; BUS TIMING AND INIT REG LDCTL HL,(C) LD A,L ; PUT IN A AND %11110011 ; CLEAR LM FIELD OR Z280_MEMLOWAIT << 2 ; SET LOW 8MB WAIT STATE BITS LD L,A ; BACK TO L LDCTL (C),HL ; DO IT ; #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; SK Z80-512K CLOCK INITIALIZATION ;-------------------------------------------------------------------------------------------------- ; #IF (SKZENABLE) ; ;;; LOCATION OF THIS CODE??? ; ; SET THE SK Z80-512K UART CLK2 DIVIDER AS ; CONFIGURED. NOTE THAT THIS IMPLICITLY ; CLEARS THE WATCHDOG BIT. THE WATCHDOG ; WILL BE ENABLED LATER IF CONFIGURED. LD A,SKZDIV ; GET DIVIDER CODE OUT ($6D),A ; IMPLEMENT IT ; #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; INITIALIZE SPEED-COMPENSATED DELAY FUNCTIONS ;-------------------------------------------------------------------------------------------------- ; ;;; LOCATION OF THIS CODE??? ; #IF (CPUFAM != CPU_EZ80) LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; SYSTEM TIMER INITIALIZATION ;-------------------------------------------------------------------------------------------------- ; #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) CALL KIO_PREINIT #ENDIF ; #IF (CTCENABLE) CALL CTC_PREINIT #ENDIF ; #IF (PLATFORM == PLT_NABU) CALL NABU_PREINIT #ENDIF ; #IF (CPUFAM == CPU_Z180) ; #IF (INTMODE > 0) ; ; FOR NOW, JUST ENABLE THE INT0 PIN WHICH IS GENERALLY ; EQUIVALENT TO Z80 INTERRUPTS. LD A,$01 ; INT0 ENABLED, INT1-2 DISABLED OUT0 (Z180_ITC),A ; WRITE TO INT/TRAP CONTROL REGISTER ; #IF (Z180_TIMER) ; ; 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 ; *** THIS ASSUMES A TICKFREQ OF 50HZ!!! *** ; #IF (TICKFREQ != 50) .ECHO "TICKFREQ *MUST* BE 50 FOR Z180 TIMER\n" !!! #ENDIF ; ; Z180 PRESCALES THE COUNTER BY 20 SO, ; RLDR = CPU CLK / 20 / TICKFREQ ; IF WE ASSUME TICKFREQ = 50, WE CAN SIMPLIFY TO ; RLDR = CPU CLK / 1000 ; IF WE DIVIDE BOTH SIDES BY 1000, WE CAN USE ; CPUKHZ VALUE AND SIMPLIFY TO ; RLDR = CPUKHZ XOR A ; ALL BITS ZERO OUT0 (Z180_TCR),A ; ... INHIBITS TIMER OPERATION 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 ; #ENDIF ; #IF (CPUFAM == CPU_Z280) ; #IF (MEMMGR == MM_Z280) ; #IF (Z280_TIMER) ; Z280_TC .EQU CPUOSC / 4 / 50 / 2 ; TIME CONSTANT ; LD HL,Z280_TIMINT LD (Z280_IVT+$16),HL ; Z280 T/C VECTOR ; ; SELECT I/O PAGE $FE LD C,Z280_IOPR ; I/O PAGE REGISTER LDCTL HL,(C) ; GET CURRENT I/O PAGE PUSH HL ; SAVE IT LD L,$FE ; I/O PAGE $FE LDCTL (C),HL ; LD A,%10100000 ; CONFIG: C, RE, IE OUT (Z280_CT0_CFG),A ; SET C/T 0 LD HL,CPUOSC / 50 / 16 ; TIME CONSTANT & COUNTER LD C,Z280_CT0_TC ; SET C/T 0 OUTW (C),HL LD C,Z280_CT0_CT ; SET C/T 0 OUTW (C),HL LD A,%11100000 ; CMD: EN, GT OUT (Z280_CT0_CMDST),A ; SET C/T 0 ; ; RESTORE I/O PAGE LD C,Z280_IOPR ; I/O PAGE REGISTER POP HL ; RESTORE I/O PAGE LDCTL (C),HL ; #ENDIF ; #ENDIF ; #ENDIF ; FPLEDS(DIAG_06) ; ;-------------------------------------------------------------------------------------------------- ; PRE-CONSOLE INITIALIZATION ;-------------------------------------------------------------------------------------------------- ; #IF (WBWDEBUG == USEMIO) ; BUFFER OUTPUT UNTIL CALL MIO_INIT ; WE GET TO BOOT MESSAGE #ENDIF ; #IF FALSE ; ; TEST DEBUG *************************************************************************************** ; CALL NEWLINE CALL REGDMP ; ; TEST DEBUG *************************************************************************************** ; #ENDIF ; ; PLATFORM SPECIFIC CODE FOR DETECTING RECOVERY MODE SWITCH ; #IF (BT_REC_TYPE != BT_REC_NONE) #IF (BT_REC_TYPE == BT_REC_FORCE) LD A,1 ; SET FOR RECOVERY MODE LD (HB_BOOT_REC),A ; SAVE FOR LATER #ENDIF #IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) #IF (BT_REC_TYPE == BT_REC_SBC01) LD A,%00100000 ; DISABLE RTC AND OUT (RTCIO),A ; DRQ DRIVER READ IN A,(RTCIO) ; BIT 0 (DRQ). CPL ; PULLED HIGH AND 1 ; IS RECOVERY MODE LD (HB_BOOT_REC),A ; SAVE FOR LATER #ENDIF #IF (BT_REC_TYPE == BT_REC_SBC1B) IN A,(RTCIO) ; RTC PORT, BIT 6 HAS THE BIT 6,A ; STATE OF CONFIG JUMPER LD A,1 ; JUMPER INSTALLED JR Z,SAVE_REC_M ; IS RECOVERY MODE LD A,0 SAVE_REC_M: LD (HB_BOOT_REC),A ; SAVE FOR LATER #ENDIF #IF (BT_REC_TYPE == BT_REC_SBCRI) IN A,($68 + 6) ; UART_MSR MODEM BIT 6,A ; STATUS REGISTER LD A,0 ; BIT 6 JR Z,SAVE_REC_M ; IS RECOVERY MODE LD A,1 SAVE_REC_M: LD (HB_BOOT_REC),A ; SAVE FOR LATER #ENDIF #ENDIF #ENDIF ; LD DE,HB_PCINITTBL ; POINT TO PRECONSOLE INIT TABLE LD B,HB_PCINITTBLLEN ; NUMBER OF ENTRIES ; #IF (BT_REC_TYPE != BT_REC_NONE) LD A,(HB_BOOT_REC) ; IF WE ARE IN RECOVERY MODE OR A ; POINT TO THE RECOVER MODE JR Z,NOT_REC_M0 ; INITIALIZATION TABLE LD B,HB_PCINITRLEN LD DE,HB_PCINIT_REC NOT_REC_M0: ; #ENDIF ; ; CYCLE THROUGH THE INITIALIZATION TABLE CALLING THE PRE-INIT ; ENTRY POINT OF ALL DRIVERS. CALL CALLLIST ; PROCESS THE PRE-INIT CALL TABLE ; #IF FALSE ; ; TEST DEBUG *************************************************************************************** ; CALL NEWLINE CALL REGDMP ; ; TEST DEBUG *************************************************************************************** ; #ENDIF ; FPLEDS(DIAG_07) DIAG(3) ; ;-------------------------------------------------------------------------------------------------- ; BOOT DELAY ;-------------------------------------------------------------------------------------------------- ; ; IF CONFIGURED, AN ARBITRARY BOOT DELAY IS IMPLEMENTED HERE. THIS IS ; TYPICALLY USED TO DELAY ACCESSING DEVICES THAT WILL NOT BE READY. ; #IF (BOOT_DELAY > 100) .ECHO "*** ERROR: INVALID BOOT_DELAY (BOOT_DELAY > 100)!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF ; #IF (BOOT_DELAY > 0) LD B,BOOT_DELAY * 2 ; SCALE TO 1/2 SEC HB_BOOTDLY: CALL LDELAY ; 1/2 SECOND DELAY DJNZ HB_BOOTDLY ; LOOP TILL DONE #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; ACTIVATE BOOT CONSOLE ;-------------------------------------------------------------------------------------------------- ; ; 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 ; FAILSAFE VALUE FOR BOOT CONSOLE DEVICE LD (CB_CONDEV),A ; SAVE IT ; LD A,(CIO_CNT) ; GET COUNT OF CHAR DEVICES CP BOOTCON + 1 ; COUNT - (DEVICE + 1) JR C,HB_CONRDY ; IF TOO HIGH, JUST USE FAILSAFE LD A,BOOTCON ; GET REQUESTED CONSOLE DEV LD (CB_CONDEV),A ; SAVE IT ; HB_CONRDY: ; ; SUPPRESS HARDWARE FLOW CONTROL TEMPORARILY, IF NEEDED. THIS IS ; GENERALLY NOT USED ANYMORE BECAUSE THE UART DRIVER NOW CHECKS FOR ; A VALID CTS SIGNAL AND ADJUSTS AS NEEDED. ; #IF (SUPCTS) ; ; MOST SERIAL PORTS ARE CONFIGURED WITH HARDWARE FLOW CONTROL ENABLED. ; IF THERE IS A PROBLEM WITH THE CTS SIGNAL, THEN OUTPUT TO THE CONSOLE ; WILL BE STALLED WHICH CAN LEAD A USER TO THINK THE SYSTEM IS TOTALLY ; DEAD WHEN, IN FACT, IT IS JUST WAITING FOR CTS TO BE ASSERTED. ALSO, ; IF THE USER IS BOOTING TO A CRT DEVICE AND DISCONNECTS THE CONSOLE ; SERIAL PORT, THE SYSTEM WILL WAIT FOR RTS AND NEVER BOOT. SO, HERE ; WE SAVE THE ACTIVE CONSOLE CONFIGURATION, THEN TURN OFF HARDWARE ; FLOW CONTROL. THE ORIGINAL CONFIGURATION WILL BE RESTORED BELOW ; PRIOR TO LAUNCING THE ROM LOADER. ; ; RETRIEVE THE CONFIG FROM THE CONSOLE PORT LD B,BF_CIOQUERY ; HBIOS QUERY CIO CONFIG LD A,(CB_CONDEV) ; GET CONSOLE DEVICE LD (HB_BOOTCONSAV),A ; SAVE IT FOR LATER LD C,A ; BOOT CONSOLE TO C CALL HB_DISPATCH ; INTERNAL HBIOS CALL LD (HB_CONCFGSAV),DE ; SAVE CONFIG RES 5,D ; CLEAR RTS BIT LD B,BF_CIOINIT ; HBIOS CIO INIT LD A,(CB_CONDEV) ; GET CONSOLE DEVICE LD C,A ; BOOT CONSOLE TO C CALL HB_DISPATCH ; INTERNAL HBIOS CALL ; #ENDIF ; #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 FALSE ; ; TEST DEBUG *************************************************************************************** ; CALL NEWLINE2 PRTS("DEBUG+IM1INT$") LD DE,HB_IM1INT CALL DUMP_BUFFER ; ; TEST DEBUG *************************************************************************************** ; #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; ANNOUNCE HBIOS ;-------------------------------------------------------------------------------------------------- ; ; DISPLAY A BANNER ON THE BOOT CONSOLE NOW. NOTE THAT WE INTENTIONALLY ; LEAVE INTERRUPTS DISABLED UNTIL A BIT LATER. SINCE INTERRUPTS CAN ; DESTABILIZE A SYSTEM, IT IS DIAGNOSTICALLY USEFUL TO GET SOMETHING ; DISPLAYED BEFORE INTRODUCING INTERRUPTS. IF THE SYSTEM CRASHES ; AFTER DISPLAYING THE BANNER, INTERRUPT INTEGRITY SHOULD BE SUSPECTED. ; PRTX(STR_BANNER) ; ; DISPLAY HBIOS MUTEX ENABLED MESSAGE ; #IF (HBIOS_MUTEX == TRUE) CALL NEWLINE CALL PRTSTRD .TEXT "HBIOS MUTEX ENABLED$" #ENDIF ; ; DISPLAY RECOVERY MODE MESSAGE ; #IF (BT_REC_TYPE != BT_REC_NONE) LD A,(HB_BOOT_REC) ; IF WE ARE IN RECOVERY MODE OR A ; DISPLAY RECOVERY MODE MESSAGE JR Z,NOT_REC_M2 CALL NEWLINE CALL PRTSTRD .TEXT "RECOVERY MODE$" #ENDIF NOT_REC_M2: ; FPLEDS(DIAG_08) ; #IF FALSE LD DE,$0123 LD HL,$4567 LD B,BF_DSKYSHOWHEX CALL DSKY_DISPATCH CALL LDELAY CALL LDELAY LD DE,$89AB LD HL,$CDEF LD B,BF_DSKYSHOWHEX CALL DSKY_DISPATCH CALL LDELAY CALL LDELAY #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; IO PORT SCAN ;-------------------------------------------------------------------------------------------------- ; #IF FALSE ; 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 ; ;-------------------------------------------------------------------------------------------------- ; CPU SPEED DETECTION ALIGNMENT TEST ;-------------------------------------------------------------------------------------------------- ; #IF FALSE ; ; IF ENABLED, THE CPU SPEED TEST WILL BE REPEATED INDEFINITELY. THIS ; IS USED TO ADJUST THE SPEED DETECTION LOOP. ; 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 ; ;-------------------------------------------------------------------------------------------------- ; ENABLE INTERRUPTS ;-------------------------------------------------------------------------------------------------- ; 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 ; #IF (CPUFAM == CPU_Z280) CALL PRTSTRD .TEXT ", BUS @ $" LD C,Z280_BTIR ; BUS TIMING AND CTL REG LDCTL HL,(C) LD A,L ; MOVE TO A AND %00000011 ; ISOLATE CS FIELD LD HL,(CB_CPUKHZ) ; GET CPU SPEED CP %00000001 ; BUS @ 1/1 JR Z,HB_Z280BUS ; GOT IT, SHOW IT SRL H ; DIVIDE RR L ; ... BY 2 CP %00000000 ; BUS @ 1/2 JR Z,HB_Z280BUS ; GOT IT, SHOW IT SRL H ; DIVIDE RR L ; ... BY 2 CP %00000010 ; BUS @ 1/4 JR Z,HB_Z280BUS ; GOT IT, SHOW IT PRTS("???$") ; INVALID VALUE JR HB_Z280BUS1 ; CONTINUE HB_Z280BUS: CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA HB_Z280BUS1: PRTS("MHz$") ; SUFFIX #ENDIF #IF (CPUFAM == CPU_EZ80) CALL EZ80_RPT_FIRMWARE #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; DISPLAY CPU CONFIGURATION ;-------------------------------------------------------------------------------------------------- ; CALL NEWLINE ; ; DISPLAY MEMORY TIMINGS ; #IF (CPUFAM == CPU_EZ80) CALL EZ80_RPT_TIMINGS #ELSE #IF (CPUFAM == CPU_Z280) LD A,Z280_MEMLOWAIT CALL PRTDECB LD A,'/' CALL COUT LD A,Z280_MEMHIWAIT CALL PRTDECB CALL PRTSTRD .TEXT " MEM W/S, $" #ELSE XOR A #IF (CPUFAM == CPU_Z180) LD A,Z180_MEMWAIT #ENDIF CALL PRTDECB CALL PRTSTRD .TEXT " MEM W/S, $" #ENDIF #ENDIF ; CPUFAM = CPU_EZ80 ; ; DISPLAY I/O TIMINGS ; #IF (CPUFAM == CPU_EZ80) ; ALREADY REPORTED BY DRIVER #ELSE LD A,1 #IF (CPUFAM == CPU_Z180) LD A,Z180_IOWAIT + 1 #ENDIF #IF (CPUFAM == CPU_Z280) LD A,Z280_IOWAIT + 1 #ENDIF CALL PRTDECB CALL PRTSTRD .TEXT " I/O W/S$" #IF (CPUFAM == CPU_Z280) CALL PRTSTRD .TEXT ", $" LD A,Z280_INTWAIT CALL PRTDECB CALL PRTSTRD .TEXT " INT W/S$" #ENDIF #ENDIF //CPUFAM = CPU_EZ80 ; ; DISPLAY INTERRUPT MODE ; #IF (INTMODE > 0) CALL PRTSTRD .TEXT ", INT MODE $" LD A,INTMODE CALL PRTDECB #ENDIF ; CALL PRTSTRD .TEXT ", $" CALL PRTSTRD #IF (MEMMGR == MM_NONE) .TEXT "NONE$" #ENDIF #IF (MEMMGR == MM_SBC) .TEXT "SBC$" #ENDIF #IF (MEMMGR == MM_Z2) .TEXT "Z2$" #ENDIF #IF (MEMMGR == MM_N8) .TEXT "N8$" #ENDIF #IF (MEMMGR == MM_Z180) .TEXT "Z180$" #ENDIF #IF (MEMMGR == MM_Z280) .TEXT "Z280$" #ENDIF #IF (MEMMGR == MM_ZRC) .TEXT "ZRC$" #ENDIF #IF (MEMMGR == MM_MBC) .TEXT "MBC$" #ENDIF #IF (MEMMGR == MM_RPH) .TEXT "RPH$" #ENDIF CALL PRTSTRD .TEXT " MMU$" ; ;-------------------------------------------------------------------------------------------------- ; DISPLAY MEMORY CONFIGURATION ;-------------------------------------------------------------------------------------------------- ; CALL NEWLINE LD HL,ROMSIZE CALL PRTDEC CALL PRTSTRD .TEXT "KB ROM, $" ; LD HL,(CB_RAMBANKS) ; GET NUMBER OF BANKS IN L LD H,0 ; CALCULATE RAM SIZE ADD HL,HL ADD HL,HL ; X4 ADD HL,HL ; X8 ADD HL,HL ; X16 ADD HL,HL ; X32 ; CALL PRTDEC CALL PRTSTRD .TEXT "KB RAM$" ; CALL PRTSTRD .TEXT ", HEAP=0x$" LD HL,BNKTOP - HB_END CALL PRTHEXWORDHL ; #IFDEF SIZERAM ; CALL PRTSTRD .TEXT ", RAMBANKS=0x$" LD A,($FFEA) CALL PRTHEXBYTE #ENDIF ; #IFDEF TESTING ; CALL PRTSTRD .TEXT ", RTCDEF=0x$" LD A,(RTCDEFVAL) CALL PRTHEXBYTE ; #ENDIF ; #IF 0 ; ; DIAGNOSTIC DISPLAY OF BANK IDS IN HCB ; CALL PRTSTRD .TEXT ", BANK IDS:$" LD DE,CB_BIDCOM LD A,8 CALL PRTHEXBUF ; #ENDIF ; #IF (CPUFAM == CPU_Z280) CALL NEWLINE PRTS("Z280: $") PRTS("MSR=$") LD C,Z280_MSR ; MASTER STATUS REGISTER LDCTL HL,(C) CALL PRTHEXWORDHL CALL PC_SPACE PRTS("ISR=$") LD C,Z280_ISR ; INTERRUPT STATUS REGISTER LDCTL HL,(C) CALL PRTHEXWORDHL CALL PC_SPACE PRTS("BTCR=$") LD C,Z280_BTCR ; BUS TIMING AND CONTROL REGISTER LDCTL HL,(C) LD A,L CALL PRTHEXBYTE CALL PC_SPACE PRTS("BTIR=$") LD C,Z280_BTIR ; BUS TIMING AND CONTROL REGISTER LDCTL HL,(C) LD A,L CALL PRTHEXBYTE CALL PC_SPACE PRTS("CCR=$") LD C,Z280_CCR ; CACHE CONTROL REGISTER LDCTL HL,(C) LD A,L CALL PRTHEXBYTE CALL PC_SPACE PRTS("TCR=$") LD C,Z280_TCR ; CACHE CONTROL REGISTER LDCTL HL,(C) LD A,L CALL PRTHEXBYTE #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; ROM CHECKSUM VERIFICATION ;-------------------------------------------------------------------------------------------------- ; #IFDEF ROMBOOT #IF (ROMSIZE > 0) ; ; ROM CHECKSUM VERIFICATION ; EACH OF THE FIRST 4 ROM BANKS HAS A CHECKSUM INJECTED SUCH THAT ; A COMPUTED CHECKSUM ACROSS THE ENTIRE BANK SHOULD ALWAYS BE ZERO ; HB_ROMCK: CALL NEWLINE PRTS("ROM VERIFY:$") ; ; COPY CHECKSUM ROUTINE TO UPPER RAM LD HL,HB_CKBNK LD DE,$F000 LD BC,HB_CKBNKSIZ LDIR ; ; TEST FIRST 4 BANKS OF ROM LD B,4 ; 4 BANKS LD C,0 ; STARTING AT BANK 0 HB_ROMCK1: PUSH BC ; SAVE LOOP CONTROL CALL $F000 ; TEST THE BANK CALL PC_SPACE ; FORMATTING CALL PRTHEXBYTE ; PRINT RESULT POP BC ; RESTORE LOOP CONTROL OR A ; SET FLAGS JR NZ,HB_ROMCK2 ; HANDLE FAILURE INC C ; NEXT BANK DJNZ HB_ROMCK1 ; LOOP FOR BANKS PRTS(" PASS$") ; DISPLAY SUCCESS JR HB_ROMCKZ ; CONTINUE BOOT HB_ROMCK2: PRTS(" FAIL$") ; DISPLAY ERROR JR HB_ROMCKZ ; CONTINUE BOOT ; ; VERIFY ROM CHECKSUM BANK SPECIFIED IN REG C ; THIS MUST BE COPIED TO UPPER RAM TO RUN ; INTERRUPTS ARE DISABLED SINCE PAGE ZERO VECTOR WILL BE ; SWAPPED OUT. ASSUMES THAT INTERRUPTS ARE ENABLED AT ENTRY. ; HB_CKBNK: HB_DI ; SUPPRESS INTERRUPTS LD A,(HB_CURBNK) ; GET CURRENT BANK LD E,A ; SAVE IN E LD A,C ; BANK TO TEST CALL HBX_BNKSEL ; SELECT BANK IT LD HL,$7FFF ; START AT BANK END LD BC,1 ; DECREMENT VALUE XOR A ; ZERO ACCUM HB_CKBNK1: #IF (MEMMGR == MM_Z280) LD D,A ; WORKING VALUE TO D LDUD A,(HL) ; GRAB NEXT BYTE FROM USER SPACE ADD A,D ; ADD NEXT BYTE #ELSE ADD A,(HL) ; ADD NEXT BYTE #ENDIF OR A ; CLEAR CARRY SBC HL,BC ; DECREMENT JR NC,HB_CKBNK1 ; LOOP TILL DONE PUSH AF ; SAVE RESULT LD A,E ; BANK TO RESTORE CALL HBX_BNKSEL ; RESTORE ORIG BANK POP AF ; RECOVER RESULT HB_EI ; ALLOW INTERRUPTS AGAIN RET ; AND DONE ; HB_CKBNKSIZ .EQU $-HB_CKBNK ; SIZE OF ROUTINE ; HB_ROMCKZ: ; #ENDIF ; #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; LOW RAM BATTERY MESSAGE ;-------------------------------------------------------------------------------------------------- ; #IF (BATCOND) LD A,(HB_BATCOND) OR A LD DE,STR_LOWBAT CALL Z,WRITESTR #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; FINAL DEVICE INITIALIZATION ;-------------------------------------------------------------------------------------------------- ; CALL NEWLINE #IF (BT_REC_TYPE != BT_REC_NONE) LD A,(HB_BOOT_REC) ; IF WE ARE IN RECOVERY MODE OR A ; POINT TO THE RECOVER MODE JR Z,NOT_REC_M1 ; INITIALIZATION TABLE LD B,HB_INITRLEN LD DE,HB_INIT_REC JR IS_REC_M1 #ENDIF NOT_REC_M1: LD B,HB_INITTBLLEN LD DE,HB_INITTBL IS_REC_M1: CALL CALLLIST ; ;-------------------------------------------------------------------------------------------------- ; WATCHDOG ACTIVATION ;-------------------------------------------------------------------------------------------------- ; ; IF WATCHDOG FUNCTIONALITY IS REQUESTED, CHECK TO MAKE SURE ; WE ARE GETTING INTERRUPTS. IF SO, ENABLE THE WATCHDOG. ; #IF (WDOGMODE != WDOG_NONE) CALL NEWLINE PRTS("WDOG: $") PRTS("MODE=$") #IF (WDOGMODE == WDOG_EZZ80) PRTS("EZZ80$") #ENDIF #IF (WDOGMODE == WDOG_SKZ) PRTS("SKZ$") #ENDIF ; PRTS(" IO=0x$") LD A,WDOGIO CALL PRTHEXBYTE ; #IF (WDOGMODE == WDOG_SKZ) ; SKZ WATCHDOG IS DISABLED EARLY IN BOOT PROCESS ; HERE, WE ONLY NEED TO ENABLE IT, IF APPROPRIATE LD HL,(HB_TICKS) ; GET LOW WORD LD A,H ; CHECK FOR OR L ; ... ZERO JR Z,HB_WDOFF ; SKIP IF NOT TICKING IN A,($6D) ; GET PORT VALUE SET 5,A ; SET THE WATCHDOG ENABLE BIT OUT ($6D),A ; ACTIVATE WATCHDOG #ENDIF ; PRTS(" ENABLED$") JR HB_WDZ ; HB_WDOFF: PRTS(" DISABLED$") ; HB_WDZ: ; #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; HEAP CURB INITIALIZATION ;-------------------------------------------------------------------------------------------------- ; ; 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 ; ;-------------------------------------------------------------------------------------------------- ; FINAL CONSOLE ACTIVATION ;-------------------------------------------------------------------------------------------------- ; ; ON SOME SYSTEMS, THE OPERATING CONSOLE IS DIFFERENT THAT THE BOOT ; CONSOLE. FOR EXAMPLE, IF A VIDEO CONSOLE IS DESIRED. A VIDEO ; CONSOLE CANNOT BE USED AS A BOOT CONSOLE BECAUSE IT WILL NOT BE ; INITIALIZED EARLY ENOUGH. SO, IF DESIRED, WE SWITCH TO THE FINAL ; RUNNING CONSOLE HERE. ; LD A,(CB_CONDEV) ; GET CURRENT CONSOLE LD (HB_NEWCON),A ; AND INIT NEW CONSOLE VAR ; #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) | (PLATFORM == PLT_MBC)) 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 ; #IF (PLATFORM == PLT_S100) IN A,($75) ; GET IO BYTE AND %00000001 ; ISOLATE CONSOLE BIT JR NZ,INITSYS3 ; NOT SET, BYPASS CONSOLE SWITCH #ENDIF ; #IF (PLATFORM == PLT_FZ80) ; IOBYTE: XXXXXVVC ; 00- FORCE ONBOARD VGA/PS2 KBD (FV) ; --1 FORCE PROPELLER CONSOLE (SCON) ; 110 NORMAL USB SERIAL BOOT ; ; WE ASSUME THAT THE ONBOARD VGA (FV) IS ALWAYS DETECTED AND ; WILL BE THE CURRENT CRTDEV. SCON IS ASSUMED TO BE THE ; DEVICE AT CRTDEV + 1. THESE ARE REASONABLE ASSUMPTIONS ; UNLESS THE DRIVER DETECTION OR DRIVER ORDER IS CHANGED. IN A,($36) ; GET IO BYTE AND %00000110 ; ISOLATE BITS JR Z,HB_CRTACT ; FORCE ONBOARD CRT IN A,($36) ; GET IO BYTE AND %00000001 ; ISOLATE BIT JR Z,INITSYS3 ; NORMAL USB SERIAL BOOT LD A,(CB_CRTDEV) ; GET CRT DEV INC A ; SWITCH FROM FV -> SCON LD (CB_CRTDEV),A ; SAVE IT AND DO CONSOLE SWITCH #ENDIF ; HB_CRTACT: LD A,(CB_CRTDEV) ; GET CRT DISPLAY DEVICE LD (HB_NEWCON),A ; AND QUEUE TO SWITCH ; #ENDIF ; #IF (FPSW_ENABLE) ; ; IF WE HAVE FRONT PANEL SWITCHES, THIS IS THE RIGHT PLACE TO HANDLE ; ANY CONSOLE CHANGE REQUESTS. THE FRONT PANEL HAS TWO SWITCHES ; RELATED TO THIS: 1) CRT/SER, AND 2) SEC/PRI. IF CRT/SER IS SET, ; THEN WE SWITCH TO THE CRT DEVICE (IF THERE IS ONE). IF THE SEC/PRI ; SWITCH IS SET, THEN WE ATTEMPT TO USE THE SECOND SERIAL OR CRT ; DEVICE. ; PRTS("\r\nFP: IO=0x$") LD A,FPSW_IO CALL PRTHEXBYTE ; CALL FP_DETECT ; ; IF FP DOESN'T EXIST, BAIL OUT. LD A,(FPSW_ACTIVE) ; GET FP EXISTENCE FLAG OR A ; SET FLAGS JR NZ,HB_FP1 ; IF WE HAVE ONE, CONTINUE ; ; HANDLE NO FP PRTS(" NOT PRESENT$") JR HB_FPZ ; HB_FP1: ; WE NOW BELIEVE WE HAVE A VALID SWITCH SETTINGS VALUE. ; CHECK FOR CRT SWITCH VALUE AND SWITCH TO CRT IF SET. ; NOTE THAT CB_CRTDEV WILL BE ZERO IF THERE IS NO CRT DEVICE ; IN THE SYSTEM, SO WE DON'T NEED TO CHECK FOR THE EXISTENCE ; OF A CRT DEVICE -- IT WILL JUST FAILBACK TO FIRST SERIAL ; PORT. PRTS(" SWITCHES=0x$") ; TAG CALL FP_GETSWITCHES ; GET SWITCH SETTINGS CALL PRTHEXBYTE ; DISPLAY VALUE LD B,A ; SAVE IN REG B AND SW_CRT ; TEST CRT BIT JR Z,HB_FP2 ; SKIP AHEAD IF NOT SET LD A,(CB_CRTDEV) ; GET CRT DISPLAY DEVICE CP $FF ; $FF MEANS NO CRT PRESENT JR Z,HB_FP2 ; BYPASS IF SO LD (HB_NEWCON),A ; QUEUE NEW CONSOLE UNIT ; HB_FP2: ; IF SEC SWITCH IS SET, WE WANT TO BUMP TO SECONDARY ; CRT OR SERIAL DEVICE. IF AN OVERRIDE IS SPECIFIED USING ; SECCON, USE THAT, OTHERWISE INCREMENT THE DEFAULT UNIT. ; THIS SHOULD WORK ASSUMING NORMAL ORDERING OF THE ; CHARACTER DEVICE UNITS. LD A,B ; RECOVER SWITCH SETTINGS AND SW_SEC ; TEST SEC BIT JR Z,HB_FPZ ; IF NOT SET, THEN ALL DONE ; LD A,(CIO_CNT) ; GET CHAR UNIT COUNT LD B,A ; MOVE TO B LD A,SECCON ; GET SEC CONSOLE SETTING CP $FF ; $FF MEANS USE INCREMENT JR NZ,HB_FP3 ; BYPASS IF NOT $FF ; ; INCREMENT CONSOLE UNIT LD A,(HB_NEWCON) ; GET NEW CONSOLE UNIT INC A ; BUMP TO SECONDARY ; HB_FP3: ; MAKE SURE NEW CONSOLE UNIT DOES NOT EXCEED THE HIGHEST ; CHAR UNIT IN SYSTEM. CP B ; A (UNIT) >= B (CNT)? JR NC,HB_FPZ ; ABORT IF UNIT TOO HIGH LD (HB_NEWCON),A ; UPDATE NEW CONSOLE UNIT ; HB_FPZ: ; #ENDIF ; INITSYS3: ; #IF (SUPCTS) ; ; RESTORE BOOT CONSOLE CONFIGURATION ; CALL LDELAY ; ALLOW SERIAL PORT TO FLUSH LD B,BF_CIOINIT ; HBIOS CIO INIT LD A,(HB_BOOTCONSAV) ; ORIGINAL BOOT CONSOLE DEVICE LD C,A ; BOOT CONSOLE TO C LD DE,(HB_CONCFGSAV) ; SAVED ORIGINAL CONSOLE CFG CALL HB_DISPATCH ; INTERNAL HBIOS CALL ; #ENDIF ; ; IF WE ARE GOING TO SWITCH CONSOLES, IT IS IMPLEMENTED HERE. A ; MESSAGE IS PRINTED ON THE OLD CONSOLE INDICATING WHERE THE NEW ; CONSOLE IS AND THE NEW CONSOLE RECEIVES AN HBIOS BANNER. ; LD A,(HB_BOOTCON) ; GET ORIGINAL BOOT CONSOLE DEV LD C,A ; PUT IN C LD A,(HB_NEWCON) ; GET NEW CONSOLE DEVICE CP C ; COMPARE JR Z,INITSYS3A ; NO CHANGE, BYPASS ; LD DE,STR_CONSOLE ; CONSOLE CHANGE NOTIFY CALL WRITESTR ; PRINT IT LD A,(HB_NEWCON) ; GET NEW CONSOLE UNIT NUM CALL PRTDECB ; PRINT UNIT NUM LD (CB_CONDEV),A ; IMPLEMENT NEW CONSOLE! LD DE,STR_BANNER ; POINT TO BANNER CALL NZ,WRITESTR ; OUTPUT IF CONSOLE MOVED ; ;-------------------------------------------------------------------------------------------------- ; PRINT DEVICE SUMMARY ;-------------------------------------------------------------------------------------------------- ; INITSYS3A: CALL PRTSUM ; PRINT UNIT/DEVICE SUMMARY TABLE ; ;-------------------------------------------------------------------------------------------------- ; DIAGNOSTIC ROUTINES ;-------------------------------------------------------------------------------------------------- ; ; DIGANOSTIC ROUTINE TO EXERCISE THE Z280 BNKCPY CODE ; #IF FALSE ; CALL NEWLINE CALL NEWLINE CALL NEWLINE ; SRC & DEST BELOW BND CALL NEWLINE LD HL,$4000 LD DE,$5000 LD BC,$3000 CALL NEWLINE CALL REGDMP CALL Z280_BNKCPYX ; SRC & DEST ABOVE BND CALL NEWLINE LD HL,$8000 LD DE,$9000 LD BC,$1000 CALL NEWLINE CALL REGDMP CALL Z280_BNKCPYX ; SRC CROSSOVER CALL NEWLINE LD HL,$7000 LD DE,$9000 LD BC,$2000 CALL NEWLINE CALL REGDMP CALL Z280_BNKCPYX ; DEST CROSSOVER CALL NEWLINE LD HL,$9000 LD DE,$7000 LD BC,$2000 CALL NEWLINE CALL REGDMP CALL Z280_BNKCPYX ; DOUBLE CROSSOVER CALL NEWLINE LD HL,$7800 LD DE,$7000 LD BC,$2000 CALL NEWLINE CALL REGDMP CALL Z280_BNKCPYX ; DOUBLE CROSSOVER SINGLE BYTES CALL NEWLINE LD HL,$7FFE LD DE,$7FFF LD BC,$0500 CALL NEWLINE CALL REGDMP CALL Z280_BNKCPYX CALL NEWLINE CALL NEWLINE CALL NEWLINE ; #ENDIF ; ; DIAGNOSTIC ROUTINE TO PLAY SERIES OF NOTES ; #IF FALSE ; LD HL,0 CALL DBG_NOTE LD HL,48 CALL DBG_NOTE LD HL,204 CALL DBG_NOTE LD HL,268 CALL DBG_NOTE LD HL,436 CALL DBG_NOTE ; JP INITSYS4 ; DBG_NOTE: PUSH HL CALL NEWLINE PRTS("AY: $") CALL PRTDEC16 PRTS("=$") CALL AY_NOTE LD HL,(AY_PENDING_PERIOD) CALL PRTDEC16 POP HL ; PRTS(" SN: $") CALL PRTDEC16 PRTS("=$") CALL SN7_NOTE LD HL,(SN7_PENDING_PERIOD) CALL PRTDEC16 ; RET ; #ENDIF ; ; MAKE A LITTLE NOISE... LD B,BF_SNDBEEP ; HBIOS BEEP FUNCTION LD C,0 ; SOUND UNIT 0 LD A,(SND_CNT) ; GET SOUND UNIT COUNT OR A ; CHECK FOR ZERO CALL NZ,HB_DISPATCH ; DO IT IF WE HAVE A SOUND UNIT ; ;-------------------------------------------------------------------------------------------------- ; TRANSITION TO USER LAND ;-------------------------------------------------------------------------------------------------- ; INITSYS4: ; ; IF Z280, WE NEED TO SWITCH TO USER MODE NOW. ; #IF (MEMMGR == MM_Z280) ; LEAVE SYSTEM MODE STACK POINTING TO THE RIGHT PLACE LD SP,HB_STACK ; DEDICATED HBIOS STACK LOC ; ; ACTIVATE THE CORRECT USER MODE BANK LD A,(HB_CURBNK) ; GET CURRENT BANK CALL HBX_BNKSEL ; DO IT ; ; PRESET THE USER MODE STACK LD HL,HBX_LOC ; USER STACK JUST BELOW PROXY LDCTL USP,HL ; DO IT ; ; SWITCH TO USER MODE NOW LD C,Z280_MSR ; MASTER STATUS REGISTER LD HL,$4000 | $0B ; USER MODE W/ NORMAL INT MASK LDCTL (C),HL ; DO IT #ENDIF ; DIAG(0) ; CLEAR BOOT DIAG LED(S) FPLEDS(DIAG_00) ; CLEAR FP LEDS ; ; CHAIN TO LOADER ; #IFDEF ROMBOOT LD A,BID_IMG0 ; CHAIN TO OS IMAGES BANK #ELSE LD A,BID_AUX ; CHAIN TO AUX BANK #ENDIF LD IX,0 ; ENTER AT ADDRESS 0 CALL HBX_BNKCALL ; GO THERE HALT ; WE SHOULD NEVER COME BACK! ; ;-------------------------------------------------------------------------------------------------- ; TABLE OF RECOVERY MODE INITIALIZATION ENTRY POINTS ;-------------------------------------------------------------------------------------------------- ; ; USE "CALLDUMMY" IF NO ENTRY REQUIRED ; #IF (BT_REC_TYPE != BT_REC_NONE) ; HB_PCINIT_REC: ; #IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) .DW UART_PREINIT ; .DW CALLDUMMY #ENDIF ; HB_PCINITRLEN .EQU (($ - HB_PCINIT_REC) / 2) ; HB_INIT_REC: ; #IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) .DW UART_INIT .DW MD_INIT .DW PPIDE_INIT #ENDIF ; HB_INITRLEN .EQU (($ - HB_INIT_REC) / 2) ; #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; TABLE OF PRE-CONSOLE INITIALIZATION ENTRY POINTS ;-------------------------------------------------------------------------------------------------- ; HB_PCINITTBL: ; #IF (SSERENABLE) .DW SSER_PREINIT #ENDIF #IF (ASCIENABLE) .DW ASCI_PREINIT #ENDIF #IF (Z2UENABLE) .DW Z2U_PREINIT #ENDIF #IF (UARTENABLE) .DW UART_PREINIT #ENDIF #IF (DUARTENABLE) .DW DUART_PREINIT #ENDIF #IF (SIOENABLE) .DW SIO_PREINIT #ENDIF #IF (EZ80UARTENABLE) .DW EZUART_PREINIT #ENDIF #IF (ACIAENABLE) .DW ACIA_PREINIT #ENDIF #IF (UFENABLE) .DW UF_PREINIT #ENDIF #IF (TMSENABLE) .DW TMS_PREINIT #ENDIF .DW TERM_PREINIT ; ALWAYS DO THIS ONE #IF (PIOENABLE) .DW PIO_PREINIT #ENDIF #IF (PIO_4P | PIO_ZP) .DW PIO_PREINIT #ENDIF ; HB_PCINITTBLLEN .EQU (($ - HB_PCINITTBL) / 2) ; ;================================================================================================== ; TABLE OF INITIALIZATION ENTRY POINTS ;================================================================================================== ; HB_INITTBL: ; #IF (KIOENABLE) .DW KIO_INIT #ENDIF #IF (CTCENABLE) .DW CTC_INIT #ENDIF #IF (PCFENABLE) .DW PCF_INIT #ENDIF ;;;#IF (DSKYENABLE) #IF (ICMENABLE) .DW ICM_INIT #ENDIF #IF (PKDENABLE) .DW PKD_INIT #ENDIF ;;;#ENDIF #IF (LCDENABLE) .DW LCD_INIT #ENDIF #IF (H8PENABLE) .DW H8P_INIT #ENDIF #IF (GM7303ENABLE) .DW GM7303_INIT #ENDIF #IF (PLATFORM == PLT_NABU) .DW NABU_INIT #ENDIF #IF (AY38910ENABLE) .DW AY38910_INIT ; AUDIBLE INDICATOR OF BOOT START #ENDIF #IF (SN76489ENABLE) .DW SN76489_INIT #ENDIF #IF (YM2612ENABLE) .DW YM2612_INIT #ENDIF #IF (SPKENABLE) .DW SP_INIT ; AUDIBLE INDICATOR OF BOOT START #ENDIF #IF (SSERENABLE) .DW SSER_INIT #ENDIF #IF (ASCIENABLE) .DW ASCI_INIT #ENDIF #IF (Z2UENABLE) .DW Z2U_INIT #ENDIF #IF (UARTENABLE) .DW UART_INIT #ENDIF #IF (DUARTENABLE) .DW DUART_INIT #ENDIF #IF (SIOENABLE) .DW SIO_INIT #ENDIF #IF (EZ80UARTENABLE) .DW EZUART_INIT #ENDIF #IF (ACIAENABLE) .DW ACIA_INIT #ENDIF #IF (UFENABLE) .DW UF_INIT #ENDIF #IF (DSRTCENABLE) .DW DSRTC_INIT #ENDIF #IF (DS1501RTCENABLE) .DW DS1501RTC_INIT #ENDIF #IF (BQRTCENABLE) .DW BQRTC_INIT #ENDIF #IF (SIMRTCENABLE) .DW SIMRTC_INIT #ENDIF #IF (INTRTCENABLE) .DW INTRTC_INIT #ENDIF #IF (DS7RTCENABLE) .DW DS7RTC_INIT #ENDIF #IF (DS5RTCENABLE) .DW DS5RTC_INIT #ENDIF #IF (RP5RTCENABLE) .DW RP5RTC_INIT #ENDIF #IF (EZ80RTCENABLE) .DW EZ80RTC_INIT #ENDIF #IF (CPUFAM == CPU_EZ80) ; INITALISE ONE OF THE SUPPORTED SYSTEM TIMER TICKS DRIVERS .DW EZ80_TMR_INIT #ENDIF #IF (VDUENABLE) .DW VDU_INIT #ENDIF #IF (CVDUENABLE) .DW CVDU_INIT #ENDIF #IF (VGAENABLE) .DW VGA_INIT #ENDIF #IF (GDCENABLE) .DW GDC_INIT #ENDIF #IF (TMSENABLE) .DW TMS_INIT #ENDIF #IF (EFENABLE) .DW EF_INIT #ENDIF #IF (VRCENABLE) .DW VRC_INIT #ENDIF #IF (FVENABLE) .DW FV_INIT #ENDIF #IF (SCONENABLE) .DW SCON_INIT #ENDIF #IF (LPTENABLE) .DW LPT_INIT #ENDIF #IF (PIOENABLE) .DW PIO_INIT #ENDIF #IF (PIO_4P | PIO_ZP) .DW PIO_INIT #ENDIF #IF (DMAENABLE) .DW DMA_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 (PPAENABLE) .DW PPA_INIT #ENDIF #IF (IMMENABLE) .DW IMM_INIT #ENDIF #IF (SYQENABLE) .DW SYQ_INIT #ENDIF #IF (CHENABLE) .DW CH_INIT #ENDIF #IF (PRPENABLE) .DW PRP_INIT #ENDIF #IF (PPPENABLE) .DW PPP_INIT #ENDIF #IF (ESPENABLE) .DW ESP_INIT #ENDIF ; HB_INITTBLLEN .EQU (($ - HB_INITTBL) / 2) ; HB_SYSINIT_END .EQU $ ; ;================================================================================================== ; BIOS FUNCTION DISPATCHER ;================================================================================================== ; HB_DISP_BEG .EQU $ ; ;-------------------------------------------------------------------------------------------------- ; HIGH LEVEL FUNCTION DISPATCHER ;-------------------------------------------------------------------------------------------------- ; ; JUMP TO FUNCTION GROUP SPECIFIC DISPATCHER. THE FUNCTION GROUP ; IS BASED ON THE TOP NIBBLE OF THE FUNCTION NUMBER. ; ; ENTRY: B=FUNCTION ; HB_DISPATCH: ; #IF (MEMMGR == MM_Z280) ; FOR Z280 MEMMGR, WE DISPATCH VIA THE Z280 SYSCALL. ; THE SYSCALL MECHANISM WILL DISABLE INTERRUPTS. IN ; GENERAL, INTERRUPTS ARE OK DURING API PROCESSING, ; SO ENABLE THEM HERE. HB_EI #ENDIF ; ; STACK INTEGRITY DIAGNOSTIC CHECK ; #IF FALSE ; *DEBUG* START ; CALL HB_DISPATCH1 ; DO THE WORK ; ; CHECK STACK INTEGRITY PUSH AF LD A,(HB_STACK - HB_STKSIZ + $08) CP $FF SYSCHKERR(ERR_INTERNAL) LD A,$FF LD (HB_STACK - HB_STKSIZ + $08),A POP AF RET ; HB_DISPATCH1: ; #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_DSKY + $10 ; $30-$3F: DSKY JP C,DSKY_DISPATCH CP BF_VDA + $10 ; $40-$4F: VIDEO DISPLAY ADAPTER JP C,VDA_DISPATCH CP BF_SND + $10 ; $50-$5F: SOUND DRIVERS JP C,SND_DISPATCH CP BF_SYS ; SKIP TO BF_SYS VALUE AT $F0 JR C,HB_DISPERR ; ERROR IF LESS THAN BF_SYS JP SYS_DISPATCH ; OTHERWISE SYS CALL ; FALL THRU ; HB_DISPERR: SYSCHKERR(ERR_NOFUNC) 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 CIO 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 ; ; CRT TYPE CHAR DEVICES CALL THIS TO REGISTER THAT THEY WANT TO BE THE ; DEFAULT CRT DEVICE. THIS ROUTINE WILL SET CB_CRTDEV WHEN CALLED THE ; FIRST TIME. SUBSEQUENT CALLS ARE IGNORED. THIS ENSURES THAT THE ; *FIRST* CRT DEVICE WINS. ; CIO_SETCRT: PUSH AF ; SAVE INCOMING CRT DEV NUM LD A,(CB_CRTDEV) ; GET CURRENT CRT DEV NUM INC A ; $FF -> $00 JR NZ,CIO_SETCRT_Z ; IF ALREADY SET, LEAVE IT ALONE POP AF ; RESTORE AF LD (CB_CRTDEV),A ; SAVE CRT DEV NUM RET ; AND DONE ; CIO_SETCRT_Z: POP AF ; RESTORE AF RET ; AND DONE ; ;-------------------------------------------------------------------------------------------------- ; DISK I/O DEVICE FUNCTION DISPATCHER ;-------------------------------------------------------------------------------------------------- ; ; ROUTE CALL TO SPECIFIED DISK I/O DRIVER ; B: FUNCTION ; C: UNIT NUMBER ; DIO_DISPATCH: ; #IF FALSE ; *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 ;-------------------------------------------------------------------------------------------------- ; ;;; RELOCATE THIS CODE??? ; ; IMPLEMENTS MULTI SECTOR READS AND I/O TO/FROM ; BANKED RAM VIA BOUNCE BUFFER ; ; ON ENTRY: ; 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 ; LD (HB_DSKCMD),BC ; SAVE HBIOS FUNC & UNIT ; #IF (FPLED_ENABLE & FPLED_DSKACT) ; 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 TRUE ; 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 TRUE ; 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 ; LD (HB_DSKCMD),BC ; SAVE HBIOS FUNC & UNIT ; #IF (FPLED_ENABLE & FPLED_DSKACT) ; 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 TRUE ; 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 TRUE ; 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 ; ;-------------------------------------------------------------------------------------------------- ; INVOKE DRIVER DISK I/O FUNCTION ;-------------------------------------------------------------------------------------------------- ; HB_DSKFN: PUSH BC ; SAVE COUNTERS #IF (FPLED_ENABLE & FPLED_DSKACT) LD A,(HB_DSKBIT) ; LOAD UNIT DISK BIT MASK CALL FP_SETLEDS ; DISPLAY ON FP LEDS #ENDIF #IF (LEDENABLE & LEDDISKIO) DIAG(1) ; BIT 0 FOR TINY Z80 & MBC, BIT 2 FOR SCXXX #ENDIF LD E,1 ; ONE SECTOR HB_DSKFNADR .EQU $+1 CALL PANIC ; READ ONE SECTOR #IF (FPLED_ENABLE & FPLED_DSKACT) FPLEDS($00) ; CLEAR FP LEDS #ENDIF #IF (LEDENABLE & LEDDISKIO) DIAG(0) #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 HB_DSKCMD: HB_DSKUNIT .DB 0 ; CURRENT DISK UNIT HB_DSKFUNC .DB 0 ; CURRENT DISK FUNCTION HB_DSKADR .FILL 4,0 ; CURRENT DISK BLOCK ADDRESS ; ;-------------------------------------------------------------------------------------------------- ; DSKY DISK ACTIVITY MONITOR ;-------------------------------------------------------------------------------------------------- ; ; THIS FUNCTION IS CALLED BY DISK DRIVERS JUST PRIOR TO ; THE START OF A DISK I/O OPERATION. ; ; THE CURRENT DISK UNIT NUMBER WILL BE DISPLAYED IN THE FIRST ; 2 SEG DISPLAYS. THE LOWER 24 BITS OF THE SECTOR WILL BE ; DISPLAYED IN THE LAST 6 SEG DISPLAYS. ; ; A DOT IS DISPLAYED TO SEPARATE THE UNIT NUMBER FROM THE ADDRESS ; DISPLAY. ALSO, A TRAILING DOT IS DISPLAYED IF THE I/O FUNCTION ; IS A WRITE. ; ; HL: ADDRESS OF 32-BIT SECTOR NUMBER (LITTLE-ENDIAN) ; ALL REGISTERS PERSERVED ; #IF (DSKYDSKACT) HB_DSKACT: ; ; SAVE EVERYTHING PUSH AF PUSH BC PUSH DE PUSH HL ; ; COPY VALUE TO LOCAL HB_DSKADR CALL LD32 ; HB_DSKACT1: LD BC,HB_DSKADR CALL ST32 ; LD B,BF_DSKYEVENT LD C,DSKY_EVT_DSKACT CALL DSKY_DISPATCH ; ; CLEAN UP AND GO AWAY POP HL POP DE POP BC POP AF JR HB_DSKACT_Z ; DONE ; ; THIS IS THE CHS VARIANT OF THE ABOVE. THIS IS USED BY CHS ORIENTED ; DISK DRIVERS (BASICALLY JUST FLOPPY). ; ; THE CURRENT DISK UNIT NUMBER WILL BE DISPLAYED IN THE FIRST ; 2 SEG DISPLAYS. THE TRACK, HEAD, AND SECTOR WILL BE DISPLAYED IN ; THE LAST 6 SEG DISPLAYS ; ; HL: ADDRESS OF CYL,HD,SEC IN THE FORMAT CCSH ; ALL REGISTERS PRESERVED ; HB_DSKACTCHS: PUSH AF PUSH BC PUSH DE PUSH HL CALL LD32 ; DE:HL = HSCC ; MAP HSCC -> CCHS EX DE,HL JR HB_DSKACT1 ; HB_DSKACT_Z: RET ; #ELSE ; HB_DSKACT: HB_DSKACTCHS: RET ; #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; REAL TIME CLOCK DEVICE DISPATCHER ;-------------------------------------------------------------------------------------------------- ; ; ROUTE CALL TO REAL TIME CLOCK DRIVER ; B: FUNCTION ; RTC_DISPATCH: PUSH HL ; SAVE INCOMING HL LD HL,(RTC_DISPADR) ; EX (SP),HL RET ; RTC_DISPERR: SYSCHKERR(ERR_NOHW) RET ; ; SET RTC DISPATCH ADDRESS, USED BY RTC DRIVERS DURING INIT ; BC HAS ADDRESS OF DISPATCH ADDRESS ; WILL ONLY SAVE THE FIRST ADDRESS SET ; RTC_SETDISP: LD A,(RTC_DISPACT) ; GET ACTIVE FLAG OR A ; IS IT ACTIVE? RET NZ ; ABORT IF ALREADY ACTIVE LD (RTC_DISPADR),BC ; SAVE THE ADDRESS OR $FF ; FLAG ACTIVE VALUE LD (RTC_DISPACT),A ; SAVE IT RET ; AND DONE ; RTC_DISPADR .DW RTC_DISPERR ; RTC DISPATCH ADDRESS RTC_DISPACT .DB 0 ; SET WHEN DISPADR SET ; ;-------------------------------------------------------------------------------------------------- ; DSKY DEVICE DISPATCHER ;-------------------------------------------------------------------------------------------------- ; ; ROUTE CALL TO DSKY DRIVER ; B: FUNCTION ; DSKY_DISPATCH: PUSH HL ; SAVE INCOMING HL LD HL,(DSKY_DISPADR) ; EX (SP),HL RET ; DSKY_DISPERR: SYSCHKERR(ERR_NOHW) RET ; ; SET DSKY DISPATCH ADDRESS, USED BY DSKY DRIVERS DURING INIT ; BC HAS ADDRESS OF DISPATCH ADDRESS ; WILL ONLY SAVE THE FIRST ADDRESS SET ; DSKY_SETDISP: LD A,(DSKY_DISPACT) ; GET ACTIVE FLAG OR A ; IS IT ACTIVE? RET NZ ; ABORT IF ALREADY ACTIVE LD (DSKY_DISPADR),BC ; SAVE THE ADDRESS OR $FF ; FLAG ACTIVE VALUE LD (DSKY_DISPACT),A ; SAVE IT RET ; AND DONE ; DSKY_DISPADR .DW DSKY_DISPERR ; DSKY DISPATCH ADDRESS DSKY_DISPACT .DB 0 ; SET WHEN DISPADR SET ; ;================================================================================================== ; 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 16 ; 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 ; ;-------------------------------------------------------------------------------------------------- ; SOUND ADAPTER DEVICE DISPATCHER ;-------------------------------------------------------------------------------------------------- ; ; ROUTE CALL TO SPECIFIED SOUND DEVICE DRIVER ; B: FUNCTION ; C: UNIT NUMBER ; SND_DISPATCH: PUSH IY ; SAVE INCOMING IY ; LD IY, SND_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 SND UNIT TABLE (SEE HB_ADDENT FOR DETAILS) ; SND_ADDENT: LD HL, SND_TBL ; POINT TO SND 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 SND FUNCTION IDS ; EACH ENTRY IS DEFINED AS: ; ; WORD DRIVER FUNCTION TABLE ADDRESS ; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) ; SND_FNCNT .EQU 9 ; NUMBER OF SND FUNCS (FOR RANGE CHECK) SND_MAX .EQU 5 ; UP TO 5 UNITS SND_SIZ .EQU SND_MAX * 4 ; EACH ENTRY IS 4 BYTES ; .DB SND_FNCNT ; SND FUNCTION COUNT (FOR RANGE CHECK) .DB SND_MAX ; MAX ENTRY COUNT TABLE PREFIX SND_CNT .DB 0 ; ENTRY COUNT PREFIX SND_TBL .FILL SND_SIZ,0 ; SPACE FOR ENTRIES ; ;-------------------------------------------------------------------------------------------------- ; SPEAKER BEEP ROUTINE ;-------------------------------------------------------------------------------------------------- ; ; ROUTINE TO BEEP A SOUND UNIT ; THE SOUND DRIVERS CAN DEFER THEIR BEEP FUNCTION TO THIS FUNCTION ; ON ENTRY, B = SOUND UNIT ; WHICH CHANNEL SHOULD BE USED? IS THERE A GOOD DEFAULT CHANNEL? ; SND_BEEP: ; RESET THE SOUND DEVICE TO START LD B,$50 ; SOUND RESET FUNCTION CALL SND_BEEP_DISP ; DO IT ; ; SET VOLUME TO MAX LD B,$51 ; VOLUME LD L,$FF ; MAX CALL SND_BEEP_DISP ; DO IT ; ; SET NOTE TO PLAY LD B,$53 ; SELECT NOTE LD HL,244 ; B5 (CLOSE TO 1 KHZ) CALL SND_BEEP_DISP ; DO IT ; ; START PLAYING THE SOUND LD B,$54 ; PLAY SOUND LD D,0 ; CHANNEL 0 CALL SND_BEEP_DISP ; DO IT ; ; WAIT A BIT FOR SOUND TO PLAY LD DE,23436 ; PLAY FOR 1/3 SECOND CALL VDELAY ; WAIT WHILE TONE IS PLAYED ; LD B,$50 ; SOUND RESET FUNCTION CALL SND_BEEP_DISP ; DO IT ; XOR A ; SIGNAL SUCCESS RET ; DONE ; SND_BEEP_DISP: ; CALL SOUND DISPATCHER PRESERVING BC ACROSS CALL PUSH BC CALL SND_DISPATCH POP BC RET ; ;-------------------------------------------------------------------------------------------------- ; 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 DEC A ; HB_DISP_END .EQU $ ; ;================================================================================================== ; Z280 INTERRUPT VECTOR TABLE ;================================================================================================== ; HB_Z280IVT_BEG .EQU $ ; ; THE Z280 IVT MUST BE ON A 4K BOUNDARY. IT HAS BEEN LOCATED ; HERE IN AN EFFORT TO MINIMIZE WASTED SPACE. THERE SHOULD BE ; A LITTLE LESS THAN 4K OF CODE ABOVE. ; #IF (MEMMGR == MM_Z280) ; Z280_IVT_SLACK_ORG .EQU $ ALIGN($1000) Z280_IVT_SLACK .EQU $ - Z280_IVT_SLACK_ORG .ECHO "Z280 IVT SLACK = " .ECHO Z280_IVT_SLACK .ECHO " bytes.\n" ; Z280_IVT: .DW 0, 0 ; RESERVED .DW 0 ; NMI MSR .DW 0 ; NMI VECTOR .DW $0000 ; INT A MSR .DW Z280_BADINT ; INT A VECTOR .DW $0000 ; INT B MSR .DW Z280_BADINT ; INT B VECTOR .DW $0000 ; INT C MSR .DW Z280_BADINT ; INT C VECTOR .DW $0000 ; COUNTER/TIMER 0 MSR .DW Z280_BADINT ; COUNTER/TIMER 0 VECTOR .DW $0000 ; COUNTER/TIMER 1 MSR .DW Z280_BADINT ; COUNTER/TIMER 1 VECTOR .DW 0, 0 ; RESERVED .DW $0000 ; COUNTER/TIMER 2 MSR .DW Z280_BADINT ; COUNTER/TIMER 2 VECTOR .DW $0000 ; DMA CHANNEL 0 MSR .DW Z280_BADINT ; DMA CHANNEL 0 VECTOR .DW $0000 ; DMA CHANNEL 1 MSR .DW Z280_BADINT ; DMA CHANNEL 1 VECTOR .DW $0000 ; DMA CHANNEL 2 MSR .DW Z280_BADINT ; DMA CHANNEL 2 VECTOR .DW $0000 ; DMA CHANNEL 3 MSR .DW Z280_BADINT ; DMA CHANNEL 3 VECTOR .DW $0000 ; UART RECEIVER MSR .DW Z280_BADINT ; UART RECEIVER VECTOR .DW $0000 ; UART TRANSMITTER MSR .DW Z280_BADINT ; UART TRANSMITTER VECTOR .DW $0000 ; SINGLE STEP TRAP MSR .DW Z280_SSTEP ; SINGLE STEP TRAP VECTOR .DW $0000 ; BREAK ON HALT TRAP MSR .DW Z280_BRKHLT ; BREAK ON HALT TRAP VECTOR .DW $0000 ; DIVISION EXCEPTION TRAP MSR .DW Z280_DIVEXC ; DIVISION EXCEPTION TRAP VECTOR .DW $0000 ; STACK OVERFLOW WARNING TRAP MSR .DW Z280_STKOVR ; STACK OVERFLOW WARNING TRAP VECTOR .DW $0000 ; ACCESS VIOLATION TRAP MSR .DW Z280_ACCVIO ; ACCESS VIOLATION TRAP VECTOR .DW $0000 ; SYSTEM CALL TRAP MSR .DW Z280_SYSCALL ; SYSTEM CALL TRAP VECTOR .DW $0000 ; PRIVILEGED INSTRUCTION TRAP MSR .DW Z280_PRIVINST ; PRIVILEGED INSTRUCTION TRAP VECTOR .DW $0000 ; EPU <- MEMORY EXTENDED INSTRUCTION TRAP MSR .DW $0000 ; EPU <- MEMORY EXTENDED INSTRUCTION TRAP VECTOR .DW $0000 ; MEMORY <- EPU EXTENDED INSTRUCTION TRAP MSR .DW $0000 ; MEMORY <- EPU EXTENDED INSTRUCTION TRAP VECTOR .DW $0000 ; A <- EPU EXTENDED INSTRUCTION TRAP MSR .DW $0000 ; A <- EPU EXTENDED INSTRUCTION TRAP VECTOR .DW $0000 ; EPU INTERNAL OPERATION EXTENDED INSTRUCTION TRAP MSR .DW $0000 ; EPU INTERNAL OPERATION EXTENDED INSTRUCTION TRAP VECTOR .DW 0, 0 ; RESERVED .DW 0, 0 ; RESERVED ; PROGRAM COUNTER VALUES FOR NMI/INTA (16) .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 ; ; THE REMAINDER OF THE Z280 IVT IS TRUNCATED HERE BECAUSE IT ; TAKES A BUNCH OF SPACE AND IS NOT USED. WE SUPPORT ONLY ; 16 VECTORED INTERRUPTS AND THEY MUST BE CONNECTED TO INTA. ; #ENDIF ; HB_Z280IVT_END .EQU $ ; ;================================================================================================== ; SYSTEM API FUNCTIONS ;================================================================================================== ; HB_SYSAPI_BEG .EQU $ ; ;-------------------------------------------------------------------------------------------------- ; SYSTEM RESET ;-------------------------------------------------------------------------------------------------- ; ; RESTART SYSTEM ; SUBFUNCTION IN C ; SYS_RESET: LD A,C ; GET REQUESTED SUB-FUNCTION CP BF_SYSRES_INT JR Z,SYS_RESINT CP BF_SYSRES_WARM JR Z,SYS_RESWARM CP BF_SYSRES_COLD JR Z,SYS_RESCOLD CP BF_SYSRES_USER JR Z,SYS_RESUSER SYSCHKERR(ERR_NOFUNC) RET ; ; SOFT RESET HBIOS, RELEASE HEAP MEMORY NOT USED BY HBIOS ; SYS_RESINT: ; ; RESET THE HEAP LD HL,(HEAPCURB) ; GET HBIOS HEAP THRESHOLD LD (CB_HEAPTOP),HL ; RESTORE HEAP TOP ; XOR A RET ; ; GO BACK TO ROM BOOT LOADER ; SYS_RESWARM: ; CALL SYS_RESINT ; HBIOS INTERNAL RESET ; #IF (MEMMGR == MM_Z280) JP INITSYS4 #ELSE ; PERFORM BANK CALL TO OS IMAGES BANK IN ROM LD SP,HBX_LOC ; STACK JUST BELOW HBIOS PROXY #IFDEF APPBOOT LD A,BID_AUX ; IF APPBOOT, CHAIN TO AUX BANK #ELSE LD A,BID_IMG0 ; ELSE CHAIN TO OS IMAGES BANK #ENDIF LD IX,0 ; ENTER AT ADDRESS 0 CALL HBX_BNKCALL ; GO THERE HALT ; WE SHOULD NEVER COME BACK! #ENDIF ; ; RESTART SYSTEM AS THOUGH POWER HAD JUST BEEN TURNED ON ; SYS_RESCOLD: ; #IFDEF APPBOOT JP HB_RESTART #ELSE ; ; MAKE ROM BOOT BANK ACTIVE IN LOW SYS MEM ; #IF (MEMMGR == MM_Z280) ; FOR Z280, NEED TO REMAP THE LOW 32K IN SYSTEM MODE AND ; CONTINUE AT ADDRESS ZERO. WE CANNOT RETURN HERE AFTER THE ; BNKSEL IS DONE BECAUSE THE SYSTEM BANK HAS BEEN CHANGED! ; SO, WE PRESET THE STACK TO CAUSE A JUMP TO THE RESTART ; ADDRESS ON RETURN FROM THE BNKSEL. SLICK, RIGHT? DI ; KILL INTERRUPTS LD SP,HBX_LOC ; STACK IN HIGH MEMORY LD HL,HB_RESTART ; RESUME AT RESTART ADDRESS PUSH HL ; ... IS PRESET ON STACK LD A,BID_BOOT ; BANK TO LAUNCH RESTART LD B,$10 ; FIRST SYS PDR JP Z280_BNKSEL ; DO IT AND RESUME FROM STACK #ELSE ; FOR OTHER THAN Z280, JUST DO AN INTERBANK CALL TO THE ; RESTART ADDRESS. DI LD SP,HBX_LOC ; STACK JUST BELOW HBIOS PROXY LD A,BID_BOOT ; BANK TO LAUNCH RESTART LD IX,HB_RESTART ; RESUME AT RESTART ADDRESS CALL HB_BNKCALL ; DOES NOT RETURN #ENDIF #ENDIF ; ; HOOK CALLED WHEN A USERLAND RESET IS INVOKED, TYPICALLY VIA A JUMP ; TO CPU ADDRESS $0000 ; ; CREDIT TO PHILLIP STEVENS FOR SUGGESTING AND SIGNIFICANT CONTRIBUTIONS ; TO THE Z180 INVALID OPCODE TRAP ENHANCEMENT. ; SYS_RESUSER: ; #IF (CPUFAM == CPU_Z180) ; ; IF Z180 CPU, CHECK FOR INVALID OPCODE FLAG AND HANDLE IF SO ; IN0 A,(Z180_ITC) ; GET ITC REGISTER XOR $80 ; PRECLEAR TRAP BIT RET M ; IF TRAP BIT NOT SET, DONE ; ; HANDLE INVALID OPCODE DEC HL ; BACK UP TO OPCODE START BIT 6,A ; CHECK UFO BIT (2 BYTE OPCODE) JR Z,SYS_RESUSER1 ; IF NOT, ALL SET DEC HL ; OTHERWISE, BACK UP 1 MORE BYTE ; SYS_RESUSER1: OUT0 (Z180_ITC),A ; SAVE IT ; CALL PRTSTRD ; PRINT ERROR TAG .TEXT "\r\n\r\n+++ INVALID Z180 OPCODE @$" CALL PRTHEXWORDHL ; PRINT OPCODE ADDRESS PRTS("H:$") ; FORMATTING ; LD B,8 ; SHOW 8 BYTES SYS_RESUSER2: PUSH BC ; SAVE BC PUSH HL ; SAVE HL LD A,(HB_INVBNK) ; GET BYTE FROM INVOKING BANK LD D,A ; PUT IN D CALL SYS_PEEK ; PEEK TO GET BYTE VALUE LD A,E ; PUT IN A CALL PC_SPACE ; FORMATTING CALL PRTHEXBYTE ; DISPLAY BYTE POP HL ; RECOVER HL POP BC ; RECOVER BC INC HL ; NEXT BYTE DJNZ SYS_RESUSER2 ; LOOP TIL DONE JP NEWLINE ; FORMATTING & EXIT ; #ENDIF ; ; RESET ACTIVE VIDEO DISPLAY ATTACHED TO EMULATOR CALL TERM_RESET ; RET ; ELSE RETURN WITH USER RESET VECTOR IN HL ; ;-------------------------------------------------------------------------------------------------- ; SYSTEM VERSION ;-------------------------------------------------------------------------------------------------- ; ; 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 BANK ;-------------------------------------------------------------------------------------------------- ; ; 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 ESTABLISH UPPER MEMORY STACK BEFORE INVOKING THIS FUNCTION! ; SYS_SETBNK: #IF (MEMMGR == MM_Z280) ; FOR Z280 MEMMGR, WE ARE IN SYSTEM MODE HERE, SO WE CAN UPDATE ; THE USER MODE BANK WITHOUT IMPACTING THE RUNNING CODE. IT ; WILL TAKE EFFECT UPON RETURN TO USER MODE. LD A,(HB_INVBNK) ; GET PREVIOUS BANK PUSH AF ; SAVE IT LD A,C ; NEW BANK TO A LD (HB_INVBNK),A ; UPDATE INVBNK LD B,$00 ; FIRST USER PDR CALL Z280_BNKSEL ; DO IT POP AF ; RECOVER PREV BANK LD C,A ; PREVIOUS BANK TO C XOR A ; SIGNAL SUCCESS RET ; DONE #ELSE 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 #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; GET BANK ;-------------------------------------------------------------------------------------------------- ; SYS_GETBNK: LD A,(HB_INVBNK) ; GET THE ACTIVE MEMORY BANK LD C,A ; MOVE TO C XOR A ; SIGNAL SUCCESS RET ; ;-------------------------------------------------------------------------------------------------- ; SETUP INTERBANK COPY ;-------------------------------------------------------------------------------------------------- ; ; 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 INTERBANK COPY ;-------------------------------------------------------------------------------------------------- ; ; 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 CALL HB_BNKCPY XOR A RET ; ;-------------------------------------------------------------------------------------------------- ; ALLOCATE HEAP SPACE ;-------------------------------------------------------------------------------------------------- ; ; 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 SPACE ;-------------------------------------------------------------------------------------------------- ; ; 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: SYSCHKERR(ERR_NOTIMPL) ; NOT YET IMPLEMENTED RET ; ;-------------------------------------------------------------------------------------------------- ; GET SYSTEM INFORMATION ;-------------------------------------------------------------------------------------------------- ; ; GET SYSTEM INFORMATION ; ITEM TO RETURN INDICATED IN C ; SYS_GET: LD A,C ; GET REQUESTED SUB-FUNCTION CP BF_SYSGET_CIOCNT JP Z,SYS_GETCIOCNT CP BF_SYSGET_CIOFN JP Z,SYS_GETCIOFN CP BF_SYSGET_DIOCNT JP Z,SYS_GETDIOCNT CP BF_SYSGET_DIOFN JP Z,SYS_GETDIOFN CP BF_SYSGET_DIOMED JP Z,SYS_GETDIOMED CP BF_SYSGET_RTCCNT JP Z,SYS_GETRTCCNT CP BF_SYSGET_DSKYCNT JP Z,SYS_GETDSKYCNT CP BF_SYSGET_VDACNT JP Z,SYS_GETVDACNT CP BF_SYSGET_VDAFN JP Z,SYS_GETVDAFN CP BF_SYSGET_SNDCNT JP Z, SYS_GETSNDCNT CP BF_SYSGET_SNDFN JP Z,SYS_GETSNDFN CP BF_SYSGET_TIMER JP Z,SYS_GETTIMER CP BF_SYSGET_SECS JP Z,SYS_GETSECS CP BF_SYSGET_BOOTINFO JP Z,SYS_GETBOOTINFO CP BF_SYSGET_CPUINFO JP Z,SYS_GETCPUINFO CP BF_SYSGET_MEMINFO JP Z,SYS_GETMEMINFO CP BF_SYSGET_BNKINFO JP Z,SYS_GETBNKINFO CP BF_SYSGET_CPUSPD JP Z,SYS_GETCPUSPD CP BF_SYSGET_PANEL JP Z,SYS_GETPANEL CP BF_SYSGET_APPBNKS JP Z,SYS_GETAPPBNKS SYSCHKERR(ERR_NOFUNC) ; SIGNAL ERROR 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 SERIAL UNIT API FN ADR AND DATA ADR ; ENTRY: ; D: FUNCTION ; E: UNIT ; RETURNS: ; HL: FUNCTION ADDRESS ; DE: DATA BLOB ADDRESS ; SYS_GETCIOFN: BIT 7,E ; CHECK FOR SPECIAL UNIT CODE CALL NZ,SYS_GETCIOFN1 ; IF SO, HANDLE IT LD IY,CIO_TBL ; POINT TO UNIT TABLE JP SYS_GETFN ; GO TO COMMON CODE ; SYS_GETCIOFN1: LD A,(CB_CONDEV) ; UNIT $80 -> CONSOLE UNIT LD E,A ; REPLACE UNIT VALUE IN C RET ; AND BACK TO REGULAR FLOW ; ; ; 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 DISK UNIT API FN ADR AND DATA ADR ; ENTRY: ; D: FUNCTION ; E: UNIT ; RETURNS: ; HL: FUNCTION ADDRESS ; DE: DATA BLOB ADDRESS ; SYS_GETDIOFN: LD IY,DIO_TBL ; POINT TO UNIT TABLE JP SYS_GETFN ; GO TO COMMON CODE ; ; GET DISK EXTENDED HARD DISK MEDIA INFORMATION ; This function is specificly intended for Hard Drives, where it will scan ; the partition table and return a Media ID, including hd1k (MID_HDNEW). ; It will also return the absolute LBA offset of the first sector in the slice ; If the slice number is invalid (wont fit) the Status will return an error ; If the Unit is not a hard disk the Media ID will be returned and slice ignored. ; ; ENTRY: ; B: FUNCTION 0xF8 SYSGET ; C: SUB FUNCTION 0x12 DIOMED ; D: DISK UNIT, preferably for a hard disk. ; E: SLICE, ignored if media is not a hard disk ; RETURNS: ; A: STATUS, -6 (parameter out of range) - if Slice is invalid ; B: DEVICE ATTRIBUTES, as reported by DIODEVICE ; C: MEDIAID, including MID_HDNEW if hd1k partition is found ; DEHL: LBAOFFSET, of Slice if valid, 0 otherwise. ; DIOMED_SLICE .DB 0 ; SLICE ARGUMENT (E) DIOMED_UNIT .DB 0 ; UNIT ARGUMENT (D) DIOMED_DEVATT .DB 0 ; DEVICE ATTRIBUTES ; DIOMED_WRKSTA .EQU $ DIOMED_LBAOFF .FILL 4,0 ; START OF PARTITION / SLICE (SECTORS) DIOMED_LBASIZ .FILL 4,0 ; SIZE OF MEDIA / PARTITION (SECTORS) DIOMED_MID .DB 0 ; DISCOVERED MEDIAID DIOMED_SPS .DW 0 ; DISCOVERED SECTORS PER SLICE (16BIT) DIOMED_FND .DB 0 ; DID WE FIND A NON CPM PARTITION DIOMED_WRKSIZ .EQU $ - DIOMED_WRKSTA ; SIZE OF WORKING DATA ; SYS_GETDIOMED: ; SAVE CALL ARGUMENTS LD (DIOMED_SLICE),DE ; STORES DE -> SLICE/UNIT PARAMETERS ; READ DEVICE INFORMATION USING DIODEVICE FUNCTION LD A,(DIOMED_UNIT) LD C,A ; UNIT ID PARAMETER INTO C LD B,BF_DIODEVICE ; DRIVER FUNCTION = DISK MEDIA CALL DIO_DISPATCH ; CALL DIO TO GET DEVICE ATTRIBUTES RET NZ ; ABORT ON ERROR ; ; DEVICE ATTRIBUTES IN C LD A,C LD (DIOMED_DEVATT),A ; STORE DEVICE ATTRIBUTES ; ; DETERMINE MEDIA IN DRIVE USING DIOMEDIA FUNCTION LD A,(DIOMED_UNIT) LD C,A ; UNIT ID PARAMETER INTO C LD E,1 ; ENABLE MEDIA CHECK/DISCOVERY LD B,BF_DIOMEDIA ; DRIVER FUNCTION = DISK MEDIA CALL DIO_DISPATCH ; CALL DIO TO GET MEDIAID (RESULT IN E) RET NZ ; ABORT ON ERROR ; ; CHECK MEDIA TYPE, ONLY HD IS APPLICABLE LD A,E ; RESULTANT MEDIA ID TO ACCUM OR A ; SET FLAGS JR Z, SYS_GETDIOMED1A ; BAIL IF NO MEDIA CP MID_HD ; IS IT A HARD DISK JR Z, SYS_GETDIOMED1B ; IS HD, CONTINUE TO PROCESS HD ; ; NOT A HARD DISK, CHECK SLICE = 0 LD A,(DIOMED_SLICE) ; GET THE SLICE OR A ; SET FLAGS JP NZ, SYS_GETDIOMED5C ; SLICE NOT ZERO - SIGNAL ERROR AND RETURN ; SYS_GETDIOMED1A: ; RETURN MEDIA ID (NOT HD) WITH SUCCESS LD DE,0 ; LBA VALUE WILL BE ZERO LD HL,0 JP SYS_GETDIOMED6A ; RETURN SUCCESS ; SYS_GETDIOMED1B: ; FOUND HD, NEED TO PROCESS MBR / PART TABLE ; CLEAR WORKING STORAGE LD HL,DIOMED_WRKSTA ; HL SET TO FIRST BYTE LD (HL),0 ; CLEAR FIRST BYTE LD D,H LD E,L INC DE ; DE SET TO SECOND BYTE LD BC,DIOMED_WRKSIZ - 1 ; NUMBER OF LDIR COPIES LDIR ; BLOCK COPY TO CLEAR WORKING STORAGE ; ; SEEK TO SECTOR ZERO (MBR TABLE) LD B,BF_DIOSEEK ; SEEK FUNCTION LD A,(DIOMED_UNIT) ; GET UNIT LD C,A ; PUT IN C LD DE,$8000 ; LBA SECTOR ZERO LD HL,0 ; ASSUME LBA ACCESS FOR NOW CALL DIO_DISPATCH ; DO IT RET NZ ; ABORT ON ERROR ; ; READ SECTOR ZERO (MBR TABLE) LD B,BF_DIOREAD ; READ FUNCTION LD A,(DIOMED_UNIT) ; GET UNIT LD C,A ; PUT IN C LD A,(HB_CURBNK) ; GET CURRENT BANK ID LD D,A ; PUT IN D LD E,1 ; SECTOR COUNT LD HL,HB_WRKBUF ; IO BUFFER TO USE CALL DIO_DISPATCH ; DO IT RET NZ ; ABORT ON ERROR ; ; CHECK MBR OF DISK TO SEE IF IT HAS A PARTITION TABLE. LD HL,HB_WRKBUF ; DSKBUF ADR LD DE,$1FE ; OFFSET TO SIGNATURE ADD HL,DE ; POINT TO SIGNATURE LD A,(HL) ; GET FIRST BYTE CP $55 ; CHECK FIRST BYTE JR NZ,SYS_GETDIOMED3C ; NO MATCH, NO PART TABLE INC HL ; NEXT BYTE LD A,(HL) ; GET SECOND BYTE CP $AA ; CHECK SECOND BYTE JR NZ,SYS_GETDIOMED3C ; NO MATCH, NO PART TABLE ; ; FOUND PARTITION TABLE - LOOP AND PROCESS PARTITION TABLE LD HL,HB_WRKBUF ; DSKBUF ADR LD DE,$1BE+4 ; OFFSET OF FIRST ENTRY PART TYPE ADD HL,DE ; POINT TO IT LD B,4 ; FOUR ENTRIES IN PART TABLE LOOP SYS_GETDIOMED2A: LD A,(HL) ; GET PART TYPE LD DE,4 ADD HL,DE ; MOVE HL FWD TO GET TO LBA OFFSET CP $2E ; CP/M PARTITION? JR Z,SYS_GETDIOMED3B ; HD1K, GRAB THE LBA OFFSET CP $00 ; IS ANOTHER PARTITION TYPE, NOT CPM JR NZ,SYS_GETDIOMED3A ; OTHER VALID PART TYPE SYS_GETDIOMED2B: LD DE,12 ; REMAINING SIZE TO GET TO NEXT PARTITION SYS_GETDIOMED2C: ADD HL,DE ; BUMP TO NEXT PARTITION ENTRY - TYPE DJNZ SYS_GETDIOMED2A ; LOOP THRU TABLE JR SYS_GETDIOMED3C ; READ ALL - NO CP/M PARTITION FOUND ; SYS_GETDIOMED3A ; FOUND OTHER (NOT CPM) PARTITION LD A,(DIOMED_FND) ; HAVE WE ALREADY FOUND PROCESSED NON CPM OR A ; PARTITION, AND CAPTURED ITS START SECTOR, SO JR NZ,SYS_GETDIOMED2B ; IGNORE AND CONTINUTE TO NEXT PARTITION ENTRY ; ; NOTE THERE SLIGHT ISSUE HERE THAT WE ONLY CONSIDER THE FIRST NON-CPM PARTITION ; TO GET THE UPPER SIZE OF MEDIA, IDEALLY WE WOULD CONSIDER ALL, AND TAKE THE LOWEWST ; STARTING SECTOR - THIS IS A COMPRIMISE - OUT OF SEQUENCE PARTITIONS ARE UNLIKELY. ; PUSH BC ; SAVE IT, BEING USED IN PARTITION LOOP LD BC, 4 ; IF NOT ALREADY SET - COPY 4 BYTES LD DE, DIOMED_LBASIZ ; FROM PARTION LBA OFFSET (HL) - TO WORKING LBA SIZE (DE) LDIR ; COPY 4 BYTES POP BC ; RESTORE ; LD A,$FF LD (DIOMED_FND),A ; SET FOUND FLAG, SO DONT PROCESS ANY OTHERS LD DE,8 ; AND INC HL BY 8 TO GET TO NEXT PARITION JR SYS_GETDIOMED2C ; CONTINUE TO NEXT PARTITION ; SYS_GETDIOMED3B: ; FOUND CP/M (HD1K) PARTITION - RECORD THIS LD A, MID_HDNEW ; DISCOVERED HD1K MEDIA LD (DIOMED_MID), A ; STORE IT LD BC, SPS_HD1K ; DISCOVERED HD1K MEDIA LD (DIOMED_SPS), BC ; STORE IT ; ; CAPTURE THE LBA OFFSET AND SECTOR COUNT FROM PARTITION ; HL POINTS TO PART LBA OFFSET FIELD OF PART ENTRY LD DE,DIOMED_LBAOFF ; LOC TO STORE OFFSET AND SIZE LD BC,8 ; 8 BYTES - LBA OFFSET AND SIZE LDIR ; COPY IT ; JR SYS_GETDIOMED4A ; CONTINUE AND COMPUTE THE SLICE ; SYS_GETDIOMED3C: ; NO PARTITION TABLE FOUND / NO CPM PARTITION FOUND -> HD512 LD A, MID_HD ; HD512 MEDIA LD (DIOMED_MID), A ; STORE IT LD BC, SPS_HD512 ; WITH HD512 SECTORS PER SLICE LD (DIOMED_SPS), BC ; STORE IT ; DID WE FIND AN OTHER (NOT CPM) PARTITION LD A,(DIOMED_FND) ; HAVE WE ALREADY FOUND PROCESSED NON CPM OR A ; PARTITION, AND CAPTURED ITS START SECTOR, SO JR NZ,SYS_GETDIOMED4A ; MEDIA SIZE IS KNOWN BASED ON START OF PARTITION ; FIND THE PHYSICAL CAPCITY OF THE MEDIA CALL (DIOCAP) LD B, BF_DIOCAP ; HBIOS FUNC: TO GET DISK LBA CAPACITY LD A, (DIOMED_UNIT) LD C, A ; PUT DISK UNIT IN C FOR FUNC CALL CALL DIO_DISPATCH ; DO IT - RETURNS SIZE in DE:HL RET NZ ; ABORT ON ERROR ; UPDATE LBA SIZE FROM MEDIA SIZE LD (DIOMED_LBASIZ), HL ; LOWER ORDER BYTES - HL EX DE,HL LD (DIOMED_LBASIZ+2), HL ; HIGHER ORDER BYTES - DE ; SYS_GETDIOMED4A: ; COMPUTE THE START SECTOR (RELATIVE) FOR SLICE -> DE:HL LD HL,0 ; STARTING SECTOR NUMBER LD DE,0 ; ASSUMING A 0 OFFSET, SO CAN COMPARE TO SIZE LD BC,(DIOMED_SPS) ; LD A,(DIOMED_SLICE) OR A ; SLICE NUMBER - SET FLAGS TO CHECK LOOP CTR JR Z,SYS_GETDIOMED5A ; NOTHING TO COUNT SYS_GETDIOMED4B: ADD HL,BC ; ADD ONE SLICE (SPS) TO LOW WORD JR NC,SYS_GETDIOMED4C ; CHECK FOR CARRY INC DE ; IF SO, BUMP HIGH WORD SYS_GETDIOMED4C: DEC A ; DEC LOOP (SLICE) COUNTER JR NZ,SYS_GETDIOMED4B ; AND LOOP ; SYS_GETDIOMED5A: ; DE:HL NOW CONTAINS THE STARTING SECTOR FOR SLICE PUSH HL ; SAVE THE SECTOR OFFSET (SPS * SLICE NUMBER) PUSH DE ; ADD HL, BC ; ADD SPS, GET REQUIRED CAPCITY (UPPER SECTOR) JR NC, SYS_GETDIOMED5B INC DE SYS_GETDIOMED5B: ; DEHL HAS THE REQUIRED NUMBER OF SECTORS (ON MEDIA) FOR THE SLICE PUSH DE ; SAVE DSK_REQ (MSW) PUSH HL ; SAVE DSK_REQ (LSW) ; ; CHECK DSK_CAPACITY >= CAP_REQUIRED, CF SET ON OVERFLOW ; NO NEED SAVE ACTUAL RESULT OR A ; CLEAR CARRY FOR SBC LD HL,(DIOMED_LBASIZ+0) ; CAPACITY LSW POP DE ; REQUIRED LSW SBC HL,DE ; CAPACITY - REQUIRED (LSW) LD HL,(DIOMED_LBASIZ+2) ; CAPAITY MSW POP DE ; REQUIRED MSW SBC HL,DE ; CAPACITY - REQUIRED (MSW) ; ; POP STARTING OFSETT SECTOR POP DE POP HL ; ; REQUIRE - CAPACITY -> GENERATES BORROW IF CAPITY > REQUIREMENT JR NC,SYS_GETDIOMED6 ; IF WE HAVE ENOUGH CAPACITY ; SYS_GETDIOMED5C: ; SLICE WONT FIT - STOP AND RETURN ERROR LD DE,0 LD HL,0 ; EMTY OFFSET IN DEHL LD A,(DIOMED_DEVATT) LD B,A ; DEVICE ATTRIBUTES IN B LD A,(DIOMED_MID) LD C,A ; RETURN MEDIA ID IN C LD A,ERR_RANGE ; OTHERWISE SIGNAL NOT ENOUGH CAPACITY OR A RET ; SYS_GETDIOMED6: ; FINAL CALC AND RETURN SUCCESS ; ADD PARTITION OFFSET (START) TO DEHL TO GET ABSOLUTE SLICE OFFSET LD BC,(DIOMED_LBAOFF+0) ; LSB OF LBA OFFSET ADD HL,BC ; ADD LSB OFFSET EX DE,HL ; FLIP DE INTO HL LD BC,(DIOMED_LBAOFF+2) ; MSB OF LBA OFFSET ADC HL,BC ; ADD MSB EX DE, HL ; FLIP BACK DE:HL AS SLICE OFFSET ; SYS_GETDIOMED6A: ; SLICE FITS - RETURN CORRECTLY LD A,(DIOMED_DEVATT) LD B,A ; DEVICE ATTRIBUTES IN B LD A,(DIOMED_MID) LD C,A ; RETURN MEDIA ID IN C XOR A ; CLEAR FLAGS RET ; RETUNING DE:HL AND C ; ; GET RTC UNIT COUNT ; SYS_GETRTCCNT: LD E,0 ; ASSUME 0 RTC DEVICES LD A,(RTC_DISPACT) ; IS RTC ACTIVE? OR A ; SET FLAGS JR Z,SYS_GETRTCCNT1 ; IF NONE, DONE INC E ; SET ONE DEVICE SYS_GETRTCCNT1: XOR A ; SIGNALS SUCCESS RET ; ; GET DSKY UNIT COUNT ; SYS_GETDSKYCNT: LD E,0 ; ASSUME 0 RTC DEVICES LD A,(DSKY_DISPACT) ; IS DSKY ACTIVE? OR A ; SET FLAGS JR Z,SYS_GETDSKYCNT1 ; IF NONE, DONE INC E ; SET ONE DEVICE SYS_GETDSKYCNT1: 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 ; ; GET VIDEO UNIT API FN ADR AND DATA ADR ; ENTRY: ; D: FUNCTION ; E: UNIT ; RETURNS: ; HL: FUNCTION ADDRESS ; DE: DATA BLOB ADDRESS ; SYS_GETVDAFN: LD IY,VDA_TBL ; POINT TO UNIT TABLE JP SYS_GETFN ; GO TO COMMON CODE ; ; GET SOUND UNIT COUNT ; SYS_GETSNDCNT: LD A,(SND_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) LD E,A ; PUT IT IN E XOR A ; SIGNALS SUCCESS RET ; ; GET SOUND UNIT API FN ADR AND DATA ADR ; ENTRY: ; D: FUNCTION ; E: UNIT ; RETURNS: ; HL: FUNCTION ADDRESS ; DE: DATA BLOB ADDRESS ; SYS_GETSNDFN: LD IY,SND_TBL ; POINT TO UNIT TABLE JP SYS_GETFN ; GO TO COMMON CODE ; ; SHARED CODE TO COMPLETE A FUNCTION LOOKUP ; ENTRY: ; IY: DISPATCH FUNCTION TABLE ; D: FUNCTION ID ; E: UNIT NUMBER ; EXIT: ; HL: DRIVER FUNCTION ADDRESS ; DE: DRIVER UNIT DATA ADDRESS ; SYS_GETFN: LD A,D ; GET FUNC NUM FROM D LD B,A ; AND PUT IN B LD A,E ; GET UNIT NUM FROM E LD C,A ; AND PUT IN C CALL HB_DISPCALC ; CALC FN ADR & BLOB ADR PUSH IY ; MOVE DATA ADR POP DE ; ... TO DE RET ; AF STILL HAS RESULT OF CALC ; #IF ((CPUFAM == CPU_EZ80) & (EZ80TIMER == EZ80TMR_FIRM)) ; IMPLEMENTED IN EZ80DRV.ASM ; #ELSE ; ; GET TIMER ; RETURNS: ; DE:HL: TIMER VALUE (32 BIT) ; SYS_GETTIMER: LD HL,HB_TICKS HB_DI CALL LD32 HB_EI LD C, TICKFREQ XOR A RET #ENDIF ; #IF ((CPUFAM == CPU_EZ80) & (EZ80TIMER == EZ80TMR_FIRM)) ; IMPLEMENTED IN EZ80DRV.ASM ; #ELSE ; ; 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,TICKFREQ LD C,A XOR A RET #ENDIF ; ; 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) LD BC,(HB_CPUOSC) XOR A RET ; ; GET MEMORY INFORMATION ; RETURNS: ; D: COUNT OF ROM BANKS ; E: COUNT OF RAM BANKS ; SYS_GETMEMINFO: LD A,(CB_ROMBANKS) LD D,A LD A,(CB_RAMBANKS) LD E,A XOR A RET ; ; GET BANK CONFIGURATION INFORMATION ; RETURNS: ; D: HBIOS BANK ID ; E: USER BANK ID ; H: FIRST APP BANK ID ; L: APP BANK COUNT ; SYS_GETBNKINFO: LD A,(CB_BIDBIOS) LD D,A LD A,(CB_BIDUSR) LD E,A XOR A RET ; ; GET SYSTEM CPU SPEED PERFORMANCE ATTRIBUTES ; RETURNS: ; L: CLOCK MULT (0:HALF, 1:FULL, 2: DOUBLE) ; D: MEMORY WAIT STATES ; E: I/O WAIT STATES ; SYS_GETCPUSPD: ; #IF (((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) & (CPUSPDCAP==SPD_HILO)) LD A,(HB_RTCVAL) #IF (PLATFORM == PLT_SBC) XOR %00001000 ; SBC SPEED BIT IS INVERTED #ENDIF BIT 3,A LD L,0 ; ASSUME HALF SPEED JR Z,SYS_GETCPUSPD1 LD L,1 SYS_GETCPUSPD1: LD DE,$FFFF ; UNKNOWN WAIT STATES ; XOR A RET #ENDIF ; #IF (PLATFORM == PLT_HEATH) LD A,(H8P_SPEED) ; GET HEATH SPEED BITS SHADOW XOR $03 ; CONVERT TO HBIOS VALUE LD L,A ; PUT IN L FOR RETURN LD DE,$FFFF ; UNKNOWN WAIT STATES ; XOR A RET #ENDIF ; #IF (CPUFAM == CPU_Z180) LD HL,0 ; INIT CPU SPEED TO HALF LD A,(HB_CPUTYPE) ; LOAD CPUTYPE CP 2 ; S-CLASS OR ABOVE? JR C,SYS_GETCPUSPD1 ; IF NOT, NO CCR/CMR ; ; GET CCR BIT IN0 A,(Z180_CCR) ; GET CLOCK CONTROL RLCA ; ROTATE BIT TO BIT 0 AND %00000001 ; ISOLATE IT LD L,A ; SAVE IN L ; LD A,(HB_CPUTYPE) ; LOAD CPUTYPE CP 3 ; REV. N? JR C,SYS_GETCPUSPD1 ; IF NOT, NO CMR ; ; GET CMR BIT IN0 A,(Z180_CMR) ; GET CLOCK MULTIPLIER RLCA ; ROTATE BIT TO BIT 0 AND %00000001 ; ISOLATE IT LD H,A ; SAVE IN H ; SYS_GETCPUSPD1: ; CALC FINAL MULTIPLIER TO L XOR A ; CLEAR ACCUM ADD A,H ; ADD IN CMR BIT ADD A,L ; ADD IN CCR BIT LD L,A ; SAVE RESULT IN L ; DCNTL = MMII???? IN0 A,(Z180_DCNTL) ; GET WAIT STATES RLCA ; ROTATE MEM WS BITS RLCA ; ... TO LOW BITS PUSH AF ; SAVE FOR NOW AND %00000011 ; ISOLATE BITS LD D,A ; PUT IN D POP AF ; RECOVER A RLCA ; ROTATE I/O WS BITS RLCA ; ... TO LOW BITS AND %00000011 ; ISOLATE BITS INC A ; ADD 1 FOR BUILT-IN WS LD E,A ; PUT IN E ; XOR A RET #ENDIF ; OR $FF RET ; ; GET FRONT PANEL SWITCH VALUES BYTE ; RETURNS: ; L: SWITCH VALUES BYTE ; SYS_GETPANEL: ; #IF (FPSW_ENABLE) LD A,(FPSW_ACTIVE) ; FP SWITCHES ACTIVE? OR A ; SET FLAGS JR Z,SYS_GETPANEL1 ; HANDLE NOT EXISTS CALL FP_GETSWITCHES ; READ SWITCHES LD H,0 ; FOR FUTURE LD L,A ; PUT SWITCHES VALUE IN L XOR A ; SIGNAL SUCCESS RET ; DONE #ENDIF SYS_GETPANEL1: ; HANDLE NON-EXISTENT FRONT PANEL LD HL,0 ; ZERO RESULT VALUE LD A,ERR_NOHW ; NO HARDWARE ERR OR A ; SET FLAGS RET ; DONE ; ; GET APPLICATION BANK INFORMATION ; RETURNS: ; H: FIRST APP BANK ID ; L: APP BANK COUNT ; E: BANK SIZE (IN 256-BYTE PAGES) ; SYS_GETAPPBNKS: LD A,(CB_BIDAPP0) ; FIRST BANK ID LD H,A LD A,(CB_APP_BNKS) ; NUMBER OF BANKS LD L,A LD E,$80 ; (256 * $80) = 32KB ; XOR A RET ; ;-------------------------------------------------------------------------------------------------- ; SET SYSTEM PARAMETERS ;-------------------------------------------------------------------------------------------------- ; ; SET SYSTEM PARAMETERS ; PARAMETER(S) TO SET INDICATED IN C ; SYS_SET: LD A,C ; GET REQUESTED SUB-FUNCTION CP BF_SYSSET_TIMER JP Z,SYS_SETTIMER CP BF_SYSSET_SECS JP Z,SYS_SETSECS CP BF_SYSSET_BOOTINFO JP Z,SYS_SETBOOTINFO CP BF_SYSSET_CPUSPD JP Z,SYS_SETCPUSPD CP BF_SYSSET_PANEL JP Z,SYS_SETPANEL SYSCHKERR(ERR_NOFUNC) ; 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 ; #IF ((CPUFAM == CPU_EZ80) & (EZ80TIMER == EZ80TMR_FIRM)) ; IMPLEMENTED IN EZ80DRV.ASM ; #ELSE ; ; 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 #ENDIF #IF ((CPUFAM == CPU_EZ80) & (EZ80TIMER == EZ80TMR_FIRM)) ; IMPLEMENTED IN EZ80DRV.ASM ; #ELSE ; ; 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 #ENDIF ; ; SET SYSTEM CPU SPEED ATTRIBUTES ; ON ENTRY: ; L: CLOCK MULT (0:HALF, 1:FULL, 2: DOUBLE, 3: QUAD) ; D: MEMORY WAIT STATES ; E: I/O WAIT STATES ; SYS_SETCPUSPD: ; #IF (((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) & (CPUSPDCAP==SPD_HILO)) ; ; NOTE: WAIT STATE SETTINGS ARE IGNORED FOR Z80 ; LD A,L ; CLK SPD TO ACCUM CP $FF ; NO CHANGE? JR Z,SYS_SETCPUSPD3 ; DONE IF SO LD C,%00000000 ; HALF SPEED CP 0 JR Z,SYS_SETCPUSPD1 LD C,%00001000 ; FULL SPEED CP 1 JR Z,SYS_SETCPUSPD1 JR SYS_SETCPUSPD_ERR ; SPD NOT SUPPORTED SYS_SETCPUSPD1: LD A,(HB_RTCVAL) AND ~%00001000 ; CLEAR SPEED BIT OR C ; IMPLEMENT NEW SPEED BIT #IF (PLATFORM == PLT_SBC) ; SBC SPEED BIT IS INVERTED, ADJUST IT LD A,C XOR %00001000 LD C,A #ENDIF LD (HB_RTCVAL),A ; SAVE IN SHADOW REGISTER OUT (RTCIO),A ; UPDATE HARDWARE REGISTER ; ; UPDATE THE CURRENT CPU SPEED IN HCB! LD A,L LD HL,(HB_CPUOSC) ; ASSUME FULL SPEED CP 1 ; CHECK FOR 1 (FULL SPEED) JR Z,SYS_SETCPUSPD2 ; IF SO, ALL DONE ; ADJUST HL TO REFLECT HALF SPEED OPERATION SRL H ; ADJUST HL ASSUMING RR L ; HALF SPEED OPERATION ; SYS_SETCPUSPD2: ; ; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ. ; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE. ; LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER LD DE,500 ; SET UP TO ROUND UP XOR A ; IF WITHIN 500 KHZ SBC HL,DE ; REMAINDER - 500 CCF ; COMPLEMENT CF ADC A,C ; C -> A; ADD CF FOR ROUNDING LD (CB_CPUMHZ),A ; SAVE IT ; #IF (CPUFAM != CPU_EZ80) ; REINIT DELAY ROUTINE LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY #ENDIF ; SYS_SETCPUSPD3: XOR A RET #ENDIF ; #IF (PLATFORM == PLT_HEATH) ; PORT $30: ; 0=16MHZ, 1=8MHZ, 2=4MHZ, 3=2MHZ LD A,L ; REQUESTED SPEED TO ACCUM XOR $03 ; CONVERT TO HEATH BITS AND $03 ; ONLY 2 LS BITS ; H8P_SETSPD: ; INVOKED BY H8P.ASM WHEN SPEED CHANGED VIA FRONT PANEL OUT (H8P_SPDIO),A ; DO IT LD (H8P_SPEED),A ; UPDATE FP SHADOW ; ; UPDATE CPUKHZ/CPMHZ LD HL,(HB_CPUOSC) ; START WITH OSC VALUE IN KHZ LD B,A ; USE BITS FOR LOOP COUNT OR A ; CHECK FOR ZERO JR Z,SYS_SETCPUSPD2 ; IF SO, SKIP ADJUSTMENT LOOP SYS_SETCPUSPD1: SRL H ; DIVIDE RR L ; ... BY TWO DJNZ SYS_SETCPUSPD1 ; LOOP AS NEEDED ; SYS_SETCPUSPD2: ; ; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ. ; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE. ; LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER LD DE,500 ; SET UP TO ROUND UP XOR A ; IF WITHIN 500 KHZ SBC HL,DE ; REMAINDER - 500 CCF ; COMPLEMENT CF ADC A,C ; C -> A; ADD CF FOR ROUNDING LD (CB_CPUMHZ),A ; SAVE IT ; #IF (CPUFAM != CPU_EZ80) ; REINIT DELAY ROUTINE LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY #ENDIF ; XOR A ; SIGNAL SUCCESS RET #ENDIF ; #IF (CPUFAM == CPU_Z180) ; VERIFY THAT REQUESTED SETTINGS ARE ALLOWED BY HARDWARE LD A,L ; GET SPEED REQUESTED CP $FF ; NO CHANGE? JR Z,SYS_SETCPUSPD0A ; SKIP CHECK LD A,(HB_CPUTYPE) ; 1=ORIG, 2=REVK, 3=REVN INC L ; 1=HALF,2=FULL,3=DOUBLE CP L ; TOO HIGH FOR CPU TYPE? JP C,SYS_SETCPUSPD_ERR ; CPU CAN'T DO SPD MULT DEC L ; RESTORE ORIG REQUEST SYS_SETCPUSPD0A: LD A,D ; MEM WS CP $FF ; NO CHANGE? JR Z,SYS_SETCPUSPD0B ; SKIP CHECK CP 4 ; TOO HIGH? JP NC,SYS_SETCPUSPD_ERR ; >3 IS TOO HIGH SYS_SETCPUSPD0B: LD A,D ; I/O WS CP $FF ; NO CHANGE? JR Z,SYS_SETCPUSPD0C ; SKIP CHECK CP 4 ; TOO HIGH? JP NC,SYS_SETCPUSPD_ERR ; >3 IS TOO HIGH SYS_SETCPUSPD0C: ; PUSH DE ; SAVE WAIT STATES FOR NOW ; BEFORE IMPLEMENTING THE NEW CPU SPEED, WE SWITCH THE ; WAIT STATES TO MAXIMUM BECAUSE WE MAY BE IMPLEMENTING ; SLOWER WAIT STATES REQUIRED BY THE NEW SPEED. WE SAVE ; THE ORIGINAL WAIT STATES REGISTER VALUE ON STACK IN0 A,(Z180_DCNTL) ; GET CURRENT REGISTER VALUE LD E,A ; PUT IN E PUSH DE ; SAVE FOR LATER OR %11110000 ; MAX WAIT STATES OUT0 (Z180_DCNTL),A ; DO IT ; LD A,L ; NEW CLK SPD TO ACCUM CP $FF ; NO CHANGE? JR Z,SYS_SETCPUSPD2B ; IF SO, SKIP TO WAIT STATES ; LD B,0 ; B HAS BIT FOR CMR LD C,0 ; C HAS BIT FOR CCR CP 2 ; DOUBLE SPEED? JR C,SYS_SETCPUSPD1 ; <2?, SKIP AHEAD LD B,%10000000 ; SET CMR BIT SYS_SETCPUSPD1: CP 1 ; FULL SPEED? JR C,SYS_SETCPUSPD2 ; <1?, SKIP AHEAD LD C,%10000000 ; SET CCR BIT SYS_SETCPUSPD2: ; ; IMPLEMENT THE NEW CPU SPEED IN0 A,(Z180_CMR) AND ~%10000000 OR B OUT0 (Z180_CMR),A IN0 A,(Z180_CCR) AND ~%10000000 OR C OUT0 (Z180_CCR),A ; ; UPDATE THE CURRENT CPU SPEED IN HCB! LD A,L ; SETTING TO A LD HL,(HB_CPUOSC) ; START WITH CPU OSC VALUE ; ADJUST HL TO REFLECT HALF SPEED OPERATION SRL H ; ADJUST HL ASSUMING RR L ; HALF SPEED OPERATION OR A ; CHECK FOR HALF SPEED JR Z,SETCPUSPD2A ; IF SO, DONE ; ADJUST HL TO REFLECT FULL SPEED OPERATION SLA L RL H CP 1 ; CHECK FOR FULL SPEED JR Z,SETCPUSPD2A ; IF SO DONE ; ADJUST HL TO REFLECT DOUBLE SPEED OPERATION SLA L RL H ; SETCPUSPD2A: ; ; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ. ; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE. ; LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER LD DE,500 ; SET UP TO ROUND UP XOR A ; IF WITHIN 500 KHZ SBC HL,DE ; REMAINDER - 500 CCF ; COMPLEMENT CF ADC A,C ; C -> A; ADD CF FOR ROUNDING LD (CB_CPUMHZ),A ; SAVE IT ; SYS_SETCPUSPD2B: ; NOW IMPLEMENT ANY WAIT STATE CHANGES. POP HL ; INIT L WITH ORIG DCNTL VALUE POP DE ; RECOVER WAIT STATES LD A,D ; GET MEM WS CP $FF ; SKIP? JR Z,SYS_SETCPUSPD3 ; IF SO, GO AHEAD AND %00000011 ; JUST TWO BITS RRCA ; MEM WS IS TOP TWO BITS RRCA LD H,A ; MOVE WS BITS TO H LD A,L ; CUR VALUE TO A AND %00111111 ; MASK OFF MEM WS BITS OR H ; SET NEW MEM WS BITS LD L,A ; BACK TO L ; SYS_SETCPUSPD3: ; LD A,E ; GET I/O WS CP $FF ; SKIP? JR Z,SYS_SETCPUSPD4 ; IF SO, GO AHEAD DEC A ; ADJUST FOR BUILT-IN I/O WS AND %00000011 ; JUST TWO BITS RRCA ; I/O WS IS BITS 5-4 RRCA RRCA RRCA LD H,A ; MOVE WS BITS TO H LD A,L ; CUR VALUE TO A AND %11001111 ; MASK OFF I/O WS BITS OR H ; SET NEW I/O WS BITS LD L,A ; BACK TO L ; SYS_SETCPUSPD4: LD A,L ; WORKING VALUE TO A OUT0 (Z180_DCNTL),A ; IMPLEMENT NEW VALUE ; #IF (CPUFAM != CPU_EZ80) ; REINIT DELAY ROUTINE LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY #ENDIF ; #IF ((INTMODE == 2) & (Z180_TIMER)) ; THE Z180 TIMER IS BASED ON CPU SPEED. SO HERE ; WE RECOMPUTE THE TIMER CONSTANTS BASED ON THE NEW SPEED. XOR A ; ALL BITS ZERO OUT0 (Z180_TCR),A ; ... INHIBITS TIMER OPERATION 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 ; #IF (ASCIENABLE) ; RESET THE ASCI PORTS IN CASE SPEED CHANGED! ; N.B., THIS WILL FAIL IF THE CURRENT BAUD RATE ; IS IMPOSSIBLE TO IMPLEMENT AT THE NEW CPU SPEED!!! LD DE,-1 LD IY,ASCI0_CFG CALL ASCI_INITDEV LD DE,-1 LD IY,ASCI1_CFG CALL ASCI_INITDEV #ENDIF ; XOR A RET #ENDIF ; SYS_SETCPUSPD_ERR: OR $FF ; NOT SUPPORTED RET ; ; SET FRONT PANEL LEDS ; ON ENTRY: ; L: LED VALUES BYTE ; SYS_SETPANEL: ; #IF (FPLED_ENABLE) LD A,L CALL FP_SETLEDS XOR A RET #ELSE LD A,ERR_NOHW ; NO HARDWARE ERR OR A ; SET FLAGS RET #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; INTERBANK MEMORY PEEK ;-------------------------------------------------------------------------------------------------- ; ; RETURN A BYTE OF MEMORY FROM SPECIFIED BANK ; ENTRY: D=BANK ID, HL=ADDRESS ; RETURN: E=BYTE VALUE ; ; IF WE ARE USING INTERRUPT MODE 1, WE NEED TO PREVENT INTERRUPTS ; BECAUSE THE LOW MEMORY BANK CONTAINING THE IM1 VECTOR WILL PROBABLY ; GET BANKED OUT DURING THE PEEK PROCESSING. ; SYS_PEEK: #IF (INTMODE == 1) #IF (CPUFAM == CPU_Z280) PUSH IY LD C,Z280_MSR LDCTL IY,(C) PUSH IY HB_DI #ELSE LD A,I ; SAVE THE INTERRUPT STATUS DI ; COPY IFF2 TO P/V FLAG PUSH AF #ENDIF #ENDIF CALL HBX_PEEK ; IMPLEMENTED IN PROXY #IF (INTMODE == 1) #IF (CPUFAM == CPU_Z280) LD C,Z280_MSR POP IY LDCTL (C),IY POP IY #ELSE POP AF ; RECALL INITIAL INTERRUPT STATUS JP PO,$+4 ; RETURN TO INITIAL STATE EI ; *** DO NOT USE HB_EI HERE *** #ENDIF #ENDIF XOR A RET ; ;-------------------------------------------------------------------------------------------------- ; INTERBANK MEMORY POKE ;-------------------------------------------------------------------------------------------------- ; ; WRITE A BYTE OF MEMORY TO SPECIFIED BANK ; ENTRY: D=BANK ID, HL=ADDRESS IN HBIOS BANK, E=BYTE VALUE ; ; IF WE ARE USING INTERRUPT MODE 1, WE NEED TO PREVENT INTERRUPTS ; BECAUSE THE LOW MEMORY BANK CONTAINING THE IM1 VECTOR WILL PROBABLY ; GET BANKED OUT DURING THE POKE PROCESSING. ; SYS_POKE: #IF (INTMODE == 1) #IF (CPUFAM == CPU_Z280) PUSH IY LD C,Z280_MSR LDCTL IY,(C) PUSH IY HB_DI #ELSE LD A,I ; SAVE THE INTERRUPT STATUS HB_DI ; COPY IFF2 TO P/V FLAG PUSH AF #ENDIF #ENDIF CALL HBX_POKE ; IMPLEMENTED IN PROXY #IF (INTMODE == 1) #IF (CPUFAM == CPU_Z280) LD C,Z280_MSR POP IY LDCTL (C),IY POP IY #ELSE POP AF ; RECALL INITIAL INTERRUPT STATUS JP PO,$+4 ; RETURN TO INITIAL STATE EI ; *** DO NOT USE HB_EI HERE *** #ENDIF #ENDIF XOR A RET ; ;-------------------------------------------------------------------------------------------------- ; INTERRUPT MANAGEMENT FUNCTIONS ;-------------------------------------------------------------------------------------------------- ; ; 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 SYSCHKERR(ERR_NOFUNC) ; 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) | (INTMODE == 3)) 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) SYSCHKERR(ERR_BADCFG) ; SIGNAL ERROR. INVALID FOR INT MODE 0 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) | (INTMODE == 3)) 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 SYSCHKERR(ERR_RANGE) ; ELSE ERROR 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 #IF (INTMODE == 1) LD DE,HB_IM1INT ; DE := START OF VECTOR TABLE #ENDIF #IF ((INTMODE == 2) | (INTMODE == 3)) LD DE,HB_IVT ; DE := START OF VECTOR TABLE #ENDIF 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 ; 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 XOR A ; SIGNAL SUCCESS RET ; DONE ; HB_SYSAPI_END .EQU $ ; ;================================================================================================== ; GLOBAL INTERNAL HBIOS FUNCTIONS ;================================================================================================== ; HB_INTFUNC_BEG .EQU $ ; ;-------------------------------------------------------------------------------------------------- ; PRINT DECIMAL VALUE WITH 3 DIGIT MANTISSA ;-------------------------------------------------------------------------------------------------- ; ; 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 ; ;-------------------------------------------------------------------------------------------------- ; INITIALIZATION VECTOR PROCESSING SUPPORT ;-------------------------------------------------------------------------------------------------- ; ; 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 ; ;-------------------------------------------------------------------------------------------------- ; GLOBAL IDLE PROCESSING ;-------------------------------------------------------------------------------------------------- ; ; GLOBAL HBIOS IDLE PROCESSING IS DONE HERE. THIS ROUTINE SHOULD ; BE CALLED WHENEVER WAITING FOR USER INPUT. ; 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 ; ; 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 ; ; 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 ; ;-------------------------------------------------------------------------------------------------- ; CHS TO LBA CONVERSION ;-------------------------------------------------------------------------------------------------- ; ; 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 ; ;-------------------------------------------------------------------------------------------------- ; SYSTEM CHECK / PANIC ;-------------------------------------------------------------------------------------------------- ; ; SYSTEM CHECK: DUMP MACHINE STATE AND CONTINUE? ; SYSCHKA: ; CHECK DIAG LEVEL TO SEE IF WE SHOULD DISPLAY PUSH AF ; PRESERVE INCOMING AF VALUE LD A,(CB_DIAGLVL) ; GET DIAGNOSTIC LEVEL CP DL_ERROR ; >= ERROR LEVEL JR C,SYSCHK1 ; IF NOT, GO HOME POP AF ; RESTORE INCOMING AF VALUE ; ; DISPLAY SYSCHK MESSAGE PUSH DE ; PRESERVE DE VALUE LD DE,STR_SYSCHK ; POINT TO PREFIX STRING CALL WRITESTR ; PRINT IT POP DE ; RESTORE DE VALUE CALL XREGDMP ; DUMP REGISTERS ; DISPLAY ERROR CODE. IT IS AT RETURN ADDRESS+1 .. LD A,XX EX (SP),HL ; GET RETURN ADDRESS INC HL ; POINT TO THE ERROR CODE PUSH AF LD A,(HL) ; DISPLAY CALL PRTHEXBYTE POP AF DEC HL ; RESTORE RETURN ADDRESS EX (SP),HL ; JR CONTINUE ; CHECK W/ USER ; SYSCHK1: ; RETURN IF MESSAGING BYPASSED BY DIAG LEVEL POP AF RET ; CONTINUE: PUSH AF CONTINUE1: PUSH DE LD DE,STR_CONTINUE CALL WRITESTR POP DE CALL CIN RES 5,A ; FORCE UPPERCASE (IMPERFECTLY) CALL COUT ; ECHO CP 'Y' JR Z,CONTINUE3 CP 'N' JR Z,SYSHALT JR CONTINUE1 CONTINUE3: CALL NEWLINE POP AF RET ; ; PANIC: DUMP MACHINE STATE AND HALT ; PANIC: PUSH DE LD DE,STR_PANIC CALL WRITESTR POP DE CALL XREGDMP ; DUMP REGISTERS JR SYSHALT ; FULL STOP ; ; ISSUE MESSAGE AND HALT SYSTEM ; SYSHALT: LD DE,STR_HALT CALL WRITESTR DI HALT ; ;-------------------------------------------------------------------------------------------------- ; INTERRUPT MANAGEMENT SUPPORT ;-------------------------------------------------------------------------------------------------- ; #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 ; #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; SYSTEM TIMER INTERRUPT HANDLER ;-------------------------------------------------------------------------------------------------- ; HB_TIMINT: ; #IF FALSE ; *DEBUG* LD HL,HB_TIMDBGCNT INC (HL) LD A,(HL) OUT (DIAGPORT),A JR HB_TIMDBG1 HB_TIMDBGCNT .DB 0 HB_TIMDBG1: #ENDIF ; *DEBUG* ; ; TIMER HANDLER VECTORS ; THESE CAN BE HOOKED AS DESIRED BY DRIVERS ; VEC_TICK: JP HB_TICK ; TICKS PROCESSING VECTOR VEC_SECOND: JP HB_SECOND ; SECONDS PROCESSING VECTOR ; ; TIMER HANDLERS ; HB_TICK: ; INCREMENT TICK COUNTER (32 BIT) LD HL,HB_TICKS ; POINT TO TICK COUNTER CALL INC32HL LD HL,HB_SECTCK ; POINT TO SECONDS TICK COUNTER DEC (HL) ; COUNTDOWN ONE SECOND OF TICKS JR NZ,HB_TICK1 ; NOT DONE, SKIP AHEAD LD A,TICKFREQ ; TICKS PER SECOND LD (HL),A ; RESET COUNTDOWN REGISTER CALL VEC_SECOND ; DO SECONDS PROCESSING VIA VECTOR ; HB_TICK1: ; #IF (CPUFAM == CPU_Z180) ; ACK/RESET Z180 TIMER INTERRUPT IN0 A,(Z180_TCR) IN0 A,(Z180_TMDR0L) #ENDIF ; #IF (WDOGMODE != WDOG_NONE) ; PULSE WATCHDOG OUT (WDOGIO),A ; VALUE IS IRRELEVANT #ENDIF ; #IF MKYENABLE CALL MKY_INT #ENDIF ; OR $FF ; NZ SET TO INDICATE INT HANDLED RET ; HB_SECOND: ; INCREMENT SECONDS COUNTER LD HL,HB_SECS ; POINT TO SECONDS COUNTER JP INC32HL ; INCREMENT AND RETURN ; ; BAD INTERRUPT HANDLER ; HB_BADINT: #IF FALSE ; *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 NEWLINE ;CALL CONTINUE OR $FF ; SIGNAL INTERRUPT HANDLED RET ; ;-------------------------------------------------------------------------------------------------- ; API FUNCTION DISPATCH SUPPORT ;-------------------------------------------------------------------------------------------------- ; ; ON ENTRY B IS API FUNCTION NUMBER AND 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: PUSH HL ; SAVE INCOMING HL VALUE CALL HB_DISPCALC ; IY = BLOB ADR, HL = FN ADR JR NZ,HB_DISPCALL1 ; ABORT ON ERROR EX (SP),HL ; RESTORE HL & FN ADR TO TOS RET ; JUMP TO FN ADR HB_DISPCALL1: POP HL ; RECOVER HL RET ; AND DONE ; ; ENTRY: BC=FUNC/UNIT, IY=DISPATCH TABLE ; EXIT: HL=FUNC ADR, IY=DATA BLOB ADR ; HB_DISPCALC: ; CHECK INCOMING UNIT INDEX IN C FOR VALIDITY LD A,C ; A := INCOMING DISK UNIT INDEX CP (IY-1) ; COMPARE TO COUNT JR NC,HB_UNITERR ; 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_FUNCERR ; 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 PUSH HL ; SAVE FUNC ADR 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 XOR A ; SIGNAL SUCCESS RET ; JUMP TO DRIVER FUNC ADR ON TOS ; HB_FUNCERR: SYSCHKERR(ERR_NOFUNC) ; SIGNAL ERROR RET ; HB_UNITERR: SYSCHKERR(ERR_NOUNIT) ; SIGNAL ERROR RET ; ; 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 ; ;-------------------------------------------------------------------------------------------------- ; HEAP MEMORY ALLOCATION ;-------------------------------------------------------------------------------------------------- ; ; 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 MEMORY ALLOCATED (DOES NOT INCLUDE 4 BYTE HEADER) ; - DWORD: ADDRESS WHERE ALLOC WAS CALLED (VALUE ON TOP OF STACK AT CALL) ; HB_ALLOC: ; #IFDEF MEMDBG CALL PRTSTRD .TEXT "\r\n>>> ALLOC SIZE=0x$") CALL PRTHEXWORDHL #ENDIF ; ; 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 ; #IFDEF MEMDBG CALL PRTSTRD .TEXT " TOP=0x$") CALL PRTHEXWORDHL #ENDIF ; ; 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 SYSCHKERR(ERR_NOMEM) ; SIGNAL ERROR RET ; HB_TMPSZ .DW 0 HB_TMPREF .DW 0 ; ;-------------------------------------------------------------------------------------------------- ; Z280 SUPPORT ROUTINES ;-------------------------------------------------------------------------------------------------- ; ; Z280 SYSTEM TIMER INTERRUPT HANDLER ; #IF (MEMMGR == MM_Z280) ; Z280_TIMINT: ; DISCARD REASON CODE INC SP INC SP ; ; SAVE INCOMING REGISTERS PUSH AF PUSH BC PUSH DE PUSH HL ; ; CALL PRIMARY TIMER LOGIC ON EVERY OTHER INT LD A,(Z280_TIMCTR) XOR $FF LD (Z280_TIMCTR),A CALL Z,HB_TIMINT ; ; SELECT I/O PAGE $FE (SAVING PREVIOUS VALUE) LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER LDCTL HL,(C) ; GET CURRENT I/O PAGE PUSH HL ; SAVE IT LD L,$FE ; NEW COUNTER/TIMER I/O PAGE LDCTL (C),HL ; ; CLEAR END OF COUNT CONDITION TO RESET INTERRUPT IN A,(Z280_CT0_CMDST) ; GET STATUS RES 1,A ; CLEAR CC OUT (Z280_CT0_CMDST),A ; SET C/T 0 ; ; RESTORE I/O PAGE LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER POP HL ; RECOVER ORIGINAL I/O PAGE LDCTL (C),HL ; ; RESTORE REGISTERS POP HL POP DE POP BC POP AF ; RETIL ; Z280_TIMCTR .DB 0 ; USED TO DIVIDE TIMER INTS ; #ENDIF ; #IF (MEMMGR == MM_Z280) ; Z280_BADINT: ; SAVE REASON CODE FOR POSSIBLE RETURN VIA RETIL EX (SP),HL ; GET MSR, SAVE HL LD (HB_RCSAV),HL ; SAVE IT POP HL ; RECOVER HL, POP STACK ; SAVE MSR FOR POSSIBLE RETURN VIA RETIL EX (SP),HL ; GET MSR, SAVE HL LD (HB_MSRSAV),HL ; SAVE IT POP HL ; RECOVER HL, POP STACK ; PUSH DE LD DE,Z280_BADINTSTR CALL NEWLINE2 PRTS("+++ $") CALL WRITESTR POP DE CALL XREGDMP ; ; RECOVER MSR, THEN RETURN VIA RETIL PUSH HL ; SAVE HL LD HL,(HB_RCSAV) ; GET SAVED REASON CODE PRTS(" RC=$") CALL PRTHEXWORDHL ; DUMP MSR LD HL,(HB_MSRSAV) ; GET SAVED MSR PRTS(" MSR=$") CALL PRTHEXWORDHL ; DUMP MSR EX (SP),HL ; MSR TO STK, RECOVER HL ; RETIL ; RETURN FROM INT ; Z280_SSTEP: ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL EX (SP),HL ; GET MSR, SAVE HL LD (HB_MSRSAV),HL ; SAVE IT POP HL ; RECOVER HL, POP STACK ; PUSH DE LD DE,Z280_SSTEPSTR JP Z280_DIAG ; Z280_BRKHLT: ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL EX (SP),HL ; GET MSR, SAVE HL LD (HB_MSRSAV),HL ; SAVE IT POP HL ; RECOVER HL, POP STACK ; PUSH DE LD DE,Z280_BRKHLTSTR JP Z280_DIAG ; Z280_DIVEXC: ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL EX (SP),HL ; GET MSR, SAVE HL LD (HB_MSRSAV),HL ; SAVE IT POP HL ; RECOVER HL, POP STACK ; PUSH DE LD DE,Z280_DIVEXCSTR JP Z280_DIAG ; Z280_STKOVR: ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL EX (SP),HL ; GET MSR, SAVE HL LD (HB_MSRSAV),HL ; SAVE IT POP HL ; RECOVER HL, POP STACK ; PUSH DE LD DE,Z280_STKOVRSTR JP Z280_DIAG ; Z280_ACCVIO: ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL EX (SP),HL ; GET MSR, SAVE HL LD (HB_MSRSAV),HL ; SAVE IT POP HL ; RECOVER HL, POP STACK ; PUSH DE LD DE,Z280_ACCVIOSTR JP Z280_DIAG ; Z280_DIAG: CALL NEWLINE2 PRTS("+++ $") CALL WRITESTR POP DE CALL XREGDMP ; ; RECOVER MSR, THEN RETURN VIA RETIL PUSH HL ; SAVE HL LD HL,(HB_MSRSAV) ; GET SAVED MSR PRTS(" MSR=$") CALL PRTHEXWORDHL ; DUMP MSR EX (SP),HL ; MSR TO STK, RECOVER HL ; ;RETIL DI HALT ; Z280_BADINTSTR .TEXT "BAD INT $" Z280_SSTEPSTR .TEXT "SINGLE STEP $" Z280_BRKHLTSTR .TEXT "BREAK HALT $" Z280_DIVEXCSTR .TEXT "DIVISION EXCEPTION $" Z280_STKOVRSTR .TEXT "STACK OVERFLOW $" Z280_ACCVIOSTR .TEXT "ACCESS VIOLATION $" ; #ENDIF ; ; Z280 PRIVILEGED INSTRUCTION HANDLER ; #IF (MEMMGR == MM_Z280) ; Z280_PRIVINST: ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL EX (SP),HL ; GET MSR, SAVE HL LD (HB_MSRSAV),HL ; SAVE IT POP HL ; RECOVER HL, POP STACK EX (SP),HL ; GET ADR, SAVE HL ; PUSH AF PUSH BC ; NEEDED? PUSH DE ; NEEDED? ; LDUP A,(HL) ; BYTE FROM USER SPACE ; ; HANDLE USER MODE Z80 DI CP $F3 ; DI? JR NZ,Z280_PRIVINST2 ;;;HB_DI ; DO THE DI XOR A ; NO INTERRUPTS LD (HB_MSRSAV),A ; UPDATE SAVED MSR LSB INC HL ; BUMP PAST IT JR Z280_PRIVINSTX ; Z280_PRIVINST2: ; HANDLE USER MODE Z80 EI CP $FB ; EI? JR NZ,Z280_PRIVINST3 ;;;HB_EI ; DO THE EI LD A,$0B ; NORMAL INTERRUPTS LD (HB_MSRSAV),A ; UPDATE SAVED MSR LSB INC HL ; BUMP PAST IT JR Z280_PRIVINSTX ; Z280_PRIVINST3: ; SOMETHING ELSE, DIAGNOSE & HALT SYSTEM LD DE,Z280_PRIVSTR CALL WRITESTR CALL PRTHEXWORDHL ; ; DUMP 16 BYTES OF USER ADDRESS SPACE CALL PC_SPACE CALL PC_LBKT LD B,$10 Z280_PRIVINST4: LDUP A,(HL) ; BYTE FROM USER SPACE CALL PRTHEXBYTE INC HL DJNZ Z280_PRIVINST4 CALL PC_RBKT ; ; GO NO FURTHER DI HALT ; Z280_PRIVINSTX: ; RESTORE REGISTERS POP DE ; NEEDED? POP BC ; NEEDED? POP AF ; ; RECOVER HL AND MSR, THEN RETURN VIA RETIL EX (SP),HL ; RECOVER HL, ADR TO STK PUSH HL ; SAVE HL LD HL,(HB_MSRSAV) ; GET SAVED MSR EX (SP),HL ; MSR TO STK, RECOVER HL RETIL ; RETURN FROM INT ; HB_MSRSAV .DW 0 ; SAVED MSR HB_RCSAV .DW 0 ; SAVED REASON CODE ; Z280_PRIVSTR .TEXT "\r\n\r\n*** Privileged Instruction @$" ; #ENDIF ; ; Z280 BANK COPY (CALLED FROM PROXY) ; ; USE Z280 PHYSICAL MEMORY DMA COPY TO PERFORM AN INTERBANK COPY. ; COPY FROM (HB_SRCBNK):(HL) TO (HB_DSTBNK):(DE) FOR BC BYTES. BOTH ; HB_SRCBNK AND HB_DSTBNK MUST BE INITIALIZED PRIOR TO CALLING THIS ; ROUTINE. ; ; ADDRESSES ARE TRANSLATED FROM LOGICAL (Z80) TO PHYSICAL (Z280) TO ; SETUP THE DMA COPY PARAMETERS. IF THE SOURCE OR DESTINATION RANGE ; CROSSES OVER THE BANKED/COMMON BOUNDARY AT $8000, THEN SPECIAL STEPS ; MUST BE TAKEN BECAUSE THE BANKED AND COMMON AEAS ARE PROBABLY NOT ; SEQUENTIALLY LOCATED IN PHYSICAL MEMORY. TWO ENTRY POINTS ARE ; PROVIDED. Z280_BNKCPY IS MUCH FASTER, BUT DOES NOT ACCOUNT FOR THE ; COPY RANGES CROSSING OVER THE BANKED/COMMON BOUNDARY (WORKS GREAT ; FOR ANY COPY KNOWN TO STAY WITHIN IT'S OWN AREA). Z280_BNKCPYX ; WILL HANDLE COPIES WHERE THE SOURCE AND/OR DESTINATION RANGES ; CROSS OVER THE BANKED/COMMON MEMORY BOUNDARY. IT DOES THIS BY ; BREAKING UP THE COPY REQUESTS INTO MULTIPLE REQUESTS THAT ALL FIT ; WITHIN A SINGLE BANKED/COMMON MEMORY SEGMENT AND CALLING Z280_BNKCPY ; ITERATIVELY UNTIL THE COPY IS COMPLETE. ; ; THERE IS ESSENTIALLY NO PROTECTION FOR CALLING THESE ROUTINES WITH ; INVALID PARAMETERS. FOR EXAMPLE, A REQUEST TO COPY $2000 BYTES ; STARTING AT $F000 EXCEEDS THE SIZE OF THE Z80 MEMORY SPACES AND ; RESULTS IN UNDEFINED BEHAVIOR. ; ; THE COPY IS ALWAYS DONE FROM START TO END. IF THE SOURCE AND ; DESTINATION RANGES OVERLAP, THEN YOU MUST TAKE THIS INTO ACCOUNT. ; ; THE ROUTINE FUNCTIONS LOGICALLY LIKE THE Z80 LDIR INSTRUCTION. ON ; RETURN THE SOURCE (HL) AND DESTINATION (DE) REGISTERS WILL BE LEFT ; POINTING TO THE NEXT BYTE THAT WOULD BE COPIED IF THE COPY ROUTINE ; CONTINUED. BC WILL BE 0. AF IS UNDEFINED. ; #IF (MEMMGR == MM_Z280) ; ; ADJUST THE LENGTH OF THE COPY SUCH THAT BOTH THE SOURCE AND ; DESTINATION RANGES DO NOT CROSS OVER THE BANKED/COMMON MEMORY ; BOUNDARY. CALL Z280_BNKCPY TO DO AS MANY ITERATIONS AS NEEDED TO ; COMPLETE THE COPY. ; ; Z280_BNKCPYX: LD (Z280_BNKCPY_LEN),BC ; SAVE LENGTH ; CALL Z280_BNKCPY_XOVER ; ADJUST FOR XOVER AS NEEDED EX DE,HL ; SWAP SOURCE/DEST CALL Z280_BNKCPY_XOVER ; ADJUST FOR XOVER AS NEEDED EX DE,HL ; SWAP BACK ; ; DO THE WORK, SAVE THE LEN OF THIS ITERATION PUSH BC ; SAVE ITER LENGTH CALL Z280_BNKCPY ; DO THE WORK ; ;;; *DEBUG* SIMULATE CALL TO Z280_BNKCPY ;;CALL NEWLINE ;;CALL REGDMP ; *DEBUG* ;;ADD HL,BC ; INCREMENT SRC ADR BY COUNT ;;EX DE,HL ; SWAP ;;ADD HL,BC ; INCREMENT DST ADR BY COUNT ;;EX DE,HL ; SWAP BACK ;;LD BC,0 ; COUNT IS NOW ZERO ;;; END *DEBUG* ; POP BC ; RECOVER ITER LENGTH ; ; ACCUNT FOR WORK ACTUALLY PERFORMED PUSH HL ; SAVE SOURCE ADR LD HL,(Z280_BNKCPY_LEN) ; GET PENDING LENGTH OR A ; CLEAR CARRY SBC HL,BC ; SUBTRACT WHAT WE DID PUSH HL ; MOVE NEW PENDING LEN POP BC ; TO BC POP HL ; RECOVER SOURCE ADR ; ; SEE IF WE NEED TO ITERATE LD A,B ; IS LENGTH OR C ; ... NOW ZERO? RET Z ; IF SO, ALL DONE JR Z280_BNKCPYX ; ELSE ITERATE UNTIL DONE ; Z280_BNKCPY_LEN .DW 0 ; TEMP STORAGE FOR BC ; Z280_BNKCPY_XOVER: ; DETECT XOVER IN RANGE AND ADJUST COPY LEN IF SO ; HL=START, BC=LEN ; BC IS REDUCED AS NEEDED TO AVOID XOVER BIT 7,H ; START ABOVE 32K? RET NZ ; YES, NO XOVER PUSH HL ; SAVE START ADR ADD HL,BC ; ADD COPY LEN DEC HL ; CONVERT TO "LAST" BYTE OF RANGE BIT 7,H ; ABOVE 32K? POP HL ; RESTORE HL RET Z ; IF NOT, NO XOVER ; ; START IS BELOW 32K, END IS OVER 32K, XOVER IN SOURCE! ; REDUCE LENGTH TO AVOID IT ; COMPUTE (32K - START) FOR NEW LEN PUSH DE ; SAVE DEST (DE) PUSH HL ; SAVE START (HL) LD DE,$8000 EX DE,HL ; DE=START, HL=32K OR A ; CLEAR CARRY SBC HL,DE ; HL = NEW LEN PUSH HL ; MOVE NEW LEN POP BC ; ... TO BC POP HL ; RECOVER START POP DE ; RECOVER DEST RET ; RETURN ; Z280_BNKCPY: ; Z280 MEMORY TO MEMORY DMA ; USE FLOW THROUGH MODE ; SINGLE BYTE TRANSFER ; TRANSACTION DESCRIPTION REGISTER (TDR) ; %0000 0000 0000 0000 ; - AUTO INCREMENT MEMORY ; - FLOWTHROUGH OPERATION ; - SINGLE TRANSACTION (CAN WE USE CONTINUOUS???) ; - 1 BYTE XFER SIZE ; ; SAVE INCOMING REGISTERS PUSH HL PUSH DE PUSH BC ; PUSH BC ; SAVE COUNT PUSH HL ; SAVE SOURCE ADDRESS ; ; SELECT I/O PAGE $FF LD C,Z280_IOPR ; I/O PAGE REGISTER LDCTL HL,(C) ; GET CURRENT I/O PAGE LD (IOPRSAV),HL ; SAVE IT LD L,$FF ; I/O PAGE $FF LDCTL (C),HL ; LD C,Z280_DMA0_DSTL ; START WITH DEST REG LO ; LD A,(HB_DSTBNK) ; DEST BANK TO ACCUM CALL Z2DMAADR ; SETUP DEST ADR REGS ; POP DE ; SRC ADR TO DE LD A,(HB_SRCBNK) ; DEST BANK TO ACCUM CALL Z2DMAADR ; SETUP SOURCE ADR REGS ; POP HL ; COUNT TO HL OUTW (C),HL INC C ; BUMP TO TDR ; LD HL,$8000 ; ENABLE DMA0 TO RUN! OUTW (C),HL ; ; WAIT FOR XFER TO COMPLETE Z2DMALOOP: INW HL,(C) ; WORD INPUT BIT 7,H ; CHECK EN BIT OF TDR JR NZ,Z2DMALOOP ; LOOP WHILE ACTIVE ; ; RESTORE I/O PAGE LD C,Z280_IOPR ; I/O PAGE REGISTER LD HL,(IOPRSAV) ; RESTORE I/O PAGE LDCTL (C),HL ; ; SETUP RETURN VALUES POP BC ; RECOVER ORIGINAL BC POP DE ; RECOVER ORIGINAL DE POP HL ; RECOVER ORIGINAL HL ADD HL,BC ; INCREMENT SRC ADR BY COUNT EX DE,HL ; SWAP ADD HL,BC ; INCREMENT DST ADR BY COUNT EX DE,HL ; SWAP BACK LD BC,0 ; COUNT IS NOW ZERO ; RET ; Z2DMAADR: ; SET ADDRESS REGISTERS, BANK IN A, ADDRESS IN DE ; C POINTS TO FIRST DMA ADR PORT TO SET ; A=R000 BBBB, DE=0AAA AAAA AAAA AAAA ; RC: DMA HI=0000 RBBB BAAA 1111 LO=1111 AAAA AAAA AAAA ; ZZ: DMA HI=R000 0BBB BAAA 1111 LO=1111 AAAA AAAA AAAA BIT 7,D ; HIGH RAM? JR Z,Z2DMAADR1 ; NO, SKIP LD A,$8F ; SUBSTITUTE COMMON RAM BANK ID ; Z2DMAADR1: ; ADR HI FROM A:DE LD L,D ; L=?AAA AAAA LD H,A ; H=R000 BBBB SLA L ; L=AAAA AAA0 ? SRL H ; H=0R00 0BBB B RR L ; L=BAAA AAAA 0 LD A,$0F ; A=0000 1111 OR L ; A=BAAA 1111 LD L,A ; L=BAAA 1111 ; ; MOVE THE RAM/ROM BIT. ; RCBUS DMA HI=0000 RBBB BAAA 1111 LO=1111 AAAA AAAA AAAA ; ZZ80MB DMA HI=R000 0BBB BAAA 1111 LO=1111 AAAA AAAA AAAA BIT 6,H ; RAM BIT SET? JR Z,Z2DMAADR2 ; IF NOT, ALL DONE RES 6,H ; OTHERWISE, REMOVE RAM BIT LD A,RAMBIAS >> 6 ; RAM OFFSET (TOP 8 BITS) OR H ; RECOMBINE LD H,A ; AND PUT BACK IN H ; Z2DMAADR2: PUSH HL ; SAVE IT FOR NOW ; ADR LO FROM DE: LD L,E ; L=AAAA AAAA LD A,$F0 ; A=1111 0000 OR D ; A=1111 AAAA LD H,A ; HL=1111 AAAA AAAA AAAA ; ; SET ADR LO REG OUTW (C),HL INC C ; BUMP TO ADR HI REG ; ; SET ADR HI REG POP HL ; RECOVER THE HI VAL OUTW (C),HL INC C ; BUMP TO NEXT REG ; RET ; #ENDIF ; HB_INTFUNC_END .EQU $ ; ;================================================================================================== ; UTILITY FUNCTIONS ;================================================================================================== ; HB_UTIL_BEG .EQU $ ; #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 ; ; INCLUDE LZSA2 decompression engine if required. ; #IF ((CVDUENABLE | GDCENABLE | TMSENABLE | VGAENABLE | VRCENABLE) & USELZSA2) #INCLUDE "unlzsa2s.asm" #ENDIF ; ;-------------------------------------------------------------------------------------------------- ; 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 ; IF 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 ; ;================================================================================================== ; DYNAMIC RAM SIZE DETECTION ROUTINE ;================================================================================================== ; ; THIS CODE IS COPIED TO $F000 TO PERFORM RAM SIZE DETECTION. ; #IFDEF SIZERAM ; RS_IMAGE: .ORG $F000 RS_START: LD A,(HB_CURBNK) ; GET CURRENT BANK PUSH AF ; SAVE IT LD C,0 ; RUNNING BANK COUNT LD HL,$7FFF ; BYTE TEST ADDRESS LD IX,RS_ARY ; ORIG BYTE STORAGE ARRAY PTR RS_LOOP1: LD A,C ADD A,$80 ; OFFSET BY START OF RAM BANKS CALL RS_BNKSEL ; SELECT THE BANK LD A,(HL) ; GET ORIGINAL VALUE LD (IX),A ; SAVE IT TO RESTORE LATER INC IX ; BUMP IX LD A,$AA ; TEST LOC WITH $AA LD (HL),A ; AVOID PROBLEMS WITH LD (HL),A ; ... DS1210 LD (HL),A LD A,(HL) CP $AA JR NZ,RS_DONE LD A,$55 ; TEST LOC WITH $55 LD (HL),A LD A,(HL) CP $55 JR NZ,RS_DONE ; STORE A UNIQUE VALUE LD A,C LD (HL),A OR A ; ZERO? JR Z,RS_NEXT ; SKIP STORED VALUE CHECK ; VERIFY ALL STORED VALUES LD B,C ; INIT LOOP COUNTER LD E,0 ; INIT BANK ID RS_LOOP3: LD A,E ADD A,$80 CALL RS_BNKSEL LD A,(HL) CP E ; VERIFY JR NZ,RS_DONE ; ABORT IF MISCOMPARE INC E ; NEXT BANK DJNZ RS_LOOP3 ; RS_NEXT: INC C ; ADD 1 TO RAM BANK COUNT JR RS_LOOP1 ; AND LOOP TILL DONE ; RS_DONE: LD E,C ; FINAL BANK COUNT TO E LD A,C OR A JR Z,RS_LOOPZ ; RESTORE SAVED VALUES LD IX,RS_ARY LD B,C ; LOOP COUNT LD C,$80 ; BANK ID RS_LOOP2: LD A,C CALL RS_BNKSEL INC C LD A,(IX) ; GET VALUE LD (HL),A ; RESTORE IT INC IX DJNZ RS_LOOP2 ; ALL BANKS RS_LOOPZ: ; ; RETURN TO ORIGINAL BANK POP AF CALL RS_BNKSEL LD A,E ; RETURN BANK COUNT RET ; ; SPECIAL BANK SELECT FOR MEMORY SIZING ; RS_BNKSEL: #IF (MEMMGR == MM_Z280) ; IF Z280 MEMMGR, THEN WE ARE IN SYSTEM MODE, SO WE NEED TO ; BANK SELECT THE SYSTEM PDRS INSTEAD OF THE NORMAL USER PDRS. PUSH BC ; SAVE BC PUSH HL ; SAVE HL LD B,$10 ; FIRST SYSTEM PDR CALL Z280_BNKSEL ; DO IT POP HL ; RESTORE HL POP BC ; RESTORE BC RET ; DONE #ELSE ; NORMAL BANK SELECT JP HBX_BNKSEL #ENDIF ; RS_ARY .EQU $ ; RS_LEN .EQU $ - RS_START .ORG RS_IMAGE + RS_LEN ; #ENDIF ; ;================================================================================================== ; FRONT PANEL SUPPORT ;================================================================================================== ; ; FRONT PANEL HARDWARE DETECTION ; ; WE ARE REALLY JUST CHECKING FOR SWITCHES. NO WAY TO QUERY FOR ; LEDS. WE CHECK FOR I/O CONFLICT WITH VGARC IF ACTIVE. ; FP_DETECT: ; D: LEDS ACTIVE, E: SWITCHES ACTIVE LD D,TRUE ; ASSUME ACTIVE FOR NOW LD E,TRUE ; ASSUME ACTIVE FOR NOW ; ; IF VGARC IS ENABLED, CHECK IF IT IS ACTIVE. IF SO AND THE ; I/O PORTS CONFLICT, DEACTIVATE FRONT PANEL. ; #IF (VRCENABLE) LD A,(VRC_ACTIVE) ; GET VGARC ACTIVE STATUS OR A ; SET FLAGS JR Z,FP_DETECT1 ; IF NO, CONTINUE #IF ((FPLED_IO >= $00) & (FPLED_IO <= $0F)) ; CONFLICT, DEACTIVATE LEDS LD D,FALSE ; FP LEDS NOT ACTIVE #ENDIF #IF ((FPSW_IO >= $00) & (FPSW_IO <= $0F)) ; CONFLICT, DEACTIVATE SWITCHES LD E,FALSE ; FP SWITCHES NOT ACTIVE #ENDIF #ENDIF ; FP_DETECT1: ; THE SWITCH HARDWARE MAY OR MAY NOT BE INSTALLED. SO, HERE WE ; ATTEMPT TO CONFIRM WE HAVE A VALID PORT. CREDIT TO STEPHEN ; COUSINS FOR THIS APPROACH. LD C,FPSW_IO ; ADR OF SWITCH PORT EZ80_IO IN C,(C) ; READ IT USING IN (C) EZ80_IO IN A,(FPSW_IO) ; READ IT USING IN (PORT) CP C ; PORT FLOATING ON MISMATCH JR NZ,FP_DETECT2 ; NO H/W, SET FLAG CP $FF ; PORT FLOATING ON $FF JR Z,FP_DETECT2 ; NO H/W, SET FLAG JR FP_DETECTZ ; H/W EXISTS, DONE ; FP_DETECT2: LD E,FALSE ; RECORD NOT PRESENT ; FP_DETECTZ: LD (FP_ACTIVE),DE ; RECORD RESULTS RET ; DONE ; #IF (FPLED_ENABLE) ; ; SET FRONT PANEL LEDS FROM VALUE IN A ; FP_SETLEDS: PUSH HL ; SAVE HL LD L,A ; LED VALUE TO L LD A,(FPLED_ACTIVE) ; LEDS ACTIVE? OR A ; SET FLAGS LD A,L ; RESTORE REG A JR Z,FP_SETLEDS1 ; BAIL OUT IF NOT ACTIVE #IF (FPLED_INV) XOR $FF ; INVERT BITS IF NEEDED #ENDIF EZ80_IO OUT (FPLED_IO),A ; WRITE FP_SETLEDS1: POP HL ; RESTORE HL RET ; DONE ; #ENDIF ; #IF (FPSW_ENABLE) ; ; GET FRONT PANEL SWITCH SETTINGS ; FP_GETSWITCHES: LD A,(FPSW_ACTIVE) ; SWITCHES ACTIVE? OR A ; SET FLAGS RET Z ; BAIL OUT IF NOT ACTIVE EZ80_IO IN A,(FPSW_IO) ; READ SWITCHES #IF (FPSW_INV) XOR $FF ; INVERT BITS IF NEEDED #ENDIF RET ; DONE ; ; #ENDIF ; FP_ACTIVE: FPSW_ACTIVE .DB TRUE FPLED_ACTIVE .DB TRUE #IF (CPUFAM != CPU_EZ80) ; eZ80 WILL RETURNED ITS MEASURED CPUOSC - SO NO NEED FOR DETECTION HERE ; ;================================================================================================== ; CPU SPEED DETECTION USING DS-1302 RTC ;================================================================================================== ; HB_CPUSPD: ; #IF (DSRTCENABLE & ((CPUFAM == CPU_Z80) | (CPUFAM == CPU_Z180))) ; 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 A SECOND TICK TO GET A FULL ONE SECOND LOOP COUNT. ; WAITSEC WILL SET ZF IF AN OVERFLOW OCCURS (MEANING THAT THE ; CLOCK IS NOT TICKING). THERE IS NO ; POINT IN CALLING HB_WAITSEC AGAIN IN THAT CASE, SO WE ONLY ; CALL HB_WAITSEC AGAIN IF ZF IS NOT SET. CALL DSRTC_START 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 AGAIN, BUT ONLY IF ZF IS NOT SET CALL NZ,HB_WAITSEC ; WAIT FOR SECONDS TICK ; #IF (CPUFAM == CPU_Z180) ; RESTORE W/S SETTINGS FROM BEFORE TEST POP AF OUT0 (Z180_DCNTL),A #ENDIF ; ; MOVE LOOP COUNT TO HL PUSH DE POP HL ; ; CHECK FOR OVERFLOW (NOT TICKING) LD A,H OR L JR Z,HB_CPUSPD2 ; FAILURE, USE DEFAULT CPU SPEED ; ; TIMES 4 FOR CPU SPEED IN KHZ ; RES 0,L ; GRANULARITY SLA L RL H SLA L RL H ; ; RETURN CURRENT CPU SPD (KHZ) IN HL XOR A ; SIGNAL SUCCESS RET ; HB_WAITSEC: ; WAIT FOR SECONDS TICK ; RETURN SECS VALUE IN A, LOOP COUNT IN DE ; ZF IS SET ON OVERFLOW (CLOCK NOT TICKING) 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 ; #ENDIF ; HB_CPUSPD2: ; HANDLE NO RTC OR NOT TICKING OR $FF ; SIGNAL ERROR RET ; AND DONE #ENDIF ; CPUFAM != CPU_EZ80 ; HB_UTIL_END .EQU $ ; ;================================================================================================== ; DISPLAY SUMMARY OF ATTACHED UNITS/DEVICES ;================================================================================================== ; HB_PRTSUM_BEG .EQU $ ; 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 ; LD C,BF_SYSGET_SNDCNT ; SOUND DEVICES LD HL,PS_SOUND 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 CP 10 ; CHECK FOR MULTIPLE DIGITS CALL C,PC_SPACE ; EXTRA SPACE IF NEEDED 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, C:=DISK ATTRIBUTES PUSH BC ; SAVE ATTRIBUTES LD HL,PS_DDMD ; 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 JP NZ,PS_PRT18 ; IF FLOPPY, JUMP AHEAD LD C,E LD DE,PS_DTHARD LD A,00001111B CALL PRTIDXMSK CALL PS_PAD18 ; PAD TO 18 SPACES 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 AND $0F ; ISOLATE TYPE BITS CP 4 ; ROM DISK? JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB CP 5 ; RAM DISK? JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB CP 7 ; FLASH 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 PRTDEC32 ; PRINT DWORD IN DECIMAL PRTS("MB$") ; PRINT SUFFIX CALL PC_COMMA PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA RET ; DONE ; PS_PRTDC1: ; PRINT ROM/RAM 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 PRTDEC32 ; PRINT DWORD IN DECIMAL 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,%00011000 ; DISPLAY FORM FACTOR LD DE,PS_FLP_FSTR ; WHICH IS DEFINED IN CALL PRTIDXMSK ; BITS 5 AND 6. ; LD A,%00000100 ; DISPLAY SIDES LD DE,PS_FLP_SSTR ; WHICH IS DEFINED CALL PRTIDXMSK ; IN BIT 4 ; LD A,%00000011 ; 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_SDUART ; 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 JP NZ,PS_PRT18 ; PARALLEL TYPE? LD HL,PS_STRS232 ; ASSUME RS-232 BIT 7,C ; 0=RS-232, 1=TERMINAL JP Z,PS_PRT18 ; HANDLE TERMINAL TYPE LD HL,PS_STTERM ; TYPE IS TERMINAL JP PS_PRT18 ; ; 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("Term Module$") 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_VDVDU ; 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 JP PS_PRT18 ; PRINT ; ; 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 SOUND CONFIG ; PS_SOUND: PUSH BC ; UNIT COLUMN PRTS("Sound $") LD A,C ; MOVE UNIT NUM TO A CALL PRTDECB ; PRINT IT CP 10 ; CHECK FOR MULTIPLE DIGITS CALL C,PC_SPACE ; EXTRA SPACE IF NEEDED PRTS(" $") ; PAD TO NEXT COLUMN ; DEVICE COLUMN PUSH BC LD E,C XOR A LD DE,PS_SDSND ; POINT TO DEVICE TYPE NAME TABLE CALL PRTIDXDEA ; PRINT DEVICE NMEMONIC PADDED TO FIELD WIDTH LD A,C ; MOVE UNIT NUM TO A CALL PRTDECB ; PRINT IT CALL PC_COLON LD A,(PRTIDXCNT) SUB 12-1 ; SUBTRACT FIELD WIDTH (LESS THE COLON) NEG ; MAKE IT A POSITIVE NUMBER CALL PS_PAD ; PAD AS NEEDED POP BC ; DEVICE TYPE ; LD B,BF_SNDQUERY ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C LD E,BF_SNDQ_DEV RST 08 PUSH BC LD A,B LD DE,PS_SDSN76489 CALL PRTIDXDEA CALL PS_PAD18 POP BC ; ; DEVICE CHARACTERISTICS ; LD B,BF_SNDQUERY ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C LD E,BF_SNDQ_CHCNT RST 08 LD A,B CALL PRTDECB LD A,'+' CALL COUT LD A,C CALL PRTDECB PRTS(" CHANNELS$") CALL NEWLINE ; POP BC RET ; ; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE ; PS_PRTDEV: EX DE,HL LD A,H ; TYPE ID CALL PRTIDXDEA ; PRINT TYPE LABEL LD A,L ; UNIT NUMBER CALL PRTDECB ; PRINT NUM, ASSUME 1 CHAR CALL PC_COLON ; PRINT COLON LD A,(PRTIDXCNT) SUB 12-2+1 ; 12 CHAR FIELD - 1 POS FOR UNIT NUM AND 1 POS FOR COLON NEG CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) RET ; ; PRINT DEVICE MNEMONIC, DEVTYP/NUM SPECIFIED IN DE ; PS_PRTNUL: LD HL,PS_STRNUL ; FALL THRU TO PS_PRT ; ; PRINT STRING AT (HL), $ TERM, RETURN CHARS PRINTED IN C ; PS_PRT: 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 ; ; PAD 18 CHARACTER FIELD ; PS_PAD18: LD A,(PRTIDXCNT) LD C,A JR PS_PRT18A ; ; PRINT STRING AT HL IN 18 CHARACTER FIELD ; PS_PRT18: CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED PS_PRT18A: LD A,18 ; 18 CHAR FIELD SUB C ; CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) ; ; PAD N SPACES SPECIFIED IN A ; PS_PAD: LD B,A LD A,' ' PS_PAD1: CALL COUT DJNZ PS_PAD1 RET ; HB_CPU_STR: .TEXT " Z80$" .TEXT " Z80180$" .TEXT " Z8S180-K$" .TEXT " Z8S180-N$" .TEXT " Z80280$" .TEXT " eZ80$" ; PS_STRNUL .TEXT "--$" ; DISPLAY STRING FOR NUL VALUE ; ; DISK DEVICE STRINGS ; 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$" PS_DDPPA .TEXT "PPA$" PS_DDIMM .TEXT "IMM$" PS_DDSYQ .TEXT "SYQ$" PS_DDCHUSB .TEXT "CHUSB$" PS_DDCHSD .TEXT "CHSD$" ; ; DISK TYPE STRINGS ; 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_DTFSH .TEXT "Flash Drive$" PS_DTCD .TEXT "CD-ROM$" PS_DTCRT .TEXT "Cartridge$" 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_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 "PIO$" PS_SDUF .TEXT "UF$" PS_SDDUART .TEXT "DUART$" PS_SDZ2U .TEXT "Z2U$" PS_SDLPT .TEXT "LPT$" PS_SDESPCON .TEXT "ESPCON$" PS_SDESPSER .TEXT "ESPSER$" PS_SDSCON .TEXT "SCON$" PS_SDEF .TEXT "EF$" PS_SDSSER .TEXT "SSER$" ; ; 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_VDVDU .TEXT "VDU$" PS_VDCVDU .TEXT "CVDU$" PS_VDGDC .TEXT "GDC$" PS_VDTMS .TEXT "TMS$" PS_VDVGA .TEXT "VGA$" PS_VDVRC .TEXT "VRC$" PS_VDEF .TEXT "EF$" PS_VDFV .TEXT "FV$" ; ; VIDEO TYPE STRINGS ; PS_VTCRT .TEXT "CRT$" ; ; SOUND DEVICE STRINGS ; PS_SDSND .TEXT "SND$" ; ; SOUND TYPE STRINGS ; PS_SDSN76489 .TEXT "SN76489$" PS_SDAY38910 .TEXT "AY-3-8910$" PS_SDBITMODE .TEXT "I/O PORT$" PS_SDYM2612 .TEXT "YM2612$" ; ; 0 1 2 3 4 5 6 7 ; 01234567890123456789012345678901234567890123456789012345678901234567890123456789 PS_STRHDR .TEXT "Unit Device Type Capacity/Mode\r\n" .TEXT "---------- ---------- ---------------- --------------------\r\n$" ; HB_PRTSUM_END .EQU $ ; ;================================================================================================== ; DEVICE DRIVERS ;================================================================================================== ; HB_DRIVERS_BEG .EQU $ ; ;;;#IF (DSKYENABLE) #IF (ICMENABLE) ORG_ICM .EQU $ #INCLUDE "icm.asm" SIZ_ICM .EQU $ - ORG_ICM MEMECHO "ICM occupies " MEMECHO SIZ_ICM MEMECHO " bytes.\n" #ENDIF ; #IF (PKDENABLE) ORG_PKD .EQU $ #INCLUDE "pkd.asm" SIZ_PKD .EQU $ - ORG_PKD MEMECHO "PKD occupies " MEMECHO SIZ_PKD MEMECHO " bytes.\n" #ENDIF ;;;#ENDIF ; #IF (LCDENABLE) ORG_LCD .EQU $ #INCLUDE "lcd.asm" SIZ_LCD .EQU $ - ORG_LCD MEMECHO "LCD occupies " MEMECHO SIZ_LCD MEMECHO " bytes.\n" #ENDIF ; #IF (GM7303ENABLE) ORG_GM7303 .EQU $ #INCLUDE "gm7303.asm" SIZ_GM7303 .EQU $ - ORG_GM7303 MEMECHO "GM7303 occupies " MEMECHO SIZ_GM7303 MEMECHO " bytes.\n" #ENDIF ; #IF (H8PENABLE) ORG_H8P .EQU $ #INCLUDE "h8p.asm" SIZ_H8P .EQU $ - ORG_H8P MEMECHO "H8P occupies " MEMECHO SIZ_H8P MEMECHO " bytes.\n" #ENDIF ; #IF (PLATFORM == PLT_NABU) ORG_NABU .EQU $ #INCLUDE "nabu.asm" SIZ_NABU .EQU $ - ORG_NABU MEMECHO "NABU occupies " MEMECHO SIZ_NABU MEMECHO " bytes.\n" #ENDIF ; #IF (DSRTCENABLE) ORG_DSRTC .EQU $ #INCLUDE "dsrtc.asm" SIZ_DSRTC .EQU $ - ORG_DSRTC MEMECHO "DSRTC occupies " MEMECHO SIZ_DSRTC MEMECHO " bytes.\n" #ENDIF ; #IF (DS1501RTCENABLE) ORG_DS1501RTC .EQU $ #INCLUDE "ds1501rtc.asm" SIZ_DS1501RTC .EQU $ - ORG_DS1501RTC MEMECHO "DS1501RTC occupies " MEMECHO SIZ_DS1501RTC MEMECHO " bytes.\n" #ENDIF ; #IF (BQRTCENABLE) ORG_BQRTC .EQU $ #INCLUDE "bqrtc.asm" SIZ_BQRTC .EQU $ - ORG_BQRTC MEMECHO "BQRTC occupies " MEMECHO SIZ_BQRTC MEMECHO " bytes.\n" #ENDIF ; #IF (SIMRTCENABLE) ORG_SIMRTC .EQU $ #INCLUDE "simrtc.asm" SIZ_SIMRTC .EQU $ - ORG_SIMRTC MEMECHO "SIMRTC occupies " MEMECHO SIZ_SIMRTC MEMECHO " bytes.\n" #ENDIF ; #IF (PCFENABLE) ORG_PCF .EQU $ #INCLUDE "pcf.asm" SIZ_PCF .EQU $ - ORG_PCF MEMECHO "PCF occupies " MEMECHO SIZ_PCF MEMECHO " bytes.\n" #ENDIF ; #IF (DS5RTCENABLE) ORG_DS5RTC .EQU $ #INCLUDE "ds5rtc.asm" SIZ_DS5RTC .EQU $ - ORG_DS5RTC MEMECHO "DS5RTC occupies " MEMECHO SIZ_DS5RTC MEMECHO " bytes.\n" #ENDIF ; #IF (INTRTCENABLE) ORG_INTRTC .EQU $ #INCLUDE "intrtc.asm" SIZ_INTRTC .EQU $ - ORG_INTRTC MEMECHO "INTRTC occupies " MEMECHO SIZ_INTRTC MEMECHO " bytes.\n" #ENDIF ; #IF (RP5RTCENABLE) ORG_RP5RTC .EQU $ #INCLUDE "rp5rtc.asm" SIZ_RP5RTC .EQU $ - ORG_RP5RTC MEMECHO "RP5RTC occupies " MEMECHO SIZ_RP5RTC MEMECHO " bytes.\n" #ENDIF ; #IF (SSERENABLE) ORG_SSER .EQU $ #INCLUDE "sser.asm" SIZ_SSER .EQU $ - ORG_SSER MEMECHO "SSER occupies " MEMECHO SIZ_SSER MEMECHO " bytes.\n" #ENDIF ; #IF (ASCIENABLE) ORG_ASCI .EQU $ #INCLUDE "asci.asm" SIZ_ASCI .EQU $ - ORG_ASCI MEMECHO "ASCI occupies " MEMECHO SIZ_ASCI MEMECHO " bytes.\n" #ENDIF ; #IF (Z2UENABLE) ORG_Z2U .EQU $ #INCLUDE "z2u.asm" SIZ_Z2U .EQU $ - ORG_Z2U MEMECHO "Z2U occupies " MEMECHO SIZ_Z2U MEMECHO " bytes.\n" #ENDIF ; #IF (UARTENABLE) ORG_UART .EQU $ #INCLUDE "uart.asm" SIZ_UART .EQU $ - ORG_UART MEMECHO "UART occupies " MEMECHO SIZ_UART MEMECHO " bytes.\n" #ENDIF ; #IF (DUARTENABLE) ORG_DUART .EQU $ #INCLUDE "duart.asm" SIZ_DUART .EQU $ - ORG_DUART MEMECHO "DUART occupies " MEMECHO SIZ_DUART MEMECHO " bytes.\n" #ENDIF ; #IF (SIOENABLE) ORG_SIO .EQU $ #INCLUDE "sio.asm" SIZ_SIO .EQU $ - ORG_SIO MEMECHO "SIO occupies " MEMECHO SIZ_SIO MEMECHO " bytes.\n" #ENDIF ; #IF (ACIAENABLE) ORG_ACIA .EQU $ #INCLUDE "acia.asm" SIZ_ACIA .EQU $ - ORG_ACIA MEMECHO "ACIA occupies " MEMECHO SIZ_ACIA MEMECHO " bytes.\n" #ENDIF ; #IF (PIOENABLE) ORG_PIO .EQU $ #INCLUDE "pio.asm" SIZ_PIO .EQU $ - ORG_PIO MEMECHO "PIO occupies " MEMECHO SIZ_PIO MEMECHO " bytes.\n" #ENDIF ; #IF (LPTENABLE) ORG_LPT .EQU $ #INCLUDE "lpt.asm" SIZ_LPT .EQU $ - ORG_LPT MEMECHO "LPT occupies " MEMECHO SIZ_LPT MEMECHO " bytes.\n" #ENDIF ; #IF (PIO_4P | PIO_ZP | PIO_SBC) ORG_PIO .EQU $ #INCLUDE "pio.asm" SIZ_PIO .EQU $ - ORG_PIO MEMECHO "PIO occupies " MEMECHO SIZ_PIO MEMECHO " bytes.\n" #ENDIF ; #IF (UFENABLE) ORG_UF .EQU $ #INCLUDE "uf.asm" SIZ_UF .EQU $ - ORG_UF MEMECHO "UF occupies " MEMECHO SIZ_UF MEMECHO " bytes.\n" #ENDIF ; #IF (VGAENABLE) ORG_VGA .EQU $ #INCLUDE "vga.asm" SIZ_VGA .EQU $ - ORG_VGA MEMECHO "VGA occupies " MEMECHO SIZ_VGA MEMECHO " bytes.\n" #ENDIF ; #IF (CVDUENABLE) ORG_CVDU .EQU $ #INCLUDE "cvdu.asm" SIZ_CVDU .EQU $ - ORG_CVDU MEMECHO "CVDU occupies " MEMECHO SIZ_CVDU MEMECHO " bytes.\n" #ENDIF ; #IF (VDUENABLE) ORG_VDU .EQU $ #INCLUDE "vdu.asm" SIZ_VDU .EQU $ - ORG_VDU MEMECHO "VDU occupies " MEMECHO SIZ_VDU MEMECHO " bytes.\n" #ENDIF ; #IF (TMSENABLE) ORG_TMS .EQU $ #INCLUDE "tms.asm" SIZ_TMS .EQU $ - ORG_TMS MEMECHO "TMS occupies " MEMECHO SIZ_TMS MEMECHO " bytes.\n" #ENDIF ; #IF (EFENABLE) ORG_EF .EQU $ #INCLUDE "ef.asm" SIZ_EF .EQU $ - ORG_EF MEMECHO "EF occupies " MEMECHO SIZ_EF MEMECHO " bytes.\n" #ENDIF ; #IF (GDCENABLE) ORG_GDC .EQU $ #INCLUDE "gdc.asm" SIZ_GDC .EQU $ - ORG_GDC MEMECHO "GDC occupies " MEMECHO SIZ_GDC MEMECHO " bytes.\n" #ENDIF ; #IF (VRCENABLE) ORG_VRC .EQU $ #INCLUDE "vrc.asm" SIZ_VRC .EQU $ - ORG_VRC MEMECHO "VRC occupies " MEMECHO SIZ_VRC MEMECHO " bytes.\n" #ENDIF ; #IF (FVENABLE) ORG_FV .EQU $ #INCLUDE "fv.asm" SIZ_FV .EQU $ - ORG_FV MEMECHO "FV occupies " MEMECHO SIZ_FV MEMECHO " bytes.\n" #ENDIF ; #IF (DMAENABLE) ORG_DMA .EQU $ #INCLUDE "dma.asm" SIZ_DMA .EQU $ - ORG_DMA MEMECHO "DMA occupies " MEMECHO SIZ_DMA MEMECHO " bytes.\n" #ENDIF ; #IF (KBDENABLE) ORG_KBD .EQU $ #INCLUDE "kbd.asm" SIZ_KBD .EQU $ - ORG_KBD MEMECHO "KBD occupies " MEMECHO SIZ_KBD MEMECHO " bytes.\n" #ENDIF ; #IF (PPKENABLE) ORG_PPK .EQU $ #INCLUDE "ppk.asm" SIZ_PPK .EQU $ - ORG_PPK MEMECHO "PPK occupies " MEMECHO SIZ_PPK MEMECHO " bytes.\n" #ENDIF ; #IF (MKYENABLE) ORG_MKY .EQU $ #INCLUDE "mky.asm" SIZ_MKY .EQU $ - ORG_MKY MEMECHO "MKY occupies " MEMECHO SIZ_MKY MEMECHO " bytes.\n" #ENDIF ; #IF (NABUKBENABLE) ORG_NABUKB .EQU $ #INCLUDE "nabukb.asm" SIZ_NABUKB .EQU $ - ORG_NABUKB MEMECHO "NABUKB occupies " MEMECHO SIZ_NABUKB MEMECHO " bytes.\n" #ENDIF ; #IF (PRPENABLE) ORG_PRP .EQU $ #INCLUDE "prp.asm" SIZ_PRP .EQU $ - ORG_PRP MEMECHO "PRP occupies " MEMECHO SIZ_PRP MEMECHO " bytes.\n" #ENDIF ; #IF (PPPENABLE) ORG_PPP .EQU $ #INCLUDE "ppp.asm" SIZ_PPP .EQU $ - ORG_PPP MEMECHO "PPP occupies " MEMECHO SIZ_PPP MEMECHO " bytes.\n" #ENDIF ; #IF (SCONENABLE) ORG_SCON .EQU $ #INCLUDE "scon.asm" SIZ_SCON .EQU $ - ORG_SCON MEMECHO "SCON occupies " MEMECHO SIZ_SCON MEMECHO " bytes.\n" #ENDIF ; #IF (CHENABLE) ORG_CH .EQU $ #INCLUDE "ch.asm" SIZ_CH .EQU $ - ORG_CH MEMECHO "CH occupies " MEMECHO SIZ_CH MEMECHO " bytes.\n" #ENDIF ; #IF (ESPENABLE) ORG_ESP .EQU $ #INCLUDE "esp.asm" SIZ_ESP .EQU $ - ORG_ESP MEMECHO "ESP occupies " MEMECHO SIZ_ESP MEMECHO " bytes.\n" #ENDIF ; #IF (MDENABLE) ORG_MD .EQU $ #INCLUDE "md.asm" SIZ_MD .EQU $ - ORG_MD MEMECHO "MD occupies " MEMECHO SIZ_MD MEMECHO " bytes.\n" #ENDIF ; #IF (FDENABLE) ORG_FD .EQU $ #INCLUDE "fd.asm" SIZ_FD .EQU $ - ORG_FD MEMECHO "FD occupies " MEMECHO SIZ_FD MEMECHO " bytes.\n" #ENDIF ; #IF (RFENABLE) ORG_RF .EQU $ #INCLUDE "rf.asm" SIZ_RF .EQU $ - ORG_RF MEMECHO "RF occupies " MEMECHO SIZ_RF MEMECHO " bytes.\n" #ENDIF ; #IF (IDEENABLE) ORG_IDE .EQU $ #INCLUDE "ide.asm" SIZ_IDE .EQU $ - ORG_IDE MEMECHO "IDE occupies " MEMECHO SIZ_IDE MEMECHO " bytes.\n" #ENDIF ; #IF (PPIDEENABLE) ORG_PPIDE .EQU $ #INCLUDE "ppide.asm" SIZ_PPIDE .EQU $ - ORG_PPIDE MEMECHO "PPIDE occupies " MEMECHO SIZ_PPIDE MEMECHO " bytes.\n" #ENDIF ; #IF (SDENABLE) ORG_SD .EQU $ #INCLUDE "sd.asm" SIZ_SD .EQU $ - ORG_SD MEMECHO "SD occupies " MEMECHO SIZ_SD MEMECHO " bytes.\n" #ENDIF ; #IF (HDSKENABLE) ORG_HDSK .EQU $ #INCLUDE "hdsk.asm" SIZ_HDSK .EQU $ - ORG_HDSK MEMECHO "HDSK occupies " MEMECHO SIZ_HDSK MEMECHO " bytes.\n" #ENDIF ; #IF (PPAENABLE) ORG_PPA .EQU $ #INCLUDE "ppa.asm" SIZ_PPA .EQU $ - ORG_PPA MEMECHO "PPA occupies " MEMECHO SIZ_PPA MEMECHO " bytes.\n" #ENDIF ; #IF (IMMENABLE) ORG_IMM .EQU $ #INCLUDE "imm.asm" SIZ_IMM .EQU $ - ORG_IMM MEMECHO "IMM occupies " MEMECHO SIZ_IMM MEMECHO " bytes.\n" #ENDIF ; #IF (SYQENABLE) ORG_SYQ .EQU $ #INCLUDE "syq.asm" SIZ_SYQ .EQU $ - ORG_SYQ MEMECHO "SYQ occupies " MEMECHO SIZ_SYQ MEMECHO " bytes.\n" #ENDIF ; ; TERM IS ALWAYS INCLUDED ORG_TERM .EQU $ #INCLUDE "term.asm" SIZ_TERM .EQU $ - ORG_TERM MEMECHO "TERM occupies ") MEMECHO SIZ_TERM MEMECHO " bytes.\n" ; ;#IF (SPKENABLE & DSRTCENABLE #IF (SPKENABLE) ORG_SPK .EQU $ #INCLUDE "spk.asm" SIZ_SPK .EQU $ - ORG_SPK MEMECHO "SPK occupies " MEMECHO SIZ_SPK MEMECHO " bytes.\n" #ENDIF #IF (KIOENABLE) ORG_KIO .EQU $ #INCLUDE "kio.asm" SIZ_KIO .EQU $ - ORG_KIO MEMECHO "KIO occupies " MEMECHO SIZ_KIO MEMECHO " bytes.\n" #ENDIF #IF (CTCENABLE) ORG_CTC .EQU $ #INCLUDE "ctc.asm" SIZ_CTC .EQU $ - ORG_CTC MEMECHO "CTC occupies " MEMECHO SIZ_CTC MEMECHO " bytes.\n" #ENDIF #IF (SN76489ENABLE) ORG_SN76489 .EQU $ #INCLUDE "sn76489.asm" SIZ_SN76489 .EQU $ - ORG_SN76489 MEMECHO "SN76489 occupies " MEMECHO SIZ_SN76489 MEMECHO " bytes.\n" #ENDIF #IF (AY38910ENABLE) ORG_AY38910 .EQU $ #INCLUDE "ay38910.asm" SIZ_AY38910 .EQU $ - ORG_AY38910 MEMECHO "AY38910 occupies " MEMECHO SIZ_AY38910 MEMECHO " bytes.\n" #ENDIF #IF (YM2612ENABLE) ORG_YM2612 .EQU $ #INCLUDE "ym2612.asm" SIZ_YM2612 .EQU $ - ORG_YM2612 MEMECHO "YM2612 occupies " MEMECHO SIZ_YM2612 MEMECHO " bytes.\n" #ENDIF ; ; #IF (CPUFAM == CPU_EZ80) MEMECHO "EZ80 DRIVERS\n" ORG_EZ80DRVS .EQU $ ; ORG_EZ80CPUDRV .EQU $ #INCLUDE "ez80cpudrv.asm" SIZ_EZ80CPUDRV .EQU $ - ORG_EZ80CPUDRV MEMECHO " EZ80 CPU DRIVER occupies " MEMECHO SIZ_EZ80CPUDRV MEMECHO " bytes.\n" ; ORG_EZ80SYSTMR .EQU $ #INCLUDE "ez80systmr.asm" SIZ_EZ80SYSTMR .EQU $ - ORG_EZ80SYSTMR MEMECHO " EZ80 SYS TIMER occupies " MEMECHO SIZ_EZ80SYSTMR MEMECHO " bytes.\n" ; #IF (EZ80RTCENABLE) ORG_EZ80RTC .EQU $ #INCLUDE "ez80rtc.asm" SIZ_EZ80RTC .EQU $ - ORG_EZ80RTC MEMECHO " EZ80 RTC occupies " MEMECHO SIZ_EZ80RTC MEMECHO " bytes.\n" #ENDIF ; #IF (EZ80UARTENABLE) ORG_EZU .EQU $ #INCLUDE "ez80uart.asm" SIZ_EZU .EQU $ - ORG_EZU MEMECHO " EZ80 UART occupies " MEMECHO SIZ_EZU MEMECHO " bytes.\n" #ENDIF SIZ_EZ80DRVS .EQU $ - ORG_EZ80DRVS MEMECHO " Total " MEMECHO SIZ_EZ80DRVS MEMECHO " bytes.\n" #ENDIF MEMECHO "RTCDEF=" MEMECHO RTCDEF MEMECHO "\n" ; HB_DRIVERS_END .EQU $ ; ;================================================================================================== ; FONTS ;================================================================================================== ; HB_FONTS_BEG .EQU $ ; ORG_FONTS .EQU $ ; MEMECHO "FONTS" ; #IFDEF USEFONT8X8 FONT8X8: ; ; FOR NOW, WE NEVER COMPRESS THE 8X8 FONT. SEE TMS DRIVER. ; #IF USELZSA2 & FALSE #INCLUDE "font8x8c.asm" #ELSE #INCLUDE "font8x8u.asm" #ENDIF MEMECHO " 8X8" #ENDIF ; #IFDEF USEFONT8X11 FONT8X11: #IF USELZSA2 #INCLUDE "font8x11c.asm" #ELSE #INCLUDE "font8x11u.asm" #ENDIF MEMECHO " 8X11" #ENDIF ; #IFDEF USEFONT8X16 FONT8X16: #IF USELZSA2 #INCLUDE "font8x16c.asm" #ELSE #INCLUDE "font8x16u.asm" #ENDIF MEMECHO " 8X16" #ENDIF ; #IFDEF USEFONTCGA FONTCGA: #IF USELZSA2 #INCLUDE "fontcgac.asm" #ELSE #INCLUDE "fontcgau.asm" #ENDIF MEMECHO " CGA" #ENDIF ; #IFDEF USEFONTVGARC FONTVGARC: #IF USELZSA2 #INCLUDE "fontvgarcc.asm" #ELSE #INCLUDE "fontvgarcu.asm" #ENDIF MEMECHO " VGARC" #ENDIF ; SIZ_FONTS .EQU $ - ORG_FONTS MEMECHO " occupy " MEMECHO SIZ_FONTS MEMECHO " bytes.\n" ; HB_FONTS_END .EQU $ ; ;================================================================================================== ; HBIOS GLOBAL DATA ;================================================================================================== ; HB_DATA_BEG .EQU $ ; IDLECOUNT .DB 0 ; HEAPCURB .DW 0 ; MARK HEAP ADDRESS AFTER INITIALIZATION ; HB_TICKS .FILL 4,0 ; 32 BIT TICK COUNTER HB_SECTCK .DB TICKFREQ ; TICK COUNTER FOR FRACTIONAL SECONDS HB_SECS .FILL 4,0 ; 32 BIT SECONDS COUNTER ; HB_CPUTYPE .DB 0 ; 0=Z80, 1=Z180, 2=Z180-K, 3=Z180-N, 4=Z280 HB_CPUOSC .DW CPUOSC ; ACTUAL CPU HARDWARE OSC FREQ IN KHZ ; HB_BATCOND .DB 0 ; BATTERY CONDITION (0=LOW, 1=OK) ; RTCDEFVAL .DB RTCDEF ; STORAGE FOR RTC DEFAULT VALUE ; #IF (BT_REC_TYPE != BT_REC_NONE) HB_BOOT_REC .DB 0 ; BOOT MODE (0=NORMAL, 1=RECOVERY MODE) #ENDIF ; STR_BANNER .DB "\r\n\r\nRomWBW HBIOS v", BIOSVER, ", ", TIMESTAMP #IFDEF APPBOOT .DB " (App Boot)" #ENDIF .DB "$" STR_PLATFORM .DB PLATFORM_NAME, "$" STR_CONSOLE .DB "\r\n\r\n Console on Unit #$" STR_BADINT .DB "\r\n*** BAD INT ***\r\n$" STR_LOWBAT .DB "\r\n\r\n+++ LOW BATTERY +++$" ; STR_PANIC .TEXT "\r\n>>> PANIC: $" STR_SYSCHK .TEXT "\r\n>>> SYSCHK: $" STR_CONTINUE .TEXT "\r\nContinue (Y/N)? $" ; HB_CURSEC .DB 0 ; CURRENT SECOND (TEMP) ; HB_BCDTMP .FILL 5,0 ; BCD NUMBER STORAGE (TEMP) ; HB_BOOTCON .DB 0 ; INITIAL BOOT CONSOLE SAVE AREA HB_BOOTCFG .DW 0 ; CONSOLE CONFIG SAVE AREA HB_NEWCON .DB 0 ; NEW CONSOLE TO SWITCH TO ; #IF (SUPCTS) HB_BOOTCONSAV .DB 0 ; INITIAL BOOT CONSOLE SAVE AREA HB_CONCFGSAV .DW 0 ; CONSOLE CONFIG SAVE AREA #ENDIF ; HB_HASFP .DB 0 ; NON-ZERO MEANS FP EXISTS ; HB_WRKBUF .EQU $ ; INTERNAL DISK BUFFER ; ; THIS AREA IS USED AS A TEMPORARY DISK BUFFER. IT IS ALSO USED ; FOR THE APPBOOT STARTUP CODE SINCE THAT CODE CAN BE DISCARDED ; AFTER STARTUP. ; HB_APPBOOT: ; #IFDEF APPBOOT ; APPBOOT IS ONLY SUPPORTED ON A RUNNING ROMWBW SYSTEM. ; CONFIRM AND DIAGNOSE IF NOT. LD HL,(HB_IDENT) ; HL := ADR OR ROMWBW HBIOS IDENT LD A,(HL) ; GET FIRST BYTE OF ROMWBW MARKER CP 'W' ; MATCH? JR NZ,HB_APPBOOTERR ; ABORT WITH INVALID CONFIG BLOCK INC HL ; NEXT BYTE (MARKER BYTE 2) LD A,(HL) ; LOAD IT CP ~'W' ; MATCH? JR NZ,HB_APPBOOTERR ; ABORT WITH INVALID CONFIG BLOCK JR HB_APPBOOT1 ; WE ARE RUNNING ROMWBW, CONTINUE ; HB_APPBOOTERR: LD DE,STR_APPBOOTERR ; POINT TO ERROR MESSAGE LD C,9 ; BDOS FUNC 9: WRITE STR CALL $0005 ; DO IT OR $FF ; SIGNAL ERROR RET ; AND RETURN ; STR_APPBOOTERR .DB "\r\n\r\n*** App Boot is only possible on running RomWBW system!\r\n\r\n$" ; HB_APPBOOT1: ; APPBOOT REQUIRES THAT THE COMMON BANK IS NOT CHANGED BY ; THE NEW CONFIG. TEST FOR THIS AND DIAGNOSE IF SO. LD A,(HCB_BIDCOM) ; RUNNING COMMON BANK ID LD B,BF_SYSGET ; HBIOS SYSGET LD C,BF_SYSGET_BNKINFO ; BANK INFORMATION RST 08 ; D = BIOS BANK ID LD B,BF_SYSPEEK ; HBIOS FUNC: PEEK LD HL,HCB_LOC + HCB_BIDCOM ; COMMON BANK ID RST 08 ; E = COMMON BANK ID LD A,E ; PUT IN A CP BID_COM ; COMPARE TO NEW CONFIG JR Z,HB_APPBOOT2 ; IF SAME, CONTINUE ; ; DIAGNOSE COMMON BANK ID MISMATCH LD DE,STR_COMBANKERR ; POINT TO ERROR MESSAGE LD C,9 ; BDOS FUNC 9: WRITE STR CALL $0005 ; DO IT OR $FF ; SIGNAL ERROR RET ; AND RETURN ; STR_COMBANKERR .DB "\r\n\r\n*** Common Bank Mismatch!\r\n\r\n$" ; HB_APPBOOT2: ; ANNOUNCE THE APPLICATION BOOT LD DE,STR_APPBOOT ; POINT TO MESSAGE LD C,9 ; BDOS FUNC 9: WRITE STR CALL $0005 ; DO IT CALL LDELAY ; SERIAL PORT FLUSH TIME JR HB_APPBOOT3 ; AND CONTINUE ; STR_APPBOOT .DB "\r\n\r\n*** Launching RomWBW HBIOS v", BIOSVER, ", ", TIMESTAMP, " for" .DB "\r\n\r\n ", PLATFORM_NAME, "$" ; HB_APPBOOT3: ; #IF (MEMMGR == MM_Z280) ; WE NEED TO SWITCH FROM USER MODE TO SYSTEM MODE, BUT CONTINUE ; RUNNING IN THE CURRENT BANK. THIS IS A LITTLE MESSY. ; ; FIRST, OVERLAY PROXY CODE WITH FRESH CODE SO WE CAN USE THE ; PROXY ROUTINES SAFELY. LD A,(HB_CURBNK) ; GET CURBNK LD DE,HBX_LOC ; RUNNING LOCATION LD HL,HBX_IMG ; LOCATION IN IMAGE LD BC,HBX_SIZ ; SIZE LDIR ; INSTALL IT LD (HB_CURBNK),A ; RESTORE CURBNK ; ; NEXT, COPY A BIT OF CODE TO DO THE SYSTEM TRANSITION TO ; UPPER MEM. WE CAN BORROW THE PROXY BOUNCE BUFFER FOR THIS. LD HL,Z280_GOSYS LD DE,HBX_BUF LD BC,Z280_GOSYS_LEN LDIR ; ; THEN SYSCALL IT. NOTE THAT THE ROUTINE CALLED DOES NOT ; (RET)URN, IT JUMPS TO HB_RESTART SO THAT THE SYSCALL DOES ; NOT RETURN TO USER MODE. SC HBX_BUF ; SYSCALL ROUTINE ; Z280_GOSYS: ; THIS BIT OF CODE RUNS IN UPPER MEM. IT REMAPS THE LOW MEM ; SYSTEM PAGES TO THE CURRENT BANK. WE LOSE STACK CONTEXT IN ; THE PROCESS, SO IN THIS CASE WE NEED TO JUMP BACK TO CONTINUE ; THE APP BOOT. DI ; NO INTERRUPTS LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY LD A,(HB_CURBNK) ; CURRENT BANK LD B,$10 ; FIRST SYSTEM PDR CALL Z280_BNKSEL ; DO THE SWITCH JP HB_RESTART ; AND RESUME BOOT ; Z280_GOSYS_LEN .EQU $ - Z280_GOSYS ; #ENDIF ; XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; #ENDIF ; .FILL (512 - ($ - HB_WRKBUF)) ; PAD REMAINDER OF WORK BUF ; #IFDEF MG014_MAP ; ; ALIGN TO 32 BYTE BOUNDARY ALIGN($20) ; MG014_STATMAPLO: ; LOWER NIBBLE .DB $08 ; 00 .DB $0C ; 01 .DB $00 ; 02 .DB $04 ; 03 .DB $0A ; 04 .DB $0E ; 05 .DB $02 ; 06 .DB $06 ; 07 .DB $09 ; 08 .DB $0D ; 09 .DB $01 ; 0A .DB $05 ; 0B .DB $0B ; 0C .DB $0F ; 0D .DB $03 ; 0E .DB $07 ; 0F ; MG014_STATMAPHI: ; UPPER NIBBLE .DB $80 ; 00 .DB $C0 ; 01 .DB $00 ; 02 .DB $40 ; 03 .DB $A0 ; 04 .DB $E0 ; 05 .DB $20 ; 06 .DB $60 ; 07 .DB $90 ; 08 .DB $D0 ; 09 .DB $10 ; 0A .DB $50 ; 0B .DB $B0 ; 0C .DB $F0 ; 0D .DB $30 ; 0E .DB $70 ; 0F ; #ENDIF ; HB_DATA_END .EQU $ ; HB_END .EQU $ ; SLACK .EQU BNKTOP - $ ; ; ; #IFDEF MEMINFO .ECHO "SECTION \tSTART\tLENGTH\n" .ECHO "-------------- \t-------\t-------\n" .ECHO "PAGE ZERO \t" \ .ECHO HB_PGZERO_BEG \ .ECHO "\t" \ .ECHO HB_PGZERO_END - HB_PGZERO_BEG \ .ECHO "\n" .ECHO "HCB \t" \ .ECHO HB_HCB_BEG \ .ECHO "\t" \ .ECHO HB_HCB_END - HB_HCB_BEG \ .ECHO "\n" .ECHO "PROXY \t" \ .ECHO HB_PROXY_BEG \ .ECHO "\t" \ .ECHO HB_PROXY_END - HB_PROXY_BEG \ .ECHO "\n" .ECHO "ENTRY \t" \ .ECHO HB_ENTRY_BEG \ .ECHO "\t" \ .ECHO HB_ENTRY_END - HB_ENTRY_BEG \ .ECHO "\n" .ECHO "INTVEC \t" \ .ECHO HB_INTVEC_BEG \ .ECHO "\t" \ .ECHO HB_INTVEC_END - HB_INTVEC_BEG \ .ECHO "\n" .ECHO "SYSINIT \t" \ .ECHO HB_SYSINIT_BEG \ .ECHO "\t" \ .ECHO HB_SYSINIT_END - HB_SYSINIT_BEG \ .ECHO "\n" .ECHO "DISP \t" \ .ECHO HB_DISP_BEG \ .ECHO "\t" \ .ECHO HB_DISP_END - HB_DISP_BEG \ .ECHO "\n" .ECHO "Z280IVT \t" \ .ECHO HB_Z280IVT_BEG \ .ECHO "\t" \ .ECHO HB_Z280IVT_END - HB_Z280IVT_BEG \ .ECHO "\n" .ECHO "SYSAPI \t" \ .ECHO HB_SYSAPI_BEG \ .ECHO "\t" \ .ECHO HB_SYSAPI_END - HB_SYSAPI_BEG \ .ECHO "\n" .ECHO "INTFUNC \t" \ .ECHO HB_INTFUNC_BEG \ .ECHO "\t" \ .ECHO HB_INTFUNC_END - HB_INTFUNC_BEG \ .ECHO "\n" .ECHO "UTIL \t" \ .ECHO HB_UTIL_BEG \ .ECHO "\t" \ .ECHO HB_UTIL_END - HB_UTIL_BEG \ .ECHO "\n" .ECHO "PRTSUM \t" \ .ECHO HB_PRTSUM_BEG \ .ECHO "\t" \ .ECHO HB_PRTSUM_END - HB_PRTSUM_BEG \ .ECHO "\n" .ECHO "DRIVERS \t" \ .ECHO HB_DRIVERS_BEG \ .ECHO "\t" \ .ECHO HB_DRIVERS_END - HB_DRIVERS_BEG \ .ECHO "\n" .ECHO "FONTS \t" \ .ECHO HB_FONTS_BEG \ .ECHO "\t" \ .ECHO HB_FONTS_END - HB_FONTS_BEG \ .ECHO "\n" .ECHO "DATA \t" \ .ECHO HB_DATA_BEG \ .ECHO "\t" \ .ECHO HB_DATA_END - HB_DATA_BEG \ .ECHO "\n" .ECHO "SLACK \t" \ .ECHO HB_END \ .ECHO "\t" \ .ECHO SLACK \ .ECHO "\n" ; #ENDIF ; .ECHO "HBIOS space remaining: " .ECHO SLACK .ECHO " bytes.\n" ; ; DIAGNOSE HBIOS BANK OVERFLOW ; #IF (SLACK < 0) .ECHO "*** ERROR: HBIOS too big!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF ; ; CHECK TO SEE IF WE HAVE ENOUGH HEAP TO CACHE THE CP/M CCP ; AND ONE DISK SECTOR. ALTHOUGH SOME OPERATING SYSTEMS OR APPS ; MAY NOT NEED THIS, THE MOST COMMON ONES DO. CREATING AN HBIOS ; WITHOUT SPACE FOR THIS WILL NOT BE USEFUL. ; #IF ((CCP_SIZ + 512 + 8) > SLACK) .ECHO "*** ERROR: Insufficient HEAP space!!!\n" !!! ; FORCE AN ASSEMBLY ERROR #ENDIF ; ;;;#IF (SLACK < (1024 * 3)) ;;; .ECHO "*** ERROR: Low HEAP space!!!\n" ;;; !!! ; FORCE AN ASSEMBLY ERROR ;;;#ENDIF ; #IFDEF ROMBOOT #IF (ROMSIZE > 0) .FILL SLACK #ENDIF #ENDIF ; .END