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

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

unix.superglobalmegacorp.com

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