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

9698 lines
254 KiB

;
;==================================================================================================
; 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/<plt>_std.asm
; - cfg_<plt>.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]
; - <drivers...>.asm
; - <fonts...>.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
;
; IF BUILDING FULL BOOT ROM, INCLUDE INFO MACROS
;
#IFDEF ROMBOOT
#DEFINE BNKINFO
#DEFINE MEMINFO
#DEFINE DEVINFO
#DEFINE SYSINFO
#ENDIF
;
; 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
#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
;
; SWITCHES SHADOW COPY (FROM RTC/NVR) START AT $30
;
.FILL (HCB + $30 - $),0
;
; First byte (header) of NVRAM = "W" if fully initialised, or a ststus byte
; = 0 if no NVRAM detected, or = 1 If NVR exists, but not configured
CB_SWITCHES .DB 0 ; this byte is set during init
;
; Byte 0: (L)
; Bit 7-0 DISK BOOT SLice Number to Boot -> default = 0
; Bit 7-0 ROM BOOT (alpha character) Application to boot -> default = "H"
; Byte 1: (H)
; Bit 7 - ROM/DISK - Rom or Disk Boot -> Default=ROM=1 (BOOT_DEFAULT is Numeric/Alpha)
; Bit 6-0 - DISK BOOT Disk Unit to Boot (0-127) -> default = 0
CB_SWDEFBOOT .DB 'H' ; (WORD) DEFAULT BOOT NVR OPTIONS. USED By ROMLDR
.DB DBOOT_ROM ; Default Boot - ROM Application
;
; Byte 0: (L)
; Bit 7-6 - Reserved
; Bit 5 - AUTO BOOT Auto boot, default=false (BOOT_TIMEOUT != -1)
; Bit 4 - Reserved
; Bit 3-0 - BOOT_TIMEOUT in seconds (0-15) 0=immediate -> default=3
CB_SWAUTOB .DB 0 ; AUTO BOOT NVR OPTIONS. USED By ROMLDR
;
; CHECKSUM
CB_SWITCHCK .DB 0 ; CHECKSUM (XOR=0), INCLUDES HEADER and CB_VERSION
;
; 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
;
;--------------------------------------------------------------------------------------------------
; NV-SWITCH INITITIALISATION
; Requires functional RTC NVR
;--------------------------------------------------------------------------------------------------
;
NVR_INIT:
; Check for the existence of NV RAM by attempting to read a byte
LD B,BF_RTCGETBYT ; GET RTC BYTE
LD C,0 ; FIRST Byte address in RTC
CALL RTC_DISPATCH ; CALL RTC
JR NZ,NVR_INIT_END ; GET BYTE Failed; Noting to do, HCB is correct. Status =0
;
CALL NVSW_READ ; read the full data into hcb
JR NZ, NVR_INIT_DEF ; failed to correclty read data
;
CALL NVSW_CHECKSUM ; checksum calc into A
LD HL,CB_SWITCHCK ; address of HCB value
CP (HL) ; compare Caculated Check, with hcb Check Value
JR Z,NVR_INIT_END ; The same so success
NVR_INIT_DEF:
; failed Read or Checksum
CALL NVSW_DEFAULTS ; set defaults into HCB, which include the "W" first byte
LD HL,CB_SWITCHES ; which is incorrect, need the value of 1
LD (HL),1 ; to indicate we while not inited, we do have NVRAM
NVR_INIT_END:
;
;--------------------------------------------------------------------------------------------------
; 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
; GAP TO E0
CP BF_EXT ; SKIP TO BF_EXT VALUE AT $E0
JR C,HB_DISPERR ; ERROR IF LESS THAN BF_EXT
CP BF_EXT + $10 ; $E0-$EF: EXTENDED
JP C,EXT_DISPATCH
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
;
;--------------------------------------------------------------------------------------------------
; EXTENDED FUNCTION DISPATCHER
;--------------------------------------------------------------------------------------------------
;
; B: FUNCTION
;
EXT_DISPATCH:
LD A,B ; GET REQUESTED FUNCTION
AND $0F ; ISOLATE SUB-FUNCTION
JP Z,EXT_SLICE ; $E0
DEC A
JP HB_DISPERR ; ERROR COULD NOT FIND FUNCTION
;
;--------------------------------------------------------------------------------------------------
; 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
JP HB_DISPERR ; ERROR COULD NOT FIND FUNCTION
;
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 $
;
;==================================================================================================
; EXTENSION API FUNCTIONS
;==================================================================================================
;
HB_EXTAPI_BEG .EQU $
;
;--------------------------------------------------------------------------------------------------
; SLICE CALCULATE - 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 0xE0 EXT_SLICE
; 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
; Other errors Include ERR_NOUNIT, ERR_NOMEDIA,
; If any error is raised the other return values are undefined
; 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.
;--------------------------------------------------------------------------------------------------
;
SLICE_SLICE .DB 0 ; SLICE ARGUMENT (E)
SLICE_UNIT .DB 0 ; UNIT ARGUMENT (D)
SLICE_DEVATT .DB 0 ; DEVICE ATTRIBUTES
SLICE_MID .DB 0 ; DISCOVERED MEDIAID
;
SLICE_WRKSTA .EQU $
SLICE_LBAOFF .FILL 4,0 ; START OF PARTITION / SLICE (SECTORS)
SLICE_LBASIZ .FILL 4,0 ; SIZE OF MEDIA / PARTITION (SECTORS)
SLICE_SPS .DW 0 ; DISCOVERED SECTORS PER SLICE (16BIT)
SLICE_FND .DB 0 ; DID WE FIND A NON CPM PARTITION
SLICE_WRKSIZ .EQU $ - SLICE_WRKSTA ; SIZE OF WORKING DATA
;
EXT_SLICE:
; SAVE CALL ARGUMENTS
LD (SLICE_SLICE),DE ; STORES DE -> SLICE/UNIT PARAMETERS
; READ DEVICE INFORMATION USING DIODEVICE FUNCTION
LD A,(SLICE_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 (SLICE_DEVATT),A ; STORE DEVICE ATTRIBUTES
;
; DETERMINE MEDIA IN DRIVE USING DIOMEDIA FUNCTION
LD A,(SLICE_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
LD (SLICE_MID),A ; INIT VALUE, MAY BE USED LATER
OR A ; SET FLAGS
JR Z,EXT_SLICE1A ; BAIL IF NO MEDIA
CP MID_HD ; IS IT A HARD DISK
JR Z,EXT_SLICE1B ; IS HD, CONTINUE TO PROCESS HD
;
; NOT A HARD DISK, CHECK SLICE = 0
LD A,(SLICE_SLICE) ; GET THE SLICE
OR A ; SET FLAGS
JP NZ,EXT_SLICE5C ; SLICE NOT ZERO - SIGNAL ERROR AND RETURN
;
EXT_SLICE1A:
; RETURN MEDIA ID (NOT HD) WITH SUCCESS
LD DE,0 ; LBA VALUE WILL BE ZERO
LD HL,0
JP EXT_SLICE6A ; RETURN SUCCESS
;
EXT_SLICE1B:
; FOUND HD, NEED TO PROCESS MBR / PART TABLE
; CLEAR WORKING STORAGE
LD HL,SLICE_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,SLICE_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,(SLICE_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,(SLICE_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,EXT_SLICE3C ; NO MATCH, NO PART TABLE
INC HL ; NEXT BYTE
LD A,(HL) ; GET SECOND BYTE
CP $AA ; CHECK SECOND BYTE
JR NZ,EXT_SLICE3C ; 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
EXT_SLICE2A:
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,EXT_SLICE3B ; HD1K, GRAB THE LBA OFFSET
CP $00 ; IS ANOTHER PARTITION TYPE, NOT CPM
JR NZ,EXT_SLICE3A ; OTHER VALID PART TYPE
EXT_SLICE2B:
LD DE,12 ; REMAINING SIZE TO GET TO NEXT PARTITION
EXT_SLICE2C:
ADD HL,DE ; BUMP TO NEXT PARTITION ENTRY - TYPE
DJNZ EXT_SLICE2A ; LOOP THRU TABLE
JR EXT_SLICE3C ; READ ALL - NO CP/M PARTITION FOUND
;
EXT_SLICE3A
; FOUND OTHER (NOT CPM) PARTITION
LD A,(SLICE_FND) ; HAVE WE ALREADY FOUND PROCESSED NON CPM
OR A ; PARTITION, AND CAPTURED ITS START SECTOR, SO
JR NZ,EXT_SLICE2B ; 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,SLICE_LBASIZ ; FROM PARTION LBA OFFSET (HL) - TO WORKING LBA SIZE (DE)
LDIR ; COPY 4 BYTES
POP BC ; RESTORE
;
LD A,$FF
LD (SLICE_FND),A ; SET FOUND FLAG, SO DONT PROCESS ANY OTHERS
LD DE,8 ; AND INC HL BY 8 TO GET TO NEXT PARITION
JR EXT_SLICE2C ; CONTINUE TO NEXT PARTITION
;
EXT_SLICE3B:
; FOUND CP/M (HD1K) PARTITION - RECORD THIS
LD A,MID_HDNEW ; DISCOVERED HD1K MEDIA
LD (SLICE_MID),A ; STORE IT
LD BC,SPS_HD1K ; DISCOVERED HD1K MEDIA
LD (SLICE_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,SLICE_LBAOFF ; LOC TO STORE OFFSET AND SIZE
LD BC,8 ; 8 BYTES - LBA OFFSET AND SIZE
LDIR ; COPY IT
;
JR EXT_SLICE4A ; CONTINUE AND COMPUTE THE SLICE
;
EXT_SLICE3C:
; NO PARTITION TABLE FOUND / NO CPM PARTITION
LD A,(SLICE_SLICE) ; IF SLICE = 0, WE BOOT THE DISK ITSELF. IGNORE SLICE(S)
OR A ; SET FLAGS FOR SLICE ARGUMENT, IF SLICE==0
JR Z,EXT_SLICE5Z ; BYPASS ALL CALCS / CHECKS - JUST BOOT THE DISK
; BOOT SLICE WITH LEGACY SPS
LD BC,SPS_HD512 ; WITH HD512 SECTORS PER SLICE
LD (SLICE_SPS),BC ; STORE IT
; DID WE FIND AN OTHER (NOT CPM) PARTITION
LD A,(SLICE_FND) ; HAVE WE ALREADY FOUND PROCESSED NON CPM
OR A ; PARTITION, AND CAPTURED ITS START SECTOR, SO
JR NZ,EXT_SLICE4A ; 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,(SLICE_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 (SLICE_LBASIZ),HL ; LOWER ORDER BYTES - HL
EX DE,HL
LD (SLICE_LBASIZ+2),HL ; HIGHER ORDER BYTES - DE
;
EXT_SLICE4A:
; 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,(SLICE_SPS)
LD A,(SLICE_SLICE)
OR A ; SLICE NUMBER - SET FLAGS TO CHECK LOOP CTR
JR Z,EXT_SLICE5A ; NOTHING TO COUNT
EXT_SLICE4B:
ADD HL,BC ; ADD ONE SLICE (SPS) TO LOW WORD
JR NC,EXT_SLICE4C ; CHECK FOR CARRY
INC DE ; IF SO, BUMP HIGH WORD
EXT_SLICE4C:
DEC A ; DEC LOOP (SLICE) COUNTER
JR NZ,EXT_SLICE4B ; AND LOOP
;
EXT_SLICE5A:
; 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,EXT_SLICE5B
INC DE
EXT_SLICE5B:
; 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,(SLICE_LBASIZ+0) ; CAPACITY LSW
POP DE ; REQUIRED LSW
SBC HL,DE ; CAPACITY - REQUIRED (LSW)
LD HL,(SLICE_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,EXT_SLICE6 ; IF WE HAVE ENOUGH CAPACITY
;
EXT_SLICE5C:
; SLICE WONT FIT - STOP AND RETURN ERROR
LD DE,0
LD HL,0 ; EMTY OFFSET IN DEHL
LD A,(SLICE_DEVATT)
LD B,A ; DEVICE ATTRIBUTES IN B
LD A,(SLICE_MID)
LD C,A ; RETURN MEDIA ID IN C
LD A,ERR_RANGE ; OTHERWISE SIGNAL NOT ENOUGH CAPACITY
OR A
RET
;
EXT_SLICE5Z:
LD HL,0 ; BOOT THE DISK TO LBA = 0
LD DE,0 ;
;
EXT_SLICE6:
; FINAL CALC AND RETURN SUCCESS
; ADD PARTITION OFFSET (START) TO DEHL TO GET ABSOLUTE SLICE OFFSET
LD BC,(SLICE_LBAOFF+0) ; LSB OF LBA OFFSET
ADD HL,BC ; ADD LSB OFFSET
EX DE,HL ; FLIP DE INTO HL
LD BC,(SLICE_LBAOFF+2) ; MSB OF LBA OFFSET
ADC HL,BC ; ADD MSB
EX DE,HL ; FLIP BACK DE:HL AS SLICE OFFSET
;
EXT_SLICE6A:
; SLICE FITS - RETURN CORRECTLY
LD A,(SLICE_DEVATT)
LD B,A ; DEVICE ATTRIBUTES IN B
LD A,(SLICE_MID)
LD C,A ; RETURN MEDIA ID IN C
XOR A ; CLEAR FLAGS
RET ; RETUNING DE:HL AND C
;
;--------------------------------------------------------------------------------------------------
;
HB_EXTAPI_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 $12 ; LEFT FOR BACKWRD COMPATABILITY
JP Z,EXT_SLICE ; FUNCTION MOVED TO TOP LEVEL $E0
; REMOVING THE ABOVE CAUSED UPGRADE ISSUES FOR EARLY ADOPTERS
; SINCE OS BOOT LOADERS DEPEND ON IT. WITHOUT CAN LEAVE OS
; UNBOOTABLE AND MIGRATION HARDER - Oct 2024
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_SWITCH
JP Z,SYS_GETSWITCH
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 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
;
; GET SWITCH
; ON ENTRY:
; D: SWITCH KEY
; 0 -> ILLEGAL / RESERVED
; 1-FE -> SWITCH
; FF -> DONT GET VALUE CHECK THE STATUS OF NVRAM -> Returning
; A=0 if no NVRAM exists. with NZ flag set
; A=1 if NVRAM is present. with Z flag set
; A='W' if NVRAM is fullly inited. with Z flag set
; Note the NZ flag can be used to detect and return an error condition
; RETURNS:
; HL: SWITCH VALUE 8/16 BIT
;
SYS_GETSWITCH:
; PUSH DE
; CALL NVSW_CONFIG ; make sure shadow copy is inited
; POP DE ;
; RET NZ ; Configuration Failed, thus cant continue
;
LD A,D
CP $FF ; test if want to just get NVRAM status
JP Z,NVSW_STATUS ; Check the Status - Call and Return
;
CALL SWITCH_RES ; D SWITCH NUMBER -> OUT HL address, E FLAGS
RET NZ ; IF NZ FLAG SET THEN ISSUE
;
LD B,0 ; Clear upper byte
LD C,(HL) ; Get LOW Order Switch Data
LD A,1 ; Compare with 1 (byte)
CP E ; Compare The byte count from SWITCH_RES
JR NC,SYS_GETSWITCH2 ; 1 byte or less, skip over
INC HL ; next byte pos in a 2 Byte Switch
LD B,(HL) ; Get HIGH Order Switch Data
;
SYS_GETSWITCH2:
LD H,B ; retun Result in HL
LD L,C
XOR A ; signal success
RET
#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_SWITCH
JP Z,SYS_SETSWITCH
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 SWITCH
; ON ENTRY:
; D: SWITCH KEY
; 0 -> ILLEGAL / RESERVED
; 1-254 -> SWITCH
; FF -> REINIT DEFAULT VALUES
; HL: SWITCH VALUE 8/16 BIT
;
SYS_SETSWITCH:
CALL NVSW_STATUS ; Check the status of NV RAM
RET NZ ; IF NZ then we cant continue, return NZ at this point
;
LD A,D ; switch # argument
CP $FF ; test if want to reset NVRAM
JP Z,NVSW_RESET ; then perform reset function. CALL AND RETURN
;
LD B,H ; move value to write into BC
LD C,L
CALL SWITCH_RES ; IN D SWITCH NUMBER -> OUT HL address, E FLAGS
RET NZ ; RETURN IF NZ - swich number illegal
;
LD (HL),C ; Save LOW Order Switch Data
LD A,1 ; Compare with 1 (byte) switch
CP E ; Compare
JR NC,SYS_SETSWITCH1 ; 1 byte or less, skip over
INC HL ; next byte pos
LD (HL),B ; Save High Order Switch Data
;
SYS_SETSWITCH1:
JP NVSW_UPDATE ; do a write to NVR, CALL AND RETURN
;
; Utility function to convert switch number into lookup
; INPUT
; D SWITCH NUMBER
; OUTPUT
; E with Byte count (1,2) for switch, or 0 if switch illegal
; HL Memory Address (CB_SWITCHES + offset)
SWITCH_RES:
LD A,SWITCH_LEN ; lengt of target array (below)
CP D ; check we fit in the loop
JR C,SWITCH_RES1 ; overflow table to abort
;
LD HL,SWITCH_TAB ; Lookup table below
LD A,D ; plus the offset switch number
CALL ADDHLA ; get address of lookup table
LD E,(HL) ; E (OUT) nubmer of bytes in switch
;
LD HL,CB_SWITCHES ; BASE ADDRESS OF SHADDOW DATA
LD A,D ; Add The offset to the address
CALL ADDHLA ; Final address of Switch Data
;
XOR A ; signal success
RET
SWITCH_RES1:
OR $FF ; signal failure
RET
;
; Switch number maps drectly into the HCB data, so to account
; for double bytes words, we need a table (loopkup)
; to defines how to map Applicability of Each Swicth Number
; 0->Cant be Used; 1->Single Byte Value; 2->Double Byte Value
;
SWITCH_TAB:
.DB 0 ; Switch 0 is header, cant be used
.DB 2 ; Switch 1 - (WORD)
.DB 0 ; Switch (byte 2) of prior word, not used
.DB 1 ; Switch 3 - (BYTE)
.DB 0 ; Last byte is checksum, cant be used
SWITCH_LEN .EQU $ - SWITCH_TAB - 2
;
; 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
;
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
;
;--------------------------------------------------------------------------------------------------
; ROUTINES FOR NON VOLITILE (NVRAM) SWITCHES
;--------------------------------------------------------------------------------------------------
;
; Return Status
; A=0 if no NVRAM exists. with NZ flag set
; A=1 if NVRAM is present. with Z flag set
; A='W' if NVRAM is fullly inited. with Z flag set
; Note the NZ flag can be used to detect and return an error condition
;
NVSW_STATUS:
LD A,(CB_SWITCHES) ; the status byte
LD B,A ; save it
AND 1 ; applies to 'W' and $01 status, -> 1
CP 1 ; set NZ based on A = 1
LD A,B ; return the
RET
;
; RESET CONTENTS OF NVRAM, STORING INTO
; RETURN NONZERO IF WRITTEN - ZERO IF NOT WRITTEN
;
NVSW_RESET:
CALL NVSW_DEFAULTS ; copy defaults into HCB
; Fall Through and Update (write) status
; JP NVSW_UPDATE
;
; UPDATE HBIOS SHADOW TO NVRAM, AFTER SETTING HBIOS VALUE
; RETURN NONZERO IF WRITTEN - ZERO IF NOT WRITTEN
;
NVSW_UPDATE:
CALL NVSW_CHECKSUM ; CALC checksum into A
LD (CB_SWITCHCK),A ; store checksum in hcb
CALL NVSW_WRITE ; write the bytes to nvr
RET Z ; Successful write, return
; write failed for some reason ???
LD A,1
LD (CB_SWITCHES),A ; ensure hcb signature=1
OR $FF ; failure
RET ; return NZ flag
;
; PERFORM CHECKSUM CALC OF DATA IN HCB
; RETURN A REGISTER -> CONTAINING THE CHECKSUM
;
NVSW_CHECKSUM:
XOR A
LD B,NVSW_SIZE ; NUMBER OF BYTES TO CHECK
LD HL,CB_SWITCHES ; First Byte in HBIOS (HCB)
NVSW_CHECKSM1:
XOR (HL) ; XOR The Byte
INC HL ; HL address
DJNZ NVSW_CHECKSM1 ; LOOP
XOR RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO
XOR RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO
RET
;
; COPY DEFAULTS INTO HCB
;
NVSW_DEFAULTS:
LD HL,NVSW_DEFAULT ; Copy default bytes from
LD DE,CB_SWITCHES ; to hbios HCB location
LD BC,NVSW_SIZE ; number of bytes top copy
LDIR ; copy bytes
RET
;
; LOAD BYTES FROM NVR - INTO HBIOS DCB
; RETURN ZERO IF READ SUCCESS, NON-ZERO IF CANT READ
;
NVSW_READ:
LD B,NVSW_SIZE + 1 ; NUMBER OF BYTES, + 1 for CHECKSUM
LD C,0 ; FIRST Byte address in RTC
LD HL,CB_SWITCHES ; First Byte in HBIOS (HCB)
NVSW_READ1:
PUSH HL ; SAVE ADDRESS
PUSH BC ; Save Loop counter
LD B,BF_RTCGETBYT ; GET RTC BYTE (at a time), requires loop
CALL RTC_DISPATCH ; CALL RTC
POP BC ; Restore Loop
POP HL ; restore Block pointer
RET NZ ; ERROR JUST RETURN
LD (HL),E ; store IT
INC C ; RTC Byte address
INC HL ; HL address
DJNZ NVSW_READ1 ; LOOP to the next byte
NVSW_READ2:
LD A,(CB_SWITCHES) ; FIRST BYTE
CP 'W' ; MUST BE 'W'
RET ; ZERO IF OK, NON-ZERO IF ISSUE
;
; SAVE BYTES FROM HBIOS DCB - INTO NVR
; RETURN ZERO IF SUCCESS, NON-ZERO IF CANT WRITE
;
NVSW_WRITE:
LD B,NVSW_SIZE + 1 ; NUMBER OF BYTES, + 1 for CHECKSUM
LD C,0 ; FIRST Byte address in RTC
LD HL,CB_SWITCHES ; First Byte in HBIOS (HCB)
NVSW_WRITE1:
PUSH HL ; SAVE ADDRESS
PUSH BC ; Save Loop counter
LD E,(HL) ; Value to Write
LD B,BF_RTCSETBYT ; SET RTC BYTE
CALL RTC_DISPATCH ; CALL RTC
POP BC ; Restore Loop
POP HL ; restore Block pointer
RET NZ ; ERROR JUST RETURN
INC C ; RTC Byte address
INC HL ; HL address
DJNZ NVSW_WRITE1 ; LOOP, One Byte at a Time
NVSW_WRITE2:
XOR A ; SUCCESS
RET ; ZERO IF OK, NON-ZERO IF ISSUE
;
; DEFAULT VALUES FOR NVRAM, USED TO RESET NVR
;
NVSW_DEFAULT:
.DB 'W' ; Signature Byte
.DB 'H' ; Default Boot - Rom Application [H]elp
.DB DBOOT_ROM ; Default Boot - ROM Application
.DB 0 ; Auto Boot - NO auto boot
; Configure above byte from (BOOT_TIMEOUT != -1)
; SIZE OF NVR BYTES
NVSW_SIZE .EQU $ - NVSW_DEFAULT
;
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 "EXTAPI \t" \ .ECHO HB_EXTAPI_BEG \ .ECHO "\t" \ .ECHO HB_EXTAPI_END - HB_EXTAPI_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