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