diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 1e39ed47..93c7a36f 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -8,6 +8,19 @@ #include #include +#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/dface.h" #include "Qt/input.h" @@ -16,31 +29,114 @@ #include "Qt/fceuWrapper.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) : QDialog( parent ) { QVBoxLayout *mainLayout; + font.setFamily("Courier New"); + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + setWindowTitle("Hex Editor"); resize( 512, 512 ); mainLayout = new QVBoxLayout(); - txt = new QTextEdit(); + txtBuf = new QPlainTextEdit(); - txt->moveCursor(QTextCursor::Start); - txt->setReadOnly(true); + txtBuf->setFont( font ); + txtBuf->moveCursor(QTextCursor::Start); + txtBuf->setReadOnly(true); + txtBuf->setLineWrapMode( QPlainTextEdit::NoWrap ); - mainLayout->addWidget( txt ); + mainLayout->addWidget( txtBuf ); 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) { + periodicTimer->stop(); + if ( mbuf != NULL ) + { + ::free( mbuf ); mbuf = NULL; + } } //---------------------------------------------------------------------------- void HexEditorDialog_t::closeWindow(void) @@ -61,3 +157,280 @@ void HexEditorDialog_t::keyReleaseEvent(QKeyEvent *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; itype == 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; rowtextCursor().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 0 ) + { + mbuf[i].draw = 1; + mbuf[i].actv--; + } + } + } + total_instructions_lp = total_instructions; + + return 0; +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 8c71d51a..79e27659 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -13,7 +14,15 @@ #include #include #include -#include +#include + +struct memByte_t +{ + unsigned char data; + unsigned char color; + unsigned char actv; + unsigned char draw; +}; class HexEditorDialog_t : public QDialog { @@ -23,16 +32,43 @@ class HexEditorDialog_t : public QDialog HexEditorDialog_t(QWidget *parent = 0); ~HexEditorDialog_t(void); + enum { + MODE_NES_RAM = 0, + MODE_NES_PPU, + MODE_NES_OAM, + MODE_NES_ROM + }; protected: void keyPressEvent(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: public slots: void closeWindow(void); private slots: + void updatePeriodic(void); };