Preliminary CP/M 3
This commit is contained in:
@@ -26,6 +26,7 @@ Version 2.9.2
|
||||
- WBW: Add support for secondry SPI (SD Card) on SC126
|
||||
- PMS: Add sound support to NASCOM BASIC
|
||||
- WBW: Updated FAT to add MD and FORMAT commands
|
||||
- WBW: Add CP/M 3 (experimental)
|
||||
|
||||
Version 2.9.1
|
||||
-------------
|
||||
|
||||
14
ReadMe.txt
14
ReadMe.txt
@@ -7,7 +7,7 @@
|
||||
***********************************************************************
|
||||
|
||||
Wayne Warthen (wwarthen@gmail.com)
|
||||
Version 2.9.2-pre.17, 2019-10-11
|
||||
Version 2.9.2-pre.18, 2019-10-14
|
||||
https://www.retrobrewcomputers.org/
|
||||
|
||||
RomWBW is a ROM-based implementation of CP/M-80 2.2 and Z-System for
|
||||
@@ -179,6 +179,18 @@ some potentially useful improvements. Please refer to "ZSDOS
|
||||
Manual.pdf" and "ZCPR Manual.pdf" in the Doc directory for more
|
||||
information on Z-System usage.
|
||||
|
||||
CP/M 3
|
||||
------
|
||||
|
||||
CP/M 3 exists in an experimental state. CP/M 3 must be started
|
||||
from a disk drive. In the distribution archive, in the Binary
|
||||
directory, you will find a cpm_hd.img file that can be copied
|
||||
over to a CF or SD Card. Start your system with this card
|
||||
installed and boot to CP/M 2.2 or ZSystem as usual. Switch to
|
||||
the drive containing the CP/M 3 image and use the CPMLDR command
|
||||
to load CP/M. It will ask you for the disk unit number containing
|
||||
the CP/M 3 system files which are on the disk image you created.
|
||||
|
||||
ROM Customization
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -7,4 +7,7 @@ setlocal & cd ZCPR && call Build || exit /b 1 & endlocal
|
||||
setlocal & cd ZCPR-DJ && call Build || exit /b 1 & endlocal
|
||||
setlocal & cd ZSDOS && call Build || exit /b 1 & endlocal
|
||||
setlocal & cd CBIOS && call Build || exit /b 1 & endlocal
|
||||
setlocal & cd CPM3 && call Build || exit /b 1 & endlocal
|
||||
setlocal & cd ZPM3 && call Build || exit /b 1 & endlocal
|
||||
setlocal & cd Forth && call Build || exit /b 1 & endlocal
|
||||
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
#DEFINE RMN 9
|
||||
#DEFINE RUP 2
|
||||
#DEFINE RTP 0
|
||||
#DEFINE BIOSVER "2.9.2-pre.17"
|
||||
#DEFINE BIOSVER "2.9.2-pre.18"
|
||||
|
||||
28
Source/CPM3/@banks.txt
Normal file
28
Source/CPM3/@banks.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
COMMON 8F ??
|
||||
CPMSYS 8E 00
|
||||
HBIOS 8D ??
|
||||
TPA 8C 01
|
||||
BUFS 8B 02
|
||||
|
||||
8D:7000 -> 8E:0300
|
||||
|
||||
|
||||
00 -> 8E
|
||||
01 -> 8C
|
||||
02 -> 8B
|
||||
03 -> 8A
|
||||
...
|
||||
|
||||
if bnk = 0, then hbbnk = 8EH (BID_USR)
|
||||
else hbbnk = 8DH (BID_BIOS) - bnk
|
||||
|
||||
or a
|
||||
jr z,bank0
|
||||
neg ; 2 -> -2
|
||||
add 8DH ; 8D - 2 = 8B
|
||||
jp HBX_SETBNK
|
||||
bank0:
|
||||
ld a,(8EH)
|
||||
jp HBX_SETBNK
|
||||
ret
|
||||
|
||||
99
Source/CPM3/Build.cmd
Normal file
99
Source/CPM3/Build.cmd
Normal file
@@ -0,0 +1,99 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
set TOOLS=../../Tools
|
||||
|
||||
set PATH=%TOOLS%\zx;%TOOLS%\cpmtools;%PATH%
|
||||
|
||||
set ZXBINDIR=%TOOLS%/cpm/bin/
|
||||
set ZXLIBDIR=%TOOLS%/cpm/lib/
|
||||
set ZXINCDIR=%TOOLS%/cpm/include/
|
||||
|
||||
rem cmd
|
||||
|
||||
rem CPM Loader
|
||||
echo.
|
||||
echo.
|
||||
echo *** CPM Loader ***
|
||||
echo.
|
||||
zx RMAC -CPMLDR
|
||||
zx Z80ASM -BIOSLDR/MF
|
||||
zx LINK -CPMLDR[L100]=CPMLDR,BIOSLDR
|
||||
rem pause
|
||||
|
||||
rem Resident CPM3
|
||||
echo.
|
||||
echo.
|
||||
echo *** Resident BIOS ***
|
||||
echo.
|
||||
copy optres.lib options.lib
|
||||
copy genres.dat gencpm.dat
|
||||
zx RMAC -BIOSKRNL
|
||||
zx RMAC -SCB
|
||||
zx Z80ASM -BOOT/MF
|
||||
zx Z80ASM -CHARIO/MF
|
||||
zx Z80ASM -MOVE/MF
|
||||
zx Z80ASM -DRVTBL/MF
|
||||
zx Z80ASM -DISKIO/MF
|
||||
zx LINK -BIOS3[OS]=BIOSKRNL,SCB,BOOT,CHARIO,MOVE,DRVTBL,DISKIO
|
||||
zx GENCPM -AUTO -DISPLAY
|
||||
copy cpm3.sys cpm3res.sys
|
||||
rem pause
|
||||
|
||||
rem Banked CPM3
|
||||
echo.
|
||||
echo.
|
||||
echo *** Banked BIOS ***
|
||||
echo.
|
||||
copy optbnk.lib options.lib
|
||||
copy genbnk.dat gencpm.dat
|
||||
zx RMAC -BIOSKRNL
|
||||
zx RMAC -SCB
|
||||
zx Z80ASM -BOOT/MF
|
||||
zx Z80ASM -CHARIO/MF
|
||||
zx Z80ASM -MOVE/MF
|
||||
zx Z80ASM -DRVTBL/MF
|
||||
zx Z80ASM -DISKIO/MF
|
||||
zx LINK -BNKBIOS3[B]=BIOSKRNL,SCB,BOOT,CHARIO,MOVE,DRVTBL,DISKIO
|
||||
zx GENCPM -AUTO -DISPLAY
|
||||
copy cpm3.sys cpm3bnk.sys
|
||||
rem pause
|
||||
|
||||
rem *** Resident ***
|
||||
rem copy cpm3res.sys cpm3.sys
|
||||
rem copy genres.dat getcpm.dat
|
||||
|
||||
rem *** Banked ***
|
||||
copy cpm3bnk.sys cpm3.sys
|
||||
copy genbnk.dat gencpm.dat
|
||||
|
||||
rem Update cpm_hd.img
|
||||
echo.
|
||||
echo.
|
||||
echo *** Update Disk Image ***
|
||||
echo.
|
||||
for %%f in (
|
||||
cpmldr.com
|
||||
ccp.com
|
||||
gencpm.com
|
||||
genres.dat
|
||||
genbnk.dat
|
||||
bios3.spr
|
||||
bnkbios3.spr
|
||||
bdos3.spr
|
||||
bnkbdos3.spr
|
||||
resbdos3.spr
|
||||
cpm3res.sys
|
||||
cpm3bnk.sys
|
||||
gencpm.dat
|
||||
cpm3.sys
|
||||
readme.1st
|
||||
cpm3fix.pat
|
||||
) do call :upd_img %%f
|
||||
goto :eof
|
||||
|
||||
:upd_img
|
||||
echo %1...
|
||||
cpmrm.exe -f wbw_hd0 ../../Binary/hd_cpm3.img 0:%1
|
||||
cpmcp.exe -f wbw_hd0 ../../Binary/hd_cpm3.img %1 0:%1
|
||||
goto :eof
|
||||
13
Source/CPM3/Clean.cmd
Normal file
13
Source/CPM3/Clean.cmd
Normal file
@@ -0,0 +1,13 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
if exist bios3.spr del bios3.spr
|
||||
if exist bnkbios3.spr del bnkbios3.spr
|
||||
if exist *.rel del *.rel
|
||||
if exist cpmldr.com del cpmldr.com
|
||||
if exist *.err del *.err
|
||||
if exist *.lst del *.lst
|
||||
if exist *.sym del *.sym
|
||||
if exist *.sys del *.sys
|
||||
if exist gencpm.dat del gencpm.dat
|
||||
if exist options.lib del options.lib
|
||||
BIN
Source/CPM3/bdos3.spr
Normal file
BIN
Source/CPM3/bdos3.spr
Normal file
Binary file not shown.
673
Source/CPM3/bioskrnl.asm
Normal file
673
Source/CPM3/bioskrnl.asm
Normal file
@@ -0,0 +1,673 @@
|
||||
title 'Root module of relocatable BIOS for CP/M 3.0'
|
||||
|
||||
; version 1.0 15 Sept 82
|
||||
|
||||
maclib options
|
||||
|
||||
|
||||
; Copyright (C), 1982
|
||||
; Digital Research, Inc
|
||||
; P.O. Box 579
|
||||
; Pacific Grove, CA 93950
|
||||
|
||||
|
||||
; This is the invariant portion of the modular BIOS and is
|
||||
; distributed as source for informational purposes only.
|
||||
; All desired modifications should be performed by
|
||||
; adding or changing externally defined modules.
|
||||
; This allows producing "standard" I/O modules that
|
||||
; can be combined to support a particular system
|
||||
; configuration.
|
||||
|
||||
cr equ 13
|
||||
lf equ 10
|
||||
bell equ 7
|
||||
ctlQ equ 'Q'-'@'
|
||||
ctlS equ 'S'-'@'
|
||||
|
||||
ccp equ 0100h ; Console Command Processor gets loaded into the TPA
|
||||
|
||||
cseg ; GENCPM puts CSEG stuff in common memory
|
||||
|
||||
|
||||
; variables in system data page
|
||||
|
||||
extrn @covec,@civec,@aovec,@aivec,@lovec ; I/O redirection vectors
|
||||
extrn @mxtpa ; addr of system entry point
|
||||
extrn @bnkbf ; 128 byte scratch buffer
|
||||
|
||||
; initialization
|
||||
|
||||
extrn ?init ; general initialization and signon
|
||||
extrn ?ldccp,?rlccp ; load & reload CCP for BOOT & WBOOT
|
||||
|
||||
; user defined character I/O routines
|
||||
|
||||
extrn ?ci,?co,?cist,?cost ; each take device in <B>
|
||||
extrn ?cinit ; (re)initialize device in <C>
|
||||
extrn @ctbl ; physical character device table
|
||||
|
||||
; disk communication data items
|
||||
|
||||
extrn @dtbl ; table of pointers to XDPHs
|
||||
public @adrv,@rdrv,@trk,@sect ; parameters for disk I/O
|
||||
public @dma,@dbnk,@cnt ; '' '' '' ''
|
||||
|
||||
; memory control
|
||||
|
||||
public @cbnk ; current bank
|
||||
extrn ?xmove,?move ; select move bank, and block move
|
||||
extrn ?bank ; select CPU bank
|
||||
|
||||
; clock support
|
||||
|
||||
extrn ?time ; signal time operation
|
||||
|
||||
; general utility routines
|
||||
|
||||
public ?pmsg,?pdec ; print message, print number from 0 to 65535
|
||||
public ?pderr ; print BIOS disk error message header
|
||||
|
||||
maclib modebaud ; define mode bits
|
||||
|
||||
|
||||
; External names for BIOS entry points
|
||||
|
||||
public ?boot,?wboot,?const,?conin,?cono,?list,?auxo,?auxi
|
||||
public ?home,?sldsk,?sttrk,?stsec,?stdma,?read,?write
|
||||
public ?lists,?sctrn
|
||||
public ?conos,?auxis,?auxos,?dvtbl,?devin,?drtbl
|
||||
public ?mltio,?flush,?mov,?tim,?bnksl,?stbnk,?xmov
|
||||
|
||||
|
||||
; BIOS Jump vector.
|
||||
|
||||
; All BIOS routines are invoked by calling these
|
||||
; entry points.
|
||||
|
||||
?boot: jmp boot ; initial entry on cold start
|
||||
?wboot: jmp wboot ; reentry on program exit, warm start
|
||||
|
||||
?const: jmp const ; return console input status
|
||||
?conin: jmp conin ; return console input character
|
||||
?cono: jmp conout ; send console output character
|
||||
?list: jmp list ; send list output character
|
||||
?auxo: jmp auxout ; send auxilliary output character
|
||||
?auxi: jmp auxin ; return auxilliary input character
|
||||
|
||||
?home: jmp home ; set disks to logical home
|
||||
?sldsk: jmp seldsk ; select disk drive, return disk parameter info
|
||||
?sttrk: jmp settrk ; set disk track
|
||||
?stsec: jmp setsec ; set disk sector
|
||||
?stdma: jmp setdma ; set disk I/O memory address
|
||||
?read: jmp read ; read physical block(s)
|
||||
?write: jmp write ; write physical block(s)
|
||||
|
||||
?lists: jmp listst ; return list device status
|
||||
?sctrn: jmp sectrn ; translate logical to physical sector
|
||||
|
||||
?conos: jmp conost ; return console output status
|
||||
?auxis: jmp auxist ; return aux input status
|
||||
?auxos: jmp auxost ; return aux output status
|
||||
?dvtbl: jmp devtbl ; return address of device def table
|
||||
?devin: jmp ?cinit ; change baud rate of device
|
||||
|
||||
?drtbl: jmp getdrv ; return address of disk drive table
|
||||
?mltio: jmp multio ; set multiple record count for disk I/O
|
||||
?flush: jmp flush ; flush BIOS maintained disk caching
|
||||
|
||||
?mov: jmp ?move ; block move memory to memory
|
||||
?tim: jmp ?time ; Signal Time and Date operation
|
||||
?bnksl: jmp bnksel ; select bank for code execution and default DMA
|
||||
?stbnk: jmp setbnk ; select different bank for disk I/O DMA operations.
|
||||
?xmov: jmp ?xmove ; set source and destination banks for one operation
|
||||
|
||||
jmp 0 ; reserved for future expansion
|
||||
jmp 0 ; reserved for future expansion
|
||||
jmp 0 ; reserved for future expansion
|
||||
|
||||
|
||||
; BOOT
|
||||
; Initial entry point for system startup.
|
||||
|
||||
dseg ; this part can be banked
|
||||
|
||||
boot:
|
||||
lxi sp,boot$stack
|
||||
mvi c,15 ; initialize all 16 character devices
|
||||
c$init$loop:
|
||||
push b ! call ?cinit ! pop b
|
||||
dcr c ! jp c$init$loop
|
||||
|
||||
call ?init ; perform any additional system initialization
|
||||
; and print signon message
|
||||
|
||||
lxi b,16*256+0 ! lxi h,@dtbl ; init all 16 logical disk drives
|
||||
d$init$loop:
|
||||
push b ; save remaining count and abs drive
|
||||
mov e,m ! inx h ! mov d,m ! inx h ; grab @drv entry
|
||||
mov a,e ! ora d ! jz d$init$next ; if null, no drive
|
||||
push h ; save @drv pointer
|
||||
xchg ; XDPH address in <HL>
|
||||
dcx h ! dcx h ! mov a,m ! sta @RDRV ; get relative drive code
|
||||
mov a,c ! sta @ADRV ; get absolute drive code
|
||||
dcx h ; point to init pointer
|
||||
mov d,m ! dcx h ! mov e,m ; get init pointer
|
||||
xchg ! call ipchl ; call init routine
|
||||
pop h ; recover @drv pointer
|
||||
d$init$next:
|
||||
pop b ; recover counter and drive #
|
||||
inr c ! dcr b ! jnz d$init$loop ; and loop for each drive
|
||||
jmp boot$1
|
||||
|
||||
cseg ; following in resident memory
|
||||
|
||||
boot$1:
|
||||
call set$jumps
|
||||
call ?ldccp ; fetch CCP for first time
|
||||
jmp ccp
|
||||
|
||||
|
||||
; WBOOT
|
||||
; Entry for system restarts.
|
||||
|
||||
wboot:
|
||||
lxi sp,boot$stack
|
||||
call set$jumps ; initialize page zero
|
||||
call ?rlccp ; reload CCP
|
||||
jmp ccp ; then reset jmp vectors and exit to ccp
|
||||
|
||||
|
||||
set$jumps:
|
||||
|
||||
if banked
|
||||
mvi a,1 ! call ?bnksl
|
||||
endif
|
||||
|
||||
mvi a,JMP
|
||||
sta 0 ! sta 5 ; set up jumps in page zero
|
||||
lxi h,?wboot ! shld 1 ; BIOS warm start entry
|
||||
lhld @MXTPA ! shld 6 ; BDOS system call entry
|
||||
|
||||
mvi a,JMP ! sta 8 ; set up HBIOS RST 08
|
||||
lxi h,0FFF0H ! shld 9 ; jump vector
|
||||
|
||||
;mvi a,3 ! sta 4 ; default drive is C:
|
||||
|
||||
; xor a
|
||||
; ld hl,40h
|
||||
; ld b,16
|
||||
;set$jumps1:
|
||||
; ld (hl),a
|
||||
; inc hl
|
||||
; djnz set$jumps1
|
||||
|
||||
xra a
|
||||
lxi h,40h
|
||||
mvi b,10h
|
||||
set$jumps1:
|
||||
mov m,a
|
||||
inx h
|
||||
dcr b
|
||||
jnz set$jumps1
|
||||
|
||||
ret
|
||||
|
||||
|
||||
ds 64
|
||||
boot$stack equ $
|
||||
|
||||
|
||||
; DEVTBL
|
||||
; Return address of character device table
|
||||
|
||||
devtbl:
|
||||
lxi h,@ctbl ! ret
|
||||
|
||||
|
||||
; GETDRV
|
||||
; Return address of drive table
|
||||
|
||||
getdrv:
|
||||
lxi h,@dtbl ! ret
|
||||
|
||||
|
||||
|
||||
; CONOUT
|
||||
; Console Output. Send character in <C>
|
||||
; to all selected devices
|
||||
|
||||
conout:
|
||||
|
||||
lhld @covec ; fetch console output bit vector
|
||||
jmp out$scan
|
||||
|
||||
|
||||
; AUXOUT
|
||||
; Auxiliary Output. Send character in <C>
|
||||
; to all selected devices
|
||||
|
||||
auxout:
|
||||
lhld @aovec ; fetch aux output bit vector
|
||||
jmp out$scan
|
||||
|
||||
|
||||
; LIST
|
||||
; List Output. Send character in <C>
|
||||
; to all selected devices.
|
||||
|
||||
list:
|
||||
lhld @lovec ; fetch list output bit vector
|
||||
|
||||
out$scan:
|
||||
mvi b,0 ; start with device 0
|
||||
co$next:
|
||||
dad h ; shift out next bit
|
||||
jnc not$out$device
|
||||
push h ; save the vector
|
||||
push b ; save the count and character
|
||||
not$out$ready:
|
||||
call coster ! ora a ! jz not$out$ready
|
||||
pop b ! push b ; restore and resave the character and device
|
||||
call ?co ; if device selected, print it
|
||||
pop b ; recover count and character
|
||||
pop h ; recover the rest of the vector
|
||||
not$out$device:
|
||||
inr b ; next device number
|
||||
mov a,h ! ora l ; see if any devices left
|
||||
jnz co$next ; and go find them...
|
||||
ret
|
||||
|
||||
|
||||
; CONOST
|
||||
; Console Output Status. Return true if
|
||||
; all selected console output devices
|
||||
; are ready.
|
||||
|
||||
conost:
|
||||
lhld @covec ; get console output bit vector
|
||||
jmp ost$scan
|
||||
|
||||
|
||||
; AUXOST
|
||||
; Auxiliary Output Status. Return true if
|
||||
; all selected auxiliary output devices
|
||||
; are ready.
|
||||
|
||||
auxost:
|
||||
lhld @aovec ; get aux output bit vector
|
||||
jmp ost$scan
|
||||
|
||||
|
||||
; LISTST
|
||||
; List Output Status. Return true if
|
||||
; all selected list output devices
|
||||
; are ready.
|
||||
|
||||
listst:
|
||||
lhld @lovec ; get list output bit vector
|
||||
|
||||
ost$scan:
|
||||
mvi b,0 ; start with device 0
|
||||
cos$next:
|
||||
dad h ; check next bit
|
||||
push h ; save the vector
|
||||
push b ; save the count
|
||||
mvi a,0FFh ; assume device ready
|
||||
cc coster ; check status for this device
|
||||
pop b ; recover count
|
||||
pop h ; recover bit vector
|
||||
ora a ; see if device ready
|
||||
rz ; if any not ready, return false
|
||||
inr b ; drop device number
|
||||
mov a,h ! ora l ; see if any more selected devices
|
||||
jnz cos$next
|
||||
ori 0FFh ; all selected were ready, return true
|
||||
ret
|
||||
|
||||
coster: ; check for output device ready, including optional
|
||||
; xon/xoff support
|
||||
mov l,b ! mvi h,0 ; make device code 16 bits
|
||||
push h ; save it in stack
|
||||
dad h ! dad h ! dad h ; create offset into device characteristics tbl
|
||||
lxi d,@ctbl+6 ! dad d ; make address of mode byte
|
||||
mov a,m ! ani mb$xonxoff
|
||||
pop h ; recover console number in <HL>
|
||||
jz ?cost ; not a xon device, go get output status direct
|
||||
lxi d,xofflist ! dad d ; make pointer to proper xon/xoff flag
|
||||
call cist1 ; see if this keyboard has character
|
||||
mov a,m ! cnz ci1 ; get flag or read key if any
|
||||
cpi ctlq ! jnz not$q ; if its a ctl-Q,
|
||||
mvi a,0FFh ; set the flag ready
|
||||
not$q:
|
||||
cpi ctls ! jnz not$s ; if its a ctl-S,
|
||||
mvi a,00h ; clear the flag
|
||||
not$s:
|
||||
mov m,a ; save the flag
|
||||
call cost1 ; get the actual output status,
|
||||
ana m ; and mask with ctl-Q/ctl-S flag
|
||||
ret ; return this as the status
|
||||
|
||||
cist1: ; get input status with <BC> and <HL> saved
|
||||
push b ! push h
|
||||
call ?cist
|
||||
pop h ! pop b
|
||||
ora a
|
||||
ret
|
||||
|
||||
cost1: ; get output status, saving <BC> & <HL>
|
||||
push b ! push h
|
||||
call ?cost
|
||||
pop h ! pop b
|
||||
ora a
|
||||
ret
|
||||
|
||||
ci1: ; get input, saving <BC> & <HL>
|
||||
push b ! push h
|
||||
call ?ci
|
||||
pop h ! pop b
|
||||
ret
|
||||
|
||||
|
||||
; CONST
|
||||
; Console Input Status. Return true if
|
||||
; any selected console input device
|
||||
; has an available character.
|
||||
|
||||
const:
|
||||
lhld @civec ; get console input bit vector
|
||||
jmp ist$scan
|
||||
|
||||
|
||||
; AUXIST
|
||||
; Auxiliary Input Status. Return true if
|
||||
; any selected auxiliary input device
|
||||
; has an available character.
|
||||
|
||||
auxist:
|
||||
lhld @aivec ; get aux input bit vector
|
||||
|
||||
ist$scan:
|
||||
mvi b,0 ; start with device 0
|
||||
cis$next:
|
||||
dad h ; check next bit
|
||||
mvi a,0 ; assume device not ready
|
||||
cc cist1 ; check status for this device
|
||||
ora a ! rnz ; if any ready, return true
|
||||
inr b ; drop device number
|
||||
mov a,h ! ora l ; see if any more selected devices
|
||||
jnz cis$next
|
||||
xra a ; all selected were not ready, return false
|
||||
ret
|
||||
|
||||
|
||||
; CONIN
|
||||
; Console Input. Return character from first
|
||||
; ready console input device.
|
||||
|
||||
conin:
|
||||
lhld @civec
|
||||
jmp in$scan
|
||||
|
||||
|
||||
; AUXIN
|
||||
; Auxiliary Input. Return character from first
|
||||
; ready auxiliary input device.
|
||||
|
||||
auxin:
|
||||
lhld @aivec
|
||||
|
||||
in$scan:
|
||||
push h ; save bit vector
|
||||
mvi b,0
|
||||
ci$next:
|
||||
dad h ; shift out next bit
|
||||
mvi a,0 ; insure zero a (nonexistant device not ready).
|
||||
cc cist1 ; see if the device has a character
|
||||
ora a
|
||||
jnz ci$rdy ; this device has a character
|
||||
inr b ; else, next device
|
||||
mov a,h ! ora l ; see if any more devices
|
||||
jnz ci$next ; go look at them
|
||||
pop h ; recover bit vector
|
||||
jmp in$scan ; loop til we find a character
|
||||
|
||||
ci$rdy:
|
||||
pop h ; discard extra stack
|
||||
jmp ?ci
|
||||
|
||||
|
||||
; Utility Subroutines
|
||||
|
||||
|
||||
ipchl: ; vectored CALL point
|
||||
pchl
|
||||
|
||||
|
||||
?pmsg: ; print message @<HL> up to a null
|
||||
; saves <BC> & <DE>
|
||||
push b
|
||||
push d
|
||||
pmsg$loop:
|
||||
mov a,m ! ora a ! jz pmsg$exit
|
||||
mov c,a ! push h
|
||||
call ?cono ! pop h
|
||||
inx h ! jmp pmsg$loop
|
||||
pmsg$exit:
|
||||
pop d
|
||||
pop b
|
||||
ret
|
||||
|
||||
?pdec: ; print binary number 0-65535 from <HL>
|
||||
lxi b,table10! lxi d,-10000
|
||||
next:
|
||||
mvi a,'0'-1
|
||||
pdecl:
|
||||
push h! inr a! dad d! jnc stoploop
|
||||
inx sp! inx sp! jmp pdecl
|
||||
stoploop:
|
||||
push d! push b
|
||||
mov c,a! call ?cono
|
||||
pop b! pop d
|
||||
nextdigit:
|
||||
pop h
|
||||
ldax b! mov e,a! inx b
|
||||
ldax b! mov d,a! inx b
|
||||
mov a,e! ora d! jnz next
|
||||
ret
|
||||
|
||||
table10:
|
||||
dw -1000,-100,-10,-1,0
|
||||
|
||||
?pderr:
|
||||
lxi h,drive$msg ! call ?pmsg ; error header
|
||||
lda @adrv ! adi 'A' ! mov c,a ! call ?cono ; drive code
|
||||
lxi h,track$msg ! call ?pmsg ; track header
|
||||
lhld @trk ! call ?pdec ; track number
|
||||
lxi h,sector$msg ! call ?pmsg ; sector header
|
||||
lhld @sect ! call ?pdec ; sector number
|
||||
ret
|
||||
|
||||
|
||||
; BNKSEL
|
||||
; Bank Select. Select CPU bank for further execution.
|
||||
|
||||
bnksel:
|
||||
sta @cbnk ; remember current bank
|
||||
jmp ?bank ; and go exit through users
|
||||
; physical bank select routine
|
||||
|
||||
|
||||
xofflist db -1,-1,-1,-1,-1,-1,-1,-1 ; ctl-s clears to zero
|
||||
db -1,-1,-1,-1,-1,-1,-1,-1
|
||||
|
||||
|
||||
|
||||
dseg ; following resides in banked memory
|
||||
|
||||
|
||||
|
||||
; Disk I/O interface routines
|
||||
|
||||
|
||||
; SELDSK
|
||||
; Select Disk Drive. Drive code in <C>.
|
||||
; Invoke login procedure for drive
|
||||
; if this is first select. Return
|
||||
; address of disk parameter header
|
||||
; in <HL>
|
||||
|
||||
seldsk:
|
||||
mov a,c ! sta @adrv ; save drive select code
|
||||
mov l,c ! mvi h,0 ! dad h ; create index from drive code
|
||||
lxi b,@dtbl ! dad b ; get pointer to dispatch table
|
||||
mov a,m ! inx h ! mov h,m ! mov l,a ; point at disk descriptor
|
||||
ora h ! rz ; if no entry in table, no disk
|
||||
mov a,e ! ani 1 ! jnz not$first$select ; examine login bit
|
||||
push h ! xchg ; put pointer in stack & <DE>
|
||||
lxi h,-2 ! dad d ! mov a,m ! sta @RDRV ; get relative drive
|
||||
lxi h,-6 ! dad d ; find LOGIN addr
|
||||
mov a,m ! inx h ! mov h,m ! mov l,a ; get address of LOGIN routine
|
||||
call ipchl ; call LOGIN
|
||||
pop h ; recover DPH pointer
|
||||
not$first$select:
|
||||
ret
|
||||
|
||||
|
||||
; HOME
|
||||
; Home selected drive. Treated as SETTRK(0).
|
||||
|
||||
home:
|
||||
lxi b,0 ; same as set track zero
|
||||
|
||||
|
||||
; SETTRK
|
||||
; Set Track. Saves track address from <BC>
|
||||
; in @TRK for further operations.
|
||||
|
||||
settrk:
|
||||
mov l,c ! mov h,b
|
||||
shld @trk
|
||||
ret
|
||||
|
||||
|
||||
; SETSEC
|
||||
; Set Sector. Saves sector number from <BC>
|
||||
; in @sect for further operations.
|
||||
|
||||
setsec:
|
||||
mov l,c ! mov h,b
|
||||
shld @sect
|
||||
ret
|
||||
|
||||
|
||||
; SETDMA
|
||||
; Set Disk Memory Address. Saves DMA address
|
||||
; from <BC> in @DMA and sets @DBNK to @CBNK
|
||||
; so that further disk operations take place
|
||||
; in current bank.
|
||||
|
||||
setdma:
|
||||
mov l,c ! mov h,b
|
||||
shld @dma
|
||||
|
||||
lda @cbnk ; default DMA bank is current bank
|
||||
; fall through to set DMA bank
|
||||
|
||||
; SETBNK
|
||||
; Set Disk Memory Bank. Saves bank number
|
||||
; in @DBNK for future disk data
|
||||
; transfers.
|
||||
|
||||
setbnk:
|
||||
sta @dbnk
|
||||
ret
|
||||
|
||||
|
||||
; SECTRN
|
||||
; Sector Translate. Indexes skew table in <DE>
|
||||
; with sector in <BC>. Returns physical sector
|
||||
; in <HL>. If no skew table (<DE>=0) then
|
||||
; returns physical=logical.
|
||||
|
||||
sectrn:
|
||||
mov l,c ! mov h,b
|
||||
mov a,d ! ora e ! rz
|
||||
xchg ! dad b ! mov l,m ! mvi h,0
|
||||
ret
|
||||
|
||||
|
||||
; READ
|
||||
; Read physical record from currently selected drive.
|
||||
; Finds address of proper read routine from
|
||||
; extended disk parameter header (XDPH).
|
||||
|
||||
read:
|
||||
lhld @adrv ! mvi h,0 ! dad h ; get drive code and double it
|
||||
lxi d,@dtbl ! dad d ; make address of table entry
|
||||
mov a,m ! inx h ! mov h,m ! mov l,a ; fetch table entry
|
||||
push h ; save address of table
|
||||
lxi d,-8 ! dad d ; point to read routine address
|
||||
jmp rw$common ; use common code
|
||||
|
||||
|
||||
; WRITE
|
||||
; Write physical sector from currently selected drive.
|
||||
; Finds address of proper write routine from
|
||||
; extended disk parameter header (XDPH).
|
||||
|
||||
write:
|
||||
lhld @adrv ! mvi h,0 ! dad h ; get drive code and double it
|
||||
lxi d,@dtbl ! dad d ; make address of table entry
|
||||
mov a,m ! inx h ! mov h,m ! mov l,a ; fetch table entry
|
||||
push h ; save address of table
|
||||
lxi d,-10 ! dad d ; point to write routine address
|
||||
|
||||
rw$common:
|
||||
mov a,m ! inx h ! mov h,m ! mov l,a ; get address of routine
|
||||
pop d ; recover address of table
|
||||
dcx d ! dcx d ; point to relative drive
|
||||
ldax d ! sta @rdrv ; get relative drive code and post it
|
||||
inx d ! inx d ; point to DPH again
|
||||
pchl ; leap to driver
|
||||
|
||||
|
||||
; MULTIO
|
||||
; Set multiple sector count. Saves passed count in
|
||||
; @CNT
|
||||
|
||||
multio:
|
||||
sta @cnt ! ret
|
||||
|
||||
|
||||
; FLUSH
|
||||
; BIOS deblocking buffer flush. Not implemented.
|
||||
|
||||
flush:
|
||||
xra a ! ret ; return with no error
|
||||
|
||||
|
||||
|
||||
; error message components
|
||||
drive$msg db cr,lf,bell,'BIOS Error on ',0
|
||||
track$msg db ': T-',0
|
||||
sector$msg db ', S-',0
|
||||
|
||||
|
||||
; disk communication data items
|
||||
|
||||
@adrv ds 1 ; currently selected disk drive
|
||||
@rdrv ds 1 ; controller relative disk drive
|
||||
@trk ds 2 ; current track number
|
||||
@sect ds 2 ; current sector number
|
||||
@dma ds 2 ; current DMA address
|
||||
@cnt db 0 ; record count for multisector transfer
|
||||
@dbnk db 0 ; bank for DMA operations
|
||||
|
||||
|
||||
cseg ; common memory
|
||||
|
||||
@cbnk db 0 ; bank for processor operations
|
||||
|
||||
|
||||
end
|
||||
480
Source/CPM3/biosldr.z80
Normal file
480
Source/CPM3/biosldr.z80
Normal file
@@ -0,0 +1,480 @@
|
||||
|
||||
maclib cpm3.lib
|
||||
|
||||
cseg
|
||||
|
||||
; BIOS Jump vector.
|
||||
|
||||
; All BIOS routines are invoked by calling these
|
||||
; entry points.
|
||||
|
||||
?boot: jp boot ; initial entry on cold start
|
||||
?wboot: jp wboot ; reentry on program exit, warm start
|
||||
|
||||
?const: jp const ; return console input status
|
||||
?conin: jp conin ; return console input character
|
||||
?cono: jp conout ; send console output character
|
||||
?list: jp list ; send list output character
|
||||
?auxo: jp auxout ; send auxilliary output character
|
||||
?auxi: jp auxin ; return auxilliary input character
|
||||
|
||||
?home: jp home ; set disks to logical home
|
||||
?sldsk: jp seldsk ; select disk drive, return disk parameter info
|
||||
?sttrk: jp settrk ; set disk track
|
||||
?stsec: jp setsec ; set disk sector
|
||||
?stdma: jp setdma ; set disk I/O memory address
|
||||
?read: jp read ; read physical block(s)
|
||||
?write: jp write ; write physical block(s)
|
||||
|
||||
?lists: jp listst ; return list device status
|
||||
?sctrn: jp sectrn ; translate logical to physical sector
|
||||
|
||||
?conos: jp conost ; return console output status
|
||||
?auxis: jp auxist ; return aux input status
|
||||
?auxos: jp auxost ; return aux output status
|
||||
?dvtbl: jp devtbl ; return address of device def table
|
||||
?devin: jp devini ; change baud rate of device
|
||||
|
||||
?drtbl: jp drvtbl ; return address of disk drive table
|
||||
?mltio: jp multio ; set multiple record count for disk I/O
|
||||
?flush: jp flush ; flush BIOS maintained disk caching
|
||||
|
||||
?mov: jp move ; block move memory to memory
|
||||
?tim: jp time ; Signal Time and Date operation
|
||||
?bnksl: jp selmem ; select bank for code execution and default DMA
|
||||
?stbnk: jp setbnk ; select different bank for disk I/O DMA operations.
|
||||
?xmov: jp xmove ; set source and destination banks for one operation
|
||||
|
||||
jp 0 ; reserved for future expansion
|
||||
jp 0 ; reserved for future expansion
|
||||
jp 0 ; reserved for future expansion
|
||||
|
||||
boot:
|
||||
;ld bc,0F8E0h ; HBIOS func: get boot info
|
||||
;call 0FFF0h ; do it, D := boot unit
|
||||
;ld a,d ; move to A
|
||||
;ld (unit),a ; save it
|
||||
;ret
|
||||
|
||||
ld (stksav),sp
|
||||
ld sp,stack
|
||||
|
||||
boot1:
|
||||
ld de,prompt
|
||||
call writestr
|
||||
|
||||
call cin
|
||||
call cout
|
||||
|
||||
push af
|
||||
ld de,crlf
|
||||
call writestr
|
||||
pop af
|
||||
|
||||
sub '0'
|
||||
jr c,boot1
|
||||
cp 10 ; !!! Need to test against max disk unit num !!!
|
||||
jr nc,boot1
|
||||
|
||||
ld (unit),a
|
||||
|
||||
ld bc,0F9E0h ; HBIOS func: set boot info
|
||||
ld d,a ; Unit
|
||||
ld e,0 ; Slice
|
||||
ld l,0 ; Bank
|
||||
call 0FFF0h ; do it
|
||||
|
||||
|
||||
|
||||
ld a,(unit) ; Get boot unit
|
||||
ld c,a ; put in C
|
||||
ld b,18h ; HBIOS Media function
|
||||
ld e,1 ; Enabled media check/discovery
|
||||
call 0FFF0H ; HBIOS call
|
||||
ld a,e ; Resultant media id to accum
|
||||
or a ; Set flags
|
||||
;halt
|
||||
;
|
||||
; !!! Need to do something on error !!!
|
||||
;
|
||||
ret z ; Bail out on error
|
||||
|
||||
ld hl,dpb$start - dpb$sz
|
||||
ld de,dpb$sz
|
||||
ld b,a ; loop count
|
||||
dsk$login1:
|
||||
add hl,de ; next dpb
|
||||
djnz dsk$login1 ; loop as needed
|
||||
|
||||
; hl is ptr to desired dpb
|
||||
ld de,dph0 ; load DPH pointer
|
||||
;halt
|
||||
ex de,hl ; de = DPB adr, hl = DPH adr
|
||||
push de ; save DPB adr
|
||||
ld de,12 ; offset of DPB in DPH
|
||||
add hl,de ; hl = adr of DPB field in DPH
|
||||
pop de ; recover DPB adr
|
||||
ld (hl),e ; update LSB
|
||||
inc hl
|
||||
ld (hl),d ; udpate MSB
|
||||
|
||||
|
||||
|
||||
ld sp,(stksav)
|
||||
ret
|
||||
|
||||
wboot:
|
||||
ld a,81H
|
||||
halt
|
||||
|
||||
const:
|
||||
ld a,82H
|
||||
halt
|
||||
conin:
|
||||
ld bc,0000H ; unit 0, func 0 = CIN
|
||||
call 0FFF0H
|
||||
|
||||
conout:
|
||||
ld e,c ; output character in E
|
||||
ld bc,0100H ; unit 0, func 1 = COUT
|
||||
;rst 08 ; do it
|
||||
call 0FFF0H
|
||||
ret ; return
|
||||
list:
|
||||
ld a,85H
|
||||
halt
|
||||
auxout:
|
||||
ld a,86H
|
||||
halt
|
||||
auxin:
|
||||
ld a,87H
|
||||
halt
|
||||
|
||||
home:
|
||||
ld hl,0
|
||||
ld (trk),hl
|
||||
ret
|
||||
seldsk:
|
||||
ld hl,dph0
|
||||
ret
|
||||
settrk:
|
||||
ld (trk),bc
|
||||
ret
|
||||
setsec:
|
||||
ld (sect),bc
|
||||
ret
|
||||
setdma:
|
||||
ld (dma),bc
|
||||
ret
|
||||
read:
|
||||
; Seek
|
||||
ld hl,(trk) ; get track value
|
||||
ld a,l ; lsb of track to a
|
||||
and 0FH ; isolate head in low 4 bits
|
||||
ld d,a ; stuff it in d
|
||||
ld a,(sect) ; get sector
|
||||
ld e,a ; stuff it in e
|
||||
ld b,4 ; prepare to shift out 4 bit head value
|
||||
read1:
|
||||
srl h ; shift one bit out
|
||||
rr l ; ... of hl
|
||||
djnz read1 ; do all 4 bits
|
||||
ld b,12h ; HBIOS seek
|
||||
ld a,(unit) ; get boot unit
|
||||
ld c,a ; put in C
|
||||
;rst 08 ; perform seek
|
||||
call 0FFF0H
|
||||
; Read Sector
|
||||
ld b,13h ; HBIOS read
|
||||
ld a,(unit) ; get boot unit
|
||||
ld c,a ; put in C
|
||||
ld hl,(dma) ; dma address
|
||||
ld a,(0FFE0H) ; current bank
|
||||
ld d,a ; ... to D
|
||||
ld e,1 ; 1 sector
|
||||
;rst 08
|
||||
call 0FFF0H
|
||||
|
||||
ret
|
||||
write:
|
||||
ld a,8EH
|
||||
halt
|
||||
|
||||
listst:
|
||||
ld a,8FH
|
||||
halt
|
||||
sectrn:
|
||||
ld h,b
|
||||
ld l,c
|
||||
ret
|
||||
|
||||
conost:
|
||||
ld a,91H
|
||||
halt
|
||||
auxist:
|
||||
ld a,92H
|
||||
halt
|
||||
auxost:
|
||||
ld a,93H
|
||||
halt
|
||||
devtbl:
|
||||
ld a,94H
|
||||
halt
|
||||
devini:
|
||||
ld a,95H
|
||||
halt
|
||||
|
||||
drvtbl:
|
||||
ld a,96H
|
||||
halt
|
||||
multio:
|
||||
ld a,97H
|
||||
halt
|
||||
flush:
|
||||
ld a,98H
|
||||
halt
|
||||
|
||||
move:
|
||||
ex de,hl ; we are passed source in DE and dest in HL
|
||||
ldir ; use Z80 block move instruction
|
||||
ex de,hl ; need next addresses in same regs
|
||||
ret
|
||||
time:
|
||||
ld a,9AH
|
||||
halt
|
||||
selmem:
|
||||
ld a,9BH
|
||||
halt
|
||||
setbnk:
|
||||
ld a,9CH
|
||||
halt
|
||||
xmove:
|
||||
ld a,9DH
|
||||
halt
|
||||
|
||||
cin:
|
||||
; save incoming registers (af is output)
|
||||
push bc
|
||||
push de
|
||||
push hl
|
||||
|
||||
; input character from console via hbios
|
||||
ld c,0D0H ; console unit to c
|
||||
ld b,00H ; hbios func: input char
|
||||
call 0FFF0H ; hbios reads character
|
||||
ld a,e ; move character to a for return
|
||||
|
||||
; restore registers (af is output)
|
||||
pop hl
|
||||
pop de
|
||||
pop bc
|
||||
ret
|
||||
|
||||
cout:
|
||||
; save all incoming registers
|
||||
push af
|
||||
push bc
|
||||
push de
|
||||
push hl
|
||||
|
||||
; output character to console via hbios
|
||||
ld e,a ; output char to e
|
||||
ld c,0D0H ; console unit to c
|
||||
ld b,01H ; hbios func: output char
|
||||
call 0FFF0H ; hbios outputs character
|
||||
|
||||
; restore all registers
|
||||
pop hl
|
||||
pop de
|
||||
pop bc
|
||||
pop af
|
||||
ret
|
||||
|
||||
writestr:
|
||||
push af
|
||||
writestr1:
|
||||
ld a,(de)
|
||||
cp '$' ; test for string terminator
|
||||
jp z,writestr2
|
||||
call cout
|
||||
inc de
|
||||
jp writestr1
|
||||
writestr2:
|
||||
pop af
|
||||
ret
|
||||
|
||||
prompt db 13,10,'Boot CP/M 3 from Disk Unit: $'
|
||||
crlf db 13,10,'$'
|
||||
|
||||
dpb$start:
|
||||
dpb$rom: ; 384K ROM Drive
|
||||
dw 64 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 1 ; exm: extent mask
|
||||
dw 192 - 1 ; dsm: total storage in blocks - 1 = (384kb / 2k bls) - 1 = 191
|
||||
dw 256 - 1 ; drm: dir entries - 1 = 256 - 1 = 255
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
|
||||
dw 0 ; off: reserved tracks = 16 trks * (16 trks * 16 heads * 16 secs * 512 bytes) = 128k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
dpb$sz equ $ - dpb$start
|
||||
|
||||
dpb$ram: ; 256K RAM Drive
|
||||
dw 64 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 1 ; exm: extent mask
|
||||
dw 128 - 1 ; dsm: total storage in blocks - 1 = (256kb / 2k bls) - 1 = 127
|
||||
dw 256 - 1 ; drm: dir entries - 1 = 256 - 1 = 255
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
|
||||
dw 0 ; off: reserved tracks = 16 trks * (16 trks * 16 heads * 16 secs * 512 bytes) = 128k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb$rf: ; 4MB RAM Floppy Drive
|
||||
dw 64 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 0 ; exm: extent mask
|
||||
dw 2047 ; dsm: total storage in blocks - 1 = (4mb / 2k bls) - 1 = 2047
|
||||
dw 255 ; drm: dir entries - 1 = 256 - 1 = 255
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
|
||||
dw 0 ; off: reserved tracks = 0 trks
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb$hd: ; 8MB Hard Disk Drive
|
||||
dw 64 ; spt: sectors per track
|
||||
db 5 ; bsh: block shift factor
|
||||
db 31 ; blm: block mask
|
||||
db 1 ; exm: extent mask
|
||||
dw 2047 ; dsm: total storage in blocks - 1 = (8mb / 4k bls) - 1 = 2047
|
||||
dw 511 ; drm: dir entries - 1 = 512 - 1 = 511
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
|
||||
dw 16 ; off: reserved tracks = 16 trks * (16 trks * 16 heads * 16 secs * 512 bytes) = 128k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb$fd720: ; 3.5" DS/DD Floppy Drive (720K)
|
||||
dw 36 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 0 ; exm: extent mask
|
||||
dw 350 ; dsm: total storage in blocks - 1 blk = ((720k - 18k off) / 2k bls) - 1 = 350
|
||||
dw 127 ; drm: dir entries - 1 = 128 - 1 = 127
|
||||
db 11000000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 32 ; cks: directory check vector size = 128 / 4
|
||||
dw 4 ; off: reserved tracks = 4 trks * (512 b/sec * 36 sec/trk) = 18k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb_fd144: ; 3.5" DS/HD Floppy Drive (1.44M)
|
||||
dw 72 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 0 ; exm: extent mask
|
||||
dw 710 ; dsm: total storage in blocks - 1 blk = ((1,440k - 18k off) / 2k bls) - 1 = 710
|
||||
dw 255 ; drm: dir entries - 1 = 256 - 1 = 255
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 64 ; cks: directory check vector size = 256 / 4
|
||||
dw 2 ; off: reserved tracks = 2 trks * (512 b/sec * 72 sec/trk) = 18k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb_fd360: ; 5.25" DS/DD Floppy Drive (360K)
|
||||
dw 36 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 1 ; exm: extent mask
|
||||
dw 170 ; dsm: total storage in blocks - 1 blk = ((360k - 18k off) / 2k bls) - 1 = 170
|
||||
dw 127 ; drm: dir entries - 1 = 128 - 1 = 127
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 32 ; cks: directory check vector size = 128 / 4
|
||||
dw 4 ; off: reserved tracks = 4 trks * (512 b/sec * 36 sec/trk) = 18k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb_fd120: ; 5.25" DS/HD Floppy Drive (1.2M)
|
||||
dw 60 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 0 ; exm: extent mask
|
||||
dw 591 ; dsm: total storage in blocks - 1 blk = ((1,200k - 15k off) / 2k bls) - 1 = 591
|
||||
dw 255 ; drm: dir entries - 1 = 256 - 1 = 255
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 64 ; cks: directory check vector size = 256 / 4
|
||||
dw 2 ; off: reserved tracks = 2 trks * (512 b/sec * 60 sec/trk) = 15k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb_fd111: ; 8" DS/DD Floppy Drive (1.11M)
|
||||
dw 60 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 0 ; exm: extent mask
|
||||
dw 569 ; dsm: total storage in blocks - 1 blk = ((1,155k - 15k off) / 2k bls) - 1 = 569
|
||||
dw 255 ; drm: dir entries - 1 = 256 - 1 = 255
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 64 ; cks: directory check vector size = 256 / 4
|
||||
dw 2 ; off: reserved tracks = 2 trks * (512 b/sec * 60 sec/trk) = 15k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dph0: dw 0 ; xlt, 0 means no translation
|
||||
db 0,0,0,0,0,0,0,0,0 ; scratch (9 bytes)
|
||||
db 0 ; mf: media flag
|
||||
dw dpb$hd ; dpb
|
||||
dw csvbuf ; csv:
|
||||
dw alvbuf ; alv:
|
||||
dw dirbcb ; dirbcb
|
||||
dw dtabcb ; dtabcb
|
||||
dw 0ffffh ; hash (disabled)
|
||||
db 0 ; hbank
|
||||
|
||||
dtbl: dtbl dph0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
|
||||
dirbcb: db 0ffh ; drv
|
||||
db 0,0,0 ; rec#
|
||||
db 0 ; wflg
|
||||
db 0 ; scratch
|
||||
dw 0 ; track
|
||||
dw 0 ; sector
|
||||
dw dirbuf ; buffad
|
||||
|
||||
dtabcb: db 0ffh ; drv
|
||||
db 0,0,0 ; rec#
|
||||
db 0 ; wflg
|
||||
db 0 ; scratch
|
||||
dw 0 ; track
|
||||
dw 0 ; sector
|
||||
dw dtabuf ; buffad
|
||||
|
||||
unit ds 1 ; HBIOS unit number
|
||||
trk ds 2 ; current track
|
||||
sect ds 2 ; current sector
|
||||
dma ds 2 ; current DMA address
|
||||
|
||||
csvbuf ds 128 ; length (CSV) = ((DRM+1)/4)
|
||||
alvbuf ds 512 ; length (ALV) = ((DSM+1)/4)
|
||||
dirbuf ds 512 ; sector buffer
|
||||
dtabuf ds 512 ; sector buffer
|
||||
|
||||
ds 32
|
||||
stack equ $
|
||||
stksav dw 0
|
||||
|
||||
end
|
||||
BIN
Source/CPM3/bnkbdos3.spr
Normal file
BIN
Source/CPM3/bnkbdos3.spr
Normal file
Binary file not shown.
362
Source/CPM3/boot.z80
Normal file
362
Source/CPM3/boot.z80
Normal file
@@ -0,0 +1,362 @@
|
||||
title 'Boot loader module for CP/M 3.0'
|
||||
|
||||
maclib options.lib
|
||||
|
||||
public ?init,?ldccp,?rlccp,?time
|
||||
public @bootdu
|
||||
extrn ?pmsg,?conin
|
||||
extrn ?mvinit,?bnkxlt,?xmove,?move
|
||||
extrn @civec,@covec,@aivec,@aovec,@lovec
|
||||
extrn @cbnk,?bnksl,?bank
|
||||
extrn @sysdr,@ccpdr
|
||||
extrn dph0
|
||||
extrn @dtbl
|
||||
|
||||
bdos equ 5
|
||||
|
||||
if banked
|
||||
tpa$bank equ 1
|
||||
else
|
||||
tpa$bank equ 0
|
||||
endif
|
||||
|
||||
dseg ; init done from banked memory
|
||||
|
||||
?init:
|
||||
call ?mvinit
|
||||
; lxi h,08000h ! shld @civec ! shld @covec ; assign console to CRT:
|
||||
ld hl,8000H ; device 0
|
||||
ld (@civec),hl ; assign to console input
|
||||
ld (@covec),hl ; assign to console output
|
||||
; lxi h,04000h ! shld @lovec ; assign printer to LPT:
|
||||
; lxi h,02000h ! shld @aivec ! shld @aovec ; assign AUX to CRT1:
|
||||
; lxi h,signon$msg ! call ?pmsg ; print signon message
|
||||
ld hl,signon$msg ; signon message
|
||||
call ?pmsg ; print it
|
||||
|
||||
if banked
|
||||
|
||||
; clone page zero from bank 0 to additional banks
|
||||
ld b,2 ; last bank
|
||||
ld c,0 ; src bank
|
||||
init$0:
|
||||
push bc ; save bank id's
|
||||
call init$1 ; copy page zero
|
||||
pop bc ; restore bank id's
|
||||
djnz init$0 ; loop till done
|
||||
jr init$2
|
||||
|
||||
init$1:
|
||||
call ?xmove ; set src/dest banks
|
||||
ld bc,0100h ; size is one page
|
||||
ld hl,0 ; dest adr is 0
|
||||
ld de,0 ; src adr is 0
|
||||
call ?move ; do it
|
||||
ret
|
||||
|
||||
endif
|
||||
|
||||
init$2:
|
||||
; get boot disk unit and save it
|
||||
ld bc,0F8E0h ; HBIOS func: get boot info
|
||||
call 0FFF0h ; do it, D := boot unit
|
||||
ld a,d ; move to A
|
||||
ld (@bootdu),a ; save it
|
||||
|
||||
call dinit
|
||||
ret
|
||||
|
||||
dinit:
|
||||
|
||||
; loop through all disk devices to count hard disk units
|
||||
ld b,0F8h ; SYS GET
|
||||
ld c,010h ; Disk Drive Unit Count
|
||||
call 0FFF0h ; e := disk unit count
|
||||
ld b,e ; count to b
|
||||
ld a,b ; count to a
|
||||
or a ; set flags
|
||||
ret z ; !!! handle zero devices (albeit poorly) !!!
|
||||
;
|
||||
; loop thru devices to count total hard disk volumes
|
||||
push bc ; save the device count
|
||||
ld c,0 ; use c as device list index
|
||||
ld e,0 ; init e for hard disk volume count
|
||||
;
|
||||
dinit2:
|
||||
push bc ; save loop control
|
||||
call dinit3 ; check drive
|
||||
pop bc ; restore loop control
|
||||
inc c ; next unit
|
||||
djnz dinit2 ; loop
|
||||
pop bc ; restore unit count in b
|
||||
jr dinit4 ; continue
|
||||
;
|
||||
dinit3:
|
||||
push de ; save de (hard disk volume counter)
|
||||
ld b,017h ; hbios func: report device info
|
||||
call 0FFF0h ; call hbios, unit to c
|
||||
ld a,d ; device type to a
|
||||
pop de ; restore de
|
||||
cp 050h ; hard disk device?
|
||||
ret c ; nope, return
|
||||
inc e ; increment hard disk count
|
||||
ret ; and return
|
||||
;
|
||||
dinit4: ; set slices per volume (hdspv) based on hard disk volume count
|
||||
ld a,e ; hard disk volume count to a
|
||||
ld e,8 ; assume 8 slices per volume
|
||||
dec a ; dec accum to check for count = 1
|
||||
jr z,dinit5 ; yes, skip ahead to implement 8 hdspv
|
||||
ld e,4 ; now assume 4 slices per volume
|
||||
dec a ; dec accum to check for count = 2
|
||||
jr z,dinit5 ; yes, skip ahead to implement 4 hdspv
|
||||
ld e,2 ; in all other cases, we use 2 hdspv
|
||||
;
|
||||
dinit5:
|
||||
ld a,e ; slices per volume value to accum
|
||||
ld (hdspv),a ; save it
|
||||
;
|
||||
; setup to enumerate devices to build drvmap
|
||||
ld b,0F8h ; SYS GET
|
||||
ld c,010h ; Disk Drive Unit Count
|
||||
call 0FFF0h ; e := disk unit count
|
||||
ld b,e ; count to b
|
||||
ld c,0 ; use c as device list index
|
||||
;ld hl,dph0 ; point to first dph
|
||||
ld hl,0 ; dph index
|
||||
;
|
||||
dinit6: ; loop thru all units available
|
||||
push bc ; preserve loop control
|
||||
push hl ; preserve dph pointer
|
||||
ld b,017h ; hbios func: report device info
|
||||
call 0FFF0h ; call hbios, d := device type
|
||||
pop hl ; restore dph pointer
|
||||
pop bc ; get unit index back in c
|
||||
push bc ; resave loop control
|
||||
call dinit7 ; update dph entries
|
||||
pop bc ; restore loop control
|
||||
inc c ; increment list index
|
||||
djnz dinit6 ; loop as needed
|
||||
|
||||
; zero out remaining dph table entries
|
||||
ld a,16 ; dph table entries
|
||||
sub l ; subtract entries used
|
||||
ret z ; return if all entries used
|
||||
ld b,a ; save as loop counter
|
||||
ld a,l ; current dph to accum
|
||||
rlca ; *2 for word entry
|
||||
ld hl,@dtbl ; start of dtbl
|
||||
call addhla ; hl now points to entry
|
||||
dinit6a:
|
||||
xor a ; zero accum
|
||||
ld (hl),a ; zero lsb
|
||||
inc hl ; next byte
|
||||
ld (hl),a ; zero msb
|
||||
inc hl ; next byte
|
||||
djnz dinit6a
|
||||
|
||||
ret ; finished
|
||||
;
|
||||
dinit7: ; process unit
|
||||
ld e,0 ; initialize slice index
|
||||
ld b,1 ; default loop counter
|
||||
ld a,d ; device type to accum
|
||||
ld d,c ; unit number to d
|
||||
cp 050h ; hard disk device?
|
||||
jr c,dinit8 ; nope, leave loop count at 1
|
||||
ld a,(hdspv) ; get slices per volume to accum
|
||||
ld b,a ; move to b for loop counter
|
||||
;
|
||||
dinit8:
|
||||
; d=unit, e=slice, l=dph#
|
||||
ld a,l ; dph # to accum
|
||||
cp 16 ; dph table size
|
||||
ret z ; bail out if overflow
|
||||
push hl ; save dph #
|
||||
rlca ; *2 for adr entry
|
||||
ld hl,@dtbl ; dph table start
|
||||
call addhla ; offset hl to desired entry
|
||||
ld a,(hl) ; dereference
|
||||
inc hl
|
||||
ld h,(hl)
|
||||
ld l,a
|
||||
dec hl ; backup to slice field
|
||||
ld (hl),e ; update slice number
|
||||
dec hl ; backup to unit number
|
||||
ld (hl),d ; update unit number
|
||||
inc e ; next slice
|
||||
pop hl ; restore dph #
|
||||
inc hl ; next dph #
|
||||
djnz dinit8 ; loop till done with unit
|
||||
ret
|
||||
|
||||
addhla:
|
||||
add a,l
|
||||
ld l,a
|
||||
ret nc
|
||||
inc h
|
||||
ret
|
||||
|
||||
|
||||
cseg ; boot loading most be done from resident memory
|
||||
|
||||
; This version of the boot loader loads the CCP from a file
|
||||
; called CCP.COM on the system drive (A:).
|
||||
|
||||
?ldccp:
|
||||
; First time, load the A:CCP.COM file into TPA
|
||||
ld a,(@sysdr) ; get system boot drive
|
||||
inc a ; drive + 1 for FCB
|
||||
ld (ccp$fcb),a ; stuff into FCB
|
||||
add 'A' - 1 ; drive letter
|
||||
ld (ccp$msg$drv),a ; save for load msg
|
||||
xor a
|
||||
ld (ccp$fcb+15),a
|
||||
ld hl,0
|
||||
ld (fcb$nr),hl
|
||||
ld de,ccp$fcb
|
||||
call open
|
||||
inc a
|
||||
jr z,no$CCP
|
||||
ld de,0100H
|
||||
call setdma
|
||||
ld de,128
|
||||
call setmulti
|
||||
ld de,ccp$fcb
|
||||
call read
|
||||
|
||||
if banked
|
||||
|
||||
; ; now,
|
||||
; ; copy CCP to bank 0 for reloading
|
||||
; lxi h,0100h ! lxi b,0C80h ; clone 3K, just in case
|
||||
; lda @cbnk ! push psw ; save current bank
|
||||
;ld$1:
|
||||
; mvi a,tpa$bank ! call ?bnksl ; select TPA
|
||||
; mov a,m ! push psw ; get a byte
|
||||
; mvi a,2 ! call ?bnksl ; select extra bank
|
||||
; pop psw ! mov m,a ; save the byte
|
||||
; inx h ! dcx b ; bump pointer, drop count
|
||||
; mov a,b ! ora c ; test for done
|
||||
; jnz ld$1
|
||||
; pop psw ! call ?bnksl ; restore original bank
|
||||
|
||||
; ; now,
|
||||
; ; copy CCP to bank 0 for reloading
|
||||
ld hl,0100h ; clone 3K, just in case
|
||||
ld bc,0C80h
|
||||
ld a,(@cbnk) ; save current bank
|
||||
push af
|
||||
ld$1:
|
||||
ld a,tpa$bank ; select TPA
|
||||
call ?bnksl
|
||||
ld a,(hl) ; get a byte
|
||||
push af
|
||||
ld a,2 ; select extra bank
|
||||
call ?bnksl
|
||||
pop af ; save the byte
|
||||
ld (hl),a
|
||||
inc hl ; bump pointer, drop count
|
||||
dec bc
|
||||
ld a,b ; test for done
|
||||
or c
|
||||
jr nz,ld$1
|
||||
pop af ; restore original bank
|
||||
call ?bnksl
|
||||
|
||||
endif
|
||||
|
||||
; Force CCP to use system boot drive as initial default
|
||||
ld a,(@sysdr) ; get system boot drive
|
||||
ld (@ccpdr),a ; set CCP current drive
|
||||
|
||||
ret
|
||||
|
||||
no$CCP: ; here if we couldn't find the file
|
||||
ld hl,ccp$msg
|
||||
call ?pmsg
|
||||
call ?conin
|
||||
jp ?ldccp
|
||||
|
||||
|
||||
?rlccp:
|
||||
|
||||
if banked
|
||||
|
||||
; lxi h,0100h ! lxi b,0C00h ; clone 3K
|
||||
;rl$1:
|
||||
; mvi a,2 ! call ?bnksl ; select extra bank
|
||||
; mov a,m ! push psw ; get a byte
|
||||
; mvi a,tpa$bank ! call ?bnksl ; select TPA
|
||||
; pop psw ! mov m,a ; save the byte
|
||||
; inx h ! dcx b ; bump pointer, drop count
|
||||
; mov a,b ! ora c ; test for done
|
||||
; jnz rl$1
|
||||
; ret
|
||||
|
||||
ld hl,0100h ; clone 3K
|
||||
ld bc,0C80h
|
||||
rl$1:
|
||||
ld a,2 ; select extra bank
|
||||
call ?bnksl
|
||||
ld a,(hl) ; get a byte
|
||||
push af
|
||||
ld a,tpa$bank ; select TPA
|
||||
call ?bnksl
|
||||
pop af ; save the byte
|
||||
ld (hl),a
|
||||
inc hl ; bump pointer, drop count
|
||||
dec bc
|
||||
ld a,b ; test for done
|
||||
or c
|
||||
jr nz,rl$1
|
||||
ret
|
||||
|
||||
else
|
||||
|
||||
jr ?ldccp
|
||||
|
||||
endif
|
||||
|
||||
; No external clock.
|
||||
?time:
|
||||
ret
|
||||
|
||||
; CP/M BDOS Function Interfaces
|
||||
|
||||
open:
|
||||
ld c,15
|
||||
jp bdos
|
||||
|
||||
setdma:
|
||||
ld c,26
|
||||
jp bdos
|
||||
|
||||
setmulti:
|
||||
ld c,44
|
||||
jp bdos
|
||||
|
||||
read:
|
||||
ld c,20
|
||||
jp bdos
|
||||
|
||||
|
||||
signon$msg db 13,10,'CP/M v3.0'
|
||||
if banked
|
||||
db ' [BANKED]'
|
||||
endif
|
||||
db ', HBIOS v2.9.2',13,10,13,10,0
|
||||
|
||||
ccp$msg db 13,10,'BIOS Err on '
|
||||
ccp$msg$drv db '?'
|
||||
db ': No CCP.COM file',0
|
||||
|
||||
|
||||
ccp$fcb db 0,'CCP ','COM',0,0,0,0
|
||||
ds 16
|
||||
fcb$nr db 0,0,0
|
||||
|
||||
@bootdu db 0
|
||||
hdspv db 2 ; slices per volume for hard disks (must be >= 1)
|
||||
|
||||
end
|
||||
BIN
Source/CPM3/ccp.com
Normal file
BIN
Source/CPM3/ccp.com
Normal file
Binary file not shown.
193
Source/CPM3/chario.z80
Normal file
193
Source/CPM3/chario.z80
Normal file
@@ -0,0 +1,193 @@
|
||||
title 'Character I/O handler for z80 chip based system'
|
||||
|
||||
; Character I/O for the Modular CP/M 3 BIOS
|
||||
|
||||
public ?cinit,?ci,?co,?cist,?cost
|
||||
public @ctbl
|
||||
|
||||
; maclib Z80 ; define Z80 op codes
|
||||
; maclib ports ; define port addresses
|
||||
maclib modebaud.lib ; define mode bits and baud equates
|
||||
|
||||
max$devices equ 6
|
||||
|
||||
cseg
|
||||
|
||||
?cinit:
|
||||
ret
|
||||
; mov a,c ! cpi max$devices ! jz cent$init ; init parallel printer
|
||||
; rnc ; invalid device
|
||||
; mov l,c ! mvi h,0 ; make 16 bits from device number
|
||||
; push h ; save device in stack
|
||||
; dad h ! dad h ! dad h ; *8
|
||||
; lxi d,@ctbl+7 ! dad d ! mov l,m ; get baud rate
|
||||
; mov a,l ! cpi baud$600 ; see if baud > 300
|
||||
; mvi a,44h ! jnc hi$speed ; if >= 600, use *16 mode
|
||||
; mvi a,0C4h ; else, use *64 mode
|
||||
;hi$speed:
|
||||
; sta sio$reg$4
|
||||
; mvi h,0 ! lxi d,speed$table ! dad d ; point to counter entry
|
||||
; mov a,m ! sta speed ; get and save ctc count
|
||||
; pop h ; recover
|
||||
; lxi d,data$ports ! dad d ; point at SIO port address
|
||||
; mov a,m ! inr a ! sta sio$port ; get and save port
|
||||
; lxi d,baud$ports-data$ports ! dad d ; offset to baud rate port
|
||||
; mov a,m ! sta ctc$port ; get and save
|
||||
; lxi h,serial$init$tbl
|
||||
; jmp stream$out
|
||||
;
|
||||
;cent$init:
|
||||
; lxi h,pio$init$tbl
|
||||
;
|
||||
;stream$out:
|
||||
; mov a,m ! ora a ! rz
|
||||
; mov b,a ! inx h ! mov c,m ! inx h
|
||||
; outir
|
||||
; jmp stream$out
|
||||
|
||||
|
||||
?ci: ; character input
|
||||
ld bc,0000H ; unit 0, func 0 = CIN
|
||||
rst 08 ; do it
|
||||
ld a,e ; put char in A
|
||||
ret ; done
|
||||
|
||||
; mov a,b ! cpi 6 ! jnc null$input ; can't read from centronics
|
||||
;ci1:
|
||||
; call ?cist ! jz ci1 ; wait for character ready
|
||||
; dcr c ! inp a ; get data
|
||||
; ani 7Fh ; mask parity
|
||||
; ret
|
||||
;
|
||||
;null$input:
|
||||
; mvi a,1Ah ; return a ctl-Z for no device
|
||||
; ret
|
||||
|
||||
?cist: ; character input status
|
||||
ld bc,0200H ; unit 0, func 2 = IST
|
||||
rst 08 ; do it
|
||||
or a ; set flags
|
||||
ret z ; return w/ ZF set if no char ready
|
||||
or 0FFH ; else signal nothing ready
|
||||
ret ; done
|
||||
|
||||
; mov a,b ! cpi 6 ! jnc null$status ; can't read from centronics
|
||||
; mov l,b ! mvi h,0 ; make device number 16 bits
|
||||
; lxi d,data$ports ! dad d ; make pointer to port address
|
||||
; mov c,m ! inr c ; get SIO status port
|
||||
; inp a ; read from status port
|
||||
; ani 1 ; isolate RxRdy
|
||||
; rz ; return with zero
|
||||
; ori 0FFh
|
||||
; ret
|
||||
|
||||
;null$status:
|
||||
; xra a ! ret
|
||||
|
||||
?co: ; character output
|
||||
ld e,c ; char to E
|
||||
ld bc,0100H ; unit 0, func 1 = COUT
|
||||
rst 08 ; do it
|
||||
ret ; done
|
||||
|
||||
; mov a,b ! cpi 6 ! jz centronics$out
|
||||
; jnc null$output
|
||||
; mov a,c ! push psw ; save character from <C>
|
||||
; push b ; save device number
|
||||
;co$spin:
|
||||
; call ?cost ! jz co$spin ; wait for TxEmpty
|
||||
; pop h ! mov l,h ! mvi h,0 ; get device number in <HL>
|
||||
; lxi d,data$ports ! dad d ; make address of port address
|
||||
; mov c,m ; get port address
|
||||
; pop psw ! outp a ; send data
|
||||
;null$output:
|
||||
; ret
|
||||
;
|
||||
;centronics$out:
|
||||
; in p$centstat ! ani 20h ! jnz centronics$out
|
||||
; mov a,c ! out p$centdata ; give printer data
|
||||
; in p$centstat ! ori 1 ! out p$centstat ; set strobe
|
||||
; ani 7Eh ! out p$centstat ; clear strobe
|
||||
; ret
|
||||
|
||||
?cost: ; character output status
|
||||
ld bc,0300H ; unit 0, func 3 = OST
|
||||
rst 08 ; do it
|
||||
or a ; set flags
|
||||
ret z ; return w/ ZF set if not ready to send
|
||||
or 0FFH ; else signal nothing ready
|
||||
ret ; done
|
||||
|
||||
|
||||
; mov a,b ! cpi 6 ! jz cent$stat
|
||||
; jnc null$status
|
||||
; mov l,b ! mvi h,0
|
||||
; lxi d,data$ports ! dad d
|
||||
; mov c,m ! inr c
|
||||
; inp a ; get input status
|
||||
; ani 4 ! rz ; test transmitter empty
|
||||
; ori 0FFh ! ret ; return true if ready
|
||||
;
|
||||
;
|
||||
;cent$stat:
|
||||
; in p$centstat ! cma
|
||||
; ani 20h ! rz
|
||||
; ori 0FFh ! ret
|
||||
|
||||
;baud$ports: ; CTC ports by physical device number
|
||||
; db p$baud$con1,p$baud$lpt1,p$baud$con2,p$baud$con34
|
||||
; db p$baud$con34,p$baud$lpt2
|
||||
;
|
||||
;data$ports: ; serial base ports by physical device number
|
||||
; db p$crt$data,p$lpt$data,p$con2data,p$con3data
|
||||
; db p$con4data,p$lpt2data
|
||||
|
||||
|
||||
@ctbl db 'COM0 '
|
||||
db mb$in$out+mb$serial+baud$none
|
||||
db baud$none
|
||||
db 0
|
||||
|
||||
;@ctbl db 'CRT ' ; device 0, CRT port 0
|
||||
; db mb$in$out+mb$serial+mb$softbaud
|
||||
; db baud$9600
|
||||
; db 'LPT ' ; device 1, LPT port 0
|
||||
; db mb$in$out+mb$serial+mb$softbaud+mb$xonxoff
|
||||
; db baud$9600
|
||||
; db 'CRT1 ' ; device 2, CRT port 1
|
||||
; db mb$in$out+mb$serial+mb$softbaud
|
||||
; db baud$9600
|
||||
; db 'CRT2 ' ; device 3, CRT port 2
|
||||
; db mb$in$out+mb$serial+mb$softbaud
|
||||
; db baud$9600
|
||||
; db 'CRT3 ' ; device 4, CRT port 3
|
||||
; db mb$in$out+mb$serial+mb$softbaud
|
||||
; db baud$9600
|
||||
; db 'VAX ' ; device 5, LPT port 1 used for VAX interface
|
||||
; db mb$in$out+mb$serial+mb$softbaud
|
||||
; db baud$9600
|
||||
; db 'CEN ' ; device 6, Centronics parallel printer
|
||||
; db mb$output
|
||||
; db baud$none
|
||||
; db 0 ; table terminator
|
||||
|
||||
|
||||
;speed$table db 0,255,255,255,233,208,104,208,104,69,52,35,26,17,13,7
|
||||
;
|
||||
;serial$init$tbl
|
||||
; db 2 ; two bytes to CTC
|
||||
;ctc$port ds 1 ; port address of CTC
|
||||
; db 47h ; CTC mode byte
|
||||
;speed ds 1 ; baud multiplier
|
||||
; db 7 ; 7 bytes to SIO
|
||||
;sio$port ds 1 ; port address of SIO
|
||||
; db 18h,3,0E1h,4
|
||||
;sio$reg$4 ds 1
|
||||
; db 5,0EAh
|
||||
; db 0 ; terminator
|
||||
;
|
||||
;pio$init$tbl db 2,p$zpio$2b,0Fh,07h
|
||||
; db 3,p$zpio$2a,0CFh,0F8h,07h
|
||||
; db 0
|
||||
|
||||
end
|
||||
180
Source/CPM3/cpm3.lib
Normal file
180
Source/CPM3/cpm3.lib
Normal file
@@ -0,0 +1,180 @@
|
||||
; Macro Definitions for CP/M3 BIOS Data Structures.
|
||||
|
||||
; dtbl <dph0,dph1,...> - drive table
|
||||
|
||||
; dph translate$table, - disk parameter header
|
||||
; disk$parameter$block,
|
||||
; checksum$size, (optional)
|
||||
; alloc$size (optional)
|
||||
|
||||
; skew sectors, - skew table
|
||||
; skew$factor,
|
||||
; first$sector$number
|
||||
|
||||
; dpb physical$sector$size, - disk parameter block
|
||||
; physical$sectors$per$track,
|
||||
; number$tracks,
|
||||
; block$size,
|
||||
; number$dir$entries,
|
||||
; track$offset,
|
||||
; checksum$vec$size (optional)
|
||||
|
||||
|
||||
; Drive Table. Contains 16 one word entries.
|
||||
|
||||
dtbl macro ?list
|
||||
local ?n
|
||||
?n aset 0
|
||||
irp ?drv,<?list>
|
||||
?n aset ?n+1
|
||||
dw ?drv
|
||||
endm
|
||||
|
||||
if ?n > 16
|
||||
.' Too many drives. Max 16 allowed'
|
||||
exitm
|
||||
endif
|
||||
|
||||
if ?n < 16
|
||||
rept (16-?n)
|
||||
dw 0
|
||||
endm
|
||||
endif
|
||||
endm
|
||||
|
||||
dph macro ?trans,?dpb,?csize,?asize
|
||||
local ?csv,?alv
|
||||
dw ?trans ; translate table address
|
||||
db 0,0,0,0,0,0,0,0,0 ; BDOS Scratch area
|
||||
db 0 ; media flag
|
||||
dw ?dpb ; disk parameter block
|
||||
if not nul ?csize
|
||||
dw ?csv ; checksum vector
|
||||
else
|
||||
dw 0FFFEh ; checksum vector allocated by
|
||||
endif ; GENCPM
|
||||
if not nul ?asize
|
||||
dw ?alv ; allocation vector
|
||||
else
|
||||
dw 0FFFEh ; alloc vector allocated by GENCPM
|
||||
endif
|
||||
dw 0fffeh,0fffeh,0fffeh ; dirbcb, dtabcb, hash allocd
|
||||
; by GENCPM
|
||||
db 0 ; hash bank
|
||||
|
||||
if not nul ?csize
|
||||
?csv ds ?csize ; checksum vector
|
||||
endif
|
||||
if not nul ?asize
|
||||
?alv ds ?asize ; allocation vector
|
||||
endif
|
||||
|
||||
endm
|
||||
|
||||
dpb macro ?psize,?pspt,?trks,?bls,?ndirs,?off,?ncks
|
||||
local ?spt,?bsh,?blm,?exm,?dsm,?drm,?al0,?al1,?cks,?psh,?psm
|
||||
local ?n
|
||||
;; physical sector mask and physical sector shift
|
||||
?psh aset 0
|
||||
?n aset ?psize/128
|
||||
?psm aset ?n-1
|
||||
rept 8
|
||||
?n aset ?n/2
|
||||
if (?n = 0)
|
||||
exitm
|
||||
endif
|
||||
?psh aset ?psh + 1
|
||||
endm
|
||||
?spt aset ?pspt*(?psize/128)
|
||||
|
||||
?bsh aset 3
|
||||
?n aset ?bls/1024
|
||||
rept 8
|
||||
?n aset ?n/2
|
||||
if (?n = 0)
|
||||
exitm
|
||||
endif
|
||||
?bsh aset ?bsh + 1
|
||||
endm
|
||||
?blm aset ?bls/128-1
|
||||
?size aset (?trks-?off)*?spt
|
||||
?dsm aset ?size/(?bls/128)-1
|
||||
|
||||
?exm aset ?bls/1024
|
||||
if ?dsm > 255
|
||||
if ?bls = 1024
|
||||
.'Error, can''t have this size disk with 1k block size'
|
||||
exitm
|
||||
endif
|
||||
?exm aset ?exm/2
|
||||
endif
|
||||
?exm aset ?exm-1
|
||||
?all aset 0
|
||||
?n aset (?ndirs*32+?bls-1)/?bls
|
||||
rept ?n
|
||||
?all aset (?all shr 1) or 8000h
|
||||
endm
|
||||
?al0 aset high ?all
|
||||
?al1 aset low ?all
|
||||
?drm aset ?ndirs-1
|
||||
if not nul ?ncks
|
||||
?cks aset ?ncks
|
||||
else
|
||||
?cks aset ?ndirs/4
|
||||
endif
|
||||
dw ?spt ; 128 byte records per track
|
||||
db ?bsh,?blm ; block shift and mask
|
||||
db ?exm ; extent mask
|
||||
dw ?dsm ; maximum block number
|
||||
dw ?drm ; maximum directory entry number
|
||||
db ?al0,?al1 ; alloc vector for directory
|
||||
dw ?cks ; checksum size
|
||||
dw ?off ; offset for system tracks
|
||||
db ?psh,?psm ; physical sector size shift
|
||||
; and mask
|
||||
endm
|
||||
|
||||
;
|
||||
gcd macro ?m,?n
|
||||
;; greatest common divisor of m,n
|
||||
;; produces value gcdn as result
|
||||
;; (used in sector translate table generation)
|
||||
?gcdm aset ?m ;;variable for m
|
||||
?gcdn aset ?n ;;variable for n
|
||||
?gcdr aset 0 ;;variable for r
|
||||
rept 65535
|
||||
?gcdx aset ?gcdm/?gcdn
|
||||
?gcdr aset ?gcdm - ?gcdx*?gcdn
|
||||
if ?gcdr = 0
|
||||
exitm
|
||||
endif
|
||||
?gcdm aset ?gcdn
|
||||
?gcdn aset ?gcdr
|
||||
endm
|
||||
endm
|
||||
|
||||
skew macro ?secs,?skf,?fsc
|
||||
;; generate the translate table
|
||||
?nxtsec aset 0 ;;next sector to fill
|
||||
?nxtbas aset 0 ;;moves by one on overflow
|
||||
gcd %?secs,?skf
|
||||
;; ?gcdn = gcd(?secs,skew)
|
||||
?neltst aset ?secs/?gcdn
|
||||
;; neltst is number of elements to generate
|
||||
;; before we overlap previous elements
|
||||
?nelts aset ?neltst ;;counter
|
||||
rept ?secs ;;once for each sector
|
||||
db ?nxtsec+?fsc
|
||||
?nxtsec aset ?nxtsec+?skf
|
||||
if ?nxtsec >= ?secs
|
||||
?nxtsec aset ?nxtsec-?secs
|
||||
endif
|
||||
?nelts aset ?nelts-1
|
||||
if ?nelts = 0
|
||||
?nxtbas aset ?nxtbas+1
|
||||
?nxtsec aset ?nxtbas
|
||||
?nelts aset ?neltst
|
||||
endif
|
||||
endm
|
||||
endm
|
||||
|
||||
BIN
Source/CPM3/cpm3fix.pat
Normal file
BIN
Source/CPM3/cpm3fix.pat
Normal file
Binary file not shown.
1572
Source/CPM3/cpmldr.asm
Normal file
1572
Source/CPM3/cpmldr.asm
Normal file
File diff suppressed because it is too large
Load Diff
781
Source/CPM3/diskio.z80
Normal file
781
Source/CPM3/diskio.z80
Normal file
@@ -0,0 +1,781 @@
|
||||
title 'HBIOS disk handler'
|
||||
|
||||
; CP/M-80 Version 3 -- Modular BIOS
|
||||
|
||||
maclib options.lib
|
||||
|
||||
dseg
|
||||
|
||||
; Disk drive dispatching tables for linked BIOS
|
||||
|
||||
public dph0,dph1,dph2,dph3,dph4,dph5,dph6,dph7
|
||||
public dph8,dph9,dph10,dph11,dph12,dph13,dph14,dph15
|
||||
|
||||
; Linked BIOS variables
|
||||
|
||||
public @sysdr
|
||||
extrn @bootdu
|
||||
|
||||
; Variables containing parameters passed by BDOS
|
||||
|
||||
extrn @adrv,@rdrv
|
||||
extrn @dma,@trk,@sect
|
||||
extrn @dbnk
|
||||
|
||||
; System Control Block variables
|
||||
|
||||
extrn @ermde ; BDOS error mode
|
||||
|
||||
; Utility routines in standard BIOS
|
||||
|
||||
extrn ?wboot ; warm boot vector
|
||||
extrn ?pmsg ; print message @<HL> up to 00, saves <BC> & <DE>
|
||||
extrn ?pdec ; print binary number in <A> from 0 to 99.
|
||||
extrn ?pderr ; print BIOS disk error header
|
||||
extrn ?conin,?cono ; con in and out
|
||||
extrn ?const ; get console status
|
||||
|
||||
extrn ?bnkxlt
|
||||
|
||||
|
||||
; CP/M 3 Disk definition macros
|
||||
|
||||
maclib cpm3.lib
|
||||
|
||||
; common control characters
|
||||
|
||||
cr equ 13
|
||||
lf equ 10
|
||||
bell equ 7
|
||||
|
||||
|
||||
; Extended Disk Parameter Headers (XPDHs)
|
||||
|
||||
; All DPH entries below are generic. They are updated during
|
||||
; boot to point to available HBIOS disk unit/slices dynamically.
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph0: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph1: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph2: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph3: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph4: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph5: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph6: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph7: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph8: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph9: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph10: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph11: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph12: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph13: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph14: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
dw dsk$write
|
||||
dw dsk$read
|
||||
dw dsk$login
|
||||
dw dsk$init
|
||||
db 0,0 ; HBIOS Disk Unit/Slice (filled in at boot)
|
||||
dph15: dph 0,dpb$max ; Real DPB filled in at disk login
|
||||
|
||||
cseg ; DPB must be resident
|
||||
|
||||
dpb$max:
|
||||
dw 64 ; spt: sectors per track
|
||||
db 5 ; bsh: block shift factor
|
||||
db 31 ; blm: block mask
|
||||
db 1 ; exm: extent mask
|
||||
dw 2047 ; dsm: total storage in blocks - 1 = (8mb / 4k bls) - 1 = 2047
|
||||
dw 511 ; drm: dir entries - 1 = 512 - 1 = 511
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 64 ; cks: directory check vector size - 256 / 4
|
||||
dw 0 ; off: reserved tracks = 16 trks * (16 trks * 16 heads * 16 secs * 512 bytes) = 128k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb$start:
|
||||
dpb$rom: ; 384K ROM Drive
|
||||
dw 64 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 1 ; exm: extent mask
|
||||
dw 192 - 1 ; dsm: total storage in blocks - 1 = (384kb / 2k bls) - 1 = 191
|
||||
dw 256 - 1 ; drm: dir entries - 1 = 256 - 1 = 255
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
|
||||
dw 0 ; off: reserved tracks = 16 trks * (16 trks * 16 heads * 16 secs * 512 bytes) = 128k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
dpb$sz equ $ - dpb$start
|
||||
|
||||
dpb$ram: ; 256K RAM Drive
|
||||
dw 64 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 1 ; exm: extent mask
|
||||
dw 128 - 1 ; dsm: total storage in blocks - 1 = (256kb / 2k bls) - 1 = 127
|
||||
dw 256 - 1 ; drm: dir entries - 1 = 256 - 1 = 255
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
|
||||
dw 0 ; off: reserved tracks = 16 trks * (16 trks * 16 heads * 16 secs * 512 bytes) = 128k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb$rf: ; 4MB RAM Floppy Drive
|
||||
dw 64 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 0 ; exm: extent mask
|
||||
dw 2047 ; dsm: total storage in blocks - 1 = (4mb / 2k bls) - 1 = 2047
|
||||
dw 255 ; drm: dir entries - 1 = 256 - 1 = 255
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
|
||||
dw 0 ; off: reserved tracks = 0 trks
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb$hd: ; 8MB Hard Disk Drive
|
||||
dw 64 ; spt: sectors per track
|
||||
db 5 ; bsh: block shift factor
|
||||
db 31 ; blm: block mask
|
||||
db 1 ; exm: extent mask
|
||||
dw 2047 ; dsm: total storage in blocks - 1 = (8mb / 4k bls) - 1 = 2047
|
||||
dw 511 ; drm: dir entries - 1 = 512 - 1 = 511
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
|
||||
dw 16 ; off: reserved tracks = 16 trks * (16 trks * 16 heads * 16 secs * 512 bytes) = 128k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb$fd720: ; 3.5" DS/DD Floppy Drive (720K)
|
||||
dw 36 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 0 ; exm: extent mask
|
||||
dw 350 ; dsm: total storage in blocks - 1 blk = ((720k - 18k off) / 2k bls) - 1 = 350
|
||||
dw 127 ; drm: dir entries - 1 = 128 - 1 = 127
|
||||
db 11000000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 32 ; cks: directory check vector size = 128 / 4
|
||||
dw 4 ; off: reserved tracks = 4 trks * (512 b/sec * 36 sec/trk) = 18k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb_fd144: ; 3.5" DS/HD Floppy Drive (1.44M)
|
||||
dw 72 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 0 ; exm: extent mask
|
||||
dw 710 ; dsm: total storage in blocks - 1 blk = ((1,440k - 18k off) / 2k bls) - 1 = 710
|
||||
dw 255 ; drm: dir entries - 1 = 256 - 1 = 255
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 64 ; cks: directory check vector size = 256 / 4
|
||||
dw 2 ; off: reserved tracks = 2 trks * (512 b/sec * 72 sec/trk) = 18k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb_fd360: ; 5.25" DS/DD Floppy Drive (360K)
|
||||
dw 36 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 1 ; exm: extent mask
|
||||
dw 170 ; dsm: total storage in blocks - 1 blk = ((360k - 18k off) / 2k bls) - 1 = 170
|
||||
dw 127 ; drm: dir entries - 1 = 128 - 1 = 127
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 32 ; cks: directory check vector size = 128 / 4
|
||||
dw 4 ; off: reserved tracks = 4 trks * (512 b/sec * 36 sec/trk) = 18k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb_fd120: ; 5.25" DS/HD Floppy Drive (1.2M)
|
||||
dw 60 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 0 ; exm: extent mask
|
||||
dw 591 ; dsm: total storage in blocks - 1 blk = ((1,200k - 15k off) / 2k bls) - 1 = 591
|
||||
dw 255 ; drm: dir entries - 1 = 256 - 1 = 255
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 64 ; cks: directory check vector size = 256 / 4
|
||||
dw 2 ; off: reserved tracks = 2 trks * (512 b/sec * 60 sec/trk) = 15k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dpb_fd111: ; 8" DS/DD Floppy Drive (1.11M)
|
||||
dw 60 ; spt: sectors per track
|
||||
db 4 ; bsh: block shift factor
|
||||
db 15 ; blm: block mask
|
||||
db 0 ; exm: extent mask
|
||||
dw 569 ; dsm: total storage in blocks - 1 blk = ((1,155k - 15k off) / 2k bls) - 1 = 569
|
||||
dw 255 ; drm: dir entries - 1 = 256 - 1 = 255
|
||||
db 11110000b ; al0: dir blk bit map, first byte
|
||||
db 00000000b ; al1: dir blk bit map, second byte
|
||||
dw 64 ; cks: directory check vector size = 256 / 4
|
||||
dw 2 ; off: reserved tracks = 2 trks * (512 b/sec * 60 sec/trk) = 15k
|
||||
db 2 ; psh: 2 for 512 byte sectors
|
||||
db 3 ; phm: (512 / 128) - 1
|
||||
|
||||
dseg ; rest is banked
|
||||
|
||||
|
||||
|
||||
; Disk I/O routines for standardized BIOS interface
|
||||
|
||||
; Initialization entry point.
|
||||
|
||||
; called for first time initialization.
|
||||
|
||||
dsk$init:
|
||||
inc de ; point to slice in XDPH
|
||||
inc de
|
||||
inc de
|
||||
ld a,(de) ; get slice
|
||||
or a ; set flags
|
||||
ret nz ; done if not zero
|
||||
|
||||
ld a,(@rdrv) ; unit being initialized
|
||||
ld hl,@bootdu
|
||||
cp (hl)
|
||||
ret nz ; done if no match
|
||||
|
||||
ld a,(@adrv) ; get cp/m drive
|
||||
ld (@sysdr),a ; and save it
|
||||
ret
|
||||
|
||||
; lxi h,init$table
|
||||
;fd$init$next:
|
||||
; mov a,m ! ora a ! rz
|
||||
; mov b,a ! inx h ! mov c,m ! inx h
|
||||
; outir
|
||||
; jmp fd$init$next
|
||||
;
|
||||
;fd$init1: ; all initialization done by drive 0
|
||||
; ret
|
||||
|
||||
;init$table db 4,p$zpio$1A
|
||||
; db 11001111b, 11000010b, 00010111b,11111111b
|
||||
; db 4,p$zpio$1B
|
||||
; db 11001111b, 11011101b, 00010111b,11111111b
|
||||
; db 0
|
||||
|
||||
|
||||
dsk$login:
|
||||
; This entry is called when a logical drive is about to
|
||||
; be logged into for the purpose of density determination.
|
||||
|
||||
; It may adjust the parameters contained in the disk
|
||||
; parameter header pointed at by <DE>
|
||||
|
||||
;ret ; we have nothing to do in
|
||||
; simple single density only environment.
|
||||
|
||||
|
||||
push de ; save DPH ptr
|
||||
|
||||
; check media
|
||||
ld a,(@rdrv) ; get disk unit
|
||||
;halt
|
||||
ld c,a ; put in C
|
||||
ld b,18h ; HBIOS Media function
|
||||
ld e,1 ; Enabled media check/discovery
|
||||
call 0FFF0H ; HBIOS call
|
||||
ld a,e ; Resultant media id to accum
|
||||
or a ; Set flags
|
||||
;halt
|
||||
;
|
||||
; !!! Need to do something on error !!!
|
||||
;
|
||||
ret z ; Bail out on error
|
||||
|
||||
ld hl,dpb$start - dpb$sz
|
||||
ld de,dpb$sz
|
||||
ld b,a ; loop count
|
||||
dsk$login1:
|
||||
add hl,de ; next dpb
|
||||
djnz dsk$login1 ; loop as needed
|
||||
|
||||
; hl is ptr to desired dpb
|
||||
pop de ; restore DPH ptr
|
||||
;halt
|
||||
ex de,hl ; de = DPB adr, hl = DPH adr
|
||||
push de ; save DPB adr
|
||||
ld de,12 ; offset of DPB in DPH
|
||||
add hl,de ; hl = adr of DPB field in DPH
|
||||
pop de ; recover DPB adr
|
||||
ld (hl),e ; update LSB
|
||||
inc hl
|
||||
ld (hl),d ; udpate MSB
|
||||
ret ; done
|
||||
|
||||
|
||||
; disk READ and WRITE entry points.
|
||||
|
||||
; these entries are called with the following arguments:
|
||||
|
||||
; relative drive number in @rdrv (8 bits)
|
||||
; absolute drive number in @adrv (8 bits)
|
||||
; disk transfer address in @dma (16 bits)
|
||||
; disk transfer bank in @dbnk (8 bits)
|
||||
; disk track address in @trk (16 bits)
|
||||
; disk sector address in @sect (16 bits)
|
||||
; pointer to XDPH in <DE>
|
||||
|
||||
; they transfer the appropriate data, perform retries
|
||||
; if necessary, then return an error code in <A>
|
||||
|
||||
dsk$read:
|
||||
; ld ix,30H
|
||||
; halt
|
||||
|
||||
push de ; save XDPH pointer
|
||||
call dsk$seek ; disk seek
|
||||
pop hl ; restore pointer to HL
|
||||
ret nz ; abort on seek error
|
||||
;
|
||||
dec hl ; point to unit field of XDPH
|
||||
dec hl
|
||||
ld c,(hl) ; BIOS Disk Unit in C
|
||||
ld b,13H ; HBIOS READ function
|
||||
ld hl,(@dma) ; Dest buffer adr
|
||||
if banked
|
||||
ld a,(@dbnk) ; destination bank
|
||||
call ?bnkxlt
|
||||
else
|
||||
ld a,(0FFE0H) ; get current bank
|
||||
endif
|
||||
ld d,a ; set desk bank
|
||||
ld e,1 ; 1 sector
|
||||
;rst 08 ; do it
|
||||
call 0FFF0H
|
||||
ret ; return
|
||||
|
||||
; lxi h,read$msg ; point at " Read "
|
||||
; mvi a,88h ! mvi b,01h ; 1797 read + Z80DMA direction
|
||||
; jmp rw$common
|
||||
|
||||
dsk$write:
|
||||
;ld ix,32H
|
||||
;halt
|
||||
|
||||
push de ; save XDPH pointer
|
||||
call dsk$seek ; disk seek
|
||||
pop hl ; restore pointer to XDPH
|
||||
ret nz ; abort on seek error
|
||||
;
|
||||
dec hl ; point to unit field of XDPH
|
||||
dec hl
|
||||
ld c,(hl) ; BIOS Disk Unit in C
|
||||
ld b,14H ; HBIOS WRITE function
|
||||
ld hl,(@dma) ; Dest buffer adr
|
||||
if banked
|
||||
ld a,(@dbnk) ; destination bank
|
||||
call ?bnkxlt
|
||||
else
|
||||
ld a,(0FFE0H) ; get current bank
|
||||
endif
|
||||
ld d,a ; set desk bank
|
||||
ld e,1 ; 1 sector
|
||||
;rst 08 ; do it
|
||||
call 0FFF0H
|
||||
ret ; return
|
||||
|
||||
; lxi h,write$msg ; point at " Write "
|
||||
; mvi a,0A8h ! mvi b,05h ; 1797 write + Z80DMA direction
|
||||
; ; jmp wr$common
|
||||
|
||||
dsk$seek:
|
||||
dec de ; point to unit field of XDPH
|
||||
dec de
|
||||
ld a,(de) ; get it
|
||||
ld c,a ; BIOS Disk Unit in C
|
||||
ld b,12H ; HBIOS SEEK function
|
||||
push bc ; save it
|
||||
|
||||
inc de ; point to slice field of XDPH
|
||||
ld a,(de) ; get it
|
||||
ld e,a ; slice to E
|
||||
ld h,65 ; number of tracks per slice
|
||||
call mult8 ; HL now has track offset for slice
|
||||
push hl ; save it for now
|
||||
|
||||
ld hl,(@trk) ; get track value
|
||||
ld a,l ; lsb of track to a
|
||||
and 0FH ; isolate head in low 4 bits
|
||||
ld d,a ; stuff it in d
|
||||
ld a,(@sect) ; get sector
|
||||
ld e,a ; stuff it in e
|
||||
ld b,4 ; prepare to shift out 4 bit head value
|
||||
seek1:
|
||||
srl h ; shift one bit out
|
||||
rr l ; ... of hl
|
||||
djnz seek1 ; do all 4 bits
|
||||
|
||||
ex de,hl ; de=track, hl=head/sect
|
||||
ex (sp),hl ; save head/sect, hl = offset
|
||||
add hl,de ; hl has final track value
|
||||
pop de ; recover head/sect to de
|
||||
|
||||
pop bc ; recover function & unit
|
||||
;rst 08 ; perform seek
|
||||
call 0FFF0H
|
||||
ret
|
||||
|
||||
;
|
||||
; multiply 8-bit values
|
||||
; in: multiply h by e
|
||||
; out: hl = result, e = 0, b = 0
|
||||
;
|
||||
mult8:
|
||||
ld d,0
|
||||
ld l,d
|
||||
ld b,8
|
||||
mult8_loop:
|
||||
add hl,hl
|
||||
jr nc,mult8_noadd
|
||||
add hl,de
|
||||
mult8_noadd:
|
||||
djnz mult8_loop
|
||||
ret
|
||||
|
||||
;rw$common: ; seek to correct track (if necessary),
|
||||
; ; initialize DMA controller,
|
||||
; ; and issue 1797 command.
|
||||
;
|
||||
; shld operation$name ; save message for errors
|
||||
; sta disk$command ; save 1797 command
|
||||
; mov a,b ! sta zdma$direction ; save Z80DMA direction code
|
||||
; lhld @dma ! shld zdma$dma ; get and save DMA address
|
||||
; lda @rdrv ! mov l,a ! mvi h,0 ; get controller-relative disk drive
|
||||
; lxi d,select$table ! dad d ; point to select mask for drive
|
||||
; mov a,m ! sta select$mask ; get select mask and save it
|
||||
; out p$select ; select drive
|
||||
;more$retries:
|
||||
; mvi c,10 ; allow 10 retries
|
||||
;retry$operation:
|
||||
; push b ; save retry counter
|
||||
;
|
||||
; lda select$mask ! lxi h,old$select ! cmp m
|
||||
; mov m,a
|
||||
; jnz new$track ; if not same drive as last, seek
|
||||
;
|
||||
; lda @trk ! lxi h,old$track ! cmp m
|
||||
; mov m,a
|
||||
; jnz new$track ; if not same track, then seek
|
||||
;
|
||||
; in p$fdmisc ! ani 2 ! jnz same$track ; head still loaded, we are OK
|
||||
;
|
||||
;new$track: ; or drive or unloaded head means we should . . .
|
||||
; call check$seek ; . . read address and seek if wrong track
|
||||
;
|
||||
; lxi b,16667 ; 100 ms / (24 t states*250 ns)
|
||||
;spin$loop: ; wait for head/seek settling
|
||||
; dcx b
|
||||
; mov a,b ! ora c
|
||||
; jnz spin$loop
|
||||
;
|
||||
;same$track:
|
||||
; lda @trk ! out p$fdtrack ; give 1797 track
|
||||
; lda @sect ! out p$fdsector ; and sector
|
||||
;
|
||||
; lxi h,dma$block ; point to dma command block
|
||||
; lxi b,dmab$length*256 + p$zdma ; command block length and port address
|
||||
; outir ; send commands to Z80 DMA
|
||||
;
|
||||
; in p$bankselect ; get old value of bank select port
|
||||
; ani 3Fh ! mov b,a ; mask off DMA bank and save
|
||||
; lda @dbnk ! rrc ! rrc ; get DMA bank to 2 hi-order bits
|
||||
; ani 0C0h ! ora b ; merge with other bank stuff
|
||||
; out p$bankselect ; and select the correct DMA bank
|
||||
;
|
||||
; lda disk$command ; get 1797 command
|
||||
; call exec$command ; start it then wait for IREQ and read status
|
||||
; sta disk$status ; save status for error messages
|
||||
;
|
||||
; pop b ; recover retry counter
|
||||
; ora a ! rz ; check status and return to BDOS if no error
|
||||
;
|
||||
; ani 0001$0000b ; see if record not found error
|
||||
; cnz check$seek ; if a record not found, we might need to seek
|
||||
;
|
||||
; dcr c ! jnz retry$operation
|
||||
;
|
||||
; ; suppress error message if BDOS is returning errors to application...
|
||||
;
|
||||
; lda @ermde ! cpi 0FFh ! jz hard$error
|
||||
;
|
||||
; ; Had permanent error, print message like:
|
||||
;
|
||||
; ; BIOS Err on d: T-nn, S-mm, <operation> <type>, Retry ?
|
||||
;
|
||||
; call ?pderr ; print message header
|
||||
;
|
||||
; lhld operation$name ! call ?pmsg ; last function
|
||||
;
|
||||
; ; then, messages for all indicated error bits
|
||||
;
|
||||
; lda disk$status ; get status byte from last error
|
||||
; lxi h,error$table ; point at table of message addresses
|
||||
;errm1:
|
||||
; mov e,m ! inx h ! mov d,m ! inx h ; get next message address
|
||||
; add a ! push psw ; shift left and push residual bits with status
|
||||
; xchg ! cc ?pmsg ! xchg ; print message, saving table pointer
|
||||
; pop psw ! jnz errm1 ; if any more bits left, continue
|
||||
;
|
||||
; lxi h,error$msg ! call ?pmsg ; print "<BEL>, Retry (Y/N) ? "
|
||||
; call u$conin$echo ; get operator response
|
||||
; cpi 'Y' ! jz more$retries ; Yes, then retry 10 more times
|
||||
;hard$error: ; otherwise,
|
||||
; mvi a,1 ! ret ; return hard error to BDOS
|
||||
;
|
||||
;cancel: ; here to abort job
|
||||
; jmp ?wboot ; leap directly to warmstart vector
|
||||
;
|
||||
;
|
||||
; ; subroutine to seek if on wrong track
|
||||
; ; called both to set up new track or drive
|
||||
;
|
||||
;check$seek:
|
||||
; push b ; save error counter
|
||||
; call read$id ; try to read ID, put track in <B>
|
||||
; jz id$ok ; if OK, we're OK
|
||||
; call step$out ; else step towards Trk 0
|
||||
; call read$id ; and try again
|
||||
; jz id$ok ; if OK, we're OK
|
||||
; call restore ; else, restore the drive
|
||||
; mvi b,0 ; and make like we are at track 0
|
||||
;id$ok:
|
||||
; mov a,b ! out p$fdtrack ; send current track to track port
|
||||
; lda @trk ! cmp b ! pop b ! rz ; if its desired track, we are done
|
||||
; out p$fddata ; else, desired track to data port
|
||||
; mvi a,00011010b ; seek w/ 10 ms. steps
|
||||
; jmp exec$command
|
||||
;
|
||||
;
|
||||
;
|
||||
;step$out:
|
||||
; mvi a,01101010b ; step out once at 10 ms.
|
||||
; jmp exec$command
|
||||
;
|
||||
;restore:
|
||||
; mvi a,00001011b ; restore at 15 ms
|
||||
; ; jmp exec$command
|
||||
;
|
||||
;
|
||||
;exec$command: ; issue 1797 command, and wait for IREQ
|
||||
; ; return status
|
||||
; out p$fdcmnd ; send 1797 command
|
||||
;wait$IREQ: ; spin til IREQ
|
||||
; in p$fdint ! ani 40h ! jz wait$IREQ
|
||||
; in p$fdstat ; get 1797 status and clear IREQ
|
||||
; ret
|
||||
;
|
||||
;read$id:
|
||||
; lxi h,read$id$block ; set up DMA controller
|
||||
; lxi b,length$id$dmab*256 + p$zdma ; for READ ADDRESS operation
|
||||
; outir
|
||||
; mvi a,11000100b ; issue 1797 read address command
|
||||
; call exec$command ; wait for IREQ and read status
|
||||
; ani 10011101b ; mask status
|
||||
; lxi h,id$buffer ! mov b,m ; get actual track number in <B>
|
||||
; ret ; and return with Z flag true for OK
|
||||
;
|
||||
;
|
||||
;u$conin$echo: ; get console input, echo it, and shift to upper case
|
||||
; call ?const ! ora a ! jz u$c1 ; see if any char already struck
|
||||
; call ?conin ! jmp u$conin$echo ; yes, eat it and try again
|
||||
;u$c1:
|
||||
; call ?conin ! push psw
|
||||
; mov c,a ! call ?cono
|
||||
; pop psw ! cpi 'a' ! rc
|
||||
; sui 'a'-'A' ; make upper case
|
||||
; ret
|
||||
;
|
||||
;
|
||||
;disk$command ds 1 ; current wd1797 command
|
||||
;select$mask ds 1 ; current drive select code
|
||||
;old$select ds 1 ; last drive selected
|
||||
;old$track ds 1 ; last track seeked to
|
||||
;
|
||||
;disk$status ds 1 ; last error status code for messages
|
||||
;
|
||||
;select$table db 0001$0000b,0010$0000b ; for now use drives C and D
|
||||
;
|
||||
;
|
||||
; ; error message components
|
||||
;
|
||||
;read$msg db ', Read',0
|
||||
;write$msg db ', Write',0
|
||||
;
|
||||
;operation$name dw read$msg
|
||||
;
|
||||
; ; table of pointers to error message strings
|
||||
; ; first entry is for bit 7 of 1797 status byte
|
||||
;
|
||||
;error$table dw b7$msg
|
||||
; dw b6$msg
|
||||
; dw b5$msg
|
||||
; dw b4$msg
|
||||
; dw b3$msg
|
||||
; dw b2$msg
|
||||
; dw b1$msg
|
||||
; dw b0$msg
|
||||
;
|
||||
;b7$msg db ' Not ready,',0
|
||||
;b6$msg db ' Protect,',0
|
||||
;b5$msg db ' Fault,',0
|
||||
;b4$msg db ' Record not found,',0
|
||||
;b3$msg db ' CRC,',0
|
||||
;b2$msg db ' Lost data,',0
|
||||
;b1$msg db ' DREQ,',0
|
||||
;b0$msg db ' Busy,',0
|
||||
;
|
||||
;error$msg db ' Retry (Y/N) ? ',0
|
||||
;
|
||||
;
|
||||
;
|
||||
; ; command string for Z80DMA device for normal operation
|
||||
;
|
||||
;dma$block db 0C3h ; reset DMA channel
|
||||
; db 14h ; channel A is incrementing memory
|
||||
; db 28h ; channel B is fixed port address
|
||||
; db 8Ah ; RDY is high, CE/ only, stop on EOB
|
||||
; db 79h ; program all of ch. A, xfer B->A (temp)
|
||||
;zdma$dma ds 2 ; starting DMA address
|
||||
; dw 128-1 ; 128 byte sectors in SD
|
||||
; db 85h ; xfer byte at a time, ch B is 8 bit address
|
||||
; db p$fddata ; ch B port address (1797 data port)
|
||||
; db 0CFh ; load B as source register
|
||||
; db 05h ; xfer A->B
|
||||
; db 0CFh ; load A as source register
|
||||
;zdma$direction ds 1 ; either A->B or B->A
|
||||
; db 0CFh ; load final source register
|
||||
; db 87h ; enable DMA channel
|
||||
;dmab$length equ $-dma$block
|
||||
|
||||
|
||||
|
||||
;read$id$block db 0C3h ; reset DMA channel
|
||||
; db 14h ; channel A is incrementing memory
|
||||
; db 28h ; channel B is fixed port address
|
||||
; db 8Ah ; RDY is high, CE/ only, stop on EOB
|
||||
; db 7Dh ; program all of ch. A, xfer A->B (temp)
|
||||
; dw id$buffer ; starting DMA address
|
||||
; dw 6-1 ; Read ID always xfers 6 bytes
|
||||
; db 85h ; byte xfer, ch B is 8 bit address
|
||||
; db p$fddata ; ch B port address (1797 data port)
|
||||
; db 0CFh ; load dest (currently source) register
|
||||
; db 01h ; xfer B->A
|
||||
; db 0CFh ; load source register
|
||||
; db 87h ; enable DMA channel
|
||||
;length$id$dmab equ $-read$id$block
|
||||
|
||||
cseg ; easier to put ID buffer in common
|
||||
|
||||
;id$buffer ds 6 ; buffer to hold ID field
|
||||
; ; track
|
||||
; ; side
|
||||
; ; sector
|
||||
; ; length
|
||||
; ; CRC 1
|
||||
; ; CRC 2
|
||||
|
||||
cseg
|
||||
|
||||
@sysdr db 0 ; system boot drive
|
||||
|
||||
end
|
||||
12
Source/CPM3/drvtbl.z80
Normal file
12
Source/CPM3/drvtbl.z80
Normal file
@@ -0,0 +1,12 @@
|
||||
public @dtbl
|
||||
extrn dph0,dph1,dph2,dph3,dph4,dph5,dph6,dph7
|
||||
extrn dph8,dph9,dph10,dph11,dph12,dph13,dph14,dph15
|
||||
|
||||
maclib cpm3.lib
|
||||
|
||||
cseg
|
||||
|
||||
@dtbl dw dph0,dph1,dph2,dph3,dph4,dph5,dph6,dph7
|
||||
dw dph8,dph9,dph10,dph11,dph12,dph13,dph14,dph15
|
||||
|
||||
end
|
||||
158
Source/CPM3/genbnk.dat
Normal file
158
Source/CPM3/genbnk.dat
Normal file
@@ -0,0 +1,158 @@
|
||||
PRTMSG = Y
|
||||
PAGWID = 4F
|
||||
PAGLEN = 17
|
||||
BACKSPC = N
|
||||
RUBOUT = N
|
||||
BOOTDRV = C
|
||||
MEMTOP = FD
|
||||
BNKSWT = Y
|
||||
COMBAS = 80
|
||||
LERROR = Y
|
||||
NUMSEGS = 02
|
||||
MEMSEG00 = 01,43,00
|
||||
MEMSEG01 = 0E,72,02
|
||||
MEMSEG02 = 01,7F,03
|
||||
MEMSEG03 = 01,7F,04
|
||||
MEMSEG04 = 00,C0,05
|
||||
MEMSEG05 = 00,C0,06
|
||||
MEMSEG06 = 00,C0,07
|
||||
MEMSEG07 = 00,C0,08
|
||||
MEMSEG08 = 00,C0,09
|
||||
MEMSEG09 = 00,C0,0A
|
||||
MEMSEG0A = 00,C0,0B
|
||||
MEMSEG0B = 00,C0,0C
|
||||
MEMSEG0C = 00,C0,0D
|
||||
MEMSEG0D = 00,C0,0E
|
||||
MEMSEG0E = 00,C0,0F
|
||||
MEMSEG0F = 00,C0,10
|
||||
HASHDRVA = Y
|
||||
HASHDRVB = Y
|
||||
HASHDRVC = Y
|
||||
HASHDRVD = Y
|
||||
HASHDRVE = Y
|
||||
HASHDRVF = Y
|
||||
HASHDRVG = Y
|
||||
HASHDRVH = Y
|
||||
HASHDRVI = Y
|
||||
HASHDRVJ = Y
|
||||
HASHDRVK = Y
|
||||
HASHDRVL = Y
|
||||
HASHDRVM = Y
|
||||
HASHDRVN = Y
|
||||
HASHDRVO = Y
|
||||
HASHDRVP = Y
|
||||
ALTBNKSA = Y
|
||||
ALTBNKSB = Y
|
||||
ALTBNKSC = Y
|
||||
ALTBNKSD = Y
|
||||
ALTBNKSE = Y
|
||||
ALTBNKSF = Y
|
||||
ALTBNKSG = Y
|
||||
ALTBNKSH = Y
|
||||
ALTBNKSI = Y
|
||||
ALTBNKSJ = Y
|
||||
ALTBNKSK = Y
|
||||
ALTBNKSL = Y
|
||||
ALTBNKSM = Y
|
||||
ALTBNKSN = Y
|
||||
ALTBNKSO = Y
|
||||
ALTBNKSP = Y
|
||||
NDIRRECA = 02
|
||||
NDIRRECB = 00
|
||||
NDIRRECC = 00
|
||||
NDIRRECD = 00
|
||||
NDIRRECE = 00
|
||||
NDIRRECF = 00
|
||||
NDIRRECG = 00
|
||||
NDIRRECH = 00
|
||||
NDIRRECI = 00
|
||||
NDIRRECJ = 00
|
||||
NDIRRECK = 00
|
||||
NDIRRECL = 00
|
||||
NDIRRECM = 00
|
||||
NDIRRECN = 00
|
||||
NDIRRECO = 00
|
||||
NDIRRECP = 00
|
||||
NDTARECA = 02
|
||||
NDTARECB = 00
|
||||
NDTARECC = 00
|
||||
NDTARECD = 00
|
||||
NDTARECE = 00
|
||||
NDTARECF = 00
|
||||
NDTARECG = 00
|
||||
NDTARECH = 00
|
||||
NDTARECI = 00
|
||||
NDTARECJ = 00
|
||||
NDTARECK = 00
|
||||
NDTARECL = 00
|
||||
NDTARECM = 00
|
||||
NDTARECN = 00
|
||||
NDTARECO = 00
|
||||
NDTARECP = 00
|
||||
ODIRDRVA = A
|
||||
ODIRDRVB = A
|
||||
ODIRDRVC = A
|
||||
ODIRDRVD = A
|
||||
ODIRDRVE = A
|
||||
ODIRDRVF = A
|
||||
ODIRDRVG = A
|
||||
ODIRDRVH = A
|
||||
ODIRDRVI = A
|
||||
ODIRDRVJ = A
|
||||
ODIRDRVK = A
|
||||
ODIRDRVL = A
|
||||
ODIRDRVM = A
|
||||
ODIRDRVN = A
|
||||
ODIRDRVO = A
|
||||
ODIRDRVP = A
|
||||
ODTADRVA = A
|
||||
ODTADRVB = A
|
||||
ODTADRVC = A
|
||||
ODTADRVD = A
|
||||
ODTADRVE = A
|
||||
ODTADRVF = A
|
||||
ODTADRVG = A
|
||||
ODTADRVH = A
|
||||
ODTADRVI = A
|
||||
ODTADRVJ = A
|
||||
ODTADRVK = A
|
||||
ODTADRVL = A
|
||||
ODTADRVM = A
|
||||
ODTADRVN = A
|
||||
ODTADRVO = A
|
||||
ODTADRVP = A
|
||||
OVLYDIRA = Y
|
||||
OVLYDIRB = Y
|
||||
OVLYDIRC = Y
|
||||
OVLYDIRD = Y
|
||||
OVLYDIRE = Y
|
||||
OVLYDIRF = Y
|
||||
OVLYDIRG = Y
|
||||
OVLYDIRH = Y
|
||||
OVLYDIRI = Y
|
||||
OVLYDIRJ = Y
|
||||
OVLYDIRK = Y
|
||||
OVLYDIRL = Y
|
||||
OVLYDIRM = Y
|
||||
OVLYDIRN = Y
|
||||
OVLYDIRO = Y
|
||||
OVLYDIRP = Y
|
||||
OVLYDTAA = Y
|
||||
OVLYDTAB = Y
|
||||
OVLYDTAC = Y
|
||||
OVLYDTAD = Y
|
||||
OVLYDTAE = Y
|
||||
OVLYDTAF = Y
|
||||
OVLYDTAG = Y
|
||||
OVLYDTAH = Y
|
||||
OVLYDTAI = Y
|
||||
OVLYDTAJ = Y
|
||||
OVLYDTAK = Y
|
||||
OVLYDTAL = Y
|
||||
OVLYDTAM = Y
|
||||
OVLYDTAN = Y
|
||||
OVLYDTAO = Y
|
||||
OVLYDTAP = Y
|
||||
CRDATAF = N
|
||||
DBLALV = Y
|
||||
|
||||
BIN
Source/CPM3/gencpm.com
Normal file
BIN
Source/CPM3/gencpm.com
Normal file
Binary file not shown.
158
Source/CPM3/genres.dat
Normal file
158
Source/CPM3/genres.dat
Normal file
@@ -0,0 +1,158 @@
|
||||
PRTMSG = Y
|
||||
PAGWID = 4F
|
||||
PAGLEN = 17
|
||||
BACKSPC = N
|
||||
RUBOUT = N
|
||||
BOOTDRV = C
|
||||
MEMTOP = FD
|
||||
BNKSWT = N
|
||||
COMBAS = 00
|
||||
LERROR = Y
|
||||
NUMSEGS = 03
|
||||
MEMSEG00 = 00,80,00
|
||||
MEMSEG01 = 00,C0,02
|
||||
MEMSEG02 = 00,C0,03
|
||||
MEMSEG03 = 00,C0,04
|
||||
MEMSEG04 = 00,C0,05
|
||||
MEMSEG05 = 00,C0,06
|
||||
MEMSEG06 = 00,C0,07
|
||||
MEMSEG07 = 00,C0,08
|
||||
MEMSEG08 = 00,C0,09
|
||||
MEMSEG09 = 00,C0,0A
|
||||
MEMSEG0A = 00,C0,0B
|
||||
MEMSEG0B = 00,C0,0C
|
||||
MEMSEG0C = 00,C0,0D
|
||||
MEMSEG0D = 00,C0,0E
|
||||
MEMSEG0E = 00,C0,0F
|
||||
MEMSEG0F = 00,C0,10
|
||||
HASHDRVA = N
|
||||
HASHDRVB = N
|
||||
HASHDRVC = N
|
||||
HASHDRVD = N
|
||||
HASHDRVE = N
|
||||
HASHDRVF = N
|
||||
HASHDRVG = N
|
||||
HASHDRVH = N
|
||||
HASHDRVI = N
|
||||
HASHDRVJ = N
|
||||
HASHDRVK = N
|
||||
HASHDRVL = N
|
||||
HASHDRVM = N
|
||||
HASHDRVN = N
|
||||
HASHDRVO = N
|
||||
HASHDRVP = N
|
||||
ALTBNKSA = N
|
||||
ALTBNKSB = N
|
||||
ALTBNKSC = N
|
||||
ALTBNKSD = N
|
||||
ALTBNKSE = N
|
||||
ALTBNKSF = N
|
||||
ALTBNKSG = N
|
||||
ALTBNKSH = N
|
||||
ALTBNKSI = N
|
||||
ALTBNKSJ = N
|
||||
ALTBNKSK = N
|
||||
ALTBNKSL = N
|
||||
ALTBNKSM = N
|
||||
ALTBNKSN = N
|
||||
ALTBNKSO = N
|
||||
ALTBNKSP = N
|
||||
NDIRRECA = 01
|
||||
NDIRRECB = 00
|
||||
NDIRRECC = 00
|
||||
NDIRRECD = 00
|
||||
NDIRRECE = 00
|
||||
NDIRRECF = 00
|
||||
NDIRRECG = 00
|
||||
NDIRRECH = 00
|
||||
NDIRRECI = 00
|
||||
NDIRRECJ = 00
|
||||
NDIRRECK = 00
|
||||
NDIRRECL = 00
|
||||
NDIRRECM = 00
|
||||
NDIRRECN = 00
|
||||
NDIRRECO = 00
|
||||
NDIRRECP = 00
|
||||
NDTARECA = 01
|
||||
NDTARECB = 00
|
||||
NDTARECC = 00
|
||||
NDTARECD = 00
|
||||
NDTARECE = 00
|
||||
NDTARECF = 00
|
||||
NDTARECG = 00
|
||||
NDTARECH = 00
|
||||
NDTARECI = 00
|
||||
NDTARECJ = 00
|
||||
NDTARECK = 00
|
||||
NDTARECL = 00
|
||||
NDTARECM = 00
|
||||
NDTARECN = 00
|
||||
NDTARECO = 00
|
||||
NDTARECP = 00
|
||||
ODIRDRVA = A
|
||||
ODIRDRVB = A
|
||||
ODIRDRVC = A
|
||||
ODIRDRVD = A
|
||||
ODIRDRVE = A
|
||||
ODIRDRVF = A
|
||||
ODIRDRVG = A
|
||||
ODIRDRVH = A
|
||||
ODIRDRVI = A
|
||||
ODIRDRVJ = A
|
||||
ODIRDRVK = A
|
||||
ODIRDRVL = A
|
||||
ODIRDRVM = A
|
||||
ODIRDRVN = A
|
||||
ODIRDRVO = A
|
||||
ODIRDRVP = A
|
||||
ODTADRVA = A
|
||||
ODTADRVB = A
|
||||
ODTADRVC = A
|
||||
ODTADRVD = A
|
||||
ODTADRVE = A
|
||||
ODTADRVF = A
|
||||
ODTADRVG = A
|
||||
ODTADRVH = A
|
||||
ODTADRVI = A
|
||||
ODTADRVJ = A
|
||||
ODTADRVK = A
|
||||
ODTADRVL = A
|
||||
ODTADRVM = A
|
||||
ODTADRVN = A
|
||||
ODTADRVO = A
|
||||
ODTADRVP = A
|
||||
OVLYDIRA = Y
|
||||
OVLYDIRB = Y
|
||||
OVLYDIRC = Y
|
||||
OVLYDIRD = Y
|
||||
OVLYDIRE = Y
|
||||
OVLYDIRF = Y
|
||||
OVLYDIRG = Y
|
||||
OVLYDIRH = Y
|
||||
OVLYDIRI = Y
|
||||
OVLYDIRJ = Y
|
||||
OVLYDIRK = Y
|
||||
OVLYDIRL = Y
|
||||
OVLYDIRM = Y
|
||||
OVLYDIRN = Y
|
||||
OVLYDIRO = Y
|
||||
OVLYDIRP = Y
|
||||
OVLYDTAA = Y
|
||||
OVLYDTAB = Y
|
||||
OVLYDTAC = Y
|
||||
OVLYDTAD = Y
|
||||
OVLYDTAE = Y
|
||||
OVLYDTAF = Y
|
||||
OVLYDTAG = Y
|
||||
OVLYDTAH = Y
|
||||
OVLYDTAI = Y
|
||||
OVLYDTAJ = Y
|
||||
OVLYDTAK = Y
|
||||
OVLYDTAL = Y
|
||||
OVLYDTAM = Y
|
||||
OVLYDTAN = Y
|
||||
OVLYDTAO = Y
|
||||
OVLYDTAP = Y
|
||||
CRDATAF = N
|
||||
DBLALV = N
|
||||
|
||||
158
Source/CPM3/genres.old
Normal file
158
Source/CPM3/genres.old
Normal file
@@ -0,0 +1,158 @@
|
||||
PRTMSG = Y
|
||||
PAGWID = 4F
|
||||
PAGLEN = 17
|
||||
BACKSPC = N
|
||||
RUBOUT = N
|
||||
BOOTDRV = A
|
||||
MEMTOP = FD
|
||||
BNKSWT = N
|
||||
COMBAS = 00
|
||||
LERROR = Y
|
||||
NUMSEGS = 03
|
||||
MEMSEG00 = 00,80,00
|
||||
MEMSEG01 = 00,C0,02
|
||||
MEMSEG02 = 00,C0,03
|
||||
MEMSEG03 = 00,C0,04
|
||||
MEMSEG04 = 00,C0,05
|
||||
MEMSEG05 = 00,C0,06
|
||||
MEMSEG06 = 00,C0,07
|
||||
MEMSEG07 = 00,C0,08
|
||||
MEMSEG08 = 00,C0,09
|
||||
MEMSEG09 = 00,C0,0A
|
||||
MEMSEG0A = 00,C0,0B
|
||||
MEMSEG0B = 00,C0,0C
|
||||
MEMSEG0C = 00,C0,0D
|
||||
MEMSEG0D = 00,C0,0E
|
||||
MEMSEG0E = 00,C0,0F
|
||||
MEMSEG0F = 00,C0,10
|
||||
HASHDRVA = N
|
||||
HASHDRVB = Y
|
||||
HASHDRVC = Y
|
||||
HASHDRVD = Y
|
||||
HASHDRVE = Y
|
||||
HASHDRVF = Y
|
||||
HASHDRVG = Y
|
||||
HASHDRVH = Y
|
||||
HASHDRVI = Y
|
||||
HASHDRVJ = Y
|
||||
HASHDRVK = Y
|
||||
HASHDRVL = Y
|
||||
HASHDRVM = Y
|
||||
HASHDRVN = Y
|
||||
HASHDRVO = Y
|
||||
HASHDRVP = Y
|
||||
ALTBNKSA = N
|
||||
ALTBNKSB = N
|
||||
ALTBNKSC = N
|
||||
ALTBNKSD = N
|
||||
ALTBNKSE = N
|
||||
ALTBNKSF = N
|
||||
ALTBNKSG = N
|
||||
ALTBNKSH = N
|
||||
ALTBNKSI = N
|
||||
ALTBNKSJ = N
|
||||
ALTBNKSK = N
|
||||
ALTBNKSL = N
|
||||
ALTBNKSM = N
|
||||
ALTBNKSN = N
|
||||
ALTBNKSO = N
|
||||
ALTBNKSP = N
|
||||
NDIRRECA = 01
|
||||
NDIRRECB = 01
|
||||
NDIRRECC = 01
|
||||
NDIRRECD = 01
|
||||
NDIRRECE = 01
|
||||
NDIRRECF = 01
|
||||
NDIRRECG = 01
|
||||
NDIRRECH = 01
|
||||
NDIRRECI = 01
|
||||
NDIRRECJ = 01
|
||||
NDIRRECK = 01
|
||||
NDIRRECL = 01
|
||||
NDIRRECM = 01
|
||||
NDIRRECN = 01
|
||||
NDIRRECO = 01
|
||||
NDIRRECP = 01
|
||||
NDTARECA = 01
|
||||
NDTARECB = 01
|
||||
NDTARECC = 01
|
||||
NDTARECD = 01
|
||||
NDTARECE = 01
|
||||
NDTARECF = 01
|
||||
NDTARECG = 01
|
||||
NDTARECH = 01
|
||||
NDTARECI = 01
|
||||
NDTARECJ = 01
|
||||
NDTARECK = 01
|
||||
NDTARECL = 01
|
||||
NDTARECM = 01
|
||||
NDTARECN = 01
|
||||
NDTARECO = 01
|
||||
NDTARECP = 01
|
||||
ODIRDRVA = A
|
||||
ODIRDRVB = A
|
||||
ODIRDRVC = A
|
||||
ODIRDRVD = A
|
||||
ODIRDRVE = A
|
||||
ODIRDRVF = A
|
||||
ODIRDRVG = A
|
||||
ODIRDRVH = A
|
||||
ODIRDRVI = A
|
||||
ODIRDRVJ = A
|
||||
ODIRDRVK = A
|
||||
ODIRDRVL = A
|
||||
ODIRDRVM = A
|
||||
ODIRDRVN = A
|
||||
ODIRDRVO = A
|
||||
ODIRDRVP = A
|
||||
ODTADRVA = A
|
||||
ODTADRVB = A
|
||||
ODTADRVC = A
|
||||
ODTADRVD = A
|
||||
ODTADRVE = A
|
||||
ODTADRVF = A
|
||||
ODTADRVG = A
|
||||
ODTADRVH = A
|
||||
ODTADRVI = A
|
||||
ODTADRVJ = A
|
||||
ODTADRVK = A
|
||||
ODTADRVL = A
|
||||
ODTADRVM = A
|
||||
ODTADRVN = A
|
||||
ODTADRVO = A
|
||||
ODTADRVP = A
|
||||
OVLYDIRA = Y
|
||||
OVLYDIRB = Y
|
||||
OVLYDIRC = Y
|
||||
OVLYDIRD = Y
|
||||
OVLYDIRE = Y
|
||||
OVLYDIRF = Y
|
||||
OVLYDIRG = Y
|
||||
OVLYDIRH = Y
|
||||
OVLYDIRI = Y
|
||||
OVLYDIRJ = Y
|
||||
OVLYDIRK = Y
|
||||
OVLYDIRL = Y
|
||||
OVLYDIRM = Y
|
||||
OVLYDIRN = Y
|
||||
OVLYDIRO = Y
|
||||
OVLYDIRP = Y
|
||||
OVLYDTAA = Y
|
||||
OVLYDTAB = Y
|
||||
OVLYDTAC = Y
|
||||
OVLYDTAD = Y
|
||||
OVLYDTAE = Y
|
||||
OVLYDTAF = Y
|
||||
OVLYDTAG = Y
|
||||
OVLYDTAH = Y
|
||||
OVLYDTAI = Y
|
||||
OVLYDTAJ = Y
|
||||
OVLYDTAK = Y
|
||||
OVLYDTAL = Y
|
||||
OVLYDTAM = Y
|
||||
OVLYDTAN = Y
|
||||
OVLYDTAO = Y
|
||||
OVLYDTAP = Y
|
||||
CRDATAF = N
|
||||
DBLALV = N
|
||||
|
||||
16
Source/CPM3/makedate.lib
Normal file
16
Source/CPM3/makedate.lib
Normal file
@@ -0,0 +1,16 @@
|
||||
;
|
||||
; [JCE] Have the date and copyright messages in only one source file
|
||||
;
|
||||
@BDATE MACRO
|
||||
db '101198'
|
||||
ENDM
|
||||
|
||||
@LCOPY MACRO
|
||||
db 'Copyright 1998, '
|
||||
db 'Caldera, Inc. '
|
||||
ENDM
|
||||
|
||||
@SCOPY MACRO
|
||||
db '(c) 98 Caldera'
|
||||
ENDM
|
||||
|
||||
32
Source/CPM3/modebaud.lib
Normal file
32
Source/CPM3/modebaud.lib
Normal file
@@ -0,0 +1,32 @@
|
||||
; equates for mode byte bit fields
|
||||
;
|
||||
mb$input equ 00000001b ; device may do input
|
||||
mb$output equ 00000010b ; device may do output
|
||||
mb$in$out equ mb$input+mb$output
|
||||
;
|
||||
mb$soft$baud equ 00000100b ; software selectable
|
||||
; baud rates
|
||||
;
|
||||
mb$serial equ 00001000b ; device may use protocol
|
||||
mb$xonxoff equ 00010000b ; XON/XOFF protocol
|
||||
; enabled
|
||||
;
|
||||
baud$none equ 0 ; no baud rate associated
|
||||
; with this device
|
||||
baud$50 equ 1 ; 50 baud
|
||||
baud$75 equ 2 ; 75 baud
|
||||
baud$110 equ 3 ; 110 baud
|
||||
baud$134 equ 4 ; 134.5 baud
|
||||
baud$150 equ 5 ; 150 baud
|
||||
baud$300 equ 6 ; 300 baud
|
||||
baud$600 equ 7 ; 600 baud
|
||||
baud$1200 equ 8 ; 1200 baud
|
||||
baud$1800 equ 9 ; 1800 baud
|
||||
baud$2400 equ 10 ; 2400 baud
|
||||
baud$3600 equ 11 ; 3600 baud
|
||||
baud$4800 equ 12 ; 4800 baud
|
||||
baud$7200 equ 13 ; 7200 baud
|
||||
baud$9600 equ 14 ; 9600 baud
|
||||
baud$19200 equ 15 ; 19.2k baud
|
||||
;
|
||||
; end of file
|
||||
116
Source/CPM3/move.z80
Normal file
116
Source/CPM3/move.z80
Normal file
@@ -0,0 +1,116 @@
|
||||
title 'bank & move module for CP/M3 linked BIOS'
|
||||
|
||||
cseg
|
||||
|
||||
public ?move,?xmove,?bank,?bnkxlt
|
||||
public ?mvinit,@hbbio,@hbusr
|
||||
extrn @cbnk
|
||||
|
||||
?mvinit:
|
||||
ld bc,0F8F2H ; HBIOS GET BNKINFO
|
||||
;rst 08 ; D: BIOS Bank, E: User Bank
|
||||
call 0FFF0H
|
||||
ld a,d
|
||||
ld (@hbbio),a
|
||||
ld a,e
|
||||
ld (@hbusr),a
|
||||
ret
|
||||
|
||||
?xmove:
|
||||
ld (movbnk),bc ; save source & dest banks
|
||||
or 0FFH ; flag interbank move type
|
||||
ld (movtyp),a ; save it
|
||||
ret
|
||||
|
||||
?move:
|
||||
ld a,(movtyp) ; get move type flag
|
||||
or a ; set flags
|
||||
jr nz,xbnkmov ; if so, go to interbank move
|
||||
|
||||
; Intrabank move
|
||||
ex de,hl ; we are passed source in DE and dest in HL
|
||||
ldir ; use Z80 block move instruction
|
||||
ex de,hl ; need next addresses in same regs
|
||||
ret
|
||||
|
||||
xbnkmov:
|
||||
;ld ix,8888H
|
||||
;halt
|
||||
; Interbank move
|
||||
xor a ; zero
|
||||
ld (movtyp),a ; clear move type flag
|
||||
push de
|
||||
push hl
|
||||
push bc
|
||||
pop hl
|
||||
ld a,(srcbnk)
|
||||
call ?bnkxlt
|
||||
ld e,a
|
||||
ld a,(dstbnk)
|
||||
call ?bnkxlt
|
||||
ld d,a
|
||||
ld b,0F4H ; SETCPY
|
||||
;rst 08
|
||||
call 0FFF0H
|
||||
pop hl
|
||||
pop de
|
||||
ex de,hl ; swap address regs for call
|
||||
ld b,0F5H ; BNKCPY
|
||||
;rst 08
|
||||
call 0FFF0H
|
||||
ex de,hl ; next addresses in same regs
|
||||
;ld ix,9999H
|
||||
;halt
|
||||
ret
|
||||
|
||||
?bank:
|
||||
call ?bnkxlt ; xlat to HBIOS bank id
|
||||
jp 0FFF3H ; do it and return
|
||||
|
||||
;
|
||||
; Convert from CPM3 bank id to HBIOS bank id.
|
||||
; CPM3 wants TPA for it's bank 0, so that is special
|
||||
; case mapping to HBIOS BID_USR (8EH). Otherwise, we index
|
||||
; down below BID_HBIOS (8DH). So CPM3 bank usage grows
|
||||
; downward.
|
||||
;
|
||||
; CPM3 HBIOS
|
||||
; ------------- -------------------
|
||||
; COMMON 8FH - BID_COM
|
||||
; 0 - OS/BUFS 8EH - BID_USR
|
||||
; 8DH - BID_BIOS
|
||||
; 1 - TPA 8CH - BID_AUX
|
||||
; 2 - BUFS 8BH - BID_AUX-1
|
||||
; 3 - BUFS 8AH - BID_AUX-2
|
||||
; ...
|
||||
;
|
||||
; N.B., Below BID_AUX is considered RAM disk bank. Need to
|
||||
; make sure RAM disk is kept small enough to stay below
|
||||
; banks used for OS buffers.
|
||||
;
|
||||
?bnkxlt:
|
||||
;ld ix,5555H
|
||||
;halt
|
||||
;cp 2
|
||||
;jr c,xxx
|
||||
;ld ix,6666H
|
||||
;halt
|
||||
;xxx:
|
||||
or a
|
||||
jr z,bank0
|
||||
neg ; 2 -> -2
|
||||
add a,08DH ; 8DH - 2 = 8BH
|
||||
@hbbio equ $ - 1 ; BID_BIOS
|
||||
ret
|
||||
bank0:
|
||||
ld a,08EH ; 0 -> 8EH
|
||||
@hbusr equ $ - 1 ; BID_USR
|
||||
ret
|
||||
|
||||
movtyp db 0 ; non-zero for interbank move
|
||||
|
||||
movbnk:
|
||||
srcbnk db 0
|
||||
dstbnk db 0
|
||||
|
||||
end
|
||||
6
Source/CPM3/optbnk.lib
Normal file
6
Source/CPM3/optbnk.lib
Normal file
@@ -0,0 +1,6 @@
|
||||
; global assembler options for BANKED BIOS
|
||||
|
||||
true equ -1
|
||||
false equ not true
|
||||
|
||||
banked equ true
|
||||
6
Source/CPM3/optres.lib
Normal file
6
Source/CPM3/optres.lib
Normal file
@@ -0,0 +1,6 @@
|
||||
; global assembler options for NONBANKED BIOS
|
||||
|
||||
true equ -1
|
||||
false equ not true
|
||||
|
||||
banked equ false
|
||||
39
Source/CPM3/readme.1st
Normal file
39
Source/CPM3/readme.1st
Normal file
@@ -0,0 +1,39 @@
|
||||
CP/M 3
|
||||
======
|
||||
|
||||
This archive contains an almost complete build of CP/M 3.
|
||||
|
||||
If you have the source distribution, the file MAKING.DOC explains how to
|
||||
set up the build environment on your computer.
|
||||
|
||||
Differences from Digital Research CP/M 3
|
||||
========================================
|
||||
|
||||
All the CP/M 3 patches described in the document CPM3FIX.PAT have been
|
||||
applied to the source code, except those to INITDIR. Patches 1-18 (except
|
||||
nos. 5 and 9) were applied.
|
||||
|
||||
CP/M 3 is now fully Year 2000 compliant. This affects the programs
|
||||
DATE.COM, DIR.COM and SHOW.COM.
|
||||
|
||||
Dates can be displayed in US, UK or Year-Month-Day format. This is set by
|
||||
SETDEF:
|
||||
|
||||
SETDEF [US]
|
||||
SETDEF [UK]
|
||||
SETDEF [YMD] respectively.
|
||||
|
||||
The CCP has a further bug fix: A command sequence such as:
|
||||
|
||||
C1
|
||||
:C2
|
||||
:C3
|
||||
|
||||
will now not execute the command C3 if the command C1 failed.
|
||||
|
||||
What's missing?
|
||||
===============
|
||||
INITDIR.COM - because it is written in PL/I and I can't make the
|
||||
PL/I compiler at <http://cdl.uta.edu/cpm> compile it.
|
||||
Apparently a more recent version of the compiler is
|
||||
required.
|
||||
BIN
Source/CPM3/resbdos3.spr
Normal file
BIN
Source/CPM3/resbdos3.spr
Normal file
Binary file not shown.
50
Source/CPM3/scb.asm
Normal file
50
Source/CPM3/scb.asm
Normal file
@@ -0,0 +1,50 @@
|
||||
title 'System Control Block Definition for CP/M3 BIOS'
|
||||
|
||||
public @civec, @covec, @aivec, @aovec, @lovec, @bnkbf
|
||||
public @crdma, @crdsk, @vinfo, @resel, @fx, @usrcd
|
||||
public @mltio, @ermde, @erdsk, @media, @bflgs
|
||||
public @date, @hour, @min, @sec, ?erjmp, @mxtpa
|
||||
public @ccpdr
|
||||
|
||||
|
||||
scb$base equ 0FE00H ; Base of the SCB
|
||||
|
||||
@CCPDR equ scb$base+13h ; CCP Current Drive
|
||||
@CIVEC equ scb$base+22h ; Console Input Redirection
|
||||
; Vector (word, r/w)
|
||||
@COVEC equ scb$base+24h ; Console Output Redirection
|
||||
; Vector (word, r/w)
|
||||
@AIVEC equ scb$base+26h ; Auxiliary Input Redirection
|
||||
; Vector (word, r/w)
|
||||
@AOVEC equ scb$base+28h ; Auxiliary Output Redirection
|
||||
; Vector (word, r/w)
|
||||
@LOVEC equ scb$base+2Ah ; List Output Redirection
|
||||
; Vector (word, r/w)
|
||||
@BNKBF equ scb$base+35h ; Address of 128 Byte Buffer
|
||||
; for Banked BIOS (word, r/o)
|
||||
@CRDMA equ scb$base+3Ch ; Current DMA Address
|
||||
; (word, r/o)
|
||||
@CRDSK equ scb$base+3Eh ; Current Disk (byte, r/o)
|
||||
@VINFO equ scb$base+3Fh ; BDOS Variable "INFO"
|
||||
; (word, r/o)
|
||||
@RESEL equ scb$base+41h ; FCB Flag (byte, r/o)
|
||||
@FX equ scb$base+43h ; BDOS Function for Error
|
||||
; Messages (byte, r/o)
|
||||
@USRCD equ scb$base+44h ; Current User Code (byte, r/o)
|
||||
@MLTIO equ scb$base+4Ah ; Current Multi-Sector Count
|
||||
; (byte,r/w)
|
||||
@ERMDE equ scb$base+4Bh ; BDOS Error Mode (byte, r/o)
|
||||
@ERDSK equ scb$base+51h ; BDOS Error Disk (byte,r/o)
|
||||
@MEDIA equ scb$base+54h ; Set by BIOS to indicate
|
||||
; open door (byte,r/w)
|
||||
@BFLGS equ scb$base+57h ; BDOS Message Size Flag (byte,r/o)
|
||||
@DATE equ scb$base+58h ; Date in Days Since 1 Jan 78
|
||||
; (word, r/w)
|
||||
@HOUR equ scb$base+5Ah ; Hour in BCD (byte, r/w)
|
||||
@MIN equ scb$base+5Bh ; Minute in BCD (byte, r/w)
|
||||
@SEC equ scb$base+5Ch ; Second in BCD (byte, r/w)
|
||||
?ERJMP equ scb$base+5Fh ; BDOS Error Message Jump
|
||||
; (word, r/w)
|
||||
@MXTPA equ scb$base+62h ; Top of User TPA
|
||||
; (address at 6,7)(word, r/o)
|
||||
end
|
||||
BIN
Source/CPM3/zpmldr.com
Normal file
BIN
Source/CPM3/zpmldr.com
Normal file
Binary file not shown.
@@ -7,6 +7,8 @@ setlocal & cd ZCPR && call Clean.cmd & endlocal
|
||||
setlocal & cd ZCPR-DJ && call Clean.cmd & endlocal
|
||||
setlocal & cd ZSDOS && call Clean.cmd & endlocal
|
||||
setlocal & cd CBIOS && call Clean.cmd & endlocal
|
||||
setlocal & cd CPM3 && call Clean.cmd & endlocal
|
||||
setlocal & cd ZPM3 && call Clean.cmd & endlocal
|
||||
setlocal & cd Forth && call Clean.cmd & endlocal
|
||||
setlocal & cd BPBIOS && call Clean.cmd & endlocal
|
||||
setlocal & cd HBIOS && call Clean.cmd & endlocal
|
||||
|
||||
@@ -828,7 +828,7 @@ COUT:
|
||||
LD E,A ; OUTPUT CHAR TO E
|
||||
LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C
|
||||
LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR
|
||||
RST 08 ; HBIOS OUTPUTS CHARACTDR
|
||||
RST 08 ; HBIOS OUTPUTS CHARACTER
|
||||
;
|
||||
; RESTORE ALL REGISTERS
|
||||
POP HL
|
||||
@@ -851,7 +851,7 @@ CIN:
|
||||
; INPUT CHARACTER FROM CONSOLE VIA HBIOS
|
||||
LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C
|
||||
LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR
|
||||
RST 08 ; HBIOS READS CHARACTDR
|
||||
RST 08 ; HBIOS READS CHARACTER
|
||||
LD A,E ; MOVE CHARACTER TO A FOR RETURN
|
||||
;
|
||||
; RESTORE REGISTERS (AF IS OUTPUT)
|
||||
|
||||
@@ -512,45 +512,24 @@ HBX_STACK .EQU $
|
||||
;
|
||||
; HBIOS INTERRUPT SLOT ASSIGNMENTS
|
||||
;
|
||||
; # SBC ZETA N8,MK4,RCZ180
|
||||
; --- -------------- -------------- --------------
|
||||
; 0 CTC0A Z180/INT1
|
||||
; 1 CTC0B Z180/INT2
|
||||
; 2 CTC0C Z180/TIM0
|
||||
; 3 CTC0D Z180/TIM1
|
||||
; 4 Z180/DMA0
|
||||
; 5 Z180/DMA1
|
||||
; 6 Z180/CSIO
|
||||
; 7 SIO0A/B Z180/SER0
|
||||
; 8 SIO1A/B Z180/SER1
|
||||
; 9 PIO0A PIO0A
|
||||
; 10 PIO0B PIO0B
|
||||
; 11 PIO1A PIO1A
|
||||
; 12 PIO1B PIO1B
|
||||
; 13
|
||||
; 14
|
||||
; 15
|
||||
; 16
|
||||
;
|
||||
; # RCZ80 EZZ80 ZETA2
|
||||
; --- -------------- ------------- --------------
|
||||
; 0 CTC0A CTC0A/SIO0CLK CTC0A/PRESCL
|
||||
; 1 CTC0B CTC0B/SIO1CLK CTC0B/TIMER
|
||||
; 2 CTC0C CTC0C/PRESCL CTC0C/UART
|
||||
; 3 CTC0D CTC0D/TIMER CTC0D/FDC
|
||||
; 4
|
||||
; 5
|
||||
; 6
|
||||
; 7 SIO0A/B SIO0A/B
|
||||
; 8 SIO1A/B SIO1A/B
|
||||
; # Z80 Z180
|
||||
; --- -------------- --------------
|
||||
; 0 CTC0A INT1 -+
|
||||
; 1 CTC0B INT2 |
|
||||
; 2 CTC0C TIM0 |
|
||||
; 3 CTC0D TIM1 |
|
||||
; 4 DMA0 +- Z180 INTERNAL
|
||||
; 5 DMA1 |
|
||||
; 6 CSIO |
|
||||
; 7 SIO0 SER0 |
|
||||
; 8 SIO1 SER1 -+
|
||||
; 9 PIO0A PIO0A
|
||||
; 10 PIO0B PIO0B
|
||||
; 11 PIO1A PIO1A
|
||||
; 12 PIO1B PIO1B
|
||||
; 13
|
||||
; 14
|
||||
; 13 SIO0
|
||||
; 14 SIO1
|
||||
; 15
|
||||
; 16
|
||||
;
|
||||
HBX_IVT:
|
||||
.DW HBX_IV00
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
#DEFINE RMN 9
|
||||
#DEFINE RUP 2
|
||||
#DEFINE RTP 0
|
||||
#DEFINE BIOSVER "2.9.2-pre.17"
|
||||
#DEFINE BIOSVER "2.9.2-pre.18"
|
||||
|
||||
BIN
Source/ZCCP/ccp.com
Normal file
BIN
Source/ZCCP/ccp.com
Normal file
Binary file not shown.
BIN
Source/ZCCP/diskinfo.com
Normal file
BIN
Source/ZCCP/diskinfo.com
Normal file
Binary file not shown.
BIN
Source/ZCCP/loadseg.com
Normal file
BIN
Source/ZCCP/loadseg.com
Normal file
Binary file not shown.
103
Source/ZCCP/read.me
Normal file
103
Source/ZCCP/read.me
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
|
||||
|
||||
|
||||
Z C C P by Simeon Cran
|
||||
=======================
|
||||
|
||||
|
||||
February 1993.
|
||||
ZCCP has been improved slightly from the original release. It
|
||||
should run much the same as before however modifications have
|
||||
been made in an attempt to allow it to work successfully from
|
||||
systems which boot from other than the A: drive. Also, the
|
||||
terminal dimensions are now automatically taken from the SCB (as
|
||||
set up by GENCPM). Special thanks go to Randy Winchester who is
|
||||
sharing his easy to follow instructions about ZCCP. Read ZCCP.TXT
|
||||
in this package for the expert help.
|
||||
|
||||
|
||||
|
||||
|
||||
ZCCP Quick Instructions
|
||||
=======================
|
||||
|
||||
ZCCP is a direct replacement for the CP/M 3.0 CCP. It requires
|
||||
ZPM3 and provides a ZCPR compatible system. There are some minor
|
||||
incompatibilities with ZCPR however the advantages of ZCCP more
|
||||
than outweigh these.
|
||||
|
||||
You must replace your current CCP with the ZCCP.COM. How you do
|
||||
this will depend on the setup of your computer so no details are
|
||||
given here.
|
||||
|
||||
When ZCCP starts, it reads ZINSTAL.ZPM (which must be on the
|
||||
default boot drive (usually A:) in user area 0). This file can
|
||||
be patched to set initial values for MHZ (speed of the computer),
|
||||
MAXU (maximum user number) and MAXD (highest disk drive). These
|
||||
values are set near the start of the ZINSTAL.ZPM file and there
|
||||
are ASCII pointers to them (which can be seen with a debugger
|
||||
such as SID.COM).
|
||||
|
||||
After ZINSTAL.ZPM has been read, ZCCP attempts to run the command
|
||||
STARTZPM.COM. This is usually an "alias" containing a number of
|
||||
commands used to put the system into a useful state. Typically
|
||||
STARTZPM.COM would contain commands to load a TCAP and named
|
||||
directory file, to set the path, and to set an error handler.
|
||||
|
||||
LOADSEG.COM is a ZCCP utility used to load RSXes, TCAPs and Named
|
||||
Directory files. It contains some online help.
|
||||
|
||||
RSXDIR.COM is a ZCPR utility which displays RSXes in memory. It
|
||||
has been included to help you understand how LOADSEG places
|
||||
various segments in high memory.
|
||||
|
||||
DISKINFO.COM is a ZCPR utility which gives information about your
|
||||
disks. It has been included for your interest.
|
||||
|
||||
Note that ZCCP has very few resident commands. If you are
|
||||
switching from a standard CP/M 3.0 CCP you will find that you are
|
||||
unable to perform certain simple functions (such as directory
|
||||
displays!). You should therefore obtain replacements for the CCP
|
||||
resident commands before installing ZCCP. The Z-Node bulletin
|
||||
boards in Australia and the USA are a good source. Note that ZCCP
|
||||
will not load Type-4 ZCPR programs.
|
||||
|
||||
If you are familiar with ZCPR systems you should have little
|
||||
trouble in getting the most from ZCCP. If you are new to ZCPR, I
|
||||
suggest that you learn as much as you can. ZCPR is a complex and
|
||||
powerful system which does very little without proper setup.
|
||||
|
||||
RCP's and IOP's are not implemented (which saves TPA space) and
|
||||
FCP's are not implemented although flow control is. To use flow
|
||||
control you must have an IF.COM program to handle IF commands.
|
||||
ZCCP handles the standard flow control commands internally (XIF,
|
||||
FI, ELSE, AND, OR). There are two other internal commands
|
||||
implemented: NOTE (a do-nothing command) and CLS (to clear the
|
||||
screen).
|
||||
|
||||
|
||||
The ZCCP package presented here may be freely distributed and
|
||||
used for your own private use. No commercial or institutional use
|
||||
is allowed without prior written agreement.
|
||||
|
||||
|
||||
The ZCCP package is copyright 1992,1993 by Simeon Cran, Brisbane,
|
||||
Australia.
|
||||
|
||||
|
||||
The Z-Node 62 BBS in Perth, Western Australia may be contacted
|
||||
from Australia on 09 450 0200 or from overseas on +619 4500200.
|
||||
Z-Node 62 also is a distribution point for ZPM3 and MYZ80. MYZ80
|
||||
is a high performance Z80 emulator for IBM AT (and better)
|
||||
computers. MYZ80 is able to run ZPM3.
|
||||
|
||||
|
||||
No support for ZCCP is being offered at this stage. Use at your
|
||||
own risk.
|
||||
|
||||
|
||||
Simeon Cran.
|
||||
February 1993.
|
||||
|
||||
|
||||
BIN
Source/ZCCP/rsxdir.com
Normal file
BIN
Source/ZCCP/rsxdir.com
Normal file
Binary file not shown.
BIN
Source/ZCCP/startzpm.com
Normal file
BIN
Source/ZCCP/startzpm.com
Normal file
Binary file not shown.
308
Source/ZCCP/zccp.txt
Normal file
308
Source/ZCCP/zccp.txt
Normal file
@@ -0,0 +1,308 @@
|
||||
The following is used by permission and remains copyright Randy Winchester.
|
||||
===========================================================================
|
||||
|
||||
ZCCP Documentation, Version 1.0
|
||||
by Randy Winchester <randy@mit.edu>
|
||||
|
||||
ZCCP Features
|
||||
|
||||
This documentation is provided to assist the user in getting a
|
||||
ZCCP system up and running. It is not an exhaustive course on Z-
|
||||
System or ZCPR. The following list details which ZCPR features
|
||||
are provided with ZCCP, and which ones aren't.
|
||||
|
||||
* ZCPR 3.3 compatibility. ZCCP can run a wide range of utilities
|
||||
an applications created for ZCPR 3.3 and ZCPR 3.4.
|
||||
|
||||
* TCAP. A Z3T termcap file describing terminal characteristics
|
||||
can be loaded into the system. Z-System programs make use of the
|
||||
TCAP for output to the screen - a big improvement over the old
|
||||
method of patching individual programs with terminal control
|
||||
codes. TCAP files are loaded by the ZCCP LOADSEG command.
|
||||
|
||||
* Named directories. Up to 12 user areas can be assigned names.
|
||||
Named Directory Registers (*.NDR files) are loaded by the ZCCP
|
||||
LOADSEG command.
|
||||
|
||||
* Command Search Path. ZCCP will search for commands along a
|
||||
user defined search path. Up to six path elements
|
||||
(directories) can be defined.
|
||||
|
||||
* Environment block. Contains TCAP, Named Directory, and Path
|
||||
information. Also includes a map of active disk drives and
|
||||
other system information. The environment block can be viewed
|
||||
with the Z-System SHOW utility.
|
||||
|
||||
* Flow control. Conditional processing for batch files. Relies
|
||||
on Z-System IF.COM for setting the flow state. Other flow
|
||||
control commands (FI, ELSE, XIF, OR, AND) are resident.
|
||||
|
||||
* Multiple commands can be entered on the command line. The
|
||||
command line buffer will hold up to 225 characters. Commands
|
||||
should be separated by semicolons.
|
||||
|
||||
* Extended Command Processor. If a command is not a built-in
|
||||
flow command, resident command, or located on disk along the
|
||||
search path, the command line is passed to an extended command
|
||||
processor. A typical extended command processor is ARUNZ, a
|
||||
sophisticated batch file executor with alias features. To use
|
||||
a program as an extended command processor, rename it to
|
||||
CMDRUN.COM and place it in the ROOT directory of your boot disk.
|
||||
|
||||
* Error handler. In the event that the extended command
|
||||
processor can't handle a command, control is passed to an error
|
||||
handler. Error handlers give information about the error
|
||||
(instead of the useless CP/M "?" message) and allow the command
|
||||
line to be edited and reused.
|
||||
|
||||
* Resident commands. The following commands are built in:
|
||||
CLS - clears the screen
|
||||
NOTE - text following the NOTE command is treated as a
|
||||
comment.
|
||||
FI - Flow control: terminate the current IF level
|
||||
ELSE - Flow control: toggle the flow state
|
||||
XIF - Flow control: exit all pending IF levels
|
||||
OR - Flow control: OR IF tests to set flow state
|
||||
AND - Flow control: AND IF tests to set flow state
|
||||
|
||||
* Shell stack. Up to four shell levels can be defined. Z-System
|
||||
provides a choice of several different shells. Applications such
|
||||
as terminal programs and word processors can also be assigned
|
||||
shell status.
|
||||
|
||||
* ZCCP uses the LOADSEG command for direct loading of RSX files
|
||||
that have not been GENCOMed. Example: LOADSEG SAVE.RSX loads
|
||||
SAVE.RSX.
|
||||
|
||||
There are some things that Z3Plus will do that ZCCP won't do.
|
||||
|
||||
- ZCCP does not support a Flow Command Package (FCP). It relies
|
||||
on the transient IF command. Other flow commands (FI, ELSE, XIF,
|
||||
OR, AND) are resident in ZCCP.
|
||||
|
||||
- A Resident Command Package (RCP) is not implemented. CLS and
|
||||
NOTE are resident in ZCCP. All other commands must be loaded
|
||||
from disk. This isn't as much of a handicap as it might sound
|
||||
if you have a fast RAM drive to store frequently used commands.
|
||||
|
||||
- ZCCP can not load type 4 programs (used with ZCPR 3.4). It
|
||||
loads standard COM files at 100H, and type 3 programs that load
|
||||
in high memory. Most type 4 programs have type 3 or COM
|
||||
equivalents, so this should not be a problem.
|
||||
|
||||
- ZCCP can not reexecute loaded programs. This trick is usually
|
||||
performed on Z-Systems with a GO command that jumps to 100H.
|
||||
Since ZCCP also loads at 100H, a GO command would only restart
|
||||
ZCCP.
|
||||
|
||||
ZCCP Files
|
||||
|
||||
Three files are included in ZCCP.ARK:
|
||||
|
||||
File name Size Description
|
||||
============ ==== ==========================================
|
||||
CCP .COM 3k ZCCP replacement for CCP.COM
|
||||
LOADSEG .COM 3k Loader for named directories and termcaps
|
||||
ZINSTAL .ZPM 1k Segment containing environment information
|
||||
|
||||
Getting Started - Preparing a Boot Disk
|
||||
|
||||
Format a system boot disk using the same proceedure that you normally
|
||||
would.
|
||||
|
||||
Copy the files from ZCCP.ARK to user area 0 of the newly
|
||||
formatted disk.
|
||||
|
||||
Copy CPM+.SYS (some systems may use a slightly different name for this
|
||||
file) to user 0 of the boot disk. The CPM+.SYS must include the BDOS
|
||||
segments from ZPM3. Use the ZPM3 MAKEDOS utility to overlay your
|
||||
system file with ZPM3. (Commodore 128 users must generate a new
|
||||
system using the ZPM3 BDOS segments. The MAKEDOS utility does not
|
||||
work properly on a C128.)
|
||||
|
||||
Locate a copy of a Z-System alias utility. A good one is
|
||||
SALIAS16, although others should work also. Copy it to user 0 of
|
||||
the boot disk.
|
||||
|
||||
At this point, reboot the system with the new system disk. After the
|
||||
system boots, you won't be able to do much with it. The only resident
|
||||
commands are CLS and NOTE, and ZCCP can only locate commands if they
|
||||
are prefixed with the drive and user number.
|
||||
|
||||
The next step is to create a startup alias. When ZCCP boots, it
|
||||
looks for a file named STARTZPM.COM and executes commands from
|
||||
it. STARTZPM.COM is created with a ZCPR alias utility. Here is
|
||||
a listing of a STARTZPM.COM created with SALIAS:
|
||||
|
||||
=============================================================
|
||||
|
||||
A0>SALIAS STARTZPM
|
||||
|
||||
15: ; Logs the ROOT directory (A15) on the
|
||||
; current drive.
|
||||
|
||||
LOADSEG NAMES.NDR TCAP.Z3T
|
||||
; LOADSEG loads the Named Directory Register
|
||||
; and TCAP.
|
||||
; Directories can now be referred to by
|
||||
; name, as in the next command:
|
||||
|
||||
SETPTH10 /C COMMANDS RAM2 WORK $$$$ $$0 ROOT
|
||||
; SETPTH sets the command search path.
|
||||
; The /c option first clears any existing path.
|
||||
; Directories are then listed in the
|
||||
; order searched. In this case, COMMANDS
|
||||
; is a 64K ramdisk (drive/user F0) where
|
||||
; frequently used commands are stored. RAM2 is
|
||||
; an additional RAM disk. (drive/user M0).
|
||||
; WORK is a standard 3.5" floppy disk
|
||||
; drive, (drive/user C15) where some 700K
|
||||
; of utilities and applications are
|
||||
; located. $$$$ refers to the currently
|
||||
; logged drive and user area. $$0 refers
|
||||
; to user area 0 of the current drive.
|
||||
; The ROOT directory is on drive A, user
|
||||
; 15, where startup utilities and system
|
||||
; files can be found.
|
||||
|
||||
AUTOTOG ON ; Turns on keyboard control of ZPM3 Auto
|
||||
; Command Prompting. Auto Command
|
||||
; Prompting is toggled by entering CTRL-Q.
|
||||
|
||||
COMMANDS: ; Logs the commands directory.
|
||||
|
||||
IF ~EXIST CP.* ; Test to see if commands are loaded.
|
||||
; This line reads: "If the CP command
|
||||
; does not exist . . ." and sets the flow
|
||||
; state to true if the file doesn't exist.
|
||||
C1:CP C1:*.* F0:
|
||||
; ". . . copy all of the commands in
|
||||
; drive/user C1 to the commands (F0)
|
||||
; directory . . ."
|
||||
FI ; ". . . end if."
|
||||
|
||||
ROOT: ; Log the root directory (A15).
|
||||
|
||||
CP C:ZF*.* M0: ; Copy ZFILER.COM and ZFILER.CMD to the
|
||||
; REU2 directory (M0).
|
||||
|
||||
VERROR ; Install VERROR error handler.
|
||||
|
||||
DATE S ; Set the system time and date.
|
||||
|
||||
ZF ; Invoke ZFILER as a shell.
|
||||
|
||||
=============================================================
|
||||
|
||||
Of course, your STARTZPM alias will vary depending on the
|
||||
hardware you need to support, your software preferences, and your
|
||||
work habits. This alias is close to the upward size limit that
|
||||
ZCCP can handle based on the capacity of the multiple command
|
||||
buffer. At the very least, I recommend an alias that will set up
|
||||
a search path and load a TCAP.
|
||||
|
||||
Actually, I put the cart before the horse in this example. If
|
||||
you try to reboot your system with the LOADSEG command as listed,
|
||||
you'll notice that you don't have a NAMES.NDR file. There isn't
|
||||
one distributed with ZCCP either. Z-System utilities won't let
|
||||
you edit the NDR either, since the buffer for it hasn't been
|
||||
created yet. This turned out to be a nasty chicken/egg
|
||||
situation, hopefully solved by the inclusion of a sample
|
||||
NAMES.NDR file containing simply A0:SYSTEM and A15:ROOT.
|
||||
|
||||
At this point, you should have a mostly functioning ZCCP system disk.
|
||||
Reboot the system with the new disk. You might want to correct any
|
||||
problems with it or tweak it to perfection before moving on.
|
||||
|
||||
List of Z-System Utilities for ZCCP
|
||||
|
||||
Some of the following utilities are essential, others are nice to
|
||||
have. The version numbers listed are the latest known versions at the
|
||||
time that this documentation was written. Utilities can be found on
|
||||
ZNode BBSs, and some of them are available on Internet anonymous ftp
|
||||
sites (Simtel20 or its mirror sites).
|
||||
|
||||
SALIAS16 - already mentioned in the example above. SALIAS (or
|
||||
one of the other ZCPR alias utilities) are essential.
|
||||
|
||||
SD138B - excellent DIRectory utility. SD offers many
|
||||
different types of sorts, list formats, etc., displays date
|
||||
stamps, and supports output to a file.
|
||||
|
||||
MKDIR32 - utility for manipulating directory names and Named
|
||||
Directory Register (*.NDR) files.
|
||||
|
||||
ERASE57 - erases files.
|
||||
|
||||
ZFILER10 - a file management shell that can launch applications.
|
||||
It is programmable in that it can execute user defined macros
|
||||
from a file. Multiple files can be "tagged" and operated on by
|
||||
other programs. ZFILER is an excellent program, sort of a GUI
|
||||
desktop without the slow graphics.
|
||||
|
||||
SETPTH10 - used to set the command search path. Essential!
|
||||
|
||||
VERROR17 - error handler that displays the command line for
|
||||
reediting. VERROR17 is the only error handler that I found that
|
||||
works with ZCCP.
|
||||
|
||||
ZEX50 - Z-System EXecutive is a powerful batch file processor
|
||||
that replaces the CP/M SUBMIT command.
|
||||
|
||||
LBRHLP22 - Z-System Help utility displays help files. Help
|
||||
files can be crunched (*.HZP), and/or loaded from a HELP.LBR
|
||||
library.
|
||||
|
||||
ARUNZ09 - runs an alias script from a text file. ARUNZ is
|
||||
frequently used as an extended command processor. To use ARUNZ
|
||||
(or any other executable utility) as an extended command
|
||||
processor, rename it to CMDRUN.COM.
|
||||
|
||||
VLU102 - Video Library Utility views or extracts files from
|
||||
libraries. Versions of VLU above 1.02 do not work reliably with
|
||||
ZPM3/ZCCP.
|
||||
|
||||
Z33IF16 - is the IF.COM discussed in the section on flow control.
|
||||
|
||||
SHOW14 - displays an immense amount of information about your
|
||||
Z-System. SHOW also includes a memory patching function.
|
||||
|
||||
ZCNFG24 - configures Z-System program options. Most Z-System
|
||||
programs are distributed with a configuration (*.CFG) file that
|
||||
produces a menu of configuration options when run with ZCNFG.
|
||||
|
||||
ZP17 - Z-System Patch utility edits files, disk sectors, or
|
||||
memory, and includes a built-in RPN calculator and number base
|
||||
converter.
|
||||
|
||||
ZMAN-NEW - This is a manual describing Z-System features in
|
||||
depth. It is based on earlier versions of Z-System, and is a
|
||||
little dated, but otherwise contains information that you won't
|
||||
find anywhere else. Not everything in the manual applies to
|
||||
operation of ZPM3/ZCCP, but with the documentation presented
|
||||
here, you should be able to get a good idea of what works and
|
||||
what doesn't.
|
||||
|
||||
A TCAP termcap file for your system - This file is essential if you
|
||||
want to use any ZCPR programs that need a TCAP.
|
||||
|
||||
ZCCP Technical Notes
|
||||
|
||||
ZCCP is a replacement CCP that implements ZCPR 3.3. It loads at
|
||||
100H and is stored in the bank 0 CCP buffer for fast reloading as
|
||||
does the standard CCP. By contrast, Z3Plus loads into high
|
||||
memory and can be overwritten by transient commands, requiring
|
||||
reloading Z3Plus from disk. Because ZCCP replaces the CCP, a
|
||||
ZCCP system has more TPA (transient program area) than a Z3Plus
|
||||
system. A ZCCP system on the C128 has more than 57K of TPA,
|
||||
almost the same amount as a standard C128 CP/M system.
|
||||
|
||||
This should be enough information to get started with ZPM3/ZCCP.
|
||||
Set up a boot disk, experiment with some Z-System utilities, read
|
||||
ZMAN-NEW, and get some applications running. You'll agree that
|
||||
ZPM3/ZCCP breaths new life into CP/M.
|
||||
|
||||
*******************************************************************************
|
||||
* Randy Winchester * randy@mit.edu * PO Box 1074, Cambridge, MA 02142 *
|
||||
*******************************************************************************
|
||||
|
||||
BIN
Source/ZCCP/zinstal.zpm
Normal file
BIN
Source/ZCCP/zinstal.zpm
Normal file
Binary file not shown.
61
Source/ZPM3/Build.cmd
Normal file
61
Source/ZPM3/Build.cmd
Normal file
@@ -0,0 +1,61 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
set TOOLS=../../Tools
|
||||
|
||||
set PATH=%TOOLS%\zx;%TOOLS%\cpmtools;%PATH%
|
||||
|
||||
set ZXBINDIR=%TOOLS%/cpm/bin/
|
||||
set ZXLIBDIR=%TOOLS%/cpm/lib/
|
||||
set ZXINCDIR=%TOOLS%/cpm/include/
|
||||
|
||||
copy ..\ZCCP\ccp.com zccp.com
|
||||
copy ..\ZCCP\zinstal.zpm .
|
||||
copy ..\ZCCP\startzpm.com
|
||||
copy ..\CPM3\genbnk.dat .
|
||||
rem copy ..\CPM3\bios3.spr .
|
||||
copy ..\CPM3\bnkbios3.spr .
|
||||
copy ..\CPM3\gencpm.com .
|
||||
copy ..\CPM3\biosldr.rel
|
||||
|
||||
rem ZPM Loader
|
||||
echo.
|
||||
echo.
|
||||
echo *** ZPM Loader ***
|
||||
echo.
|
||||
zx LINK -ZPMLDR[L100]=ZPM3LDR,BIOSLDR
|
||||
rem pause
|
||||
|
||||
rem Banked CPM3
|
||||
echo.
|
||||
echo.
|
||||
echo *** Banked ZPM3 ***
|
||||
echo.
|
||||
copy genbnk.dat gencpm.dat
|
||||
zx gencpm -auto -display
|
||||
if exist zpm3.sys del zpm3.sys
|
||||
ren cpm3.sys zpm3.sys
|
||||
rem pause
|
||||
|
||||
rem Update cpm_hd.img
|
||||
echo.
|
||||
echo.
|
||||
echo *** Update Disk Image ***
|
||||
echo.
|
||||
for %%f in (
|
||||
zpmldr.com
|
||||
autotog.com
|
||||
clrhist.com
|
||||
setz3.com
|
||||
zpm3.sys
|
||||
zccp.com
|
||||
zinstal.zpm
|
||||
startzpm.com
|
||||
) do call :upd_img %%f
|
||||
goto :eof
|
||||
|
||||
:upd_img
|
||||
echo %1...
|
||||
cpmrm.exe -f wbw_hd0 ../../Binary/hd_cpm3.img 0:%1
|
||||
cpmcp.exe -f wbw_hd0 ../../Binary/hd_cpm3.img %1 0:%1
|
||||
goto :eof
|
||||
18
Source/ZPM3/Clean.cmd
Normal file
18
Source/ZPM3/Clean.cmd
Normal file
@@ -0,0 +1,18 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
if exist ccp.com del ccp.com
|
||||
if exist *.sys del *.sys
|
||||
if exist gencpm.dat del gencpm.dat
|
||||
if exist loader.cim del loader.cim
|
||||
if exist bnkbios3.spr del bnkbios3.spr
|
||||
if exist system.epr del system.epr
|
||||
if exist system.evn del system.evn
|
||||
if exist system.odd del system.odd
|
||||
if exist biosldr.rel del biosldr.rel
|
||||
if exist *.sym del *.sym
|
||||
if exist zpmldr.com del zpmldr.com
|
||||
if exist zccp.com del zccp.com
|
||||
if exist startzpm.com del startzpm.com
|
||||
if exist gencpm.com del gencpm.com
|
||||
if exist *.dat del *.dat
|
||||
BIN
Source/ZPM3/autotog.com
Normal file
BIN
Source/ZPM3/autotog.com
Normal file
Binary file not shown.
131
Source/ZPM3/autotog.z80
Normal file
131
Source/ZPM3/autotog.z80
Normal file
@@ -0,0 +1,131 @@
|
||||
|
||||
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; A U T O T O G
|
||||
; for ZPM3
|
||||
; by Simeon Cran
|
||||
; 30/3/92
|
||||
;
|
||||
; This program toggles the Auto Command Prompting facility of ZPM3. It is
|
||||
; presented in source code form to inform users about how the facility is
|
||||
; manipulated.
|
||||
|
||||
; Be aware that when Auto Command Prompting is enabled with this program,
|
||||
; it won't actually operate until turned on at the keyboard with ^Q. This
|
||||
; program simply enables the ^Q toggling of Auto Command Prompting.
|
||||
|
||||
; When ZPM3 is booted, Auto Command Prompting is disabled. Usually, a
|
||||
; startup file would include the AUTOTOG command to turn it on unless it
|
||||
; is felt that the facility could confuse the operator (as may happen with
|
||||
; a remote ZPM3 system).
|
||||
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
; SYNTAX:
|
||||
; AUTOTOG Toggles the state of the Auto Command Prompting
|
||||
; AUTOTOG ON Enables Auto Command Prompting
|
||||
; AUTOTOG OFF Disables Auto Command Prompting
|
||||
; AUTOTOG // Displays a brief help message
|
||||
|
||||
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
;
|
||||
; Automatic Command Prompting is enabled and disabled by a bit 6 of offset
|
||||
; 85h of the SCB page. This offset can not be directly accessed by the SCB
|
||||
; function (31h). Instead, we get the SCB base page with function 31h, and
|
||||
; then find the offset from there. No other bits in the byte may be touched.
|
||||
;
|
||||
;===============================================================================
|
||||
|
||||
BDOS equ 5
|
||||
deffcb equ 5ch
|
||||
SCBfunc equ 31h ; Get/Set SCB function number
|
||||
SCBoff equ 3bh ; Offset in SCB to get SCB base page
|
||||
ACPoff equ 85h ; Offset in SCB base page of Auto Command Prompting bit
|
||||
|
||||
jp start ; Jump over general data
|
||||
|
||||
HELPmsg:
|
||||
db ' SYNTAX:'
|
||||
db 10,13
|
||||
db ' AUTOTOG Toggles the state of the Auto Command Prompting'
|
||||
db 10,13
|
||||
db ' AUTOTOG ON Enables Auto Command Prompting'
|
||||
db 10,13
|
||||
db ' AUTOTOG OFF Disables Auto Command Prompting'
|
||||
db 10,13
|
||||
db ' AUTOTOG // Displays a brief help message'
|
||||
db '$'
|
||||
ONmsg:
|
||||
db 'ZPM3 Auto Command Prompting is now enabled. Toggle with ^Q.'
|
||||
db '$'
|
||||
OFFmsg:
|
||||
db 'ZPM3 Auto Command Prompting is now disabled.'
|
||||
db '$'
|
||||
|
||||
ONword: ; Word to match to turn Auto Command Prompting on
|
||||
db 'ON '
|
||||
OFFword: ; Word to match to turn Auto Command Prompting off
|
||||
db 'OFF '
|
||||
TOGword: ; Word to match to toggle Auto Command Prompting
|
||||
db ' '
|
||||
|
||||
HELP: ld de,HELPmsg
|
||||
MSGexit:
|
||||
ld c,9
|
||||
call bdos
|
||||
rst 0
|
||||
|
||||
start: ; Get the address of the bit which controls Auto Command Prompting.
|
||||
ld c,SCBfunc
|
||||
ld de,SCBPB
|
||||
call bdos ; Get base page of SCB
|
||||
ld h,a
|
||||
ld l,ACPoff ; HL is now the address of the byte
|
||||
ld (ACPaddr),hl ; Save it
|
||||
|
||||
; Find out what the user wants to do. If the argument matches
|
||||
; any of the three control words, act accordingly, otherwise
|
||||
; show the help message and exit.
|
||||
ld hl,ONword
|
||||
call matchWord
|
||||
jr z,TurnON
|
||||
ld hl,OFFword
|
||||
call matchWord
|
||||
jr z,TurnOFF
|
||||
ld hl,TOGword
|
||||
call matchWord
|
||||
jr nz,HELP
|
||||
; Toggle the Auto Command Prompting.
|
||||
ld hl,(ACPaddr)
|
||||
bit 6,(hl)
|
||||
jr z,TurnON
|
||||
TurnOFF: ; Turn the Auto Command Prompting off.
|
||||
ld hl,(ACPaddr)
|
||||
res 6,(hl)
|
||||
ld de,OFFmsg
|
||||
jr MSGexit
|
||||
|
||||
TurnON: ; Turn the Auto Command Prompting on.
|
||||
ld hl,(ACPaddr)
|
||||
set 6,(hl)
|
||||
ld de,ONmsg
|
||||
jr MSGexit
|
||||
|
||||
|
||||
|
||||
matchWord: ; Compare the string at HL with the string at defFCB+1 for
|
||||
; 8 bytes. Return Z if it matches.
|
||||
ld de,defFCB
|
||||
ld bc,8
|
||||
matchW1:
|
||||
inc de
|
||||
ld a,(de)
|
||||
cpi
|
||||
ret nz
|
||||
jp pe,matchW1
|
||||
ret
|
||||
|
||||
SCBPB: ; System control block function parameter block.
|
||||
ACPaddr: ; Save the address of the ACP bit here too.
|
||||
db 03bh
|
||||
db 0 ; Get operation
|
||||
|
||||
|
||||
230
Source/ZPM3/bios.txt
Normal file
230
Source/ZPM3/bios.txt
Normal file
@@ -0,0 +1,230 @@
|
||||
NOTES on your CP/M 3.0 BIOS and ZPM3
|
||||
====================================
|
||||
Last updated 19/4/92
|
||||
|
||||
ZPM3 will work fine with your current CP/M 3.0 BIOS. This
|
||||
document is not meant to tell you how to change your BIOS for
|
||||
ZPM3, but rather to point out some interesting and useful facts
|
||||
about the way ZPM3 uses the BIOS, and how you should configure
|
||||
your BIOS.
|
||||
|
||||
|
||||
|
||||
XMOVE routine.
|
||||
~~~~~~~~~~~~~~
|
||||
If you have 128 byte physical sectors, or your BIOS does all the
|
||||
deblocking so that it appears to the BDOS that you have 128 byte
|
||||
physical sectors, XMOVE does not get used at all by ZPM3. Such
|
||||
was not the case with CP/M 3.0 which would make redundant calls
|
||||
to XMOVE. Make sure XMOVE is implemented and working anyhow as
|
||||
applications may attempt to use it.
|
||||
|
||||
When the BDOS is operating in the system bank (bank 0) and it
|
||||
needs to move data in the TPA bank, it switches to the TPA bank
|
||||
and does an ordinary LDIR. As such, XMOVE will never get called
|
||||
by the BDOS with B=C (source bank and destination bank the same).
|
||||
|
||||
In the CP/M 3.0 manuals, there are two differing opinions about
|
||||
XMOVE as far as whether B is the source or the destination. The
|
||||
truth is that C is the source and B is the destination. Anything
|
||||
you see to the contrary is a misprint.
|
||||
|
||||
MOVE routine.
|
||||
~~~~~~~~~~~~~
|
||||
When CP/M 3.0 was released, it was made 8080 compatible simply
|
||||
because CP/M 2.2 was 8080 compatible. I have never heard of an
|
||||
8080 machine running CP/M 3.0, and it is likely that there has
|
||||
never been one. Digital Research knew that the Z80 was the CPU of
|
||||
choice for modern PC's, and while they wrote their code for the
|
||||
8080, they recognised the Z80 with the MOVE routine (which a Z80
|
||||
BIOS could implement in just three instructions).
|
||||
|
||||
ZPM3 uses the MOVE routine much less than CP/M 3.0 does. In fact,
|
||||
the only time ZPM3 uses MOVE is with an XMOVE call directly
|
||||
preceding it. If you have 128 byte physical sectors (or the BIOS
|
||||
does the sector deblocking), MOVE will never get called.
|
||||
|
||||
Always remember that MOVE must return with HL and DE pointing to
|
||||
the end of the moved data. If they don't, you will have trouble.
|
||||
|
||||
|
||||
TIME routine.
|
||||
~~~~~~~~~~~~~
|
||||
Be aware that the DATE program supplied with CP/M 3.0 will not
|
||||
work properly if your BIOS does not update the SCB with
|
||||
interrupts. There have been replacements since then that are
|
||||
available in the public domain.
|
||||
|
||||
One common trap for BIOS writers is forgetting that HL and DE
|
||||
must be saved by the TIME routine. There is no obvious reason for
|
||||
it, and really they should be saved in the BDOS.
|
||||
|
||||
ZPM3 does not expect HL to be saved. If you have had trouble with
|
||||
your CP/M 3.0 clock things might work now. It was decided that
|
||||
seeing as TIME was the only routine (apart from MOVE) which
|
||||
required HL to be saved, it was too easy to overlook, and a real
|
||||
pain to implement (some systems use HL to switch banks on entry
|
||||
to the BIOS. MOVE is always accounted for, but TIME sometimes
|
||||
isn't (Morrow MD11 owners take note!)).
|
||||
|
||||
Ideally, there should be no reason to save HL in your BIOS,
|
||||
unless you intend to run CP/M 3.0 sometimes (although I can't
|
||||
imagine why). Any applications which attempt to use TIME through
|
||||
the function 50 are not guaranteed that HL will be saved anyhow.
|
||||
|
||||
Buffers.
|
||||
~~~~~~~~
|
||||
CP/M 3.0 (and therefore ZPM3) keeps special disk buffers. The
|
||||
system is rather complex. The directory is buffered separately
|
||||
from the rest of the disk (and in the case of 128 byte sectors
|
||||
the rest of the disk isn't buffered anyhow).
|
||||
|
||||
You decide how many buffers to give to each disk's directory and
|
||||
data, and you may choose to have buffers shared by different
|
||||
drives. All these choices can make for lots of fun for the
|
||||
hacker, but without knowing much about the internal workings of
|
||||
the BDOS how do you best set the buffer up?
|
||||
|
||||
There are many cases to consider depending on how much RAM you
|
||||
have available to allocate to buffers. If you have virtually
|
||||
unlimited RAM, you might as well allocate as many buffers as
|
||||
GENCPM will allow. The only catch to this is that more buffers
|
||||
implies the BDOS will take more time to look through them all
|
||||
before coming to the decision that a disk read is required. The
|
||||
good news is that the ZPM3 searching algorithm is particularly
|
||||
fast. Empty buffers are discovered even faster than buffers
|
||||
which are valid but don't match, so large numbers of empty
|
||||
buffers pose very little problem. In general, even with the
|
||||
maximum number of buffers, the advantages they give outweigh the
|
||||
disadvantages.
|
||||
|
||||
Of course, few people have unlimited RAM. If you have very little
|
||||
room available, spend most of it on the directory buffers. These
|
||||
buffers act like a cache of the directory, and can save the disk
|
||||
heads from moving back to the directory tracks to find out where
|
||||
the next block is stored. Even on very fast hard disks, the
|
||||
advantages that decent directory buffers give are great.
|
||||
|
||||
When dividing up directory buffers between a number of drives,
|
||||
consider which drive holds the most files and which drive does
|
||||
the most work. A drive which holds a lot of files but is rarely
|
||||
accessed is not worth wasting buffers on. If you have a system
|
||||
with one hard drive and one floppy drive, and you don't intend to
|
||||
use the floppy drive very much, give only one buffer to the
|
||||
floppy and all the rest to your hard drive. This will penalise
|
||||
the floppy's performance somewhat, but the improvement it gives
|
||||
to the hard drive will make it worthwhile.
|
||||
|
||||
Data buffers, like directory buffers, perform two tasks:
|
||||
deblocking of physical sectors, and cacheing. For data buffers
|
||||
however the cacheing is the less important job, unless you have a
|
||||
lot of data buffers available. The reason for this is that the
|
||||
buffer algorithms work by taking the least recently used buffer
|
||||
and using it for deblocking. If you are working on a file which
|
||||
is 8k long, but you only have 4k of buffers, the BDOS will run
|
||||
out of buffers before it has read the whole file and will grab
|
||||
the least recently used one even though it contains valid data
|
||||
from the file which could be required later on. The result is
|
||||
that the BDOS does much searching through its 4k of buffers, but
|
||||
rarely finds anything which matches and must read from the disk
|
||||
anyhow.
|
||||
|
||||
In practice the system works a little better than that because of
|
||||
the way files are used by most programs, so data buffers are
|
||||
still worthwhile, but to take real advantage of their cacheing
|
||||
ability you must have more room in the data buffers than the size
|
||||
of the file you are working with. With word processors such as
|
||||
Wordstar and NewWord creating extra files as they work, you
|
||||
really need more than twice as much room in the buffers than the
|
||||
size of the file.
|
||||
|
||||
So you can see why data buffers are less important than directory
|
||||
buffers. Something else you should be aware of concerns multi-
|
||||
sector i/o and the data buffers. When the BDOS is told to read a
|
||||
file it searches its buffers and if it can't find the data there
|
||||
it reads it from the disk. Normally it deblocks the data one
|
||||
record at a time through its data buffers, leaving the data in
|
||||
the buffers in case it is required again. However multi-sector
|
||||
i/o does not usually need to deblock its data, so the data is
|
||||
sent straight to the TPA without going through the data buffers.
|
||||
If any of that data is required again, it will not be in the data
|
||||
buffers and must be read from the disk. So two reads of the same
|
||||
data using multi-sector i/o might actually be slower than reads
|
||||
that are done a sector at a time!
|
||||
|
||||
And the really important thing about all this is that the CCP
|
||||
uses multi-sector i/o to load programs. So if you thought that
|
||||
implementing large numbers of data buffers would give you faster
|
||||
loading of programs, you were wrong. The data buffers won't help
|
||||
program loading unless the data can be put into the buffers
|
||||
first.
|
||||
|
||||
If you use ZCCP, you will find there is a facility to prevent the
|
||||
data buffers from being bypassed on program loads. It involves
|
||||
simply setting the f1' bit of the file. The idea is that you set
|
||||
f1' on all the files which are small enough not to clog up your
|
||||
buffers, and then they run as if they are on a ram disk, but one
|
||||
in which you can never lose data. The system is quite wonderful
|
||||
in that the RAM used to hold the files is available to buffer
|
||||
other data if required. Unlike a ram disk, the RAM is dynamically
|
||||
allocated and the data is completely safe. But you must be using
|
||||
ZCCP, and you must have at least 6k of data buffers before it
|
||||
does anything useful. If you currently have a ram disk but few
|
||||
data buffers, consider taking a chunk of your ram disk for data
|
||||
buffers and switching to ZCCP.
|
||||
|
||||
CPMLDR bug.
|
||||
~~~~~~~~~~~
|
||||
This is closely related to the subject of buffers because you
|
||||
will find that if you increase your buffers past a certain point,
|
||||
the system will not boot. Almost certainly you will suspect a
|
||||
problem with your BIOS code (you normally should), however the
|
||||
CPMLDR.REL code supplied by DRI has a bug in it.
|
||||
|
||||
You may be wondering if everything DRI did with CP/M 3.0 was
|
||||
buggy! I must say that what they achieved was terrific, but it
|
||||
had its faults as well. Hopefully ZPM3 has addressed them all.
|
||||
|
||||
The CPMLDR problem occurs when your CPM3.SYS grows from being 16k
|
||||
or less, to over 16k (and therefore two logical extents). You may
|
||||
not have this problem under certain drive configurations, but if
|
||||
you do, the symptom is that described above.
|
||||
|
||||
There really is no way of patching around this, but if you have
|
||||
your loader BIOS, you can certainly use the (somewhat superior)
|
||||
ZPM3LDR.REL code instead. This works very similarly to the DRI
|
||||
code, except that it works properly. Unlike the DRI code, you
|
||||
will find that ZPM3LDR has all its messages at the head of the
|
||||
file so that you can patch them and change them if you wish.
|
||||
|
||||
ZPM3LDR does not clear the screen on boot up (CPMLDR does by
|
||||
sending multiple linefeeds), but you could patch this if you
|
||||
like. ZPM3LDR.REL will directly replace CPMLDR.REL. ZPM3LDR
|
||||
however does not use the MOVE routine that CPMLDR requires
|
||||
(although there is nothing much to be gained by removing it from
|
||||
your loader bios code).
|
||||
|
||||
|
||||
GENCPM bugs.
|
||||
~~~~~~~~~~~~
|
||||
GENCPM has bugs in it. If you can, try and set up all your
|
||||
buffers manually. That way you'll know where they are and you are
|
||||
in complete control.
|
||||
|
||||
The biggest fault I have found with GENCPM is that it will
|
||||
allocate allocation vectors incorrectly. CP/M 3.0 can use double
|
||||
bit allocation vectors, but doesn't necessarily. Sometimes (and I
|
||||
think it is mainly with big disks), GENCPM will only allocate
|
||||
enough room for single bit allocation vectors when double bit
|
||||
vectors had been specified. The symptoms of this are varied, but
|
||||
often, you can use your A: drive for a while, but as soon as you
|
||||
use your B: drive funny things happen. If you only use A: and C:
|
||||
drives, things appear to work OK.
|
||||
|
||||
The first thing to try if you suspect a GENCPM induced problem is
|
||||
setting up with only one drive and a single buffer. If that fixes
|
||||
it, the problem could well be with GENCPM.
|
||||
|
||||
Naturally, your BIOS code could still be the problem, so look out
|
||||
for that too!
|
||||
|
||||
BIN
Source/ZPM3/bnkbdos3.spr
Normal file
BIN
Source/ZPM3/bnkbdos3.spr
Normal file
Binary file not shown.
BIN
Source/ZPM3/clrhist.com
Normal file
BIN
Source/ZPM3/clrhist.com
Normal file
Binary file not shown.
49
Source/ZPM3/clrhist.z80
Normal file
49
Source/ZPM3/clrhist.z80
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; C L R H I S T
|
||||
; for ZPM3
|
||||
; by Simeon Cran
|
||||
; 26/4/92
|
||||
;
|
||||
; This program clears the ZPM3 function 10 history buffer. It is presented in
|
||||
; source code form to inform users about how the facility is manipulated.
|
||||
|
||||
; The only real use for clearing the history buffer is as a security feature
|
||||
; on RZPM3 systems (remote ZPM3 systems (such as BBSes)). Note that individual
|
||||
; commands may be cleared from the history buffer with control-V.
|
||||
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
; SYNTAX:
|
||||
; CLRHIST Clears the history buffer
|
||||
|
||||
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
;
|
||||
; The history buffer is cleared by setting bit 7 of offset 85h of the SCB page.
|
||||
; This offset can not be directly accessed by the SCB function (31h). Instead
|
||||
; we get the SCB base page with function 31h, and then find the offset from
|
||||
; there. No other bits in the byte may be touched.
|
||||
;===============================================================================
|
||||
|
||||
BDOS equ 5
|
||||
deffcb equ 5ch
|
||||
SCBfunc equ 31h ; Get/Set SCB function number
|
||||
SCBoff equ 3bh ; Offset in SCB to get SCB base page
|
||||
CLHoff equ 85h ; Offset in SCB base page of Clear History buffer bit.
|
||||
|
||||
jp start ; Jump over general data
|
||||
|
||||
start: ; Get the address of the bit which controls History buffer clearing
|
||||
ld c,SCBfunc
|
||||
ld de,SCBPB
|
||||
call bdos ; Get base page of SCB
|
||||
ld h,a
|
||||
ld l,CLHoff ; HL is now the address of the byte
|
||||
|
||||
set 7,(hl) ; All to do
|
||||
rst 0
|
||||
|
||||
SCBPB: ; System control block function parameter block.
|
||||
db 03bh
|
||||
db 0 ; Get operation
|
||||
|
||||
|
||||
BIN
Source/ZPM3/makedos.com
Normal file
BIN
Source/ZPM3/makedos.com
Normal file
Binary file not shown.
90
Source/ZPM3/makedos.txt
Normal file
90
Source/ZPM3/makedos.txt
Normal file
@@ -0,0 +1,90 @@
|
||||
Using the MAKEDOS utility.
|
||||
==========================
|
||||
|
||||
In an ideal world, MAKEDOS would not be required as every
|
||||
computer manufacturer would have provided the source code for
|
||||
your BIOS and the GENCPM.COM utility. This however is not an
|
||||
ideal world.
|
||||
|
||||
If you have all the appropriate files, use GENCPM with the new
|
||||
ZPM3 BNKBDOS3.SPR and RESBDOS3.SPR to make a new CP/M system. If
|
||||
you only have your CP/M 3.0 system file, then read on to learn
|
||||
how to use MAKEDOS.COM to convert it from CP/M 3.0 to ZPM3.
|
||||
|
||||
|
||||
You CP/M 3.0 system file could be called one of a number of
|
||||
things. Ideally it will be called CPM3.SYS. But it might have
|
||||
another name such as J14CPM3.EMS (Amstrad computers). Even if you
|
||||
find it, you must know how the system uses it. For example does
|
||||
it load it from A0: when you boot your computer? If it does then
|
||||
you are going to have to return your modified file to A0:. Or
|
||||
does it keep the file hidden in system tracks of your disk? If
|
||||
that is the case you will have to find out how to change the
|
||||
system tracks. Chances are though that the file is read from A0:
|
||||
on each cold boot.
|
||||
|
||||
Before continuing, make sure you have a backup bootable disk. If
|
||||
you overwrite your only system file and it fails to work you are
|
||||
going to be pretty unhappy... so don't let it happen!
|
||||
|
||||
Put your system file, MAKEDOS.COM, BNKBDOS3.SPR and RESBDOS3.SPR
|
||||
onto the same disk and user area. Note that you must do this ON
|
||||
THE SAME COMPUTER RUNNING CP/M 3.0 as the system is intended for.
|
||||
This is most important because MAKEDOS gets information from its
|
||||
host computer, and if the computer is different from the one the
|
||||
system is intended for, it will get the wrong information.
|
||||
|
||||
Type MAKEDOS SYSTEM.FIL at the prompt (replacing the SYSTEM.FIL
|
||||
in the above command with the actual name of your system file
|
||||
(such as MAKEDOS CPM3.SYS)). MAKEDOS will churn away for a while
|
||||
and tell you some information. If it doesn't come up with an
|
||||
error message, all is well and you can proceed.
|
||||
|
||||
MAKEDOS makes three files. RES.DAT, BNK.DAT and another file with
|
||||
the same name as your original but with the tail .NEW (eg
|
||||
CPM3.SYS becomes CPM3.NEW). Your original file has not been
|
||||
touched. Obviously, you have to rename the .NEW file so that it
|
||||
has the correct name as the system. MAKEDOS doesn't do this for
|
||||
you just in case something goes wrong... until you rename the new
|
||||
file, you will still have a copy of the original. So, rename the
|
||||
new file, put it where it needs to be for it to become the
|
||||
system, and reboot the computer. All being well, you will come up
|
||||
running ZPM3.
|
||||
|
||||
Possible problems:
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
A few things may cause a failure and should be checked if you get
|
||||
an error message.
|
||||
|
||||
You must have enough disk space for all the files. Figure on
|
||||
having enough for the new system (same size as the old system),
|
||||
plus about another 16k.
|
||||
|
||||
Another problem is that your serial number gets overwritten.
|
||||
MAKEDOS uses your CP/M 3.0 serial number to find the BDOS in your
|
||||
system file. It checks the serial number in the file against the
|
||||
serial number on the host machine. However, it is possible for
|
||||
your serial number to become corrupted. In such a case you should
|
||||
reboot and try again.
|
||||
|
||||
It is unlikely to affect anyone, but MAKEDOS may fail with
|
||||
system files larger than 48k. If you need to convert such a file,
|
||||
please contact me.
|
||||
|
||||
Be aware that running MAKEDOS on a machine different from the
|
||||
machine that the system file is intended for may not result in
|
||||
any error messages, but will most likely cause the file to not be
|
||||
converted properly. Always use the host computer, and make sure
|
||||
you are running CP/M 3.0 or ZPM3.
|
||||
|
||||
|
||||
Once you have successfully installed ZPM3, it may not be obvious
|
||||
that it is running. ZPM3 will act just like CP/M 3.0 for the most
|
||||
part. The easiest way to check is to enter a few commands, then
|
||||
press control-W a few times. Unlike CP/M 3.0, ZPM3 remembers more
|
||||
than one previous command, and you should see them presented to
|
||||
you with control-W.
|
||||
|
||||
If you have any further trouble, all you can really do is talk to
|
||||
me, via Z-Node 62 in Perth, Western Australia (09 450 0200). Good
|
||||
luck.
|
||||
BIN
Source/ZPM3/resbdos3.spr
Normal file
BIN
Source/ZPM3/resbdos3.spr
Normal file
Binary file not shown.
435
Source/ZPM3/scb.txt
Normal file
435
Source/ZPM3/scb.txt
Normal file
@@ -0,0 +1,435 @@
|
||||
The following has been taken direct from the ZPM3 source and is
|
||||
provided as a reference. No guarantees are made with regard to
|
||||
its accuracy. The only SCB entries that you should manipulate in
|
||||
CP/M 3.0 are the ones published by its authors.
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
;68 TRAPS FOR WARM BOOT and CONSOLE FUNCTIONS
|
||||
;-------------------------------------------------------------------------------
|
||||
; This table allows you to replace certain BIOS functions with new ones in the
|
||||
; TPA. Because of the banked nature of CP/M 3, simply changing the BIOS
|
||||
; vector could cause a problem as some BIOS functions need to be in the
|
||||
; system bank. If you redirect any of these functions, you should replace
|
||||
; the first jump (0c3h) in each group with a LD HL, (21h). When restoring
|
||||
; the jumps check first that the BIOS vectors you are restoring are in
|
||||
; fact to the BIOS and not to another redirection. To do this, make sure
|
||||
; that the BIOS jumps are pointing above themselves, not down into TPA.
|
||||
|
||||
; For ZPM, the need for the traps has been eliminated.
|
||||
; Because pre-ZPM programs may attempt to write to the first byte of each
|
||||
; trap, these bytes can only be used for other things with some caution!
|
||||
|
||||
; Warm boot trap
|
||||
jp ?wboot ;68
|
||||
jp dotpa ;6b
|
||||
; Console status trap
|
||||
jp ?const ;6e
|
||||
jp dotpa ;71
|
||||
; Console input trap
|
||||
jp ?conin ;74
|
||||
jp dotpa ;77
|
||||
; Console output trap
|
||||
jp ?conout ;7a
|
||||
jp dotpa ;7d
|
||||
|
||||
;;; List output trap
|
||||
;; jp ?list ;80
|
||||
;; jp dotpa ;83
|
||||
|
||||
|
||||
db 0c3h ;80 This first byte should not be used as it
|
||||
; could get changed by programs which attempt to
|
||||
; redirect the printer
|
||||
|
||||
db 0 ;81 Not used yet
|
||||
|
||||
db 0 ;82 Function 59 load user number. Normally
|
||||
; function 59 loads from the current user
|
||||
; however by setting this byte to a user
|
||||
; number + 1, function 59 will load from
|
||||
; that user area instead (only works with
|
||||
; the ZCCP loader RSX). 0=current user number.
|
||||
|
||||
dw 0 ; -19 83
|
||||
; This word is set to the address of the
|
||||
; ZCPR system environment. If it is 0000h
|
||||
; the BDOS assumes that the normal CP/M 3
|
||||
; CCP system is running. Otherwise, the BDOS
|
||||
; will perform certain functions differently.
|
||||
; For example function 152 will use named
|
||||
; directories if available, function 10
|
||||
; will the use message buffers for CCP running
|
||||
; flag and wheel protection of files is enabled.
|
||||
|
||||
; Note that Z3PLUS users can set this word
|
||||
; once Z3PLUS is installed to enable the
|
||||
; extra functions. ZCCP users need not worry
|
||||
; as it will be done automatically.
|
||||
|
||||
db 0 ; -17 85
|
||||
; This byte holds control flags for various ZPM3
|
||||
; functions.
|
||||
; bit 7: Setting this bit will clear the function
|
||||
; 10 history buffer. Write only.
|
||||
; bit 6: Controls enabling of the function 10 AUTO
|
||||
; COMMAND facility. If set, control-Q toggles
|
||||
; the facility on and off. If clear, control-Q
|
||||
; has no effect. Read/Write.
|
||||
; bit 5: After function 152 has been called, if a DU:
|
||||
; D:,U: or DIR: spec has been found, this
|
||||
; bit is set and the drive and user is
|
||||
; set in the FCB.
|
||||
; bit 4: This flag is for system use only. It is
|
||||
; set after a function 55 call, but is reset
|
||||
; after any other call.
|
||||
; bit 3: After function 152 has been called, if a
|
||||
; DIR: spec has been parsed, this bit is set
|
||||
; and the user and drive is set in the FCB.
|
||||
; bits 2-0: Not used yet
|
||||
;-------------------------------------------------------------------------------
|
||||
; SYSTEM CONTROL BLOCK (unofficial)
|
||||
;-------------------------------------------------------------------------------
|
||||
; None of these is accessed by the resident BDOS or the user
|
||||
dw 0 ; -16 86
|
||||
dw 0 ; -14 88
|
||||
dw 0 ; -12 8a
|
||||
dw 0 ; -10 8c
|
||||
dw 0 ; -e 8e
|
||||
|
||||
dw 0 ; Bit mapped vector of drives -c 90
|
||||
; with open files since last warm boot.
|
||||
dw 0 ; Bit mapped vector of drives -a 92
|
||||
; accessed since last warm boot.
|
||||
|
||||
dw 0 ; -8 94
|
||||
dw 07h ; -6 96
|
||||
dw base+6 ; This word is the address -4 98
|
||||
; of the entry to the BDOS.
|
||||
; It can be used to find the
|
||||
; actual BDOS as opposed to
|
||||
; the top of TPA.
|
||||
db 0 ; -2 9a
|
||||
db 0 ; -1 9b
|
||||
;------------------------------------------------------------------------------
|
||||
;9c SYSTEM CONTROL BLOCK
|
||||
;------------------------------------------------------------------------------
|
||||
; The official system control block starts here. In reality, the control block
|
||||
; begins before this point, but this is the data section that we are
|
||||
; told about in the DRI literature
|
||||
; In this section, a code is used to signify which sections of the code
|
||||
; access the bytes: a * means that that user may read and write the bytes
|
||||
; a + means that the resident portion of the BDOS accesses the bytes
|
||||
; a ~ means the banked portion of the BDOS accesses the bytes
|
||||
; a ~~ means the banked portion of ZPM3 accesses the bytes, but CPM doesn't
|
||||
scb:
|
||||
db 0 ;+ Reserved 0 9c
|
||||
dw 0 ;+ Reserved 1 9d
|
||||
db 0 ; Reserved 3 9f
|
||||
db 0 ; Reserved 4 a0
|
||||
|
||||
db 31h ; BDOS version number (in BCD) 5 a1
|
||||
|
||||
; The following four bytes may be used for any purpose.
|
||||
; Note that CCP104 used 8 and 9. ZCCP and ZPM3 do not
|
||||
; affect these bytes at all.
|
||||
db 0 ;* Reserved for user 6 a2
|
||||
db 0 ;* Reserved for user 7 a3
|
||||
db 0 ;* Reserved for user 8 a4
|
||||
db 0 ;* Reserved for user 9 a5
|
||||
|
||||
db 0 ; Reserved 0a a6
|
||||
db 0 ; Reserved 0b a7
|
||||
db 0 ; Reserved 0c a8
|
||||
db 0 ; Reserved 0d a9
|
||||
db 0 ; Reserved 0e aa
|
||||
db 0 ; Reserved 0f ab
|
||||
|
||||
dw 0 ;* Program Error Return Code. 10 ac
|
||||
; This 2-byte field can be used by a program to pass
|
||||
; an error code or value to chained programs. CP/M 3's
|
||||
; conditional command facility also uses this field to
|
||||
; determine if a program executes successfuly. The
|
||||
; BDOS Function 108 (Get/SET Program Return Code) is
|
||||
; used to get/set this value
|
||||
|
||||
; Following byte holds the base page of the top
|
||||
; multiple command RSX (only used by CCP).
|
||||
db 0 ; Reserved 12 ae
|
||||
|
||||
; The following bytes are the default disk and user
|
||||
; of the CCP. When the CCP is run, the disk and user
|
||||
; is restored to these values unless flagged not to
|
||||
; by the chain command.
|
||||
db 0 ; CCP disk 13 af
|
||||
db 0 ; CCP user number 14 b0
|
||||
|
||||
; The following word holds the address of the next
|
||||
; command to get if running multiple commands or
|
||||
; shells. It should not be set by the user.
|
||||
|
||||
dw 0 ; Multiple command pointer. CCP 15 b1
|
||||
|
||||
db 0 ; System flag CCP use 17 b3
|
||||
; This byte is bit mapped as follows:
|
||||
; Bit 0 Submit flag (set if a file beginning with '$'
|
||||
; is found, cleared by CCP)
|
||||
; 1 RSX flag (set by loader when it loads a null
|
||||
; file with RSXs attached (indicates to CCP
|
||||
; not to attempt to remove the RSXs until the
|
||||
; second warm boot). May be set by RSXs
|
||||
; 2-5 unknown (probably used by utilities)
|
||||
; 6 Change default DU to last program's DU
|
||||
; when chaining.
|
||||
; 7 Chain flag. Set to indicate to CCP that
|
||||
; there is a command to chain to at 080h.
|
||||
|
||||
db 0 ; System flag CCP use 18 b4
|
||||
; This byte is bit mapped as follows:
|
||||
; Bit 0 Display command flag
|
||||
; 1 Display command flag
|
||||
; 2 Unknown
|
||||
; 3 File type search order
|
||||
; 4 File type search order
|
||||
; 5 Reset disk system
|
||||
; 6 "GET" RSX flag (set if GET RSX is redirecting)
|
||||
; 7 CCP running flag
|
||||
; Bit 7 is the only one used by the BDOS (in function 10)
|
||||
|
||||
db 0 ; System flag CCP use 19 b5
|
||||
; This byte is bit mapped as follows:
|
||||
; Bit 0 Unknown
|
||||
; 1 Cold boot flag
|
||||
; 2-7 Unknown
|
||||
|
||||
db 0 ;* Console Width 1a b6
|
||||
; This byte contains the number of columns
|
||||
; (characters) per line on your console relative
|
||||
; to zero. Most systems default this value to
|
||||
; 79. You can set this default value by using
|
||||
; GENCPM or the DEVICE utility. The console width
|
||||
; value is used by CP/M 3 in BDOS function 10. It
|
||||
; is not used by ZPM3. Typing a character into the
|
||||
; last position of the screen, as specified by the
|
||||
; Console Width field, must not cause the terminal
|
||||
; to advance to the next line.
|
||||
|
||||
db 0 ; Console Column Position 1b b7
|
||||
; This byte contains the current console column postion
|
||||
|
||||
db 0 ;* Console Page Length 1c b8
|
||||
; This byte contains the number of lines (rows) on your
|
||||
; console relative to zero. Most systems default this
|
||||
; value to 23. This default value may be changed by
|
||||
; using GENCPM or the DEVICE utility.
|
||||
|
||||
db 0 ; Reserved 1d b9
|
||||
; The following word is used by function 10 and points
|
||||
; to the next character to get in an initialised
|
||||
; function 10 buffer. If a ^C termination occurs or
|
||||
; if a null terminator is found before a CR or LF,
|
||||
; this word is set 0. By setting DE NZ and pointing
|
||||
; this word to a buffer before calling it, you
|
||||
; can have it initialize buffers other than
|
||||
; the default DMA.
|
||||
|
||||
dw 0 ;+~Reserved 1e ba
|
||||
; The following word is used by multiple commands and
|
||||
; shells. When function 10 retrieves information from
|
||||
; an initialised buffer, it stores the next character
|
||||
; position at offset 1e and here at 20. If a ^C
|
||||
; termination occurs, 1e is set to 00, but 20 is left
|
||||
; as it was so that the next command can be retrieved.
|
||||
; Therefore, if 1e is 00 and 20 is NZ it means that
|
||||
; a ^C termination happened
|
||||
|
||||
dw 0 ;~ Reserved 20 bc
|
||||
|
||||
|
||||
; Redirection flags (following) for each of the five
|
||||
; logical character devices. If your system's BIOS
|
||||
; supports assignment of logical devices to physical
|
||||
; devices, you can direct each of the five logical
|
||||
; character devices to any combination of up to 12
|
||||
; physical devices. The 16 bit word for each device
|
||||
; represents the following:
|
||||
;
|
||||
; Each bit represents a physical device where bit 15
|
||||
; corresponds to device zero and bit 4 corresponds to
|
||||
; device 11. Bits zero through 3 are reserved for
|
||||
; system use and are used for redirection to disk files.
|
||||
;
|
||||
dw 0 ;* CONIN Redirection Flag 22 be
|
||||
dw 0 ;* CONOUT Redirection Flag 24 c0
|
||||
dw 0 ;* AUXIN Redirection Flag 26 c2
|
||||
dw 0 ;* AUXOUT Redirection Flag 28 c4
|
||||
dw 0 ;* LIST Redirection Flag 2a c6
|
||||
|
||||
db 0 ;* Page Mode 2c c8
|
||||
; If this byte is set to zero, some CP/M 3 utilities
|
||||
; and CCP built in commands display one page of data
|
||||
; at a time; you display the next page by pressing
|
||||
; any key. If this byte is not set to zero, the system
|
||||
; displays data on the screen without stopping. To
|
||||
; stop and start the display, you can press CTRL-S and
|
||||
; CTRL-Q respectively.
|
||||
|
||||
db 0 ; Default page mode 2d c9
|
||||
|
||||
db 0 ;* ~~ 2e ca
|
||||
; Determines if CTRL-H is interpreted as a rub/del
|
||||
; character. If this byte is set to 0, then CTRL-H is
|
||||
; a backspace character (moves back and deletes). If
|
||||
; this byte is set to 0ffh, then CTRL-H is a rub/del
|
||||
; character, echoes the deleted character.
|
||||
; Under ZPM3, the byte has no effect. It should not
|
||||
; be used however as it may be written to by
|
||||
; applications.
|
||||
|
||||
db 0 ;* 2f cb
|
||||
; Determines if rub/del is interpreted as CTRL-H
|
||||
; character. If this byte is set to 0, then rub/del
|
||||
; echoes the deleted character. If this byte is
|
||||
; set to 0ffh, then rub/del is interpreted as a
|
||||
; CTRL-H character (moves back and deletes).
|
||||
; Under ZPM3, the byte has no effect. It should not
|
||||
; be used however as it may be written to by
|
||||
; applications.
|
||||
|
||||
db 0 ;~ Reserved 30 cc
|
||||
|
||||
; Following two bytes are probably used by CP/M3 utilities
|
||||
db 0 ; Reserved 31 cd
|
||||
db 0 ; Reserved 32 ce
|
||||
|
||||
dw 0 ;*+ Console Mode 33 cf
|
||||
; This is a 16 bit system parameter that determines
|
||||
; the action of certain BDOS Console I/O functions.
|
||||
|
||||
dw bnkbuf ; Address of 128 byte buffer 35 d1
|
||||
|
||||
db '$' ;*+ Output delimiter character. 37 d3
|
||||
; The default output delimiter character is $, but
|
||||
; you can change this value by using the BDOS Function
|
||||
; 110 Get/Set Output Delimiter.
|
||||
|
||||
db 0 ;* List Output Flag 38 d4
|
||||
; If this byte is reset to 0, console output is not
|
||||
; echoed to the list device. If this byte is set
|
||||
; to 1, console output is echoed to the list device.
|
||||
|
||||
db 0 ; Scroll flag 39 d5
|
||||
; Following bits set when in system bank and:
|
||||
; Bit 7 is set when function 11 is checking the status.
|
||||
; Bit 6 is set when function 2 is checking input.
|
||||
; Note that raw input (function 6 and function 2 raw)
|
||||
; will not set these bits.
|
||||
|
||||
dw scb ; Holds the address of the SCB 3a d6
|
||||
|
||||
dw 0080h ;+ Current DMA Address. 3c d8
|
||||
; This address can be set by BDOS Function 26. The
|
||||
; CCP initializes this value to 0080h. BDOS Function
|
||||
; 13, Reset Disk System also sets the DMA address to
|
||||
; 0080h.
|
||||
|
||||
db 0 ; Current Disk. 3e da
|
||||
; This byte contains the currently selected default
|
||||
; disk number. This value ranges from 0-15
|
||||
; corresponding to drives a-p, respectively. BDOS
|
||||
; Function 24, Return Current Disk, can be used to
|
||||
; determine the current disk value.
|
||||
|
||||
dw 0 ; BDOS variable 'INFO' 3f db
|
||||
; This word is used by the banked portion of the
|
||||
; BDOS. It is normally an entry parameter.
|
||||
|
||||
db 0 ; FCB flag 41 dd
|
||||
; If this byte = 0ffh, the word at 03fh is a valid
|
||||
; FCB address.
|
||||
|
||||
db 0 ; Same drive flag 42 de
|
||||
|
||||
db 0 ;+ BDOS function for error 43 df
|
||||
|
||||
db 0 ; Current User Number. 44 e0
|
||||
; This byte contains the current user number. This
|
||||
; value ranges from 0-15. BDOS Function 32,
|
||||
; Get/Set User Code can change or interrogate
|
||||
; the currently active user number. Under ZPM3 you may
|
||||
; change the currently active user number directly
|
||||
; by writing to this byte.
|
||||
|
||||
dw 0 ;+ Reserved 45 e1
|
||||
; Holds the current directory entry number. Lower
|
||||
; two bits are the search return code.
|
||||
|
||||
dw 0 ;+ Search FCB address 47 e3
|
||||
; Holds the FCB address of the last search for
|
||||
; first/next operation.
|
||||
|
||||
db 0 ;+ Search type flag 49 e5
|
||||
; 0=? in drive code search.
|
||||
; 0fh=normal search.
|
||||
|
||||
db 01 ;* BDOS Multi-Sector Count. 4a e6
|
||||
; This field is set by BDOS Function 44, Set Multi-
|
||||
; Sector Count.
|
||||
|
||||
db 0 ;* BDOS Error Mode. 4b e7
|
||||
; This field is set by BDOS Function 45, Set BDOS
|
||||
; Error Mode. If this byte is set to 0ffh, the
|
||||
; system returns to the current program without
|
||||
; displaying any error messages.
|
||||
|
||||
|
||||
db 0 ;* Drive Search Chain 1 4c e8
|
||||
db 0ffh ;* Drive Search Chain 2 4d e9
|
||||
db 0ffh ;* Drive Search Chain 3 4e ea
|
||||
db 0ffh ;* Drive Search Chain 4 4f eb
|
||||
|
||||
db 0 ;* Temporary File Drive 50 ec
|
||||
|
||||
db 0 ; Error Drive. 51 ed
|
||||
; This byte contains the drive number of the selected
|
||||
; drive when the last physical or extended error
|
||||
; occured.
|
||||
|
||||
db 0 ; Reserved 52 ee
|
||||
db 0 ; Reserved 53 ef
|
||||
|
||||
db 0 ; Media Flag 54 f0
|
||||
; This flag may be set by the BIOS to indicate that
|
||||
; a drive door has opened thus signalling the BDOS
|
||||
; to relog the drive if required.
|
||||
db 0 ; Reserved 55 f1
|
||||
db 0 ; Reserved 56 f2
|
||||
|
||||
db 080h ; BDOS Flags. 57 f3
|
||||
; bit 7= expanded error messages
|
||||
; 6= single byte allocation vectors
|
||||
|
||||
dw 0ffffh ;* Date in days in binary since 1 Jan 78 58 f4
|
||||
db 0ffh ;* Hour in BCD 5a f6
|
||||
db 0ffh ;* Minutes in BCD 5b f7
|
||||
db 0ffh ;* Seconds in BCD 5c f8
|
||||
|
||||
COMBASE:
|
||||
dw 0 ; Common Memory Base address 5d f9
|
||||
; This value is zero for nonbanked systems, and
|
||||
; nonzero for banked systems. Because the base
|
||||
; address must reside on a page boundary, the
|
||||
; first byte will always be 0. The second byte
|
||||
; is the important one being the common memory
|
||||
; base page.
|
||||
|
||||
jp bnkdos2 ; Pointer to second entry in banked DOS 5f fb
|
||||
; This entry handles the displaying of errors to
|
||||
; the user
|
||||
|
||||
dw start ; Top of user TPA 62 fe
|
||||
; This word always reflects the top of TPA and
|
||||
; should be the same as the word at 0006h unless a
|
||||
; transient changes (0006h) without knowing about
|
||||
; this word
|
||||
|
||||
BIN
Source/ZPM3/setz3.com
Normal file
BIN
Source/ZPM3/setz3.com
Normal file
Binary file not shown.
80
Source/ZPM3/setz3.z80
Normal file
80
Source/ZPM3/setz3.z80
Normal file
@@ -0,0 +1,80 @@
|
||||
|
||||
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; S E T Z 3
|
||||
; for ZPM3
|
||||
; by Simeon Cran
|
||||
; 30/3/92
|
||||
;
|
||||
; This program automatically sets the system environment address in the ZPM3
|
||||
; SCB for Z3PLUS users. Certain advanced ZCPR facilities such as wheel
|
||||
; protection of files will then be activated.
|
||||
;
|
||||
; Z3PLUS users should run SETZ3.COM once when they start up Z3PLUS and again
|
||||
; when returning to regular (non-Z-System) operation. When run after Z3PLUS
|
||||
; is started, the SCB environment address word is set with the ZCPR environment
|
||||
; address. When run after returning to regular operation, the SCB environment
|
||||
; address word is cleared to 0000h.
|
||||
;
|
||||
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
;===============================================================================
|
||||
|
||||
BDOS equ 5
|
||||
deffcb equ 5ch
|
||||
SCBfunc equ 31h ; Get/Set SCB function number
|
||||
SCBoff equ 3bh ; Offset in SCB to get SCB base page
|
||||
Z3ENVoff equ 83h ; Offset in SCB base page of the ZCPR system
|
||||
; environment pointer.
|
||||
|
||||
jp start ; Jump over general data
|
||||
db 'Z3ENV'
|
||||
db 1
|
||||
Z3ENV: dw 0
|
||||
dw 0
|
||||
HELPmsg:
|
||||
db ' SYNTAX:'
|
||||
db 10,13
|
||||
db ' SETZ3'
|
||||
db 10,13
|
||||
db ' Sets the ZCPR environment address in the SCB,'
|
||||
db 10,13
|
||||
db ' or else clears it if not running ZCPR.'
|
||||
db 10,13
|
||||
db ' SETZ3 // Displays this brief help message'
|
||||
db '$'
|
||||
|
||||
HELP: ld de,HELPmsg
|
||||
MSGexit:
|
||||
ld c,9
|
||||
call bdos
|
||||
rst 0
|
||||
|
||||
start: ; Get the address of the SCB environment address pointer.
|
||||
ld de,(Z3ENV)
|
||||
ld a,d
|
||||
or e ; Has it been set by Z3PLUS?
|
||||
jr nz,Zinstall ; Jump if it has
|
||||
ex de,hl
|
||||
ld a,d
|
||||
or e ; Was it in HL instead?
|
||||
jr nz,Zinstall
|
||||
Zinstall: ; DE holds 0 if uninstalling, otherwise the address of the
|
||||
; ZCPR evironment descriptor.
|
||||
push de
|
||||
ld c,SCBfunc
|
||||
ld de,SCBPB
|
||||
call bdos ; Get base page of SCB
|
||||
ld h,a
|
||||
ld l,Z3ENVoff ; HL is now the address of the word
|
||||
pop de
|
||||
ld (hl),e
|
||||
inc hl
|
||||
ld (hl),d ; Set it appropriately
|
||||
rst 0 ; And exit.
|
||||
|
||||
|
||||
SCBPB: ; System control block function parameter block.
|
||||
db 03bh
|
||||
db 0 ; Get operation
|
||||
|
||||
|
||||
35
Source/ZPM3/version.not
Normal file
35
Source/ZPM3/version.not
Normal file
@@ -0,0 +1,35 @@
|
||||
ZPM3 by Simeon Cran.
|
||||
====================
|
||||
ZPM3 is a Z80 coded BDOS replacement for banked CP/M 3.0 systems.
|
||||
|
||||
This is release 0010 on 1/2/93.
|
||||
|
||||
Since version 0009 the .SPR files have been updated. They are
|
||||
slightly faster and will possibly work on the Bondwell or other
|
||||
machines that they seemed to fail on before. ZPM3LDR.REL has also
|
||||
been modified. The main improvements throughout should be in
|
||||
speed. The differences may not be obvious, but you should upgrade
|
||||
to this latest version. SJC.
|
||||
|
||||
Files in this release are:
|
||||
|
||||
VERSION.NOT
|
||||
ZPM3.TXT
|
||||
RESBDOS3.SPR
|
||||
BNKBDOS3.SPR
|
||||
AUTOTOG.COM
|
||||
AUTOTOG.Z80
|
||||
SETZ3.COM
|
||||
SETZ3.Z80
|
||||
MAKEDOS.COM
|
||||
MAKEDOS.TXT
|
||||
BIOS.TXT
|
||||
SCB.TXT
|
||||
ZPM3LDR.TXT
|
||||
ZPM3LDR.REL
|
||||
CLRHIST.COM
|
||||
CLRHIST.Z80
|
||||
ECHOTERM.COM
|
||||
============
|
||||
17 files
|
||||
============
|
||||
BIN
Source/ZPM3/zinstal.zpm
Normal file
BIN
Source/ZPM3/zinstal.zpm
Normal file
Binary file not shown.
483
Source/ZPM3/zpm3.txt
Normal file
483
Source/ZPM3/zpm3.txt
Normal file
@@ -0,0 +1,483 @@
|
||||
|
||||
Z P M 3 by Simeon Cran
|
||||
========================
|
||||
|
||||
A Z80 coded CP/M 3.0 compatible BDOS replacement.
|
||||
|
||||
The first public release: 27/3/92
|
||||
This document dated: 16/6/92
|
||||
|
||||
Distributed at: Z-Node 62 (Perth, Western Australia)
|
||||
V21,V22,V22bis 09 450 0200
|
||||
|
||||
|
||||
WELCOME TO ZPM3
|
||||
~~~~~~~~~~~~~~~
|
||||
Welcome to the best CP/M compatible operating system for Z80
|
||||
based computers with banked memory. The best? Yes, we believe so.
|
||||
CP/M 3.0 has had bad press, but the fact is that it is faster
|
||||
than CP/M 2.2 ever was, and it offered more integrated
|
||||
facilities. Perhaps it was all the Z80 replacement BDOSes for
|
||||
CP/M 2.2 which stole the limelight from CP/M 3.0, or was it just
|
||||
that few computers had the required banked memory?
|
||||
|
||||
Whatever the reason for CP/M 3.0's lack of success in the
|
||||
marketplace, there are still plenty of users who will stand by
|
||||
its wonderful facilities and speed. For those users ZPM3 provides
|
||||
the long awaited Z80 coded update.
|
||||
|
||||
ZPM3 offers all the good things that CP/M 3.0 does, and then it
|
||||
offers more. Because ZPM3 is written in Z80 code rather than the
|
||||
8080 code of CP/M 3.0, it can do everything that CP/M 3.0 does,
|
||||
but in much less space. With the extra space recovered, ZPM3
|
||||
packs in a number of new facilities. Yet the whole package fits
|
||||
in exactly the same space as CP/M 3.0 so you can directly replace
|
||||
your old CP/M 3.0 BDOS with ZPM3 without a worry.
|
||||
|
||||
ZPM3 is also fast. Faster, in fact, than CP/M 3.0. This is
|
||||
possible because the rich Z80 instruction set allows many
|
||||
algorithms to be implemented more efficiently. In addition, the
|
||||
extra space available in ZPM3 has been put to use to further
|
||||
optimise the code. Lots of small optimisations smooth the
|
||||
execution flow, so ZPM3 becomes the fastest operating system on
|
||||
most banked CP/M computers.
|
||||
|
||||
|
||||
THE FEATURES
|
||||
~~~~~~~~~~~~
|
||||
ZPM3, in addition to complete CP/M 3.0 compatibility, offers the
|
||||
following features:
|
||||
|
||||
|
||||
Random Read Bug fixed.
|
||||
++++++++++++++++++++++
|
||||
Maybe you didn't know, but CP/M 3.0 has a bug. It affects random
|
||||
reads under very specific circumstances, and can result in a
|
||||
program thinking that you don't have some pieces of data in a
|
||||
file when in fact you do. The bug would occur very, very rarely,
|
||||
but it is real. ZPM3 finally squashes it.
|
||||
|
||||
|
||||
Protected SCB User code
|
||||
+++++++++++++++++++++++
|
||||
The System Control Block of CP/M 3.0 was a revolution at the
|
||||
time. ZCPR has a system environment and most other operating
|
||||
systems have other similar structures, but the SCB of CP/M 3.0
|
||||
was one of the very first.
|
||||
|
||||
Unfortunately, Digital Research never properly documented it, and
|
||||
some programmers found things out about it that weren't quite
|
||||
true and started programming accordingly. As well, because it is
|
||||
available in the TPA bank, runaway programs can overwrite it
|
||||
causing problems.
|
||||
|
||||
Mostly though, the SCB will survive, or at least any problems
|
||||
will be so obvious that the user will realise that a crash has
|
||||
occurred and will reboot. A real problem exists with the CP/M 3.0
|
||||
code however when the user value is written over with a value
|
||||
above 15. Many programs now directly write to this byte, and if
|
||||
they put a value in that is above 15, all sorts of havoc can
|
||||
happen with the disk system. Actually, CP/M 3.0 will handle user
|
||||
areas above 15 with this method, and all seems ok until the
|
||||
operating system mistakes one of these directory entries as an
|
||||
XFCB. Simply put, user areas above 15 must not be used with CP/M
|
||||
3.0.
|
||||
|
||||
ZPM3 has code which prevents these problems, making the system
|
||||
even more stable.
|
||||
|
||||
|
||||
Obsoleted Trap system.
|
||||
++++++++++++++++++++++
|
||||
One of the problems of the banked operating system was that it
|
||||
was possible to redirect the BIOS to code below common memory, in
|
||||
which case the banked BDOS could not access it. One solution is
|
||||
to call all BIOS code from common memory, but this involves a
|
||||
bank switch for every BIOS call, and this slows things down
|
||||
considerably.
|
||||
|
||||
CP/M 3.0 got around the problem by providing special code just
|
||||
below the SCB. If you redirected the BIOS, you also had to change
|
||||
this code which caused a bank switch when your new BIOS routine
|
||||
was called. When you removed the redirection, you also had to
|
||||
restore the special code.
|
||||
|
||||
This system has major drawbacks. For a start, if you redirect the
|
||||
BIOS, then another program redirects your redirection, then you
|
||||
remove your first redirection (along with the special code), the
|
||||
bank switch won't happen for the second redirection and the
|
||||
system will crash.
|
||||
|
||||
If a CP/M 2.2 program tried to do the redirection, it would know
|
||||
nothing about CP/M 3.0 and would not adjust the special code, so
|
||||
a crash would result in that case too.
|
||||
|
||||
The special code was called the "Trap System" as it was meant to
|
||||
trap redirection (as long as you set the trap). ZPM3 has
|
||||
eliminated the need for the traps. They are still there, and
|
||||
programs can still fiddle with them, but it doesn't matter how
|
||||
they are set, they are ignored. There is simply no need for them
|
||||
anymore. And this has been achieved without a performance
|
||||
penalty. In fact, in the case of a program which sets the traps
|
||||
but forgets to restore them, performance is now much better.
|
||||
|
||||
|
||||
Semi-Permanent Read Only status for drives.
|
||||
+++++++++++++++++++++++++++++++++++++++++++
|
||||
In recent years, a trend in CP/M 2.2 is to make drives which have
|
||||
been set read only to remain that way until explicitly changed by
|
||||
function 37. ZPM3 now adopts this logic. Previously a control-C
|
||||
would return a read only drive to read write. The advantage is
|
||||
that a program can now make a drive read only for a session and
|
||||
know that it will stay that way.
|
||||
|
||||
|
||||
ZCPR compatible function 152
|
||||
++++++++++++++++++++++++++++
|
||||
Function 152 is the CP/M 3.0 parser. It was a great innovation at
|
||||
the time as parsing is one of the more tedious aspects of
|
||||
programming for CP/M. Unfortunately, almost as soon as it
|
||||
appeared, it was made obsolete by the fact that it didn't handle
|
||||
references to user number (DU references). A line such as
|
||||
A:FILE.TYP would be correctly parsed, but A3:FILE.TYP would not.
|
||||
CP/M 3.0 programs would often parse the drive and user
|
||||
separately, then give function 152 the line without the DU:
|
||||
reference. All this extra work should not have been necessary if
|
||||
CP/M 3.0 had included user number parsing.
|
||||
|
||||
ZPM3 parses the user number, and goes even further by handling
|
||||
named directories for ZCPR. This is possible as long as you set a
|
||||
special word in the SCB which tells ZPM3 where to find the ZCPR
|
||||
system environment descriptor. ZCCP, a companion CCP for ZPM3,
|
||||
handles this automatically, but for Z3PLUS users, a special
|
||||
utility is available which automatically sets this word.
|
||||
|
||||
The result is that CP/M 3.0 programs will not balk at DU:
|
||||
references and ZPM3 aware programs can use the full DU: and DIR:
|
||||
facilities of function 152. It has also made the brilliant ZCCP
|
||||
code possible.
|
||||
|
||||
|
||||
New Functions 54 and 55
|
||||
+++++++++++++++++++++++
|
||||
Datestamps in CP/M 3.0 are wonderful, but difficult to
|
||||
manipulate. Two new functions make them easier to handle and at
|
||||
the same time give compatibility to Z80DOS aware programs.
|
||||
|
||||
Function 54 (Get Stamp) returns a Z80DOS compatible datestamp.
|
||||
Any program (such as many directory programs) which recognise the
|
||||
Z80DOS standard can make use of function 54. There is only one
|
||||
slight difference between Z80DOS datestamps and ZPM3's which you
|
||||
should be aware of. Z80DOS will return a correct datestamp after
|
||||
any successful open or search of any extent. ZPM3 can only return
|
||||
a correct datestamp after a successful open or search of the
|
||||
first extent of the file. This is because CP/M 3.0 datestamps are
|
||||
only saved for the first extents of each file, in order to
|
||||
provide the highest performance.
|
||||
|
||||
Even more interesting is Function 55 (Use Stamp) which provides a
|
||||
mechanism for changing datestamps on files. Trying to do this
|
||||
with CP/M 3.0 was virtually impossible because it involved direct
|
||||
sector writes. With Function 55 you can simply set the stamp and
|
||||
then write.
|
||||
|
||||
|
||||
Wheel protected files
|
||||
+++++++++++++++++++++
|
||||
If you are using a ZCPR system (ZCCP or Z3PLUS), ZPM3 has access
|
||||
to the wheel byte and supports wheel protected files. Such files
|
||||
act normally if the wheel is set (signifying a priveleged user),
|
||||
but if the wheel is not set, the files can not be changed. This
|
||||
is of most benefit to BBS systems. The implementation is
|
||||
virtually the same as most current Z80 CP/M 2.2 compatible
|
||||
BDOSes.
|
||||
|
||||
|
||||
Better error messages
|
||||
+++++++++++++++++++++
|
||||
CP/M 3.0 introduced the best error messages that CP/M had ever
|
||||
had. ZPM3 goes further. The main difference you will notice is
|
||||
that the user number as well as the drive is shown in the error
|
||||
message. This is invaluable in helping you identify which file
|
||||
might have caused a problem.
|
||||
|
||||
|
||||
Function 10 history buffer and improved editing.
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Function 10 is used by the CCP to input command lines. Many other
|
||||
programs use function 10 for input.
|
||||
|
||||
CP/M 3.0 introduced a history buffer for function 10. You press
|
||||
control-W and you were returned the last command. It is a great
|
||||
facility, but because it only remembers one command it is rather
|
||||
limited. There have been RSXes written which give a much larger
|
||||
history buffer, but RSXes take up extra program memory so are
|
||||
undesirable.
|
||||
|
||||
ZPM3 gives a large (approximately 250 bytes) history buffer which
|
||||
can store multiple commands. It also makes very intelligent use
|
||||
of the buffer so that identical commands are not stored twice,
|
||||
and commands of less than three characters are not stored. The
|
||||
history buffer takes up no additional memory, and is always
|
||||
available.
|
||||
|
||||
For security, it is possible to clear the history buffer so that
|
||||
other users can not see what commands you have used.
|
||||
|
||||
The ZPM3 history buffer feature is so good, that for many users,
|
||||
the ZPM3 upgrade is completely justified by it.
|
||||
|
||||
As part of the history buffer system, ZPM3 also offers a facility
|
||||
called Automatic Command Prompting. This can be disabled, or can
|
||||
be made switchable from the keyboard. When it is on, ZPM3 tries
|
||||
to fill in the rest of your command based on what commands you
|
||||
used most recently. It is like magic, and can save you typing out
|
||||
complicated commands many times. In effect, it looks through the
|
||||
history buffer for you and finds the command it thinks you want.
|
||||
As you keep typing, if it turns out that the command doesn't
|
||||
match anymore, it will try to match another command, and if it
|
||||
can't, it lets you make the command by yourself. This facility is
|
||||
quite amazing to watch.
|
||||
|
||||
And to integrate the history buffer and the automatic command
|
||||
prompting, function 10 has the best command line editing you'll
|
||||
find anywhere. Most of the control keys do something when you are
|
||||
editing a function 10 line, and for the most part they mimic the
|
||||
standard WordStar/NewWord/ZDE functions. You can jump to
|
||||
different words in the command, delete individual words, delete
|
||||
individual letters, insert letters, and a whole lot more.
|
||||
|
||||
|
||||
Here is a list of what the various control keys do for function
|
||||
10:
|
||||
|
||||
A Move left one word
|
||||
B Go to the beginning or end of the line
|
||||
C Warm boot if at start of line, otherwise nothing
|
||||
D Go right one character
|
||||
E Go backwards one command in the history buffer
|
||||
F Go right one word
|
||||
G Delete current character
|
||||
H Destructive backspace
|
||||
I
|
||||
J Enter line
|
||||
K Delete all to the right
|
||||
L
|
||||
M Enter line
|
||||
N
|
||||
O
|
||||
P Toggle printing
|
||||
Q Toggle automatic command prompting (if enabled)
|
||||
R
|
||||
S Go left one character
|
||||
T Delete current word
|
||||
U Add current line to history buffer
|
||||
V Clear line and delete from history buffer
|
||||
W Go forwards one command in the history buffer
|
||||
X Delete all to the left
|
||||
Y Clear the whole line
|
||||
Z
|
||||
|
||||
|
||||
CPMLDR.REL bug fixed.
|
||||
+++++++++++++++++++++
|
||||
If you have ever tried to use the CPMLDR.REL code supplied with
|
||||
CP/M 3.0 to load a CPM3.SYS file larger than 16k, you have
|
||||
probably come across the CPMLDR.REL bug. The computer probably
|
||||
crashed, and you were left wondering what you did wrong in your
|
||||
bios.
|
||||
|
||||
Well CPMLDR.REL has a bug. To solve this for you ZPM3 comes with
|
||||
ZPM3LDR.REL which directly replaces CPMLDR.REL. It is also
|
||||
somewhat better in that all the messages, and the fcb for loading
|
||||
CPM3.SYS, are at the start of the file along with plenty of spare
|
||||
room. As a result you can easily patch the signon and error
|
||||
messages to say whatever you like and even change the FCB to load
|
||||
a file called something other than CPM3.SYS.
|
||||
|
||||
|
||||
|
||||
|
||||
All About the Random Read Bug.
|
||||
==============================
|
||||
Never heard of it? Well it's there in CP/M 3.0. I spent a lot of
|
||||
time trying to work out what it was and just why it was
|
||||
happening, and if you are interested, here are the details.
|
||||
|
||||
CP/M 3.0 uses the Record Count byte of an active FCB a little
|
||||
differently from the way CP/M 2.2 does. It is mentioned in the
|
||||
CP/M 3.0 manuals that the record count may contain numbers
|
||||
greater than 128, but in such a case it implies that the record
|
||||
count is really 128. CP/M 2.2 would not return record counts
|
||||
greater than 128.
|
||||
|
||||
The reason for the use of the record count in this way is to help
|
||||
speed up some of the logic used to find records in a file. It
|
||||
works very well for sequential access. When it comes to random
|
||||
access, the system has some failings.
|
||||
|
||||
The idea behind CP/M 3.0's unusual use of the record count is to
|
||||
keep the record count of the last logical extent of the current
|
||||
physical extent always in the Record Count byte. When accessing
|
||||
extents before the last one, bit 7 of the byte is set. That way
|
||||
it will always be at least 128 for logical extents before the
|
||||
last (which CP/M 3.0 translates to mean equal to 128), and the
|
||||
lower 7 bits are used as convenient storage for the record count
|
||||
of the last logical extent. This is particularly convenient
|
||||
because it means there is no need to go and read the directory
|
||||
entry again when it comes time to read the last logical extent.
|
||||
|
||||
I hope you have followed that! In sequential access, this scheme
|
||||
is great. The problem occurs with random access. In this case it
|
||||
is possible to access a logical extent which has no records in
|
||||
it. This could be any logical extent past the last one. In such a
|
||||
case the record count must be returned as 0 (which is correct).
|
||||
If we then go back to a previous logical extent in the same
|
||||
physical extent, CP/M 3.0 gets confused and assumes that there
|
||||
must be 128 records in that extent because the one we just came
|
||||
from had no records and we are now accessing an earlier extent.
|
||||
You're probably well and truly lost by now!
|
||||
|
||||
Anyhow, the assumption that CP/M 3.0 makes is quite wrong. The
|
||||
record count ends up being set to 128, a read is allowed to go
|
||||
ahead as if nothing was wrong, no error is returned, and the
|
||||
record count remains incorrectly set until a different physical
|
||||
extent is opened. The result could be chaos, but mostly it just
|
||||
means that a program returns the wrong information.
|
||||
|
||||
Remember, a logical extent is always 16k. A physical extent can
|
||||
be a multiple of 16k and is all the data described by one
|
||||
directory entry. If your system has physical extents which are
|
||||
16k, you would never have the problem because a new physical
|
||||
extent would be properly opened for every new logical extent that
|
||||
was accessed.
|
||||
|
||||
Typically though, a physical extent is 32k, so it holds 2 logical
|
||||
extents. The problem won't arise until the file grows past the
|
||||
32k mark in such a case. And when the file gets over 48k the
|
||||
problem can't occur again until it gets over 64k... and so on.
|
||||
Even then, it can only happen if reads are attempted to
|
||||
particular extents in a particular order. So you shouldn't be too
|
||||
surprised if the bug hasn't been too noticeable to you.
|
||||
|
||||
ZPM3 squashes the bug once and for all by using the correct
|
||||
logic. In the situation where the bug would normally occur, ZPM3
|
||||
makes sure it gets the correct record count information, and the
|
||||
reads return the correct record count every time.
|
||||
|
||||
If you are interested in seeing a demonstration of the bug in
|
||||
action (on CP/M 3.0) and comparing it with ZPM3, there is a file
|
||||
floating around various bulletin boards which contains
|
||||
demonstrations for the bug and an RSX to fix it. The RSX is a
|
||||
less than perfect way of overcoming the bug, although it seems to
|
||||
work. However, now that you have ZPM3, you don't need to worry.
|
||||
|
||||
|
||||
|
||||
|
||||
Other things you should know about ZPM3
|
||||
=======================================
|
||||
ZPM3 has worked on EVERY CP/M 3.0 system tried so far except one.
|
||||
This is a Bondwell computer, and as yet it isn't clear why it
|
||||
won't work. I will study the source code of its BIOS and come up
|
||||
with a fix shortly.
|
||||
|
||||
The MAKEDOS.COM utility is not perfect (as mentioned previously)
|
||||
and it seems that nobody has managed to get it to work with the
|
||||
Commodore C128 system. You must use the conventional method for
|
||||
installing ZPM3 on such systems.
|
||||
|
||||
If you have a computer that ZPM3 will not install on with MAKEDOS
|
||||
and you do not have access to the files required to do a
|
||||
conventional install, please contact me. I am interested in
|
||||
making ZPM3 as universal as possible and will help you to install
|
||||
it on your system.
|
||||
|
||||
The ESCAPE key is ignored by function 10. There has been some
|
||||
lively discussion about this but the decision is final: it stays
|
||||
ignored. Remember what function 10 is for and you will understand
|
||||
why I made it ignore the ESCAPE key. The argument against this
|
||||
has been from people who control their terminals from the command
|
||||
line. Apparently some people type in an escape sequence at the
|
||||
command line (which CP/M 3.0 will not output correctly anyhow
|
||||
(converting the escape character to ^[)) then press return to
|
||||
have the CCP echo back the line including the escape character.
|
||||
|
||||
Sorry folks, that is a KLUDGE in my books! Anybody using Z-System
|
||||
would of course use an ALIAS and ECHO to do this properly, but
|
||||
for those who will continue to complain that I have sacrificed
|
||||
CP/M 3.0 compatibility I am now including ECHOTERM.COM to solve
|
||||
your problems. Run it and whatever you type will be sent to the
|
||||
terminal correctly after you press RETURN. Press RETURN twice to
|
||||
exit the program.
|
||||
|
||||
And a reminder that the ability to put control characters into
|
||||
function 10 lines was always limited by the fact that some
|
||||
control keys were used to edit the command line. CP/M 3.0 added
|
||||
even more, and ZPM3 uses virtually all the control keys. The few
|
||||
that aren't used are ignored, and this is in fact a FEATURE which
|
||||
guarantees that unusable characters can't get into function 10
|
||||
lines by accident.
|
||||
|
||||
|
||||
|
||||
|
||||
LEGALS and SUCH
|
||||
===============
|
||||
The ZPM3 package is supplied free of charge, on the condition
|
||||
that you don't use it to make money. If you want to use it
|
||||
commercially you must contact me to get the OK (and negotiate our
|
||||
fee).
|
||||
|
||||
If you find anyone (except myself) charging money for ZPM3,
|
||||
please inform me!
|
||||
|
||||
Nobody is making any guarantees about this software. None at all.
|
||||
If it causes your house to burn down, or a divorce, or just a bad
|
||||
day, this is unfortunate, regrettable, but there is nothing that
|
||||
I can or will do about it. You have been warned.
|
||||
|
||||
The ZPM3 package must only be distributed in the form that you
|
||||
found it. Do not change or add anything. Don't even change it
|
||||
into a different type of archive. Just leave it alone. However
|
||||
you are free to distribute it to as many places and people that
|
||||
you can. Just don't charge for it.
|
||||
|
||||
|
||||
|
||||
If in using ZPM3 you find that it doesn't act as described,
|
||||
please forward the details to me so that either the ZPM3 code or
|
||||
the documentation can be changed. If you would like further
|
||||
details, please forward your specific questions to me. SJC.
|
||||
|
||||
|
||||
|
||||
|
||||
As a service to all our ZPM3 fans, the latest version of the ZPM3
|
||||
package can now be ordered. At this stage we can only supply IBM
|
||||
formatted 3.5 inch 720k disks, however if you are keen enough
|
||||
that shouldn't matter. ZPM3 remains free, however this service
|
||||
will cost you $15 Australian (for the disk, copying, postage and
|
||||
packing) to most places in the Western World (others by
|
||||
arrangement).
|
||||
|
||||
This is a good way to guarantee you have the latest version, and
|
||||
to guarantee that your package has not been corrupted by some
|
||||
unscrupulous person.
|
||||
|
||||
When we fill your order, we will make sure to include the latest
|
||||
demonstration copy of MYZ80 - the fastest and best Z80 emulator
|
||||
for IBM AT (and better) compatibles. MYZ80 can run ZPM3 with
|
||||
ease. It also handles ZCPR and CP/M 2.2. And yes, we do mean
|
||||
FASTEST.
|
||||
|
||||
Send your international money order to:
|
||||
|
||||
Software by Simeon
|
||||
ZPM3 Package
|
||||
2 Maytone Ave
|
||||
Killara NSW
|
||||
Australia 2071
|
||||
|
||||
Your order will be promptly filled.
|
||||
|
||||
BIN
Source/ZPM3/zpm3ldr.rel
Normal file
BIN
Source/ZPM3/zpm3ldr.rel
Normal file
Binary file not shown.
68
Source/ZPM3/zpm3ldr.txt
Normal file
68
Source/ZPM3/zpm3ldr.txt
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
|
||||
ZPM3LDR.REL
|
||||
===========
|
||||
|
||||
A CPMLDR.REL replacement for CP/M 3.0 and ZPM3 systems.
|
||||
|
||||
|
||||
CPMLDR.REL, as supplied by DRI, has a bug on some systems which
|
||||
prevents the loading of CPM3.SYS files larger than 16k. This is a
|
||||
significant problem especially if you intend to enlarge your bios
|
||||
or increase the number of buffers allocated to your system.
|
||||
|
||||
ZPM3LDR.REL was developed primarily to overcome this bug.
|
||||
ZPM3LDR.REL is able to load CPM3.SYS files up to the maximum
|
||||
possible system size without any problem. ZPM3LDR.REL also offers
|
||||
some convenient enhancements.
|
||||
|
||||
|
||||
The usual way to use ZPM3LDR.REL is exactly as you would use
|
||||
CPMLDR.REL: link it to your loader bios and SCB.REL files to make
|
||||
the loader program which must be installed onto your system
|
||||
tracks. Before you install the program however, you may choose to
|
||||
patch the file at locations provided for in ZPM3LDR.REL.
|
||||
|
||||
The messages issued by ZPM3LDR can be changed. They take a
|
||||
standard '$' terminated form (as used by BDOS function 9). Using
|
||||
a debugger such as SID.COM, you should be able to view these
|
||||
messages and note that they have extra '$' terminators at then
|
||||
end of each. This is the room in which you may expand or alter
|
||||
the ZPM3LDR messages. Just remember not to overwrite the next
|
||||
message.
|
||||
|
||||
The CPM3.SYS FCB will be visible there too, allowing you to
|
||||
change it so that ZPM3LDR will load a file of a different name
|
||||
instead.
|
||||
|
||||
The copyright message is there but not to show that DRI has
|
||||
copyright on ZPM3LDR.REL (which it doesn't!). That is part of an
|
||||
advanced feature of ZPM3LDR.REL which allows it to check for
|
||||
valid CPM3.SYS files. CPMLDR.REL would attempt to load any file
|
||||
called CPM3.SYS, even if it wasn't really a CP/M 3.0 system file.
|
||||
The results could be catastrophic. ZPM3LDR.REL will always check
|
||||
for the 112 byte signature at the start of the file, and will
|
||||
refuse to load CPM3.SYS unless the signature is correct.
|
||||
|
||||
This has another advantage. You may patch this signature to
|
||||
whatever you wish. Then, after generating your CPM3.SYS file
|
||||
(using GENCPM.COM) you should patch it too. The patch might be to
|
||||
put in the version of your BIOS or some such thing. On MYZ80, I
|
||||
use this system whenever I change the MYZ80 80x86 bios in such a
|
||||
way that the CPM3.SYS files won't work properly anymore. That
|
||||
way, any old CPM3.SYS files that are not valid anymore, won't get
|
||||
loaded accidentally.
|
||||
|
||||
For your information, the first 128 bytes of CPM3.SYS always
|
||||
begin with 6 bytes which tell CPMLDR where to load each section
|
||||
and where the cold boot entry is. After that there are 10 bytes
|
||||
of 0. ZPM3LDR does not check these bytes against anything so you
|
||||
can patch them with whatever you like.
|
||||
|
||||
The next 112 bytes would normally contain the DRI copyright
|
||||
message, the serial number of your system, then a fill of 0 bytes
|
||||
to the next record. Because ZPM3LDR looks for the copyright
|
||||
message as a signature of a valid CPM3.SYS, if it is changed, you
|
||||
will have to change ZPM3LDR as well.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user