|
|
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: {
1.1.1.5 ! root 138: Log_AlertDlg(LOG_ERROR, "Hatari built with IPF floppy support, but no IPF data in memory snapshot -> skip");
1.1 root 139: return; /* Continue restoring the rest of the memory snapshot */
140: }
141: else if ( ( StructSize > 0 ) && ( sizeof ( IPF_State ) == 0 ) )
142: {
1.1.1.5 ! root 143: Log_AlertDlg(LOG_ERROR, "Memory snapshot with IPF floppy data, but Hatari built without IPF support -> skip");
1.1 root 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: {
1.1.1.5 ! root 149: Log_AlertDlg(LOG_ERROR, "Memory snapshot IPF floppy data incompatible with this Hatari version -> skip");
1.1 root 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.1.5 ! root 213: Log_Printf ( LOG_DEBUG , "ipf load ok\n" );
1.1 root 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
1.1.1.5 ! root 283: Log_AlertDlg(LOG_ERROR, "Hatari built without IPF support -> can't handle floppy image");
1.1 root 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:
1.1.1.5 ! root 330: Log_Printf ( LOG_DEBUG , "IPF : IPF_Init\n" );
1.1 root 331:
332: if ( CAPSInit() != imgeOk )
333: {
1.1.1.5 ! root 334: Log_Printf ( LOG_ERROR , "IPF : Could not initialize the capsimage library\n" );
1.1 root 335: return false;
336: }
337:
338: if ( CAPSGetVersionInfo ( &caps_vi , 0 ) != imgeOk )
339: {
1.1.1.5 ! root 340: Log_Printf ( LOG_ERROR , "IPF : CAPSVersionInfo failed\n" );
1.1 root 341: return false;
342: }
1.1.1.5 ! root 343: Log_Printf ( LOG_INFO , "IPF : capsimage library version release=%d revision=%d\n" , (int)caps_vi.release , (int)caps_vi.revision );
1.1 root 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: {
1.1.1.5 ! root 373: Log_Printf ( LOG_ERROR , "IPF : CAPSFdcInit failed\n" );
1.1 root 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;
1.1.1.5 ! root 424: const char *ImageTypeStr;
! 425: bool Type_OK;
! 426:
1.1 root 427:
428: ImageId = CAPSAddImage();
429: if ( ImageId < 0 )
430: {
1.1.1.5 ! root 431: Log_Printf ( LOG_ERROR , "IPF : error CAPSAddImage\n" );
1.1 root 432: return false;
433: }
434:
435: #if CAPS_LIB_REL_REV >= 501
436: ImageType = CAPSGetImageTypeMemory ( pImageBuffer , ImageSize );
437: if ( ImageType == citError )
438: {
1.1.1.5 ! root 439: Log_Printf ( LOG_ERROR , "IPF : error CAPSGetImageTypeMemory\n" );
1.1.1.4 root 440: CAPSRemImage ( ImageId ) ;
1.1 root 441: return false;
442: }
443: else if ( ImageType == citUnknown )
444: {
1.1.1.5 ! root 445: Log_Printf ( LOG_ERROR , "IPF : unknown image type\n" );
1.1.1.4 root 446: CAPSRemImage ( ImageId ) ;
1.1 root 447: return false;
448: }
449:
1.1.1.5 ! root 450: Type_OK = true;
1.1 root 451: switch ( ImageType ) {
1.1.1.5 ! root 452: case citIPF: ImageTypeStr = "IPF"; break;
! 453: case citCTRaw: ImageTypeStr = "CT RAW"; break;
! 454: case citKFStream: ImageTypeStr = "KF STREAM" ; break;
! 455: case citDraft: ImageTypeStr = "DRAFT" ; break;
! 456: default : ImageTypeStr = "NOT SUPPORTED\n";
! 457: Type_OK = false;
1.1 root 458: }
1.1.1.5 ! root 459: Log_Printf ( LOG_INFO , "IPF : IPF_Insert drive=%d buf=%p size=%ld imageid=%d type=%s\n" , Drive , pImageBuffer , ImageSize , ImageId , ImageTypeStr );
! 460:
! 461: if ( !Type_OK )
! 462: {
! 463: CAPSRemImage ( ImageId ) ;
! 464: return false;
! 465: }
! 466:
1.1.1.4 root 467:
468: /* Special case for RAW stream image, we load all the tracks now */
469: if ( ImageType == citKFStream )
470: {
471: if ( IPF_Insert_RawStreamImage ( Drive ) == false )
472: {
1.1.1.5 ! root 473: Log_Printf ( LOG_ERROR , "IPF : can't load raw stream files\n" );
1.1.1.4 root 474: CAPSRemImage ( ImageId ) ;
475: return false;
476: }
477: }
478:
479: #else
480: ImageType = -1;
1.1 root 481: #endif
482:
483: if ( CAPSLockImageMemory ( ImageId , pImageBuffer , (CapsULong)ImageSize , DI_LOCK_MEMREF ) == imgeOk )
484: {
485: struct CapsImageInfo cii;
486: int i;
487:
488: /* Print some debug infos */
489: if ( CAPSGetImageInfo ( &cii , ImageId ) == imgeOk )
490: {
491: printf("Type: %d\n", (int)cii.type);
492: printf("Release: %d\n", (int)cii.release);
493: printf("Revision: %d\n", (int)cii.revision);
494: printf("Min Cylinder: %d\n", (int)cii.mincylinder);
495: printf("Max Cylinder: %d\n", (int)cii.maxcylinder);
496: printf("Min Head: %d\n", (int)cii.minhead);
497: printf("Max Head: %d\n", (int)cii.maxhead);
498: 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);
499: printf("Platforms:");
500: for (i = 0; i < CAPS_MAXPLATFORM; i++)
501: if (cii.platform[i] != ciipNA)
502: printf ( " %s" , CAPSGetPlatformName(cii.platform[i]) );
503: printf("\n");
504:
505: /* Some IPF disks are not correctly supported yet : display a warning */
506: if ( (int)cii.release == 3222 ) /* Sundog */
507: Log_AlertDlg ( LOG_INFO , "'Sundog' is not correctly supported yet, it requires write access." );
508: else if ( (int)cii.release == 3058 ) /* Lethal Xcess */
509: Log_AlertDlg ( LOG_INFO , "'Lethal Xcess' is not correctly supported yet, protection will fail" );
510: }
511: }
512: else
513: {
514: CAPSRemImage ( ImageId ) ;
515: return false;
516: }
517:
518: if ( CAPSLoadImage ( ImageId , DI_LOCK_DENALT | DI_LOCK_DENVAR | DI_LOCK_UPDATEFD ) != imgeOk )
519: {
1.1.1.5 ! root 520: Log_Printf ( LOG_ERROR , "IPF : error CAPSLoadImage\n" );
1.1 root 521: CAPSUnlockImage ( ImageId );
522: CAPSRemImage ( ImageId ) ;
523: return false;
524: }
525:
526:
527: IPF_State.CapsImage[ Drive ] = ImageId;
1.1.1.4 root 528: IPF_State.CapsImageType[ Drive ] = ImageType;
1.1 root 529:
530: IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_IN; /* Disk inserted, keep the value for "write protect" */
531:
532: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive ); /* Invalidate previous buffered track data for drive, if any */
533:
534: IPF_State.Rev_Track[ Drive ] = -1; /* Invalidate previous track/side to handle revolution's count */
535: IPF_State.Rev_Side[ Drive ] = -1;
536:
537: return true;
538: #endif
539: }
540:
541:
1.1.1.4 root 542: /*
543: * Load all the raw stream files for all tracks/sides of a dump.
544: * We use the filename of the raw file in drive 'Drive' as a template
545: * where we replace track and side will all the possible values.
546: */
547: #ifdef HAVE_CAPSIMAGE
548: static bool IPF_Insert_RawStreamImage ( int Drive )
549: {
550: int Track , Side;
551: char TrackFileName[ FILENAME_MAX ];
552: char *TrackSide_pointer;
553: char TrackSide_buf[ 4 + 1 ]; /* "tt.s" + \0 */
554: int TrackCount;
555: int TrackCount_0 , TrackCount_1;
556: Uint8 *p;
557: long Size;
558:
559:
560: return true; /* This function is not used for now, always return true */
561: /* Ensure the previous tracks are removed from memory */
562: IPF_Eject_RawStreamImage ( Drive );
563:
564:
565: /* Get the path+filename of the raw file that was inserted in 'Drive' */
566: /* then parse it to find the part with track/side */
567: strcpy ( TrackFileName , ConfigureParams.DiskImage.szDiskFileName[Drive] );
568:
569: TrackSide_pointer = IPF_FilenameFindTrackSide ( TrackFileName );
570: if ( TrackSide_pointer == NULL )
571: {
1.1.1.5 ! root 572: Log_Printf ( LOG_ERROR , "IPF : error parsing track/side in raw filename\n" );
1.1.1.4 root 573: return false;
574: }
575:
576: /* We try to load all the tracks for all the sides */
577: /* We ignore errors, as some tracks/side can really be missing from the image dump */
578: TrackCount = 0;
579: TrackCount_0 = 0;
580: TrackCount_1 = 0;
581: for ( Track=0 ; Track<IPF_MAX_TRACK_RAW_STREAM_IMAGE ; Track++ )
582: {
583: for ( Side=0 ; Side<IPF_MAX_SIDE_RAW_STREAM_IMAGE ; Side++ )
584: {
585: sprintf ( TrackSide_buf , "%02d.%d" , Track , Side );
586: memcpy ( TrackSide_pointer , TrackSide_buf , 4 );
1.1.1.5 ! root 587: Log_Printf ( LOG_INFO , "IPF : insert raw stream drive=%d track=%d side=%d %s\n" , Drive , Track , Side , TrackFileName );
1.1.1.4 root 588:
589: p = File_Read ( TrackFileName , &Size , NULL);
590: if ( p )
591: {
592: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = p;
593: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize = Size;
594: TrackCount++;
595: if ( Side==0 ) TrackCount_0++;
596: else TrackCount_1++;
597: }
598: else
599: {
1.1.1.5 ! root 600: Log_Printf ( LOG_INFO , "IPF : insert raw stream drive=%d track=%d side=%d %s -> not found\n" , Drive , Track , Side , TrackFileName );
1.1.1.4 root 601: /* File not loaded : either this track really doesn't exist or there was a system error */
602: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = NULL;
603: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize = 0;
604: }
605: }
606: }
607:
608:
609: /* If we didn't load any track, there's a problem, we stop here */
610: if ( TrackCount == 0 )
611: {
1.1.1.5 ! root 612: Log_Printf ( LOG_WARN , "IPF : error, no raw track file could be loaded for %s\n" , ConfigureParams.DiskImage.szDiskFileName[Drive] );
1.1.1.4 root 613: /* Free all the tracks that were loaded so far */
614: IPF_Eject_RawStreamImage ( Drive );
615: return false;
616: }
617:
1.1.1.5 ! root 618: Log_Printf ( LOG_INFO , "IPF : insert raw stream drive=%d, loaded %d tracks for side 0 and %d tracks for side 1\n", Drive, TrackCount_0, TrackCount_1 );
1.1.1.4 root 619:
620: return true;
621: }
622: #endif
623:
1.1 root 624:
625:
626: /*
627: * When ejecting a disk, free the ressources associated with an IPF image
628: */
629: bool IPF_Eject ( int Drive )
630: {
631: #ifndef HAVE_CAPSIMAGE
632: return false;
633:
634: #else
1.1.1.5 ! root 635: Log_Printf ( LOG_DEBUG , "IPF : IPF_Eject drive=%d imageid=%d\n" , Drive , IPF_State.CapsImage[ Drive ] );
1.1 root 636:
637: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive ); /* Invalidate previous buffered track data for drive, if any */
638:
639: if ( CAPSUnlockImage ( IPF_State.CapsImage[ Drive ] ) < 0 )
640: {
1.1.1.5 ! root 641: Log_Printf ( LOG_ERROR , "IPF : error CAPSUnlockImage\n" );
1.1 root 642: return false;
643: }
644:
645: if ( CAPSRemImage ( IPF_State.CapsImage[ Drive ] ) < 0 )
646: {
1.1.1.5 ! root 647: Log_Printf ( LOG_ERROR , "IPF : error CAPSRemImage\n" );
1.1 root 648: return false;
649: }
650:
1.1.1.4 root 651: /* Special case for RAW stream image, we must free all the tracks */
652: if ( IPF_State.CapsImageType[ Drive ] == citKFStream )
653: IPF_Eject_RawStreamImage ( Drive );
654:
1.1 root 655: IPF_State.CapsImage[ Drive ] = -1;
1.1.1.4 root 656: IPF_State.CapsImageType[ Drive ] = -1;
1.1 root 657:
658: IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_IN;
659:
660: return true;
661: #endif
662: }
663:
664:
1.1.1.4 root 665: /*
666: * When ejecting a RAW stream image we must free all the individual tracks
667: */
668: static bool IPF_Eject_RawStreamImage ( int Drive )
669: {
670: #ifndef HAVE_CAPSIMAGE
671: return true;
672:
673: #else
674: int Track , Side;
675:
676: return true; /* This function is not used for now, always return true */
677: for ( Track=0 ; Track<IPF_MAX_TRACK_RAW_STREAM_IMAGE ; Track++ )
678: for ( Side=0 ; Side<IPF_MAX_SIDE_RAW_STREAM_IMAGE ; Side++ )
679: {
680: if ( IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData != NULL )
681: {
1.1.1.5 ! root 682: Log_Printf ( LOG_DEBUG , "IPF : eject raw stream drive=%d track=%d side=%d\n" , Drive , Track , Side );
1.1.1.4 root 683: free ( IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData );
684: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = NULL;
685: IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize = 0;
686: }
687: }
688:
689: return true;
690: #endif
691: }
692:
693:
1.1 root 694:
695:
696: /*
697: * Reset FDC state when a reset signal was received
698: */
699: void IPF_Reset ( void )
700: {
701: #ifdef HAVE_CAPSIMAGE
702: CAPSFdcReset ( &IPF_State.Fdc );
703:
704: IPF_State.FdcClock = CyclesGlobalClockCounter;
705: #endif
706: }
707:
708:
709:
710:
711: /*
712: * Callback function used when track is changed.
713: * We need to update the track data by calling CAPSLockTrack
714: */
715: #ifdef HAVE_CAPSIMAGE
716: static void IPF_CallBack_Trk ( struct CapsFdc *pc , CapsULong State )
717: {
718: int Drive = State; /* State is the drive number in that case */
719: struct CapsDrive *pd = pc->drive+Drive; /* Current drive where the track change occurred */
720: struct CapsTrackInfoT1 cti;
721:
722: cti.type=1;
723: if ( CAPSLockTrack ( &cti , IPF_State.CapsImage[ Drive ] , pd->buftrack , pd->bufside ,
724: DI_LOCK_DENALT|DI_LOCK_DENVAR|DI_LOCK_UPDATEFD|DI_LOCK_TYPE ) != imgeOk )
725: return;
726:
727: LOG_TRACE(TRACE_FDC, "fdc ipf callback trk drive=%d buftrack=%d bufside=%d VBL=%d HBL=%d\n" , Drive ,
728: (int)pd->buftrack , (int)pd->bufside , nVBLs , nHBL );
729:
730: pd->ttype = cti.type;
731: pd->trackbuf = cti.trackbuf;
732: pd->timebuf = cti.timebuf;
733: pd->tracklen = cti.tracklen;
734: pd->overlap = cti.overlap;
735: }
736: #endif
737:
738:
739:
740:
741: /*
742: * Callback function used when the FDC change the IRQ signal
743: */
744: #ifdef HAVE_CAPSIMAGE
745: static void IPF_CallBack_Irq ( struct CapsFdc *pc , CapsULong State )
746: {
747: LOG_TRACE(TRACE_FDC, "fdc ipf callback irq state=0x%x VBL=%d HBL=%d\n" , (int)State , nVBLs , nHBL );
748:
749: if ( State )
750: FDC_SetIRQ ( FDC_IRQ_SOURCE_OTHER ); /* IRQ bit was set */
751: else
752: FDC_ClearIRQ (); /* IRQ bit was reset */
753: }
754: #endif
755:
756:
757:
758:
759: /*
760: * Callback function used when the FDC change the DRQ signal
761: * -> copy the byte to/from the DMA's FIFO if it's a read or a write to the disk
762: */
763: #ifdef HAVE_CAPSIMAGE
764: static void IPF_CallBack_Drq ( struct CapsFdc *pc , CapsULong State )
765: {
766: Uint8 Byte;
767:
768: if ( State == 0 )
769: return; /* DRQ bit was reset, do nothing */
770:
771: if ( FDC_DMA_GetModeControl_R_WR () != 0 ) /* DMA write mode */
772: {
773: Byte = FDC_DMA_FIFO_Pull (); /* Get a byte from the DMA FIFO */
774: CAPSFdcWrite ( &IPF_State.Fdc , 3 , Byte ); /* Write to FDC's reg 3 */
775:
776: 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 );
777: }
778:
779: else /* DMA read mode */
780: {
781: Byte = CAPSFdcRead ( &IPF_State.Fdc , 3 ); /* Read from FDC's reg 3 */
782: FDC_DMA_FIFO_Push ( Byte ); /* Add byte to the DMA FIFO */
783:
784: 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 );
785: }
786: }
787: #endif
788:
789:
790:
791: /*
792: * This function is used to enable/disable a drive when
793: * using the UI or command line parameters
794: *
795: * NOTE : for now, IPF only supports changing drive 1, drive 0
796: * is always ON.
797: */
798: void IPF_Drive_Set_Enable ( int Drive , bool value )
799: {
800: #ifndef HAVE_CAPSIMAGE
801: return;
802:
803: #else
804: IPF_State.DriveEnabled[ Drive ] = value; /* Store the new state */
805:
806: IPF_Drive_Update_Enable_Side (); /* Update IPF's internal state */
807: #endif
808: }
809:
810:
811: /*
812: * This function is used to configure a drive as single sided
813: * or double sided when using the UI or command line parameters
814: */
815: void IPF_Drive_Set_DoubleSided ( int Drive , bool value )
816: {
817: #ifndef HAVE_CAPSIMAGE
818: return;
819:
820: #else
821: IPF_State.DoubleSided[ Drive ] = value; /* Store the new state */
822:
823: IPF_Drive_Update_Enable_Side (); /* Update IPF's internal state */
824: #endif
825: }
826:
827:
828: /*
829: * Update IPF's internal state depending on which drives are ON or OFF
830: * and if the drive is single or double sided (for capslib >= 5.1)
831: */
832: #ifdef HAVE_CAPSIMAGE
833: static void IPF_Drive_Update_Enable_Side ( void )
834: {
1.1.1.2 root 835: #if CAPS_LIB_REL_REV >= 501
1.1 root 836: int i;
1.1.1.2 root 837: #endif
1.1 root 838:
839: if ( IPF_State.DriveEnabled[ 1 ] )
840: IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES; /* Should be 2 */
841: else
842: IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES - 1; /* Should be 1 */
843:
844: #if CAPS_LIB_REL_REV >= 501
845: for ( i=0 ; i < MAX_FLOPPYDRIVES ; i++ )
846: {
847: if ( IPF_State.DoubleSided[ i ] )
848: IPF_State.Drive[ i ].diskattr &= ~CAPSDRIVE_DA_SS; /* Double sided */
849: else
850: IPF_State.Drive[ i ].diskattr |= CAPSDRIVE_DA_SS; /* Single sided */
851: }
852: #endif
853: }
854: #endif
855:
856:
857: /*
858: * Set the drive and the side to be used for the next FDC commands
859: * io_porta_old is the previous value, io_porta_new is the new value
860: * to take into account.
861: * We report a side change only when a drive is selected.
862: */
863: void IPF_SetDriveSide ( Uint8 io_porta_old , Uint8 io_porta_new )
864: {
865: #ifndef HAVE_CAPSIMAGE
866: return;
867:
868: #else
869: int Side;
870:
871: 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 );
872:
873: Side = ( (~io_porta_new) & 0x01 ); /* Side 0 or 1 */
874:
875: IPF_State.Fdc.drivenew = -1; /* By default, don't select any drive */
876:
877: /* Check drive 1 first */
878: if ( ( io_porta_new & 0x04 ) == 0 )
879: {
880: IPF_State.Drive[ 1 ].newside = Side;
881: IPF_State.Fdc.drivenew = 1; /* Select drive 1 */
882: }
883:
884: /* If both drive 0 and drive 1 are enabled, we keep only drive 0 as newdrive */
885: if ( ( io_porta_new & 0x02 ) == 0 )
886: {
887: IPF_State.Drive[ 0 ].newside = Side;
888: IPF_State.Fdc.drivenew = 0; /* Select drive 0 (and un-select drive 1 if set above) */
889: }
890:
891: IPF_Emulate(); /* Update emulation's state up to this point, then set new drive/side */
892: #endif
893: }
894:
895:
896:
897:
898: /*
899: * Write a byte into one of the FDC registers
900: * 0=command 1=track 2=sector 3=data
901: */
902: void IPF_FDC_WriteReg ( Uint8 Reg , Uint8 Byte )
903: {
904: #ifndef HAVE_CAPSIMAGE
905: return; /* This should not be reached (an IPF image can't be inserted without capsimage) */
906:
907: #else
1.1.1.4 root 908: if ( Reg == 0 ) /* more detailed logs for command register */
909: IPF_FDC_LogCommand ( Byte );
910: else
911: LOG_TRACE(TRACE_FDC, "fdc ipf write reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL );
1.1 root 912:
913: #if CAPS_LIB_REL_REV >= 501
914: /* In the case of CTR images, we must reset the revolution counter */
915: /* when a command access data on disk and track/side changed since last access */
916: if ( Reg == 0 )
917: {
918: int Type;
919: int Drive;
920:
921: Type = FDC_GetCmdType ( Byte );
922: if ( ( Type == 2 ) || ( Type == 3 ) )
923: {
924: Drive = IPF_State.Fdc.driveact;
925: if ( ( Drive >= 0 )
926: && ( ( IPF_State.Drive[ Drive ].side != IPF_State.Rev_Side[ Drive ] ) || ( IPF_State.Drive[ Drive ].track != IPF_State.Rev_Track[ Drive ] ) ) )
927: {
928: IPF_State.Rev_Side[ Drive ] = IPF_State.Drive[ Drive ].side;
929: IPF_State.Rev_Track[ Drive ] = IPF_State.Drive[ Drive ].track;
930: CAPSSetRevolution ( IPF_State.CapsImage[ Drive ] , 0 );
931: }
932: }
933: }
934: #endif
935:
936: IPF_Emulate(); /* Update emulation's state up to this point */
937:
938: CAPSFdcWrite ( &IPF_State.Fdc , Reg , Byte );
939: #endif
940: }
941:
942:
943:
944:
945: /*
946: * Read the content of one of the FDC registers
947: * 0=status 1=track 2=sector 3=data
948: */
949: Uint8 IPF_FDC_ReadReg ( Uint8 Reg )
950: {
951: #ifndef HAVE_CAPSIMAGE
952: return 0; /* This should not be reached (an IPF image can't be inserted without capsimage) */
953: #else
954: Uint8 Byte;
955:
956: IPF_Emulate(); /* Update emulation's state up to this point */
957:
958: Byte = CAPSFdcRead ( &IPF_State.Fdc , Reg );
959: LOG_TRACE(TRACE_FDC, "fdc ipf read reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL );
960:
961: return Byte;
962: #endif
963: }
964:
965:
966:
967:
968: /*
969: * Return the content of some registers to display them in the statusbar
970: * We should not call IPF_Emulate() or similar, reading should not change emulation's state
971: */
972: void IPF_FDC_StatusBar ( Uint8 *pCommand , Uint8 *pHead , Uint8 *pTrack , Uint8 *pSector , Uint8 *pSide )
973: {
974: #ifndef HAVE_CAPSIMAGE
975: return; /* This should not be reached (an IPF image can't be inserted without capsimage) */
976: #else
977: int Drive;
978:
979: Drive = IPF_State.Fdc.driveact;
980: if ( Drive < 0 ) /* If no drive enabled, use drive O for Head/Side */
981: Drive = 0;
982:
983: /* We read directly in the structures, to be sure we don't change emulation's state */
984: *pCommand = IPF_State.Fdc.r_command;
985: *pHead = IPF_State.Drive[ Drive ].track;
986: *pTrack = IPF_State.Fdc.r_track;
987: *pSector = IPF_State.Fdc.r_sector;
988: *pSide = IPF_State.Drive[ Drive ].side;
989: #endif
990: }
991:
992:
993:
1.1.1.4 root 994: #ifdef HAVE_CAPSIMAGE
995: static void IPF_FDC_LogCommand ( Uint8 Command )
996: {
997: Uint8 Head , Track , Sector , Side , DataReg;
998: int Drive;
999: int FrameCycles, HblCounterVideo, LineCycles;
1000: char buf[ 200 ];
1001:
1002:
1003: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1004:
1005: Drive = IPF_State.Fdc.driveact;
1006: if ( Drive < 0 ) /* If no drive enabled, use drive O for Head/Side */
1007: Drive = 0;
1008:
1009: /* We read directly in the structures, to be sure we don't change emulation's state */
1010: Head = IPF_State.Drive[ Drive ].track;
1011: Track = IPF_State.Fdc.r_track;
1012: Sector = IPF_State.Fdc.r_sector;
1013: DataReg = IPF_State.Fdc.r_data;
1014: Side = IPF_State.Drive[ Drive ].side;
1015:
1016: if ( ( Command & 0xf0 ) == 0x00 ) /* Restore */
1017: sprintf ( buf , "type I restore spinup=%s verify=%s steprate=%d drive=%d tr=0x%x head_track=0x%x" ,
1018: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
1019: ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
1020: FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
1021:
1022: else if ( ( Command & 0xf0 ) == 0x10 ) /* Seek */
1023: sprintf ( buf , "type I seek dest_track=0x%x spinup=%s verify=%s steprate=%d drive=%d tr=0x%x head_track=0x%x" ,
1024: DataReg , ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
1025: ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
1026: FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
1027:
1028: else if ( ( Command & 0xe0 ) == 0x20 ) /* Step */
1029: sprintf ( buf , "type I step %d spinup=%s verify=%s steprate_ms=%d drive=%d tr=0x%x head_track=0x%x",
1030: ( IPF_State.Fdc.lineout & CAPSFDC_LO_DIRC ) ? 1 : -1 ,
1031: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
1032: ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
1033: FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
1034:
1035: else if ( ( Command & 0xe0 ) == 0x40 ) /* Step In */
1036: sprintf ( buf , "type I step in spinup=%s verify=%s steprate=%d drive=%d tr=0x%x head_track=0x%x" ,
1037: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
1038: ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
1039: FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
1040:
1041: else if ( ( Command & 0xe0 ) == 0x60 ) /* Step Out */
1042: sprintf ( buf , "type I step out spinup=%s verify=%s steprate=%d drive=%d tr=0x%x head_track=0x%x" ,
1043: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
1044: ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
1045: FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
1046:
1047: else if ( ( Command & 0xe0 ) == 0x80 ) /* Read Sector */
1048: sprintf ( buf , "type II read sector sector=0x%x multi=%s spinup=%s settle=%s tr=0x%x head_track=0x%x"
1049: " side=%d drive=%d dmasector=%d addr=0x%x",
1050: Sector, ( Command & FDC_COMMAND_BIT_MULTIPLE_SECTOR ) ? "on" : "off" ,
1051: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
1052: ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
1053: Track , Head , Side , Drive , FDC_DMA_GetSectorCount() , FDC_GetDMAAddress() );
1054:
1055: else if ( ( Command & 0xe0 ) == 0xa0 ) /* Write Sector */
1056: sprintf ( buf , "type II write sector sector=0x%x multi=%s spinup=%s settle=%s tr=0x%x head_track=0x%x"
1057: " side=%d drive=%d dmasector=%d addr=0x%x",
1058: Sector, ( Command & FDC_COMMAND_BIT_MULTIPLE_SECTOR ) ? "on" : "off" ,
1059: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
1060: ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
1061: Track , Head , Side , Drive , FDC_DMA_GetSectorCount() , FDC_GetDMAAddress() );
1062:
1063: else if ( ( Command & 0xf0 ) == 0xc0 ) /* Read Address */
1064: sprintf ( buf , "type III read address spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x" ,
1065: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
1066: ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
1067: Track , Head , Side , Drive , FDC_GetDMAAddress() );
1068:
1069: else if ( ( Command & 0xf0 ) == 0xe0 ) /* Read Track */
1070: sprintf ( buf , "type III read track spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x" ,
1071: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
1072: ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
1073: Track , Head , Side , Drive , FDC_GetDMAAddress() );
1074:
1075: else if ( ( Command & 0xf0 ) == 0xf0 ) /* Write Track */
1076: sprintf ( buf , "type III write track spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x" ,
1077: ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
1078: ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
1079: Track , Head , Side , Drive , FDC_GetDMAAddress() );
1080:
1081: else /* Force Int */
1082: sprintf ( buf , "type IV force int 0x%x irq=%d index=%d" ,
1083: Command , ( Command & 0x8 ) >> 3 , ( Command & 0x4 ) >> 2 );
1084:
1085:
1086: LOG_TRACE(TRACE_FDC, "fdc ipf %s VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
1087: buf , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
1088: }
1089: #endif
1090:
1091:
1.1 root 1092:
1093: /*
1094: * Run the FDC emulation during NbCycles cycles (relative to the 8MHz FDC's clock)
1095: */
1096: void IPF_Emulate ( void )
1097: {
1098: #ifndef HAVE_CAPSIMAGE
1099: return;
1100:
1101: #else
1102: int NbCycles;
1103: int Drive;
1104:
1105: NbCycles = CyclesGlobalClockCounter - IPF_State.FdcClock; /* Number of cycles since last emulation */
1106: if ( NbCycles < 0 )
1107: NbCycles = 0; /* We should call CAPSFdcEmulate even when NbCycles=0 */
1108:
1109: // LOG_TRACE(TRACE_FDC, "fdc ipf emulate cycles=%d VBL=%d HBL=%d clock=%lld\n" , NbCycles , nVBLs , nHBL , CyclesGlobalClockCounter );
1110:
1111: /* Update Write Protect status for each drive */
1112: for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
1113: if ( Floppy_IsWriteProtected ( Drive ) )
1114: IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_WP; /* Disk write protected */
1115: else
1116: IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_WP; /* Disk is not write protected */
1117:
1118:
1119: CAPSFdcEmulate ( &IPF_State.Fdc , NbCycles ); /* Process at max NbCycles */
1120: IPF_State.FdcClock += IPF_State.Fdc.clockact; /* clockact can be < NbCycle in some cases */
1121:
1122: /* Update UI's LEDs depending on Status Register */
1123: FDC_Drive_Set_BusyLed ( (IPF_State.Fdc.r_st0 & ~IPF_State.Fdc.r_stm) | (IPF_State.Fdc.r_st1 & IPF_State.Fdc.r_stm) );
1124: #endif
1125: }
1126:
1127:
1128:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.