Files
RomWBW/Source/HBIOS/hbios.asm
Wayne Warthen 4ee14cbefa Tweak S100 Z80 IOBYTE Handling
Attempting to ensure that RomWBW properly "follows" the IOBYTE settings at implemented in the dedicated S100 Z80 Monitor.  Specifically, the bit that controls the boot console.
2025-10-13 16:54:20 -07:00

9748 lines
257 KiB
NASM

;
;==================================================================================================
; 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>_<cfg>.asm
; - cfg_<plt>.asm
; - cfg_MASTER.asm
; - hbios.inc
; - [z180.inc]
; - [z280.inc]
; - [eipc.inc]
; - layout.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
;
; SC130/SC140/SC5xx/SC7xx: LED Port=0x0E, bit 0, inverted, dedicated port (LEDMODE_STD)
; SC131: LED Port=0x0E, bit 2, inverted, dedicated port (LEDMODE_SC)
; 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)
; RPH?
; DUO: LED Port=0x94, bits 1-0, normal, shared w/ RTC port (LEDMODE_RTC)
; S100 Z180 SBC: 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
;
; PUSH/POP INTERRUPT STATE
; AF IS DESTROYED IN ALL CASES
;
; IF NMOSCPU IS SET, THE INT STATUS BUG WORKAROUND IS USED
; NMOS Z80 BUG PREVENTS USE OF "LD A,I" TO GATHER IFF2 INTO P/V FLAG
; SEE http://www.z80.info/zip/ZilogProductSpecsDatabook129-143.pdf
;
#IF NMOSCPU
#DEFINE HB_PUSHINT \
#DEFCONT \ XOR A
#DEFCONT \ PUSH AF
#DEFCONT \ POP AF
#DEFCONT \ LD A,I
#DEFCONT \ JP PE,$+10
#DEFCONT \ DEC SP
#DEFCONT \ DEC SP
#DEFCONT \ POP AF
#DEFCONT \ AND A
#DEFCONT \ JR NZ,$+3
#DEFCONT \ SCF
#DEFCONT \ HB_DI
#DEFCONT \ PUSH AF
#ELSE
#DEFINE HB_PUSHINT \
#DEFCONT \ LD A,I
#DEFCONT \ HB_DI
#DEFCONT \ PUSH AF
#ENDIF
#IF NMOSCPU
#DEFINE HB_POPINT \
#DEFCONT \ POP AF
#DEFCONT \ JR NC,$+3
#DEFCONT \ EI
#ELSE
#DEFINE HB_POPINT \
#DEFCONT \ POP AF
#DEFCONT \ JP PO,$+4
#DEFCONT \ EI
#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
;
; IF VDAEMU_SEKBD AND AUTOCON ARE BOTH ACTIVE, THEN THE BOOT LOADER
; PROMPT WILL BE CONFUSED BECAUSE IT WILL POLL THE SHARED SERIAL PORT
; FOR BOTH DEVICES.
;
#IF ((VDAEMU_SERKBD != $FF) & (AUTOCON == TRUE))
.ECHO "*** ERROR: VDAEMU_SERKBD CANNOT BE COMBINED WITH AUTOCON!!! ***\n"
.ECHO "SET VDAEMU_SERKBD = $FF OR SET AUTOCON = FALSE\n"
!!! ; FORCE AN ASSEMBLY ERROR
#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 ASSOCIATED
; 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 status 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 (AUTO_CMD is Numeric/Alpha)
; Bit 6-0 - DISK BOOT Disk Unit to Boot (0-127) -> default = 0
CB_SW_AB_OPT .DB 'H' ; (WORD) AUTO BOOT NVR OPTIONS. USED By ROMLDR
.DB BOPTS_ROM ; Boot Opts - 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_SW_AB_CFG .DB 0 ; AUTO BOOT NVR CONFIG. USED By ROMLDR
;
; CHECKSUM
CB_SW_CKSUM .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 $
HBX_IMG .EQU $ ; LOC OF HBX IMAGE IN HBIOS IMAGE BANK
;
;;; .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_EZ512)
AND $F ; HCS mask off high nibble
BIT 3,A ; HCS if banks $8-$F, set bit 6
JR Z,MM_EZ512_BANK0TO7
AND 7 ; HCS clear bit 3
OR $40 ; HCS set bit 6 for banks $8-$F
MM_EZ512_BANK0TO7:
OR $80 ; HCS set bit 7 to keep RAM enabled
OUT ($0C),A ; HCS write to the bank control register
RET ; DONE
#ENDIF
;
#IF (MEMMGR == MM_MBC)
;
#IF (INTMODE == 1)
LD (HBX_MMA),A ; SAVE ACCUM
HB_PUSHINT
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)
HB_POPINT
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)
;
; *** DEPRECATED ***
;
; 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
;
#IF (MEMMGR == MM_SZ80)
;
; The S100 Z80 CPU implements a custom memory manager that allows mapping the 2
; lowest 16K portions of CPU address space ($0000-$3FFFF, and $4000-$7FFF).
; Each of these banks can be mapped to any physical 16K bank.
; The physical 16K banks are 16K aligned. The memory manager
; can address a maximum of 1MB of physical memory. Which is
; 64 x 16K banks (bank numbers $00-$3F)
;
; The top 32K of CPU address space ($8000-$FFFF) is statically mapped
; to physical banks $02 & $03. RomWBW is designed to have the top
; 32K of CPU address space assigned to the last two banks of
; RAM. So the RomWBW memory manager for this board (MM_SZ80)
; rotates the requested bank numbers by 4. With wrapping, this
; causes a RomWBW request for the top two banks to be mapped to
; physical banks $02 & $03.
;
; Z80 CPU Physical: $00 $01 $02 $03 ... $38 $39 $3A $3B $3C $3D $3E $3F
; RomWBW Logical: $04 $05 $06 $07 ... $3C $3D $3E $3F $00 $01 $02 $03
;
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:
ADD A,2 ; OFFSET TO SKIP OVER FIXED PAGES
RLA ; LOW 2 BITS
RLA ; ... ARE NOT USED
RLA ; TIMES 2 - GET 16K PAGE INSTEAD OF 32K
OUT ($D2),A ; BANK_0: 0K - 16K
ADD A,4 + 1 ; +1 TO KEEP MONITOR ROM INACTIVE
OUT ($D3),A ; BANK_1: 16K - 32K
RET ; DONE
#ENDIF
;
#IF (MEMMGR == MM_MSX)
; MSX_NOTE: THE MSX PLATFORM PRELOADS THE ROM IMAGE IN RAM AND THE BANK ID ROM/RAM FLAG IS IGNORED
RES 7,A ; CLEAR RAM BIT
ADD A,RAMBIAS ; ADD 2 x 32K - RAM STARTS FROM 16K SEGMENT 4
RLCA ; TIMES 2 - GET 16K PAGE INSTEAD OF 32K
OUT (MPGSEL_0),A ; BANK_0: 0K - 16K
INC A ;
OUT (MPGSEL_1),A ; BANK_1: 16K - 32K
RET ; DONE
#ENDIF
;
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; Copy Data - Possibly between banks. This resembles CP/M 3, but
; usage of the HL and DE registers is reversed.
; Caller MUST 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 (INTMODE == 1)
#IF (CPUFAM == CPU_Z280)
PUSH HL
PUSH BC
LD C,Z280_MSR
LDCTL HL,(C)
POP BC
EX (SP),HL
HB_DI
#ELSE
HB_PUSHINT
#ENDIF
#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 (INTMODE == 1)
#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
HB_POPINT
#ENDIF
#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 PS2KBD | 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) HB_IDENT: ADDRESS OF HBIOS IDENT INFO DATA BLOCK
.DW HBX_IDENT ; (+30) RESERVED (USED BY MSX PLATFORM), SET TO HBX_IDENT FOR BACKWARD COMPATIBILITY
;
.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
;
; IF WE ARE RESTARTING IN RAM, WE NEED TO RESET THE INTERRUPTS
; ENABLED FLAG. IF THIS IS A NORMAL ROM START, THIS DOES
; NOTHING AND THE FLAG IS RESET BY DEFAULT.
XOR A
LD (INTSENAB),A
;
;
#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_SZ80)
; REMOVE FPGA ROM MONITOR FROM THE CPU ADDRESS SPACE
LD A,%00000010
OUT ($07),A
#ENDIF
#ENDIF
;
; S100 Z80 MMU INITIALIZATION
;
#IF (MEMMGR == MM_SZ80)
;
#IFDEF ROMBOOT
LD A,4 << 2
OUT ($D2),A
LD A,(5 << 2) + 1 ; +1 TO DEACTIVATE MONITOR ROM
OUT ($D3),A
#ENDIF
;
#ENDIF
;
#IF (MEMMGR == MM_MSX)
LD A,((ROMSIZE + RAMSIZE) / 16) - 2 + RAMBIAS * 2
OUT (MPGSEL_2),A
INC A
OUT (MPGSEL_3),A
#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
#IF (PLATFORM == PLT_MSX)
; MSX_NOTE: AVOID WRITING TO SECONDARY SLOT REGISTER AT ADDRESS $FFFF
LD BC,HBX_SIZ-2 ; SIZE OF PROXY
#ELSE
LD BC,HBX_SIZ ; SIZE OF PROXY
#ENDIF
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,HWMON_IMGLOC ; EXECUTION RESUMES HERE
CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN
JR $ ; 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
JR $ ; 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 ONCE 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 PERFORM 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) | (WDOGMODE != WDOG_NONE))
;
;;; 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_SBCB0)
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
#IF ((PLATFORM == PLT_DUO)
#IF (BT_REC_TYPE == BT_REC_DUORI)
IN A,($78 + 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:
;
; S100 Z80 CONSOLE SELECTION
; THE S100 Z80 USES AN IOBYTE BIT TO SELECT BETWEEN SERIAL PORT
; AND THE PROPELLER CONSOLE. THE PROPELLER CONSOLE IS ASSUMED TO
; BE THE CRT DEVICE. WE USE THE IOBYTE BIT TO SET THE STARTUP
; CHARACTER DEVICE TO THE PROPELLER CONSOLE IF APPROPRIATE. THIS
; DOES ASSUME THAT THE CRT DEVICE IS THE PROPELLER CONSOLE OR THERE
; IS NO CRT DEVICE.
;
;
#IF ((PLATFORM == PLT_SZ80) & (MEMMGR == MM_SZ80))
IN A,($EF) ; GET IO BYTE
AND %00100000 ; ISOLATE CONSOLE BIT
JR Z,HB_SZ80CON_Z ; IF ZERO, BYPASS CONSOLE SWITCH
LD A,(CB_CRTDEV) ; GET CRT DEVICE
CP $FF ; CHECK FOR NO H/W
JR Z,HB_SZ80CON_Z ; IF ZERO, BYPASS CONSOLE SWITCH
LD (CB_CONDEV),A ; SET CONSOLE DEVICE
;
HB_SZ80CON_Z:
;
#ENDIF
;
; 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
;
; PERFORM A RESET OPERATION ON ALL CHARACTER DEVICES THAT HAVE BEEN
; INSTALLED. THIS SHOULD CORRECT ANY PROBLEMS IF A PROBE DESTROYED
; THE PROGRAMMING OF ANOTHER DEVICE.
;
LD A,(CIO_CNT) ; NUMBER OF CHARACTER DEVICES
OR A ; CHECK FOR ZERO TO AVOID CRASHING
JR Z,HB_CHRES_Z ; BYPASS IF NONE
LD B,A ; SETUP LOOP COUNTER
LD C,0 ; DEVICE INDEX
HB_CHRES:
PUSH BC ; SAVE LOOP CONTROL
LD B,BF_CIOINIT ; HBIOS RESET FUNCTION
LD DE,$FFFF ; NO CONFIG CHANGES
CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY
POP BC ; RECOVER LOOP CONTROL
INC C ; NEXT DEVICE
DJNZ HB_CHRES ; LOOP AS NEEDED
HB_CHRES_Z:
;
;--------------------------------------------------------------------------------------------------
; 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.
;
#IF (BOOT_PRETTY)
PRTX(STR_PLT_PRETTY)
#ENDIF
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
;--------------------------------------------------------------------------------------------------
;
#IFDEF TESTING
;
INTTEST:
; TEST TO SEE IF SOMEBODY ENABLED INTS EARLY!
LD A,I
JP PO,INTTEST_Z ; IF PO, INTS DISABLED AS EXPECTED
PRTX(STR_INTWARN) ; WARNING
JR INTTEST_Z ; CONTINUE
;
STR_INTWARN .TEXT "\r\n\r\nWARNING: INTERRUPTS ENABLED TOO EARLY!!!$"
;
INTTEST_Z:
;
#ENDIF
;
HB_EI ; INTERRUPTS SHOULD BE OK NOW
;
#IF (INTMODE != 0)
OR $FF ; TRUE
LD (INTSENAB),A ; SET INTERRUPTS ENABLED FLAG
#ENDIF
;
;--------------------------------------------------------------------------------------------------
; 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
;#IF (MEMMGR == MM_MON) ; DEPRECATED
; .TEXT "MON$"
;#ENDIF
#IF (MEMMGR == MM_EZ512)
.TEXT "EZ512$"
#ENDIF
#IF (MEMMGR == MM_SZ80)
.TEXT "SZ80$"
#ENDIF
#IF (MEMMGR == MM_MSX)
.TEXT "MSX$"
#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 INITIALISATION
; 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_SW_CKSUM ; address of HCB switch checksum 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_SZ80) & (MEMMGR == MM_Z2))
; 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
;
INITSYS3A:
;
;--------------------------------------------------------------------------------------------------
; 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
;--------------------------------------------------------------------------------------------------
;
; WE CAN GET HERE 2 WAYS. ON A COLD START, WE JUST FALL THROUGH FROM
; ABOVE. ON A WARM START, INITSYS4 IS INVOKED FROM SYS_RESWARM.
; REGISTER E IS SET TO INDICATE WHICH OF THESE IF OCCURRING SO THAT
; ROMLDR CAN BEHAVE AS APPROPRIATE.
;
LD E,START_COLD ; SIGNAL A COLD START
;
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
#ELSE
LD SP,HBX_LOC ; STACK JUST BELOW HBIOS PROXY
#ENDIF
;
DIAG(0) ; CLEAR BOOT DIAG LED(S)
FPLEDS(DIAG_00) ; CLEAR FP LEDS
;
; CHAIN TO ROM LOADER (ROMLDR)
;
#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
JR $ ; 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) | (PLATFORM == PLT_DUO))
.DW UART_PREINIT
; .DW CALLDUMMY
#ENDIF
;
HB_PCINITRLEN .EQU (($ - HB_PCINIT_REC) / 2)
;
HB_INIT_REC:
;
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC) | (PLATFORM == PLT_DUO))
.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 (CVDUENABLE)
.DW CVDU_PREINIT
#ENDIF
#IF (VGAENABLE)
.DW VGA_PREINIT
#ENDIF
#IF (GDCENABLE)
.DW GDC_PREINIT
#ENDIF
#IF (TMSENABLE)
.DW TMS_PREINIT
#ENDIF
#IF (SCONENABLE)
.DW SCON_PREINIT
#ENDIF
.DW TERM_PREINIT ; ALWAYS DO THIS ONE
#IF (PIOENABLE)
.DW PIO_PREINIT
#ENDIF
#IF (PIO_4P | PIO_ZP)
.DW PIO_PREINIT
#ENDIF
#IF (XOSENABLE)
.DW XOS_PREINIT
#ENDIF
;
HB_PCINITTBLLEN .EQU (($ - HB_PCINITTBL) / 2)
;
;==================================================================================================
; TABLE OF INITIALIZATION ENTRY POINTS
;==================================================================================================
;
HB_INITTBL:
;
#IF (CHNATIVEENABLE)
; NEED TO ENUMERATE USB DEVICES EARLY, SO THAT ACTUAL DRIVERS
; WILL BE ABLE TO FIND THEM.
#IF (CHNATIVEFORCE)
.DW CHNATIVE_INITF
#ELSE
.DW CHNATIVE_INIT
#ENDIF
#ENDIF
#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 (PCRTCENABLE)
.DW PCRTC_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 (XOSENABLE)
.DW XOS_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 (ESPSDENABLE)
.DW ESPSD_INIT
#ENDIF
#IF (PRPENABLE)
.DW PRP_INIT
#ENDIF
#IF (PPPENABLE)
.DW PPP_INIT
#ENDIF
#IF (ESPENABLE)
.DW ESP_INIT
#ENDIF
#IF (CHSCSIENABLE)
.DW CHSCSI_INIT
#ENDIF
#IF (CHUFIENABLE)
.DW CHUFI_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
LD A,%10000000 ; START WITH HIGH BIT SET
HB_DSKREAD0:
RLCA ; 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
;
#IF (STRICTPART)
;
; THE FOLLOWING TEST RECORDS THE START OF A FOREIGN PARTITION AS THE IMPLIED
; END OF NON-PARTITIONED CP/M SPACE (HD512). THIS IS SUBSEQUENTLY USED TO
; ENSURE WE DON'T ACCESS AN HD512 SLICE THAT IS ACTUALLY INSIDE OF A
; FOREIGN PARTITION. HOWEVER, ROMWBW HAS PREVIOUSLY IGNORED FOREIGN
; PARTITIONS AND ENFORCING THIS BEHAVIOR NOW MAY RENDER LEGACY DISK
; SLICES INACCESSIBLE DUE TO PRE-EXISTING IMPROPER PARTITION TABLES.
; THE STRICTPART CONDITIONAL WILL ENABLE STRICT PARTITION TABLE
; VALIDATION, IF DESIRED.
;
CP $00 ; IS ANOTHER PARTITION TYPE, NOT CPM
JR NZ,EXT_SLICE3A ; OTHER VALID PART TYPE
#ENDIF
;
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
LD E,START_WARM ; SIGNAL A WARM START
JP INITSYS4 ; DO OUR NORMAL USER LAND STARTUP
;
; 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
JP M,SYS_RESUSER3 ; 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
;
SYS_RESUSER3:
; 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 VERSION IN TOP 4 BITS, MINOR VERSION IN LOW 4 BITS
; E: UPDATE VERSION 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:
LD A,D
CP $FF ; test if want to just get NVRAM status
JR Z,SYS_GETSWITCH3 ; 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
;
; Return Status
; A=0 if NVRAM does not exist. with NZ flag set
; A=1 if NVRAM exists, not inited. with NZ flag set
; A='W' if NVRAM is fully inited. with Z flag set
;
; Note the NZ flag can be used to detect and return an error condition
; where the NVRAM is not fully initialised
;
SYS_GETSWITCH3:
LD A,(CB_SWITCHES) ; the status byte
CP 'W' ; set NZ based on A = W
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:
LD A,(CB_SWITCHES) ; Check the basic status of NV RAM
CP 0 ; no nv ram is present. ( if = 0 )
JR Z,SWITCH_RES1 ; 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
;
CALL SYS_GETSWITCH3 ; Check the Full status of NV RAM
RET NZ ; is not fully initialised, so 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_SETCPUSPD_OK ; 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
#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
#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
#ENDIF
;
SYS_SETCPUSPD_OK:
;
LD B,BF_DSKYEVENT
LD C,DSKY_EVT_CPUSPD
CALL DSKY_DISPATCH
;
XOR A
RET
;
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
HB_PUSHINT
#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
HB_POPINT
#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
HB_PUSHINT
#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
HB_POPINT
#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
JR $ ; 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
JR $ ; 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
JR $ ; 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
;--------------------------------------------------------------------------------------------------
;
; 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_SW_CKSUM),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' ; Auto Boot - Rom Application [H]elp
.DB BOPTS_ROM ; Auto 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
;
;==================================================================================================
; FONT MANAGEMENT ROUTINES
;==================================================================================================
;
; SELECT A FONT BASED ON THE FONT ID PASSED IN REGISTER A. THIS WILL
; PREPARE TO STREAM FONT DATA VIA THE FNT_NEXT ROUTINE. USES AF, BC,
; DE, AND HL. RETURNS ZERO (ZF SET) FOR SUCCESS OR NON-ZERO (ZF CLEAR)
; IF FONT NOT FOUND.
;
#IF ROMFONTS
FNT_BNKID .EQU FONTS_BNK
FNT_MAP .EQU FONTS_LOC
#ELSE
FNT_BNKID .EQU BID_BIOS
#ENDIF
;
FNT_SELECT:
;;;CALL PC_SPACE ; ** DEBUG ***
;;;CALL PRTHEXBYTE ; ** DEBUG ***
LD E,A ; DESIRED FONT ID TO E
LD A,FNT_BNKID ; FONT BANK ID TO A
LD (FNT_BID),A ; SAVE IN WORKING VARIABLE
LD D,FNT_BNKID ; D = BANK FOR FONT DATA
LD HL,FNT_MAP ; POINT TO START OF MAP
;
; FONT MAP TABLE BEGINS WITH A 2 BYTE SIGNATURE. ATTEMPTING
; TO DECOMPRESS INVALID DATA WOULD BE VERY BAD.
CALL FNT_BYTE ; FIRST SIGNATURE BYTE
;;;CALL PC_SPACE ; ** DEBUG ***
;;;CALL COUT ; ** DEBUG ***
INC HL ; BUMP PTR
CP 'F' ; SHOULD BE 'F'
JR NZ,FNT_SELECT_ERR ; IF MISMATCH, BAIL OUT W/ ERR
CALL FNT_BYTE ; SECOND SIGNATURE BYTE
;;;CALL COUT ; ** DEBUG ***
INC HL ; BUMP PTR
CP 'M' ; SHOULD BE 'M'
JR NZ,FNT_SELECT_ERR ; IF MISMATCH, BAIL OUT W/ ERR
;
FNT_SELECT0:
CALL FNT_BYTE ; LOAD THE FONT ID FROM MAP
;;;CALL PC_SPACE ; ** DEBUG ***
;;;CALL PRTHEXBYTE ; ** DEBUG ***
AND $7F ; MASK OUT COMP INDICATOR
OR A ; CHECK FOR END OF TABLE
JR Z,FNT_SELECT_ERR ; IF SO, BAIL OUT W/ ERR
CP E ; CHECK FOR DESIRED FONT ID
JR Z,FNT_SELECT1 ; IF SO, LOCK IT IN
INC HL ; BUMP PAST FONT ID
INC HL ; BUMP TO
INC HL ; ... NEXT TABLE ENTRY
JR FNT_SELECT0 ; AND LOOP
;
FNT_SELECT1:
CALL FNT_BYTE ; GET FONT ID BYTE
PUSH AF ; SAVE IT
LD C,A ; SAVE IT IN E
INC HL ; BUMP PAST FONT ID
CALL FNT_BYTE ; LO BYTE OF ADDRESS
LD E,A ; PUT IN E
INC HL ; BUMP
CALL FNT_BYTE ; HI BYTE OF ADDRESS
LD D,A ; PUT IN D
EX DE,HL ; FULL ADDRESS TO HL
;
;;;#IF ROMFONTS
;;; CALL PC_SPACE ; ** DEBUG ***
;;; LD A,'R' ; ** DEBUG ***
;;; CALL COUT ; ** DEBUG ***
;;;#ELSE
;;; CALL PC_SPACE ; ** DEBUG ***
;;; LD A,'H' ; ** DEBUG ***
;;; CALL COUT ; ** DEBUG ***
;;;#ENDIF
;
POP AF ; RECOVER FONT ID
AND $80 ; COMPRESSED FONT DATA?
JR Z,FNT_SELECT2 ; IF NOT, SKIP DECOMP
;
#IF ((CVDUENABLE | GDCENABLE | TMSENABLE | VGAENABLE | VRCENABLE) & USELZSA2)
;
; DECOMPRESS THE FONT DATA. WE USURP $E000-$EFFF AS A BUFFER FOR THE
; DECOMPRESSED DATA. IF THE FONT DATA IS IN ROM, WE FIRST COPY THE
; COMPRESSED DATA TO $D000-DFFF. THE BUFFER SIZES ARE LARGE ENOUGH TO
; CONTAIN THE LARGEST FONT IN ITS DECOMPRESSED STATE. THE BUFFER
; LOCATIONS ARE SAFE DURING BOOT, BUT *NOT* FOR A RUNNING SYSTEM. SO,
; ANY FONT THAT MUST BE RELOADED AFTER BOOT WILL NEED TO BE SAVED IN
; DECOMPRESSED STATE! SPECIFICALLY THE 6X8 TMS FONT.
;
;;;LD A,'C' ; ** DEBUG ***
;;;CALL COUT ; ** DEBUG ***
;
#IF ROMFONTS
; COPY THE COMPRESSED DATA FROM ROM TO RAM BUFFER
LD A,(FNT_BID) ; GET ROM FONT BANK ID
LD (HB_SRCBNK),A ; SETUP SOURCE BANK
LD A,BID_BIOS ; DEST BANK IS BIOS BANK
LD (HB_DSTBNK),A ; SETUP DESTINATION BANK
LD DE,$D000 ; PUT DEST IN DE
LD BC,$1000 ; BLINDLY COPY 4K
CALL HBX_BNKCPY ; COPY COMP FONT DATA TO RAM
;
; DO THE DECOMPRESSION
LD HL,$D000 ; COMP BUF ADR TO HL
LD DE,$E000 ; DECOMP BUF ADR TO DE
CALL DLZSA2 ; DECOMPRESS
LD A,BID_BIOS ; BANK OF DECOMP BUF
LD (FNT_BID),A ; UPDATE FNT_BID
LD HL,$E000 ; DECOMP BUF ADR TO HL
#ELSE
LD DE,$E000 ; DECOMP BUF ADR TO DE
CALL DLZSA2 ; DECOMPRESS
LD HL,$E000 ; DECOMP BUF ADR TO HL
#ENDIF
;
#ELSE
JR FNT_SELECT_ERR ; OOPS, CAN'T DECOMPRESS
#ENDIF
;
FNT_SELECT2:
LD (FNT_PTR),HL ; SAVE STARTING POINTER
;;;LD A,(FNT_BID) ; ** DEBUG ***
;;;CALL PC_SPACE ; ** DEBUG ***
;;;CALL PRTHEXBYTE ; ** DEBUG ***
;;;LD HL,(FNT_PTR) ; ** DEBUG ***
;;;CALL PC_SPACE ; ** DEBUG ***
;;;CALL PRTHEXWORDHL ; ** DEBUG ***
XOR A ; SIGNAL SUCCESS
RET
FNT_SELECT_ERR:
OR $FF ; SIGNAL FAILURE
RET
;
; RETURN THE NEXT BYTE OF FONT DATA IN REGISTER A. EACH CALL RETURNS
; THE NEXT BYTE OF DATA. THERE IS NO INDICATION OF THE END OF THE
; FONT DATA. THE CALLER CONTROLS NUMBER OF BYTES REQUESTED.
; ONLY REGISTER A IS MODIFIED.
;
FNT_NEXT:
PUSH HL
LD HL,(FNT_PTR)
CALL FNT_BYTE
INC HL
LD (FNT_PTR),HL
POP HL
RET
;
; HELPER FUNCTION TO RETRIEVE A BYTE OF ROM FONT DATA FROM THE
; ROM FONT BANK. RETURNS BYTE FROM (FNT_BID:HL). RETURNS BYTE IN A.
; ALL OTHER REGSITERS UNCHANGED.
;
FNT_BYTE:
#IF (MEMMGR == MM_Z280)
; THERE IS A DEFICIENCY IN HBX_PEEK FOR Z280 W/ MM_Z280.
; IT WILL NOT WORK WHEN CALLED FROM Z280 SYSTEM MODE.
; THIS SHOULD BE REVISITED.
;
; NOTE: WHEN WE GO TO RESTORE THE USER SPACE BANK, WE DON'T
; REALLY HAVE A GOOD SOURCE OF WHAT BANK ID TO RESTORE IT TO.
; IN THEORY, WE ARE BEING INVOKED EITHER DURING SYSTEM BOOT OR
; VIA HB_INVOKE. DURING SYSTEM BOOT, THE USER BANK IS NOT
; RELEVANT. FOR HB_INVOKE, THE PREVIOUS USER BANK WILL BE
; RECORDED IN HB_INVBNK. SO, WE BLINDLY USE HB_INVBNK. THIS
; WILL BE CORRECT WHEN INVOKED VIA HB_INVOKE AND SHOULD DO NO
; HARM WHEN INVOKED DURING SYSTEM BOOT. THIS REALLY NEEDS TO
; BE REVIEWED.
;
LD A,(FNT_BID) ; GET THE FONT BANK ID
PUSH BC ; SAVE BC
PUSH HL ; SAVE HL
LD B,$00 ; POINT TO USER PDRS
CALL Z280_BNKSEL ; SELECT Z280 USER BANK
POP HL ; RECOVER HL
PUSH HL ; AND RESAVE IT
LDUP A,(HL) ; GET THE BYTE FROM USER SPACE
PUSH AF ; SAVE THE BYTE
LD A,(HB_INVBNK) ; GET PRIOR BANK (SEE NOTE ABOVE)
LD B,$00 ; POINT TO USER PDRS
CALL Z280_BNKSEL ; SELECT IT
POP AF ; RECOVER VALUE
POP HL ; RECOVER HL
POP BC ; RECOVER BC
RET ; DONE
#ELSE
PUSH DE
LD A,(FNT_BID)
LD D,A
CALL SYS_PEEK
LD A,E
POP DE
RET
#ENDIF
;
FNT_BID .DB 0 ; BANK CONTAINING FONT DATA
FNT_PTR .DW 0 ; POINTER TO NEXT BYTE OF DATA
;
HB_UTIL_END .EQU $
;
;==================================================================================================
; DISPLAY SUMMARY OF ATTACHED UNITS/DEVICES
;==================================================================================================
;
HB_PRTSUM_BEG .EQU $
;
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
;
HB_CPU_STR: .TEXT " Z80$"
.TEXT " Z80180$"
.TEXT " Z8S180-K$"
.TEXT " Z8S180-N$"
.TEXT " Z80280$"
.TEXT " eZ80$"
;
PS_STPARMAP .DB "NONENMNS"
;
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 (PCRTCENABLE)
ORG_PCRTC .EQU $
#INCLUDE "pcrtc.asm"
SIZ_PCRTC .EQU $ - ORG_PCRTC
MEMECHO "PCRTC occupies "
MEMECHO SIZ_PCRTC
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 (DS7RTCENABLE)
ORG_DS7RTC .EQU $
#INCLUDE "ds7rtc.asm"
SIZ_DS7RTC .EQU $ - ORG_DS7RTC
.ECHO "DS7RTC occupies "
.ECHO SIZ_DS7RTC
.ECHO " 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 (XOSENABLE)
ORG_XOS .EQU $
#INCLUDE "xosera.asm"
SIZ_XOS .EQU $ - ORG_XOS
MEMECHO "XOS occupies "
MEMECHO SIZ_XOS
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 (ESPSDENABLE)
ORG_ESPSD .EQU $
#INCLUDE "espsd.asm"
SIZ_ESPSD .EQU $ - ORG_ESPSD
MEMECHO "ESPSD occupies "
MEMECHO SIZ_ESPSD
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 (CHNATIVEENABLE)
ORG_CHNATIVE .EQU $
#INCLUDE "ch376.asm"
SIZ_CHNATIVE .EQU $ - ORG_CHNATIVE
MEMECHO "CH376 Native occupies "
MEMECHO SIZ_CHNATIVE
MEMECHO " bytes.\n"
#ENDIF
;
#IF (CHSCSIENABLE)
ORG_CHSCSI .EQU $
#INCLUDE "ch376scsi.asm"
SIZ_CHSCSI .EQU $ - ORG_CHSCSI
MEMECHO " CH376 SCSI Mass Storage occupies "
MEMECHO SIZ_CHSCSI
MEMECHO " bytes.\n"
#ENDIF
;
#IF (CHUFIENABLE)
ORG_CHUFI .EQU $
#INCLUDE "ch376ufi.asm"
SIZ_CHUFI .EQU $ - ORG_CHUFI
MEMECHO " CH376 UFI Floppy Storage occupies "
MEMECHO SIZ_CHUFI
MEMECHO " bytes.\n"
#ENDIF
;
#IF (USBKYBENABLE)
ORG_UKY .EQU $
#INCLUDE "ch376kyb.asm"
SIZ_UKY .EQU $ - ORG_UKY
MEMECHO " CH376 USB Keyboard occupies "
MEMECHO SIZ_UKY
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"
;
#IF !ROMFONTS
;
; HIGH BIT OF THE FONTID BYTE INDICATES THAT THE FONT DATA IS COMPRESSED
;
#IF USELZSA2
FNT_CMPMASK .EQU $80
#ELSE
FNT_CMPMASK .EQU $00
#ENDIF
;
; FONT LOCATION MAP
;
FNT_MAP:
.DB 'F','M' ; TABLE SIGNATURE
#IFDEF USEFONT6X8
; FOR NOW, WE NEVER COMPRESS THE 6X8 FONT. SEE TMS DRIVER.
;;; .DB FONTID_6X8 | FNT_CMPMASK
.DB FONTID_6X8
.DW FONT6X8
#ENDIF
;
#IFDEF USEFONT8X8
.DB FONTID_8X8 | FNT_CMPMASK
.DW FONT8X8
#ENDIF
;
#IFDEF USEFONT8X11
.DB FONTID_8X11 | FNT_CMPMASK
.DW FONT8X11
#ENDIF
;
#IFDEF USEFONT8X16
.DB FONTID_8X16 | FNT_CMPMASK
.DW FONT8X16
#ENDIF
;
.DB 0 ; END OF TABLE
;
#IFDEF USEFONT6X8
FONT6X8:
;
; FOR NOW, WE NEVER COMPRESS THE 6X8 FONT. SEE TMS DRIVER.
;
#IF USELZSA2 & FALSE
#INCLUDE "font6x8c.asm"
#ELSE
#INCLUDE "font6x8u.asm"
#ENDIF
MEMECHO " 6X8"
#ENDIF
;
#IFDEF USEFONT8X8
FONT8X8:
;
#IF USELZSA2
#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
;
#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
;
INTSENAB .DB 0 ; INTERRUPTS ENABLED
;
#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
.DB "$"
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)? $"
;
#IF (BOOT_PRETTY)
#INCLUDE "plt_pretty.inc"
#ENDIF
;
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 "
.DB PLATFORM_NAME
.DB "$"
;
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