From df292aade4d174a7a5824f463b3a1dccf20e6c54 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Tue, 12 Feb 2019 16:18:58 +0100 Subject: Make memory and program listing editable. Instruction parsing is rough and does not support branch offset computation. Signed-off-by: Pavel Pisa --- qtmips_gui/memorymodel.cpp | 42 +++++++ qtmips_gui/memorymodel.h | 2 + qtmips_gui/programmodel.cpp | 41 +++++++ qtmips_gui/programmodel.h | 2 + qtmips_machine/instruction.cpp | 258 ++++++++++++++++++++++++++++++++++++++- qtmips_machine/instruction.h | 1 + qtmips_machine/qtmipsmachine.cpp | 8 ++ qtmips_machine/qtmipsmachine.h | 2 + 8 files changed, 352 insertions(+), 4 deletions(-) diff --git a/qtmips_gui/memorymodel.cpp b/qtmips_gui/memorymodel.cpp index 12b3fcb..597b88f 100644 --- a/qtmips_gui/memorymodel.cpp +++ b/qtmips_gui/memorymodel.cpp @@ -225,3 +225,45 @@ void MemoryModel::cached_access(int cached) { access_through_cache = cached; update_all(); } + +Qt::ItemFlags MemoryModel::flags(const QModelIndex &index) const { + if (index.column() == 0) + return QAbstractTableModel::flags(index); + else + return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; +} + +bool MemoryModel::setData(const QModelIndex & index, const QVariant & value, int role) { + if (role == Qt::EditRole) + { + bool ok; + std::uint32_t address; + std::uint32_t data = value.toString().toULong(&ok, 16); + if (!ok) + return false; + machine::MemoryAccess *mem; + if (!get_row_address(address, index.row())) + return false; + if (index.column() == 0 || machine == nullptr) + return false; + mem = machine->memory_rw(); + if (mem == nullptr) + return false; + if ((access_through_cache > 0) && (machine->cache_data_rw() != nullptr)) + mem = machine->cache_data_rw(); + address += cellSizeBytes() * (index.column() - 1); + switch (cell_size) { + case CELLSIZE_BYTE: + mem->write_byte(address, data); + break; + case CELLSIZE_HWORD: + mem->write_hword(address, data); + break; + default: + case CELLSIZE_WORD: + mem->write_word(address, data); + break; + } + } + return true; +} diff --git a/qtmips_gui/memorymodel.h b/qtmips_gui/memorymodel.h index 83bc057..7d12f91 100644 --- a/qtmips_gui/memorymodel.h +++ b/qtmips_gui/memorymodel.h @@ -57,6 +57,8 @@ public: int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex &index) const; + bool setData(const QModelIndex & index, const QVariant & value, int role); bool adjustRowAndOffset(int &row, int optimal_row, std::uint32_t address); void update_all(); diff --git a/qtmips_gui/programmodel.cpp b/qtmips_gui/programmodel.cpp index 4a758b7..5112bb8 100644 --- a/qtmips_gui/programmodel.cpp +++ b/qtmips_gui/programmodel.cpp @@ -203,3 +203,44 @@ void ProgramModel::toggle_hw_break(const QModelIndex & index) { machine->insert_hwbreak(address); update_all(); } + +Qt::ItemFlags ProgramModel::flags(const QModelIndex &index) const { + if (index.column() != 2 && index.column() != 3) + return QAbstractTableModel::flags(index); + else + return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; +} + +bool ProgramModel::setData(const QModelIndex & index, const QVariant & value, int role) { + if (role == Qt::EditRole) + { + bool ok; + std::uint32_t address; + std::uint32_t data; + machine::MemoryAccess *mem; + if (!get_row_address(address, index.row())) + return false; + if (index.column() == 0 || machine == nullptr) + return false; + mem = machine->memory_rw(); + if (mem == nullptr) + return false; + switch (index.column()) { + case 2: + data = value.toString().toULong(&ok, 16); + if (!ok) + return false; + mem->write_word(address, data); + break; + case 3: + data = machine::Instruction::from_string(value.toString(), &ok).data(); + if (!ok) + return false; + mem->write_word(address, data); + break; + default: + return false; + } + } + return true; +} diff --git a/qtmips_gui/programmodel.h b/qtmips_gui/programmodel.h index a6db493..9beecef 100644 --- a/qtmips_gui/programmodel.h +++ b/qtmips_gui/programmodel.h @@ -51,6 +51,8 @@ public: int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex &index) const; + bool setData(const QModelIndex & index, const QVariant & value, int role); bool adjustRowAndOffset(int &row, int optimal_row, std::uint32_t address); void update_all(); diff --git a/qtmips_machine/instruction.cpp b/qtmips_machine/instruction.cpp index 70247bd..90a6ca1 100644 --- a/qtmips_machine/instruction.cpp +++ b/qtmips_machine/instruction.cpp @@ -33,6 +33,8 @@ * ******************************************************************************/ +#include +#include #include "instruction.h" #include "alu.h" #include "memory.h" @@ -440,24 +442,29 @@ Instruction::Instruction(const Instruction &i) { #define MASK(LEN,OFF) ((this->dt >> (OFF)) & ((1 << (LEN)) - 1)) +#define RS_SHIFT 21 +#define RT_SHIFT 16 +#define RD_SHIFT 11 +#define SHAMT_SHIFT 6 + std::uint8_t Instruction::opcode() const { return (std::uint8_t) MASK(6, 26); } std::uint8_t Instruction::rs() const { - return (std::uint8_t) MASK(5, 21); + return (std::uint8_t) MASK(5, RS_SHIFT); } std::uint8_t Instruction::rt() const { - return (std::uint8_t) MASK(5, 16); + return (std::uint8_t) MASK(5, RT_SHIFT); } std::uint8_t Instruction::rd() const { - return (std::uint8_t) MASK(5, 11); + return (std::uint8_t) MASK(5, RD_SHIFT); } std::uint8_t Instruction::shamt() const { - return (std::uint8_t) MASK(5, 6); + return (std::uint8_t) MASK(5, SHAMT_SHIFT); } @@ -617,3 +624,246 @@ QString Instruction::to_str(std::int32_t inst_addr) const { } return res; } + +QMultiMap str_to_instruction_code_map; + +void instruction_from_string_build_base(const InstructionMap *im = nullptr, + unsigned int flags = 0, std::uint32_t base_code = 0) { + std::uint32_t code; + + if (im == nullptr) { + im = instruction_map; + flags = instruction_map_opcode_field; + base_code = 0; + } + unsigned int bits = IMF_SUB_GET_BITS(flags); + unsigned int shift = IMF_SUB_GET_SHIFT(flags); + + for (unsigned int i = 0; i < 1U << bits; i++, im++) { + code = base_code | (i << shift); + if (im->subclass) { + instruction_from_string_build_base(im->subclass, im->flags, code); + continue; + } + if (!(im->flags & IMF_SUPPORTED)) + continue; + str_to_instruction_code_map.insert(im->name, code); + } +} + +static int parse_reg_from_string(QString str) +{ + bool ok; + int res; + if (str.count() < 2 || str.at(0) != '$') + return -1; + str = str.mid(1, str.count() - 1); + res = str.toULong(&ok, 10); + if (!ok) + return -1; + if (res > 31) + return -1; + return res; +} + +Instruction Instruction::from_string(QString str, bool *pok) { + std::uint32_t code; + int val; + bool ok = false; + + if (str_to_instruction_code_map.isEmpty()) + instruction_from_string_build_base(); + + str = str.toUpper(); + + QString inst_base = ""; + QVector inst_fields(0); + bool prev_white = true; + bool act_white; + bool comma = false; + bool next_comma = false; + int field = 0; + bool error = false; + + for (int k = 0, l = 0; k < str.count() + 1; k++, prev_white = act_white) { + if (next_comma) + comma = true; + next_comma = false; + if (k >= str.count()) { + act_white = true; + } else { + act_white = str.at(k).isSpace(); + if (str.at(k) == ',') + next_comma = act_white = true; + } + + if (prev_white and !act_white) + l = k; + if (!prev_white and act_white) { + if (inst_base.count() == 0) { + if (comma) { + error = true; + break; + } + inst_base = str.mid(l, k - l); + } else { + if ((field && !comma) || (!field && comma)) { + error = true; + break; + } + inst_fields.append(str.mid(l, k - l)); + comma = false; + field++; + } + l = k; + } + } + + if (error) { + if (pok != nullptr) + *pok = true; + return Instruction(0); + } + + auto i = str_to_instruction_code_map.lowerBound(inst_base); + for (; ; i++) { + if (i == str_to_instruction_code_map.end()) + break; + if (i.key() != inst_base) + break; + code = i.value(); + const InstructionMap &im = InstructionMapFind(code); + + field = 0; + switch (im.type) { + case T_I: + if (im.flags & IMF_MEM) { + if (field >= inst_fields.count()) + continue; + if ((val = parse_reg_from_string(inst_fields.at(field++))) < 0) + continue; + code |= val << RT_SHIFT; + if (field >= inst_fields.count()) + continue; + int lpar = inst_fields.at(field).indexOf('('); + int rpar = inst_fields.at(field).indexOf(')'); + if (lpar == -1 || rpar == -1) + continue; + if ((val = parse_reg_from_string(inst_fields. + at(field).mid(lpar+1, rpar - lpar - 1))) < 0) + continue; + code |= val << RS_SHIFT; + + val = inst_fields.at(field).mid(0, lpar).toLong(&ok, 0); + if (!ok) + continue; + ok = false; + code |= val & 0xffff; + field ++; + } else { + if (im.flags & IMF_REGWRITE) { + if (field >= inst_fields.count()) + continue; + if ((val = parse_reg_from_string(inst_fields.at(field++))) < 0) + continue; + code |= val << RT_SHIFT; + } + if (im.flags & (IMF_BJR_REQ_RS | IMF_ALU_REQ_RS)) { + if (field >= inst_fields.count()) + continue; + if ((val = parse_reg_from_string(inst_fields.at(field++))) < 0) + continue; + code |= val << RS_SHIFT; + } + if (im.flags & (IMF_BJR_REQ_RT | IMF_ALU_REQ_RT) && !(im.flags & IMF_REGWRITE)) { + if (field >= inst_fields.count()) + continue; + if ((val = parse_reg_from_string(inst_fields.at(field++))) < 0) + continue; + code |= val << RT_SHIFT; + } + if (field >= inst_fields.count()) + continue; + val = inst_fields.at(field++).toLong(&ok, 0); + if (!ok) + continue; + ok = false; + code |= val & 0xffff; + } + break; + case T_J: + if (field >= inst_fields.count()) + continue; + val = inst_fields.at(field++).toLong(&ok, 0); + code |= (val >> 2) & ~0xF0000000; + break; + case T_R: + if (im.flags & IMF_REGD) { + if (field >= inst_fields.count()) + continue; + if ((val = parse_reg_from_string(inst_fields.at(field++))) < 0) + continue; + code |= val << RD_SHIFT; + } + if (!(im.flags & IMF_ALU_SHIFT)) { + if (im.flags & (IMF_BJR_REQ_RS | IMF_ALU_REQ_RS)) { + if (field >= inst_fields.count()) + continue; + if ((val = parse_reg_from_string(inst_fields.at(field++))) < 0) + continue; + code |= val << RS_SHIFT; + } + } + if (im.flags & (IMF_BJR_REQ_RT | IMF_ALU_REQ_RT)) { + if (field >= inst_fields.count()) + continue; + if ((val = parse_reg_from_string(inst_fields.at(field++))) < 0) + continue; + code |= val << RT_SHIFT; + } + if (im.flags & IMF_ALU_SHIFT) { + if (im.flags & (IMF_BJR_REQ_RS | IMF_ALU_REQ_RS)) { + if (field >= inst_fields.count()) + continue; + if ((val = parse_reg_from_string(inst_fields.at(field++))) < 0) + continue; + code |= val << RS_SHIFT; + } else { + if (field >= inst_fields.count()) + continue; + val = inst_fields.at(field++).toLong(&ok, 0); + if (!ok) + continue; + ok = false; + code |= val << (SHAMT_SHIFT & 0x1f); + } + } + if ((im.flags & IMF_REGWRITE) && !(im.flags & IMF_REGD)) { + if (field >= inst_fields.count()) + continue; + if ((val = parse_reg_from_string(inst_fields.at(field++))) < 0) + continue; + code |= val << RD_SHIFT; + } + break; + case T_UNKNOWN: + break; + } + + if (field != inst_fields.count()) + continue; + + if (pok != nullptr) + *pok = true; + + return Instruction(code); + } + + printf("not found\n"); + + if (str == "NOP") + ok = true; + if (pok != nullptr) + *pok = ok; + return Instruction(0); +} diff --git a/qtmips_machine/instruction.h b/qtmips_machine/instruction.h index bb6f410..0d76eeb 100644 --- a/qtmips_machine/instruction.h +++ b/qtmips_machine/instruction.h @@ -115,6 +115,7 @@ public: QString to_str(std::int32_t inst_addr = 0) const; + static Instruction from_string(QString str, bool *pok = nullptr); private: std::uint32_t dt; }; diff --git a/qtmips_machine/qtmipsmachine.cpp b/qtmips_machine/qtmipsmachine.cpp index 382a9f2..69deeb1 100644 --- a/qtmips_machine/qtmipsmachine.cpp +++ b/qtmips_machine/qtmipsmachine.cpp @@ -114,6 +114,10 @@ const Memory *QtMipsMachine::memory() { return mem; } +Memory *QtMipsMachine::memory_rw() { + return mem; +} + const Cache *QtMipsMachine::cache_program() { return cch_program; } @@ -122,6 +126,10 @@ const Cache *QtMipsMachine::cache_data() { return cch_data; } +Cache *QtMipsMachine::cache_data_rw() { + return cch_data; +} + const Core *QtMipsMachine::core() { return cr; } diff --git a/qtmips_machine/qtmipsmachine.h b/qtmips_machine/qtmipsmachine.h index 22ba0f9..4ad39c5 100644 --- a/qtmips_machine/qtmipsmachine.h +++ b/qtmips_machine/qtmipsmachine.h @@ -61,8 +61,10 @@ public: const Registers *registers(); const Memory *memory(); + Memory *memory_rw(); const Cache *cache_program(); const Cache *cache_data(); + Cache *cache_data_rw(); const Core *core(); const CoreSingle *core_singe(); const CorePipelined *core_pipelined(); -- cgit v1.2.3