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