Annotation of hatari/src/floppy_stx.c, revision 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.