Refactor System::myCycles to be 64-bit instead of 32-bit.

- The cycles counter is now essentially monotonically increasing (ie, we never need to worry about it going backwards and giving a negative difference, simplifying a lot of code
- There are now reset() methods in all places that keep track of system cycles, but they are used for a full reset only; not called each frame like before (which had to be done to prevent overflow).
This commit is contained in:
Stephen Anthony 2017-09-08 11:29:30 -02:30
parent fc104c3b4a
commit ebb8725126
40 changed files with 182 additions and 339 deletions

View File

@ -56,14 +56,6 @@ class SoundNull : public Sound
*/
void setEnabled(bool enable) override { }
/**
The system cycle counter is being adjusting by the specified amount. Any
members using the system cycle counter should be adjusted as needed.
@param amount The amount the cycle counter is being adjusted by
*/
void adjustCycleCounter(Int32 amount) override { }
/**
Sets the number of channels (mono or stereo sound).
@ -110,7 +102,7 @@ class SoundNull : public Sound
@param value The value to save into the register
@param cycle The system cycle at which the register is being updated
*/
void set(uInt16 addr, uInt8 value, Int32 cycle) override { }
void set(uInt16 addr, uInt8 value, uInt64 cycle) override { }
/**
Sets the volume of the sound device to the specified level. The

View File

@ -226,12 +226,6 @@ void SoundSDL2::adjustVolume(Int8 direction)
myOSystem.frameBuffer().showMessage(message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL2::adjustCycleCounter(Int32 amount)
{
myLastRegisterSetCycle += amount;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL2::setChannels(uInt32 channels)
{
@ -249,7 +243,7 @@ void SoundSDL2::setFrameRate(float framerate)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL2::set(uInt16 addr, uInt8 value, Int32 cycle)
void SoundSDL2::set(uInt16 addr, uInt8 value, uInt64 cycle)
{
SDL_LockAudio();
@ -386,7 +380,7 @@ bool SoundSDL2::save(Serializer& out) const
for(int i = 0; i < 6; ++i)
out.putByte(0);
out.putInt(myLastRegisterSetCycle);
out.putLong(myLastRegisterSetCycle);
}
catch(...)
{
@ -423,7 +417,7 @@ bool SoundSDL2::load(Serializer& in)
for(int i = 0; i < 6; ++i)
in.getByte();
myLastRegisterSetCycle = in.getInt();
myLastRegisterSetCycle = in.getLong();
}
catch(...)
{

View File

@ -55,14 +55,6 @@ class SoundSDL2 : public Sound
*/
void setEnabled(bool state) override;
/**
The system cycle counter is being adjusting by the specified amount. Any
members using the system cycle counter should be adjusted as needed.
@param amount The amount the cycle counter is being adjusted by
*/
void adjustCycleCounter(Int32 amount) override;
/**
Sets the number of channels (mono or stereo sound). Note that this
determines how the emulation should 'mix' the channels of the TIA sound
@ -113,7 +105,7 @@ class SoundSDL2 : public Sound
@param value The value to save into the register
@param cycle The system cycle at which the register is being updated
*/
void set(uInt16 addr, uInt8 value, Int32 cycle) override;
void set(uInt16 addr, uInt8 value, uInt64 cycle) override;
/**
Sets the volume of the sound device to the specified level. The
@ -258,7 +250,7 @@ class SoundSDL2 : public Sound
bool myIsInitializedFlag;
// Indicates the cycle when a sound register was last set
Int32 myLastRegisterSetCycle;
uInt64 myLastRegisterSetCycle;
// Indicates the number of channels (mono or stereo)
uInt32 myNumChannels;

View File

@ -28,7 +28,7 @@
#include "StateManager.hxx"
#define STATE_HEADER "05000300state"
#define STATE_HEADER "05000301state"
#define MOVIE_HEADER "03030000movie"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -99,6 +99,7 @@ static const char* const pseudo_registers[][2] = {
{ "_rwport", "Address at which a read from a write port occurred" },
{ "_scan", "Current scanline count" },
{ "_fcount", "Number of frames since emulation started" },
//FIXME { "_fcycles", "Number of cycles since frame started" },
{ "_cclocks", "Color clocks on current scanline" },
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" },
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },
@ -302,13 +303,13 @@ int Debugger::step()
saveOldState();
mySystem.clearDirtyPages();
int cyc = mySystem.cycles();
uInt64 startCycle = mySystem.cycles();
unlockBankswitchState();
myOSystem.console().tia().updateScanlineByStep().flushLineCache();
lockBankswitchState();
return mySystem.cycles() - cyc;
return int(mySystem.cycles() - startCycle);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -330,14 +331,14 @@ int Debugger::trace()
saveOldState();
mySystem.clearDirtyPages();
int cyc = mySystem.cycles();
uInt64 startCycle = mySystem.cycles();
int targetPC = myCpuDebug->pc() + 3; // return address
unlockBankswitchState();
myOSystem.console().tia().updateScanlineByTrace(targetPC).flushLineCache();
lockBankswitchState();
return mySystem.cycles() - cyc;
return int(mySystem.cycles() - startCycle);
}
else
return step();

View File

@ -153,11 +153,6 @@ class Debugger : public DialogContainer
*/
const string run(const string& command);
/**
The current cycle count of the System.
*/
int cycles() const { return int(mySystem.cycles()); }
string autoExec();
string showWatches();

View File

@ -694,6 +694,12 @@ int TIADebug::frameCount() const
return myTIA.myFrameManager.frameCount();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int TIADebug::frameCycles() const
{
return myTIA.frameCycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int TIADebug::scanlines() const
{

View File

@ -159,6 +159,7 @@ class TIADebug : public DebuggerSystem
int scanlines() const;
int scanlinesLastFrame() const;
int frameCount() const;
int frameCycles() const;
int clocksThisLine() const;
bool vsync() const;
bool vblank() const;

View File

@ -129,7 +129,7 @@ void TiaInfoWidget::loadConfig()
TIADebug& tia = dbg.tiaDebug();
myFrameCount->setText(Common::Base::toString(tia.frameCount(), Common::Base::F_10));
myFrameCycles->setText(Common::Base::toString(dbg.cycles(), Common::Base::F_10));
myFrameCycles->setText(Common::Base::toString(tia.frameCycles(), Common::Base::F_10));
myVSync->setState(tia.vsync());
myVBlank->setState(tia.vblank());

View File

@ -99,13 +99,12 @@ void AtariVox::write(DigitalPin pin, bool value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariVox::clockDataIn(bool value)
{
uInt32 cycle = mySystem.cycles();
if(value && (myShiftCount == 0))
return;
// If this is the first write this frame, or if it's been a long time
// since the last write, start a new data byte.
uInt64 cycle = mySystem.cycles();
if((cycle < myLastDataWriteCycle) || (cycle > myLastDataWriteCycle + 1000))
{
myShiftRegister = 0;
@ -138,6 +137,13 @@ void AtariVox::clockDataIn(bool value)
myLastDataWriteCycle = cycle;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariVox::reset()
{
myLastDataWriteCycle = mySystem.cycles();
myEEPROM->systemReset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariVox::close()
{
@ -145,16 +151,6 @@ void AtariVox::close()
myEEPROM.reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariVox::systemCyclesReset()
{
myLastDataWriteCycle -= mySystem.cycles();
// The EEPROM keeps track of cycle counts, and needs to know when the
// cycles are reset
myEEPROM->systemCyclesReset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string AtariVox::about() const
{

View File

@ -79,6 +79,13 @@ class AtariVox : public Controller
*/
void update() override { }
/**
Notification method invoked by the system after its reset method has
been called. It may be necessary to override this method for
controllers that need to know a reset has occurred.
*/
void reset() override;
/**
Notification method invoked by the system indicating that the
console is about to be destroyed. It may be necessary to override
@ -86,13 +93,6 @@ class AtariVox : public Controller
*/
void close() override;
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
void systemCyclesReset() override;
string about() const override;
private:
@ -121,7 +121,7 @@ class AtariVox : public Controller
// The real SpeakJet chip reads data at 19200 bits/sec. Alex's
// driver code sends data at 62 CPU cycles per bit, which is
// "close enough".
uInt32 myLastDataWriteCycle;
uInt64 myLastDataWriteCycle;
// Holds information concerning serial port usage
string myAboutString;

View File

@ -26,7 +26,6 @@ CartridgeAR::CartridgeAR(const BytePtr& image, uInt32 size,
mySize(std::max(size, 8448u)),
myWriteEnabled(false),
myPower(true),
myPowerRomCycle(0),
myDataHoldRegister(0),
myNumberOfDistinctAccesses(0),
myWritePending(false),
@ -64,7 +63,6 @@ void CartridgeAR::reset()
myWriteEnabled = false;
myPower = true;
myPowerRomCycle = mySystem->cycles();
myDataHoldRegister = 0;
myNumberOfDistinctAccesses = 0;
@ -74,13 +72,6 @@ void CartridgeAR::reset()
bankConfiguration(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeAR::systemCyclesReset()
{
// Adjust cycle values
myPowerRomCycle -= mySystem->cycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeAR::install(System& system)
{
@ -243,11 +234,6 @@ bool CartridgeAR::bankConfiguration(uInt8 configuration)
// Handle ROM power configuration
myPower = !(configuration & 0x01);
if(myPower)
{
myPowerRomCycle = mySystem->cycles();
}
myWriteEnabled = configuration & 0x02;
switch((configuration >> 2) & 0x07)
@ -474,9 +460,6 @@ bool CartridgeAR::save(Serializer& out) const
// Indicates if the ROM's power is on or off
out.putBool(myPower);
// Indicates when the power was last turned on
out.putInt(myPowerRomCycle);
// Data hold register used for writing
out.putByte(myDataHoldRegister);
@ -525,9 +508,6 @@ bool CartridgeAR::load(Serializer& in)
// Indicates if the ROM's power is on or off
myPower = in.getBool();
// Indicates when the power was last turned on
myPowerRomCycle = in.getInt();
// Data hold register used for writing
myDataHoldRegister = in.getByte();

View File

@ -60,13 +60,6 @@ class CartridgeAR : public Cartridge
*/
void reset() override;
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
void systemCyclesReset() override;
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@ -208,9 +201,6 @@ class CartridgeAR : public Cartridge
// Indicates if the ROM's power is on or off
bool myPower;
// Indicates when the power was last turned on
Int32 myPowerRomCycle;
// Data hold register used for writing
uInt8 myDataHoldRegister;

View File

@ -112,14 +112,6 @@ void CartridgeBUS::consoleChanged(ConsoleTiming timing)
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeBUS::systemCyclesReset()
{
// Adjust the cycle counter so that it reflects the new value
mySystemCycles -= mySystem->cycles();
myARMCycles -= mySystem->cycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeBUS::install(System& system)
{
@ -143,7 +135,7 @@ void CartridgeBUS::install(System& system)
inline void CartridgeBUS::updateMusicModeDataFetchers()
{
// Calculate the number of cycles since the last update
Int32 cycles = mySystem->cycles() - mySystemCycles;
Int32 cycles = Int32(mySystem->cycles() - mySystemCycles);
mySystemCycles = mySystem->cycles();
// Calculate the number of BUS OSC clocks since the last update
@ -170,7 +162,7 @@ inline void CartridgeBUS::callFunction(uInt8 value)
// time for Stella as ARM code "runs in zero 6507 cycles".
case 255: // call without IRQ driven audio
try {
Int32 cycles = mySystem->cycles() - myARMCycles;
Int32 cycles = Int32(mySystem->cycles() - myARMCycles);
myARMCycles = mySystem->cycles();
myThumbEmulator->run(cycles);
@ -570,9 +562,9 @@ bool CartridgeBUS::save(Serializer& out) const
out.putShort(myJMPoperandAddress);
// Save cycles and clocks
out.putInt(mySystemCycles);
out.putLong(mySystemCycles);
out.putInt((uInt32)(myFractionalClocks * 100000000.0));
out.putInt(myARMCycles);
out.putLong(myARMCycles);
// Audio info
out.putIntArray(myMusicCounters, 3);
@ -614,9 +606,9 @@ bool CartridgeBUS::load(Serializer& in)
myJMPoperandAddress = in.getShort();
// Get system cycles and fractional clocks
mySystemCycles = (Int32)in.getInt();
mySystemCycles = in.getLong();
myFractionalClocks = (double)in.getInt() / 100000000.0;
myARMCycles = (Int32)in.getInt();
myARMCycles = in.getLong();
// Audio info
in.getIntArray(myMusicCounters, 3);

View File

@ -73,13 +73,6 @@ class CartridgeBUS : public Cartridge
*/
void consoleChanged(ConsoleTiming timing) override;
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
void systemCyclesReset() override;
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@ -252,10 +245,10 @@ class CartridgeBUS : public Cartridge
uInt16 myJMPoperandAddress;
// System cycle count when the last update to music data fetchers occurred
Int32 mySystemCycles;
uInt64 mySystemCycles;
// ARM cycle count from when the last callFunction() occurred
Int32 myARMCycles;
uInt64 myARMCycles;
// The music mode counters
uInt32 myMusicCounters[3];

View File

@ -119,14 +119,6 @@ void CartridgeCDF::consoleChanged(ConsoleTiming timing)
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCDF::systemCyclesReset()
{
// Adjust the cycle counter so that it reflects the new value
myAudioCycles -= mySystem->cycles();
myARMCycles -= mySystem->cycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCDF::install(System& system)
{
@ -145,7 +137,7 @@ void CartridgeCDF::install(System& system)
inline void CartridgeCDF::updateMusicModeDataFetchers()
{
// Calculate the number of cycles since the last update
Int32 cycles = mySystem->cycles() - myAudioCycles;
Int32 cycles = Int32(mySystem->cycles() - myAudioCycles);
myAudioCycles = mySystem->cycles();
// Calculate the number of CDF OSC clocks since the last update
@ -172,7 +164,7 @@ inline void CartridgeCDF::callFunction(uInt8 value)
// time for Stella as ARM code "runs in zero 6507 cycles".
case 255: // call without IRQ driven audio
try {
Int32 cycles = mySystem->cycles() - myARMCycles;
Int32 cycles = Int32(mySystem->cycles() - myARMCycles);
myARMCycles = mySystem->cycles();
myThumbEmulator->run(cycles);
@ -519,9 +511,9 @@ bool CartridgeCDF::save(Serializer& out) const
out.putByteArray(myMusicWaveformSize, 3);
// Save cycles and clocks
out.putInt(myAudioCycles);
out.putLong(myAudioCycles);
out.putInt((uInt32)(myFractionalClocks * 100000000.0));
out.putInt(myARMCycles);
out.putLong(myARMCycles);
}
catch(...)
{
@ -562,9 +554,9 @@ bool CartridgeCDF::load(Serializer& in)
in.getByteArray(myMusicWaveformSize, 3);
// Get cycles and clocks
myAudioCycles = (Int32)in.getInt();
myAudioCycles = in.getLong();
myFractionalClocks = (double)in.getInt() / 100000000.0;
myARMCycles = (Int32)in.getInt();
myARMCycles = in.getLong();
}
catch(...)
{

View File

@ -73,13 +73,6 @@ class CartridgeCDF : public Cartridge
*/
void consoleChanged(ConsoleTiming timing) override;
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
void systemCyclesReset() override;
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@ -239,10 +232,10 @@ class CartridgeCDF : public Cartridge
uInt16 myBankOffset;
// System cycle count from when the last update to music data fetchers occurred
Int32 myAudioCycles;
uInt64 myAudioCycles;
// ARM cycle count from when the last callFunction() occurred
Int32 myARMCycles;
uInt64 myARMCycles;
// The audio routines in the driver run in 32-bit mode and take advantage
// of the FIQ Shadow Registers which are not accessible to 16-bit thumb

View File

@ -61,13 +61,6 @@ void CartridgeCTY::reset()
bank(myStartBank);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCTY::systemCyclesReset()
{
// Adjust the cycle counter so that it reflects the new value
mySystemCycles -= mySystem->cycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCTY::install(System& system)
{
@ -296,7 +289,7 @@ bool CartridgeCTY::save(Serializer& out) const
out.putShort(myCounter);
out.putBool(myLDAimmediate);
out.putInt(myRandomNumber);
out.putInt(mySystemCycles);
out.putLong(mySystemCycles);
out.putInt(uInt32(myFractionalClocks * 100000000.0));
}
@ -325,7 +318,7 @@ bool CartridgeCTY::load(Serializer& in)
myCounter = in.getShort();
myLDAimmediate = in.getBool();
myRandomNumber = in.getInt();
mySystemCycles = in.getInt();
mySystemCycles = in.getLong();
myFractionalClocks = double(in.getInt()) / 100000000.0;
}
catch(...)
@ -513,7 +506,7 @@ void CartridgeCTY::wipeAllScores()
inline void CartridgeCTY::updateMusicModeDataFetchers()
{
// Calculate the number of cycles since the last update
Int32 cycles = mySystem->cycles() - mySystemCycles;
Int32 cycles = Int32(mySystem->cycles() - mySystemCycles);
mySystemCycles = mySystem->cycles();
// Calculate the number of DPC OSC clocks since the last update

View File

@ -130,13 +130,6 @@ class CartridgeCTY : public Cartridge
*/
void reset() override;
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
void systemCyclesReset() override;
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@ -300,7 +293,7 @@ class CartridgeCTY : public Cartridge
string myEEPROMFile;
// System cycle count when the last update to music data fetchers occurred
Int32 mySystemCycles;
uInt64 mySystemCycles;
// Fractional DPC music OSC clocks unused during the last update
double myFractionalClocks;

View File

@ -62,13 +62,6 @@ void CartridgeDPC::reset()
bank(myStartBank);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPC::systemCyclesReset()
{
// Adjust the cycle counter so that it reflects the new value
mySystemCycles -= mySystem->cycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPC::install(System& system)
{
@ -105,7 +98,7 @@ inline void CartridgeDPC::clockRandomNumberGenerator()
inline void CartridgeDPC::updateMusicModeDataFetchers()
{
// Calculate the number of cycles since the last update
Int32 cycles = mySystem->cycles() - mySystemCycles;
Int32 cycles = Int32(mySystem->cycles() - mySystemCycles);
mySystemCycles = mySystem->cycles();
// Calculate the number of DPC OSC clocks since the last update
@ -481,7 +474,7 @@ bool CartridgeDPC::save(Serializer& out) const
// The random number generator register
out.putByte(myRandomNumber);
out.putInt(mySystemCycles);
out.putLong(mySystemCycles);
out.putInt(uInt32(myFractionalClocks * 100000000.0));
}
catch(...)
@ -524,7 +517,7 @@ bool CartridgeDPC::load(Serializer& in)
myRandomNumber = in.getByte();
// Get system cycles and fractional clocks
mySystemCycles = Int32(in.getInt());
mySystemCycles = in.getLong();
myFractionalClocks = double(in.getInt()) / 100000000.0;
}
catch(...)

View File

@ -58,13 +58,6 @@ class CartridgeDPC : public Cartridge
*/
void reset() override;
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
void systemCyclesReset() override;
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@ -203,7 +196,7 @@ class CartridgeDPC : public Cartridge
uInt8 myRandomNumber;
// System cycle count when the last update to music data fetchers occurred
Int32 mySystemCycles;
uInt64 mySystemCycles;
// Fractional DPC music OSC clocks unused during the last update
double myFractionalClocks;

View File

@ -110,14 +110,6 @@ void CartridgeDPCPlus::consoleChanged(ConsoleTiming timing)
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPCPlus::systemCyclesReset()
{
// Adjust the cycle counter so that it reflects the new value
mySystemCycles -= mySystem->cycles();
myARMCycles -= mySystem->cycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPCPlus::install(System& system)
{
@ -153,7 +145,7 @@ inline void CartridgeDPCPlus::priorClockRandomNumberGenerator()
inline void CartridgeDPCPlus::updateMusicModeDataFetchers()
{
// Calculate the number of cycles since the last update
Int32 cycles = mySystem->cycles() - mySystemCycles;
Int32 cycles = Int32(mySystem->cycles() - mySystemCycles);
mySystemCycles = mySystem->cycles();
// Calculate the number of DPC OSC clocks since the last update
@ -195,7 +187,7 @@ inline void CartridgeDPCPlus::callFunction(uInt8 value)
// time for Stella as ARM code "runs in zero 6507 cycles".
case 255: // call without IRQ driven audio
try {
Int32 cycles = mySystem->cycles() - myARMCycles;
Int32 cycles = Int32(mySystem->cycles() - myARMCycles);
myARMCycles = mySystem->cycles();
myThumbEmulator->run(cycles);
@ -690,11 +682,11 @@ bool CartridgeDPCPlus::save(Serializer& out) const
out.putInt(myRandomNumber);
// Get system cycles and fractional clocks
out.putInt(mySystemCycles);
out.putLong(mySystemCycles);
out.putInt(uInt32(myFractionalClocks * 100000000.0));
// Clock info for Thumbulator
out.putInt(myARMCycles);
out.putLong(myARMCycles);
}
catch(...)
{
@ -754,11 +746,11 @@ bool CartridgeDPCPlus::load(Serializer& in)
myRandomNumber = in.getInt();
// Get system cycles and fractional clocks
mySystemCycles = in.getInt();
mySystemCycles = in.getLong();
myFractionalClocks = double(in.getInt()) / 100000000.0;
// Clock info for Thumbulator
myARMCycles = in.getInt();
myARMCycles = in.getLong();
}
catch(...)
{

View File

@ -74,13 +74,6 @@ class CartridgeDPCPlus : public Cartridge
*/
void consoleChanged(ConsoleTiming timing) override;
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
void systemCyclesReset() override;
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@ -267,13 +260,13 @@ class CartridgeDPCPlus : public Cartridge
uInt32 myRandomNumber;
// System cycle count when the last update to music data fetchers occurred
Int32 mySystemCycles;
uInt64 mySystemCycles;
// Fractional DPC music OSC clocks unused during the last update
double myFractionalClocks;
// System cycle count when the last Thumbulator::run() occurred
Int32 myARMCycles;
uInt64 myARMCycles;
// Indicates the offset into the ROM image (aligns to current bank)
uInt16 myBankOffset;

View File

@ -275,7 +275,7 @@ bool CartridgeWD::save(Serializer& out) const
out.putString(name());
out.putShort(myCurrentBank);
out.putByteArray(myRAM, 64);
out.putInt(myCyclesAtBankswitchInit);
out.putLong(myCyclesAtBankswitchInit);
out.putShort(myPendingBank);
}
catch(...)
@ -297,7 +297,7 @@ bool CartridgeWD::load(Serializer& in)
myCurrentBank = in.getShort();
in.getByteArray(myRAM, 64);
myCyclesAtBankswitchInit = in.getInt();
myCyclesAtBankswitchInit = in.getLong();
myPendingBank = in.getShort();
bank(myCurrentBank);

View File

@ -224,7 +224,7 @@ class CartridgeWD : public Cartridge
uInt16 myOffset[4];
// Indicates the cycle at which a bankswitch was initiated
uInt32 myCyclesAtBankswitchInit;
uInt64 myCyclesAtBankswitchInit;
// Indicates the bank we wish to switch to in the future
uInt16 myPendingBank;

View File

@ -171,6 +171,13 @@ class Controller : public Serializable
*/
virtual void update() = 0;
/**
Notification method invoked by the system after its reset method has
been called. It may be necessary to override this method for
controllers that need to know a reset has occurred.
*/
virtual void reset() { }
/**
Notification method invoked by the system indicating that the
console is about to be destroyed. It may be necessary to override
@ -178,13 +185,6 @@ class Controller : public Serializable
*/
virtual void close() { };
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for controllers that remember cycle counts.
*/
virtual void systemCyclesReset() { }
/**
Determines how this controller will treat values received from the
X/Y axis and left/right buttons of the mouse. Since not all controllers

View File

@ -55,13 +55,6 @@ class Device : public Serializable
*/
virtual void consoleChanged(ConsoleTiming timing) { }
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
virtual void systemCyclesReset() { }
/**
Install device in the specified system. Invoked by the system
when the device is attached to it.

View File

@ -68,19 +68,10 @@ void M6532::reset()
// Edge-detect set to negative (high to low)
myEdgeDetectPositive = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6532::systemCyclesReset()
{
// System cycles are being reset to zero so we need to adjust
// the cycle count we remembered when the timer was last set
myLastCycle -= mySystem->cycles();
mySetTimerCycle -= mySystem->cycles();
// We should also inform any 'smart' controllers as well
myConsole.leftController().systemCyclesReset();
myConsole.rightController().systemCyclesReset();
// Let the controllers know about the reset
myConsole.leftController().reset();
myConsole.rightController().reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -109,7 +100,7 @@ void M6532::update()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6532::updateEmulation()
{
uInt32 cycles = mySystem->cycles() - myLastCycle;
uInt32 cycles = uInt32(mySystem->cycles() - myLastCycle);
uInt32 subTimer = mySubTimer;
// Guard against further state changes if the debugger alread forwarded emulation
@ -361,8 +352,8 @@ bool M6532::save(Serializer& out) const
out.putInt(myDivider);
out.putBool(myTimerWrapped);
out.putBool(myWrappedThisCycle);
out.putInt(myLastCycle);
out.putInt(mySetTimerCycle);
out.putLong(myLastCycle);
out.putLong(mySetTimerCycle);
out.putByte(myDDRA);
out.putByte(myDDRB);
@ -397,8 +388,8 @@ bool M6532::load(Serializer& in)
myDivider = in.getInt();
myTimerWrapped = in.getBool();
myWrappedThisCycle = in.getBool();
myLastCycle = in.getInt();
mySetTimerCycle = in.getInt();
myLastCycle = in.getLong();
mySetTimerCycle = in.getLong();
myDDRA = in.getByte();
myDDRB = in.getByte();
@ -449,5 +440,5 @@ Int32 M6532::intimClocks()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 M6532::timerClocks() const
{
return mySystem->cycles() - mySetTimerCycle;
return uInt32(mySystem->cycles() - mySetTimerCycle);
}

View File

@ -60,13 +60,6 @@ class M6532 : public Device
*/
void reset() override;
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
void systemCyclesReset() override;
/**
Update the entire digital and analog pin state of ports A and B.
*/
@ -178,7 +171,7 @@ class M6532 : public Device
bool myWrappedThisCycle;
// Cycle when the timer set. Debugging only.
Int32 mySetTimerCycle;
uInt64 mySetTimerCycle;
// Last cycle considered in emu updates
Int32 myLastCycle;

View File

@ -144,6 +144,13 @@ void MT24LC256::update()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::systemReset()
{
myCyclesWhenSDASet = myCyclesWhenSCLSet = myCyclesWhenTimerSet =
mySystem.cycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::erase()
{
@ -151,17 +158,6 @@ void MT24LC256::erase()
myDataChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::systemCyclesReset()
{
// System cycles are being reset to zero so we need to adjust
// the cycle counts we remembered
uInt32 cycles = mySystem.cycles();
myCyclesWhenSDASet -= cycles;
myCyclesWhenSCLSet -= cycles;
myCyclesWhenTimerSet -= cycles;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::jpee_init()
{
@ -366,7 +362,7 @@ bool MT24LC256::jpee_timercheck(int mode)
{
if(myTimerActive)
{
uInt32 elapsed = mySystem.cycles() - myCyclesWhenTimerSet;
uInt32 elapsed = uInt32(mySystem.cycles() - myCyclesWhenTimerSet);
myTimerActive = elapsed < uInt32(5000000.0 / 838.0);
}
return myTimerActive;

View File

@ -50,16 +50,12 @@ class MT24LC256
void writeSDA(bool state);
void writeSCL(bool state);
/** Called when the system is being reset */
void systemReset();
/** Erase entire EEPROM to known state ($FF) */
void erase();
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
void systemCyclesReset();
private:
// I2C access code provided by Supercat
void jpee_init();
@ -85,10 +81,10 @@ class MT24LC256
bool myTimerActive;
// Indicates when the timer was set
uInt32 myCyclesWhenTimerSet;
uInt64 myCyclesWhenTimerSet;
// Indicates when the SDA and SCL pins were set/written
uInt32 myCyclesWhenSDASet, myCyclesWhenSCLSet;
uInt64 myCyclesWhenSDASet, myCyclesWhenSCLSet;
// The file containing the EEPROM data
string myDataFile;

View File

@ -72,17 +72,15 @@ void SaveKey::write(DigitalPin pin, bool value)
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SaveKey::reset()
{
myEEPROM->systemReset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SaveKey::close()
{
// Force the EEPROM object to cleanup
myEEPROM.reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SaveKey::systemCyclesReset()
{
// The EEPROM keeps track of cycle counts, and needs to know when the
// cycles are reset
myEEPROM->systemCyclesReset();
}

View File

@ -74,6 +74,13 @@ class SaveKey : public Controller
*/
void update() override { }
/**
Notification method invoked by the system after its reset method has
been called. It may be necessary to override this method for
controllers that need to know a reset has occurred.
*/
void reset() override;
/**
Notification method invoked by the system indicating that the
console is about to be destroyed. It may be necessary to override
@ -81,13 +88,6 @@ class SaveKey : public Controller
*/
void close() override;
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
void systemCyclesReset() override;
private:
// The EEPROM used in the SaveKey
unique_ptr<MT24LC256> myEEPROM;

View File

@ -133,6 +133,15 @@ void Serializer::getIntArray(uInt32* array, uInt32 size) const
myStream->read(reinterpret_cast<char*>(array), sizeof(uInt32)*size);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt64 Serializer::getLong() const
{
uInt64 val = 0;
myStream->read(reinterpret_cast<char*>(&val), sizeof(uInt64));
return val;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
double Serializer::getDouble() const
{
@ -195,6 +204,12 @@ void Serializer::putIntArray(const uInt32* array, uInt32 size)
myStream->write(reinterpret_cast<const char*>(array), sizeof(uInt32)*size);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Serializer::putLong(uInt64 value)
{
myStream->write(reinterpret_cast<char*>(&value), sizeof(uInt64));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Serializer::putDouble(double value)
{

View File

@ -27,12 +27,9 @@
stream can be either an actual file, or an in-memory structure.
Bytes are written as characters, shorts as 2 characters (16-bits),
integers as 4 characters (32-bits), strings are written as characters
prepended by the length of the string, boolean values are written using
a special character pattern.
All bytes, shorts and ints should be cast to their appropriate data type upon
method return.
integers as 4 characters (32-bits), long integers as 8 bytes (64-bits),
strings are written as characters prepended by the length of the string,
boolean values are written using a special character pattern.
@author Stephen Anthony
*/
@ -110,6 +107,13 @@ class Serializer
*/
void getIntArray(uInt32* array, uInt32 size) const;
/**
Reads a long int value (unsigned 64-bit) from the current input stream.
@result The long int value which has been read from the stream.
*/
uInt64 getLong() const;
/**
Reads a double value (signed 64-bit) from the current input stream.
@ -176,6 +180,13 @@ class Serializer
*/
void putIntArray(const uInt32* array, uInt32 size);
/**
Writes a long int value (unsigned 64-bit) to the current output stream.
@param value The long int value to write to the output stream.
*/
void putLong(uInt64 value);
/**
Writes a double value (signed 64-bit) to the current output stream.

View File

@ -47,14 +47,6 @@ class Sound : public Serializable
*/
virtual void setEnabled(bool enable) = 0;
/**
The system cycle counter is being adjusting by the specified amount. Any
members using the system cycle counter should be adjusted as needed.
@param amount The amount the cycle counter is being adjusted by
*/
virtual void adjustCycleCounter(Int32 amount) = 0;
/**
Sets the number of channels (mono or stereo sound).
@ -101,7 +93,7 @@ class Sound : public Serializable
@param value The value to save into the register
@param cycle The system cycle at which the register is being updated
*/
virtual void set(uInt16 addr, uInt8 value, Int32 cycle) = 0;
virtual void set(uInt16 addr, uInt8 value, uInt64 cycle) = 0;
/**
Sets the volume of the sound device to the specified level. The

View File

@ -69,10 +69,8 @@ void System::reset(bool autodetect)
// Provide hint to devices that autodetection is active (or not)
mySystemInAutodetect = autodetect;
// Reset system cycle counter
resetCycles();
// Reset all devices
myCycles = 0; // Must be done first (the reset() methods use its value)
myM6532.reset();
myTIA.reset();
myCart.reset();
@ -82,18 +80,6 @@ void System::reset(bool autodetect)
clearDirtyPages();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void System::resetCycles()
{
// First we let all of the device attached to me know about the reset
myM6532.systemCyclesReset();
myTIA.systemCyclesReset();
myCart.systemCyclesReset();
// Now, we reset cycle count to zero
myCycles = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void System::consoleChanged(ConsoleTiming timing)
{
@ -209,7 +195,7 @@ bool System::save(Serializer& out) const
try
{
out.putString(name());
out.putInt(myCycles);
out.putLong(myCycles);
out.putByte(myDataBusState);
// Save the state of each device
@ -241,7 +227,7 @@ bool System::load(Serializer& in)
if(in.getString() != name())
return false;
myCycles = in.getInt();
myCycles = in.getLong();
myDataBusState = in.getByte();
// Load the state of each device

View File

@ -126,12 +126,12 @@ class System : public Serializable
public:
/**
Get the number of system cycles which have passed since the last
time cycles were reset or the system was reset.
Get the number of system cycles which have passed since the
system was created.
@return The number of system cycles which have passed
*/
uInt32 cycles() const { return myCycles; }
uInt64 cycles() const { return myCycles; }
/**
Increment the system cycles by the specified number of cycles.
@ -140,14 +140,6 @@ class System : public Serializable
*/
void incrementCycles(uInt32 amount) { myCycles += amount; }
/**
Reset the system cycle count to zero. The first thing that
happens is that all devices are notified of the reset by invoking
their systemCyclesReset method then the system cycle count is
reset to zero.
*/
void resetCycles();
/**
Informs all attached devices that the console type has changed.
*/
@ -396,8 +388,8 @@ class System : public Serializable
// Cartridge device attached to the system
Cartridge& myCart;
// Number of system cycles executed since the last reset
uInt32 myCycles;
// Number of system cycles executed since instantiation
uInt64 myCycles;
// Null device to use for page which are not installed
NullDevice myNullDevice;

View File

@ -145,6 +145,8 @@ void TIA::reset()
myDelayQueue.reset();
myFrameManager.reset();
myCyclesAtFrameStart = 0;
frameReset(); // Recalculate the size of the display
// Must be done last, after all other items have reset
@ -160,16 +162,6 @@ void TIA::frameReset()
enableColorLoss(mySettings.getBool("colorloss"));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::systemCyclesReset()
{
const uInt32 cycles = mySystem->cycles();
myLastCycle -= cycles;
mySound.adjustCycleCounter(-1 * cycles);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::install(System& system)
{
@ -243,7 +235,7 @@ bool TIA::save(Serializer& out) const
out.putInt(int(myPriority));
out.putByte(mySubClock);
out.putInt(myLastCycle);
out.putLong(myLastCycle);
out.putByte(mySpriteEnabledBits);
out.putByte(myCollisionsEnabledBits);
@ -255,6 +247,8 @@ bool TIA::save(Serializer& out) const
out.putBool(myAutoFrameEnabled);
out.putByteArray(myShadowRegisters, 64);
out.putLong(myCyclesAtFrameStart);
}
catch(...)
{
@ -312,7 +306,7 @@ bool TIA::load(Serializer& in)
myPriority = Priority(in.getInt());
mySubClock = in.getByte();
myLastCycle = in.getInt();
myLastCycle = in.getLong();
mySpriteEnabledBits = in.getByte();
myCollisionsEnabledBits = in.getByte();
@ -324,6 +318,8 @@ bool TIA::load(Serializer& in)
myAutoFrameEnabled = in.getBool();
in.getByteArray(myShadowRegisters, 64);
myCyclesAtFrameStart = in.getLong();
}
catch(...)
{
@ -811,6 +807,12 @@ bool TIA::enableColorLoss(bool enabled)
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 TIA::frameCycles() const
{
return uInt32(mySystem->cycles() - myCyclesAtFrameStart);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool TIA::electronBeamPos(uInt32& x, uInt32& y) const
{
@ -1055,12 +1057,12 @@ uInt8 TIA::registerValue(uInt8 reg) const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::updateEmulation()
{
const uInt32 systemCycles = mySystem->cycles();
const uInt64 systemCycles = mySystem->cycles();
if (mySubClock > 2)
throw runtime_error("subclock exceeds range");
const uInt32 cyclesToRun = 3 * (systemCycles - myLastCycle) + mySubClock;
const uInt32 cyclesToRun = 3 * uInt32(systemCycles - myLastCycle) + mySubClock;
mySubClock = 0;
myLastCycle = systemCycles;
@ -1103,7 +1105,7 @@ void TIA::onRenderingStart()
void TIA::onFrameComplete()
{
mySystem->m6502().stop();
mySystem->resetCycles();
myCyclesAtFrameStart = mySystem->cycles();
if (myXAtRenderingStart > 0)
memset(myFramebuffer, 0, myXAtRenderingStart);

View File

@ -112,12 +112,6 @@ class TIA : public Device
*/
void frameReset();
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero.
*/
void systemCyclesReset() override;
/**
Install TIA in the specified system. Invoked by the system
when the TIA is attached to it.
@ -264,6 +258,11 @@ class TIA : public Device
*/
uInt32 scanlinesLastFrame() const { return myFrameManager.scanlinesLastFrame(); }
/**
Answers the system cycles from the start of the current frame.
*/
uInt32 frameCycles() const;
/**
Answers whether the TIA is currently in being rendered
(we're in between the start and end of drawing a frame).
@ -707,6 +706,11 @@ class TIA : public Device
bool myColorLossEnabled;
bool myColorLossActive;
/**
* System cycles at the end of the previous frame / beginning of next frame
*/
uInt64 myCyclesAtFrameStart;
private:
TIA() = delete;
TIA(const TIA&) = delete;