#include <assert.h>
#include "Console.hxx"
#include "M6532.hxx"
#include "Switches.hxx"
#include "System.hxx"
#include "Serializer.hxx"
#include "Deserializer.hxx"
#include "OSystem.hxx"
#include <iostream>
using namespace std;
#include "../common/Log.hpp"
M6532::M6532(const Console& console)
: myConsole(console)
{
for(uInt32 t = 0; t < 128; ++t)
{
myRAM[t] = myConsole.osystem().rng().next();
}
reset();
}
M6532::~M6532()
{
}
const char* M6532::name() const
{
return "M6532";
}
void M6532::reset()
{
myTimer = 25 + (myConsole.osystem().rng().next() % 75);
myIntervalShift = 6;
myCyclesWhenTimerSet = 0;
myCyclesWhenInterruptReset = 0;
myTimerReadAfterInterrupt = false;
myDDRA = 0x00;
myDDRB = 0x00;
}
void M6532::systemCyclesReset()
{
myCyclesWhenTimerSet -= mySystem->cycles();
myCyclesWhenInterruptReset -= mySystem->cycles();
}
void M6532::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
assert((0x1080 & mask) == 0);
System::PageAccess access;
access.device = this;
for(int address = 0; address < 8192; address += (1 << shift))
{
if((address & 0x1080) == 0x0080)
{
if((address & 0x0200) == 0x0000)
{
access.directPeekBase = &myRAM[address & 0x007f];
access.directPokeBase = &myRAM[address & 0x007f];
mySystem->setPageAccess(address >> shift, access);
}
else
{
access.directPeekBase = 0;
access.directPokeBase = 0;
mySystem->setPageAccess(address >> shift, access);
}
}
}
}
uInt8 M6532::peek(uInt16 addr)
{
switch(addr & 0x07)
{
case 0x00: {
uInt8 value = 0x00;
if(myConsole.controller(Controller::Left).read(Controller::One))
value |= 0x10;
if(myConsole.controller(Controller::Left).read(Controller::Two))
value |= 0x20;
if(myConsole.controller(Controller::Left).read(Controller::Three))
value |= 0x40;
if(myConsole.controller(Controller::Left).read(Controller::Four))
value |= 0x80;
if(myConsole.controller(Controller::Right).read(Controller::One))
value |= 0x01;
if(myConsole.controller(Controller::Right).read(Controller::Two))
value |= 0x02;
if(myConsole.controller(Controller::Right).read(Controller::Three))
value |= 0x04;
if(myConsole.controller(Controller::Right).read(Controller::Four))
value |= 0x08;
return value;
}
case 0x01: {
return myDDRA;
}
case 0x02: {
return myConsole.switches().read();
}
case 0x03: {
return myDDRB;
}
case 0x04: case 0x06:
{
uInt32 cycles = mySystem->cycles() - 1;
uInt32 delta = cycles - myCyclesWhenTimerSet;
Int32 timer = (Int32)myTimer - (Int32)(delta >> myIntervalShift) - 1;
if(timer >= 0)
{
return (uInt8)timer;
}
else
{
timer = (Int32)(myTimer << myIntervalShift) - (Int32)delta - 1;
if((timer <= -2) && !myTimerReadAfterInterrupt)
{
myTimerReadAfterInterrupt = true;
myCyclesWhenInterruptReset = mySystem->cycles();
}
if(myTimerReadAfterInterrupt)
{
Int32 offset = myCyclesWhenInterruptReset -
(myCyclesWhenTimerSet + (myTimer << myIntervalShift));
timer = (Int32)myTimer - (Int32)(delta >> myIntervalShift) - offset;
}
return (uInt8)timer;
}
}
case 0x05: case 0x07:
{
uInt32 cycles = mySystem->cycles() - 1;
uInt32 delta = cycles - myCyclesWhenTimerSet;
Int32 timer = (Int32)myTimer - (Int32)(delta >> myIntervalShift) - 1;
if((timer >= 0) || myTimerReadAfterInterrupt)
return 0x00;
else
return 0x80;
}
default:
{
#ifdef DEBUG_ACCESSES
ale::Logger::Error << "BAD M6532 Peek: " << hex << addr << endl;
#endif
return 0;
}
}
}
void M6532::poke(uInt16 addr, uInt8 value)
{
if((addr & 0x07) == 0x00) {
uInt8 a = value & myDDRA;
myConsole.controller(Controller::Left).write(Controller::One, a & 0x10);
myConsole.controller(Controller::Left).write(Controller::Two, a & 0x20);
myConsole.controller(Controller::Left).write(Controller::Three, a & 0x40);
myConsole.controller(Controller::Left).write(Controller::Four, a & 0x80);
myConsole.controller(Controller::Right).write(Controller::One, a & 0x01);
myConsole.controller(Controller::Right).write(Controller::Two, a & 0x02);
myConsole.controller(Controller::Right).write(Controller::Three, a & 0x04);
myConsole.controller(Controller::Right).write(Controller::Four, a & 0x08);
}
else if((addr & 0x07) == 0x01) {
myDDRA = value;
#ifdef ATARIVOX_SUPPORT
Controller &c = myConsole.controller(Controller::Right);
if(c.type() == Controller::AtariVox) {
c.write(Controller::One, !(value & 0x01));
c.write(Controller::Two, !(value & 0x02));
c.write(Controller::Three, !(value & 0x04));
c.write(Controller::Four, !(value & 0x08));
}
#endif
}
else if((addr & 0x07) == 0x02) {
return;
}
else if((addr & 0x07) == 0x03) {
return;
}
else if((addr & 0x17) == 0x14) {
myTimer = value;
myIntervalShift = 0;
myCyclesWhenTimerSet = mySystem->cycles();
myTimerReadAfterInterrupt = false;
}
else if((addr & 0x17) == 0x15) {
myTimer = value;
myIntervalShift = 3;
myCyclesWhenTimerSet = mySystem->cycles();
myTimerReadAfterInterrupt = false;
}
else if((addr & 0x17) == 0x16) {
myTimer = value;
myIntervalShift = 6;
myCyclesWhenTimerSet = mySystem->cycles();
myTimerReadAfterInterrupt = false;
}
else if((addr & 0x17) == 0x17) {
myTimer = value;
myIntervalShift = 10;
myCyclesWhenTimerSet = mySystem->cycles();
myTimerReadAfterInterrupt = false;
}
else if((addr & 0x14) == 0x04) {
#ifdef DEBUG_ACCESSES
ale::Logger::Error << "M6532 Poke (Write Edge Detect): "
<< ((addr & 0x02) ? "PA7 enabled" : "PA7 disabled")
<< ", "
<< ((addr & 0x01) ? "Positive edge" : "Negative edge")
<< endl;
#endif
}
else
{
#ifdef DEBUG_ACCESSES
ale::Logger::Error << "BAD M6532 Poke: " << hex << addr << endl;
#endif
}
}
bool M6532::save(Serializer& out)
{
string device = name();
try
{
out.putString(device);
out.putInt(128);
for(uInt32 t = 0; t < 128; ++t)
out.putInt(myRAM[t]);
out.putInt(myTimer);
out.putInt(myIntervalShift);
out.putInt(myCyclesWhenTimerSet);
out.putInt(myCyclesWhenInterruptReset);
out.putBool(myTimerReadAfterInterrupt);
out.putInt(myDDRA);
out.putInt(myDDRB);
}
catch(char *msg)
{
ale::Logger::Error << msg << endl;
return false;
}
catch(...)
{
ale::Logger::Error << "Unknown error in save state for " << device << endl;
return false;
}
return true;
}
bool M6532::load(Deserializer& in)
{
string device = name();
try
{
if(in.getString() != device)
return false;
uInt32 limit = (uInt32) in.getInt();
for(uInt32 t = 0; t < limit; ++t)
myRAM[t] = (uInt8) in.getInt();
myTimer = (uInt32) in.getInt();
myIntervalShift = (uInt32) in.getInt();
myCyclesWhenTimerSet = (uInt32) in.getInt();
myCyclesWhenInterruptReset = (uInt32) in.getInt();
myTimerReadAfterInterrupt = in.getBool();
myDDRA = (uInt8) in.getInt();
myDDRB = (uInt8) in.getInt();
}
catch(char *msg)
{
ale::Logger::Error << msg << endl;
return false;
}
catch(...)
{
ale::Logger::Error << "Unknown error in load state for " << device << endl;
return false;
}
return true;
}
M6532::M6532(const M6532& c)
: myConsole(c.myConsole)
{
assert(false);
}
M6532& M6532::operator = (const M6532&)
{
assert(false);
return *this;
}