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

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

unix.superglobalmegacorp.com

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