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

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.7   root        7:   Floppy Disk Controller(FDC) emulation. We need to simulate the movement of
                      8:   the head of the floppy disk drive to accurately perform the FDC commands,
                      9:   such as 'Step'. The is important for ST demo disk images. We have to go
1.1.1.6   root       10:   into a lot of details - including the start up/stop of the drive motor.
                     11:   To help with this emulation, we keep our own internal commands which are
1.1.1.7   root       12:   checked each HBL to perform the transfer of data from our disk image into
1.1.1.6   root       13:   the ST RAM area by simulating the DMA.
1.1       root       14: */
1.1.1.9   root       15: 
                     16: /* 2007/11/06   [NP]    Add calls to HATARI_TRACE and set FDC_DELAY_HBL=180            */
1.1.1.10  root       17: /* 2008/05/03  [NP]    Add more traces to all commandes.                               */
                     18: /*                     FIXME : after a type II read sector with multi bit 'm' on, we   */
                     19: /*                     should update FDCSectorRegister to be 'max sector for current   */
                     20: /*                     track'+1 and set command status to 'Record Not Found'.          */
                     21: /*                     Also,  if multi bit is set and sector count is less than number */
                     22: /*                     of sectors in the track, then the FDC reads the whole track     */
                     23: /*                     anyway, setting RNF at the end, but the DMA stops transferring  */
                     24: /*                     data once DMA sector count $ff8604 reaches 0.                   */
                     25: /*                     Timings for read sector with multi bit are not good and prevent */
                     26: /*                     some programs from working (eg Super Monaco GP on Superior 65)  */
                     27: /*                     because intrq bit 5 in $fffa01 seems to be cleared too late,    */
                     28: /*                     the command takes more time than a real ST to complete.         */
                     29: /* 2008/10/02  [NP]    FDCTrackRegister, FDCSectorRegister and FDCDataRegister are     */
                     30: /*                     stored on 8 bits in the WD 1772. When writing to $ff8604 to     */
                     31: /*                     access these registers, we must keep only the lower 8 bits.     */
1.1.1.11! root       32: /*                     (fix High Fidelity Dreams by Aura, writes $fb07 in sector reg). */
1.1.1.10  root       33: /*                     TODO : FDCxxxxRegister should use Uint8, not Sint16/Uint16.     */
1.1.1.11! root       34: /* 2008/12/15  [NP]    Although the Read Address command is not supported yet, add a   */
        !            35: /*                     function FDC_UpdateReadAddressCmd that does nothing, but        */
        !            36: /*                     completes with no DMA error and clear bit 6 of $fffa01 (fixes   */
        !            37: /*                     loader routine used in various Pompey Pirates compilations (23, */
        !            38: /*                     27, ...) that uses the read address command only to update the  */
        !            39: /*                     status register and get the state of the write protection).     */
1.1.1.9   root       40: 
1.1.1.10  root       41: 
1.1.1.11! root       42: const char FDC_fileid[] = "Hatari fdc.c : " __DATE__ " " __TIME__;
1.1       root       43: 
                     44: #include "main.h"
1.1.1.4   root       45: #include "configuration.h"
1.1       root       46: #include "fdc.h"
1.1.1.3   root       47: #include "hdc.h"
1.1       root       48: #include "floppy.h"
                     49: #include "ikbd.h"
1.1.1.6   root       50: #include "ioMem.h"
                     51: #include "log.h"
1.1       root       52: #include "m68000.h"
                     53: #include "memorySnapShot.h"
                     54: #include "mfp.h"
                     55: #include "psg.h"
                     56: #include "stMemory.h"
1.1.1.10  root       57: #include "video.h"
1.1       root       58: 
1.1.1.3   root       59: 
1.1       root       60: /*
1.1.1.7   root       61:   Floppy Disk Controller
1.1       root       62: 
                     63: Programmable Sound Generator (YM-2149)
                     64: 
                     65:   0xff8800(even byte)  - PSG Register Data (Read, used for parallel port)
                     66:             - PSG Register Select (Write)
                     67: 
                     68:   Write to bits 0-3 to select PSG register to use(then write data to 0xfff8802)
                     69:     Value    Register
                     70: 
                     71:     0000    Channel A Fine Tune
                     72:     0001    Channel A Coarse Tune
                     73:     0010    Channel B Fine Tune
                     74:     0011    Channel B Coarse Tune
                     75:     0100    Channel C Fine Tune
                     76:     0101    Channel C Coarse Tune
                     77:     0110    Noise Generator Control
                     78:     0111    Mixer Control - I/O enable
                     79:     1000    Channel A Amplitude
                     80:     1001    Channel B Amplitude
                     81:     1010    Channel C Amplitude
                     82:     1011    Envelope Period Fine Tune
                     83:     1100    Envelope Peroid Coarse Tune
                     84:     1101    Envelope Shape
                     85:     1110    I/O Port A Select (Write only)
                     86:     1111    I/O Port B Select
                     87: 
                     88:   0xfff8802(even byte)  - Bits according to 0xff8800 Register select
1.1.1.4   root       89: 
1.1       root       90:   1110(Register 14) - I/O Port A
                     91:     Bit 0 - Floppy side 0/1
                     92:     Bit 1 - Floppy drive 0 select
                     93:     Bit 2 - Floppy drive 1 select
                     94:     Bit 3 - RS232 Ready to send (RTS)
                     95:     Bit 4 - RS232 Data Terminal Ready (DTR)
                     96:     Bit 5 - Centronics Strobe
                     97:     Bit 6 - General Purpose Output
                     98:     Bit 7 - Reserved
                     99: 
1.1.1.7   root      100: ACSI DMA and Floppy Disk Controller(FDC)
1.1       root      101:   0xff8604 - information from file '1772.info.txt, by David Gahris' (register r0)
                    102:   (write) - Disk controller
                    103:   (read) - Disk controller status
                    104:     Bit 0 - Busy.  This bit is 1 when the 177x is busy.  This bit is 0 when the 177x is free for CPU commands.
                    105:     Bit 1 - Index / Data Request.  On Type I commands, this bit is high during the index pulse that occurs once
                    106:       per disk rotation.  This bit is low at all times other than the index pulse.  For Type II and III commands,
                    107:       Bit 1 high signals the CPU to handle the data register in order to maintain a continuous flow of data.
                    108:       Bit 1 is high when the data register is full during a read or when the data register is empty during a write.
                    109:       "Worst case service time" for Data Request is 23.5 cycles.
                    110:     Bit 2 - Track Zero / Lost Data.  After Type I commands, this bit is 0 if the mechanism is at track zero.
                    111:       This bit is 1 if the head is not at track zero.  After Type II or III commands, this bit is 1 if the
                    112:       CPU did not respond to Data Request (Status bit 1) in time for the 177x to maintain a continuous data flow.
                    113:       This bit is 0 if the CPU responded promptly to Data Request.
                    114:     Bit 3 - CRC Error.  This bit is high if a sector CRC on disk does not match the CRC which the 177x
                    115:       computed from the data.  The CRC polynomial is x^16+x^12+x^5+1.  If the stored CRC matches the newly
                    116:       calculated CRC, the CRC Error bit is low.  If this bit and the Record Not Found bit are set, the error
                    117:       was in an ID field.  If this bit is set but Record Not Found is clear, the error was in a data field.
                    118:     Bit 4 - Record Not Found.  This bit is set if the 177x cannot find the track, sector, or side which
                    119:       the CPU requested.  Otherwise, this bit is clear.
                    120:     Bit 5 - Spin-up / Record Type.  For Type I commands, this bit is low during the 6-revolution motor
                    121:       spin-up time.  This bit is high after spin-up.  For Type II and Type III commands, Bit 5 low
                    122:       indicates a normal data mark.  Bit 5 high indicates a deleted data mark.
                    123:     Bit 6 - Write Protect.  This bit is not used during reads.  During writes, this bit is high when the disk is write protected.
                    124:     Bit 7 - Motor On.  This bit is high when the drive motor is on, and low when the motor is off.
                    125: 
                    126:   0xff8606 - DMA Status(read), DMA Mode Control(write) - NOTE bits 0,9-15 are not used
                    127:     Bit 1 - FDC Pin A0 (See below)
                    128:     Bit 2 - FDC Pin A1
                    129:     Bit 3 - FDC/HDC Register Select
                    130:     Bit 4 - FDC/Sector count select
                    131:     Bit 5 - Reserved
                    132:     Bit 6 - Enable/Disable DMA
                    133:     Bit 7 - HDC/FDC
                    134:     Bit 8 - Read/Write
                    135: 
                    136:     A1  A0    Read        Write(bit 8==1)
                    137:     0  0    Status        Command
                    138:     0  1    Track Register    Track Register
                    139:     1  0    Sector Register    Sector Register
                    140:     1  1    Data Register    Data Register
                    141: 
                    142: 
1.1.1.6   root      143:   This handles any read/writes to the FDC and PSG. FDC commands are then sent
1.1.1.7   root      144:   through to read/write disk sector code. We have full documents on 1772 FDC,
1.1.1.6   root      145:   but they use r0,r1,r2,r3 etc.. which are not seen at first glance as Atari
                    146:   access them via the A0,A1 bits. Once this is understood it is all relativly
1.1.1.7   root      147:   easy as a lot of information can be ignored as we are using disk images and
                    148:   not actual disks. We do NOT support the reading of the PC's A: drive - newer
                    149:   PC's cannot read an ST single sided disk, ST disks are very old and so are
1.1.1.6   root      150:   dirty which gets onto the PC drive heads and ruins them and also support for
1.1.1.7   root      151:   disk sector access under the various modern operating systems is not so easy
1.1.1.6   root      152:   (if possible at all).
                    153: 
                    154:   According to the documentation INTRQ is generated at the completion of each
                    155:   command (causes an interrupt in the MFP). INTRQ is reset by reading the status
                    156:   register OR by loading a new command. So, does this mean the GPIP? Or does it
                    157:   actually CANCEL the interrupt? Can this be done?
1.1       root      158: */
                    159: 
                    160: 
1.1.1.7   root      161: Sint16 FDCSectorCountRegister;
1.1       root      162: 
1.1.1.7   root      163: Uint16 DiskControllerWord_ff8604wr;                             /* 0xff8604 (write) */
                    164: static Uint16 DiskControllerStatus_ff8604rd;                    /* 0xff8604 (read) */
