koreth@ssyx.ucsc.edu (Steven Grimm) (05/25/88)
Submitted-by: uunet!mcvax!mirsa.inria.fr!colas (Colas Nahaboo) Posting-number: Volume 1, Issue 35 Archive-name: flip/part02 #--------------------------Cut Here-------------------------- #! /bin/sh # This is a shell archive. Remove anything before the "#! /bin/sh" line, # then unpack it by saving it in a file and typing "sh file." # # Wrapped by Steven Grimm (koreth) at ssyx on Tue May 24 15:54:23 1988 # # unpacks with default permissions # # Contents : MAKEFILE MAN.C README TWST.C # if `test ! -s MAKEFILE` then echo "x - MAKEFILE" cat > MAKEFILE << '@\Rogue\Monster\' VERSION=26b flip_$(VERSION).tos: flip.o twst.o man.o mmlink -o flip_$(VERSION).tos flip.o twst.o man.o imp: flip.o twst.o man.o mmimp flip.o mmimp twst.o mmimp man.o mmlink -o flip_$(VERSION).tos flip.o twst.o man.o @\Rogue\Monster\ else echo "shar: Will not over write MAKEFILE" fi if `test ! -s MAN.C` then echo "x - MAN.C" cat > MAN.C << '@\Rogue\Monster\' /* FLIP HISTORY & MANUAL */ /* HISTORY: *========= * 2.6b tells when copies an executable boot to detect virii * 2.6a bug de 'r' repaired * No checksum done if no previous checksum * option 's' for single instead of double (double=default) * v 2.6 27 fevrier 88 * 2.5c re-designing of command parsing * formats disk ('f' command) * randomization of serial # at each copy * 2.5b t can override disk * ESC aborts without confirm * 2.5a no ESC to another disk, BS! * aborts on key even in format * man in another C file * v 2.5 released * 2.4.5 write-protect detected * 2.4.3 option v to verify source only * multipass copies possible * 2.4.2 all sects# outputted on any kind of error. * twister modified to accept starttrack parameter * track_map to know what to copy * t option to specify track * r takes options fvV * 2.4.1 i for interactive: default no stop * V verify after format (case-sensitive options) * bug of verify reading into main buffer repaired * v 2.4: Jan 15 88 * 2.3.2 If esc on insert abort * track_read first * no more skip opt * # of sect printed * 2.3.1 Drive B presence is really tested * v 2.3: Dec 28 87 * 2.2.3 comparisons were not done!!! -- repaired * copy by 3 sectors * stops if copy sector only by 1 * 2.2.2 bug de a1a1 repare * 2.2.1 no verify by default * r for re-copy * v 2.2: Dec 19 87 * 2.1.1 prints buffer size on start * sector_read done 4 times with comparison! * RETURN repeats last command * v 2.1: Nov 28 87 * 2.0.1 retrys in writes and verify work now. * verify there is a drive B before copying * v 2.0: Nov 22 87 * 1.6.3 verify is another pass * 1.6.2 format does not verify anymore * format outputs a char * 1.6.1 uses TWISTER's code mmtwst.c to format * v 1.6: Nov 11 87 * 1.5.4 abort on ESC * option "2" for 2-sided. * 1.5.3 abort on key with confirm * 1.5.2 track, sectors begin at 1 instead of 0 * retrys on writes retry format-write-verify loop * on write errors, ESC to go to another disk * 1.5.1 port to megamax * uses all memory * v 1.5: more checking of entry syntax. * on-line help * fills bad sectors with 0s before writing * more sensible memory allocation * s option for auto skip * v 1.4: one automatic retry without prompting. If skips, copies good * sectors anyway. * v 1.3: when error on a track, asks for retrys, which are done sector * by sector. * v 1.2: when double sided, copy the two sides * v 1.1: whole side in memory for one drive use. * v 1.0: original one in mark williams. quick and really dirty. */ /* ON_LINE_MANUAL: *================ */ char *help_text[] = { "", " FLIP 2.6 manual", " Colas Nahaboo", "", " flip - disk copier with error-recovery, on either sides.", " with FAST formatting as TWISTER or DCFORMAT", "", "SYNTAX", " the commands are given as: (items in [] are optional)", "", " <source-drive>[<dest-drive>][fvVtios9] : copy disks", " f[<drive>][fvVtis9] : format disk", " v[<drive>][tios9] : verify disk", " r[<drive>][fvVi] : re-write disk in memory", " q : quits", " ? : help", "", " A drive is specified by the letter \"a\" or \"b\", followed optionally by", " \"1\" or \"2\" to indicate the side. (default drive is \"a\", side is \"1\")", "", "OPTIONS", " f - to format destination side", " V - verify disk by re-reading track just after being formatted.", " v - verify copy by re-reading track just after being written", " t - to specify what track(s) to copy (used with \"z\" to give the", " number of tracks of the new disk, default 80)", " i - interactive: ask user in case of error (default don't)", " o - override: do not look at the source disk boot sector to determine", " its type, take 10 sectors, 1 sided, 80 tracks, unless told", " otherwise by options \"9\", \"d\" or \"t\"", " 9 - disk is 9 sectors per track (default 10). Used with \"z\" or \"o\"", " s - disk is single-sided (default double). Used with \"z\" or \"o\"", "", "EXAMPLES", " ab2fv - to copy a non-protected SS disk in drive A on the unformatted", " back of a SS disk in drive B, verifying the copy.", " afv - (or fv) to copy ANY disk with format and verify, in drive A.", " rfv - to re-write last copy into drive A", " ffv - to format a double-sided disk in drive A", " fs - to erase all files of a previously formatted single sided disk", "", "OPERATION", " During copy, flip prints for each track, a:", " , for reading track without problem", " ; for reading track successfully after 4 retrys sector-by-sector", " - for formatting a track (in FAST format)", " v for verifying a track", "", " You can pause during the copy at any time by pressing a key, but pressing", " ESC will abort. ^C always quits.", "", " Without i option, on read error, it retries 4 times to read the track,", " then reads sector by sector. With option i, it prompts you for what to do:", " (the track and sector number given start at 1, but sector number at 0)", " - RETURN or SPACE retries. You'd better try to extract, then re-insert", " the disk to try to re-center it. (or try on another drive later)", " - \"s\" skips the bad sectors, going on with the rest of the copy.", " the bad sectors will be filled with 0s on the copy", " (but all that could be read is kept, of course!)", " - if it is writing the copy, you can press BACKSPACE if you want to try", " to write to another disk.", " - any other key aborts the copy.", " Experience shows that you can recover most of your damaged disks this way.", " If it cannot read the track, it reads it sector by sector, but tells you so", " because due to a bug in the TOS, a sector can be read incorrectly without", " giving an error. So FLIP does 4 reads of the same sector and compares", " them to be sure, but even if reads are equals, it warns you because the", " risk subsists, due to the bug in old TOS roms...", "", "DESCRIPTION", " The program copies TOS disks as a whole, and only non-protected", " ones. It can consider the back side of a single-sided disk as another disk", " so, it is very useful to use the back sides of protected disks, or", " single sided disks, such as MAGIC! ones. (with a two-side drive, of", " course!)", "", " But it also reads disks with care, being able to read CORRECTLY most disks", " causing a read error to copiers or the GEM desktop. Thus, if you get a", " read error on a disk, copy it with FLIP!. Moreover, if it cannot read a", " sector, it tells you so! (Unlike the HELP program)", "", " Version 2.6 can format and changes randomly the serial # of the disk", " when copying, (without the override option). It copies also executable", " boot sectors, but tells you so (in 2.6b) so that you can check for a VIRUS.", " it gives you the values at $3A offset to identify the virus", " Known virus values are: 41,FA,FF ", " ", " When it reads a disk, it first tries to read the boot sector in order", " to know the size (tracks and sectors per track) of the disk. If it", " can't make sense out of it, it uses 80 tracks by 9 sector, unless you", " used the \"o\" option", " Thus you don't have to tell him the type of the disk you want to copy.", " It will recognize double sided disks automatically, but you can only", " copy double sided disks, without flipping their faces!", "", " So, NEVER COPY A DISK WICH GIVES READ ERRORS WITH A BIT-COPIER (procopy)", " use FLIP instead!", "", " From version 2.0 on, FLIP format in FAST format, all disks accesses on", " this disk will be twice faster compared to a normal disk!. It ALWAYS ", " formats disks in 10 sectors, even if only to store 9 sectors.", " Be aware that I didn't test the validy of the formatting code on the", " new roms, so make some tests if you have them.", "", "COPYRIGHT", " This program is PUBLIC DOMAIN, and should be given with its sources", " Feel free to improve it!, but please mention my name.", " I would be very glad if you send me back any improved version, such as", " a GEM port", " CREDIT: It uses code from TWISTER from Dave SMALL & Dan MOORE.", "", "BUGS", " Not under GEM - yet!", " Cannot copy IBM boot sectors (use DCFORMAT)", "", "AUTHOR", " Colas NAHABOO", " 383 ch du clos d'Embertrand", " 06250 MOUGINS", " FRANCE.", " Personal phone: 93 75 68 29, give me a call...", " Electronic mail address: colas@mirsa.inria.fr", 0L }; #include "osbind.h" #include "stdio.h" more(text) char **text; { char **p = text, c; int line = 0; while (*p) { printf("%s\n", *p++); line++; if (line > 22) { printf("%cp more (SP, CR, BS or ESC) %cq", 27, 27); fflush(stdout); while (!Cconis()); c = Cnecin(); printf("%cM", 27); fflush(stdout); switch (c) { case 27: case 'q': printf("\n"); return; break; case ' ': line = 0; break; case 8: line = 0; p -= 48; if (p < text) p = text; printf("%cp...Backing 1 page...%cq\n", 27, 27); break; } } } printf("\n"); } @\Rogue\Monster\ else echo "shar: Will not over write MAN.C" fi if `test ! -s README` then echo "x - README" cat > README << '@\Rogue\Monster\' Flip is a small copier that I wrote for my personal use to: - use the back of SS disks - try to save data from damaged disks (getting frustrated with the abort message of DCFORMAT) Since I and my friends are using it all the time, it might be of use to some netlanders. As it was developed for my own use, it is not under GEM. It is in no way as great a program as is GULAM or UNITERM It is completly public domain, files are: (MEGAMAX C v1.1) binaries: flip_26b.tos the executable sources: makefile flip.c main code man.c manual & history twst.c formatter in in-line assembly, in fact TWISTER code slightly modified (MEGAMAX v1.1) @\Rogue\Monster\ else echo "shar: Will not over write README" fi if `test ! -s TWST.C` then echo "x - TWST.C" cat > TWST.C << '@\Rogue\Monster\' /* * Megamax C inline ASM version of Twister. * Converted from AS68 format dlm 12/14/86. * AS68 version by David Small before that date. * Used for the MegAMin HD backup program. * */ /* patched by colas for use with FLIP: * add params: * flipped: 0= no, 1=use back as front (must be SS then) * endtrack: 80 for normal disks * starttrack: 0 normally * outputs a '-' for each formatted cylinder (see PUTCHAR comments) * no more verify */ /* routine that are callable from C are: */ extern twister(); extern confirm_abort(); extern printf(); #include "osbind.h" #include "stdio.h" /* global variables */ int thedisk, dblsided, sectoroffset; /* input parameters */ int flipped, endtrack, starttrack, keypress; /* colas params */ long buffer; int badflag; /* bad sector error flag */ /* local variables */ static int theside, thetrack, twistsectorno, sectorno, retrycnt, cdev, ctrack, csect, cside, ccount, A7t, interlv, virgin, def_error, curr_err; static long cdma, edma, tmpdma, saveA2; static int saveA0, saveA1, saveD0; /* now the defines (AS68 equ's) */ /* tunable values */ #define retries 2 /* default # of retries -1 */ #define midretry 1 /* "middle" retry, when to reseek */ #define timeout 0x40000 /* short timeout, motor already on */ #define ltimeout 0x60000 /* long timeout, to startup motor */ /* Floppy state variables in DSB: RAM usage */ #define recal 0xff00 /* recalibrate flag */ #define dcurtrack 0 /* current track number */ #define dseekrt dcurtrack+2 /* seek rate */ #define dsbsiz dseekrt+2 /* size of a DSB */ /* hardware equates */ /* DMA chip */ #define diskctl 0xffff8604 /* disk controller data access */ #define fifo 0xffff8606 /* DMA mode control / status */ #define dmahigh 0xffff8609 /* DMA base high */ #define dmamid 0xffff860b /* DMA base mid */ #define dmalow 0xffff860d /* DMA base low */ /* 1170 select values */ #define cmdreg 0x80 /* select command register */ #define trkreg 0x82 /* select track register */ #define secreg 0x84 /* select sector register */ #define datareg 0x86 /* select data register */ /* GI sound chip (drive a/b select lines and side select) */ #define giselect 0xffff8800 /* (W) sound chip register select */ #define giread 0xffff8800 /* (R) sound chip read data */ #define giwrite 0xffff8802 /* (W) sound chip write data */ #define giporta 0x0e /* GI register # for i/o port A */ /* 68901 mfp chip */ #define mfp 0xfffffa00 /* mfp base */ #define gpip mfp+1 /* general purpose i/o */ /* misc defines */ #define seekrate 3 #define dsb0 0xa06 #define dsb1 0xa0a #define flock 0x43e char *abort_message = "\n\007KEY PRESSED! CR/SP = continue, other abort:\n"; asm { /* start of inline ASM */ /* * All the following is munged code from AS68 (that's why the * weird format). The AS68 code was munged from the BIOS * source. And most of this is from the FDC article in Start * issue number 3. * * Anyway, we apologize for the mess, but heh it works. * * Oh yes. The labels are usually on nops, not empty lines. Thats * because AS68 occasionally pukes on labels on empty lines. And * I didn't take the time to remove them. (Megamax doesn't care.) * */ ;**************************************************************** ; Twister: Faster formatter (zipformat) hack. MM version * ; Copyright (c) 1986, 1987 START Magazine (as usual) * ; Written by David Y. Small & Dan Moore * ;**************************************************************** ; ; Dedication: ; ; For Bill The Cat: because he's twisted, too. ; ;**************************************************************** ; ; code begins. ; ; PASS ME THIS STUFF DAN! Then SHAVE! For God's sakes! What ; are you trying to do, look like Fidel Castro? ; ; And get SOME BEER in here okay? Sheesh! ; ; input integers (if coming from C): ; ; dblsided: 0000 or ffff ; thedisk: 0 = a, 1 = b ;************************************************************* ;******************************************************** ; Frammatter ;******************************************************** twister: move.l A2, saveA2(A4) ; everything else saved by the Supexec clr.w badflag(A4) ; assume no errors ; ;*** Init vars for formatting loop ; move.w D0, saveD0(A4); move.w starttrack(A4), D0 ;start at starttrack move.w D0, thetrack(A4) move.w saveD0(A4), D0 ;WAS move.w #0,thetrack(A4) ; start at track 0 move.w #1,twistsectorno(A4) ; twister value move.w A0, saveA0(A4) move.w A1, saveA1(A4) trackloop: nop ; comes here for subseq tracks move.w saveA0(A4), A0 move.w saveA1(A4), A1 ;***** FRONT SIDE *********** ;**** Setup stack: .. based on read sec command, tweaked for frammat move.w #0xe5e5,-(A7) ; virgin data -- e5's work okay move.l #0x87654321,-(A7) ; magic # to make format work / fmt only move.w #1,-(A7) ; sector interleave factor / fmt only move.w flipped(A4),-(A7) ; ** side.w (relevant) / side: FRONT move.w thetrack(A4),-(A7) ; ** track.w (relevant) / same move.w #10,-(A7) ; sector.w (irrelevant) / sectors per track move.w thedisk(A4),-(A7) ; ** device.w (relevant) / same move.l #0,-(A7) ; dummy.l (irreleveant) / same move.l buffer(A4),-(A7) ; ** buffer address.l (relevant) / same jsr _flopfmt adda.l #24,A7 ; Fix stack. cmpi.w #0xffff, badflag(A4) ; aborts on error beq gemexit ;**** ; Jazz twistsectorno(A4). Look at what it ended up as; set it to ; the next track twist depending on that. ; ; It will end up as "+1" from the last sector formatted, because ; the formatter bumps it up. ; cmpi.w #1,twistsectorno(A4) ; 0-1 transition beq fgoto1 cmpi.w #9,twistsectorno(A4) ; 1-2 transition beq fgoto2 cmpi.w #7,twistsectorno(A4) ; 2-3 transition beq fgoto3 cmpi.w #5,twistsectorno(A4) ; 3-4 transition beq fgoto4 cmpi.w #3,twistsectorno(A4) ; 4-0 transition beq fgoto0 dc.b 0x4a dc.b 0xfc ; oops, die (illegal instruction) ;***** ; Really class coding, eh? Oh,well, it's easy and it works, which ; twelve other fancy ways of doing this *don't*. ; fgoto1: move.w #0x9,twistsectorno(A4) ; 9,a,1,2,3,4,5,6,7,8 bra fkeepformatting fgoto2: move.w #0x7,twistsectorno(A4) ; 7,8,9,a,1,2,3,4,5,6 bra fkeepformatting fgoto3: move.w #0x5,twistsectorno(A4) ; 5,6,7,8,9,a,1,2,3,4 bra fkeepformatting fgoto4: move.w #0x3,twistsectorno(A4) ; 3,4,5,6,7,8,9,a,1,2 bra fkeepformatting fgoto0: move.w #0x1,twistsectorno(A4) ; 1,2,3,4,5,6,7,8,9,a bra fkeepformatting nop ;***** fkeepformatting: nop ;***** ; now, do a verify on those sectors. ;**** Setup stack: .. based on read sec command, tweaked for frammat ; ; tst.w sectoroffset(A4) ; no verify if 11 to 20 sector ; ; numbering ; bne nover1 ; ; move.w #0xa,-(A7) ; count.w 2 ; move.w flipped(A4),-(A7) ; ** side.w (relevant) / side: FRONT 4 ; move.w thetrack(A4),-(A7) ; ** track.w (relevant) / same 6 ; move.w #0x1,-(A7) ; sector.w (relevant) / starting sector 8 ; move.w thedisk(A4),-(A7) ; ** device.w (relevant) / same 0xa ; move.l #0,-(A7) ; dummy.l (irreleveant) / same 0xe ; move.l buffer(A4),-(A7) ; ** buffer address.l (relevant) / same 0x12 ; ; move.w #19,-(A7) ; do BIOS _flopver 0x14 ; trap #14 ; adda.l #20, A7 ; fix stack. ; ; tst.l D0 ; bne badsecs ; ;**** ;***** BACK SIDE ****** (How kinky Dave. What _are_ you talking about?) nover1: tst.w dblsided(A4) beq nobackside ;**** Setup stack: .. based on read sec command, tweaked for frammat move.w #0xe5e5,-(A7) ; virgin data -- e5's work okay ; and with a virgin. My, you really are weird Dave. move.l #0x87654321,-(A7) ; magic # to make format work / fmt only move.w #1,-(A7) ; sector interleave factor / fmt only move.w #1,-(A7) ; ** side.w (relevant) / side: BACK move.w thetrack(A4),-(A7) ; ** track.w (relevant) / same move.w #10,-(A7) ; sector.w (irrelevant) / sectors per track move.w thedisk(A4),-(A7) ; ** device.w (relevant) / same move.l #0,-(A7) ; dummy.l (irreleveant) / same move.l buffer(A4),-(A7) ; ** buffer address.l (relevant) / same jsr _flopfmt adda.l #24,A7 ; Fix stack. cmpi.w #0xffff, badflag(A4) ; aborts on error beq gemexit ;***** ; ; Jazz twistsectorno(A4). Look at what it ended up as; set it to ; the next track twist depending on that. ; ; It will end up as "+1" from the last sector formatted, because ; the formatter bumps it up. ; cmpi.w #1,twistsectorno(A4) ; 0-1 transition beq goto1 cmpi.w #9,twistsectorno(A4) ; 1-2 transition beq goto2 cmpi.w #7,twistsectorno(A4) ; 2-3 transition beq goto3 cmpi.w #5,twistsectorno(A4) ; 3-4 transition beq goto4 cmpi.w #3,twistsectorno(A4) ; 4-0 transition beq goto0 dc.b 0x4a dc.b 0xfc ; oops, die ; goto1: move.w #0x9,twistsectorno(A4) ; 9,a,1,2,3,4,5,6,7,8 bra keepformatting goto2: move.w #0x7,twistsectorno(A4) ; 7,8,9,a,1,2,3,4,5,6 bra keepformatting goto3: move.w #0x5,twistsectorno(A4) ; 5,6,7,8,9,a,1,2,3,4 bra keepformatting goto4: move.w #0x3,twistsectorno(A4) ; 3,4,5,6,7,8,9,a,1,2 bra keepformatting goto0: move.w #0x1,twistsectorno(A4) ; 1,2,3,4,5,6,7,8,9,a bra keepformatting nop ; keepformatting: nop ; entry after twisting. ; ; ; ;**** Setup stack: .. based on read sec command, tweaked for frammat ; ; tst.w sectoroffset(A4) ; no verify for strange sector numbers ; bne nobackside ; ; move.w #0xa,-(A7) ; count.w 2 ; move.w #1,-(A7) ; ** side.w (relevant) / side: BACK 4 ; move.w thetrack(A4),-(A7) ; ** track.w (relevant) / same 6 ; move.w #0x1,-(A7) ; sector.w (relevant) / starting sector # 8 ; move.w thedisk(A4),-(A7) ; ** device.w (relevant) / same 0xa ; move.l #0,-(A7) ; dummy.l (irreleveant) / same 0xe ; move.l buffer(A4),-(A7) ; ** buffer address.l (relevant) / same 0x12 ; ; move.w #19,-(A7) ; do BIOS _flopver 0x14 (why not) ; trap #14 ; adda.l #20, A7 ; fix stack ; ; tst.l D0 ; bne badsecs ; wham ; ;**** nobackside: nop ; entry if not DS (well at least this isn't kinky Dave) ; add 1 to thetrack. If endtrack, quit. addi.w #1, thetrack(A4) move.w A0, saveA0(A4) move.w A1, saveA1(A4) move.w D0, saveD0(A4) /* PUTCHAR */ move.w #0x2D, -(A7) /* outputs a '-' */ move.w #6, -(A7) trap #1 adda.l #4, A7 move.w #0xB, -(A7) /* CNONIS */ trap #1 adda.l #2, A7 cmpi.w #0,D0 bne key_pressed /* aborts on keypress */ resume: move.w saveD0(A4), D0 /* PUTCHAR end */ move.w endtrack(A4), A0 move.w thetrack(A4), A1 cmpa A0, A1 bne trackloop ; "do another" move.w saveA0(A4), A0 move.w saveA1(A4), A1 bra gemexit ; Continue, etc, and so forth ;********* key_pressed: MOVE.w #8,-(A7) trap #1 ADDa.L #2,A7 CMPI.w #27,D0 beq key_abort move.l abort_message(A4),-(A7) move.w #9,-(A7) trap #1 ADDa.L #6,A7 MOVE.w #8,-(A7) trap #1 ADDa.L #2,A7 CMPI.w #32,D0 beq resume CMPI.w #10,D0 beq resume CMPI.w #13,D0 beq resume key_abort: MOVE.w #1,keypress(A4) move.w saveD0(A4), D0 bra gemexit ;********* badsecs: move.w #0xffff, badflag(A4) ; bad sectors found ;************** ; ; End. Exit to calling routine. ; gemexit: movea.l saveA2(A4), A2 ; only reg not saved by Supexec rts ;****************************************************** ; ;------------------------------------------------------------------------ ; 130-ST / 520-ST ; Floppy Disk Driver ; (C)1985 Atari Corp. ; From the FDC article (Start issue 3); shortened to just ; the formatter routine and the low level I/O. ; ;------------------------------------------------------------------------ ; ;************************************************************ ; ; _flopfmt - format a track ; Passed (on the stack): ; 0x1a(A7) initial sector data ; 0x16(A7) magic number ; 0x14(A7) interleave ; 0x12(A7) side ; 0x10(A7) track ; 0xe(A7) A7t(A4) ; 0xc(A7) drive ; 0x8(A7) pointer to state block ; 0x4(A7) dma address ; 0x0(A7) [return] ; ; Returns: EQ: track successfully written. Zero.W-terminated list of ; bad sectors left in buffer (they might /all/ be bad.) ; ; NE: could not write track (write-protected, drive ; failure, or something catastrophic happened). ;- _flopfmt: cmpi.l #0x87654321, 0x16(A7) ; check for magic# on stack bne flopfail ; no magic, so we just saved the world ; bsr change ; check for disk flip ; moveq #e_error,D0 ; set default error number bsr floplock ; lock floppies, setup parms bsr select ; select drive and side move.w 0xe(A7),A7t(A4) ; save sectors-per-track move.w 0x14(A7),interlv(A4) ; save interleave factor move.w 0x1a(A7),virgin(A4) ; save initial sector data ;--- put drive into "changed" mode ; moveq #m_changed,D0 ; D0 = "CHANGED" ; bsr setdmode ; set media change mode ;--- seek to track (hard seek): ;debug* move.l #0xff00ff00,0xf8030 bsr hseek ; hard seek to 'ctrack' ;debug* move.l #0x00000000,0xf8030 bne flopfail ; (return error on seek failure) move.w ctrack(A4),dcurtrack(A1) ; record current track# ;--- format track, then verify it: ;* move.w #e_error,curr_err(A4)(A5) ; vanilla error mode ;debug* move.l #0xff00ff00,0xfA030 bsr fmtrack ; format track ;debug* move.l #0x0,0xfA030 bne flopfail ; (return error on seek failure) bra flopok ;**************************** ;+ ; fmtrack - format a track. Tweaked for skewed interleave. ; ; Passed: variables setup by _flopfmt ; Returns: NE on failure, EQ on success ; Uses: almost everything ; Called-by: _flopfmt ; ;- fmtrack: ;* move.w #e_write,def_error(A4) ; set default error number move.w #1,D3 ; start with sector 1, first pass ;** movea.l cdma(A4),A2 ; A2 = prototyping area ; Lay down beginning of track move.w #60-1,D1 ; 60 x 0x4e (track leadin) move.b #0x4e,D0 bsr wmult ; Repeat 10 times: sector data. move.w #1,sectorno(A4) ; how many secs written ; Note that twistsectorno is initialized out of this routine. ;--- address mark secloop: nop ; ot1: move.w #12-1,D1 ; 12 x 0x00 clr.b D0 bsr wmult move.w #3-1,D1 ; 3 x 0xf5 move.b #0xf5,D0 bsr wmult move.b #0xfe,(A2)+ ; 0xfe -- address mark intro move.b ctrack+1(A4),(A2)+ ; track# - low half of word move.b cside+1(A4),(A2)+ ; side# - low half of word ;* #1: just use a plain sector number ;* move.b D4,(A2)+ ; sector# ;* #2: use a twisted sector number ;* move.b twistsectorno+1(A4),(A2)+ ; new: sector #. move.w twistsectorno(A4),D0 ; fetch 1-10 sector # ; ; Note that meg-a-minute backup uses sectors # 11-20 to force GEM ; not to use MM disks. ; add.w sectoroffset(A4),D0 ; add possible shift to 11-20 sector # move.b D0,(A2)+ ; plug it into sector table ; Add 1 to sector #. If it is b, wrap it to 1. addi.w #1,twistsectorno(A4) ; real sector # being plopped cmpi.w #0xb,twistsectorno(A4) bne notb move.w #1,twistsectorno(A4) ; notb: nop move.b #0x02,(A2)+ ; sector size (512) move.b #0xf7,(A2)+ ; write checksum ;--- gap between AM and data: move.w #22-1,D1 ; 22 x 0x4e move.b #0x4e,D0 bsr wmult move.w #12-1,D1 ; 12 x 0x00 clr.b D0 bsr wmult move.w #3-1,D1 ; 3 x 0xf5 move.b #0xf5,D0 bsr wmult ;--- data block: move.b #0xfb,(A2)+ ; 0xfb -- data intro move.w #256-1,D1 ; 256 x virgin.w (initial sector data) ot2: move.b virgin(A4),(A2)+ ; copy high byte move.b virgin+1(A4),(A2)+ ; copy low byte dbf D1,ot2 ; fill 512 bytes move.b #0xf7,(A2)+ ; 0xf7 -- write checksum move.w #40-1,D1 ; 40 x 0x4e move.b #0x4e,D0 bsr wmult ; ; Next sector, or, end-of-track. If we hit sector 11, time to quit. ; addi.w #1,sectorno(A4) cmpi.w #11,sectorno(A4) bne secloop ; loop again ; ; Okay, 10 sectors laid down. ; ;--- end-of-track move.w #1400,D1 ; 1401 x 0x4e -- end of track trailer move.b #0x4e,D0 bsr wmult ;--- setup to write the track: move.b cdma+3(A4),dmalow ; load dma pointer move.b cdma+2(A4),dmamid move.b cdma+1(A4),dmahigh move.w #0x190,(A6) ; toggle R/W flag and move.w #0x090,(A6) ; select sector-count register move.w #0x190,(A6) move.w #0x1f,D7 ; (absurd sector count) bsr wdiskctl move.w #0x180,(A6) ; select 1770 cmd register move.w #0xf0,D7 ; write format_track command ;debug* move.l #0xff00ff00,0xfc030 bsr wdiskctl move.l #timeout,D7 ; D7 = timeout value ;--- wait for 1770 to complete: otw1: btst.b #5,gpip ; is 1770 done? beq otw2 ; (yes) subq.l #1,D7 ; if(--D7) continue; bne otw1 ;debug* move.l #0xffffffff,0xfc030 bsr reset1770 ; timed out -- reset 1770 oterr: moveq #1,D7 ; return NE (error status) rts ;--- see if the write-track won: otw2: nop ;debug* move.l #0x0,0xfc030 move.w #0x190,(A6) ; check DMA status bit move.w (A6),D0 btst #0,D0 ; if its zero, there was a DMA error beq oterr ; (so return NE) move.w #0x180,(A6) ; get 1770 status bsr rdiskctl ;** bsr err_bits ; set 1770 error bits and.b #0x44,D0 ; check for writeProtect & lostData rts ; return NE on 1770 error ;------ write 'D1+1' copies of D0.B into A2, A2+1, ... wmult: move.b D0,(A2)+ ; record byte in proto buffer dbf D1,wmult ; (do it again) rts ; ;************************************************************ ; ; floplock - lock floppies and setup floppy parameters ; ; Passed (on the stack): ; 0x18(A7) - count.W (sector count) ; 0x16(A7) - side.W (side#) ; 0x14(A7) - track.W (track#) ; 0x12(A7) - sect.W (sector#) ; 0x10(A7) - dev.W (device#) ; 0xc(A7) - obsolete.L ; 8(A7) - dma.L (dma pointer) ; 4(A7) - ret1.L (caller's return address) ; 0(A7) - ret.L (floplock's return address) ; ; It is not coincidence that this matches the read and write input list; ; they call us to get stuff off stack and plug into parameters. Then, ; routine "select" actually pops this stuff into hardware. ; ; Passed: D0.W = default error number ; ; Also, we helpfully point A6 at the DMA chip, and A1 at the DSB. ;- floplock: lea regsave, A0 movem.l D3-D7/A3-A6, (A0) ; save C registers lea fifo,A6 ; A6 -> fifo ; Start setting up param block.. move.w D0,def_error(A4) ; set default error number move.w D0,curr_err(A4) ; set current error number ; Kick VBL off floppies.. move.w #1,flock ; tell vbl not to touch floppies ; Stuff off stack: move.l 8(A7),cdma(A4) ; cdma -> /even/ DMA address move.w 0x10(A7),cdev(A4) ; save device# (0 .. 1) move.w 0x12(A7),csect(A4) ; save sector# (1 .. 9, usually) move.w 0x14(A7),ctrack(A4) ; save track# (0 .. 39 .. 79 ..) move.w 0x16(A7),cside(A4) ; save side# (0 .. 1) move.w 0x18(A7),ccount(A4) ; save sector count (1..A) ;--- pick a DSB: Point A1 at it. lea dsb0,A1 ; pick dsb 0 (drive A) tst.w cdev(A4) beq flock2 lea dsb1,A1 ; pick dsb 1 (drive B) ;--- compute ending DMA address from count parameter: Plug into edma. ; This is used in multisector transfers in read-multiple-sector, ; but we don't use it here. flock2: moveq #0,D7 move.w ccount(A4),D7 ; edma = cdma + (ccount * 512) lsl.w #8,D7 lsl.w #1,D7 ; do a 9 shift.. movea.l cdma(A4),A0 adda.l D7,A0 move.l A0,edma(A4) ; save in edma ;--- recalibrate drive, if it needs it. This only happens when the DSB ; says that this drive has never awoken before, and needs an initial ; recal to match its current track # with the DSB track #. tst.w dcurtrack(A1) ; if (curtrack < 0) recalibrate() bpl flockr ; RECAL needed. Show flag about it.. move.l #0xf0f0f0f0,0xfe000 move.l #0xf0f0f0f0,0xfe004 bsr select ; select drive & side clr.w dcurtrack(A1) ; we're optimistic -- assume winnage ; Restore. bsr restore ; attempt restore beq flockr ; (it won) moveq #10,D7 ; attempt seek to track 10 bsr hseek1 bne flock1 ; (failed) bsr restore ; attempt restore again beq flockr ; (it won) ; flock1: move.w #recal, dcurtrack(A1) ; complete failure (what can we do?) movem.l regsave(PC), D3-D7/A3-A6 flockr: rts ; ;******************************************************************** ;+ ; flopfail - unlock floppies and return error. ; Common way for read and write to return. ; ; Note: Returns via unlok1. ;- flopfail: move.w #0xffff, badflag(A4) ; bad sectors found move.l #0xffffffff,D0 ; aargh, error bra unlok1 ;*************************************************** ;+ ; flopok - unlock floppies and return success status. Also a common ; way for r/w to return. ; ;- flopok: clr.l D0 ; return 0 (success) ; Entry point from flopfail.. unlok1: move.l D0,-(A7) ; (save return value) ; I believe this code returns the FDC's status to a type-1 status, where ; the write protect switch is available for VBL to look at. move.w #datareg,(A6) ; force WP to real-time mode ; Sets FDC's current track register to track we are on right now. move.w dcurtrack(A1),D7 ; dest-track = current track bsr wdiskctl ; Does it with a "noop seek" (source=dest). Only forces FDC to type 1 status. move.w #0x10,D6 ; cmd = seek w/o verify bsr flopcmds ; do it ; unlok2: move.l (A7)+,D0 ; restore return value movem.l regsave(PC), D3-D7/A3-A6 ; clear floppy lock of vblank.. clr.w flock ; allow vblank .. unlock floppies ; wave byebye at the pretty camera, jenny... rts ;************************ Seek routines ******************** ;+ ; hseek - seek to 'ctrack(A4)' without verify ; hseek1 - seek to 'D7' without verify ; hseek2 - seek to 'D7' without verify, keep current error number ; ; Returns: NE on seek failure ("cannot happen"?) ; EQ if seek wins ; ; Uses: D7, D6, ... ; Exits to: flopcmds ; Called-by: _flopfmt, _flopini ; ;- hseek: move.w ctrack(A4),D7 ; dest track = 'ctrack' hseek1: nop hseek2: move.w #datareg,(A6) ; write destination track# to data reg bsr wdiskctl ; write D7 to FDC data register ; seek command: move.w #0x10,D6 ; execute "seek" command ; * Note: no spinup time. bra flopcmds ; (without verify...) ; ;*********************************************** ;+ ; reseek - home head, then reseek track ; Returns: EQ/NE on success/failure ; Falls-into: go2track ; ;- reseek: bsr restore ; restore head bne go2trr ; (punt if home fails) clr.w dcurtrack(A1) ; current track = 0 move.w #trkreg,(A6) ; set "current track" reg on 1770 clr.w D7 bsr wdiskctl ; write a 00 to trk register. move.w #datareg,(A6) ; seek out to track five move.w #5,D7 bsr wdiskctl ; dest track = 5 move.w #0x10,D6 bsr flopcmds ; seek ; * Note: no spinup time. bne go2trr ; return error on seek failure move.w #5,dcurtrack(A1) ; set current track# ;***********************************************+ ; go2track - seek proper track ; Passed: Current floppy parameters (ctrack, et al.). ; Returns: EQ/NE on success/failure ; Calls: flopcmds ; Called by: read sector, for instance. Lots of places. ;- go2track: move.w #datareg,(A6) ; set destination track# in move.w ctrack(A4),D7 ; 1770's data register bsr wdiskctl ; (write track#) moveq #0x14,D6 ; execute 1770 "seek_with_verify" bsr flopcmds ; (include seek-rate bits) bne go2trr ; return error on seek failure move.w ctrack(A4),dcurtrack(A1) ; update current track number and.b #0x18,D7 ; check for RNF, CRC_error, lost_data go2trr: rts ; return EQ/NE on succes/failure ;************************************************* ;+ ; restore - home head ; Passed: nothing ; Returns: EQ/NE on success/failure ;- restore: clr.w D6 ; 0x00 = 1770 "restore" command bsr flopcmds ; do restore bne res_r ; punt on timeout btst #2,D7 ; test TRK00 bit eori.w #0x04, CCR ; flip Z bit (return NE if bit is zero) bne res_r ; punt if didn't win clr.w dcurtrack(A1) ; set current track# res_r: rts ;**************************************************** ; Special floppy cmd just for seeking: ;+ ; flopcmds - floppy command (or-in seek speed bits from database) ; Passed: D6.w = 1770 command ; Sets-up: seek bits (bits 0 and 1) in D6.w ; Falls-into: flopcmd ; Returns: EQ/NE on success/failure ; ; I get the impression this is only used for seeking. I am right. ;- flopcmds: move.w dseekrt(A1),D0 ; get floppy's seek rate bits andi.b #3,D0 ; OR into command or.b D0,D6 ; Fall in... ;******************************************************+ ; flopcmd - execute any ol' 1770 command (with timeout) ; Passed: D6.w = 1770 command ; ; Returns: EQ/NE on success/failure ; D7 = 1770 status bits ; ; Note: does motor spinup, if cmd in D6 specs it (I would *hope*!) ;- flopcmd: move.l #timeout,D7 ; setup timeout count (assume short) move.w #cmdreg,(A6) ; select 1770 command register bsr rdiskctl ; read it to clobber READY status btst #7,D0 ; is motor on? bne flopcm ; (yes, keep short timeout) move.l #ltimeout,D7 ; extra timeout for motor startup flopcm: bsr wdiskct6 ; write command (in D6) flopc1: subq.l #1,D7 ; timeout? beq flopcto ; (yes, reset and return failure) btst.b #5,gpip ; 1770 completion? bne flopc1 ; (not yet, so wait some more) bsr rdiskct7 ; return EQ + 1770 status in D7 clr.w D6 rts ;**** flopcto: ; We timed out.. a gruesome death indeed. ; Whap controller back to life. (Hit him harder Dave, he likes it that way) bsr reset1770 ; bash controller moveq #1,D6 ; and return NE rts ;******************************************************* ;+ ; reset1770 - reset disk controller after a catastrophe ; Passed: nothing ; Returns: nothing ; Uses: D7 ;- reset1770: move.w #cmdreg,(A6) ; execute 1770 "reset" command move.w #0xD0,D7 ; force interrupt bsr wdiskctl move.w #15,D7 ; wait for 1770 to stop convulsing r1770: dbf D7,r1770 ; (short delay loop) bsr rdiskct7 ; return 1770 status in D7 rts ;****************************************************** ;+ ; select - setup drive select, 1770 and DMA registers ; Passed: cside(A4), cdev(A4) ; Returns: appropriate drive and side selected ; ; Called: All over the place. ; ;- select: move.w #0,0x9c0 ; floppies NOT deselected ; * lets VBL shut them off... move.w cdev(A4),D0 ; get device number addq.b #1,D0 ; add and shift to get select bits lsl.b #1,D0 ; into bits 1 and 2 or.w cside(A4),D0 ; or-in side number (bit 0) eori.b #7,D0 ; negate bits for funky hardware select andi.b #7,D0 ; strip anything else out there bsr setporta ; do drive select ; Have to restore 1770's track register from table..in dsb. move.w #trkreg,(A6) ; setup 1770 track register move.w dcurtrack(A1),D7 ; from current track number bsr wdiskctl clr.b tmpdma(A4) ; zero bits 24..32 of target DMA addr ; Setup R/W parameters on 1770. Used by ; r/w sector, among others. This is where the sector register gets set. ; select1: move.w #secreg,(A6) ; setup requested sector_number from move.w csect(A4),D7 ; caller's parameters bsr wdiskctl move.b cdma+3(A4),dmalow ; setup DMA chip's DMA pointer move.b cdma+2(A4),dmamid move.b cdma+1(A4),dmahigh rts ;************************************************ ;+ ; setporta - set floppy select bits in PORT A on the sound chip ; Passed: D0.b (low three bits) ; Returns: D1 = value written to port A ; D2 = old value read from port A ; Uses: D1 ;- setporta: move SR,-(A7) ; save our IPL ori #0x0700,SR ; start critical section move.b #giporta,giselect ; select port on GI chip move.b giread,D1 ; get current bits move.b D1,D2 ; save old bits for caller andi.b #0xff-7,D1 ; strip low three bits there or.b D0,D1 ; or-in our new bits move.b D1,giwrite ; and write 'em back out there move (A7)+,SR ; restore IPL to terminate CS, return rts ;************************************************** ;+ ; Primitives to read/write 1770 controller chip (DISKCTL register). ; ; The 1770 can't keep up with full-tilt CPU accesses, so ; we have to surround reads and writes with delay loops. ; This is not really as slow as it sounds. ; wdiskct6: ; write D6 to diskctl bsr rwdelay ; delay move.w D6,diskctl ; write it bra rwdelay ; delay and return wdiskctl: ; write D7 to diskctl bsr rwdelay ; delay move.w D7,diskctl ; write it bra rwdelay ; delay and return rdiskct7: ; read diskctl into D7 bsr rwdelay ; delay move.w diskctl,D7 ; read it bra rwdelay ; delay and return rdiskctl: ; read diskctl into D0 bsr rwdelay ; delay move.w diskctl,D0 ; read it ; And here's the delay loop: rwdelay: move SR,-(A7) ; save flags move.w D7,-(A7) ; save counter register move.w #0x20,D7 ; 0x20 seems about right... rwdly1: dbf D7,rwdly1 ; busy-loop: give 1770 time to settle move.w (A7)+,D7 ; restore register, flags, and return move (A7)+,SR rts ;------------------------------------- regsave: dc.l 1 ; PC relative data area dc.l 2 dc.l 3 dc.l 4 dc.l 5 dc.l 6 dc.l 7 dc.l 8 dc.l 9 } /* MY GOD! It's DONE! */ @\Rogue\Monster\ else echo "shar: Will not over write TWST.C" fi echo "Finished archive 2 of 2" # to concatenate archives, remove anything after this line exit 0