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

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

unix.superglobalmegacorp.com

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