TITLE 'CP/M BASIC INPUT/OUTPUT ROUTINES' ; CP/M BASIC INPUT/OUTPUT OPERATING SYSTEM (BIOS) ; TARBELL ELECTRONICS ; 2.1 VERSION OF 1-9-80 ; CHANGE SIGN-ON DATE FOR CP/M 2.1 ; ; UPDATED BY: ; ROBERT M. WHITE ; H & W COMPUTER SYSTEMS, INC. ; 8530 STONEHAVEN ; BOISE, ID 83704 ; ; ; THIS MODULE CONTAINS ALL THE INPUT/OUTPUT ; ROUTINES FOR THE CP/M SYSTEM, INCLUDING ; THE DISK ROUTINES. It has been designed ; to provide a full implementation for a ; Tarbell controller and console configura- ; tion. The disk drivers fully support ; various sector sizes and densities as ; documented later. The I/O drivers fully ; support the IOBYTE as defined in the ; CP/M Alteration Manual. Note this is an ; oversized BIOS and requires that the CCP ; be defined as a file on the default drive. ; Thus only the BDOS and BIOS are on the ; system tracks allowing a BIOS of 2.75k ; when both tracks are single density. ; Currently, a total of 4k is being allocated ; to the BIOS. Therefore, the max CP/M ; memory size is 61k. To calculate this, ; do as follows: ; Max memory size+1 (64k) =10000H ; 10000H-1000H = F000H (Bios Base) ; F000H-1600H = DA00H (CP/M Base) ; DA00H-3400H = A600H (CBASE) ; A600H/400H = 41 ; 41+20 = 61 (Max CP/M Size) ; ; To SYSGEN, do the following: ; 1. Assemble this BIOS using MAC and ; creating the file, 21BIOS.HEX. ; 2. Assemble the special Boot creating ; the file, 21BOOT.HEX. ; 3. Create a CCP file on the ; new default disk as follows: ; DDT CPMxx.COM ; -M980,1180,100 ; -^C ; SAVE 8 CCP.COM ; 4. Put BDOS, BOOT & BIOS on the ; new default disk as follows: ; DDT CPMxx.COM ; -M1180,1F80,980 ; -I21BOOT.HEX ; -R900 ; -I21BIOS.HEX ; -H1780,nnnn ; xxxx yyyy (Returned by DDT) ; -Ryyyy ; -^C ; SYSGEN ; (Answer as normal). ; ; Note -- A handy way of debugging this BIOS is ; to have an operating CP/M which is 16k larger. ; Boot this bios. To capture data areas, simply ; re-boot the other and look at them with DDT. ; This technique was used extensively to get this ; BIOS operational. ; ; ; THIS SECTION DEFINES THE I/O PORTS AND ; STATUS BITS. BY SETTING THE PROPER VALUES ; FOR THE EQU STATEMENTS, THE I/O MAY BE ; AUTOMATICALLY RECONFIGURED TO FIT MOST ; SITUATIONS. THE TRUE AND FALSE ONES ; CONTROL CONDITIONAL ASSEMBLIES OF DIFFERENT ; SECTIONS OF I/O ROUTINES TO FIT DIFFERENT ; INTERFACE REQUIREMENTS. MACLIB SPCLMAC TRUE EQU 0FFFFH ;DEFINE VALUE OF TRUE. FALSE EQU NOT TRUE ;DEFINE VALUE OF FALSE. BC EQU B ;DOUBLE REGISTER EQUATES DE EQU D HL EQU H ;*************************************************** ;*** THIS BEGINS THE AREA WHICH REQUIRES CHANGES *** ;*** FOR DIFFERENT CONSOLE I/O SYSTEMS *** ;*************************************************** MSIZE EQU 61 ;MEMORY SIZE IN KBYTES. INTRP EQU FALSE ;TRUE IF INTERRUPTS ALLOWED. DFTDSK EQU 0 ;DEFAULT DISK ON BOOT (0-3) DFTUSR EQU 0 ;DEFAULT USER ON BOOT (0-15) OLDTARB EQU FALSE ;TRUE IF OLD TARBELL CONTROLLER (1771) TARBELL EQU TRUE ;TRUE IF NEW TARBELL CONTROLLER (1791) DEBUG EQU FALSE ;TRUE FOR SPECIAL DEBUGGING MESSAGES SPOOL EQU FALSE ;TRUE IF USING KLH SPOOLER. NDISK EQU 3 ;DEFINES THE NUMBER DRIVES IN SYSTEM. CSTAT EQU 16 ;CONSOLE STATUS PORT. CCOM EQU 16 ;CONSOLE COMMAND PORT. CDATA EQU 17 ;CONSOLE DATA PORT. CONUL EQU FALSE ;CONSOLE NULLS? CNULL EQU 0 ;CONSOLE NULL COUNT. LSTAT EQU 18 ;LIST STATUS PORT. LCOM EQU 18 ;LIST COMMAND PORT. LDATA EQU 19 ;LIST DATA PORT. LSTNUL EQU FALSE ;LIST DEVICE NULLS? LNULL EQU 0 ;LIST NULL COUNT. LSTPAG EQU FALSE ;LIST DEVICE PAGING? LINCNT EQU 66 ;LINES PER PAGE. STPRAT EQU 2 ;RATE 1=6MS, 2=10MS, 3=20MS. DUAL EQU FALSE ;TRUE IF DUAL DRIVE. PERSCI EQU FALSE ;TRUE IF FAST SEEK (PERSCI). ;******************************************************* ;*** THIS IS THE END OF THE AREA WHICH NORMALLY NEED *** ;*** BE CHANGED FOR MOST CONSOLE I/O SYSTEMS *** ;******************************************************* DISK EQU 0F8H ;DISK BASE ADDRESS. DCOM EQU DISK ;DISK COMMAND PORT. DSTAT EQU DISK ;DISK STATUS PORT. TRACK EQU DISK+1 ;DISK TRACK PORT. SECTP EQU DISK+2 ;DISK SECTOR PORT. DDATA EQU DISK+3 ;DISK DATA PORT. WAIT EQU DISK+4 ;DISK WAIT PORT. DCONT EQU DISK+4 ;DISK CONTROL PORT. IF TARBELL DMACHK EQU DISK+5 ;DMA CHECK PORT. ENDIF RTCNT EQU 10 ;RETRY COUNT. CKBR EQU 00000001B ;KEYBOARD READY BIT. CPTR EQU 00000010B ;PRINT READY BIT. LKBR EQU 00000001B ;LISTER READY BIT. LPTR EQU 00000010B ;LISTER READY BIT. IOBYTE EQU 3 ;ADDRESS OF I/O BYTE. CBASE EQU (MSIZE-20)*1024 ;BIAS FOR LARGER THAN 20K. CPMB EQU CBASE+3400H ;START OF CPM 2.0 BDOS EQU CPMB+806H ;START OF BDOS 2.0. BIOS EQU CPMB+1600H ;START OF CBIOS IO. CDISK EQU 4 ;LOCATION 4 IS CURRENT DISK. NSECTS EQU 44 ;NUMBER OF SECTORS IN IT. ORG BIOS ;START OF CBIOS STRUCTURE. ; ; I/O JUMP VECTOR ; THIS IS WHERE CPM CALLS WHENEVER IT NEEDS ; TO DO ANY INPUT/OUTPUT OPERATION. ; USER PROGRAMS MAY USE THESE ENTRY POINTS ; ALSO, BUT NOTE THAT THE LOCATION OF THIS ; VECTOR CHANGES WITH THE MEMORY SIZE. ; JMP BOOT ;FROM COLD START LOADER. WBOOTE: JMP WBOOT ;FROM WARM BOOT. JMP CONST ;CHECK CONSOLE KB STATUS. JMP CONIN ;READ CONSOLE CHARACTER. JMP CONOUT ;WRITE CONSOLE CHARACTER. JMP LSTOUT ;WRITE LISTING CHAR. JMP PUNOUT ;WRITE PUNCH CHAR. JMP RDRIN ;READ READER CHAR. JMP HOME ;MOVE DISK TO TRACK ZERO. JMP SELDSK ;SELECT DISK DRIVE. JMP SETTRK ;SEEK TO TRACK IN REG A. JMP SETSEC ;SET SECTOR NUMBER. JMP SETDMA ;SET DISK STARTING ADR. JMP READ ;READ SELECTED SECTOR. JMP WRITE ;WRITE SELECTED SECTOR. JMP LSTST ;LIST STATUS CHECK. JMP SECTRAN ;SECTOR TRANSLATE ROUTINE. ; THESE ENTRY POINTS ADDED BY TARBELL ELECTRONICS. IF SPOOL ;IF USING KLH SPOOLER. DB 0FFH ;FLAG FOR SPOOLER. DW LTBSY ;LISTER STATUS LOCATION DW LTBSY ;FOR SPOOLER - - DW LTBSY ;I DON'T KNOW WHY IT'S DW LTBSY ;HERE 4 TIMES EITHER. ENDIF ; SPECIAL ENTRY POINTS FOR DIRECT DISK I/O JMP Pselct ;Select the drive in (C). JMP Phome ;Home current drive. JMP Pseek ;Seek track in (C). JMP Pread ;Read a sector in (C), dma in (HL) JMP Pwrite ;Write a sector in (C), dma in (HL) ;***************************************************** ;* * ;* Sector Deblocking Algorithms for CP/M 2.0 * ;* * ;***************************************************** ; ; This section of programming provides the disk ;drivers for the BIOS. They are designed to handle ;many combinations of disk formats and sector sizes. ;Currently, the definitions of these combinations are ;defined as in DFOCO distributed by S. J. Singer via ;the CP/M User's Group. For further information, see ;the documentation for that fine program. ; The actual routines are divided into two sec- ;tions. The first performs logical blocking and de- ;blocking of the host physical sectors. The second ;section contains the actual physical routines to per- ;form the I/O functions necessary for proper operation ;of the disk drives. Currently, these routines assume ;a Tarbell Single or Double Density Controller. The ;original logical routines were supplied by Digital ;Research as a part of CP/M 2.0. ; ;***************************************************** ;* * ;* CP/M to host disk constants * ;* * ;***************************************************** hstmax equ 1024 ;host max disk sector size ; ;***************************************************** ;* * ;* BDOS constants on entry to write * ;* * ;***************************************************** wrall equ 0 ;write to allocated wrdir equ 1 ;write to directory wrual equ 2 ;write to unallocated ;///////////////////////////////////////////////////// ;/ Logical Disk I/O Driver Routines / ;///////////////////////////////////////////////////// ;***************************************************** ;* * ;* The BDOS entry points given below show the * ;* code which is relevant to deblocking only. * ;* * ;***************************************************** ; ; DISKDEF macro, or hand coded tables go here ; ; * * * Disk Parameter Header * * * ; In general, each disk has an associated Disk ;Parameter Header which both contains information about ;the disk drive and provides a scratchpad area for ;certain BDOS operations. ; dphbase equ $ ;disk param block header DPE0 equ $ ;** Disk A ** dw 00000H,00000H ;XLT adr, Scratch dw 00000H,00000H ;Scratch, Scratch dw dirbuf,00000H ;Dir Buf adr, DPB adr dw CSV0,ALV0 ;CSV adr, ALV adr DPE1 equ $ ;** Disk B ** dw 00000H,00000H ;XLT adr, Scratch dw 00000H,00000H ;Scratch, Scratch dw dirbuf,00000H ;Dir Buf adr, DPB adr dw CSV1,ALV1 ;CSV adr, ALV adr DPE2 equ $ ;** Disk C ** dw 00000H,00000H ;XLT adr, Scratch dw 00000H,00000H ;Scratch, Scratch dw dirbuf,00000H ;Dir Buf adr, DPB adr dw CSV2,ALV2 ;CSV adr, ALV adr DPE3 equ $ ;** Disk D ** dw 00000H,00000H ;XLT adr, Scratch dw 00000H,00000H ;Scratch, Scratch dw dirbuf,00000H ;Dir Buf adr, DPB adr dw CSV3,ALV3 ;CSV adr, ALV adr ; ; * * * Disk Parameter Block * * * ; In general, each DPH, Disk Parameter Header, ;points to a particular DPB, Disk Parameter Block. ;The DPB contains information directly relating to ;the organition of data on the disk and its hardware ;characteristics. ; ; * * DPB Field Displacements * * dpbspt equ 0 ;host CP/M sectors/track dpbbsh equ 2 ;block shift factor dpbblm equ 3 ;block shift mask dpbexm equ 4 ;extent mask dpbdsm equ 5 ;max block rcd # dpbdrm equ 7 ;max dir mask dpbal0 equ 9 ;dir allocation vector dpbal1 equ 10 ;dir allocation vector dpbcks equ 11 ;dir check value dpboff equ 13 ;rsvd tracks offset dpbdfc equ 15 ;disk format code dpbssc equ 16 ;host sector size dpbhbm equ 18 ;host sector mask dpbhbs equ 19 ;host sector shift value dpbxlt equ 20 ;xlt ptr dpblen equ 22 ;DPB length ; dpbbase equ $ ;Base of Disk Parameter Blocks dpbs00 equ $ ;** Single Density, 128 byte Sectors ** DPB 020H,128,26,1024,243,64,64,2,xlts00 dpbs01 equ $ ;** Single Density, 256 byte Sectors ** DPB 021H,256,16,2048,150,64,64,2,0 dpbs02 equ $ ;** Single Density, 512 byte Sectors ** DPB 022H,512,8,2048,150,64,64,2,0 dpbs03 equ $ ;** Single Density, 1024 byte Sectors ** DPB 023H,1024,4,2048,150,64,64,2,0 dpbd00 equ $ ;** Double Density, 128 byte Sectors ** DPB 010H,128,51,2048,239,128,128,2,xltd00 dpbd01 equ $ ;** Double Density, 256 byte Sectors ** DPB 011H,256,26,2048,243,128,128,2,0 dpbd02 equ $ ;** Double Density, 512 byte Sectors ** DPB 012H,512,16,2048,300,128,128,2,0 dpbd03 equ $ ;** Double Density, 1024 byte Sectors ** DPB 013H,1024,8,2048,300,128,128,2,0 dpbnum equ ($-dpbbase)/dpblen ;# of entries in table ; * * * Sector Translation Table * * * ; This section contains the STT, Sector Translation ;Table, for particular disk configurations (I.E. DPB's). ;The table gives a logical to physical mapping of sector ;numbers. Thereby, allowing different mappings for per- ;formance betterment. Note that all entries must be rela- ;tive to zero, not one. xltbase equ $ ;Base of Sector Translation Tables xlts00 equ $ ;** Single density, 128 byte sectors, ; ; 26 Sec/Trk, Skew 6 ** db 0,6,12,18,24 db 4,10,16,22,2 db 8,14,20,1,7 db 13,19,25,5,11 db 17,23,3,9,15,21 xltd00 equ $ ;** Double density, 128 byte sectors, ; ; 51 Sec/Trk, Skew 18 ** db 0,17,34,9,26,43,1,18,35,10,27 db 44,2,19,36,11,28,45,3,20,37,12 db 29,46,4,21,38,13,30,47,5,22,39 db 14,31,48,6,23,40,15,32,49,7,24 db 41,16,33,50,8,25,42 ; ; ;***************************************************** ;* * ;* BOOT - Cold Boot Routine. * ;* Executed whenever Reset is pressed. * ;* * ;***************************************************** BOOT: ; Do initialization. lxi sp,080H ;set stack ptr. if INTRP ei ;enable interrupts. endif ; Initialize Mits 2SIO. mvi a,3 ;Issue reset. out ccom out lcom mvi a,015H ;Set up Ports. out ccom out lcom in cdata ;clear console port. ; Save last six bytes of CCP. lxi h,BDOS-6 lxi d,ccpsav mvi c,6 mov a,m stax d inx h inx d dcr c jnz $-5 ; Zero defined Scratch area. lxi b,ENDZ-STARTZ lxi h,STARTZ mvi m,0 inx h dcx b mov a,b ora c jnz $-6 ; Set Low memory areas excluding jumps. mvi a,095H ;IOBYTE := CON=CRT, LST=LPT, PUN=PTP, sta IOBYTE ; RDR=PTR mvi a,0 ;Default disk = A: sta CDISK ; Issue opening message. lxi h,smsg call Pmsg ; Finish by warm booting. jmp WBOOT ;***************************************************** ;* * ;* WBOOT - Warm Boot Routine. * ;* * ;***************************************************** WBOOT: ; Do initialization. lxi sp,080H ;set stack ptr. if INTRP di ;disable interrupts. endif ; Set up jumps for CP/M in low memory. mvi a,0C3H ;put (JMP) for WBOOT. sta 0 lxi h,WBOOTE shld 1 sta 5 ;put (JMP) for BDOS. lxi h,BDOS shld 6 ; Issue loading CCP message. if DEBUG lxi h,lodccp call pmsg endif ; Zero Disk table. mvi c,4*2 lxi h,dsktbl mvi m,0 inx h dcr c jnz $-4 ; Reset Deblock fields. xra a sta hstact ;host buffer inactive sta unacnt ;clear unalloc count. ; Select and login default disk drive. mvi c,DFTDSK ;do it. call SELDSK ; Set default user to zero for now. mvi e,0 mvi c,020H call BDOS ; Reset disk system. mvi c,00DH call BDOS ; Select default drive. mvi e,DFTDSK mvi c,00EH call BDOS ; Zero CCP's FCB. lxi h,ccpfcb+12 mvi c,21 mvi m,0 inx h dcr c jnz $-4 ; Open CCP's FCB. lxi d,ccpfcb mvi c,00FH call BDOS inr a ;Error? jc Bterr ;...yes. ; Read in the CCP. mvi c,16 ;set # of sectors in CCP. lxi d,128 ;set sector size. lxi h,CPMB ;set CCP base address. call Ccpred ;Read a sector. dad d ;bump ptr. dcr c ;Decr count. jnz $-5 ;loop till done. ; Restore CCP's last six bytes. lxi h,ccpsav lxi d,BDOS-6 mvi c,6 mov a,m stax d inx h inx d dcr c jnz $-5 ; Issue CCP loaded Message. if DEBUG lxi h,ccplod call Pmsg endif ; Do misc initialization. lxi h,080H ;set default buffer in dma. shld dmaadr if INTRP ei ;enable interrupts. endif ; Set default drive and user and go to CCP. lda CDISK ;get default drive. mov c,a ;save it. mvi a,DFTUSR ;get Default user (0-15). ral ;Put it in high hex digit. ral ral ral add c ;add in default drive. mov c,a ;set for CCP. jmp CPMB ;go to CCP. ccpfcb: db 0,'CCP ','COM',0,0,0,0 db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 db 0 ; * * Read a sector of CCP. * * Ccpred: ; Do initialization. push b ;save regs. push d push h ; Set DMA for read. xchg mvi c,01AH call BDOS ; Issue the read. lxi d,ccpfcb mvi c,014H call BDOS ora a ;Error? jnz Bterr ;...yes. ; Return to caller. pop h ;restore regs. pop d pop b ret ; * * Handle boot errors * * Bterr: ; Tell operator. lxi h,btmsg ;Issue Boot error msg. call Pmsg call CONIN ;Wait. jmp WBOOT ;Try warm boot again. ;***************************************************** ;* * ;* SELDSK - Select a Disk. * ;* * ;***************************************************** SELDSK: ; Validate the disk #. lxi h,0 ;set for error. mov a,c ;get the disk #. cpi NDISK ;Undefined drive? rnc ;...yes, return w/error. mov a,c ;selected disk number sta sekdsk ;seek disk number ; Get ptr to disk's DPH. mov l,a ;disk number to HL mvi h,0 rept 4 ;multiply by 16 dad h endm lxi d,dphbase ;base of parm block dad d ;hl=.dph(curdsk) shld sekdph ;save it. ; Log the disk if not already logged. mov a,c ;point to disk table entry. call Dskadr mov a,m ;get flag byte. ora a ;Already logged? jm $+6 ;...yes. call Logdsk ;...no, log it in. ; now get address of dpb. lhld sekdph ;hl = .dph(curdsk) lxi d,10 ;hl = .dphdpb(curdsk) dad d mov e,m ;hl = .dpb(curdsk) inx h mov d,m xchg shld sekdpb ;save it. ; return to caller. lhld sekdph ret ;***************************************************** ;* * ;* Logdsk - Login disk in (C). * ;* * ;***************************************************** Logdsk: ; Get the format code from sector 1 track 0. call Pselct ;Physically select the drive. call Phome ;Home the head. mvi c,0 ;Seek track 0 setting density. call Pseek mvi c,1 ;Read in first Sector. lxi h,dirbuf call Pread lda dirbuf+07FH ;Get the format code. sta dskdfc ;save it. ; Log the disk's DPH. lhld sekdph call Logdph ; Log it into the disk table. lda sekdsk ;point to disk table entry. call Dskadr lda dskdfc ;get the density code. ani 010H rrc ;put it in low order byte. rrc rrc rrc ori 080H ;add in logged bit. mov m,a ;put it in table flag byte. ; return to caller. ret ;***************************************************** ;* * ;* Logdph - Login disk parameter header. * ;* * ;***************************************************** Logdph: ; Get the right DPB. xchg ;de = .dph lda dskdfc ;get format code for search. call Srcdpb ;Search the DPB table. ; Put the XLT address in the DPH. push h ;save DPB ptr. rxdld b,<>,dpbxlt ;Get XLT address. xchg ;put it in DPH. mov m,c inx h mov m,b ; Put DPB address in DPH. lxi d,9 ;point to dphdpb. dad d pop d ;get DPB address. mov m,e ;put it in DPH. inx h mov m,d ; return to caller. ret ;***************************************************** ;* * ;* Srcdpb - Search DPB table on format code. * ;* * ;***************************************************** Srcdpb: ; Do initialization. push b ;save regs. push d mov b,a ;save format code. mvi c,dpbnum ;set for # of entries. lxi h,dpbbase ;point to DPB table. lxi d,dpblen ;get entry length. ; Scan the table taking default if not ; found. Srcdpl: push h ;save current entry ptr. rxld a,<>,dpbdfc ;get entry's format code. pop h cmp b ;Did we find it? jz Srcdpf ;...yes, return w/it. dad d ;bump ptr to next entry. dcr c ;loop till no more entries. jnz Srcdpl lxi h,dpbs00 ;Default to SD/SS 128 byte. ; Return to caller w/entry ptr. Srcdpf: pop d ;restore regs. pop b ret ;***************************************************** ;* * ;* HOME - Home a particular disk. * ;* * ;***************************************************** HOME: ;set track given by registers BC lxi h,0 shld sektrk ;track to seek ret ;***************************************************** ;* * ;* SETTRK - Set appropriate track. * ;* * ;***************************************************** SETTRK: ;set track given by registers BC mov h,b mov l,c shld sektrk ;track to seek ret ;***************************************************** ;* * ;* SETSEC - Set appropriate sector. * ;* * ;***************************************************** SETSEC: ;set sector given by register c mov a,c sta seksec ;sector to seek ret ;***************************************************** ;* * ;* SETDMA - Set Data Memory Address. * ;* * ;***************************************************** SETDMA: ;set dma address given by BC mov h,b mov l,c shld dmaadr ret ;***************************************************** ;* * ;* SECTRAN - Do Sector Translation. * ;* * ;***************************************************** SECTRAN: ;translate sector number BC mvi h,0 ;hl = physical sector mov l,c mov a,d ;if not using xlat tbl then ora e ; return. rz xchg ;hl = .xlt dad b ;hl = .xlt(sector) mov l,m ;hl = xlt'd sector mvi h,0 ret ;***************************************************** ;* * ;* The READ entry point takes the place of * ;* the previous BIOS defintion for READ. * ;* * ;***************************************************** READ: ;read the selected CP/M sector xra a ;accum = 00 sta unacnt ;unacnt= 00 mvi a,1 sta readop ;read operation sta rsflag ;must read data mvi a,wrual sta wrtype ;treat as unalloc jmp rwoper ;to perform the read ;***************************************************** ;* * ;* The WRITE entry point takes the place of * ;* the previous BIOS defintion for WRITE. * ;* * ;***************************************************** WRITE: ;write the selected CP/M sector xra a ;0 to accumulator sta readop ;not a read operation mov a,c ;write type in c sta wrtype cpi wrual ;write unallocated? jnz chkuna ;check for unalloc ; ; write to unallocated, set parameters rxld a,sekdpb,dpbblm ;a = dpbblm(sekdsk) + 1 inr a sta unacnt lda sekdsk ;disk to seek sta unadsk ;unadsk = sekdsk lhld sektrk shld unatrk ;unatrk = sectrk lda seksec sta unasec ;unasec = seksec ; chkuna: ;check for write to unallocated sector lda unacnt ;any unalloc remain? ora a jz alloc ;skip if not ; ; more unallocated records remain dcr a ;unacnt = unacnt-1 sta unacnt lda sekdsk ;same disk? lxi h,unadsk cmp m ;sekdsk = unadsk? jnz alloc ;skip if not ; ; disks are the same lxi h,unatrk call sektrkcmp ;sektrk = unatrk? jnz alloc ;skip if not ; ; tracks are the same lda seksec ;same sector? lxi h,unasec cmp m ;seksec = unasec? jnz alloc ;skip if not ; ; match, move to next sector for future ref inr m ;unasec = unasec+1 mov a,m ;end of track? push h rxad sekdpb,dpbspt cmp m pop h jc noovf ;skip if no overflow ; ; overflow to next track mvi m,0 ;unasec = 0 lhld unatrk inx h shld unatrk ;unatrk = unatrk+1 ; noovf: ;match found, mark as unnecessary read xra a ;0 to accumulator sta rsflag ;rsflag = 0 jmp rwoper ;to perform the write ; alloc: ;not an unallocated record, requires pre-read xra a ;0 to accum sta unacnt ;unacnt = 0 inr a ;1 to accum sta rsflag ;rsflag = 1 ;***************************************************** ;* * ;* Common code for READ and WRITE follows * ;* * ;***************************************************** rwoper: ; convert sector to host sector # by ; dividing it by the number of sectors ; per host sector. xra a ;zero to accum sta erflag ;no errors (yet) lda seksec ;compute host sector rxld b,sekdpb,dpbhbs ;b = dpbhbs(sekdpb) dcr b ;b = 0? inr b jz rwope1 ;...yes, use as is. ora a ;carry = 0 rar ;shift right dcr b ;decr shift count. jnz $-3 ;go shift it again. rwope1: sta sekhst ;host sector to seek ; ; active host sector? lxi h,hstact ;host active flag mov a,m mvi m,1 ;always becomes 1 ora a ;was it already? jz filhst ;fill host if not ; ; host buffer active, same as seek buffer? lda sekdsk lxi h,hstdsk ;same disk? cmp m ;sekdsk = hstdsk? jnz nomatch ; ; same disk, same track? lxi h,hsttrk call sektrkcmp ;sektrk = hsttrk? jnz nomatch ; ; same disk, same track, same buffer? lda sekhst lxi h,hstsec ;sekhst = hstsec? cmp m jz match ;skip if match ; nomatch: ;proper disk, but not correct sector lda hstwrt ;host written? ora a cnz writehst ;clear host buff ; filhst: ;may have to fill the host buffer lda sekdsk sta hstdsk lhld sektrk shld hsttrk lda sekhst sta hstsec lhld sekdph shld hstdph lhld sekdpb shld hstdpb lda rsflag ;need to read? ora a cnz readhst ;yes, if 1 xra a ;0 to accum sta hstwrt ;no pending write ; match: ;copy data to or from buffer lda seksec ;mask buffer number rxad sekdpb,dpbhbm ;hl = .dpbhbm(sekdpb) ana m ;least signif bits mov l,a ;ready to shift mvi h,0 ;double count rept 7 ;shift left 7 dad h endm ; hl has relative host buffer address lxi d,hstbuf dad d ;hl = host address xchg ;now in DE lhld dmaadr ;get/put CP/M data mvi c,128 ;length of move lda readop ;which way? ora a jnz rwmove ;skip if read ; ; write operation, mark and switch direction mvi a,1 sta hstwrt ;hstwrt = 1 xchg ;source/dest swap ; rwmove: ;C initially 128, DE is source, HL is dest ldax d ;source character inx d mov m,a ;to dest inx h dcr c ;loop 128 times jnz rwmove ; ; data has been moved to/from host buffer lda wrtype ;write type cpi wrdir ;to directory? lda erflag ;in case of errors rnz ;no further processing ; ; clear host buffer for directory write ora a ;errors? rnz ;skip if so xra a ;0 to accum sta hstwrt ;buffer written call writehst lda erflag ret ;***************************************************** ;* * ;* Utility subroutine for 16-bit compare * ;* * ;***************************************************** sektrkcmp: ;HL = .unatrk or .hsttrk, compare with sektrk xchg lxi h,sektrk ldax d ;low byte compare cmp m ;same? rnz ;return if not ; low bytes equal, test high 1s inx d inx h ldax d cmp m ;sets flags ret ; ;***************************************************** ;* * ;* WRITEHST performs the physical write to * ;* the host disk, READHST reads the physical * ;* disk. * ;* * ;***************************************************** writehst: ;hstdsk = host disk #, hsttrk = host track #, ;hstsec = host sect #. write "hstsiz" bytes ;from hstbuf and return error flag in erflag. ;return erflag non-zero if error ; Select the drive. lxi h,hstdsk ;c = disk # mov c,m call Pselct ;Select it. ; Set the head on the proper track. lxi h,hsttrk ;c = track # mov c,m call Pseek ;do it. sta erflag ;save error code. rnz ;return if error. ; Write the sector. lxi h,hstsec ;c = sector # mov c,m inr c ;make it relative to one. lxi h,hstbuf ;hl = .buffer call Pwrite ;do it. sta erflag ;save error code. ret readhst: ;hstdsk = host disk #, hsttrk = host track #, ;hstsec = host sect #. read "hstsiz" bytes ;into hstbuf and return error flag in erflag. ; Select the drive. lda hstdsk ;c = disk # mov c,a call Pselct ;Select it. ; Set the head on the proper track. lxi h,hsttrk ;c = track # mov c,m call Pseek ;do it. sta erflag ;save error code. rnz ;return if error. ; Read the sector. lxi h,hstsec ;c = sector # mov c,m inr c ;make it relative to one. lxi h,hstbuf ;hl = .buffer call Pread ;do it. sta erflag ;save error code. ret ;///////////////////////////////////////////////////// ;/ / ;/ Physical Disk I/O Driver Routines / ;/ / ;///////////////////////////////////////////////////// ;***************************************************** ;* * ;* Pselct - Physical Device Select * ;* * ;***************************************************** Pselct: ; Trace activity. if DEBUG push h lxi h,trcact mvi m,1 pop h endif ; Save current disk's Track #. lda dskcur ;point to Disk table entry. call Dskadr inx h ;point to track save. in TRACK ;get the track #. mov m,a ;save it. ; Get the new track #. mov a,c ;get new disk #. sta dskcur ;make it the current one. call Dskadr ;point to disk table entry. inx h ;point to track save. mov a,m ;get track #. sta dsktrk ;save it. out TRACK ;put it in controller. ; Set the new disk's latch. mov a,c ;get the disk #. if OLDTARB cma ;invert it. add a ;Put bits 1&2 in 4&5. add a add a add a ori 2 ;make latch command. endif if TARBELL add a ;Put bits 1&2 in 4&5. add a add a add a endif sta dsklth ;save new latch. ; Return to caller. ret ;***************************************************** ;* * ;* Phome - Physical Device Home * ;* * ;***************************************************** Phome: ; Trace activity. if DEBUG push h lxi h,trcact mvi m,2 pop h endif ; Select the drive in single density. lda dsklth ;Get current latch. out DCONT ;Issue it to controller. ; Wait for device not to be busy. in DSTAT ;get disk status. rrc ;check busy bit. jc $-3 ;...loop till not busy. ; Issue Restore Command. mvi a,002H ;Restore cmd - no hdld, no verify out DCOM ;Issue it. in WAIT ;Wait for completion. ; Delay 200 msec. mvi a,200 call delay ; Check the status for track zero. in DSTAT ani 4 ;Track zero? jz Phome ;...no, try again. ; Reset track # in table. lda dskcur ;point to table entry. call Dskadr inx h ;point to track #. mvi m,0 ;reset it. lxi h,dsktrk ;reset current track #. mvi m,0 ; Return to caller. ret ;***************************************************** ;* * ;* Pseek - Physical Device Seek * ;* * ;***************************************************** Pseek: ; Trace activity. if DEBUG push h lxi h,trcact mvi m,3 pop h endif ; Select the drive and density. mov a,c ;get track #. sta dsktrk ;save it. sta dsktrs ;...again. ora a ;Track zero? jz Pseek1 ;...yes, force single density. lda dskcur ;point to disk table entry. call Dskadr mov a,m ;get flag byte. ani 1 ;Double density? jz $+5 ;...no. mvi a,8 ;...yes, set it. Pseek1: mov b,a ;save density. lda dsklth ;get current latch. ora b ;add in density. out DCONT ;put it to controller. ; If we've changed drives since last seek, ; force a seek to the same track to unload ; the head. Thus insuring that the head ; load bit is properly set for this drive. lhld dsklth ;get old and new latches. mov a,l ;Are they the same? cmp h lda dsklth ;reset them no matter what. sta dskolt jnz Pseek2-2 ;...no, insure seek to same track. ; Check to see if current track is desired one. in TRACK ;get current track. cmp c ;Are they the same? rz ;...yes, return. ; Issue the Seek command. mvi b,RTCNT ;set retry count. Pseek2: lda dsktrk ;get the desired track #. out DDATA ;tell controller. in DSTAT ;Wait till not busy. rrc jc $-3 mvi a,014H+STPRAT ;seek cmd w/verify. out DCOM in Wait ;Wait till complete. in DSTAT ;get disk status. if DEBUG sta trcerr endif ani 091H ;Check for error. rz ;...none, return. ; Handle errors. dcr b ;Decr retry count. jz Pseek3 ;...hard error. call Phome ;home the device. lda dsktrs ;restore original trk #. sta dsktrk jmp Pseek2 ;Try seeking again. Pseek3: call Recov ;Ask about recovery. lda dsktrs ;restore original trk #. sta dsktrk jmp Pseek2-2 ;Try it again. ;***************************************************** ;* * ;* Pread - Physical Sector read. * ;* * ;***************************************************** Pread: ; Trace activity. if DEBUG push h lxi h,trcact mvi m,4 pop h endif ; Save input parameters. shld dskdma ;dma address lxi h,dsksec ;sector # mov m,c if INTRP di ;disable interrupts. endif ; Set retry count and interrupt controller. Prdagn: mvi a,RTCNT ;Set retry count. Prdrty: sta dskerr mvi a,0D0H ;Issue soft interrupt. out DCOM xthl ;Do some delay. xthl ; Set the Sector. lda dsksec ;get it. out SECTP ; Point to buffer. lhld dskdma ; Issue Read command to controller. in DSTAT ;get head load status. ani 020H xri 020H ;invert it. rrc ;put it in proper bit. rrc rrc if OLDTARB ori 088H ;Read cmd w/o hdld endif if TARBELL ori 080H ;Read cmd w/o hdld endif out DCOM ;Issue it. ; Read the data. Prdlop: in WAIT ;Wait for INTRQ. ora a ;Is it there? jp Prddon ;...yes, we're done. in DDATA ;get a char. mov m,a ;put it in buffer. inx h ;bump ptr. jmp Prdlop ;go get another. ; Analyze read status. Prddon: in DSTAT ;get it. if DEBUG sta trcerr endif if INTRP ei ;enable interrupts. endif ani 09DH ;any errors? rz ;...no, return. call Erchk ;...yes, insure proper track. lda dskerr ;get retry count. dcr a ;Decr it. jnz Prdrty ;...Try reading it again. call Recov ;Give possible operater cancel. jmp Prdagn ;Try reading again. ;***************************************************** ;* * ;* Pwrite - Physical Sector Write. * ;* * ;***************************************************** Pwrite: ; Trace activity. if DEBUG push h lxi h,trcact mvi m,5 pop h endif ; Save input parameters. shld dskdma ;dma address lxi h,dsksec ;sector # mov m,c if INTRP di ;disable interrupts. endif ; Set retry count and interrupt controller. Pwragn: mvi a,RTCNT ;Set retry count. Pwrrty: sta dskerr mvi a,0D0H ;Issue soft interrupt. out DCOM xthl ;Do some delay. xthl ; Set the Sector. lda dsksec ;get it. out SECTP ; Point to buffer. lhld dskdma ; Issue Write command to controller. in DSTAT ;get head load status. ani 020H xri 020H ;invert it. rrc ;put it in proper bit. rrc rrc if OLDTARB ori 0A8H ;Write cmd w/o hdld endif if TARBELL ori 0A0H ;Write cmd w/o hdld endif out DCOM ;Issue it. ; Write the data. Pwrlop: in WAIT ;Wait for INTRQ. ora a ;Is it there? jp Pwrdon ;...yes, we're done. mov a,m ;get a char from the buffer. out DDATA ;put it to disk. inx h ;bump ptr. jmp Pwrlop ;go get another. ; Analyze read status. Pwrdon: mvi a,1 ;delay some. call Delay in DSTAT ;get it. if DEBUG sta trcerr endif if INTRP ei ;enable interrupts. endif ani 0FDH ;any errors? rz ;...no, return. call Erchk ;...yes, insure proper track. lda dskerr ;get retry count. dcr a ;Decr it. jnz Pwrrty ;...Try reading it again. call Recov ;Give possible operater cancel. jmp Pwragn ;Try reading again. ;***************************************************** ;* * ;* Erchk - Insure proper seek on read/write * ;* * ;***************************************************** Erchk: ; Return if not Rcd not found error. push psw ;save error flags. ani 010H ;Record not found? jnz Erchk1 ;...yes, read address and seek. pop psw ;...no, return. ora a ret ; Read the next address. Erchk1: mvi a,0C4H ;Read address w/15ms delay out DCOM in WAIT ;Wait for DRQ or INTRQ. in DDATA ;Read track address. push psw ;save it. ; Flush rest of address data. Erchk2: in Wait ;Wait for INTRQ. ora a ;Read done? jp Erchk3 ;...yes. in DDATA ;...no, flush rest. jmp Erchk2 ; Check on Read Status. Erchk3: in DSTAT ;Get read Status. ora a ;Sucessful? jz Erchk4 ;...yes. pop psw ;...no, clean up stack. call Phome ; home head jmp Erchk1 ; and try again. ; Put track # read in controller. Erchk4: pop psw ;restore track address. out TRACK ;put it in controller. ; Seek to proper track. lda dsktrk ;get the proper track #. mov c,a call Pseek ;do the seek. pop psw ;restore error flag. ret ;***************************************************** ;* * ;* Dskadr - Get disk table entry ptr. * ;* * ;***************************************************** Dskadr: push d ;save regs. mov l,a ;hl = disp to entry. mvi h,0 dad h lxi d,dsktbl ;get base adr. dad d ;add base to disp. pop d ret ;***************************************************** ;* * ;* Recov - Recover from read, seek and write * ;* errors. * ;* * ;***************************************************** Recov: lxi h,errmsg ;Issue error message call Pmsg ; to console. call conin ;get a response from operator. cpi 003H ;Control C? jz WBOOT ;...yes, abort. ret ;***************************************************** ;* * ;* Pmsg - Print message on console. * ;* * ;***************************************************** Pmsg: mov a,m ;get next char of msg. ora a ;if zero, eom. rz push b ;save bc. mov c,a ;print char on console. call CONOUT pop b ;restore bc. inx h ;bump msg ptr. jmp Pmsg ;loop till eom. ;***************************************************** ;* * ;* Delay - Delay (A) msec. * ;* * ;***************************************************** Delay: push d ;save regs. push h Delay1: lxi d,1 lxi h,65335 ;Constant for 1 msec @ 4mhz dad d jnc $-1 dcr a ;Decr msec count. jnz Delay1 ;...loop till done. pop h ;restore regs. pop d ret ;***************************************************** ;* * ;* BDOS Messages * ;* * ;***************************************************** btmsg: db '** Boot Error **',0 errmsg: db '** BDOS Error **',0 smsg: db 00DH,00AH,'Tarbell' if OLDTARB db '(1771) ' endif if TARBELL db '(1791) ' endif db MSIZE/10+'0',MSIZE mod 10 + '0' db 'K CP/M 2.1',0 if DEBUG lodccp: db 00DH,00AH,'***Loading CCP---',0 ccplod: db 00DH,00AH,'***CCP is loaded!',0 endif ;**************************************************************************** ;* L-O-G-I-C-A-L D-E-V-I-C-E D-R-I-V-E-R-S * ;* THE FOLLOWING SECTION CONTAINS THE LOGICAL DEVICE DRIVERS FOR * ;* EACH LOGICAL DEVICE IN THE SYSTEM. THESE DEVICES ARE DEFINED * ;* BY THE IOBYTE FUNCTION FOUND IN THE CP/M ALTERATION GUIDE. * ;**************************************************************************** ;*************************** CON - SYSTEM CONSOLE ************************** CONST: LDA IOBYTE ;GET IOBYTE. CALL IOCAL ;EXIT TO SELECTED ROUTINE. DW TTYST DW CRTST DW RDRST DW DUMST CONIN: LDA IOBYTE ;GET IOBYTE. CALL IOCAL ;EXIT TO SELECTED ROUTINE. DW TTYIN DW CRTIN DW RDRIN DW DUMIN CONOUT: LDA IOBYTE ;GET IOBYTE. CALL IOCAL ;EXIT TO SELECTED ROUTINE. DW TTYOUT DW CRTOUT DW PUNOUT DW DUMOUT ;*************************** LST - OUTPUT LIST DEVICE ********************** LSTST: LDA IOBYTE ;GET IOBYTE. RLC ;SHIFT BITS. RLC CALL IOCAL ;EXIT TO SELECTED ROUTINE. DW TTYST DW CRTST DW LPTST DW DUMST LSTOUT: LDA IOBYTE ;GET IOBYTE. RLC ;SHIFT BITS. RLC CALL IOCAL ;EXIT TO SELECTED ROUTINE. DW TTYOUT DW CRTOUT DW LPTOUT DW DUMOUT ;*************************** PUN - PAPER TAPE PUNCH ************************ PUNOUT: LDA IOBYTE ;GET IOBYTE. RRC ;SHIFT BITS. RRC RRC RRC CALL IOCAL ;EXIT TO SELECTED ROUTINE. DW TTYOUT DW PTPOUT DW DUMOUT DW DUMOUT ;*************************** RDR - PAPER TAPE READER *********************** RDRST: LDA IOBYTE ;GET IOBYTE. RRC ;SHIFT BITS. RRC CALL IOCAL ;EXIT TO SELECTED ROUTINE. DW TTYST DW PTRST DW DUMST DW DUMST RDRIN: LDA IOBYTE ;GET IOBYTE. RRC ;SHIFT BITS. RRC CALL IOCAL ;EXIT TO SELECTED ROUTINE. DW TTYIN DW PTRIN DW DUMIN DW DUMIN ;*************************** I/O DISPATCHER ******************************** IOCAL: RLC ;SHIFT BITS. ANI 006H ;LIMIT BITS. XTHL ;SAVE HL, GET TABLE ADDRESS. PUSH D ;SAVE DE. MOV E,A ;GET SELECTION VALUE. MVI D,0 DAD D ;GET TABLE ENTRY. MOV A,M INX H MOV H,M MOV L,A POP D ;RESTORE DE. XTHL ;RESTORE HL, SAVE RTN ADDRESS. RET ;EXIT TO ROUTINE. ;**************************************************************************** ;* P-H-Y-S-I-C-A-L D-E-V-I-C-E D-R-I-V-E-R-S * ;* THE FOLLOWING SECTION CONTAINS THE PHYSICAL DEVICE DRIVERS FOR * ;* EACH ACTUAL DEVICE IN THE SYSTEM. FOR EACH DEVICE, THERE MUST * ;* EXIST AT LEAST TWO OF THREE ROUTINES, A DEVICE STATUS ROUTINE * ;* AND A DEVICE INPUT OR OUTPUT ROUTINE. THE LOGICAL PORTION OF * ;* THE BIOS WILL ONLY CALL A STATUS, INPUT OR OUTPUT ROUTINE. * ;**************************************************************************** ;*************************** DUM - DUMMY DEVICE **************************** DUMST: MVI A,0FFH ;INDICATE READY. RET DUMIN: MVI A,01AH ;INDICATE . RET DUMOUT: RET ;*************************** CRT - HIGH SPEED CONSOLE ********************** CRTST: IN CSTAT ;GET CONSOLE STATUS. ANI CKBR ;IF NOT READY, MVI A,0 RZ ; RETURN. CMA ;RETURN 0FFH. RET CRTIN: IN CSTAT ;GET CONSOLE STATUS. ANI CKBR ;IF NOT READY, JZ CRTIN ; LOOP. IN CDATA ;READ THE CHAR. ANI 07FH ;MAKE MOST SIG. BIT=0. RET CRTOUT: IN CSTAT ;GET CONSOLE STATUS. ANI CPTR ;IF NOT READY, JZ CRTOUT ; LOOP. MOV A,C ;GET THE CHAR. OUT CDATA ;PRINT IT. RET ;*************************** LPT - LINE PRINTER **************************** ;NOTE -- THIS SECTION GIVES AN LA-36 DECWRITER SOME INTELLIGENCE. LPTST: IN LSTAT ;GET PRINTER STATUS. ANI LPTR ;IF NOT READY, MVI A,0 RZ ; RETURN. CMA ;RETURN 0FFH. RET LPTIN EQU DUMIN LPTOUT: MOV A,C ;GET CHAR. CPI 007H ;? JZ LPTOUTC ;...YES. CPI 008H ;? JZ LPTBS ;...YES. CPI 009H ;? JZ LPTHT ;...YES. CPI 00AH ;? JZ LPTLF ;...YES. CPI 00CH ;
? JZ LPTFF ;...YES. CPI 00DH ;? JZ LPTCR ;...YES. LPTCLI: LDA CLCNT ;INCR COLUMN COUNT. INR A STA CLCNT MOV B,A ;SAVE IT. LPTOUTC: IN LSTAT ;GET PRINTER STATUS. ANI LPTR ;IF NOT READY, JZ LPTOUTC ; LOOP. MOV A,C ;GET THE CHAR. OUT LDATA ;PRINT IT. RET LPTBS: LDA CLCNT ;DECR COLUMN COUNT. DCR A RZ ;IF <0 THEN RETURN W/O PRINTING. STA CLCNT JMP LPTOUTC LPTHT: MVI C,' ' ;ISSUE . CALL LPTCLI MOV A,B ;GET COLUMN COUNT. ANI 8-1 ;ROUND TO MOD 8. JNZ LPTHT ;LOOP TO MOD 8. RET LPTLF: LDA LFCNT ;INCR LF COUNT. CPI 66 ;MAX VALUE? JC $+4 ;...NO. XRA A ;...YES, RESET IT. INR A STA LFCNT JMP LPTOUTC LPTFF: LDA LFCNT ;TOP OF FORM? CPI 1 RZ ;...YES. MVI C,00AH ;ISSUE . CALL LPTLF JMP LPTFF LPTCR: XRA A ;ZERO COLUMN COUNT. STA CLCNT JMP LPTOUTC CLCNT: DB 0 ;COLUMN COUNT LFCNT: DB 1 ;LINE FEED COUNT ;************************ PTP - PAPER TAPE PUNCH *************************** PTPST EQU DUMST PTPIN EQU DUMIN PTPOUT EQU DUMOUT ;************************ PTR - PAPER TAPE READER ************************** PTRST EQU DUMST PTRIN EQU DUMIN PTROUT EQU DUMOUT ;************************ TTY - SLOW SPEED CONSOLE ************************* TTYST: IN LSTAT ;GET TTY STATUS. ANI LKBR ;IF NOT READY, MVI A,0 RZ ; RETURN. CMA ;RETURN 0FFH. RET TTYIN: IN LSTAT ;GET TTY STATUS. ANI LKBR ;IF NOT READY, JZ TTYIN ; LOOP. IN LDATA ;READ THE CHAR. ANI 07FH ;MAKE MOST SIG. BIT=0. RET TTYOUT EQU LPTOUT ;***************************************************** ;* * ;* Unitialized RAM data areas * ;* * ;***************************************************** ; STARTZ: ;** Start of zeroed area ** sekdsk: ds 1 ;seek disk number sektrk: ds 2 ;seek track number seksec: ds 1 ;seek sector number sekdph: ds 2 ;seek .dph(sekdsk) sekdpb: ds 2 ;seek .dpb(sekdsk) ; hstdsk: ds 1 ;host disk number hsttrk: ds 2 ;host track number hstsec: ds 1 ;host sector number hstdph: ds 2 ;host .dph(sekdsk) hstdpb: ds 2 ;host .dpb(sekdsk) ; sekhst: ds 1 ;seek shr secshf hstact: ds 1 ;host active flag hstwrt: ds 1 ;host written flag ; unacnt: ds 1 ;unalloc rec cnt unadsk: ds 1 ;last unalloc disk unatrk: ds 2 ;last unalloc track unasec: ds 1 ;last unalloc sector ; dskcur: ds 1 ;current disk # dsktrk: ds 2 ;current track # dsksec: ds 1 ;current sector # dsktrs: ds 1 ;current trk # (saved) dskdfc: ds 1 ;current format code ; note - the following two latches must be kept ; contiguous. dsklth: ds 1 ;current disk latch dskolt: ds 1 ;old disk latch dskdma: ds 2 ;current dma address dskerr: ds 1 ;current disk error count dsktbl: ds 4*2 ;disk parameter table ; ; one entry for each ; ; physical drive ; db 0nnH ;flags ; 80 - 0=not logged, 1=disk logged ; 40 - 0=single density, 1=double ; db nn ;current track ENDZ: ;** End of Zeroed Area ** if DEBUG trcact: ds 1 ;last traced activity number trcerr: ds 1 ;last traced controller error endif erflag: ds 1 ;error reporting rsflag: ds 1 ;read sector flag readop: ds 1 ;1 if read operation wrtype: ds 1 ;write operation type ccpsav: ds 6 ;CCP non-128-byte boundary data. dmaadr: ds 2 ;last dma address ALV0: ds 48 CSV0: ds 32 ALV1: ds 48 CSV1: ds 32 ALV2: ds 48 CSV2: ds 32 ALV3: ds 48 CSV3: ds 32 dirbuf: ds 128 ;directory buffer hstbuf: ds hstmax ;host buffer end