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

1.1       root        1: /*
1.1.1.4   root        2:   Hatari - fdc.c
                      3: 
                      4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   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.6   root       25: #include "ioMem.h"
                     26: #include "log.h"
1.1       root       27: #include "m68000.h"
                     28: #include "memorySnapShot.h"
                     29: #include "mfp.h"
                     30: #include "psg.h"
                     31: #include "stMemory.h"
1.1.1.14  root       32: #include "screen.h"
1.1.1.10  root       33: #include "video.h"
1.1.1.15  root       34: #include "clocks_timings.h"
                     35: #include "utils.h"
1.1       root       36: 
1.1.1.3   root       37: 
1.1       root       38: /*
1.1.1.7   root       39:   Floppy Disk Controller
1.1       root       40: 
                     41: Programmable Sound Generator (YM-2149)
                     42: 
                     43:   0xff8800(even byte)  - PSG Register Data (Read, used for parallel port)
                     44:             - PSG Register Select (Write)
                     45: 
                     46:   Write to bits 0-3 to select PSG register to use(then write data to 0xfff8802)
                     47:     Value    Register
                     48: 
                     49:     0000    Channel A Fine Tune
                     50:     0001    Channel A Coarse Tune
                     51:     0010    Channel B Fine Tune
                     52:     0011    Channel B Coarse Tune
                     53:     0100    Channel C Fine Tune
                     54:     0101    Channel C Coarse Tune
                     55:     0110    Noise Generator Control
                     56:     0111    Mixer Control - I/O enable
                     57:     1000    Channel A Amplitude
                     58:     1001    Channel B Amplitude
                     59:     1010    Channel C Amplitude
                     60:     1011    Envelope Period Fine Tune
                     61:     1100    Envelope Peroid Coarse Tune
                     62:     1101    Envelope Shape
                     63:     1110    I/O Port A Select (Write only)
                     64:     1111    I/O Port B Select
                     65: 
                     66:   0xfff8802(even byte)  - Bits according to 0xff8800 Register select
1.1.1.4   root       67: 
1.1       root       68:   1110(Register 14) - I/O Port A
                     69:     Bit 0 - Floppy side 0/1
                     70:     Bit 1 - Floppy drive 0 select
                     71:     Bit 2 - Floppy drive 1 select
                     72:     Bit 3 - RS232 Ready to send (RTS)
                     73:     Bit 4 - RS232 Data Terminal Ready (DTR)
                     74:     Bit 5 - Centronics Strobe
                     75:     Bit 6 - General Purpose Output
                     76:     Bit 7 - Reserved
                     77: 
1.1.1.7   root       78: ACSI DMA and Floppy Disk Controller(FDC)
1.1       root       79:   0xff8604 - information from file '1772.info.txt, by David Gahris' (register r0)
1.1.1.15  root       80:     Word access only, but only lower byte (ff8605) is used
1.1       root       81:   (write) - Disk controller
1.1.1.15  root       82:     Set DMA sector count if ff8606 bit 4 == 1
                     83:     Set FDC's internal registers depending on bit 1/2 of ff8606 if bit 4 == 0
1.1       root       84:   (read) - Disk controller status
                     85:     Bit 0 - Busy.  This bit is 1 when the 177x is busy.  This bit is 0 when the 177x is free for CPU commands.
                     86:     Bit 1 - Index / Data Request.  On Type I commands, this bit is high during the index pulse that occurs once
                     87:       per disk rotation.  This bit is low at all times other than the index pulse.  For Type II and III commands,
                     88:       Bit 1 high signals the CPU to handle the data register in order to maintain a continuous flow of data.
                     89:       Bit 1 is high when the data register is full during a read or when the data register is empty during a write.
                     90:       "Worst case service time" for Data Request is 23.5 cycles.
                     91:     Bit 2 - Track Zero / Lost Data.  After Type I commands, this bit is 0 if the mechanism is at track zero.
                     92:       This bit is 1 if the head is not at track zero.  After Type II or III commands, this bit is 1 if the
                     93:       CPU did not respond to Data Request (Status bit 1) in time for the 177x to maintain a continuous data flow.
                     94:       This bit is 0 if the CPU responded promptly to Data Request.
1.1.1.15  root       95:       NOTE : on ST, Lost Data is never set because the DMA always handles the data request signal.
1.1       root       96:     Bit 3 - CRC Error.  This bit is high if a sector CRC on disk does not match the CRC which the 177x
                     97:       computed from the data.  The CRC polynomial is x^16+x^12+x^5+1.  If the stored CRC matches the newly
                     98:       calculated CRC, the CRC Error bit is low.  If this bit and the Record Not Found bit are set, the error
                     99:       was in an ID field.  If this bit is set but Record Not Found is clear, the error was in a data field.
                    100:     Bit 4 - Record Not Found.  This bit is set if the 177x cannot find the track, sector, or side which
                    101:       the CPU requested.  Otherwise, this bit is clear.
                    102:     Bit 5 - Spin-up / Record Type.  For Type I commands, this bit is low during the 6-revolution motor
                    103:       spin-up time.  This bit is high after spin-up.  For Type II and Type III commands, Bit 5 low
                    104:       indicates a normal data mark.  Bit 5 high indicates a deleted data mark.
                    105:     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      106:       After a type I command, this bit is constantly updated an give the current value of the WPT signal.
1.1       root      107:     Bit 7 - Motor On.  This bit is high when the drive motor is on, and low when the motor is off.
                    108: 
                    109:   0xff8606 - DMA Status(read), DMA Mode Control(write) - NOTE bits 0,9-15 are not used
                    110:     Bit 1 - FDC Pin A0 (See below)
                    111:     Bit 2 - FDC Pin A1
                    112:     Bit 3 - FDC/HDC Register Select
                    113:     Bit 4 - FDC/Sector count select
                    114:     Bit 5 - Reserved
                    115:     Bit 6 - Enable/Disable DMA
                    116:     Bit 7 - HDC/FDC
                    117:     Bit 8 - Read/Write
                    118: 
                    119:     A1  A0    Read        Write(bit 8==1)
                    120:     0  0    Status        Command
                    121:     0  1    Track Register    Track Register
                    122:     1  0    Sector Register    Sector Register
                    123:     1  1    Data Register    Data Register
                    124: 
                    125: 
1.1.1.6   root      126:   According to the documentation INTRQ is generated at the completion of each
                    127:   command (causes an interrupt in the MFP). INTRQ is reset by reading the status
                    128:   register OR by loading a new command. So, does this mean the GPIP? Or does it
                    129:   actually CANCEL the interrupt? Can this be done?
1.1.1.15  root      130: 
                    131:   NOTE [NP] : The DMA is connected to the FDC and its Data Register, each time a DRQ
                    132:   is made by the FDC, it's handled by the DMA through its internal 16 bytes buffer.
                    133:   This means that in the case of the Atari ST the LOST_DATA bit will never be set
                    134:   in the Status Register (but data can be lost if FDC_DMA.SectorCount=0 as there
                    135:   will be no transfer between DMA and RAM)
                    136: 
                    137: 
                    138:   Detecting disk changes :
                    139:   ------------------------
                    140:   3'1/2 floppy drives include a 'DSKCHG' signal on pin 34 to detect when a disk was changed.
                    141:   Unfortunatelly on ST, this signal is not connected. Nevertheless, it's possible to detect
                    142:   a disk was inserted or ejected by looking at the 'WPT' signal which tells if a disk is write
                    143:   protected or not.
                    144:   At the drive level, a light is emitted above the top left corner of the floppy :
                    145:    - if the write protection hole on the floppy is opened, the light goes through and the disk
                    146:      is considered to be write protected.
                    147:    - if the write protection hole on the floppy is closed, the light can't go through and the
                    148:      disk is write enabled.
                    149:   The point is that when any "solid" part of the floppy obstructs the light signal, the WPT
                    150:   signal will change immediatly : it will be considered as if a write enabled disk was present.
                    151:   So, when a floppy is ejected or inserted, the body of the floppy will briefly obstruct the light,
                    152:   whatever the state of the protection hole could be.
                    153:   Similarly, when there's no floppy inside the drive, the light signal can pass through, so it will
                    154:   be considered as if a write protected disk was present.
                    155:   So, let's call 'C' the state when protection hole is Closed (ie WPT = 0) and 'O' the state
                    156:   when protection hole is Opened (ie WPT = 1). We have the following cases :
                    157:     - floppy in drive : state can be C or O depending on the protection tab. Let's call it 'X'
                    158:     - no floppy in drive : state is equivalent to O (because the light signal is not obstructed)
                    159:     - ejecting a floppy : states will go from X to C and finally to O
                    160:     - inserting a floppy : states will go from O to C and finally to X
                    161: 
                    162:   The TOS monitors the changes on the WPT signal to determine if a floppy was ejected or inserted.
                    163:   On TOS 1.02fr, the code is located between $fc1bc4 and $fc1ebc. Every 8 VBL, one floppy drive is checked
                    164:   to see if the WPT signal changed. When 1 drive is connected, this means a floppy change should keep the
                    165:   WPT signal during at least 8 VBLs. When 2 drive are connected, each drive is checked every 16 VBLs, so
                    166:   the WPT signal should be kept for at least 16 VBLs.
                    167: 
                    168:   During these transition phases between "ejected" and "inserted", we force the WPT signal to either 0 or 1,
                    169:   depending on which transition we're emulating (see Floppy_DriveTransitionUpdateState()) :
                    170:     - Ejecting : WPT will be X, then 0, then 1
                    171:     - Inserting : WPT will be 1, then 0, then X
                    172: 
1.1       root      173: */
                    174: 
1.1.1.14  root      175: /*-----------------------------------------------------------------------*/
1.1.1.15  root      176: 
                    177: #define        FDC_STR_BIT_BUSY                        0x01
                    178: #define        FDC_STR_BIT_INDEX                       0x02            /* type I */
                    179: #define        FDC_STR_BIT_DRQ                         0x02            /* type II and III */
                    180: #define        FDC_STR_BIT_TR00                        0x04            /* type I */
                    181: #define        FDC_STR_BIT_LOST_DATA                   0x04            /* type II and III */
                    182: #define        FDC_STR_BIT_CRC_ERROR                   0x08
                    183: #define        FDC_STR_BIT_RNF                         0x10
                    184: #define        FDC_STR_BIT_SPIN_UP                     0x20            /* type I */
                    185: #define        FDC_STR_BIT_RECORD_TYPE                 0x20            /* type II and III */
                    186: #define        FDC_STR_BIT_WPRT                        0x40
                    187: #define        FDC_STR_BIT_MOTOR_ON                    0x80
                    188: 
                    189: 
                    190: #define        FDC_COMMAND_BIT_VERIFY                  (1<<2)          /* 0=verify after type I, 1=no verify after type I */
                    191: #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 */
                    192: #define        FDC_COMMAND_BIT_MOTOR_ON                (1<<3)          /* 0=enable motor test, 1=disable motor test */
                    193: #define        FDC_COMMAND_BIT_UPDATE_TRACK            (1<<4)          /* 0=don't update TR after type I, 1=update TR after type I */
                    194: #define        FDC_COMMAND_BIT_MULTIPLE_SECTOR         (1<<4)          /* 0=read/write only 1 sector, 1=read/write many sectors */
                    195: 
                    196: 
                    197: 
                    198: /* FDC Emulation commands used in FDC.Command */
1.1.1.14  root      199: enum
                    200: {
                    201:        FDCEMU_CMD_NULL = 0,
                    202:        /* Type I */
                    203:        FDCEMU_CMD_RESTORE,
                    204:        FDCEMU_CMD_SEEK,
1.1.1.15  root      205:        FDCEMU_CMD_STEP,                                        /* Also used for STEP IN and STEP OUT */
1.1.1.14  root      206:        /* Type II */
                    207:        FDCEMU_CMD_READSECTORS,
                    208:        FDCEMU_CMD_WRITESECTORS,
                    209:        /* Type III */
                    210:        FDCEMU_CMD_READADDRESS,
1.1.1.15  root      211:        FDCEMU_CMD_READTRACK,
                    212:        FDCEMU_CMD_WRITETRACK,
                    213: 
                    214:        /* Other fake commands used internally */
                    215:        FDCEMU_CMD_MOTOR_STOP
1.1.1.14  root      216: };
                    217: 
                    218: 
1.1.1.15  root      219: /* FDC Emulation commands' sub-states used in FDC.CommandState */
1.1.1.14  root      220: enum
                    221: {
1.1.1.15  root      222:        FDCEMU_RUN_NULL = 0,
1.1.1.14  root      223: 
1.1.1.15  root      224:        /* Restore */
                    225:        FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO,
                    226:        FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_LOOP,
                    227:        FDCEMU_RUN_RESTORE_COMPLETE,
                    228:        /* Seek */
1.1.1.14  root      229:        FDCEMU_RUN_SEEK_TOTRACK,
1.1.1.15  root      230:        FDCEMU_RUN_SEEK_COMPLETE,
                    231:        /* Step / Step In / Step Out */
1.1.1.14  root      232:        FDCEMU_RUN_STEP_ONCE,
1.1.1.15  root      233:        FDCEMU_RUN_STEP_COMPLETE,
                    234:        /* Read Sector */
                    235:        FDCEMU_RUN_READSECTORS_READDATA,
                    236:        FDCEMU_RUN_READSECTORS_READDATA_CHECK_SECTOR_HEADER,
                    237:        FDCEMU_RUN_READSECTORS_READDATA_DMA,
                    238:        FDCEMU_RUN_READSECTORS_RNF,
                    239:        FDCEMU_RUN_READSECTORS_COMPLETE,
                    240:        /* Write Sector */
                    241:        FDCEMU_RUN_WRITESECTORS_WRITEDATA,
                    242:        FDCEMU_RUN_WRITESECTORS_WRITEDATA_CHECK_SECTOR_HEADER,
                    243:        FDCEMU_RUN_WRITESECTORS_WRITEDATA_DMA,
                    244:        FDCEMU_RUN_WRITESECTORS_RNF,
                    245:        FDCEMU_RUN_WRITESECTORS_COMPLETE,
                    246:        /* Read Address */
                    247:        FDCEMU_RUN_READADDRESS,
                    248:        FDCEMU_RUN_READADDRESS_DMA,
                    249:        FDCEMU_RUN_READADDRESS_COMPLETE,
                    250:        /* Read Track */
                    251:        FDCEMU_RUN_READTRACK,
                    252:        FDCEMU_RUN_READTRACK_DMA,
                    253:        FDCEMU_RUN_READTRACK_COMPLETE,
                    254:        /* Write Track */
                    255:        FDCEMU_RUN_WRITETRACK,
                    256:        FDCEMU_RUN_WRITETRACK_DMA,
                    257:        FDCEMU_RUN_WRITETRACK_COMPLETE
1.1.1.14  root      258: };
                    259: 
                    260: 
                    261: 
1.1.1.15  root      262: /* Standard hardware values for the FDC. This should allow to get good timings estimation */
                    263: /* when dealing with non protected disks that require a correct speed (MSA or ST images) */
                    264: /* FIXME [NP] : Those timings could be improved by taking into account the time */
                    265: /* it takes to reach the track index/sector/address field before really reading it, but this level */
                    266: /* of accuracy is not necessary for ST/MSA disk images (it would be required to emulate protections */
                    267: /* in Pasti disk images) */
1.1.1.14  root      268: 
1.1.1.15  root      269: #define        FDC_BITRATE_STANDARD                    250000          /* read/write speed of the WD1772 in bits per sec */
                    270: #define        FDC_RPM_STANDARD                        300             /* 300 RPM or 5 spins per sec */
                    271: #define        FDC_TRACK_BYTES_STANDARD                ( ( FDC_BITRATE_STANDARD / 8 ) / ( FDC_RPM_STANDARD / 60 ) )    /* 6250 bytes */
1.1.1.14  root      272: 
1.1.1.15  root      273: #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      274: 
1.1.1.15  root      275: /* Delays are in micro sec */
                    276: #define        FDC_DELAY_MOTOR_ON                      ( 1000000.L * 6 / ( FDC_RPM_STANDARD / 60 ) )   /* 6 spins to reach correct speed */
                    277: #define        FDC_DELAY_MOTOR_OFF                     ( 1000000.L * 9 / ( FDC_RPM_STANDARD / 60 ) )   /* Turn off motor 9 spins after the last command */
1.1.1.14  root      278: 
1.1.1.15  root      279: #define        FDC_DELAY_HEAD_LOAD                     ( 30 * 1000 )   /* Additionnal 30 ms delay to load the head in type II/III */
1.1.1.14  root      280: 
1.1.1.15  root      281: #define        FDC_DELAY_RNF                           ( 1000000.L * 5 / ( FDC_RPM_STANDARD / 60 ) )   /* 5 spins to set RNF */
1.1       root      282: 
1.1.1.15  root      283: #define        FDC_DELAY_TYPE_I_PREPARE                100             /* Types I commands take at least 0.1 ms to execute */
                    284:                                                                /* (~800 cpu cycles @ 8 Mhz). FIXME [NP] : this was not measured, it's */
                    285:                                                                /* to avoid returning immediatly when command has no effect */
                    286: #define        FDC_DELAY_TYPE_II_PREPARE               1               /* Start Type II commands immediatly */
                    287: #define        FDC_DELAY_TYPE_III_PREPARE              1               /* Start Type III commands immediatly */
                    288: #define        FDC_DELAY_TYPE_IV_PREPARE               100             /* FIXME [NP] : this was not measured */
                    289:                                                                
                    290: #define        FDC_DELAY_TRANSFER_DMA_16               FDC_TRANSFER_BYTES_US( DMA_DISK_TRANSFER_SIZE )
