Added TIA INPTx and VBLANK D6/D7 items to the debugger I/O tab.

git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2343 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2012-01-08 16:55:10 +00:00
parent c19d934f75
commit 293a8a69b4
14 changed files with 135 additions and 147 deletions

View File

@ -14,6 +14,9 @@
3.5 to 3.5.1: (January xx, 2012)
* Due to changes in the debugger, old state files will not work with
this release.
* Fixed bug in sound restructuring introduced in the last release; in
some cases, there could be some sound 'crackling' when starting a
ROM after at least one ROM had already been loaded.
@ -21,8 +24,12 @@
* Fixed bug in 'Fixed Debug Colors' mode; under certain circumstances,
playfield graphics could be colored as being player graphics.
* Added ability to modify the SWCHB/SWBCNT port B registers to the
debugger I/O tab.
* Several significant improvements to the debugger I/O tab:
- added controller input widgets for many of the built-in
controllers, allowing to control joysticks, paddles, etc
from within the debugger.
- added ability to modify the SWCHB/SWBCNT port B registers.
- added ability to view TIA INPTx and VBLANK latch/dump bits.
* Added CompuMate bankswitching support to the emulation core;
the SpectraVision Compumate ROM now works.

View File

@ -164,7 +164,7 @@ void Debugger::initialize()
myWidth = BSPF_max(w, 0);
myHeight = BSPF_max(h, 0);
myWidth = BSPF_max(myWidth, 1050u);
myHeight = BSPF_max(myHeight, 620u);
myHeight = BSPF_max(myHeight, 700u);
myOSystem->settings().setSize("debuggerres", myWidth, myHeight);
const GUI::Rect& r = getDialogBounds();

View File

@ -21,6 +21,7 @@
#include "System.hxx"
#include "M6532.hxx"
#include "TIA.hxx"
#include "Debugger.hxx"
#include "Switches.hxx"
@ -49,6 +50,14 @@ const DebuggerState& RiotDebug::getState()
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);
// Timer registers
myState.TIM1T = tim1T();
myState.TIM8T = tim8T();
@ -58,20 +67,6 @@ const DebuggerState& RiotDebug::getState()
myState.TIMINT = timint();
myState.TIMCLKS = timClocks();
// Controller port pins
const Controller& port0 = myConsole.controller(Controller::Left);
myState.P0_PIN1 = port0.myDigitalPinState[Controller::One];
myState.P0_PIN2 = port0.myDigitalPinState[Controller::Two];
myState.P0_PIN3 = port0.myDigitalPinState[Controller::Three];
myState.P0_PIN4 = port0.myDigitalPinState[Controller::Four];
myState.P0_PIN6 = port0.myDigitalPinState[Controller::Six];
const Controller& port1 = myConsole.controller(Controller::Right);
myState.P1_PIN1 = port1.myDigitalPinState[Controller::One];
myState.P1_PIN2 = port1.myDigitalPinState[Controller::Two];
myState.P1_PIN3 = port1.myDigitalPinState[Controller::Three];
myState.P1_PIN4 = port1.myDigitalPinState[Controller::Four];
myState.P1_PIN6 = port1.myDigitalPinState[Controller::Six];
return myState;
}
@ -92,6 +87,14 @@ void RiotDebug::saveOldState()
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);
// Timer registers
myOldState.TIM1T = tim1T();
myOldState.TIM8T = tim8T();
@ -100,20 +103,6 @@ void RiotDebug::saveOldState()
myOldState.INTIM = intim();
myOldState.TIMINT = timint();
myOldState.TIMCLKS = timClocks();
// Controller port pins
const Controller& port0 = myConsole.controller(Controller::Left);
myOldState.P0_PIN1 = port0.myDigitalPinState[Controller::One];
myOldState.P0_PIN2 = port0.myDigitalPinState[Controller::Two];
myOldState.P0_PIN3 = port0.myDigitalPinState[Controller::Three];
myOldState.P0_PIN4 = port0.myDigitalPinState[Controller::Four];
myOldState.P0_PIN6 = port0.myDigitalPinState[Controller::Six];
const Controller& port1 = myConsole.controller(Controller::Right);
myOldState.P1_PIN1 = port1.myDigitalPinState[Controller::One];
myOldState.P1_PIN2 = port1.myDigitalPinState[Controller::Two];
myOldState.P1_PIN3 = port1.myDigitalPinState[Controller::Three];
myOldState.P1_PIN4 = port1.myDigitalPinState[Controller::Four];
myOldState.P1_PIN6 = port1.myDigitalPinState[Controller::Six];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -152,6 +141,25 @@ uInt8 RiotDebug::swbcnt(int newVal)
return mySystem.peek(0x283);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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 mySystem.tia().myVBLANK & 0x40;
else if(bit == 7) // dump to ground
return mySystem.tia().myDumpEnabled;
else
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 RiotDebug::tim1T(int newVal)
{

View File

@ -40,8 +40,8 @@ class RiotState : public DebuggerState
uInt8 TIM1T, TIM8T, TIM64T, TIM1024T, INTIM, TIMINT;
Int32 TIMCLKS;
bool P0_PIN1, P0_PIN2, P0_PIN3, P0_PIN4, P0_PIN6;
bool P1_PIN1, P1_PIN2, P1_PIN3, P1_PIN4, P1_PIN6;
// These are actually from the TIA, but are I/O related
uInt8 INPT0, INPT1, INPT2, INPT3, INPT4, INPT5;
};
class RiotDebug : public DebuggerSystem
@ -61,6 +61,11 @@ class RiotDebug : public DebuggerSystem
uInt8 swchb(int newVal = -1);
uInt8 swbcnt(int newVal = -1);
/* TIA INPTx and VBLANK registers
Techically not part of the RIOT, but more appropriately placed here */
uInt8 inpt(int x);
bool vblank(int bit);
/* Timer registers & associated clock */
uInt8 tim1T(int newVal = -1);
uInt8 tim8T(int newVal = -1);

