diff options
author | Pavel Pisa <pisa@cmp.felk.cvut.cz> | 2019-03-05 00:57:02 +0100 |
---|---|---|
committer | Pavel Pisa <pisa@cmp.felk.cvut.cz> | 2019-03-05 00:57:02 +0100 |
commit | 675ede8c34671415bc423e6360ffe0de12d49ec8 (patch) | |
tree | 5d33ca19a47bd4f35303176d102e1b27310da472 | |
parent | 73886d9d1733368fe3c876c8e613ba5821e12944 (diff) | |
download | qtmips-675ede8c34671415bc423e6360ffe0de12d49ec8.tar.gz qtmips-675ede8c34671415bc423e6360ffe0de12d49ec8.tar.bz2 qtmips-675ede8c34671415bc423e6360ffe0de12d49ec8.zip |
Dock to view coprocessor 0 and cop0 counter/comparator support.
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
-rw-r--r-- | qtmips_gui/MainWindow.ui | 9 | ||||
-rw-r--r-- | qtmips_gui/cop0dock.cpp | 96 | ||||
-rw-r--r-- | qtmips_gui/cop0dock.h | 67 | ||||
-rw-r--r-- | qtmips_gui/mainwindow.cpp | 5 | ||||
-rw-r--r-- | qtmips_gui/mainwindow.h | 4 | ||||
-rw-r--r-- | qtmips_gui/qtmips_gui.pro | 6 | ||||
-rw-r--r-- | qtmips_machine/cop0state.cpp | 81 | ||||
-rw-r--r-- | qtmips_machine/cop0state.h | 24 | ||||
-rw-r--r-- | qtmips_machine/core.cpp | 4 | ||||
-rw-r--r-- | qtmips_machine/qtmipsmachine.cpp | 18 | ||||
-rw-r--r-- | qtmips_machine/qtmipsmachine.h | 3 |
11 files changed, 281 insertions, 36 deletions
diff --git a/qtmips_gui/MainWindow.ui b/qtmips_gui/MainWindow.ui index 1b9bfbd..4847304 100644 --- a/qtmips_gui/MainWindow.ui +++ b/qtmips_gui/MainWindow.ui @@ -70,6 +70,7 @@ <addaction name="actionData_Cache"/> <addaction name="actionPeripherals"/> <addaction name="actionTerminal"/> + <addaction name="actionCop0State"/> </widget> <widget class="QMenu" name="menuMachine"> <property name="title"> @@ -295,6 +296,14 @@ <string>Ctrl+D</string> </property> </action> + <action name="actionCop0State"> + <property name="text"> + <string>Cop0 State</string> + </property> + <property name="shortcut"> + <string>Ctrl+C</string> + </property> + </action> <action name="actionReload"> <property name="icon"> <iconset resource="icons.qrc"> diff --git a/qtmips_gui/cop0dock.cpp b/qtmips_gui/cop0dock.cpp new file mode 100644 index 0000000..1070444 --- /dev/null +++ b/qtmips_gui/cop0dock.cpp @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0+ +/******************************************************************************* + * QtMips - MIPS 32-bit Architecture Subset Simulator + * + * Implemented to support following courses: + * + * B35APO - Computer Architectures + * https://cw.fel.cvut.cz/wiki/courses/b35apo + * + * B4M35PAP - Advanced Computer Architectures + * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start + * + * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz> + * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz> + * + * Faculty of Electrical Engineering (http://www.fel.cvut.cz) + * Czech Technical University (http://www.cvut.cz/) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + ******************************************************************************/ + +#include "cop0dock.h" + + +Cop0Dock::Cop0Dock(QWidget *parent) : QDockWidget(parent) { + scrollarea = new QScrollArea(this); + scrollarea->setWidgetResizable(true); + widg = new StaticTable(scrollarea); + +#define INIT(X, LABEL) do{ \ + X = new QLabel("0x00000000", widg); \ + X->setFixedSize(X->sizeHint()); \ + X->setText(""); \ + X->setTextInteractionFlags(Qt::TextSelectableByMouse); \ + widg->addRow({new QLabel(LABEL, widg), X}); \ + } while(false) + + cop0reg[0] = nullptr; + for (int i = 1; i < machine::Cop0State::COP0REGS_CNT; i++) + INIT(cop0reg[i], machine::Cop0State::cop0reg_name((machine::Cop0State::Cop0Registers)i)); +#undef INIT + scrollarea->setWidget(widg); + + setWidget(scrollarea); + setObjectName("Coprocessor0"); + setWindowTitle("Coprocessor0"); +} + +Cop0Dock::~Cop0Dock() { + for (int i = 1; i < machine::Cop0State::COP0REGS_CNT; i++) + delete cop0reg[i]; + delete widg; + delete scrollarea; +} + +void Cop0Dock::setup(machine::QtMipsMachine *machine) { + if (machine == nullptr) { + // Reset data + for (int i = 1; i < machine::Cop0State::COP0REGS_CNT; i++) + cop0reg[i]->setText(""); + return; + } + + const machine::Cop0State *cop0state = machine->cop0state(); + connect(cop0state, &machine::Cop0State::cop0reg_update, + this, &Cop0Dock::cop0reg_changed); + + for (int i = 1; i < machine::Cop0State::COP0REGS_CNT; i++) + labelVal(cop0reg[i], cop0state->read_cop0reg((machine::Cop0State::Cop0Registers)i)); +} + +void Cop0Dock::cop0reg_changed(enum machine::Cop0State::Cop0Registers reg, std::uint32_t val) { + SANITY_ASSERT((uint)reg < machine::Cop0State::COP0REGS_CNT && (uint)reg, + QString("Cop0Dock received signal with invalid cop0 register: ") + + QString::number((uint)reg)); + labelVal(cop0reg[(uint)reg], val); +} + +void Cop0Dock::labelVal(QLabel *label, std::uint32_t value) { + QString t = QString("0x") + QString::number(value, 16); + label->setText(t); +} diff --git a/qtmips_gui/cop0dock.h b/qtmips_gui/cop0dock.h new file mode 100644 index 0000000..5dfa058 --- /dev/null +++ b/qtmips_gui/cop0dock.h @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/******************************************************************************* + * QtMips - MIPS 32-bit Architecture Subset Simulator + * + * Implemented to support following courses: + * + * B35APO - Computer Architectures + * https://cw.fel.cvut.cz/wiki/courses/b35apo + * + * B4M35PAP - Advanced Computer Architectures + * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start + * + * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz> + * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz> + * + * Faculty of Electrical Engineering (http://www.fel.cvut.cz) + * Czech Technical University (http://www.cvut.cz/) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + ******************************************************************************/ + +#ifndef COP0DOCK_H +#define COP0DOCK_H + +#include <QDockWidget> +#include <QLabel> +#include <QFormLayout> +#include <QScrollArea> +#include <QPropertyAnimation> +#include "qtmipsmachine.h" +#include "statictable.h" + +class Cop0Dock : public QDockWidget { + Q_OBJECT +public: + Cop0Dock(QWidget *parent); + ~Cop0Dock(); + + void setup(machine::QtMipsMachine *machine); + +private slots: + void cop0reg_changed(enum machine::Cop0State::Cop0Registers reg, std::uint32_t val); + +private: + StaticTable *widg; + QScrollArea *scrollarea; + + QLabel *cop0reg[machine::Cop0State::COP0REGS_CNT]; + + void labelVal(QLabel *label, std::uint32_t val); +}; + +#endif // COP0DOCK_H diff --git a/qtmips_gui/mainwindow.cpp b/qtmips_gui/mainwindow.cpp index 01321cf..3cefe94 100644 --- a/qtmips_gui/mainwindow.cpp +++ b/qtmips_gui/mainwindow.cpp @@ -67,6 +67,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { peripherals->hide(); terminal = new TerminalDock(this, settings); terminal->hide(); + cop0dock = new Cop0Dock(this); + cop0dock->hide(); // Execution speed actions speed_group = new QActionGroup(this); @@ -90,6 +92,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { connect(ui->actionData_Cache, SIGNAL(triggered(bool)), this, SLOT(show_cache_data())); connect(ui->actionPeripherals, SIGNAL(triggered(bool)), this, SLOT(show_peripherals())); connect(ui->actionTerminal, SIGNAL(triggered(bool)), this, SLOT(show_terminal())); + connect(ui->actionCop0State, SIGNAL(triggered(bool)), this, SLOT(show_cop0dock())); connect(ui->actionAbout, SIGNAL(triggered(bool)), this, SLOT(about_qtmips())); connect(ui->actionAboutQt, SIGNAL(triggered(bool)), this, SLOT(about_qt())); connect(ui->ips1, SIGNAL(toggled(bool)), this, SLOT(set_speed())); @@ -187,6 +190,7 @@ void MainWindow::create_core(const machine::MachineConfig &config) { cache_data->setup(machine->cache_data()); terminal->setup(machine->serial_port()); peripherals->setup(machine->peripheral_spi_led()); + cop0dock->setup(machine); // Connect signals for instruction address followup connect(machine->core(), SIGNAL(fetch_inst_addr_value(std::uint32_t)), @@ -237,6 +241,7 @@ SHOW_HANDLER(cache_program) SHOW_HANDLER(cache_data) SHOW_HANDLER(peripherals) SHOW_HANDLER(terminal) +SHOW_HANDLER(cop0dock) #undef SHOW_HANDLER void MainWindow::show_symbol_dialog(){ diff --git a/qtmips_gui/mainwindow.h b/qtmips_gui/mainwindow.h index 796dd33..84c9d08 100644 --- a/qtmips_gui/mainwindow.h +++ b/qtmips_gui/mainwindow.h @@ -47,6 +47,7 @@ #include "cachedock.h" #include "peripheralsdock.h" #include "terminaldock.h" +#include "cop0dock.h" #include "qtmipsmachine.h" #include "machineconfig.h" @@ -74,6 +75,7 @@ public slots: void show_cache_program(); void show_peripherals(); void show_terminal(); + void show_cop0dock(); void show_symbol_dialog(); // Actions - help menu void about_qtmips(); @@ -102,6 +104,8 @@ private: CacheDock *cache_program, *cache_data; PeripheralsDock *peripherals; TerminalDock *terminal; + Cop0Dock *cop0dock; + QActionGroup *speed_group; diff --git a/qtmips_gui/qtmips_gui.pro b/qtmips_gui/qtmips_gui.pro index acdbd55..e10631b 100644 --- a/qtmips_gui/qtmips_gui.pro +++ b/qtmips_gui/qtmips_gui.pro @@ -62,7 +62,8 @@ SOURCES += \ peripheralsview.cpp \ coreview/multitext.cpp \ fontsize.cpp \ - gotosymboldialog.cpp + gotosymboldialog.cpp \ + cop0dock.cpp HEADERS += \ mainwindow.h \ @@ -100,7 +101,8 @@ HEADERS += \ peripheralsview.h \ coreview/multitext.h \ fontsize.h \ - gotosymboldialog.h + gotosymboldialog.h \ + cop0dock.h FORMS += \ NewDialog.ui \ diff --git a/qtmips_machine/cop0state.cpp b/qtmips_machine/cop0state.cpp index 9957560..35f78d1 100644 --- a/qtmips_machine/cop0state.cpp +++ b/qtmips_machine/cop0state.cpp @@ -40,9 +40,11 @@ using namespace machine; +#define COUNTER_IRQ_LEVEL 7 + // sorry, unimplemented: non-trivial designated initializers not supported -static enum Cop0State::Cop0Regsisters cop0reg_map[32][8] = { +static enum Cop0State::Cop0Registers cop0reg_map[32][8] = { /*0*/ {}, /*1*/ {}, /*2*/ {}, @@ -83,13 +85,13 @@ const Cop0State::cop0reg_desc_t Cop0State::cop0reg_desc[Cop0State::COP0REGS_CNT] [Cop0State::Unsupported] = {"Unsupported", 0x00000000, 0x00000000, &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default}, [Cop0State::UserLocal] = {"UserLocal", 0xffffffff, 0x00000000, - &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default}, + &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_user_local}, [Cop0State::BadVAddr] = {"BadVAddr", 0x00000000, 0x00000000, &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default}, - [Cop0State::Count] = {"Count", 0x00000000, 0x00000000, - &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default}, - [Cop0State::Compare] = {"Compare", 0x00000000, 0x00000000, - &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default}, + [Cop0State::Count] = {"Count", 0xffffffff, 0x00000000, + &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_count_compare}, + [Cop0State::Compare] = {"Compare", 0xffffffff, 0x00000000, + &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_count_compare}, [Cop0State::Status] = {"Status", Status_IE | Status_IntMask, 0x00000000, &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default}, [Cop0State::Cause] = {"Cause", 0x00000000, 0x00000000, @@ -110,7 +112,7 @@ Cop0State::Cop0State(Core *core) : QObject() { Cop0State::Cop0State(const Cop0State &orig) : QObject() { this->core = orig.core; for (int i = 0; i < COP0REGS_CNT; i++) - this->cop0reg[i] = orig.read_cop0reg((enum Cop0Regsisters)i); + this->cop0reg[i] = orig.read_cop0reg((enum Cop0Registers)i); } void Cop0State::setup_core(Core *core) { @@ -120,7 +122,7 @@ void Cop0State::setup_core(Core *core) { std::uint32_t Cop0State::read_cop0reg(std::uint8_t rd, std::uint8_t sel) const { SANITY_ASSERT(rd < 32, QString("Trying to read from cop0 register ") + QString(rd) + ',' + QString(sel)); SANITY_ASSERT(sel < 8, QString("Trying to read from cop0 register ") + QString(rd) + ',' + QString(sel)); - enum Cop0Regsisters reg = cop0reg_map[rd][sel]; + enum Cop0Registers reg = cop0reg_map[rd][sel]; SANITY_ASSERT(reg != 0, QString("Cop0 register ") + QString(rd) + ',' + QString(sel) + "unsupported"); return read_cop0reg(reg); } @@ -128,33 +130,38 @@ std::uint32_t Cop0State::read_cop0reg(std::uint8_t rd, std::uint8_t sel) const { void Cop0State::write_cop0reg(std::uint8_t rd, std::uint8_t sel, std::uint32_t value) { SANITY_ASSERT(rd < 32, QString("Trying to write to cop0 register ") + QString(rd) + ',' + QString(sel)); SANITY_ASSERT(sel < 8, QString("Trying to write to cop0 register ") + QString(rd) + ',' + QString(sel)); - enum Cop0Regsisters reg = cop0reg_map[rd][sel]; + enum Cop0Registers reg = cop0reg_map[rd][sel]; SANITY_ASSERT(reg != 0, QString("Cop0 register ") + QString(rd) + ',' + QString(sel) + "unsupported"); write_cop0reg(reg, value); } -std::uint32_t Cop0State::read_cop0reg(enum Cop0Regsisters reg) const { - SANITY_ASSERT(reg < COP0REGS_CNT, QString("Trying to read from cop0 register ") + QString(reg)); - return cop0reg[(int)reg]; +std::uint32_t Cop0State::read_cop0reg(enum Cop0Registers reg) const { + SANITY_ASSERT(reg != Unsupported && reg < COP0REGS_CNT, QString("Trying to read from cop0 register ") + QString(reg)); + return (this->*cop0reg_desc[reg].reg_read)(reg); } -void Cop0State::write_cop0reg(enum Cop0Regsisters reg, std::uint32_t value) { - SANITY_ASSERT(reg < COP0REGS_CNT, QString("Trying to write to cop0 register ") + QString(reg)); - cop0reg[(int)reg] = value; +void Cop0State::write_cop0reg(enum Cop0Registers reg, std::uint32_t value) { + SANITY_ASSERT(reg != Unsupported && reg < COP0REGS_CNT, QString("Trying to write to cop0 register ") + QString(reg)); + (this->*cop0reg_desc[reg].reg_write)(reg, value); } -std::uint32_t Cop0State::read_cop0reg_default(enum Cop0Regsisters reg) const { +QString Cop0State::cop0reg_name(enum Cop0Registers reg) { + return QString(cop0reg_desc[(int)reg].name); +} + +std::uint32_t Cop0State::read_cop0reg_default(enum Cop0Registers reg) const { return cop0reg[(int)reg]; } -void Cop0State::write_cop0reg_default(enum Cop0Regsisters reg, std::uint32_t value) { +void Cop0State::write_cop0reg_default(enum Cop0Registers reg, std::uint32_t value) { std::uint32_t mask = cop0reg_desc[(int)reg].write_mask; cop0reg[(int)reg] = (value & mask) | (cop0reg[(int)reg] & ~mask); + emit cop0reg_update(reg, cop0reg[(int)reg]); } bool Cop0State::operator==(const Cop0State &c) const { for (int i = 0; i < COP0REGS_CNT; i++) - if (read_cop0reg((enum Cop0Regsisters)i) != c.read_cop0reg((enum Cop0Regsisters)i)) + if (read_cop0reg((enum Cop0Registers)i) != c.read_cop0reg((enum Cop0Registers)i)) return false; return true; } @@ -164,8 +171,11 @@ bool Cop0State::operator!=(const Cop0State &c) const { } void Cop0State::reset() { - for (int i = 0; i < COP0REGS_CNT; i++) + for (int i = 1; i < COP0REGS_CNT; i++) { this->cop0reg[i] = cop0reg_desc[i].init_value; + emit cop0reg_update((enum Cop0Registers)i, cop0reg[i]); + } + last_core_cycles = 0; } void Cop0State::update_execption_cause(enum ExceptionCause excause, bool in_delay_slot) { @@ -176,6 +186,7 @@ void Cop0State::update_execption_cause(enum ExceptionCause excause, bool in_dela cop0reg[(int)Cause] &= ~0x0000007f; if (excause != EXCAUSE_INT) cop0reg[(int)Cause] |= (int)excause << 2; + emit cop0reg_update(Cause, cop0reg[(int)Cause]); } void Cop0State::set_interrupt_signal(uint irq_num, bool active) { @@ -187,10 +198,14 @@ void Cop0State::set_interrupt_signal(uint irq_num, bool active) { cop0reg[(int)Cause] |= mask; else cop0reg[(int)Cause] &= ~mask; + emit cop0reg_update(Cause, cop0reg[(int)Cause]); } bool Cop0State::core_interrupt_request() { std::uint32_t irqs; + + update_count_and_compare_irq(); + irqs = cop0reg[(int)Status]; irqs &= cop0reg[(int)Cause]; irqs &= Status_IntMask; @@ -205,8 +220,36 @@ void Cop0State::set_status_exl(bool value) { cop0reg[(int)Status] |= Status_EXL; else cop0reg[(int)Status] &= ~Status_EXL; + emit cop0reg_update(Status, cop0reg[(int)Status]); } std::uint32_t Cop0State::exception_pc_address() { return cop0reg[(int)EBase] + 0x180; } + +void Cop0State::write_cop0reg_count_compare(enum Cop0Registers reg, std::uint32_t value) { + set_interrupt_signal(COUNTER_IRQ_LEVEL, false); + write_cop0reg_default(reg, value); +} + +void Cop0State::update_count_and_compare_irq() { + std::uint32_t core_cycles; + std::uint32_t count_orig; + if (core == nullptr) + return; + count_orig = cop0reg[(int)Count]; + core_cycles = core->cycles(); + cop0reg[(int)Count] += core_cycles - last_core_cycles; + last_core_cycles = core_cycles; + emit cop0reg_update(Count, cop0reg[(int)Count]); + + if ((std::int32_t)(cop0reg[(int)Compare] - count_orig) > 0 && + (std::int32_t)(cop0reg[(int)Compare] - cop0reg[(int)Count]) <= 0) + set_interrupt_signal(COUNTER_IRQ_LEVEL, true); +} + +void Cop0State::write_cop0reg_user_local(enum Cop0Registers reg, std::uint32_t value) { + write_cop0reg_default(reg, value); + if (core != nullptr) + core->set_c0_userlocal(value); +} diff --git a/qtmips_machine/cop0state.h b/qtmips_machine/cop0state.h index 06be9a7..0fd3d3f 100644 --- a/qtmips_machine/cop0state.h +++ b/qtmips_machine/cop0state.h @@ -37,6 +37,7 @@ #define COP0STATE_H #include <QObject> +#include <QString> #include <cstdint> #include <machinedefs.h> namespace machine { @@ -47,7 +48,7 @@ class Cop0State : public QObject { Q_OBJECT friend class Core; public: - enum Cop0Regsisters { + enum Cop0Registers { Unsupported = 0, UserLocal, BadVAddr, // Reports the address for the most recent address-related exception @@ -72,10 +73,11 @@ public: Cop0State(Core *core = nullptr); Cop0State(const Cop0State&); - std::uint32_t read_cop0reg(enum Cop0Regsisters reg) const; + std::uint32_t read_cop0reg(enum Cop0Registers reg) const; std::uint32_t read_cop0reg(std::uint8_t rd, std::uint8_t sel) const; // Read coprocessor 0 register - void write_cop0reg(enum Cop0Regsisters reg, std::uint32_t value); + void write_cop0reg(enum Cop0Registers reg, std::uint32_t value); void write_cop0reg(std::uint8_t reg, std::uint8_t sel, std::uint32_t value); // Write coprocessor 0 register + static QString cop0reg_name(enum Cop0Registers reg); bool operator ==(const Cop0State &c) const; bool operator !=(const Cop0State &c) const; @@ -85,6 +87,9 @@ public: bool core_interrupt_request(); std::uint32_t exception_pc_address(); +signals: + void cop0reg_update(enum Cop0Registers reg, std::uint32_t val); + public slots: void set_interrupt_signal(uint irq_num, bool active); void set_status_exl(bool value); @@ -92,14 +97,15 @@ public slots: protected: void setup_core(Core *core); void update_execption_cause(enum ExceptionCause excause, bool in_delay_slot); + void update_count_and_compare_irq(); private: typedef std::uint32_t (Cop0State::*reg_read_t) - (enum Cop0Regsisters reg) const; + (enum Cop0Registers reg) const; typedef void (Cop0State::*reg_write_t) - (enum Cop0Regsisters reg, std::uint32_t value); + (enum Cop0Registers reg, std::uint32_t value); struct cop0reg_desc_t { const char *name; @@ -112,14 +118,18 @@ private: static const cop0reg_desc_t cop0reg_desc[COP0REGS_CNT]; - std::uint32_t read_cop0reg_default(enum Cop0Regsisters reg) const; - void write_cop0reg_default(enum Cop0Regsisters reg, std::uint32_t value); + std::uint32_t read_cop0reg_default(enum Cop0Registers reg) const; + void write_cop0reg_default(enum Cop0Registers reg, std::uint32_t value); + void write_cop0reg_count_compare(enum Cop0Registers reg, std::uint32_t value); + void write_cop0reg_user_local(enum Cop0Registers reg, std::uint32_t value); Core *core; std::uint32_t cop0reg[COP0REGS_CNT]; // coprocessor 0 registers + std::uint32_t last_core_cycles; }; } Q_DECLARE_METATYPE(machine::Cop0State) +Q_DECLARE_METATYPE(machine::Cop0State::Cop0Registers) #endif // COP0STATE_H diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp index 351ffb0..2ba8d34 100644 --- a/qtmips_machine/core.cpp +++ b/qtmips_machine/core.cpp @@ -160,6 +160,10 @@ bool Core::handle_exception(Core *core, Registers *regs, ExceptionCause excause, void Core::set_c0_userlocal(std::uint32_t address) { hwr_userlocal = address; + if (cop0state != nullptr) { + if (address != cop0state->read_cop0reg(Cop0State::UserLocal)) + cop0state->write_cop0reg(Cop0State::UserLocal, address); + } } enum ExceptionCause Core::memory_special(enum AccessControl memctl, diff --git a/qtmips_machine/qtmipsmachine.cpp b/qtmips_machine/qtmipsmachine.cpp index 41ca56f..afcae54 100644 --- a/qtmips_machine/qtmipsmachine.cpp +++ b/qtmips_machine/qtmipsmachine.cpp @@ -81,16 +81,16 @@ QtMipsMachine::QtMipsMachine(const MachineConfig &cc, bool load_symtab) : cc.cache_program().blocks() < min_cache_row_size) min_cache_row_size = cc.cache_program().blocks() * 4; - cop0state = new Cop0State(); + cop0st = new Cop0State(); if (cc.pipelined()) cr = new CorePipelined(regs, cch_program, cch_data, cc.hazard_unit(), - min_cache_row_size, cop0state); + min_cache_row_size, cop0st); else cr = new CoreSingle(regs, cch_program, cch_data, cc.delay_slot(), - min_cache_row_size, cop0state); + min_cache_row_size, cop0st); connect(this, SIGNAL(set_interrupt_signal(uint,bool)), - cop0state, SLOT(set_interrupt_signal(uint,bool))); + cop0st, SLOT(set_interrupt_signal(uint,bool))); run_t = new QTimer(this); set_speed(0); // In default run as fast as possible @@ -104,9 +104,9 @@ QtMipsMachine::~QtMipsMachine() { if (cr != nullptr) delete cr; cr = nullptr; - if (cop0state != nullptr) - delete cop0state; - cop0state = nullptr; + if (cop0st != nullptr) + delete cop0st; + cop0st = nullptr; if (regs != nullptr) delete regs; regs = nullptr; @@ -143,6 +143,10 @@ const Registers *QtMipsMachine::registers() { return regs; } +const Cop0State *QtMipsMachine::cop0state() { + return cop0st; +} + const Memory *QtMipsMachine::memory() { return mem; } diff --git a/qtmips_machine/qtmipsmachine.h b/qtmips_machine/qtmipsmachine.h index 60291a8..349e0df 100644 --- a/qtmips_machine/qtmipsmachine.h +++ b/qtmips_machine/qtmipsmachine.h @@ -63,6 +63,7 @@ public: void set_speed(unsigned int ips, unsigned int time_chunk = 0); const Registers *registers(); + const Cop0State *cop0state(); const Memory *memory(); Memory *memory_rw(); const Cache *cache_program(); @@ -120,7 +121,7 @@ private: SerialPort *ser_port; PeripSpiLed *perip_spi_led; Cache *cch_program, *cch_data; - Cop0State *cop0state; + Cop0State *cop0st; Core *cr; QTimer *run_t; |