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

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.6 ! root        7:   Floppy Disc Controller(FDC) emulation. We need to simulate the movement of
        !             8:   the head of the floppy disc drive to accurately perform the FDC commands,
        !             9:   such as 'Step'. The is important for ST demo disc images. We have to go
        !            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
        !            12:   checked each HBL to perform the transfer of data from our disc image into
        !            13:   the ST RAM area by simulating the DMA.
1.1       root       14: */
1.1.1.6 ! root       15: char FDC_rcsid[] = "Hatari $Id: fdc.c,v 1.19 2005/04/07 10:15:01 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: /*
                     34:   Floppy Disc Controller
                     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: 
                     73: ACSI DMA and Floppy Disc Controller(FDC)
                     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
        !           117:   through to read/write disc sector code. We have full documents on 1772 FDC,
        !           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
        !           120:   easy as a lot of information can be ignored as we are using disc images and
        !           121:   not actual discs. We do NOT support the reading of the PC's A: drive - newer
        !           122:   PC's cannot read an ST single sided disc, ST discs are very old and so are
        !           123:   dirty which gets onto the PC drive heads and ruins them and also support for
        !           124:   disc sector access under the various modern operating systems is not so easy
        !           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: 
                    134: short int FDCSectorCountRegister;
                    135: 
1.1.1.6 ! root      136: Uint16 DiscControllerWord_ff8604wr;                             /* 0xff8604 (write) */
        !           137: static Uint16 DiscControllerStatus_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: 
                    142: static unsigned short int FDCCommandRegister;
                    143: static short int FDCTrackRegister,FDCSectorRegister,FDCDataRegister;
                    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: 
                    158: static unsigned char 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 */
        !           168:        DiscControllerStatus_ff8604rd = 0;
        !           169:        DiscControllerWord_ff8604wr = 0;
        !           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 */
        !           196:        MemorySnapShot_Store(&DiscControllerStatus_ff8604rd, sizeof(DiscControllerStatus_ff8604rd));
        !           197:        MemorySnapShot_Store(&DiscControllerWord_ff8604wr, sizeof(DiscControllerWord_ff8604wr));
        !           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.5   root      327: static void FDC_UpdateDiscDrive(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.6 ! root      332:        if (EmulationDrives[nReadWriteDev].bDiscInserted)
        !           333:                Floppy_FindDiscDetails(EmulationDrives[nReadWriteDev].pBuffer,EmulationDrives[nReadWriteDev].nImageBytes,&nReadWriteSectorsPerTrack,NULL);
1.1       root      334: }
                    335: 
1.1.1.2   root      336: 
                    337: /*-----------------------------------------------------------------------*/
1.1       root      338: /*
                    339:   Set disc controller status (RD 0xff8604)
                    340: */
1.1.1.5   root      341: static void FDC_SetDiscControllerStatus(void)
1.1       root      342: {
1.1.1.6 ! root      343:        /* Update disc */
        !           344:        FDC_UpdateDiscDrive();
1.1       root      345: 
1.1.1.6 ! root      346:        /* Clear out to default */
        !           347:        DiscControllerStatus_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)
        !           354:                        DiscControllerStatus_ff8604rd |= 0x4;    /* Bit 2 - Track Zero, '0' if head is NOT at zero */
        !           355:        }
        !           356: 
        !           357:        /* If no disc inserted, tag as error */
        !           358:        if (!EmulationDrives[nReadWriteDev].bDiscInserted)
        !           359:                DiscControllerStatus_ff8604rd |= 0x10;     /* RNF - Record not found, ie no disc 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: /*
                    395:   Copy parameters for disc sector/s read/write
                    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;
        !           404:        /* Update disc */
        !           405:        FDC_UpdateDiscDrive();
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
        !           424:                        nDelayHBLs = 300;
        !           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: 
        !           471:                /* Set disc controller status (RD 0xff8604) */
        !           472:                FDC_SetDiscControllerStatus();
        !           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.6 ! root      752:        FDC_SetDiscControllerStatus();
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.6 ! root      763:        FDC_SetDiscControllerStatus();
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.6 ! root      774:        FDC_SetDiscControllerStatus();
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.6 ! root      786:        FDC_SetDiscControllerStatus();
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.6 ! root      798:        FDC_SetDiscControllerStatus();
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.6 ! root      819:        FDC_SetDiscControllerStatus();
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.6 ! root      832:        FDC_SetDiscControllerStatus();
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.6 ! root      845:        FDC_SetDiscControllerStatus();
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.6 ! root      858:        FDC_SetDiscControllerStatus();
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.6 ! root      890:        FDC_SetDiscControllerStatus();
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.6 ! root      907:        FDC_SetDiscControllerStatus();
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.6 ! root     1066:        FDCSectorCountRegister = DiscControllerWord_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.6 ! root     1076:        FDCCommandRegister = DiscControllerWord_ff8604wr;
        !          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.6 ! root     1088:        FDCTrackRegister = DiscControllerWord_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.6 ! root     1098:        FDCSectorRegister = DiscControllerWord_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.6 ! root     1108:        FDCDataRegister = DiscControllerWord_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.6 ! root     1116: void FDC_DiscController_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: 
        !          1125:        DiscControllerWord_ff8604wr = IoMem_ReadWord(0xff8604);
        !          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
                   1160:   Return 'DiscControllerByte'
                   1161: */
1.1.1.6 ! root     1162: void FDC_DiscControllerStatus_ReadWord(void)
1.1       root     1163: {
1.1.1.6 ! root     1164:        Sint16 DiscControllerByte = 0;            /* Used to pass parameter back to assembler */
        !          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 */
        !          1176:                DiscControllerByte = HDCCommand.returnCode;
        !          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 */
        !          1184:                        DiscControllerByte = DiscControllerStatus_ff8604rd;
        !          1185:                        if (bMotorOn)
        !          1186:                                DiscControllerByte |= 0x80;
        !          1187: 
        !          1188:                        if (Floppy_IsWriteProtected(nReadWriteDev))
        !          1189:                                DiscControllerByte |= 0x40;
        !          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. */
        !          1197:                                DiscControllerByte ^= 0x40;
        !          1198:                                EmulationDrives[nReadWriteDev].bMediaChanged = FALSE;
        !          1199:                        }
        !          1200: 
        !          1201:                        /* Reset FDC GPIP */
        !          1202:                        MFP_GPIP |= 0x20;
        !          1203:                        break;
        !          1204:                 case 0x2:                               /* 0 1 - Track register */
        !          1205:                        DiscControllerByte = FDCTrackRegister;
        !          1206:                        break;
        !          1207:                 case 0x4:                               /* 1 0 - Sector register */
        !          1208:                        DiscControllerByte = FDCSectorRegister;
        !          1209:                        break;
        !          1210:                 case 0x6:                               /* 1 1 - Data register */
        !          1211:                        DiscControllerByte = FDCDataRegister;
        !          1212:                        break;
        !          1213:                }
        !          1214:        }
        !          1215: 
        !          1216:        IoMem_WriteWord(0xff8604, DiscControllerByte);
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 */
        !          1256:        if (Floppy_ReadSectors(nReadWriteDev,(char *)DMASectorWorkSpace,nReadWriteSector,nReadWriteTrack,nReadWriteSide,1,NULL))
        !          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.