diff --git a/nesemu/CMakeLists.txt b/nesemu/CMakeLists.txt index cb71abb..141c358 100644 --- a/nesemu/CMakeLists.txt +++ b/nesemu/CMakeLists.txt @@ -5,10 +5,12 @@ find_package(Qt5Multimedia CONFIG REQUIRED) find_package(Qt5Gamepad CONFIG REQUIRED) set(HEADERS + memorymodel.h ) set(SOURCES main.cpp + memorymodel.cpp ) add_executable(nesemu ${HEADERS} ${SOURCES}) diff --git a/nesemu/main.cpp b/nesemu/main.cpp index f790edb..6ef7b25 100644 --- a/nesemu/main.cpp +++ b/nesemu/main.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -22,6 +24,9 @@ #include "nesemulator.h" #include "emusettings.h" +// local includes +#include "memorymodel.h" + int main(int argc, char **argv) { QApplication app(argc, argv); @@ -103,6 +108,23 @@ int main(int argc, char **argv) dataStream << frame; }); + MemoryModel model(emulator); + QObject::connect(&emulator.ppu(), &Ppu::frameFinished, &model, &MemoryModel::refresh); + + QTableView tableView; + { + QHeaderView *horizontalHeader = tableView.horizontalHeader(); + horizontalHeader->setSectionResizeMode(QHeaderView::Fixed); + horizontalHeader->setDefaultSectionSize(0); + } + { + QHeaderView *verticalHeader = tableView.verticalHeader(); + verticalHeader->setSectionResizeMode(QHeaderView::Fixed); + verticalHeader->setDefaultSectionSize(0); + } + tableView.setModel(&model); + tableView.show(); + QTimer timer; QObject::connect(&timer, &QTimer::timeout, &emulator, &NesEmulator::emuClockFrame); timer.setInterval(EmuSettings::emuTimeFramePeriod); diff --git a/nesemu/memorymodel.cpp b/nesemu/memorymodel.cpp new file mode 100644 index 0000000..926e89a --- /dev/null +++ b/nesemu/memorymodel.cpp @@ -0,0 +1,64 @@ +#include "memorymodel.h" + +// nescorelib includes +#include "nesemulator.h" + +MemoryModel::MemoryModel(NesEmulator &emu, QObject *parent) : + QAbstractTableModel(parent), + m_emu(emu), + m_wram(emu.memory().wram()) +{ +} + +int MemoryModel::rowCount(const QModelIndex &parent) const +{ + return (END_ADDR - START_ADDR) / VALUES_PER_ROW; +} + +int MemoryModel::columnCount(const QModelIndex &parent) const +{ + return VALUES_PER_ROW; +} + +QVariant MemoryModel::data(const QModelIndex &index, int role) const +{ + const quint16 address = START_ADDR + (index.row() * VALUES_PER_ROW) + index.column(); + const auto arrIndex = Memory::wramAddressToIndex(address); + + switch(role) + { + case Qt::DisplayRole: + return QString("%0").arg(m_wram[arrIndex], 2, 16, QLatin1Char('0')); + } + + return QVariant(); +} + +QVariant MemoryModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(role == Qt::DisplayRole) + { + if(orientation == Qt::Horizontal) + return QString::number(section, 16); + else + return QString("0x%0").arg(START_ADDR + (section * VALUES_PER_ROW), 4, 16, QLatin1Char('0')); + } + + return QVariant(); +} + +void MemoryModel::refresh() +{ + const auto &newWram = m_emu.memory().wram(); + + for(quint16 i = START_ADDR; i < END_ADDR; i++) + { + const auto arrIndex = Memory::wramAddressToIndex(i); + if(m_wram[arrIndex] != newWram[arrIndex]) + { + QModelIndex index = createIndex((i-START_ADDR)/VALUES_PER_ROW, (i-START_ADDR)%VALUES_PER_ROW); + Q_EMIT dataChanged(index, index, QVector { Qt::DisplayRole }); + m_wram[arrIndex] = newWram[arrIndex]; + } + } +} diff --git a/nesemu/memorymodel.h b/nesemu/memorymodel.h new file mode 100644 index 0000000..f189971 --- /dev/null +++ b/nesemu/memorymodel.h @@ -0,0 +1,34 @@ +#pragma once + +// Qt includes +#include + +// system includes +#include + +// forward declarations +class NesEmulator; + +class MemoryModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit MemoryModel(NesEmulator &emu, QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; + +public Q_SLOTS: + void refresh(); + +private: + static constexpr quint16 START_ADDR = 0x0000; + static constexpr quint16 END_ADDR = 0x2000; + static constexpr quint16 VALUES_PER_ROW = 16; + + NesEmulator &m_emu; + std::array m_wram; +};