aboutsummaryrefslogtreecommitdiff
path: root/qtmips_machine
diff options
context:
space:
mode:
Diffstat (limited to 'qtmips_machine')
-rw-r--r--qtmips_machine/cop0state.cpp81
-rw-r--r--qtmips_machine/cop0state.h24
-rw-r--r--qtmips_machine/core.cpp4
-rw-r--r--qtmips_machine/qtmipsmachine.cpp18
-rw-r--r--qtmips_machine/qtmipsmachine.h3
5 files changed, 96 insertions, 34 deletions
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;