1 /*
2   Hatari - fdc.c
3 
4   This file is distributed under the GNU General Public License, version 2
5   or at your option any later version. Read the file gpl.txt for details.
6 
7   Floppy Disk Controller(FDC) emulation.
8   All commands are emulated with good timings estimation, as many programs
9   (demo or cracked games) rely on accurate FDC timings and DMA transfer by blocks
10   of 16 bytes.
11   The behaviour of all FDC's registers matches the official docs and should not
12   cause programs to fail when accessing the FDC (especially for Status Register).
13   As Hatari only handles ST/MSA disk images that only support 512 bytes sectors as
14   well as a fixed number of sectors per track, a few parts of the FDC emulation are
15   simplified and would need to be changed to handle more complex disk images (Pasti).
16 */
17 
18 const char FDC_fileid[] = "Hatari fdc.c : " __DATE__ " " __TIME__;
19 
20 #include <inttypes.h>
21 
22 #include "main.h"
23 #include "configuration.h"
24 #include "fdc.h"
25 #include "hdc.h"
26 #include "floppy.h"
27 #include "floppy_ipf.h"
28 #include "floppy_stx.h"
29 #include "ioMem.h"
30 #include "log.h"
31 #include "m68000.h"
32 #include "memorySnapShot.h"
33 #include "mfp.h"
34 #include "psg.h"
35 #include "stMemory.h"
36 #include "screen.h"
37 #include "video.h"
38 #include "clocks_timings.h"
39 #include "utils.h"
40 #include "statusbar.h"
41 
42 
43 /*
44   Floppy Disk Controller
45 
46 Programmable Sound Generator (YM-2149)
47 
48   0xff8800(even byte)  - PSG Register Data (Read, used for parallel port)
49             - PSG Register Select (Write)
50 
51   Write to bits 0-3 to select PSG register to use(then write data to 0xfff8802)
52     Value    Register
53 
54     0000    Channel A Fine Tune
55     0001    Channel A Coarse Tune
56     0010    Channel B Fine Tune
57     0011    Channel B Coarse Tune
58     0100    Channel C Fine Tune
59     0101    Channel C Coarse Tune
60     0110    Noise Generator Control
61     0111    Mixer Control - I/O enable
62     1000    Channel A Amplitude
63     1001    Channel B Amplitude
64     1010    Channel C Amplitude
65     1011    Envelope Period Fine Tune
66     1100    Envelope Peroid Coarse Tune
67     1101    Envelope Shape
68     1110    I/O Port A Select (Write only)
69     1111    I/O Port B Select
70 
71   0xfff8802(even byte)  - Bits according to 0xff8800 Register select
72 
73   1110(Register 14) - I/O Port A
74     Bit 0 - Floppy side 0/1
75     Bit 1 - Floppy drive 0 select
76     Bit 2 - Floppy drive 1 select
77     Bit 3 - RS232 Ready to send (RTS)
78     Bit 4 - RS232 Data Terminal Ready (DTR)
79     Bit 5 - Centronics Strobe
80     Bit 6 - General Purpose Output
81     Bit 7 - Reserved
82 
83 ACSI DMA and Floppy Disk Controller(FDC)
84   0xff8604 - information from file '1772.info.txt, by David Gahris' (register r0)
85     Word access only, but only lower byte (ff8605) is used
86   (write) - Disk controller
87     Set DMA sector count if ff8606 bit 4 == 1
88     Set FDC's internal registers depending on bit 1/2 of ff8606 if bit 4 == 0
89   (read) - Disk controller status
90     Bit 0 - Busy.  This bit is 1 when the 177x is busy.  This bit is 0 when the 177x is free for CPU commands.
91     Bit 1 - Index / Data Request.  On Type I commands, this bit is high during the index pulse that occurs once
92       per disk rotation.  This bit is low at all times other than the index pulse.  For Type II and III commands,
93       Bit 1 high signals the CPU to handle the data register in order to maintain a continuous flow of data.
94       Bit 1 is high when the data register is full during a read or when the data register is empty during a write.
95       "Worst case service time" for Data Request is 23.5 cycles.
96     Bit 2 - Track Zero / Lost Data.  After Type I commands, this bit is 0 if the mechanism is at track zero.
97       This bit is 1 if the head is not at track zero.  After Type II or III commands, this bit is 1 if the
98       CPU did not respond to Data Request (Status bit 1) in time for the 177x to maintain a continuous data flow.
99       This bit is 0 if the CPU responded promptly to Data Request.
100       NOTE : on ST, Lost Data is never set because the DMA always handles the data request signal.
101     Bit 3 - CRC Error.  This bit is high if a sector CRC on disk does not match the CRC which the 177x
102       computed from the data.  The CRC polynomial is x^16+x^12+x^5+1.  If the stored CRC matches the newly
103       calculated CRC, the CRC Error bit is low.  If this bit and the Record Not Found bit are set, the error
104       was in an ID field.  If this bit is set but Record Not Found is clear, the error was in a data field.
105     Bit 4 - Record Not Found.  This bit is set if the 177x cannot find the track, sector, or side which
106       the CPU requested.  Otherwise, this bit is clear.
107     Bit 5 - Spin-up / Record Type.  For Type I commands, this bit is low during the 6-revolution motor
108       spin-up time.  This bit is high after spin-up.  For Type II and Type III commands, Bit 5 low
109       indicates a normal data mark.  Bit 5 high indicates a deleted data mark.
110     Bit 6 - Write Protect.  This bit is not used during reads.  During writes, this bit is high when the disk is write protected.
111       After a type I command, this bit is constantly updated an give the current value of the WPT signal.
112     Bit 7 - Motor On.  This bit is high when the drive motor is on, and low when the motor is off.
113 
114   0xff8606 - DMA Status(read), DMA Mode Control(write) - NOTE bits 0,9-15 are not used
115     Bit 1 - FDC Pin A0 (See below)
116     Bit 2 - FDC Pin A1
117     Bit 3 - FDC/HDC Register Select
118     Bit 4 - FDC/Sector count select
119     Bit 5 - Reserved
120     Bit 6 - Enable/Disable DMA
121     Bit 7 - HDC/FDC
122     Bit 8 - Read/Write
123 
124     A1  A0    Read        Write(bit 8==1)
125     0  0    Status        Command
126     0  1    Track Register    Track Register
127     1  0    Sector Register    Sector Register
128     1  1    Data Register    Data Register
129 
130 
131   NOTE [NP] : The DMA is connected to the FDC and its Data Register, each time a DRQ
132   is made by the FDC, it's handled by the DMA through its internal 16 bytes buffer.
133   This means that in the case of the Atari ST the LOST_DATA bit will never be set
134   in the Status Register (but data can be lost if FDC_DMA.SectorCount=0 as there
135   will be no transfer between DMA and RAM).
136   So, "read sector" and "write sector" type II command will never set LOST_DATA, but
137   strangely on a real STF the "read track" type III command will set LOST_DATA when
138   it succeeds (maybe it depends on the size of the track ?)
139   (eg Super Monaco GP on Superior 65 : loader fails if LOST_DATA is set when
140   there're not enough DMA sectors to transfer bytes with read sectors)
141 
142   NOTE [NP] : All commands that require to read data from the floppy (verify sequence,
143   searching next sector id, ...) will not fail if the drive is OFF or empty. They will
144   wait forever until the drive is enabled again or a floppy is inserted ; at this point
145   the command will complete as usual, even after several seconds/minutes of delay.
146 
147   NOTE [NP] : Although the doc says a new type I/II/III command can't be started while
148   the busy bit is set, it's in fact possible to do it under certain conditions. As seen
149   in the loader of 'The Overdrive Demos' by Phalanx, the 'restore' command should be
150   replaced by a 'seek' command when it occurs in less than 900 cycles.
151   A possible explanation from this could be seen in the WD1772's documentation, where
152   the specific type I command is in fact checked after the 'prepare + spinup' sequence
153   in the state machine diagram.
154   Similarly, we can guess that a type II command can be replaced by another type II as long
155   as the 'prepare + spinup + head settle' sequence is not over (this was not tested on real HW)
156 
157   NOTE [NP] : As verified on a real STF, when reading DMA status at $ff8606 or DMA sector
158   count at $ff8604, the unused bits are not set to 0, but they contain the value from the latest
159   read/write made at $ff8604 when accessing FDC or HDC registers. Moreover, it's not possible to
160   read DMA sector count, so we return the lowest 8 bits from the latest access at $ff8604.
161 
162 
163   Cycles and wait states :
164   ------------------------
165   As verified on a real STF, reading or writing to $ff8604 or $ff8606 can add some 4 cycles
166   wait state.
167 	lea	$ffff8604,a3
168 	lea	$ffff8606,a4
169 
170 	move.w  (a4),d0		; dma status			motorola=8	stf=8
171 
172 	move.w  #$90,(a4)	; dma ctrl sector count		motorola=12	stf=12+4
173 	move.w  (a3),d0		; read sector count / fdc reg	motorola=8	stf=8
174 	move.w  #1,(a3)		; write sector count		motorola=12	stf=12+4
175 
176 	move.w  #$80,(a4)	; dma ctrl status/cmd reg	motorola=12	stf=12+4
177 	move.w  (a3),d0		; read fdc reg			motorola=8	stf=8+4
178 	move.w  #$d0,(a3)	; write fdc reg			motorola=12	stf=12+4
179 
180   -> All accesses take 4 extra cycles, except reading DMA status and reading DMA sector count
181   (which can't really be read, see note above)
182 
183 
184   Detecting disk changes :
185   ------------------------
186   3'1/2 floppy drives include a 'DSKCHG' signal on pin 34 to detect when a disk was changed.
187   Unfortunatelly on ST, this signal is not connected. Nevertheless, it's possible to detect
188   a disk was inserted or ejected by looking at the 'WPT' signal which tells if a disk is write
189   protected or not (but this method has some limitations and doesn't work in all cases).
190 
191   The following values of the WPT signal were measured with a custom program when ejecting/inserting
192   a floppy (tested on a 520 STF with a single sided drive and with a double sided drive) :
193     - floppy with write protection OFF (write possible), WPT=0 :
194 	eject   start=0 -> end=1
195 	insert  start=1 -> end=0
196     - floppy with write protection ON (write not possible), WPT=1 :
197 	eject   start=1 -> end=1
198 	insert  start=1 -> end=1
199 
200   As can be seen, when a disk is write protected (WPT=1), it is not possible to detect the
201   transition between inserting and ejecting, WPT will always be 1.
202 
203   The TOS monitors the changes on the WPT signal to determine if a floppy was ejected or inserted.
204   On TOS 1.02fr, the code is located between $fc1bc4 and $fc1ebc. Every 8 VBL, one floppy drive is checked
205   to see if the WPT signal changed. When 1 drive is connected, this means a floppy change should keep the
206   WPT signal during at least 8 VBLs. When 2 drive are connected, each drive is checked every 16 VBLs, so
207   the WPT signal should be kept for at least 16 VBLs.
208 
209   During these transition phases between "ejected" and "inserted", we force the WPT signal to 1,
210   depending on which transition we're emulating (see Floppy_DriveTransitionUpdateState()) :
211     - Ejecting : WPT will be X, then 1
212     - Inserting : WPT will be 1, then X
213 
214 */
215 
216 /*-----------------------------------------------------------------------*/
217 
218 /* Status register */
219 #define	FDC_STR_BIT_BUSY			0x01
220 #define	FDC_STR_BIT_INDEX			0x02		/* type I */
221 #define	FDC_STR_BIT_DRQ				0x02		/* type II and III */
222 #define	FDC_STR_BIT_TR00			0x04		/* type I */
223 #define	FDC_STR_BIT_LOST_DATA			0x04		/* type II and III */
224 #define	FDC_STR_BIT_CRC_ERROR			0x08
225 #define	FDC_STR_BIT_RNF				0x10
226 #define	FDC_STR_BIT_SPIN_UP			0x20		/* type I */
227 #define	FDC_STR_BIT_RECORD_TYPE			0x20		/* type II and III */
228 #define	FDC_STR_BIT_WPRT			0x40
229 #define	FDC_STR_BIT_MOTOR_ON			0x80
230 
231 
232 
233 /* FDC Emulation commands used in FDC.Command */
234 enum
235 {
236 	FDCEMU_CMD_NULL = 0,
237 	/* Type I */
238 	FDCEMU_CMD_RESTORE,
239 	FDCEMU_CMD_SEEK,
240 	FDCEMU_CMD_STEP,					/* Also used for STEP IN and STEP OUT */
241 	/* Type II */
242 	FDCEMU_CMD_READSECTORS,
243 	FDCEMU_CMD_WRITESECTORS,
244 	/* Type III */
245 	FDCEMU_CMD_READADDRESS,
246 	FDCEMU_CMD_READTRACK,
247 	FDCEMU_CMD_WRITETRACK,
248 
249 	/* Other fake commands used internally */
250 	FDCEMU_CMD_MOTOR_STOP
251 };
252 
253 
254 /* FDC Emulation commands' sub-states used in FDC.CommandState */
255 enum
256 {
257 	FDCEMU_RUN_NULL = 0,
258 
259 	/* Restore */
260 	FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO,
261 	FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_SPIN_UP,
262 	FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_MOTOR_ON,
263 	FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_LOOP,
264 	FDCEMU_RUN_RESTORE_VERIFY,
265 	FDCEMU_RUN_RESTORE_VERIFY_HEAD_OK,
266 	FDCEMU_RUN_RESTORE_VERIFY_NEXT_SECTOR_HEADER,
267 	FDCEMU_RUN_RESTORE_VERIFY_CHECK_SECTOR_HEADER,
268 	FDCEMU_RUN_RESTORE_COMPLETE,
269 	/* Seek */
270 	FDCEMU_RUN_SEEK_TOTRACK,
271 	FDCEMU_RUN_SEEK_TOTRACK_SPIN_UP,
272 	FDCEMU_RUN_SEEK_TOTRACK_MOTOR_ON,
273 	FDCEMU_RUN_SEEK_VERIFY,
274 	FDCEMU_RUN_SEEK_VERIFY_HEAD_OK,
275 	FDCEMU_RUN_SEEK_VERIFY_NEXT_SECTOR_HEADER,
276 	FDCEMU_RUN_SEEK_VERIFY_CHECK_SECTOR_HEADER,
277 	FDCEMU_RUN_SEEK_COMPLETE,
278 	/* Step / Step In / Step Out */
279 	FDCEMU_RUN_STEP_ONCE,
280 	FDCEMU_RUN_STEP_ONCE_SPIN_UP,
281 	FDCEMU_RUN_STEP_ONCE_MOTOR_ON,
282 	FDCEMU_RUN_STEP_VERIFY,
283 	FDCEMU_RUN_STEP_VERIFY_HEAD_OK,
284 	FDCEMU_RUN_STEP_VERIFY_NEXT_SECTOR_HEADER,
285 	FDCEMU_RUN_STEP_VERIFY_CHECK_SECTOR_HEADER,
286 	FDCEMU_RUN_STEP_COMPLETE,
287 	/* Read Sector */
288 	FDCEMU_RUN_READSECTORS_READDATA,
289 	FDCEMU_RUN_READSECTORS_READDATA_SPIN_UP,
290 	FDCEMU_RUN_READSECTORS_READDATA_HEAD_LOAD,
291 	FDCEMU_RUN_READSECTORS_READDATA_MOTOR_ON,
292 	FDCEMU_RUN_READSECTORS_READDATA_NEXT_SECTOR_HEADER,
293 	FDCEMU_RUN_READSECTORS_READDATA_CHECK_SECTOR_HEADER,
294 	FDCEMU_RUN_READSECTORS_READDATA_TRANSFER_START,
295 	FDCEMU_RUN_READSECTORS_READDATA_TRANSFER_LOOP,
296 	FDCEMU_RUN_READSECTORS_CRC,
297 	FDCEMU_RUN_READSECTORS_MULTI,
298 	FDCEMU_RUN_READSECTORS_RNF,
299 	FDCEMU_RUN_READSECTORS_COMPLETE,
300 	/* Write Sector */
301 	FDCEMU_RUN_WRITESECTORS_WRITEDATA,
302 	FDCEMU_RUN_WRITESECTORS_WRITEDATA_SPIN_UP,
303 	FDCEMU_RUN_WRITESECTORS_WRITEDATA_HEAD_LOAD,
304 	FDCEMU_RUN_WRITESECTORS_WRITEDATA_MOTOR_ON,
305 	FDCEMU_RUN_WRITESECTORS_WRITEDATA_NEXT_SECTOR_HEADER,
306 	FDCEMU_RUN_WRITESECTORS_WRITEDATA_CHECK_SECTOR_HEADER,
307 	FDCEMU_RUN_WRITESECTORS_WRITEDATA_TRANSFER_START,
308 	FDCEMU_RUN_WRITESECTORS_WRITEDATA_TRANSFER_LOOP,
309 	FDCEMU_RUN_WRITESECTORS_CRC,
310 	FDCEMU_RUN_WRITESECTORS_MULTI,
311 	FDCEMU_RUN_WRITESECTORS_RNF,
312 	FDCEMU_RUN_WRITESECTORS_COMPLETE,
313 	/* Read Address */
314 	FDCEMU_RUN_READADDRESS,
315 	FDCEMU_RUN_READADDRESS_SPIN_UP,
316 	FDCEMU_RUN_READADDRESS_HEAD_LOAD,
317 	FDCEMU_RUN_READADDRESS_MOTOR_ON,
318 	FDCEMU_RUN_READADDRESS_NEXT_SECTOR_HEADER,
319 	FDCEMU_RUN_READADDRESS_TRANSFER_START,
320 	FDCEMU_RUN_READADDRESS_TRANSFER_LOOP,
321 	FDCEMU_RUN_READADDRESS_RNF,
322 	FDCEMU_RUN_READADDRESS_COMPLETE,
323 	/* Read Track */
324 	FDCEMU_RUN_READTRACK,
325 	FDCEMU_RUN_READTRACK_SPIN_UP,
326 	FDCEMU_RUN_READTRACK_HEAD_LOAD,
327 	FDCEMU_RUN_READTRACK_MOTOR_ON,
328 	FDCEMU_RUN_READTRACK_INDEX,
329 	FDCEMU_RUN_READTRACK_TRANSFER_LOOP,
330 	FDCEMU_RUN_READTRACK_COMPLETE,
331 	/* Write Track */
332 	FDCEMU_RUN_WRITETRACK,
333 	FDCEMU_RUN_WRITETRACK_SPIN_UP,
334 	FDCEMU_RUN_WRITETRACK_HEAD_LOAD,
335 	FDCEMU_RUN_WRITETRACK_MOTOR_ON,
336 	FDCEMU_RUN_WRITETRACK_INDEX,
337 	FDCEMU_RUN_WRITETRACK_TRANSFER_LOOP,
338 	FDCEMU_RUN_WRITETRACK_COMPLETE,
339 
340 	/*  Motor Stop */
341 	FDCEMU_RUN_MOTOR_STOP,
342 	FDCEMU_RUN_MOTOR_STOP_WAIT,
343 	FDCEMU_RUN_MOTOR_STOP_COMPLETE
344 };
345 
346 
347 
348 /*
349  * Standard hardware values for the FDC. This should allow to get very good timings' emulation
350  * when dealing with non protected disks that still require a correct speed (MSA or ST images)
351  *
352  * - WD1772's datasheet is based on a reference clock of 8 MHz, so delays expressed in milli-seconds
353  *   will be slightly different for the Atari ST, whose FDC's clock is around 8.021247 MHz (but this is
354  *   not really noticeable in practice, less than 0.3 %)
355  * - DD MFM encoding defines a standard signal of 4 micro sec per bit (a possible variation of +/- 10 %
356  *   should still be possible). This means the WD1772 will read/write at 250 kbits/sec.
357  *   Taking 4 us per bit means 32 us for a full byte, and with a 8 MHz clock, 256 cycles per byte.
358  * - The floppy drives used in the Atari ST are spinning at 300 RPM. Variations are possible, as long
359  *   as it keeps the duration of an MFM bit in the required 4 us +/- 10 % (in practice, ST drives are often
360  *   at 299-301 RPM)
361  * - When FDC runs at 8 MHz, the 250 kbits/s and 300 RPM give 6250 bytes for a standard track
362  * - When FDC runs at 8.021247 MHz (Atari ST), the 250.664 kbit/s and 300 RPM give 6267 bytes per track
363  *
364  * Notes on timings required for precise emulation :
365  * For a standard floppy recorded with a constant speed, the FDC will take 32 microsec
366  * to read/write 1 byte on the floppy. On STF with a 8 MHz CPU clock, this means one byte can be
367  * transferred every 256 cpu cycles. So, to get some correct timings as required by some games' protection
368  * we must update the emulated FDC's state every 256 cycles (it could be less frequently and still work,
369  * due to the 16 bytes DMA FIFO that will transfer data only 16 bytes at a time, every 256*16=4096 cycles)
370  */
371 
372 
373 #define	FDC_CLOCK_STANDARD			(8000000.L)	/* In the WD1772's datasheet, all timings are related to a reference clock of 8 MHz */
374 #define FDC_DELAY_CYCLE_MFM_BYTE		( 4 * 8 * 8 )	/* 4 us per bit, 8 bits per byte, 8 MHz clock -> 256 cycles */
375 #define	FDC_BITRATE_STANDARD			250000		/* read/write speed of the WD1772 in bits per sec */
376 #define	FDC_RPM_STANDARD			300		/* 300 RPM or 5 spins per sec */
377 //#define	FDC_TRACK_BYTES_STANDARD		( ( FDC_BITRATE_STANDARD / 8 ) / ( FDC_RPM_STANDARD / 60 ) )	/* 6250 bytes */
378 #define FDC_TRACK_BYTES_STANDARD	6268
379 
380 #define FDC_TRANSFER_BYTES_US( n )		(  ( n ) * 8 * 1000000.L / FDC_BITRATE_STANDARD )	/* micro sec to read/write 'n' bytes in the WD1772 */
381 
382 #define	FDC_DELAY_IP_SPIN_UP			6		/* 6 index pulses to reach correct speed during spin up */
383 #define	FDC_DELAY_IP_MOTOR_OFF			9		/* Turn off motor 9 index pulses after the last command */
384 #define	FDC_DELAY_IP_ADDRESS_ID			5		/* 5 index pulses max when looking for next sector's address id field */
385 
386 
387 /* Delays are in micro sec */
388 #define	FDC_DELAY_US_HEAD_LOAD			( 15 * 1000 )	/* Additionnal 15 ms delay to load the head in type II/III */
389 
390 /* Index pulse signal remains high during 3.71 ms on each rotation ([NP] tested on my STF, can vary between 1.5 and 4 ms depending on the drive) */
391 #define	FDC_DELAY_US_INDEX_PULSE_LENGTH		( 3.71 * 1000 )
392 
393 
394 /* Internal delays to process commands are in fdc cycles for a 8 MHz clock */
395 #define	FDC_DELAY_CYCLE_TYPE_I_PREPARE		(90*8)		/* Types I commands take at least 0.09 ms to execute */
396 								/* (~740 cpu cycles @ 8 Mhz). [NP] : this was measured on a 520 STF */
397 								/* and avoid returning immediately when command has no effect */
398 #define	FDC_DELAY_CYCLE_TYPE_II_PREPARE		(1*8) // 65	/* Start Type II commands immediately */
399 #define	FDC_DELAY_CYCLE_TYPE_III_PREPARE	(1*8)		/* Start Type III commands immediately */
400 #define	FDC_DELAY_CYCLE_TYPE_IV_PREPARE		(100*8)		/* FIXME [NP] : this was not measured */
401 #define	FDC_DELAY_CYCLE_COMMAND_COMPLETE	(1*8)		/* Number of cycles before going to the _COMPLETE state (~8 cpu cycles) */
402 #define	FDC_DELAY_CYCLE_COMMAND_IMMEDIATE	(0)		/* Number of cycles to go immediately to another state */
403 
404 /* When the drive is switched off or if there's no floppy, some commands will wait forever */
405 /* as they can't find the next index pulse. Instead of continuously testing if a valid drive */
406 /* or floppy becomes available (which would slow down emulation), we only test every 50000 FDC cycles, */
407 /* which shouldn't give any noticeable emulation error */
408 #define	FDC_DELAY_CYCLE_WAIT_NO_DRIVE_FLOPPY	50000
409 
410 /* Update the floppy's angular position on a regular basis to detect the index pulses */
411 #define	FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE	500
412 
413 
414 #define	FDC_DMA_SECTOR_SIZE			512		/* Sector count at $ff8606 is for 512 bytes blocks */
415 #define	FDC_DMA_FIFO_SIZE			16		/* DMA transfers blocks of 16 bytes at a time */
416 
417 #define	FDC_PHYSICAL_MAX_TRACK			90		/* Head can't go beyond 90 tracks */
418 
419 
420 #define	FDC_STEP_RATE				( FDC.CR & 0x03 )	/* Bits 0 and 1 of the current type I command */
421 
422 int FDC_StepRate_ms[] = { 6 , 12 , 2 , 3 };			/* Controlled by bits 1 and 0 (r1/r0) in type I commands */
423 
424 
425 
426 
427 #define	FDC_FAST_FDC_FACTOR			10		/* Divide all delays by this value when --fastfdc is used */
428 
429 /* Standard ST floppies are double density ; to simulate HD or ED floppies, we use */
430 /* a density factor to have x2 or x4 bytes more during 1 FDC cycle */
431 #define	FDC_DENSITY_FACTOR_DD			1
432 #define	FDC_DENSITY_FACTOR_HD			2		/* For a HD disk, we get x2 bytes than DD */
433 #define	FDC_DENSITY_FACTOR_ED			4		/* For a ED disk, we get x4 bytes than DD */
434 
435 
436 #define	FDC_EMULATION_MODE_INTERNAL		1		/* Use fdc.c to handle emulation (ST, MSA, DIM and STX images) */
437 #define	FDC_EMULATION_MODE_IPF			2		/* Use floppy_ipf.c to handle emulation (IPF, CTR images) */
438 
439 
440 typedef struct {
441 	/* WD1772 internal registers */
442 	Uint8		DR;					/* Data Register */
443 	Uint8		TR;					/* Track Register */
444 	Uint8		SR;					/* Sector Register */
445 	Uint8		CR;					/* Command Register */
446 	Uint8		STR;					/* Status Register */
447 	int		StepDirection;				/* +1 (Step In) or -1 (Step Out) */
448 
449 	Uint8		SideSignal;				/* Side 0 or 1 */
450 	int		DriveSelSignal;				/* 0 or 1 for drive A or B ; or -1 if no drive selected */
451 	Uint8		IRQ_Signal;				/* 0 if IRQ is not set, else value depends on the source of the IRQ */
452 
453 	/* Other variables */
454 	int		Command;				/* FDC emulation command currently being executed */
455 	int		CommandState;				/* Current state for the running command */
456 	Uint8		CommandType;				/* Type of latest FDC command (1,2,3 or 4) */
457 	bool		ReplaceCommandPossible;			/* true if the current command can be replaced by another one (see notes) */
458 
459 	Uint8		Status_Temp;				/* Temporary content of the status register */
460 	bool		StatusTypeI;				/* When true, STR will report the status of a type I command */
461 	int		IndexPulse_Counter;			/* To count the number of rotations when motor is ON */
462 	Uint8		NextSector_ID_Field_TR;			/* Track value in the next ID Field after a call to FDC_NextSectorID_FdcCycles_ST() */
463 	Uint8		NextSector_ID_Field_SR;			/* Sector value in the next ID Field after a call to FDC_NextSectorID_FdcCycles_ST() */
464 	Uint8		NextSector_ID_Field_LEN;		/* Sector's length in the next ID Field after a call to FDC_NextSectorID_FdcCycles_ST() */
465 	Uint8		NextSector_ID_Field_CRC_OK;		/* CRC OK or not in the next ID Field after a call to FDC_NextSectorID_FdcCycles_ST() */
466 	Uint8		InterruptCond;				/* For a type IV force interrupt, contains the condition on the lower 4 bits */
467 
468 	int		EmulationMode;				/* FDC_EMULATION_MODE_INTERNAL or FDC_EMULATION_MODE_IPF */
469 } FDC_STRUCT;
470 
471 
472 typedef struct {
473 	/* DMA internal registers */
474 	Uint16		Status;
475 	Uint16		Mode;
476 	Uint16		SectorCount;
477 	Sint16		BytesInSector;
478 
479 	Uint8		FIFO[ FDC_DMA_FIFO_SIZE ];
480 	int		FIFO_Size;				/* Between 0 and FDC_DMA_FIFO_SIZE */
481 
482 	Uint16		ff8604_recent_val;			/* Most recent value read/written at $ff8604 in fdc/hdc mode (bit4=0 in $ff8606) */
483 
484 	/* Variables to handle our DMA buffer */
485 	int		PosInBuffer;
486 	int		PosInBufferTransfer;			/* FIXME REMOVE */
487 	int		BytesToTransfer;
488 } FDC_DMA_STRUCT;
489 
490 Uint32	FDC_DMA_Address;					// TODO : move into FDC_DMA_STRUCT (which will change memory snapshot)
491 
492 
493 typedef struct {
494 	bool		Enabled;
495 	bool		DiskInserted;
496 	int		RPM;					/* Rotation Per Minutes * 1000 */
497 	int		Density;				/* 1 for DD (720 kB), 2 for HD (1.4 MB), 4 for ED (2.8 MB) */
498 	Uint8		HeadTrack;				/* Current position of the head */
499 //	Uint8		Motor;					/* State of the drive's motor : 0=OFF 1=ON */
500 	Uint8		NumberOfHeads;				/* 1 for single sided drive, 2 for double sided */
501 
502 	Uint64		IndexPulse_Time;			/* CyclesGlobalClockCounter value last time we had an index pulse with motor ON */
503 } FDC_DRIVE_STRUCT;
504 
505 
506 /**
507  * Bytes to transfer with type II/III commands are stored in this buffer
508  * which associates a specific delay to each byte. This allows to
509  * have a common method to transfer data from ST/MSA disk images (with fixed
510  * timing), as well as data from STX disk images (with possible timing variations)
511  */
512 typedef struct {
513 	int		Size;
514 	int		PosRead;
515 
516 	struct {
517 		Uint8		Byte;
518 		Uint16		Timing;
519 	} Data [ FDC_TRACK_BYTES_STANDARD*4+1000 ];
520 } FDC_BUFFER_STRUCT;
521 
522 
523 static FDC_STRUCT	FDC;					/* All variables related to the WD1772 emulation */
524 static FDC_DMA_STRUCT	FDC_DMA;				/* All variables related to the DMA transfer */
525 static FDC_DRIVE_STRUCT	FDC_DRIVES[ MAX_FLOPPYDRIVES ];		/* A: and B: */
526 static FDC_BUFFER_STRUCT	FDC_BUFFER;			/* Buffer of Timing/Byte to transfer with the FDC */
527 
528 static Uint8 DMADiskWorkSpace[ FDC_TRACK_BYTES_STANDARD*4+1000 ];/* Workspace used to transfer bytes between floppy and DMA */
529 								/* It should be large enough to contain a whole track */
530 								/* We use a x4 factor when we need to simulate HD and ED too */
531 
532 
533 
534 /*--------------------------------------------------------------*/
535 /* Local functions prototypes					*/
536 /*--------------------------------------------------------------*/
537 
538 static Uint32	FDC_DelayToFdcCycles ( Uint32 Delay_micro );
539 static Uint32	FDC_FdcCyclesToCpuCycles ( Uint32 FdcCycles );
540 static Uint32	FDC_CpuCyclesToFdcCycles ( Uint32 CpuCycles );
541 static void	FDC_StartTimer_FdcCycles ( int FdcCycles , int InternalCycleOffset );
542 static int	FDC_TransferByte_FdcCycles ( int NbBytes );
543 static void	FDC_CRC16 ( Uint8 *buf , int nb , Uint16 *pCRC );
544 
545 static void	FDC_ResetDMA ( void );
546 
547 static int	FDC_GetEmulationMode ( void );
548 static int	FDC_GetSectorsPerTrack ( int Drive , int Track , int Side );
549 static int	FDC_GetSidesPerDisk ( int Drive , int Track );
550 static int	FDC_GetTracksPerDisk ( int Drive );
551 static int	FDC_GetDensity ( int Drive );
552 
553 static Uint32	FDC_GetCyclesPerRev_FdcCycles ( int Drive );
554 static void	FDC_IndexPulse_Update ( void );
555 static void	FDC_IndexPulse_Init ( int Drive );
556 
557 static void	FDC_Update_STR ( Uint8 DisableBits , Uint8 EnableBits );
558 static int	FDC_CmdCompleteCommon ( bool DoInt );
559 static bool	FDC_VerifyTrack ( void );
560 static int	FDC_UpdateMotorStop ( void );
561 static int	FDC_UpdateRestoreCmd ( void );
562 static int	FDC_UpdateSeekCmd ( void );
563 static int	FDC_UpdateStepCmd ( void );
564 static int	FDC_UpdateReadSectorsCmd ( void );
565 static int	FDC_UpdateWriteSectorsCmd ( void );
566 static int	FDC_UpdateReadAddressCmd ( void );
567 static int	FDC_UpdateReadTrackCmd ( void );
568 static int	FDC_UpdateWriteTrackCmd ( void );
569 
570 static bool	FDC_Set_MotorON ( Uint8 FDC_CR );
571 static int	FDC_TypeI_Restore ( void );
572 static int	FDC_TypeI_Seek ( void );
573 static int	FDC_TypeI_Step ( void );
574 static int	FDC_TypeI_StepIn ( void );
575 static int	FDC_TypeI_StepOut ( void );
576 static int	FDC_TypeII_ReadSector ( void );
577 static int	FDC_TypeII_WriteSector(void);
578 static int	FDC_TypeIII_ReadAddress ( void );
579 static int	FDC_TypeIII_ReadTrack ( void );
580 static int	FDC_TypeIII_WriteTrack ( void );
581 static int	FDC_TypeIV_ForceInterrupt ( void );
582 
583 static int	FDC_ExecuteTypeICommands ( void );
584 static int	FDC_ExecuteTypeIICommands ( void );
585 static int	FDC_ExecuteTypeIIICommands ( void );
586 static int	FDC_ExecuteTypeIVCommands ( void );
587 static void	FDC_ExecuteCommand ( void );
588 
589 static void	FDC_WriteSectorCountRegister ( void );
590 static void	FDC_WriteCommandRegister ( void );
591 static void	FDC_WriteTrackRegister ( void );
592 static void	FDC_WriteSectorRegister ( void );
593 static void	FDC_WriteDataRegister ( void );
594 
595 static int	FDC_NextSectorID_FdcCycles_ST ( Uint8 Drive , Uint8 NumberOfHeads , Uint8 Track , Uint8 Side );
596 static Uint8	FDC_NextSectorID_TR_ST ( void );
597 static Uint8	FDC_NextSectorID_SR_ST ( void );
598 static Uint8	FDC_NextSectorID_LEN_ST ( void );
599 static Uint8	FDC_NextSectorID_CRC_OK_ST ( void );
600 static Uint8	FDC_ReadSector_ST ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side , int *pSectorSize );
601 static Uint8	FDC_WriteSector_ST ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side , int SectorSize );
602 static Uint8	FDC_ReadAddress_ST ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side );
603 static Uint8	FDC_ReadTrack_ST ( Uint8 Drive , Uint8 Track , Uint8 Side );
604 static Uint8	FDC_WriteTrack_ST ( Uint8 Drive , Uint8 Track , Uint8 Side , int TrackSize );
605 
606 
607 /*-----------------------------------------------------------------------*/
608 /**
609  * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
610  */
FDC_MemorySnapShot_Capture(bool bSave)611 void	FDC_MemorySnapShot_Capture(bool bSave)
612 {
613 	MemorySnapShot_Store(&FDC, sizeof(FDC));
614 	MemorySnapShot_Store(&FDC_DMA, sizeof(FDC_DMA));
615 	MemorySnapShot_Store(&FDC_DRIVES, sizeof(FDC_DRIVES));
616 	MemorySnapShot_Store(&FDC_BUFFER, sizeof(FDC_BUFFER_STRUCT));
617 
618 	MemorySnapShot_Store(DMADiskWorkSpace, sizeof(DMADiskWorkSpace));
619 }
620 
621 
622 /*-----------------------------------------------------------------------*/
623 /**
624  * Change the color of the drive's led color in the statusbar, depending
625  * on the state of the busy bit in STR
626  */
FDC_Drive_Set_BusyLed(Uint8 STR)627 void	FDC_Drive_Set_BusyLed ( Uint8 STR )
628 {
629 //fprintf ( stderr ,"fdc led %d %x\n" , FDC.DriveSelSignal , STR );
630 	if ( FDC.DriveSelSignal < 0 )
631 		return;						/* no drive selected */
632 
633 	if ( STR & FDC_STR_BIT_BUSY )
634 		Statusbar_SetFloppyLed ( FDC.DriveSelSignal , LED_STATE_ON_BUSY );
635 	else
636 		Statusbar_SetFloppyLed ( FDC.DriveSelSignal , LED_STATE_ON );
637 }
638 
639 
640 /*-----------------------------------------------------------------------*/
641 /**
642  * Return a small text + length with the current values of the FDC's registers
643  * This text is displayed in the statusbar and it looks like :
644  * CC:xx HH:TT:SS:s
645  *   CC=command in 2 letters
646  *   xx=command in hexa
647  *   HH=physical head's position
648  *   TT=track register
649  *   SS=sector register
650  *   s=side
651  */
FDC_Get_Statusbar_Text(char * text,size_t maxlen)652 int	FDC_Get_Statusbar_Text ( char *text, size_t maxlen )
653 {
654 	Uint8	Command , Head , Track , Sector , Side;
655 	char	CommandText[ 3 ];
656 	size_t	written;
657 	int	Drive;
658 
659 	Drive = FDC.DriveSelSignal;
660 	if ( Drive < 0 )					/* If no drive enabled, use drive O for Head */
661 		Drive = 0;
662 
663 	if ( FDC_GetEmulationMode() == FDC_EMULATION_MODE_INTERNAL )
664 	{
665 		Command = FDC.CR;
666 		Head	= FDC_DRIVES[ Drive ].HeadTrack;
667 		Track	= FDC.TR;
668 		Sector	= FDC.SR;
669 		Side	= FDC.SideSignal;
670 	}
671 	else							/* FDC_EMULATION_MODE_IPF */
672 	{
673 		IPF_FDC_StatusBar ( &Command , &Head , &Track , &Sector , &Side );
674 	}
675 
676 	if      ( ( Command & 0xf0 ) == 0x00 )	strcpy ( CommandText , "RE" );		/* Restore */
677 	else if ( ( Command & 0xf0 ) == 0x10 )	strcpy ( CommandText , "SE" );		/* Seek */
678 	else if ( ( Command & 0xe0 ) == 0x20 )	strcpy ( CommandText , "ST" );		/* Step */
679 	else if ( ( Command & 0xe0 ) == 0x40 )	strcpy ( CommandText , "SI" );		/* Step In */
680 	else if ( ( Command & 0xe0 ) == 0x60 )	strcpy ( CommandText , "SO" );		/* Step Out */
681 	else if ( ( Command & 0xe0 ) == 0x80 )	strcpy ( CommandText , "RS" );		/* Read Sector */
682 	else if ( ( Command & 0xe0 ) == 0xa0 )	strcpy ( CommandText , "WS" );		/* Write Sector */
683 	else if ( ( Command & 0xf0 ) == 0xc0 )	strcpy ( CommandText , "RA" );		/* Read Address */
684 	else if ( ( Command & 0xf0 ) == 0xe0 )	strcpy ( CommandText , "RT" );		/* Read Track */
685 	else if ( ( Command & 0xf0 ) == 0xf0 )	strcpy ( CommandText , "WT" );		/* Write Track */
686 	else					strcpy ( CommandText , "FI" );		/* Force Int */
687 
688 	written = snprintf ( text, maxlen, "%s:%02X %02X:%02X:%02X:%d" , CommandText , Command , Head , Track , Sector , Side );
689 	assert(written < maxlen); /* more space needs to be allocated */
690 	return written;
691 }
692 
693 
694 /*-----------------------------------------------------------------------*/
695 /**
696  * Convert a delay in micro seconds to its equivalent of fdc cycles
697  * (delays in the WD1772 specs are relative to a 8 MHz reference clock)
698  */
FDC_DelayToFdcCycles(Uint32 Delay_micro)699 static Uint32	FDC_DelayToFdcCycles ( Uint32 Delay_micro )
700 {
701 	Uint32	FdcCycles;
702 
703 	FdcCycles = (Uint32) ( ( (Uint64) FDC_CLOCK_STANDARD * Delay_micro ) / 1000000 );
704 
705 //fprintf ( stderr , "fdc state %d delay %d us %d fdc cycles\n" , FDC.Command , Delay_micro , FdcCycles );
706 	return FdcCycles;
707 }
708 
709 
710 /*-----------------------------------------------------------------------*/
711 /**
712  * Convert a number of fdc cycles at freq MachineClocks.FDC_Freq to a number
713  * of cpu cycles at freq MachineClocks.CPU_Freq
714  * TODO : we use a fixed 8 MHz clock to convert cycles for our internal timers
715  * in cycInt.c. This should be replaced some days by using MachineClocks.CPU_Freq.
716  * (for Falcon, we multiply cycles by 2 to simulate a freq in the 8 MHz range)
717  */
FDC_FdcCyclesToCpuCycles(Uint32 FdcCycles)718 static Uint32	FDC_FdcCyclesToCpuCycles ( Uint32 FdcCycles )
719 {
720 	Uint32	CpuCycles;
721 
722 	/* Our conversion expects FDC_Freq to be nearly the same as CPU_Freq (8 Mhz) */
723 	/* but the Falcon uses a 16 MHz clock for the Ajax FDC */
724 	/* FIXME : as stated above, this should be handled better, without involving 8 MHz CPU_Freq */
725 	if (Config_IsMachineFalcon())
726 		FdcCycles *= 2;					/* correct delays for a 8 MHz FDC_Freq clock instead of 16 */
727 
728 //	CpuCycles = rint ( ( (Uint64)FdcCycles * MachineClocks.CPU_Freq ) / MachineClocks.FDC_Freq );
729 	CpuCycles = rint ( ( (Uint64)FdcCycles * 8021247.L ) / MachineClocks.FDC_Freq );
730 	CpuCycles <<= nCpuFreqShift;				/* Convert to x1 or x2 or x4 cpu speed */
731 
732 //fprintf ( stderr , "fdc command %d machine %d fdc cycles %d cpu cycles %d\n" , FDC.Command , ConfigureParams.System.nMachineType , FdcCycles , CpuCycles );
733 //if ( Delay==4104) Delay=4166;		// 4166 : decade demo
734 	return CpuCycles;
735 }
736 
737 
738 /*-----------------------------------------------------------------------*/
739 /**
740  * Convert a number of cpu cycles at freq MachineClocks.CPU_Freq to a number
741  * of fdc cycles at freq MachineClocks.FDC_Freq (this is the opposite
742  * of FDC_FdcCyclesToCpuCycles)
743  * TODO : we use a fixed 8 MHz clock to convert cycles for our internal timers
744  * in cycInt.c. This should be replaced some days by using MachineClocks.CPU_Freq.
745  */
FDC_CpuCyclesToFdcCycles(Uint32 CpuCycles)746 static Uint32	FDC_CpuCyclesToFdcCycles ( Uint32 CpuCycles )
747 {
748 	int	FdcCycles;
749 
750 
751 	CpuCycles >>= nCpuFreqShift;				/* Compensate for x2 or x4 cpu speed */
752 
753 //	FdcCycles = rint ( ( (Uint64)CpuCycles * MachineClocks.FDC_Freq ) / MachineClocks.CPU_Freq );
754 	FdcCycles = rint ( ( (Uint64)CpuCycles * MachineClocks.FDC_Freq ) / 8021247.L );
755 
756 	/* Our conversion expects FDC_Freq to be nearly the same as CPU_Freq (8 Mhz) */
757 	/* but the Falcon uses a 16 MHz clock for the Ajax FDC */
758 	/* FIXME : as stated above, this should be handled better, without involving 8 MHz CPU_Freq */
759 	if (Config_IsMachineFalcon())
760 		FdcCycles /= 2;					/* correct delays for a 8 MHz FDC_Freq clock instead of 16 */
761 
762 //fprintf ( stderr , "fdc state %d delay %d cpu cycles %d fdc cycles\n" , FDC.Command , CpuCycles , FdcCycles );
763 	return FdcCycles;
764 }
765 
766 
767 /*-----------------------------------------------------------------------*/
768 /**
769  * Start an internal timer to handle the FDC's events.
770  * If "fast floppy" mode is used, we speed up the timer by dividing
771  * the number of cycles by a fixed number.
772  */
FDC_StartTimer_FdcCycles(int FdcCycles,int InternalCycleOffset)773 static void	FDC_StartTimer_FdcCycles ( int FdcCycles , int InternalCycleOffset )
774 {
775 //fprintf ( stderr , "fdc start timer %d cycles\n" , FdcCycles );
776 
777 	if ( ( ConfigureParams.DiskImage.FastFloppy ) && ( FdcCycles > FDC_FAST_FDC_FACTOR ) )
778 		FdcCycles /= FDC_FAST_FDC_FACTOR;
779 
780 	CycInt_AddRelativeInterruptWithOffset ( FDC_FdcCyclesToCpuCycles ( FdcCycles ) , INT_CPU_CYCLE , INTERRUPT_FDC , InternalCycleOffset );
781 }
782 
783 
784 /*-----------------------------------------------------------------------*/
785 /**
786  * Return the number of FDC cycles required to read/write 'nb' bytes
787  * This function will always be called when FDC.DriveSelSignal >= 0, as
788  * there's no case where we transfer bytes if no drive is enabled. This
789  * means we can safely call FDC_GetDensity() here to simulate HD/ED floppies.
790  *
791  * 2015/10/23 [NP] As seen in the 'Bird Mad Girl Show' demo, it's possible to get
792  * FDC.DriveSelSignal < 0 once a transfer was started (for example, read sector
793  * will complete successfully). So we use DD by default in that case.
794  */
FDC_TransferByte_FdcCycles(int NbBytes)795 static int	FDC_TransferByte_FdcCycles ( int NbBytes )
796 {
797 //fprintf ( stderr , "fdc state %d transfer %d bytes\n" , FDC.Command , NbBytes );
798 	if ( FDC.DriveSelSignal < 0 )
799 	{
800 		/* Drive was unselected during the transfer : assume DD for the rest of the bytes */
801 		return ( NbBytes * FDC_DELAY_CYCLE_MFM_BYTE ) / FDC_DENSITY_FACTOR_DD;
802 	}
803 
804 	return ( NbBytes * FDC_DELAY_CYCLE_MFM_BYTE ) / FDC_DRIVES[ FDC.DriveSelSignal ].Density;
805 }
806 
807 
808 /*-----------------------------------------------------------------------*/
809 /**
810  * Compute the CRC16 of 'nb' bytes stored in 'buf'.
811  */
FDC_CRC16(Uint8 * buf,int nb,Uint16 * pCRC)812 static void FDC_CRC16 ( Uint8 *buf , int nb , Uint16 *pCRC )
813 {
814 	int	i;
815 
816 	crc16_reset ( pCRC );
817 	for ( i=0 ; i<nb ; i++ )
818 	{
819 //		fprintf ( stderr , "fdc crc16 %d 0x%x\n" , i , buf[ i ] );
820 		crc16_add_byte ( pCRC , buf[ i ] );
821 	}
822 //	fprintf ( stderr , "fdc crc16 0x%x 0x%x\n" , *pCRC>>8 , *pCRC & 0xff );
823 }
824 
825 
826 /*-----------------------------------------------------------------------*/
827 /**
828  * Init variables used in FDC and DMA emulation
829  */
FDC_Init(void)830 void FDC_Init ( void )
831 {
832 	int	i;
833 
834         LOG_TRACE ( TRACE_FDC , "fdc init\n" );
835 
836 	for ( i=0 ; i<MAX_FLOPPYDRIVES ; i++ )
837 	{
838 		FDC_DRIVES[ i ].Enabled = true;
839 		FDC_DRIVES[ i ].DiskInserted = false;
840 		FDC_DRIVES[ i ].RPM = FDC_RPM_STANDARD * 1000;
841 		FDC_DRIVES[ i ].Density = FDC_DENSITY_FACTOR_DD;
842 		FDC_DRIVES[ i ].HeadTrack = 0;			/* Set all drives to track 0 */
843 		FDC_DRIVES[ i ].NumberOfHeads = 2;		/* Double sided drive */
844 		FDC_DRIVES[ i ].IndexPulse_Time = 0;
845 	}
846 
847 	FDC_Buffer_Reset();
848 
849 	FDC.EmulationMode = FDC_EMULATION_MODE_INTERNAL;
850 }
851 
852 
853 /*-----------------------------------------------------------------------*/
854 /**
855  * Reset variables used in FDC and DMA emulation
856  */
857 
858 /* This function is called after a hardware reset of the FDC.
859  * Cold reset is when the computer is turned off/on.
860  * Warm reset is when the reset button is pressed or the 68000
861  * RESET instruction is used.
862  * On warm reset, TR and DR should not be reset.
863  * STR is set to 0 and SR is set to 1 (verified on a real STF)
864  */
FDC_Reset(bool bCold)865 void FDC_Reset ( bool bCold )
866 {
867 	int	i;
868 
869 	LOG_TRACE ( TRACE_FDC , "fdc reset mode=%s\n" , bCold?"cold":"warm" );
870 
871 	/* Clear out FDC registers */
872 	FDC.CR = 0;
873 	FDC.STR = 0;
874 	FDC.SR = 1;
875 	FDC.StatusTypeI = false;
876 
877 	/* On cold reset, TR and DR should be reset */
878 	/* On warm reset, TR and DR value should be kept */
879 	if ( bCold )
880 	{
881 		FDC.TR = 0;
882 		FDC.DR = 0;
883 		FDC_DMA.ff8604_recent_val = 0;		/* Only set to 0 on cold reset */
884 	}
885 	FDC.StepDirection = 1;
886 
887 	FDC.Command = FDCEMU_CMD_NULL;			/* FDC emulation command currently being executed */
888 	FDC.CommandState = FDCEMU_RUN_NULL;
889 	FDC.CommandType = 0;
890 	FDC.InterruptCond = 0;
891 	FDC.IRQ_Signal = 0;
892 	FDC_ClearIRQ();					/* Propagate IRQ signal to MFP GPIP5 */
893 
894 	FDC.IndexPulse_Counter = 0;
895 	for ( i=0 ; i<MAX_FLOPPYDRIVES ; i++ )
896 	{
897 		FDC_DRIVES[ i ].IndexPulse_Time = 0;	/* Current IP's locations are lost after a reset (motor is now OFF) */
898 	}
899 
900 	FDC_DMA.Status = 1;				/* no DMA error and SectorCount=0 */
901 	FDC_DMA.Mode = 0;
902 
903 	FDC_ResetDMA();
904 
905 	FDC_Buffer_Reset();
906 
907 	/* Also reset IPF emulation */
908 	IPF_Reset();
909 }
910 
911 
912 /*-----------------------------------------------------------------------*/
913 /**
914  * Reset DMA (clear internal 16 bytes buffer)
915  *
916  * This is done by 'toggling' bit 8 of the DMA Mode Control register
917  * This will empty the FIFOs and reset Sector Count to 0
918  */
FDC_ResetDMA(void)919 static void FDC_ResetDMA ( void )
920 {
921 	int	FrameCycles, HblCounterVideo, LineCycles;
922 
923 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
924 	LOG_TRACE(TRACE_FDC, "fdc reset dma VBL=%d video_cyc=%d %d@%d pc=%x\n",
925 		nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
926 
927 	/* Empty FIFO */
928 	FDC_DMA.FIFO_Size = 0;
929 
930 	/* Reset bytes count for current DMA sector */
931 	FDC_DMA.BytesInSector = FDC_DMA_SECTOR_SIZE;
932 	FDC_DMA.SectorCount = 0;			/* After a reset, sector count is 0 (verified on a real STF) */
933 
934 	/* Reset internal variables used to handle DMA transfer */
935 	FDC_DMA.PosInBuffer = 0;
936 	FDC_DMA.PosInBufferTransfer = 0;
937 	FDC_DMA.BytesToTransfer = 0;
938 
939 	/* Reset HDC command status */
940 	HDC_ResetCommandStatus();
941 }
942 
943 
944 /*-----------------------------------------------------------------------*/
945 /**
946  * Set DMA Status at $ff8606
947  *
948  * Bit 0 - Error Status (0=Error 1=No error)
949  * Bit 1 - Sector Count Zero Status (0=Sector Count Zero)
950  * Bit 2 - Data Request signal from the FDC
951  */
FDC_SetDMAStatus(bool bError)952 void FDC_SetDMAStatus ( bool bError )
953 {
954 	/* Set error bit */
955 	if (!bError)
956 		FDC_DMA.Status |= 0x1;					/* No Error, set bit 0 */
957 	else
958 		FDC_DMA.Status &= ~0x1;					/* Error, clear bit 0 */
959 }
960 
961 
962 /*-----------------------------------------------------------------------*/
963 /**
964  * Return the value of bit 8 in the FDC's DMA mode control register.
965  * 0=dma read  0x100=dma write
966  */
FDC_DMA_GetModeControl_R_WR(void)967 int	FDC_DMA_GetModeControl_R_WR ( void )
968 {
969 	return FDC_DMA.Mode & 0x100;
970 }
971 
FDC_DMA_GetMode(void)972 int FDC_DMA_GetMode(void)
973 {
974 	return FDC_DMA.Mode;
975 }
976 
977 
978 /*-----------------------------------------------------------------------*/
979 /**
980  * Add a byte to the DMA's FIFO buffer (read from disk).
981  * If the buffer is full and DMA is ON, write the FIFO's 16 bytes to DMA's address.
982  *
983  * NOTE [NP] : the DMA is connected to the FDC, each time a DRQ is made by the FDC,
984  * it's handled by the DMA and stored in the DMA's 16 bytes buffer. This means
985  * FDC_STR_BIT_LOST_DATA will never be set (but data can be lost if FDC_DMA.SectorCount==0)
986  *
987  * NOTE [NP] : as seen on a real STF, the unused bits when reading DMA Status at $ff8606
988  * are also changed by the DMA operations (this might not be complete, but seems quite reproducible) :
989  *  - reading a byte from the FDC to the DMA will change unused bits in the lowest byte at $ff8604
990  *  - transferring the 16 byte DMA buffer to RAM will change the unused bits in the 2 bytes at $ff8604
991  *
992  * In all cases, the byte read from the FDC is transferred to the DMA, even if DMA sector count is 0, so
993  * we must always update lowest byte of ff8604_recent_val.
994  * DMA FIFO is transferred only when DMA sector count is >0, so high byte of ff8604_recent_val will be
995  * updated only in that case.
996  */
FDC_DMA_FIFO_Push(Uint8 Byte)997 void	FDC_DMA_FIFO_Push ( Uint8 Byte )
998 {
999 	Uint32	Address;
1000 
1001 //fprintf ( stderr , "dma push pos=%d byte=%x %lld\n" , FDC_DMA.FIFO_Size , Byte , CyclesGlobalClockCounter );
1002 
1003 	/* Store the byte that was just read from FDC's Data Register */
1004 	FDC_DMA.ff8604_recent_val = ( FDC_DMA.ff8604_recent_val & 0xff00 ) | Byte;
1005 
1006 	if ( FDC_DMA.SectorCount == 0 )
1007 	{
1008 		//FDC_Update_STR ( 0 , FDC_STR_BIT_LOST_DATA );		/* If DMA is OFF, data are lost -> Not on the ST */
1009 		FDC_SetDMAStatus ( true );				/* Set DMA error (bit 0) */
1010 		return;
1011 	}
1012 
1013 	FDC_SetDMAStatus ( false );					/* No DMA error (bit 0) */
1014 
1015 	FDC_DMA.FIFO [ FDC_DMA.FIFO_Size++ ] = Byte;
1016 
1017 	if ( FDC_DMA.FIFO_Size < FDC_DMA_FIFO_SIZE )			/* FIFO is not full yet */
1018 		return;
1019 
1020 	/* FIFO full : transfer data from FIFO to RAM and update DMA address */
1021 	Address = FDC_GetDMAAddress();
1022 	STMemory_SafeCopy ( Address , FDC_DMA.FIFO , FDC_DMA_FIFO_SIZE , "FDC DMA push to fifo" );
1023 	FDC_WriteDMAAddress ( Address + FDC_DMA_FIFO_SIZE );
1024 	FDC_DMA.FIFO_Size = 0;						/* FIFO is now empty again */
1025 
1026 	/* Store the last word that was just transferred by the DMA */
1027 	FDC_DMA.ff8604_recent_val = ( FDC_DMA.FIFO [ FDC_DMA_FIFO_SIZE-2 ] << 8 ) | FDC_DMA.FIFO [ FDC_DMA_FIFO_SIZE-1 ];
1028 
1029 	/* Update Sector Count */
1030 	FDC_DMA.BytesInSector -= FDC_DMA_FIFO_SIZE;
1031 	if ( FDC_DMA.BytesInSector <= 0 )
1032 	{
1033 		FDC_DMA.SectorCount--;
1034 		FDC_DMA.BytesInSector = FDC_DMA_SECTOR_SIZE;
1035 	}
1036 }
1037 
1038 
1039 /*-----------------------------------------------------------------------*/
1040 /**
1041  * Get a byte from the DMA's FIFO buffer (write to disk).
1042  * If the buffer is empty and DMA is ON, load 16 bytes in the FIFO from DMA's address.
1043  *
1044  * NOTE [NP] : on a real ST, there're two 16 byte DMA FIFO, this allows to refill one FIFO
1045  * while the other FIFO is used to transfer data to the FDC. We don't emulate this at the
1046  * moment, as it doesn't cause any problem (when a DMA is set to write mode, we would need
1047  * to prefill 32 bytes instead of 16 bytes as we do now)
1048  *
1049  * NOTE [NP] : as with FDC_DMA_FIFO_Push, this also changes the unused bits at $ff8606
1050  */
FDC_DMA_FIFO_Pull(void)1051 Uint8	FDC_DMA_FIFO_Pull ( void )
1052 {
1053 	Uint32	Address;
1054 	Uint8	Byte;
1055 
1056 //fprintf ( stderr , "fifo pull %d %d %d\n" , FDC_DMA.BytesToTransfer , FDC_DMA.BytesInSector , FDC_DMA.SectorCount );
1057 	if ( FDC_DMA.SectorCount == 0 )
1058 	{
1059 		//FDC_Update_STR ( 0 , FDC_STR_BIT_LOST_DATA );		/* If DMA is OFF, data are lost -> Not on the ST */
1060 		FDC_SetDMAStatus ( true );				/* Set DMA error (bit 0) */
1061 		return 0;						/* Write a '0' byte when dma is off */
1062 	}
1063 
1064 	FDC_SetDMAStatus ( false );					/* No DMA error (bit 0) */
1065 
1066 	if ( FDC_DMA.FIFO_Size > 0 )					/* FIFO is not empty yet */
1067 		Byte = FDC_DMA.FIFO [ FDC_DMA_FIFO_SIZE - ( FDC_DMA.FIFO_Size-- ) ];	/* return byte at pos 0, 1, .., 15 */
1068 
1069 	else
1070 	{
1071 		/* FIFO empty : transfer data from RAM to FIFO and update DMA address */
1072 		Address = FDC_GetDMAAddress();
1073 		memcpy ( FDC_DMA.FIFO , &STRam[ Address ] , FDC_DMA_FIFO_SIZE );/* TODO : check we read from a valid RAM location ? */
1074 		FDC_WriteDMAAddress ( Address + FDC_DMA_FIFO_SIZE );
1075 		FDC_DMA.FIFO_Size = FDC_DMA_FIFO_SIZE - 1;			/* FIFO is now full again (minus the byte we will return below) */
1076 
1077 		/* Store the last word that was just transferred by the DMA */
1078 		FDC_DMA.ff8604_recent_val = ( FDC_DMA.FIFO [ FDC_DMA_FIFO_SIZE-2 ] << 8 ) | FDC_DMA.FIFO [ FDC_DMA_FIFO_SIZE-1 ];
1079 
1080 		/* Update Sector Count */
1081 		FDC_DMA.BytesInSector -= FDC_DMA_FIFO_SIZE;
1082 		if ( FDC_DMA.BytesInSector < 0 )
1083 		{
1084 			FDC_DMA.SectorCount--;
1085 			FDC_DMA.BytesInSector = FDC_DMA_SECTOR_SIZE;
1086 		}
1087 
1088 		Byte = FDC_DMA.FIFO [ 0 ];				/* return the 1st byte we just transferred in the FIFO */
1089 	}
1090 
1091 	/* Store the byte that will be written to FDC's Data Register */
1092 	FDC_DMA.ff8604_recent_val = ( FDC_DMA.ff8604_recent_val & 0xff00 ) | Byte;
1093 
1094 	return Byte;
1095 }
1096 
1097 
1098 /*-----------------------------------------------------------------------*/
1099 /**
1100  * Return the value of FDC_DMA.SectorCount (used in floppy_ipf.c)
1101  */
FDC_DMA_GetSectorCount(void)1102 int	FDC_DMA_GetSectorCount ( void )
1103 {
1104 	return FDC_DMA.SectorCount;
1105 }
1106 
1107 
1108 /*-----------------------------------------------------------------------*/
1109 /**
1110  * Reset the buffer used to transfer data between the FDC and the DMA
1111  */
FDC_Buffer_Reset(void)1112 void	FDC_Buffer_Reset ( void )
1113 {
1114 	FDC_BUFFER.Size = 0;
1115 	FDC_BUFFER.PosRead = 0;
1116 }
1117 
1118 
1119 /*-----------------------------------------------------------------------*/
1120 /**
1121  * Add a byte to the FDC transfer buffer, using a specific timing
1122  */
FDC_Buffer_Add_Timing(Uint8 Byte,Uint16 Timing)1123 void	FDC_Buffer_Add_Timing ( Uint8 Byte , Uint16 Timing )
1124 {
1125 	FDC_BUFFER.Data[ FDC_BUFFER.Size ].Byte = Byte;
1126 	FDC_BUFFER.Data[ FDC_BUFFER.Size ].Timing = Timing;
1127 	FDC_BUFFER.Size++;
1128 }
1129 
1130 
1131 /*-----------------------------------------------------------------------*/
1132 /**
1133  * Add a byte to the FDC transfer buffer, using a default timing
1134  */
FDC_Buffer_Add(Uint8 Byte)1135 void	FDC_Buffer_Add ( Uint8 Byte )
1136 {
1137 	FDC_Buffer_Add_Timing ( Byte , FDC_TransferByte_FdcCycles ( 1 ) );
1138 }
1139 
1140 
1141 /*-----------------------------------------------------------------------*/
1142 /**
1143  * Return the timing needed to transfer the Byte at the current position
1144  */
FDC_Buffer_Read_Timing(void)1145 Uint16	FDC_Buffer_Read_Timing ( void )
1146 {
1147 //fprintf ( stderr , "read timing %d %x\n" , FDC_BUFFER.PosRead , FDC_BUFFER.Data[ FDC_BUFFER.PosRead ].Timing );
1148 	return FDC_BUFFER.Data[ FDC_BUFFER.PosRead ].Timing;
1149 }
1150 
1151 
1152 /*-----------------------------------------------------------------------*/
1153 /**
1154  * Return the Byte at the current position and increment position
1155  */
FDC_Buffer_Read_Byte(void)1156 Uint8	FDC_Buffer_Read_Byte ( void )
1157 {
1158 //fprintf ( stderr , "read byte %d %x\n" , FDC_BUFFER.PosRead , FDC_BUFFER.Data[ FDC_BUFFER.PosRead ].Byte );
1159 	return FDC_BUFFER.Data[ FDC_BUFFER.PosRead++ ].Byte;
1160 }
1161 
1162 
1163 /*-----------------------------------------------------------------------*/
1164 /**
1165  * Return the Byte at a given position
1166  */
FDC_Buffer_Read_Byte_pos(int pos)1167 Uint8	FDC_Buffer_Read_Byte_pos ( int pos )
1168 {
1169 //fprintf ( stderr , "read byte pos %d %x\n" , pos , FDC_BUFFER.Data[ pos ].Byte );
1170 	return FDC_BUFFER.Data[ pos ].Byte;
1171 }
1172 
1173 
1174 /*-----------------------------------------------------------------------*/
1175 /**
1176  * Return the number of bytes stored in FDC_BUFFER
1177  */
FDC_Buffer_Get_Size(void)1178 int	FDC_Buffer_Get_Size ( void )
1179 {
1180 	return FDC_BUFFER.Size;
1181 }
1182 
1183 
1184 /*-----------------------------------------------------------------------*/
1185 /**
1186  * Return the mode to handle a read/write in $ff86xx
1187  * Depending on the images inserted in each floppy drive and on the
1188  * selected drive, we must choose which fdc emulation should be used.
1189  * Possible emulation methods are 'internal' or 'ipf'.
1190  * To avoid mixing emulation methods on both drives when possible (which
1191  * could lead to inconstancies when precise timings are required), we also
1192  * use the IPF mode for an empty drive if the other drive contains an IPF
1193  * image.
1194  * If no drive is selected, we must use the previous mode (before drives were
1195  * unselected), not the internal one : in case some commands are sent when
1196  * drives are deselected and the drive was in IPF mode, we must send
1197  * the command to IPF to ensure no command are lost if the drive is selected again
1198  * (eg : D0 command in "Saint Dragon" IPF)
1199  */
FDC_GetEmulationMode(void)1200 static int FDC_GetEmulationMode ( void )
1201 {
1202 	int	Mode;
1203 
1204 	Mode = FDC.EmulationMode;				/* Default to previous mode if no drive is selected */
1205 
1206 	/* Check drive 1 first */
1207 	if ( ( PSGRegisters[PSG_REG_IO_PORTA] & 0x04 ) == 0 )
1208 	{
1209 		if ( EmulationDrives[ 1 ].ImageType == FLOPPY_IMAGE_TYPE_IPF )
1210 			Mode = FDC_EMULATION_MODE_IPF;
1211 		else if ( ( EmulationDrives[ 1 ].ImageType == FLOPPY_IMAGE_TYPE_NONE )		/* Drive 1 is empty */
1212 			&& ( EmulationDrives[ 0 ].ImageType == FLOPPY_IMAGE_TYPE_IPF ) )	/* Drive 0 is an IPF image */
1213 			Mode = FDC_EMULATION_MODE_IPF;						/* Use IPF for drive 1 too */
1214 		else
1215 			Mode = FDC_EMULATION_MODE_INTERNAL;
1216 	}
1217 
1218 	/* If both drive 0 and drive 1 are enabled, we keep only drive 0 to choose emulation's mode */
1219 	if ( ( PSGRegisters[PSG_REG_IO_PORTA] & 0x02 ) == 0 )
1220 	{
1221 		if ( EmulationDrives[ 0 ].ImageType == FLOPPY_IMAGE_TYPE_IPF )
1222 			Mode = FDC_EMULATION_MODE_IPF;
1223 		else if ( ( EmulationDrives[ 0 ].ImageType == FLOPPY_IMAGE_TYPE_NONE )		/* Drive 0 is empty */
1224 			&& ( EmulationDrives[ 1 ].ImageType == FLOPPY_IMAGE_TYPE_IPF ) )	/* Drive 1 is an IPF image */
1225 			Mode = FDC_EMULATION_MODE_IPF;						/* Use IPF for drive 0 too */
1226 		else
1227 			Mode = FDC_EMULATION_MODE_INTERNAL;
1228 	}
1229 
1230 	FDC.EmulationMode = Mode;
1231 //fprintf ( stderr , "emul mode %x %d\n" , PSGRegisters[PSG_REG_IO_PORTA] & 0x06 , Mode );
1232 //	return FDC_EMULATION_MODE_INTERNAL;
1233 //	return FDC_EMULATION_MODE_IPF;
1234 	return Mode;
1235 }
1236 
1237 
1238 /*-----------------------------------------------------------------------*/
1239 /**
1240  * Update the FDC's internal variables on a regular basis.
1241  * To get correct accuracy, this should be called every 200-500 FDC cycles
1242  * So far, we only need to update the index position for the valid
1243  * drive/floppy ; updating every 500 cycles is enough for this case.
1244  */
FDC_UpdateAll(void)1245 static void FDC_UpdateAll(void)
1246 {
1247 	FDC_IndexPulse_Update ();
1248 }
1249 
1250 
1251 /*-----------------------------------------------------------------------*/
1252 /**
1253  * This function is used to enable/disable a drive when
1254  * using the UI or command line parameters
1255  */
FDC_Drive_Set_Enable(int Drive,bool value)1256 void	FDC_Drive_Set_Enable ( int Drive , bool value )
1257 {
1258 	LOG_TRACE ( TRACE_FDC , "fdc enable drive=%d %s\n" , Drive , value?"on":"off" );
1259 
1260 	if ( ( Drive >= 0 ) && ( Drive < MAX_FLOPPYDRIVES ) )
1261 		FDC_DRIVES[ Drive ].Enabled = value;
1262 
1263 	/* Also forward change to IPF emulation */
1264 	IPF_Drive_Set_Enable ( Drive , value );
1265 }
1266 
1267 
1268 /*-----------------------------------------------------------------------*/
1269 /**
1270  * This function is used to choose single sided or double sided for a drive
1271  * when using the UI or command line parameters
1272  */
FDC_Drive_Set_NumberOfHeads(int Drive,int NbrHeads)1273 void	FDC_Drive_Set_NumberOfHeads ( int Drive , int NbrHeads )
1274 {
1275 	LOG_TRACE ( TRACE_FDC , "fdc set nbr heads drive=%d %d\n" , Drive , NbrHeads );
1276 
1277 	if ( ( Drive >= 0 ) && ( Drive < MAX_FLOPPYDRIVES ) )
1278 		FDC_DRIVES[ Drive ].NumberOfHeads = NbrHeads;
1279 
1280 	/* Also forward change to IPF emulation */
1281 	IPF_Drive_Set_DoubleSided ( Drive , NbrHeads==2 ? true : false );
1282 }
1283 
1284 
1285 /*-----------------------------------------------------------------------*/
1286 /**
1287  * This function is called when a floppy is inserted in a drive
1288  * using the UI or command line parameters
1289  */
FDC_InsertFloppy(int Drive)1290 void	FDC_InsertFloppy ( int Drive )
1291 {
1292 	LOG_TRACE ( TRACE_FDC , "fdc insert drive=%d\n" , Drive );
1293 
1294 	if ( ( Drive >= 0 ) && ( Drive < MAX_FLOPPYDRIVES ) )
1295 	{
1296 		FDC_DRIVES[ Drive ].DiskInserted = true;
1297 		if ( ( FDC.STR & FDC_STR_BIT_MOTOR_ON ) != 0 )		/* If we insert a floppy while motor is already on, we must */
1298 			FDC_IndexPulse_Init ( Drive );			/* init the index pulse's position */
1299 		else
1300 			FDC_DRIVES[ Drive ].IndexPulse_Time = 0;	/* Index pulse's position not known yet */
1301 		FDC_DRIVES[ Drive ].Density = FDC_GetDensity ( Drive );
1302 	}
1303 }
1304 
1305 
1306 /*-----------------------------------------------------------------------*/
1307 /**
1308  * This function is called when a floppy is ejected from a drive
1309  * using the UI or command line parameters
1310  */
FDC_EjectFloppy(int Drive)1311 void	FDC_EjectFloppy ( int Drive )
1312 {
1313 	LOG_TRACE ( TRACE_FDC , "fdc eject drive=%d\n" , Drive );
1314 
1315 	if ( ( Drive >= 0 ) && ( Drive < MAX_FLOPPYDRIVES ) )
1316 	{
1317 		FDC_DRIVES[ Drive ].DiskInserted = false;
1318 		FDC_DRIVES[ Drive ].IndexPulse_Time = 0;		/* Stop counting index pulses on an empty drive */
1319 	}
1320 }
1321 
1322 
1323 /*-----------------------------------------------------------------------*/
1324 /**
1325  * Handle a write in the IO_PORTA register $E through $ff8802. Only bits
1326  * 0-2 are available here, others are masked to 0.
1327  * bit 0 : side select
1328  * bit 1-2 : drive select
1329  *
1330  * - For internal FDC emulation, we init index pulse if the active drive
1331  *   changed
1332  * - We also forward the change to IPF emulation, as it doesn't have direct access
1333  *   to this IO_PORTA register.
1334  *
1335  * If both drives are selected, we keep only drive 0
1336  */
FDC_SetDriveSide(Uint8 io_porta_old,Uint8 io_porta_new)1337 void	FDC_SetDriveSide ( Uint8 io_porta_old , Uint8 io_porta_new )
1338 {
1339 	int	Side;
1340 	int	Drive;
1341 
1342 	if ( io_porta_old == io_porta_new )
1343 		return;							/* No change */
1344 
1345 	Side = ( (~io_porta_new) & 0x01 );				/* Side 0 or 1 */
1346 
1347 	Drive = -1;							/* By default, don't select any drive */
1348 
1349 	/* Check drive 1 first */
1350 	if ( ( io_porta_new & 0x04 ) == 0 )
1351 		Drive = 1;						/* Select drive 1 */
1352 
1353 	/* If both drive 0 and drive 1 are enabled, we keep only drive 0 as newdrive */
1354 	if ( ( io_porta_new & 0x02 ) == 0 )
1355 		Drive = 0;						/* Select drive 0 (and un-select drive 1 if set above) */
1356 
1357 	LOG_TRACE(TRACE_FDC, "fdc change drive/side io_porta_old=0x%x io_porta_new=0x%x side %d->%d drive %d->%d VBL=%d HBL=%d\n" ,
1358 		  io_porta_old , io_porta_new , FDC.SideSignal , Side , FDC.DriveSelSignal , Drive , nVBLs , nHBL );
1359 
1360 	if ( FDC.DriveSelSignal != Drive )
1361 	{
1362 		if ( FDC.DriveSelSignal >= 0 )					/* A drive was previously enabled */
1363 			FDC_DRIVES[ FDC.DriveSelSignal ].IndexPulse_Time = 0;	/* Stop counting index pulses on the previous drive */
1364 
1365 		if ( Drive >= 0 )						/* A new drive is enabled */
1366 		{
1367 			if ( ( FDC_DRIVES[ Drive ].DiskInserted )		/* If there's a disk in the new drive and motor is already */
1368 			  && ( ( FDC.STR & FDC_STR_BIT_MOTOR_ON ) != 0 ) )	/* on, we must init the index pulse's position */
1369 				FDC_IndexPulse_Init ( Drive );
1370 			else
1371 				FDC_DRIVES[ Drive ].IndexPulse_Time = 0;	/* Index pulse's position not known yet */
1372 		}
1373 	}
1374 
1375 	FDC.SideSignal = Side;
1376 	FDC.DriveSelSignal = Drive;
1377 
1378 
1379 	/* Also forward change to IPF emulation */
1380 	IPF_SetDriveSide ( io_porta_old , io_porta_new );
1381 }
1382 
1383 
1384 /*-----------------------------------------------------------------------*/
1385 /**
1386  * Return the number of sectors for track/side for the current floppy in a drive
1387  * TODO [NP] : this function calls Floppy_FindDiskDetails which handles only ST/MSA
1388  * disk images so far, so this implies all tracks have in fact the same number
1389  * of sectors (we don't use Track and Side for now)
1390  * Drive should be a valid drive (0 or 1)
1391  */
FDC_GetSectorsPerTrack(int Drive,int Track,int Side)1392 static int FDC_GetSectorsPerTrack ( int Drive , int Track , int Side )
1393 {
1394 	Uint16	SectorsPerTrack;
1395 
1396 	if (EmulationDrives[ Drive ].bDiskInserted)
1397 	{
1398 		Floppy_FindDiskDetails ( EmulationDrives[ Drive ].pBuffer , EmulationDrives[ Drive ].nImageBytes , &SectorsPerTrack , NULL );
1399 		return SectorsPerTrack;
1400 	}
1401 	else
1402 		return 0;
1403 }
1404 
1405 
1406 /*-----------------------------------------------------------------------*/
1407 /**
1408  * Return the number of sides for a track for the current floppy in a drive
1409  * Drive should be a valid drive (0 or 1)
1410  */
FDC_GetSidesPerDisk(int Drive,int Track)1411 static int FDC_GetSidesPerDisk ( int Drive , int Track )
1412 {
1413 	Uint16	SidesPerDisk;
1414 
1415 	if (EmulationDrives[ Drive ].bDiskInserted)
1416 	{
1417 		Floppy_FindDiskDetails ( EmulationDrives[ Drive ].pBuffer , EmulationDrives[ Drive ].nImageBytes , NULL , &SidesPerDisk );
1418 		return SidesPerDisk;					/* 1 or 2 */
1419 	}
1420 	else
1421 		return 0;
1422 }
1423 
1424 
1425 /*-----------------------------------------------------------------------*/
1426 /**
1427  * Return the number of tracks for the current floppy in a drive
1428  * For ST/MSA, this assumes both sides have the same number of tracks
1429  * Drive should be a valid drive (0 or 1)
1430  */
FDC_GetTracksPerDisk(int Drive)1431 static int FDC_GetTracksPerDisk ( int Drive )
1432 {
1433 	Uint16	SectorsPerTrack;
1434 	Uint16	SidesPerDisk;
1435 
1436 	if (EmulationDrives[ Drive ].bDiskInserted)
1437 	{
1438 		Floppy_FindDiskDetails ( EmulationDrives[ Drive ].pBuffer , EmulationDrives[ Drive ].nImageBytes , &SectorsPerTrack , &SidesPerDisk );
1439 		return ( ( EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR ) / SectorsPerTrack ) / SidesPerDisk;
1440 	}
1441 	else
1442 		return 0;
1443 }
1444 
1445 
1446 /*-----------------------------------------------------------------------*/
1447 /**
1448  * Return a density factor for the current floppy in a drive
1449  * A DD track is usually 9 or 10 sectors and has a x1 factor,
1450  * but to handle HD or ED ST/MSA disk images, we check if we
1451  * have more than 18 or 36 sectors.
1452  * In that case, we use a x2 or x4 factor for theses disks,
1453  * to simulate more bytes per FDC cycles.
1454  * Drive should be a valid drive (0 or 1)
1455  */
FDC_GetDensity(int Drive)1456 static int FDC_GetDensity ( int Drive )
1457 {
1458 	Uint16	SectorsPerTrack;
1459 
1460 	if ( EmulationDrives[ Drive ].bDiskInserted )
1461 	{
1462 		SectorsPerTrack = FDC_GetSectorsPerTrack ( Drive , FDC_DRIVES[ Drive ].HeadTrack , FDC.SideSignal );
1463 		if ( SectorsPerTrack >= 36 )
1464 			return FDC_DENSITY_FACTOR_ED;			/* Simulate a ED disk, 36 sectors or more */
1465 		else if ( SectorsPerTrack >= 18 )
1466 			return FDC_DENSITY_FACTOR_HD;			/* Simulate a HD disk, between 18 and 36 sectors */
1467 		else
1468 			return FDC_DENSITY_FACTOR_DD;			/* Normal DD disk */
1469 	}
1470 	else
1471 		return FDC_DENSITY_FACTOR_DD;				/* No disk, default to Double Density */
1472 }
1473 
1474 
1475 /*-----------------------------------------------------------------------*/
1476 /**
1477  * Return the number of bytes in a raw track
1478  * For ST/MSA disk images, we consider all the tracks have the same size.
1479  * To simulate HD/ED floppies, we multiply the size by a density factor.
1480  * Drive should be a valid drive (0 or 1)
1481  */
FDC_GetBytesPerTrack(int Drive)1482 int	FDC_GetBytesPerTrack ( int Drive )
1483 {
1484 	int	TrackSize;
1485 
1486 	TrackSize = FDC_TRACK_BYTES_STANDARD;				/* For a standard DD disk */
1487 	return TrackSize * FDC_DRIVES[ Drive ].Density;			/* Take density into account for HD/ED floppies */
1488 }
1489 
1490 
1491 /*-----------------------------------------------------------------------*/
1492 /**
1493  * Get the number of FDC cycles for one revolution of the floppy
1494  * RPM is already multiplied by 1000 to simulate non-integer values
1495  * (for Falcon, we divide cycles by 2 to simulate a FDC freq in the 8 MHz range)
1496  * For STX image, the number of cycles depends on drive/track/side.
1497  * Drive should be a valid drive (0 or 1)
1498  */
FDC_GetCyclesPerRev_FdcCycles(int Drive)1499 static Uint32	FDC_GetCyclesPerRev_FdcCycles ( int Drive )
1500 {
1501 	Uint32	FdcCyclesPerRev;
1502 
1503 	assert(Drive == 0 || Drive == 1);
1504 
1505 	/* If the inserted disk is an STX, we use the supplied track length to compute cycles per rev */
1506 	if ( EmulationDrives[Drive].ImageType == FLOPPY_IMAGE_TYPE_STX )
1507 		return FDC_GetCyclesPerRev_FdcCycles_STX ( Drive , FDC_DRIVES[ Drive ].HeadTrack , FDC.SideSignal );
1508 
1509 	/* Assume a standard length for all tracks for ST/MSA images */
1510 	FdcCyclesPerRev = (Uint64)(MachineClocks.FDC_Freq * 1000.L) / ( FDC_DRIVES[ Drive ].RPM / 60 );
1511 
1512 	/* Our conversion expects FDC_Freq to be nearly the same as CPU_Freq (8 Mhz) */
1513 	/* but the Falcon uses a 16 MHz clock for the Ajax FDC */
1514 	/* FIXME : this should be handled better, without involving 8 MHz CPU_Freq */
1515 	if (Config_IsMachineFalcon())
1516 		FdcCyclesPerRev /= 2;					/* correct delays for a 8 MHz FDC_Freq clock instead of 16 */
1517 
1518 	return FdcCyclesPerRev;
1519 }
1520 
1521 
1522 
1523 /*-----------------------------------------------------------------------*/
1524 /**
1525  * If some valid drive/floppy are available and the motor signal is on,
1526  * update the current angular position for the drive and check if
1527  * a new index pulse was reached. Increase Index Pulse counter in that case.
1528  *
1529  * This function should be called at least every 500 FDC cycles when motor
1530  * is ON to get good accuracy.
1531  *
1532  * [NP] TODO : should we have 2 different Index Pulses for each side or do they
1533  * happen at the same time ?
1534  */
FDC_IndexPulse_Update(void)1535 static void FDC_IndexPulse_Update(void)
1536 {
1537 	Uint32	FdcCyclesPerRev;
1538 	int	FrameCycles, HblCounterVideo, LineCycles;
1539 
1540 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1541 
1542 //fprintf ( stderr , "update index drive=%d side=%d counter=%d VBL=%d HBL=%d\n" , FDC.DriveSelSignal , FDC.SideSignal , FDC.IndexPulse_Counter , nVBLs , nHBL );
1543 
1544 	if ( ( FDC.STR & FDC_STR_BIT_MOTOR_ON ) == 0 )
1545 		return;							/* Motor is OFF, nothing to update */
1546 
1547 	if ( ( FDC.DriveSelSignal < 0 ) || ( !FDC_DRIVES[ FDC.DriveSelSignal ].Enabled )
1548 		|| ( !FDC_DRIVES[ FDC.DriveSelSignal ].DiskInserted ) )
1549 		return;							/* No valid drive/floppy, nothing to update */
1550 
1551 	if ( FDC_DRIVES[ FDC.DriveSelSignal ].IndexPulse_Time == 0 )	/* No reference Index Pulse for this drive */
1552 		FDC_IndexPulse_Init ( FDC.DriveSelSignal );		/* (could be the case after a 'reset') */
1553 
1554 	FdcCyclesPerRev = FDC_GetCyclesPerRev_FdcCycles ( FDC.DriveSelSignal );
1555 
1556 	if ( CyclesGlobalClockCounter - FDC_DRIVES[ FDC.DriveSelSignal ].IndexPulse_Time >= FDC_FdcCyclesToCpuCycles ( FdcCyclesPerRev ) )
1557 	{
1558 		/* Store new position of the most recent Index Pulse */
1559 		FDC_DRIVES[ FDC.DriveSelSignal ].IndexPulse_Time += FDC_FdcCyclesToCpuCycles ( FdcCyclesPerRev );
1560 		FDC.IndexPulse_Counter++;
1561 		LOG_TRACE(TRACE_FDC, "fdc update index drive=%d side=%d counter=%d ip_time=%"PRIu64" VBL=%d HBL=%d\n" ,
1562 			FDC.DriveSelSignal , FDC.SideSignal , FDC.IndexPulse_Counter ,
1563 			FDC_DRIVES[ FDC.DriveSelSignal ].IndexPulse_Time , nVBLs , nHBL );
1564 
1565 		if ( FDC.InterruptCond & FDC_INTERRUPT_COND_IP )	/* Do we have a "force int on index pulse" command running ? */
1566 		{
1567 			LOG_TRACE(TRACE_FDC, "fdc type IV force int on index, set irq VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
1568 				nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1569 			FDC_SetIRQ ( FDC_IRQ_SOURCE_INDEX );
1570 		}
1571 	}
1572 }
1573 
1574 
1575 /*-----------------------------------------------------------------------*/
1576 /**
1577  * When motor is started, the position of the next index pulse will be random,
1578  * as we don't know how much the floppy rotated when the motor was stopped or
1579  * the floppy was inserted.
1580  * We compute a random position in the "past" (less than one revolution)
1581  * and use it as a reference to detect the next index pulse.
1582  *
1583  */
FDC_IndexPulse_Init(int Drive)1584 static void	FDC_IndexPulse_Init ( int Drive )
1585 {
1586 	Uint32	FdcCyclesPerRev;
1587 	Uint64	IndexPulse_Time;
1588 
1589 	FdcCyclesPerRev = FDC_GetCyclesPerRev_FdcCycles ( Drive );
1590 	IndexPulse_Time = CyclesGlobalClockCounter - rand () % FDC_FdcCyclesToCpuCycles ( FdcCyclesPerRev );
1591 	if ( IndexPulse_Time <= 0 )					/* Should not happen (only if FDC_IndexPulse_Init is */
1592 		IndexPulse_Time = 1;					/* called just after emulation starts) */
1593 	FDC_DRIVES[ Drive ].IndexPulse_Time = IndexPulse_Time;
1594 
1595 	LOG_TRACE(TRACE_FDC, "fdc init index drive=%d side=%d counter=%d ip_time=%"PRIu64" VBL=%d HBL=%d\n" ,
1596 		  FDC.DriveSelSignal , FDC.SideSignal , FDC.IndexPulse_Counter ,
1597 		  FDC_DRIVES[ FDC.DriveSelSignal ].IndexPulse_Time , nVBLs , nHBL );
1598 }
1599 
1600 
1601 /*-----------------------------------------------------------------------*/
1602 /**
1603  * Return the number of FDC cycles since the previous index pulse signal
1604  * for the current drive.
1605  * If there's no available drive/floppy (i.e. no index), we return -1
1606  */
FDC_IndexPulse_GetCurrentPos_FdcCycles(Uint32 * pFdcCyclesPerRev)1607 int	FDC_IndexPulse_GetCurrentPos_FdcCycles ( Uint32 *pFdcCyclesPerRev )
1608 {
1609 	Uint32	FdcCyclesPerRev;
1610 	Uint32	CpuCyclesSinceIndex;
1611 
1612 	if ( ( FDC.DriveSelSignal < 0 ) || ( FDC_DRIVES[ FDC.DriveSelSignal ].IndexPulse_Time == 0 ) )
1613 		return -1;
1614 
1615 	FdcCyclesPerRev = FDC_GetCyclesPerRev_FdcCycles ( FDC.DriveSelSignal );
1616 	CpuCyclesSinceIndex = CyclesGlobalClockCounter - FDC_DRIVES[ FDC.DriveSelSignal ].IndexPulse_Time;
1617 
1618 	if ( pFdcCyclesPerRev )
1619 		*pFdcCyclesPerRev = FdcCyclesPerRev;
1620 
1621 //fprintf ( stderr , "current pos %d %lld %d %lld\n" , FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].IndexPulse_Time ,
1622 //      FdcCyclesPerRev , CyclesGlobalClockCounter - FDC_DRIVES[ FDC.DriveSelSignal ].IndexPulse_Time );
1623 
1624 	return FDC_CpuCyclesToFdcCycles ( CpuCyclesSinceIndex );
1625 }
1626 
1627 
1628 /*-----------------------------------------------------------------------*/
1629 /**
1630  * Return the current position in the track relative to the index pulse.
1631  * For standard floppy, this is a number of bytes in the range [0,6250[
1632  * If there's no available drive/floppy and no index, we return -1
1633  * To simulate HD/ED floppies, we multiply the number of bytes by a density factor.
1634  */
FDC_IndexPulse_GetCurrentPos_NbBytes(void)1635 int	FDC_IndexPulse_GetCurrentPos_NbBytes ( void )
1636 {
1637 	int	FdcCyclesSinceIndex;
1638 
1639 	FdcCyclesSinceIndex = FDC_IndexPulse_GetCurrentPos_FdcCycles ( NULL );
1640 	if ( FdcCyclesSinceIndex < 0 )					/* No drive/floppy available at the moment */
1641 		return -1;
1642 //fprintf ( stderr , "fdc index current pos new=%d\n" , FdcCyclesSinceIndex / FDC_DELAY_CYCLE_MFM_BYTE );
1643 
1644 	return FdcCyclesSinceIndex * FDC_DRIVES[ FDC.DriveSelSignal ].Density / FDC_DELAY_CYCLE_MFM_BYTE;
1645 }
1646 
1647 
1648 
1649 /*-----------------------------------------------------------------------*/
1650 /**
1651  * Return the current state of the index pulse signal.
1652  * The signal goes to 1 when reaching the index pulse location and remain
1653  * to 1 during 1.5 ms (approx 46 bytes).
1654  * During the rest of the track, the signal will be 0 (it will also be 0
1655  * if the drive if OFF or empty)
1656  */
FDC_IndexPulse_GetState(void)1657 int	FDC_IndexPulse_GetState ( void )
1658 {
1659 	int	state;
1660 	int	FdcCyclesSinceIndex;
1661 
1662 	FdcCyclesSinceIndex = FDC_IndexPulse_GetCurrentPos_FdcCycles ( NULL );
1663 
1664 	state = 0;
1665 	if ( ( FdcCyclesSinceIndex >= 0 )				/* We have a valid drive/floppy */
1666 	  && ( (Uint32)FdcCyclesSinceIndex < FDC_DelayToFdcCycles ( FDC_DELAY_US_INDEX_PULSE_LENGTH ) ) )
1667 		state = 1;
1668 
1669 //fprintf ( stderr , "fdc index state 2 pos pos=%d state=%d\n" , FdcCyclesSinceIndex , state );
1670 	return state;
1671 }
1672 
1673 
1674 /*-----------------------------------------------------------------------*/
1675 /**
1676  * Return the number of FDC cycles before reaching the next index pulse signal.
1677  * If there's no available drive/floppy and no index, we return -1
1678  */
FDC_NextIndexPulse_FdcCycles(void)1679 int	FDC_NextIndexPulse_FdcCycles ( void )
1680 {
1681 	Uint32	FdcCyclesPerRev;
1682 	int	FdcCyclesSinceIndex;
1683 	int	res;
1684 
1685 	FdcCyclesSinceIndex = FDC_IndexPulse_GetCurrentPos_FdcCycles ( &FdcCyclesPerRev );
1686 	if ( FdcCyclesSinceIndex < 0 )					/* No drive/floppy available at the moment */
1687 		return -1;
1688 
1689 	res = FdcCyclesPerRev - FdcCyclesSinceIndex;
1690 
1691 	/* If the next IP is in 0 or 1 cycle, we consider this is a rounding error */
1692 	/* and we wait for one full revolution (this can happen in Force Int on Index Pulse */
1693 	/* when we call FDC_NextIndexPulse_FdcCycles in a loop) */
1694 	if ( res <= 1 )
1695 		res = FdcCyclesPerRev;					// TODO : 0 should be allowed
1696 
1697 //fprintf ( stderr , "fdc next index current pos new=%d\n" , res );
1698 	return res;
1699 }
1700 
1701 
1702 /*-----------------------------------------------------------------------*/
1703 /**
1704  * Set the IRQ signal
1705  * This is called either on command completion, or when an index pulse
1706  * is received or when the "force interrupt immediate" command is used.
1707  * This function can also be called from the HDC emulation or from another
1708  * FDC emulation module (IPF for example)
1709  *
1710  * NOTE : although high/1 on the IRQ pin of the FDC means an interrupt is
1711  * requested, this signal is inverted before going into MFP's GPIP5.
1712  * So, we must set the line to low/0 to request an interrupt.
1713  */
FDC_SetIRQ(Uint8 IRQ_Source)1714 void FDC_SetIRQ ( Uint8 IRQ_Source )
1715 {
1716 	if ( FDC.IRQ_Signal != 0 )					/* Don't set MFP's IRQ again if already set */
1717 	{
1718 	  LOG_TRACE(TRACE_FDC, "fdc set irq, irq 0x%x already set VBL=%d HBL=%d\n" , FDC.IRQ_Signal , nVBLs , nHBL );
1719 	}
1720 
1721 	else
1722 	{
1723 		/* Acknowledge in MFP circuit, pass bit, enable, pending */
1724 		MFP_GPIP_Set_Line_Input ( MFP_GPIP_LINE_FDC_HDC , MFP_GPIP_STATE_LOW );
1725 		LOG_TRACE(TRACE_FDC, "fdc set irq 0x%x source 0x%x VBL=%d HBL=%d\n" , FDC.IRQ_Signal , IRQ_Source , nVBLs , nHBL );
1726 	}
1727 
1728 	/* If IRQ comes from HDC or other sources (IPF), we don't need */
1729 	/* to handle the forced IRQ case used in FDC */
1730 	if ( IRQ_Source == FDC_IRQ_SOURCE_HDC )
1731 		FDC.IRQ_Signal = FDC_IRQ_SOURCE_HDC;
1732 
1733 	else if ( IRQ_Source == FDC_IRQ_SOURCE_OTHER )
1734 		FDC.IRQ_Signal = FDC_IRQ_SOURCE_OTHER;
1735 
1736 	else								/* IRQ comes from FDC */
1737 	{
1738 		FDC.IRQ_Signal &= ~( FDC_IRQ_SOURCE_HDC | FDC_IRQ_SOURCE_OTHER );
1739 		FDC.IRQ_Signal |= IRQ_Source;
1740 	}
1741 }
1742 
1743 
1744 /*-----------------------------------------------------------------------*/
1745 /**
1746  * Reset the IRQ signal ; in case the source of the interrupt is also
1747  * a "force interrupt immediate" command, the IRQ signal should not be cleared
1748  * (only command 0xD0 or any new command followed by a read of status reg
1749  * can clear the forced IRQ)
1750  *
1751  * NOTE : although low/0 on the IRQ pin of the FDC means interrupt is
1752  * cleared, this signal is inverted before going into MFP's GPIP5.
1753  * So, we must set the line to high/1 to clear interrupt request.
1754  */
FDC_ClearIRQ(void)1755 void FDC_ClearIRQ ( void )
1756 {
1757 	if ( ( FDC.IRQ_Signal & FDC_IRQ_SOURCE_FORCED ) == 0 )
1758 	{
1759 		FDC.IRQ_Signal = 0;
1760 		MFP_GPIP_Set_Line_Input ( MFP_GPIP_LINE_FDC_HDC , MFP_GPIP_STATE_HIGH );
1761 		LOG_TRACE(TRACE_FDC, "fdc clear irq VBL=%d HBL=%d\n" , nVBLs , nHBL );
1762 	}
1763 
1764 	else
1765 	{
1766 		FDC.IRQ_Signal &= FDC_IRQ_SOURCE_FORCED;		/* Clear all sources except 'forced irq' and keep IRQ set in MFP */
1767 		LOG_TRACE(TRACE_FDC, "fdc clear irq not done, irq forced VBL=%d HBL=%d\n" , nVBLs , nHBL );
1768 	}
1769 }
1770 
FDC_ClearHdcIRQ(void)1771 void FDC_ClearHdcIRQ(void)
1772 {
1773 	FDC.IRQ_Signal &= ~FDC_IRQ_SOURCE_HDC;
1774 	if (FDC.IRQ_Signal == 0)
1775 	{
1776 		MFP_GPIP_Set_Line_Input ( MFP_GPIP_LINE_FDC_HDC , MFP_GPIP_STATE_HIGH );
1777 	}
1778 }
1779 
1780 /*-----------------------------------------------------------------------*/
1781 /**
1782  * Handle the current FDC command.
1783  * We use a timer to go from one state to another to emulate the different
1784  * phases of an FDC command.
1785  * When the command completes (success or failure), FDC.Command will be
1786  * set to FDCEMU_CMD_NULL. Until then, this function will be called to
1787  * handle each state of the command and the corresponding delay in micro
1788  * seconds.
1789  * This handler is called after a first delay corresponding to the prepare
1790  * delay and the eventual motor on delay.
1791  * Once we reach this point, the current command can not be replaced by
1792  * another command (except 'Force Interrupt')
1793  */
FDC_InterruptHandler_Update(void)1794 void FDC_InterruptHandler_Update ( void )
1795 {
1796 	int	FdcCycles = 0;
1797 	int	PendingCyclesOver;
1798 
1799 	/* Number of internal cycles we went over for this timer ( <= 0 ) */
1800 	/* Used to restart the next timer and keep a constant rate (important for DMA transfers) */
1801 	PendingCyclesOver = -PendingInterruptCount;			/* >= 0 */
1802 
1803 //fprintf ( stderr , "fdc int handler %lld delay %d\n" , CyclesGlobalClockCounter, PendingCyclesOver );
1804 
1805 	CycInt_AcknowledgeInterrupt();
1806 
1807 	do								/* We loop as long as FdcCycles == 0 (immediate change of state) */
1808 	{
1809 		/* Update FDC's internal variables */
1810 		FDC_UpdateAll ();
1811 
1812 		/* Is FDC active? */
1813 		if (FDC.Command!=FDCEMU_CMD_NULL)
1814 		{
1815 			/* Which command are we running ? */
1816 			switch(FDC.Command)
1817 			{
1818 			case FDCEMU_CMD_RESTORE:
1819 				FdcCycles = FDC_UpdateRestoreCmd();
1820 				break;
1821 			case FDCEMU_CMD_SEEK:
1822 				FdcCycles = FDC_UpdateSeekCmd();
1823 				break;
1824 			case FDCEMU_CMD_STEP:
1825 				FdcCycles = FDC_UpdateStepCmd();
1826 				break;
1827 
1828 			case FDCEMU_CMD_READSECTORS:
1829 				FdcCycles = FDC_UpdateReadSectorsCmd();
1830 				break;
1831 			case FDCEMU_CMD_WRITESECTORS:
1832 				FdcCycles = FDC_UpdateWriteSectorsCmd();
1833 				break;
1834 
1835 			case FDCEMU_CMD_READADDRESS:
1836 				FdcCycles = FDC_UpdateReadAddressCmd();
1837 				break;
1838 
1839 			case FDCEMU_CMD_READTRACK:
1840 				FdcCycles = FDC_UpdateReadTrackCmd();
1841 				break;
1842 
1843 			case FDCEMU_CMD_WRITETRACK:
1844 				FdcCycles = FDC_UpdateWriteTrackCmd();
1845 				break;
1846 
1847 			case FDCEMU_CMD_MOTOR_STOP:
1848 				FdcCycles = FDC_UpdateMotorStop();
1849 				break;
1850 			}
1851 		}
1852 	}
1853 	while ( ( FDC.Command != FDCEMU_CMD_NULL ) && ( FdcCycles == 0 ) );
1854 
1855 	if ( FDC.Command != FDCEMU_CMD_NULL )
1856 	{
1857 		FDC_StartTimer_FdcCycles ( FdcCycles , -PendingCyclesOver );
1858 	}
1859 }
1860 
1861 
1862 /*-----------------------------------------------------------------------*/
1863 /**
1864  * Return the type of a command, based on the upper bits of CR
1865  */
FDC_GetCmdType(Uint8 CR)1866 Uint8 FDC_GetCmdType ( Uint8 CR )
1867 {
1868 	if ( ( CR & 0x80 ) == 0 )					/* Type I - Restore, Seek, Step, Step-In, Step-Out */
1869 		return 1;
1870 	else if ( ( CR & 0x40 ) == 0 )					/* Type II - Read Sector, Write Sector */
1871 		return 2;
1872 	else if ( ( CR & 0xf0 ) != 0xd0 )				/* Type III - Read Address, Read Track, Write Track */
1873 		return 3;
1874 	else								/* Type IV - Force Interrupt */
1875 		return 4;
1876 }
1877 
1878 
1879 /*-----------------------------------------------------------------------*/
1880 /**
1881  * Update the FDC's Status Register.
1882  * All bits in DisableBits are cleared in STR, then all bits in EnableBits
1883  * are set in STR.
1884  */
FDC_Update_STR(Uint8 DisableBits,Uint8 EnableBits)1885 static void FDC_Update_STR ( Uint8 DisableBits , Uint8 EnableBits )
1886 {
1887 	FDC.STR &= (~DisableBits);					/* Clear bits in DisableBits */
1888 	FDC.STR |= EnableBits;						/* Set bits in EnableBits */
1889 
1890 	FDC_Drive_Set_BusyLed ( FDC.STR );
1891 //fprintf ( stderr , "fdc str 0x%x\n" , FDC.STR );
1892 }
1893 
1894 
1895 /*-----------------------------------------------------------------------*/
1896 /**
1897  * Common to all commands once they're completed :
1898  * - remove busy bit
1899  * - set interrupt if necessary
1900  * - stop motor after 2 sec
1901  */
FDC_CmdCompleteCommon(bool DoInt)1902 static int FDC_CmdCompleteCommon ( bool DoInt )
1903 {
1904 	int	FrameCycles, HblCounterVideo, LineCycles;
1905 
1906 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1907 	LOG_TRACE(TRACE_FDC, "fdc complete command VBL=%d video_cyc=%d %d@%d pc=%x\n",
1908 		nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1909 
1910 	FDC_Update_STR ( FDC_STR_BIT_BUSY , 0 );			/* Remove busy bit */
1911 
1912 	if ( DoInt )
1913 		FDC_SetIRQ ( FDC_IRQ_SOURCE_COMPLETE );
1914 
1915 	FDC.Command = FDCEMU_CMD_MOTOR_STOP;				/* Fake command to stop the motor */
1916 	FDC.CommandState = FDCEMU_RUN_MOTOR_STOP;
1917 	return FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
1918 }
1919 
1920 
1921 /*-----------------------------------------------------------------------*/
1922 /**
1923  * Verify track after a type I command.
1924  * The FDC will read the first ID field of the current track and will
1925  * compare the track number in this ID field with the current Track Register.
1926  * If they don't match, we try again with the next ID field until we
1927  * reach 5 revolutions, in which case we set RNF.
1928  *
1929  * NOTE [NP] : in the case of Hatari when using ST/MSA images, the track is always the correct one,
1930  * so the verify will always be good (except if no disk is inserted or the physical head is
1931  * not on the same track as FDC.TR)
1932  * For STX images, verify track might fail on purpose with some protection
1933  */
FDC_VerifyTrack(void)1934 static bool FDC_VerifyTrack ( void )
1935 {
1936 	int	FrameCycles, HblCounterVideo, LineCycles;
1937 	Uint8	Next_TR;
1938 	Uint8	Next_CRC_OK;
1939 
1940 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1941 
1942 	/* Return false if no drive selected, or drive not enabled, or no disk in drive */
1943 	if ( ( FDC.DriveSelSignal < 0 ) || ( !FDC_DRIVES[ FDC.DriveSelSignal ].Enabled )
1944 		|| ( !FDC_DRIVES[ FDC.DriveSelSignal ].DiskInserted ) )
1945 	{
1946 		LOG_TRACE(TRACE_FDC, "fdc type I verify track failed disabled/empty drive=%d VBL=%d video_cyc=%d %d@%d pc=%x\n",
1947 			FDC.DriveSelSignal , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1948 		return false;
1949 	}
1950 
1951 	/* Check if the current ID Field is the one we're looking for (same track and correct CRC) */
1952 	if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
1953 	{
1954 		Next_TR = FDC_NextSectorID_TR_STX ();
1955 		Next_CRC_OK = FDC_NextSectorID_CRC_OK_STX ();
1956 	}
1957 	else
1958 	{
1959 		Next_TR = FDC_NextSectorID_TR_ST ();
1960 		Next_CRC_OK = FDC_NextSectorID_CRC_OK_ST ();
1961 	}
1962 
1963 	/* ST/MSA image will always be correct, only STX can fail depending on some protections */
1964 	if ( ( Next_TR != FDC.TR ) || ( Next_CRC_OK == 0 ) )
1965 	{
1966 		LOG_TRACE(TRACE_FDC, "fdc type I verify track failed ID_TR=0x%x TR=0x%x crc_ok=%d head=0x%x drive=%d VBL=%d video_cyc=%d %d@%d pc=%x\n",
1967 			Next_TR , FDC.TR , Next_CRC_OK , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.DriveSelSignal ,
1968 			nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1969 
1970 		return false;
1971 	}
1972 
1973 	/* If disk image has only one side or drive is single sided and we're trying to verify on 2nd side, then return false */
1974 	if ( ( FDC.SideSignal == 1  )
1975 	  && ( ( FDC_GetSidesPerDisk ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack ) != 2 )
1976 	    || ( FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads == 1 ) ) )
1977 	{
1978 		LOG_TRACE(TRACE_FDC, "fdc type I verify track failed TR=0x%x head=0x%x side=1 doesn't exist drive=%d VBL=%d video_cyc=%d %d@%d pc=%x\n",
1979 			FDC.TR , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.DriveSelSignal ,
1980 			nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1981 
1982 		return false;
1983 	}
1984 
1985 	/* The track is the correct one */
1986 	return true;
1987 }
1988 
1989 
1990 /*-----------------------------------------------------------------------*/
1991 /**
1992  * Run the 'motor stop' sequence : wait for 9 revolutions (1.8 sec)
1993  * and stop the motor.
1994  * We clear motor bit, but spinup bit remains to 1 (verified on a real STF)
1995  */
FDC_UpdateMotorStop(void)1996 static int FDC_UpdateMotorStop ( void )
1997 {
1998 	int	FdcCycles = 0;
1999 	int	FrameCycles, HblCounterVideo, LineCycles;
2000 
2001 	/* Which command is running? */
2002 	switch (FDC.CommandState)
2003 	{
2004 	 case FDCEMU_RUN_MOTOR_STOP:
2005 		FDC.IndexPulse_Counter = 0;
2006 		FDC.CommandState = FDCEMU_RUN_MOTOR_STOP_WAIT;
2007 		/* Continue to next state */
2008 	 case FDCEMU_RUN_MOTOR_STOP_WAIT:
2009 		if ( FDC.IndexPulse_Counter < FDC_DELAY_IP_MOTOR_OFF )
2010 		{
2011 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Wait for the correct number of IP */
2012 			break;
2013 		}
2014 		/* If IndexPulse_Counter reached, we go directly to the _COMPLETE state */
2015 	 case FDCEMU_RUN_MOTOR_STOP_COMPLETE:
2016 		Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2017 		LOG_TRACE(TRACE_FDC, "fdc motor stopped VBL=%d video_cyc=%d %d@%d pc=%x\n",
2018 			nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2019 
2020 		FDC.IndexPulse_Counter = 0;
2021 		if ( FDC.DriveSelSignal >= 0 )                                  /* A drive was previously enabled */
2022 			FDC_DRIVES[ FDC.DriveSelSignal ].IndexPulse_Time = 0;   /* Stop counting index pulses on the drive */
2023 
2024 		FDC_Update_STR ( FDC_STR_BIT_MOTOR_ON , 0 );		/* Unset motor bit and keep spin up bit */
2025 		FDC.Command = FDCEMU_CMD_NULL;				/* Motor stopped, this is the last state */
2026 		FdcCycles = 0;
2027 		break;
2028 	}
2029 	return FdcCycles;
2030 }
2031 
2032 
2033 /*-----------------------------------------------------------------------*/
2034 /**
2035  * Run 'RESTORE' command
2036  */
FDC_UpdateRestoreCmd(void)2037 static int FDC_UpdateRestoreCmd ( void )
2038 {
2039 	int	FdcCycles = 0;
2040 	int	FrameCycles, HblCounterVideo, LineCycles;
2041 
2042 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2043 
2044 	/* Which command is running? */
2045 	switch (FDC.CommandState)
2046 	{
2047 	 case FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO:
2048 		if ( FDC_Set_MotorON ( FDC.CR ) )
2049 		{
2050 			FDC.CommandState = FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_SPIN_UP;
2051 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Spin up needed */
2052 		}
2053 		else
2054 		{
2055 			FDC.CommandState = FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_MOTOR_ON;
2056 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;		/* No spin up needed */
2057 		}
2058 		break;
2059 	 case FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_SPIN_UP:
2060 		if ( FDC.IndexPulse_Counter < FDC_DELAY_IP_SPIN_UP )
2061 		{
2062 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Wait for the correct number of IP */
2063 			break;
2064 		}
2065 		/* If IndexPulse_Counter reached, we go directly to the _MOTOR_ON state */
2066 	 case FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_MOTOR_ON:
2067 		FDC_Update_STR ( 0 , FDC_STR_BIT_SPIN_UP );		/* At this point, spin up sequence is ok */
2068 		FDC.ReplaceCommandPossible = false;
2069 
2070 		/* The FDC will try 255 times to reach track 0 using step out signals */
2071 		/* If track 0 signal is not detected after 255 attempts, the command is interrupted */
2072 		/* and FDC_STR_BIT_RNF is set in the Status Register. */
2073 		/* This can happen if no drive is selected or if the selected drive is disabled */
2074 		/* TR should be set to 255 once the spin-up sequence is made and the command */
2075 		/* can't be interrupted anymore by another command (else TR value will be wrong */
2076 		/* for other type I commands) */
2077 		FDC.TR = 0xff;
2078 		FDC.CommandState = FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_LOOP;
2079 		/* Continue in the _LOOP state */
2080 	 case FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_LOOP:
2081 		if ( FDC.TR == 0 )					/* Track 0 not reached after 255 attempts ? */
2082 		{							/* (this can happen if the drive is disabled) */
2083 			FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );
2084 			FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 );	/* Unset bit TR00 */
2085 			FdcCycles = FDC_CmdCompleteCommon( true );
2086 			break;
2087 		}
2088 
2089 		if ( ( FDC.DriveSelSignal < 0 ) || ( !FDC_DRIVES[ FDC.DriveSelSignal ].Enabled )
2090 			|| ( FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack != 0 ) )	/* Are we at track zero ? */
2091 		{
2092 			FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 );	/* Unset bit TR00 */
2093 			FDC.TR--;					/* One less attempt */
2094 			if ( ( FDC.DriveSelSignal >= 0 ) && ( FDC_DRIVES[ FDC.DriveSelSignal ].Enabled ) )
2095 				FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack--;	/* Move physical head only if an enabled drive is selected */
2096 			FdcCycles = FDC_DelayToFdcCycles ( FDC_StepRate_ms[ FDC_STEP_RATE ] * 1000 );
2097 		}
2098 		else							/* Drive is enabled and head is at track 0 */
2099 		{
2100 			FDC_Update_STR ( 0 , FDC_STR_BIT_TR00 );	/* Set bit TR00 */
2101 			FDC.TR = 0;					/* Update Track Register to 0 */
2102 			FDC.CommandState = FDCEMU_RUN_RESTORE_VERIFY;
2103 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2104 		}
2105 		break;
2106 	 case FDCEMU_RUN_RESTORE_VERIFY:
2107 		if ( FDC.CR & FDC_COMMAND_BIT_VERIFY )
2108 		{
2109 			FDC.CommandState = FDCEMU_RUN_RESTORE_VERIFY_HEAD_OK;
2110 			FdcCycles = FDC_DelayToFdcCycles ( FDC_DELAY_US_HEAD_LOAD );	/* Head settle delay */
2111 		}
2112 		else
2113 		{
2114 			FDC.CommandState = FDCEMU_RUN_RESTORE_COMPLETE;
2115 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
2116 		}
2117 		break;
2118 	 case FDCEMU_RUN_RESTORE_VERIFY_HEAD_OK:
2119 		FDC.IndexPulse_Counter = 0;
2120 		/* Head OK, continue and look for sector header */
2121 	 case FDCEMU_RUN_RESTORE_VERIFY_NEXT_SECTOR_HEADER:
2122 		/* If 'verify' doesn't succeed after 5 revolutions, we abort with RNF */
2123 		if ( FDC.IndexPulse_Counter >= FDC_DELAY_IP_ADDRESS_ID )
2124 		{
2125 			LOG_TRACE(TRACE_FDC, "fdc type I restore track=%d drive=%d verify RNF VBL=%d video_cyc=%d %d@%d pc=%x\n",
2126 				FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.DriveSelSignal , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2127 
2128 			FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );			/* Set RNF bit */
2129 			FDC.CommandState = FDCEMU_RUN_RESTORE_COMPLETE;
2130 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
2131 			break;
2132 		}
2133 
2134 		if ( FDC.DriveSelSignal < 0 )					/* No drive selected */
2135 			FdcCycles = -1;
2136 		else if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
2137 			FdcCycles = FDC_NextSectorID_FdcCycles_STX ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads ,
2138 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
2139 		else
2140 			FdcCycles = FDC_NextSectorID_FdcCycles_ST ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads ,
2141 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
2142 		if ( FdcCycles < 0 )
2143 		{
2144 			FDC.CommandState = FDCEMU_RUN_RESTORE_VERIFY_NEXT_SECTOR_HEADER;
2145 			FdcCycles = FDC_DELAY_CYCLE_WAIT_NO_DRIVE_FLOPPY;	/* Wait for a valid drive/floppy */
2146 		}
2147 		else
2148 		{
2149 			/* Read bytes to reach the next sector's ID field and skip 10 more bytes to read the whole ID field */
2150 			FdcCycles += FDC_TransferByte_FdcCycles ( 10 );		/* Add delay to read 3xA1, FE, ID field */
2151 			FDC.CommandState = FDCEMU_RUN_RESTORE_VERIFY_CHECK_SECTOR_HEADER;
2152 		}
2153 		break;
2154 	 case FDCEMU_RUN_RESTORE_VERIFY_CHECK_SECTOR_HEADER:
2155 		/* Check if the current ID Field matches the track number */
2156 		if ( FDC_VerifyTrack () )
2157 		{
2158 			FDC_Update_STR ( FDC_STR_BIT_RNF , 0 );			/* Track is correct, remove RNF bit */
2159 			FDC.CommandState = FDCEMU_RUN_RESTORE_COMPLETE;
2160 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
2161 		}
2162 		else
2163 		{
2164 			/* Verify failed with this ID field ; check the next one */
2165 			FDC.CommandState = FDCEMU_RUN_RESTORE_VERIFY_NEXT_SECTOR_HEADER;
2166 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2167 		}
2168 		break;
2169 	 case FDCEMU_RUN_RESTORE_COMPLETE:
2170 		FdcCycles = FDC_CmdCompleteCommon( true );
2171 		break;
2172 	}
2173 
2174 	return FdcCycles;
2175 }
2176 
2177 
2178 /*-----------------------------------------------------------------------*/
2179 /**
2180  * Run 'SEEK' command
2181  */
FDC_UpdateSeekCmd(void)2182 static int FDC_UpdateSeekCmd ( void )
2183 {
2184 	int	FdcCycles = 0;
2185 	int	FrameCycles, HblCounterVideo, LineCycles;
2186 
2187 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2188 
2189 	/* Which command is running? */
2190 	switch (FDC.CommandState)
2191 	{
2192 	 case FDCEMU_RUN_SEEK_TOTRACK:
2193 		if ( FDC_Set_MotorON ( FDC.CR ) )
2194 		{
2195 			FDC.CommandState = FDCEMU_RUN_SEEK_TOTRACK_SPIN_UP;
2196 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Spin up needed */
2197 		}
2198 		else
2199 		{
2200 			FDC.CommandState = FDCEMU_RUN_SEEK_TOTRACK_MOTOR_ON;
2201 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;		/* No spin up needed */
2202 		}
2203 		break;
2204 	 case FDCEMU_RUN_SEEK_TOTRACK_SPIN_UP:
2205 		if ( FDC.IndexPulse_Counter < FDC_DELAY_IP_SPIN_UP )
2206 		{
2207 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Wait for the correct number of IP */
2208 			break;
2209 		}
2210 		/* If IndexPulse_Counter reached, we go directly to the _MOTOR_ON state */
2211 	 case FDCEMU_RUN_SEEK_TOTRACK_MOTOR_ON:
2212 		FDC_Update_STR ( 0 , FDC_STR_BIT_SPIN_UP );		/* At this point, spin up sequence is ok */
2213 		FDC.ReplaceCommandPossible = false;
2214 
2215 		if ( FDC.TR == FDC.DR )					/* Are we at the selected track ? */
2216 		{
2217 			FDC.CommandState = FDCEMU_RUN_SEEK_VERIFY;
2218 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2219 		}
2220 		else
2221 		{
2222 			if ( FDC.DR < FDC.TR )				/* Set StepDirection to the correct value */
2223 				FDC.StepDirection = -1;
2224 			else
2225 				FDC.StepDirection = 1;
2226 
2227 			/* Move head by one track depending on FDC.StepDirection and update Track Register */
2228 			FDC.TR += FDC.StepDirection;
2229 
2230 			FdcCycles = FDC_DelayToFdcCycles ( FDC_StepRate_ms[ FDC_STEP_RATE ] * 1000 );
2231 			FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 );	/* By default, unset bit TR00 */
2232 
2233 			/* Check / move physical head only if an enabled drive is selected */
2234 			if ( ( FDC.DriveSelSignal >= 0 ) && ( FDC_DRIVES[ FDC.DriveSelSignal ].Enabled ) )
2235 			{
2236 				if ( ( FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack == FDC_PHYSICAL_MAX_TRACK ) && ( FDC.StepDirection == 1 ) )
2237 				{
2238 					FDC.CommandState = FDCEMU_RUN_SEEK_VERIFY;
2239 					FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;	/* No delay if trying to go after max track */
2240 				}
2241 
2242 				else if ( ( FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack == 0 ) && ( FDC.StepDirection == -1 ) )
2243 				{
2244 					FDC.TR = 0;			/* If we reach track 0, we stop there */
2245 					FDC.CommandState = FDCEMU_RUN_SEEK_VERIFY;
2246 					FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2247 				}
2248 
2249 				else
2250 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack += FDC.StepDirection;	/* Move physical head */
2251 
2252 				if ( FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack == 0 )
2253 					FDC_Update_STR ( 0 , FDC_STR_BIT_TR00 );	/* Set bit TR00 */
2254 			}
2255 		}
2256 
2257 		break;
2258 	 case FDCEMU_RUN_SEEK_VERIFY:
2259 		if ( FDC.CR & FDC_COMMAND_BIT_VERIFY )
2260 		{
2261 			FDC.CommandState = FDCEMU_RUN_SEEK_VERIFY_HEAD_OK;
2262 			FdcCycles = FDC_DelayToFdcCycles ( FDC_DELAY_US_HEAD_LOAD );	/* Head settle delay */
2263 		}
2264 		else
2265 		{
2266 			FDC.CommandState = FDCEMU_RUN_SEEK_COMPLETE;
2267 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
2268 		}
2269 		break;
2270 	 case FDCEMU_RUN_SEEK_VERIFY_HEAD_OK:
2271 		FDC.IndexPulse_Counter = 0;
2272 		/* Head OK, continue and look for sector header */
2273 	 case FDCEMU_RUN_SEEK_VERIFY_NEXT_SECTOR_HEADER:
2274 		/* If 'verify' doesn't succeed after 5 revolutions, we abort with RNF */
2275 		if ( FDC.IndexPulse_Counter >= FDC_DELAY_IP_ADDRESS_ID )
2276 		{
2277 			LOG_TRACE(TRACE_FDC, "fdc type I seek track=%d drive=%d verify RNF VBL=%d video_cyc=%d %d@%d pc=%x\n",
2278 				FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.DriveSelSignal , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2279 
2280 			FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );			/* Set RNF bit */
2281 			FDC.CommandState = FDCEMU_RUN_SEEK_COMPLETE;
2282 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
2283 			break;
2284 		}
2285 
2286 		if ( FDC.DriveSelSignal < 0 )					/* No drive selected */
2287 			FdcCycles = -1;
2288 		else if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
2289 			FdcCycles = FDC_NextSectorID_FdcCycles_STX ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads ,
2290 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
2291 		else
2292 			FdcCycles = FDC_NextSectorID_FdcCycles_ST ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads ,
2293 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
2294 		if ( FdcCycles < 0 )
2295 		{
2296 			FDC.CommandState = FDCEMU_RUN_SEEK_VERIFY_NEXT_SECTOR_HEADER;
2297 			FdcCycles = FDC_DELAY_CYCLE_WAIT_NO_DRIVE_FLOPPY;	/* Wait for a valid drive/floppy */
2298 		}
2299 		else
2300 		{
2301 			/* Read bytes to reach the next sector's ID field and skip 10 more bytes to read the whole ID field */
2302 			FdcCycles += FDC_TransferByte_FdcCycles ( 10 );		/* Add delay to read 3xA1, FE, ID field */
2303 			FDC.CommandState = FDCEMU_RUN_SEEK_VERIFY_CHECK_SECTOR_HEADER;
2304 		}
2305 		break;
2306 	 case FDCEMU_RUN_SEEK_VERIFY_CHECK_SECTOR_HEADER:
2307 		/* Check if the current ID Field matches the track number */
2308 		if ( FDC_VerifyTrack () )
2309 		{
2310 			FDC_Update_STR ( FDC_STR_BIT_RNF , 0 );			/* Track is correct, remove RNF bit */
2311 			FDC.CommandState = FDCEMU_RUN_SEEK_COMPLETE;
2312 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
2313 		}
2314 		else
2315 		{
2316 			/* Verify failed with this ID field ; check the next one */
2317 			FDC.CommandState = FDCEMU_RUN_SEEK_VERIFY_NEXT_SECTOR_HEADER;
2318 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2319 		}
2320 		break;
2321 	 case FDCEMU_RUN_SEEK_COMPLETE:
2322 		FdcCycles = FDC_CmdCompleteCommon( true );
2323 		break;
2324 	}
2325 
2326 	return FdcCycles;
2327 }
2328 
2329 
2330 /*-----------------------------------------------------------------------*/
2331 /**
2332  * Run 'STEP' command
2333  */
FDC_UpdateStepCmd(void)2334 static int FDC_UpdateStepCmd ( void )
2335 {
2336 	int	FdcCycles = 0;
2337 	int	FrameCycles, HblCounterVideo, LineCycles;
2338 
2339 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2340 
2341 	/* Which command is running? */
2342 	switch (FDC.CommandState)
2343 	{
2344 	 case FDCEMU_RUN_STEP_ONCE:
2345 		if ( FDC_Set_MotorON ( FDC.CR ) )
2346 		{
2347 			FDC.CommandState = FDCEMU_RUN_STEP_ONCE_SPIN_UP;
2348 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Spin up needed */
2349 		}
2350 		else
2351 		{
2352 			FDC.CommandState = FDCEMU_RUN_STEP_ONCE_MOTOR_ON;
2353 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;		/* No spin up needed */
2354 		}
2355 		break;
2356 	 case FDCEMU_RUN_STEP_ONCE_SPIN_UP:
2357 		if ( FDC.IndexPulse_Counter < FDC_DELAY_IP_SPIN_UP )
2358 		{
2359 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Wait for the correct number of IP */
2360 			break;
2361 		}
2362 		/* If IndexPulse_Counter reached, we go directly to the _MOTOR_ON state */
2363 	 case FDCEMU_RUN_STEP_ONCE_MOTOR_ON:
2364 		FDC_Update_STR ( 0 , FDC_STR_BIT_SPIN_UP );		/* At this point, spin up sequence is ok */
2365 		FDC.ReplaceCommandPossible = false;
2366 
2367 		/* Move head by one track depending on FDC.StepDirection */
2368 		if ( FDC.CR & FDC_COMMAND_BIT_UPDATE_TRACK )
2369 			FDC.TR += FDC.StepDirection;			/* Update Track Register */
2370 
2371 		FdcCycles = FDC_DelayToFdcCycles ( FDC_StepRate_ms[ FDC_STEP_RATE ] * 1000 );
2372 		FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 );		/* By default, unset bit TR00 */
2373 
2374 		/* Check / move physical head only if an enabled drive is selected */
2375 		if ( ( FDC.DriveSelSignal >= 0 ) && ( FDC_DRIVES[ FDC.DriveSelSignal ].Enabled ) )
2376 		{
2377 			if ( ( FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack == FDC_PHYSICAL_MAX_TRACK ) && ( FDC.StepDirection == 1 ) )
2378 				FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;	/* No delay if trying to go after max track */
2379 
2380 			else if ( ( FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack == 0 ) && ( FDC.StepDirection == -1 ) )
2381 				FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;	/* No delay if trying to go before track 0 */
2382 
2383 			else
2384 				FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack += FDC.StepDirection;	/* Move physical head */
2385 
2386 			if ( FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack == 0 )
2387 				FDC_Update_STR ( 0 , FDC_STR_BIT_TR00 );	/* Set bit TR00 */
2388 		}
2389 
2390 		FDC.CommandState = FDCEMU_RUN_STEP_VERIFY;
2391 		break;
2392 	 case FDCEMU_RUN_STEP_VERIFY:
2393 		if ( FDC.CR & FDC_COMMAND_BIT_VERIFY )
2394 		{
2395 			FDC.CommandState = FDCEMU_RUN_STEP_VERIFY_HEAD_OK;
2396 			FdcCycles = FDC_DelayToFdcCycles ( FDC_DELAY_US_HEAD_LOAD );	/* Head settle delay */
2397 		}
2398 		else
2399 		{
2400 			FDC.CommandState = FDCEMU_RUN_STEP_COMPLETE;
2401 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
2402 		}
2403 		break;
2404 	 case FDCEMU_RUN_STEP_VERIFY_HEAD_OK:
2405 		FDC.IndexPulse_Counter = 0;
2406 		/* Head OK, continue and look for sector header */
2407 	 case FDCEMU_RUN_STEP_VERIFY_NEXT_SECTOR_HEADER:
2408 		/* If 'verify' doesn't succeed after 5 revolutions, we abort with RNF */
2409 		if ( FDC.IndexPulse_Counter >= FDC_DELAY_IP_ADDRESS_ID )
2410 		{
2411 			LOG_TRACE(TRACE_FDC, "fdc type I step track=%d drive=%d verify RNF VBL=%d video_cyc=%d %d@%d pc=%x\n",
2412 				FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.DriveSelSignal , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2413 
2414 			FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );			/* Set RNF bit */
2415 			FDC.CommandState = FDCEMU_RUN_STEP_COMPLETE;
2416 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
2417 			break;
2418 		}
2419 
2420 		if ( FDC.DriveSelSignal < 0 )					/* No drive selected */
2421 			FdcCycles = -1;
2422 		else if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
2423 			FdcCycles = FDC_NextSectorID_FdcCycles_STX ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads ,
2424 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
2425 		else
2426 			FdcCycles = FDC_NextSectorID_FdcCycles_ST ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads ,
2427 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
2428 		if ( FdcCycles < 0 )
2429 		{
2430 			FDC.CommandState = FDCEMU_RUN_STEP_VERIFY_NEXT_SECTOR_HEADER;
2431 			FdcCycles = FDC_DELAY_CYCLE_WAIT_NO_DRIVE_FLOPPY;	/* Wait for a valid drive/floppy */
2432 		}
2433 		else
2434 		{
2435 			/* Read bytes to reach the next sector's ID field and skip 10 more bytes to read the whole ID field */
2436 			FdcCycles += FDC_TransferByte_FdcCycles ( 10 );		/* Add delay to read 3xA1, FE, ID field */
2437 			FDC.CommandState = FDCEMU_RUN_STEP_VERIFY_CHECK_SECTOR_HEADER;
2438 		}
2439 		break;
2440 	 case FDCEMU_RUN_STEP_VERIFY_CHECK_SECTOR_HEADER:
2441 		/* Check if the current ID Field matches the track number */
2442 		if ( FDC_VerifyTrack () )
2443 		{
2444 			FDC_Update_STR ( FDC_STR_BIT_RNF , 0 );			/* Track is correct, remove RNF bit */
2445 			FDC.CommandState = FDCEMU_RUN_STEP_COMPLETE;
2446 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
2447 		}
2448 		else
2449 		{
2450 			/* Verify failed with this ID field ; check the next one */
2451 			FDC.CommandState = FDCEMU_RUN_STEP_VERIFY_NEXT_SECTOR_HEADER;
2452 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2453 		}
2454 		break;
2455 	 case FDCEMU_RUN_STEP_COMPLETE:
2456 		FdcCycles = FDC_CmdCompleteCommon( true );
2457 		break;
2458 	}
2459 
2460 	return FdcCycles;
2461 }
2462 
2463 
2464 /*-----------------------------------------------------------------------*/
2465 /**
2466  * Run 'READ SECTOR/S' command
2467  */
FDC_UpdateReadSectorsCmd(void)2468 static int FDC_UpdateReadSectorsCmd ( void )
2469 {
2470 	int	FdcCycles = 0;
2471 	int	SectorSize;
2472 	int	FrameCycles, HblCounterVideo, LineCycles;
2473 	Uint8	Next_TR;
2474 	Uint8	Next_SR;
2475 	Uint8	Next_CRC_OK;
2476 
2477 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2478 
2479 
2480 	/* Which command is running? */
2481 	switch (FDC.CommandState)
2482 	{
2483 	 case FDCEMU_RUN_READSECTORS_READDATA:
2484 		if ( FDC_Set_MotorON ( FDC.CR ) )
2485 		{
2486 			FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_SPIN_UP;
2487 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Spin up needed */
2488 		}
2489 		else
2490 		{
2491 			FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_HEAD_LOAD;
2492 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;		/* No spin up needed */
2493 		}
2494 		break;
2495 	 case FDCEMU_RUN_READSECTORS_READDATA_SPIN_UP:
2496 		if ( FDC.IndexPulse_Counter < FDC_DELAY_IP_SPIN_UP )
2497 		{
2498 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Wait for the correct number of IP */
2499 			break;
2500 		}
2501 		/* If IndexPulse_Counter reached, we go directly to the _HEAD_LOAD state */
2502 	 case FDCEMU_RUN_READSECTORS_READDATA_HEAD_LOAD:
2503 		if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
2504 		{
2505 			FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_MOTOR_ON;
2506 			FdcCycles = FDC_DelayToFdcCycles ( FDC_DELAY_US_HEAD_LOAD );	/* Head settle delay */
2507 			break;
2508 		}
2509 		/* If there's no head settle, we go directly to the _MOTOR_ON state */
2510 	 case FDCEMU_RUN_READSECTORS_READDATA_MOTOR_ON:
2511 		FDC.ReplaceCommandPossible = false;
2512 		FDC.IndexPulse_Counter = 0;
2513 		FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_NEXT_SECTOR_HEADER;
2514 		FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2515 		break;
2516 	 case FDCEMU_RUN_READSECTORS_READDATA_NEXT_SECTOR_HEADER:
2517 		/* If we're looking for sector FDC.SR for more than 5 revolutions, we abort with RNF */
2518 		if ( FDC.IndexPulse_Counter >= FDC_DELAY_IP_ADDRESS_ID )
2519 		{
2520 			FDC.CommandState = FDCEMU_RUN_READSECTORS_RNF;
2521 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2522 			break;
2523 		}
2524 
2525 		if ( FDC.DriveSelSignal < 0 )					/* No drive selected */
2526 			FdcCycles = -1;
2527 		else if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
2528 			FdcCycles = FDC_NextSectorID_FdcCycles_STX ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads ,
2529 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
2530 		else
2531 			FdcCycles = FDC_NextSectorID_FdcCycles_ST ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads ,
2532 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
2533 		if ( FdcCycles < 0 )
2534 		{
2535 			FdcCycles = FDC_DELAY_CYCLE_WAIT_NO_DRIVE_FLOPPY;	/* Wait for a valid drive/floppy */
2536 		}
2537 		else
2538 		{
2539 			/* Read bytes to reach the next sector's ID field and skip 10 more bytes to read the whole ID field */
2540 			FdcCycles += FDC_TransferByte_FdcCycles ( 10 );		/* Add delay to read 3xA1, FE, TR, SIDE, SR, LEN, CRC1, CRC2 */
2541 			FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_CHECK_SECTOR_HEADER;
2542 		}
2543 		break;
2544 	 case FDCEMU_RUN_READSECTORS_READDATA_CHECK_SECTOR_HEADER:
2545 		/* Check if the current ID Field is the one we're looking for (same track/sector and correct CRC) */
2546 		if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
2547 		{
2548 			Next_TR = FDC_NextSectorID_TR_STX ();
2549 			Next_SR = FDC_NextSectorID_SR_STX ();
2550 			Next_CRC_OK = FDC_NextSectorID_CRC_OK_STX ();
2551 		}
2552 		else
2553 		{
2554 			Next_TR = FDC_NextSectorID_TR_ST ();
2555 			Next_SR = FDC_NextSectorID_SR_ST ();
2556 			Next_CRC_OK = FDC_NextSectorID_CRC_OK_ST ();
2557 		}
2558 		if ( ( Next_TR == FDC.TR ) && ( Next_SR == FDC.SR ) && ( Next_CRC_OK ) )
2559 		{
2560 			FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_TRANSFER_START;
2561 			/* Read bytes to reach the sector's data : GAP3a + GAP3b + 3xA1 + FB */
2562 			FdcCycles = FDC_TransferByte_FdcCycles ( FDC_TRACK_LAYOUT_STANDARD_GAP3a + FDC_TRACK_LAYOUT_STANDARD_GAP3b + 3 + 1 );
2563 		}
2564 		else
2565 		{
2566 			/* This is not the ID field we're looking for ; check the next one */
2567 			FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_NEXT_SECTOR_HEADER;
2568 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2569 		}
2570 		break;
2571 	 case FDCEMU_RUN_READSECTORS_READDATA_TRANSFER_START:
2572 		/* Read a single sector into temporary buffer (512 bytes for ST/MSA) */
2573 		FDC_Buffer_Reset();
2574 
2575 		if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
2576 			FDC.Status_Temp = FDC_ReadSector_STX ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack ,
2577 				FDC.SR , FDC.SideSignal , &SectorSize );
2578 		else
2579 			FDC.Status_Temp = FDC_ReadSector_ST ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack ,
2580 				FDC.SR , FDC.SideSignal , &SectorSize );
2581 
2582 		if ( FDC.Status_Temp & FDC_STR_BIT_RNF )		/* Sector FDC.SR was not found */
2583 		{
2584 			FDC.CommandState = FDCEMU_RUN_READSECTORS_RNF;
2585 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2586 		}
2587 		else
2588 		{
2589 			if ( FDC.Status_Temp & FDC_STR_BIT_RECORD_TYPE )
2590 				FDC_Update_STR ( 0 , FDC_STR_BIT_RECORD_TYPE );
2591 			else
2592 				FDC_Update_STR ( FDC_STR_BIT_RECORD_TYPE , 0 );
2593 
2594 			FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_TRANSFER_LOOP;
2595 			FdcCycles = FDC_Buffer_Read_Timing ();		/* Delay to transfer the first byte */
2596 		}
2597 		break;
2598 	 case FDCEMU_RUN_READSECTORS_READDATA_TRANSFER_LOOP:
2599 		/* Transfer the sector 1 byte at a time using DMA */
2600 		FDC_DMA_FIFO_Push ( FDC_Buffer_Read_Byte () );		/* Add 1 byte to the DMA FIFO */
2601 		if ( FDC_BUFFER.PosRead < FDC_Buffer_Get_Size () )
2602 		{
2603 			FdcCycles = FDC_Buffer_Read_Timing ();		/* Delay to transfer the next byte */
2604 		}
2605 		else							/* Sector transferred, check the CRC */
2606 		{
2607 			FDC.CommandState = FDCEMU_RUN_READSECTORS_CRC;
2608 			FdcCycles = FDC_TransferByte_FdcCycles ( 2 );	/* Read 2 bytes for CRC */
2609 		}
2610 		break;
2611 	 case FDCEMU_RUN_READSECTORS_CRC:
2612 		/* Sector completely transferred, CRC is always good for ST/MSA, but not always for STX */
2613 		if ( FDC.Status_Temp & FDC_STR_BIT_CRC_ERROR )
2614 		{
2615 			LOG_TRACE(TRACE_FDC, "fdc type II read sector=%d track=0x%x side=%d drive=%d CRC VBL=%d video_cyc=%d %d@%d pc=%x\n",
2616 				  FDC.SR , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal , FDC.DriveSelSignal , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2617 
2618 			FDC_Update_STR ( 0 , FDC_STR_BIT_CRC_ERROR );
2619 			FdcCycles = FDC_CmdCompleteCommon( true );
2620 		}
2621 		else
2622 		{
2623 			FDC.CommandState = FDCEMU_RUN_READSECTORS_MULTI;
2624 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2625 		}
2626 		break;
2627 	 case FDCEMU_RUN_READSECTORS_MULTI:
2628 		/* Check for multi bit */
2629 		if ( FDC.CR & FDC_COMMAND_BIT_MULTIPLE_SECTOR  )
2630 		{
2631 			FDC.SR++;					/* Try to read next sector and set RNF if not possible */
2632 			FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_MOTOR_ON;
2633 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2634 			LOG_TRACE(TRACE_FDC, "fdc type II read sector with multi sector=0x%x track=0x%x side=%d drive=%d addr=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
2635 				FDC.SR, FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal , FDC.DriveSelSignal ,
2636 				FDC_GetDMAAddress(), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2637 		}
2638 		else							/* Multi=0, stop here with no error */
2639 		{
2640 			FDC.CommandState = FDCEMU_RUN_READSECTORS_COMPLETE;
2641 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
2642 		}
2643 		break;
2644 	 case FDCEMU_RUN_READSECTORS_RNF:
2645 		LOG_TRACE(TRACE_FDC, "fdc type II read sector=%d track=0x%x side=%d drive=%d RNF VBL=%d video_cyc=%d %d@%d pc=%x\n",
2646 			  FDC.SR , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal , FDC.DriveSelSignal , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2647 
2648 		FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );
2649 		FdcCycles = FDC_CmdCompleteCommon( true );
2650 		break;
2651 	 case FDCEMU_RUN_READSECTORS_COMPLETE:
2652 		FdcCycles = FDC_CmdCompleteCommon( true );
2653 		break;
2654 	}
2655 
2656 	return FdcCycles;
2657 }
2658 
2659 
2660 /*-----------------------------------------------------------------------*/
2661 /**
2662  * Run 'WRITE SECTOR/S' command
2663  */
FDC_UpdateWriteSectorsCmd(void)2664 static int FDC_UpdateWriteSectorsCmd ( void )
2665 {
2666 	int	FdcCycles = 0;
2667 	int	FrameCycles, HblCounterVideo, LineCycles;
2668 	Uint8	Next_TR;
2669 	Uint8	Next_SR;
2670 	Uint8	Next_LEN;
2671 	Uint8	Next_CRC_OK;
2672 	Uint8	Byte;
2673 	Uint8	Status;
2674 
2675 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2676 
2677 	/* Stop now if disk is write protected */
2678 	if ( ( FDC.DriveSelSignal >= 0 ) && ( FDC_DRIVES[ FDC.DriveSelSignal ].Enabled )
2679 		&& ( FDC_DRIVES[ FDC.DriveSelSignal ].DiskInserted )
2680 		&& ( Floppy_IsWriteProtected ( FDC.DriveSelSignal ) ) )
2681 	{
2682 		LOG_TRACE(TRACE_FDC, "fdc type II write sector=%d track=0x%x side=%d drive=%d WPRT VBL=%d video_cyc=%d %d@%d pc=%x\n",
2683 			  FDC.SR , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal , FDC.DriveSelSignal , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2684 
2685 		FDC_Update_STR ( 0 , FDC_STR_BIT_WPRT );		/* Set WPRT bit */
2686 		FdcCycles = FDC_CmdCompleteCommon( true );
2687 	}
2688 	else
2689 		FDC_Update_STR ( FDC_STR_BIT_WPRT , 0 );		/* Unset WPRT bit */
2690 
2691 
2692 	/* Which command is running? */
2693 	switch (FDC.CommandState)
2694 	{
2695 	 case FDCEMU_RUN_WRITESECTORS_WRITEDATA:
2696 		if ( FDC_Set_MotorON ( FDC.CR ) )
2697 		{
2698 			FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_SPIN_UP;
2699 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Spin up needed */
2700 		}
2701 		else
2702 		{
2703 			FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_HEAD_LOAD;
2704 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;		/* No spin up needed */
2705 		}
2706 		break;
2707 	 case FDCEMU_RUN_WRITESECTORS_WRITEDATA_SPIN_UP:
2708 		if ( FDC.IndexPulse_Counter < FDC_DELAY_IP_SPIN_UP )
2709 		{
2710 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Wait for the correct number of IP */
2711 			break;
2712 		}
2713 		/* If IndexPulse_Counter reached, we go directly to the _HEAD_LOAD state */
2714 	 case FDCEMU_RUN_WRITESECTORS_WRITEDATA_HEAD_LOAD:
2715 		if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
2716 		{
2717 			FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_MOTOR_ON;
2718 			FdcCycles = FDC_DelayToFdcCycles ( FDC_DELAY_US_HEAD_LOAD );	/* Head settle delay */
2719 			break;
2720 		}
2721 		/* If there's no head settle, we go directly to the _MOTOR_ON state */
2722 	 case FDCEMU_RUN_WRITESECTORS_WRITEDATA_MOTOR_ON:
2723 		FDC.ReplaceCommandPossible = false;
2724 		FDC.IndexPulse_Counter = 0;
2725 		FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_NEXT_SECTOR_HEADER;
2726 		FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2727 		break;
2728 	 case FDCEMU_RUN_WRITESECTORS_WRITEDATA_NEXT_SECTOR_HEADER:
2729 		/* If we're looking for sector FDC.SR for more than 5 revolutions, we abort with RNF */
2730 		if ( FDC.IndexPulse_Counter >= FDC_DELAY_IP_ADDRESS_ID )
2731 		{
2732 			FDC.CommandState = FDCEMU_RUN_WRITESECTORS_RNF;
2733 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2734 			break;
2735 		}
2736 
2737 		if ( FDC.DriveSelSignal < 0 )					/* No drive selected */
2738 			FdcCycles = -1;
2739 		else if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
2740 			FdcCycles = FDC_NextSectorID_FdcCycles_STX ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads ,
2741 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
2742 		else
2743 			FdcCycles = FDC_NextSectorID_FdcCycles_ST ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads ,
2744 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
2745 		if ( FdcCycles < 0 )
2746 		{
2747 			FdcCycles = FDC_DELAY_CYCLE_WAIT_NO_DRIVE_FLOPPY;	/* Wait for a valid drive/floppy */
2748 		}
2749 		else
2750 		{
2751 			/* Read bytes to reach the next sector's ID field and skip 10 more bytes to read the whole ID field */
2752 			FdcCycles += FDC_TransferByte_FdcCycles ( 10 );		/* Add delay to read 3xA1, FE, TR, SIDE, SR, LEN, CRC1, CRC2 */
2753 			FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_CHECK_SECTOR_HEADER;
2754 		}
2755 		break;
2756 	 case FDCEMU_RUN_WRITESECTORS_WRITEDATA_CHECK_SECTOR_HEADER:
2757 		/* Check if the current ID Field is the one we're looking for (same track/sector and correct CRC) */
2758 		if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
2759 		{
2760 			Next_TR = FDC_NextSectorID_TR_STX ();
2761 			Next_SR = FDC_NextSectorID_SR_STX ();
2762 			Next_CRC_OK = FDC_NextSectorID_CRC_OK_STX ();
2763 		}
2764 		else
2765 		{
2766 			Next_TR = FDC_NextSectorID_TR_ST ();
2767 			Next_SR = FDC_NextSectorID_SR_ST ();
2768 			Next_CRC_OK = FDC_NextSectorID_CRC_OK_ST ();
2769 		}
2770 		if ( ( Next_TR == FDC.TR ) && ( Next_SR == FDC.SR ) && ( Next_CRC_OK ) )
2771 		{
2772 			FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_TRANSFER_START;
2773 			/* Read bytes to reach the sector's data : GAP3a + GAP3b + 3xA1 + FB */
2774 			FdcCycles = FDC_TransferByte_FdcCycles ( FDC_TRACK_LAYOUT_STANDARD_GAP3a + FDC_TRACK_LAYOUT_STANDARD_GAP3b + 3 + 1 );
2775 		}
2776 		else
2777 		{
2778 			/* This is not the ID field we're looking for ; check the next one */
2779 			FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_NEXT_SECTOR_HEADER;
2780 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2781 		}
2782 		break;
2783 	 case FDCEMU_RUN_WRITESECTORS_WRITEDATA_TRANSFER_START:
2784 		/* Write a single sector from RAM (512 bytes for ST/MSA) */
2785 		if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
2786 			Next_LEN = FDC_NextSectorID_LEN_STX ();
2787 		else
2788 			Next_LEN = FDC_NextSectorID_LEN_ST ();
2789 
2790 		FDC_Buffer_Reset();
2791 		FDC_DMA.BytesToTransfer = 128 << ( Next_LEN & FDC_SECTOR_SIZE_MASK );
2792 
2793 		FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_TRANSFER_LOOP;
2794 		FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2795 		break;
2796 	 case FDCEMU_RUN_WRITESECTORS_WRITEDATA_TRANSFER_LOOP:
2797 		/* Transfer the sector 1 byte at a time using DMA */
2798 		if ( FDC_DMA.BytesToTransfer-- > 0 )
2799 		{
2800 			Byte = FDC_DMA_FIFO_Pull ();			/* Get 1 byte from the DMA FIFO */
2801 //fprintf ( stderr , "byte %d %x\n" , FDC_DMA.BytesToTransfer , Byte );
2802 			FDC_Buffer_Add ( Byte );
2803 			FdcCycles = FDC_TransferByte_FdcCycles ( 1 );
2804 		}
2805 		else							/* Sector transferred, add the CRC */
2806 		{
2807 			FDC.CommandState = FDCEMU_RUN_WRITESECTORS_CRC;
2808 			FdcCycles = FDC_TransferByte_FdcCycles ( 2 );	/* Write 2 bytes for CRC */
2809 		}
2810 		break;
2811 	 case FDCEMU_RUN_WRITESECTORS_CRC:
2812 		/* Sector completely transferred, CRC is always good for ST/MSA */
2813 		/* This is where we save the buffer to the disk image */
2814 
2815 		if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
2816 			Status = FDC_WriteSector_STX ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack ,
2817 				FDC.SR , FDC.SideSignal , FDC_Buffer_Get_Size () );
2818 		else
2819 			Status = FDC_WriteSector_ST ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack ,
2820 				FDC.SR , FDC.SideSignal , FDC_Buffer_Get_Size () );
2821 
2822 		if ( Status & FDC_STR_BIT_RNF )				/* Sector FDC.SR was not correctly written */
2823 		{
2824 			FDC.CommandState = FDCEMU_RUN_WRITESECTORS_RNF;
2825 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2826 		}
2827 		else
2828 		{
2829 			FDC.CommandState = FDCEMU_RUN_WRITESECTORS_MULTI;
2830 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2831 		}
2832 		break;
2833 	 case FDCEMU_RUN_WRITESECTORS_MULTI:
2834 		/* Check for multi bit */
2835 		if ( FDC.CR & FDC_COMMAND_BIT_MULTIPLE_SECTOR  )
2836 		{
2837 			FDC.SR++;					/* Try to write next sector and set RNF if not possible */
2838 			FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_MOTOR_ON;
2839 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2840 			LOG_TRACE(TRACE_FDC, "fdc type II write sector with multi sector=0x%x track=0x%x side=%d drive=%d addr=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
2841 				FDC.SR, FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal , FDC.DriveSelSignal ,
2842 				FDC_GetDMAAddress(), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2843 		}
2844 		else							/* Multi=0, stop here with no error */
2845 		{
2846 			FDC.CommandState = FDCEMU_RUN_WRITESECTORS_COMPLETE;
2847 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
2848 		}
2849 		break;
2850 	 case FDCEMU_RUN_WRITESECTORS_RNF:
2851 		LOG_TRACE(TRACE_FDC, "fdc type II write sector=%d track=0x%x side=%d drive=%d RNF VBL=%d video_cyc=%d %d@%d pc=%x\n",
2852 			  FDC.SR , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal , FDC.DriveSelSignal , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2853 
2854 		FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );
2855 		FdcCycles = FDC_CmdCompleteCommon( true );
2856 		break;
2857 	 case FDCEMU_RUN_WRITESECTORS_COMPLETE:
2858 		FdcCycles = FDC_CmdCompleteCommon( true );
2859 		break;
2860 	}
2861 
2862 	return FdcCycles;
2863 }
2864 
2865 
2866 /*-----------------------------------------------------------------------*/
2867 /**
2868  * Run 'READ ADDRESS' command
2869  */
FDC_UpdateReadAddressCmd(void)2870 static int FDC_UpdateReadAddressCmd ( void )
2871 {
2872 	int	FdcCycles = 0;
2873 	int	FrameCycles, HblCounterVideo, LineCycles;
2874 
2875 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2876 
2877 	/* Which command is running? */
2878 	switch (FDC.CommandState)
2879 	{
2880 	 case FDCEMU_RUN_READADDRESS:
2881 		if ( FDC_Set_MotorON ( FDC.CR ) )
2882 		{
2883 			FDC.CommandState = FDCEMU_RUN_READADDRESS_SPIN_UP;
2884 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Spin up needed */
2885 		}
2886 		else
2887 		{
2888 			FDC.CommandState = FDCEMU_RUN_READADDRESS_HEAD_LOAD;
2889 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;		/* No spin up needed */
2890 		}
2891 		break;
2892 	 case FDCEMU_RUN_READADDRESS_SPIN_UP:
2893 		if ( FDC.IndexPulse_Counter < FDC_DELAY_IP_SPIN_UP )
2894 		{
2895 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Wait for the correct number of IP */
2896 			break;
2897 		}
2898 		/* If IndexPulse_Counter reached, we go directly to the _HEAD_LOAD state */
2899 	 case FDCEMU_RUN_READADDRESS_HEAD_LOAD:
2900 		FDC.ReplaceCommandPossible = false;
2901 		if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
2902 		{
2903 			FDC.CommandState = FDCEMU_RUN_READADDRESS_MOTOR_ON;
2904 			FdcCycles = FDC_DelayToFdcCycles ( FDC_DELAY_US_HEAD_LOAD );	/* Head settle delay */
2905 			break;
2906 		}
2907 		/* If there's no head settle, we go directly to the _MOTOR_ON state */
2908 	 case FDCEMU_RUN_READADDRESS_MOTOR_ON:
2909 		FDC.ReplaceCommandPossible = false;
2910 		FDC.IndexPulse_Counter = 0;
2911 		FDC.CommandState = FDCEMU_RUN_READADDRESS_NEXT_SECTOR_HEADER;
2912 		FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2913 		break;
2914 	 case FDCEMU_RUN_READADDRESS_NEXT_SECTOR_HEADER:
2915 		/* If we don't find a sector header after more than 5 revolutions, we abort with RNF */
2916 		if ( FDC.IndexPulse_Counter >= FDC_DELAY_IP_ADDRESS_ID )
2917 		{
2918 			FDC.CommandState = FDCEMU_RUN_READADDRESS_RNF;
2919 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
2920 			break;
2921 		}
2922 
2923 		if ( FDC.DriveSelSignal < 0 )					/* No drive selected */
2924 			FdcCycles = -1;
2925 		else if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
2926 			FdcCycles = FDC_NextSectorID_FdcCycles_STX ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads ,
2927 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
2928 		else
2929 			FdcCycles = FDC_NextSectorID_FdcCycles_ST ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads ,
2930 					FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
2931 		if ( FdcCycles < 0 )
2932 		{
2933 			FdcCycles = FDC_DELAY_CYCLE_WAIT_NO_DRIVE_FLOPPY;	/* Wait for a valid drive/floppy */
2934 		}
2935 		else
2936 		{
2937 			/* Read bytes to reach the next sector's ID field */
2938 			FdcCycles += FDC_TransferByte_FdcCycles ( 4 );		/* Add delay to read 3xA1, FE */
2939 			FDC.CommandState = FDCEMU_RUN_READADDRESS_TRANSFER_START;
2940 		}
2941 		break;
2942 	 case FDCEMU_RUN_READADDRESS_TRANSFER_START:
2943 		/* Read the ID field into buffer */
2944 		FDC_Buffer_Reset();
2945 
2946 		if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
2947 			FDC.Status_Temp = FDC_ReadAddress_STX ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack ,
2948 				     FDC_NextSectorID_SR_STX () , FDC.SideSignal );
2949 		else
2950 			FDC.Status_Temp = FDC_ReadAddress_ST ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack ,
2951 				     FDC_NextSectorID_SR_ST () , FDC.SideSignal );
2952 
2953 		FDC.SR = FDC_Buffer_Read_Byte_pos ( 0 );		/* The 1st byte of the ID field is also copied into Sector Register */
2954 
2955 		FDC.CommandState = FDCEMU_RUN_READADDRESS_TRANSFER_LOOP;
2956 		FdcCycles = FDC_Buffer_Read_Timing ();			/* Delay to transfer the first byte */
2957 		break;
2958 	 case FDCEMU_RUN_READADDRESS_TRANSFER_LOOP:
2959 		/* Transfer the ID field 1 byte at a time using DMA */
2960 		FDC_DMA_FIFO_Push ( FDC_Buffer_Read_Byte () );		/* Add 1 byte to the DMA FIFO */
2961 		if ( FDC_BUFFER.PosRead < FDC_Buffer_Get_Size () )
2962 		{
2963 			FdcCycles = FDC_Buffer_Read_Timing ();		/* Delay to transfer the next byte */
2964 		}
2965 		else
2966 		{
2967 			FDC.CommandState = FDCEMU_RUN_READADDRESS_COMPLETE;
2968 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
2969 		}
2970 		break;
2971 	 case FDCEMU_RUN_READADDRESS_RNF:
2972 		LOG_TRACE(TRACE_FDC, "fdc type III read address track=0x%x side=%d drive=%d RNF VBL=%d video_cyc=%d %d@%d pc=%x\n",
2973 			  FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal , FDC.DriveSelSignal , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2974 
2975 		FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );
2976 		FdcCycles = FDC_CmdCompleteCommon( true );
2977 		break;
2978 	 case FDCEMU_RUN_READADDRESS_COMPLETE:
2979 		FdcCycles = FDC_CmdCompleteCommon( true );
2980 		break;
2981 	}
2982 
2983 	return FdcCycles;
2984 }
2985 
2986 
2987 /*-----------------------------------------------------------------------*/
2988 /**
2989  * Run 'READ TRACK' command
2990  */
FDC_UpdateReadTrackCmd(void)2991 static int FDC_UpdateReadTrackCmd ( void )
2992 {
2993 	int	FdcCycles = 0;
2994 	int	i;
2995 	int	FrameCycles, HblCounterVideo, LineCycles;
2996 
2997 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2998 
2999 	/* Which command is running? */
3000 	switch (FDC.CommandState)
3001 	{
3002 	 case FDCEMU_RUN_READTRACK:
3003 		if ( FDC_Set_MotorON ( FDC.CR ) )
3004 		{
3005 			FDC.CommandState = FDCEMU_RUN_READTRACK_SPIN_UP;
3006 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Spin up needed */
3007 		}
3008 		else
3009 		{
3010 			FDC.CommandState = FDCEMU_RUN_READTRACK_HEAD_LOAD;
3011 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;		/* No spin up needed */
3012 		}
3013 		break;
3014 	 case FDCEMU_RUN_READTRACK_SPIN_UP:
3015 		if ( FDC.IndexPulse_Counter < FDC_DELAY_IP_SPIN_UP )
3016 		{
3017 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Wait for the correct number of IP */
3018 			break;
3019 		}
3020 		/* If IndexPulse_Counter reached, we go directly to the _HEAD_LOAD state */
3021 	 case FDCEMU_RUN_READTRACK_HEAD_LOAD:
3022 		FDC.ReplaceCommandPossible = false;
3023 		if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
3024 		{
3025 			FDC.CommandState = FDCEMU_RUN_READTRACK_MOTOR_ON;
3026 			FdcCycles = FDC_DelayToFdcCycles ( FDC_DELAY_US_HEAD_LOAD );	/* Head settle delay */
3027 			break;
3028 		}
3029 		/* If there's no head settle, we go directly to the _MOTOR_ON state */
3030 	 case FDCEMU_RUN_READTRACK_MOTOR_ON:
3031 		FdcCycles = FDC_NextIndexPulse_FdcCycles ();		/* Wait for the next index pulse */
3032 //fprintf ( stderr , "read tr idx=%d %d\n" , FDC_IndexPulse_GetState() , FdcCycles );
3033 		if ( FdcCycles < 0 )
3034 		{
3035 			FdcCycles = FDC_DELAY_CYCLE_WAIT_NO_DRIVE_FLOPPY;	/* Wait for a valid drive/floppy */
3036 		}
3037 		else
3038 		{
3039 			FDC.CommandState = FDCEMU_RUN_READTRACK_INDEX;
3040 		}
3041 		break;
3042 	 case FDCEMU_RUN_READTRACK_INDEX:
3043 		/* At this point, we have a valid drive/floppy, build the track data */
3044 		FDC_Buffer_Reset();
3045 
3046 		if ( ( FDC.SideSignal == 1 )				/* Try to read side 1 on a disk that doesn't have 2 sides or drive is single sided */
3047 			&& ( ( FDC_GetSidesPerDisk ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack ) != 2 )
3048 			  || ( FDC_DRIVES[ FDC.DriveSelSignal ].NumberOfHeads == 1 ) ) )
3049 		{
3050 			LOG_TRACE(TRACE_FDC, "fdc type III read track drive=%d track=%d side=%d, side not found VBL=%d video_cyc=%d %d@%d pc=%x\n",
3051 				  FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal ,
3052 				  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3053 
3054 			for ( i=0 ; i<FDC_GetBytesPerTrack ( FDC.DriveSelSignal ) ; i++ )
3055 				FDC_Buffer_Add ( rand() & 0xff );	/* Fill the track buffer with random bytes */
3056 		}
3057 		else if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
3058 		{
3059 			FDC.Status_Temp = FDC_ReadTrack_STX ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
3060 		}
3061 		else							/* Track/side available in the disk image */
3062 		{
3063 			FDC.Status_Temp = FDC_ReadTrack_ST ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal );
3064 		}
3065 
3066 		FDC.CommandState = FDCEMU_RUN_READTRACK_TRANSFER_LOOP;
3067 		FdcCycles = FDC_Buffer_Read_Timing ();			/* Delay to transfer the first byte */
3068 		break;
3069 	 case FDCEMU_RUN_READTRACK_TRANSFER_LOOP:
3070 		/* Transfer the track 1 byte at a time using DMA */
3071 		FDC_DMA_FIFO_Push ( FDC_Buffer_Read_Byte () );		/* Add 1 byte to the DMA FIFO */
3072 		if ( FDC_BUFFER.PosRead < FDC_Buffer_Get_Size () )
3073 		{
3074 			FdcCycles = FDC_Buffer_Read_Timing ();		/* Delay to transfer the next byte */
3075 		}
3076 		else							/* Track completely transferred */
3077 		{
3078 			FDC.CommandState = FDCEMU_RUN_READTRACK_COMPLETE;
3079 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_COMPLETE;
3080 		}
3081 		break;
3082 	 case FDCEMU_RUN_READTRACK_COMPLETE:
3083 		FdcCycles = FDC_CmdCompleteCommon( true );
3084 		break;
3085 	}
3086 
3087 	return FdcCycles;
3088 }
3089 
3090 
3091 /*-----------------------------------------------------------------------*/
3092 /**
3093  * Run 'WRITE TRACK' command
3094  */
FDC_UpdateWriteTrackCmd(void)3095 static int FDC_UpdateWriteTrackCmd ( void )
3096 {
3097 	int	FdcCycles = 0;
3098 	int	FrameCycles, HblCounterVideo, LineCycles;
3099 	Uint8	Byte;
3100 	Uint8	Status;
3101 
3102 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3103 
3104 	/* Which command is running? */
3105 	switch (FDC.CommandState)
3106 	{
3107 	 case FDCEMU_RUN_WRITETRACK:
3108 		if ( FDC_Set_MotorON ( FDC.CR ) )
3109 		{
3110 			FDC.CommandState = FDCEMU_RUN_WRITETRACK_SPIN_UP;
3111 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Spin up needed */
3112 		}
3113 		else
3114 		{
3115 			FDC.CommandState = FDCEMU_RUN_WRITETRACK_HEAD_LOAD;
3116 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;		/* No spin up needed */
3117 		}
3118 		break;
3119 	 case FDCEMU_RUN_WRITETRACK_SPIN_UP:
3120 		if ( FDC.IndexPulse_Counter < FDC_DELAY_IP_SPIN_UP )
3121 		{
3122 			FdcCycles = FDC_DELAY_CYCLE_REFRESH_INDEX_PULSE;	/* Wait for the correct number of IP */
3123 			break;
3124 		}
3125 		/* If IndexPulse_Counter reached, we go directly to the _HEAD_LOAD state */
3126 	 case FDCEMU_RUN_WRITETRACK_HEAD_LOAD:
3127 		FDC.ReplaceCommandPossible = false;
3128 		if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
3129 		{
3130 			FDC.CommandState = FDCEMU_RUN_WRITETRACK_MOTOR_ON;
3131 			FdcCycles = FDC_DelayToFdcCycles ( FDC_DELAY_US_HEAD_LOAD );	/* Head settle delay */
3132 			break;
3133 		}
3134 		/* If there's no head settle, we go directly to the _MOTOR_ON state */
3135 	 case FDCEMU_RUN_WRITETRACK_MOTOR_ON:
3136 		FdcCycles = FDC_NextIndexPulse_FdcCycles ();		/* Wait for the next index pulse */
3137 //fprintf ( stderr , "write tr idx=%d %d\n" , FDC_IndexPulse_GetState() , FdcCycles );
3138 		if ( FdcCycles < 0 )
3139 		{
3140 			FdcCycles = FDC_DELAY_CYCLE_WAIT_NO_DRIVE_FLOPPY;	/* Wait for a valid drive/floppy */
3141 		}
3142 		else
3143 		{
3144 			FDC.CommandState = FDCEMU_RUN_WRITETRACK_INDEX;
3145 		}
3146 		break;
3147 	 case FDCEMU_RUN_WRITETRACK_INDEX:
3148 		/* At this point, we have a valid drive/floppy, check write protection and write the track data */
3149 		if ( Floppy_IsWriteProtected ( FDC.DriveSelSignal ) )
3150 		{
3151 			LOG_TRACE(TRACE_FDC, "fdc type III write track drive=%d track=0x%x side=%d WPRT VBL=%d video_cyc=%d %d@%d pc=%x\n",
3152 				  FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack , FDC.SideSignal , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3153 
3154 			FDC_Update_STR ( 0 , FDC_STR_BIT_WPRT );	/* Set WPRT bit */
3155 			FdcCycles = FDC_CmdCompleteCommon( true );
3156 			break;
3157 		}
3158 
3159 		FDC_Update_STR ( FDC_STR_BIT_WPRT , 0 );		/* Unset WPRT bit */
3160 
3161 		FDC_Buffer_Reset();
3162 		FDC_DMA.BytesToTransfer = FDC_GetBytesPerTrack ( FDC.DriveSelSignal );
3163 
3164 		FDC.CommandState = FDCEMU_RUN_WRITETRACK_TRANSFER_LOOP;
3165 		FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
3166 		break;
3167 	 case FDCEMU_RUN_WRITETRACK_TRANSFER_LOOP:
3168 		/* Transfer the track 1 byte at a time using DMA */
3169 		if ( FDC_DMA.BytesToTransfer-- > 0 )
3170 		{
3171 			Byte = FDC_DMA_FIFO_Pull ();			/* Get 1 byte from the DMA FIFO */
3172 //fprintf ( stderr , "byte %d %x\n" , FDC_DMA.BytesToTransfer , Byte );
3173 			FDC_Buffer_Add ( Byte );
3174 			FdcCycles = FDC_TransferByte_FdcCycles ( 1 );
3175 		}
3176 		else							/* Track written */
3177 		{
3178 			FDC.CommandState = FDCEMU_RUN_WRITETRACK_COMPLETE;
3179 			FdcCycles = FDC_DELAY_CYCLE_COMMAND_IMMEDIATE;
3180 		}
3181 		break;
3182 	 case FDCEMU_RUN_WRITETRACK_COMPLETE:
3183 		/* Track completely transferred */
3184 		/* This is where we save the buffer to the disk image */
3185 		if ( EmulationDrives[ FDC.DriveSelSignal ].ImageType == FLOPPY_IMAGE_TYPE_STX )
3186 			Status = FDC_WriteTrack_STX ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack ,
3187 				FDC.SideSignal , FDC_Buffer_Get_Size () );
3188 		else
3189 			Status = FDC_WriteTrack_ST ( FDC.DriveSelSignal , FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack ,
3190 				FDC.SideSignal , FDC_Buffer_Get_Size () );
3191 
3192 		if ( Status & FDC_STR_BIT_LOST_DATA )			/* Error while writing */
3193 			FDC_Update_STR ( 0 , FDC_STR_BIT_LOST_DATA );	/* Set LOST_DATA bit */
3194 
3195 		FdcCycles = FDC_CmdCompleteCommon( true );
3196 		break;
3197 	}
3198 
3199 	return FdcCycles;
3200 }
3201 
3202 
3203 /*-----------------------------------------------------------------------*/
3204 /**
3205  * Common to types I, II and III
3206  *
3207  * Start motor / spin up sequence if needed
3208  * Return true if spin up sequence is needed, else false
3209  */
3210 
FDC_Set_MotorON(Uint8 FDC_CR)3211 static bool FDC_Set_MotorON ( Uint8 FDC_CR )
3212 {
3213 	int	FrameCycles, HblCounterVideo, LineCycles;
3214 	bool	SpinUp;
3215 
3216 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3217 
3218 	if ( ( ( FDC_CR & FDC_COMMAND_BIT_SPIN_UP ) == 0 )		/* Command wants motor's spin up */
3219 	  && ( ( FDC.STR & FDC_STR_BIT_MOTOR_ON ) == 0 ) )		/* Motor on not enabled yet */
3220 	{
3221 		LOG_TRACE(TRACE_FDC, "fdc start motor with spinup VBL=%d video_cyc=%d %d@%d pc=%x\n",
3222 			nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3223 
3224 		FDC_Update_STR ( FDC_STR_BIT_SPIN_UP , 0 );		/* Unset spin up bit */
3225 		FDC.IndexPulse_Counter = 0;				/* Reset counter to measure the spin up sequence */
3226 		SpinUp = true;
3227 	}
3228 	else								/* No spin up : don't add delay to start the motor */
3229 	{
3230 		LOG_TRACE(TRACE_FDC, "fdc start motor without spinup VBL=%d video_cyc=%d %d@%d pc=%x\n",
3231 			nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3232 
3233 		SpinUp = false;
3234 	}
3235 
3236 	FDC_Update_STR ( 0 , FDC_STR_BIT_MOTOR_ON );			/* Start motor */
3237 
3238 	if ( ( FDC.DriveSelSignal < 0 ) || ( !FDC_DRIVES[ FDC.DriveSelSignal ].Enabled )
3239 		|| ( !FDC_DRIVES[ FDC.DriveSelSignal ].DiskInserted ) )
3240 	{
3241 		LOG_TRACE(TRACE_FDC, "fdc start motor : no disk/drive VBL=%d video_cyc=%d %d@%d pc=%x\n",
3242 			nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3243 	}
3244 	else if ( FDC_DRIVES[ FDC.DriveSelSignal ].IndexPulse_Time == 0 )
3245 		FDC_IndexPulse_Init ( FDC.DriveSelSignal );		/* Index Pulse's position is random when motor starts */
3246 
3247 	return SpinUp;
3248 }
3249 
3250 
3251 /*-----------------------------------------------------------------------*/
3252 /**
3253  * Type I Commands
3254  *
3255  * Restore, Seek, Step, Step-In and Step-Out
3256  */
3257 
3258 
3259 /*-----------------------------------------------------------------------*/
FDC_TypeI_Restore(void)3260 static int FDC_TypeI_Restore(void)
3261 {
3262 	int	FrameCycles, HblCounterVideo, LineCycles;
3263 
3264 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3265 
3266 	LOG_TRACE(TRACE_FDC, "fdc type I restore spinup=%s verify=%s steprate_ms=%d drive=%d tr=0x%x head_track=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3267 		  ( FDC.CR & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
3268 		  ( FDC.CR & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
3269 		  FDC_StepRate_ms[ FDC_STEP_RATE ] ,
3270 		  FDC.DriveSelSignal , FDC.TR , FDC.DriveSelSignal >= 0 ? FDC_DRIVES[ FDC.DriveSelSignal].HeadTrack : -1 ,
3271 		  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3272 
3273 	/* Set emulation to seek to track zero */
3274 	FDC.Command = FDCEMU_CMD_RESTORE;
3275 	FDC.CommandState = FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO;
3276 
3277 	FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
3278 
3279 	return FDC_DELAY_CYCLE_TYPE_I_PREPARE;
3280 }
3281 
3282 
3283 /*-----------------------------------------------------------------------*/
FDC_TypeI_Seek(void)3284 static int FDC_TypeI_Seek ( void )
3285 {
3286 	int	FrameCycles, HblCounterVideo, LineCycles;
3287 
3288 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3289 
3290 	LOG_TRACE(TRACE_FDC, "fdc type I seek dest_track=0x%x spinup=%s verify=%s steprate_ms=%d drive=%d tr=0x%x head_track=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3291 		  FDC.DR,
3292 		  ( FDC.CR & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
3293 		  ( FDC.CR & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
3294 		  FDC_StepRate_ms[ FDC_STEP_RATE ] ,
3295 		  FDC.DriveSelSignal , FDC.TR , FDC.DriveSelSignal >= 0 ? FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack : -1 ,
3296 		  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3297 
3298 	/* Set emulation to seek to chosen track */
3299 	FDC.Command = FDCEMU_CMD_SEEK;
3300 	FDC.CommandState = FDCEMU_RUN_SEEK_TOTRACK;
3301 
3302 	FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
3303 
3304 	return FDC_DELAY_CYCLE_TYPE_I_PREPARE;
3305 }
3306 
3307 
3308 /*-----------------------------------------------------------------------*/
FDC_TypeI_Step(void)3309 static int FDC_TypeI_Step ( void )
3310 {
3311 	int	FrameCycles, HblCounterVideo, LineCycles;
3312 
3313 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3314 
3315 	LOG_TRACE(TRACE_FDC, "fdc type I step %d spinup=%s verify=%s steprate_ms=%d drive=%d tr=0x%x head_track=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3316 		  FDC.StepDirection,
3317 		  ( FDC.CR & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
3318 		  ( FDC.CR & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
3319 		  FDC_StepRate_ms[ FDC_STEP_RATE ] ,
3320 		  FDC.DriveSelSignal , FDC.TR , FDC.DriveSelSignal >= 0 ? FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack : -1 ,
3321 		  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3322 
3323 	/* Set emulation to step (using same direction as latest seek executed, ie 'FDC.StepDirection') */
3324 	FDC.Command = FDCEMU_CMD_STEP;
3325 	FDC.CommandState = FDCEMU_RUN_STEP_ONCE;
3326 
3327 	FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
3328 
3329 	return FDC_DELAY_CYCLE_TYPE_I_PREPARE;
3330 }
3331 
3332 
3333 /*-----------------------------------------------------------------------*/
FDC_TypeI_StepIn(void)3334 static int FDC_TypeI_StepIn(void)
3335 {
3336 	int	FrameCycles, HblCounterVideo, LineCycles;
3337 
3338 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3339 
3340 	LOG_TRACE(TRACE_FDC, "fdc type I step in spinup=%s verify=%s steprate_ms=%d drive=%d tr=0x%x head_track=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3341 		  ( FDC.CR & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
3342 		  ( FDC.CR & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
3343 		  FDC_StepRate_ms[ FDC_STEP_RATE ] ,
3344 		  FDC.DriveSelSignal , FDC.TR , FDC.DriveSelSignal >= 0 ? FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack : -1 ,
3345 		  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3346 
3347 	/* Set emulation to step in (direction = +1) */
3348 	FDC.Command = FDCEMU_CMD_STEP;
3349 	FDC.CommandState = FDCEMU_RUN_STEP_ONCE;
3350 	FDC.StepDirection = 1;						/* Increment track*/
3351 
3352 	FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
3353 
3354 	return FDC_DELAY_CYCLE_TYPE_I_PREPARE;
3355 }
3356 
3357 
3358 /*-----------------------------------------------------------------------*/
FDC_TypeI_StepOut(void)3359 static int FDC_TypeI_StepOut ( void )
3360 {
3361 	int	FrameCycles, HblCounterVideo, LineCycles;
3362 
3363 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3364 
3365 	LOG_TRACE(TRACE_FDC, "fdc type I step out spinup=%s verify=%s steprate_ms=%d drive=%d tr=0x%x head_track=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3366 		  ( FDC.CR & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
3367 		  ( FDC.CR & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
3368 		  FDC_StepRate_ms[ FDC_STEP_RATE ] ,
3369 		  FDC.DriveSelSignal , FDC.TR , FDC.DriveSelSignal >= 0 ? FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack : -1 ,
3370 		  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3371 
3372 	/* Set emulation to step out (direction = -1) */
3373 	FDC.Command = FDCEMU_CMD_STEP;
3374 	FDC.CommandState = FDCEMU_RUN_STEP_ONCE;
3375 	FDC.StepDirection = -1;						/* Decrement track */
3376 
3377 	FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
3378 
3379 	return FDC_DELAY_CYCLE_TYPE_I_PREPARE;
3380 }
3381 
3382 
3383 /*-----------------------------------------------------------------------*/
3384 /**
3385  * Type II Commands
3386  *
3387  * Read Sector, Write Sector
3388  */
3389 
3390 
3391 /*-----------------------------------------------------------------------*/
FDC_TypeII_ReadSector(void)3392 static int FDC_TypeII_ReadSector ( void )
3393 {
3394 	int	FrameCycles, HblCounterVideo, LineCycles;
3395 
3396 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3397 
3398 	LOG_TRACE(TRACE_FDC, "fdc type II read sector sector=0x%x multi=%s spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d dmasector=%d addr=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3399 		  FDC.SR, ( FDC.CR & FDC_COMMAND_BIT_MULTIPLE_SECTOR ) ? "on" : "off" ,
3400 		  ( FDC.CR & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
3401 		  ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
3402 		  FDC.TR , FDC.DriveSelSignal >= 0 ? FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack : -1 ,
3403 		  FDC.SideSignal , FDC.DriveSelSignal , FDC_DMA.SectorCount ,
3404 		  FDC_GetDMAAddress(), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3405 
3406 	/* Set emulation to read sector(s) */
3407 	FDC.Command = FDCEMU_CMD_READSECTORS;
3408 	FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA;
3409 
3410 	FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
3411 		| FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE | FDC_STR_BIT_WPRT , FDC_STR_BIT_BUSY );
3412 
3413 	return FDC_DELAY_CYCLE_TYPE_II_PREPARE;
3414 }
3415 
3416 
3417 /*-----------------------------------------------------------------------*/
FDC_TypeII_WriteSector(void)3418 static int FDC_TypeII_WriteSector ( void )
3419 {
3420 	int	FrameCycles, HblCounterVideo, LineCycles;
3421 
3422 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3423 
3424 	LOG_TRACE(TRACE_FDC, "fdc type II write sector sector=0x%x multi=%s spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d dmasector=%d addr=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3425 		  FDC.SR, ( FDC.CR & FDC_COMMAND_BIT_MULTIPLE_SECTOR ) ? "on" : "off" ,
3426 		  ( FDC.CR & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
3427 		  ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
3428 		  FDC.TR , FDC.DriveSelSignal >= 0 ? FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack : -1 ,
3429 		  FDC.SideSignal , FDC.DriveSelSignal , FDC_DMA.SectorCount,
3430 		  FDC_GetDMAAddress(), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3431 
3432 	/* Set emulation to write a sector(s) */
3433 	FDC.Command = FDCEMU_CMD_WRITESECTORS;
3434 	FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA;
3435 
3436 	FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
3437 		| FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE , FDC_STR_BIT_BUSY );
3438 
3439 	return FDC_DELAY_CYCLE_TYPE_II_PREPARE;
3440 }
3441 
3442 
3443 /*-----------------------------------------------------------------------*/
3444 /**
3445  * Type III Commands
3446  *
3447  * Read Address, Read Track, Write Track
3448  */
3449 
3450 
3451 /*-----------------------------------------------------------------------*/
FDC_TypeIII_ReadAddress(void)3452 static int FDC_TypeIII_ReadAddress ( void )
3453 {
3454 	int	FrameCycles, HblCounterVideo, LineCycles;
3455 
3456 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3457 
3458 	LOG_TRACE(TRACE_FDC, "fdc type III read address spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3459 		  ( FDC.CR & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
3460 		  ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
3461 		  FDC.TR , FDC.DriveSelSignal >= 0 ? FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack : -1 ,
3462 		  FDC.SideSignal , FDC.DriveSelSignal , FDC_GetDMAAddress(),
3463 		  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3464 
3465 	/* Set emulation to seek to track zero */
3466 	FDC.Command = FDCEMU_CMD_READADDRESS;
3467 	FDC.CommandState = FDCEMU_RUN_READADDRESS;
3468 
3469 	FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
3470 		| FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE | FDC_STR_BIT_WPRT , FDC_STR_BIT_BUSY );
3471 
3472 	return FDC_DELAY_CYCLE_TYPE_III_PREPARE;
3473 }
3474 
3475 
3476 /*-----------------------------------------------------------------------*/
FDC_TypeIII_ReadTrack(void)3477 static int FDC_TypeIII_ReadTrack ( void )
3478 {
3479 	int	FrameCycles, HblCounterVideo, LineCycles;
3480 
3481 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3482 
3483 	LOG_TRACE(TRACE_FDC, "fdc type III read track spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3484 		  ( FDC.CR & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
3485 		  ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
3486 		  FDC.TR , FDC.DriveSelSignal >= 0 ? FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack : -1 ,
3487 		  FDC.SideSignal , FDC.DriveSelSignal , FDC_GetDMAAddress(),
3488 		  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3489 
3490 	/* Set emulation to read a single track */
3491 	FDC.Command = FDCEMU_CMD_READTRACK;
3492 	FDC.CommandState = FDCEMU_RUN_READTRACK;
3493 
3494 	FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
3495 		| FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE | FDC_STR_BIT_WPRT , FDC_STR_BIT_BUSY );
3496 
3497 	return FDC_DELAY_CYCLE_TYPE_III_PREPARE;
3498 }
3499 
3500 
3501 /*-----------------------------------------------------------------------*/
FDC_TypeIII_WriteTrack(void)3502 static int FDC_TypeIII_WriteTrack ( void )
3503 {
3504 	int	FrameCycles, HblCounterVideo, LineCycles;
3505 
3506 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3507 
3508 	LOG_TRACE(TRACE_FDC, "fdc type III write track spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3509 		  ( FDC.CR & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
3510 		  ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
3511 		  FDC.TR , FDC.DriveSelSignal >= 0 ? FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack : -1 ,
3512 		  FDC.SideSignal , FDC.DriveSelSignal , FDC_GetDMAAddress(),
3513 		  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3514 
3515 	/* Set emulation to write a single track */
3516 	FDC.Command = FDCEMU_CMD_WRITETRACK;
3517 	FDC.CommandState = FDCEMU_RUN_WRITETRACK;
3518 
3519 	FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
3520 		| FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE | FDC_STR_BIT_WPRT , FDC_STR_BIT_BUSY );
3521 
3522 	return FDC_DELAY_CYCLE_TYPE_III_PREPARE;
3523 }
3524 
3525 
3526 /*-----------------------------------------------------------------------*/
3527 /**
3528  * Type IV Commands
3529  *
3530  * Force Interrupt
3531  */
3532 
3533 
3534 /*-----------------------------------------------------------------------*/
FDC_TypeIV_ForceInterrupt(void)3535 static int FDC_TypeIV_ForceInterrupt ( void )
3536 {
3537 	int	FdcCycles;
3538 	int	FrameCycles, HblCounterVideo, LineCycles;
3539 
3540 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3541 
3542 	LOG_TRACE(TRACE_FDC, "fdc type IV force int 0x%x irq=%d index=%d VBL=%d video_cyc=%d %d@%d pc=%x\n",
3543 		  FDC.CR , ( FDC.CR & 0x8 ) >> 3 , ( FDC.CR & 0x4 ) >> 2 ,
3544 		  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3545 
3546 	/* If a command was running, just remove busy bit and keep the current content of Status reg */
3547 	/* If FDC was idle, the content of Status reg is forced to type I */
3548 	if ( ( FDC.STR & FDC_STR_BIT_BUSY ) == 0 )
3549 	{
3550 		FDC.StatusTypeI = true;
3551 
3552 		/* Starting a Force Int command when idle should set the motor bit and clear the spinup bit (verified on STF) */
3553 		FDC_Update_STR ( FDC_STR_BIT_SPIN_UP , FDC_STR_BIT_MOTOR_ON );	/* Clear spinup bit and set motor bit */
3554 	}
3555 
3556 	/* Get the interrupt's condition and set IRQ accordingly */
3557 	/* Most of the time a 0xD8 command is followed by a 0xD0 command and a read STR to clear the IRQ signal */
3558 	FDC.InterruptCond = FDC.CR & 0x0f;				/* Keep the 4 lowest bits */
3559 
3560 	if ( FDC.InterruptCond & FDC_INTERRUPT_COND_IMMEDIATE )
3561 		FDC_SetIRQ ( FDC_IRQ_SOURCE_FORCED );
3562 	else
3563 		FDC_ClearIRQ ();
3564 
3565 	/* Remove busy bit, don't change IRQ's state and stop the motor */
3566 	FdcCycles = FDC_CmdCompleteCommon( false );
3567 
3568 	return FDC_DELAY_CYCLE_TYPE_IV_PREPARE + FdcCycles;
3569 }
3570 
3571 
3572 /*-----------------------------------------------------------------------*/
3573 /**
3574  * Execute Type I commands
3575  */
FDC_ExecuteTypeICommands(void)3576 static int FDC_ExecuteTypeICommands ( void )
3577 {
3578 	int	FdcCycles = 0;
3579 
3580 	FDC.CommandType = 1;
3581 	FDC.StatusTypeI = true;
3582 
3583 	/* Check Type I Command */
3584 	switch ( FDC.CR & 0xf0 )
3585 	{
3586 	 case 0x00:             /* Restore */
3587 		FdcCycles = FDC_TypeI_Restore();
3588 		break;
3589 	 case 0x10:             /* Seek */
3590 		FdcCycles = FDC_TypeI_Seek();
3591 		break;
3592 	 case 0x20:             /* Step */
3593 	 case 0x30:
3594 		FdcCycles = FDC_TypeI_Step();
3595 		break;
3596 	 case 0x40:             /* Step-In */
3597 	 case 0x50:
3598 		FdcCycles = FDC_TypeI_StepIn();
3599 		break;
3600 	 case 0x60:             /* Step-Out */
3601 	 case 0x70:
3602 		FdcCycles = FDC_TypeI_StepOut();
3603 		break;
3604 	}
3605 
3606 	return FdcCycles;
3607 }
3608 
3609 
3610 /*-----------------------------------------------------------------------*/
3611 /**
3612  * Execute Type II commands
3613  */
FDC_ExecuteTypeIICommands(void)3614 static int FDC_ExecuteTypeIICommands ( void )
3615 {
3616 	int	FdcCycles = 0;
3617 
3618 	FDC.CommandType = 2;
3619 	FDC.StatusTypeI = false;
3620 
3621 	/* Check Type II Command */
3622 	switch ( FDC.CR & 0xf0 )
3623 	{
3624 	 case 0x80:             /* Read Sector multi=0*/
3625 	 case 0x90:             /* Read Sectors multi=1 */
3626 		FdcCycles = FDC_TypeII_ReadSector();
3627 		break;
3628 	 case 0xa0:             /* Write Sector multi=0 */
3629 	 case 0xb0:             /* Write Sectors multi=1 */
3630 		FdcCycles = FDC_TypeII_WriteSector();
3631 		break;
3632 	}
3633 
3634 	return FdcCycles;
3635 }
3636 
3637 
3638 /*-----------------------------------------------------------------------*/
3639 /**
3640  * Execute Type III commands
3641  */
FDC_ExecuteTypeIIICommands(void)3642 static int FDC_ExecuteTypeIIICommands ( void )
3643 {
3644 	int	FdcCycles = 0;
3645 
3646 	FDC.CommandType = 3;
3647 	FDC.StatusTypeI = false;
3648 
3649 	/* Check Type III Command */
3650 	switch ( FDC.CR & 0xf0 )
3651 	{
3652 	 case 0xc0:             /* Read Address */
3653 		FdcCycles = FDC_TypeIII_ReadAddress();
3654 		break;
3655 	 case 0xe0:             /* Read Track */
3656 		FdcCycles = FDC_TypeIII_ReadTrack();
3657 		break;
3658 	 case 0xf0:             /* Write Track */
3659 		FdcCycles = FDC_TypeIII_WriteTrack();
3660 		break;
3661 	}
3662 
3663 	return FdcCycles;
3664 }
3665 
3666 
3667 /*-----------------------------------------------------------------------*/
3668 /**
3669  * Execute Type IV commands
3670  */
FDC_ExecuteTypeIVCommands(void)3671 static int FDC_ExecuteTypeIVCommands ( void )
3672 {
3673 	int	FdcCycles;
3674 
3675 	FDC.CommandType = 4;
3676 
3677 	FdcCycles = FDC_TypeIV_ForceInterrupt();
3678 
3679 	return FdcCycles;
3680 }
3681 
3682 
3683 /*-----------------------------------------------------------------------*/
3684 /**
3685  * Find FDC command type and execute
3686  *
3687  * NOTE [NP] : as verified on a real STF and contrary to what is written
3688  * in the WD1772 doc, any new command will reset the InterruptCond set by
3689  * a previous Dx command, not just a D0.
3690  * This means that a D8 command (force int) can be cancelled by a D0 command
3691  * or by any other command ; but in any case, IRQ will remain set until
3692  * status register is read or another new command is started.
3693  * -> 1st command clears force IRQ condition, 2nd command clears IRQ
3694  */
FDC_ExecuteCommand(void)3695 static void FDC_ExecuteCommand ( void )
3696 {
3697 	int	FdcCycles;
3698 	Uint8	Type;
3699 
3700 	Type = FDC_GetCmdType ( FDC.CR );
3701 
3702 	/* When a new command is started, FDC's IRQ is reset (except if "force interrupt immediate" is set) */
3703 
3704 	/* If IRQ is forced but FDC_INTERRUPT_COND_IMMEDIATE is not set anymore, this means */
3705 	/* the D8 command was stopped and we can clear the forced IRQ when starting a new command */
3706 	if ( ( FDC.IRQ_Signal & FDC_IRQ_SOURCE_FORCED )
3707 	  && ( ( FDC.InterruptCond & FDC_INTERRUPT_COND_IMMEDIATE ) == 0 ) )
3708 		FDC.IRQ_Signal &= ~FDC_IRQ_SOURCE_FORCED;	/* Really stop the forced IRQ */
3709 
3710 	/* Starting a new type I/II/III should clear the IRQ (except when IRQ is forced) */
3711 	/* For type IV, this is handled in FDC_TypeIV_ForceInterrupt() */
3712 	if ( Type != 4 )
3713 		FDC_ClearIRQ ();
3714 
3715 	/* When a new command is executed, we clear InterruptCond */
3716 	/* (not just when the new command is D0) */
3717 	/* InterruptCond is cleared here, but it might be set again just after */
3718 	/* when we call FDC_ExecuteTypeIVCommands() */
3719 	FDC.InterruptCond = 0;
3720 
3721 	/* Check type of command and execute */
3722 	if ( Type == 1 )						/* Type I - Restore, Seek, Step, Step-In, Step-Out */
3723 		FdcCycles = FDC_ExecuteTypeICommands();
3724 	else if ( Type == 2 )						/* Type II - Read Sector, Write Sector */
3725 		FdcCycles = FDC_ExecuteTypeIICommands();
3726 	else if ( Type == 3 )						/* Type III - Read Address, Read Track, Write Track */
3727 		FdcCycles = FDC_ExecuteTypeIIICommands();
3728 	else								/* Type IV - Force Interrupt */
3729 		FdcCycles = FDC_ExecuteTypeIVCommands();
3730 
3731 	FDC.ReplaceCommandPossible = true;				/* This new command can be replaced during the prepare+spinup phase */
3732 	FDC_StartTimer_FdcCycles ( FdcCycles , 0 );
3733 }
3734 
3735 
3736 /*-----------------------------------------------------------------------*/
3737 /**
3738  * Write to SectorCount register $ff8604
3739  */
FDC_WriteSectorCountRegister(void)3740 static void FDC_WriteSectorCountRegister ( void )
3741 {
3742 	int FrameCycles, HblCounterVideo, LineCycles;
3743 
3744 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3745 
3746 	FDC_DMA.SectorCount = IoMem_ReadWord(0xff8604);
3747 	if (!Config_IsMachineFalcon())
3748 		FDC_DMA.SectorCount &= 0xff;
3749 
3750 	LOG_TRACE(TRACE_FDC, "fdc write 8604 dma sector count=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3751 	          FDC_DMA.SectorCount, nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3752 
3753 }
3754 
3755 
3756 /*-----------------------------------------------------------------------*/
3757 /**
3758  * Write to Command register $ff8604
3759  */
FDC_WriteCommandRegister(void)3760 static void FDC_WriteCommandRegister ( void )
3761 {
3762 	int FrameCycles, HblCounterVideo, LineCycles;
3763 	Uint8 Type_new;
3764 
3765 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3766 
3767 	LOG_TRACE(TRACE_FDC, "fdc write 8604 command=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3768 		  IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3769 
3770 	/* If fdc is busy, only 'Force Interrupt' is possible */
3771 	/* [NP] : it's also possible to start a new command just after another command */
3772 	/* was started and spinup phase was not completed yet (eg Overdrive Demos by Phalanx) (see notes at the top of the file)*/
3773 	if ( FDC.STR & FDC_STR_BIT_BUSY )
3774 	{
3775 		Type_new = FDC_GetCmdType ( IoMem_ReadByte(0xff8605) );
3776 		if ( Type_new == 4 )					/* 'Force Interrupt' command */
3777 		{
3778 			LOG_TRACE(TRACE_FDC, "fdc write 8604 while fdc busy, current command=0x%x interrupted by command=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3779 				FDC.CR , IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3780 		}
3781 
3782 		else if ( FDC.ReplaceCommandPossible
3783 			&& ( ( ( Type_new == 1 ) && ( FDC.CommandType == Type_new ) )		/* Replace a type I command with a type I */
3784 			  || ( ( Type_new == 2 ) && ( FDC.CommandType == Type_new ) ) ) )	/* Replace a type II command with a type II */
3785 		{
3786 			LOG_TRACE(TRACE_FDC, "fdc write 8604 while fdc busy in prepare+spinup, current command=0x%x replaced by command=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3787 				FDC.CR , IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3788 		}
3789 
3790 		else								/* Other cases : new command is ignored */
3791 		{
3792 			LOG_TRACE(TRACE_FDC, "fdc write 8604 fdc busy, command=0x%x ignored VBL=%d video_cyc=%d %d@%d pc=%x\n",
3793 				IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3794 			return;
3795 		}
3796 	}
3797 
3798 	FDC.CR = IoMem_ReadByte(0xff8605);
3799 	FDC_ExecuteCommand();
3800 }
3801 
3802 
3803 /*-----------------------------------------------------------------------*/
3804 /**
3805  * Write to Track register $ff8604
3806  */
FDC_WriteTrackRegister(void)3807 static void FDC_WriteTrackRegister ( void )
3808 {
3809 	int FrameCycles, HblCounterVideo, LineCycles;
3810 
3811 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3812 
3813 	LOG_TRACE(TRACE_FDC, "fdc write 8604 track=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
3814 		IoMem_ReadByte(0xff8605) , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
3815 
3816 	/* [NP] Contrary to what is written in the WD1772 doc, Track Register can be changed */
3817 	/* while the fdc is busy (the change will be ignored or not, depending on the current sub-state */
3818 	/* in the state machine) */
3819 	if ( FDC.STR & FDC_STR_BIT_BUSY )
3820 	{
3821 		LOG_TRACE(TRACE_FDC, "fdc write 8604 fdc busy, track=0x%x may be ignored VBL=%d video_cyc=%d %d@%d pc=%x\n",
3822 			IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3823 //return;
3824 	}
3825 
3826 	FDC.TR = IoMem_ReadByte(0xff8605);
3827 }
3828 
3829 
3830 /*-----------------------------------------------------------------------*/
3831 /**
3832  * Write to Sector register $ff8604
3833  */
FDC_WriteSectorRegister(void)3834 static void FDC_WriteSectorRegister ( void )
3835 {
3836 	int FrameCycles, HblCounterVideo, LineCycles;
3837 
3838 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3839 
3840 	LOG_TRACE(TRACE_FDC, "fdc write 8604 sector=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
3841 		IoMem_ReadByte(0xff8605) , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
3842 
3843 	/* [NP] Contrary to what is written in the WD1772 doc, Sector Register can be changed */
3844 	/* while the fdc is busy (but it will have no effect once the sector's header is found) */
3845 	/* (fix Delirious Demo IV's loader, which is bugged and set SR after starting the Read Sector command) */
3846 	if ( FDC.STR & FDC_STR_BIT_BUSY )
3847 	{
3848 		LOG_TRACE(TRACE_FDC, "fdc write 8604 fdc busy, sector=0x%x may be ignored VBL=%d video_cyc=%d %d@%d pc=%x\n",
3849 			IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3850 	}
3851 
3852 	FDC.SR = IoMem_ReadByte(0xff8605);
3853 }
3854 
3855 
3856 /*-----------------------------------------------------------------------*/
3857 /**
3858  * Write to Data register $ff8604
3859  */
FDC_WriteDataRegister(void)3860 static void FDC_WriteDataRegister ( void )
3861 {
3862 	int FrameCycles, HblCounterVideo, LineCycles;
3863 
3864 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3865 
3866 	LOG_TRACE(TRACE_FDC, "fdc write 8604 data=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
3867 		IoMem_ReadByte(0xff8605), nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
3868 
3869 	FDC.DR = IoMem_ReadByte(0xff8605);
3870 }
3871 
3872 
3873 /*-----------------------------------------------------------------------*/
3874 /**
3875  * Store byte in FDC/HDC registers or DMA sector count, when writing to $ff8604
3876  * When accessing FDC/HDC registers, a copy of $ff8604 should be kept in ff8604_recent_val
3877  * to be used later when reading unused bits at $ff8604/$ff8606
3878  *
3879  * NOTE [NP] : add 4 cycles wait state in all cases (sector count / FDC / HDC)
3880  */
FDC_DiskController_WriteWord(void)3881 void FDC_DiskController_WriteWord ( void )
3882 {
3883 	int FrameCycles, HblCounterVideo, LineCycles;
3884 	int EmulationMode;
3885 	int FDC_reg;
3886 
3887 	if ( nIoMemAccessSize == SIZE_BYTE )
3888 	{
3889 		/* This register does not like to be accessed in byte mode on a normal ST */
3890 		M68000_BusError(IoAccessFullAddress, BUS_ERROR_WRITE, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
3891 		return;
3892 	}
3893 
3894 	M68000_WaitState(4);
3895 
3896 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
3897 
3898 	LOG_TRACE(TRACE_FDC, "fdc write 8604 data=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
3899 		IoMem_ReadWord(0xff8604), nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
3900 
3901 
3902 	/* Are we trying to set the DMA SectorCount ? */
3903 	if ( FDC_DMA.Mode & 0x10 )					/* Bit 4 */
3904 	{
3905 		FDC_WriteSectorCountRegister();
3906 		return;
3907 	}
3908 
3909 	/* Store the byte that was just accessed by this write */
3910 	FDC_DMA.ff8604_recent_val = ( FDC_DMA.ff8604_recent_val & 0xff00 ) | IoMem_ReadByte(0xff8605);
3911 
3912 	if ( ( FDC_DMA.Mode & 0x0008 ) == 0x0008 )			/* Is it an ACSI (or Falcon SCSI) HDC command access ? */
3913 	{
3914 		/*  Handle HDC access */
3915 		LOG_TRACE(TRACE_FDC, "fdc write 8604 hdc command addr=%x command=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
3916 			  FDC_DMA.Mode & 0x7 , IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
3917 
3918 		HDC_WriteCommandByte(FDC_DMA.Mode & 0x7, IoMem_ReadByte(0xff8605));
3919 		return;
3920 	}
3921 
3922 	else								/* It's a FDC register access */
3923 	{
3924 		FDC_reg = ( FDC_DMA.Mode & 0x6 ) >> 1;			/* Bits 1,2 (A0,A1) */
3925 
3926 		EmulationMode = FDC_GetEmulationMode();
3927 		if ( EmulationMode == FDC_EMULATION_MODE_INTERNAL )
3928 		{
3929 			/* Update FDC's internal variables */
3930 			FDC_UpdateAll ();
3931 
3932 			/* Write to FDC registers */
3933 			switch ( FDC_reg )
3934 			{
3935 			 case 0x0:					/* 0 0 - Command register */
3936 				FDC_WriteCommandRegister();
3937 				break;
3938 			 case 0x1:					/* 0 1 - Track register */
3939 				FDC_WriteTrackRegister();
3940 				break;
3941 			 case 0x2:					/* 1 0 - Sector register */
3942 				FDC_WriteSectorRegister();
3943 				break;
3944 			 case 0x3:					/* 1 1 - Data register */
3945 				FDC_WriteDataRegister();
3946 				break;
3947 			}
3948 		}
3949 		else if ( EmulationMode == FDC_EMULATION_MODE_IPF )
3950 		{
3951 			IPF_FDC_WriteReg ( FDC_reg , IoMem_ReadByte(0xff8605) );
3952 		}
3953 	}
3954 }
3955 
3956 
3957 /*-----------------------------------------------------------------------*/
3958 /**
3959  * Return FDC/HDC registers or DMA sector count when reading from $ff8604
3960  * - When accessing FDC/HDC registers, a copy of $ff8604 should be kept in ff8604_recent_val
3961  *   to be used later when reading unused bits at $ff8604/$ff8606
3962  * - DMA sector count can't be read, this will return ff8604_recent_val (verified on a real STF)
3963  *
3964  * NOTE [NP] : add 4 cycles wait state in that case, except when reading DMA sector count
3965  */
FDC_DiskControllerStatus_ReadWord(void)3966 void FDC_DiskControllerStatus_ReadWord ( void )
3967 {
3968 	Uint16 DiskControllerByte = 0;					/* Used to pass back the parameter */
3969 	int FrameCycles, HblCounterVideo, LineCycles;
3970 	int ForceWPRT;
3971 	int EmulationMode;
3972 	int FDC_reg;
3973 
3974 	if (nIoMemAccessSize == SIZE_BYTE && !Config_IsMachineFalcon())
3975 	{
3976 		/* This register does not like to be accessed in byte mode on a normal ST */
3977 		M68000_BusError(IoAccessFullAddress, BUS_ERROR_READ, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
3978 		return;
3979 	}
3980 
3981 	/* Are we trying to read the DMA SectorCount ? */
3982 	if ( FDC_DMA.Mode & 0x10 )					/* Bit 4 */
3983 	{
3984 		DiskControllerByte = FDC_DMA.ff8604_recent_val;		/* As verified on real STF, DMA sector count can't be read back */
3985 	}
3986 
3987 	else if ( ( FDC_DMA.Mode & 0x0008) == 0x0008)			/* HDC status reg selected ? */
3988 	{
3989 		M68000_WaitState(4);					/* [NP] : possible, but not tested on real HW */
3990 
3991 		/* Return the HDC status byte */
3992 		DiskControllerByte = HDC_ReadCommandByte(FDC_DMA.Mode & 0x7);
3993 	}
3994 
3995 	else								/* It's a FDC register access */
3996 	{
3997 		M68000_WaitState(4);
3998 
3999 		FDC_reg = ( FDC_DMA.Mode & 0x6 ) >> 1;			/* Bits 1,2 (A0,A1) */
4000 
4001 		EmulationMode = FDC_GetEmulationMode();
4002 		if ( EmulationMode == FDC_EMULATION_MODE_INTERNAL )
4003 		{
4004 			/* Update FDC's internal variables */
4005 			FDC_UpdateAll ();
4006 
4007 			/* Read FDC registers */
4008 			switch ( FDC_reg )
4009 			{
4010 			 case 0x0:						/* 0 0 - Status register */
4011 				/* If we report a type I status, some bits are updated in real time */
4012 				/* depending on the corresponding signals. If this is not a type I, we return STR unmodified */
4013 				/* [NP] Contrary to what is written in the WD1772 doc, the WPRT bit */
4014 				/* is updated after a Type I command */
4015 				/* (eg : Procopy or Terminators Copy 1.68 do a Restore/Seek to test WPRT) */
4016 				if ( FDC.StatusTypeI )
4017 				{
4018 					/* If no drive available, FDC's input signals TR00, INDEX and WPRT are off */
4019 					if ( ( FDC.DriveSelSignal < 0 ) || ( !FDC_DRIVES[ FDC.DriveSelSignal ].Enabled ) )
4020 						FDC_Update_STR ( FDC_STR_BIT_TR00 | FDC_STR_BIT_INDEX | FDC_STR_BIT_WPRT , 0 );
4021 
4022 					else
4023 					{
4024 						if ( FDC_DRIVES[ FDC.DriveSelSignal ].HeadTrack == 0 )
4025 							FDC_Update_STR ( 0 , FDC_STR_BIT_TR00 );	/* Set TR00 bit2 */
4026 						else
4027 							FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 );	/* Unset TR00 bit2 */
4028 
4029 						if ( FDC_IndexPulse_GetState () )
4030 							FDC_Update_STR ( 0 , FDC_STR_BIT_INDEX );	/* Set INDEX bit1 */
4031 						else
4032 							FDC_Update_STR ( FDC_STR_BIT_INDEX , 0 );	/* Unset INDEX bit1 */
4033 
4034 						/* For Type I, always unset CRC ERROR  bit3 */
4035 						FDC_Update_STR ( FDC_STR_BIT_CRC_ERROR , 0 );
4036 
4037 						/* When there's no disk in drive, the floppy drive hardware can't see */
4038 						/* the difference with an inserted disk that would be write protected */
4039 						if ( ! FDC_DRIVES[ FDC.DriveSelSignal ].DiskInserted )
4040 							FDC_Update_STR ( 0 , FDC_STR_BIT_WPRT );	/* Set WPRT bit6 */
4041 						else if ( Floppy_IsWriteProtected ( FDC.DriveSelSignal ) )
4042 							FDC_Update_STR ( 0 , FDC_STR_BIT_WPRT );	/* Set WPRT bit6 */
4043 						else
4044 							FDC_Update_STR ( FDC_STR_BIT_WPRT , 0 );	/* Unset WPRT bit6 */
4045 
4046 						/* Temporarily change the WPRT bit if we're in a transition phase */
4047 						/* regarding the disk in the drive (inserting or ejecting) */
4048 						ForceWPRT = Floppy_DriveTransitionUpdateState ( FDC.DriveSelSignal );
4049 						if ( ForceWPRT == 1 )
4050 							FDC_Update_STR ( 0 , FDC_STR_BIT_WPRT );	/* Force setting WPRT */
4051 						else if ( ForceWPRT == -1 )
4052 							FDC_Update_STR ( FDC_STR_BIT_WPRT , 0 );	/* Force clearing WPRT */
4053 
4054 						if ( ForceWPRT != 0 )
4055 							LOG_TRACE(TRACE_FDC, "force wprt=%d VBL=%d drive=%d str=%x\n",
4056 							  ForceWPRT==1?1:0, nVBLs, FDC.DriveSelSignal, FDC.STR );
4057 					}
4058 				}
4059 
4060 				DiskControllerByte = FDC.STR;
4061 
4062 				/* When Status Register is read, FDC's IRQ is reset (except if "force interrupt immediate" is set) */
4063 
4064 				/* If IRQ is forced but FDC_INTERRUPT_COND_IMMEDIATE is not set anymore, this means */
4065 				/* the D8 command was stopped and we can clear the forced IRQ while reading status register */
4066 				if ( ( FDC.IRQ_Signal & FDC_IRQ_SOURCE_FORCED )
4067 				  && ( ( FDC.InterruptCond & FDC_INTERRUPT_COND_IMMEDIATE ) == 0 ) )
4068 					FDC.IRQ_Signal &= ~FDC_IRQ_SOURCE_FORCED;	/* Really stop the forced IRQ */
4069 
4070 				FDC_ClearIRQ ();
4071 				break;
4072 			 case 0x1:						/* 0 1 - Track register */
4073 				DiskControllerByte = FDC.TR;
4074 				break;
4075 			 case 0x2:						/* 1 0 - Sector register */
4076 				DiskControllerByte = FDC.SR;
4077 				break;
4078 			 case 0x3:						/* 1 1 - Data register */
4079 				DiskControllerByte = FDC.DR;
4080 				break;
4081 			}
4082 		}
4083 		else if ( EmulationMode == FDC_EMULATION_MODE_IPF )
4084 		{
4085 			DiskControllerByte = IPF_FDC_ReadReg ( FDC_reg );
4086 			if ( ( FDC_reg == 0x0 ) && ( FDC.DriveSelSignal >= 0 ) )	/* 0 0 - Status register */
4087 			{
4088 				/* Temporarily change the WPRT bit if we're in a transition phase */
4089 				/* regarding the disk in the drive (inserting or ejecting) */
4090 				ForceWPRT = Floppy_DriveTransitionUpdateState ( FDC.DriveSelSignal );
4091 				if ( ForceWPRT == 1 )
4092 					DiskControllerByte |= FDC_STR_BIT_WPRT;		/* Force setting WPRT */
4093 				if ( ForceWPRT == -1 )
4094 					DiskControllerByte &= ~FDC_STR_BIT_WPRT;	/* Force clearing WPRT */
4095 
4096 				if ( ForceWPRT != 0 )
4097 					LOG_TRACE(TRACE_FDC, "force wprt=%d VBL=%d drive=%d str=%x\n", ForceWPRT==1?1:0, nVBLs, FDC.DriveSelSignal, DiskControllerByte );
4098 			}
4099 		}
4100 	}
4101 
4102 
4103 	/* Store the byte that was just returned by this read if we accessed fdc/hdc regs */
4104 	if ( ( FDC_DMA.Mode & 0x10 ) == 0 )				/* Bit 4 */
4105 		FDC_DMA.ff8604_recent_val = ( FDC_DMA.ff8604_recent_val & 0xff00 ) | ( DiskControllerByte & 0xff );
4106 
4107 	IoMem_WriteWord(0xff8604, DiskControllerByte);
4108 
4109 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
4110 
4111 	LOG_TRACE(TRACE_FDC, "fdc read 8604 ctrl status=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
4112 		DiskControllerByte , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
4113 }
4114 
4115 
4116 /*-----------------------------------------------------------------------*/
4117 /**
4118  * Write word to $ff8606 (DMA Mode Control)
4119  *
4120  * Eg.
4121  * $80 - Selects command/status register
4122  * $82 - Selects track register
4123  * $84 - Selects sector register
4124  * $86 - Selects data register
4125  * NOTE - OR above values with $100 is transfer from memory to floppy
4126  * Also if bit 4 is set, write to DMA sector count register
4127  *
4128  * NOTE [NP] : add 4 cycles wait state in that case
4129  */
FDC_DmaModeControl_WriteWord(void)4130 void FDC_DmaModeControl_WriteWord ( void )
4131 {
4132 	Uint16 Mode_prev;						/* Store previous write to 0xff8606 for 'toggle' checks */
4133 	int FrameCycles, HblCounterVideo, LineCycles;
4134 
4135 
4136 	if (nIoMemAccessSize == SIZE_BYTE)
4137 	{
4138 		/* This register does not like to be accessed in byte mode on a normal ST */
4139 		M68000_BusError(IoAccessFullAddress, BUS_ERROR_WRITE, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
4140 		return;
4141 	}
4142 
4143 	M68000_WaitState(4);
4144 
4145 	Mode_prev = FDC_DMA.Mode;					/* Store previous to check for _read/_write toggle (DMA reset) */
4146 	FDC_DMA.Mode = IoMem_ReadWord(0xff8606);			/* Store to DMA Mode control */
4147 
4148 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
4149 
4150 	LOG_TRACE(TRACE_FDC, "fdc write 8606 ctrl=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
4151 		FDC_DMA.Mode , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
4152 
4153 	/* When write to 0xff8606, check bit '8' toggle. This causes DMA status reset */
4154 	if ((Mode_prev ^ FDC_DMA.Mode) & 0x0100)
4155 		FDC_ResetDMA();
4156 
4157 	if ((Mode_prev & 0xc0) != 0 && (FDC_DMA.Mode & 0xc0) == 0)
4158 		HDC_DmaTransfer();
4159 }
4160 
4161 
4162 /*-----------------------------------------------------------------------*/
4163 /**
4164  * Read DMA Status at $ff8606
4165  *
4166  * Only bits 0-2 are used :
4167  *   Bit 0 - Error Status (0=Error)
4168  *   Bit 1 - Sector Count Zero Status (0=Sector Count Zero)
4169  *   Bit 2 - Data Request signal from the FDC
4170  *
4171  * NOTE [NP] : as verified on STF, bit 0 will be cleared (=error) if DMA sector count is 0
4172  * when we get some DRQ to process.
4173  *
4174  * NOTE [NP] : on the ST, the Data Register will always be read by the DMA when the FDC's DRQ
4175  * signal is set. This means bit 2 of DMA status will be '0' nearly all the time
4176  * (as verified on STF by constantly reading DMA Status, bit 2 can be '1' during
4177  * a few cycles, before the DMA read the Data Register, but for the emulation we
4178  * consider it's always '0')
4179  *
4180  * NOTE [NP] : unused bits 3-15 are the ones from the latest $ff8604 access (verified on real STF)
4181  *
4182  * NOTE [NP] : no 4 cycles wait state in that case
4183  */
FDC_DmaStatus_ReadWord(void)4184 void FDC_DmaStatus_ReadWord ( void )
4185 {
4186 	if (nIoMemAccessSize == SIZE_BYTE && !Config_IsMachineFalcon())
4187 	{
4188 		/* This register does not like to be accessed in byte mode on a normal ST */
4189 		M68000_BusError(IoAccessFullAddress, BUS_ERROR_READ, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
4190 		return;
4191 	}
4192 
4193 	/* Update Bit1 for zero sector count */
4194 	if ( FDC_DMA.SectorCount != 0 )
4195 		FDC_DMA.Status |= 0x02;
4196 	else
4197 		FDC_DMA.Status &= ~0x02;
4198 
4199 	/* In the case of the ST, Bit2 / DRQ is always 0 because it's handled by the DMA and its 16 bytes buffer */
4200 
4201 	/* Return Status with unused bits replaced by latest bits from $ff8604 */
4202 	IoMem_WriteWord( 0xff8606 , FDC_DMA.Status | ( FDC_DMA.ff8604_recent_val & 0xfff8 ) );
4203 }
4204 
4205 
4206 /*-----------------------------------------------------------------------*/
4207 /**
4208  * Read hi/med/low DMA address byte at $ff8609/0b/0d
4209  */
FDC_DmaAddress_ReadByte(void)4210 void	FDC_DmaAddress_ReadByte ( void )
4211 {
4212 	int FrameCycles, HblCounterVideo, LineCycles;
4213 
4214 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
4215 
4216 	LOG_TRACE(TRACE_FDC, "fdc read dma address %x val=0x%02x address=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
4217 		IoAccessCurrentAddress , IoMem[ IoAccessCurrentAddress ] , FDC_GetDMAAddress() ,
4218 		nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
4219 }
4220 
4221 
4222 /*-----------------------------------------------------------------------*/
4223 /**
4224  * Write hi/med/low DMA address byte at $ff8609/0b/0d
4225  *
4226  * NOTE [NP] : as described by Ijor in http://atari-forum.com/viewtopic.php?f=16&t=30289
4227  * the STF DMA address counter uses a ripple carry adder that will increment middle byte
4228  * when bit 7 of lower byte goes from 1 to 0 (same for middle/high bytes)
4229  * To avoid possible error with this carry, DMA address bytes should be written in the order
4230  * low, middle, high (as specified by Atari documentations) and not high/middle/low
4231  */
FDC_DmaAddress_WriteByte(void)4232 void	FDC_DmaAddress_WriteByte ( void )
4233 {
4234 	Uint32 Address;
4235 	Uint32 Address_old;
4236 	int FrameCycles, HblCounterVideo, LineCycles;
4237 
4238 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
4239 
4240 	LOG_TRACE(TRACE_FDC, "fdc write dma address %x val=0x%02x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
4241 		IoAccessCurrentAddress , IoMem[ IoAccessCurrentAddress ] ,
4242 		nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
4243 
4244 	/* Build up 24-bit address from hardware registers */
4245 	Address = ((Uint32)STMemory_ReadByte(0xff8609)<<16) | ((Uint32)STMemory_ReadByte(0xff860b)<<8) | (Uint32)STMemory_ReadByte(0xff860d);
4246 
4247 	/* On STF, DMA address uses a "ripple carry adder" which can trigger when writing to $ff860b/0d */
4248 	if ( Config_IsMachineST() )
4249 	{
4250 		Address_old = FDC_GetDMAAddress();
4251 
4252 		if ( ( Address_old & 0x80 ) && !( Address & 0x80 ) )		/* Bit 7 goes from 1 to 0 */
4253 		{
4254 			Address += 0x100;					/* Increase middle byte (and high byte if needed) */
4255 //fprintf ( stderr , "fdc write dma address detect ripple carry at $ff860d old=0x%x new=0x%x\n" , Address_old , Address );
4256 			LOG_TRACE(TRACE_FDC, "fdc write dma address detect ripple carry at $ff860d old=0x%x new=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
4257 				Address_old , Address ,
4258 				nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
4259 		}
4260 		else if ( ( Address_old & 0x8000 ) && !( Address & 0x8000 ) )	/* Bit 15 goes from 1 to 0 */
4261 		{
4262 			Address += 0x10000;					/* Increase high byte */
4263 //fprintf ( stderr , "fdc write dma address detect ripple carry at $ff860b old=0x%x new=0x%x\n" , Address_old , Address );
4264 			LOG_TRACE(TRACE_FDC, "fdc write dma address detect ripple carry at $ff860b old=0x%x new=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
4265 				Address_old , Address ,
4266 				nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
4267 		}
4268 	}
4269 
4270 	/* Store new address as DMA address and update $ff8609/0b/0d */
4271 	FDC_WriteDMAAddress ( Address );
4272 }
4273 
4274 
4275 /*-----------------------------------------------------------------------*/
4276 /**
4277  * Get DMA address used to transfer data between FDC/HDC and RAM
4278  */
FDC_GetDMAAddress(void)4279 Uint32 FDC_GetDMAAddress(void)
4280 {
4281 	return FDC_DMA_Address;
4282 }
4283 
4284 
4285 /*-----------------------------------------------------------------------*/
4286 /**
4287  * Write a new address to the FDC/HDC DMA address registers at $ff8909/0b/0d
4288  * As verified on real STF, DMA address high byte written at $ff8609 is masked
4289  * with 0x3f :
4290  *	move.b #$ff,$ff8609
4291  *	move.b $ff8609,d0  -> d0=$3f
4292  * DMA address must also be word-aligned, low byte at $ff860d is masked with 0xfe
4293  *	move.b #$ff,$ff860d
4294  *	move.b $ff860d,d0  -> d0=$fe
4295  */
FDC_WriteDMAAddress(Uint32 Address)4296 void FDC_WriteDMAAddress ( Uint32 Address )
4297 {
4298 	int FrameCycles, HblCounterVideo, LineCycles;
4299 	Uint32 dma_mask;
4300 
4301 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
4302 
4303 	LOG_TRACE(TRACE_FDC, "fdc write dma address new=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
4304 		Address , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
4305 
4306 	/* Mask DMA address : */
4307 	/*  - DMA address must be word-aligned, bit 0 at $ff860d is always 0 */
4308 	/*  - On STF/STE machines limited to 4MB of RAM, DMA address is also limited to $3fffff */
4309 	dma_mask = 0xff00fffe | ( DMA_MaskAddressHigh() << 16 );		/* Force bit 0 to 0 */
4310 	FDC_DMA_Address = Address & dma_mask;
4311 
4312 	/* Store as 24-bit address */
4313 	STMemory_WriteByte(0xff8609, FDC_DMA_Address>>16);
4314 	STMemory_WriteByte(0xff860b, FDC_DMA_Address>>8);
4315 	STMemory_WriteByte(0xff860d, FDC_DMA_Address);
4316 }
4317 
4318 
4319 /*-----------------------------------------------------------------------*/
4320 /**
4321  * Return the number of FDC cycles to wait before reaching the next
4322  * sector's ID Field in the track ($A1 $A1 $A1 $FE TR SIDE SR LEN CRC1 CRC2)
4323  * If no ID Field is found before the end of the track, we use the 1st
4324  * ID Field of the track (which simulates a full spin of the floppy).
4325  * We also store the next sector's number into NextSector_ID_Field_SR,
4326  * the next track's number into NextSector_ID_Field_TR, the next sector's length
4327  * into NextSector_ID_Field_LEN and if the CRC is correct or not into
4328  * NextSector_ID_Field_CRC_OK.
4329  * This function assumes some 512 byte sectors stored in ascending
4330  * order (for ST/MSA)
4331  * If there's no available drive/floppy, we return -1
4332  */
FDC_NextSectorID_FdcCycles_ST(Uint8 Drive,Uint8 NumberOfHeads,Uint8 Track,Uint8 Side)4333 static int	FDC_NextSectorID_FdcCycles_ST ( Uint8 Drive , Uint8 NumberOfHeads , Uint8 Track , Uint8 Side )
4334 {
4335 	int	CurrentPos;
4336 	int	MaxSector;
4337 	int	TrackPos;
4338 	int	i;
4339 	int	NextSector;
4340 	int	NbBytes;
4341 
4342 	CurrentPos = FDC_IndexPulse_GetCurrentPos_NbBytes ();
4343 	if ( CurrentPos < 0 )						/* No drive/floppy available at the moment */
4344 		return -1;
4345 
4346 	if ( ( Side == 1 ) && ( NumberOfHeads == 1 ) )			/* Can't read side 1 on a single sided drive */
4347 		return -1;
4348 
4349 	if ( Track >= FDC_GetTracksPerDisk ( Drive ) )			/* Try to access a non existing track */
4350 		return -1;
4351 
4352 	MaxSector = FDC_GetSectorsPerTrack ( Drive , Track , Side );
4353 	TrackPos = FDC_TRACK_LAYOUT_STANDARD_GAP1;			/* Position of 1st raw sector */
4354 	TrackPos += FDC_TRACK_LAYOUT_STANDARD_GAP2;			/* Position of ID Field in 1st raw sector */
4355 
4356 	/* Compare CurrentPos with each sector's position in ascending order */
4357 	for ( i=0 ; i<MaxSector ; i++ )
4358 	{
4359 		if ( CurrentPos < TrackPos )
4360 			break;						/* We found the next sector */
4361 		else
4362 			TrackPos += FDC_TRACK_LAYOUT_STANDARD_RAW_SECTOR_512;
4363 	}
4364 
4365 	if ( i == MaxSector )						/* CurrentPos is after the last ID Field of this track */
4366 	{
4367 		/* Reach end of track (new index pulse), then go to sector 1 */
4368 		NbBytes = FDC_GetBytesPerTrack ( Drive ) - CurrentPos + FDC_TRACK_LAYOUT_STANDARD_GAP1 + FDC_TRACK_LAYOUT_STANDARD_GAP2;
4369 		NextSector = 1;
4370 	}
4371 	else								/* There's an ID Field before end of track */
4372 	{
4373 		NbBytes = TrackPos - CurrentPos;
4374 		NextSector = i+1;
4375 	}
4376 
4377 //fprintf ( stderr , "fdc bytes next sector pos=%d trpos=%d nbbytes=%d maxsr=%d nextsr=%d\n" , CurrentPos, TrackPos, NbBytes, MaxSector, NextSector );
4378 	FDC.NextSector_ID_Field_TR = Track;
4379 	FDC.NextSector_ID_Field_SR = NextSector;
4380 	FDC.NextSector_ID_Field_LEN = FDC_SECTOR_SIZE_512;		/* ST/MSA have 512 bytes per sector */
4381 	FDC.NextSector_ID_Field_CRC_OK = 1;				/* CRC is always correct for ST/MSA */
4382 
4383 	return FDC_TransferByte_FdcCycles ( NbBytes );
4384 }
4385 
4386 
4387 /*-----------------------------------------------------------------------*/
4388 /**
4389  * Return the value of the track number in the next ID field set by
4390  * FDC_NextSectorID_FdcCycles_ST (for ST/MSA, it's always HeadTrack value)
4391  */
FDC_NextSectorID_TR_ST(void)4392 static Uint8	FDC_NextSectorID_TR_ST ( void )
4393 {
4394 	return FDC.NextSector_ID_Field_TR;
4395 }
4396 
4397 
4398 /*-----------------------------------------------------------------------*/
4399 /**
4400  * Return the value of the sector number in the next ID field set by
4401  * FDC_NextSectorID_FdcCycles_ST.
4402  */
FDC_NextSectorID_SR_ST(void)4403 static Uint8	FDC_NextSectorID_SR_ST ( void )
4404 {
4405 	return FDC.NextSector_ID_Field_SR;
4406 }
4407 
4408 
4409 /*-----------------------------------------------------------------------*/
4410 /**
4411  * Return the value of the sector's length in the next ID field set by
4412  * FDC_NextSectorID_FdcCycles_ST.
4413  * For ST/MSA, it's always 2 (512 bytes per sector)
4414  */
FDC_NextSectorID_LEN_ST(void)4415 static Uint8	FDC_NextSectorID_LEN_ST ( void )
4416 {
4417 	return FDC.NextSector_ID_Field_LEN;
4418 }
4419 
4420 
4421 /*-----------------------------------------------------------------------*/
4422 /**
4423  * Return the status of the CRC in the next ID field set by
4424  * FDC_NextSectorID_FdcCycles_ST.
4425  * If '0', CRC is bad, else CRC is OK
4426  * For ST/MSA, CRC is always OK
4427  */
FDC_NextSectorID_CRC_OK_ST(void)4428 static Uint8	FDC_NextSectorID_CRC_OK_ST ( void )
4429 {
4430 	return FDC.NextSector_ID_Field_CRC_OK;
4431 }
4432 
4433 
4434 /*-----------------------------------------------------------------------*/
4435 /**
4436  * Read a sector from a floppy image in ST format (used in type II command)
4437  * Each byte of the sector is added to the FDC buffer with a default timing
4438  * (32 microsec)
4439  * Return 0 if sector was read without error, or FDC_STR_BIT_RNF if an error occurred
4440  * (FDC_STR_BIT_CRC_ERROR and FDC_STR_BIT_RECORD_TYPE are always set 0 for ST/MSA)
4441  */
FDC_ReadSector_ST(Uint8 Drive,Uint8 Track,Uint8 Sector,Uint8 Side,int * pSectorSize)4442 static Uint8 FDC_ReadSector_ST ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side , int *pSectorSize )
4443 {
4444 	int	FrameCycles, HblCounterVideo, LineCycles;
4445 	int	i;
4446 	Uint8	*pSectorData;
4447 
4448 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
4449 
4450 	LOG_TRACE(TRACE_FDC, "fdc read sector addr=0x%x drive=%d track=%d sect=%d side=%d VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
4451 		FDC_GetDMAAddress(), Drive, Track, Sector, Side,
4452 		nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
4453 
4454 	/* Get a pointer to the sector's data and convert into bytes/timings */
4455 	if ( Floppy_ReadSectors ( Drive, &pSectorData, Sector, Track, Side, 1, NULL, pSectorSize ) )
4456 	{
4457 		for ( i=0 ; i<*pSectorSize ; i++ )
4458 			FDC_Buffer_Add ( pSectorData[ i ] );
4459 		return 0;						/* No error */
4460 	}
4461 
4462 	/* Failed */
4463 	LOG_TRACE(TRACE_FDC, "fdc read sector failed\n" );
4464 	return FDC_STR_BIT_RNF;
4465 }
4466 
4467 
4468 /*-----------------------------------------------------------------------*/
4469 /**
4470  * Write a sector to a floppy image in ST format (used in type II command)
4471  * Bytes were added to the FDC Buffer with a default timing (32 microsec) ;
4472  * we copy only the bytes into a temporary buffer, and write this buffer
4473  * to the floppy image.
4474  * If DMASectorsCount==0, the DMA won't transfer any byte from RAM to the FDC
4475  * and some '0' bytes will be written to the disk.
4476  * Return 0 if sector was written without error, or FDC_STR_BIT_RNF if an error occurred
4477  */
FDC_WriteSector_ST(Uint8 Drive,Uint8 Track,Uint8 Sector,Uint8 Side,int SectorSize)4478 static Uint8 FDC_WriteSector_ST ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side , int SectorSize )
4479 {
4480 	int	FrameCycles, HblCounterVideo, LineCycles;
4481 	int	i;
4482 	Uint8	SectorData[ 1024 ];					/* max sector size for WD1772 */
4483 
4484 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
4485 
4486 	LOG_TRACE(TRACE_FDC, "fdc write sector addr=0x%x drive=%d track=%d sect=%d side=%d VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
4487 		FDC_GetDMAAddress(), Drive, Track, Sector, Side,
4488 		nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
4489 
4490 	/* Get the sector's data (ignore timings) */
4491 	for ( i=0 ; i<SectorSize ; i++ )
4492 		SectorData[ i ] = FDC_Buffer_Read_Byte_pos ( i );
4493 
4494 	/* Write the sector's data */
4495 	if ( Floppy_WriteSectors ( Drive, SectorData, Sector, Track, Side, 1, NULL, NULL ) )
4496 		return 0;						/* No error */
4497 
4498 	/* Failed */
4499 	LOG_TRACE(TRACE_FDC, "fdc write sector failed\n" );
4500 	return FDC_STR_BIT_RNF;
4501 }
4502 
4503 
4504 /*-----------------------------------------------------------------------*/
4505 /**
4506  * Read an address field from a floppy image in ST format (used in type III command)
4507  * As ST images don't have address field, we compute a standard one based
4508  * on the current track/sector/side.
4509  * Each byte of the ID field is added to the FDC buffer with a default timing
4510  * (32 microsec)
4511  * Always return 0 = OK (FDC_STR_BIT_CRC_ERROR and FDC_STR_BIT_RNF are
4512  * always set 0 for ST/MSA)
4513  */
FDC_ReadAddress_ST(Uint8 Drive,Uint8 Track,Uint8 Sector,Uint8 Side)4514 static Uint8 FDC_ReadAddress_ST ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side )
4515 {
4516 	int	FrameCycles, HblCounterVideo, LineCycles;
4517 	Uint8	buf_id[ 10 ];						/* 3 SYNC + IAM + TR + SIDE + SECTOR + SIZE + CRC1 + CRC2 */
4518 	Uint8	*p;
4519 	Uint16	CRC;
4520 	int	i;
4521 
4522 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
4523 
4524 	/* If trying to access address field on a non existing track, then return RNF */
4525 	if ( Track >= FDC_GetTracksPerDisk ( Drive ) )
4526 	{
4527 		fprintf ( stderr , "fdc : read address drive=%d track=%d side=%d, but maxtrack=%d, return RNF\n" ,
4528 			Drive , Track , Side , FDC_GetTracksPerDisk ( Drive ) );
4529 		return STX_SECTOR_FLAG_RNF;				/* Should not happen if FDC_NextSectorID_FdcCycles_ST succeeded before */
4530 	}
4531 
4532 	p = buf_id;
4533 
4534 	*p++ = 0xa1;							/* SYNC bytes and IAM byte are included in the CRC */
4535 	*p++ = 0xa1;
4536 	*p++ = 0xa1;
4537 	*p++ = 0xfe;
4538 	*p++ = Track;
4539 	*p++ = Side;
4540 	*p++ = Sector;
4541 	*p++ = FDC_SECTOR_SIZE_512;					/* ST/MSA images are 512 bytes per sector */
4542 
4543 	FDC_CRC16 ( buf_id , 8 , &CRC );
4544 
4545 	*p++ = CRC >> 8;
4546 	*p++ = CRC & 0xff;
4547 
4548 	/* 6 bytes per ID field,  don't return the 3 x $A1 and $FE */
4549 	for ( i=4 ; i<10 ; i++ )
4550 		FDC_Buffer_Add ( buf_id[ i ] );
4551 
4552 	LOG_TRACE(TRACE_FDC, "fdc read address 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x VBL=%d video_cyc=%d %d@%d pc=%x\n",
4553 		buf_id[4] , buf_id[5] , buf_id[6] , buf_id[7] , buf_id[8] , buf_id[9] ,
4554 		nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
4555 
4556 	return 0;							/* No error */
4557 }
4558 
4559 
4560 /*-----------------------------------------------------------------------*/
4561 /**
4562  * Read a track from a floppy image in ST format (used in type III command)
4563  * As ST images don't have gaps,sync,..., we compute a standard track based
4564  * on the current track/side.
4565  * Each byte of the track is added to the FDC buffer with a default timing
4566  * (32 microsec)
4567  * Always return 0 = OK (we fill the track buffer in all cases)
4568  */
FDC_ReadTrack_ST(Uint8 Drive,Uint8 Track,Uint8 Side)4569 static Uint8 FDC_ReadTrack_ST ( Uint8 Drive , Uint8 Track , Uint8 Side )
4570 {
4571 	int	FrameCycles, HblCounterVideo, LineCycles;
4572 	Uint8	buf_id[ 10 ];						/* 3 SYNC + IAM + TR + SIDE + SECTOR + SIZE + CRC1 + CRC2 */
4573 	Uint8	*p;
4574 	Uint16	CRC;
4575 	int	Sector;
4576 	Uint8	*pSectorData;
4577 	int	SectorSize;
4578 	int	i;
4579 
4580 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
4581 
4582 	LOG_TRACE(TRACE_FDC, "fdc type III read track drive=%d track=%d side=%d VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
4583 		Drive, Track, Side, nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
4584 
4585 	/* If trying to access a non existing track, then return an empty / not formatted track */
4586 	if ( Track >= FDC_GetTracksPerDisk ( Drive ) )
4587 	{
4588 		fprintf ( stderr , "fdc : read track drive=%d track=%d side=%d, but maxtrack=%d, building an unformatted track\n" ,
4589 			Drive , Track , Side , FDC_GetTracksPerDisk ( Drive ) );
4590 		for ( i=0 ; i<FDC_GetBytesPerTrack ( Drive ) ; i++ )
4591 			FDC_Buffer_Add ( rand() & 0xff );		/* Fill the track buffer with random bytes */
4592 		return 0;
4593 	}
4594 
4595 	for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP1 ; i++ )		/* GAP1 */
4596 		FDC_Buffer_Add ( 0x4e );
4597 
4598 	for ( Sector=1 ; Sector <= FDC_GetSectorsPerTrack ( Drive , Track , Side ) ; Sector++ )
4599 	{
4600 		for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP2 ; i++ )	/* GAP2 */
4601 			FDC_Buffer_Add ( 0x00 );
4602 
4603 		/* Add the ID field for the sector */
4604 		p = buf_id;
4605 		for ( i=0 ; i<3 ; i++ )		*p++ = 0xa1;		/* SYNC (write $F5) */
4606 		*p++ = 0xfe;						/* Index Address Mark */
4607 		*p++ = Track;						/* Track */
4608 		*p++ = Side;						/* Side */
4609 		*p++ = Sector;						/* Sector */
4610 		*p++ = FDC_SECTOR_SIZE_512;				/* 512 bytes/sector for ST/MSA */
4611 		FDC_CRC16 ( buf_id , 8 , &CRC );
4612 		*p++ = CRC >> 8;					/* CRC1 (write $F7) */
4613 		*p++ = CRC & 0xff;					/* CRC2 */
4614 
4615 		for ( i=0 ; i<10 ; i++ )				/* Add the ID field to the track data */
4616 			FDC_Buffer_Add ( buf_id[ i ] );
4617 
4618 		for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP3a ; i++ )	/* GAP3a */
4619 			FDC_Buffer_Add ( 0x4e );
4620 		for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP3b ; i++ )	/* GAP3b */
4621 			FDC_Buffer_Add ( 0x00 );
4622 
4623 		/* Add the data for the sector + build the CRC */
4624 		crc16_reset ( &CRC );
4625 		for ( i=0 ; i<3 ; i++ )
4626 		{
4627 			FDC_Buffer_Add ( 0xa1 );			/* SYNC (write $F5) */
4628 			crc16_add_byte ( &CRC , 0xa1 );
4629 		}
4630 
4631 		FDC_Buffer_Add ( 0xfb );				/* Data Address Mark */
4632 		crc16_add_byte ( &CRC , 0xfb );
4633 
4634 		if ( Floppy_ReadSectors ( Drive, &pSectorData, Sector, Track, Side, 1, NULL, &SectorSize ) )
4635 		{
4636 			for ( i=0 ; i<SectorSize ; i++ )
4637 			{
4638 				FDC_Buffer_Add ( pSectorData[ i ] );
4639 				crc16_add_byte ( &CRC , pSectorData[ i ] );
4640 			}
4641 		}
4642 		else
4643 		{
4644 			/* In case of error, we put some 0x00 bytes, but this case should */
4645 			/* not happen with ST/MSA disk images, all sectors should be present on each track */
4646 			for ( i=0 ; i<512 ; i++ )
4647 			{
4648 				FDC_Buffer_Add ( 0x00 );
4649 				crc16_add_byte ( &CRC , 0x00 );
4650 			}
4651 		}
4652 
4653 		FDC_Buffer_Add ( CRC >> 8 );				/* CRC1 (write $F7) */
4654 		FDC_Buffer_Add ( CRC & 0xff );				/* CRC2 */
4655 
4656 		for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP4 ; i++ )	/* GAP4 */
4657 			FDC_Buffer_Add ( 0x4e );
4658 	}
4659 
4660 	while ( FDC_Buffer_Get_Size () < FDC_GetBytesPerTrack ( Drive ) )	/* Complete the track buffer */
4661 	      FDC_Buffer_Add ( 0x4e );					/* GAP5 */
4662 
4663 	return 0;							/* No error */
4664 }
4665 
4666 
4667 /*-----------------------------------------------------------------------*/
4668 /**
4669  * Write a track to a floppy image in ST format (used in type III command)
4670  * Bytes were added to the FDC Buffer with a default timing (32 microsec) ;
4671  * we copy only the bytes into a temporary buffer, and write this buffer
4672  * to the floppy image.
4673  * If DMASectorsCount==0, the DMA won't transfer any byte from RAM to the FDC
4674  * and some '0' bytes will be written to the disk.
4675  * Return 0 if track was written without error, or FDC_STR_BIT_LOST_DATA if an error occurred
4676  *
4677  * TODO : this is not supported for ST/MSA at the moment, so we return FDC_STR_BIT_LOST_DATA
4678  */
FDC_WriteTrack_ST(Uint8 Drive,Uint8 Track,Uint8 Side,int TrackSize)4679 static Uint8 FDC_WriteTrack_ST ( Uint8 Drive , Uint8 Track , Uint8 Side , int TrackSize )
4680 {
4681 	int	FrameCycles, HblCounterVideo, LineCycles;
4682 
4683 	Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
4684 
4685 	LOG_TRACE(TRACE_FDC, "fdc write track not supported addr=0x%x drive=%d track=%d side=%d VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
4686 		FDC_GetDMAAddress(), Drive, Track, Side,
4687 		nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
4688 
4689 	Log_Printf(LOG_TODO, "FDC type III command 'write track' is not supported with ST/MSA files\n");
4690 
4691 	/* TODO : "Write track" should write all the sectors after extracting them from the track data ? */
4692 
4693 	/* Failed */
4694 	LOG_TRACE(TRACE_FDC, "fdc write track failed\n" );
4695 	return FDC_STR_BIT_LOST_DATA;
4696 }
4697 
4698 
4699 /*-----------------------------------------------------------------------*/
4700 /**
4701  * Write to floppy mode/control (?) register (0xff860F).
4702  * Used on Falcon only!
4703  * FIXME: I've found hardly any documentation about this register, only
4704  * the following description of the bits:
4705  *
4706  *   __________54__10  Floppy Controll-Register
4707  *             ||  ||
4708  *             ||  |+- Prescaler 1
4709  *             ||  +-- Media detect 1
4710  *             |+----- Prescaler 2
4711  *             +------ Media detect 2
4712  *
4713  * For DD - disks:  0x00
4714  * For HD - disks:  0x03
4715  * for ED - disks:  0x30 (not supported by TOS)
4716  */
FDC_FloppyMode_WriteByte(void)4717 void FDC_FloppyMode_WriteByte ( void )
4718 {
4719 	// printf("Write to floppy mode reg.: 0x%02x\n", IoMem_ReadByte(0xff860f));
4720 }
4721 
4722 
4723 /*-----------------------------------------------------------------------*/
4724 /**
4725  * Read from floppy mode/control (?) register (0xff860F).
4726  * Used on Falcon only!
4727  * FIXME: I've found hardly any documentation about this register, only
4728  * the following description of the bits:
4729  *
4730  *   ________76543210  Floppy Controll-Register
4731  *           ||||||||
4732  *           |||||||+- Prescaler 1
4733  *           ||||||+-- Mode select 1
4734  *           |||||+--- Media detect 1
4735  *           ||||+---- accessed during DMA transfers (?)
4736  *           |||+----- Prescaler 2
4737  *           ||+------ Mode select 2
4738  *           |+------- Media detect 2
4739  *           +-------- Disk changed
4740  */
FDC_FloppyMode_ReadByte(void)4741 void FDC_FloppyMode_ReadByte ( void )
4742 {
4743 	IoMem_WriteByte(0xff860f, 0x80);  // FIXME: Is this ok?
4744 	// printf("Read from floppy mode reg.: 0x%02x\n", IoMem_ReadByte(0xff860f));
4745 }
4746