|
|
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:
20: #include "main.h"
1.1.1.4 root 21: #include "configuration.h"
1.1 root 22: #include "fdc.h"
1.1.1.3 root 23: #include "hdc.h"
1.1 root 24: #include "floppy.h"
1.1.1.6 root 25: #include "ioMem.h"
26: #include "log.h"
1.1 root 27: #include "m68000.h"
28: #include "memorySnapShot.h"
29: #include "mfp.h"
30: #include "psg.h"
31: #include "stMemory.h"
1.1.1.14 root 32: #include "screen.h"
1.1.1.10 root 33: #include "video.h"
1.1.1.15 root 34: #include "clocks_timings.h"
35: #include "utils.h"
1.1.1.17! root 36: #include "statusbar.h"
1.1 root 37:
1.1.1.3 root 38:
1.1 root 39: /*
1.1.1.7 root 40: Floppy Disk Controller
1.1 root 41:
42: Programmable Sound Generator (YM-2149)
43:
44: 0xff8800(even byte) - PSG Register Data (Read, used for parallel port)
45: - PSG Register Select (Write)
46:
47: Write to bits 0-3 to select PSG register to use(then write data to 0xfff8802)
48: Value Register
49:
50: 0000 Channel A Fine Tune
51: 0001 Channel A Coarse Tune
52: 0010 Channel B Fine Tune
53: 0011 Channel B Coarse Tune
54: 0100 Channel C Fine Tune
55: 0101 Channel C Coarse Tune
56: 0110 Noise Generator Control
57: 0111 Mixer Control - I/O enable
58: 1000 Channel A Amplitude
59: 1001 Channel B Amplitude
60: 1010 Channel C Amplitude
61: 1011 Envelope Period Fine Tune
62: 1100 Envelope Peroid Coarse Tune
63: 1101 Envelope Shape
64: 1110 I/O Port A Select (Write only)
65: 1111 I/O Port B Select
66:
67: 0xfff8802(even byte) - Bits according to 0xff8800 Register select
1.1.1.4 root 68:
1.1 root 69: 1110(Register 14) - I/O Port A
70: Bit 0 - Floppy side 0/1
71: Bit 1 - Floppy drive 0 select
72: Bit 2 - Floppy drive 1 select
73: Bit 3 - RS232 Ready to send (RTS)
74: Bit 4 - RS232 Data Terminal Ready (DTR)
75: Bit 5 - Centronics Strobe
76: Bit 6 - General Purpose Output
77: Bit 7 - Reserved
78:
1.1.1.7 root 79: ACSI DMA and Floppy Disk Controller(FDC)
1.1 root 80: 0xff8604 - information from file '1772.info.txt, by David Gahris' (register r0)
1.1.1.15 root 81: Word access only, but only lower byte (ff8605) is used
1.1 root 82: (write) - Disk controller
1.1.1.15 root 83: Set DMA sector count if ff8606 bit 4 == 1
84: Set FDC's internal registers depending on bit 1/2 of ff8606 if bit 4 == 0
1.1 root 85: (read) - Disk controller status
86: Bit 0 - Busy. This bit is 1 when the 177x is busy. This bit is 0 when the 177x is free for CPU commands.
87: Bit 1 - Index / Data Request. On Type I commands, this bit is high during the index pulse that occurs once
88: per disk rotation. This bit is low at all times other than the index pulse. For Type II and III commands,
89: Bit 1 high signals the CPU to handle the data register in order to maintain a continuous flow of data.
90: Bit 1 is high when the data register is full during a read or when the data register is empty during a write.
91: "Worst case service time" for Data Request is 23.5 cycles.
92: Bit 2 - Track Zero / Lost Data. After Type I commands, this bit is 0 if the mechanism is at track zero.
93: This bit is 1 if the head is not at track zero. After Type II or III commands, this bit is 1 if the
94: CPU did not respond to Data Request (Status bit 1) in time for the 177x to maintain a continuous data flow.
95: This bit is 0 if the CPU responded promptly to Data Request.
1.1.1.15 root 96: NOTE : on ST, Lost Data is never set because the DMA always handles the data request signal.
1.1 root 97: Bit 3 - CRC Error. This bit is high if a sector CRC on disk does not match the CRC which the 177x
98: computed from the data. The CRC polynomial is x^16+x^12+x^5+1. If the stored CRC matches the newly
99: calculated CRC, the CRC Error bit is low. If this bit and the Record Not Found bit are set, the error
100: was in an ID field. If this bit is set but Record Not Found is clear, the error was in a data field.
101: Bit 4 - Record Not Found. This bit is set if the 177x cannot find the track, sector, or side which
102: the CPU requested. Otherwise, this bit is clear.
103: Bit 5 - Spin-up / Record Type. For Type I commands, this bit is low during the 6-revolution motor
104: spin-up time. This bit is high after spin-up. For Type II and Type III commands, Bit 5 low
105: indicates a normal data mark. Bit 5 high indicates a deleted data mark.
106: 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 107: After a type I command, this bit is constantly updated an give the current value of the WPT signal.
1.1 root 108: Bit 7 - Motor On. This bit is high when the drive motor is on, and low when the motor is off.
109:
110: 0xff8606 - DMA Status(read), DMA Mode Control(write) - NOTE bits 0,9-15 are not used
111: Bit 1 - FDC Pin A0 (See below)
112: Bit 2 - FDC Pin A1
113: Bit 3 - FDC/HDC Register Select
114: Bit 4 - FDC/Sector count select
115: Bit 5 - Reserved
116: Bit 6 - Enable/Disable DMA
117: Bit 7 - HDC/FDC
118: Bit 8 - Read/Write
119:
120: A1 A0 Read Write(bit 8==1)
121: 0 0 Status Command
122: 0 1 Track Register Track Register
123: 1 0 Sector Register Sector Register
124: 1 1 Data Register Data Register
125:
126:
1.1.1.6 root 127: According to the documentation INTRQ is generated at the completion of each
128: command (causes an interrupt in the MFP). INTRQ is reset by reading the status
129: register OR by loading a new command. So, does this mean the GPIP? Or does it
130: actually CANCEL the interrupt? Can this be done?
1.1.1.15 root 131:
132: NOTE [NP] : The DMA is connected to the FDC and its Data Register, each time a DRQ
133: is made by the FDC, it's handled by the DMA through its internal 16 bytes buffer.
134: This means that in the case of the Atari ST the LOST_DATA bit will never be set
135: in the Status Register (but data can be lost if FDC_DMA.SectorCount=0 as there
136: will be no transfer between DMA and RAM)
137:
138:
139: Detecting disk changes :
140: ------------------------
141: 3'1/2 floppy drives include a 'DSKCHG' signal on pin 34 to detect when a disk was changed.
142: Unfortunatelly on ST, this signal is not connected. Nevertheless, it's possible to detect
143: a disk was inserted or ejected by looking at the 'WPT' signal which tells if a disk is write
144: protected or not.
145: At the drive level, a light is emitted above the top left corner of the floppy :
146: - if the write protection hole on the floppy is opened, the light goes through and the disk
147: is considered to be write protected.
148: - if the write protection hole on the floppy is closed, the light can't go through and the
149: disk is write enabled.
150: The point is that when any "solid" part of the floppy obstructs the light signal, the WPT
1.1.1.17! root 151: signal will change immediately : it will be considered as if a write enabled disk was present.
1.1.1.15 root 152: So, when a floppy is ejected or inserted, the body of the floppy will briefly obstruct the light,
153: whatever the state of the protection hole could be.
154: Similarly, when there's no floppy inside the drive, the light signal can pass through, so it will
155: be considered as if a write protected disk was present.
156: So, let's call 'C' the state when protection hole is Closed (ie WPT = 0) and 'O' the state
157: when protection hole is Opened (ie WPT = 1). We have the following cases :
158: - floppy in drive : state can be C or O depending on the protection tab. Let's call it 'X'
159: - no floppy in drive : state is equivalent to O (because the light signal is not obstructed)
160: - ejecting a floppy : states will go from X to C and finally to O
161: - inserting a floppy : states will go from O to C and finally to X
162:
163: The TOS monitors the changes on the WPT signal to determine if a floppy was ejected or inserted.
164: On TOS 1.02fr, the code is located between $fc1bc4 and $fc1ebc. Every 8 VBL, one floppy drive is checked
165: to see if the WPT signal changed. When 1 drive is connected, this means a floppy change should keep the
166: WPT signal during at least 8 VBLs. When 2 drive are connected, each drive is checked every 16 VBLs, so
167: the WPT signal should be kept for at least 16 VBLs.
168:
169: During these transition phases between "ejected" and "inserted", we force the WPT signal to either 0 or 1,
170: depending on which transition we're emulating (see Floppy_DriveTransitionUpdateState()) :
171: - Ejecting : WPT will be X, then 0, then 1
172: - Inserting : WPT will be 1, then 0, then X
173:
1.1 root 174: */
175:
1.1.1.14 root 176: /*-----------------------------------------------------------------------*/
1.1.1.15 root 177:
178: #define FDC_STR_BIT_BUSY 0x01
179: #define FDC_STR_BIT_INDEX 0x02 /* type I */
180: #define FDC_STR_BIT_DRQ 0x02 /* type II and III */
181: #define FDC_STR_BIT_TR00 0x04 /* type I */
182: #define FDC_STR_BIT_LOST_DATA 0x04 /* type II and III */
183: #define FDC_STR_BIT_CRC_ERROR 0x08
184: #define FDC_STR_BIT_RNF 0x10
185: #define FDC_STR_BIT_SPIN_UP 0x20 /* type I */
186: #define FDC_STR_BIT_RECORD_TYPE 0x20 /* type II and III */
187: #define FDC_STR_BIT_WPRT 0x40
188: #define FDC_STR_BIT_MOTOR_ON 0x80
189:
190:
1.1.1.17! root 191: #define FDC_COMMAND_BIT_VERIFY (1<<2) /* 0=no verify after type I, 1=verify after type I */
1.1.1.15 root 192: #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 */
193: #define FDC_COMMAND_BIT_MOTOR_ON (1<<3) /* 0=enable motor test, 1=disable motor test */
194: #define FDC_COMMAND_BIT_UPDATE_TRACK (1<<4) /* 0=don't update TR after type I, 1=update TR after type I */
195: #define FDC_COMMAND_BIT_MULTIPLE_SECTOR (1<<4) /* 0=read/write only 1 sector, 1=read/write many sectors */
196:
197:
198:
199: /* FDC Emulation commands used in FDC.Command */
1.1.1.14 root 200: enum
201: {
202: FDCEMU_CMD_NULL = 0,
203: /* Type I */
204: FDCEMU_CMD_RESTORE,
205: FDCEMU_CMD_SEEK,
1.1.1.15 root 206: FDCEMU_CMD_STEP, /* Also used for STEP IN and STEP OUT */
1.1.1.14 root 207: /* Type II */
208: FDCEMU_CMD_READSECTORS,
209: FDCEMU_CMD_WRITESECTORS,
210: /* Type III */
211: FDCEMU_CMD_READADDRESS,
1.1.1.15 root 212: FDCEMU_CMD_READTRACK,
213: FDCEMU_CMD_WRITETRACK,
214:
215: /* Other fake commands used internally */
216: FDCEMU_CMD_MOTOR_STOP
1.1.1.14 root 217: };
218:
219:
1.1.1.15 root 220: /* FDC Emulation commands' sub-states used in FDC.CommandState */
1.1.1.14 root 221: enum
222: {
1.1.1.15 root 223: FDCEMU_RUN_NULL = 0,
1.1.1.14 root 224:
1.1.1.15 root 225: /* Restore */
226: FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO,
227: FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_LOOP,
1.1.1.17! root 228: FDCEMU_RUN_RESTORE_VERIFY,
! 229: FDCEMU_RUN_RESTORE_VERIFY_LOOP,
1.1.1.15 root 230: FDCEMU_RUN_RESTORE_COMPLETE,
231: /* Seek */
1.1.1.14 root 232: FDCEMU_RUN_SEEK_TOTRACK,
1.1.1.17! root 233: FDCEMU_RUN_SEEK_VERIFY,
! 234: FDCEMU_RUN_SEEK_VERIFY_LOOP,
1.1.1.15 root 235: FDCEMU_RUN_SEEK_COMPLETE,
236: /* Step / Step In / Step Out */
1.1.1.14 root 237: FDCEMU_RUN_STEP_ONCE,
1.1.1.17! root 238: FDCEMU_RUN_STEP_VERIFY,
! 239: FDCEMU_RUN_STEP_VERIFY_LOOP,
1.1.1.15 root 240: FDCEMU_RUN_STEP_COMPLETE,
241: /* Read Sector */
242: FDCEMU_RUN_READSECTORS_READDATA,
243: FDCEMU_RUN_READSECTORS_READDATA_CHECK_SECTOR_HEADER,
1.1.1.17! root 244: FDCEMU_RUN_READSECTORS_READDATA_TRANSFER_START,
! 245: FDCEMU_RUN_READSECTORS_READDATA_TRANSFER_LOOP,
! 246: FDCEMU_RUN_READSECTORS_CRC,
1.1.1.15 root 247: FDCEMU_RUN_READSECTORS_RNF,
248: FDCEMU_RUN_READSECTORS_COMPLETE,
249: /* Write Sector */
250: FDCEMU_RUN_WRITESECTORS_WRITEDATA,
251: FDCEMU_RUN_WRITESECTORS_WRITEDATA_CHECK_SECTOR_HEADER,
1.1.1.17! root 252: FDCEMU_RUN_WRITESECTORS_WRITEDATA_TRANSFER_START,
! 253: FDCEMU_RUN_WRITESECTORS_WRITEDATA_TRANSFER_LOOP,
! 254: FDCEMU_RUN_WRITESECTORS_CRC,
1.1.1.15 root 255: FDCEMU_RUN_WRITESECTORS_RNF,
256: FDCEMU_RUN_WRITESECTORS_COMPLETE,
257: /* Read Address */
258: FDCEMU_RUN_READADDRESS,
259: FDCEMU_RUN_READADDRESS_DMA,
260: FDCEMU_RUN_READADDRESS_COMPLETE,
261: /* Read Track */
262: FDCEMU_RUN_READTRACK,
1.1.1.17! root 263: FDCEMU_RUN_READTRACK_INDEX,
1.1.1.15 root 264: FDCEMU_RUN_READTRACK_DMA,
265: FDCEMU_RUN_READTRACK_COMPLETE,
266: /* Write Track */
267: FDCEMU_RUN_WRITETRACK,
1.1.1.17! root 268: FDCEMU_RUN_WRITETRACK_INDEX,
1.1.1.15 root 269: FDCEMU_RUN_WRITETRACK_DMA,
270: FDCEMU_RUN_WRITETRACK_COMPLETE
1.1.1.14 root 271: };
272:
273:
274:
1.1.1.15 root 275: /* Standard hardware values for the FDC. This should allow to get good timings estimation */
276: /* when dealing with non protected disks that require a correct speed (MSA or ST images) */
277: /* FIXME [NP] : Those timings could be improved by taking into account the time */
278: /* it takes to reach the track index/sector/address field before really reading it, but this level */
279: /* of accuracy is not necessary for ST/MSA disk images (it would be required to emulate protections */
280: /* in Pasti disk images) */
1.1.1.14 root 281:
1.1.1.15 root 282: #define FDC_BITRATE_STANDARD 250000 /* read/write speed of the WD1772 in bits per sec */
283: #define FDC_RPM_STANDARD 300 /* 300 RPM or 5 spins per sec */
284: #define FDC_TRACK_BYTES_STANDARD ( ( FDC_BITRATE_STANDARD / 8 ) / ( FDC_RPM_STANDARD / 60 ) ) /* 6250 bytes */
1.1.1.17! root 285: //#define FDC_TRACK_BYTES_STANDARD 6272
1.1.1.14 root 286:
1.1.1.15 root 287: #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 288:
1.1.1.15 root 289: /* Delays are in micro sec */
290: #define FDC_DELAY_MOTOR_ON ( 1000000.L * 6 / ( FDC_RPM_STANDARD / 60 ) ) /* 6 spins to reach correct speed */
291: #define FDC_DELAY_MOTOR_OFF ( 1000000.L * 9 / ( FDC_RPM_STANDARD / 60 ) ) /* Turn off motor 9 spins after the last command */
1.1.1.14 root 292:
1.1.1.17! root 293: #define FDC_DELAY_HEAD_LOAD ( 15 * 1000 ) /* Additionnal 15 ms delay to load the head in type II/III */
1.1.1.14 root 294:
1.1.1.15 root 295: #define FDC_DELAY_RNF ( 1000000.L * 5 / ( FDC_RPM_STANDARD / 60 ) ) /* 5 spins to set RNF */
1.1 root 296:
1.1.1.17! root 297: #define FDC_DELAY_INDEX_PULSE_LENGTH 1500 /* Index pulse signal remain high during 1.5 ms on each rotation */
! 298:
! 299: #define FDC_DELAY_TYPE_I_PREPARE 90 /* Types I commands take at least 0.09 ms to execute */
! 300: /* (~740 cpu cycles @ 8 Mhz). [NP] : this was measured on a 520 STF */
! 301: /* and avoid returning immediately when command has no effect */
! 302: #define FDC_DELAY_TYPE_II_PREPARE 1 // 65 /* Start Type II commands immediately */
! 303: #define FDC_DELAY_TYPE_III_PREPARE 1 /* Start Type III commands immediately */
1.1.1.15 root 304: #define FDC_DELAY_TYPE_IV_PREPARE 100 /* FIXME [NP] : this was not measured */
305:
306: #define FDC_DELAY_TRANSFER_DMA_16 FDC_TRANSFER_BYTES_US( DMA_DISK_TRANSFER_SIZE )
1.1 root 307:
1.1.1.15 root 308: #define FDC_DELAY_COMMAND_COMPLETE 1 /* Number of us before going to the _COMPLETE state (~8 cpu cycles) */
1.1.1.5 root 309:
1.1.1.17! root 310: #define FDC_DELAY_COMMAND_IMMEDIATE 1 /* Number of us to go immediately to another state */
1.1.1.5 root 311:
312:
1.1.1.15 root 313: #define DMA_DISK_SECTOR_SIZE 512 /* Sector count at $ff8606 is for 512 bytes blocks */
314: #define DMA_DISK_TRANSFER_SIZE 16 /* DMA transfers blocks of 16 bytes at a time */
1.1.1.5 root 315:
1.1.1.15 root 316: #define FDC_PHYSICAL_MAX_TRACK 90 /* Head can't go beyond 90 tracks */
1.1 root 317:
1.1.1.2 root 318:
1.1.1.15 root 319: #define FDC_SIDE ( (~PSGRegisters[PSG_REG_IO_PORTA]) & 0x01 ) /* Side 0 or 1 */
320: #define FDC_DRIVE FDC_FindFloppyDrive()
1.1.1.14 root 321:
1.1.1.15 root 322: #define FDC_STEP_RATE ( FDC.CR & 0x03 ) /* Bits 0 and 1 of the current type I command */
323:
324: static int FDC_StepRate_ms[] = { 6 , 12 , 2 , 3 }; /* Controlled by bits 1 and 0 (r1/r0) in type I commands */
325:
326:
327: #define FDC_SECTOR_SIZE_128 0 /* Sector size used in the ID fields */
328: #define FDC_SECTOR_SIZE_256 1
329: #define FDC_SECTOR_SIZE_512 2
330: #define FDC_SECTOR_SIZE_1024 3
331:
332:
1.1.1.17! root 333: /* These are some standard GAP values to format a track with 9 or 10 sectors */
! 334: /* When handling ST/MSA disk images, those values are required to get accurate */
! 335: /* timings when emulating disk's spin and index's position. */
! 336:
! 337: #define FDC_TRACK_LAYOUT_STANDARD_GAP1 60 /* Track Pre GAP : 0x4e */
! 338: #define FDC_TRACK_LAYOUT_STANDARD_GAP2 12 /* Sector ID Pre GAP : 0x00 */
! 339: #define FDC_TRACK_LAYOUT_STANDARD_GAP3a 22 /* Sector ID Post GAP : 0x4e */
! 340: #define FDC_TRACK_LAYOUT_STANDARD_GAP3b 12 /* Sector DATA Pre GAP : 0x00 */
! 341: #define FDC_TRACK_LAYOUT_STANDARD_GAP4 40 /* Sector DATA Pre GAP : 0x4e */
! 342: #define FDC_TRACK_LAYOUT_STANDARD_GAP5 0 /* Track Post GAP : 0x4e (to fill the rest of the track, value is variable) */
! 343: /* GAP5 is 664 bytes for 9 sectors or 50 bytes for 10 sectors */
! 344:
! 345: /* Size of a raw standard 512 byte sector in a track, including ID field and all GAPs : 614 bytes */
! 346: /* (this must be the same as the data returned in FDC_UpdateReadTrackCmd() ) */
! 347: #define FDC_TRACK_LAYOUT_STANDARD_RAW_SECTOR_512 ( FDC_TRACK_LAYOUT_STANDARD_GAP2 \
! 348: + 3 + 1 + 6 + FDC_TRACK_LAYOUT_STANDARD_GAP3a + FDC_TRACK_LAYOUT_STANDARD_GAP3b \
! 349: + 3 + 1 + 512 + 2 + FDC_TRACK_LAYOUT_STANDARD_GAP4 )
! 350:
! 351:
1.1.1.15 root 352: #define FDC_FAST_FDC_FACTOR 10 /* Divide all delays by this value when --fastfdc is used */
353:
354:
355: typedef struct {
356: /* WD1772 internal registers */
357: Uint8 DR; /* Data Register */
358: Uint8 TR; /* Track Register */
359: Uint8 SR; /* Sector Register */
360: Uint8 CR; /* Command Register */
361: Uint8 STR; /* Status Register */
362: int StepDirection; /* +1 (Step In) or -1 (Step Out) */
363:
364: /* Other variables */
365: int Command; /* FDC emulation command currently being exceuted */
366: int CommandState; /* Current state for the running command */
367: Uint8 CommandType; /* Type of latest FDC command (1,2,3 or 4) */
368: bool ReplaceCommandPossible; /* true if the current command can be replaced by another one */
369: /* ([NP] FIXME : only possible during prepare+spinup phases ?) */
370:
371: Uint8 ID_FieldLastSector; /* Last sector number returned by Read Address (to simulate a spinning disk) */
1.1.1.17! root 372: bool UpdateIndexPulse; /* true if motor was stopped and we're starting a spin up sequence */
! 373: Uint64 IndexPulse_Time; /* Clock value last time we had an index pulse with motor ON */
! 374: Uint64 CommandExpire_Time; /* Clock value to abort a command if it didn't complete before */
! 375: Uint8 NextSector_ID_Field_SR; /* Sector Register from the ID Field after a call to FDC_NextSectorID_NbBytes() */
1.1.1.15 root 376: } FDC_STRUCT;
377:
378:
379: typedef struct {
380: /* DMA internal registers */
381: Uint16 Status;
382: Uint16 Mode;
383: Uint16 SectorCount;
384: Uint16 BytesInSector;
385:
386: /* Variables to handle our DMA buffer */
387: int PosInBuffer;
388: int PosInBufferTransfer;
389: int BytesToTransfer;
390: } FDC_DMA_STRUCT;
391:
392:
393: static FDC_STRUCT FDC; /* All variables related to the WD1772 emulation */
394: static FDC_DMA_STRUCT FDC_DMA; /* All variables related to the DMA transfer */
395:
396: static Uint8 HeadTrack[ MAX_FLOPPYDRIVES ]; /* A: and B: */
397:
1.1.1.17! root 398: //static Uint8 DMADiskWorkSpace[ FDC_TRACK_BYTES_STANDARD+1000 ]; /* Workspace used to transfer bytes between floppy and DMA */
! 399: static Uint8 DMADiskWorkSpace[ 6275+1000 ]; /* Workspace used to transfer bytes between floppy and DMA */
1.1.1.15 root 400: /* It should be large enough to contain a whole track */
401:
402:
403: /*--------------------------------------------------------------*/
404: /* Local functions prototypes */
405: /*--------------------------------------------------------------*/
406:
1.1.1.17! root 407: static void FDC_SetDriveLedBusy ( void );
! 408:
1.1.1.15 root 409: static int FDC_DelayToCpuCycles ( int Delay_micro );
1.1.1.17! root 410: static void FDC_StartTimer_micro ( int Delay_micro , int InternalCycleOffset );
1.1.1.15 root 411: static void FDC_CRC16 ( Uint8 *buf , int nb , Uint16 *pCRC );
412:
413: static void FDC_ResetDMA ( void );
414: static void FDC_DMA_InitTransfer ( void );
415: static bool FDC_DMA_ReadFromFloppy ( void );
416: static bool FDC_DMA_WriteToFloppy ( void );
417:
1.1.1.16 root 418: static bool FDC_ValidFloppyDrive ( void );
1.1.1.15 root 419: static int FDC_FindFloppyDrive ( void );
420: static int FDC_GetSectorsPerTrack ( int Track , int Side );
421: static int FDC_GetSidesPerDisk ( int Track );
422:
1.1.1.17! root 423: static void FDC_IndexPulse_Init ( void );
! 424: static int FDC_IndexPulse_GetCurrentPos ( void );
! 425: static int FDC_IndexPulse_GetState ( void );
! 426: static int FDC_NextIndexPulse_NbBytes ( void );
! 427: static int FDC_NextSectorID_NbBytes ( void );
! 428:
1.1.1.15 root 429: static void FDC_Update_STR ( Uint8 DisableBits , Uint8 EnableBits );
430: static int FDC_CmdCompleteCommon ( bool DoInt );
431: static void FDC_VerifyTrack ( void );
432: static int FDC_UpdateMotorStop ( void );
433: static int FDC_UpdateRestoreCmd ( void );
434: static int FDC_UpdateSeekCmd ( void );
435: static int FDC_UpdateStepCmd ( void );
436: static int FDC_UpdateReadSectorsCmd ( void );
437: static int FDC_UpdateWriteSectorsCmd ( void );
438: static int FDC_UpdateReadAddressCmd ( void );
439: static int FDC_UpdateReadTrackCmd ( void );
440:
441: static int FDC_Check_MotorON ( Uint8 FDC_CR );
442: static int FDC_TypeI_Restore ( void );
443: static int FDC_TypeI_Seek ( void );
444: static int FDC_TypeI_Step ( void );
445: static int FDC_TypeI_StepIn ( void );
446: static int FDC_TypeI_StepOut ( void );
447: static int FDC_TypeII_ReadSector ( void );
448: static int FDC_TypeII_WriteSector(void);
449: static int FDC_TypeIII_ReadAddress ( void );
450: static int FDC_TypeIII_ReadTrack ( void );
451: static int FDC_TypeIII_WriteTrack ( void );
452: static int FDC_TypeIV_ForceInterrupt ( bool bCauseCPUInterrupt );
453:
454: static int FDC_ExecuteTypeICommands ( void );
455: static int FDC_ExecuteTypeIICommands ( void );
456: static int FDC_ExecuteTypeIIICommands ( void );
457: static int FDC_ExecuteTypeIVCommands ( void );
458: static void FDC_ExecuteCommand ( void );
459:
460: static void FDC_WriteSectorCountRegister ( void );
461: static void FDC_WriteCommandRegister ( void );
462: static void FDC_WriteTrackRegister ( void );
463: static void FDC_WriteSectorRegister ( void );
464: static void FDC_WriteDataRegister ( void );
465:
466: static bool FDC_ReadSectorFromFloppy ( Uint8 *buf , Uint8 Sector , int *pSectorSize );
467: static bool FDC_WriteSectorToFloppy ( int DMASectorsCount , Uint8 Sector , int *pSectorSize );
1.1 root 468:
1.1.1.2 root 469:
470: /*-----------------------------------------------------------------------*/
1.1.1.9 root 471: /**
472: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
473: */
1.1.1.10 root 474: void FDC_MemorySnapShot_Capture(bool bSave)
1.1 root 475: {
1.1.1.15 root 476: MemorySnapShot_Store(&FDC, sizeof(FDC));
477: MemorySnapShot_Store(&FDC_DMA, sizeof(FDC_DMA));
478: MemorySnapShot_Store(HeadTrack, sizeof(HeadTrack));
479:
480: MemorySnapShot_Store(DMADiskWorkSpace, sizeof(DMADiskWorkSpace));
1.1 root 481: }
482:
1.1.1.2 root 483:
484: /*-----------------------------------------------------------------------*/
1.1.1.9 root 485: /**
1.1.1.17! root 486: * Change the color of the drive's led color in the statusbar, depending
! 487: * on the state of the busy bit in SR
! 488: */
! 489: static void FDC_SetDriveLedBusy ( void )
! 490: {
! 491: int ActiveDrive;
! 492:
! 493: /* Check Drive A first */
! 494: if ((PSGRegisters[PSG_REG_IO_PORTA]&0x2)==0)
! 495: ActiveDrive = 0;
! 496: /* If off, check Drive B */
! 497: else if ((PSGRegisters[PSG_REG_IO_PORTA]&0x4)==0)
! 498: ActiveDrive = 1;
! 499: else
! 500: return;
! 501:
! 502: if ( FDC.SR & FDC_STR_BIT_BUSY )
! 503: Statusbar_SetFloppyLed ( ActiveDrive , LED_STATE_ON_BUSY );
! 504: else
! 505: Statusbar_SetFloppyLed ( ActiveDrive , LED_STATE_ON );
! 506: }
! 507:
! 508:
! 509: /*-----------------------------------------------------------------------*/
! 510: /**
1.1.1.15 root 511: * Convert a delay in micro seconds to its equivalent of cpu cycles
512: * (FIXME [NP] : for now we use a fixed 8 MHz clock, because cycInt.c requires it)
1.1.1.9 root 513: */
1.1.1.17! root 514: static int FDC_DelayToCpuCycles ( int Delay_micro )
1.1 root 515: {
1.1.1.15 root 516: int Delay;
517:
518: Delay = (int) ( ( (Sint64)MachineClocks.FDC_Freq * Delay_micro ) / 1000000 ) & -4;
1.1.1.17! root 519: Delay = Delay_micro*8;
! 520: //if ( Delay_micro==32 ) Delay=255;
1.1.1.15 root 521:
522: /* Our conversion expect FDC_Freq to be the same as CPU_Freq (8 Mhz) */
523: /* but the Falcon uses a 16 MHz clock for the Ajax FDC */
524: /* FIXME : as stated above, this should be handled better, without involving 8 MHz CPU_Freq */
525: if ( ConfigureParams.System.nMachineType == MACHINE_FALCON )
526: Delay /= 2; /* correct delays for a 8 MHz clock instead of 16 */
527:
1.1.1.17! root 528: //fprintf ( stderr , "fdc state %d delay %d us %d cycles\n" , FDC.Command , Delay_micro , Delay );
! 529: //if ( Delay==4104) Delay=4166; // 4166 : decade demo
1.1.1.15 root 530: return Delay;
1.1 root 531: }
532:
1.1.1.2 root 533:
534: /*-----------------------------------------------------------------------*/
1.1.1.9 root 535: /**
1.1.1.17! root 536: * Start an internal timer to handle the FDC's events.
! 537: * If "fast floppy" mode is used, we speed up the timer by dividing
! 538: * the number of cycles by a fixed number.
! 539: */
! 540: static void FDC_StartTimer_micro ( int Delay_micro , int InternalCycleOffset )
! 541: {
! 542: //fprintf ( stderr , "fdc start timer %d us\n" , Delay_micro );
! 543:
! 544: if ( ( ConfigureParams.DiskImage.FastFloppy ) && ( Delay_micro > FDC_FAST_FDC_FACTOR ) )
! 545: Delay_micro /= FDC_FAST_FDC_FACTOR;
! 546:
! 547: CycInt_AddRelativeInterruptWithOffset ( FDC_DelayToCpuCycles ( Delay_micro ) , INT_CPU_CYCLE , INTERRUPT_FDC , InternalCycleOffset );
! 548: }
! 549:
! 550:
! 551: /*-----------------------------------------------------------------------*/
! 552: /**
1.1.1.15 root 553: * Compute the CRC16 of 'nb' bytes stored in 'buf'.
1.1.1.9 root 554: */
1.1.1.15 root 555: static void FDC_CRC16 ( Uint8 *buf , int nb , Uint16 *pCRC )
1.1 root 556: {
1.1.1.15 root 557: int i;
558:
559: crc16_reset ( pCRC );
560: for ( i=0 ; i<nb ; i++ )
561: {
562: // fprintf ( stderr , "fdc crc16 %d 0x%x\n" , i , buf[ i ] );
563: crc16_add_byte ( pCRC , buf[ i ] );
564: }
565: // fprintf ( stderr , "fdc crc16 0x%x 0x%x\n" , *pCRC>>8 , *pCRC & 0xff );
1.1 root 566: }
567:
1.1.1.2 root 568:
569: /*-----------------------------------------------------------------------*/
1.1.1.9 root 570: /**
1.1.1.15 root 571: * Reset variables used in FDC and DMA emulation
1.1.1.9 root 572: */
1.1.1.15 root 573: void FDC_Reset ( void )
1.1 root 574: {
1.1.1.15 root 575: int i;
1.1.1.6 root 576:
1.1.1.15 root 577: /* Clear out FDC registers */
578:
579: FDC.CR = 0;
580: FDC.TR = 0;
581: FDC.SR = 1;
582: FDC.DR = 0;
583: FDC.STR = 0;
584: FDC.StepDirection = 1;
585: FDC.ID_FieldLastSector = 1;
586:
587: FDC.Command = FDCEMU_CMD_NULL; /* FDC emulation command currently being executed */
588: FDC.CommandState = FDCEMU_RUN_NULL;
589: FDC.CommandType = 0;
590:
591: FDC_DMA.Status = 1; /* no DMA error and SectorCount=0 */
592: FDC_DMA.Mode = 0;
593: FDC_DMA.SectorCount = 0;
594: FDC_ResetDMA();
595:
596: for ( i=0 ; i<MAX_FLOPPYDRIVES ; i++ )
597: HeadTrack[ i ] = 0; /* Set all drives to track 0 */
1.1 root 598: }
599:
1.1.1.2 root 600:
601: /*-----------------------------------------------------------------------*/
1.1.1.9 root 602: /**
1.1.1.15 root 603: * Reset DMA (clear internal 16 bytes buffer)
1.1.1.9 root 604: *
605: * This is done by 'toggling' bit 8 of the DMA Mode Control register
606: */
1.1.1.15 root 607: static void FDC_ResetDMA ( void )
1.1 root 608: {
1.1.1.15 root 609: int FrameCycles, HblCounterVideo, LineCycles;
1.1 root 610:
1.1.1.15 root 611: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
612: LOG_TRACE(TRACE_FDC, "fdc reset dma VBL=%d video_cyc=%d %d@%d pc=%x\n",
613: nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
614:
615: /* Reset bytes count for current DMA sector */
616: FDC_DMA.BytesInSector = DMA_DISK_SECTOR_SIZE;
617:
618: /* Reset variables used to handle DMA transfer */
619: FDC_DMA.PosInBuffer = 0;
620: FDC_DMA.PosInBufferTransfer = 0;
621: FDC_DMA.BytesToTransfer = 0;
1.1.1.3 root 622:
1.1.1.10 root 623: /* Reset HDC command status */
1.1.1.15 root 624: HDC_ResetCommandStatus();
1.1 root 625: }
626:
1.1.1.2 root 627:
628: /*-----------------------------------------------------------------------*/
1.1.1.9 root 629: /**
1.1.1.15 root 630: * Set DMA Status at $ff8606
1.1.1.9 root 631: *
1.1.1.15 root 632: * Bit 0 - _Error Status (0=Error 1=No erroe)
1.1.1.9 root 633: * Bit 1 - _Sector Count Zero Status (0=Sector Count Zero)
634: * Bit 2 - _Data Request Inactive Status
1.1.1.15 root 635: *
636: * FIXME [NP] : is bit 0 really used on ST ? It seems it's always 1 (no DMA error)
1.1.1.9 root 637: */
1.1.1.15 root 638: void FDC_SetDMAStatus ( bool bError )
1.1 root 639: {
1.1.1.15 root 640: /* Set error bit */
1.1.1.6 root 641: if (!bError)
1.1.1.15 root 642: FDC_DMA.Status |= 0x1; /* No Error, set bit 0 */
1.1.1.6 root 643: else
1.1.1.15 root 644: FDC_DMA.Status &= ~0x1; /* Error, clear bit 0 */
1.1 root 645: }
646:
1.1.1.2 root 647:
648: /*-----------------------------------------------------------------------*/
1.1.1.9 root 649: /**
1.1.1.15 root 650: * Init some variables before starting a new DMA transfer.
651: * We must store new data just after the most recent bytes that
652: * were not yet transferred by the DMA (16 bytes buffer).
653: * To avoid writing above the limit of DMADiskWorkSpace, we move
654: * the current 16 bytes buffer at the start of DMADiskWorkSpace
655: * if some bytes remain to be transferred, this way we never use
656: * more than FDC_TRACK_BYTES_STANDARD in DMADiskWorkSpace.
1.1.1.9 root 657: */
1.1.1.15 root 658: static void FDC_DMA_InitTransfer ( void )
1.1 root 659: {
1.1.1.15 root 660: int i;
661:
662: /* How many bytes remain in the current 16 bytes DMA buffer ? */
663: if ( ( FDC_DMA.BytesToTransfer == 0 ) /* DMA buffer is empty */
664: || ( FDC_DMA.BytesToTransfer > DMA_DISK_TRANSFER_SIZE ) ) /* Previous DMA transfer did not finish (FDC errror or Force Int command) */
1.1.1.6 root 665: {
1.1.1.15 root 666: FDC_DMA.PosInBuffer = 0; /* Add new data at the start of DMADiskWorkSpace */
667: FDC_DMA.PosInBufferTransfer = 0;
668: FDC_DMA.BytesToTransfer = 0; /* No more data to transfer from the previous DMA buffer */
1.1.1.6 root 669: }
1.1.1.15 root 670: else /* 16 bytes buffer partially filled */
671: {
672: for ( i=0 ; i<FDC_DMA.BytesToTransfer ; i++ ) /* Move these bytes at the start of the buffer */
673: DMADiskWorkSpace[ i ] = DMADiskWorkSpace[ FDC_DMA.PosInBufferTransfer + i ];
1.1.1.6 root 674:
1.1.1.15 root 675: FDC_DMA.PosInBuffer = FDC_DMA.BytesToTransfer; /* Add new data after the latest bytes stored in the 16 bytes buffer */
676: FDC_DMA.PosInBufferTransfer = 0;
677: }
1.1 root 678: }
679:
1.1.1.2 root 680:
681: /*-----------------------------------------------------------------------*/
1.1.1.9 root 682: /**
1.1.1.15 root 683: * Transfer 16 bytes from the DMA workspace to the RAM.
684: * Instead of handling a real 16 bytes buffer, this implementation moves
685: * a 16 bytes window in DMADiskWorkSpace. The current position of this window
686: * is stored in FDC_DMA.PosInBufferTransfer and contains the equivalent of the
687: * DMA's internal 16 bytes buffer.
688: *
689: * Return true if there're no more bytes to transfer or false if some
690: * bytes can still be tranfered by the DMA.
691: *
692: * NOTE [NP] : The DMA is connected to the FDC, each time a DRQ is made by the FDC,
693: * it's handled by the DMA and stored in the DMA 16 bytes buffer. This means
694: * FDC_STR_BIT_LOST_DATA will never be set (but data can be lost if FDC_DMA.SectorCount==0)
1.1.1.14 root 695: */
1.1.1.15 root 696: static bool FDC_DMA_ReadFromFloppy ( void )
1.1.1.14 root 697: {
1.1.1.15 root 698: Uint32 Address;
699: //fprintf ( stderr , "dma transfer read count=%d bytes=%d pos=%d\n" , FDC_DMA.SectorCount, FDC_DMA.BytesToTransfer, FDC_DMA.PosInBufferTransfer );
1.1.1.14 root 700:
1.1.1.15 root 701: if ( FDC_DMA.BytesToTransfer < DMA_DISK_TRANSFER_SIZE )
702: return true; /* There should be at least 16 bytes to start a DMA transfer */
1.1.1.14 root 703:
1.1.1.15 root 704: if ( FDC_DMA.SectorCount == 0 )
705: {
706: //FDC_Update_STR ( 0 , FDC_STR_BIT_LOST_DATA ); /* If DMA is OFF, data are lost -> Not on the ST */
707: FDC_DMA.PosInBufferTransfer += DMA_DISK_TRANSFER_SIZE;
708: FDC_DMA.BytesToTransfer -= DMA_DISK_TRANSFER_SIZE;
1.1.1.17! root 709: if ( FDC_DMA.BytesToTransfer < DMA_DISK_TRANSFER_SIZE )
! 710: return true; /* There should be at least 16 bytes to start a new DMA transfer */
! 711: else
! 712: return false; /* FDC DMA is off but we still need to read all bytes from the floppy */
1.1.1.15 root 713: }
714:
715: /* Transfer data and update DMA address */
716: Address = FDC_GetDMAAddress();
717: STMemory_SafeCopy ( Address , DMADiskWorkSpace + FDC_DMA.PosInBufferTransfer , DMA_DISK_TRANSFER_SIZE , "FDC DMA data read" );
718: FDC_DMA.PosInBufferTransfer += DMA_DISK_TRANSFER_SIZE;
719: FDC_DMA.BytesToTransfer -= DMA_DISK_TRANSFER_SIZE;
720: FDC_WriteDMAAddress ( Address + DMA_DISK_TRANSFER_SIZE );
721:
722: /* Update Sector Count */
723: FDC_DMA.BytesInSector -= DMA_DISK_TRANSFER_SIZE;
724: if ( FDC_DMA.BytesInSector <= 0 )
725: {
726: FDC_DMA.SectorCount--;
727: FDC_DMA.BytesInSector = DMA_DISK_SECTOR_SIZE;
728: }
1.1.1.2 root 729:
1.1.1.17! root 730: if ( FDC_DMA.BytesToTransfer < DMA_DISK_TRANSFER_SIZE )
! 731: return true; /* There should be at least 16 bytes to start a new DMA transfer */
! 732: else
! 733: return false; /* Transfer is not complete */
1.1 root 734: }
735:
1.1.1.2 root 736:
737: /*-----------------------------------------------------------------------*/
1.1.1.9 root 738: /**
1.1.1.15 root 739: * Transfer 16 bytes from the RAM to disk using DMA.
740: * This is used to write data to the disk with correct timings
741: * by writing blocks of 16 bytes at a time.
742: *
743: * Return true if there're no more bytes to transfer or false if some
744: * bytes can still be tranfered by the DMA.
745: *
746: * NOTE [NP] : in the case of the emulation in Hatari, the sector is first written
747: * to the disk image and this function is just used to increment
748: * DMA address at the correct pace to simulate that bytes are written from
749: * blocks of 16 bytes handled by the DMA.
1.1.1.9 root 750: */
1.1.1.15 root 751: static bool FDC_DMA_WriteToFloppy ( void )
1.1 root 752: {
1.1.1.15 root 753: Uint32 Address;
754: //fprintf ( stderr , "dma transfer write count=%d bytes=%d pos=%d\n" , FDC_DMA.SectorCount, FDC_DMA.BytesToTransfer, FDC_DMA.PosInBufferTransfer );
755:
756: if ( FDC_DMA.BytesToTransfer < DMA_DISK_TRANSFER_SIZE )
757: return true; /* There should be at least 16 bytes to start a DMA transfer */
758:
759: if ( FDC_DMA.SectorCount == 0 )
760: {
761: //FDC_Update_STR ( 0 , FDC_STR_BIT_LOST_DATA ); /* If DMA is OFF, data are lost -> Not on the ST */
762: FDC_DMA.PosInBufferTransfer += DMA_DISK_TRANSFER_SIZE;
763: FDC_DMA.BytesToTransfer -= DMA_DISK_TRANSFER_SIZE;
1.1.1.17! root 764: if ( FDC_DMA.BytesToTransfer < DMA_DISK_TRANSFER_SIZE )
! 765: return true; /* There should be at least 16 bytes to start a new DMA transfer */
! 766: else
! 767: return false; /* FDC DMA is off but we still need to read all bytes from the floppy */
1.1.1.15 root 768: }
1.1 root 769:
1.1.1.15 root 770: /* Transfer data and update DMA address */
771: Address = FDC_GetDMAAddress();
772: //STMemory_SafeCopy ( Address , DMADiskWorkSpace + FDC_DMA.PosInBufferTransfer , DMA_DISK_TRANSFER_SIZE , "FDC DMA data read" );
773: FDC_DMA.PosInBufferTransfer += DMA_DISK_TRANSFER_SIZE;
774: FDC_DMA.BytesToTransfer -= DMA_DISK_TRANSFER_SIZE;
775: FDC_WriteDMAAddress ( Address + DMA_DISK_TRANSFER_SIZE );
1.1 root 776:
1.1.1.15 root 777: /* Update Sector Count */
778: FDC_DMA.BytesInSector -= DMA_DISK_TRANSFER_SIZE;
779: if ( FDC_DMA.BytesInSector <= 0 )
1.1.1.6 root 780: {
1.1.1.15 root 781: FDC_DMA.SectorCount--;
782: FDC_DMA.BytesInSector = DMA_DISK_SECTOR_SIZE;
1.1.1.6 root 783: }
784:
1.1.1.17! root 785: if ( FDC_DMA.BytesToTransfer < DMA_DISK_TRANSFER_SIZE )
! 786: return true; /* There should be at least 16 bytes to start a new DMA transfer */
! 787: else
! 788: return false; /* Transfer is not complete */
1.1 root 789: }
790:
1.1.1.2 root 791:
792: /*-----------------------------------------------------------------------*/
1.1.1.9 root 793: /**
1.1.1.16 root 794: * Check if a floppy drive is selected
795: * If not, we should ignore the corresponding FDC commands
796: */
797: static bool FDC_ValidFloppyDrive ( void )
798: {
799: if ((PSGRegisters[PSG_REG_IO_PORTA]&0x6)==0x6)
800: return false; /* neither A: not B: are selected */
801: else
802: return true;
803: }
804:
805:
806: /*-----------------------------------------------------------------------*/
807: /**
1.1.1.15 root 808: * Return device for FDC, check PORTA bits 1,2 (0=on,1=off)
1.1.1.9 root 809: */
1.1.1.15 root 810: static int FDC_FindFloppyDrive ( void )
1.1 root 811: {
1.1.1.6 root 812: /* Check Drive A first */
813: if ((PSGRegisters[PSG_REG_IO_PORTA]&0x2)==0)
1.1.1.15 root 814: return 0; /* Device 0 (A:) */
1.1.1.6 root 815: /* If off, check Drive B */
816: if ((PSGRegisters[PSG_REG_IO_PORTA]&0x4)==0)
1.1.1.15 root 817: return 1; /* Device 1 (B:) */
1.1 root 818:
1.1.1.6 root 819: /* None appear to be selected so default to Drive A */
1.1.1.16 root 820: /* [NP] 2012/03/04 : this is certainly wrong, we should ignore commands, not default to A: (see FDC_ValidFloppyDrive()) */
1.1.1.15 root 821: return 0; /* Device 0 (A:) */
1.1 root 822: }
823:
1.1.1.2 root 824:
825: /*-----------------------------------------------------------------------*/
1.1.1.9 root 826: /**
1.1.1.15 root 827: * Return number of sectors for track/side of current drive
828: * TODO [NP] : this function calls Floppy_FindDiskDetails which handles only ST/MSA
829: * disk image so far, so this implies all tracks have in fact the same number
830: * of sectors (we don't use Track and Side for now)
1.1.1.9 root 831: */
1.1.1.15 root 832: static int FDC_GetSectorsPerTrack ( int Track , int Side )
1.1 root 833: {
1.1.1.15 root 834: Uint16 SectorsPerTrack;
835:
836: if (EmulationDrives[ FDC_DRIVE ].bDiskInserted)
837: {
838: Floppy_FindDiskDetails ( EmulationDrives[ FDC_DRIVE ].pBuffer , EmulationDrives[ FDC_DRIVE ].nImageBytes , &SectorsPerTrack , NULL );
839: return SectorsPerTrack;
840: }
841: else
842: return 0;
1.1 root 843: }
844:
1.1.1.2 root 845:
1.1.1.15 root 846: static int FDC_GetSidesPerDisk ( int Track )
1.1 root 847: {
1.1.1.15 root 848: Uint16 SidesPerDisk;
849:
850: if (EmulationDrives[ FDC_DRIVE ].bDiskInserted)
851: {
852: Floppy_FindDiskDetails ( EmulationDrives[ FDC_DRIVE ].pBuffer , EmulationDrives[ FDC_DRIVE ].nImageBytes , NULL , &SidesPerDisk );
853: return SidesPerDisk; /* 1 or 2 */
854: }
855: else
856: return 0;
1.1 root 857: }
858:
1.1.1.2 root 859:
1.1.1.17! root 860:
! 861: /*-----------------------------------------------------------------------*/
! 862: /**
! 863: * Store the time of the most recent index pulse.
! 864: * This is called when motor was off and reaches its peak speed, and is used
! 865: * to compute the position relative to the start of the track when we need
! 866: * to wait for the next track index or the next sector header while the
! 867: * floppy is spinning.
! 868: * As the FDC waits 6 index pulses during the spin up phase, this means
! 869: * that when motor reaches its desired speed an index pulse was just
! 870: * encountered.
! 871: * So, the position after peak speed is reached is not random, it will always
! 872: * be 0 and we set the index pulse time to "now".
! 873: */
! 874: static void FDC_IndexPulse_Init ( void )
! 875: {
! 876: FDC.IndexPulse_Time = CyclesGlobalClockCounter;
! 877: //fprintf ( stderr , "fdc index pulse init %lld\n" , FDC.IndexPulse_Time );
! 878: }
! 879:
! 880:
! 881: /*-----------------------------------------------------------------------*/
! 882: /**
! 883: * Return the current position in the track relative to the index pulse.
! 884: * For standard floppy, this is a number of bytes in the range [0,6250[
! 885: */
! 886: static int FDC_IndexPulse_GetCurrentPos ( void )
! 887: {
! 888: Uint64 BytesSinceIndex;
! 889:
! 890: /* Transform the current number of cycles since the reference index into a number of bytes */
! 891: BytesSinceIndex = ( CyclesGlobalClockCounter - FDC.IndexPulse_Time ) / FDC_DelayToCpuCycles ( FDC_TRANSFER_BYTES_US ( 1 ) );
! 892:
! 893: //fprintf ( stderr , "fdc index pulse pos cur=%lld ref=%lld bytes=%lld pos=%d\n" , CyclesGlobalClockCounter , FDC.IndexPulse_Time , BytesSinceIndex , (int)(BytesSinceIndex % FDC_TRACK_BYTES_STANDARD) );
! 894: /* Ignore the total number of spins, only keep the position relative to the index pulse */
! 895: return ( BytesSinceIndex % FDC_TRACK_BYTES_STANDARD );
! 896: }
! 897:
! 898:
! 899: /*-----------------------------------------------------------------------*/
! 900: /**
! 901: * Return the current state of the index pulse signal.
! 902: * The signal goes to 1 when reaching the index pulse location and remain
! 903: * to 1 during 1.5 ms (approx 46 bytes).
! 904: * During the rest of the track, the signal will be 0.
! 905: */
! 906: static int FDC_IndexPulse_GetState ( void )
! 907: {
! 908: int CurrentPos;
! 909: int state;
! 910:
! 911: CurrentPos = FDC_IndexPulse_GetCurrentPos ();
! 912:
! 913: state = 0;
! 914: if ( CurrentPos < FDC_DELAY_INDEX_PULSE_LENGTH / FDC_TRANSFER_BYTES_US ( 1 ) )
! 915: state = 1;
! 916:
! 917: //fprintf ( stderr , "fdc index state pos pos=%d state=%d\n" , CurrentPos , state );
! 918: return state;
! 919: }
! 920:
! 921:
! 922: /*-----------------------------------------------------------------------*/
! 923: /**
! 924: * Return the number of bytes to read from the track before reaching the
! 925: * next index pulse signal.
! 926: */
! 927: static int FDC_NextIndexPulse_NbBytes ( void )
! 928: {
! 929: return FDC_TRACK_BYTES_STANDARD - FDC_IndexPulse_GetCurrentPos ();
! 930: }
! 931:
! 932:
! 933: /*-----------------------------------------------------------------------*/
! 934: /**
! 935: * Return the number of bytes to read from the track before reaching the
! 936: * next sector's ID Field ($A1 $A1 $A1 $FE TR SIDE SR LEN CRC1 CRC2)
! 937: * If no ID Field is found before the end of the track, we use the 1st
! 938: * ID Field of the track (which simulates a full spin of the floppy).
! 939: * We also store the next sector's number into NextSector_ID_Field_SR.
! 940: * This function assumes some 512 byte sectors stored in ascending
! 941: * order (for ST/MSA)
! 942: */
! 943: static int FDC_NextSectorID_NbBytes ( void )
! 944: {
! 945: int CurrentPos;
! 946: int MaxSector;
! 947: int TrackPos;
! 948: int i;
! 949: int NextSector;
! 950: int NbBytes;
! 951:
! 952: CurrentPos = FDC_IndexPulse_GetCurrentPos ();
! 953:
! 954: MaxSector = FDC_GetSectorsPerTrack ( HeadTrack[ FDC_DRIVE ] , FDC_SIDE );
! 955: TrackPos = FDC_TRACK_LAYOUT_STANDARD_GAP1; /* Position of 1st raw sector */
! 956: TrackPos += FDC_TRACK_LAYOUT_STANDARD_GAP2; /* Position of ID Field in 1st raw sector */
! 957:
! 958: /* Compare CurrentPos with each sector's position in ascending order */
! 959: for ( i=0 ; i<MaxSector ; i++ )
! 960: {
! 961: if ( CurrentPos < TrackPos )
! 962: break; /* We found the next sector */
! 963: else
! 964: TrackPos += FDC_TRACK_LAYOUT_STANDARD_RAW_SECTOR_512;
! 965: }
! 966:
! 967: if ( i == MaxSector ) /* CurrentPos is after the last ID Field of this track */
! 968: {
! 969: /* Reach end of track (new index pulse), then go to sector 1 */
! 970: NbBytes = FDC_TRACK_BYTES_STANDARD - CurrentPos + FDC_TRACK_LAYOUT_STANDARD_GAP1 + FDC_TRACK_LAYOUT_STANDARD_GAP2;
! 971: NextSector = 1;
! 972: }
! 973: else /* There's an ID Field before end of track */
! 974: {
! 975: NbBytes = TrackPos - CurrentPos;
! 976: NextSector = i+1;
! 977: }
! 978:
! 979: //fprintf ( stderr , "fdc bytes next sector pos=%d trpos=%d nbbytes=%d nextsr=%d\n" , CurrentPos, TrackPos, NbBytes, NextSector );
! 980: FDC.NextSector_ID_Field_SR = NextSector;
! 981: return NbBytes;
! 982: }
! 983:
! 984:
! 985:
1.1.1.2 root 986: /*-----------------------------------------------------------------------*/
1.1.1.9 root 987: /**
1.1.1.15 root 988: * Acknowledge FDC interrupt
1.1.1.9 root 989: */
1.1.1.15 root 990: void FDC_AcknowledgeInterrupt ( void )
1.1.1.8 root 991: {
1.1.1.15 root 992: /* Acknowledge in MFP circuit, pass bit, enable, pending */
1.1.1.17! root 993: MFP_InputOnChannel ( MFP_INT_FDCHDC , 0 );
1.1.1.15 root 994: MFP_GPIP &= ~0x20;
1.1.1.8 root 995: }
996:
997:
998: /*-----------------------------------------------------------------------*/
1.1.1.9 root 999: /**
1.1.1.15 root 1000: * Handle the current FDC command.
1001: * We use a timer to go from one state to another to emulate the different
1002: * phases of an FDC command.
1003: * When the command completes (success or failure), FDC.Command will be
1004: * set to FDCEMU_CMD_NULL. Until then, this function will be called to
1005: * handle each state of the command and the corresponding delay in micro
1006: * seconds.
1007: * This handler is called after a first delay corresponding to the prepare
1008: * delay and the eventual motor on delay.
1009: * Once we reach this point, the current command can not be replaced by
1010: * another command (except 'Force Interrupt')
1.1.1.9 root 1011: */
1.1.1.15 root 1012: void FDC_InterruptHandler_Update ( void )
1.1 root 1013: {
1.1.1.15 root 1014: int Delay_micro = 0;
1.1.1.17! root 1015: int PendingCyclesOver;
! 1016:
! 1017: /* Number of internal cycles we went over for this timer ( <= 0 ) */
! 1018: /* Used to restart the next timer and keep a constant rate (important for DMA transfers) */
! 1019: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */
! 1020:
! 1021: //fprintf ( stderr , "fdc int handler %lld delay %d\n" , CyclesGlobalClockCounter, PendingCyclesOver );
1.1.1.6 root 1022:
1.1.1.15 root 1023: CycInt_AcknowledgeInterrupt();
1.1.1.6 root 1024:
1025: /* Is FDC active? */
1.1.1.15 root 1026: if (FDC.Command!=FDCEMU_CMD_NULL)
1.1.1.6 root 1027: {
1.1.1.15 root 1028: FDC.ReplaceCommandPossible = false;
1.1.1.17! root 1029:
! 1030: /* If the command needed to restart the motor, the motor is now ON */
! 1031: /* so we must compute a new random index position */
! 1032: if ( FDC.UpdateIndexPulse == true )
! 1033: {
! 1034: FDC_IndexPulse_Init ();
! 1035: FDC.UpdateIndexPulse = false;
! 1036: }
! 1037:
! 1038: /* Which command are we running ? */
1.1.1.15 root 1039: switch(FDC.Command)
1.1.1.6 root 1040: {
1041: case FDCEMU_CMD_RESTORE:
1.1.1.15 root 1042: Delay_micro = FDC_UpdateRestoreCmd();
1.1.1.6 root 1043: break;
1044: case FDCEMU_CMD_SEEK:
1.1.1.15 root 1045: Delay_micro = FDC_UpdateSeekCmd();
1.1.1.6 root 1046: break;
1047: case FDCEMU_CMD_STEP:
1.1.1.15 root 1048: Delay_micro = FDC_UpdateStepCmd();
1.1.1.6 root 1049: break;
1050:
1051: case FDCEMU_CMD_READSECTORS:
1.1.1.15 root 1052: Delay_micro = FDC_UpdateReadSectorsCmd();
1.1.1.6 root 1053: break;
1054: case FDCEMU_CMD_WRITESECTORS:
1.1.1.15 root 1055: Delay_micro = FDC_UpdateWriteSectorsCmd();
1.1.1.6 root 1056: break;
1.1.1.11 root 1057:
1058: case FDCEMU_CMD_READADDRESS:
1.1.1.15 root 1059: Delay_micro = FDC_UpdateReadAddressCmd();
1060: break;
1061:
1062: case FDCEMU_CMD_READTRACK:
1063: Delay_micro = FDC_UpdateReadTrackCmd();
1064: break;
1065:
1066: case FDCEMU_CMD_MOTOR_STOP:
1067: Delay_micro = FDC_UpdateMotorStop();
1.1.1.11 root 1068: break;
1.1.1.6 root 1069: }
1.1.1.15 root 1070: }
1.1.1.6 root 1071:
1.1.1.15 root 1072: if (FDC.Command != FDCEMU_CMD_NULL)
1073: {
1.1.1.17! root 1074: FDC_StartTimer_micro ( Delay_micro , -PendingCyclesOver );
1.1.1.6 root 1075: }
1.1.1.15 root 1076: }
1077:
1078:
1079: /*-----------------------------------------------------------------------*/
1080: /**
1081: * Update the FDC's Status Register.
1082: * All bits in DisableBits are cleared in STR, then all bits in EnableBits
1083: * are set in STR.
1084: */
1085: static void FDC_Update_STR ( Uint8 DisableBits , Uint8 EnableBits )
1086: {
1087: FDC.STR &= (~DisableBits); /* Clear bits in DisableBits */
1088: FDC.STR |= EnableBits; /* Set bits in EnableBits */
1.1.1.17! root 1089:
! 1090: FDC_SetDriveLedBusy ();
1.1.1.15 root 1091: //fprintf ( stderr , "fdc str 0x%x\n" , FDC.STR );
1092: }
1093:
1094:
1095: /*-----------------------------------------------------------------------*/
1096: /**
1097: * Common to all commands once they're completed :
1098: * - remove busy bit
1099: * - acknowledge interrupt if necessary
1100: * - stop motor after 2 sec
1101: */
1102: static int FDC_CmdCompleteCommon ( bool DoInt )
1103: {
1104: int FrameCycles, HblCounterVideo, LineCycles;
1105:
1106: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1107: LOG_TRACE(TRACE_FDC, "fdc complete command VBL=%d video_cyc=%d %d@%d pc=%x\n",
1108: nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1109:
1110: FDC_Update_STR ( FDC_STR_BIT_BUSY , 0 ); /* Remove busy bit */
1.1.1.9 root 1111:
1.1.1.15 root 1112: if ( DoInt )
1113: FDC_AcknowledgeInterrupt();
1114:
1115: FDC.Command = FDCEMU_CMD_MOTOR_STOP; /* Fake command to stop the motor */
1116: return FDC_DELAY_MOTOR_OFF;
1117: }
1118:
1119:
1120: /*-----------------------------------------------------------------------*/
1121: /**
1122: * Verify track after a type I command.
1123: * The FDC will read the first ID field of the current track and will
1124: * compare the track number in this ID field with the current Track Register.
1125: * If they don't match, an error is set with the RNF bit.
1126: * NOTE : in the case of Hatari when using ST/MSA images, the track is always the correct one,
1127: * so the verify will always be good (except if no disk is inserted or the physical head is
1128: * not on the same track as FDC.TR)
1129: * This function could be improved to support other images format where logical track
1130: * could be different from physical track (eg Pasti)
1131: */
1132: static void FDC_VerifyTrack ( void )
1133: {
1134: int FrameCycles, HblCounterVideo, LineCycles;
1135:
1136: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1137:
1138: if ( ! EmulationDrives[FDC_DRIVE].bDiskInserted ) /* Set RNF bit if no disk is inserted */
1.1.1.9 root 1139: {
1.1.1.15 root 1140: LOG_TRACE(TRACE_FDC, "fdc type I verify track failed no disk in drive=%d VBL=%d video_cyc=%d %d@%d pc=%x\n",
1141: FDC_DRIVE , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1142:
1143: FDC_Update_STR ( 0 , FDC_STR_BIT_RNF ); /* Set RNF bit */
1144: return;
1145: }
1146:
1147: /* In the case of Hatari when using ST/MSA images, the physical track and the track register */
1148: /* should always be the same. Else, it means TR was not correctly set before running the type I command */
1149: if ( HeadTrack[ FDC_DRIVE ] != FDC.TR )
1150: {
1151: 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",
1152: FDC.TR , HeadTrack[ FDC_DRIVE ] , FDC_DRIVE ,
1153: nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1154:
1155: FDC_Update_STR ( 0 , FDC_STR_BIT_RNF ); /* Set RNF bit */
1156: return;
1.1.1.9 root 1157: }
1.1.1.15 root 1158:
1159: /* In the case of Hatari when using ST/MSA images, the track is always the correct one */
1160: FDC_Update_STR ( FDC_STR_BIT_RNF , 0 ); /* remove RNF bit */
1161: }
1162:
1163:
1164: /*-----------------------------------------------------------------------*/
1165: /**
1166: * When the motor really stops (2 secs after the last command), clear all related bits in SR
1167: */
1168: static int FDC_UpdateMotorStop ( void )
1169: {
1170: int FrameCycles, HblCounterVideo, LineCycles;
1171:
1172: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1173: LOG_TRACE(TRACE_FDC, "fdc motor stopped VBL=%d video_cyc=%d %d@%d pc=%x\n",
1174: nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1175:
1176: FDC_Update_STR ( FDC_STR_BIT_MOTOR_ON | FDC_STR_BIT_SPIN_UP , 0 ); /* Unset motor and spinup bits */
1177: /* [NP] FIXME should we clear spin up here or only when the motor is started again ? */
1178:
1179: FDC.Command = FDCEMU_CMD_NULL; /* Motor stopped, this is the last state */
1180: return 0;
1.1 root 1181: }
1182:
1.1.1.2 root 1183:
1184: /*-----------------------------------------------------------------------*/
1.1.1.9 root 1185: /**
1186: * Run 'RESTORE' command
1187: */
1.1.1.15 root 1188: static int FDC_UpdateRestoreCmd ( void )
1.1 root 1189: {
1.1.1.15 root 1190: int Delay_micro = 0;
1191:
1192: FDC_Update_STR ( 0 , FDC_STR_BIT_SPIN_UP ); /* at this point, spin up sequence is ok */
1193:
1.1.1.6 root 1194: /* Which command is running? */
1.1.1.15 root 1195: switch (FDC.CommandState)
1.1.1.6 root 1196: {
1197: case FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO:
1.1.1.15 root 1198: /* The FDC will try 255 times to reach track 0 using step out signals */
1199: /* If track 0 signal is not detected after 255 attempts, the command is interrupted */
1200: /* and FDC_STR_BIT_RNF is set in the Status Register. */
1201: /* This will never happen in the case of Hatari, because the physical track can't go */
1202: /* beyond track FDC_PHYSICAL_MAX_TRACK (=90) */
1203: /* TR should be set to 255 once the spin-up sequence is made and the command */
1204: /* can't be interrupted anymore by another command (else TR value will be wrong */
1205: /* for other type I commands) */
1206: FDC.TR = 0xff;
1207: FDC.CommandState = FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_LOOP; /* continue in the _LOOP state */
1208: case FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_LOOP:
1209: if ( FDC.TR == 0 ) /* Track 0 not reached after 255 attempts ? */
1210: { /* (this should never happen in the case of Hatari) */
1211: FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );
1212: FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 ); /* Unset bit TR00 */
1213: Delay_micro = FDC_CmdCompleteCommon( true );
1214: }
1215:
1216: if ( HeadTrack[ FDC_DRIVE ] != 0 ) /* Are we at track zero ? */
1217: {
1218: FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 ); /* Unset bit TR00 */
1219: FDC.TR--; /* One less attempt */
1220: HeadTrack[ FDC_DRIVE ]--; /* Move physical head */
1221: Delay_micro = FDC_StepRate_ms[ FDC_STEP_RATE ] * 1000;
1222: }
1.1.1.6 root 1223: else
1224: {
1.1.1.15 root 1225: FDC_Update_STR ( 0 , FDC_STR_BIT_TR00 ); /* Set bit TR00 */
1226: FDC.TR = 0; /* Update Track Register to 0 */
1.1.1.17! root 1227: FDC.CommandState = FDCEMU_RUN_RESTORE_VERIFY;
! 1228: Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE;
! 1229: }
! 1230: break;
! 1231: case FDCEMU_RUN_RESTORE_VERIFY:
! 1232: if ( FDC.CR & FDC_COMMAND_BIT_VERIFY )
! 1233: {
! 1234: FDC.CommandState = FDCEMU_RUN_RESTORE_VERIFY_LOOP;
! 1235: Delay_micro = FDC_DELAY_HEAD_LOAD /* Head settle delay */
! 1236: + FDC_TRANSFER_BYTES_US ( FDC_NextSectorID_NbBytes () + 10 ); /* Add delay to read 3xA1, FE, ID field */
! 1237: }
! 1238: else
! 1239: {
1.1.1.15 root 1240: FDC.CommandState = FDCEMU_RUN_RESTORE_COMPLETE;
1241: Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
1.1.1.6 root 1242: }
1243: break;
1.1.1.17! root 1244: case FDCEMU_RUN_RESTORE_VERIFY_LOOP:
! 1245: FDC_VerifyTrack();
! 1246: FDC.CommandState = FDCEMU_RUN_RESTORE_COMPLETE;
! 1247: Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
! 1248: break;
1.1.1.6 root 1249: case FDCEMU_RUN_RESTORE_COMPLETE:
1.1.1.15 root 1250: Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6 root 1251: break;
1252: }
1.1.1.15 root 1253:
1254: return Delay_micro;
1.1 root 1255: }
1256:
1.1.1.2 root 1257:
1258: /*-----------------------------------------------------------------------*/
1.1.1.9 root 1259: /**
1260: * Run 'SEEK' command
1261: */
1.1.1.15 root 1262: static int FDC_UpdateSeekCmd ( void )
1.1 root 1263: {
1.1.1.15 root 1264: int Delay_micro = 0;
1265:
1266: FDC_Update_STR ( 0 , FDC_STR_BIT_SPIN_UP ); /* at this point, spin up sequence is ok */
1267:
1.1.1.6 root 1268: /* Which command is running? */
1.1.1.15 root 1269: switch (FDC.CommandState)
1.1.1.6 root 1270: {
1271: case FDCEMU_RUN_SEEK_TOTRACK:
1.1.1.15 root 1272: if ( FDC.TR == FDC.DR ) /* Are we at the selected track ? */
1273: {
1.1.1.17! root 1274: FDC.CommandState = FDCEMU_RUN_SEEK_VERIFY;
! 1275: Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE;
1.1.1.15 root 1276: }
1.1.1.6 root 1277: else
1278: {
1.1.1.15 root 1279: if ( FDC.DR < FDC.TR ) /* Set StepDirection to the correct value */
1280: FDC.StepDirection = -1;
1281: else
1282: FDC.StepDirection = 1;
1283:
1284: /* Move head by one track depending on FDC.StepDirection and update Track Register */
1285: FDC.TR += FDC.StepDirection;
1286:
1287: if ( ( HeadTrack[ FDC_DRIVE ] == FDC_PHYSICAL_MAX_TRACK ) && ( FDC.StepDirection == 1 ) )
1.1.1.17! root 1288: {
! 1289: FDC.CommandState = FDCEMU_RUN_SEEK_VERIFY;
! 1290: Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE; /* No delay if trying to go after max track */
! 1291: }
1.1.1.15 root 1292:
1293: else if ( ( HeadTrack[ FDC_DRIVE ] == 0 ) && ( FDC.StepDirection == -1 ) )
1294: {
1295: FDC.TR = 0; /* If we reach track 0, we stop there */
1.1.1.17! root 1296: FDC.CommandState = FDCEMU_RUN_SEEK_VERIFY;
! 1297: Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE;
1.1.1.15 root 1298: }
1299:
1.1.1.6 root 1300: else
1.1.1.15 root 1301: {
1302: HeadTrack[ FDC_DRIVE ] += FDC.StepDirection; /* Move physical head */
1303: Delay_micro = FDC_StepRate_ms[ FDC_STEP_RATE ] * 1000;
1304: }
1.1.1.6 root 1305: }
1.1.1.15 root 1306:
1307: if ( HeadTrack[ FDC_DRIVE ] == 0 )
1308: FDC_Update_STR ( 0 , FDC_STR_BIT_TR00 ); /* Set bit TR00 */
1309: else
1310: FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 ); /* Unset bit TR00 */
1311:
1.1.1.6 root 1312: break;
1.1.1.17! root 1313: case FDCEMU_RUN_SEEK_VERIFY:
1.1.1.15 root 1314: if ( FDC.CR & FDC_COMMAND_BIT_VERIFY )
1.1.1.17! root 1315: {
! 1316: FDC.CommandState = FDCEMU_RUN_SEEK_VERIFY_LOOP;
! 1317: Delay_micro = FDC_DELAY_HEAD_LOAD /* Head settle delay */
! 1318: + FDC_TRANSFER_BYTES_US ( FDC_NextSectorID_NbBytes () + 10 ); /* Add delay to read 3xA1, FE, ID field */
! 1319: }
! 1320: else
! 1321: {
! 1322: FDC.CommandState = FDCEMU_RUN_SEEK_COMPLETE;
! 1323: Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
! 1324: }
! 1325: break;
! 1326: case FDCEMU_RUN_SEEK_VERIFY_LOOP:
! 1327: FDC_VerifyTrack();
! 1328: FDC.CommandState = FDCEMU_RUN_SEEK_COMPLETE;
! 1329: Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
! 1330: break;
! 1331: case FDCEMU_RUN_SEEK_COMPLETE:
1.1.1.15 root 1332: Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6 root 1333: break;
1334: }
1.1.1.15 root 1335:
1336: return Delay_micro;
1.1 root 1337: }
1338:
1.1.1.2 root 1339:
1340: /*-----------------------------------------------------------------------*/
1.1.1.9 root 1341: /**
1342: * Run 'STEP' command
1343: */
1.1.1.15 root 1344: static int FDC_UpdateStepCmd ( void )
1.1 root 1345: {
1.1.1.15 root 1346: int Delay_micro = 0;
1347:
1348: FDC_Update_STR ( 0 , FDC_STR_BIT_SPIN_UP ); /* at this point, spin up sequence is ok */
1349:
1.1.1.6 root 1350: /* Which command is running? */
1.1.1.15 root 1351: switch (FDC.CommandState)
1.1.1.6 root 1352: {
1353: case FDCEMU_RUN_STEP_ONCE:
1.1.1.15 root 1354: /* Move head by one track depending on FDC.StepDirection */
1355: if ( FDC.CR & FDC_COMMAND_BIT_UPDATE_TRACK )
1356: FDC.TR += FDC.StepDirection; /* Update Track Register */
1357:
1358: if ( ( HeadTrack[ FDC_DRIVE ] == FDC_PHYSICAL_MAX_TRACK ) && ( FDC.StepDirection == 1 ) )
1.1.1.17! root 1359: Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE; /* No delay if trying to go after max track */
1.1.1.15 root 1360:
1361: else if ( ( HeadTrack[ FDC_DRIVE ] == 0 ) && ( FDC.StepDirection == -1 ) )
1.1.1.17! root 1362: Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE; /* No delay if trying to go before track 0 */
1.1.1.6 root 1363:
1.1.1.15 root 1364: else
1365: {
1366: HeadTrack[ FDC_DRIVE ] += FDC.StepDirection; /* Move physical head */
1367: Delay_micro = FDC_StepRate_ms[ FDC_STEP_RATE ] * 1000;
1368: }
1369:
1370: if ( HeadTrack[ FDC_DRIVE ] == 0 )
1371: FDC_Update_STR ( 0 , FDC_STR_BIT_TR00 ); /* Set bit TR00 */
1372: else
1373: FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 ); /* Unset bit TR00 */
1374:
1.1.1.17! root 1375: FDC.CommandState = FDCEMU_RUN_STEP_VERIFY;
! 1376: break;
! 1377: case FDCEMU_RUN_STEP_VERIFY:
! 1378: if ( FDC.CR & FDC_COMMAND_BIT_VERIFY )
! 1379: {
! 1380: FDC.CommandState = FDCEMU_RUN_STEP_VERIFY_LOOP;
! 1381: Delay_micro = FDC_DELAY_HEAD_LOAD /* Head settle delay */
! 1382: + FDC_TRANSFER_BYTES_US ( FDC_NextSectorID_NbBytes () + 10 ); /* Add delay to read 3xA1, FE, ID field */
! 1383: }
! 1384: else
! 1385: {
! 1386: FDC.CommandState = FDCEMU_RUN_STEP_COMPLETE;
! 1387: Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
! 1388: }
! 1389: break;
! 1390: case FDCEMU_RUN_STEP_VERIFY_LOOP:
! 1391: FDC_VerifyTrack();
1.1.1.15 root 1392: FDC.CommandState = FDCEMU_RUN_STEP_COMPLETE;
1.1.1.17! root 1393: Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
1.1.1.6 root 1394: break;
1395: case FDCEMU_RUN_STEP_COMPLETE:
1.1.1.15 root 1396: Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6 root 1397: break;
1398: }
1.1.1.15 root 1399:
1400: return Delay_micro;
1.1 root 1401: }
1402:
1.1.1.2 root 1403:
1404: /*-----------------------------------------------------------------------*/
1.1.1.9 root 1405: /**
1.1.1.15 root 1406: * Run 'READ SECTOR/S' command
1.1.1.9 root 1407: */
1.1.1.15 root 1408: static int FDC_UpdateReadSectorsCmd ( void )
1.1 root 1409: {
1.1.1.15 root 1410: int Delay_micro = 0;
1411: int FrameCycles, HblCounterVideo, LineCycles;
1412: int SectorSize;
1413:
1414: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1415:
1416:
1.1.1.6 root 1417: /* Which command is running? */
1.1.1.15 root 1418: switch (FDC.CommandState)
1.1.1.6 root 1419: {
1.1.1.15 root 1420: case FDCEMU_RUN_READSECTORS_READDATA:
1.1.1.17! root 1421: #ifdef no_spin
1.1.1.15 root 1422: /* TODO : for better FDC's emulation , we should measure the time it takes to spin the disk */
1423: /* until we reach the next sector header. In the best case, the head would be just at the start */
1.1.1.17! root 1424: /* of the sector header, which would mean 7 bytes to be read. */
! 1425: /* So, the delay will be at least 7 bytes; during that time, FDC.SR can be changed (Delirious Demo 4) */
! 1426: FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_CHECK_SECTOR_HEADER;
! 1427: Delay_micro = FDC_TRANSFER_BYTES_US ( 7 ); /* Min delay to read 3xA1, FE, TR, SIDE, SR */
! 1428:
! 1429: #else
! 1430: /* We search the sector FDC.SR during 5 revolutions max */
! 1431: FDC.CommandExpire_Time = CyclesGlobalClockCounter + FDC_DelayToCpuCycles ( FDC_DELAY_RNF );
! 1432:
! 1433: /* Read bytes to reach the next sector's ID field and skip 7 more bytes to reach SR in this ID field */
! 1434: Delay_micro = FDC_TRANSFER_BYTES_US ( FDC_NextSectorID_NbBytes () + 7 ); /* Add delay to read 3xA1, FE, TR, SIDE, SR */
! 1435: FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_CHECK_SECTOR_HEADER;
! 1436: #endif
1.1.1.15 root 1437: break;
1.1.1.17! root 1438:
1.1.1.15 root 1439: case FDCEMU_RUN_READSECTORS_READDATA_CHECK_SECTOR_HEADER:
1440: /* TODO : on a real FDC we should compare the sector header at the current */
1441: /* spin's position to see if it's the same as FDC.SR. If not, we should wait */
1442: /* for the next sector header and check again. After 5 revolutions, set RNF */
1443:
1.1.1.17! root 1444: #ifndef no_spin
! 1445: /* If we're looking for sector FDC.SR for more than 5 revolutions, we abort with RNF */
! 1446: if ( CyclesGlobalClockCounter > FDC.CommandExpire_Time )
! 1447: {
! 1448: FDC.CommandState = FDCEMU_RUN_READSECTORS_RNF;
! 1449: Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE;
! 1450: break;
! 1451: }
! 1452: #endif
! 1453:
! 1454: /* Check if the current ID Field is the one we're looking for */
! 1455: #ifdef no_spin
! 1456: if ( 1 )
! 1457: #else
! 1458: if ( FDC.NextSector_ID_Field_SR == FDC.SR )
! 1459: #endif
! 1460: {
! 1461: FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_TRANSFER_START;
! 1462: /* Read bytes to reach the sector's data : rest of ID field (length+crc) + GAP3a + GAP3b + 3xA1 + FB */
! 1463: Delay_micro = FDC_TRANSFER_BYTES_US ( 1+2 + FDC_TRACK_LAYOUT_STANDARD_GAP3a + FDC_TRACK_LAYOUT_STANDARD_GAP3b + 3 + 1 );
! 1464: }
! 1465: else
! 1466: {
! 1467: /* This is not the ID field we're looking for ; check the next one */
! 1468: Delay_micro = FDC_TRANSFER_BYTES_US ( FDC_NextSectorID_NbBytes () + 7 );
! 1469: FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_CHECK_SECTOR_HEADER;
! 1470: }
! 1471: break;
! 1472:
! 1473: case FDCEMU_RUN_READSECTORS_READDATA_TRANSFER_START:
1.1.1.15 root 1474: /* Read a single sector into temporary buffer (512 bytes for ST/MSA) */
1475: FDC_DMA_InitTransfer (); /* Update FDC_DMA.PosInBuffer */
1476: if ( FDC_ReadSectorFromFloppy ( DMADiskWorkSpace + FDC_DMA.PosInBuffer , FDC.SR , &SectorSize ) )
1477: {
1478: FDC_DMA.BytesToTransfer += SectorSize; /* 512 bytes per sector for ST/MSA disk images */
1479: FDC_DMA.PosInBuffer += SectorSize;
1480: FDC.ID_FieldLastSector = FDC.SR;
1.1.1.17! root 1481:
! 1482: FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_TRANSFER_LOOP;
1.1.1.15 root 1483: Delay_micro = FDC_DELAY_TRANSFER_DMA_16; /* Transfer blocks of 16 bytes from the sector we just read */
1484: }
1485: else /* Sector FDC.SR was not found */
1486: {
1487: FDC.CommandState = FDCEMU_RUN_READSECTORS_RNF;
1.1.1.17! root 1488: Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE;
1.1.1.15 root 1489: }
1490: break;
1.1.1.17! root 1491: case FDCEMU_RUN_READSECTORS_READDATA_TRANSFER_LOOP:
! 1492: /* Transfer the sector as blocks of 16 bytes using DMA */
1.1.1.15 root 1493: if ( ! FDC_DMA_ReadFromFloppy () )
1494: {
1495: Delay_micro = FDC_DELAY_TRANSFER_DMA_16; /* Continue transferring blocks of 16 bytes */
1496: }
1.1.1.17! root 1497: else /* Sector transferred, check the CRC */
1.1.1.15 root 1498: {
1.1.1.17! root 1499: FDC.CommandState = FDCEMU_RUN_READSECTORS_CRC;
! 1500: Delay_micro = FDC_TRANSFER_BYTES_US ( 2 ); /* Read 2 bytes for CRC */
! 1501: }
! 1502: break;
! 1503: case FDCEMU_RUN_READSECTORS_CRC:
! 1504: /* Sector completely transferred, CRC is always good for ST/MSA. Check for multi bit */
! 1505: if ( FDC.CR & FDC_COMMAND_BIT_MULTIPLE_SECTOR )
! 1506: {
! 1507: FDC.SR++; /* Try to read next sector and set RNF if not possible */
! 1508: FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA;
! 1509: Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE;
! 1510: }
! 1511: else /* Multi=0, stop here with no error */
! 1512: {
! 1513: FDC.CommandState = FDCEMU_RUN_READSECTORS_COMPLETE;
! 1514: Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
1.1.1.15 root 1515: }
1516: break;
1517: case FDCEMU_RUN_READSECTORS_RNF:
1518: LOG_TRACE(TRACE_FDC, "fdc type II read sector=%d track=%d drive=%d RNF VBL=%d video_cyc=%d %d@%d pc=%x\n",
1519: FDC.SR , HeadTrack[ FDC_DRIVE ] , FDC_DRIVE , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.6 root 1520:
1.1.1.15 root 1521: FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );
1522: Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6 root 1523: break;
1.1.1.15 root 1524: case FDCEMU_RUN_READSECTORS_COMPLETE:
1525: Delay_micro = FDC_CmdCompleteCommon( true );
1526: break;
1527: }
1528:
1529: return Delay_micro;
1530: }
1531:
1532:
1533: /*-----------------------------------------------------------------------*/
1534: /**
1535: * Run 'WRITE SECTOR/S' command
1536: */
1537: static int FDC_UpdateWriteSectorsCmd ( void )
1538: {
1539: int Delay_micro = 0;
1540: int FrameCycles, HblCounterVideo, LineCycles;
1541: int SectorSize;
1542:
1543: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1544:
1545: if ( Floppy_IsWriteProtected ( FDC_DRIVE ) )
1546: {
1547: LOG_TRACE(TRACE_FDC, "fdc type II write sector=%d track=%d drive=%d WPRT VBL=%d video_cyc=%d %d@%d pc=%x\n",
1548: FDC.SR , HeadTrack[ FDC_DRIVE ] , FDC_DRIVE , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1549:
1550: FDC_Update_STR ( 0 , FDC_STR_BIT_WPRT ); /* Set WPRT bit */
1551: Delay_micro = FDC_CmdCompleteCommon( true );
1552: }
1553: else
1554: FDC_Update_STR ( FDC_STR_BIT_WPRT , 0 ); /* Unset WPRT bit */
1555:
1556:
1557: /* Which command is running? */
1558: switch (FDC.CommandState)
1559: {
1560: case FDCEMU_RUN_WRITESECTORS_WRITEDATA:
1.1.1.17! root 1561: #ifdef no_spin
1.1.1.15 root 1562: /* TODO : for better FDC's emulation , we should measure the time it takes to spin the disk */
1563: /* until we reach the next sector header. In the best case, the head would be just at the start */
1.1.1.17! root 1564: /* of the sector header, which would mean 7 bytes to be read. */
! 1565: /* So, the delay will be at least 7 bytes; during that time, FDC.SR can be changed (Delirious Demo 4) */
! 1566: FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_CHECK_SECTOR_HEADER;
! 1567: Delay_micro = FDC_TRANSFER_BYTES_US ( 7 ); /* Min delay to read 3xA1, FE, TR, SIDE, SR */
! 1568:
! 1569: #else
! 1570: /* We search the sector FDC.SR during 5 revolutions max */
! 1571: FDC.CommandExpire_Time = CyclesGlobalClockCounter + FDC_DelayToCpuCycles ( FDC_DELAY_RNF );
! 1572:
! 1573: /* Read bytes to reach the next sector's ID field and skip 7 more bytes to reach SR in this ID field */
! 1574: Delay_micro = FDC_TRANSFER_BYTES_US ( FDC_NextSectorID_NbBytes () + 7 ); /* Add delay to read 3xA1, FE, TR, SIDE, SR */
! 1575: FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_CHECK_SECTOR_HEADER;
! 1576: #endif
1.1.1.15 root 1577: break;
1.1.1.17! root 1578:
1.1.1.15 root 1579: case FDCEMU_RUN_WRITESECTORS_WRITEDATA_CHECK_SECTOR_HEADER:
1580: /* TODO : on a real FDC we should compare the sector header at the current */
1581: /* spin's position to see if it's the same as FDC.SR. If not, we should wait */
1582: /* for the next sector header and check again. After 5 revolutions, set RNF */
1583:
1.1.1.17! root 1584: #ifndef no_spin
! 1585: /* If we're looking for sector FDC.SR for more than 5 revolutions, we abort with RNF */
! 1586: if ( CyclesGlobalClockCounter > FDC.CommandExpire_Time )
! 1587: {
! 1588: FDC.CommandState = FDCEMU_RUN_READSECTORS_RNF;
! 1589: Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE;
! 1590: break;
! 1591: }
! 1592: #endif
! 1593:
! 1594: /* Check if the current ID Field is the one we're looking for */
! 1595: #ifdef no_spin
! 1596: if ( 1 )
! 1597: #else
! 1598: if ( FDC.NextSector_ID_Field_SR == FDC.SR )
! 1599: #endif
! 1600: {
! 1601: FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_TRANSFER_START;
! 1602: /* Read bytes to reach the sector's data : rest of ID field (length+crc) + GAP3a + GAP3b + 3xA1 + FB */
! 1603: Delay_micro = FDC_TRANSFER_BYTES_US ( 1+2 + FDC_TRACK_LAYOUT_STANDARD_GAP3a + FDC_TRACK_LAYOUT_STANDARD_GAP3b + 3 + 1 );
! 1604: }
! 1605: else
! 1606: {
! 1607: /* This is not the ID field we're looking for ; check the next one */
! 1608: Delay_micro = FDC_TRANSFER_BYTES_US ( FDC_NextSectorID_NbBytes () + 7 );
! 1609: FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_CHECK_SECTOR_HEADER;
! 1610: }
! 1611: break;
! 1612:
! 1613: case FDCEMU_RUN_WRITESECTORS_WRITEDATA_TRANSFER_START:
1.1.1.15 root 1614: /* Write a single sector from RAM (512 bytes for ST/MSA) */
1615: FDC_DMA_InitTransfer (); /* Update FDC_DMA.PosInBuffer */
1616: if ( FDC_WriteSectorToFloppy ( FDC_DMA.SectorCount , FDC.SR , &SectorSize ) )
1617: {
1618: FDC_DMA.BytesToTransfer += SectorSize; /* 512 bytes per sector for ST/MSA disk images */
1619: FDC_DMA.PosInBuffer += SectorSize;
1620: FDC.ID_FieldLastSector = FDC.SR;
1621:
1.1.1.17! root 1622: FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_TRANSFER_LOOP;
1.1.1.15 root 1623: Delay_micro = FDC_DELAY_TRANSFER_DMA_16; /* Transfer blocks of 16 bytes from the sector we just wrote */
1624: }
1625: else /* Sector FDC.SR was not found */
1626: {
1.1.1.17! root 1627: FDC.CommandState = FDCEMU_RUN_WRITESECTORS_RNF;
! 1628: Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE;
1.1.1.15 root 1629: }
1630: break;
1.1.1.17! root 1631: case FDCEMU_RUN_WRITESECTORS_WRITEDATA_TRANSFER_LOOP:
! 1632: /* Transfer the sector as blocks of 16 bytes using DMA */
1.1.1.15 root 1633: if ( ! FDC_DMA_WriteToFloppy () )
1634: {
1635: Delay_micro = FDC_DELAY_TRANSFER_DMA_16; /* Continue transferring blocks of 16 bytes */
1636: }
1.1.1.17! root 1637: else /* Sector transferred, check the CRC */
1.1.1.15 root 1638: {
1.1.1.17! root 1639: FDC.CommandState = FDCEMU_RUN_WRITESECTORS_CRC;
! 1640: Delay_micro = FDC_TRANSFER_BYTES_US ( 2 ); /* Write 2 bytes for CRC */
! 1641: }
! 1642: break;
! 1643: case FDCEMU_RUN_WRITESECTORS_CRC:
! 1644: /* Sector completely transferred, CRC is always good for ST/MSA. Check for multi bit */
! 1645: if ( FDC.CR & FDC_COMMAND_BIT_MULTIPLE_SECTOR )
! 1646: {
! 1647: FDC.SR++; /* Try to write next sector and set RNF if not possible */
! 1648: FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA;
! 1649: Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE;
! 1650: }
! 1651: else /* Multi=0, stop here with no error */
! 1652: {
! 1653: FDC.CommandState = FDCEMU_RUN_WRITESECTORS_COMPLETE;
! 1654: Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
1.1.1.15 root 1655: }
1656: break;
1657: case FDCEMU_RUN_WRITESECTORS_RNF:
1658: LOG_TRACE(TRACE_FDC, "fdc type II write sector=%d track=%d drive=%d RNF VBL=%d video_cyc=%d %d@%d pc=%x\n",
1659: FDC.SR , HeadTrack[ FDC_DRIVE ] , FDC_DRIVE , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1660:
1661: FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );
1662: Delay_micro = FDC_CmdCompleteCommon( true );
1663: break;
1664: case FDCEMU_RUN_WRITESECTORS_COMPLETE:
1665: Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6 root 1666: break;
1667: }
1.1.1.15 root 1668:
1669: return Delay_micro;
1.1 root 1670: }
1671:
1.1.1.2 root 1672:
1673: /*-----------------------------------------------------------------------*/
1.1.1.9 root 1674: /**
1.1.1.15 root 1675: * Run 'READ ADDRESS' command
1.1.1.9 root 1676: */
1.1.1.15 root 1677: static int FDC_UpdateReadAddressCmd ( void )
1.1 root 1678: {
1.1.1.15 root 1679: int Delay_micro = 0;
1680: Uint16 CRC;
1681: Uint8 buf[ 4+6 ];
1682: Uint8 *p;
1.1.1.17! root 1683: int FrameCycles, HblCounterVideo, LineCycles;
! 1684:
! 1685: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1.1.1.15 root 1686:
1687: if ( ! EmulationDrives[FDC_DRIVE].bDiskInserted ) /* Set RNF bit if no disk is inserted */
1688: {
1689: FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );
1.1.1.17! root 1690: return FDC_CmdCompleteCommon( true );
1.1.1.15 root 1691: }
1692:
1.1.1.6 root 1693: /* Which command is running? */
1.1.1.15 root 1694: switch (FDC.CommandState)
1.1.1.6 root 1695: {
1.1.1.17! root 1696: #ifdef old_read_addr
! 1697: int Sector;
1.1.1.15 root 1698: case FDCEMU_RUN_READADDRESS:
1699: Sector = FDC.ID_FieldLastSector + 1; /* Increase sector from latest ID Field */
1700: if ( Sector > FDC_GetSectorsPerTrack ( HeadTrack[ FDC_DRIVE ] , FDC_SIDE ) )
1701: Sector = 1;
1702:
1703: /* In the case of Hatari, only ST/MSA images are supported, so we build */
1704: /* a simplified ID field based on current track/sector/side */
1705: p = buf;
1706: *p++ = 0xa1; /* SYNC bytes and IAM byte are included in the CRC */
1707: *p++ = 0xa1;
1708: *p++ = 0xa1;
1709: *p++ = 0xfe;
1710: *p++ = HeadTrack[ FDC_DRIVE ];
1711: FDC.SR = HeadTrack[ FDC_DRIVE ]; /* The 1st byte of the ID field is also copied into Sector Register */
1712: *p++ = FDC_SIDE;
1713: *p++ = Sector;
1714: *p++ = FDC_SECTOR_SIZE_512; /* ST/MSA images are 512 bytes per sector */
1715:
1716: FDC_CRC16 ( buf , 8 , &CRC );
1717:
1718: *p++ = CRC >> 8;
1719: *p++ = CRC & 0xff;
1720:
1721: FDC_DMA_InitTransfer (); /* Update FDC_DMA.PosInBuffer */
1722: memcpy ( DMADiskWorkSpace + FDC_DMA.PosInBuffer , buf + 4 , 6 ); /* Don't return the 3 x $A1 and $FE in the Address Field */
1723: FDC_DMA.BytesToTransfer += 6; /* 6 bytes per ID field */
1724: FDC_DMA.PosInBuffer += 6;
1725:
1726: FDC.CommandState = FDCEMU_RUN_READADDRESS_DMA;
1727:
1728: /* Very simplified method to get correct timings when doing a Read Address just after an index pulse */
1729: /* or after a previous Read Address. The right method is to use a timer to count bytes since the */
1730: /* latest index pulse, but this would add too much complexity just to handle ST/MSA disk images. */
1731: /* So we use a simpler method where ID_FieldLastSector is set to 0 when we simulate an index pulse. */
1732: /* The number of bytes to skip should be exactly the same as the GAPs used in ReadTrack */
1733: /* (allow Procopy to analyze an ST/MSA disk with the correct timings) */
1734: if ( FDC.ID_FieldLastSector == 0 ) /* First Read Address just after an index pulse */
1735: Delay_micro = FDC_TRANSFER_BYTES_US ( 72 + 3 + 1 + 6 ); /* Skip 72+3+1 bytes then read 6 bytes */
1736: else /* Read Address after a previous sector was just read */
1737: Delay_micro = FDC_TRANSFER_BYTES_US ( 614 + 6 ); /* Skip 614 bytes then read 6 bytes */
1.1.1.6 root 1738:
1.1.1.15 root 1739: FDC.ID_FieldLastSector = Sector;
1.1.1.6 root 1740: break;
1.1.1.15 root 1741: case FDCEMU_RUN_READADDRESS_DMA:
1742: FDC_DMA_ReadFromFloppy (); /* Transfer bytes if 16 bytes or more are in the DMA buffer */
1743:
1744: FDC.CommandState = FDCEMU_RUN_READADDRESS_COMPLETE;
1745: Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
1746: break;
1.1.1.17! root 1747:
! 1748: #else
! 1749: case FDCEMU_RUN_READADDRESS:
! 1750: /* Read bytes to reach the next sector's ID field and add 10 more bytes to read this ID field */
! 1751: Delay_micro = FDC_TRANSFER_BYTES_US ( FDC_NextSectorID_NbBytes () + 10 ); /* Add delay to read 3xA1, FE, ID field */
! 1752: FDC.CommandState = FDCEMU_RUN_READADDRESS_DMA;
! 1753: break;
! 1754:
! 1755: case FDCEMU_RUN_READADDRESS_DMA:
! 1756: /* In the case of Hatari, only ST/MSA images are supported, so we build */
! 1757: /* a standard ID field with a valid CRC based on current track/sector/side */
! 1758: p = buf;
! 1759: *p++ = 0xa1; /* SYNC bytes and IAM byte are included in the CRC */
! 1760: *p++ = 0xa1;
! 1761: *p++ = 0xa1;
! 1762: *p++ = 0xfe;
! 1763: *p++ = HeadTrack[ FDC_DRIVE ];
! 1764: FDC.SR = HeadTrack[ FDC_DRIVE ]; /* The 1st byte of the ID field is also copied into Sector Register */
! 1765: *p++ = FDC_SIDE;
! 1766: *p++ = FDC.NextSector_ID_Field_SR;
! 1767: *p++ = FDC_SECTOR_SIZE_512; /* ST/MSA images are 512 bytes per sector */
! 1768:
! 1769: FDC_CRC16 ( buf , 8 , &CRC );
! 1770:
! 1771: *p++ = CRC >> 8;
! 1772: *p++ = CRC & 0xff;
! 1773:
! 1774: 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",
! 1775: buf[4] , buf[5] , buf[6] , buf[7] , buf[8] , buf[9] ,
! 1776: nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
! 1777:
! 1778: FDC_DMA_InitTransfer (); /* Update FDC_DMA.PosInBuffer */
! 1779: memcpy ( DMADiskWorkSpace + FDC_DMA.PosInBuffer , buf + 4 , 6 ); /* Don't return the 3 x $A1 and $FE in the Address Field */
! 1780: FDC_DMA.BytesToTransfer += 6; /* 6 bytes per ID field */
! 1781: FDC_DMA.PosInBuffer += 6;
! 1782:
! 1783: FDC_DMA_ReadFromFloppy (); /* Transfer bytes if 16 bytes or more are in the DMA buffer */
! 1784:
! 1785: FDC.CommandState = FDCEMU_RUN_READADDRESS_COMPLETE;
! 1786: Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
! 1787: break;
! 1788: #endif
! 1789:
1.1.1.15 root 1790: case FDCEMU_RUN_READADDRESS_COMPLETE:
1791: Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6 root 1792: break;
1793: }
1.1.1.15 root 1794:
1795: return Delay_micro;
1.1 root 1796: }
1797:
1.1.1.2 root 1798:
1799: /*-----------------------------------------------------------------------*/
1.1.1.9 root 1800: /**
1.1.1.15 root 1801: * Run 'READ TRACK' command
1.1.1.9 root 1802: */
1.1.1.15 root 1803: static int FDC_UpdateReadTrackCmd ( void )
1.1 root 1804: {
1.1.1.15 root 1805: int Delay_micro = 0;
1806: Uint16 CRC;
1807: Uint8 *buf;
1808: Uint8 *buf_crc;
1809: int Sector;
1810: int SectorSize;
1811: int i;
1812:
1813: if ( ! EmulationDrives[FDC_DRIVE].bDiskInserted ) /* Set RNF bit if no disk is inserted */
1814: {
1815: FDC_Update_STR ( 0 , FDC_STR_BIT_RNF ); /* [NP] Should we return random bytes instead ? */
1.1.1.17! root 1816: return FDC_CmdCompleteCommon( true );
1.1.1.15 root 1817: }
1818:
1819:
1.1.1.6 root 1820: /* Which command is running? */
1.1.1.15 root 1821: switch (FDC.CommandState)
1.1.1.6 root 1822: {
1.1.1.15 root 1823: case FDCEMU_RUN_READTRACK:
1.1.1.17! root 1824: FDC.CommandState = FDCEMU_RUN_READTRACK_INDEX;
! 1825: Delay_micro = FDC_TRANSFER_BYTES_US ( FDC_NextIndexPulse_NbBytes () ); /* Wait for the next index pulse */
! 1826: break;
! 1827: case FDCEMU_RUN_READTRACK_INDEX:
1.1.1.15 root 1828: /* Build the track data */
1829: FDC_DMA_InitTransfer (); /* Update FDC_DMA.PosInBuffer */
1830: buf = DMADiskWorkSpace + FDC_DMA.PosInBuffer;
1.1.1.6 root 1831:
1.1.1.15 root 1832: if ( ( FDC_SIDE == 1 ) /* Try to read side 1 on a disk that doesn't have 2 sides */
1833: && ( FDC_GetSidesPerDisk ( HeadTrack[ FDC_DRIVE ] ) != 2 ) )
1834: {
1835: for ( i=0 ; i<FDC_TRACK_BYTES_STANDARD ; i++ )
1836: *buf++ = rand() & 0xff; /* Fill the track buffer with random bytes */
1.1.1.6 root 1837: }
1.1.1.15 root 1838:
1839: else /* Track/side available in the disk image */
1.1.1.6 root 1840: {
1.1.1.17! root 1841: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP1 ; i++ ) /* GAP1 */
! 1842: *buf++ = 0x4e;
1.1.1.15 root 1843:
1844: for ( Sector=1 ; Sector <= FDC_GetSectorsPerTrack ( HeadTrack[ FDC_DRIVE ] , FDC_SIDE ) ; Sector++ )
1845: {
1.1.1.17! root 1846: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP2 ; i++ ) /* GAP2 */
! 1847: *buf++ = 0x00;
1.1.1.15 root 1848:
1849: buf_crc = buf;
1850: for ( i=0 ; i<3 ; i++ ) *buf++ = 0xa1; /* SYNC (write $F5) */
1851: *buf++ = 0xfe; /* Index Address Mark */
1852: *buf++ = HeadTrack[ FDC_DRIVE ]; /* Track */
1853: *buf++ = FDC_SIDE; /* Side */
1854: *buf++ = Sector; /* Sector */
1855: FDC.ID_FieldLastSector = Sector;
1856: *buf++ = FDC_SECTOR_SIZE_512; /* 512 bytes/sector for ST/MSA */
1857: FDC_CRC16 ( buf_crc , buf - buf_crc , &CRC );
1858: *buf++ = CRC >> 8; /* CRC1 (write $F7) */
1859: *buf++ = CRC & 0xff; /* CRC2 */
1860:
1.1.1.17! root 1861: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP3a ; i++ ) /* GAP3a */
! 1862: *buf++ = 0x4e;
! 1863: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP3b ; i++ ) /* GAP3b */
! 1864: *buf++ = 0x00;
1.1.1.15 root 1865:
1866: buf_crc = buf;
1867: for ( i=0 ; i<3 ; i++ ) *buf++ = 0xa1; /* SYNC (write $F5) */
1868: *buf++ = 0xfb; /* Data Address Mark */
1869:
1870: if ( ! FDC_ReadSectorFromFloppy ( buf , Sector , &SectorSize ) ) /* Read a single 512 bytes sector into temporary buffer */
1871: {
1872: /* Do nothing in case of error, we could put some random bytes, but this case should */
1873: /* not happen with ST/MSA disk images, all sectors should be present on each track. */
1874: }
1875: buf += SectorSize;
1876:
1877: FDC_CRC16 ( buf_crc , buf - buf_crc , &CRC );
1878: *buf++ = CRC >> 8; /* CRC1 (write $F7) */
1879: *buf++ = CRC & 0xff; /* CRC2 */
1880:
1.1.1.17! root 1881: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP4 ; i++ ) /* GAP4 */
! 1882: *buf++ = 0x4e;
1.1.1.15 root 1883: }
1884:
1885: while ( buf < DMADiskWorkSpace + FDC_DMA.PosInBuffer + FDC_TRACK_BYTES_STANDARD ) /* Complete the track buffer */
1886: *buf++ = 0x4e; /* GAP5 */
1.1.1.6 root 1887: }
1.1 root 1888:
1.1.1.15 root 1889: /* Transfer Track data to RAM using DMA */
1890: FDC_DMA.BytesToTransfer += FDC_TRACK_BYTES_STANDARD;
1891: FDC_DMA.PosInBuffer += FDC_TRACK_BYTES_STANDARD;
1.1.1.2 root 1892:
1.1.1.15 root 1893: FDC.CommandState = FDCEMU_RUN_READTRACK_DMA;
1894: Delay_micro = FDC_DELAY_TRANSFER_DMA_16; /* Transfer blocks of 16 bytes from the track we just read */
1895: break;
1896: case FDCEMU_RUN_READTRACK_DMA:
1897: if ( ! FDC_DMA_ReadFromFloppy () )
1.1.1.6 root 1898: {
1.1.1.15 root 1899: Delay_micro = FDC_DELAY_TRANSFER_DMA_16; /* Continue transferring blocks of 16 bytes */
1.1.1.6 root 1900: }
1.1.1.17! root 1901: else /* Track completely transferred */
1.1.1.6 root 1902: {
1.1.1.15 root 1903: FDC.CommandState = FDCEMU_RUN_READTRACK_COMPLETE;
1904: Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
1.1.1.6 root 1905: }
1906: break;
1.1.1.15 root 1907: case FDCEMU_RUN_READTRACK_COMPLETE:
1908: Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6 root 1909: break;
1910: }
1.1.1.15 root 1911:
1912: return Delay_micro;
1.1 root 1913: }
1914:
1.1.1.2 root 1915:
1916: /*-----------------------------------------------------------------------*/
1.1.1.9 root 1917: /**
1.1.1.15 root 1918: * Common to types I, II and III
1919: *
1920: * Start motor / spin up sequence if needed
1.1.1.11 root 1921: */
1.1.1.15 root 1922:
1923: static int FDC_Check_MotorON ( Uint8 FDC_CR )
1.1.1.11 root 1924: {
1.1.1.15 root 1925: int FrameCycles, HblCounterVideo, LineCycles;
1926:
1927: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1928:
1929: if ( ( ( FDC_CR & FDC_COMMAND_BIT_MOTOR_ON ) == 0 ) /* Command wants motor on / spin up */
1930: && ( ( FDC.STR & FDC_STR_BIT_MOTOR_ON ) == 0 ) ) /* Motor on not enabled yet */
1.1.1.11 root 1931: {
1.1.1.15 root 1932: LOG_TRACE(TRACE_FDC, "fdc start motor VBL=%d video_cyc=%d %d@%d pc=%x\n",
1933: nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1934: FDC_Update_STR ( FDC_STR_BIT_SPIN_UP , FDC_STR_BIT_MOTOR_ON ); /* Unset spin up bit and set motor bit */
1.1.1.17! root 1935: FDC.UpdateIndexPulse = true;
1.1.1.15 root 1936: return FDC_DELAY_MOTOR_ON; /* Motor's delay */
1.1.1.11 root 1937: }
1.1.1.15 root 1938:
1939: /* Other cases : set bit in STR and don't add delay */
1940: LOG_TRACE(TRACE_FDC, "fdc motor already on VBL=%d video_cyc=%d %d@%d pc=%x\n",
1941: nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1942: FDC_Update_STR ( 0 , FDC_STR_BIT_MOTOR_ON );
1943: return 0;
1.1.1.11 root 1944: }
1945:
1946:
1947: /*-----------------------------------------------------------------------*/
1948: /**
1.1.1.9 root 1949: * Type I Commands
1950: *
1951: * Restore, Seek, Step, Step-In and Step-Out
1952: */
1.1 root 1953:
1.1.1.2 root 1954:
1955: /*-----------------------------------------------------------------------*/
1.1.1.15 root 1956: static int FDC_TypeI_Restore(void)
1.1 root 1957: {
1.1.1.15 root 1958: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12 root 1959:
1960: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1961:
1.1.1.17! root 1962: 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",
! 1963: ( FDC.CR & FDC_COMMAND_BIT_MOTOR_ON ) ? "off" : "on" ,
! 1964: ( FDC.CR & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
! 1965: FDC_StepRate_ms[ FDC_STEP_RATE ] ,
1.1.1.16 root 1966: FDC_DRIVE , FDC.TR , HeadTrack[ FDC_DRIVE ] , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10 root 1967:
1.1.1.6 root 1968: /* Set emulation to seek to track zero */
1.1.1.15 root 1969: FDC.Command = FDCEMU_CMD_RESTORE;
1970: FDC.CommandState = FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO;
1971:
1972: FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
1.1 root 1973:
1.1.1.15 root 1974: return FDC_DELAY_TYPE_I_PREPARE;
1.1 root 1975: }
1976:
1.1.1.2 root 1977:
1978: /*-----------------------------------------------------------------------*/
1.1.1.15 root 1979: static int FDC_TypeI_Seek ( void )
1.1 root 1980: {
1.1.1.15 root 1981: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12 root 1982:
1983: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1984:
1.1.1.17! root 1985: 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",
! 1986: FDC.DR,
! 1987: ( FDC.CR & FDC_COMMAND_BIT_MOTOR_ON ) ? "off" : "on" ,
! 1988: ( FDC.CR & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
! 1989: FDC_StepRate_ms[ FDC_STEP_RATE ] ,
! 1990: FDC_DRIVE , FDC.TR , HeadTrack[ FDC_DRIVE ] , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10 root 1991:
1.1.1.6 root 1992: /* Set emulation to seek to chosen track */
1.1.1.15 root 1993: FDC.Command = FDCEMU_CMD_SEEK;
1994: FDC.CommandState = FDCEMU_RUN_SEEK_TOTRACK;
1995:
1996: FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
1.1 root 1997:
1.1.1.15 root 1998: return FDC_DELAY_TYPE_I_PREPARE;
1.1 root 1999: }
2000:
1.1.1.2 root 2001:
2002: /*-----------------------------------------------------------------------*/
1.1.1.15 root 2003: static int FDC_TypeI_Step ( void )
1.1 root 2004: {
1.1.1.15 root 2005: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12 root 2006:
2007: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2008:
1.1.1.17! root 2009: 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",
! 2010: FDC.StepDirection,
! 2011: ( FDC.CR & FDC_COMMAND_BIT_MOTOR_ON ) ? "off" : "on" ,
! 2012: ( FDC.CR & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
! 2013: FDC_StepRate_ms[ FDC_STEP_RATE ] ,
! 2014: FDC_DRIVE , FDC.TR , HeadTrack[ FDC_DRIVE ] , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.15 root 2015:
2016: /* Set emulation to step (using same direction as latest seek executed, ie 'FDC.StepDirection') */
2017: FDC.Command = FDCEMU_CMD_STEP;
2018: FDC.CommandState = FDCEMU_RUN_STEP_ONCE;
1.1.1.10 root 2019:
1.1.1.15 root 2020: FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
1.1 root 2021:
1.1.1.15 root 2022: return FDC_DELAY_TYPE_I_PREPARE;
1.1 root 2023: }
2024:
1.1.1.2 root 2025:
2026: /*-----------------------------------------------------------------------*/
1.1.1.15 root 2027: static int FDC_TypeI_StepIn(void)
1.1 root 2028: {
1.1.1.15 root 2029: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12 root 2030:
2031: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2032:
1.1.1.17! root 2033: 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",
! 2034: ( FDC.CR & FDC_COMMAND_BIT_MOTOR_ON ) ? "off" : "on" ,
! 2035: ( FDC.CR & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
! 2036: FDC_StepRate_ms[ FDC_STEP_RATE ] ,
1.1.1.16 root 2037: FDC_DRIVE , FDC.TR , HeadTrack[ FDC_DRIVE ] , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10 root 2038:
1.1.1.15 root 2039: /* Set emulation to step in (direction = +1) */
2040: FDC.Command = FDCEMU_CMD_STEP;
2041: FDC.CommandState = FDCEMU_RUN_STEP_ONCE;
2042: FDC.StepDirection = 1; /* Increment track*/
1.1 root 2043:
1.1.1.15 root 2044: FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
2045:
2046: return FDC_DELAY_TYPE_I_PREPARE;
1.1 root 2047: }
2048:
1.1.1.2 root 2049:
2050: /*-----------------------------------------------------------------------*/
1.1.1.15 root 2051: static int FDC_TypeI_StepOut ( void )
1.1 root 2052: {
1.1.1.15 root 2053: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12 root 2054:
2055: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2056:
1.1.1.17! root 2057: 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",
! 2058: ( FDC.CR & FDC_COMMAND_BIT_MOTOR_ON ) ? "off" : "on" ,
! 2059: ( FDC.CR & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
! 2060: FDC_StepRate_ms[ FDC_STEP_RATE ] ,
1.1.1.16 root 2061: FDC_DRIVE , FDC.TR , HeadTrack[ FDC_DRIVE ] , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.15 root 2062:
2063: /* Set emulation to step out (direction = -1) */
2064: FDC.Command = FDCEMU_CMD_STEP;
2065: FDC.CommandState = FDCEMU_RUN_STEP_ONCE;
2066: FDC.StepDirection = -1; /* Decrement track */
1.1.1.10 root 2067:
1.1.1.15 root 2068: FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
1.1 root 2069:
1.1.1.15 root 2070: return FDC_DELAY_TYPE_I_PREPARE;
1.1 root 2071: }
2072:
1.1.1.2 root 2073:
2074: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2075: /**
2076: * Type II Commands
2077: *
1.1.1.15 root 2078: * Read Sector, Write Sector
1.1.1.9 root 2079: */
1.1 root 2080:
1.1.1.2 root 2081:
2082: /*-----------------------------------------------------------------------*/
1.1.1.15 root 2083: static int FDC_TypeII_ReadSector ( void )
1.1 root 2084: {
1.1.1.15 root 2085: int Delay_micro = 0;
2086: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12 root 2087:
2088: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2089:
1.1.1.17! root 2090: 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",
! 2091: FDC.SR, ( FDC.CR & FDC_COMMAND_BIT_MULTIPLE_SECTOR ) ? "on" : "off" ,
! 2092: ( FDC.CR & FDC_COMMAND_BIT_MOTOR_ON ) ? "off" : "on" ,
! 2093: ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
! 2094: FDC.TR , HeadTrack[ FDC_DRIVE ] , FDC_SIDE, FDC_DRIVE , FDC_DMA.SectorCount ,
1.1.1.15 root 2095: FDC_GetDMAAddress(), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.12 root 2096:
1.1.1.15 root 2097: /* Set emulation to read sector(s) */
2098: FDC.Command = FDCEMU_CMD_READSECTORS;
2099: FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA;
1.1.1.10 root 2100:
1.1.1.15 root 2101: FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
2102: | FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE | FDC_STR_BIT_WPRT , FDC_STR_BIT_BUSY );
1.1 root 2103:
1.1.1.15 root 2104: if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
2105: Delay_micro = FDC_DELAY_HEAD_LOAD;
2106:
2107: return FDC_DELAY_TYPE_II_PREPARE + Delay_micro;
1.1 root 2108: }
2109:
1.1.1.2 root 2110:
2111: /*-----------------------------------------------------------------------*/
1.1.1.15 root 2112: static int FDC_TypeII_WriteSector ( void )
1.1 root 2113: {
1.1.1.15 root 2114: int Delay_micro = 0;
2115: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12 root 2116:
2117: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2118:
1.1.1.17! root 2119: 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",
! 2120: FDC.SR, ( FDC.CR & FDC_COMMAND_BIT_MULTIPLE_SECTOR ) ? "on" : "off" ,
! 2121: ( FDC.CR & FDC_COMMAND_BIT_MOTOR_ON ) ? "off" : "on" ,
! 2122: ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
! 2123: FDC.TR , HeadTrack[ FDC_DRIVE ] , FDC_SIDE, FDC_DRIVE , FDC_DMA.SectorCount,
1.1.1.15 root 2124: FDC_GetDMAAddress(), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.2 root 2125:
1.1.1.15 root 2126: /* Set emulation to write a sector(s) */
2127: FDC.Command = FDCEMU_CMD_WRITESECTORS;
2128: FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA;
1.1.1.10 root 2129:
1.1.1.15 root 2130: FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
2131: | FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE , FDC_STR_BIT_BUSY );
1.1 root 2132:
1.1.1.15 root 2133: if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
2134: Delay_micro = FDC_DELAY_HEAD_LOAD;
2135:
2136: return FDC_DELAY_TYPE_II_PREPARE + Delay_micro;
1.1 root 2137: }
2138:
1.1.1.2 root 2139:
2140: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2141: /**
2142: * Type III Commands
2143: *
2144: * Read Address, Read Track, Write Track
2145: */
1.1 root 2146:
1.1.1.2 root 2147:
2148: /*-----------------------------------------------------------------------*/
1.1.1.15 root 2149: static int FDC_TypeIII_ReadAddress ( void )
1.1 root 2150: {
1.1.1.15 root 2151: int Delay_micro = 0;
2152: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12 root 2153:
2154: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2155:
1.1.1.17! root 2156: 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",
! 2157: ( FDC.CR & FDC_COMMAND_BIT_MOTOR_ON ) ? "off" : "on" ,
! 2158: ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
1.1.1.16 root 2159: FDC.TR , HeadTrack[ FDC_DRIVE ], FDC_SIDE, FDC_DRIVE , FDC_GetDMAAddress(),
1.1.1.12 root 2160: nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10 root 2161:
1.1.1.11 root 2162: /* Set emulation to seek to track zero */
1.1.1.15 root 2163: FDC.Command = FDCEMU_CMD_READADDRESS;
2164: FDC.CommandState = FDCEMU_RUN_READADDRESS;
1.1.1.11 root 2165:
1.1.1.15 root 2166: FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
2167: | FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE | FDC_STR_BIT_WPRT , FDC_STR_BIT_BUSY );
2168:
2169: if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
2170: Delay_micro = FDC_DELAY_HEAD_LOAD;
2171:
2172: return FDC_DELAY_TYPE_III_PREPARE + Delay_micro;
1.1 root 2173: }
2174:
1.1.1.2 root 2175:
2176: /*-----------------------------------------------------------------------*/
1.1.1.15 root 2177: static int FDC_TypeIII_ReadTrack ( void )
1.1 root 2178: {
1.1.1.15 root 2179: int Delay_micro = 0;
2180: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12 root 2181:
2182: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2183:
1.1.1.17! root 2184: 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",
! 2185: ( FDC.CR & FDC_COMMAND_BIT_MOTOR_ON ) ? "off" : "on" ,
! 2186: ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
1.1.1.16 root 2187: FDC.TR , HeadTrack[ FDC_DRIVE ], FDC_SIDE, FDC_DRIVE , FDC_GetDMAAddress(),
1.1.1.15 root 2188: nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10 root 2189:
1.1.1.15 root 2190: /* Set emulation to read a single track */
2191: FDC.Command = FDCEMU_CMD_READTRACK;
2192: FDC.CommandState = FDCEMU_RUN_READTRACK;
1.1.1.5 root 2193:
1.1.1.15 root 2194: FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
2195: | FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE | FDC_STR_BIT_WPRT , FDC_STR_BIT_BUSY );
1.1.1.5 root 2196:
1.1.1.15 root 2197: if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
2198: Delay_micro = FDC_DELAY_HEAD_LOAD;
1.1 root 2199:
1.1.1.15 root 2200: return FDC_DELAY_TYPE_III_PREPARE + Delay_micro;
1.1 root 2201: }
2202:
1.1.1.2 root 2203:
2204: /*-----------------------------------------------------------------------*/
1.1.1.15 root 2205: static int FDC_TypeIII_WriteTrack ( void )
1.1 root 2206: {
1.1.1.15 root 2207: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12 root 2208:
2209: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2210:
1.1.1.17! root 2211: 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",
! 2212: ( FDC.CR & FDC_COMMAND_BIT_MOTOR_ON ) ? "off" : "on" ,
! 2213: ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
1.1.1.16 root 2214: FDC.TR , HeadTrack[ FDC_DRIVE ], FDC_SIDE, FDC_DRIVE , FDC_GetDMAAddress(),
1.1.1.15 root 2215: nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10 root 2216:
2217: Log_Printf(LOG_TODO, "FDC type III command 'write track' does not work yet!\n");
1.1.1.5 root 2218:
1.1.1.15 root 2219: /* FIXME: "Write track" should write all the sectors after extracting them from the track data */
1.1.1.5 root 2220:
1.1.1.6 root 2221: /* Set emulation to write a single track */
1.1.1.15 root 2222: FDC_Update_STR ( 0 , FDC_STR_BIT_RNF ); /* FIXME : Not supported yet, set RNF bit */
2223: FDC.Command = FDCEMU_CMD_NULL;
2224: FDC.CommandState = FDCEMU_RUN_NULL;
1.1 root 2225:
1.1.1.15 root 2226: return FDC_DELAY_TYPE_III_PREPARE;
1.1 root 2227: }
2228:
1.1.1.2 root 2229:
2230: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2231: /**
2232: * Type IV Commands
2233: *
2234: * Force Interrupt
2235: */
1.1 root 2236:
1.1.1.2 root 2237:
2238: /*-----------------------------------------------------------------------*/
1.1.1.15 root 2239: static int FDC_TypeIV_ForceInterrupt ( bool bCauseCPUInterrupt )
1.1 root 2240: {
1.1.1.15 root 2241: int Delay_micro;
2242: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12 root 2243:
2244: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2245:
1.1.1.15 root 2246: LOG_TRACE(TRACE_FDC, "fdc type IV force int 0x%x irq=%d index=%d VBL=%d video_cyc=%d %d@%dpc=%x\n",
2247: FDC.CR , ( FDC.CR & 0x8 ) >> 3 , ( FDC.CR & 0x4 ) >> 2 ,
1.1.1.12 root 2248: nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10 root 2249:
1.1.1.15 root 2250: /* For Type II/III commands, LOST DATA bit is never set (DRQ is always handled by the DMA) */
2251: /* (eg Super Monaco GP on Superior 65 : loader fails if LOST DATA is set when there're not enough DMA sectors to transfer bytes) */
2252: FDC_Update_STR ( FDC_STR_BIT_LOST_DATA , 0 ); /* Remove LOST DATA / TR00 bit */
2253:
2254: /* TR00 is updated when a type I command is interrupted or when no command was running */
2255: /* MOTOR ON is also set when a type I command is interrupted or when no command was running */
2256: /* (eg Knightmare on DBUG 24 : loader fails if motor is off because of the added delay to start it) */
2257: if ( ( ( FDC.STR & FDC_STR_BIT_BUSY ) == 0 ) /* No command running */
2258: || ( FDC.CommandType == 1 ) ) /* Or busy command is Type I */
2259: {
2260: if ( HeadTrack[ FDC_DRIVE ] == 0 )
2261: FDC_Update_STR ( 0 , FDC_STR_BIT_TR00 ); /* Set bit TR00 */
2262:
2263: FDC_Update_STR ( 0 , FDC_STR_BIT_MOTOR_ON ); /* Set Motor ON */
1.1.1.17! root 2264:
! 2265: if ( FDC_IndexPulse_GetState () )
! 2266: FDC_Update_STR ( 0 , FDC_STR_BIT_INDEX ); /* Set INDEX bit */
! 2267: else
! 2268: FDC_Update_STR ( FDC_STR_BIT_INDEX , 0 ); /* Unset INDEX bit */
1.1.1.15 root 2269: }
2270:
2271: /* Remove busy bit, ack int and stop the motor */
2272: Delay_micro = FDC_CmdCompleteCommon( bCauseCPUInterrupt );
1.1.1.6 root 2273:
1.1.1.15 root 2274: return FDC_DELAY_TYPE_IV_PREPARE + Delay_micro;
1.1 root 2275: }
2276:
1.1.1.2 root 2277:
2278: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2279: /**
2280: * Execute Type I commands
2281: */
1.1.1.15 root 2282: static int FDC_ExecuteTypeICommands ( void )
1.1 root 2283: {
1.1.1.15 root 2284: int Delay_micro = 0;
2285:
2286: FDC.CommandType = 1;
1.1.1.6 root 2287: MFP_GPIP |= 0x20;
1.1 root 2288:
1.1.1.6 root 2289: /* Check Type I Command */
1.1.1.15 root 2290: switch ( FDC.CR & 0xf0 )
1.1.1.6 root 2291: {
2292: case 0x00: /* Restore */
1.1.1.15 root 2293: Delay_micro = FDC_TypeI_Restore();
1.1.1.6 root 2294: break;
2295: case 0x10: /* Seek */
1.1.1.15 root 2296: Delay_micro = FDC_TypeI_Seek();
1.1.1.6 root 2297: break;
2298: case 0x20: /* Step */
2299: case 0x30:
1.1.1.15 root 2300: Delay_micro = FDC_TypeI_Step();
1.1.1.6 root 2301: break;
2302: case 0x40: /* Step-In */
2303: case 0x50:
1.1.1.15 root 2304: Delay_micro = FDC_TypeI_StepIn();
1.1.1.6 root 2305: break;
2306: case 0x60: /* Step-Out */
2307: case 0x70:
1.1.1.15 root 2308: Delay_micro = FDC_TypeI_StepOut();
1.1.1.6 root 2309: break;
2310: }
1.1 root 2311:
1.1.1.15 root 2312: /* Check if motor needs to be started and add possible delay */
2313: Delay_micro += FDC_Check_MotorON ( FDC.CR );
2314:
2315: return Delay_micro;
1.1 root 2316: }
2317:
1.1.1.2 root 2318:
2319: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2320: /**
2321: * Execute Type II commands
2322: */
1.1.1.15 root 2323: static int FDC_ExecuteTypeIICommands ( void )
1.1 root 2324: {
1.1.1.15 root 2325: int Delay_micro = 0;
2326:
2327: FDC.CommandType = 2;
1.1.1.6 root 2328: MFP_GPIP |= 0x20;
1.1 root 2329:
1.1.1.6 root 2330: /* Check Type II Command */
1.1.1.15 root 2331: switch ( FDC.CR & 0xf0 )
1.1.1.6 root 2332: {
1.1.1.15 root 2333: case 0x80: /* Read Sector multi=0*/
2334: case 0x90: /* Read Sectors multi=1 */
2335: Delay_micro = FDC_TypeII_ReadSector();
1.1.1.6 root 2336: break;
1.1.1.15 root 2337: case 0xa0: /* Write Sector multi=0 */
2338: case 0xb0: /* Write Sectors multi=1 */
2339: Delay_micro = FDC_TypeII_WriteSector();
1.1.1.6 root 2340: break;
2341: }
1.1 root 2342:
1.1.1.15 root 2343: /* Check if motor needs to be started and add possible delay */
2344: Delay_micro += FDC_Check_MotorON ( FDC.CR );
2345:
2346: return Delay_micro;
1.1 root 2347: }
2348:
1.1.1.2 root 2349:
2350: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2351: /**
2352: * Execute Type III commands
2353: */
1.1.1.15 root 2354: static int FDC_ExecuteTypeIIICommands ( void )
1.1 root 2355: {
1.1.1.15 root 2356: int Delay_micro = 0;
2357:
2358: FDC.CommandType = 3;
1.1.1.6 root 2359: MFP_GPIP |= 0x20;
1.1 root 2360:
1.1.1.6 root 2361: /* Check Type III Command */
1.1.1.15 root 2362: switch ( FDC.CR & 0xf0 )
1.1.1.6 root 2363: {
2364: case 0xc0: /* Read Address */
1.1.1.15 root 2365: Delay_micro = FDC_TypeIII_ReadAddress();
1.1.1.6 root 2366: break;
2367: case 0xe0: /* Read Track */
1.1.1.15 root 2368: Delay_micro = FDC_TypeIII_ReadTrack();
1.1.1.6 root 2369: break;
2370: case 0xf0: /* Write Track */
1.1.1.15 root 2371: Delay_micro = FDC_TypeIII_WriteTrack();
1.1.1.6 root 2372: break;
2373: }
1.1 root 2374:
1.1.1.15 root 2375: /* Check if motor need to be started and add possible delay */
2376: Delay_micro += FDC_Check_MotorON ( FDC.CR );
2377:
2378: return Delay_micro;
1.1 root 2379: }
2380:
1.1.1.2 root 2381:
2382: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2383: /**
2384: * Execute Type IV commands
2385: */
1.1.1.15 root 2386: static int FDC_ExecuteTypeIVCommands ( void )
1.1 root 2387: {
1.1.1.15 root 2388: int Delay_micro;
1.1 root 2389:
1.1.1.15 root 2390: /* Check Type IV command */
2391: /* Most of the time a 0xD8 command is followed by a 0xD0 command to clear the IRQ signal */
2392: if ( FDC.CR & 0x8 ) /* I3 set (0xD8) : immediate interrupt with IRQ */
2393: Delay_micro = FDC_TypeIV_ForceInterrupt ( true );
2394:
2395: else if ( FDC.CR & 0x4 ) /* I2 set (0xD4) : IRQ on next index pulse */
2396: {
2397: /* FIXME [NP] This is not complete, we should report */
2398: /* an interrupt each time the FDC sees an index pulse, not just once */
2399: FDC.ID_FieldLastSector = 0; /* We simulate an index pulse now */
2400: Delay_micro = FDC_TypeIV_ForceInterrupt ( true );
2401: }
2402:
2403: else /* I3-I2 clear (0xD0) : stop command without IRQ */
2404: {
2405: MFP_GPIP |= 0x20; /* reset IRQ signal */
2406: Delay_micro = FDC_TypeIV_ForceInterrupt ( false );
2407: }
2408:
2409: FDC.CommandType = 4; /* Change CommandType after interrupting the current command */
2410: return Delay_micro;
1.1 root 2411: }
2412:
1.1.1.2 root 2413:
2414: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2415: /**
2416: * Find FDC command type and execute
2417: */
1.1.1.15 root 2418: static void FDC_ExecuteCommand ( void )
1.1 root 2419: {
1.1.1.15 root 2420: int Delay_micro;
2421:
1.1.1.6 root 2422: /* Check type of command and execute */
1.1.1.15 root 2423: if ( ( FDC.CR & 0x80 ) == 0 ) /* Type I - Restore, Seek, Step, Step-In, Step-Out */
2424: Delay_micro = FDC_ExecuteTypeICommands();
2425: else if ( ( FDC.CR & 0x40 ) == 0 ) /* Type II - Read Sector, Write Sector */
2426: Delay_micro = FDC_ExecuteTypeIICommands();
2427: else if ( ( FDC.CR & 0xf0 ) != 0xd0 ) /* Type III - Read Address, Read Track, Write Track */
2428: Delay_micro = FDC_ExecuteTypeIIICommands();
2429: else /* Type IV - Force Interrupt */
2430: Delay_micro = FDC_ExecuteTypeIVCommands();
1.1.1.9 root 2431:
1.1.1.15 root 2432: FDC.ReplaceCommandPossible = true; /* This new command can be replaced during the Delay_micro phase */
1.1.1.17! root 2433: FDC_StartTimer_micro ( Delay_micro , 0 );
1.1 root 2434: }
2435:
1.1.1.2 root 2436:
2437: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2438: /**
1.1.1.15 root 2439: * Write to SectorCount register $ff8604
1.1.1.9 root 2440: */
1.1.1.15 root 2441: static void FDC_WriteSectorCountRegister ( void )
1.1 root 2442: {
1.1.1.12 root 2443: int FrameCycles, HblCounterVideo, LineCycles;
2444:
2445: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2446:
1.1.1.15 root 2447: LOG_TRACE(TRACE_FDC, "fdc write 8604 dma sector count=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
2448: IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.9 root 2449:
1.1.1.15 root 2450: FDC_DMA.SectorCount = IoMem_ReadByte(0xff8605);
1.1 root 2451: }
2452:
1.1.1.2 root 2453:
2454: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2455: /**
1.1.1.15 root 2456: * Write to Command register $ff8604
1.1.1.9 root 2457: */
1.1.1.15 root 2458: static void FDC_WriteCommandRegister ( void )
1.1 root 2459: {
1.1.1.12 root 2460: int FrameCycles, HblCounterVideo, LineCycles;
2461:
2462: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2463:
2464: 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 2465: IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2466:
2467: /* If fdc is busy, only 'Force Interrupt' is possible */
2468: /* [NP] : it's also possible to start a new command just after another command */
2469: /* was started and spinup phase was not completed yet (or is this only possible during the 'prepare' delay ?) */
2470: /* FIXME : this delay was not measured, it should be at least 880 cycles for Overdrive Demos by Phalanx */
2471: /* For now, we allow to cancel the current command if we're in the prepare+spinup delay */
2472: if ( FDC.STR & FDC_STR_BIT_BUSY )
2473: {
2474: if ( ( IoMem_ReadByte(0xff8605) & 0xf0 ) == 0xd0 ) /* 'Force Interrupt' command */
2475: {
2476: 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",
2477: FDC.CR , IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2478: }
2479:
2480: else if ( FDC.ReplaceCommandPossible )
2481: {
2482: 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",
2483: FDC.CR , IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2484: }
2485:
2486: else /* Other cases : new command is ignored */
2487: {
2488: LOG_TRACE(TRACE_FDC, "fdc write 8604 fdc busy, command=0x%x ignored VBL=%d video_cyc=%d %d@%d pc=%x\n",
2489: IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2490: return;
2491: }
2492: }
1.1.1.9 root 2493:
1.1.1.16 root 2494:
2495: if ( ( ( IoMem_ReadByte(0xff8605) & 0xf0 ) != 0xd0 ) /* Type I, II and III commands */
2496: && ( !FDC_ValidFloppyDrive() ) )
2497: {
2498: LOG_TRACE(TRACE_FDC, "fdc write 8604 no drive selected, command=0x%x ignored VBL=%d video_cyc=%d %d@%d pc=%x\n",
2499: IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2500: return;
2501: }
2502:
1.1.1.15 root 2503: FDC.CR = IoMem_ReadByte(0xff8605);
1.1.1.6 root 2504: FDC_ExecuteCommand();
1.1 root 2505: }
2506:
1.1.1.2 root 2507:
2508: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2509: /**
1.1.1.15 root 2510: * Write to Track register $ff8604
1.1.1.9 root 2511: */
1.1.1.15 root 2512: static void FDC_WriteTrackRegister ( void )
1.1 root 2513: {
1.1.1.12 root 2514: int FrameCycles, HblCounterVideo, LineCycles;
2515:
2516: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2517:
2518: 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 2519: IoMem_ReadByte(0xff8605) , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1.1.9 root 2520:
1.1.1.15 root 2521: /* [NP] Contrary to what is written in the WD1772 doc, Track Register can be changed */
2522: /* while the fdc is busy */
2523: if ( FDC.STR & FDC_STR_BIT_BUSY )
2524: {
2525: 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",
2526: IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2527: }
2528:
2529: FDC.TR = IoMem_ReadByte(0xff8605);
1.1 root 2530: }
2531:
1.1.1.2 root 2532:
2533: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2534: /**
1.1.1.15 root 2535: * Write to Sector register $ff8604
1.1.1.9 root 2536: */
1.1.1.15 root 2537: static void FDC_WriteSectorRegister ( void )
1.1 root 2538: {
1.1.1.12 root 2539: int FrameCycles, HblCounterVideo, LineCycles;
2540:
2541: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2542:
2543: 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 2544: IoMem_ReadByte(0xff8605) , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
2545:
2546: /* [NP] Contrary to what is written in the WD1772 doc, Sector Register can be changed */
2547: /* while the fdc is busy (but it will have no effect once the sector's header is found) */
2548: /* (fix Delirious Demo IV's loader, which is bugged and set SR after starting the Read Sector command) */
2549: if ( FDC.STR & FDC_STR_BIT_BUSY )
2550: {
2551: 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",
2552: IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
2553: }
1.1.1.9 root 2554:
1.1.1.15 root 2555: FDC.SR = IoMem_ReadByte(0xff8605);
1.1 root 2556: }
2557:
1.1.1.2 root 2558:
2559: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2560: /**
1.1.1.15 root 2561: * Write to Data register $ff8604
1.1.1.9 root 2562: */
1.1.1.15 root 2563: static void FDC_WriteDataRegister ( void )
1.1 root 2564: {
1.1.1.12 root 2565: int FrameCycles, HblCounterVideo, LineCycles;
2566:
2567: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2568:
2569: 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 2570: IoMem_ReadByte(0xff8605), nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1.1.9 root 2571:
1.1.1.15 root 2572: FDC.DR = IoMem_ReadByte(0xff8605);
1.1 root 2573: }
2574:
1.1.1.2 root 2575:
2576: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2577: /**
1.1.1.15 root 2578: * Store byte in FDC registers or DMA sector count, when writing to $ff8604
1.1.1.9 root 2579: */
1.1.1.15 root 2580: void FDC_DiskController_WriteWord ( void )
1.1 root 2581: {
1.1.1.12 root 2582: int FrameCycles, HblCounterVideo, LineCycles;
2583:
1.1.1.15 root 2584: if ( nIoMemAccessSize == SIZE_BYTE )
1.1.1.6 root 2585: {
2586: /* This register does not like to be accessed in byte mode on a normal ST */
1.1.1.8 root 2587: M68000_BusError(IoAccessBaseAddress, BUS_ERROR_WRITE);
1.1.1.6 root 2588: return;
2589: }
2590:
1.1.1.8 root 2591: M68000_WaitState(4);
2592:
1.1.1.12 root 2593: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1.1.1.9 root 2594:
1.1.1.12 root 2595: 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 2596: IoMem_ReadWord(0xff8604), nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1.1.6 root 2597:
1.1.1.12 root 2598: /* Is it an ASCII HD command? */
1.1.1.15 root 2599: if ( ( FDC_DMA.Mode & 0x0018 ) == 8 )
1.1.1.12 root 2600: {
2601: /* Handle HDC functions */
2602: HDC_WriteCommandPacket();
1.1.1.10 root 2603: return;
1.1.1.12 root 2604: }
1.1.1.6 root 2605:
1.1.1.15 root 2606: /* Are we trying to set the SectorCount ? */
2607: if ( FDC_DMA.Mode & 0x10 ) /* Bit 4 */
1.1.1.6 root 2608: FDC_WriteSectorCountRegister();
2609: else
1.1.1.8 root 2610: {
2611: /* Write to FDC registers */
1.1.1.15 root 2612: switch ( FDC_DMA.Mode & 0x6 )
1.1.1.6 root 2613: { /* Bits 1,2 (A1,A0) */
1.1.1.15 root 2614: case 0x0: /* 0 0 - Command register */
1.1.1.6 root 2615: FDC_WriteCommandRegister();
2616: break;
1.1.1.15 root 2617: case 0x2: /* 0 1 - Track register */
1.1.1.6 root 2618: FDC_WriteTrackRegister();
2619: break;
1.1.1.15 root 2620: case 0x4: /* 1 0 - Sector register */
1.1.1.6 root 2621: FDC_WriteSectorRegister();
2622: break;
1.1.1.15 root 2623: case 0x6: /* 1 1 - Data register */
1.1.1.6 root 2624: FDC_WriteDataRegister();
2625: break;
2626: }
2627: }
1.1 root 2628: }
2629:
1.1.1.2 root 2630:
2631: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2632: /**
1.1.1.15 root 2633: * Return Status/FDC register when reading from $ff8604
1.1.1.9 root 2634: */
1.1.1.15 root 2635: void FDC_DiskControllerStatus_ReadWord ( void )
1.1 root 2636: {
1.1.1.15 root 2637: Uint16 DiskControllerByte = 0; /* Used to pass back the parameter */
1.1.1.12 root 2638: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.15 root 2639: int ForceWPRT;
1.1.1.6 root 2640:
2641: if (nIoMemAccessSize == SIZE_BYTE)
2642: {
2643: /* This register does not like to be accessed in byte mode on a normal ST */
1.1.1.8 root 2644: M68000_BusError(IoAccessBaseAddress, BUS_ERROR_READ);
1.1.1.6 root 2645: return;
2646: }
2647:
1.1.1.8 root 2648: M68000_WaitState(4);
2649:
1.1.1.15 root 2650: if ((FDC_DMA.Mode & 0x18) == 0x08) /* HDC status reg selected? */
1.1.1.6 root 2651: {
2652: /* return the HDC status reg */
1.1.1.15 root 2653: DiskControllerByte = HDC_GetCommandStatus();
1.1.1.6 root 2654: }
1.1.1.15 root 2655: else if ((FDC_DMA.Mode & 0x18) == 0x18) /* HDC sector counter??? */
1.1.1.8 root 2656: {
2657: Log_Printf(LOG_DEBUG, "*** Read HDC sector counter???\n");
1.1.1.15 root 2658: DiskControllerByte = HDC_GetSectorCount();
1.1.1.8 root 2659: }
1.1.1.6 root 2660: else
2661: {
1.1.1.15 root 2662: /* FDC code */
2663: switch (FDC_DMA.Mode & 0x6) /* Bits 1,2 (A1,A0) */
1.1.1.6 root 2664: {
1.1.1.15 root 2665: case 0x0: /* 0 0 - Status register */
2666: /* [NP] Contrary to what is written in the WD1772 doc, the WPRT bit */
2667: /* is updated after a Type I command */
2668: /* (eg : Procopy or Terminators Copy 1.68 do a Restore/Seek to test WPRT) */
2669: if ( FDC.CommandType == 1 )
1.1.1.6 root 2670: {
1.1.1.15 root 2671: if ( Floppy_IsWriteProtected ( FDC_DRIVE ) )
2672: FDC_Update_STR ( 0 , FDC_STR_BIT_WPRT ); /* Set WPRT bit */
2673: else
2674: FDC_Update_STR ( FDC_STR_BIT_WPRT , 0 ); /* Unset WPRT bit */
1.1.1.17! root 2675:
! 2676: if ( FDC_IndexPulse_GetState () )
! 2677: FDC_Update_STR ( 0 , FDC_STR_BIT_INDEX ); /* Set INDEX bit */
! 2678: else
! 2679: FDC_Update_STR ( FDC_STR_BIT_INDEX , 0 ); /* Unset INDEX bit */
1.1.1.6 root 2680: }
2681:
1.1.1.15 root 2682: /* When there's no disk in drive, the floppy drive hardware can't see */
2683: /* the difference with an inserted disk that would be write protected */
2684: if ( ! EmulationDrives[ FDC_DRIVE ].bDiskInserted )
2685: FDC_Update_STR ( 0 , FDC_STR_BIT_WPRT ); /* Set WPRT bit */
2686:
2687: DiskControllerByte = FDC.STR;
2688:
2689: /* Temporarily change the WPRT bit if we're in a transition phase */
2690: /* regarding the disk in the drive (inserting or ejecting) */
2691: ForceWPRT = Floppy_DriveTransitionUpdateState ( FDC_DRIVE );
2692: if ( ForceWPRT == 1 )
2693: DiskControllerByte |= FDC_STR_BIT_WPRT; /* Force setting WPRT */
2694: if ( ForceWPRT == -1 )
2695: DiskControllerByte &= ~FDC_STR_BIT_WPRT; /* Force clearing WPRT */
2696:
2697: if ( ForceWPRT != 0 )
2698: LOG_TRACE(TRACE_FDC, "force wprt=%d VBL=%d drive=%d str=%x\n", ForceWPRT==1?1:0, nVBLs, FDC_DRIVE, DiskControllerByte );
2699:
2700: /* When Status Register is read, FDC's INTRQ is reset */
1.1.1.6 root 2701: MFP_GPIP |= 0x20;
2702: break;
1.1.1.15 root 2703: case 0x2: /* 0 1 - Track register */
2704: DiskControllerByte = FDC.TR;
1.1.1.6 root 2705: break;
1.1.1.15 root 2706: case 0x4: /* 1 0 - Sector register */
2707: DiskControllerByte = FDC.SR;
1.1.1.6 root 2708: break;
1.1.1.15 root 2709: case 0x6: /* 1 1 - Data register */
2710: DiskControllerByte = FDC.DR;
1.1.1.6 root 2711: break;
2712: }
2713: }
2714:
1.1.1.7 root 2715: IoMem_WriteWord(0xff8604, DiskControllerByte);
1.1.1.9 root 2716:
1.1.1.12 root 2717: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2718:
2719: LOG_TRACE(TRACE_FDC, "fdc read 8604 ctrl status=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
2720: DiskControllerByte , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1 root 2721: }
2722:
1.1.1.2 root 2723:
2724: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2725: /**
1.1.1.15 root 2726: * Write word to $ff8606 (DMA Mode Control)
2727: *
2728: * Eg.
2729: * $80 - Selects command/status register
2730: * $82 - Selects track register
2731: * $84 - Selects sector register
1.1.1.17! root 2732: * $86 - Selects data register
1.1.1.15 root 2733: * NOTE - OR above values with $100 is transfer from memory to floppy
2734: * Also if bit 4 is set, write to DMA sector count register
2735: */
2736: void FDC_DmaModeControl_WriteWord ( void )
2737: {
2738: Uint16 Mode_prev; /* Store previous write to 0xff8606 for 'toggle' checks */
2739: int FrameCycles, HblCounterVideo, LineCycles;
2740:
2741:
2742: if (nIoMemAccessSize == SIZE_BYTE)
2743: {
2744: /* This register does not like to be accessed in byte mode on a normal ST */
2745: M68000_BusError(IoAccessBaseAddress, BUS_ERROR_WRITE);
2746: return;
2747: }
2748:
2749: Mode_prev = FDC_DMA.Mode; /* Store previous to check for _read/_write toggle (DMA reset) */
2750: FDC_DMA.Mode = IoMem_ReadWord(0xff8606); /* Store to DMA Mode control */
2751:
2752: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2753:
2754: LOG_TRACE(TRACE_FDC, "fdc write 8606 ctrl=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
2755: FDC_DMA.Mode , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
2756:
2757: /* When write to 0xff8606, check bit '8' toggle. This causes DMA status reset */
2758: if ((Mode_prev ^ FDC_DMA.Mode) & 0x0100)
2759: FDC_ResetDMA();
2760: }
2761:
2762:
2763: /*-----------------------------------------------------------------------*/
2764: /**
2765: * Read DMA Status at $ff8606
2766: *
2767: * Bit 0 - Error Status (0=Error)
2768: * Bit 1 - Sector Count Zero Status (0=Sector Count Zero)
2769: * Bit 2 - Data Request Inactive Status
2770: */
2771: void FDC_DmaStatus_ReadWord ( void )
2772: {
2773: if (nIoMemAccessSize == SIZE_BYTE)
2774: {
2775: /* This register does not like to be accessed in byte mode on a normal ST */
2776: M68000_BusError(IoAccessBaseAddress, BUS_ERROR_READ);
2777: return;
2778: }
2779:
2780: /* Set zero sector count */
2781: FDC_DMA.Status &= ~0x2; /* Clear bit 1 */
2782: if ( FDC_DMA.Mode & 0x08 ) /* Get which sector count ? */
2783: FDC_DMA.Status |= (HDC_GetSectorCount())?0x2:0; /* HDC */
2784: else
2785: FDC_DMA.Status |= (FDC_DMA.SectorCount)?0x2:0; /* FDC */
2786:
2787: /* In the case of the ST, DRQ is always 0 because it's handled by the DMA and its 16 bytes buffer */
2788:
2789: IoMem_WriteWord(0xff8606, FDC_DMA.Status);
2790: }
2791:
2792:
2793: /*-----------------------------------------------------------------------*/
2794: /**
2795: * Read hi/med/low DMA address byte at $ff8609/0b/0d
2796: */
2797: void FDC_DmaAddress_ReadByte ( void )
2798: {
2799: int FrameCycles, HblCounterVideo, LineCycles;
2800:
2801: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2802:
2803: 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" ,
2804: IoAccessCurrentAddress , IoMem[ IoAccessCurrentAddress ] , FDC_GetDMAAddress() ,
2805: nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
2806: }
2807:
2808:
2809: /*-----------------------------------------------------------------------*/
2810: /**
2811: * Write hi/med/low DMA address byte at $ff8609/0b/0d
2812: */
2813: void FDC_DmaAddress_WriteByte ( void )
2814: {
2815: int FrameCycles, HblCounterVideo, LineCycles;
2816:
2817: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2818:
2819: 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" ,
2820: IoAccessCurrentAddress , IoMem[ IoAccessCurrentAddress ] , FDC_GetDMAAddress() ,
2821: nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
2822: }
2823:
2824:
2825: /*-----------------------------------------------------------------------*/
2826: /**
2827: * Get DMA address used to transfer data between FDC and RAM
1.1.1.9 root 2828: */
1.1.1.15 root 2829: Uint32 FDC_GetDMAAddress(void)
1.1 root 2830: {
1.1.1.6 root 2831: Uint32 Address;
1.1 root 2832:
1.1.1.6 root 2833: /* Build up 24-bit address from hardware registers */
2834: Address = ((Uint32)STMemory_ReadByte(0xff8609)<<16) | ((Uint32)STMemory_ReadByte(0xff860b)<<8) | (Uint32)STMemory_ReadByte(0xff860d);
1.1 root 2835:
1.1.1.6 root 2836: return Address;
1.1 root 2837: }
2838:
1.1.1.2 root 2839:
2840: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2841: /**
1.1.1.15 root 2842: * Write a new address to the FDC DMA address registers at $ff8909/0b/0d
1.1.1.9 root 2843: */
1.1.1.15 root 2844: void FDC_WriteDMAAddress ( Uint32 Address )
1.1 root 2845: {
1.1.1.12 root 2846: int FrameCycles, HblCounterVideo, LineCycles;
2847:
2848: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2849:
2850: LOG_TRACE(TRACE_FDC, "fdc write 0x%x to dma address VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
2851: Address , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1.1.9 root 2852:
1.1.1.6 root 2853: /* Store as 24-bit address */
2854: STMemory_WriteByte(0xff8609, Address>>16);
2855: STMemory_WriteByte(0xff860b, Address>>8);
2856: STMemory_WriteByte(0xff860d, Address);
1.1 root 2857: }
2858:
1.1.1.2 root 2859:
2860: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2861: /**
2862: * Read sector from floppy drive into workspace
2863: * We copy the bytes in chunks to simulate reading of the floppy using DMA
2864: */
1.1.1.15 root 2865: static bool FDC_ReadSectorFromFloppy ( Uint8 *buf , Uint8 Sector , int *pSectorSize )
1.1 root 2866: {
1.1.1.12 root 2867: int FrameCycles, HblCounterVideo, LineCycles;
2868:
2869: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2870:
2871: LOG_TRACE(TRACE_FDC, "fdc read sector addr=0x%x dev=%d sect=%d track=%d side=%d VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
1.1.1.15 root 2872: FDC_GetDMAAddress(), FDC_DRIVE, Sector, HeadTrack[ FDC_DRIVE ], FDC_SIDE,
1.1.1.12 root 2873: nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1.1.9 root 2874:
1.1.1.15 root 2875: /* Copy 1 sector to our workspace */
2876: if ( Floppy_ReadSectors ( FDC_DRIVE, buf, Sector, HeadTrack[ FDC_DRIVE ], FDC_SIDE, 1, NULL, pSectorSize ) )
1.1.1.12 root 2877: return true;
1.1 root 2878:
1.1.1.6 root 2879: /* Failed */
1.1.1.12 root 2880: LOG_TRACE(TRACE_FDC, "fdc read sector failed\n" );
2881: return false;
1.1 root 2882: }
2883:
1.1.1.2 root 2884:
2885: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2886: /**
1.1.1.15 root 2887: * Write sector from RAM to floppy drive
1.1.1.9 root 2888: * We copy the bytes in chunks to simulate writing of the floppy using DMA
1.1.1.15 root 2889: * If DMASectorsCount==0, the DMA won't transfer any byte from RAM to the FDC
2890: * and some '0' bytes will be written to the disk.
1.1.1.9 root 2891: */
1.1.1.15 root 2892: static bool FDC_WriteSectorToFloppy ( int DMASectorsCount , Uint8 Sector , int *pSectorSize )
1.1 root 2893: {
1.1.1.15 root 2894: Uint8 *pBuffer;
1.1.1.12 root 2895: int FrameCycles, HblCounterVideo, LineCycles;
2896:
2897: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
2898:
2899: LOG_TRACE(TRACE_FDC, "fdc write sector addr=0x%x dev=%d sect=%d track=%d side=%d VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
1.1.1.15 root 2900: FDC_GetDMAAddress(), FDC_DRIVE, Sector, HeadTrack[ FDC_DRIVE ], FDC_SIDE,
1.1.1.12 root 2901: nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1.1.9 root 2902:
1.1.1.15 root 2903: if ( DMASectorsCount > 0 )
2904: pBuffer = &STRam[ FDC_GetDMAAddress() ];
2905: else
1.1.1.6 root 2906: {
1.1.1.15 root 2907: pBuffer = DMADiskWorkSpace; /* If DMA can't transfer data, we write '0' bytes */
2908: memset ( pBuffer , 0 , DMA_DISK_SECTOR_SIZE );
1.1.1.6 root 2909: }
1.1.1.15 root 2910:
2911: /* Write 1 sector from our workspace */
2912: if ( Floppy_WriteSectors ( FDC_DRIVE, pBuffer, Sector, HeadTrack[ FDC_DRIVE ], FDC_SIDE, 1, NULL, pSectorSize ) )
2913: return true;
1.1 root 2914:
1.1.1.6 root 2915: /* Failed */
1.1.1.12 root 2916: LOG_TRACE(TRACE_FDC, "fdc write sector failed\n" );
2917: return false;
1.1 root 2918: }
2919:
2920:
1.1.1.2 root 2921: /*-----------------------------------------------------------------------*/
1.1.1.9 root 2922: /**
2923: * Write to floppy mode/control (?) register (0xff860F).
2924: * Used on Falcon only!
2925: * FIXME: I've found hardly any documentation about this register, only
2926: * the following description of the bits:
2927: *
2928: * __________54__10 Floppy Controll-Register
2929: * || ||
2930: * || |+- Prescaler 1
2931: * || +-- Media detect 1
2932: * |+----- Prescaler 2
2933: * +------ Media detect 2
2934: *
2935: * For DD - disks: 0x00
2936: * For HD - disks: 0x03
2937: * for ED - disks: 0x30 (not supported by TOS)
2938: */
1.1.1.15 root 2939: void FDC_FloppyMode_WriteByte ( void )
1.1.1.9 root 2940: {
2941: // printf("Write to floppy mode reg.: 0x%02x\n", IoMem_ReadByte(0xff860f));
2942: }
2943:
2944:
2945: /*-----------------------------------------------------------------------*/
2946: /**
2947: * Read from floppy mode/control (?) register (0xff860F).
2948: * Used on Falcon only!
2949: * FIXME: I've found hardly any documentation about this register, only
2950: * the following description of the bits:
2951: *
2952: * ________76543210 Floppy Controll-Register
2953: * ||||||||
2954: * |||||||+- Prescaler 1
2955: * ||||||+-- Mode select 1
2956: * |||||+--- Media detect 1
2957: * ||||+---- accessed during DMA transfers (?)
2958: * |||+----- Prescaler 2
2959: * ||+------ Mode select 2
2960: * |+------- Media detect 2
2961: * +-------- Disk changed
2962: */
1.1.1.15 root 2963: void FDC_FloppyMode_ReadByte ( void )
1.1.1.9 root 2964: {
2965: IoMem_WriteByte(0xff860f, 0x80); // FIXME: Is this ok?
2966: // printf("Read from floppy mode reg.: 0x%02x\n", IoMem_ReadByte(0xff860f));
2967: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.