mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 22:43:15 -06:00
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.
9748 lines
257 KiB
NASM
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
|