1.1.1.5   root      165: 
1.1.1.6   root      166: Uint16 DMAModeControl_ff8606wr;                                 /* 0xff8606 (write) */
                    167: static Uint16 DMAStatus_ff8606rd;                               /* 0xff8606 (read) */
1.1.1.5   root      168: 
1.1.1.7   root      169: static Uint16 FDCCommandRegister;
                    170: static Sint16 FDCTrackRegister, FDCSectorRegister, FDCDataRegister;
1.1.1.5   root      171: static int FDCEmulationCommand;                                 /* FDC emulation command currently being exceuted */
                    172: static int FDCEmulationRunning;                                 /* Running command under above */
                    173: static int FDCStepDirection;                                    /* +Track on 'Step' command */
1.1.1.10  root      174: static bool bDMAWaiting;                                        /* Is DMA waiting to copy? */
1.1.1.5   root      175: static int bMotorOn;                                            /* Is motor on? */
                    176: static int MotorSlowingCount;                                   /* Counter used to slow motor before stopping */
                    177: 
                    178: static short int nReadWriteTrack;                               /* Parameters used in sector read/writes */
                    179: static short int nReadWriteSector;
                    180: static short int nReadWriteSide;
                    181: static short int nReadWriteDev;
                    182: static unsigned short int nReadWriteSectorsPerTrack;
                    183: static short int nReadWriteSectors;
                    184: 
1.1.1.7   root      185: static Uint8 DMASectorWorkSpace[NUMBYTESPERSECTOR];             /* Workspace used to copy to/from for floppy DMA */
1.1       root      186: 
1.1.1.2   root      187: 
                    188: /*-----------------------------------------------------------------------*/
1.1.1.9   root      189: /**
                    190:  * Reset variables used in FDC
                    191:  */
1.1       root      192: void FDC_Reset(void)
                    193: {
1.1.1.6   root      194:        /* Clear out FDC registers */
1.1.1.7   root      195:        DiskControllerStatus_ff8604rd = 0;
                    196:        DiskControllerWord_ff8604wr = 0;
1.1.1.6   root      197:        DMAStatus_ff8606rd = 0x01;
                    198:        DMAModeControl_ff8606wr = 0;
                    199:        FDC_ResetDMAStatus();
                    200:        FDCCommandRegister = 0;
                    201:        FDCTrackRegister = 0;
                    202:        FDCSectorRegister = 1;
                    203:        FDCDataRegister = 0;
                    204:        FDCSectorCountRegister = 0;
                    205: 
                    206:        FDCEmulationCommand = FDCEMU_CMD_NULL;        /* FDC emulation command currently being exceuted */
                    207:        FDCEmulationRunning = FDCEMU_RUN_NULL;        /* Running command under above */
                    208: 
                    209:        FDCStepDirection = 1;                         /* +Track on 'Step' command */
                    210:        bDMAWaiting = FALSE;                          /* No DMA waiting */
                    211:        bMotorOn = FALSE;                             /* Motor off */
                    212:        MotorSlowingCount = 0;                        /* Counter for motor slowing down before stopping */
1.1       root      213: }
                    214: 
1.1.1.2   root      215: 
                    216: /*-----------------------------------------------------------------------*/
1.1.1.9   root      217: /**
                    218:  * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                    219:  */
1.1.1.10  root      220: void FDC_MemorySnapShot_Capture(bool bSave)
1.1       root      221: {
1.1.1.6   root      222:        /* Save/Restore details */
1.1.1.7   root      223:        MemorySnapShot_Store(&DiskControllerStatus_ff8604rd, sizeof(DiskControllerStatus_ff8604rd));
                    224:        MemorySnapShot_Store(&DiskControllerWord_ff8604wr, sizeof(DiskControllerWord_ff8604wr));
1.1.1.6   root      225:        MemorySnapShot_Store(&DMAStatus_ff8606rd, sizeof(DMAStatus_ff8606rd));
                    226:        MemorySnapShot_Store(&DMAModeControl_ff8606wr, sizeof(DMAModeControl_ff8606wr));
                    227:        MemorySnapShot_Store(&FDCCommandRegister, sizeof(FDCCommandRegister));
                    228:        MemorySnapShot_Store(&FDCTrackRegister, sizeof(FDCTrackRegister));
                    229:        MemorySnapShot_Store(&FDCSectorRegister, sizeof(FDCSectorRegister));
                    230:        MemorySnapShot_Store(&FDCDataRegister, sizeof(FDCDataRegister));
                    231:        MemorySnapShot_Store(&FDCSectorCountRegister, sizeof(FDCSectorCountRegister));
                    232:        MemorySnapShot_Store(&FDCEmulationCommand, sizeof(FDCEmulationCommand));
                    233:        MemorySnapShot_Store(&FDCEmulationRunning, sizeof(FDCEmulationRunning));
                    234:        MemorySnapShot_Store(&FDCStepDirection, sizeof(FDCStepDirection));
                    235:        MemorySnapShot_Store(&bDMAWaiting, sizeof(bDMAWaiting));
                    236:        MemorySnapShot_Store(&bMotorOn, sizeof(bMotorOn));
                    237:        MemorySnapShot_Store(&MotorSlowingCount, sizeof(MotorSlowingCount));
                    238:        MemorySnapShot_Store(&nReadWriteTrack, sizeof(nReadWriteTrack));
                    239:        MemorySnapShot_Store(&nReadWriteSector, sizeof(nReadWriteSector));
                    240:        MemorySnapShot_Store(&nReadWriteSide, sizeof(nReadWriteSide));
                    241:        MemorySnapShot_Store(&nReadWriteDev, sizeof(nReadWriteDev));
                    242:        MemorySnapShot_Store(&nReadWriteSectorsPerTrack, sizeof(nReadWriteSectorsPerTrack));
                    243:        MemorySnapShot_Store(&nReadWriteSectors, sizeof(nReadWriteSectors));
                    244:        MemorySnapShot_Store(DMASectorWorkSpace, sizeof(DMASectorWorkSpace));
1.1       root      245: }
                    246: 
1.1.1.2   root      247: 
                    248: /*-----------------------------------------------------------------------*/
1.1.1.9   root      249: /**
                    250:  * Turn floppy motor on
                    251:  */
1.1.1.5   root      252: static void FDC_TurnMotorOn(void)
1.1       root      253: {
1.1.1.6   root      254:        bMotorOn = TRUE;                  /* Turn motor on */
                    255:        MotorSlowingCount = 0;
1.1       root      256: }
                    257: 
1.1.1.2   root      258: 
                    259: /*-----------------------------------------------------------------------*/
1.1.1.9   root      260: /**
                    261:  * Turn floppy motor off (this sets a count as it takes a set amount of time for the motor to slow to a halt)
                    262:  */
1.1.1.5   root      263: static void FDC_TurnMotorOff(void)
1.1       root      264: {
1.1.1.6   root      265:        MotorSlowingCount = 160;          /* Set timer so takes 'x' HBLs before turn off... */
1.1       root      266: }
                    267: 
1.1.1.2   root      268: 
                    269: /*-----------------------------------------------------------------------*/
1.1.1.9   root      270: /**
                    271:  * Update floppy drive motor each HBL, to simulate slowing down and stopping for drive; needed for New Zealand Story(PP_001)
                    272:  */
1.1.1.5   root      273: static void FDC_UpdateMotor(void)
1.1       root      274: {
1.1.1.6   root      275:        /* Is drive slowing down? Decrement counter */
                    276:        if (MotorSlowingCount>0)
                    277:        {
                    278:                MotorSlowingCount--;
                    279: 
                    280:                if (MotorSlowingCount==0)
                    281:                        bMotorOn = FALSE;         /* Motor finally stopped */
                    282:        }
1.1       root      283: }
                    284: 
1.1.1.2   root      285: 
                    286: /*-----------------------------------------------------------------------*/
1.1.1.9   root      287: /**
                    288:  * Reset DMA Status (RD 0xff8606)
                    289:  *
                    290:  * This is done by 'toggling' bit 8 of the DMA Mode Control register
                    291:  */
1.1       root      292: void FDC_ResetDMAStatus(void)
                    293: {
1.1.1.6   root      294:        DMAStatus_ff8606rd = 0;           /* Clear out */
1.1       root      295: 
1.1.1.6   root      296:        FDCSectorCountRegister = 0;
                    297:        FDC_SetDMAStatus(FALSE);          /* Set no error */
1.1.1.3   root      298: 
1.1.1.10  root      299:        /* Reset HDC command status */
1.1.1.6   root      300:        HDCSectorCount = 0;
1.1.1.10  root      301:        /*HDCCommand.byteCount = 0;*/  /* Not done on real ST? */
1.1.1.8   root      302:        HDCCommand.returnCode = 0;
1.1       root      303: }
                    304: 
1.1.1.2   root      305: 
                    306: /*-----------------------------------------------------------------------*/
1.1.1.9   root      307: /**
                    308:  * Set DMA Status (RD 0xff8606)
1.1.1.10  root      309:  *
1.1.1.9   root      310:  * NOTE FDC Doc's are incorrect - Bit 0 is '0' on error (See TOS floprd, Ninja III etc...)
                    311:  * Look like Atari(yet again) connected the hardware up differently to the spec'
                    312:  *
                    313:  * Bit 0 - _Error Status (0=Error)
                    314:  * Bit 1 - _Sector Count Zero Status (0=Sector Count Zero)
                    315:  * Bit 2 - _Data Request Inactive Status
                    316:  */
1.1.1.10  root      317: void FDC_SetDMAStatus(bool bError)
1.1       root      318: {
1.1.1.6   root      319:        DMAStatus_ff8606rd &= 0x1;        /* Clear(except for error) */
1.1       root      320: 
1.1.1.6   root      321:        /* Set error condition - NOTE this is incorrect in the FDC Doc's! */
                    322:        if (!bError)
                    323:                DMAStatus_ff8606rd |= 0x1;
                    324: 
                    325:        /* Set zero sector count */
                    326: 
                    327:        if (DMAModeControl_ff8606wr&0x08)         /* Get which sector count? */
1.1.1.8   root      328:                DMAStatus_ff8606rd |= (HDCSectorCount)?0x2:0;         /* HDC */
1.1.1.6   root      329:        else
                    330:                DMAStatus_ff8606rd |= (FDCSectorCountRegister)?0x2:0; /* FDC */
                    331:        /* Perhaps the DRQ should be set here */
1.1       root      332: }
                    333: 
