mirror of https://github.com/stella-emu/stella.git
215 lines
5.7 KiB
C++
215 lines
5.7 KiB
C++
//============================================================================
|
|
//
|
|
// SSSS tt lll lll
|
|
// SS SS tt ll ll
|
|
// SS tttttt eeee ll ll aaaa
|
|
// SSSS tt ee ee ll ll aa
|
|
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
|
// SS SS tt ee ll ll aa aa
|
|
// SSSS ttt eeeee llll llll aaaaa
|
|
//
|
|
// Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony
|
|
// and the Stella Team
|
|
//
|
|
// See the file "License.txt" for information on usage and redistribution of
|
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
//
|
|
// $Id$
|
|
//============================================================================
|
|
|
|
#ifndef M6532_HXX
|
|
#define M6532_HXX
|
|
|
|
class Console;
|
|
class RiotDebug;
|
|
class Settings;
|
|
|
|
#include "bspf.hxx"
|
|
#include "Device.hxx"
|
|
#include "System.hxx"
|
|
|
|
/**
|
|
This class models the M6532 RAM-I/O-Timer (aka RIOT) chip in the 2600
|
|
console. Note that since the M6507 CPU doesn't contain an interrupt line,
|
|
the following functionality relating to the RIOT IRQ line is not emulated:
|
|
|
|
- A3 to enable/disable interrupt from timer to IRQ
|
|
- A1 to enable/disable interrupt from PA7 to IRQ
|
|
|
|
@author Bradford W. Mott and Stephen Anthony
|
|
@version $Id$
|
|
*/
|
|
class M6532 : public Device
|
|
{
|
|
public:
|
|
/**
|
|
The RIOT debugger class is a friend who needs special access
|
|
*/
|
|
friend class RiotDebug;
|
|
|
|
public:
|
|
/**
|
|
Create a new 6532 for the specified console
|
|
|
|
@param console The console the 6532 is associated with
|
|
@param settings The settings used by the system
|
|
*/
|
|
M6532(const Console& console, const Settings& settings);
|
|
|
|
/**
|
|
Destructor
|
|
*/
|
|
virtual ~M6532();
|
|
|
|
public:
|
|
/**
|
|
Reset cartridge to its power-on state
|
|
*/
|
|
void reset();
|
|
|
|
/**
|
|
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();
|
|
|
|
/**
|
|
Update the entire digital and analog pin state of ports A and B.
|
|
*/
|
|
void update();
|
|
|
|
/**
|
|
Install 6532 in the specified system. Invoked by the system
|
|
when the 6532 is attached to it.
|
|
|
|
@param system The system the device should install itself in
|
|
*/
|
|
void install(System& system);
|
|
|
|
/**
|
|
Install 6532 in the specified system and device. Invoked by
|
|
the system when the 6532 is attached to it. All devices
|
|
which invoke this method take responsibility for chaining
|
|
requests back to *this* device.
|
|
|
|
@param system The system the device should install itself in
|
|
@param device The device responsible for this address space
|
|
*/
|
|
void install(System& system, Device& device);
|
|
|
|
/**
|
|
Save the current state of this device to the given Serializer.
|
|
|
|
@param out The Serializer object to use
|
|
@return False on any errors, else true
|
|
*/
|
|
bool save(Serializer& out) const;
|
|
|
|
/**
|
|
Load the current state of this device from the given Serializer.
|
|
|
|
@param in The Serializer object to use
|
|
@return False on any errors, else true
|
|
*/
|
|
bool load(Serializer& in);
|
|
|
|
/**
|
|
Get a descriptor for the device name (used in error checking).
|
|
|
|
@return The name of the object
|
|
*/
|
|
string name() const { return "M6532"; }
|
|
|
|
public:
|
|
/**
|
|
Get the byte at the specified address
|
|
|
|
@return The byte at the specified address
|
|
*/
|
|
uInt8 peek(uInt16 address);
|
|
|
|
/**
|
|
Change the byte at the specified address to the given value
|
|
|
|
@param address The address where the value should be stored
|
|
@param value The value to be stored at the address
|
|
|
|
@return True if the poke changed the device address space, else false
|
|
*/
|
|
bool poke(uInt16 address, uInt8 value);
|
|
|
|
private:
|
|
Int32 timerClocks() const
|
|
{ return myTimer - (mySystem->cycles() - myCyclesWhenTimerSet); }
|
|
|
|
void setTimerRegister(uInt8 data, uInt8 interval);
|
|
void setPinState(bool shcha);
|
|
|
|
// The following are used by the debugger to read INTIM/TIMINT
|
|
// We need separate methods to do this, so the state of the system
|
|
// isn't changed
|
|
uInt8 intim() const;
|
|
uInt8 timint() const;
|
|
Int32 intimClocks() const;
|
|
|
|
private:
|
|
// Accessible bits in the interrupt flag register
|
|
// All other bits are always zeroed
|
|
enum {
|
|
TimerBit = 0x80,
|
|
PA7Bit = 0x40
|
|
};
|
|
|
|
// Reference to the console
|
|
const Console& myConsole;
|
|
|
|
// Reference to the settings
|
|
const Settings& mySettings;
|
|
|
|
// An amazing 128 bytes of RAM
|
|
uInt8 myRAM[128];
|
|
|
|
// Current value of the timer
|
|
uInt32 myTimer;
|
|
|
|
// Log base 2 of the number of cycles in a timer interval
|
|
uInt32 myIntervalShift;
|
|
|
|
// Indicates the number of cycles when the timer was last set
|
|
Int32 myCyclesWhenTimerSet;
|
|
|
|
// Data Direction Register for Port A
|
|
uInt8 myDDRA;
|
|
|
|
// Data Direction Register for Port B
|
|
uInt8 myDDRB;
|
|
|
|
// Last value written to Port A
|
|
uInt8 myOutA;
|
|
|
|
// Last value written to Port B
|
|
uInt8 myOutB;
|
|
|
|
// Interrupt Flag Register
|
|
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;
|
|
|
|
// Used to determine whether an active transition on PA7 has occurred
|
|
// True is positive edge-detect, false is negative edge-detect
|
|
bool myEdgeDetectPositive;
|
|
|
|
// Last value written to the timer registers
|
|
uInt8 myOutTimer[4];
|
|
|
|
private:
|
|
// Copy constructor and assignment operator not supported
|
|
M6532(const M6532&);
|
|
M6532& operator = (const M6532&);
|
|
};
|
|
|
|
#endif
|