* * REGEN.ASM vers 1.1 september 30, 1980 * * By Bryan G. Moore * Design Technology * 4888-H Ronson Court * San Diego, CA 92111 * * Modified for all revision Disk Jockey 2D'S by Bobby Dale Gifford * 9/30/80 * * The program is used to correct the format on Single Density * IBM 3740 compatible diskettes. Attempts to use other diskettes * will probably result in an error message. * * Last modified 25 Sep 84 GLH:W6BSK * Comments added to damned near everything. * * vernum equ 11 ;Version number * 10 origin equ 0E000h ;Disk Jockey 2D prom bdos equ 5 ;CP/M entry point wboot equ 0 ;Warm boot diskio equ origin+3f8h ;Disc Jockey control block address drvsel equ diskio+1 ;DJ drive select register djserp equ diskio+2 ;DJ serial i/o status port - NUsed cstall equ diskio+3 ;DJ stall routine entry cmdreg equ diskio+4 ;DJ command register trkreg equ diskio+5 ;DJ track register secreg equ diskio+6 ;DJ sector register datreg equ diskio+7 ;DJ data register dside equ 10Q ;Double sided mask sicmd equ 131Q ;Step in command immirq equ 320Q ;Immediate interrupt command unloada equ 30Q ;Unload mask for Model A DJ unloadb equ 17Q ;Unload mask for Model B DJ restor equ 11Q ;Seek track 0 command rtcmd equ 0e4h ;Read track command wtcmd equ 0f4h ;Write track command wsec equ 0a0h ;Write sector command rsec equ 80h ;Read sector command index equ 20Q ;Index hole mask trkzro equ 4 ;Track 0 mask lhsdenb equ 90dh ;DJ Model B sd load head mask lhddenb equ 80ch ;DJ Model B dd load head mask lhsdena equ 111h ;DJ Model A sd load head mask lhddena equ 10h ;DJ Model A dd load head mask acr equ 0dh ;cr/lf masks, naturally alf equ 0ah org 100h ;CP/M Tpa begin lxi sp,stack ;Stack pointer Š lxi d,prompt ;Sign-on call pbuff ;To console lhld origin+7 ;Adjust the calling routines for different inx h ; revisions of the Disk Jockey mov a,m lxi h,stdvsl+1 ;Get the DJ Model id byte from memory and lxi d,4 ;store it in the program. 00=model A, mov m,a ;C9=model B. xri 3 dad d mov m,a dad d mov m,a start lxi d,srcmsg ;Prompt the user to select drive call readdrv ;Get a drive designator sta sdisk ;Save source disk lxi d,dstmsg ;Prompt the user to select drive call readdrv ;Get drive designator sta ddisk ;Save destination disk mount lxi d,mntmsg ;Prompt the user to call prbuff ;Read console jnz start ;Ignore anything else regena lxi d,acralf ;Do a cr/lf call pbuff xra a ;Select source call select ;Select the drive lxi h,cmdreg ;Get the command ;lregister mvi m,immirq ;and load an immediate interrup command mvi a,40h ;Simple delay delay01 dcr a jnz delay01 mov a,m ;Check ready rar jc notrdy ral ral jc notrdy lxi d,0 call gtindx ;Get polarity of index pulse call gtstat ;Test for double sided ani dside jnz index01 ;Continue if single sided; dblside lxi d,sglside ;double sided not allowed. jmp notrdyx index01 call gtstat ;Wait for index pulses ani index Š xra b jnz restora dcx d mov a,d ora a jnz index01 notrdy lxi d,rmessg ;" is not ready." notrdyx xchg lxi d,amessg ;cr/lf,"Drive " push h call pbuff ;Print drive message lda cdisk ana a lda sdisk jz notdrv lda ddisk ;Get the destination drive notdrv adi 'A' ;and convert to ASCII mov e,a mvi c,2 call bdos ;Display it pop d call pbuff ;Complete the message call unload ;unload the heads jmp mount ;and loop back. restora call restore ;Set to track 0 of both drives regenb mvi a,1 ;Select destination call select ;Select the drive lxi h,cmdreg mvi m,immirq ;Immediate interupt request mvi a,40h ;Do a short delay to give time for delay02 dcr a ;request to be granted. jnz delay02 mov a,m ;Check ready rar jc notrdy ;Busy or otherwise done in ral ral jc notrdy lxi d,wmessg ;" is write protected." ral ;Test for write protected- jc notrdyx ;is, say so. lxi d,0 ;taint, go ahaid. call gtindx ;Get polarity of index pulse index02 call gtstat ;Wait for index pulses ani index xra b jnz regen ;Ready, jump out. Š dcx d ;Not found yet, look some more mov a,d ora a ;try,try again, until jnz index02 jmp notrdy ;all hope is lost. restore lxi h,cmdreg ;Point to command register mvi m,restor ;and do a seek track 0 command delay03 mov a,m rar ;Wait for busy jnc delay03 delay04 mov a,m rar ;Wait for not busy jc delay04 mov a,m ;Get status byte ani trkzro ;Mask for track 00 jz notrdy ;Error if not at track 00 ret regen call restore ;Seek track 0 and set the track counter xra a ;to 0 initially. This counter will sta tkno ;keep track of the current track. mvi a,10 ;Reset read retry sta trcnt ; counter to 10 dloop xra a ;Set for drive A call select ;each read. call wnbusy ;Wait until not busy lxi d,datreg ;Pointer acts as Data Register lxi h,tkbuf ;Track buffer lxi b,24 ; Set page count mvi a,rtcmd ;Set in read track command sta cmdreg ;and execute it. datin ldax d ;Load a data byte mov m,a ;Store in memory inr l ;Bump pointer / counter jnz datin ;Get next byte inr h ;Bump high order dcr c ;Hit page count jnz datin ;Loop til track read in * twloop lda ddisk ;get the destination disk call select ;and make it current. call windex db 00,00,00,00,00,00 lxi b,24 ;Wait for Controller Ready lxi d,datreg ;Point to 1791 data register lxi h,tkbuf mvi a,wtcmd ;Do the track write operation Š sta cmdreg ; Number of pages xchg ;Start of track buffer wloop ldax d ;Get source byte from memory mov m,a ;Write the data to the controller inr e ; Get next byte jnz wloop ; and dump it. inr d ; Update page count dcr c ; and test if done. jnz wloop lxi h,tkno ;Point to Track number inr m ;Bump it mov a,m ;Get next track number cpi 77 ;Is re-formatting complete ? jc tkstep ;No - do next track call unload finish lxi d,fmessg ;Send completion done call prbuff ; message to console cpi 'R' ;More Re-formatting ? jz start ;Yes - jump exit xra a call selda ;Select the default drive (A) and call restore ;drive the head to track 0. Unload call unload ;the heads and return to CP/M via jmp wboot ;a warm boot. Aloha! * * Step to next track * tkstep lda sdisk ;Get the source disk and save it mov b,a ;in B. Get desitination disk and see lda ddisk ;if they are the same. If so, do the cmp b ;samedrv routine. jz samedrv mvi a,'*' ;Write an asterisk to the console call pchar ;for each track processed. call takstep ;Step in to next track and back up one lda trkreg ;track to compensate for next series of dcr a ;operations. sta trkreg samedrv xra a ;Default to drive A call select ;and test for current drive- call takstep ;Step in one track in preparation jmp dloop ;for next track manipulation, and go. takstep lxi d,cmdreg ;Point to the command register and mvi a,sicmd ;perform a step-in command. Š stax d delay05 ldax d rar jnc delay05 delay06 ldax d rar jc delay06 ret * * Re-write error, track did not verify * Bump counter, then flag permanent error * rwerr lxi h,rwcnt ;Point to Track Verify Retry counter dcr m ;Decrement it lxi d,vmsg ;cr/lf'Diskette will not accept etc' * * Permanent error common routine * No error codes determined yet * Unload head, then abort * perr call pbuff ;Print the error message call unload ;Unload the heads lda trkreg ;Get current track number mvi l,'0'-1 ;Preset the l register per1 inr l ;This routine converts a binary byte sui 10 ;to its ASCII equivalent. It does it by jnc per1 ;bumping the L register the 10's digit adi '0'+10 ;number of times and converting the remainder mov h,a ;from binary to ASCII in the H register. The mov a,l ;two-digit ASCII result is stored in memory for cpi '0' ;further use. jnz per2 mvi l,' ' ;Suppress leading zero... per2 shld tdsply ;Save track number display lxi d,retmsg ;Prompt to press return jmp done ;Treat as if done * * Track read error - decrement counter and try again * terr lxi h,trcnt ;Get the number of times to try, tryi again dcr m ;and update it. Loop until all hope is gone. jnz dloop lxi d,tmessg ;'Track read error etc' jmp perr ;Continue error routine * Š* Wait until drive not busy * wnbusy lda cmdreg ;Get the controller status byte and test it ani 1 ;for BUSY... if it is indeed still doing its jnz wnbusy ;thing, loop until it finishes. ret ;No longer busy, here we go! * * Wait for index hole to go by * windex push b call gtindx ;Get proper polarity mask for model id. windxh call gtstat ;Load DJ disk status byte ani index ;and mask for index pulse. xra b ;Use proper polarity jz windxh ;and loop until index comes up. windxl call gtstat ;Index pulse present (high), play games until ani index ;it goes away (low). xra b jnz windxl windxc call gtstat ani index xra b jz windxc pop b ret * * Search up to (B) bytes at HL for pattern represented * by (C). Assumes upper 4 bits are 1s. Exit to TERR if * byte not found. * searc mov a,m ;Load a byte ori 0f0h ;Turn on upper nibble mov m,a ;Save in memory cmp c ;Match ? rz ;Yes - Return inx h ;Bump data pointer dcr b ;Hit byte search count jnz searc ;Loop til search complete pop psw ;Clear stack jmp terr ;Go to error routine * * Checksum checker * Adapted from the Disk Jockey I Shugart Firmware * Performs the Cyclic Redundancy Check (CRC) * The polynomial is G(X) = X^16 + X^12 + X^5 + 1. * * Entry SETCRC - Pointer to data block in HL, * Field length (in bytes) - 1 in D,E Š* Verify checksum at end of block * Return with Z set if match * *I haven't the faintest idea (yet) how this works. BUT I WILL FIND OUT. setcrc push h ;Save start address pointer xchg ;Flip start addr to DE dad d ;HL points to last byte xchg ;Swap back again crech lxi b,-1 ;Initial value per formula crechx push d ;Save terminating pointer mov a,m xra c mov d,a rrc rrc rrc rrc ani 0fh xra d mov e,a rrc rrc rrc mov d,a ani 1fh xra b mov c,a mov a,d ani 0e0h xra e mov b,a ;Update high order CRC word mov a,d rrc ani 0f0h xra c mov c,a ;Save low order CRC word inx h ;Bump pointer to next data byte pop d ;Restore terminating pointer mov a,d ;Get high order cmp h ;Test for done CRECH jc crec1 ;Done - Test CRC and set flags jnz crechx ;Continue - next data byte mov a,e ;Get low order and cmp l ; test terminating pointer jnc crechx ;Loop if more bytes to scan crec1 xchg ;Swap CRC word pointer to D,E pop h ;Restore data start address pointer ldax d ;Test low order cmp c ;Clear Z flag if no match Š inx d ;Next byte rnz ;Done if error ldax d ;High order cmp b ;Set flags and ret ;Return * * Select selects the disk specified by drive A and * loads the head * select mov b,a ;Save in B lda cdisk ;Get currently selected disk cmp b jz loadhd ;Load appropriate head. mov a,b ;Recover request sta cdisk ;Update selected drive ana a lda sdisk ;Assume source lxi d,mntsrc ;Mount source message jz sselec ;Source select ? lda ddisk ;Not source, destination lxi d,mntdst ;Mount destination message sselec push psw ;Save drive to select lda sdisk ;Get source drive mov b,a ;Save in B lda ddisk ;Get destination drive cmp b ;Same ? push psw ;Stack flags, and if the drives are the same, cz unload ;unload the heads. Then proceed to give out pop psw ;alternate mount-source, mount-destination push psw ;messages until done. This is intended for a cz pbuff ;single-drive system. Slow slow slow, work pop psw ;work work. cz conin ;Print string, and read console pop psw ;Recover drive to select selda mov c,a mvi a,7fh ;Drive select bits qloop rlc ;Rotate select bits dcr c ; to proper drive position jp qloop ani 3fh call stdvsl loadhd call model ;Load the heads, using appropriate masks for lxi b,lhsdena ;the different models of the DJ. jz selprep lxi b,lhsdenb selprep mov a,b ;Dump contents of the BC registers into the call stbits ;controller register of the 1791. Set drive, Š mov a,c ;density, and all those good things. jmp stbits * * Get index level * gtindx call model ;Establish polarity mask for use in other mvi b,0 ;routines, to allow for proper DJ model. rz mvi b,index ret * * Get disk Jockey 2D model * model lda diskio-4 ;Get the DJ Model id: cpi (ret) ;00 = Model A ret ;C9 = Model B * * Prompt the console for a drive, then read and verify the drive * selected * readdrv push d ;Save prompt call pbuff ;Send the prompt call rbuff ;Read the console character pop d ;Recover prompt jz exit sui 'A' ;Subtract ASCII bias jc readdrv ;Invalid input cpi 4 ;Upper limit jp readdrv ;Invalid input ret * * Pbuff is the CP/M print buffer function * pbuff mvi c,9 ;Standard BDOS call routine. jmp bdos pchar push h ;and so is this one. push b push d push psw mov e,a mvi c,2 call bdos pop psw pop d pop b pop h Š ret * * Rbuff is the CP/M read buffer function * prbuff call pbuff rbuff lxi d,inbuff mvi c,10 ;Standard read-the-buffer and/or input call bdos ;routine. lda inbuff+1 ana a rz lda inbuff+2 cpi 'a' rc cpi 'z'+1 rnc sui ' ' ret inbuff db 10,10 ds 10 conin mvi c,1 ;Standard input routine with Control-C call bdos ;intercept. ani 7fh cpi 3 jz finish ret stdvsl sta diskio+1 ;Set the drive to be used. ret stbits sta diskio+2 ;Set the standard things. ret gtstat lda diskio+2 ;Read the 1791 status byte. ret unload call model ;Just what it says. mvi a,unloada jz stbits mvi a,unloadb jmp stbits * * Messages and data * prompt db acr,alf db 'Format correction program, VERS ' Š DB (VERNUM/10)+'0','.',(VERNUM MOD 10)+'0' DB acr,alf,'by Design Technology, San Diego, CA$' srcmsg db acr,alf db 'Select source drive A,B,C, or D (RETURN to exit): $' dstmsg db acr,alf db 'Select destination drive A,B,C or D (RETURN to exit): $' mntmsg db acr,alf db 'Press RETURN to correct the format' db acr,alf,'on the above specified diskette: $' fmessg db acr,alf db 'Function Complete' db acr,alf db 'Type R to reformat another, RETURN to exit: $' wmessg db ' is Write Protected.$' rmessg db ' is Not Ready.$' amessg db acr,alf db 'Drive $' sglside db ' is not single sided.$' mntsrc db acr,alf db 'Insert source diskette, then press RETURN: $' mntdst db acr,alf db 'Insert destination diskette, then press RETURN: $' tmessg db acr,alf db 'Track read error' db acr,alf db 'Invalid CRC, Illegal Density, or' db acr,alf db 'Illegal track or sector sequence.$' retmsg db acr,alf db 'Error occured on Track: ' tdsply db ' .' db acr,alf db 'Type R to reformat another, RETURN to exit: $' vmsg db acr,alf db 'Diskette will not accept re-formatting.' db acr,alf db 'Permanent Verification Error and' db acr,alf db 'probable physical damage.$' acralf db acr,alf,'$' Š* * Data space * sdisk db 0ffh ddisk db 0ffh cdisk db 0ffh trcnt DS 1 ;Track read retry counter rwcnt DS 1 ;Re-write counter tkno DS 1 ;Track number secno DS 1 ;Sector number secix DS 2 ;Sector data pointer table pointer sectb ds 2*26 ;Space for sector address table ds 40 stack equ $ org (($+255)shr 8)shl 8 ;Must start on page tkbuf ds 1800H ;Lots of space for track buffer nbuf equ $-1 ;Last byte in track buffer storage area end