|
|
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:
1.1.1.4 ! root 12: RAW stream files made with KryoFlux board or CT RAW dumped with an Amiga are also handled
1.1 root 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"
1.1.1.4 ! root 26: #include "m68000.h"
1.1 root 27: #include "cycles.h"
28:
1.1.1.4 ! root 29: #include <string.h>
! 30:
1.1 root 31: #ifdef HAVE_CAPSIMAGE
32: #if CAPSIMAGE_VERSION == 5
33: #include <caps5/CapsLibAll.h>
34: #else
35: #include <caps/fdc.h>
36: #define CAPS_LIB_RELEASE 4
37: #define CAPS_LIB_REVISION 2
38: #endif
39: /* Macro to check release and revision */
40: #define CAPS_LIB_REL_REV ( CAPS_LIB_RELEASE * 100 + CAPS_LIB_REVISION )
41: #endif
42:
43:
1.1.1.4 ! root 44: /* To handle RAW stream images with one file per track/side */
! 45: #define IPF_MAX_TRACK_RAW_STREAM_IMAGE 84 /* track number can be 0 .. 83 */
! 46: #define IPF_MAX_SIDE_RAW_STREAM_IMAGE 2 /* side number can be 0 or 1 */
! 47:
! 48: struct
! 49: {
! 50: int TrackSize;
! 51: Uint8 *TrackData;
! 52: } IPF_RawStreamImage[ MAX_FLOPPYDRIVES ][ IPF_MAX_TRACK_RAW_STREAM_IMAGE ][ IPF_MAX_SIDE_RAW_STREAM_IMAGE ];
! 53:
! 54:
! 55:
1.1 root 56: typedef struct
57: {
58: #ifdef HAVE_CAPSIMAGE
59: Uint32 CapsLibRelease;
60: Uint32 CapsLibRevision;
61:
62: struct CapsFdc Fdc; /* Fdc state */
63: struct CapsDrive Drive[ MAX_FLOPPYDRIVES ]; /* Physical drives */
1.1.1.4 ! root 64: CapsLong CapsImage[ MAX_FLOPPYDRIVES ]; /* Image Id or -1 if drive empty */
! 65: CapsLong CapsImageType[ MAX_FLOPPYDRIVES ]; /* ImageType or -1 if not known */
1.1 root 66:
67: int Rev_Track[ MAX_FLOPPYDRIVES ]; /* Needed to handle CAPSSetRevolution for type II/III commands */
68: int Rev_Side[ MAX_FLOPPYDRIVES ];
69:
70: bool DriveEnabled[ MAX_FLOPPYDRIVES ];/* Is drive ON or OFF */
71: bool DoubleSided[ MAX_FLOPPYDRIVES ];/* Is drive double sided or not */
1.1.1.3 root 72: #endif
1.1 root 73:
74: Sint64 FdcClock; /* Current value of CyclesGlobalClockCounter */
75: } IPF_STRUCT;
76:
77:
78: static IPF_STRUCT IPF_State; /* All variables related to the IPF support */
79:
80:
1.1.1.4 ! root 81: static bool IPF_Eject_RawStreamImage ( int Drive );
1.1 root 82: #ifdef HAVE_CAPSIMAGE
1.1.1.4 ! root 83: static char *IPF_FilenameFindTrackSide (char *FileName);
! 84: static bool IPF_Insert_RawStreamImage ( int Drive );
! 85:
1.1 root 86: static void IPF_CallBack_Trk ( struct CapsFdc *pc , CapsULong State );
87: static void IPF_CallBack_Irq ( struct CapsFdc *pc , CapsULong State );
88: static void IPF_CallBack_Drq ( struct CapsFdc *pc , CapsULong State );
89: static void IPF_Drive_Update_Enable_Side ( void );
1.1.1.4 ! root 90: static void IPF_FDC_LogCommand ( Uint8 Command );
1.1 root 91: #endif
92:
93:
94:
95:
96: /*-----------------------------------------------------------------------*/
97: /**
98: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
99: * We must take care of whether Hatari was compiled with IPF support of not
100: * when saving/restoring snapshots to avoid incompatibilies.
101: */
102: void IPF_MemorySnapShot_Capture(bool bSave)
103: {
104: int StructSize;
105: int Drive;
1.1.1.4 ! root 106: int Track , Side;
! 107: int TrackSize;
! 108: Uint8 *p;
! 109:
1.1 root 110:
111: if ( bSave ) /* Saving snapshot */
112: {
113: StructSize = sizeof ( IPF_State ); /* 0 if HAVE_CAPSIMAGE is not defined */
114: MemorySnapShot_Store(&StructSize, sizeof(StructSize));
115: if ( StructSize > 0 )
1.1.1.4 ! root 116: {
1.1 root 117: MemorySnapShot_Store(&IPF_State, sizeof(IPF_State));
1.1.1.4 ! root 118:
! 119: /* Save the content of IPF_RawStreamImage[] */
! 120: for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
! 121: for ( Track=0 ; Track<IPF_MAX_TRACK_RAW_STREAM_IMAGE ; Track++ )
! 122: for ( Side=0 ; Side<IPF_MAX_SIDE_RAW_STREAM_IMAGE ; Side++ )
! 123: {
! 124: TrackSize = IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize;
! 125: // fprintf ( stderr , "IPF : save raw stream drive=%d track=%d side=%d : %d\n" , Drive , Track , Side , TrackSize );
! 126: MemorySnapShot_Store(&TrackSize, sizeof(TrackSize));
! 127: if ( TrackSize > 0 )
! 128: MemorySnapShot_Store(IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData, TrackSize);
! 129: }
! 130: }
1.1 root 131: }
132:
133: else /* Restoring snapshot */
134: {
135: MemorySnapShot_Store(&StructSize, sizeof(StructSize));
136: if ( ( StructSize == 0 ) && ( sizeof ( IPF_State ) > 0 ) )
137: {
138: Log_AlertDlg(LOG_ERROR, "This memory snapshot doesn't include IPF data but this version of Hatari was built with IPF support");
139: return; /* Continue restoring the rest of the memory snapshot */
140: }
141: else if ( ( StructSize > 0 ) && ( sizeof ( IPF_State ) == 0 ) )
142: {
143: Log_AlertDlg(LOG_ERROR, "This memory snapshot includes IPF data but this version of Hatari was not built with IPF support");
144: MemorySnapShot_Skip( StructSize ); /* Ignore the IPF data */
145: return; /* Continue restoring the rest of the memory snapshot */
146: }
147: else if ( ( StructSize > 0 ) && ( StructSize != sizeof ( IPF_State ) ) )
148: {
149: Log_AlertDlg(LOG_ERROR, "This memory snapshot includes IPF data different from the ones handled in this version of Hatari");
150: MemorySnapShot_Skip( StructSize ); /* Ignore the IPF data */
151: return; /* Continue restoring the rest of the memory snapshot */
152: }
153:
154: if ( StructSize > 0 )
155: {
156: MemorySnapShot_Store(&IPF_State, sizeof(IPF_State));
157:
158: #ifdef HAVE_CAPSIMAGE
159: /* For IPF structures, we need to update some pointers in Fdc/Drive/CapsImage */
160: /* drive : PUBYTE trackbuf, PUDWORD timebuf */
161: /* fdc : PCAPSDRIVE driveprc, PCAPSDRIVE drive, CAPSFDCHOOK callback functions */
162: IPF_State.Fdc.drive = IPF_State.Drive; /* Connect drives array to the FDC */
163: if ( IPF_State.Fdc.driveprc != NULL ) /* Recompute active drive's pointer */
164: IPF_State.Fdc.driveprc = IPF_State.Fdc.drive + IPF_State.Fdc.driveact;
165:
1.1.1.2 root 166: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , 0 ); /* Invalidate buffered track data for drive 0 */
167: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , 1 ); /* Invalidate buffered track data for drive 1 */
168:
1.1 root 169: /* Set callback functions */
170: IPF_State.Fdc.cbirq = IPF_CallBack_Irq;
171: IPF_State.Fdc.cbdrq = IPF_CallBack_Drq;
172: IPF_State.Fdc.cbtrk = IPF_CallBack_Trk;
173: #endif
174:
175: /* Call IPF_Insert to recompute IPF_State.CapsImage[ Drive ] */
176: for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
177: if ( EmulationDrives[Drive].ImageType == FLOPPY_IMAGE_TYPE_IPF )
178: if ( IPF_Insert ( Drive , EmulationDrives[Drive].pBuffer , EmulationDrives[Drive].nImageBytes ) == false )
179: {
180: Log_AlertDlg(LOG_ERROR, "Error restoring IPF image %s in drive %d" ,
181: EmulationDrives[Drive].sFileName , Drive );
182: return;
183: }
184:
1.1.1.4 ! root 185: /* Restore the content of IPF_RawStreamImage[] */
! 186: /* NOTE : IPF_Insert above might already have read the raw tracks from disk, */
! 187: /* so we free all those tracks and read them again from the snapshot instead */
! 188: /* (not very efficient, but it's a rare case anyway) */
! 189: for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
! 190: {
! 191: IPF_Eject_RawStreamImage ( Drive );
! 192: for ( Track=0 ; Track<IPF_MAX_TRACK_RAW_STREAM_IMAGE ; Track++ )
! 193: for ( Side=0 ; Side<IPF_MAX_SIDE_RAW_STREAM_IMAGE ; Side++ )
! 194: {
! 195: MemorySnapShot_Store(&TrackSize, sizeof(TrackSize));
! 196: // fprintf ( stderr , "IPF : restore raw stream drive=%d track=%d side=%d : %d\n" , Drive , Track , Side , TrackSize );
! 197: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize = TrackSize;
! 198: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = NULL;
! 199: if ( TrackSize > 0 )
! 200: {
! 201: p = malloc ( TrackSize );
! 202: if ( p == NULL )
! 203: {
! 204: Log_AlertDlg(LOG_ERROR, "Error restoring IPF raw track drive %d track %d side %d size %d" ,
! 205: Drive, Track, Side , TrackSize );
! 206: return;
! 207: }
! 208: MemorySnapShot_Store(p, TrackSize);
! 209: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = p;
! 210: }
! 211: }
! 212: }
1.1 root 213: fprintf ( stderr , "ipf load ok\n" );
214: }
215: }
216: }
217:
218:
219:
220:
221: /*-----------------------------------------------------------------------*/
222: /**
223: * Does filename end with a .IPF or .RAW or .CTR extension ? If so, return true.
224: * .RAW and .CTR support requires caps lib >= 5.1
225: */
226: bool IPF_FileNameIsIPF(const char *pszFileName, bool bAllowGZ)
227: {
228: return ( File_DoesFileExtensionMatch(pszFileName,".ipf" )
229: || ( bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".ipf.gz") )
230: #if CAPS_LIB_REL_REV >= 501
231: || File_DoesFileExtensionMatch(pszFileName,".raw" )
232: || ( bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".raw.gz") )
233: || File_DoesFileExtensionMatch(pszFileName,".ctr" )
234: || ( bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".ctr.gz") )
235: #endif
236: );
237: }
238:
239:
1.1.1.4 ! root 240: /*
! 241: * Return a pointer to the part "tt.s.raw" at the end of the filename
! 242: * (there can be an extra suffix to ignore if the file is compressed).
! 243: * If we found a string where "tt" and "s" are digits, then we return
! 244: * a pointer to this string.
! 245: * If not found, we return NULL
! 246: */
! 247: #ifdef HAVE_CAPSIMAGE
! 248: static char *IPF_FilenameFindTrackSide (char *FileName)
! 249: {
! 250: char ext[] = ".raw";
! 251: int len;
! 252: char *p;
! 253:
! 254: len = strlen ( FileName );
! 255: len -= strlen ( ext );
! 256:
! 257: while ( len >= 4 ) /* need at least 4 chars for "tt.s" */
! 258: {
! 259: if ( strncasecmp ( ext , FileName + len , strlen ( ext ) ) == 0 )
! 260: {
! 261: p = FileName + len - 4;
! 262: if ( isdigit( p[0] ) && isdigit( p[1] )
! 263: && ( p[2] == '.' ) && isdigit( p[3] ) )
! 264: return p;
! 265: }
! 266:
! 267: len--;
! 268: }
! 269:
! 270: return NULL;
! 271: }
! 272: #endif
! 273:
! 274:
1.1 root 275: /*-----------------------------------------------------------------------*/
276: /**
277: * Load .IPF file into memory, set number of bytes loaded and return a pointer
278: * to the buffer.
279: */
280: Uint8 *IPF_ReadDisk(int Drive, const char *pszFileName, long *pImageSize, int *pImageType)
281: {
282: #ifndef HAVE_CAPSIMAGE
283: Log_AlertDlg(LOG_ERROR, "This version of Hatari was not built with IPF support, this disk image can't be handled.");
284: return NULL;
285:
286: #else
287: Uint8 *pIPFFile;
288:
289: *pImageSize = 0;
290:
291: /* Just load directly a buffer, and set ImageSize accordingly */
292: pIPFFile = File_Read(pszFileName, pImageSize, NULL);
293: if (!pIPFFile)
294: {
295: *pImageSize = 0;
296: return NULL;
297: }
298:
299: *pImageType = FLOPPY_IMAGE_TYPE_IPF;
300: return pIPFFile;
301: #endif
302: }
303:
304:
305: /*-----------------------------------------------------------------------*/
306: /**
307: * Save .IPF file from memory buffer. Returns true is all OK.
308: */
309: bool IPF_WriteDisk(int Drive, const char *pszFileName, Uint8 *pBuffer, int ImageSize)
310: {
311: /* saving is not supported for IPF files */
312: return false;
313: }
314:
315:
316:
317:
318: /*
319: * Init the FDC and the drives used to handle IPF images
320: */
321: bool IPF_Init ( void )
322: {
323: #ifndef HAVE_CAPSIMAGE
324: return true;
325:
326: #else
327: int i;
328: struct CapsVersionInfo caps_vi;
329:
330: fprintf ( stderr , "IPF : IPF_Init\n" );
331:
332: if ( CAPSInit() != imgeOk )
333: {
334: fprintf ( stderr , "IPF : Could not initialize the capsimage library\n" );
335: return false;
336: }
337:
338: if ( CAPSGetVersionInfo ( &caps_vi , 0 ) != imgeOk )
339: {
340: fprintf ( stderr , "IPF : CAPSVersionInfo failed\n" );
341: return false;
342: }
343: fprintf ( stderr , "IPF : capsimage library version release=%d revision=%d\n" , (int)caps_vi.release , (int)caps_vi.revision );
344: IPF_State.CapsLibRelease = caps_vi.release;
345: IPF_State.CapsLibRevision = caps_vi.revision;
346:
347: /* Default values for each physical drive */
348: memset ( IPF_State.Drive , 0 , sizeof ( IPF_State.Drive ) );
349: for ( i=0 ; i < MAX_FLOPPYDRIVES ; i++ )
350: {
351: IPF_State.Drive[ i ].type = sizeof ( struct CapsDrive );
352: IPF_State.Drive[ i ].rpm = CAPSDRIVE_35DD_RPM;
353: IPF_State.Drive[ i ].maxtrack = CAPSDRIVE_35DD_HST;
354:
355: IPF_State.Rev_Track[ i ] = -1;
356: IPF_State.Rev_Side[ i ] = -1;
357:
358: IPF_State.DriveEnabled[ i ] = true;
359: IPF_State.DoubleSided[ i ] = true;
1.1.1.4 ! root 360:
! 361: IPF_State.CapsImageType[ i ] = -1;
1.1 root 362: }
363:
364: /* Init FDC with 2 physical drives */
365: memset ( &IPF_State.Fdc , 0 , sizeof ( IPF_State.Fdc ) );
366: IPF_State.Fdc.type = sizeof( struct CapsFdc );
367: IPF_State.Fdc.model = cfdcmWD1772;
368: IPF_State.Fdc.drive = IPF_State.Drive;
369: IPF_State.Fdc.drivecnt = MAX_FLOPPYDRIVES;
370:
371: if ( CAPSFdcInit ( &IPF_State.Fdc ) != imgeOk)
372: {
373: fprintf ( stderr , "IPF : CAPSFdcInit failed\n" );
374: return false;
375: }
376:
377: /* 2 drives by default */
378: IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES;
379: /* Update drives' state in case we have some drives ON or OFF in config or parameters */
380: IPF_Drive_Update_Enable_Side ();
381:
382: /* FDC clock */
383: IPF_State.Fdc.clockfrq = 8000000;
384:
385: /* Set callback functions */
386: IPF_State.Fdc.cbirq = IPF_CallBack_Irq;
387: IPF_State.Fdc.cbdrq = IPF_CallBack_Drq;
388: IPF_State.Fdc.cbtrk = IPF_CallBack_Trk;
389:
390: CAPSFdcReset ( &IPF_State.Fdc );
391:
392: return true;
393: #endif
394: }
395:
396:
397:
398:
399: /*
400: * Exit
401: */
402: void IPF_Exit ( void )
403: {
404: #ifndef HAVE_CAPSIMAGE
405: #else
406: CAPSExit();
407: #endif
408: }
409:
410:
411:
412:
413: /*
414: * Init the ressources to handle the IPF image inserted into a drive (0=A: 1=B:)
415: */
416: bool IPF_Insert ( int Drive , Uint8 *pImageBuffer , long ImageSize )
417: {
418: #ifndef HAVE_CAPSIMAGE
419: return false;
420:
421: #else
422: CapsLong ImageId;
423: CapsLong ImageType;
424:
425: ImageId = CAPSAddImage();
426: if ( ImageId < 0 )
427: {
428: fprintf ( stderr , "IPF : error CAPSAddImage\n" );
429: return false;
430: }
431:
432: #if CAPS_LIB_REL_REV >= 501
433: ImageType = CAPSGetImageTypeMemory ( pImageBuffer , ImageSize );
434: if ( ImageType == citError )
435: {
436: fprintf ( stderr , "IPF : error CAPSGetImageTypeMemory\n" );
1.1.1.4 ! root 437: CAPSRemImage ( ImageId ) ;
1.1 root 438: return false;
439: }
440: else if ( ImageType == citUnknown )
441: {
442: fprintf ( stderr , "IPF : unknown image type\n" );
1.1.1.4 ! root 443: CAPSRemImage ( ImageId ) ;
1.1 root 444: return false;
445: }
446:
447: fprintf ( stderr , "IPF : IPF_Insert drive=%d buf=%p size=%ld imageid=%d type=" , Drive , pImageBuffer , ImageSize , ImageId );
448: switch ( ImageType ) {
449: case citIPF: fprintf ( stderr , "IPF\n" ); break;
450: case citCTRaw: fprintf ( stderr , "CT RAW\n" ); break;
451: case citKFStream: fprintf ( stderr , "KF STREAM\n" ) ; break;
452: case citDraft: fprintf ( stderr , "DRAFT\n" ) ; break;
453: default : fprintf ( stderr , "NOT SUPPORTED\n" );
1.1.1.4 ! root 454: CAPSRemImage ( ImageId ) ;
1.1 root 455: return false;
456: }
1.1.1.4 ! root 457:
! 458: /* Special case for RAW stream image, we load all the tracks now */
! 459: if ( ImageType == citKFStream )
! 460: {
! 461: if ( IPF_Insert_RawStreamImage ( Drive ) == false )
! 462: {
! 463: fprintf ( stderr , "IPF : can't load raw stream files\n" );
! 464: CAPSRemImage ( ImageId ) ;
! 465: return false;
! 466: }
! 467: }
! 468:
! 469: #else
! 470: ImageType = -1;
1.1 root 471: #endif
472:
473: if ( CAPSLockImageMemory ( ImageId , pImageBuffer , (CapsULong)ImageSize , DI_LOCK_MEMREF ) == imgeOk )
474: {
475: struct CapsImageInfo cii;
476: int i;
477:
478: /* Print some debug infos */
479: if ( CAPSGetImageInfo ( &cii , ImageId ) == imgeOk )
480: {
481: printf("Type: %d\n", (int)cii.type);
482: printf("Release: %d\n", (int)cii.release);
483: printf("Revision: %d\n", (int)cii.revision);
484: printf("Min Cylinder: %d\n", (int)cii.mincylinder);
485: printf("Max Cylinder: %d\n", (int)cii.maxcylinder);
486: printf("Min Head: %d\n", (int)cii.minhead);
487: printf("Max Head: %d\n", (int)cii.maxhead);
488: 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);
489: printf("Platforms:");
490: for (i = 0; i < CAPS_MAXPLATFORM; i++)
491: if (cii.platform[i] != ciipNA)
492: printf ( " %s" , CAPSGetPlatformName(cii.platform[i]) );
493: printf("\n");
494:
495: /* Some IPF disks are not correctly supported yet : display a warning */
496: if ( (int)cii.release == 3222 ) /* Sundog */
497: Log_AlertDlg ( LOG_INFO , "'Sundog' is not correctly supported yet, it requires write access." );
498: else if ( (int)cii.release == 3058 ) /* Lethal Xcess */
499: Log_AlertDlg ( LOG_INFO , "'Lethal Xcess' is not correctly supported yet, protection will fail" );
500: }
501: }
502: else
503: {
504: CAPSRemImage ( ImageId ) ;
505: return false;
506: }
507:
508: if ( CAPSLoadImage ( ImageId , DI_LOCK_DENALT | DI_LOCK_DENVAR | DI_LOCK_UPDATEFD ) != imgeOk )
509: {
510: fprintf ( stderr , "IPF : error CAPSLoadImage\n" );
511: CAPSUnlockImage ( ImageId );
512: CAPSRemImage ( ImageId ) ;
513: return false;
514: }
515:
516:
517: IPF_State.CapsImage[ Drive ] = ImageId;
1.1.1.4 ! root 518: IPF_State.CapsImageType[ Drive ] = ImageType;
1.1 root 519:
520: IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_IN; /* Disk inserted, keep the value for "write protect" */
521:
522: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive ); /* Invalidate previous buffered track data for drive, if any */
523:
524: IPF_State.Rev_Track[ Drive ] = -1; /* Invalidate previous track/side to handle revolution's count */
525: IPF_State.Rev_Side[ Drive ] = -1;
526:
527: return true;
528: #endif
529: }
530:
531:
1.1.1.4 ! root 532: /*
! 533: * Load all the raw stream files for all tracks/sides of a dump.
! 534: * We use the filename of the raw file in drive 'Drive' as a template
! 535: * where we replace track and side will all the possible values.
! 536: */
! 537: #ifdef HAVE_CAPSIMAGE
! 538: static bool IPF_Insert_RawStreamImage ( int Drive )
! 539: {
! 540: int Track , Side;
! 541: char TrackFileName[ FILENAME_MAX ];
! 542: char *TrackSide_pointer;
! 543: char TrackSide_buf[ 4 + 1 ]; /* "tt.s" + \0 */
! 544: int TrackCount;
! 545: int TrackCount_0 , TrackCount_1;
! 546: Uint8 *p;
! 547: long Size;
! 548:
! 549:
! 550: return true; /* This function is not used for now, always return true */
! 551: /* Ensure the previous tracks are removed from memory */
! 552: IPF_Eject_RawStreamImage ( Drive );
! 553:
! 554:
! 555: /* Get the path+filename of the raw file that was inserted in 'Drive' */
! 556: /* then parse it to find the part with track/side */
! 557: strcpy ( TrackFileName , ConfigureParams.DiskImage.szDiskFileName[Drive] );
! 558:
! 559: TrackSide_pointer = IPF_FilenameFindTrackSide ( TrackFileName );
! 560: if ( TrackSide_pointer == NULL )
! 561: {
! 562: fprintf ( stderr , "IPF : error parsing track/side in raw filename\n" );
! 563: return false;
! 564: }
! 565:
! 566: /* We try to load all the tracks for all the sides */
! 567: /* We ignore errors, as some tracks/side can really be missing from the image dump */
! 568: TrackCount = 0;
! 569: TrackCount_0 = 0;
! 570: TrackCount_1 = 0;
! 571: for ( Track=0 ; Track<IPF_MAX_TRACK_RAW_STREAM_IMAGE ; Track++ )
! 572: {
! 573: for ( Side=0 ; Side<IPF_MAX_SIDE_RAW_STREAM_IMAGE ; Side++ )
! 574: {
! 575: sprintf ( TrackSide_buf , "%02d.%d" , Track , Side );
! 576: memcpy ( TrackSide_pointer , TrackSide_buf , 4 );
! 577: fprintf ( stderr , "IPF : insert raw stream drive=%d track=%d side=%d %s\n" , Drive , Track , Side , TrackFileName );
! 578:
! 579: p = File_Read ( TrackFileName , &Size , NULL);
! 580: if ( p )
! 581: {
! 582: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = p;
! 583: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize = Size;
! 584: TrackCount++;
! 585: if ( Side==0 ) TrackCount_0++;
! 586: else TrackCount_1++;
! 587: }
! 588: else
! 589: {
! 590: fprintf ( stderr , "IPF : insert raw stream drive=%d track=%d side=%d %s -> not found\n" , Drive , Track , Side , TrackFileName );
! 591: /* File not loaded : either this track really doesn't exist or there was a system error */
! 592: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = NULL;
! 593: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize = 0;
! 594: }
! 595: }
! 596: }
! 597:
! 598:
! 599: /* If we didn't load any track, there's a problem, we stop here */
! 600: if ( TrackCount == 0 )
! 601: {
! 602: fprintf ( stderr , "IPF : error, no raw track file could be loaded for %s\n" , ConfigureParams.DiskImage.szDiskFileName[Drive] );
! 603: /* Free all the tracks that were loaded so far */
! 604: IPF_Eject_RawStreamImage ( Drive );
! 605: return false;
! 606: }
! 607:
! 608: fprintf ( stderr , "IPF : insert raw stream drive=%d, loaded %d tracks for side 0 and %d tracks for side 1\n", Drive, TrackCount_0, TrackCount_1 );
! 609:
! 610: return true;
! 611: }
! 612: #endif
! 613:
1.1 root 614:
615:
616: /*
617: * When ejecting a disk, free the ressources associated with an IPF image
618: */
619: bool IPF_Eject ( int Drive )
620: {
621: #ifndef HAVE_CAPSIMAGE
622: return false;
623:
624: #else
625: fprintf ( stderr , "IPF : IPF_Eject drive=%d imageid=%d\n" , Drive , IPF_State.CapsImage[ Drive ] );
626:
627: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive ); /* Invalidate previous buffered track data for drive, if any */
628:
629: if ( CAPSUnlockImage ( IPF_State.CapsImage[ Drive ] ) < 0 )
630: {
631: fprintf ( stderr , "IPF : error CAPSUnlockImage\n" );
632: return false;
633: }
634:
635: if ( CAPSRemImage ( IPF_State.CapsImage[ Drive ] ) < 0 )
636: {
637: fprintf ( stderr , "IPF : error CAPSRemImage\n" );
638: return false;
639: }
640:
1.1.1.4 ! root 641: /* Special case for RAW stream image, we must free all the tracks */
! 642: if ( IPF_State.CapsImageType[ Drive ] == citKFStream )
! 643: IPF_Eject_RawStreamImage ( Drive );
! 644:
1.1 root 645: IPF_State.CapsImage[ Drive ] = -1;
1.1.1.4 ! root 646: IPF_State.CapsImageType[ Drive ] = -1;
1.1 root 647:
648: IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_IN;
649:
650: return true;
651: #endif
652: }
653:
654:
1.1.1.4 ! root 655: /*
! 656: * When ejecting a RAW stream image we must free all the individual tracks
! 657: */
! 658: static bool IPF_Eject_RawStreamImage ( int Drive )
! 659: {
! 660: #ifndef HAVE_CAPSIMAGE
! 661: return true;
! 662:
! 663: #else
! 664: int Track , Side;
! 665:
! 666: return true; /* This function is not used for now, always return true */
! 667: for ( Track=0 ; Track<IPF_MAX_TRACK_RAW_STREAM_IMAGE ; Track++ )
! 668: for ( Side=0 ; Side<IPF_MAX_SIDE_RAW_STREAM_IMAGE ; Side++ )
! 669: {
! 670: if ( IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData != NULL )
! 671: {
! 672: fprintf ( stderr , "IPF : eject raw stream drive=%d track=%d side=%d\n" , Drive , Track , Side );
! 673: free ( IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData );
! 674: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = NULL;
! 675: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize = 0;
! 676: }
! 677: }
! 678:
! 679: return true;
! 680: #endif
! 681: }
! 682:
! 683:
1.1 root 684:
685:
686: /*
687: * Reset FDC state when a reset signal was received
688: */
689: void IPF_Reset ( void )
690: {
691: #ifdef HAVE_CAPSIMAGE
692: CAPSFdcReset ( &IPF_State.Fdc );
693:
694: IPF_State.FdcClock = CyclesGlobalClockCounter;
695: #endif
696: }
697:
698:
699:
700:
701: /*
702: * Callback function used when track is changed.
703: * We need to update the track data by calling CAPSLockTrack
704: */
705: #ifdef HAVE_CAPSIMAGE
706: static void IPF_CallBack_Trk ( struct CapsFdc *pc , CapsULong State )
707: {
708: int Drive = State; /* State is the drive number in that case */
709: struct CapsDrive *pd = pc->drive+Drive; /* Current drive where the track change occurred */
710: struct CapsTrackInfoT1 cti;
711:
712: cti.type=1;
713: if ( CAPSLockTrack ( &cti , IPF_State.CapsImage[ Drive ] , pd->buftrack , pd->bufside ,
714: DI_LOCK_DENALT|DI_LOCK_DENVAR|DI_LOCK_UPDATEFD|DI_LOCK_TYPE ) != imgeOk )
715: return;
716:
717: LOG_TRACE(TRACE_FDC, "fdc ipf callback trk drive=%d buftrack=%d bufside=%d VBL=%d HBL=%d\n" , Drive ,
718: (int)pd->buftrack , (int)pd->bufside , nVBLs , nHBL );
719:
720: pd->ttype = cti.type;
721: pd->trackbuf = cti.trackbuf;
722: pd->timebuf = cti.timebuf;
723: pd->tracklen = cti.tracklen;
724: pd->overlap = cti.overlap;
725: }
726: #endif
727:
728:
729:
730:
731: /*
732: * Callback function used when the FDC change the IRQ signal
733: */
734: #ifdef HAVE_CAPSIMAGE
735: static void IPF_CallBack_Irq ( struct CapsFdc *pc , CapsULong State )
736: {
737: LOG_TRACE(TRACE_FDC, "fdc ipf callback irq state=0x%x VBL=%d HBL=%d\n" , (int)State , nVBLs , nHBL );
738:
739: if ( State )
740: FDC_SetIRQ ( FDC_IRQ_SOURCE_OTHER ); /* IRQ bit was set */
741: else
742: FDC_ClearIRQ (); /* IRQ bit was reset */
743: }
744: #endif
745:
746:
747:
748:
749: /*
750: * Callback function used when the FDC change the DRQ signal
751: * -> copy the byte to/from the DMA's FIFO if it's a read or a write to the disk
752: */
753: #ifdef HAVE_CAPSIMAGE
754: static void IPF_CallBack_Drq ( struct CapsFdc *pc , CapsULong State )
755: {
756: Uint8 Byte;
757:
758: if ( State == 0 )
759: return; /* DRQ bit was reset, do nothing */
760:
761: if ( FDC_DMA_GetModeControl_R_WR () != 0 ) /* DMA write mode */
762: {
763: Byte = FDC_DMA_FIFO_Pull (); /* Get a byte from the DMA FIFO */
764: CAPSFdcWrite ( &IPF_State.Fdc , 3 , Byte ); /* Write to FDC's reg 3 */
765:
766: 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 );
767: }
768:
769: else /* DMA read mode */
770: {
771: Byte = CAPSFdcRead ( &IPF_State.Fdc , 3 ); /* Read from FDC's reg 3 */
772: FDC_DMA_FIFO_Push ( Byte ); /* Add byte to the DMA FIFO */
773:
774: 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 );
775: }
776: }
777: #endif
778:
779:
780:
781: /*
782: * This function is used to enable/disable a drive when
783: * using the UI or command line parameters
784: *
785: * NOTE : for now, IPF only supports changing drive 1, drive 0
786: * is always ON.
787: */
788: void IPF_Drive_Set_Enable ( int Drive , bool value )
789: {
790: #ifndef HAVE_CAPSIMAGE
791: return;
792:
793: #else
794: IPF_State.DriveEnabled[ Drive ] = value; /* Store the new state */
795:
796: IPF_Drive_Update_Enable_Side (); /* Update IPF's internal state */
797: #endif
798: }
799:
800:
801: /*
802: * This function is used to configure a drive as single sided
803: * or double sided when using the UI or command line parameters
804: */
805: void IPF_Drive_Set_DoubleSided ( int Drive , bool value )
806: {
807: #ifndef HAVE_CAPSIMAGE
808: return;
809:
810: #else
811: IPF_State.DoubleSided[ Drive ] = value; /* Store the new state */
812:
813: IPF_Drive_Update_Enable_Side (); /* Update IPF's internal state */
814: #endif
815: }
816:
817:
818: /*
819: * Update IPF's internal state depending on which drives are ON or OFF
820: * and if the drive is single or double sided (for capslib >= 5.1)
821: */
822: #ifdef HAVE_CAPSIMAGE
823: static void IPF_Drive_Update_Enable_Side ( void )
824: {
1.1.1.2 root 825: #if CAPS_LIB_REL_REV >= 501
1.1 root 826: int i;
1.1.1.2 root 827: #endif
1.1 root 828:
829: if ( IPF_State.DriveEnabled[ 1 ] )
830: IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES; /* Should be 2 */
831: else
832: IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES - 1; /* Should be 1 */
833:
834: #if CAPS_LIB_REL_REV >= 501
835: for ( i=0 ; i < MAX_FLOPPYDRIVES ; i++ )
836: {
837: if ( IPF_State.DoubleSided[ i ] )
838: IPF_State.Drive[ i ].diskattr &= ~CAPSDRIVE_DA_SS; /* Double sided */
839: else
840: IPF_State.Drive[ i ].diskattr |= CAPSDRIVE_DA_SS; /* Single sided */
841: }
842: #endif
843: }
844: #endif
845:
846:
847: /*
848: * Set the drive and the side to be used for the next FDC commands
849: * io_porta_old is the previous value, io_porta_new is the new value
850: * to take into account.
851: * We report a side change only when a drive is selected.
852: */
853: void IPF_SetDriveSide ( Uint8 io_porta_old , Uint8 io_porta_new )
854: {
855: #ifndef HAVE_CAPSIMAGE
856: return;
857:
858: #else
859: int Side;
860:
861: 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 );
862:
863: Side = ( (~io_porta_new) & 0x01 ); /* Side 0 or 1 */
864:
865: IPF_State.Fdc.drivenew = -1; /* By default, don't select any drive */
866:
867: /* Check drive 1 first */
868: if ( ( io_porta_new & 0x04 ) == 0 )
869: {
870: IPF_State.Drive[ 1 ].newside = Side;
871: IPF_State.Fdc.drivenew = 1; /* Select drive 1 */
872: }
873:
874: /* If both drive 0 and drive 1 are enabled, we keep only drive 0 as newdrive */
875: if ( ( io_porta_new & 0x02 ) == 0 )
876: {
877: IPF_State.Drive[ 0 ].newside = Side;
878: IPF_State.Fdc.drivenew = 0; /* Select drive 0 (and un-select drive 1 if set above) */
879: }
880:
881: IPF_Emulate(); /* Update emulation's state up to this point, then set new drive/side */
882: #endif
883: }
884:
885:
886:
887:
888: /*
889: * Write a byte into one of the FDC registers
890: * 0=command 1=track 2=sector 3=data
891: */
892: void IPF_FDC_WriteReg ( Uint8 Reg , Uint8 Byte )
893: {
894: #ifndef HAVE_CAPSIMAGE
895: return; /* This should not be reached (an IPF image can't be inserted without capsimage) */
896:
897: #else
1.1.1.4 ! root 898: if ( Reg == 0 ) /* more detailed logs for command register */
! 899: IPF_FDC_LogCommand ( Byte );
! 900: else
! 901: LOG_TRACE(TRACE_FDC, "fdc ipf write reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL );
1.1 root 902:
903: #if CAPS_LIB_REL_REV >= 501
904: /* In the case of CTR images, we must reset the revolution counter */
905: /* when a command access data on disk and track/side changed since last access */
906: if ( Reg == 0 )
907: {
908: int Type;
909: int Drive;
910:
911: Type = FDC_GetCmdType ( Byte );
912: if ( ( Type == 2 ) || ( Type == 3 ) )
913: {
914: Drive = IPF_State.Fdc.driveact;
915: if ( ( Drive >= 0 )
916: && ( ( IPF_State.Drive[ Drive ].side != IPF_State.Rev_Side[ Drive ] ) || ( IPF_State.Drive[ Drive ].track != IPF_State.Rev_Track[ Drive ] ) ) )
917: {
918: IPF_State.Rev_Side[ Drive ] = IPF_State.Drive[ Drive ].side;
919: IPF_State.Rev_Track[ Drive ] = IPF_State.Drive[ Drive ].track;
920: CAPSSetRevolution ( IPF_State.CapsImage[ Drive ] , 0 );
921: }
922: }
923: }
924: #endif
925:
926: IPF_Emulate(); /* Update emulation's state up to this point */
927:
928: CAPSFdcWrite ( &IPF_State.Fdc , Reg , Byte );
929: #endif
930: }
931:
932:
933:
934:
935: /*
936: * Read the content of one of the FDC registers
937: * 0=status 1=track 2=sector 3=data
938: */
939: Uint8 IPF_FDC_ReadReg ( Uint8 Reg )
940: {
941: #ifndef HAVE_CAPSIMAGE
942: return 0; /* This should not be reached (an IPF image can't be inserted without capsimage) */
943: #else
944: Uint8 Byte;
945:
946: IPF_Emulate(); /* Update emulation's state up to this point */
947:
948: Byte = CAPSFdcRead ( &IPF_State.Fdc , Reg );
949: LOG_TRACE(TRACE_FDC, "fdc ipf read reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL );
950:
951: return Byte;
952: #endif
953: }
954:
955:
956:
957:
958: /*
959: * Return the content of some registers to display them in the statusbar
960: * We should not call IPF_Emulate() or similar, reading should not change emulation's state
961: */
962: void IPF_FDC_StatusBar ( Uint8 *pCommand , Uint8 *pHead , Uint8 *pTrack , Uint8 *pSector , Uint8 *pSide )
963: {
964: #ifndef HAVE_CAPSIMAGE
965: return; /* This should not be reached (an IPF image can't be inserted without capsimage) */
966: #else
967: int Drive;
968:
969: Drive = IPF_State.Fdc.driveact;
970: if ( Drive < 0 ) /* If no drive enabled, use drive O for Head/Side */
971: Drive = 0;
972:
973: /* We read directly in the structures, to be sure we don't change emulation's state */
974: *pCommand = IPF_State.Fdc.r_command;
975: *pHead = IPF_State.Drive[ Drive ].track;
976: *pTrack = IPF_State.Fdc.r_track;
977: *pSector = IPF_State.Fdc.r_sector;
978: *pSide = IPF_State.Drive[ Drive ].side;
979: #endif
980: }
981:
982:
983:
1.1.1.4 ! root 984: #ifdef HAVE_CAPSIMAGE
! 985: static void IPF_FDC_LogCommand ( Uint8 Command )
! 986: {
! 987: Uint8 Head , Track , Sector , Side , DataReg;
! 988: int Drive;
! 989: int FrameCycles, HblCounterVideo, LineCycles;
! 990: char buf[ 200 ];
! 991:
! 992:
! 993: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
! 994:
! 995: Drive = IPF_State.Fdc.driveact;
! 996: if ( Drive < 0 ) /* If no drive enabled, use drive O for Head/Side */
! 997: Drive = 0;
! 998:
! 999: /* We read directly in the structures, to be sure we don't change emulation's state */
! 1000: Head = IPF_State.Drive[ Drive ].track;
! 1001: Track = IPF_State.Fdc.r_track;
! 1002: Sector = IPF_State.Fdc.r_sector;
! 1003: DataReg = IPF_State.Fdc.r_data;
! 1004: Side = IPF_State.Drive[ Drive ].side;
! 1005:
! 1006: if ( ( Command & 0xf0 ) == 0x00 ) /* Restore */
! 1007: sprintf ( buf , "type I restore spinup=%s verify=%s steprate=%d drive=%d tr=0x%x head_track=0x%x" ,
! 1008: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
! 1009: ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
! 1010: FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
! 1011:
! 1012: else if ( ( Command & 0xf0 ) == 0x10 ) /* Seek */
! 1013: sprintf ( buf , "type I seek dest_track=0x%x spinup=%s verify=%s steprate=%d drive=%d tr=0x%x head_track=0x%x" ,
! 1014: DataReg , ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
! 1015: ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
! 1016: FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
! 1017:
! 1018: else if ( ( Command & 0xe0 ) == 0x20 ) /* Step */
! 1019: sprintf ( buf , "type I step %d spinup=%s verify=%s steprate_ms=%d drive=%d tr=0x%x head_track=0x%x",
! 1020: ( IPF_State.Fdc.lineout & CAPSFDC_LO_DIRC ) ? 1 : -1 ,
! 1021: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
! 1022: ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
! 1023: FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
! 1024:
! 1025: else if ( ( Command & 0xe0 ) == 0x40 ) /* Step In */
! 1026: sprintf ( buf , "type I step in spinup=%s verify=%s steprate=%d drive=%d tr=0x%x head_track=0x%x" ,
! 1027: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
! 1028: ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
! 1029: FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
! 1030:
! 1031: else if ( ( Command & 0xe0 ) == 0x60 ) /* Step Out */
! 1032: sprintf ( buf , "type I step out spinup=%s verify=%s steprate=%d drive=%d tr=0x%x head_track=0x%x" ,
! 1033: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
! 1034: ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
! 1035: FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
! 1036:
! 1037: else if ( ( Command & 0xe0 ) == 0x80 ) /* Read Sector */
! 1038: sprintf ( buf , "type II read sector sector=0x%x multi=%s spinup=%s settle=%s tr=0x%x head_track=0x%x"
! 1039: " side=%d drive=%d dmasector=%d addr=0x%x",
! 1040: Sector, ( Command & FDC_COMMAND_BIT_MULTIPLE_SECTOR ) ? "on" : "off" ,
! 1041: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
! 1042: ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
! 1043: Track , Head , Side , Drive , FDC_DMA_GetSectorCount() , FDC_GetDMAAddress() );
! 1044:
! 1045: else if ( ( Command & 0xe0 ) == 0xa0 ) /* Write Sector */
! 1046: sprintf ( buf , "type II write sector sector=0x%x multi=%s spinup=%s settle=%s tr=0x%x head_track=0x%x"
! 1047: " side=%d drive=%d dmasector=%d addr=0x%x",
! 1048: Sector, ( Command & FDC_COMMAND_BIT_MULTIPLE_SECTOR ) ? "on" : "off" ,
! 1049: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
! 1050: ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
! 1051: Track , Head , Side , Drive , FDC_DMA_GetSectorCount() , FDC_GetDMAAddress() );
! 1052:
! 1053: else if ( ( Command & 0xf0 ) == 0xc0 ) /* Read Address */
! 1054: sprintf ( buf , "type III read address spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x" ,
! 1055: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
! 1056: ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
! 1057: Track , Head , Side , Drive , FDC_GetDMAAddress() );
! 1058:
! 1059: else if ( ( Command & 0xf0 ) == 0xe0 ) /* Read Track */
! 1060: sprintf ( buf , "type III read track spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x" ,
! 1061: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
! 1062: ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
! 1063: Track , Head , Side , Drive , FDC_GetDMAAddress() );
! 1064:
! 1065: else if ( ( Command & 0xf0 ) == 0xf0 ) /* Write Track */
! 1066: sprintf ( buf , "type III write track spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x" ,
! 1067: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
! 1068: ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
! 1069: Track , Head , Side , Drive , FDC_GetDMAAddress() );
! 1070:
! 1071: else /* Force Int */
! 1072: sprintf ( buf , "type IV force int 0x%x irq=%d index=%d" ,
! 1073: Command , ( Command & 0x8 ) >> 3 , ( Command & 0x4 ) >> 2 );
! 1074:
! 1075:
! 1076: LOG_TRACE(TRACE_FDC, "fdc ipf %s VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
! 1077: buf , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
! 1078: }
! 1079: #endif
! 1080:
! 1081:
1.1 root 1082:
1083: /*
1084: * Run the FDC emulation during NbCycles cycles (relative to the 8MHz FDC's clock)
1085: */
1086: void IPF_Emulate ( void )
1087: {
1088: #ifndef HAVE_CAPSIMAGE
1089: return;
1090:
1091: #else
1092: int NbCycles;
1093: int Drive;
1094:
1095: NbCycles = CyclesGlobalClockCounter - IPF_State.FdcClock; /* Number of cycles since last emulation */
1096: if ( NbCycles < 0 )
1097: NbCycles = 0; /* We should call CAPSFdcEmulate even when NbCycles=0 */
1098:
1099: // LOG_TRACE(TRACE_FDC, "fdc ipf emulate cycles=%d VBL=%d HBL=%d clock=%lld\n" , NbCycles , nVBLs , nHBL , CyclesGlobalClockCounter );
1100:
1101: /* Update Write Protect status for each drive */
1102: for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
1103: if ( Floppy_IsWriteProtected ( Drive ) )
1104: IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_WP; /* Disk write protected */
1105: else
1106: IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_WP; /* Disk is not write protected */
1107:
1108:
1109: CAPSFdcEmulate ( &IPF_State.Fdc , NbCycles ); /* Process at max NbCycles */
1110: IPF_State.FdcClock += IPF_State.Fdc.clockact; /* clockact can be < NbCycle in some cases */
1111:
1112: /* Update UI's LEDs depending on Status Register */
1113: FDC_Drive_Set_BusyLed ( (IPF_State.Fdc.r_st0 & ~IPF_State.Fdc.r_stm) | (IPF_State.Fdc.r_st1 & IPF_State.Fdc.r_stm) );
1114: #endif
1115: }
1116:
1117:
1118:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.