1.1.1.2   root      334: 
                    335: /*-----------------------------------------------------------------------*/
1.1.1.9   root      336: /**
                    337:  * Read DMA Status (RD 0xff8606)
                    338:  */
1.1.1.6   root      339: void FDC_DmaStatus_ReadWord(void)
1.1       root      340: {
1.1.1.6   root      341:        if (nIoMemAccessSize == SIZE_BYTE)
                    342:        {
                    343:                /* This register does not like to be accessed in byte mode on a normal ST */
1.1.1.8   root      344:                M68000_BusError(IoAccessBaseAddress, BUS_ERROR_READ);
1.1.1.6   root      345:                return;
                    346:        }
                    347: 
                    348:        IoMem_WriteWord(0xff8606, DMAStatus_ff8606rd);
1.1       root      349: }
                    350: 
1.1.1.2   root      351: 
                    352: /*-----------------------------------------------------------------------*/
1.1.1.9   root      353: /**
1.1.1.10  root      354:  *
1.1.1.9   root      355:  */
1.1.1.7   root      356: static void FDC_UpdateDiskDrive(void)
1.1       root      357: {
1.1.1.6   root      358:        /* Set details for current selecte drive */
                    359:        nReadWriteDev = FDC_FindFloppyDrive();
1.1.1.2   root      360: 
1.1.1.7   root      361:        if (EmulationDrives[nReadWriteDev].bDiskInserted)
                    362:                Floppy_FindDiskDetails(EmulationDrives[nReadWriteDev].pBuffer,EmulationDrives[nReadWriteDev].nImageBytes,&nReadWriteSectorsPerTrack,NULL);
1.1       root      363: }
                    364: 
1.1.1.2   root      365: 
                    366: /*-----------------------------------------------------------------------*/
1.1.1.9   root      367: /**
                    368:  * Set disk controller status (RD 0xff8604)
                    369:  */
1.1.1.7   root      370: static void FDC_SetDiskControllerStatus(void)
1.1       root      371: {
1.1.1.7   root      372:        /* Update disk */
                    373:        FDC_UpdateDiskDrive();
1.1       root      374: 
1.1.1.6   root      375:        /* Clear out to default */
1.1.1.7   root      376:        DiskControllerStatus_ff8604rd = 0;
1.1       root      377: 
1.1.1.6   root      378:        /* ONLY do this if we are running a Type I command */
                    379:        if ((FDCCommandRegister&0x80)==0)
                    380:        {
                    381:                /* Type I - Restore, Seek, Step, Step-In, Step-Out */
                    382:                if (FDCTrackRegister==0)
1.1.1.7   root      383:                        DiskControllerStatus_ff8604rd |= 0x4;    /* Bit 2 - Track Zero, '0' if head is NOT at zero */
1.1.1.6   root      384:        }
                    385: 
1.1.1.7   root      386:        /* If no disk inserted, tag as error */
                    387:        if (!EmulationDrives[nReadWriteDev].bDiskInserted)
                    388:                DiskControllerStatus_ff8604rd |= 0x10;     /* RNF - Record not found, ie no disk in drive */
1.1       root      389: }
                    390: 
1.1.1.2   root      391: 
                    392: /*-----------------------------------------------------------------------*/
1.1.1.9   root      393: /**
                    394:  * Return device for FDC, check PORTA bits 1,2(0=on,1=off)
                    395:  */
1.1       root      396: int FDC_FindFloppyDrive(void)
                    397: {
1.1.1.6   root      398:        /* Check Drive A first */
                    399:        if ((PSGRegisters[PSG_REG_IO_PORTA]&0x2)==0)
                    400:                return 0;                     /* Device 0 (A:) */
                    401:        /* If off, check Drive B */
                    402:        if ((PSGRegisters[PSG_REG_IO_PORTA]&0x4)==0)
                    403:                return 1;                     /* Device 1 (B:) */
1.1       root      404: 
1.1.1.6   root      405:        /* None appear to be selected so default to Drive A */
                    406:        return 0;                         /* Device 0 (A:) */
1.1       root      407: }
                    408: 
1.1.1.2   root      409: 
                    410: /*-----------------------------------------------------------------------*/
1.1.1.9   root      411: /**
                    412:  * Acknowledge FDC interrupt
                    413:  */
1.1       root      414: void FDC_AcknowledgeInterrupt(void)
                    415: {
1.1.1.6   root      416:        /* Acknowledge in MFP circuit, pass bit, enable, pending */
                    417:        MFP_InputOnChannel(MFP_FDCHDC_BIT,MFP_IERB,&MFP_IPRB);
                    418:        MFP_GPIP &= ~0x20;
1.1       root      419: }
                    420: 
1.1.1.2   root      421: 
                    422: /*-----------------------------------------------------------------------*/
1.1.1.9   root      423: /**
                    424:  * Copy parameters for disk sector/s read/write
                    425:  */
1.1.1.5   root      426: static void FDC_SetReadWriteParameters(int nSectors)
1.1       root      427: {
1.1.1.6   root      428:        /* Copy read/write details so we can modify them */
                    429:        nReadWriteTrack = FDCTrackRegister;
                    430:        nReadWriteSector = FDCSectorRegister;
                    431:        nReadWriteSide = (~PSGRegisters[PSG_REG_IO_PORTA]) & 0x01;
                    432:        nReadWriteSectors = nSectors;
1.1.1.7   root      433:        /* Update disk */
                    434:        FDC_UpdateDiskDrive();
1.1       root      435: }
                    436: 
1.1.1.2   root      437: 
                    438: /*-----------------------------------------------------------------------*/
1.1.1.9   root      439: /**
                    440:  * ST program (or TOS) has read the MFP GPIP register to check if the FDC
                    441:  * is already done. Then we can skip the usual FDC waiting period!
                    442:  */
1.1.1.8   root      443: void FDC_GpipRead(void)
                    444: {
                    445:        static int nLastGpipBit;
                    446: 
                    447:        if ((MFP_GPIP & 0x20) == nLastGpipBit)
                    448:        {
                    449:                if (!ConfigureParams.System.bSlowFDC)
1.1.1.9   root      450:                {
                    451:                        /* Restart FDC update interrupt to occur right after a few cycles */
                    452:                        Int_RemovePendingInterrupt(INTERRUPT_FDC);
1.1.1.10  root      453:                        Int_AddRelativeInterrupt(4, INT_CPU_CYCLE, INTERRUPT_FDC);
1.1.1.9   root      454:                }
1.1.1.8   root      455:        }
                    456:        else
                    457:        {
                    458:                nLastGpipBit = MFP_GPIP & 0x20;
                    459:        }
                    460: }
                    461: 
                    462: 
                    463: /*-----------------------------------------------------------------------*/
1.1.1.9   root      464: /**
                    465:  * Update floppy drive after a while.
                    466:  * Some games/demos (e.g. Fantasia by Dune, Alien World, ...) don't work
                    467:  * if the FDC is too fast. So we use the update "interrupt" for delayed
                    468:  * execution of the commands.
                    469:  * FIXME: We urgently need better timings here!
                    470:  */
                    471: void FDC_InterruptHandler_Update(void)
1.1       root      472: {
1.1.1.9   root      473:        Int_AcknowledgeInterrupt();
1.1.1.6   root      474: 
                    475:        /* Do we have a DMA ready to copy? */
                    476:        if (bDMAWaiting)
                    477:        {
                    478:                /* Yes, copy it */
                    479:                FDC_DMADataFromFloppy();
                    480:                /* Signal done */
                    481:                bDMAWaiting = FALSE;
                    482:        }
                    483: 
                    484:        /* Update drive motor */
                    485:        FDC_UpdateMotor();
                    486: 
                    487:        /* Is FDC active? */
                    488:        if (FDCEmulationCommand!=FDCEMU_CMD_NULL)
                    489:        {
                    490:                /* Which command are we running? */
                    491:                switch(FDCEmulationCommand)
                    492:                {
                    493:                 case FDCEMU_CMD_RESTORE:
                    494:                        FDC_UpdateRestoreCmd();
                    495:                        break;
                    496:                 case FDCEMU_CMD_SEEK:
                    497:                        FDC_UpdateSeekCmd();
                    498:                        break;
                    499:                 case FDCEMU_CMD_STEP:
                    500:                        FDC_UpdateStepCmd();
                    501:                        break;
                    502:                 case FDCEMU_CMD_STEPIN:
                    503:                        FDC_UpdateStepInCmd();
                    504:                        break;
                    505:                 case FDCEMU_CMD_STEPOUT:
                    506:                        FDC_UpdateStepOutCmd();
                    507:                        break;
                    508: 
                    509:                 case FDCEMU_CMD_READSECTORS:
                    510:                 case FDCEMU_CMD_READMULTIPLESECTORS:
                    511:                        FDC_UpdateReadSectorsCmd();
                    512:                        break;
                    513:                 case FDCEMU_CMD_WRITESECTORS:
                    514:                 case FDCEMU_CMD_WRITEMULTIPLESECTORS:
                    515:                        FDC_UpdateWriteSectorsCmd();
                    516:                        break;
1.1.1.11! root      517: 
        !           518:                 case FDCEMU_CMD_READADDRESS:
        !           519:                        FDC_UpdateReadAddressCmd();
        !           520:                        break;
1.1.1.6   root      521:                }
                    522: 
1.1.1.7   root      523:                /* Set disk controller status (RD 0xff8604) */
                    524:                FDC_SetDiskControllerStatus();
1.1.1.6   root      525:        }
1.1.1.9   root      526: 
                    527:        if (FDCEmulationCommand != FDCEMU_CMD_NULL || bMotorOn)
                    528:        {
                    529:                Int_AddAbsoluteInterrupt(FDC_DELAY_CYCLES,  INT_CPU_CYCLE, INTERRUPT_FDC);
                    530:        }
1.1       root      531: }
                    532: 
1.1.1.2   root      533: 
                    534: /*-----------------------------------------------------------------------*/
1.1.1.9   root      535: /**
                    536:  * Run 'RESTORE' command
                    537:  */
