|
|
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:
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: }
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: {
351: fprintf ( stderr , "Error : %s is not a valid STX image\n" , pszFileName );
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:
385: fprintf ( stderr , "stx write <%s>\n" , pszFileName );
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: {
410: fprintf ( stderr , "STX_WriteDisk drive=%d file=%s, error STX_FileNameToSave\n" , Drive , pszFileName );
411: return false;
412: }
413: fprintf ( stderr , "stx write <%s>\n" , FilenameSave );
414:
415:
416: FileOut = fopen ( FilenameSave , "wb+" );
417: if ( !FileOut )
418: {
419: fprintf ( stderr , "STX_WriteDisk drive=%d file=%s, error fopen\n" , Drive , pszFileName );
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: {
438: fprintf ( stderr , "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: {
483: fprintf ( stderr , "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: {
492: fprintf ( stderr , "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: {
526: fprintf ( stderr , "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: {
535: fprintf ( stderr , "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: {
571: fprintf ( stderr , "STX_LoadSaveFile drive=%d file=%s error\n" , Drive , FilenameSave );
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: {
579: fprintf ( stderr , "STX_LoadSaveFile drive=%d file=%s bad header\n" , Drive , FilenameSave );
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: {
589: fprintf ( stderr , "STX_LoadSaveFile drive=%d file=%s bad version 0x%x revision 0x%x\n" , Drive , FilenameSave , version , revision );
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: {
701: fprintf ( stderr , "STX_LoadSaveFile drive=%d file=%s, unknown block %4.4s, skipping\n" , Drive , FilenameSave , p );
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: {
826: fprintf ( stderr , "STX : STX_Insert drive=%d file=%s buf=%p size=%ld load wd1172 %s\n" , Drive , FilenameSTX , pImageBuffer , ImageSize , FilenameSave );
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: {
846: fprintf ( stderr , "STX : STX_Insert_internal drive=%d file=%s buf=%p size=%ld\n" , Drive , FilenameSTX , pImageBuffer , ImageSize );
847:
848: STX_State.ImageBuffer[ Drive ] = STX_BuildStruct ( pImageBuffer , STX_DEBUG_FLAG );
849: if ( STX_State.ImageBuffer[ Drive ] == NULL )
850: {
851: fprintf ( stderr , "STX : STX_Insert_internal drive=%d file=%s buf=%p size=%ld, error in STX_BuildStruct\n" , Drive , FilenameSTX , pImageBuffer , ImageSize );
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: {
865: fprintf ( stderr , "STX : STX_Eject drive=%d\n" , Drive );
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 */
1525: for ( i=0 ; i<pStxTrack->SectorsCount ; i++ )
1526: {
1527: if ( CurrentPos_FdcCycles < (int)pStxTrack->pSectorsStruct[ i ].BitPosition*FDC_DELAY_CYCLE_MFM_BIT ) /* 1 bit = 32 cycles at 8 MHz */
1528: break; /* We found the next sector */
1529: }
1530:
1531: if ( i == pStxTrack->SectorsCount ) /* CurrentPos_FdcCycles is after the last ID Field of this track */
1532: {
1533: /* Reach end of track (new index pulse), then go to 1st sector from current position */
1534: if ( pStxTrack->pTrackImageData )
1535: TrackSize = pStxTrack->TrackImageSize;
1536: else if ( ( pStxTrack->Flags & STX_TRACK_FLAG_SECTOR_BLOCK ) == 0 )
1537: TrackSize = pStxTrack->MFMSize / 8; /* When the track contains only sector data, MFMSize is in bits */
1538: else
1539: TrackSize = pStxTrack->MFMSize;
1540:
1541: Delay_FdcCycles = TrackSize * FDC_DELAY_CYCLE_MFM_BYTE - CurrentPos_FdcCycles
1542: + pStxTrack->pSectorsStruct[ 0 ].BitPosition*FDC_DELAY_CYCLE_MFM_BIT;
1543: STX_State.NextSectorStruct_Nbr = 0;
1544: //fprintf ( stderr , "size=%d pos=%d pos0=%d delay=%d\n" , TrackSize, CurrentPos_FdcCycles, pStxTrack->pSectorsStruct[ 0 ].BitPosition , Delay_FdcCycles );
1545: }
1546: else /* There's an ID Field before end of track */
1547: {
1548: Delay_FdcCycles = (int)pStxTrack->pSectorsStruct[ i ].BitPosition*FDC_DELAY_CYCLE_MFM_BIT - CurrentPos_FdcCycles;
1549: STX_State.NextSectorStruct_Nbr = i;
1550: //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 );
1551: }
1552:
1553: /* Store the value of the track/sector numbers in the next ID field */
1554: STX_State.NextSector_ID_Field_TR = pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].ID_Track;
1555: STX_State.NextSector_ID_Field_SR = pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].ID_Sector;
1556: STX_State.NextSector_ID_Field_LEN = pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].ID_Size;
1557:
1558: /* If RNF is set and CRC error is set, then this ID field has a CRC error */
1559: if ( ( pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].FDC_Status & STX_SECTOR_FLAG_RNF )
1560: && ( pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].FDC_Status & STX_SECTOR_FLAG_CRC ) )
1561: STX_State.NextSector_ID_Field_CRC_OK = 0; /* CRC bad */
1562: else
1563: STX_State.NextSector_ID_Field_CRC_OK = 1; /* CRC correct */
1564:
1565: /* BitPosition in STX seems to point just after the IDAM $FE ; we need to point 4 bytes earlier at the 1st $A1 */
1566: Delay_FdcCycles -= 4 * FDC_DELAY_CYCLE_MFM_BYTE; /* Correct delay to point to $A1 $A1 $A1 $FE */
1567:
1568: //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 );
1569: return Delay_FdcCycles;
1570: }
1571:
1572:
1573:
1574: /*-----------------------------------------------------------------------*/
1575: /**
1576: * Return the value of the track number in the next ID field set by
1577: * FDC_NextSectorID_FdcCycles_STX.
1578: */
1.1.1.2 root 1579: Uint8 FDC_NextSectorID_TR_STX ( void )
1.1 root 1580: {
1581: return STX_State.NextSector_ID_Field_TR;
1582: }
1583:
1584:
1585: /*-----------------------------------------------------------------------*/
1586: /**
1587: * Return the value of the sector number in the next ID field set by
1588: * FDC_NextSectorID_FdcCycles_STX.
1589: */
1.1.1.2 root 1590: Uint8 FDC_NextSectorID_SR_STX ( void )
1.1 root 1591: {
1592: return STX_State.NextSector_ID_Field_SR;
1593: }
1594:
1595:
1596: /*-----------------------------------------------------------------------*/
1597: /**
1598: * Return the value of the sector's length in the next ID field set by
1599: * FDC_NextSectorID_FdcCycles_STX.
1600: */
1.1.1.2 root 1601: Uint8 FDC_NextSectorID_LEN_STX ( void )
1.1 root 1602: {
1603: return STX_State.NextSector_ID_Field_LEN;
1604: }
1605:
1606:
1607: /*-----------------------------------------------------------------------*/
1608: /**
1609: * Return the status of the CRC in the next ID field set by
1610: * FDC_NextSectorID_FdcCycles_STX.
1611: * If '0', CRC is bad, else CRC is OK
1612: */
1.1.1.2 root 1613: Uint8 FDC_NextSectorID_CRC_OK_STX ( void )
1.1 root 1614: {
1615: return STX_State.NextSector_ID_Field_CRC_OK;
1616: }
1617:
1618:
1619: /*-----------------------------------------------------------------------*/
1620: /**
1621: * Read a sector from a floppy image in STX format (used in type II command)
1622: * We return the sector NextSectorStruct_Nbr, whose value was set
1623: * by the latest call to FDC_NextSectorID_FdcCycles_STX
1624: * Each byte of the sector is added to the FDC buffer with a default timing
1625: * (32 microsec) or a variable timing, depending on the sector's flags.
1626: * Some sectors can also contains "fuzzy" bits.
1627: * Special care must be taken to compute the timing of each byte, which can
1628: * be a decimal value and must be rounded to the best possible integer.
1629: *
1630: * If the sector's data were changed by a 'write sector' command, then we assume
1631: * a sector with no fuzzy byte and standard timings.
1632: *
1633: * Return RNF if sector was not found, else return CRC and RECORD_TYPE values
1634: * for the status register.
1635: */
1.1.1.2 root 1636: Uint8 FDC_ReadSector_STX ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side , int *pSectorSize )
1.1 root 1637: {
1638: STX_SECTOR_STRUCT *pStxSector;
1639: int i;
1640: Uint8 Byte;
1641: Uint16 Timing;
1642: Uint32 Sector_ReadTime;
1643: double Total_cur; /* To compute closest integer timings for each byte */
1644: double Total_prev;
1645: Uint8 *pSector_WriteData;
1646:
1647: pStxSector = STX_FindSector ( Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1648: if ( pStxSector == NULL )
1649: {
1650: fprintf ( stderr , "FDC_ReadSector_STX drive=%d track=%d side=%d sector=%d returns null !\n" ,
1651: Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1652: return STX_SECTOR_FLAG_RNF; /* Should not happen if FDC_NextSectorID_FdcCycles_STX succeeded before */
1653: }
1654:
1655: /* If RNF is set, return FDC_STR_BIT_RNF */
1656: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF )
1657: return STX_SECTOR_FLAG_RNF; /* RNF in FDC's status register */
1658:
1659: *pSectorSize = pStxSector->SectorSize;
1660: Sector_ReadTime = pStxSector->ReadTime;
1661:
1662: /* Check if this sector was changed by a 'write sector' command */
1663: /* If so, we use this recent buffer instead of the original STX content */
1664: if (STX_SaveStruct[Drive].SaveSectorsCount > 0 && pStxSector->SaveSectorIndex >= 0)
1665: {
1666: pSector_WriteData = STX_SaveStruct[ Drive ].pSaveSectorsStruct[ pStxSector->SaveSectorIndex ].pData;
1667: Sector_ReadTime = 0; /* Standard timings */
1668:
1669: LOG_TRACE(TRACE_FDC, "fdc stx read sector drive=%d track=%d sect=%d side=%d using saved sector=%d\n" ,
1670: Drive, Track, Sector, Side , pStxSector->SaveSectorIndex );
1671: }
1672: else
1673: pSector_WriteData = NULL;
1674:
1675: if ( Sector_ReadTime == 0 ) /* Sector has a standard delay (32 us per byte) */
1676: Sector_ReadTime = 32 * pStxSector->SectorSize; /* Use the real standard value instead of 0 */
1677: Sector_ReadTime *= 8; /* Convert delay in us to a number of FDC cycles at 8 MHz */
1678:
1679: Total_prev = 0;
1680: for ( i=0 ; i<pStxSector->SectorSize ; i++ )
1681: {
1682: /* Get the value of each byte, with possible fuzzy bits */
1683: if ( pSector_WriteData == NULL ) /* Use original STX content */
1684: {
1685: Byte = pStxSector->pData[ i ];
1686: if ( pStxSector->pFuzzyData )
1687: Byte = ( Byte & pStxSector->pFuzzyData[ i ] ) | ( rand() & ~pStxSector->pFuzzyData[ i ] );
1688: }
1689:
1690: else /* Use data from 'write sector' */
1691: Byte = pSector_WriteData[ i ];
1692:
1693: /* Compute the timing in FDC cycles to transfer this byte */
1694: if ( ( pStxSector->pTimingData ) /* Specific timing for each block of 16 bytes */
1695: && ( pSector_WriteData == NULL ) )
1696: {
1697: Timing = ( pStxSector->pTimingData[ ( i>>4 ) * 2 ] << 8 )
1698: + pStxSector->pTimingData[ ( i>>4 ) * 2 + 1 ]; /* Get big endian timing for this block of 16 bytes */
1699:
1700: /* [NP] Formula to convert timing data comes from Pasti.prg 0.4b : */
1701: /* 1 unit of timing = 32 FDC cycles at 8 MHz + 28 cycles to complete each block of 16 bytes */
1702: Timing = Timing * 32 + 28;
1703:
1704: if ( i % 16 == 0 ) Total_prev = 0; /* New block of 16 bytes */
1705: Total_cur = ( (double)Timing * ( ( i % 16 ) + 1 ) ) / 16;
1706: Timing = rint ( Total_cur - Total_prev );
1707: Total_prev += Timing;
1708: }
1709: else /* Specific timing in us for the whole sector */
1710: {
1711: Total_cur = ( (double)Sector_ReadTime * ( i+1 ) ) / pStxSector->SectorSize;
1712: Timing = rint ( Total_cur - Total_prev );
1713: Total_prev += Timing;
1714: }
1715:
1716: /* Add the Byte to the buffer, Timing should be a number of FDC cycles at 8 MHz */
1717: FDC_Buffer_Add_Timing ( Byte , Timing );
1718: }
1719:
1720: /* Return only bits 3 and 5 of the FDC_Status */
1721: return pStxSector->FDC_Status & ( STX_SECTOR_FLAG_CRC | STX_SECTOR_FLAG_RECORD_TYPE );
1722: }
1723:
1724:
1725: /*-----------------------------------------------------------------------*/
1726: /**
1727: * Write a sector to a floppy image in STX format (used in type II command)
1728: *
1729: * STX format doesn't support write command. For each 'write sector' we
1730: * store the sector data in a dedicated buffer STX_SaveStruct[].pSaveSectorsStruct.
1731: * When the sector is read later, we return the data from STX_SaveStruct[].pSaveSectorsStruct
1732: * instead of returning the data from the original STX file.
1733: *
1734: * We only allow writing for sectors whose ID field has a correct CRC and
1735: * where RNF is not set.
1736: * Any valid size can be written : 128, 256, 512 or 1024 bytes
1737: *
1738: * NOTE : data will saved in memory snapshot, as well as in an additional
1739: * file with the extension .wd1772.
1740: *
1741: * Return RNF if sector was not found or CRC if ID field has a CRC error.
1742: * Return 0 if OK.
1743: */
1.1.1.2 root 1744: Uint8 FDC_WriteSector_STX ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side , int SectorSize )
1.1 root 1745: {
1746: STX_SECTOR_STRUCT *pStxSector;
1747: int i;
1748: Uint8 *pSector_WriteData;
1749: void *pNewBuf;
1750: STX_SAVE_SECTOR_STRUCT *pStxSaveSector;
1751:
1752: pStxSector = STX_FindSector ( Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1753: if ( pStxSector == NULL )
1754: {
1755: fprintf ( stderr , "FDC_WriteSector_STX drive=%d track=%d side=%d sector=%d returns null !\n" ,
1756: Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1757: return STX_SECTOR_FLAG_RNF; /* Should not happen if FDC_NextSectorID_FdcCycles_STX succeeded before */
1758: }
1759:
1760: /* If RNF is set, return FDC_STR_BIT_RNF */
1761: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF )
1762: return STX_SECTOR_FLAG_RNF; /* RNF in FDC's status register */
1763:
1764: /* If CRC is set, return FDC_STR_BIT_RNF */
1765: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_CRC )
1766: return STX_SECTOR_FLAG_CRC; /* CRC in FDC's status register */
1767:
1768:
1769: /* Check if this sector was already changed by a 'write sector' command */
1770: /* If so, we use the same buffer. Else we alloc a new buffer for this sector */
1771: if ( pStxSector->SaveSectorIndex < 0 )
1772: {
1773: //fprintf ( stderr , "realloc\n" );
1774: /* Increase save buffer by 1 */
1775: pNewBuf = realloc ( STX_SaveStruct[ Drive ].pSaveSectorsStruct ,
1776: ( STX_SaveStruct[ Drive ].SaveSectorsCount + 1 ) * sizeof ( STX_SAVE_SECTOR_STRUCT ) );
1777: if ( pNewBuf == NULL )
1778: {
1779: fprintf ( stderr , "FDC_WriteSector_STX drive=%d track=%d side=%d sector=%d realloc error !\n" ,
1780: Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1781: return STX_SECTOR_FLAG_RNF;
1782: }
1783:
1784: /* Save the new buffer values */
1785: STX_SaveStruct[ Drive ].pSaveSectorsStruct = (STX_SAVE_SECTOR_STRUCT *) pNewBuf;;
1786: STX_SaveStruct[ Drive ].SaveSectorsCount++;
1787:
1788: /* Create the new entry in pSaveSectorsStruct */
1789: pNewBuf = malloc ( SectorSize );
1790: if ( pNewBuf == NULL )
1791: {
1792: fprintf ( stderr , "FDC_WriteSector_STX drive=%d track=%d side=%d sector=%d malloc error !\n" ,
1793: Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1794: return STX_SECTOR_FLAG_RNF;
1795: }
1796:
1797: pStxSector->SaveSectorIndex = STX_SaveStruct[ Drive ].SaveSectorsCount - 1;
1798:
1799: /* Fill the new SaveSectorStruct. We copy some of the original sector's values */
1800: /* in the saved sector */
1801: pStxSaveSector = &STX_SaveStruct[ Drive ].pSaveSectorsStruct[ pStxSector->SaveSectorIndex ];
1802:
1803: pStxSaveSector->Track = Track;
1804: pStxSaveSector->Side = Side;
1805: pStxSaveSector->BitPosition = pStxSector->BitPosition;
1806: pStxSaveSector->ID_Track = pStxSector->ID_Track;
1807: pStxSaveSector->ID_Head = pStxSector->ID_Head;
1808: pStxSaveSector->ID_Sector = pStxSector->ID_Sector;
1809: pStxSaveSector->ID_Size = pStxSector->ID_Size;
1810: pStxSaveSector->ID_CRC = pStxSector->ID_CRC;
1811:
1812: pStxSaveSector->SectorSize = SectorSize;
1813: pStxSaveSector->pData = (Uint8 *) pNewBuf;
1814:
1815: pStxSaveSector->StructIsUsed = 1;
1816: }
1817:
1818: pSector_WriteData = STX_SaveStruct[ Drive ].pSaveSectorsStruct[ pStxSector->SaveSectorIndex ].pData;
1819:
1820: /* Get the sector's data (ignore timings) */
1821: for ( i=0 ; i<SectorSize ; i++ )
1822: pSector_WriteData[ i ] = FDC_Buffer_Read_Byte_pos ( i );
1823:
1824: //fprintf ( stderr , "write drive=%d track=%d side=%d sector=%d size=%d index=%d\n", Drive, Track, Side, Sector, SectorSize , pStxSector->SaveSectorIndex );
1825: //Str_Dump_Hex_Ascii ( (char *) pSector_WriteData, SectorSize, 16, "" , stderr );
1826:
1827: /* Warn that 'write sector' data will be lost or saved (if zipped or not) */
1828: if ( STX_State.ImageBuffer[ Drive ]->WarnedWriteSector == false )
1829: {
1830: if ( File_DoesFileExtensionMatch ( EmulationDrives[ Drive ].sFileName , ".zip" ) )
1831: Log_AlertDlg ( LOG_INFO , "WARNING : can't save changes made with 'write sector' to an STX disk inside a zip file" );
1832: else
1833: Log_AlertDlg ( LOG_INFO , "Changes made with 'write sector' to an STX disk will be saved into an additional .wd1772 file" );
1834: STX_State.ImageBuffer[ Drive ]->WarnedWriteSector = true;
1835: }
1836:
1837:
1838: /* No error */
1839: EmulationDrives[Drive].bContentsChanged = true;
1840: return 0;
1841: }
1842:
1843:
1844: /*-----------------------------------------------------------------------*/
1845: /**
1846: * Read an address field from a floppy image in STX format (used in type III command)
1847: * We return the address field NextSectorStruct_Nbr, whose value was set
1848: * by the latest call to FDC_NextSectorID_FdcCycles_STX
1849: * Each byte of the ID field is added to the FDC buffer with a default timing
1850: * (32 microsec)
1851: * Return 0 if OK, or a CRC error
1852: */
1.1.1.2 root 1853: Uint8 FDC_ReadAddress_STX ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side )
1.1 root 1854: {
1855: STX_SECTOR_STRUCT *pStxSector;
1856:
1857: pStxSector = STX_FindSector ( Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1858: if ( pStxSector == NULL )
1859: {
1860: fprintf ( stderr , "FDC_ReadAddress_STX drive=%d track=%d side=%d sector=%d returns null !\n" ,
1861: Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1862: return STX_SECTOR_FLAG_RNF; /* Should not happen if FDC_NextSectorID_FdcCycles_STX succeeded before */
1863: }
1864:
1865: FDC_Buffer_Add ( pStxSector->ID_Track );
1866: FDC_Buffer_Add ( pStxSector->ID_Head );
1867: FDC_Buffer_Add ( pStxSector->ID_Sector );
1868: FDC_Buffer_Add ( pStxSector->ID_Size );
1869: FDC_Buffer_Add ( pStxSector->ID_CRC >> 8 );
1870: FDC_Buffer_Add ( pStxSector->ID_CRC & 0xff );
1871:
1872: /* If RNF is set and CRC error is set, then this ID field has a CRC error */
1873: if ( ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF ) && ( pStxSector->FDC_Status & STX_SECTOR_FLAG_CRC ) )
1874: return STX_SECTOR_FLAG_CRC;
1875:
1876: return 0; /* No error */
1877: }
1878:
1879:
1880: /*-----------------------------------------------------------------------*/
1881: /**
1882: * Read a track from a floppy image in STX format (used in type III command)
1883: * This function is called after an index pulse was encountered, and it will
1884: * always succeeds and fill the track buffer.
1885: * If the Track/Side infos exist in the STX image, then the corresponding
1886: * bytes from the track's image are returned.
1887: * If these Track/Side infos don't exist, we return some random bytes
1888: * (empty / not formatted track).
1889: * If the Track/Side infos exist but there's no track's image, then we build
1890: * a standard track by using the available sectors and standard GAP values.
1891: * Return 0 if OK
1892: */
1.1.1.2 root 1893: Uint8 FDC_ReadTrack_STX ( Uint8 Drive , Uint8 Track , Uint8 Side )
1.1 root 1894: {
1895: STX_TRACK_STRUCT *pStxTrack;
1896: STX_SECTOR_STRUCT *pStxSector;
1897: int i;
1898: Uint16 Timing;
1899: Uint32 Track_ReadTime;
1900: double Total_cur; /* To compute closest integer timings for each byte */
1901: double Total_prev;
1902: int TrackSize;
1903: int Sector;
1904: int SectorSize;
1905: Uint16 CRC;
1906: Uint8 *pData;
1907: Uint8 Byte;
1908:
1909: if ( STX_State.ImageBuffer[ Drive ] == NULL )
1910: {
1911: fprintf ( stderr , "FDC_ReadTrack_STX drive=%d track=%d side=%d, no image buffer !\n" , Drive , Track , Side );
1912: return STX_SECTOR_FLAG_RNF; /* Should not happen, just in case of a bug */
1913: }
1914:
1915: pStxTrack = STX_FindTrack ( Drive , Track , Side );
1916: if ( pStxTrack == NULL ) /* Track/Side don't exist in this STX image */
1917: {
1918: fprintf ( stderr , "fdc stx : track info not found for read track drive=%d track=%d side=%d, returning random bytes\n" , Drive , Track , Side );
1919: for ( i=0 ; i<FDC_GetBytesPerTrack ( Drive ) ; i++ )
1920: FDC_Buffer_Add ( rand() & 0xff ); /* Fill the track buffer with random bytes */
1921: return 0;
1922: }
1923:
1924: /* If the Track block contains a complete dump of the track image, use it directly */
1925: /* The timing for each byte is the average timing based on TrackImageSize */
1926: if ( pStxTrack->pTrackImageData )
1927: {
1928: Track_ReadTime = 8000000 / 5; /* 300 RPM, gives 5 RPS and 1600000 cycles per revolution at 8 MHz */
1929: Total_prev = 0;
1930: for ( i=0 ; i<pStxTrack->TrackImageSize ; i++ )
1931: {
1932: Total_cur = ( (double)Track_ReadTime * ( i+1 ) ) / pStxTrack->TrackImageSize;
1933: Timing = rint ( Total_cur - Total_prev );
1934: Total_prev += Timing;
1935: /* Add each byte to the buffer, Timing should be a number of FDC cycles at 8 MHz */
1936: FDC_Buffer_Add_Timing ( pStxTrack->pTrackImageData[ i ] , Timing );
1937: }
1938: }
1939:
1940: /* If the track block doesn't contain a dump of the track image, we must build a track */
1941: /* using the sector blocks and some standard GAP values */
1942: /* [NP] NOTE : we build a track of pStxTrack->MFMSize bytes, as this seems to always be != 0 */
1943: /* even for empty / not formatted track */
1944: /* [NP] NOTE : instead of using standard GAP values, we could compute GAP based on pStxSector->BitPosition */
1945: /* but this seems unnecessary, as a track image would certainly be present if precise GAP values */
1946: /* were required */
1947: else
1948: {
1949: TrackSize = pStxTrack->MFMSize;
1950: if ( ( pStxTrack->Flags & STX_TRACK_FLAG_SECTOR_BLOCK ) == 0 )
1951: TrackSize /= 8; /* When the track contains only sector data, MFMSize is in bits */
1952:
1953: /* If there's no image for this track, and no sector as well, then track is empty / not formatted */
1954: if ( pStxTrack->SectorsCount == 0 )
1955: {
1956: 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 );
1957: for ( i=0 ; i<TrackSize ; i++ )
1958: FDC_Buffer_Add ( rand() & 0xff ); /* Fill the track buffer with random bytes */
1959: return 0;
1960: }
1961:
1962: /* Use the available sectors and add some default GAPs to build the track */
1963: fprintf ( stderr , "fdc stx : no track image for read track drive=%d track=%d side=%d, building a standard track\n" , Drive , Track , Side );
1964:
1965: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP1 ; i++ ) /* GAP1 */
1966: FDC_Buffer_Add ( 0x4e );
1967:
1968: for ( Sector=0 ; Sector < pStxTrack->SectorsCount ; Sector++ )
1969: {
1970: pStxSector = &(pStxTrack->pSectorsStruct[ Sector ]);
1971: SectorSize = pStxSector->SectorSize;
1972:
1973: /* Check that the data+GAPs for this sector will not be above track's length */
1974: /* (in case we build a track with a high / non standard number of sectors) */
1975: if ( FDC_Buffer_Get_Size () + SectorSize + FDC_TRACK_LAYOUT_STANDARD_GAP2 + 10 + FDC_TRACK_LAYOUT_STANDARD_GAP3a
1976: + FDC_TRACK_LAYOUT_STANDARD_GAP3b + 4 + 2 + FDC_TRACK_LAYOUT_STANDARD_GAP4 >= TrackSize )
1977: {
1978: 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 );
1979: break; /* Exit the loop and fill the rest of the track */
1980: }
1981:
1982: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP2 ; i++ ) /* GAP2 */
1983: FDC_Buffer_Add ( 0x00 );
1984:
1985: /* Add the ID field for the sector */
1986: for ( i=0 ; i<3 ; i++ )
1987: FDC_Buffer_Add ( 0xa1 ); /* SYNC (write $F5) */
1988: FDC_Buffer_Add ( 0xfe ); /* Index Address Mark */
1989: FDC_Buffer_Add ( pStxSector->ID_Track );
1990: FDC_Buffer_Add ( pStxSector->ID_Head );
1991: FDC_Buffer_Add ( pStxSector->ID_Sector );
1992: FDC_Buffer_Add ( pStxSector->ID_Size );
1993: FDC_Buffer_Add ( pStxSector->ID_CRC >> 8 );
1994: FDC_Buffer_Add ( pStxSector->ID_CRC & 0xff );
1995:
1996: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP3a ; i++ ) /* GAP3a */
1997: FDC_Buffer_Add ( 0x4e );
1998: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP3b ; i++ ) /* GAP3b */
1999: FDC_Buffer_Add ( 0x00 );
2000:
2001: /* Add the data for the sector + build the CRC */
2002: crc16_reset ( &CRC );
2003: for ( i=0 ; i<3 ; i++ )
2004: {
2005: FDC_Buffer_Add ( 0xa1 ); /* SYNC (write $F5) */
2006: crc16_add_byte ( &CRC , 0xa1 );
2007: }
2008:
2009: FDC_Buffer_Add ( 0xfb ); /* Data Address Mark */
2010: crc16_add_byte ( &CRC , 0xfb );
2011:
2012: /* [NP] NOTE : when building the sector, we assume there's no specific timing or fuzzy bytes */
2013: /* If it was not the case, there would certainly be a real track image (and STX format doesn't */
2014: /* support fuzzy bytes or specific timing for a track image anyway) */
2015: /* If the sector was changed by a 'write sector' command, we use the data from pSaveSectorsStruct */
2016: if ( pStxSector->SaveSectorIndex < 0 ) /* Use original data from the STX */
2017: pData = pStxSector->pData;
2018: else /* Use data from the 'write sector' */
2019: pData = STX_SaveStruct[ Drive ].pSaveSectorsStruct[ pStxSector->SaveSectorIndex ].pData;
2020:
2021: for ( i=0 ; i<SectorSize ; i++ )
2022: {
2023: Byte = pData[ i ];
2024: FDC_Buffer_Add ( Byte );
2025: crc16_add_byte ( &CRC , Byte );
2026: }
2027:
2028: FDC_Buffer_Add ( CRC >> 8 ); /* CRC1 (write $F7) */
2029: FDC_Buffer_Add ( CRC & 0xff ); /* CRC2 */
2030:
2031: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP4 ; i++ ) /* GAP4 */
2032: FDC_Buffer_Add ( 0x4e );
2033: }
2034:
2035: while ( FDC_Buffer_Get_Size () < TrackSize ) /* Complete the track buffer */
2036: FDC_Buffer_Add ( 0x4e ); /* GAP5 */
2037: }
2038:
2039: return 0; /* No error */
2040: }
2041:
2042:
2043: /*-----------------------------------------------------------------------*/
2044: /**
2045: * Write a track to a floppy image in STX format (used in type III command)
2046: *
2047: * STX format doesn't support write command. For each 'write track' we
2048: * store the track data in a dedicated buffer STX_SaveStruct[].pSaveTracksStruct.
2049: * When the track is read later, we return the data from STX_SaveStruct[].pSaveTracksStruct
2050: * instead of returning the data from the original STX file.
2051: *
2052: * NOTE : data will saved in memory snapshot, as well as in an additional
2053: * file with the extension .wd1772.
2054: *
2055: * Return 0 if track was written without error, or LOST_DATA if an error occurred
2056: */
1.1.1.2 root 2057: Uint8 FDC_WriteTrack_STX ( Uint8 Drive , Uint8 Track , Uint8 Side , int TrackSize )
1.1 root 2058: {
2059: STX_TRACK_STRUCT *pStxTrack;
2060: int i;
2061: Uint8 *pTrack_DataWrite;
2062: void *pNewBuf;
2063: STX_SAVE_TRACK_STRUCT *pStxSaveTrack;
2064: int Sector;
2065:
2066: pStxTrack = STX_FindTrack ( Drive , Track , Side );
2067: if ( pStxTrack == NULL )
2068: {
2069: fprintf ( stderr , "FDC_WriteTrack_STX drive=%d track=%d side=%d returns null !\n" ,
2070: Drive , Track , Side );
2071: return STX_SECTOR_FLAG_LOST_DATA;
2072: }
2073:
2074: /* Check if this track was already changed by a 'write track' command */
2075: /* If so, we use the same structure. Else we alloc a new structure for this track */
2076: if ( pStxTrack->SaveTrackIndex < 0 )
2077: {
2078: //fprintf ( stderr , "realloc\n" );
2079: /* Increase save buffer by 1 */
2080: pNewBuf = realloc ( STX_SaveStruct[ Drive ].pSaveTracksStruct ,
2081: ( STX_SaveStruct[ Drive ].SaveTracksCount + 1 ) * sizeof ( STX_SAVE_TRACK_STRUCT ) );
2082: if ( pNewBuf == NULL )
2083: {
2084: fprintf ( stderr , "FDC_WriteTrack_STX drive=%d track=%d side=%d realloc error !\n" ,
2085: Drive , Track , Side );
2086: return STX_SECTOR_FLAG_LOST_DATA;
2087: }
2088:
2089: /* Save the new buffer values */
2090: STX_SaveStruct[ Drive ].pSaveTracksStruct = (STX_SAVE_TRACK_STRUCT *) pNewBuf;;
2091: STX_SaveStruct[ Drive ].SaveTracksCount++;
2092:
2093: pStxTrack->SaveTrackIndex = STX_SaveStruct[ Drive ].SaveTracksCount - 1;
2094: }
2095:
2096: /* Use the same structure : free previous DataWrite buffer */
2097: else
2098: {
2099: free ( STX_SaveStruct[ Drive ].pSaveTracksStruct[ pStxTrack->SaveTrackIndex ].pDataWrite );
2100: STX_SaveStruct[ Drive ].pSaveTracksStruct[ pStxTrack->SaveTrackIndex ].pDataWrite = NULL;
2101: /* TODO : also free pDataRead */
2102: }
2103:
2104: /* Create the new DataWrite buffer in pSaveTracksStruct */
2105: pNewBuf = malloc ( TrackSize );
2106: if ( pNewBuf == NULL )
2107: {
2108: fprintf ( stderr , "FDC_WriteTrack_STX drive=%d track=%d side=%d malloc error !\n" ,
2109: Drive , Track , Side );
2110: return STX_SECTOR_FLAG_LOST_DATA;
2111: }
2112:
2113: /* Fill the new SaveTrackStruct */
2114: pStxSaveTrack = &STX_SaveStruct[ Drive ].pSaveTracksStruct[ pStxTrack->SaveTrackIndex ];
2115:
2116: pStxSaveTrack->Track = Track;
2117: pStxSaveTrack->Side = Side;
2118:
2119: pStxSaveTrack->TrackSizeWrite = TrackSize;
2120: pStxSaveTrack->pDataWrite = (Uint8 *) pNewBuf;
2121:
2122:
2123: /* Get the track's data (ignore timings) */
2124: pTrack_DataWrite = STX_SaveStruct[ Drive ].pSaveTracksStruct[ pStxTrack->SaveTrackIndex ].pDataWrite;
2125:
2126: for ( i=0 ; i<pStxSaveTrack->TrackSizeWrite ; i++ )
2127: pTrack_DataWrite[ i ] = FDC_Buffer_Read_Byte_pos ( i );
2128:
2129: //fprintf ( stderr , "write drive=%d track=%d side=%d size=%d index=%d\n", Drive, Track, Side, pStxSaveTrack->TrackSizeWrite , pStxTrack->SaveTrackIndex );
2130: //Str_Dump_Hex_Ascii ( (char *) pTrack_DataWrite, pStxSaveTrack->TrackSizeWrite, 16, "" , stderr );
2131:
2132: // TODO : convert pDataWrite into pDataRead
2133: pStxSaveTrack->TrackSizeRead = 0; /* TODO : compute interpreted track */
2134: pStxSaveTrack->pDataRead = NULL; /* TODO : compute interpreted track */
2135:
2136:
2137: /* If some sectors were already saved for that track, we must remove them */
2138: /* as the 'write track' takes precedence over the previous 'write sector' */
2139: for ( Sector=0 ; Sector < pStxTrack->SectorsCount ; Sector++ )
2140: {
2141: if ( pStxTrack->pSectorsStruct[ Sector ].SaveSectorIndex >= 0 )
2142: {
2143: STX_FreeSaveSectorsStruct ( STX_SaveStruct[ Drive ].pSaveSectorsStruct ,
2144: pStxTrack->pSectorsStruct[ Sector ].SaveSectorIndex );
2145: pStxTrack->pSectorsStruct[ Sector ].SaveSectorIndex = -1;
2146: }
2147: }
2148:
2149:
2150: /* Warn that 'write track' data will be lost or saved (if zipped or not) */
2151: if ( STX_State.ImageBuffer[ Drive ]->WarnedWriteTrack == false )
2152: {
2153: if ( File_DoesFileExtensionMatch ( EmulationDrives[ Drive ].sFileName , ".zip" ) )
2154: Log_AlertDlg ( LOG_INFO , "WARNING : can't save changes made with 'write track' to an STX disk inside a zip file" );
2155: else
2156: Log_AlertDlg ( LOG_INFO , "Changes made with 'write track' to an STX disk will be saved into an additional .wd1772 file" );
2157: STX_State.ImageBuffer[ Drive ]->WarnedWriteTrack = true;
2158: }
2159:
2160:
2161: /* No error */
2162: EmulationDrives[Drive].bContentsChanged = true;
2163: return 0;
2164: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.