BPBIOS Sources From Jörg Linder

Jörg Linder has disassembled and thoroughly commented a great deal of the BPBIOS binaries.   This was an incredible amount of work.  I have added all of these to the RomWBW build scripts and will ultimately integrate them more completely.
This commit is contained in:
Wayne Warthen
2025-06-16 20:19:07 -07:00
parent eefb0d2df1
commit bccd80882c
68 changed files with 22402 additions and 68 deletions

View File

@@ -15,8 +15,7 @@ as needed. The RomWBW ASSIGN command is not supported. BPBIOS
will boot from the first hard disk unit number you assign and
always from the first slice.
BPBIOS does not yet understand the 1024 directory entry
hard disk format. You must use the 512 directory entry
format images.
BPBIOS is hard-coded to use the 1024 directory entry hard disk
format (hd1k). The hd512 format is not supported at all.
--WBW 1:25 PM 10/7/2021
--WBW 5:04 PM 6/16/2025

View File

@@ -2,6 +2,7 @@
setlocal
pushd ZCPR33 && call Build || exit /b & popd
pushd UTIL && call Build || exit /b & popd
set TOOLS=..\..\Tools
set PATH=%PATH%;%TOOLS%\zxcc;%TOOLS%\cpmtools;

View File

@@ -11,3 +11,4 @@ if exist *.bak del *.bak
if exist def-ww.lib del def-ww.lib
pushd ZCPR33 && call Clean.cmd & popd
pushd UTIL && call Clean.cmd & popd

View File

@@ -13,7 +13,7 @@ OTHERS = zcpr33.rel bp*.prn bp*.rel \
TOOLS = ../../Tools
SUBDIRS = ZCPR33
SUBDIRS = ZCPR33 UTIL
include $(TOOLS)/Makefile.inc
zcpr33.rel:

View File

@@ -0,0 +1,55 @@
@echo off
setlocal
set TOOLS=..\..\..\Tools
set PATH=%PATH%;%TOOLS%\zxcc;%TOOLS%\cpmtools;
set CPMDIR80=%TOOLS%/cpm/
zxcc Z80ASM -BPBUILD/RFS || exit /b
zxcc SLRNK -BPBUILD/N,/A:100,/D:23E0,BPBUILD,B:SLINK0,B:VLIBS/S,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b
zxcc Z80ASM -BPCNFG/RFS || exit /b
zxcc SLRNK -BPCNFG/N,/A:100,/D:3A55,BPCNFG,B:VLIBS/S,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b
zxcc Z80ASM -BPSWAP/RFS || exit /b
zxcc SLRNK -BPSWAP/N,/A:100,/D:0854,BPSWAP,B:VLIBS/S,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b
zxcc Z80ASM -BPSYSGEN/RFS || exit /b
zxcc SLRNK -BPSYSGEN/N,/A:100,/D:08CD,BPSYSGEN,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b
zxcc Z80ASM -CONFZ4/RFS || exit /b
zxcc SLRNK -CONFZ4/N,/A:100,/D:080A,CONFZ4,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b
zxcc Z80ASM -HASHINI/RFS || exit /b
zxcc SLRNK -HASHINI/N,/A:100,/D:09E5,HASHINI,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b
zxcc Z80ASM -LDSYS/RFS || exit /b
zxcc SLRNK -LDSYS/N,/A:100,/D:0CF8,LDSYS,B:VLIBS/S,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b
zxcc Z80ASM -SHOWHD/RFS || exit /b
zxcc SLRNK -SHOWHD/N,/A:100,/D:064D,SHOWHD,B:SYSLIBS/S,/E || exit /b
zxcc Z80ASM -SIZERAM/RFS || exit /b
zxcc SLRNK -SIZERAM/N,/A:100,/D:0750,SIZERAM,B:VLIBS/S,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b
zxcc Z80ASM -ZSCFG2/RFS || exit /b
zxcc SLRNK -ZSCFG2/N,/A:100,/D:145E,ZSCFG2,B:VLIBS/S,B:Z3LIBS/S,B:SYSLIBS/S,/E || exit /b
:: zxcc Z80ASM
:: zxcc ZMAC -zcpr33.z80 -/P || exit /b

View File

@@ -0,0 +1,6 @@
@echo off
setlocal
if exist *.com del *.com
if exist *.lst del *.lst
if exist *.rel del *.rel

View File

