mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 14:11:48 -06:00
If serial hardware flow control is enabled, but not working, then a system will appear dead because it won't send any data to the host computer. This change suppresses hardware flow control during boot just to ensure that boot messages can make it to the serial console. This will only be effective for serial interfaces that support dynamic management of HFC.
7343 lines
180 KiB
NASM
7343 lines
180 KiB
NASM
;
|
|
;==================================================================================================
|
|
; HBIOS
|
|
;==================================================================================================
|
|
;
|
|
; THIS FILE CONTAINS THE HBIOS IMAGE THAT IS INTENDED TO RUN IN A DEDICATED RAM BANK. THE CODE IS
|
|
; CONSTRUCTED SUCH THAT IT CAN BE LAUNCHED IN A VARIETY OF MODES AND INSTALL ITSELF. A SMALL 512
|
|
; BYTE PROXY IS PLACED AT THE TOP OF CPU MEMORY (FE00H-FFFFH). THIS PROXY CODE ALLOWS CODE
|
|
; RUNNING FROM ANY BANK TO INVOKE HBIOS FUNCTIONS. NORMALLY, ANY BANK THAT RUNS CODE WOULD SETUP
|
|
; THE RST 8 VECTOR TO POINT TO THE PROXY INVOKE ENTRY POINT AT FFF0H. CALLS VIA THE PROXY INVOKE
|
|
; ENTRY POINT TRANSPARENTLY SWAP IN THE HBIOS BANK, PERFORM THE REQUESTED FUNCTION, AND RETURN
|
|
; WITH THE ORIGINAL BANK ACTIVE. THE CODE USING HBIOS FUNCTIONS DOES NOT NEED TO BE AWARE OF
|
|
; THE BANK SWITCHING THAT OCCURS.
|
|
;
|
|
; THIS FILE CAN BE COMPILED TO BOOT IN ONE OF 3 MODES (ROM, APPLICATION, OR IMAGE) AS DESCRIBED
|
|
; BELOW. WHEN COMPILED, YOU MUST DEFINE EXACTLY ONE OF THE FOLLOWING MACROS:
|
|
;
|
|
; - ROMBOOT: BOOT FROM A ROM BANK
|
|
;
|
|
; WHEN ROMBOOT IS DEFINED, THE FILE IS ASSEMBLED TO BE IMBEDDED AT THE START OF A ROM
|
|
; ASSUMING THAT THE CPU WILL START EXECUTION AT ADDRESS 0. AFTER PERFORMING MINIMAL
|
|
; SYSTEM INITIALIZATION, THE IMAGE OF THE RUNNING ROM BANK IS COPIED TO A RAM BANK
|
|
; CREATING A SHADOW COPY IN RAM. EXECUTION IS THAN TRANSFERRED TO THE RAM SHADOW COPY.
|
|
; THIS IS ESSENTIAL BECAUSE THE HBIOS CODE DOES NOT SUPPORT RUNNING IN READ ONLY MEMORY
|
|
; (EXCEPT FOR THE INITIAL LAUNCHING CODE). IN THIS MODE, THE HBIOS INITIALIZATION WILL
|
|
; ALSO COPY THE OS IMAGES BANK IN ROM TO THE USER RAM BANK AND LAUNCH IT AFTER HBIOS
|
|
; IS INSTALLED.
|
|
;
|
|
; - 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 USER RAM
|
|
; BANK AND LAUNCHED AFTER HBIOS HAS INSTALLED ITSELF.
|
|
;
|
|
; - IMGBOOT: BOOT FROM AN IMAGE FILE THAT HAS BEEN PLACED IN THE USER BANK
|
|
;
|
|
; 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:
|
|
;
|
|
; hbios.asm
|
|
; - std.asm
|
|
; - ver.inc
|
|
; - hbios.inc
|
|
; - build.inc
|
|
; - config/<plt>_<cfg>.asm
|
|
; - cfg_<plt>.asm
|
|
; - [z180.inc|z280.inc]
|
|
; - [eipc.inc]
|
|
; - <drivers>.asm
|
|
; - <fonts>.asm
|
|
; - util.asm
|
|
; - time.asm
|
|
; - bcd.asm
|
|
; - decode.asm
|
|
; - encode.asm
|
|
; - [xio|mio].asm
|
|
; - [dsky.asm|dskyng.asm]
|
|
; - unlzsa2s.asm
|
|
;
|
|
; INCLUDE GENERIC STUFF
|
|
;
|
|
#INCLUDE "std.asm"
|
|
;
|
|
#DEFINE HBIOS
|
|
;
|
|
; MAKE SURE EXACTLY ONE OF ROMBOOT, APPBOOT, IMGBOOT IS DEFINED.
|
|
;
|
|
MODCNT .EQU 0
|
|
#IFDEF ROMBOOT
|
|
MODCNT .SET MODCNT + 1
|
|
#ENDIF
|
|
#IFDEF APPBOOT
|
|
MODCNT .SET MODCNT + 1
|
|
#ENDIF
|
|
#IFDEF 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
|
|
;
|
|
; SOME HARDWARE REQUIRES A SPECIFIC ROMSIZE (NOTABLY ZZRCC) OR THE
|
|
; RESULTING BUILD IMAGES WILL BE CORRUPT. ROMSIZE_CHK IS SPECIFIED
|
|
; IN THE CONFIG FILE AND IS VERIFIED AGAINST THE ROMSIZE BEING USED
|
|
; BY THE BUILD. A ROMSIZE_CHK VALUE OF 0 INDICATES THE VERIFICATION
|
|
; IS DISABLED (WHICH IT USUALLY IS).
|
|
;
|
|
#IF (ROMSIZE_CHK != 0) & (ROMSIZE != ROMSIZE_CHK)
|
|
.ECHO "*** ERROR: ROMSIZE VALUE VERIFICATION FAILURE.\n"
|
|
.ECHO "THIS CONFIGURATION REQUIRES A ROMSIZE OF " \ .ECHO ROMSIZE_CHK \ .ECHO ".\n"
|
|
.ECHO "BUILD IS USING A ROMSIZE OF " \ .ECHO ROMSIZE \ .ECHO ".\n"
|
|
.ECHO "SEE COMMENTS IN HBIOS.ASM.\n"
|
|
!!! ; FORCE AN ASSEMBLY ERROR
|
|
#ENDIF
|
|
;
|
|
;
|
|
;
|
|
#IF (DIAGENABLE)
|
|
#DEFINE DIAG(N) PUSH AF
|
|
#DEFCONT \ LD A,N
|
|
#DEFCONT \ OUT (DIAGPORT),A
|
|
#DEFCONT \ POP AF
|
|
#ELSE
|
|
#DEFINE DIAG(N) \;
|
|
#ENDIF
|
|
;
|
|
; SCxxx: LED Port=0x0E, bit 2, inverted, dedicated port
|
|
; TinyZ80: LED Port=0x6E, bit 0, inverted, dedicated port
|
|
; Z80-512K: LED Port=0x6E, bit 0, inverted, dedicated port
|
|
; MBC: LED Port=0x70, bits 1-0, normal, shared w/ RTC port
|
|
;
|
|
#IF (LEDENABLE)
|
|
#IF (LEDMODE == LEDMODE_STD)
|
|
#DEFINE LED(N) PUSH AF
|
|
#DEFCONT \ LD A,~N
|
|
#DEFCONT \ OUT (LEDPORT),A
|
|
#DEFCONT \ POP AF
|
|
#ENDIF
|
|
#IF (LEDMODE == LEDMODE_RTC)
|
|
#DEFINE LED(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
|
|
#ELSE
|
|
#DEFINE LED(N) \;
|
|
#ENDIF
|
|
;
|
|
#DEFINE SYSCHKERR(HB_ERR) \
|
|
#DEFCONT \ CALL SYSCHKA
|
|
#DEFCONT \ LD A,HB_ERR
|
|
#DEFCONT \ OR A
|
|
;
|
|
;
|
|
;
|
|
#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
|
|
;
|
|
#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
|
|
;
|
|
;
|
|
;
|
|
; 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 SET ANY BITS THEY OWN WITHIN THE RTC LATCH BYTE.
|
|
; SINCE RTCDEF IS CHANGED AFTER IT NEEDS TO BE USED BY THE CODE, IT
|
|
; CANNOT 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 HBIOS.ASM. SO (RTCDEFVAL) CAN BE USED ANYWHERE IN
|
|
; HBIOS.ASM TO ACCESS THE FINAL RTCDEF VALUE.
|
|
;
|
|
RTCDEF .EQU 0 ; ALLOWS DRIVERS TO SET BITS
|
|
;
|
|
#IF (PLATFORM == PLT_SCZ180)
|
|
RTCDEF .SET RTCDEF | %00000001 ; SC128 I2C SCL BIT
|
|
#ENDIF
|
|
;
|
|
#IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_MBC))
|
|
RTCDEF .SET RTCDEF & ~%00001000 ; INITIAL SPEED LOW
|
|
#ENDIF
|
|
;
|
|
#IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_SBC))
|
|
RTCDEF .SET RTCDEF | %00001000 ; INITIAL SPEED LOW
|
|
#ENDIF
|
|
;
|
|
;
|
|
;
|
|
#IFNDEF APPBOOT
|
|
;
|
|
.ORG 0
|
|
;
|
|
;==================================================================================================
|
|
; NORMAL PAGE ZERO SETUP, RET/RETI/RETN AS APPROPRIATE, LEAVE INTERRUPTS DISABLED
|
|
;==================================================================================================
|
|
;
|
|
.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)
|
|
JP INT_IM1 ; JP TO INTERRUPT HANDLER IN HI MEM
|
|
#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, ", ", TIMESTAMP, 0
|
|
AUTH .DB "WBW",0
|
|
DESC .DB "ROMWBW v", BIOSVER, ", Copyright (C) 2020, Wayne Warthen, GNU GPL v3", 0
|
|
;
|
|
.FILL ($100 - $),$FF ; PAD REMAINDER OF PAGE ZERO
|
|
;
|
|
#ENDIF
|
|
;
|
|
;==================================================================================================
|
|
; HBIOS CONFIGURATION BLOCK (HCB)
|
|
;==================================================================================================
|
|
;
|
|
.ORG HCB_LOC
|
|
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
|
|
;
|
|
; MEMORY MANAGEMENT VARIABLES START AT $20
|
|
;
|
|
.FILL (HCB + $20 - $),0
|
|
;
|
|
CB_HEAP .DW 0
|
|
CB_HEAPTOP .DW 0
|
|
;
|
|
; STANDARD BANK ID'S START AT $D8. DEFAULT VALUES FOR 512KB SYSTEM WITH NO RESERVED BANKS
|
|
;
|
|
.FILL (HCB + $D8 - $),0
|
|
;
|
|
CB_BIDCOM .DB BID_COM
|
|
CB_BIDUSR .DB BID_USR
|
|
CB_BIDBIOS .DB BID_BIOS
|
|
CB_BIDAUX .DB BID_AUX
|
|
CB_BIDRAMD0 .DB BID_RAMD0
|
|
CB_BIDRAMDN .DB BID_RAMDN
|
|
CB_BIDROMD0 .DB BID_ROMD0
|
|
CB_BIDROMDN .DB BID_ROMDN
|
|
;
|
|
.FILL (HCB + HCB_SIZ - $),0 ; PAD REMAINDER OF HCB
|
|
;
|
|
;==================================================================================================
|
|
; 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
|
|
;
|
|
.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 (128 BYTES)
|
|
; HBIOS PROXY COPY BUFFER $FF80 (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 (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.
|
|
;; Preserve all Registers including Flags.
|
|
;;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
;
|
|
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.
|
|
;BIT 7,A ; [8] TEST RAM BIT
|
|
;JR Z,HBX_ROM ; [12/7] IF NOT SET, JUST DO ROM
|
|
OR A ; [4] SET FLAGS
|
|
JP P,HBX_ROM ; [10] 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)
|
|
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 (MPGSEL_0),A ; BANK_0: 0K - 16K
|
|
INC A ;
|
|
OUT (MPGSEL_1),A ; BANK_1: 16K - 32K
|
|
#IF (CPUFAM == CPU_Z280)
|
|
PCACHE
|
|
#ENDIF
|
|
RET ; DONE
|
|
#ENDIF
|
|
;
|
|
#IF (MEMMGR == MM_N8)
|
|
BIT 7,A ; TEST BIT 7 FOR RAM VS. ROM
|
|
JR Z,HBX_ROM ; IF NOT SET, SELECT ROM PAGE
|
|
;
|
|
HBX_RAM:
|
|
AND %00011111 ; AVOID WRAPPING BITS
|
|
RLCA ; SCALE SELECTOR TO
|
|
RLCA ; ... GO FROM Z180 4K PAGE SIZE
|
|
RLCA ; ... TO DESIRED 32K PAGE SIZE
|
|
OUT0 (Z180_BBR),A ; WRITE TO BANK BASE
|
|
LD A,N8_DEFACR | 80H ; SELECT RAM BY SETTING BIT 7
|
|
OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER
|
|
RET ; DONE
|
|
;
|
|
HBX_ROM:
|
|
OUT0 (N8_RMAP),A ; BANK INDEX TO N8 RMAP REGISTER
|
|
XOR A ; ZERO ACCUM
|
|
OUT0 (Z180_BBR),A ; ZERO BANK BASE
|
|
LD A,N8_DEFACR ; SELECT ROM BY CLEARING BIT 7
|
|
OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER
|
|
RET ; DONE
|
|
#ENDIF
|
|
;
|
|
#IF (MEMMGR == MM_Z180)
|
|
RLCA ; RAM FLAG TO CARRY FLAG AND BIT 0
|
|
JR NC,HBX_BNKSEL1 ; IF NC, WANT ROM PAGE, SKIP AHEAD
|
|
XOR %00100001 ; SET BIT FOR HI 512K, CLR BIT 0
|
|
HBX_BNKSEL1:
|
|
AND %00111111 ; AVOID WRAPPING BITS
|
|
RLCA ; CONTINUE SHIFTING TO SCALE SELECTOR
|
|
RLCA ; FOR Z180 4K PAGE -> DESIRED 32K PAGE
|
|
OUT0 (Z180_BBR),A ; WRITE TO BANK BASE
|
|
RET ; DONE
|
|
#ENDIF
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
PUSH BC ; SAVE BC
|
|
PUSH HL ; SAVE HL
|
|
LD B,$00 ; FIRST USER PDR
|
|
SC Z280_BNKSEL ; SYSCALL
|
|
POP HL ; RESTORE HL
|
|
POP BC ; RESTORE BC
|
|
RET ; DONE
|
|
#ENDIF
|
|
;
|
|
#IF (MEMMGR == MM_ZRC)
|
|
BIT 7,A ; BIT 7 SET REQUESTS RAM PAGE
|
|
JR Z,HBX_ROM ; NOT SET, SELECT ROM PAGE
|
|
RES 7,A ; RAM PAGE REQUESTED: CLEAR ROM BIT
|
|
ADD A,ROMSIZE / 32 ; STARTING RAM BANK NUMBER OFFSET
|
|
;
|
|
HBX_ROM:
|
|
OUT ($1F),A ; HCS WRITE TO THE BANK CONTROL REGISTER
|
|
RET ; DONE
|
|
#ENDIF
|
|
;
|
|
#IF (MEMMGR == MM_MBC)
|
|
;
|
|
#IF (INTMODE == 1)
|
|
LD (HBX_MMA),A ; SAVE ACCUM
|
|
LD A,I ; GET INT CTL REG
|
|
HB_DI ; DISABLE INTS
|
|
PUSH AF ; SAVE INT CTL REG
|
|
LD A,(HBX_MMA) ; RESTORE ACCUM
|
|
#ENDIF
|
|
;
|
|
OR A ; SET FLAGS
|
|
JP P,HBX_ROM ; BIT 7 INDICATES RAM
|
|
OUT (MPCL_ROM),A ; ENSURE ROM PAGE OUT OF MEMORY BEFORE SWITCH
|
|
; SEE MBC RUNTIME MEMORY SIZE ADJUSTMENT
|
|
HBX_MBCMSK .EQU $+1 ; FORCE TOP 32K ; MASK POPULATED
|
|
XOR %00000000 ; TO BE IN FIRST CHIP ; DURING INITIALIZATION
|
|
OUT (MPCL_RAM),A ; SET RAM PAGE SELECTOR
|
|
JR HBX_RAMX
|
|
HBX_ROM:
|
|
OUT (MPCL_RAM),A ; ENSURE RAM PAGE OUT OF MEMORY BEFORE SWITCH
|
|
OUT (MPCL_ROM),A ; SET ROM PAGE SELECTOR
|
|
;
|
|
HBX_RAMX:
|
|
;
|
|
#IF (INTMODE == 1)
|
|
POP AF ; RESTORE INT CTL REG
|
|
JP PO,$+4 ; WERE INTS DISABLED AT ENTRY?
|
|
EI ; *** DO NOT USE HB_EI HERE ***
|
|
LD A,(HBX_MMA) ; RESTORE INCOMING ACCUM
|
|
#ENDIF
|
|
;
|
|
RET
|
|
;
|
|
HBX_MMA .DB 0 ; TEMPORARY STORAGE FOR REG A
|
|
#ENDIF
|
|
;
|
|
#IF (MEMMGR == MM_RPH)
|
|
BIT 7,A ; TEST BIT 7 FOR RAM VS. ROM
|
|
JR Z,HBX_ROM ; IF NOT SET, SELECT ROM PAGE
|
|
;
|
|
HBX_RAM:
|
|
AND %00011111 ; AVOID WRAPPING BITS
|
|
RLCA ; SCALE SELECTOR TO
|
|
RLCA ; ... GO FROM Z180 4K PAGE SIZE
|
|
RLCA ; ... TO DESIRED 32K PAGE SIZE
|
|
OUT0 (Z180_BBR),A ; WRITE TO BANK BASE
|
|
LD A,RPH_DEFACR | 80H ; SELECT RAM BY SETTING BIT 7
|
|
OUT0 (RPH_ACR),A ; ... IN RPH ACR REGISTER
|
|
RET ; DONE
|
|
;
|
|
HBX_ROM:
|
|
OR RPH_DEFACR ; COMBINE WITH DEFAULT BITS
|
|
OUT0 (RPH_ACR),A ; BANK INDEX TO RPH ACR REGISTER
|
|
XOR A ; ZERO ACCUM
|
|
OUT0 (Z180_BBR),A ; ZERO BANK BASE
|
|
RET ; DONE
|
|
#ENDIF
|
|
;
|
|
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; Copy Data - Possibly between banks. This resembles CP/M 3, but
|
|
; usage of the HL and DE registers is reversed.
|
|
; Caller MUST preset HBX_SRCBNK and HBX_DSTBNK.
|
|
; IM1/IM2 interrupts are disabled during HBX_BNKCPY.
|
|
; Enter:
|
|
; HL = Source Address
|
|
; DE = Destination Address
|
|
; BC = Number of bytes to copy
|
|
; Exit : None
|
|
; Uses : AF,BC,DE,HL
|
|
;
|
|
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
;
|
|
HBX_BNKCPY:
|
|
#IF (MEMMGR == MM_Z280)
|
|
SC Z280_BNKCPYX ; SYSCALL TO BNKCPYX
|
|
RET
|
|
;
|
|
IOPRSAV .DW 0 ; TEMP STORAGE FOR IOPR
|
|
;
|
|
#ELSE
|
|
#IF (CPUFAM == CPU_Z280)
|
|
PUSH HL
|
|
PUSH BC
|
|
LD C,Z280_MSR
|
|
LDCTL HL,(C)
|
|
POP BC
|
|
EX (SP),HL
|
|
HB_DI
|
|
#ELSE
|
|
LD A,I
|
|
HB_DI
|
|
PUSH AF
|
|
#ENDIF
|
|
LD (HBX_BC_SP),SP ; PUT STACK
|
|
LD SP,HBX_TMPSTK ; ... IN HI MEM
|
|
|
|
LD A,(HB_CURBNK) ; GET CURRENT BANK
|
|
PUSH AF ; AND SAVE TO RESTORE LATER
|
|
PUSH BC ; CUR LEN -> (SP)
|
|
;
|
|
HBX_BC_LOOP:
|
|
EX (SP),HL ; HL := CUR LEN, (SP) := CUR SRC
|
|
LD BC,HBX_BUFSIZ ; SET BC TO BOUNCE BUFFER SIZE
|
|
OR A ; CLEAR CARRY FLAG
|
|
SBC HL,BC ; CUR LEN := CUR LEN - BBUF SIZE
|
|
JR C,HBX_BC_LAST ; END GAME, LESS THAN BBUF BYTES LEFT
|
|
EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN
|
|
CALL HBX_BC_ITER ; DO A FULL BBUF SIZE CHUNK
|
|
JR HBX_BC_LOOP ; AND REPEAT TILL DONE
|
|
;
|
|
HBX_BC_LAST:
|
|
; HL IS BETWEEN -(BBUF SIZE) AND -1, BC = BBUF SIZE
|
|
OR A ; CLEAR CARRY
|
|
ADC HL,BC ; HL := REM LEN (0 - 127)
|
|
EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN
|
|
POP BC ; BC := REM LEN
|
|
CALL NZ,HBX_BC_ITER ; DO FINAL CHUNK, IFF > 0 BYTES
|
|
POP AF ; RECOVER ORIGINAL BANK
|
|
CALL HBX_BNKSEL ; SWITCH
|
|
|
|
LD SP,$FFFF ; RESTORE STACK
|
|
HBX_BC_SP .EQU $ - 2 ; ... TO ORIGINAL VALUE
|
|
#IF (CPUFAM == CPU_Z280)
|
|
EX (SP),HL ; SAVE HL, RECOVER MSR
|
|
PUSH BC ; SAVE BC
|
|
LD C,Z280_MSR
|
|
LDCTL (C),HL
|
|
POP BC ; RECOVER BC
|
|
POP HL ; RECOVER HL
|
|
#ELSE
|
|
POP AF
|
|
JP PO,$+4
|
|
EI ; *** DO NOT USE HB_EI HERE ***
|
|
#ENDIF
|
|
RET
|
|
;
|
|
HBX_BC_ITER:
|
|
; HL = SRC ADR, DE = DEST ADR, BC = LEN
|
|
PUSH BC ; SAVE COPY LEN
|
|
PUSH DE ; FINAL DEST ON STACK
|
|
LD DE,HBX_BUF ; SET DEST TO BUF
|
|
LD A,(HB_SRCBNK) ; GET SOURCE BANK
|
|
CALL HBX_BNKSEL ; SWITCH TO SOURCE BANK
|
|
LDIR ; HL -> BUF (DE), BC BYTES, HL UPDATED SRC ADR
|
|
POP DE ; DE := FINAL DEST
|
|
POP BC ; GET LEN BACK IN BC
|
|
PUSH HL ; SAVE UPDATED SRC ADR
|
|
LD HL,HBX_BUF ; SET SRC ADR TO BUF
|
|
LD A,(HB_DSTBNK) ; GET DEST BANK
|
|
CALL HBX_BNKSEL ; SWITCH TO DEST BANK
|
|
LDIR ; BUF (HL) -> DE, BC BYTES, DE UPDATED DEST ADR
|
|
POP HL ; RECOVER UPDATED SRC ADR
|
|
; HL = UPDATED SRC, DE = UPDATED DEST, BC = 0
|
|
RET
|
|
#ENDIF
|
|
;
|
|
; CALL A ROUTINE IN ANOTHER BANK.
|
|
; CALLER MUST ENSURE STACK IS ALREADY IN HIGH MEMORY AND HAS ADEQUATE SPACE.
|
|
; IF IM1 INTERRUPTS ARE POSSIBLE, CALLER MUST EITHER DISABLE THEM PRIOR TO
|
|
; BNKCALL OR MAKE SURE THAT PAGE ZERO IN TARGET BANK IS PREPARED FOR THEM.
|
|
; ON INPUT A=TARGET BANK, IX=TARGET ADDRESS
|
|
;
|
|
HBX_BNKCALL:
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
CP BID_BIOS ; CALLING HBIOS?
|
|
JR NZ,HBX_BNKCALL3 ; NOPE, DO NORMAL PROCESSING
|
|
SC HBX_BNKCALL2 ; SYSCALL TO BNKCALL2
|
|
RET ; THEN RETURN
|
|
;
|
|
HBX_BNKCALL2:
|
|
HB_EI ; INTS ARE OK
|
|
LD (HBX_BNKCALL_GO+1),IX ; SETUP DEST ADR
|
|
PCACHE ; CRITICAL!!!
|
|
HBX_BNKCALL_GO:
|
|
JP $FFFF ; DO THE REAL WORK AND RETURN
|
|
#ENDIF
|
|
;
|
|
HBX_BNKCALL3:
|
|
LD (HBX_BNKCALL_BNK+1),A ; STUFF TARGET BANK TO CALL INTO CODE BELOW
|
|
LD (HBX_BNKCALL_ADR+1),IX ; STUFF ADDRESS TO CALL INTO CODE BELOW
|
|
LD A,(HB_CURBNK) ; GET CURRENT BANK
|
|
PUSH AF ; SAVE FOR RETURN
|
|
HBX_BNKCALL_BNK:
|
|
LD A,$FF ; LOAD BANK TO CALL ($FF OVERLAID AT ENTRY)
|
|
CALL HBX_BNKSEL ; ACTIVATE THE NEW BANK
|
|
HBX_BNKCALL_ADR:
|
|
CALL $FFFF ; CALL ROUTINE ($FFFF IS OVERLAID ABOVE)
|
|
EX (SP),HL ; SAVE HL AND GET BANK TO RESTORE IN HL
|
|
PUSH AF ; SAVE AF
|
|
LD A,H ; BANK TO RESTORE TO A
|
|
CALL HBX_BNKSEL ; RESTORE IT
|
|
POP AF ; RECOVER AF
|
|
POP HL ; RECOVER HL
|
|
RET
|
|
;
|
|
; PEEK & POKE ROUTINES
|
|
; ADDRESS IN HL, BANK IN D, VALUE IN/OUT IN E, A IS TRASHED
|
|
;
|
|
; THESE ROUTINES ARE NOT INTENDED TO BE CALLED DIRECTLY -- THEY ARE
|
|
; HELPERS FOR THE HBIOS API AND ARE CALLED BY HBIOS BANK CODE. THE
|
|
; HBIOS BANK CODE BRACKETS THE USE OF THESE ROUTINES WITH DI/EI IF
|
|
; NECESSARY FOR THE CURRENT INTERRUPT MODE.
|
|
;
|
|
; NOTE: THE SIZE OF HBX_TMPSTK (TYPICALLY 20 BYTES) IS INSUFFICIENT FOR
|
|
; FREERTOS IF AN INTERRUPT STRIKES WHILE THE TEMPORARY STACK IS ACTIVE.
|
|
; BELOW, HBX_BUF HAS BEEN USURPED TO PROVIDE A LARGER TEMP STACK TO
|
|
; ACCOMMODATE FREERTOS. HBX_BUF IS ONLY USED AS A BOUNCE BUFFER, SO IT'S
|
|
; USE WILL NEVER OVERLAP WITH BELOW.
|
|
;
|
|
HBX_PEEK:
|
|
LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME
|
|
LD SP,HBX_BUF_END ; BORROW HBX_BUF FOR TEMP STACK
|
|
LD 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 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
|
|
;
|
|
; SPECIAL ROUTINE IN HIGH MEMORY TO PERFORM A COLD START ON Z280
|
|
; THIS REQUIRES US TO REMAP LOW MEMORY, THEN JUMP TO ZERO
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
;
|
|
Z280_RESTART:
|
|
DI ; KILL INTERRUPTS
|
|
LD SP,HBX_LOC ; STACK IN HIGH MEMORY
|
|
;
|
|
; COPY Z280 BANK SELECT ROUTINE TO HIGH MEMORY
|
|
LD HL,Z280_BNKSEL
|
|
LD DE,$8000
|
|
LD BC,Z280_BNKSEL_LEN
|
|
LDIR
|
|
;
|
|
; MAKE ROM BOOT BANK ACTIVE IN LOW SYS MEM
|
|
LD A,BID_BOOT
|
|
LD B,$10 ; FIRST SYS PDR
|
|
CALL $8000 ; DO IT
|
|
;
|
|
; NOW JUST JUMP TO START OF ROM BOOT CODE
|
|
JP 0
|
|
#ENDIF
|
|
;
|
|
; PRIVATE STACK AT END OF HBIOS CODE
|
|
; OCCUPIES SPACE BEFORE IVT
|
|
;
|
|
HBX_INTSTKSIZ .EQU $FF00 - $
|
|
.ECHO "HBIOS INT STACK space: "
|
|
.ECHO HBX_INTSTKSIZ
|
|
.ECHO " bytes.\n"
|
|
.FILL HBX_INTSTKSIZ,$FF
|
|
HBX_INTSTK .EQU $
|
|
;
|
|
;#IF (HBX_INTSTKSIZ < 24)
|
|
#IF (HBX_INTSTKSIZ < 22)
|
|
.ECHO "*** ERROR: INTERRUPT STACK IS TOO SMALL!!!\n"
|
|
!!! ; FORCE AN ASSEMBLY ERROR
|
|
#ENDIF
|
|
;
|
|
#IF ((INTMODE == 2) | (INTMODE == 3))
|
|
;
|
|
; HBIOS INTERRUPT SLOT ASSIGNMENTS
|
|
;
|
|
; # Z80 Z180
|
|
; --- -------------- --------------
|
|
; 0 CTC0A INT1 -+
|
|
; 1 CTC0B INT2 |
|
|
; 2 CTC0C TIM0 |
|
|
; 3 CTC0D TIM1 |
|
|
; 4 UART0 DMA0 +- Z180 INTERNAL
|
|
; 5 UART1 DMA1 |
|
|
; 6 CSIO |
|
|
; 7 SIO0 SER0 |
|
|
; 8 SIO1 SER1 -+
|
|
; 9 PIO0A PIO0A
|
|
; 10 PIO0B PIO0B
|
|
; 11 PIO1A PIO1A
|
|
; 12 PIO1B PIO1B
|
|
; 13 SIO0
|
|
; 14 SIO1
|
|
; 15
|
|
;
|
|
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
|
|
;
|
|
#ENDIF
|
|
;
|
|
INT_IM1:
|
|
#IF (INTMODE == 1)
|
|
CALL HBX_INT
|
|
.DB $00
|
|
#ELSE
|
|
RETI ; UNEXPECTED INT, RET W/ INTS LEFT DISABLED
|
|
#ENDIF
|
|
;
|
|
#IF (INTMODE > 0)
|
|
;
|
|
HBX_INT: ; COMMON INTERRUPT ROUTING CODE
|
|
;
|
|
#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
|
|
;
|
|
; 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
|
|
;
|
|
HB_EI ; ENABLE INTERRUPTS
|
|
RETI ; AND RETURN
|
|
;
|
|
#ENDIF
|
|
|
|
#ENDIF
|
|
;
|
|
; SMALL TEMPORARY STACK FOR USE BY HBX_BNKCPY
|
|
;
|
|
HBX_TMPSTKSIZ .EQU (HBX_XFC - HBX_BUFSIZ - $)
|
|
.ECHO "HBIOS TEMP STACK space: "
|
|
.ECHO HBX_TMPSTKSIZ
|
|
.ECHO " 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)
|
|
;
|
|
#IFDEF ROMBOOT
|
|
.DB BID_BOOT ; HB_CURBNK: CURRENTLY ACTIVE LOW MEMORY BANK ID
|
|
#ELSE
|
|
.DB BID_USR ; HB_CURBNK: CURRENTLY ACTIVE LOW MEMORY BANK ID
|
|
#ENDIF
|
|
.DB $FF ; HB_INVBNK: BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION
|
|
.DW 0 ; HB_SRCADR: BNKCPY SOURCE ADDRESS
|
|
.DB BID_USR ; HB_SRCBNK: BNKCPY SOURCE BANK ID
|
|
.DW 0 ; HB_DSTADR: BNKCPY DESTINATION ADDRESS
|
|
.DB BID_USR ; HB_DSTBNK: BNKCPY DESTINATION BANK ID
|
|
.DW 0 ; HB_CPYLEN: BNKCPY LENGTH
|
|
.FILL 4,0 ; FILLER, RESERVED FOR FUTURE HBIOS USE
|
|
.DB 0 ; SHADOW VALUE FOR RTC LATCH PORT
|
|
.DB $FE ; HB_LOCK: HBIOS MUTEX LOCK
|
|
JP HBX_INVOKE ; HB_INVOKE: FIXED ADR ENTRY FOR HBX_INVOKE (ALT FOR RST 08)
|
|
JP HBX_BNKSEL ; HB_BNKSEL: FIXED ADR ENTRY FOR HBX_BNKSEL
|
|
JP HBX_BNKCPY ; HB_BNKCPY: FIXED ADR ENTRY FOR HBX_BNKCPY
|
|
JP HBX_BNKCALL ; HB_BNKCALL: FIXED ADR ENTRY FOR HBX_BNKCALL
|
|
.DW HBX_IDENT ; ADDRESS OF HBIOS PROXY START (DEPRECATED)
|
|
.DW HBX_IDENT ; HB_IDENT: ADDRESS OF HBIOS IDENT INFO DATA BLOCK
|
|
;
|
|
.FILL MEMTOP - $ ; FILL TO END OF MEMORY (AS NEEDED)
|
|
.ORG HBX_IMG + HBX_SIZ ; RESET ORG
|
|
;
|
|
;==================================================================================================
|
|
; HBIOS CORE
|
|
;==================================================================================================
|
|
;
|
|
;==================================================================================================
|
|
; ENTRY VECTORS (JUMP TABLE) AND INTERNAL PROCESSING STACK
|
|
;==================================================================================================
|
|
;
|
|
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
|
|
;
|
|
;==================================================================================================
|
|
; INTERRUPT VECTOR TABLE (MUST START AT PAGE BOUNDARY!!!)
|
|
;==================================================================================================
|
|
;
|
|
; 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.
|
|
;
|
|
#IF (INTMODE < 2)
|
|
;
|
|
HB_IVT:
|
|
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
|
|
;
|
|
#ENDIF
|
|
;
|
|
; 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.
|
|
;
|
|
#IF ((INTMODE == 2) | (INTMODE == 3))
|
|
;
|
|
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
|
|
;
|
|
#ENDIF
|
|
;
|
|
;==================================================================================================
|
|
; SYSTEM INITIALIZATION
|
|
;==================================================================================================
|
|
;
|
|
HB_START:
|
|
;
|
|
#IFDEF APPBOOT
|
|
#IF (MEMMGR == MM_Z280)
|
|
LD A,DIAG_01
|
|
OUT (DIAGPORT),A
|
|
LD DE,Z280_BOOTERR
|
|
LD C,9
|
|
LD A,DIAG_02
|
|
OUT (DIAGPORT),A
|
|
CALL $0005
|
|
LD A,DIAG_04
|
|
OUT (DIAGPORT),A
|
|
RET
|
|
;
|
|
Z280_BOOTERR .TEXT "\r\n\r\n*** Application mode boot not supported under Z280 native memory management!!!\r\n\r\n$"
|
|
#ENDIF
|
|
#ENDIF
|
|
;
|
|
DI ; NO INTERRUPTS
|
|
IM 1 ; INTERRUPT MODE 1
|
|
|
|
;#IF ((PLATFORM == PLT_MBC) | (PLATFORM == PLT_SBC))
|
|
; INITIALIZE RTC LATCH BYTE
|
|
; FOR SOME PLATFORMS THIS CONTROLS HI/LO SPEED CIRCUIT
|
|
LD A,(RTCDEFVAL) ; GET DEFAULT VALUE
|
|
OUT (RTCIO),A ; SET IT
|
|
;#ENDIF
|
|
;
|
|
#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
|
|
;
|
|
#IF (DIAGENABLE)
|
|
LD A,DIAG_01
|
|
OUT (DIAGPORT),A
|
|
#ENDIF
|
|
#IF (LEDENABLE)
|
|
#IF (LEDMODE == LEDMODE_STD)
|
|
XOR A ; LED IS INVERTED, TURN IT ON
|
|
#ENDIF
|
|
#IF (LEDMODE == LEDMODE_RTC)
|
|
LD A,(RTCDEFVAL) ; DEFAULT LATCH VALUE
|
|
OR %00000001 ; LED 0 ON
|
|
#ENDIF
|
|
OUT (LEDPORT),A
|
|
#ENDIF
|
|
;
|
|
; 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
|
|
;
|
|
#IF (CPUFAM == CPU_Z280)
|
|
; 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
|
|
;
|
|
; START BY SELECTING I/O PAGE $FF
|
|
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
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
;
|
|
; INITIALIZE ALL OF THE SYSTEM PAGE DESCRIPTORS WITH BLOCK MOVE
|
|
XOR A ; FIRST USER PDR
|
|
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,16 ; PROGRAM 16 PDRS
|
|
OTIRW ; OTIRW
|
|
;
|
|
; INITIALIZE ALL OF THE USER PAGE DESCRIPTORS WITH BLOCK MOVE
|
|
LD A,$10 ; FIRST SYSTEM PDR
|
|
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,16 ; PROGRAM 16 PDRS
|
|
OTIRW ; OTIRW
|
|
;
|
|
; ENABLE MMU (SYSTEM AND USER TRANSLATION)
|
|
LD C,Z280_MMUMCR ; MMU MASTER CONTROL REGISTER
|
|
LD HL,$BBFF ; ENABLE USER & SYSTEM TRANSLATE
|
|
OUTW (C),HL
|
|
;
|
|
; DISABLE MEMORY REFRESH CYCLES
|
|
LD A,$08 ; DISABLED
|
|
OUT (Z280_RRR),A ; SET REFRESH RATE REGISTER
|
|
;
|
|
; CONFIGURE Z280 INT/TRAP VECTOR TABLE POINTER REGISTER
|
|
; WILL POINT TO ROM COPY FOR NOW, UPDATED TO RAM LATER ON
|
|
LD C,Z280_VPR
|
|
LD HL,Z280_IVT >> 8 ; TOP 16 BITS OF PHYSICAL ADR OF IVT
|
|
LDCTL (C),HL
|
|
;
|
|
JR Z280_INITZ ; JUMP TO CODE CONTINUATION
|
|
;
|
|
#IF (($ % 2) == 1)
|
|
; WORD ALIGN THE TABLE
|
|
.DB 0
|
|
#ENDIF
|
|
;
|
|
Z280_BOOTPDRTBL:
|
|
; LOWER 32 K (BANKED)
|
|
.DW ($000 << 4) | $A
|
|
.DW ($001 << 4) | $A
|
|
.DW ($002 << 4) | $A
|
|
.DW ($003 << 4) | $A
|
|
.DW ($004 << 4) | $A
|
|
.DW ($005 << 4) | $A
|
|
.DW ($006 << 4) | $A
|
|
.DW ($007 << 4) | $A
|
|
; UPPER 32 K (COMMON)
|
|
.DW (((((BID_COM & $7F) * 8) + 0) + (1 << (RAMLOC - 12))) << 4) | $A
|
|
.DW (((((BID_COM & $7F) * 8) + 1) + (1 << (RAMLOC - 12))) << 4) | $A
|
|
.DW (((((BID_COM & $7F) * 8) + 2) + (1 << (RAMLOC - 12))) << 4) | $A
|
|
.DW (((((BID_COM & $7F) * 8) + 3) + (1 << (RAMLOC - 12))) << 4) | $A
|
|
.DW (((((BID_COM & $7F) * 8) + 4) + (1 << (RAMLOC - 12))) << 4) | $A
|
|
.DW (((((BID_COM & $7F) * 8) + 5) + (1 << (RAMLOC - 12))) << 4) | $A
|
|
.DW (((((BID_COM & $7F) * 8) + 6) + (1 << (RAMLOC - 12))) << 4) | $A
|
|
.DW (((((BID_COM & $7F) * 8) + 7) + (1 << (RAMLOC - 12))) << 4) | $A
|
|
;
|
|
Z280_INITZ:
|
|
;
|
|
#ENDIF
|
|
;
|
|
; RESTORE I/O PAGE TO $00
|
|
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
|
|
;
|
|
#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
|
|
|
|
DIAG(DIAG_02)
|
|
|
|
; 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)
|
|
;
|
|
; IT HAS BEEN REPORTED THAT CMR NEEDS TO BE SET PRIOR TO CCR
|
|
; WHEN USING AN INPUT FREQUENCY THAT IS XTAL / 2.
|
|
; I NEVER EXPERIENCED A PROBLEM RELATED TO ORDER, BUT JUST
|
|
; FOR GOOD MEASURE, CMR IS SET PRIOR TO CCR BELOW.
|
|
; https://www.retrobrewcomputers.org/forum/index.php?t=msg&th=316&#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
|
|
;
|
|
#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
|
|
;
|
|
#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
|
|
;
|
|
#IF (MEMMGR == MM_Z2)
|
|
; SET PAGING REGISTERS
|
|
#IFDEF ROMBOOT
|
|
XOR A
|
|
OUT (MPGSEL_0),A
|
|
INC A
|
|
OUT (MPGSEL_1),A
|
|
#ENDIF
|
|
LD A,62
|
|
OUT (MPGSEL_2),A
|
|
INC A
|
|
OUT (MPGSEL_3),A
|
|
; ENABLE PAGING
|
|
LD A,1
|
|
OUT (MPGENA),A
|
|
#ENDIF
|
|
;
|
|
; AT THIS POINT, RAM SHOULD BE AVAILABLE IN THE COMMON BANK
|
|
; (TOP 32K).
|
|
;
|
|
; NOTIFICATION THAT WE HAVE MADE THE JUMP TO RAM BANK!
|
|
; THE DIAG() MACRO IS NOT USED BECAUSE IT USES THE STACK AND WE DO
|
|
; NOT WANT TO EFFECT RAM UNTIL AFTER THE BACKUP BATTERY STATUS CHECK
|
|
; IS PERFORMED NEXT.
|
|
;
|
|
#IF (DIAGENABLE)
|
|
LD A,DIAG_02
|
|
OUT (DIAGPORT),A
|
|
#ENDIF
|
|
;
|
|
; 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) = APPBANK
|
|
; 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
|
|
INC A ; 1 MEANS BAT OK
|
|
LD (HL),A
|
|
;
|
|
; INSTALL PROXY IN UPPER MEMORY
|
|
; THE HB_CURBNK MUST BE PRESERVED IF THIS IS AN APPBOOT.
|
|
;
|
|
LD A,(HB_CURBNK) ; SAVE EXISTING HB_CURBNK
|
|
LD DE,HBX_LOC ; AS PER ABOVE
|
|
LD HL,HBX_IMG
|
|
LD BC,HBX_SIZ
|
|
LDIR
|
|
;
|
|
#IFDEF APPBOOT
|
|
LD (HB_CURBNK),A ; RESTORE HB_CURBNK
|
|
#ENDIF
|
|
;
|
|
; SAVE CURRENT BANKID
|
|
;
|
|
; THIS IS NOT GOING TO WORK IF THE APP BOOT IMAGE IS LOADED
|
|
; USING THE UNA FAT32 LOADER. SHOULD PROBABLY CHECK THAT THERE
|
|
; IS A VALID ROMWBW PROXY IN MEMORY BEFORE DOING THIS. HOWEVER,
|
|
; THIS USE CASE IS PROBABLY NON-EXISTENT. THE IMG BOOT IMAGE
|
|
; SHOULD WORK FINE WITH THE UNA FAT32 LOADER.
|
|
;
|
|
; THIS VALUE IS TEMPORARILY STORED AT HBX_LOC - 2
|
|
; BECAUSE WE ARE CURRENTLY RUNNING IN ROM. AFTER WE TRANSITION HBIOS
|
|
; TO RAM, THE VALUE IS MOVED TO IT'S REAL LCOATION AT HB_APPBNK.
|
|
;
|
|
LD A,(HB_CURBNK) ; GET HB_CURBNK
|
|
LD (HBX_LOC - 2),A ; ... AND SAVE TEMP FOR APPBNK
|
|
;
|
|
; THE RTCVAL FIELD OF THE PROXY DATA NEEDS TO BE INITIALIZED HERE
|
|
; BECAUSE IT CANNOT BE PRE-INITIALIZED (SEE COMMENTS ABOVE WHERE
|
|
; RTCVAL EQUATE IS DEFINED).
|
|
;
|
|
LD A,(RTCDEFVAL)
|
|
LD (HB_RTCVAL),A
|
|
;
|
|
#IFDEF TESTING
|
|
;
|
|
; 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.
|
|
;
|
|
LD DE,$F000
|
|
LD HL,RS_IMAGE
|
|
LD BC,RS_LEN
|
|
LDIR
|
|
CALL RS_START
|
|
JP RS_IMAGE + RS_LEN
|
|
;
|
|
; CODE THAT IS COPIED TO $F000 TO PERFORM RAM SIZE DETECTION
|
|
;
|
|
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 HBX_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 HBX_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 HBX_BNKSEL
|
|
INC C
|
|
LD A,(IX) ; GET VALUE
|
|
LD (HL),A ; RESTORE IT
|
|
INC IX
|
|
DJNZ RS_LOOP2 ; ALL BANKS
|
|
RS_LOOPZ:
|
|
;
|
|
; MBC RUNTIME MEMORY SIZE ADJUSTMENT
|
|
;
|
|
; THE MBC RAM BOARD CAN CONTAIN 1 OR 2 RAM CHIPS. THEY CAN BE
|
|
; EITHER 128K OR 512K EACH. SO THE MBC RAM BOARD CAN HAVE A
|
|
; TOTAL OF 128K, 256K, 512K, OR 1024K. THE COMMON (HIMEM) RAM
|
|
; IS ALWAYS MAPPED TO THE LAST 32K OF THE FIRST CHIP ON THE BOARD.
|
|
; IF THERE ARE TWO CHIPS ON THE BOARD, THIS MEANS THE COMMON
|
|
; BANK WILL APPEAR IN THE "MIDDLE" OF THE PHYSICAL RAM BANKS.
|
|
; ROMWBW NEEDS THE COMMON BANK TO BE AT THE LAST BANK OF PHYSICAL
|
|
; RAM IN ORDER TO HAVE SEQUENTIAL RAM BANKS AVAILABLE FOR THE
|
|
; RAM DISK. TO WORK AROUND THIS, WE FLIP THE HIGH BIT OF THE
|
|
; BANK ID FOR AN MBC SYSTEM IFF IT HAS 2 CHIPS (256K OR 1024K).
|
|
; THE CODE BELOW GENERATES THE CORRECT MASK TO ACCOMPLISH THIS
|
|
; AND THEN POKES THE MASK INTO AN XOR INSTRUCTION IN THE MBC
|
|
; MEMORY MANAGER.
|
|
;
|
|
#IF (MEMMGR == MM_MBC)
|
|
;
|
|
;LD HL,CB_RAMBANKS ; IN NUMBER OF RAMBANKS DETECTED FOR MBC
|
|
LD A,%11101011 ; IS 4 (128KB) OR 16 (512KB) THEN
|
|
;AND (HL) ; ZERO THE LAST BANK MASK OTHERWISE
|
|
AND E ; ZERO THE LAST BANK MASK OTHERWISE
|
|
JR Z,MBC_SINGLE ; CALCULATE THE LAST BANK MASK (BANKS/2)
|
|
RRA ; 256K = %00000100, 1024K = %00010000
|
|
MBC_SINGLE:
|
|
LD (HBX_MBCMSK),A
|
|
;
|
|
#ENDIF
|
|
;
|
|
; RETURN TO ORIGINAL BANK
|
|
POP AF
|
|
CALL HBX_BNKSEL
|
|
LD A,E ; RETURN BANK COUNT
|
|
LD ($FFEA),A ; STASH HERE FOR A BIT
|
|
RET
|
|
;
|
|
RS_ARY .EQU $
|
|
;
|
|
RS_LEN .EQU $ - RS_START
|
|
.ORG RS_IMAGE + RS_LEN
|
|
;
|
|
#ELSE
|
|
;
|
|
; MBC RUNTIME MEMORY SIZE ADJUSTMENT
|
|
;
|
|
; THE MBC RAM BOARD CAN CONTAIN 1 OR 2 RAM CHIPS. THEY CAN BE
|
|
; EITHER 128K OR 512K EACH. SO THE MBC RAM BOARD CAN HAVE A
|
|
; TOTAL OF 128K, 256K, 512K, OR 1024K. THE COMMON (HIMEM) RAM
|
|
; IS ALWAYS MAPPED TO THE LAST 32K OF THE FIRST CHIP ON THE BOARD.
|
|
; IF THERE ARE TWO CHIPS ON THE BOARD, THIS MEANS THE COMMON
|
|
; BANK WILL APPEAR IN THE "MIDDLE" OF THE PHYSICAL RAM BANKS.
|
|
; ROMWBW NEEDS THE COMMON BANK TO BE AT THE LAST BANK OF PHYSICAL
|
|
; RAM IN ORDER TO HAVE SEQUENTIAL RAM BANKS AVAILABLE FOR THE
|
|
; RAM DISK. TO WORK AROUND THIS, WE FLIP THE HIGH BIT OF THE
|
|
; BANK ID FOR AN MBC SYSTEM IFF IT HAS 2 CHIPS (256K OR 1024K).
|
|
; THE CODE BELOW GENERATES THE CORRECT MASK TO ACCOMPLISH THIS
|
|
; AND THEN POKES THE MASK INTO AN XOR INSTRUCTION IN THE MBC
|
|
; MEMORY MANAGER.
|
|
;
|
|
#IF (MEMMGR == MM_MBC)
|
|
LD HL,CB_RAMBANKS ; IF NUMBER OF RAMBANKS DETECTED FOR MBC
|
|
LD A,%11101011 ; IS 4 (128KB) OR 16 (512KB) THEN
|
|
AND (HL) ; ZERO THE LAST BANK MASK OTHERWISE
|
|
JR Z,MBC_SINGLE ; CALCULATE THE LAST BANK MASK (BANKS/2)
|
|
RRA ; 256K = %00000100, 1024K = %00010000
|
|
MBC_SINGLE:
|
|
LD (HBX_MBCMSK),A
|
|
#ENDIF
|
|
;
|
|
#ENDIF
|
|
;
|
|
; IF THIS IS A ROM-LESS SYSTEM, THEN WE NEED TO COPY THE PAYLOAD
|
|
; (LOADER, MONITOR, ZSDOS) THAT HAS BEEN LOADED TO PHYSICAL RAM
|
|
; BANKS 0 AND 1 TO THE USER TPA BANK TO RUN AFTER BOOT.
|
|
; IT IS DONE PRIOR TO COPYING HBIOS TO IT'S FINAL BANK BECAUSE
|
|
; THE PAYLOAD MAY EXTEND INTO THE HBIOS OPERATING BANK. THIS
|
|
; HAPPENS PRIMARILY IN THE CASE WHERE THE
|
|
; SYSTEM HAS THE MINIMUM 128KB OF RAM.
|
|
;
|
|
#IFDEF ROMBOOT
|
|
#IF (ROMSIZE == 0)
|
|
;
|
|
; THE PAYLOAD IS LIKELY TO CROSS OVER THE RAM BANK 0/1
|
|
; BOUNDARY. BNKCPY DOES NOT HANDLE THIS BECAUSE IT ASSUMES
|
|
; THE COMMON BANK IS USED AFTER PASSING OVER THE BANK
|
|
; BOUNDARY. WE WORK AROUND THAT HERE BY DOING TWO COPIES.
|
|
; THE FIRST ONE HANDLES THE PORTION OF THE PAYLOAD FROM THE
|
|
; END OF HBIOS TO THE BANK BOUNDARY ($8000). THE SECOND
|
|
; ONE HANDLES THE PORTION THAT EXTENDS INTO THE SECOND
|
|
; PHYSICAL RAM BANK.
|
|
;
|
|
; COPY PORTION OF PAYLOAD FOLLOWING HBIOS TO THE BANK
|
|
; BOUNDARY AT $8000 INTO START OF TPA.
|
|
LD A,BID_RAM0
|
|
LD (HB_SRCBNK),A
|
|
LD A,BID_USR
|
|
LD (HB_DSTBNK),A
|
|
LD HL,HB_END
|
|
LD DE,0
|
|
LD BC,$8000-HB_END
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
CALL Z280_BNKCPY
|
|
#ELSE
|
|
CALL HBX_BNKCPY
|
|
#ENDIF
|
|
;
|
|
; COPY REMAINDER OF PAYLOAD EXTENDING INTO THE SECOND PHYSICAL
|
|
; RAM BANK. NOTE THAT THE DESTINATION ADDRESS (DE) IS
|
|
; ALREADY CORRECT FROM THE PRIOR COPY.
|
|
LD A,BID_RAM0+1
|
|
LD (HB_SRCBNK),A
|
|
LD HL,$0000
|
|
; DE IS ALREADY CORRECT
|
|
LD BC,$8000-($8000-HB_END)
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
CALL Z280_BNKCPY
|
|
#ELSE
|
|
CALL HBX_BNKCPY
|
|
#ENDIF
|
|
;
|
|
#ENDIF
|
|
;
|
|
#ENDIF
|
|
;
|
|
; IF ALREADY EXECUTING IN RAM, BYPASS RAM BANK INSTALLATION
|
|
;
|
|
LD A,(HB_RAMFLAG)
|
|
OR A
|
|
JR NZ,HB_START1
|
|
;
|
|
; INSTALL HBIOS IN RAM BANK
|
|
;
|
|
LD A,(HB_CURBNK)
|
|
LD (HB_SRCBNK),A
|
|
LD A,BID_BIOS
|
|
LD (HB_DSTBNK),A
|
|
LD HL,0
|
|
LD DE,0
|
|
LD BC,$8000
|
|
#IF (MEMMGR == MM_Z280)
|
|
CALL Z280_BNKCPY
|
|
#ELSE
|
|
CALL HBX_BNKCPY
|
|
#ENDIF
|
|
;
|
|
; TRANSITION TO HBIOS IN RAM BANK
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
LD A,BID_BIOS
|
|
LD B,$10 ; FIRST SYSTEM PDR
|
|
CALL Z280_BNKSEL
|
|
JR HB_START1
|
|
#ELSE
|
|
LD A,BID_BIOS ; BIOS BANK ID
|
|
LD IX,HB_START1 ; EXECUTION RESUMES HERE
|
|
CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN
|
|
HALT ; WE SHOULD NOT COME BACK HERE!
|
|
#ENDIF
|
|
;
|
|
HB_RAMFLAG .DB FALSE ; INITIALLY FALSE, SET TO TRUE BELOW AFTER RAM TRANSITION
|
|
;
|
|
; 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!
|
|
DIAG(DIAG_03)
|
|
LED(%00000010)
|
|
;
|
|
; SET THE IN-RAM FLAG
|
|
LD A,TRUE ; ACCUM := TRUE
|
|
LD (HB_RAMFLAG),A ; SET RAMFLAG
|
|
;
|
|
; RECOVER DATA PASSED PRIOR TO RAM TRANSITION
|
|
; (HBX_LOC - 1) = BATCOND, (HBX_LOC - 2) = APPBNK
|
|
POP HL ; POP 2 BYTES
|
|
LD A,H ; GET FIRST BYTE PUSHED
|
|
LD (HB_BATCOND),A ; ... AND SAVE AS BAT COND
|
|
;
|
|
#IFDEF APPBOOT
|
|
LD A,L ; GET SECOND BYTE PUSHED
|
|
LD (HB_APPBNK),A ; ... AND SAVE AS APPBNK
|
|
#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 + ((((BID_BIOS & $7F) * 8) + (1 << (RAMLOC - 12))) << 4) + (Z280_IVT >> 8)
|
|
LDCTL (C),HL
|
|
#ENDIF
|
|
;
|
|
; IF APPBOOT, WE NEED TO FIX UP A FEW THINGS IN PAGE ZERO
|
|
;
|
|
#IFDEF APPBOOT
|
|
;
|
|
; 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)
|
|
; JP INT_IM1 IF INTERRUPT MODE ACTIVE
|
|
LD A,$C3
|
|
LD ($0038),A
|
|
LD HL,INT_IM1
|
|
LD ($0039),HL
|
|
#ELSE
|
|
; RETI ($ED, $4D) IF NON-INTERRUPT MODE
|
|
LD HL,$0038
|
|
LD (HL),$ED
|
|
INC HL
|
|
LD (HL),$4D
|
|
#ENDIF
|
|
#ENDIF
|
|
;
|
|
#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
|
|
;
|
|
;==================================================================================================
|
|
; RECOVERY MODE
|
|
;==================================================================================================
|
|
;
|
|
; PLATFORM SPECIFIC CODE FOR DETECTING RECOVERY MODE SWITCH
|
|
;
|
|
#IF (BT_REC_TYPE != BT_REC_NONE)
|
|
#IF (BT_REC_TYPE == BT_REC_FORCE)
|
|
LD A,1 ; SET FOR RECOVERY MODE
|
|
LD (HB_BOOT_REC),A ; SAVE FOR LATER
|
|
#ENDIF
|
|
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC))
|
|
#IF (BT_REC_TYPE == BT_REC_SBC01)
|
|
LD A,%00100000 ; DISABLE RTC AND
|
|
OUT (RTCIO),A ; DRQ DRIVER READ
|
|
IN A,(RTCIO) ; BIT 0 (DRQ).
|
|
CPL ; PULLED HIGH
|
|
AND 1 ; IS RECOVERY MODE
|
|
LD (HB_BOOT_REC),A ; SAVE FOR LATER
|
|
#ENDIF
|
|
#IF (BT_REC_TYPE == BT_REC_SBC1B)
|
|
IN A,(RTCIO) ; RTC PORT, BIT 6 HAS THE
|
|
BIT 6,A ; STATE OF CONFIG JUMPER
|
|
LD A,1 ; JUMPER INSTALLED
|
|
JR Z,SAVE_REC_M ; IS RECOVERY MODE
|
|
LD A,0
|
|
SAVE_REC_M:
|
|
LD (HB_BOOT_REC),A ; SAVE FOR LATER
|
|
#ENDIF
|
|
#IF (BT_REC_TYPE == BT_REC_SBCRI)
|
|
IN A,($68 + 6) ; UART_MSR MODEM
|
|
BIT 6,A ; STATUS REGISTER
|
|
LD A,0 ; BIT 6
|
|
JR Z,SAVE_REC_M ; IS RECOVERY MODE
|
|
LD A,1
|
|
SAVE_REC_M:
|
|
LD (HB_BOOT_REC),A ; SAVE FOR LATER
|
|
#ENDIF
|
|
#ENDIF
|
|
#ENDIF
|
|
;
|
|
DIAG(DIAG_04)
|
|
;
|
|
#IF (WBWDEBUG == USEMIO) ; BUFFER OUTPUT UNTIL
|
|
CALL MIO_INIT ; WE GET TO BOOT MESSAGE
|
|
#ENDIF
|
|
;
|
|
#IF FALSE
|
|
;
|
|
; TEST DEBUG ***************************************************************************************
|
|
;
|
|
PRTS("DEBUG-IVT$")
|
|
LD DE,HB_IVT
|
|
CALL DUMP_BUFFER
|
|
CALL NEWLINE
|
|
;
|
|
; TEST DEBUG ***************************************************************************************
|
|
;
|
|
#ENDIF
|
|
;
|
|
; DISCOVER CPU TYPE
|
|
;
|
|
; 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
|
|
;
|
|
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
|
|
;
|
|
#IF (DSRTCENABLE)
|
|
CALL DSRTC_PREINIT
|
|
#ENDIF
|
|
;
|
|
#IF (SKZENABLE)
|
|
;
|
|
; 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
|
|
;
|
|
DIAG(DIAG_05)
|
|
;
|
|
; INIT OSCILLATOR SPEED FROM CONFIG
|
|
;
|
|
LD HL,CPUOSC / 1000 ; OSC SPD IN KHZ
|
|
LD (HB_CPUOSC),HL ; INIT HB_CPUOSC DEFAULT
|
|
;
|
|
; ATTEMPT DYNAMIC CPU SPEED DERIVATION
|
|
; NOTE THAT FOR PLATFORMS WITH SOFTWARE SELECTABLE CPU SPEED,
|
|
; THIS IS BEING DONE WITH THE CPU SPEED SET TO THE LOWEST
|
|
; POSSIBLE SETTING. THE FINAL CPU SPEED WILL BE ADJUSTED
|
|
; LATER.
|
|
;
|
|
CALL HB_CPUSPD ; DYNAMIC CPU SPEED DETECTION
|
|
JR NZ,HB_CPU2 ; SKIP AHEAD IF FAILED
|
|
;
|
|
; RECORD THE UPDATED CPU OSCILLATOR SPEED
|
|
;
|
|
#IF ((CPUFAM == CPU_Z180) | (CPUSPDCAP == SPD_HILO))
|
|
; SPEED MEASURED WILL BE HALF OSCILLATOR SPEED
|
|
; SO RECORD DOUBLE THE MEASURED VALUE
|
|
SLA L
|
|
RL H
|
|
#ENDIF
|
|
;
|
|
LD (HB_CPUOSC),HL ; RECORD MEASURED SPEED
|
|
;
|
|
HB_CPU2:
|
|
;
|
|
; INIT CPUKHZ BASED ON OSCILLATOR SPEED
|
|
;
|
|
LD HL,(HB_CPUOSC)
|
|
;
|
|
; TRANSITION TO FINAL DESIRED CPU SPEED FOR THOSE PLATFORMS
|
|
; THAT SUPPORT SOFTWARE SELECTABLE CPU SPEED. UPDATE CB_CPUKHZ
|
|
; IN HCB AS WE DO THIS.
|
|
;
|
|
#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 ((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
|
|
;
|
|
; 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_Z180)
|
|
;
|
|
; SET FINAL DESIRED WAIT STATES
|
|
LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4)
|
|
OUT0 (Z180_DCNTL),A
|
|
;
|
|
#ENDIF
|
|
;
|
|
#IF (CPUFAM == CPU_Z280)
|
|
;
|
|
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
|
|
;
|
|
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
|
|
;
|
|
#ENDIF
|
|
;
|
|
LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT
|
|
CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY
|
|
;
|
|
#IF (INTMODE == 2)
|
|
; 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
|
|
|
|
IM 2 ; SWITCH TO INT MODE 2
|
|
#ENDIF
|
|
;
|
|
#IF (INTMODE == 3)
|
|
;
|
|
; SETUP Z280 INT A FOR VECTORED INTERRUPTS
|
|
LD HL,%0010000000000000
|
|
LD C,Z280_ISR
|
|
LDCTL (C),HL
|
|
;
|
|
IM 3
|
|
;
|
|
#ENDIF
|
|
;
|
|
#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 (CPUFAM == CPU_Z180)
|
|
;
|
|
#IF (INTMODE == 2)
|
|
;
|
|
; MASK ALL EXTERNAL INTERRUPTS FOR NOW
|
|
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 SIMPIFY TO
|
|
; RLDR = CPU CLK / 1000
|
|
; NOW IF 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
|
|
;
|
|
; 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
|
|
;
|
|
DIAG(DIAG_06)
|
|
;
|
|
#IF FALSE
|
|
;
|
|
; TEST DEBUG ***************************************************************************************
|
|
;
|
|
CALL NEWLINE
|
|
CALL REGDMP
|
|
;
|
|
; TEST DEBUG ***************************************************************************************
|
|
;
|
|
#ENDIF
|
|
;
|
|
; PRE-CONSOLE INITIALIZATION
|
|
;
|
|
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
|
|
CALL CALLLIST ; PROCESS THE PRE-INIT CALL TABLE
|
|
;
|
|
#IF (DSKYENABLE)
|
|
LD HL,MSG_HBVER + 5
|
|
LD A,(DSKY_HEXMAP + RMJ)
|
|
OR $80
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(DSKY_HEXMAP + RMN)
|
|
OR $80
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(DSKY_HEXMAP + RUP)
|
|
LD (HL),A
|
|
LD HL,MSG_HBVER
|
|
CALL DSKY_SHOW
|
|
#ENDIF
|
|
;
|
|
#IF FALSE
|
|
;
|
|
; TEST DEBUG ***************************************************************************************
|
|
;
|
|
CALL NEWLINE
|
|
CALL REGDMP
|
|
;
|
|
; TEST DEBUG ***************************************************************************************
|
|
;
|
|
#ENDIF
|
|
;
|
|
DIAG(DIAG_07)
|
|
LED(%00000111)
|
|
;
|
|
;
|
|
;
|
|
;
|
|
#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
|
|
;
|
|
; 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:
|
|
;
|
|
; MOST SERIAL PORTS ARE CONFIGURED WITH HARDWARE FLOW CONTROL ENABLED.
|
|
; IF THERE IS A PROBLEM WITH THE RTS 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 RTS 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
|
|
|
|
#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+IVT$")
|
|
LD DE,HB_IVT
|
|
CALL DUMP_BUFFER
|
|
;
|
|
; TEST DEBUG ***************************************************************************************
|
|
;
|
|
#ENDIF
|
|
;
|
|
; ANNOUNCE HBIOS
|
|
;
|
|
CALL NEWLINE2
|
|
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:
|
|
;
|
|
DIAG(DIAG_08)
|
|
;
|
|
; 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
|
|
;
|
|
#IF FALSE
|
|
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
|
|
;
|
|
HB_EI ; INTERRUPTS SHOULD BE OK NOW
|
|
;
|
|
; DISPLAY PLATFORM INFORMATION
|
|
;
|
|
CALL NEWLINE2
|
|
PRTX(STR_PLATFORM)
|
|
;
|
|
LD A,(HB_CPUTYPE) ; GET CPU TYPE
|
|
LD DE,HB_CPU_STR ; DISPLAY IT
|
|
CALL PRTIDXDEA
|
|
;
|
|
PRTS(" @ $")
|
|
LD HL,(CB_CPUKHZ)
|
|
CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA
|
|
PRTS("MHz$")
|
|
;
|
|
#IF (CPUFAM == CPU_Z180)
|
|
PRTS(" IO=0x$")
|
|
LD A,Z180_BASE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
#IF (CPUFAM == CPU_Z280)
|
|
CALL PRTSTRD
|
|
.TEXT ", BUS @ $"
|
|
LD C,Z280_BTIR ; BUS TIMING AND CTL REG
|
|
LDCTL HL,(C)
|
|
LD A,L ; MOVE TO A
|
|
AND %00000011 ; ISOLATE CS FIELD
|
|
LD HL,(CB_CPUKHZ) ; GET CPU SPEED
|
|
CP %00000001 ; BUS @ 1/1
|
|
JR Z,HB_Z280BUS ; GOT IT, SHOW IT
|
|
SRL H ; DIVIDE
|
|
RR L ; ... BY 2
|
|
CP %00000000 ; BUS @ 1/2
|
|
JR Z,HB_Z280BUS ; GOT IT, SHOW IT
|
|
SRL H ; DIVIDE
|
|
RR L ; ... BY 2
|
|
CP %00000010 ; BUS @ 1/4
|
|
JR Z,HB_Z280BUS ; GOT IT, SHOW IT
|
|
PRTS("???$") ; INVALID VALUE
|
|
JR HB_Z280BUS1 ; CONTINUE
|
|
HB_Z280BUS:
|
|
CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA
|
|
HB_Z280BUS1:
|
|
PRTS("MHz$") ; SUFFIX
|
|
#ENDIF
|
|
;
|
|
; DISPLAY CPU CONFIG
|
|
;
|
|
CALL NEWLINE
|
|
|
|
#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
|
|
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
|
|
#IF (INTMODE > 0)
|
|
CALL PRTSTRD
|
|
.TEXT ", INT MODE $"
|
|
LD A,INTMODE
|
|
CALL PRTDECB
|
|
#ENDIF
|
|
;
|
|
CALL PRTSTRD
|
|
.TEXT ", $"
|
|
CALL PRTSTRD
|
|
#IF (MEMMGR == MM_NONE)
|
|
.TEXT "NONE$"
|
|
#ENDIF
|
|
#IF (MEMMGR == MM_SBC)
|
|
.TEXT "SBC$"
|
|
#ENDIF
|
|
#IF (MEMMGR == MM_Z2)
|
|
.TEXT "Z2$"
|
|
#ENDIF
|
|
#IF (MEMMGR == MM_N8)
|
|
.TEXT "N8$"
|
|
#ENDIF
|
|
#IF (MEMMGR == MM_Z180)
|
|
.TEXT "Z180$"
|
|
#ENDIF
|
|
#IF (MEMMGR == MM_Z280)
|
|
.TEXT "Z280$"
|
|
#ENDIF
|
|
#IF (MEMMGR == MM_ZRC)
|
|
.TEXT "ZRC$"
|
|
#ENDIF
|
|
#IF (MEMMGR == MM_MBC)
|
|
.TEXT "MBC$"
|
|
#ENDIF
|
|
#IF (MEMMGR == MM_RPH)
|
|
.TEXT "RPH$"
|
|
#ENDIF
|
|
CALL PRTSTRD
|
|
.TEXT " MMU$"
|
|
;
|
|
; DISPLAY MEMORY CONFIG
|
|
;
|
|
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$"
|
|
;
|
|
#IFDEF TESTING
|
|
;
|
|
CALL PRTSTRD
|
|
.TEXT ", RAMBANKS=0x$"
|
|
LD A,($FFEA)
|
|
CALL PRTHEXBYTE
|
|
;
|
|
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("BTCR=$")
|
|
LD C,Z280_BTCR ; BUS TIMING AND CONTROL REGISTER
|
|
LDCTL HL,(C)
|
|
CALL PRTHEXWORDHL
|
|
CALL PC_SPACE
|
|
PRTS("BTIR=$")
|
|
LD C,Z280_BTIR ; BUS TIMING AND CONTROL REGISTER
|
|
LDCTL HL,(C)
|
|
CALL PRTHEXWORDHL
|
|
CALL PC_SPACE
|
|
PRTS("CCR=$")
|
|
LD C,Z280_CCR ; CACHE CONTROL REGISTER
|
|
LDCTL HL,(C)
|
|
CALL PRTHEXWORDHL
|
|
#ENDIF
|
|
;
|
|
#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 BATTERY DIAGNOSTIC MESSAGE
|
|
;
|
|
#IF (BATCOND)
|
|
LD A,(HB_BATCOND)
|
|
OR A
|
|
LD DE,STR_LOWBAT
|
|
CALL Z,WRITESTR
|
|
#ENDIF
|
|
;
|
|
; PERFORM 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
|
|
;
|
|
; 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
|
|
;
|
|
; 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
|
|
;
|
|
; NOW SWITCH TO CRT CONSOLE IF CONFIGURED
|
|
;
|
|
#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
|
|
;
|
|
; NOTIFY USER OF CONSOLE SWITCH ON BOOT CONSOLE
|
|
CALL NEWLINE2
|
|
PRTX(STR_SWITCH)
|
|
CALL NEWLINE
|
|
;
|
|
; SWITCH TO CRT CONSOLE
|
|
LD A,(CB_CRTDEV) ; GET CRT DISPLAY DEVICE
|
|
LD (CB_CONDEV),A ; SAVE IT AS ACTIVE CONSOLE DEVICE
|
|
;
|
|
#ENDIF
|
|
;
|
|
INITSYS3:
|
|
;
|
|
; 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
|
|
;
|
|
LD A,(HB_BOOTCONSAV) ; GET ORIGINAL BOOT CONSOLE DEV
|
|
LD C,A ; PUT IN C
|
|
LD A,(CB_CONDEV) ; GET ACTIVE CONSOLE DEVICE
|
|
CP C ; COMPARE
|
|
JR Z,INITSYS3A ; SKIP AHEAD IF NO CHANGE
|
|
;
|
|
; DISPLAY HBIOS BANNER ON NEW CONSOLE IF WE SWITCHED TO NEW
|
|
; CONSOLE DEVICE
|
|
PRTX(STR_BANNER) ; DISPLAY HBIOS BANNER
|
|
;
|
|
INITSYS3A:
|
|
CALL PRTSUM ; PRINT UNIT/DEVICE SUMMARY TABLE
|
|
;
|
|
#IF 0
|
|
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
|
|
;
|
|
#IF 0
|
|
;
|
|
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
|
|
;
|
|
INITSYS4:
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
; LEAVE SYSTEM MODE STACK POINTING TO AN OK PLACE
|
|
LD SP,HB_STACK ; NOW USE REAL SYSTEM STACK LOC
|
|
;
|
|
HB_DI ; NOT SURE THIS IS NEEDED
|
|
;
|
|
; ACTIVATE THE CORRECT USER MODE BANK
|
|
LD A,(HB_CURBNK) ; GET CURRENT BANK
|
|
CALL HBX_BNKSEL
|
|
;
|
|
; PRESET THE USER MODE STACK
|
|
LD HL,HBX_LOC
|
|
LDCTL USP,HL
|
|
;
|
|
HB_EI ; NOT SURE THIS IS NEEDED
|
|
;
|
|
; SWITCH TO USER MODE NOW
|
|
LD C,Z280_MSR
|
|
LD HL,$407F
|
|
LDCTL (C),HL
|
|
#ENDIF
|
|
;
|
|
#IFDEF TESTING
|
|
CALL SND_BEEP
|
|
#ENDIF
|
|
;
|
|
#IFNDEF ROMBOOT
|
|
;
|
|
; COPY OS IMAGE: BID_USR:<IMG START> --> BID_USR:0
|
|
LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY
|
|
LD D,BID_USR ; D = DEST BANK = USER BANK
|
|
;LD E,BID_USR ; E = SRC BANK = USER BANK
|
|
LD A,(HB_APPBNK) ; GET APP LOAD BANK
|
|
LD E,A ; USE AS SOURCE
|
|
LD HL,$8000 ; HL = COPY LEN = ENTIRE BANK
|
|
RST 08 ; DO IT
|
|
LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY
|
|
LD HL,HB_END ; COPY FROM END OF HBIOS
|
|
LD DE,0 ; TO USER ADDRESS 0
|
|
RST 08 ; DO IT
|
|
;
|
|
#ENDIF
|
|
;
|
|
; CHAIN TO LOADER
|
|
;
|
|
#IFDEF ROMBOOT
|
|
#IF (ROMSIZE > 0)
|
|
LD A,BID_IMG0 ; CHAIN TO OS IMAGES BANK
|
|
#ELSE
|
|
LD A,BID_USR ; CHAIN TO USER BANK
|
|
#ENDIF
|
|
#ELSE
|
|
LD A,BID_USR ; CHAIN TO USER BANK
|
|
#ENDIF
|
|
LD IX,0 ; ENTER AT ADDRESS 0
|
|
CALL HBX_BNKCALL ; GO THERE
|
|
HALT ; WE SHOULD NEVER COME BACK!
|
|
;
|
|
; 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
|
|
|
|
;
|
|
;==================================================================================================
|
|
; TABLE OF RECOVERY MODE INITIALIZATION ENTRY POINTS
|
|
;==================================================================================================
|
|
;
|
|
; USE "CALLDUMMY" IF NO ENTRY REQUIRED
|
|
;
|
|
#IF (BT_REC_TYPE != BT_REC_NONE)
|
|
;
|
|
HB_PCINIT_REC:
|
|
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC))
|
|
.DW UART_PREINIT
|
|
; .DW CALLDUMMY
|
|
#ENDIF
|
|
HB_PCINITRLEN .EQU (($ - HB_PCINIT_REC) / 2)
|
|
;
|
|
HB_INIT_REC:
|
|
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC))
|
|
.DW UART_INIT
|
|
.DW MD_INIT
|
|
.DW PPIDE_INIT
|
|
#ENDIF
|
|
HB_INITRLEN .EQU (($ - HB_INIT_REC) / 2)
|
|
;
|
|
#ENDIF
|
|
;
|
|
;==================================================================================================
|
|
; TABLE OF PRE-CONSOLE INITIALIZATION ENTRY POINTS
|
|
;==================================================================================================
|
|
;
|
|
HB_PCINITTBL:
|
|
#IF (DSKYENABLE)
|
|
.DW DSKY_PREINIT
|
|
#ENDIF
|
|
#IF (ASCIENABLE)
|
|
.DW ASCI_PREINIT
|
|
#ENDIF
|
|
#IF (Z2UENABLE)
|
|
.DW Z2U_PREINIT
|
|
#ENDIF
|
|
#IF (UARTENABLE)
|
|
.DW UART_PREINIT
|
|
#ENDIF
|
|
#IF (DUARTENABLE)
|
|
.DW DUART_PREINIT
|
|
#ENDIF
|
|
#IF (SIOENABLE)
|
|
.DW SIO_PREINIT
|
|
#ENDIF
|
|
#IF (ACIAENABLE)
|
|
.DW ACIA_PREINIT
|
|
#ENDIF
|
|
#IF (PIOENABLE)
|
|
.DW PIO_PREINIT
|
|
#ENDIF
|
|
#IF LPTENABLE)
|
|
.DW LPT_PREINIT
|
|
#ENDIF
|
|
#IF (PIO_4P | PIO_ZP)
|
|
.DW PIO_PREINIT
|
|
#ENDIF
|
|
#IF (UFENABLE)
|
|
.DW UF_PREINIT
|
|
#ENDIF
|
|
#IF (TMSENABLE)
|
|
.DW TMS_PREINIT
|
|
#ENDIF
|
|
HB_PCINITTBLLEN .EQU (($ - HB_PCINITTBL) / 2)
|
|
|
|
;==================================================================================================
|
|
; TABLE OF INITIALIZATION ENTRY POINTS
|
|
;==================================================================================================
|
|
;
|
|
HB_INITTBL:
|
|
#IF (KIOENABLE)
|
|
.DW KIO_INIT
|
|
#ENDIF
|
|
#IF (CTCENABLE)
|
|
.DW CTC_INIT
|
|
#ENDIF
|
|
#IF (DSKYENABLE)
|
|
.DW DSKY_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 (UARTENABLE)
|
|
.DW UART_INIT
|
|
#ENDIF
|
|
#IF (DUARTENABLE)
|
|
.DW DUART_INIT
|
|
#ENDIF
|
|
#IF (SIOENABLE)
|
|
.DW SIO_INIT
|
|
#ENDIF
|
|
#IF (ACIAENABLE)
|
|
.DW ACIA_INIT
|
|
#ENDIF
|
|
#IF (PIOENABLE)
|
|
.DW PIO_INIT
|
|
#ENDIF
|
|
#IF (LPTENABLE)
|
|
.DW LPT_INIT
|
|
#ENDIF
|
|
#IF (PIO_4P | PIO_ZP)
|
|
.DW PIO_INIT
|
|
#ENDIF
|
|
#IF (UFENABLE)
|
|
.DW UF_INIT
|
|
#ENDIF
|
|
#IF (DSRTCENABLE)
|
|
.DW DSRTC_INIT
|
|
#ENDIF
|
|
#IF (DS1501RTCENABLE)
|
|
.DW DS1501RTC_INIT
|
|
#ENDIF
|
|
#IF (BQRTCENABLE)
|
|
.DW BQRTC_INIT
|
|
#ENDIF
|
|
#IF (SIMRTCENABLE)
|
|
.DW SIMRTC_INIT
|
|
#ENDIF
|
|
#IF (INTRTCENABLE)
|
|
.DW INTRTC_INIT
|
|
#ENDIF
|
|
#IF (DS7RTCENABLE)
|
|
.DW PCF8584_INIT
|
|
.DW DS7RTC_INIT
|
|
#ENDIF
|
|
#IF (RP5RTCENABLE)
|
|
.DW RP5RTC_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 (DSKYENABLE)
|
|
; .DW DSKY_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 (PRPENABLE)
|
|
.DW PRP_INIT
|
|
#ENDIF
|
|
#IF (PPPENABLE)
|
|
.DW PPP_INIT
|
|
#ENDIF
|
|
;
|
|
HB_INITTBLLEN .EQU (($ - HB_INITTBL) / 2)
|
|
;
|
|
;==================================================================================================
|
|
; IDLE
|
|
;==================================================================================================
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
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
|
|
;
|
|
;==================================================================================================
|
|
; BIOS FUNCTION DISPATCHER
|
|
;==================================================================================================
|
|
;
|
|
; MAIN BIOS FUNCTION
|
|
; B: FUNCTION
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
HB_DISPATCH:
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
; FOR Z280 MEMMGR, WE DISPATCH VIA THE Z280 SYSCALL.
|
|
; THE SYSCALL MECHANISM WILL CLEAR INTERRUPTS. IN
|
|
; GENERAL, INTERRUPTS ARE OK DURING API PROCESSING,
|
|
; SO ENABLE THEM HERE.
|
|
HB_EI
|
|
#ENDIF
|
|
;
|
|
;
|
|
#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_EMU + $10 ; $30-$3F: EMULATION
|
|
JR C,HB_DISPERR
|
|
CP BF_VDA + $10 ; $40-$4F: VIDEO DISPLAY ADAPTER
|
|
JP C,VDA_DISPATCH
|
|
CP BF_SND + $08 ; $50-$58: SOUND DRIVERS
|
|
JP C,SND_DISPATCH
|
|
CP BF_SYS ; SKIP TO BF_SYS VALUE AT $F0
|
|
JR C,HB_DISPERR ; ERROR IF LESS THAN BF_SYS
|
|
JP SYS_DISPATCH ; OTHERWISE SYS CALL
|
|
; FALL THRU
|
|
;
|
|
HB_DISPERR:
|
|
SYSCHKERR(ERR_NOFUNC)
|
|
RET
|
|
;
|
|
;==================================================================================================
|
|
; CHARACTER I/O DEVICE FUNCTION DISPATCHER
|
|
;==================================================================================================
|
|
;
|
|
; ROUTE CALL TO SPECIFIED CHARACTER I/O DRIVER
|
|
; B: FUNCTION
|
|
; C: UNIT NUMBER
|
|
;
|
|
CIO_DISPATCH:
|
|
BIT 7,C ; CHECK FOR SPECIAL UNIT CODE
|
|
CALL NZ,CIO_SPECIAL ; IF SO, HANDLE IT
|
|
|
|
PUSH IY ; SAVE INCOMING IY
|
|
|
|
LD IY,CIO_TBL ; POINT IY TO START OF CIO TABLE
|
|
CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE
|
|
|
|
POP IY ; RESTORE IY
|
|
RET ; AND DONE
|
|
;
|
|
; SPECIAL HANDLING FOR DEDICATED UNIT CODES
|
|
;
|
|
CIO_SPECIAL:
|
|
; FOR NOW, ONLY SPECIAL CODE IS A CONSOLE REQUEST
|
|
; SO JUST SWAP IN ACTIVE CONSOLE UNIT
|
|
LD A,(CB_CONDEV) ; GET ACTIVE CONSOLE
|
|
LD C,A ; OVERLAY UNIT CODE IN C
|
|
RET ; AND REJOIN MAIN DISPATCH FLOW
|
|
;
|
|
; ADD AN ENTRY TO THE CIO UNIT TABLE (SEE HB_ADDENT FOR DETAILS)
|
|
;
|
|
CIO_ADDENT:
|
|
LD HL,CIO_TBL ; POINT TO CIO TABLE
|
|
JP HB_ADDENT ; ... AND GO TO COMMON CODE
|
|
;
|
|
; HBIOS CHARACTER DEVICE UNIT TABLE
|
|
;
|
|
; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION.
|
|
; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT
|
|
; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES.
|
|
; TABLE - 3 CONTAINS THE NUMBER OF CIO FUNCTION IDS
|
|
; EACH ENTRY IS DEFINED AS:
|
|
;
|
|
; WORD DRIVER FUNCTION TABLE ADDRESS
|
|
; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS)
|
|
;
|
|
CIO_FNCNT .EQU 7 ; NUMBER OF CIO FUNCS (FOR RANGE CHECK)
|
|
CIO_MAX .EQU 32 ; UP TO 32 UNITS
|
|
CIO_SIZ .EQU CIO_MAX * 4 ; EACH ENTRY IS 4 BYTES
|
|
;
|
|
.DB CIO_FNCNT ; CIO FUNCTION COUNT (FOR RANGE CHECK)
|
|
.DB CIO_MAX ; MAX ENTRY COUNT TABLE PREFIX
|
|
CIO_CNT .DB 0 ; ENTRY COUNT PREFIX
|
|
CIO_TBL .FILL CIO_SIZ,0 ; SPACE FOR ENTRIES
|
|
;
|
|
;==================================================================================================
|
|
; 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
|
|
;==================================================================================================
|
|
;
|
|
; 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 (DIAGENABLE)
|
|
; SAVE DISK UNIT NUMBER BIT MASK
|
|
LD A,C ; GET DISK UNIT NUMBER
|
|
LD B,A ; PUT IN B FOR LOOP COUNTER
|
|
INC B ; LOOP ONE EXTRA TIME TO HANDLE UNIT=0
|
|
XOR A ; START WITH ACCUM ZERO
|
|
SCF ; ... AND CF SET
|
|
HB_DSKREAD0:
|
|
RLA ; ROTATE BIT
|
|
DJNZ HB_DSKREAD0 ; ... UNTIL IN PROPER LOCATION
|
|
LD (HB_DSKBIT),A ; SAVE IT FOR DIAGNOSTICS
|
|
#ENDIF
|
|
;
|
|
#IF 1
|
|
; 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 1
|
|
; RAM BANK RANGE CHECK
|
|
LD A,D ; GET TGT BANK
|
|
CP BID_RAMN ; BANK IN RANGE 0-N?
|
|
CALL NC,PANIC ; IF >N, PANIC
|
|
#ENDIF
|
|
;
|
|
; SAVE TGT BUF BNK/ADR
|
|
LD (HB_IOBUF),HL
|
|
LD A,D
|
|
LD (HB_IOBNK),A
|
|
;
|
|
; SETUP READ AND LOOP COUNT
|
|
LD B,E ; SEC LOOP COUNTER
|
|
LD C,0 ; SEC COMPLETE COUNTER
|
|
;
|
|
HB_DSKREAD1:
|
|
LD HL,HB_WRKBUF ; USE WORK BUF REAL I/O
|
|
;
|
|
; CALL READ FN
|
|
CALL HB_DSKFN ; READ ONE SECTOR
|
|
;
|
|
; IF FAIL, RETURN ERR
|
|
JR NZ,HB_DSKREADX ; BAIL OUT ON ERROR
|
|
;
|
|
; BNKCPY SEC DATA TO REAL BANK/BUF & INC BUF ADR
|
|
PUSH BC ; SAVE COUNTERS
|
|
LD A,(HB_IOBNK) ; DEST BANK
|
|
LD (HB_DSTBNK),A ; ... TO PROXY
|
|
LD A,BID_BIOS ; SRC BANK
|
|
LD (HB_SRCBNK),A ; ... TO PROXY
|
|
LD BC,512 ; COPY 512 BYTES (1 SEC)
|
|
LD DE,(HB_IOBUF) ; TGT BUFFER ADR
|
|
LD HL,HB_WRKBUF ; SOURCE BUFFER
|
|
CALL HBX_BNKCPY ; DO BANK COPY
|
|
LD (HB_IOBUF),DE ; SAVE UPDATED TGT BUF ADR
|
|
POP BC ; RESTORE COUNTERS
|
|
;
|
|
; INC READ COUNT
|
|
INC C ; BUMP SEC READ COUNT
|
|
DJNZ HB_DSKREAD1 ; LOOP AS NEEDED
|
|
XOR A ; SIGNAL SUCCESS
|
|
;
|
|
HB_DSKREADX:
|
|
LD HL,(HB_IOBUF) ; NEXT BUF ADR
|
|
JR HB_DSKIOX ; DONE
|
|
;
|
|
;==================================================================================================
|
|
; DISK WRITE HELPER
|
|
;==================================================================================================
|
|
;
|
|
; IMPLEMENTS MULTI SECTOR WRITES AND I/O TO/FROM
|
|
; BANKED RAM VIA BOUNCE BUFFER
|
|
;
|
|
; TOS=WRITE FN ADR
|
|
; HL=BUF ADR
|
|
; E=SEC COUNT
|
|
; D=BUF BANK ID
|
|
;
|
|
HB_DSKWRITE:
|
|
;
|
|
; THE ACTUAL SECTOR READ FUNCTION ADDRESS IS ON TOS, SAVE IT
|
|
EX (SP),HL ; SAVE HL TO TOS, HL := READ FN ADR
|
|
LD (HB_DSKFNADR),HL ; IMBED IN CALL OP BELOW
|
|
POP HL ; RECOVER HL
|
|
;
|
|
LD (HB_DSKCMD),BC ; SAVE HBIOS FUNC & UNIT
|
|
;
|
|
#IF (DIAGENABLE)
|
|
; 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 1
|
|
; 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 1
|
|
; RAM BANK RANGE CHECK
|
|
LD A,D ; GET TGT BANK
|
|
CP BID_RAMN ; BANK IN RANGE 0-N?
|
|
CALL NC,PANIC ; IF >N, PANIC
|
|
#ENDIF
|
|
;
|
|
; SAVE TGT BUF BNK/ADR
|
|
LD (HB_IOBUF),HL
|
|
LD A,D
|
|
LD (HB_IOBNK),A
|
|
;
|
|
; SETUP WRITE AND LOOP COUNT
|
|
LD B,E ; SEC LOOP COUNTER
|
|
LD C,0 ; SEC COMPLETE COUNTER
|
|
;
|
|
HB_DSKWRITE1:
|
|
; BNKCPY SEC DATA TO WORK BANK/BUF & INC BUF ADR
|
|
PUSH BC ; SAVE COUNTERS
|
|
LD A,BID_BIOS ; DEST BANK
|
|
LD (HB_DSTBNK),A ; ... TO PROXY
|
|
LD A,(HB_IOBNK) ; SRC BANK
|
|
LD (HB_SRCBNK),A ; ... TO PROXY
|
|
LD BC,512 ; COPY 512 BYTES (1 SEC)
|
|
LD DE,HB_WRKBUF ; TGT BUFFER ADR
|
|
LD HL,(HB_IOBUF) ; SOURCE BUFFER
|
|
CALL HBX_BNKCPY ; DO BANK COPY
|
|
LD (HB_IOBUF),HL ; SAVE UPDATED SRC BUF ADR
|
|
POP BC ; RESTORE COUNTERS
|
|
;
|
|
; CALL WRITE FN
|
|
LD HL,HB_WRKBUF ; WRITE FROM WORK BUFFER
|
|
CALL HB_DSKFN ; WRITE ONE SECTOR
|
|
;
|
|
; IF FAIL, RETURN ERR
|
|
JR NZ,HB_DSKWRITEX ; BAIL OUT ON ERROR
|
|
;
|
|
; INC WRITE COUNT
|
|
INC C ; BUMP SEC WRITE COUNT
|
|
DJNZ HB_DSKWRITE1 ; LOOP AS NEEDED
|
|
XOR A ; SIGNAL SUCCESS
|
|
;
|
|
HB_DSKWRITEX:
|
|
LD HL,(HB_IOBUF) ; NEXT BUF ADR
|
|
JR HB_DSKIOX ; DONE
|
|
;
|
|
;==================================================================================================
|
|
; NON-BANKED DISK READ/WRITE
|
|
;==================================================================================================
|
|
;
|
|
HB_DSKIO:
|
|
;
|
|
; SETUP LOOP COUNT
|
|
LD B,E ; SEC LOOP COUNTER
|
|
LD C,0 ; SEC COMPLETE COUNTER
|
|
;
|
|
HB_DSKIO1:
|
|
; CALL READ/WRITE FN
|
|
CALL HB_DSKFN ; READ/WRITE ONE SECTOR
|
|
;
|
|
; IF FAIL, RETURN ERR
|
|
JR NZ,HB_DSKIOX ; BAIL OUT ON ERROR
|
|
;
|
|
; INC SECTOR COUNT
|
|
INC C ; BUMP SEC READ/WRITE COUNT
|
|
DJNZ HB_DSKIO1 ; LOOP AS NEEDED
|
|
XOR A ; SIGNAL SUCCESS
|
|
;
|
|
HB_DSKIOX:
|
|
LD E,C ; WRITE COUNT TO E
|
|
OR A ; SET RESULT FLAGS
|
|
RET ; DONE
|
|
;
|
|
HB_DSKFN:
|
|
PUSH BC ; SAVE COUNTERS
|
|
#IF (DIAGENABLE & DIAGDISKIO)
|
|
LD A,(HB_DSKBIT) ; LOAD UNIT DISK BIT MASK
|
|
OUT (DIAGPORT),A ; DISPLAY ON DIAG LEDS
|
|
#ENDIF
|
|
#IF (LEDENABLE & LEDDISKIO)
|
|
LED(%00000101) ; 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 (DIAGENABLE & DIAGDISKIO)
|
|
DIAG(DIAG_00) ; CLEAR DIAG LEDS
|
|
#ENDIF
|
|
#IF (LEDENABLE & LEDDISKIO)
|
|
LED($00)
|
|
#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
|
|
;
|
|
#IF (DSKYENABLE)
|
|
;
|
|
;==================================================================================================
|
|
; 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
|
|
;
|
|
HB_DSKACT:
|
|
PUSH AF
|
|
PUSH BC
|
|
PUSH DE
|
|
PUSH HL
|
|
LD DE,DSKY_HEXBUF+3 ; START AT END
|
|
LD B,3 ; 3 BYTES OF SECTOR ADDRESS
|
|
HB_DSKACT1:
|
|
LD A,(HL) ; GET FIRST BYTE
|
|
LD (DE),A ; AND STORE IN BUF
|
|
INC HL ; NEXT SRC BYTE
|
|
DEC DE ; NEXT DEST BYTE
|
|
DJNZ HB_DSKACT1 ; LOOP
|
|
LD A,(HB_DSKUNIT) ; GET DISK UNIT NUM
|
|
LD (DE),A ; PUT AT HEAD OF BUF
|
|
HB_DSKACT2:
|
|
LD HL,DSKY_HEXBUF ; BINARY BUF
|
|
LD DE,DSKY_BUF ; DISPLAY BUF
|
|
CALL DSKY_BIN2SEG ; CONVERT TO SEG DISPLAY BUF
|
|
LD A,(DSKY_BUF+1) ; SECOND SEGMENT
|
|
OR %10000000 ; TURN ON DOT
|
|
LD (DSKY_BUF+1),A ; SAVE IT
|
|
LD A,(HB_DSKFUNC) ; GET CURRENT I/O FUNCTION
|
|
CP BF_DIOWRITE ; IS IT A WRITE?
|
|
JR NZ,HB_DSKACT3 ; IF NOT, NO DOT, SKIP AHEAD
|
|
LD A,(DSKY_BUF+7) ; LAST SEGMENT
|
|
OR %10000000 ; TURN ON DOT
|
|
LD (DSKY_BUF+7),A ; SAVE IT
|
|
HB_DSKACT3:
|
|
EX DE,HL ; SEG DISPLAY BUF TO HL
|
|
CALL DSKY_SHOW ; DISPLAY ON DSKY
|
|
POP HL
|
|
POP DE
|
|
POP BC
|
|
POP AF
|
|
RET
|
|
;
|
|
; 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
|
|
LD DE,DSKY_HEXBUF ; START OF HEX BUF
|
|
LD A,(HB_DSKUNIT) ; GET DISK UNIT NUM
|
|
LD (DE),A ; PUT AT HEAD OF BUF
|
|
INC DE ; NEXT BYTE OF BUF
|
|
LD A,(HL) ; LSB OF TRACK
|
|
LD (DE),A ; ADD TO BUF
|
|
INC DE ; NEXT BYTE OF BUF
|
|
INC HL ; BUMP TO HEAD
|
|
INC HL ; "
|
|
INC HL ; "
|
|
LD A,(HL) ; GET HEAD
|
|
LD (DE),A ; ADD TO BUF
|
|
INC DE ; NEXT BYTE OF BUF
|
|
DEC HL ; BACK TO SECTOR
|
|
LD A,(HL) ; GET SECTOR
|
|
LD (DE),A ; ADD TO BUF
|
|
JR HB_DSKACT2
|
|
;
|
|
#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 (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
|
|
;
|
|
;==================================================================================================
|
|
; 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 8 ; 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 THE DEFAULT SOUND UNIT
|
|
; NEED TO CHECK FOR EXISTENCE OF SOUND UNIT
|
|
; WHICH CHANNEL SHOULD BE USED? IS THERE A GOOD DEFAULT CHANNEL?
|
|
;
|
|
SND_BEEP:
|
|
; CHECK FOR AT LEAST 1 SOUND DEVICE
|
|
LD A,(SND_CNT) ; GET SOUND UNIT COUNT
|
|
OR A ; CHECK FOR ZERO
|
|
RET Z ; BAIL OUT IF NO SOUND UNITS
|
|
|
|
; PLAY A BEEP ON SOUND DEVICE UNIT 0
|
|
LD B,$50 ; SOUND RESET FUNCTION
|
|
LD C,0 ; SOUND UNIT NUMBER
|
|
CALL SND_DISPATCH ; DO IT
|
|
LD B,$51 ; VOLUME
|
|
LD C,0 ; SOUND UNIT NUMBER
|
|
LD L,$FF ; MAX
|
|
CALL SND_DISPATCH ; DO IT
|
|
LD B,$53 ; SELECT NOTE
|
|
LD C,0 ; SOUND UNIT NUMBER
|
|
;LD HL,0 ; A0#
|
|
LD HL,244 ; B5 (CLOSE TO 1 KHZ)
|
|
CALL SND_DISPATCH ; DO IT
|
|
;LD B,$56 ; DURATION
|
|
;LD C,0 ; SOUND UNIT NUMBER
|
|
;LD HL,500 ; 1/2 SECOND
|
|
;CALL SND_DISPATCH ; DO IT
|
|
LD B,$54 ; PLAY SOUND
|
|
LD C,0 ; SOUND UNIT NUMBER
|
|
LD D,0 ; CHANNEL 0
|
|
CALL SND_DISPATCH ; DO IT
|
|
LD DE,15625 ; PLAY FOR 1/4 SECOND
|
|
CALL VDELAY ; WAIT WHILE TONE IS PLAYED
|
|
;CALL LDELAY ; LET SOUND PLAY 1/2 SECOND
|
|
LD B,$50 ; SOUND RESET FUNCTION
|
|
LD C,0 ; SOUND UNIT NUMBER
|
|
CALL SND_DISPATCH ; DO IT
|
|
RET ; DONE
|
|
;
|
|
;==================================================================================================
|
|
; 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
|
|
;
|
|
; 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
|
|
;;
|
|
; ; MAKE SURE THE PROPER RESET VECTOR IS AT ADDRESS $0000
|
|
; LD HL,$0040 ; USER RESET CODE STUB
|
|
; LD ($0001),HL ; OPERAND OF JP AT $0000
|
|
;
|
|
XOR A
|
|
RET
|
|
;
|
|
; GO BACK TO ROM BOOT LOADER
|
|
;
|
|
SYS_RESWARM:
|
|
;
|
|
#IF (ROMSIZE == 0)
|
|
JR SYS_RESCOLD
|
|
#ENDIF
|
|
;
|
|
CALL SYS_RESINT
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
JP INITSYS4
|
|
#ELSE
|
|
; PERFORM BANK CALL TO OS IMAGES BANK IN ROM
|
|
LD SP,HBX_LOC ; STACK JUST BELOW HBIOS PROXY
|
|
LD A,BID_IMG0 ; CHAIN TO OS IMAGES BANK
|
|
LD IX,0 ; ENTER AT ADDRESS 0
|
|
CALL HBX_BNKCALL ; GO THERE
|
|
HALT ; WE SHOULD NEVER COME BACK!
|
|
#ENDIF
|
|
;
|
|
; RESTART SYSTEM AS THOUGH POWER HAD JUST BEEN TURNED ON
|
|
;
|
|
SYS_RESCOLD:
|
|
;
|
|
#IF (ROMSIZE == 0)
|
|
LD DE,STR_RESTART
|
|
CALL Z,WRITESTR
|
|
DI
|
|
HALT
|
|
#ENDIF
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
JP Z280_RESTART
|
|
#ELSE
|
|
DI
|
|
LD SP,HBX_LOC ; STACK JUST BELOW HBIOS PROXY
|
|
LD A,BID_BOOT ; BOOT BANK
|
|
LD IX,0 ; ADDRESS ZERO
|
|
CALL HB_BNKCALL ; DOES NOT RETURN
|
|
#ENDIF
|
|
;
|
|
; HOOK CALLED WHEN A USERLAND RESET IS INVOKED, TYPICALLY VIA A JUMP
|
|
; TO LOGICAL CPU ADDRESS $0000
|
|
;
|
|
; CREDIT TO PHILLIP STEVENS FOR SUGGESTING AND SIGNIFICANT CONTRIBUTIONS
|
|
; TO THE Z180 INVALID OPCODE TRAP ENHANCEMENT.
|
|
;
|
|
SYS_RESUSER:
|
|
;
|
|
#IF (CPUFAM == CPU_Z180)
|
|
;
|
|
IN0 A,(Z180_ITC) ; GET ITC REGISTER
|
|
XOR $80 ; PRECLEAR TRAP BIT
|
|
RET M ; IF TRAP BIT NOT SET, DONE
|
|
;
|
|
; HANDLE INVALID OPCODE
|
|
DEC HL ; BACK UP TO OPCODE START
|
|
BIT 6,A ; CHECK UFO BIT (2 BYTE OPCODE)
|
|
JR Z,SYS_RESUSER1 ; IF NOT, ALL SET
|
|
DEC HL ; OTHERWISE, BACK UP 1 MORE BYTE
|
|
;
|
|
SYS_RESUSER1:
|
|
OUT0 (Z180_ITC),A ; SAVE IT
|
|
;
|
|
CALL PRTSTRD ; PRINT ERROR TAG
|
|
.TEXT "\r\n\r\n+++ INVALID Z180 OPCODE @$"
|
|
CALL PRTHEXWORDHL ; PRINT OPCODE ADDRESS
|
|
PRTS("H:$") ; FORMATTING
|
|
;
|
|
LD B,8 ; SHOW 8 BYTES
|
|
SYS_RESUSER2:
|
|
PUSH BC ; SAVE BC
|
|
PUSH HL ; SAVE HL
|
|
LD A,(HB_INVBNK) ; GET BYTE FROM INVOKING BANK
|
|
LD D,A ; PUT IN D
|
|
CALL SYS_PEEK ; PEEK TO GET BYTE VALUE
|
|
LD A,E ; PUT IN A
|
|
CALL PC_SPACE ; FORMATTING
|
|
CALL PRTHEXBYTE ; DISPLAY BYTE
|
|
POP HL ; RECOVER HL
|
|
POP BC ; RECOVER BC
|
|
INC HL ; NEXT BYTE
|
|
DJNZ SYS_RESUSER2 ; LOOP TIL DONE
|
|
JP NEWLINE ; FORMATTING & EXIT
|
|
;
|
|
#ENDIF
|
|
;
|
|
RET ; ELSE RETURN WITH USER RESET VECTOR IN HL
|
|
;
|
|
; GET THE CURRENT HBIOS VERSION
|
|
; ON INPUT, C=0
|
|
; RETURNS VERSION IN DE AS BCD
|
|
; D: MAJOR VERION IN TOP 4 BITS, MINOR VERSION IN LOW 4 BITS
|
|
; E: UPDATE VERION IN TOP 4 BITS, PATCH VERSION IN LOW 4 BITS
|
|
; L: PLATFORM ID
|
|
;
|
|
SYS_VER:
|
|
LD DE,0 | (RMJ << 12) | (RMN << 8) | (RUP << 4) | RTP
|
|
LD L,PLATFORM
|
|
XOR A
|
|
RET
|
|
;
|
|
; SET 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
|
|
; 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 ACTIVE MEMORY BANK
|
|
;
|
|
SYS_GETBNK:
|
|
LD A,(HB_INVBNK) ; GET THE ACTIVE MEMORY BANK
|
|
LD C,A ; MOVE TO C
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
; 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 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 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 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
|
|
; ITEM TO RETURN INDICATED IN C
|
|
;
|
|
SYS_GET:
|
|
LD A,C ; GET REQUESTED SUB-FUNCTION
|
|
CP BF_SYSGET_CIOCNT
|
|
JP Z,SYS_GETCIOCNT
|
|
CP BF_SYSGET_CIOFN
|
|
JP Z,SYS_GETCIOFN
|
|
CP BF_SYSGET_DIOCNT
|
|
JP Z,SYS_GETDIOCNT
|
|
CP BF_SYSGET_DIOFN
|
|
JP Z,SYS_GETDIOFN
|
|
CP BF_SYSGET_RTCCNT
|
|
JP Z,SYS_GETRTCCNT
|
|
CP BF_SYSGET_VDACNT
|
|
JP Z,SYS_GETVDACNT
|
|
CP BF_SYSGET_VDAFN
|
|
JP Z,SYS_GETVDAFN
|
|
CP BF_SYSGET_SNDCNT
|
|
JP Z, SYS_GETSNDCNT
|
|
CP BF_SYSGET_SNDFN
|
|
JP Z,SYS_GETSNDFN
|
|
CP BF_SYSGET_TIMER
|
|
JP Z,SYS_GETTIMER
|
|
CP BF_SYSGET_SECS
|
|
JP Z,SYS_GETSECS
|
|
CP BF_SYSGET_BOOTINFO
|
|
JP Z,SYS_GETBOOTINFO
|
|
CP BF_SYSGET_CPUINFO
|
|
JP Z,SYS_GETCPUINFO
|
|
CP BF_SYSGET_MEMINFO
|
|
JP Z,SYS_GETMEMINFO
|
|
CP BF_SYSGET_BNKINFO
|
|
JP Z,SYS_GETBNKINFO
|
|
CP BF_SYSGET_CPUSPD
|
|
JP Z,SYS_GETCPUSPD
|
|
SYSCHKERR(ERR_NOFUNC) ; SIGNAL ERROR
|
|
RET
|
|
;
|
|
; 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
|
|
;
|
|
; 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
|
|
;
|
|
; 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
|
|
;
|
|
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 (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 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 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
|
|
;
|
|
; SET SYSTEM PARAMETERS
|
|
; PARAMETER(S) TO SET INDICATED IN C
|
|
;
|
|
SYS_SET:
|
|
LD A,C ; GET REQUESTED SUB-FUNCTION
|
|
CP BF_SYSSET_TIMER
|
|
JR Z,SYS_SETTIMER
|
|
CP BF_SYSSET_SECS
|
|
JR Z,SYS_SETSECS
|
|
CP BF_SYSSET_BOOTINFO
|
|
JR Z,SYS_SETBOOTINFO
|
|
CP BF_SYSSET_CPUSPD
|
|
JR Z,SYS_SETCPUSPD
|
|
SYSCHKERR(ERR_NOFUNC) ; SIGNAL ERROR
|
|
RET
|
|
;
|
|
; SET BOOT INFORMATION
|
|
; ON ENTRY:
|
|
; L: BOOT BANK ID
|
|
; DE: BOOT DISK VOLUME (UNIT/SLICE)
|
|
;
|
|
SYS_SETBOOTINFO:
|
|
LD A,L
|
|
LD (CB_BOOTBID),A
|
|
LD (CB_BOOTVOL),DE
|
|
XOR A
|
|
RET
|
|
;
|
|
; 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
|
|
;
|
|
; 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
|
|
;
|
|
; SET SYSTEM CPU SPEED ATTRIBUTES
|
|
; ON ENTRY:
|
|
; L: CLOCK MULT (0:HALF, 1:FULL, 2: DOUBLE)
|
|
; D: MEMORY WAIT STATES
|
|
; E: I/O WAIT STATES
|
|
;
|
|
SYS_SETCPUSPD:
|
|
;
|
|
#IF (((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) & (CPUSPDCAP==SPD_HILO))
|
|
;
|
|
; NOTE: WAIT STATE SETTINGS ARE IGNORED FOR Z80
|
|
;
|
|
LD A,L ; CLK SPD TO ACCUM
|
|
CP $FF ; NO CHANGE?
|
|
JR Z,SYS_SETCPUSPD3 ; DONE IF SO
|
|
LD C,%00000000 ; HALF SPEED
|
|
CP 0
|
|
JR Z,SYS_SETCPUSPD1
|
|
LD C,%00001000 ; FULL SPEED
|
|
CP 1
|
|
JR Z,SYS_SETCPUSPD1
|
|
JR SYS_SETCPUSPD_ERR ; SPD NOT SUPPORTED
|
|
SYS_SETCPUSPD1:
|
|
LD A,(HB_RTCVAL)
|
|
AND ~%00001000 ; CLEAR SPEED BIT
|
|
OR C ; IMPLEMENT NEW SPEED BIT
|
|
#IF (PLATFORM == PLT_SBC)
|
|
; SBC SPEED BIT IS INVERTED, ADJUST IT
|
|
LD A,C
|
|
XOR %00001000
|
|
LD C,A
|
|
#ENDIF
|
|
LD (HB_RTCVAL),A ; SAVE IN SHADOW REGISTER
|
|
OUT (RTCIO),A ; UPDATE HARDWARE REGISTER
|
|
;
|
|
; UPDATE THE CURRENT CPU SPEED IN HCB!
|
|
LD A,L
|
|
LD HL,(HB_CPUOSC) ; ASSUME FULL SPEED
|
|
CP 1 ; CHECK FOR 1 (FULL SPEED)
|
|
JR Z,SYS_SETCPUSPD2 ; IF SO, ALL DONE
|
|
; ADJUST HL TO REFLECT HALF SPEED OPERATION
|
|
SRL H ; ADJUST HL ASSUMING
|
|
RR L ; HALF SPEED OPERATION
|
|
;
|
|
SYS_SETCPUSPD2:
|
|
;
|
|
; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ.
|
|
; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE.
|
|
;
|
|
LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ
|
|
LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ
|
|
CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER
|
|
LD DE,500 ; SET UP TO ROUND UP
|
|
XOR A ; IF WITHIN 500 KHZ
|
|
SBC HL,DE ; REMAINDER - 500
|
|
CCF ; COMPLEMENT CF
|
|
ADC A,C ; C -> A; ADD CF FOR ROUNDING
|
|
LD (CB_CPUMHZ),A ; SAVE IT
|
|
;
|
|
; REINIT DELAY ROUTINE
|
|
LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT
|
|
CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY
|
|
;
|
|
SYS_SETCPUSPD3:
|
|
XOR A
|
|
RET
|
|
#ENDIF
|
|
;
|
|
#IF (CPUFAM == CPU_Z180)
|
|
; VERIFY THAT REQUESTED SETTINGS ARE ALLOWED BY HARDWARE
|
|
LD A,L ; GET SPEED REQUESTED
|
|
CP $FF ; NO CHANGE?
|
|
JR Z,SYS_SETCPUSPD0A ; SKIP CHECK
|
|
LD A,(HB_CPUTYPE) ; 1=ORIG, 2=REVK, 3=REVN
|
|
INC L ; 1=HALF,2=FULL,3=DOUBLE
|
|
CP L ; TOO HIGH FOR CPU TYPE?
|
|
JP C,SYS_SETCPUSPD_ERR ; CPU CAN'T DO SPD MULT
|
|
DEC L ; RESTORE ORIG REQUEST
|
|
SYS_SETCPUSPD0A:
|
|
LD A,D ; MEM WS
|
|
CP $FF ; NO CHANGE?
|
|
JR Z,SYS_SETCPUSPD0B ; SKIP CHECK
|
|
CP 4 ; TOO HIGH?
|
|
JP NC,SYS_SETCPUSPD_ERR ; >3 IS TOO HIGH
|
|
SYS_SETCPUSPD0B:
|
|
LD A,D ; I/O WS
|
|
CP $FF ; NO CHANGE?
|
|
JR Z,SYS_SETCPUSPD0C ; SKIP CHECK
|
|
CP 4 ; TOO HIGH?
|
|
JP NC,SYS_SETCPUSPD_ERR ; >3 IS TOO HIGH
|
|
SYS_SETCPUSPD0C:
|
|
;
|
|
PUSH DE ; SAVE WAIT STATES FOR NOW
|
|
; BEFORE IMPLEMENTING THE NEW CPU SPEED, WE SWITCH THE
|
|
; WAIT STATES TO MAXIMUM BECAUSE WE MAY BE IMPLEMENTING
|
|
; SLOWER WAIT STATES REQUIRED BY THE NEW SPEED. WE SAVE
|
|
; THE ORIGINAL WAIT STATES REGISTER VALUE ON STACK
|
|
IN0 A,(Z180_DCNTL) ; GET CURRENT REGISTER VALUE
|
|
LD E,A ; PUT IN E
|
|
PUSH DE ; SAVE FOR LATER
|
|
OR %11110000 ; MAX WAIT STATES
|
|
OUT0 (Z180_DCNTL),A ; DO IT
|
|
;
|
|
LD A,L ; NEW CLK SPD TO ACCUM
|
|
CP $FF ; NO CHANGE?
|
|
JR Z,SYS_SETCPUSPD2B ; IF SO, SKIP TO WAIT STATES
|
|
;
|
|
LD B,0 ; B HAS BIT FOR CMR
|
|
LD C,0 ; C HAS BIT FOR CCR
|
|
CP 2 ; DOUBLE SPEED?
|
|
JR C,SYS_SETCPUSPD1 ; <2?, SKIP AHEAD
|
|
LD B,%10000000 ; SET CMR BIT
|
|
SYS_SETCPUSPD1:
|
|
CP 1 ; FULL SPEED?
|
|
JR C,SYS_SETCPUSPD2 ; <1?, SKIP AHEAD
|
|
LD C,%10000000 ; SET CCR BIT
|
|
SYS_SETCPUSPD2:
|
|
;
|
|
; IMPLEMENT THE NEW CPU SPEED
|
|
IN0 A,(Z180_CMR)
|
|
AND ~%10000000
|
|
OR B
|
|
OUT0 (Z180_CMR),A
|
|
IN0 A,(Z180_CCR)
|
|
AND ~%10000000
|
|
OR C
|
|
OUT0 (Z180_CCR),A
|
|
;
|
|
; UPDATE THE CURRENT CPU SPEED IN HCB!
|
|
LD A,L ; SETTING TO A
|
|
LD HL,(HB_CPUOSC) ; START WITH CPU OSC VALUE
|
|
; ADJUST HL TO REFLECT HALF SPEED OPERATION
|
|
SRL H ; ADJUST HL ASSUMING
|
|
RR L ; HALF SPEED OPERATION
|
|
OR A ; CHECK FOR HALF SPEED
|
|
JR Z,SETCPUSPD2A ; IF SO, DONE
|
|
; ADJUST HL TO REFLECT FULL SPEED OPERATION
|
|
SLA L
|
|
RL H
|
|
CP 1 ; CHECK FOR FULL SPEED
|
|
JR Z,SETCPUSPD2A ; IF SO DONE
|
|
; ADJUST HL TO REFLECT DOUBLE SPEED OPERATION
|
|
SLA L
|
|
RL H
|
|
;
|
|
SETCPUSPD2A:
|
|
;
|
|
; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ.
|
|
; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE.
|
|
;
|
|
LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ
|
|
LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ
|
|
CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER
|
|
LD DE,500 ; SET UP TO ROUND UP
|
|
XOR A ; IF WITHIN 500 KHZ
|
|
SBC HL,DE ; REMAINDER - 500
|
|
CCF ; COMPLEMENT CF
|
|
ADC A,C ; C -> A; ADD CF FOR ROUNDING
|
|
LD (CB_CPUMHZ),A ; SAVE IT
|
|
;
|
|
SYS_SETCPUSPD2B:
|
|
; NOW IMPLEMENT ANY WAIT STATE CHANGES.
|
|
POP HL ; INIT L WITH ORIG DCNTL VALUE
|
|
POP DE ; RECOVER WAIT STATES
|
|
LD A,D ; GET MEM WS
|
|
CP $FF ; SKIP?
|
|
JR Z,SYS_SETCPUSPD3 ; IF SO, GO AHEAD
|
|
AND %00000011 ; JUST TWO BITS
|
|
RRCA ; MEM WS IS TOP TWO BITS
|
|
RRCA
|
|
LD H,A ; MOVE WS BITS TO H
|
|
LD A,L ; CUR VALUE TO A
|
|
AND %00111111 ; MASK OFF MEM WS BITS
|
|
OR H ; SET NEW MEM WS BITS
|
|
LD L,A ; BACK TO L
|
|
;
|
|
SYS_SETCPUSPD3:
|
|
;
|
|
LD A,E ; GET I/O WS
|
|
CP $FF ; SKIP?
|
|
JR Z,SYS_SETCPUSPD4 ; IF SO, GO AHEAD
|
|
DEC A ; ADJUST FOR BUILT-IN I/O WS
|
|
AND %00000011 ; JUST TWO BITS
|
|
RRCA ; I/O WS IS BITS 5-4
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
LD H,A ; MOVE WS BITS TO H
|
|
LD A,L ; CUR VALUE TO A
|
|
AND %11001111 ; MASK OFF I/O WS BITS
|
|
OR H ; SET NEW I/O WS BITS
|
|
LD L,A ; BACK TO L
|
|
;
|
|
SYS_SETCPUSPD4:
|
|
LD A,L ; WORKING VALUE TO A
|
|
OUT0 (Z180_DCNTL),A ; IMPLEMENT NEW VALUE
|
|
;
|
|
; REINIT DELAY ROUTINE
|
|
LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT
|
|
CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY
|
|
;
|
|
#IF ((INTMODE == 2) & (Z180_TIMER))
|
|
; THE Z180 TIMER IS BASED ON CPU SPEED. SO HERE
|
|
; WE RECOMPUTE THE TIMER CONSTANTS BASED ON THE NEW SPEED.
|
|
XOR A ; ALL BITS ZERO
|
|
OUT0 (Z180_TCR),A ; ... INHIBITS TIMER OPERATION
|
|
LD HL,(CB_CPUKHZ) ; 50HZ = 18432000 / 20 / 50 / X, SO X = CPU KHZ
|
|
OUT0 (Z180_TMDR0L),L ; INITIALIZE TIMER 0 DATA REGISTER
|
|
OUT0 (Z180_TMDR0H),H
|
|
DEC HL ; RELOAD OCCURS *AFTER* ZERO
|
|
OUT0 (Z180_RLDR0L),L ; INITIALIZE TIMER 0 RELOAD REGISTER
|
|
OUT0 (Z180_RLDR0H),H
|
|
LD A,%00010001 ; ENABLE TIMER0 INT AND DOWN COUNTING
|
|
OUT0 (Z180_TCR),A
|
|
#ENDIF
|
|
;
|
|
#IF (ASCIENABLE)
|
|
; RESET THE ASCI PORTS IN CASE SPEED CHANGED!
|
|
; N.B., THIS WILL FAIL IF THE CURRENT BAUD RATE
|
|
; IS IMPOSSIBLE TO IMPLEMENT AT THE NEW CPU SPEED!!!
|
|
LD DE,-1
|
|
LD IY,ASCI0_CFG
|
|
CALL ASCI_INITDEV
|
|
LD DE,-1
|
|
LD IY,ASCI1_CFG
|
|
CALL ASCI_INITDEV
|
|
#ENDIF
|
|
;
|
|
XOR A
|
|
RET
|
|
#ENDIF
|
|
;
|
|
SYS_SETCPUSPD_ERR:
|
|
OR $FF ; NOT SUPPORTED
|
|
RET
|
|
;
|
|
; RETURN A BYTE OF MEMORY FROM SPECIFIED BANK
|
|
; ENTRY: D=BANK ID, HL=ADDRESS
|
|
; RETURN: E=BYTE VALUE
|
|
;
|
|
; IF WE ARE USING INTERRUPT MODE 1, WE NEED TO PREVENT INTERRUPTS
|
|
; BECAUSE THE LOW MEMORY BANK CONTAINING THE IM1 VECTOR WILL PROBABLY
|
|
; GET BANKED OUT DURING THE PEEK PROCESSING.
|
|
;
|
|
SYS_PEEK:
|
|
#IF (INTMODE == 1)
|
|
#IF (CPUFAM == CPU_Z280)
|
|
PUSH IY
|
|
LD C,Z280_MSR
|
|
LDCTL IY,(C)
|
|
PUSH IY
|
|
HB_DI
|
|
#ELSE
|
|
LD A,I ; SAVE THE INTERRUPT STATUS
|
|
DI ; COPY IFF2 TO P/V FLAG
|
|
PUSH AF
|
|
#ENDIF
|
|
#ENDIF
|
|
CALL HBX_PEEK ; IMPLEMENTED IN PROXY
|
|
#IF (INTMODE == 1)
|
|
#IF (CPUFAM == CPU_Z280)
|
|
LD C,Z280_MSR
|
|
POP IY
|
|
LDCTL (C),IY
|
|
POP IY
|
|
#ELSE
|
|
POP AF ; RECALL INITIAL INTERRUPT STATUS
|
|
JP PO,$+4 ; RETURN TO INITIAL STATE
|
|
EI ; *** DO NOT USE HB_EI HERE ***
|
|
#ENDIF
|
|
#ENDIF
|
|
XOR A
|
|
RET
|
|
;
|
|
; WRITE A BYTE OF MEMORY TO SPECIFIED BANK
|
|
; ENTRY: D=BANK ID, HL=ADDRESS IN HBIOS BANK, E=BYTE VALUE
|
|
;
|
|
; IF WE ARE USING INTERRUPT MODE 1, WE NEED TO PREVENT INTERRUPTS
|
|
; BECAUSE THE LOW MEMORY BANK CONTAINING THE IM1 VECTOR WILL PROBABLY
|
|
; GET BANKED OUT DURING THE POKE PROCESSING.
|
|
;
|
|
SYS_POKE:
|
|
#IF (INTMODE == 1)
|
|
#IF (CPUFAM == CPU_Z280)
|
|
PUSH IY
|
|
LD C,Z280_MSR
|
|
LDCTL IY,(C)
|
|
PUSH IY
|
|
HB_DI
|
|
#ELSE
|
|
LD A,I ; SAVE THE INTERRUPT STATUS
|
|
HB_DI ; COPY IFF2 TO P/V FLAG
|
|
PUSH AF
|
|
#ENDIF
|
|
#ENDIF
|
|
CALL HBX_POKE ; IMPLEMENTED IN PROXY
|
|
#IF (INTMODE == 1)
|
|
#IF (CPUFAM == CPU_Z280)
|
|
LD C,Z280_MSR
|
|
POP IY
|
|
LDCTL (C),IY
|
|
POP IY
|
|
#ELSE
|
|
POP AF ; RECALL INITIAL INTERRUPT STATUS
|
|
JP PO,$+4 ; RETURN TO INITIAL STATE
|
|
EI ; *** DO NOT USE HB_EI HERE ***
|
|
#ENDIF
|
|
#ENDIF
|
|
XOR A
|
|
RET
|
|
;
|
|
; INTERRUPT MANAGEMENT FUNCTIONS
|
|
; 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)
|
|
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)
|
|
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
|
|
LD DE,HB_IVT ; DE := START OF VECTOR TABLE
|
|
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
|
|
;
|
|
;==================================================================================================
|
|
; GLOBAL HBIOS FUNCTIONS
|
|
;==================================================================================================
|
|
;
|
|
; 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
|
|
;
|
|
#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
|
|
;
|
|
HB_IM1CNT .DB 0 ; NUMBER OF ENTRIES IN CALL LIST
|
|
HB_IM1MAX .DB 8 ; MAX ENTRIES IN CALL LIST
|
|
HB_IM1PTR .DW HB_IVT ; POINTER FOR NEXT IM1 ENTRY
|
|
;
|
|
#ENDIF
|
|
;
|
|
;
|
|
;
|
|
#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
|
|
;
|
|
;
|
|
;
|
|
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 ; TICK PROCESSING VECTOR
|
|
VEC_SECOND:
|
|
JP HB_SECOND ; SECOND PROCESSING VECTOR
|
|
;
|
|
; TIMER HANDLERS
|
|
;
|
|
HB_TICK:
|
|
; INCREMENT TICK COUNTER (32 BIT)
|
|
LD HL,HB_TICKS ; POINT TO TICK COUNTER
|
|
CALL INC32HL
|
|
LD HL,HB_SECTCK ; POINT TO SECONDS TICK COUNTER
|
|
DEC (HL) ; COUNTDOWN ONE SECOND OF TICKS
|
|
JR NZ,HB_TICK1 ; NOT DONE, SKIP AHEAD
|
|
LD A,TICKFREQ ; TICKS PER SECOND
|
|
LD (HL),A ; RESET COUNTDOWN REGISTER
|
|
CALL VEC_SECOND ; DO SECONDS PROCESSING VIA VECTOR
|
|
;
|
|
HB_TICK1:
|
|
;
|
|
#IF (CPUFAM == CPU_Z180)
|
|
; ACK/RESET Z180 TIMER INTERRUPT
|
|
IN0 A,(Z180_TCR)
|
|
IN0 A,(Z180_TMDR0L)
|
|
#ENDIF
|
|
;
|
|
#IF (WDOGMODE != WDOG_NONE)
|
|
; PULSE WATCHDOG
|
|
OUT (WDOGIO),A ; VALUE IS IRRELEVANT
|
|
#ENDIF
|
|
;
|
|
#IF MKYENABLE
|
|
CALL MKY_INT
|
|
#ENDIF
|
|
;
|
|
OR $FF ; NZ SET TO INDICATE INT HANDLED
|
|
RET
|
|
;
|
|
HB_SECOND:
|
|
; INCREMENT SECONDS COUNTER
|
|
LD HL,HB_SECS ; POINT TO SECONDS COUNTER
|
|
JP INC32HL ; INCREMENT AND RETURN
|
|
;
|
|
; BAD INTERRUPT HANDLER
|
|
;
|
|
HB_BADINT:
|
|
|
|
#IF FALSE ; *DEBUG*
|
|
LD HL,HB_BADINTCNT
|
|
INC (HL)
|
|
LD A,(HL)
|
|
OUT (DIAGPORT),A
|
|
OR $FF
|
|
RET
|
|
HB_BADINTCNT .DB 0
|
|
#ENDIF ; *DEBUG*
|
|
|
|
CALL NEWLINE2
|
|
PRTS("+++ BAD INT $")
|
|
LD A,L
|
|
RRCA
|
|
RRCA
|
|
CALL PRTHEXBYTE
|
|
PRTS("H: $")
|
|
|
|
CALL XREGDMP
|
|
;CALL CONTINUE
|
|
OR $FF ; SIGNAL INTERRUPT HANDLED
|
|
RET
|
|
;
|
|
; Z280 BAD INT HANDLER
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
;
|
|
Z280_BADINT:
|
|
; SAVE REASON CODE FOR POSSIBLE RETURN VIA RETIL
|
|
EX (SP),HL ; GET MSR, SAVE HL
|
|
LD (HB_RCSAV),HL ; SAVE IT
|
|
POP HL ; RECOVER HL, POP STACK
|
|
; SAVE MSR FOR POSSIBLE RETURN VIA RETIL
|
|
EX (SP),HL ; GET MSR, SAVE HL
|
|
LD (HB_MSRSAV),HL ; SAVE IT
|
|
POP HL ; RECOVER HL, POP STACK
|
|
;
|
|
PUSH DE
|
|
LD DE,Z280_BADINTSTR
|
|
CALL NEWLINE2
|
|
PRTS("+++ $")
|
|
CALL WRITESTR
|
|
POP DE
|
|
CALL XREGDMP
|
|
;
|
|
; RECOVER MSR, THEN RETURN VIA RETIL
|
|
PUSH HL ; SAVE HL
|
|
LD HL,(HB_RCSAV) ; GET SAVED REASON CODE
|
|
PRTS(" RC=$")
|
|
CALL PRTHEXWORDHL ; DUMP MSR
|
|
LD HL,(HB_MSRSAV) ; GET SAVED MSR
|
|
PRTS(" MSR=$")
|
|
CALL PRTHEXWORDHL ; DUMP MSR
|
|
EX (SP),HL ; MSR TO STK, RECOVER HL
|
|
;
|
|
RETIL ; RETURN FROM INT
|
|
;
|
|
Z280_SSTEP:
|
|
; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL
|
|
EX (SP),HL ; GET MSR, SAVE HL
|
|
LD (HB_MSRSAV),HL ; SAVE IT
|
|
POP HL ; RECOVER HL, POP STACK
|
|
;
|
|
PUSH DE
|
|
LD DE,Z280_SSTEPSTR
|
|
JP Z280_DIAG
|
|
;
|
|
Z280_BRKHLT:
|
|
; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL
|
|
EX (SP),HL ; GET MSR, SAVE HL
|
|
LD (HB_MSRSAV),HL ; SAVE IT
|
|
POP HL ; RECOVER HL, POP STACK
|
|
;
|
|
PUSH DE
|
|
LD DE,Z280_BRKHLTSTR
|
|
JP Z280_DIAG
|
|
;
|
|
Z280_DIVEXC:
|
|
; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL
|
|
EX (SP),HL ; GET MSR, SAVE HL
|
|
LD (HB_MSRSAV),HL ; SAVE IT
|
|
POP HL ; RECOVER HL, POP STACK
|
|
;
|
|
PUSH DE
|
|
LD DE,Z280_DIVEXCSTR
|
|
JP Z280_DIAG
|
|
;
|
|
Z280_STKOVR:
|
|
; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL
|
|
EX (SP),HL ; GET MSR, SAVE HL
|
|
LD (HB_MSRSAV),HL ; SAVE IT
|
|
POP HL ; RECOVER HL, POP STACK
|
|
;
|
|
PUSH DE
|
|
LD DE,Z280_STKOVRSTR
|
|
JP Z280_DIAG
|
|
;
|
|
Z280_ACCVIO:
|
|
; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL
|
|
EX (SP),HL ; GET MSR, SAVE HL
|
|
LD (HB_MSRSAV),HL ; SAVE IT
|
|
POP HL ; RECOVER HL, POP STACK
|
|
;
|
|
PUSH DE
|
|
LD DE,Z280_ACCVIOSTR
|
|
JP Z280_DIAG
|
|
;
|
|
Z280_DIAG:
|
|
CALL NEWLINE2
|
|
PRTS("+++ $")
|
|
CALL WRITESTR
|
|
POP DE
|
|
CALL XREGDMP
|
|
;
|
|
; RECOVER MSR, THEN RETURN VIA RETIL
|
|
PUSH HL ; SAVE HL
|
|
LD HL,(HB_MSRSAV) ; GET SAVED MSR
|
|
PRTS(" MSR=$")
|
|
CALL PRTHEXWORDHL ; DUMP MSR
|
|
EX (SP),HL ; MSR TO STK, RECOVER HL
|
|
;
|
|
;RETIL
|
|
DI
|
|
HALT
|
|
;
|
|
Z280_BADINTSTR .TEXT "BAD INT $"
|
|
Z280_SSTEPSTR .TEXT "SINGLE STEP $"
|
|
Z280_BRKHLTSTR .TEXT "BREAK HALT $"
|
|
Z280_DIVEXCSTR .TEXT "DIVISION EXCEPTION $"
|
|
Z280_STKOVRSTR .TEXT "STACK OVERFLOW $"
|
|
Z280_ACCVIOSTR .TEXT "ACCESS VIOLATION $"
|
|
;
|
|
#ENDIF
|
|
;
|
|
; Z280 PRIVILEGED INSTRUCTION HANDLER
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
;
|
|
Z280_PRIVINST:
|
|
; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL
|
|
EX (SP),HL ; GET MSR, SAVE HL
|
|
LD (HB_MSRSAV),HL ; SAVE IT
|
|
POP HL ; RECOVER HL, POP STACK
|
|
EX (SP),HL ; GET ADR, SAVE HL
|
|
;
|
|
PUSH AF
|
|
PUSH BC
|
|
PUSH DE
|
|
;
|
|
LDUP A,(HL) ; BYTE FROM USER SPACE
|
|
;
|
|
; HANDLE DI
|
|
CP $F3 ; DI?
|
|
JR NZ,Z280_PRIVINST2
|
|
HB_DI ; DO THE DI
|
|
INC HL ; BUMP PAST IT
|
|
JR Z280_PRIVINSTX
|
|
;
|
|
Z280_PRIVINST2:
|
|
; HANDLE EI
|
|
CP $FB ; EI?
|
|
JR NZ,Z280_PRIVINST3
|
|
HB_EI ; DO THE EI
|
|
INC HL ; BUMP PAST IT
|
|
JR Z280_PRIVINSTX
|
|
;
|
|
Z280_PRIVINST3:
|
|
; SOMETHING ELSE, DIAGNOSE & HALT SYSTEM
|
|
LD DE,Z280_PRIVSTR
|
|
CALL WRITESTR
|
|
CALL PRTHEXWORDHL
|
|
;
|
|
; DUMP 16 BYTES OF USER ADDRESS SPACE
|
|
CALL PC_SPACE
|
|
CALL PC_LBKT
|
|
LD B,$10
|
|
Z280_PRIVINST4:
|
|
LDUP A,(HL) ; BYTE FROM USER SPACE
|
|
CALL PRTHEXBYTE
|
|
INC HL
|
|
DJNZ Z280_PRIVINST4
|
|
CALL PC_RBKT
|
|
;
|
|
; GO NO FURTHER
|
|
DI
|
|
HALT
|
|
;
|
|
Z280_PRIVINSTX:
|
|
; RESTORE REGISTERS
|
|
POP DE
|
|
POP BC
|
|
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
|
|
;
|
|
; COMMON API FUNCTION DISPATCH CODE
|
|
;
|
|
; 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
|
|
;
|
|
; 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:
|
|
; 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
|
|
;
|
|
; 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 INTERRUPT VECTOR TABLE
|
|
;==================================================================================================
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
;
|
|
; 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.
|
|
;
|
|
.FILL $1000 - ($ & $FFF) ; MUST BE 4K ALIGNED!
|
|
;
|
|
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
|
|
;
|
|
; Z280 BANK SELECTION (CALLED FROM PROXY)
|
|
;
|
|
#IF (MEMMGR == MM_Z280)
|
|
;
|
|
; REG A HAS BANK ID, REG B HAS INITIAL PDR TO PROGRAM
|
|
; REGISTERS AF, BC, HL DESTROYED
|
|
;
|
|
; THIS ROUTINE MAY BE RELOCATED TO RUN IN HIGH MEMORY IN CERTAIN CASES
|
|
; LIKE A SYSTEM RESTART. IT MUST BE KEPT ENTIRELY RELOCATABLE.
|
|
;
|
|
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
|
|
;
|
|
; 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, MOVE RAM BIT
|
|
SET RAMLOC-16,H ; HL=0000 RBBB B000 0000
|
|
;
|
|
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 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
|
|
JR Z,Z2DMAADR2
|
|
RES 6,H
|
|
SET RAMLOC-16,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
|
|
;
|
|
; 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
|
|
;
|
|
;==================================================================================================
|
|
; DEVICE DRIVERS
|
|
;==================================================================================================
|
|
;
|
|
#IF (DSRTCENABLE)
|
|
ORG_DSRTC .EQU $
|
|
#INCLUDE "dsrtc.asm"
|
|
SIZ_DSRTC .EQU $ - ORG_DSRTC
|
|
.ECHO "DSRTC occupies "
|
|
.ECHO SIZ_DSRTC
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (DS1501RTCENABLE)
|
|
ORG_DS1501RTC .EQU $
|
|
#INCLUDE "ds1501rtc.asm"
|
|
SIZ_DS1501RTC .EQU $ - ORG_DS1501RTC
|
|
.ECHO "DS1501RTC occupies "
|
|
.ECHO SIZ_DS1501RTC
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (BQRTCENABLE)
|
|
ORG_BQRTC .EQU $
|
|
#INCLUDE "bqrtc.asm"
|
|
SIZ_BQRTC .EQU $ - ORG_BQRTC
|
|
.ECHO "BQRTC occupies "
|
|
.ECHO SIZ_BQRTC
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
#IF (SIMRTCENABLE)
|
|
ORG_SIMRTC .EQU $
|
|
#INCLUDE "simrtc.asm"
|
|
SIZ_SIMRTC .EQU $ - ORG_SIMRTC
|
|
.ECHO "SIMRTC occupies "
|
|
.ECHO SIZ_SIMRTC
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
#IF (DS7RTCENABLE & (DS7RTCMODE=DS7RTCMODE_PCF))
|
|
ORG_PCF8584 .EQU $
|
|
#INCLUDE "pcf8584.asm"
|
|
SIZ_PCF8584 .EQU $ - ORG_PCF8584
|
|
.ECHO "PCF8584 occupies "
|
|
.ECHO SIZ_PCF8584
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
|
|
#IF (DS7RTCENABLE)
|
|
ORG_DS7RTC .EQU $
|
|
#INCLUDE "ds7rtc.asm"
|
|
SIZ_DS7RTC .EQU $ - ORG_DS7RTC
|
|
.ECHO "DS7RTC occupies "
|
|
.ECHO SIZ_DS7RTC
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (INTRTCENABLE)
|
|
ORG_INTRTC .EQU $
|
|
#INCLUDE "intrtc.asm"
|
|
SIZ_INTRTC .EQU $ - ORG_INTRTC
|
|
.ECHO "INTRTC occupies "
|
|
.ECHO SIZ_INTRTC
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (RP5RTCENABLE)
|
|
ORG_RP5RTC .EQU $
|
|
#INCLUDE "rp5rtc.asm"
|
|
SIZ_RP5RTC .EQU $ - ORG_RP5RTC
|
|
.ECHO "RP5RTC occupies "
|
|
.ECHO SIZ_RP5RTC
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
#IF (ASCIENABLE)
|
|
ORG_ASCI .EQU $
|
|
#INCLUDE "asci.asm"
|
|
SIZ_ASCI .EQU $ - ORG_ASCI
|
|
.ECHO "ASCI occupies "
|
|
.ECHO SIZ_ASCI
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (Z2UENABLE)
|
|
ORG_Z2U .EQU $
|
|
#INCLUDE "z2u.asm"
|
|
SIZ_Z2U .EQU $ - ORG_Z2U
|
|
.ECHO "Z2U occupies "
|
|
.ECHO SIZ_Z2U
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (UARTENABLE)
|
|
ORG_UART .EQU $
|
|
#INCLUDE "uart.asm"
|
|
SIZ_UART .EQU $ - ORG_UART
|
|
.ECHO "UART occupies "
|
|
.ECHO SIZ_UART
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (DUARTENABLE)
|
|
ORG_DUART .EQU $
|
|
#INCLUDE "duart.asm"
|
|
SIZ_DUART .EQU $ - ORG_DUART
|
|
.ECHO "DUART occupies "
|
|
.ECHO SIZ_DUART
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (SIOENABLE)
|
|
ORG_SIO .EQU $
|
|
#INCLUDE "sio.asm"
|
|
SIZ_SIO .EQU $ - ORG_SIO
|
|
.ECHO "SIO occupies "
|
|
.ECHO SIZ_SIO
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (ACIAENABLE)
|
|
ORG_ACIA .EQU $
|
|
#INCLUDE "acia.asm"
|
|
SIZ_ACIA .EQU $ - ORG_ACIA
|
|
.ECHO "ACIA occupies "
|
|
.ECHO SIZ_ACIA
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (PIOENABLE)
|
|
ORG_PIO .EQU $
|
|
#INCLUDE "pio.asm"
|
|
SIZ_PIO .EQU $ - ORG_PIO
|
|
.ECHO "PIO occupies "
|
|
.ECHO SIZ_PIO
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (LPTENABLE)
|
|
ORG_LPT .EQU $
|
|
#INCLUDE "lpt.asm"
|
|
SIZ_LPT .EQU $ - ORG_LPT
|
|
.ECHO "LPT occupies "
|
|
.ECHO SIZ_LPT
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (PIO_4P | PIO_ZP | PIO_SBC)
|
|
ORG_PIO .EQU $
|
|
#INCLUDE "pio.asm"
|
|
SIZ_PIO .EQU $ - ORG_PIO
|
|
.ECHO "PIO occupies "
|
|
.ECHO SIZ_PIO
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (UFENABLE)
|
|
ORG_UF .EQU $
|
|
#INCLUDE "uf.asm"
|
|
SIZ_UF .EQU $ - ORG_UF
|
|
.ECHO "UF occupies "
|
|
.ECHO SIZ_UF
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (VGAENABLE)
|
|
ORG_VGA .EQU $
|
|
#INCLUDE "vga.asm"
|
|
SIZ_VGA .EQU $ - ORG_VGA
|
|
.ECHO "VGA occupies "
|
|
.ECHO SIZ_VGA
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (CVDUENABLE)
|
|
ORG_CVDU .EQU $
|
|
#INCLUDE "cvdu.asm"
|
|
SIZ_CVDU .EQU $ - ORG_CVDU
|
|
.ECHO "CVDU occupies "
|
|
.ECHO SIZ_CVDU
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (VDUENABLE)
|
|
ORG_VDU .EQU $
|
|
#INCLUDE "vdu.asm"
|
|
SIZ_VDU .EQU $ - ORG_VDU
|
|
.ECHO "VDU occupies "
|
|
.ECHO SIZ_VDU
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (TMSENABLE)
|
|
ORG_TMS .EQU $
|
|
#INCLUDE "tms.asm"
|
|
SIZ_TMS .EQU $ - ORG_TMS
|
|
.ECHO "TMS occupies "
|
|
.ECHO SIZ_TMS
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (GDCENABLE)
|
|
ORG_GDC .EQU $
|
|
#INCLUDE "gdc.asm"
|
|
SIZ_GDC .EQU $ - ORG_GDC
|
|
.ECHO "GDC occupies "
|
|
.ECHO SIZ_GDC
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (DMAENABLE)
|
|
ORG_DMA .EQU $
|
|
#INCLUDE "dma.asm"
|
|
SIZ_DMA .EQU $ - ORG_DMA
|
|
.ECHO "DMA occupies "
|
|
.ECHO SIZ_DMA
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
; FONTS AREA
|
|
;
|
|
ORG_FONTS .EQU $
|
|
;
|
|
.ECHO "FONTS"
|
|
;
|
|
#IFDEF USEFONT8X8
|
|
FONT8X8:
|
|
#IF USELZSA2
|
|
#INCLUDE "font8x8c.asm"
|
|
#ELSE
|
|
#INCLUDE "font8x8u.asm"
|
|
#ENDIF
|
|
.ECHO " 8X8"
|
|
#ENDIF
|
|
;
|
|
#IFDEF USEFONT8X11
|
|
FONT8X11:
|
|
#IF USELZSA2
|
|
#INCLUDE "font8x11c.asm"
|
|
#ELSE
|
|
#INCLUDE "font8x11u.asm"
|
|
#ENDIF
|
|
.ECHO " 8X11"
|
|
#ENDIF
|
|
;
|
|
#IFDEF USEFONT8X16
|
|
FONT8X16:
|
|
#IF USELZSA2
|
|
#INCLUDE "font8x16c.asm"
|
|
#ELSE
|
|
#INCLUDE "font8x16u.asm"
|
|
#ENDIF
|
|
.ECHO " 8X16"
|
|
#ENDIF
|
|
;
|
|
#IFDEF USEFONTCGA
|
|
FONTCGA:
|
|
#IF USELZSA2
|
|
#INCLUDE "fontcgac.asm"
|
|
#ELSE
|
|
#INCLUDE "fontcgau.asm"
|
|
#ENDIF
|
|
.ECHO " CGA"
|
|
#ENDIF
|
|
;
|
|
SIZ_FONTS .EQU $ - ORG_FONTS
|
|
.ECHO " occupy "
|
|
.ECHO SIZ_FONTS
|
|
.ECHO " bytes.\n"
|
|
;
|
|
#IF (CVDUENABLE | VGAENABLE) | GDCENABLE | (TMSENABLE & ((TMSMODE == TMSMODE_MSXKBD) | (TMSMODE == TMSMODE_MBC)))
|
|
ORG_KBD .EQU $
|
|
#INCLUDE "kbd.asm"
|
|
SIZ_KBD .EQU $ - ORG_KBD
|
|
.ECHO "KBD occupies "
|
|
.ECHO SIZ_KBD
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (VDUENABLE | (TMSENABLE & (TMSMODE == TMSMODE_N8)))
|
|
ORG_PPK .EQU $
|
|
#INCLUDE "ppk.asm"
|
|
SIZ_PPK .EQU $ - ORG_PPK
|
|
.ECHO "PPK occupies "
|
|
.ECHO SIZ_PPK
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (MKYENABLE)
|
|
ORG_MKY .EQU $
|
|
#INCLUDE "mky.asm"
|
|
SIZ_MKY .EQU $ - ORG_MKY
|
|
.ECHO "MKY occupies "
|
|
.ECHO SIZ_MKY
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (PRPENABLE)
|
|
ORG_PRP .EQU $
|
|
#INCLUDE "prp.asm"
|
|
SIZ_PRP .EQU $ - ORG_PRP
|
|
.ECHO "PRP occupies "
|
|
.ECHO SIZ_PRP
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (PPPENABLE)
|
|
ORG_PPP .EQU $
|
|
#INCLUDE "ppp.asm"
|
|
SIZ_PPP .EQU $ - ORG_PPP
|
|
.ECHO "PPP occupies "
|
|
.ECHO SIZ_PPP
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (MDENABLE)
|
|
ORG_MD .EQU $
|
|
#INCLUDE "md.asm"
|
|
SIZ_MD .EQU $ - ORG_MD
|
|
.ECHO "MD occupies "
|
|
.ECHO SIZ_MD
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (FDENABLE)
|
|
ORG_FD .EQU $
|
|
#INCLUDE "fd.asm"
|
|
SIZ_FD .EQU $ - ORG_FD
|
|
.ECHO "FD occupies "
|
|
.ECHO SIZ_FD
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (RFENABLE)
|
|
ORG_RF .EQU $
|
|
#INCLUDE "rf.asm"
|
|
SIZ_RF .EQU $ - ORG_RF
|
|
.ECHO "RF occupies "
|
|
.ECHO SIZ_RF
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (IDEENABLE)
|
|
ORG_IDE .EQU $
|
|
#INCLUDE "ide.asm"
|
|
SIZ_IDE .EQU $ - ORG_IDE
|
|
.ECHO "IDE occupies "
|
|
.ECHO SIZ_IDE
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (PPIDEENABLE)
|
|
ORG_PPIDE .EQU $
|
|
#INCLUDE "ppide.asm"
|
|
SIZ_PPIDE .EQU $ - ORG_PPIDE
|
|
.ECHO "PPIDE occupies "
|
|
.ECHO SIZ_PPIDE
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (SDENABLE)
|
|
ORG_SD .EQU $
|
|
#INCLUDE "sd.asm"
|
|
SIZ_SD .EQU $ - ORG_SD
|
|
.ECHO "SD occupies "
|
|
.ECHO SIZ_SD
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (HDSKENABLE)
|
|
ORG_HDSK .EQU $
|
|
#INCLUDE "hdsk.asm"
|
|
SIZ_HDSK .EQU $ - ORG_HDSK
|
|
.ECHO "HDSK occupies "
|
|
.ECHO SIZ_HDSK
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
#IF (TERMENABLE)
|
|
ORG_TERM .EQU $
|
|
#INCLUDE "term.asm"
|
|
SIZ_TERM .EQU $ - ORG_TERM
|
|
.ECHO "TERM occupies "
|
|
.ECHO SIZ_TERM
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
;#IF (SPKENABLE & DSRTCENABLE)
|
|
#IF (SPKENABLE)
|
|
ORG_SPK .EQU $
|
|
#INCLUDE "spk.asm"
|
|
SIZ_SPK .EQU $ - ORG_SPK
|
|
.ECHO "SPK occupies "
|
|
.ECHO SIZ_SPK
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
#IF (KIOENABLE)
|
|
ORG_KIO .EQU $
|
|
#INCLUDE "kio.asm"
|
|
SIZ_KIO .EQU $ - ORG_KIO
|
|
.ECHO "KIO occupies "
|
|
.ECHO SIZ_KIO
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
#IF (CTCENABLE)
|
|
ORG_CTC .EQU $
|
|
#INCLUDE "ctc.asm"
|
|
SIZ_CTC .EQU $ - ORG_CTC
|
|
.ECHO "CTC occupies "
|
|
.ECHO SIZ_CTC
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
#IF (SN76489ENABLE)
|
|
ORG_SN76489 .EQU $
|
|
#INCLUDE "sn76489.asm"
|
|
SIZ_SN76489 .EQU $ - ORG_SN76489
|
|
.ECHO "SN76489 occupies "
|
|
.ECHO SIZ_SN76489
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
#IF (AY38910ENABLE)
|
|
ORG_AY38910 .EQU $
|
|
#INCLUDE "ay38910.asm"
|
|
SIZ_AY38910 .EQU $ - ORG_AY38910
|
|
.ECHO "AY38910 occupies "
|
|
.ECHO SIZ_AY38910
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
#IF (YM2612ENABLE)
|
|
ORG_YM2612 .EQU $
|
|
#INCLUDE "ym2612.asm"
|
|
SIZ_YM2612 .EQU $ - ORG_YM2612
|
|
.ECHO "YM2612 occupies "
|
|
.ECHO SIZ_YM2612
|
|
.ECHO " bytes.\n"
|
|
#ENDIF
|
|
;
|
|
.ECHO "RTCDEF="
|
|
.ECHO RTCDEF
|
|
.ECHO "\n"
|
|
;
|
|
#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
|
|
;
|
|
#IF (DSKYENABLE)
|
|
#DEFINE DSKY_KBD
|
|
#IF (DSKYMODE == DSKYMODE_V1)
|
|
#INCLUDE "dsky.asm"
|
|
#ENDIF
|
|
#IF (DSKYMODE == DSKYMODE_NG)
|
|
#INCLUDE "dskyng.asm"
|
|
#ENDIF
|
|
#ENDIF
|
|
;
|
|
; INCLUDE LZSA2 decompression engine if required.
|
|
;
|
|
#IF ((VGAENABLE | CVDUENABLE | TMSENABLE | GDCENABLE) & USELZSA2)
|
|
#INCLUDE "unlzsa2s.asm"
|
|
#ENDIF
|
|
;
|
|
; DETECT CPU SPEED 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
|
|
;
|
|
; 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
|
|
;
|
|
; 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
|
|
;
|
|
;
|
|
;
|
|
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
|
|
;
|
|
;
|
|
;
|
|
SYSHALT:
|
|
LD DE,STR_HALT
|
|
CALL WRITESTR
|
|
DI
|
|
HALT
|
|
;
|
|
; 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
|
|
;==================================================================================================
|
|
; DISPLAY SUMMARY OF ATTACHED UNITS/DEVICES
|
|
;==================================================================================================
|
|
;
|
|
PRTSUM:
|
|
CALL NEWLINE2 ; SKIP A LINE
|
|
LD DE,PS_STRHDR ; POINT TO HEADER
|
|
CALL WRITESTR ; PRINT IT
|
|
;
|
|
LD C,BF_SYSGET_CIOCNT ; CHARACTER DEVICES
|
|
LD HL,PS_SERIAL
|
|
CALL PRT_ALLD
|
|
;
|
|
LD C,BF_SYSGET_DIOCNT ; DISK DRIVES
|
|
LD HL,PS_DISK
|
|
CALL PRT_ALLD
|
|
;
|
|
LD C,BF_SYSGET_VDACNT ; VIDEO DEVICES
|
|
LD HL,PS_VIDEO
|
|
CALL PRT_ALLD
|
|
;
|
|
LD C,BF_SYSGET_SNDCNT ; SOUND DEVICES
|
|
LD HL,PS_SOUND
|
|
CALL PRT_ALLD
|
|
RET
|
|
;
|
|
PRT_ALLD:
|
|
LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET
|
|
RST 08 ; E := UNIT COUNT
|
|
LD B,E ; MOVE TO B FOR LOOP COUNT
|
|
LD A,E ; MOVE TO ACCUM
|
|
OR A ; SET FLAGS
|
|
RET Z ; IF NONE, JUST RETURN
|
|
LD C,0 ; C WILL BE UNIT INDEX
|
|
PRT_ALLD1:
|
|
PUSH BC ; SAVE LOOP CONTROL
|
|
PUSH DE
|
|
PUSH HL
|
|
CALL JPHL ; CALL THE ROUTINE PASSED IN HL
|
|
POP HL
|
|
POP DE
|
|
POP BC ; RESTORE LOOP CONTROL
|
|
INC C ; BUMP UNIT INDEX
|
|
DJNZ PRT_ALLD1 ; LOOP THRU ALL DEVICES
|
|
RET
|
|
;
|
|
; PRINT ONE LINE DISK UNIT/DEVICE INFO, DISK UNIT INDEX IN C
|
|
;
|
|
PS_DISK:
|
|
PUSH BC ; SAVE UNIT INDEX FOR LATER
|
|
;
|
|
; UNIT COLUMN
|
|
PRTS("Disk $")
|
|
LD A,C ; MOVE UNIT NUM TO A
|
|
CALL PRTDECB ; PRINT IT
|
|
CP 10 ; CHECK FOR MULTIPLE DIGITS
|
|
CALL C,PC_SPACE ; EXTRA SPACE IF NEEDED
|
|
PRTS(" $") ; PAD TO NEXT COLUMN
|
|
;
|
|
; DEVICE COLUMN
|
|
LD B,BF_DIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C
|
|
RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES
|
|
PUSH BC ; SAVE ATTRIBUTES
|
|
LD HL,PS_DDMD ; POINT TO DISK DEVICE TYPE NAME TABLE
|
|
CALL PS_PRTDEV ; PRINT DISK DEVICE NMEMONIC PADDED TO FIELD WIDTH
|
|
POP DE ; RECOVER ATTRIBUTES TO DE
|
|
PUSH DE ; SAVE ATTRIBUTES AGAIN
|
|
CALL PS_PRTDT ; PRINT DISK TYPE
|
|
POP DE ; RESTORE ATTRIBUTES
|
|
POP BC ; RESTORE UNIT NUM
|
|
CALL PS_PRTDC ; PRINT DISK CAPACITY
|
|
;
|
|
CALL NEWLINE
|
|
RET
|
|
;
|
|
; PRINT DISK TYPE (DISK ATTRIBUTE IN E)
|
|
;
|
|
PS_PRTDT:
|
|
LD A,E ; ATTRIBUTES TO A
|
|
BIT 7,A ; FLOPPY BIT SET?
|
|
LD HL,PS_DTFLOP ; ASSUME FLOPPY
|
|
JP NZ,PS_PRT18 ; IF FLOPPY, JUMP AHEAD
|
|
|
|
LD C,E
|
|
LD DE,PS_DTHARD
|
|
LD A,00111000B
|
|
CALL PRTIDXMSK
|
|
CALL PS_PAD18 ; PAD TO 18 SPACES
|
|
RET
|
|
;
|
|
; PRINT DISK CAPACITY (UNIT IN C, ATTRIBUTE IN E)
|
|
;
|
|
PS_PRTDC:
|
|
;
|
|
LD A,E ; ATTRIBUTE TO ACCUM
|
|
BIT 7,A ; TEST FOR FLOPPY
|
|
JR NZ,PS_PRTDC2 ; HANDLE FLOPPY
|
|
RRCA ; ISOLATE TYPE BITS
|
|
RRCA
|
|
RRCA
|
|
AND $07
|
|
CP 4 ; ROM DISK?
|
|
JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB
|
|
CP 5 ; RAM DISK?
|
|
JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB
|
|
CP 7 ; FLASH DISK?
|
|
JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB
|
|
;
|
|
; PRINT HARD DISK STORAGE SIZE IN MB
|
|
LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY
|
|
RST 08 ; DE:HL := BLOCKS
|
|
JP NZ,PS_PRTNUL ; MEDIA PROBLEM
|
|
RES 7,D ; CLEAR LBA BIT
|
|
LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB
|
|
CALL SRL32 ; RIGHT SHIFT
|
|
;CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED)
|
|
CALL PRTDEC32 ; PRINT DWORD IN DECIMAL
|
|
PRTS("MB$") ; PRINT SUFFIX
|
|
CALL PC_COMMA
|
|
PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA
|
|
RET ; DONE
|
|
;
|
|
PS_PRTDC1:
|
|
; PRINT ROM/RAM DISK CAPACITY IN KB
|
|
LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY
|
|
RST 08 ; DE:HL := BLOCKS
|
|
JP NZ,PS_PRTNUL ; MEDIA PROBLEM
|
|
RES 7,D ; CLEAR LBA BIT
|
|
LD B,1 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB
|
|
CALL SRL32 ; RIGHT SHIFT
|
|
;CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED)
|
|
CALL PRTDEC32 ; PRINT DWORD IN DECIMAL
|
|
PRTS("KB$") ; PRINT SUFFIX
|
|
CALL PC_COMMA
|
|
PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA
|
|
RET ; DONE
|
|
;
|
|
PS_PRTDC2:
|
|
LD C,E ; ATTRIBUTE TO C FOR SAFE KEEPING
|
|
;
|
|
LD A,01100000B ; DISPLAY FORM FACTOR
|
|
LD DE,PS_FLP_FSTR ; WHICH IS DEFINED IN
|
|
CALL PRTIDXMSK ; BITS 5 AND 6.
|
|
;
|
|
LD A,00010000B ; DISPLAY SIDES
|
|
LD DE,PS_FLP_SSTR ; WHICH IS DEFINED
|
|
CALL PRTIDXMSK ; IN BIT 4
|
|
;
|
|
LD A,00001100B ; DISPLAY DENSITY
|
|
LD DE,PS_FLP_DSTR ; WHICH IS DEFINED IN
|
|
CALL PRTIDXMSK ; BITS 2 AND 3.
|
|
;
|
|
CALL PC_COMMA
|
|
PRTS("CHS$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA
|
|
;
|
|
RET ; DONE
|
|
;
|
|
; PRINT ONE LINE SERIAL UNIT/DEVICE INFO, SERIAL UNIT INDEX IN C
|
|
;
|
|
PS_SERIAL:
|
|
PUSH BC ; SAVE UNIT INDEX FOR LATER
|
|
;
|
|
; UNIT COLUMN
|
|
PRTS("Char $")
|
|
LD A,C ; MOVE UNIT NUM TO A
|
|
CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT
|
|
PRTS(" $") ; PAD TO NEXT COLUMN
|
|
;
|
|
; DEVICE COLUMN
|
|
LD B,BF_CIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C
|
|
RST 08 ; DE:=DEVTYP/NUM, C:=DEVICE ATTRIBUTES
|
|
PUSH BC ; SAVE ATTRIBUTES
|
|
LD HL,PS_SDUART ; POINT TO SERIAL DEVICE TYPE NAME TABLE
|
|
CALL PS_PRTDEV ; PRINT SERIAL DEVICE NMEMONIC PADDED TO FIELD WIDTH
|
|
POP BC ; RECOVER ATTRIBUTES
|
|
PUSH BC ; SAVE ATTRIBUTES AGAIN
|
|
CALL PS_PRTST ; PRINT SERIAL TYPE
|
|
POP BC ; RESTORE ATTRIBUTES
|
|
POP DE ; RESTORE UNIT NUM TO E
|
|
CALL PS_PRTSC ; PRINT SERIAL CONFIG
|
|
;
|
|
CALL NEWLINE
|
|
RET
|
|
;
|
|
; PRINT CHARACTER TYPE (SERIAL ATTRIBUTE IN E)
|
|
;
|
|
PS_PRTST:
|
|
LD HL,PS_STPPT
|
|
BIT 6,C
|
|
JP NZ,PS_PRT18 ; PARALLEL TYPE?
|
|
LD HL,PS_STRS232 ; ASSUME RS-232
|
|
BIT 7,C ; 0=RS-232, 1=TERMINAL
|
|
JP Z,PS_PRT18 ; HANDLE TERMINAL TYPE
|
|
LD HL,PS_STTERM ; TYPE IS TERMINAL
|
|
JP PS_PRT18
|
|
;
|
|
; PRINT SERIAL CONFIG (UNIT IN E, ATTRIBUTE IN C)
|
|
;
|
|
PS_PRTSC:
|
|
BIT 6,C ; PARALLEL TYPE?
|
|
JR NZ,PSPRTPC0
|
|
|
|
BIT 7,C ; 0=RS-232, 1=TERMINAL
|
|
JP NZ,PS_PRTSC1 ; PRINT TERMINAL CONFIG
|
|
;
|
|
; PRINT RS-232 CONFIG
|
|
LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG
|
|
LD C,E ; SET SERIAL UNIT NUM
|
|
RST 08 ; DE:HL := BAUD RATE
|
|
LD A,D ; TEST FOR $FF
|
|
AND E
|
|
INC A ; SET Z IF DE == $FF
|
|
JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED
|
|
;
|
|
PS_PRTSC0:
|
|
; PRINT BAUD RATE
|
|
PUSH DE ; PRESERVE DE
|
|
LD A,D
|
|
AND $1F ; ISOLATE ENCODED BAUD RATE
|
|
LD L,A ; PUT IN L
|
|
LD H,0 ; H IS ALWAYS ZERO
|
|
LD DE,75 ; BAUD RATE DECODE CONSTANT
|
|
CALL DECODE ; DE:HL := BAUD RATE
|
|
LD BC,HB_BCDTMP ; POINT TO TEMP BCD BUF
|
|
CALL BIN2BCD ; CONVERT TO BCD
|
|
CALL PRTBCD ; AND PRINT IN DECIMAL
|
|
POP DE ; RESTORE DE
|
|
;
|
|
; PRINT DATA BITS
|
|
PUSH DE ; PRESERVE DE
|
|
CALL PC_COMMA ; FORMATTING
|
|
LD A,E ; GET CONFIG BYTE
|
|
AND $03 ; ISOLATE DATA BITS VALUE
|
|
ADD A,'5' ; CONVERT TO CHARACTER
|
|
CALL COUT ; AND PRINT
|
|
POP DE ; RESTORE DE
|
|
;
|
|
; PRINT PARITY
|
|
PUSH DE ; PRESERVE DE
|
|
CALL PC_COMMA ; FORMATTING
|
|
LD A,E ; GET CONFIG BYTE
|
|
RRCA ; SHIFT RELEVANT BITS
|
|
RRCA ; ...
|
|
RRCA ; ...
|
|
AND $07 ; AND ISOLATE DATA BITS VALUE
|
|
LD HL,PS_STPARMAP ; CHARACTER LOOKUP TABLE
|
|
CALL ADDHLA ; APPLY OFFSET
|
|
LD A,(HL) ; GET CHARACTER
|
|
CALL COUT ; AND PRINT
|
|
POP DE ; RESTORE DE
|
|
;
|
|
; PRINT STOP BITS
|
|
CALL PC_COMMA ; FORMATTING
|
|
LD A,E ; GET CONFIG BYTE
|
|
RRCA ; SHIFT RELEVANT BITS
|
|
RRCA ; ...
|
|
AND $01 ; AND ISOLATE DATA BITS VALUE
|
|
ADD A,'1' ; MAKE IT A CHARACTER
|
|
CALL COUT ; AND PRINT
|
|
;
|
|
RET
|
|
;
|
|
PSPRTPC0:
|
|
LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG
|
|
LD C,E ; SET PARALLEL UNIT NUM
|
|
RST 08 ; DE:HL := I/O SETTING
|
|
LD A,D ; TEST FOR $FF
|
|
AND E
|
|
INC A ; SET Z IF DE == $FF
|
|
JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED
|
|
;
|
|
PS_PRTPC0:
|
|
LD C,E ; DISPLAY PIO TYPE
|
|
LD A,11000000B ; WHICH IS DEFINE BY
|
|
LD DE,PIO_MODE_STR ; BITS 6 AND 7
|
|
JP PRTIDXMSK
|
|
; RET ; TRICK RETURN
|
|
;
|
|
PS_PRTSC1:
|
|
; PRINT TERMINAL CONFIG
|
|
LD A,C ; GET ATTRIBUTE VALUE
|
|
CP $BF ; NO ATTACHED VDA
|
|
JR Z,PS_PRTSC2
|
|
PRTS("Video $") ; FORMATTING
|
|
AND $0F ; ISOLATE VIDEO UNIT NUM
|
|
CALL PRTDECB ; PRINT IT
|
|
CALL PC_COMMA
|
|
#IF (VDAEMU == EMUTYP_TTY)
|
|
PRTS("TTY$")
|
|
#ENDIF
|
|
#IF (VDAEMU == EMUTYP_ANSI)
|
|
PRTS("ANSI$")
|
|
#ENDIF
|
|
RET
|
|
;
|
|
PS_PRTSC2:
|
|
PRTS("PropTerm$") ; ASSUME PROPELLER
|
|
CALL PC_COMMA
|
|
PRTS("ANSI$")
|
|
RET
|
|
;
|
|
; PRINT ONE LINE VIDEO UNIT/DEVICE INFO, VIDEO UNIT INDEX IN C
|
|
;
|
|
PS_VIDEO:
|
|
PUSH BC ; SAVE UNIT INDEX FOR LATER
|
|
;
|
|
; UNIT COLUMN
|
|
PRTS("Video $")
|
|
LD A,C ; MOVE UNIT NUM TO A
|
|
CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT
|
|
PRTS(" $") ; PAD TO NEXT COLUMN
|
|
;
|
|
; DEVICE COLUMN
|
|
LD B,BF_VDADEV ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C
|
|
RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES
|
|
PUSH BC ; SAVE ATTRIBUTES
|
|
LD HL,PS_VDVDU ; POINT TO VIDEO DEVICE TYPE NAME TABLE
|
|
CALL PS_PRTDEV ; PRINT VIDEO DEVICE NMEMONIC PADDED TO FIELD WIDTH
|
|
POP DE ; RECOVER ATTRIBUTES
|
|
PUSH DE ; SAVE ATTRIBUTES AGAIN
|
|
CALL PS_PRTVT ; PRINT VIDEO TYPE
|
|
POP DE ; RESTORE ATTRIBUTES
|
|
POP BC ; RESTORE UNIT NUM
|
|
CALL PS_PRTVC ; PRINT VIDEO CONFIG
|
|
;
|
|
CALL NEWLINE
|
|
RET
|
|
;
|
|
; PRINT VIDEO TYPE (VIDEO ATTRIBUTE IN E)
|
|
;
|
|
PS_PRTVT:
|
|
LD HL,PS_VTCRT ; ASSUME CRT
|
|
JP PS_PRT18 ; PRINT
|
|
;
|
|
; PRINT VIDEO CONFIG (UNIT IN C, ATTRIBUTE IN E)
|
|
;
|
|
PS_PRTVC:
|
|
PRTS("Text$")
|
|
CALL PC_COMMA
|
|
LD B,BF_VDAQRY ; FUNC: QUERY FOR VDA CONFIG
|
|
RST 08 ; D:=ROWS, E:=COLS
|
|
LD A,E
|
|
CALL PRTDECB
|
|
LD A,'x'
|
|
CALL COUT
|
|
LD A,D
|
|
CALL PRTDECB
|
|
RET
|
|
;
|
|
; PRINT SOUND CONFIG
|
|
;
|
|
PS_SOUND:
|
|
PUSH BC
|
|
|
|
; UNIT COLUMN
|
|
PRTS("Sound $")
|
|
LD A,C ; MOVE UNIT NUM TO A
|
|
CALL PRTDECB ; PRINT IT
|
|
CP 10 ; CHECK FOR MULTIPLE DIGITS
|
|
CALL C,PC_SPACE ; EXTRA SPACE IF NEEDED
|
|
PRTS(" $") ; PAD TO NEXT COLUMN
|
|
|
|
; DEVICE COLUMN
|
|
|
|
PUSH BC
|
|
LD E,C
|
|
XOR A
|
|
LD DE,PS_SDSND ; POINT TO DEVICE TYPE NAME TABLE
|
|
CALL PRTIDXDEA ; PRINT DEVICE NMEMONIC PADDED TO FIELD WIDTH
|
|
LD A,C ; MOVE UNIT NUM TO A
|
|
CALL PRTDECB ; PRINT IT
|
|
CALL PC_COLON
|
|
LD A,(PRTIDXCNT)
|
|
SUB 12-1 ; SUBTRACT FIELD WIDTH (LESS THE COLON)
|
|
NEG ; MAKE IT A POSITIVE NUMBER
|
|
CALL PS_PAD ; PAD AS NEEDED
|
|
POP BC
|
|
|
|
; DEVICE TYPE
|
|
;
|
|
LD B,BF_SNDQUERY ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C
|
|
LD E,BF_SNDQ_DEV
|
|
RST 08
|
|
PUSH BC
|
|
LD C,B
|
|
LD A,11110000B ; TYPE IS IN UPPER NIBBLE
|
|
LD DE,PS_SDSN76489
|
|
CALL PRTIDXMSK
|
|
CALL PS_PAD18
|
|
POP BC
|
|
;
|
|
; DEVICE CHARACTERISTICS
|
|
;
|
|
LD B,BF_SNDQUERY ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C
|
|
LD E,BF_SNDQ_CHCNT
|
|
RST 08
|
|
LD A,B
|
|
CALL PRTDECB
|
|
LD A,'+'
|
|
CALL COUT
|
|
LD A,C
|
|
CALL PRTDECB
|
|
PRTS(" CHANNELS$")
|
|
CALL NEWLINE
|
|
;
|
|
POP BC
|
|
RET
|
|
;
|
|
; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE
|
|
;
|
|
PS_PRTDEV:
|
|
EX DE,HL
|
|
LD C,H
|
|
LD A,11110000B ; TYPE IS IN UPPER NIBBLE
|
|
CALL PRTIDXMSK
|
|
LD A,L ; UNIT NUMBER
|
|
CALL PRTDECB ; PRINT NUM, ASSUME 1 CHAR
|
|
CALL PC_COLON ; PRINT COLON
|
|
LD A,(PRTIDXCNT)
|
|
SUB 12-2+1 ; 12 CHAR FIELD - 1 POS FOR UNIT NUM AND 1 POS FOR COLON
|
|
NEG
|
|
CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A)
|
|
RET
|
|
;
|
|
; PRINT DEVICE MNEMONIC, DEVTYP/NUM SPECIFIED IN DE
|
|
;
|
|
PS_PRTNUL:
|
|
LD HL,PS_STRNUL
|
|
; FALL THRU TO PS_PRT
|
|
;
|
|
; PRINT STRING AT (HL), $ TERM, RETURN CHARS PRINTED IN C
|
|
;
|
|
PS_PRT: LD C,0 ; INIT CHAR COUNT
|
|
PS_PRT1:
|
|
LD A,(HL) ; GET CHAR
|
|
INC HL ; BUMP INDEX
|
|
CP '$' ; TERM?
|
|
RET Z ; IF SO, DONE
|
|
CALL COUT ; PRINT IT
|
|
INC C ; BUMP COUNTER
|
|
JR PS_PRT1 ; AND LOOP
|
|
;
|
|
; PAD 18 CHARACTER FIELD
|
|
;
|
|
PS_PAD18:
|
|
LD A,(PRTIDXCNT)
|
|
LD C,A
|
|
JR PS_PRT18A
|
|
;
|
|
; PRINT STRING AT HL IN 18 CHARACTER FIELD
|
|
;
|
|
PS_PRT18:
|
|
CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED
|
|
PS_PRT18A:
|
|
LD A,18 ; 18 CHAR FIELD
|
|
SUB C
|
|
; CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A)
|
|
;
|
|
; PAD N SPACES SPECIFIED IN A
|
|
;
|
|
PS_PAD: LD B,A
|
|
LD A,' '
|
|
PS_PAD1:
|
|
CALL COUT
|
|
DJNZ PS_PAD1
|
|
RET
|
|
;
|
|
HB_CPU_STR: .TEXT " Z80$"
|
|
.TEXT " Z80180$"
|
|
.TEXT " Z8S180-K$"
|
|
.TEXT " Z8S180-N$"
|
|
.TEXT " Z80280$"
|
|
;
|
|
PS_STRNUL .TEXT "--$" ; DISPLAY STRING FOR NUL VALUE
|
|
;
|
|
; DISK DEVICE STRINGS
|
|
;
|
|
PS_DDMD .TEXT "MD$"
|
|
PS_DDFD .TEXT "FD$"
|
|
PS_DDRF .TEXT "RF$"
|
|
PS_DDIDE .TEXT "IDE$"
|
|
PS_DDATAPI .TEXT "ATAPI$"
|
|
PS_DDPPIDE .TEXT "PPIDE$"
|
|
PS_DDSD .TEXT "SD$"
|
|
PS_DDPRPSD .TEXT "PRPSD$"
|
|
PS_DDPPPSD .TEXT "PPPSD$"
|
|
PS_DDHDSK .TEXT "HDSK$"
|
|
;
|
|
; DISK TYPE STRINGS
|
|
;
|
|
PS_DTFLOP .TEXT "Floppy Disk$"
|
|
PS_DTHARD .TEXT "Hard Disk$"
|
|
PS_DTCF .TEXT "CompactFlash$"
|
|
PS_DTSD .TEXT "SD Card$"
|
|
PS_DTUSB .TEXT "USB Drive$"
|
|
PS_DTROM .TEXT "ROM Disk$"
|
|
PS_DTRAM .TEXT "RAM Disk$"
|
|
PS_DTRF .TEXT "RAM Floppy$"
|
|
PS_DTFSH .TEXT "Flash Drive$"
|
|
PS_DTOTHER .TEXT "???$"
|
|
;
|
|
; FLOPPY ATTRIBUTE STRINGS
|
|
;
|
|
PS_FLP_FSTR: .TEXT "8\",$" ; PS_FLP8
|
|
.TEXT "5.25\",$" ; PS_FLP5
|
|
.TEXT "3.5\",$" ; PS_FLP3
|
|
.TEXT "???\",$" ; PS_FLPN
|
|
;
|
|
PS_FLP_SSTR: .TEXT "SS/$" ; PS_FLPSS
|
|
.TEXT "DS/$" ; PS_FLPDS
|
|
;
|
|
PS_FLP_DSTR: .TEXT "SD$" ; PS_FLPSD
|
|
.TEXT "DD$" ; PS_FLPDD
|
|
.TEXT "HD$" ; PS_FLPHD
|
|
.TEXT "ED$" ; PS_FLPED
|
|
;
|
|
; CHARACTER DEVICE STRINGS
|
|
;
|
|
PS_SDUART .TEXT "UART$"
|
|
PS_SDASCI .TEXT "ASCI$"
|
|
PS_SDTERM .TEXT "TERM$"
|
|
PS_SDPRPCON .TEXT "PRPCON$"
|
|
PS_SDPPPCON .TEXT "PPPCON$"
|
|
PS_SDSIO .TEXT "SIO$"
|
|
PS_SDACIA .TEXT "ACIA$"
|
|
PS_SDPIO .TEXT "PIO$"
|
|
PS_SDUF .TEXT "UF$"
|
|
PS_SDDUART .TEXT "DUART$"
|
|
PS_SDZ2U .TEXT "Z2U$"
|
|
PS_SDLPT .TEXT "LPT$"
|
|
;
|
|
; CHARACTER SUB TYPE STRINGS
|
|
;
|
|
PS_STRS232 .TEXT "RS-232$"
|
|
PS_STTERM .TEXT "Terminal$"
|
|
PS_STPPT .TEXT "Parallel$"
|
|
;
|
|
PS_STPARMAP .DB "NONENMNS"
|
|
;
|
|
; PARALLEL TYPE STRINGS
|
|
;
|
|
PIO_MODE_STR: .TEXT "Output$"
|
|
.TEXT "Input$"
|
|
.TEXT "Bidirectional$"
|
|
.TEXT "BitCtrl$"
|
|
;
|
|
; VIDEO DEVICE STRINGS
|
|
;
|
|
PS_VDVDU .TEXT "VDU$"
|
|
PS_VDCVDU .TEXT "CVDU$"
|
|
PS_VDGDC .TEXT "GDC$"
|
|
PS_VDTMS .TEXT "TMS$"
|
|
PS_VDVGA .TEXT "VGA$"
|
|
;
|
|
; VIDEO TYPE STRINGS
|
|
;
|
|
PS_VTCRT .TEXT "CRT$"
|
|
;
|
|
; SOUND DEVICE STRINGS
|
|
;
|
|
PS_SDSND .TEXT "SND$"
|
|
;
|
|
; SOUND TYPE STRINGS
|
|
;
|
|
PS_SDSN76489 .TEXT "SN76489$"
|
|
PS_SDAY38910 .TEXT "AY-3-8910$"
|
|
PS_SDBITMODE .TEXT "I/O PORT$"
|
|
PS_SDYM2612 .TEXT "YM2612$"
|
|
;
|
|
; 0 1 2 3 4 5 6 7
|
|
; 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
PS_STRHDR .TEXT "Unit Device Type Capacity/Mode\r\n"
|
|
.TEXT "---------- ---------- ---------------- --------------------\r\n$"
|
|
;
|
|
;==================================================================================================
|
|
; 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 ; IIF 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
|
|
;
|
|
;==================================================================================================
|
|
; MISCELLANEOUS UTILITY FUNCTIONS
|
|
;==================================================================================================
|
|
;
|
|
; 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
|
|
;
|
|
; 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
|
|
;
|
|
;==================================================================================================
|
|
; HBIOS GLOBAL DATA
|
|
;==================================================================================================
|
|
;
|
|
IDLECOUNT .DB 0
|
|
;
|
|
HEAPCURB .DW 0 ; MARK HEAP ADDRESS AFTER INITIALIZATION
|
|
;
|
|
HB_TICKS .FILL 4,0 ; 32 BIT TICK COUNTER
|
|
HB_SECTCK .DB TICKFREQ ; TICK COUNTER FOR FRACTIONAL SECONDS
|
|
HB_SECS .FILL 4,0 ; 32 BIT SECONDS COUNTER
|
|
;
|
|
HB_CPUTYPE .DB 0 ; 0=Z80, 1=80180, 2=SL1960, 3=ASCI BRG
|
|
HB_CPUOSC .DW CPUOSC ; ACTUAL CPU HARDWARE OSC FREQ IN KHZ
|
|
;
|
|
HB_BATCOND .DB 0 ; BATTERY CONDITION (0=LOW, 1=OK)
|
|
;
|
|
RTCDEFVAL .DB RTCDEF ; STORAGE FOR RTC DEFAULT VALUE
|
|
;
|
|
#IF (BT_REC_TYPE != BT_REC_NONE)
|
|
HB_BOOT_REC .DB 0 ; BOOT MODE (0=NORMAL, 1=RECOVERY MODE)
|
|
#ENDIF
|
|
;
|
|
STR_BANNER .DB "RomWBW HBIOS v", BIOSVER, ", ", TIMESTAMP, "$"
|
|
STR_PLATFORM .DB PLATFORM_NAME, "$"
|
|
STR_SWITCH .DB "*** Activating CRT Console ***$"
|
|
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)? $"
|
|
STR_RESTART .TEXT "\r\n\r\n>>> Press hardware reset button to restart system\r\n\r\n$"
|
|
;
|
|
#IF (DSKYENABLE) ; 'H','B','I','O',' ',' ',' ',' '
|
|
#IF (DSKYMODE == DSKYMODE_V1)
|
|
MSG_HBVER .DB $3E,$7F,$0A,$7B,$00,$00,$00,$00 ; "HBIO "
|
|
#ENDIF
|
|
#IF (DSKYMODE == DSKYMODE_NG)
|
|
MSG_HBVER .DB $76,$7F,$30,$3F,$00,$00,$00,$00 ; "HBIO "
|
|
#ENDIF
|
|
#ENDIF
|
|
;
|
|
HB_APPBNK .DB 0 ; START BANK WHEN RUN IN APP MODE
|
|
;
|
|
HB_CURSEC .DB 0 ; CURRENT SECOND (TEMP)
|
|
;
|
|
HB_BCDTMP .FILL 5,0 ; BCD NUMBER STORAGE (TEMP)
|
|
;
|
|
HB_BOOTCONSAV .DB 0 ; INITIAL BOOT CONSOLE SAVE AREA
|
|
HB_CONCFGSAV .DW 0 ; CONSOLE CONFIG SAVE AREA
|
|
;
|
|
HB_WRKBUF .FILL 512,0 ; INTERNAL DISK BUFFER
|
|
;
|
|
HB_END .EQU $
|
|
;
|
|
SLACK .EQU BNKTOP - $
|
|
.ECHO "HBIOS space remaining: "
|
|
.ECHO SLACK
|
|
.ECHO " bytes.\n"
|
|
|
|
#IF (SLACK<0)
|
|
.ECHO "*** ERROR: HBIOS too big.\n"
|
|
!!! ; FORCE AN ASSEMBLY ERROR
|
|
#ENDIF
|
|
;
|
|
#IF (CCP_SIZ > SLACK)
|
|
.ECHO "*** ERROR: Insufficient space for CCP cache.\n"
|
|
!!! ; FORCE AN ASSEMBLY ERROR
|
|
#ENDIF
|
|
;
|
|
#IFDEF ROMBOOT
|
|
#IF (ROMSIZE > 0)
|
|
.FILL SLACK
|
|
#ENDIF
|
|
#ENDIF
|
|
;
|
|
.END
|