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

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

unix.superglobalmegacorp.com

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