1.1       root      291: 
1.1.1.15  root      292: #define        FDC_DELAY_COMMAND_COMPLETE              1               /* Number of us before going to the _COMPLETE state (~8 cpu cycles) */
1.1.1.5   root      293: 
1.1.1.15  root      294: #define        FDC_DELAY_COMMAND_IMMEDIATE             1               /* Number of us to go immediatly to another state */
1.1.1.5   root      295: 
                    296: 
1.1.1.15  root      297: #define        DMA_DISK_SECTOR_SIZE                    512             /* Sector count at $ff8606 is for 512 bytes blocks */
                    298: #define        DMA_DISK_TRANSFER_SIZE                  16              /* DMA transfers blocks of 16 bytes at a time */
1.1.1.5   root      299: 
1.1.1.15  root      300: #define        FDC_PHYSICAL_MAX_TRACK                  90              /* Head can't go beyond 90 tracks */
1.1       root      301: 
1.1.1.2   root      302: 
1.1.1.15  root      303: #define FDC_SIDE                               ( (~PSGRegisters[PSG_REG_IO_PORTA]) & 0x01 )    /* Side 0 or 1 */
                    304: #define        FDC_DRIVE                               FDC_FindFloppyDrive()
1.1.1.14  root      305: 
1.1.1.15  root      306: #define        FDC_STEP_RATE                           ( FDC.CR & 0x03 )       /* Bits 0 and 1 of the current type I command */
                    307: 
                    308: static int FDC_StepRate_ms[] = { 6 , 12 , 2 , 3 };             /* Controlled by bits 1 and 0 (r1/r0) in type I commands */
                    309: 
                    310: 
                    311: #define        FDC_SECTOR_SIZE_128                     0               /* Sector size used in the ID fields */
                    312: #define        FDC_SECTOR_SIZE_256                     1
                    313: #define        FDC_SECTOR_SIZE_512                     2
                    314: #define        FDC_SECTOR_SIZE_1024                    3
                    315: 
                    316: 
                    317: #define        FDC_FAST_FDC_FACTOR                     10              /* Divide all delays by this value when --fastfdc is used */
                    318: 
                    319: 
                    320: typedef struct {
                    321:        /* WD1772 internal registers */
                    322:        Uint8           DR;                                     /* Data Register */
                    323:        Uint8           TR;                                     /* Track Register */
                    324:        Uint8           SR;                                     /* Sector Register */
                    325:        Uint8           CR;                                     /* Command Register */
                    326:        Uint8           STR;                                    /* Status Register */
                    327:        int             StepDirection;                          /* +1 (Step In) or -1 (Step Out) */
                    328: 
                    329:        /* Other variables */
                    330:        int             Command;                                /* FDC emulation command currently being exceuted */
                    331:        int             CommandState;                           /* Current state for the running command */
                    332:        Uint8           CommandType;                            /* Type of latest FDC command (1,2,3 or 4) */
                    333:        bool            ReplaceCommandPossible;                 /* true if the current command can be replaced by another one */
                    334:                                                                /* ([NP] FIXME : only possible during prepare+spinup phases ?) */
                    335: 
                    336:        Uint8           ID_FieldLastSector;                     /* Last sector number returned by Read Address (to simulate a spinning disk) */
                    337: } FDC_STRUCT;
                    338: 
                    339: 
                    340: typedef struct {
                    341:        /* DMA internal registers */
                    342:        Uint16          Status;
                    343:        Uint16          Mode;
                    344:        Uint16          SectorCount;
                    345:        Uint16          BytesInSector;
                    346: 
                    347:        /* Variables to handle our DMA buffer */
                    348:        int             PosInBuffer;
                    349:        int             PosInBufferTransfer;
                    350:        int             BytesToTransfer;
                    351: } FDC_DMA_STRUCT;
                    352: 
                    353: 
                    354: static FDC_STRUCT      FDC;                                    /* All variables related to the WD1772 emulation */
                    355: static FDC_DMA_STRUCT  FDC_DMA;                                /* All variables related to the DMA transfer */
                    356: 
                    357: static Uint8 HeadTrack[ MAX_FLOPPYDRIVES ];                    /* A: and B: */
                    358: 
                    359: static Uint8 DMADiskWorkSpace[ FDC_TRACK_BYTES_STANDARD+1000 ];        /* Workspace used to transfer bytes between floppy and DMA */
                    360:                                                                /* It should be large enough to contain a whole track */
                    361: 
                    362: 
                    363: /*--------------------------------------------------------------*/
                    364: /* Local functions prototypes                                  */
                    365: /*--------------------------------------------------------------*/
                    366: 
                    367: static int     FDC_DelayToCpuCycles ( int Delay_micro );
                    368: static void    FDC_CRC16 ( Uint8 *buf , int nb , Uint16 *pCRC );
                    369: 
                    370: static void    FDC_ResetDMA ( void );
                    371: static void    FDC_DMA_InitTransfer ( void );
                    372: static bool    FDC_DMA_ReadFromFloppy ( void );
                    373: static bool    FDC_DMA_WriteToFloppy ( void );
                    374: 
1.1.1.16! root      375: static bool    FDC_ValidFloppyDrive ( void );
1.1.1.15  root      376: static int     FDC_FindFloppyDrive ( void );
                    377: static int     FDC_GetSectorsPerTrack ( int Track , int Side );
                    378: static int     FDC_GetSidesPerDisk ( int Track );
                    379: 
                    380: static void    FDC_Update_STR ( Uint8 DisableBits , Uint8 EnableBits );
                    381: static int     FDC_CmdCompleteCommon ( bool DoInt );
                    382: static void    FDC_VerifyTrack ( void );
                    383: static int     FDC_UpdateMotorStop ( void );
                    384: static int     FDC_UpdateRestoreCmd ( void );
                    385: static int     FDC_UpdateSeekCmd ( void );
                    386: static int     FDC_UpdateStepCmd ( void );
                    387: static int     FDC_UpdateReadSectorsCmd ( void );
                    388: static int     FDC_UpdateWriteSectorsCmd ( void );
                    389: static int     FDC_UpdateReadAddressCmd ( void );
                    390: static int     FDC_UpdateReadTrackCmd ( void );
                    391: 
                    392: static int     FDC_Check_MotorON ( Uint8 FDC_CR );
                    393: static int     FDC_TypeI_Restore ( void );
                    394: static int     FDC_TypeI_Seek ( void );
                    395: static int     FDC_TypeI_Step ( void );
                    396: static int     FDC_TypeI_StepIn ( void );
                    397: static int     FDC_TypeI_StepOut ( void );
                    398: static int     FDC_TypeII_ReadSector ( void );
                    399: static int     FDC_TypeII_WriteSector(void);
                    400: static int     FDC_TypeIII_ReadAddress ( void );
                    401: static int     FDC_TypeIII_ReadTrack ( void );
                    402: static int     FDC_TypeIII_WriteTrack ( void );
                    403: static int     FDC_TypeIV_ForceInterrupt ( bool bCauseCPUInterrupt );
                    404: 
                    405: static int     FDC_ExecuteTypeICommands ( void );
                    406: static int     FDC_ExecuteTypeIICommands ( void );
                    407: static int     FDC_ExecuteTypeIIICommands ( void );
                    408: static int     FDC_ExecuteTypeIVCommands ( void );
                    409: static void    FDC_ExecuteCommand ( void );
                    410: 
                    411: static void    FDC_WriteSectorCountRegister ( void );
                    412: static void    FDC_WriteCommandRegister ( void );
                    413: static void    FDC_WriteTrackRegister ( void );
                    414: static void    FDC_WriteSectorRegister ( void );
                    415: static void    FDC_WriteDataRegister ( void );
                    416: 
                    417: static bool    FDC_ReadSectorFromFloppy ( Uint8 *buf , Uint8 Sector , int *pSectorSize );
                    418: static bool    FDC_WriteSectorToFloppy ( int DMASectorsCount , Uint8 Sector , int *pSectorSize );
1.1       root      419: 
1.1.1.2   root      420: 
                    421: /*-----------------------------------------------------------------------*/
1.1.1.9   root      422: /**
                    423:  * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                    424:  */
1.1.1.10  root      425: void FDC_MemorySnapShot_Capture(bool bSave)
1.1       root      426: {
1.1.1.15  root      427:        MemorySnapShot_Store(&FDC, sizeof(FDC));
                    428:        MemorySnapShot_Store(&FDC_DMA, sizeof(FDC_DMA));
                    429:        MemorySnapShot_Store(HeadTrack, sizeof(HeadTrack));
                    430: 
                    431:        MemorySnapShot_Store(DMADiskWorkSpace, sizeof(DMADiskWorkSpace));
1.1       root      432: }
                    433: 
1.1.1.2   root      434: 
                    435: /*-----------------------------------------------------------------------*/
1.1.1.9   root      436: /**
1.1.1.15  root      437:  * Convert a delay in micro seconds to its equivalent of cpu cycles
                    438:  * (FIXME [NP] : for now we use a fixed 8 MHz clock, because cycInt.c requires it)
1.1.1.9   root      439:  */
1.1.1.15  root      440: static int FDC_DelayToCpuCycles ( int Delay_micro )
1.1       root      441: {
1.1.1.15  root      442:        int     Delay;
                    443: 
                    444:        Delay = (int) ( ( (Sint64)MachineClocks.FDC_Freq * Delay_micro ) / 1000000 ) & -4;
                    445: 
                    446:        /* Our conversion expect FDC_Freq to be the same as CPU_Freq (8 Mhz) */
                    447:        /* but the Falcon uses a 16 MHz clock for the Ajax FDC */
                    448:        /* FIXME : as stated above, this should be handled better, without involving 8 MHz CPU_Freq */
                    449:        if ( ConfigureParams.System.nMachineType == MACHINE_FALCON )
                    450:                Delay /= 2;                                     /* correct delays for a 8 MHz clock instead of 16 */
                    451: 
                    452:        if ( ( ConfigureParams.DiskImage.FastFloppy ) && ( Delay > FDC_FAST_FDC_FACTOR ) )
                    453:                Delay /= FDC_FAST_FDC_FACTOR;
                    454: 
                    455: //  fprintf ( stderr , "fdc state %d delay %d us %d cycles\n" , FDC.Command , Delay_micro , Delay );
                    456:        return Delay;
1.1       root      457: }
                    458: 
1.1.1.2   root      459: 
                    460: /*-----------------------------------------------------------------------*/
1.1.1.9   root      461: /**
1.1.1.15  root      462:  * Compute the CRC16 of 'nb' bytes stored in 'buf'.
1.1.1.9   root      463:  */
1.1.1.15  root      464: static void FDC_CRC16 ( Uint8 *buf , int nb , Uint16 *pCRC )
1.1       root      465: {
1.1.1.15  root      466:        int     i;
                    467: 
                    468:        crc16_reset ( pCRC );
                    469:        for ( i=0 ; i<nb ; i++ )
                    470:        {
                    471: //             fprintf ( stderr , "fdc crc16 %d 0x%x\n" , i , buf[ i ] );
                    472:                crc16_add_byte ( pCRC , buf[ i ] );
                    473:        }
                    474: //     fprintf ( stderr , "fdc crc16 0x%x 0x%x\n" , *pCRC>>8 , *pCRC & 0xff );
1.1       root      475: }
                    476: 
1.1.1.2   root      477: 
                    478: /*-----------------------------------------------------------------------*/
1.1.1.9   root      479: /**
1.1.1.15  root      480:  * Reset variables used in FDC and DMA emulation
1.1.1.9   root      481:  */
1.1.1.15  root      482: void FDC_Reset ( void )
1.1       root      483: {
1.1.1.15  root      484:        int     i;
1.1.1.6   root      485: 
1.1.1.15  root      486:        /* Clear out FDC registers */
                    487: 
                    488:        FDC.CR = 0;
                    489:        FDC.TR = 0;
                    490:        FDC.SR = 1;
                    491:        FDC.DR = 0;
                    492:        FDC.STR = 0;
                    493:        FDC.StepDirection = 1;
                    494:        FDC.ID_FieldLastSector = 1;
                    495: 
                    496:        FDC.Command = FDCEMU_CMD_NULL;                  /* FDC emulation command currently being executed */
                    497:        FDC.CommandState = FDCEMU_RUN_NULL;
                    498:        FDC.CommandType = 0;
                    499: 
                    500:        FDC_DMA.Status = 1;                             /* no DMA error and SectorCount=0 */
                    501:        FDC_DMA.Mode = 0;
                    502:        FDC_DMA.SectorCount = 0;
                    503:        FDC_ResetDMA();
                    504: 
                    505:        for ( i=0 ; i<MAX_FLOPPYDRIVES ; i++ )
                    506:                HeadTrack[ i ] = 0;                     /* Set all drives to track 0 */
1.1       root      507: }
                    508: 
1.1.1.2   root      509: 
                    510: /*-----------------------------------------------------------------------*/
1.1.1.9   root      511: /**
1.1.1.15  root      512:  * Reset DMA (clear internal 16 bytes buffer)
1.1.1.9   root      513:  *
                    514:  * This is done by 'toggling' bit 8 of the DMA Mode Control register
                    515:  */
