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