; ;================================================================================================== ; 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/_.asm ; - cfg_.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 (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 .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. ; 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 .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