; ; REGEN.ASM vers 1.0 August 22, 1979 ; ; By Bryan G. Moore ; Design Technology ; 4888-H Ronson Court ; San Diego, CA 92111 ; ; 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. For complete infor- ; mation on the design and operation of this program, refer to ; the file "REGEN.DOC". ; ; Regardless of the CPU speed, this program requires about two ; minutes per diskette to execute. ; VERNUM EQU 10 ;Version number * 10 EXIDY EQU 0 ;0 = Standard, -1 = EXIDY IF EXIDY ;Test EXIDY flag origin equ 0d000h else origin equ 0E000H ENDIF ;End conditional org origin ; ; Disk Jockey 2D Port addresses and key memory locations ; The "$" represents the ORIGIN address. ; model equ $+3f4h ;Byte distinguishing model A from model B DCREG EQU $+3F9H ;Drive Command register DRVREG EQU $+3FAH ;Drive select register CMDREG EQU $+3FCH ;Controller Command register TRKREG EQU $+3FDH ;Controller Track register SECREG EQU $+3FEH ;Controller Sector register DATREG EQU $+3FFH ;Data register DSTAT EQU DCREG ;Drive status register STATUS EQU CMDREG ;Controller Status register CDISK EQU $+6F4H ;Current selected disk USTAT EQU $+21H ;Address of Uart status routine ; ; Disk Jockey 2D Command Port values ; SDHDLD EQU 1 ;Single Density "Head Load" UNLOAD EQU 30Q ;Unload head command RESTOR EQU 11Q ;Home to track 0 command SICMD EQU 131Q ;Step IN command (Update Track register) RSEC EQU 200Q ;Read single Sector command WSEC EQU 240Q ;Write single Sector command RTCMD EQU 344Q ;Read track command WTCMD EQU 364Q ;Write track command IMMIRQ EQU 320Q ;Wait state release control ; ; Controller sense bits ; INDEX EQU 20Q ;Index mark READY EQU 40Q ;Drive ready sense TRKZRO EQU 4 ;Track 0 sensor WPROT EQU 100Q ;Write protected ; ; ASCII Characters used ; CR EQU 15Q ;Carriage return LF EQU 12Q ;Line feed CTLC EQU 3 ;Abort character ; ORG 100H ;CP/M version JMP BEGIN ;Skip Console interactives ; ; System - dependent subroutines ; The current versions below are for the CP/M operating ; system. ; ; SENDM prints a buffer starting at H,L and terminated by a ; dollar sign (24 Hex). ; ; CONIN Fetches a console character in the accumulator and ; echoes it to the console output. ; BDOS EQU 0005H ;CP/M entry point REBOOT EQU 0 ;Warm start entry point ; SENDM MVI C,9 ;CP/M Buffer Print function XCHG ;Place the pointer JMP BDOS ;Print and return later ; CONIN MVI C,1 ;CP/M Fetch console character CALL BDOS ; and echo it to console CPI 'A'+' ' ;Test for lower case RC ;Done if not CPI 'Z'+' '+1 ;Upper limit RNC ;Done if not lower case SUI ' ' ;Else convert to upper case RET ;Return ; BEGIN LXI SP,STACK ;Stack pointer LHLD USTAT+1 ;Get address of 2D Uart status routine INX H ;Bump to load address MOV A,M STA L01+1 ;Self modify the rest of the program XRI 3 ; to work with Disk Jockey 2D STA L02+1 ; Revision 0,1,2 (not released),3,4 STA L03+1 STA L04+1 STA L05+1 STA L06+1 STA L07+1 STA L08+1 LXI H,PROMPT ;Sign-on CALL SENDM ;To console ; ; Formatting loop - Get desired destination disk drive ; Loop to START unless all parameters are valid ; START LXI SP,STACK ;Stack pointer lda model cpi (ret) jz modok lxi h,badmod call sendm jmp 0 badmod db 0dh,0ah db 'Bad Model Disk Jockey 2D, This Regen Program Only' db ' Works With Model A.$' modok LXI H,DMESSG ;Prompt the user to select CALL SENDM ; the destination drive CALL CONIN ;Read the console character CPI CTLC ;Abort ? JZ REBOOT ;Yes - reboot system SUI 'A' ;Subtract ASCII bias JC START ;Invalid input CPI 4 ;Upper limit JP START ;Invalid input STA CDISK ;Save the drive name for later LXI H,SMESSG ;Prompt the user to CALL SENDM ; mount the diskette CALL CONIN ;Read console CPI CR ;Was it a carriage return ? JZ REGEN ;Yes - jump CPI CTLC ;Abort character ? JZ 0 ;Yes - reboot system JMP START ;Ignore anything else ; REGEN LDA CDISK ;Get selected disk MOV C,A ;Save in C register MVI A,177Q ;Set all but MSB QLOOP RLC ;Shift from LSB to MSB DCR C ;Loop until bit pattern formed JP QLOOP ; for the drive select register L01 EQU $ STA DRVREG ;Select drive MVI A,SDHDLD ;Single density L02 EQU $ STA DCREG ;Load head MVI A,IMMIRQ ;Reset "Interrupt" control STA CMDREG ;Clear any commands in progress LXI D,0 ;Wait for index hole L05 EQU $ IXLOOP LDA DSTAT ;Load drive status ANI INDEX ;Extract index hole JZ IXGOOD ;Exit if hole found DCX D ;Hit timer MOV A,D ; and test ORA E ; for 0 JNZ IXLOOP ;Loop if more time to go NOTRDY LXI H,NMESSG ;Assume drive not ready CALL SENDM JMP START ;Start over ; L06 EQU $ IXGOOD LDA DSTAT ;Load drive status ANI READY ;Extract drive ready JNZ NOTRDY ;Exit if not MVI A,RESTOR ;Home to track 0 command STA CMDREG ;Restore and re-calibrate drive WTKZRO LDA STATUS ;Load drive status ANI TRKZRO ;Extract track 0 sensor JZ WTKZRO ;Loop until home LDA STATUS ;Load diskette status register ANI WPROT ;Extract write protected status LXI H,WMESSG ;Write protected message JNZ NOTRDY+3 ;Jump if diskette is protected LXI H,PMESSG ;Inform operator that the CALL SENDM ; reformatting is in progress XRA A ;Initialize track number STA TKNO ;Start with track 0 MVI A,10 ;Reset read retry STA TRCNT ; counter to 10 DLOOP: CALL WNBUSY ;Wait until not busy LXI D,DATREG ;Pointer acts as Data Register LXI H,TKBUF ;Track buffer MVI C,24 ;C is page count MVI A,RTCMD ;Read Track command STA CMDREG ;Setup controller 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 ; ; Scan track for Sector Address Mark (FE Hex) ; Since this value is not always read properly using the Read ; Track command, this search assumes the high four bits of the ; Sector Address Mark are ones. ; LXI H,SECTB ;Initialize sector data pointer table SHLD SECIX ; to first sector LXI H,TKBUF ;Initial Track buffer pointer MVI A,1 ;Initial sector number (1) STA SECNO ;Save sector number SLOOP: LXI B,0FEH ;Give up after 256 bytes CALL SEARC ;Search for Sector Address mark LXI D,4 ;Field byte count CALL SETCRC ;Evaluate CRC status INX H ;Offset to track number JNZ SLOOP ;Error - Continue Sector mark search LDA TKNO ;Get current track CMP M ;Compare with memory image JNZ TERR ;Illegal track number INX H ;Next byte must be 0 MOV A,M ;Is it a zero ? ORA A JNZ TERR ;No - jump INX H ;Sector number LDA SECNO ;Get current sector number CMP M ;Correct sector ? JNZ TERR ;No - jump INX H ;Next byte MOV A,M ; must also be ORA A ; a zero JNZ TERR ;Not a zero - jump INX H ;Skip CRC word INX H SC1: LXI B,0FBH ;Search pattern and retry CALL SEARC ;Search for mark LXI D,128 ;Sector length (including Data Mark) CALL SETCRC ;Get the CRC status INX H ;Offset pointer to data JNZ SC1 ;Error - continue search PUSH D ;Save pointer to last CRC byte XCHG ;Flip Data address into D,E LHLD SECIX ;Get sector pointer index MOV M,E ;Store the INX H ; new sector MOV M,D ; data address INX H ;Point to next address storage SHLD SECIX ;Save sector index POP D ;Restore pointer to last CRC byte INX D ;Bump to next raw data byte LXI H,SECNO ;Point to the sector number INR M ; and bump to next sector MOV A,M ;Get this number XCHG ;Flip data pointer back to HL CPI 27 ;More sectors to go ? JC SLOOP ;Yes - jump LHLD SECIX ;Get sector data address index DCX H ;To last high order MOV D,M DCX H ;Low order MOV E,M ;Load the start address LXI H,130 ;Sector length + CRC word DAD D ;Compute last address used LXI D,-NBUF ;Negative of last track buffer address DAD D ;Is sector data address out of bounds ? JC TERR ;Yes - jump MVI A,10 ;Reset some counters STA TRCNT ;Reset track read error counter STA RWCNT ;Reset the Re-Write counter CALL WNBUSY ;Wait for controller ready REWRT: CALL TRACK ;Write the IBM 3740 format to the disk LXI H,SECTB ;Point to Sector Data address table SHLD SECIX ;Initialize index value MVI A,1 ;Initialize sector number STA SECNO TWLOOP: CALL WNBUSY ;Wait for Controller Ready LDA SECNO ;Fetch sector number STA SECREG ;Send to controller LHLD SECIX ;Get sector address index MOV E,M ;Load the next dma address INX H MOV D,M ;High order INX H SHLD SECIX ;Save for next loop LXI H,DATREG;Controller data register MVI A,WSEC ;Write Sector command STA CMDREG ;Start controller MVI C,128 ;Bytes in a sector WLOOP: LDAX D ;Get source byte from memory MOV M,A ;Write the data to the controller INX D ;Next data byte DCR C ;Hit data byte count JNZ WLOOP ;Loop until data written LXI H,SECNO ;Point to the sector number INR M ;Increment to next MOV A,M ;Load the value CPI 27 ;More sectors to write ? JC TWLOOP ;Yes - jump ; ; Read the track back. Ignore the data, but verify the CRC ; status from the Disk Jockey 1791. ; CALL WNBUSY ;Wait until not busy CALL WINDEX ;Wait for index hole LXI H,DATREG ;Data register pointer MVI A,1 ;Initialize the RTL1: STA SECREG ; sector number MVI C,128 ;Bytes in a sector MVI A,RSEC ;Read Sector command STA CMDREG ;Start controller RTLOOP: MOV A,M ;Read a byte DCR C ;Done this sector ? JNZ RTLOOP ;No - Loop until sector is read CALL WNBUSY ;Wait until not busy LDA STATUS ;Load controller status ANI 9CH ;Extract Not Ready, Not Found, ; CRC Error, Lost Data JNZ RWERR ;Go re-write if error LDA SECREG ;Load sector register INR A ;Next sector CPI 27 ;More sectors to do ? JC RTL1 ;Yes - Loop 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 MVI A,UNLOAD ;Unload the head using the L03 STA DCREG ; Drive Command register DONE: LXI H,FMESSG ;Send completion CALL SENDM ; message to console CALL CONIN ;Get a character CPI 'B' ;Re-boot ? JZ REBOOT ;Yes - jump CPI 'R' ;More Re-formatting ? JZ START ;Yes - jump JMP DONE ;Ignore anything else ; ; Step to next track ; TKSTEP MVI A,SICMD ;Step in 1 track STA CMDREG WBUSY LDA STATUS ;Wait for controller to acknowledge ANI 1 ;Test BUSY status JZ WBUSY ;Loop until it acknowledged CALL WNBUSY ;Wait until controller not busy JMP DLOOP ;Go do the next track ; ; 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 JNZ REWRT ;Go re-write if not expired LXI H,VMSG ;Permanent verify error ; ; Permanent error common routine ; No error codes determined yet ; Unload head, then abort ; PERR: CALL SENDM ;Print the error message MVI A,UNLOAD ;Let the head go L04 STA DCREG ;Drive Control register LDA TRKREG ;Get current track number MVI L,'0'-1 ;L is one less than 0 PER1: INR L ;Bump digit value SUI 10 ;Hit tens digit count JNC PER1 ;Loop til C = ASCII tens digit ADI '0'+10 ;Restore + ASCII bias for units MOV H,A ;Place units digit MOV A,L ;Get the tens digit CPI '0' ;Is it an ASCII 0 ? JNZ PER2 ;No - use it MVI L,' ' ;Else make it a space PER2: SHLD TDSPLY ;Save track number display LXI H,RETMSG ;Prompt to press return JMP DONE+3 ;Treat as if done ; ; Track read error - decrement counter and try again ; TERR: LXI H,TRCNT ;Point to the track read counter DCR M ;Have we tried too many times ? JNZ DLOOP ;No - try again LXI H,TMESSG ;Track read message JMP PERR ;Continue error routine ; ; Format track in single density ; Writes in 1791 compatible IBM 3740 format ; 26 consecutive sectors per track, 128 byte sectors ; 77 tracks ; TRACK LXI H,DATREG ;HL is pointer to data register LDA TKNO ;Get track number MOV D,A ;Copy to D register MVI E,1 ;Sector counter MVI A,WTCMD ;Send the Write Track STA CMDREG ; command to the controller LXI B,0FF28H ;Write 40 leading FF's SILP1 MOV M,B ;Write a value DCR C ;Hit the counter JNZ SILP1 ;Loop until bytes written LXI B,6 ;Write 6 leading 0's SILP2 MOV M,B DCR C JNZ SILP2 MVI M,0FCH ;Track Index mark LXI B,0FF1AH ;Write 26 FF's SILP3 MOV M,B DCR C JNZ SILP3 ; ; Sector Loop - writes 6 leading zeroes, sector header mark, ; track number, zero, sector number, 0 (single density), ; sector header checksum, 11 FF's (spacing), 6 zeroes, sector ; data mark, 128 E5's (IBM format), sector data checksum, ; and 27 FF's of sector trailer. ; SLOOPS LXI B,6 ;6 leading zeroes before sector mark SILP4 MOV M,B DCR C JNZ SILP4 MVI M,0FEH ;Sector Header mark MOV M,D ;Write track number MVI M,0 ;Space with 0 MOV M,E ;Write sector number MVI M,0 ;Write 0 for Single Density MVI M,0F7H ;Command to write checksum INR E ;Bump sector counter LXI B,0FF0BH ;Write 11 FF's SILP5 MOV M,B DCR C JNZ SILP5 LXI B,6 ;6 leading zeroes before data mark SILP6 MOV M,B DCR C JNZ SILP6 MVI M,0FBH ;Data mark LXI B,0E520H ;Write the IBM format data SILP7 MOV M,B DCR C JNZ SILP7 MVI C,20H ;32 more bytes SILP8 MOV M,B DCR C JNZ SILP8 MVI C,20H ;32 more bytes SILP9 MOV M,B DCR C JNZ SILP9 MVI C,20H ;32 more bytes SILPA MOV M,B DCR C JNZ SILPA MVI M,0F7H ;Command to write checksum MVI A,27 ;Load accumulator for later LXI B,0FF1BH ;Write 27 trailing FF's SILPB MOV M,B DCR C JNZ SILPB CMP E ;Done this track ? JNZ SLOOPS ;No - loop ; ; End sector loop ; SILPC MOV M,B ;Write lots more FF's DCR C JNZ SILPC SILPD MOV M,B ;More FF's DCR C JNZ SILPD SILPE MOV M,B ;More FF's DCR C JNZ SILPE RET ;Return ; ; Wait until drive not busy ; WNBUSY LDA CMDREG ;Wait for controller to accomplish ANI 1 JNZ WNBUSY ;Loop until it does RET ;Return when Ready ; ; Wait for index hole to go by ; L07 EQU $ WINDEX LDA DSTAT ;Get disk status ANI INDEX ;Extract index hole JNZ WINDEX ; and wait for it L08 EQU $ WIXHI LDA DSTAT ;Load disk status ANI INDEX ;Extract index hole JZ WIXHI ;Wait for it to go away RET ;Return ; ; 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 ; 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 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 CRECH+3 ;Continue - next data byte MOV A,E ;Get low order and CMP L ; test terminating pointer JNC CRECH+3 ;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 ; ; Messages and data ; PROMPT DB CR,LF,'Format correction program, VERS ' DB (VERNUM/10)+'0','.',(VERNUM MOD 10)+'0' DB CR,LF,'by Design Technology, San Diego, CA$' DMESSG DB CR,LF,LF,'Select Drive A,B,C, OR D: $' SMESSG DB CR,LF,'Press RETURN to correct the format' DB CR,LF,'on the above specified diskette: $' FMESSG DB CR,LF,'Function Complete',CR,LF DB 'Type B for BOOT or R for Reformat: $' WMESSG DB CR,LF,'Diskette is Write Protected$' NMESSG DB CR,LF,'Drive not ready$' PMESSG: DB CR,LF,'Reformatting in progress',CR,LF,'$' TMESSG DB CR,LF,'Track read error' DB CR,LF,'Invalid CRC, Illegal Density, or' DB CR,LF,'Illegal track or sector sequence$' VMSG: DB CR,LF,'Diskette will not accept re-formatting' DB CR,LF,'Permanent Verification Error and' DB CR,LF,'probable physical damage$' RETMSG: DB CR,LF,'Error occured on Track: ' TDSPLY: DB ' .' DB CR,LF,'Press RETURN$' ; ; Data space ; 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 BEGIN