1.1       root      538: void FDC_UpdateRestoreCmd(void)
                    539: {
1.1.1.6   root      540:        /* Which command is running? */
                    541:        switch (FDCEmulationRunning)
                    542:        {
                    543:         case FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO:
                    544:                /* Are we at track zero? */
                    545:                if (FDCTrackRegister>0)
                    546:                        FDCTrackRegister--;             /* Move towards track zero */
                    547:                else
                    548:                {
                    549:                        FDCTrackRegister = 0;           /* We're there */
                    550:                        FDCEmulationRunning = FDCEMU_RUN_RESTORE_COMPLETE;
                    551:                }
                    552:                break;
                    553:         case FDCEMU_RUN_RESTORE_COMPLETE:
                    554:                /* Acknowledge interrupt, move along there's nothing more to see */
                    555:                FDC_AcknowledgeInterrupt();
                    556:                /* Set error */
                    557:                FDC_SetDMAStatus(FALSE);          /* No DMA error */
                    558:                /* Done */
                    559:                FDCEmulationCommand = FDCEMU_CMD_NULL;
                    560:                /* Turn motor off */
                    561:                FDC_TurnMotorOff();
                    562:                break;
                    563:        }
1.1       root      564: }
                    565: 
1.1.1.2   root      566: 
                    567: /*-----------------------------------------------------------------------*/
1.1.1.9   root      568: /**
                    569:  * Run 'SEEK' command
                    570:  */
1.1       root      571: void FDC_UpdateSeekCmd(void)
                    572: {
1.1.1.6   root      573:        /* Which command is running? */
                    574:        switch (FDCEmulationRunning)
                    575:        {
                    576:         case FDCEMU_RUN_SEEK_TOTRACK:
                    577:                /* Are we at the selected track? */
                    578:                if (FDCTrackRegister==FDCDataRegister)
                    579:                        FDCEmulationRunning = FDCEMU_RUN_SEEK_COMPLETE;
                    580:                else
                    581:                {
                    582:                        /* No, seek towards track */
                    583:                        if (FDCDataRegister<FDCTrackRegister)
                    584:                                FDCTrackRegister--;
                    585:                        else
                    586:                                FDCTrackRegister++;
                    587:                }
                    588:                break;
                    589:         case FDCEMU_RUN_SEEK_COMPLETE:
                    590:                /* Acknowledge interrupt, move along there's nothing more to see */
                    591:                FDC_AcknowledgeInterrupt();
                    592:                /* Set error */
                    593:                FDC_SetDMAStatus(FALSE);          /* No DMA error */
                    594:                /* Done */
                    595:                FDCEmulationCommand = FDCEMU_CMD_NULL;
                    596:                /* Turn motor off */
                    597:                FDC_TurnMotorOff();
                    598:                break;
                    599:        }
1.1       root      600: }
                    601: 
1.1.1.2   root      602: 
                    603: /*-----------------------------------------------------------------------*/
1.1.1.9   root      604: /**
                    605:  * Run 'STEP' command
                    606:  */
1.1       root      607: void FDC_UpdateStepCmd(void)
                    608: {
1.1.1.6   root      609:        /* Which command is running? */
                    610:        switch (FDCEmulationRunning)
                    611:        {
                    612:         case FDCEMU_RUN_STEP_ONCE:
                    613:                /* Move head by one track in same direction as last step */
                    614:                FDCTrackRegister += FDCStepDirection;
                    615:                if (FDCTrackRegister<0)             /* Limit to stop */
                    616:                        FDCTrackRegister = 0;
                    617: 
                    618:                FDCEmulationRunning = FDCEMU_RUN_STEP_COMPLETE;
                    619:                break;
                    620:         case FDCEMU_RUN_STEP_COMPLETE:
                    621:                /* Acknowledge interrupt, move along there's nothing more to see */
                    622:                FDC_AcknowledgeInterrupt();
                    623:                /* Set error */
                    624:                FDC_SetDMAStatus(FALSE);            /* No DMA error */
                    625:                /* Done */
                    626:                FDCEmulationCommand = FDCEMU_CMD_NULL;
                    627:                /* Turn motor off */
                    628:                FDC_TurnMotorOff();
                    629:                break;
                    630:        }
1.1       root      631: }
                    632: 
1.1.1.2   root      633: 
                    634: /*-----------------------------------------------------------------------*/
1.1.1.9   root      635: /**
                    636:  * Run 'STEP IN' command
                    637:  */
1.1       root      638: void FDC_UpdateStepInCmd(void)
                    639: {
1.1.1.6   root      640:        /* Which command is running? */
                    641:        switch (FDCEmulationRunning)
                    642:        {
                    643:         case FDCEMU_RUN_STEPIN_ONCE:
                    644:                FDCTrackRegister++;
                    645: 
                    646:                FDCEmulationRunning = FDCEMU_RUN_STEPIN_COMPLETE;
                    647:                break;
                    648:         case FDCEMU_RUN_STEPIN_COMPLETE:
                    649:                /* Acknowledge interrupt, move along there's nothing more to see */
                    650:                FDC_AcknowledgeInterrupt();
                    651:                /* Set error */
                    652:                FDC_SetDMAStatus(FALSE);            /* No DMA error */
                    653:                /* Done */
                    654:                FDCEmulationCommand = FDCEMU_CMD_NULL;
                    655:                /* Turn motor off */
                    656:                FDC_TurnMotorOff();
                    657:                break;
                    658:        }
1.1       root      659: }
                    660: 
1.1.1.2   root      661: 
                    662: /*-----------------------------------------------------------------------*/
1.1.1.9   root      663: /**
                    664:  * Run 'STEP OUT' command
                    665:  */
1.1       root      666: void FDC_UpdateStepOutCmd(void)
                    667: {
1.1.1.6   root      668:        /* Which command is running? */
                    669:        switch (FDCEmulationRunning)
                    670:        {
                    671:         case FDCEMU_RUN_STEPOUT_ONCE:
                    672:                FDCTrackRegister--;
                    673:                if (FDCTrackRegister < 0)           /* Limit to stop */
                    674:                        FDCTrackRegister = 0;
                    675: 
                    676:                FDCEmulationRunning = FDCEMU_RUN_STEPOUT_COMPLETE;
                    677:                break;
                    678:         case FDCEMU_RUN_STEPOUT_COMPLETE:
                    679:                /* Acknowledge interrupt, move along there's nothing more to see */
                    680:                FDC_AcknowledgeInterrupt();
                    681:                /* Set error */
                    682:                FDC_SetDMAStatus(FALSE);            /* No DMA error */
                    683:                /* Done */
                    684:                FDCEmulationCommand = FDCEMU_CMD_NULL;
                    685:                /* Turn motor off */
                    686:                FDC_TurnMotorOff();
                    687:                break;
                    688:        }
1.1       root      689: }
                    690: 
1.1.1.2   root      691: 
                    692: /*-----------------------------------------------------------------------*/
1.1.1.9   root      693: /**
                    694:  * Run 'READ SECTOR/S' command
                    695:  */
1.1       root      696: void FDC_UpdateReadSectorsCmd(void)
                    697: {
1.1.1.6   root      698:        /* Which command is running? */
                    699:        switch (FDCEmulationRunning)
                    700:        {
                    701:         case FDCEMU_RUN_READSECTORS_READDATA:
                    702:                /* Read in a sector */
                    703:                if (FDC_ReadSectorFromFloppy())         /* Read a single sector through DMA */
                    704:                {
                    705:                        FDCSectorCountRegister--;           /* Decrement FDCSectorCount */
                    706:                        if (FDCSectorCountRegister <= 0)
                    707:                                FDCSectorCountRegister = 0;
                    708: 
                    709:                        /* Have we finished? */
                    710:                        nReadWriteSectors--;
                    711:                        if (nReadWriteSectors<=0)
                    712:                                FDCEmulationRunning = FDCEMU_RUN_READSECTORS_COMPLETE;
                    713: 
                    714:                        bDMAWaiting = TRUE;
                    715:                }
                    716:                else
                    717:                {
                    718:                        /* Acknowledge interrupt, move along there's nothing more to see */
                    719:                        FDC_AcknowledgeInterrupt();
                    720:                        /* Set error */
                    721:                        FDC_SetDMAStatus(TRUE);             /* DMA error */
                    722:                        /* Done */
                    723:                        FDCEmulationCommand = FDCEMU_CMD_NULL;
                    724:                        /* Turn motor off */
                    725:                        FDC_TurnMotorOff();
                    726:                }
                    727:                break;
                    728:         case FDCEMU_RUN_READSECTORS_COMPLETE:
                    729:                /* Acknowledge interrupt, move along there's nothing more to see */
                    730:                FDC_AcknowledgeInterrupt();
                    731:                /* Set error */
                    732:                FDC_SetDMAStatus(FALSE);              /* No DMA error */
                    733:                /* Done */
                    734:                FDCEmulationCommand = FDCEMU_CMD_NULL;
                    735:                /* Turn motor off */
                    736:                FDC_TurnMotorOff();
                    737:                break;
                    738:        }
1.1       root      739: }
                    740: 
1.1.1.2   root      741: 
                    742: /*-----------------------------------------------------------------------*/
1.1.1.9   root      743: /**
                    744:  * Run 'WRITE SECTOR/S' command
                    745:  */
1.1       root      746: void FDC_UpdateWriteSectorsCmd(void)
                    747: {
1.1.1.6   root      748:        /* Which command is running? */
                    749:        switch (FDCEmulationRunning)
                    750:        {
                    751:         case FDCEMU_RUN_WRITESECTORS_WRITEDATA:
                    752:                /* Write out a sector */
                    753:                if (FDC_WriteSectorFromFloppy())        /* Write a single sector through DMA */
                    754:                {
                    755:                        /* Decrement FDCsector count */
                    756:                        FDCSectorCountRegister--;           /* Decrement FDCSectorCount */
                    757:                        if (FDCSectorCountRegister<=0)
                    758:                                FDCSectorCountRegister = 0;
                    759: 
                    760:                        /* Have we finished? */
                    761:                        nReadWriteSectors--;
                    762:                        if (nReadWriteSectors<=0)
                    763:                                FDCEmulationRunning = FDCEMU_RUN_WRITESECTORS_COMPLETE;
                    764: 
                    765:                        /* Update DMA pointer */
                    766:                        FDC_WriteDMAAddress(FDC_ReadDMAAddress()+NUMBYTESPERSECTOR);
                    767:                }
                    768:                else
                    769:                {
                    770:                        /* Acknowledge interrupt, move along there's nothing more to see */
                    771:                        FDC_AcknowledgeInterrupt();
                    772:                        /* Set error */
                    773:                        FDC_SetDMAStatus(TRUE);             /* DMA error */
                    774:                        /* Done */
                    775:                        FDCEmulationCommand = FDCEMU_CMD_NULL;
                    776:                        /* Turn motor off */
                    777:                        FDC_TurnMotorOff();
                    778:                }
                    779:                break;
                    780:         case FDCEMU_RUN_WRITESECTORS_COMPLETE:
                    781:                /* Acknowledge interrupt, move along there's nothing more to see */
                    782:                FDC_AcknowledgeInterrupt();
                    783:                /* Set error */
                    784:                FDC_SetDMAStatus(FALSE);              /* No DMA error */
                    785:                /* Done */
                    786:                FDCEmulationCommand = FDCEMU_CMD_NULL;
                    787:                /* Turn motor off */
                    788:                FDC_TurnMotorOff();
                    789:                break;
                    790:        }
1.1       root      791: }
                    792: 