View File

@ -38,14 +38,14 @@
#include "RiotWidget.hxx"
#define CREATE_IO_REGS(desc, bits, bitsID) \
#define CREATE_IO_REGS(desc, bits, bitsID, editable) \
t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth, fontHeight, \
desc, kTextAlignLeft); \
xpos += t->getWidth() + 5; \
bits = new ToggleBitWidget(boss, font, xpos, ypos, 8, 1); \
bits->setTarget(this); \
bits->setID(bitsID); \
addFocusWidget(bits); \
if(editable) addFocusWidget(bits); else bits->setEditable(false); \
xpos += bits->getWidth() + 5; \
bits->setList(off, on);
@ -74,30 +74,28 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& font,
}
// SWCHA bits in 'poke' mode
CREATE_IO_REGS("SWCHA(W):", mySWCHAWriteBits, kSWCHABitsID);
CREATE_IO_REGS("SWCHA(W):", mySWCHAWriteBits, kSWCHABitsID, true);
col = xpos + 20; // remember this for adding widgets to the second column
// SWACNT bits
xpos = 10; ypos += lineHeight + 5;
CREATE_IO_REGS("SWACNT:", mySWACNTBits, kSWACNTBitsID);
CREATE_IO_REGS("SWACNT:", mySWACNTBits, kSWACNTBitsID, true);
// SWCHA bits in 'peek' mode
xpos = 10; ypos += lineHeight + 5;
CREATE_IO_REGS("SWCHA(R):", mySWCHAReadBits, 0);
mySWCHAReadBits->setEditable(false);
CREATE_IO_REGS("SWCHA(R):", mySWCHAReadBits, 0, false);
// SWCHB bits in 'poke' mode
xpos = 10; ypos += 2 * lineHeight;
CREATE_IO_REGS("SWCHB(W):", mySWCHBWriteBits, kSWCHBBitsID);
CREATE_IO_REGS("SWCHB(W):", mySWCHBWriteBits, kSWCHBBitsID, true);
// SWBCNT bits
xpos = 10; ypos += lineHeight + 5;
CREATE_IO_REGS("SWBCNT:", mySWBCNTBits, kSWBCNTBitsID);
CREATE_IO_REGS("SWBCNT:", mySWBCNTBits, kSWBCNTBitsID, true);
// SWCHB bits in 'peek' mode
xpos = 10; ypos += lineHeight + 5;
CREATE_IO_REGS("SWCHB(R):", mySWCHBReadBits, 0);
mySWCHBReadBits->setEditable(false);
CREATE_IO_REGS("SWCHB(R):", mySWCHBReadBits, 0, false);
// Timer registers (R/W)
const char* writeNames[] = { "TIM1T:", "TIM8T:", "TIM64T:", "TIM1024T:" };
@ -125,7 +123,6 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& font,
myTimRead = new DataGridWidget(boss, font, xpos, ypos, 1, 3, 8, 32, kBASE_16);
myTimRead->setTarget(this);
myTimRead->setEditable(false);
addFocusWidget(myTimRead);
// Controller ports
const RiotDebug& riot = instance().debugger().riotDebug();
@ -136,10 +133,46 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& font,
myRightControl = addControlWidget(boss, font, xpos, ypos,
riot.controller(Controller::Right));
// TIA INPTx registers (R), left port
const char* contLeftReadNames[] = { "INPT0:", "INPT1:", "INPT4:" };
xpos = col; ypos += myLeftControl->getHeight() + 2 * lineHeight;
for(int row = 0; row < 3; ++row)
{
new StaticTextWidget(boss, font, xpos, ypos + row*lineHeight + 2,
6*fontWidth, fontHeight, contLeftReadNames[row], kTextAlignLeft);
}
xpos += 6*fontWidth + 5;
myLeftINPT = new DataGridWidget(boss, font, xpos, ypos, 1, 3, 2, 8, kBASE_16);
myLeftINPT->setTarget(this);
myLeftINPT->setEditable(false);
// TIA INPTx registers (R), right port
const char* contRightReadNames[] = { "INPT2:", "INPT3:", "INPT5:" };
xpos = col + myLeftControl->getWidth() + 15;
for(int row = 0; row < 3; ++row)
{
new StaticTextWidget(boss, font, xpos, ypos + row*lineHeight + 2,
6*fontWidth, fontHeight, contRightReadNames[row], kTextAlignLeft);
}
xpos += 6*fontWidth + 5;
myRightINPT = new DataGridWidget(boss, font, xpos, ypos, 1, 3, 2, 8, kBASE_16);
myRightINPT->setTarget(this);
myRightINPT->setEditable(false);
// TIA INPTx VBLANK bits (D6-latch, D7-dump) (R)
xpos = col + 20; ypos += myLeftINPT->getHeight() + lineHeight;
myINPTLatch = new CheckboxWidget(boss, font, xpos, ypos, "INPT latch (VBlank D6)");
myINPTLatch->setTarget(this);
myINPTLatch->setEditable(false);
ypos += lineHeight + 5;
myINPTDump = new CheckboxWidget(boss, font, xpos, ypos, "INPT dump to gnd (VBlank D7)");
myINPTDump->setTarget(this);
myINPTDump->setEditable(false);
// PO & P1 difficulty switches
int pwidth = font.getStringWidth("B/easy");
lwidth = font.getStringWidth("P0 Diff: ");
xpos = col; ypos += myLeftControl->getHeight() + 2 * lineHeight;
xpos = col; ypos += 2 * lineHeight;
items.clear();
items.push_back("B/easy", "b");
items.push_back("A/hard", "a");
@ -221,6 +254,28 @@ void RiotWidget::loadConfig()
// Update the SWCHB register booleans (peek mode)
IO_REGS_UPDATE(mySWCHBReadBits, swchbReadBits);
// Update TIA INPTx registers
alist.clear(); vlist.clear(); changed.clear();
alist.push_back(0); vlist.push_back(state.INPT0);
changed.push_back(state.INPT0 != oldstate.INPT0);
alist.push_back(1); vlist.push_back(state.INPT1);
changed.push_back(state.INPT1 != oldstate.INPT1);
alist.push_back(4); vlist.push_back(state.INPT4);
changed.push_back(state.INPT4 != oldstate.INPT4);
myLeftINPT->setList(alist, vlist, changed);
alist.clear(); vlist.clear(); changed.clear();
alist.push_back(2); vlist.push_back(state.INPT2);
changed.push_back(state.INPT2 != oldstate.INPT2);
alist.push_back(3); vlist.push_back(state.INPT3);
changed.push_back(state.INPT3 != oldstate.INPT3);
alist.push_back(5); vlist.push_back(state.INPT5);
changed.push_back(state.INPT5 != oldstate.INPT5);
myRightINPT->setList(alist, vlist, changed);
// Update TIA VBLANK bits
myINPTLatch->setState(riot.vblank(6));
myINPTDump->setState(riot.vblank(7));
// Update timer write registers
alist.clear(); vlist.clear(); changed.clear();
alist.push_back(kTim1TID); vlist.push_back(state.TIM1T);

