SaveKey/AtariVox detects EEPROM areas accessed by ROM and allows erasing only these in the debugger.

This commit is contained in:
thrust26 2017-09-29 20:12:41 +02:00
parent d51a9e09d6
commit a92ceed195
10 changed files with 293 additions and 112 deletions

View File

@ -22,50 +22,31 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AtariVoxWidget::AtariVoxWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, Controller& controller)
: ControllerWidget(boss, font, x, y, controller)
: FlashWidget(boss, font, x, y, controller)
{
bool leftport = myController.jack() == Controller::Left;
const string& label = leftport ? "Left (AtariVox)" : "Right (AtariVox)";
const int fontHeight = font.getFontHeight(),
lineHeight = font.getLineHeight(),
bwidth = font.getStringWidth("Erase EEPROM") + 20,
bheight = lineHeight + 4;
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (AtariVox)");
StaticTextWidget* t;
t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth,
fontHeight, label, kTextAlignLeft);
ypos += t->getHeight() + 20;
myEEPROMErase =
new ButtonWidget(boss, font, xpos+10, ypos, bwidth, bheight,
"Erase EEPROM", kEEPROMErase);
myEEPROMErase->setTarget(this);
ypos += lineHeight + 20;
const GUI::Font& ifont = instance().frameBuffer().infoFont();
lwidth = ifont.getMaxCharWidth() * 20;
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
fontHeight, "(*) This will erase", kTextAlignLeft);
ypos += lineHeight + 2;
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
fontHeight, "all EEPROM data, not", kTextAlignLeft);
ypos += lineHeight + 2;
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
fontHeight, "just the range used", kTextAlignLeft);
ypos += lineHeight + 2;
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
fontHeight, "for this ROM", kTextAlignLeft);
init(boss, font, x, y);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariVoxWidget::handleCommand(CommandSender*, int cmd, int, int)
void AtariVoxWidget::eraseCurrent()
{
if(cmd == kEEPROMErase)
{
AtariVox& avox = static_cast<AtariVox&>(myController);
avox.myEEPROM->erase();
}
AtariVox& avox = static_cast<AtariVox&>(myController);
avox.myEEPROM->eraseCurrent();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariVoxWidget::eraseAll()
{
AtariVox& avox = static_cast<AtariVox&>(myController);
avox.myEEPROM->eraseAll();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool AtariVoxWidget::isPageDetected()
{
AtariVox& avox = static_cast<AtariVox&>(myController);
return avox.myEEPROM->isPageDetected();
}

View File

@ -18,25 +18,26 @@
#ifndef ATARIVOX_WIDGET_HXX
#define ATARIVOX_WIDGET_HXX
class ButtonWidget;
#include "Control.hxx"
#include "ControllerWidget.hxx"
#include "FlashWidget.hxx"
class AtariVoxWidget : public ControllerWidget
class AtariVoxWidget : public FlashWidget
{
public:
AtariVoxWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
Controller& controller);
virtual ~AtariVoxWidget() = default;
private:
ButtonWidget* myEEPROMErase;
enum { kEEPROMErase = 'eeER' };
private:
private:
void loadConfig() override { }
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
string getName()
{
return "AtariVox";
}
void eraseCurrent();
void eraseAll();
bool isPageDetected();
// Following constructors and assignment operators not supported
AtariVoxWidget() = delete;

View File

@ -21,51 +21,32 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SaveKeyWidget::SaveKeyWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, Controller& controller)
: ControllerWidget(boss, font, x, y, controller)
int x, int y, Controller& controller)
: FlashWidget(boss, font, x, y, controller)
{
bool leftport = myController.jack() == Controller::Left;
const string& label = leftport ? "Left (SaveKey)" : "Right (SaveKey)";
const int fontHeight = font.getFontHeight(),
lineHeight = font.getLineHeight(),
bwidth = font.getStringWidth("Erase EEPROM") + 20,
bheight = lineHeight + 4;
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (SaveKey)");
StaticTextWidget* t;
t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth,
fontHeight, label, kTextAlignLeft);
ypos += t->getHeight() + 20;
myEEPROMErase =
new ButtonWidget(boss, font, xpos+10, ypos, bwidth, bheight,
"Erase EEPROM", kEEPROMErase);
myEEPROMErase->setTarget(this);
ypos += lineHeight + 20;
const GUI::Font& ifont = instance().frameBuffer().infoFont();
lwidth = ifont.getMaxCharWidth() * 20;
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
fontHeight, "(*) This will erase", kTextAlignLeft);
ypos += lineHeight + 2;
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
fontHeight, "all EEPROM data, not", kTextAlignLeft);
ypos += lineHeight + 2;
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
fontHeight, "just the range used", kTextAlignLeft);
ypos += lineHeight + 2;
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
fontHeight, "for this ROM", kTextAlignLeft);
init(boss, font, x, y);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SaveKeyWidget::handleCommand(CommandSender*, int cmd, int, int)
void SaveKeyWidget::eraseCurrent()
{
if(cmd == kEEPROMErase)
{
SaveKey& skey = static_cast<SaveKey&>(myController);
skey.myEEPROM->erase();
}
SaveKey& skey = static_cast<SaveKey&>(myController);
skey.myEEPROM->eraseCurrent();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SaveKeyWidget::eraseAll()
{
SaveKey& skey = static_cast<SaveKey&>(myController);
skey.myEEPROM->eraseAll();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SaveKeyWidget::isPageDetected()
{
SaveKey& skey = static_cast<SaveKey&>(myController);
return skey.myEEPROM->isPageDetected();
}

View File

@ -18,25 +18,26 @@
#ifndef SAVEKEY_WIDGET_HXX
#define SAVEKEY_WIDGET_HXX
class ButtonWidget;
#include "Control.hxx"
#include "ControllerWidget.hxx"
#include "FlashWidget.hxx"
class SaveKeyWidget : public ControllerWidget
class SaveKeyWidget : public FlashWidget
{
public:
SaveKeyWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
Controller& controller);
virtual ~SaveKeyWidget() = default;
private:
ButtonWidget* myEEPROMErase;
enum { kEEPROMErase = 'eeER' };
private:
void loadConfig() override { }
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
string getName()
{
return "SaveKey";
}
void eraseCurrent();
void eraseAll();
bool isPageDetected();
// Following constructors and assignment operators not supported
SaveKeyWidget() = delete;

View File

@ -55,6 +55,7 @@ MT24LC256::MT24LC256(const string& filename, const System& system)
myDataFile(filename),
myDataFileExists(false),
myDataChanged(false),
myPageDetected(false),
jpee_mdat(0),
jpee_sdat(0),
jpee_mclk(0),
@ -74,10 +75,10 @@ MT24LC256::MT24LC256(const string& filename, const System& system)
{
// Get length of file; it must be 32768
in.seekg(0, std::ios::end);
if(uInt32(in.tellg()) == 32768u)
if(uInt32(in.tellg()) == FLASH_SIZE)
{
in.seekg(0, std::ios::beg);
in.read(reinterpret_cast<char*>(myData), 32768);
in.read(reinterpret_cast<char*>(myData), FLASH_SIZE);
myDataFileExists = true;
}
}
@ -96,7 +97,7 @@ MT24LC256::~MT24LC256()
{
ofstream out(myDataFile, std::ios_base::binary);
if(out.is_open())
out.write(reinterpret_cast<char*>(myData), 32768);
out.write(reinterpret_cast<char*>(myData), FLASH_SIZE);
}
}
@ -149,27 +150,43 @@ void MT24LC256::systemReset()
{
myCyclesWhenSDASet = myCyclesWhenSCLSet = myCyclesWhenTimerSet =
mySystem.cycles();
myPageDetected = false;
memset(myPageHit, false, sizeof(myPageHit));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::erase()
void MT24LC256::eraseAll()
{
memset(myData, 0xff, 32768);
memset(myData, INIT_VALUE, FLASH_SIZE);
myDataChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::eraseCurrent()
{
for(uInt32 page = 0; page < PAGE_NUM; page++)
{
if(myPageHit[page])
{
memset(myData + page * PAGE_SIZE, INIT_VALUE, PAGE_SIZE);
myDataChanged = true;
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::jpee_init()
{
jpee_sdat = 1;
jpee_address = 0;
jpee_state=0;
jpee_sizemask = 32767;
jpee_pagemask = 63;
jpee_sizemask = FLASH_SIZE - 1;
jpee_pagemask = PAGE_SIZE - 1;
jpee_smallmode = 0;
jpee_logmode = -1;
if(!myDataFileExists)
memset(myData, 0xff, 32768);
memset(myData, INIT_VALUE, FLASH_SIZE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -226,6 +243,7 @@ void MT24LC256::jpee_data_stop()
for (int i=3; i<jpee_pptr; i++)
{
myDataChanged = true;
myPageDetected = myPageHit[jpee_address / PAGE_SIZE] = true;
myData[(jpee_address++) & jpee_sizemask] = jpee_packet[i];
if (!(jpee_address & jpee_pagemask))
break; /* Writes can't cross page boundary! */
@ -322,6 +340,7 @@ void MT24LC256::jpee_clock_fall()
break;
}
jpee_state=3;
myPageDetected = myPageHit[jpee_address / PAGE_SIZE] = true;
jpee_nb = (myData[jpee_address & jpee_sizemask] << 1) | 1; /* Fall through */
JPEE_LOG2("I2C_READ(%04X=%02X)",jpee_address,jpee_nb/2);
[[fallthrough]];

View File

@ -54,7 +54,16 @@ class MT24LC256
void systemReset();
/** Erase entire EEPROM to known state ($FF) */
void erase();
void eraseAll();
/** Erase the pages used by the current ROM to known state ($FF) */
void eraseCurrent();
/** Returns true if at least one EEPROM page has been detected for the current ROM */
bool isPageDetected()
{
return myPageDetected;
}
private:
// I2C access code provided by Supercat
@ -68,11 +77,23 @@ class MT24LC256
void update();
private:
// Sizes of the EEPROM
static constexpr uInt32 FLASH_SIZE = 32 * 1024;
static constexpr uInt32 PAGE_SIZE = 64;
static constexpr uInt32 PAGE_NUM = FLASH_SIZE / PAGE_SIZE;
// Inital state value of flash EEPROM
static constexpr uInt8 INIT_VALUE = 0xff;
// The system of the parent controller
const System& mySystem;
// The EEPROM data
uInt8 myData[32768];
uInt8 myData[FLASH_SIZE];
// Track which pages are used
bool myPageHit[PAGE_NUM];
bool myPageDetected;
// Cached state of the SDA and SCL pins on the last write
bool mySDA, mySCL;

View File

@ -0,0 +1,97 @@
//============================================================================
//
// 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-2017 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 "FlashWidget.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FlashWidget::FlashWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, Controller& controller)
: ControllerWidget(boss, font, x, y, controller) {}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FlashWidget::init(GuiObject* boss, const GUI::Font& font, int x, int y)
{
bool leftport = myController.jack() == Controller::Left;
const string& label = (leftport ? "Left (" : "Right (") + getName() + ")";
const int fontHeight = font.getFontHeight(),
lineHeight = font.getLineHeight(),
bwidth = font.getStringWidth("Erase EEPROM area") + 20,
bheight = lineHeight + 4;
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (" + getName() + ")");
StaticTextWidget* t;
t = new StaticTextWidget(boss, font, xpos, ypos + 2, lwidth,
fontHeight, label, kTextAlignLeft);
ypos += t->getHeight() + 8;
myEEPROMEraseCurrent =
new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
"Erase EEPROM range", kEEPROMEraseCurrent);
myEEPROMEraseCurrent->setTarget(this);
ypos += lineHeight + 8;
const GUI::Font& ifont = instance().frameBuffer().infoFont();
lwidth = ifont.getMaxCharWidth() * 20;
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
fontHeight, "(*) Erases only the", kTextAlignLeft);
ypos += lineHeight + 2;
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
fontHeight, "current ROM's range", kTextAlignLeft);
ypos += lineHeight + 8;
myEEPROMEraseAll =
new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
"Erase EEPROM", kEEPROMEraseAll);
myEEPROMEraseAll->setTarget(this);
ypos += lineHeight + 8;
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
fontHeight, "(*) This will erase", kTextAlignLeft);
ypos += lineHeight + 2;
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
fontHeight, "all EEPROM data!", kTextAlignLeft);
updateButtonState();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FlashWidget::handleCommand(CommandSender*, int cmd, int, int)
{
if(cmd == kEEPROMEraseAll) {
eraseAll();
}
if(cmd == kEEPROMEraseCurrent) {
eraseCurrent();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FlashWidget::drawWidget(bool hilite)
{
updateButtonState();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FlashWidget::updateButtonState()
{
myEEPROMEraseCurrent->setEnabled(isPageDetected());
}

View File

@ -0,0 +1,64 @@
//============================================================================
//
// 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-2017 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.
//============================================================================
#ifndef FLASH_WIDGET_HXX
#define FLASH_WIDGET_HXX
class ButtonWidget;
#include "Control.hxx"
#include "ControllerWidget.hxx"
class FlashWidget : public ControllerWidget
{
public:
FlashWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
Controller& controller);
virtual ~FlashWidget() = default;
protected:
void init(GuiObject* boss, const GUI::Font& font, int x, int y);
void drawWidget(bool hilite) override;
private:
ButtonWidget* myEEPROMEraseAll;
ButtonWidget* myEEPROMEraseCurrent;
enum
{
kEEPROMEraseAll = 'eeER',
kEEPROMEraseCurrent = 'eeEC'
};
private:
void loadConfig() override {}
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
void updateButtonState();
virtual string getName() = 0;
virtual void eraseCurrent() = 0;
virtual void eraseAll() = 0;
virtual bool isPageDetected() = 0;
// Following constructors and assignment operators not supported
FlashWidget() = delete;
FlashWidget(const FlashWidget&) = delete;
FlashWidget(FlashWidget&&) = delete;
FlashWidget& operator=(const FlashWidget&) = delete;
FlashWidget& operator=(FlashWidget&&) = delete;
};
#endif

View File

@ -331,6 +331,7 @@
<ClCompile Include="..\gui\JoystickDialog.cxx" />
<ClCompile Include="..\gui\LoggerDialog.cxx" />
<ClCompile Include="..\gui\SnapshotDialog.cxx" />
<ClCompile Include="FlashWidget.cxx" />
<ClCompile Include="FSNodeWINDOWS.cxx" />
<ClCompile Include="OSystemWINDOWS.cxx" />
<ClCompile Include="..\common\PNGLibrary.cxx" />
@ -489,6 +490,7 @@
<ClCompile Include="..\libpng\pngwrite.c" />
<ClCompile Include="..\libpng\pngwtran.c" />
<ClCompile Include="..\libpng\pngwutil.c" />
<ClCompile Include="StateList.cxx" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\common\Base.hxx" />
@ -619,6 +621,7 @@
<ClInclude Include="..\libpng\pnginfo.h" />
<ClInclude Include="..\libpng\pnglibconf.h" />
<ClInclude Include="..\libpng\pngstruct.h" />
<ClInclude Include="FlashWidget.hxx" />
<ClInclude Include="FSNodeWINDOWS.hxx" />
<ClInclude Include="HomeFinder.hxx" />
<ClInclude Include="OSystemWINDOWS.hxx" />
@ -782,6 +785,7 @@
<ClInclude Include="..\libpng\png.h" />
<ClInclude Include="..\libpng\pngconf.h" />
<ClInclude Include="..\libpng\pngpriv.h" />
<ClInclude Include="StateList.hxx" />
</ItemGroup>
<ItemGroup>
<None Include="stella.ico" />

View File

@ -840,6 +840,12 @@
<ClCompile Include="..\common\StateManager.cxx">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StateList.cxx">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FlashWidget.cxx">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\common\bspf.hxx">
@ -1715,6 +1721,12 @@
<ClInclude Include="..\common\StateManager.hxx">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="StateList.hxx">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FlashWidget.hxx">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="stella.ico">