1.1.1.2   root      793: 
                    794: /*-----------------------------------------------------------------------*/
1.1.1.9   root      795: /**
1.1.1.11! root      796:  * Run 'READ ADDRESS' command
        !           797:  */
        !           798: void FDC_UpdateReadAddressCmd(void)
        !           799: {
        !           800:        /* Which command is running? */
        !           801:        switch (FDCEmulationRunning)
        !           802:        {
        !           803:         case FDCEMU_RUN_READADDRESS:
        !           804:                /* not implemented, just return with no error */
        !           805:                FDCEmulationRunning = FDCEMU_RUN_READADDRESS_COMPLETE;
        !           806:                break;
        !           807:         case FDCEMU_RUN_READADDRESS_COMPLETE:
        !           808:                /* Acknowledge interrupt, move along there's nothing more to see */
        !           809:                FDC_AcknowledgeInterrupt();
        !           810:                /* Set error */
        !           811:                FDC_SetDMAStatus(FALSE);            /* No DMA error */
        !           812:                /* Done */
        !           813:                FDCEmulationCommand = FDCEMU_CMD_NULL;
        !           814:                /* Turn motor off */
        !           815:                FDC_TurnMotorOff();
        !           816:                break;
        !           817:        }
        !           818: }
        !           819: 
        !           820: 
        !           821: /*-----------------------------------------------------------------------*/
        !           822: /**
1.1.1.9   root      823:  * Type I Commands
                    824:  *
                    825:  * Restore, Seek, Step, Step-In and Step-Out
                    826:  */
1.1       root      827: 
1.1.1.2   root      828: 
                    829: /*-----------------------------------------------------------------------*/
1.1.1.5   root      830: static void FDC_TypeI_Restore(void)
1.1       root      831: {
1.1.1.10  root      832:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type I restore VBL=%d video_cyc=%d pc=%x\n" ,
                    833:                nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                    834: 
1.1.1.6   root      835:        /* Set emulation to seek to track zero */
                    836:        FDCEmulationCommand = FDCEMU_CMD_RESTORE;
                    837:        FDCEmulationRunning = FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO;
1.1       root      838: 
1.1.1.7   root      839:        FDC_SetDiskControllerStatus();
1.1       root      840: }
                    841: 
1.1.1.2   root      842: 
                    843: /*-----------------------------------------------------------------------*/
1.1.1.5   root      844: static void FDC_TypeI_Seek(void)
1.1       root      845: {
1.1.1.10  root      846:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type I seek track=0x%x VBL=%d video_cyc=%d pc=%x\n" ,
                    847:                FDCDataRegister , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                    848: 
1.1.1.6   root      849:        /* Set emulation to seek to chosen track */
                    850:        FDCEmulationCommand = FDCEMU_CMD_SEEK;
                    851:        FDCEmulationRunning = FDCEMU_RUN_SEEK_TOTRACK;
1.1       root      852: 
1.1.1.7   root      853:        FDC_SetDiskControllerStatus();
1.1       root      854: }
                    855: 
1.1.1.2   root      856: 
                    857: /*-----------------------------------------------------------------------*/
1.1.1.5   root      858: static void FDC_TypeI_Step(void)
1.1       root      859: {
1.1.1.10  root      860:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type I step %d VBL=%d video_cyc=%d pc=%x\n" ,
                    861:                FDCStepDirection , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                    862: 
1.1.1.6   root      863:        /* Set emulation to step(same direction as last seek executed, eg 'FDCStepDirection') */
                    864:        FDCEmulationCommand = FDCEMU_CMD_STEP;
                    865:        FDCEmulationRunning = FDCEMU_RUN_STEP_ONCE;
1.1       root      866: 
1.1.1.7   root      867:        FDC_SetDiskControllerStatus();
1.1       root      868: }
                    869: 
1.1.1.2   root      870: 
                    871: /*-----------------------------------------------------------------------*/
1.1.1.5   root      872: static void FDC_TypeI_StepIn(void)
1.1       root      873: {
1.1.1.10  root      874:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type I step in VBL=%d video_cyc=%d pc=%x\n" ,
                    875:                nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                    876: 
1.1.1.6   root      877:        /* Set emulation to step in(Set 'FDCStepDirection') */
                    878:        FDCEmulationCommand = FDCEMU_CMD_STEPIN;
                    879:        FDCEmulationRunning = FDCEMU_RUN_STEPIN_ONCE;
                    880:        FDCStepDirection = 1;                 /* Increment track*/
1.1       root      881: 
1.1.1.7   root      882:        FDC_SetDiskControllerStatus();
1.1       root      883: }
                    884: 
1.1.1.2   root      885: 
                    886: /*-----------------------------------------------------------------------*/
1.1.1.5   root      887: static void FDC_TypeI_StepOut(void)
1.1       root      888: {
1.1.1.10  root      889:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type I step out VBL=%d video_cyc=%d pc=%x\n" ,
                    890:                nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                    891: 
1.1.1.6   root      892:        /* Set emulation to step out(Set 'FDCStepDirection') */
                    893:        FDCEmulationCommand = FDCEMU_CMD_STEPOUT;
                    894:        FDCEmulationRunning = FDCEMU_RUN_STEPOUT_ONCE;
                    895:        FDCStepDirection = -1;                /* Decrement track */
1.1       root      896: 
1.1.1.7   root      897:        FDC_SetDiskControllerStatus();
1.1       root      898: }
                    899: 
1.1.1.2   root      900: 
                    901: /*-----------------------------------------------------------------------*/
1.1.1.9   root      902: /**
                    903:  * Type II Commands
                    904:  *
                    905:  * Read Sector, Read Multiple Sectors, Write Sector, Write Multiple Sectors
                    906:  */
1.1       root      907: 
1.1.1.2   root      908: 
                    909: /*-----------------------------------------------------------------------*/
1.1.1.5   root      910: static void FDC_TypeII_ReadSector(void)
1.1       root      911: {
1.1.1.10  root      912:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type II read sector %d VBL=%d video_cyc=%d pc=%x\n" ,
                    913:                FDCSectorRegister , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                    914: 
1.1.1.6   root      915:        /* Set emulation to read a single sector */
                    916:        FDCEmulationCommand = FDCEMU_CMD_READSECTORS;
                    917:        FDCEmulationRunning = FDCEMU_RUN_READSECTORS_READDATA;
                    918:        /* Set reading parameters */
                    919:        FDC_SetReadWriteParameters(1);        /* Read in a single sector */
1.1       root      920: 
1.1.1.7   root      921:        FDC_SetDiskControllerStatus();
1.1       root      922: }
                    923: 
1.1.1.2   root      924: 
                    925: /*-----------------------------------------------------------------------*/
1.1.1.5   root      926: static void FDC_TypeII_ReadMultipleSectors(void)
1.1       root      927: {
1.1.1.10  root      928:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type II read multi sectors %d count %d VBL=%d video_cyc=%d pc=%x\n" ,
                    929:                FDCSectorRegister , FDCSectorCountRegister , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                    930: 
1.1.1.6   root      931:        /* Set emulation to read sectors */
                    932:        FDCEmulationCommand = FDCEMU_CMD_READMULTIPLESECTORS;
                    933:        FDCEmulationRunning = FDCEMU_RUN_READSECTORS_READDATA;
                    934:        /* Set reading parameters */
                    935:        FDC_SetReadWriteParameters(FDCSectorCountRegister);   /* Read multiple sectors */
1.1       root      936: 
1.1.1.7   root      937:        FDC_SetDiskControllerStatus();
1.1       root      938: }
                    939: 
1.1.1.2   root      940: 
                    941: /*-----------------------------------------------------------------------*/
1.1.1.5   root      942: static void FDC_TypeII_WriteSector(void)
1.1       root      943: {
1.1.1.10  root      944:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type II write sector %d VBL=%d video_cyc=%d pc=%x\n" ,
                    945:                FDCSectorRegister , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                    946: 
1.1.1.6   root      947:        /* Set emulation to write a single sector */
                    948:        FDCEmulationCommand = FDCEMU_CMD_WRITESECTORS;
                    949:        FDCEmulationRunning = FDCEMU_RUN_WRITESECTORS_WRITEDATA;
                    950:        /* Set writing parameters */
                    951:        FDC_SetReadWriteParameters(1);                        /* Write out a single sector */
1.1       root      952: 
1.1.1.7   root      953:        FDC_SetDiskControllerStatus();
1.1       root      954: }
                    955: 
1.1.1.2   root      956: 
                    957: /*-----------------------------------------------------------------------*/
1.1.1.5   root      958: static void FDC_TypeII_WriteMultipleSectors(void)
1.1       root      959: {
1.1.1.10  root      960:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type II write multi sectors %d count %d VBL=%d video_cyc=%d pc=%x\n" ,
                    961:                FDCSectorRegister , FDCSectorCountRegister , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                    962: 
1.1.1.6   root      963:        /* Set emulation to write sectors */
                    964:        FDCEmulationCommand = FDCEMU_CMD_WRITEMULTIPLESECTORS;
                    965:        FDCEmulationRunning = FDCEMU_RUN_WRITESECTORS_WRITEDATA;
                    966:        /* Set witing parameters */
                    967:        FDC_SetReadWriteParameters(FDCSectorCountRegister);   /* Write multiple sectors */
1.1       root      968: 
1.1.1.7   root      969:        FDC_SetDiskControllerStatus();
1.1       root      970: }
                    971: 
1.1.1.2   root      972: 
                    973: /*-----------------------------------------------------------------------*/
