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.
 
 
 
 
 
 

570 lines
14 KiB

;=======================================================================
;
; XMHB.Z80 - XMODEM12 PATCH FILE FOR ROMWBW HBIOS
;
; Wayne Warthen - wwarthen@gmail.com
;
; 2020-05-23 WBW Rewrite for HBIOS FastPath(tm)
;
;=======================================================================
;
ASEG
;
BASE EQU 100H ; Start of CP/M normal program area
;
BDOS EQU 0005H ; BDOS function dispatch vector
;
;=======================================================================
;
; Jump table: The jump table must be in exactly the same sequence as the
; one in XMODEM. Note the ORG of 103H - This jump table has no jump to
; 'BEGIN'.
;
ORG BASE + 3 ; start after 'JMP BEGIN'
;
JP CONOUT ; must be 00000h if not used, see below
JP MINIT ; initialization routine (if needed)
JP UNINIT ; undo whatever 'MINIT' did (or return)
JPTBL:
JP SENDR ; send character (via pop psw)
JP CAROK ; test for carrier
JP MDIN ; receive data byte
JP GETCHR ; get character from modem
JP RCVRDY ; check receive ready
JP SNDRDY ; check send ready
JP SPEED ; get speed value for file transfer time
JP EXTRA1 ; extra for custom routine
JP EXTRA2 ; extra for custom routine
JP EXTRA3 ; extra for custom routine
;
;-----------------------------------------------------------------------
;
; Output character to console
;
CONOUT EQU 0 ; not used
;
;-----------------------------------------------------------------------
;
; Initialize modem
;
; This procedure has been usurped to dynamically detect the type
; of system we are running on and install the *real* jump table
; entries as appropriate.
;
MINIT:
; Announce
LD DE,TAG ; Tagline
LD C,9 ; BDOS string display function
CALL BDOS ; Do it
;
; Identify BIOS (RomWBW HBIOS or UNA UBIOS)
CALL IDBIO ; 1=HBIOS, 2=UBIOS
LD (BIOID),A ; Save it
DEC A ; Test for HBIOS
JR Z,HINIT ; Do HBIOS setup
DEC A ; Test for UBIOS
JR Z,UINIT ; Do UBIOS setup
;
; Neither UNA nor RomWBW
LD DE,ERR_BIO ; BIOS error message
LD C,9 ; BDOS string display function
CALL BDOS ; Do it
JP 0 ; Bail out!
;
MINIT_RET:
PUSH HL ; Save HL (JP table adr)
; Display port notification string
LD C,9 ; BDOS string display function
CALL BDOS ; Do it
;
; Declare experimental
LD DE,EXP_LBL ; Declare experimental
LD C,9 ; BDOS string display function
CALL BDOS ; Do it
;
; Newline
LD C,9 ; BDOS string display function
LD DE,CRLF ; Newline
CALL BDOS ; Do it
;
; Copy real vectors into active jump table
POP HL ; Recover HL
LD DE,JPTBL ; Real jump table is destination
LD BC,7 * 3 ; Copy 7 3-byte entries
LDIR ; Do the copy
;
; Return with CPU speed in A
LD A,(CPUSPD) ; A := CPU speed in MHz
LD HL,(RCVSCL) ; HL := receive scalar
RET ; and return
;
HINIT:
; Display RomWBW notification string
LD DE,HBTAG ; BIOS notification string
LD C,9 ; BDOS string display function
CALL BDOS ; Do it
;
; Get CPU speed from RomWBW HBIOS and save it
LD B,0F8H ; HBIOS SYSGET function 0xF8
LD C,0F0H ; CPUINFO subfunction 0xF0
RST 08 ; Do it, L := CPU speed in MHz
LD A,L ; Move it to A
LD (CPUSPD),A ; Save it
;
JP H_INIT ; Otherwise, use HBIOS I/O
;
UINIT:
; Display UNA notification string
LD DE,UBTAG ; BIOS notification string
LD C,9 ; BDOS string display function
CALL BDOS ; Do it
;
; Get CPU speed from UNA and save it
LD C,0F8H ; UNA BIOS Get PHI function
RST 08 ; Returns speed in Hz in DE:HL
LD B,4 ; Divide MHz in DE:HL by 100000H
UINIT1:
SRL D ; ... to get approx CPU speed in
RR E ; ...MHz. Throw away HL, and
DJNZ UINIT1 ; ...right shift DE by 4.
INC E ; Fix up for value truncation
LD A,E ; Put in A
LD (CPUSPD),A ; Save it
;
JP U_INIT ; UNA BIOS init
;
HWERR:
; Failed to identify target comm hardware
LD DE,ERR_HW ; Hardware error message
LD C,9 ; BDOS string display function
CALL BDOS ; Do it
JP 0 ; Bail out!
;
; Identify active BIOS. RomWBW HBIOS=1, UNA UBIOS=2, else 0
;
IDBIO:
;
; Check for UNA (UBIOS)
LD A,(0FFFDH) ; fixed location of UNA API vector
CP 0C3H ; jp instruction?
JR NZ,IDBIO1 ; if not, not UNA
LD HL,(0FFFEH) ; get jp address
LD A,(HL) ; get byte at target address
CP 0FDH ; first byte of UNA push ix instruction
JR NZ,IDBIO1 ; if not, not UNA
INC HL ; point to next byte
LD A,(HL) ; get next byte
CP 0E5H ; second byte of UNA push ix instruction
JR NZ,IDBIO1 ; if not, not UNA, check others
LD A,2 ; UNA BIOS id = 2
RET ; and done
;
IDBIO1:
; Check for RomWBW (HBIOS)
LD HL,(0FFFEH) ; HL := HBIOS ident location
LD A,'W' ; First byte of ident
CP (HL) ; Compare
JR NZ,IDBIO2 ; Not HBIOS
INC HL ; Next byte of ident
LD A,~'W' ; Second byte of ident
CP (HL) ; Compare
JR NZ,IDBIO2 ; Not HBIOS
LD A,1 ; HBIOS BIOS id = 1
RET ; and done
;
IDBIO2:
; No idea what this is
XOR A ; Setup return value of 0
RET ; and done
;
;-----------------------------------------------------------------------
;
; Uninitialize modem
;
UNINIT:
LD A,(BIOID)
CP 1 ; Is HBIOS?
JR Z,H_UNINIT ; Handle HBIOS
CP 2 ; Is UBIOS?
JR Z,U_UNINIT ; Handle UBIOS
RET ; Just return
;
H_UNINIT:
; HBIOS: Reset character device 0
LD B,04H ; HBIOS CIOINIT function 0x04
LD C,80H ; Unit = 80 (console)
LD DE,-1 ; Reset w/ current settings
RST 08 ; Do it
RET ; not initialized, so no 'UN-INITIALIZE'
;
U_UNINIT:
; UBIOS: Reset character device 0
LD C,10H ; UNA INIT function 0x10
LD B,0 ; Unit = 0
LD DE,-1 ; Reset w/ current settings
RST 08 ; Do it
RET ; not initialized, so no 'UN-INITIALIZE'
;
;-----------------------------------------------------------------------
;
; The following are all dummy routines that are unused because MINIT
; dynamically installs the real jump table.
;
SENDR:
CAROK:
MDIN:
GETCHR:
RCVRDY:
SNDRDY:
SPEED:
EXTRA1:
EXTRA2:
EXTRA3:
RET
;
BIOID DB 0 ; BIOS ID, 1=HBIOS, 2=UBIOS
CPUSPD DB 10 ; CPU speed in MHz
RCVSCL DW 6600 ; RECV loop timeout scalar
;
TAG DB "RomWBW, 23-May-2020$"
;
COM_LBL DB ", HBIOS FastPath on COM?:$"
EXP_LBL DB 13, 10, 13, 10, "*** Experimental ***$"
;
UBTAG DB " [UNA]$"
HBTAG DB " [WBW]$"
;
CRLF DB 13, 10, "$"
;
ERR_BIO DB 13, 10, 13, 10, "++ Unknown BIOS ++", 13, 10, "$"
ERR_HW DB 13, 10, 13, 10, "++ Unknown Hardware ++", 13, 10, "$"
;
;=======================================================================
;=======================================================================
;
; RomWBW HBIOS Interface
;
;=======================================================================
;=======================================================================
;
; Following jump table is dynamically patched over initial jump
; table at program startup. See MINIT above. Note that only a
; subset of the jump table is overlaid (SENDR to SPEED).
;
H_JPTBL:
JP H_SENDR ; send character (via pop psw)
JP H_CAROK ; test for carrier
JP H_MDIN ; receive data byte
JP H_GETCHR ; get character from modem
JP H_RCVRDY ; check receive ready
JP H_SNDRDY ; check send ready
JP H_SPEED ; get speed value for file transfer time
;
;-----------------------------------------------------------------------
;
; HBIOS initialization
;
H_INIT:
LD HL,2150 ; Smaller receive loop timeout scalar
LD (RCVSCL),HL ; ... to compensate for BIOS overhead
;
; Get HBIOS bank id
LD BC,0F8F2H ; HBIOS SYSGET, Bank Info
RST 08 ; do it
LD A,D ; BIOS bank id to A
LD (H_BNKID),A ; save it
;
; Patch SENDR w/ FastPath addresses
LD BC,0F801H ; Get CIO func/data adr
LD D,01H ; Func=CIO OUT
LD A,(H_UNIT) ; get desired char unit
LD E,A ; and put in E
RST 08
; handle error?
LD (H_SCDAT),DE ; Plug in data adr
LD (H_SCFN),HL ; Plug in func adr
;
; Patch GETCHR/MDIN w/ FastPath addresses
LD BC,0F801H ; Get CIO func/data adr
LD D,00H ; Func=CIO IN
LD A,(H_UNIT) ; get desired char unit
LD E,A ; and put in E
RST 08
; handle error?
LD (H_GCDAT),DE ; Plug in data adr
LD (H_GCFN),HL ; Plug in func adr
;
; Patch RCVRDY w/ FastPath addresses
LD BC,0F801H ; Get CIO func/data adr
LD D,02H ; Func=CIO IST
LD A,(H_UNIT) ; get desired char unit
LD E,A ; and put in E
RST 08
; handle error?
LD (H_RRDAT),DE ; Plug in data adr
LD (H_RRFN),HL ; Plug in func adr
;
; Patch SNDRDY w/ FastPath addresses
LD BC,0F801H ; Get CIO func/data adr
LD D,03H ; Func=CIO OST
LD A,(H_UNIT) ; get desired char unit
LD E,A ; and put in E
RST 08
; handle error?
LD (H_SRDAT),DE ; Plug in data adr
LD (H_SRFN),HL ; Plug in func adr
;
LD HL,H_JPTBL
LD DE,COM_LBL
JP MINIT_RET
;
;-----------------------------------------------------------------------
;
; Send character on top of stack
;
H_SENDR:
POP AF ; get character to send from stack
PUSH BC
PUSH DE
PUSH HL
LD E,A ; character to E
LD IY,0000H
H_SCDAT EQU $-2
LD A,(H_BNKID) ; call into HBIOS bank
LD HL,0000H
H_SCFN EQU $-2
CALL 0FFF9H ; HBIOS bank call
POP HL
POP DE
POP BC
RET
;
;-----------------------------------------------------------------------
;
; Test and report carrier status, Z set if carrier present
;
H_CAROK:
XOR A ; not used, always indicate present
RET
;
;-----------------------------------------------------------------------
;
; Get a character (assume character ready has already been tested)
;
; GETCHR must NOT block.
;
H_GETCHR:
CALL H_RCVRDY
RET NZ
H_MDIN:
PUSH BC
PUSH DE
PUSH HL
LD IY,0000H
H_GCDAT EQU $-2
LD A,(H_BNKID) ; call into HBIOS bank
LD HL,0000H
H_GCFN EQU $-2
CALL 0FFF9H ; HBIOS bank call
LD A,E ; byte received to A
POP HL
POP DE
POP BC
RET
;
;-----------------------------------------------------------------------
;
; Test for character ready to receive, Z = ready
; Error code returned in A register
; *** Error code does not seem to be used ***
;
H_RCVRDY:
PUSH BC
PUSH DE
PUSH HL
LD IY,0000H
H_RRDAT EQU $-2
LD A,(H_BNKID) ; call into HBIOS bank
LD HL,0000H
H_RRFN EQU $-2
CALL 0FFF9H ; HBIOS bank call
SUB 1 ; CF set IFF zero
RL A ; CF to bit 0 of A
AND 01H ; set Z flag as needed
LD A,0 ; report no line errors
POP HL
POP DE
POP BC
RET
;
;-----------------------------------------------------------------------
;
; Test for ready to send a character, Z = ready
;
H_SNDRDY:
PUSH BC
PUSH DE
PUSH HL
LD IY,0000H
H_SRDAT EQU $-2
LD A,(H_BNKID) ; call into HBIOS bank
LD HL,0000H
H_SRFN EQU $-2
CALL 0FFF9H ; HBIOS bank call
SUB 1 ; CF set IFF zero
RL A ; CF to bit 0 of A
AND 01H ; set Z flag as needed
POP HL
POP DE
POP BC
RET
;
;-----------------------------------------------------------------------
;
; Report baud rate (index into SPTBL returned in register A)
;
H_SPEED:
LD A,8 ; arbitrarily return 9600 baud
RET
;
;
;
H_BNKID DB 0 ; HBIOS bank id
H_UNIT DB 80H ; HBIOS unit id
;
;
;=======================================================================
;=======================================================================
;
; UNA UBIOS Interface
;
;=======================================================================
;=======================================================================
;
; Following jump table is dynamically patched over initial jump
; table at program startup. See MINIT above. Note that only a
; subset of the jump table is overlaid (SENDR to SPEED).
;
U_JPTBL:
JP U_SENDR ; send character (via pop psw)
JP U_CAROK ; test for carrier
JP U_MDIN ; receive data byte
JP U_GETCHR ; get character from modem
JP U_RCVRDY ; check receive ready
JP U_SNDRDY ; check send ready
JP U_SPEED ; get speed value for file transfer time
;
;-----------------------------------------------------------------------
;
; UBIOS initialization
;
U_INIT:
;
; TODO:
; - TEST!!!
; - ADJUST RCVSCL?
;
LD HL,3000 ; Smaller receive loop timeout scalar
LD (RCVSCL),HL ; ... to compensate for BIOS overhead
;
LD HL,U_JPTBL
LD DE,COM_LBL
JP MINIT_RET
;
;-----------------------------------------------------------------------
;
; Send character on top of stack
;
U_SENDR:
POP AF ; get character to send from stack
PUSH BC
PUSH DE
PUSH HL
LD BC,0012H ; unit 0, func 12h (write char)
LD E,A ; character to E
RST 08
POP HL
POP DE
POP BC
RET
;
;-----------------------------------------------------------------------
;
; Test and report carrier status, Z set if carrier present
;
U_CAROK:
XOR A ; not used, always indicate present
RET
;
;-----------------------------------------------------------------------
;
; Get a character (assume character ready has already been tested)
;
; GETCHR must NOT block.
;
U_GETCHR:
CALL U_RCVRDY
RET NZ
U_MDIN:
PUSH BC
PUSH DE
PUSH HL
LD BC,0011H ; unit 0, func 12h (write char)
RST 08
LD A,E ; byte received to A
POP HL
POP DE
POP BC
RET
;
;-----------------------------------------------------------------------
;
; Test for character ready to receive, Z = ready
; Error code returned in A register
; *** Error code does not seem to be used ***
;
U_RCVRDY:
PUSH BC
PUSH DE
PUSH HL
LD BC,0013H ; unit 0, func 13h (input stat)
LD A,E ; # chars waiting to A
SUB 1 ; CF set IFF zero
RL A ; CF to bit 0 of A
AND 01H ; set Z flag as needed
LD A,0 ; report no line errors
POP HL
POP DE
POP BC
RET
;
;-----------------------------------------------------------------------
;
; Test for ready to send a character, Z = ready
;
U_SNDRDY:
PUSH BC
PUSH DE
PUSH HL
LD BC,0014H ; unit 0, func 14h (output stat)
LD A,E ; # chars space in output buf
SUB 1 ; CF set IFF zero
RL A ; CF to bit 0 of A
AND 01H ; set Z flag as needed
POP HL
POP DE
POP BC
RET
;
;-----------------------------------------------------------------------
;
; Report baud rate (index into SPTBL returned in register A)
;
U_SPEED:
LD A,8 ; arbitrarily return 9600 baud
RET
;
END