IMD 1.18: 17/11/2012 15:06:09 hd master ver su HDXFR COMBIOS SUBCOPYFIL COMGENCPM DATPORTS LIB! PMCEQU LIBJ BNKBIOS3ASMBNKBIOS3ASM@ !"#DISKIO ASM~$%&'()*+DISKIOH ASM9,-./FORMATHDCOM01PARKHD COM 2yHCF Copyright (C), 1983 Personal Micro Computers, Inc. 475 Ellis St. Mountain View, CA 94304 version 3.0 07 FEB. 19841(!)"/QVp͏͚͡QQͼ>2͚͡QÅQ!2"""""""""Q 8K! -*"DM~SK S # : ´*"*R"R҃ C*[R*"*["*R*"*[R8K*"!P"!͇ͤ 8:[K*"!P"!͇ͷ–* "! >w#›( ѷ–‘!![s#rS*R!¥" ª *"!"S*[~#SɃ_¥[*R(l[l3ll[l l!q#p#s#r#|ʯ !1w~  !j- KlÅElllVll>q Insert HDD MASTER diskette into A: drive$ Insert CP/M SOURCE diskette into A: drive$ Verifying...$ Insert SYSTEM diskette into A: drive$ Press to continue.$ ***** File is too large to transfer! *****$ ***** File name is incorrect! *****$ ***** Read error! *****$ ***** Write error! *****$ ***** Cannot determine file length! *****$ ***** Open error! *****$ ***** Close error! *****$ ***** Cannot ERASE file! *****$ File: $is good.$ ***** CANNOT VERIFY FILE: $*****$A:BIOS.SUB $A:GENCPM.DAT $A:PORTS.LIB $A:PMCEQU.LIB $A:BNKBIOS3.ASM $A:DISKIO.ASM $A:DISKIOH.ASM $A:FORMATHD.COM $A:PARKHD.COM $RMAC SCB $$PZ SZ RMAC BNKBIOS3 $$PZ SZ RMAC DISKIO $$PZ SZ RMAC DISKIOH $$PZ SZ LINK BNKBIOS3[B]=BNKBIOS3,SCB,DISKIO,DISKIOH ERA SCB.REL ERA BNKBIOS3.REL ERA DISKIO.REL ERA DISKIOH.REL ERA BNKBIOS3.SYM GENCPM AUTO DISPLAY  Insert CP/M SOURCE diskette into A: drive$ Verifying...$ Insert SYSTEM diskette into A: drive$ Press to continue.$ ***** File is too large to transfer! *****$ ***** File name is incorrect! *****$ ***** Read error! *****$ ***** Write error! *****$ ***** Cannot determine file length! *****$ ***** Open error! *****$ ***** Close error! *****$ ***** Cannot ERASE file! *****$ File: $is good.$ ***** CANNOT VERIFY FILE: $*****$A:BIOS.SUB $A:GENCPM.DAT $A:PORTS.LIB $A:PMCEQU.LIB $A:BNKBIOS3.ASM $A:DISKIO.ASM $A:DISKIOH.ASM $A:FORMATHD.COM $A:PARKHD.COM $}COPYFIL Copyright (C), 1983 Personal Micro Computers, Inc. 475 Ellis St. Mountain View, CA 94304 version 3.0 07 FEB. 198418 &?u]b|͛ͦͭ]g]>2uͦͭg]̓]͗]0DW?H0#!~#~_A8DM ͞0͞ͷͷ>ͼ-ͷ>ͼW ͞W0͞ # :.*,"*R"Rҏ C*[R*"*["*R*"*[R DW*"!E"-ͮ#0D:gW*"!E"-ͮ#* "! >w#(7Oͷ>ͼ!W~_Y(#0ѷ!![s#rS*R! "0*"!"S0*[~#:SɃ_[*RY`rͷͷͷ͑>üͷ͑>üͷ͑>ü÷eͷ!q#p#s#r#| !Uw  +!  ]-ͷ͑ Insert SOURCE diskette into A: drive$ Insert DESTINATION diskette into A: drive$ Verifying............$ Insert SYSTEM diskette into A: drive$ Enter name of file to copy: $ Press to continue.$ ***** File is too large to transfer! ***** $ ***** File name is incorrect! ***** $ ***** Read error! ***** $ ***** Write error! ***** $ ***** Cannot determine file length! ***** $ ***** Open error! ***** $ ***** Close error! ***** $ ***** Cannot ERASE file! ***** $ Do you want to erase it (Y/N)?$ ***** File is good! ***** $ ***** Bad file, please copy over again! ***** $ SINGLE DRIVE SINGLE FILE COPY UTILITY  This utility permits the user of a single drive PMC-101 to copy a single file from one diskette to another diskette. The user is prompted for a file NAME, the SOURCE diskette and the DESTINATION diskette. As much of the file as can fit into RAM is read from the SOURCE and written to the DESTINATION diskette, which should have been previously formatted. If the file is larger than available RAM the prompts repeat until the entire file is copied. The maximum file size that can be copied is 8 Megabytes. If the DESTINATION diskette already contains a file by the same name the user is given the option of aborting or erasing the existing copy of the file.$ File: $is good.$ ***** CANNOT VERIFY FILE: $*****$A:BIOS.SUB $A:GENCPM.DAT $A:PORTS.LIB $A:PMCEQU.LIB $A:BNKBIOS3.ASM $A:DISKIO.ASM $A:DISKIOH.ASM $A:FORMATHD.COM $A:PARKHD.COM $PRTMSG = N PAGWID = 4F PAGLEN = 17 BACKSPC = N RUBOUT = Y BOOTDRV = A MEMTOP = FF BNKSWT = Y COMBAS = C0 LERROR = Y NUMSEGS = 03 MEMSEG00 = 8D,33,03 MEMSEG01 = 40,44,00 MEMSEG02 = 40,40,07 MEMSEG03 = 00,00,00 MEMSEG04 = 00,00,00 MEMSEG05 = 00,00,00 MEMSEG06 = 00,00,00 MEMSEG07 = 00,00,00 MEMSEG08 = 00,00,00 MEMSEG09 = 00,00,00 MEMSEG0A = 00,00,00 MEMSEG0B = 00,00,00 MEMSEG0C = 00,00,00 MEMSEG0D = 00,00,00 MEMSEG0E = 00,00,00 MEMSEG0F = 00,00,00 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 = 01 NDIRRECB = 00 NDIRRECC = 00 NDIRRECD = 00 NDIRRECE = 00 NDIRRECF = 00 NDIRRECG = 00 NDIRRECH = 00 NDIRRECI = 00 NDIRRECJ = 00 NDIRRECK = 00 NDIRRECL = 00 NDIRRECM = 0F 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 = 09 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 = M 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 = M ODTADRVO = A ODTADRVP = A OVLYDIRA = N OVLYDIRB = N OVLYDIRC = N OVLYDIRD = N OVLYDIRE = N OVLYDIRF = N OVLYDIRG = N OVLYDIRH = N OVLYDIRI = N OVLYDIRJ = N OVLYDIRK = N OVLYDIRL = N OVLYDIRM = N OVLYDIRN = N OVLYDIRO = N OVLYDIRP = N OVLYDTAA = N OVLYDTAB = N OVLYDTAC = N OVLYDTAD = N OVLYDTAE = N OVLYDTAF = N OVLYDTAG = N OVLYDTAH = N OVLYDTAI = N OVLYDTAJ = N OVLYDTAK = N OVLYDTAL = N OVLYDTAM = N OVLYDTAN = N OVLYDTAO = N OVLYDTAP = N CRDATAF = N DBLALV = Y . If the file is larger than available RAM the prompts repeat until the entire file is copied. The maximum file size that can be copied is 8 Megabytes. If the DESTINATION diskette already contains a file by the same name the user is given the option of aborting or erasing the existing copy of the file.$ File: $is good.$ ***** CANNOT VERIFY FILE: $*****$A:BIOS.SUB $A:GENCPM.DAT $A:PORTS.LIB $A:PMCEQU.LIB $A:BNKBIOS3.ASM $A:DISKIO.ASM $A:DISKIOH.ASM $A:FORMATHD.COM $A:PARKHD.COM $ ; 'PORTS.LIB' ; ' Copyright (C), 1983 Personal Micro Computers, Inc.' ; ' 475 Ellis St. Mountain View, CA 94304' ; ' version 3.0 1 Oct. 1983' ;04/21/83 created ;06/06/83 no changes ;10/01/83 added Ports for Hard Disk ; ***************************************************** ; * * ; * NOTE: * ; * * ; * DO NOT MODIFY ANY CODE IN THIS MODULE * ; * * ; * PMC CANNOT SUPPORT ANY MODIFICATIONS * ; * * ; ***************************************************** ; -PMC 101- Port Definitions ; Hard Disk Adaptor Port addresses HAbase equ 010h HAdata equ HAbase HActrl equ HAbase+1 HAstat equ HAbase+2 HAack equ HAbase+2 ; SASI interface Port addresses SASIbase equ 044h SASIdata equ SASIbase+1 SASIctrl equ SASIbase+2 SASIstat equ SASIbase+0 SASIack equ SASIbase+0 ; I/O Port addresses p$fdcmnd equ 080H ;WD1797 command p$fdstat equ 080H ; status p$fdtrack equ 081H ; track p$fdsector equ 082H ; sector p$fddata equ 083H ; data p$select equ 084H ; select ; set b6 for Single Density ; res b6 for Double Density ; set b5 for Motor On ; res b5 for Motor off ; set b3 for drive #4 (D)  ; set b2 for drive #3 (C) ; set b1 for drive #2 (B) ; set b0 for drive #1 (A) p$TRM$data equ 088H ;Zilog DART Channel A data p$MDM$data equ 089H ; B data p$TRM$stat equ 08AH ; A status p$MDM$stat equ 08BH ; B status p$cent$data equ 08CH ;Centronics parallel data p$cent$stat equ 08CH ; status centronics$mask equ 0011$0000b ; desired status mask ; b7 res = Busy ; b6 res = Paper Empty ; b5 res = Printer Selected ; b4 res = not Fault p$boot equ 090H ;PROM OUT any bit to Phantom boot EPROM out p$unboot equ 091H  ; OUT any bit to enable boot EPROM p$bankselect equ 092H ;Bank select res all bits for primary bank ; set b7 for alternate 64K bank ; set b2 for upper 32K ; res b2 for lower 32K ; Bank is from 4000H to BFFFH p$baud equ 093H ;Baud rate Upper nibble = A channel ; Lower nibble = B channel ; see Modebaud.lib for definition p$getbank equ 094H ;read bank select port P$getbaud equ 095H ;read baud rate port p$rtc equ 09CH ;Zilog CTC ch0 Real Time Clock p$ctc1 equ 09DH ; ch1 Reserved p$index equ 09EH ; ch2 Disk Drive Index Pulse P$ctc3 equ 09FH ;  ch3 User available  ; set b7 for alternate 64K bank ; set b2 for upper 32K ; res b2 for lower 32K ; Bank is from 4000H to BFFFH p$baud equ 093H ;Baud rate Upper nibble = A channel ; Lower nibble = B channel ; see Modebaud.lib for definition p$getbank equ 094H ;read bank select port P$getbaud equ 095H ;read baud rate port p$rtc equ 09CH ;Zilog CTC ch0 Real Time Clock p$ctc1 equ 09DH ; ch1 Reserved p$index equ 09EH ; ch2 Disk Drive Index Pulse P$ctc3 equ 09FH ;  ; 'PMCequ.LIB' ; ' Copyright (C), 1983 Personal Micro Computers, Inc.' ; ' 475 Ellis St. Mountain View, CA 94304' ; ' version 3.0 1 Oct. 1983' ;04/21/83 created ;06/06/83 added Parity mask conditional ;10/01/83 added equates for Hard Disk true equ -1 false equ not true CTS$protocol equ false ;True = CTS protocol enabled DSR$protocol equ false ;True = DSR protocol enabled Parity$Mask equ false ;True = Parity bit masked from ; TERMINAL & MODEM input ; ***************************************************** ; * * ; * NOTE: * ; * * ; * DO NOT MODIFY ANY CODE IN THIS MODULE * ; *  * ; * PMC CANNOT SUPPORT ANY MODIFICATIONS * ; * * ; ***************************************************** ; -PMC 101- Misc Values ; ASCII CR equ 0dh LF equ 0ah bdos equ 0005h bell equ 7 Bkspc equ 8 ctlQ equ 'Q'-'@' ctlS equ 'S'-'@' space equ 20H Pgm equ '3' Vrs equ '0' ; -PMC 101- Memory variables Bank0$cmd equ 00h ;turns on Bank 0 Bank1$cmd equ 81h ; 1 Bank2$cmd equ 82h ; 2 comon equ 0C000h ;physical adr of Common memory window equ 4000h ;physical adr of start of bank window sys$bank equ 0 ;CP/M system bank tpa equ 100h ;TPA begins at this adr tpa$bank equ 1 ;TPA located in this bank ccp equ 0100h ;CCP gets loaded into the TPA at this adr ccp$length equ 0C80h ;length of CCP.com ccp$ld$adr equ window*2 ;CCP stored at this adr ccp$bank equ 3 ;CCP stored in this bank ; -PMC 101- Device Variables max$devices equ 2 ;maximum I/O devices (0,1,2) ; -PMC 101- Real Time Clock Variables MaxFrc equ 62 ;RTC pps 62*16.128ms=.999936sec RTCcnt equ 252 ;RTC CTC ch0 count ; -PMC 101- Hard Disk Variables HDsec$siz equ 1024 ;Physical SEctor size HDspt equ 9 ;Physical Sectors/Track HDlogspt equ 10 ;Logical Sectors/Track HDtracks equ 306 ;Physical Tracks/Surface HDheads equ 4 ;Physical Head qty HDmax$block equ HDspt*HDtracks*HDheads ;Maximum Block Number ;CONTROL REG HDselect equ  40h ;asserts SEL to get controller onto bus ;STATUS HDreq equ 80h ;SASI REQ line (1=asserted) HDio equ 40h ;SASI I/O line (1=input) HDmsg equ 20h ;SASI MSG line (1=asserted) HDcd equ 10h ;SASI C/D line (1=command) HDbusy equ 08h ;SASI BUSY line (1-asserted) HDbsybit equ 08h ;LUN is busy HDerror equ 02h ;error in last operation ; -PMC 101- Floppy Disk Variables ; Misc max$drive equ 4 ;max possible number of physical drives SctCnt equ 5 ;Physical sectors per track retries equ 10 ;disk retry quantity IdxCnt equ 10 ;index hole count to drive motor time out Seldly equ 102 ;drive Select/motor on delay =504ms Sekdly equ 4 ;head settle delay =19ms dpb$length equ 18 ;fixed length of a DPB +1 for PMC extension trans$length equ 37 ;Max length of any translation table ; Select commands DrvA equ 001H ;Drive select bit set DrvB equ 002H DrvC equ 004H DrvD equ 008H MOTbit equ 5 ;MOTOR on bit (Select) MOTon equ 020H ;motor on bit set DENbit equ 6 ;DENSITY bit (Select) SDen equ 040H ;Single Density enable bit set DrvAon equ DrvA+MOTon ;drive A + motor on bit set DrvBon equ DrvB+MOTon DrvCon equ DrvC+MOTon DrvDon equ DrvD+MOTon ; FDC commands Homcmd equ 000H ;TYP I 6Ms step, no verify, no HLD HomVcmd equ 004H ;TYP I 6Ms step, verify, no HLD Sekcmd equ 010H ; I 6Ms step, no verify, no HLD SekVCmd equ 014H ; I 6Ms step, verify, no HLD RDcmd equ 088H ; II single Sector, no Side test, no HLD RDMcmd equ 098H ; II mult sector, IBM fmt, HLD WRcmd equ 0A8H ; II single sector, no side test no HLD WRTcmd equ 0F0H ; III write track IDcmd equ 0C0H ; III no HLD FRCcmd equ 0D0H ; IV clear previous Cmd, no int SIDbit equ 1 ;SIDE bit Sid2 equ 002H ;Side Select bit set ; -PMC 101- Drive TYPE conversion variables ;Format Types ; xx Type0 equ 0000$0000b ;Double Sided Double Density Type1 equ 0000$0001b ;Double Sided Single Density Type2 equ 0000$0010b ;Single Sided Double Density Type3 equ 0000$0011b ;Single Sided Single Density Type? equ 1111$1111b ;Undefined type ;Head Switching types ; xx Sct$sw equ 0000$0000b ;Switch head on sector count Trk$sw equ 0000$0100b ;Switch head on track count Odd$sw equ 0000$1000b ;Switch to head 1 on Odd track numbers Evn$sw equ 0000$1100b ;Switch to head 1 on Even track numbers ;Track# for head switching (Used with Trk$sw only) ; xx Trk34 equ 0000$0000b ;Switch to head 1 if Track >= 34 Trk35 equ 0001$0000b ; 36 Trk40 equ 0010$0000b ; 41 Trk80 equ 0011$0000b ; 81 ; x Side0first equ 0000$0000b ;Start with Side 0 first Side1first equ 0100$0000b ;Start with Side 1 first ;Sector# for Head switching (Used with Sct$sw only) ; xxxx Sct6 equ 0000$0000b ;Switch to head 1 if sector >= 6 Sct7 equ 0001$0000b ; 7 Sct8 equ 0010$0000b ; 8 Sct9 equ 0011$0000b ; 9 Sct10 equ 0100$0000b ; 10 Sct11 equ 0101$0000b ; 11 Sct12 equ 0110$0000b ; 12 Sct13 equ 0111$0000b ; 13 Sct14 equ 1000$0000b ; 14 Sct15 equ 1001$0000b ; 15 Sct16 equ 1010$0000b ; 16 Sct17 equ 1011$0000b ; 17 Sct18 equ 1100$0000b ; 18 Sct19 equ 1101$0000b ; 19 Sct20 equ 1110$0000b ; 20 Sct21 equ 1111$0000b ; 21 ;Conversion Drive Types PMC101d equ Type0+Sct$sw+Sct6 ;1024x 5x40 Ds Dd Morrow2 equ Type0+Odd$sw ;1024x 5x40 Ds Dd InterSystems1 equ Type0+Sct$sw+Sct11 ; 512x10x40 Ds Dd Televideo802 equ Type0+Sct$sw+Sct19 ; 256x18x40  Ds Dd HP125 equ Type0+Odd$sw ; 256x16x33 Ds Dd Sanyo equ Type0+Odd$sw ; 256x16x40 Ds Dd Kaypro4 equ Type0+Odd$sw ; 512x10x40 Ds Dd DatMac2 equ Type0+Odd$sw ; 512x10x40 Ds Dd PMC101s equ Type2 ;1024x 5x40 Ss Dd Morrow1 equ Type2 ;1024x 5x40 Ss Dd Osborne2 equ Type2 ;1024x 5x40 Ss Dd Kaypro equ Type2 ; 512x10x40 Ss Dd InterSystems2 equ Type2 ; 512x10x40 Ss Dd Dec equ Type2 ; 512x 9x40 Ss Dd IBM equ Type2 ; 512x 8x40 Ss Dd Xerox2 equ Type2 ; 256x17x40 Ss Dd Z37 equ Type2 ; 256x16x40 Ss Dd DatMac1 equ Type2 ; 128x26x40 Ss Dd Osborne1 equ Type3 ; 256x10x40 Ss Sd Xerox1 equ Type3 ; 128x18x40 Ss Sd Omikron equ Type3 ; 128x18x40 Ss Sd Cromemco equ Type3 ; 128x18x40 Ss Sd  Ds Dd PMC101s equ Type2 ;1024x 5x40 Ss Dd Morrow1 equ Type2 ;1024x 5x40 Ss Dd Osborne2 equ Type2 ;1024x 5x40 Ss Dd Kaypro equ Type2 ; 512x10x40 Ss Dd InterSystems2 equ Type2 ; 512x10x40 Ss Dd Dec equ Type2 ; 512x 9x40 Ss Dd IBM equ Type2 ; 512x 8x40 Ss Dd Xerox2 equ Type2 ; 256x17x40 Ss Dd Z37 equ Type2 ; 256x16x40 Ss Dd DatMac1 equ Type2 ; 128x26x40 Ss Dd Osborne1 equ Type3 ; 256x10x40 Ss Sd Xerox1 equ Type3 ; 128x18x40 Ss Sd title 'BIOS for CP/M 3.0 & PMC-101' ; Copyright (C), 1982,83 ; ; Digital Research, Inc Personal Micro Computers, Inc. ; P.O. Box 579 475 Ellis St. ;Pacific Grove, CA 93950 Mountain View, CA 94304 ; ; version 1.0 15 Sept 82 version 3.0 07 FEB. 1984 ;04/21/83 created ;06/06/83 added Parity mask conditional ;10/01/83 added Hard Disk Driver ;02/07/84 added DRI patches 9-14 to INITDIR,DIRLBL,HELP,CCP,BDOS,PATCH ;??/??/?? ; ***************************************************** ; * * ; * NOTE: * ; * * ; * DO NOT MODIFY ANY CODE IN THIS MODULE * ; * * ; * PMC CANNOT SUPPORT ANY MODIFICATIONS  * ; * * ; ***************************************************** ; ; To generate a new copy of CPM3.SYS insert a COPY of the SOURCE disk into ; the A drive. Press the reset buton. When the ' A> ' prompt appears type ; SUBMIT BIOS. This will automatically execute all the necessary ; commands to generate a new CPM3.SYS file. When execution is ; completed press the reset button to load the new operating system. ; ; This module contains BIOSKRNL, MOVE, CHARIO, BOOT, DRVTBL ;ONLY USE ODD NUMBERED BANKS WHEN SETTING UP THE SEGMENT TABLES WITH GENCPM. ; bank number 00 is used for the system bank. ; bank number 01 is used for the TPA (bank 1) ; bank number 03 is used for the CCP stored in bank 2 ; bank number 07 is used for bank 2 ; **************************************************** maclib z80 maclib ports maclib modebaud maclib PMCequ public @adrv,@rdrv,@trk,@sect,@dma,@cbnk,@dbnk,@type public pmsg,pderr,?const,?conin,?conout extrn f$write, f$read, f$login, f$init extrn f$Hwrite, f$Hread, f$Hlogin, f$Hinit extrn @covec,@civec,@aovec,@aivec,@lovec,@mxtpa,@bnkbf,@sec,@date ;********************** Cseg Code ******************************************** cseg ; GENCPM puts CSEG stuff in common memory 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 ?conout:jmp conout ; send console output character jmp list ; send list output character jmp auxout ; send auxilliary output character jmp auxin ; return auxilliary input character jmp home ; set disks to logical home jmp seldsk ; select disk drive, return disk parameter info jmp settrk ; set disk track jmp setsec ; set disk sector jmp setdma ; set disk I/O memory address jmp read ; read physical block(s) jmp write ; write physical block(s) jmp listst ; return list device status jmp sectrn ; translate logical to physical sector jmp conost ; return console output status jmp auxist ; return aux input status jmp auxost ; return aux output status jmp devtbl ; return address of device def table jmp cinit ; change baud rate of device jmp getdrv ; return address of disk drive table jmp multio ; set multiple record count for disk I/O jmp flush ; flush BIOS maintained disk caching jmp move ; block move memory to memory jmp time ; Signal Time and Date operation ?bnksl: jmp bnksel ; select bank for code execution and default DMA jmp setbnk ; select different bank for disk I/O DMA operations. jmp xmove ; set source and destination banks for one operation jmp 0 ; reserved for future expansion +5A jmp 0 ; reserved for future expansion +5D jmp 0 ; reserved for future expansion +60 jmp 0 ; reserved by PMC +63 jmp 0 ; reserved by PMC +66 jmp 0 ; reserved by PMC +69 jmp 0 ; reserved by PMC +6C db 0C4h ; Do Not Change +6f ;***************** ; Interrupt Vectors ;***************** INTvec: CTCvec: DW i$rtc,i$ctc1,i$index,i$ctc3 ;***************** ; Interrupt Routines ;***************** i$rtc: ;CTC ch0 REAL TIME CLOCK di sspd RTCstk ;interrupts every 16.384ms lxi sp,RTCstk push psw push b push d push h lxi h,Frac inr m mvi a,maxFrc cmp m jrnz rtc$ext mvi m,0 mvi b,3 lxi h,timtbl lxi d,@sec rtc$1: ldax d inr a daa stax d cmp m ;compare to MAX value from table jrnz rtc$ext ;if not Max then skip mov a,b ;see if Day would be next dcr a xchg mvi m,0 ;preset current to 0 jrnz rtc$2 push h lhld @date ;and up date inx h shld @date pop h rtc$2: xchg inx h dcx d djnz rtc$1 rtc$ext:pop h pop d pop b pop psw lspd RTCstk ei reti i$ctc1: ;CTC ch1 RESERVED reti ;reserved for bus port i$index: ;CTC ch2 INDEX PULSE di push psw ;use 1 level of user stack mvi a,0000$0011B ;reset out p$index xra a out p$select ;deselect all drives pop psw ei reti i$ctc3: ;CTC channel 3 ; di ;sample entry & exit code for ; sspd CTC3stk ;user available CTC interrupts ; lxi sp,CTC3stk ; push psw ; push b ; push d ; push h ; ;user code goes here ; pop h ; pop d ; pop b ; pop psw ; lspd CTC3stk ; ei reti ; ds 16 ; stack space ;CTC3stk: ds 2 ; storage for SP on entry to i$CTC3 ;***************** ; Warm boot ;***************** wboot: lxi sp,boot$stack boot$1: 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,ccp$bank call ?bnksl ; select extra bank lxi d,0100h ; copy CCP to bank 3 for reloading lxi b,ccp$length lxi h,ccp$ld$adr ldir mvi a,tpa$bank call ?bnksl ; activate TPA bank jmp ccp ;***************** ; Character Init ;***************** cinit: mov a,c cpi max$devices jrz cent$init rnc ; invalid device or no init required for parll ser$init: mov l,c mvi h,0 ; make 16 bits from device number dad h dad h dad h ; *8 lxi d,@ctbl+7 dad d  mov a,m ;DRI's baud table does not match ours cpi 10 ;if the baud rate is 9 or less then jrnc no$change ;we need to drop it down 1 rate to dcr a ;compensate for our 2000 baud rate no$change: ;which they do not support mov b,a mov a,c ;get device numer ora a jrz chA$baud ;if A ch in p$getbaud ;read baud ani 0F0H ;mask out old B ch jr set$bd chA$baud: mov a,b ;move baud bits to hi nibbble rlc rlc rlc rlc mov b,a ;save back to b in p$getbaud ;read old baud ani 0FH ;mask out old A ch set$bd: ora b ;or in new baud di out p$baud ;set it ei ret ;***************** cent$init:  ret ;***************** ; Character output ;***************** conout: lhld @covec ; fetch console output bit vector jr out$scan auxout: lhld @aovec ; fetch aux output bit vector jr out$scan list: lhld @lovec ; fetch list output bit vector out$scan: mvi b,0 ; start with device 15 co$next:dad h ; shift out next bit jrnc not$out$device push h ; save the vector push b ; save the count and character not$out$ready: call coster ora a jrz 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 jrnz co$next ; and go find them... ret ;***************** ?co: ; character output mov a,b cpi max$devices jrz centronics$out jrnc null$output mov a,c push psw ; save character from push b ; save device number co$spin: mov a,b call ?cost jrz 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 1111$0000b ;mask off spurious bits cpi centronics$mask ;check Busy, Empty, Selected & Fault jrnz centronics$out mov a,c out p$centdata ; give printer data ret ;***************** ; Character Output Status ;***************** conost: lhld @covec ; get console output bit vector jr ost$scan auxost: lhld @aovec ; get aux output bit vector jr ost$scan 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,-1 ; 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 jrnz cos$next ori -1 ; all selected were ready, return true ret ;***************** ?cost: ; character output status mov a,b cpi max$devices jrz cent$stat jrnc null$status mov l,b mvi h,0 lxi d,data$ports dad d mov c,m inr c inr c if CTS$protocol mvi a,0001$0000b ;reset Ext. status outp a inp a ; get output status ani 0010$0000b ; test CTS rz endif if DSR$protocol mvi a,0001$0000b ;reset Ext. status outp  a inp a ; get output status ani 0001$0000b ; test RI (DSR) rz endif inp a ; get output status ani 0000$0100b ; test transmitter empty rz ; ret false if not ready ori -1 ret ; return true if ready ;***************** cent$stat: in p$centstat ani 1111$0000b cpi centronics$mask mvi a,-1 ;ready rz mvi a,0 ;not ready ret ;***************** ; Character Input Status ;***************** const: lhld @civec ; get console input bit vector jr ist$scan 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 jrnz cis$next xra a ; all selected were not ready, return false ret ;***************** cist1: ; get input status with and saved push b push h call ?cist pop h pop b ora a ret ;***************** ?cist: ; character input status mov a,b cpi max$devices jrnc 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 DART status port inr c inp a ; read from status port ani 1 ; isolate RxRdy rz ; return with zero no char ori -1 ret ;***************** null$status: xra a ret ;***************** ; Character Input ;***************** conin: lhld @civec jr in$scan 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 jrnz ci$rdy ; this device has a character inr b ; else, next device mov a,h ora l ; see if any more devices jrnz ci$next  ; go look at them pop h ; recover bit vector jr in$scan ; loop til we find a character ci$rdy: pop h ; discard extra stack ?ci: mov a,b ; character input cpi max$devices jrnc null$input ; can't read from centronics cir1: mov a,b call ?cist jrz cir1 ; wait for character ready dcr c dcr c inp a ; get data if parity$mask ani 7Fh ; mask parity endif ret ;***************** null$input: mvi a,1Ah ; return a ctl-Z for no device 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 jrnz not$q ; if its a ctl-Q, mvi a,-1 ; set the flag ready not$q: cpi ctls jrnz 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 ;***************** ci1: ; get input, saving & push b push h call ?ci pop h pop b ret ;***************** cost1: ; get output status, saving & push b push h call ?cost pop h pop b ora a ret ;***************** ; Get Device Table adr ;***************** devtbl: lxi h,@ctbl ret ;***************** ; Get Drive Table adr ;***************** getdrv: lxi h,@dtbl ;get Drive table adr ret ;***************** ; Set/Get Time ;***************** time: mov a,c ora a ;0= get time -1= set time rz ;RTC updates SCB directly no need to get time set$time: ;Set time activates Clock, Time already in SCB mvi a,1010$0111b ;set CTC ch0 command to: di ; Int enable, Timer mode, prescaler 256 out p$rtc ; auto trigger,load count next & reset mvi a,RTCcnt ;set CTC ch0 time count to 252 out p$rtc ; time = 250ns*256presc*252Cnt=16.128ms ei ret ;***************** ; Inter bank Block Move ;***************** xmove: ; C= src bank B= dest bank sbcd src$bnk ;save banks ori -1 ;set xmove pending flag sta xmv$flg ret ;***************** ; Intra bank Block Move ;***************** move: lda xmv$flg ; check xmove pending flag ora a jrnz exmve ;if set do an extended move else xchg ; we are passed source in DE and dest in HL, len in BC ldir ; use Z80 block move instruction xchg ; need next addresses in same regs ret exmve: xra a sta xmv$flg ;clear xmove flag lda @cbnk push psw ;save current bank xchg ;HL=src DE=dest lda src$bnk call bank ;set source bank push d ;save dest aadr push b ;save length lxi d,buffer ldir ;src->buffer pop b ;restore length pop d ;restore destination adr lda dst$bnk call bank ;set destination bank push h ;save end of source adr lxi h,buffer ldir ;buffer ->dst pop h ;restore source adr end xchg pop psw ;restore current bank fall through to bnksel: sta @cbnk ; remember current bank bank: ora a jrz bank1 ;skip if bank 0 else ori 80h ;set hibit to activate bank select bank1: out p$bankselect ; put new memory control byte ret ;***************** ; Utility Subroutines ;***************** ; none ;********************** Cseg Data ******************************************** ; Drive Table ;All four dph's must be set for GENCPM to allocated the necessary buffers @dtbl dw dph0 ,dph1 ,dph2 ,dph3 ;Drives A-D (5") dw 00000,00000,0000 ,00000 ;Drives E-H dw 00000,00000,00000,00000 ;Drives I-L dw dph12,dph13,00000,00000 ;Drives M-P (Hard) ; Device Table @ctbl: ;Channel A must always be first item in table db 'TERMNL' ; device 0[8000], DART ch A db mb$in$out+mb$serial+mb$softbaud @Abaud: ds 1  ;set by boot: ;Channel B must always be second item in table db 'MODEM ' ; device 1[4000], DART ch B db mb$in$out+mb$serial+mb$softbaud @Bbaud: ds 1 ;set by boot: ;Other Devices ahould be inserted here ;Centronics must always be last item in table db 'CENTRN' ; device 3[1000], Centronics parallel printer db mb$output db baud$none db 0 ; Disk Parameter Blocks dpb0: ; Double Density Double Sided for PMC-101 1024 dw 80 ; SPT 128 BYTE RECORDS PER TRACK db 4,15,1 ; BSH,BLM,EXM BLOCK SHIFT AND MSK, EXTENT MSK dw 194,127 ; DSM,DRM MAX BLOCK #, MAX DIR ENTRY # db 192,0 ; AL0,AL1 ALLOC VEC f/DIR dw 32,1 ; CKS,OFF CHECKSUM SIZ, OFFSET f/SYS TRK db 3,7  ; PSH,PHM PHYSICAL SECTOR SIZE SHIFT db 'A' ; CONVERT TYPE PMC extension dpb1: ; Double Density Double Sided for PMC-101 1024 dw 80 ; SPT db 4,15,1 ; BSH,BLM,EXM dw 194,127 ; DSM,DRM db 192,0 ; AL0,AL1 dw 32,1 ; CKS,OFF db 3,7 ; PSH,PHM db 'A' ; CONVERT TYPE PMC extension dpb2: ; Double Density Double Sided for PMC-101 1024 dw 80 ; SPT db 4,15,1 ; BSH,BLM,EXM dw 194,127 ; DSM,DRM db 192,0 ; AL0,AL1 dw 32,1 ; CKS,OFF db 3,7 ; PSH,PHM db 'A' ; CONVERT TYPE PMC extension dpb3: ; Double Density Double Sided for PMC-101 1024 dw 80 ; SPT  db 4,15,1 ; BSH,BLM,EXM dw 194,127 ; DSM,DRM db 192,0 ; AL0,AL1 dw 32,1 ; CKS,OFF db 3,7 ; PSH,PHM db 'A' ; CONVERT TYPE PMC extension dpbHD: DW 80 ; SPT SEC=9sptx4hdsx8logical DB 5,31,1 ; BSH,BLM,EXM BLS=4096 DW 2749,2047 ; DSM,DRM DRM=2048 DB 255,255 ; AL0,AL1 DRM+1/32 bits hi DW 8000h,1 ; CKS,OFF DRM+1/4 DB 3,7 ; PSH,PHM db 'A' ; Misc storage data$ports: db p$TRM$data, p$MDM$data ; serial base ports src$bnk: db 0 ;source bank f/xmove DO NOT dst$bnk: db 0 ;dest " " CHANGE ORDER xmv$flg:  db 0 ;xmove flag buffer: ds 128 ;xmove buffer @cbnk db 0 ; bank for processor operations Frac: db 00 ;Fractions of Seconds for RTC TimTbl: db 60h,60h,24h ;Max Seconds,Minutes,Hours xofflist rept max$devices ; ctl-s clears to zero db -1 endm ; Stack space allocation ds 18 ;RTC Int stack space RTCstk: ds 2 ;storage for SP on entry to RTC ds 4 ;boot&wboot stack space boot$stack equ $ ;********************** Dseg Code ******************************************** dseg ; this part is banked ;***************** ; Select Disk ;***************** 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 mov a,e ani 1 jrnz not$first$select push h xchg lxi h,-2 dad d mov a,m sta @rdrv lxi h,-6 dad d mov a,m inx h mov h,m mov l,a call ipchl pop h not$first$select: ret ;***************** ; Home Disk ;***************** home: lxi b,0 ; same as set track zero ;***************** ; Set Desired Track ;***************** settrk: mov l,c mov h,b shld @trk ret ;***************** ; Set Desired Sector ;***************** setsec: mov l,c mov h,b shld @sect ret ;***************** ; Set Desired DMA adr ;***************** setdma: mov l,c mov h,b shld @dma lda @cbnk ; default DMA bank is current bank setbnk: sta @dbnk ret ;***************** ; Logical to physical sector translation ;***************** sectrn: mov l,c mov h,b mov a,d ora e rz xchg dad b mov l,m mvi h,0 ret ;***************** ; Read sector ;***************** 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 jr rw$common ; use common code ;***************** ; write sector ;***************** 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 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 ; point to drive type ldax d sta @type ; post drive type 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 ipchl: pchl ; leap to driver ;***************** ; Multiple Sector I/O ; & ; Flush buffers ;***************** multio: ;not implemented xra a ret flush: ;not implemented xra a ret ;***************** ; Print message to terminal ;***************** pmsg: ; print msg pointed to by push b ; until a null is found push d ; saves & pmsg$loop: mov a,m ora a jrz pmsg$exit mov c,a push h call ?conout pop h inx h jr pmsg$loop pmsg$exit: pop d pop b ret ;***************** ; Print Disk error message ;***************** pderr: lxi h,drive$msg call pmsg ; error header lda @adrv adi 'A' mov c,a call ?conout ; 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 pdec: ; Convert HL to decimal and print (0->65535) lxi b,table10 lxi d,-10000 next: mvi a,'0'-1 pdecl: push h inr a dad d jrnc stoploop inx sp inx sp jr pdecl stoploop: push d push b mov c,a call ?conout 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 jrnz next ret ;********************** Dseg Data ******************************************** ; Disk Parameter Headers xdph0: dw f$write ; Write vector dw f$read ; Read Vector dw f$login ; Login vector dw f$init ; Init vector db 0 ; UNIT ->@rdrv db PMC101d ; TYPE dph0: dw Trans0 ; XLT Translate Table Address db 0,0,0,0,0,0,0,0,0 ; -0- BDOS scratch area db 0 ; MF Media Flag dw dpb0 ; DPB Disk Parameter Block dw ck0 ; CSV Checksum Vector dw al0 ; ALV Allocation Vector dw 0FFFEh ; DIRBCB Directory Buffer Control Block Vector dw 0FFFEh ; DTABCB Data Buffer Control Block Vector dw 0FFFEh ; HASH Hash Table Vector db 0 ; HBANK Hash Bank xdph1: dw f$write,f$read,f$login,f$init db 1,PMC101d dph1: dw Trans1 db 0,0,0,0,0,0,0,0,0,0 dw dpb1,ck1,al1,0FFFEh,0FFFEh,0FFFEh db 0 xdph2: dw f$write,f$read,f$login,f$init db 2,PMC101d dph2: dw Trans2 db 0,0,0,0,0,0,0,0,0,0 dw dpb2,ck2,al2,0FFFEh,0FFFEh,0FFFEh db 0 xdph3: dw f$write,f$read,f$login,f$init db 3,PMC101d dph3: dw Trans3 db 0,0,0,0,0,0,0,0,0,0 dw dpb3,ck3,al3,0FFFEh,0FFFEh,0FFFEh db 0 xdph12: dw f$Hwrite,f$Hread,f$Hlogin,f$Hinit db 00h,0 ;drive #0, ID=0 dph12: dw 0000 ;no trans for HD db 0,0,0,0,0,0,0,0,0,0 dw dpbHD,0000,al12,0FFFEh,0FFFEh,0FFFEh ;no ck12 vector db 0 xdph13: dw f$Hwrite,f$Hread,f$Hlogin,f$Hinit db 20h,0 ;drive #1, ID=0 dph13: dw 0000 ;no trans for HD db 0,0,0,0,0,0,0,0,0,0 dw dpbHD,0000,al13,0FFFEh,0FFFEh,0FFFEh ;no ck12 vector db 0 ;***************************** ; OVERLAY: Since BOOT is only called once the Boot code is overlayed by ; buffer space allocated to CKS & ALL. overlay$1: ;Define addresses of buffers ;Set buffer size to largest needed by any drive in 'CONVERT' ck0 equ overlay1 ;5" CHECKSUM VECTOR DRM+1/4 ck1 equ ck0+48 ;set for max required in CONVERT ck2 equ ck1+48 ck3 equ ck2+48 nxt$adr set ck3+48 ck12 equ nxt$adr ;HD ck13 equ ck12+0 nxt$adr set ck13+0 al0 equ nxt$adr ;5"  ALLOCATION VECTOR DSM/4+2 al1 equ al0+101 ;set for max required in CONVERT al2 equ al1+101 ;101 for 96 tpi, 65 for 48 tpi al3 equ al2+101 nxt$adr set al3+101 al12 equ nxt$adr ;HD al13 equ al12+690 next$adr set al13+690 ;***************** ; Cold Boot ;***************** boot: di ;BOOT ROM & CPMLDR leave us in di mode lxi sp,boot$stack lxi h,0 ;clear drives 2,3,4 from drive table shld @dtbl+2 ; (they must be present for GENCPM to allocate shld @dtbl+4 ; the proper buffers) shld @dtbl+6 ldai ; I reg contains drive quantity (from BOOT ROM) dcr a ; Drop count jrz no$more$drives ; if 0 then drive B is not present lxi h,dph1 ;else set dph adr into drive table shld @dtbl+2 dcr a ; Drop count jrz no$more$drives ; if 0 then drive C is not present lxi h,dph2 ;else set dph adr into drive table shld @dtbl+4 dcr a ; Drop count jrz no$more$drives ; if 0 then drive D is not present lxi h,dph3 ;else set dph adr into drive table shld @dtbl+6 no$more$drives ;BOOT ROM sets Baud rate, so we ; set current Baud Rates into @ctbl in p$getbaud ;read current baud rates mov c,a ;save in c ani 0fh ;mask off unwanted bits cpi 10 ;if the baud rate is 9 or less then jrnc no$change1 ;we need to up it 1 rate to inr a ;compensate for our 2000 baud rate no$change1: ;which they do not support sta @Bbaud ;save in B channel baud slot of Char table mov a,c ;restore baud rrc ;move A chan bits to Lo nibble rrc rrc rrc ani 0fh ;mask off unwanted bits cpi 10 ;if the baud rate is 9 or less then jrnc no$change2 ;we need to up it 1 rate to inr a ;compensate for our 2000 baud rate no$change2: ;which they do not support sta @Abaud ;save in A channel baud slot of Char table ; Next set up the Device Vectors ; Logical Physical Baud Prot- ; device device Rate ocol ; ;+-----------> dev 00 TERMNL 9600 ;|+----------> dev 01 MODEM 9600 ;||+---------> dev 02 CEN none ;|||+-++++-++++---> dev 03-11 ;|||| |||| |||| ++++-> reserved ;|||| |||| |||| |||| lxi h,08000h ; assign TERMNL to CON: shld @civec shld @covec lxi h,4000H ; assign MODEM to AUX: shld @aivec shld @aovec lxi h,2000H ; assign CEN to LPT: shld @lovec lxi h,INTvec ; Set I register with MSB of the Interrupt Vect mov a,h stai im2 ;Set IM 2 interrupt mode lxi h,CTCvec ;get CTC interrupt Vector mvi b,4 ;CTC channel quantity mvi c,p$rtc ;1st CTC ch mvi a,03 ;RESET command outp a ;reset channel 0 outp l ;set LSB of CTC Interrupt Vector into ch0 init$lp:inr c outp a ;reset all other channels djnz init$lp ei lxi h,signon$msg call pmsg ; print signon message jmp boot$1 ; back to Cseg code signon$msg db '128K PMC-101 CP/M 3.0 with extended Bios' db ' for MicroMate -Vers' db pgm,'.',vrs,'-',cr,lf,0 ; End of BOOT routine cannot exceed the length of the buffers! ; BOOT routine cannot do any Disk IO ;(length of buffers) - (length of BOOT) = size of space still to be defined ; for buffers ds (next$adr-overlay$1)-($-boot) ;***************** ; Translation Tables ; Each drive must have its own Trans table for 'CONVERT' ; Each table has a fixed length, set to largest used by 'CONVERT' Trans0: db 1,2,3,4,5 ;Side 0 db 6,7,8,9,10 ;Side 1 ds trans$length-($-Trans0) ; room for expansion Trans1: db 1,2,3,4,5 ;Side 0 db 6,7,8,9,10 ;Side 1 ds trans$length-($-Trans1) Trans2: db 1,2,3,4,5 ;Side 0 db 6,7,8,9,10 ;Side 1 ds trans$length-($-Trans2) Trans3: db 1,2,3,4,5 ;Side 0 db 6,7,8,9,10 ;Side 1 ds trans$length-($-Trans3) ; Variable Storage @type ds 1 ; currently selected format type @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 @dbnk db 0 ; bank for DMA operations ; Disk Error message drive$msg db cr,lf,bell,'Error on ',0 track$msg db ': T-',0 sector$msg db ', S-',0 table10: dw -1000,-100,-10,-1,0 ;Hex to Dec table end  title 'Disk I/O routines for CP/M 3.0 & PMC-101' ; ***************************************************** ; * * ; * NOTE: * ; * * ; * DO NOT MODIFY ANY CODE IN THIS MODULE * ; * * ; * PMC CANNOT SUPPORT ANY MODIFICATIONS * ; * * ; ***************************************************** ; 'DISKIO' ; ' Copyright (C), 1983 Personal Micro Computers, Inc.' ; ' 475 Ellis St. Mountain View, CA 94304' ; ' version 3.0 07 FEB. 1984' ;04/21/83 created ;06/06/83 no changes ;10/01/83 no changes ;02/07/84 no changes ;??/??/?? maclib z80 maclib ports maclib PMCequ public f$read, f$write, f$login, f$init, RWdon extrn @rdrv, @adrv, @dma, @dbnk, @trk, @sect, @ermde, @cbnk, @type extrn ?conin, ?const, ?conout, pderr, pmsg dseg ;******************** ; Initialization entry point. called for first time initialization. ; ;******************** f$init: ;******************** ; 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 ; ;******************** f$login: ret ;no initialization or login required ;******************** ; 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 ;******************** f$read: lxi h,read$msg mvi a,RDcmd lxiy RDent ;IY->entry point jr f$rw$common f$write: lxi h,write$msg mvi a,WRcmd lxiy WRent f$rw$common: lxix Disk$command stx a,0 ;LD (IX+0),A save command shld operation$name ;save operation in error message lda @rdrv lxi h,track$table ;set HL to base of Track Table call adahl shld Trk$tbl$ptr ;Save HL pointing to current track mov a,m out p$fdtrack ;put cur Trk for this Drv back in tk reg mvi a,4 call adahl mov b,m ;b-> Select Value lda @sect ;save sector  sta s$sect lda @trk ;save track sta s$trk lda @type ;check type mov c,a ani 0000$0011b ;mask TYPE bits lxi h,Type$tbl get$tbl: add a ;pointer *2 call adahl mov a,m ;get table entry inx h mov h,m mov l,a mov a,c pchl ;jump rw$DsSd: ;TYPE 1 setb DENbit,b ;set Single Density always jr Ds$Ent rw$DsDd: ;TYPE 0 res DENbit,b ;set Double Density always Ds$ent: rrc ;-0000$000 rrc ;--0000$00 mov c,a ani 0000$0011b ;mask SWITCH bits lxi h,switch$tbl jr get$tbl Sector$switch: rrc ;---0000$0 rrc ;----0000$ ani 0000$1111b ;mask COUNT bits adi 6 ;sectors range from 6 to 21 mov c,a lda s$sect ;get desired Sector cmp c ;see if <=physical Sec/Trk jrc set$S0 lxi h,s$sect change: dcr c sub c mov m,a jr set$S1 Track$switch: rrc ;---0000$0 rrc ;----0000$ mov c,a ani 0000$0011b ;mask COUNT bits lxi h,Trk$tbl call adahl mov a,c mov c,m rrc ;-----000 rrc ;------00 ani 0000$0001b ;mask side first bit ora a jrnz S1$first S0$first: lda s$trk ;get desired Track cmp c ;see if <=physical Trk/side jrc set$S0 lxi h,s$trk dcr  c sub c mov m,a jr set$S1 S1$first: lda s$trk ;get desired Track cmp c ;see if <=physical Trk/side jrc set$S1 lxi h,s$trk dcr c sub c mov m,a jr set$S0 Odd$switch: lda s$trk ;get desired Track bit 0,a ;0=even=side 0 push psw rrc ;make side 1 same track # as side 0 ani 0111$1111b sta s$trk pop psw jrz set$S0 ;set side 0 if yes jr set$S1 ;else set side 1 Even$switch: lda s$trk ;get desired Track bit 0,a ;1=Odd=side 0 push psw rrc ;make side 1 same track # as side 0 ani 0111$1111b sta s$trk pop psw jrnz set$S0 ;set side 0 if yes set$S1: setx SIDbit,0 ;else set Side 1 bit in 1797 cmnd jr select$drive rw$SsDd: ;TYPE 2 res DENbit,b ;set Double Density always jr set$S0 rw$SsSd: ;TYPE 3 setb DENbit,b ;set Single Density always set$S0: resx SIDbit,0 ;set Side 0 always select$drive: call SelDrv ;Select & check for Disk Drive in B usr$rty: xra a ;clear retry count sta RtyCnt retry$lp: lda s$sect out p$fdsector ;set Sector lhld Trk$tbl$ptr ;get Track table pointer mvi a,-1 ;if Drv not previously Selected cmp m jz go$home ;then do a home & go back to retry$lp lda s$trk ;else get desired track cmp m ;see if =current track jrz noSek ;if so skip seek out p$fddata ;else output track to data port mov m,a ;save as current Trk call f$seek ;seek the track noSek: mvi C,p$fddata lhld @dma ;get DMA adr lda disk$command ;get command call execute ;in cseg, sets @dbnk,does I/O,set bank 0,ret sta disk$status ;save returned status lxi h,disk$command ;check command bit 6,m jrz wr$mask ;if command was a write use write error mask ani 0001$1111b ;else use read error mask jr save$error wr$mask: ani 0111$1111b ;mask write errors save$error: jrz RWexit ;return if no errors lxi h,RtyCnt inr m ;up retry count mov a,m cpi retries ;see if max jrz MaxRty ;if so set to NZ and ret go$home: call restor e jr retry$lp ;else home & reseek MaxRty: lda @ermde ; suppress error message if BDOS is returning cpi -1 ; errors to application... jrz hard$error call pderr ; Had permanent error, print error message lhld operation$name call pmsg ; then, messages for all indicated error bits lda disk$status ; get status byte from last error lxi h,err$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 jrnz errm1 ; if any more bits left, continue lxi h,err$msg  call pmsg ; print ", retry (Y/N) ? " call u$conin$echo ; get operator response cpi 'Y' jrz usr$rty hard$error: ; otherwise, mvi a,1 RWexit: push psw mvi a,11000111B ;set CTC ch2 (Index Pulse Interrupt) for di ; Int enable, Counter mode, Load constant next out p$index ; & reset mvi a,IdxCnt ;set count out p$index ei pop psw ret cseg ;********** execute: ;must reside in cseg push psw lda @dbnk ;set DMA bank ora a jrz exec$1 dcr A ori 80H ;set hi bit if not bank 0 exec$1: out p$bankselect pop psw ;restore command di out p$fdcmnd call Delay ;command delay pciy ;********** RDent: in p$fdcmnd bit 1,A ;check DRQ jrz noDRQ1 ini noDRQ1: bit 0,A ;check busy jnz RDent jr RWdon WRent: in p$fdcmnd bit 1,A ;check DRQ jrz noDRQ2 outi noDRQ2: bit 0,A ;check busy jnz WRent RWdon: push psw ;save status xra a ;set bank 0 out p$bankselect pop psw ;restore status ei ret ;********** Delay: push b ;44us lxi b,5 USRdly: dcx b mov a,B ora C jrnz USRdly pop b ret ;******************** adahl: add l mov l,a rnc inr h ret dseg ;********** SelDrv: mvi a,00000011B ;reset Index Pulse interrupts di out p$index ei in p$fdcmnd ;check FOR TIMEOUT rlc push psw ;C=not READY mov a,b out p$select pop psw rnc mvi a,Seldly call Delay2 DSKin?: in p$fdcmnd rrc jrc DSKin? ;loop until not busy mvi a,FRCcmd out p$fdcmnd call Delay in p$fdcmnd ani 00000010B ;check index mov d,a ;save index status mvi h,78 ;set counter din$2: dcx h ;drop counter mov a,h ora l jrz DSKin? ;if counter expires try again in p$fdcmnd ani 00000010B ;check index cmp d ;compare it to last index status mov d,a ;save new status jrz din$2 ;loop back if equal  ret ;********** f$seek: ora a jrz restore out p$fddata ;else output track to p$fddata mvi a,Sekcmd ;seek command out p$fdcmnd ;output to p$fdcmnd call Delay sk$1: in p$fdcmnd rrc ;check busy jrc sk$1 mvi a,Sekdly ;Wait for STEP to settle Delay2: push d ;4945$25us*A+14us push b mov c,a Dly2$1: lxi d,0760 Dly2$2: dcx d mov a,e ora d jrnz Dly2$2 dcr c jrnz Dly2$1 pop b pop d ret ;********** restore: mvi a,Homcmd out p$fdcmnd wait3: call Delay in p$fdcmnd bit 0,a jrnz wait3 lhld Trk$tbl$ptr mvi m,0 ;UpDate Track# ret ;******************** u$conin$echo:   ; get console input, echo it, and shift to upper case call ?const ora a jrz u$c1 ; see if any char already struck call ?conin jr u$conin$echo ; yes, eat it and try again u$c1: call ?conin push psw mov c,a call ?conout pop psw ani 5fh ; make upper case ret ;******************** disk$command: ds 1 ; current wd1797 command disk$status: ds 1 ; last error status code for messages s$sect: ds 1 ; current physical sector s$trk: ds 1 ; current physical track RtyCnt: db retries ;disk retry count Trk$tbl$ptr: dw track$table ;Pointer to current track$table entry track$table: DB -1 ;Current Track Table A KEEP ORDER DB -1 ; B  DB -1 ; C DB -1 ; D sel$table: DB DrvAon ;drive#+motor on bit A KEEP ORDER DB DrvBon ; B DB DrvCon ; C DB DrvDon ; D Type$tbl: dw rw$DsDd ;type 0 DsDd 00 dw rw$DsSd ;type 1 DsSd 01 dw rw$SsDd ;type 2 SsDd 01 dw rw$SsSd ;type 3 SsSd 00 switch$tbl: dw Sector$switch ;switch on sector count 00 dw Track$switch ;switch on track count 01 dw Odd$switch ;switch on Odd track 10 dw Even$switch ;switch on even track 11 Trk$tbl: db 34,35,40,80 ;track# to switch on 00,01,10,11 ;******************** read$msg: DB  ', Read',0 ; error message components write$msg: DB ', Write',0 operation$name: DW read$msg err$msg: DB ' retry (Y/N) ? ',0 ;******************** err$table: DW b7$msg ; table of pointers to error message strings first DW b6$msg ; entry is for bit 7 of 1797 status byte DW b5$msg DW b4$msg DW b3$msg DW b2$msg DW b1$msg DW b0$msg b7$msg: DB ' RDY,',0 b6$msg: DB ' WP,',0 b5$msg: DB ' FLT,',0 b4$msg: DB ' RNF,',0 b3$msg: DB ' CRC,',0 b2$msg: DB ' LD,',0 b1$msg: DB ' DREQ,',0 b0$msg: DB ' BSY,',0 end count 01 dw Odd$switch ;switch on Odd track 10 dw Even$switch ;switch on even track 11 Trk$tbl: db 34,35,40,80 ;track# to switch on 00,01,10,11 ;******************** read$msg: DB  title 'ADAPTEC hard disk controller & Seagate 412 drive' ; ***************************************************** ; * * ; * NOTE: * ; * * ; * DO NOT MODIFY ANY CODE IN THIS MODULE * ; * * ; * PMC CANNOT SUPPORT ANY MODIFICATIONS * ; * * ; ***************************************************** ; 'DISKIOH' ; ' Copyright (C), 1983 Personal Micro Computers, Inc.' ; ' 475 Ellis St. Mountain View, CA 94304' ; ' version 3.0 07 FEB. 1984 ' ;10/01/83 created ;02/07/84 no changes ;??/??/?? maclib z80 maclib ports maclib pmcequ public f$Hread, f$Hwrite, f$Hlogin, f$Hinit, ID extrn @rdrv, @adrv, @dma, @dbnk, @trk, @sect, @ermde, @cbnk, @type extrn RWdon dseg ;******************** ; Initialization entry point. called for first time initialization. ; ;******************** f$Hinit: f$Hlogin: ret ;no initialization or login required ;******************** ; 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 DPH IN ; they transfer the appropriate data, perform retries if necessary, ; then return an error code IN ;******************** f$Hread: lxi h,RDcmd jr f$rw$common f$Hwrite: lxi h,WRcmd f$rw$common: shld cmdptr inx  h lda @rdrv ;get drive code ani 0000$0111b ;get ID bits ; jrz ID0 ;if 0 then =ID 0 mov b,a ;convert binary number to ID bit inr b ;0=ID0=set bit 0 xra a stc nxt$ID: ralr a ;RL A djnz nxt$ID ID0: sta ID lda @rdrv ;get drive code ani 0011$0000b ;mask out ID bits res 5,m ora m ;set new drive mov m,a ;save new drive select ;Algorithm to calc Phy SPT from any DPB!! lxi h,12 ;offset to DPB dad d mov e,m ;get DPB from DPH inx h mov d,m xchg mov e,m ;get logical SPT from DPB inx h mov d,m dcx h push d ;save SPT count lxi d,15 ;offset to PSH (shift factor) dad d pop d ;restore SPT count mov a,m ;get PSH from DPB ora a jrz noshift ;if 0 shift factor then skip mov b,a shftlp: ;b=shift factor, de=Log SPT srlr d ;16 bit shift (MSB) rarr e ; (LSB) djnz shftlp noshift: lxi h,0 ;calculate virtual sector# lbcd @trk calc$lp: mov a,b ora c jrz no$calc dad d ;DE=SPT from dpb dcx bc jr calc$lp no$calc: lded @sect ;add in sector count dad d xchg ;DE=logical sector lhld cmdptr inx h ;->Msb (cannot have) inx h  ;->mSB mov m,d ;save inx h ;->LSB mov m,e ;save driver: ;H=ptr->cmd$ call wakeup lhld cmdptr call send call waitrq bit 4,a jrnz getsta ani HDio lxiy Hwrite jrz do$it lxiy Hread do$it: call execute getsta: call status jrc driver rz call wakeup lxi h,sense call send call waitrq lxi h,ercode call Hread call status mvi a,-1 sta endsta ret wakeup: in HAstat ani HDbusy jrnz wakeup lda ID out HAdata out HAack mvi a,HDselect out HActrl ckbusy: in HAstat ani HDbusy jrz ckbusy  mvi a,00 ;release SEL line once BUSY is active out HActrl ret send: call waitrq bit 4,a rz ani HDio rnz mov a,m out HAdata out HAack inx h jr send cseg ;************************ execute: ;must reside in cseg lhld @dma mvi c,HAdata lda @dbnk ;set DMA bank ora a jrz exec$1 dcr A ori 80H ;set hi bit if not bank 0 exec$1: out p$bankselect pciy Hread: in HAstat rlc jnc Hwrite ani HDcd shl 1 jnz RWdon ini out HAack jr Hread Hwrite: in HAstat rlc jnc Hwrite ani HDcd shl 1 jnz RWdon outi out HAack jr Hwrite ;************************** dseg status: call waitrq in HAdata ;read status byte out HAack sta endsta call waitrq in HAdata ;read message byte out HAack lda endsta ani HDbsybit jrz notbsy stc ret notbsy: lda endsta ana a ret waitrq: in HAstat bit 7,a jrz waitrq ret ID: db 0 cmdptr: dw 00 endsta: db 0 ercode: db 0,0,0,0 sense: db 003h,000h,000h,000h,000h,000h rdcmd: db 008h,000h,000h,000h,001h,000h wrcmd: db 00Ah,000h,000h,000h,001h,000h ; | | | | |____reserved ; | | | |_________number of blocks ; | | |______________block adr LSB ; | |___________________ mSB   ; |________________________ 4->0 = MSB bits 7->5=LUN end  ;read status byte out HAack sta endsta call waitrq in HAdata ;read message byte out HAack lda endsta ani HDbsybit jrz notbsy stc ret notbsy: lda endsta ana a ret waitrq: in HAstat bit 7,a jrz waitrq ret ID: db 0 cmdptr: dw 00 endsta: db 0 ercode: db 0,0,0,0 sense: db 003h,000h,000h,000h,000h,000h rdcmd: db 008h,000h,000h,000h,001h,000h wrcmd: db 00Ah,000h,000h,000h,001h,000h ; | | | | |____reserved ; | | | |_________number of blocks ; | | |______________block adr LSB ; | |___________________ mSB ~FORMATHD Copyright (C), 1983 Personal Micro Computers, Inc. 475 Ellis St. Mountain View, CA 94304 version 3.0 07 FEB. 19841r>2!2&: ˧˟˗ˇ2 ! "$!+""!~GG#~A0G_S #~A0G˯2 2 2 25 2 MGQG=!O6(6#! ˮ! ˮ! ˮ! ˮ! ˮ! ˮ! ˮ#! ! ! ! ! ! ! ! ͧ>͕_Y!< A!ͧ! ͪ:)4!ͧ! ͪ:)9! ͪ:)>! V#^S"! r#s! r#s!ͧ! ͪ:!( :)*:):&: ˇ2 >2![!&4y^!ͧ! ͪ:)%:&! ͮ! ͧ:&! A!, ! !!;  !c ! ! ͧ!Jͧ6!ͧ>͕!,V#^! r#s*"R! r#s!,V#^! r#s! ͪ! [$S$! 44444444+4"'*'͋@9Qiڱ! ͋!*9i>2):>@>͋7@7~#͋Nw#;͋f~#S͋2)͋:)ʆ7Ê:)ʌr !s~#~ ŷG>('0w#>!a ͧ>EFDD2202F2_2m2wz2 222H2a2o2yx22y22222!2(2?2W2! ͧ>͕!< A -PMC 101- Hard Disk Format Utility -Ver3.0-SU This utility is used to prepare a new Hard Drive to accept information or to re-prepare an old Hard Drive that may have a blown format. The drive letters M: through P: are assigned to Hard Drives. M: is the first Hard Drive and N: is an optional second Hard Drive. Formatting a Hard Drive will erase all information currently stored on that drive and then automatically Verify the drive integrity. If a bad block is found while verifying, it is marked and verifying continues. Once the whole drive is verified it is re-formatted, locking out all of the bad blocks found. If more than 6 bad blocks are found on the drive, the BIOS must be modified and re-assembled to compensate for the locked out blocks. See your Hard Disk user's guide. $ Home$ Setting Mode$ Seeking 0$ Formatting...$ Verifying...$ Enter Drive to Format (M-N): $ ERROR: Cannot Verify on Second Pass. Possible Bad drive.$ ERROR: Drive letter is out of Range.$ ERROR: Mode Command Error.$ ERROR: Format Command Error.$ ERROR: Capacity Command Error.$ ERROR: Seek Command Error.$ ?? Bad Blocks were found on drive x: .$ Drive x: is now ready to use.$ Drive x: has too many bad blocks, if you want to use it you will have to modify the the DRVTBL.ASM file and re-assemble your BIOS. Refer to the MicroMate Hard Drive Manual.$ Any information contained on drive x: WILL BE ERASED. Do you wish to proceed? (Y/N) $ Hard Disk Formatting Aborted. $ Using 8 inch/SASI interface. $ Press to continue or control C <^C> to abort$% /+22- ; | | |______________block adr LSB ; | |___________________ mSB  |PARKHD Copyright (C), 1983 Personal Micro Computers, Inc. 475 Ellis St. Mountain View, CA 94304 version 3.0 07 FEB. 198412?B!~+G#~A0+_S O#~A0+˯232H2qM+Q+2?=!2O6(6!ˮ!ˮ !!:? !g;>-_Y!%!;!B:6"!?!;!;ͬ!;>-î"4͔*4ʹ#l@ilIʏ͔!ʹ#!7>26•:2>@ʧ>#@~#õ#w##~##26#:67":6$ !~ >!;>EFDD222222z222222x22y2V2]2222222%!;-!% -PMC 101- Hard Disk Head Parking Utility-Ver3.0- This utility permits you to move the Hard Drive Heads to an inner landing Zone. The heads should be parked on this Landing Zone before powering down the Hard Disk Drive. If the Heads are not parked in the Landing Zone prior to powering down, data and/or directory files may be damaged. If you have two Hard Drives on line then you need to run this utility again to park the heads on the other drive. $ ***** CAN NOT PARK HEADS *****$ Parking Heads....$ Aborting park command$ Enter Drive to Park (M-N): $ ERROR: Drive letter is out of Range.$ Drive x: is now ready to power down.$ DRIVE x: WILL BE PARKED FOR POWER DOWN. Do you wish to proceed? (Y/N) $ Using 8 inch/SASI interface. $ Press to continue or control C <^C> to abort$e. $ Press to continue or control C <^C> to abort$% /+22- ; | | |______________block adr LSB ; | |___________________ mSB        !!""##$$%%&&''