1.1.1.9   root      974: /**
                    975:  * Type III Commands
                    976:  *
                    977:  * Read Address, Read Track, Write Track
                    978:  */
1.1       root      979: 
1.1.1.2   root      980: 
                    981: /*-----------------------------------------------------------------------*/
1.1.1.5   root      982: static void FDC_TypeIII_ReadAddress(void)
1.1       root      983: {
1.1.1.10  root      984:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type III read address unimplemented VBL=%d video_cyc=%d pc=%x\n" ,
                    985:                nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                    986: 
                    987:        Log_Printf(LOG_TODO, "FDC type III command 'read address' is not implemented yet!\n");
1.1.1.11! root      988: 
        !           989:        /* Set emulation to seek to track zero */
        !           990:        FDCEmulationCommand = FDCEMU_CMD_READADDRESS;
        !           991:        FDCEmulationRunning = FDCEMU_RUN_READADDRESS;
        !           992: 
        !           993:        FDC_SetDiskControllerStatus();
1.1       root      994: }
                    995: 
1.1.1.2   root      996: 
                    997: /*-----------------------------------------------------------------------*/
1.1.1.5   root      998: static void FDC_TypeIII_ReadTrack(void)
1.1       root      999: {
1.1.1.10  root     1000:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type III read track 0x%x VBL=%d video_cyc=%d pc=%x\n" ,
                   1001:                FDCTrackRegister , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                   1002: 
                   1003:        Log_Printf(LOG_TODO, "FDC type III command 'read track' does not work yet!\n");
1.1.1.5   root     1004: 
1.1.1.6   root     1005:        /* FIXME: "Read track" should read more than only the sectors! (also sector headers, gaps, etc.) */
1.1.1.5   root     1006: 
1.1.1.6   root     1007:        /* Set emulation to read a single track */
                   1008:        FDCEmulationCommand = FDCEMU_CMD_READSECTORS;
                   1009:        FDCEmulationRunning = FDCEMU_RUN_READSECTORS_READDATA;
                   1010:        /* Set reading parameters */
                   1011:        FDC_SetReadWriteParameters(nReadWriteSectorsPerTrack);  /* Read whole track */
1.1       root     1012: 
1.1.1.7   root     1013:        FDC_SetDiskControllerStatus();
1.1       root     1014: }
                   1015: 
1.1.1.2   root     1016: 
                   1017: /*-----------------------------------------------------------------------*/
1.1.1.5   root     1018: static void FDC_TypeIII_WriteTrack(void)
1.1       root     1019: {
1.1.1.10  root     1020:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type III write track 0x%x VBL=%d video_cyc=%d pc=%x\n" ,
                   1021:                FDCTrackRegister , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                   1022: 
                   1023:        Log_Printf(LOG_TODO, "FDC type III command 'write track' does not work yet!\n");
1.1.1.5   root     1024: 
1.1.1.6   root     1025:        /* FIXME: "Write track" not only writes the sectors! (also sector headers, gaps, etc.) */
1.1.1.5   root     1026: 
1.1.1.6   root     1027:        /* Set emulation to write a single track */
                   1028:        FDCEmulationCommand = FDCEMU_CMD_WRITESECTORS;
                   1029:        FDCEmulationRunning = FDCEMU_RUN_WRITESECTORS_WRITEDATA;
                   1030:        /* Set writing parameters */
                   1031:        FDC_SetReadWriteParameters(nReadWriteSectorsPerTrack);  /* Write whole track */
1.1       root     1032: 
1.1.1.7   root     1033:        FDC_SetDiskControllerStatus();
1.1       root     1034: }
                   1035: 
1.1.1.2   root     1036: 
                   1037: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1038: /**
                   1039:  * Type IV Commands
                   1040:  *
                   1041:  * Force Interrupt
                   1042:  */
1.1       root     1043: 
1.1.1.2   root     1044: 
                   1045: /*-----------------------------------------------------------------------*/
1.1.1.10  root     1046: static void FDC_TypeIV_ForceInterrupt(bool bCauseCPUInterrupt)
1.1       root     1047: {
1.1.1.10  root     1048:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc type IV force int VBL=%d video_cyc=%d pc=%x\n" ,
                   1049:                nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
                   1050: 
1.1.1.6   root     1051:        /* Acknowledge interrupt, move along there's nothing more to see */
                   1052:        if (bCauseCPUInterrupt)
                   1053:                FDC_AcknowledgeInterrupt();
                   1054: 
                   1055:        /* Reset FDC */
                   1056:        FDCEmulationCommand = FDCEMU_CMD_NULL;
                   1057:        FDCEmulationRunning = FDCEMU_RUN_NULL;
1.1       root     1058: }
                   1059: 
1.1.1.2   root     1060: 
                   1061: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1062: /**
                   1063:  * Execute Type I commands
                   1064:  */
1.1.1.5   root     1065: static void FDC_ExecuteTypeICommands(void)
1.1       root     1066: {
1.1.1.6   root     1067:        MFP_GPIP |= 0x20;
1.1       root     1068: 
1.1.1.6   root     1069:        /* Check Type I Command */
                   1070:        switch(FDCCommandRegister&0xf0)
                   1071:        {
                   1072:         case 0x00:             /* Restore */
                   1073:                FDC_TypeI_Restore();
                   1074:                break;
                   1075:         case 0x10:             /* Seek */
                   1076:                FDC_TypeI_Seek();
                   1077:                break;
                   1078:         case 0x20:             /* Step */
                   1079:         case 0x30:
                   1080:                FDC_TypeI_Step();
                   1081:                break;
                   1082:         case 0x40:             /* Step-In */
                   1083:         case 0x50:
                   1084:                FDC_TypeI_StepIn();
                   1085:                break;
                   1086:         case 0x60:             /* Step-Out */
                   1087:         case 0x70:
                   1088:                FDC_TypeI_StepOut();
                   1089:                break;
                   1090:        }
1.1       root     1091: 
1.1.1.6   root     1092:        /* Signal motor on as we need to execute command */
                   1093:        FDC_TurnMotorOn();
1.1       root     1094: }
                   1095: 
1.1.1.2   root     1096: 
                   1097: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1098: /**
                   1099:  * Execute Type II commands
                   1100:  */
1.1.1.5   root     1101: static void FDC_ExecuteTypeIICommands(void)
1.1       root     1102: {
1.1.1.6   root     1103:        MFP_GPIP |= 0x20;
1.1       root     1104: 
1.1.1.6   root     1105:        /* Check Type II Command */
                   1106:        switch(FDCCommandRegister&0xf0)
                   1107:        {
                   1108:         case 0x80:             /* Read Sector */
                   1109:                FDC_TypeII_ReadSector();
                   1110:                break;
                   1111:         case 0x90:             /* Read Sectors */
                   1112:                FDC_TypeII_ReadMultipleSectors();
                   1113:                break;
                   1114:         case 0xa0:             /* Write Sector */
                   1115:                FDC_TypeII_WriteSector();
                   1116:                break;
                   1117:         case 0xb0:             /* Write Sectors */
                   1118:                FDC_TypeII_WriteMultipleSectors();
                   1119:                break;
                   1120:        }
1.1       root     1121: 
1.1.1.6   root     1122:        /* Signal motor on as we need to execute command */
                   1123:        FDC_TurnMotorOn();
1.1       root     1124: }
                   1125: 
1.1.1.2   root     1126: 
                   1127: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1128: /**
                   1129:  * Execute Type III commands
                   1130:  */
1.1.1.5   root     1131: static void FDC_ExecuteTypeIIICommands(void)
1.1       root     1132: {
1.1.1.6   root     1133:        MFP_GPIP |= 0x20;
1.1       root     1134: 
1.1.1.6   root     1135:        /* Check Type III Command */
                   1136:        switch(FDCCommandRegister&0xf0)
                   1137:        {
                   1138:         case 0xc0:             /* Read Address */
                   1139:                FDC_TypeIII_ReadAddress();
                   1140:                break;
                   1141:         case 0xe0:             /* Read Track */
                   1142:                FDC_TypeIII_ReadTrack();
                   1143:                break;
                   1144:         case 0xf0:             /* Write Track */
                   1145:                FDC_TypeIII_WriteTrack();
                   1146:                break;
                   1147:        }
1.1       root     1148: 
1.1.1.6   root     1149:        /* Signal motor on as we need to execute command */
                   1150:        FDC_TurnMotorOn();
1.1       root     1151: }
                   1152: 
1.1.1.2   root     1153: 
                   1154: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1155: /**
                   1156:  * Execute Type IV commands
                   1157:  */
1.1.1.5   root     1158: static void FDC_ExecuteTypeIVCommands(void)
1.1       root     1159: {
1.1.1.6   root     1160:        if (FDCCommandRegister!=0xD8)           /* Is an 'immediate interrupt command'? don't reset interrupt */
                   1161:                MFP_GPIP |= 0x20;
1.1       root     1162: 
1.1.1.6   root     1163:        /* Check Type IV Command */
                   1164:        if ((FDCCommandRegister&0x0c) == 0)     /* I3 and I2 are clear? If so we don't need a CPU interrupt */
                   1165:                FDC_TypeIV_ForceInterrupt(FALSE);   /* Force Interrupt - no interrupt */
                   1166:        else
                   1167:                FDC_TypeIV_ForceInterrupt(TRUE);    /* Force Interrupt */
1.1       root     1168: }
                   1169: 
1.1.1.2   root     1170: 
                   1171: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1172: /**
                   1173:  * Find FDC command type and execute
                   1174:  */
1.1.1.5   root     1175: static void FDC_ExecuteCommand(void)
1.1       root     1176: {
1.1.1.6   root     1177:        /* Check type of command and execute */
                   1178:        if ((FDCCommandRegister&0x80) == 0)           /* Type I - Restore,Seek,Step,Step-In,Step-Out */
                   1179:                FDC_ExecuteTypeICommands();
                   1180:        else if ((FDCCommandRegister&0x40) == 0)      /* Type II - Read Sector, Write Sector */
                   1181:                FDC_ExecuteTypeIICommands();
                   1182:        else if ((FDCCommandRegister&0xf0) != 0xd0)   /* Type III - Read Address, Read Track, Write Track */
                   1183:                FDC_ExecuteTypeIIICommands();
                   1184:        else                                          /* Type IV - Force Interrupt */
                   1185:                FDC_ExecuteTypeIVCommands();
1.1.1.9   root     1186: 
                   1187:        Int_AddAbsoluteInterrupt(FDC_DELAY_CYCLES,  INT_CPU_CYCLE, INTERRUPT_FDC);
1.1       root     1188: }
                   1189: 
