TITLE EQUATE TABLE ; ;SNOOPY DISK TEST PROGRAM ;VERSION 1.2 ; ;WRITTEN BY RALPH E. BUCKNAM ;COPYRITE (C) 1981 ;ALL RIGHTS RESERVED ; ;EQUATE TABLE ; RAM EQU 0DFFFH ; ; ;Disk Driver's In/Out ports ; Select EQU 63H Cmd EQU 64H Stat EQU 64H Track EQU 65H Sect.or EQU 66H Data EQU 67H ; ;Constants for Disk ; TS.SEC EQU 1BH ;LARGE DISK VALUE MAX.SC EQU 0E5H ;LARGE DISK VALUE MAX.TR EQU 0B3H ;LARGE DISK VALUE ; ;Memory buffers ; BUFAD: EQU RAM-2B8H STAK: EQU BUFAD STKADR: EQU RAM-279H L.Byte EQU RAM-77H SyByte EQU RAM-76H ; ;Disk Driver's linkages ; DMA EQU RAM-75H Sctr EQU RAM-73H TRK EQU RAM-72H ERSTAT EQU RAM-71H IDVS EQU RAM-65H SVSP EQU RAM-70H DRVBYT EQU RAM-6EH SECTOR EQU RAM-6DH ; TYPE EQU RAM-6AH HEXAD EQU RAM-31H HEXAD2 EQU RAM-2FH HEXAD3 EQU RAM-2DH HEXADX EQU RAM-2BH HEXAD4 EQU RAM-29H OFSET EQU RAM-27H ; SAVESP: EQU RAM-0FH STACK2 EQU SAVESP PGBUF: EQU RAM-0DH BRKMSG: EQU RAM-0AH VDMBF: EQU RAM-09H VDMBF2: EQU RAM-07H SPEED: EQU RAM-05H ;ONE BYTE DrvChg EQU RAM-3H IOBYT: EQU RAM-02H INIBF: EQU RAM-1H VDMBA: EQU 0CC00H TITLE JUMP TABLE, INITILIZATION, & COMMAND PROCESSOR ; Start JR START2 INIT1: JR INIT1A ;JUMP TO INIT1 ROUTINE ; ;Master jump table ; OUTPUT JP START+1C02H ;Main output INPUT JP START+1C04H ;Main input STATUS JP START+1C07H ;Main status input ; START2 LD SP,STAK ; XOR A LD (IOBYT),A LD (DRVBYT),A ;SET FOR DRIVE 1 LD HL,MSG1 ;DISK TEST PROGRAM ; INIT3 CALL BUFOUT ;SEND MSG1 ; INIT1A: LD SP,STAK CALL CRLF ;GET A NEW LINE CALL CRLF ;INSERT EXTRA CRLF LD A,10H ;LINES PER DISPLAY STOP LD (L.Byte),A ;STORE THE VALUE LD A,(DRVBYT) ;GET DRIVE ADD 'A' CALL OUTPUT LD A,':' ;THE PROMPT CALL OUTPUT ; CALL INBUF ;GET COMMAND ; BUSCA LD HL,INIT1 ;WHERE TO RET PUSH HL ;PUSH IT ON THE STACK PUSH HL ;EQULIZING PUSH LD BC,(BUFAD) ;GET INPUT CHAR. LD DE,CLIST ; FIND POP HL ;REMOVE UNUSED RET. JP EX DE,HL ;CLIST PTR IN HL REG LD E,(HL) ;LOW BYTE INC HL LD D,(HL) INC HL PUSH DE ;PUSH ADDRESS LD E,(HL) ;GET FIRST NAME INC HL LD D,(HL) ;GET SECOND NAME INC HL LD A,E OR D ;TEST FOR END JP Z,ERR1 ;NO COMMAND EX DE,HL ;HIDE ADDRESS OR A ;CLEAR FLAGS SBC HL,BC ;TEST JR NZ,FIND ;KEEP LOOKING ; ;SCANNER ROUTINE FROM DMON ; LD DE,BUFAD+1 LD BC,HEXAD PUSH BC LD L,12 ;12 ZEROS XOR A ;GET A ZERO ; HXZERO LD (BC),A INC BC DEC L JR NZ,HXZERO ; POP BC ; SCA0: INC DE LD A,(DE) CP 0DH JR Z,SCA4 CP '0' ;IS IT A SEPERATOR JR NC,SCA0 ; SCA1: LD HL,0 ; SCA2: INC DE LD A,(DE) CP '0' JR C,SCA3 ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL CALL TSTHX JP NC,ERR1 ADD L LD L,A JR SCA2 ; SCA3: LD A,L LD (BC),A INC BC LD A,H ;IN A BUFFER LD (BC),A ;AS HEX INC BC LD A,(DE) CP 0DH ;ARE WE FINSHED JR NZ,SCA1 ;NOPE! ; SCA4 CALL BLKIN CALL CRLF ;GET A NEW LINE LD BC,(BUFAD+2) ;EXTRA COMMAND BYTES LD DE,(HEXAD2) ;SECOND PARAMETER LD HL,(HEXAD) ;FIRST PARAMETER RET ;RETURN JP TO ROUTINE ; TITLE COMMAND TABLE ; ;COMMAND LIST ; CLIST DW DPHEX ;DUMP MEMORY DB 'DM' DW DPHEX4 ;DUMP HEX AND ASCII DB 'DA' DW ENTER ;ENTER INTO MEMORY DB 'EM' DW INIT0 ;INITILIZE SNOOP DB 'I0' DW GO ;GO DB 'GO' DW MARG ;MARG DB 'PG' DW T.GET ;GET A TRACK DB 'GT' DW T.STORE ;PUT A TRACK DB 'PT' DW SR ;READ X SECTORS DB 'SR' DW SW ;WRITE X SECTORS DB 'SW' DW DRIVE ;CHANGE DRIVES DB 'DV' DW VMEM ;VERIFY MEMORY DB 'VM' DW PROM ;PROM EROMS DB 'PM' DW MOVE ;MOVE MEMORY DB 'MM' DW MTEST ;TEST MEMORY DB 'TM' DW ZERO ;ZERO MEMORY DB 'ZM' DW Sy.Get ;Get a CP/M type system DB 'SG' DW Sy.Put ;Put CP/M system on disk DB 'SP' DW Cp.Dsk ;Copy disk DB 'CD' DW O.Port ;Output to a port DB 'OP' DW I.Port ;Input from a port DB 'IP' DW FORMAT DB 'DF' ;Format a Disk DB 0,0,0,0 DB 0,0,0,0 DB 0,0,0,0 DB 0,0,0,0 DB 0,0,0,0 DB 0,0,0,0 DB 0,0,0,0 DB 0,0,0,0 ; TITLE SYSTEM UTILITIES #1 ; ERR1 LD HL,MSG3 ;Point to the error Msg. CALL BUFOUT ;Do the bitching JP INIT1 ;Start over ; FORCE: CP 61H RET C CP 7BH RET NC SUB 20H RET ; BLKIN OR A ;CLEAR FLAGS LD DE,(HEXAD) ;GET START LD HL,(HEXAD2) ;GET END SBC HL,DE ;GET RESULTS INC HL LD (HEXAD4),HL ;BLOCK LNGTH RET ; ;OFSET CALCULATION ; COFSET AND A ;CLEAR CARRY FLAG LD HL,0 LD DE,(HEXAD3) ;GET OFFSET SBC HL,DE JR Z,OFFSTR LD HL,(HEXAD) EX DE,HL AND A SBC HL,DE EX DE,HL LD HL,0 AND A SBC HL,DE OFFSTR: AND A EX DE,HL LD HL,0 SBC HL,DE LD (OFSET),HL ;STORE OFSET RET ; ;BUFFER INPUT ROUTINE ;ACCEPS UP TO 64 CHARACTERS. ; INBUFX CALL CRLF ;START WITH A NEW LINE ; INBUF: LD HL,BUFAD LD B,40H ; INB1: CALL INPUT CALL OUTPUT CALL FORCE ;MAKE UPPER CASE CP 15H ;TEST FOR CTRL U JR Z,INBUFX ;GET A NEW LINE CP 00H ;TEST FOR A NULL JR Z,INB1 ;NO EFFECT IF NULL CP 7FH ;TEST FOR DELETE JR Z,DELETE ;GO BACKSPACE LD (HL),A ;STORE DATA CP 0DH ;TEST FOR CR RET Z ;RETURN TO CALLER INC HL DJNZ INB1 ; JR ERR1 ; DELETE: LD A,40H ;INITIAL BUFF SIZE CP B JR Z,INB1 ;NO INPUTS YEAT INC B ;ADJ POINTERS DEC HL JR INB1 ; CRLF.5 LD A,10H LD (L.Byte),A ;Reset page counter ; CRLF: LD A,0DH ;CRLF WITH SWITCH CALL OUTPUT LD A,0AH ;TOKEN FOR LINE FEED CALL OUTPUT LD A,(IOBYT) ;GET THE DATA BYTE AND 27H ;DO THE TESTING JR NZ,CRLF.3 ;JUST CHECK FOR A ;KEY PRESS PUSH HL ;SAVE CALLERS HL REG. LD HL,L.Byte ;POINT TO THE REMAINING ;LINES TO BE OUTPUTED DEC (HL) ;REDUCE # OF LINES JR NZ,CRLF.2 ;MORE TO GO LD (HL),15 ;RELOAD THE COUNT ; CRLF.2 POP HL ;RETREIVE CALLERS REG. JR Z,CRLF.4 ;CHECK IF PROGRAM ;CONTINUES EXECUTION ; CRLF.3 CALL STATUS CP 0FFH ;TEST IF KEYPRESS RET NZ ;NO KEY PRESS CALL INPUT ;CLEAR BYTE THAT ;DID THE FLAGGING CRLF.4 CALL INPUT ;WAIT TILL A KEY IS ;PRESSED CP 0DH ;TEST FOR A CRET RET NZ ;CONTINUE JP INIT1 ;TERMINATE COMMAND ; BUFOUT: CALL CRLF ;GET NEW LINE ; BUFOT2 LD A,(HL) ;GET CHAR OR A ;TEST IF DONE RET Z PUSH AF ;SAVE FLAGS AND 7FH ;STRIP 7 BIT CALL OUTPUT POP AF RET M ;DONE INC HL JR BUFOT2 ;CONTINUE ; TSTHX SUB 30H ;TEST FOR HEX CP 10 ;LESS THAN A RET C ;YES IT IS 0-9 SUB 10H CP 7 ;A THROUGH F ONLY RET NC ;IT IS TO BIG ADD 9 SCF ;FLAG AS HEX RET ; ;This routine outputs the drive byte ; DrvOut JR C,DrvOt2 ;Do not get drive from ;memory LD A,(DRVBYT) ;Get the drive byte DrvOt2 LD B,A ;Save byte in B Reg. JR Z,DrvOt3 ;Donot output message LD HL,DrvMsg ;Point to the message CALL BUFOT2 ;Output ' Drive ' DrvOt3 LD A,B ;Retreive drive Num. ADD 'A' ;Convert to a letter JP OUTPUT ;Output the drive Letter ; DrvMsg DM ' Drive ' ; ;Output the message with drive number ;and check if ready ; Ready2 CALL BUFOT2 ;Output the message OR A ;Clear the flags Ready3 CALL DrvOut ;Output the drive ;letter CALL CRLF.5 ;Get a new line ; ;Check to see if you really want a command ; Ready LD HL,R.Msg1 ;Point to message CALL BUFOT2 ;Output the message CALL CRLF ;Get a new line CALL INPUT ;Get response OR 20H ;Convert to upper case CP 'y' ;Cleck if ready RET Z ;Yes LD HL,R.Msg2 ;' Command terminated ' CALL BUFOT2 ;Output messaged CALL CRLF ;get a new line JP INIT1 ;End the mess ; R.Msg1 DM 'Ready (Y/N)' R.Msg2 DM 'Command terminated' TITLE SYSTEM COMMANDS #1 ; ;SUBROUTINE TO SET PAGE LENGTH ;AND SPACE BETWEEN PAGES ; MARG ;HL CONTAINS (HEXAD) LD A,L SUB H LD L,A LD (PGBUF),HL LD (PGBUF+2),A RET ; MSG1 DM 'Snoopy Disk testing program! MSG3 DM 'ERROR' MemErr DM 'Memory is defective' ; ;EXECUTE AT SELECTED ADDRESS ; GO LD HL,(HEXAD) ;GIT THE GO ADDRESS PUSH HL LD BC,6 LD HL,HEXAD2 LD DE,HEXAD LDIR JP BLKIN ;SETUP BLOCK LINGTH ; ;ROUTINE TO ENTER HEX FROM THE KEYBOARD ; ENTER ;HL CONTAINS (HEXAD) ; ENTR1 CALL ADOUT2 ;O/P CURRENT ADD CALL MOUT2 ;OUTPUT AND SPACE CALL HEXTT PUSH AF CALL SPACE CALL MOUT ;OUTPUT FINAL POP AF JR NZ,BKK1 DEC HL DEC HL BKK1 INC HL CALL CRLF.5 ;Get a new line JR ENTR1 ; ;Output to a specified port ; O.Port ;DE and HL contains ;the info. LD C,L ;Move port no in L reg ;to C reg. LD A,E ;Move data to accum. CALL Binit2 ;Output the data LD HL,OpMsg ;Message pointer CALL BUFOT2 ;Output the message LD A,C ;Move Port to ACCUM CALL HEXOUT ;Output the port number OUT (C),E ;Do the outputing RET ; OpMsg DM ' is outputed from port # ' ; ;Input from port or ports ; I.Port ;De and HL registers ;contain the data LD C,L ;Move port to C Reg. ; IPort2 In A,(C) ;Get the input CALL Binit2 ;Output the data LD HL,InMsg ;Point to the message CALL BUFOT2 ;Output the message LD A,C ;Get the port number CALL HEXOUT ;Output port Number CALL CRLF.5 ;get a new line CALL INPUT ;Find out what to do CP 0DH ;Check for a carrage ;return RET Z ;The end of routine CP 07FH ;Check for a delete JR Z,IPort3 ;Backup port pointer CP ' ' ;Check for a space JR Z,IPort4 ;Advance the pointer JR IPort2 ;Get annother input ; IPort3 DEC C ;Backup pointer JR IPort2 ;Loop again ; IPort4 INC C ;Advance pointer JR IPort2 ;Loop again ; InMsg DM ' is inputted from port # ' TITLE SYSTEM UTILITIES #2 ; ;SUBROUTINE TO O/P REG IN HEX ; HEXOUT: PUSH BC ;SAVE LD B,A ;SAVE TEMP. CALL HEXO1 POP BC RET HEXO1: RRCA RRCA RRCA RRCA CALL CHASE ;CHANGE TO ASCII ; CHASE: AND 0FH ;MASK ADD 30H ;ADD '0' CP 3AH ;?>9 JR C,CH1 ADD 7 ;CHANG TO A-F CH1: CALL OUTPUT LD A,B RET ; HXOUT2 CALL HEXOUT JR SPACE ; ;OUT MEM BYT IN HEX ; MOUT: LD A,(HL) ;GET IT JR HEXOUT ;OUTPUT IT ; MOUT2 CALL MOUT ;OUTPUT MEM. JR SPACE2 ;OUTPUT 2 SPACES ; ;OUTPUT ADDRESS ; ADOUT: LD A,H ;GET HI ADRESS CALL HEXOUT ;0/P IT LD A,L ;AND THE LOW JR HEXOUT ;O/P IT ; ADOUT4 CALL SPACE CALL ADOUT JR SPACE2 ; ADOUT2 CALL ADOUT ;OUTPUT ADDRESS JR SPACE ;OUTPUT A SPACE ; ;OFSET ADDRESS OUTPUT ROUTINE ; OFFADR: PUSH DE PUSH HL LD DE,(OFSET) ADD HL,DE CALL ADOUT POP HL POP DE RET ; SPACE4 CALL SPACE2 ; SPACE2 CALL SPACE ; SPACE LD A,' ' ;GET A SPACE JP OUTPUT ;OUTPUT IT ; ;INPUT CHARACTER FROM KEYBOARD ; HEXTT: CALL INPUT ;GET BYTE CP 0 ;IS IT A NULL JR Z,HEXTT CALL FORCE ;MAKE UPPER CASE CP 7FH ;TEST FOR DELETE RET Z ;YES CP ' ' ;IS IT S SPACE JR Z,NXT CALL OUTPUT CALL TSTHX ;IS IT VALID JR NC,NOPE LD B,A ;SAVE NEW DATA LD A,(HL) ;GET CURRENT DATA RLCA ;SAVE RIGHT HALF RLCA RLCA RLCA AND 0F0H OR B ;ADD IN NEW LD (HL),A JR HEXTT ;KEEP GOING ; NXT: OR A ;TURN OFF ZERO RET ; NOPE: POP AF ;CORRECT STACT RET TITLE SYSTEM COMMANDS # 2 ; ;DUMP HEX AND ASCII ; DPHEX4 DPHEX EXX ;SAVE PARAMETERS CALL COFSET LD A,1 LD (BRKMSG),A ;RESET HEADER OUTPUT EXX ;RETREIVE (HEXAD) & ;(HEXAD2) LD A,(BUFAD+1) ;LOOK AT BUF. LD C,0 ;ZERO TEST BYTE REG. CP 'A' ;TEST FOR ASCII JR NZ,DPHEX1 ;DONOT SET FLAGS SET 0,C ;SET ASCII FLAG ; DPHEX1: PUSH BC ;PUSH DUMP TYPE PUSH HL EXX ;FLIP POP HL ;ADR IN PROPER POS POP BC ;RETREVE DUMP TYPE ; LD A,L AND 0FH ;STRIP OFF UPPER BITS INC A DEC A ;TEST FOR ZERO JR Z,DPHEX2 ;NO ADJUSTING REQ. ; LD B,A ;GET ADJ FACT IN B ZERHEX: DEC HL DJNZ ZERHEX ;REPEAT TILL ZERO ; DPHEX2: CALL MSTEST ;TEST FOR MESSAGE JR NOMSG ;GO TO WORK ; MSTEST: LD A,(BRKMSG) ;GET MSG BYTE BIT 0,A ;TEST FOR MSG RET Z ;NO MESSAGE PUSH HL LD HL,HEXMSG ;MESSAGE ADDRESS CALL BUFOT2 ;OUTPUT MSG POP HL XOR A ;ZERRO ACCUM LD (BRKMSG),A ;RESET MSG COUNTER RET ; NOMSG: CALL OFFADR ;OUTPUT ADDRESS CALL SPACE PUSH HL POP DE ;TRANSER COMPLEAT ; CALL OUTHEX ;OPUT 8 HEX BYTES CALL OUTHEX ;OPUT 8 HEX BYTES BIT 0,C ;TEST FOR ASCII JR Z,PASEND ;NO ASCII ; PUSH DE POP HL ;TRRANSFER COMPLETE CALL CRLF ;GET NEW LINE CALL MSTEST ;TEST FOR MSG CALL SPACE4 ;SET FOR 4 SPACES CALL OUTASC ;OUTPUT 8 ASCII BYTES CALL SPACE CALL OUTASC ;OUTPUT 8 ASCII BYTES CALL CRLF ;GET A CLEAN LINE ; PASEND: PUSH HL EXX ;Get back regs. POP HL ;PRESENT ADR AND A ;CLEAR CARRY FLAG SBC HL,DE ;MAKE END CALC. RET NC ;FINISHED ? EXX ;GET FRONT REGS. CALL CRLF ;GET NEW LINE JR DPHEX2 ;KEEP GOING ; OUTHEX: CALL SPACE LD B,8 ;8 HEX OUTPUTS HEX: LD A,(HL) PUSH BC CALL HXOUT2 ;OUTPUT BYTE POP BC ;RETREIVE DATA INC HL DJNZ HEX ;KEEP GOING RET ; OUTASC: LD B,8 ASCII: PUSH BC ;SAVE FLAGS CALL SPACE2 ;OUTPUT 2 SPACES POP BC ;RETREIVE FLAGS LD A,(HL) ;GET BYTE CALL CANCL ;CHECK FOR ASCII CALL OUTPUT INC HL ;ADVANCE COUNTER DJNZ ASCII RET ; CANCL: CP 20H ;LETER CHECK JR C,CNCL1 ;NO LETER CP 5FH ;TEST FOR BACK SPACE JR Z,CNCL1 CP 7EH RET C ; CNCL1: LD A,'.' ;SET TO OUTPUT (.) RET ; HEXMSG: DB ' 0 1 2 3 4 5 6 7 ' DB ' 8 9 A B C D E F' DB 0DH,8AH ; ;CHANGE DRIVES ; DRIVE LD HL,DRVBYT ;WHERE DRIVE IS LD B,0 LD A,(BUFAD+2) ;GET LETTER CP 'B' ;TEST IF B JR NZ,D.DEF ;SET UP DRIVE A INC B D.DEF LD (HL),B ;STORE DRIVE NO RET ; ;ZERO ROUTINE -- ZERO A BLOCK OF MEMORY ;WITH SELECTED FILL ; ZERO: LD A,(HEXAD3) ;GET FILL LD B,A CALL ZBLOK ZERO2: LD (HL),B ;FILL BLOCK INC HL DEC DE LD A,E OR D ;CHECK FOR END JR NZ,ZERO2 ZBLOK: LD DE,(HEXAD4) ;GET BLKLN LD HL,(HEXAD) ;AND START RET ; MTEST: CALL ZERO ;MEMORY TEST DB 0C4H ;SKIP 3 BYTES TWR1: DEC (HL) INC HL ;NEXT TRW: LD A,B CP (HL) ;TEST CALL NZ,ZERR DEC DE LD A,E ;END CHECK OR D ;END CHECK JR NZ,TWR1 ;KEEP GOING ; DEC (HL) ;GET THE LAST ONE CALL ZBLOK ;SET UP AGAIN CALL MSTRS ;CHECK FOR ESCAPE DEC B ;NEXT CHAR JR NZ,TRW ; RET ;END OF ROUTINE ; ZERR PUSH HL LD HL,MSGA CALL BUFOUT POP HL CALL ADOUT PUSH HL LD HL,MSGB CALL BUFOT2 POP HL CALL Binit PUSH HL LD HL,MSGC CALL BUFOT2 POP HL LD A,B JP Binit2 ; MSGA: DB 'DATA AT:',0A0H MSGB: DB ' IS',0A0H MSGC: DB ' SHOULD BE',0A0H ; MSTRS: CALL STATUS ;CHECK IF KEY PRESS CP 0FFH ;TEST FOR KEYPRESS RET NZ ;NO KEY PRESS CALL INPUT ;GET DATA CP 1BH ;TEST FOR ESCAPE JP Z,INIT1 RET ; LDREG ;(HEXAD), Is in HL reg. LD DE,(HEXAD3) LD BC,(HEXAD4) RET ; MOVE: CALL LDREG CALL MOVER JR VMEM2 ; PROM: CALL LDREG LD A,64H M.MOVES CALL MOVER DEC A JR NZ,M.MOVES ; VMEM: CALL LDREG VMEM2: LD A,(DE) CPI JR Z,NO.ERR ; ;OUTPUT ERROR INFORMATION ; PUSH AF PUSH HL PUSH DE PUSH BC DEC HL CALL ADOUT4 CALL MOUT CALL SPACE4 ;MAKE 4 SPACES EX DE,HL CALL ADOUT4 CALL MOUT CALL CRLF POP BC POP DE POP HL POP AF ; NO.ERR: INC DE RET PO JR VMEM2 ;NEXT CHECK ; MOVER: PUSH HL PUSH DE PUSH BC LDIR POP BC POP DE POP HL RET ; TITLE DISK UTILITY COMMANDS ; ;Get track 0 & 1 for a system transfer ; Sy.Get LD A,55H ;Token for setup LD (SyByte),A ;Store setup token XOR A ;Token for Read ; SyPut2 LD (DMA),HL ;Store the DMA adr. LD DE,1 ;Set track 0 sector 1 LD (SECTOR),DE ;Store track and sector LD B,52 ;Number of sectors for ;the transfer LD (TYPE),A ;Store the read o write ;token JP M.DUMP ;Do the work ; ;Put a system on a disk ; Sy.Put LD A,(SyByte) ;Get the transfer byte CP 55H ;Test if initilized JP NZ,ERR1 ;Not setup LD A,1 ;Token fo write JR SyPut2 ;Continue elsewhere ; ;Copy disk for drive X to drive Y ; Cp.Dsk Push HL ;Save the DMA adr. LD HL,ERR1 ;Point to the error ;routine PUSH HL ;Make a return jump LD A,C ;Get the source drive SUB 'A' ;Convert to drive RET M ;Not a drive CP 2 ;Test if to large RET NC ;Too large LD C,A ;Save the source drive LD A,B ;Get the designation ;drive SUB 'A' ;Convert to drive RET M ;Not a drive number CP 2 ;Test if to many drives RET NC ;Not a existant drive CP C ;Test for the same drive RET Z ;Was same drive LD B,A ;Save drive number POP HL ;Remove the RET Jump POP HL ;Retreive the DMA Adr. PUSH AF ;Save the designation ;Drive LD A,C ;Get the source drive EXX ;Save the data registers PUSH AF ;Hide the source drive LD HL,D.Msg8 ;Copy disk from CALL BUFOT2 ;Output the message POP BC ;Retreive source drive OR A ;Clear the flags LD A,B ;Get drive number SCF ;Set the carry flag ;Do not get the Mem byte CALL DrvOut ;Output drive info LD HL,D.Msg9 ;Output the ' to' CALL BUFOT2 ;Do the outputing POP BC ;Retreive the designation ;drive OR A ;Clear the flags LD A,B ;Get the drive No. SCF ;Set the carry flag Call Ready3 ;output the data EXX ;Retreive Data regs. PUSH HL ;Start a transfer POP IX ;Finish the transfer LD H,77 ;77 tracks LD L,0 ;Start at zero track LD IY,IOBYT ;Point to the I/O byte SET 7,(IY+00) ;Go into unskewed mode ; Tr.Loop LD A,0 ;Token to read CALL CdTrans ;Read 7 tracks LD A,1 ;Token to write CALL CdTrans ;Write 7 tracks LD A,L ;Move the present ;Track to Accum. ADD 7 ;Move to the next tracks ;to be transfered LD L,A ;Save the value LD A,H ;Move remaining sectors ;to the accumulator SUB 7 ;Reduce track count LD H,A ;Saving remaning sectors JR NZ,Tr.Loop ;More to transfer ; RES 7,(IY+00) ;Return to the skewed ;mode PUSH BC CALL Home POP BC LD A,C ;Get source drive LD (DRVBYT),A ;Swtich drives JP Home ;End of routine ; CdTrans OR A ;Test if read or write LD (TYPE),A ;Store type of transfer LD A,C ;Source byte to A JR Z,CdTr2 ;Is a read ; LD A,B ;Was a write CdTr2 LD (DRVBYT),A ;Store the drive LD (DMA),IX ;Store DMA Adr. LD E,1 ;Sector 1 LD D,L ;Next track PUSH DE ;Strat transfer EXX ;Go to the back side POP DE ;Complete transfer of ;track and sector LD B,26*7 ;Number of sectors to ;transfer LD (SECTOR),DE ;Store Track and Sector Call M.DUMP ;Transfer the data EXX ;Retreive the registors RET ; ;READ X SECTORS FROM DISK ; SR XOR A JR D.RD2 ; ;WRITE X SECTORS FROM DISK ; SW LD A,1 D.RD2 LD (TYPE),A ;STORE TYPE OF OPERATION LD HL,(HEXADX) ;GET ADDRESS LD (DMA),HL ;STORE DMA CALL ADOUT2 ;OUTPUT ADDRES & SP LD HL,HEXAD ;GET THE POINTER LD B,(HL) ;SECTORS TO B INC HL INC HL LD D,(HL) ;START TRACK TO D INC HL INC HL LD E,(HL) ;START SECTOR TO E LD (SECTOR),DE ;STORE START INC B ;ZERO TEST DEC B JP Z,ILL.SEC ;COMPLAIN CALL M.DUMP ;TRANSFER DATA CALL SPACE DEC HL CALL ADOUT ;OUTPUT END RET ;END OF ROUTINE ; ;GET A TRACK ROUTINE ; T.GET XOR A ;FLAG FOR READ JR T.GET2 ;STORE TYPE ; ;STORE A TRACK ROUTINE ; T.STORE LD A,1 ;FLAG FOR REED T.GET2 LD (TYPE),A ;STORE OPERATION EX DE,HL ;(HEXAD2) IN HL REG. ;(HEXAD) IN DE REG LD (DMA),HL ;STORE DMA ADR LD A,D OR A ;TEST FOR ZERO JP NZ,ERR1 ;NO GOOD LD D,E LD E,1 ;FIRST SECTOR OF TRK. LD (SECTOR),DE ;STORE START ; T.DUMP PUSH HL ;SAVE ADDRESS LD HL,D.MSG1 ;'+ TRACK NO ' CALL BUFOT2 ;OUTPUT MSG POP HL LD A,D ;GET TRACK NO IN A CALL HXOUT2 ;OUT TRACK & SPACE CALL SPACE CALL ADOUT2 ;OUTPUT ADR. & SPACE LD B,TS.SEC-1 ;SET FOR 26 SECTORS CALL M.DUMPS ;GO TO WORK DEC HL ;POINT TO LAST BYTE CALL ADOUT ;OUTPUT END INC HL CALL CRLF CALL INPUT CP ' ' ;TEST IF SPACE JR Z,T.DUMP ;CONTINUE ; RET ;END OF ROUTINE ; M.DUMP PUSH BC CALL RD.WR ;GET A SECTOR CALL ADVANC ;ADVANCE POINTER POP BC DJNZ M.DUMP ;CONTINUE ; RET ; ;ADVANCE DMA TO NEXT POSITION ; ADVANC LD HL,(DMA) LD DE,80H ADD HL,DE LD (DMA),HL ; ;ADVANCE TO NEXT SECTOR AND WHEN NECESSARY ;ADVANCE TO NEXT TRACK ; LD DE,(SECTOR) ;GET TRACK AND SECTOR INC E ;MOVE TO NEXT SEC LD A,TS.SEC ;TEST FACTOR CP E ;TEST JR NZ,S.STORE ;STORE TRACK AND SEC LD E,1 ;START AGAIN INC D ;NEXT TRACK S.STORE LD (SECTOR),DE ;STORE SECTORS RET ; ;READ OR WRITE A SECTOR ; RD.WR LD DE,(SECTOR) ;GET TRACK AND SECTOR LD A,(IOBYT) ;Get Skewing info RLA ;Test for Skewin JR C,N.Skew ;Was not skewed ; ;UNSKEW ROUTINE ; LD HL,TRANS ;POINT TO THE TABLE LD B,0 ;ZERO THE REGISTER LD C,E ;TRANSFER THE RAW SEC. DEC C ADD HL,BC ;POINT TO WHERE IT IS ;ON THE DISK LD E,(HL) ;GET THE SEKWED SECTOR ; N.Skew LD (Sctr),DE ;STORE TRACK AND " XOR A ;GET A ZERO OR E ;CERTIFY SECTOR JR Z,ILL.SEC ;ILLEGAL SECTOR ADD MAX.SC ;TEST FOR MAX SEC JR C,ILL.SEC ;ILLEGAL SECTOR LD A,MAX.TR ;MAX TRACKS ADD A,D ;TEST FOR MAX TRACKS JR C,END.DSK ;END DISK LD A,(TYPE) ;READ OR WRITE OR A ;TEST PUSH AF ;SAVE CALL NZ,WRITE ;WRITE A SECTOR JR NZ,DSK.ERR ;ERROR OCCURED POP AF XOR A,1 CALL NZ,READ ;READ A SECTOR JR NZ,DSK.ERR ;ERROR OCCURED RET ; ILL.SEC LD HL,D.MSG2 JR D.ERR2 ; END.DSK LD HL,D.MSG3 JR D.ERR2 ; DSK.ERR LD HL,D.MSG4 D.ERR2 CALL BUFOUT ;OUTPUT BITCH JP INIT1 ;START OVER ; D.MSG1 DM '+ TRACK NO. ' D.MSG2 DM 'ILLEGAL SECTOR NO.!' D.MSG3 DM 'END OF DISK!' D.MSG4 DM 'DISK ERROR' D.Msg8 DM 'Copy disk from' D.Msg9 DM ' to ' ; TRANS DB 1H,7H,0DH,13H,19H,5H DB 0BH,11H,17H,3H,9H,0FH DB 15H,2H,8H,0EH,14H,1AH DB 6H,0CH,12H,18H,4H,0AH DB 10H,16H TITLE FORMAT DISK COMMAND ; ;TRACK FORMAT ROUTINE ; ;Modified IMB 3740 format--128 bytes/sector. ;The 40 FFH's bytes has been changed to 50 FFH's ;bytes. This assures snychronization of the ;disk controler clock. ; TrkFmt DB 0FDH ;Make unpublished LD A,H ;Get the track in ;in the accumulator OUT Data,A ;Output Trk # to Disk LD D,1AH ;Token to seek with ;out verify CALL CmdI ;Seek track LD HL,1A01H ;26 Sectors, start at ;Sector 1 LD B,32H ;Setup for 50 0FFH's ;IBM Spec. 40 0FFH's CALL SetWait ;Setup wait states LD A,0F4H ;Token to write track OUT Cmd,A ;Output write command CALL FF.Out ;Output the FFH's ;followed by 6 00H's LD A,0FCH ;Token for index mark OUT Data,A ;Output index mark ; ;Write a sector with required ID bytes ; SecFmt LD B,1AH ;Setup for 26 0FFH's CALL FF.Out ;Output FFH's followed ;By 6 00H's LD A,0FEH ;Token for ID Mark OUT Data,A ;Output ID Mark IN A,Track ;Get Track # from ;Controler OUT Data,A ;Output the current track XOR A ;Token for side # 1 OUT Data,A ;Output side Number LD A,L ;Get present sector # OUT Data,A ;Output sector number XOR A ;Token for a 128 byte ;Sector OUT Data,A ;Output sector size LD A,0F7H ;Token for two CRC ;Nibbles OUT Data,A ;Output the CRC byte LD B,0BH ;Setup for 11 0FFH's CALL FF.Out ;Output the 11 0FFH's ;Folowed by 6 00H's LD A,0FBH ;Token for start of ;Data field OUT Data,A ;Output data field token ; ;Setup for a data field of 128 bytes ; LD B,80H ;Set length of data field LD A,0E5H ;Fill for data field ; D.Fill OUT Data,A ;Fill the data field DJNZ D.Fill ;Loop till done ; LD A,0F7H ;Token for two CRC's ;nibbles OUT Data,A ;Output the CRC byte INC L ;Increas sector number DEC H ;Reduce remaining sectors LD A,0FFH ;Get a exta FFH OUT Data,A ;Output the FFH JR NZ,SecFmt ;Loop till track is ;Done ; LD E,80H ;Error mask CALL Err.Ck ;Check for errors XOR A ;Token for no errors RET ; FF.Out LD A,0FFH ;A null token ; FF.Loop OUT Data,A ;Output A Null byte DJNZ FF.Loop ; LD B,06H ;Setup for 6 00H bytes XOR A ;Get a 00H ; Out.00H OUT Data,A ;Output the 00H's DJNZ Out.00H ; RET ; FormMsg DM 'Format disk in' ; ;Format command routine ; FORMAT LD HL,FormMsg ;Point to format Msg. CALL Ready2 ;Output the message ;and check if ready CALL Home ;Home and setup drive DB 0FDH ;Make unpublished LD H,0 ;Set start at track 0 ; F.Next Call TrkFmt ;Format a track DB 0FDH ;Make unpublished INC H ;Advance track pointer LD A,4DH ;Max tracks in Accum. DB 0FDH ;Make unpublished CP H ;Check for the end JR NZ,F.Next ;More tracks to format ; ;Falls into the Home ;Routine TITLE DISK DRIVERS ; ;VERSAFLOOPY ROUTINES ; ;Rewritten for Z80 code by Ralph E. Bucknam ;January 1981 ; Home LD (SVSP),SP ;Save the Stack CALL DrvSet ;SET UP THE DRIVE IF ;REQUIRED LD D,0BH ;HOME TOKEN ;& ENGAGE HEAD ; ;PROCESS TYPE [ I ] COMMANDS ;D Registor contains the command ; CmdI LD E,80H ;ERROR MASK ; CmdI.W IN A,Stat ;GET THE STATUS RRCA ;TEST IF BUSY JR C,CmdI.W ;WAIT TILL NOT BUSY ; IN A,Select ;GET DATA FROM PORT AND 1FH ;SAVE LOWER BITS OR 60H ;SET 5 & 6 BITS HIGH OUT Select,A ;OUTPUT THE WAIT ;COMMAND LD A,D ;COMMAND TO A OUT Cmd,A ;DO IT LD A,90H ;THE WAIT FACTOR ; Wait.2 DEC A JP NZ,Wait.2 ;WAIT TILL ZERO ; ;Error checking routine ;Error mask is in E Regisitor ; Err.Ck IN A,Stat ;GET THE STATUS RRCA ;TEST IF READY JR C,Err.Ck ;WAIT TILL READY ; ;Dissable the wait states ; IN A,Select ;GET THE DATA OR 0E0H ;TURN WAIT STATE OFF OUT Select,A ;DISABLE THE WAIT STATES ; ;Do the error checking ; IN A,Stat ;GET THE STATUS AND E ;AND WITH ERROR MASK RET Z ;NO ERRORS ; ;Disk error routine ; DskErr LD (ErStat),A ;Save the status LD (IDVS),DE ;SAVE THE DATA ABOUT ;THE COMMAND OR 1 ;SET A ERROR FLAG LD SP,(SVSP) ;GET ORIGINAL CALLERS ;STACK RET ;RETURN TO THE ORIGINAL ;CALLER ; ;READ OR WRITE A SECTOR SETUP ; READ LD HL,88FEH ;TOKEN TO READ SECTOR ;& THE ERROR MASK JR Write.2 ;CONTINUE ELSE WHERE ; WRITE LD HL,0A8FCH ;TOKEN TO WRITE SECTOR ;& THE ERROR MASK ; Write.2 LD B,10 ;TEN TRIES ; W.Write PUSH BC ;SAVE THE NUMBER OF ;RETRIES CALL RedWrit ;READ OR WRITE THE ;SECTOR POP BC ;RETRIEVE # OF RETRIES RET Z ;NO ERRORS DJNZ W.Write ;TRY AGAIN ; XOR A ;CLEAR THE ACCUMULATOR INC A ;CLEAR THE ZERO FLAG ;AND RETURN THE ACCUM. ;WITH A 1 RET ;RETURN WITH ERROR ;FLAGS SET ; ;Seek the dseried track routine ; Seek IN A,Track ;GET THE LAST TRACK LD C,A ;SAVE IT IN C REG. LD A,(TRK) ;GET THE DESIRED TRACK CP 4DH ;TEST IF TO LARGE JP NC,END.DSK ;A error occured CP C ;TEST IF THE SAME RET Z ;SAME TRACK LD C,A ;SAVE THE DESIRED TRACK LD B,3 ;THREE TRIES ; R.Seek LD A,C ;GET THE DESIRED TRACK OUT Data,A ;OUTPUT DISIRED TRACK LD D,1FH ;TOKEN FOR SEEK CALL CmdI ;SEEK THE TRACK LD A,Stat ;GET THE STATUS AND 10H ;TEST FOR SEEK ERROR RET Z ;NO ERRORS LD D,0BH ;TOKEN TO HOME WITH ;HEAD ENGAGED CALL CmdI ;GO TO HOME DJNZ R.Seek ;TRY AGAIN ; LD A,20H ;TOKEN FOR SEEK ERROR JR DskErr ;ANOUNCE SEEK ERROR ; ;Check if correct drive is selected and select ;a new drive if necessary. ; DrvSet IN A,Select ;GET INFO ON THE DRIVES CPL ;INVERT THE DATA AND 0FH ;STRIP OTHER DATA OFF JR Z,DrSel ;NO DRIVE SELECTED LD C,0FFH ;ROTATE FACTOR ; DrvS0 INC C ;MAKE C RET 1 HIGHER RRA ;CARRYS ARE INCLUDED JR NC,DrvS0 ;LOOP TILL BITS ARE IN ;THE RIGHT SPOT ; LD A,(DRVBYT) ;Get the drive # AND 3 ;MAKE SHURE NUMBER IS ;RIGHT CP C ;COMPARE DESIRE AGAINST ;WHAT IS SELECTED RET Z ;THE SAME DRIVE ; ;Select desired drive ; DrSel LD A,(DRVBYT) ;GET DRIVE # AND 3 ;MAKE RIGHT OR A ;TEST FOR DRIVE 0 LD C,A ;SAVE DESIRED DRIVE LD A,1 ;SET FOR DRIVE 0 JR Z,DrSel3 ;IS DRIVE 0 ; DrSel2 RLCA ;MAKE UP DRIVE BYTE DEC C JR NZ,DrSel2 ;LOOP TILL DONE ; DrSel3 CPL ;INVERT DATA OUT Select,A ;SEND IT TO DRIVE PORT LD C,23H ;TOKEN FOR 23 MS WAIT ; M.Sec1 LD A,8EH ;TOKEN FOR 1 MS WAIT ; M.Sec2 DEC A JP NZ,M.Sec2 ;LOOP FOR 1 MS ; DEC C ;ONE LESS PASS JR NZ,M.Sec1 ;LOOP TILL DONE ; LD E,80H ;ERROR MASK IN A,Stat ;GET STATUS AND E ;TEST IF BUSY SCF ;Set flag the there ;has been a drive change RET Z ;NO PROBLEMS ; ;Error has occured ; POP AF ;REMOVE LAST CALLERS ;RETURN ADDRESS LD A,40H ;ERROR TOKEN JP DskErr ;HANDEL AS A ERROR ; ;MAIN READ OR WRITE ROUTINE ; ;H Reg. contains the read or write token ;L Reg. contains the error mask ; RedWrit LD (SVSP),SP ;Save callers return ;address CALL DrvSet ;CHECK AND SELECT THE ;PROPER DRIVE JR NC,SeekIt ;Drive change did not ;occure ; ;Turn select drive, read into memory Track and ;sector of the selected drive and update the ;disk controlers track register ; TrkFind LD A,1 ;Token command not ;complete LD (DrvChg),A ;Store the token PUSH HL ;Save commands LD HL,IDVS ;Where to store data LD DE,0C4F8H ;Command and Error mask LD BC,467H ;Bytes to read and ;Command CALL SetWait ;Setup wait states LD A,D ;Get Command OUT Cmd,A ;Output the command INIR ;Read the data POP HL ;Retreive callers ;Commands CALL Err.Ck ;Check for errors XOR A ;Get a Zero LD (DrvChg),A ;Command completed LD A,(IDVS) ;Get the track which ;the new disk is on OUT Track,A ;Output the track info ; SeekIt LD A,(DrvChg) ;Command completed ? OR A ;Test JR NZ,TrkFind ;Find the track CALL Seek ;SEEK THE DESIRED TRACK LD A,(Sctr) ;Get the desired sector OUT Sect.or,A ;SELECT DESIRED SECTOR ; ;Enable the wait states ; CALL SetWait ;Setup wait states ; ;Check to see if head is down ; LD D,H ;MOVE THE COMMAND TO ;D REG. LD E,L ;MOVE THE ERROR MASK ;TO E REG. LD A,0D0H ;TOKEN FOR FORCED ;INTERUPTS OUT Cmd,A ;SETUP FORCED INTERUPTS LD A,4 ;SETUP FOR SOME DELAY ; F.Wait DEC A JR NZ,F.Wait ;WAIT TILL TIME IS UP ; IN A,Stat ;GET STATUS AND 20H ;TEST IF HEAD WAS DOWN JR NZ,R.W.2 ;HEAD WAS DOWN SET 2,D ;LOAD HEAD BIT ; R.W.2 PUSH HL ;SAVE THE COMMAND ;AND ERROR MASK LD HL,(DMA) ;Get the transfer adr. LD B,80H ;NUMBER OF BYTES TO ;BE TRANSFERED ; LD A,D ;Move the command to ;the accumulator LD C,Data ;Disk data port BIT 5,A ;Read or write command? JR NZ,Write2 ;ITS A WRITE COMMAND ; ;Read a sector ; OUT Cmd,A ;Output the read command INIR ;Read the intire sector JR Write3 ;Continue else where ; ;Write a sector ; Write2 OUT Cmd,A ;Output write command OTIR ;Write the intire sector ; Write3 POP HL ;Retreive R/W token CALL Err.Ck ;Check for a error XOR A ;Set zero flag RET ; ;Set Up wait states routine ; SetWait IN A,Select ;Get the port info AND 1FH ;Setup for wait states OUT Select,A ;Setup wait states RET ; END ct ;Get the port info