2006-02-25 20:50:29 +00:00
/*
AppleWin : An Apple //e emulator for Windows
Copyright ( C ) 1994 - 1996 , Michael O ' Brien
Copyright ( C ) 1999 - 2001 , Oliver Schmidt
Copyright ( C ) 2002 - 2005 , Tom Charlesworth
2015-09-13 10:39:58 +00:00
Copyright ( C ) 2006 - 2015 , Tom Charlesworth , Michael Pohoreski , Nick Westgate
2006-02-25 20:50:29 +00:00
AppleWin is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
AppleWin is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with AppleWin ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
/* Description: Disk
*
* Author : Various
2015-09-13 10:39:58 +00:00
*
2017-05-14 10:33:07 +00:00
* In comments , UTAIIe is an abbreviation for a reference to " Understanding the Apple //e " by James Sather
2006-02-25 20:50:29 +00:00
*/
# include "StdAfx.h"
2014-08-13 20:30:35 +00:00
2015-02-13 22:40:53 +00:00
# include "SaveState_Structs_v1.h"
2014-08-13 20:30:35 +00:00
# include "AppleWin.h"
2018-01-14 18:01:22 +00:00
# include "CPU.h"
2014-08-13 20:30:35 +00:00
# include "Disk.h"
2018-01-14 18:01:22 +00:00
# include "DiskLog.h"
# include "DiskFormatTrack.h"
2010-01-03 18:43:08 +00:00
# include "DiskImage.h"
2014-08-13 20:30:35 +00:00
# include "Frame.h"
2015-09-13 10:39:58 +00:00
# include "Log.h"
2014-08-13 20:30:35 +00:00
# include "Memory.h"
# include "Registry.h"
# include "Video.h"
2015-12-05 16:50:27 +00:00
# include "YamlHelper.h"
2014-08-13 20:30:35 +00:00
2007-05-28 11:16:42 +00:00
# include "..\resource\resource.h"
2018-01-14 18:01:22 +00:00
# if LOG_DISK_NIBBLES_USE_RUNTIME_VAR
static bool g_bLogDisk_NibblesRW = false ; // From VS Debugger, change this to true/false during runtime for precise nibble logging
2007-04-04 21:28:10 +00:00
# endif
2007-03-23 22:26:35 +00:00
2006-02-26 02:02:57 +00:00
// Public _________________________________________________________________________________________
2018-01-14 18:01:22 +00:00
BOOL enhancedisk = 1 ; // TODO: Make static & add accessor funcs
2010-01-03 18:43:08 +00:00
2006-02-26 02:02:57 +00:00
// Private ________________________________________________________________________________________
2009-02-24 22:13:46 +00:00
static WORD currdrive = 0 ;
2010-01-03 18:43:08 +00:00
static Disk_t g_aFloppyDisk [ NUM_DRIVES ] ;
2009-02-24 22:13:46 +00:00
static BYTE floppylatch = 0 ;
static BOOL floppymotoron = 0 ;
2015-09-13 10:39:58 +00:00
static BOOL floppyloadmode = 0 ; // for efficiency this is not used; it's extremely unlikely to affect emulation (nickw)
2009-02-24 22:13:46 +00:00
static BOOL floppywritemode = 0 ;
2017-03-08 10:13:56 +00:00
static WORD phases = 0 ; // state bits for stepper magnet phases 0 - 3
2010-01-03 18:43:08 +00:00
static bool g_bSaveDiskImage = true ; // Save the DiskImage name to Registry
2015-02-13 22:40:53 +00:00
static UINT g_uSlot = 0 ;
2018-01-14 18:01:22 +00:00
static unsigned __int64 g_uDiskLastCycle = 0 ;
static FormatTrack g_formatTrack ;
2006-02-25 20:50:29 +00:00
2018-01-14 18:01:22 +00:00
static void CheckSpinning ( const ULONG nCyclesLeft ) ;
2006-02-28 18:37:47 +00:00
static Disk_Status_e GetDriveLightStatus ( const int iDrive ) ;
static bool IsDriveValid ( const int iDrive ) ;
2006-02-25 20:50:29 +00:00
static void ReadTrack ( int drive ) ;
static void RemoveDisk ( int drive ) ;
static void WriteTrack ( int drive ) ;
2015-04-11 21:24:54 +00:00
static LPCTSTR DiskGetFullPathName ( const int iDrive ) ;
2006-02-25 20:50:29 +00:00
2017-08-11 21:01:47 +00:00
# define SPINNING_CYCLES (20000*64) // 1280000 cycles = 1.25s
# define WRITELIGHT_CYCLES (20000*64) // 1280000 cycles = 1.25s
2008-08-31 04:31:35 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
2013-11-02 21:24:45 +00:00
int DiskGetCurrentDrive ( void ) { return currdrive ; }
int DiskGetCurrentTrack ( void ) { return g_aFloppyDisk [ currdrive ] . track ; }
int DiskGetCurrentPhase ( void ) { return g_aFloppyDisk [ currdrive ] . phase ; }
int DiskGetCurrentOffset ( void ) { return g_aFloppyDisk [ currdrive ] . byte ; }
2014-07-22 01:21:31 +00:00
int DiskGetTrack ( int drive ) { return g_aFloppyDisk [ drive ] . track ; }
2013-11-02 21:24:45 +00:00
2015-02-13 22:40:53 +00:00
const char * DiskGetDiskPathFilename ( const int iDrive )
2013-12-06 21:10:41 +00:00
{
2015-02-13 22:40:53 +00:00
return g_aFloppyDisk [ iDrive ] . fullname ;
2013-12-06 21:10:41 +00:00
}
2013-11-02 21:24:45 +00:00
char * DiskGetCurrentState ( void )
{
if ( g_aFloppyDisk [ currdrive ] . imagehandle = = NULL )
return " Empty " ;
if ( ! floppymotoron )
{
if ( g_aFloppyDisk [ currdrive ] . spinning > 0 )
return " Off (spinning) " ;
else
return " Off " ;
}
else if ( floppywritemode )
{
if ( g_aFloppyDisk [ currdrive ] . bWriteProtected )
return " Writing (write protected) " ;
2015-09-13 10:39:58 +00:00
else
return " Writing " ;
2013-11-02 21:24:45 +00:00
}
else
{
2015-09-13 10:39:58 +00:00
/*if (floppyloadmode)
{
if ( g_aFloppyDisk [ currdrive ] . bWriteProtected )
return " Reading write protect state (write protected) " ;
else
return " Reading write protect state (not write protected) " ;
}
else */
return " Reading " ;
2013-11-02 21:24:45 +00:00
}
}
//===========================================================================
2015-02-13 22:40:53 +00:00
void Disk_LoadLastDiskImage ( const int iDrive )
2008-08-31 04:31:35 +00:00
{
2013-12-06 21:10:41 +00:00
_ASSERT ( iDrive = = DRIVE_1 | | iDrive = = DRIVE_2 ) ;
2008-08-31 04:31:35 +00:00
char sFilePath [ MAX_PATH + 1 ] ;
sFilePath [ 0 ] = 0 ;
2010-01-17 18:43:06 +00:00
char * pRegKey = ( iDrive = = DRIVE_1 )
2008-08-31 04:31:35 +00:00
? REGVALUE_PREF_LAST_DISK_1
: REGVALUE_PREF_LAST_DISK_2 ;
2009-05-29 21:39:13 +00:00
2015-02-13 22:40:53 +00:00
if ( RegLoadString ( TEXT ( REG_PREFS ) , pRegKey , 1 , sFilePath , MAX_PATH ) )
2008-08-31 04:31:35 +00:00
{
sFilePath [ MAX_PATH ] = 0 ;
2010-01-03 18:43:08 +00:00
g_bSaveDiskImage = false ;
2009-05-29 21:39:13 +00:00
// Pass in ptr to local copy of filepath, since RemoveDisk() sets DiskPathFilename = ""
2010-01-03 18:43:08 +00:00
DiskInsert ( iDrive , sFilePath , IMAGE_USE_FILES_WRITE_PROTECT_STATUS , IMAGE_DONT_CREATE ) ;
g_bSaveDiskImage = true ;
2008-08-31 04:31:35 +00:00
}
}
//===========================================================================
2010-01-03 18:43:08 +00:00
void Disk_SaveLastDiskImage ( const int iDrive )
2008-08-31 04:31:35 +00:00
{
2013-12-06 21:10:41 +00:00
_ASSERT ( iDrive = = DRIVE_1 | | iDrive = = DRIVE_2 ) ;
2008-08-31 04:31:35 +00:00
2013-12-06 21:10:41 +00:00
if ( ! g_bSaveDiskImage )
return ;
2015-02-13 22:40:53 +00:00
const char * pFileName = g_aFloppyDisk [ iDrive ] . fullname ;
2013-12-06 21:10:41 +00:00
if ( iDrive = = DRIVE_1 )
RegSaveString ( TEXT ( REG_PREFS ) , REGVALUE_PREF_LAST_DISK_1 , TRUE , pFileName ) ;
else
RegSaveString ( TEXT ( REG_PREFS ) , REGVALUE_PREF_LAST_DISK_2 , TRUE , pFileName ) ;
2015-04-11 21:24:54 +00:00
//
char szPathName [ MAX_PATH ] ;
strcpy ( szPathName , DiskGetFullPathName ( iDrive ) ) ;
if ( _tcsrchr ( szPathName , TEXT ( ' \\ ' ) ) )
{
char * pPathEnd = _tcsrchr ( szPathName , TEXT ( ' \\ ' ) ) + 1 ;
* pPathEnd = 0 ;
RegSaveString ( TEXT ( REG_PREFS ) , TEXT ( REGVALUE_PREF_START_DIR ) , 1 , szPathName ) ;
}
2008-08-31 04:31:35 +00:00
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
2018-01-14 18:01:22 +00:00
// Called by DiskControlMotor() & DiskEnable()
static void CheckSpinning ( const ULONG nCyclesLeft )
2010-01-03 18:43:08 +00:00
{
DWORD modechange = ( floppymotoron & & ! g_aFloppyDisk [ currdrive ] . spinning ) ;
2014-07-26 20:23:57 +00:00
2010-01-03 18:43:08 +00:00
if ( floppymotoron )
2017-08-11 21:01:47 +00:00
g_aFloppyDisk [ currdrive ] . spinning = SPINNING_CYCLES ;
2014-07-26 20:23:57 +00:00
2010-01-03 18:43:08 +00:00
if ( modechange )
2014-07-24 01:08:52 +00:00
FrameDrawDiskLEDS ( ( HDC ) 0 ) ;
2018-01-14 18:01:22 +00:00
if ( modechange )
{
// Set g_uDiskLastCycle when motor changes: not spinning (ie. off for 1 sec) -> on
CpuCalcCycles ( nCyclesLeft ) ;
g_uDiskLastCycle = g_nCumulativeCycles ;
}
2006-02-25 20:50:29 +00:00
}
2006-02-28 18:37:47 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
static Disk_Status_e GetDriveLightStatus ( const int iDrive )
2006-02-28 18:37:47 +00:00
{
if ( IsDriveValid ( iDrive ) )
{
Disk_t * pFloppy = & g_aFloppyDisk [ iDrive ] ;
if ( pFloppy - > spinning )
{
2010-01-03 18:43:08 +00:00
if ( pFloppy - > bWriteProtected )
2006-02-28 18:37:47 +00:00
return DISK_STATUS_PROT ;
if ( pFloppy - > writelight )
return DISK_STATUS_WRITE ;
else
return DISK_STATUS_READ ;
}
else
return DISK_STATUS_OFF ;
}
return DISK_STATUS_OFF ;
}
2006-02-26 02:02:57 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
static bool IsDriveValid ( const int iDrive )
{
return ( iDrive > = 0 & & iDrive < NUM_DRIVES ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
static void AllocTrack ( const int iDrive )
2006-02-25 20:50:29 +00:00
{
2014-07-26 20:23:57 +00:00
Disk_t * fptr = & g_aFloppyDisk [ iDrive ] ;
fptr - > trackimage = ( LPBYTE ) VirtualAlloc ( NULL , NIBBLES_PER_TRACK , MEM_COMMIT , PAGE_READWRITE ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
static void ReadTrack ( const int iDrive )
2006-02-26 02:02:57 +00:00
{
if ( ! IsDriveValid ( iDrive ) )
return ;
Disk_t * pFloppy = & g_aFloppyDisk [ iDrive ] ;
2009-05-29 21:39:13 +00:00
if ( pFloppy - > track > = ImageGetNumTracks ( pFloppy - > imagehandle ) )
2006-02-26 02:02:57 +00:00
{
pFloppy - > trackimagedata = 0 ;
return ;
}
if ( ! pFloppy - > trackimage )
AllocTrack ( iDrive ) ;
if ( pFloppy - > trackimage & & pFloppy - > imagehandle )
{
2015-09-13 10:39:58 +00:00
# if LOG_DISK_TRACKS
LOG_DISK ( " track $%02X%s read \r \n " , pFloppy - > track , ( pFloppy - > phase & 1 ) ? " .5 " : " " ) ;
# endif
2006-02-26 02:02:57 +00:00
ImageReadTrack (
pFloppy - > imagehandle ,
pFloppy - > track ,
pFloppy - > phase ,
pFloppy - > trackimage ,
& pFloppy - > nibbles ) ;
pFloppy - > byte = 0 ;
pFloppy - > trackimagedata = ( pFloppy - > nibbles ! = 0 ) ;
}
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2017-10-20 05:49:10 +00:00
void DiskFlushCurrentTrack ( const int iDrive )
{
Disk_t * pFloppy = & g_aFloppyDisk [ iDrive ] ;
if ( pFloppy - > trackimage & & pFloppy - > trackimagedirty )
WriteTrack ( iDrive ) ;
}
//===========================================================================
2010-01-03 18:43:08 +00:00
static void RemoveDisk ( const int iDrive )
2006-02-26 02:02:57 +00:00
{
Disk_t * pFloppy = & g_aFloppyDisk [ iDrive ] ;
if ( pFloppy - > imagehandle )
{
2017-10-20 05:49:10 +00:00
DiskFlushCurrentTrack ( iDrive ) ;
2006-02-26 02:02:57 +00:00
ImageClose ( pFloppy - > imagehandle ) ;
2016-10-25 20:09:48 +00:00
pFloppy - > imagehandle = NULL ;
2006-02-26 02:02:57 +00:00
}
if ( pFloppy - > trackimage )
{
VirtualFree ( pFloppy - > trackimage , 0 , MEM_RELEASE ) ;
pFloppy - > trackimage = NULL ;
pFloppy - > trackimagedata = 0 ;
}
memset ( pFloppy - > imagename , 0 , MAX_DISK_IMAGE_NAME + 1 ) ;
memset ( pFloppy - > fullname , 0 , MAX_DISK_FULL_NAME + 1 ) ;
2010-01-03 18:43:08 +00:00
pFloppy - > strFilenameInZip = " " ;
2008-08-31 04:31:35 +00:00
Disk_SaveLastDiskImage ( iDrive ) ;
Video_ResetScreenshotCounter ( NULL ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
static void WriteTrack ( const int iDrive )
2006-02-26 02:02:57 +00:00
{
Disk_t * pFloppy = & g_aFloppyDisk [ iDrive ] ;
2009-05-29 21:39:13 +00:00
if ( pFloppy - > track > = ImageGetNumTracks ( pFloppy - > imagehandle ) )
2006-02-26 02:02:57 +00:00
return ;
2010-01-03 18:43:08 +00:00
if ( pFloppy - > bWriteProtected )
2006-02-26 02:02:57 +00:00
return ;
if ( pFloppy - > trackimage & & pFloppy - > imagehandle )
2015-09-13 10:39:58 +00:00
{
# if LOG_DISK_TRACKS
LOG_DISK ( " track $%02X%s write \r \n " , pFloppy - > track , ( pFloppy - > phase & 0 ) ? " .5 " : " " ) ; // TODO: hard-coded to whole tracks - see below (nickw)
# endif
2006-02-26 02:02:57 +00:00
ImageWriteTrack (
pFloppy - > imagehandle ,
pFloppy - > track ,
2015-09-13 10:39:58 +00:00
pFloppy - > phase , // TODO: this should never be used; it's the current phase (half-track), not that of the track to be written (nickw)
2006-02-26 02:02:57 +00:00
pFloppy - > trackimage ,
2015-09-13 10:39:58 +00:00
pFloppy - > nibbles ) ;
}
2006-02-26 02:02:57 +00:00
pFloppy - > trackimagedirty = 0 ;
2006-02-25 20:50:29 +00:00
}
//
// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE -----
//
//===========================================================================
2010-01-03 18:43:08 +00:00
void DiskBoot ( void )
{
// THIS FUNCTION RELOADS A PROGRAM IMAGE IF ONE IS LOADED IN DRIVE ONE.
// IF A DISK IMAGE OR NO IMAGE IS LOADED IN DRIVE ONE, IT DOES NOTHING.
if ( g_aFloppyDisk [ 0 ] . imagehandle & & ImageBoot ( g_aFloppyDisk [ 0 ] . imagehandle ) )
floppymotoron = 0 ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2015-09-13 10:39:58 +00:00
static void __stdcall DiskControlMotor ( WORD , WORD address , BYTE , BYTE , ULONG uExecutedCycles )
2010-01-03 18:43:08 +00:00
{
2018-01-14 18:01:22 +00:00
BOOL newState = address & 1 ;
if ( newState ! = floppymotoron ) // motor changed state
g_formatTrack . DriveNotWritingTrack ( ) ;
floppymotoron = newState ;
2018-01-28 12:30:54 +00:00
// NB. Motor off doesn't reset the Command Decoder like reset. (UTAIIe figures 9.7 & 9.8 chip C2)
// - so it doesn't reset this state: floppyloadmode, floppywritemode, phases
2015-09-13 10:39:58 +00:00
# if LOG_DISK_MOTOR
LOG_DISK ( " motor %s \r \n " , ( floppymotoron ) ? " on " : " off " ) ;
# endif
2018-01-14 18:01:22 +00:00
CheckSpinning ( uExecutedCycles ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2015-09-13 10:39:58 +00:00
static void __stdcall DiskControlStepper ( WORD , WORD address , BYTE , BYTE , ULONG uExecutedCycles )
2007-03-23 22:26:35 +00:00
{
2018-01-28 12:21:28 +00:00
Disk_t * fptr = & g_aFloppyDisk [ currdrive ] ;
2018-01-27 17:02:33 +00:00
if ( ! floppymotoron ) // GH#525
{
2018-01-28 12:21:28 +00:00
if ( ! fptr - > spinning )
{
2018-01-27 17:02:33 +00:00
# if LOG_DISK_PHASES
2018-01-28 12:21:28 +00:00
LOG_DISK ( " stepper accessed whilst motor is off and not spinning \r \n " ) ;
# endif
return ;
}
# if LOG_DISK_PHASES
LOG_DISK ( " stepper accessed whilst motor is off, but still spinning \r \n " ) ;
2018-01-27 17:02:33 +00:00
# endif
}
2015-09-13 10:39:58 +00:00
int phase = ( address > > 1 ) & 3 ;
2010-01-03 18:43:08 +00:00
int phase_bit = ( 1 < < phase ) ;
2007-03-23 22:26:35 +00:00
2015-09-13 10:39:58 +00:00
# if 1
2010-01-03 18:43:08 +00:00
// update the magnet states
if ( address & 1 )
{
// phase on
phases | = phase_bit ;
}
else
{
// phase off
phases & = ~ phase_bit ;
}
2007-03-23 22:26:35 +00:00
2010-01-03 18:43:08 +00:00
// check for any stepping effect from a magnet
// - move only when the magnet opposite the cog is off
// - move in the direction of an adjacent magnet if one is on
// - do not move if both adjacent magnets are on
// momentum and timing are not accounted for ... maybe one day!
int direction = 0 ;
if ( phases & ( 1 < < ( ( fptr - > phase + 1 ) & 3 ) ) )
direction + = 1 ;
if ( phases & ( 1 < < ( ( fptr - > phase + 3 ) & 3 ) ) )
direction - = 1 ;
// apply magnet step, if any
if ( direction )
{
fptr - > phase = MAX ( 0 , MIN ( 79 , fptr - > phase + direction ) ) ;
const int nNumTracksInImage = ImageGetNumTracks ( fptr - > imagehandle ) ;
const int newtrack = ( nNumTracksInImage = = 0 ) ? 0
: MIN ( nNumTracksInImage - 1 , fptr - > phase > > 1 ) ; // (round half tracks down)
if ( newtrack ! = fptr - > track )
{
2017-10-20 05:49:10 +00:00
DiskFlushCurrentTrack ( currdrive ) ;
2010-01-03 18:43:08 +00:00
fptr - > track = newtrack ;
fptr - > trackimagedata = 0 ;
2018-01-14 18:01:22 +00:00
g_formatTrack . DriveNotWritingTrack ( ) ;
2010-01-03 18:43:08 +00:00
}
2014-07-24 01:08:52 +00:00
// Feature Request #201 Show track status
// https://github.com/AppleWin/AppleWin/issues/201
FrameDrawDiskStatus ( ( HDC ) 0 ) ;
2010-01-03 18:43:08 +00:00
}
2015-09-13 10:39:58 +00:00
# else
// substitute alternate stepping code here to test
# endif
2018-01-14 18:01:22 +00:00
2015-09-13 10:39:58 +00:00
# if LOG_DISK_PHASES
LOG_DISK ( " track $%02X%s phases %d%d%d%d phase %d %s address $%4X \r \n " ,
fptr - > phase > > 1 ,
( fptr - > phase & 1 ) ? " .5 " : " " ,
( phases > > 3 ) & 1 ,
( phases > > 2 ) & 1 ,
( phases > > 1 ) & 1 ,
( phases > > 0 ) & 1 ,
phase ,
( address & 1 ) ? " on " : " off " ,
address ) ;
2011-05-10 20:26:47 +00:00
# endif
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
void DiskDestroy ( void )
2006-02-26 02:02:57 +00:00
{
2010-01-03 18:43:08 +00:00
g_bSaveDiskImage = false ;
RemoveDisk ( DRIVE_1 ) ;
2008-08-31 04:31:35 +00:00
2010-01-03 18:43:08 +00:00
g_bSaveDiskImage = false ;
RemoveDisk ( DRIVE_2 ) ;
2008-08-31 04:31:35 +00:00
2010-01-03 18:43:08 +00:00
g_bSaveDiskImage = true ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2015-09-13 10:39:58 +00:00
static void __stdcall DiskEnable ( WORD , WORD address , BYTE , BYTE , ULONG uExecutedCycles )
2010-01-03 18:43:08 +00:00
{
currdrive = address & 1 ;
2018-01-14 18:01:22 +00:00
# if LOG_DISK_ENABLE_DRIVE
LOG_DISK ( " enable drive: %d \r \n " , currdrive ) ;
# endif
2010-01-03 18:43:08 +00:00
g_aFloppyDisk [ ! currdrive ] . spinning = 0 ;
g_aFloppyDisk [ ! currdrive ] . writelight = 0 ;
2018-01-14 18:01:22 +00:00
CheckSpinning ( uExecutedCycles ) ;
2010-01-03 18:43:08 +00:00
}
2006-02-26 02:02:57 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
void DiskEject ( const int iDrive )
2006-02-26 02:02:57 +00:00
{
2010-01-03 18:43:08 +00:00
if ( IsDriveValid ( iDrive ) )
2006-02-26 02:02:57 +00:00
{
2010-01-03 18:43:08 +00:00
RemoveDisk ( iDrive ) ;
2006-02-26 02:02:57 +00:00
}
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
// Return the file or zip name
// . Used by Property Sheet Page (Disk)
LPCTSTR DiskGetFullName ( const int iDrive )
{
return g_aFloppyDisk [ iDrive ] . fullname ;
2006-02-25 20:50:29 +00:00
}
2010-01-03 18:43:08 +00:00
// Return the filename
// . Used by Drive Buttons' tooltips
LPCTSTR DiskGetFullDiskFilename ( const int iDrive )
{
if ( ! g_aFloppyDisk [ iDrive ] . strFilenameInZip . empty ( ) )
return g_aFloppyDisk [ iDrive ] . strFilenameInZip . c_str ( ) ;
2006-02-28 18:37:47 +00:00
2010-01-03 18:43:08 +00:00
return DiskGetFullName ( iDrive ) ;
}
2008-06-20 23:47:25 +00:00
2015-02-13 22:40:53 +00:00
static LPCTSTR DiskGetFullPathName ( const int iDrive )
{
return ImageGetPathname ( g_aFloppyDisk [ iDrive ] . imagehandle ) ;
}
2010-01-03 18:43:08 +00:00
// Return the imagename
// . Used by Drive Button's icons & Property Sheet Page (Save snapshot)
LPCTSTR DiskGetBaseName ( const int iDrive )
{
return g_aFloppyDisk [ iDrive ] . imagename ;
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
2010-12-20 23:46:11 +00:00
void DiskGetLightStatus ( Disk_Status_e * pDisk1Status_ , Disk_Status_e * pDisk2Status_ )
2006-02-28 18:37:47 +00:00
{
if ( pDisk1Status_ )
* pDisk1Status_ = GetDriveLightStatus ( 0 ) ;
2014-07-26 20:23:57 +00:00
2006-02-28 18:37:47 +00:00
if ( pDisk2Status_ )
* pDisk2Status_ = GetDriveLightStatus ( 1 ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2007-05-28 11:16:42 +00:00
2010-01-03 18:43:08 +00:00
void DiskInitialize ( void )
2007-05-28 11:16:42 +00:00
{
2010-01-03 18:43:08 +00:00
int loop = NUM_DRIVES ;
2007-05-28 11:16:42 +00:00
while ( loop - - )
2015-12-05 16:50:27 +00:00
ZeroMemory ( & g_aFloppyDisk [ loop ] , sizeof ( Disk_t ) ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2008-06-20 23:47:25 +00:00
2010-01-03 18:43:08 +00:00
ImageError_e DiskInsert ( const int iDrive , LPCTSTR pszImageFilename , const bool bForceWriteProtected , const bool bCreateIfNecessary )
2008-06-20 23:47:25 +00:00
{
2008-08-31 04:31:35 +00:00
Disk_t * fptr = & g_aFloppyDisk [ iDrive ] ;
2008-06-20 23:47:25 +00:00
if ( fptr - > imagehandle )
2008-08-31 04:31:35 +00:00
RemoveDisk ( iDrive ) ;
2008-06-20 23:47:25 +00:00
2011-07-17 20:34:42 +00:00
// Reset the drive's struct, but preserve the physical attributes (bug#18242: Platoon)
// . Changing the disk (in the drive) doesn't affect the drive's head etc.
{
int track = fptr - > track ;
int phase = fptr - > phase ;
ZeroMemory ( fptr , sizeof ( Disk_t ) ) ;
fptr - > track = track ;
fptr - > phase = phase ;
}
2008-06-20 23:47:25 +00:00
2010-01-03 18:43:08 +00:00
const DWORD dwAttributes = GetFileAttributes ( pszImageFilename ) ;
if ( dwAttributes = = INVALID_FILE_ATTRIBUTES )
fptr - > bWriteProtected = false ; // Assume this is a new file to create
else
fptr - > bWriteProtected = bForceWriteProtected ? true : ( dwAttributes & FILE_ATTRIBUTE_READONLY ) ;
2015-02-13 22:40:53 +00:00
// Check if image is being used by the other drive, and if so remove it in order so it can be swapped
{
const char * pszOtherPathname = DiskGetFullPathName ( ! iDrive ) ;
char szCurrentPathname [ MAX_PATH ] ;
DWORD uNameLen = GetFullPathName ( pszImageFilename , MAX_PATH , szCurrentPathname , NULL ) ;
if ( uNameLen = = 0 | | uNameLen > = MAX_PATH )
strcpy_s ( szCurrentPathname , MAX_PATH , pszImageFilename ) ;
if ( ! strcmp ( pszOtherPathname , szCurrentPathname ) )
{
DiskEject ( ! iDrive ) ;
FrameRefreshStatus ( DRAW_LEDS | DRAW_BUTTON_DRIVES ) ;
}
2014-10-01 23:18:46 +00:00
}
2010-01-03 18:43:08 +00:00
ImageError_e Error = ImageOpen ( pszImageFilename ,
2008-06-20 23:47:25 +00:00
& fptr - > imagehandle ,
2010-01-03 18:43:08 +00:00
& fptr - > bWriteProtected ,
bCreateIfNecessary ,
fptr - > strFilenameInZip ) ;
if ( Error = = eIMAGE_ERROR_NONE & & ImageIsMultiFileZip ( fptr - > imagehandle ) )
{
TCHAR szText [ 100 + MAX_PATH ] ;
2018-01-14 18:01:22 +00:00
szText [ sizeof ( szText ) - 1 ] = 0 ;
_snprintf ( szText , sizeof ( szText ) - 1 , " Only the first file in a multi-file zip is supported \n Use disk image '%s' ? " , fptr - > strFilenameInZip . c_str ( ) ) ;
2010-01-03 18:43:08 +00:00
int nRes = MessageBox ( g_hFrameWindow , szText , TEXT ( " Multi-Zip Warning " ) , MB_ICONWARNING | MB_YESNO | MB_SETFOREGROUND ) ;
if ( nRes = = IDNO )
{
RemoveDisk ( iDrive ) ;
Error = eIMAGE_ERROR_REJECTED_MULTI_ZIP ;
}
}
2008-06-20 23:47:25 +00:00
2010-01-03 18:43:08 +00:00
if ( Error = = eIMAGE_ERROR_NONE )
2008-06-20 23:47:25 +00:00
{
2015-02-13 22:40:53 +00:00
GetImageTitle ( pszImageFilename , fptr - > imagename , fptr - > fullname ) ;
Video_ResetScreenshotCounter ( fptr - > imagename ) ;
2008-08-31 04:31:35 +00:00
}
else
{
2015-02-13 22:40:53 +00:00
Video_ResetScreenshotCounter ( NULL ) ;
2008-06-20 23:47:25 +00:00
}
2015-02-13 22:40:53 +00:00
Disk_SaveLastDiskImage ( iDrive ) ;
2008-08-31 04:31:35 +00:00
2010-01-03 18:43:08 +00:00
return Error ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
BOOL DiskIsSpinning ( void )
2006-06-27 02:34:46 +00:00
{
return floppymotoron ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
void DiskNotifyInvalidImage ( const int iDrive , LPCTSTR pszImageFilename , const ImageError_e Error )
2006-02-26 02:02:57 +00:00
{
2010-01-03 18:43:08 +00:00
TCHAR szBuffer [ MAX_PATH + 128 ] ;
2018-01-14 18:01:22 +00:00
szBuffer [ sizeof ( szBuffer ) - 1 ] = 0 ;
2006-02-26 02:02:57 +00:00
2010-01-03 18:43:08 +00:00
switch ( Error )
2006-06-27 02:34:46 +00:00
{
2010-01-03 18:43:08 +00:00
case eIMAGE_ERROR_UNABLE_TO_OPEN :
case eIMAGE_ERROR_UNABLE_TO_OPEN_GZ :
case eIMAGE_ERROR_UNABLE_TO_OPEN_ZIP :
2018-01-14 18:01:22 +00:00
_snprintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2018-01-14 18:01:22 +00:00
sizeof ( szBuffer ) - 1 ,
2006-06-27 02:34:46 +00:00
TEXT ( " Unable to open the file %s. " ) ,
2010-01-03 18:43:08 +00:00
pszImageFilename ) ;
break ;
case eIMAGE_ERROR_BAD_SIZE :
2018-01-14 18:01:22 +00:00
_snprintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2018-01-14 18:01:22 +00:00
sizeof ( szBuffer ) - 1 ,
2010-01-03 18:43:08 +00:00
TEXT ( " Unable to use the file %s \n because the " )
TEXT ( " disk image is an unsupported size. " ) ,
pszImageFilename ) ;
break ;
case eIMAGE_ERROR_BAD_FILE :
2018-01-14 18:01:22 +00:00
_snprintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2018-01-14 18:01:22 +00:00
sizeof ( szBuffer ) - 1 ,
2010-01-03 18:43:08 +00:00
TEXT ( " Unable to use the file %s \n because the " )
TEXT ( " OS can't access it. " ) ,
pszImageFilename ) ;
2006-06-27 02:34:46 +00:00
break ;
2010-01-03 18:43:08 +00:00
case eIMAGE_ERROR_UNSUPPORTED :
2018-01-14 18:01:22 +00:00
_snprintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2018-01-14 18:01:22 +00:00
sizeof ( szBuffer ) - 1 ,
2006-06-27 02:34:46 +00:00
TEXT ( " Unable to use the file %s \n because the " )
TEXT ( " disk image format is not recognized. " ) ,
2010-01-03 18:43:08 +00:00
pszImageFilename ) ;
break ;
case eIMAGE_ERROR_UNSUPPORTED_HDV :
2018-01-14 18:01:22 +00:00
_snprintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2018-01-14 18:01:22 +00:00
sizeof ( szBuffer ) - 1 ,
2010-01-03 18:43:08 +00:00
TEXT ( " Unable to use the file %s \n " )
TEXT ( " because this UniDisk 3.5/Apple IIGS/hard-disk image is not supported. \n " )
TEXT ( " Try inserting as a hard-disk image instead. " ) ,
pszImageFilename ) ;
break ;
case eIMAGE_ERROR_UNSUPPORTED_MULTI_ZIP :
2018-01-14 18:01:22 +00:00
_snprintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2018-01-14 18:01:22 +00:00
sizeof ( szBuffer ) - 1 ,
2010-01-03 18:43:08 +00:00
TEXT ( " Unable to use the file %s \n because the " )
TEXT ( " first file (%s) in this multi-zip archive is not recognized. \n " )
TEXT ( " Try unzipping and using the disk images directly. \n " ) ,
pszImageFilename ,
g_aFloppyDisk [ iDrive ] . strFilenameInZip . c_str ( ) ) ;
break ;
case eIMAGE_ERROR_GZ :
case eIMAGE_ERROR_ZIP :
2018-01-14 18:01:22 +00:00
_snprintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2018-01-14 18:01:22 +00:00
sizeof ( szBuffer ) - 1 ,
2010-01-03 18:43:08 +00:00
TEXT ( " Unable to use the compressed file %s \n because the " )
TEXT ( " compressed disk image is corrupt/unsupported. " ) ,
pszImageFilename ) ;
2006-06-27 02:34:46 +00:00
break ;
2015-02-13 22:40:53 +00:00
case eIMAGE_ERROR_FAILED_TO_GET_PATHNAME :
2018-01-14 18:01:22 +00:00
_snprintf (
2015-02-13 22:40:53 +00:00
szBuffer ,
2018-01-14 18:01:22 +00:00
sizeof ( szBuffer ) - 1 ,
2015-02-13 22:40:53 +00:00
TEXT ( " Unable to GetFullPathName() for the file: %s. " ) ,
pszImageFilename ) ;
break ;
2018-01-14 18:01:22 +00:00
case eIMAGE_ERROR_ZEROLENGTH_WRITEPROTECTED :
_snprintf (
szBuffer ,
sizeof ( szBuffer ) - 1 ,
TEXT ( " Unsupported zero-length write-protected file: %s. " ) ,
pszImageFilename ) ;
break ;
case eIMAGE_ERROR_FAILED_TO_INIT_ZEROLENGTH :
_snprintf (
szBuffer ,
sizeof ( szBuffer ) - 1 ,
TEXT ( " Failed to resize the zero-length file: %s. " ) ,
pszImageFilename ) ;
break ;
2006-06-27 02:34:46 +00:00
default :
// IGNORE OTHER ERRORS SILENTLY
return ;
}
2006-02-25 20:50:29 +00:00
2006-06-27 02:34:46 +00:00
MessageBox (
g_hFrameWindow ,
2010-01-03 18:43:08 +00:00
szBuffer ,
2006-06-27 02:34:46 +00:00
g_pAppTitle ,
MB_ICONEXCLAMATION | MB_SETFOREGROUND ) ;
2006-02-25 20:50:29 +00:00
}
2006-02-26 02:02:57 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
bool DiskGetProtect ( const int iDrive )
2006-03-07 18:14:09 +00:00
{
2010-01-03 18:43:08 +00:00
if ( IsDriveValid ( iDrive ) )
2006-03-07 18:14:09 +00:00
{
Disk_t * pFloppy = & g_aFloppyDisk [ iDrive ] ;
2010-01-03 18:43:08 +00:00
if ( pFloppy - > bWriteProtected )
2006-03-07 18:14:09 +00:00
return true ;
}
return false ;
}
//===========================================================================
2010-01-03 18:43:08 +00:00
void DiskSetProtect ( const int iDrive , const bool bWriteProtect )
2006-02-26 02:02:57 +00:00
{
if ( IsDriveValid ( iDrive ) )
{
Disk_t * pFloppy = & g_aFloppyDisk [ iDrive ] ;
2010-01-03 18:43:08 +00:00
pFloppy - > bWriteProtected = bWriteProtect ;
2006-02-26 02:02:57 +00:00
}
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
bool Disk_ImageIsWriteProtected ( const int iDrive )
{
if ( ! IsDriveValid ( iDrive ) )
return true ;
Disk_t * pFloppy = & g_aFloppyDisk [ iDrive ] ;
return ImageIsWriteProtected ( pFloppy - > imagehandle ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2007-05-28 11:16:42 +00:00
2010-01-03 18:43:08 +00:00
bool Disk_IsDriveEmpty ( const int iDrive )
2007-05-28 11:16:42 +00:00
{
2010-01-03 18:43:08 +00:00
if ( ! IsDriveValid ( iDrive ) )
return true ;
Disk_t * pFloppy = & g_aFloppyDisk [ iDrive ] ;
return pFloppy - > imagehandle = = NULL ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2018-01-14 18:01:22 +00:00
# if LOG_DISK_NIBBLES_WRITE
static UINT64 g_uWriteLastCycle = 0 ;
static UINT g_uSyncFFCount = 0 ;
static bool LogWriteCheckSyncFF ( BYTE floppylatch , ULONG & uCycleDelta )
{
bool bIsSyncFF = false ;
if ( g_uWriteLastCycle = = 0 ) // Reset to 0 when write mode is enabled
{
uCycleDelta = 0 ;
if ( floppylatch = = 0xFF )
{
g_uSyncFFCount = 0 ;
bIsSyncFF = true ;
}
}
else
{
uCycleDelta = ( ULONG ) ( g_nCumulativeCycles - g_uWriteLastCycle ) ;
if ( floppylatch = = 0xFF & & uCycleDelta > 32 )
{
g_uSyncFFCount + + ;
bIsSyncFF = true ;
}
}
g_uWriteLastCycle = g_nCumulativeCycles ;
return bIsSyncFF ;
}
# endif
//===========================================================================
2015-09-13 10:39:58 +00:00
static void __stdcall DiskReadWrite ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nCyclesLeft )
2006-02-25 20:50:29 +00:00
{
2015-09-13 10:39:58 +00:00
/* floppyloadmode = 0; */
2010-01-03 18:43:08 +00:00
Disk_t * fptr = & g_aFloppyDisk [ currdrive ] ;
if ( ! fptr - > trackimagedata & & fptr - > imagehandle )
ReadTrack ( currdrive ) ;
if ( ! fptr - > trackimagedata )
{
2015-09-13 10:39:58 +00:00
floppylatch = 0xFF ;
return ;
2010-01-03 18:43:08 +00:00
}
2006-02-25 20:50:29 +00:00
2018-01-14 18:01:22 +00:00
// Improve precision of "authentic" drive mode - GH#125
UINT uSpinNibbleCount = 0 ;
CpuCalcCycles ( nCyclesLeft ) ; // g_nCumulativeCycles required for uSpinNibbleCount & LogWriteCheckSyncFF()
if ( ! enhancedisk & & fptr - > spinning )
{
const ULONG nCycleDiff = ( ULONG ) ( g_nCumulativeCycles - g_uDiskLastCycle ) ;
g_uDiskLastCycle = g_nCumulativeCycles ;
if ( nCycleDiff > 40 )
{
// 40 cycles for a write of a 10-bit 0xFF sync byte
uSpinNibbleCount = nCycleDiff > > 5 ; // ...but divide by 32 (not 40)
ULONG uWrapOffset = uSpinNibbleCount % fptr - > nibbles ;
fptr - > byte + = uWrapOffset ;
if ( fptr - > byte > = fptr - > nibbles )
fptr - > byte - = fptr - > nibbles ;
# if LOG_DISK_NIBBLES_SPIN
UINT uCompleteRevolutions = uSpinNibbleCount / fptr - > nibbles ;
LOG_DISK ( " spin: revs=%d, nibbles=%d \r \n " , uCompleteRevolutions , uWrapOffset ) ;
# endif
}
}
2017-05-14 10:33:07 +00:00
// Should really test for drive off - after 1 second drive off delay (UTAIIe page 9-13)
2017-03-08 10:13:56 +00:00
// but Sherwood Forest sets shift mode and reads with the drive off, so don't check for now
2015-09-13 10:39:58 +00:00
if ( ! floppywritemode )
{
floppylatch = * ( fptr - > trackimage + fptr - > byte ) ;
2018-01-14 18:01:22 +00:00
# if LOG_DISK_NIBBLES_READ
# if LOG_DISK_NIBBLES_USE_RUNTIME_VAR
if ( g_bLogDisk_NibblesRW )
# endif
{
LOG_DISK ( " read %04X = %02X \r \n " , fptr - > byte , floppylatch ) ;
}
g_formatTrack . DecodeLatchNibbleRead ( floppylatch ) ;
2015-09-13 10:39:58 +00:00
# endif
}
2017-03-08 10:13:56 +00:00
else if ( ! fptr - > bWriteProtected ) // && floppywritemode
2015-09-13 10:39:58 +00:00
{
* ( fptr - > trackimage + fptr - > byte ) = floppylatch ;
fptr - > trackimagedirty = 1 ;
2018-01-14 18:01:22 +00:00
g_formatTrack . DecodeLatchNibbleWrite ( floppylatch , uSpinNibbleCount , fptr ) ; // GH#125
# if LOG_DISK_NIBBLES_WRITE
# if LOG_DISK_NIBBLES_USE_RUNTIME_VAR
if ( g_bLogDisk_NibblesRW )
# endif
{
ULONG uCycleDelta = 0 ;
if ( ! LogWriteCheckSyncFF ( floppylatch , uCycleDelta ) )
LOG_DISK ( " write %04X = %02X (cy=+%d) \r \n " , fptr - > byte , floppylatch , uCycleDelta ) ;
else
LOG_DISK ( " write %04X = %02X (cy=+%d) sync #%d \r \n " , fptr - > byte , floppylatch , uCycleDelta , g_uSyncFFCount ) ;
}
# endif
2015-09-13 10:39:58 +00:00
}
2006-02-25 20:50:29 +00:00
2010-01-03 18:43:08 +00:00
if ( + + fptr - > byte > = fptr - > nibbles )
fptr - > byte = 0 ;
2006-02-25 20:50:29 +00:00
2014-07-24 01:08:52 +00:00
// Feature Request #201 Show track status
// https://github.com/AppleWin/AppleWin/issues/201
// NB. Prevent flooding of forcing UI to redraw!!!
if ( ( ( fptr - > byte ) & 0xFF ) = = 0 )
2017-08-11 20:45:07 +00:00
FrameDrawDiskStatus ( ( HDC ) 0 ) ;
2010-01-03 18:43:08 +00:00
}
//===========================================================================
2017-08-11 20:45:07 +00:00
void DiskReset ( const bool bIsPowerCycle /*=false*/ )
2010-01-03 18:43:08 +00:00
{
2017-05-14 10:33:07 +00:00
// RESET forces all switches off (UTAIIe Table 9.1)
2017-03-08 10:13:56 +00:00
currdrive = 0 ;
2010-01-03 18:43:08 +00:00
floppymotoron = 0 ;
2017-03-08 10:13:56 +00:00
floppyloadmode = 0 ;
floppywritemode = 0 ;
2010-01-03 18:43:08 +00:00
phases = 0 ;
2017-08-11 20:45:07 +00:00
2018-01-14 18:01:22 +00:00
g_formatTrack . Reset ( ) ;
2017-08-12 10:50:31 +00:00
if ( bIsPowerCycle ) // GH#460
2017-08-11 20:45:07 +00:00
{
g_aFloppyDisk [ DRIVE_1 ] . spinning = 0 ;
g_aFloppyDisk [ DRIVE_1 ] . writelight = 0 ;
g_aFloppyDisk [ DRIVE_2 ] . spinning = 0 ;
g_aFloppyDisk [ DRIVE_2 ] . writelight = 0 ;
2018-01-14 18:01:22 +00:00
FrameRefreshStatus ( DRAW_LEDS , false ) ;
2017-08-11 20:45:07 +00:00
}
2010-01-03 18:43:08 +00:00
}
//===========================================================================
2015-02-13 22:40:53 +00:00
static bool DiskSelectImage ( const int iDrive , LPCSTR pszFilename )
2010-01-03 18:43:08 +00:00
{
TCHAR directory [ MAX_PATH ] = TEXT ( " " ) ;
2010-01-17 18:43:06 +00:00
TCHAR filename [ MAX_PATH ] = TEXT ( " " ) ;
2010-01-03 18:43:08 +00:00
TCHAR title [ 40 ] ;
strcpy ( filename , pszFilename ) ;
2010-01-17 18:43:06 +00:00
RegLoadString ( TEXT ( REG_PREFS ) , REGVALUE_PREF_START_DIR , 1 , directory , MAX_PATH ) ;
2010-01-03 18:43:08 +00:00
_tcscpy ( title , TEXT ( " Select Disk Image For Drive " ) ) ;
_tcscat ( title , iDrive ? TEXT ( " 2 " ) : TEXT ( " 1 " ) ) ;
2010-12-30 20:10:48 +00:00
_ASSERT ( sizeof ( OPENFILENAME ) = = sizeof ( OPENFILENAME_NT4 ) ) ; // Required for Win98/ME support (selected by _WIN32_WINNT=0x0400 in stdafx.h)
2010-01-03 18:43:08 +00:00
OPENFILENAME ofn ;
ZeroMemory ( & ofn , sizeof ( OPENFILENAME ) ) ;
ofn . lStructSize = sizeof ( OPENFILENAME ) ;
ofn . hwndOwner = g_hFrameWindow ;
ofn . hInstance = g_hInstance ;
2010-01-17 18:43:06 +00:00
ofn . lpstrFilter = TEXT ( " All Images \0 *.bin;*.do;*.dsk;*.nib;*.po;*.gz;*.zip;*.2mg;*.2img;*.iie;*.apl \0 " )
TEXT ( " Disk Images (*.bin,*.do,*.dsk,*.nib,*.po,*.gz,*.zip,*.2mg,*.2img,*.iie) \0 *.bin;*.do;*.dsk;*.nib;*.po;*.gz;*.zip;*.2mg;*.2img;*.iie \0 " )
TEXT ( " All Files \0 *.* \0 " ) ;
2010-01-03 18:43:08 +00:00
ofn . lpstrFile = filename ;
ofn . nMaxFile = MAX_PATH ;
ofn . lpstrInitialDir = directory ;
ofn . Flags = OFN_PATHMUSTEXIST ;
ofn . lpstrTitle = title ;
2006-02-25 20:50:29 +00:00
2015-02-13 22:40:53 +00:00
bool bRes = false ;
2008-08-31 04:31:35 +00:00
if ( GetOpenFileName ( & ofn ) )
2006-02-25 20:50:29 +00:00
{
2008-08-31 04:31:35 +00:00
if ( ( ! ofn . nFileExtension ) | | ! filename [ ofn . nFileExtension ] )
2010-01-17 18:43:06 +00:00
_tcscat ( filename , TEXT ( " .dsk " ) ) ;
2008-08-31 04:31:35 +00:00
2010-01-03 18:43:08 +00:00
ImageError_e Error = DiskInsert ( iDrive , filename , ofn . Flags & OFN_READONLY , IMAGE_CREATE ) ;
if ( Error = = eIMAGE_ERROR_NONE )
2008-08-31 04:31:35 +00:00
{
2015-02-13 22:40:53 +00:00
bRes = true ;
2008-08-31 04:31:35 +00:00
}
else
{
2010-01-03 18:43:08 +00:00
DiskNotifyInvalidImage ( iDrive , filename , Error ) ;
2008-08-31 04:31:35 +00:00
}
2006-02-25 20:50:29 +00:00
}
2015-02-13 22:40:53 +00:00
return bRes ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2017-06-03 17:12:40 +00:00
bool DiskSelect ( const int iDrive )
2006-02-25 20:50:29 +00:00
{
2017-06-03 17:12:40 +00:00
return DiskSelectImage ( iDrive , TEXT ( " " ) ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2007-05-28 11:16:42 +00:00
2015-09-13 10:39:58 +00:00
static void __stdcall DiskLoadWriteProtect ( WORD , WORD , BYTE write , BYTE value , ULONG ) {
/* floppyloadmode = 1; */
if ( ! write )
{
2017-05-14 10:33:07 +00:00
// Should really test for drive off - after 1 second drive off delay (UTAIIe page 9-13)
2017-03-08 10:13:56 +00:00
// but Gemstone Warrior sets load mode with the drive off, so don't check for now
if ( ! floppywritemode )
2015-09-13 10:39:58 +00:00
{
2017-05-14 10:33:07 +00:00
// Phase 1 on also forces write protect in the Disk II drive (UTAIIe page 9-7) but we don't implement that
2015-09-13 10:39:58 +00:00
if ( g_aFloppyDisk [ currdrive ] . bWriteProtected )
floppylatch | = 0x80 ;
else
floppylatch & = 0x7F ;
}
}
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2015-09-13 10:39:58 +00:00
static void __stdcall DiskSetReadMode ( WORD , WORD , BYTE , BYTE , ULONG )
2010-01-03 18:43:08 +00:00
{
floppywritemode = 0 ;
2018-01-14 18:01:22 +00:00
g_formatTrack . DriveSwitchedToReadMode ( & g_aFloppyDisk [ currdrive ] ) ;
# if LOG_DISK_RW_MODE
LOG_DISK ( " rw mode: read \r \n " ) ;
# endif
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2015-09-13 10:39:58 +00:00
static void __stdcall DiskSetWriteMode ( WORD , WORD , BYTE , BYTE , ULONG uExecutedCycles )
2010-01-03 18:43:08 +00:00
{
floppywritemode = 1 ;
2018-01-14 18:01:22 +00:00
g_formatTrack . DriveSwitchedToWriteMode ( g_aFloppyDisk [ currdrive ] . byte ) ;
2010-01-03 18:43:08 +00:00
BOOL modechange = ! g_aFloppyDisk [ currdrive ] . writelight ;
2018-01-14 18:01:22 +00:00
# if LOG_DISK_RW_MODE
LOG_DISK ( " rw mode: write (mode changed=%d) \r \n " , modechange ? 1 : 0 ) ;
# endif
# if LOG_DISK_NIBBLES_WRITE
g_uWriteLastCycle = 0 ;
# endif
2017-08-11 21:01:47 +00:00
g_aFloppyDisk [ currdrive ] . writelight = WRITELIGHT_CYCLES ;
2018-01-14 18:01:22 +00:00
2010-01-03 18:43:08 +00:00
if ( modechange )
2014-07-24 01:08:52 +00:00
FrameDrawDiskLEDS ( ( HDC ) 0 ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2018-01-14 18:01:22 +00:00
void DiskUpdateDriveState ( DWORD cycles )
2010-01-03 18:43:08 +00:00
{
int loop = NUM_DRIVES ;
while ( loop - - )
{
Disk_t * fptr = & g_aFloppyDisk [ loop ] ;
2018-01-14 18:01:22 +00:00
if ( fptr - > spinning & & ! floppymotoron )
{
2017-08-11 21:01:47 +00:00
if ( ! ( fptr - > spinning - = MIN ( fptr - > spinning , cycles ) ) )
2014-07-24 01:08:52 +00:00
{
FrameDrawDiskLEDS ( ( HDC ) 0 ) ;
FrameDrawDiskStatus ( ( HDC ) 0 ) ;
}
2010-01-03 18:43:08 +00:00
}
if ( floppywritemode & & ( currdrive = = loop ) & & fptr - > spinning )
{
2017-08-11 21:01:47 +00:00
fptr - > writelight = WRITELIGHT_CYCLES ;
2010-01-03 18:43:08 +00:00
}
else if ( fptr - > writelight )
{
2017-08-11 21:01:47 +00:00
if ( ! ( fptr - > writelight - = MIN ( fptr - > writelight , cycles ) ) )
2014-07-24 01:08:52 +00:00
{
FrameDrawDiskLEDS ( ( HDC ) 0 ) ;
FrameDrawDiskStatus ( ( HDC ) 0 ) ;
}
2010-01-03 18:43:08 +00:00
}
}
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
bool DiskDriveSwap ( void )
2006-02-25 20:50:29 +00:00
{
// Refuse to swap if either Disk][ is active
2017-05-11 15:34:57 +00:00
// TODO: if Shift-Click then FORCE drive swap to bypass message
2006-02-26 02:02:57 +00:00
if ( g_aFloppyDisk [ 0 ] . spinning | | g_aFloppyDisk [ 1 ] . spinning )
2017-05-11 15:34:57 +00:00
{
// 1.26.2.4 Prompt when trying to swap disks while drive is on instead of silently failing
int status = MessageBox (
g_hFrameWindow ,
" WARNING: \n "
" \n "
" \t Attempting to swap a disk while a drive is on \n "
" \t \t --> is NOT recommended <-- \n "
" \t as this will most likely read/write incorrect data! \n "
" \n "
" If the other drive is empty then swapping is harmless. The "
2017-05-22 21:04:34 +00:00
" computer will appear to 'hang' trying to read non-existent data but "
2017-05-11 15:34:57 +00:00
" you can safely swap disks once more to restore the original disk. \n "
" \n "
" Do you still wish to swap disks? " ,
" Trying to swap a disk while a drive is on ... " ,
MB_ICONWARNING | MB_YESNOCANCEL
) ;
switch ( status )
{
case IDNO :
case IDCANCEL :
return false ;
default :
break ; // User is OK with swapping disks so let them proceed at their own risk
}
}
2006-02-25 20:50:29 +00:00
// Swap disks between drives
2013-12-06 21:10:41 +00:00
// . NB. We swap trackimage ptrs (so don't need to swap the buffers' data)
// . TODO: Consider array of Pointers: Disk_t* g_aDrive[]
2014-08-13 20:30:35 +00:00
std : : swap ( g_aFloppyDisk [ 0 ] , g_aFloppyDisk [ 1 ] ) ;
2006-02-25 20:50:29 +00:00
2013-12-06 21:10:41 +00:00
Disk_SaveLastDiskImage ( DRIVE_1 ) ;
Disk_SaveLastDiskImage ( DRIVE_2 ) ;
2006-02-25 20:50:29 +00:00
2018-01-14 18:01:22 +00:00
FrameRefreshStatus ( DRAW_LEDS | DRAW_BUTTON_DRIVES , false ) ;
2006-02-25 20:50:29 +00:00
return true ;
}
//===========================================================================
2010-01-03 18:43:08 +00:00
static BYTE __stdcall Disk_IORead ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nCyclesLeft ) ;
static BYTE __stdcall Disk_IOWrite ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nCyclesLeft ) ;
2007-05-28 11:16:42 +00:00
2008-09-04 16:42:14 +00:00
// TODO: LoadRom_Disk_Floppy()
2007-05-28 11:16:42 +00:00
void DiskLoadRom ( LPBYTE pCxRomPeripheral , UINT uSlot )
{
2008-09-04 16:42:14 +00:00
const UINT DISK2_FW_SIZE = APPLE_SLOT_SIZE ;
2007-05-28 11:16:42 +00:00
HRSRC hResInfo = FindResource ( NULL , MAKEINTRESOURCE ( IDR_DISK2_FW ) , " FIRMWARE " ) ;
if ( hResInfo = = NULL )
return ;
DWORD dwResSize = SizeofResource ( NULL , hResInfo ) ;
if ( dwResSize ! = DISK2_FW_SIZE )
return ;
HGLOBAL hResData = LoadResource ( NULL , hResInfo ) ;
if ( hResData = = NULL )
return ;
BYTE * pData = ( BYTE * ) LockResource ( hResData ) ; // NB. Don't need to unlock resource
if ( pData = = NULL )
return ;
2009-01-17 15:10:00 +00:00
memcpy ( pCxRomPeripheral + uSlot * APPLE_SLOT_SIZE , pData , DISK2_FW_SIZE ) ;
2007-05-28 11:16:42 +00:00
2015-09-13 10:39:58 +00:00
// Note: We used to disable the track stepping delay in the Disk II controller firmware by
2009-02-01 10:33:37 +00:00
// patching $C64C with $A9,$00,$EA. Now not doing this since:
// . Authentic Speed should be authentic
// . Enhanced Speed runs emulation unthrottled, so removing the delay has negligible effect
2009-02-03 02:24:50 +00:00
// . Patching the firmware breaks the ADC checksum used by "The CIA Files" (Tricky Dick)
2015-09-13 10:39:58 +00:00
// . In this case we can patch to compensate for an ADC or EOR checksum but not both (nickw)
2007-05-28 11:16:42 +00:00
RegisterIoHandler ( uSlot , Disk_IORead , Disk_IOWrite , NULL , NULL , NULL , NULL ) ;
2015-02-13 22:40:53 +00:00
g_uSlot = uSlot ;
2007-05-28 11:16:42 +00:00
}
//===========================================================================
static BYTE __stdcall Disk_IORead ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nCyclesLeft )
{
2015-09-13 10:39:58 +00:00
switch ( addr & 0xF )
2007-05-28 11:16:42 +00:00
{
2015-09-13 10:39:58 +00:00
case 0x0 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x1 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x2 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x3 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x4 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x5 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x6 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x7 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x8 : DiskControlMotor ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x9 : DiskControlMotor ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0xA : DiskEnable ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0xB : DiskEnable ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0xC : DiskReadWrite ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0xD : DiskLoadWriteProtect ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0xE : DiskSetReadMode ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0xF : DiskSetWriteMode ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
2007-05-28 11:16:42 +00:00
}
2017-05-14 10:33:07 +00:00
// only even addresses return the latch (UTAIIe Table 9.1)
2015-09-13 10:39:58 +00:00
if ( ! ( addr & 1 ) )
return floppylatch ;
else
return MemReadFloatingBus ( nCyclesLeft ) ;
2007-05-28 11:16:42 +00:00
}
static BYTE __stdcall Disk_IOWrite ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nCyclesLeft )
{
2015-09-13 10:39:58 +00:00
switch ( addr & 0xF )
2007-05-28 11:16:42 +00:00
{
2015-09-13 10:39:58 +00:00
case 0x0 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x1 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x2 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x3 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x4 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x5 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x6 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x7 : DiskControlStepper ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x8 : DiskControlMotor ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0x9 : DiskControlMotor ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0xA : DiskEnable ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0xB : DiskEnable ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0xC : DiskReadWrite ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0xD : DiskLoadWriteProtect ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0xE : DiskSetReadMode ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
case 0xF : DiskSetWriteMode ( pc , addr , bWrite , d , nCyclesLeft ) ; break ;
2007-05-28 11:16:42 +00:00
}
2015-09-13 10:39:58 +00:00
// any address writes the latch via sequencer LD command (74LS323 datasheet)
if ( floppywritemode /* && floppyloadmode */ )
{
floppylatch = d ;
}
2007-05-28 11:16:42 +00:00
return 0 ;
}
//===========================================================================
2015-02-13 22:40:53 +00:00
int DiskSetSnapshot_v1 ( const SS_CARD_DISK2 * const pSS )
2006-02-25 20:50:29 +00:00
{
2015-02-13 22:40:53 +00:00
if ( pSS - > Hdr . UnitHdr . hdr . v1 . dwVersion > MAKE_VERSION ( 1 , 0 , 0 , 2 ) )
return - 1 ;
2006-02-25 20:50:29 +00:00
2015-02-13 22:40:53 +00:00
phases = pSS - > phases ;
currdrive = pSS - > currdrive ;
2018-01-14 18:01:22 +00:00
//diskaccessed = pSS->diskaccessed; // deprecated
2006-02-25 20:50:29 +00:00
enhancedisk = pSS - > enhancedisk ;
floppylatch = pSS - > floppylatch ;
floppymotoron = pSS - > floppymotoron ;
floppywritemode = pSS - > floppywritemode ;
2013-04-26 21:55:45 +00:00
// Eject all disks first in case Drive-2 contains disk to be inserted into Drive-1
2010-01-03 18:43:08 +00:00
for ( UINT i = 0 ; i < NUM_DRIVES ; i + + )
2006-02-25 20:50:29 +00:00
{
2010-08-01 19:51:11 +00:00
DiskEject ( i ) ; // Remove any disk & update Registry to reflect empty drive
2015-12-05 16:50:27 +00:00
ZeroMemory ( & g_aFloppyDisk [ i ] , sizeof ( Disk_t ) ) ;
2013-04-26 21:55:45 +00:00
}
for ( UINT i = 0 ; i < NUM_DRIVES ; i + + )
{
2006-02-25 20:50:29 +00:00
if ( pSS - > Unit [ i ] . szFileName [ 0 ] = = 0x00 )
continue ;
DWORD dwAttributes = GetFileAttributes ( pSS - > Unit [ i ] . szFileName ) ;
if ( dwAttributes = = INVALID_FILE_ATTRIBUTES )
{
// Get user to browse for file
DiskSelectImage ( i , pSS - > Unit [ i ] . szFileName ) ;
dwAttributes = GetFileAttributes ( pSS - > Unit [ i ] . szFileName ) ;
}
2013-04-26 21:55:45 +00:00
bool bImageError = false ;
2006-02-25 20:50:29 +00:00
if ( dwAttributes ! = INVALID_FILE_ATTRIBUTES )
{
2010-01-03 18:43:08 +00:00
if ( DiskInsert ( i , pSS - > Unit [ i ] . szFileName , dwAttributes & FILE_ATTRIBUTE_READONLY , IMAGE_DONT_CREATE ) ! = eIMAGE_ERROR_NONE )
2006-02-25 20:50:29 +00:00
bImageError = true ;
// DiskInsert() sets up:
// . imagename
2013-12-06 21:10:41 +00:00
// . fullname
2006-02-25 20:50:29 +00:00
// . writeprotected
}
//
2006-02-26 02:02:57 +00:00
// strcpy(g_aFloppyDisk[i].fullname, pSS->Unit[i].szFileName);
g_aFloppyDisk [ i ] . track = pSS - > Unit [ i ] . track ;
g_aFloppyDisk [ i ] . phase = pSS - > Unit [ i ] . phase ;
g_aFloppyDisk [ i ] . byte = pSS - > Unit [ i ] . byte ;
2010-01-03 18:43:08 +00:00
// g_aFloppyDisk[i].writeprotected = pSS->Unit[i].writeprotected;
g_aFloppyDisk [ i ] . trackimagedata = pSS - > Unit [ i ] . trackimagedata ;
2006-02-26 02:02:57 +00:00
g_aFloppyDisk [ i ] . trackimagedirty = pSS - > Unit [ i ] . trackimagedirty ;
g_aFloppyDisk [ i ] . spinning = pSS - > Unit [ i ] . spinning ;
2010-01-03 18:43:08 +00:00
g_aFloppyDisk [ i ] . writelight = pSS - > Unit [ i ] . writelight ;
2006-02-26 02:02:57 +00:00
g_aFloppyDisk [ i ] . nibbles = pSS - > Unit [ i ] . nibbles ;
2006-02-25 20:50:29 +00:00
//
if ( ! bImageError )
{
2006-02-26 02:02:57 +00:00
if ( ( g_aFloppyDisk [ i ] . trackimage = = NULL ) & & g_aFloppyDisk [ i ] . nibbles )
2006-02-25 20:50:29 +00:00
AllocTrack ( i ) ;
2006-02-26 02:02:57 +00:00
if ( g_aFloppyDisk [ i ] . trackimage = = NULL )
2006-02-25 20:50:29 +00:00
bImageError = true ;
else
2006-02-26 02:02:57 +00:00
memcpy ( g_aFloppyDisk [ i ] . trackimage , pSS - > Unit [ i ] . nTrack , NIBBLES_PER_TRACK ) ;
2006-02-25 20:50:29 +00:00
}
if ( bImageError )
{
2010-01-03 18:43:08 +00:00
g_aFloppyDisk [ i ] . trackimagedata = 0 ;
2006-02-26 02:02:57 +00:00
g_aFloppyDisk [ i ] . trackimagedirty = 0 ;
g_aFloppyDisk [ i ] . nibbles = 0 ;
2006-02-25 20:50:29 +00:00
}
}
FrameRefreshStatus ( DRAW_LEDS | DRAW_BUTTON_DRIVES ) ;
return 0 ;
}
2015-02-13 22:40:53 +00:00
//===========================================================================
2018-01-14 18:01:22 +00:00
// Unit version history:
// 2: Added: Format Track state & DiskLastCycle
static const UINT kUNIT_VERSION = 2 ;
2015-12-05 16:50:27 +00:00
# define SS_YAML_VALUE_CARD_DISK2 "Disk]["
# define SS_YAML_KEY_PHASES "Phases"
# define SS_YAML_KEY_CURRENT_DRIVE "Current Drive"
# define SS_YAML_KEY_DISK_ACCESSED "Disk Accessed"
# define SS_YAML_KEY_ENHANCE_DISK "Enhance Disk"
# define SS_YAML_KEY_FLOPPY_LATCH "Floppy Latch"
# define SS_YAML_KEY_FLOPPY_MOTOR_ON "Floppy Motor On"
# define SS_YAML_KEY_FLOPPY_WRITE_MODE "Floppy Write Mode"
2018-01-14 18:01:22 +00:00
# define SS_YAML_KEY_LAST_CYCLE "Last Cycle"
2015-12-05 16:50:27 +00:00
2016-02-15 22:33:38 +00:00
# define SS_YAML_KEY_DISK2UNIT "Unit"
2015-12-05 16:50:27 +00:00
# define SS_YAML_KEY_FILENAME "Filename"
# define SS_YAML_KEY_TRACK "Track"
# define SS_YAML_KEY_PHASE "Phase"
# define SS_YAML_KEY_BYTE "Byte"
# define SS_YAML_KEY_WRITE_PROTECTED "Write Protected"
# define SS_YAML_KEY_SPINNING "Spinning"
# define SS_YAML_KEY_WRITE_LIGHT "Write Light"
# define SS_YAML_KEY_NIBBLES "Nibbles"
# define SS_YAML_KEY_TRACK_IMAGE_DATA "Track Image Data"
# define SS_YAML_KEY_TRACK_IMAGE_DIRTY "Track Image Dirty"
# define SS_YAML_KEY_TRACK_IMAGE "Track Image"
std : : string DiskGetSnapshotCardName ( void )
{
static const std : : string name ( SS_YAML_VALUE_CARD_DISK2 ) ;
return name ;
}
static void DiskSaveSnapshotDisk2Unit ( YamlSaveHelper & yamlSaveHelper , UINT unit )
{
YamlSaveHelper : : Label label ( yamlSaveHelper , " %s%d: \n " , SS_YAML_KEY_DISK2UNIT , unit ) ;
2016-02-24 21:51:20 +00:00
yamlSaveHelper . SaveString ( SS_YAML_KEY_FILENAME , g_aFloppyDisk [ unit ] . fullname ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_TRACK , g_aFloppyDisk [ unit ] . track ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_PHASE , g_aFloppyDisk [ unit ] . phase ) ;
2016-03-04 21:26:14 +00:00
yamlSaveHelper . SaveHexUint16 ( SS_YAML_KEY_BYTE , g_aFloppyDisk [ unit ] . byte ) ;
2016-03-01 22:31:17 +00:00
yamlSaveHelper . SaveBool ( SS_YAML_KEY_WRITE_PROTECTED , g_aFloppyDisk [ unit ] . bWriteProtected ) ;
2016-02-24 21:51:20 +00:00
yamlSaveHelper . SaveUint ( SS_YAML_KEY_SPINNING , g_aFloppyDisk [ unit ] . spinning ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_WRITE_LIGHT , g_aFloppyDisk [ unit ] . writelight ) ;
2016-03-04 21:26:14 +00:00
yamlSaveHelper . SaveHexUint16 ( SS_YAML_KEY_NIBBLES , g_aFloppyDisk [ unit ] . nibbles ) ;
2016-02-24 21:51:20 +00:00
yamlSaveHelper . SaveUint ( SS_YAML_KEY_TRACK_IMAGE_DATA , g_aFloppyDisk [ unit ] . trackimagedata ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_TRACK_IMAGE_DIRTY , g_aFloppyDisk [ unit ] . trackimagedirty ) ;
2015-12-05 16:50:27 +00:00
2016-02-14 16:01:30 +00:00
if ( g_aFloppyDisk [ unit ] . trackimage )
2015-12-05 16:50:27 +00:00
{
YamlSaveHelper : : Label image ( yamlSaveHelper , " %s: \n " , SS_YAML_KEY_TRACK_IMAGE ) ;
2016-02-24 22:54:53 +00:00
yamlSaveHelper . SaveMemory ( g_aFloppyDisk [ unit ] . trackimage , NIBBLES_PER_TRACK ) ;
2015-12-05 16:50:27 +00:00
}
}
void DiskSaveSnapshot ( class YamlSaveHelper & yamlSaveHelper )
{
2018-01-14 18:01:22 +00:00
YamlSaveHelper : : Slot slot ( yamlSaveHelper , DiskGetSnapshotCardName ( ) , g_uSlot , kUNIT_VERSION ) ;
2015-12-05 16:50:27 +00:00
YamlSaveHelper : : Label state ( yamlSaveHelper , " %s: \n " , SS_YAML_KEY_STATE ) ;
2016-03-04 21:26:14 +00:00
yamlSaveHelper . SaveHexUint4 ( SS_YAML_KEY_PHASES , phases ) ;
2016-02-24 21:51:20 +00:00
yamlSaveHelper . SaveUint ( SS_YAML_KEY_CURRENT_DRIVE , currdrive ) ;
2018-01-14 18:01:22 +00:00
yamlSaveHelper . SaveBool ( SS_YAML_KEY_DISK_ACCESSED , false ) ; // deprecated
2016-03-01 22:31:17 +00:00
yamlSaveHelper . SaveBool ( SS_YAML_KEY_ENHANCE_DISK , enhancedisk = = TRUE ) ;
2016-03-04 21:26:14 +00:00
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_FLOPPY_LATCH , floppylatch ) ;
2016-03-01 22:31:17 +00:00
yamlSaveHelper . SaveBool ( SS_YAML_KEY_FLOPPY_MOTOR_ON , floppymotoron = = TRUE ) ;
yamlSaveHelper . SaveBool ( SS_YAML_KEY_FLOPPY_WRITE_MODE , floppywritemode = = TRUE ) ;
2018-01-14 18:01:22 +00:00
yamlSaveHelper . SaveHexUint64 ( SS_YAML_KEY_LAST_CYCLE , g_uDiskLastCycle ) ; // v2
g_formatTrack . SaveSnapshot ( yamlSaveHelper ) ; // v2
2015-12-05 16:50:27 +00:00
DiskSaveSnapshotDisk2Unit ( yamlSaveHelper , DRIVE_1 ) ;
DiskSaveSnapshotDisk2Unit ( yamlSaveHelper , DRIVE_2 ) ;
}
static void DiskLoadSnapshotDriveUnit ( YamlLoadHelper & yamlLoadHelper , UINT unit )
{
std : : string disk2UnitName = std : : string ( SS_YAML_KEY_DISK2UNIT ) + ( unit = = DRIVE_1 ? std : : string ( " 0 " ) : std : : string ( " 1 " ) ) ;
if ( ! yamlLoadHelper . GetSubMap ( disk2UnitName ) )
throw std : : string ( " Card: Expected key: " ) + disk2UnitName ;
bool bImageError = false ;
2016-02-24 21:51:20 +00:00
g_aFloppyDisk [ unit ] . fullname [ 0 ] = 0 ;
g_aFloppyDisk [ unit ] . imagename [ 0 ] = 0 ;
g_aFloppyDisk [ unit ] . bWriteProtected = false ; // Default to false (until image is successfully loaded below)
2016-02-24 22:38:59 +00:00
std : : string filename = yamlLoadHelper . LoadString ( SS_YAML_KEY_FILENAME ) ;
2015-12-05 16:50:27 +00:00
if ( ! filename . empty ( ) )
{
DWORD dwAttributes = GetFileAttributes ( filename . c_str ( ) ) ;
if ( dwAttributes = = INVALID_FILE_ATTRIBUTES )
{
// Get user to browse for file
DiskSelectImage ( unit , filename . c_str ( ) ) ;
dwAttributes = GetFileAttributes ( filename . c_str ( ) ) ;
}
bImageError = ( dwAttributes = = INVALID_FILE_ATTRIBUTES ) ;
if ( ! bImageError )
{
if ( DiskInsert ( unit , filename . c_str ( ) , dwAttributes & FILE_ATTRIBUTE_READONLY , IMAGE_DONT_CREATE ) ! = eIMAGE_ERROR_NONE )
bImageError = true ;
// DiskInsert() zeros g_aFloppyDisk[unit], then sets up:
// . imagename
// . fullname
// . writeprotected
}
}
2016-02-24 22:38:59 +00:00
g_aFloppyDisk [ unit ] . track = yamlLoadHelper . LoadUint ( SS_YAML_KEY_TRACK ) ;
g_aFloppyDisk [ unit ] . phase = yamlLoadHelper . LoadUint ( SS_YAML_KEY_PHASE ) ;
g_aFloppyDisk [ unit ] . byte = yamlLoadHelper . LoadUint ( SS_YAML_KEY_BYTE ) ;
2016-03-01 22:31:17 +00:00
yamlLoadHelper . LoadBool ( SS_YAML_KEY_WRITE_PROTECTED ) ; // Consume
2016-02-24 22:38:59 +00:00
g_aFloppyDisk [ unit ] . spinning = yamlLoadHelper . LoadUint ( SS_YAML_KEY_SPINNING ) ;
g_aFloppyDisk [ unit ] . writelight = yamlLoadHelper . LoadUint ( SS_YAML_KEY_WRITE_LIGHT ) ;
g_aFloppyDisk [ unit ] . nibbles = yamlLoadHelper . LoadUint ( SS_YAML_KEY_NIBBLES ) ;
g_aFloppyDisk [ unit ] . trackimagedata = yamlLoadHelper . LoadUint ( SS_YAML_KEY_TRACK_IMAGE_DATA ) ;
g_aFloppyDisk [ unit ] . trackimagedirty = yamlLoadHelper . LoadUint ( SS_YAML_KEY_TRACK_IMAGE_DIRTY ) ;
2015-12-05 16:50:27 +00:00
2017-12-17 19:35:54 +00:00
std : : vector < BYTE > track ;
track . resize ( NIBBLES_PER_TRACK ) ;
memset ( & track [ 0 ] , 0 , track . size ( ) ) ;
2016-02-14 16:01:30 +00:00
if ( yamlLoadHelper . GetSubMap ( SS_YAML_KEY_TRACK_IMAGE ) )
{
2017-12-17 19:35:54 +00:00
yamlLoadHelper . LoadMemory ( & track [ 0 ] , NIBBLES_PER_TRACK ) ;
2016-02-14 16:01:30 +00:00
yamlLoadHelper . PopMap ( ) ;
}
2015-12-05 16:50:27 +00:00
yamlLoadHelper . PopMap ( ) ;
//
if ( ! filename . empty ( ) & & ! bImageError )
{
if ( ( g_aFloppyDisk [ unit ] . trackimage = = NULL ) & & g_aFloppyDisk [ unit ] . nibbles )
AllocTrack ( unit ) ;
if ( g_aFloppyDisk [ unit ] . trackimage = = NULL )
bImageError = true ;
else
2017-12-17 19:35:54 +00:00
memcpy ( g_aFloppyDisk [ unit ] . trackimage , & track [ 0 ] , NIBBLES_PER_TRACK ) ;
2015-12-05 16:50:27 +00:00
}
if ( bImageError )
{
g_aFloppyDisk [ unit ] . trackimagedata = 0 ;
g_aFloppyDisk [ unit ] . trackimagedirty = 0 ;
g_aFloppyDisk [ unit ] . nibbles = 0 ;
}
}
bool DiskLoadSnapshot ( class YamlLoadHelper & yamlLoadHelper , UINT slot , UINT version )
{
if ( slot ! = 6 ) // fixme
throw std : : string ( " Card: wrong slot " ) ;
2018-01-14 18:01:22 +00:00
if ( version < 1 | | version > kUNIT_VERSION )
2015-12-05 16:50:27 +00:00
throw std : : string ( " Card: wrong version " ) ;
2016-02-24 22:38:59 +00:00
phases = yamlLoadHelper . LoadUint ( SS_YAML_KEY_PHASES ) ;
currdrive = yamlLoadHelper . LoadUint ( SS_YAML_KEY_CURRENT_DRIVE ) ;
2018-01-14 18:01:22 +00:00
( void ) yamlLoadHelper . LoadBool ( SS_YAML_KEY_DISK_ACCESSED ) ; // deprecated - but retrieve the value to avoid the "State: Unknown key (Disk Accessed)" warning
2016-03-01 22:31:17 +00:00
enhancedisk = yamlLoadHelper . LoadBool ( SS_YAML_KEY_ENHANCE_DISK ) ;
2016-02-24 22:38:59 +00:00
floppylatch = yamlLoadHelper . LoadUint ( SS_YAML_KEY_FLOPPY_LATCH ) ;
2016-03-01 22:31:17 +00:00
floppymotoron = yamlLoadHelper . LoadBool ( SS_YAML_KEY_FLOPPY_MOTOR_ON ) ;
floppywritemode = yamlLoadHelper . LoadBool ( SS_YAML_KEY_FLOPPY_WRITE_MODE ) ;
2015-12-05 16:50:27 +00:00
2018-01-14 18:01:22 +00:00
if ( version > = 2 )
{
g_uDiskLastCycle = yamlLoadHelper . LoadUint64 ( SS_YAML_KEY_LAST_CYCLE ) ;
g_formatTrack . LoadSnapshot ( yamlLoadHelper ) ;
}
2015-12-05 16:50:27 +00:00
// Eject all disks first in case Drive-2 contains disk to be inserted into Drive-1
for ( UINT i = 0 ; i < NUM_DRIVES ; i + + )
{
DiskEject ( i ) ; // Remove any disk & update Registry to reflect empty drive
ZeroMemory ( & g_aFloppyDisk [ i ] , sizeof ( Disk_t ) ) ;
}
DiskLoadSnapshotDriveUnit ( yamlLoadHelper , DRIVE_1 ) ;
DiskLoadSnapshotDriveUnit ( yamlLoadHelper , DRIVE_2 ) ;
FrameRefreshStatus ( DRAW_LEDS | DRAW_BUTTON_DRIVES ) ;
return true ;
}