**=====================================================** * * * "DUTIL" DISK UTILITY * * Version 2.22 25 October 1983 * * BB-II 5"/8" SD/DD:512 DMA version * * EPROM/RAM Version * * * **=====================================================** TRUE equ 0FFFFH FALSE equ 0 EPROM equ false ;EPROM or CPM version IF EPROM ROM equ 01000H RUN equ 0D600H BUF equ 00100H org RUN cpi '/' ;make this position rnz ; independent lxi h,ROM lxi d,RUN lxi b,01000H db 0EDH,0B0H ENDIF IF NOT EPROM org 0100H BUF equ 01200H ENDIF jmp START ;*------------------------------------------------------* ;* DISK TYPE CONFIGURATION * ;*------------------------------------------------------* FIVE equ true ;0=8" 0FFFFH=5" NSTART equ 5 ;revs til ready IF FIVE SPEED equ 12 ;Step speed FSPEED equ 1 ;FDÃ 0=6ms,1=12ms,2=20ms,3=30ms NTRKS equ 80 ;Number of tracks both sides DOUBLE equ 0 ;double sided:0=false,1=true WHACK equ 10 ;copy tracks SPTSD equ 18 ;sectors/track single SPTDD equ 10 ;sectors/track double DTYPSD equ 2 ;DSKTYP 5" SD DTYPDD equ 3 ; DD SGAP0: equ 0 ;gap0: pre-index SGAP1: equ 32 ;gap1: post-index SGAP2: equ 11 ;gap2: id SGAP3: equ 6 ;gap3: post-data DGAP0: equ 0 ;gap0: pre-index DGAP1: equ 32 ;gap1: post-index DGAP2: equ 24 ;gap2: id DGAP3: equ 22 ;gap3: post-data ILDD: db 1,6,2,7,3,8,4,9,5,10 ILSD: db 1,10,2,11,3,12,4,13,5,14,6,15,7,16,8,17,9,18 ENDIF IF NOT FIVE SPEED equ 8 ;ROM step speed FSPEED equ 2 ;FDÃ 0=3ms,1=6ms,2=10ms,3=15ms DOUBLE equ 0 ;double sided 0=false 1=true NTRKS equ 40*(DOUBLE+1) ;Number of tracks both sides WHACK equ 6 ;copy tracks SPTSD equ 26 ;sectors/track single SPTDD equ 16 ;sectors/track double DTYPSD equ 0 ;DSKTYP 8" SD DTYPDD equ 1 ; DD SGAP0: equ 40 ;gap0: pre-index SGAP1: equ 26 ;gap1: post-index SGAP2: equ 11 ;gap2: id SGAP3: equ 27 ;gap3: post-data DGAP0: equ 0 ;gap0: pre-index DGAP1: equ 50 ;gap1: post-index DGAP2: equ 22 ;gap2: id DGAP3: equ 54 ;gap3: post-data ILDD: db 1,9,2,10,3,11,4,12,5,13,6,14,7,15,8,16 ILSD: db 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 db 19,20,21,22,23,24,25,26 ENDIF SBYTES equ 128 ;bytes/sector single SDSTYP equ 0 ;sector type 128 bytes DBYTES equ 512 ;bytes/sector double DDSTYP equ 2 ; 512 bytes ;*------------------------------------------------------* ;* INITIALIZATION AND MAIN PROGRAM LOOP * ;*------------------------------------------------------* START: mvi a,008H ;enable sta 0FF70H ; RAM and out 0C8h ; DSCOPY mvi a,SPEED ;Set sta 0FF90H ; step speed mvi a,NSTART ;Set sta 0FF95H ; NREVS lxi sp,STACK ;init stack pointer xra a sta UNIT sta TRK cma sta SELUNIT ; for new unit and new track sta DDFLG ;init for double lxi h,HLMSG ;print call PTXT ; help menu ; Main program loop DUTIL: lxi sp,STACK ;re init sp mvi a,2 ;set track to track sta SKEWF ; skew factor xra a sta PASCNT mvi a,0FFH sta OLDTRK call HOME ;home drive each time call CRLF ;newline DUTI1: mvi c,'A' ;print prompt lda UNIT cpi 0 jz DUTI2 mvi c,'B' DUTI2: call CONOUT mvi c,':' ; and density lda DDFLG ; ':' for DD ora a ; '.' for SD jnz DUTI3 mvi c,'.' DUTI3: call CONOUT mvi c,'>' call CONOUT call GCHAR ;get command letter cpi 0DH ; do nothing if jz DUTI1 call DUTIL0 ;go decode jmp DUTIL ; and loop ; Input or Command error INERR: lxi H,INEMSG call PTXT jmp DUTIL INEMSG db 7,' ?? ',0DH,0AH,3 ; Decode command and jump to routine DUTIL0: cpi 'Q' ;'Q' Sequential commands jnz DECOD3 ; no, skip lxi h,SQMSG ; yes, print call PTXT ; 'Sequential' call GCHAR cpi 'W' ;'SW'? jnz DECOD1 ; no, skip lxi H,WRMSG ; yes, complete call ACCEPT ; command jmp DQW ; and jump to routine DECOD1 cpi 'R' ;random? jnz INERR ; no, skip lxi H,RDMSG ; yes, accept call ACCEPT jmp DQR DECOD3 cpi 'R' ;'RR' read read ? jnz DECOD5 ; no, skip lxi H,RAMSG ; yes, complete command call PTXT call GCHAR ;get next cpi 'W' ; write? jnz DECOD4 ; no, skip lxi H,WRMSG ; yes, complete command call ACCEPT jmp DRW DECOD4 cpi 'R' ;read? jnz INERR ; no, error lxi H,RDMSG ; yes, complete call ACCEPT jmp DRR SQMSG db 8,'Sequential ',3 RAMSG db 'andom ',3 RDMSG db 'ead',3 WRMSG db 'rite/Readback',3 DECOD5: cpi 'A' jz SUNITA cpi 'B' jz SUNITB cpi 'C' jz COPY ;COPY DISK cpi 'V' jz VCOPY ;Verify copy cpi 'D' jz DUMP ;DUMP SECTOR cpi 'Z' jz TSTSK ;SEEK cpi 'F' jz FORMAT ;FORMAT TRACK cpi 'T' jz RTRK ;FORMAT READ cpi 'L' jz LOAD ;LOAD (READ) FROM DISK cpi 'S' jz SAVE ;SAVE (WRITE) TO DISK cpi 'P' jz PATCH ;PATCH SECTOR cpi '?' jz HELP ;HELP LIST cpi 'M' jz MODE ;change density cpi 'X' jz EXIT ;exit to system jmp INERR ;*------------------------------------------------------* ;* COMMANDS * ;*------------------------------------------------------* ******************* * COPY A DISKETTE * ******************* VCOPY: mvi a,0FFH ;set verify sta VFLAG ; flag lxi H,VCOPMSG ;command completion jmp COPY0 COPY: xra a ;clear sta VFLAG ; flag lxi H,COPMSG ;command COPY0: call ACCEPT ; completion xra a ;set sta TRK ; TRK = 0 mvi a,4 sta SKEWF call FDRAW lxi H,SPTSD+SPTDD*(NTRKS-1) lda DDFLG ora a jnz COPY00 lxi H,NTRKS*SPTSD COPY00: shld SECREM ;sectors to be copied lxi H,SPTSD ;just 1 SD track shld SECINC ; first time jmp COPY2 ; through COPY1: lda TRK ; and then cpi 1 ; for DD jnz COPY2 lxi H,SPTDD*WHACK ; tracks per read/write lda DDFLG ora a jnz COPY10 lxi H,SPTSD*WHACK COPY10: shld SECINC COPY2: lhld SECREM ;test for number of sectors mov A,H ; remaining equal to zero ora L ; or h=l=0 jz COPYR ; done xchg ;put in de lhld SECINC ; load sectors remaining in hl xchg ;now calculate mov A,L ;SECREM=SECREM-SECINC sub E ; do 16bit mov L,A ; subtraction mov A,H sbb D mov H,A jnc COPY3 ;if result .GE. 0, update SECREM lhld SECREM ; else this will be last time and shld SECINC ; SECINC = SECREM lxi H,0 ;set SECREM = 0 no more left COPY3: shld SECREM ; Read from Drive A: xra A ;set unit sta UNIT lda TRK ;set track sta CTRK call CSETUP ;setup COPY4: call DDOTS ;print dots call READP ;read physical sector jnz ERROR call ISKEWA ;increment skew address call DCREC ;decrement record count jnz COPY4 ; Write to Drive B: mvi a,1 ;set unit sta UNIT lda CTRK ;set track sta TRK call CSETUP COPY5: call WRITP ;write physical jnz ERROR call ISKEWA ;increment skew address call DCREC ;decrement record count jnz COPY5 ; Verify tracks lda VFLAG ora A jz COPY1 lda CTRK ;SET sta TRK ; TRACK call CSETUP COPY6: call READP ;READ JUST WRITTEN jnz ERROR ; ERROR? call ISKEWA call DCREC jnz COPY6 jmp COPY1 ;NO, CONTINUE COPYR: xra A sta UNIT ret ; Setup for Copy: set sector, skew, dma addr and # records CSETUP: mvi a,1 ;each operation sta SCTR ; starts with sector 1 sta SKEW lxi H,BFFR1 ;set buffer shld TADDR ; address lhld SECINC ;set number of sectors shld CREC ; (records) in CREC ret ; Increment skewed disk address ISKEWA: lda NSCTP1 ;get SPT plus 1 mov B,A ; into B lda SCTR ;get sector inr A ; incrment cmp B ; and test with B jnz ISKEW0 ;skip if not end of track mvi A,1 ; else, new track ISKEW0 sta SCTR lxi H,SKEW ;test for end of cmp M ; skewed track stc ;set carry if not end rnz ; exit lda SKEW ;else calculate new lxi H,SKEWF ; skewed end by adding in add M ; track skew factor cmp B ;modulo NSP jc ISKEW2 ;skip if not over dcr B ;subtrac off sub B ; NSP ISKEW2: sta SKEW ;update sta SCTR ; for new track lxi H,TRK ;incrment for inr M ; next track mvi A,NTRKS ;test for end cmp M ; of disk stc ; and set carry if not rnz cmc ;clear carry to indicate ret ; last track ; Decrement sector (record) count DCREC: lhld TADDR ;increment xchg ; dma lhld NBYTES ; address dad D shld TADDR lhld CREC ;decrement dcx H ; record count shld CREC mov A,H ora L ret COPMSG db 'opy entire disk from A: to B:',3 VCOPMSG db 008H,'Copy and verify entire disk from A: to B:',3 ***************** * DUMP A SECTOR * ***************** DUMP: lxi H,DUMSG ;COMPLETE CMD call ACCEPT ; AND ACCEPT lxi H,BFFR1 ;SET BUFFER #1 shld TADDR ; FOR TaddDR lxi H,TSMSG ;GET TRACK/SECTOR call PTXT ; PROMPT call IHEXN ;GET VALUES mov a,h sta TRK mov a,l sta SCTR DUMP0: call READ ;READ THE SECTOR jnz ERROR ; ERROR? * DUMP1 lhld TADDR ;SET HL call DBFFR ;DUMP BFFR lxi h,DNMSG ;NEXT? call PTXT ; PROMPT call CONIN ; GET RESPONSE cpi ' ' ; IF SPACE jz DUMP2 ; YES, ELSE NO call CRLF ret DUMP2: lxi h,DTMSG ;PRINT THIS call PTXT lda NSCTP1 mov b,a lda SCTR ;INCR DISK addR inr a ; SECTOR sta SCTR ; AND cmp b ; TEST END OF TRACK jnz DUMP5 mvi A,1 ;YES, RESET sta SCTR ; UPDATE lda TRK ; AND INCR cpi NTRKS-1 ; TRACK, END? jz INERR ; YES, ERROR inr A ; NO, INCR sta TRK ; UPDATE DUMP5 lda TRK ;GET TRACK call PACC ; PRINT lda SCTR ;GET SECTOR call PACC ; AND PRINT call CRLF ;SPACE A LINE jmp DUMP0 ; AND CONTINUE ; Dump Buffer DBFFR: push h xra a sta DLCNTR lxi h,0 shld DCNTR ; Print Address for each line printed DBFFR0: lhld DCNTR ;this is the mov a,h ; relative address push h call PACC pop h mov a,l call PACC mvi c,':' call CONOUT call SPACES ; Print hex values first DBFFR1: pop h ;GET POINTER mov a,m ; INTO BUFFER inx h ;INCR push h ; AND SAVE call PACC ;PRINT ONE VALUE mvi c,' ' ; AND ONE call CONOUT ; SPACE lhld DCNTR inx h shld DCNTR mov a,l ani 00FH ;TEST FOR EOL? jnz DBFFR1 ; NO, CONTINUE ; Print ASCII values next call SPACES ;SPACE OVER A LITTLE lxi D,-16 ;BACK UP BUFFER pop H ;POINTER DAD D ; TO BEGIN OF LINE push H ; AND SAVE lhld DCNTR lxi d,-16 dad d shld DCNTR DBFFR2 pop H ;GET POINTER mov A,M ; AND THE CHAR inx H ;INC POINTER push H ; AND SAVE ani 07FH ;MASK TO PRINT mov C,A ; SAVE IN C cpi 07FH ;TEST PRINTABLE jz DBFFR3 ; NO, USE '.' cpi ' ' ;TEST PRINTABLE jnc DBFFR4 ; YES, SKIP DBFFR3 mvi C,'.' ; NO, USE '.' DBFFR4 call CONOUT ;PRINT CHAR lhld DCNTR inx h shld DCNTR mov a,l ani 00FH ;TEST FOR jnz DBFFR2 ; EOL, NO CONTINUE ; Pause after half sector call CRLF call BREAK lxi H,DLCNTR inr M mvi A,21 cmp M jnz DBFFR5 mvi M,0 call CONIN cpi ' ' jnz DUTIL ; test for end DBFFR5: lhld DCNTR xchg lhld NBYTES mov a,h cmp d jnz DBFFR0 ;CONTINUE mov a,l cmp e jnz DBFFR0 DBFFR6: call CRLF ; ELSE pop H ;STRIP OFF ret ; AND EXIT DTMSG db ' Track/Sector: ',3 DNMSG db ' Next?',3 DUMSG db 'ump Sector',3 ************************************ * SEQUENTIAL AND RANDOM READ/WRITE * ************************************ ; Sequential read DQR call FDRAW DQR0: call ZADDR ;SET TTSS=0001 DQR1 call DDOTS ;dots and console break call DREAD call ISKEWA ;increment disk address jc DQR1 ; and loop call DPMSG ;print pass message jmp DQR0 ; Sequential write/readback DQW: call FDRAW mvi a,4 sta SKEWF DQW0: call ZADDR call RDATA DQW1: call DDOTS lhld DQCNT shld BFFR1 inx h shld DQCNT shld BFFR1 call DWRITE ;write to disk call ISKEWA jc DQW1 call CRLF call ZADDR DQW2: call DDOTS call DREAD ;read into other lhld DQCNT inx h shld DQCNT xchg lhld BFFR2 mov a,h cmp d jnz DQW3 mov a,l cmp e jz DQW4 DQW3: call ERROR DQW4: call ISKEWA ;increment address jc DQW2 call DPMSG jmp DQW0 ; Random Read DRR: call RADDR ;random address call DREAD ;READ call BREAK jmp DRR ; Randon Write/readback DRW: call RADDR ;get random address call RDATA ;RANDOM DATA call DWRITE ;WRITE call DREAD ;READBACK jnz DRW0 call COMPR ;COMPARE DRW0: call BREAK jmp DRW ; Zero disk address ZADDR: lxi h,0 shld DQCNT xra a ;start at 0,1,1 sta TRK mvi A,1 sta SCTR sta SKEW ret ; Read from disk into buffer2 DREAD: lxi H,BFFR2 shld TADDR call READP push psw cnz ERROR pop psw ret ; Write to disk from buffer1 DWRITE: lxi H,BFFR1 shld TADDR call WRITP push psw cnz ERROR pop psw ret ; Print '+++' for each new track DDOTS: call BREAK lda TRK lxi h,OLDTRK cmp m rz mov M,A IF DOUBLE lda TRK cpi NTRKS/2 cz CRLF ENDIF mvi c,'+' call CONOUT ret ; Print ' Pass ' message DPMSG: lxi h,PSMSG call PTXT lda PASCNT inr a sta PASCNT call PACC mvi c,' ' call CONOUT call CRLF ret PSMSG: db 0DH,'++ Pass ',3 ; Compare buffers COMPR: lhld NBYTES mov B,H mov C,L lxi H,BFFR1 ;HL=PTR1 lxi D,BFFR2 ;DE=PTR2 CMPR1: ldax D ;FETCH cmp M ;COMPARE jz CMPR2 ;ERROR IF MISMATCH mvi A,0FFH ;SPECIAL CODE call ERROR CMPR2: inx H ;INCR inx D ; PTRS dcx B ;dcr COUNTER mov A,B ora C jnz CMPR1 ret ; Fill buffers with random data pattern RDATA: lxi B,DBYTES lxi D,BFFR1 RDATA0: mov A,C stax D inx D dcx B mov A,B ora C jnz RDATA0 ret ; Generate random disk address RADDR: mvi A,NTRKS ;max track number mov B,A db 0EDH,05FH ;LDAR ani 07FH ;0-127 sta TRK cmp B jnc RADDR ;try again if too big RADDR1: lda TRK ;compare random mvi b,SPTSD+1 ; sector to approriate cpi 0 ; NSPT for SD or DD jz RADDR2 lda DDFLG ora a jz RADDR2 mvi b,SPTDD+1 RADDR2: db 0EDH,05FH ;LDAR ani 01FH ;0-31 ora A jz RADDR sta SCTR cmp B jnc RADDR2 ;if sector too big ret db 0EDH,05FH ;LDAR ************* * TEST SEEK * ************* TSTSK: lxi h,SKMSG ;Command call ACCEPT ; completion TSTSK0: call HOME ;Home first jnz ERROR IF NOT DOUBLE mvi a,NTRKS-1 ENDIF IF DOUBLE mvi a,NTRKS/2-1 ENDIF sta TRK ; last track side 0 call SEEKN jnz ERROR call BREAK jmp TSTSK0 SKMSG DB 08H,'Test Seek',3 ************************** * LOAD/SAVE TO/FROM DISK * ************************** LOAD: lxi H,LDMSG call ACCEPT lxi H,L1MSG call SPARMS LOADER: call READ jnz ERROR call INCP jnz LOADER ret SAVE: lxi H,SVMSG call ACCEPT lxi H,L1MSG call SPARMS SAVER: call WRITE jnz ERROR call INCP jnz SAVER ret LDMSG db 'oad (read) from disk',3 L1MSG db ' memory address (MMMM):',3 SVMSG DB 'ave (write) to disk',3 ; Scan for input parameters SPARMS: call PTXT ;print load or save msg call IHEXN ;get transfer address shld TADDR lxi H,TSMSG ;Request track call PTXT ; and sector call IHEXN mov A,H sta TRK mov A,L sta SCTR lxi H,SZMSG ;Request number call PTXT ; of sectors call IHEXN ; and mov A,L ; store sta NREC ; in 'NREC' ret TSMSG DB ' Enter track/sector (TTSS): ',03 SZMSG DB ' Enter number of sectors (NN):',03 ; Increment Sector and Track for sequential load/save INCP: lhld TADDR ;increment DMA address xchg lhld NBYTES dad d shld TADDR lxi H,NREC ;decrement record count dcr M RZ lxi H,SCTR ;increment sectotr inr M ; and wrap around to lda NSCTP1 ; next track cmp M rnz mvi M,1 lxi H,TRK inr M ret **************** * PATCH SECTOR * **************** PATCH: lxi H,PTMSG call ACCEPT lxi H,TSMSG ;Prompt for track/sector call PTXT call IHEXN mov a,h sta TRK mov a,l sta SCTR lxi H,BFFR2 shld TADDR call READ ;read into BFFR2 PATCH1: call CRLF call CRLF ;print sector lxi H,BFFR2 call DBFFR PATCH2: lxi H,PAMSG ;address call PTXT call SCAN jz PATC22 PATC21: mvi c,7 call conout jmp PATCH2 ;error try again PATC22: mov A,B ;test for only cr cpi 1 jz PATCH4 push h xchg lhld NBYTES xchg ora a db 0EDH,052H ;SBC hl,de pop h jnc PATC21 ;must be less than or equal shld TADDR ; to NBYTES ; Print address, datum and prompt for input PATCH3: lhld TADDR ;get displacement push h ;print address mov a,h call PACC pop h push h mov a,l call PACC mvi C,' ' call CONOUT pop h lxi D,BFFR2 dad D mov A,M call PACC ;print datum mvi C,' ' call CONOUT PATC31: call SCAN ;prompt for input jnz PATCH1 mov A,B ;Test for cpi 1 ; single character jz PATC35 mov A,L lhld TADDR lxi D,BFFR2 dad D mov M,A PATC35 lhld TADDR inx h shld TADDR jmp PATCH3 ; Prompt for write out PATCH4: lxi H,PWMSG ;query for write out call PTXT call GCHAR ;get response cpi 'Y' jz PATCH5 ;yes, skip go write cpi 'N' ;no, done jz PATCH6 jmp PATCH1 ;continue command PATCH5: lxi H,BFFR2 ;set address shld TADDR ; and write out call WRITE jnz ERROR PATCH6: call CRLF ret PTMSG db 'atch Sector',3 PAMSG db 0DH,'Address: ',8,8,8,8,3 PWMSG db 0AH,0DH,' Write out? (Y/N/Continue)',3 **************** * HELP COMMAND * **************** HELP: lxi H,HLMSG call PTXT ret HLMSG: db 01AH,0AH,'DISK UTILITY (SD/DD-512) VER 2.22R',0AH db 0AH,0DH,' QR Sequential Read' db 0AH,0DH,' QW Sequential Write' db 0AH,0DH,' RR Random Read' db 0AH,0DH,' RW Random Write' db 0AH,0DH,' F Format Disk' db 0AH,0DH,' T Format Track Read' db 0AH,0DH,' A Select drive A:' db 0AH,0DH,' B Select drive B:' db 0AH,0DH,' C Copy Disk' db 0AH,0DH,' V Verify copy disk' db 0AH,0DH,' D Dump Sector' db 0AH,0DH,' L Load from disk' db 0AH,0DH,' S Save to disk' db 0AH,0DH,' P Patch Sector' db 0AH,0DH,' M Change Density mode' db 0AH,0DH,' X Exit program' db 0AH,0DH,' ? Help',0AH,0DH,3 ************ * SET UNIT * ************ SUNITA: lxi H,SUNMSG call ACCEPT mvi a,0 sta UNIT ret SUNITB: lxi H,SUNMSG call ACCEPT mvi A,1 sta UNIT ret SUNMSG db ':',3 **************** * MODE DENSITY * **************** MODE: lxi H,MODMSG call ACCEPT lda DDFLG xri 0FFH sta DDFLG ret MODMSG db 8,'Change Mode',3 *************** * EXIT SYSTEM * *************** EXIT: lxi H,EXIMSG call ACCEPT call CRLF IF EPROM jmp 0F003H EXIMSG db 8,'Exiting to Monitor ...',3 ENDIF IF NOT EPROM EXIMSG db 8,'Exiting to CPM ...',3 jmp 0 ENDIF ;*------------------------------------------------------* ;* UTILITY ROUTINES * ;*------------------------------------------------------* ; Error print routine ERROR: push PSW ;save status lxi H,ERMSG ;print call PTXT ;"DISK ERROR" pop PSW ;recover status call PACC ;print call SPACES lda UNIT ;get unit call PACC ; and print call SPACES lda TRK ;get track call PACC ; and print call SPACES lda SCTR ;get sector call PACC ; and print call CRLF mvi a,FINCMD call CMDOUT mvi a,0ffh sta SELTRK sta SELUNIT mvi b,6 mvi a,0c3h ERROR1: out DMA dcr b jnz ERROR1 mvi a,RESCMD call FCMDI ret ERMSG db 'sta drv trk sct',07H,0AH,0DH,03 ; Get character from console and echo GCHAR: call CONIN mov C,A push psw call CONOUT pop psw ret ; Output for newline CRLF: mvi C,0DH call CONOUT mvi C,0AH call CONOUT ret ; Output two spaces SPACES: mvi C,' ' call CONOUT mvi C,' ' call CONOUT ret ; Print message and accept ACCEPT: call PTXT ;print message pointed to by hl call CONIN ;get accept cpi 0DH ; is accept jnz INERR ; no, go back to start call CRLF ; yes, ret ; Test for console break or DC1/DC2 handshake BREAK: call CONST ;char pending rz ; no, return BREAK1: call CONIN ;get char cpi 013H ;x-off jz BREAK1 ;wait for x-on cpi 00DH ;escape character? jz DUTIL cpi 01BH jz DUTIL ret ; Print text pointed to by hl with 003H terminator PTXT: mov A,M cpi 03H rz mov C,A push H call CONOUT pop H inx H jmp PTXT ; Print a-register as two hex digits PACC: push PSW rrc rrc rrc rrc call PACC0 pop PSW PACC0: ani 0FH adi 090H daa aci 040H daa mov C,A call CONOUT ret ; ASCII to binary conversion ASBIN: sui 030H cpi 10 rm sbi 007H ret ; Check for valid hex digit AORN: cpi '0' jc AORN2 cpi '9'+1 jc AORN1 cpi 'A'-1 jc AORN2 cpi 'F'+1 jnc AORN2 AORN1: xra A ret AORN2: ori 0FFH ret ; SCAN FOR NUMERIC OPERAND ; VALUE IN HL, LENGTH IN B, NZ=ERROR SCAN: lxi H,0 ;INIT retURNED VALUE mvi B,0 ; AND LENGTH SCAN1: push H ;SAVE HL, B push B call CONIN ;GET A CHARACTER pop B ;RESTORE HL,B pop H mov C,A ;SAVE IN C ; test for backspace cpi 08H ;BACKSPACE jnz SCAN2 ; NO, SKIP mov A,B ;YES, TEST ora A ; FOR BEGINNING jz SCAN1 ; OF LINE push H ;NO, SAVE push B lxi H,BKMSG ;BACKUP AND BLANK call PTXT pop B ;RESTORE pop H dcr B ;DECREMENT COUNTER mov A,L ;DECREMENT ani 0F0H ; ACCUMULATED rar rar rar rar mov L,H mvi H,0 jmp SCAN4 ; Test for carriage return SCAN2 inr B ;INCR COUNTER cpi 0DH ;TEST FOR END jnz SCAN3 ; NO, SKIP push B ;YES call CRLF ; OUTPUT CRLF pop B xra A ;SET Z ret ; Test for valid digit SCAN3 call AORN ;check rnz ; no, return with nz push H ;echo char push B call CONOUT pop B pop H mov A,C ;CONVERT TO call ASBIN ; HEX SCAN4 dad H ;ACCUMULATE TOTAL dad H dad H dad H add L mov L,A jmp SCAN1 BKMSG: db 08H,' ',08H,03H ; Input hex number IHEXN: call SCAN jnz INERR mov A,B cpi 1 jz INERR ret ;*------------------------------------------------------* ;* FORMATTING ROUTINES * ;*------------------------------------------------------* RESCMD equ 008H+FSPEED ;Restore command SKNCMD equ 018H+FSPEED ;Seek no verify SKVCMD equ 01CH+FSPEED ;Seek verify FMTCMD equ 0F0H ;Format track RDTCMD equ 0E0H ;Read format track RDCMD equ 080H ;Read data FINCMD equ 0D0H ;Force interupt STATUS equ 0D4H ;1793 FDC status register CMD equ 0D4H ; command TRACK equ 0D5H ; track SECTOR equ 0D6H ; sector DATA equ 0D7H ; data DMA equ 08CH ;dma channel ****************** * FORMAT COMMAND * ****************** FORMAT: lxi H,FMDMSG ;command lda DDFLG ora a jnz FORM00 lxi H,FMSMSG FORM00: call ACCEPT ; completion xra a ;zero sta FERCNT ; error count call FDRAW ;draw track line FORMA0: call SEEKN ;seek no verify jnz ERROR ; exit if error call SETTLE ;this will be write mvi A,1 ;set sta SCTR ; sector sta PSCTR ; for first lxi H,BFFR1 ;build track here call DENTST ;test density jnz FORMA2 ; double, skip call SBUILD ; single jmp FORMA3 ; go format FORMA2: call DBUILD ; build double FORMA3: call FTRACK ;format track jnz ERROR call FVERFY ;Verify read cpi '+' ; if OK jz FORMA4 ; print '+' lxi H,FERCNT ;bump error count inr m FORMA4: mov c,a call CONOUT ;print '+,2,3,?' call BREAK ;Console break? IF DOUBLE lda TRK cpi NTRKS/2-1 cz CRLF ENDIF lxi H,TRK ;Increment track inr M ; and test mvi A,NTRKS ; for end cmp M jnz FORMA0 ;no, continue call CRLF ;yes, newline lda FERCNT ; and report ora a ; errors if any rz call PACC lxi H,FERMSG call PTXT ret FERMSG db ' Error(s)',0AH,0DH,7,3 FMDMSG: db 'ormat Disk (DD:512)',3 FMSMSG db 'ormat Disk (SD.128)',3 ; Build single density track in memory SBUILD: mvi a,SGAP0 ;gap0: pre-index ora a jz SBUI00 call SGAP mvi a,0FCH ;index mark call FPUT SBUI00: mvi a,SGAP1 ;gap1: post-index jmp SBUIL1 SBUIL0: mvi a,SGAP3 ;gap3: post-data SBUIL1: call SGAP call FID mvi a,SGAP2 ;gap2: id call SGAP mvi A,0FBH ;data mark call FPUT lxi b,SBYTES call DFILL mvi A,0F7H ;crc bytes call FPUT call ISIL jnz SBUIL0 mvi B,0 ;gap4: pre-index mvi A,0FFH call FILL call FILL ret ; Build double density track DBUILD: mvi a,DGAP0 ;gap0: pre-index ora a jz DBUI00 ;skip if none mvi c,0F6H call DGAP mvi a,0FCH ;index mark call FPUT DBUI00: mvi a,DGAP1 ;gap1: post-index jmp DBUIL1 DBUIL0: mvi a,DGAP3 ;gap3: post-data DBUIL1: mvi C,0F5H call DGAP call FID mvi a,DGAP2 ;gap2: id mvi C,0F5H call DGAP mvi A,0FBH ;data mark call FPUT lxi b,DBYTES call DFILL mvi A,0F7H ;crc bytes call FPUT call ISIL jnz DBUIL0 mvi B,0 ;gap4: pre-index mvi A,0FEH call FILL call FILL ret ; Increment sector interleaved ISIL: lda NSCTP1 mov b,a lda SCTR inr a sta SCTR cmp b rz push h ;preserve hl for format call PSFMAP pop h ora a ;set nz ret ; Formatter logical to physical sector mapper (SD and DD) PSFMAP: lda SCTR mov c,a ;make index mvi b,0 dcx b lxi h,ILSD ;assume SD call DENTST jz PSFMP0 ; yes, skip lxi h,ILDD ; no, DD PSFMP0: dad b ;index into table mov a,m ; get result sta PSCTR ; store and ret ; return ; Logical to physical sector mapper (DD only) PSMAP: lda SCTR ;get logical sector mov c,a ; save in c call DENTST ;test SD jz PSMAP0 ; yes, skip mvi b,0 ;make dcx b ; into lxi h,ILDD ; index dad b ; into table mov c,m ;get result into c PSMAP0: mov a,c sta PSCTR ; store and ret ; return ; Draw the track-status line FDRAW: mvi c,'1' mvi b,8 FDRAW0: push b mvi c,'.' mvi b,8 FDRAW1: call conout dcr b jnz FDRAW1 pop b call conout push b mvi c,'0' call conout pop b inr c dcr b jnz FDRAW0 call CRLF ret ; Format write of a single track from BFFR1 FTRACK: mvi a,1 ;setup for write call DMAOUT ;start up DMA channel mvi A,FMTCMD ;output format call CMDOUT ; track command FTRK0: in STATUS ;loop ani 001H ; until busy jnz FTRK0 ; not busy mvi a,083 ;stop DMA out DMA ; channel in STATUS ;get status mask for ani 0C4H ; NR,WP,LOSTDATA ret ; Output DMA channel program (direction in a-reg) DMAOUT: push psw DMAOU0: ; lda MOVECS ; ora a ; jnz DMAOU0 pop psw sta DMADIR ;set direction mvi b,DMALEN ;b=count mvi c,DMA ;c=port lxi h,DMADCB ;hl=channel program db 0EDH,0B3H ;OTIR ret DMADCB: db 0C3H ;WR6: RESET db 06DH ;WR0: XFER,A->B,PORT A,BLKSZ FOLLOWS db DATA ; PORT A (1793 data port) DMABLK: dw 0FFFFH ; BLOCKSIZE db 02CH ;WR1: A IS I/O FIXED db 010H ;WR2: B IS MEMORY INCREMENTING db 08DH ;WR3: BYTE MODE, DMA FOLLOWS DMADDR: dw BFFR1 ; DMA BUFFER ADDRESS db 08AH ;WR4: HI RDY, /CE ONLY db 0CFH ;WR6: LOAD SOURCE DMADIR: db 001H ;WR0: 05:A->B READ; 01:B->A WRITE db 0CFH ;WR6: LOAD SOURCE db 087H ;WR6: ENABLE DMA DMALEN equ $-DMADCB ; Read verify track FVERFY: call FTREAD mvi a,'+' rz ;verify OK call FTREAD mvi a,'2' rz ;recoverable read error call FTRACK ;try another write call FTREAD mvi a,'3' ;recoverable write error rz mvi a,'?' ret ;nfg FTREAD: mvi a,1 sta SCTR sta PSCTR FTREA0: lda PSCTR out SECTOR mvi a,005H ;setup for read call DMAOUT ;start up DMA mvi A,RDCMD ;read data command call CMDOUT FTREA1: in STATUS ;loop until ani 001H ; busy jnz FTREA1 ; goes away mvi a,083H ;stop out DMA ; DMA in STATUS ;check status ani 0BDH ; NR,WP,LOSTDATA rnz call ISIL ;increment sector jnz FTREA0 ; interleaved ret ; Fill buffer with HL = B*A FILL: mov M,A inx H dcr B jnz FILL ret ; Fill buffer with prep data HL = B*E5 DFILL: mvi m,0E5H ;SECTOR PREP DATA inx h dcx b mov a,c ora b jnz DFILL ret ; Build double density gap: HL = A*4E+12*0+3*C DGAP: mov B,A ;count in b mvi A,04EH call FILL xra A mvi B,12 call FILL mov A,C mvi B,3 call FILL ret ; Build single density gap: HL = A*FF+6*0 SGAP: mov B,A ;count in b mvi A,0FFH ;datum in a call FILL xra A mvi B,6 call FILL ret ; Put a single character into buffer FPUT: mov M,A inx H ret ; Build ID record: FEh.TRK.SIDE.SCTR.SECTYP.F7h FID: mvi A,0FEH call FPUT FID4 mvi b,0 ;assume side 0 lda TRK ;test track IF DOUBLE cpi NTRKS/2 ;side 0 jc FID5 ; yes, skip mvi b,1 ; no, side=1 sui NTRKS-1 ;calc track going cma inr a ENDIF FID5: call FPUT ;track mov a,b call FPUT ;side lda PSCTR call FPUT ;sector lda NSCTYP call FPUT ;sector type mvi A,0F7H call FPUT ;crc's ret ********************* * FORMAT TRACK READ * ********************* RTRK: lxi H,RTMSG ;Command completion call ACCEPT lxi H,RTTMSG ;request track call PTXT call IHEXN mov A,L sta TRK call SEEKN jnz ERROR mvi a,0FFH ;set for next sta SELTRK ; operation mvi a,5 ;setup for read call DMAOUT ;start up DMA channel mvi A,RDTCMD ;output format call CMDOUT ; track command RTRK0: in STATUS ;loop ani 001H ; until busy jnz RTRK0 ; not busy mvi a,083 ;stop DMA out DMA ; channel lxi H,11000 ;print buffer shld NBYTES lxi H,BFFR1 call DBFFR ret RTMSG: db 08H,'Format Read',3 RTTMSG: db ' Enter track: ',03 ;*------------------------------------------------------* ;* BB-II MONITOR INTERFACE * ;*------------------------------------------------------* ********************* * Console Interface * ********************* MCONST equ 0F006H ;console status MCONIN equ 0F009H ; input MCONOUT equ 0F00CH ; output CONST: call MCONST ora a ;must set flags ret CONIN: call MCONIN cpi 07BH ;upshift rnc ; to upper case cpi 061H rc ani 05FH ret CONOUT: mov a,c push b call MCONOUT pop b ret ****************** * Disk Interface * ****************** MSELC equ 0F01BH ;select MSEEK equ 0F021H ;seek MREAD equ 0F024H ;read MWRIT equ 0F027H ;write SETDEN equ 0F030H ;SMC disk type/density READY equ 0F033H ;drive ready and set spinup MTRACK equ 0FF87H ;track for TRKTAB CTCB3 equ 08BH ; Test density Z=SD, NZ=DD DENTST: lda TRK ;if track=0 ora a ; then rz ; return Z lda DDFLG ;if not double ora a ; then ret ; return Z ; Select Density and Side DENSET: call DENTST jnz DENSE1 mvi A,SPTSD+1 ;SD track sta NSCTP1 lxi H,SBYTES shld NBYTES mvi a,SDSTYP sta NSCTYP mvi a,DTYPSD ;set single density call SETDEN ret DENSE1: mvi A,SPTDD+1 ;DD track sta NSCTP1 lxi H,DBYTES shld NBYTES mvi a,DDSTYP sta NSCTYP mvi a,DTYPDD ;set double density call SETDEN ret ; Set side SIDSET: lda TRK ;get track mvi B,1 ;assume side 1 IF DOUBLE cpi NTRKS/2 jc SETSD3 mvi B,9 sui NTRKS-1 cma inr A ENDIF SETSD3: sta MTRACK mov A,B ;set side out 0C8H ret ; Select Disk SELECT: lda UNIT ;test same unit lxi H,SELUNIT cmp M jz SELEC1 ;yes, skip mov m,a ;no, update lxi h,SELTRK mvi m,0FFH SELEC1: mov C,A call MSELC ret ; Seek Track HOME: xra a ;home special sta TRK ; case of seek SEEKN: mvi a,0FFH ;assure sta SELTRK ; seek to track sta RDFLAG ; but no verify SEEK: call SELECT ;select drive rnz ; exit if error lda TRK ;test for change lxi H,SELTRK ;of track cmp M rz ;no, exit mov M,A call READY ;spinup rnz ; exit if error call DENSET ;set correct density call SIDSET ; and side lda TRK ;set for cpi 0 ; correct seek command mvi A,RESCMD jz SEEK2 lda MTRACK ;get single sided track out DATA ; output to 1793 lda RDFLAG ora a mvi a,SKNCMD ;if write then jnz SEEK2 ; verify seek mvi a,SKVCMD SEEK2: call FCMDI call SETTLE ; else do head settling ret ; Output type I command FCMDI: call CMDOUT ;output command to 1793 FCMDI0: in STATUS ;wait until ani 001H ; busy goes jnz FCMDI0 ; away in STATUS ;test for ani 098H ; ready.writeprotect, ret ; Output command and delay CMDOUT: out CMD ;output command mvi a,10 ; and wait CMDOU1: dcr a ; a little jnz CMDOU1 ; before status ret ; is ready 28us MFM ; Head settling delay (15ms) SETTLE: push PSW ;keep flags intact mvi B,15 SETTL0: in CTCB3 mov C,A SETTL1: in CTCB3 cmp C jz SETTL1 dcr B jnz SETTL0 pop PSW ret ; Disk read and write routines READP: call PSMAP ;read physical sector jmp READ0 READ: lda SCTR ;read logical sector sta PSCTR READ0: mvi a,0FFH jmp WRIT1 WRITP: call PSMAP ;write physical sector jmp WRIT0 WRITE: lda SCTR ;write logical sector sta PSCTR WRIT0: xra a WRIT1: sta RDFLAG call SEEK rnz lhld TADDR lda PSCTR mov C,A lda RDFLAG ora A jz MWRIT jmp MREAD ;*------------------------------------------------------* ;* VARIABLES * ;*------------------------------------------------------* ; org RAM TADDR ds 2 ;disk DMA address UNIT ds 1 ; UNIT SELUNIT ds 1 ; selected UNIT TRK ds 1 ; TRACK SELTRK ds 1 ; selected TRACK SCTR ds 1 ;logical sector PSCTR ds 1 ;physical sector RDFLAG ds 1 ;read (write/) flag NBYTES ds 2 ;bytes/sector NSCTP1 ds 1 ;sectors/track + 1 NSCTYP ds 1 ;sector type DDFLG ds 1 ;density flag SKEWF ds 1 ;track to track skew SKEW ds 1 ;"first" sector of skewed track DCNTR ds 2 ;dump byte counter DLCNTR ds 1 ; line counter PASCNT ds 1 ;pass counter OLDTRK ds 1 ;dots counter FERCNT ds 1 ;format error count RQST ds 1 ;command request VFLAG ds 1 ;verify flag for copy CTRK ds 1 ;COPY current track CSCTR ds 1 ; current sector SECREM ds 2 ; sectors remaining SECINC ds 2 ; sectors/read increment CREC ds 2 ; number of sectors read/written NREC ds 1 ;number of sectors (records) DQCNT ds 2 ;sequential sector count ds 32 STACK equ $ ; Disk Buffers org BUF BFFR1 ds DBYTES BFFR2 ds DBYTES END