|
|
1.1 ! root 1: /* ! 2: Hatari - floppy_stx.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: STX disk image support. ! 8: ! 9: STX files are created using the program 'Pasti' made by Jorge Cwik (Ijor). ! 10: As no official documentation exists, this file is based on the reverse ! 11: engineering and docs made by the following people, mainly using Pasti 0.4b : ! 12: - Markus Fritze (Sarnau) ! 13: - P. Putnik ! 14: - Jean Louis Guerin (Dr CoolZic) ! 15: - Nicolas Pomarede ! 16: */ ! 17: const char floppy_stx_fileid[] = "Hatari floppy_stx.c : " __DATE__ " " __TIME__; ! 18: ! 19: #include "main.h" ! 20: #include "file.h" ! 21: #include "floppy.h" ! 22: #include "floppy_stx.h" ! 23: #include "fdc.h" ! 24: #include "log.h" ! 25: #include "memorySnapShot.h" ! 26: #include "screen.h" ! 27: #include "video.h" ! 28: #include "cycles.h" ! 29: #include "str.h" ! 30: #include "utils.h" ! 31: ! 32: ! 33: #define STX_DEBUG_FLAG_STRUCTURE 1 ! 34: #define STX_DEBUG_FLAG_DATA 2 ! 35: ! 36: #define STX_DEBUG_FLAG 0 ! 37: // #define STX_DEBUG_FLAG ( STX_DEBUG_FLAG_STRUCTURE ) ! 38: // #define STX_DEBUG_FLAG ( STX_DEBUG_FLAG_STRUCTURE | STX_DEBUG_FLAG_DATA ) ! 39: ! 40: ! 41: #define FDC_DELAY_CYCLE_MFM_BIT ( 4 * 8 ) /* 4 us per bit, 8 MHz clock -> 32 cycles */ ! 42: #define FDC_DELAY_CYCLE_MFM_BYTE ( 4 * 8 * 8 ) /* 4 us per bit, 8 bits per byte, 8 MHz clock -> 256 cycles */ ! 43: ! 44: #define FDC_TRACK_BYTES_STANDARD 6250 ! 45: ! 46: ! 47: #define WD1772_SAVE_FILE_EXT ".wd1772" ! 48: #define WD1772_SAVE_FILE_ID "WD1772" /* 6 bytes */ ! 49: #define WD1772_SAVE_VERSION 1 ! 50: #define WD1772_SAVE_REVISION 0 ! 51: #define WD1772_SAVE_SECTOR_ID "SECT" /* 4 bytes */ ! 52: #define WD1772_SAVE_TRACK_ID "TRCK" /* 4 bytes */ ! 53: ! 54: ! 55: typedef struct ! 56: { ! 57: STX_MAIN_STRUCT *ImageBuffer[ MAX_FLOPPYDRIVES ]; /* For the STX disk images */ ! 58: ! 59: Uint32 NextSectorStruct_Nbr; /* Sector Number in pSectorsStruct after a call to FDC_NextSectorID_FdcCycles_STX() */ ! 60: Uint8 NextSector_ID_Field_TR; /* Track value in the next ID Field after a call to FDC_NextSectorID_FdcCycles_STX() */ ! 61: Uint8 NextSector_ID_Field_SR; /* Sector value in the next ID Field after a call to FDC_NextSectorID_FdcCycles_STX() */ ! 62: Uint8 NextSector_ID_Field_LEN; /* Sector's length in the next ID Field after a call to FDC_NextSectorID_FdcCycles_STX() */ ! 63: Uint8 NextSector_ID_Field_CRC_OK; /* CRC OK or not in the next ID Field after a call to FDC_NextSectorID_FdcCycles_STX() */ ! 64: ! 65: } STX_STRUCT; ! 66: ! 67: ! 68: static STX_STRUCT STX_State; /* All variables related to the STX support */ ! 69: ! 70: static STX_SAVE_STRUCT STX_SaveStruct[ MAX_FLOPPYDRIVES ]; /* To save 'write sector' data */ ! 71: ! 72: ! 73: ! 74: /* Default timing table for Macrodos when revision=0 */ ! 75: /* 1 unit of timing means 32 FDC cycles ; + 28 cycles every 16 bytes, so a standard block of 16 bytes */ ! 76: /* should have a value of 0x7f or 0x80, which gives 4092-4124 cycles */ ! 77: Uint8 TimingDataDefault[] = { ! 78: 0x00,0x7f,0x00,0x7f,0x00,0x7f,0x00,0x7f,0x00,0x7f,0x00,0x7f,0x00,0x7f,0x00,0x7f, ! 79: 0x00,0x85,0x00,0x85,0x00,0x85,0x00,0x85,0x00,0x85,0x00,0x85,0x00,0x85,0x00,0x85, ! 80: 0x00,0x79,0x00,0x79,0x00,0x79,0x00,0x79,0x00,0x79,0x00,0x79,0x00,0x79,0x00,0x79, ! 81: 0x00,0x7f,0x00,0x7f,0x00,0x7f,0x00,0x7f,0x00,0x7f,0x00,0x7f,0x00,0x7f,0x00,0x7f ! 82: }; ! 83: ! 84: ! 85: ! 86: /*--------------------------------------------------------------*/ ! 87: /* Local functions prototypes */ ! 88: /*--------------------------------------------------------------*/ ! 89: ! 90: static bool STX_LoadSaveFile ( int Drive , const char *FilenameSave ); ! 91: static bool STX_LoadSaveFile_SECT ( int Drive, STX_SAVE_SECTOR_STRUCT *pStxSaveSector , Uint8 *p ); ! 92: static bool STX_LoadSaveFile_TRCK ( int Drive , STX_SAVE_TRACK_STRUCT *pStxSaveTrack , Uint8 *p ); ! 93: ! 94: static bool STX_Insert_internal ( int Drive , const char *FilenameSTX , Uint8 *pImageBuffer , long ImageSize ); ! 95: ! 96: static Uint16 STX_ReadU16_LE ( Uint8 *p ); ! 97: static Uint32 STX_ReadU32_LE ( Uint8 *p ); ! 98: static Uint16 STX_ReadU16_BE ( Uint8 *p ); ! 99: static Uint32 STX_ReadU32_BE ( Uint8 *p ); ! 100: static void STX_WriteU16_BE ( Uint8 *p , Uint16 val ); ! 101: static void STX_WriteU32_BE ( Uint8 *p , Uint32 val ); ! 102: ! 103: static void STX_FreeStruct ( STX_MAIN_STRUCT *pStxMain ); ! 104: static void STX_FreeSaveStruct ( int Drive ); ! 105: static void STX_FreeSaveSectorsStructAll ( STX_SAVE_SECTOR_STRUCT *pSaveSectorsStruct , Uint32 SaveSectorsCount ); ! 106: static void STX_FreeSaveSectorsStruct ( STX_SAVE_SECTOR_STRUCT *pSaveSectorsStruct , int Nb ); ! 107: static void STX_FreeSaveTracksStructAll ( STX_SAVE_TRACK_STRUCT *pSaveTracksStruct , Uint32 SaveTracksCount ); ! 108: static void STX_FreeSaveTracksStruct ( STX_SAVE_TRACK_STRUCT *pSaveTracksStruct , int Nb ); ! 109: ! 110: static void STX_BuildSectorsSimple ( STX_TRACK_STRUCT *pStxTrack , Uint8 *p ); ! 111: static Uint16 STX_BuildSectorID_CRC ( STX_SECTOR_STRUCT *pStxSector ); ! 112: static STX_TRACK_STRUCT *STX_FindTrack ( Uint8 Drive , Uint8 Track , Uint8 Side ); ! 113: static STX_SECTOR_STRUCT *STX_FindSector ( Uint8 Drive , Uint8 Track , Uint8 Side , Uint8 SectorStruct_Nb ); ! 114: static STX_SECTOR_STRUCT *STX_FindSector_By_Position ( Uint8 Drive , Uint8 Track , Uint8 Side , Uint16 BitPosition ); ! 115: ! 116: ! 117: ! 118: /*-----------------------------------------------------------------------*/ ! 119: /** ! 120: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type) ! 121: */ ! 122: void STX_MemorySnapShot_Capture(bool bSave) ! 123: { ! 124: int Drive; ! 125: Uint32 i; ! 126: STX_SECTOR_STRUCT *pStxSector; ! 127: STX_TRACK_STRUCT *pStxTrack; ! 128: ! 129: if ( bSave ) /* Saving snapshot */ ! 130: { ! 131: MemorySnapShot_Store( &STX_State , sizeof (STX_State) ); ! 132: ! 133: /* Also save the 'write sector' and 'write track' buffers */ ! 134: for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ ) ! 135: { ! 136: /* Save the sectors' buffer */ ! 137: MemorySnapShot_Store ( &STX_SaveStruct[ Drive ].SaveSectorsCount , sizeof ( STX_SaveStruct[ Drive ].SaveSectorsCount ) ); ! 138: if ( STX_SaveStruct[ Drive ].SaveSectorsCount > 0 ) ! 139: { ! 140: /* Save all sectors in the memory state */ ! 141: /* For each sector, we save the structure, then the data */ ! 142: for ( i=0 ; i<STX_SaveStruct[ Drive ].SaveSectorsCount ; i++ ) ! 143: { ! 144: //Str_Dump_Hex_Ascii ( (char *) &STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ], sizeof( STX_SAVE_SECTOR_STRUCT ), 16, "" , stderr ); ! 145: /* Save the structure */ ! 146: MemorySnapShot_Store ( &STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ] , sizeof( STX_SAVE_SECTOR_STRUCT ) ); ! 147: /* Save the sector's data */ ! 148: MemorySnapShot_Store ( STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ].pData , ! 149: STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ].SectorSize ); ! 150: } ! 151: } ! 152: //fprintf ( stderr , "stx save write buffer drive=%d count=%d buf=%p\n" , Drive , STX_SaveStruct[ Drive ].SaveSectorsCount , STX_SaveStruct[ Drive ].pSaveSectorsStruct ); ! 153: ! 154: /* Save the tracks' buffer */ ! 155: MemorySnapShot_Store ( &STX_SaveStruct[ Drive ].SaveTracksCount , sizeof ( STX_SaveStruct[ Drive ].SaveTracksCount ) ); ! 156: if ( STX_SaveStruct[ Drive ].SaveTracksCount > 0 ) ! 157: { ! 158: /* Save all tracks in the memory state */ ! 159: /* For each track, we save the structure, then the data */ ! 160: for ( i=0 ; i<STX_SaveStruct[ Drive ].SaveTracksCount ; i++ ) ! 161: { ! 162: //Str_Dump_Hex_Ascii ( (char *) &STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ], sizeof( STX_SAVE_TRACK_STRUCT ), 16, "" , stderr ); ! 163: /* Save the structure */ ! 164: MemorySnapShot_Store ( &STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ] , sizeof( STX_SAVE_TRACK_STRUCT ) ); ! 165: /* Save the track's data (as it was written, don't save the interpreted track) */ ! 166: MemorySnapShot_Store ( STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ].pDataWrite , ! 167: STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ].TrackSizeWrite ); ! 168: } ! 169: } ! 170: } ! 171: } ! 172: ! 173: else /* Restoring snapshot */ ! 174: { ! 175: MemorySnapShot_Store ( &STX_State , sizeof (STX_State) ); ! 176: ! 177: /* Call STX_Insert_internal to recompute STX_State */ ! 178: /* (without loading an optional ".wd1772" file) */ ! 179: for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ ) ! 180: if ( EmulationDrives[Drive].ImageType == FLOPPY_IMAGE_TYPE_STX ) ! 181: if ( STX_Insert_internal ( Drive , EmulationDrives[Drive].sFileName , EmulationDrives[Drive].pBuffer , ! 182: EmulationDrives[Drive].nImageBytes ) == false ) ! 183: { ! 184: Log_AlertDlg(LOG_ERROR, "Error restoring STX image %s in drive %d" , ! 185: EmulationDrives[Drive].sFileName , Drive ); ! 186: return; ! 187: } ! 188: ! 189: /* Also restore the 'write sector' and 'write track' buffers */ ! 190: for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ ) ! 191: { ! 192: /* Restore the sectors' buffer */ ! 193: MemorySnapShot_Store ( &STX_SaveStruct[ Drive ].SaveSectorsCount , sizeof ( STX_SaveStruct[ Drive ].SaveSectorsCount ) ); ! 194: if ( STX_SaveStruct[ Drive ].SaveSectorsCount > 0 ) ! 195: { ! 196: /* Alloc a buffer for all the sectors */ ! 197: STX_SaveStruct[ Drive ].pSaveSectorsStruct = malloc ( STX_SaveStruct[ Drive ].SaveSectorsCount * sizeof ( STX_SAVE_SECTOR_STRUCT ) ); ! 198: if ( !STX_SaveStruct[ Drive ].pSaveSectorsStruct ) ! 199: { ! 200: Log_AlertDlg(LOG_ERROR, "Error restoring STX sectors save buffer malloc size=%d in drive %d" , ! 201: STX_SaveStruct[ Drive ].SaveSectorsCount , Drive ); ! 202: return; ! 203: } ! 204: ! 205: /* Load all the sectors from the memory state */ ! 206: /* For each sector, we load the structure, then the data */ ! 207: for ( i=0 ; i<STX_SaveStruct[ Drive ].SaveSectorsCount ; i++ ) ! 208: { ! 209: /* Load the structure */ ! 210: MemorySnapShot_Store ( &STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ] , sizeof( STX_SAVE_SECTOR_STRUCT ) ); ! 211: //Str_Dump_Hex_Ascii ( (char *) &STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ], sizeof( STX_SAVE_SECTOR_STRUCT ), 16, "" , stderr ); ! 212: ! 213: /* Load the sector's data */ ! 214: STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ].pData = malloc ( STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ].SectorSize ); ! 215: if ( !STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ].pData ) ! 216: { ! 217: Log_AlertDlg(LOG_ERROR, "Error restoring STX save buffer for sector=%d in drive %d" , ! 218: i , Drive ); ! 219: return; ! 220: } ! 221: MemorySnapShot_Store ( STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ].pData , ! 222: STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ].SectorSize ); ! 223: ! 224: /* Find the original sector to associate it with this saved sector */ ! 225: pStxSector = STX_FindSector_By_Position ( Drive , STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ].Track , ! 226: STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ].Side , ! 227: STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i ].BitPosition ); ! 228: if ( !pStxSector ) ! 229: { ! 230: Log_AlertDlg(LOG_ERROR, "Error restoring STX save buffer for sector=%d in drive %d" , ! 231: i , Drive ); ! 232: return; ! 233: } ! 234: pStxSector->SaveSectorIndex = i; ! 235: } ! 236: } ! 237: ! 238: else ! 239: STX_SaveStruct[ Drive ].pSaveSectorsStruct = NULL; ! 240: //fprintf ( stderr , "stx load write buffer drive=%d count=%d buf=%p\n" , Drive , STX_SaveStruct[ Drive ].SaveSectorsCount , STX_SaveStruct[ Drive ].pSaveSectorsStruct ); ! 241: ! 242: /* Restore the tracks' buffer */ ! 243: MemorySnapShot_Store ( &STX_SaveStruct[ Drive ].SaveTracksCount , sizeof ( STX_SaveStruct[ Drive ].SaveTracksCount ) ); ! 244: if ( STX_SaveStruct[ Drive ].SaveTracksCount > 0 ) ! 245: { ! 246: /* Alloc a buffer for all the tracks */ ! 247: STX_SaveStruct[ Drive ].pSaveTracksStruct = malloc ( STX_SaveStruct[ Drive ].SaveTracksCount * sizeof ( STX_SAVE_TRACK_STRUCT ) ); ! 248: if ( !STX_SaveStruct[ Drive ].pSaveTracksStruct ) ! 249: { ! 250: Log_AlertDlg(LOG_ERROR, "Error restoring STX tracks save buffer malloc size=%d in drive %d" , ! 251: STX_SaveStruct[ Drive ].SaveTracksCount , Drive ); ! 252: return; ! 253: } ! 254: ! 255: /* Load all the tracks from the memory state */ ! 256: /* For each track, we load the structure, then the data */ ! 257: for ( i=0 ; i<STX_SaveStruct[ Drive ].SaveTracksCount ; i++ ) ! 258: { ! 259: /* Load the structure */ ! 260: MemorySnapShot_Store ( &STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ] , sizeof( STX_SAVE_TRACK_STRUCT ) ); ! 261: //Str_Dump_Hex_Ascii ( (char *) &STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ], sizeof( STX_SAVE_TRACK_STRUCT ), 16, "" , stderr ); ! 262: ! 263: /* Load the track's data (as it was written, don't load the interpreted track) */ ! 264: STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ].pDataWrite = malloc ( STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ].TrackSizeWrite ); ! 265: if ( !STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ].pDataWrite ) ! 266: { ! 267: Log_AlertDlg(LOG_ERROR, "Error restoring STX save buffer for track=%d in drive %d" , ! 268: i , Drive ); ! 269: return; ! 270: } ! 271: MemorySnapShot_Store ( STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ].pDataWrite , ! 272: STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ].TrackSizeWrite ); ! 273: ! 274: STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ].pDataRead = NULL; /* TODO : compute interpreted track */ ! 275: STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ].TrackSizeRead = 0; /* TODO : compute interpreted track */ ! 276: ! 277: /* Find the original track to associate it with this saved track */ ! 278: pStxTrack = STX_FindTrack ( Drive , STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ].Track , ! 279: STX_SaveStruct[ Drive ].pSaveTracksStruct[ i ].Side ); ! 280: if ( !pStxTrack ) ! 281: { ! 282: Log_AlertDlg(LOG_ERROR, "Error restoring STX save buffer for track=%d in drive %d" , ! 283: i , Drive ); ! 284: return; ! 285: } ! 286: pStxTrack->SaveTrackIndex = i; ! 287: } ! 288: } ! 289: ! 290: else ! 291: STX_SaveStruct[ Drive ].pSaveTracksStruct = NULL; ! 292: } ! 293: ! 294: fprintf ( stderr , "stx load ok\n" ); ! 295: } ! 296: } ! 297: ! 298: ! 299: /*-----------------------------------------------------------------------*/ ! 300: /** ! 301: * Does filename end with a .STX extension? If so, return true. ! 302: */ ! 303: bool STX_FileNameIsSTX(const char *pszFileName, bool bAllowGZ) ! 304: { ! 305: return(File_DoesFileExtensionMatch(pszFileName,".stx") ! 306: || (bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".stx.gz"))); ! 307: } ! 308: ! 309: ! 310: /*-----------------------------------------------------------------------*/ ! 311: /** ! 312: * Create a filename to save modifications made to an STX file ! 313: * We replace the ".stx" or ".stx.gz" extension with ".wd1772" ! 314: * Return true if OK ! 315: */ ! 316: bool STX_FileNameToSave ( const char *FilenameSTX , char *FilenameSave ) ! 317: { ! 318: if ( File_ChangeFileExtension ( FilenameSTX , ".stx.gz" , FilenameSave , WD1772_SAVE_FILE_EXT ) ) ! 319: return true; ! 320: ! 321: else if ( File_ChangeFileExtension ( FilenameSTX , ".stx" , FilenameSave , WD1772_SAVE_FILE_EXT ) ) ! 322: return true; ! 323: ! 324: return false; ! 325: } ! 326: ! 327: ! 328: /*-----------------------------------------------------------------------*/ ! 329: /** ! 330: * Load .STX file into memory, set number of bytes loaded and return a pointer ! 331: * to the buffer. ! 332: */ ! 333: Uint8 *STX_ReadDisk(int Drive, const char *pszFileName, long *pImageSize, int *pImageType) ! 334: { ! 335: Uint8 *pSTXFile; ! 336: ! 337: *pImageSize = 0; ! 338: ! 339: /* Just load directly a buffer, and set ImageSize accordingly */ ! 340: pSTXFile = File_Read(pszFileName, pImageSize, NULL); ! 341: if (!pSTXFile) ! 342: { ! 343: *pImageSize = 0; ! 344: return NULL; ! 345: } ! 346: ! 347: *pImageType = FLOPPY_IMAGE_TYPE_STX; ! 348: return pSTXFile; ! 349: } ! 350: ! 351: ! 352: /*-----------------------------------------------------------------------*/ ! 353: /** ! 354: * Save .STX file from memory buffer. Returns true if all OK. ! 355: * We create a file based on the initial filename by replacing the ".stx" extension ! 356: * with ".wd1172". ! 357: * We save all sectors, then all tracks. ! 358: * If there're no sector and no track to save, return true and don't create ! 359: * the save file ! 360: */ ! 361: bool STX_WriteDisk ( int Drive , const char *pszFileName , Uint8 *pBuffer , int ImageSize ) ! 362: { ! 363: FILE *FileOut; ! 364: char FilenameSave[ FILENAME_MAX ]; ! 365: Uint8 buf[ 100 ]; ! 366: Uint8 *p; ! 367: Uint32 Sector; ! 368: Uint32 Track; ! 369: Uint32 BlockLen; ! 370: Uint32 SaveSectorsCount_real; ! 371: STX_SAVE_SECTOR_STRUCT *pStxSaveSector; ! 372: STX_SAVE_TRACK_STRUCT *pStxSaveTrack; ! 373: Uint32 i; ! 374: ! 375: fprintf ( stderr , "stx write <%s>\n" , pszFileName ); ! 376: ! 377: ! 378: /* We can only save if the filename ends with ".stx" (or ".stx.gz"), not if it's a ".zip" file */ ! 379: if ( STX_FileNameIsSTX ( pszFileName , true ) == false ) ! 380: { ! 381: Log_AlertDlg ( LOG_INFO , "WARNING : can't save changes made to this STX disk, bad file extension" ); ! 382: return false; ! 383: } ! 384: ! 385: /* Count the saved sectors that are really used */ ! 386: SaveSectorsCount_real = 0; ! 387: i = 0; ! 388: while ( i < STX_SaveStruct[ Drive ].SaveSectorsCount ) ! 389: if ( STX_SaveStruct[ Drive ].pSaveSectorsStruct[ i++ ].StructIsUsed != 0 ) ! 390: SaveSectorsCount_real++; ! 391: ! 392: /* Do we have data to save ? */ ! 393: if ( ( SaveSectorsCount_real == 0 ) ! 394: && ( STX_SaveStruct[ Drive ].SaveTracksCount == 0 ) ) ! 395: return true; ! 396: ! 397: ! 398: if ( STX_FileNameToSave ( pszFileName , FilenameSave ) == false ) ! 399: { ! 400: fprintf ( stderr , "STX_WriteDisk drive=%d file=%s, error STX_FileNameToSave\n" , Drive , pszFileName ); ! 401: return false; ! 402: } ! 403: fprintf ( stderr , "stx write <%s>\n" , FilenameSave ); ! 404: ! 405: ! 406: FileOut = fopen ( FilenameSave , "wb+" ); ! 407: if ( !FileOut ) ! 408: { ! 409: fprintf ( stderr , "STX_WriteDisk drive=%d file=%s, error fopen\n" , Drive , pszFileName ); ! 410: return false; ! 411: } ! 412: ! 413: /* Write the file's header : 6 + 1 + 1 + 4 + 4 = 16 bytes */ ! 414: p = buf; ! 415: strcpy ( (char *) p , WD1772_SAVE_FILE_ID ); /* +0 .. +5 */ ! 416: p += strlen ( WD1772_SAVE_FILE_ID ); ! 417: *p++ = WD1772_SAVE_VERSION; /* +6 */ ! 418: *p++ = WD1772_SAVE_REVISION; /* +7 */ ! 419: ! 420: STX_WriteU32_BE ( p , SaveSectorsCount_real ); /* +8 ... +11 */ ! 421: p += 4; ! 422: ! 423: STX_WriteU32_BE ( p , STX_SaveStruct[ Drive ].SaveTracksCount ); /* +12 ... +15 */ ! 424: p += 4; ! 425: ! 426: if ( fwrite ( buf , p-buf , 1 , FileOut ) != 1 ) ! 427: { ! 428: fprintf ( stderr , "STX_WriteDisk drive=%d file=%s, error fwrite header\n" , Drive , pszFileName ); ! 429: return false; ! 430: } ! 431: ! 432: ! 433: /* Write the sectors' buffer */ ! 434: Sector = 0; ! 435: while ( Sector < STX_SaveStruct[ Drive ].SaveSectorsCount ) ! 436: { ! 437: pStxSaveSector = &STX_SaveStruct[ Drive ].pSaveSectorsStruct[ Sector ]; ! 438: ! 439: if ( pStxSaveSector->StructIsUsed == 0 ) ! 440: { ! 441: Sector++; ! 442: continue; /* This structure is not used anymore, ignore it */ ! 443: } ! 444: ! 445: /* Build the sector's header : 20 bytes */ ! 446: p = buf; ! 447: strcpy ( (char *) p , WD1772_SAVE_SECTOR_ID ); /* +0 .. +3 */ ! 448: p += strlen ( WD1772_SAVE_SECTOR_ID ); ! 449: ! 450: BlockLen = 20-4 + pStxSaveSector->SectorSize; ! 451: STX_WriteU32_BE ( p , BlockLen ); /* +4 ... +7 */ ! 452: p += 4; ! 453: ! 454: *p++ = pStxSaveSector->Track; /* +8 */ ! 455: *p++ = pStxSaveSector->Side; /* +9 */ ! 456: STX_WriteU16_BE ( p , pStxSaveSector->BitPosition ); /* +10 ... +11 */ ! 457: p += 2; ! 458: *p++ = pStxSaveSector->ID_Track; /* +12 */ ! 459: *p++ = pStxSaveSector->ID_Head; /* +13 */ ! 460: *p++ = pStxSaveSector->ID_Sector; /* +14 */ ! 461: *p++ = pStxSaveSector->ID_Size; /* +15 */ ! 462: STX_WriteU16_BE ( p , pStxSaveSector->ID_CRC ); /* +16 ... +17 */ ! 463: p += 2; ! 464: ! 465: STX_WriteU16_BE ( p , pStxSaveSector->SectorSize ); /* +18 ... +19 */ ! 466: p += 2; ! 467: ! 468: /* Write the header */ ! 469: //Str_Dump_Hex_Ascii ( (char *) buf , p-buf, 16, "" , stderr ); ! 470: if ( fwrite ( buf , p-buf , 1 , FileOut ) != 1 ) ! 471: { ! 472: fprintf ( stderr , "STX_WriteDisk drive=%d file=%s, error fwrite sector header\n" , Drive , pszFileName ); ! 473: return false; ! 474: } ! 475: ! 476: /* Write the data */ ! 477: //Str_Dump_Hex_Ascii ( (char *) pStxSaveSector->pData , pStxSaveSector->SectorSize, 16, "" , stderr ); ! 478: if ( fwrite ( pStxSaveSector->pData , pStxSaveSector->SectorSize , 1 , FileOut ) != 1 ) ! 479: { ! 480: fprintf ( stderr , "STX_WriteDisk drive=%d file=%s, error fwrite sector data\n" , Drive , pszFileName ); ! 481: return false; ! 482: } ! 483: ! 484: Sector++; ! 485: } ! 486: ! 487: ! 488: /* Write the tracks' buffer */ ! 489: Track = 0; ! 490: while ( Track < STX_SaveStruct[ Drive ].SaveTracksCount ) ! 491: { ! 492: pStxSaveTrack = &STX_SaveStruct[ Drive ].pSaveTracksStruct[ Track ]; ! 493: ! 494: /* Build the track's header : 12 bytes */ ! 495: p = buf; ! 496: strcpy ( (char *) p , WD1772_SAVE_TRACK_ID ); /* +0 ... +3 */ ! 497: p += strlen ( WD1772_SAVE_TRACK_ID ); ! 498: ! 499: BlockLen = 12-4 + pStxSaveTrack->TrackSizeWrite; ! 500: STX_WriteU32_BE ( p , BlockLen ); /* +4 ... +7 */ ! 501: p += 4; ! 502: ! 503: *p++ = pStxSaveTrack->Track; /* +8 */ ! 504: *p++ = pStxSaveTrack->Side; /* +9 */ ! 505: ! 506: STX_WriteU16_BE ( p , pStxSaveTrack->TrackSizeWrite ); /* +10 ... +11 */ ! 507: p += 2; ! 508: ! 509: /* Write the header */ ! 510: //Str_Dump_Hex_Ascii ( (char *) buf , p-buf, 16, "" , stderr ); ! 511: if ( fwrite ( buf , p-buf , 1 , FileOut ) != 1 ) ! 512: { ! 513: fprintf ( stderr , "STX_WriteDisk drive=%d file=%s, error fwrite track header\n" , Drive , pszFileName ); ! 514: return false; ! 515: } ! 516: ! 517: /* Write the data at +12 */ ! 518: //Str_Dump_Hex_Ascii ( (char *) pStxSaveTrack->pDataWrite , pStxSaveTrack->TrackSizeWrite, 16, "" , stderr ); ! 519: if ( fwrite ( pStxSaveTrack->pDataWrite , pStxSaveTrack->TrackSizeWrite , 1 , FileOut ) != 1 ) ! 520: { ! 521: fprintf ( stderr , "STX_WriteDisk drive=%d file=%s, error fwrite track data\n" , Drive , pszFileName ); ! 522: return false; ! 523: } ! 524: ! 525: Track++; ! 526: } ! 527: ! 528: ! 529: fclose ( FileOut ); ! 530: ! 531: return true; ! 532: } ! 533: ! 534: ! 535: /*-----------------------------------------------------------------------*/ ! 536: /* ! 537: * Load a ".wd1772" save file and add it to the STX structures ! 538: * Return true if OK. ! 539: */ ! 540: static bool STX_LoadSaveFile ( int Drive , const char *FilenameSave ) ! 541: { ! 542: Uint8 *SaveFileBuffer; ! 543: long SaveFileSize; ! 544: Uint8 *p; ! 545: Uint8 *p_save; ! 546: Uint8 version , revision; ! 547: Uint32 SectorNb; ! 548: Uint32 TrackNb; ! 549: STX_SECTOR_STRUCT *pStxSector; ! 550: STX_TRACK_STRUCT *pStxTrack; ! 551: ! 552: ! 553: SaveFileBuffer = File_Read ( FilenameSave, &SaveFileSize, NULL ); ! 554: if (!SaveFileBuffer) ! 555: { ! 556: fprintf ( stderr , "STX_LoadSaveFile drive=%d file=%s error\n" , Drive , FilenameSave ); ! 557: return false; ! 558: } ! 559: ! 560: p = SaveFileBuffer; ! 561: ! 562: if ( strncmp ( (char *) p , WD1772_SAVE_FILE_ID , strlen ( WD1772_SAVE_FILE_ID ) ) ) /* +0 ... +5 */ ! 563: { ! 564: fprintf ( stderr , "STX_LoadSaveFile drive=%d file=%s bad header\n" , Drive , FilenameSave ); ! 565: free ( SaveFileBuffer ); ! 566: return false; ! 567: } ! 568: p += strlen ( WD1772_SAVE_FILE_ID ); ! 569: ! 570: version = *p++; /* +6 */ ! 571: revision = *p++; /* +7 */ ! 572: if ( ( version != WD1772_SAVE_VERSION ) || ( revision != WD1772_SAVE_REVISION ) ) ! 573: { ! 574: fprintf ( stderr , "STX_LoadSaveFile drive=%d file=%s bad version 0x%x revision 0x%x\n" , Drive , FilenameSave , version , revision ); ! 575: free ( SaveFileBuffer ); ! 576: return false; ! 577: } ! 578: ! 579: STX_SaveStruct[ Drive ].SaveSectorsCount = STX_ReadU32_BE ( p ); /* +8 ... +11 */ ! 580: p += 4; ! 581: ! 582: STX_SaveStruct[ Drive ].SaveTracksCount = STX_ReadU32_BE ( p ); /* +12 ... +15 */ ! 583: p += 4; ! 584: ! 585: ! 586: /* Alloc a buffer for all the sectors */ ! 587: if ( STX_SaveStruct[ Drive ].SaveSectorsCount > 0 ) ! 588: { ! 589: STX_SaveStruct[ Drive ].pSaveSectorsStruct = malloc ( STX_SaveStruct[ Drive ].SaveSectorsCount * sizeof ( STX_SAVE_SECTOR_STRUCT ) ); ! 590: if ( !STX_SaveStruct[ Drive ].pSaveSectorsStruct ) ! 591: { ! 592: Log_AlertDlg(LOG_ERROR, "Error loading STX sectors save file malloc size=%d in drive %d" , ! 593: STX_SaveStruct[ Drive ].SaveSectorsCount , Drive ); ! 594: STX_FreeSaveStruct ( Drive ); ! 595: free ( SaveFileBuffer ); ! 596: return false; ! 597: } ! 598: } ! 599: ! 600: /* Alloc a buffer for all the tracks */ ! 601: if ( STX_SaveStruct[ Drive ].SaveTracksCount > 0 ) ! 602: { ! 603: STX_SaveStruct[ Drive ].pSaveTracksStruct = malloc ( STX_SaveStruct[ Drive ].SaveTracksCount * sizeof ( STX_SAVE_TRACK_STRUCT ) ); ! 604: if ( !STX_SaveStruct[ Drive ].pSaveTracksStruct ) ! 605: { ! 606: Log_AlertDlg(LOG_ERROR, "Error loading STX tracks save file malloc size=%d in drive %d" , ! 607: STX_SaveStruct[ Drive ].SaveTracksCount , Drive ); ! 608: STX_FreeSaveStruct ( Drive ); ! 609: free ( SaveFileBuffer ); ! 610: return false; ! 611: } ! 612: } ! 613: ! 614: ! 615: SectorNb = 0; ! 616: TrackNb = 0; ! 617: while ( p < SaveFileBuffer + SaveFileSize ) ! 618: { ! 619: /* Start of a block */ ! 620: p_save = p; ! 621: //Str_Dump_Hex_Ascii ( (char *) p , 32, 16, "" , stderr ); ! 622: ! 623: /* Check the name of this block */ ! 624: if ( strncmp ( (char *) p , WD1772_SAVE_SECTOR_ID , 4 ) == 0 ) ! 625: { ! 626: //fprintf ( stderr , "STX_LoadSaveFile drive=%d SECT block %d\n" , Drive , SectorNb ); ! 627: if ( STX_LoadSaveFile_SECT ( Drive , &STX_SaveStruct[ Drive ].pSaveSectorsStruct[ SectorNb ] , p+4+4 ) == false ) ! 628: { ! 629: Log_AlertDlg(LOG_ERROR, "Error loading STX save file SECT block %d in drive %d" , ! 630: SectorNb , Drive ); ! 631: STX_FreeSaveStruct ( Drive ); ! 632: free ( SaveFileBuffer ); ! 633: return false; ! 634: } ! 635: ! 636: //Str_Dump_Hex_Ascii ( (char *) &STX_SaveStruct[ Drive ].pSaveSectorsStruct[ SectorNb ] , sizeof(STX_SAVE_SECTOR_STRUCT) , 16, "" , stderr ); ! 637: //Str_Dump_Hex_Ascii ( (char *) STX_SaveStruct[ Drive ].pSaveSectorsStruct[ SectorNb ].pData , 32, 16, "" , stderr ); ! 638: ! 639: /* Find the original sector to associate it with this saved sector */ ! 640: pStxSector = STX_FindSector_By_Position ( Drive , STX_SaveStruct[ Drive ].pSaveSectorsStruct[ SectorNb ].Track , ! 641: STX_SaveStruct[ Drive ].pSaveSectorsStruct[ SectorNb ].Side , ! 642: STX_SaveStruct[ Drive ].pSaveSectorsStruct[ SectorNb ].BitPosition ); ! 643: if ( !pStxSector ) ! 644: { ! 645: Log_AlertDlg(LOG_ERROR, "Error restoring STX save buffer for sector=%d in drive %d" , ! 646: SectorNb , Drive ); ! 647: STX_FreeSaveStruct ( Drive ); ! 648: free ( SaveFileBuffer ); ! 649: return false; ! 650: } ! 651: pStxSector->SaveSectorIndex = SectorNb; ! 652: ! 653: SectorNb++; ! 654: } ! 655: ! 656: else if ( strncmp ( (char *) p , WD1772_SAVE_TRACK_ID , 4 ) == 0 ) ! 657: { ! 658: //fprintf ( stderr , "STX_LoadSaveFile drive=%d TRCK block %d\n" , Drive , TrackNb ); ! 659: if ( STX_LoadSaveFile_TRCK ( Drive , &STX_SaveStruct[ Drive ].pSaveTracksStruct[ TrackNb ] , p+4+4 ) == false ) ! 660: { ! 661: Log_AlertDlg(LOG_ERROR, "Error loading STX save file TRCK block %d in drive %d" , ! 662: TrackNb , Drive ); ! 663: STX_FreeSaveStruct ( Drive ); ! 664: free ( SaveFileBuffer ); ! 665: return false; ! 666: } ! 667: ! 668: /* Find the original track to associate it with this saved track */ ! 669: pStxTrack = STX_FindTrack ( Drive , STX_SaveStruct[ Drive ].pSaveTracksStruct[ TrackNb ].Track , ! 670: STX_SaveStruct[ Drive ].pSaveTracksStruct[ TrackNb ].Side ); ! 671: if ( !pStxTrack ) ! 672: { ! 673: Log_AlertDlg(LOG_ERROR, "Error loading STX save file TRCK block %d in drive %d" , ! 674: TrackNb , Drive ); ! 675: STX_FreeSaveStruct ( Drive ); ! 676: free ( SaveFileBuffer ); ! 677: return false; ! 678: } ! 679: pStxTrack->SaveTrackIndex = TrackNb; ! 680: ! 681: TrackNb++; ! 682: } ! 683: ! 684: else ! 685: { ! 686: fprintf ( stderr , "STX_LoadSaveFile drive=%d file=%s, unknown block %4.4s, skipping\n" , Drive , FilenameSave , p ); ! 687: } ! 688: ! 689: /* Next block */ ! 690: p = p_save + 4; ! 691: p += STX_ReadU32_BE ( p ); ! 692: } ! 693: ! 694: free ( SaveFileBuffer ); ! 695: return true; ! 696: } ! 697: ! 698: ! 699: /*-----------------------------------------------------------------------*/ ! 700: /* ! 701: * Parse the "SECT" block from a ".wd1772" save file ! 702: * Return true if OK. ! 703: */ ! 704: static bool STX_LoadSaveFile_SECT ( int Drive, STX_SAVE_SECTOR_STRUCT *pStxSaveSector , Uint8 *p ) ! 705: { ! 706: pStxSaveSector->Track = *p++; ! 707: pStxSaveSector->Side = *p++; ! 708: ! 709: pStxSaveSector->BitPosition = STX_ReadU16_BE ( p ); ! 710: p += 2; ! 711: ! 712: pStxSaveSector->ID_Track = *p++; ! 713: pStxSaveSector->ID_Head = *p++; ! 714: pStxSaveSector->ID_Sector = *p++; ! 715: pStxSaveSector->ID_Size = *p++; ! 716: pStxSaveSector->ID_CRC = STX_ReadU16_BE ( p ); ! 717: p += 2; ! 718: ! 719: pStxSaveSector->SectorSize = STX_ReadU16_BE ( p ); ! 720: p += 2; ! 721: ! 722: /* Copy the sector's data */ ! 723: pStxSaveSector->pData = malloc ( pStxSaveSector->SectorSize ); ! 724: if ( !pStxSaveSector->pData ) ! 725: { ! 726: Log_AlertDlg(LOG_ERROR, "Error loading STX save buffer for track=%d side=%d bitposition=%d in drive %d" , ! 727: pStxSaveSector->Track , pStxSaveSector->Side , pStxSaveSector->BitPosition , Drive ); ! 728: return false; ! 729: } ! 730: ! 731: memcpy ( pStxSaveSector->pData , p , pStxSaveSector->SectorSize ); ! 732: ! 733: pStxSaveSector->StructIsUsed = 1; ! 734: ! 735: return true; ! 736: } ! 737: ! 738: ! 739: /*-----------------------------------------------------------------------*/ ! 740: /* ! 741: * Parse the "TRCK" block from a ".wd1772" save file ! 742: * Return true if OK. ! 743: */ ! 744: static bool STX_LoadSaveFile_TRCK ( int Drive , STX_SAVE_TRACK_STRUCT *pStxSaveTrack , Uint8 *p ) ! 745: { ! 746: pStxSaveTrack->Track = *p++; ! 747: pStxSaveTrack->Side = *p++; ! 748: ! 749: pStxSaveTrack->TrackSizeWrite = STX_ReadU16_BE ( p ); ! 750: p += 2; ! 751: ! 752: /* Copy the track's data */ ! 753: pStxSaveTrack->pDataWrite = malloc ( pStxSaveTrack->TrackSizeWrite ); ! 754: if ( !pStxSaveTrack->pDataWrite ) ! 755: { ! 756: Log_AlertDlg(LOG_ERROR, "Error loading STX save buffer for track=%d side=%d in drive %d" , ! 757: pStxSaveTrack->Track , pStxSaveTrack->Side , Drive ); ! 758: return false; ! 759: } ! 760: ! 761: memcpy ( pStxSaveTrack->pDataWrite , p , pStxSaveTrack->TrackSizeWrite ); ! 762: ! 763: pStxSaveTrack->pDataRead = NULL; /* TODO : compute interpreted track */ ! 764: pStxSaveTrack->TrackSizeRead = 0; /* TODO : compute interpreted track */ ! 765: ! 766: return true; ! 767: } ! 768: ! 769: ! 770: ! 771: /*-----------------------------------------------------------------------*/ ! 772: /* ! 773: * Init variables used to handle STX images ! 774: */ ! 775: bool STX_Init ( void ) ! 776: { ! 777: int i; ! 778: ! 779: for ( i=0 ; i<MAX_FLOPPYDRIVES ; i++ ) ! 780: { ! 781: STX_State.ImageBuffer[ i ] = NULL; ! 782: ! 783: STX_SaveStruct[ i ].SaveSectorsCount = 0; ! 784: STX_SaveStruct[ i ].pSaveSectorsStruct = NULL; ! 785: STX_SaveStruct[ i ].SaveTracksCount = 0; ! 786: STX_SaveStruct[ i ].pSaveTracksStruct = NULL; ! 787: } ! 788: ! 789: return true; ! 790: } ! 791: ! 792: ! 793: /*-----------------------------------------------------------------------*/ ! 794: /* ! 795: * Init the ressources to handle the STX image inserted into a drive (0=A: 1=B:) ! 796: * We also look for an optional save file with the ".wd1772" extension. ! 797: * If this file exists, then we load it too. ! 798: */ ! 799: bool STX_Insert ( int Drive , const char *FilenameSTX , Uint8 *pImageBuffer , long ImageSize ) ! 800: { ! 801: char FilenameSave[ FILENAME_MAX ]; ! 802: ! 803: /* Process the current STX image */ ! 804: if ( STX_Insert_internal ( Drive , FilenameSTX , pImageBuffer , ImageSize ) == false ) ! 805: return false; ! 806: ! 807: /* Try to load an optional ".wd1772" save file. In case of error, we continue anyway with the current STX image */ ! 808: if ( ( STX_FileNameToSave ( FilenameSTX , FilenameSave ) ) ! 809: && ( File_Exists ( FilenameSave ) ) ) ! 810: { ! 811: fprintf ( stderr , "STX : STX_Insert drive=%d file=%s buf=%p size=%ld load wd1172 %s\n" , Drive , FilenameSTX , pImageBuffer , ImageSize , FilenameSave ); ! 812: if ( STX_LoadSaveFile ( Drive , FilenameSave ) == false ) ! 813: { ! 814: Log_AlertDlg ( LOG_ERROR , "Can't read the STX save file '%s'. Ignore it" , FilenameSave ); ! 815: } ! 816: } ! 817: ! 818: return true; ! 819: } ! 820: ! 821: ! 822: /*-----------------------------------------------------------------------*/ ! 823: /* ! 824: * Init the ressources to handle the STX image inserted into a drive (0=A: 1=B:) ! 825: * This function is used when restoring a memory snapshot and does not load ! 826: * an optional ".wd1772" save file (the saved data are already in the memory ! 827: * snapshot) ! 828: */ ! 829: static bool STX_Insert_internal ( int Drive , const char *FilenameSTX , Uint8 *pImageBuffer , long ImageSize ) ! 830: { ! 831: fprintf ( stderr , "STX : STX_Insert_internal drive=%d file=%s buf=%p size=%ld\n" , Drive , FilenameSTX , pImageBuffer , ImageSize ); ! 832: ! 833: STX_State.ImageBuffer[ Drive ] = STX_BuildStruct ( pImageBuffer , STX_DEBUG_FLAG ); ! 834: if ( STX_State.ImageBuffer[ Drive ] == NULL ) ! 835: { ! 836: fprintf ( stderr , "STX : STX_Insert_internal drive=%d file=%s buf=%p size=%ld, error in STX_BuildStruct\n" , Drive , FilenameSTX , pImageBuffer , ImageSize ); ! 837: return false; ! 838: } ! 839: ! 840: return true; ! 841: } ! 842: ! 843: ! 844: /*-----------------------------------------------------------------------*/ ! 845: /* ! 846: * When ejecting a disk, free the ressources associated with an STX image ! 847: */ ! 848: bool STX_Eject ( int Drive ) ! 849: { ! 850: fprintf ( stderr , "STX : STX_Eject drive=%d\n" , Drive ); ! 851: ! 852: if ( STX_State.ImageBuffer[ Drive ] ) ! 853: { ! 854: STX_FreeStruct ( STX_State.ImageBuffer[ Drive ] ); ! 855: STX_State.ImageBuffer[ Drive ] = NULL; ! 856: } ! 857: ! 858: STX_FreeSaveStruct ( Drive ); ! 859: ! 860: return true; ! 861: } ! 862: ! 863: ! 864: /*-----------------------------------------------------------------------*/ ! 865: /* ! 866: * Read words and longs stored in little endian order ! 867: */ ! 868: static Uint16 STX_ReadU16_LE ( Uint8 *p ) ! 869: { ! 870: return (p[1]<<8) +p [0]; ! 871: } ! 872: ! 873: static Uint32 STX_ReadU32_LE ( Uint8 *p ) ! 874: { ! 875: return (p[3]<<24) + (p[2]<<16) + (p[1]<<8) +p[0]; ! 876: } ! 877: ! 878: ! 879: /*-----------------------------------------------------------------------*/ ! 880: /* ! 881: * Read words and longs stored in big endian order ! 882: */ ! 883: static Uint16 STX_ReadU16_BE ( Uint8 *p ) ! 884: { ! 885: return (p[0]<<8) + p[1]; ! 886: } ! 887: ! 888: static Uint32 STX_ReadU32_BE ( Uint8 *p ) ! 889: { ! 890: return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) +p[3]; ! 891: } ! 892: ! 893: ! 894: /*-----------------------------------------------------------------------*/ ! 895: /* ! 896: * Store words and longs in big endian order ! 897: */ ! 898: static void STX_WriteU16_BE ( Uint8 *p , Uint16 val ) ! 899: { ! 900: p[ 1 ] = val & 0xff; ! 901: val >>= 8; ! 902: p[ 0 ] = val & 0xff; ! 903: } ! 904: ! 905: static void STX_WriteU32_BE ( Uint8 *p , Uint32 val ) ! 906: { ! 907: p[ 3 ] = val & 0xff; ! 908: val >>= 8; ! 909: p[ 2 ] = val & 0xff; ! 910: val >>= 8; ! 911: p[ 1 ] = val & 0xff; ! 912: val >>= 8; ! 913: p[ 0 ] = val & 0xff; ! 914: } ! 915: ! 916: /*-----------------------------------------------------------------------*/ ! 917: /** ! 918: * Free all the memory allocated to store an STX file ! 919: */ ! 920: static void STX_FreeStruct ( STX_MAIN_STRUCT *pStxMain ) ! 921: { ! 922: int Track; ! 923: ! 924: if ( !pStxMain ) ! 925: return; ! 926: ! 927: for ( Track = 0 ; Track < pStxMain->TracksCount ; Track++ ) ! 928: { ! 929: free ( (pStxMain->pTracksStruct[ Track ]).pSectorsStruct ); ! 930: } ! 931: ! 932: free ( pStxMain->pTracksStruct ); ! 933: free ( pStxMain ); ! 934: } ! 935: ! 936: ! 937: /*-----------------------------------------------------------------------*/ ! 938: /** ! 939: * Free all the memory allocated to store saved sectors / tracks ! 940: */ ! 941: static void STX_FreeSaveStruct ( int Drive ) ! 942: { ! 943: if ( STX_SaveStruct[ Drive ].pSaveSectorsStruct ) ! 944: { ! 945: STX_FreeSaveSectorsStructAll ( STX_SaveStruct[ Drive ].pSaveSectorsStruct , STX_SaveStruct[ Drive ].SaveSectorsCount ); ! 946: STX_SaveStruct[ Drive ].SaveSectorsCount = 0; ! 947: STX_SaveStruct[ Drive ].pSaveSectorsStruct = NULL; ! 948: } ! 949: ! 950: if ( STX_SaveStruct[ Drive ].pSaveTracksStruct ) ! 951: { ! 952: STX_FreeSaveTracksStructAll ( STX_SaveStruct[ Drive ].pSaveTracksStruct , STX_SaveStruct[ Drive ].SaveTracksCount ); ! 953: STX_SaveStruct[ Drive ].SaveTracksCount = 0; ! 954: STX_SaveStruct[ Drive ].pSaveTracksStruct = NULL; ! 955: } ! 956: } ! 957: ! 958: ! 959: /*-----------------------------------------------------------------------*/ ! 960: /** ! 961: * Free the memory allocated to store all the STX_SAVE_SECTOR_STRUCT ! 962: */ ! 963: static void STX_FreeSaveSectorsStructAll ( STX_SAVE_SECTOR_STRUCT *pSaveSectorsStruct , Uint32 SaveSectorsCount ) ! 964: { ! 965: Uint32 i; ! 966: ! 967: if ( !pSaveSectorsStruct ) ! 968: return; ! 969: ! 970: for ( i = 0 ; i < SaveSectorsCount ; i++ ) ! 971: { ! 972: STX_FreeSaveSectorsStruct ( pSaveSectorsStruct , i ); ! 973: } ! 974: ! 975: free ( pSaveSectorsStruct ); ! 976: } ! 977: ! 978: ! 979: /*-----------------------------------------------------------------------*/ ! 980: /** ! 981: * Free the memory allocated to store one STX_SAVE_SECTOR_STRUCT ! 982: */ ! 983: static void STX_FreeSaveSectorsStruct ( STX_SAVE_SECTOR_STRUCT *pSaveSectorsStruct , int Nb ) ! 984: { ! 985: if ( pSaveSectorsStruct[ Nb ].StructIsUsed == 0 ) ! 986: return; /* This structure is already free */ ! 987: ! 988: if ( pSaveSectorsStruct[ Nb ].pData ) ! 989: free ( pSaveSectorsStruct[ Nb ].pData ); ! 990: ! 991: pSaveSectorsStruct[ Nb ].StructIsUsed = 0; ! 992: } ! 993: ! 994: ! 995: /*-----------------------------------------------------------------------*/ ! 996: /** ! 997: * Free the memory allocated to store all the STX_SAVE_TRACK_STRUCT ! 998: */ ! 999: static void STX_FreeSaveTracksStructAll ( STX_SAVE_TRACK_STRUCT *pSaveTracksStruct , Uint32 SaveTracksCount ) ! 1000: { ! 1001: Uint32 i; ! 1002: ! 1003: if ( !pSaveTracksStruct ) ! 1004: return; ! 1005: ! 1006: for ( i = 0 ; i < SaveTracksCount ; i++ ) ! 1007: { ! 1008: STX_FreeSaveTracksStruct ( pSaveTracksStruct , i ); ! 1009: } ! 1010: ! 1011: free ( pSaveTracksStruct ); ! 1012: } ! 1013: ! 1014: ! 1015: /*-----------------------------------------------------------------------*/ ! 1016: /** ! 1017: * Free the memory allocated to store one STX_SAVE_TRACK_STRUCT ! 1018: */ ! 1019: static void STX_FreeSaveTracksStruct ( STX_SAVE_TRACK_STRUCT *pSaveTracksStruct , int Nb ) ! 1020: { ! 1021: if ( pSaveTracksStruct[ Nb ].pDataWrite ) ! 1022: free ( pSaveTracksStruct[ Nb ].pDataWrite ); ! 1023: if ( pSaveTracksStruct[ Nb ].pDataRead ) ! 1024: free ( pSaveTracksStruct[ Nb ].pDataRead ); ! 1025: } ! 1026: ! 1027: ! 1028: /*-----------------------------------------------------------------------*/ ! 1029: /** ! 1030: * Parse an STX file. ! 1031: * The file is in pFileBuffer and we dynamically allocate memory to store ! 1032: * the components (main header, tracks, sectors). ! 1033: * Some internal variables/pointers are also computed, to speed up ! 1034: * data access when the FDC emulates an STX file. ! 1035: */ ! 1036: STX_MAIN_STRUCT *STX_BuildStruct ( Uint8 *pFileBuffer , int Debug ) ! 1037: { ! 1038: ! 1039: STX_MAIN_STRUCT *pStxMain; ! 1040: STX_TRACK_STRUCT *pStxTrack; ! 1041: STX_SECTOR_STRUCT *pStxSector; ! 1042: Uint8 *p; ! 1043: Uint8 *p_cur; ! 1044: int Track; ! 1045: int Sector; ! 1046: Uint8 *pFuzzyData; ! 1047: Uint8 *pTimingData; ! 1048: Uint32 MaxOffsetSectorEnd; ! 1049: int VariableTimings; ! 1050: ! 1051: pStxMain = malloc ( sizeof ( STX_MAIN_STRUCT ) ); ! 1052: if ( !pStxMain ) ! 1053: return NULL; ! 1054: memset ( pStxMain , 0 , sizeof ( STX_MAIN_STRUCT ) ); ! 1055: ! 1056: p = pFileBuffer; ! 1057: ! 1058: /* Read file's header */ ! 1059: memcpy ( pStxMain->FileID , p , 4 ); p += 4; ! 1060: pStxMain->Version = STX_ReadU16_LE ( p ); p += 2; ! 1061: pStxMain->ImagingTool = STX_ReadU16_LE ( p ); p += 2; ! 1062: pStxMain->Reserved_1 = STX_ReadU16_LE ( p ); p += 2; ! 1063: pStxMain->TracksCount = *p++;; ! 1064: pStxMain->Revision = *p++; ! 1065: pStxMain->Reserved_2 = STX_ReadU32_LE ( p ); p += 4; ! 1066: ! 1067: if ( Debug & STX_DEBUG_FLAG_STRUCTURE ) ! 1068: fprintf ( stderr , "STX header ID='%.4s' Version=%4.4x ImagingTool=%4.4x Reserved1=%4.4x" ! 1069: " TrackCount=%d Revision=%2.2x Reserved2=%x\n" , pStxMain->FileID , pStxMain->Version , ! 1070: pStxMain->ImagingTool , pStxMain->Reserved_1 , pStxMain->TracksCount , pStxMain->Revision , ! 1071: pStxMain->Reserved_2 ); ! 1072: ! 1073: pStxMain->WarnedWriteSector = false; ! 1074: pStxMain->WarnedWriteTrack = false; ! 1075: ! 1076: pStxTrack = malloc ( sizeof ( STX_TRACK_STRUCT ) * pStxMain->TracksCount ); ! 1077: if ( !pStxTrack ) ! 1078: { ! 1079: STX_FreeStruct ( pStxMain ); ! 1080: return NULL; ! 1081: } ! 1082: memset ( pStxTrack , 0 , sizeof ( STX_TRACK_STRUCT ) * pStxMain->TracksCount ); ! 1083: pStxMain->pTracksStruct = pStxTrack; ! 1084: ! 1085: /* Parse all the track blocks */ ! 1086: for ( Track = 0 ; Track < pStxMain->TracksCount ; Track++ ) ! 1087: { ! 1088: p_cur = p; ! 1089: ! 1090: pStxTrack->BlockSize = STX_ReadU32_LE ( p ); p += 4; ! 1091: pStxTrack->FuzzySize = STX_ReadU32_LE ( p ); p += 4; ! 1092: pStxTrack->SectorsCount = STX_ReadU16_LE ( p ); p += 2; ! 1093: pStxTrack->Flags = STX_ReadU16_LE ( p ); p += 2; ! 1094: pStxTrack->MFMSize = STX_ReadU16_LE ( p ); p += 2; ! 1095: pStxTrack->TrackNumber = *p++; ! 1096: pStxTrack->RecordType = *p++; ! 1097: ! 1098: pStxTrack->SaveTrackIndex = -1; ! 1099: ! 1100: if ( pStxTrack->SectorsCount == 0 ) /* No sector (track image only, or empty / non formatted track) */ ! 1101: { ! 1102: pStxTrack->pSectorsStruct = NULL; ! 1103: } ! 1104: else ! 1105: { ! 1106: /* Track contains some sectors */ ! 1107: pStxSector = malloc ( sizeof ( STX_SECTOR_STRUCT ) * pStxTrack->SectorsCount ); ! 1108: if ( !pStxSector ) ! 1109: { ! 1110: STX_FreeStruct ( pStxMain ); ! 1111: return NULL; ! 1112: } ! 1113: memset ( pStxSector , 0 , sizeof ( STX_SECTOR_STRUCT ) * pStxTrack->SectorsCount ); ! 1114: pStxTrack->pSectorsStruct = pStxSector; ! 1115: ! 1116: /* Do we have some sector infos after the track header or only sector data ? */ ! 1117: if ( ( pStxTrack->Flags & STX_TRACK_FLAG_SECTOR_BLOCK ) == 0 ) ! 1118: { ! 1119: /* The track only contains SectorsCount sectors of 512 bytes */ ! 1120: /* NOTE |NP] : in that case, pStxTrack->MFMSize seems to be in bits instead of bytes */ ! 1121: STX_BuildSectorsSimple ( pStxTrack , p ); ! 1122: goto next_track; ! 1123: } ! 1124: } ! 1125: ! 1126: /* Start of the optional fuzzy bits data */ ! 1127: pStxTrack->pFuzzyData = p + pStxTrack->SectorsCount * STX_SECTOR_BLOCK_SIZE; ! 1128: ! 1129: /* Start of the optional track data */ ! 1130: pStxTrack->pTrackData = pStxTrack->pFuzzyData + pStxTrack->FuzzySize; ! 1131: ! 1132: if ( ( pStxTrack->Flags & STX_TRACK_FLAG_TRACK_IMAGE ) == 0 ) ! 1133: { ! 1134: pStxTrack->TrackImageSyncPosition = 0; ! 1135: pStxTrack->TrackImageSize = 0; ! 1136: pStxTrack->pTrackImageData = NULL; ! 1137: pStxTrack->pSectorsImageData = pStxTrack->pTrackData; ! 1138: } ! 1139: else if ( ( pStxTrack->Flags & STX_TRACK_FLAG_TRACK_IMAGE_SYNC ) == 0 ) /* Track with size+data */ ! 1140: { ! 1141: pStxTrack->TrackImageSyncPosition = 0; ! 1142: pStxTrack->TrackImageSize = STX_ReadU16_LE ( pStxTrack->pTrackData ); ! 1143: pStxTrack->pTrackImageData = pStxTrack->pTrackData + 2; ! 1144: pStxTrack->pSectorsImageData = pStxTrack->pTrackImageData + pStxTrack->TrackImageSize; ! 1145: } ! 1146: else /* Track with sync offset + size + data */ ! 1147: { ! 1148: pStxTrack->TrackImageSyncPosition = STX_ReadU16_LE ( pStxTrack->pTrackData ); ! 1149: pStxTrack->TrackImageSize = STX_ReadU16_LE ( pStxTrack->pTrackData + 2 ); ! 1150: pStxTrack->pTrackImageData = pStxTrack->pTrackData + 4; ! 1151: pStxTrack->pSectorsImageData = pStxTrack->pTrackImageData + pStxTrack->TrackImageSize; ! 1152: } ! 1153: ! 1154: if ( pStxTrack->SectorsCount == 0 ) /* No sector (track image only, or empty / non formatted track) */ ! 1155: goto next_track; ! 1156: ! 1157: /* Parse all the sectors in this track */ ! 1158: pFuzzyData = pStxTrack->pFuzzyData; ! 1159: VariableTimings = 0; ! 1160: MaxOffsetSectorEnd = 0; ! 1161: for ( Sector = 0 ; Sector < pStxTrack->SectorsCount ; Sector++ ) ! 1162: { ! 1163: pStxSector = &(pStxTrack->pSectorsStruct[ Sector ]); ! 1164: ! 1165: pStxSector->DataOffset = STX_ReadU32_LE ( p ); p += 4; ! 1166: pStxSector->BitPosition = STX_ReadU16_LE ( p ); p += 2; ! 1167: pStxSector->ReadTime = STX_ReadU16_LE ( p ); p += 2; ! 1168: pStxSector->ID_Track = *p++; ! 1169: pStxSector->ID_Head = *p++; ! 1170: pStxSector->ID_Sector = *p++; ! 1171: pStxSector->ID_Size = *p++; ! 1172: pStxSector->ID_CRC = ( p[0] << 8 ) | p[1] ; p +=2; ! 1173: pStxSector->FDC_Status = *p++; ! 1174: pStxSector->Reserved = *p++; ! 1175: ! 1176: /* Check if sector has data */ ! 1177: if ( ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF ) == 0 ) ! 1178: { ! 1179: /* Check if SectorSize is valid (this is just a warning, we keep only bits 0-1 anyway) */ ! 1180: if ( pStxSector->ID_Size & ~FDC_SECTOR_SIZE_MASK ) ! 1181: { ! 1182: // fprintf ( stderr , "STX : invalid ID_Size=%d on track %d sector %d\n" , ! 1183: // pStxSector->ID_Size , Track , Sector ); ! 1184: } ! 1185: ! 1186: pStxSector->SectorSize = 128 << ( pStxSector->ID_Size & FDC_SECTOR_SIZE_MASK ); ! 1187: ! 1188: pStxSector->pData = pStxTrack->pTrackData + pStxSector->DataOffset; ! 1189: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_FUZZY ) ! 1190: { ! 1191: pStxSector->pFuzzyData = pFuzzyData; ! 1192: pFuzzyData += pStxSector->SectorSize; ! 1193: } ! 1194: ! 1195: /* Max offset of the end of all sectors image in the track */ ! 1196: if ( MaxOffsetSectorEnd < pStxSector->DataOffset + pStxSector->SectorSize ) ! 1197: MaxOffsetSectorEnd = pStxSector->DataOffset + pStxSector->SectorSize; ! 1198: ! 1199: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_VARIABLE_TIME ) ! 1200: VariableTimings = 1; ! 1201: } ! 1202: ! 1203: pStxSector->SaveSectorIndex = -1; ! 1204: } ! 1205: ! 1206: /* Start of the optional timings data, after the optional sectors image data */ ! 1207: pStxTrack->pTiming = pStxTrack->pTrackData + MaxOffsetSectorEnd; ! 1208: if ( pStxTrack->pTiming < pStxTrack->pSectorsImageData ) /* If all sectors image were inside the track image */ ! 1209: pStxTrack->pTiming = pStxTrack->pSectorsImageData; /* then timings data are just after the track image */ ! 1210: ! 1211: if ( VariableTimings == 1 ) /* Track has at least one variable sector */ ! 1212: { ! 1213: if ( pStxMain->Revision == 2 ) /* Specific timing table */ ! 1214: { ! 1215: pStxTrack->TimingFlags = STX_ReadU16_LE ( pStxTrack->pTiming ); /* always '5' ? */ ! 1216: pStxTrack->TimingSize = STX_ReadU16_LE ( pStxTrack->pTiming + 2 ); ! 1217: pStxTrack->pTimingData = pStxTrack->pTiming + 4; /* 2 bytes of timing for each block of 16 bytes */ ! 1218: } ! 1219: ! 1220: /* Compute the address of the timings data for each sector with variable timings */ ! 1221: pTimingData = pStxTrack->pTimingData; ! 1222: for ( Sector = 0 ; Sector < pStxTrack->SectorsCount ; Sector++ ) ! 1223: { ! 1224: pStxSector = &(pStxTrack->pSectorsStruct[ Sector ]); ! 1225: pStxSector->pTimingData = NULL; /* No timings by default */ ! 1226: ! 1227: /* Check if sector has data + variable timings */ ! 1228: if ( ( ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF ) == 0 ) ! 1229: && ( pStxSector->FDC_Status & STX_SECTOR_FLAG_VARIABLE_TIME ) ) ! 1230: { ! 1231: if ( pStxMain->Revision == 2 ) /* Specific table for revision 2 */ ! 1232: { ! 1233: pStxSector->pTimingData = pTimingData; ! 1234: pTimingData += ( pStxSector->SectorSize / 16 ) * 2; ! 1235: } ! 1236: else ! 1237: pStxSector->pTimingData = TimingDataDefault; /* Fixed table for revision 0 */ ! 1238: } ! 1239: } ! 1240: } ! 1241: ! 1242: next_track: ! 1243: if ( Debug & STX_DEBUG_FLAG_STRUCTURE ) ! 1244: { ! 1245: fprintf ( stderr , " track %3d BlockSize=%d FuzzySize=%d Sectors=%4.4x Flags=%4.4x" ! 1246: " MFMSize=%d TrackNb=%2.2x Side=%d RecordType=%x" ! 1247: " TrackImage=%s (%d bytes, sync=%4.4x) Timings=%d,%d\n" , ! 1248: Track , pStxTrack->BlockSize , ! 1249: pStxTrack->FuzzySize , pStxTrack->SectorsCount , pStxTrack->Flags , pStxTrack->MFMSize , ! 1250: pStxTrack->TrackNumber & 0x7f , ( pStxTrack->TrackNumber >> 7 ) & 0x01 , pStxTrack->RecordType , ! 1251: pStxTrack->pTrackImageData ? "yes" : "no" , pStxTrack->TrackImageSize , pStxTrack->TrackImageSyncPosition , ! 1252: pStxTrack->TimingFlags , pStxTrack->TimingSize ); ! 1253: ! 1254: if ( ( Debug & STX_DEBUG_FLAG_DATA ) && pStxTrack->pTrackImageData ) ! 1255: { ! 1256: fprintf ( stderr , " track image data :\n" ); ! 1257: Str_Dump_Hex_Ascii ( (char *)pStxTrack->pTrackImageData , pStxTrack->TrackImageSize , ! 1258: 16 , " " , stderr ); ! 1259: } ! 1260: ! 1261: if ( pStxTrack->SectorsCount == 0 ) ! 1262: fprintf ( stderr , " no sector in this track, %s\n" , ! 1263: pStxTrack->pTrackImageData ? "only track image" : "track empty / not formatted" ); ! 1264: else ! 1265: for ( Sector = 0 ; Sector < pStxTrack->SectorsCount ; Sector++ ) ! 1266: { ! 1267: /* If the sector use the internal timing table, we print TimingsOffset=-1 */ ! 1268: pStxSector = &(pStxTrack->pSectorsStruct[ Sector ]); ! 1269: fprintf ( stderr , " sector %2d DataOffset=%d BitPosition=%d ReadTime=%d" ! 1270: " [track=%2.2x head=%2.2x sector=%2.2x size=%2.2x crc=%4.4x]" ! 1271: " FdcStatus=%2.2x Reserved=%2.2x TimingsOffset=%d\n" , ! 1272: Sector , pStxSector->DataOffset , pStxSector->BitPosition , ! 1273: pStxSector->ReadTime , pStxSector->ID_Track , pStxSector->ID_Head , ! 1274: pStxSector->ID_Sector , pStxSector->ID_Size , pStxSector->ID_CRC , ! 1275: pStxSector->FDC_Status , pStxSector->Reserved , ! 1276: pStxSector->pTimingData ? ! 1277: ( pStxTrack->TimingSize > 0 ? (int)(pStxSector->pTimingData - pStxTrack->pTrackData) : -1 ) ! 1278: : 0 ); ! 1279: ! 1280: if ( ( Debug & STX_DEBUG_FLAG_DATA ) && pStxSector->pData ) ! 1281: { ! 1282: fprintf ( stderr , " sector data :\n" ); ! 1283: Str_Dump_Hex_Ascii ( (char *)pStxSector->pData , pStxSector->SectorSize , ! 1284: 16 , " " , stderr ); ! 1285: } ! 1286: if ( ( Debug & STX_DEBUG_FLAG_DATA ) && pStxSector->pFuzzyData ) ! 1287: { ! 1288: fprintf ( stderr , " fuzzy data :\n" ); ! 1289: Str_Dump_Hex_Ascii ( (char *)pStxSector->pFuzzyData , pStxSector->SectorSize , ! 1290: 16 , " " , stderr ); ! 1291: } ! 1292: if ( ( Debug & STX_DEBUG_FLAG_DATA ) && pStxSector->pTimingData ) ! 1293: { ! 1294: fprintf ( stderr , " timing data :\n" ); ! 1295: Str_Dump_Hex_Ascii ( (char *)pStxSector->pTimingData , ( pStxSector->SectorSize / 16 ) * 2 , ! 1296: 16 , " " , stderr ); ! 1297: } ! 1298: } ! 1299: } ! 1300: ! 1301: p = p_cur + pStxTrack->BlockSize; /* Next Track block */ ! 1302: pStxTrack++; ! 1303: } ! 1304: ! 1305: ! 1306: return pStxMain; ! 1307: } ! 1308: ! 1309: ! 1310: /*-----------------------------------------------------------------------*/ ! 1311: /** ! 1312: * When a track only consists of the content of each 512 bytes sector and ! 1313: * no timings informations, we must compute some default values for each ! 1314: * sector, as well as the position of the corresponding 512 bytes of data. ! 1315: * This is only used when storing unprotected tracks. ! 1316: */ ! 1317: static void STX_BuildSectorsSimple ( STX_TRACK_STRUCT *pStxTrack , Uint8 *p ) ! 1318: { ! 1319: int Sector; ! 1320: int BytePosition; ! 1321: Uint16 CRC; ! 1322: ! 1323: BytePosition = FDC_TRACK_LAYOUT_STANDARD_GAP1 + FDC_TRACK_LAYOUT_STANDARD_GAP2; /* Points to the 3x$A1 before the 1st IDAM $FE */ ! 1324: BytePosition += 4; /* Pasti seems to point after the 3x$A1 and the IDAM $FE */ ! 1325: ! 1326: for ( Sector = 0 ; Sector < pStxTrack->SectorsCount ; Sector++ ) ! 1327: { ! 1328: pStxTrack->pSectorsStruct[ Sector ].SaveSectorIndex = -1; ! 1329: pStxTrack->pSectorsStruct[ Sector ].DataOffset = 0; ! 1330: pStxTrack->pSectorsStruct[ Sector ].BitPosition = BytePosition * 8; ! 1331: pStxTrack->pSectorsStruct[ Sector ].ReadTime = 0; ! 1332: ! 1333: /* Build the ID Field */ ! 1334: pStxTrack->pSectorsStruct[ Sector ].ID_Track = pStxTrack->TrackNumber & 0x7f; ! 1335: pStxTrack->pSectorsStruct[ Sector ].ID_Head = ( pStxTrack->TrackNumber >> 7 ) & 0x01; ! 1336: pStxTrack->pSectorsStruct[ Sector ].ID_Sector = Sector + 1; ! 1337: pStxTrack->pSectorsStruct[ Sector ].ID_Size = FDC_SECTOR_SIZE_512; ! 1338: CRC = STX_BuildSectorID_CRC ( &(pStxTrack->pSectorsStruct[ Sector ]) ); ! 1339: pStxTrack->pSectorsStruct[ Sector ].ID_CRC = CRC; ! 1340: ! 1341: pStxTrack->pSectorsStruct[ Sector ].FDC_Status = 0; ! 1342: pStxTrack->pSectorsStruct[ Sector ].Reserved = 0; ! 1343: pStxTrack->pSectorsStruct[ Sector ].pData = p + Sector * 512; ! 1344: pStxTrack->pSectorsStruct[ Sector ].SectorSize = 128 << pStxTrack->pSectorsStruct[ Sector ].ID_Size; ! 1345: ! 1346: BytePosition += FDC_TRACK_LAYOUT_STANDARD_RAW_SECTOR_512; ! 1347: } ! 1348: } ! 1349: ! 1350: ! 1351: ! 1352: /*-----------------------------------------------------------------------*/ ! 1353: /** ! 1354: * Compute the CRC of the Address Field for a given sector. ! 1355: */ ! 1356: static Uint16 STX_BuildSectorID_CRC ( STX_SECTOR_STRUCT *pStxSector ) ! 1357: { ! 1358: Uint16 CRC; ! 1359: ! 1360: crc16_reset ( &CRC ); ! 1361: crc16_add_byte ( &CRC , 0xa1 ); ! 1362: crc16_add_byte ( &CRC , 0xa1 ); ! 1363: crc16_add_byte ( &CRC , 0xa1 ); ! 1364: crc16_add_byte ( &CRC , 0xfe ); ! 1365: crc16_add_byte ( &CRC , pStxSector->ID_Track ); ! 1366: crc16_add_byte ( &CRC , pStxSector->ID_Head ); ! 1367: crc16_add_byte ( &CRC , pStxSector->ID_Sector ); ! 1368: crc16_add_byte ( &CRC , pStxSector->ID_Size ); ! 1369: ! 1370: return CRC; ! 1371: } ! 1372: ! 1373: ! 1374: ! 1375: /*-----------------------------------------------------------------------*/ ! 1376: /** ! 1377: * Find a track in the floppy image inserted into a drive. ! 1378: */ ! 1379: static STX_TRACK_STRUCT *STX_FindTrack ( Uint8 Drive , Uint8 Track , Uint8 Side ) ! 1380: { ! 1381: int i; ! 1382: ! 1383: if ( STX_State.ImageBuffer[ Drive ] == NULL ) ! 1384: return NULL; ! 1385: ! 1386: for ( i=0 ; i<STX_State.ImageBuffer[ Drive ]->TracksCount ; i++ ) ! 1387: if ( STX_State.ImageBuffer[ Drive ]->pTracksStruct[ i ].TrackNumber == ( ( Track & 0x7f ) | ( Side << 7 ) ) ) ! 1388: return &(STX_State.ImageBuffer[ Drive ]->pTracksStruct[ i ]); ! 1389: ! 1390: return NULL; ! 1391: } ! 1392: ! 1393: ! 1394: ! 1395: /*-----------------------------------------------------------------------*/ ! 1396: /** ! 1397: * Find a sector in the floppy image inserted into a drive. ! 1398: * SectorStruct_Nb is a value set by a previous call to FDC_NextSectorID_FdcCycles_STX() ! 1399: */ ! 1400: static STX_SECTOR_STRUCT *STX_FindSector ( Uint8 Drive , Uint8 Track , Uint8 Side , Uint8 SectorStruct_Nb ) ! 1401: { ! 1402: STX_TRACK_STRUCT *pStxTrack; ! 1403: ! 1404: if ( STX_State.ImageBuffer[ Drive ] == NULL ) ! 1405: return NULL; ! 1406: ! 1407: pStxTrack = STX_FindTrack ( Drive , Track , Side ); ! 1408: if ( pStxTrack == NULL ) ! 1409: return NULL; ! 1410: ! 1411: if ( pStxTrack->pSectorsStruct == NULL ) ! 1412: return NULL; ! 1413: ! 1414: return &(pStxTrack->pSectorsStruct[ SectorStruct_Nb ]); ! 1415: } ! 1416: ! 1417: ! 1418: ! 1419: /*-----------------------------------------------------------------------*/ ! 1420: /** ! 1421: * Find a sector in the floppy image inserted into a drive. ! 1422: * The sector is identified by its BitPosition which is unique per track/side ! 1423: */ ! 1424: static STX_SECTOR_STRUCT *STX_FindSector_By_Position ( Uint8 Drive , Uint8 Track , Uint8 Side , Uint16 BitPosition ) ! 1425: { ! 1426: STX_TRACK_STRUCT *pStxTrack; ! 1427: int Sector; ! 1428: ! 1429: if ( STX_State.ImageBuffer[ Drive ] == NULL ) ! 1430: return NULL; ! 1431: ! 1432: pStxTrack = STX_FindTrack ( Drive , Track , Side ); ! 1433: if ( pStxTrack == NULL ) ! 1434: return NULL; ! 1435: ! 1436: if ( pStxTrack->pSectorsStruct == NULL ) ! 1437: return NULL; ! 1438: ! 1439: for ( Sector=0 ; Sector<pStxTrack->SectorsCount ; Sector++ ) ! 1440: if ( pStxTrack->pSectorsStruct[ Sector ].BitPosition == BitPosition ) ! 1441: return &(pStxTrack->pSectorsStruct[ Sector ]); ! 1442: ! 1443: return NULL; ! 1444: } ! 1445: ! 1446: ! 1447: ! 1448: /*-----------------------------------------------------------------------*/ ! 1449: /** ! 1450: * Return the number of FDC cycles to go from one index pulse to the next ! 1451: * one on a given drive/track/side. ! 1452: * We take the TrackSize into account to return this delay. ! 1453: */ ! 1454: extern Uint32 FDC_GetCyclesPerRev_FdcCycles_STX ( Uint8 Drive , Uint8 Track , Uint8 Side ) ! 1455: { ! 1456: STX_TRACK_STRUCT *pStxTrack; ! 1457: int TrackSize; ! 1458: ! 1459: pStxTrack = STX_FindTrack ( Drive , Track , Side ); ! 1460: if ( pStxTrack == NULL ) ! 1461: TrackSize = FDC_TRACK_BYTES_STANDARD; /* Use a standard track length is track is not available */ ! 1462: ! 1463: else if ( pStxTrack->pTrackImageData ) ! 1464: TrackSize = pStxTrack->TrackImageSize; ! 1465: else if ( ( pStxTrack->Flags & STX_TRACK_FLAG_SECTOR_BLOCK ) == 0 ) ! 1466: TrackSize = pStxTrack->MFMSize / 8; /* When the track contains only sector data, MFMSize is in bits */ ! 1467: else ! 1468: TrackSize = pStxTrack->MFMSize; ! 1469: ! 1470: //fprintf ( stderr , "fdc stx drive=%d track=0x%x side=%d size=%d\n" , Drive , Track, Side , TrackSize ); ! 1471: return TrackSize * FDC_DELAY_CYCLE_MFM_BYTE; ! 1472: } ! 1473: ! 1474: ! 1475: ! 1476: /*-----------------------------------------------------------------------*/ ! 1477: /** ! 1478: * Return the number of FDC cycles to wait before reaching the next ! 1479: * sector's ID Field in the track ($A1 $A1 $A1 $FE TR SIDE SR LEN CRC1 CRC2) ! 1480: * If no ID Field is found before the end of the track, we use the 1st ! 1481: * ID Field of the track (which simulates a full spin of the floppy). ! 1482: * We also store the next sector's number into NextSectorStruct_Nbr, ! 1483: * the next sector's number into NextSector_ID_Field_SR, the next track's number ! 1484: * into NextSector_ID_Field_TR, the next sector's lenght into ! 1485: * NextSector_ID_Field_LEN and if the CRC is correct or not into NextSector_ID_Field_CRC_OK. ! 1486: * This function assumes the sectors of each track are sorted in ascending order ! 1487: * using BitPosition. ! 1488: * If there's no available drive/floppy or no ID field in the track, we return -1 ! 1489: */ ! 1490: extern int FDC_NextSectorID_FdcCycles_STX ( Uint8 Drive , Uint8 NumberOfHeads , Uint8 Track , Uint8 Side ) ! 1491: { ! 1492: STX_TRACK_STRUCT *pStxTrack; ! 1493: int CurrentPos_FdcCycles; ! 1494: int i; ! 1495: int Delay_FdcCycles; ! 1496: int TrackSize; ! 1497: ! 1498: CurrentPos_FdcCycles = FDC_IndexPulse_GetCurrentPos_FdcCycles ( NULL ); ! 1499: if ( CurrentPos_FdcCycles < 0 ) /* No drive/floppy available at the moment */ ! 1500: return -1; ! 1501: ! 1502: if ( ( Side == 1 ) && ( NumberOfHeads == 1 ) ) /* Can't read side 1 on a single sided drive */ ! 1503: return -1; ! 1504: ! 1505: pStxTrack = STX_FindTrack ( Drive , Track , Side ); ! 1506: if ( pStxTrack == NULL ) /* Track/Side don't exist in this STX image */ ! 1507: return -1; ! 1508: ! 1509: if ( pStxTrack->SectorsCount == 0 ) /* No sector (track image only, or empty / non formatted track) */ ! 1510: return -1; ! 1511: ! 1512: /* Compare CurrentPos_FdcCycles with each sector's position in ascending order */ ! 1513: for ( i=0 ; i<pStxTrack->SectorsCount ; i++ ) ! 1514: { ! 1515: if ( CurrentPos_FdcCycles < (int)pStxTrack->pSectorsStruct[ i ].BitPosition*FDC_DELAY_CYCLE_MFM_BIT ) /* 1 bit = 32 cycles at 8 MHz */ ! 1516: break; /* We found the next sector */ ! 1517: } ! 1518: ! 1519: if ( i == pStxTrack->SectorsCount ) /* CurrentPos_FdcCycles is after the last ID Field of this track */ ! 1520: { ! 1521: /* Reach end of track (new index pulse), then go to 1st sector from current position */ ! 1522: if ( pStxTrack->pTrackImageData ) ! 1523: TrackSize = pStxTrack->TrackImageSize; ! 1524: else if ( ( pStxTrack->Flags & STX_TRACK_FLAG_SECTOR_BLOCK ) == 0 ) ! 1525: TrackSize = pStxTrack->MFMSize / 8; /* When the track contains only sector data, MFMSize is in bits */ ! 1526: else ! 1527: TrackSize = pStxTrack->MFMSize; ! 1528: ! 1529: Delay_FdcCycles = TrackSize * FDC_DELAY_CYCLE_MFM_BYTE - CurrentPos_FdcCycles ! 1530: + pStxTrack->pSectorsStruct[ 0 ].BitPosition*FDC_DELAY_CYCLE_MFM_BIT; ! 1531: STX_State.NextSectorStruct_Nbr = 0; ! 1532: //fprintf ( stderr , "size=%d pos=%d pos0=%d delay=%d\n" , TrackSize, CurrentPos_FdcCycles, pStxTrack->pSectorsStruct[ 0 ].BitPosition , Delay_FdcCycles ); ! 1533: } ! 1534: else /* There's an ID Field before end of track */ ! 1535: { ! 1536: Delay_FdcCycles = (int)pStxTrack->pSectorsStruct[ i ].BitPosition*FDC_DELAY_CYCLE_MFM_BIT - CurrentPos_FdcCycles; ! 1537: STX_State.NextSectorStruct_Nbr = i; ! 1538: //fprintf ( stderr , "i=%d pos=%d posi=%d delay=%d\n" , i, CurrentPos_FdcCycles, pStxTrack->pSectorsStruct[ i ].BitPosition*FDC_DELAY_CYCLE_MFM_BIT , Delay_FdcCycles ); ! 1539: } ! 1540: ! 1541: /* Store the value of the track/sector numbers in the next ID field */ ! 1542: STX_State.NextSector_ID_Field_TR = pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].ID_Track; ! 1543: STX_State.NextSector_ID_Field_SR = pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].ID_Sector; ! 1544: STX_State.NextSector_ID_Field_LEN = pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].ID_Size; ! 1545: ! 1546: /* If RNF is set and CRC error is set, then this ID field has a CRC error */ ! 1547: if ( ( pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].FDC_Status & STX_SECTOR_FLAG_RNF ) ! 1548: && ( pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].FDC_Status & STX_SECTOR_FLAG_CRC ) ) ! 1549: STX_State.NextSector_ID_Field_CRC_OK = 0; /* CRC bad */ ! 1550: else ! 1551: STX_State.NextSector_ID_Field_CRC_OK = 1; /* CRC correct */ ! 1552: ! 1553: /* BitPosition in STX seems to point just after the IDAM $FE ; we need to point 4 bytes earlier at the 1st $A1 */ ! 1554: Delay_FdcCycles -= 4 * FDC_DELAY_CYCLE_MFM_BYTE; /* Correct delay to point to $A1 $A1 $A1 $FE */ ! 1555: ! 1556: //fprintf ( stderr , "fdc bytes next sector pos=%d delay=%d maxsr=%d nextsr=%d\n" , CurrentPos_FdcCycles, Delay_FdcCycles, pStxTrack->SectorsCount, STX_State.NextSectorStruct_Nbr ); ! 1557: return Delay_FdcCycles; ! 1558: } ! 1559: ! 1560: ! 1561: ! 1562: /*-----------------------------------------------------------------------*/ ! 1563: /** ! 1564: * Return the value of the track number in the next ID field set by ! 1565: * FDC_NextSectorID_FdcCycles_STX. ! 1566: */ ! 1567: extern Uint8 FDC_NextSectorID_TR_STX ( void ) ! 1568: { ! 1569: return STX_State.NextSector_ID_Field_TR; ! 1570: } ! 1571: ! 1572: ! 1573: /*-----------------------------------------------------------------------*/ ! 1574: /** ! 1575: * Return the value of the sector number in the next ID field set by ! 1576: * FDC_NextSectorID_FdcCycles_STX. ! 1577: */ ! 1578: extern Uint8 FDC_NextSectorID_SR_STX ( void ) ! 1579: { ! 1580: return STX_State.NextSector_ID_Field_SR; ! 1581: } ! 1582: ! 1583: ! 1584: /*-----------------------------------------------------------------------*/ ! 1585: /** ! 1586: * Return the value of the sector's length in the next ID field set by ! 1587: * FDC_NextSectorID_FdcCycles_STX. ! 1588: */ ! 1589: extern Uint8 FDC_NextSectorID_LEN_STX ( void ) ! 1590: { ! 1591: return STX_State.NextSector_ID_Field_LEN; ! 1592: } ! 1593: ! 1594: ! 1595: /*-----------------------------------------------------------------------*/ ! 1596: /** ! 1597: * Return the status of the CRC in the next ID field set by ! 1598: * FDC_NextSectorID_FdcCycles_STX. ! 1599: * If '0', CRC is bad, else CRC is OK ! 1600: */ ! 1601: extern Uint8 FDC_NextSectorID_CRC_OK_STX ( void ) ! 1602: { ! 1603: return STX_State.NextSector_ID_Field_CRC_OK; ! 1604: } ! 1605: ! 1606: ! 1607: /*-----------------------------------------------------------------------*/ ! 1608: /** ! 1609: * Read a sector from a floppy image in STX format (used in type II command) ! 1610: * We return the sector NextSectorStruct_Nbr, whose value was set ! 1611: * by the latest call to FDC_NextSectorID_FdcCycles_STX ! 1612: * Each byte of the sector is added to the FDC buffer with a default timing ! 1613: * (32 microsec) or a variable timing, depending on the sector's flags. ! 1614: * Some sectors can also contains "fuzzy" bits. ! 1615: * Special care must be taken to compute the timing of each byte, which can ! 1616: * be a decimal value and must be rounded to the best possible integer. ! 1617: * ! 1618: * If the sector's data were changed by a 'write sector' command, then we assume ! 1619: * a sector with no fuzzy byte and standard timings. ! 1620: * ! 1621: * Return RNF if sector was not found, else return CRC and RECORD_TYPE values ! 1622: * for the status register. ! 1623: */ ! 1624: extern Uint8 FDC_ReadSector_STX ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side , int *pSectorSize ) ! 1625: { ! 1626: STX_SECTOR_STRUCT *pStxSector; ! 1627: int i; ! 1628: Uint8 Byte; ! 1629: Uint16 Timing; ! 1630: Uint32 Sector_ReadTime; ! 1631: double Total_cur; /* To compute closest integer timings for each byte */ ! 1632: double Total_prev; ! 1633: Uint8 *pSector_WriteData; ! 1634: ! 1635: pStxSector = STX_FindSector ( Drive , Track , Side , STX_State.NextSectorStruct_Nbr ); ! 1636: if ( pStxSector == NULL ) ! 1637: { ! 1638: fprintf ( stderr , "FDC_ReadSector_STX drive=%d track=%d side=%d sector=%d returns null !\n" , ! 1639: Drive , Track , Side , STX_State.NextSectorStruct_Nbr ); ! 1640: return STX_SECTOR_FLAG_RNF; /* Should not happen if FDC_NextSectorID_FdcCycles_STX succeeded before */ ! 1641: } ! 1642: ! 1643: /* If RNF is set, return FDC_STR_BIT_RNF */ ! 1644: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF ) ! 1645: return STX_SECTOR_FLAG_RNF; /* RNF in FDC's status register */ ! 1646: ! 1647: *pSectorSize = pStxSector->SectorSize; ! 1648: Sector_ReadTime = pStxSector->ReadTime; ! 1649: ! 1650: /* Check if this sector was changed by a 'write sector' command */ ! 1651: /* If so, we use this recent buffer instead of the original STX content */ ! 1652: if (STX_SaveStruct[Drive].SaveSectorsCount > 0 && pStxSector->SaveSectorIndex >= 0) ! 1653: { ! 1654: pSector_WriteData = STX_SaveStruct[ Drive ].pSaveSectorsStruct[ pStxSector->SaveSectorIndex ].pData; ! 1655: Sector_ReadTime = 0; /* Standard timings */ ! 1656: ! 1657: LOG_TRACE(TRACE_FDC, "fdc stx read sector drive=%d track=%d sect=%d side=%d using saved sector=%d\n" , ! 1658: Drive, Track, Sector, Side , pStxSector->SaveSectorIndex ); ! 1659: } ! 1660: else ! 1661: pSector_WriteData = NULL; ! 1662: ! 1663: if ( Sector_ReadTime == 0 ) /* Sector has a standard delay (32 us per byte) */ ! 1664: Sector_ReadTime = 32 * pStxSector->SectorSize; /* Use the real standard value instead of 0 */ ! 1665: Sector_ReadTime *= 8; /* Convert delay in us to a number of FDC cycles at 8 MHz */ ! 1666: ! 1667: Total_prev = 0; ! 1668: for ( i=0 ; i<pStxSector->SectorSize ; i++ ) ! 1669: { ! 1670: /* Get the value of each byte, with possible fuzzy bits */ ! 1671: if ( pSector_WriteData == NULL ) /* Use original STX content */ ! 1672: { ! 1673: Byte = pStxSector->pData[ i ]; ! 1674: if ( pStxSector->pFuzzyData ) ! 1675: Byte = ( Byte & pStxSector->pFuzzyData[ i ] ) | ( rand() & ~pStxSector->pFuzzyData[ i ] ); ! 1676: } ! 1677: ! 1678: else /* Use data from 'write sector' */ ! 1679: Byte = pSector_WriteData[ i ]; ! 1680: ! 1681: /* Compute the timing in FDC cycles to transfer this byte */ ! 1682: if ( ( pStxSector->pTimingData ) /* Specific timing for each block of 16 bytes */ ! 1683: && ( pSector_WriteData == NULL ) ) ! 1684: { ! 1685: Timing = ( pStxSector->pTimingData[ ( i>>4 ) * 2 ] << 8 ) ! 1686: + pStxSector->pTimingData[ ( i>>4 ) * 2 + 1 ]; /* Get big endian timing for this block of 16 bytes */ ! 1687: ! 1688: /* [NP] Formula to convert timing data comes from Pasti.prg 0.4b : */ ! 1689: /* 1 unit of timing = 32 FDC cycles at 8 MHz + 28 cycles to complete each block of 16 bytes */ ! 1690: Timing = Timing * 32 + 28; ! 1691: ! 1692: if ( i % 16 == 0 ) Total_prev = 0; /* New block of 16 bytes */ ! 1693: Total_cur = ( (double)Timing * ( ( i % 16 ) + 1 ) ) / 16; ! 1694: Timing = rint ( Total_cur - Total_prev ); ! 1695: Total_prev += Timing; ! 1696: } ! 1697: else /* Specific timing in us for the whole sector */ ! 1698: { ! 1699: Total_cur = ( (double)Sector_ReadTime * ( i+1 ) ) / pStxSector->SectorSize; ! 1700: Timing = rint ( Total_cur - Total_prev ); ! 1701: Total_prev += Timing; ! 1702: } ! 1703: ! 1704: /* Add the Byte to the buffer, Timing should be a number of FDC cycles at 8 MHz */ ! 1705: FDC_Buffer_Add_Timing ( Byte , Timing ); ! 1706: } ! 1707: ! 1708: /* Return only bits 3 and 5 of the FDC_Status */ ! 1709: return pStxSector->FDC_Status & ( STX_SECTOR_FLAG_CRC | STX_SECTOR_FLAG_RECORD_TYPE ); ! 1710: } ! 1711: ! 1712: ! 1713: /*-----------------------------------------------------------------------*/ ! 1714: /** ! 1715: * Write a sector to a floppy image in STX format (used in type II command) ! 1716: * ! 1717: * STX format doesn't support write command. For each 'write sector' we ! 1718: * store the sector data in a dedicated buffer STX_SaveStruct[].pSaveSectorsStruct. ! 1719: * When the sector is read later, we return the data from STX_SaveStruct[].pSaveSectorsStruct ! 1720: * instead of returning the data from the original STX file. ! 1721: * ! 1722: * We only allow writing for sectors whose ID field has a correct CRC and ! 1723: * where RNF is not set. ! 1724: * Any valid size can be written : 128, 256, 512 or 1024 bytes ! 1725: * ! 1726: * NOTE : data will saved in memory snapshot, as well as in an additional ! 1727: * file with the extension .wd1772. ! 1728: * ! 1729: * Return RNF if sector was not found or CRC if ID field has a CRC error. ! 1730: * Return 0 if OK. ! 1731: */ ! 1732: extern Uint8 FDC_WriteSector_STX ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side , int SectorSize ) ! 1733: { ! 1734: STX_SECTOR_STRUCT *pStxSector; ! 1735: int i; ! 1736: Uint8 *pSector_WriteData; ! 1737: void *pNewBuf; ! 1738: STX_SAVE_SECTOR_STRUCT *pStxSaveSector; ! 1739: ! 1740: pStxSector = STX_FindSector ( Drive , Track , Side , STX_State.NextSectorStruct_Nbr ); ! 1741: if ( pStxSector == NULL ) ! 1742: { ! 1743: fprintf ( stderr , "FDC_WriteSector_STX drive=%d track=%d side=%d sector=%d returns null !\n" , ! 1744: Drive , Track , Side , STX_State.NextSectorStruct_Nbr ); ! 1745: return STX_SECTOR_FLAG_RNF; /* Should not happen if FDC_NextSectorID_FdcCycles_STX succeeded before */ ! 1746: } ! 1747: ! 1748: /* If RNF is set, return FDC_STR_BIT_RNF */ ! 1749: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF ) ! 1750: return STX_SECTOR_FLAG_RNF; /* RNF in FDC's status register */ ! 1751: ! 1752: /* If CRC is set, return FDC_STR_BIT_RNF */ ! 1753: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_CRC ) ! 1754: return STX_SECTOR_FLAG_CRC; /* CRC in FDC's status register */ ! 1755: ! 1756: ! 1757: /* Check if this sector was already changed by a 'write sector' command */ ! 1758: /* If so, we use the same buffer. Else we alloc a new buffer for this sector */ ! 1759: if ( pStxSector->SaveSectorIndex < 0 ) ! 1760: { ! 1761: //fprintf ( stderr , "realloc\n" ); ! 1762: /* Increase save buffer by 1 */ ! 1763: pNewBuf = realloc ( STX_SaveStruct[ Drive ].pSaveSectorsStruct , ! 1764: ( STX_SaveStruct[ Drive ].SaveSectorsCount + 1 ) * sizeof ( STX_SAVE_SECTOR_STRUCT ) ); ! 1765: if ( pNewBuf == NULL ) ! 1766: { ! 1767: fprintf ( stderr , "FDC_WriteSector_STX drive=%d track=%d side=%d sector=%d realloc error !\n" , ! 1768: Drive , Track , Side , STX_State.NextSectorStruct_Nbr ); ! 1769: return STX_SECTOR_FLAG_RNF; ! 1770: } ! 1771: ! 1772: /* Save the new buffer values */ ! 1773: STX_SaveStruct[ Drive ].pSaveSectorsStruct = (STX_SAVE_SECTOR_STRUCT *) pNewBuf;; ! 1774: STX_SaveStruct[ Drive ].SaveSectorsCount++; ! 1775: ! 1776: /* Create the new entry in pSaveSectorsStruct */ ! 1777: pNewBuf = malloc ( SectorSize ); ! 1778: if ( pNewBuf == NULL ) ! 1779: { ! 1780: fprintf ( stderr , "FDC_WriteSector_STX drive=%d track=%d side=%d sector=%d malloc error !\n" , ! 1781: Drive , Track , Side , STX_State.NextSectorStruct_Nbr ); ! 1782: return STX_SECTOR_FLAG_RNF; ! 1783: } ! 1784: ! 1785: pStxSector->SaveSectorIndex = STX_SaveStruct[ Drive ].SaveSectorsCount - 1; ! 1786: ! 1787: /* Fill the new SaveSectorStruct. We copy some of the original sector's values */ ! 1788: /* in the saved sector */ ! 1789: pStxSaveSector = &STX_SaveStruct[ Drive ].pSaveSectorsStruct[ pStxSector->SaveSectorIndex ]; ! 1790: ! 1791: pStxSaveSector->Track = Track; ! 1792: pStxSaveSector->Side = Side; ! 1793: pStxSaveSector->BitPosition = pStxSector->BitPosition; ! 1794: pStxSaveSector->ID_Track = pStxSector->ID_Track; ! 1795: pStxSaveSector->ID_Head = pStxSector->ID_Head; ! 1796: pStxSaveSector->ID_Sector = pStxSector->ID_Sector; ! 1797: pStxSaveSector->ID_Size = pStxSector->ID_Size; ! 1798: pStxSaveSector->ID_CRC = pStxSector->ID_CRC; ! 1799: ! 1800: pStxSaveSector->SectorSize = SectorSize; ! 1801: pStxSaveSector->pData = (Uint8 *) pNewBuf; ! 1802: ! 1803: pStxSaveSector->StructIsUsed = 1; ! 1804: } ! 1805: ! 1806: pSector_WriteData = STX_SaveStruct[ Drive ].pSaveSectorsStruct[ pStxSector->SaveSectorIndex ].pData; ! 1807: ! 1808: /* Get the sector's data (ignore timings) */ ! 1809: for ( i=0 ; i<SectorSize ; i++ ) ! 1810: pSector_WriteData[ i ] = FDC_Buffer_Read_Byte_pos ( i ); ! 1811: ! 1812: //fprintf ( stderr , "write drive=%d track=%d side=%d sector=%d size=%d index=%d\n", Drive, Track, Side, Sector, SectorSize , pStxSector->SaveSectorIndex ); ! 1813: //Str_Dump_Hex_Ascii ( (char *) pSector_WriteData, SectorSize, 16, "" , stderr ); ! 1814: ! 1815: /* Warn that 'write sector' data will be lost or saved (if zipped or not) */ ! 1816: if ( STX_State.ImageBuffer[ Drive ]->WarnedWriteSector == false ) ! 1817: { ! 1818: if ( File_DoesFileExtensionMatch ( EmulationDrives[ Drive ].sFileName , ".zip" ) ) ! 1819: Log_AlertDlg ( LOG_INFO , "WARNING : can't save changes made with 'write sector' to an STX disk inside a zip file" ); ! 1820: else ! 1821: Log_AlertDlg ( LOG_INFO , "Changes made with 'write sector' to an STX disk will be saved into an additional .wd1772 file" ); ! 1822: STX_State.ImageBuffer[ Drive ]->WarnedWriteSector = true; ! 1823: } ! 1824: ! 1825: ! 1826: /* No error */ ! 1827: EmulationDrives[Drive].bContentsChanged = true; ! 1828: return 0; ! 1829: } ! 1830: ! 1831: ! 1832: /*-----------------------------------------------------------------------*/ ! 1833: /** ! 1834: * Read an address field from a floppy image in STX format (used in type III command) ! 1835: * We return the address field NextSectorStruct_Nbr, whose value was set ! 1836: * by the latest call to FDC_NextSectorID_FdcCycles_STX ! 1837: * Each byte of the ID field is added to the FDC buffer with a default timing ! 1838: * (32 microsec) ! 1839: * Return 0 if OK, or a CRC error ! 1840: */ ! 1841: extern Uint8 FDC_ReadAddress_STX ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side ) ! 1842: { ! 1843: STX_SECTOR_STRUCT *pStxSector; ! 1844: ! 1845: pStxSector = STX_FindSector ( Drive , Track , Side , STX_State.NextSectorStruct_Nbr ); ! 1846: if ( pStxSector == NULL ) ! 1847: { ! 1848: fprintf ( stderr , "FDC_ReadAddress_STX drive=%d track=%d side=%d sector=%d returns null !\n" , ! 1849: Drive , Track , Side , STX_State.NextSectorStruct_Nbr ); ! 1850: return STX_SECTOR_FLAG_RNF; /* Should not happen if FDC_NextSectorID_FdcCycles_STX succeeded before */ ! 1851: } ! 1852: ! 1853: FDC_Buffer_Add ( pStxSector->ID_Track ); ! 1854: FDC_Buffer_Add ( pStxSector->ID_Head ); ! 1855: FDC_Buffer_Add ( pStxSector->ID_Sector ); ! 1856: FDC_Buffer_Add ( pStxSector->ID_Size ); ! 1857: FDC_Buffer_Add ( pStxSector->ID_CRC >> 8 ); ! 1858: FDC_Buffer_Add ( pStxSector->ID_CRC & 0xff ); ! 1859: ! 1860: /* If RNF is set and CRC error is set, then this ID field has a CRC error */ ! 1861: if ( ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF ) && ( pStxSector->FDC_Status & STX_SECTOR_FLAG_CRC ) ) ! 1862: return STX_SECTOR_FLAG_CRC; ! 1863: ! 1864: return 0; /* No error */ ! 1865: } ! 1866: ! 1867: ! 1868: /*-----------------------------------------------------------------------*/ ! 1869: /** ! 1870: * Read a track from a floppy image in STX format (used in type III command) ! 1871: * This function is called after an index pulse was encountered, and it will ! 1872: * always succeeds and fill the track buffer. ! 1873: * If the Track/Side infos exist in the STX image, then the corresponding ! 1874: * bytes from the track's image are returned. ! 1875: * If these Track/Side infos don't exist, we return some random bytes ! 1876: * (empty / not formatted track). ! 1877: * If the Track/Side infos exist but there's no track's image, then we build ! 1878: * a standard track by using the available sectors and standard GAP values. ! 1879: * Return 0 if OK ! 1880: */ ! 1881: extern Uint8 FDC_ReadTrack_STX ( Uint8 Drive , Uint8 Track , Uint8 Side ) ! 1882: { ! 1883: STX_TRACK_STRUCT *pStxTrack; ! 1884: STX_SECTOR_STRUCT *pStxSector; ! 1885: int i; ! 1886: Uint16 Timing; ! 1887: Uint32 Track_ReadTime; ! 1888: double Total_cur; /* To compute closest integer timings for each byte */ ! 1889: double Total_prev; ! 1890: int TrackSize; ! 1891: int Sector; ! 1892: int SectorSize; ! 1893: Uint16 CRC; ! 1894: Uint8 *pData; ! 1895: Uint8 Byte; ! 1896: ! 1897: if ( STX_State.ImageBuffer[ Drive ] == NULL ) ! 1898: { ! 1899: fprintf ( stderr , "FDC_ReadTrack_STX drive=%d track=%d side=%d, no image buffer !\n" , Drive , Track , Side ); ! 1900: return STX_SECTOR_FLAG_RNF; /* Should not happen, just in case of a bug */ ! 1901: } ! 1902: ! 1903: pStxTrack = STX_FindTrack ( Drive , Track , Side ); ! 1904: if ( pStxTrack == NULL ) /* Track/Side don't exist in this STX image */ ! 1905: { ! 1906: fprintf ( stderr , "fdc stx : track info not found for read track drive=%d track=%d side=%d, returning random bytes\n" , Drive , Track , Side ); ! 1907: for ( i=0 ; i<FDC_GetBytesPerTrack ( Drive ) ; i++ ) ! 1908: FDC_Buffer_Add ( rand() & 0xff ); /* Fill the track buffer with random bytes */ ! 1909: return 0; ! 1910: } ! 1911: ! 1912: /* If the Track block contains a complete dump of the track image, use it directly */ ! 1913: /* The timing for each byte is the average timing based on TrackImageSize */ ! 1914: if ( pStxTrack->pTrackImageData ) ! 1915: { ! 1916: Track_ReadTime = 8000000 / 5; /* 300 RPM, gives 5 RPS and 1600000 cycles per revolution at 8 MHz */ ! 1917: Total_prev = 0; ! 1918: for ( i=0 ; i<pStxTrack->TrackImageSize ; i++ ) ! 1919: { ! 1920: Total_cur = ( (double)Track_ReadTime * ( i+1 ) ) / pStxTrack->TrackImageSize; ! 1921: Timing = rint ( Total_cur - Total_prev ); ! 1922: Total_prev += Timing; ! 1923: /* Add each byte to the buffer, Timing should be a number of FDC cycles at 8 MHz */ ! 1924: FDC_Buffer_Add_Timing ( pStxTrack->pTrackImageData[ i ] , Timing ); ! 1925: } ! 1926: } ! 1927: ! 1928: /* If the track block doesn't contain a dump of the track image, we must build a track */ ! 1929: /* using the sector blocks and some standard GAP values */ ! 1930: /* [NP] NOTE : we build a track of pStxTrack->MFMSize bytes, as this seems to always be != 0 */ ! 1931: /* even for empty / not formatted track */ ! 1932: /* [NP] NOTE : instead of using standard GAP values, we could compute GAP based on pStxSector->BitPosition */ ! 1933: /* but this seems unnecessary, as a track image would certainly be present if precise GAP values */ ! 1934: /* were required */ ! 1935: else ! 1936: { ! 1937: TrackSize = pStxTrack->MFMSize; ! 1938: if ( ( pStxTrack->Flags & STX_TRACK_FLAG_SECTOR_BLOCK ) == 0 ) ! 1939: TrackSize /= 8; /* When the track contains only sector data, MFMSize is in bits */ ! 1940: ! 1941: /* If there's no image for this track, and no sector as well, then track is empty / not formatted */ ! 1942: if ( pStxTrack->SectorsCount == 0 ) ! 1943: { ! 1944: fprintf ( stderr , "fdc stx : no track image and no sector for read track drive=%d track=%d side=%d, building an unformatted track\n" , Drive , Track , Side ); ! 1945: for ( i=0 ; i<TrackSize ; i++ ) ! 1946: FDC_Buffer_Add ( rand() & 0xff ); /* Fill the track buffer with random bytes */ ! 1947: return 0; ! 1948: } ! 1949: ! 1950: /* Use the available sectors and add some default GAPs to build the track */ ! 1951: fprintf ( stderr , "fdc stx : no track image for read track drive=%d track=%d side=%d, building a standard track\n" , Drive , Track , Side ); ! 1952: ! 1953: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP1 ; i++ ) /* GAP1 */ ! 1954: FDC_Buffer_Add ( 0x4e ); ! 1955: ! 1956: for ( Sector=0 ; Sector < pStxTrack->SectorsCount ; Sector++ ) ! 1957: { ! 1958: pStxSector = &(pStxTrack->pSectorsStruct[ Sector ]); ! 1959: SectorSize = pStxSector->SectorSize; ! 1960: ! 1961: /* Check that the data+GAPs for this sector will not be above track's length */ ! 1962: /* (in case we build a track with a high / non standard number of sectors) */ ! 1963: if ( FDC_Buffer_Get_Size () + SectorSize + FDC_TRACK_LAYOUT_STANDARD_GAP2 + 10 + FDC_TRACK_LAYOUT_STANDARD_GAP3a ! 1964: + FDC_TRACK_LAYOUT_STANDARD_GAP3b + 4 + 2 + FDC_TRACK_LAYOUT_STANDARD_GAP4 >= TrackSize ) ! 1965: { ! 1966: fprintf ( stderr , "fdc stx : no track image for read track drive=%d track=%d side=%d, too many data sector=%d\n" , Drive , Track , Side , Sector ); ! 1967: break; /* Exit the loop and fill the rest of the track */ ! 1968: } ! 1969: ! 1970: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP2 ; i++ ) /* GAP2 */ ! 1971: FDC_Buffer_Add ( 0x00 ); ! 1972: ! 1973: /* Add the ID field for the sector */ ! 1974: for ( i=0 ; i<3 ; i++ ) ! 1975: FDC_Buffer_Add ( 0xa1 ); /* SYNC (write $F5) */ ! 1976: FDC_Buffer_Add ( 0xfe ); /* Index Address Mark */ ! 1977: FDC_Buffer_Add ( pStxSector->ID_Track ); ! 1978: FDC_Buffer_Add ( pStxSector->ID_Head ); ! 1979: FDC_Buffer_Add ( pStxSector->ID_Sector ); ! 1980: FDC_Buffer_Add ( pStxSector->ID_Size ); ! 1981: FDC_Buffer_Add ( pStxSector->ID_CRC >> 8 ); ! 1982: FDC_Buffer_Add ( pStxSector->ID_CRC & 0xff ); ! 1983: ! 1984: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP3a ; i++ ) /* GAP3a */ ! 1985: FDC_Buffer_Add ( 0x4e ); ! 1986: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP3b ; i++ ) /* GAP3b */ ! 1987: FDC_Buffer_Add ( 0x00 ); ! 1988: ! 1989: /* Add the data for the sector + build the CRC */ ! 1990: crc16_reset ( &CRC ); ! 1991: for ( i=0 ; i<3 ; i++ ) ! 1992: { ! 1993: FDC_Buffer_Add ( 0xa1 ); /* SYNC (write $F5) */ ! 1994: crc16_add_byte ( &CRC , 0xa1 ); ! 1995: } ! 1996: ! 1997: FDC_Buffer_Add ( 0xfb ); /* Data Address Mark */ ! 1998: crc16_add_byte ( &CRC , 0xfb ); ! 1999: ! 2000: /* [NP] NOTE : when building the sector, we assume there's no specific timing or fuzzy bytes */ ! 2001: /* If it was not the case, there would certainly be a real track image (and STX format doesn't */ ! 2002: /* support fuzzy bytes or specific timing for a track image anyway) */ ! 2003: /* If the sector was changed by a 'write sector' command, we use the data from pSaveSectorsStruct */ ! 2004: if ( pStxSector->SaveSectorIndex < 0 ) /* Use original data from the STX */ ! 2005: pData = pStxSector->pData; ! 2006: else /* Use data from the 'write sector' */ ! 2007: pData = STX_SaveStruct[ Drive ].pSaveSectorsStruct[ pStxSector->SaveSectorIndex ].pData; ! 2008: ! 2009: for ( i=0 ; i<SectorSize ; i++ ) ! 2010: { ! 2011: Byte = pData[ i ]; ! 2012: FDC_Buffer_Add ( Byte ); ! 2013: crc16_add_byte ( &CRC , Byte ); ! 2014: } ! 2015: ! 2016: FDC_Buffer_Add ( CRC >> 8 ); /* CRC1 (write $F7) */ ! 2017: FDC_Buffer_Add ( CRC & 0xff ); /* CRC2 */ ! 2018: ! 2019: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP4 ; i++ ) /* GAP4 */ ! 2020: FDC_Buffer_Add ( 0x4e ); ! 2021: } ! 2022: ! 2023: while ( FDC_Buffer_Get_Size () < TrackSize ) /* Complete the track buffer */ ! 2024: FDC_Buffer_Add ( 0x4e ); /* GAP5 */ ! 2025: } ! 2026: ! 2027: return 0; /* No error */ ! 2028: } ! 2029: ! 2030: ! 2031: /*-----------------------------------------------------------------------*/ ! 2032: /** ! 2033: * Write a track to a floppy image in STX format (used in type III command) ! 2034: * ! 2035: * STX format doesn't support write command. For each 'write track' we ! 2036: * store the track data in a dedicated buffer STX_SaveStruct[].pSaveTracksStruct. ! 2037: * When the track is read later, we return the data from STX_SaveStruct[].pSaveTracksStruct ! 2038: * instead of returning the data from the original STX file. ! 2039: * ! 2040: * NOTE : data will saved in memory snapshot, as well as in an additional ! 2041: * file with the extension .wd1772. ! 2042: * ! 2043: * Return 0 if track was written without error, or LOST_DATA if an error occurred ! 2044: */ ! 2045: extern Uint8 FDC_WriteTrack_STX ( Uint8 Drive , Uint8 Track , Uint8 Side , int TrackSize ) ! 2046: { ! 2047: STX_TRACK_STRUCT *pStxTrack; ! 2048: int i; ! 2049: Uint8 *pTrack_DataWrite; ! 2050: void *pNewBuf; ! 2051: STX_SAVE_TRACK_STRUCT *pStxSaveTrack; ! 2052: int Sector; ! 2053: ! 2054: pStxTrack = STX_FindTrack ( Drive , Track , Side ); ! 2055: if ( pStxTrack == NULL ) ! 2056: { ! 2057: fprintf ( stderr , "FDC_WriteTrack_STX drive=%d track=%d side=%d returns null !\n" , ! 2058: Drive , Track , Side ); ! 2059: return STX_SECTOR_FLAG_LOST_DATA; ! 2060: } ! 2061: ! 2062: /* Check if this track was already changed by a 'write track' command */ ! 2063: /* If so, we use the same structure. Else we alloc a new structure for this track */ ! 2064: if ( pStxTrack->SaveTrackIndex < 0 ) ! 2065: { ! 2066: //fprintf ( stderr , "realloc\n" ); ! 2067: /* Increase save buffer by 1 */ ! 2068: pNewBuf = realloc ( STX_SaveStruct[ Drive ].pSaveTracksStruct , ! 2069: ( STX_SaveStruct[ Drive ].SaveTracksCount + 1 ) * sizeof ( STX_SAVE_TRACK_STRUCT ) ); ! 2070: if ( pNewBuf == NULL ) ! 2071: { ! 2072: fprintf ( stderr , "FDC_WriteTrack_STX drive=%d track=%d side=%d realloc error !\n" , ! 2073: Drive , Track , Side ); ! 2074: return STX_SECTOR_FLAG_LOST_DATA; ! 2075: } ! 2076: ! 2077: /* Save the new buffer values */ ! 2078: STX_SaveStruct[ Drive ].pSaveTracksStruct = (STX_SAVE_TRACK_STRUCT *) pNewBuf;; ! 2079: STX_SaveStruct[ Drive ].SaveTracksCount++; ! 2080: ! 2081: pStxTrack->SaveTrackIndex = STX_SaveStruct[ Drive ].SaveTracksCount - 1; ! 2082: } ! 2083: ! 2084: /* Use the same structure : free previous DataWrite buffer */ ! 2085: else ! 2086: { ! 2087: free ( STX_SaveStruct[ Drive ].pSaveTracksStruct[ pStxTrack->SaveTrackIndex ].pDataWrite ); ! 2088: STX_SaveStruct[ Drive ].pSaveTracksStruct[ pStxTrack->SaveTrackIndex ].pDataWrite = NULL; ! 2089: /* TODO : also free pDataRead */ ! 2090: } ! 2091: ! 2092: /* Create the new DataWrite buffer in pSaveTracksStruct */ ! 2093: pNewBuf = malloc ( TrackSize ); ! 2094: if ( pNewBuf == NULL ) ! 2095: { ! 2096: fprintf ( stderr , "FDC_WriteTrack_STX drive=%d track=%d side=%d malloc error !\n" , ! 2097: Drive , Track , Side ); ! 2098: return STX_SECTOR_FLAG_LOST_DATA; ! 2099: } ! 2100: ! 2101: /* Fill the new SaveTrackStruct */ ! 2102: pStxSaveTrack = &STX_SaveStruct[ Drive ].pSaveTracksStruct[ pStxTrack->SaveTrackIndex ]; ! 2103: ! 2104: pStxSaveTrack->Track = Track; ! 2105: pStxSaveTrack->Side = Side; ! 2106: ! 2107: pStxSaveTrack->TrackSizeWrite = TrackSize; ! 2108: pStxSaveTrack->pDataWrite = (Uint8 *) pNewBuf; ! 2109: ! 2110: ! 2111: /* Get the track's data (ignore timings) */ ! 2112: pTrack_DataWrite = STX_SaveStruct[ Drive ].pSaveTracksStruct[ pStxTrack->SaveTrackIndex ].pDataWrite; ! 2113: ! 2114: for ( i=0 ; i<pStxSaveTrack->TrackSizeWrite ; i++ ) ! 2115: pTrack_DataWrite[ i ] = FDC_Buffer_Read_Byte_pos ( i ); ! 2116: ! 2117: //fprintf ( stderr , "write drive=%d track=%d side=%d size=%d index=%d\n", Drive, Track, Side, pStxSaveTrack->TrackSizeWrite , pStxTrack->SaveTrackIndex ); ! 2118: //Str_Dump_Hex_Ascii ( (char *) pTrack_DataWrite, pStxSaveTrack->TrackSizeWrite, 16, "" , stderr ); ! 2119: ! 2120: // TODO : convert pDataWrite into pDataRead ! 2121: pStxSaveTrack->TrackSizeRead = 0; /* TODO : compute interpreted track */ ! 2122: pStxSaveTrack->pDataRead = NULL; /* TODO : compute interpreted track */ ! 2123: ! 2124: ! 2125: /* If some sectors were already saved for that track, we must remove them */ ! 2126: /* as the 'write track' takes precedence over the previous 'write sector' */ ! 2127: for ( Sector=0 ; Sector < pStxTrack->SectorsCount ; Sector++ ) ! 2128: { ! 2129: if ( pStxTrack->pSectorsStruct[ Sector ].SaveSectorIndex >= 0 ) ! 2130: { ! 2131: STX_FreeSaveSectorsStruct ( STX_SaveStruct[ Drive ].pSaveSectorsStruct , ! 2132: pStxTrack->pSectorsStruct[ Sector ].SaveSectorIndex ); ! 2133: pStxTrack->pSectorsStruct[ Sector ].SaveSectorIndex = -1; ! 2134: } ! 2135: } ! 2136: ! 2137: ! 2138: /* Warn that 'write track' data will be lost or saved (if zipped or not) */ ! 2139: if ( STX_State.ImageBuffer[ Drive ]->WarnedWriteTrack == false ) ! 2140: { ! 2141: if ( File_DoesFileExtensionMatch ( EmulationDrives[ Drive ].sFileName , ".zip" ) ) ! 2142: Log_AlertDlg ( LOG_INFO , "WARNING : can't save changes made with 'write track' to an STX disk inside a zip file" ); ! 2143: else ! 2144: Log_AlertDlg ( LOG_INFO , "Changes made with 'write track' to an STX disk will be saved into an additional .wd1772 file" ); ! 2145: STX_State.ImageBuffer[ Drive ]->WarnedWriteTrack = true; ! 2146: } ! 2147: ! 2148: ! 2149: /* No error */ ! 2150: EmulationDrives[Drive].bContentsChanged = true; ! 2151: return 0; ! 2152: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.