Qt Hex editor in work.

This commit is contained in:
Matthew Budd 2020-08-16 10:38:42 -04:00
parent 11ccdf77b4
commit 490289a6f7
2 changed files with 415 additions and 6 deletions

View File

@ -8,6 +8,19 @@
#include <SDL.h> #include <SDL.h>
#include <QHeaderView> #include <QHeaderView>
#include "../../types.h"
#include "../../fceu.h"
#include "../../cheat.h"
#include "../../debug.h"
#include "../../driver.h"
#include "../../version.h"
#include "../../movie.h"
#include "../../palette.h"
#include "../../fds.h"
#include "../../cart.h"
#include "../../ines.h"
#include "../common/configSys.h"
#include "Qt/main.h" #include "Qt/main.h"
#include "Qt/dface.h" #include "Qt/dface.h"
#include "Qt/input.h" #include "Qt/input.h"
@ -16,31 +29,114 @@
#include "Qt/fceuWrapper.h" #include "Qt/fceuWrapper.h"
#include "Qt/HexEditor.h" #include "Qt/HexEditor.h"
//----------------------------------------------------------------------------
static int getRAM( unsigned int i )
{
return GetMem(i);
}
static int getPPU( unsigned int i )
{
i &= 0x3FFF;
if (i < 0x2000)return VPage[(i) >> 10][(i)];
//NSF PPU Viewer crash here (UGETAB) (Also disabled by 'MaxSize = 0x2000')
if (GameInfo->type == GIT_NSF)
return 0;
else
{
if (i < 0x3F00)
return vnapage[(i >> 10) & 0x3][i & 0x3FF];
return READPAL_MOTHEROFALL(i & 0x1F);
}
return 0;
}
static int getOAM( unsigned int i )
{
return SPRAM[i & 0xFF];
}
static int getROM( unsigned int offset)
{
if (offset < 16)
{
return *((unsigned char *)&head+offset);
}
else if (offset < (16+PRGsize[0]) )
{
return PRGptr[0][offset-16];
}
else if (offset < (16+PRGsize[0]+CHRsize[0]) )
{
return CHRptr[0][offset-16-PRGsize[0]];
}
return -1;
}
static int conv2xchar( int i )
{
int c = 0;
if ( (i >= 0) && (i < 10) )
{
c = i + '0';
}
else if ( i < 16 )
{
c = (i - 10) + 'A';
}
return c;
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) HexEditorDialog_t::HexEditorDialog_t(QWidget *parent)
: QDialog( parent ) : QDialog( parent )
{ {
QVBoxLayout *mainLayout; QVBoxLayout *mainLayout;
font.setFamily("Courier New");
font.setStyle( QFont::StyleNormal );
font.setStyleHint( QFont::Monospace );
setWindowTitle("Hex Editor"); setWindowTitle("Hex Editor");
resize( 512, 512 ); resize( 512, 512 );
mainLayout = new QVBoxLayout(); mainLayout = new QVBoxLayout();
txt = new QTextEdit(); txtBuf = new QPlainTextEdit();
txt->moveCursor(QTextCursor::Start); txtBuf->setFont( font );
txt->setReadOnly(true); txtBuf->moveCursor(QTextCursor::Start);
txtBuf->setReadOnly(true);
txtBuf->setLineWrapMode( QPlainTextEdit::NoWrap );
mainLayout->addWidget( txt ); mainLayout->addWidget( txtBuf );
setLayout( mainLayout ); setLayout( mainLayout );
mode = MODE_NES_RAM;
numLines = 0;
numCharsPerLine = 90;
mbuf = NULL;
memSize = 0;
mbuf_size = 0;
memAccessFunc = getRAM;
redraw = false;
total_instructions_lp = 0;
showMemViewResults(true);
periodicTimer = new QTimer( this );
connect( periodicTimer, &QTimer::timeout, this, &HexEditorDialog_t::updatePeriodic );
periodicTimer->start( 1000 ); // 10hz
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
HexEditorDialog_t::~HexEditorDialog_t(void) HexEditorDialog_t::~HexEditorDialog_t(void)
{ {
periodicTimer->stop();
if ( mbuf != NULL )
{
::free( mbuf ); mbuf = NULL;
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void HexEditorDialog_t::closeWindow(void) void HexEditorDialog_t::closeWindow(void)
@ -61,3 +157,280 @@ void HexEditorDialog_t::keyReleaseEvent(QKeyEvent *event)
//assignHotkey( event ); //assignHotkey( event );
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
int HexEditorDialog_t::calcVisibleRange( int *start_out, int *end_out, int *center_out )
{
int start_pos, end_pos;
QPoint bottom_left( 0, txtBuf->viewport()->height() - 1);
start_pos = txtBuf->cursorForPosition(QPoint(0, 0)).position();
end_pos = txtBuf->cursorForPosition(bottom_left).position();
start_pos = (start_pos / numCharsPerLine) - 1;
end_pos = (end_pos / numCharsPerLine) + 1;
if ( start_pos < 0 )
{
start_pos = 0;
}
printf("Start: %i End: %i\n", start_pos, end_pos );
if ( start_out )
{
*start_out = start_pos;
}
if ( end_out )
{
*end_out = end_pos;
}
if ( center_out )
{
*center_out = (start_pos + end_pos) / 2;
}
return 0;
}
//----------------------------------------------------------------------------
void HexEditorDialog_t::setMode(int new_mode)
{
if ( mode != new_mode )
{
mode = new_mode;
showMemViewResults(true);
}
}
//----------------------------------------------------------------------------
void HexEditorDialog_t::initMem(void)
{
for (int i=0; i<mbuf_size; i++)
{
mbuf[i].data = memAccessFunc(i);
mbuf[i].color = 0;
mbuf[i].actv = 0;
mbuf[i].draw = 1;
}
}
//----------------------------------------------------------------------------
void HexEditorDialog_t::showMemViewResults (bool reset)
{
int i, row, row_start, row_end;
int addr = 0, lineAddr = 0, c, un, ln;
char addrStr[128], valStr[16][8], ascii[18];
char valChg[16], activityColoringOn, colorEnable;
switch ( mode )
{
default:
case MODE_NES_RAM:
memAccessFunc = getRAM;
memSize = 0x10000;
break;
case MODE_NES_PPU:
memAccessFunc = getPPU;
memSize = (GameInfo->type == GIT_NSF ? 0x2000 : 0x4000);
break;
case MODE_NES_OAM:
memAccessFunc = getOAM;
memSize = 0x100;
break;
case MODE_NES_ROM:
if ( GameInfo != NULL )
{
memAccessFunc = getROM;
memSize = 16 + CHRsize[0] + PRGsize[0];
}
else
{ // No Game Loaded!!! Get out of Function
memAccessFunc = NULL;
memSize = 0;
if ( mbuf )
{
free(mbuf); mbuf = NULL;
}
mbuf_size = 0;
redraw = true;
txtBuf->setPlainText("No ROM Loaded");
return;
}
break;
}
numLines = memSize / 16;
if ( (mbuf == NULL) || (mbuf_size != memSize) )
{
printf("Mode: %i MemSize:%i 0x%08x\n", mode, memSize, (unsigned int)memSize );
reset = 1;
if ( mbuf )
{
free(mbuf); mbuf = NULL;
}
mbuf = (struct memByte_t *)malloc( memSize * sizeof(struct memByte_t) );
if ( mbuf )
{
mbuf_size = memSize;
initMem();
}
else
{
printf("Error: Failed to allocate memview buffer size\n");
mbuf_size = 0;
return;
}
}
if ( reset )
{
txtBuf->clear();
row_start = 0;
row_end = numLines;
}
else
{
calcVisibleRange( &row_start, &row_end, NULL );
if ( row_start < 0 )
{
row_start = 0;
}
if ( row_end > numLines )
{
row_end = numLines;
}
}
for (row=row_start; row<row_end; row++)
{
lineAddr = (row*16);
if ( !reset )
{
txtBuf->textCursor().setPosition( row * numCharsPerLine );
}
if ( reset )
{
//next_iter = iter;
//gtk_text_iter_forward_chars( &next_iter, 9 );
sprintf( addrStr, "%08X ", lineAddr );
txtBuf->insertPlainText( addrStr );
}
else
{
txtBuf->textCursor().movePosition( QTextCursor::NextCharacter, QTextCursor::MoveAnchor, 9 );
}
for (i=0; i<16; i++)
{
valChg[i] = reset;
addr = lineAddr+i;
c = memAccessFunc(addr);
if ( mbuf[addr].draw )
{
mbuf[addr].draw = 0;
valChg[i] = 1;
}
un = ( c & 0x00f0 ) >> 4;
ln = ( c & 0x000f );
valStr[i][0] = ' ';
valStr[i][1] = conv2xchar(un);
valStr[i][2] = conv2xchar(ln);
valStr[i][3] = ' ';
valStr[i][4] = 0;
if ( isprint(c) )
{
ascii[i] = c;
}
else
{
ascii[i] = '.';
}
if ( valChg[i] )
{
if ( !reset )
{
for (int j=0; j<4; j++)
{
txtBuf->textCursor().deleteChar();
}
}
txtBuf->insertPlainText( valStr[i] );
}
else
{
txtBuf->textCursor().movePosition( QTextCursor::NextCharacter, QTextCursor::MoveAnchor, 4 );
}
}
ascii[16] = 0;
if ( reset )
{
txtBuf->insertPlainText( ascii );
}
if ( reset )
{
txtBuf->insertPlainText("\n");
}
}
}
//----------------------------------------------------------------------------
void HexEditorDialog_t::updatePeriodic(void)
{
printf("Update Periodic\n");
checkMemActivity();
showMemViewResults(false);
}
//----------------------------------------------------------------------------
int HexEditorDialog_t::checkMemActivity(void)
{
int c;
// Don't perform memory activity checks when:
// 1. In ROM View Mode
// 2. The simulation is not cycling (paused)
if ( ( mode == MODE_NES_ROM ) ||
( total_instructions_lp == total_instructions ) )
{
return -1;
}
for (int i=0; i<mbuf_size; i++)
{
c = memAccessFunc(i);
if ( c != mbuf[i].data )
{
mbuf[i].actv = 15;
mbuf[i].data = c;
mbuf[i].draw = 1;
}
else
{
if ( mbuf[i].actv > 0 )
{
mbuf[i].draw = 1;
mbuf[i].actv--;
}
}
}
total_instructions_lp = total_instructions;
return 0;
}
//----------------------------------------------------------------------------

View File

@ -5,6 +5,7 @@
#include <QWidget> #include <QWidget>
#include <QDialog> #include <QDialog>
#include <QTimer>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QComboBox> #include <QComboBox>
@ -13,7 +14,15 @@
#include <QLabel> #include <QLabel>
#include <QFrame> #include <QFrame>
#include <QGroupBox> #include <QGroupBox>
#include <QTextEdit> #include <QPlainTextEdit>
struct memByte_t
{
unsigned char data;
unsigned char color;
unsigned char actv;
unsigned char draw;
};
class HexEditorDialog_t : public QDialog class HexEditorDialog_t : public QDialog
{ {
@ -23,16 +32,43 @@ class HexEditorDialog_t : public QDialog
HexEditorDialog_t(QWidget *parent = 0); HexEditorDialog_t(QWidget *parent = 0);
~HexEditorDialog_t(void); ~HexEditorDialog_t(void);
enum {
MODE_NES_RAM = 0,
MODE_NES_PPU,
MODE_NES_OAM,
MODE_NES_ROM
};
protected: protected:
void keyPressEvent(QKeyEvent *event); void keyPressEvent(QKeyEvent *event);
void keyReleaseEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event);
QTextEdit *txt; void initMem(void);
void setMode(int new_mode);
void showMemViewResults (bool reset);
int checkMemActivity(void);
int calcVisibleRange( int *start_out, int *end_out, int *center_out );
QFont font;
QPlainTextEdit *txtBuf;
QTimer *periodicTimer;
int mode;
int numLines;
int numCharsPerLine;
int memSize;
int mbuf_size;
int (*memAccessFunc)( unsigned int offset);
struct memByte_t *mbuf;
uint64_t total_instructions_lp;
bool redraw;
private: private:
public slots: public slots:
void closeWindow(void); void closeWindow(void);
private slots: private slots:
void updatePeriodic(void);
}; };