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
2019-04-16 19:30:54 +00:00
Copyright ( C ) 2006 - 2019 , 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
2020-11-11 21:15:27 +00:00
# include "Disk.h"
2015-02-13 22:40:53 +00:00
# include "SaveState_Structs_v1.h"
2020-11-29 17:30:06 +00:00
# include "Interface.h"
2020-11-26 21:50:06 +00:00
# include "Core.h"
2018-01-14 18:01:22 +00:00
# include "CPU.h"
2010-01-03 18:43:08 +00:00
# include "DiskImage.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"
2020-10-25 17:14:23 +00:00
# include "SaveState.h"
2015-12-05 16:50:27 +00:00
# include "YamlHelper.h"
2014-08-13 20:30:35 +00:00
2018-02-24 15:12:40 +00:00
# include "../resource/resource.h"
2007-05-28 11:16:42 +00:00
2019-04-11 21:34:40 +00:00
// About m_enhanceDisk:
// . In general m_enhanceDisk==false is used for authentic disk access speed, whereas m_enhanceDisk==true is for enhanced speed.
// Details:
// . if false: Used by ImageReadTrack() to skew the sectors in a track (for .do, .dsk, .po 5.25" images).
// . if true && m_floppyMotorOn, then this is a condition for full-speed (unthrottled) emulation mode.
// . if false && I/O ReadWrite($C0EC) && drive is spinning, then advance the track buffer's nibble index (to simulate spinning).
// Also m_enhanceDisk is persisted to the save-state, so it's an attribute of the DiskII interface card.
2021-04-10 14:31:54 +00:00
// NB. Non-standard 4&4, with Vol=0x00 and Chk=0x00 (only a few match, eg. Wasteland, Legacy of the Ancients, Planetfall, Border Zone & Wizardry). [*1]
const BYTE Disk2InterfaceCard : : m_T00S00Pattern [ ] = { 0xD5 , 0xAA , 0x96 , 0xAA , 0xAA , 0xAA , 0xAA , 0xAA , 0xAA , 0xAA , 0xAA , 0xDE } ;
2020-05-25 19:21:36 +00:00
Disk2InterfaceCard : : Disk2InterfaceCard ( UINT slot ) :
2021-11-01 21:01:28 +00:00
Card ( CT_Disk2 , slot )
2018-02-25 13:38:04 +00:00
{
2021-11-25 20:23:21 +00:00
if ( m_slot ! = 5 & & m_slot ! = 6 ) // fixme
2021-12-18 16:37:28 +00:00
throw std : : runtime_error ( " Card: wrong slot " ) ;
2021-11-25 20:23:21 +00:00
2019-07-05 22:01:19 +00:00
ResetSwitches ( ) ;
2019-04-07 14:54:26 +00:00
m_floppyLatch = 0 ;
m_saveDiskImage = true ; // Save the DiskImage name to Registry
m_diskLastCycle = 0 ;
m_diskLastReadLatchCycle = 0 ;
m_enhanceDisk = true ;
2020-02-22 11:38:25 +00:00
m_is13SectorFirmware = false ;
2018-02-25 15:09:25 +00:00
2019-07-05 22:01:19 +00:00
ResetLogicStateSequencer ( ) ;
2021-11-01 20:12:42 +00:00
// if created by user in Config->Disk, then MemInitializeIO() won't be called
if ( GetCxRomPeripheral ( ) )
2021-11-01 20:39:26 +00:00
InitializeIO ( GetCxRomPeripheral ( ) ) ; // During regular start-up, Initialize() will be called later by MemInitializeIO()
2021-11-01 20:12:42 +00:00
2019-04-07 14:32:24 +00:00
// Debug:
# if LOG_DISK_NIBBLES_USE_RUNTIME_VAR
2019-04-07 14:54:26 +00:00
m_bLogDisk_NibblesRW = false ;
2019-04-07 14:32:24 +00:00
# endif
# if LOG_DISK_NIBBLES_WRITE
2019-04-07 14:54:26 +00:00
m_uWriteLastCycle = 0 ;
m_uSyncFFCount = 0 ;
2019-04-07 14:32:24 +00:00
# endif
}
2010-01-03 18:43:08 +00:00
2019-12-19 19:42:30 +00:00
Disk2InterfaceCard : : ~ Disk2InterfaceCard ( void )
{
EjectDiskInternal ( DRIVE_1 ) ;
EjectDiskInternal ( DRIVE_2 ) ;
2021-11-01 20:12:42 +00:00
// if destroyed by user in Config->Disk, then ensure that old object's reference is removed
UnregisterIoHandler ( m_slot ) ;
2019-12-19 19:42:30 +00:00
}
2019-04-14 16:00:15 +00:00
bool Disk2InterfaceCard : : GetEnhanceDisk ( void ) { return m_enhanceDisk ; }
void Disk2InterfaceCard : : SetEnhanceDisk ( bool bEnhanceDisk ) { m_enhanceDisk = bEnhanceDisk ; }
2018-02-25 15:09:25 +00:00
2019-04-14 16:00:15 +00:00
int Disk2InterfaceCard : : GetCurrentDrive ( void ) { return m_currDrive ; }
2019-07-05 22:01:19 +00:00
int Disk2InterfaceCard : : GetCurrentTrack ( void ) { return ImagePhaseToTrack ( m_floppyDrive [ m_currDrive ] . m_disk . m_imagehandle , m_floppyDrive [ m_currDrive ] . m_phasePrecise , false ) ; }
float Disk2InterfaceCard : : GetCurrentPhase ( void ) { return m_floppyDrive [ m_currDrive ] . m_phasePrecise ; }
2019-04-14 16:00:15 +00:00
int Disk2InterfaceCard : : GetCurrentOffset ( void ) { return m_floppyDrive [ m_currDrive ] . m_disk . m_byte ; }
2019-07-05 22:01:19 +00:00
BYTE Disk2InterfaceCard : : GetCurrentLSSBitMask ( void ) { return m_floppyDrive [ m_currDrive ] . m_disk . m_bitMask ; }
double Disk2InterfaceCard : : GetCurrentExtraCycles ( void ) { return m_floppyDrive [ m_currDrive ] . m_disk . m_extraCycles ; }
2019-07-09 21:18:36 +00:00
int Disk2InterfaceCard : : GetTrack ( const int drive ) { return ImagePhaseToTrack ( m_floppyDrive [ drive ] . m_disk . m_imagehandle , m_floppyDrive [ drive ] . m_phasePrecise , false ) ; }
2019-07-05 22:01:19 +00:00
std : : string Disk2InterfaceCard : : GetCurrentTrackString ( void )
{
const UINT trackInt = ( UINT ) ( m_floppyDrive [ m_currDrive ] . m_phasePrecise / 2 ) ;
const float trackFrac = ( m_floppyDrive [ m_currDrive ] . m_phasePrecise / 2 ) - ( float ) trackInt ;
char szInt [ 8 ] = " " ;
sprintf ( szInt , " %02X " , trackInt ) ; // "$NN"
char szFrac [ 8 ] = " " ;
sprintf ( szFrac , " %.02f " , trackFrac ) ; // "0.nn"
return std : : string ( szInt ) + std : : string ( szFrac + 1 ) ;
}
std : : string Disk2InterfaceCard : : GetCurrentPhaseString ( void )
{
const UINT phaseInt = ( UINT ) ( m_floppyDrive [ m_currDrive ] . m_phasePrecise ) ;
const float phaseFrac = m_floppyDrive [ m_currDrive ] . m_phasePrecise - ( float ) phaseInt ;
char szInt [ 8 ] = " " ;
sprintf ( szInt , " %02X " , phaseInt ) ; // "$NN"
char szFrac [ 8 ] = " " ;
sprintf ( szFrac , " %.02f " , phaseFrac ) ; // "0.nn"
2013-11-02 21:24:45 +00:00
2019-07-05 22:01:19 +00:00
return std : : string ( szInt ) + std : : string ( szFrac + 1 ) ;
}
2019-04-14 16:00:15 +00:00
LPCTSTR Disk2InterfaceCard : : GetCurrentState ( void )
2013-11-02 21:24:45 +00:00
{
2019-04-14 15:58:49 +00:00
if ( m_floppyDrive [ m_currDrive ] . m_disk . m_imagehandle = = NULL )
2013-11-02 21:24:45 +00:00
return " Empty " ;
2019-04-07 14:54:26 +00:00
if ( ! m_floppyMotorOn )
2013-11-02 21:24:45 +00:00
{
2019-04-14 15:47:41 +00:00
if ( m_floppyDrive [ m_currDrive ] . m_spinning > 0 )
2013-11-02 21:24:45 +00:00
return " Off (spinning) " ;
else
return " Off " ;
}
2019-10-05 08:53:02 +00:00
else if ( m_seqFunc . writeMode )
2013-11-02 21:24:45 +00:00
{
2019-04-14 15:58:49 +00:00
if ( m_floppyDrive [ m_currDrive ] . m_disk . m_bWriteProtected )
2013-11-02 21:24:45 +00:00
return " Writing (write protected) " ;
2015-09-13 10:39:58 +00:00
else
return " Writing " ;
2013-11-02 21:24:45 +00:00
}
else
{
2019-10-05 08:53:02 +00:00
/*if (m_seqFunc.loadMode)
2015-09-13 10:39:58 +00:00
{
2019-04-07 14:54:26 +00:00
if ( m_floppyDrive [ m_currDrive ] . disk . bWriteProtected )
2015-09-13 10:39:58 +00:00
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
}
}
//===========================================================================
2019-04-14 16:00:15 +00:00
void Disk2InterfaceCard : : LoadLastDiskImage ( const int drive )
2008-08-31 04:31:35 +00:00
{
2019-04-08 15:54:11 +00:00
_ASSERT ( drive = = DRIVE_1 | | drive = = DRIVE_2 ) ;
2013-12-06 21:10:41 +00:00
2021-08-29 10:39:51 +00:00
const std : : string regKey = ( drive = = DRIVE_1 )
2021-09-17 19:43:10 +00:00
? REGVALUE_LAST_DISK_1
: REGVALUE_LAST_DISK_2 ;
2008-08-31 04:31:35 +00:00
2021-08-29 10:39:51 +00:00
char pathname [ MAX_PATH ] ;
std : : string & regSection = RegGetConfigSlotSection ( m_slot ) ;
2021-11-09 21:04:57 +00:00
if ( RegLoadString ( regSection . c_str ( ) , regKey . c_str ( ) , TRUE , pathname , MAX_PATH , TEXT ( " " ) ) & & ( pathname [ 0 ] ! = 0 ) )
2008-08-31 04:31:35 +00:00
{
2019-04-07 14:54:26 +00:00
m_saveDiskImage = false ;
2021-11-09 21:04:57 +00:00
ImageError_e error = InsertDisk ( drive , pathname , IMAGE_USE_FILES_WRITE_PROTECT_STATUS , IMAGE_DONT_CREATE ) ;
2019-04-07 14:54:26 +00:00
m_saveDiskImage = true ;
2021-11-09 21:04:57 +00:00
if ( error ! = eIMAGE_ERROR_NONE )
{
NotifyInvalidImage ( drive , pathname , error ) ;
EjectDisk ( drive ) ;
}
2008-08-31 04:31:35 +00:00
}
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2019-04-14 16:00:15 +00:00
void Disk2InterfaceCard : : SaveLastDiskImage ( const int drive )
2008-08-31 04:31:35 +00:00
{
2019-04-08 15:54:11 +00:00
_ASSERT ( drive = = DRIVE_1 | | drive = = DRIVE_2 ) ;
2008-08-31 04:31:35 +00:00
2019-04-07 14:54:26 +00:00
if ( ! m_saveDiskImage )
2013-12-06 21:10:41 +00:00
return ;
2021-08-29 10:39:51 +00:00
std : : string & regSection = RegGetConfigSlotSection ( m_slot ) ;
RegSaveValue ( regSection . c_str ( ) , REGVALUE_CARD_TYPE , TRUE , CT_Disk2 ) ;
2013-12-06 21:10:41 +00:00
2021-08-29 10:39:51 +00:00
const std : : string regKey = ( drive = = DRIVE_1 )
2021-09-17 19:43:10 +00:00
? REGVALUE_LAST_DISK_1
: REGVALUE_LAST_DISK_2 ;
2021-08-29 10:39:51 +00:00
const std : : string & pathName = DiskGetFullPathName ( drive ) ;
RegSaveString ( regSection . c_str ( ) , regKey . c_str ( ) , TRUE , pathName ) ;
2015-04-11 21:24:54 +00:00
//
2021-08-29 10:39:51 +00:00
// For now, only update 'Starting Directory' for slot6 & drive1
// . otherwise you'll get inconsistent results if you set drive1, then drive2 (and the images were in different folders)
if ( m_slot ! = SLOT6 | | drive ! = DRIVE_1 )
return ;
2019-08-09 03:50:29 +00:00
TCHAR szPathName [ MAX_PATH ] ;
2021-08-29 10:39:51 +00:00
StringCbCopy ( szPathName , MAX_PATH , pathName . c_str ( ) ) ;
TCHAR * slash = _tcsrchr ( szPathName , PATH_SEPARATOR ) ;
2019-08-09 03:50:29 +00:00
if ( slash ! = NULL )
2015-04-11 21:24:54 +00:00
{
2019-08-09 03:50:29 +00:00
slash [ 1 ] = ' \0 ' ;
2021-08-29 10:39:51 +00:00
RegSaveString ( REG_PREFS , REGVALUE_PREF_START_DIR , 1 , szPathName ) ;
2015-04-11 21:24:54 +00:00
}
2008-08-31 04:31:35 +00:00
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
2019-04-14 16:41:26 +00:00
// Called by ControlMotor() & Enable()
2020-12-12 20:05:29 +00:00
void Disk2InterfaceCard : : CheckSpinning ( const bool stateChanged , const ULONG uExecutedCycles )
2010-01-03 18:43:08 +00:00
{
2020-12-12 20:05:29 +00:00
bool modeChanged = m_floppyMotorOn & & ! m_floppyDrive [ m_currDrive ] . m_spinning ;
2014-07-26 20:23:57 +00:00
2020-12-12 20:05:29 +00:00
if ( m_floppyMotorOn & & IsDriveConnected ( m_currDrive ) )
2019-04-14 15:47:41 +00:00
m_floppyDrive [ m_currDrive ] . m_spinning = SPINNING_CYCLES ;
2014-07-26 20:23:57 +00:00
2020-12-12 20:05:29 +00:00
if ( modeChanged )
2021-01-10 16:33:06 +00:00
GetFrame ( ) . FrameDrawDiskLEDS ( ) ;
2018-01-14 18:01:22 +00:00
2020-12-12 20:05:29 +00:00
if ( modeChanged )
2018-01-14 18:01:22 +00:00
{
2019-04-07 14:54:26 +00:00
// Set m_diskLastCycle when motor changes: not spinning (ie. off for 1 sec) -> on
m_diskLastCycle = g_nCumulativeCycles ;
2018-01-14 18:01:22 +00:00
}
2020-12-12 20:05:29 +00:00
if ( m_floppyMotorOn & & stateChanged )
{
// Set m_motorOnCycle when: motor changes to on, or the other drive is enabled (and motor is on)
m_floppyDrive [ m_currDrive ] . m_motorOnCycle = 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
2019-04-14 16:00:15 +00:00
bool Disk2InterfaceCard : : IsDriveValid ( const int drive )
2010-01-03 18:43:08 +00:00
{
2019-04-08 15:54:11 +00:00
return ( drive > = 0 & & drive < NUM_DRIVES ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2019-12-31 12:07:45 +00:00
void Disk2InterfaceCard : : AllocTrack ( const int drive , const UINT minSize /*=NIBBLES_PER_TRACK*/ )
2006-02-25 20:50:29 +00:00
{
2019-04-14 15:58:49 +00:00
FloppyDisk * pFloppy = & m_floppyDrive [ drive ] . m_disk ;
2019-12-31 12:07:45 +00:00
const UINT maxNibblesPerTrack = ImageGetMaxNibblesPerTrack ( m_floppyDrive [ drive ] . m_disk . m_imagehandle ) ;
pFloppy - > m_trackimage = new BYTE [ MAX ( minSize , maxNibblesPerTrack ) ] ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2019-07-05 22:01:19 +00:00
void Disk2InterfaceCard : : ReadTrack ( const int drive , ULONG uExecutedCycles )
2006-02-26 02:02:57 +00:00
{
2019-09-30 19:39:47 +00:00
if ( ! IsDriveValid ( drive ) )
2006-02-26 02:02:57 +00:00
return ;
2019-04-14 15:47:41 +00:00
FloppyDrive * pDrive = & m_floppyDrive [ drive ] ;
2019-04-14 15:58:49 +00:00
FloppyDisk * pFloppy = & pDrive - > m_disk ;
2006-02-26 02:02:57 +00:00
2019-07-05 22:01:19 +00:00
if ( ImagePhaseToTrack ( pFloppy - > m_imagehandle , pDrive - > m_phasePrecise , false ) > = ImageGetNumTracks ( pFloppy - > m_imagehandle ) )
2006-02-26 02:02:57 +00:00
{
2019-07-05 22:01:19 +00:00
_ASSERT ( 0 ) ; // What can cause this? Add a comment to replace this assert.
2020-02-09 21:23:15 +00:00
// Boot with DOS 3.3 Master in D1
// Create a blank disk in D2
// INIT HELLO,D2
// RUN HELLO
// F2 to reboot DOS 3.3 Master
// RUN HELLO,D2
2019-04-14 15:58:49 +00:00
pFloppy - > m_trackimagedata = false ;
2006-02-26 02:02:57 +00:00
return ;
}
2019-04-14 15:58:49 +00:00
if ( ! pFloppy - > m_trackimage )
2019-04-08 15:54:11 +00:00
AllocTrack ( drive ) ;
2006-02-26 02:02:57 +00:00
2019-04-14 15:58:49 +00:00
if ( pFloppy - > m_trackimage & & pFloppy - > m_imagehandle )
2006-02-26 02:02:57 +00:00
{
2019-07-05 22:01:19 +00:00
const UINT32 currentPosition = pFloppy - > m_byte ;
const UINT32 currentTrackLength = pFloppy - > m_nibbles ;
2006-02-26 02:02:57 +00:00
ImageReadTrack (
2019-04-14 15:58:49 +00:00
pFloppy - > m_imagehandle ,
2019-07-05 22:01:19 +00:00
pDrive - > m_phasePrecise ,
2019-04-14 15:58:49 +00:00
pFloppy - > m_trackimage ,
& pFloppy - > m_nibbles ,
2019-07-05 22:01:19 +00:00
& pFloppy - > m_bitCount ,
2019-04-07 14:54:26 +00:00
m_enhanceDisk ) ;
2006-02-26 02:02:57 +00:00
2019-07-05 22:01:19 +00:00
if ( ! ImageIsWOZ ( pFloppy - > m_imagehandle ) | | ( currentTrackLength = = 0 ) )
{
pFloppy - > m_byte = 0 ;
}
else
{
_ASSERT ( pFloppy - > m_nibbles & & pFloppy - > m_bitCount ) ;
if ( pFloppy - > m_nibbles = = 0 | | pFloppy - > m_bitCount = = 0 )
{
pFloppy - > m_nibbles = 1 ;
pFloppy - > m_bitCount = 8 ;
}
pFloppy - > m_byte = ( currentPosition * pFloppy - > m_nibbles ) / currentTrackLength ; // Ref: WOZ-1.01
if ( pFloppy - > m_byte = = ( pFloppy - > m_nibbles - 1 ) ) // Last nibble may not be complete, so advance by 1 nibble
pFloppy - > m_byte = 0 ;
pFloppy - > m_bitOffset = pFloppy - > m_byte * 8 ;
pFloppy - > m_bitMask = 1 < < 7 ;
pFloppy - > m_extraCycles = 0.0 ;
pDrive - > m_headWindow = 0 ;
}
2019-04-14 15:58:49 +00:00
pFloppy - > m_trackimagedata = ( pFloppy - > m_nibbles ! = 0 ) ;
2006-02-26 02:02:57 +00:00
}
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2019-12-19 19:42:30 +00:00
void Disk2InterfaceCard : : EjectDiskInternal ( const int drive )
2006-02-26 02:02:57 +00:00
{
2019-04-14 15:58:49 +00:00
FloppyDisk * pFloppy = & m_floppyDrive [ drive ] . m_disk ;
2006-02-26 02:02:57 +00:00
2019-04-14 15:58:49 +00:00
if ( pFloppy - > m_imagehandle )
2006-02-26 02:02:57 +00:00
{
2019-04-08 15:54:11 +00:00
FlushCurrentTrack ( drive ) ;
2006-02-26 02:02:57 +00:00
2019-04-14 15:58:49 +00:00
ImageClose ( pFloppy - > m_imagehandle ) ;
pFloppy - > m_imagehandle = NULL ;
2006-02-26 02:02:57 +00:00
}
2019-04-14 15:58:49 +00:00
if ( pFloppy - > m_trackimage )
2006-02-26 02:02:57 +00:00
{
2019-12-31 12:07:45 +00:00
delete [ ] pFloppy - > m_trackimage ;
2019-12-19 19:42:30 +00:00
pFloppy - > m_trackimage = NULL ;
2019-04-14 15:58:49 +00:00
pFloppy - > m_trackimagedata = false ;
2006-02-26 02:02:57 +00:00
}
2019-09-07 08:02:39 +00:00
pFloppy - > m_imagename . clear ( ) ;
pFloppy - > m_fullname . clear ( ) ;
2019-04-14 15:58:49 +00:00
pFloppy - > m_strFilenameInZip = " " ;
2019-12-19 19:42:30 +00:00
}
void Disk2InterfaceCard : : EjectDisk ( const int drive )
{
if ( ! IsDriveValid ( drive ) )
return ;
2008-08-31 04:31:35 +00:00
2019-12-19 19:42:30 +00:00
EjectDiskInternal ( drive ) ;
2020-10-25 17:14:23 +00:00
Snapshot_UpdatePath ( ) ;
2019-12-19 19:42:30 +00:00
SaveLastDiskImage ( drive ) ;
2021-01-03 16:21:24 +00:00
GetFrame ( ) . Video_ResetScreenshotCounter ( " " ) ;
2006-02-25 20:50:29 +00:00
}
2020-12-12 20:49:46 +00:00
void Disk2InterfaceCard : : UnplugDrive ( const int drive )
{
if ( ! IsDriveValid ( drive ) )
return ;
EjectDisk ( drive ) ;
m_floppyDrive [ drive ] . m_isConnected = false ;
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
2019-04-14 16:00:15 +00:00
void Disk2InterfaceCard : : WriteTrack ( const int drive )
2006-02-26 02:02:57 +00:00
{
2019-04-14 15:47:41 +00:00
FloppyDrive * pDrive = & m_floppyDrive [ drive ] ;
2019-04-14 15:58:49 +00:00
FloppyDisk * pFloppy = & pDrive - > m_disk ;
2006-02-26 02:02:57 +00:00
2019-07-05 22:01:19 +00:00
if ( ImagePhaseToTrack ( pFloppy - > m_imagehandle , pDrive - > m_phasePrecise , false ) > = ImageGetNumTracks ( pFloppy - > m_imagehandle ) )
{
_ASSERT ( 0 ) ; // What can cause this? Add a comment to replace this assert.
2006-02-26 02:02:57 +00:00
return ;
2019-07-05 22:01:19 +00:00
}
2006-02-26 02:02:57 +00:00
2019-04-14 15:58:49 +00:00
if ( pFloppy - > m_bWriteProtected )
2006-02-26 02:02:57 +00:00
return ;
2019-04-14 15:58:49 +00:00
if ( pFloppy - > m_trackimage & & pFloppy - > m_imagehandle )
2015-09-13 10:39:58 +00:00
{
# if LOG_DISK_TRACKS
2019-07-05 22:01:19 +00:00
LOG_DISK ( " track $%s write \r \n " , GetCurrentTrackString ( ) . c_str ( ) ) ;
2015-09-13 10:39:58 +00:00
# endif
2006-02-26 02:02:57 +00:00
ImageWriteTrack (
2019-04-14 15:58:49 +00:00
pFloppy - > m_imagehandle ,
2019-07-05 22:01:19 +00:00
pDrive - > m_phasePrecise ,
2019-04-14 15:58:49 +00:00
pFloppy - > m_trackimage ,
pFloppy - > m_nibbles ) ;
2015-09-13 10:39:58 +00:00
}
2006-02-26 02:02:57 +00:00
2019-04-14 15:58:49 +00:00
pFloppy - > m_trackimagedirty = false ;
2018-04-02 17:21:18 +00:00
}
2019-04-14 16:00:15 +00:00
void Disk2InterfaceCard : : FlushCurrentTrack ( const int drive )
2018-04-02 17:21:18 +00:00
{
2019-04-14 15:58:49 +00:00
FloppyDisk * pFloppy = & m_floppyDrive [ drive ] . m_disk ;
2018-04-02 17:21:18 +00:00
2019-04-14 15:58:49 +00:00
if ( pFloppy - > m_trackimage & & pFloppy - > m_trackimagedirty )
2019-04-08 15:54:11 +00:00
WriteTrack ( drive ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2019-04-14 16:00:15 +00:00
void Disk2InterfaceCard : : Boot ( void )
2010-01-03 18:43:08 +00:00
{
// 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.
2019-04-14 15:58:49 +00:00
if ( m_floppyDrive [ 0 ] . m_disk . m_imagehandle & & ImageBoot ( m_floppyDrive [ 0 ] . m_disk . m_imagehandle ) )
2019-04-07 14:54:26 +00:00
m_floppyMotorOn = 0 ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2019-04-14 16:00:15 +00:00
void __stdcall Disk2InterfaceCard : : ControlMotor ( 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 ;
2020-12-12 20:05:29 +00:00
bool stateChanged = ( newState ! = m_floppyMotorOn ) ;
2018-01-14 18:01:22 +00:00
2020-12-12 20:05:29 +00:00
if ( stateChanged )
{
m_floppyMotorOn = newState ;
2019-04-07 14:54:26 +00:00
m_formatTrack . DriveNotWritingTrack ( ) ;
2020-12-12 20:05:29 +00:00
}
2018-01-14 18:01:22 +00:00
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)
2019-10-05 08:53:02 +00:00
// - so it doesn't reset this state: m_seqFunc, m_magnetStates
2015-09-13 10:39:58 +00:00
# if LOG_DISK_MOTOR
2019-09-30 19:39:47 +00:00
LOG_DISK ( " %08X: motor %s \r \n " , ( UINT32 ) g_nCumulativeCycles , ( m_floppyMotorOn ) ? " on " : " off " ) ;
2015-09-13 10:39:58 +00:00
# endif
2020-12-12 20:05:29 +00:00
CheckSpinning ( stateChanged , uExecutedCycles ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2019-04-14 16:00:15 +00:00
void __stdcall Disk2InterfaceCard : : ControlStepper ( WORD , WORD address , BYTE , BYTE , ULONG uExecutedCycles )
2007-03-23 22:26:35 +00:00
{
2019-04-14 15:47:41 +00:00
FloppyDrive * pDrive = & m_floppyDrive [ m_currDrive ] ;
2019-04-14 15:58:49 +00:00
FloppyDisk * pFloppy = & pDrive - > m_disk ;
2018-01-28 12:21:28 +00:00
2019-04-07 14:54:26 +00:00
if ( ! m_floppyMotorOn ) // GH#525
2018-01-27 17:02:33 +00:00
{
2019-04-14 15:47:41 +00:00
if ( ! pDrive - > m_spinning )
2018-01-28 12:21:28 +00:00
{
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
}
2019-07-05 22:01:19 +00:00
// update phases (magnet states)
2010-01-03 18:43:08 +00:00
{
2019-07-05 22:01:19 +00:00
const int phase = ( address > > 1 ) & 3 ;
const int phase_bit = ( 1 < < phase ) ;
// update the magnet states
if ( address & 1 )
m_magnetStates | = phase_bit ; // phase on
else
m_magnetStates & = ~ phase_bit ; // phase off
2010-01-03 18:43:08 +00:00
}
2007-03-23 22:26:35 +00:00
2019-07-05 22:01:19 +00:00
# if LOG_DISK_PHASES
const ULONG cycleDelta = ( ULONG ) ( g_nCumulativeCycles - pDrive - > m_lastStepperCycle ) ;
# endif
pDrive - > m_lastStepperCycle = g_nCumulativeCycles ;
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
2019-07-05 22:01:19 +00:00
// - do not move if both adjacent magnets are on (ie. quarter track)
2010-01-03 18:43:08 +00:00
// momentum and timing are not accounted for ... maybe one day!
int direction = 0 ;
2019-07-05 22:01:19 +00:00
if ( m_magnetStates & ( 1 < < ( ( pDrive - > m_phase + 1 ) & 3 ) ) )
2010-01-03 18:43:08 +00:00
direction + = 1 ;
2019-07-05 22:01:19 +00:00
if ( m_magnetStates & ( 1 < < ( ( pDrive - > m_phase + 3 ) & 3 ) ) )
2010-01-03 18:43:08 +00:00
direction - = 1 ;
2019-07-05 22:01:19 +00:00
// Only calculate quarterDirection for WOZ, as NIB/DSK don't support half phases.
int quarterDirection = 0 ;
if ( ImageIsWOZ ( pFloppy - > m_imagehandle ) )
2010-01-03 18:43:08 +00:00
{
2019-07-05 22:01:19 +00:00
if ( ( m_magnetStates = = 0xC | | // 1100
m_magnetStates = = 0x6 | | // 0110
m_magnetStates = = 0x3 | | // 0011
m_magnetStates = = 0x9 ) ) // 1001
2010-01-03 18:43:08 +00:00
{
2019-07-05 22:01:19 +00:00
quarterDirection = direction ;
direction = 0 ;
2010-01-03 18:43:08 +00:00
}
2019-07-05 22:01:19 +00:00
}
2014-07-24 01:08:52 +00:00
2019-07-05 22:01:19 +00:00
pDrive - > m_phase = MAX ( 0 , MIN ( 79 , pDrive - > m_phase + direction ) ) ;
float newPhasePrecise = ( float ) ( pDrive - > m_phase ) + ( float ) quarterDirection * 0.5f ;
if ( newPhasePrecise < 0 )
newPhasePrecise = 0 ;
// apply magnet step, if any
if ( newPhasePrecise ! = pDrive - > m_phasePrecise )
{
FlushCurrentTrack ( m_currDrive ) ;
pDrive - > m_phasePrecise = newPhasePrecise ;
pFloppy - > m_trackimagedata = false ;
m_formatTrack . DriveNotWritingTrack ( ) ;
2021-01-10 16:33:06 +00:00
GetFrame ( ) . FrameDrawDiskStatus ( ) ; // Show track status (GH#201)
2010-01-03 18:43:08 +00:00
}
2018-01-14 18:01:22 +00:00
2015-09-13 10:39:58 +00:00
# if LOG_DISK_PHASES
2019-09-30 19:39:47 +00:00
LOG_DISK ( " %08X: track $%s magnet-states %d%d%d%d phase %d %s address $%4X last-stepper %.3fms \r \n " ,
( UINT32 ) g_nCumulativeCycles ,
2019-07-05 22:01:19 +00:00
GetCurrentTrackString ( ) . c_str ( ) ,
( m_magnetStates > > 3 ) & 1 ,
( m_magnetStates > > 2 ) & 1 ,
( m_magnetStates > > 1 ) & 1 ,
( m_magnetStates > > 0 ) & 1 ,
2019-07-08 20:14:31 +00:00
( address > > 1 ) & 3 , // phase
2015-09-13 10:39:58 +00:00
( address & 1 ) ? " on " : " off " ,
2019-07-05 22:01:19 +00:00
address ,
2019-07-06 11:03:15 +00:00
( ( float ) cycleDelta ) / ( CLK_6502_NTSC / 1000.0 ) ) ;
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
2019-04-14 16:00:15 +00:00
void Disk2InterfaceCard : : Destroy ( void )
2006-02-26 02:02:57 +00:00
{
2019-04-07 14:54:26 +00:00
m_saveDiskImage = false ;
2019-12-19 19:42:30 +00:00
EjectDisk ( DRIVE_1 ) ;
2008-08-31 04:31:35 +00:00
2019-04-07 14:54:26 +00:00
m_saveDiskImage = false ;
2019-12-19 19:42:30 +00:00
EjectDisk ( DRIVE_2 ) ;
2008-08-31 04:31:35 +00:00
2019-04-07 14:54:26 +00:00
m_saveDiskImage = true ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2019-04-14 16:00:15 +00:00
void __stdcall Disk2InterfaceCard : : Enable ( WORD , WORD address , BYTE , BYTE , ULONG uExecutedCycles )
2010-01-03 18:43:08 +00:00
{
2020-12-12 20:05:29 +00:00
WORD newDrive = address & 1 ;
bool stateChanged = ( newDrive ! = m_currDrive ) ;
m_currDrive = newDrive ;
2018-01-14 18:01:22 +00:00
# if LOG_DISK_ENABLE_DRIVE
2019-09-30 19:39:47 +00:00
LOG_DISK ( " %08X: enable drive: %d \r \n " , ( UINT32 ) g_nCumulativeCycles , m_currDrive ) ;
2018-01-14 18:01:22 +00:00
# endif
2019-04-14 15:47:41 +00:00
m_floppyDrive [ ! m_currDrive ] . m_spinning = 0 ;
m_floppyDrive [ ! m_currDrive ] . m_writelight = 0 ;
2020-12-12 20:05:29 +00:00
CheckSpinning ( stateChanged , 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
// Return the filename
// . Used by Drive Buttons' tooltips
2019-09-07 08:02:39 +00:00
const std : : string & Disk2InterfaceCard : : GetFullDiskFilename ( const int drive )
2010-01-03 18:43:08 +00:00
{
2019-04-14 15:58:49 +00:00
if ( ! m_floppyDrive [ drive ] . m_disk . m_strFilenameInZip . empty ( ) )
2019-09-07 08:02:39 +00:00
return m_floppyDrive [ drive ] . m_disk . m_strFilenameInZip ;
2006-02-28 18:37:47 +00:00
2019-04-08 15:54:11 +00:00
return GetFullName ( drive ) ;
2010-01-03 18:43:08 +00:00
}
2008-06-20 23:47:25 +00:00
2019-04-09 18:29:58 +00:00
// Return the file or zip name
// . Used by Property Sheet Page (Disk)
2019-09-07 08:02:39 +00:00
const std : : string & Disk2InterfaceCard : : GetFullName ( const int drive )
2015-02-13 22:40:53 +00:00
{
2019-04-14 15:58:49 +00:00
return m_floppyDrive [ drive ] . m_disk . m_fullname ;
2015-02-13 22:40:53 +00:00
}
2010-01-03 18:43:08 +00:00
// Return the imagename
// . Used by Drive Button's icons & Property Sheet Page (Save snapshot)
2019-09-07 08:02:39 +00:00
const std : : string & Disk2InterfaceCard : : GetBaseName ( const int drive )
2010-01-03 18:43:08 +00:00
{
2019-04-14 15:58:49 +00:00
return m_floppyDrive [ drive ] . m_disk . m_imagename ;
2010-01-03 18:43:08 +00:00
}
2019-04-09 18:29:58 +00:00
2020-10-25 17:14:23 +00:00
void Disk2InterfaceCard : : GetFilenameAndPathForSaveState ( std : : string & filename , std : : string & path )
{
filename = " " ;
path = " " ;
for ( UINT i = DRIVE_1 ; i < = DRIVE_2 ; i + + )
{
if ( IsDriveEmpty ( i ) )
continue ;
filename = GetBaseName ( i ) ;
std : : string pathname = DiskGetFullPathName ( i ) ;
2021-05-19 20:10:22 +00:00
int idx = pathname . find_last_of ( PATH_SEPARATOR ) ;
2020-10-25 17:14:23 +00:00
if ( idx > = 0 & & idx + 1 < ( int ) pathname . length ( ) ) // path exists?
{
path = pathname . substr ( 0 , idx + 1 ) ;
return ;
}
_ASSERT ( 0 ) ;
break ;
}
}
2019-09-07 08:02:39 +00:00
const std : : string & Disk2InterfaceCard : : DiskGetFullPathName ( const int drive )
2019-04-09 18:29:58 +00:00
{
2019-04-14 15:58:49 +00:00
return ImageGetPathname ( m_floppyDrive [ drive ] . m_disk . m_imagehandle ) ;
2019-04-09 18:29:58 +00:00
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
2020-02-22 11:38:25 +00:00
Disk_Status_e Disk2InterfaceCard : : GetDriveLightStatus ( const int drive )
{
if ( IsDriveValid ( drive ) )
{
FloppyDrive * pDrive = & m_floppyDrive [ drive ] ;
if ( pDrive - > m_spinning )
{
if ( pDrive - > m_disk . m_bWriteProtected )
return DISK_STATUS_PROT ;
if ( pDrive - > m_writelight )
return DISK_STATUS_WRITE ;
else
return DISK_STATUS_READ ;
}
else
{
return DISK_STATUS_OFF ;
}
}
return DISK_STATUS_OFF ;
}
2019-04-14 16:00:15 +00:00
void Disk2InterfaceCard : : GetLightStatus ( Disk_Status_e * pDisk1Status , Disk_Status_e * pDisk2Status )
2006-02-28 18:37:47 +00:00
{
2018-02-25 13:38:04 +00:00
if ( pDisk1Status )
* pDisk1Status = GetDriveLightStatus ( DRIVE_1 ) ;
2014-07-26 20:23:57 +00:00
2018-02-25 13:38:04 +00:00
if ( pDisk2Status )
* pDisk2Status = GetDriveLightStatus ( DRIVE_2 ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2007-05-28 11:16:42 +00:00
2021-07-15 18:23:01 +00:00
// Pre: pathname likely to include path (but can also just be filename)
ImageError_e Disk2InterfaceCard : : InsertDisk ( const int drive , const std : : string & pathname , const bool bForceWriteProtected , const bool bCreateIfNecessary )
2008-06-20 23:47:25 +00:00
{
2019-04-14 15:47:41 +00:00
FloppyDrive * pDrive = & m_floppyDrive [ drive ] ;
2019-04-14 15:58:49 +00:00
FloppyDisk * pFloppy = & pDrive - > m_disk ;
2018-02-25 13:38:04 +00:00
2019-04-14 15:58:49 +00:00
if ( pFloppy - > m_imagehandle )
2019-12-19 19:42:30 +00:00
EjectDisk ( drive ) ;
2008-06-20 23:47:25 +00:00
2019-04-16 20:11:47 +00:00
// Reset the disk's attributes, but preserve the drive's attributes (GH#138/Platoon, GH#640)
// . Changing the disk (in the drive) doesn't affect the drive's attributes.
2019-04-16 20:13:55 +00:00
pFloppy - > clear ( ) ;
2008-06-20 23:47:25 +00:00
2021-07-15 18:23:01 +00:00
const DWORD dwAttributes = GetFileAttributes ( pathname . c_str ( ) ) ;
2020-02-11 21:29:27 +00:00
if ( dwAttributes = = INVALID_FILE_ATTRIBUTES )
pFloppy - > m_bWriteProtected = false ; // Assume this is a new file to create (so it must be write-enabled to allow it to be formatted)
2010-01-03 18:43:08 +00:00
else
2019-04-14 15:58:49 +00:00
pFloppy - > m_bWriteProtected = bForceWriteProtected ? true : ( dwAttributes & FILE_ATTRIBUTE_READONLY ) ;
2010-01-03 18:43:08 +00:00
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
{
2019-09-07 08:02:39 +00:00
const std : : string & pszOtherPathname = DiskGetFullPathName ( ! drive ) ;
2015-02-13 22:40:53 +00:00
char szCurrentPathname [ MAX_PATH ] ;
2021-07-15 18:23:01 +00:00
DWORD uNameLen = GetFullPathName ( pathname . c_str ( ) , MAX_PATH , szCurrentPathname , NULL ) ;
2015-02-13 22:40:53 +00:00
if ( uNameLen = = 0 | | uNameLen > = MAX_PATH )
2021-07-15 18:23:01 +00:00
strcpy_s ( szCurrentPathname , MAX_PATH , pathname . c_str ( ) ) ;
2015-02-13 22:40:53 +00:00
2019-09-07 08:02:39 +00:00
if ( ! strcmp ( pszOtherPathname . c_str ( ) , szCurrentPathname ) )
2015-02-13 22:40:53 +00:00
{
2019-04-08 15:54:11 +00:00
EjectDisk ( ! drive ) ;
2021-01-10 16:33:06 +00:00
GetFrame ( ) . FrameRefreshStatus ( DRAW_LEDS | DRAW_BUTTON_DRIVES | DRAW_DISK_STATUS ) ;
2015-02-13 22:40:53 +00:00
}
2014-10-01 23:18:46 +00:00
}
2021-07-15 18:23:01 +00:00
ImageError_e Error = ImageOpen ( pathname ,
2019-04-14 15:58:49 +00:00
& pFloppy - > m_imagehandle ,
& pFloppy - > m_bWriteProtected ,
2010-01-03 18:43:08 +00:00
bCreateIfNecessary ,
2019-04-14 15:58:49 +00:00
pFloppy - > m_strFilenameInZip ) ;
2010-01-03 18:43:08 +00:00
2019-04-14 15:58:49 +00:00
if ( Error = = eIMAGE_ERROR_NONE & & ImageIsMultiFileZip ( pFloppy - > m_imagehandle ) )
2010-01-03 18:43:08 +00:00
{
TCHAR szText [ 100 + MAX_PATH ] ;
2019-08-25 18:21:33 +00:00
StringCbPrintf ( szText , sizeof ( szText ) , " Only the first file in a multi-file zip is supported \n Use disk image '%s' ? " , pFloppy - > m_strFilenameInZip . c_str ( ) ) ;
2021-01-19 20:37:43 +00:00
int nRes = GetFrame ( ) . FrameMessageBox ( szText , TEXT ( " Multi-Zip Warning " ) , MB_ICONWARNING | MB_YESNO | MB_SETFOREGROUND ) ;
2010-01-03 18:43:08 +00:00
if ( nRes = = IDNO )
{
2019-12-19 19:42:30 +00:00
EjectDisk ( drive ) ;
2010-01-03 18:43:08 +00:00
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
{
2021-07-15 18:23:01 +00:00
GetImageTitle ( pathname . c_str ( ) , pFloppy - > m_imagename , pFloppy - > m_fullname ) ;
2020-10-25 17:14:23 +00:00
Snapshot_UpdatePath ( ) ;
2021-01-03 16:21:24 +00:00
GetFrame ( ) . Video_ResetScreenshotCounter ( pFloppy - > m_imagename ) ;
2020-02-22 11:38:25 +00:00
if ( g_nAppMode = = MODE_LOGO )
InitFirmware ( GetCxRomPeripheral ( ) ) ;
2008-08-31 04:31:35 +00:00
}
else
{
2021-01-03 16:21:24 +00:00
GetFrame ( ) . Video_ResetScreenshotCounter ( " " ) ;
2008-06-20 23:47:25 +00:00
}
2019-04-08 15:54:11 +00:00
SaveLastDiskImage ( drive ) ;
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
2019-04-14 16:00:15 +00:00
bool Disk2InterfaceCard : : IsConditionForFullSpeed ( void )
2018-02-27 21:07:16 +00:00
{
2019-04-07 14:54:26 +00:00
return m_floppyMotorOn & & m_enhanceDisk ;
2018-02-27 21:07:16 +00:00
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2010-01-03 18:43:08 +00:00
2019-04-14 16:00:15 +00:00
void Disk2InterfaceCard : : NotifyInvalidImage ( const int drive , LPCTSTR pszImageFilename , const ImageError_e Error )
2006-02-26 02:02:57 +00:00
{
2019-08-09 03:50:29 +00:00
TCHAR szBuffer [ MAX_PATH + 128 ] ;
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 :
2019-08-09 03:50:29 +00:00
StringCbPrintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2019-08-09 03:50:29 +00:00
MAX_PATH + 128 ,
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 :
2019-08-09 03:50:29 +00:00
StringCbPrintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2019-08-09 03:50:29 +00:00
MAX_PATH + 128 ,
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 :
2019-08-09 03:50:29 +00:00
StringCbPrintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2019-08-09 03:50:29 +00:00
MAX_PATH + 128 ,
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 :
2019-08-09 03:50:29 +00:00
StringCbPrintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2019-08-09 03:50:29 +00:00
MAX_PATH + 128 ,
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 :
2019-08-09 03:50:29 +00:00
StringCbPrintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2019-08-09 03:50:29 +00:00
MAX_PATH + 128 ,
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_GZ :
case eIMAGE_ERROR_ZIP :
2019-08-09 03:50:29 +00:00
StringCbPrintf (
2010-01-03 18:43:08 +00:00
szBuffer ,
2019-08-09 03:50:29 +00:00
MAX_PATH + 128 ,
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 :
2019-08-09 03:50:29 +00:00
StringCbPrintf (
2015-02-13 22:40:53 +00:00
szBuffer ,
2019-08-09 03:50:29 +00:00
MAX_PATH + 128 ,
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 :
2019-08-09 03:50:29 +00:00
StringCbPrintf (
2018-01-14 18:01:22 +00:00
szBuffer ,
2019-08-09 03:50:29 +00:00
MAX_PATH + 128 ,
2018-01-14 18:01:22 +00:00
TEXT ( " Unsupported zero-length write-protected file: %s. " ) ,
pszImageFilename ) ;
break ;
case eIMAGE_ERROR_FAILED_TO_INIT_ZEROLENGTH :
2019-08-09 03:50:29 +00:00
StringCbPrintf (
2018-01-14 18:01:22 +00:00
szBuffer ,
2019-08-09 03:50:29 +00:00
MAX_PATH + 128 ,
2018-01-14 18:01:22 +00:00
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
2021-01-19 20:37:43 +00:00
GetFrame ( ) . FrameMessageBox (
2010-01-03 18:43:08 +00:00
szBuffer ,
2019-09-07 09:16:51 +00:00
g_pAppTitle . c_str ( ) ,
2006-06-27 02:34:46 +00:00
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
2019-04-14 16:00:15 +00:00
bool Disk2InterfaceCard : : GetProtect ( const int drive )
2006-03-07 18:14:09 +00:00
{
2021-10-18 20:13:37 +00:00
if ( ! IsDriveValid ( drive ) )
return true ;
2018-02-25 13:38:04 +00:00
2021-10-18 20:13:37 +00:00
return m_floppyDrive [ drive ] . m_disk . m_bWriteProtected ;
2006-03-07 18:14:09 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2019-04-14 16:00:15 +00:00
void Disk2InterfaceCard : : SetProtect ( const int drive , const bool bWriteProtect )
2006-02-26 02:02:57 +00:00
{
2021-10-18 20:13:37 +00:00
if ( ! IsDriveValid ( drive ) )
return ;
m_floppyDrive [ drive ] . m_disk . m_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
2021-10-18 20:13:37 +00:00
bool Disk2InterfaceCard : : IsDriveEmpty ( const int drive )
2010-01-03 18:43:08 +00:00
{
2019-04-08 15:54:11 +00:00
if ( ! IsDriveValid ( drive ) )
2010-01-03 18:43:08 +00:00
return true ;
2021-10-18 20:13:37 +00:00
return m_floppyDrive [ drive ] . m_disk . m_imagehandle = = NULL ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2007-05-28 11:16:42 +00:00
2021-10-18 20:13:37 +00:00
bool Disk2InterfaceCard : : IsWozImageInDrive ( const int drive )
2007-05-28 11:16:42 +00:00
{
2019-04-08 15:54:11 +00:00
if ( ! IsDriveValid ( drive ) )
2021-10-18 20:13:37 +00:00
return false ;
2010-01-03 18:43:08 +00:00
2021-10-18 20:13:37 +00:00
return ImageIsWOZ ( m_floppyDrive [ drive ] . m_disk . m_imagehandle ) ;
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
2019-04-14 16:00:15 +00:00
bool Disk2InterfaceCard : : LogWriteCheckSyncFF ( ULONG & uCycleDelta )
2018-01-14 18:01:22 +00:00
{
bool bIsSyncFF = false ;
2019-04-07 14:54:26 +00:00
if ( m_uWriteLastCycle = = 0 ) // Reset to 0 when write mode is enabled
2018-01-14 18:01:22 +00:00
{
uCycleDelta = 0 ;
2019-04-07 14:54:26 +00:00
if ( m_floppyLatch = = 0xFF )
2018-01-14 18:01:22 +00:00
{
2019-04-07 14:54:26 +00:00
m_uSyncFFCount = 0 ;
2018-01-14 18:01:22 +00:00
bIsSyncFF = true ;
}
}
else
{
2019-04-07 14:54:26 +00:00
uCycleDelta = ( ULONG ) ( g_nCumulativeCycles - m_uWriteLastCycle ) ;
if ( m_floppyLatch = = 0xFF & & uCycleDelta > 32 )
2018-01-14 18:01:22 +00:00
{
2019-04-07 14:54:26 +00:00
m_uSyncFFCount + + ;
2018-01-14 18:01:22 +00:00
bIsSyncFF = true ;
}
}
2019-04-07 14:54:26 +00:00
m_uWriteLastCycle = g_nCumulativeCycles ;
2018-01-14 18:01:22 +00:00
return bIsSyncFF ;
}
# endif
//===========================================================================
2020-12-12 20:05:29 +00:00
void Disk2InterfaceCard : : UpdateLatchForEmptyDrive ( FloppyDrive * pDrive )
{
if ( ! pDrive - > m_isConnected )
{
m_floppyLatch = 0x80 ; // GH#864
return ;
}
// Drive connected
if ( ( g_nCumulativeCycles - pDrive - > m_motorOnCycle ) < MOTOR_ON_UNTIL_LSS_STABLE_CYCLES )
m_floppyLatch = 0x80 ; // GH#864
else
m_floppyLatch = rand ( ) & 0xFF ; // GH#748
}
2019-07-05 22:01:19 +00:00
void __stdcall Disk2InterfaceCard : : ReadWrite ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG uExecutedCycles )
2006-02-25 20:50:29 +00:00
{
2019-04-14 15:47:41 +00:00
FloppyDrive * pDrive = & m_floppyDrive [ m_currDrive ] ;
2019-04-14 15:58:49 +00:00
FloppyDisk * pFloppy = & pDrive - > m_disk ;
2010-01-03 18:43:08 +00:00
2019-04-14 15:58:49 +00:00
if ( ! pFloppy - > m_trackimagedata & & pFloppy - > m_imagehandle )
2019-07-05 22:01:19 +00:00
ReadTrack ( m_currDrive , uExecutedCycles ) ;
2010-01-03 18:43:08 +00:00
2019-04-14 15:58:49 +00:00
if ( ! pFloppy - > m_trackimagedata )
2020-12-12 20:05:29 +00:00
return UpdateLatchForEmptyDrive ( pDrive ) ;
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 ;
2019-04-14 15:47:41 +00:00
if ( ! m_enhanceDisk & & pDrive - > m_spinning )
2018-01-14 18:01:22 +00:00
{
2019-04-07 14:54:26 +00:00
const ULONG nCycleDiff = ( ULONG ) ( g_nCumulativeCycles - m_diskLastCycle ) ;
m_diskLastCycle = g_nCumulativeCycles ;
2018-01-14 18:01:22 +00:00
if ( nCycleDiff > 40 )
{
// 40 cycles for a write of a 10-bit 0xFF sync byte
uSpinNibbleCount = nCycleDiff > > 5 ; // ...but divide by 32 (not 40)
2019-04-14 15:58:49 +00:00
ULONG uWrapOffset = uSpinNibbleCount % pFloppy - > m_nibbles ;
pFloppy - > m_byte + = uWrapOffset ;
if ( pFloppy - > m_byte > = pFloppy - > m_nibbles )
pFloppy - > m_byte - = pFloppy - > m_nibbles ;
2018-01-14 18:01:22 +00:00
# if LOG_DISK_NIBBLES_SPIN
2019-04-14 15:58:49 +00:00
UINT uCompleteRevolutions = uSpinNibbleCount / pFloppy - > m_nibbles ;
2018-01-14 18:01:22 +00:00
LOG_DISK ( " spin: revs=%d, nibbles=%d \r \n " , uCompleteRevolutions , uWrapOffset ) ;
# endif
}
}
2019-10-05 08:53:02 +00:00
if ( ! m_seqFunc . writeMode )
2015-09-13 10:39:58 +00:00
{
2018-12-03 17:38:52 +00:00
// Don't change latch if drive off after 1 second drive-off delay (UTAIIe page 9-13)
// "DRIVES OFF forces the data register to hold its present state." (UTAIIe page 9-12)
// Note: Sherwood Forest sets shift mode and reads with the drive off.
2019-04-14 15:47:41 +00:00
if ( ! pDrive - > m_spinning ) // GH#599
2018-12-03 17:38:52 +00:00
return ;
2019-04-07 14:54:26 +00:00
const ULONG nReadCycleDiff = ( ULONG ) ( g_nCumulativeCycles - m_diskLastReadLatchCycle ) ;
2018-10-02 21:08:54 +00:00
// Support partial nibble read if disk reads are very close: (GH#582)
// . 6 cycles (1st->2nd read) for DOS 3.3 / $BD34: "read with delays to see if disk is spinning." (Beneath Apple DOS)
// . 6 cycles (1st->2nd read) for Curse of the Azure Bonds (loop to see if disk is spinning)
2019-12-08 16:23:29 +00:00
// . 25 cycles or higher fails for Legacy of the Ancients (GH#733)
2018-10-02 21:08:54 +00:00
// . 31 cycles is the max for a partial 8-bit nibble
2019-12-08 16:23:29 +00:00
const ULONG kReadAccessThreshold = 6 ; // Same for enhanced/authentic modes
2018-10-02 21:08:54 +00:00
if ( nReadCycleDiff < = kReadAccessThreshold )
{
UINT invalidBits = 8 - ( nReadCycleDiff / 4 ) ; // 4 cycles per bit-cell
2019-04-14 15:58:49 +00:00
m_floppyLatch = * ( pFloppy - > m_trackimage + pFloppy - > m_byte ) > > invalidBits ;
2019-04-07 14:54:26 +00:00
return ; // Early return so don't update: m_diskLastReadLatchCycle & pFloppy->byte
2018-10-02 21:08:54 +00:00
}
2019-04-14 15:58:49 +00:00
m_floppyLatch = * ( pFloppy - > m_trackimage + pFloppy - > m_byte ) ;
2019-04-07 14:54:26 +00:00
m_diskLastReadLatchCycle = g_nCumulativeCycles ;
2018-01-14 18:01:22 +00:00
# if LOG_DISK_NIBBLES_READ
# if LOG_DISK_NIBBLES_USE_RUNTIME_VAR
2019-04-07 14:54:26 +00:00
if ( m_bLogDisk_NibblesRW )
2018-01-14 18:01:22 +00:00
# endif
{
2019-04-14 15:58:49 +00:00
LOG_DISK ( " read %04X = %02X \r \n " , pFloppy - > m_byte , m_floppyLatch ) ;
2018-01-14 18:01:22 +00:00
}
2019-04-07 14:54:26 +00:00
m_formatTrack . DecodeLatchNibbleRead ( m_floppyLatch ) ;
2015-09-13 10:39:58 +00:00
# endif
}
2019-10-05 08:53:02 +00:00
else if ( ! pFloppy - > m_bWriteProtected ) // && m_seqFunc.writeMode
2015-09-13 10:39:58 +00:00
{
2019-07-05 22:01:19 +00:00
if ( ! pDrive - > m_spinning )
return ; // If not spinning then only 1 bit-cell gets written?
2019-04-14 15:58:49 +00:00
* ( pFloppy - > m_trackimage + pFloppy - > m_byte ) = m_floppyLatch ;
pFloppy - > m_trackimagedirty = true ;
2018-01-14 18:01:22 +00:00
2018-02-15 21:54:15 +00:00
bool bIsSyncFF = false ;
# if LOG_DISK_NIBBLES_WRITE
ULONG uCycleDelta = 0 ;
2018-02-24 13:18:26 +00:00
bIsSyncFF = LogWriteCheckSyncFF ( uCycleDelta ) ;
2018-02-15 21:54:15 +00:00
# endif
2019-04-07 14:54:26 +00:00
m_formatTrack . DecodeLatchNibbleWrite ( m_floppyLatch , uSpinNibbleCount , pFloppy , bIsSyncFF ) ; // GH#125
2018-01-14 18:01:22 +00:00
# if LOG_DISK_NIBBLES_WRITE
# if LOG_DISK_NIBBLES_USE_RUNTIME_VAR
2019-04-07 14:54:26 +00:00
if ( m_bLogDisk_NibblesRW )
2018-01-14 18:01:22 +00:00
# endif
{
2018-02-15 21:54:15 +00:00
if ( ! bIsSyncFF )
2019-04-14 15:58:49 +00:00
LOG_DISK ( " write %04X = %02X (cy=+%d) \r \n " , pFloppy - > m_byte , m_floppyLatch , uCycleDelta ) ;
2018-01-14 18:01:22 +00:00
else
2019-04-14 15:58:49 +00:00
LOG_DISK ( " write %04X = %02X (cy=+%d) sync #%d \r \n " , pFloppy - > m_byte , m_floppyLatch , uCycleDelta , m_uSyncFFCount ) ;
2018-01-14 18:01:22 +00:00
}
# endif
2015-09-13 10:39:58 +00:00
}
2006-02-25 20:50:29 +00:00
2019-04-14 15:58:49 +00:00
if ( + + pFloppy - > m_byte > = pFloppy - > m_nibbles )
pFloppy - > m_byte = 0 ;
2006-02-25 20:50:29 +00:00
2018-12-03 17:38:52 +00:00
// Show track status (GH#201) - NB. Prevent flooding of forcing UI to redraw!!!
2019-04-14 15:58:49 +00:00
if ( ( pFloppy - > m_byte & 0xFF ) = = 0 )
2021-01-10 16:33:06 +00:00
GetFrame ( ) . FrameDrawDiskStatus ( ) ;
2010-01-03 18:43:08 +00:00
}
//===========================================================================
2019-07-05 22:01:19 +00:00
void Disk2InterfaceCard : : ResetLogicStateSequencer ( void )
{
m_shiftReg = 0 ;
m_latchDelay = 0 ;
m_resetSequencer = true ;
2020-02-09 21:23:15 +00:00
m_writeStarted = false ;
2019-07-05 22:01:19 +00:00
m_dbgLatchDelayedCnt = 0 ;
2021-04-10 14:31:54 +00:00
m_T00S00PatternIdx = 0 ;
m_foundT00S00Pattern = false ;
2019-07-05 22:01:19 +00:00
}
2020-02-09 21:23:15 +00:00
UINT Disk2InterfaceCard : : GetBitCellDelta ( const ULONG uExecutedCycles )
2019-07-05 22:01:19 +00:00
{
FloppyDisk & floppy = m_floppyDrive [ m_currDrive ] . m_disk ;
2020-02-09 21:23:15 +00:00
const BYTE optimalBitTiming = ImageGetOptimalBitTiming ( floppy . m_imagehandle ) ;
2019-07-05 22:01:19 +00:00
// NB. m_extraCycles is needed to retain accuracy:
2019-07-08 20:14:31 +00:00
// . Read latch #1: 0-> 9: cycleDelta= 9, bitCellDelta=2, extraCycles=1
// . Read latch #2: 9->20: cycleDelta=11, bitCellDelta=2, extraCycles=3
// . Overall: 0->20: cycleDelta=20, bitCellDelta=5, extraCycles=0
2019-07-05 22:01:19 +00:00
UINT bitCellDelta ;
#if 0
if ( optimalBitTiming = = 32 )
{
2020-02-09 21:23:15 +00:00
const ULONG cycleDelta = ( ULONG ) ( g_nCumulativeCycles - m_diskLastCycle ) + ( BYTE ) floppy . m_extraCycles ;
2019-07-05 22:01:19 +00:00
bitCellDelta = cycleDelta / 4 ; // DIV 4 for 4us per bit-cell
2020-02-09 21:23:15 +00:00
floppy . m_extraCycles = cycleDelta & 3 ; // MOD 4 : remainder carried forward for next time
2019-07-05 22:01:19 +00:00
}
else
# endif
{
const double cycleDelta = ( double ) ( g_nCumulativeCycles - m_diskLastCycle ) + floppy . m_extraCycles ;
const double bitTime = 0.125 * ( double ) optimalBitTiming ; // 125ns units
bitCellDelta = ( UINT ) floor ( cycleDelta / bitTime ) ;
floppy . m_extraCycles = ( double ) cycleDelta - ( ( double ) bitCellDelta * bitTime ) ;
}
2020-02-09 21:23:15 +00:00
// NB. actual m_diskLastCycle for the last bitCell is minus floppy.m_extraCycles
// - but don't need this value; and it's correctly accounted for in this function.
m_diskLastCycle = g_nCumulativeCycles ;
2019-07-05 22:01:19 +00:00
return bitCellDelta ;
}
void Disk2InterfaceCard : : UpdateBitStreamPosition ( FloppyDisk & floppy , const ULONG bitCellDelta )
{
2020-02-22 12:04:13 +00:00
if ( floppy . m_bitCount = = 0 ) // Repro: Boot DOS3.3(WOZ), eject+reinsert disk, CALL-151, C0E9 N C0ED ; motor-on & LoadWriteProtect()
2019-07-05 22:01:19 +00:00
return ;
floppy . m_bitOffset + = bitCellDelta ;
if ( floppy . m_bitOffset > = floppy . m_bitCount )
floppy . m_bitOffset % = floppy . m_bitCount ;
UpdateBitStreamOffsets ( floppy ) ;
2020-02-09 21:23:15 +00:00
m_resetSequencer = false ;
2019-07-05 22:01:19 +00:00
}
void Disk2InterfaceCard : : UpdateBitStreamOffsets ( FloppyDisk & floppy )
{
floppy . m_byte = floppy . m_bitOffset / 8 ;
const UINT remainder = 7 - ( floppy . m_bitOffset & 7 ) ;
floppy . m_bitMask = 1 < < remainder ;
}
2020-02-09 21:23:15 +00:00
__forceinline void Disk2InterfaceCard : : IncBitStream ( FloppyDisk & floppy )
{
floppy . m_bitMask > > = 1 ;
if ( ! floppy . m_bitMask )
{
floppy . m_bitMask = 1 < < 7 ;
floppy . m_byte + + ;
}
floppy . m_bitOffset + + ;
if ( floppy . m_bitOffset = = floppy . m_bitCount )
{
floppy . m_bitMask = 1 < < 7 ;
floppy . m_bitOffset = 0 ;
floppy . m_byte = 0 ;
}
}
2021-04-10 14:31:54 +00:00
void Disk2InterfaceCard : : PreJitterCheck ( int phase , BYTE latch )
{
if ( phase ! = 0 | | ( latch & 0x80 ) = = 0 )
return ;
if ( latch = = m_T00S00Pattern [ m_T00S00PatternIdx ] )
{
m_T00S00PatternIdx + + ;
if ( m_T00S00PatternIdx = = sizeof ( m_T00S00Pattern ) )
m_foundT00S00Pattern = true ; // 6502 code has just read latch nibbles for T$00,S$00 address prologue
}
else
{
m_T00S00PatternIdx = 0 ;
}
}
// GH#930: After T$00,S$00 randomly skip 1 bit-cell.
// . PreJitterCheck() condition met && skipped a big number of bit-cells.
// . Fix is just for 'Wasteland' and 'Legacy of the Ancients' (but shouldn't interfere with any other woz images).
// . NB. This is likely to be the transition from DiskII firmware ($C6xx) to user-code ($801),
// so skipping 1 bit-cell here shouldn't matter.
// . And (see comment [*1]) the T00S00 pattern only matches a handful of titles.
void Disk2InterfaceCard : : AddJitter ( int phase , FloppyDisk & floppy )
{
if ( phase = = 0 & & m_foundT00S00Pattern )
{
if ( rand ( ) < RAND_THRESHOLD ( 1 , 10 ) )
{
LogOutput ( " Disk: T$00 jitter - slip 1 bitcell (PC=%04X) \n " , regs . pc ) ;
IncBitStream ( floppy ) ;
}
else
{
LogOutput ( " Disk: T$00 jitter - *** SKIP *** (PC=%04X) \n " , regs . pc ) ;
}
}
m_T00S00PatternIdx = 0 ;
m_foundT00S00Pattern = false ;
}
2020-02-09 21:23:15 +00:00
void __stdcall Disk2InterfaceCard : : DataLatchReadWriteWOZ ( WORD pc , WORD addr , BYTE bWrite , ULONG uExecutedCycles )
2019-07-05 22:01:19 +00:00
{
2020-02-09 21:23:15 +00:00
_ASSERT ( m_seqFunc . function ! = dataShiftWrite ) ;
2019-07-05 22:01:19 +00:00
FloppyDrive & drive = m_floppyDrive [ m_currDrive ] ;
FloppyDisk & floppy = drive . m_disk ;
if ( ! floppy . m_trackimagedata & & floppy . m_imagehandle )
ReadTrack ( m_currDrive , uExecutedCycles ) ;
if ( ! floppy . m_trackimagedata )
{
_ASSERT ( 0 ) ; // Can't happen for WOZ - ReadTrack() should return an empty track
2020-12-12 20:05:29 +00:00
return UpdateLatchForEmptyDrive ( & drive ) ;
2019-07-05 22:01:19 +00:00
}
// Don't change latch if drive off after 1 second drive-off delay (UTAIIe page 9-13)
// "DRIVES OFF forces the data register to hold its present state." (UTAIIe page 9-12)
// Note: Sherwood Forest sets shift mode and reads with the drive off.
// TODO: And same for a write?
if ( ! drive . m_spinning ) // GH#599
2019-08-03 17:21:41 +00:00
return ;
2019-07-05 22:01:19 +00:00
// Skipping forward a large amount of bitcells means the bitstream will very likely be out-of-sync.
// The first 1-bit will produce a latch nibble, and this 1-bit is unlikely to be the nibble's high bit.
// So we need to ensure we run enough bits through the sequencer to re-sync.
const UINT significantBitCells = 50 ; // 5x 10-bit sync FF nibbles
2020-02-09 21:23:15 +00:00
UINT bitCellDelta = GetBitCellDelta ( uExecutedCycles ) ;
2019-07-05 22:01:19 +00:00
UINT bitCellRemainder ;
if ( bitCellDelta < = significantBitCells )
{
bitCellRemainder = bitCellDelta ;
}
else
{
bitCellRemainder = significantBitCells ;
bitCellDelta - = significantBitCells ;
UpdateBitStreamPosition ( floppy , bitCellDelta ) ;
m_latchDelay = 0 ;
2019-09-30 19:39:47 +00:00
drive . m_headWindow = 0 ;
2021-04-10 14:31:54 +00:00
AddJitter ( drive . m_phase , floppy ) ; // Only call when skipping a big number of bit-cells (ie. >significantBitCells)
2019-07-05 22:01:19 +00:00
}
2019-08-03 17:21:41 +00:00
if ( ! bWrite )
2019-10-05 08:53:02 +00:00
{
if ( m_seqFunc . function ! = readSequencing )
2020-02-09 21:23:15 +00:00
{
_ASSERT ( m_seqFunc . function = = checkWriteProtAndInitWrite ) ;
UpdateBitStreamPosition ( floppy , bitCellRemainder ) ;
2019-10-05 08:53:02 +00:00
return ;
2020-02-09 21:23:15 +00:00
}
2019-10-05 08:53:02 +00:00
2019-08-03 17:21:41 +00:00
DataLatchReadWOZ ( pc , addr , bitCellRemainder ) ;
2021-04-10 14:31:54 +00:00
PreJitterCheck ( drive . m_phase , m_floppyLatch ) ; // Pre: m_floppyLatch just updated
2019-10-05 08:53:02 +00:00
}
2019-08-03 17:21:41 +00:00
else
2019-10-05 08:53:02 +00:00
{
2020-02-09 21:23:15 +00:00
_ASSERT ( m_seqFunc . function = = dataLoadWrite ) ;
DataLoadWriteWOZ ( pc , addr , bitCellRemainder ) ;
2019-10-05 08:53:02 +00:00
}
2019-08-03 17:21:41 +00:00
// Show track status (GH#201) - NB. Prevent flooding of forcing UI to redraw!!!
if ( ( floppy . m_byte & 0xFF ) = = 0 )
2021-01-10 16:33:06 +00:00
GetFrame ( ) . FrameDrawDiskStatus ( ) ;
2019-07-30 21:41:28 +00:00
}
2019-08-03 17:10:39 +00:00
void Disk2InterfaceCard : : DataLatchReadWOZ ( WORD pc , WORD addr , UINT bitCellRemainder )
2019-07-30 21:41:28 +00:00
{
// m_diskLastReadLatchCycle = g_nCumulativeCycles; // Not used by WOZ (only by NIB)
2019-07-05 22:01:19 +00:00
# if LOG_DISK_NIBBLES_READ
2019-07-30 21:41:28 +00:00
bool newLatchData = false ;
2019-07-05 22:01:19 +00:00
# endif
2019-07-30 21:41:28 +00:00
FloppyDrive & drive = m_floppyDrive [ m_currDrive ] ;
FloppyDisk & floppy = drive . m_disk ;
2019-07-05 22:01:19 +00:00
2019-08-03 16:51:19 +00:00
# if _DEBUG
static int dbgWOZ = 0 ;
if ( dbgWOZ )
{
2019-09-30 19:39:47 +00:00
dbgWOZ = 0 ;
2019-12-30 19:52:49 +00:00
DumpTrackWOZ ( floppy ) ; // Enable as necessary
2019-08-03 16:51:19 +00:00
}
# endif
2019-07-30 21:41:28 +00:00
for ( UINT i = 0 ; i < bitCellRemainder ; i + + )
{
BYTE n = floppy . m_trackimage [ floppy . m_byte ] ;
2019-07-05 22:01:19 +00:00
2019-07-30 21:41:28 +00:00
drive . m_headWindow < < = 1 ;
drive . m_headWindow | = ( n & floppy . m_bitMask ) ? 1 : 0 ;
BYTE outputBit = ( drive . m_headWindow & 0xf ) ? ( drive . m_headWindow > > 1 ) & 1
2020-11-10 20:33:55 +00:00
: ( rand ( ) < RAND_THRESHOLD ( 3 , 10 ) ) ? 1 : 0 ; // ~30% chance of a 1 bit (Ref: WOZ-2.0)
2019-07-05 22:01:19 +00:00
2020-02-09 21:23:15 +00:00
IncBitStream ( floppy ) ;
2019-07-05 22:01:19 +00:00
2019-07-30 21:41:28 +00:00
if ( m_resetSequencer )
{
m_resetSequencer = false ; // LSS takes some cycles to reset (ref?)
continue ;
}
//
2019-07-05 22:01:19 +00:00
2019-07-30 21:41:28 +00:00
m_shiftReg < < = 1 ;
m_shiftReg | = outputBit ;
if ( m_latchDelay )
{
m_latchDelay - = 4 ;
if ( m_latchDelay < 0 )
m_latchDelay = 0 ;
2019-07-05 22:01:19 +00:00
2019-07-30 21:41:28 +00:00
if ( m_shiftReg )
2019-07-05 22:01:19 +00:00
{
2019-07-30 21:41:28 +00:00
m_dbgLatchDelayedCnt = 0 ;
}
else // m_shiftReg==0
{
m_latchDelay + = 4 ; // extend by 4us (so 7us again) - GH#662
2019-07-05 22:01:19 +00:00
2019-07-30 21:41:28 +00:00
m_dbgLatchDelayedCnt + + ;
# if LOG_DISK_NIBBLES_READ
if ( m_dbgLatchDelayedCnt > = 3 )
2019-07-05 22:01:19 +00:00
{
2019-07-30 21:41:28 +00:00
LOG_DISK ( " read: latch held due to 0: PC=%04X, cnt=%02X \r \n " , regs . pc , m_dbgLatchDelayedCnt ) ;
2019-07-05 22:01:19 +00:00
}
# endif
}
2019-07-30 21:41:28 +00:00
}
2019-07-05 22:01:19 +00:00
2019-07-30 21:41:28 +00:00
if ( ! m_latchDelay )
{
2019-07-05 22:01:19 +00:00
# if LOG_DISK_NIBBLES_READ
2019-07-30 21:41:28 +00:00
if ( newLatchData )
{
LOG_DISK ( " read skipped latch data: %04X = %02X \r \n " , floppy . m_byte , m_floppyLatch ) ;
newLatchData = false ;
}
2019-07-05 22:01:19 +00:00
# endif
2019-07-30 21:41:28 +00:00
m_floppyLatch = m_shiftReg ;
2019-07-05 22:01:19 +00:00
2019-07-30 21:41:28 +00:00
if ( m_shiftReg & 0x80 )
{
m_latchDelay = 7 ;
m_shiftReg = 0 ;
2019-07-05 22:01:19 +00:00
# if LOG_DISK_NIBBLES_READ
2019-07-30 21:41:28 +00:00
// May not actually be read by 6502 (eg. Prologue's CHKSUM 4&4 nibble pair), but still pass to the log's nibble reader
m_formatTrack . DecodeLatchNibbleRead ( m_floppyLatch ) ;
newLatchData = true ;
2019-07-05 22:01:19 +00:00
# endif
}
}
2019-12-30 19:52:49 +00:00
} // for
2019-07-05 22:01:19 +00:00
# if LOG_DISK_NIBBLES_READ
2019-07-30 21:41:28 +00:00
if ( m_floppyLatch & 0x80 )
{
# if LOG_DISK_NIBBLES_USE_RUNTIME_VAR
if ( m_bLogDisk_NibblesRW )
# endif
2019-07-05 22:01:19 +00:00
{
2019-07-30 21:41:28 +00:00
LOG_DISK ( " read %04X = %02X \r \n " , floppy . m_byte , m_floppyLatch ) ;
2019-07-05 22:01:19 +00:00
}
}
2019-07-30 21:41:28 +00:00
# endif
}
2020-02-09 21:23:15 +00:00
void Disk2InterfaceCard : : DataLoadWriteWOZ ( WORD pc , WORD addr , UINT bitCellRemainder )
2019-07-30 21:41:28 +00:00
{
2020-02-09 21:23:15 +00:00
_ASSERT ( m_seqFunc . function = = dataLoadWrite ) ;
2019-07-30 21:41:28 +00:00
FloppyDrive & drive = m_floppyDrive [ m_currDrive ] ;
FloppyDisk & floppy = drive . m_disk ;
2020-02-09 21:23:15 +00:00
if ( floppy . m_bWriteProtected )
{
_ASSERT ( 0 ) ; // Must be a bug in the 6502 code for this to occur!
UpdateBitStreamPosition ( floppy , bitCellRemainder ) ;
return ;
}
if ( ! m_writeStarted )
UpdateBitStreamPosition ( floppy , bitCellRemainder ) ; // skip over bitCells before switching to write mode
m_writeStarted = true ;
# if LOG_DISK_WOZ_LOADWRITE
LOG_DISK ( " load shiftReg with %02X (was: %02X) \n " , m_floppyLatch , m_shiftReg ) ;
# endif
m_shiftReg = m_floppyLatch ;
}
void Disk2InterfaceCard : : DataShiftWriteWOZ ( WORD pc , WORD addr , ULONG uExecutedCycles )
{
_ASSERT ( m_seqFunc . function = = dataShiftWrite ) ;
FloppyDrive & drive = m_floppyDrive [ m_currDrive ] ;
FloppyDisk & floppy = drive . m_disk ;
const UINT bitCellRemainder = GetBitCellDelta ( uExecutedCycles ) ;
if ( floppy . m_bWriteProtected )
{
_ASSERT ( 0 ) ; // Must be a bug in the 6502 code for this to occur!
UpdateBitStreamPosition ( floppy , bitCellRemainder ) ;
return ;
}
# if LOG_DISK_WOZ_SHIFTWRITE
LOG_DISK ( " T$%02X, bitOffset=%04X: %02X (%d bits) \n " , drive . m_phase / 2 , floppy . m_bitOffset , m_shiftReg , bitCellRemainder ) ;
# endif
for ( UINT i = 0 ; i < bitCellRemainder ; i + + )
2019-07-05 22:01:19 +00:00
{
2020-02-09 21:23:15 +00:00
BYTE outputBit = m_shiftReg & 0x80 ;
m_shiftReg < < = 1 ;
BYTE n = floppy . m_trackimage [ floppy . m_byte ] ;
n & = ~ floppy . m_bitMask ;
if ( outputBit ) n | = floppy . m_bitMask ;
floppy . m_trackimage [ floppy . m_byte ] = n ;
IncBitStream ( floppy ) ;
2019-07-05 22:01:19 +00:00
}
2020-02-09 21:23:15 +00:00
floppy . m_trackimagedirty = true ;
2019-08-03 17:10:39 +00:00
}
2019-07-05 22:01:19 +00:00
//===========================================================================
2019-08-03 16:51:19 +00:00
# ifdef _DEBUG
// Dump nibbles from current position bitstream wraps to same position
2021-02-20 12:32:29 +00:00
// NB. Need to define LOG_DISK_NIBBLES_READ so that GetReadD5AAxxDetectedString() works.
2019-08-03 16:51:19 +00:00
void Disk2InterfaceCard : : DumpTrackWOZ ( FloppyDisk floppy ) // pass a copy of m_floppy
{
2020-02-23 13:19:38 +00:00
FormatTrack formatTrack ( true ) ;
2019-08-03 16:51:19 +00:00
BYTE shiftReg = 0 ;
2019-09-30 19:39:47 +00:00
UINT zeroCount = 0 ;
2019-08-03 16:51:19 +00:00
UINT nibbleCount = 0 ;
2021-02-20 12:32:29 +00:00
const UINT startBitOffset = 0 ; // NB. may need to tweak this offset, since the bistream is a circular buffer
2020-02-23 13:19:38 +00:00
floppy . m_bitOffset = startBitOffset ;
2019-08-03 16:51:19 +00:00
2020-02-23 13:19:38 +00:00
floppy . m_byte = floppy . m_bitOffset / 8 ;
const UINT remainder = 7 - ( floppy . m_bitOffset & 7 ) ;
floppy . m_bitMask = 1 < < remainder ;
2019-08-03 16:51:19 +00:00
2019-12-20 12:49:02 +00:00
bool newLine = true ;
2021-02-20 12:32:29 +00:00
TCHAR str [ 20 ] ;
2019-12-20 12:49:02 +00:00
2019-08-03 16:51:19 +00:00
while ( 1 )
{
2019-12-20 12:49:02 +00:00
if ( newLine )
{
newLine = false ;
StringCbPrintf ( str , sizeof ( str ) , " %04X: " , floppy . m_bitOffset & 0xffff ) ;
OutputDebugString ( str ) ;
}
2019-08-03 16:51:19 +00:00
BYTE n = floppy . m_trackimage [ floppy . m_byte ] ;
BYTE outputBit = ( n & floppy . m_bitMask ) ? 1 : 0 ;
2021-02-20 12:32:29 +00:00
IncBitStream ( floppy ) ;
2019-08-03 16:51:19 +00:00
2021-02-20 12:32:29 +00:00
if ( startBitOffset = = floppy . m_bitOffset ) // done complete track?
2019-08-03 16:51:19 +00:00
break ;
if ( shiftReg = = 0 & & outputBit = = 0 )
2019-09-30 19:39:47 +00:00
{
zeroCount + + ;
2019-08-03 16:51:19 +00:00
continue ;
2019-09-30 19:39:47 +00:00
}
2019-08-03 16:51:19 +00:00
shiftReg < < = 1 ;
shiftReg | = outputBit ;
if ( ( shiftReg & 0x80 ) = = 0 )
continue ;
nibbleCount + + ;
2019-09-30 19:39:47 +00:00
char syncBits = zeroCount < = 9 ? ' 0 ' + zeroCount : ' + ' ;
2019-12-20 12:49:02 +00:00
if ( zeroCount = = 0 ) StringCbPrintf ( str , sizeof ( str ) , " %02X " , shiftReg ) ;
else StringCbPrintf ( str , sizeof ( str ) , " (%c)%02X " , syncBits , shiftReg ) ;
2019-08-03 16:51:19 +00:00
OutputDebugString ( str ) ;
2020-02-23 13:19:38 +00:00
formatTrack . DecodeLatchNibbleRead ( shiftReg ) ;
2019-08-03 16:51:19 +00:00
if ( ( nibbleCount % 32 ) = = 0 )
2019-12-20 12:49:02 +00:00
{
2020-02-23 13:19:38 +00:00
std : : string strReadDetected = formatTrack . GetReadD5AAxxDetectedString ( ) ;
if ( ! strReadDetected . empty ( ) )
{
OutputDebugString ( " \t ; " ) ;
OutputDebugString ( strReadDetected . c_str ( ) ) ;
}
2019-08-03 16:51:19 +00:00
OutputDebugString ( " \n " ) ;
2019-12-20 12:49:02 +00:00
newLine = true ;
}
2019-08-03 16:51:19 +00:00
shiftReg = 0 ;
2019-09-30 19:39:47 +00:00
zeroCount = 0 ;
2019-08-03 16:51:19 +00:00
}
2021-02-20 12:32:29 +00:00
// Output any remaining zeroCount
if ( zeroCount )
{
char syncBits = zeroCount < = 9 ? ' 0 ' + zeroCount : ' + ' ;
StringCbPrintf ( str , sizeof ( str ) , " (%c) " , syncBits ) ;
OutputDebugString ( str ) ;
}
// Output any partial nibble
if ( shiftReg )
{
StringCbPrintf ( str , sizeof ( str ) , " %02X/Partial Nibble " , shiftReg ) ;
OutputDebugString ( str ) ;
}
2020-02-23 13:19:38 +00:00
// Output any remaining "read D5AAxx detected"
if ( nibbleCount % 32 )
{
std : : string strReadDetected = formatTrack . GetReadD5AAxxDetectedString ( ) ;
if ( ! strReadDetected . empty ( ) )
{
OutputDebugString ( " \t ; " ) ;
OutputDebugString ( strReadDetected . c_str ( ) ) ;
}
OutputDebugString ( " \n " ) ;
}
2019-08-03 16:51:19 +00:00
}
# endif
//===========================================================================
2019-12-19 19:42:30 +00:00
void Disk2InterfaceCard : : Reset ( const bool bIsPowerCycle )
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)
2019-07-05 22:01:19 +00:00
ResetSwitches ( ) ;
2017-08-11 20:45:07 +00:00
2019-04-07 14:54:26 +00:00
m_formatTrack . Reset ( ) ;
2018-01-14 18:01:22 +00:00
2019-07-05 22:01:19 +00:00
ResetLogicStateSequencer ( ) ;
2017-08-12 10:50:31 +00:00
if ( bIsPowerCycle ) // GH#460
2017-08-11 20:45:07 +00:00
{
2018-10-02 21:08:54 +00:00
// NB. This doesn't affect the drive head (ie. drive's track position)
// . The initial machine start-up state is track=0, but after a power-cycle the track could be any value.
// . (For DiskII firmware, this results in a subtle extra latch read in this latter case, for the track!=0 case)
2019-04-14 15:47:41 +00:00
m_floppyDrive [ DRIVE_1 ] . m_spinning = 0 ;
m_floppyDrive [ DRIVE_1 ] . m_writelight = 0 ;
m_floppyDrive [ DRIVE_2 ] . m_spinning = 0 ;
m_floppyDrive [ DRIVE_2 ] . m_writelight = 0 ;
2017-08-11 20:45:07 +00:00
2021-01-10 16:33:06 +00:00
GetFrame ( ) . FrameRefreshStatus ( DRAW_LEDS ) ;
2017-08-11 20:45:07 +00:00
}
2020-02-22 11:38:25 +00:00
InitFirmware ( GetCxRomPeripheral ( ) ) ;
2021-01-10 16:33:06 +00:00
GetFrame ( ) . FrameRefreshStatus ( DRAW_TITLE ) ;
2010-01-03 18:43:08 +00:00
}
2019-07-05 22:01:19 +00:00
void Disk2InterfaceCard : : ResetSwitches ( void )
{
m_currDrive = 0 ;
m_floppyMotorOn = 0 ;
m_magnetStates = 0 ;
2019-10-05 08:53:02 +00:00
m_seqFunc . function = readSequencing ;
2019-07-05 22:01:19 +00:00
}
2010-01-03 18:43:08 +00:00
//===========================================================================
2019-04-14 16:00:15 +00:00
bool Disk2InterfaceCard : : UserSelectNewDiskImage ( const int drive , LPCSTR pszFilename /*=""*/ )
2010-01-03 18:43:08 +00:00
{
2020-12-12 20:49:46 +00:00
if ( ! IsDriveConnected ( drive ) )
{
2021-01-19 20:37:43 +00:00
GetFrame ( ) . FrameMessageBox ( " Drive not connected! " , " Insert disk " , MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_OK ) ;
2020-12-12 20:49:46 +00:00
return false ;
}
2019-08-09 03:50:29 +00:00
TCHAR directory [ MAX_PATH ] ;
TCHAR filename [ MAX_PATH ] ;
2010-01-03 18:43:08 +00:00
TCHAR title [ 40 ] ;
2019-08-09 03:50:29 +00:00
StringCbCopy ( filename , MAX_PATH , pszFilename ) ;
2010-01-03 18:43:08 +00:00
2020-10-25 17:14:23 +00:00
RegLoadString ( TEXT ( REG_PREFS ) , TEXT ( REGVALUE_PREF_START_DIR ) , 1 , directory , MAX_PATH , TEXT ( " " ) ) ;
2019-08-09 03:50:29 +00:00
StringCbPrintf ( title , 40 , TEXT ( " Select Disk Image For Drive %d " ) , drive + 1 ) ;
2010-01-03 18:43:08 +00:00
OPENFILENAME ofn ;
2020-12-10 21:08:15 +00:00
memset ( & ofn , 0 , sizeof ( OPENFILENAME ) ) ;
2010-01-03 18:43:08 +00:00
ofn . lStructSize = sizeof ( OPENFILENAME ) ;
2020-12-24 15:08:50 +00:00
ofn . hwndOwner = GetFrame ( ) . g_hFrameWindow ;
ofn . hInstance = GetFrame ( ) . g_hInstance ;
2019-07-05 22:01:19 +00:00
ofn . lpstrFilter = TEXT ( " All Images \0 *.bin;*.do;*.dsk;*.nib;*.po;*.gz;*.woz;*.zip;*.2mg;*.2img;*.iie;*.apl \0 " )
TEXT ( " Disk Images (*.bin,*.do,*.dsk,*.nib,*.po,*.gz,*.woz,*.zip,*.2mg,*.2img,*.iie) \0 *.bin;*.do;*.dsk;*.nib;*.po;*.gz;*.woz;*.zip;*.2mg;*.2img;*.iie \0 " )
2010-01-17 18:43:06 +00:00
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 ] )
2019-08-09 03:50:29 +00:00
StringCbCat ( filename , MAX_PATH , TEXT ( " .dsk " ) ) ;
2008-08-31 04:31:35 +00:00
2019-04-08 15:54:11 +00:00
ImageError_e Error = InsertDisk ( drive , filename , ofn . Flags & OFN_READONLY , IMAGE_CREATE ) ;
2010-01-03 18:43:08 +00:00
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
{
2019-04-08 15:54:11 +00:00
NotifyInvalidImage ( drive , 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
2019-07-05 22:01:19 +00:00
void __stdcall Disk2InterfaceCard : : LoadWriteProtect ( WORD , WORD , BYTE write , BYTE value , ULONG uExecutedCycles )
2018-02-11 14:52:21 +00:00
{
2020-02-09 21:23:15 +00:00
// NB. Only reads in LOAD mode can issue the SR (shift write-protect) operation - UTAIIe page 9-20, fig 9.11
// But STA $C08D,X (no PX) does a read from $C08D+X, followed by the write to $C08D+X
// So just want to ignore: STA $C0ED or eg. STA $BFFF,X (PX, X=$EE)
2018-12-03 17:38:52 +00:00
// Don't change latch if drive off after 1 second drive-off delay (UTAIIe page 9-13)
// "DRIVES OFF forces the data register to hold its present state." (UTAIIe page 9-12)
// Note: Gemstone Warrior sets load mode with the drive off.
2019-04-14 15:47:41 +00:00
if ( ! m_floppyDrive [ m_currDrive ] . m_spinning ) // GH#599
2018-12-03 17:38:52 +00:00
return ;
2019-09-30 20:29:58 +00:00
// Notes:
// . Phase 1 on also forces write protect in the Disk II drive (UTAIIe page 9-7) but we don't implement that.
// . write mode doesn't prevent reading write protect (GH#537):
// "If for some reason the above write protect check were entered with the READ/WRITE switch in WRITE,
// the write protect switch would still be read correctly" (UTAIIe page 9-21)
// . Sequencer "SR" (Shift Right) command only loads QA (bit7) of data register (UTAIIe page 9-21)
2019-10-05 08:53:02 +00:00
// . A read or write will shift 'write protect' in QA.
2020-02-09 21:23:15 +00:00
FloppyDisk & floppy = m_floppyDrive [ m_currDrive ] . m_disk ;
if ( floppy . m_bWriteProtected )
2019-09-30 20:29:58 +00:00
m_floppyLatch | = 0x80 ;
else
m_floppyLatch & = 0x7F ;
2019-07-05 22:01:19 +00:00
2020-02-09 21:23:15 +00:00
if ( m_writeStarted ) // Prevent ResetLogicStateSequencer() from resetting m_writeStarted
return ;
if ( ImageIsWOZ ( floppy . m_imagehandle ) )
2019-07-05 22:01:19 +00:00
{
# if LOG_DISK_NIBBLES_READ
2019-09-30 19:39:47 +00:00
LOG_DISK ( " %08X: reset LSS: ~PC=%04X \r \n " , ( UINT32 ) g_nCumulativeCycles , regs . pc ) ;
2019-07-05 22:01:19 +00:00
# endif
2020-02-09 21:23:15 +00:00
const UINT bitCellDelta = GetBitCellDelta ( uExecutedCycles ) ;
UpdateBitStreamPosition ( floppy , bitCellDelta ) ; // Fix E7-copy protection
2020-03-27 20:31:06 +00:00
// UpdateBitStreamPosition() must be done before ResetLSS, as the former clears m_resetSequencer (and the latter sets it).
2020-02-13 19:39:35 +00:00
// . Commando.woz is sensitive to this. EG. It can crash after pressing 'J' (1 failure in 20 reboot repeats)
2019-09-30 19:39:47 +00:00
ResetLogicStateSequencer ( ) ; // reset sequencer (UTAIIe page 9-21)
2019-07-05 22:01:19 +00:00
}
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2019-09-30 19:39:47 +00:00
void __stdcall Disk2InterfaceCard : : SetReadMode ( WORD , WORD , BYTE , BYTE , ULONG uExecutedCycles )
2010-01-03 18:43:08 +00:00
{
2019-04-14 15:47:41 +00:00
m_formatTrack . DriveSwitchedToReadMode ( & m_floppyDrive [ m_currDrive ] . m_disk ) ;
2018-01-14 18:01:22 +00:00
# if LOG_DISK_RW_MODE
2019-09-30 19:39:47 +00:00
LOG_DISK ( " %08X: rw mode: read \r \n " , ( UINT32 ) g_nCumulativeCycles ) ;
2018-01-14 18:01:22 +00:00
# endif
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2019-04-14 16:00:15 +00:00
void __stdcall Disk2InterfaceCard : : SetWriteMode ( WORD , WORD , BYTE , BYTE , ULONG uExecutedCycles )
2010-01-03 18:43:08 +00:00
{
2019-04-14 15:58:49 +00:00
m_formatTrack . DriveSwitchedToWriteMode ( m_floppyDrive [ m_currDrive ] . m_disk . m_byte ) ;
2018-01-14 18:01:22 +00:00
2019-04-14 15:47:41 +00:00
BOOL modechange = ! m_floppyDrive [ m_currDrive ] . m_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
2019-04-07 14:54:26 +00:00
m_uWriteLastCycle = 0 ;
2018-01-14 18:01:22 +00:00
# endif
2019-04-14 15:47:41 +00:00
m_floppyDrive [ m_currDrive ] . m_writelight = WRITELIGHT_CYCLES ;
2018-01-14 18:01:22 +00:00
2010-01-03 18:43:08 +00:00
if ( modechange )
2021-01-10 16:33:06 +00:00
GetFrame ( ) . FrameDrawDiskLEDS ( ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2010-01-03 18:43:08 +00:00
2021-11-13 18:13:01 +00:00
void Disk2InterfaceCard : : Update ( const ULONG cycles )
2010-01-03 18:43:08 +00:00
{
int loop = NUM_DRIVES ;
while ( loop - - )
{
2019-04-14 15:47:41 +00:00
FloppyDrive * pDrive = & m_floppyDrive [ loop ] ;
2010-01-03 18:43:08 +00:00
2019-04-14 15:47:41 +00:00
if ( pDrive - > m_spinning & & ! m_floppyMotorOn )
2018-01-14 18:01:22 +00:00
{
2019-04-14 15:47:41 +00:00
if ( ! ( pDrive - > m_spinning - = MIN ( pDrive - > m_spinning , cycles ) ) )
2014-07-24 01:08:52 +00:00
{
2021-01-10 16:33:06 +00:00
GetFrame ( ) . FrameDrawDiskLEDS ( ) ;
GetFrame ( ) . FrameDrawDiskStatus ( ) ;
2014-07-24 01:08:52 +00:00
}
2010-01-03 18:43:08 +00:00
}
2019-10-05 08:53:02 +00:00
if ( m_seqFunc . writeMode & & ( m_currDrive = = loop ) & & pDrive - > m_spinning )
2010-01-03 18:43:08 +00:00
{
2019-04-14 15:47:41 +00:00
pDrive - > m_writelight = WRITELIGHT_CYCLES ;
2010-01-03 18:43:08 +00:00
}
2019-04-14 15:47:41 +00:00
else if ( pDrive - > m_writelight )
2010-01-03 18:43:08 +00:00
{
2019-04-14 15:47:41 +00:00
if ( ! ( pDrive - > m_writelight - = MIN ( pDrive - > m_writelight , cycles ) ) )
2014-07-24 01:08:52 +00:00
{
2021-01-10 16:33:06 +00:00
GetFrame ( ) . FrameDrawDiskLEDS ( ) ;
GetFrame ( ) . FrameDrawDiskStatus ( ) ;
2014-07-24 01:08:52 +00:00
}
2010-01-03 18:43:08 +00:00
}
}
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2019-04-14 16:00:15 +00:00
bool Disk2InterfaceCard : : DriveSwap ( 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
2019-04-14 15:47:41 +00:00
if ( m_floppyDrive [ DRIVE_1 ] . m_spinning | | m_floppyDrive [ DRIVE_2 ] . m_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
2021-01-19 20:37:43 +00:00
int status = GetFrame ( ) . FrameMessageBox (
2017-05-11 15:34:57 +00:00
" 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
2019-04-08 09:41:47 +00:00
FlushCurrentTrack ( DRIVE_1 ) ;
FlushCurrentTrack ( DRIVE_2 ) ;
2018-04-02 17:21:18 +00:00
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)
2019-04-14 15:47:41 +00:00
std : : swap ( m_floppyDrive [ DRIVE_1 ] . m_disk , m_floppyDrive [ DRIVE_2 ] . m_disk ) ;
2018-04-02 17:21:18 +00:00
// Invalidate the trackimage so that a read latch will re-read the track for the new floppy (GH#543)
2019-04-14 15:58:49 +00:00
m_floppyDrive [ DRIVE_1 ] . m_disk . m_trackimagedata = false ;
m_floppyDrive [ DRIVE_2 ] . m_disk . m_trackimagedata = false ;
2006-02-25 20:50:29 +00:00
2019-04-08 09:41:47 +00:00
SaveLastDiskImage ( DRIVE_1 ) ;
SaveLastDiskImage ( DRIVE_2 ) ;
2006-02-25 20:50:29 +00:00
2021-01-10 16:33:06 +00:00
GetFrame ( ) . FrameRefreshStatus ( DRAW_LEDS | DRAW_BUTTON_DRIVES ) ;
2006-02-25 20:50:29 +00:00
return true ;
}
//===========================================================================
2021-01-19 20:37:43 +00:00
bool Disk2InterfaceCard : : GetFirmware ( WORD lpNameId , BYTE * pDst )
2007-05-28 11:16:42 +00:00
{
2021-01-19 20:37:43 +00:00
BYTE * pData = GetFrame ( ) . GetResource ( lpNameId , " FIRMWARE " , DISK2_FW_SIZE ) ;
2020-02-22 11:38:25 +00:00
if ( ! pData )
return false ;
memcpy ( pDst , pData , DISK2_FW_SIZE ) ;
return true ;
}
void Disk2InterfaceCard : : InitFirmware ( LPBYTE pCxRomPeripheral )
{
if ( pCxRomPeripheral = = NULL )
2007-05-28 11:16:42 +00:00
return ;
2020-02-22 11:38:25 +00:00
ImageInfo * pImage = m_floppyDrive [ DRIVE_1 ] . m_disk . m_imagehandle ;
m_is13SectorFirmware = ImageIsBootSectorFormatSector13 ( pImage ) ;
if ( m_is13SectorFirmware )
memcpy ( pCxRomPeripheral + m_slot * APPLE_SLOT_SIZE , m_13SectorFirmware , DISK2_FW_SIZE ) ;
else
memcpy ( pCxRomPeripheral + m_slot * APPLE_SLOT_SIZE , m_16SectorFirmware , DISK2_FW_SIZE ) ;
}
2021-11-01 20:39:26 +00:00
void Disk2InterfaceCard : : InitializeIO ( LPBYTE pCxRomPeripheral )
2020-02-22 11:38:25 +00:00
{
2021-01-19 20:37:43 +00:00
bool res = GetFirmware ( IDR_DISK2_13SECTOR_FW , m_13SectorFirmware ) ;
2020-02-22 11:38:25 +00:00
_ASSERT ( res ) ;
2021-01-19 20:37:43 +00:00
res = GetFirmware ( IDR_DISK2_16SECTOR_FW , m_16SectorFirmware ) ;
2020-02-22 11:38:25 +00:00
_ASSERT ( res ) ;
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
2021-11-01 20:12:42 +00:00
RegisterIoHandler ( m_slot , & Disk2InterfaceCard : : IORead , & Disk2InterfaceCard : : IOWrite , NULL , NULL , this , NULL ) ;
2020-02-22 11:38:25 +00:00
InitFirmware ( pCxRomPeripheral ) ;
2007-05-28 11:16:42 +00:00
}
//===========================================================================
2019-09-30 20:29:58 +00:00
void Disk2InterfaceCard : : SetSequencerFunction ( WORD addr )
{
if ( ( addr & 0xf ) < 0xc )
return ;
2019-10-13 09:25:33 +00:00
switch ( ( addr & 3 ) ^ 2 )
2019-09-30 20:29:58 +00:00
{
2019-10-05 08:53:02 +00:00
case 0 : m_seqFunc . writeMode = 0 ; break ; // $C08E,X (sequence addr A2 input)
case 1 : m_seqFunc . writeMode = 1 ; break ; // $C08F,X (sequence addr A2 input)
case 2 : m_seqFunc . loadMode = 0 ; break ; // $C08C,X (sequence addr A3 input)
case 3 : m_seqFunc . loadMode = 1 ; break ; // $C08D,X (sequence addr A3 input)
2019-09-30 20:29:58 +00:00
}
2020-02-09 21:23:15 +00:00
if ( ! m_seqFunc . writeMode )
m_writeStarted = false ;
2019-09-30 20:29:58 +00:00
}
2019-04-14 16:00:15 +00:00
BYTE __stdcall Disk2InterfaceCard : : IORead ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2020-11-14 14:54:39 +00:00
CpuCalcCycles ( nExecutedCycles ) ; // g_nCumulativeCycles needed by most Disk I/O functions
2019-04-07 13:22:05 +00:00
UINT uSlot = ( ( addr & 0xff ) > > 4 ) - 8 ;
2019-04-14 16:00:15 +00:00
Disk2InterfaceCard * pCard = ( Disk2InterfaceCard * ) MemGetSlotParameters ( uSlot ) ;
2019-04-07 13:22:05 +00:00
2019-07-05 22:01:19 +00:00
ImageInfo * pImage = pCard - > m_floppyDrive [ pCard - > m_currDrive ] . m_disk . m_imagehandle ;
bool isWOZ = ImageIsWOZ ( pImage ) ;
2020-02-09 21:23:15 +00:00
if ( isWOZ & & pCard - > m_seqFunc . function = = dataShiftWrite ) // Occurs at end of sector write ($C0EE)
pCard - > DataShiftWriteWOZ ( pc , addr , nExecutedCycles ) ; // Finish any previous write
2019-09-30 20:29:58 +00:00
pCard - > SetSequencerFunction ( addr ) ;
2015-09-13 10:39:58 +00:00
switch ( addr & 0xF )
2007-05-28 11:16:42 +00:00
{
2019-04-08 09:41:47 +00:00
case 0x0 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x1 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x2 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x3 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x4 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x5 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x6 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x7 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x8 : pCard - > ControlMotor ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x9 : pCard - > ControlMotor ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0xA : pCard - > Enable ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0xB : pCard - > Enable ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
2019-07-30 21:41:28 +00:00
case 0xC : if ( ! isWOZ ) pCard - > ReadWrite ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
2019-04-08 09:41:47 +00:00
case 0xD : pCard - > LoadWriteProtect ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0xE : pCard - > SetReadMode ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0xF : pCard - > SetWriteMode ( pc , addr , bWrite , d , nExecutedCycles ) ; 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 ) )
2019-07-30 21:41:28 +00:00
{
2020-02-09 21:23:15 +00:00
if ( isWOZ & & pCard - > m_seqFunc . function ! = dataShiftWrite )
pCard - > DataLatchReadWriteWOZ ( pc , addr , bWrite , nExecutedCycles ) ;
2019-07-30 21:41:28 +00:00
2019-04-07 14:54:26 +00:00
return pCard - > m_floppyLatch ;
2019-07-30 21:41:28 +00:00
}
return MemReadFloatingBus ( nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
}
2019-04-14 16:00:15 +00:00
BYTE __stdcall Disk2InterfaceCard : : IOWrite ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2020-11-14 14:54:39 +00:00
CpuCalcCycles ( nExecutedCycles ) ; // g_nCumulativeCycles needed by most Disk I/O functions
2019-04-07 13:22:05 +00:00
UINT uSlot = ( ( addr & 0xff ) > > 4 ) - 8 ;
2019-04-14 16:00:15 +00:00
Disk2InterfaceCard * pCard = ( Disk2InterfaceCard * ) MemGetSlotParameters ( uSlot ) ;
2019-04-07 13:22:05 +00:00
2019-07-05 22:01:19 +00:00
ImageInfo * pImage = pCard - > m_floppyDrive [ pCard - > m_currDrive ] . m_disk . m_imagehandle ;
bool isWOZ = ImageIsWOZ ( pImage ) ;
2020-02-09 21:23:15 +00:00
if ( isWOZ & & pCard - > m_seqFunc . function = = dataShiftWrite )
pCard - > DataShiftWriteWOZ ( pc , addr , nExecutedCycles ) ; // Finish any previous write
2019-09-30 20:29:58 +00:00
pCard - > SetSequencerFunction ( addr ) ;
2015-09-13 10:39:58 +00:00
switch ( addr & 0xF )
2007-05-28 11:16:42 +00:00
{
2019-04-08 09:41:47 +00:00
case 0x0 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x1 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x2 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x3 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x4 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x5 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x6 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x7 : pCard - > ControlStepper ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x8 : pCard - > ControlMotor ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0x9 : pCard - > ControlMotor ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0xA : pCard - > Enable ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0xB : pCard - > Enable ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
2019-07-30 21:41:28 +00:00
case 0xC : if ( ! isWOZ ) pCard - > ReadWrite ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
2019-04-08 09:41:47 +00:00
case 0xD : pCard - > LoadWriteProtect ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0xE : pCard - > SetReadMode ( pc , addr , bWrite , d , nExecutedCycles ) ; break ;
case 0xF : pCard - > SetWriteMode ( pc , addr , bWrite , d , nExecutedCycles ) ; 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)
2019-10-05 08:53:02 +00:00
if ( pCard - > m_seqFunc . function = = dataLoadWrite )
2015-09-13 10:39:58 +00:00
{
2019-04-07 14:54:26 +00:00
pCard - > m_floppyLatch = d ;
2019-07-30 21:41:28 +00:00
if ( isWOZ )
2020-02-09 21:23:15 +00:00
pCard - > DataLatchReadWriteWOZ ( pc , addr , bWrite , nExecutedCycles ) ;
2015-09-13 10:39:58 +00:00
}
2019-07-30 21:41:28 +00:00
2007-05-28 11:16:42 +00:00
return 0 ;
}
//===========================================================================
2019-02-02 15:51:27 +00:00
// Unit version history:
2018-01-14 18:01:22 +00:00
// 2: Added: Format Track state & DiskLastCycle
2018-10-02 21:08:54 +00:00
// 3: Added: DiskLastReadLatchCycle
2019-07-05 22:01:19 +00:00
// 4: Added: WOZ state
// Split up 'Unit' putting some state into a new 'Floppy'
2019-10-05 08:53:02 +00:00
// 5: Added: Sequencer Function
2020-12-12 20:05:29 +00:00
// 6: Added: Drive Connected & Motor On Cycle
static const UINT kUNIT_VERSION = 6 ;
2018-01-14 18:01:22 +00:00
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"
2019-10-05 08:53:02 +00:00
# define SS_YAML_KEY_FLOPPY_WRITE_MODE "Floppy Write Mode" // deprecated at v5
2018-01-14 18:01:22 +00:00
# define SS_YAML_KEY_LAST_CYCLE "Last Cycle"
2018-10-02 21:08:54 +00:00
# define SS_YAML_KEY_LAST_READ_LATCH_CYCLE "Last Read Latch Cycle"
2019-07-05 22:01:19 +00:00
# define SS_YAML_KEY_LSS_SHIFT_REG "LSS Shift Reg"
# define SS_YAML_KEY_LSS_LATCH_DELAY "LSS Latch Delay"
# define SS_YAML_KEY_LSS_RESET_SEQUENCER "LSS Reset Sequencer"
2019-10-05 08:53:02 +00:00
# define SS_YAML_KEY_LSS_SEQUENCER_FUNCTION "LSS Sequencer Function"
2015-12-05 16:50:27 +00:00
2016-02-15 22:33:38 +00:00
# define SS_YAML_KEY_DISK2UNIT "Unit"
2020-12-12 20:05:29 +00:00
# define SS_YAML_KEY_DRIVE_CONNECTED "Drive Connected"
2015-12-05 16:50:27 +00:00
# define SS_YAML_KEY_PHASE "Phase"
2019-07-05 22:01:19 +00:00
# define SS_YAML_KEY_PHASE_PRECISE "Phase (precise)"
# define SS_YAML_KEY_TRACK "Track" // deprecated at v4
# define SS_YAML_KEY_HEAD_WINDOW "Head Window"
# define SS_YAML_KEY_LAST_STEPPER_CYCLE "Last Stepper Cycle"
2020-12-12 20:05:29 +00:00
# define SS_YAML_KEY_MOTOR_ON_CYCLE "Motor On Cycle"
2019-07-05 22:01:19 +00:00
# define SS_YAML_KEY_FLOPPY "Floppy"
2020-12-12 20:05:29 +00:00
# define SS_YAML_KEY_FILENAME "Filename"
2015-12-05 16:50:27 +00:00
# define SS_YAML_KEY_BYTE "Byte"
2019-07-05 22:01:19 +00:00
# define SS_YAML_KEY_NIBBLES "Nibbles"
# define SS_YAML_KEY_BIT_OFFSET "Bit Offset"
# define SS_YAML_KEY_BIT_COUNT "Bit Count"
# define SS_YAML_KEY_EXTRA_CYCLES "Extra Cycles"
2015-12-05 16:50:27 +00:00
# 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_TRACK_IMAGE_DATA "Track Image Data"
# define SS_YAML_KEY_TRACK_IMAGE_DIRTY "Track Image Dirty"
# define SS_YAML_KEY_TRACK_IMAGE "Track Image"
2019-04-14 16:00:15 +00:00
std : : string Disk2InterfaceCard : : GetSnapshotCardName ( void )
2015-12-05 16:50:27 +00:00
{
static const std : : string name ( SS_YAML_VALUE_CARD_DISK2 ) ;
return name ;
}
2019-07-05 22:01:19 +00:00
void Disk2InterfaceCard : : SaveSnapshotFloppy ( YamlSaveHelper & yamlSaveHelper , UINT unit )
2015-12-05 16:50:27 +00:00
{
2019-07-05 22:01:19 +00:00
YamlSaveHelper : : Label label ( yamlSaveHelper , " %s: \n " , SS_YAML_KEY_FLOPPY ) ;
2019-04-14 15:58:49 +00:00
yamlSaveHelper . SaveString ( SS_YAML_KEY_FILENAME , m_floppyDrive [ unit ] . m_disk . m_fullname ) ;
yamlSaveHelper . SaveHexUint16 ( SS_YAML_KEY_BYTE , m_floppyDrive [ unit ] . m_disk . m_byte ) ;
yamlSaveHelper . SaveHexUint16 ( SS_YAML_KEY_NIBBLES , m_floppyDrive [ unit ] . m_disk . m_nibbles ) ;
2019-07-05 22:01:19 +00:00
yamlSaveHelper . SaveHexUint32 ( SS_YAML_KEY_BIT_OFFSET , m_floppyDrive [ unit ] . m_disk . m_bitOffset ) ; // v4
yamlSaveHelper . SaveHexUint32 ( SS_YAML_KEY_BIT_COUNT , m_floppyDrive [ unit ] . m_disk . m_bitCount ) ; // v4
yamlSaveHelper . SaveDouble ( SS_YAML_KEY_EXTRA_CYCLES , m_floppyDrive [ unit ] . m_disk . m_extraCycles ) ; // v4
yamlSaveHelper . SaveBool ( SS_YAML_KEY_WRITE_PROTECTED , m_floppyDrive [ unit ] . m_disk . m_bWriteProtected ) ;
2019-04-14 15:58:49 +00:00
yamlSaveHelper . SaveUint ( SS_YAML_KEY_TRACK_IMAGE_DATA , m_floppyDrive [ unit ] . m_disk . m_trackimagedata ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_TRACK_IMAGE_DIRTY , m_floppyDrive [ unit ] . m_disk . m_trackimagedirty ) ;
2019-04-14 15:47:41 +00:00
2019-04-14 15:58:49 +00:00
if ( m_floppyDrive [ unit ] . m_disk . m_trackimage )
2015-12-05 16:50:27 +00:00
{
YamlSaveHelper : : Label image ( yamlSaveHelper , " %s: \n " , SS_YAML_KEY_TRACK_IMAGE ) ;
2019-12-31 12:07:45 +00:00
yamlSaveHelper . SaveMemory ( m_floppyDrive [ unit ] . m_disk . m_trackimage , ImageGetMaxNibblesPerTrack ( m_floppyDrive [ unit ] . m_disk . m_imagehandle ) ) ;
2015-12-05 16:50:27 +00:00
}
}
2019-07-05 22:01:19 +00:00
void Disk2InterfaceCard : : SaveSnapshotDriveUnit ( YamlSaveHelper & yamlSaveHelper , UINT unit )
{
YamlSaveHelper : : Label label ( yamlSaveHelper , " %s%d: \n " , SS_YAML_KEY_DISK2UNIT , unit ) ;
2020-12-12 20:05:29 +00:00
yamlSaveHelper . SaveBool ( SS_YAML_KEY_DRIVE_CONNECTED , m_floppyDrive [ unit ] . m_isConnected ) ;
2019-07-05 22:01:19 +00:00
yamlSaveHelper . SaveUint ( SS_YAML_KEY_PHASE , m_floppyDrive [ unit ] . m_phase ) ;
yamlSaveHelper . SaveFloat ( SS_YAML_KEY_PHASE_PRECISE , m_floppyDrive [ unit ] . m_phasePrecise ) ; // v4
yamlSaveHelper . SaveHexUint4 ( SS_YAML_KEY_HEAD_WINDOW , m_floppyDrive [ unit ] . m_headWindow ) ; // v4
yamlSaveHelper . SaveHexUint64 ( SS_YAML_KEY_LAST_STEPPER_CYCLE , m_floppyDrive [ unit ] . m_lastStepperCycle ) ; // v4
2020-12-12 20:05:29 +00:00
yamlSaveHelper . SaveHexUint64 ( SS_YAML_KEY_MOTOR_ON_CYCLE , m_floppyDrive [ unit ] . m_motorOnCycle ) ; // v6
2019-07-05 22:01:19 +00:00
yamlSaveHelper . SaveUint ( SS_YAML_KEY_SPINNING , m_floppyDrive [ unit ] . m_spinning ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_WRITE_LIGHT , m_floppyDrive [ unit ] . m_writelight ) ;
SaveSnapshotFloppy ( yamlSaveHelper , unit ) ;
}
2021-11-25 20:23:21 +00:00
void Disk2InterfaceCard : : SaveSnapshot ( YamlSaveHelper & yamlSaveHelper )
2015-12-05 16:50:27 +00:00
{
2019-04-08 09:41:47 +00:00
YamlSaveHelper : : Slot slot ( yamlSaveHelper , GetSnapshotCardName ( ) , m_slot , kUNIT_VERSION ) ;
2015-12-05 16:50:27 +00:00
YamlSaveHelper : : Label state ( yamlSaveHelper , " %s: \n " , SS_YAML_KEY_STATE ) ;
2019-04-07 14:54:26 +00:00
yamlSaveHelper . SaveUint ( SS_YAML_KEY_CURRENT_DRIVE , m_currDrive ) ;
2019-07-05 22:01:19 +00:00
yamlSaveHelper . SaveHexUint4 ( SS_YAML_KEY_PHASES , m_magnetStates ) ;
2018-01-14 18:01:22 +00:00
yamlSaveHelper . SaveBool ( SS_YAML_KEY_DISK_ACCESSED , false ) ; // deprecated
2019-04-07 14:54:26 +00:00
yamlSaveHelper . SaveBool ( SS_YAML_KEY_ENHANCE_DISK , m_enhanceDisk ) ;
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_FLOPPY_LATCH , m_floppyLatch ) ;
yamlSaveHelper . SaveBool ( SS_YAML_KEY_FLOPPY_MOTOR_ON , m_floppyMotorOn = = TRUE ) ;
yamlSaveHelper . SaveHexUint64 ( SS_YAML_KEY_LAST_CYCLE , m_diskLastCycle ) ; // v2
yamlSaveHelper . SaveHexUint64 ( SS_YAML_KEY_LAST_READ_LATCH_CYCLE , m_diskLastReadLatchCycle ) ; // v3
2019-07-05 22:01:19 +00:00
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_LSS_SHIFT_REG , m_shiftReg ) ; // v4
yamlSaveHelper . SaveInt ( SS_YAML_KEY_LSS_LATCH_DELAY , m_latchDelay ) ; // v4
yamlSaveHelper . SaveBool ( SS_YAML_KEY_LSS_RESET_SEQUENCER , m_resetSequencer ) ; // v4
2019-10-05 08:53:02 +00:00
yamlSaveHelper . SaveInt ( SS_YAML_KEY_LSS_SEQUENCER_FUNCTION , m_seqFunc . function ) ; // v5
2019-04-07 14:54:26 +00:00
m_formatTrack . SaveSnapshot ( yamlSaveHelper ) ; // v2
2015-12-05 16:50:27 +00:00
2019-07-05 22:01:19 +00:00
SaveSnapshotDriveUnit ( yamlSaveHelper , DRIVE_1 ) ;
SaveSnapshotDriveUnit ( yamlSaveHelper , DRIVE_2 ) ;
2015-12-05 16:50:27 +00:00
}
2019-07-05 22:01:19 +00:00
bool Disk2InterfaceCard : : LoadSnapshotFloppy ( YamlLoadHelper & yamlLoadHelper , UINT unit , UINT version , std : : vector < BYTE > & track )
2015-12-05 16:50:27 +00:00
{
2016-02-24 22:38:59 +00:00
std : : string filename = yamlLoadHelper . LoadString ( SS_YAML_KEY_FILENAME ) ;
2019-07-05 22:01:19 +00:00
bool bImageError = filename . empty ( ) ;
if ( ! bImageError )
2015-12-05 16:50:27 +00:00
{
DWORD dwAttributes = GetFileAttributes ( filename . c_str ( ) ) ;
2019-07-05 22:01:19 +00:00
if ( dwAttributes = = INVALID_FILE_ATTRIBUTES )
2015-12-05 16:50:27 +00:00
{
// Get user to browse for file
2019-04-08 09:41:47 +00:00
UserSelectNewDiskImage ( unit , filename . c_str ( ) ) ;
2015-12-05 16:50:27 +00:00
dwAttributes = GetFileAttributes ( filename . c_str ( ) ) ;
}
bImageError = ( dwAttributes = = INVALID_FILE_ATTRIBUTES ) ;
if ( ! bImageError )
{
2021-07-25 10:55:25 +00:00
if ( InsertDisk ( unit , filename , dwAttributes & FILE_ATTRIBUTE_READONLY , IMAGE_DONT_CREATE ) ! = eIMAGE_ERROR_NONE )
2015-12-05 16:50:27 +00:00
bImageError = true ;
2019-12-31 12:07:45 +00:00
// InsertDisk() zeros m_floppyDrive[unit], then sets up:
2019-07-05 22:01:19 +00:00
// . m_imagename
// . m_fullname
// . m_bWriteProtected
2015-12-05 16:50:27 +00:00
}
}
2016-03-01 22:31:17 +00:00
yamlLoadHelper . LoadBool ( SS_YAML_KEY_WRITE_PROTECTED ) ; // Consume
2019-07-05 22:01:19 +00:00
m_floppyDrive [ unit ] . m_disk . m_byte = yamlLoadHelper . LoadUint ( SS_YAML_KEY_BYTE ) ;
m_floppyDrive [ unit ] . m_disk . m_nibbles = yamlLoadHelper . LoadUint ( SS_YAML_KEY_NIBBLES ) ;
m_floppyDrive [ unit ] . m_disk . m_trackimagedata = yamlLoadHelper . LoadUint ( SS_YAML_KEY_TRACK_IMAGE_DATA ) ? true : false ;
m_floppyDrive [ unit ] . m_disk . m_trackimagedirty = yamlLoadHelper . LoadUint ( SS_YAML_KEY_TRACK_IMAGE_DIRTY ) ? true : false ;
if ( version > = 4 )
{
m_floppyDrive [ unit ] . m_disk . m_bitOffset = yamlLoadHelper . LoadUint ( SS_YAML_KEY_BIT_OFFSET ) ;
m_floppyDrive [ unit ] . m_disk . m_bitCount = yamlLoadHelper . LoadUint ( SS_YAML_KEY_BIT_COUNT ) ;
m_floppyDrive [ unit ] . m_disk . m_extraCycles = yamlLoadHelper . LoadDouble ( SS_YAML_KEY_EXTRA_CYCLES ) ;
if ( m_floppyDrive [ unit ] . m_disk . m_bitCount & & ( m_floppyDrive [ unit ] . m_disk . m_bitOffset > = m_floppyDrive [ unit ] . m_disk . m_bitCount ) )
2021-12-18 16:37:28 +00:00
throw std : : runtime_error ( " Disk image: bitOffset >= bitCount " ) ;
2019-07-05 22:01:19 +00:00
if ( ImageIsWOZ ( m_floppyDrive [ unit ] . m_disk . m_imagehandle ) )
UpdateBitStreamOffsets ( m_floppyDrive [ unit ] . m_disk ) ; // overwrites m_byte, inits m_bitMask
}
2015-12-05 16:50:27 +00:00
2016-02-14 16:01:30 +00:00
if ( yamlLoadHelper . GetSubMap ( SS_YAML_KEY_TRACK_IMAGE ) )
{
2019-12-31 12:52:10 +00:00
yamlLoadHelper . LoadMemory ( track , ImageGetMaxNibblesPerTrack ( m_floppyDrive [ unit ] . m_disk . m_imagehandle ) ) ;
2016-02-14 16:01:30 +00:00
yamlLoadHelper . PopMap ( ) ;
}
2015-12-05 16:50:27 +00:00
2019-07-05 22:01:19 +00:00
return bImageError ;
}
bool Disk2InterfaceCard : : LoadSnapshotDriveUnitv3 ( YamlLoadHelper & yamlLoadHelper , UINT unit , UINT version , std : : vector < BYTE > & track )
{
_ASSERT ( version < = 3 ) ;
std : : string disk2UnitName = std : : string ( SS_YAML_KEY_DISK2UNIT ) + ( unit = = DRIVE_1 ? std : : string ( " 0 " ) : std : : string ( " 1 " ) ) ;
if ( ! yamlLoadHelper . GetSubMap ( disk2UnitName ) )
2021-12-18 16:37:28 +00:00
throw std : : runtime_error ( " Card: Expected key: " + disk2UnitName ) ;
2019-07-05 22:01:19 +00:00
bool bImageError = LoadSnapshotFloppy ( yamlLoadHelper , unit , version , track ) ;
yamlLoadHelper . LoadUint ( SS_YAML_KEY_TRACK ) ; // consume
m_floppyDrive [ unit ] . m_phase = yamlLoadHelper . LoadUint ( SS_YAML_KEY_PHASE ) ;
m_floppyDrive [ unit ] . m_phasePrecise = ( float ) m_floppyDrive [ unit ] . m_phase ;
m_floppyDrive [ unit ] . m_spinning = yamlLoadHelper . LoadUint ( SS_YAML_KEY_SPINNING ) ;
m_floppyDrive [ unit ] . m_writelight = yamlLoadHelper . LoadUint ( SS_YAML_KEY_WRITE_LIGHT ) ;
yamlLoadHelper . PopMap ( ) ;
return bImageError ;
}
bool Disk2InterfaceCard : : LoadSnapshotDriveUnitv4 ( YamlLoadHelper & yamlLoadHelper , UINT unit , UINT version , std : : vector < BYTE > & track )
{
_ASSERT ( version > = 4 ) ;
std : : string disk2UnitName = std : : string ( SS_YAML_KEY_DISK2UNIT ) + ( unit = = DRIVE_1 ? std : : string ( " 0 " ) : std : : string ( " 1 " ) ) ;
if ( ! yamlLoadHelper . GetSubMap ( disk2UnitName ) )
2021-12-18 16:37:28 +00:00
throw std : : runtime_error ( " Card: Expected key: " + disk2UnitName ) ;
2019-07-05 22:01:19 +00:00
if ( ! yamlLoadHelper . GetSubMap ( SS_YAML_KEY_FLOPPY ) )
2021-12-18 16:37:28 +00:00
throw std : : runtime_error ( " Card: Expected key: " SS_YAML_KEY_FLOPPY ) ;
2019-07-05 22:01:19 +00:00
bool bImageError = LoadSnapshotFloppy ( yamlLoadHelper , unit , version , track ) ;
2015-12-05 16:50:27 +00:00
yamlLoadHelper . PopMap ( ) ;
//
2019-07-05 22:01:19 +00:00
m_floppyDrive [ unit ] . m_phase = yamlLoadHelper . LoadUint ( SS_YAML_KEY_PHASE ) ;
m_floppyDrive [ unit ] . m_phasePrecise = yamlLoadHelper . LoadFloat ( SS_YAML_KEY_PHASE_PRECISE ) ;
m_floppyDrive [ unit ] . m_headWindow = yamlLoadHelper . LoadUint ( SS_YAML_KEY_HEAD_WINDOW ) & 0xf ;
m_floppyDrive [ unit ] . m_lastStepperCycle = yamlLoadHelper . LoadUint64 ( SS_YAML_KEY_LAST_STEPPER_CYCLE ) ;
m_floppyDrive [ unit ] . m_spinning = yamlLoadHelper . LoadUint ( SS_YAML_KEY_SPINNING ) ;
m_floppyDrive [ unit ] . m_writelight = yamlLoadHelper . LoadUint ( SS_YAML_KEY_WRITE_LIGHT ) ;
2020-12-12 20:05:29 +00:00
if ( version > = 6 )
{
m_floppyDrive [ unit ] . m_isConnected = yamlLoadHelper . LoadBool ( SS_YAML_KEY_DRIVE_CONNECTED ) ;
m_floppyDrive [ unit ] . m_motorOnCycle = yamlLoadHelper . LoadUint64 ( SS_YAML_KEY_MOTOR_ON_CYCLE ) ;
}
2019-07-05 22:01:19 +00:00
yamlLoadHelper . PopMap ( ) ;
return bImageError ;
}
void Disk2InterfaceCard : : LoadSnapshotDriveUnit ( YamlLoadHelper & yamlLoadHelper , UINT unit , UINT version )
{
bool bImageError = false ;
2019-12-31 12:07:45 +00:00
std : : vector < BYTE > track ( NIBBLES_PER_TRACK ) ; // Default size - may expand vector after loading disk image (eg. WOZ Info.largestTrack)
2019-07-05 22:01:19 +00:00
if ( version < = 3 )
bImageError = LoadSnapshotDriveUnitv3 ( yamlLoadHelper , unit , version , track ) ;
else
bImageError = LoadSnapshotDriveUnitv4 ( yamlLoadHelper , unit , version , track ) ;
if ( ! bImageError )
2015-12-05 16:50:27 +00:00
{
2019-04-14 15:58:49 +00:00
if ( ( m_floppyDrive [ unit ] . m_disk . m_trackimage = = NULL ) & & m_floppyDrive [ unit ] . m_disk . m_nibbles )
2019-12-31 12:07:45 +00:00
AllocTrack ( unit , track . size ( ) ) ;
2015-12-05 16:50:27 +00:00
2019-04-14 15:58:49 +00:00
if ( m_floppyDrive [ unit ] . m_disk . m_trackimage = = NULL )
2015-12-05 16:50:27 +00:00
bImageError = true ;
else
2019-12-31 12:07:45 +00:00
memcpy ( m_floppyDrive [ unit ] . m_disk . m_trackimage , & track [ 0 ] , track . size ( ) ) ;
2015-12-05 16:50:27 +00:00
}
if ( bImageError )
{
2019-07-05 22:01:19 +00:00
m_floppyDrive [ unit ] . m_disk . m_trackimagedata = false ;
m_floppyDrive [ unit ] . m_disk . m_trackimagedirty = false ;
m_floppyDrive [ unit ] . m_disk . m_nibbles = 0 ;
2015-12-05 16:50:27 +00:00
}
}
2021-11-25 20:23:21 +00:00
bool Disk2InterfaceCard : : LoadSnapshot ( YamlLoadHelper & yamlLoadHelper , UINT version )
2015-12-05 16:50:27 +00:00
{
2018-01-14 18:01:22 +00:00
if ( version < 1 | | version > kUNIT_VERSION )
2021-12-18 16:37:28 +00:00
throw std : : runtime_error ( " Card: wrong version " ) ;
2015-12-05 16:50:27 +00:00
2019-07-05 22:01:19 +00:00
m_currDrive = yamlLoadHelper . LoadUint ( SS_YAML_KEY_CURRENT_DRIVE ) ;
m_magnetStates = yamlLoadHelper . LoadUint ( SS_YAML_KEY_PHASES ) ;
2019-04-08 09:41:47 +00:00
( void ) yamlLoadHelper . LoadBool ( SS_YAML_KEY_DISK_ACCESSED ) ; // deprecated - but retrieve the value to avoid the "State: Unknown key (Disk Accessed)" warning
2019-04-07 14:54:26 +00:00
m_enhanceDisk = yamlLoadHelper . LoadBool ( SS_YAML_KEY_ENHANCE_DISK ) ;
m_floppyLatch = yamlLoadHelper . LoadUint ( SS_YAML_KEY_FLOPPY_LATCH ) ;
2019-04-08 09:41:47 +00:00
m_floppyMotorOn = yamlLoadHelper . LoadBool ( SS_YAML_KEY_FLOPPY_MOTOR_ON ) ;
2015-12-05 16:50:27 +00:00
2018-01-14 18:01:22 +00:00
if ( version > = 2 )
{
2019-04-07 14:54:26 +00:00
m_diskLastCycle = yamlLoadHelper . LoadUint64 ( SS_YAML_KEY_LAST_CYCLE ) ;
m_formatTrack . LoadSnapshot ( yamlLoadHelper ) ;
2018-01-14 18:01:22 +00:00
}
2018-10-02 21:08:54 +00:00
if ( version > = 3 )
{
2019-04-07 14:54:26 +00:00
m_diskLastReadLatchCycle = yamlLoadHelper . LoadUint64 ( SS_YAML_KEY_LAST_READ_LATCH_CYCLE ) ;
2018-10-02 21:08:54 +00:00
}
2019-07-05 22:01:19 +00:00
if ( version > = 4 )
{
m_shiftReg = yamlLoadHelper . LoadUint ( SS_YAML_KEY_LSS_SHIFT_REG ) & 0xff ;
m_latchDelay = yamlLoadHelper . LoadInt ( SS_YAML_KEY_LSS_LATCH_DELAY ) ;
m_resetSequencer = yamlLoadHelper . LoadBool ( SS_YAML_KEY_LSS_RESET_SEQUENCER ) ;
}
2019-10-05 08:53:02 +00:00
if ( version > = 5 )
{
m_seqFunc . function = ( SEQFUNC ) yamlLoadHelper . LoadInt ( SS_YAML_KEY_LSS_SEQUENCER_FUNCTION ) ;
}
2019-10-06 15:39:43 +00:00
else
{
m_seqFunc . writeMode = yamlLoadHelper . LoadBool ( SS_YAML_KEY_FLOPPY_WRITE_MODE ) ? 1 : 0 ;
m_seqFunc . loadMode = 0 ; // Wasn't saved until v5
}
2019-10-05 08:53:02 +00:00
2015-12-05 16:50:27 +00:00
// Eject all disks first in case Drive-2 contains disk to be inserted into Drive-1
2019-04-08 09:41:47 +00:00
for ( UINT i = 0 ; i < NUM_DRIVES ; i + + )
2015-12-05 16:50:27 +00:00
{
2019-04-08 09:41:47 +00:00
EjectDisk ( i ) ; // Remove any disk & update Registry to reflect empty drive
2019-04-07 14:54:26 +00:00
m_floppyDrive [ i ] . clear ( ) ;
2015-12-05 16:50:27 +00:00
}
2019-07-05 22:01:19 +00:00
LoadSnapshotDriveUnit ( yamlLoadHelper , DRIVE_1 , version ) ;
LoadSnapshotDriveUnit ( yamlLoadHelper , DRIVE_2 , version ) ;
2015-12-05 16:50:27 +00:00
2021-01-10 16:33:06 +00:00
GetFrame ( ) . FrameRefreshStatus ( DRAW_LEDS | DRAW_BUTTON_DRIVES | DRAW_DISK_STATUS ) ;
2015-12-05 16:50:27 +00:00
return true ;
}