From 57c87db9a127072c838acaef5f9842706ad9a62e Mon Sep 17 00:00:00 2001 From: Wayne Warthen Date: Mon, 14 Oct 2019 16:30:19 -0700 Subject: [PATCH] Preliminary CP/M 3 --- Doc/ChangeLog.txt | 1 + ReadMe.txt | 14 +- Source/BuildShared.cmd | 3 + Source/CBIOS/ver.inc | 2 +- Source/CPM3/@banks.txt | 28 + Source/CPM3/Build.cmd | 99 +++ Source/CPM3/Clean.cmd | 13 + Source/CPM3/bdos3.spr | Bin 0 -> 9856 bytes Source/CPM3/bioskrnl.asm | 673 ++++++++++++++++ Source/CPM3/biosldr.z80 | 480 ++++++++++++ Source/CPM3/bnkbdos3.spr | Bin 0 -> 13568 bytes Source/CPM3/boot.z80 | 362 +++++++++ Source/CPM3/ccp.com | Bin 0 -> 3200 bytes Source/CPM3/chario.z80 | 193 +++++ Source/CPM3/cpm3.lib | 180 +++++ Source/CPM3/cpm3fix.pat | Bin 0 -> 38272 bytes Source/CPM3/cpmldr.asm | 1572 ++++++++++++++++++++++++++++++++++++++ Source/CPM3/diskio.z80 | 781 +++++++++++++++++++ Source/CPM3/drvtbl.z80 | 12 + Source/CPM3/genbnk.dat | 158 ++++ Source/CPM3/gencpm.com | Bin 0 -> 21155 bytes Source/CPM3/genres.dat | 158 ++++ Source/CPM3/genres.old | 158 ++++ Source/CPM3/makedate.lib | 16 + Source/CPM3/modebaud.lib | 32 + Source/CPM3/move.z80 | 116 +++ Source/CPM3/optbnk.lib | 6 + Source/CPM3/optres.lib | 6 + Source/CPM3/readme.1st | 39 + Source/CPM3/resbdos3.spr | Bin 0 -> 2048 bytes Source/CPM3/scb.asm | 50 ++ Source/CPM3/zpmldr.com | Bin 0 -> 4608 bytes Source/Clean.cmd | 2 + Source/HBIOS/dbgmon.asm | 4 +- Source/HBIOS/hbios.asm | 47 +- Source/HBIOS/ver.inc | 2 +- Source/ZCCP/ccp.com | Bin 0 -> 3200 bytes Source/ZCCP/diskinfo.com | Bin 0 -> 2944 bytes Source/ZCCP/loadseg.com | Bin 0 -> 3456 bytes Source/ZCCP/read.me | 103 +++ Source/ZCCP/rsxdir.com | Bin 0 -> 1792 bytes Source/ZCCP/startzpm.com | Bin 0 -> 1024 bytes Source/ZCCP/zccp.txt | 308 ++++++++ Source/ZCCP/zinstal.zpm | Bin 0 -> 1536 bytes Source/ZPM3/Build.cmd | 61 ++ Source/ZPM3/Clean.cmd | 18 + Source/ZPM3/autotog.com | Bin 0 -> 512 bytes Source/ZPM3/autotog.z80 | 131 ++++ Source/ZPM3/bios.txt | 230 ++++++ Source/ZPM3/bnkbdos3.spr | Bin 0 -> 13568 bytes Source/ZPM3/clrhist.com | Bin 0 -> 128 bytes Source/ZPM3/clrhist.z80 | 49 ++ Source/ZPM3/makedos.com | Bin 0 -> 2176 bytes Source/ZPM3/makedos.txt | 90 +++ Source/ZPM3/resbdos3.spr | Bin 0 -> 2048 bytes Source/ZPM3/scb.txt | 435 +++++++++++ Source/ZPM3/setz3.com | Bin 0 -> 256 bytes Source/ZPM3/setz3.z80 | 80 ++ Source/ZPM3/version.not | 35 + Source/ZPM3/zinstal.zpm | Bin 0 -> 1536 bytes Source/ZPM3/zpm3.txt | 483 ++++++++++++ Source/ZPM3/zpm3ldr.rel | Bin 0 -> 2944 bytes Source/ZPM3/zpm3ldr.txt | 68 ++ 63 files changed, 7259 insertions(+), 39 deletions(-) create mode 100644 Source/CPM3/@banks.txt create mode 100644 Source/CPM3/Build.cmd create mode 100644 Source/CPM3/Clean.cmd create mode 100644 Source/CPM3/bdos3.spr create mode 100644 Source/CPM3/bioskrnl.asm create mode 100644 Source/CPM3/biosldr.z80 create mode 100644 Source/CPM3/bnkbdos3.spr create mode 100644 Source/CPM3/boot.z80 create mode 100644 Source/CPM3/ccp.com create mode 100644 Source/CPM3/chario.z80 create mode 100644 Source/CPM3/cpm3.lib create mode 100644 Source/CPM3/cpm3fix.pat create mode 100644 Source/CPM3/cpmldr.asm create mode 100644 Source/CPM3/diskio.z80 create mode 100644 Source/CPM3/drvtbl.z80 create mode 100644 Source/CPM3/genbnk.dat create mode 100644 Source/CPM3/gencpm.com create mode 100644 Source/CPM3/genres.dat create mode 100644 Source/CPM3/genres.old create mode 100644 Source/CPM3/makedate.lib create mode 100644 Source/CPM3/modebaud.lib create mode 100644 Source/CPM3/move.z80 create mode 100644 Source/CPM3/optbnk.lib create mode 100644 Source/CPM3/optres.lib create mode 100644 Source/CPM3/readme.1st create mode 100644 Source/CPM3/resbdos3.spr create mode 100644 Source/CPM3/scb.asm create mode 100644 Source/CPM3/zpmldr.com create mode 100644 Source/ZCCP/ccp.com create mode 100644 Source/ZCCP/diskinfo.com create mode 100644 Source/ZCCP/loadseg.com create mode 100644 Source/ZCCP/read.me create mode 100644 Source/ZCCP/rsxdir.com create mode 100644 Source/ZCCP/startzpm.com create mode 100644 Source/ZCCP/zccp.txt create mode 100644 Source/ZCCP/zinstal.zpm create mode 100644 Source/ZPM3/Build.cmd create mode 100644 Source/ZPM3/Clean.cmd create mode 100644 Source/ZPM3/autotog.com create mode 100644 Source/ZPM3/autotog.z80 create mode 100644 Source/ZPM3/bios.txt create mode 100644 Source/ZPM3/bnkbdos3.spr create mode 100644 Source/ZPM3/clrhist.com create mode 100644 Source/ZPM3/clrhist.z80 create mode 100644 Source/ZPM3/makedos.com create mode 100644 Source/ZPM3/makedos.txt create mode 100644 Source/ZPM3/resbdos3.spr create mode 100644 Source/ZPM3/scb.txt create mode 100644 Source/ZPM3/setz3.com create mode 100644 Source/ZPM3/setz3.z80 create mode 100644 Source/ZPM3/version.not create mode 100644 Source/ZPM3/zinstal.zpm create mode 100644 Source/ZPM3/zpm3.txt create mode 100644 Source/ZPM3/zpm3ldr.rel create mode 100644 Source/ZPM3/zpm3ldr.txt diff --git a/Doc/ChangeLog.txt b/Doc/ChangeLog.txt index 601d45be..ba2a36ed 100644 --- a/Doc/ChangeLog.txt +++ b/Doc/ChangeLog.txt @@ -26,6 +26,7 @@ Version 2.9.2 - WBW: Add support for secondry SPI (SD Card) on SC126 - PMS: Add sound support to NASCOM BASIC - WBW: Updated FAT to add MD and FORMAT commands +- WBW: Add CP/M 3 (experimental) Version 2.9.1 ------------- diff --git a/ReadMe.txt b/ReadMe.txt index 82b5053b..899657a3 100644 --- a/ReadMe.txt +++ b/ReadMe.txt @@ -7,7 +7,7 @@ *********************************************************************** Wayne Warthen (wwarthen@gmail.com) -Version 2.9.2-pre.17, 2019-10-11 +Version 2.9.2-pre.18, 2019-10-14 https://www.retrobrewcomputers.org/ RomWBW is a ROM-based implementation of CP/M-80 2.2 and Z-System for @@ -179,6 +179,18 @@ some potentially useful improvements. Please refer to "ZSDOS Manual.pdf" and "ZCPR Manual.pdf" in the Doc directory for more information on Z-System usage. +CP/M 3 +------ + +CP/M 3 exists in an experimental state. CP/M 3 must be started +from a disk drive. In the distribution archive, in the Binary +directory, you will find a cpm_hd.img file that can be copied +over to a CF or SD Card. Start your system with this card +installed and boot to CP/M 2.2 or ZSystem as usual. Switch to +the drive containing the CP/M 3 image and use the CPMLDR command +to load CP/M. It will ask you for the disk unit number containing +the CP/M 3 system files which are on the disk image you created. + ROM Customization ----------------- diff --git a/Source/BuildShared.cmd b/Source/BuildShared.cmd index c2852206..13c23f9d 100644 --- a/Source/BuildShared.cmd +++ b/Source/BuildShared.cmd @@ -7,4 +7,7 @@ setlocal & cd ZCPR && call Build || exit /b 1 & endlocal setlocal & cd ZCPR-DJ && call Build || exit /b 1 & endlocal setlocal & cd ZSDOS && call Build || exit /b 1 & endlocal setlocal & cd CBIOS && call Build || exit /b 1 & endlocal +setlocal & cd CPM3 && call Build || exit /b 1 & endlocal +setlocal & cd ZPM3 && call Build || exit /b 1 & endlocal setlocal & cd Forth && call Build || exit /b 1 & endlocal + diff --git a/Source/CBIOS/ver.inc b/Source/CBIOS/ver.inc index ed69f866..315bcced 100644 --- a/Source/CBIOS/ver.inc +++ b/Source/CBIOS/ver.inc @@ -2,4 +2,4 @@ #DEFINE RMN 9 #DEFINE RUP 2 #DEFINE RTP 0 -#DEFINE BIOSVER "2.9.2-pre.17" +#DEFINE BIOSVER "2.9.2-pre.18" diff --git a/Source/CPM3/@banks.txt b/Source/CPM3/@banks.txt new file mode 100644 index 00000000..7fb0d406 --- /dev/null +++ b/Source/CPM3/@banks.txt @@ -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 + diff --git a/Source/CPM3/Build.cmd b/Source/CPM3/Build.cmd new file mode 100644 index 00000000..a8ce11cf --- /dev/null +++ b/Source/CPM3/Build.cmd @@ -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 \ No newline at end of file diff --git a/Source/CPM3/Clean.cmd b/Source/CPM3/Clean.cmd new file mode 100644 index 00000000..d308082d --- /dev/null +++ b/Source/CPM3/Clean.cmd @@ -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 diff --git a/Source/CPM3/bdos3.spr b/Source/CPM3/bdos3.spr new file mode 100644 index 0000000000000000000000000000000000000000..728fe2af69efc063315e597bec713fe1faf61c2f GIT binary patch literal 9856 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 literal 0 HcmV?d00001 diff --git a/Source/CPM3/bioskrnl.asm b/Source/CPM3/bioskrnl.asm new file mode 100644 index 00000000..7056e025 --- /dev/null +++ b/Source/CPM3/bioskrnl.asm @@ -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 + extrn ?cinit ; (re)initialize device in + 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 + 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 + ; to all selected devices + +conout: + + lhld @covec ; fetch console output bit vector + jmp out$scan + + + ; AUXOUT + ; Auxiliary Output. Send character in + ; to all selected devices + +auxout: + lhld @aovec ; fetch aux output bit vector + jmp out$scan + + + ; LIST + ; List Output. Send character in + ; 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 + 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 and saved + push b ! push h + call ?cist + pop h ! pop b + ora a + ret + +cost1: ; get output status, saving & + push b ! push h + call ?cost + pop h ! pop b + ora a + ret + +ci1: ; get input, saving & + 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 @ up to a null + ; saves & + 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 + 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 . + ; Invoke login procedure for drive + ; if this is first select. Return + ; address of disk parameter header + ; in + +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 & + 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 + ; in @TRK for further operations. + +settrk: + mov l,c ! mov h,b + shld @trk + ret + + + ; SETSEC + ; Set Sector. Saves sector number from + ; in @sect for further operations. + +setsec: + mov l,c ! mov h,b + shld @sect + ret + + + ; SETDMA + ; Set Disk Memory Address. Saves DMA address + ; from 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 + ; with sector in . Returns physical sector + ; in . If no skew table (=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 diff --git a/Source/CPM3/biosldr.z80 b/Source/CPM3/biosldr.z80 new file mode 100644 index 00000000..3b7e0751 --- /dev/null +++ b/Source/CPM3/biosldr.z80 @@ -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 \ No newline at end of file diff --git a/Source/CPM3/bnkbdos3.spr b/Source/CPM3/bnkbdos3.spr new file mode 100644 index 0000000000000000000000000000000000000000..97c8aee4db0cdff0e1f28dde4396da6d1fdec799 GIT binary patch literal 13568 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 U1?s~D`= 1) + + end diff --git a/Source/CPM3/ccp.com b/Source/CPM3/ccp.com new file mode 100644 index 0000000000000000000000000000000000000000..3934d84051c1cef0e8a430ce52f691daa9a37e21 GIT binary patch literal 3200 zcmZ`*e{dAl9e=xbw|D#FZL)V*@odxG?17M!g`~+@k0b;k{AeLy5)`Zo2r&YYV1iyS zu%wPi|8Za(2Jt7->F7+09I3#nLowM+oZFi`rTpIkRRUGtXsOgp-Gmf5!&Z0Hd$(5NI~eHic6l- zS3E=c(i5Kj=O=~{T^L+Mrxir$j-7ggdZzYWb2AmglmSf{N0l7VsuCD z5%vC_KbX%_#6!gp?bzmrRM`t2?OlD6j+ar?^0f-0B}9?A9t$>SkcKD*L9b+XumlJ1 ztn&wVmGE6^XTGyM%4p1tZqkb$vBL5pkYBzd{>;gu5b{AuxI%oq6y_xost= zyD#-Gn(rC+n_tsk=;{|82X5~e`IZhp7YtdS(&@Af$|}7GR4|Xwii1jD^H@h{S9SiV z$0-_%Q)S0J7omBe1liqvNnQ_zR0~kO1^&3+W#`3k4zv_!m7Vb9;RRMm8_9=k%q`ox zdw0iPxxHiSc6ohgM_cFCC*+Dn6&3gVOrE!Gz6{N>t?k=eJGTPi{-@NSM;+9QQ17ax z#ok~fSRX*e=-10vA=%rDSR^Av!BdQo6hvq#Dz1MvprFzK1z(U%A#Z@91Cbz#)T8GR z?NWQDg#TapUI3wr1x3nDZ%*2Y#R}INpxBgNdBmf=tXIB?0hr_FDlc`626}GW1^fi& z>=GGrhA-hso)RC0Im`tz&DRt`884Dv!a?mly*3m~go1UEP*D3*TpN#4Y9g+E3{6}+ z6|KEp79bAvvV1wxP0IXGHbef&T1@%o&0mfC|`Nm6HH}z*PI8vIx;=z5v5GZ8z__Xt|m^tZn&q!q(R=)9Cws(Egx)rO}G-%C; zT;mBVDCI>r5|uAw*KGJwu8&ix79T7`I#{uYTw_Ik_!?_2@hQh~ygXi>i#>~LjuAk zb(7q(X?=s-(6qFQ_aBGvXX;|)ErI-2ATPM} zP>wvvl8bD1z=VC6{+zTM(?M+fiy(Jzgh2>W?@pxmc5EanUo3AotRX!K%N8Ro1IPlh8VJ7t;^hm0--ve$%(~4KrLn`QvcfYRxV5&%bx_e%HTLC}sB(gkIE;4nEWWFU3q z(_evNGAJppZ(1Xx1AzfQJo|!nk*m{L0hALx7HEs8(#yE)B%Y)7=faiiQC?JCBie8k z5W8IZ70SCn8GI!K>dRc|eW<Axk#>ZKVm)xjI^V1_14dgG`%LpYNw&Ak1vUfiy;#_oVk!yPQZbyI&LmtZHtn1i4}uDEEugx*1CotcGKBeA)lzV6E4eV&5Rnh)P-Sph&uU1 z&f=t_q=K9iGeewqTCb^rj;hxrLoVjJ^Gj3aK-$?lwt#bbMiy|Ra@qLvzE)xB!e(!_X29&S9Y$$jY%TsgEeoe5j&`@jvIQs2elxA`0(n$`Nu z0S-7;Rb8GM;DFc(@S%3*F-@$t;2H#Y+|5mpF|J_G=$Db&v3SCTaR2!gs(GDLO8EWf z&1ttKF`?VhOolH9S+Q8Tf-}HAfFGQBhEMBo@iSJYG#<{r?krZ#yLda32!%OShvItq?6tm zaDW;~*J8*sv5}Yn76ZnURJY9_eRR=Phr2S-efV(i;gtooccoK2)+Inn3e63W6K?RH z>j{q^guOy@%oBoLClA4ekz=#z0sBzLm55!pBpC9UhG5v#G|J>a)=|c;2$#&yg^*Au zUsBCM0Rr$Dz8mI3@2^5S?G>l>QEJ2#?1tTYTRY_qT~MhpInvl6uh`Mv8j(9&pL}XZ zXY2OJOpc4l^ENGPoWDelU=DNZJ6pTDAn&zoXlj)AcF4;*cJJM>`>9qrBFpn`t+i-= t1U0T}TmTudrD3h?-ZbVl&zBoEu5NCLz%?rd&lL<66^XzkC=ejge*r^Sk{$p6 literal 0 HcmV?d00001 diff --git a/Source/CPM3/chario.z80 b/Source/CPM3/chario.z80 new file mode 100644 index 00000000..27c78616 --- /dev/null +++ b/Source/CPM3/chario.z80 @@ -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 +; 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 +; 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 diff --git a/Source/CPM3/cpm3.lib b/Source/CPM3/cpm3.lib new file mode 100644 index 00000000..6b45a43d --- /dev/null +++ b/Source/CPM3/cpm3.lib @@ -0,0 +1,180 @@ +; Macro Definitions for CP/M3 BIOS Data Structures. + + ; dtbl - 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, +?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 + \ No newline at end of file diff --git a/Source/CPM3/cpm3fix.pat b/Source/CPM3/cpm3fix.pat new file mode 100644 index 0000000000000000000000000000000000000000..b60a2720c8d7a3deca3fc21394d3ae901927bf0a GIT binary patch literal 38272 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 M@n+E +high$fxs: + sbi 100! jc lret$eq$ff ; Skip if function < 100 + +bdos$jmp: + + mov e,a! mvi d,0 ; de=func, hl=.ciotab + dad d! dad d! mov e,m! inx h! mov d,m ; de=functab(func) + lhld info ; info in de for later xchg + xchg! pchl ; dispatched + + +; dispatch table for functions + +functab: + dw func$ret, func1, func2, func3 + dw func$ret, func$ret, func6, func$ret + dw func$ret, func9, func10, func11 +diskf equ ($-functab)/2 ; disk funcs + dw func12,func13,func14,func15 + dw func16,func17,func18,func19 + dw func20,func21,func22,func23 + dw func24,func25,func26,func27 + dw func28,func29,func30,func31 + dw func32,func33,func34,func35 + dw func36,func37,func38,func39 + dw func40,func42,func43 + dw func44,func45,func46,func47 + dw func48,func49,func50 +nfuncs equ ($-functab)/2 + + +entsp: ds 2 ; entry stack pointer + + ; 40 level stack + + dw 0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h + dw 0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h + dw 0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h + dw 0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h + dw 0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h +lstack: + + +page + title 'CP/M 3.0 LDRBDOS Interface, Version 3.1 July, 1982' +;***************************************************************** +;***************************************************************** +;** ** +;** B a s i c D i s k O p e r a t i n g S y s t e m ** +;** ** +;** C o n s o l e P o r t i o n ** +;** ** +;***************************************************************** +;***************************************************************** +; +; July, 1982 +; +; +; console handlers + +conout: + ;compute character position/write console char from C + ;compcol = true if computing column position + lda compcol! ora a! jnz compout + ;write the character, then compute the column + ;write console character from C + push b ;recall/save character + call conoutf ;externally, to console + pop b ;recall the character + compout: + mov a,c ;recall the character + ;and compute column position + lxi h,column ;A = char, HL = .column + cpi rubout! rz ;no column change if nulls + inr m ;column = column + 1 + cpi ' '! rnc ;return if graphic + ;not graphic, reset column position + dcr m ;column = column - 1 + mov a,m! ora a! rz ;return if at zero + ;not at zero, may be backspace or eol + mov a,c ;character back to A + cpi ctlh! jnz notbacksp + ;backspace character + dcr m ;column = column - 1 + ret + + notbacksp: + ;not a backspace character, eol? + cpi lf! rnz ;return if not + ;end of line, column = 0 + mvi m,0 ;column = 0 + ret +; +; +tabout: + ;expand tabs to console + mov a,c! cpi tab! jnz conout ;direct to conout if not + ;tab encountered, move to next tab pos + tab0: + mvi c,' '! call conout ;another blank + lda column! ani 111b ;column mod 8 = 0 ? + jnz tab0 ;back for another if not + ret +; +print: + ;print message until M(BC) = '$' + LXI H,OUTDELIM + ldax b! CMP M! rz ;stop on $ + ;more to print + inx b! push b! mov c,a ;char to C + call tabout ;another character printed + pop b! jmp print +; +; +func2: equ tabout + ;write console character with tab expansion +; +func9: + ;write line until $ encountered + xchg ;was lhld info + mov c,l! mov b,h ;BC=string address + jmp print ;out to console +; +sta$ret: + ;store the A register to aret + sta aret +func$ret: + ret ;jmp goback (pop stack for non cp/m functions) +; +setlret1: + ;set lret = 1 + mvi a,1! jmp sta$ret +; +func1: equ func$ret +; +func3: equ func$ret +; +func6: equ func$ret +; +func10: equ func$ret +func11: equ func$ret +; +; data areas +; + + +compcol:db 0 ;true if computing column position +; end of BDOS Console module + +;********************************************************************** +;***************************************************************** +; +; Error Messages + +md equ 24h + +err$msg: db cr,lf,'BDOS ERR: ',md +err$select: db 'Select',md +err$phys: db 'Perm.',md + +;***************************************************************** +;***************************************************************** +; +; common values shared between bdosi and bdos + + +aret: ds 2 ; address value to return +lret equ aret ; low(aret) + +;***************************************************************** +;***************************************************************** +;** ** +;** b a s i c d i s k o p e r a t i n g s y s t e m ** +;** ** +;***************************************************************** +;***************************************************************** + +; literal constants + +true equ 0ffh ; constant true +false equ 000h ; constant false +enddir equ 0ffffh ; end of directory +byte equ 1 ; number of bytes for "byte" type +word equ 2 ; number of bytes for "word" type + +; fixed addresses in low memory + +tbuff equ 0080h ; default buffer location + +; error message handlers + +sel$error: + ; report select error + lxi b,err$msg + call print + lxi b,err$select + jmp goerr1 + +goerr: + lxi b,err$msg + call print + lxi b,err$phys +goerr1: + call print + di ! hlt + +bde$e$bde$m$hl: + mov a,e! sub l! mov e,a + mov a,d! sbb h! mov d,a + rnc! dcr b! ret + +bde$e$bde$p$hl: + mov a,e! add l! mov e,a + mov a,d! adc h! mov d,a + rnc! inr b! ret + +shl3bv: + inr c +shl3bv1: + dcr c! rz + dad h! adc a! jmp shl3bv1 + +compare: + ldax d! cmp m! rnz + inx h! inx d! dcr c! rz + jmp compare + +; +; local subroutines for bios interface +; + +move: + ; Move data length of length c from source de to + ; destination given by hl + inr c ; in case it is zero + move0: + dcr c! rz ; more to move + ldax d! mov m,a ; one byte moved + inx d! inx h ; to next byte + jmp move0 + +selectdisk: + ; Select the disk drive given by register D, and fill + ; the base addresses curtrka - alloca, then fill + ; the values of the disk parameter block + mov c,d ; current disk# to c + ; lsb of e = 0 if not yet logged - in + call seldskf ; hl filled by call + ; hl = 0000 if error, otherwise disk headers + mov a,h! ora l! rz ; Return with C flag reset if select error + ; Disk header block address in hl + mov e,m! inx h! mov d,m! inx h ; de=.tran + inx h ! inx h + shld curtrka! inx h! inx h ; hl=.currec + shld curreca! inx h! inx h ; hl=.buffa + inx h! inx h + inx h! inx h + ; de still contains .tran + xchg! shld tranv ; .tran vector + lxi h,dpbaddr ; de= source for move, hl=dest + mvi c,addlist! call move ; addlist filled + ; Now fill the disk parameter block + lhld dpbaddr! xchg ; de is source + lxi h,sectpt ; hl is destination + mvi c,dpblist! call move ; data filled + ; Now set single/double map mode + lhld maxall ; largest allocation number + mov a,h ; 00 indicates < 255 + lxi h,single! mvi m,true ; Assume a=00 + ora a! jz retselect + ; high order of maxall not zero, use double dm + mvi m,false + retselect: + ; C flag set indicates successful select + stc + ret + +home: + ; Move to home position, then offset to start of dir + call homef + xra a ; constant zero to accumulator + lhld curtrka! mov m,a! inx h! mov m,a ; curtrk=0000 + lhld curreca! mov m,a! inx h! mov m,a ; currec=0000 + inx h! mov m,a ; currec high byte=00 + + ret + +pass$arecord: + lxi h,arecord + mov e,m! inx h! mov d,m! inx h! mov b,m + ret + +rdbuff: + ; Read buffer and check condition + call pass$arecord + call readf ; current drive, track, sector, dma + + +diocomp: ; Check for disk errors + ora a! rz + mov c,a + cpi 3! jc goerr + mvi c,1! jmp goerr + +seekdir: + ; Seek the record containing the current dir entry + + lhld dcnt ; directory counter to hl + mvi c,dskshf! call hlrotr ; value to hl + + mvi b,0! xchg + + lxi h,arecord + mov m,e! inx h! mov m,d! inx h! mov m,b + ret + +seek: + ; Seek the track given by arecord (actual record) + + lhld curtrka! mov c,m! inx h! mov b,m ; bc = curtrk + push b ; s0 = curtrk + lhld curreca! mov e,m! inx h! mov d,m + inx h! mov b,m ; bde = currec + lhld arecord! lda arecord+2! mov c,a ; chl = arecord +seek0: + mov a,l! sub e! mov a,h! sbb d! mov a,c! sbb b + push h ; Save low(arecord) + jnc seek1 ; if arecord >= currec then go to seek1 + lhld sectpt! call bde$e$bde$m$hl ; currec = currec - sectpt + pop h! xthl! dcx h! xthl ; curtrk = curtrk - 1 + jmp seek0 +seek1: + lhld sectpt! call bde$e$bde$p$hl ; currec = currec + sectpt + pop h ; Restore low(arecord) + mov a,l! sub e! mov a,h! sbb d! mov a,c! sbb b + jc seek2 ; if arecord < currec then go to seek2 + xthl! inx h! xthl ; curtrk = curtrk + 1 + push h ; save low (arecord) + jmp seek1 +seek2: + xthl! push h ; hl,s0 = curtrk, s1 = low(arecord) + lhld sectpt! call bde$e$bde$m$hl ; currec = currec - sectpt + pop h! push d! push b! push h ; hl,s0 = curtrk, + ; s1 = high(arecord,currec), s2 = low(currec), + ; s3 = low(arecord) + xchg! lhld offset! dad d + mov b,h! mov c,l! shld track + call settrkf ; call bios settrk routine + ; Store curtrk + pop d! lhld curtrka! mov m,e! inx h! mov m,d + ; Store currec + pop b! pop d! + lhld curreca! mov m,e! inx h! mov m,d + inx h! mov m,b ; currec = bde + pop b ; bc = low(arecord), de = low(currec) + mov a,c! sub e! mov l,a ; hl = bc - de + mov a,b! sbb d! mov h,a + call shr$physhf + mov b,h! mov c,l + + lhld tranv! xchg ; bc=sector#, de=.tran + call sectran ; hl = tran(sector) + mov c,l! mov b,h ; bc = tran(sector) + shld sector + call setsecf ; sector selected + lhld curdma! mov c,l! mov b,h! jmp setdmaf + +shr$physhf: + lda physhf! mov c,a! jmp hlrotr + + +; file control block (fcb) constants + +empty equ 0e5h ; empty directory entry +recsiz equ 128 ; record size +fcblen equ 32 ; file control block size +dirrec equ recsiz/fcblen ; directory fcbs / record +dskshf equ 2 ; log2(dirrec) +dskmsk equ dirrec-1 +fcbshf equ 5 ; log2(fcblen) + +extnum equ 12 ; extent number field +maxext equ 31 ; largest extent number +ubytes equ 13 ; unfilled bytes field + +namlen equ 15 ; name length +reccnt equ 15 ; record count field +dskmap equ 16 ; disk map field +nxtrec equ fcblen + +; utility functions for file access + +dm$position: + ; Compute disk map position for vrecord to hl + lxi h,blkshf! mov c,m ; shift count to c + lda vrecord ; current virtual record to a + dmpos0: + ora a! rar! dcr c! jnz dmpos0 + ; a = shr(vrecord,blkshf) = vrecord/2**(sect/block) + mov b,a ; Save it for later addition + mvi a,8! sub m ; 8-blkshf to accumulator + mov c,a ; extent shift count in register c + lda extval ; extent value ani extmsk + dmpos1: + ; blkshf = 3,4,5,6,7, c=5,4,3,2,1 + ; shift is 4,3,2,1,0 + dcr c! jz dmpos2 + ora a! ral! jmp dmpos1 + dmpos2: + ; Arrive here with a = shl(ext and extmsk,7-blkshf) + add b ; Add the previous shr(vrecord,blkshf) value + ; a is one of the following values, depending upon alloc + ; bks blkshf + ; 1k 3 v/8 + extval * 16 + ; 2k 4 v/16+ extval * 8 + ; 4k 5 v/32+ extval * 4 + ; 8k 6 v/64+ extval * 2 + ; 16k 7 v/128+extval * 1 + ret ; with dm$position in a + +getdma: + lhld info! lxi d,dskmap! dad d! ret + +getdm: + ; Return disk map value from position given by bc + call getdma + dad b ; Index by a single byte value + lda single ; single byte/map entry? + ora a! jz getdmd ; Get disk map single byte + mov l,m! mov h,b! ret ; with hl=00bb + getdmd: + dad b ; hl=.fcb(dm+i*2) + ; double precision value returned + mov a,m! inx h! mov h,m! mov l,a! ret + +index: + ; Compute disk block number from current fcb + call dm$position ; 0...15 in register a + sta dminx + mov c,a! mvi b,0! call getdm ; value to hl + shld arecord! mov a,l! ora h! ret + +atran: + ; Compute actual record address, assuming index called + +; arecord = shl(arecord,blkshf) + + lda blkshf! mov c,a + lhld arecord! xra a! call shl3bv + shld arecord! sta arecord+2 + + shld arecord1 ; Save low(arecord) + +; arecord = arecord or (vrecord and blkmsk) + + lda blkmsk! mov c,a! lda vrecord! ana c + mov b,a ; Save vrecord & blkmsk in reg b & blk$off + sta blk$off + lxi h,arecord! ora m! mov m,a! ret + + +getexta: + ; Get current extent field address to hl + lhld info! lxi d,extnum! dad d ; hl=.fcb(extnum) + ret + +getrcnta: + ; Get reccnt address to hl + lhld info! lxi d,reccnt! dad d! ret + +getfcba: + ; Compute reccnt and nxtrec addresses for get/setfcb + call getrcnta! xchg ; de=.fcb(reccnt) + lxi h,(nxtrec-reccnt)! dad d ; hl=.fcb(nxtrec) + ret + +getfcb: + ; Set variables from currently addressed fcb + call getfcba ; addresses in de, hl + mov a,m! sta vrecord ; vrecord=fcb(nxtrec) + xchg! mov a,m! sta rcount ; rcount=fcb(reccnt) + call getexta ; hl=.fcb(extnum) + lda extmsk ; extent mask to a + ana m ; fcb(extnum) and extmsk + sta extval + ret + +setfcb: + ; Place values back into current fcb + call getfcba ; addresses to de, hl + mvi c,1 + + lda vrecord! add c! mov m,a ; fcb(nxtrec)=vrecord+seqio + xchg! lda rcount! mov m,a ; fcb(reccnt)=rcount + ret + +hlrotr: + ; hl rotate right by amount c + inr c ; in case zero + hlrotr0: dcr c! rz ; return when zero + + mov a,h! ora a! rar! mov h,a ; high byte + mov a,l! rar! mov l,a ; low byte + jmp hlrotr0 + +hlrotl: + ; Rotate the mask in hl by amount in c + inr c ; may be zero + hlrotl0: dcr c! rz ; return if zero + + dad h! jmp hlrotl0 + +set$cdisk: + ; Set a "1" value in curdsk position of bc + lda seldsk + push b ; Save input parameter + mov c,a ; Ready parameter for shift + lxi h,1 ; number to shift + call hlrotl ; hl = mask to integrate + pop b ; original mask + mov a,c! ora l! mov l,a + mov a,b! ora h! mov h,a ; hl = mask or rol(1,curdsk) + ret + +test$vector: + lda seldsk + mov c,a! call hlrotr + mov a,l! ani 1b! ret ; non zero if curdsk bit on + +getdptra: + ; Compute the address of a directory element at + ; positon dptr in the buffer + + lhld buffa! lda dptr + ; hl = hl + a + add l! mov l,a! rnc + ; overflow to h + inr h! ret + +clr$ext: + ; fcb ext = fcb ext & 1fh + + call getexta! mov a,m! ani 0001$1111b! mov m,a! + ret + + +subdh: + ; Compute hl = de - hl + mov a,e! sub l! mov l,a! mov a,d! sbb h! mov h,a + ret + +get$buffa: + push d! lxi d,10! dad d + mov e,m! inx h! mov d,m + xchg! pop d! ret + + +rddir: + ; Read a directory entry into the directory buffer + call seek$dir + lda phymsk! ora a! jz rddir1 + mvi a,3 + call deblock$dir! jmp setdata + +rddir1: + call setdir ; directory dma + shld buffa! call seek + call rdbuff ; directory record loaded + +setdata: + ; Set data dma address + lhld dmaad! jmp setdma ; to complete the call + +setdir: + ; Set directory dma address + + lhld dirbcba + call get$buffa + +setdma: + ; hl=.dma address to set (i.e., buffa or dmaad) + shld curdma! ret + +end$of$dir: + ; Return zero flag if at end of directory, non zero + ; if not at end (end of dir if dcnt = 0ffffh) + lxi h,dcnt + mov a,m ; may be 0ffh + inx h! cmp m ; low(dcnt) = high(dcnt)? + rnz ; non zero returned if different + ; high and low the same, = 0ffh? + inr a ; 0ffh becomes 00 if so + ret + +set$end$dir: + ; Set dcnt to the end of the directory + lxi h,enddir! shld dcnt! ret + + +read$dir: + ; Read next directory entry, with c=true if initializing + + lhld dirmax! xchg ; in preparation for subtract + lhld dcnt! inx h! shld dcnt ; dcnt=dcnt+1 + + ; while(dirmax >= dcnt) + call subdh ; de-hl + jc set$end$dir + ; not at end of directory, seek next element + ; initialization flag is in c + + lda dcnt! ani dskmsk ; low(dcnt) and dskmsk + mvi b,fcbshf ; to multiply by fcb size + + read$dir1: + add a! dcr b! jnz read$dir1 + ; a = (low(dcnt) and dskmsk) shl fcbshf + sta dptr ; ready for next dir operation + ora a! rnz ; Return if not a new record + + push b ; Save initialization flag c + call rd$dir ; Read the directory record + pop b ; Recall initialization flag + ret +compext: + ; Compare extent# in a with that in c, return nonzero + ; if they do not match + push b ; Save c's original value + push psw! lda extmsk! cma! mov b,a + ; b has negated form of extent mask + mov a,c! ana b! mov c,a ; low bits removed from c + pop psw! ana b ; low bits removed from a + sub c! ani maxext ; Set flags + pop b ; Restore original values + ret + +get$dir$ext: + ; Compute directory extent from fcb + ; Scan fcb disk map backwards + call getfcba ; hl = .fcb(vrecord) + mvi c,16! mov b,c! inr c! push b + ; b=dskmap pos (rel to 0) +get$de0: + pop b + dcr c + xra a ; Compare to zero +get$de1: + dcx h! dcr b ; Decr dskmap position + cmp m! jnz get$de2 ; fcb(dskmap(b)) ~= 0 + dcr c! jnz get$de1 + ; c = 0 -> all blocks = 0 in fcb disk map +get$de2: + mov a,c! sta dminx + lda single! ora a! mov a,b + jnz get$de3 + rar ; not single, divide blk idx by 2 +get$de3: + push b! push h ; Save dskmap position & count + mov l,a! mvi h,0 ; hl = non-zero blk idx + ; Compute ext offset from last non-zero + ; block index by shifting blk idx right + ; 7 - blkshf + lda blkshf! mov d,a! mvi a,7! sub d + mov c,a! call hlrotr! mov b,l + ; b = ext offset + lda extmsk! cmp b! pop h! jc get$de0 + ; Verify computed extent offset <= extmsk + call getexta! mov c,m + cma! ani maxext! ana c! ora b + ; dir ext = (fcb ext & (~ extmsk) & maxext) | ext offset + pop b ; Restore stack + ret ; a = directory extent + + +search: + ; Search for directory element of length c at info + lhld info! shld searcha ; searcha = info + mov a,c! sta searchl ; searchl = c + + call set$end$dir ; dcnt = enddir + call home ; to start at the beginning + +searchn: + ; Search for the next directory element, assuming + ; a previous call on search which sets searcha and + ; searchl + + mvi c,false! call read$dir ; Read next dir element + call end$of$dir! jz lret$eq$ff + ; not end of directory, scan for match + lhld searcha! xchg ; de=beginning of user fcb + + call getdptra ; hl = buffa+dptr + lda searchl! mov c,a ; length of search to c + mvi b,0 ; b counts up, c counts down + + mov a,m! cpi empty! jz searchn + + searchloop: + mov a,c! ora a! jz endsearch + ; Scan next character if not ubytes + mov a,b! cpi ubytes! jz searchok + ; not the ubytes field, extent field? + cpi extnum ; may be extent field + jz searchext ; Skip to search extent + ldax d + sub m! ani 7fh ; Mask-out flags/extent modulus + jnz searchn ; Skip if not matched + jmp searchok ; matched character + searchext: + ldax d + ; Attempt an extent # match + push b ; Save counters + mov c,m ; directory character to c + call compext ; Compare user/dir char + pop b ; Recall counters + ora a ; Set flag + jnz searchn ; Skip if no match + searchok: + ; current character matches + inx d! inx h! inr b! dcr c + jmp searchloop + endsearch: + ; entire name matches, return dir position + xra a + sta lret ; lret = 0 + ; successful search - + ; return with zero flag reset + mov b,a! inr b + ret + lret$eq$ff: + ; unsuccessful search - + ; return with zero flag set + ; lret,low(aret) = 0ffh + mvi a,255 ! mov b,a ! inr b ! jmp sta$ret + +open: + ; Search for the directory entry, copy to fcb + mvi c,namlen! call search + rz ; Return with lret=255 if end + + ; not end of directory, copy fcb information +open$copy: + call getexta ! mov a,m ! push a ; save extent to check for extent + ; folding - move moves entire dir FCB + call getdptra! xchg ; hl = .buff(dptr) + lhld info ; hl=.fcb(0) + mvi c,nxtrec ; length of move operation + call move ; from .buff(dptr) to .fcb(0) + + ; Note that entire fcb is copied, including indicators + + call get$dir$ext! mov c,a + pop a ! mov m,a ; restore extent + + ; hl = .user extent#, c = dir extent# + ; above move set fcb(reccnt) to dir(reccnt) + ; if fcb ext < dir ext then fcb(reccnt) = fcb(reccnt) | 128 + ; if fcb ext = dir ext then fcb(reccnt) = fcb(reccnt) + ; if fcb ext > dir ext then fcb(reccnt) = 0 + +set$rc: ; hl=.fcb(ext), c=dirext + mvi b,0 + xchg! lxi h,(reccnt-extnum)! dad d + ldax d! sub c! jz set$rc2 + mov a,b! jnc set$rc1 + mvi a,128! mov b,m + + set$rc1: + mov m,a! mov a,b! sta actual$rc! ret + set$rc2: + sta actual$rc + mov a,m! ora a! rnz ; ret if rc ~= 0 + lda dminx! ora a! rz ; ret if no blks in fcb + lda fx! cpi 15! rz ; ret if fx = 15 + mvi m,128 ; rc = 128 + ret + +restore$rc: + ; hl = .fcb(extnum) + ; if actual$rc ~= 0 then rcount = actual$rc + push h + lda actual$rc! ora a! jz restore$rc1 + lxi d,(reccnt-extnum)! dad d + mov m,a! xra a! sta actual$rc + +restore$rc1: + pop h! ret + +open$reel: + ; Close the current extent, and open the next one + ; if possible. + + call getexta + mov a,m! mov c,a + inr c! call compext + jz open$reel3 + + mvi a,maxext! ana c! mov m,a ; Incr extent field + mvi c,namlen! call search ; Next extent found? + ; not end of file, open + call open$copy + + open$reel2: + call getfcb ; Set parameters + xra a! sta vrecord! jmp sta$ret ; lret = 0 + open$reel3: + inr m ; fcb(ex) = fcb(ex) + 1 + call get$dir$ext! mov c,a + ; Is new extent beyond dir$ext? + cmp m! jnc open$reel4 ; no + dcr m ; fcb(ex) = fcb(ex) - 1 + jmp set$lret1 + open$reel4: + call restore$rc + call set$rc! jmp open$reel2 + +seqdiskread: + ; Sequential disk read operation + ; Read the next record from the current fcb + + call getfcb ; sets parameters for the read + + lda vrecord! lxi h,rcount! cmp m ; vrecord-rcount + ; Skip if rcount > vrecord + jc recordok + + ; not enough records in the extent + ; record count must be 128 to continue + cpi 128 ; vrecord = 128? + jnz setlret1 ; Skip if vrecord<>128 + call open$reel ; Go to next extent if so + ; Check for open ok + lda lret! ora a! jnz setlret1 ; Stop at eof + + recordok: + ; Arrive with fcb addressing a record to read + + call index ; Z flag set if arecord = 0 + + jz setlret1 ; Reading unwritten data + + ; Record has been allocated + call atran ; arecord now a disk address + + lda phymsk! ora a ; if not 128 byte sectors + jnz read$deblock ; go to deblock + + call setdata ; Set curdma = dmaad + call seek ; Set up for read + call rdbuff ; Read into (curdma) + jmp setfcb ; Update FCB + +curselect: + lda seldsk! inr a! jz sel$error + dcr a! lxi h,curdsk! cmp m! rz + + ; Skip if seldsk = curdsk, fall into select +select: + ; Select disk info for subsequent input or output ops + mov m,a ; curdsk = seldsk + + mov d,a ; Save seldsk in register D for selectdisk call + lhld dlog! call test$vector ; test$vector does not modify DE + mov e,a! push d ; Send to seldsk, save for test below + call selectdisk! pop h ; Recall dlog vector + jnc sel$error ; returns with C flag set if select ok + ; Is the disk logged in? + dcr l ; reg l = 1 if so + rz ; yes - drive previously logged in + + lhld dlog! mov c,l! mov b,h ; call ready + call set$cdisk! shld dlog ; dlog=set$cdisk(dlog) + ret + +set$seldsk: + lda linfo! sta seldsk! ret + +reselectx: + xra a! sta high$ext! jmp reselect1 +reselect: + ; Check current fcb to see if reselection necessary + mvi a,80h! mov b,a! dcr a! mov c,a ; b = 80h, c = 7fh + lhld info! lxi d,7! xchg! dad d + mov a,m! ana b + ; fcb(7) = fcb(7) & 7fh + mov a,m! ana c! mov m,a + ; high$ext = 80h & fcb(8) + inx h! mov a,m! ana b! sta high$ext + ; fcb(8) = fcb(8) & 7fh + mov a,m! ana c! mov m,a + ; fcb(ext) = fcb(ext) & 1fh + call clr$ext + + ; if fcb(rc) & 80h + ; then fcb(rc) = 80h, actual$rc = fcb(rc) & 7fh + ; else actual$rc = 0 + + call getrcnta! mov a,m! ana b! jz reselect1 + mov a,m! ana c! mov m,b + +reselect1: + sta actual$rc + + lxi h,0 + shld fcbdsk ; fcbdsk = 0 + mvi a,true! sta resel ; Mark possible reselect + lhld info! mov a,m ; drive select code + ani 1$1111b ; non zero is auto drive select + dcr a ; Drive code normalized to 0..30, or 255 + sta linfo ; Save drive code + cpi 0ffh! jz noselect + ; auto select function, seldsk saved above + mov a,m! sta fcbdsk ; Save drive code + call set$seldsk + + noselect: + call curselect + mvi a,0 ! lhld info ! mov m,a + ret + +; +; individual function handlers +; + +func12 equ func$ret + +func13: + + ; Reset disk system - initialize to disk 0 + lxi h,0! shld dlog + + xra a! sta seldsk + dcr a! sta curdsk + + lxi h,tbuff! shld dmaad ; dmaad = tbuff + jmp setdata ; to data dma address + +func14: + ; Select disk info + call set$seldsk ; seldsk = linfo + jmp curselect + +func15: + ; Open file + call reselectx + call open! call openx ; returns if unsuccessful, a = 0 + ret + +openx: + call end$of$dir! rz + call getfcba! mov a,m! inr a! jnz openxa + dcx d! dcx d! ldax d! mov m,a +openxa: + ; open successful + pop h ; Discard return address + mvi c,0100$0000b + ret + +func16 equ func$ret + +func17 equ func$ret + +func18 equ func$ret + +func19 equ func$ret + +func20: + ; Read a file + call reselect + jmp seqdiskread + +func21 equ func$ret + +func22 equ func$ret + +func23 equ func$ret + +func24 equ func$ret + +func25: lda seldsk ! jmp sta$ret + +func26: xchg ! shld dmaad + jmp setdata + +func27 equ func$ret + +func28: equ func$ret + +func29 equ func$ret + +func30 equ func$ret + +func31 equ func$ret + +func32 equ func$ret + +func33 equ func$ret + +func34 equ func$ret + +func35 equ func$ret + +func36 equ func$ret + +func37 equ func$ret + +func38 equ func$ret + +func39 equ func$ret + +func40 equ func$ret + +func42 equ func$ret + +func43 equ func$ret + +func44 equ func$ret + +func45 equ func$ret + +func46 equ func$ret + +func47 equ func$ret + +func48 equ func$ret + +func49 equ func$ret + +func50 equ func$ret + +func100 equ func$ret + +func101 equ func$ret + +func102 equ func$ret + +func103 equ func$ret + +func104 equ func$ret + +func105 equ func$ret + +func106 equ func$ret + +func107 equ func$ret + +func108 equ func$ret + +func109 equ func$ret + + +goback: + ; Arrive here at end of processing to return to user + lda fx! cpi 15! jc retmon + lda olddsk! sta seldsk ; Restore seldsk + lda resel! ora a! jz retmon + + lhld info! mvi m,0 ; fcb(0)=0 + lda fcbdsk! ora a! jz goback1 + ; Restore fcb(0) + mov m,a ; fcb(0)=fcbdsk + goback1: + ; fcb(8) = fcb(8) | high$ext + inx h! lda high$ext! ora m! mov m,a + ; fcb(rc) = fcb(rc) | actual$rc + call getrcnta! lda actual$rc! ora m! mov m,a + ; return from the disk monitor +retmon: + lhld entsp! sphl + lhld aret! mov a,l! mov b,h + ret +; +; data areas +; +dlog: dw 0 ; logged-in disks +curdma ds word ; current dma address +buffa: ds word ; pointer to directory dma address + +; +; curtrka - alloca are set upon disk select +; (data must be adjacent, do not insert variables) +; (address of translate vector, not used) +cdrmaxa:ds word ; pointer to cur dir max value (2 bytes) +curtrka:ds word ; current track address (2) +curreca:ds word ; current record address (3) +drvlbla:ds word ; current drive label byte address (1) +lsn$add:ds word ; login sequence # address (1) + ; +1 -> bios media change flag (1) +dpbaddr:ds word ; current disk parameter block address +checka: ds word ; current checksum vector address +alloca: ds word ; current allocation vector address +dirbcba:ds word ; dir bcb list head +dtabcba:ds word ; data bcb list head +hash$tbla: + ds word + ds byte + +addlist equ $-dpbaddr ; address list size + +; +; buffer control block format +; +; bcb format : drv(1) || rec(3) || pend(1) || sequence(1) || +; 0 1 4 5 +; +; track(2) || sector(2) || buffer$add(2) || +; 6 8 10 +; +; link(2) +; 12 +; + +; sectpt - offset obtained from disk parm block at dpbaddr +; (data must be adjacent, do not insert variables) +sectpt: ds word ; sectors per track +blkshf: ds byte ; block shift factor +blkmsk: ds byte ; block mask +extmsk: ds byte ; extent mask +maxall: ds word ; maximum allocation number +dirmax: ds word ; largest directory number +dirblk: ds word ; reserved allocation bits for directory +chksiz: ds word ; size of checksum vector +offset: ds word ; offset tracks at beginning +physhf: ds byte ; physical record shift +phymsk: ds byte ; physical record mask +dpblist equ $-sectpt ; size of area +; +; local variables +; +blk$off: ds byte ; record offset within block +dir$cnt: ds byte ; direct i/o count + +tranv: ds word ; address of translate vector +linfo: ds byte ; low(info) +dminx: ds byte ; local for diskwrite + +actual$rc: + ds byte ; directory ext record count + +single: ds byte ; set true if single byte allocation map + + +olddsk: ds byte ; disk on entry to bdos +rcount: ds byte ; record count in current fcb +extval: ds byte ; extent number and extmsk + +vrecord:ds byte ; current virtual record + +curdsk: + +adrive: db 0ffh ; current disk +arecord:ds word ; current actual record + ds byte + +arecord1: ds word ; current actual block# * blkmsk + +;******** following variable order critical ***************** + +high$ext: ds byte ; fcb high ext bits +;xfcb$read$only: ds byte + +; local variables for directory access +dptr: ds byte ; directory pointer 0,1,2,3 + +; +; local variables initialized by bdos at entry +; +fcbdsk: ds byte ; disk named in fcb + +phy$off: ds byte +curbcba: ds word + +track: ds word +sector: ds word + +read$deblock: + mvi a,1! call deblock$dta + jmp setfcb + +column db 0 +outdelim: db '$' + +dmaad: dw 0080h +seldsk: db 0 +info: dw 0 +resel: db 0 +fx: db 0 +dcnt: dw 0 +searcha: dw 0 +searchl: db 0 + + +; ************************** +; Blocking/Deblocking Module +; ************************** + +deblock$dir: + + lhld dirbcba + + jmp deblock + +deblock$dta: + lhld dtabcba + +deblock: + + ; BDOS Blocking/Deblocking routine + ; a = 1 -> read command + ; a = 2 -> write command + ; a = 3 -> locate command + ; a = 4 -> flush command + ; a = 5 -> directory update + + push a ; Save z flag and deblock fx + + ; phy$off = low(arecord) & phymsk + ; low(arecord) = low(arecord) & ~phymsk + call deblock8 + lda arecord! mov e,a! ana b! sta phy$off + mov a,e! ana c! sta arecord + + shld curbcba! call getbuffa! shld curdma + + call deblock9 + ; Is command flush? + pop a! push a! cpi 4 + jnc deblock1 ; yes + ; Is referenced physical record + ;already in buffer? + call compare! jz deblock45 ; yes + xra a +deblock1: + call deblock10 + ; Read physical record buffer + mvi a,2! call deblock$io + + call deblock9 ; phypfx = adrive || arecord + call move! mvi m,0 ; zero pending flag + +deblock45: + ; recadd = phybuffa + phy$off*80h + lda phy$off! inr a! lxi d,80h! lxi h,0ff80h +deblock5: + dad d! dcr a! jnz deblock5 + xchg! lhld curdma! dad d + ; If deblock command = locate + ; then buffa = recadd; return + pop a! cpi 3! jnz deblock6 + shld buffa! ret +deblock6: + xchg! lhld dmaad! lxi b,80h + ; If deblock command = read + jmp move$tpa ; then move to dma + +deblock8: + lda phymsk! mov b,a! cma! mov c,a! ret + +deblock9: + lhld curbcba! lxi d,adrive! mvi c,4! ret + +deblock10: + lxi d,4 +deblock11: + lhld curbcba! dad d! ret + +deblock$io: + ; a = 0 -> seek only + ; a = 1 -> write + ; a = 2 -> read + push a! call seek + pop a! dcr a + cp rdbuff + ; Move track & sector to bcb + call deblock10! inx h! inx h + lxi d,track! mvi c,4! jmp move + + org base+((($-base)+255) and 0ff00h)-1 + db 0 + +; Bios equates + +bios$pg equ $ + +bootf equ bios$pg+00 ; 00. cold boot +conoutf equ bios$pg+12 ; 04. console output function +homef equ bios$pg+24 ; 08. disk home function +seldskf equ bios$pg+27 ; 09. select disk function +settrkf equ bios$pg+30 ; 10. set track function +setsecf equ bios$pg+33 ; 11. set sector function +setdmaf equ bios$pg+36 ; 12. set dma function +sectran equ bios$pg+48 ; 16. sector translate +movef equ bios$pg+75 ; 25. memory move function +readf equ bios$pg+39 ; 13. read disk function +move$out equ movef +move$tpa equ movef + + end + \ No newline at end of file diff --git a/Source/CPM3/diskio.z80 b/Source/CPM3/diskio.z80 new file mode 100644 index 00000000..91613e73 --- /dev/null +++ b/Source/CPM3/diskio.z80 @@ -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 @ up to 00, saves & + extrn ?pdec ; print binary number in 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 + + ;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 + + ; they transfer the appropriate data, perform retries + ; if necessary, then return an error code in + +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, , 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 ", 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 +; 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 +; 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 diff --git a/Source/CPM3/drvtbl.z80 b/Source/CPM3/drvtbl.z80 new file mode 100644 index 00000000..27a4fda5 --- /dev/null +++ b/Source/CPM3/drvtbl.z80 @@ -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 diff --git a/Source/CPM3/genbnk.dat b/Source/CPM3/genbnk.dat new file mode 100644 index 00000000..1e9f59df --- /dev/null +++ b/Source/CPM3/genbnk.dat @@ -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 + \ No newline at end of file diff --git a/Source/CPM3/gencpm.com b/Source/CPM3/gencpm.com new file mode 100644 index 0000000000000000000000000000000000000000..d9d67499f9eff1fddf7748bc52fe835818a0886d GIT binary patch literal 21155 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 HIrIMk=LF{; literal 0 HcmV?d00001 diff --git a/Source/CPM3/genres.dat b/Source/CPM3/genres.dat new file mode 100644 index 00000000..3622d946 --- /dev/null +++ b/Source/CPM3/genres.dat @@ -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 + \ No newline at end of file diff --git a/Source/CPM3/genres.old b/Source/CPM3/genres.old new file mode 100644 index 00000000..75b45a49 --- /dev/null +++ b/Source/CPM3/genres.old @@ -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 + \ No newline at end of file diff --git a/Source/CPM3/makedate.lib b/Source/CPM3/makedate.lib new file mode 100644 index 00000000..3fe3f25b --- /dev/null +++ b/Source/CPM3/makedate.lib @@ -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 + diff --git a/Source/CPM3/modebaud.lib b/Source/CPM3/modebaud.lib new file mode 100644 index 00000000..29853d35 --- /dev/null +++ b/Source/CPM3/modebaud.lib @@ -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 diff --git a/Source/CPM3/move.z80 b/Source/CPM3/move.z80 new file mode 100644 index 00000000..885eecb2 --- /dev/null +++ b/Source/CPM3/move.z80 @@ -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 diff --git a/Source/CPM3/optbnk.lib b/Source/CPM3/optbnk.lib new file mode 100644 index 00000000..a5bf221d --- /dev/null +++ b/Source/CPM3/optbnk.lib @@ -0,0 +1,6 @@ + ; global assembler options for BANKED BIOS + +true equ -1 +false equ not true + +banked equ true diff --git a/Source/CPM3/optres.lib b/Source/CPM3/optres.lib new file mode 100644 index 00000000..5b94dab5 --- /dev/null +++ b/Source/CPM3/optres.lib @@ -0,0 +1,6 @@ + ; global assembler options for NONBANKED BIOS + +true equ -1 +false equ not true + +banked equ false diff --git a/Source/CPM3/readme.1st b/Source/CPM3/readme.1st new file mode 100644 index 00000000..1277e897 --- /dev/null +++ b/Source/CPM3/readme.1st @@ -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 compile it. + Apparently a more recent version of the compiler is + required. \ No newline at end of file diff --git a/Source/CPM3/resbdos3.spr b/Source/CPM3/resbdos3.spr new file mode 100644 index 0000000000000000000000000000000000000000..a5f21969dbeb7400343090f04c4367b379896603 GIT binary patch literal 2048 zcmd^AVQ5=b6h8Of_hK_^`jSqok=gfN-k?iMX*%03A(o`AYeO`3a}x%l;EzuBCliEq zb_s1dM1KggDh#P2vLF7CWok!7bhNz`lQ*6vlP4u2659mILuA5!C?U`D+D?#({?LEB z@XkBu+;h+Q&X<$>09RLSebM$H^cuj@XCuC?<>E zH;B1yZ;kFa8VAc)NaKa_m$dQH4HRj;k6`9L!q-T{tA9-zKK(jr_*d45rLK$W!%(!; z4KcVOTFOuCES~(HD4#L>WwN8IW_$T((q66;-b%4QOGybt0&J~h=6m;n5)_E$nAmq^ zd9|uO0@!V7d9qe7;GRVkXe-C4M{{Ib`9Nca)k z0qA&=b{?&5s<}ng{Q^3b?^re8yBC7{g^?$NKCprnv1>ZjR;${1;DFmJz(d~m zME~Vl`^p$ImYAMpRwb~}nOWGVS}Oq-tyGGU2XQJtWzm%ZW@1PQ-;oE<^&yMuX_m#K z1B_=GCTT$}TkC1`=mQLkS(Q$;A}(iYticLXwfgg!T0M;bt`-Ju#FZ~*YZ6B89^{|1 zY~vPYuqtXB@Gy(ai;IQvmX`KW|K$&ss)1HxlU0hh90qO{r`}1wGJmq@zqS-;y|2JG z8UFibbE?X6xmibdOn_W&Xb81j&as;SD8)I4Sw?;I?!FrxKK`%8nayVjUQCX3Z%e!t zP;YVM9aZl6lljmcd;jb>C1?Qi;`Cpluz+pbyRKEU9DK?Rawh_^~&o z*Iw7O8Cjc?nsNz=64?zfqDez>DxH^N=M{I;kfz0DAtA-(3mTB*X3}W*67LzqGjoHW%9o#E%ky=>L!F E56j=wzyJUM literal 0 HcmV?d00001 diff --git a/Source/CPM3/scb.asm b/Source/CPM3/scb.asm new file mode 100644 index 00000000..814deef6 --- /dev/null +++ b/Source/CPM3/scb.asm @@ -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 diff --git a/Source/CPM3/zpmldr.com b/Source/CPM3/zpmldr.com new file mode 100644 index 0000000000000000000000000000000000000000..d355f5747753d524e8a110dae1d04b963734892f GIT binary patch literal 4608 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 literal 0 HcmV?d00001 diff --git a/Source/Clean.cmd b/Source/Clean.cmd index 63f011c0..8f681c22 100644 --- a/Source/Clean.cmd +++ b/Source/Clean.cmd @@ -7,6 +7,8 @@ setlocal & cd ZCPR && call Clean.cmd & endlocal setlocal & cd ZCPR-DJ && call Clean.cmd & endlocal setlocal & cd ZSDOS && call Clean.cmd & endlocal setlocal & cd CBIOS && call Clean.cmd & endlocal +setlocal & cd CPM3 && call Clean.cmd & endlocal +setlocal & cd ZPM3 && call Clean.cmd & endlocal setlocal & cd Forth && call Clean.cmd & endlocal setlocal & cd BPBIOS && call Clean.cmd & endlocal setlocal & cd HBIOS && call Clean.cmd & endlocal diff --git a/Source/HBIOS/dbgmon.asm b/Source/HBIOS/dbgmon.asm index a75898e7..e93e6c38 100644 --- a/Source/HBIOS/dbgmon.asm +++ b/Source/HBIOS/dbgmon.asm @@ -828,7 +828,7 @@ COUT: LD E,A ; OUTPUT CHAR TO E LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR - RST 08 ; HBIOS OUTPUTS CHARACTDR + RST 08 ; HBIOS OUTPUTS CHARACTER ; ; RESTORE ALL REGISTERS POP HL @@ -851,7 +851,7 @@ CIN: ; INPUT CHARACTER FROM CONSOLE VIA HBIOS LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR - RST 08 ; HBIOS READS CHARACTDR + RST 08 ; HBIOS READS CHARACTER LD A,E ; MOVE CHARACTER TO A FOR RETURN ; ; RESTORE REGISTERS (AF IS OUTPUT) diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index bb8b0965..b518104d 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -512,45 +512,24 @@ HBX_STACK .EQU $ ; ; HBIOS INTERRUPT SLOT ASSIGNMENTS ; -; # SBC ZETA N8,MK4,RCZ180 -; --- -------------- -------------- -------------- -; 0 CTC0A Z180/INT1 -; 1 CTC0B Z180/INT2 -; 2 CTC0C Z180/TIM0 -; 3 CTC0D Z180/TIM1 -; 4 Z180/DMA0 -; 5 Z180/DMA1 -; 6 Z180/CSIO -; 7 SIO0A/B Z180/SER0 -; 8 SIO1A/B Z180/SER1 -; 9 PIO0A PIO0A -; 10 PIO0B PIO0B -; 11 PIO1A PIO1A -; 12 PIO1B PIO1B -; 13 -; 14 -; 15 -; 16 -; -; # RCZ80 EZZ80 ZETA2 -; --- -------------- ------------- -------------- -; 0 CTC0A CTC0A/SIO0CLK CTC0A/PRESCL -; 1 CTC0B CTC0B/SIO1CLK CTC0B/TIMER -; 2 CTC0C CTC0C/PRESCL CTC0C/UART -; 3 CTC0D CTC0D/TIMER CTC0D/FDC -; 4 -; 5 -; 6 -; 7 SIO0A/B SIO0A/B -; 8 SIO1A/B SIO1A/B +; # Z80 Z180 +; --- -------------- -------------- +; 0 CTC0A INT1 -+ +; 1 CTC0B INT2 | +; 2 CTC0C TIM0 | +; 3 CTC0D TIM1 | +; 4 DMA0 +- Z180 INTERNAL +; 5 DMA1 | +; 6 CSIO | +; 7 SIO0 SER0 | +; 8 SIO1 SER1 -+ ; 9 PIO0A PIO0A ; 10 PIO0B PIO0B ; 11 PIO1A PIO1A ; 12 PIO1B PIO1B -; 13 -; 14 +; 13 SIO0 +; 14 SIO1 ; 15 -; 16 ; HBX_IVT: .DW HBX_IV00 diff --git a/Source/HBIOS/ver.inc b/Source/HBIOS/ver.inc index ed69f866..315bcced 100644 --- a/Source/HBIOS/ver.inc +++ b/Source/HBIOS/ver.inc @@ -2,4 +2,4 @@ #DEFINE RMN 9 #DEFINE RUP 2 #DEFINE RTP 0 -#DEFINE BIOSVER "2.9.2-pre.17" +#DEFINE BIOSVER "2.9.2-pre.18" diff --git a/Source/ZCCP/ccp.com b/Source/ZCCP/ccp.com new file mode 100644 index 0000000000000000000000000000000000000000..72a01c681b5e2e921dfa29fec4300ab5f71541c1 GIT binary patch literal 3200 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 literal 0 HcmV?d00001 diff --git a/Source/ZCCP/read.me b/Source/ZCCP/read.me new file mode 100644 index 00000000..83dd11e6 --- /dev/null +++ b/Source/ZCCP/read.me @@ -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. + + \ No newline at end of file diff --git a/Source/ZCCP/rsxdir.com b/Source/ZCCP/rsxdir.com new file mode 100644 index 0000000000000000000000000000000000000000..dd880a61912086fe1607e71c1500f98729aa892e GIT binary patch literal 1792 zcmcgtUu;uV7(d-k&xMZLttpz@#+bvdz_lBfI@FLVll{SE#xU#{49A}odRrRTUhOSH zM^{J$een+uyqK6c-ytJWQy(BD$i{rcmBG#zm>o4|u>5(pEsFz3kg@&yp}N4)+I|cf z6z=Rp?BH#5%?kDpcJ~J9`+m92!Pl)Z98c5!SX@yPv@01($PRubus@whh0X*ht%lao zv!P`4R9s1Kt3Ci5knlXc+$c5cXd9t zQRD;ezgRVPc0U<8ie>Vo5%@}`O#tL0k3qZCcpM6>wp#_gpA{o&Ef!e=+`q5GBC49+ zjF-{o99hOLgiAsHlIIMYAvqVam4Z7P$EQ4?djNq@`wW5o9hjvFMEAlBER4={3TWO3 zL(^zSbs#{^uG*>|*2-PGfGTzaLuMx`4V}ZI2BE`&EWR%B8y1t|qU7XEn4i4JXi z>ds4egYO(}8M&yoqmQEzxrwZ6r|elS3!m6@->e164cW`{(GQMgRw<^4-6jRoXtK1b zhSb6p(C!Ha`+}P&O{j@&S_)oIC>b^%42`I#5@C2M9mmyVDwc@KvNc(j$2BZ!_OiAg z2ftrUg@!3gLq@Bb6RYVc%2btR%Rl2=0fau|ifkMgixu`ME*JHzn7eJ*r1eIf=sTYmc70r9A~SYZWRUYynE=So8%P9Wxfg3C|#*v*qt(?n~Ud}-(i=gmnC zY@a=Fh-3Hc_m(GS3lN=W^>*PO(zpdJaDAnr_qZQg?CxpLuTRRrL2f#FQ*c_lm*TN+ zqWV~r?Y7@62sr>L4XGyl6&AD$UvA#!bwdxEr3T|Lt@FCgE=sUH&l%m)n?{?|W$ch% zF=VO5XpwwIyCfJvsnO__IAbrpJ1+eAT&r+nbT}$}=XGEA*LyES-NMz3Q15kL04PQH z%4rk042X43lp$d@Z6^*8Q-0yMxu>^Z+US3DzGuYnQ#{=v*&)JdJ2R_ibJ7OUtS2j) z_53}OyIsl8_xV2IGT#y`HO#qMkY^UWY(07Q44L5RQemR3vu4utPwcx+=|P zfP`J=k*B$z%fq=lYi!#2+PsTLo^0CyCuZ9YnBpMkvLlackh9gJ(lz2_UjtGhFu?V# zFO3mwU2Qy=Cdx1fQt!G-HVtwwBeCfracW{xY7wbdMbzM zk|>yE>3M=CXGxwc&sVmD+3#eF0|Z+l<-&w6FJEr;Ke`Yd&Czw&GE41L!sAo^9-tzl zS2C=D8-=f|SJ>+u=*kuLhPCSp=kk@lcFbPn$`f!gLcbVie_A*OOt4ou^8u+JU4$Pp awWv43T4Mg(#&9^i=$w)5>Nb6lq5?65$V!k|c1cL~ z6!g$z55DvmzIEwsB8g{uVv8m|c9AQ^Wz-Jth=<{&CU(V-y4xjV+p6_~- zWwJY-oUkxQLrlBFvZ!sYx3H7lKpwd$r@MN3)A7uxoEZk;0T2uVxvK}r5(tk)M-+K5 z9Z!Iyd^w&DB?nU=Ga!$KCc86Hc|49~~LV}hc z`zG&KA%4!2RN*B@LWT1jX)pLWGFZ@AGG6$^k|D8+B*lJ`5r=mq(NCQ3PH_n%u*Bdj zuZceQHNU_@GI89Yb?!UA+Ha=|7+_H9kb&({uin4NW?0!5UrsE zzRhQ~P0IR!>H6-`Z#CAzSBUQyTo0D<~fSxSyR}yc@wh_$aWQohoJE*e$mN!D zj}+mvH&E}@rirI`{E^Fh_BfYg-O4EQ)3<^U4w(kF^H$MI06281G$&EwPZMqKBfTnYRcWz@XUt}E4&Kv$ zo79K!6+R{{(MG8#c2=;(f&v>8@Eu--)3Yd+pd+?CTMQzq6H+1cGk`o4z8hs%Gqy4Z ZEj1UQQK=?MIwCiA$%EqlHS`b1=O-Y4Ibi?* literal 0 HcmV?d00001 diff --git a/Source/ZCCP/zccp.txt b/Source/ZCCP/zccp.txt new file mode 100644 index 00000000..fb4efce9 --- /dev/null +++ b/Source/ZCCP/zccp.txt @@ -0,0 +1,308 @@ +The following is used by permission and remains copyright Randy Winchester. +=========================================================================== + +ZCCP Documentation, Version 1.0 +by Randy Winchester + +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 * +******************************************************************************* + \ No newline at end of file diff --git a/Source/ZCCP/zinstal.zpm b/Source/ZCCP/zinstal.zpm new file mode 100644 index 0000000000000000000000000000000000000000..1a6b2c4c135c490834b26ced0b91b7879c4d4570 GIT binary patch literal 1536 zcmeHG&ubGw6n-q-;DA*8b_-c_tA&C=Wacj|dgabp&gJ|HrV|BYQVl`$aI zxLdWs|J!y`X#u`iCjeh;;x!f3F60tm;)?Q40uuRu)m)WJ>f(-`7=+*Z+-g#xJ%lz Mh16{+*Zm#)33l$uwEzGB literal 0 HcmV?d00001 diff --git a/Source/ZPM3/Build.cmd b/Source/ZPM3/Build.cmd new file mode 100644 index 00000000..1e195248 --- /dev/null +++ b/Source/ZPM3/Build.cmd @@ -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 \ No newline at end of file diff --git a/Source/ZPM3/Clean.cmd b/Source/ZPM3/Clean.cmd new file mode 100644 index 00000000..f4b6eab1 --- /dev/null +++ b/Source/ZPM3/Clean.cmd @@ -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 diff --git a/Source/ZPM3/autotog.com b/Source/ZPM3/autotog.com new file mode 100644 index 0000000000000000000000000000000000000000..3c7a5980c7744b404e9190fa8c0e10b1149de8a6 GIT binary patch literal 512 zcmX>c$)pe*=@;S{Va3I(px_u9;veGg&KZ)Qo}QChtWc7Xs!&{#Sdyxcp9bbQmX_oz zIOpf)Cg!Cm1Qg}x7L;V>r6Xxo@b}|%%}Y!I=_W$4n;WM~W-+nK_4Prj3vv=GixmTFG>}OoIzVZ4=~Xk~j=veG@#-D6vy8hJlfTL0IbT!UL}sFrBn!kfH?u E009w?DgXcg literal 0 HcmV?d00001 diff --git a/Source/ZPM3/autotog.z80 b/Source/ZPM3/autotog.z80 new file mode 100644 index 00000000..b59a6663 --- /dev/null +++ b/Source/ZPM3/autotog.z80 @@ -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 + + \ No newline at end of file diff --git a/Source/ZPM3/bios.txt b/Source/ZPM3/bios.txt new file mode 100644 index 00000000..f9a6ccd7 --- /dev/null +++ b/Source/ZPM3/bios.txt @@ -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! + \ No newline at end of file diff --git a/Source/ZPM3/bnkbdos3.spr b/Source/ZPM3/bnkbdos3.spr new file mode 100644 index 0000000000000000000000000000000000000000..cd31a6a463a73ffa0d30b6a7bae7705a0613745f GIT binary patch literal 13568 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 literal 0 HcmV?d00001 diff --git a/Source/ZPM3/clrhist.z80 b/Source/ZPM3/clrhist.z80 new file mode 100644 index 00000000..9b149d24 --- /dev/null +++ b/Source/ZPM3/clrhist.z80 @@ -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 + + \ No newline at end of file diff --git a/Source/ZPM3/makedos.com b/Source/ZPM3/makedos.com new file mode 100644 index 0000000000000000000000000000000000000000..5ca35e7414c2587086e49b441cba5d94969848dd GIT binary patch literal 2176 zcmbtTU1$_n6rOBmH+K>;?o^Y`Cc3$kRhl2O>e@ZLs5m~6T3avHv+`F07q{IrnyUd+? z&Ue3a&Uen#_&KRjP%dzl&!e;4+?_Q~^aF1F@ONt-=_W4v=v46A*Zia8m)JZ^3oV`2p_C*#(1%r9=zP#S3i0x z=g$esXnj-QiZsgwuAdmBu0XBxAy0`uVMKek5-mPY1cxm|fh*SsB`^ZTr@YcA01M=f4(LelKBz_A4%A3DbQpE#fK5S+PuNQwxGD9pSP+U@^SIwF7~@D!UjB0IM{ z^hjAmLGpO%?w3GKwqM)WK@@hrPj@Eh0!L-<>Ooh(SXyyT@XO^DC_rqY5xm^8!o3}M zuqyv7eO+zg!bcvd(<}eBQl_X~%PRn)y$H_I=ImkT`Q?*K^j>-K0f6Ltm1HL?tGydB zOXYkg5}V-Sd{;N}m)Vi#UFtd~l%b*X!UK4&G}qpkZW}DN4K?A%%Zn{@*jIx%K^A=I z)gOwrA^#uq4bwN5cFXr3l~)#L2G^hAx@Zf!T_d-xKfzvjm7CZ9f|tEWZd`u~FRe)C zqx;b8)co@5!_r7bvoQQsoL9{(G4Z%z;yh7cRn7#FGAant>*$m(f|29lL+uBu?_guc z*O0_L3ABe$*8wQ*n?SpQN-bY@H+1->Z+5iGzeh1T30Id|neidxfxGhet4wxDuUq)Z zqZ~ptKKNcrb1=b`#Nmd(`{F@RLgBblIXKJSS4(Uwi7iwjaW{QFYJ=t2{KH>%JwCi1 zebaNh?xN_S9!c=BPYsxTzQyv4ljTogXNF&$5BYyBNgvlSZ%JCKlOOe)M71@20w-e0 z@IdbfR`oRQJ9~z{H`ecOtWO$wVrM8~is&|;G7Wtq91i1DhNQAs&E@d8mLnkHgsSQ6 z#=y|o7+f4PCQaNwd?=1BVrps*>y!CQAhBjeF$O>V;q5EldnPt8lmrB<49OM3RoI4| z_KLP>vXHK3U91L)AH{ueZ5vo8ByC~az!~*2!3=5@Et}+7%DAI{IDRyo97{4vGOgwd zInsHMW(5LJKJX4Fm?EIgKL$g`Bd6a<;WA`OCFF#tuqQ<|M|;e|+y*O6HbsxJix_3t9^LVik2;on|7q%+MpZJ+5g}EZUhKY|tpMTz79gIg;od z2*={dYHO)`!wKV3wb2V33mTa+3Pn?!$k;fkl;za{PFtO6@|~-e+poB~>SI z=mkAZHK(aCL^zg63?=A1;>`kK9O;~Bdde_OlCo)KdDW)qEs-=GZ?bN3LQ~Uhs;OjC zhMA?kcn=1JN$pn4xG+AwF;|#ehQYQ7(IKj(r3nZQ8L-dhEm+F_DEFe}P8UqujxfM5 mA>h0GUl@0^Ula>4{~7CLFpQ-7*fD1pb2j$wPMDULUw;E$FENz> literal 0 HcmV?d00001 diff --git a/Source/ZPM3/makedos.txt b/Source/ZPM3/makedos.txt new file mode 100644 index 00000000..a55b1e36 --- /dev/null +++ b/Source/ZPM3/makedos.txt @@ -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. \ No newline at end of file diff --git a/Source/ZPM3/resbdos3.spr b/Source/ZPM3/resbdos3.spr new file mode 100644 index 0000000000000000000000000000000000000000..2908ed3e73746f0aa6424ba416168140c7b081cc GIT binary patch literal 2048 zcmd^AZ)jUp6hHUfceA8x^RMgjjN5wOOQf$WNSoCzhBTB?+m2z&)^<838|;JlZ7m9R z>l&ZwU|$r<_Q8o2CW;@I$~ponW93muR-&emS(V^oNn}1AvO!_Y?mbVsP7(Yv1V8A3 zcka38-t#;6oO92801nuqKZM7M|HC+P;Kdh)hx8WEy;KiTy@hT?Jt{sD^jC;JK~Bp6 zead!PQV1={bL^qQsQJ2+cD%;q--L=)zoL=Ik4%0UT&`s3)l+w<9VE9PEsVn(upktK zTf)2W0R+iG-ESY%J$8&kCSl*u9k$FN*#(&!y2}ohuJ6w_7Kiiwq#)fpbCuW05mEV^ zna5U{QE|W!rPS9hn)5~%;OMT)2T80$9CiSua=TbC=W|Y%uko#;QxO|V%lnS=J*DMn zKYv#K1|00V+8XjcK*v_2x-0LnGkm8T(tnM@TUN*7!|~=4&=k71Z;S)g5XI5z339?b3I# z2dw+c1c}xmQhyC@GMCIHNDcQT7Pv#LkGFH}8|+bm~}tT9P6kF7EJ7kb({8Kv?U)B&#K zz*4a}%9^7dDZF=;`9?+J1#`YoOhj+ERxEi`l)fbzNcSG+ zOui;omWoP5lsiQQU2AaWs>;rM9Ot4rg6 zG9DJon{TqEzNxtCiL2YR(~<2|Y6v7CO1e=*)u$!A*AMaQ06;$7m&)r}L=)s0ie zrqhItr%30LRj>N~rrAY_C9QS-j!{+uAf1oRu}pTr<7plaUis)or7;w|&S|6femS>Z zyLESS*xEBGMWLzG%vQh80HjjAy||D{)f(RkAPCr2Fhd2u@ZWqILrAq){|(Zqjn61P zcQx+XUVK@>GnAWrcdoC6J<+BsR&Gzi12(~sDIIuJGB7eIhn xNTKOquUGRD-~hn6;^!dXKBs`!s@7<@VRP`J_yiQbZ~%ArJhG_401N&@`W-vF#6SQ5 literal 0 HcmV?d00001 diff --git a/Source/ZPM3/scb.txt b/Source/ZPM3/scb.txt new file mode 100644 index 00000000..78c65af8 --- /dev/null +++ b/Source/ZPM3/scb.txt @@ -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 + \ No newline at end of file diff --git a/Source/ZPM3/setz3.com b/Source/ZPM3/setz3.com new file mode 100644 index 0000000000000000000000000000000000000000..4ddb374f7fde1623e0851a6b05db4e864f310a72 GIT binary patch literal 256 zcmX?nnlZ}Q)h~>Z0SFX=BmF`gBdoZ16%>M9L!yj93}g_TT2ib~l98$q!3ZoT`wVlbTorR9T{snWm7JU!qV{ znwOWEmku^m4{o=DzCOrmm(1dVoWx3ywVA~VNky5dX$l#sIRy&2Kp3008vq-;DA*8b_-c_tA&C=Wacj|dgabp&gJ|HrV|BYQVl`$aI zxLdWs|J!y`X#u`iCjeh;;x!f3F60tm;)?Q40uuRu)m)WJ>f(-`7=+*Z+-g#xJ%lz Mh16{+*Zm#)33l$uwEzGB literal 0 HcmV?d00001 diff --git a/Source/ZPM3/zpm3.txt b/Source/ZPM3/zpm3.txt new file mode 100644 index 00000000..7df5cb8f --- /dev/null +++ b/Source/ZPM3/zpm3.txt @@ -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. + \ No newline at end of file diff --git a/Source/ZPM3/zpm3ldr.rel b/Source/ZPM3/zpm3ldr.rel new file mode 100644 index 0000000000000000000000000000000000000000..bca9c4beffba8db32815d828b89f58cf30ce8978 GIT binary patch literal 2944 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