View File

@ -56,6 +56,11 @@ class RiotWidget : public Widget, public CommandSender
ToggleBitWidget* mySWCHBWriteBits;
ToggleBitWidget* mySWBCNTBits;
DataGridWidget* myLeftINPT;
DataGridWidget* myRightINPT;
CheckboxWidget* myINPTLatch;
CheckboxWidget* myINPTDump;
DataGridWidget* myTimWrite;
DataGridWidget* myTimRead;

View File

@ -111,7 +111,7 @@ TiaInfoWidget::~TiaInfoWidget()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TiaInfoWidget::handleMouseDown(int x, int y, int button, int clickCount)
{
cerr << "TiaInfoWidget button press: x = " << x << ", y = " << y << endl;
//cerr << "TiaInfoWidget button press: x = " << x << ", y = " << y << endl;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -45,64 +45,11 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& font,
const int fontWidth = font.getMaxCharWidth(),
fontHeight = font.getFontHeight(),
lineHeight = font.getLineHeight();
int xpos = 10, ypos = 10, lwidth = 4 * font.getMaxCharWidth();
int xpos = 10, ypos = 15 + lineHeight, lwidth = 4 * font.getMaxCharWidth();
StaticTextWidget* t;
// Create a 16x1 grid holding byte values with labels
// Only do so if we have the vertical height
// TODO - at some point, viewing RAM may be removed, as I don't know
// how useful it really is
if(h >= 400)
{
ypos += lineHeight;
myRamGrid = new DataGridWidget(boss, font, xpos + lwidth, ypos,
16, 1, 2, 8, kBASE_16);
myRamGrid->setEditable(false);
myRamGrid->setTarget(this);
myRamGrid->setID(kRamID);
addFocusWidget(myRamGrid);
t = new StaticTextWidget(boss, font, xpos, ypos + 2,
lwidth-2, fontHeight,
"00:", kTextAlignLeft);
for(int col = 0; col < 16; ++col)
{
t = new StaticTextWidget(boss, font, xpos + col*myRamGrid->colWidth() + lwidth + 7,
ypos - lineHeight,
fontWidth, fontHeight,
instance().debugger().valueToString(col, kBASE_16_1),
kTextAlignLeft);
}
xpos = 20; ypos += 2 * lineHeight;
t = new StaticTextWidget(boss, font, xpos, ypos, 6*fontWidth, fontHeight,
"Label:", kTextAlignLeft);
xpos += 6*fontWidth + 5;
myLabel = new EditTextWidget(boss, font, xpos, ypos-2, 15*fontWidth,
lineHeight, "");
myLabel->setEditable(false);
xpos += 15*fontWidth + 20;
t = new StaticTextWidget(boss, font, xpos, ypos, 4*fontWidth, fontHeight,
"Dec:", kTextAlignLeft);
xpos += 4*fontWidth + 5;
myDecValue = new EditTextWidget(boss, font, xpos, ypos-2, 4*fontWidth,
lineHeight, "");
myDecValue->setEditable(false);
xpos += 4*fontWidth + 20;
t = new StaticTextWidget(boss, font, xpos, ypos, 4*fontWidth, fontHeight,
"Bin:", kTextAlignLeft);
xpos += 4*fontWidth + 5;
myBinValue = new EditTextWidget(boss, font, xpos, ypos-2, 9*fontWidth,
lineHeight, "");
myBinValue->setEditable(false);
ypos += lineHeight + 10;
}
// Color registers
const char* regNames[] = { "COLUP0:", "COLUP1:", "COLUPF:", "COLUBK:" };
xpos = 10; ypos += lineHeight + 5;
for(int row = 0; row < 4; ++row)
{
t = new StaticTextWidget(boss, font, xpos, ypos + row*lineHeight + 2,
@ -593,14 +540,7 @@ TiaWidget::~TiaWidget()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TiaWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
{
// We simply change the values in the DataGridWidget
// It will then send the 'kDGItemDataChangedCmd' signal to change the actual
// memory location
int addr, value;
string buf;
Debugger& dbg = instance().debugger();
CartDebug& cart = dbg.cartDebug();
TIADebug& tia = dbg.tiaDebug();
switch(cmd)
@ -745,23 +685,6 @@ void TiaWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
}
break;
case kDGSelectionChangedCmd:
switch(id)
{
case kRamID:
addr = myRamGrid->getSelectedAddr();
value = myRamGrid->getSelectedValue();
// We're using the read-addresses here
// Should we also add write-addresses, or remove this entirely?
myLabel->setEditString(cart.getLabel(addr, true));
myDecValue->setEditString(dbg.valueToString(value, kBASE_10));
myBinValue->setEditString(dbg.valueToString(value, kBASE_2));
break;
}
break;
case kCheckActionCmd:
switch(id)
{
@ -888,19 +811,6 @@ void TiaWidget::fillGrid()
TiaState& state = (TiaState&) tia.getState();
TiaState& oldstate = (TiaState&) tia.getOldState();
// TIA RAM
if(myRamGrid)
{
alist.clear(); vlist.clear(); changed.clear();
for(unsigned int i = 0; i < 16; i++)
{
alist.push_back(i);
vlist.push_back(state.ram[i]);
changed.push_back(state.ram[i] != oldstate.ram[i]);
}
myRamGrid->setList(alist, vlist, changed);
}
// Color registers
alist.clear(); vlist.clear(); changed.clear();
for(unsigned int i = 0; i < 4; i++)

View File

@ -51,11 +51,6 @@ class TiaWidget : public Widget, public CommandSender
void changeColorRegs();
private:
DataGridWidget* myRamGrid;
EditTextWidget* myBinValue;
EditTextWidget* myDecValue;
EditTextWidget* myLabel;
DataGridWidget* myColorRegs;
ColorWidget* myCOLUP0Color;

View File

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

View File

@ -311,6 +311,7 @@ bool System::save(Serializer& out) const
{
out.putString(name());
out.putInt(myCycles);
out.putByte(myDataBusState);
if(!myM6502->save(out))
return false;
@ -338,6 +339,7 @@ bool System::load(Serializer& in)
return false;
myCycles = (uInt32) in.getInt();
myDataBusState = (uInt8) in.getByte();
// Next, load state for the CPU
if(!myM6502->load(in))

View File

@ -1327,7 +1327,7 @@ bool TIA::poke(uInt16 addr, uInt8 value)
myDumpDisabledCycle = mySystem->cycles();
}
// Are the latches for I4 and I5 being set?
// Are the latches for I4 and I5 being reset?
if (!(myVBLANK & 0x40))
myINPT4 = myINPT5 = 0x80;

View File

@ -47,6 +47,7 @@ class TIA : public Device
{
public:
friend class TIADebug;
friend class RiotDebug;
/**
Create a new TIA for the specified console

View File

@ -173,7 +173,7 @@ UIDialog::UIDialog(OSystem* osystem, DialogContainer* parent,
myDebuggerHeightSlider = new SliderWidget(myTab, font, xpos, ypos, pwidth,
lineHeight, "Debugger Height: ",
lwidth, kDHeightChanged);
myDebuggerHeightSlider->setMinValue(620);
myDebuggerHeightSlider->setMinValue(700);
myDebuggerHeightSlider->setMaxValue(1200);
myDebuggerHeightSlider->setStepValue(10);
wid.push_back(myDebuggerHeightSlider);
@ -381,8 +381,8 @@ void UIDialog::setDefaults()
case 1: // Debugger options
myDebuggerWidthSlider->setValue(1050);
myDebuggerWidthLabel->setValue(1050);
myDebuggerHeightSlider->setValue(690);
myDebuggerHeightLabel->setValue(690);
myDebuggerHeightSlider->setValue(700);
myDebuggerHeightLabel->setValue(700);
break;
case 2: // Misc. options