@@ -0,0 +1,40 @@
OBJECTS = bpbuild.com bpcnfg.com bpswap.com bpsysgen.com confz4.com hashini.com \
ldsys.com showhd.com sizeram.com zscfg2.com
TOOLS = ../../../Tools
# DEST = ..
OTHERS = *.rel
include $(TOOLS)/Makefile.inc
%.rel: %.z80
@$(ZXCC) $(CPM)/Z80ASM -$(basename $<)/RFS
bpbuild.com : bpbuild.rel
$(ZXCC) slrnk -bpbuild/n,/a:100,/d:23e0,bpbuild,b:slink0,b:vlibs/s,b:z3libs/s,b:syslibs/s,/e
bpcnfg.com : bpcnfg.rel
$(ZXCC) slrnk -bpcnfg/n,/a:100,/d:3a55,bpcnfg,b:vlibs/s,b:z3libs/s,b:syslibs/s,/e
bpswap.com : bpswap.rel
$(ZXCC) slrnk -bpswap/n,/a:100,/d:0854,bpswap,b:vlibs/s,b:z3libs/s,b:syslibs/s,/e
bpsysgen.com : bpsysgen.rel
$(ZXCC) slrnk -bpsysgen/n,/a:100,/d:08cd,bpsysgen,b:z3libs/s,b:syslibs/s,/e
confz4.com : confz4.rel
$(ZXCC) slrnk -confz4/n,/a:100,/d:080a,confz4,b:z3libs/s,b:syslibs/s,/e
hashini.com : hashini.rel
$(ZXCC) slrnk -hashini/n,/a:100,/d:09e5,hashini,b:z3libs/s,b:syslibs/s,/e
ldsys.com : ldsys.rel
$(ZXCC) slrnk -ldsys/n,/a:100,/d:0cf8,ldsys,b:vlibs/s,b:z3libs/s,b:syslibs/s,/e
showhd.com : showhd.rel
$(ZXCC) slrnk -showhd/n,/a:100,/d:064d,showhd,b:syslibs/s,/e
sizeram.com : sizeram.rel
$(ZXCC) slrnk -sizeram/n,/a:100,/d:0750,sizeram,b:vlibs/s,b:z3libs/s,b:syslibs/s,/e
zscfg2.com : zscfg2.rel
$(ZXCC) slrnk -zscfg2/n,/a:100,/d:145e,zscfg2,b:vlibs/s,b:z3libs/s,b:syslibs/s,/e

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,483 @@
TITLE "Swap drives under B/P Bios"
;************************************************************************
;* B P S W A P *
;* Swap two drive letters in a running B/P Bios system *
;* by Harold F. Bower and Cameron W. Cotrill *
;*----------------------------------------------------------------------*
;* Disassembly: jxl Dec 2024 *
;* public release 1.0 Apr 2025 *
;* see remarks at the end *
;*----------------------------------------------------------------------*
;* LINK with Version 4 libraries: VLIB, Z3LIB, SYSLIB *
;* *
;* A>Z80ASM BPSWAP/RS *
;* A>SLRNK BPSWAP/N,/A:100,/D:0854,BPSWAP,VLIBS/S,Z3LIBS/S,SYSLIBS/S,/E *
;************************************************************************
VER EQU 10
REV EQU ' '
DATE MACRO
DEFB '31 Aug 92'
ENDM
CTRLC EQU 03H ; Control-C character
BEL EQU 07H ; Bell character
TAB EQU 09H ; Tab character
LF EQU 0AH ; Line Feed character
CR EQU 0DH ; Carriage Return character
CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP)
CPMBDOS EQU 5 ; CP/M BDOS entry point (JP)
CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype)
CPMDMA EQU 80H ; CP/M standard DMA buffer
; From VLIB Get..
EXTRN VPRINT, Z3VINIT
; From Z3LIB Get..
EXTRN GETNAME, PRTNAME, WHRENV
; From SYSLIB Get..
EXTRN CRLF, CAPINE, COUT
;::::: PROGRAM START
ORG 100H
CSEG
BPSWAP: JP START ; bypass header
DEFB 'Z3ENV' ; this is a ZCPR3 utility
DEFB 1 ; show external environment
ENVADR: DEFW 0 ; addr of Z3 environment
START: LD HL,(CPMBDOS) ; ##### BUG: should be CPMBDOS+1 ?
CALL WHRENV ; find Z3 Environment Descriptor
LD (ENVADR),HL ; store addr
CALL Z3VINIT ; ..and init for Z3LIB routines
CALL GETNAME ; get actual program name
CALL GQFLAG
AND A ; running in quiet mode ?
JR NZ,START0 ; ..if so, skip over
CALL VPRINT
DEFB 1,'B/P Drive Swap',2,' V',VER/10+'0','.',VER MOD 10 + '0',', '
DATE
DEFB CR,LF
DEFB 0
START0: LD (STACK),SP
LD SP,STACK
; get first token from command line (in FCB #1)
LD A,(CPMFCB+1) ; get char
CP '/' ; is this a help request ?
JP Z,HELP ; ..if so, show help screen
LD HL,(CPMBIOS+1) ; get warm boot addr (BIOS fn #1)
LD L,30*3 ; adjust ptr to fn #30
LD A,(HL) ; check byte at ptr location
CP 0C3H ; is it opcode 0xC3 (JP) ?
JR NZ,E$BPBIO ; ..if not, jump error and exit
CALL JUMPHL ; else, "call" B/P Bios fn #30 (RETBIO)
LD (BPBASE),BC ; store B/P Bios base addr
LD HL,-6 ; move ptr 6 bytes backward
ADD HL,DE ; (signature string)
LD A,(HL) ; get byte
CP 'B' ; is it 'B' ?
JR NZ,E$BPBIO ; ..if not, error and exit
INC HL ; ptr fwd
LD A,(HL) ; get byte
CP '/' ; is it '/' ?
JR NZ,E$BPBIO ; ..if not, error and exit
INC HL ; ptr fwd
LD A,(HL) ; get byte
CP 'P' ; is it 'P' ?
JR Z,EVALCMD ; ..if so, jump to continue
; else, fall through (error and exit)
E$BPBIO: CALL VPRINT
DEFB CR,LF,BEL,'+++ Not B/P Bios ... aborting +++',CR,LF
DEFB 0
JP EXIT
; evaluate command line
EVALCMD: LD HL,CPMDMA ; ptr to standard DMA buffer (holds command line)
LD A,(HL) ; get length of first token
INC HL ; +1
CALL ADDHLA ; move ptr fwd
LD (HL),0 ; set <NUL> terminator
LD HL,CPMDMA+1 ; set ptr to start of string
CALL FINDDRV ; find letter of first drive
JR C,RUNIMOD ; ..if invalid/not found, switch to interactive mode
LD (DRV1ST),A ; else, store # of first drive
LD A,(HL) ; get following byte
CALL EVALSEP ; is it a separator char ?
JP C,M$ABORT ; ..if not, abort program
CALL FINDDRV ; find letter of second drive
JR C,RUNIM0 ; ..if invalid/not found, switch to interactive mode
LD (DRV2ND),A ; else, store # of second drive
LD A,(HL) ; get following byte
CALL EVALSEP ; is it a separator char ?
JP C,M$ABORT ; ..if not, abort program
JR SWAPDRV ; else, jump to continue
; run in interactive mode
RUNIMOD: CALL VPRINT
DEFB ' First Drive to Swap [A..P] : '
DEFB 0
CALL CAPINE ; get input
CALL CRLF
CP CTRLC ; is it <Ctrl-C> ?
JP Z,M$ABORT ; ..if so, abort program
CALL EVALDRV ; check if drive letter is valid (A..P)
JR C,RUNIMOD ; ..if not, loop ask for new input
LD (DRV1ST),A ; else, store drive #
RUNIM0: CALL VPRINT
DEFB ' Second Drive to Swap [A..P] : '
DEFB 0
CALL CAPINE ; get input
CALL CRLF
CP CTRLC ; is it <Ctrl-C> ?
JP Z,M$ABORT ; ..if so, abort program
CALL EVALDRV ; check if drive letter is valid (A..P)
JR C,RUNIM0 ; ..if not, loop ask for new input
LD (DRV2ND),A ; else, store drive #
;::::: PROCESS
SWAPDRV: LD HL,(BPBASE) ; get B/P Bios base addr
LD L,22*3 ; adjust ptr to fn #22 (DRVTBL)
CALL JUMPHL ; ..and "call" fn
PUSH HL ; save ptr to DRVTBL
LD A,(DRV1ST) ; get # of first drive
ADD A,A ; *2 for 16-bit entries
CALL ADDHLA ; ..and move ptr fwd
EX DE,HL ; swap regs
POP HL ; restore ptr to DRVTBL
LD A,(DRV2ND) ; get # of second drive
ADD A,A ; *2
CALL ADDHLA ; ..and move ptr fwd
; DE= addr DPH first drive
; HL= addr DPH second drive
LD C,(HL) ; swap addr's in DRVTBL using
LD A,(DE) ; regs DE, HL as pointers
LD (HL),A ; and regs A, C holding bytes to copy
LD A,C
LD (DE),A
INC HL
INC DE
LD C,(HL)
LD A,(DE)
LD (HL),A
LD A,C
LD (DE),A
LD HL,0
LD (PDRVVCT),HL ; init new Drive Vector (pos) with 0x0000
DEC HL
LD (NDRVVCT),HL ; init new Drive Vector (neg) with 0xFFFF
LD HL,(ENVADR) ; get ENV addr
LD DE,52 ; offset to Drive Vector
ADD HL,DE ; move ptr
PUSH HL ; ..and save it
LD E,(HL) ; get Drive Vector in DE
INC HL
LD D,(HL)
LD A,(DRV1ST) ; get # of first drive
CALL MKDRMSK ; get bit mask for first drive
LD C,L ; ..and move it to BC
LD B,H
LD A,(DRV2ND) ; get # of second drive
CALL MKDRMSK ; get bit mask for second drive
EX DE,HL ; ..and move it to DE
CALL MKVCMSK ; update new Drive Vector for first drive
PUSH BC ; swap BC and DE
PUSH DE
POP BC
POP DE
CALL MKVCMSK ; update new Drive Vector for second drive
; (Stack) = addr of Drive Vector in ENV - PUSH HL
; HL= current Drive Vector, DE= bit mask first drive, BC= bit mask second drive
EX DE,HL ; swap regs (save current Drive Vector in DE)
ADD HL,BC ; add/merge bit masks
EX (SP),HL ; put merged mask on stack - used by SWAPDRX
; get addr of Drive Vector in ENV
PUSH HL ; ..and save it
EX DE,HL ; swap regs back (current Drive Vector in HL)
LD BC,(PDRVVCT) ; get new Drive Vector (pos)
LD DE,(NDRVVCT) ; and (neg)
LD A,L ; low byte of current Drive Vector
AND E ; reset bit (neg)
OR C ; set bit (pos)
LD E,A ; ..and store result in E
LD A,H ; high byte of current Drive Vector
AND D ; reset bit (neg)
OR B ; set bit (pos)
LD D,A ; ..and store result in D
POP HL ; get addr of Drive Vector in ENV
LD (HL),E ; store new Drive Vector (low byte)
INC HL
LD (HL),D ; ..and high byte
CALL GQFLAG
OR A ; check quiet flag
JR NZ,SWAPDRX ; ..if quiet mode, skip over
CALL VPRINT
DEFB ' ...Drives '
DEFB 0
LD A,(DRV1ST) ; get # of first drive
ADD A,'A' ; make ascii letter
CALL COUT ; ..and display it
CALL VPRINT
DEFB ': and '
DEFB 0
LD A,(DRV2ND) ; get # of second drive
ADD A,'A' ; make ascii letter
CALL COUT ; ..and display it
CALL VPRINT
DEFB ': exchanged',CR,LF
DEFB 0
; exit function
SWAPDRX: POP DE ; restore merged bit masked 1st+2nd drive
LD C,37 ; BDOS fn #37 Reset Drive(s)
CALL CPMBDOS
JP EXIT
M$ABORT: CALL VPRINT
DEFB ' ...aborting...',CR,LF
DEFB 0
JP EXIT
;::::: HELP SCREEN
HELP: CALL VPRINT
DEFB CR,LF,1
DEFB 0
CALL PPRGNAM
CALL VPRINT
DEFB 2,' exchanges the logical definition '
DEFB 'of two physical disk drives',CR,LF
DEFB ' or partitions. Drive letters must be '
DEFB 'in the range of "A"-"P".',CR,LF
DEFB ' The program is re-executable under '
DEFB 'ZCPR with the "GO" command',CR,LF,LF
DEFB ' Syntax: '
DEFB 0
CALL PPRGNAM
CALL VPRINT
DEFB ' <Drv1>[:] <tab| |,> <Drv2>[:]',CR,LF,LF
DEFB ' Examples:',CR,LF,' '
DEFB 0
CALL PPRGNAM
CALL VPRINT
DEFB ' A: E: - Exchange E drive with A',CR,LF
DEFB ' '
DEFB 0
CALL PPRGNAM
CALL VPRINT
DEFB ' D,H - Exchange D drive with H',CR,LF
DEFB ' '
DEFB 0
CALL PPRGNAM
CALL VPRINT
DEFB ' // - display this message',CR,LF
DEFB 0
;::::: EXIT PROGRAM
EXIT: LD SP,(STACK) ; restore stack
RET ; ..and return to system
;::::: SUPPORT FUNCTIONS
; "called" as a pseudo-routine that returns to caller
; in: HL= target addr
JUMPHL: JP (HL) ; jump to addr in HL regs
; parse nul-terminated string skipping separator chars
; then fall through and check/convert drive letter
; in: HL= ptr to string
; out: A= drive number (or <NUL> if invalid letter)
; HL= ptr to byte after end of string
; C-Flag set if <NUL> (end of string) reached
FINDDRV: LD A,(HL) ; get byte
INC HL ; move ptr fwd
OR A ; check if <NUL> (zero) = end of string
SCF ; prepare status indicator (C-Flag set)
RET Z ; ..if <NUL> byte, return
CALL EVALSEP ; check if byte is a separator
JR NC,FINDDRV ; ..if so, get next char
; else, fall through and check if letter is valid
; evaluate if letter is a valid drive (A..P) and return as number
; in: A= letter to check
; out: A= drive number
; C-Flag set if error, NC= ok
EVALDRV: CP 'A' ; is it lower than ascii 'A' ?
RET C ; ..return with C-Flag already set
CP 'P'+1 ; is it greater than ascii 'P' ?
CCF ; ..reverse C-Flag to set correct status
RET C ; and return
SUB 'A' ; else, convert to number
RET
; evaluate char in register A whether it is a separator
; (space, comma, colon, tab, zero)
; in: A= char
; out: C-Flag set if not separator, NC= char is separator
EVALSEP: CP ' ' ; is it <SP> ?
RET Z
CP ',' ; Comma ?
RET Z
CP ':' ; Colon ?
RET Z
CP TAB ; <TAB> ?
RET Z
OR A ; <NUL> (zero) ?
RET Z
SCF ; set C-Flag
RET
; make bit mask for specified drive #
; position of 1-bit represents drive in 16-bit word (similar to Drive Vector)
; in: A= drive number
; out: HL= bit mask
MKDRMSK: LD HL,1 ; set bit 0
INC A ; ahead of loop, increase A
MKDRMS0: DEC A ; decrease A
RET Z ; ..if zero, finished
ADD HL,HL ; *2 (shift 1-bit to next position)
JR MKDRMS0 ; loop
; make bit masks for new Drive Vector
; maintaining a positive (bits set) map, and a negate version (bits reset)
; in: HL= current Drive Vector (from ENV)
; BC= bit mask w/ old position
; DE= bit mask w/ new position
MKVCMSK: PUSH BC ; save regs
LD A,B
AND H ; mask high byte
LD B,A ; ..and store result back in B
LD A,C
AND L ; mask low byte
OR B ; check if invalid (= zero), ie. not mapped in Vector
POP BC ; restore regs
JR Z,MKVCMS0 ; if invalid drive, jump
; drive at new position exists in Drive Vector - set bit
PUSH HL
LD HL,(PDRVVCT)
LD A,H ; high byte first
OR D ; ..merge with new position
LD H,A ; and store result back in H
LD A,L ; low byte
OR E ; ..merge with new position
LD L,A ; and store result back in L
LD (PDRVVCT),HL ; save final result
POP HL
RET
; drive at new position does _not_ exist in Drive Vector - reset bit
MKVCMS0: PUSH HL
LD HL,(NDRVVCT)
LD A,D ; get high byte of new position
CPL ; invert it
AND H ; reset corresponding bit
LD H,A ; ..and store result in H
LD A,E ; get low byte of new position
CPL ; invert it
AND L ; reset corresponding bit
LD L,A ; ..and store result in L
LD (NDRVVCT),HL ; save final result
POP HL
RET
; get Quiet Flag from Z3 Environment
; in: -
; out: A= Quiet Flag, defaults to A= 0 (not quiet)
GQFLAG: LD HL,(ENVADR) ; get ENV addr
LD A,H ; check if invalid (= zero)
OR L
RET Z ; ..if so, return
LD A,40 ; else, move ptr forward
CALL ADDHLA ; to Quiet Flag
LD A,(HL) ; get value
RET ; ..and return
; add A to HL (result in HL)
ADDHLA: ADD A,L ; add L
LD L,A ; store result in L
RET NC ; ..if no overflow, return
INC H ; else, increment H
RET
; print program name on CON: device
; (either the actual name, or fallback to default)
; only used by HELP
PPRGNAM: LD A,(ENVADR+1) ; get high byte of ENVPTR
OR A ; check if valid (<> zero)
JP NZ,PRTNAME ; ..if so, display actual name
; and let return from there
CALL VPRINT ; else, display default
DEFB 'BPSWAP'
DEFB 0
RET
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
; VLIB - 0x0536
; Z3LIB - 0x0757
; SYSLIB - 0x0805
; end addr 0x0854 (begin DSEG)
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
;::::: RAM STORAGE
DSEG
PDRVVCT: DEFW 0 ; new Drive Vector
; (positive notation, bit _set_ for existing drives)
NDRVVCT: DEFW 0 ; new Drive Vector
; (negative notation, bits _reset_ for existing drives)
BPBASE: DEFW 0 ; B/P Bios base addr
DRV1ST: DEFB 0 ; # of first drive
DRV2ND: DEFB 0 ; # of second drive
DEFS 40H ; room for stack
STACK: DEFW 0 ; stack storage location
END
;************************************************************************
; Remarks jxl:
; BPSWAP.COM, included in available B/P Bios package(s), was dis-
; assembled and extensively commented. Labels are up to seven chars long
; to comply with M-REL standards. However, it is recommended to use SLR
; tools that support labels up to sixteen chars.
; In its current state, the compiled/linked file matches exactly the
; original BPSWAP.COM, i.e. no changes to the source were made. There
; seems to be one bug (marked with "##### BUG") at the beginning of the
; program.
;************************************************************************

View File

@@ -0,0 +1,636 @@
TITLE "Write B/P Bios System to system tracks of a disk"
;************************************************************************
;* B P S Y S G E N *
;* Copy B/P Bios based Operating System to system tracks *
;* by Harold F. Bower and Cameron W. Cotrill *
;*----------------------------------------------------------------------*
;* Disassembly: jxl Dec 2024 *
;* public release 1.0 Apr 2025 *
;* see remarks at the end *
;*----------------------------------------------------------------------*
;* LINK with Version 4 libraries: VLIB, Z3LIB, SYSLIB *
;* *
;* A>Z80ASM BPSYSGEN/RS *
;* A>SLRNK BPSYSGEN/N,/A:100,/D:08CD,BPSYSGEN,Z3LIBS/S,SYSLIBS/S,/E *
;************************************************************************
VER EQU 10
REV EQU ' '
DATE MACRO
DEFB '31 Aug 92'
ENDM
CTRLC EQU 03H ; Control-C character
BEL EQU 07H ; Bell character
LF EQU 0AH ; Line Feed character
CR EQU 0DH ; Carriage Return character
CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP)
CPMBDOS EQU 5 ; CP/M BDOS entry point (JP)
CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype)
CPMFCB2 EQU 6CH ; CP/M standard FCB #2
; From Z3LIB Get..
EXTRN GETNAME, PRTNAME, Z3INIT, WHRENV
; From SYSLIB Get..
EXTRN PUTUD, GETUD, SUA, EPRINT, CRLF, CAPINE, CIN, COUT
;::::: PROGRAM START
ORG 100H
CSEG
BPSYSGEN: JP START ; bypass header
DEFB 'Z3ENV' ; this is a ZCPR3 utility
DEFB 1 ; show external environment
ENVADR: DEFW 0 ; addr of Z3 environment
START: LD HL,(CPMBDOS+1) ; BDOS entry as starting point for Z3ENV search
CALL WHRENV ; get Z3 Environment
LD (ENVADR),HL ; ..store it
CALL Z3INIT ; init ENV ptr for Z3LIB modules
CALL GETNAME ; get actual program name
CALL GETQFLG ; check ENV quiet flag
AND A ; zero means 'verbose' i.e. not quiet
JR NZ,START1 ; ..if quiet mode, skip msg
START0: CALL EPRINT
DEFB 'B/P SYSGEN Utility V',VER/10+'0','.',VER MOD 10 + '0',REV
DATE
DEFB CR,LF,LF
DEFB 0
START1: CALL PUTUD ; currently logged in drive/user
LD HL,RESDISK ; prepare exit with resetting disk system
PUSH HL ; by putting addr of 'RESDISK' on stack
LD HL,(CPMBIOS+1) ; get BIOS entry addr
LD A,8*3 ; move forward to fn #9 SELDSK
CALL ADDHLA
LD DE,BIOSELD ; ptr to target addr
LD BC,8*3 ; bytes to copy (8 JP instructions, 3 bytes each)
LDIR ; ..copy
; Evaluate command line (if invalid parameters, switch to interactive mode)
EVALCMD: LD HL,CPMFCB ; set ptr to standard FCB #1
LD A,(HL) ; get drive
LD (SRCDRV),A ; ..and store it (SRC)
INC HL ; move ptr forard
LD A,(HL) ; get byte/char
CP '/' ; is this a help request ?
JP Z,HELP ; ..if so, jump display help
; ..and quit (addr of exit routine on stack)
; syntax: BPSYSGEN [d:]fn[.ft] [d:]
; drive #1 = source, drive #2 = destination
LD A,(CPMFCB2) ; get first byte of standard FCB #2
LD (DSTDRV),A ; store drive # (DEST)
LD (DSTDR2),A ; ..and a copy (as indicator for cmdline input)
LD B,A ; remember value
LD A,(HL) ; get first char of filename in FCB #1
CP ' ' ; is it <SP> ?
JP NZ,SRCRD0 ; ..if not, jump read sys file
LD A,B ; else, restore char (from FCB #2)
AND A ; is it <NUL> ?
JP NZ,SRCREAD ; ..if not, jump read sys tracks
; else, no source specified in command line
; (switch to interactive mode)
LD A,(SRCDRV) ; get source drive number
LD (DSTDRV),A ; ..and overwrite destination drive number
;::::: SOURCE DRIVE
; interactive mode
SRCINP: CALL EPRINT
DEFB 'Source Drive (CR to skip)? '
DEFB 0
CALL CAPINE ; get user input
CALL CRLF
CP CR ; is it <CR> ?
JP Z,SRCRD1 ; ..if so, skip
SUB 40H ; else, convert ascii to number
LD (SRCDRV),A ; ..and store it
CALL EPRINT
DEFB 'Place source disk in drive '
DEFB 0
LD A,(SRCDRV) ; get source drive number
ADD A,40H ; convert to ascii
CALL COUT ; ..and display it
CALL EPRINT
DEFB ': and press return to continue...'
DEFB 0
SRCINP0: CALL CIN ; get input
CP CTRLC ; is it <Ctrl-C> ?
RET Z ; ..if so, return
CP CR ; <CR> ?
JR NZ,SRCINP0 ; ..if not, loop ask for new input
CALL CRLF
; start reading
SRCREAD: CALL RDTRACK ; read system tracks of source disk
JR SRCRD1 ; ..and skip over
SRCRD0: CALL RDFILE ; read system file
SRCRD1: CALL CHKSYS ; check if a valid system was loaded/read
; (fn _not_ implemented, simply returns)
JP NZ,E$NOSYS ; ..if not, jump error and exit
LD A,(DSTDRV) ; get # of destination disk
AND A
JP NZ,DSTINP0 ; ..if not empty (= zero), jump to continue
; else, fall through and ask user
;::::: DESTINATION DRIVE
; interactive mode
DSTINP: CALL EPRINT
DEFB CR,LF,'Destination Drive (^C quits)? '
DEFB 0
CALL CAPINE ; get user input
CP CTRLC ; is it <Ctrl-C> ?
RET Z ; ..if so, return
SUB 40H ; else, convert ascii to number
LD (DSTDRV),A ; ..and store it
CALL CRLF
DSTINP0: LD A,(DSTDR2) ; get copy of # destination disk
AND A ; check if valid
JR NZ,DSTWRIT ; ..if so, running in command line mode
; ..continue writing to destination immediately
; else, fall through and ask user for input
CALL EPRINT
DEFB 'Place destination disk in drive '
DEFB 0
LD A,(DSTDRV) ; get destination drive number
ADD A,40H ; convert to ascii
CALL COUT ; ..and display it
CALL EPRINT
DEFB ': and press return to continue...'
DEFB 0
DSTINP1: CALL CIN ; get input
CP CTRLC ; is it <Ctrl-C> ?
RET Z ; ..if so, return
CP CR ; <CR> ?
JR NZ,DSTINP1 ; ..if not, loop ask for new input
CALL CRLF
; start writing
; exit through "RET", addr of RESDISK routine is on stack
DSTWRIT: CALL WRTRACK
CALL GETQFLG
AND A ; check if quiet flag is set
RET NZ ; ..if not (= verbose), exit program
LD A,(DSTDR2) ; else, get copy of # dest. disk (indicator cmdline mode)
AND A ; check if valid
RET NZ ; ..if not, exit program
JP DSTINP ; else, loop ask for input
; initiate a reset of disk system when returning to system
RESDISK: LD C,13 ; BDOS fn #13 (reset disk system)
CALL CPMBDOS
JP GETUD ; set Drive/User and let return from there
;::::: HELP SCREEN
HELP: CALL PRGNAME
CALL EPRINT
DEFB ' Places a copy of the operating '
DEFB 'system onto the system',CR,LF
DEFB ' tracks of a drive on the system.',CR,LF,LF
DEFB ' Syntax: '
DEFB 0
CALL PRGNAME
CALL EPRINT
DEFB ' [DIR:[Ufn.Ft]] [D:]',CR,LF,LF
DEFB ' Examples:',CR,LF,LF
DEFB ' '
DEFB 0
CALL PRGNAME
CALL EPRINT
DEFB ' - Execute in Interactive Mode',CR,LF
DEFB ' '
DEFB 0
CALL PRGNAME
CALL EPRINT
DEFB ' A: - Prompt for Source, '
DEFB 'Place System onto A',CR,LF
DEFB ' '
DEFB 0
CALL PRGNAME
CALL EPRINT
DEFB ' B:ZSDOS64.COM - Get System from File, '
DEFB 'Prompt for Drive',CR,LF
DEFB ' '
DEFB 0
CALL PRGNAME
CALL EPRINT
DEFB ' A: B: - Copy System from Drive A '
DEFB 'to Drive B',CR,LF
DEFB ' '
DEFB 0
CALL PRGNAME
CALL EPRINT
DEFB ' // - display this help',CR,LF
DEFB 0
RET
;::::: SUPPORT FUNCTIONS
; get Quiet Flag from Z3 Environment
; in: -
; out: A= Quiet Flag, defaults to A= 0 (not quiet)
GETQFLG: LD HL,(ENVADR) ; get local ENVPTR
LD A,H ; check if invalid (= zero)
OR L
RET Z ; ..if so, return
LD A,40 ; else, move ptr forward
CALL ADDHLA ; to Quiet Flag
LD A,(HL) ; get value
RET ; ..and return
; print program name on CON: device
; (either the actual name, or fallback to default)
; only used by HELP
PRGNAME: LD A,(ENVADR+1) ; get high byte of ENVPTR
OR A ; check if valid (<> zero)
JP NZ,PRTNAME ; ..if so, display actual name
; and let return from there
CALL EPRINT ; else, display default
DEFB 'BPSYSGEN'
DEFB 0
RET
; Read system tracks - source
RDTRACK: LD A,(SRCDRV) ; get source drive
CALL SELDRV ; and select it
JP Z,E$SRC ; ..if error, jump
LD (SRCDPH),HL ; store addr of DPH
LD A,10 ; move forward to DPB addr
CALL ADDHLA ; at DPH+10
LD E,(HL) ; get DPB addr in DE
INC HL
LD D,(HL)
EX DE,HL ; swap regs
LD (SRCDPB),HL ; ..and store DPB addr
LD E,(HL) ; get sectors per track in DE
INC HL ; at DPB+0
LD D,(HL)
LD (SECTTRK),DE ; store value
LD A,12 ; move forward to track offset
CALL ADDHLA ; (beginning of directory) at DPB+13
LD E,(HL) ; get track offset in DE
INC HL
LD D,(HL)
LD A,D ; check upper nybble
AND A ; is it zero ?
JP NZ,RDTRK0 ; ..if not, jump to adjust
OR E ; check lower nybble
JP Z,E$NOSYS ; ..if also zero, jump to error and exit
CP 4 ; check upper limit for # of system tracks
JR C,RDTRK1 ; ..if within boundaries, skip over
RDTRK0: LD DE,2 ; set (default) # of system tracks
RDTRK1: LD B,E ; trk offset in B (counter)
LD DE,(SECTTRK) ; get sect/trk
LD HL,0 ; set initial value
RDTRK2: ADD HL,DE ; multiply by addition
DJNZ RDTRK2 ; loop till done
XOR A ; nullify A
OR H ; check if H is zero
JP NZ,E$NOSYS ; ..if not, jump error and exit
PUSH HL ; save regs
LD BC,0
CALL BIOSTTR ; set track # 0
POP HL ; restore regs
LD C,H ; move # of sectors containing system
LD B,L ; to BC (as counter)
LD DE,0 ; set intial value
LD HL,FILEBUF ; set target addr to file buffer
; (at 0x0900, page-aligned after end of program)
RDTRK3: PUSH DE ; save regs
PUSH BC
PUSH HL
LD HL,(SRCDPH) ; get addr of DPH
LD E,(HL) ; get skew table ptr in DE
INC HL
LD D,(HL)
CALL BIOSTRN ; translate logical sector # in BC
LD B,H ; move physical sector # to BC
LD C,L
CALL BIOSTSE ; ..and set (physical) sector
POP BC ; restore target addr
PUSH BC
CALL BIOSTDM ; set as DMA buffer addr
CALL BIOREAD ; read one sector
OR A ; check for error (A <> 0)
JP NZ,E$READ ; ..if error, jump
POP HL ; restore target addr
LD DE,128 ; increase by 128 bytes (1 sector)
ADD HL,DE
POP BC ; restore regs / clear stack
POP DE
DEC B ; decrease counter
RET Z ; ..if finished, return
INC C
LD A,C
AND 00000011b ; mask lower 2 bits
LD A,'.'
CALL Z,COUT ; display progress every 4 sectors (0.5 kB)
LD A,(SECTTRK)
CP C ; max. # sect/trk reached ?
JR NZ,RDTRK3 ; ..if not, loop
INC DE ; increase trk counter
LD C,0 ; reset sect counter
PUSH DE ; save regs
PUSH BC
PUSH HL
LD B,D ; copy trk # in BC
LD C,E
CALL BIOSTTR ; ..and set track #
POP HL ; restore regs
POP BC
POP DE
JR RDTRK3 ; loop
; Read system file (img) - source
RDFILE: LD A,(ENVADR+1) ; get base addr of ENV
AND A ; check if invalid (= zero)
JR Z,RDFIL0 ; ..if no ENV, skip over
LD A,(CPMFCB+0DH) ; else, get user no from standard FCB #1
CALL SUA ; ..and log in
RDFIL0: LD DE,CPMFCB ; set ptr to standard FCB #1
LD C,15 ; BDOS fn #15 Open File
CALL BDOSSV
JP Z,E$SOPEN
LD HL,32 ; ptr to current record
ADD HL,DE
LD (HL),16 ; set # of current record
; (skip 16 records = 2kB, MOVSYS boot loader code)
LD HL,FILEBUF-128 ; set addr of file buffer (-128 ahead of loop)
RDFIL1: LD A,128 ; move forward by 128 bytes (1 sector)
CALL ADDHLA
EX DE,HL ; swap regs
LD C,26 ; BDOS fn #26 Set DMA Address
CALL BDOSSV
EX DE,HL ; swap regs back
LD C,20 ; BDOS fn #20 Read Sequentially
CALL BDOSSV
DEC A ; A= 1 returned means EOF, so decrease A
JR Z,RDFIL1 ; ..if zero, continue with next sector
LD C,16 ; BDOS fn #16 Close File
JP BDOSSV
; Write system tracks - destination
WRTRACK: LD A,(DSTDRV) ; get destination drive
CALL SELDRV ; and select it
JP Z,E$DEST ; ..if error, jump and exit
LD (DSTDPH),HL ; store addr of DPH
LD A,10 ; move forward to DPB addr
CALL ADDHLA ; at DPH+10
LD E,(HL) ; get DPB addr in DE
INC HL
LD D,(HL)
EX DE,HL ; swap regs
LD (DSTDPB),HL ; ..and store DPB addr
LD E,(HL) ; get sectors per track in DE
INC HL ; at DPB+0
LD D,(HL)
LD (SECTTRK),DE ; store value
LD A,12 ; move forward to track offset
CALL ADDHLA ; (beginning of directory) at DPB+13
LD E,(HL) ; get track offset in DE
INC HL
LD D,(HL)
LD A,D ; check upper nybble
AND A ; is it zero ?
JP NZ,WRTRK0 ; ..if not, jump to adjust
OR E ; check lower nybble
JP Z,E$NOSYS ; ..if also zero, jump to error and exit
CP 4 ; check upper limit for # of system tracks
JR C,WRTRK1 ; ..if within boundaries, skip over
WRTRK0: LD DE,2 ; set (default) # of system tracks
WRTRK1: LD B,E ; trk offset in B (counter)
LD DE,(SECTTRK) ; get sect/trk
LD HL,0 ; set initial value
WRTRK2: ADD HL,DE ; multiply by addition
DJNZ WRTRK2 ; loop till done
XOR A ; nullify A
OR H ; check if H is zero
JP NZ,E$NOSYS ; ..if not, jump error and exit
PUSH HL ; save regs
LD BC,0
CALL BIOSTTR ; set track # 0
POP HL ; save regs
LD C,H ; move # of sectors containing system
LD B,L ; to BC (as counter)
LD DE,0 ; set initial value
LD HL,FILEBUF ; set origin addr (file buffer)
WRTRK3: PUSH DE ; save regs
PUSH BC
PUSH HL
LD HL,(DSTDPH) ; get addr of DPH
LD E,(HL) ; get skew table ptr in DE
INC HL
LD D,(HL)
CALL BIOSTRN ; translate logical sector # in BC
LD B,H ; move physical sector # to BC
LD C,L
CALL BIOSTSE ; ..and set (physical) sector
POP BC ; restore origin addr
PUSH BC
CALL BIOSTDM ; set as DMA buffer addr
LD C,0
CALL BIOWRIT ; write one sector
OR A ; check for error (A <> 0)
JP NZ,E$WRITE ; ..if error, jump
POP HL ; restore origin addr
LD DE,128 ; ..and increase by 128 bytes (1 sector)
ADD HL,DE
POP BC ; restore regs / clear stack
POP DE
DEC B ; decrease counter
JR NZ,WRTRK4 ; ..if not finished, continue
LD C,1 ; else, force write (flush to disk)
JP BIOWRIT ; ..and let return from there
WRTRK4: INC C
LD A,C
AND 00000011b ; mask lower 2 bits
LD A,'.'
CALL Z,COUT ; display progress every 4 sectors (0.5 kB)
LD A,(SECTTRK)
CP C ; max. # sect/trk reached ?
JR NZ,WRTRK3 ; ..if not, loop
INC DE ; increase trk counter
LD C,0 ; reset sect counter
PUSH DE ; save regs
PUSH BC
PUSH HL
LD B,D ; copy trk # in BC
LD C,E
CALL BIOSTTR ; ..and set track
POP HL ; restore regs
POP BC
POP DE
JR WRTRK3 ; loop
; check if a valid B/P Bios was loaded
; *** function not implemented ***
; in: -
; out: Z-Flag set if ok, NZ= error
CHKSYS: XOR A ; always return Z-Flag set
RET
; select disk drive
; in: A= drive number (one-based)
; out: Z-Flag set if error
SELDRV: DEC A ; -1 to comply with CP/M BIOS standards
LD C,A
LD E,0
CALL BIOSELD ; call BIOS fn #9 directly
LD A,H
OR L
RET
; call BDOS saving regs BC, DE, HL
; out: A= 0 and Z-Flag set if not found
BDOSSV: PUSH BC
PUSH DE
PUSH HL
CALL CPMBDOS
INC A ; 0xFF --> 0x00 if not found
POP HL
POP DE
POP BC
RET
; add A to HL (result in HL)
ADDHLA: ADD A,L ; add L
LD L,A ; store result in L
RET NC ; ..if no overflow, return
INC H ; else, increment H
RET
;::::: ERROR MESSAGES
; display msg on CON: then exit with warm boot
E$READ: CALL EPRINT
DEFB BEL,'*** Read error'
DEFB 0
JP EXIT
E$SRC: CALL EPRINT
DEFB BEL,'*** Bad source!'
DEFB 0
JP EXIT
E$WRITE: CALL EPRINT
DEFB BEL,'*** Write error'
DEFB 0
JP EXIT
E$DEST: CALL EPRINT
DEFB BEL,'*** Bad destination!'
DEFB 0
JP EXIT
E$NOSYS: CALL EPRINT
DEFB BEL,'*** No system!'
DEFB 0
JP EXIT
E$SOPEN: CALL EPRINT
DEFB BEL,"*** Can't open source file!"
DEFB 0
;::::: EXIT PROGRAM
EXIT: CALL CRLF
LD HL,0 ; set addr
JP (HL) ; and jump to CP/M WBOOT
;::::: BIOS JUMPS (for direct calls)
; area is filled with actual jumps at runtime
; to call BIOS fn's directly
BIOSELD: JP 0 ; fn #9 SELDSK select disk
BIOSTTR: JP 0 ; fn #10 SETTRK set track
BIOSTSE: JP 0 ; fn #11 SETSEC set sector
BIOSTDM: JP 0 ; fn #12 SETDMA set buffer addr
BIOREAD: JP 0 ; fn #13 READ read one sector
BIOWRIT: JP 0 ; fn #14 WRITE write one sector
BIOLIST: JP 0 ; fn #15 LISTST list status (not used)
BIOSTRN: JP 0 ; fn #16 SECTRN sector translation
;::::: RAM STORAGE (not in DSEG !)
SECTTRK: DEFW 0 ; sectors per track (sect/trk), used for src+dst
SRCDPH: DEFW 0 ; source: addr of Disk Parameter Header (DPH)
SRCDPB: DEFW 0 ; source: addr of Disk Parameter Block (DPB)
DSTDPH: DEFW 0 ; destination: addr of DPH
DSTDPB: DEFW 0 ; destination: addr of DPB
SRCDRV: DEFB 0 ; source: drive # (from standard FCB #1)
DSTDRV: DEFB 0 ; destination drive #
DSTDR2: DEFB 0 ; destination drive # (copy)
; extracted from cmdline, used as indicator for run mode
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
; Z3LIB - 0x0735
; SYSLIB - 0x07e3
; end addr 0x08cc (DSEG Z3+SYS = 4 bytes)
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
; buffer start addr = 0x0900
FILEBUF: EQU $+512-($-BPSYSGEN AND 255)
DSEG
END
;************************************************************************
; Remarks jxl:
; BPSYSGEN.COM, included in available B/P Bios package(s), was dis-
; assembled and extensively commented. Labels are up to seven chars long
; to comply with M-REL standards. However, it is recommended to use SLR
; tools that support labels up to sixteen chars.
; In its current state, the compiled/linked file matches exactly the
; original BPSYSGEN.COM, i.e. no changes to the source were made.
; The program is pretty straightforward. It supports a command line
; mode and an interactive mode. (Code portions for the latter are pretty
; short.) Functionality to check if the running system is valid, was
; not implemented. Since other B/P Bios tools perform such checks, this
; is rather surprising.
; An interesting approach was used to end the program and literally
; return to the system. The address of RESDISK routine is pushed on the
; stack at the very beginning.
;************************************************************************

View File

@@ -0,0 +1,489 @@
TITLE "ZCPR 4 Configuration Utility"
;************************************************************************
;* C O N F Z 4 *
;* Configure ZCPR 4 options *
;* by Harold F. Bower and Cameron W. Cotrill *
;*----------------------------------------------------------------------*
;* Disassembly: jxl Jan 2025 *
;* public release 1.0 Apr 2025 *
;* see remarks at the end *
;*----------------------------------------------------------------------*
;* LINK with Version 4 libraries: Z3LIB, SYSLIB *
;* *
;* A>Z80ASM CONFZ4/RS *
;* A>SLRNK CONFZ4/N,/A:100,/D:080A,CONFZ4,Z3LIBS/S,SYSLIBS/S,/E *
;************************************************************************
VER EQU 10
REV EQU ' '
DATE MACRO
DEFB '18 Nov 95'
ENDM
BEL EQU 07H ; Bell character
BS EQU 08H ; Backspace character
TAB EQU 09H ; Tab character
LF EQU 0AH ; Line Feed character
CR EQU 0DH ; Carriage Return character
CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP)
CPMBDOS EQU 5 ; CP/M BDOS entry point (JP)
CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype)
CPMDMA EQU 80H ; CP/M standard DMA buffer
; From Z3LIB Get..
EXTRN GETNAME, PRTNAME, Z3INIT, WHRENV
; From SYSLIB Get..
EXTRN EPRINT, CRLF, CAPIN, PA2HC, COUT
;::::: PROGRAM START
ORG 100H
CSEG
CONFZ4: JP START ; bypass header
DEFB 'Z3ENV' ; this is a ZCPR3 utility
DEFB 1 ; show external environment
ENVADR: DEFW 0 ; addr of Z3 environment
DEFW CONFZ4 ; type 4 filler
DEFB 'CONFZ41 ',0 ; configuration name
START: LD (STACK),SP
LD SP,STACK
CALL EPRINT
DEFB 'B/P System Command Processor Configuration V'
DEFB VER/10+'0','.',VER MOD 10 + '0',REV,' '
DATE
DEFB CR,LF
DEFB 0
CALL INITZ3 ; find Z3ENV and check Wheel Byte
CALL GETNAME ; get actual program name
CALL CHKHLP ; check if help was requested
SUB ' ' ; ##### convert to ... ??
LD (UNUSED1),A ; ##### and store (not used at all)
CALL CHKSYS ; check if running B/P Bios
LD HL,(BPCNFG) ; addr CONFIG area
INC HL ; move ptr fwd
INC HL
LD A,(HL) ; get option flags (OPTF1)
AND 00000001B ; mask bit 0 (0= unbanked, 1= banked)
LD (BPBNKD),A ; store indicator
JR NZ,CHKXENV ; ..if banked, jump to continue
CALL EPRINT ; else, display msg and exit
DEFB CR,LF,'+++ Not Banked System..aborting...!',BEL
DEFB 0
JP EXIT
; check for extended environment
CHKXENV: INC HL ; move ptr fwd
INC HL
INC HL
LD A,(HL) ; get first system bank (SYSBNK)
LD (SYSBNK),A ; store it
LD HL,(ENVADR) ; addr ENV
LD DE,8 ; offset to type
ADD HL,DE ; move ptr
BIT 7,(HL) ; check high bit (= 0x80+ for extended Z3ENV)
JR NZ,CHKVERS ; ..if set, jump to continue
CALL EPRINT
DEFB CR,LF,'+++ Not Extended Environment..aborting..!',BEL
DEFB 0
JP EXIT
; check ZCPR version
CHKVERS
LD DE,55 ; offset addr CPR (8+55 = 63)
ADD HL,DE ; move ptr
LD E,(HL) ; get addr in DE
INC HL
LD D,(HL)
LD HL,5 ; offset to version byte in ZCPR 4.x
; (code starts with JP.., JR.., VERSION)
ADD HL,DE ; move ptr
LD A,(HL) ; get byte
CP 41H ; is it 4.1 (or higher) ?
JR NC,PVRSION ; ..if so, jump to continue
PUSH AF ; else, display error msg and exit
CALL EPRINT
DEFB CR,LF,BEL,"+++ Can't Configure Vers : "
DEFB 0
POP AF
CALL PA2HC
CALL EPRINT
DEFB ' of Command Processor!'
DEFB 0
JP EXIT
; display version
PVRSION: PUSH AF
CALL EPRINT
DEFB CR,LF,' Configuring Options for CPR Version : '
DEFB 0
POP AF ; restore version #
PUSH AF
RRCA ; rotate upper nybble to lower
RRCA ; (major version #)
RRCA
RRCA
AND 00001111B ; mask lower nybble
ADD A,'0' ; ..and convert to ascii
CALL COUT ; display major version #
LD A,'.'
CALL COUT
POP AF ; restore version #
AND 00001111B ; mask lower nybble
ADD A,'0' ; ..and convert to ascii
CALL COUT ; display minor version #
CALL CRLF
LD DE,10 ; move forward by another 10 bytes
ADD HL,DE ; (in Z40-1.Z80 three bytes are defined as 'Space
; reserved for expansion' - this is the last byte)
LD (PFLGADR),HL ; store addr
; branch interactive/cmdline mode
LD A,(CPMFCB+1) ; get first char from cmdline
CP ' ' ; is it <SP> ?
JP NZ,EVALCMD ; ..if not, jump cmdline mode
CALL EPRINT ; else, interactive mode
DEFB CR,LF,'Turn Time ON in Prompt Line ([Y]/N)? : '
DEFB 0
CALL CAPIN ; get user input
LD BC,0FE01H ; default to ON, European format
; ( 11111110 00000001 B )
CP 'N' ; is it 'N' ?
JR NZ,RUNIMOD ; ..if not, skip over
LD C,0 ; else, clear C (indicating OFF)
; run interactive mode
RUNIMOD: CALL SETOPTB ; set byte
CALL EPRINT
DEFB CR,LF,'US (mm/dd/yy) or European (dd.mm.yy) Dates ([U]/E) : '
DEFB 0
CALL CAPIN ; get user input
LD BC,0FD00H ; default to US format
; ( 11111101 00000000 B )
CP 'E' ; is it 'E' ?
JR NZ,RUNIM0 ; ..if not, skip over
LD C,00000010B ; else, set European format
RUNIM0: CALL SETOPTB ; set byte
JP EXIT
; evaluate command line
EVALCMD: LD HL,CPMDMA
LD A,(HL) ; get # of chars
INC HL ; set ptr to start of cmdline
PUSH HL ; save regs
CALL ADDHLA ; move ptr to end of cmdline
LD (HL),0 ; set <NUL> terminator
POP HL ; restore start of cmdline
CALL SKPWHSP ; skip any whitespace at the beginning
LD A,(HL) ; get char
CP '/' ; is it option char ?
JR NZ,ECMD0 ; ..if not, skip over
INC HL ; else, move ptr forward
ECMD0: LD A,(HL) ; get byte
OR A
JR Z,ECMD1 ; ..if zero, jump and exit
CALL CMPRMPT ; else, attempt processing option
JR ECMD0 ; ..and loop
ECMD1: JP EXIT
; cmdline: /T[+|-] Toggle Time in Prompt
; option byte, bit 0 = 0 off / 1 on
;
; cmdline: /U /E US/Europe format
; option byte, bit 1 = 0 US / 1 European
; process prompt on/off
CMPRMPT: CP 'T' ; is char 'T' (Toggle) ?
JR NZ,CMFORMT ; ..if not, try processing format option
INC HL
LD C,00000001B ; prepare for ON
LD A,(HL) ; get next char
CP '+' ; is it '+' ?
JR Z,CMPRMP0 ; ..if so, skip over
LD C,00000000B ; else, prepare for OFF
CP '-' ; is it '-' ?
JR NZ,CMFORMT ; ..if not, rather check format
CMPRMP0: LD B,11111110B ; default to European format
CMSETOP: CALL SETOPTB ; set
CMSETX: INC HL ; move ptr fwd
RET ; ..and exit
; process format
CMFORMT: LD B,11111101B ; default to ON (else, format wouldn't make sense)
LD C,00000010B ; prepare for European
CP 'E' ; is it 'E' ?
JR Z,CMSETOP ; ..if so, set byte
LD C,00000000B ; else, prepare for US
CP 'U' ; is it 'U' ?
JR Z,CMSETOP ; ..if so, set byte
JR CMSETX ; jump exit
; set option byte
; in: B= format (US/European)
; C= on/off
SETOPTB: EX DE,HL ; swap regs (save HL)
LD HL,(PFLGADR) ; addr of Prompt flag in ZCPR4 config area
LD A,(HL) ; get byte
AND B ; apply format setting
OR C ; merge on/off setting
LD (HL),A ; ..and save byte
LD HL,010FH ; offset to option byte in SYSBNK
CALL GETFRB ; get current setting
AND B ; apply format setting
OR C ; merge on/off setting
CALL SETINB ; ..and write back
EX DE,HL
RET
; check if help was requested
; get first token from command line (in FCB #1)
CHKHLP: LD HL,CPMFCB+1
LD A,(HL) ; get char
CP '/' ; is this a help request ?
RET NZ ; ..if not, return
INC HL ; move ptr fwd
LD A,(HL) ; check following char
CP '/' ; if it is also '/'
RET NZ ; ..if not, return
; else, fall through and show help screen
;::::: HELP SCREEN
HELP: CALL EPRINT
DEFB CR,LF,' '
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' Configure Running B/P Command Processor Options.',CR,LF,LF
DEFB ' Syntax:',CR,LF,' '
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' - Configure in Interactive Mode',CR,LF,' '
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' /T[+|-] - Toggle Time in Prompt [Set On/Off]',CR,LF,' '
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' /E - Display Date in European (dd.mm.yy) form',CR,LF,' '
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' /U - Display Date in US (mm/dd/yy) form',CR,LF,' '
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' // - display this screen',CR,LF,LF
DEFB ' Arguments may be combined as:',CR,LF,' '
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' /T+U - Turn Time On, US-style Date Display',CR,LF,LF
DEFB 'This program will only run in Banked B/P Systems.',CR,LF
DEFB 0
;::::: EXIT PROGRAM
EXIT: CALL CRLF
LD SP,(STACK) ; restore stack
RET ; ..and return to system
;::::: SUPPORT FUNCTIONS
; init Z3ENV and check Wheel byte
; if not successful, exit program
INITZ3: LD HL,(CPMBDOS+1)
CALL WHRENV ; find Z3 Environment Descriptor
LD (ENVADR),HL ; store ENV addr
LD A,H ; check if invalid (= zero)
OR L
JP Z,E$BPBIO ; ..if so, jump exit
CALL Z3INIT ; init for Z3LIB routines
LD A,41 ; offset to addr wheel byte (Z3WHL)
CALL ADDHLA ; move ptr fwd
LD E,(HL) ; get addr in DE
INC HL
LD D,(HL)
EX DE,HL ; swap regs
LD A,(HL) ; get value of wheel byte
AND A ; check if zero
RET NZ ; ..if not ON, return
CALL EPRINT ; else, display message and exit
DEFB BEL,CR,LF,'Must be wheel to Execute !',CR,LF
DEFB 0
JR EXIT
; check if running under B/P Bios
; if not, program is terminated
CHKSYS: LD HL,(CPMBIOS+1) ; get warm boot addr (BIOS fn #1)
LD L,30*3 ; adjust ptr to fn #30
LD A,(HL) ; check byte at ptr location
CP 0C3H ; is it opcode 0xC3 (JP) ?
JR NZ,E$BPBIO ; ..if not, jump error and exit
CALL JUMPHL ; else, "call" B/P Bios fn #30 (RETBIO)
LD (BPADDR),BC ; store base addr of B/P Bios
LD (BPCNFG),DE ; " config area addr
LD HL,-6 ; move ptr 6 bytes backward
ADD HL,DE ; (signature string)
LD A,(HL) ; get byte
CP 'B' ; is it 'B' ?
JR NZ,E$BPBIO ; ..if not, jump error and exit
INC HL
LD A,(HL) ; get next byte
CP '/' ; is it '/' ?
JR NZ,E$BPBIO ; ..if not, jump error and exit
INC HL
LD A,(HL) ; and get next byte
CP 'P' ; is it 'P' ?
RET Z ; ..if so, return
; else, fall through (error and exit)
; error msg
E$BPBIO: CALL EPRINT
DEFB CR,LF,BEL,'Not B/P Bios, aborting...!',CR,LF
DEFB 0
RST 0
; print program name on CON: device
; (either the actual name, or fallback to default)
; only used by HELP
PPRGNAM: LD A,(ENVADR+1) ; get high byte of local ENVPTR
OR A ; check if valid (<> zero)
JP NZ,PRTNAME ; ..if so, display actual name
; and let return from there
CALL EPRINT ; else, display default
DEFB 'SIZERAM' ; apparently wrong :-)
DEFB 0
RET
; skip whitespace (<SP> or <TAB>)
; in: HL= ptr to string
; out: HL= ptr to first char <> whitespace
SKPWHSP: DEC HL ; prior to loop, set ptr back
SKPWH0: INC HL ; move ptr fwd
LD A,(HL) ; get byte
CP ' ' ; is it <SP> ?
JR Z,SKPWH0 ; ..if so, loop
CP TAB ; is it <TAB> ?
JR Z,SKPWH0 ; ..if so, loop
RET ; else, return
; add A to HL (result in HL)
ADDHLA: ADD A,L ; add L
LD L,A ; store result in L
RET NC ; ..if no overflow, return
INC H ; else, increment H
RET
; the following routines rearrange Top of Stack by injecting an
; intermediate return addr, and putting the Bios fn call on top
; so that HL regs are preserved
; order of steps:
; [1] HL (= addr) is pushed onto stack
; [2] intermediate return addr is swapped to Top of Stack
; [3] HL (= addr) is pushed onto stack again
; [4] Bios fn JP addr is swapped to Top of Stack
; [5] Bios is "called" through RET, and returns to intermediate addr
; get byte from ram bank (in C) - in the form LD A,(HL)
; in: HL= addr
; out: A= byte
GETFRB: PUSH BC
PUSH HL ; save addr
LD BC,(SYSBNK) ; C= System Bank, B= not used
LD HL,GETFRB0 ; load return addr
EX (SP),HL ; put it on stack
PUSH HL ; save HL again (previous top of stack)
LD HL,(BPADDR) ; get B/P Bios base addr
LD L,35*3 ; adjust ptr to fn #35 (FRGETB)
EX (SP),HL ; put addr on stack
RET ; ..and "call" Bios fn through stack
GETFRB0: POP BC ; restore regs
RET ; ..and finally return
; set byte in ram bank (in C) - in the form LD (HL),A
; in: HL= addr, A= byte to set
SETINB: PUSH BC
PUSH HL ; save addr
LD BC,(SYSBNK)
LD HL,GETFRB0 ; load return addr
EX (SP),HL ; put it on stack
PUSH HL ; save HL again (previous top of stack)
LD HL,(BPADDR) ; get B/P Bios base addr
LD L,37*3 ; adjust ptr to fn #37 (FRPUTB)
EX (SP),HL
RET ; ..and "call" Bios fn through stack
; "called" as a pseudo-routine that returns to caller
; in: HL= target addr
JUMPHL: JP (HL) ; jump to addr in HL regs
;::::: RAM STORAGE (_no_ DSEG !)
PFLGADR: DEFW 0 ; addr of Prompt flag (last reserved option byte)
SYSBNK: DEFB 0 ; beginning of System Bank(s)
UNUSED1: DEFB 0 ; #####
BPADDR: DEFW 0 ; base addr B/P Bios
BPCNFG: DEFW 0 ; addr of B/P Bios CONFIG area
BPBNKD: DEFB 0 ; indicator banked system
; (bit 0 of OPTF1, 0= unbanked, 1= banked)
DEFS 30H ; room for stack
STACK: DEFW 0 ; stack storage location
END
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
; Z3LIB - 0x06b4
; SYSLIB - 0x0762
; end addr 0x080a (begin DSEG of LIB's)
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
;************************************************************************
; Remarks jxl:
; CONFZ4.COM, included in available B/P Bios package(s), was dis-
; assembled and extensively commented. Labels are up to seven chars long
; to comply with M-REL standards. However, it is recommended to use SLR
; tools that support labels up to sixteen chars.
; In its current state, the compiled/linked file matches exactly the
; original CONFZ4.COM, i.e. no changes to the source were made. Possible
; optimisations detected during disassembly are marked with "#####" in the
; comment.
; The program seems to be in an early stage as it does not comply with
; general coding standards seen by HFB/CWC. For instance, no DSEG is used.
; Only 2 options can be configured with this program. It is not known
; whether provisions were made in ZCPR v4.1 for further options.
;************************************************************************

View File

@@ -0,0 +1,752 @@
TITLE "HASHINI Drive Utility"
;************************************************************************
;* H A S H I N I *
;* Set Drive Volume Name and Init for File Stamps *
;* by Harold F. Bower and Cameron W. Cotrill *
;*----------------------------------------------------------------------*
;* Disassembly: jxl Mar 2025 *
;* public release 1.0 Apr 2025 *
;* see remarks at the end *
;*----------------------------------------------------------------------*
;* LINK with Version 4 libraries: Z3LIB, SYSLIB *
;* *
;* A>Z80ASM HASHINI/RS *
;* A>SLRNK HASHINI/N,/A:100,/D:09E5,HASHINI,Z3LIBS/S,SYSLIBS/S,/E *
;************************************************************************
VER EQU 02
REV EQU ' '
DATE MACRO
DEFB '12 Sep 93'
ENDM
CTRLC EQU 03H ; Control-C character
BEL EQU 07H ; Bell character
BS EQU 08H ; Backspace character
TAB EQU 09H ; Tab character
LF EQU 0AH ; Line Feed character
CR EQU 0DH ; Carriage Return character
ESC EQU 1BH ; Escape character
CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP)
CPMBDOS EQU 5 ; CP/M BDOS entry point (JP)
CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype)
CPMFCB2 EQU 6CH ; CP/M standard FCB #2
CPMDMA EQU 80H ; CP/M standard DMA buffer
; From Z3LIB Get..
EXTRN GETNAME, PRTNAME, GETQUIET, Z3INIT
; From SYSLIB Get..
EXTRN BLINE, EPRINT, CRLF, CAPIN, COUT, CODEND
;::::: PROGRAM START
ORG 100H
CSEG
HASHINI: JP START ; bypass header
DEFB 'Z3ENV' ; this is a ZCPR3 utility
DEFB 1 ; show external environment
DEFB 1
ENVADR: DEFW 0 ; addr of Z3 environment
DEFB 1
DEFB 'HASHINI '
DEFB 0
; config area (for ZNCFG.COM)
CFGAREA: DEFB 0 ; default value for program quiet flag
DEFB 0FFH
START: LD (STACK),SP ; save stack
LD SP,STACK
CALL Z3INIT ; init ENVPTR for Z3LIB routines
CALL GETNAME ; get ptr to program name
CALL GETQUIET ; check ENV quiet flag
LD HL,CFGAREA ; ptr to config area
OR (HL) ; merge flags (ENV + program)
LD (PRGQFLG),A ; store program quiet flag
CALL EPRINT
DEFB CR,LF,'Initialize Volume Label and File Stamps Ver '
DEFB VER/10+'0','.',VER MOD 10 + '0',REV,' '
DATE
DEFB CR,LF
DEFB 0
LD C,25 ; get current disk (BDOS fn #25)
CALL CPMBDOS
LD (OLDDRV),A ; remember drive #
CALL EVALCMD ; evaluate command line
JR INITWSPC
;::::: MAIN LOOP
START0: LD SP,STACK ; reset stack pointer
CALL EPRINT
DEFB CR,LF,LF,'Initialize another Disk? (Y/[N]) : '
DEFB 0
CALL CINPUT ; get user input
CP 'Y' ; is it 'Y' ?
JP NZ,EXIT ; ..if not, jump to exit
CALL SELODRV ; restore previously logged drive
CALL CRLF
OR 0FFH ; from now on run interactively
; init workspace (ram storage)
INITWSPC: LD (RUNMODE),A ; store mode
LD HL,WSPC ; clear workspace data area
LD B,(STACK-WSPC)-3
CALL FILLZ
;::::: DISK DRIVE
GETDISK: LD A,(RUNMODE) ; get mode
OR A ; running in cmdline mode ?
JR Z,GETVOLN ; ..if so, drive is known, jump to continue
; interactive mode - ask for disk to initialize
IMDISK: CALL EPRINT
DEFB CR,LF,LF,'Initialize which Disk for '
DEFB 0
LD A,(STMPTYP) ; stamp format indicator
OR A ; is it P2Dos ?
JR NZ,IMDISK1 ; ..if not, jump to continue
CALL EPRINT ; display chosen format
DEFB 'P2DOS'
DEFB 0
JR IMDISK2 ; skip over
IMDISK1: CALL EPRINT
DEFB 'NZTIME'
DEFB 0
IMDISK2: CALL EPRINT
DEFB ' Date/Time Stamps? : '
DEFB 0
CALL CINPUT ; get user input
CP 'A' ; disk drive letter must be
JR C,IMDISK3 ; between 'A' and 'P'
CP 'P'+1
JR C,IMDISK4
IMDISK3: CALL EPRINT ; else, notify user and loop
DEFB BEL,BS,' ',BS
DEFB 0
JR IMDISK
IMDISK4: LD (CURRDSK),A ; store disk drive letter
;::::: VOLUME NAME
GETVOLN: LD A,(VOLNAME)
OR A
JR NZ,IMVOLN3
; interactive mode - ask for volume name
IMVOLN: CALL EPRINT
DEFB CR,LF,'Enter Volume Name [1-11 chars] : '
DEFB 0
LD HL,CPMDMA ; set ptr to standard buffer
LD (HL),11 ; prepare char count (max. 11 chars)
XOR A ; clear A
LD (CPMDMA+1),A ; prepare end-of-string
DEC A ; let capitalize (A= non-zero)
CALL BLINE ; get user input
LD A,(HL) ; check char count
OR A ; is it empty string (nothing entered) ?
JR Z,IMVOLN ; ..if so, loop
LD DE,VOLNAME ; point to volname buffer
IMVOLN1: LD A,(HL) ; get char
LDI ; ..and copy over
OR A ; end of string ?
JR NZ,IMVOLN1 ; ..if not, loop
IMVOLN3: LD A,(PRGQFLG) ; get program quiet flag
OR A ; running in quiet mode ?
JR Z,DSKPROC ; ..if so, skip over
CALL EPRINT
DEFB CR,LF,' Confirm Initialize Drive '
DEFB 0
LD A,(CURRDSK)
CALL COUT
CALL EPRINT
DEFB ': (Y/[N]) '
DEFB 0
CALL CINPUT ; get user input
CP 'Y'
JP NZ,FINISH
;::::: PROCESS DISK
DSKPROC: LD A,(CURRDSK) ; get current disk drive letter
SUB 'A' ; make numeric
PUSH AF ; save regs
LD E,A ; drive # in E
CALL BDSELD ; select disk drive (BDOS call)
CALL EPRINT ; display warning
DEFB BEL,CR,LF,'+++ Existing Files will be ERASED! +++'
DEFB CR,LF,' --- Proceed anyway (Y/[N]) : '
DEFB 0
CALL CINPUT ; get user input
CP 'Y' ; is it 'Y' ?
JP NZ,FINISH ; ..if not, jump to finish processing
POP AF ; restore regs
LD C,A ; drive # in C
CALL BIOSELD ; select disk drive (BIOS call)
LD A,H ; check if DPH addr is valid
OR L
JP Z,E$DRVILL ; ..if not, jump display error msg and exit
; get parameters of current disk drive
LD E,(HL) ; get addr of skew table in DE
INC HL
LD D,(HL)
LD (SKEWTBL),DE ; and store value
LD DE,9
ADD HL,DE ; move ptr fwd (to DPH+10)
LD E,(HL) ; addr of DPB in DE
INC HL
LD D,(HL)
PUSH DE ; move addr to IX
POP IX
; ??? ##### CODEND not used
CALL CODEND ; get first free memory page addr in HL
LD D,(IX+8) ; get DirMax in DE
LD E,(IX+7) ; (max. dir entries -1)
INC DE ; +1
LD (DIRMAX),DE ; store value
SRL D ; /2
RR E
SRL D ; /4
RR E
LD (STMPMAX),DE ; store value
; (1 stamp dir entry for 4 file dir entries)
LD BC,0
LD HL,CPMDMA ; set to standard buffer
PUSH DE ; save regs
PUSH BC
LD DE,VOLNAME ; ptr to volume name
LD A,(DE) ; get char
OR A ; is it zero ? (<NUL> means empty string)
LD B,3*32 ; prepare counter for 3 stamp entries
JR Z,MKSTMP ; ..if no volume name, jump to continue
; make a volume name entry
; HL= ptr to standard buffer, DE= ptr to VOLNAME
; B= char count, C= char
LD (HL),020H ; set first byte of dir entry (user area)
; to 0x20 - indicates time stamp
INC HL ; move ptr fwd
LD B,11 ; number of chars
MKVOLN: LD A,(DE) ; get VOLNAME char in A
LD C,' ' ; prepare for <NUL> byte
OR A ; end of string ?
JR Z,MKVOLN1 ; ..if so, skip over
LD C,A ; else, get char in C
INC DE ; move VOLNAME ptr forward
MKVOLN1: LD (HL),C ; copy char to buffer
INC HL ; move ptr fwd
DJNZ MKVOLN ; loop till done
LD B,32-12 ; clear remaining bytes of stamp entry
CALL FILLZ
LD B,2*32 ; fill next 2 stamp entries
; make a stamp entry and write to dir
MKSTMP: LD A,0E5H ; CP/M default byte for free dir entries
CALL FILLA ; fill stamp entries
LD A,(STMPTYP) ; get chosen stamp format (0x00 = P2Dos, 0xFF = NZTime)
OR A ; ..and check
LD A,021H ; prepare for P2Dos
JR Z,MKSTMP1 ; ..if so, skip over
LD A,0A1H ; else, prepare for NZTime
MKSTMP1: LD (HL),A ; store byte
INC HL ; move ptr fwd
LD B,32-1 ; ..and clear remaining bytes of stamp entry
CALL FILLZ
POP BC ; restore regs
POP DE
CALL PVBOSE ; if verbose mode, display msg
DEFB CR,LF,'...Writing Initialized Directory...'
DEFB 0
LD DE,0 ; initial start #
LD (STMPCUR),DE ; set # of current stamp entry
CALL WRSTMP ; ..and write stamp to directory
LD HL,CPMDMA ; reset ptr to begin of standard buffer
LD A,0E5H ; clear first part of stamp entry
LD B,32
CALL FILLA
MKSTMP2: CALL WRSTMP ; ..and write next stamp entry
LD HL,(STMPCUR) ; get current #
LD DE,(STMPMAX) ; get max. #
OR A ; clear flags
SBC HL,DE ; check if all entries were written
ADD HL,DE
JR NZ,MKSTMP2 ; ..if not, loop
LD BC,1 ; set C= 1 to indicate Directory Write (forced)
CALL BIOWRIT ; ..and perform through BIOS
JP DSKDONE
; display help and exit
HLPEXIT: XOR A ; clear A
LD (RUNMODE),A ; ..and store mode (cmdline)
JR HELP
E$DRVILL: CALL EPRINT ; display error msg and fall through
DEFB CR,LF,LF,BEL,'Illegal drive name'
DEFB 0
;::::: HELP
HELP: CALL EPRINT
DEFB CR,LF,'Usage: Set Drive Volume Name & '
DEFB 'Initialize for P2Dos/NzTime file stamps',CR,LF,LF
DEFB 'Syntax:',CR,LF,TAB
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' [d:][volname] [/][P | Z | Q]',CR,LF
DEFB 'Examples:',CR,LF,TAB
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB TAB,'- Enter Interactive Mode',CR,LF,TAB
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' /P',TAB,'- Init Drive interactively w/P2D stamps',CR,LF,TAB
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' d:',TAB,'- Initialize drive "d" w/default Stamp',CR,LF,TAB
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' d:name',TAB,'- Init drive "d" adding Vol ID "name"',CR,LF,TAB
DEFB TAB,TAB,' file with default Stamps',CR,LF,TAB
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' d: ZQ',TAB,'- Init drive "d" for NZTime Stamps',CR,LF,TAB
DEFB TAB,TAB,' suppressing unneeded messages',CR,LF,TAB
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' //',TAB,'- Display this message',CR,LF,LF
DEFB 'Note: ZCNFG may be used to configure a flag to suppress',CR,LF
DEFB ' drive confirmation prompt and status messages',CR,LF
DEFB 0
JP FINISH
; print program name on CON: device
; (either the actual name, or fallback to default)
; only used by HELP
PPRGNAM: LD A,(ENVADR) ; get high byte of ENV ptr
OR A ; check if valid (<> zero)
JP NZ,PRTNAME ; ..if so, display actual name
; and let return from there
CALL EPRINT ; else, display default name
DEFB 'HASHINI'
DEFB 0
RET
; write a stamp entry to directory
; in: IX= ptr DPB
; STMPCUR= # of current stamp entry
WRSTMP: PUSH BC ; save regs
PUSH DE
PUSH HL
LD HL,0
LD BC,(STMPCUR) ; get # of current stamp entry
LD D,(IX+1) ; get sectors per track (DPB+0)
LD E,(IX+0)
LD A,17 ; set counter
; determine track # (in BC) and sector # (in HL)
WRSTMP1: OR A ; clear flags
SBC HL,DE ; divide by subtraction
CCF ; inverse C-flag
JR C,WRSTMP2
ADD HL,DE ; compensate overflow
OR A ; clear flags
WRSTMP2: RL C ; divide BC by 2 (track #)
RL B
DEC A ; decrease counter
JR Z,WRSTMP3 ; ..if zero, exit loop
RL L ; else, also divide HL by 2 (sector #)
RL H
JR WRSTMP1 ; and continue
WRSTMP3: PUSH HL ; save (log.) sector #
LD H,(IX+14) ; get track offset (# sys tracks)
LD L,(IX+13)
ADD HL,BC ; add to calculated track #
LD B,H
LD C,L
CALL BIOSTTR ; set track
POP BC ; restore (log.) sector #
LD DE,(SKEWTBL) ; get addr of skew table
CALL BIOSTRN ; translate logical to physical sector
LD B,H
LD C,L
CALL BIOSTSE ; set (phys.) sector
LD BC,CPMDMA ; set buffer addr
CALL BIOSTDM
LD BC,0 ; set C= 0 to indicate Unallocated Write
CALL BIOWRIT ; ..and perform through BIOS
OR A ; check for error
JR Z,WRSTMPX ; ..if not, jump to exit subroutine
CALL EPRINT ; else, display msg
DEFB CR,LF,BEL,'Directory write error'
DEFB 0
JR FINISH
WRSTMPX: LD BC,(STMPCUR) ; get current stamp #
INC BC ; increase
LD (STMPCUR),BC ; ..and save again
POP HL ; restore regs
POP DE
POP BC
RET
; select disk drive that was logged at start of program
; using BIOS fn first, then BDOS fn
SELODRV: LD A,(OLDDRV) ; get # of old logged disk drive
LD C,A ; in C
LD B,0
PUSH BC ; save it
LD DE,1 ; ??? ##### not necessary
CALL BIOSELD ; select disk drive (through BIOS)
POP DE ; restore drive # in E
; ..and fall through
; call BDOS fn #14 SELDSK
; in: E= drive #
BDSELD: LD C,14
JP CPMBDOS ; jump BDOS and let return from there
;::::: FINISH PROCESSING DISK
FINISH: CALL SELODRV ; restore previously logged drive
; ..and fall through
DSKDONE: LD A,(CURRDSK)
SUB 40H ; make numeric
LD B,A ; use value as counter
SCF ; set C-flag
LD HL,0 ; start with all bits cleared
DSKDN0: ADC HL,HL ; shift Carry bit into position
DJNZ DSKDN0 ; loop till done
EX DE,HL ; bit mask in DE (selected disk drive)
LD C,37 ; BDOS fn #37 RESDSK reset disk system
CALL CPMBDOS
LD A,(RUNMODE) ; get mode
OR A ; running in cmdline mode ?
JP NZ,START0 ; ..if not, loop for next drive
; else, fall through and exit
;::::: EXIT PROGRAM
EXIT: LD SP,(STACK) ; restore stack
RET ; ..and return to system
;::::: SUPPORT FUNCTIONS
; EVALCMD Evaluate command line
; based on tokens provided by CP/M parser in FCB #1/#2
; in: A= # of current drive
; out: A= 0x00 cmdline mode, 0xFF interactive mode
; Syntax: [d:][volname] [/][P | Z | Q]
EVALCMD: XOR A ; clear A
LD (CURRDSK),A ; ..and variables
LD (RUNMODE),A
LD HL,CPMFCB ; set ptr to standard FCB #1
LD A,(HL) ; get drive #
OR A ; check if zero
JR Z,ECMD1 ; ..if so, skip over
ADD A,40H ; else, make ascii
CP 'P'+1 ; check if valid
JR NC,ECMD1 ; ..if not, skip over
LD (CURRDSK),A ; else, save disk drive letter
ECMD1
INC HL ; move ptr fwd
LD A,(HL) ; get char
LD DE,VOLNAME ; ptr to buffer for volume name
LD B,11 ; max. 11 chars
CP ' ' ; is it <SP> ?
JR Z,ECMD2 ; ..if so, jump to continue
CP '/' ; is it option or help request ?
JR NZ,ECMD1V ; ..if not, jump to copy volume name
INC HL ; else, move ptr fwd
CP (HL) ; and check next char
JP Z,HLPEXIT ; ..if also '/', jump to display help
JR ECMD3OPT ; else, this char indicates an option
; volume name found, copy it
ECMD1V0: LD A,(HL) ; get char
ECMD1V: CP ' ' ; is it <SP> ?
JR Z,ECMD2 ; ..if so, jump to continue
LD (DE),A ; save char in VOLNAME buffer
INC DE ; move both ptr's forward
INC HL
DJNZ ECMD1V0 ; loop till done
; eval 2nd cmdline token (FCB #2)
ECMD2: XOR A ; clear A
LD (DE),A ; store in VOLNAME to indicate no name
LD HL,CPMFCB2+1 ; set ptr to standard FCB #2, after drive letter
LD A,(HL) ; get char
CP '/' ; is it option or help request ?
JR NZ,ECMD3OPT ; ..if not, letter must be an option, so skip over
INC HL ; else, move ptr fwd
CP (HL) ; and check next char
JP Z,HLPEXIT ; ..if also '/', jump to display help
; eval option and done
ECMD3OPT: CALL EVLOPT ; eval option
RET NZ ; if error, switch to interactive mode and return
; else, continue final check
LD HL,CPMFCB ; set ptr to standard FCB #1
LD A,(HL) ; get byte
OR A ; is it zero ?
JR Z,ECMDIM ; ..if so, jump done (interactive mode)
INC HL ; move ptr fwd
LD A,(HL) ; get char
CP ' ' ; is it <SP> ?
JR NZ,ECMDCM ; ..if not, jump done (cmdline mode)
LD A,(CPMFCB2+1) ; get char of 2nd token
CP ' ' ; is it <SP> ?
JR NZ,ECMDCM ; ..if not, jump done (cmdline mode)
; else, fall through (interactive mode)
ECMDIM: OR 0FFH ; set status (interactive mode)
RET
ECMDCM: XOR A ; set status (cmdline mode)
RET
; evaluate _one_ option on cmdline
; in: HL= ptr to char (already behind a leading '/')
; out: A= 0x00 cmdline mode, 0xFF interactive mode
; Z-flag reset (NZ) in case of error, i.e. interactive mode
; possible flags are /Q (quiet), /P (P2Dos stamps), /Z (NZTime stamps)
EVLOPT: LD B,7 ; max. 7 chars
EVLOPTQ: LD A,(HL) ; get char
CP 'Q' ; option /Q - quiet ?
JR NZ,EVLOPTP ; ..if not, jump to check next option
LD A,(PRGQFLG) ; get program quiet flag
XOR 0FFH ; toggle
LD (PRGQFLG),A ; ..and save back
JR EVLONXT ; jump to continue
EVLOPTP: CP 'P' ; option /P - P2Dos stamps ?
JR NZ,EVLOPTZ ; ..if not, jump to check next option
XOR A ; clear A
LD (STMPTYP),A ; ..and store stamp type
JR EVLONXT ; jump to continue
EVLOPTZ: CP 'Z' ; option /Z - NZTime stamps ?
JR NZ,EVLONX1 ; ..if not, jump to check for whitespace
OR 0FFH ; set A= 0xFF
LD (STMPTYP),A ; store stamp type
; ..and fall through to read next char
EVLONXT: INC HL ; move ptr fwd
LD A,(HL) ; get char
; options are separated by whitespace
EVLONX1: CP ' ' ; is it <SP> ?
JR Z,EVLOXIT ; ..if so, jump to exit loop
CP TAB ; is it <TAB> ?
JR Z,EVLOXIT ; ..if so, jump to exit loop
JR NZ,EVLOERR ; else, invalid option char found
DJNZ EVLOPTQ ; loop till done
EVLOXIT: XOR A ; set return code 0x00 (clear A and flags)
RET
EVLOERR: LD A,(PRGQFLG) ; get program quiet flag
OR A ; running in verbose mode ?
LD A,BEL
CALL Z,COUT ; ..if so, notify user
CALL EPRINT
DEFB CR,LF,'+++ Unrecognized Option "'
DEFB 0
LD A,(HL)
CALL COUT
CALL EPRINT
DEFB '" ... Setting Interactive'
DEFB 0
OR 0FFH ; set return code 0xFF
RET
; get console input
; and check for abort request
CINPUT: CALL CAPIN ; get char and capitalize
CP CTRLC ; is it <Ctrl-C> ?
JP Z,EXIT
CP ESC ; is it <ESC> ?
JP Z,EXIT
CP 'a' ; below 'a' ? (not possible, CAPIN capitalizes)
RET C
CP 'z'+1 ; between lowercase 'a' and lowercase 'z' ?
RET NC
AND 01011111b ; remove bit 5 to capitalize
RET
; ##### unreferenced code (not used)
; copy 32 (0x20) bytes from (HL) to (DE)
LD B,32
UNUSED1: LD A,(HL)
LD (DE),A
INC HL
INC DE
DJNZ UNUSED1
RET
; #####
; fill memory with zero, or byte
; in: A= byte
; B= # of bytes
; HL= target addr
FILLZ: XOR A ; clear A
FILLA: LD (HL),A ; store byte
INC HL ; move ptr fwd
DJNZ FILLA ; loop
RET
; verbose print - print string to CON: if quiet flag is off
; in: (Stack) contains start addr of nul-terminated string
PVBOSE: LD A,(PRGQFLG) ; get program quiet flag
OR A ; running in verbose mode ?
JP Z,EPRINT ; ..if so, jump to print and let return from there
EX (SP),HL ; else, swap HL and top-of-stack
PVBOSE0: LD A,(HL) ; get char
INC HL ; move ptr fwd
OR A ; is byte = zero ?
JR NZ,PVBOSE0 ; ..if not, loop
EX (SP),HL ; else, swap back
RET
; entry points for indirect BIOS calls
; BC is loaded with absolute offset from WBOOT (fn #1)
; to respective jump instruction, i.e. 3 bytes per fn
BIOSELD: PUSH BC
LD BC,3*8 ; fn #9 SELDSK select disk
JR BIOSFN
BIOSTTR: PUSH BC
LD BC,3*9 ; fn #10 SETTRK set track
JR BIOSFN
BIOSTSE: PUSH BC
LD BC,3*10 ; fn #11 SETSEC set sector
JR BIOSFN
BIOSTDM: PUSH BC
LD BC,3*11 ; fn #12 SETDMA set buffer addr
JR BIOSFN
BIOREAD: PUSH BC
LD BC,3*12 ; fn #13 READ read one sector (not used)
JR BIOSFN
BIOWRIT: PUSH BC
LD BC,3*13 ; fn #14 WRITE write one sector
JR BIOSFN
BIOSTRN: PUSH BC
LD BC,3*15 ; fn #16 SECTRN sector translation
JR BIOSFN
; call BIOS fn indirectly
; in: BC= offset to fn in Bios jump table
BIOSFN: EX (SP),HL ; swap HL and top-of-stack (= prev. BC)
PUSH HL ; save HL (prev. BC)
LD HL,(CPMBIOS+1) ; Bios base addr
ADD HL,BC ; add offset to fn #
POP BC ; restore BC
EX (SP),HL ; swap HL and top-of-stack again
RET ; "call" by returning to Bios fn
UNUSED2:
DEFB 0,0,0,0,0,0 ; ##### unreferenced chunk of data
DEFB '!!!TIME&DAT' ; obviously not used
DEFB 0,0,0,0,0,0,0,0
DEFB 0,0,0,0,0,0,0,0
DEFB 0,0,0,0,0,0,0,0
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
; Z3LIB - 0x08a7
; SYSLIB - 0x091a
; end addr 0x09e5 (begin DSEG)
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
DSEG
STMPTYP: DEFB 0 ; stamp type flag, 0x00 = P2Dos, 0xFF = NZTime
PRGQFLG: DEFB 0 ; program quiet flag, 0x00 = verbose
VOLNAME: DEFS 12 ; buffer for volume name, 11 bytes + <NUL> terminator
RUNMODE: DEFB 0 ; indicator, 0x00 = cmdline mode / 0xFF = interactive mode
OLDDRV: DEFB 0 ; logged drive at program start
CURRDSK: DEFB 0 ; current disk drive letter
WSPC: ; workspace starts here
DIRMAX: DEFW 0 ; max. # of dir entries (from DPH +1)
STMPMAX: DEFW 0 ; max. # of stamp entries (= DIRMAX / 4)
STMPCUR: DEFW 0 ; current # of stamp entry (used as counter)
SKEWTBL: DEFW 0 ; addr of skew table (from DPH)
DEFS 070H ; room for stack
STACK: DEFW 0 ; stack storage location
END
;************************************************************************
; Remarks jxl:
; HASHINI.COM, included in available B/P Bios package(s), was dis-
; assembled and extensively commented. Labels are up to seven chars long
; to comply with M-REL standards. However, it is recommended to use SLR
; tools that support labels up to sixteen chars.
; In its current state, the compiled/linked file matches exactly the
; original SHOWHD.COM, i.e. no changes to the source were made. Possible
; optimisations detected during disassembly are marked with "#####" in the
; comment. It is fair to say that the program seems to be in an early
; stage; as the version number indicates. Apparently, provisions were made
; to test exitence, or even generate a DateStamper !!!TIME&.DAT file
; (which is not the case right now.)
; The program supports an interactive and a command line mode. Labels
; start with "IM" to indicate code specifically for interactive mode.
;************************************************************************

View File

@@ -0,0 +1,640 @@
TITLE "B/P Bios System Loader"
;************************************************************************
;* L D S Y S *
;* Load a B/P Bios based system into RAM memory for direct execution *
;* by Harold F. Bower and Cameron W. Cotrill *
;*----------------------------------------------------------------------*
;* Disassembly: jxl Dec 2024 *
;* public release 1.0 Apr 2025 *
;* see remarks at the end *
;*----------------------------------------------------------------------*
;* LINK with Version 4 libraries: VLIB, Z3LIB, SYSLIB *
;* *
;* A>Z80ASM LDSYS/RS *
;* A>SLRNK LDSYS/N,/A:100,/D:0CF8,LDSYS,VLIBS/S,Z3LIBS/S,SYSLIBS/S,/E *
;************************************************************************
VER EQU 12
REV EQU ' '
DATE MACRO
DEFB '17 Jul 96'
ENDM
BEL EQU 07H ; Bell character
LF EQU 0AH ; Line Feed character
CR EQU 0DH ; Carriage Return character
CPMBDOS EQU 5 ; CP/M BDOS entry point (JP)
CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype)
CPMDMA EQU 80H ; CP/M standard DMA buffer
; From VLIB Get..
EXTRN VPRINT, Z3VINIT
; From Z3LIB Get..
EXTRN GETNAME, PRTNAME, ZFNAME, Z3LOG, WHRENV
EXTRN GZMTOP ; ##### not used, but linked
; From SYSLIB Get..
EXTRN PUTUD, GETUD, F$OPEN, F$READ, SETDMA, PFN3, PHL4HC, COUT, CODEND
EXTRN F$CLOSE, CRLF ; ##### not used, but linked
;::::: PROGRAM START
ORG 100H
CSEG
LDSYS: JP START ; bypass header
DEFB 'Z3ENV' ; this is a ZCPR3 utility
DEFB 1 ; show external environment
ENVADR: DEFW 0 ; addr of Z3 environment
DEFW LDSYS ; type 4 filler
DEFB 'LDSYS ',0 ; configuration name
FTYPE: DEFB 'IMG' ; standard file type
START: LD (STACK),SP
LD SP,STACK
CALL PUTUD ; currently logged drive/user
LD HL,(CPMBDOS+1)
CALL WHRENV ; find Z3 Environment Descriptor
PUSH AF
LD (ENVADR),HL ; store ENV addr
CALL Z3VINIT ; ..and init for Z3LIB routines
CALL GETNAME ; get actual program name
CALL VPRINT
DEFB CR,LF,1,'B/P Bios System Loader',2,' Vers ',VER/10+'0','.'
DEFB VER MOD 10 + '0',REV,' '
DATE
DEFB CR,LF,' Copyright (C) 1991,3 by H.F.Bower & C.W.Cotrill',CR,LF
DEFB 0
; get first token from command line (in FCB #1)
LD A,(CPMFCB+1)
CP '/' ; is this a help request ?
JP Z,HELP ; ..if so, jump display help screen
POP AF
JR Z,E$NOFIL ; else, jump error no file specified
LD HL,(ENVADR) ; get addr Z3ENV
LD DE,70 ; offset to high byte BIOS addr
ADD HL,DE ; move ptr
LD H,(HL) ; get high byte of B/P Bios page addr
LD L,30*3 ; ..and set low byte to fn #30
LD A,(HL) ; check byte at ptr location
CP 0C3H ; is it opcode 0xC3 (JP) ?
JR NZ,E$NOFIL ; ..if not, jump error and exit
CALL JUMPHL ; else, "call" B/P Bios fn #30 (RETBIO)
LD HL,-6 ; move ptr 6 bytes backward
ADD HL,DE ; (signature string)
LD A,(HL) ; get byte
CP 'B' ; is it 'B' ?
JR NZ,E$NOFIL ; ..if not, jump error and exit
INC HL ; ptr fwd
LD A,(HL) ; get byte
CP '/' ; is it '/' ?
JR NZ,E$NOFIL ; ..if not, jump error and exit
INC HL ; ptr fwd
LD A,(HL) ; get byte
CP 'P' ; is it 'P' ?
JR NZ,E$NOFIL ; ..if not, jump error and exit
LD DE,6 ; else, set ptr to OPTF1 (Bios Option Flags)
ADD HL,DE ; at CONFIG+2
BIT 7,(HL) ; check bit 7 (0= not locked, 1= locked, can't reload)
JR Z,E$NOFIL ; ..if not set, skip over
E$RUNBP: CALL VPRINT
DEFB CR,LF,BEL,'*** Running Bios Cannot be Replaced ! ***',CR,LF
DEFB 0
JP EXIT
E$NOFIL: LD A,(CPMFCB+1)
CP ' '
JR NZ,EVALCMD
CALL VPRINT
DEFB ' *** No file specified ! ***',CR,LF,BEL
DEFB 0
;::::: EXIT PROGRAM
EXIT: CALL GETUD ; set previous drive/user
LD SP,(STACK) ; set stack to initial location
RET ; ..and return to system
;::::: EVALUATE COMMAND LINE
EVALCMD: LD DE,CPMFCB
LD HL,CPMDMA+1 ; set ptr to start of string
ECMD1: LD A,(HL) ; get char
INC HL ; move ptr fwd
CP ' ' ; is it <SP> ?
JR Z,ECMD1 ; ..if so, loop get next char
DEC HL ; non-blank char found, move ptr back
XOR A ; and nullify A
CALL ZFNAME ; parse token into FCB
JP NZ,E$AMBIG ; filename must be unambiguous, jump if error
LD HL,9 ; move ptr to file type
ADD HL,DE
LD A,(HL) ; get char
CP ' ' ; is it <SP> ?
JR NZ,RDIMG ; ..if not, skip over
PUSH DE ; else, save regs
EX DE,HL ; swap regs
LD HL,FTYPE ; ptr to standard file type
LD BC,3 ; 3 chars
LDIR ; ... and copy
POP DE ; restore ptr to ZCPR3 FCB
;::::: READ IMAGE FILE
RDIMG: CALL Z3LOG ; log in drive/user
CALL F$OPEN ; attempt to open file
OR A
JP NZ,E$OPEN ; ..if error, jump error and exit
CALL CODEND ; get first available page after code end
LD (WSPCBEG),HL ; ..and store it
RDIMG0: PUSH HL
CALL SETDMA ; set DMA buffer addr (HL)
LD DE,CPMFCB ; set standard FCB #1
CALL F$READ ; read one sector (128 bytes)
POP HL ; restore start addr
JR NZ,RDIMG1 ; ..if end of file, jump exit loop
LD DE,128 ; else, move buffer addr forward
ADD HL,DE
JR RDIMG0 ; ..and loop
RDIMG1: CALL GETUD ; set previously logged drive/user
CALL VPRINT
DEFB CR,LF,' CCP starts at : '
DEFB 0
;::::: READ IMAGE HEADER
; header contains information at following offsets:
; ZCPR CCP 0x10 (16) filename
; 0x1B (27) Unbanked base addr, 0x1D (29) Unbanked size
; 0x1F (31) Banked base addr, 0x22 (33) Banked size
; ZSDOS 0x30 (48) filename
; 0x3B (59) Unbanked base addr, 0x3D (61) Unbanked size
; 0x3F (63) Banked base addr, 0x41 (65) Banked size
; B/P Bios 0x50 (80) filename
; 0x5B (91) Unbanked base addr, 0x5D (93) Unbanked size
; 0x5F (95) Banked base addr, 0x62 (98) Banked size
; 0x70 (112) IMG filename
RDHDR: LD DE,27 ; offset CCP Unbanked base addr
CALL PSEGAS ; display addr and size of segment
LD DE,33 ; offset CCP Banked size
CALL GBYTEWS ; check if empty (0x0000)
JR Z,RDHDR0 ; ..if so, skip over
CALL VPRINT
DEFB ' Banked Ccp at : '
DEFB 0
LD DE,31 ; offset to CCP Banked base addr
CALL PSEGAS ; display addr and size
RDHDR0: CALL VPRINT
DEFB ' DOS starts at : '
DEFB 0
LD DE,59 ; offset to DOS Unbanked base addr
CALL PSEGAS ; display addr and size of segment
LD DE,65 ; offset to DOS Banked size
CALL GBYTEWS ; check if empty (0x0000)
JR Z,RDHDR1 ; ..if so, skip over
CALL VPRINT
DEFB ' Banked Dos at : '
DEFB 0
LD DE,63 ; offset to DOS Banked base addr
CALL PSEGAS ; display addr and size
RDHDR1: CALL VPRINT
DEFB ' BIOS starts at : '
DEFB 0
LD DE,91 ; offset to B/P Bios Unbanked base addr
CALL PSEGAS ; display addr and size of segment
LD DE,97 ; offset to B/P Bios Banked size
CALL GBYTEWS ; check if empty (0x0000)
JR Z,LDSEG ; ..if so, skip over
CALL VPRINT
DEFB ' Banked Bios at : '
DEFB 0
LD DE,95 ; offset to B/P Bios Banked base addr
CALL PSEGAS ; display addr and size
;::::: LOAD SYSTEM SEGMENTS
LDSEG: CALL VPRINT
DEFB CR,LF,' ...installing '
DEFB 0
CALL CHKBNKD ; check options flag if banked system
JR Z,LDSEG0 ; ..if not, skip over
CALL VPRINT
DEFB 'Banked '
DEFB 0
LDSEG0: CALL VPRINT
DEFB 'System',CR,LF,LF
DEFB 0
LDSEG1: DI ; disable interrupts
LD HL,(WSPCBEG) ; get addr WSPC area
LD DE,100H ; + 100H to account for file base
ADD HL,DE
; ZCPR Unbanked portion
LD (CCPUSTRT),HL ; store start in WSPC area
LD DE,27 ; file offset to ZCPR Unbanked base addr
CALL G2WRDWS
LD (CCPUSIZ),BC ; store size
LD (CCPUADR),DE ; store base addr
LD HL,(CCPUSTRT) ; get start in WSPC
PUSH HL
ADD HL,BC ; calc end / start of ZSDOS Unbanked portion
LD (DOSUSTRT),HL ; ..and store it
POP HL ; restore start
LDIR ; copy ZCPR Unbanked
; from img file to target addr
; ZCPR Banked portion
LD DE,31 ; offset to ZCPR Banked base addr
CALL G2WRDWS
LD (CCPBSIZ),BC ; store size
LD (CCPBADR),DE ; store base addr
LD HL,(DOSUSTRT) ; get previously calc'd end
LD (CCPBSTRT),HL ; ..and store it as Banked start in WSPC
LD A,B ; check if size is zero
OR C
JR Z,LDSEG2 ; ..if so, skip over
ADD HL,BC ; else, calc new start of ZSDOS Unbanked
LD (DOSUSTRT),HL ; ..and update it
; ZSDOS Unbanked portion
LDSEG2: LD DE,59 ; offset to ZSDOS Unbanked base addr
CALL G2WRDWS ; DE= base addr, BC= size
LD (DOSUSIZ),BC ; store size
LD HL,(DOSUSTRT) ; get ZSDOS Unbanked start in WSPC area
PUSH HL
ADD HL,BC ; calc end / start of B/P Bios Unbanked portion
LD (BIOUSTRT),HL ; ..and store it
POP HL ; restore start
LDIR ; copy ZSDOS Unbanked
; from img file to target addr
; ZSDOS Banked portion
LD DE,63 ; offset to ZSDOS Banked base addr
CALL G2WRDWS
LD (DOSBSIZ),BC ; store size
LD (DOSBADR),DE ; store base addr
LD HL,(BIOUSTRT) ; get previously calc'd end
LD (DOSBSTRT),HL ; ..and store it as Banked start in WSPC
LD A,B ; check if size is zero
OR C
JR Z,LDSEG3 ; ..if so, skip over
ADD HL,BC ; else, calc new start of B/P Bios Unbanked
LD (BIOUSTRT),HL ; ..and update it
; B/P Bios Unbanked portion
LDSEG3: LD DE,91 ; offset to B/P Bios Unbanked base addr
CALL G2WRDWS
LD (BIOUSIZ),BC ; store size
LD (BIOUADR),DE ; store base addr
LD HL,(BIOUSTRT) ; get start in WSPC area
PUSH HL
ADD HL,BC ; calc end / beginning of Banked portion
LD (BIOBSTRT),HL ; ..and store it
POP HL ; restore start
LDIR ; copy B/P Bios Unbanked
; from img file to target addr
; B/P Bios Banked portion
LD DE,95 ; offset to B/P Bios Banked base addr
CALL G2WRDWS
LD (BIOBSIZ),BC ; store size
LD (BIOBADR),DE ; store base addr
; use B/P Bios functions at new location (Unbanked portion was just loaded)
LD HL,(BIOUADR) ; get (new) B/P Bios base addr
LD L,82h ; offset to TPABNK in config area
LD A,(HL) ; get value
LD L,27*3 ; offset to B/P Bios fn #27 (SELMEM)
CALL JUMPHL ; "call" fn
LD HL,CCPBSIZ ; ptr to stored ZCPR Banked size
CALL LDBNKD
LD HL,DOSBSIZ ; ptr to stored ZSDOS Banked size
CALL LDBNKD
LD HL,BIOBSIZ ; ptr to stored B/P Bios Banked size
CALL LDBNKD
; Z3ENV Descriptor
LD BC,(WSPCBEG) ; get (new) B/P Bios base addr
LD HL,155 ; offset to addr of Z3 Environment Descriptor
ADD HL,BC ; in B/P Bios config area (CONFIG+26)
LD E,(HL) ; get addr in DE
INC HL
LD D,(HL)
LD HL,128 ; offset from start of WSPC area (img file)
ADD HL,BC
LD BC,128 ; bytes to copy
LDIR
; boot new system
LD SP,80H ; set stack pointer to default
XOR A ; nullify A
; ..and fall through, initiating a cold boot
;::::: SUPPORT FUNCTIONS
; call B/P Bios function (at new base addr in RAM)
; in: A= offset to JP (fn # *3)
BIOSFN: LD HL,(BIOUADR) ; get (new) B/P Bios base addr
LD L,A ; adjust to JP of fn #
; ..and fall through
; "called" as a pseudo-routine that returns to caller
; in: HL= target addr
JUMPHL: JP (HL) ; jump to addr in HL regs
; load banked portions of (new) system from WSPC area to SYSBNK
; segment information is stored as consecutive 16-bit words
; in the order <size> <base addr> <start addr in WSPC>
; in: HL= ptr to <size>
; uses B/P Bios functions at new location (Unbanked portion)
LDBNKD: LD C,(HL) ; get <size> low byte
LD A,C
INC HL ; move ptr fwd
LD B,(HL) ; get <size> high byte
INC HL ; ptr fwd
OR B ; check if <size> is zero
RET Z ; ..if so, return
PUSH BC ; save regs
PUSH HL
LD HL,(BIOUADR) ; get (new) B/P Bios base addr
LD L,82H ; offset to TPABNK in config area
LD C,(HL) ; get value
INC HL ; move ptr to SYSBNK
LD B,(HL) ; get value
LD A,29*3 ; offset to B/P Bios fn #29 (XMOVE)
CALL BIOSFN
POP DE ; restore regs, DE now ptr to <base addr>
POP BC
LD HL,(BIOUADR) ; get (new) B/P Bios base addr
LD L,25*3 ; offset to B/P Bios fn #25 (MOVE)
PUSH HL ; put on stack, so it is called at return
; and let Bios routine return to initial caller
EX DE,HL ; swap regs
LD E,(HL) ; get <base addr> in DE
INC HL
LD D,(HL)
INC HL
LD A,(HL)
INC HL
LD H,(HL) ; get <start addr in WSPC> in HL
LD L,A
RET ; ..and call B/P Bios fn #25 (MOVE)
; to copy banked segment to SYSBNK
; get _two_ consecutive 16-bit words from offset addr in WSPC area
; in: DE= offset
; out: DE= first value (at addr)
; BC= second value (at addr+2)
; HL= ptr to high byte of second value in WSPC area
; uses BC, DE, HL
G2WRDWS: CALL G1WRDWS ; get first word in HL
EX DE,HL ; swap regs
INC HL ; move ptr fwd
LD C,(HL) ; get second word in BC
INC HL
LD B,(HL)
RET
; print base addr and size of system segment ton CON:
; in: DE= offset in WSPC area
PSEGAS: CALL G1WRDWS ; get 16-bit word (in HL) at offset (in DE)
CALL PHL4HC ; ..and print to CON: as hex digits
EX DE,HL ; swap regs
INC HL ; move ptr fwd
LD E,(HL) ; get next 16-bit word in DE
INC HL
LD D,(HL)
CALL VPRINT
DEFB ' ('
DEFB 0
EX DE,HL ; swap regs
CALL PHL4HC ; print value (now in HL) to CON: as hex digits
CALL VPRINT
DEFB 'H Bytes)',CR,LF
DEFB 0
RET
; get _one_ 16-bit word from offset addr in WSPC area
; in: DE= offset
; out: HL= value
; DE= ptr to high byte in WSPC area
G1WRDWS: LD HL,(WSPCBEG) ; addr WSPC area
ADD HL,DE ; add offset
LD E,(HL) ; get low byte at ptr addr in E
INC HL
LD D,(HL) ; get high byte at ptr addr in D
EX DE,HL ; swap regs
RET
; get byte from offset addr in WSPC area
; in: DE= offset
; out: A= value, Z-Flag set if following byte is eqal
; HL= ptr to next byte in WSPC area
GBYTEWS: LD HL,(WSPCBEG) ; addr WSPC area
ADD HL,DE ; add offset
LD A,(HL) ; get byte
INC HL ; move ptr fwd
OR (HL) ; check if next byte has same value
RET
; check if img file contains a banked system
; in: -
; out: Z-Flag set for Unbanked Bios, NZ= Banked
CHKBNKD: LD HL,(WSPCBEG) ; addr WSPC area
INC H ; + 100H to account for file base
EX DE,HL ; swap regs, DE holds result over next calc's
LD BC,29 ; offset to ZCPR Unbanked size
CALL SEGTSIZ ; ..add ZCPR size(s) to DE
LD BC,61 ; offset to ZSDOS Unbanked size
CALL SEGTSIZ ; ..add ZSDOS size(s) to DE
LD HL,128 ; DE= offset to beginning of B/P Bios in
ADD HL,DE ; img file, move fwd by 128 more bytes
LD A,(HL) ; get B/P Bios options flag OPTF1 (at CONFIG+2)
AND 00000001b ; check bit 0, and set Z-Flag accordingly
RET
; get total size of a system segment (add Unbanked and Banked sizes)
; in: BC= offset in WSPC area to Unbanked size
; out: DE= sum of segment sizes
SEGTSIZ: LD HL,(WSPCBEG) ; addr WSPC area
ADD HL,BC ; add offset
LD C,(HL) ; get 16-bit word in BC
INC HL ; (Unbanked size)
LD B,(HL)
EX DE,HL ; swap regs
ADD HL,BC ; add retrieved value
EX DE,HL ; ..and swap regs back
INC HL ; move ptr 3 bytes fwd
INC HL
INC HL
LD C,(HL) ; get 16-bit value in BC
INC HL ; (Banked size)
LD B,(HL)
EX DE,HL ; swap regs
ADD HL,BC ; add retrieved value
EX DE,HL ; ..and swap regs back
RET
;::::: ERROR MESSAGES
E$AMBIG: CALL VPRINT
DEFB CR,LF,BEL,' --- Ambiguous File: '
DEFB 0
JR E$FNAME
E$OPEN: CALL VPRINT
DEFB CR,LF,BEL,' --- Error Opening: '
DEFB 0
E$FNAME: LD DE,CPMFCB+1 ; ptr to file name in standard FCB #1
CALL PFN3 ; print it
JP EXIT
;::::: HELP SCREEN
HELP: CALL VPRINT
DEFB CR,LF,1
DEFB 0
CALL PPRGNAM
CALL VPRINT
DEFB 2,' Loads and executes a System image prepared by',CR,LF
DEFB ' BPBUILD containing a B/P Bios.',CR,LF,LF
DEFB ' Syntax:',CR,LF
DEFB ' '
DEFB 0
CALL PPRGNAM
CALL VPRINT
DEFB ' // - print this message',CR,LF
DEFB ' '
DEFB 0
CALL PPRGNAM
CALL VPRINT
DEFB ' [du|dir:]name[.typ] - load system image',CR,LF,LF
DEFB ' File Type Defaults to "'
DEFB 0
LD HL,FTYPE ; ptr to default file type
LD B,3 ; # of chars
HELP0: LD A,(HL) ; get char
INC HL ; move ptr fwd
CALL COUT ; display char on CON:
DJNZ HELP0 ; ..and loop
CALL VPRINT
DEFB '" if not explicitly entered',CR,LF,LF
DEFB 'NOTE: This utility will NOT load a system '
DEFB 'if the "Lock" bit in',CR,LF
DEFB 'the Option Byte (Bit 7 of CONFIG+2) is Set to "1"',CR,LF
DEFB 0
JP EXIT
; print program name on CON: device
; (either the actual name, or fallback to default)
; only used by HELP
PPRGNAM: LD A,(ENVADR+1) ; get high byte of ENVPTR
OR A ; check if valid (<> zero)
JP NZ,PRTNAME ; ..if so, display actual name
; and let return from there
CALL VPRINT ; else, display default
DEFB 'LDSYS'
DEFB 0
RET
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
; VLIB - 0x06db
; Z3LIB - 0x08fc
; SYSLIB - 0x0bcf
; end addr 0x0bf8 (begin DSEG)
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
;::::: RAM STORAGE
DSEG
WSPCBEG: DEFW 0 ; begin of workspace
; (first available page, returned by CODEND)
; addresses of new system as extracted from img file
; first _Unbanked_, then _Banked_
BIOUADR: DEFW 0 ; B/P Bios Unbanked base addr
CCPUADR: DEFW 0 ; ZCPR Unbanked base addr
CCPUSTRT: DEFW 0 ; start in WSPC area
CCPUSIZ: DEFW 0 ; size
DOSUSTRT: DEFW 0 ; ZSDOS Unbanked start
DOSUSIZ: DEFW 0 ; size
BIOUSTRT: DEFW 0 ; B/P Bios Unbanked start
BIOUSIZ: DEFW 0 ; size
CCPBSIZ: DEFW 0 ; ZCPR Banked size
CCPBADR: DEFW 0 ; base addr
CCPBSTRT: DEFW 0 ; start
DOSBSIZ: DEFW 0 ; ZSDOS Banked size
DOSBADR: DEFW 0 ; base addr
DOSBSTRT: DEFW 0 ; start
BIOBSIZ: DEFW 0 ; B/P Bios Banked size
BIOBADR: DEFW 0 ; base addr
BIOBSTRT: DEFW 0 ; start
DEFW GZMTOP ; reference Z3LIB/SYSLIB routines, so they are linked
DEFW F$CLOSE
DEFW CRLF
DEFS 30H-6 ; room for stack
; -6 to account for above ref's
STACK: DEFW 0 ; stack storage location
END
;************************************************************************
; Remarks jxl:
; LDSYS.COM, included in available B/P Bios package(s), was dis-
; assembled and extensively commented. Labels are unique up to the seventh
; character to comply with M-REL standards. However, it is recommended to
; use SLR tools that support labels up to sixteen chars.
; In its current state, the compiled/linked file _almost_ matches the
; original LDSYS.COM with the exception of Z3LIB routine GZMTOP, and
; SYSLIB routines F$CLOSE and CRLF. Even though they are part of the
; original program, they are neither needed nor referenced. This seems
; to indicate that other versions of the LIB's were used. To reproduce
; the original program, the above mentioned routines are referenced (in
; stack area) to have them included when linking.
;
; As a byproduct of the disassembly, the structure of a B/P Bios image
; file was documented. This file contains an excerpt.
;************************************************************************

View File

@@ -0,0 +1,409 @@
TITLE "B/P Bios HD drive partition display"
;************************************************************************
;* S H O W H D *
;* Display DPH and DPB data for making B/P HD Partition data the same *
;* by Harold F. Bower and Cameron W. Cotrill *
;*----------------------------------------------------------------------*
;* Disassembly: jxl Jan 2025 *
;* public release 1.0 Apr 2025 *
;* see remarks at the end *
;*----------------------------------------------------------------------*
;* LINK with Version 4 libraries: SYSLIB *
;* *
;* A>Z80ASM SHOWHD/RS *
;* A>SLRNK SHOWHD/N,/A:100,/D:064D,SHOWHD,SYSLIBS/S,/E *
;************************************************************************
VER EQU 10
REV EQU ' '
DATE MACRO
DEFB '2 Nov 91'
ENDM
CTRLC EQU 03H ; Control-C character
BEL EQU 07H ; Bell character
TAB EQU 09H ; Tab character
LF EQU 0AH ; Line Feed character
CR EQU 0DH ; Carriage Return character
ESC EQU 1BH ; Escape character
CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP)
CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype)
; For SYSLIB make visible...
PUBLIC COUT
; From SYSLIB Get..
EXTRN EPRINT, BOUT, CAPINE, PAFDC, PHLFDC, PA2HC
;::::: PROGRAM START
ORG 100H
CSEG
SHOWHD: JP START ; bypass header
DEFB 'Z3ENV' ; this is (not really) a Z3CPR utility
DEFB 1 ; show external environment
ENVADR: DEFW 0 ; addr of Z3 environment
START: LD (STACK),SP
LD SP,STACK
CALL EPRINT
DEFB CR,LF,'Show Hard Drive Partition Data - '
DATE
DEFB CR,LF
DEFB 0
LD A,(CPMFCB+1) ; check first char of cmdline
CP '/' ; is this a help request ?
JP Z,HELP ; ..if so, jump
START0: CALL EPRINT
DEFB CR,LF,'Enter Drive Letter [A..P] : '
DEFB 0
CALL CAPINE ; get user input
CP CTRLC ; is it <Ctrl-C> ?
JP Z,0 ; ..abort
CP ESC ; is it <ESC> ?
JP Z,0 ; ..abort
CP 'A' ; below ascii 'A' ?
JR C,START0 ; ..if so, loop ask for new input
CP 'P'+1 ; greater than ascii 'P' ?
JR NC,START0 ; ..if so, loop ask for new input
LD (DRLTR),A ; store drive letter
CALL EPRINT
DEFB CR,LF,LF,'Drive: '
DEFB 0
CALL COUT ; display drive
CALL EPRINT
DEFB CR,LF,TAB,'DPH Info',TAB,TAB,'BPCNFG Info',CR,LF
DEFB 0
CALL GDPHADR ; get DPH addr for selected Disk drive
LD (DPHADR),HL ; ..and store it
LD A,H ; check if invalid (= zero)
OR L
JR NZ,PDSKDAT ; ..if not, skip over
CALL EPRINT
DEFB CR,LF,BEL,'+++ Invalid Drive : '
DEFB 0
LD A,(DRLTR) ; get drive letter
CALL COUT ; ..and display it
JP START0 ; then loop to ask for new input
;::::: DISPLAY DISK DRIVE DATA
PDSKDAT: LD DE,10 ; offset in DPH to DPB addr
ADD HL,DE
LD E,(HL) ; DPB addr in DE
INC HL
LD D,(HL)
EX DE,HL ; swap regs
LD (DPBADR),HL ; ..and store DPB addr
CALL EPRINT
DEFB CR,LF,LF,' Sectors/Track = '
DEFB 0
LD E,(HL) ; get Sect/Trk from DPB in DE
INC HL
LD D,(HL)
INC HL
EX DE,HL ; swap regs
CALL PHLFDC ; ..and display (as decimal)
SRL H ; divide by 2
RR L
SRL H ; .. /4
RR L
SRL H ; .. /8
RR L
LD (KBTRK),HL ; store kByte/Trk
EX DE,HL ; swap regs
CALL P2TAB
CALL EPRINT
DEFB '(same)',CR,LF,' Blk Shift Fctr = '
DEFB 0
LD A,(HL) ; get next byte from DPB (= BSH, Block Shift Factor)
INC HL ; move ptr fwd
CALL PAFDC ; display BSH
CALL P2TAB
SUB 3 ; BSH -3
LD B,A ; use as counter for multiplication
LD (BSH3),A ; ..and also store it
LD A,1 ; set initial value
JR Z,PBLKSIZ ; if BSH -3 = 0, skip over
BLKSZLP: ADD A,A ; *2
DJNZ BLKSZLP ; loop
PBLKSIZ: CALL PAFDC ; display block size
; (BSH= 3 -> 1k, 4 -> 2k, ... 8 -> 32k)
CALL EPRINT
DEFB 'k/Block',CR,LF,' Block Mask = '
DEFB 0
LD A,(HL) ; next byte from DPB (= BSM, Block Mask)
INC HL
CALL PAFDC ; ..display it
CALL EPRINT
DEFB CR,LF,' Extent Mask = '
DEFB 0
LD A,(HL) ; next byte from DPB (= EXM, Extent Mask)
INC HL
CALL PAFDC ; ..display it
CALL EPRINT
DEFB CR,LF,' Disk Blocks-1 = '
DEFB 0
LD E,(HL) ; next 16-bit value from DPB in DE
INC HL ; (= Disk Size in BLS units -1)
LD D,(HL)
INC HL
EX DE,HL ; swap regs
CALL PHLFDC ; display value
CALL P2TAB
INC HL ; +1 (= Disk Size)
LD A,(BSH3) ; get BSH-3
LD B,A ; set as initial loop counter
OR A ; check if zero (means single density 1k/block)
LD A,0 ; nullify A
JR Z,PDSKCAP ; ..if already zero, no more calc needed
DSKCLP: ADD HL,HL ; double HL (2, 4, 8 etc. k/block)
ADC A,0 ; a power-of-two multiple
DJNZ DSKCLP ; ..and loop
LD (DCAPH),A ; store disk capacity in kByte
LD (DCAPML),HL ; as 24-bit value
PDSKCAP: CALL PDSKSZ ; ..and display it
CALL EPRINT
DEFB 'k Total ('
DEFB 0
PUSH DE
LD DE,(KBTRK) ; kByte/Trk
LD HL,(DCAPML) ; disk capacity in kByte
LD A,(DCAPH)
LD BC,-1 ; set initial counter value
OR A
DSKTRLP: INC BC ; increase counter (quotient)
SBC HL,DE ; divide by subtraction
SBC A,0 ; check for underflow
JR NC,DSKTRLP ; ..and loop while more to go
LD H,B ; result in HL
LD L,C
CALL PHLFDC ; ..display it
CALL EPRINT
DEFB ' Tracks)'
DEFB 0
POP DE ; restore DPB ptr
EX DE,HL ; swap to HL
CALL EPRINT
DEFB CR,LF,' Max Dirs - 1 = '
DEFB 0
LD E,(HL) ; get next 16-bit value from DPB in DE
INC HL ; (= Dir Max -1)
LD D,(HL)
INC HL
EX DE,HL ; swap regs
CALL PHLFDC ; ..and display value
CALL P2TAB
INC HL ; +1 (= Dir Max)
CALL PHLFDC ; ..and display, too
EX DE,HL
CALL EPRINT
DEFB ' Dir Entries',CR,LF,' Alloc bytes = '
DEFB 0
LD A,(HL) ; next byte from DPB (= AL0, Allocation byte 0)
INC HL
LD D,(HL) ; (= AL1, Allocation byte 1)
INC HL
CALL PA2HC ; display AL0 as hex
CALL EPRINT
DEFB 'H, '
DEFB 0
LD A,D ; AL1 in A
CALL PA2HC ; ..and display as hex
CALL EPRINT
DEFB 'H',CR,LF,' Check Size = '
DEFB 0
LD E,(HL) ; next 16-bit value from DPB in DE
INC HL ; (= CKS, Check Size)
LD D,(HL)
INC HL
EX DE,HL ; swap regs
CALL PHLFDC ; display value
EX DE,HL ; swap regs back
CALL EPRINT
DEFB CR,LF,' Track Offset = '
DEFB 0
LD E,(HL) ; next 16-bit value from DPB in DE
INC HL ; (= Track Offset)
LD D,(HL)
INC HL
EX DE,HL ; swap regs
CALL PHLFDC ; display value
EX DE,HL ; swap regs back
CALL P2TAB
CALL EPRINT
DEFB '(same)',CR,LF
DEFB 0
JP 0 ; and exit with Warm Boot
; print 2 tabs on CON:
P2TAB: PUSH AF
LD A,TAB ; <TAB> in A
CALL COUT ; display on CON:
CALL COUT ; 2x
POP AF ; restore
RET
;::::: HELP
HELP
CALL EPRINT
DEFB CR,LF,'SHOWHD - Display DPH and DPB data for '
DEFB 'specified drive for making B/P',CR,LF
DEFB ' Hard Drive Partition data the same as '
DEFB 'an operating system.',CR,LF,LF
DEFB ' Syntax:',CR,LF,LF
DEFB TAB,'SHOWHD <-- Execute program interactively',CR,LF
DEFB TAB,'SHOWHD // <-- Display this message',CR,LF
DEFB 0
LD SP,(STACK)
RET
;::::: SUPPORT FUNCTIONS
; get addr of Disk Parameter Header (DPH)
; in: Disk drive letter in mem variable
; out: HL= addr DPH
GDPHADR: LD HL,(CPMBIOS+1) ; addr Bios fn #1 (WBOOT)
LD L,9*3 ; adjust ptr to fn #9 (SELDSK)
LD A,(DRLTR) ; get drive letter
SUB 'A' ; ..and convert to number
LD C,A ; copy to reg. C (for Bios call)
LD E,0
JP (HL) ; "call" Bios fn #9 and let return from there
; (SELDSK returns DPH addr in HL)
; print disk size to CON: (capacity of a drive in kB)
; output as decimal with provision for 3-byte values - see ZXD21.Z80 PRBIG
; in: 24-bit value to print in A,H,L
PDSKSZ: PUSH DE ; save regs
PUSH BC
EX AF,AF' ; swap AF
PUSH AF ; save it
EX AF,AF' ; ..and swap back
LD B,0
LD C,-1 ; set initial result
LD DE,86A0H ; 100,000 = 0x0186A0, set lower 2 bytes
OR A ; clear C-Flag
PDSKSZ0: INC C ; accumulate count
SBC HL,DE ; subtract lower 2 bytes
SBC A,1 ; ..and upper byte
JR NC,PDSKSZ0 ; loop till done
ADD HL,DE ; adjust underflow
ADC A,1
CALL PHLD1
LD DE,10000 ; print 10000's
CALL PHLD
LD DE,1000 ; print 1000's
CALL PHLD
LD DE,100 ; print 100's
CALL PHLD
LD DE,10 ; print 10's
CALL PHLD
LD A,L ; print 1's
CALL PHLD2
POP AF ; restore regs
EX AF,AF' ; swap
POP BC ; ..and also restore other regs
POP DE
RET
; print content of HL to CON: as decimal
; divide HL by DE, convert remainder to ascii digit and print it
; (similar to SYSLIB's PHLFDC/PHDC1 - see ZXD21.Z80 DECDSP)
; in: HL= value, DE= divisor
PHLD: LD C,-1 ; set initial count
OR A ; clear C-Flag
PHLD0: INC C ; accumulate count
SBC HL,DE ; divide by subtraction
SBC A,0
JR NC,PHLD0 ; ..and loop while more to go
ADD HL,DE ; compensate underflow
ADC A,0
PHLD1: EX AF,AF' ; swap to retain flags
LD A,C ; get result (quotient)
OR A ; is it zero ?
JR NZ,PHLD2 ; ..if not, skip over
OR B ; get prior digit print flag
JR Z,PHLD3 ; ..if anything printed yet, jump
XOR A ; else, print a zero
PHLD2: ADD A,'0' ; convert to ascii
LD B,A ; remember for next loop
CALL COUT ; ..and display it
PHLD3: EX AF,AF' ; swap regs back
RET
; intercept COUT to re-route SYSLIB calls to to BOUT
; --> declare COUT as PUBLIC, and do _not_ import from SYSLIB
COUT: JP BOUT
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
; SYSLIB - 0x0530
; end addr 0x064d (begin DSEG)
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
;::::: RAM STORAGE
DSEG
KBTRK: DEFW 0 ; kByte/Trk (Sect/Trk divided by 8)
BSH3: DEFB 0 ; BSH -3 (Block Shift Factor -3)
; disk capacity as 24-bit value
DCAPH: DEFB 0 ; high byte
DCAPML: DEFW 0 ; middle and low byte
DRLTR: DEFB 0 ; drive letter (entered by user)
DPHADR: DEFW 0 ; addr DPH (not used)
DPBADR: DEFW 0 ; addr DPB (not used)
DEFS 30H ; room for stack
STACK: DEFW 0 ; stack storage location
END
;************************************************************************
; Remarks jxl:
; SHOWHD.COM, included in available B/P Bios package(s), was dis-
; assembled and extensively commented. Labels are up to seven chars long
; to comply with M-REL standards. However, it is recommended to use SLR
; tools that support labels up to sixteen chars.
; In its current state, the compiled/linked file matches exactly the
; original SHOWHD.COM, i.e. no changes to the source were made.
;
; The program is not very complex. However, one thing might be worth
; to be pointed out: SYSLIB's routine COUT is replaced with an own
; implementation. While it is just a re-routing to another SYSLIB routine,
; it shows how simply this can be achieved. Bear in mind that _all_
; SYSLIB routines calling COUT would now call the local implementation
; instead. With this technique existing routines can be modified without
; rewriting them entirely.
;************************************************************************

View File

@@ -0,0 +1,546 @@
TITLE "B/P Bios RAM size display"
;************************************************************************
;* S I Z E R A M *
;* Determine size and location of (banked) Memory *
;* by Harold F. Bower and Cameron W. Cotrill *
;*----------------------------------------------------------------------*
;* Disassembly: jxl Dec 2024 *
;* public release 1.0 Apr 2025 *
;* see remarks at the end *
;*----------------------------------------------------------------------*
;* LINK with Version 4 libraries: VLIB, Z3LIB, SYSLIB *
;* *
;* A>Z80ASM SIZERAM/RS *
;* A>SLRNK SIZERAM/N,/A:100,/D:0750,SIZERAM,VLIBS/S,Z3LIBS/S,SYSLIBS/S,/E *
;************************************************************************
VER EQU 12
REV EQU ' '
DATE MACRO
DEFB '30 Aug 01'
ENDM
BEL EQU 07H ; Bell character
LF EQU 0AH ; Line Feed character
CR EQU 0DH ; Carriage Return character
CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP)
CPMBDOS EQU 5 ; CP/M BDOS entry point (JP)
CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype)
; From Z3LIB Get..
EXTRN GETNAME, PRTNAME, Z3INIT, WHRENV
; From SYSLIB Get..
EXTRN EPRINT, CRLF, PAFDC, PHLFDC, COUT, CODEND
;::::: PROGRAM START
ORG 100H
CSEG
SIZERAM: JP START ; bypass header
DEFB 'Z3ENV' ; this is a ZCPR3 utility
DEFB 1 ; show external environment
ENVADR: DEFW 0 ; addr of Z3 environment
DEFW SIZERAM ; type 4 filler
DEFB 'SIZERAM ',0 ; configuration name
START: LD (STACK),SP
LD SP,STACK
CALL EPRINT
DEFB 'B/P Banked RAM Sizing Utility V',VER/10+'0','.'
DEFB VER MOD 10 + '0',REV,' '
DATE
DEFB CR,LF
DEFB 0
CALL CHKZ3E ; check if Z3 Environment is valid
CALL GETNAME ; get actual program name
CALL CHKHELP ; check cmdline for help request
CALL CHKSYS ; check if running under B/P Bios
CALL M$BVER ; display version # msg
LD HL,(BPCNFG) ; get addr of config area
INC HL ; move ptr fwd
INC HL
LD A,(HL) ; get OPTF1 (option flag at CONFIG+2)
AND 00000001b ; mask bit 0
LD (BPBNKD),A ; ..and store it
JP NZ,BNKDSYS ; if banked, jump to continue
;::::: NON-BANKED SYSTEM
NBNKSYS: INC HL ; move ptr to TPABNK in config area
INC HL
CALL EPRINT
DEFB CR,LF,LF,'Non-Banked System using TPA Banks = '
DEFB 0
LD A,(HL) ; get value
PUSH AF
CALL PAFDC ; ..and display
LD A,'/'
CALL COUT
POP AF ; restore value
INC A ; increase it
CALL PAFDC ; ..and display
CALL CRLF
JP EXIT
;::::: BANKED SYSTEM
BNKDSYS: INC HL ; move ptr to UABNK in config area
LD DE,UABNK ; ..and make local copies
LD BC,5 ; (5 bytes, UABNK..MAXBNK)
LDIR
CALL CODEND ; get first available page after code end
LD (WSPCBEG),HL ; and store it
EX DE,HL ; swap regs
; memory read/write tests for all ram banks at addr 0x0000
; building a map in WSPC area: b1= zero if no bank found, b2= initially read byte
; test #1: 0x00/0xFF byte - iterate over banks in forward order
LD HL,0 ; set addr 0x0000
LD C,0 ; start with bank #0 (TPA)
MEMRW: CALL GETFRB ; get byte
LD B,A ; store in B
CPL ; invert (complement) byte
CALL SETINB ; write it back
CALL GETFRB ; read again
CPL ; ..and invert
XOR B ; xor'd with initially read byte
JR NZ,MEMRW0 ; ..if no match, skip over
LD A,B ; get initially read byte
CALL SETINB ; write it
CALL GETFRB ; and read again
SUB B ; subtract initially read byte
JR NZ,MEMRW0 ; ..if not zero, skip over
; injected opcode 0xF6 (OR n) to skip following XOR A
DEFB 0F6h ; = OR 0AFH (write non-zero)
MEMRW0: XOR A ; nullify A
LD (DE),A ; store in WSPC area
INC DE ; move ptr fwd
LD A,B ; get initially read byte
LD (DE),A ; store it, too
INC DE ; move ptr fwd
INC C ; bank # +1
JR NZ,MEMRW ; ..loop till all possible (256 / 0x100) banks tested
; test #2: write no. in each bank (iterate backward), then read and compare (forward)
DEC C ; correct bank # (loop was 1 ahead)
MEMWRB: DEC DE ; move ptr back
DEC DE
LD A,(DE) ; get byte
OR A ; check if bank exists
JR Z,MEMWRB0 ; ..if not, skip over
LD A,C ; else, get bank #
CALL SETINB ; and write in bank
MEMWRB0: LD A,C ; get bank #
SUB 1 ; -1
LD C,A ; set bank #
JR NC,MEMWRB ; ..if not below zero, loop
INC C ; correct bank #
MEMRDB: LD A,(DE) ; get byte from WSPC area
OR A ; check if bank exists
JR Z,MEMRDB0 ; ..if not, skip over
CALL GETFRB ; read byte from bank
CP C ; compare to bank #
JR Z,MEMRDB0 ; ..if match, skip over
XOR A ; else, set <NUL> as indicator
LD (DE),A ; that bank doesn't exist
MEMRDB0: INC DE ; move ptr fwd
INC DE
INC C ; bank # +1
JR NZ,MEMRDB ; ..loop till all possible (256 / 0x100) banks tested
; restore bytes initially read in all banks
LD DE,(WSPCBEG) ; set ptr to start of WSPC addr
MEMRST: LD A,(DE) ; get byte
OR A ; check bank exists
JR Z,MEMRST0 ; ..if not, skip over
INC DE ; move ptr fwd
LD A,(DE) ; get initially read byte
CALL SETINB ; ..and restore it
INC DE ; ptr fwd
JR MEMRST1 ; skip over
MEMRST0: INC DE ; ptr fwd
INC DE
MEMRST1: INC C ; bank # +1
JR NZ,MEMRST ; loop till done
; ..then fall through to display collected data
; display information for Banked System
; detect ranges of continuous ram banks
;
; HL= ptr in WSPC area
; C= counter (up) bank #, B= counter (down) for outer loop
; D= bank # begin of range, E= bank # end of range
LD BC,0
LD HL,(WSPCBEG) ; set ptr to start of WSPC addr
BRANGLP: LD A,(HL) ; get byte
OR A ; check bank exists
JR NZ,BRANGE ; ..if so, skip over
INC HL ; else, use a shorter loop
INC HL ; ..move ptr fwd
INC C ; ..and bank #
JR NZ,BRANGLP ; loop until max. reached (256 / 0x100)
JR PCNFIG ; else, display Bios config report
BRANGE: LD D,C ; store start of range (bank # in D)
BRANG0: INC HL ; ptr fwd
INC HL
INC C ; bank # +1
JR NZ,BRANG1 ; ..if not max., skip over
DEC B
JR PBRANG ; else, display bank ranges
BRANG1: LD A,(HL) ; get byte
OR A ; check bank exists
JR NZ,BRANG0 ; ..if so, loop
; else, fall through
; display collected information
PBRANG: LD E,C ; get current bank # in E
DEC E ; loop is ahead, so -1
CALL EPRINT
DEFB CR,LF,'RAM Banks '
DEFB 0
LD A,D ; get begin of range
CALL PAFDC ; ..and display it
CALL EPRINT
DEFB ' - '
DEFB 0
LD A,E ; get end of range
CALL PAFDC ; ..and display it
CALL EPRINT
DEFB ' ('
DEFB 0
LD A,E ; get end of range
INC A ; adjust for correct calc
SUB D ; calc difference of begin/end
PUSH HL
LD L,A ; get value in L
LD H,0 ; ..and multiply for display
ADD HL,HL ; *2
ADD HL,HL ; *4
ADD HL,HL ; *8
ADD HL,HL ; *16
ADD HL,HL ; *32 (fixed bank size of 32k assumed)
CALL PHLFDC ; ..and display
POP HL
CALL EPRINT
DEFB 'k Bytes)'
DEFB 0
LD A,B ; check if more to go
OR A
JR Z,BRANGLP ; loop till done
; display information as stored in B/P Bios config area
PCNFIG: CALL EPRINT
DEFB CR,LF,LF,'Bios Reports:',CR,LF
DEFB ' TPA Banks = '
DEFB 0
LD A,(TPABNK) ; get TPA bank #
PUSH AF ; save regs
CALL PAFDC ; and display it
LD A,'/'
CALL COUT
POP AF ; restore value
INC A ; +1 (TPA bank is build by 2 consecutive banks)
; fixed size of 32k per bank is assumed
CALL PAFDC ; and display it
CALL EPRINT
DEFB CR,LF,' System Bank = '
DEFB 0
LD A,(SYSBNK) ; get SYSTEM bank #
CALL PAFDC ; and display it
CALL EPRINT
DEFB CR,LF,' User Bank = '
DEFB 0
LD A,(UABNK) ; get # of USER banks
OR A
JR NZ,PCNFIG0 ; ..if not zero, skip over
CALL EPRINT
DEFB '(None)'
DEFB 0
JR PCNFIG1
PCNFIG0: CALL PAFDC ; display # of USER banks
PCNFIG1: CALL EPRINT
DEFB CR,LF,' RAM Disk Start = '
DEFB 0
LD A,(RAMBNK) ; get # of begin RAM Disk
CALL PAFDC
CALL EPRINT
DEFB CR,LF,' Last Used Bank = '
DEFB 0
LD A,(MAXBNK) ; get max. available bank #
CALL PAFDC
CALL EPRINT
DEFB CR,LF,LF,' -- Scan Complete.',CR,LF
DEFB 0
JP EXIT
;::::: SUPPORT FUNCTIONS
; get first token from command line (in FCB #1)
; and check if help was requested
CHKHELP: LD HL,CPMFCB+1
LD A,(HL) ; get byte
CP '/' ; is this a help request ?
RET NZ ; ..if not, return
INC HL ; else, move ptr fwd
LD A,(HL) ; and get next byte
CP '/' ; is it also '/' ?
RET NZ ; ..if not, return
; else, fall through and display help
;::::: HELP SCREEN
HELP: CALL EPRINT
DEFB CR,LF,' '
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' Determines location and Size of Banked Memory.',CR,LF
DEFB ' (Only TPA Banks printed if Non-Banked)',CR,LF,LF
DEFB ' Syntax:',CR,LF
DEFB ' '
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' - Print 32k RAM banks present and B/P Allocations',CR,LF
DEFB ' '
DEFB 0
CALL PPRGNAM
CALL EPRINT
DEFB ' // - display this screen',CR,LF
DEFB 0 ; fall through and exit
;::::: EXIT PROGRAM
EXIT: CALL CRLF
LD SP,(STACK) ; restore stack pointer
RET ; ..and return to system
;::::: SUPPORT FUNCTIONS
; check if running under ZCPR3 and status of wheel byte
; terminate program if not succesful
CHKZ3E: LD HL,(CPMBDOS+1)
CALL WHRENV ; find Z3 Environment Descriptor
LD (ENVADR),HL ; store ENV ptr
LD A,H ; check if invalid (= zero)
OR L
JP Z,E$BPBIO ; ..if so, jump error and terminate
CALL Z3INIT ; else, init for Z3LIB routines
LD A,41 ; offset to addr of wheel byte (Z3WHL)
CALL ADDHLA ; adjust ptr
LD E,(HL) ; get addr in DE
INC HL
LD D,(HL)
EX DE,HL ; swap regs
LD A,(HL) ; get value of wheel byte
AND A ; check if zero
RET NZ ; ..if not (wheel on), return
CALL EPRINT ; else, display message and exit
DEFB BEL,CR,LF,'Must be wheel to Execute !',CR,LF
DEFB 0
JR EXIT
; check if running under B/P Bios
; if not, program is terminated
CHKSYS: LD HL,(CPMBIOS+1) ; get warm boot addr (BIOS fn #1)
LD L,30*3 ; adjust ptr to fn #30
LD A,(HL) ; check byte at ptr location
CP 0C3H ; is it opcode 0xC3 (JP) ?
JR NZ,E$BPBIO ; ..if not, jump error and terminate
CALL JUMPHL ; else, "call" B/P Bios fn #30 (RETBIO)
LD (BPVERS),A ; store version of B/P Bios
LD (BPADDR),BC ; " base addr
LD (BPCNFG),DE ; " config area addr
LD HL,-6 ; move ptr 6 bytes backward
ADD HL,DE ; (signature string)
LD A,(HL) ; get byte
CP 'B' ; is it 'B' ?
JR NZ,E$BPBIO ; ..if not, jump error and exit
INC HL ; ptr fwd
LD A,(HL) ; get byte
CP '/' ; is it '/' ?
JR NZ,E$BPBIO ; ..if not, jump error and exit
INC HL ; ptr fwd
LD A,(HL) ; get byte
CP 'P' ; is it 'P' ?
RET Z ; ..if so, return
; else, fall through (error and exit)
; msg aborting
E$BPBIO: CALL EPRINT
DEFB CR,LF,BEL,'Not B/P Bios, aborting...!',CR,LF
DEFB 0
RST 0
; print program name on CON: device
; (either the actual name, or fallback to default)
; only used by HELP
PPRGNAM: LD A,(ENVADR+1) ; get high byte of ENVPTR
OR A ; check if valid (<> zero)
JP NZ,PRTNAME ; ..if so, display actual name
; ..and let return from there
CALL EPRINT ; else, display default
DEFB 'SIZERAM'
DEFB 0
RET
; msg B/P Bios Vers x.x
M$BVER: CALL EPRINT
DEFB ' (B/P Bios Vers '
DEFB 0
LD A,(BPVERS) ; get version #
RRCA ; reverse nybbles in A
RRCA
RRCA
RRCA
AND 00001111b ; mask lower nybble
ADD A,'0' ; make it ascii
CALL COUT ; ..and display
LD A,'.'
CALL COUT
LD A,(BPVERS) ; get version #
AND 00001111b ; mask lower nybble
ADD A,'0' ; make it ascii
CALL COUT ; ..and display
CALL EPRINT
DEFB ')',CR,LF
DEFB 0
RET
; add A to HL (result in HL)
ADDHLA: ADD A,L ; add L
LD L,A ; store result in L
RET NC ; ..if no overflow, return
INC H ; else, increment H
RET
; the following routines rearrange Top of Stack by injecting an
; intermediate return addr, and putting the Bios fn call on top
; so that HL regs are preserved
; order of steps:
; [1] HL (= addr) is pushed onto stack
; [2] intermediate return addr is swapped to Top of Stack
; [3] HL (= addr) is pushed onto stack again
; [4] Bios fn JP addr is swapped to Top of Stack
; [5] Bios is "called" through RET, and returns to intermediate addr
; get byte from ram bank - in the form LD A,(HL)
; in: C= bank #, HL= addr
; out: A= byte
GETFRB: PUSH BC
PUSH HL ; save addr
LD HL,GETFRB0 ; load return addr
EX (SP),HL ; put it on stack
PUSH HL ; save HL again (previous top of stack)
LD HL,(BPADDR) ; get B/P Bios base addr
LD L,35*3 ; adjust ptr to fn #35 (FRGETB)
EX (SP),HL ; put addr on stack
RET ; ..and "call" Bios fn through stack
GETFRB0: POP BC ; restore regs
RET ; ..and finally return
; set byte in ram bank - in the form LD (HL),A
; in: C= bank #, HL= addr, A= byte to set
SETINB: PUSH BC
PUSH HL ; save addr
LD HL,GETFRB0 ; load return addr
EX (SP),HL ; put it on stack
PUSH HL ; save HL again (previous top of stack)
LD HL,(BPADDR) ; get B/P Bios base addr
LD L,37*3 ; adjust ptr to fn #37 (FRPUTB)
EX (SP),HL ; put addr on stack
RET ; ..and "call" Bios fn through stack
; "called" as a pseudo-routine that returns to caller
; in: HL= target addr
JUMPHL: JP (HL) ; jump to addr in HL regs
;::::: LOCAL DATA (not in DSEG)
WSPCBEG: DEFW 0 ; addr begin of workspace area
; (first available page, returned by CODEND)
; data retrieved from running system
BPVERS: DEFB 0 ; B/P Bios version
BPADDR: DEFW 0 ; B/P Bios base addr
BPCNFG: DEFW 0 ; addr of Config Area
BPBNKD: DEFB 0 ; indicator banked system (bit 0 of OPTF1) --> not used
; local copies of RAM bank configuration
UABNK: DEFB 0 ; beginning of User Bank(s)
TPABNK: DEFB 0 ; TPA Bank
SYSBNK: DEFB 0 ; beginning of System Bank(s)
RAMBNK: DEFB 0 ; base bank # for Ram Disk
MAXBNK: DEFB 0 ; highest permissible Bank #
DEFS 30H ; room for stack
STACK: DEFW 0 ; stack storage location
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
; Z3LIB - 0x05ae
; SYSLIB - 0x065c
; end addr 0x0750 (begin DSEG)
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
;::::: RAM STORAGE
DSEG
END
;************************************************************************
; Remarks jxl:
; SIZERAM.COM, included in available B/P Bios package(s), was dis-
; assembled and extensively commented. Labels are up to seven chars long
; to comply with M-REL standards. However, it is recommended to use SLR
; tools that support labels up to sixteen chars.
; In its current state, the compiled/linked file matches exactly the
; original INITRAM.COM, i.e. no changes to the source were made.
;
; The program uses an interesting technique to read and write data in
; alternative ram banks utilizing B/P Bios functions no. 35 FRGETB and
; no. 37 FRPUTB. Top of Stack is manipulated to keep registers intact
; and "call" functions through a RET statement (instead of CALL.)
; Another specialty which is worth mentioning: Routine MEMRW (memory
; read/write) contains an "injected" opcode to alter the behaviour at
; runtime. Otherwise a more complex logic and/or additional routine
; would have been necessary.
; Storage of local data is in CSEG (code segment), not DSEG. There
; seems to be no particular reason for this. So, it can be assumed that
; this just happened by mistake.
;************************************************************************

File diff suppressed because it is too large Load Diff

1247
Source/BPBIOS/bpart.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,7 @@ pushd QPM && call Build || exit /b & popd
pushd ZCPR && call Build || exit /b & popd
pushd ZCPR-DJ && call Build || exit /b & popd
pushd ZSDOS && call Build || exit /b & popd
pushd ZSDOS2 && call Build || exit /b & popd
pushd CPM3 && call Build || exit /b & popd
pushd ZPM3 && call Build || exit /b & popd
pushd CPNET && call Build || exit /b & popd

View File

@@ -8,6 +8,7 @@ pushd QPM && call Clean.cmd & popd
pushd ZCPR && call Clean.cmd & popd
pushd ZCPR-DJ && call Clean.cmd & popd
pushd ZSDOS && call Clean.cmd & popd
pushd ZSDOS2 && call Clean.cmd & popd
pushd CBIOS && call Clean.cmd & popd
pushd CPM3 && call Clean.cmd & popd
pushd ZPM3 && call Clean.cmd & popd

View File

@@ -328,6 +328,9 @@ please let me know if I missed you!
contributed a driver for the Xosera FPGA-based video
controller.
* Jörg Linder has contributed disassembled and nicely commented
source for ZSDOS2 and the BPBIOS utilities.
`\clearpage`{=latex}
## Related Projects

View File

@@ -8,19 +8,14 @@ set PATH=%TOOLS%\lzsa;%TOOLS%\fonttool;%PATH%
echo.
echo Preparing compressed font files...
lzsa -f2 -r font8x8u.bin font8x8c.bin || exit /b
lzsa -f2 -r font8x11u.bin font8x11c.bin || exit /b
lzsa -f2 -r font8x16u.bin font8x16c.bin || exit /b
lzsa -f2 -r fontcgau.bin fontcgac.bin || exit /b
lzsa -f2 -r fontvgarcu.bin fontvgarcc.bin || exit /b
for %%f in (font6x8 font8x8 font8x11 font8x16 fontcga fontvgarc) do call :genfont %%f
fonttool font8x8u.bin > font8x8u.asm || exit /b
fonttool font8x11u.bin > font8x11u.asm || exit /b
fonttool font8x16u.bin > font8x16u.asm || exit /b
fonttool font8x8c.bin > font8x8c.asm || exit /b
fonttool font8x11c.bin > font8x11c.asm || exit /b
fonttool font8x16c.bin > font8x16c.asm || exit /b
fonttool fontcgau.bin > fontcgau.asm || exit /b
fonttool fontcgac.bin > fontcgac.asm || exit /b
fonttool fontvgarcu.bin > fontvgarcu.asm || exit /b
fonttool fontvgarcc.bin > fontvgarcc.asm || exit /b
goto :eof
:genfont
echo Processing font %1...
lzsa -f2 -r %1u.bin %1c.bin || exit /b
fonttool %1u.bin >%1u.asm || exit /b
fonttool %1c.bin >%1c.asm || exit /b
goto :eof

View File

@@ -1,8 +1,8 @@
OBJECTS = \
font8x8u.asm font8x11u.asm font8x16u.asm fontcgau.asm fontvgarcu.asm \
font8x8c.asm font8x11c.asm font8x16c.asm fontcgac.asm fontvgarcc.asm
font6x8u.asm font8x8u.asm font8x11u.asm font8x16u.asm fontcgau.asm fontvgarcu.asm \
font6x8c.asm font8x8c.asm font8x11c.asm font8x16c.asm fontcgac.asm fontvgarcc.asm
OTHERS = font8x8c.bin font8x11c.bin font8x16c.bin fontcgac.bin fontvgarcc.bin
OTHERS = font6x8c.bin font8x8c.bin font8x11c.bin font8x16c.bin fontcgac.bin fontvgarcc.bin
TOOLS = ../../Tools
@@ -14,6 +14,9 @@ include $(TOOLS)/Makefile.inc
%.rel: %.asm
%.bin: %.asm
font6x8c.bin: font6x8u.bin
$(BINDIR)/lzsa -f2 -r $< $@
font8x8c.bin: font8x8u.bin
$(BINDIR)/lzsa -f2 -r $< $@

BIN
Source/Fonts/font6x8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
Source/Fonts/font6x8u.bin Normal file

Binary file not shown.

View File

@@ -17,16 +17,18 @@ There are multiple fonts associated with ROMWBW supported hardware:
MBC-VDP tms.asm 9938/9958
RCBUS-VRC vrc.asm PLD
RCBUS-TMS tms.asm 99x8
XOSERA xosera.asm ?
Name Glyph Cell Size Comp Board & Display Mode
------------------------------------------------------------------------------------------------
font8x8 6x8 8x8 2048 1034 ECB-SCG, ECB-VGA3 (80x60), MBC-VDP
font6x8 6x8 8x8 2048 1094 ECB-SCG, MBC-VDP
font8x8 6x8 8x8 2048 1034 ECB-VGA3 (80x60)
font8x11 8x11 8x11 2816 1252 ECB-VGA3 (80x43)
font8x16 8x14 8x16 4096 1466 ECB-CVDU (EGA), ECB-VGA3 (80x24, 80x25, 80x30), MBC-VDC (EGA)
fontcga 8x8 8x16 4096 1280 ECB-CVDU (CGA), MBC-VDC (CGA)
fontvrc 8x8 8x8 1024 650 VGARC
----- -----
14080 5682
16128 6776
Notes:
@@ -36,7 +38,7 @@ Notes:
but the font definition must still be 8x16. The CGA font is used for this.
For inclusion in HBIOS the .bin format files must be converted to assembler .asm format.
This is acheived using the fonttool utility and is completed automatically as part of the build process.
This is achieved using the fonttool utility and is completed automatically as part of the build process.
i.e. fonts files are converted to .asm format and then copied to the HBIOS directory.
To replace a font, simply copy it to the Fonts directory using the same naming convention above,

View File

@@ -98,6 +98,8 @@ call :asm game || exit /b
call :asm usrrom || exit /b
call :asm updater || exit /b
:: call :asm fonts || exit /b
:: Sysconf builds as both BIN and COM files
tasm -t%CPUType% -g3 -fFF -dROMWBW sysconf.asm sysconf.bin sysconf_bin.lst || exit /b
tasm -t%CPUType% -g3 -fFF -dCPM sysconf.asm sysconf.com sysconf_com.lst || exit /b

View File

@@ -1,6 +1,6 @@
MOREDIFF = game.bin hbios_rom.bin nascom.bin usrrom.bin \
dbgmon.bin hbios_app.bin imgpad2.bin rom2.bin rom3.bin romldr.bin \
dbgmon.bin hbios_app.bin rom2.bin rom3.bin romldr.bin \
eastaegg.bin hbios_img.bin rom1.bin game.bin updater.bin usrrom.bin
DEST = ../../Binary
@@ -24,7 +24,7 @@ endif
include $(TOOLS)/Makefile.inc
FONTS := font8x11c.asm font8x11u.asm font8x16c.asm font8x16u.asm font8x8c.asm font8x8u.asm \
fontcgac.asm fontcgau.asm fontvgarcc.asm fontvgarcu.asm
font6x8c.asm font6x8u.asm fontcgac.asm fontcgau.asm fontvgarcc.asm fontvgarcu.asm
ifeq ($(CPUFAM),2)
TASM=$(BINDIR)/uz80as -t hd64180
@@ -32,7 +32,7 @@ else ifeq ($(CPUFAM),3)
TASM=$(BINDIR)/uz80as -t z280
endif
DEPS=prereq dbgmon.bin romldr.bin nascom.bin tastybasic.bin game.bin eastaegg.bin updater.bin sysconf.bin sysconf.com usrrom.bin imgpad2.bin
DEPS=prereq dbgmon.bin romldr.bin nascom.bin tastybasic.bin game.bin eastaegg.bin updater.bin sysconf.bin sysconf.com usrrom.bin
ifeq ($(ROM_PLATFORM),UNA)
ROMDEPS=romldr.bin dbgmon.bin

View File

@@ -1927,7 +1927,7 @@ ROMRESUME:
;
; LAUNCH S100 MONITOR FROM ROM BANK 3
LD A,BID_IMG2 ; S100 MONITOR BANK
LD IX,0 ; EXECUTION RESUMES HERE
LD IX,HWMON_IMGLOC ; EXECUTION RESUMES HERE
CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN
HALT ; WE SHOULD NOT COME BACK HERE!
;
@@ -9506,12 +9506,23 @@ ORG_FONTS .EQU $
;
MEMECHO "FONTS"
;
#IFDEF USEFONT6X8
FONT6X8:
;
; FOR NOW, WE NEVER COMPRESS THE 6X8 FONT. SEE TMS DRIVER.
;
#IF USELZSA2 & FALSE
#INCLUDE "font6x8c.asm"
#ELSE
#INCLUDE "font6x8u.asm"
#ENDIF
MEMECHO " 6X8"
#ENDIF
;
#IFDEF USEFONT8X8
FONT8X8:
;
; FOR NOW, WE NEVER COMPRESS THE 8X8 FONT. SEE TMS DRIVER.
;
#IF USELZSA2 & FALSE
#IF USELZSA2
#INCLUDE "font8x8c.asm"
#ELSE
#INCLUDE "font8x8u.asm"

View File

@@ -1,10 +0,0 @@
#INCLUDE "std.asm"
;
SLACK .EQU $8000
.FILL SLACK,00H
;
.ECHO "Padspace space created: "
.ECHO SLACK
.ECHO " bytes.\n"
.END

View File

@@ -185,9 +185,9 @@ HWMON_IMGLOC .EQU BNK_NXTLOC ; LOCATION OF BINARY LOAD IMAGE IN BANK
BNK_NXTLOC .SET HWMON_IMGLOC + HWMON_SIZ ; IMG LOC OF NEXT COMPONENT
;
FONTS_BNK .EQU BNK_CUR
;;;FONTS_LOC .EQU $E000
FONTS_SIZ .EQU $2000
;;;FONTS_END .EQU FONTS_LOC + FONTS_SIZ
FONTS_LOC .EQU $0000
FONTS_SIZ .EQU $4000
FONTS_END .EQU FONTS_LOC + FONTS_SIZ
FONTS_IMGLOC .EQU BNK_NXTLOC ; LOCATION OF BINARY LOAD IMAGE IN BANK
BNK_NXTLOC .SET FONTS_IMGLOC + FONTS_SIZ ; IMG LOC OF NEXT COMPONENT
;
@@ -206,19 +206,19 @@ BNK3_SLACK .EQU BNKTOP - BNK_NXTLOC ; REMAINING BANK SPACE
.ECHO "BANK3 BID_IMG2 \t" \ .ECHO BNK3_LEN \ .ECHO "\t" \ .ECHO BNK3_SLACK \ .ECHO "\n"
.ECHO "-------------------------------\n"
;
#IF (BNK1_LEN > BNKTOP)
#ENDIF
;
#IF (BNK1_SLACK < 0)
.ECHO "*** ROM BANK 1 IS TOO BIG!!!\n"
!!! ; FORCE AN ASSEMBLY ERROR IF BANK SIZE EXCEEDS SPACE
#ENDIF
#ENDIF
;
#IF (BNK2_LEN > BNKTOP)
#IF (BNK2_SLACK < 0)
.ECHO "*** ROM BANK 2 IS TOO BIG!!!\n"
!!! ; FORCE AN ASSEMBLY ERROR IF BANK SIZE EXCEEDS SPACE
#ENDIF
#ENDIF
;
#IF (BNK3_LEN > BNKTOP)
#IF (BNK3_SLACK < 0)
.ECHO "*** ROM BANK 3 IS TOO BIG!!!\n"
!!! ; FORCE AN ASSEMBLY ERROR IF BANK SIZE EXCEEDS SPACE
#ENDIF
;
#ENDIF

View File

@@ -1554,7 +1554,7 @@ s100mon1:
call ldelay ; wait for UART buf to empty
di ; suspend interrupts
ld a,HWMON_BNK ; S100 monitor bank
ld ix,0 ; execution resumes here
ld ix,HWMON_IMGLOC ; execution resumes here
jp HB_BNKCALL ; do it
;
str_smon .db "S100 Z180 Monitor",0

View File

@@ -432,16 +432,16 @@ CNTLB0_VALUE equ 00H ; For setting final baud rate from
;
jp mon_start
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;To clean up PROM for easy reading
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Db 0,0,0,0
;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;To clean up PROM for easy reading
;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;; DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;; Db 0,0,0,0
; Jump to monitor!!!
;

View File

@@ -549,6 +549,14 @@ V80X43 .EQU 5 ; ECB-VGA3
V80X60 .EQU 6 ; ECB-VGA3
V40X24 .EQU 7 ; EF9345
;
; FONT IDS
;
FONTID_8X8 .EQU 1
FONTID_8X11 .EQU 2
FONTID_8X16 .EQU 3
FONTID_CGA .EQU 4
FONTID_VGARC .EQU 5
;
; KEYBOARD LAYOUTS
;
KBD_US .EQU 0 ; US ENGLISH

View File

@@ -150,8 +150,10 @@ TMS_COLS .EQU 40
DEVECHO "X"
DEVECHO TMS_ROWS
;
#DEFINE USEFONT8X8
#DEFINE TMS_FONT FONT8X8
;;;#DEFINE USEFONT8X8
;;;#DEFINE TMS_FONT FONT8X8
#DEFINE USEFONT6X8
#DEFINE TMS_FONT FONT6X8
;
TERMENABLE .SET TRUE ; INCLUDE TERMINAL PSEUDODEVICE DRIVER
;

View File

@@ -23,6 +23,7 @@ shared:
$(MAKE) --directory ZCPR $(ACTION)
$(MAKE) --directory ZCPR-DJ $(ACTION)
$(MAKE) --directory ZSDOS $(ACTION)
$(MAKE) --directory ZSDOS2 $(ACTION)
$(MAKE) --directory CPM3 $(ACTION)
$(MAKE) --directory ZPM3 $(ACTION)
$(MAKE) --directory CPNET $(ACTION)

12
Source/ZSDOS2/Build.cmd Normal file
View File

@@ -0,0 +1,12 @@
@echo off
setlocal
set TOOLS=../../Tools
set PATH=%TOOLS%\tasm32;%TOOLS%\zxcc;%PATH%
set TASMTABS=%TOOLS%\tasm32
set CPMDIR80=%TOOLS%/cpm/
zxcc Z80ASM -ZSDOS2/6FS || exit /b

6
Source/ZSDOS2/Clean.cmd Normal file
View File

@@ -0,0 +1,6 @@
@echo off
setlocal
if exist *.lst del *.lst
if exist *.rel del *.rel
if exist *.sym del *.sym

5
Source/ZSDOS2/Makefile Normal file
View File

@@ -0,0 +1,5 @@
TOOLS = ../../Tools
OBJECTS = zsdos2.rel
include $(TOOLS)/Makefile.inc

4116
Source/ZSDOS2/zsdos2.z80 Normal file

File diff suppressed because it is too large Load Diff