stella/src/debugger/RiotDebug.cxx

384 lines
12 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-2019 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.
//============================================================================
#include "System.hxx"
#include "TIA.hxx"
#include "M6532.hxx"
#include "Debugger.hxx"
#include "Switches.hxx"
#include "RiotDebug.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RiotDebug::RiotDebug(Debugger& dbg, Console& console)
: DebuggerSystem(dbg, console)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const DebuggerState& RiotDebug::getState()
{
// Port A & B registers
myState.SWCHA_R = swcha();
myState.SWCHA_W = mySystem.m6532().myOutA;
myState.SWACNT = swacnt();
myState.SWCHB_R = swchb();
myState.SWCHB_W = mySystem.m6532().myOutB;
myState.SWBCNT = swbcnt();
Debugger::set_bits(myState.SWCHA_R, myState.swchaReadBits);
Debugger::set_bits(myState.SWCHA_W, myState.swchaWriteBits);
Debugger::set_bits(myState.SWACNT, myState.swacntBits);
Debugger::set_bits(myState.SWCHB_R, myState.swchbReadBits);
Debugger::set_bits(myState.SWCHB_W, myState.swchbWriteBits);
Debugger::set_bits(myState.SWBCNT, myState.swbcntBits);
// TIA INPTx registers
myState.INPT0 = inpt(0);
myState.INPT1 = inpt(1);
myState.INPT2 = inpt(2);
myState.INPT3 = inpt(3);
myState.INPT4 = inpt(4);
myState.INPT5 = inpt(5);
myState.INPTLatch = vblank(6);
myState.INPTDump = vblank(7);
// Timer registers
myState.TIM1T = tim1T();
myState.TIM8T = tim8T();
myState.TIM64T = tim64T();
myState.T1024T = tim1024T();
myState.INTIM = intim();
myState.TIMINT = timint();
myState.TIMCLKS = timClocks();
myState.INTIMCLKS = intimClocks();
myState.TIMDIV = timDivider();
return myState;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RiotDebug::saveOldState()
{
// Port A & B registers
myOldState.SWCHA_R = swcha();
myOldState.SWCHA_W = mySystem.m6532().myOutA;
myOldState.SWACNT = swacnt();
myOldState.SWCHB_R = swchb();
myOldState.SWCHB_W = mySystem.m6532().myOutB;
myOldState.SWBCNT = swbcnt();
Debugger::set_bits(myOldState.SWCHA_R, myOldState.swchaReadBits);
Debugger::set_bits(myOldState.SWCHA_W, myOldState.swchaWriteBits);
Debugger::set_bits(myOldState.SWACNT, myOldState.swacntBits);
Debugger::set_bits(myOldState.SWCHB_R, myOldState.swchbReadBits);
Debugger::set_bits(myOldState.SWCHB_W, myOldState.swchbWriteBits);
Debugger::set_bits(myOldState.SWBCNT, myOldState.swbcntBits);
// TIA INPTx registers
myOldState.INPT0 = inpt(0);
myOldState.INPT1 = inpt(1);
myOldState.INPT2 = inpt(2);
myOldState.INPT3 = inpt(3);
myOldState.INPT4 = inpt(4);
myOldState.INPT5 = inpt(5);
myOldState.INPTLatch = vblank(6);
myOldState.INPTDump = vblank(7);
// Timer registers
myOldState.TIM1T = tim1T();
myOldState.TIM8T = tim8T();
myOldState.TIM64T = tim64T();
myOldState.T1024T = tim1024T();
myOldState.INTIM = intim();
myOldState.TIMINT = timint();
myOldState.TIMCLKS = timClocks();
myOldState.INTIMCLKS = intimClocks();
myOldState.TIMDIV = timDivider();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 RiotDebug::swcha(int newVal)
{
if(newVal > -1)
mySystem.poke(0x280, newVal);
return mySystem.peek(0x280);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 RiotDebug::swchb(int newVal)
{
if(newVal > -1)
mySystem.poke(0x282, newVal);
return mySystem.peek(0x282);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 RiotDebug::swacnt(int newVal)
{
if(newVal > -1)
mySystem.poke(0x281, newVal);
return mySystem.m6532().myDDRA;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 RiotDebug::swbcnt(int newVal)
{
if(newVal > -1)
mySystem.poke(0x283, newVal);
return mySystem.m6532().myDDRB;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 RiotDebug::inpt(int x)
{
static TIARegister _inpt[6] = { INPT0, INPT1, INPT2, INPT3, INPT4, INPT5 };
return mySystem.peek(_inpt[x]);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RiotDebug::vblank(int bit)
{
if(bit == 6) // latches
return myConsole.tia().myInput0.vblankLatched();
else if(bit == 7) // dump to ground
return myConsole.tia().myPaddleReaders[0].vblankDumped();
else
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 RiotDebug::tim1T(int newVal)
{
if(newVal > -1)
mySystem.poke(0x294, newVal);
return mySystem.m6532().myOutTimer[0];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 RiotDebug::tim8T(int newVal)
{
if(newVal > -1)
mySystem.poke(0x295, newVal);
return mySystem.m6532().myOutTimer[1];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 RiotDebug::tim64T(int newVal)
{
if(newVal > -1)
mySystem.poke(0x296, newVal);
return mySystem.m6532().myOutTimer[2];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 RiotDebug::tim1024T(int newVal)
{
if(newVal > -1)
mySystem.poke(0x297, newVal);
return mySystem.m6532().myOutTimer[3];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 RiotDebug::intim() const
{
return mySystem.m6532().intim();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 RiotDebug::timint() const
{
return mySystem.m6532().timint();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 RiotDebug::timClocks() const
{
return mySystem.m6532().timerClocks();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 RiotDebug::intimClocks() const
{
return mySystem.m6532().intimClocks();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 RiotDebug::timDivider() const
{
return mySystem.m6532().myDivider;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RiotDebug::diffP0(int newVal)
{
uInt8& switches = myConsole.switches().mySwitches;
if(newVal > -1)
switches = Debugger::set_bit(switches, 6, newVal > 0);
return switches & 0x40;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RiotDebug::diffP1(int newVal)
{
uInt8& switches = myConsole.switches().mySwitches;
if(newVal > -1)
switches = Debugger::set_bit(switches, 7, newVal > 0);
return switches & 0x80;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RiotDebug::tvType(int newVal)
{
uInt8& switches = myConsole.switches().mySwitches;
if(newVal > -1)
switches = Debugger::set_bit(switches, 3, newVal > 0);
return switches & 0x08;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RiotDebug::select(int newVal)
{
uInt8& switches = myConsole.switches().mySwitches;
if(newVal > -1)
switches = Debugger::set_bit(switches, 1, newVal > 0);
return switches & 0x02;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RiotDebug::reset(int newVal)
{
uInt8& switches = myConsole.switches().mySwitches;
if(newVal > -1)
switches = Debugger::set_bit(switches, 0, newVal > 0);
return switches & 0x01;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string RiotDebug::dirP0String()
{
uInt8 reg = swcha();
ostringstream buf;
buf << ((reg & 0x80) ? "" : "right ")
<< ((reg & 0x40) ? "" : "left ")
<< ((reg & 0x20) ? "" : "left ")
<< ((reg & 0x10) ? "" : "left ")
<< ((reg & 0xf0) == 0xf0 ? "(no directions) " : "");
return buf.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string RiotDebug::dirP1String()
{
uInt8 reg = swcha();
ostringstream buf;
buf << ((reg & 0x08) ? "" : "right ")
<< ((reg & 0x04) ? "" : "left ")
<< ((reg & 0x02) ? "" : "left ")
<< ((reg & 0x01) ? "" : "left ")
<< ((reg & 0x0f) == 0x0f ? "(no directions) " : "");
return buf.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string RiotDebug::diffP0String()
{
return (swchb() & 0x40) ? "hard/A" : "easy/B";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string RiotDebug::diffP1String()
{
return (swchb() & 0x80) ? "hard/A" : "easy/B";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string RiotDebug::tvTypeString()
{
return (swchb() & 0x8) ? "Color" : "B&W";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string RiotDebug::switchesString()
{
ostringstream buf;
buf << ((swchb() & 0x2) ? "-" : "+") << "select "
<< ((swchb() & 0x1) ? "-" : "+") << "reset";
return buf.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string RiotDebug::toString()
{
const RiotState& state = static_cast<const RiotState&>(getState());
const RiotState& oldstate = static_cast<const RiotState&>(getOldState());
ostringstream buf;
buf << "280/SWCHA(R)=" << myDebugger.invIfChanged(state.SWCHA_R, oldstate.SWCHA_R)
<< " 280/SWCHA(W)=" << myDebugger.invIfChanged(state.SWCHA_W, oldstate.SWCHA_W)
<< " 281/SWACNT=" << myDebugger.invIfChanged(state.SWACNT, oldstate.SWACNT)
<< endl
<< "282/SWCHB(R)=" << myDebugger.invIfChanged(state.SWCHB_R, oldstate.SWCHB_R)
<< " 282/SWCHB(W)=" << myDebugger.invIfChanged(state.SWCHB_W, oldstate.SWCHB_W)
<< " 283/SWBCNT=" << myDebugger.invIfChanged(state.SWBCNT, oldstate.SWBCNT)
<< endl
// These are squirrely: some symbol files will define these as
// 0x284-0x287. Doesn't actually matter, these registers repeat
// every 16 bytes.
<< "294/TIM1T=" << myDebugger.invIfChanged(state.TIM1T, oldstate.TIM1T)
<< " 295/TIM8T=" << myDebugger.invIfChanged(state.TIM8T, oldstate.TIM8T)
<< " 296/TIM64T=" << myDebugger.invIfChanged(state.TIM64T, oldstate.TIM64T)
<< " 297/T1024T=" << myDebugger.invIfChanged(state.T1024T, oldstate.T1024T)
<< endl
<< "0x284/INTIM=" << myDebugger.invIfChanged(state.INTIM, oldstate.INTIM)
<< " 285/TIMINT=" << myDebugger.invIfChanged(state.TIMINT, oldstate.TIMINT)
<< " Timer_Clocks=" << myDebugger.invIfChanged(state.TIMCLKS, oldstate.TIMCLKS)
<< " INTIM_Clocks=" << myDebugger.invIfChanged(state.INTIMCLKS, oldstate.INTIMCLKS)
<< " Divider=" << myDebugger.invIfChanged(state.TIMDIV, oldstate.TIMDIV)
<< endl
<< "Left/P0diff: " << diffP0String() << " Right/P1diff: " << diffP1String()
<< endl
<< "TVType: " << tvTypeString() << " Switches: " << switchesString()
<< endl
// Yes, the fire buttons are in the TIA, but we might as well
// show them here for convenience.
<< "Left/P0 stick: " << dirP0String()
<< ((mySystem.peek(0x03c) & 0x80) ? "" : "(button) ")
<< endl
<< "Right/P1 stick: " << dirP1String()
<< ((mySystem.peek(0x03d) & 0x80) ? "" : "(button) ");
return buf.str();
}