***************************************************************** * * * Cbios for CP/M Ver 2.2 for Disk Jockey 2D controller (all * * revs, and models A & B). Handles diskettes with sector sizes * * of 128 bytes single density, 256, 512, 1024 bytes double * * density. There are conditional assemblies for Diskus M26 Hard * * Disk Controller. * * * * Written by Bobby Dale Gifford. * * 6/30/80 * * * ***************************************************************** title '*** Cbios For CP/M Ver. 2.2 ***' ***************************************************************** * * * The following revision number is in reference to the CP/M * * 2.2 Cbios. * * * ***************************************************************** revnum equ 56 ;Cbios revision number cpmrev equ 22 ;CP/M revision number ***************************************************************** * * * The following equates set up the relationship between the * * 2D floppies and the Hard Disk Controllers. * * * ***************************************************************** first equ 1 ;0 = Floppies are before Hard Disks (standard) ;1 = Hard Disks are before Floppies maxhd equ 1 ;Set to number of hard disks maxflop equ 0 ;Set to number of floppies if (maxflop ne 0) and (maxhd < 2) drvbias equ 13-maxflop drvtop equ 13+(maxhd*3) else drvbias equ 16-maxflop-(maxhd*3) drvtop equ 16 endif retries equ 10 ;Max retries on disk i/o before error bdos equ 6 ***************************************************************** * * * The following equates are for the Diskus M26 if wanted. * * * ***************************************************************** if maxhd ne 0 ;Want M26 included ? hdorg equ 50h ;Hard Disk Controller origin hdstat equ hdorg ;Hard Disk Status hdcntl equ hdorg ;Hard Disk Control hddata equ hdorg+3 ;Hard Disk Data hdfunc equ hdorg+2 ;Hard Disk Function hdcmnd equ hdorg+1 ;Hard Disk Command hdreslt equ hdorg+1 ;Hard Disk Result retry equ 2 ;Retry bit of result tkzero equ 1 ;Track zero bit of status opdone equ 2 ;Operaction done bit of status complt equ 4 ;Complete bit of status tmout equ 8 ;Time out bit of status wfault equ 10h ;Write fault bit of status drvrdy equ 20h ;Drive ready bit of status index equ 40h ;Index bit of status pstep equ 4 ;Step bit of function nstep equ 0fbh ;Step bit mask of function hdrlen equ 4 ;Sector header length seclen equ 512 ;Sector data length wenabl equ 0fh ;Write enable wreset equ 0bh ;Write reset of function scenbl equ 5 ;Controller control dskclk equ 7 ;Disk clock for control mdir equ 0f7h ;Direction mask for function null equ 0fch ;Null command idbuff equ 0 ;Initialize data command isbuff equ 8 ;Initialize header command rsect equ 1 ;Read sector command wsect equ 5 ;Write sector command endif ***************************************************************** * * * The jump table below must remain in the same order, the * * routines may be changed, but the function executed must be * * the same. * * * ***************************************************************** org 0 jmp $ ;Cold boot entry point owboot jmp wboot ;Warm boot entry point jmp $ ;Console status routine ocin jmp $ ;Console input ocout jmp $ ;Console output jmp $ ;List device output jmp $ ;Punch device output jmp $ ;Reader device input ohome jmp home ;Home drive osetdrv jmp setdrv ;Select disk osettrk jmp settrk ;Set track osetsec jmp setsec ;Set sector osetdma jmp setdma ;Set DMA address oread jmp read ;Read the disk owrite jmp write ;Write the disk jmp $ ;List device status osectrn jmp sectran ;Sector translation ***************************************************************** * * * Mirror image of Disk Jockey jump table. * * * ***************************************************************** if maxflop ne 0 origin equ 0 djram equ origin+400h ;Disk Jockey 2D RAM address dblsid equ 8 ;Side bit from controller orig dw origin djboot jmp djram ;Disk Jockey 2D initialization jmp djram+3 ;Disk jockey 2D cin jmp djram+6 ;Disk Jockey 2D cout djhome jmp djram+9h ;Disk Jockey 2D track zero seek djtrk jmp djram+0ch ;Disk Jockey 2D track seek routine djsec jmp djram+0fh ;Disk Jockey 2D set sector routine djdma jmp djram+012h ;Disk Jockey 2D set DMA address djread jmp djram+15h ;Disk Jockey 2D read routine djwrite jmp djram+18h ;Disk Jockey 2D write routine djdrv jmp djram+1bh ;Disk Jockey 2D select drive routine jmp djram+1eh djtstat jmp djram+21h ;Disk Jockey 2D terminal status routine jmp djram+24h djstat jmp djram+27h ;Disk Jockey 2D status routine djerr jmp djram+2ah ;Disk Jockey 2D error, flash led djden jmp djram+2dh ;Disk Jockey 2D set density routine djside jmp djram+30h ;Disk Jockey 2D set side routine endif dbot db drvbias ;First logical drive dtop db drvtop ;Last logical drive ***************************************************************** * * * Warm boot searches for the Disk Jockey prom, and then fills * * in the preceeding jump table. * * * ***************************************************************** wboot mvi a,0ffh inr a jnz owboot sta wboot+1 lda 80h ana a jz nochng sui 'A' cpi 1 jc nochng cpi 16 jnc nochng sta dbot adi drvtop-drvbias sta dtop nochng equ $ if maxflop ne 0 lhld bdos mov a,h ani 0f8h mov h,a mvi l,0 wblop push h mvi b,17 lxi d,djboot wbloop mov a,m inx h inx h inx h cpi 0c3h jnz next inx d inx d mov a,h adi 4 stax d inx d dcr b jnz wbloop pop h push h lxi d,7 dad d mov a,m inx h mov h,m mov l,a mov a,m cpi 03ah jnz next inx h inx h inx h mov a,m cpi 0e6h jnz next inx h mov a,m cpi 8 jnz next inx h mov a,m cpi 0c2h jnz next pop h shld orig jmp owboot next pop h lxi d,1024 dad d mov a,h ana a jnz wblop lxi h,messg err mov a,m inx h ana a stop jz stop mov c,a push h call ocout pop h jmp err messg db 0dh,0ah db 'Can not locate the Disk Jockey 2D.' db 0dh,0ah db 0 else jmp owboot endif ***************************************************************** * * * conin: flush the disk buffer before console I/O. * * * ***************************************************************** conin call flush ;Flush the disk buffer jmp ocin conout push b ;Save the character call flush ;Flush the disk buffer pop b ;Restore the character jmp ocout ***************************************************************** * * * Setsec just saves the desired sector to seek to until an * * actual read or write is attempted. * * * ***************************************************************** setsec mov h,b mov l,c shld cpmsec lda dbot mov h,a lda dtop mov l,a lda cpmdrv cmp h jc osetsec cmp l jnc osetsec ret ***************************************************************** * * * Setdma saves the DMA address for the data transfer. * * * ***************************************************************** setdma mov h,b ;hl <- bc mov l,c shld cpmdma ;CP/M dma address lda dbot mov h,a lda dtop mov l,a lda cpmdrv cmp h jc osetdma cmp l jnc osetdma ret ***************************************************************** * * * Home is translated into a seek to track zero. * * * ***************************************************************** home xra a ;Track to seek to sta cpmtrk lda dbot mov h,a lda dtop mov l,a lda cpmdrv cmp h jc ohome cmp l jnc ohome ret ***************************************************************** * * * Settrk saves the track # to seek to. Nothing is done at this * * point, everything is deffered until a read or write. * * * ***************************************************************** settrk mov a,c ;A <- track # sta cpmtrk ;CP/M track # lda dbot mov h,a lda dtop mov l,a lda cpmdrv cmp h jc osettrk cmp l jnc osettrk ret ***************************************************************** * * * Sectran translates a logical sector # into a physical sector * * #. * * * ***************************************************************** sectran lda dbot mov h,a lda dtop mov l,a lda cpmdrv cmp h jc osectrn cmp l jnc osectrn if (maxhd ne 0) and (maxflop ne 0) ;Both types ? lda cpmdrv ;Get the Drive Number sub h if first cpi maxhd*3 ;Over the # of hard disks ? jc tranhd else cpi maxflop ;Over the # of floppies ? jnc tranhd endif endif if maxflop ne 0 ;Floppy translation tranfp inx b push d ;Save table address push b ;Save sector # call getdpb ;Get DPB address into HL mov a,m ;Get # of CP/M sectors/track ora a ;Clear cary rar ;Divide by two sub c push psw ;Save adjusted sector jm sidetwo sidea pop psw ;Discard adjusted sector pop b ;Restore sector requested pop d ;Restor address of xlt table sideone xchg ;hl <- &(translation table) dad b ;bc = offset into table mov l,m ;hl <- physical sector mvi h,0 donop ret sidetwo lxi b,15 ;Offset to side bit dad b mov a,m ani 8 ;Test for double sided jz sidea ;Media is only single sided pop psw ;Retrieve adjusted sector pop b cma ;Make sector request positive inr a mov c,a ;Make new sector the requested sector pop d call sideone mvi a,80h ;Side two bit ora h ; and sector mov h,a ret endif if maxhd ne 0 ;Hard Disk translation routine tranhd mov h,b mov l,c inx h ret endif ***************************************************************** * * * Setdrv selects the next drive to be used in read/write * * operations. If the drive has never been selected before, a * * parameter table is created which correctly describes the * * diskette currently in the drive. Diskettes can be of four * * different sector sizes: * * 1) 128 bytes single density. * * 2) 256 bytes double density. * * 3) 512 bytes double density. * * 4) 1024 bytes double density. * * * ***************************************************************** setdrv mov a,c ;Save the drive # sta cpmdrv lda dbot mov h,a lda dtop mov l,a lda cpmdrv cmp h ;Check for a valid drive # jc osetdrv ;Illegal drive # cmp l jnc osetdrv mov a,e ;Test if drive ever logged in before ani 1 jnz setdrv1 ;Bit 0 of E = 0 -> Never selected before if (maxhd ne 0) and (maxflop ne 0) ;Both types ? lda cpmdrv ;Get the Drive Number sub h if first cpi maxhd*3 ;Over the # of hard disks ? jc drvhd sui maxhd*3 else cpi maxflop ;Over the # of floppies ? jnc subfp endif endif if maxflop ne 0 mov c,a ;Save drive # mvi a,0 ;Have the floppies been accessed yet ? flopflg equ $-1 ana a jnz flopok mvi b,17 ;Floppies havn't been accessed lxi h,djboot ;Check if 2D controller is installed mvi a,(jmp) clopp cmp m jnz zret dcr b jnz clopp call djboot ;Initialize the controller mvi a,1 ;Save 2D initialized flag sta flopflg flopok lxi h,1 ;Select sector 1 of track 1 shld truesec mvi a,1 sta cpmtrk call fill ;Flush buffer and refill jc zret ;Test for error return call djstat ;Get status on current drive ani 0ch ;Strip off unwanted bits push psw ;Used to select a DPB rar lxi h,xlts ;Table of XLT addresses mov e,a mvi d,0 dad d push h ;Save pointer to proper XLT call getdpb ;Get DPH pointer into DE xchg ; pop d mvi b,2 ;Number of bytes to move call movlop ;Move the address of XLT lxi d,8 ;Offset to DPB pointer dad d ;HL <- &DPH.DPB push h lhld orig ;Get address of DJ terminal out routine lxi d,7 dad d mov a,m mov h,m mov l,a inx h ;Bump to look at address of ; uart status location mov a,m xri 3 ;Adjust for proper rev DJ mov l,a lda orig+1 adi 3 mov h,a mov a,m ani dblsid ;Check double sided bit lxi d,dpb128s ;Base for single sided DPB's jnz sideok lxi d,dpb128d ;Base of double sided DPB's sideok xchg ;HL <- DBP base, DE <- &DPH.DPB pop d ;Restore DE (pointer into DPH) pop psw ;Offset to correct DPB ral ral mov c,a mvi b,0 dad b xchg ;Put DPB address in DPH mov m,e inx h mov m,d endif if (maxhd ne 0) and (maxflop ne 0) jmp setdrv1 ;Skip over the Hard Disk select if not first subfp sui maxflop ;Adjust the drive # endif endif if maxhd ne 0 drvhd call div3 ;Divide by three to get drive # mov a,c sta hddisk call drvptr mov a,m inr a jnz setdrv1 ori null ;Select drive out hdfunc mvi a,scenbl ;Enable the controller out hdcntl mvi c,239 ;Wait approx 2 minutes for Disk to ready lxi h,0 tdelay dcx h mov a,h ora l cz dcrc rz in hdstat ;Test if ready yet ani drvrdy jnz tdelay lxi h,0 ;Time one revolution of the drive mvi c,index in hdstat ana c mov b,a ;Save current index level in B indx1 in hdstat ana c cmp b ;Loop util index level changes jz indx1 indx2 inx h in hdstat ;Start counting until index returns to ana c ; previous state cmp b jnz indx2 shld settle ;Save the Count for timeout delay call hdhome endif setdrv1 call getdpb ;Get address of DPB in HL lxi b,15 ;Offset to sector size dad b mov a,m ;Get sector size ani 7h sta secsiz mov a,m rar rar rar rar ani 0fh sta secpsec xchg ;HL <- DPH ret zret lxi h,0 ;Seldrv error exit ret if maxhd ne 0 dcrc dcr c ;Conditional decrement C routine ret div3 mvi c,0 div3x sui 3 rc inr c jmp div3x endif ***************************************************************** * * * Getdpb returns HL pointing to the DPB of the currently * * selected drive, DE pointing to DPH. * * * ***************************************************************** getdpb lda dbot mov h,a lda cpmdrv sub h mov l,a ;Form offset mvi h,0 dad h dad h dad h dad h lxi d,dpbase ;Base of DPH's dad d push h ;Save address of DPH lxi d,10 ;Offset to DPB dad d mov a,m ;Get low byte of DPB address inx h mov h,m ;Get low byte of DPB mov l,a pop d ret ***************************************************************** * * * Xlts is a table of address that point to each of the xlt * * tables for each sector size. * * * ***************************************************************** if maxflop ne 0 xlts dw xlt128 ;Xlt for 128 byte sectors dw xlt256 ;Xlt for 256 byte sectors dw xlt512 ;Xlt for 512 byte sectors dw xlt124 ;Xlt for 1024 byte sectors endif ***************************************************************** * * * Write routine moves data from memory into the buffer. If the * * desired CP/M sector is not contained in the disk buffer, the * * buffer is first flushed to the disk if it has ever been * * written into, then a read is performed into the buffer to get * * the desired sector. Once the correct sector is in memory, the * * buffer written indicator is set, so the buffer will be * * flushed, then the data is transferred into the buffer. * * * ***************************************************************** write lda dbot mov h,a lda dtop mov l,a lda cpmdrv cmp h jc owrite cmp l jnc owrite mov a,c ;Save write command type sta writtyp mvi a,1 ;Set write command db (mvi) or (b*8) ;This "mvi b" instruction causes ; the following "xra a" to ; be skipped over. ***************************************************************** * * * Read routine to buffer data from the disk. If the sector * * requested from CP/M is in the buffer, then the data is simply * * transferreä froí thå buffeò tï thå desireä dma address. If * * the buffer does not contain the desired sector, the buffer is * * flushed to the disk if it has ever been written into, then * * filled with the sector from the disk that contains the * * desired CP/M sector. * * * ***************************************************************** read xra a ;Set the command type to read sta rdwr ;Save command type lda dbot mov h,a lda dtop mov l,a lda cpmdrv cmp h jc oread cmp l jnc oread ***************************************************************** * * * Redwrt calculates the physical sector on the disk that * * contains the desired CP/M sector, then checks if it is the * * sector currently in the buffer. If no match is made, the * * buffer is flushed if necessary and the correct sector read * * from the disk. * * * ***************************************************************** redwrt mvi b,0 ;The 0 is modified to contain the log2 secsiz equ $-1 ; of the physical sector size/128 ; on the currently selected disk. lhld cpmsec ;Get the desired CP/M sector # mov a,h ani 80h ;Save only the side bit mov c,a ;Remember the side mov a,h ani 7fh ;Forget the side bit mov h,a dcx h ;Temporary adjustment divloop dcr b ;Update repeat count jz divdone ora a mov a,h rar mov h,a mov a,l rar ;Divide the CP/M sector # by the size ; of the physical sectors mov l,a jmp divloop ; divdone inx h mov a,h ora c ;Restore the side bit mov h,a shld truesec ;Save the physical sector number lxi h,cpmdrv ;Pointer to desired drive,track, and sector lxi d,bufdrv ;Pointer to buffer drive,track, and sector mvi b,5 ;Count loop dtslop dcr b ;Test if done with compare jz move ;Yes, match. Go move the data ldax d ;Get a byte to compare cmp m ;Test for match inx h ;Bump pointers to next data item inx d jz dtslop ;Match, continue testing ***************************************************************** * * * Drive, track, and sector don't match, flush the buffer if * * necessary and then refill. * * * ***************************************************************** call fill ;Fill the buffer with correct physical sector rc ;No good, return with error indication ***************************************************************** * * * Move has been modified to cause either a transfer into or out * * the buffer. * * * ***************************************************************** move lda cpmsec ;Get the CP/M sector to transfer dcr a ;Adjust to proper sector in buffer ani 0 ;Strip off high ordered bits secpsec equ $-1 ;The 0 is modified to represent the # of ; CP/M sectors per physical sectors mov l,a ;Put into HL mvi h,0 dad h ;Form offset into buffer dad h dad h dad h dad h dad h dad h lxi d,buffer ;Beginning address of buffer dad d ;Form beginning address of sector to transfer xchg ;DE = address in buffer lxi h,0 ;Get DMA address, the 0 is modified to ; contain the DMA address cpmdma equ $-2 mvi a,0 ;The zero gets modified to contain ; a zero if a read, or a 1 if write rdwr equ $-1 ana a ;Test which kind of operation jnz into ;Transfer data into the buffer outof call mover xra a ret into xchg ; call mover ;Move the data, HL = destination ; DE = source mvi a,1 sta bufwrtn ;Set buffer written into flag mvi a,0 ;Check for directory write writtyp equ $-1 dcr a mvi a,0 sta writtyp ;Set no directory write rnz ;No error exit ***************************************************************** * * * Flush writes the contents of the buffer out to the disk if * * it has ever been written into. * * * ***************************************************************** flush mvi a,0 ;The 0 is modified to reflect if ; the buffer has been written into bufwrtn equ $-1 ana a ;Test if written into rz ;Not written, all done if (maxhd ne 0) and (maxflop ne 0) lxi h,djwrite ;Write operation for Disk Jockey lxi d,hdwrite ;Write operation for Hard Disk call decide else if maxhd ne 0 lxi h,hdwrite endif if maxflop ne 0 lxi h,djwrite endif endif ***************************************************************** * * * Prep prepares to read/write the disk. Retries are attempted. * * Upon entry, H&L must contain the read or write operation * * address. * * * ***************************************************************** prep xra a ;Reset buffer written flag sta bufwrtn shld retryop ;Set up the read/write operation mvi b,retries ;Maximum number of retries to attempt retrylp push b ;Save the retry count lda dbot mov h,a lda bufdrv ;Get drive number involved in the operation sub h if (maxhd ne 0) and (maxflop ne 0) if first cpi maxhd*3 jc noadjst sui maxhd*3 else cpi maxflop jc noadjst sui maxflop endif noadjst mov c,a lxi h,djdrv ;Select drive lxi d,hddrv call decidgo else mov c,a if maxhd ne 0 call hddrv endif if maxflop ne 0 call djdrv ;Select the drive endif endif lda buftrk ana a ;Test for track zero mov c,a push b if (maxhd ne 0) and (maxflop ne 0) lxi h,djhome lxi d,hdhome cz decidgo else if maxhd ne 0 cz hdhome endif if maxflop ne 0 cz djhome ;Home the drive if track 0 endif endif pop b ;Restore track # if (maxhd ne 0) and (maxflop ne 0) lxi h,djtrk lxi d,hdtrk call decidgo else if maxhd ne 0 call hdtrk endif if maxflop ne 0 call djtrk ;Seek to proper track endif endif lhld bufsec mov a,h ;Get sector involved in operation rlc ;Bit 0 of A equals side # ani 1 ;Strip off unnecessary bits mov c,a ;C <- side # if (maxhd ne 0) and (maxflop ne 0) lxi h,djside lxi d,hdside call decidgo else if maxhd ne 0 call hdside endif if maxflop ne 0 call djside ;Select the side endif endif lhld bufsec mov a,h ani 7fh ;Strip off side bit mov b,a ;C <- sector # mov c,l if (maxhd ne 0) and (maxflop ne 0) lxi h,djsec lxi d,hdsec call decidgo else if maxhd ne 0 call hdsec endif if maxflop ne 0 call djsec ;Select the side endif endif lxi b,buffer ;Set the DMA address if (maxhd ne 0) and (maxflop ne 0) lxi h,djdma lxi d,hddma call decidgo else if maxhd ne 0 call hddma endif if maxflop ne 0 call djdma ;Select the side endif endif call 0 ;Get operation address retryop equ $-2 pop b ;Restore the retry counter mvi a,0 ;No error exit status rnc ;Return no error dcr b ;Update the retry counter stc ;Assume retry count expired mvi a,0ffh ;Error return rz jmp retrylp ;Try again ***************************************************************** * * * Fill fills the buffer with a new sector from the disk. * * * ***************************************************************** fill call flush ;Flush buffer first rc ;Check for error lxi d,cpmdrv ;Update the drive, track, and sector lxi h,bufdrv mvi b,4 ;Number of bytes to move call movlop ;Copy the data lda rdwr ana a jz not128 lda writtyp dcr a dcr a rz call getdpb lxi d,15 dad d mov a,m ani 3 dcr a rz not128 equ $ if (maxhd ne 0) and (maxflop ne 0) lxi h,djread lxi d,hdread call decide else if maxhd ne 0 lxi h,hdread endif if maxflop ne 0 lxi h,djread ;Select the side endif endif jmp prep ;Select drive, track, and sector. ; Then read the buffer ***************************************************************** * * * Mover moves 128 bytes of data. Source pointer in DE, Dest * * pointer in HL. * * * ***************************************************************** mover mvi b,128 ;Length of transfer movlop ldax d ;Get a bte of source mov m,a ;Move it inx d ;Bump pointers inx h dcr b ;Update counter jnz movlop ;Continue moving until done ret ***************************************************************** * * * Routines to decide which controller to use. * * * ***************************************************************** if (maxhd ne 0) and (maxflop ne 0) decidgo call decide ;which controller ? pchl endif if (maxhd ne 0) and (maxflop ne 0) decide lda dbot push h mov h,a lda bufdrv ;Get proper routine into H&L, based sub h pop h if first ; on currently selected drive cpi maxhd*3 rnc else cpi maxflop rc endif xchg ret endif ***************************************************************** * * * The following is the equivalent of the lowest level drivers * * for the Hard Disk. * * * ***************************************************************** if maxhd ne 0 hddrv mov a,c ;Select Hard Disk drive call div3 ;Get the physical drive # mov a,c sta hddisk ;Select the drive ori null out hdfunc mvi a,wenabl out hdcntl ret setkey mov a,c sta nkey ret hdhome call drvptr mvi m,0 ;Set track to zero stepo in hdstat ;Test status ani tkzero ;At track zero ? jz delay mvi a,1 stc call accok ;Take one step out call wsdone ;Wait for previous seek to finish jmp stepo delay lxi h,0 ;Get delay settle equ $-2 deloop dcx h ;Wait 20ms mov a,h ora l inx h dcx h jnz deloop ret hdtrk call drvptr ;Get pointer to current track mov e,m ;Get current track mov m,c ;Update the track mov a,e ;Need to seek at all ? sub c rz cmc ;Get carry into direction jc accok cma inr a accok mov b,a ;Prep for build call build sloop ani nstep ;Get step pulse low out hdfunc ;Output low step line ori pstep ;Set step line high out hdfunc ;Output high step line dcr b ;Update repeat count jnz sloop ;Keep going the required # of tracks call wsdone jmp delay hddma mov h,b ;Save the DMA address mov l,c shld hdadd hdside equ $ ret wsdone in hdstat ;Wait for seek complete to finish ani complt jz wsdone ret hdsec mvi a,01fh ;Mask for sector # ana c cz get32 sta hdsectr mvi a,0e0h ;Mask for Head # ana c rlc rlc rlc sta head get32 mvi a,32 ret hdread mvi a,0 nkey equ $-1 sta okey xra a sta nkey call hdprep rc xra a out hdcmnd cma out hddata out hddata mvi a,rsect ;Read sector command out hdcmnd call process rc xra a out hdcmnd mvi b,seclen/4 lxi h,0 hdadd equ $-2 in hddata in hddata rtloop in hddata ;Move four bytes mov m,a inx h in hddata mov m,a inx h in hddata mov m,a inx h in hddata mov m,a inx h dcr b jnz rtloop ret hdwrite call hdprep ;Prepare header rc xra a out hdcmnd lhld hdadd mvi b,seclen/4 wtloop mov a,m ;Move 4 bytes out hddata inx h mov a,m out hddata inx h mov a,m out hddata inx h mov a,m out hddata inx h dcr b jnz wtloop mvi a,wsect ;Issue write sector command out hdcmnd call process rc mvi a,wfault ana b stc rz xra a ret process in hdstat ;Wait for command to finish mov b,a ani opdone jz process mvi a,dskclk out hdcntl in hdstat ani tmout ;Timed out ? stc rnz in hdreslt ani retry ;Any retries ? stc rnz xra a ret hdprep in hdstat ani drvrdy stc rnz mvi a,isbuff ;Initialize pointer out hdcmnd call build ori 0ch out hdfunc lda head out hddata ;Form head byte call drvptr mov a,m ;Form track byte out hddata mvi a,0 ;Form sector byte hdsectr equ $-1 out hddata mvi a,0 okey equ $-1 out hddata mvi a,dskclk out hdcntl mvi a,wenabl out hdcntl xra a ret drvptr lhld hddisk xchg mvi d,0 lxi h,drives dad d ret build mvi a,0 head equ $-1 ral ral ral ral ori 0 hddisk equ $-1 xri 0f0h ret drives equ $ rept maxhd db 0ffffh endm endif ***************************************************************** * * * Xlt tables (sector skew tables) for CP/M 2.0. These tables * * define the sector translation that occurs when mapping CP/M * * sectors to physical sectors on the disk. There is one skew * * table for each of the possible sector sizes. Currently the * * tables are located on track 0 sectors 6 and 8. They are * * loaded into memory in the Cbios ram by the cold boot routine. * * * ***************************************************************** if maxflop ne 0 xlt128 db 0 db 1,7,13,19,25 db 5,11,17,23 db 3,9,15,21 db 2,8,14,20,26 db 6,12,18,24 db 4,10,16,22 xlt256 db 0 db 1,2,19,20,37,38 db 3,4,21,22,39,40 db 5,6,23,24,41,42 db 7,8,25,26,43,44 db 9,10,27,28,45,46 db 11,12,29,30,47,48 db 13,14,31,32,49,50 db 15,16,33,34,51,52 db 17,18,35,36 xlt512 db 0 db 1,2,3,4,17,18,19,20 db 33,34,35,36,49,50,51,52 db 5,6,7,8,21,22,23,24 db 37,38,39,40,53,54,55,56 db 9,10,11,12,25,26,27,28 db 41,42,43,44,57,58,59,60 db 13,14,15,16,29,30,31,32 db 45,46,47,48 xlt124 db 0 db 1,2,3,4,5,6,7,8 db 25,26,27,28,29,30,31,32 db 49,50,51,52,53,54,55,56 db 9,10,11,12,13,14,15,16 db 33,34,35,36,37,38,39,40 db 57,58,59,60,61,62,63,64 db 17,18,19,20,21,22,23,24 db 41,42,43,44,45,46,47,48 ***************************************************************** * * * Each of the following tables describes a diskette with the * * specified characteristics. The tables are currently stored * * on track 0 sector 13. They are read into memory by the GOCPM * * routine in the CBIOS for CP/M ver 2.0. * * * ***************************************************************** ***************************************************************** * * * The following DPB defines a diskette for 128 byte sectors, * * single density, and single sided. * * * ***************************************************************** dpb128s dw 26 ;CP/M sectors/track db 3 ;BSH db 7 ;BLM db 0 ;EXM dw 242 ;DSM dw 63 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 16 ;CKS dw 2 ;OFF db 1h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * The following DPB defines a diskette for 256 byte sectors, * * double density, and single sided. * * * ***************************************************************** dpb256s dw 52 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 242 ;DSM dw 127 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 32 ;CKS dw 2 ;OFF db 12h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * The following DPB defines a diskette as 512 byte sectors, * * double density, and single sided. * * * ***************************************************************** dpb512s dw 60 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 280 ;DSM dw 127 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 32 ;CKS dw 2 ;OFF db 33h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * The following DPB defines a diskette as 1024 byte sectors, * * double density, and single sided. * * * ***************************************************************** dp1024s dw 64 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 299 ;DSM dw 127 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 32 ;CKS dw 2 ;OFF db 74h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * The following DPB defines a diskette for 128 byte sectors, * * single density, and double sided. * * * ***************************************************************** dpb128d dw 52 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 1 ;EXM dw 242 ;DSM dw 127 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 32 ;CKS dw 2 ;OFF db 9h ***************************************************************** * * * The following DPB defines a diskette as 256 byte sectors, * * double density, and double sided. * * * ***************************************************************** dpb256d dw 104 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 486 ;DSM dw 255 ;DRM db 0f0h ;AL0 db 0 ;AL1 dw 64 ;CKS dw 2 ;OFF db 1ah ***************************************************************** * * * The following DPB defines a diskette as 512 byte sectors, * * double density, and double sided. * * * ***************************************************************** dpb512d dw 120 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 561 ;DSM dw 255 ;DRM db 0f0h ;AL0 db 0 ;AL1 dw 64 ;CKS dw 2 ;OFF db 3bh ***************************************************************** * * * The following DPB defines a diskette as 1024 byte sectors, * * double density, and double sided. * * * ***************************************************************** dp1024d dw 128 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 599 ;DSM dw 255 ;DRM db 0f0h ;AL0 db 0 ;AL1 dw 64 ;CKS dw 2 ;OFF db 7ch endif ***************************************************************** * * * The following DPB defines a 26 Megabyte Hard disk, with 512 * * byte sectors. * * * ***************************************************************** if maxhd ne 0 dpbhd1 dw 1024 ;CP/M sectors/track db 5 ;BSH db 31 ;BLM db 1 ;EXM dw 1973 ;DSM dw 511 ;DRM db 0ffh ;AL0 db 0ffh ;AL1 dw 0 ;CKS dw 1 ;OFF db 33h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. dpbhd2 dw 1024 ;CP/M sectors/track db 5 ;BSH db 31 ;BLM db 1 ;EXM dw 1973 ;DSM dw 511 ;DRM db 0ffh ;AL0 db 0ffh ;AL1 dw 0 ;CKS dw 64 ;OFF db 33h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. dpbhd3 dw 1024 ;CP/M sectors/track db 5 ;BSH db 31 ;BLM db 1 ;EXM dw 1973 ;DSM dw 511 ;DRM db 0ffh ;AL0 db 0ffh ;AL1 dw 0 ;CKS dw 127 ;OFF db 33h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. endif ***************************************************************** * * * CP/M disk parameter headers, unitialized. * * * ***************************************************************** header macro nd,dpb dw 0 ;Translation table filled in later dw 0,0,0 ;Scratch dw dirbuf ;Directory buffer dw dpb ;DPB filled in later dw csv&nd ;Directory check vector dw alv&nd ;Allocation vector endm dpbase equ $ dn set 0 if first rept maxhd ;Generate Hard Disk DPH's followed header %dn,dpbhd1 ; by Floppy DPH's dn set dn+1 header %dn,dpbhd2 dn set dn+1 header %dn,dpbhd3 dn set dn+1 endm rept maxflop header %dn,0 dn set dn+1 endm else rept maxflop ;Generate Floppy DPH's followed by header %dn,0 ; HArd Disk DPH's dn set dn+1 endm rept maxhd header %dn,dpbhd1 dn set dn+1 header %dn,dpbhd2 dn set dn+1 header %dn,dpbhd3 dn set dn+1 endm endif ***************************************************************** * * * Cbios ram locations that don't need initialization. * * * ***************************************************************** cpmsec dw 0 ;CP/M sector # cpmdrv db 0 ;CP/M drive # cpmtrk db 0 ;CP/M track # truesec dw 0 ;Disk Jockey sector that contains CP/M sector bufdrv db 0 ;Drive that buffer belongs to buftrk db 0 ;Track that buffer belongs to bufsec dw 0 ;Sector that buffer belongs to buffer ds 512 ;Maximum size buffer for 512 byte sectors if maxflop ne 0 ds 512 ;Additional space for floppies 1k sectors endif if (maxflop ne 0) or (maxhd ne 0) dirbuf ds 128 ;Directory buffer endif alloc macro nd,al,cs alv&nd ds al csv&nd ds cs endm dn set 0 if not first rept maxflop alloc %dn,75,64 dn set dn+1 endm rept maxhd*3 alloc %dn,247,0 dn set dn+1 endm else rept maxhd*3 alloc %dn,247,0 dn set dn+1 endm rept maxflop alloc %dn,75,64 dn set dn+1 endm endif db 0 end