1.1.1.15  root      516: static void FDC_ResetDMA ( void )
1.1       root      517: {
1.1.1.15  root      518:        int     FrameCycles, HblCounterVideo, LineCycles;
1.1       root      519: 
1.1.1.15  root      520:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                    521:        LOG_TRACE(TRACE_FDC, "fdc reset dma VBL=%d video_cyc=%d %d@%d pc=%x\n",
                    522:                  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                    523: 
                    524:        /* Reset bytes count for current DMA sector */
                    525:        FDC_DMA.BytesInSector = DMA_DISK_SECTOR_SIZE;
                    526: 
                    527:        /* Reset variables used to handle DMA transfer */
                    528:        FDC_DMA.PosInBuffer = 0;
                    529:        FDC_DMA.PosInBufferTransfer = 0;
                    530:        FDC_DMA.BytesToTransfer = 0;
1.1.1.3   root      531: 
1.1.1.10  root      532:        /* Reset HDC command status */
1.1.1.15  root      533:        HDC_ResetCommandStatus();
1.1       root      534: }
                    535: 
1.1.1.2   root      536: 
                    537: /*-----------------------------------------------------------------------*/
1.1.1.9   root      538: /**
1.1.1.15  root      539:  * Set DMA Status at $ff8606
1.1.1.9   root      540:  *
1.1.1.15  root      541:  * Bit 0 - _Error Status (0=Error 1=No erroe)
1.1.1.9   root      542:  * Bit 1 - _Sector Count Zero Status (0=Sector Count Zero)
                    543:  * Bit 2 - _Data Request Inactive Status
1.1.1.15  root      544:  *
                    545:  * FIXME [NP] : is bit 0 really used on ST ? It seems it's always 1 (no DMA error)
1.1.1.9   root      546:  */
1.1.1.15  root      547: void FDC_SetDMAStatus ( bool bError )
1.1       root      548: {
1.1.1.15  root      549:        /* Set error bit */
1.1.1.6   root      550:        if (!bError)
1.1.1.15  root      551:                FDC_DMA.Status |= 0x1;                                  /* No Error, set bit 0 */
1.1.1.6   root      552:        else
1.1.1.15  root      553:                FDC_DMA.Status &= ~0x1;                                 /* Error, clear bit 0 */
1.1       root      554: }
                    555: 
1.1.1.2   root      556: 
                    557: /*-----------------------------------------------------------------------*/
1.1.1.9   root      558: /**
1.1.1.15  root      559:  * Init some variables before starting a new DMA transfer.
                    560:  * We must store new data just after the most recent bytes that
                    561:  * were not yet transferred by the DMA (16 bytes buffer).
                    562:  * To avoid writing above the limit of DMADiskWorkSpace, we move
                    563:  * the current 16 bytes buffer at the start of DMADiskWorkSpace
                    564:  * if some bytes remain to be transferred, this way we never use
                    565:  * more than FDC_TRACK_BYTES_STANDARD in DMADiskWorkSpace.
1.1.1.9   root      566:  */
1.1.1.15  root      567: static void FDC_DMA_InitTransfer ( void )
1.1       root      568: {
1.1.1.15  root      569:        int     i;
                    570: 
                    571:        /* How many bytes remain in the current 16 bytes DMA buffer ? */
                    572:        if ( ( FDC_DMA.BytesToTransfer == 0 )                           /* DMA buffer is empty */
                    573:          || ( FDC_DMA.BytesToTransfer > DMA_DISK_TRANSFER_SIZE ) )     /* Previous DMA transfer did not finish (FDC errror or Force Int command) */
1.1.1.6   root      574:        {
1.1.1.15  root      575:                FDC_DMA.PosInBuffer = 0;                                /* Add new data at the start of DMADiskWorkSpace */
                    576:                FDC_DMA.PosInBufferTransfer = 0;
                    577:                FDC_DMA.BytesToTransfer = 0;                            /* No more data to transfer from the previous DMA buffer */
1.1.1.6   root      578:        }
1.1.1.15  root      579:        else                                                            /* 16 bytes buffer partially filled */
                    580:        {
                    581:                for ( i=0 ; i<FDC_DMA.BytesToTransfer ; i++ )           /* Move these bytes at the start of the buffer */
                    582:                        DMADiskWorkSpace[ i ] = DMADiskWorkSpace[ FDC_DMA.PosInBufferTransfer + i ];
1.1.1.6   root      583: 
1.1.1.15  root      584:                FDC_DMA.PosInBuffer = FDC_DMA.BytesToTransfer;          /* Add new data after the latest bytes stored in the 16 bytes buffer */
                    585:                FDC_DMA.PosInBufferTransfer = 0;
                    586:        }
1.1       root      587: }
                    588: 
1.1.1.2   root      589: 
                    590: /*-----------------------------------------------------------------------*/
1.1.1.9   root      591: /**
1.1.1.15  root      592:  * Transfer 16 bytes from the DMA workspace to the RAM.
                    593:  * Instead of handling a real 16 bytes buffer, this implementation moves
                    594:  * a 16 bytes window in DMADiskWorkSpace. The current position of this window
                    595:  * is stored in FDC_DMA.PosInBufferTransfer and contains the equivalent of the
                    596:  * DMA's internal 16 bytes buffer.
                    597:  *
                    598:  * Return true if there're no more bytes to transfer or false if some
                    599:  * bytes can still be tranfered by the DMA.
                    600:  *
                    601:  * NOTE [NP] : The DMA is connected to the FDC, each time a DRQ is made by the FDC,
                    602:  * it's handled by the DMA and stored in the DMA 16 bytes buffer. This means
                    603:  * FDC_STR_BIT_LOST_DATA will never be set (but data can be lost if FDC_DMA.SectorCount==0)
1.1.1.14  root      604:  */
1.1.1.15  root      605: static bool FDC_DMA_ReadFromFloppy ( void )
1.1.1.14  root      606: {
1.1.1.15  root      607:        Uint32  Address;
                    608: //fprintf ( stderr , "dma transfer read count=%d bytes=%d pos=%d\n" , FDC_DMA.SectorCount, FDC_DMA.BytesToTransfer, FDC_DMA.PosInBufferTransfer );
1.1.1.14  root      609: 
1.1.1.15  root      610:        if ( FDC_DMA.BytesToTransfer < DMA_DISK_TRANSFER_SIZE )
                    611:                return true;                                            /* There should be at least 16 bytes to start a DMA transfer */
1.1.1.14  root      612: 
1.1.1.15  root      613:        if ( FDC_DMA.SectorCount == 0 )
                    614:        {
                    615:                //FDC_Update_STR ( 0 , FDC_STR_BIT_LOST_DATA );         /* If DMA is OFF, data are lost -> Not on the ST */
                    616:                FDC_DMA.PosInBufferTransfer += DMA_DISK_TRANSFER_SIZE;
                    617:                FDC_DMA.BytesToTransfer -= DMA_DISK_TRANSFER_SIZE;
                    618:                return false;                                           /* FDC DMA is off but we still need to read all bytes from the floppy */
                    619:        }
                    620: 
                    621:        /* Transfer data and update DMA address */
                    622:        Address = FDC_GetDMAAddress();
                    623:        STMemory_SafeCopy ( Address , DMADiskWorkSpace + FDC_DMA.PosInBufferTransfer , DMA_DISK_TRANSFER_SIZE , "FDC DMA data read" );
                    624:        FDC_DMA.PosInBufferTransfer += DMA_DISK_TRANSFER_SIZE;
                    625:        FDC_DMA.BytesToTransfer -= DMA_DISK_TRANSFER_SIZE;
                    626:        FDC_WriteDMAAddress ( Address + DMA_DISK_TRANSFER_SIZE );
                    627: 
                    628:        /* Update Sector Count */
                    629:        FDC_DMA.BytesInSector -= DMA_DISK_TRANSFER_SIZE;
                    630:        if ( FDC_DMA.BytesInSector <= 0 )
                    631:        {
                    632:                FDC_DMA.SectorCount--;
                    633:                FDC_DMA.BytesInSector = DMA_DISK_SECTOR_SIZE;
                    634:        }
1.1.1.2   root      635: 
1.1.1.15  root      636:        return false;                                                   /* Transfer is not complete */
1.1       root      637: }
                    638: 
1.1.1.2   root      639: 
                    640: /*-----------------------------------------------------------------------*/
1.1.1.9   root      641: /**
1.1.1.15  root      642:  * Transfer 16 bytes from the RAM to disk using DMA.
                    643:  * This is used to write data to the disk with correct timings
                    644:  * by writing blocks of 16 bytes at a time.
                    645:  *
                    646:  * Return true if there're no more bytes to transfer or false if some
                    647:  * bytes can still be tranfered by the DMA.
                    648:  *
                    649:  * NOTE [NP] : in the case of the emulation in Hatari, the sector is first written
                    650:  * to the disk image and this function is just used to increment
                    651:  * DMA address at the correct pace to simulate that bytes are written from
                    652:  * blocks of 16 bytes handled by the DMA.
1.1.1.9   root      653:  */
1.1.1.15  root      654: static bool FDC_DMA_WriteToFloppy ( void )
1.1       root      655: {
1.1.1.15  root      656:        Uint32  Address;
                    657: //fprintf ( stderr , "dma transfer write count=%d bytes=%d pos=%d\n" , FDC_DMA.SectorCount, FDC_DMA.BytesToTransfer, FDC_DMA.PosInBufferTransfer );
                    658: 
                    659:        if ( FDC_DMA.BytesToTransfer < DMA_DISK_TRANSFER_SIZE )
                    660:                return true;                                            /* There should be at least 16 bytes to start a DMA transfer */
                    661: 
                    662:        if ( FDC_DMA.SectorCount == 0 )
                    663:        {
                    664:                //FDC_Update_STR ( 0 , FDC_STR_BIT_LOST_DATA );         /* If DMA is OFF, data are lost -> Not on the ST */
                    665:                FDC_DMA.PosInBufferTransfer += DMA_DISK_TRANSFER_SIZE;
                    666:                FDC_DMA.BytesToTransfer -= DMA_DISK_TRANSFER_SIZE;
                    667:                return false;                                           /* FDC DMA is off but we still need to process the whole sector */
                    668:        }
1.1       root      669: 
1.1.1.15  root      670:        /* Transfer data and update DMA address */
                    671:        Address = FDC_GetDMAAddress();
                    672:        //STMemory_SafeCopy ( Address , DMADiskWorkSpace + FDC_DMA.PosInBufferTransfer , DMA_DISK_TRANSFER_SIZE , "FDC DMA data read" );
                    673:        FDC_DMA.PosInBufferTransfer += DMA_DISK_TRANSFER_SIZE;
                    674:        FDC_DMA.BytesToTransfer -= DMA_DISK_TRANSFER_SIZE;
                    675:        FDC_WriteDMAAddress ( Address + DMA_DISK_TRANSFER_SIZE );
1.1       root      676: 
1.1.1.15  root      677:        /* Update Sector Count */
                    678:        FDC_DMA.BytesInSector -= DMA_DISK_TRANSFER_SIZE;
                    679:        if ( FDC_DMA.BytesInSector <= 0 )
1.1.1.6   root      680:        {
1.1.1.15  root      681:                FDC_DMA.SectorCount--;
                    682:                FDC_DMA.BytesInSector = DMA_DISK_SECTOR_SIZE;
1.1.1.6   root      683:        }
                    684: 
1.1.1.15  root      685:        return false;                                                   /* Transfer is not complete */
                    686: 
1.1       root      687: }
                    688: 
1.1.1.2   root      689: 
                    690: /*-----------------------------------------------------------------------*/
1.1.1.9   root      691: /**
1.1.1.16! root      692:  * Check if a floppy drive is selected
        !           693:  * If not, we should ignore the corresponding FDC commands
        !           694:  */
        !           695: static bool FDC_ValidFloppyDrive ( void )
        !           696: {
        !           697:        if ((PSGRegisters[PSG_REG_IO_PORTA]&0x6)==0x6)
        !           698:                return false;                                           /* neither A: not B: are selected */
        !           699:        else
        !           700:                return true;
        !           701: }
        !           702: 
        !           703: 
        !           704: /*-----------------------------------------------------------------------*/
        !           705: /**
1.1.1.15  root      706:  * Return device for FDC, check PORTA bits 1,2 (0=on,1=off)
1.1.1.9   root      707:  */
1.1.1.15  root      708: static int FDC_FindFloppyDrive ( void )
1.1       root      709: {
1.1.1.6   root      710:        /* Check Drive A first */
                    711:        if ((PSGRegisters[PSG_REG_IO_PORTA]&0x2)==0)
1.1.1.15  root      712:                return 0;                                               /* Device 0 (A:) */
1.1.1.6   root      713:        /* If off, check Drive B */
                    714:        if ((PSGRegisters[PSG_REG_IO_PORTA]&0x4)==0)
1.1.1.15  root      715:                return 1;                                               /* Device 1 (B:) */
1.1       root      716: 
1.1.1.6   root      717:        /* None appear to be selected so default to Drive A */
1.1.1.16! root      718:        /* [NP] 2012/03/04 : this is certainly wrong, we should ignore commands, not default to A: (see FDC_ValidFloppyDrive()) */
1.1.1.15  root      719:        return 0;                                                       /* Device 0 (A:) */
1.1       root      720: }
                    721: 
1.1.1.2   root      722: 
                    723: /*-----------------------------------------------------------------------*/
1.1.1.9   root      724: /**
1.1.1.15  root      725:  * Return number of sectors for track/side of current drive
                    726:  * TODO [NP] : this function calls Floppy_FindDiskDetails which handles only ST/MSA
                    727:  * disk image so far, so this implies all tracks have in fact the same number
                    728:  * of sectors (we don't use Track and Side for now)
1.1.1.9   root      729:  */
1.1.1.15  root      730: static int FDC_GetSectorsPerTrack ( int Track , int Side )
1.1       root      731: {
1.1.1.15  root      732:        Uint16  SectorsPerTrack;
                    733: 
                    734:        if (EmulationDrives[ FDC_DRIVE ].bDiskInserted)
                    735:        {
                    736:                Floppy_FindDiskDetails ( EmulationDrives[ FDC_DRIVE ].pBuffer , EmulationDrives[ FDC_DRIVE ].nImageBytes , &SectorsPerTrack , NULL );
                    737:                return SectorsPerTrack;
                    738:        }
                    739:        else
                    740:                return 0;
1.1       root      741: }
                    742: 
1.1.1.2   root      743: 
1.1.1.15  root      744: static int FDC_GetSidesPerDisk ( int Track )
1.1       root      745: {
1.1.1.15  root      746:        Uint16  SidesPerDisk;
                    747: 
                    748:        if (EmulationDrives[ FDC_DRIVE ].bDiskInserted)
                    749:        {
                    750:                Floppy_FindDiskDetails ( EmulationDrives[ FDC_DRIVE ].pBuffer , EmulationDrives[ FDC_DRIVE ].nImageBytes , NULL , &SidesPerDisk );
                    751:                return SidesPerDisk;                                    /* 1 or 2 */
                    752:        }
                    753:        else
                    754:                return 0;
1.1       root      755: }
                    756: 
1.1.1.2   root      757: 
                    758: /*-----------------------------------------------------------------------*/
1.1.1.9   root      759: /**
1.1.1.15  root      760:  * Acknowledge FDC interrupt
1.1.1.9   root      761:  */
1.1.1.15  root      762: void FDC_AcknowledgeInterrupt ( void )
1.1.1.8   root      763: {
1.1.1.15  root      764:        /* Acknowledge in MFP circuit, pass bit, enable, pending */
                    765:        MFP_InputOnChannel(MFP_FDCHDC_BIT,MFP_IERB,&MFP_IPRB);
                    766:        MFP_GPIP &= ~0x20;
1.1.1.8   root      767: }
                    768: 
                    769: 
                    770: /*-----------------------------------------------------------------------*/
1.1.1.9   root      771: /**
1.1.1.15  root      772:  * Handle the current FDC command.
                    773:  * We use a timer to go from one state to another to emulate the different
                    774:  * phases of an FDC command.
                    775:  * When the command completes (success or failure), FDC.Command will be
                    776:  * set to FDCEMU_CMD_NULL. Until then, this function will be called to
                    777:  * handle each state of the command and the corresponding delay in micro
                    778:  * seconds.
                    779:  * This handler is called after a first delay corresponding to the prepare
                    780:  * delay and the eventual motor on delay.
                    781:  * Once we reach this point, the current command can not be replaced by
                    782:  * another command (except 'Force Interrupt')
1.1.1.9   root      783:  */
1.1.1.15  root      784: void FDC_InterruptHandler_Update ( void )
1.1       root      785: {
1.1.1.15  root      786:        int     Delay_micro = 0;
1.1.1.6   root      787: 
1.1.1.15  root      788:        CycInt_AcknowledgeInterrupt();
1.1.1.6   root      789: 
                    790:        /* Is FDC active? */
1.1.1.15  root      791:        if (FDC.Command!=FDCEMU_CMD_NULL)
1.1.1.6   root      792:        {
1.1.1.15  root      793:                FDC.ReplaceCommandPossible = false;
                    794:        
1.1.1.6   root      795:                /* Which command are we running? */
1.1.1.15  root      796:                switch(FDC.Command)
1.1.1.6   root      797:                {
                    798:                 case FDCEMU_CMD_RESTORE:
1.1.1.15  root      799:                        Delay_micro = FDC_UpdateRestoreCmd();
1.1.1.6   root      800:                        break;
                    801:                 case FDCEMU_CMD_SEEK:
1.1.1.15  root      802:                        Delay_micro = FDC_UpdateSeekCmd();
1.1.1.6   root      803:                        break;
                    804:                 case FDCEMU_CMD_STEP:
1.1.1.15  root      805:                        Delay_micro = FDC_UpdateStepCmd();
1.1.1.6   root      806:                        break;
                    807: 
                    808:                 case FDCEMU_CMD_READSECTORS:
1.1.1.15  root      809:                        Delay_micro = FDC_UpdateReadSectorsCmd();
1.1.1.6   root      810:                        break;
                    811:                 case FDCEMU_CMD_WRITESECTORS:
1.1.1.15  root      812:                        Delay_micro = FDC_UpdateWriteSectorsCmd();
1.1.1.6   root      813:                        break;
1.1.1.11  root      814: 
                    815:                 case FDCEMU_CMD_READADDRESS:
1.1.1.15  root      816:                        Delay_micro = FDC_UpdateReadAddressCmd();
                    817:                        break;
                    818: 
                    819:                 case FDCEMU_CMD_READTRACK:
                    820:                        Delay_micro = FDC_UpdateReadTrackCmd();
                    821:                        break;
                    822: 
                    823:                 case FDCEMU_CMD_MOTOR_STOP:
                    824:                        Delay_micro = FDC_UpdateMotorStop();
1.1.1.11  root      825:                        break;
1.1.1.6   root      826:                }
1.1.1.15  root      827:        }
1.1.1.6   root      828: 
1.1.1.15  root      829:        if (FDC.Command != FDCEMU_CMD_NULL)
                    830:        {
                    831:                CycInt_AddAbsoluteInterrupt ( FDC_DelayToCpuCycles ( Delay_micro ) , INT_CPU_CYCLE , INTERRUPT_FDC );
1.1.1.6   root      832:        }
1.1.1.15  root      833: }
                    834: 
                    835: 
                    836: /*-----------------------------------------------------------------------*/
                    837: /**
                    838:  * Update the FDC's Status Register.
                    839:  * All bits in DisableBits are cleared in STR, then all bits in EnableBits
                    840:  * are set in STR.
                    841:  */
                    842: static void FDC_Update_STR ( Uint8 DisableBits , Uint8 EnableBits )
                    843: {
                    844:        FDC.STR &= (~DisableBits);                                      /* Clear bits in DisableBits */
                    845:        FDC.STR |= EnableBits;                                          /* Set bits in EnableBits */
                    846: //fprintf ( stderr , "fdc str 0x%x\n" , FDC.STR );
                    847: }
                    848: 
                    849: 
                    850: /*-----------------------------------------------------------------------*/
                    851: /**
                    852:  * Common to all commands once they're completed :
                    853:  * - remove busy bit
                    854:  * - acknowledge interrupt if necessary
                    855:  * - stop motor after 2 sec
                    856:  */
                    857: static int FDC_CmdCompleteCommon ( bool DoInt )
                    858: {
                    859:        int     FrameCycles, HblCounterVideo, LineCycles;
                    860: 
                    861:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                    862:        LOG_TRACE(TRACE_FDC, "fdc complete command VBL=%d video_cyc=%d %d@%d pc=%x\n",
                    863:                nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                    864: 
                    865:        FDC_Update_STR ( FDC_STR_BIT_BUSY , 0 );                        /* Remove busy bit */
1.1.1.9   root      866: 
1.1.1.15  root      867:        if ( DoInt )
                    868:                FDC_AcknowledgeInterrupt();
                    869: 
                    870:        FDC.Command = FDCEMU_CMD_MOTOR_STOP;                            /* Fake command to stop the motor */
                    871:        return FDC_DELAY_MOTOR_OFF;
                    872: }
                    873: 
                    874: 
                    875: /*-----------------------------------------------------------------------*/
                    876: /**
                    877:  * Verify track after a type I command.
                    878:  * The FDC will read the first ID field of the current track and will
                    879:  * compare the track number in this ID field with the current Track Register.
                    880:  * If they don't match, an error is set with the RNF bit.
                    881:  * NOTE : in the case of Hatari when using ST/MSA images, the track is always the correct one,
                    882:  * so the verify will always be good (except if no disk is inserted or the physical head is
                    883:  * not on the same track as FDC.TR)
                    884:  * This function could be improved to support other images format where logical track
                    885:  * could be different from physical track (eg Pasti)
                    886:  */
                    887: static void FDC_VerifyTrack ( void )
                    888: {
                    889:        int     FrameCycles, HblCounterVideo, LineCycles;
                    890: 
                    891:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                    892: 
                    893:        if ( ! EmulationDrives[FDC_DRIVE].bDiskInserted )               /* Set RNF bit if no disk is inserted */
1.1.1.9   root      894:        {
1.1.1.15  root      895:                LOG_TRACE(TRACE_FDC, "fdc type I verify track failed no disk in drive=%d VBL=%d video_cyc=%d %d@%d pc=%x\n",
                    896:                        FDC_DRIVE , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                    897: 
                    898:                FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );                 /* Set RNF bit */
                    899:                return;
                    900:        }
                    901: 
                    902:        /* In the case of Hatari when using ST/MSA images, the physical track and the track register */
                    903:        /* should always be the same. Else, it means TR was not correctly set before running the type I command */
                    904:        if ( HeadTrack[ FDC_DRIVE ] != FDC.TR )
                    905:        {
                    906:                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",
                    907:                        FDC.TR , HeadTrack[ FDC_DRIVE ] , FDC_DRIVE ,
                    908:                        nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                    909: 
                    910:                FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );                 /* Set RNF bit */
                    911:                return;
1.1.1.9   root      912:        }
1.1.1.15  root      913: 
                    914:        /* In the case of Hatari when using ST/MSA images, the track is always the correct one */
                    915:        FDC_Update_STR ( FDC_STR_BIT_RNF , 0 );                         /* remove RNF bit */
                    916: }
                    917: 
                    918: 
                    919: /*-----------------------------------------------------------------------*/
                    920: /**
                    921:  * When the motor really stops (2 secs after the last command), clear all related bits in SR
                    922:  */
                    923: static int FDC_UpdateMotorStop ( void )
                    924: {
                    925:        int     FrameCycles, HblCounterVideo, LineCycles;
                    926: 
                    927:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                    928:        LOG_TRACE(TRACE_FDC, "fdc motor stopped VBL=%d video_cyc=%d %d@%d pc=%x\n",
                    929:                nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                    930: 
                    931:        FDC_Update_STR ( FDC_STR_BIT_MOTOR_ON | FDC_STR_BIT_SPIN_UP , 0 );      /* Unset motor and spinup bits */
                    932:                                                /* [NP] FIXME should we clear spin up here or only when the motor is started again ? */
                    933: 
                    934:        FDC.Command = FDCEMU_CMD_NULL;                                  /* Motor stopped, this is the last state */
                    935:        return 0;
1.1       root      936: }
                    937: 
1.1.1.2   root      938: 
                    939: /*-----------------------------------------------------------------------*/
1.1.1.9   root      940: /**
                    941:  * Run 'RESTORE' command
                    942:  */
1.1.1.15  root      943: static int FDC_UpdateRestoreCmd ( void )
1.1       root      944: {
1.1.1.15  root      945:        int     Delay_micro = 0;
                    946: 
                    947:        FDC_Update_STR ( 0 , FDC_STR_BIT_SPIN_UP );                     /* at this point, spin up sequence is ok */
                    948: 
1.1.1.6   root      949:        /* Which command is running? */
1.1.1.15  root      950:        switch (FDC.CommandState)
1.1.1.6   root      951:        {
                    952:         case FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO:
1.1.1.15  root      953:                /* The FDC will try 255 times to reach track 0 using step out signals */
                    954:                /* If track 0 signal is not detected after 255 attempts, the command is interrupted */
                    955:                /* and FDC_STR_BIT_RNF is set in the Status Register. */
                    956:                /* This will never happen in the case of Hatari, because the physical track can't go */
                    957:                /* beyond track FDC_PHYSICAL_MAX_TRACK (=90) */
                    958:                /* TR should be set to 255 once the spin-up sequence is made and the command */
                    959:                /* can't be interrupted anymore by another command (else TR value will be wrong */
                    960:                /* for other type I commands) */
                    961:                FDC.TR = 0xff;                          
                    962:                FDC.CommandState = FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_LOOP;     /* continue in the _LOOP state */
                    963:         case FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO_LOOP:
                    964:                if ( FDC.TR == 0 )                                      /* Track 0 not reached after 255 attempts ? */
                    965:                {                                                       /* (this should never happen in the case of Hatari) */
                    966:                        FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );
                    967:                        FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 );        /* Unset bit TR00 */
                    968:                        Delay_micro = FDC_CmdCompleteCommon( true );
                    969:                }
                    970: 
                    971:                if ( HeadTrack[ FDC_DRIVE ] != 0 )                      /* Are we at track zero ? */
                    972:                {
                    973:                        FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 );        /* Unset bit TR00 */
                    974:                        FDC.TR--;                                       /* One less attempt */
                    975:                        HeadTrack[ FDC_DRIVE ]--;                       /* Move physical head */
                    976:                        Delay_micro = FDC_StepRate_ms[ FDC_STEP_RATE ] * 1000;
                    977:                }
1.1.1.6   root      978:                else
                    979:                {
1.1.1.15  root      980:                        FDC_Update_STR ( 0 , FDC_STR_BIT_TR00 );        /* Set bit TR00 */
                    981:                        FDC.TR = 0;                                     /* Update Track Register to 0 */
                    982:                        FDC.CommandState = FDCEMU_RUN_RESTORE_COMPLETE;
                    983:                        Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
1.1.1.6   root      984:                }
                    985:                break;
                    986:         case FDCEMU_RUN_RESTORE_COMPLETE:
1.1.1.15  root      987:                if ( FDC.CR & FDC_COMMAND_BIT_VERIFY )
                    988:                        FDC_VerifyTrack();
                    989:                Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6   root      990:                break;
                    991:        }
