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

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

unix.superglobalmegacorp.com

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