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

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

unix.superglobalmegacorp.com

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