You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2543 lines
63 KiB

;
;==================================================================================================
; HDIAG
;==================================================================================================
;
; THIS FILE CONTAINS A FRAMEWORK FOR A DIAGNOTIC ENVIRONMENT. IT IS ESSENTIALLY A STRIPPED DOWN
; VERSION OF HBIOS. IT DOES NO BANK SWITCHING, BUT THE INTERRUPT MANAGEMENT FRAMEWORK IS
; RETAINED. UPON STARTUP, IT RELOCATES TO UPPER (COMMON) RAM AS QUICKLY AS POSSIBLE.
;
; THERE IS NO HBIOS API. MINIMAL SERIAL PORT ACCESS IS PROVIDED BY INCLUDING THE PLATFORM
; APPROPRIATE MIN_XXX.ASM SERIAL DRIVER. SERIAL PORT SPEEDS ARE FIXED AND THERE IS NO
; FLOW CONTROL. NONE OF THE TYPICAL DRIVER MODULES (CHARACTER, DISK, VIDEO, ETC.) ARE INCLUDED
; AND THERE IS NO DISPATCHING MECHANISM.
;
; IN ORDER TO BUILD PLATFORM APPROPRIATE VERSIONS, THE FULL HBIOS INCLUDE FILE STRUCTURE
; IS USED SO THAT ALL OF THE HBIOS CONFIG SETTINGS CAN BE USED.
;
; THIS FILE CAN BE COMPILED TO BOOT IN ONE OF 2 MODES (ROM OR APPLICATION) 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.
;
; - 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.
;
; INCLUDE FILE NESTING:
;
; hdiag.asm
; - std.asm
; - ver.inc
; - hbios.inc
; - build.inc
; - config/<plt>_<cfg>.asm
; - cfg_<plt>.asm
; - util.asm
; - min_[uart|asci|sio|acia].asm
; - dsky.asm ???
; - diagnostic modules...
;
; INCLUDE GENERIC STUFF
;
#INCLUDE "std.asm"
;
#DEFINE HDIAG
;
; MAKE SURE EXACTLY ONE OF ROMBOOT, APPBOOT IS DEFINED.
;
MODCNT .EQU 0
#IFDEF ROMBOOT
MODCNT .SET MODCNT + 1
#ENDIF
#IFDEF APPBOOT
MODCNT .SET MODCNT + 1
#ENDIF
#IF (MODCNT != 1)
.ECHO "*** ERROR: PLEASE DEFINE ONE AND ONLY ONE OF ROMBOOT, APPBOOT!!!\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
;
#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
;
;
;
#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 .DB $ED,$7F,$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
;
;
;
#IF (CTCENABLE)
CTCA .EQU CTCBASE + 0 ; CTC: CHANNEL A REGISTER ADR
CTCB .EQU CTCBASE + 1 ; CTC: CHANNEL B REGISTER ADR
CTCC .EQU CTCBASE + 2 ; CTC: CHANNEL C REGISTER ADR
CTCD .EQU CTCBASE + 3 ; CTC: CHANNEL D REGISTER ADR
#ENDIF
;
; THIS EQUATE IS UPDATED BY DRIVER INCLUDES THAT SHARE THE RTC LATCH.
; AS DRIVER IS INCLUDED, IT WILL USE .SET TO SET ANY BITS THEY OWN
; AND WANT TO SET AS DEFAULT.
;
RTCDEF .EQU 0 ; ALLOWS DRIVERS TO SET BITS
;
#IF (PLATFORM == PLT_SCZ180)
RTCDEF .SET RTCDEF | %00000001 ; SC128 I2C SCL BIT
#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
.DW ROM_SIG
.FILL (008H - $),0FFH ; RST 8
RET
.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
;
;
;
.ORG $100
JP HB_START
;
;==================================================================================================
; 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
HBX_IMG .SET $
.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
;;;;
;;; .DB $ED,$71 ; SC
;;; .DW HB_DISPATCH ; SC PARAMETER
;;;;
;;; 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:
RES 7,A ; CLEAR BIT 7 FROM ABOVE
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:
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
.DB $ED,$71 ; SC
.DW Z280_BNKSEL ; SC PARAMETER
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,$10 ; ADD 16 x 32K - RAM STARTS FROM 512K
;
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
#IF (RAMSIZE == 256)
XOR %00000100 ; TOP 32K IS ALWAYS IN FIRST CHIP
#ENDIF
#IF (RAMSIZE == 1024)
XOR %00010000 ; TOP 32K IS ALWAYS IN FIRST CHIP
#ENDIF
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
;
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; 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)
.DB $ED,$71 ; SC
.DW Z280_BNKCPY ; SC PARAMETER
RET
#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
.DB $ED,$71 ; SC
.DW HBX_BNKCALL2 ; CALL HERE IN SYSTEM MODE
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 RTCDEF ; SHADOW VALUE FOR RTC LATCH PORT
.DB $FE ; HB_LOCK: HBIOS MUTEX LOCK
JP 0 ; 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
;
;==================================================================================================
; HDIAG CORE
;==================================================================================================
;
;==================================================================================================
; SYSTEM INITIALIZATION
;==================================================================================================
;
HB_START:
#IFDEF APPBOOT
#IF (MEMMGR == MM_Z280)
LD A,%00000001
OUT (DIAGPORT),A
LD DE,Z280_BOOTERR
LD C,9
LD A,%00000010
OUT (DIAGPORT),A
CALL $0005
LD A,%00001000
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 (DIAGENABLE)
LD A,%00000001
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,%00000001 ; LED 0
LD (HB_RTCVAL),A ; SAVE TO SHADOW REGISTER
#ENDIF
OUT (LEDPORT),A
#ENDIF
;
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
.DB $ED,$93 ; 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
.DB $ED,$93 ; 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(%00000010)
; 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))
; 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
;
DIAG(%00000011)
;
; CHECK BATTERY BACKUP STATUS BEFORE WE COPY PROXY TO 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.
; IF THERE IS NO DS1210 IN THE SYSTEM, THE CODE BELOW DOES NO HARM.
;
DEC SP ; RESERVE A STACK BYTE
XOR A ; ZERO MEANS LOW BAT
LD (HBX_LOC - 1),A ; WRITE IT (SHOULD ALWAYS WORK)
INC A ; 1 MEANS BAT OK
LD (HBX_LOC - 1),A ; OVERWRITE IF NVC ALLOWS IT
;
; IF APPBOOT, 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.
;
#IFDEF APPBOOT
LD A,(HB_CURBNK)
DEC SP ; RESERVE A STACK BYTE
LD (HBX_LOC - 2),A ; SAVE BANK
PUSH AF ; ALSO ON STACK
#ENDIF
;
; INSTALL PROXY IN UPPER MEMORY
;
LD DE,HBX_LOC ; AS PER ABOVE
LD HL,HBX_IMG
LD BC,HBX_SIZ
LDIR
;
; IF APPBOOT, RESTORE CURRENT BANK ID
;
#IFDEF APPBOOT
POP AF
LD (HB_CURBNK),A
#ENDIF
;
; TRANSITION TO UPPER (COMMON) RAM
;
LD HL,0 ; FROM START OF CURRENT BANK
LD DE,$8000 ; TO START OF COMMON RAM
LD BC,$8000-$200-1 ; EVERYTHING BUT THE PROXY AND BATCOND
LDIR
JP HB_START1
;
; EXECUTION RESUMES HERE AFTER SWITCH TO RAM BANK
;
.ORG $8000 + $
;
HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK
;
DIAG(%00000111)
LED(%00000010)
;
LD A,(HBX_LOC - 1) ; RECALL BATTERY STATE AND SAVE
LD (HB_BATCOND),A ; FOR FUTURE REFERENCE
;
LD SP,HBX_LOC ; RESET STACK SINCE WE DO NOT RETURN
;
#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
;
; GET AND SAVE APP BOOT BANK ID
LD A,(HBX_LOC - 2)
LD (HB_APPBNK),A
;;;;
;;; ; 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
;
DIAG(%00001111)
;
#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 (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
;
#IF (CPUFAM == CPU_Z180)
;
; AT BOOT, Z180 PHI IS OSC / 2
LD C,(CPUOSC / 2) / 1000000
LD DE,(CPUOSC / 2) / 1000
;
#IF (Z180_CLKDIV >= 1)
LD A,(HB_CPUTYPE) ; GET CPU TYPE
CP 2 ; Z8S180 REV K OR BETTER?
JR C,HB_CPU2 ; IF NOT, NOT POSSIBLE!
; SET CLOCK DIVIDE TO 1 RESULTING IN FULL XTAL SPEED
LD A,$80
OUT0 (Z180_CCR),A
; REFLECT SPEED CHANGE
LD C,CPUOSC / 1000000
LD DE,CPUOSC / 1000
#ENDIF
#IF (Z180_CLKDIV >= 2)
LD A,(HB_CPUTYPE) ; GET CPU TYPE
CP 3 ; Z8S180 REV N OR BETTER?
JR C,HB_CPU2 ; 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
; REFLECT SPEED CHANGE
LD C,(CPUOSC * 2) / 1000000
LD DE,(CPUOSC * 2) / 1000
#ENDIF
;
HB_CPU2:
; SAVE CPU SPEED
LD A,C
LD (CB_CPUMHZ),A
LD (CB_CPUKHZ),DE
;
#ENDIF
;
DIAG(%00011111)
;
LD A,(CPUMHZ) ; CPU SPEED TO ACCUM AND INIT
CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY
;
#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
;
#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 (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
;
#ENDIF
;
#ENDIF
;
DIAG(%00111111)
#IF FALSE
;
; TEST DEBUG ***************************************************************************************
;
CALL NEWLINE
CALL REGDMP
;
; TEST DEBUG ***************************************************************************************
;
#ENDIF
;
#IF (DSKYENABLE)
CALL DSKY_PREINIT
;
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
;
; INITIALIZE SERIAL PORT
CALL CINIT
;
#IF FALSE
;
; TEST DEBUG ***************************************************************************************
;
CALL NEWLINE
CALL REGDMP
;
; TEST DEBUG ***************************************************************************************
;
#ENDIF
;
DIAG(%01111111)
LED(%00000011)
;
#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)
;
DIAG(%11111111)
;
; 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
;
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
CALL PRTSTRD
.TEXT " MMU$"
;
; DISPLAY MEMORY CONFIG
;
CALL NEWLINE
LD HL,ROMSIZE
CALL PRTDEC
CALL PRTSTRD
.TEXT "KB ROM, $"
LD HL,RAMSIZE
CALL PRTDEC
CALL PRTSTRD
.TEXT "KB RAM$"
;
#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
;
; ROM CHECKSUM VERIFICATION
; THE FIRST ROM BANK HAS A CHECKSUM INJECTED SUCH THAT
; A COMPUTED CHECKSUM ACROSS THE ENTIRE BANK SHOLD ALWAYS BE ZERO
;
HB_ROMCK:
CALL NEWLINE
PRTS("ROM VERIFY:$")
;
; TEST FIRST 4 BANKS OF ROM
LD B,1 ; 1 BANK
LD C,0 ; STARTING AT BANK 0
HB_ROMCK1:
PUSH BC ; SAVE LOOP CONTROL
CALL HB_CKBNK ; 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 HL,$7FFF ; START AT BANK END
LD BC,1 ; DECREMENT VALUE
XOR A ; ZERO ACCUM
HB_CKBNK1:
ADD A,(HL) ; ADD NEXT BYTE
OR A ; CLEAR CARRY
SBC HL,BC ; DECREMENT
JR NC,HB_CKBNK1 ; LOOP TILL DONE
HB_EI ; ALLOW INTERRUPTS AGAIN
RET ; AND DONE
;
HB_CKBNKSIZ .EQU $-HB_CKBNK ; SIZE OF ROUTINE
;
HB_ROMCKZ:
;
#ENDIF
;
; LOW BATTERY DIAGNOSTIC MESSAGE
;
#IF (BATCOND)
LD A,(HB_BATCOND)
OR A
LD DE,STR_LOWBAT
CALL Z,WRITESTR
#ENDIF
;
LD DE,STR_SYSHALT
CALL WRITESTR
JR $
DI
HALT
;
;==================================================================================================
; INTERRUPT VECTOR TABLE (MUST START AT PAGE BOUNDARY!!!)
;==================================================================================================
;
.FILL $100 - ($ & $FF)
;
;
; 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
;
#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
;
; 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
;
.DB $ED,$55 ; RETIL
;
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
;
.DB $ED,$96 ; LDUP A,(HL)
;
; 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:
.DB $ED,$96 ; LDUP A,(HL)
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
.DB $ED,$55 ; RETIL
;
HB_MSRSAV .DW 0 ; SAVED MSR
HB_RCSAV .DW 0 ; SAVED REASON CODE
;
Z280_PRIVSTR .TEXT "\r\n\r\n*** Privileged Instruction @$"
;
#ENDIF
;
;==================================================================================================
; 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 (RC2014)
; 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
.DB $ED,$6D ; 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)
;
#IF (MEMMGR == MM_Z280)
;
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 (IOPRVAL),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:
.DB $ED,$B7 ; INW HL,(C)
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,(IOPRVAL) ; 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.
; RC2014 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
.DB $ED,$55 ; RETIL
#ENDIF
;
#DEFINE USEDELAY
#INCLUDE "util.asm"
;
#IF (DSKYENABLE)
#DEFINE DSKY_KBD
#IF (DSKYMODE == DSKYMODE_V1)
#INCLUDE "dsky.asm"
#ENDIF
#IF (DSKYMODE == DSKYMODE_NG)
#INCLUDE "dskyng.asm"
#ENDIF
#ENDIF
;
; 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
;
HB_CPU_STR: .TEXT " Z80$"
.TEXT " Z80180$"
.TEXT " Z8S180-K$"
.TEXT " Z8S180-N$"
.TEXT " Z80280$"
;
;==================================================================================================
; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED)
;==================================================================================================
;
#IF (MINIO == MINIO_UART)
#INCLUDE "min_uart.asm"
#ENDIF
;
#IF (MINIO == MINIO_ASCI)
#INCLUDE "min_asci.asm"
#ENDIF
;
#IF (MINIO == MINIO_ACIA)
#INCLUDE "min_acia.asm"
#ENDIF
;
#IF (MINIO == MINIO_SIO)
#INCLUDE "min_sio.asm"
#ENDIF
;
#IF (MINIO == MINIO_Z2U)
#INCLUDE "min_z2u.asm"
#ENDIF
;
;==================================================================================================
; 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
;
;==================================================================================================
; HBIOS GLOBAL DATA
;==================================================================================================
;
HB_CPUTYPE .DB 0 ; 0=Z80, 1=80180, 2=SL1960, 3=ASCI BRG
;
CB_CPUMHZ .DB CPUMHZ
CB_CPUKHZ .DW CPUKHZ
;
IOPRVAL .DW 0 ; TEMP STORAGE FOR IOPR
;
HB_BATCOND .DB 0 ; BATTERY CONDITION (0=LOW, 1=OK)
;
STR_BANNER .DB "RomWBW HDIAG 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_SYSHALT .TEXT "\r\n\r\n*** SYSTEM HALTED ***$"
;
#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_BCDTMP .FILL 5,0 ; BCD NUMBER STORAGE (TEMP)
;
HB_END .EQU $
;
SLACK .EQU HBX_LOC - $
.ECHO "HDIAG space remaining: "
.ECHO SLACK
.ECHO " bytes.\n"
;
#IFDEF ROMBOOT
.FILL SLACK
#ENDIF
;
.END