|
|
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:
1003: if ( pSaveSectorsStruct[ Nb ].pData )
1004: free ( pSaveSectorsStruct[ Nb ].pData );
1005:
1006: pSaveSectorsStruct[ Nb ].StructIsUsed = 0;
1007: }
1008:
1009:
1010: /*-----------------------------------------------------------------------*/
1011: /**
1012: * Free the memory allocated to store all the STX_SAVE_TRACK_STRUCT
1013: */
1014: static void STX_FreeSaveTracksStructAll ( STX_SAVE_TRACK_STRUCT *pSaveTracksStruct , Uint32 SaveTracksCount )
1015: {
1016: Uint32 i;
1017:
1018: if ( !pSaveTracksStruct )
1019: return;
1020:
1021: for ( i = 0 ; i < SaveTracksCount ; i++ )
1022: {
1023: STX_FreeSaveTracksStruct ( pSaveTracksStruct , i );
1024: }
1025:
1026: free ( pSaveTracksStruct );
1027: }
1028:
1029:
1030: /*-----------------------------------------------------------------------*/
1031: /**
1032: * Free the memory allocated to store one STX_SAVE_TRACK_STRUCT
1033: */
1034: static void STX_FreeSaveTracksStruct ( STX_SAVE_TRACK_STRUCT *pSaveTracksStruct , int Nb )
1035: {
1036: if ( pSaveTracksStruct[ Nb ].pDataWrite )
1037: free ( pSaveTracksStruct[ Nb ].pDataWrite );
1038: if ( pSaveTracksStruct[ Nb ].pDataRead )
1039: free ( pSaveTracksStruct[ Nb ].pDataRead );
1040: }
1041:
1042:
1043: /*-----------------------------------------------------------------------*/
1044: /**
1045: * Parse an STX file.
1046: * The file is in pFileBuffer and we dynamically allocate memory to store
1047: * the components (main header, tracks, sectors).
1048: * Some internal variables/pointers are also computed, to speed up
1049: * data access when the FDC emulates an STX file.
1050: */
1051: STX_MAIN_STRUCT *STX_BuildStruct ( Uint8 *pFileBuffer , int Debug )
1052: {
1053:
1054: STX_MAIN_STRUCT *pStxMain;
1055: STX_TRACK_STRUCT *pStxTrack;
1056: STX_SECTOR_STRUCT *pStxSector;
1057: Uint8 *p;
1058: Uint8 *p_cur;
1059: int Track;
1060: int Sector;
1061: Uint8 *pFuzzyData;
1062: Uint8 *pTimingData;
1063: Uint32 MaxOffsetSectorEnd;
1064: int VariableTimings;
1065:
1066: pStxMain = malloc ( sizeof ( STX_MAIN_STRUCT ) );
1067: if ( !pStxMain )
1068: return NULL;
1069: memset ( pStxMain , 0 , sizeof ( STX_MAIN_STRUCT ) );
1070:
1071: p = pFileBuffer;
1072:
1073: /* Read file's header */
1074: memcpy ( pStxMain->FileID , p , 4 ); p += 4;
1075: pStxMain->Version = STX_ReadU16_LE ( p ); p += 2;
1076: pStxMain->ImagingTool = STX_ReadU16_LE ( p ); p += 2;
1077: pStxMain->Reserved_1 = STX_ReadU16_LE ( p ); p += 2;
1078: pStxMain->TracksCount = *p++;;
1079: pStxMain->Revision = *p++;
1080: pStxMain->Reserved_2 = STX_ReadU32_LE ( p ); p += 4;
1081:
1082: if ( Debug & STX_DEBUG_FLAG_STRUCTURE )
1083: fprintf ( stderr , "STX header ID='%.4s' Version=%4.4x ImagingTool=%4.4x Reserved1=%4.4x"
1084: " TrackCount=%d Revision=%2.2x Reserved2=%x\n" , pStxMain->FileID , pStxMain->Version ,
1085: pStxMain->ImagingTool , pStxMain->Reserved_1 , pStxMain->TracksCount , pStxMain->Revision ,
1086: pStxMain->Reserved_2 );
1087:
1088: pStxMain->WarnedWriteSector = false;
1089: pStxMain->WarnedWriteTrack = false;
1090:
1091: pStxTrack = malloc ( sizeof ( STX_TRACK_STRUCT ) * pStxMain->TracksCount );
1092: if ( !pStxTrack )
1093: {
1094: STX_FreeStruct ( pStxMain );
1095: return NULL;
1096: }
1097: memset ( pStxTrack , 0 , sizeof ( STX_TRACK_STRUCT ) * pStxMain->TracksCount );
1098: pStxMain->pTracksStruct = pStxTrack;
1099:
1100: /* Parse all the track blocks */
1101: for ( Track = 0 ; Track < pStxMain->TracksCount ; Track++ )
1102: {
1103: p_cur = p;
1104:
1105: pStxTrack->BlockSize = STX_ReadU32_LE ( p ); p += 4;
1106: pStxTrack->FuzzySize = STX_ReadU32_LE ( p ); p += 4;
1107: pStxTrack->SectorsCount = STX_ReadU16_LE ( p ); p += 2;
1108: pStxTrack->Flags = STX_ReadU16_LE ( p ); p += 2;
1109: pStxTrack->MFMSize = STX_ReadU16_LE ( p ); p += 2;
1110: pStxTrack->TrackNumber = *p++;
1111: pStxTrack->RecordType = *p++;
1112:
1113: pStxTrack->SaveTrackIndex = -1;
1114:
1115: if ( pStxTrack->SectorsCount == 0 ) /* No sector (track image only, or empty / non formatted track) */
1116: {
1117: pStxTrack->pSectorsStruct = NULL;
1118: }
1119: else
1120: {
1121: /* Track contains some sectors */
1122: pStxSector = malloc ( sizeof ( STX_SECTOR_STRUCT ) * pStxTrack->SectorsCount );
1123: if ( !pStxSector )
1124: {
1125: STX_FreeStruct ( pStxMain );
1126: return NULL;
1127: }
1128: memset ( pStxSector , 0 , sizeof ( STX_SECTOR_STRUCT ) * pStxTrack->SectorsCount );
1129: pStxTrack->pSectorsStruct = pStxSector;
1130:
1131: /* Do we have some sector infos after the track header or only sector data ? */
1132: if ( ( pStxTrack->Flags & STX_TRACK_FLAG_SECTOR_BLOCK ) == 0 )
1133: {
1134: /* The track only contains SectorsCount sectors of 512 bytes */
1135: /* NOTE |NP] : in that case, pStxTrack->MFMSize seems to be in bits instead of bytes */
1136: STX_BuildSectorsSimple ( pStxTrack , p );
1137: goto next_track;
1138: }
1139: }
1140:
1141: /* Start of the optional fuzzy bits data */
1142: pStxTrack->pFuzzyData = p + pStxTrack->SectorsCount * STX_SECTOR_BLOCK_SIZE;
1143:
1144: /* Start of the optional track data */
1145: pStxTrack->pTrackData = pStxTrack->pFuzzyData + pStxTrack->FuzzySize;
1146:
1147: if ( ( pStxTrack->Flags & STX_TRACK_FLAG_TRACK_IMAGE ) == 0 )
1148: {
1149: pStxTrack->TrackImageSyncPosition = 0;
1150: pStxTrack->TrackImageSize = 0;
1151: pStxTrack->pTrackImageData = NULL;
1152: pStxTrack->pSectorsImageData = pStxTrack->pTrackData;
1153: }
1154: else if ( ( pStxTrack->Flags & STX_TRACK_FLAG_TRACK_IMAGE_SYNC ) == 0 ) /* Track with size+data */
1155: {
1156: pStxTrack->TrackImageSyncPosition = 0;
1157: pStxTrack->TrackImageSize = STX_ReadU16_LE ( pStxTrack->pTrackData );
1158: pStxTrack->pTrackImageData = pStxTrack->pTrackData + 2;
1159: pStxTrack->pSectorsImageData = pStxTrack->pTrackImageData + pStxTrack->TrackImageSize;
1160: }
1161: else /* Track with sync offset + size + data */
1162: {
1163: pStxTrack->TrackImageSyncPosition = STX_ReadU16_LE ( pStxTrack->pTrackData );
1164: pStxTrack->TrackImageSize = STX_ReadU16_LE ( pStxTrack->pTrackData + 2 );
1165: pStxTrack->pTrackImageData = pStxTrack->pTrackData + 4;
1166: pStxTrack->pSectorsImageData = pStxTrack->pTrackImageData + pStxTrack->TrackImageSize;
1167: }
1168:
1169: if ( pStxTrack->SectorsCount == 0 ) /* No sector (track image only, or empty / non formatted track) */
1170: goto next_track;
1171:
1172: /* Parse all the sectors in this track */
1173: pFuzzyData = pStxTrack->pFuzzyData;
1174: VariableTimings = 0;
1175: MaxOffsetSectorEnd = 0;
1176: for ( Sector = 0 ; Sector < pStxTrack->SectorsCount ; Sector++ )
1177: {
1178: pStxSector = &(pStxTrack->pSectorsStruct[ Sector ]);
1179:
1180: pStxSector->DataOffset = STX_ReadU32_LE ( p ); p += 4;
1181: pStxSector->BitPosition = STX_ReadU16_LE ( p ); p += 2;
1182: pStxSector->ReadTime = STX_ReadU16_LE ( p ); p += 2;
1183: pStxSector->ID_Track = *p++;
1184: pStxSector->ID_Head = *p++;
1185: pStxSector->ID_Sector = *p++;
1186: pStxSector->ID_Size = *p++;
1187: pStxSector->ID_CRC = ( p[0] << 8 ) | p[1] ; p +=2;
1188: pStxSector->FDC_Status = *p++;
1189: pStxSector->Reserved = *p++;
1190:
1191: /* Check if sector has data */
1192: if ( ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF ) == 0 )
1193: {
1194: /* Check if SectorSize is valid (this is just a warning, we keep only bits 0-1 anyway) */
1195: if ( pStxSector->ID_Size & ~FDC_SECTOR_SIZE_MASK )
1196: {
1197: // fprintf ( stderr , "STX : invalid ID_Size=%d on track %d sector %d\n" ,
1198: // pStxSector->ID_Size , Track , Sector );
1199: }
1200:
1201: pStxSector->SectorSize = 128 << ( pStxSector->ID_Size & FDC_SECTOR_SIZE_MASK );
1202:
1203: pStxSector->pData = pStxTrack->pTrackData + pStxSector->DataOffset;
1204: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_FUZZY )
1205: {
1206: pStxSector->pFuzzyData = pFuzzyData;
1207: pFuzzyData += pStxSector->SectorSize;
1208: }
1209:
1210: /* Max offset of the end of all sectors image in the track */
1211: if ( MaxOffsetSectorEnd < pStxSector->DataOffset + pStxSector->SectorSize )
1212: MaxOffsetSectorEnd = pStxSector->DataOffset + pStxSector->SectorSize;
1213:
1214: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_VARIABLE_TIME )
1215: VariableTimings = 1;
1216: }
1217:
1218: pStxSector->SaveSectorIndex = -1;
1219: }
1220:
1221: /* Start of the optional timings data, after the optional sectors image data */
1222: pStxTrack->pTiming = pStxTrack->pTrackData + MaxOffsetSectorEnd;
1223: if ( pStxTrack->pTiming < pStxTrack->pSectorsImageData ) /* If all sectors image were inside the track image */
1224: pStxTrack->pTiming = pStxTrack->pSectorsImageData; /* then timings data are just after the track image */
1225:
1226: if ( VariableTimings == 1 ) /* Track has at least one variable sector */
1227: {
1228: if ( pStxMain->Revision == 2 ) /* Specific timing table */
1229: {
1230: pStxTrack->TimingFlags = STX_ReadU16_LE ( pStxTrack->pTiming ); /* always '5' ? */
1231: pStxTrack->TimingSize = STX_ReadU16_LE ( pStxTrack->pTiming + 2 );
1232: pStxTrack->pTimingData = pStxTrack->pTiming + 4; /* 2 bytes of timing for each block of 16 bytes */
1233: }
1234:
1235: /* Compute the address of the timings data for each sector with variable timings */
1236: pTimingData = pStxTrack->pTimingData;
1237: for ( Sector = 0 ; Sector < pStxTrack->SectorsCount ; Sector++ )
1238: {
1239: pStxSector = &(pStxTrack->pSectorsStruct[ Sector ]);
1240: pStxSector->pTimingData = NULL; /* No timings by default */
1241:
1242: /* Check if sector has data + variable timings */
1243: if ( ( ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF ) == 0 )
1244: && ( pStxSector->FDC_Status & STX_SECTOR_FLAG_VARIABLE_TIME ) )
1245: {
1246: if ( pStxMain->Revision == 2 ) /* Specific table for revision 2 */
1247: {
1248: pStxSector->pTimingData = pTimingData;
1249: pTimingData += ( pStxSector->SectorSize / 16 ) * 2;
1250: }
1251: else
1252: pStxSector->pTimingData = TimingDataDefault; /* Fixed table for revision 0 */
1253: }
1254: }
1255: }
1256:
1257: next_track:
1258: if ( Debug & STX_DEBUG_FLAG_STRUCTURE )
1259: {
1260: fprintf ( stderr , " track %3d BlockSize=%d FuzzySize=%d Sectors=%4.4x Flags=%4.4x"
1261: " MFMSize=%d TrackNb=%2.2x Side=%d RecordType=%x"
1262: " TrackImage=%s (%d bytes, sync=%4.4x) Timings=%d,%d\n" ,
1263: Track , pStxTrack->BlockSize ,
1264: pStxTrack->FuzzySize , pStxTrack->SectorsCount , pStxTrack->Flags , pStxTrack->MFMSize ,
1265: pStxTrack->TrackNumber & 0x7f , ( pStxTrack->TrackNumber >> 7 ) & 0x01 , pStxTrack->RecordType ,
1266: pStxTrack->pTrackImageData ? "yes" : "no" , pStxTrack->TrackImageSize , pStxTrack->TrackImageSyncPosition ,
1267: pStxTrack->TimingFlags , pStxTrack->TimingSize );
1268:
1269: if ( ( Debug & STX_DEBUG_FLAG_DATA ) && pStxTrack->pTrackImageData )
1270: {
1271: fprintf ( stderr , " track image data :\n" );
1272: Str_Dump_Hex_Ascii ( (char *)pStxTrack->pTrackImageData , pStxTrack->TrackImageSize ,
1273: 16 , " " , stderr );
1274: }
1275:
1276: if ( pStxTrack->SectorsCount == 0 )
1277: fprintf ( stderr , " no sector in this track, %s\n" ,
1278: pStxTrack->pTrackImageData ? "only track image" : "track empty / not formatted" );
1279: else
1280: for ( Sector = 0 ; Sector < pStxTrack->SectorsCount ; Sector++ )
1281: {
1282: /* If the sector use the internal timing table, we print TimingsOffset=-1 */
1283: pStxSector = &(pStxTrack->pSectorsStruct[ Sector ]);
1284: fprintf ( stderr , " sector %2d DataOffset=%d BitPosition=%d ReadTime=%d"
1285: " [track=%2.2x head=%2.2x sector=%2.2x size=%2.2x crc=%4.4x]"
1286: " FdcStatus=%2.2x Reserved=%2.2x TimingsOffset=%d\n" ,
1287: Sector , pStxSector->DataOffset , pStxSector->BitPosition ,
1288: pStxSector->ReadTime , pStxSector->ID_Track , pStxSector->ID_Head ,
1289: pStxSector->ID_Sector , pStxSector->ID_Size , pStxSector->ID_CRC ,
1290: pStxSector->FDC_Status , pStxSector->Reserved ,
1291: pStxSector->pTimingData ?
1292: ( pStxTrack->TimingSize > 0 ? (int)(pStxSector->pTimingData - pStxTrack->pTrackData) : -1 )
1293: : 0 );
1294:
1295: if ( ( Debug & STX_DEBUG_FLAG_DATA ) && pStxSector->pData )
1296: {
1297: fprintf ( stderr , " sector data :\n" );
1298: Str_Dump_Hex_Ascii ( (char *)pStxSector->pData , pStxSector->SectorSize ,
1299: 16 , " " , stderr );
1300: }
1301: if ( ( Debug & STX_DEBUG_FLAG_DATA ) && pStxSector->pFuzzyData )
1302: {
1303: fprintf ( stderr , " fuzzy data :\n" );
1304: Str_Dump_Hex_Ascii ( (char *)pStxSector->pFuzzyData , pStxSector->SectorSize ,
1305: 16 , " " , stderr );
1306: }
1307: if ( ( Debug & STX_DEBUG_FLAG_DATA ) && pStxSector->pTimingData )
1308: {
1309: fprintf ( stderr , " timing data :\n" );
1310: Str_Dump_Hex_Ascii ( (char *)pStxSector->pTimingData , ( pStxSector->SectorSize / 16 ) * 2 ,
1311: 16 , " " , stderr );
1312: }
1313: }
1314: }
1315:
1316: p = p_cur + pStxTrack->BlockSize; /* Next Track block */
1317: pStxTrack++;
1318: }
1319:
1320:
1321: return pStxMain;
1322: }
1323:
1324:
1325: /*-----------------------------------------------------------------------*/
1326: /**
1327: * When a track only consists of the content of each 512 bytes sector and
1328: * no timings informations, we must compute some default values for each
1329: * sector, as well as the position of the corresponding 512 bytes of data.
1330: * This is only used when storing unprotected tracks.
1331: */
1332: static void STX_BuildSectorsSimple ( STX_TRACK_STRUCT *pStxTrack , Uint8 *p )
1333: {
1334: int Sector;
1335: int BytePosition;
1336: Uint16 CRC;
1337:
1338: BytePosition = FDC_TRACK_LAYOUT_STANDARD_GAP1 + FDC_TRACK_LAYOUT_STANDARD_GAP2; /* Points to the 3x$A1 before the 1st IDAM $FE */
1339: BytePosition += 4; /* Pasti seems to point after the 3x$A1 and the IDAM $FE */
1340:
1341: for ( Sector = 0 ; Sector < pStxTrack->SectorsCount ; Sector++ )
1342: {
1343: pStxTrack->pSectorsStruct[ Sector ].SaveSectorIndex = -1;
1344: pStxTrack->pSectorsStruct[ Sector ].DataOffset = 0;
1345: pStxTrack->pSectorsStruct[ Sector ].BitPosition = BytePosition * 8;
1346: pStxTrack->pSectorsStruct[ Sector ].ReadTime = 0;
1347:
1348: /* Build the ID Field */
1349: pStxTrack->pSectorsStruct[ Sector ].ID_Track = pStxTrack->TrackNumber & 0x7f;
1350: pStxTrack->pSectorsStruct[ Sector ].ID_Head = ( pStxTrack->TrackNumber >> 7 ) & 0x01;
1351: pStxTrack->pSectorsStruct[ Sector ].ID_Sector = Sector + 1;
1352: pStxTrack->pSectorsStruct[ Sector ].ID_Size = FDC_SECTOR_SIZE_512;
1353: CRC = STX_BuildSectorID_CRC ( &(pStxTrack->pSectorsStruct[ Sector ]) );
1354: pStxTrack->pSectorsStruct[ Sector ].ID_CRC = CRC;
1355:
1356: pStxTrack->pSectorsStruct[ Sector ].FDC_Status = 0;
1357: pStxTrack->pSectorsStruct[ Sector ].Reserved = 0;
1358: pStxTrack->pSectorsStruct[ Sector ].pData = p + Sector * 512;
1359: pStxTrack->pSectorsStruct[ Sector ].SectorSize = 128 << pStxTrack->pSectorsStruct[ Sector ].ID_Size;
1360:
1361: BytePosition += FDC_TRACK_LAYOUT_STANDARD_RAW_SECTOR_512;
1362: }
1363: }
1364:
1365:
1366:
1367: /*-----------------------------------------------------------------------*/
1368: /**
1369: * Compute the CRC of the Address Field for a given sector.
1370: */
1371: static Uint16 STX_BuildSectorID_CRC ( STX_SECTOR_STRUCT *pStxSector )
1372: {
1373: Uint16 CRC;
1374:
1375: crc16_reset ( &CRC );
1376: crc16_add_byte ( &CRC , 0xa1 );
1377: crc16_add_byte ( &CRC , 0xa1 );
1378: crc16_add_byte ( &CRC , 0xa1 );
1379: crc16_add_byte ( &CRC , 0xfe );
1380: crc16_add_byte ( &CRC , pStxSector->ID_Track );
1381: crc16_add_byte ( &CRC , pStxSector->ID_Head );
1382: crc16_add_byte ( &CRC , pStxSector->ID_Sector );
1383: crc16_add_byte ( &CRC , pStxSector->ID_Size );
1384:
1385: return CRC;
1386: }
1387:
1388:
1389:
1390: /*-----------------------------------------------------------------------*/
1391: /**
1392: * Find a track in the floppy image inserted into a drive.
1393: */
1394: static STX_TRACK_STRUCT *STX_FindTrack ( Uint8 Drive , Uint8 Track , Uint8 Side )
1395: {
1396: int i;
1397:
1398: if ( STX_State.ImageBuffer[ Drive ] == NULL )
1399: return NULL;
1400:
1401: for ( i=0 ; i<STX_State.ImageBuffer[ Drive ]->TracksCount ; i++ )
1402: if ( STX_State.ImageBuffer[ Drive ]->pTracksStruct[ i ].TrackNumber == ( ( Track & 0x7f ) | ( Side << 7 ) ) )
1403: return &(STX_State.ImageBuffer[ Drive ]->pTracksStruct[ i ]);
1404:
1405: return NULL;
1406: }
1407:
1408:
1409:
1410: /*-----------------------------------------------------------------------*/
1411: /**
1412: * Find a sector in the floppy image inserted into a drive.
1413: * SectorStruct_Nb is a value set by a previous call to FDC_NextSectorID_FdcCycles_STX()
1414: */
1415: static STX_SECTOR_STRUCT *STX_FindSector ( Uint8 Drive , Uint8 Track , Uint8 Side , Uint8 SectorStruct_Nb )
1416: {
1417: STX_TRACK_STRUCT *pStxTrack;
1418:
1419: if ( STX_State.ImageBuffer[ Drive ] == NULL )
1420: return NULL;
1421:
1422: pStxTrack = STX_FindTrack ( Drive , Track , Side );
1423: if ( pStxTrack == NULL )
1424: return NULL;
1425:
1426: if ( pStxTrack->pSectorsStruct == NULL )
1427: return NULL;
1428:
1429: return &(pStxTrack->pSectorsStruct[ SectorStruct_Nb ]);
1430: }
1431:
1432:
1433:
1434: /*-----------------------------------------------------------------------*/
1435: /**
1436: * Find a sector in the floppy image inserted into a drive.
1437: * The sector is identified by its BitPosition which is unique per track/side
1438: */
1439: static STX_SECTOR_STRUCT *STX_FindSector_By_Position ( Uint8 Drive , Uint8 Track , Uint8 Side , Uint16 BitPosition )
1440: {
1441: STX_TRACK_STRUCT *pStxTrack;
1442: int Sector;
1443:
1444: if ( STX_State.ImageBuffer[ Drive ] == NULL )
1445: return NULL;
1446:
1447: pStxTrack = STX_FindTrack ( Drive , Track , Side );
1448: if ( pStxTrack == NULL )
1449: return NULL;
1450:
1451: if ( pStxTrack->pSectorsStruct == NULL )
1452: return NULL;
1453:
1454: for ( Sector=0 ; Sector<pStxTrack->SectorsCount ; Sector++ )
1455: if ( pStxTrack->pSectorsStruct[ Sector ].BitPosition == BitPosition )
1456: return &(pStxTrack->pSectorsStruct[ Sector ]);
1457:
1458: return NULL;
1459: }
1460:
1461:
1462:
1463: /*-----------------------------------------------------------------------*/
1464: /**
1465: * Return the number of FDC cycles to go from one index pulse to the next
1466: * one on a given drive/track/side.
1467: * We take the TrackSize into account to return this delay.
1468: */
1.1.1.2 ! root 1469: Uint32 FDC_GetCyclesPerRev_FdcCycles_STX ( Uint8 Drive , Uint8 Track , Uint8 Side )
1.1 root 1470: {
1471: STX_TRACK_STRUCT *pStxTrack;
1472: int TrackSize;
1473:
1474: pStxTrack = STX_FindTrack ( Drive , Track , Side );
1475: if ( pStxTrack == NULL )
1476: TrackSize = FDC_TRACK_BYTES_STANDARD; /* Use a standard track length is track is not available */
1477:
1478: else if ( pStxTrack->pTrackImageData )
1479: TrackSize = pStxTrack->TrackImageSize;
1480: else if ( ( pStxTrack->Flags & STX_TRACK_FLAG_SECTOR_BLOCK ) == 0 )
1481: TrackSize = pStxTrack->MFMSize / 8; /* When the track contains only sector data, MFMSize is in bits */
1482: else
1483: TrackSize = pStxTrack->MFMSize;
1484:
1485: //fprintf ( stderr , "fdc stx drive=%d track=0x%x side=%d size=%d\n" , Drive , Track, Side , TrackSize );
1486: return TrackSize * FDC_DELAY_CYCLE_MFM_BYTE;
1487: }
1488:
1489:
1490:
1491: /*-----------------------------------------------------------------------*/
1492: /**
1493: * Return the number of FDC cycles to wait before reaching the next
1494: * sector's ID Field in the track ($A1 $A1 $A1 $FE TR SIDE SR LEN CRC1 CRC2)
1495: * If no ID Field is found before the end of the track, we use the 1st
1496: * ID Field of the track (which simulates a full spin of the floppy).
1497: * We also store the next sector's number into NextSectorStruct_Nbr,
1498: * the next sector's number into NextSector_ID_Field_SR, the next track's number
1499: * into NextSector_ID_Field_TR, the next sector's lenght into
1500: * NextSector_ID_Field_LEN and if the CRC is correct or not into NextSector_ID_Field_CRC_OK.
1501: * This function assumes the sectors of each track are sorted in ascending order
1502: * using BitPosition.
1503: * If there's no available drive/floppy or no ID field in the track, we return -1
1504: */
1.1.1.2 ! root 1505: int FDC_NextSectorID_FdcCycles_STX ( Uint8 Drive , Uint8 NumberOfHeads , Uint8 Track , Uint8 Side )
1.1 root 1506: {
1507: STX_TRACK_STRUCT *pStxTrack;
1508: int CurrentPos_FdcCycles;
1509: int i;
1510: int Delay_FdcCycles;
1511: int TrackSize;
1512:
1513: CurrentPos_FdcCycles = FDC_IndexPulse_GetCurrentPos_FdcCycles ( NULL );
1514: if ( CurrentPos_FdcCycles < 0 ) /* No drive/floppy available at the moment */
1515: return -1;
1516:
1517: if ( ( Side == 1 ) && ( NumberOfHeads == 1 ) ) /* Can't read side 1 on a single sided drive */
1518: return -1;
1519:
1520: pStxTrack = STX_FindTrack ( Drive , Track , Side );
1521: if ( pStxTrack == NULL ) /* Track/Side don't exist in this STX image */
1522: return -1;
1523:
1524: if ( pStxTrack->SectorsCount == 0 ) /* No sector (track image only, or empty / non formatted track) */
1525: return -1;
1526:
1527: /* Compare CurrentPos_FdcCycles with each sector's position in ascending order */
1528: for ( i=0 ; i<pStxTrack->SectorsCount ; i++ )
1529: {
1530: if ( CurrentPos_FdcCycles < (int)pStxTrack->pSectorsStruct[ i ].BitPosition*FDC_DELAY_CYCLE_MFM_BIT ) /* 1 bit = 32 cycles at 8 MHz */
1531: break; /* We found the next sector */
1532: }
1533:
1534: if ( i == pStxTrack->SectorsCount ) /* CurrentPos_FdcCycles is after the last ID Field of this track */
1535: {
1536: /* Reach end of track (new index pulse), then go to 1st sector from current position */
1537: if ( pStxTrack->pTrackImageData )
1538: TrackSize = pStxTrack->TrackImageSize;
1539: else if ( ( pStxTrack->Flags & STX_TRACK_FLAG_SECTOR_BLOCK ) == 0 )
1540: TrackSize = pStxTrack->MFMSize / 8; /* When the track contains only sector data, MFMSize is in bits */
1541: else
1542: TrackSize = pStxTrack->MFMSize;
1543:
1544: Delay_FdcCycles = TrackSize * FDC_DELAY_CYCLE_MFM_BYTE - CurrentPos_FdcCycles
1545: + pStxTrack->pSectorsStruct[ 0 ].BitPosition*FDC_DELAY_CYCLE_MFM_BIT;
1546: STX_State.NextSectorStruct_Nbr = 0;
1547: //fprintf ( stderr , "size=%d pos=%d pos0=%d delay=%d\n" , TrackSize, CurrentPos_FdcCycles, pStxTrack->pSectorsStruct[ 0 ].BitPosition , Delay_FdcCycles );
1548: }
1549: else /* There's an ID Field before end of track */
1550: {
1551: Delay_FdcCycles = (int)pStxTrack->pSectorsStruct[ i ].BitPosition*FDC_DELAY_CYCLE_MFM_BIT - CurrentPos_FdcCycles;
1552: STX_State.NextSectorStruct_Nbr = i;
1553: //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 );
1554: }
1555:
1556: /* Store the value of the track/sector numbers in the next ID field */
1557: STX_State.NextSector_ID_Field_TR = pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].ID_Track;
1558: STX_State.NextSector_ID_Field_SR = pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].ID_Sector;
1559: STX_State.NextSector_ID_Field_LEN = pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].ID_Size;
1560:
1561: /* If RNF is set and CRC error is set, then this ID field has a CRC error */
1562: if ( ( pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].FDC_Status & STX_SECTOR_FLAG_RNF )
1563: && ( pStxTrack->pSectorsStruct[ STX_State.NextSectorStruct_Nbr ].FDC_Status & STX_SECTOR_FLAG_CRC ) )
1564: STX_State.NextSector_ID_Field_CRC_OK = 0; /* CRC bad */
1565: else
1566: STX_State.NextSector_ID_Field_CRC_OK = 1; /* CRC correct */
1567:
1568: /* BitPosition in STX seems to point just after the IDAM $FE ; we need to point 4 bytes earlier at the 1st $A1 */
1569: Delay_FdcCycles -= 4 * FDC_DELAY_CYCLE_MFM_BYTE; /* Correct delay to point to $A1 $A1 $A1 $FE */
1570:
1571: //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 );
1572: return Delay_FdcCycles;
1573: }
1574:
1575:
1576:
1577: /*-----------------------------------------------------------------------*/
1578: /**
1579: * Return the value of the track number in the next ID field set by
1580: * FDC_NextSectorID_FdcCycles_STX.
1581: */
1.1.1.2 ! root 1582: Uint8 FDC_NextSectorID_TR_STX ( void )
1.1 root 1583: {
1584: return STX_State.NextSector_ID_Field_TR;
1585: }
1586:
1587:
1588: /*-----------------------------------------------------------------------*/
1589: /**
1590: * Return the value of the sector number in the next ID field set by
1591: * FDC_NextSectorID_FdcCycles_STX.
1592: */
1.1.1.2 ! root 1593: Uint8 FDC_NextSectorID_SR_STX ( void )
1.1 root 1594: {
1595: return STX_State.NextSector_ID_Field_SR;
1596: }
1597:
1598:
1599: /*-----------------------------------------------------------------------*/
1600: /**
1601: * Return the value of the sector's length in the next ID field set by
1602: * FDC_NextSectorID_FdcCycles_STX.
1603: */
1.1.1.2 ! root 1604: Uint8 FDC_NextSectorID_LEN_STX ( void )
1.1 root 1605: {
1606: return STX_State.NextSector_ID_Field_LEN;
1607: }
1608:
1609:
1610: /*-----------------------------------------------------------------------*/
1611: /**
1612: * Return the status of the CRC in the next ID field set by
1613: * FDC_NextSectorID_FdcCycles_STX.
1614: * If '0', CRC is bad, else CRC is OK
1615: */
1.1.1.2 ! root 1616: Uint8 FDC_NextSectorID_CRC_OK_STX ( void )
1.1 root 1617: {
1618: return STX_State.NextSector_ID_Field_CRC_OK;
1619: }
1620:
1621:
1622: /*-----------------------------------------------------------------------*/
1623: /**
1624: * Read a sector from a floppy image in STX format (used in type II command)
1625: * We return the sector NextSectorStruct_Nbr, whose value was set
1626: * by the latest call to FDC_NextSectorID_FdcCycles_STX
1627: * Each byte of the sector is added to the FDC buffer with a default timing
1628: * (32 microsec) or a variable timing, depending on the sector's flags.
1629: * Some sectors can also contains "fuzzy" bits.
1630: * Special care must be taken to compute the timing of each byte, which can
1631: * be a decimal value and must be rounded to the best possible integer.
1632: *
1633: * If the sector's data were changed by a 'write sector' command, then we assume
1634: * a sector with no fuzzy byte and standard timings.
1635: *
1636: * Return RNF if sector was not found, else return CRC and RECORD_TYPE values
1637: * for the status register.
1638: */
1.1.1.2 ! root 1639: Uint8 FDC_ReadSector_STX ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side , int *pSectorSize )
1.1 root 1640: {
1641: STX_SECTOR_STRUCT *pStxSector;
1642: int i;
1643: Uint8 Byte;
1644: Uint16 Timing;
1645: Uint32 Sector_ReadTime;
1646: double Total_cur; /* To compute closest integer timings for each byte */
1647: double Total_prev;
1648: Uint8 *pSector_WriteData;
1649:
1650: pStxSector = STX_FindSector ( Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1651: if ( pStxSector == NULL )
1652: {
1653: fprintf ( stderr , "FDC_ReadSector_STX drive=%d track=%d side=%d sector=%d returns null !\n" ,
1654: Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1655: return STX_SECTOR_FLAG_RNF; /* Should not happen if FDC_NextSectorID_FdcCycles_STX succeeded before */
1656: }
1657:
1658: /* If RNF is set, return FDC_STR_BIT_RNF */
1659: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF )
1660: return STX_SECTOR_FLAG_RNF; /* RNF in FDC's status register */
1661:
1662: *pSectorSize = pStxSector->SectorSize;
1663: Sector_ReadTime = pStxSector->ReadTime;
1664:
1665: /* Check if this sector was changed by a 'write sector' command */
1666: /* If so, we use this recent buffer instead of the original STX content */
1667: if (STX_SaveStruct[Drive].SaveSectorsCount > 0 && pStxSector->SaveSectorIndex >= 0)
1668: {
1669: pSector_WriteData = STX_SaveStruct[ Drive ].pSaveSectorsStruct[ pStxSector->SaveSectorIndex ].pData;
1670: Sector_ReadTime = 0; /* Standard timings */
1671:
1672: LOG_TRACE(TRACE_FDC, "fdc stx read sector drive=%d track=%d sect=%d side=%d using saved sector=%d\n" ,
1673: Drive, Track, Sector, Side , pStxSector->SaveSectorIndex );
1674: }
1675: else
1676: pSector_WriteData = NULL;
1677:
1678: if ( Sector_ReadTime == 0 ) /* Sector has a standard delay (32 us per byte) */
1679: Sector_ReadTime = 32 * pStxSector->SectorSize; /* Use the real standard value instead of 0 */
1680: Sector_ReadTime *= 8; /* Convert delay in us to a number of FDC cycles at 8 MHz */
1681:
1682: Total_prev = 0;
1683: for ( i=0 ; i<pStxSector->SectorSize ; i++ )
1684: {
1685: /* Get the value of each byte, with possible fuzzy bits */
1686: if ( pSector_WriteData == NULL ) /* Use original STX content */
1687: {
1688: Byte = pStxSector->pData[ i ];
1689: if ( pStxSector->pFuzzyData )
1690: Byte = ( Byte & pStxSector->pFuzzyData[ i ] ) | ( rand() & ~pStxSector->pFuzzyData[ i ] );
1691: }
1692:
1693: else /* Use data from 'write sector' */
1694: Byte = pSector_WriteData[ i ];
1695:
1696: /* Compute the timing in FDC cycles to transfer this byte */
1697: if ( ( pStxSector->pTimingData ) /* Specific timing for each block of 16 bytes */
1698: && ( pSector_WriteData == NULL ) )
1699: {
1700: Timing = ( pStxSector->pTimingData[ ( i>>4 ) * 2 ] << 8 )
1701: + pStxSector->pTimingData[ ( i>>4 ) * 2 + 1 ]; /* Get big endian timing for this block of 16 bytes */
1702:
1703: /* [NP] Formula to convert timing data comes from Pasti.prg 0.4b : */
1704: /* 1 unit of timing = 32 FDC cycles at 8 MHz + 28 cycles to complete each block of 16 bytes */
1705: Timing = Timing * 32 + 28;
1706:
1707: if ( i % 16 == 0 ) Total_prev = 0; /* New block of 16 bytes */
1708: Total_cur = ( (double)Timing * ( ( i % 16 ) + 1 ) ) / 16;
1709: Timing = rint ( Total_cur - Total_prev );
1710: Total_prev += Timing;
1711: }
1712: else /* Specific timing in us for the whole sector */
1713: {
1714: Total_cur = ( (double)Sector_ReadTime * ( i+1 ) ) / pStxSector->SectorSize;
1715: Timing = rint ( Total_cur - Total_prev );
1716: Total_prev += Timing;
1717: }
1718:
1719: /* Add the Byte to the buffer, Timing should be a number of FDC cycles at 8 MHz */
1720: FDC_Buffer_Add_Timing ( Byte , Timing );
1721: }
1722:
1723: /* Return only bits 3 and 5 of the FDC_Status */
1724: return pStxSector->FDC_Status & ( STX_SECTOR_FLAG_CRC | STX_SECTOR_FLAG_RECORD_TYPE );
1725: }
1726:
1727:
1728: /*-----------------------------------------------------------------------*/
1729: /**
1730: * Write a sector to a floppy image in STX format (used in type II command)
1731: *
1732: * STX format doesn't support write command. For each 'write sector' we
1733: * store the sector data in a dedicated buffer STX_SaveStruct[].pSaveSectorsStruct.
1734: * When the sector is read later, we return the data from STX_SaveStruct[].pSaveSectorsStruct
1735: * instead of returning the data from the original STX file.
1736: *
1737: * We only allow writing for sectors whose ID field has a correct CRC and
1738: * where RNF is not set.
1739: * Any valid size can be written : 128, 256, 512 or 1024 bytes
1740: *
1741: * NOTE : data will saved in memory snapshot, as well as in an additional
1742: * file with the extension .wd1772.
1743: *
1744: * Return RNF if sector was not found or CRC if ID field has a CRC error.
1745: * Return 0 if OK.
1746: */
1.1.1.2 ! root 1747: Uint8 FDC_WriteSector_STX ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side , int SectorSize )
1.1 root 1748: {
1749: STX_SECTOR_STRUCT *pStxSector;
1750: int i;
1751: Uint8 *pSector_WriteData;
1752: void *pNewBuf;
1753: STX_SAVE_SECTOR_STRUCT *pStxSaveSector;
1754:
1755: pStxSector = STX_FindSector ( Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1756: if ( pStxSector == NULL )
1757: {
1758: fprintf ( stderr , "FDC_WriteSector_STX drive=%d track=%d side=%d sector=%d returns null !\n" ,
1759: Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1760: return STX_SECTOR_FLAG_RNF; /* Should not happen if FDC_NextSectorID_FdcCycles_STX succeeded before */
1761: }
1762:
1763: /* If RNF is set, return FDC_STR_BIT_RNF */
1764: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF )
1765: return STX_SECTOR_FLAG_RNF; /* RNF in FDC's status register */
1766:
1767: /* If CRC is set, return FDC_STR_BIT_RNF */
1768: if ( pStxSector->FDC_Status & STX_SECTOR_FLAG_CRC )
1769: return STX_SECTOR_FLAG_CRC; /* CRC in FDC's status register */
1770:
1771:
1772: /* Check if this sector was already changed by a 'write sector' command */
1773: /* If so, we use the same buffer. Else we alloc a new buffer for this sector */
1774: if ( pStxSector->SaveSectorIndex < 0 )
1775: {
1776: //fprintf ( stderr , "realloc\n" );
1777: /* Increase save buffer by 1 */
1778: pNewBuf = realloc ( STX_SaveStruct[ Drive ].pSaveSectorsStruct ,
1779: ( STX_SaveStruct[ Drive ].SaveSectorsCount + 1 ) * sizeof ( STX_SAVE_SECTOR_STRUCT ) );
1780: if ( pNewBuf == NULL )
1781: {
1782: fprintf ( stderr , "FDC_WriteSector_STX drive=%d track=%d side=%d sector=%d realloc error !\n" ,
1783: Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1784: return STX_SECTOR_FLAG_RNF;
1785: }
1786:
1787: /* Save the new buffer values */
1788: STX_SaveStruct[ Drive ].pSaveSectorsStruct = (STX_SAVE_SECTOR_STRUCT *) pNewBuf;;
1789: STX_SaveStruct[ Drive ].SaveSectorsCount++;
1790:
1791: /* Create the new entry in pSaveSectorsStruct */
1792: pNewBuf = malloc ( SectorSize );
1793: if ( pNewBuf == NULL )
1794: {
1795: fprintf ( stderr , "FDC_WriteSector_STX drive=%d track=%d side=%d sector=%d malloc error !\n" ,
1796: Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1797: return STX_SECTOR_FLAG_RNF;
1798: }
1799:
1800: pStxSector->SaveSectorIndex = STX_SaveStruct[ Drive ].SaveSectorsCount - 1;
1801:
1802: /* Fill the new SaveSectorStruct. We copy some of the original sector's values */
1803: /* in the saved sector */
1804: pStxSaveSector = &STX_SaveStruct[ Drive ].pSaveSectorsStruct[ pStxSector->SaveSectorIndex ];
1805:
1806: pStxSaveSector->Track = Track;
1807: pStxSaveSector->Side = Side;
1808: pStxSaveSector->BitPosition = pStxSector->BitPosition;
1809: pStxSaveSector->ID_Track = pStxSector->ID_Track;
1810: pStxSaveSector->ID_Head = pStxSector->ID_Head;
1811: pStxSaveSector->ID_Sector = pStxSector->ID_Sector;
1812: pStxSaveSector->ID_Size = pStxSector->ID_Size;
1813: pStxSaveSector->ID_CRC = pStxSector->ID_CRC;
1814:
1815: pStxSaveSector->SectorSize = SectorSize;
1816: pStxSaveSector->pData = (Uint8 *) pNewBuf;
1817:
1818: pStxSaveSector->StructIsUsed = 1;
1819: }
1820:
1821: pSector_WriteData = STX_SaveStruct[ Drive ].pSaveSectorsStruct[ pStxSector->SaveSectorIndex ].pData;
1822:
1823: /* Get the sector's data (ignore timings) */
1824: for ( i=0 ; i<SectorSize ; i++ )
1825: pSector_WriteData[ i ] = FDC_Buffer_Read_Byte_pos ( i );
1826:
1827: //fprintf ( stderr , "write drive=%d track=%d side=%d sector=%d size=%d index=%d\n", Drive, Track, Side, Sector, SectorSize , pStxSector->SaveSectorIndex );
1828: //Str_Dump_Hex_Ascii ( (char *) pSector_WriteData, SectorSize, 16, "" , stderr );
1829:
1830: /* Warn that 'write sector' data will be lost or saved (if zipped or not) */
1831: if ( STX_State.ImageBuffer[ Drive ]->WarnedWriteSector == false )
1832: {
1833: if ( File_DoesFileExtensionMatch ( EmulationDrives[ Drive ].sFileName , ".zip" ) )
1834: Log_AlertDlg ( LOG_INFO , "WARNING : can't save changes made with 'write sector' to an STX disk inside a zip file" );
1835: else
1836: Log_AlertDlg ( LOG_INFO , "Changes made with 'write sector' to an STX disk will be saved into an additional .wd1772 file" );
1837: STX_State.ImageBuffer[ Drive ]->WarnedWriteSector = true;
1838: }
1839:
1840:
1841: /* No error */
1842: EmulationDrives[Drive].bContentsChanged = true;
1843: return 0;
1844: }
1845:
1846:
1847: /*-----------------------------------------------------------------------*/
1848: /**
1849: * Read an address field from a floppy image in STX format (used in type III command)
1850: * We return the address field NextSectorStruct_Nbr, whose value was set
1851: * by the latest call to FDC_NextSectorID_FdcCycles_STX
1852: * Each byte of the ID field is added to the FDC buffer with a default timing
1853: * (32 microsec)
1854: * Return 0 if OK, or a CRC error
1855: */
1.1.1.2 ! root 1856: Uint8 FDC_ReadAddress_STX ( Uint8 Drive , Uint8 Track , Uint8 Sector , Uint8 Side )
1.1 root 1857: {
1858: STX_SECTOR_STRUCT *pStxSector;
1859:
1860: pStxSector = STX_FindSector ( Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1861: if ( pStxSector == NULL )
1862: {
1863: fprintf ( stderr , "FDC_ReadAddress_STX drive=%d track=%d side=%d sector=%d returns null !\n" ,
1864: Drive , Track , Side , STX_State.NextSectorStruct_Nbr );
1865: return STX_SECTOR_FLAG_RNF; /* Should not happen if FDC_NextSectorID_FdcCycles_STX succeeded before */
1866: }
1867:
1868: FDC_Buffer_Add ( pStxSector->ID_Track );
1869: FDC_Buffer_Add ( pStxSector->ID_Head );
1870: FDC_Buffer_Add ( pStxSector->ID_Sector );
1871: FDC_Buffer_Add ( pStxSector->ID_Size );
1872: FDC_Buffer_Add ( pStxSector->ID_CRC >> 8 );
1873: FDC_Buffer_Add ( pStxSector->ID_CRC & 0xff );
1874:
1875: /* If RNF is set and CRC error is set, then this ID field has a CRC error */
1876: if ( ( pStxSector->FDC_Status & STX_SECTOR_FLAG_RNF ) && ( pStxSector->FDC_Status & STX_SECTOR_FLAG_CRC ) )
1877: return STX_SECTOR_FLAG_CRC;
1878:
1879: return 0; /* No error */
1880: }
1881:
1882:
1883: /*-----------------------------------------------------------------------*/
1884: /**
1885: * Read a track from a floppy image in STX format (used in type III command)
1886: * This function is called after an index pulse was encountered, and it will
1887: * always succeeds and fill the track buffer.
1888: * If the Track/Side infos exist in the STX image, then the corresponding
1889: * bytes from the track's image are returned.
1890: * If these Track/Side infos don't exist, we return some random bytes
1891: * (empty / not formatted track).
1892: * If the Track/Side infos exist but there's no track's image, then we build
1893: * a standard track by using the available sectors and standard GAP values.
1894: * Return 0 if OK
1895: */
1.1.1.2 ! root 1896: Uint8 FDC_ReadTrack_STX ( Uint8 Drive , Uint8 Track , Uint8 Side )
1.1 root 1897: {
1898: STX_TRACK_STRUCT *pStxTrack;
1899: STX_SECTOR_STRUCT *pStxSector;
1900: int i;
1901: Uint16 Timing;
1902: Uint32 Track_ReadTime;
1903: double Total_cur; /* To compute closest integer timings for each byte */
1904: double Total_prev;
1905: int TrackSize;
1906: int Sector;
1907: int SectorSize;
1908: Uint16 CRC;
1909: Uint8 *pData;
1910: Uint8 Byte;
1911:
1912: if ( STX_State.ImageBuffer[ Drive ] == NULL )
1913: {
1914: fprintf ( stderr , "FDC_ReadTrack_STX drive=%d track=%d side=%d, no image buffer !\n" , Drive , Track , Side );
1915: return STX_SECTOR_FLAG_RNF; /* Should not happen, just in case of a bug */
1916: }
1917:
1918: pStxTrack = STX_FindTrack ( Drive , Track , Side );
1919: if ( pStxTrack == NULL ) /* Track/Side don't exist in this STX image */
1920: {
1921: fprintf ( stderr , "fdc stx : track info not found for read track drive=%d track=%d side=%d, returning random bytes\n" , Drive , Track , Side );
1922: for ( i=0 ; i<FDC_GetBytesPerTrack ( Drive ) ; i++ )
1923: FDC_Buffer_Add ( rand() & 0xff ); /* Fill the track buffer with random bytes */
1924: return 0;
1925: }
1926:
1927: /* If the Track block contains a complete dump of the track image, use it directly */
1928: /* The timing for each byte is the average timing based on TrackImageSize */
1929: if ( pStxTrack->pTrackImageData )
1930: {
1931: Track_ReadTime = 8000000 / 5; /* 300 RPM, gives 5 RPS and 1600000 cycles per revolution at 8 MHz */
1932: Total_prev = 0;
1933: for ( i=0 ; i<pStxTrack->TrackImageSize ; i++ )
1934: {
1935: Total_cur = ( (double)Track_ReadTime * ( i+1 ) ) / pStxTrack->TrackImageSize;
1936: Timing = rint ( Total_cur - Total_prev );
1937: Total_prev += Timing;
1938: /* Add each byte to the buffer, Timing should be a number of FDC cycles at 8 MHz */
1939: FDC_Buffer_Add_Timing ( pStxTrack->pTrackImageData[ i ] , Timing );
1940: }
1941: }
1942:
1943: /* If the track block doesn't contain a dump of the track image, we must build a track */
1944: /* using the sector blocks and some standard GAP values */
1945: /* [NP] NOTE : we build a track of pStxTrack->MFMSize bytes, as this seems to always be != 0 */
1946: /* even for empty / not formatted track */
1947: /* [NP] NOTE : instead of using standard GAP values, we could compute GAP based on pStxSector->BitPosition */
1948: /* but this seems unnecessary, as a track image would certainly be present if precise GAP values */
1949: /* were required */
1950: else
1951: {
1952: TrackSize = pStxTrack->MFMSize;
1953: if ( ( pStxTrack->Flags & STX_TRACK_FLAG_SECTOR_BLOCK ) == 0 )
1954: TrackSize /= 8; /* When the track contains only sector data, MFMSize is in bits */
1955:
1956: /* If there's no image for this track, and no sector as well, then track is empty / not formatted */
1957: if ( pStxTrack->SectorsCount == 0 )
1958: {
1959: 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 );
1960: for ( i=0 ; i<TrackSize ; i++ )
1961: FDC_Buffer_Add ( rand() & 0xff ); /* Fill the track buffer with random bytes */
1962: return 0;
1963: }
1964:
1965: /* Use the available sectors and add some default GAPs to build the track */
1966: fprintf ( stderr , "fdc stx : no track image for read track drive=%d track=%d side=%d, building a standard track\n" , Drive , Track , Side );
1967:
1968: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP1 ; i++ ) /* GAP1 */
1969: FDC_Buffer_Add ( 0x4e );
1970:
1971: for ( Sector=0 ; Sector < pStxTrack->SectorsCount ; Sector++ )
1972: {
1973: pStxSector = &(pStxTrack->pSectorsStruct[ Sector ]);
1974: SectorSize = pStxSector->SectorSize;
1975:
1976: /* Check that the data+GAPs for this sector will not be above track's length */
1977: /* (in case we build a track with a high / non standard number of sectors) */
1978: if ( FDC_Buffer_Get_Size () + SectorSize + FDC_TRACK_LAYOUT_STANDARD_GAP2 + 10 + FDC_TRACK_LAYOUT_STANDARD_GAP3a
1979: + FDC_TRACK_LAYOUT_STANDARD_GAP3b + 4 + 2 + FDC_TRACK_LAYOUT_STANDARD_GAP4 >= TrackSize )
1980: {
1981: 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 );
1982: break; /* Exit the loop and fill the rest of the track */
1983: }
1984:
1985: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP2 ; i++ ) /* GAP2 */
1986: FDC_Buffer_Add ( 0x00 );
1987:
1988: /* Add the ID field for the sector */
1989: for ( i=0 ; i<3 ; i++ )
1990: FDC_Buffer_Add ( 0xa1 ); /* SYNC (write $F5) */
1991: FDC_Buffer_Add ( 0xfe ); /* Index Address Mark */
1992: FDC_Buffer_Add ( pStxSector->ID_Track );
1993: FDC_Buffer_Add ( pStxSector->ID_Head );
1994: FDC_Buffer_Add ( pStxSector->ID_Sector );
1995: FDC_Buffer_Add ( pStxSector->ID_Size );
1996: FDC_Buffer_Add ( pStxSector->ID_CRC >> 8 );
1997: FDC_Buffer_Add ( pStxSector->ID_CRC & 0xff );
1998:
1999: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP3a ; i++ ) /* GAP3a */
2000: FDC_Buffer_Add ( 0x4e );
2001: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP3b ; i++ ) /* GAP3b */
2002: FDC_Buffer_Add ( 0x00 );
2003:
2004: /* Add the data for the sector + build the CRC */
2005: crc16_reset ( &CRC );
2006: for ( i=0 ; i<3 ; i++ )
2007: {
2008: FDC_Buffer_Add ( 0xa1 ); /* SYNC (write $F5) */
2009: crc16_add_byte ( &CRC , 0xa1 );
2010: }
2011:
2012: FDC_Buffer_Add ( 0xfb ); /* Data Address Mark */
2013: crc16_add_byte ( &CRC , 0xfb );
2014:
2015: /* [NP] NOTE : when building the sector, we assume there's no specific timing or fuzzy bytes */
2016: /* If it was not the case, there would certainly be a real track image (and STX format doesn't */
2017: /* support fuzzy bytes or specific timing for a track image anyway) */
2018: /* If the sector was changed by a 'write sector' command, we use the data from pSaveSectorsStruct */
2019: if ( pStxSector->SaveSectorIndex < 0 ) /* Use original data from the STX */
2020: pData = pStxSector->pData;
2021: else /* Use data from the 'write sector' */
2022: pData = STX_SaveStruct[ Drive ].pSaveSectorsStruct[ pStxSector->SaveSectorIndex ].pData;
2023:
2024: for ( i=0 ; i<SectorSize ; i++ )
2025: {
2026: Byte = pData[ i ];
2027: FDC_Buffer_Add ( Byte );
2028: crc16_add_byte ( &CRC , Byte );
2029: }
2030:
2031: FDC_Buffer_Add ( CRC >> 8 ); /* CRC1 (write $F7) */
2032: FDC_Buffer_Add ( CRC & 0xff ); /* CRC2 */
2033:
2034: for ( i=0 ; i<FDC_TRACK_LAYOUT_STANDARD_GAP4 ; i++ ) /* GAP4 */
2035: FDC_Buffer_Add ( 0x4e );
2036: }
2037:
2038: while ( FDC_Buffer_Get_Size () < TrackSize ) /* Complete the track buffer */
2039: FDC_Buffer_Add ( 0x4e ); /* GAP5 */
2040: }
2041:
2042: return 0; /* No error */
2043: }
2044:
2045:
2046: /*-----------------------------------------------------------------------*/
2047: /**
2048: * Write a track to a floppy image in STX format (used in type III command)
2049: *
2050: * STX format doesn't support write command. For each 'write track' we
2051: * store the track data in a dedicated buffer STX_SaveStruct[].pSaveTracksStruct.
2052: * When the track is read later, we return the data from STX_SaveStruct[].pSaveTracksStruct
2053: * instead of returning the data from the original STX file.
2054: *
2055: * NOTE : data will saved in memory snapshot, as well as in an additional
2056: * file with the extension .wd1772.
2057: *
2058: * Return 0 if track was written without error, or LOST_DATA if an error occurred
2059: */
1.1.1.2 ! root 2060: Uint8 FDC_WriteTrack_STX ( Uint8 Drive , Uint8 Track , Uint8 Side , int TrackSize )
1.1 root 2061: {
2062: STX_TRACK_STRUCT *pStxTrack;
2063: int i;
2064: Uint8 *pTrack_DataWrite;
2065: void *pNewBuf;
2066: STX_SAVE_TRACK_STRUCT *pStxSaveTrack;
2067: int Sector;
2068:
2069: pStxTrack = STX_FindTrack ( Drive , Track , Side );
2070: if ( pStxTrack == NULL )
2071: {
2072: fprintf ( stderr , "FDC_WriteTrack_STX drive=%d track=%d side=%d returns null !\n" ,
2073: Drive , Track , Side );
2074: return STX_SECTOR_FLAG_LOST_DATA;
2075: }
2076:
2077: /* Check if this track was already changed by a 'write track' command */
2078: /* If so, we use the same structure. Else we alloc a new structure for this track */
2079: if ( pStxTrack->SaveTrackIndex < 0 )
2080: {
2081: //fprintf ( stderr , "realloc\n" );
2082: /* Increase save buffer by 1 */
2083: pNewBuf = realloc ( STX_SaveStruct[ Drive ].pSaveTracksStruct ,
2084: ( STX_SaveStruct[ Drive ].SaveTracksCount + 1 ) * sizeof ( STX_SAVE_TRACK_STRUCT ) );
2085: if ( pNewBuf == NULL )
2086: {
2087: fprintf ( stderr , "FDC_WriteTrack_STX drive=%d track=%d side=%d realloc error !\n" ,
2088: Drive , Track , Side );
2089: return STX_SECTOR_FLAG_LOST_DATA;
2090: }
2091:
2092: /* Save the new buffer values */
2093: STX_SaveStruct[ Drive ].pSaveTracksStruct = (STX_SAVE_TRACK_STRUCT *) pNewBuf;;
2094: STX_SaveStruct[ Drive ].SaveTracksCount++;
2095:
2096: pStxTrack->SaveTrackIndex = STX_SaveStruct[ Drive ].SaveTracksCount - 1;
2097: }
2098:
2099: /* Use the same structure : free previous DataWrite buffer */
2100: else
2101: {
2102: free ( STX_SaveStruct[ Drive ].pSaveTracksStruct[ pStxTrack->SaveTrackIndex ].pDataWrite );
2103: STX_SaveStruct[ Drive ].pSaveTracksStruct[ pStxTrack->SaveTrackIndex ].pDataWrite = NULL;
2104: /* TODO : also free pDataRead */
2105: }
2106:
2107: /* Create the new DataWrite buffer in pSaveTracksStruct */
2108: pNewBuf = malloc ( TrackSize );
2109: if ( pNewBuf == NULL )
2110: {
2111: fprintf ( stderr , "FDC_WriteTrack_STX drive=%d track=%d side=%d malloc error !\n" ,
2112: Drive , Track , Side );
2113: return STX_SECTOR_FLAG_LOST_DATA;
2114: }
2115:
2116: /* Fill the new SaveTrackStruct */
2117: pStxSaveTrack = &STX_SaveStruct[ Drive ].pSaveTracksStruct[ pStxTrack->SaveTrackIndex ];
2118:
2119: pStxSaveTrack->Track = Track;
2120: pStxSaveTrack->Side = Side;
2121:
2122: pStxSaveTrack->TrackSizeWrite = TrackSize;
2123: pStxSaveTrack->pDataWrite = (Uint8 *) pNewBuf;
2124:
2125:
2126: /* Get the track's data (ignore timings) */
2127: pTrack_DataWrite = STX_SaveStruct[ Drive ].pSaveTracksStruct[ pStxTrack->SaveTrackIndex ].pDataWrite;
2128:
2129: for ( i=0 ; i<pStxSaveTrack->TrackSizeWrite ; i++ )
2130: pTrack_DataWrite[ i ] = FDC_Buffer_Read_Byte_pos ( i );
2131:
2132: //fprintf ( stderr , "write drive=%d track=%d side=%d size=%d index=%d\n", Drive, Track, Side, pStxSaveTrack->TrackSizeWrite , pStxTrack->SaveTrackIndex );
2133: //Str_Dump_Hex_Ascii ( (char *) pTrack_DataWrite, pStxSaveTrack->TrackSizeWrite, 16, "" , stderr );
2134:
2135: // TODO : convert pDataWrite into pDataRead
2136: pStxSaveTrack->TrackSizeRead = 0; /* TODO : compute interpreted track */
2137: pStxSaveTrack->pDataRead = NULL; /* TODO : compute interpreted track */
2138:
2139:
2140: /* If some sectors were already saved for that track, we must remove them */
2141: /* as the 'write track' takes precedence over the previous 'write sector' */
2142: for ( Sector=0 ; Sector < pStxTrack->SectorsCount ; Sector++ )
2143: {
2144: if ( pStxTrack->pSectorsStruct[ Sector ].SaveSectorIndex >= 0 )
2145: {
2146: STX_FreeSaveSectorsStruct ( STX_SaveStruct[ Drive ].pSaveSectorsStruct ,
2147: pStxTrack->pSectorsStruct[ Sector ].SaveSectorIndex );
2148: pStxTrack->pSectorsStruct[ Sector ].SaveSectorIndex = -1;
2149: }
2150: }
2151:
2152:
2153: /* Warn that 'write track' data will be lost or saved (if zipped or not) */
2154: if ( STX_State.ImageBuffer[ Drive ]->WarnedWriteTrack == false )
2155: {
2156: if ( File_DoesFileExtensionMatch ( EmulationDrives[ Drive ].sFileName , ".zip" ) )
2157: Log_AlertDlg ( LOG_INFO , "WARNING : can't save changes made with 'write track' to an STX disk inside a zip file" );
2158: else
2159: Log_AlertDlg ( LOG_INFO , "Changes made with 'write track' to an STX disk will be saved into an additional .wd1772 file" );
2160: STX_State.ImageBuffer[ Drive ]->WarnedWriteTrack = true;
2161: }
2162:
2163:
2164: /* No error */
2165: EmulationDrives[Drive].bContentsChanged = true;
2166: return 0;
2167: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.