mirror of https://github.com/stella-emu/stella.git
Restructured the RIOT handling of reads from INTIM and TIMINT. Also removed
all aspects of the M6532 chip that a real 2600 console doesn't use. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2549 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
d5269bce26
commit
b59c95062c
|
@ -20,6 +20,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "Debugger.hxx"
|
||||||
#include "Console.hxx"
|
#include "Console.hxx"
|
||||||
#include "Settings.hxx"
|
#include "Settings.hxx"
|
||||||
#include "Switches.hxx"
|
#include "Switches.hxx"
|
||||||
|
@ -27,6 +28,8 @@
|
||||||
|
|
||||||
#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),
|
||||||
|
@ -54,14 +57,15 @@ void M6532::reset()
|
||||||
myTimer = (0xff - (mySystem->randGenerator().next() % 0xfe)) << 10;
|
myTimer = (0xff - (mySystem->randGenerator().next() % 0xfe)) << 10;
|
||||||
myIntervalShift = 10;
|
myIntervalShift = 10;
|
||||||
myCyclesWhenTimerSet = 0;
|
myCyclesWhenTimerSet = 0;
|
||||||
myInterruptEnabled = false;
|
|
||||||
myInterruptTriggered = false;
|
|
||||||
|
|
||||||
// Zero the I/O registers
|
// Zero the I/O registers
|
||||||
myDDRA = myDDRB = myOutA = myOutB = 0x00;
|
myDDRA = myDDRB = myOutA = myOutB = 0x00;
|
||||||
|
|
||||||
// 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
|
||||||
|
myInterruptFlag = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -115,6 +119,8 @@ uInt8 M6532::peek(uInt16 addr)
|
||||||
return myRAM[addr & 0x007f];
|
return myRAM[addr & 0x007f];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//cerr << Debugger::debugger().valueToString(addr&0xff, kBASE_2_8) << endl;
|
||||||
|
|
||||||
switch(addr & 0x07)
|
switch(addr & 0x07)
|
||||||
{
|
{
|
||||||
case 0x00: // SWCHA - Port A I/O Register (Joystick)
|
case 0x00: // SWCHA - Port A I/O Register (Joystick)
|
||||||
|
@ -147,38 +153,16 @@ uInt8 M6532::peek(uInt16 addr)
|
||||||
case 0x04: // Timer Output
|
case 0x04: // Timer Output
|
||||||
case 0x06:
|
case 0x06:
|
||||||
{
|
{
|
||||||
myInterruptTriggered = false;
|
// Update timer state and return the resulting clock
|
||||||
Int32 timer = timerClocks();
|
return updateTimer();
|
||||||
|
|
||||||
// See if the timer has expired yet?
|
|
||||||
// Note that this constant comes from z26, and corresponds to
|
|
||||||
// 256 intervals of T1024T (ie, the maximum that the timer should hold)
|
|
||||||
// I'm not sure why this is required, but quite a few PAL ROMs fail
|
|
||||||
// if we just check >= 0.
|
|
||||||
if(!(timer & 0x40000))
|
|
||||||
{
|
|
||||||
return (timer >> myIntervalShift) & 0xff;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(timer != -1)
|
|
||||||
myInterruptTriggered = true;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x05: // Interrupt Flag
|
case 0x05: // Interrupt Flag
|
||||||
case 0x07:
|
case 0x07:
|
||||||
{
|
{
|
||||||
if((timerClocks() >= 0) || (myInterruptEnabled && myInterruptTriggered))
|
// Update timer state and return the resulting flag(s)
|
||||||
return 0x00;
|
updateTimer();
|
||||||
else
|
return myInterruptFlag;
|
||||||
return 0x80;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -208,10 +192,7 @@ bool M6532::poke(uInt16 addr, uInt8 value)
|
||||||
if((addr & 0x04) != 0)
|
if((addr & 0x04) != 0)
|
||||||
{
|
{
|
||||||
if((addr & 0x10) != 0)
|
if((addr & 0x10) != 0)
|
||||||
{
|
|
||||||
myInterruptEnabled = (addr & 0x08);
|
|
||||||
setTimerRegister(value, addr & 0x03);
|
setTimerRegister(value, addr & 0x03);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -252,11 +233,13 @@ void M6532::setTimerRegister(uInt8 value, uInt8 interval)
|
||||||
{
|
{
|
||||||
static const uInt8 shift[] = { 0, 3, 6, 10 };
|
static const uInt8 shift[] = { 0, 3, 6, 10 };
|
||||||
|
|
||||||
myInterruptTriggered = false;
|
|
||||||
myIntervalShift = shift[interval];
|
myIntervalShift = shift[interval];
|
||||||
myOutTimer[interval] = value;
|
myOutTimer[interval] = value;
|
||||||
myTimer = value << myIntervalShift;
|
myTimer = value << myIntervalShift;
|
||||||
myCyclesWhenTimerSet = mySystem->cycles();
|
myCyclesWhenTimerSet = mySystem->cycles();
|
||||||
|
|
||||||
|
// Interrupt timer flag is reset when writing to the timer
|
||||||
|
myInterruptFlag &= ~TIMER_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -293,6 +276,32 @@ 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
|
||||||
|
{
|
||||||
|
if(timer < 0)
|
||||||
|
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
|
||||||
{
|
{
|
||||||
|
@ -306,13 +315,12 @@ bool M6532::save(Serializer& out) const
|
||||||
out.putInt(myTimer);
|
out.putInt(myTimer);
|
||||||
out.putInt(myIntervalShift);
|
out.putInt(myIntervalShift);
|
||||||
out.putInt(myCyclesWhenTimerSet);
|
out.putInt(myCyclesWhenTimerSet);
|
||||||
out.putBool(myInterruptEnabled);
|
|
||||||
out.putBool(myInterruptTriggered);
|
|
||||||
|
|
||||||
out.putByte(myDDRA);
|
out.putByte(myDDRA);
|
||||||
out.putByte(myDDRB);
|
out.putByte(myDDRB);
|
||||||
out.putByte(myOutA);
|
out.putByte(myOutA);
|
||||||
out.putByte(myOutB);
|
out.putByte(myOutB);
|
||||||
|
out.putByte(myInterruptFlag);
|
||||||
out.putByteArray(myOutTimer, 4);
|
out.putByteArray(myOutTimer, 4);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
|
@ -338,13 +346,12 @@ bool M6532::load(Serializer& in)
|
||||||
myTimer = in.getInt();
|
myTimer = in.getInt();
|
||||||
myIntervalShift = in.getInt();
|
myIntervalShift = in.getInt();
|
||||||
myCyclesWhenTimerSet = in.getInt();
|
myCyclesWhenTimerSet = in.getInt();
|
||||||
myInterruptEnabled = in.getBool();
|
|
||||||
myInterruptTriggered = in.getBool();
|
|
||||||
|
|
||||||
myDDRA = in.getByte();
|
myDDRA = in.getByte();
|
||||||
myDDRB = in.getByte();
|
myDDRB = in.getByte();
|
||||||
myOutA = in.getByte();
|
myOutA = in.getByte();
|
||||||
myOutB = in.getByte();
|
myOutB = in.getByte();
|
||||||
|
myInterruptFlag = in.getByte();
|
||||||
in.getByteArray(myOutTimer, 4);
|
in.getByteArray(myOutTimer, 4);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
|
|
|
@ -29,7 +29,15 @@ class Settings;
|
||||||
#include "System.hxx"
|
#include "System.hxx"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
RIOT
|
This class models the M6532 RAM-I/O-Timer (aka RIOT) chip in the 2600
|
||||||
|
console. Note that only the functionality used by the console is
|
||||||
|
emulated here; several aspects of the chip are completely ignored:
|
||||||
|
|
||||||
|
- Pin 25 (IRQ) is not connected at all, therefore all related
|
||||||
|
items are ignored (A3 determining IRQ enable/disable, etc).
|
||||||
|
|
||||||
|
- D6 of the Interrupt Flag is ignored, including PA7 interrupt flag (A1)
|
||||||
|
and negative/positive edge-detection (A0)
|
||||||
|
|
||||||
@author Bradford W. Mott
|
@author Bradford W. Mott
|
||||||
@version $Id$
|
@version $Id$
|
||||||
|
@ -135,6 +143,7 @@ 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:
|
||||||
// Reference to the console
|
// Reference to the console
|
||||||
|
@ -155,12 +164,6 @@ class M6532 : public Device
|
||||||
// Indicates the number of cycles when the timer was last set
|
// Indicates the number of cycles when the timer was last set
|
||||||
Int32 myCyclesWhenTimerSet;
|
Int32 myCyclesWhenTimerSet;
|
||||||
|
|
||||||
// Indicates if a timer interrupt has been enabled
|
|
||||||
bool myInterruptEnabled;
|
|
||||||
|
|
||||||
// Indicates if a read from timer has taken place after interrupt occured
|
|
||||||
bool myInterruptTriggered;
|
|
||||||
|
|
||||||
// Data Direction Register for Port A
|
// Data Direction Register for Port A
|
||||||
uInt8 myDDRA;
|
uInt8 myDDRA;
|
||||||
|
|
||||||
|
@ -173,6 +176,9 @@ class M6532 : public Device
|
||||||
// Last value written to Port B
|
// Last value written to Port B
|
||||||
uInt8 myOutB;
|
uInt8 myOutB;
|
||||||
|
|
||||||
|
// Interrupt Flag Register
|
||||||
|
uInt8 myInterruptFlag;
|
||||||
|
|
||||||
// Last value written to the timer registers
|
// Last value written to the timer registers
|
||||||
uInt8 myOutTimer[4];
|
uInt8 myOutTimer[4];
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
#include "StateManager.hxx"
|
#include "StateManager.hxx"
|
||||||
|
|
||||||
#define STATE_HEADER "03070100state"
|
#define STATE_HEADER "03070101state"
|
||||||
#define MOVIE_HEADER "03030000movie"
|
#define MOVIE_HEADER "03030000movie"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
Loading…
Reference in New Issue