1.1.1.2   root     1190: 
                   1191: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1192: /**
                   1193:  * Write to SectorCount register (WR 0xff8604)
                   1194:  */
1.1.1.5   root     1195: static void FDC_WriteSectorCountRegister(void)
1.1       root     1196: {
1.1.1.10  root     1197:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc write 8604 sector count=0x%x VBL=%d video_cyc=%d pc=%x\n" ,
                   1198:                DiskControllerWord_ff8604wr , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
1.1.1.9   root     1199: 
1.1.1.7   root     1200:        FDCSectorCountRegister = DiskControllerWord_ff8604wr;
1.1       root     1201: }
                   1202: 
1.1.1.2   root     1203: 
                   1204: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1205: /**
                   1206:  * Write to Command register (WR 0xff8604)
                   1207:  */
1.1.1.5   root     1208: static void FDC_WriteCommandRegister(void)
1.1       root     1209: {
1.1.1.10  root     1210:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc write 8604 command=0x%x VBL=%d video_cyc=%d pc=%x\n" ,
                   1211:                DiskControllerWord_ff8604wr , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
1.1.1.9   root     1212: 
1.1.1.7   root     1213:        FDCCommandRegister = DiskControllerWord_ff8604wr;
1.1.1.6   root     1214:        /* And execute */
                   1215:        FDC_ExecuteCommand();
1.1       root     1216: }
                   1217: 
1.1.1.2   root     1218: 
                   1219: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1220: /**
                   1221:  * Write to Track register (WR 0xff8604)
                   1222:  */
1.1.1.5   root     1223: static void FDC_WriteTrackRegister(void)
1.1       root     1224: {
1.1.1.10  root     1225:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc write 8604 track=0x%x VBL=%d video_cyc=%d pc=%x\n" ,
                   1226:                DiskControllerWord_ff8604wr , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
1.1.1.9   root     1227: 
1.1.1.10  root     1228:        FDCTrackRegister = DiskControllerWord_ff8604wr & 0xff;  /* 0...79 */
1.1       root     1229: }
                   1230: 
1.1.1.2   root     1231: 
                   1232: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1233: /**
                   1234:  * Write to Track register (WR 0xff8604)
                   1235:  */
1.1.1.5   root     1236: static void FDC_WriteSectorRegister(void)
1.1       root     1237: {
1.1.1.10  root     1238:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc write 8604 sector=0x%x VBL=%d video_cyc=%d pc=%x\n" ,
                   1239:                DiskControllerWord_ff8604wr , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
1.1.1.9   root     1240: 
1.1.1.10  root     1241:        FDCSectorRegister = DiskControllerWord_ff8604wr & 0xff; /* 1,2,3..... */
1.1       root     1242: }
                   1243: 
1.1.1.2   root     1244: 
                   1245: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1246: /**
                   1247:  * Write to Data register (WR 0xff8604)
                   1248:  */
1.1.1.5   root     1249: static void FDC_WriteDataRegister(void)
1.1       root     1250: {
1.1.1.10  root     1251:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc write 8604 data=0x%x VBL=%d video_cyc=%d pc=%x\n" ,
                   1252:                DiskControllerWord_ff8604wr , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
1.1.1.9   root     1253: 
1.1.1.10  root     1254:        FDCDataRegister = DiskControllerWord_ff8604wr & 0xff;
1.1       root     1255: }
                   1256: 
1.1.1.2   root     1257: 
                   1258: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1259: /**
                   1260:  * Store byte in FDC registers, when write to 0xff8604
                   1261:  */
1.1.1.7   root     1262: void FDC_DiskController_WriteWord(void)
1.1       root     1263: {
1.1.1.6   root     1264:        if (nIoMemAccessSize == SIZE_BYTE)
                   1265:        {
                   1266:                /* This register does not like to be accessed in byte mode on a normal ST */
1.1.1.8   root     1267:                M68000_BusError(IoAccessBaseAddress, BUS_ERROR_WRITE);
1.1.1.6   root     1268:                return;
                   1269:        }
                   1270: 
1.1.1.8   root     1271:        M68000_WaitState(4);
                   1272: 
1.1.1.7   root     1273:        DiskControllerWord_ff8604wr = IoMem_ReadWord(0xff8604);
1.1.1.6   root     1274: 
1.1.1.10  root     1275:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc write 8604 data=0x%x VBL=%d video_cyc=%d pc=%x\n" ,
                   1276:                DiskControllerWord_ff8604wr , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
1.1.1.9   root     1277: 
1.1.1.6   root     1278:        HDC_WriteCommandPacket();                 /*  Handle HDC functions */
                   1279: 
                   1280:        /* filter hdc commands */
1.1.1.8   root     1281:        if ((DMAModeControl_ff8606wr & 0x0018) == 8)
1.1.1.10  root     1282:                return;
1.1.1.6   root     1283: 
                   1284:        /* Are we trying to set the SectorCount? */
                   1285:        if (DMAModeControl_ff8606wr&0x10)         /* Bit 4 */
                   1286:                FDC_WriteSectorCountRegister();
                   1287:        else
1.1.1.8   root     1288:        {
                   1289:                /* Write to FDC registers */
1.1.1.6   root     1290:                switch(DMAModeControl_ff8606wr&0x6)
                   1291:                {   /* Bits 1,2 (A1,A0) */
                   1292:                 case 0x0:                            /* 0 0 - Command register */
                   1293:                        FDC_WriteCommandRegister();
                   1294:                        break;
                   1295:                 case 0x2:                            /* 0 1 - Track register */
                   1296:                        FDC_WriteTrackRegister();
                   1297:                        break;
                   1298:                 case 0x4:                            /* 1 0 - Sector register */
                   1299:                        FDC_WriteSectorRegister();
                   1300:                        break;
                   1301:                 case 0x6:                            /* 1 1 - Data register */
                   1302:                        FDC_WriteDataRegister();
                   1303:                        break;
                   1304:                }
                   1305:        }
1.1       root     1306: }
                   1307: 
1.1.1.2   root     1308: 
                   1309: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1310: /**
                   1311:  * Read Status/FDC registers, when read from 0xff8604
                   1312:  * Return 'DiskControllerByte'
                   1313:  */
1.1.1.7   root     1314: void FDC_DiskControllerStatus_ReadWord(void)
1.1       root     1315: {
1.1.1.7   root     1316:        Sint16 DiskControllerByte = 0;            /* Used to pass back the parameter */
1.1.1.6   root     1317: 
                   1318:        if (nIoMemAccessSize == SIZE_BYTE)
                   1319:        {
                   1320:                /* This register does not like to be accessed in byte mode on a normal ST */
1.1.1.8   root     1321:                M68000_BusError(IoAccessBaseAddress, BUS_ERROR_READ);
1.1.1.6   root     1322:                return;
                   1323:        }
                   1324: 
1.1.1.8   root     1325:        M68000_WaitState(4);
                   1326: 
                   1327:        if ((DMAModeControl_ff8606wr & 0x18) == 0x08)     /* HDC status reg selected? */
1.1.1.6   root     1328:        {
                   1329:                /* return the HDC status reg */
1.1.1.7   root     1330:                DiskControllerByte = HDCCommand.returnCode;
1.1.1.6   root     1331:        }
1.1.1.8   root     1332:        else if ((DMAModeControl_ff8606wr & 0x18) == 0x18)  /* HDC sector counter??? */
                   1333:        {
                   1334:                Log_Printf(LOG_DEBUG, "*** Read HDC sector counter???\n");
                   1335:                DiskControllerByte = HDCSectorCount;
                   1336:        }
1.1.1.6   root     1337:        else
                   1338:        {
                   1339:                /* old FDC code */
                   1340:                switch (DMAModeControl_ff8606wr&0x6)      /* Bits 1,2 (A1,A0) */
                   1341:                {
                   1342:                 case 0x0:                               /* 0 0 - Status register */
1.1.1.7   root     1343:                        DiskControllerByte = DiskControllerStatus_ff8604rd;
1.1.1.6   root     1344:                        if (bMotorOn)
1.1.1.7   root     1345:                                DiskControllerByte |= 0x80;
1.1.1.6   root     1346: 
                   1347:                        if (Floppy_IsWriteProtected(nReadWriteDev))
1.1.1.7   root     1348:                                DiskControllerByte |= 0x40;
1.1.1.6   root     1349: 
                   1350:                        if (EmulationDrives[nReadWriteDev].bMediaChanged)
                   1351:                        {
                   1352:                                /* Some games apparently poll the write-protection signal to check
                   1353:                                 * for disk image changes (the signal seems to change when you
                   1354:                                 * exchange disks on a real ST). We now also simulate this behaviour
                   1355:                                 * here, so that these games can continue with the other disk. */
1.1.1.7   root     1356:                                DiskControllerByte ^= 0x40;
1.1.1.6   root     1357:                                EmulationDrives[nReadWriteDev].bMediaChanged = FALSE;
                   1358:                        }
                   1359: 
                   1360:                        /* Reset FDC GPIP */
                   1361:                        MFP_GPIP |= 0x20;
                   1362:                        break;
                   1363:                 case 0x2:                               /* 0 1 - Track register */
1.1.1.7   root     1364:                        DiskControllerByte = FDCTrackRegister;
1.1.1.6   root     1365:                        break;
                   1366:                 case 0x4:                               /* 1 0 - Sector register */
1.1.1.7   root     1367:                        DiskControllerByte = FDCSectorRegister;
1.1.1.6   root     1368:                        break;
                   1369:                 case 0x6:                               /* 1 1 - Data register */
1.1.1.7   root     1370:                        DiskControllerByte = FDCDataRegister;
1.1.1.6   root     1371:                        break;
                   1372:                }
                   1373:        }
                   1374: 
1.1.1.7   root     1375:        IoMem_WriteWord(0xff8604, DiskControllerByte);
1.1.1.9   root     1376: 
1.1.1.10  root     1377:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc read 8604 ctrl status=0x%x VBL=%d video_cyc=%d pc=%x\n" ,
                   1378:                DiskControllerByte , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
1.1       root     1379: }
                   1380: 
