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

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

unix.superglobalmegacorp.com

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