|
|
1.1 ! root 1: /* ! 2: Hatari - floppy_ipf.c ! 3: ! 4: This file is distributed under the GNU General Public License, version 2 or at ! 5: your option any later version. Read the file gpl.txt for details. ! 6: ! 7: IPF disk image support. ! 8: ! 9: IPF files are handled using the capsimage library, which emulates the FDC ! 10: at low level and allows to read complex protections. ! 11: ! 12: RAW files made with KryoFlux board or CT RAW dumped with an Amiga are also handled ! 13: by the capsimage library. ! 14: */ ! 15: const char floppy_ipf_fileid[] = "Hatari floppy_ipf.c : " __DATE__ " " __TIME__; ! 16: ! 17: #include "main.h" ! 18: #include "file.h" ! 19: #include "floppy.h" ! 20: #include "floppy_ipf.h" ! 21: #include "fdc.h" ! 22: #include "log.h" ! 23: #include "memorySnapShot.h" ! 24: #include "screen.h" ! 25: #include "video.h" ! 26: #include "cycles.h" ! 27: ! 28: #ifdef HAVE_CAPSIMAGE ! 29: #if CAPSIMAGE_VERSION == 5 ! 30: #include <caps5/CapsLibAll.h> ! 31: #else ! 32: #include <caps/fdc.h> ! 33: #define CAPS_LIB_RELEASE 4 ! 34: #define CAPS_LIB_REVISION 2 ! 35: #endif ! 36: /* Macro to check release and revision */ ! 37: #define CAPS_LIB_REL_REV ( CAPS_LIB_RELEASE * 100 + CAPS_LIB_REVISION ) ! 38: #endif ! 39: ! 40: ! 41: typedef struct ! 42: { ! 43: #ifdef HAVE_CAPSIMAGE ! 44: Uint32 CapsLibRelease; ! 45: Uint32 CapsLibRevision; ! 46: ! 47: struct CapsFdc Fdc; /* Fdc state */ ! 48: struct CapsDrive Drive[ MAX_FLOPPYDRIVES ]; /* Physical drives */ ! 49: CapsLong CapsImage[ MAX_FLOPPYDRIVES ]; /* For the IPF disk images */ ! 50: ! 51: int Rev_Track[ MAX_FLOPPYDRIVES ]; /* Needed to handle CAPSSetRevolution for type II/III commands */ ! 52: int Rev_Side[ MAX_FLOPPYDRIVES ]; ! 53: ! 54: bool DriveEnabled[ MAX_FLOPPYDRIVES ];/* Is drive ON or OFF */ ! 55: bool DoubleSided[ MAX_FLOPPYDRIVES ];/* Is drive double sided or not */ ! 56: ! 57: Sint64 FdcClock; /* Current value of CyclesGlobalClockCounter */ ! 58: #endif ! 59: } IPF_STRUCT; ! 60: ! 61: ! 62: static IPF_STRUCT IPF_State; /* All variables related to the IPF support */ ! 63: ! 64: ! 65: #ifdef HAVE_CAPSIMAGE ! 66: static void IPF_CallBack_Trk ( struct CapsFdc *pc , CapsULong State ); ! 67: static void IPF_CallBack_Irq ( struct CapsFdc *pc , CapsULong State ); ! 68: static void IPF_CallBack_Drq ( struct CapsFdc *pc , CapsULong State ); ! 69: static void IPF_Drive_Update_Enable_Side ( void ); ! 70: #endif ! 71: ! 72: ! 73: ! 74: ! 75: /*-----------------------------------------------------------------------*/ ! 76: /** ! 77: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type) ! 78: * We must take care of whether Hatari was compiled with IPF support of not ! 79: * when saving/restoring snapshots to avoid incompatibilies. ! 80: */ ! 81: void IPF_MemorySnapShot_Capture(bool bSave) ! 82: { ! 83: int StructSize; ! 84: int Drive; ! 85: ! 86: if ( bSave ) /* Saving snapshot */ ! 87: { ! 88: StructSize = sizeof ( IPF_State ); /* 0 if HAVE_CAPSIMAGE is not defined */ ! 89: MemorySnapShot_Store(&StructSize, sizeof(StructSize)); ! 90: fprintf ( stderr , "ipf save %d\n" , StructSize ); ! 91: if ( StructSize > 0 ) ! 92: MemorySnapShot_Store(&IPF_State, sizeof(IPF_State)); ! 93: } ! 94: ! 95: else /* Restoring snapshot */ ! 96: { ! 97: MemorySnapShot_Store(&StructSize, sizeof(StructSize)); ! 98: fprintf ( stderr , "ipf load %d\n" , StructSize ); ! 99: if ( ( StructSize == 0 ) && ( sizeof ( IPF_State ) > 0 ) ) ! 100: { ! 101: Log_AlertDlg(LOG_ERROR, "This memory snapshot doesn't include IPF data but this version of Hatari was built with IPF support"); ! 102: return; /* Continue restoring the rest of the memory snapshot */ ! 103: } ! 104: else if ( ( StructSize > 0 ) && ( sizeof ( IPF_State ) == 0 ) ) ! 105: { ! 106: Log_AlertDlg(LOG_ERROR, "This memory snapshot includes IPF data but this version of Hatari was not built with IPF support"); ! 107: MemorySnapShot_Skip( StructSize ); /* Ignore the IPF data */ ! 108: return; /* Continue restoring the rest of the memory snapshot */ ! 109: } ! 110: else if ( ( StructSize > 0 ) && ( StructSize != sizeof ( IPF_State ) ) ) ! 111: { ! 112: Log_AlertDlg(LOG_ERROR, "This memory snapshot includes IPF data different from the ones handled in this version of Hatari"); ! 113: MemorySnapShot_Skip( StructSize ); /* Ignore the IPF data */ ! 114: return; /* Continue restoring the rest of the memory snapshot */ ! 115: } ! 116: ! 117: if ( StructSize > 0 ) ! 118: { ! 119: MemorySnapShot_Store(&IPF_State, sizeof(IPF_State)); ! 120: ! 121: #ifdef HAVE_CAPSIMAGE ! 122: /* For IPF structures, we need to update some pointers in Fdc/Drive/CapsImage */ ! 123: /* drive : PUBYTE trackbuf, PUDWORD timebuf */ ! 124: /* fdc : PCAPSDRIVE driveprc, PCAPSDRIVE drive, CAPSFDCHOOK callback functions */ ! 125: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , 0 ); /* Invalidate buffered track data for drive 0 */ ! 126: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , 1 ); /* Invalidate buffered track data for drive 1 */ ! 127: ! 128: IPF_State.Fdc.drive = IPF_State.Drive; /* Connect drives array to the FDC */ ! 129: if ( IPF_State.Fdc.driveprc != NULL ) /* Recompute active drive's pointer */ ! 130: IPF_State.Fdc.driveprc = IPF_State.Fdc.drive + IPF_State.Fdc.driveact; ! 131: ! 132: /* Set callback functions */ ! 133: IPF_State.Fdc.cbirq = IPF_CallBack_Irq; ! 134: IPF_State.Fdc.cbdrq = IPF_CallBack_Drq; ! 135: IPF_State.Fdc.cbtrk = IPF_CallBack_Trk; ! 136: #endif ! 137: ! 138: /* Call IPF_Insert to recompute IPF_State.CapsImage[ Drive ] */ ! 139: for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ ) ! 140: if ( EmulationDrives[Drive].ImageType == FLOPPY_IMAGE_TYPE_IPF ) ! 141: if ( IPF_Insert ( Drive , EmulationDrives[Drive].pBuffer , EmulationDrives[Drive].nImageBytes ) == false ) ! 142: { ! 143: Log_AlertDlg(LOG_ERROR, "Error restoring IPF image %s in drive %d" , ! 144: EmulationDrives[Drive].sFileName , Drive ); ! 145: return; ! 146: } ! 147: ! 148: fprintf ( stderr , "ipf load ok\n" ); ! 149: } ! 150: } ! 151: } ! 152: ! 153: ! 154: ! 155: ! 156: /*-----------------------------------------------------------------------*/ ! 157: /** ! 158: * Does filename end with a .IPF or .RAW or .CTR extension ? If so, return true. ! 159: * .RAW and .CTR support requires caps lib >= 5.1 ! 160: */ ! 161: bool IPF_FileNameIsIPF(const char *pszFileName, bool bAllowGZ) ! 162: { ! 163: return ( File_DoesFileExtensionMatch(pszFileName,".ipf" ) ! 164: || ( bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".ipf.gz") ) ! 165: #if CAPS_LIB_REL_REV >= 501 ! 166: || File_DoesFileExtensionMatch(pszFileName,".raw" ) ! 167: || ( bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".raw.gz") ) ! 168: || File_DoesFileExtensionMatch(pszFileName,".ctr" ) ! 169: || ( bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".ctr.gz") ) ! 170: #endif ! 171: ); ! 172: } ! 173: ! 174: ! 175: /*-----------------------------------------------------------------------*/ ! 176: /** ! 177: * Load .IPF file into memory, set number of bytes loaded and return a pointer ! 178: * to the buffer. ! 179: */ ! 180: Uint8 *IPF_ReadDisk(int Drive, const char *pszFileName, long *pImageSize, int *pImageType) ! 181: { ! 182: #ifndef HAVE_CAPSIMAGE ! 183: Log_AlertDlg(LOG_ERROR, "This version of Hatari was not built with IPF support, this disk image can't be handled."); ! 184: return NULL; ! 185: ! 186: #else ! 187: Uint8 *pIPFFile; ! 188: ! 189: *pImageSize = 0; ! 190: ! 191: /* Just load directly a buffer, and set ImageSize accordingly */ ! 192: pIPFFile = File_Read(pszFileName, pImageSize, NULL); ! 193: if (!pIPFFile) ! 194: { ! 195: *pImageSize = 0; ! 196: return NULL; ! 197: } ! 198: ! 199: *pImageType = FLOPPY_IMAGE_TYPE_IPF; ! 200: return pIPFFile; ! 201: #endif ! 202: } ! 203: ! 204: ! 205: /*-----------------------------------------------------------------------*/ ! 206: /** ! 207: * Save .IPF file from memory buffer. Returns true is all OK. ! 208: */ ! 209: bool IPF_WriteDisk(int Drive, const char *pszFileName, Uint8 *pBuffer, int ImageSize) ! 210: { ! 211: /* saving is not supported for IPF files */ ! 212: return false; ! 213: } ! 214: ! 215: ! 216: ! 217: ! 218: /* ! 219: * Init the FDC and the drives used to handle IPF images ! 220: */ ! 221: bool IPF_Init ( void ) ! 222: { ! 223: #ifndef HAVE_CAPSIMAGE ! 224: return true; ! 225: ! 226: #else ! 227: int i; ! 228: struct CapsVersionInfo caps_vi; ! 229: ! 230: fprintf ( stderr , "IPF : IPF_Init\n" ); ! 231: ! 232: if ( CAPSInit() != imgeOk ) ! 233: { ! 234: fprintf ( stderr , "IPF : Could not initialize the capsimage library\n" ); ! 235: return false; ! 236: } ! 237: ! 238: if ( CAPSGetVersionInfo ( &caps_vi , 0 ) != imgeOk ) ! 239: { ! 240: fprintf ( stderr , "IPF : CAPSVersionInfo failed\n" ); ! 241: return false; ! 242: } ! 243: fprintf ( stderr , "IPF : capsimage library version release=%d revision=%d\n" , (int)caps_vi.release , (int)caps_vi.revision ); ! 244: IPF_State.CapsLibRelease = caps_vi.release; ! 245: IPF_State.CapsLibRevision = caps_vi.revision; ! 246: ! 247: /* Default values for each physical drive */ ! 248: memset ( IPF_State.Drive , 0 , sizeof ( IPF_State.Drive ) ); ! 249: for ( i=0 ; i < MAX_FLOPPYDRIVES ; i++ ) ! 250: { ! 251: IPF_State.Drive[ i ].type = sizeof ( struct CapsDrive ); ! 252: IPF_State.Drive[ i ].rpm = CAPSDRIVE_35DD_RPM; ! 253: IPF_State.Drive[ i ].maxtrack = CAPSDRIVE_35DD_HST; ! 254: ! 255: IPF_State.Rev_Track[ i ] = -1; ! 256: IPF_State.Rev_Side[ i ] = -1; ! 257: ! 258: IPF_State.DriveEnabled[ i ] = true; ! 259: IPF_State.DoubleSided[ i ] = true; ! 260: } ! 261: ! 262: /* Init FDC with 2 physical drives */ ! 263: memset ( &IPF_State.Fdc , 0 , sizeof ( IPF_State.Fdc ) ); ! 264: IPF_State.Fdc.type = sizeof( struct CapsFdc ); ! 265: IPF_State.Fdc.model = cfdcmWD1772; ! 266: IPF_State.Fdc.drive = IPF_State.Drive; ! 267: IPF_State.Fdc.drivecnt = MAX_FLOPPYDRIVES; ! 268: ! 269: if ( CAPSFdcInit ( &IPF_State.Fdc ) != imgeOk) ! 270: { ! 271: fprintf ( stderr , "IPF : CAPSFdcInit failed\n" ); ! 272: return false; ! 273: } ! 274: ! 275: /* 2 drives by default */ ! 276: IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES; ! 277: /* Update drives' state in case we have some drives ON or OFF in config or parameters */ ! 278: IPF_Drive_Update_Enable_Side (); ! 279: ! 280: /* FDC clock */ ! 281: IPF_State.Fdc.clockfrq = 8000000; ! 282: ! 283: /* Set callback functions */ ! 284: IPF_State.Fdc.cbirq = IPF_CallBack_Irq; ! 285: IPF_State.Fdc.cbdrq = IPF_CallBack_Drq; ! 286: IPF_State.Fdc.cbtrk = IPF_CallBack_Trk; ! 287: ! 288: CAPSFdcReset ( &IPF_State.Fdc ); ! 289: ! 290: return true; ! 291: #endif ! 292: } ! 293: ! 294: ! 295: ! 296: ! 297: /* ! 298: * Exit ! 299: */ ! 300: void IPF_Exit ( void ) ! 301: { ! 302: #ifndef HAVE_CAPSIMAGE ! 303: #else ! 304: CAPSExit(); ! 305: #endif ! 306: } ! 307: ! 308: ! 309: ! 310: ! 311: /* ! 312: * Init the ressources to handle the IPF image inserted into a drive (0=A: 1=B:) ! 313: */ ! 314: bool IPF_Insert ( int Drive , Uint8 *pImageBuffer , long ImageSize ) ! 315: { ! 316: #ifndef HAVE_CAPSIMAGE ! 317: return false; ! 318: ! 319: #else ! 320: CapsLong ImageId; ! 321: CapsLong ImageType; ! 322: ! 323: ImageId = CAPSAddImage(); ! 324: if ( ImageId < 0 ) ! 325: { ! 326: fprintf ( stderr , "IPF : error CAPSAddImage\n" ); ! 327: return false; ! 328: } ! 329: ! 330: #if CAPS_LIB_REL_REV >= 501 ! 331: ImageType = CAPSGetImageTypeMemory ( pImageBuffer , ImageSize ); ! 332: if ( ImageType == citError ) ! 333: { ! 334: fprintf ( stderr , "IPF : error CAPSGetImageTypeMemory\n" ); ! 335: return false; ! 336: } ! 337: else if ( ImageType == citUnknown ) ! 338: { ! 339: fprintf ( stderr , "IPF : unknown image type\n" ); ! 340: return false; ! 341: } ! 342: ! 343: fprintf ( stderr , "IPF : IPF_Insert drive=%d buf=%p size=%ld imageid=%d type=" , Drive , pImageBuffer , ImageSize , ImageId ); ! 344: switch ( ImageType ) { ! 345: case citIPF: fprintf ( stderr , "IPF\n" ); break; ! 346: case citCTRaw: fprintf ( stderr , "CT RAW\n" ); break; ! 347: case citKFStream: fprintf ( stderr , "KF STREAM\n" ) ; break; ! 348: case citDraft: fprintf ( stderr , "DRAFT\n" ) ; break; ! 349: default : fprintf ( stderr , "NOT SUPPORTED\n" ); ! 350: return false; ! 351: } ! 352: #endif ! 353: ! 354: if ( CAPSLockImageMemory ( ImageId , pImageBuffer , (CapsULong)ImageSize , DI_LOCK_MEMREF ) == imgeOk ) ! 355: { ! 356: struct CapsImageInfo cii; ! 357: int i; ! 358: ! 359: /* Print some debug infos */ ! 360: if ( CAPSGetImageInfo ( &cii , ImageId ) == imgeOk ) ! 361: { ! 362: printf("Type: %d\n", (int)cii.type); ! 363: printf("Release: %d\n", (int)cii.release); ! 364: printf("Revision: %d\n", (int)cii.revision); ! 365: printf("Min Cylinder: %d\n", (int)cii.mincylinder); ! 366: printf("Max Cylinder: %d\n", (int)cii.maxcylinder); ! 367: printf("Min Head: %d\n", (int)cii.minhead); ! 368: printf("Max Head: %d\n", (int)cii.maxhead); ! 369: printf("Creation Date: %04d/%02d/%02d %02d:%02d:%02d.%03d\n", (int)cii.crdt.year, (int)cii.crdt.month, (int)cii.crdt.day, (int)cii.crdt.hour, (int)cii.crdt.min, (int)cii.crdt.sec, (int)cii.crdt.tick); ! 370: printf("Platforms:"); ! 371: for (i = 0; i < CAPS_MAXPLATFORM; i++) ! 372: if (cii.platform[i] != ciipNA) ! 373: printf ( " %s" , CAPSGetPlatformName(cii.platform[i]) ); ! 374: printf("\n"); ! 375: ! 376: /* Some IPF disks are not correctly supported yet : display a warning */ ! 377: if ( (int)cii.release == 3222 ) /* Sundog */ ! 378: Log_AlertDlg ( LOG_INFO , "'Sundog' is not correctly supported yet, it requires write access." ); ! 379: else if ( (int)cii.release == 3058 ) /* Lethal Xcess */ ! 380: Log_AlertDlg ( LOG_INFO , "'Lethal Xcess' is not correctly supported yet, protection will fail" ); ! 381: } ! 382: } ! 383: else ! 384: { ! 385: CAPSRemImage ( ImageId ) ; ! 386: return false; ! 387: } ! 388: ! 389: if ( CAPSLoadImage ( ImageId , DI_LOCK_DENALT | DI_LOCK_DENVAR | DI_LOCK_UPDATEFD ) != imgeOk ) ! 390: { ! 391: fprintf ( stderr , "IPF : error CAPSLoadImage\n" ); ! 392: CAPSUnlockImage ( ImageId ); ! 393: CAPSRemImage ( ImageId ) ; ! 394: return false; ! 395: } ! 396: ! 397: ! 398: IPF_State.CapsImage[ Drive ] = ImageId; ! 399: ! 400: IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_IN; /* Disk inserted, keep the value for "write protect" */ ! 401: ! 402: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive ); /* Invalidate previous buffered track data for drive, if any */ ! 403: ! 404: IPF_State.Rev_Track[ Drive ] = -1; /* Invalidate previous track/side to handle revolution's count */ ! 405: IPF_State.Rev_Side[ Drive ] = -1; ! 406: ! 407: return true; ! 408: #endif ! 409: } ! 410: ! 411: ! 412: ! 413: ! 414: /* ! 415: * When ejecting a disk, free the ressources associated with an IPF image ! 416: */ ! 417: bool IPF_Eject ( int Drive ) ! 418: { ! 419: #ifndef HAVE_CAPSIMAGE ! 420: return false; ! 421: ! 422: #else ! 423: fprintf ( stderr , "IPF : IPF_Eject drive=%d imageid=%d\n" , Drive , IPF_State.CapsImage[ Drive ] ); ! 424: ! 425: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive ); /* Invalidate previous buffered track data for drive, if any */ ! 426: ! 427: if ( CAPSUnlockImage ( IPF_State.CapsImage[ Drive ] ) < 0 ) ! 428: { ! 429: fprintf ( stderr , "IPF : error CAPSUnlockImage\n" ); ! 430: return false; ! 431: } ! 432: ! 433: if ( CAPSRemImage ( IPF_State.CapsImage[ Drive ] ) < 0 ) ! 434: { ! 435: fprintf ( stderr , "IPF : error CAPSRemImage\n" ); ! 436: return false; ! 437: } ! 438: ! 439: IPF_State.CapsImage[ Drive ] = -1; ! 440: ! 441: IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_IN; ! 442: ! 443: return true; ! 444: #endif ! 445: } ! 446: ! 447: ! 448: ! 449: ! 450: /* ! 451: * Reset FDC state when a reset signal was received ! 452: */ ! 453: void IPF_Reset ( void ) ! 454: { ! 455: #ifdef HAVE_CAPSIMAGE ! 456: CAPSFdcReset ( &IPF_State.Fdc ); ! 457: ! 458: IPF_State.FdcClock = CyclesGlobalClockCounter; ! 459: #endif ! 460: } ! 461: ! 462: ! 463: ! 464: ! 465: /* ! 466: * Callback function used when track is changed. ! 467: * We need to update the track data by calling CAPSLockTrack ! 468: */ ! 469: #ifdef HAVE_CAPSIMAGE ! 470: static void IPF_CallBack_Trk ( struct CapsFdc *pc , CapsULong State ) ! 471: { ! 472: int Drive = State; /* State is the drive number in that case */ ! 473: struct CapsDrive *pd = pc->drive+Drive; /* Current drive where the track change occurred */ ! 474: struct CapsTrackInfoT1 cti; ! 475: ! 476: cti.type=1; ! 477: if ( CAPSLockTrack ( &cti , IPF_State.CapsImage[ Drive ] , pd->buftrack , pd->bufside , ! 478: DI_LOCK_DENALT|DI_LOCK_DENVAR|DI_LOCK_UPDATEFD|DI_LOCK_TYPE ) != imgeOk ) ! 479: return; ! 480: ! 481: LOG_TRACE(TRACE_FDC, "fdc ipf callback trk drive=%d buftrack=%d bufside=%d VBL=%d HBL=%d\n" , Drive , ! 482: (int)pd->buftrack , (int)pd->bufside , nVBLs , nHBL ); ! 483: ! 484: pd->ttype = cti.type; ! 485: pd->trackbuf = cti.trackbuf; ! 486: pd->timebuf = cti.timebuf; ! 487: pd->tracklen = cti.tracklen; ! 488: pd->overlap = cti.overlap; ! 489: } ! 490: #endif ! 491: ! 492: ! 493: ! 494: ! 495: /* ! 496: * Callback function used when the FDC change the IRQ signal ! 497: */ ! 498: #ifdef HAVE_CAPSIMAGE ! 499: static void IPF_CallBack_Irq ( struct CapsFdc *pc , CapsULong State ) ! 500: { ! 501: LOG_TRACE(TRACE_FDC, "fdc ipf callback irq state=0x%x VBL=%d HBL=%d\n" , (int)State , nVBLs , nHBL ); ! 502: ! 503: if ( State ) ! 504: FDC_SetIRQ ( FDC_IRQ_SOURCE_OTHER ); /* IRQ bit was set */ ! 505: else ! 506: FDC_ClearIRQ (); /* IRQ bit was reset */ ! 507: } ! 508: #endif ! 509: ! 510: ! 511: ! 512: ! 513: /* ! 514: * Callback function used when the FDC change the DRQ signal ! 515: * -> copy the byte to/from the DMA's FIFO if it's a read or a write to the disk ! 516: */ ! 517: #ifdef HAVE_CAPSIMAGE ! 518: static void IPF_CallBack_Drq ( struct CapsFdc *pc , CapsULong State ) ! 519: { ! 520: Uint8 Byte; ! 521: ! 522: if ( State == 0 ) ! 523: return; /* DRQ bit was reset, do nothing */ ! 524: ! 525: if ( FDC_DMA_GetModeControl_R_WR () != 0 ) /* DMA write mode */ ! 526: { ! 527: Byte = FDC_DMA_FIFO_Pull (); /* Get a byte from the DMA FIFO */ ! 528: CAPSFdcWrite ( &IPF_State.Fdc , 3 , Byte ); /* Write to FDC's reg 3 */ ! 529: ! 530: LOG_TRACE(TRACE_FDC, "fdc ipf callback drq state=0x%x write byte 0x%02x VBL=%d HBL=%d\n" , (int)State , Byte , nVBLs , nHBL ); ! 531: } ! 532: ! 533: else /* DMA read mode */ ! 534: { ! 535: Byte = CAPSFdcRead ( &IPF_State.Fdc , 3 ); /* Read from FDC's reg 3 */ ! 536: FDC_DMA_FIFO_Push ( Byte ); /* Add byte to the DMA FIFO */ ! 537: ! 538: LOG_TRACE(TRACE_FDC, "fdc ipf callback drq state=0x%x read byte 0x%02x VBL=%d HBL=%d\n" , (int)State , Byte , nVBLs , nHBL ); ! 539: } ! 540: } ! 541: #endif ! 542: ! 543: ! 544: ! 545: /* ! 546: * This function is used to enable/disable a drive when ! 547: * using the UI or command line parameters ! 548: * ! 549: * NOTE : for now, IPF only supports changing drive 1, drive 0 ! 550: * is always ON. ! 551: */ ! 552: void IPF_Drive_Set_Enable ( int Drive , bool value ) ! 553: { ! 554: #ifndef HAVE_CAPSIMAGE ! 555: return; ! 556: ! 557: #else ! 558: IPF_State.DriveEnabled[ Drive ] = value; /* Store the new state */ ! 559: ! 560: IPF_Drive_Update_Enable_Side (); /* Update IPF's internal state */ ! 561: #endif ! 562: } ! 563: ! 564: ! 565: /* ! 566: * This function is used to configure a drive as single sided ! 567: * or double sided when using the UI or command line parameters ! 568: */ ! 569: void IPF_Drive_Set_DoubleSided ( int Drive , bool value ) ! 570: { ! 571: #ifndef HAVE_CAPSIMAGE ! 572: return; ! 573: ! 574: #else ! 575: IPF_State.DoubleSided[ Drive ] = value; /* Store the new state */ ! 576: ! 577: IPF_Drive_Update_Enable_Side (); /* Update IPF's internal state */ ! 578: #endif ! 579: } ! 580: ! 581: ! 582: /* ! 583: * Update IPF's internal state depending on which drives are ON or OFF ! 584: * and if the drive is single or double sided (for capslib >= 5.1) ! 585: */ ! 586: #ifdef HAVE_CAPSIMAGE ! 587: static void IPF_Drive_Update_Enable_Side ( void ) ! 588: { ! 589: int i; ! 590: ! 591: if ( IPF_State.DriveEnabled[ 1 ] ) ! 592: IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES; /* Should be 2 */ ! 593: else ! 594: IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES - 1; /* Should be 1 */ ! 595: ! 596: #if CAPS_LIB_REL_REV >= 501 ! 597: for ( i=0 ; i < MAX_FLOPPYDRIVES ; i++ ) ! 598: { ! 599: if ( IPF_State.DoubleSided[ i ] ) ! 600: IPF_State.Drive[ i ].diskattr &= ~CAPSDRIVE_DA_SS; /* Double sided */ ! 601: else ! 602: IPF_State.Drive[ i ].diskattr |= CAPSDRIVE_DA_SS; /* Single sided */ ! 603: } ! 604: #endif ! 605: } ! 606: #endif ! 607: ! 608: ! 609: /* ! 610: * Set the drive and the side to be used for the next FDC commands ! 611: * io_porta_old is the previous value, io_porta_new is the new value ! 612: * to take into account. ! 613: * We report a side change only when a drive is selected. ! 614: */ ! 615: void IPF_SetDriveSide ( Uint8 io_porta_old , Uint8 io_porta_new ) ! 616: { ! 617: #ifndef HAVE_CAPSIMAGE ! 618: return; ! 619: ! 620: #else ! 621: int Side; ! 622: ! 623: LOG_TRACE(TRACE_FDC, "fdc ipf change drive/side io_porta_old=0x%x io_porta_new=0x%x VBL=%d HBL=%d\n" , io_porta_old , io_porta_new , nVBLs , nHBL ); ! 624: ! 625: Side = ( (~io_porta_new) & 0x01 ); /* Side 0 or 1 */ ! 626: ! 627: IPF_State.Fdc.drivenew = -1; /* By default, don't select any drive */ ! 628: ! 629: /* Check drive 1 first */ ! 630: if ( ( io_porta_new & 0x04 ) == 0 ) ! 631: { ! 632: IPF_State.Drive[ 1 ].newside = Side; ! 633: IPF_State.Fdc.drivenew = 1; /* Select drive 1 */ ! 634: } ! 635: ! 636: /* If both drive 0 and drive 1 are enabled, we keep only drive 0 as newdrive */ ! 637: if ( ( io_porta_new & 0x02 ) == 0 ) ! 638: { ! 639: IPF_State.Drive[ 0 ].newside = Side; ! 640: IPF_State.Fdc.drivenew = 0; /* Select drive 0 (and un-select drive 1 if set above) */ ! 641: } ! 642: ! 643: IPF_Emulate(); /* Update emulation's state up to this point, then set new drive/side */ ! 644: #endif ! 645: } ! 646: ! 647: ! 648: ! 649: ! 650: /* ! 651: * Write a byte into one of the FDC registers ! 652: * 0=command 1=track 2=sector 3=data ! 653: */ ! 654: void IPF_FDC_WriteReg ( Uint8 Reg , Uint8 Byte ) ! 655: { ! 656: #ifndef HAVE_CAPSIMAGE ! 657: return; /* This should not be reached (an IPF image can't be inserted without capsimage) */ ! 658: ! 659: #else ! 660: LOG_TRACE(TRACE_FDC, "fdc ipf write reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL ); ! 661: ! 662: ! 663: #if CAPS_LIB_REL_REV >= 501 ! 664: /* In the case of CTR images, we must reset the revolution counter */ ! 665: /* when a command access data on disk and track/side changed since last access */ ! 666: if ( Reg == 0 ) ! 667: { ! 668: int Type; ! 669: int Drive; ! 670: ! 671: Type = FDC_GetCmdType ( Byte ); ! 672: if ( ( Type == 2 ) || ( Type == 3 ) ) ! 673: { ! 674: Drive = IPF_State.Fdc.driveact; ! 675: if ( ( Drive >= 0 ) ! 676: && ( ( IPF_State.Drive[ Drive ].side != IPF_State.Rev_Side[ Drive ] ) || ( IPF_State.Drive[ Drive ].track != IPF_State.Rev_Track[ Drive ] ) ) ) ! 677: { ! 678: IPF_State.Rev_Side[ Drive ] = IPF_State.Drive[ Drive ].side; ! 679: IPF_State.Rev_Track[ Drive ] = IPF_State.Drive[ Drive ].track; ! 680: CAPSSetRevolution ( IPF_State.CapsImage[ Drive ] , 0 ); ! 681: } ! 682: } ! 683: } ! 684: #endif ! 685: ! 686: IPF_Emulate(); /* Update emulation's state up to this point */ ! 687: ! 688: CAPSFdcWrite ( &IPF_State.Fdc , Reg , Byte ); ! 689: #endif ! 690: } ! 691: ! 692: ! 693: ! 694: ! 695: /* ! 696: * Read the content of one of the FDC registers ! 697: * 0=status 1=track 2=sector 3=data ! 698: */ ! 699: Uint8 IPF_FDC_ReadReg ( Uint8 Reg ) ! 700: { ! 701: #ifndef HAVE_CAPSIMAGE ! 702: return 0; /* This should not be reached (an IPF image can't be inserted without capsimage) */ ! 703: #else ! 704: Uint8 Byte; ! 705: ! 706: IPF_Emulate(); /* Update emulation's state up to this point */ ! 707: ! 708: Byte = CAPSFdcRead ( &IPF_State.Fdc , Reg ); ! 709: LOG_TRACE(TRACE_FDC, "fdc ipf read reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL ); ! 710: ! 711: return Byte; ! 712: #endif ! 713: } ! 714: ! 715: ! 716: ! 717: ! 718: /* ! 719: * Return the content of some registers to display them in the statusbar ! 720: * We should not call IPF_Emulate() or similar, reading should not change emulation's state ! 721: */ ! 722: void IPF_FDC_StatusBar ( Uint8 *pCommand , Uint8 *pHead , Uint8 *pTrack , Uint8 *pSector , Uint8 *pSide ) ! 723: { ! 724: #ifndef HAVE_CAPSIMAGE ! 725: return; /* This should not be reached (an IPF image can't be inserted without capsimage) */ ! 726: #else ! 727: int Drive; ! 728: ! 729: Drive = IPF_State.Fdc.driveact; ! 730: if ( Drive < 0 ) /* If no drive enabled, use drive O for Head/Side */ ! 731: Drive = 0; ! 732: ! 733: /* We read directly in the structures, to be sure we don't change emulation's state */ ! 734: *pCommand = IPF_State.Fdc.r_command; ! 735: *pHead = IPF_State.Drive[ Drive ].track; ! 736: *pTrack = IPF_State.Fdc.r_track; ! 737: *pSector = IPF_State.Fdc.r_sector; ! 738: *pSide = IPF_State.Drive[ Drive ].side; ! 739: #endif ! 740: } ! 741: ! 742: ! 743: ! 744: ! 745: /* ! 746: * Run the FDC emulation during NbCycles cycles (relative to the 8MHz FDC's clock) ! 747: */ ! 748: void IPF_Emulate ( void ) ! 749: { ! 750: #ifndef HAVE_CAPSIMAGE ! 751: return; ! 752: ! 753: #else ! 754: int NbCycles; ! 755: int Drive; ! 756: ! 757: NbCycles = CyclesGlobalClockCounter - IPF_State.FdcClock; /* Number of cycles since last emulation */ ! 758: if ( NbCycles < 0 ) ! 759: NbCycles = 0; /* We should call CAPSFdcEmulate even when NbCycles=0 */ ! 760: ! 761: // LOG_TRACE(TRACE_FDC, "fdc ipf emulate cycles=%d VBL=%d HBL=%d clock=%lld\n" , NbCycles , nVBLs , nHBL , CyclesGlobalClockCounter ); ! 762: ! 763: /* Update Write Protect status for each drive */ ! 764: for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ ) ! 765: if ( Floppy_IsWriteProtected ( Drive ) ) ! 766: IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_WP; /* Disk write protected */ ! 767: else ! 768: IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_WP; /* Disk is not write protected */ ! 769: ! 770: ! 771: CAPSFdcEmulate ( &IPF_State.Fdc , NbCycles ); /* Process at max NbCycles */ ! 772: IPF_State.FdcClock += IPF_State.Fdc.clockact; /* clockact can be < NbCycle in some cases */ ! 773: ! 774: /* Update UI's LEDs depending on Status Register */ ! 775: FDC_Drive_Set_BusyLed ( (IPF_State.Fdc.r_st0 & ~IPF_State.Fdc.r_stm) | (IPF_State.Fdc.r_st1 & IPF_State.Fdc.r_stm) ); ! 776: #endif ! 777: } ! 778: ! 779: ! 780:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.