1.1.1.15  root      992: 
                    993:        return Delay_micro;
1.1       root      994: }
                    995: 
1.1.1.2   root      996: 
                    997: /*-----------------------------------------------------------------------*/
1.1.1.9   root      998: /**
                    999:  * Run 'SEEK' command
                   1000:  */
1.1.1.15  root     1001: static int FDC_UpdateSeekCmd ( void )
1.1       root     1002: {
1.1.1.15  root     1003:        int     Delay_micro = 0;
                   1004: 
                   1005:        FDC_Update_STR ( 0 , FDC_STR_BIT_SPIN_UP );                     /* at this point, spin up sequence is ok */
                   1006: 
1.1.1.6   root     1007:        /* Which command is running? */
1.1.1.15  root     1008:        switch (FDC.CommandState)
1.1.1.6   root     1009:        {
                   1010:         case FDCEMU_RUN_SEEK_TOTRACK:
1.1.1.15  root     1011:                if ( FDC.TR == FDC.DR )                                 /* Are we at the selected track ? */
                   1012:                {
                   1013:                        FDC.CommandState = FDCEMU_RUN_SEEK_COMPLETE;
                   1014:                        Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
                   1015:                }
1.1.1.6   root     1016:                else
                   1017:                {
1.1.1.15  root     1018:                        if ( FDC.DR < FDC.TR )                          /* Set StepDirection to the correct value */
                   1019:                                FDC.StepDirection = -1;
                   1020:                        else
                   1021:                                FDC.StepDirection = 1;
                   1022: 
                   1023:                        /* Move head by one track depending on FDC.StepDirection and update Track Register */
                   1024:                        FDC.TR += FDC.StepDirection;
                   1025: 
                   1026:                        if ( ( HeadTrack[ FDC_DRIVE ] == FDC_PHYSICAL_MAX_TRACK ) && ( FDC.StepDirection == 1 ) )
                   1027:                                Delay_micro = FDC_DELAY_COMMAND_COMPLETE;       /* No delay if trying to go after max track */
                   1028: 
                   1029:                        else if ( ( HeadTrack[ FDC_DRIVE ] == 0 ) && ( FDC.StepDirection == -1 ) )
                   1030:                        {
                   1031:                                FDC.TR = 0;                             /* If we reach track 0, we stop there */
                   1032:                                FDC.CommandState = FDCEMU_RUN_SEEK_COMPLETE;
                   1033:                                Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
                   1034:                        }
                   1035: 
1.1.1.6   root     1036:                        else
1.1.1.15  root     1037:                        {
                   1038:                                HeadTrack[ FDC_DRIVE ] += FDC.StepDirection;    /* Move physical head */
                   1039:                                Delay_micro = FDC_StepRate_ms[ FDC_STEP_RATE ] * 1000;
                   1040:                        }
1.1.1.6   root     1041:                }
1.1.1.15  root     1042: 
                   1043:                if ( HeadTrack[ FDC_DRIVE ] == 0 )
                   1044:                        FDC_Update_STR ( 0 , FDC_STR_BIT_TR00 );        /* Set bit TR00 */
                   1045:                else
                   1046:                        FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 );        /* Unset bit TR00 */
                   1047: 
1.1.1.6   root     1048:                break;
                   1049:         case FDCEMU_RUN_SEEK_COMPLETE:
1.1.1.15  root     1050:                if ( FDC.CR & FDC_COMMAND_BIT_VERIFY )
                   1051:                        FDC_VerifyTrack();
                   1052:                Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6   root     1053:                break;
                   1054:        }
1.1.1.15  root     1055: 
                   1056:        return Delay_micro;
1.1       root     1057: }
                   1058: 
1.1.1.2   root     1059: 
                   1060: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1061: /**
                   1062:  * Run 'STEP' command
                   1063:  */
1.1.1.15  root     1064: static int FDC_UpdateStepCmd ( void )
1.1       root     1065: {
1.1.1.15  root     1066:        int     Delay_micro = 0;
                   1067: 
                   1068:        FDC_Update_STR ( 0 , FDC_STR_BIT_SPIN_UP );                     /* at this point, spin up sequence is ok */
                   1069: 
1.1.1.6   root     1070:        /* Which command is running? */
1.1.1.15  root     1071:        switch (FDC.CommandState)
1.1.1.6   root     1072:        {
                   1073:         case FDCEMU_RUN_STEP_ONCE:
1.1.1.15  root     1074:                /* Move head by one track depending on FDC.StepDirection */
                   1075:                if ( FDC.CR & FDC_COMMAND_BIT_UPDATE_TRACK )
                   1076:                        FDC.TR += FDC.StepDirection;                    /* Update Track Register */
                   1077: 
                   1078:                if ( ( HeadTrack[ FDC_DRIVE ] == FDC_PHYSICAL_MAX_TRACK ) && ( FDC.StepDirection == 1 ) )
                   1079:                        Delay_micro = FDC_DELAY_COMMAND_COMPLETE;       /* No delay if trying to go after max track */
                   1080: 
                   1081:                else if ( ( HeadTrack[ FDC_DRIVE ] == 0 ) && ( FDC.StepDirection == -1 ) )
                   1082:                        Delay_micro = FDC_DELAY_COMMAND_COMPLETE;       /* No delay if trying to go before track 0 */
1.1.1.6   root     1083: 
1.1.1.15  root     1084:                else
                   1085:                {
                   1086:                        HeadTrack[ FDC_DRIVE ] += FDC.StepDirection;    /* Move physical head */
                   1087:                        Delay_micro = FDC_StepRate_ms[ FDC_STEP_RATE ] * 1000;
                   1088:                }
                   1089: 
                   1090:                if ( HeadTrack[ FDC_DRIVE ] == 0 )
                   1091:                        FDC_Update_STR ( 0 , FDC_STR_BIT_TR00 );        /* Set bit TR00 */
                   1092:                else
                   1093:                        FDC_Update_STR ( FDC_STR_BIT_TR00 , 0 );        /* Unset bit TR00 */
                   1094: 
                   1095:                FDC.CommandState = FDCEMU_RUN_STEP_COMPLETE;
1.1.1.6   root     1096:                break;
                   1097:         case FDCEMU_RUN_STEP_COMPLETE:
1.1.1.15  root     1098:                if ( FDC.CR & FDC_COMMAND_BIT_VERIFY )
                   1099:                        FDC_VerifyTrack();
                   1100:                Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6   root     1101:                break;
                   1102:        }
1.1.1.15  root     1103: 
                   1104:        return Delay_micro;
1.1       root     1105: }
                   1106: 
