mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9756 lines
260 KiB
9756 lines
260 KiB
;
|
|
;==================================================================================================
|
|
; HBIOS
|
|
;==================================================================================================
|
|
;
|
|
; THIS FILE CONTAINS THE HBIOS IMAGE THAT IS INTENDED TO RUN IN A DEDICATED RAM BANK. THE CODE IS
|
|
; CONSTRUCTED SUCH THAT IT CAN BE LAUNCHED IN A VARIETY OF MODES AND INSTALL ITSELF. A SMALL 512
|
|
; BYTE PROXY IS PLACED AT THE TOP OF CPU MEMORY (FE00H-FFFFH). THIS PROXY CODE ALLOWS CODE
|
|
; RUNNING FROM ANY BANK TO INVOKE HBIOS FUNCTIONS. NORMALLY, ANY BANK THAT RUNS CODE WOULD SETUP
|
|
; THE RST 8 VECTOR TO POINT TO THE PROXY INVOKE ENTRY POINT AT FFF0H. CALLS VIA THE PROXY INVOKE
|
|
; ENTRY POINT TRANSPARENTLY SWAP IN THE HBIOS BANK, PERFORM THE REQUESTED FUNCTION, AND RETURN
|
|
; WITH THE ORIGINAL BANK ACTIVE. THE CODE USING HBIOS FUNCTIONS DOES NOT NEED TO BE AWARE OF
|
|
; THE BANK SWITCHING THAT OCCURS.
|
|
;
|
|
; THIS FILE CAN BE COMPILED TO BOOT IN ONE OF 3 MODES (ROM, APPLICATION, OR IMAGE) AS DESCRIBED
|
|
; BELOW. WHEN COMPILED, YOU MUST DEFINE EXACTLY ONE OF THE FOLLOWING MACROS:
|
|
;
|
|
; - ROMBOOT: BOOT FROM A ROM BANK
|
|
;
|
|
; WHEN ROMBOOT IS DEFINED, THE FILE IS ASSEMBLED TO BE IMBEDDED AT THE START OF A ROM
|
|
; ASSUMING THAT THE CPU WILL START EXECUTION AT ADDRESS 0. AFTER PERFORMING MINIMAL
|
|
; SYSTEM INITIALIZATION, THE IMAGE OF THE RUNNING ROM BANK IS COPIED TO A RAM BANK
|
|
; CREATING A SHADOW COPY IN RAM. EXECUTION IS THAN TRANSFERRED TO THE RAM SHADOW COPY.
|
|
; THIS IS ESSENTIAL BECAUSE THE HBIOS CODE DOES NOT SUPPORT RUNNING IN READ ONLY MEMORY
|
|
; (EXCEPT FOR THE INITIAL LAUNCHING CODE).
|
|
;
|
|
; - APPBOOT: BOOT FROM A CP/M STYLE APPLICATION FILE
|
|
;
|
|
; WHEN APPBOOT IS DEFINED, THE FILE IS ASSEMBLED AS A CP/M APPLICATION ASSUMING
|
|
; THAT IT WILL BE LOADED AT 100H BY THE CP/M (OR COMPATIBLE) OS. NOTE THAT IN
|
|
; THIS CASE IT IS ASSUMED THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE
|
|
; HBIOS APPLICATION BINARY. THE APPENDED OS IMAGES ARE COPIED TO THE AUX RAM
|
|
; BANK AND LAUNCHED AFTER HBIOS HAS INSTALLED ITSELF.
|
|
;
|
|
; - IMGBOOT: BOOT FROM AN IMAGE FILE THAT HAS BEEN PLACED IN THE USER BANK
|
|
;
|
|
; NOTE: THIS BOOT MODE IS DEPRECATED.
|
|
;
|
|
; WHEN IMGBOOT IS DEFINED, THE FILE IS ASSEMBLED SUCH THAT IT CAN BE PRELOADED
|
|
; INTO THE RAM USER BANK BY AN EXTERNAL PROCESS THAT SUBSEQUENTLY LAUNCHES
|
|
; THE CODE AT ADDRESS 0. THE MOST COMMON EXAMPLE OF THIS IS THE UNA FSFAT
|
|
; TOOL WHICH CAN LOAD AN IMAGE FROM A DOS FAT FILESYSTEM PROVIDING A SIMPLE
|
|
; WAY TO LOAD A TEST COPY OF HBIOS. AS IS THE CASE WITH APPBOOT, IT IS ASSUMED
|
|
; THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE IMAGE AND IS LAUNCHED
|
|
; AFTER HBIOS IS INSTALLED.
|
|
;
|
|
; INCLUDE FILE NESTING:
|
|
;
|
|
; - std.asm
|
|
; - ../ver.inc
|
|
; - build.inc
|
|
; - Config/<plt>_<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.
|
|
;
|
|
; RomWBW Logical: $00 $01 $02 $03 ... $38 $39 $3A $3B $3C $3D $3E $3F
|
|
; Z80 CPU Physical: $04 $05 $06 $07 ... $3C $3D $3E $3F $00 $01 $02 $03
|
|
;
|
|
; RomWBW Bank Id: $80 $81 $82 $83 ... $98 $99 $9A $9B $9C $9D $9E $9F
|
|
; Physical Address: $10000 $18000 $20000 $28000 ... $D0000 $D8000 $E0000 $E8000 $F0000 $F8000 $00000 $08000
|
|
;
|
|
; WARNING: If the MS-DOS Support Board is used with ROM enabled it will
|
|
; map ROM to $F0000-$FFFFF! This means that we can only use bank ids
|
|
; up to $9B which is 28 banks or 896K. The RAMSIZE config must be limited
|
|
; to 896 in this case.
|
|
;
|
|
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 ALIGN WITH FIXED COMMON BANK
|
|
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
|
|
#IF (TURBOZ80)
|
|
; IF THE CPU HAS BOOSTED TO 20MHZ, ANY PERIPHERAL THAT ATTEMPTS
|
|
; TO DETECT THE RETI INSTRUCTION ON THE DATA BUS WILL LIKELY FAIL.
|
|
; WE NEED TO SLOW THE PROCESSOR BACK TO THE DEFAULT SPEED.
|
|
; ANY I/O OPERATION WILL CAUSE THE PROCESSOR TO CLOCK DOWN TO THE
|
|
; DEFAULT SPEED FOR THE NEXT 31 CLOCK TICKS
|
|
PUSH AF
|
|
IN A, (TURBOZ80DISPRT) ; ANY IO ADDRESS CAN BE USED, SO LONG AS IT HAS NO DEVICE IMPACT
|
|
POP AF
|
|
#ENDIF
|
|
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.
|
|
;
|
|
; FPLEDS(DIAG_02)
|
|
;
|
|
#IF (FPLED_ENABLE)
|
|
#IF (FPLED_INV)
|
|
LD A,~DIAG_01
|
|
#ELSE
|
|
LD A,DIAG_01
|
|
#ENDIF
|
|
;
|
|
EZ80_IO()
|
|
OUT (FPLED_IO),A
|
|
#ENDIF
|
|
;
|
|
; DIAG(1)
|
|
;
|
|
#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)
|
|
RAMSEG .EQU ((ROMSIZE + RAMSIZE) / 16) - 2 + (RAMBIAS * 2)
|
|
LD A,RAMSEG
|
|
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 Z180 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_SZ180) & TRUE)
|
|
; CHECK S100 BOARD DIP SWITCH, BIT 1
|
|
IN A,($75) ; READ SWITCHES
|
|
BIT 1,A ; CHECK BIT 1
|
|
JR NZ,SZ180MON_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,SZ180MON_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!
|
|
;
|
|
SZ180MON_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
|
|
#IF (PLATFORM!=PLT_N8PC)
|
|
EZ80_IO()
|
|
OUT (RTCIO),A ; SET IT
|
|
DIAG(1) ; REAPPLY CURRENT DIAG LED SETUP
|
|
#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; 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
|
|
;
|
|
; PRE-INIT OSCILLATOR SPEED AND SPEED COMPENSATED DELAY FROM CONFIG
|
|
;
|
|
LD A,CPUMHZ ; CPU SPD IN MHZ
|
|
LD (CB_CPUMHZ),A ; INIT HB_CPUMHZ
|
|
#IF (CPUFAM != CPU_EZ80)
|
|
CALL DELAY_INIT ; ... AND SPEED COMPENSATED DELAY
|
|
#ENDIF
|
|
LD HL,CPUOSC / 1000 ; OSC SPD IN KHZ
|
|
LD (HB_CPUOSC),HL ; INIT HB_CPUOSC DEFAULT
|
|
;;;;
|
|
;;;;--------------------------------------------------------------------------------------------------
|
|
;;;; 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 (ICMENABLE)
|
|
;;; CALL ICM_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (PKDENABLE)
|
|
;;; CALL PKD_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (LCDENABLE)
|
|
;;; CALL LCD_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (H8PENABLE)
|
|
;;; CALL H8P_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (GM7303ENABLE)
|
|
;;; CALL GM7303_PREINIT
|
|
;;;#ENDIF
|
|
;
|
|
FPLEDS(DIAG_05)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; 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
|
|
;
|
|
; SET INIT PHASE TO PREINIT AND CALL ALL MODULES
|
|
LD A,HB_PHASE_PREINIT ; PHASE = PREINIT
|
|
LD (HB_CURPHASE),A ; SAVE IT
|
|
CALL MODINIT ; WALK THE MODULE LIST, A=PHASE
|
|
;
|
|
; MEASURE RUNNING CPU SPEED DYNAMICALLY IF POSSIBLE
|
|
;
|
|
; 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
|
|
;
|
|
#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
|
|
;
|
|
; RECORD THE UPDATED CPU OSCILLATOR SPEED
|
|
LD (HB_CPUOSC),HL ; RECORD MEASURED SPEED
|
|
;
|
|
HB_CPU2:
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; 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
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; FINALIZE 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)
|
|
;
|
|
#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_SZ180) & SCONENABLE)
|
|
IN A,($75) ; GET IO BYTE
|
|
AND %00000001 ; ISOLATE CONSOLE BIT
|
|
JR NZ,HB_CONRDY_Z ; NOT SET, BYPASS CONSOLE SWITCH
|
|
LD A,(SCON_UNIT) ; GET THE CONSOLE UNIT NUMBER
|
|
CP $FF ; VALID?
|
|
JR Z,HB_CONRDY_Z ; IF NOT, BYPASS CONSOLE SWITCH
|
|
LD (CB_CONDEV),A ; SET CONSOLE DEVICE
|
|
#ENDIF
|
|
;
|
|
#IF ((PLATFORM == PLT_SZ80) & (MEMMGR == MM_SZ80))
|
|
;
|
|
; ATTEMPT TO MATCH 100 CONSOLE ROUTING:
|
|
; IF (K8 EXISTS AND =0)
|
|
; Z80 CPU V3 BOARD DLP USB
|
|
; ELSE ROUTE BASED ON IOBYTE (PORT 0XEF) BITS 5&4:
|
|
; 11: PROPELLER (SCON)
|
|
; 10: SCC PORT A
|
|
; 01: SERIAL I/O BOARD DLP USB
|
|
; 00: VGA
|
|
;
|
|
LD C,($E8) ; POINT TO K8 PORT
|
|
IN B,(C) ; GET VALUE TO B USING IN (C)
|
|
IN A,($E8) ; GET VALUE TO A USING IN (XX)
|
|
CP B ; A==B IF PORT EXISTS
|
|
JR NZ,HB_CONRDY1 ; SKIP IF NOT VALID PORT (PRE-V3 CPU BOARD)
|
|
BIT 0,A ; CHECK BIT 0
|
|
JR NZ,HB_CONRDY1 ; IF NZ, NOT SET, SKIP
|
|
;
|
|
; USE Z80 CPU V3 BOARD DLP USB
|
|
#IF (DLPSERENABLE)
|
|
#IF (DLPSERCNT >= 1)
|
|
LD A,(DLPSER0_CFG + 2) ; GET THE DLP SERIAL UNIT NUMBER
|
|
CP $FF ; VALID?
|
|
JR Z,HB_CONRDY1 ; IF NOT, BYPASS CONSOLE SWITCH
|
|
LD (CB_CONDEV),A ; SET CONSOLE DEVICE
|
|
JR HB_CONRDY_Z ; AND DONE
|
|
#ENDIF
|
|
#ENDIF
|
|
HB_CONRDY1:
|
|
LD C,($EF) ; POINT TO IOBYTE PORT
|
|
IN B,(C) ; GET VALUE TO B USING IN (C)
|
|
IN A,($EF) ; GET VALUE TO A USING IN (XX)
|
|
CP B ; A==B IF PORT EXISTS
|
|
JR NZ,HB_CONRDY_Z ; BAIL OUT IF PORT NOT FOUND
|
|
;
|
|
AND %00110000 ; ISOLOATE CONSOLE BITS 5&4
|
|
CP %00110000 ; PROPELLER REQUESTED?
|
|
JR Z,HB_CONRDY2 ; IF SO, HANDLE IT
|
|
CP %00100000 ; SCC PORT A REQUESTED?
|
|
JR Z,HB_CONRDY3 ; IF SO, HANDLE IT
|
|
CP %00010000 ; SERIAL I/O BOARD DLP USB?
|
|
JR Z,HB_CONRDY4 ; IF SO, HANDLE IT
|
|
JR HB_CONRDY_Z ; OTHERWISE BAIL OUT
|
|
;
|
|
HB_CONRDY2: ; PROPELLER
|
|
#IF (SCONENABLE)
|
|
LD A,(SCON_UNIT) ; GET THE CONSOLE UNIT NUMBER
|
|
CP $FF ; VALID?
|
|
JR Z,HB_CONRDY_Z ; IF NOT, BYPASS CONSOLE SWITCH
|
|
LD (CB_CONDEV),A ; SET CONSOLE DEVICE
|
|
#ENDIF
|
|
JR HB_CONRDY_Z
|
|
;
|
|
HB_CONRDY3: ; SCC PORT A
|
|
#IF (SCCENABLE)
|
|
; FOR NOW, WE ASSUME THE DEFAULT CONSOLE UNIT IS THIS
|
|
#ENDIF
|
|
JR HB_CONRDY_Z
|
|
;
|
|
HB_CONRDY4: ; SERIAL I/O BOARD DLP USB
|
|
#IF (DLPSERENABLE)
|
|
#IF (DLPSERCNT >= 2)
|
|
LD A,(DLPSER1_CFG + 2) ; GET THE DLP SERIAL UNIT NUMBER
|
|
CP $FF ; VALID?
|
|
JR Z,HB_CONRDY_Z ; IF NOT, BYPASS CONSOLE SWITCH
|
|
LD (CB_CONDEV),A ; SET CONSOLE DEVICE
|
|
#ENDIF
|
|
#ENDIF
|
|
JR HB_CONRDY_Z
|
|
#ENDIF
|
|
;
|
|
#IF ((PLATFORM == PLT_SZ80) & (MEMMGR == MM_Z2) & SCONENABLE)
|
|
IN A,($36) ; GET IO BYTE
|
|
AND %00000111 ; ISOLATE CONSOLE BITS
|
|
CP %00000111 ; PROPELLER CONSOLE REQUEST?
|
|
JR NZ,HB_CONRDY_Z ; IF NOT, BYPASS CONSOLE SWITCH
|
|
LD A,(SCON_UNIT) ; GET THE CONSOLE UNIT NUMBER
|
|
CP $FF ; VALID?
|
|
JR Z,HB_CONRDY_Z ; IF NOT, BYPASS CONSOLE SWITCH
|
|
LD (CB_CONDEV),A ; SET CONSOLE DEVICE
|
|
#ENDIF
|
|
;
|
|
HB_CONRDY_Z:
|
|
;
|
|
; 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 (TURBOZ80)
|
|
CALL PRTSTRD
|
|
.TEXT " (TURBO: 20Mhz)$"
|
|
#ENDIF
|
|
;
|
|
#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 ; PROCESS THE INIT CALL TABLE
|
|
;
|
|
; SET INIT PHASE TO INIT AND CALL ALL MODULES
|
|
LD A,HB_PHASE_INIT ; PHASE = INIT
|
|
LD (HB_CURPHASE),A ; SAVE IT
|
|
CALL MODINIT ; WALK THE MODULE LIST, A=PHASE
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; 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
|
|
;
|
|
HB_CRTACT:
|
|
LD A,(CB_CRTDEV) ; GET CRT DISPLAY DEVICE
|
|
LD (HB_NEWCON),A ; AND QUEUE TO SWITCH
|
|
;
|
|
#ENDIF
|
|
;
|
|
#IF ((PLATFORM == PLT_SZ80) & (MEMMGR == MM_Z2) & TVGAENABLE)
|
|
; IOBYTE: XXXXXVVC
|
|
; 00- FORCE ONBOARD VGA/PS2 KBD (T35)
|
|
; --1 FORCE PROPELLER CONSOLE (SCON)
|
|
; 110 NORMAL USB SERIAL BOOT
|
|
;
|
|
; IF ONBOARD VGA/PS2 KBD IS REQUESTED, SETUP FOR CONSOLE SWITCH
|
|
IN A,($36) ; GET IO BYTE
|
|
AND %00000110 ; ISOLATE BITS
|
|
JR NZ,INITSYS3 ; BIT(S) NOT ZERO, BYPASS SWITCH
|
|
LD A,(TVGA_UNIT) ; GET TVGA UNIT NUMBER
|
|
CP $FF ; IS HARDWARE THERE?
|
|
JR Z,INITSYS3 ; IF NOT, BYPASS SWITCH
|
|
LD (HB_NEWCON),A ; ELSE QUEUE TO SWITCH
|
|
LD (CB_CRTDEV),A ; AND ENSURE IT IS THE CRT DEVICE
|
|
#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,(CB_CONDEV) ; GET 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 (ASCIENABLE)
|
|
;;; .DW ASCI_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (Z2UENABLE)
|
|
;;; .DW Z2U_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (TSERENABLE)
|
|
;;; .DW TSER_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (UARTENABLE)
|
|
;;; .DW UART_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (DUARTENABLE)
|
|
;;; .DW DUART_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (SIOENABLE)
|
|
;;; .DW SIO_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (SCCENABLE)
|
|
;;; .DW SCC_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (EZ80UARTENABLE)
|
|
;;; .DW EZUART_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (ACIAENABLE)
|
|
;;; .DW ACIA_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (SSERENABLE)
|
|
;;; .DW SSER_PREINIT
|
|
;;;#ENDIF
|
|
;;;#IF (DLPSERENABLE)
|
|
;;; .DW DLPSER_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 (ICMENABLE)
|
|
;;; .DW ICM_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (PKDENABLE)
|
|
;;; .DW PKD_INIT
|
|
;;;#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 (ASCIENABLE)
|
|
;;; .DW ASCI_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (Z2UENABLE)
|
|
;;; .DW Z2U_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (TSERENABLE)
|
|
;;; .DW TSER_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (UARTENABLE)
|
|
;;; .DW UART_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (DUARTENABLE)
|
|
;;; .DW DUART_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (SIOENABLE)
|
|
;;; .DW SIO_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (SCCENABLE)
|
|
;;; .DW SCC_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (EZ80UARTENABLE)
|
|
;;; .DW EZUART_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (ACIAENABLE)
|
|
;;; .DW ACIA_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (SSERENABLE)
|
|
;;; .DW SSER_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (DLPSERENABLE)
|
|
;;; .DW DLPSER_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 (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 (MMRTCENABLE)
|
|
;;; .DW MMRTC_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (DS12RTCENABLE)
|
|
;;; .DW DS12RTC_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (INTRTCENABLE)
|
|
;;; .DW INTRTC_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (CPUFAM == CPU_EZ80)
|
|
;;; ; INITALISE ONE OF THE SUPPORTED SYSTEM TIMER TICKS DRIVERS
|
|
;;; .DW EZ80_TMR_INIT
|
|
;;;#ENDIF
|
|
;;;#IF (M6242RTCENABLE)
|
|
;;; .DW M6242RTC_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 (TVGAENABLE)
|
|
;;; .DW TVGA_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 (SCSIENABLE)
|
|
;;; .DW SCSI_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
|
|
;
|
|
#IF TRUE
|
|
; ZERO SECTOR COUNT CHECK
|
|
LD A,B ; SEC COUNT TO ACCUM
|
|
OR A ; SET FLAGS
|
|
JR Z,HB_DSKREAD2 ; SKIP I/O IF ZERO
|
|
#ENDIF
|
|
;
|
|
HB_DSKREAD1:
|
|
LD HL,HB_WRKBUF ; USE WORK BUF REAL I/O
|
|
;
|
|
; CALL READ FN
|
|
LD E,1 ; READ EXACTLY 1 SECTOR
|
|
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
|
|
HB_DSKREAD2:
|
|
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
|
|
;
|
|
#IF TRUE
|
|
; ZERO SECTOR COUNT CHECK
|
|
LD A,B ; SEC COUNT TO ACCUM
|
|
OR A ; SET FLAGS
|
|
JR Z,HB_DSKWRITE2 ; SKIP I/O IF ZERO
|
|
#ENDIF
|
|
;
|
|
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
|
|
LD E,1 ; WRITE EXACTLY 1 SECTOR
|
|
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
|
|
HB_DSKWRITE2:
|
|
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
|
|
;
|
|
#IF TRUE
|
|
; ZERO SECTOR COUNT CHECK
|
|
LD A,B ; SEC COUNT TO ACCUM
|
|
OR A ; SET FLAGS
|
|
JR Z,HB_DSKIO2 ; SKIP I/O IF ZERO
|
|
#ENDIF
|
|
;
|
|
HB_DSKIO1:
|
|
; CALL READ/WRITE FN
|
|
LD E,1 ; READ/WRITE EXACTLY 1 SECTOR
|
|
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
|
|
HB_DSKIO2:
|
|
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. HL IS EXPECTED TO TO CONTAIN VALUE OF PC
|
|
; WHEN THE $0000 VECTOR WAS INVOKED (I.E., THE PC AT THE TIME AN
|
|
; INVALID INSTRUCTION TRAP OCCURRED.
|
|
;
|
|
; 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:
|
|
;;; WHY IS THIS NOT DONE ABOVE???
|
|
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
|
|
;;; SHOULD THIS BE DONE PRIOR TO CHECKING FOR
|
|
;;; INVALID OPCODE???
|
|
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
|
|
;
|
|
; WALK THE MODULE LIST CALLING THE MODULE INIT
|
|
; PHASE HANDLER WITH THE CURRENT INIT PHASE ID IN A.
|
|
;
|
|
MODINIT:
|
|
LD HL,HB_MODSTART ; POINT TO START OF MODULES
|
|
MODINIT1:
|
|
PUSH HL ; SAVE MODULE START
|
|
;CALL NEWLINE ; *DEBUG*
|
|
;CALL PRTHEXWORDHL ; *DEBUG*
|
|
LD E,(HL) ; GET MODULE LENGTH
|
|
INC HL
|
|
LD D,(HL)
|
|
INC HL
|
|
LD A,E ; CHECK FOR ZERO (END OF LIST)
|
|
OR D
|
|
JR Z,MODINIT_Z ; IF ZERO, DONE
|
|
PUSH DE ; SAVE MODULE LENGTH
|
|
;
|
|
LD A,(HL) ; ADR OF MOD INIT HANDLER TO HL
|
|
INC HL
|
|
LD H,(HL)
|
|
LD L,A
|
|
LD A,(HB_CURPHASE) ; PHASE ID TO A
|
|
CALL JPHL ; DO IT
|
|
;
|
|
POP DE ; RECOVER MODULE LENGTH
|
|
POP HL ; RECOVER MODULE START
|
|
ADD HL,DE ; BUMP TO NEXT
|
|
JR MODINIT1 ; LOOP
|
|
MODINIT_Z:
|
|
POP HL ; FIX STACK
|
|
RET ; AND DONE
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; 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
|
|
;
|
|
; COMMON RETURN FUNCTIONS (WILL BE EXPANDED AT SOME POINT)
|
|
;
|
|
HB_RETOK:
|
|
XOR A
|
|
RET
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; 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
|
|
|
|
;==================================================================================================
|
|
; 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
|
|
;
|
|
;==================================================================================================
|
|
; 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 BID_IMG0 + 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
|
|
;==================================================================================================
|
|
;
|
|
; *** ORDER OF MODULES INCLUDED BELOW MATTERS!!! ***
|
|
;
|
|
; THE ORDER OF INCLUSION BELOW DICTATES THE ORDER IN WHICH THE INIT
|
|
; HANDLER OF EACH MODULE IS CALLED. THE ORDER THAT DRIVERS ARE
|
|
; REGISTERED IS AFFECTED BY THIS.
|
|
;
|
|
; EACH MODULE INCLUDED BELOW **MUST** HAVE THE STANDARD MODULE HEADER
|
|
; AND TRAILER.
|
|
;
|
|
HB_DRIVERS_BEG .EQU $
|
|
;
|
|
HB_MODSTART .EQU $
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; SYSTEM MODULES
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
; - EZ80CPU
|
|
; - CHNATIVE
|
|
; - KIO
|
|
; - CTC
|
|
; - PCF
|
|
; - DMA
|
|
; - NABU
|
|
; - EZ80TMR
|
|
;
|
|
#IF (CPUFAM == CPU_EZ80)
|
|
#INCLUDE "ez80cpu.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (CHNATIVEENABLE)
|
|
#INCLUDE "ch376.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (KIOENABLE)
|
|
#INCLUDE "kio.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (CTCENABLE)
|
|
#INCLUDE "ctc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (PCFENABLE)
|
|
#INCLUDE "pcf.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (DMAENABLE)
|
|
#INCLUDE "dma.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (PLATFORM == PLT_NABU)
|
|
#INCLUDE "nabu.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (CPUFAM == CPU_EZ80)
|
|
#INCLUDE "ez80tmr.asm"
|
|
#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; DSKY MODULES
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
; - ICM
|
|
; - PKD
|
|
; - LCD
|
|
; - H8P
|
|
; - GM7303
|
|
;
|
|
#IF (ICMENABLE)
|
|
#INCLUDE "icm.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (PKDENABLE)
|
|
#INCLUDE "pkd.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (LCDENABLE)
|
|
#INCLUDE "lcd.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (H8PENABLE)
|
|
#INCLUDE "h8p.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (GM7303ENABLE)
|
|
#INCLUDE "gm7303.asm"
|
|
#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; SOUND MODULES
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
; - AY38910
|
|
; - SN76489
|
|
; - YM2612
|
|
; - SPKENABLE
|
|
;
|
|
#IF (AY38910ENABLE)
|
|
#INCLUDE "ay38910.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (SN76489ENABLE)
|
|
#INCLUDE "sn76489.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (YM2612ENABLE)
|
|
#INCLUDE "ym2612.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (SPKENABLE)
|
|
#INCLUDE "spk.asm"
|
|
#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; CHARACTER DEVICE MODULES
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
; - ASCI
|
|
; - Z2U
|
|
; - TSER
|
|
; - UART
|
|
; - DUART
|
|
; - SIO
|
|
; - SCC
|
|
; - EZUART
|
|
; - ACIA
|
|
; - SSER
|
|
; - DLPSER
|
|
; - SCON
|
|
; - UF
|
|
;
|
|
#IF (ASCIENABLE)
|
|
#INCLUDE "asci.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (Z2UENABLE)
|
|
#INCLUDE "z2u.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (TSERENABLE)
|
|
#INCLUDE "tser.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (UARTENABLE)
|
|
#INCLUDE "uart.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (DUARTENABLE)
|
|
#INCLUDE "duart.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (SIOENABLE)
|
|
#INCLUDE "sio.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (SCCENABLE)
|
|
#INCLUDE "scc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (EZ80UARTENABLE)
|
|
#INCLUDE "ez80uart.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (ACIAENABLE)
|
|
#INCLUDE "acia.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (SSERENABLE)
|
|
#INCLUDE "sser.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (DLPSERENABLE)
|
|
#INCLUDE "dlpser.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (SCONENABLE)
|
|
#INCLUDE "scon.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (UFENABLE)
|
|
#INCLUDE "uf.asm"
|
|
#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; PARALLEL DEVICE MODULES
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
; - LPT
|
|
; - PIO
|
|
;
|
|
#IF (LPTENABLE)
|
|
#INCLUDE "lpt.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (PIOENABLE)
|
|
#INCLUDE "pio.asm"
|
|
#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; REAL-TIME CLOCK / NON-VOLATILE MEMORY MODULES
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
; - DSRTC
|
|
; - DS1501RTC
|
|
; - BQRTC
|
|
; - SIMRTC
|
|
; - DS7RTC
|
|
; - DS5RTC
|
|
; - RP5RTC
|
|
; - EZ80RTC
|
|
; - PCRTC
|
|
; - MMRTC
|
|
; - DS12RTC
|
|
; - M6242RTC
|
|
; - INTRTC
|
|
;
|
|
#IF (DSRTCENABLE)
|
|
#INCLUDE "dsrtc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (DS1501RTCENABLE)
|
|
#INCLUDE "ds1501rtc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (BQRTCENABLE)
|
|
#INCLUDE "bqrtc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (SIMRTCENABLE)
|
|
#INCLUDE "simrtc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (DS7RTCENABLE)
|
|
#INCLUDE "ds7rtc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (DS5RTCENABLE)
|
|
#INCLUDE "ds5rtc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (RP5RTCENABLE)
|
|
#INCLUDE "rp5rtc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (EZ80RTCENABLE)
|
|
#INCLUDE "ez80rtc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (PCRTCENABLE)
|
|
#INCLUDE "pcrtc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (MMRTCENABLE)
|
|
#INCLUDE "mmrtc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (DS12RTCENABLE)
|
|
#INCLUDE "ds12rtc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (M6242RTCENABLE)
|
|
#INCLUDE "m6242rtc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (INTRTCENABLE)
|
|
#INCLUDE "intrtc.asm"
|
|
#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; VIDEO DISPLAY MODULES
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
; - VDU
|
|
; - CVDU
|
|
; - VGA
|
|
; - GDC
|
|
; - TMS
|
|
; - EF
|
|
; - VRC
|
|
; - TVGA
|
|
; - XOS
|
|
;
|
|
#IF (VDUENABLE)
|
|
#INCLUDE "vdu.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (CVDUENABLE)
|
|
#INCLUDE "cvdu.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (VGAENABLE)
|
|
#INCLUDE "vga.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (GDCENABLE)
|
|
#INCLUDE "gdc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSENABLE)
|
|
#INCLUDE "tms.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (EFENABLE)
|
|
#INCLUDE "ef.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (VRCENABLE)
|
|
#INCLUDE "vrc.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (TVGAENABLE)
|
|
#INCLUDE "tvga.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (XOSENABLE)
|
|
#INCLUDE "xosera.asm"
|
|
#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; KEYBOARD MODULES
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
; - KBD
|
|
; - MKY
|
|
; - NABUKBD
|
|
; - PPK
|
|
; - USBKYB
|
|
;
|
|
#IF (KBDENABLE)
|
|
#INCLUDE "kbd.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (MKYENABLE)
|
|
#INCLUDE "mky.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (NABUKBENABLE)
|
|
#INCLUDE "nabukb.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (PPKENABLE)
|
|
#INCLUDE "ppk.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (USBKYBENABLE)
|
|
#INCLUDE "ch376kyb.asm"
|
|
#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; TERMINAL MODULES
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
; NOTE: TERM MODULE IS ALWAYS INCLUDED!!! CONDITIONALS IN THE TERM
|
|
; DRIVER SOURCE DETERMINE THE CODE THAT IS ACTUALLY INCLUDED.
|
|
;
|
|
#IF (TRUE)
|
|
#INCLUDE "term.asm"
|
|
#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; DISK / STORAGE MODULES
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
; - MD
|
|
; - FD
|
|
; - RF
|
|
; - IDE
|
|
; - PPIDE
|
|
; - SD
|
|
; - HDSK
|
|
; - PPA
|
|
; - IMM
|
|
; - SYQ
|
|
; - CH
|
|
; - ESPSD
|
|
; - SCSI
|
|
; - CHSCSI
|
|
; - CHUFI
|
|
;
|
|
#IF (MDENABLE)
|
|
#INCLUDE "md.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (FDENABLE)
|
|
#INCLUDE "fd.asm"
|
|
#ENDIF
|
|
;
|
|
;
|
|
#IF (RFENABLE)
|
|
#INCLUDE "rf.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (IDEENABLE)
|
|
#INCLUDE "ide.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (PPIDEENABLE)
|
|
#INCLUDE "ppide.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (SDENABLE)
|
|
#INCLUDE "sd.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (HDSKENABLE)
|
|
#INCLUDE "hdsk.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (PPAENABLE)
|
|
#INCLUDE "ppa.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (IMMENABLE)
|
|
#INCLUDE "imm.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (SYQENABLE)
|
|
#INCLUDE "syq.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (CHENABLE)
|
|
#INCLUDE "ch.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (ESPSDENABLE)
|
|
#INCLUDE "espsd.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (SCSIENABLE)
|
|
#INCLUDE "scsi.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (CHSCSIENABLE)
|
|
#INCLUDE "ch376scsi.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (CHUFIENABLE)
|
|
#INCLUDE "ch376ufi.asm"
|
|
#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; MULTI-FUNCTION MODULES
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
; - PRP (PRPCON, PRPSD)
|
|
; - PPP (PPPCON, PPPSD)
|
|
; - ESP (ESPCON, ESPSER)
|
|
;
|
|
#IF (PRPENABLE)
|
|
#INCLUDE "prp.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (PPPENABLE)
|
|
#INCLUDE "ppp.asm"
|
|
#ENDIF
|
|
;
|
|
#IF (ESPENABLE)
|
|
#INCLUDE "esp.asm"
|
|
#ENDIF
|
|
;
|
|
;--------------------------------------------------------------------------------------------------
|
|
; END OF DEVICE DRIVERS
|
|
;--------------------------------------------------------------------------------------------------
|
|
;
|
|
.DW $0000 ; END OF MODULES MARKER
|
|
;
|
|
HB_DRIVERS_END .EQU $
|
|
;
|
|
;
|
|
;
|
|
MEMECHO "RTCDEF="
|
|
MEMECHO RTCDEF
|
|
MEMECHO "\n"
|
|
;
|
|
;==================================================================================================
|
|
; 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
|
|
;
|
|
HB_CURPHASE .DB 0 ; CURRENT OPERATIONAL PHASE (SEE HB_PHASE_... IN STD.ASM)
|
|
;
|
|
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 / 1000 ; 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_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
|
|
|