1.1.1.2   root     1381: 
                   1382: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1383: /**
                   1384:  * Read DMA address from ST's RAM (always up-to-date)
                   1385:  */
1.1.1.6   root     1386: Uint32 FDC_ReadDMAAddress(void)
1.1       root     1387: {
1.1.1.6   root     1388:        Uint32 Address;
1.1       root     1389: 
1.1.1.6   root     1390:        /* Build up 24-bit address from hardware registers */
                   1391:        Address = ((Uint32)STMemory_ReadByte(0xff8609)<<16) | ((Uint32)STMemory_ReadByte(0xff860b)<<8) | (Uint32)STMemory_ReadByte(0xff860d);
1.1       root     1392: 
1.1.1.6   root     1393:        return Address;
1.1       root     1394: }
                   1395: 
1.1.1.2   root     1396: 
                   1397: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1398: /**
                   1399:  * Write DMA address to ST's RAM(always keep up-to-date)
                   1400:  */
1.1.1.6   root     1401: void FDC_WriteDMAAddress(Uint32 Address)
1.1       root     1402: {
1.1.1.10  root     1403:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc write 0x%x to dma address VBL=%d video_cyc=%d pc=%x\n" ,
                   1404:                Address , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
1.1.1.9   root     1405: 
1.1.1.6   root     1406:        /* Store as 24-bit address */
                   1407:        STMemory_WriteByte(0xff8609, Address>>16);
                   1408:        STMemory_WriteByte(0xff860b, Address>>8);
                   1409:        STMemory_WriteByte(0xff860d, Address);
1.1       root     1410: }
                   1411: 
1.1.1.2   root     1412: 
                   1413: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1414: /**
                   1415:  * Read sector from floppy drive into workspace
                   1416:  * We copy the bytes in chunks to simulate reading of the floppy using DMA
                   1417:  */
1.1.1.10  root     1418: bool FDC_ReadSectorFromFloppy(void)
1.1       root     1419: {
1.1.1.10  root     1420:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc read sector addr=0x%x dev=%d sect=%d track=%d side=%d VBL=%d video_cyc=%d pc=%x\n" ,
                   1421:                FDC_ReadDMAAddress(), nReadWriteDev, nReadWriteSector, nReadWriteTrack, nReadWriteSide, nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
1.1.1.9   root     1422: 
1.1.1.6   root     1423:        /* Copy in 1 sector to our workspace */
1.1.1.7   root     1424:        if (Floppy_ReadSectors(nReadWriteDev, DMASectorWorkSpace, nReadWriteSector, nReadWriteTrack, nReadWriteSide, 1, NULL))
1.1.1.6   root     1425:        {
                   1426:                /* Update reading/writing parameters */
                   1427:                nReadWriteSector++;
                   1428:                if (nReadWriteSector > nReadWriteSectorsPerTrack)   /* Advance into next track? */
                   1429:                {
                   1430:                        nReadWriteSector = 1;
                   1431:                        nReadWriteTrack++;
                   1432:                }
                   1433:                return TRUE;
                   1434:        }
1.1       root     1435: 
1.1.1.6   root     1436:        /* Failed */
1.1.1.9   root     1437:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc read sector failed\n" );
1.1.1.6   root     1438:        return FALSE;
1.1       root     1439: }
                   1440: 
1.1.1.2   root     1441: 
                   1442: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1443: /**
                   1444:  * Write sector from workspace to floppy drive
                   1445:  * We copy the bytes in chunks to simulate writing of the floppy using DMA
                   1446:  */
1.1.1.10  root     1447: bool FDC_WriteSectorFromFloppy(void)
1.1       root     1448: {
1.1.1.6   root     1449:        Uint32 Address;
1.1       root     1450: 
1.1.1.6   root     1451:        /* Get DMA address */
                   1452:        Address = FDC_ReadDMAAddress();
1.1       root     1453: 
1.1.1.10  root     1454:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc write sector addr=0x%x dev=%d sect=%d track=%d side=%d VBL=%d video_cyc=%d pc=%x\n" ,
                   1455:                Address, nReadWriteDev, nReadWriteSector, nReadWriteTrack, nReadWriteSide, nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
1.1.1.9   root     1456: 
1.1.1.6   root     1457:        /* Write out 1 sector from our workspace */
                   1458:        if (Floppy_WriteSectors(nReadWriteDev, &STRam[Address], nReadWriteSector, nReadWriteTrack, nReadWriteSide, 1, NULL))
                   1459:        {
                   1460:                /* Update reading/writing parameters */
                   1461:                nReadWriteSector++;
                   1462:                if (nReadWriteSector > nReadWriteSectorsPerTrack)   /* Advance to next track? */
                   1463:                {
                   1464:                        nReadWriteSector = 1;
                   1465:                        nReadWriteTrack++;
                   1466:                }
                   1467:                return TRUE;
                   1468:        }
1.1       root     1469: 
1.1.1.6   root     1470:        /* Failed */
1.1.1.9   root     1471:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc write sector failed\n" );
1.1.1.6   root     1472:        return FALSE;
1.1       root     1473: }
                   1474: 
                   1475: 
1.1.1.2   root     1476: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1477: /**
                   1478:  * Copy data from DMA workspace into ST RAM
                   1479:  */
1.1       root     1480: void FDC_DMADataFromFloppy(void)
                   1481: {
1.1.1.6   root     1482:        /* Copy data to DMA address */
                   1483:        memcpy(&STRam[FDC_ReadDMAAddress()], DMASectorWorkSpace, NUMBYTESPERSECTOR );
1.1       root     1484: 
1.1.1.6   root     1485:        /* Update DMA pointer */
                   1486:        FDC_WriteDMAAddress(FDC_ReadDMAAddress()+NUMBYTESPERSECTOR);
1.1       root     1487: }
                   1488: 
                   1489: 
1.1.1.2   root     1490: /*-----------------------------------------------------------------------*/
1.1.1.9   root     1491: /**
                   1492:  * Write word to 0xff8606 (DMA Mode Control)
1.1.1.10  root     1493:  *
1.1.1.9   root     1494:  * Eg.
                   1495:  * $80 - Selects command/status register
                   1496:  * $82 - Selects track register
                   1497:  * $84 - Selects sector register
                   1498:  * $86 - Selects data regsiter
                   1499:  * NOTE - OR above values with $100 is transfer from memory to floppy
                   1500:  * Also if bit 4 is set, write to sector count register
                   1501:  */
1.1.1.6   root     1502: void FDC_DmaModeControl_WriteWord(void)
1.1       root     1503: {
1.1.1.6   root     1504:        Uint16 DMAModeControl_ff8606wr_prev;                     /* stores previous write to 0xff8606 for 'toggle' checks */
1.1       root     1505: 
1.1.1.6   root     1506:        if (nIoMemAccessSize == SIZE_BYTE)
                   1507:        {
                   1508:                /* This register does not like to be accessed in byte mode on a normal ST */
1.1.1.8   root     1509:                M68000_BusError(IoAccessBaseAddress, BUS_ERROR_WRITE);
1.1.1.6   root     1510:                return;
                   1511:        }
                   1512: 
                   1513:        DMAModeControl_ff8606wr_prev = DMAModeControl_ff8606wr;  /* Store previous to check for _read/_write toggle (DMA reset) */
                   1514:        DMAModeControl_ff8606wr = IoMem_ReadWord(0xff8606);      /* Store to DMA Mode control */
                   1515: 
1.1.1.10  root     1516:        HATARI_TRACE ( HATARI_TRACE_FDC , "fdc write 8606 ctrl=0x%x VBL=%d video_cyc=%d pc=%x\n" ,
                   1517:                DMAModeControl_ff8606wr , nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , M68000_GetPC() );
1.1.1.9   root     1518: 
1.1.1.6   root     1519:        /* When write to 0xff8606, check bit '8' toggle. This causes DMA status reset */
                   1520:        if ((DMAModeControl_ff8606wr_prev ^ DMAModeControl_ff8606wr) & 0x0100)
                   1521:                FDC_ResetDMAStatus();
                   1522: }
1.1.1.9   root     1523: 
                   1524: 
                   1525: /*-----------------------------------------------------------------------*/
                   1526: /**
                   1527:  * Write to floppy mode/control (?) register (0xff860F).
                   1528:  * Used on Falcon only!
                   1529:  * FIXME: I've found hardly any documentation about this register, only
                   1530:  * the following description of the bits:
                   1531:  *
                   1532:  *   __________54__10  Floppy Controll-Register
                   1533:  *             ||  ||
                   1534:  *             ||  |+- Prescaler 1
                   1535:  *             ||  +-- Media detect 1
                   1536:  *             |+----- Prescaler 2
                   1537:  *             +------ Media detect 2
                   1538:  *
                   1539:  * For DD - disks:  0x00
                   1540:  * For HD - disks:  0x03
                   1541:  * for ED - disks:  0x30 (not supported by TOS)
                   1542:  */
                   1543: void FDC_FloppyMode_WriteByte(void)
                   1544: {
                   1545:        // printf("Write to floppy mode reg.: 0x%02x\n", IoMem_ReadByte(0xff860f));
                   1546: }
                   1547: 
                   1548: 
                   1549: /*-----------------------------------------------------------------------*/
                   1550: /**
                   1551:  * Read from floppy mode/control (?) register (0xff860F).
                   1552:  * Used on Falcon only!
                   1553:  * FIXME: I've found hardly any documentation about this register, only
                   1554:  * the following description of the bits:
                   1555:  *
                   1556:  *   ________76543210  Floppy Controll-Register
                   1557:  *           ||||||||
                   1558:  *           |||||||+- Prescaler 1
                   1559:  *           ||||||+-- Mode select 1
                   1560:  *           |||||+--- Media detect 1
                   1561:  *           ||||+---- accessed during DMA transfers (?)
                   1562:  *           |||+----- Prescaler 2
                   1563:  *           ||+------ Mode select 2
                   1564:  *           |+------- Media detect 2
                   1565:  *           +-------- Disk changed
                   1566:  */
                   1567: void FDC_FloppyMode_ReadByte(void)
                   1568: {
                   1569:        IoMem_WriteByte(0xff860f, 0x80);  // FIXME: Is this ok?
                   1570:        // printf("Read from floppy mode reg.: 0x%02x\n", IoMem_ReadByte(0xff860f));
                   1571: }

unix.superglobalmegacorp.com

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