Annotation of hatari/src/fdc.c, revision 1.1.1.17

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.