From 040c1998500d3b0b50b3ddef4fe93216563343a8 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Tue, 2 Jul 2019 17:14:38 +0200 Subject: Teach simple embedded assembler .orig and .word directives. Signed-off-by: Pavel Pisa --- qtmips_gui/fixmatheval.cpp | 2 +- qtmips_gui/fixmatheval.h | 2 +- qtmips_gui/mainwindow.cpp | 93 ++++++++++++++++++++++++++++++++++++------ qtmips_gui/srceditor.cpp | 7 ++++ qtmips_gui/srceditor.h | 1 + qtmips_machine/instruction.cpp | 90 +++++++++++++++++++++++++++++----------- qtmips_machine/instruction.h | 9 ++-- 7 files changed, 163 insertions(+), 41 deletions(-) diff --git a/qtmips_gui/fixmatheval.cpp b/qtmips_gui/fixmatheval.cpp index 8672cbc..f695e30 100644 --- a/qtmips_gui/fixmatheval.cpp +++ b/qtmips_gui/fixmatheval.cpp @@ -186,7 +186,7 @@ FmeExpression::FmeExpression() : FmeNode(0) { root = nullptr; } -bool FmeExpression::parse(QString &expression, QString &error) { +bool FmeExpression::parse(const QString &expression, QString &error) { delete root; int base_prio = 100; root = nullptr; diff --git a/qtmips_gui/fixmatheval.h b/qtmips_gui/fixmatheval.h index 7712530..3312bfa 100644 --- a/qtmips_gui/fixmatheval.h +++ b/qtmips_gui/fixmatheval.h @@ -112,7 +112,7 @@ class FmeExpression : public FmeNode { public: FmeExpression(); virtual ~FmeExpression(); - virtual bool parse(QString &expression, QString &error); + virtual bool parse(const QString &expression, QString &error); virtual bool eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) override; virtual bool insert(FmeNode *node) override; virtual FmeNode *child() override; diff --git a/qtmips_gui/mainwindow.cpp b/qtmips_gui/mainwindow.cpp index 3301367..58a0173 100644 --- a/qtmips_gui/mainwindow.cpp +++ b/qtmips_gui/mainwindow.cpp @@ -567,7 +567,25 @@ bool SymbolTableDb::getValue(fixmatheval::FmeValue &value, QString name) { return true; } +static std::uint64_t string_to_uint64(QString str, int base, + int *chars_taken = nullptr) { + int i; + std::int64_t val; + char *p, *r; + char cstr[str.count() + 1]; + for (i = 0; i < str.count(); i++) + cstr[i] = str.at(i).toLatin1(); + cstr[i] = 0; + p = cstr; + val = std::strtoll(p, &r, base); + if (chars_taken != nullptr) + *chars_taken = r - p; + return val; +} + void MainWindow::compile_source() { + SymbolTableDb symtab(machine->symbol_table()); + int error_line = 0; if (current_srceditor == nullptr) return; if (machine == nullptr) { @@ -586,7 +604,6 @@ void MainWindow::compile_source() { machine::RelocExpressionList reloc; int ln = 1; - bool ok = true; for ( QTextBlock block = doc->begin(); block.isValid(); block = block.next(), ln++) { int pos; QString label = ""; @@ -606,14 +623,53 @@ void MainWindow::compile_source() { } if (line.isEmpty()) continue; + QString op = line.split(" ").at(0).toUpper(); + if (op == ".ORG") { + bool ok; + QString error; + fixmatheval::FmeExpression expression; + fixmatheval::FmeValue value; + ok = expression.parse(line.mid(op.size()), error); + if (ok) + ok = expression.eval(value, &symtab, error); + if (!ok) { + error_line = ln; + editor->setCursorToLine(error_line); + QMessageBox::critical(this, "QtMips Error", + tr("line %1 .orig %2 parse error.") + .arg(QString::number(ln), line)); + break; + } + address = value; + continue; + } + if (op == ".WORD") { + QString error; + foreach (QString s, line.mid(op.size()).split(",")) { + s = s.simplified(); + std::uint32_t val = 0; + int chars_taken; + val = string_to_uint64(s, 0, &chars_taken); + if (chars_taken != s.size()) { + val = 0; + reloc.append(new machine::RelocExpression(address, s, 0, + -0xffffffff, 0xffffffff, 0, 32, 0, ln, 0)); + } + mem->write_word(address, val); + address += 4; + } + continue; + } + std::uint32_t inst[2] = {0, 0}; ssize_t size = machine::Instruction::code_from_string(inst, 8, line, address, &reloc, ln, true); if (size < 0) { + error_line = ln; + editor->setCursorToLine(error_line); QMessageBox::critical(this, "QtMips Error", - tr("line %1 instruction %2 parse error.") - .arg(QString::number(ln), line)); - ok = false; + tr("line %1 instruction %2 parse error.") + .arg(QString::number(ln), line)); break; } std::uint32_t *p = inst; @@ -622,28 +678,41 @@ void MainWindow::compile_source() { address += 4; } } - SymbolTableDb symtab(machine->symbol_table()); foreach(machine::RelocExpression *r, reloc) { QString error; fixmatheval::FmeExpression expression; - if (ok && !expression.parse(r->expression, error)) { - QMessageBox::critical(this, "QtMips Error", + if (!expression.parse(r->expression, error)) { + if (!error_line) { + error_line = r->line; + editor->setCursorToLine(error_line); + QMessageBox::critical(this, "QtMips Error", tr("expression parse error %1 at line %2, expression %3.") .arg(error, QString::number(r->line), expression.dump())); - ok = false; + } } else { fixmatheval::FmeValue value; - if (ok && !expression.eval(value, &symtab, error)) { - QMessageBox::critical(this, "QtMips Error", + if (!expression.eval(value, &symtab, error)) { + if (!error_line) { + error_line = r->line; + editor->setCursorToLine(error_line); + QMessageBox::critical(this, "QtMips Error", tr("expression evalution error %1 at line %2 , expression %3.") .arg(error, QString::number(r->line), expression.dump())); - ok = false; + } } else { if (false) QMessageBox::information(this, "QtMips info", expression.dump() + " -> " + QString::number(value)); machine::Instruction inst(mem->read_word(r->location, true)); - inst.update(value, r); + if (!inst.update(value, r)) { + if (!error_line) { + error_line = r->line; + editor->setCursorToLine(error_line); + QMessageBox::critical(this, "QtMips Error", + tr("instruction update error %1 at line %2, expression %3.") + .arg(error, QString::number(r->line), expression.dump())); + } + } mem->write_word(r->location, inst.data()); } } diff --git a/qtmips_gui/srceditor.cpp b/qtmips_gui/srceditor.cpp index 79e16e9..2f4d3a6 100644 --- a/qtmips_gui/srceditor.cpp +++ b/qtmips_gui/srceditor.cpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include "srceditor.h" @@ -87,3 +89,8 @@ bool SrcEditor::saveFile(QString filename) { } return success; } + +void SrcEditor::setCursorToLine(int ln) { + QTextCursor cursor(document()->findBlockByLineNumber(ln-1)); + setTextCursor(cursor); +} diff --git a/qtmips_gui/srceditor.h b/qtmips_gui/srceditor.h index 4deeb5f..a727f99 100644 --- a/qtmips_gui/srceditor.h +++ b/qtmips_gui/srceditor.h @@ -51,6 +51,7 @@ public: QString title(); bool loadFile(QString filename); bool saveFile(QString filename = ""); + void setCursorToLine(int ln); private: QString fname; QString tname; diff --git a/qtmips_machine/instruction.cpp b/qtmips_machine/instruction.cpp index 1d32f17..502fa81 100644 --- a/qtmips_machine/instruction.cpp +++ b/qtmips_machine/instruction.cpp @@ -1041,11 +1041,11 @@ static int parse_reg_from_string(QString str, uint *chars_taken = nullptr) static void reloc_append(RelocExpressionList *reloc, QString fl, uint32_t inst_addr, std::int64_t offset, const ArgumentDesc *adesc, uint *chars_taken = nullptr, - int line = 0) { + int line = 0, int options = 0) { uint bits = IMF_SUB_GET_BITS(adesc->loc); uint shift = IMF_SUB_GET_SHIFT(adesc->loc); QString expression = ""; - QString allowed_operators = "+-/*"; + QString allowed_operators = "+-/*|&"; int i = 0; for (; i < fl.size(); i++) { QChar ch = fl.at(i); @@ -1060,16 +1060,18 @@ static void reloc_append(RelocExpressionList *reloc, QString fl, uint32_t inst_a } reloc->append(new RelocExpression(inst_addr, expression, offset, - adesc->min, adesc->max, shift, bits, adesc->shift, line)); + adesc->min, adesc->max, shift, bits, adesc->shift, line, options)); if (chars_taken != nullptr) { *chars_taken = i; } } +#define CFS_OPTION_SILENT_MASK 0x100 + ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, QString inst_base, QVector &inst_fields, std::uint32_t inst_addr, RelocExpressionList *reloc, - int line, bool pseudo_opt) + int line, bool pseudo_opt, int options) { int field = 0; std::uint32_t inst_code = 0; @@ -1144,7 +1146,7 @@ ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, val += std::strtoull(p, &r, 0); chars_taken = r - p; } else { - reloc_append(reloc, fl, inst_addr, val, adesc, &chars_taken, line); + reloc_append(reloc, fl, inst_addr, val, adesc, &chars_taken, line, options); val = 0; } break; @@ -1161,7 +1163,7 @@ ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, chars_taken = r - p; break; } else { - reloc_append(reloc, fl, val, inst_addr, adesc, &chars_taken, line); + reloc_append(reloc, fl, val, inst_addr, adesc, &chars_taken, line, options); val = 0; } } @@ -1169,25 +1171,29 @@ ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, field = -1; break; } - if (val & ((1 << adesc->shift) - 1)) { + if ((val & ((1 << adesc->shift) - 1)) && + !(options & CFS_OPTION_SILENT_MASK)) { field = -1; break; } + int shift_right = adesc->shift + (options & 0xff); if (adesc->min >= 0) - val = (val >> adesc->shift) ; + val = (val >> shift_right) ; else - val = (std::uint64_t)((std::int64_t)val >> adesc->shift) ; - if (adesc->min < 0) { - if (((std::int64_t)val < adesc->min) || - ((std::int64_t)val > adesc->max)) { - field = -1; - break; - } - } else { - if ((val < (std::uint64_t)adesc->min) || - (val > (std::uint64_t)adesc->max)) { - field = -1; - break; + val = (std::uint64_t)((std::int64_t)val >> shift_right) ; + if (!(options & CFS_OPTION_SILENT_MASK)) { + if (adesc->min < 0) { + if (((std::int64_t)val < adesc->min) || + ((std::int64_t)val > adesc->max)) { + field = -1; + break; + } + } else { + if ((val < (std::uint64_t)adesc->min) || + (val > (std::uint64_t)adesc->max)) { + field = -1; + break; + } } } val = (val & ((1 << bits) - 1)) << shift; @@ -1210,6 +1216,19 @@ ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, if ((inst_base == "NOP") && (inst_fields.size() == 0)) { inst_code = 0; ret = 4; + } else if (pseudo_opt) { + if (((inst_base == "LA") || (inst_base == "LI")) && (inst_fields.size() == 2)) { + if(code_from_string(code, buffsize, "LUI", inst_fields, + inst_addr, reloc, line, false, + CFS_OPTION_SILENT_MASK + 16) < 0) + return -1; + inst_fields.insert(1, "$0"); + if (code_from_string(code + 1, buffsize - 4, "ORI", inst_fields, + inst_addr + 4, reloc, line, false, + CFS_OPTION_SILENT_MASK + 0) < 0) + return -1; + return 8; + } } if (buffsize >= 4) *code = inst_code; @@ -1218,7 +1237,7 @@ ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, QString str, std::uint32_t inst_addr, - RelocExpressionList *reloc, int line, bool pseudo_opt) + RelocExpressionList *reloc, int line, bool pseudo_opt, int options) { if (str_to_instruction_code_map.isEmpty()) instruction_from_string_build_base(); @@ -1270,12 +1289,35 @@ ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, return -1; return code_from_string(code, buffsize, inst_base, inst_fields, inst_addr, - reloc, line, pseudo_opt); + reloc, line, pseudo_opt, options); } bool Instruction::update(std::int64_t val, RelocExpression *relocexp) { - std::int64_t mask = ((1 << relocexp->bits) - 1) << relocexp->lsb_bit; + std::int64_t mask = (((std::int64_t)1 << relocexp->bits) - 1) << relocexp->lsb_bit; dt &= ~ mask; - dt |= (((val + relocexp->offset) >> relocexp->shift) << relocexp->lsb_bit) & mask; + val += relocexp->offset; + if ((val & ((1 << relocexp->shift) - 1)) && + !(relocexp->options & CFS_OPTION_SILENT_MASK)) { + return false; + } + int shift_right = relocexp->shift + (relocexp->options & 0xff); + if (relocexp->min >= 0) + val = (val >> shift_right) ; + else + val = (std::uint64_t)((std::int64_t)val >> shift_right); + if (!(relocexp->options & CFS_OPTION_SILENT_MASK)) { + if (relocexp->min < 0) { + if (((std::int64_t)val < relocexp->min) || + ((std::int64_t)val > relocexp->max)) { + return false; + } + } else { + if (((std::uint64_t)val < (std::uint64_t)relocexp->min) || + ((std::uint64_t)val > (std::uint64_t)relocexp->max)) { + return false; + } + } + } + dt |= (val << relocexp->lsb_bit) & mask; return true; } diff --git a/qtmips_machine/instruction.h b/qtmips_machine/instruction.h index 3e48fc2..76fca87 100644 --- a/qtmips_machine/instruction.h +++ b/qtmips_machine/instruction.h @@ -77,7 +77,8 @@ enum InstructionFlags { struct RelocExpression { inline RelocExpression(std::int32_t location, QString expression, std::int64_t offset, std::int64_t min, - std::int64_t max, unsigned lsb_bit, unsigned bits, unsigned shift, int line) { + std::int64_t max, unsigned lsb_bit, unsigned bits, unsigned shift, int line, + int options) { this->location = location; this->expression = expression; this->offset = offset; @@ -87,6 +88,7 @@ struct RelocExpression { this->bits = bits; this->shift = shift; this->line = line; + this->options = options; } std::int32_t location; QString expression; @@ -97,6 +99,7 @@ struct RelocExpression { unsigned bits; unsigned shift; int line; + int options; }; typedef QVector RelocExpressionList; @@ -148,12 +151,12 @@ public: QString inst_base, QVector &inst_fields, std::uint32_t inst_addr = 0, RelocExpressionList *reloc = nullptr, - int line = 0, bool pseudo_opt = false); + int line = 0, bool pseudo_opt = false, int options = 0); static ssize_t code_from_string(std::uint32_t *code, size_t buffsize, QString str, std::uint32_t inst_addr = 0, RelocExpressionList *reloc = nullptr, - int line = 0, bool pseudo_opt = false); + int line = 0, bool pseudo_opt = false, int options = 0); bool update(std::int64_t val, RelocExpression *relocexp); private: -- cgit v1.2.3