Files
RomWBW/Source/HBIOS/hbios.asm
Wayne Warthen b5437c56e9 Suppress Serial HFC During Boot
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.
2023-04-11 13:09:22 -07:00

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