aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Pisa <pisa@cmp.felk.cvut.cz>2019-02-12 16:18:58 +0100
committerPavel Pisa <pisa@cmp.felk.cvut.cz>2019-02-12 16:18:58 +0100
commitdf292aade4d174a7a5824f463b3a1dccf20e6c54 (patch)
tree85d26d5a0d5101f5caae6dcde20b515f98bcbb06
parentfc27072b451dd8385401fadf198db69b0e87c72c (diff)
downloadqtmips-df292aade4d174a7a5824f463b3a1dccf20e6c54.tar.gz
qtmips-df292aade4d174a7a5824f463b3a1dccf20e6c54.tar.bz2
qtmips-df292aade4d174a7a5824f463b3a1dccf20e6c54.zip
Make memory and program listing editable.
Instruction parsing is rough and does not support branch offset computation. Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
-rw-r--r--qtmips_gui/memorymodel.cpp42
-rw-r--r--qtmips_gui/memorymodel.h2
-rw-r--r--qtmips_gui/programmodel.cpp41
-rw-r--r--qtmips_gui/programmodel.h2
-rw-r--r--qtmips_machine/instruction.cpp258
-rw-r--r--qtmips_machine/instruction.h1
-rw-r--r--qtmips_machine/qtmipsmachine.cpp8
-rw-r--r--qtmips_machine/qtmipsmachine.h2
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 <QMultiMap>
+#include <QVector>
#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<QString, std::uint32_t> 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<QString> 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();