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.
 
 
 
 
 
 

3131 lines
75 KiB

;
;==================================================================================================
; HBIOS
;==================================================================================================
;
; THIS FILE CONTAINS THE HBIOS IMAGE THAT IS INTENDED TO RUN IN A DEDICATED RAM BANK. THE CODE IS
; CONSTRUCTED SUCH THAT IT CAN BE LAUNCHED IN A VARIETY OF MODES AND INSTALL ITSELF. A SMALL 512
; BYTE PROXY IS PLACED AT THE TOP OF CPU MEMORY (FE00H-FFFFH). THIS PROXY CODE ALLOWS CODE
; RUNNING FROM ANY BANK TO INVOKE HBIOS FUNCTIONS. NORMALLY, ANY BANK THAT RUNS CODE WOULD SETUP
; THE RST 8 VECTOR TO POINT TO THE PROXY INVOKE ENTRY POINT AT FFF0H. CALLS VIA THE PROXY INVOKE
; ENTRY POINT TRANSPARENTLY SWAP IN THE HBIOS BANK, PERFORM THE REQUESTED FUNCTION, AND RETURN
; WITH THE ORIGINAL BANK ACTIVE. THE CODE USING HBIOS FUNCTIONS DOES NOT NEED TO BE AWARE OF
; THE BANK SWITCHING THAT OCCURS.
;
; THIS FILE CAN BE COMPILED TO BOOT IN ONE OF 3 MODES (ROM, APPLICATION, OR IMAGE) AS DESCRIBED
; BELOW. WHEN COMPILED, YOU MUST DEFINE EXACTLY ONE OF THE FOLLOWING MACROS:
;
; - ROMBOOT: BOOT FROM A ROM BANK
;
; WHEN ROMBOOT IS DEFINED, THE FILE IS ASSEMBLED TO BE IMBEDDED AT THE START OF A ROM
; ASSUMING THAT THE CPU WILL START EXECUTION AT ADDRESS 0. AFTER PERFORMING MINIMAL
; SYSTEM INITIALIZATION, THE IMAGE OF THE RUNNING ROM BANK IS COPIED TO A RAM BANK
; CREATING A SHADOW COPY IN RAM. EXECUTION IS THAN TRANSFERRED TO THE RAM SHADOW COPY.
; THIS IS ESSENTIAL BECAUSE THE HBIOS CODE DOES NOT SUPPORT RUNNING IN READ ONLY MEMORY
; (EXCEPT FOR THE INITIAL LAUNCHING CODE). IN THIS MODE, THE HBIOS INITIALIZATION WILL
; ALSO COPY THE OS IMAGES BANK IN ROM TO THE USER RAM BANK AND LAUNCH IT AFTER HBIOS
; IS INSTALLED.
;
; - APPBOOT: BOOT FROM A CP/M STYLE APPLICATION FILE
;
; WHEN APPBOOT IS DEFINED, THE FILE IS ASSEMBLED AS A CP/M APPLICATION ASSUMING
; THAT IT WILL BE LOADED AT 100H BY THE CP/M (OR COMPATIBLE) OS. NOTE THAT IN
; THIS CASE IT IS ASSUMED THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE
; HBIOS APPLICATION BINARY. THE APPENDED OS IMAGES ARE COPIED TO THE USER RAM
; BANK AND LAUNCHED AFTER HBIOS HAS INSTALLED ITSELF.
;
; - IMGBOOT: BOOT FROM AN IMAGE FILE THAT HAS BEEN PLACED IN THE USER BANK
;
; WHEN IMGBOOT IS DEFINED, THE FILE IS ASSEMBLED SUCH THAT IT CAN BE PRELOADED
; INTO THE RAM USER BANK BY AN EXTERNAL PROCESS THAT SUBSEQUENTLY LAUNCHES
; THE CODE AT ADDRESS 0. THE MOST COMMON EXAMPLE OF THIS IS THE UNA FSFAT
; TOOL WHICH CAN LOAD AN IMAGE FROM A DOS FAT FILESYSTEM PROVIDING A SIMPLE
; WAY TO LOAD A TEST COPY OF HBIOS. AS IS THE CASE WITH APPBOOT, IT IS ASSUMED
; THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE IMAGE AND IS LAUNCHED
; AFTER HBIOS IS INSTALLED.
;
; INCLUDE GENERIC STUFF
;
#INCLUDE "std.asm"
;
; MAKE SURE EXACTLY ONE OF ROMBOOT, APPBOOT, IMGBOOT IS DEFINED.
;
MODCNT .EQU 0
#IFDEF ROMBOOT
MODCNT .SET MODCNT + 1
#ENDIF
#IFDEF APPBOOT
MODCNT .SET MODCNT + 1
#ENDIF
#IFDEF IMGBOOT
MODCNT .SET MODCNT + 1
#ENDIF
#IF (MODCNT != 1)
.ECHO "*** ERROR: PLEASE DEFINE ONE AND ONLY ONE OF ROMBOOT, APPBOOT, IMGBOOT!!!\n"
!!! ; FORCE AN ASSEMBLY ERROR
#ENDIF
;
;
;
#IF (INTTYPE != IT_NONE)
#DEFINE HB_EI EI
#DEFINE HB_DI DI
#ELSE
#DEFINE HB_EI ;
#DEFINE HB_DI ;
#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
JP HB_INVOKE ; INVOKE HBIOS FUNCTION
.FILL (010H - $),0FFH ; RST 10
RET
.FILL (018H - $),0FFH ; RST 18
RET
.FILL (020H - $),0FFH ; RST 20
RET
.FILL (028H - $),0FFH ; RST 28
RET
.FILL (030H - $),0FFH ; RST 30
RET
.FILL (038H - $),0FFH ; RST 38 / IM1 INT
RETI
.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) 2015, Wayne Warthen, GNU GPL v3", 0
;
.FILL ($100 - $),$FF ; PAD REMAINDER OF PAGE ZERO
;
#ENDIF
;
;==================================================================================================
; HBIOS CONFIGURATION BLOCK (HCB)
;==================================================================================================
;
.ORG HCB_LOC
HCB:
JP HB_START
;
CB_MARKER .DB 'W',~'W' ; MARKER
CB_VERSION .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO
.DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO
;
CB_PLATFORM .DB PLATFORM
CB_CPUMHZ .DB CPUMHZ
CB_CPUKHZ .DW CPUKHZ
CB_RAMBANKS .DB RAMSIZE / 32
CB_ROMBANKS .DB ROMSIZE / 32
;
CB_BOOTVOL .DW 0 ; BOOT VOLUME IS UNIT/SLICE, SET BY LOADER
CB_BOOTBID .DB 0 ; BOOT BANK ID, SET BY LOADER
CB_SERDEV .DB 0 ; PRIMARY SERIAL UNIT IS UNIT #0 BY FIAT
CB_CRTDEV .DB $FF ; PRIMARY CRT UNIT, $FF UNTIL AFTER HBIOS INIT
CB_CONDEV .DB $FF ; CONSOLE UNIT, $FF UNTIL AFTER HBIOS INIT
;
;CB_CUREMU .DB VDAEMU ; CURRENT VDA TERMINAL EMULATION (DEPRECATED)
;CB_CURVDA .DB VDADEV ; CURRENT VDA TARGET FOR EMULATION (DEPRECATED)
;
; MEMORY MANAGEMENT VARIABLES START AT $20
;
.FILL (HCB + $20 - $),0
;
CB_HEAP .DW 0
CB_HEAPTOP .DW 0
;
; STANDARD BANK ID'S START AT $D8
;
.FILL (HCB + $D8 - $),0
;
CB_BIDCOM .DB BID_COM
CB_BIDUSR .DB BID_USR
CB_BIDBIOS .DB BID_BIOS
CB_BIDAUX .DB BID_AUX
CB_BIDRAMD0 .DB BID_RAMD0
CB_BIDRAMDN .DB BID_RAMDN
CB_BIDROMD0 .DB BID_ROMD0
CB_BIDROMDN .DB BID_ROMDN
;
.FILL (HCB + HCB_SIZ - $),0 ; PAD REMAINDER OF HCB
;
;==================================================================================================
; HBIOS UPPER MEMORY PROXY (RELOCATED TO RUN IN TOP 2 PAGES OF CPU RAM)
;==================================================================================================
;
; THE FOLLOWING CODE IS RELOCATED TO THE TOP OF MEMORY TO HANDLE INVOCATION DISPATCHING
;
.FILL (HBX_IMG - $) ; FILL TO START OF PROXY IMAGE START
.ORG HBX_LOC ; ADJUST FOR RELOCATION
;
; MEMORY LAYOUT:
;
; HBIOS PROXY CODE $FE00 (256 BYTES)
; INTERRUPT VECTORS $FF00 (32 BYTES, 16 ENTRIES)
; INTERRUPT HANDLER STUBS $FF20 (128 BYTES)
; HBIOS PROXY COPY BUFFER $FF80 (64 BYTES)
; HBIOS PROXY MGMT BLOCK $FFE0 (32 BYTES)
;
; DEFINITIONS
;
HBX_BUFSIZ .EQU $40 ; INTERBANK COPY BUFFER
;
; 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
;==================================================================================================
;
HBX_INVOKE:
LD (HBX_INVSP),SP ; SAVE ORIGINAL STACK FRAME
LD A,(HB_CURBNK) ; GET CURRENT BANK
LD (HB_INVBNK),A ; SAVE INVOCATION BANK
; HB_DI
LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM FOR BANK SWITCH
LD A,BID_BIOS ; HBIOS BANK
CALL HBX_BNKSEL ; SELECT IT
LD SP,HB_STACK ; NOW USE FULL HBIOS STACK IN HBIOS BANK
; HB_EI
CALL HB_DISPATCH ; CALL HBIOS FUNCTION DISPATCHER
; HB_DI
LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM FOR BANK SWITCH
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
; HB_EI
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 ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA))
OUT (MPCL_ROM),A ; SET ROM PAGE SELECTOR
OUT (MPCL_RAM),A ; SET RAM PAGE SELECTOR
RET ; DONE
#ENDIF
#IF ((PLATFORM == PLT_ZETA2) | (PLATFORM == PLT_RC))
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
RET ; DONE
#ENDIF
#IF (PLATFORM == PLT_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 (PLATFORM == PLT_MK4)
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
;
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; Copy Data - Possibly between banks. This resembles CP/M 3, but
; usage of the HL and DE registers is reversed.
; Caller MUST ensure stack is already in high memory.
; Caller MUST preset HBX_SRCBNK and HBX_DSTBNK.
; Enter:
; HL = Source Address
; DE = Destination Address
; BC = Number of bytes to copy
; Exit : None
; Uses : AF,BC,DE,HL
;
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
HBX_BNKCPY:
#IF (INTTYPE == IT_SIMH)
HB_DI
#ENDIF
LD (HBX_BC_SP),SP
LD SP,HBX_TMPSTK
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, BUT ONLY IF NOT ZERO BYTES
POP AF ; RECOVER ORIGINAL BANK
CALL HBX_BNKSEL ; SWITCH TO CURRENT BANK AND EXIT
LD SP,$FFFF
HBX_BC_SP .EQU $ - 2
#IF (INTTYPE == IT_SIMH)
HB_EI
#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 = UPD SRC, DE = UPD DEST, BC = 0
RET
;
; CALL A ROUTINE IN ANOTHER BANK.
; CALLER MUST ENSURE STACK IS ALREADY IN HIGH MEMORY AND HAS ADEQUATE SPACE.
; ON INPUT A=TARGET BANK, HL=TARGET ADDRESS
;
HBX_BNKCALL:
LD (HBX_TGTBNK),A ; STUFF TARGET BANK TO CALL INTO CODE BELOW
LD (HBX_TGTADR),HL ; STUFF ADDRESS TO CALL INTO CODE BELOW
LD A,(HB_CURBNK) ; GET CURRENT BANK
PUSH AF ; SAVE FOR RETURN
HBX_TGTBNK .EQU $ + 1
LD A,$FF ; LOAD BANK TO CALL ($FF OVERLAID AT ENTRY)
CALL HBX_BNKSEL ; ACTIVATE THE NEW BANK
HBX_TGTADR .EQU $ + 1
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
;
HBX_PEEK:
#IF (INTTYPE == IT_SIMH)
HB_DI
#ENDIF
LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME
LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM
LD A,(HB_CURBNK)
PUSH AF
LD A,D
CALL HBX_BNKSEL
LD E,(HL)
JR HBX_PPRET
;
HBX_POKE:
#IF (INTTYPE == IT_SIMH)
HB_DI
#ENDIF
LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME
LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM
LD A,(HB_CURBNK)
PUSH AF
LD A,D
CALL HBX_BNKSEL
LD (HL),E
;
HBX_PPRET:
POP AF
CALL HBX_BNKSEL
LD SP,0 ; RESTORE ORIGINAL STACK FRAME
HBX_PPSP .EQU $ - 2
#IF (INTTYPE == IT_SIMH)
HB_EI
#ENDIF
RET
;
; SMALL TEMPORARY STACK FOR USE BY HB_INVOKE
;
.FILL 20,$CC ; 10 LEVEL STACK
HBX_TMPSTK .EQU $
;
; PRIVATE STACK AT END OF HBIOS CODE
; OCCUPIES SPACE BEFORE IVT
;
HBX_STKSIZ .EQU $FF00 - $
.ECHO "HBIOS PROXY STACK space: "
.ECHO HBX_STKSIZ
.ECHO " bytes.\n"
.FILL HBX_STKSIZ,$FF
HBX_STACK .EQU $
;
; HBIOS INTERRUPT VECTOR TABLE (16 ENTRIES)
;
HBX_IVT:
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
.DW INT_BAD
;
; INTERRUPT HANDLER STUBS
;
; THE FOLLOWING INTERRUPT STUBS RECEIVE CONTROL FROM THE
; INTERRUPT, SETUP A HANDLER VECTOR IN HBIOS AND THEN
; BRANCH TO THE COMMON INTERRUPT DISPATCHER
;
INT_TIMER: ; TIMER INTERRUPT HANDLER
PUSH HL ; SAVE HL
LD HL,HB_TIMINT ; HL := INT ADR IN BIOS
JR HBX_INT ; GO TO ROUTING CODE
;
INT_BAD: ; BAD INTERRUPT HANDLER
PUSH HL ; SAVE HL
LD HL,HB_BADINT ; HL := INT HANDLER IN BIOS BANK
JR HBX_INT ; TO TO ROUTING CODE
;
#IF (SIOENABLE)
INT_SIO: ; SIO DEVICE INTERRUPT HANDLER
;PUSH AF
;IN A,(SIOA_DAT)
;LD A,'='
;OUT (SIOA_DAT),A
;POP AF
;EI
;RETI
PUSH HL ; SAVE HL
LD HL,SIO_INT ; HL := SIO INT HANDLER IN BIOS BANK
JR HBX_INT ; TO TO ROUTING CODE
#ENDIF
;
; COMMON INTERRUPT DISPATCHING CODE
; SETUP AND CALL HANDLER IN BIOS BANK
;
HBX_INT: ; COMMON INTERRUPT ROUTING CODE
;
LD (HBX_INT_SP),SP ; SAVE ORIGINAL STACK FRAME
LD SP,HBX_STACK ; USE STACK FRAME IN HI MEM
; SAVE STATE (HL SAVED PREVIOUSLY)
PUSH AF ; SAVE AF
PUSH BC ; SAVE BC
PUSH DE ; SAVE DE
LD A,BID_BIOS ; HBIOS BANK
CALL HBX_BNKSEL_INT ; SELECT IT
CALL JPHL ; CALL INTERRUPT ROUTINE
LD A,(HB_CURBNK) ; GET PRE-INT BANK
CALL HBX_BNKSEL ; SELECT IT
; RESTORE STATE
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
EI ; ENABLE INTERRUPTS
RETI ; AND RETURN
;
; FILL TO START OF BOUNCE BUFFER
;
HBX_INTFILL .EQU (HBX_XFC - HBX_BUFSIZ - $)
.ECHO "HBIOS INT space remaining: "
.ECHO HBX_INTFILL
.ECHO " bytes.\n"
.FILL HBX_INTFILL,$FF
;
; INTERBANK COPY BUFFER (64 BYTES)
;
HBX_BUF .FILL HBX_BUFSIZ,0
;
; HBIOS PROXY MGMT BLOCK (TOP 32 BYTES)
;
#IFDEF ROMBOOT
.DB BID_BOOT ; CURRENTLY ACTIVE LOW MEMORY BANK ID
#ELSE
.DB BID_USR ; CURRENTLY ACTIVE LOW MEMORY BANK ID
#ENDIF
.DB 0 ; BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION
.DW 0 ; BNKCPY SOURCE ADDRESS
.DB BID_USR ; BNKCPY SOURCE BANK ID
.DW 0 ; BNKCPY DESTINATION ADDRESS
.DB BID_USR ; BNKCPY DESTINATION BANK ID
.DW 0 ; BNKCPY LENGTH
.FILL 6,0 ; FILLER, RESERVED FOR FUTURE HBIOS USE
JP HBX_INVOKE ; FIXED ADR ENTRY FOR HBX_INVOKE (ALT FOR RST 08)
JP HBX_BNKSEL ; FIXED ADR ENTRY FOR HBX_BNKSEL
JP HBX_BNKCPY ; FIXED ADR ENTRY FOR HBX_BNKCPY
JP HBX_BNKCALL ; FIXED ADR ENTRY FOR HBX_BNKCALL
.DW HBX_IDENT ; ADDRESS OF HBIOS PROXY START (DEPRECATED)
.DW HBX_IDENT ; ADDRESS OF HBIOS IDENT INFO DATA BLOCK
;
.FILL $MEMTOP - $ ; FILL TO END OF MEMORY (AS NEEDED)
.ORG HBX_IMG + HBX_SIZ ; RESET ORG
;
;==================================================================================================
; HBIOS CORE
;==================================================================================================
;
;==================================================================================================
; ENTRY VECTORS (JUMP TABLE) AND INTERNAL PROCESSING STACK
;==================================================================================================
;
HB_ENTRYTBL .EQU $
;
JP HB_START ; HBIOS INITIALIZATION
JP HB_DISPATCH ; VECTOR TO DISPATCHER
;
HB_STKSIZ .EQU HB_ENTRYTBL + 256 - $
;
.FILL HB_STKSIZ,$FF ; USE REMAINDER OF PAGE FOR HBIOS STACK
HB_STACK .EQU $ ; TOP OF HBIOS STACK
;
;==================================================================================================
; SYSTEM INITIALIZATION
;==================================================================================================
;
HB_START:
DI ; NO INTERRUPTS
IM 1 ; INTERRUPT MODE 1
LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY
;
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4))
; SET BASE FOR CPU IO REGISTERS
LD A,Z180_BASE
OUT0 (Z180_ICR),A
; DISABLE REFRESH
XOR A
OUT0 (Z180_RCR),A
; MASK OFF TIMER INTERRUPTS
XOR A
OUT0 (Z180_TCR),A
; SET DEFAULT CPU CLOCK MULTIPLIERS (XTAL / 2)
XOR A
OUT0 (Z180_CCR),A
OUT0 (Z180_CMR),A
; SET DEFAULT WAIT STATES
LD A,$F0
OUT0 (Z180_DCNTL),A
; 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
#IF (Z180_CLKDIV >= 1)
; SET CLOCK DIVIDE TO 1 RESULTING IN FULL XTAL SPEED
LD A,$80
OUT0 (Z180_CCR),A
#ENDIF
#IF (Z180_CLKDIV >= 2)
; SET CPU MULTIPLIER TO 1 RESULTING IN XTAL * 2 SPEED
LD A,$80
OUT0 (Z180_CMR),A
#ENDIF
#ENDIF
;
#IF ((PLATFORM == PLT_ZETA2) | (PLATFORM == PLT_RC))
; 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
;
; INSTALL PROXY IN UPPER MEMORY
;
LD HL,HBX_IMG
LD DE,HBX_LOC
LD BC,HBX_SIZ
LDIR
;
; IF ALREADY EXECUTING IN RAM, BYPASS RAM BANK INSTALLATION
;
LD A,(HB_RAMFLAG)
OR A
JR NZ,HB_START1
;
; INSTALL HBIOS IN RAM BANK
;
LD A,(HB_CURBNK)
LD (HB_SRCBNK),A
LD A,BID_BIOS
LD (HB_DSTBNK),A
LD HL,0
LD DE,0
LD BC,$8000
CALL HBX_BNKCPY
;
; INTERRUPTS ARE ENABLED BY BNKCPY!!!
DI ; RE-DISABLE INTERRUPTS
;
; TRANSITION TO HBIOS IN RAM BANK
;
LD A,BID_BIOS ; BIOS BANK ID
LD HL,HB_START1 ; EXECUTION RESUMES HERE
CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN
HALT ; WE SHOULD NOT COME BACK HERE!
;
HB_RAMFLAG .DB FALSE ; ASSUME FALSE, SET TO TRUE BELOW AFTER RAM TRANSITION
;
; EXECUTION RESUMES HERE AFTER SWITCH TO RAM BANK
;
HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK
;
; INTERRUPTS ARE ENABLED BY BNKCALL!!!
DI ; RE-DISABLE INTERRUTPS
;
LD SP,HBX_LOC ; RESET STACK SINCE WE DO NOT RETURN
LD A,TRUE ; ACCUM := TRUE
LD (HB_RAMFLAG),A ; SET RAMFLAG
;
; PERFORM DYNAMIC CPU SPEED DERIVATION
;
CALL HB_CPUSPD ; CPU SPEED DETECTION
;
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4))
;
; SET DESIRED WAIT STATES
LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4)
OUT0 (Z180_DCNTL),A
;
#ENDIF
;
CALL DELAY_INIT ; INITIALIZE SPEED COMPENSATED DELAY FUNCTIONS
;
; INITIALIZE HEAP STORAGE
;
; INITIALIZE POINTERS
LD HL,HB_END ; HEAP FOLLOWS HBIOS CODE
LD (CB_HEAP),HL ; INIT HEAP BASE ADDRESS
LD (CB_HEAPTOP),HL ; INIT HEAP TOP ADDRESS
; CLEAR HEAP
LD BC,BNKTOP - HB_END ; MAX SIZE OF HEAP
LD A,$FF ; FILL WITH $FF
CALL FILL ; DO IT
;
; PRE-CONSOLE INITIALIZATION
;
#IF (ASCIENABLE)
CALL ASCI_PREINIT
#ENDIF
#IF (UARTENABLE)
CALL UART_PREINIT
#ENDIF
#IF (SIOENABLE)
CALL SIO_PREINIT
#ENDIF
;
; PRIOR TO THIS POINT, CONSOLE I/O WAS DIRECTED TO HARDWARE (XIO.ASM).
; NOW THAT HBIOS IS READY, SET THE CONSOLE UNIT TO ACTIVATE CONSOLE I/O
; VIA HBIOS.
;
XOR A ; CONSOLE DEVICE IS UNIT #0 BY FIAT
LD (CB_CONDEV),A ; SAVE IT, ACTIVATES CONSOLE ON HBIOS
;
; ANNOUNCE HBIOS
;
CALL NEWLINE2
PRTX(STR_BANNER)
;
; WE CAN HANDLE INTERRUPTS NOW (HOPEFULLY)
;
HB_DI ; START OF CRITICAL SECTION
#IF (INTTYPE != IT_NONE)
;
#IF (INTTYPE == IT_SIMH)
;
; SETUP TIMER INT VECTOR VIA INT MODE 1 IN PAGE ZERO
LD A,$C3 ; JP OPCODE
;LD ($38),A ; ... AT INT VECTOR ADDRESS
LD ($30),A ; ... AT INT VECTOR ADDRESS
LD HL,INT_TIMER ; ADDRESS OF TIMER INT HANDLER
;LD ($39),HL ; ... IS TARGET OF JP
LD ($31),HL ; ... IS TARGET OF JP
LD HL,INT_TIMER
LD (HBX_IVT),HL
;
#ENDIF
;
#IF (INTTYPE == IT_Z180)
;
; SETUP Z180 IVT
LD A,HBX_IVT >> 8 ; SETUP HI BYTE OF IVT ADDRESS
LD I,A ; ... AND PLACE IT IN I REGISTER
XOR A ; SETUP LO BYTE OF IVT ADDRESS
OUT0 (Z180_IL),A ; ... AND PLACE IN Z180 IL REGISTER
;
IM 2 ; SWITCH TO INT MODE 2
;
; MASK ALL EXTERNAL INTERRUPTS FOR NOW
XOR A ; INT0-2 DISABLED
OUT0 (Z180_ITC),A ; WRITE TO INT/TRAP CONTROL REGISTER
;
; SETUP Z180 TIMER0 INTERRUPT VECTOR IN IVT
LD HL,INT_TIMER
LD (HBX_IVT + Z180_IVTIM0),HL
; SETUP PERIODIC TIMER INTERRUPT ON TIMER 0
LD HL,(CB_CPUKHZ) ; 50HZ = 18432000 / 20 / 50 / X, SO X = CPU KHZ
LD B,0
LD C,Z180_RLDR0L ; INITIALIZE TIMER 0 RELOAD REGISTER
OUT (C),L
INC C
OUT (C),H
LD C,Z180_TMDR0L ; INITIALIZE TIMER 0 DATA REGISTER
OUT (C),L
INC C
OUT (C),H
LD A,%00010001 ; ENABLE TIMER0 INT AND DOWN COUNTING
OUT0 (Z180_TCR),A
;
#ENDIF
;
#IF (INTTYPE == IT_RC)
;
; SETUP Z80 IVT
LD A,HBX_IVT >> 8 ; SETUP HI BYTE OF IVT ADDRESS
LD I,A ; ... AND PLACE IT IN I REGISTER
;
IM 2 ; SWITCH TO INT MODE 2
;
#IF (SIOENABLE)
; SETUP SIO INTERRUPT VECTOR IN IVT
LD HL,INT_SIO
LD (HBX_IVT + 4),HL
#ENDIF
;
; IM 1
;
;#IF (SIOENABLE)
;;
; ; SETUP SIO INT VECTOR VIA INT MODE 1 IN PAGE ZERO
; ;LD A,$C3 ; JP OPCODE
; ;LD ($38),A ; ... AT INT VECTOR ADDRESS
; ;LD HL,INT_SIO ; ADDRESS OF SIO INT HANDLER
; ;LD ($39),HL ; ... IS TARGET OF JP
;;
;#ENDIF
;
#ENDIF
;
#ENDIF
HB_EI ; END OF CRITICAL SECTION
;
; DISPLAY PLATFORM INFORMATION
;
CALL NEWLINE2
PRTX(STR_PLATFORM)
PRTS(" @ $")
LD HL,(CB_CPUKHZ)
CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA
PRTS("MHz$")
;
; DISPLAY CPU CONFIG
;
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4))
;
CALL PRTSTRD
.TEXT ", $"
LD A,Z180_MEMWAIT
CALL PRTDECB
CALL PRTSTRD
.TEXT " MEM W/S, $"
LD A,Z180_IOWAIT
CALL PRTDECB
CALL PRTSTRD
.TEXT " I/O W/S$"
;
#ENDIF
;
; DISPLAY MEMORY CONFIG
;
CALL NEWLINE
CALL PRTSTRD
.TEXT "MEMORY LAYOUT $"
LD HL,ROMSIZE
CALL PRTDEC
CALL PRTSTRD
.TEXT "KB ROM, $"
LD HL,RAMSIZE
CALL PRTDEC
CALL PRTSTRD
.TEXT "KB RAM$"
;
; PERFORM DEVICE INITIALIZATION
;
CALL NEWLINE
LD B,HB_INITTBLLEN
LD DE,HB_INITTBL
INITSYS1:
LD A,(DE)
LD L,A
INC DE
LD A,(DE)
LD H,A
INC DE
PUSH DE
PUSH BC
CALL JPHL
POP BC
POP DE
DJNZ INITSYS1
;
; RECORD HEAP CURB AT THE CURRENT VALUE OF HEAP TOP. HEAP CURB
; MARKS THE POINT IN THE HEAP AFTER WHICH MEMORY IS RELEASED
; WHEN AN HBIOS RESET IS PEFORMED.
;
LD HL,(CB_HEAPTOP)
LD (HEAPCURB),HL
;
; NOW SWITCH TO CRT CONSOLE IF CONFIGURED
;
#IF CRTACT
;
; BIOS IS CONFIGURED TO AUTO ACTIVATE CRT DEVICE. FIRST,
; CHECK TO SEE IF WE HAVE A VALID CRT DEVICE TO USE.
;
LD A,(CB_CRTDEV) ; GET THE CRT DEVICE
INC A ; INCREMENT TO TEST FOR $FF
JR Z,INITSYS3 ; IF NO CRT DEVICE, BYPASS CONSOLE SWITCH
;
; IF PLATFORM HAS A CONFIG JUMPER, CHECK TO SEE IF IT IS JUMPERED.
; IF SO, BYPASS SWITCH TO CRT CONSOLE (FAILSAFE MODE)
;
#IF ((PLATFORM != PLT_N8) & (PLATFORM != PLT_MK4))
IN A,(RTC) ; RTC PORT, BIT 6 HAS STATE OF CONFIG JUMPER
BIT 6,A ; BIT 6 HAS CONFIG JUMPER STATE
JR Z,INITSYS3 ; Z=SHORTED, BYPASS CONSOLE SWITCH
#ENDIF
;
; NOTIFY USER OF CONSOLE SWITCH ON BOOT CONSOLE
CALL NEWLINE2
PRTX(STR_SWITCH)
CALL NEWLINE
;
; SWITCH TO CRT CONSOLE
LD A,(CB_CRTDEV) ; GET CRT DISPLAY DEVICE
LD (CB_CONDEV),A ; SAVE IT AS ACTIVE CONSOLE DEVICE
;
; DISPLAY HBIOS BANNER ON NEW CONSOLE
PRTX(STR_BANNER)
#ENDIF
;
INITSYS3:
;
CALL PRTSUM ; PRINT UNIT/DEVICE SUMMARY TABLE
;
;
;
; CALL TSTPT
; LD HL,($FF00 + 2)
; CALL JPHL
; CALL TSTPT
;
; CHAIN TO OS LOADER
;
#IFDEF ROMBOOT
; PERFORM BANK CALL TO OS IMAGES BANK
LD A,BID_OSIMG ; CHAIN TO OS IMAGES BANK
LD HL,0 ; ENTER AT ADDRESS 0
CALL HBX_BNKCALL ; GO THERE
HALT ; WE SHOULD NEVER COME BACK!
#ELSE
; COPY OS IMAGE: BID_USR:<IMG START> --> BID_USR:0
LD A,BID_USR
LD (HB_SRCBNK),A
LD (HB_DSTBNK),A
LD HL,HB_END
LD DE,0
LD BC,$8000
CALL HBX_BNKCPY
;
; PERFORM BANK CALL TO OS IMAGES BANK
LD A,BID_USR ; CHAIN TO OS IMAGES BANK
LD HL,0 ; ENTER AT ADDRESS 0
CALL HBX_BNKCALL ; GO THERE
HALT ; WE SHOULD NEVER COME BACK!
; ; SLIDE OS IMAGES BLOB DOWN TO $0000
; LD HL,LDR_END ; SOURCE IS LOADER END
; LD BC,HB_END ; PLUS HBIOS IMAGE SIZE
; ADD HL,BC ; FINAL SOURCE ADDRESS
; LD DE,0 ; TARGET ADDRESS IS ZERO
; LD BC,BNKTOP ; MAX SIZE OF OS IMAGES
; LDIR ; DO IT
; ; JUMP TO START
; JP 0 ; AND CHAIN
#ENDIF
;
RET
;
;==================================================================================================
; TABLE OF INITIALIZATION ENTRY POINTS
;==================================================================================================
;
HB_INITTBL:
#IF (ASCIENABLE)
.DW ASCI_INIT
#ENDIF
#IF (UARTENABLE)
.DW UART_INIT
#ENDIF
#IF (SIOENABLE)
.DW SIO_INIT
#ENDIF
#IF (SIMRTCENABLE)
.DW SIMRTC_INIT
#ENDIF
#IF (DSRTCENABLE)
.DW DSRTC_INIT
#ENDIF
#IF (VDUENABLE)
.DW VDU_INIT
#ENDIF
#IF (CVDUENABLE)
.DW CVDU_INIT
#ENDIF
#IF (VGAENABLE)
.DW VGA_INIT
#ENDIF
#IF (NECENABLE)
.DW NEC_INIT
#ENDIF
#IF (TMSENABLE)
.DW TMS_INIT
#ENDIF
#IF (DSKYENABLE)
.DW DSKY_INIT
#ENDIF
#IF (MDENABLE)
.DW MD_INIT
#ENDIF
#IF (FDENABLE)
.DW FD_INIT
#ENDIF
#IF (RFENABLE)
.DW RF_INIT
#ENDIF
#IF (IDEENABLE)
.DW IDE_INIT
#ENDIF
#IF (PPIDEENABLE)
.DW PPIDE_INIT
#ENDIF
#IF (SDENABLE)
.DW SD_INIT
#ENDIF
#IF (HDSKENABLE)
.DW HDSK_INIT
#ENDIF
#IF (PRPENABLE)
.DW PRP_INIT
#ENDIF
#IF (PPPENABLE)
.DW PPP_INIT
#ENDIF
;
HB_INITTBLLEN .EQU (($ - HB_INITTBL) / 2)
;
;==================================================================================================
; IDLE
;==================================================================================================
;
;__________________________________________________________________________________________________
;
IDLE:
PUSH AF
PUSH BC
PUSH DE
PUSH HL
#IF (FDENABLE)
CALL FD_IDLE
#ENDIF
POP HL
POP DE
POP BC
POP AF
RET
;
;==================================================================================================
; BIOS FUNCTION DISPATCHER
;==================================================================================================
;
; MAIN BIOS FUNCTION
; B: FUNCTION
;__________________________________________________________________________________________________
;
HB_DISPATCH:
;
#IF 0 ; *DEBUG* START
;
CALL HB_DISPCALL ; DO THE WORK
;
; CHECK STACK INTEGRITY
PUSH AF
LD A,(HB_STACK - HB_STKSIZ + $08)
CP $FF
CALL NZ,PANIC
LD A,$FF
LD (HB_STACK - HB_STKSIZ + $08),A
POP AF
RET
HB_DISPCALL:
;
#ENDIF ; *DEBUG* END
;
LD A,B ; REQUESTED FUNCTION IS IN B
CP BF_CIO + $10 ; $00-$0F: CHARACTER I/O
JP C,CIO_DISPATCH
CP BF_DIO + $10 ; $10-$1F: DISK I/O
JP C,DIO_DISPATCH
CP BF_RTC + $10 ; $20-$2F: REAL TIME CLOCK (RTC)
JP C,RTC_DISPATCH
CP BF_EMU + $10 ; $30-$3F: EMULATION
CALL C,PANIC ; OBSOLETE!
CP BF_VDA + $10 ; $40-$4F: VIDEO DISPLAY ADAPTER
JP C,VDA_DISPATCH
CP BF_SYS ; SKIP TO BF_SYS VALUE AT $F0
CALL C,PANIC ; PANIC IF LESS THAN BF_SYS
JP SYS_DISPATCH ; OTHERWISE SYS CALL
CALL PANIC ; THIS SHOULD NEVER BE REACHED
;
;==================================================================================================
; CHARACTER I/O DEVICE DISPATCHER
;==================================================================================================
;
; ROUTE CALL TO SPECIFIED CHARACTER I/O DRIVER
; B: FUNCTION
; C: UNIT NUMBER
;
CIO_DISPATCH:
;
; ON ENTRY C IS HBIOS UNIT # (INDEX INTO CIO_TBL OF CHARACTER DEVICES)
; USE UNIT # IN C TO LOOKUP CIO_TBL ENTRY, THEN
; CONVERT C TO THE DEVICE/DRIVER SPECIFIC UNIT ID
; AND GET THE DEVICE TYPE TO A FOR DRIVER DISPATCHING
;
PUSH IY ; SAVE INCOMING IY
LD A,C ; INCOMING UNIT INDEX TO A
PUSH HL ; SAVE INCOMING HL
LD HL,CIO_CNT ; HL := ADDRESS OF TABLE ENTRY COUNT PREFIX
CP (HL) ; COMPARE TO INCOMING ENTRY INDEX
JR C,CIO_DISPATCH1 ; UNIT OK, PROCEED
CP CIODEV_CONSOLE ; CHECK FOR SPECIAL VALUE - CONSOLE OUTPUT
JR Z,CIO_DISPATCH_CON ; DO IT
;
; NOT GOOD, INCOMING UNIT IS OUT OF RANGE
POP HL ; RESTORE HL/STACK
CALL PANIC ; PANIC
OR $FF ; SIGNAL ERROR
RET ; AND RETURN
;
CIO_DISPATCH_CON:
LD A,(CB_CONDEV) ; PUT CONSOLE UNIT NUMBER IN A
; FALL THRU
;
CIO_DISPATCH1:
;
; SET HL := TABLE ENTRY ADDRESS
INC HL ; BUMP PAST COUNT PREFIX TO START OF TABLE ENTRIES
RLCA ; MULTIPLY UNIT # BY 4 TO
RLCA ; ... TO CALC ENTRY OFFSET
CALL ADDHLA ; HL := ADDRESS OF ENTRY IN TABLE
;
; GET FIRST WORD OF TABLE ENTRY AND SAVE FOR DRIVER CALL
LD A,(HL) ; DEREFERENCE
INC HL ; ...
PUSH HL ; SAVE IT FOR BELOW
LD H,(HL) ; ...
LD L,A ; ... SO HL HAS ADDRESS OF DRIVER DISPATCH
LD (CIO_TGTADR),HL ; SAVE THE TARGET ADDRESS TO CALL LATER
;
; GET SECOND WORD OF TABLE ENTRY AND PUT IN IY FOR DRIVER CALL
POP HL ; GET TABLE ENTRY ADDRESS BACK
INC HL ; INCREMENT TO DATA WORD
LD A,(HL) ; GET DATA WORD
INC HL ; ...
LD H,(HL) ; ...
LD L,A ; ... INTO HL
PUSH HL ; AND COPY IT
POP IY ; ... TO IY
;
; CALL DRIVER (ADDRESS BYTES OF CALL INSTRUCTION UPDATED ABOVE)
POP HL ; GET ORIGINAL HL BACK (10)
CALL PANIC ; CALL DRIVER DISPATCH ENTRY
CIO_TGTADR .EQU $ - 2 ; REFERENCE TO ADDRESS OF CALL INSTRUCTION
POP IY ; RESTORE ORIGINAL IY
RET ; AND RETURN
;
; HBIOS CHARACTER DEVICE UNIT TABLE
;
; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION.
; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT
; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES.
; EACH ENTRY IS DEFINED AS:
;
; WORD DRIVER DISPATCH ENTRY ADDRESS
; WORD UNIT SPECIFIC DATA (MAY BE AN ADDRESS)
;
CIO_MAX .EQU 16 ; UP TO 16 UNITS
CIO_SIZ .EQU CIO_MAX * 4 ; EACH ENTRY IS 4 BYTES
;
.DB CIO_MAX ; MAX ENTRY COUNT TABLE PREFIX
CIO_CNT .DB 0 ; ENTRY COUNT PREFIX
CIO_TBL .FILL CIO_SIZ,0 ; SPACE FOR ENTRIES
;
; ADD AN ENTRY TO THE CIO UNIT TABLE (SEE HB_ADDENT FOR DETAILS)
;
CIO_ADDENT:
LD HL,CIO_TBL ; POINT TO CIO TABLE
JP HB_ADDENT ; ... AND GO TO COMMON CODE
;
;==================================================================================================
; DISK I/O DEVICE DISPATCHER
;==================================================================================================
;
; ROUTE CALL TO SPECIFIED DISK I/O DRIVER
; B: FUNCTION
; C: UNIT NUMBER
;
;NDIO_NEWDISP:
; ; START OF THE ACTUAL DRIVER DISPATCHING LOGIC
; PUSH IY ; SAVE ORIGINAL IY
; PUSH HL ; SAVE HL
; LD HL,NDIO_RET ; GET RETURN VECTOR
; EX (SP),HL ; RECOVER HL & PUT RETURN VECTOR ON TOS
; PUSH HL ; SAVE HL
; LD HL,DIO_TBL ; POINT TO DISPATCH TABLE
; LD A,C ; GET REQUESTED UNIT FROM C
; RLCA ; MULTIPLY UNIT BY 4
; RLCA ; ... TO GET BYTE OFFSET OF ENTRY
; CALL ADDHLA ; HL -> ENTRY ADDRESS
; LD A,(HL) ; DRIVER ID TO A
; PUSH AF ; SAVE IT FOR NOW
; INC HL ; POINT TO UNIT
; LD C,(HL) ; PUT IT IN C FOR DRIVER
; INC HL ; POINT TO LSB OF UNIT DATA ADDRESS
; LD A,(HL) ; HL := UNIT DATA ADDRESS
; INC HL ; ...
; LD H,(HL) ; ...
; LD L,A ; ...
; POP AF ; RECOVER DRIVER ID
; EX (SP),HL ; RECOVER ORIG HL & PUT UNIT DATA ADDRESS TO TOS
; POP IY ; IY := UNIT DATA ADDRESS
; JP NDIO_DISPATCH2 ; USE LEGACY DISPATCHER
;;
;NDIO_RET:
; POP IY ; RECOVER IY
; OR A ; MAKE SURE FLAGS ARE SET
; RET ; AND RETURN
DIO_DISPATCH:
;
#IF 0 ; *DEBUG* START
;
; DUMP INCOMING CALL
CALL NEWLINE
PRTS("DIO>$")
CALL REGDMP ; DUMP REGS, NONE DESTROYED
;
; DO THE ACTUAL DISPATCH PROCESSING
CALL DIO_DISPCALL
;
; DUMP CALL RESULTS AND RETURN
CALL NEWLINE
PRTS("DIO<$")
CALL REGDMP ; DUMP REGS, NONE DESTROYED
RET
DIO_DISPCALL:
;
#ENDIF ; *DEBUG* END
;
; ON ENTRY C IS HBIOS UNIT # (INDEX INTO DIO_TBL OF DISK DEVICES)
; USE UNIT # IN C TO LOOKUP DIO_TBL ENTRY, THEN
; CONVERT C TO THE DEVICE/DRIVER SPECIFIC UNIT ID
; AND GET THE DEVICE TYPE TO A FOR DRIVER DISPATCHING
;
LD A,C ; INCOMING UNIT INDEX TO A
PUSH HL ; SAVE INCOMING HL
LD HL,DIO_CNT ; HL := ADDRESS OF TABLE ENTRY COUNT
CP (HL) ; COMPARE TO INCOMING ENTRY INDEX
JR C,DIO_DISPATCH1 ; UNIT OK, PROCEED
;
; NOT GOOD, INCOMING UNIT IS OUT OF RANGE
POP HL ; RESTORE HL/STACK
CALL PANIC ; PANIC
OR $FF ; SIGNAL ERROR
RET ; AND RETURN
;
DIO_DISPATCH1:
INC HL ; BUMP PAST COUNT PREFIX TO START OF TABLE
RLCA ; MULTIPLY BY 4 TO
RLCA ; ... TO CALC ENTRY OFFSET
CALL ADDHLA ; HL := ENTRY OFFSET
LD A,(HL) ; GET DEVICE TYPE BYTE
INC HL ; BUMP TO DEVICE UNIT INDEX BYTE
LD C,(HL) ; DEVICE UNIT INDEX TO C
POP HL ; RECOVER INCOMING HL VALUE
;
; DISPATCH TO DRIVER BASED ON DEVICE TYPE IN A
;
#IF (MDENABLE)
CP DIODEV_MD
JP Z,MD_DISPATCH
#ENDIF
#IF (FDENABLE)
CP DIODEV_FD
JP Z,FD_DISPATCH
#ENDIF
#IF (RFENABLE)
CP DIODEV_RF
JP Z,RF_DISPATCH
#ENDIF
#IF (IDEENABLE)
CP DIODEV_IDE
JP Z,IDE_DISPATCH
#ENDIF
#IF (PPIDEENABLE)
CP DIODEV_PPIDE
JP Z,PPIDE_DISPATCH
#ENDIF
#IF (SDENABLE)
CP DIODEV_SD
JP Z,SD_DISPATCH
#ENDIF
#IF (PRPENABLE)
#IF (PRPSDENABLE)
CP DIODEV_PRPSD
JP Z,PRPSD_DISPATCH
#ENDIF
#ENDIF
#IF (PPPENABLE)
#IF (PPPSDENABLE)
CP DIODEV_PPPSD
JP Z,PPPSD_DISPATCH
#ENDIF
#ENDIF
#IF (HDSKENABLE)
CP DIODEV_HDSK
JP Z,HDSK_DISPATCH
#ENDIF
CALL PANIC
RET
;
; CONVERT AN HBIOS STANDARD HARD DISK CHS ADDRESS TO
; AN LBA ADDRESS. A STANDARD HBIOS HARD DISK IS ASSUMED
; TO HAVE 16 SECTORS PER TRACK AND 16 HEADS PER CYLINDER.
;
; INPUT: HL=TRACK, D=HEAD, E=SECTOR
; OUTPUT: DE:HL=32 BIT LBA ADDRESS (D:7 IS NOT SET IN THE RESULT)
;
HB_CHS2LBA:
;
;; DEBUG: DUMP INCOMING TRACK:HEAD/SEC
;CALL NEWLINE
;PUSH BC
;PUSH HL
;POP BC
;CALL PRTHEXWORD
;CALL PC_COLON
;PUSH DE
;POP BC
;CALL PRTHEXWORD
;POP BC
;
; WE HAVE INCOMING HARDDISK CHS, CONVERT TO LBA
; HL=TRACK (0..N), D=HEAD (0..15), E=SECTOR (0..15)
; XLAT HL:DE (TT:HS) --> 32 BIT LBA (LBAHI:LBALO)
;
; D/E -> A (COMBINE HEAD/SEC AND SAVE IN A)
; 0 -> D
; H -> E
; L -> H
; A -> L
;
LD A,D ; HEAD TO A
RLCA ; LEFT SHIFT TO HIGH NIBBLE
RLCA ; ... DEPENDS ON HIGH
RLCA ; ... NIBBLE BEING 0 SINCE
RLCA ; ... IT ROTATES INTO LOW NIBBLE
OR E ; COMBINE WITH SECTOR (HIGH NIBBLE MUST BE ZERO)
LD D,0
LD E,H
LD H,L
LD L,A
;
;; DEBUG: DUMP RESULTING LBA (32 BIT)
;PRTS("-->$")
;PUSH BC
;PUSH DE
;POP BC
;CALL PRTHEXWORD
;PUSH HL
;POP BC
;CALL PRTHEXWORD
;POP BC
;
XOR A
RET
;
; HBIOS DISK DEVICE UNIT TABLE
;
; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION.
; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT
; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES.
; EACH ENTRY IS DEFINED AS:
;
; BYTE DEVICE TYPE ID
; BYTE DEVICE/DRIVER UNIT NUMBER
; WORD UNIT DATA ADDRESS
;
DIO_MAX .EQU 16 ; UP TO 16 UNITS
DIO_SIZ .EQU DIO_MAX * 4 ; EACH ENTRY IS 4 BYTES
;
.DB DIO_MAX ; MAX ENTRY COUNT TABLE PREFIX
DIO_CNT .DB 0 ; ENTRY COUNT PREFIX
DIO_TBL .FILL DIO_SIZ,0 ; SPACE FOR ENTRIES
;
; ADD AN ENTRY TO THE DIO UNIT TABLE
;
DIO_ADDENT:
LD HL,DIO_TBL ; POINT TO DIO TABLE
JP HB_ADDENT ; ... AND GO TO COMMON CODE
;
;==================================================================================================
; REAL TIME CLOCK DEVICE DISPATCHER
;==================================================================================================
;
; ROUTE CALL TO REAL TIME CLOCK DRIVER
; B: FUNCTION
;
RTC_DISPATCH:
#IF (SIMRTCENABLE)
JP SIMRTC_DISPATCH
#ENDIF
#IF (DSRTCENABLE)
JP DSRTC_DISPATCH
#ENDIF
CALL PANIC
;
;==================================================================================================
; VIDEO DISPLAY ADAPTER DEVICE DISPATCHER
;==================================================================================================
;
; ROUTE CALL TO SPECIFIED VDA DEVICE DRIVER
; B: FUNCTION
; C: UNIT NUMBER
;
VDA_DISPATCH:
; LD A,C ; REQUESTED DEVICE/UNIT IS IN C
; AND $F0 ; ISOLATE THE DEVICE PORTION
;
; ON ENTRY C IS HBIOS UNIT # (INDEX INTO VDA_TBL OF VIDEO DEVICES)
; USE UNIT # IN C TO LOOKUP VDA_TBL ENTRY, THEN
; CONVERT C TO THE DEVICE/DRIVER SPECIFIC UNIT ID
; AND GET THE DEVICE TYPE TO A FOR DRIVER DISPATCHING
;
PUSH IY ; SAVE INCOMING IY
LD A,C ; INCOMING UNIT INDEX TO A
PUSH HL ; SAVE INCOMING HL
LD HL,VDA_CNT ; HL := ADDRESS OF TABLE ENTRY COUNT
CP (HL) ; COMPARE TO INCOMING ENTRY INDEX
JR C,VDA_DISPATCH1 ; UNIT OK, PROCEED
;
; NOT GOOD, INCOMING UNIT IS OUT OF RANGE
POP HL ; RESTORE HL/STACK
CALL PANIC ; PANIC
OR $FF ; SIGNAL ERROR
RET ; AND RETURN
;
VDA_DISPATCH1:
;
; SET HL := TABLE ENTRY ADDRESS
INC HL ; BUMP PAST COUNT PREFIX TO START OF TABLE ENTRIES
RLCA ; MULTIPLY UNIT # BY 4 TO
RLCA ; ... TO CALC ENTRY OFFSET
CALL ADDHLA ; HL := ADDRESS OF ENTRY IN TABLE
;
; GET FIRST WORD OF TABLE ENTRY AND SAVE FOR DRIVER CALL
LD A,(HL) ; DEREFERENCE
INC HL ; ...
PUSH HL ; SAVE IT FOR BELOW
LD H,(HL) ; ...
LD L,A ; ... SO HL HAS ADDRESS OF DRIVER DISPATCH
LD (VDA_TGTADR),HL ; SAVE THE TARGET ADDRESS TO CALL LATER
;
; GET SECOND WORD OF TABLE ENTRY AND PUT IN IY FOR DRIVER CALL
POP HL ; GET TABLE ENTRY ADDRESS BACK
INC HL ; INCREMENT TO DATA WORD
LD A,(HL) ; GET DATA WORD
INC HL ; ...
LD H,(HL) ; ...
LD L,A ; ... INTO HL
PUSH HL ; AND COPY IT
POP IY ; ... TO IY
;
; CALL DRIVER (ADDRESS BYTES OF CALL INSTRUCTION UPDATED ABOVE)
POP HL ; GET ORIGINAL HL BACK (10)
CALL PANIC ; CALL DRIVER DISPATCH ENTRY
VDA_TGTADR .EQU $ - 2 ; REFERENCE TO ADDRESS OF CALL INSTRUCTION
POP IY ; RESTORE ORIGINAL IY
RET ; AND RETURN
;
; HBIOS VIDEO DEVICE UNIT TABLE
;
; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION.
; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT
; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES.
; EACH ENTRY IS DEFINED AS:
;
; WORD DRIVER DISPATCH ADDRESS
; WORD UNIT DATA ADDRESS
;
VDA_MAX .EQU 16 ; UP TO 16 UNITS
VDA_SIZ .EQU VDA_MAX * 4 ; EACH ENTRY IS 4 BYTES
;
.DB VDA_MAX ; MAX ENTRY COUNT TABLE PREFIX
VDA_CNT .DB 0 ; ENTRY COUNT PREFIX
VDA_TBL .FILL VDA_SIZ,0 ; SPACE FOR ENTRIES
;
; ADD AN ENTRY TO THE VDA UNIT TABLE (SEE HB_ADDENT FOR DETAILS)
;
VDA_ADDENT:
LD HL,VDA_TBL ; POINT TO VDA TABLE
JP HB_ADDENT ; ... AND GO TO COMMON CODE
;
;==================================================================================================
; SYSTEM FUNCTION DISPATCHER
;==================================================================================================
;
; B: FUNCTION
;
SYS_DISPATCH:
LD A,B ; GET REQUESTED FUNCTION
AND $0F ; ISOLATE SUB-FUNCTION
JP Z,SYS_RESET ; $F0
DEC A
JP Z,SYS_VER ; $F1
DEC A
JP Z,SYS_SETBNK ; $F2
DEC A
JP Z,SYS_GETBNK ; $F3
DEC A
JP Z,SYS_SETCPY ; $F4
DEC A
JP Z,SYS_BNKCPY ; $F5
DEC A
JP Z,SYS_ALLOC ; $F6
DEC A
JP Z,SYS_FREE ; $F7
DEC A
JP Z,SYS_GET ; $F8
DEC A
JP Z,SYS_SET ; $F9
DEC A
JP Z,SYS_PEEK ; $FA
DEC A
JP Z,SYS_POKE ; $FB
CALL PANIC ; INVALID
;
; SET ACTIVE MEMORY BANK AND RETURN PREVIOUSLY ACTIVE MEMORY BANK
; NOTE THAT IT GOES INTO EFFECT AS HBIOS FUNCTION IS EXITED
; HERE, WE JUST SET THE CURRENT BANK
; CALLER MUST EXTABLISH UPPER MEMORY STACK BEFORE INVOKING THIS FUNCTION!
;
SYS_SETBNK:
PUSH HL ; SAVE INCOMING HL
LD HL,HB_INVBNK ; POINT TO HBIOS INVOKE BANK ID ADDRESS
LD A,(HL) ; GET EXISTING BANK ID TO A
LD (HL),C ; UPDATE INVOKE BANK TO NEW BANK ID
LD C,A ; PUT PREVIOUS BANK ID IN C FOR RETURN
POP HL ; RESTORE ORIGINAL HL
XOR A ; SIGNAL SUCCESS
RET ; DONE
;
; GET ACTIVE MEMORY BANK
;
SYS_GETBNK:
LD A,(HB_INVBNK) ; GET THE ACTIVE MEMORY BANK
LD C,A ; MOVE TO C
XOR A ; SIGNAL SUCCESS
RET
;
; SET BANKS AND LENGTH FOR INTERBANK MEMORY COPY (BNKCPY)
; ENTRY: E=SOURCE BANK ID
; D=DEST BANK ID
; HL=COPY LENGTH (IN BYTES)
;
SYS_SETCPY:
LD A,E
LD (HB_SRCBNK),A ; RECORD THE SOURCE BANK
LD A,D
LD (HB_DSTBNK),A ; RECORD THE DESTINATION BANK
LD (HB_CPYLEN),HL ; RECORD THE COPY LENGTH
XOR A
RET
;
; PERFORM MEMORY COPY POTENTIALLY ACROSS BANKS
; ENTRY: HL=SOURCE ADDRESS
; DE=DESTINATION ADDRESS
; NOTE: SRC/DEST BANK & COPY LENGTH MUST BE SET VIA SETCPY
;
SYS_BNKCPY:
PUSH HL ; SAVE INCOMING HL
LD HL,(HB_CPYLEN) ; HL := COPY LEN (SAVED IN SETCPY)
EX (SP),HL ; RESTORE HL & SET (SP) TO COPY LEN
POP BC ; BC := COPY LEN
;; *DEBUG* START
;PUSH AF
;PUSH BC
;PUSH DE
;PUSH HL
;
;CALL NEWLINE
;
;LD A,(HB_SRCBNK)
;CALL PRTHEXBYTE
;CALL PC_COLON
;PUSH BC
;PUSH HL
;POP BC
;CALL PRTHEXWORD
;POP BC
;CALL PC_SPACE
;LD A,(HB_DSTBNK)
;CALL PRTHEXBYTE
;CALL PC_COLON
;PUSH BC
;PUSH DE
;POP BC
;CALL PRTHEXWORD
;POP BC
;CALL PC_SPACE
;CALL PRTHEXWORD
;POP HL
;POP DE
;POP BC
;POP AF
; *DEBUG* END
CALL HB_BNKCPY
XOR A
RET
;
; ALLOCATE HL BYTES OF MEMORY FROM HBIOS HEAP
; RETURNS POINTER TO ALLOCATED MEMORY IN HL
; ON SUCCESS RETURN A == 0, AND Z SET
; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED
; ALL OTHER REGISTERS PRESERVED
;
SYS_ALLOC:
JP HB_ALLOC
;
; FREE HEAP MEMORY BY SIMPLY RELEASING ALL
; MEMORY BEYOND POINTER IN HL.
; ON SUCCESS RETURN A == 0, AND Z SET
; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED
; ALL OTHER REGISTERS PRESERVED
;
SYS_FREE:
CALL PANIC ; NOT YET IMPLEMENTED
OR $FF
RET
;
; GET THE CURRENT HBIOS VERSION
; ON INPUT, C=0
; RETURNS VERSION IN DE AS BCD
; D: MAJOR VERION IN TOP 4 BITS, MINOR VERSION IN LOW 4 BITS
; E: UPDATE VERION IN TOP 4 BITS, PATCH VERSION IN LOW 4 BITS
; L: PLATFORM ID
;
SYS_VER:
LD DE,0 | (RMJ << 12) | (RMN << 8) | (RUP << 4) | RTP
LD L,PLATFORM
XOR A
RET
;
; GET SYSTEM INFORMATION
; ITEM TO RETURN INDICATED IN C
;
SYS_GET:
LD A,C ; GET REQUESTED SUB-FUNCTION
CP BF_SYSGET_CIOCNT
JR Z,SYS_GETCIOCNT
CP BF_SYSGET_DIOCNT
JR Z,SYS_GETDIOCNT
CP BF_SYSGET_VDACNT
JR Z,SYS_GETVDACNT
CP BF_SYSGET_BOOTINFO
JR Z,SYS_GETBOOTINFO
CP BF_SYSGET_CPUINFO
JR Z,SYS_GETCPUINFO
CP BF_SYSGET_MEMINFO
JR Z,SYS_GETMEMINFO
CP BF_SYSGET_BNKINFO
JR Z,SYS_GETBNKINFO
OR $FF ; SIGNAL ERROR
RET
;
; GET BOOT INFORMATION
; RETURNS:
; L: BOOT BANK ID
; DE: BOOT DISK VOLUME (UNIT/SLICE)
;
SYS_GETBOOTINFO:
LD A,(CB_BOOTBID)
LD L,A
LD DE,(CB_BOOTVOL)
XOR A
RET
;
; GET CPU INFORMATION
; RETURNS:
; H: Z80 CPU VARIANT
; L: CPU SPEED IN MHZ
; DE: CPU SPEED IN KHZ
;
SYS_GETCPUINFO:
LD H,0 ; NOT YET DEFINED
LD A,(CB_CPUMHZ)
LD L,A
LD DE,(CB_CPUKHZ)
XOR A
RET
;
; GET MEMORY INFORMATION
; RETURNS:
; D: COUNT OF ROM BANKS
; E: COUNT OF RAM BANKS
;
SYS_GETMEMINFO:
LD D,ROMSIZE / 32
LD E,RAMSIZE / 32
XOR A
RET
;
; GET BANK CONFIGURATION INFORMATION
; RETURNS:
; D: HBIOS BANK ID
; E: USER BANK ID
;
SYS_GETBNKINFO:
LD A,(CB_BIDBIOS)
LD D,A
LD A,(CB_BIDUSR)
LD E,A
XOR A
RET
;
; GET SERIAL UNIT COUNT
;
SYS_GETCIOCNT:
LD A,(CIO_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST)
LD E,A ; PUT IT IN E
XOR A ; SIGNALS SUCCESS
RET
;
; GET DISK UNIT COUNT
;
SYS_GETDIOCNT:
LD A,(DIO_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST)
LD E,A ; PUT IT IN E
XOR A ; SIGNALS SUCCESS
RET
;
; GET VIDEO UNIT COUNT
;
SYS_GETVDACNT:
LD A,(VDA_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST)
LD E,A ; PUT IT IN E
XOR A ; SIGNALS SUCCESS
RET
;
; SET SYSTEM PARAMETERS
; PARAMETER(S) TO SET INDICATED IN C
;
SYS_SET:
LD A,C ; GET REQUESTED SUB-FUNCTION
CP BF_SYSSET_BOOTINFO
JR Z,SYS_SETBOOTINFO
OR $FF ; SIGNAL ERROR
RET
;
; SET BOOT INFORMATION
; ON ENTRY:
; L: BOOT BANK ID
; DE: BOOT DISK VOLUME (UNIT/SLICE)
;
SYS_SETBOOTINFO:
LD A,L
LD (CB_BOOTBID),A
LD (CB_BOOTVOL),DE
XOR A
RET
;
; RETURN A BYTE OF MEMORY FROM SPECIFIED BANK
; ENTRY: D=BANK ID, HL=ADDRESS
; RETURN: E=BYTE VALUE
;
SYS_PEEK:
CALL HBX_PEEK ; IMPLEMENTED IN PROXY
XOR A
RET
;
; WRITE A BYTE OF MEMORY TO SPECIFIED BANK
; ENTRY: D=BANK ID, HL=ADDRESS IN HBIOS BANK, E=BYTE VALUE
;
SYS_POKE:
CALL HBX_POKE ; IMPLEMENTED IN PROXY
XOR A
RET
;
; SOFT RESET HBIOS, RELEASE HEAP MEMORY NOT USED BY HBIOS
;
SYS_RESET:
LD HL,(HEAPCURB) ; GET HBIOS HEAP THRESHOLD
LD (CB_HEAPTOP),HL ; RESTORE HEAP TOP
XOR A
RET
;;
;; GET HCB VALUE BYTE
;; C: HCB INDEX (OFFSET INTO HCB)
;; RETURN BYTE VALUE IN E
;;
;SYS_HCBGETB:
; CALL SYS_HCBPTR ; LOAD HL WITH PTR
; LD E,(HL) ; GET BYTE VALUE
; RET ; DONE
;;
;; PUT HCB VALUE BYTE
;; C: HCB INDEX (OFFSET INTO HCB)
;; E: VALUE TO WRITE
;;
;SYS_HCBPUTB:
; CALL SYS_HCBPTR ; LOAD HL WITH PTR
; LD (HL),E ; PUT BYTE VALUE
; RET
;;
;; GET HCB VALUE WORD
;; C: HCB INDEX (OFFSET INTO HCB)
;; RETURN WORD VALUE IN DE
;;
;SYS_HCBGETW:
; CALL SYS_HCBPTR ; LOAD HL WITH PTR
; LD E,(HL) ; GET BYTE VALUE
; INC HL
; LD D,(HL) ; GET BYTE VALUE
; RET ; DONE
;;
;; PUT HCB VALUE WORD
;; C: HCB INDEX (OFFSET INTO HCB)
;; DE: VALUE TO WRITE
;;
;SYS_HCBPUTW:
; CALL SYS_HCBPTR ; LOAD HL WITH PTR
; LD (HL),E ; PUT BYTE VALUE
; INC HL
; LD (HL),D ; PUT BYTE VALUE
; RET
;
;; CALCULATE REAL ADDRESS OF HCB VALUE FROM HCB OFFSET
;;
;SYS_HCBPTR:
; LD A,C ; LOAD INDEX (HCB OFFSET)
; LD HL,HCB ; GET HCB ADDRESS
; JP ADDHLA ; CALC REAL ADDRESS AND RET
;
;==================================================================================================
; GLOBAL HBIOS FUNCTIONS
;==================================================================================================
;
; COMMON ROUTINE THAT IS CALLED BY CHARACTER IO DRIVERS WHEN
; AN IDLE CONDITION IS DETECTED (WAIT FOR INPUT/OUTPUT)
;
CIO_IDLE:
PUSH AF ; PRESERVE AF
LD A,(IDLECOUNT) ; GET CURRENT IDLE COUNT
DEC A ; DECREMENT
LD (IDLECOUNT),A ; SAVE UPDATED VALUE
CALL Z,IDLE ; IF ZERO, DO IDLE PROCESSING
POP AF ; RECOVER AF
RET
;
; TIMER INTERRUPT
;
HB_TIMINT:
; INCREMENT TICK COUNTER (32 BIT)
LD HL,HB_TICKS ; POINT TO TICK COUNTER
INC (HL)
JR NZ,HB_TIMINT1
INC HL
INC (HL)
JR NZ,HB_TIMINT1
INC HL
INC (HL)
JR NZ,HB_TIMINT1
INC HL
INC (HL)
;
HB_TIMINT1:
;
#IF 0
;
LD HL,TEMPCNT
DEC (HL)
JR NZ,HB_TIMINT2
LD (HL),250
;
LD A,'*'
CALL COUT
JR HB_TIMINT2
;
TEMPCNT .DB 250
;
#ENDIF
;
HB_TIMINT2:
;
#IF (INTTYPE == IT_Z180)
; ACK/RESET INTERRUPT
IN0 A,(Z180_TCR)
IN0 A,(Z180_TMDR0L)
#ENDIF
;
RET
;
; BAD INTERRUPT HANDLER
;
HB_BADINT:
CALL NEWLINE2
PRTS("+++ BAD INT: $")
CALL _REGDMP
CALL CONTINUE
RET
;
; ADD AN ENTRY TO THE UNIT TABLE AT ADDRESS IN HL
; C: DEVICE TYPE ID
; B: UNIT INDEX
; DE: ADDRESS OF UNIT DATA
; RETURN
; A: UNIT NUMBER ASSIGNED
;
HB_ADDENT:
DEC HL ; POINT TO ENTRY COUNT
LD A,(HL) ; GET ENTRY COUNT
PUSH AF ; SAVE VALUE TO RETURN AS ENTRY NUM AT END
INC A ; INCREMENT TO ACCOUNT FOR NEW ENTRY
DEC HL ; POINT TO ENTRY MAX
CP (HL) ; COMPARE MAX TO CURRENT COUNT (COUNT - MAX)
CALL NC,PANIC ; OVERFLOW
INC HL ; POINT TO COUNT
LD (HL),A ; SAVE NEW COUNT
INC HL ; POINT TO START OF TABLE
DEC A ; CONVERT A FROM ENTRY COUNT TO ENTRY INDEX
RLCA ; MULTIPLY BY 4
RLCA ; ... TO GET BYTE OFFSET OF ENTRY
CALL ADDHLA ; MAKE HL POINT TO ACTUAL ENTRY ADDRESS
PUSH BC ; GET TABLE ENTRY ADDRESS TO BC
EX (SP),HL ; ... AND DISPATCH ADDRESS TO HL
POP BC ; ... SO THAT DE:HL HAS 32 BIT ENTRY
CALL ST32 ; LD (BC),DE:HL STORES THE ENTRY
POP AF ; RETURN ENTRY INDEX
RET
;
; ALLOCATE HL BYTES OF MEMORY ON THE HEAP
; RETURNS POINTER TO ALLOCATED SPACE IN HL
; ON SUCCESS RETURN A == 0, AND Z SET
; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED
; ALL OTHER REGISTERS PRESERVED
;
; A 4 BYTE HEADER IS PLACED IN FRONT OF THE ALLOCATED MEMORY
; - DWORD: SIZE OF MEMROY ALLOCATED (DOES NOT INCLUDE 4 BYTE HEADER)
; - DWORD: ADDRESS WHERE ALLOC WAS CALLED (VALUE ON TOP OF STACK AT CALL)
;
HB_ALLOC:
; SAVE ALLOC SIZE AND REFERENCE ADR FOR SUBSEQUENT HEADER CONSTRUCTION
LD (HB_TMPSZ),HL ; SAVE INCOMING SIZE REQUESTED
; USE EX (SP),HL INSTEAD????
POP HL ; GET RETURN ADDRESS
LD (HB_TMPREF),HL ; SAVE AS REFERENCE
; USE EX (SP),HL INSTEAD????
PUSH HL ; PUT IT BACK ON STACK
LD HL,(HB_TMPSZ) ; RECOVER INCOMING MEM SIZE PARM
;
; CALC NEW HEAP TOP AND HANDLE OUT-OF-SPACE ERROR
PUSH DE ; SAVE INCOMING DE
LD DE,4 ; SIZE OF HEADER
ADD HL,DE ; ADD IT IN
JR C,HB_ALLOC1 ; ERROR ON OVERFLOW
LD DE,(CB_HEAPTOP) ; CURRENT HEAP TOP
ADD HL,DE ; ADD IT IN, HL := NEW HEAP TOP
JR C,HB_ALLOC1 ; ERROR ON OVERFLOW
BIT 7,H ; TEST PAST END OF BANK (>= 32K)
JR NZ,HB_ALLOC1 ; ERROR IF PAST END
;
; SAVE NEW HEAP TOP
LD DE,(CB_HEAPTOP) ; GET ORIGINAL HEAP TOP
LD (CB_HEAPTOP),HL ; SAVE NEW HEAP TOP
;
; SET HEADER VALUES
EX DE,HL ; HEADER ADR TO HL
LD DE,(HB_TMPSZ) ; GET THE ORIG SIZE REQUESTED
LD (HL),E ; SAVE SIZE (LSB)
INC HL ; BUMP HEADER POINTER
LD (HL),D ; SAVE SIZE (MSB)
INC HL ; BUMP HEADER POINTER
LD DE,(HB_TMPREF) ; GET THE REFERENCE ADR
LD (HL),E ; SAVE REF ADR (LSB)
INC HL ; BUMP HEADER POINTER
LD (HL),D ; SAVE REF ADR (MSB)
INC HL ; BUMP HEADER POINTER
;
; RETURN SUCCESS, HL POINTS TO START OF ALLOCATED MEMORY (PAST HEADER)
POP DE ; RESTORE INCOMING DE
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
HB_ALLOC1:
; ERROR RETURN
POP DE ; RESTORE INCOMING DE
OR $FF ; SIGNAL ERROR
RET ; AND RETURN
;
HB_TMPSZ .DW 0
HB_TMPREF .DW 0
;
;==================================================================================================
; DEVICE DRIVERS
;==================================================================================================
;
#IF (SIMRTCENABLE)
ORG_SIMRTC .EQU $
#INCLUDE "simrtc.asm"
SIZ_SIMRTC .EQU $ - ORG_SIMRTC
.ECHO "SIMRTC occupies "
.ECHO SIZ_SIMRTC
.ECHO " bytes.\n"
#ENDIF
;
#IF (DSRTCENABLE)
ORG_DSRTC .EQU $
#INCLUDE "dsrtc.asm"
SIZ_DSRTC .EQU $ - ORG_DSRTC
.ECHO "DSRTC occupies "
.ECHO SIZ_DSRTC
.ECHO " bytes.\n"
#ENDIF
;
#IF (ASCIENABLE)
ORG_ASCI .EQU $
#INCLUDE "asci.asm"
SIZ_ASCI .EQU $ - ORG_ASCI
.ECHO "ASCI occupies "
.ECHO SIZ_ASCI
.ECHO " bytes.\n"
#ENDIF
;
#IF (UARTENABLE)
ORG_UART .EQU $
#INCLUDE "uart.asm"
SIZ_UART .EQU $ - ORG_UART
.ECHO "UART occupies "
.ECHO SIZ_UART
.ECHO " bytes.\n"
#ENDIF
;
#IF (SIOENABLE)
ORG_SIO .EQU $
#INCLUDE "sio.asm"
SIZ_SIO .EQU $ - ORG_SIO
.ECHO "SIO occupies "
.ECHO SIZ_SIO
.ECHO " bytes.\n"
#ENDIF
;
#IF (VGAENABLE)
ORG_VGA .EQU $
#INCLUDE "vga.asm"
SIZ_VGA .EQU $ - ORG_VGA
.ECHO "VGA occupies "
.ECHO SIZ_VGA
.ECHO " bytes.\n"
#ENDIF
;
#IF (CVDUENABLE)
ORG_CVDU .EQU $
#INCLUDE "cvdu.asm"
SIZ_CVDU .EQU $ - ORG_CVDU
.ECHO "CVDU occupies "
.ECHO SIZ_CVDU
.ECHO " bytes.\n"
#ENDIF
;
#IF (VDUENABLE)
ORG_VDU .EQU $
#INCLUDE "vdu.asm"
SIZ_VDU .EQU $ - ORG_VDU
.ECHO "VDU occupies "
.ECHO SIZ_VDU
.ECHO " bytes.\n"
#ENDIF
;
#IF (TMSENABLE)
ORG_TMS .EQU $
#INCLUDE "tms.asm"
SIZ_TMS .EQU $ - ORG_TMS
.ECHO "TMS occupies "
.ECHO SIZ_TMS
.ECHO " bytes.\n"
#ENDIF
;
#IF (NECENABLE)
ORG_NEC .EQU $
;#INCLUDE "nec.asm"
SIZ_NEC .EQU $ - ORG_NEC
.ECHO "NEC occupies "
.ECHO SIZ_NEC
.ECHO " bytes.\n"
#ENDIF
;
#IF (CVDUENABLE | VGAENABLE)
ORG_FONTHI .EQU $
#INCLUDE "font_hi.asm"
SIZ_FONTHI .EQU $ - ORG_FONTHI
.ECHO "FONTHI occupies "
.ECHO SIZ_FONTHI
.ECHO " bytes.\n"
#ENDIF
;
#IF (TMSENABLE)
ORG_FONTTMS .EQU $
#INCLUDE "font_tms.asm"
SIZ_FONTTMS .EQU $ - ORG_FONTTMS
.ECHO "FONTTMS occupies "
.ECHO SIZ_FONTTMS
.ECHO " bytes.\n"
#ENDIF
;
#IF (CVDUENABLE | VGAENABLE)
ORG_KBD .EQU $
#INCLUDE "kbd.asm"
SIZ_KBD .EQU $ - ORG_KBD
.ECHO "KBD occupies "
.ECHO SIZ_KBD
.ECHO " bytes.\n"
#ENDIF
;
#IF (VDUENABLE | (TMSENABLE & (PLATFORM == PLT_N8)))
ORG_PPK .EQU $
#INCLUDE "ppk.asm"
SIZ_PPK .EQU $ - ORG_PPK
.ECHO "PPK occupies "
.ECHO SIZ_PPK
.ECHO " bytes.\n"
#ENDIF
;
#IF (PRPENABLE)
ORG_PRP .EQU $
#INCLUDE "prp.asm"
SIZ_PRP .EQU $ - ORG_PRP
.ECHO "PRP occupies "
.ECHO SIZ_PRP
.ECHO " bytes.\n"
#ENDIF
;
#IF (PPPENABLE)
ORG_PPP .EQU $
#INCLUDE "ppp.asm"
SIZ_PPP .EQU $ - ORG_PPP
.ECHO "PPP occupies "
.ECHO SIZ_PPP
.ECHO " bytes.\n"
#ENDIF
;
#IF (MDENABLE)
ORG_MD .EQU $
#INCLUDE "md.asm"
SIZ_MD .EQU $ - ORG_MD
.ECHO "MD occupies "
.ECHO SIZ_MD
.ECHO " bytes.\n"
#ENDIF
#IF (FDENABLE)
ORG_FD .EQU $
#INCLUDE "fd.asm"
SIZ_FD .EQU $ - ORG_FD
.ECHO "FD occupies "
.ECHO SIZ_FD
.ECHO " bytes.\n"
#ENDIF
#IF (RFENABLE)
ORG_RF .EQU $
#INCLUDE "rf.asm"
SIZ_RF .EQU $ - ORG_RF
.ECHO "RF occupies "
.ECHO SIZ_RF
.ECHO " bytes.\n"
#ENDIF
#IF (IDEENABLE)
ORG_IDE .EQU $
#INCLUDE "ide.asm"
SIZ_IDE .EQU $ - ORG_IDE
.ECHO "IDE occupies "
.ECHO SIZ_IDE
.ECHO " bytes.\n"
#ENDIF
#IF (PPIDEENABLE)
ORG_PPIDE .EQU $
#INCLUDE "ppide.asm"
SIZ_PPIDE .EQU $ - ORG_PPIDE
.ECHO "PPIDE occupies "
.ECHO SIZ_PPIDE
.ECHO " bytes.\n"
#ENDIF
#IF (SDENABLE)
ORG_SD .EQU $
#INCLUDE "sd.asm"
SIZ_SD .EQU $ - ORG_SD
.ECHO "SD occupies "
.ECHO SIZ_SD
.ECHO " bytes.\n"
#ENDIF
#IF (HDSKENABLE)
ORG_HDSK .EQU $
#INCLUDE "hdsk.asm"
SIZ_HDSK .EQU $ - ORG_HDSK
.ECHO "HDSK occupies "
.ECHO SIZ_HDSK
.ECHO " bytes.\n"
#ENDIF
#IF (TERMENABLE)
ORG_TERM .EQU $
#INCLUDE "term.asm"
SIZ_TERM .EQU $ - ORG_TERM
.ECHO "TERM occupies "
.ECHO SIZ_TERM
.ECHO " bytes.\n"
#ENDIF
;
#DEFINE USEDELAY
#INCLUDE "util.asm"
#INCLUDE "time.asm"
#INCLUDE "bcd.asm"
#INCLUDE "decode.asm"
;#INCLUDE "xio.asm"
;
#IF (DSKYENABLE)
#DEFINE DSKY_KBD
#INCLUDE "dsky.asm"
#ENDIF
;
; DETECT CPU SPEED USING DS-1302 RTC
;
HB_CPUSPD:
;
#IF (DSRTCENABLE)
;
CALL DSRTC_TSTCLK ; IS CLOCK RUNNING?
JR Z,HB_CPUSPD1 ; YES, CONTINUE
; MAKE SURE CLOCK IS RUNNING
LD HL,DSRTC_TIMDEF
CALL DSRTC_TIM2CLK
LD HL,DSRTC_BUF
CALL DSRTC_WRCLK
CALL DSRTC_TSTCLK ; NOW IS CLOCK RUNNING?
RET NZ
;
HB_CPUSPD1:
; LD B,8
;HB_CPUSPDX:
; PUSH BC
; WAIT FOR AN INITIAL TICK TO ALIGN, THEN WAIT
; FOR SECOND TICK AND TO GET A FULL ONE SECOND LOOP COUNT
CALL HB_RDSEC ; GET SECONDS
LD (HB_CURSEC),A ; AND INIT CURSEC
CALL HB_WAITSEC ; WAIT FOR SECONDS TICK
LD (HB_CURSEC),A ; SAVE NEW VALUE
CALL HB_WAITSEC ; WAIT FOR SECONDS TICK
; PUSH DE
; POP BC
; CALL NEWLINE
; CALL PRTHEXWORD
; POP BC
; DJNZ HB_CPUSPDX
;
LD A,H
OR L
RET Z ; FAILURE, USE DEFAULT CPU SPEED
;
; MOVE LOOP COUNT TO HL
PUSH DE
POP HL
;
; TIMES 4 FOR CPU SPEED IN KHZ
RES 0,L ; GRANULARITY
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4))
SLA L
RL H
#ENDIF
SLA L
RL H
SLA L
RL H
;
LD (CB_CPUKHZ),HL
LD DE,1000
CALL DIV16
LD A,C
LD (CB_CPUMHZ),A
;
RET
;
HB_WAITSEC:
; WAIT FOR SECONDS TICK
; RETURN SECS VALUE IN A, LOOP COUNT IN DE
LD DE,0 ; INIT LOOP COUNTER
HB_WAITSEC1:
#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2))
; LOOP TARGET IS 4000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 4
CALL DLY32
CALL DLY8
CALL DLY2
JP $ + 3 ; 10 TSTATES
JP $ + 3 ; 10 TSTATES
JP $ + 3 ; 10 TSTATES
JP $ + 3 ; 10 TSTATES
;LD A,R ; 9 TSTATES
INC BC ; 6 TSTATES
;LD A,(BC) ; 7 TSTATES
;NOP ; 4 TSTATES
NOP ; 4 TSTATES
#ENDIF
#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4))
; LOOP TARGET IS 8000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 8
;CALL DLY64
CALL DLY32
CALL DLY16
CALL DLY8
CALL DLY4
CALL DLY2
CALL DLY1 ; CALL (25TS) & RET (18TS) = 43TS
OR A ; 7 TSTATES
OR A ; 7 TSTATES
;OR A ; 7 TSTATES
;OR A ; 7 TSTATES
NOP ; 6 TSTATES
;NOP ; 6 TSTATES
;NOP ; 6 TSTATES
;NOP ; 6 TSTATES
;NOP ; 6 TSTATES
#ENDIF
;
PUSH DE
CALL HB_RDSEC ; GET SECONDS
POP DE
INC DE ; BUMP COUNTER
LD HL,HB_CURSEC ; POINT TO COMP VALUE
CP (HL) ; TEST FOR CHANGE
RET NZ ; DONE IF TICK OCCURRED
LD A,D ; CHECK HL
OR E ; ... FOR OVERFLOW
RET Z ; TIMEOUT, SOMETHING IS WRONG
JR HB_WAITSEC1 ; LOOP
;
HB_RDSEC:
; READ SECONDS BYTE INTO A
LD C,$81 ; SECONDS REGISTER
CALL DSRTC_CMD ; SEND THE COMMAND
CALL DSRTC_GET ; READ THE REGISTER
CALL DSRTC_END ; FINISH IT
RET
;
#ELSE
;
RET ; NO RTC, ABORT
;
#ENDIF
;
; PRINT VALUE OF HL AS THOUSANDTHS, IE. 0.000
;
PRTD3M:
PUSH BC
PUSH DE
PUSH HL
LD E,'0'
LD BC,-10000
CALL PRTD3M1
LD E,0
LD BC,-1000
CALL PRTD3M1
CALL PC_PERIOD
LD BC,-100
CALL PRTD3M1
LD C,-10
CALL PRTD3M1
LD C,-1
CALL PRTD3M1
POP HL
POP DE
POP BC
RET
PRTD3M1:
LD A,'0' - 1
PRTD3M2:
INC A
ADD HL,BC
JR C,PRTD3M2
SBC HL,BC
CP E
JR Z,PRTD3M3
LD E,0
CALL COUT
PRTD3M3:
RET
;
;==================================================================================================
; DISPLAY SUMMARY OF ATTACHED UNITS/DEVICES
;==================================================================================================
;
PRTSUM:
CALL NEWLINE2 ; SKIP A LINE
LD DE,PS_STRHDR ; POINT TO HEADER
CALL WRITESTR ; PRINT IT
;
; PRINT DISK DEVICES
LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET
LD C,BF_SYSGET_DIOCNT ; SUBFUNC: DISK UNIT COUNT
RST 08 ; E := DISK UNIT COUNT
LD B,E ; MOVE TO B FOR LOOP COUNT
LD A,E ; MOVE TO ACCUM
OR A ; SET FLAGS
JR Z,PRTSUM1A ; IF NONE, BYPASS
LD C,0 ; C WILL BE UNIT INDEX
PRTSUM1:
PUSH BC ; SAVE LOOP CONTROL
CALL PS_DISK ; PRINT DISK INFO
POP BC ; RESTORE LOOP CONTROL
INC C ; BUMP DISK UNIT INDEX
DJNZ PRTSUM1 ; LOOP THRU ALL DISK DEVICES
;
PRTSUM1A:
; PRINT SERIAL DEVICES
LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET
LD C,BF_SYSGET_CIOCNT ; SUBFUNC: SERIAL UNIT COUNT
RST 08 ; E := SERIAL UNIT COUNT
LD B,E ; MOVE TO B FOR LOOP COUNT
LD A,E ; MOVE TO ACCUM
OR A ; SET FLAGS
JR Z,PRTSUM2A ; IF NONE, BYPASS
LD C,0 ; C WILL BE UNIT INDEX
PRTSUM2:
PUSH BC ; SAVE LOOP CONTROL
CALL PS_SERIAL ; PRINT SERIAL INFO
POP BC ; RESTORE LOOP CONTROL
INC C ; BUMP SERIAL UNIT INDEX
DJNZ PRTSUM2 ; LOOP THRU ALL SERIAL DEVICES
;
PRTSUM2A:
; PRINT VIDEO DEVICES
LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET
LD C,BF_SYSGET_VDACNT ; SUBFUNC: VIDEO UNIT COUNT
RST 08 ; E := SERIAL UNIT COUNT
LD B,E ; MOVE TO B FOR LOOP COUNT
LD A,E ; MOVE TO ACCUM
OR A ; SET FLAGS
JR Z,PRTSUM3A ; IF NONE, BYPASS
LD C,0 ; C WILL BE UNIT INDEX
PRTSUM3:
PUSH BC ; SAVE LOOP CONTROL
CALL PS_VIDEO ; PRINT VIDEO INFO
POP BC ; RESTORE LOOP CONTROL
INC C ; BUMP VIDEO UNIT INDEX
DJNZ PRTSUM3 ; LOOP THRU ALL VIDEO DEVICES
;
PRTSUM3A:
RET ; DONE
;
; PRINT ONE LINE DISK UNIT/DEVICE INFO, DISK UNIT INDEX IN C
;
PS_DISK:
PUSH BC ; SAVE UNIT INDEX FOR LATER
;
; UNIT COLUMN
PRTS("Disk $")
LD A,C ; MOVE UNIT NUM TO A
CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT
PRTS(" $") ; PAD TO NEXT COLUMN
;
; DEVICE COLUMN
LD B,BF_DIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C
RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES
PUSH BC ; SAVE ATTRIBUTES
LD HL,PS_DDSTRREF ; POINT TO DISK DEVICE TYPE NAME TABLE
CALL PS_PRTDEV ; PRINT DISK DEVICE NMEMONIC PADDED TO FIELD WIDTH
POP DE ; RECOVER ATTRIBUTES TO DE
PUSH DE ; SAVE ATTRIBUTES AGAIN
CALL PS_PRTDT ; PRINT DISK TYPE
POP DE ; RESTORE ATTRIBUTES
POP BC ; RESTORE UNIT NUM
CALL PS_PRTDC ; PRINT DISK CAPACITY
;
CALL NEWLINE
RET
;
; PRINT DISK TYPE (DISK ATTRIBUTE IN E)
;
PS_PRTDT:
LD A,E ; ATTRIBUTES TO A
BIT 7,A ; FLOPPY BIT SET?
LD HL,PS_DTFLOP ; ASSUME FLOPPY
JR NZ,PS_PRTDT1 ; IF FLOPPY, JUMP AHEAD
RRCA ; SHIFT TYPE BITS
RRCA
RRCA
AND $07 ; AND ISOLATE THEM
RLCA ; X2 FOR WORD OFFSET IN STRING TABLE
LD HL,PS_DTSTRREF + 2 ; POINT TO STR REF TABLE (SKIP FLOPPY STRING)
CALL ADDHLA
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
;
PS_PRTDT1:
CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED
LD A,18 ; 18 CHAR FIELD
SUB C
CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A)
RET
;
; PRINT DISK CAPACITY (UNIT IN C, ATTRIBUTE IN E)
;
PS_PRTDC:
;
LD A,E ; ATTRIBUTE TO ACCUM
BIT 7,A ; TEST FOR FLOPPY
JR NZ,PS_PRTDC2 ; HANDLE FLOPPY
RRCA ; ISOLATE TYPE BITS
RRCA
RRCA
AND $07
CP 4 ; ROM DISK?
JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB
CP 5 ; RAM DISK?
JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB
;
; PRINT HARD DISK STORAGE SIZE IN MB
LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY
RST 08 ; DE:HL := BLOCKS
JP NZ,PS_PRTNUL ; MEDIA PROBLEM
RES 7,D ; CLEAR LBA BIT
LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB
CALL SRL32 ; RIGHT SHIFT
CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED)
PRTS("MB$") ; PRINT SUFFIX
CALL PC_COMMA
PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA
RET ; DONE
;
PS_PRTDC1:
; PRINT ROM/ROM DISK CAPACITY IN KB
LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY
RST 08 ; DE:HL := BLOCKS
JP NZ,PS_PRTNUL ; MEDIA PROBLEM
RES 7,D ; CLEAR LBA BIT
LD B,1 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB
CALL SRL32 ; RIGHT SHIFT
CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED)
PRTS("KB$") ; PRINT SUFFIX
CALL PC_COMMA
PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA
RET ; DONE
;
PS_PRTDC2:
LD C,E ; ATTRIBUTE TO C FOR SAFE KEEPING
; PRINT FLOPPY TYPE
LD A,C ; ATTRIBUTE TO ACCUM
RLCA ; ISOLATE FORM FACTOR BITS
RLCA
RLCA
AND $03
LD DE,PS_FLP8 ; ASSUME 8"
CP 0
JR Z,PS_PRTDC2A
LD DE,PS_FLP5 ; ASSUME 5.25"
CP 1
JR Z,PS_PRTDC2A
LD DE,PS_FLP3 ; ASSUME 3.5"
CP 2
JR Z,PS_PRTDC2A
LD DE,PS_FLPN ; ASSUME OTHER"
PS_PRTDC2A:
CALL WRITESTR
; PRINT FLOPPY SIDES
LD A,C ; ATTRIBUTE TO ACCUM
LD DE,PS_FLPSS ; ASSUME SINGLE SIDED
BIT 4,A ; DS?
JR Z,PS_PRTDC2B
LD DE,PS_FLPDS ; DOUBLE SIDED
PS_PRTDC2B:
CALL WRITESTR
; PRINT FLOPPY DENSITY
LD A,C ; ATTRIBUTE TO ACCUM
RRCA ; ISOLATE DENSITY BITS
RRCA
AND $03
LD DE,PS_FLPSD ; SINGLE DENSITY
CP 0
JR Z,PS_PRTDC2C
LD DE,PS_FLPDD ; DOUBLE DENSITY
CP 1
JR Z,PS_PRTDC2C
LD DE,PS_FLPHD ; HIGH DENSITY
CP 2
JR Z,PS_PRTDC2C
LD DE,PS_FLPED ; EXTENDED DENSITY
CP 3
JR Z,PS_PRTDC2C
PS_PRTDC2C:
CALL WRITESTR
CALL PC_COMMA
PRTS("CHS$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA
;
RET ; DONE
;
; PRINT ONE LINE SERIAL UNIT/DEVICE INFO, SERIAL UNIT INDEX IN C
;
PS_SERIAL:
PUSH BC ; SAVE UNIT INDEX FOR LATER
;
; UNIT COLUMN
PRTS("Serial $")
LD A,C ; MOVE UNIT NUM TO A
CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT
PRTS(" $") ; PAD TO NEXT COLUMN
;
; DEVICE COLUMN
LD B,BF_CIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C
RST 08 ; DE:=DEVTYP/NUM, C:=DISK ATTRIBUTES
PUSH BC ; SAVE ATTRIBUTES
LD HL,PS_SDSTRREF ; POINT TO SERIAL DEVICE TYPE NAME TABLE
CALL PS_PRTDEV ; PRINT SERIAL DEVICE NMEMONIC PADDED TO FIELD WIDTH
POP BC ; RECOVER ATTRIBUTES
PUSH BC ; SAVE ATTRIBUTES AGAIN
CALL PS_PRTST ; PRINT SERIAL TYPE
POP BC ; RESTORE ATTRIBUTES
POP DE ; RESTORE UNIT NUM
CALL PS_PRTSC ; PRINT SERIAL CONFIG
;
CALL NEWLINE
RET
;
; PRINT SERIAL TYPE (SERIAL ATTRIBUTE IN E)
;
PS_PRTST:
LD HL,PS_STRS232 ; ASSUME RS-232
BIT 7,C ; 0=RS-232, 1=TERMINAL
JR Z,PS_PRTST1 ; HANDLE TERMINAL TYPE
LD HL,PS_STTERM ; TYPE IS TERMINAL
;
PS_PRTST1:
CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED
LD A,18 ; 18 CHAR FIELD
SUB C
CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A)
RET
;
; PRINT SERIAL CONFIG (UNIT IN C, ATTRIBUTE IN E)
;
PS_PRTSC:
BIT 7,C ; 0=RS-232, 1=TERMINAL
JR NZ,PS_PRTSC1 ; PRINT TERMINAL CONFIG
;
; PRINT RS-232 CONFIG
LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG
RST 08 ; DE:HL := BAUD RATE
LD A,D ; TEST FOR $FF
AND E
INC A ; SET Z IF DE == $FF
JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED
;
PS_PRTSC0:
; PRINT BAUD RATE
PUSH DE ; PRESERVE DE
LD A,D
AND $1F ; ISOLATE ENCODED BAUD RATE
LD L,A ; PUT IN L
LD H,0 ; H IS ALWAYS ZERO
LD DE,75 ; BAUD RATE DECODE CONSTANT
CALL DECODE ; DE:HL := BAUD RATE
LD BC,HB_BCDTMP ; POINT TO TEMP BCD BUF
CALL BIN2BCD ; CONVERT TO BCD
CALL PRTBCD ; AND PRINT IN DECIMAL
POP DE ; RESTORE DE
;
; PRINT DATA BITS
PUSH DE ; PRESERVE DE
CALL PC_COMMA ; FORMATTING
LD A,E ; GET CONFIG BYTE
AND $03 ; ISOLATE DATA BITS VALUE
ADD A,'5' ; CONVERT TO CHARACTER
CALL COUT ; AND PRINT
POP DE ; RESTORE DE
;
; PRINT PARITY
PUSH DE ; PRESERVE DE
CALL PC_COMMA ; FORMATTING
LD A,E ; GET CONFIG BYTE
RRCA ; SHIFT RELEVANT BITS
RRCA ; ...
RRCA ; ...
AND $07 ; AND ISOLATE DATA BITS VALUE
LD HL,PS_STPARMAP ; CHARACTER LOOKUP TABLE
CALL ADDHLA ; APPLY OFFSET
LD A,(HL) ; GET CHARACTER
CALL COUT ; AND PRINT
POP DE ; RESTORE DE
;
; PRINT STOP BITS
CALL PC_COMMA ; FORMATTING
LD A,E ; GET CONFIG BYTE
RRCA ; SHIFT RELEVANT BITS
RRCA ; ...
AND $01 ; AND ISOLATE DATA BITS VALUE
ADD A,'1' ; MAKE IT A CHARACTER
CALL COUT ; AND PRINT
;
RET
;
PS_PRTSC1:
; PRINT TERMINAL CONFIG
LD A,C ; GET ATTRIBUTE VALUE
CP $FF ; NO ATTACHED VDA
JR Z,PS_PRTSC2
PRTS("Video $") ; FORMATTING
AND $0F ; ISOLATE VIDEO UNIT NUM
CALL PRTDECB ; PRINT IT
CALL PC_COMMA
#IF (VDAEMU == EMUTYP_TTY)
PRTS("TTY$")
#ENDIF
#IF (VDAEMU == EMUTYP_ANSI)
PRTS("ANSI$")
#ENDIF
RET
;
PS_PRTSC2:
PRTS("PropTerm$") ; ASSUME PROPELLER
CALL PC_COMMA
PRTS("ANSI$")
RET
;
; PRINT ONE LINE VIDEO UNIT/DEVICE INFO, VIDEO UNIT INDEX IN C
;
PS_VIDEO:
PUSH BC ; SAVE UNIT INDEX FOR LATER
;
; UNIT COLUMN
PRTS("Video $")
LD A,C ; MOVE UNIT NUM TO A
CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT
PRTS(" $") ; PAD TO NEXT COLUMN
;
; DEVICE COLUMN
LD B,BF_VDADEV ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C
RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES
PUSH BC ; SAVE ATTRIBUTES
LD HL,PS_VDSTRREF ; POINT TO VIDEO DEVICE TYPE NAME TABLE
CALL PS_PRTDEV ; PRINT VIDEO DEVICE NMEMONIC PADDED TO FIELD WIDTH
POP DE ; RECOVER ATTRIBUTES
PUSH DE ; SAVE ATTRIBUTES AGAIN
CALL PS_PRTVT ; PRINT VIDEO TYPE
POP DE ; RESTORE ATTRIBUTES
POP BC ; RESTORE UNIT NUM
CALL PS_PRTVC ; PRINT VIDEO CONFIG
;
CALL NEWLINE
RET
;
; PRINT VIDEO TYPE (VIDEO ATTRIBUTE IN E)
;
PS_PRTVT:
LD HL,PS_VTCRT ; ASSUME CRT
CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED
LD A,18 ; 18 CHAR FIELD
SUB C
CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A)
RET
;
; PRINT VIDEO CONFIG (UNIT IN C, ATTRIBUTE IN E)
;
PS_PRTVC:
PRTS("Text$")
CALL PC_COMMA
LD B,BF_VDAQRY ; FUNC: QUERY FOR VDA CONFIG
RST 08 ; D:=ROWS, E:=COLS
LD A,E
CALL PRTDECB
LD A,'x'
CALL COUT
LD A,D
CALL PRTDECB
RET
;
; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE
;
PS_PRTDEV:
LD A,D
RRCA ; TYPE IS IN UPPER NIBBLE, MOVE TO LOWER NIBBLE
RRCA
RRCA
RRCA
RLCA ; X2 FOR WORD OFFSET IN STRING TABLE
CALL ADDHLA
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED
LD A,E ; NUM
CALL PRTDECB ; PRINT NUM, ASSUME 1 CHAR
CALL PC_COLON ; PRINT COLON
LD A,12 - 2 ; 12 CHAR FIELD - 1 POS FOR UNIT NUM AND 1 POS FOR COLON
SUB C
CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A)
RET
;
; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE
;
PS_PRTNUL:
LD HL,PS_STRNUL
; FALL THRU TO PS_PRT
;
;
;
PS_PRT:
; PRINT STRING AT (HL), $ TERM, RETURN CHARS PRINTED IN C
LD C,0 ; INIT CHAR COUNT
PS_PRT1:
LD A,(HL) ; GET CHAR
INC HL ; BUMP INDEX
CP '$' ; TERM?
RET Z ; IF SO, DONE
CALL COUT ; PRINT IT
INC C ; BUMP COUNTER
JR PS_PRT1 ; AND LOOP
;
;
;
PS_PAD:
; PAD N SPACES SPECIFIED IN A
LD B,A
LD A,' '
PS_PAD1:
CALL COUT
DJNZ PS_PAD1
RET
;
;
;
PS_STRNUL .TEXT "--$" ; DISPLAY STRING FOR NUL VALUE
;
; DISK DEVICE STRINGS
;
PS_DDSTRREF:
.DW PS_DDMD, PS_DDFD, PS_DDRF, PS_DDIDE, PS_DDATAPI, PS_DDPPIDE
.DW PS_DDSD, PS_DDPRPSD, PS_DDPPPSD, PS_DDHDSK
;
PS_DDMD .TEXT "MD$"
PS_DDFD .TEXT "FD$"
PS_DDRF .TEXT "RF$"
PS_DDIDE .TEXT "IDE$"
PS_DDATAPI .TEXT "ATAPI$"
PS_DDPPIDE .TEXT "PPIDE$"
PS_DDSD .TEXT "SD$"
PS_DDPRPSD .TEXT "PRPSD$"
PS_DDPPPSD .TEXT "PPPSD$"
PS_DDHDSK .TEXT "HDSK$"
;
; DISK TYPE STRINGS
;
PS_DTSTRREF:
.DW PS_DTFLOP, PS_DTHARD, PS_DTCF, PS_DTSD
.DW PS_DTUSB, PS_DTROM, PS_DTRAM, PS_DTRF
;
PS_DTFLOP .TEXT "Floppy Disk$"
PS_DTHARD .TEXT "Hard Disk$"
PS_DTCF .TEXT "CompactFlash$"
PS_DTSD .TEXT "SD Card$"
PS_DTUSB .TEXT "USB Drive$"
PS_DTROM .TEXT "ROM Disk$"
PS_DTRAM .TEXT "RAM Disk$"
PS_DTRF .TEXT "RAM Floppy$"
PS_DTOTHER .TEXT "???$"
;
; FLOPPY ATTRIBUTE STRINGS
;
PS_FLP8 .TEXT "8\",$"
PS_FLP5 .TEXT "5.25\",$"
PS_FLP3 .TEXT "3.5\",$"
PS_FLPN .TEXT "???\",$"
;
PS_FLPSS .TEXT "SS/$"
PS_FLPDS .TEXT "DS/$"
;
PS_FLPSD .TEXT "SD$"
PS_FLPDD .TEXT "DD$"
PS_FLPHD .TEXT "HD$"
PS_FLPED .TEXT "ED$"
;
; SERIAL DEVICE STRINGS
;
PS_SDSTRREF:
.DW PS_SDUART, PS_SDASCI, PS_SDTERM,
.DW PS_SDPRPCON, PS_SDPPPCON, PS_SDSIO
;
PS_SDUART .TEXT "UART$"
PS_SDASCI .TEXT "ASCI$"
PS_SDTERM .TEXT "TERM$"
PS_SDPRPCON .TEXT "PRPCON$"
PS_SDPPPCON .TEXT "PPPCON$"
PS_SDSIO .TEXT "SIO$"
;
; SERIAL TYPE STRINGS
;
PS_STRS232 .TEXT "RS-232$"
PS_STTERM .TEXT "Terminal$"
;
PS_STPARMAP .DB "NONENMNS"
;
; SERIAL TYPE STRINGS
;
;
; VIDEO DEVICE STRINGS
;
PS_VDSTRREF:
.DW PS_VDVDU, PS_VDCVDU, PS_VDNEC, PS_VDTMS, PS_VDVGA
;
PS_VDVDU .TEXT "VDU$"
PS_VDCVDU .TEXT "CVDU$"
PS_VDNEC .TEXT "NEC$"
PS_VDTMS .TEXT "TMS$"
PS_VDVGA .TEXT "VGA$"
;
; VIDEO TYPE STRINGS
;
PS_VTCRT .TEXT "CRT$"
;
; VIDEO CONFIG STRINGS
;
;
;
; 0 1 2 3 4 5 6 7
; 01234567890123456789012345678901234567890123456789012345678901234567890123456789
PS_STRHDR .TEXT "Unit Device Type Capacity/Mode\r\n"
.TEXT "---------- ---------- ---------------- --------------------\r\n$"
;
;==================================================================================================
; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED)
;==================================================================================================
;
; OUTPUT CHARACTER FROM A
;
COUT:
; SAVE ALL INCOMING REGISTERS
PUSH AF
PUSH BC
PUSH DE
PUSH HL
;
; GET CURRENT CONSOLE UNIT
LD E,A ; TEMPORARILY STASH OUTPUT CHAR IN E
LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE
CP $FF ; TEST FOR $FF (HBIOS NOT READY)
JR Z,COUT1 ; IF NOT READY, USE XIO
;
; USE HBIOS
LD C,A ; CONSOLE UNIT TO C
LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR
CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY
JR COUT2 ; CONTINUE
;
COUT1:
;; USE XIO
;LD A,E ; GET OUTPUT CHAR BACK TO ACCUM
;CALL XIO_OUTC ; OUTPUT VIA XIO
;
COUT2:
; RESTORE ALL REGISTERS
POP HL
POP DE
POP BC
POP AF
RET
;
; INPUT CHARACTER TO A
;
CIN:
; SAVE INCOMING REGISTERS (AF IS OUTPUT)
PUSH BC
PUSH DE
PUSH HL
;
LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE
CP $FF ; TEST FOR $FF (HBIOS NOT READY)
JR Z,CIN1 ; IF NOT READY, USE XIO
;
; USE HBIOS
LD C,A ; CONSOLE UNIT TO C
LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR
CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY
LD A,E ; RESULTANT CHAR TO A
JR CIN2 ; CONTINUE
;
CIN1:
;; USE XIO
;CALL XIO_INC ; GET CHAR
;
CIN2:
;
; RESTORE REGISTERS (AF IS OUTPUT)
POP HL
POP DE
POP BC
RET
;
; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING)
;
CST:
; SAVE INCOMING REGISTERS (AF IS OUTPUT)
PUSH BC
PUSH DE
PUSH HL
;
LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE
CP $FF ; TEST FOR $FF (HBIOS NOT READY)
JR Z,CST1 ; IF NOT READY, USE XIO
;
; USE HBIOS
LD C,A ; CONSOLE UNIT TO C
LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS
CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY
JR CST2 ; CONTINUE
;
CST1:
;; USE XIO
;CALL XIO_IST ; GET STATUS
;
CST2:
; RESTORE REGISTERS (AF IS OUTPUT)
POP HL
POP DE
POP BC
RET
;
;==================================================================================================
; HBIOS GLOBAL DATA
;==================================================================================================
;
IDLECOUNT .DB 0
;
; THE HOST (HST) VALUES BELOW INDICATE THE DISK AND BLOCK CURRENTLY
; ADDRESSED FOR READ/WRITE OPERATIONS.
; THE 32-BIT BLOCK ADDRESS CAN BE TREADED AS EITHER CHS OR LBA, HIGH ORDER BIT ON SIGNIFIES LBA
; CHS:
; .DW 0 ; TRACK (0-65535)
; .DB 0 ; SECTOR (0-255)
; .DB 0 ; HEAD (0-127)
;
; LBA:
; .DW 0 ; LBA LOW WORD
; .DW 0 ; LBA HIGH WORD
;
; FULL 32 BIT LBA
HSTLBA .EQU $ ; REFERS TO START OF 32-BIT LBA
; LBA LOW WORD -OR- TRACK
HSTLBALO .EQU $ ; BLOCK ADDRESS LBA LOW WORD
HSTTRK .DW 0 ; CYLINDER (0-65535)
; LBA HIGH WORD -OR- HEAD/SECTOR
HSTLBAHI .EQU $ ; BLOCK ADDRESS LBA HIGH WORD
HSTSEC .DB 0 ; SECTOR (0-255)
HSTHEAD .DB 0 ; HEAD (0-255)
;
HEAPCURB .DW 0 ; MARK HEAP ADDRESS AFTER INITIALIZATION
;
HB_TICKS .FILL 4,0 ; 32 BIT TICK COUNTER
;
STR_BANNER .DB "RetroBrew HBIOS v", BIOSVER, ", ", TIMESTAMP, "$"
STR_PLATFORM .DB PLATFORM_NAME, "$"
STR_SWITCH .DB "*** Activating CRT Console ***$"
;
HB_CURSEC .DB 0
;
HB_BCDTMP .FILL 5,0 ; TEMPORARY BCD NUMBER STORAGE
;
HB_WRKBUF .FILL 512,0 ; INTERNAL DISK BUFFER
;
HB_END .EQU $
;
SLACK .EQU BNKTOP - $
.ECHO "HBIOS space remaining: "
.ECHO SLACK
.ECHO " bytes.\n"
;
#IFDEF ROMBOOT
.FILL SLACK
#ENDIF
;
.END