1.1.1.2   root     1107: 
                   1108: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1109: /**
1.1.1.15  root     1110:  * Run 'READ SECTOR/S' command
1.1.1.9   root     1111:  */
1.1.1.15  root     1112: static int FDC_UpdateReadSectorsCmd ( void )
1.1       root     1113: {
1.1.1.15  root     1114:        int     Delay_micro = 0;
                   1115:        int     FrameCycles, HblCounterVideo, LineCycles;
                   1116:        int     SectorSize;
                   1117: 
                   1118:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1119: 
                   1120: 
1.1.1.6   root     1121:        /* Which command is running? */
1.1.1.15  root     1122:        switch (FDC.CommandState)
1.1.1.6   root     1123:        {
1.1.1.15  root     1124:         case FDCEMU_RUN_READSECTORS_READDATA:
                   1125:                /* TODO : for better FDC's emulation , we should measure the time it takes to spin the disk */
                   1126:                /* until we reach the next sector header. In the best case, the head would be just at the start */
                   1127:                /* of the sector header, which would mean 6 bytes to be read. */
                   1128:                /* So, the delay will be at least 6 bytes; during that time, FDC.SR can be changed (Delirious Demo 4) */
                   1129:                        FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_CHECK_SECTOR_HEADER;
                   1130:                        Delay_micro = FDC_TRANSFER_BYTES_US ( 6 );      /* Min delay to read 3xA1, FE, TR, SR */
                   1131:                break;
                   1132:         case FDCEMU_RUN_READSECTORS_READDATA_CHECK_SECTOR_HEADER:
                   1133:                /* TODO : on a real FDC we should compare the sector header at the current */
                   1134:                /* spin's position to see if it's the same as FDC.SR. If not, we should wait */
                   1135:                /* for the next sector header and check again. After 5 revolutions, set RNF */
                   1136: 
                   1137:                /* Read a single sector into temporary buffer (512 bytes for ST/MSA) */
                   1138:                FDC_DMA_InitTransfer ();                                /* Update FDC_DMA.PosInBuffer */
                   1139:                if ( FDC_ReadSectorFromFloppy ( DMADiskWorkSpace + FDC_DMA.PosInBuffer , FDC.SR , &SectorSize ) )
                   1140:                {
                   1141:                        FDC_DMA.BytesToTransfer += SectorSize;          /* 512 bytes per sector for ST/MSA disk images */
                   1142:                        FDC_DMA.PosInBuffer += SectorSize;
                   1143:                        FDC.ID_FieldLastSector = FDC.SR;
                   1144:                                
                   1145:                        FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA_DMA;
                   1146:                        Delay_micro = FDC_DELAY_TRANSFER_DMA_16;        /* Transfer blocks of 16 bytes from the sector we just read */
                   1147:                }
                   1148:                else                                                    /* Sector FDC.SR was not found */
                   1149:                {
                   1150:                        FDC.CommandState = FDCEMU_RUN_READSECTORS_RNF;
                   1151:                        Delay_micro = FDC_DELAY_RNF;
                   1152:                }
                   1153:                break;
                   1154:         case FDCEMU_RUN_READSECTORS_READDATA_DMA:
                   1155:                if ( ! FDC_DMA_ReadFromFloppy () )
                   1156:                {
                   1157:                        Delay_micro = FDC_DELAY_TRANSFER_DMA_16;        /* Continue transferring blocks of 16 bytes */
                   1158:                }
                   1159:                else                                                    /* Sector completly transferred, check for multi bit */
                   1160:                {
                   1161:                        if ( FDC.CR & FDC_COMMAND_BIT_MULTIPLE_SECTOR  )
                   1162:                        {
                   1163:                                FDC.SR++;                               /* Try to read next sector and set RNF if not possible */
                   1164:                                FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA;
                   1165:                                Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE;
                   1166:                        }
                   1167:                        else                                            /* Multi=0, stop here with no error */
                   1168:                        {
                   1169:                                FDC.CommandState = FDCEMU_RUN_READSECTORS_COMPLETE;
                   1170:                                Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
                   1171:                        }
                   1172:                }
                   1173:                break;
                   1174:         case FDCEMU_RUN_READSECTORS_RNF:
                   1175:                LOG_TRACE(TRACE_FDC, "fdc type II read sector=%d track=%d drive=%d RNF VBL=%d video_cyc=%d %d@%d pc=%x\n",
                   1176:                          FDC.SR , HeadTrack[ FDC_DRIVE ] , FDC_DRIVE , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.6   root     1177: 
1.1.1.15  root     1178:                FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );
                   1179:                Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6   root     1180:                break;
1.1.1.15  root     1181:         case FDCEMU_RUN_READSECTORS_COMPLETE:
                   1182:                Delay_micro = FDC_CmdCompleteCommon( true );
                   1183:                break;
                   1184:        }
                   1185: 
                   1186:        return Delay_micro;
                   1187: }
                   1188: 
                   1189: 
                   1190: /*-----------------------------------------------------------------------*/
                   1191: /**
                   1192:  * Run 'WRITE SECTOR/S' command
                   1193:  */
                   1194: static int FDC_UpdateWriteSectorsCmd ( void )
                   1195: {
                   1196:        int     Delay_micro = 0;
                   1197:        int     FrameCycles, HblCounterVideo, LineCycles;
                   1198:        int     SectorSize;
                   1199: 
                   1200:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1201: 
                   1202:        if ( Floppy_IsWriteProtected ( FDC_DRIVE ) )
                   1203:        {
                   1204:                LOG_TRACE(TRACE_FDC, "fdc type II write sector=%d track=%d drive=%d WPRT VBL=%d video_cyc=%d %d@%d pc=%x\n",
                   1205:                          FDC.SR , HeadTrack[ FDC_DRIVE ] , FDC_DRIVE , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                   1206: 
                   1207:                FDC_Update_STR ( 0 , FDC_STR_BIT_WPRT );                /* Set WPRT bit */
                   1208:                Delay_micro = FDC_CmdCompleteCommon( true );
                   1209:        }
                   1210:        else
                   1211:                FDC_Update_STR ( FDC_STR_BIT_WPRT , 0 );                /* Unset WPRT bit */
                   1212: 
                   1213:        
                   1214:        /* Which command is running? */
                   1215:        switch (FDC.CommandState)
                   1216:        {
                   1217:         case FDCEMU_RUN_WRITESECTORS_WRITEDATA:
                   1218:                /* TODO : for better FDC's emulation , we should measure the time it takes to spin the disk */
                   1219:                /* until we reach the next sector header. In the best case, the head would be just at the start */
                   1220:                /* of the sector header, which would mean 6 bytes to be read. */
                   1221:                /* So, the delay will be at least 6 bytes; during that time, FDC.SR can be changed (Delirious Demo 4) */
                   1222:                        FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_CHECK_SECTOR_HEADER;
                   1223:                        Delay_micro = FDC_TRANSFER_BYTES_US ( 6 );      /* Min delay to read 3xA1, FE, TR, SR */
                   1224:                break;
                   1225:         case FDCEMU_RUN_WRITESECTORS_WRITEDATA_CHECK_SECTOR_HEADER:
                   1226:                /* TODO : on a real FDC we should compare the sector header at the current */
                   1227:                /* spin's position to see if it's the same as FDC.SR. If not, we should wait */
                   1228:                /* for the next sector header and check again. After 5 revolutions, set RNF */
                   1229: 
                   1230:                /* Write a single sector from RAM (512 bytes for ST/MSA) */
                   1231:                FDC_DMA_InitTransfer ();                                /* Update FDC_DMA.PosInBuffer */
                   1232:                if ( FDC_WriteSectorToFloppy ( FDC_DMA.SectorCount , FDC.SR , &SectorSize ) )
                   1233:                {
                   1234:                        FDC_DMA.BytesToTransfer += SectorSize;          /* 512 bytes per sector for ST/MSA disk images */
                   1235:                        FDC_DMA.PosInBuffer += SectorSize;
                   1236:                        FDC.ID_FieldLastSector = FDC.SR;
                   1237:                                
                   1238:                        FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA_DMA;
                   1239:                        Delay_micro = FDC_DELAY_TRANSFER_DMA_16;        /* Transfer blocks of 16 bytes from the sector we just wrote */
                   1240:                }
                   1241:                else                                                    /* Sector FDC.SR was not found */
                   1242:                {
                   1243:                        FDC.CommandState = FDCEMU_RUN_READSECTORS_RNF;
                   1244:                        Delay_micro = FDC_DELAY_RNF;
                   1245:                }
                   1246:                break;
                   1247:         case FDCEMU_RUN_WRITESECTORS_WRITEDATA_DMA:
                   1248:                if ( ! FDC_DMA_WriteToFloppy () )
                   1249:                {
                   1250:                        Delay_micro = FDC_DELAY_TRANSFER_DMA_16;        /* Continue transferring blocks of 16 bytes */
                   1251:                }
                   1252:                else                                                    /* Sector completly transferred, check for multi bit */
                   1253:                {
                   1254:                        if ( FDC.CR & FDC_COMMAND_BIT_MULTIPLE_SECTOR  )
                   1255:                        {
                   1256:                                FDC.SR++;                               /* Try to write next sector and set RNF if not possible */
                   1257:                                FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA;
                   1258:                                Delay_micro = FDC_DELAY_COMMAND_IMMEDIATE;
                   1259:                        }
                   1260:                        else                                            /* Multi=0, stop here with no error */
                   1261:                        {
                   1262:                                FDC.CommandState = FDCEMU_RUN_WRITESECTORS_COMPLETE;
                   1263:                                Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
                   1264:                        }
                   1265:                }
                   1266:                break;
                   1267:         case FDCEMU_RUN_WRITESECTORS_RNF:
                   1268:                LOG_TRACE(TRACE_FDC, "fdc type II write sector=%d track=%d drive=%d RNF VBL=%d video_cyc=%d %d@%d pc=%x\n",
                   1269:                          FDC.SR , HeadTrack[ FDC_DRIVE ] , FDC_DRIVE , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                   1270: 
                   1271:                FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );
                   1272:                Delay_micro = FDC_CmdCompleteCommon( true );
                   1273:                break;
                   1274:         case FDCEMU_RUN_WRITESECTORS_COMPLETE:
                   1275:                Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6   root     1276:                break;
                   1277:        }
1.1.1.15  root     1278: 
                   1279:        return Delay_micro;
1.1       root     1280: }
                   1281: 
1.1.1.2   root     1282: 
                   1283: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1284: /**
1.1.1.15  root     1285:  * Run 'READ ADDRESS' command
1.1.1.9   root     1286:  */
1.1.1.15  root     1287: static int FDC_UpdateReadAddressCmd ( void )
1.1       root     1288: {
1.1.1.15  root     1289:        int     Delay_micro = 0;
                   1290:        Uint16  CRC;
                   1291:        Uint8   buf[ 4+6 ];
                   1292:        Uint8   *p;
                   1293:        int     Sector;
                   1294: 
                   1295:        if ( ! EmulationDrives[FDC_DRIVE].bDiskInserted )       /* Set RNF bit if no disk is inserted */
                   1296:        {
                   1297:                FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );
                   1298:                Delay_micro = FDC_CmdCompleteCommon( true );
                   1299:        }
                   1300: 
                   1301:        
1.1.1.6   root     1302:        /* Which command is running? */
1.1.1.15  root     1303:        switch (FDC.CommandState)
1.1.1.6   root     1304:        {
1.1.1.15  root     1305:         case FDCEMU_RUN_READADDRESS:
                   1306:                Sector = FDC.ID_FieldLastSector + 1;            /* Increase sector from latest ID Field */
                   1307:                if ( Sector > FDC_GetSectorsPerTrack ( HeadTrack[ FDC_DRIVE ] , FDC_SIDE ) )
                   1308:                        Sector = 1;
                   1309: 
                   1310:                /* In the case of Hatari, only ST/MSA images are supported, so we build */
                   1311:                /* a simplified ID field based on current track/sector/side */
                   1312:                p = buf;
                   1313:                *p++ = 0xa1;                                    /* SYNC bytes and IAM byte are included in the CRC */
                   1314:                *p++ = 0xa1;
                   1315:                *p++ = 0xa1;
                   1316:                *p++ = 0xfe;
                   1317:                *p++ = HeadTrack[ FDC_DRIVE ];
                   1318:                FDC.SR = HeadTrack[ FDC_DRIVE ];                /* The 1st byte of the ID field is also copied into Sector Register */
                   1319:                *p++ = FDC_SIDE;
                   1320:                *p++ = Sector;
                   1321:                *p++ = FDC_SECTOR_SIZE_512;                     /* ST/MSA images are 512 bytes per sector */
                   1322: 
                   1323:                FDC_CRC16 ( buf , 8 , &CRC );
                   1324: 
                   1325:                *p++ = CRC >> 8;
                   1326:                *p++ = CRC & 0xff;
                   1327: 
                   1328:                FDC_DMA_InitTransfer ();                        /* Update FDC_DMA.PosInBuffer */
                   1329:                memcpy ( DMADiskWorkSpace + FDC_DMA.PosInBuffer , buf + 4 , 6 );        /* Don't return the 3 x $A1 and $FE in the Address Field */
                   1330:                FDC_DMA.BytesToTransfer += 6;                   /* 6 bytes per ID field */
                   1331:                FDC_DMA.PosInBuffer += 6;
                   1332: 
                   1333:                FDC.CommandState = FDCEMU_RUN_READADDRESS_DMA;
                   1334: 
                   1335:                /* Very simplified method to get correct timings when doing a Read Address just after an index pulse */
                   1336:                /* or after a previous Read Address. The right method is to use a timer to count bytes since the */
                   1337:                /* latest index pulse, but this would add too much complexity just to handle ST/MSA disk images. */
                   1338:                /* So we use a simpler method where ID_FieldLastSector is set to 0 when we simulate an index pulse. */
                   1339:                /* The number of bytes to skip should be exactly the same as the GAPs used in ReadTrack */
                   1340:                /* (allow Procopy to analyze an ST/MSA disk with the correct timings) */
                   1341:                if ( FDC.ID_FieldLastSector == 0 )                              /* First Read Address just after an index pulse */
                   1342:                        Delay_micro = FDC_TRANSFER_BYTES_US ( 72 + 3 + 1 + 6 ); /* Skip 72+3+1 bytes then read 6 bytes */
                   1343:                else                                                            /* Read Address after a previous sector was just read */
                   1344:                        Delay_micro = FDC_TRANSFER_BYTES_US ( 614 + 6 );        /* Skip 614 bytes then read 6 bytes */
1.1.1.6   root     1345: 
1.1.1.15  root     1346:                FDC.ID_FieldLastSector = Sector;
1.1.1.6   root     1347:                break;
1.1.1.15  root     1348:         case FDCEMU_RUN_READADDRESS_DMA:
                   1349:                FDC_DMA_ReadFromFloppy ();                      /* Transfer bytes if 16 bytes or more are in the DMA buffer */
                   1350: 
                   1351:                FDC.CommandState = FDCEMU_RUN_READADDRESS_COMPLETE;
                   1352:                Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
                   1353:                break;
                   1354:         case FDCEMU_RUN_READADDRESS_COMPLETE:
                   1355:                Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6   root     1356:                break;
                   1357:        }
1.1.1.15  root     1358: 
                   1359:        return Delay_micro;
1.1       root     1360: }
                   1361: 
1.1.1.2   root     1362: 
                   1363: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1364: /**
1.1.1.15  root     1365:  * Run 'READ TRACK' command
1.1.1.9   root     1366:  */
1.1.1.15  root     1367: static int FDC_UpdateReadTrackCmd ( void )
1.1       root     1368: {
1.1.1.15  root     1369:        int     Delay_micro = 0;
                   1370:        Uint16  CRC;
                   1371:        Uint8   *buf;
                   1372:        Uint8   *buf_crc;
                   1373:        int     Sector;
                   1374:        int     SectorSize;
                   1375:        int     i;
                   1376: 
                   1377:        if ( ! EmulationDrives[FDC_DRIVE].bDiskInserted )       /* Set RNF bit if no disk is inserted */
                   1378:        {
                   1379:                FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );         /* [NP] Should we return random bytes instead ? */
                   1380:                Delay_micro = FDC_CmdCompleteCommon( true );
                   1381:        }
                   1382: 
                   1383: 
1.1.1.6   root     1384:        /* Which command is running? */
1.1.1.15  root     1385:        switch (FDC.CommandState)
1.1.1.6   root     1386:        {
1.1.1.15  root     1387:         case FDCEMU_RUN_READTRACK:
                   1388: 
                   1389:                /* Build the track data */
                   1390:                FDC_DMA_InitTransfer ();                                        /* Update FDC_DMA.PosInBuffer */
                   1391:                buf = DMADiskWorkSpace + FDC_DMA.PosInBuffer;
1.1.1.6   root     1392: 
1.1.1.15  root     1393:                if ( ( FDC_SIDE == 1 )                                          /* Try to read side 1 on a disk that doesn't have 2 sides */
                   1394:                        && ( FDC_GetSidesPerDisk ( HeadTrack[ FDC_DRIVE ] ) != 2 ) )
                   1395:                {
                   1396:                        for ( i=0 ; i<FDC_TRACK_BYTES_STANDARD ; i++ )
                   1397:                                *buf++ = rand() & 0xff;                         /* Fill the track buffer with random bytes */
1.1.1.6   root     1398:                }
1.1.1.15  root     1399:                
                   1400:                else                                                            /* Track/side available in the disk image */
1.1.1.6   root     1401:                {
1.1.1.15  root     1402:                        for ( i=0 ; i<60 ; i++ )                *buf++ = 0x4e;          /* GAP1 */
                   1403: 
                   1404:                        for ( Sector=1 ; Sector <= FDC_GetSectorsPerTrack ( HeadTrack[ FDC_DRIVE ] , FDC_SIDE ) ; Sector++ )
                   1405:                        {
                   1406:                                for ( i=0 ; i<12 ; i++ )        *buf++ = 0x00;          /* GAP2 */
                   1407: 
                   1408:                                buf_crc = buf;
                   1409:                                for ( i=0 ; i<3 ; i++ )         *buf++ = 0xa1;          /* SYNC (write $F5) */
                   1410:                                *buf++ = 0xfe;                                          /* Index Address Mark */
                   1411:                                *buf++ = HeadTrack[ FDC_DRIVE ];                        /* Track */
                   1412:                                *buf++ = FDC_SIDE;                                      /* Side */
                   1413:                                *buf++ = Sector;                                        /* Sector */
                   1414:                                FDC.ID_FieldLastSector = Sector;
                   1415:                                *buf++ = FDC_SECTOR_SIZE_512;                           /* 512 bytes/sector for ST/MSA */
                   1416:                                FDC_CRC16 ( buf_crc , buf - buf_crc , &CRC );
                   1417:                                *buf++ = CRC >> 8;                                      /* CRC1 (write $F7) */
                   1418:                                *buf++ = CRC & 0xff;                                    /* CRC2 */
                   1419: 
                   1420:                                for ( i=0 ; i<22 ; i++ )        *buf++ = 0x4e;          /* GAP3a */
                   1421:                                for ( i=0 ; i<12 ; i++ )        *buf++ = 0x00;          /* GAP3b */
                   1422: 
                   1423:                                buf_crc = buf;
                   1424:                                for ( i=0 ; i<3 ; i++ )         *buf++ = 0xa1;          /* SYNC (write $F5) */
                   1425:                                *buf++ = 0xfb;                                          /* Data Address Mark */
                   1426: 
                   1427:                                if ( ! FDC_ReadSectorFromFloppy ( buf , Sector , &SectorSize ) )        /* Read a single 512 bytes sector into temporary buffer */
                   1428:                                {
                   1429:                                        /* Do nothing in case of error, we could put some random bytes, but this case should */
                   1430:                                        /* not happen with ST/MSA disk images, all sectors should be present on each track. */
                   1431:                                }
                   1432:                                buf += SectorSize;
                   1433: 
                   1434:                                FDC_CRC16 ( buf_crc , buf - buf_crc , &CRC );
                   1435:                                *buf++ = CRC >> 8;                                      /* CRC1 (write $F7) */
                   1436:                                *buf++ = CRC & 0xff;                                    /* CRC2 */
                   1437: 
                   1438:                                for ( i=0 ; i<40 ; i++ )        *buf++ = 0x4e;          /* GAP4 */
                   1439:                        }
                   1440: 
                   1441:                        while ( buf < DMADiskWorkSpace + FDC_DMA.PosInBuffer + FDC_TRACK_BYTES_STANDARD )       /* Complete the track buffer */
                   1442:                              *buf++ = 0x4e;                                            /* GAP5 */
1.1.1.6   root     1443:                }
1.1       root     1444: 
1.1.1.15  root     1445:                /* Transfer Track data to RAM using DMA */
                   1446:                FDC_DMA.BytesToTransfer += FDC_TRACK_BYTES_STANDARD;
                   1447:                FDC_DMA.PosInBuffer += FDC_TRACK_BYTES_STANDARD;
1.1.1.2   root     1448: 
1.1.1.15  root     1449:                FDC.CommandState = FDCEMU_RUN_READTRACK_DMA;
                   1450:                Delay_micro = FDC_DELAY_TRANSFER_DMA_16;                        /* Transfer blocks of 16 bytes from the track we just read */
                   1451:                break;
                   1452:         case FDCEMU_RUN_READTRACK_DMA:
                   1453:                if ( ! FDC_DMA_ReadFromFloppy () )
1.1.1.6   root     1454:                {
1.1.1.15  root     1455:                        Delay_micro = FDC_DELAY_TRANSFER_DMA_16;                /* Continue transferring blocks of 16 bytes */
1.1.1.6   root     1456:                }
1.1.1.15  root     1457:                else                                                            /* Track completly transferred */
1.1.1.6   root     1458:                {
1.1.1.15  root     1459:                        FDC.CommandState = FDCEMU_RUN_READTRACK_COMPLETE;
                   1460:                        Delay_micro = FDC_DELAY_COMMAND_COMPLETE;
1.1.1.6   root     1461:                }
                   1462:                break;
1.1.1.15  root     1463:         case FDCEMU_RUN_READTRACK_COMPLETE:
                   1464:                Delay_micro = FDC_CmdCompleteCommon( true );
1.1.1.6   root     1465:                break;
                   1466:        }
1.1.1.15  root     1467: 
                   1468:        return Delay_micro;
1.1       root     1469: }
                   1470: 
1.1.1.2   root     1471: 
                   1472: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1473: /**
1.1.1.15  root     1474:  * Common to types I, II and III
                   1475:  *
                   1476:  * Start motor / spin up sequence if needed
1.1.1.11  root     1477:  */
1.1.1.15  root     1478: 
                   1479: static int FDC_Check_MotorON ( Uint8 FDC_CR )
