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