Some improvements to RIOT handling of INTIM and TIMINT behaviour,

particularly in edge cases.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2551 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2012-09-15 12:44:24 +00:00
parent f3d5beb3d6
commit 06854e7877
4 changed files with 50 additions and 41 deletions

View File

@ -22,7 +22,7 @@
#include <cstdlib> #include <cstdlib>
#define STELLA_VERSION "3.7.3_svn" #define STELLA_VERSION "3.8_pre1"
#define STELLA_BUILD atoi("$Rev$" + 6) #define STELLA_BUILD atoi("$Rev$" + 6)
#endif #endif

View File

@ -27,8 +27,6 @@
#include "M6532.hxx" #include "M6532.hxx"
#define TIMER_BIT 0x80
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6532::M6532(const Console& console, const Settings& settings) M6532::M6532(const Console& console, const Settings& settings)
: myConsole(console), : myConsole(console),
@ -63,8 +61,9 @@ void M6532::reset()
// Zero the timer registers // Zero the timer registers
myOutTimer[0] = myOutTimer[1] = myOutTimer[2] = myOutTimer[3] = 0x00; myOutTimer[0] = myOutTimer[1] = myOutTimer[2] = myOutTimer[3] = 0x00;
// Zero the interrupt flag register // Zero the interrupt flag register and mark D7 as invalid
myInterruptFlag = 0x00; myInterruptFlag = 0x00;
myTimerFlagValid = false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -147,18 +146,41 @@ uInt8 M6532::peek(uInt16 addr)
return myDDRB; return myDDRB;
} }
case 0x04: // Timer Output case 0x04: // INTIM - Timer Output
case 0x06: case 0x06:
{ {
// Update timer state and return the resulting clock // Timer Flag is always cleared when accessing INTIM
return updateTimer(); myInterruptFlag &= ~TimerBit;
// Get number of clocks since timer was set
Int32 timer = timerClocks();
if(timer >= 0)
{
// Return at 'divide by TIMxT' interval rate
return (timer >> myIntervalShift) & 0xff;
}
else
{
// Return at 'divide by 1' rate
uInt8 divByOne = timer & 0xff;
// Timer flag has been updated; don't update it again on TIMINT read
if(divByOne != 0 && divByOne != 255)
myTimerFlagValid = true;
return divByOne;
}
} }
case 0x05: // Interrupt Flag case 0x05: // TIMINT/INSTAT - Interrupt Flag
case 0x07: case 0x07:
{ {
// Update timer state and return the resulting flag(s) // Update timer flag if it is invalid and timer has expired
updateTimer(); if(!myTimerFlagValid && timerClocks() < 0)
{
myInterruptFlag |= TimerBit;
myTimerFlagValid = true;
}
return myInterruptFlag; return myInterruptFlag;
} }
@ -188,7 +210,7 @@ bool M6532::poke(uInt16 addr, uInt8 value)
// A2 distinguishes I/O registers from the timer // A2 distinguishes I/O registers from the timer
if((addr & 0x04) != 0) if((addr & 0x04) != 0)
{ {
if((addr & 0x10) != 0) if((addr & 0x10) != 0) // TIMxT (x = 1, 8, 64, 1024)
setTimerRegister(value, addr & 0x03); setTimerRegister(value, addr & 0x03);
} }
else else
@ -235,8 +257,9 @@ void M6532::setTimerRegister(uInt8 value, uInt8 interval)
myTimer = value << myIntervalShift; myTimer = value << myIntervalShift;
myCyclesWhenTimerSet = mySystem->cycles(); myCyclesWhenTimerSet = mySystem->cycles();
// Interrupt timer flag is reset when writing to the timer // Interrupt timer flag is cleared (and invalid) when writing to the timer
myInterruptFlag &= ~TIMER_BIT; myInterruptFlag &= ~TimerBit;
myTimerFlagValid = false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -273,32 +296,6 @@ void M6532::setPinState(bool swcha)
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 M6532::updateTimer()
{
// Get number of clocks since timer was set
Int32 timer = timerClocks();
if(timer >= 0)
{
// Timer hasn't expired yet
myInterruptFlag &= ~TIMER_BIT;
return (timer >> myIntervalShift) & 0xff;
}
else
{
// Timer has expired, set flag
myInterruptFlag |= TIMER_BIT;
// According to the M6532 documentation, the timer continues to count
// down to -255 timer clocks after wraparound. However, it isn't
// entirely clear what happens *after* if reaches -255.
// For now, we'll let it continuously wrap around.
return timer & 0xff;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool M6532::save(Serializer& out) const bool M6532::save(Serializer& out) const
{ {
@ -318,6 +315,7 @@ bool M6532::save(Serializer& out) const
out.putByte(myOutA); out.putByte(myOutA);
out.putByte(myOutB); out.putByte(myOutB);
out.putByte(myInterruptFlag); out.putByte(myInterruptFlag);
out.putBool(myTimerFlagValid);
out.putByteArray(myOutTimer, 4); out.putByteArray(myOutTimer, 4);
} }
catch(...) catch(...)
@ -349,6 +347,7 @@ bool M6532::load(Serializer& in)
myOutA = in.getByte(); myOutA = in.getByte();
myOutB = in.getByte(); myOutB = in.getByte();
myInterruptFlag = in.getByte(); myInterruptFlag = in.getByte();
myTimerFlagValid = in.getBool();
in.getByteArray(myOutTimer, 4); in.getByteArray(myOutTimer, 4);
} }
catch(...) catch(...)

View File

@ -143,9 +143,15 @@ class M6532 : public Device
void setTimerRegister(uInt8 data, uInt8 interval); void setTimerRegister(uInt8 data, uInt8 interval);
void setPinState(bool shcha); void setPinState(bool shcha);
uInt8 updateTimer();
private: private:
// Accessible bits in the interrupt flag register
// All other bits are always zeroed
enum {
TimerBit = 0x80,
PA7Bit = 0x40
};
// Reference to the console // Reference to the console
const Console& myConsole; const Console& myConsole;
@ -179,6 +185,10 @@ class M6532 : public Device
// Interrupt Flag Register // Interrupt Flag Register
uInt8 myInterruptFlag; uInt8 myInterruptFlag;
// Whether the timer flag (as currently set) can be used
// If it isn't valid, it will be updated as required
bool myTimerFlagValid;
// Last value written to the timer registers // Last value written to the timer registers
uInt8 myOutTimer[4]; uInt8 myOutTimer[4];

View File

@ -30,7 +30,7 @@
#include "StateManager.hxx" #include "StateManager.hxx"
#define STATE_HEADER "03070101state" #define STATE_HEADER "03070102state"
#define MOVIE_HEADER "03030000movie" #define MOVIE_HEADER "03030000movie"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -