aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Pisa <pisa@cmp.felk.cvut.cz>2019-07-02 17:14:38 +0200
committerPavel Pisa <pisa@cmp.felk.cvut.cz>2019-07-02 17:14:38 +0200
commit040c1998500d3b0b50b3ddef4fe93216563343a8 (patch)
treec05815e566cc82d4276128b974e1557cb0d56a51
parentdce00ea47fd4100df97349fd2bf998169b05b74a (diff)
downloadqtmips-040c1998500d3b0b50b3ddef4fe93216563343a8.tar.gz
qtmips-040c1998500d3b0b50b3ddef4fe93216563343a8.tar.bz2
qtmips-040c1998500d3b0b50b3ddef4fe93216563343a8.zip
Teach simple embedded assembler .orig and .word directives.
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
-rw-r--r--qtmips_gui/fixmatheval.cpp2
-rw-r--r--qtmips_gui/fixmatheval.h2
-rw-r--r--qtmips_gui/mainwindow.cpp93
-rw-r--r--qtmips_gui/srceditor.cpp7
-rw-r--r--qtmips_gui/srceditor.h1
-rw-r--r--qtmips_machine/instruction.cpp90
-rw-r--r--qtmips_machine/instruction.h9
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 <QFile>
#include <QFileInfo>
#include <QTextDocumentWriter>
+#include <QTextCursor>
+#include <QTextBlock>
#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<QString> &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<RelocExpression *> RelocExpressionList;
@@ -148,12 +151,12 @@ public:
QString inst_base, QVector<QString> &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: