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