|
|
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 */
1.1.1.3 ! root 56: #endif
1.1 root 57:
58: Sint64 FdcClock; /* Current value of CyclesGlobalClockCounter */
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: IPF_State.Fdc.drive = IPF_State.Drive; /* Connect drives array to the FDC */
126: if ( IPF_State.Fdc.driveprc != NULL ) /* Recompute active drive's pointer */
127: IPF_State.Fdc.driveprc = IPF_State.Fdc.drive + IPF_State.Fdc.driveact;
128:
1.1.1.2 root 129: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , 0 ); /* Invalidate buffered track data for drive 0 */
130: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , 1 ); /* Invalidate buffered track data for drive 1 */
131:
1.1 root 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;
1.1.1.2 root 321: #if CAPS_LIB_REL_REV >= 501
1.1 root 322: CapsLong ImageType;
1.1.1.2 root 323: #endif
1.1 root 324:
325: ImageId = CAPSAddImage();
326: if ( ImageId < 0 )
327: {
328: fprintf ( stderr , "IPF : error CAPSAddImage\n" );
329: return false;
330: }
331:
332: #if CAPS_LIB_REL_REV >= 501
333: ImageType = CAPSGetImageTypeMemory ( pImageBuffer , ImageSize );
334: if ( ImageType == citError )
335: {
336: fprintf ( stderr , "IPF : error CAPSGetImageTypeMemory\n" );
337: return false;
338: }
339: else if ( ImageType == citUnknown )
340: {
341: fprintf ( stderr , "IPF : unknown image type\n" );
342: return false;
343: }
344:
345: fprintf ( stderr , "IPF : IPF_Insert drive=%d buf=%p size=%ld imageid=%d type=" , Drive , pImageBuffer , ImageSize , ImageId );
346: switch ( ImageType ) {
347: case citIPF: fprintf ( stderr , "IPF\n" ); break;
348: case citCTRaw: fprintf ( stderr , "CT RAW\n" ); break;
349: case citKFStream: fprintf ( stderr , "KF STREAM\n" ) ; break;
350: case citDraft: fprintf ( stderr , "DRAFT\n" ) ; break;
351: default : fprintf ( stderr , "NOT SUPPORTED\n" );
352: return false;
353: }
354: #endif
355:
356: if ( CAPSLockImageMemory ( ImageId , pImageBuffer , (CapsULong)ImageSize , DI_LOCK_MEMREF ) == imgeOk )
357: {
358: struct CapsImageInfo cii;
359: int i;
360:
361: /* Print some debug infos */
362: if ( CAPSGetImageInfo ( &cii , ImageId ) == imgeOk )
363: {
364: printf("Type: %d\n", (int)cii.type);
365: printf("Release: %d\n", (int)cii.release);
366: printf("Revision: %d\n", (int)cii.revision);
367: printf("Min Cylinder: %d\n", (int)cii.mincylinder);
368: printf("Max Cylinder: %d\n", (int)cii.maxcylinder);
369: printf("Min Head: %d\n", (int)cii.minhead);
370: printf("Max Head: %d\n", (int)cii.maxhead);
371: 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);
372: printf("Platforms:");
373: for (i = 0; i < CAPS_MAXPLATFORM; i++)
374: if (cii.platform[i] != ciipNA)
375: printf ( " %s" , CAPSGetPlatformName(cii.platform[i]) );
376: printf("\n");
377:
378: /* Some IPF disks are not correctly supported yet : display a warning */
379: if ( (int)cii.release == 3222 ) /* Sundog */
380: Log_AlertDlg ( LOG_INFO , "'Sundog' is not correctly supported yet, it requires write access." );
381: else if ( (int)cii.release == 3058 ) /* Lethal Xcess */
382: Log_AlertDlg ( LOG_INFO , "'Lethal Xcess' is not correctly supported yet, protection will fail" );
383: }
384: }
385: else
386: {
387: CAPSRemImage ( ImageId ) ;
388: return false;
389: }
390:
391: if ( CAPSLoadImage ( ImageId , DI_LOCK_DENALT | DI_LOCK_DENVAR | DI_LOCK_UPDATEFD ) != imgeOk )
392: {
393: fprintf ( stderr , "IPF : error CAPSLoadImage\n" );
394: CAPSUnlockImage ( ImageId );
395: CAPSRemImage ( ImageId ) ;
396: return false;
397: }
398:
399:
400: IPF_State.CapsImage[ Drive ] = ImageId;
401:
402: IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_IN; /* Disk inserted, keep the value for "write protect" */
403:
404: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive ); /* Invalidate previous buffered track data for drive, if any */
405:
406: IPF_State.Rev_Track[ Drive ] = -1; /* Invalidate previous track/side to handle revolution's count */
407: IPF_State.Rev_Side[ Drive ] = -1;
408:
409: return true;
410: #endif
411: }
412:
413:
414:
415:
416: /*
417: * When ejecting a disk, free the ressources associated with an IPF image
418: */
419: bool IPF_Eject ( int Drive )
420: {
421: #ifndef HAVE_CAPSIMAGE
422: return false;
423:
424: #else
425: fprintf ( stderr , "IPF : IPF_Eject drive=%d imageid=%d\n" , Drive , IPF_State.CapsImage[ Drive ] );
426:
427: CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive ); /* Invalidate previous buffered track data for drive, if any */
428:
429: if ( CAPSUnlockImage ( IPF_State.CapsImage[ Drive ] ) < 0 )
430: {
431: fprintf ( stderr , "IPF : error CAPSUnlockImage\n" );
432: return false;
433: }
434:
435: if ( CAPSRemImage ( IPF_State.CapsImage[ Drive ] ) < 0 )
436: {
437: fprintf ( stderr , "IPF : error CAPSRemImage\n" );
438: return false;
439: }
440:
441: IPF_State.CapsImage[ Drive ] = -1;
442:
443: IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_IN;
444:
445: return true;
446: #endif
447: }
448:
449:
450:
451:
452: /*
453: * Reset FDC state when a reset signal was received
454: */
455: void IPF_Reset ( void )
456: {
457: #ifdef HAVE_CAPSIMAGE
458: CAPSFdcReset ( &IPF_State.Fdc );
459:
460: IPF_State.FdcClock = CyclesGlobalClockCounter;
461: #endif
462: }
463:
464:
465:
466:
467: /*
468: * Callback function used when track is changed.
469: * We need to update the track data by calling CAPSLockTrack
470: */
471: #ifdef HAVE_CAPSIMAGE
472: static void IPF_CallBack_Trk ( struct CapsFdc *pc , CapsULong State )
473: {
474: int Drive = State; /* State is the drive number in that case */
475: struct CapsDrive *pd = pc->drive+Drive; /* Current drive where the track change occurred */
476: struct CapsTrackInfoT1 cti;
477:
478: cti.type=1;
479: if ( CAPSLockTrack ( &cti , IPF_State.CapsImage[ Drive ] , pd->buftrack , pd->bufside ,
480: DI_LOCK_DENALT|DI_LOCK_DENVAR|DI_LOCK_UPDATEFD|DI_LOCK_TYPE ) != imgeOk )
481: return;
482:
483: LOG_TRACE(TRACE_FDC, "fdc ipf callback trk drive=%d buftrack=%d bufside=%d VBL=%d HBL=%d\n" , Drive ,
484: (int)pd->buftrack , (int)pd->bufside , nVBLs , nHBL );
485:
486: pd->ttype = cti.type;
487: pd->trackbuf = cti.trackbuf;
488: pd->timebuf = cti.timebuf;
489: pd->tracklen = cti.tracklen;
490: pd->overlap = cti.overlap;
491: }
492: #endif
493:
494:
495:
496:
497: /*
498: * Callback function used when the FDC change the IRQ signal
499: */
500: #ifdef HAVE_CAPSIMAGE
501: static void IPF_CallBack_Irq ( struct CapsFdc *pc , CapsULong State )
502: {
503: LOG_TRACE(TRACE_FDC, "fdc ipf callback irq state=0x%x VBL=%d HBL=%d\n" , (int)State , nVBLs , nHBL );
504:
505: if ( State )
506: FDC_SetIRQ ( FDC_IRQ_SOURCE_OTHER ); /* IRQ bit was set */
507: else
508: FDC_ClearIRQ (); /* IRQ bit was reset */
509: }
510: #endif
511:
512:
513:
514:
515: /*
516: * Callback function used when the FDC change the DRQ signal
517: * -> copy the byte to/from the DMA's FIFO if it's a read or a write to the disk
518: */
519: #ifdef HAVE_CAPSIMAGE
520: static void IPF_CallBack_Drq ( struct CapsFdc *pc , CapsULong State )
521: {
522: Uint8 Byte;
523:
524: if ( State == 0 )
525: return; /* DRQ bit was reset, do nothing */
526:
527: if ( FDC_DMA_GetModeControl_R_WR () != 0 ) /* DMA write mode */
528: {
529: Byte = FDC_DMA_FIFO_Pull (); /* Get a byte from the DMA FIFO */
530: CAPSFdcWrite ( &IPF_State.Fdc , 3 , Byte ); /* Write to FDC's reg 3 */
531:
532: 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 );
533: }
534:
535: else /* DMA read mode */
536: {
537: Byte = CAPSFdcRead ( &IPF_State.Fdc , 3 ); /* Read from FDC's reg 3 */
538: FDC_DMA_FIFO_Push ( Byte ); /* Add byte to the DMA FIFO */
539:
540: 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 );
541: }
542: }
543: #endif
544:
545:
546:
547: /*
548: * This function is used to enable/disable a drive when
549: * using the UI or command line parameters
550: *
551: * NOTE : for now, IPF only supports changing drive 1, drive 0
552: * is always ON.
553: */
554: void IPF_Drive_Set_Enable ( int Drive , bool value )
555: {
556: #ifndef HAVE_CAPSIMAGE
557: return;
558:
559: #else
560: IPF_State.DriveEnabled[ Drive ] = value; /* Store the new state */
561:
562: IPF_Drive_Update_Enable_Side (); /* Update IPF's internal state */
563: #endif
564: }
565:
566:
567: /*
568: * This function is used to configure a drive as single sided
569: * or double sided when using the UI or command line parameters
570: */
571: void IPF_Drive_Set_DoubleSided ( int Drive , bool value )
572: {
573: #ifndef HAVE_CAPSIMAGE
574: return;
575:
576: #else
577: IPF_State.DoubleSided[ Drive ] = value; /* Store the new state */
578:
579: IPF_Drive_Update_Enable_Side (); /* Update IPF's internal state */
580: #endif
581: }
582:
583:
584: /*
585: * Update IPF's internal state depending on which drives are ON or OFF
586: * and if the drive is single or double sided (for capslib >= 5.1)
587: */
588: #ifdef HAVE_CAPSIMAGE
589: static void IPF_Drive_Update_Enable_Side ( void )
590: {
1.1.1.2 root 591: #if CAPS_LIB_REL_REV >= 501
1.1 root 592: int i;
1.1.1.2 root 593: #endif
1.1 root 594:
595: if ( IPF_State.DriveEnabled[ 1 ] )
596: IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES; /* Should be 2 */
597: else
598: IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES - 1; /* Should be 1 */
599:
600: #if CAPS_LIB_REL_REV >= 501
601: for ( i=0 ; i < MAX_FLOPPYDRIVES ; i++ )
602: {
603: if ( IPF_State.DoubleSided[ i ] )
604: IPF_State.Drive[ i ].diskattr &= ~CAPSDRIVE_DA_SS; /* Double sided */
605: else
606: IPF_State.Drive[ i ].diskattr |= CAPSDRIVE_DA_SS; /* Single sided */
607: }
608: #endif
609: }
610: #endif
611:
612:
613: /*
614: * Set the drive and the side to be used for the next FDC commands
615: * io_porta_old is the previous value, io_porta_new is the new value
616: * to take into account.
617: * We report a side change only when a drive is selected.
618: */
619: void IPF_SetDriveSide ( Uint8 io_porta_old , Uint8 io_porta_new )
620: {
621: #ifndef HAVE_CAPSIMAGE
622: return;
623:
624: #else
625: int Side;
626:
627: 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 );
628:
629: Side = ( (~io_porta_new) & 0x01 ); /* Side 0 or 1 */
630:
631: IPF_State.Fdc.drivenew = -1; /* By default, don't select any drive */
632:
633: /* Check drive 1 first */
634: if ( ( io_porta_new & 0x04 ) == 0 )
635: {
636: IPF_State.Drive[ 1 ].newside = Side;
637: IPF_State.Fdc.drivenew = 1; /* Select drive 1 */
638: }
639:
640: /* If both drive 0 and drive 1 are enabled, we keep only drive 0 as newdrive */
641: if ( ( io_porta_new & 0x02 ) == 0 )
642: {
643: IPF_State.Drive[ 0 ].newside = Side;
644: IPF_State.Fdc.drivenew = 0; /* Select drive 0 (and un-select drive 1 if set above) */
645: }
646:
647: IPF_Emulate(); /* Update emulation's state up to this point, then set new drive/side */
648: #endif
649: }
650:
651:
652:
653:
654: /*
655: * Write a byte into one of the FDC registers
656: * 0=command 1=track 2=sector 3=data
657: */
658: void IPF_FDC_WriteReg ( Uint8 Reg , Uint8 Byte )
659: {
660: #ifndef HAVE_CAPSIMAGE
661: return; /* This should not be reached (an IPF image can't be inserted without capsimage) */
662:
663: #else
664: LOG_TRACE(TRACE_FDC, "fdc ipf write reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL );
665:
666:
667: #if CAPS_LIB_REL_REV >= 501
668: /* In the case of CTR images, we must reset the revolution counter */
669: /* when a command access data on disk and track/side changed since last access */
670: if ( Reg == 0 )
671: {
672: int Type;
673: int Drive;
674:
675: Type = FDC_GetCmdType ( Byte );
676: if ( ( Type == 2 ) || ( Type == 3 ) )
677: {
678: Drive = IPF_State.Fdc.driveact;
679: if ( ( Drive >= 0 )
680: && ( ( IPF_State.Drive[ Drive ].side != IPF_State.Rev_Side[ Drive ] ) || ( IPF_State.Drive[ Drive ].track != IPF_State.Rev_Track[ Drive ] ) ) )
681: {
682: IPF_State.Rev_Side[ Drive ] = IPF_State.Drive[ Drive ].side;
683: IPF_State.Rev_Track[ Drive ] = IPF_State.Drive[ Drive ].track;
684: CAPSSetRevolution ( IPF_State.CapsImage[ Drive ] , 0 );
685: }
686: }
687: }
688: #endif
689:
690: IPF_Emulate(); /* Update emulation's state up to this point */
691:
692: CAPSFdcWrite ( &IPF_State.Fdc , Reg , Byte );
693: #endif
694: }
695:
696:
697:
698:
699: /*
700: * Read the content of one of the FDC registers
701: * 0=status 1=track 2=sector 3=data
702: */
703: Uint8 IPF_FDC_ReadReg ( Uint8 Reg )
704: {
705: #ifndef HAVE_CAPSIMAGE
706: return 0; /* This should not be reached (an IPF image can't be inserted without capsimage) */
707: #else
708: Uint8 Byte;
709:
710: IPF_Emulate(); /* Update emulation's state up to this point */
711:
712: Byte = CAPSFdcRead ( &IPF_State.Fdc , Reg );
713: LOG_TRACE(TRACE_FDC, "fdc ipf read reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL );
714:
715: return Byte;
716: #endif
717: }
718:
719:
720:
721:
722: /*
723: * Return the content of some registers to display them in the statusbar
724: * We should not call IPF_Emulate() or similar, reading should not change emulation's state
725: */
726: void IPF_FDC_StatusBar ( Uint8 *pCommand , Uint8 *pHead , Uint8 *pTrack , Uint8 *pSector , Uint8 *pSide )
727: {
728: #ifndef HAVE_CAPSIMAGE
729: return; /* This should not be reached (an IPF image can't be inserted without capsimage) */
730: #else
731: int Drive;
732:
733: Drive = IPF_State.Fdc.driveact;
734: if ( Drive < 0 ) /* If no drive enabled, use drive O for Head/Side */
735: Drive = 0;
736:
737: /* We read directly in the structures, to be sure we don't change emulation's state */
738: *pCommand = IPF_State.Fdc.r_command;
739: *pHead = IPF_State.Drive[ Drive ].track;
740: *pTrack = IPF_State.Fdc.r_track;
741: *pSector = IPF_State.Fdc.r_sector;
742: *pSide = IPF_State.Drive[ Drive ].side;
743: #endif
744: }
745:
746:
747:
748:
749: /*
750: * Run the FDC emulation during NbCycles cycles (relative to the 8MHz FDC's clock)
751: */
752: void IPF_Emulate ( void )
753: {
754: #ifndef HAVE_CAPSIMAGE
755: return;
756:
757: #else
758: int NbCycles;
759: int Drive;
760:
761: NbCycles = CyclesGlobalClockCounter - IPF_State.FdcClock; /* Number of cycles since last emulation */
762: if ( NbCycles < 0 )
763: NbCycles = 0; /* We should call CAPSFdcEmulate even when NbCycles=0 */
764:
765: // LOG_TRACE(TRACE_FDC, "fdc ipf emulate cycles=%d VBL=%d HBL=%d clock=%lld\n" , NbCycles , nVBLs , nHBL , CyclesGlobalClockCounter );
766:
767: /* Update Write Protect status for each drive */
768: for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
769: if ( Floppy_IsWriteProtected ( Drive ) )
770: IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_WP; /* Disk write protected */
771: else
772: IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_WP; /* Disk is not write protected */
773:
774:
775: CAPSFdcEmulate ( &IPF_State.Fdc , NbCycles ); /* Process at max NbCycles */
776: IPF_State.FdcClock += IPF_State.Fdc.clockact; /* clockact can be < NbCycle in some cases */
777:
778: /* Update UI's LEDs depending on Status Register */
779: FDC_Drive_Set_BusyLed ( (IPF_State.Fdc.r_st0 & ~IPF_State.Fdc.r_stm) | (IPF_State.Fdc.r_st1 & IPF_State.Fdc.r_stm) );
780: #endif
781: }
782:
783:
784:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.