From 675ede8c34671415bc423e6360ffe0de12d49ec8 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Tue, 5 Mar 2019 00:57:02 +0100 Subject: Dock to view coprocessor 0 and cop0 counter/comparator support. Signed-off-by: Pavel Pisa --- qtmips_machine/cop0state.cpp | 81 ++++++++++++++++++++++++++++++---------- qtmips_machine/cop0state.h | 24 ++++++++---- qtmips_machine/core.cpp | 4 ++ qtmips_machine/qtmipsmachine.cpp | 18 +++++---- qtmips_machine/qtmipsmachine.h | 3 +- 5 files changed, 96 insertions(+), 34 deletions(-) (limited to 'qtmips_machine') 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 +#include #include #include 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; -- cgit v1.2.3