forked from MirrorRepos/RomWBW
63 changed files with 7259 additions and 39 deletions
@ -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 |
|||
|
|||
@ -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 |
|||
@ -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 |
|||
Binary file not shown.
@ -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 |
|||
@ -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 |
|||
Binary file not shown.
@ -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 |
|||
Binary file not shown.
@ -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 |
|||
@ -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 |
|||
|
|||
Binary file not shown.
File diff suppressed because it is too large
@ -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 |
|||
@ -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 |
|||
@ -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 |
|||
|
|||
Binary file not shown.
@ -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 |
|||
|
|||
@ -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 |
|||
|
|||
@ -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 |
|||
|
|||
@ -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 |
|||
@ -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 |
|||
@ -0,0 +1,6 @@ |
|||
; global assembler options for BANKED BIOS |
|||
|
|||
true equ -1 |
|||
false equ not true |
|||
|
|||
banked equ true |
|||
@ -0,0 +1,6 @@ |
|||
; global assembler options for NONBANKED BIOS |
|||
|
|||
true equ -1 |
|||
false equ not true |
|||
|
|||
banked equ false |
|||
@ -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. |
|||
Binary file not shown.
@ -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 |
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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. |
|||
|
|||
|
|||
Binary file not shown.
Binary file not shown.
@ -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 * |
|||
******************************************************************************* |
|||
|
|||
Binary file not shown.
@ -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 |
|||
@ -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 |
|||
Binary file not shown.
@ -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 |
|||
|
|||
|
|||
@ -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! |
|||
|
|||
Binary file not shown.
Binary file not shown.
@ -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 |
|||
|
|||
|
|||
Binary file not shown.
@ -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. |
|||
Binary file not shown.
@ -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 |
|||
|
|||
Binary file not shown.
@ -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 |
|||
|
|||
|
|||
@ -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 |
|||
============ |
|||
Binary file not shown.
@ -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. |
|||
|
|||
Binary file not shown.
@ -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. |
|||
|
|||
|
|||
Loading…
Reference in new issue