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

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

unix.superglobalmegacorp.com

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