Annotation of hatari/src/floppy_stx.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.