T H E M E C H A N I C S O F D I S K A C C E S S By Phil!93 If you've ever tried writing a routine to read the disk drives directly from hardware you'll know that it can be a a right err, pig. There are quite a few areas where critical time delays must be observed and the involvement of those Completely Incomprehesable Adapters (CIAs) doesnt jolly along the process much! The hardware reference manual has only the briefest of coverage to the disk-interface so I hope to fill in the gaps a bit. Once you've identified the registers that are required for disk access and sorted out the timing loops everything becomes clear - Tab clear. The are only 2 cia registers involoved in the "mechanics" of disk access and first up is $BFD100. Here's the run down; Bit 7-MTR - Motor On/Off line * 6-SEL3-Select drive 3: df3 * 5-SEL2-Select drive 2: df2 * 4-SEL1-Select drive 1: df1 * 3-SEL0-Select drive 0: df0 * 2-SIDE-Disk side to access.* 1-DIR -Direction to move heads 0-STEP-Step those heads! * * The motor,select,side and step bits are "active low" which means that to activate the "device" using that bit, you write a 0 into that bit location instead of the usual 1. Now more info about each of these bits in turn. BIT 7, MRT - The motor line is a funny fish. This is non-standard on the Amiga. A drive will latch the value of this bit into its own flip/flop whenever its select bit is turned on. And drives remember the state of their motors when they arent selected. So to switch on the motor in the internal drive you could do this: a. bclr #7,$bfd100 - motor line on. b. bclr #3,$bfd100 - select df0 c. bset #7,$bfd100 - motor line off d. bset #3,$bfd100 - deselect df0 The motor actually switches on after line b has been executed by the CPU. Notice that it doesnt matter that the motor line is switched off (at c) cus the drive has already latched (stored) the on motor value. Also it doesnt matter that the drive is deselected because it will remember its motor latch value. To switch off the motor you could use: a. bset #7,$bfd100 - motor line off b. bclr #3,$bfd100 - select df0 c. bset #3,$bfd100 - deselect df0 BITS 6-3, (SEL3-0) - These are the select lines for the drives. Any drive that has a 0 in its respective bit location will become "active" (even though its motor may not be on) - its possible to have more than one drive selected at a time but you have to be careful that you are getting the status info (see below) from the drive you want. BIT 2, SIDE - Just tells the Drive which head it should use and therefore which disk side to read from. A 0 here means use the upper head and a 1 the lower head. Also see timing info. BIT 1, DIR - Tells the drive which direction it should step the heads when the STEP bit is pulsed (see below). A 0 means step inwards (toward track 79) and a 1 therefore means step outwards towards track 0 (the one with the boot block!). BIT 0, STEP - This bit actually causes the heads to be stepped up or down the disk. It is an active low line and it should always be sent a pulse, first a 0, then a 1. A NOP between setting the line to 0 then 1 should be enough for the drive to realise you want the heads stepped. The head actually moves within 3 microseconds of receiving the 1. Remember that the head is a mechanical creature and therefore requires a time to actually move and settle after doing so (see timing info). So that's $bfd100 taken care of, the second cia location that deals with the drives is: $BFE001. BITS 7 & 6 are not used for disk access. BIT 5 - RDY: Disk ready or ID stream. BIT 4 - TK0: Active when head over track0 BIT 3 - WRPRO: Disk is write protected. BIT 2 - CHNG: Disk removed/changed. BITS 1 & 0 are not used for disk access. All the above disk bits are active low The data in these bits is relevant to the selected drive. Now for an in depth look at each bit's meaning. BIT 5, RDY - This actually has two uses. If the motor in the selected drive is on then a 0 here means that a disk is inserted and the motor is up to speed. If the motor is off, this bit acts as an identification stream to enable you so find out what drives are connected to the Amiga (See example later). BIT 4, TK0. A Nice simple one. If the heads on the selected drive are positioned over track 0 then a zero is presented here. BIT 3, WRPRO - Simple again. If the disk inserted in the selected drive is write protected then a zero appears here. BIT 2, CHNG. If you select a drive that has had a disk removed/changed this becomes zero. THAT drive will not return a 1 to this bit until a disk in inserted in it and its heads are stepped. This is why Amiga drives click when there's no disks in 'em! So with the CIA addresses taken care of we must consider timing. As I said before drives are mecahnical devices and require time to settle/respond etc. The timing requirements are as follows; Head stepping delay - Drives are guarrenteed to step the head within 3 milliseconds (.003 seconds). Head settling time (before disk access): 15 milliseconds should be allowed before disk access after the last step. When reversing the direction of the head 18 milli-seconds should be allowed after the last step pulse. Disk side selection - This signal must be stable for at least 100 micro- seconds before disk access. And 1.3 milliseconds must elapse before switching sides. Anyone who's thinking of using a simple counter loop for the timings- FORGET IT! Instant A1200 incompatibilty is probably all you'll achieve! Not all Amigas have a 68000 running at 7.14Mhz you know! One method of timing that will work on any Amiga model is to wait for x raster lines. You can find a conveniant raster line counter in $bfd800. A better if more complex method is to use the CIA timers (which run at 715.379 Khz on PAL Amigas and 715.909 on NTSC Amigas -So long as you are a bit generous with your timings you should be OK in the USA!). Using these timers allows you to issue an interupt at the end of your delay if you want. Anyway, the timers are 16 bit, ie: they can count 65535 clock pulses before wrapping to 0. There are 4 of these in all, 2 in each cia (Bfd400/500 and Bfd600/700 and Bfe401/501 and bfe601/701). These timers can be set up so that when you write to these addresses the Cia uses your value as a figure to count down from to 0, then sets an interrupt flag, whether this actually causes an interrupt depends on the settings of the IRQ mask. Cia_a causes a lev 2 irq and cia_b causes a lev 6 irq. So to do a simple busy wait delay using CIAb, timer B, the method is:- move.l #$bfd000,a0 ;cia_b base move.w #TimerValue,d0 ;countdown move.b d0,$600(a0) ;set lo byte lsr.w #8,d0 move.b d0,$700(a0) ;set hi byte move.b #%00011001,$f00(a0) ;start loop btst #1,$d00(a0) ;wait for time beq.s loop ;to elapse OTHER CONSIDERATIONS Obvious this, but theres no way of knowing where the head is apart from stepping the head to zero, once you know this you can set up a track marker variable and just step the head to where you want it to go with a vector (+/- x tracks). I read somewhere that swapping disks can shift the head on some drives so you may want to reinitialize the head back to zero whenever a disk is changed (Amiga Dos does this to find info on the dos type etc anyway). The Head Direction must be set up before the step pulse is issued. Don't set both operations into one instruction. Stick a NOP or two between the instructions as well if you like. Dont try to step the heads beyond track 0, too much of this could result in a knackered drive. After starting the motor, wait for the RDY to become active before accessing this disk - This could be up to 500 milliseconds. Don't over do the head step delay! It won't cause any damage but its sounds terrible! Especially when moving the heads over more than a few tracks. If you're tinkering about with the drive hardware make sure the system and any unwanted interrupts are off! IDENTIFYING AVAILABLE DRIVES Its amazing how many disk routines still ingnore the presence of any external drives - forcing you to swap disks even when there's no need. The fact is that its a piece of piss to check for external drives. The method for identifying drives is: a. Select the drive to check. b. Switch its motor on then off. c. (Re)select the drive to check. d. Read the DISK_RDY bit and store in a 32 bit shift register. e. Deselect drive & loop back to b 32 times. f. Invert the shift register. This will provide you with a I.D. longword which will be either: a. $00000000 - No drive present. b. $FFFFFFFF - Amiga 3.5" Drive. There are other IDs but these are the only ones we're interested in. Normally you only want to check for DF1: so here's some source code to do just that: move.l #$bfd100,a0 ;cia we need. move.b #$7f,(a0) bclr #4,(a0) ;df1: motor on. - wait - move.b #$ff,(a0) ;df1: motor off bclr #4,(a0) Moveq #$1f,d7 ;loop 32 times. moveq #$00,d0 nxt lsl.l #1,d0 bclr #4,(a0) ;select df1: btst #5,$f01(a0) ;read RDY. beq skp ori.w #1,d0 skp bset #4,(a0) ;deselect df1: dbf d7,nxt not.l d0 cmpi.l #$ffffffff,d0 beq DF1available df1notavailable.... code..... df1available rest of code...... The wait should be at least .5 seconds I know that was a very long winded way of coding it. But I wanted to follow the "method text" more or less to the letter. Actually doing the DMA to read and write has been covered loads of times and the MFM layout of a disk was on GV15 so theres no need to repeat it here. If you want to write to me, see my ad in the Advert section.