1.1.1.11  root     1480: {
1.1.1.15  root     1481:        int     FrameCycles, HblCounterVideo, LineCycles;
                   1482: 
                   1483:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1484: 
                   1485:        if ( ( ( FDC_CR & FDC_COMMAND_BIT_MOTOR_ON ) == 0 )                     /* Command wants motor on / spin up */
                   1486:          && ( ( FDC.STR & FDC_STR_BIT_MOTOR_ON ) == 0 ) )                      /* Motor on not enabled yet */
1.1.1.11  root     1487:        {
1.1.1.15  root     1488:                LOG_TRACE(TRACE_FDC, "fdc start motor VBL=%d video_cyc=%d %d@%d pc=%x\n",
                   1489:                        nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                   1490:                FDC_Update_STR ( FDC_STR_BIT_SPIN_UP , FDC_STR_BIT_MOTOR_ON );  /* Unset spin up bit and set motor bit */
                   1491:                return FDC_DELAY_MOTOR_ON;                                      /* Motor's delay */
1.1.1.11  root     1492:        }
1.1.1.15  root     1493: 
                   1494:        /* Other cases : set bit in STR and don't add delay */
                   1495:        LOG_TRACE(TRACE_FDC, "fdc motor already on VBL=%d video_cyc=%d %d@%d pc=%x\n",
                   1496:                nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                   1497:        FDC_Update_STR ( 0 , FDC_STR_BIT_MOTOR_ON );
                   1498:        return 0;
1.1.1.11  root     1499: }
                   1500: 
                   1501: 
                   1502: /*-----------------------------------------------------------------------*/
                   1503: /**
1.1.1.9   root     1504:  * Type I Commands
                   1505:  *
                   1506:  * Restore, Seek, Step, Step-In and Step-Out
                   1507:  */
1.1       root     1508: 
1.1.1.2   root     1509: 
                   1510: /*-----------------------------------------------------------------------*/
1.1.1.15  root     1511: static int FDC_TypeI_Restore(void)
1.1       root     1512: {
1.1.1.15  root     1513:        int     FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12  root     1514: 
                   1515:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1516: 
1.1.1.16! root     1517:        LOG_TRACE(TRACE_FDC, "fdc type I restore drive=%d tr=0x%x head_track=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
        !          1518:                  FDC_DRIVE , FDC.TR , HeadTrack[ FDC_DRIVE ] , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10  root     1519: 
1.1.1.6   root     1520:        /* Set emulation to seek to track zero */
1.1.1.15  root     1521:        FDC.Command = FDCEMU_CMD_RESTORE;
                   1522:        FDC.CommandState = FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO;
                   1523: 
                   1524:        FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
1.1       root     1525: 
1.1.1.15  root     1526:        return FDC_DELAY_TYPE_I_PREPARE;
1.1       root     1527: }
                   1528: 
1.1.1.2   root     1529: 
                   1530: /*-----------------------------------------------------------------------*/
1.1.1.15  root     1531: static int FDC_TypeI_Seek ( void )
1.1       root     1532: {
1.1.1.15  root     1533:        int     FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12  root     1534: 
                   1535:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1536: 
1.1.1.16! root     1537:        LOG_TRACE(TRACE_FDC, "fdc type I seek dest_track=0x%x drive=%d tr=0x%x head_track=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
        !          1538:                  FDC.DR, FDC_DRIVE , FDC.TR , HeadTrack[ FDC_DRIVE ] , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10  root     1539: 
1.1.1.6   root     1540:        /* Set emulation to seek to chosen track */
1.1.1.15  root     1541:        FDC.Command = FDCEMU_CMD_SEEK;
                   1542:        FDC.CommandState = FDCEMU_RUN_SEEK_TOTRACK;
                   1543: 
                   1544:        FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
1.1       root     1545: 
1.1.1.15  root     1546:        return FDC_DELAY_TYPE_I_PREPARE;
1.1       root     1547: }
                   1548: 
1.1.1.2   root     1549: 
                   1550: /*-----------------------------------------------------------------------*/
1.1.1.15  root     1551: static int FDC_TypeI_Step ( void )
1.1       root     1552: {
1.1.1.15  root     1553:        int     FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12  root     1554: 
                   1555:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1556: 
1.1.1.16! root     1557:        LOG_TRACE(TRACE_FDC, "fdc type I step %d drive=%d tr=0x%x head_track=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
        !          1558:                  FDC.StepDirection, FDC_DRIVE , FDC.TR , HeadTrack[ FDC_DRIVE ] , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.15  root     1559: 
                   1560:        /* Set emulation to step (using same direction as latest seek executed, ie 'FDC.StepDirection') */
                   1561:        FDC.Command = FDCEMU_CMD_STEP;
                   1562:        FDC.CommandState = FDCEMU_RUN_STEP_ONCE;
1.1.1.10  root     1563: 
1.1.1.15  root     1564:        FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
1.1       root     1565: 
1.1.1.15  root     1566:        return FDC_DELAY_TYPE_I_PREPARE;
1.1       root     1567: }
                   1568: 
1.1.1.2   root     1569: 
                   1570: /*-----------------------------------------------------------------------*/
1.1.1.15  root     1571: static int FDC_TypeI_StepIn(void)
1.1       root     1572: {
1.1.1.15  root     1573:        int     FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12  root     1574: 
                   1575:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1576: 
1.1.1.16! root     1577:        LOG_TRACE(TRACE_FDC, "fdc type I step in drive=%d tr=0x%x head_track=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
        !          1578:                  FDC_DRIVE , FDC.TR , HeadTrack[ FDC_DRIVE ] , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10  root     1579: 
1.1.1.15  root     1580:        /* Set emulation to step in (direction = +1) */
                   1581:        FDC.Command = FDCEMU_CMD_STEP;
                   1582:        FDC.CommandState = FDCEMU_RUN_STEP_ONCE;
                   1583:        FDC.StepDirection = 1;                                          /* Increment track*/
1.1       root     1584: 
1.1.1.15  root     1585:        FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
                   1586: 
                   1587:        return FDC_DELAY_TYPE_I_PREPARE;
1.1       root     1588: }
                   1589: 
1.1.1.2   root     1590: 
                   1591: /*-----------------------------------------------------------------------*/
1.1.1.15  root     1592: static int FDC_TypeI_StepOut ( void )
1.1       root     1593: {
1.1.1.15  root     1594:        int     FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12  root     1595: 
                   1596:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1597: 
1.1.1.16! root     1598:        LOG_TRACE(TRACE_FDC, "fdc type I step out drive=%d tr=0x%x head_track=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
        !          1599:                  FDC_DRIVE , FDC.TR , HeadTrack[ FDC_DRIVE ] , nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.15  root     1600: 
                   1601:        /* Set emulation to step out (direction = -1) */
                   1602:        FDC.Command = FDCEMU_CMD_STEP;
                   1603:        FDC.CommandState = FDCEMU_RUN_STEP_ONCE;
                   1604:        FDC.StepDirection = -1;                                         /* Decrement track */
1.1.1.10  root     1605: 
1.1.1.15  root     1606:        FDC_Update_STR ( FDC_STR_BIT_INDEX | FDC_STR_BIT_CRC_ERROR | FDC_STR_BIT_RNF , FDC_STR_BIT_BUSY );
1.1       root     1607: 
1.1.1.15  root     1608:        return FDC_DELAY_TYPE_I_PREPARE;
1.1       root     1609: }
                   1610: 
1.1.1.2   root     1611: 
                   1612: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1613: /**
                   1614:  * Type II Commands
                   1615:  *
1.1.1.15  root     1616:  * Read Sector, Write Sector
1.1.1.9   root     1617:  */
1.1       root     1618: 
1.1.1.2   root     1619: 
                   1620: /*-----------------------------------------------------------------------*/
1.1.1.15  root     1621: static int FDC_TypeII_ReadSector ( void )
1.1       root     1622: {
1.1.1.15  root     1623:        int     Delay_micro = 0;
                   1624:        int     FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12  root     1625: 
                   1626:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1627: 
1.1.1.16! root     1628:        LOG_TRACE(TRACE_FDC, "fdc type II read sector sector=0x%x multi=%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",
        !          1629:                  FDC.SR, ( FDC.CR & FDC_COMMAND_BIT_MULTIPLE_SECTOR ) ? "on" : "off" , FDC.TR , HeadTrack[ FDC_DRIVE ] , FDC_SIDE, FDC_DRIVE , FDC_DMA.SectorCount ,
1.1.1.15  root     1630:                  FDC_GetDMAAddress(), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.12  root     1631: 
1.1.1.15  root     1632:        /* Set emulation to read sector(s) */
                   1633:        FDC.Command = FDCEMU_CMD_READSECTORS;
                   1634:        FDC.CommandState = FDCEMU_RUN_READSECTORS_READDATA;
1.1.1.10  root     1635: 
1.1.1.15  root     1636:        FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
                   1637:                | FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE | FDC_STR_BIT_WPRT , FDC_STR_BIT_BUSY );
1.1       root     1638: 
1.1.1.15  root     1639:        if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
                   1640:                Delay_micro = FDC_DELAY_HEAD_LOAD;
                   1641:        
                   1642:        return FDC_DELAY_TYPE_II_PREPARE + Delay_micro;
1.1       root     1643: }
                   1644: 
1.1.1.2   root     1645: 
                   1646: /*-----------------------------------------------------------------------*/
1.1.1.15  root     1647: static int FDC_TypeII_WriteSector ( void )
1.1       root     1648: {
1.1.1.15  root     1649:        int     Delay_micro = 0;
                   1650:        int     FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12  root     1651: 
                   1652:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1653: 
1.1.1.16! root     1654:        LOG_TRACE(TRACE_FDC, "fdc type II write sector sector=0x%x multi=%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",
        !          1655:                  FDC.SR, ( FDC.CR & FDC_COMMAND_BIT_MULTIPLE_SECTOR ) ? "on" : "off" , FDC.TR , HeadTrack[ FDC_DRIVE ] , FDC_SIDE, FDC_DRIVE , FDC_DMA.SectorCount,
1.1.1.15  root     1656:                  FDC_GetDMAAddress(), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.2   root     1657: 
1.1.1.15  root     1658:        /* Set emulation to write a sector(s) */
                   1659:        FDC.Command = FDCEMU_CMD_WRITESECTORS;
                   1660:        FDC.CommandState = FDCEMU_RUN_WRITESECTORS_WRITEDATA;
1.1.1.10  root     1661: 
1.1.1.15  root     1662:        FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
                   1663:                | FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE , FDC_STR_BIT_BUSY );
1.1       root     1664: 
1.1.1.15  root     1665:        if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
                   1666:                Delay_micro = FDC_DELAY_HEAD_LOAD;
                   1667:        
                   1668:        return FDC_DELAY_TYPE_II_PREPARE + Delay_micro;
1.1       root     1669: }
                   1670: 
1.1.1.2   root     1671: 
                   1672: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1673: /**
                   1674:  * Type III Commands
                   1675:  *
                   1676:  * Read Address, Read Track, Write Track
                   1677:  */
1.1       root     1678: 
1.1.1.2   root     1679: 
                   1680: /*-----------------------------------------------------------------------*/
1.1.1.15  root     1681: static int FDC_TypeIII_ReadAddress ( void )
1.1       root     1682: {
1.1.1.15  root     1683:        int     Delay_micro = 0;
                   1684:        int     FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12  root     1685: 
                   1686:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1687: 
1.1.1.16! root     1688:        LOG_TRACE(TRACE_FDC, "fdc type III read address tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
        !          1689:                  FDC.TR , HeadTrack[ FDC_DRIVE ], FDC_SIDE, FDC_DRIVE , FDC_GetDMAAddress(),
1.1.1.12  root     1690:                  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10  root     1691: 
1.1.1.11  root     1692:        /* Set emulation to seek to track zero */
1.1.1.15  root     1693:        FDC.Command = FDCEMU_CMD_READADDRESS;
                   1694:        FDC.CommandState = FDCEMU_RUN_READADDRESS;
1.1.1.11  root     1695: 
1.1.1.15  root     1696:        FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
                   1697:                | FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE | FDC_STR_BIT_WPRT , FDC_STR_BIT_BUSY );
                   1698: 
                   1699:        if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
                   1700:                Delay_micro = FDC_DELAY_HEAD_LOAD;
                   1701:        
                   1702:        return FDC_DELAY_TYPE_III_PREPARE + Delay_micro;
1.1       root     1703: }
                   1704: 
1.1.1.2   root     1705: 
                   1706: /*-----------------------------------------------------------------------*/
1.1.1.15  root     1707: static int FDC_TypeIII_ReadTrack ( void )
1.1       root     1708: {
1.1.1.15  root     1709:        int     Delay_micro = 0;
                   1710:        int     FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12  root     1711: 
                   1712:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1713: 
1.1.1.16! root     1714:        LOG_TRACE(TRACE_FDC, "fdc type III read track tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
        !          1715:                  FDC.TR , HeadTrack[ FDC_DRIVE ], FDC_SIDE, FDC_DRIVE , FDC_GetDMAAddress(),
1.1.1.15  root     1716:                  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10  root     1717: 
1.1.1.15  root     1718:        /* Set emulation to read a single track */
                   1719:        FDC.Command = FDCEMU_CMD_READTRACK;
                   1720:        FDC.CommandState = FDCEMU_RUN_READTRACK;
1.1.1.5   root     1721: 
1.1.1.15  root     1722:        FDC_Update_STR ( FDC_STR_BIT_DRQ | FDC_STR_BIT_LOST_DATA | FDC_STR_BIT_CRC_ERROR
                   1723:                | FDC_STR_BIT_RNF | FDC_STR_BIT_RECORD_TYPE | FDC_STR_BIT_WPRT , FDC_STR_BIT_BUSY );
1.1.1.5   root     1724: 
1.1.1.15  root     1725:        if ( FDC.CR & FDC_COMMAND_BIT_HEAD_LOAD )
                   1726:                Delay_micro = FDC_DELAY_HEAD_LOAD;
1.1       root     1727: 
1.1.1.15  root     1728:        return FDC_DELAY_TYPE_III_PREPARE + Delay_micro;
1.1       root     1729: }
                   1730: 
1.1.1.2   root     1731: 
                   1732: /*-----------------------------------------------------------------------*/
1.1.1.15  root     1733: static int FDC_TypeIII_WriteTrack ( void )
1.1       root     1734: {
1.1.1.15  root     1735:        int     FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12  root     1736: 
                   1737:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1738: 
1.1.1.16! root     1739:        LOG_TRACE(TRACE_FDC, "fdc type III write track tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
        !          1740:                  FDC.TR , HeadTrack[ FDC_DRIVE ], FDC_SIDE, FDC_DRIVE , FDC_GetDMAAddress(),
1.1.1.15  root     1741:                  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10  root     1742: 
                   1743:        Log_Printf(LOG_TODO, "FDC type III command 'write track' does not work yet!\n");
1.1.1.5   root     1744: 
1.1.1.15  root     1745:        /* FIXME: "Write track" should write all the sectors after extracting them from the track data */
1.1.1.5   root     1746: 
1.1.1.6   root     1747:        /* Set emulation to write a single track */
1.1.1.15  root     1748:        FDC_Update_STR ( 0 , FDC_STR_BIT_RNF );                         /* FIXME : Not supported yet, set RNF bit */
                   1749:        FDC.Command = FDCEMU_CMD_NULL;
                   1750:        FDC.CommandState = FDCEMU_RUN_NULL;
1.1       root     1751: 
1.1.1.15  root     1752:        return FDC_DELAY_TYPE_III_PREPARE;
1.1       root     1753: }
                   1754: 
1.1.1.2   root     1755: 
                   1756: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1757: /**
                   1758:  * Type IV Commands
                   1759:  *
                   1760:  * Force Interrupt
                   1761:  */
1.1       root     1762: 
1.1.1.2   root     1763: 
                   1764: /*-----------------------------------------------------------------------*/
1.1.1.15  root     1765: static int FDC_TypeIV_ForceInterrupt ( bool bCauseCPUInterrupt )
1.1       root     1766: {
1.1.1.15  root     1767:        int     Delay_micro;
                   1768:        int     FrameCycles, HblCounterVideo, LineCycles;
1.1.1.12  root     1769: 
                   1770:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1771: 
1.1.1.15  root     1772:        LOG_TRACE(TRACE_FDC, "fdc type IV force int 0x%x irq=%d index=%d VBL=%d video_cyc=%d %d@%dpc=%x\n",
                   1773:                  FDC.CR , ( FDC.CR & 0x8 ) >> 3 , ( FDC.CR & 0x4 ) >> 2 ,
1.1.1.12  root     1774:                  nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.10  root     1775: 
1.1.1.15  root     1776:        /* For Type II/III commands, LOST DATA bit is never set (DRQ is always handled by the DMA) */
                   1777:        /* (eg Super Monaco GP on Superior 65 : loader fails if LOST DATA is set when there're not enough DMA sectors to transfer bytes) */
                   1778:        FDC_Update_STR ( FDC_STR_BIT_LOST_DATA , 0 );                   /* Remove LOST DATA / TR00 bit */
                   1779: 
                   1780:        /* TR00 is updated when a type I command is interrupted or when no command was running */
                   1781:        /* MOTOR ON is also set when a type I command is interrupted or when no command was running */
                   1782:        /* (eg Knightmare on DBUG 24 : loader fails if motor is off because of the added delay to start it) */
                   1783:        if ( ( ( FDC.STR & FDC_STR_BIT_BUSY ) == 0 )                    /* No command running */
                   1784:          || ( FDC.CommandType == 1 ) )                                 /* Or busy command is Type I */
                   1785:        {
                   1786:                if ( HeadTrack[ FDC_DRIVE ] == 0 )
                   1787:                        FDC_Update_STR ( 0 , FDC_STR_BIT_TR00 );        /* Set bit TR00 */
                   1788: 
                   1789:                FDC_Update_STR ( 0 , FDC_STR_BIT_MOTOR_ON );            /* Set Motor ON */
                   1790:        }
                   1791: 
                   1792:        /* Remove busy bit, ack int and stop the motor */
                   1793:        Delay_micro = FDC_CmdCompleteCommon( bCauseCPUInterrupt );
1.1.1.6   root     1794: 
1.1.1.15  root     1795:        return FDC_DELAY_TYPE_IV_PREPARE + Delay_micro;
1.1       root     1796: }
                   1797: 
1.1.1.2   root     1798: 
                   1799: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1800: /**
                   1801:  * Execute Type I commands
                   1802:  */
1.1.1.15  root     1803: static int FDC_ExecuteTypeICommands ( void )
1.1       root     1804: {
1.1.1.15  root     1805:        int     Delay_micro = 0;
                   1806: 
                   1807:        FDC.CommandType = 1;
1.1.1.6   root     1808:        MFP_GPIP |= 0x20;
1.1       root     1809: 
1.1.1.6   root     1810:        /* Check Type I Command */
1.1.1.15  root     1811:        switch ( FDC.CR & 0xf0 )
1.1.1.6   root     1812:        {
                   1813:         case 0x00:             /* Restore */
1.1.1.15  root     1814:                Delay_micro = FDC_TypeI_Restore();
1.1.1.6   root     1815:                break;
                   1816:         case 0x10:             /* Seek */
1.1.1.15  root     1817:                Delay_micro = FDC_TypeI_Seek();
1.1.1.6   root     1818:                break;
                   1819:         case 0x20:             /* Step */
                   1820:         case 0x30:
1.1.1.15  root     1821:                Delay_micro = FDC_TypeI_Step();
1.1.1.6   root     1822:                break;
                   1823:         case 0x40:             /* Step-In */
                   1824:         case 0x50:
1.1.1.15  root     1825:                Delay_micro = FDC_TypeI_StepIn();
1.1.1.6   root     1826:                break;
                   1827:         case 0x60:             /* Step-Out */
                   1828:         case 0x70:
1.1.1.15  root     1829:                Delay_micro = FDC_TypeI_StepOut();
1.1.1.6   root     1830:                break;
                   1831:        }
1.1       root     1832: 
1.1.1.15  root     1833:        /* Check if motor needs to be started and add possible delay */
                   1834:        Delay_micro += FDC_Check_MotorON ( FDC.CR );
                   1835:        
                   1836:        return Delay_micro;
1.1       root     1837: }
                   1838: 
1.1.1.2   root     1839: 
                   1840: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1841: /**
                   1842:  * Execute Type II commands
                   1843:  */
1.1.1.15  root     1844: static int FDC_ExecuteTypeIICommands ( void )
1.1       root     1845: {
1.1.1.15  root     1846:        int     Delay_micro = 0;
                   1847: 
                   1848:        FDC.CommandType = 2;
1.1.1.6   root     1849:        MFP_GPIP |= 0x20;
1.1       root     1850: 
1.1.1.6   root     1851:        /* Check Type II Command */
1.1.1.15  root     1852:        switch ( FDC.CR & 0xf0 )
1.1.1.6   root     1853:        {
1.1.1.15  root     1854:         case 0x80:             /* Read Sector multi=0*/
                   1855:         case 0x90:             /* Read Sectors multi=1 */
                   1856:                Delay_micro = FDC_TypeII_ReadSector();
1.1.1.6   root     1857:                break;
1.1.1.15  root     1858:         case 0xa0:             /* Write Sector multi=0 */
                   1859:         case 0xb0:             /* Write Sectors multi=1 */
                   1860:                Delay_micro = FDC_TypeII_WriteSector();
1.1.1.6   root     1861:                break;
                   1862:        }
1.1       root     1863: 
1.1.1.15  root     1864:        /* Check if motor needs to be started and add possible delay */
                   1865:        Delay_micro += FDC_Check_MotorON ( FDC.CR );
                   1866: 
                   1867:        return Delay_micro;
1.1       root     1868: }
                   1869: 
1.1.1.2   root     1870: 
                   1871: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1872: /**
                   1873:  * Execute Type III commands
                   1874:  */
1.1.1.15  root     1875: static int FDC_ExecuteTypeIIICommands ( void )
1.1       root     1876: {
1.1.1.15  root     1877:        int     Delay_micro = 0;
                   1878: 
                   1879:        FDC.CommandType = 3;
1.1.1.6   root     1880:        MFP_GPIP |= 0x20;
1.1       root     1881: 
1.1.1.6   root     1882:        /* Check Type III Command */
1.1.1.15  root     1883:        switch ( FDC.CR & 0xf0 )
1.1.1.6   root     1884:        {
                   1885:         case 0xc0:             /* Read Address */
1.1.1.15  root     1886:                Delay_micro = FDC_TypeIII_ReadAddress();
1.1.1.6   root     1887:                break;
                   1888:         case 0xe0:             /* Read Track */
1.1.1.15  root     1889:                Delay_micro = FDC_TypeIII_ReadTrack();
1.1.1.6   root     1890:                break;
                   1891:         case 0xf0:             /* Write Track */
1.1.1.15  root     1892:                Delay_micro = FDC_TypeIII_WriteTrack();
1.1.1.6   root     1893:                break;
                   1894:        }
1.1       root     1895: 
1.1.1.15  root     1896:        /* Check if motor need to be started and add possible delay */
                   1897:        Delay_micro += FDC_Check_MotorON ( FDC.CR );
                   1898: 
                   1899:        return Delay_micro;
1.1       root     1900: }
                   1901: 
1.1.1.2   root     1902: 
                   1903: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1904: /**
                   1905:  * Execute Type IV commands
                   1906:  */
1.1.1.15  root     1907: static int FDC_ExecuteTypeIVCommands ( void )
1.1       root     1908: {
1.1.1.15  root     1909:        int     Delay_micro;
1.1       root     1910: 
1.1.1.15  root     1911:        /* Check Type IV command */
                   1912:        /* Most of the time a 0xD8 command is followed by a 0xD0 command to clear the IRQ signal */
                   1913:        if ( FDC.CR & 0x8 )                                             /* I3 set (0xD8) : immediate interrupt with IRQ */
                   1914:                Delay_micro = FDC_TypeIV_ForceInterrupt ( true );
                   1915: 
                   1916:        else if ( FDC.CR & 0x4 )                                        /* I2 set (0xD4) : IRQ on next index pulse */
                   1917:        {
                   1918:                /* FIXME [NP] This is not complete, we should report */
                   1919:                /* an interrupt each time the FDC sees an index pulse, not just once */
                   1920:                FDC.ID_FieldLastSector = 0;                             /* We simulate an index pulse now */
                   1921:                Delay_micro = FDC_TypeIV_ForceInterrupt ( true );
                   1922:        }
                   1923: 
                   1924:        else                                                            /* I3-I2 clear (0xD0) : stop command without IRQ */
                   1925:        {
                   1926:                MFP_GPIP |= 0x20;                                       /* reset IRQ signal */
                   1927:                Delay_micro = FDC_TypeIV_ForceInterrupt ( false );
                   1928:        }
                   1929:                
                   1930:        FDC.CommandType = 4;                                            /* Change CommandType after interrupting the current command */
                   1931:        return Delay_micro;
1.1       root     1932: }
                   1933: 
1.1.1.2   root     1934: 
                   1935: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1936: /**
                   1937:  * Find FDC command type and execute
                   1938:  */
1.1.1.15  root     1939: static void FDC_ExecuteCommand ( void )
1.1       root     1940: {
1.1.1.15  root     1941:        int     Delay_micro;
                   1942: 
1.1.1.6   root     1943:        /* Check type of command and execute */
1.1.1.15  root     1944:        if ( ( FDC.CR & 0x80 ) == 0 )                                   /* Type I - Restore, Seek, Step, Step-In, Step-Out */
                   1945:                Delay_micro = FDC_ExecuteTypeICommands();
                   1946:        else if ( ( FDC.CR & 0x40 ) == 0 )                              /* Type II - Read Sector, Write Sector */
                   1947:                Delay_micro = FDC_ExecuteTypeIICommands();
                   1948:        else if ( ( FDC.CR & 0xf0 ) != 0xd0 )                           /* Type III - Read Address, Read Track, Write Track */
                   1949:                Delay_micro = FDC_ExecuteTypeIIICommands();
                   1950:        else                                                            /* Type IV - Force Interrupt */
                   1951:                Delay_micro = FDC_ExecuteTypeIVCommands();
1.1.1.9   root     1952: 
1.1.1.15  root     1953:        FDC.ReplaceCommandPossible = true;                              /* This new command can be replaced during the Delay_micro phase */
                   1954:        CycInt_AddAbsoluteInterrupt ( FDC_DelayToCpuCycles ( Delay_micro ) , INT_CPU_CYCLE , INTERRUPT_FDC );
1.1       root     1955: }
                   1956: 
1.1.1.2   root     1957: 
                   1958: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1959: /**
1.1.1.15  root     1960:  * Write to SectorCount register $ff8604
1.1.1.9   root     1961:  */
1.1.1.15  root     1962: static void FDC_WriteSectorCountRegister ( void )
1.1       root     1963: {
1.1.1.12  root     1964:        int FrameCycles, HblCounterVideo, LineCycles;
                   1965: 
                   1966:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1967: 
1.1.1.15  root     1968:        LOG_TRACE(TRACE_FDC, "fdc write 8604 dma sector count=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n",
                   1969:                  IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
1.1.1.9   root     1970: 
1.1.1.15  root     1971:        FDC_DMA.SectorCount = IoMem_ReadByte(0xff8605);
1.1       root     1972: }
                   1973: 
1.1.1.2   root     1974: 
                   1975: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1976: /**
1.1.1.15  root     1977:  * Write to Command register $ff8604
1.1.1.9   root     1978:  */
1.1.1.15  root     1979: static void FDC_WriteCommandRegister ( void )
1.1       root     1980: {
1.1.1.12  root     1981:        int FrameCycles, HblCounterVideo, LineCycles;
                   1982: 
                   1983:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1984: 
                   1985:        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     1986:                  IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                   1987: 
                   1988:        /* If fdc is busy, only 'Force Interrupt' is possible */
                   1989:        /* [NP] : it's also possible to start a new command just after another command */
                   1990:        /* was started and spinup phase was not completed yet (or is this only possible during the 'prepare' delay ?) */
                   1991:        /* FIXME : this delay was not measured, it should be at least 880 cycles for Overdrive Demos by Phalanx */
                   1992:        /* For now, we allow to cancel the current command if we're in the prepare+spinup delay */
                   1993:        if ( FDC.STR & FDC_STR_BIT_BUSY )
                   1994:        {
                   1995:                if ( ( IoMem_ReadByte(0xff8605) & 0xf0 ) == 0xd0 )              /* 'Force Interrupt' command */
                   1996:                {
                   1997:                        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",
                   1998:                                FDC.CR , IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                   1999:                }
                   2000: 
                   2001:                else if ( FDC.ReplaceCommandPossible )
                   2002:                {
                   2003:                        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",
                   2004:                                FDC.CR , IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                   2005:                }
                   2006: 
                   2007:                else                                                            /* Other cases : new command is ignored */
                   2008:                {
                   2009:                        LOG_TRACE(TRACE_FDC, "fdc write 8604 fdc busy, command=0x%x ignored VBL=%d video_cyc=%d %d@%d pc=%x\n",
                   2010:                                IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                   2011:                        return;
                   2012:                }
                   2013:        }
1.1.1.9   root     2014: 
1.1.1.16! root     2015: 
        !          2016:        if ( ( ( IoMem_ReadByte(0xff8605) & 0xf0 ) != 0xd0 )                    /* Type I, II and III commands */
        !          2017:          && ( !FDC_ValidFloppyDrive() ) )
        !          2018:        {
        !          2019:                LOG_TRACE(TRACE_FDC, "fdc write 8604 no drive selected, command=0x%x ignored VBL=%d video_cyc=%d %d@%d pc=%x\n",
        !          2020:                        IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
        !          2021:                return;
        !          2022:        }
        !          2023: 
1.1.1.15  root     2024:        FDC.CR = IoMem_ReadByte(0xff8605);
1.1.1.6   root     2025:        FDC_ExecuteCommand();
1.1       root     2026: }
                   2027: 
1.1.1.2   root     2028: 
                   2029: /*-----------------------------------------------------------------------*/
1.1.1.9   root     2030: /**
1.1.1.15  root     2031:  * Write to Track register $ff8604
1.1.1.9   root     2032:  */
1.1.1.15  root     2033: static void FDC_WriteTrackRegister ( void )
1.1       root     2034: {
1.1.1.12  root     2035:        int FrameCycles, HblCounterVideo, LineCycles;
                   2036: 
                   2037:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2038: 
                   2039:        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     2040:                IoMem_ReadByte(0xff8605) , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1.1.9   root     2041: 
1.1.1.15  root     2042:        /* [NP] Contrary to what is written in the WD1772 doc, Track Register can be changed */
                   2043:        /* while the fdc is busy */
                   2044:        if ( FDC.STR & FDC_STR_BIT_BUSY )
                   2045:        {
                   2046:                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",
                   2047:                        IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                   2048:        }
                   2049: 
                   2050:        FDC.TR = IoMem_ReadByte(0xff8605);
1.1       root     2051: }
                   2052: 
1.1.1.2   root     2053: 
                   2054: /*-----------------------------------------------------------------------*/
1.1.1.9   root     2055: /**
1.1.1.15  root     2056:  * Write to Sector register $ff8604
1.1.1.9   root     2057:  */
1.1.1.15  root     2058: static void FDC_WriteSectorRegister ( void )
1.1       root     2059: {
1.1.1.12  root     2060:        int FrameCycles, HblCounterVideo, LineCycles;
                   2061: 
                   2062:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2063: 
                   2064:        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     2065:                IoMem_ReadByte(0xff8605) , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
                   2066: 
                   2067:        /* [NP] Contrary to what is written in the WD1772 doc, Sector Register can be changed */
                   2068:        /* while the fdc is busy (but it will have no effect once the sector's header is found) */
                   2069:        /* (fix Delirious Demo IV's loader, which is bugged and set SR after starting the Read Sector command) */
                   2070:        if ( FDC.STR & FDC_STR_BIT_BUSY )
                   2071:        {
                   2072:                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",
                   2073:                        IoMem_ReadByte(0xff8605), nVBLs, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC());
                   2074:        }
1.1.1.9   root     2075: 
1.1.1.15  root     2076:        FDC.SR = IoMem_ReadByte(0xff8605);
1.1       root     2077: }
                   2078: 
1.1.1.2   root     2079: 
                   2080: /*-----------------------------------------------------------------------*/
1.1.1.9   root     2081: /**
1.1.1.15  root     2082:  * Write to Data register $ff8604
1.1.1.9   root     2083:  */
1.1.1.15  root     2084: static void FDC_WriteDataRegister ( void )
1.1       root     2085: {
1.1.1.12  root     2086:        int FrameCycles, HblCounterVideo, LineCycles;
                   2087: 
                   2088:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2089: 
                   2090:        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     2091:                IoMem_ReadByte(0xff8605), nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1.1.9   root     2092: 
1.1.1.15  root     2093:        FDC.DR = IoMem_ReadByte(0xff8605);
1.1       root     2094: }
                   2095: 
1.1.1.2   root     2096: 
                   2097: /*-----------------------------------------------------------------------*/
1.1.1.9   root     2098: /**
1.1.1.15  root     2099:  * Store byte in FDC registers or DMA sector count, when writing to $ff8604
1.1.1.9   root     2100:  */
1.1.1.15  root     2101: void FDC_DiskController_WriteWord ( void )
1.1       root     2102: {
1.1.1.12  root     2103:        int FrameCycles, HblCounterVideo, LineCycles;
                   2104: 
1.1.1.15  root     2105:        if ( nIoMemAccessSize == SIZE_BYTE )
1.1.1.6   root     2106:        {
                   2107:                /* This register does not like to be accessed in byte mode on a normal ST */
1.1.1.8   root     2108:                M68000_BusError(IoAccessBaseAddress, BUS_ERROR_WRITE);
1.1.1.6   root     2109:                return;
                   2110:        }
                   2111: 
1.1.1.8   root     2112:        M68000_WaitState(4);
                   2113: 
1.1.1.12  root     2114:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1.1.1.9   root     2115: 
1.1.1.12  root     2116:        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     2117:                IoMem_ReadWord(0xff8604), nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1.1.6   root     2118: 
1.1.1.12  root     2119:        /* Is it an ASCII HD command? */
1.1.1.15  root     2120:        if ( ( FDC_DMA.Mode & 0x0018 ) == 8 )
1.1.1.12  root     2121:        {
                   2122:                /*  Handle HDC functions */
                   2123:                HDC_WriteCommandPacket();
1.1.1.10  root     2124:                return;
1.1.1.12  root     2125:        }
1.1.1.6   root     2126: 
1.1.1.15  root     2127:        /* Are we trying to set the SectorCount ? */
                   2128:        if ( FDC_DMA.Mode & 0x10 )                                      /* Bit 4 */
1.1.1.6   root     2129:                FDC_WriteSectorCountRegister();
                   2130:        else
1.1.1.8   root     2131:        {
                   2132:                /* Write to FDC registers */
1.1.1.15  root     2133:                switch ( FDC_DMA.Mode & 0x6 )
1.1.1.6   root     2134:                {   /* Bits 1,2 (A1,A0) */
1.1.1.15  root     2135:                 case 0x0:                                              /* 0 0 - Command register */
1.1.1.6   root     2136:                        FDC_WriteCommandRegister();
                   2137:                        break;
1.1.1.15  root     2138:                 case 0x2:                                              /* 0 1 - Track register */
1.1.1.6   root     2139:                        FDC_WriteTrackRegister();
                   2140:                        break;
1.1.1.15  root     2141:                 case 0x4:                                              /* 1 0 - Sector register */
1.1.1.6   root     2142:                        FDC_WriteSectorRegister();
                   2143:                        break;
1.1.1.15  root     2144:                 case 0x6:                                              /* 1 1 - Data register */
1.1.1.6   root     2145:                        FDC_WriteDataRegister();
                   2146:                        break;
                   2147:                }
                   2148:        }
1.1       root     2149: }
                   2150: 
1.1.1.2   root     2151: 
                   2152: /*-----------------------------------------------------------------------*/
1.1.1.9   root     2153: /**
1.1.1.15  root     2154:  * Return Status/FDC register when reading from $ff8604
1.1.1.9   root     2155:  */
1.1.1.15  root     2156: void FDC_DiskControllerStatus_ReadWord ( void )
1.1       root     2157: {
1.1.1.15  root     2158:        Uint16 DiskControllerByte = 0;                                  /* Used to pass back the parameter */
1.1.1.12  root     2159:        int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.15  root     2160:        int ForceWPRT;
1.1.1.6   root     2161: 
                   2162:        if (nIoMemAccessSize == SIZE_BYTE)
                   2163:        {
                   2164:                /* This register does not like to be accessed in byte mode on a normal ST */
1.1.1.8   root     2165:                M68000_BusError(IoAccessBaseAddress, BUS_ERROR_READ);
1.1.1.6   root     2166:                return;
                   2167:        }
                   2168: 
1.1.1.8   root     2169:        M68000_WaitState(4);
                   2170: 
1.1.1.15  root     2171:        if ((FDC_DMA.Mode & 0x18) == 0x08)                              /* HDC status reg selected? */
1.1.1.6   root     2172:        {
                   2173:                /* return the HDC status reg */
1.1.1.15  root     2174:                DiskControllerByte = HDC_GetCommandStatus();
1.1.1.6   root     2175:        }
1.1.1.15  root     2176:        else if ((FDC_DMA.Mode & 0x18) == 0x18)                         /* HDC sector counter??? */
1.1.1.8   root     2177:        {
                   2178:                Log_Printf(LOG_DEBUG, "*** Read HDC sector counter???\n");
1.1.1.15  root     2179:                DiskControllerByte = HDC_GetSectorCount();
1.1.1.8   root     2180:        }
1.1.1.6   root     2181:        else
                   2182:        {
1.1.1.15  root     2183:                /* FDC code */
                   2184:                switch (FDC_DMA.Mode & 0x6)                             /* Bits 1,2 (A1,A0) */
1.1.1.6   root     2185:                {
1.1.1.15  root     2186:                 case 0x0:                                              /* 0 0 - Status register */
                   2187:                        /* [NP] Contrary to what is written in the WD1772 doc, the WPRT bit */
                   2188:                        /* is updated after a Type I command */
                   2189:                        /* (eg : Procopy or Terminators Copy 1.68 do a Restore/Seek to test WPRT) */
                   2190:                        if ( FDC.CommandType == 1 )
1.1.1.6   root     2191:                        {
1.1.1.15  root     2192:                                if ( Floppy_IsWriteProtected ( FDC_DRIVE ) )
                   2193:                                        FDC_Update_STR ( 0 , FDC_STR_BIT_WPRT );        /* Set WPRT bit */
                   2194:                                else
                   2195:                                        FDC_Update_STR ( FDC_STR_BIT_WPRT , 0 );        /* Unset WPRT bit */
1.1.1.6   root     2196:                        }
                   2197: 
1.1.1.15  root     2198:                        /* When there's no disk in drive, the floppy drive hardware can't see */
                   2199:                        /* the difference with an inserted disk that would be write protected */
                   2200:                        if ( ! EmulationDrives[ FDC_DRIVE ].bDiskInserted )
                   2201:                                FDC_Update_STR ( 0 , FDC_STR_BIT_WPRT );                /* Set WPRT bit */
                   2202: 
                   2203:                        DiskControllerByte = FDC.STR;
                   2204: 
                   2205:                        /* Temporarily change the WPRT bit if we're in a transition phase */
                   2206:                        /* regarding the disk in the drive (inserting or ejecting) */
                   2207:                        ForceWPRT = Floppy_DriveTransitionUpdateState ( FDC_DRIVE );
                   2208:                        if ( ForceWPRT == 1 )
                   2209:                                DiskControllerByte |= FDC_STR_BIT_WPRT;         /* Force setting WPRT */
                   2210:                        if ( ForceWPRT == -1 )
                   2211:                                DiskControllerByte &= ~FDC_STR_BIT_WPRT;        /* Force clearing WPRT */
                   2212: 
                   2213:                        if ( ForceWPRT != 0 )
                   2214:                                LOG_TRACE(TRACE_FDC, "force wprt=%d VBL=%d drive=%d str=%x\n", ForceWPRT==1?1:0, nVBLs, FDC_DRIVE, DiskControllerByte );
                   2215: 
                   2216:                        /* When Status Register is read, FDC's INTRQ is reset */
1.1.1.6   root     2217:                        MFP_GPIP |= 0x20;
                   2218:                        break;
1.1.1.15  root     2219:                 case 0x2:                                              /* 0 1 - Track register */
                   2220:                        DiskControllerByte = FDC.TR;
1.1.1.6   root     2221:                        break;
1.1.1.15  root     2222:                 case 0x4:                                              /* 1 0 - Sector register */
                   2223:                        DiskControllerByte = FDC.SR;
1.1.1.6   root     2224:                        break;
1.1.1.15  root     2225:                 case 0x6:                                              /* 1 1 - Data register */
                   2226:                        DiskControllerByte = FDC.DR;
1.1.1.6   root     2227:                        break;
                   2228:                }
                   2229:        }
                   2230: 
1.1.1.7   root     2231:        IoMem_WriteWord(0xff8604, DiskControllerByte);
1.1.1.9   root     2232: 
1.1.1.12  root     2233:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2234: 
                   2235:        LOG_TRACE(TRACE_FDC, "fdc read 8604 ctrl status=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
                   2236:                DiskControllerByte , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1       root     2237: }
                   2238: 
1.1.1.2   root     2239: 
                   2240: /*-----------------------------------------------------------------------*/
1.1.1.9   root     2241: /**
1.1.1.15  root     2242:  * Write word to $ff8606 (DMA Mode Control)
                   2243:  *
                   2244:  * Eg.
                   2245:  * $80 - Selects command/status register
                   2246:  * $82 - Selects track register
                   2247:  * $84 - Selects sector register
                   2248:  * $86 - Selects data regsiter
                   2249:  * NOTE - OR above values with $100 is transfer from memory to floppy
                   2250:  * Also if bit 4 is set, write to DMA sector count register
                   2251:  */
                   2252: void FDC_DmaModeControl_WriteWord ( void )
                   2253: {
                   2254:        Uint16 Mode_prev;                                               /* Store previous write to 0xff8606 for 'toggle' checks */
                   2255:        int FrameCycles, HblCounterVideo, LineCycles;
                   2256: 
                   2257: 
                   2258:        if (nIoMemAccessSize == SIZE_BYTE)
                   2259:        {
                   2260:                /* This register does not like to be accessed in byte mode on a normal ST */
                   2261:                M68000_BusError(IoAccessBaseAddress, BUS_ERROR_WRITE);
                   2262:                return;
                   2263:        }
                   2264: 
                   2265:        Mode_prev = FDC_DMA.Mode;                                       /* Store previous to check for _read/_write toggle (DMA reset) */
                   2266:        FDC_DMA.Mode = IoMem_ReadWord(0xff8606);                        /* Store to DMA Mode control */
                   2267: 
                   2268:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2269: 
                   2270:        LOG_TRACE(TRACE_FDC, "fdc write 8606 ctrl=0x%x VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
                   2271:                FDC_DMA.Mode , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
                   2272: 
                   2273:        /* When write to 0xff8606, check bit '8' toggle. This causes DMA status reset */
                   2274:        if ((Mode_prev ^ FDC_DMA.Mode) & 0x0100)
                   2275:                FDC_ResetDMA();
                   2276: }
                   2277: 
                   2278: 
                   2279: /*-----------------------------------------------------------------------*/
                   2280: /**
                   2281:  * Read DMA Status at $ff8606
                   2282:  *
                   2283:  * Bit 0 - Error Status (0=Error)
                   2284:  * Bit 1 - Sector Count Zero Status (0=Sector Count Zero)
                   2285:  * Bit 2 - Data Request Inactive Status
                   2286:  */
                   2287: void FDC_DmaStatus_ReadWord ( void )
                   2288: {
                   2289:        if (nIoMemAccessSize == SIZE_BYTE)
                   2290:        {
                   2291:                /* This register does not like to be accessed in byte mode on a normal ST */
                   2292:                M68000_BusError(IoAccessBaseAddress, BUS_ERROR_READ);
                   2293:                return;
                   2294:        }
                   2295: 
                   2296:        /* Set zero sector count */
                   2297:        FDC_DMA.Status &= ~0x2;                                         /* Clear bit 1 */
                   2298:        if ( FDC_DMA.Mode & 0x08 )                                      /* Get which sector count ? */
                   2299:                FDC_DMA.Status |= (HDC_GetSectorCount())?0x2:0;         /* HDC */
                   2300:        else
                   2301:                FDC_DMA.Status |= (FDC_DMA.SectorCount)?0x2:0;          /* FDC */
                   2302: 
                   2303:        /* In the case of the ST, DRQ is always 0 because it's handled by the DMA and its 16 bytes buffer */
                   2304: 
                   2305:        IoMem_WriteWord(0xff8606, FDC_DMA.Status);
                   2306: }
                   2307: 
                   2308: 
                   2309: /*-----------------------------------------------------------------------*/
                   2310: /**
                   2311:  * Read hi/med/low DMA address byte at $ff8609/0b/0d
                   2312:  */
                   2313: void   FDC_DmaAddress_ReadByte ( void )
                   2314: {
                   2315:        int FrameCycles, HblCounterVideo, LineCycles;
                   2316: 
                   2317:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2318: 
                   2319:        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" ,
                   2320:                IoAccessCurrentAddress , IoMem[ IoAccessCurrentAddress ] , FDC_GetDMAAddress() ,
                   2321:                nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
                   2322: }
                   2323: 
                   2324: 
                   2325: /*-----------------------------------------------------------------------*/
                   2326: /**
                   2327:  * Write hi/med/low DMA address byte at $ff8609/0b/0d
                   2328:  */
                   2329: void   FDC_DmaAddress_WriteByte ( void )
                   2330: {
                   2331:        int FrameCycles, HblCounterVideo, LineCycles;
                   2332: 
                   2333:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2334: 
                   2335:        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" ,
                   2336:                IoAccessCurrentAddress , IoMem[ IoAccessCurrentAddress ] , FDC_GetDMAAddress() ,
                   2337:                nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
                   2338: }
                   2339: 
                   2340: 
                   2341: /*-----------------------------------------------------------------------*/
                   2342: /**
                   2343:  * Get DMA address used to transfer data between FDC and RAM
1.1.1.9   root     2344:  */
1.1.1.15  root     2345: Uint32 FDC_GetDMAAddress(void)
1.1       root     2346: {
1.1.1.6   root     2347:        Uint32 Address;
1.1       root     2348: 
1.1.1.6   root     2349:        /* Build up 24-bit address from hardware registers */
                   2350:        Address = ((Uint32)STMemory_ReadByte(0xff8609)<<16) | ((Uint32)STMemory_ReadByte(0xff860b)<<8) | (Uint32)STMemory_ReadByte(0xff860d);
1.1       root     2351: 
1.1.1.6   root     2352:        return Address;
1.1       root     2353: }
                   2354: 
1.1.1.2   root     2355: 
                   2356: /*-----------------------------------------------------------------------*/
1.1.1.9   root     2357: /**
1.1.1.15  root     2358:  * Write a new address to the FDC DMA address registers at $ff8909/0b/0d
1.1.1.9   root     2359:  */
1.1.1.15  root     2360: void FDC_WriteDMAAddress ( Uint32 Address )
1.1       root     2361: {
1.1.1.12  root     2362:        int FrameCycles, HblCounterVideo, LineCycles;
                   2363: 
                   2364:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2365: 
                   2366:        LOG_TRACE(TRACE_FDC, "fdc write 0x%x to dma address VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
                   2367:                Address , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1.1.9   root     2368: 
1.1.1.6   root     2369:        /* Store as 24-bit address */
                   2370:        STMemory_WriteByte(0xff8609, Address>>16);
                   2371:        STMemory_WriteByte(0xff860b, Address>>8);
                   2372:        STMemory_WriteByte(0xff860d, Address);
1.1       root     2373: }
                   2374: 
1.1.1.2   root     2375: 
                   2376: /*-----------------------------------------------------------------------*/
1.1.1.9   root     2377: /**
                   2378:  * Read sector from floppy drive into workspace
                   2379:  * We copy the bytes in chunks to simulate reading of the floppy using DMA
                   2380:  */
1.1.1.15  root     2381: static bool FDC_ReadSectorFromFloppy ( Uint8 *buf , Uint8 Sector , int *pSectorSize )
1.1       root     2382: {
1.1.1.12  root     2383:        int FrameCycles, HblCounterVideo, LineCycles;
                   2384: 
                   2385:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2386: 
                   2387:        LOG_TRACE(TRACE_FDC, "fdc read sector addr=0x%x dev=%d sect=%d track=%d side=%d VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
1.1.1.15  root     2388:                FDC_GetDMAAddress(), FDC_DRIVE, Sector, HeadTrack[ FDC_DRIVE ], FDC_SIDE,
1.1.1.12  root     2389:                nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1.1.9   root     2390: 
1.1.1.15  root     2391:        /* Copy 1 sector to our workspace */
                   2392:        if ( Floppy_ReadSectors ( FDC_DRIVE, buf, Sector, HeadTrack[ FDC_DRIVE ], FDC_SIDE, 1, NULL, pSectorSize ) )
1.1.1.12  root     2393:                return true;
1.1       root     2394: 
1.1.1.6   root     2395:        /* Failed */
1.1.1.12  root     2396:        LOG_TRACE(TRACE_FDC, "fdc read sector failed\n" );
                   2397:        return false;
1.1       root     2398: }
                   2399: 
1.1.1.2   root     2400: 
                   2401: /*-----------------------------------------------------------------------*/
1.1.1.9   root     2402: /**
1.1.1.15  root     2403:  * Write sector from RAM to floppy drive
1.1.1.9   root     2404:  * We copy the bytes in chunks to simulate writing of the floppy using DMA
1.1.1.15  root     2405:  * If DMASectorsCount==0, the DMA won't transfer any byte from RAM to the FDC
                   2406:  * and some '0' bytes will be written to the disk.
1.1.1.9   root     2407:  */
1.1.1.15  root     2408: static bool FDC_WriteSectorToFloppy ( int DMASectorsCount , Uint8 Sector , int *pSectorSize )
1.1       root     2409: {
1.1.1.15  root     2410:        Uint8 *pBuffer;
1.1.1.12  root     2411:        int FrameCycles, HblCounterVideo, LineCycles;
                   2412: 
                   2413:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   2414: 
                   2415:        LOG_TRACE(TRACE_FDC, "fdc write sector addr=0x%x dev=%d sect=%d track=%d side=%d VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
1.1.1.15  root     2416:                FDC_GetDMAAddress(), FDC_DRIVE, Sector, HeadTrack[ FDC_DRIVE ], FDC_SIDE,
1.1.1.12  root     2417:                nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1.1.1.9   root     2418: 
1.1.1.15  root     2419:        if ( DMASectorsCount > 0 )
                   2420:                pBuffer = &STRam[ FDC_GetDMAAddress() ];
                   2421:        else
1.1.1.6   root     2422:        {
1.1.1.15  root     2423:                pBuffer = DMADiskWorkSpace;                             /* If DMA can't transfer data, we write '0' bytes */
                   2424:                memset ( pBuffer , 0 , DMA_DISK_SECTOR_SIZE );
1.1.1.6   root     2425:        }
1.1.1.15  root     2426:        
                   2427:        /* Write 1 sector from our workspace */
                   2428:        if ( Floppy_WriteSectors ( FDC_DRIVE, pBuffer, Sector, HeadTrack[ FDC_DRIVE ], FDC_SIDE, 1, NULL, pSectorSize ) )
                   2429:                return true;
1.1       root     2430: 
1.1.1.6   root     2431:        /* Failed */
1.1.1.12  root     2432:        LOG_TRACE(TRACE_FDC, "fdc write sector failed\n" );
                   2433:        return false;
1.1       root     2434: }
                   2435: 
                   2436: 
1.1.1.2   root     2437: /*-----------------------------------------------------------------------*/
1.1.1.9   root     2438: /**
                   2439:  * Write to floppy mode/control (?) register (0xff860F).
                   2440:  * Used on Falcon only!
                   2441:  * FIXME: I've found hardly any documentation about this register, only
                   2442:  * the following description of the bits:
                   2443:  *
                   2444:  *   __________54__10  Floppy Controll-Register
                   2445:  *             ||  ||
                   2446:  *             ||  |+- Prescaler 1
                   2447:  *             ||  +-- Media detect 1
                   2448:  *             |+----- Prescaler 2
                   2449:  *             +------ Media detect 2
                   2450:  *
                   2451:  * For DD - disks:  0x00
                   2452:  * For HD - disks:  0x03
                   2453:  * for ED - disks:  0x30 (not supported by TOS)
                   2454:  */
1.1.1.15  root     2455: void FDC_FloppyMode_WriteByte ( void )
1.1.1.9   root     2456: {
                   2457:        // printf("Write to floppy mode reg.: 0x%02x\n", IoMem_ReadByte(0xff860f));
                   2458: }
                   2459: 
                   2460: 
                   2461: /*-----------------------------------------------------------------------*/
                   2462: /**
                   2463:  * Read from floppy mode/control (?) register (0xff860F).
                   2464:  * Used on Falcon only!
                   2465:  * FIXME: I've found hardly any documentation about this register, only
                   2466:  * the following description of the bits:
                   2467:  *
                   2468:  *   ________76543210  Floppy Controll-Register
                   2469:  *           ||||||||
                   2470:  *           |||||||+- Prescaler 1
                   2471:  *           ||||||+-- Mode select 1
                   2472:  *           |||||+--- Media detect 1
                   2473:  *           ||||+---- accessed during DMA transfers (?)
                   2474:  *           |||+----- Prescaler 2
                   2475:  *           ||+------ Mode select 2
                   2476:  *           |+------- Media detect 2
                   2477:  *           +-------- Disk changed
                   2478:  */
1.1.1.15  root     2479: void FDC_FloppyMode_ReadByte ( void )
1.1.1.9   root     2480: {
                   2481:        IoMem_WriteByte(0xff860f, 0x80);  // FIXME: Is this ok?
                   2482:        // printf("Read from floppy mode reg.: 0x%02x\n", IoMem_ReadByte(0xff860f));
                   2483: }

unix.superglobalmegacorp.com

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