aboutsummaryrefslogtreecommitdiff
path: root/qtmips_machine/cop0state.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qtmips_machine/cop0state.cpp')
-rw-r--r--qtmips_machine/cop0state.cpp180
1 files changed, 180 insertions, 0 deletions
diff --git a/qtmips_machine/cop0state.cpp b/qtmips_machine/cop0state.cpp
new file mode 100644
index 0000000..ea937ce
--- /dev/null
+++ b/qtmips_machine/cop0state.cpp
@@ -0,0 +1,180 @@
+// 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 "cop0state.h"
+#include "machinedefs.h"
+#include "core.h"
+#include "qtmipsexception.h"
+
+using namespace machine;
+
+
+// sorry, unimplemented: non-trivial designated initializers not supported
+
+static enum Cop0State::Cop0Regsisters cop0reg_map[32][8] = {
+ /*0*/ {},
+ /*1*/ {},
+ /*2*/ {},
+ /*3*/ {},
+ /*4*/ {Cop0State::Unsupported, Cop0State::Unsupported, Cop0State::UserLocal},
+ /*5*/ {},
+ /*6*/ {},
+ /*7*/ {},
+ /*8*/ {Cop0State::BadVAddr},
+ /*9*/ {Cop0State::Count},
+ /*10*/ {},
+ /*11*/ {Cop0State::Compare},
+ /*12*/ {Cop0State::Status},
+ /*13*/ {Cop0State::Cause},
+ /*14*/ {Cop0State::EPC},
+ /*15*/ {Cop0State::Unsupported, Cop0State::EBase},
+ /*16*/ {Cop0State::Config},
+ /*17*/ {},
+ /*18*/ {},
+ /*19*/ {},
+ /*20*/ {},
+ /*21*/ {},
+ /*22*/ {},
+ /*23*/ {},
+ /*24*/ {},
+ /*25*/ {},
+ /*26*/ {},
+ /*27*/ {},
+ /*28*/ {},
+ /*29*/ {},
+ /*30*/ {},
+ /*31*/ {},
+};
+
+// sorry, unimplemented: non-trivial designated initializers not supported
+
+const Cop0State::cop0reg_desc_t Cop0State::cop0reg_desc[Cop0State::COP0REGS_CNT] = {
+ [Cop0State::Unsupported] = {"Unsupported", 0x00000000,
+ &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default},
+ [Cop0State::UserLocal] = {"UserLocal", 0xffffffff,
+ &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default},
+ [Cop0State::BadVAddr] = {"BadVAddr", 0x00000000,
+ &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default},
+ [Cop0State::Count] = {"Count", 0x00000000,
+ &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default},
+ [Cop0State::Compare] = {"Compare", 0x00000000,
+ &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default},
+ [Cop0State::Status] = {"Status", 0x00000000,
+ &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default},
+ [Cop0State::Cause] = {"Cause", 0x00000000,
+ &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default},
+ [Cop0State::EPC] = {"EPC", 0xffffffff,
+ &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default},
+ [Cop0State::EBase] = {"EBase", 0xfffffffc,
+ &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default},
+ [Cop0State::Config] = {"Config", 0x00000000,
+ &Cop0State::read_cop0reg_default, &Cop0State::write_cop0reg_default},
+};
+
+Cop0State::Cop0State(Core *core) : QObject() {
+ this->core = core;
+ reset();
+}
+
+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);
+}
+
+void Cop0State::setup_core(Core *core) {
+ this->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];
+ SANITY_ASSERT(reg != 0, QString("Cop0 register ") + QString(rd) + ',' + QString(sel) + "unsupported");
+ return read_cop0reg(reg);
+}
+
+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];
+ 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];
+}
+
+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;
+}
+
+std::uint32_t Cop0State::read_cop0reg_default(enum Cop0Regsisters reg) const {
+ return cop0reg[(int)reg];
+}
+
+void Cop0State::write_cop0reg_default(enum Cop0Regsisters reg, std::uint32_t value) {
+ std::uint32_t mask = cop0reg_desc[(int)reg].write_mask;
+ cop0reg[(int)reg] = (value & mask) | (cop0reg[(int)reg] & ~mask);
+}
+
+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))
+ return false;
+ return true;
+}
+
+bool Cop0State::operator!=(const Cop0State &c) const {
+ return ! this->operator==(c);
+}
+
+void Cop0State::reset() {
+ for (int i = 0; i < COP0REGS_CNT; i++)
+ this->cop0reg[i] = 0;
+}
+
+void Cop0State::update_execption_cause(enum ExceptionCause excause, bool in_delay_slot) {
+ if (in_delay_slot)
+ cop0reg[(int)Cause] |= 0x80000000;
+ else
+ cop0reg[(int)Cause] &= ~0x80000000;
+ cop0reg[(int)Cause] &= ~0x0000007f;
+ if (excause != EXCAUSE_INT)
+ cop0reg[(int)Cause] |= (int)excause << 2;
+}