; ; Reverse Engineer of Ampro's CP/M floppy formatter ; rzh Sept. 11, 2001 ; cr equ 0dh lf equ 0ah cpm equ 0 bdos equ 5 bksp equ 8 esc equ 1bh ; flcmd equ 0c0H flwtrk equ 0c1H flwsec equ 0c2H flwdat equ 0c3h flstat equ 0c4h fldata equ 0c7h ; ORG 100H ; LD SP,stack CALL clrscr CALL pnxtmsg db cr,lf db ' AMPRO Copy/For' db 'mat/Verify Utility' db cr,lf db ' Copyright (C) 1984' db ' AMPRO Computers, Inc.' db cr,lf db ' ' db 'Version 2.6$' start: CALL pnxtmsg db cr,lf,lf db 'COPY, FORMAT or VERIFY?' db ' (C, F or V)' db cr,lf db 'Press or ^C to' db ' quit. $' cforv: CALL getinp CP esc JP Z,exit CP 3 ;^C? JP Z,exit AND 5FH CP 'V' JP Z,vrfy CP 'C' JP Z,copy CP 'F' JP NZ,cforv LD A,1 ;format LD (func),A JP fmtcod vrfy: LD A,2 ;verify LD (func),A JP vercod copy: LD A,3 ;copy LD (func),A JP copcod fmtcod: CALL clrscr CALL pnxtmsg db bksp,' ',cr,lf,lf db 'FORMAT prepares a' db ' fresh diskette for' db ' data or program' db ' storage.$' CALL getdst JP C,start CALL pickf JP C,start CALL ntrksv CALL rdydst JP C,start CALL doit JP start vercod: CALL clrscr CALL pnxtmsg db bksp,' ',cr,lf,cr,lf db 'VERIFY checks the' db ' reliability of data' db ' on a disk.$' CALL getdst JP C,start CALL doit JP start copcod: CALL clrscr CALL pnxtmsg db bksp,' ',cr,lf,cr,lf db 'COPY creates a duplicate' db ' of a disk.$' CALL getsrc JP C,start CALL getdst JP C,start CALL rdydst JP C,start CALL doit JP start pickf: CALL pnxtmsg db cr,lf,lf db 'Formats Available:' db cr,lf,' 1. Sing' db 'le side 48 tpi' db cr,lf db ' 2. Double' db ' side 48 tpi' db cr,lf db ' 3. Single' db ' side 96 tpi' db cr,lf db ' 4. Double' db ' side 96 tpi' db cr,lf,lf db 'Choose one (1, 2, 3 or 4). $' getfnbr: CALL getinp CP esc JP Z,exit CP 3 ;^C JP Z,exit CP '1' ;ck, for valid input JP C,getfnbr CP '5' JP NC,getfnbr AND 0FH DEC A JP Z,ss48tpi DEC A JP Z,ds48tpi DEC A JP Z,ss96tpi LD (fa1),A ;ds96tpi LD (tpi),A LD A,10H LD (fa6),A OR A RET ss48tpi: LD (fa1),A LD (tpi),A LD (fa6),A OR A RET ds48tpi: LD (tpi),A INC A LD (fa1),A LD A,10H LD (fa6),A OR A RET ss96tpi: LD (fa6),A LD (fa1),A INC A LD (tpi),A OR A RET ntrksv: LD A,(tpi) OR A LD A,79 JP NZ,ntsv1 LD A,39 ntsv1: LD (ntrks),A OR A RET getsrc: CALL pnxtmsg db cr,lf,lf db 'Source drive?' db ' (A, B, C or D) $' redodr: CALL getinp CP esc JP Z,exit CP 3 ;^C JP Z,exit AND 5FH CP 'A' ;ck for proper range JP C,redodr CP 'E' JP NC,redodr LD (srcdrv),A LD (srcdmsg),A CALL wrtcon CALL pnxtmsg db cr,lf,lf db 'Place source disk' db ' on drive ' srcdmsg: db 'a',cr,lf,lf db 'Press to' db ' continue, to' db ' quit.$' over: CALL getinp CP cr RET Z CP esc JP Z,exit CP 3 ;^C JP Z,exit JP over getdst: CALL pnxtmsg db cr,lf,lf db 'Destination drive?' db ' (A, B, C or D) $' redodd: CALL getinp CP esc JP Z,exit CP 3 ;^C? JP Z,exit AND 5FH CP 'A' JP C,redodd CP 'E' JP NC,redodd LD (dstdrv),A CALL wrtcon LD A,(dstdrv) CALL shfdr OR A RET rdydst: CALL pnxtmsg db cr,lf,lf db 'Place destination' db ' disk on drive $' LD A,(dstdrv) CALL wrtcon CALL pnxtmsg db cr,lf,lf db 'Press to' db ' write, to' db ' quit. $' goon: CALL getinp CP cr RET Z CP esc JP Z,exit JP goon doit: CALL pnxtmsg db cr,lf,lf,'$' LD A,(func) CP 1 JP Z,dofmt CP 2 JP Z,dovrfy LD A,0 LD (fa2),A LD A,39 LD (ntrks),A LD A,(dstdrv) CALL shfdr CALL rdydrv LD A,(srcdrv) CALL shfdr CALL rdydrv LD A,3 LD (ntry),A rdsloop: CALL rdaddr JP Z,rdsrc1 LD HL,ntry DEC (HL) JP NZ,rdsloop CALL pnxtmsg db cr,lf,lf db 'COPY failed. ' db ' Cannot read source' db ' disk.',cr,lf,'$' RET rdsrc1: LD A,(ff0) CP 11H LD A,0 JP C,rdsrc2 INC A rdsrc2: LD (fa1),A OR A RLA RLA RLA RLA LD (fa6),A XOR A LD (trkim+7),A CALL settpi rdsrc5: CALL ckinp LD A,(fa2) OR A PUSH AF LD A,(srcdrv) CALL shfdr POP AF LD A,(shddrv) JP Z,rdsrc3 OR 10H rdsrc3: OUT (0),A LD (shddrv),A LD HL,rdmsg CALL pmsghl CALL ptsmsg rdsmor: LD A,10 LD (ntry),A rdsrc4: CALL prep2rd JP Z,wrdest LD HL,ntry DEC (HL) JP NZ,rdsrc4 CALL pnxtmsg db cr,' ' db ' ' db cr,lf db 'COPY failed. ' db ' Unrecoverable read' db ' error on source' db ' disk.',cr,lf,'$' CALL ckwpt CALL pnxtmsg db cr,lf db 'Try again? (Y or N) $' CALL getinp AND 5FH CP 'Y' RET NZ CALL pnxtmsg db cr,lf,lf,'$' ; may not be used JP rdsmor wrdest: LD A,(fa2) OR A PUSH AF LD A,(dstdrv) CALL shfdr POP AF LD A,(shddrv) JP Z,wrdst1 OR 10H wrdst1: OUT (0),A LD (shddrv),A LD HL,wrmsg CALL pmsghl CALL ptsmsg CALL bldtrk LD A,3 LD (ntry),A wrdst2: CALL wrtrk JP Z,rdyswr LD HL,ntry DEC (HL) JP NZ,wrdst2 CALL pnxtmsg db cr,' ' db ' ' db cr,lf db 'COPY failed. Can' db 'not write destination' db ' disk.',cr,lf,'$' JP ckwpt rdyswr: LD A,3 LD (ntry),A rdysw1: CALL setswr JP Z,rwedone LD HL,ntry DEC (HL) JP NZ,rdysw1 CALL pnxtmsg db cr,' ' db ' ' db cr,lf db 'COPY failed. Unre' db 'coverable write er' db 'ror on destination' db ' disk.',cr,lf,'$' JP ckwpt rwedone: LD A,(fa1) OR A LD A,(trkim+7) JP Z,rwdn1 LD A,(fa2) OR A LD A,(trkim+7) JP Z,nxtrk rwdn1: LD HL,ntrks CP (HL) JP NZ,nxtrk CALL pnxtmsg db cr,' ' db ' ' db cr,lf db 'COPY complete.',cr db lf,lf,'$' JP dovrfy nxtrk: INC A LD (trkim+7),A CALL rsmul LD A,(fa1) OR A JP Z,nxtk1 LD A,(fa2) CPL AND 1 LD (fa2),A JP NZ,nxtk1 LD HL,trkim+7 INC (HL) nxtk1: LD A,(srcdrv) CALL shfdr CALL rsmul LD A,(trkim+7) OUT (flwtrk),A ;track reg? JP rdsrc5 dofmt: LD A,(dstdrv) CALL shfdr CALL rdydrv XOR A LD (trkim+7),A LD (fa2),A dfmt1: CALL ckinp LD HL,fmsg CALL pmsghl CALL ptsmsg CALL bldtrk LD A,3 LD (ntry),A dfmt2: CALL wrtrk JP Z,inctrk LD HL,ntry DEC (HL) JP NZ,dfmt2 CALL pnxtmsg db cr,' ' db ' ' db cr,lf db 'FORMAT failed.',cr db lf,'$' CALL ckwpt RET inctrk: LD A,(fa1) OR A LD A,(trkim+7) JP Z,inctr1 LD A,(fa2) OR A LD A,(trkim+7) JP Z,dosid1 inctr1: LD HL,ntrks CP (HL) JP NZ,dosid1 CALL pnxtmsg db cr,' ' db ' ' db cr,lf db 'FORMAT complete.' db cr,lf,lf,'$' JP dovrfy dosid1: INC A LD (trkim+7),A CALL rsmul JP dfmt1 dovrfy: LD A,0 LD (fa2),A LD A,(dstdrv) CALL shfdr CALL rdydrv LD A,3 LD (ntry),A dovr1: CALL rdaddr JP Z,ctvrfy LD HL,ntry DEC (HL) JP NZ,dovr1 CALL pnxtmsg db cr,lf,'VERIFY' db ' failed. Cannot' db ' read source disk.' db cr,lf,'$' RET ctvrfy: LD A,(ff0) CP 11H LD A,0 JP C,ctvr1 INC A ctvr1: LD (fa1),A OR A RLA RLA RLA RLA LD (fa6),A XOR A LD (trkim+7),A CALL settpi ctvr2: CALL ckinp LD HL,vrfmsg CALL pmsghl CALL ptsmsg LD A,3 LD (ntry),A ctvr3: CALL prep2rd JP Z,vinctr LD HL,ntry DEC (HL) JP NZ,ctvr3 CALL pnxtmsg db cr,' ' db ' ' db cr,lf db 'VERIFY failed. Un' db 'recoverable read' db ' error.',cr,lf,'$' CALL ckwpt RET vinctr: LD A,(fa1) OR A LD A,(trkim+7) JP Z,vinct1 LD A,(fa2) OR A LD A,(trkim+7) JP Z,vdosid vinct1: LD HL,ntrks CP (HL) JP NZ,vdosid CALL pnxtmsg db cr,' ' db ' ' db cr,lf db 'VERIFY complete.' db cr,lf,'$' RET vdosid: INC A LD (trkim+7),A CALL rsmul JP ctvr2 settpi: LD A,(ff1) CP 3 JP Z,settp1 LD A,39 LD (ntrks),A XOR A LD (tpi),A RET settp1: LD A,79 LD (ntrks),A LD A,1 LD (tpi),A RET rsmul: LD A,(fa1) OR A JP Z,rsmul2 LD A,(fa2) OR A LD A,1 JP Z,rsmul1 LD A,0 rsmul1: LD (fa2),A JP Z,a8f rsmul2: LD A,(shddrv) AND 0EFH OUT (0),A LD (shddrv),A CALL longr LD A,90 ;read sector mult. CALL isucmd rsmul3: IN A,(flstat) RRA JP C,rsmul3 RET a8f: LD A,(shddrv) OR 10H OUT (0),A LD (shddrv),A LD HL,trkim+7 DEC (HL) JP longr wrtrk: IN A,(flstat) RRA JP C,wrtrk LD HL,23F4H LD A,0F8H ;write track CALL isucmd CALL flwr LD A,B LD (faa),A AND 44H RET flwr: IN A,(flstat) ;disk write LD B,A RRA RET NC RRA JP NC,flwr LD A,(HL) OUT (flwdat),A INC HL JP flwr bldtrk: LD HL,23F4H LD B,60 LD A,4EH bdtk1: LD (HL),A INC HL DEC B JP NZ,bdtk1 LD (tmphl),HL LD A,(fa2) LD (trkim+9),A LD A,(tpi) OR A LD HL,8002H JP Z,bdtk2 LD HL,3 bdtk2: CALL modim CALL gsectab bdtk3: LD C,(HL) INC HL INC C JP Z,add4e DEC C LD A,(fa6) ADD A,C LD (trkim+11),A PUSH HL CALL genscs POP HL JP bdtk3 add4e: LD HL,(tmphl) LD BC,3E8H add4e1: LD (HL),4EH INC HL DEC BC LD A,B OR C JP NZ,add4e1 LD (tmphl),HL RET modim: LD A,L LD (trkim+13),A LD A,H LD B,4 LD HL,trkdat LD DE,2 mdim1: LD (HL),A ADD HL,DE DEC B JP NZ,mdim1 RET genscs: LD HL,(tmphl) PUSH HL LD HL,trkim gens1: LD D,(HL) INC HL LD E,(HL) INC HL LD A,E INC A JP Z,gensend EX (SP),HL CALL repeat EX (SP),HL JP gens1 gensend: POP HL LD (tmphl),HL RET setswr: LD HL,ff4 LD (tmphl),HL CALL gsectab setswr1: LD C,(HL) INC HL INC C RET Z DEC C LD A,(fa6) ADD A,C OUT (flwsec),A ;sector reg.? PUSH HL CALL wrsec POP HL JP setswr1 wrsec: IN A,(flstat) IN A,(fldata) LD HL,(tmphl) LD A,0A8H ;write sector CALL isucmd CALL flwr LD (tmphl),HL LD A,B LD (faa),A AND 5CH RET Z POP HL POP HL RET prep2rd: LD HL,ff4 LD (tmphl),HL CALL gsectab nxtsect: LD C,(HL) INC HL INC C RET Z DEC C LD A,(fa6) ADD A,C LD (trkim+11),A OUT (flwsec),A ;sector reg.? PUSH HL CALL begrd POP HL JP nxtsect begrd: IN A,(flstat) IN A,(fldata) LD HL,(tmphl) LD A,88H ;read sector CALL isucmd CALL flrd LD (tmphl),HL LD A,B LD (faa),A AND 5CH RET Z POP HL POP HL RET flrd: IN A,(flstat) ;disk read LD B,A RRA RET NC RRA JP NC,flrd IN A,(fldata) LD (HL),A INC HL JP flrd rdaddr: IN A,(flstat) IN A,(fldata) LD HL,fee LD A,0C8H ;read address CALL isucmd CALL flrd LD A,B LD (faa),A AND 44H RET longr: LD BC,209EH delay: DEC BC LD A,B OR C JP NZ,delay RET short: LD BC,686H JP delay repeat: LD (HL),E INC HL DEC D JP NZ,repeat RET clrscr: LD D,24 clrscr1: LD A,lf CALL wrtcon CALL short DEC D JP NZ,clrscr1 RET pmsghl: LD A,(HL) INC HL CP '$' RET Z PUSH AF CALL wrtcon POP AF CP lf CALL Z,short JP pmsghl pnxtmsg: EX (SP),HL CALL pmsghl EX (SP),HL RET wrtcon: PUSH BC PUSH DE PUSH HL LD E,A LD C,2 CALL bdos POP HL POP DE POP BC RET getinp: LD A,9 LD HL,(1) LD L,A JP (HL) rdcon: PUSH BC PUSH DE PUSH HL LD C,1 CALL bdos POP HL POP DE POP BC RET rdydrv: LD A,(shddrv) OUT (0),A LD A,3 ;restore CALL isucmd LD HL,1388H LD C,0 rdydr1: DEC C JP NZ,rdydr1 IN A,(flstat) RRA JP NC,notrdy DEC HL LD A,H OR L JP NZ,rdydr1 LD A,0D0H ;force interrupt CALL isucmd JP notrd1 notrdy: IN A,(flstat) AND 4 JP Z,rdydrv notrd1: LD BC,0 IN A,(flstat) AND 2 LD E,A notrd2: IN A,(flstat) AND 2 CP E JP Z,notrd3 LD E,A INC C LD A,C CP 2 JP Z,doret notrd3: INC A JP NZ,notrd3 notrd4: INC A JP NZ,notrd4 INC B JP NZ,notrd2 LD A,(shddrv) AND 0FH LD C,0 notrd5: INC C RRA JP NC,notrd5 LD A,C OR 40H LD (dnrunt),A CALL pnxtmsg db cr,lf,'Drive ' dnrunt: db 'A Not Ready,' db ' Insert disk and' db ' close the door.' db cr,lf,'$' POP BC doret: RET gsectab: LD H,0 LD A,(tpi) LD L,A ADD HL,HL EX DE,HL LD HL,sptrtab ADD HL,DE LD E,(HL) INC HL LD D,(HL) EX DE,HL RET isucmd: OUT (flcmd),A LD A,10 dwait: DEC A JP NZ,dwait RET ckinp: LD C,0BH ;get console status CALL bdos OR A RET Z CALL rdcon CP 3 ;^C JP Z,exit PUSH AF CALL pnxtmsg db cr,' ' db ' ' db cr,'$' POP AF CP esc RET NZ POP HL RET exit: JP cpm ptsmsg: LD A,(trkim+7) LD DE,instrk CALL fixmsg LD A,(fa2) LD DE,inssid CALL fixmsg LD HL,tsmsg JP pmsghl ckwpt: LD DE,drspot LD A,(shddrv) AND 0FH LD C,0 dla: INC C RRA JP NC,dla LD A,C ADD A,40H LD (DE),A LD (wpmdsk),A LD A,(faa) AND 40H JP Z,prepem LD HL,wprtmsg CALL pmsghl POP HL agin: CALL getinp CP 3 ;^c JP Z,exit CP cr JP Z,doit CP esc JP NZ,agin RET prepem: LD DE,errtrk LD A,(trkim+7) CALL fixmsg LD DE,errhd LD A,(trkim+9) OR A JP Z,prpem1 LD A,1 prpem1: CALL fixmsg LD DE,errsct LD A,(trkim+11) CALL fixmsg LD DE,errst LD A,(faa) AND 10H JP NZ,prnf LD HL,crcch CALL cp3 JP doerm ; following 3 lines unused? LD HL,dnrch CALL cp3 JP doerm prnf: LD HL,rnfch CALL cp3 doerm: LD HL,errmsg JP pmsghl cp3: LD B,3 cp3a: LD A,(HL) LD (DE),A INC HL INC DE DEC B JP NZ,cp3a RET fixmsg: PUSH AF PUSH DE LD A,30H LD (DE),A LD BC,2 XOR A de7: INC DE LD (DE),A DEC C JP NZ,de7 POP DE LD HL,e1f df1: LD C,0 LD A,(HL) INC A JP Z,e1d POP AF df9: SUB (HL) JP C,e01 INC C JP df9 e01: ADD A,(HL) PUSH AF LD A,C CP 0 JP NZ,e13 LD A,B CP 0 JP NZ,e13 e0f: INC HL JP df1 e13: LD B,1 LD A,C ADD A,30H LD (DE),A INC DE JP e0f e1d: POP AF RET e1f: db 64h,0Ah,1,0ffh shfdr: AND 0FH LD C,A XOR A SCF shfdr1: RLA DEC C JP NZ,shfdr1 OR 40H LD (shddrv),A RET errmsg: db cr,lf db ' Error: Drive ' drspot: db 0 db ': Track ' errtrk: db 0,0,0 db ' Head ' errhd: db 0,0,0 db ' Sector ' errsct: db 0,0,0 db ' Status ' errst: db 0,0,0 db cr,lf,'$' tsmsg: db 'Track ' instrk: db 0,0,0 db ' Side ' inssid: db 0,0,0 db cr,'$' wrmsg: db 'Writing $' vrfmsg: db 'Verify $' rdmsg: db 'Reading $' fmsg: db 'Format $' db 'Copy $' wprtmsg: db cr,' ' db ' ' db cr,lf db 'Remove write prot' db 'ect tab from dest' db 'ination diskette.' db cr,lf db 'Place diskette in' db ' drive ' wpmdsk: db 'A, then press' db ' to write' db ' or to quit. $' dnrch: db 'DNR' rnfch: db 'RNF' crcch: db 'CRC' trkim: db 12,0 db 3,0f5h db 1,0feh db 1,0 db 1,0 db 1,1 db 1,2 db 1,0f7h db 22,4eh db 12,0 db 3,0f5h db 1,0fbh trkdat: db 128,0e5h db 128,0e5h db 128,0e5h db 128,0e5h db 1,0f7h db 24,4eh db 0ffh,0ffh sptrtab: dw 0f8eh dw 0f99h db 1,6,2,7,3,8,4,9,5,10,0ffh db 1,4,2,5,3,0ffh func: db 65h ntrks: db 61h fa1: db 64h ;0=ss,1=ds fa2: db 0 srcdrv: db 6eh dstdrv: db 67h shddrv: db 20h fa6: db 0 ;0=ss,10h=ds tpi: db 0 ;0=48,1=96 tmphl: dw 0 faa: db 0 ntry: db 0 db 0,0,0 db 0,0,0,0,0,0,0,0 db 0,0,0,0,0,0,0,0 db 0,0,0,0,0,0,0,0 db 0,0,0,0,0,0,0,0 db 0,0,0,0,0,0,0,0 db 0,0,0,0,0,0,0,0 db 0,0,0,0,0,0,0,0 db 0,0,0,0,0 stack: db 0 db 0 fee: db 0 db 0 ff0: db 0 ff1: db 0,0,0 ff4: db 0 db 0,0 db 0,0,0,0,0,0,0,0 db 0 END