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

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

unix.superglobalmegacorp.com

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