aboutsummaryrefslogtreecommitdiff
path: root/qtmips_asm
diff options
context:
space:
mode:
Diffstat (limited to 'qtmips_asm')
-rw-r--r--qtmips_asm/fixmatheval.cpp331
-rw-r--r--qtmips_asm/fixmatheval.h126
-rw-r--r--qtmips_asm/qtmips_asm.pro20
3 files changed, 477 insertions, 0 deletions
diff --git a/qtmips_asm/fixmatheval.cpp b/qtmips_asm/fixmatheval.cpp
new file mode 100644
index 0000000..8852938
--- /dev/null
+++ b/qtmips_asm/fixmatheval.cpp
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*******************************************************************************
+ * QtMips - MIPS 32-bit Architecture Subset Simulator
+ *
+ * Implemented to support following courses:
+ *
+ * B35APO - Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b35apo
+ *
+ * B4M35PAP - Advanced Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start
+ *
+ * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz>
+ * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *
+ * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
+ * Czech Technical University (http://www.cvut.cz/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ ******************************************************************************/
+
+#include "fixmatheval.h"
+
+#include "limits.h"
+
+using namespace fixmatheval;
+
+FmeSymbolDb::~FmeSymbolDb() {
+}
+
+bool FmeSymbolDb::getValue(FmeValue &value, QString name) {
+ (void)value;
+ (void)name;
+ return false;
+}
+
+FmeNode::FmeNode(int priority) {
+ prio = priority;
+}
+
+FmeNode::~FmeNode() {
+}
+
+int FmeNode::priority() {
+ return prio;
+}
+
+bool FmeNode::insert(FmeNode *node) {
+ (void)node;
+ return false;
+}
+
+FmeNode *FmeNode::child() {
+ return nullptr;
+}
+
+
+FmeNodeConstant::FmeNodeConstant(FmeValue value) : FmeNode(INT_MAX) {
+ this->value = value;
+}
+
+FmeNodeConstant::~FmeNodeConstant() {
+
+}
+
+bool FmeNodeConstant::eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) {
+ (void)symdb;
+ (void)error;
+ value = this->value;
+ return true;
+}
+
+QString FmeNodeConstant::dump() {
+ return QString::number(value);
+}
+
+FmeNodeSymbol::FmeNodeSymbol(QString &name) : FmeNode(INT_MAX) {
+ this->name = name;
+}
+
+FmeNodeSymbol::~FmeNodeSymbol() {
+}
+
+bool FmeNodeSymbol::eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) {
+ if (!symdb) {
+ error = QString("no symbol table to find value for %1").arg(name);
+ return false;
+ }
+ bool ok = symdb->getValue(value, name);
+ if (!ok)
+ error = QString("value for symbol \"%1\" not found").arg(name);
+ return ok;
+}
+
+QString FmeNodeSymbol::dump() {
+ return name;
+}
+
+FmeNodeUnaryOp::FmeNodeUnaryOp(int priority, FmeValue (*op)(FmeValue &a)) :
+ FmeNode(priority) {
+ this->operand_a = nullptr;
+ this->op = op;
+}
+
+FmeNodeUnaryOp::~FmeNodeUnaryOp() {
+ delete operand_a;
+}
+
+bool FmeNodeUnaryOp::FmeNodeUnaryOp::eval(FmeValue &value, FmeSymbolDb *symdb,
+ QString &error) {
+ FmeValue value_a;
+ if (!operand_a)
+ return false;
+ if (!operand_a->eval(value_a, symdb, error))
+ return false;
+ value = op(value_a);
+ return true;
+}
+
+FmeNode *FmeNodeUnaryOp::child() {
+ return operand_a;
+}
+
+bool FmeNodeUnaryOp::insert(FmeNode *node) {
+ operand_a = node;
+ return true;
+}
+
+QString FmeNodeUnaryOp::dump() {
+ return "(OP " + (operand_a? operand_a->dump(): "nullptr") + ")";
+}
+
+FmeNodeBinaryOp::FmeNodeBinaryOp(int priority, FmeValue (*op)(FmeValue &a, FmeValue &b),
+ FmeNode *left) : FmeNode(priority) {
+ this->operand_a = left;
+ this->operand_b = nullptr;
+ this->op = op;
+}
+
+FmeNodeBinaryOp::~FmeNodeBinaryOp() {
+ delete operand_a;
+ delete operand_b;
+}
+
+bool FmeNodeBinaryOp::eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) {
+ FmeValue value_a;
+ FmeValue value_b;
+ if (!operand_a || !operand_b)
+ return false;
+ if (!operand_a->eval(value_a, symdb, error) ||
+ !operand_b->eval(value_b, symdb, error))
+ return false;
+ value = op(value_a, value_b);
+ return true;
+}
+
+FmeNode *FmeNodeBinaryOp::child() {
+ return operand_b;
+}
+
+bool FmeNodeBinaryOp::insert(FmeNode *node) {
+ operand_b = node;
+ return true;
+}
+
+QString FmeNodeBinaryOp::dump() {
+ return "(" + (operand_a? operand_a->dump(): "nullptr") +
+ " OP " + (operand_b? operand_b->dump(): "nullptr") + ")";
+}
+
+FmeExpression::FmeExpression() : FmeNode(0) {
+ root = nullptr;
+}
+
+bool FmeExpression::parse(const QString &expression, QString &error) {
+ delete root;
+ int base_prio = 100;
+ root = nullptr;
+ bool ok = true;
+ int i;
+ int word_start = 0;
+ bool in_word = false;
+ bool is_unary = true;
+ for (i = 0; true; i++) {
+ QChar ch = 0;
+ if (i < expression.size())
+ ch = expression.at(i);
+ if(!(ch.isLetterOrNumber() || (ch == '_')) || (i >= expression.size())) {
+ if (in_word) {
+ FmeNode *new_node = nullptr;
+ QString word = expression.mid(word_start, i - word_start);
+ if (word.at(0).isDigit()) {
+ new_node = new FmeNodeConstant(word.toLongLong(&ok, 0));
+ if (!ok) {
+ error = QString("cannot convert \"%1\" to number").arg(word);
+ break;
+ }
+ } else {
+ new_node = new FmeNodeSymbol(word);
+ }
+ FmeNode *node;
+ FmeNode *child;
+ for (node = this; (child = node->child()) != nullptr; node = child);
+ ok = node->insert(new_node);
+ if (!ok) {
+ error = QString("parse stuck at \"%1\"").arg(word);
+ break;
+ }
+
+ in_word = false;
+ is_unary = false;
+ if (i >= expression.size())
+ break;
+ }
+ if (ch.isSpace())
+ continue;
+ FmeValue (*binary_op)(FmeValue &a, FmeValue &b) = nullptr;
+ FmeValue (*unary_op)(FmeValue &a) = nullptr;
+ int prio = base_prio;
+
+ if (ch == '~') {
+ prio += 90;
+ unary_op = [](FmeValue &a) -> FmeValue { return ~a; };
+ } else if (ch == '-') {
+ if (is_unary) {
+ prio += 90;
+ unary_op = [](FmeValue &a) -> FmeValue { return -a; };
+ } else {
+ binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a - b; };
+ prio += 20;
+ }
+ } else if (ch == '+') {
+ if (is_unary)
+ continue;
+ binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a + b; };
+ prio += 20;
+ } else if (ch == '*') {
+ binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a * b; };
+ prio += 30;
+ } else if (ch == '/') {
+ binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a / b; };
+ prio += 30;
+ } else if (ch == '|') {
+ binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a | b; };
+ prio += 10;
+ } else if (ch == '&') {
+ binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a & b; };
+ prio += 15;
+ } else if (ch == '^') {
+ binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a ^ b; };
+ prio += 15;
+ } else if (ch == '(') {
+ base_prio += 100;
+ } else if (ch == ')') {
+ base_prio -= 100;
+ if (base_prio <= 0) {
+ ok = false;
+ error = QString("Unbalanced brackets.");
+ break;
+ }
+ } else {
+ error = QString("Unknow character \"%1\" in expression.").arg(ch);
+ ok = false;
+ break;
+ }
+ if ((binary_op != nullptr) || (unary_op != nullptr)) {
+ FmeNode *node;
+ FmeNode *child;
+ for (node = this; (child = node->child()) != nullptr; node = child) {
+ if (child->priority() >= prio)
+ break;
+ }
+ if (binary_op != nullptr) {
+ ok = node->insert(new FmeNodeBinaryOp(prio, binary_op, child));
+ is_unary = true;
+ } else {
+ ok = node->insert(new FmeNodeUnaryOp(prio, unary_op));
+ }
+ if (!ok) {
+ error = QString("parse stuck at \"%1\"").arg(QString(ch));
+ break;
+ }
+ }
+ } else {
+ if (!in_word)
+ word_start = i;
+ in_word = true;
+ }
+ }
+
+ return ok;
+}
+
+FmeExpression::~FmeExpression() {
+ delete root;
+ root = nullptr;
+}
+
+bool FmeExpression::eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) {
+ if (!root)
+ return false;
+ return root->eval(value, symdb, error);
+}
+
+bool FmeExpression::insert(FmeNode *node) {
+ root = node;
+ return true;
+}
+
+FmeNode *FmeExpression::child() {
+ return root;
+}
+
+QString FmeExpression::dump() {
+ return "(" + (root? root->dump(): "nullptr") + ")";
+}
+
diff --git a/qtmips_asm/fixmatheval.h b/qtmips_asm/fixmatheval.h
new file mode 100644
index 0000000..3312bfa
--- /dev/null
+++ b/qtmips_asm/fixmatheval.h
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*******************************************************************************
+ * QtMips - MIPS 32-bit Architecture Subset Simulator
+ *
+ * Implemented to support following courses:
+ *
+ * B35APO - Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b35apo
+ *
+ * B4M35PAP - Advanced Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start
+ *
+ * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz>
+ * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *
+ * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
+ * Czech Technical University (http://www.cvut.cz/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ ******************************************************************************/
+
+#ifndef FIXMATHEVAL_H
+#define FIXMATHEVAL_H
+
+#include <QString>
+
+namespace fixmatheval {
+
+typedef std::int64_t FmeValue;
+
+class FmeSymbolDb {
+public:
+ virtual ~FmeSymbolDb();
+ virtual bool getValue(FmeValue &value, QString name) = 0;
+};
+
+class FmeNode {
+public:
+ FmeNode(int priority);
+ virtual ~FmeNode();
+ virtual bool eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) = 0;
+ virtual bool insert(FmeNode *node);
+ virtual FmeNode *child();
+ virtual QString dump() = 0;
+ int priority();
+private:
+ int prio;
+};
+
+class FmeNodeConstant : public FmeNode {
+public:
+ FmeNodeConstant(FmeValue value);
+ virtual ~FmeNodeConstant();
+ virtual bool eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) override;
+ virtual QString dump() override;
+private:
+ FmeValue value;
+};
+
+class FmeNodeSymbol : public FmeNode {
+public:
+ FmeNodeSymbol(QString &name);
+ virtual ~FmeNodeSymbol();
+ virtual bool eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) override;
+ virtual QString dump() override;
+private:
+ QString name;
+};
+
+class FmeNodeUnaryOp : public FmeNode {
+public:
+ FmeNodeUnaryOp(int priority, FmeValue (*op)(FmeValue &a));
+ virtual ~FmeNodeUnaryOp();
+ virtual bool eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) override;
+ virtual bool insert(FmeNode *node) override;
+ virtual FmeNode *child() override;
+ virtual QString dump() override;
+private:
+ FmeValue (*op)(FmeValue &a);
+ FmeNode *operand_a;
+};
+
+class FmeNodeBinaryOp : public FmeNode {
+public:
+ FmeNodeBinaryOp(int priority, FmeValue (*op)(FmeValue &a, FmeValue &b), FmeNode *left);
+ virtual ~FmeNodeBinaryOp();
+ virtual bool eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) override;
+ virtual bool insert(FmeNode *node) override;
+ virtual FmeNode *child() override;
+ virtual QString dump() override;
+private:
+ FmeValue (*op)(FmeValue &a, FmeValue &b);
+ FmeNode *operand_a;
+ FmeNode *operand_b;
+};
+
+class FmeExpression : public FmeNode {
+public:
+ FmeExpression();
+ virtual ~FmeExpression();
+ 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;
+ virtual QString dump() override;
+private:
+ FmeNode *root;
+};
+
+}
+
+#endif /*FIXMATHEVAL*/
diff --git a/qtmips_asm/qtmips_asm.pro b/qtmips_asm/qtmips_asm.pro
new file mode 100644
index 0000000..20b988f
--- /dev/null
+++ b/qtmips_asm/qtmips_asm.pro
@@ -0,0 +1,20 @@
+QT -= gui
+
+TARGET = qtmips_asm
+CONFIG += c++11
+
+TEMPLATE = lib
+CONFIG += staticlib
+
+LIBS += -lelf
+QMAKE_CXXFLAGS += -std=c++0x
+QMAKE_CXXFLAGS_DEBUG += -ggdb
+
+DEFINES += QTMIPS_MACHINE_LIBRARY
+DEFINES += QT_DEPRECATED_WARNINGS
+
+SOURCES += \
+ fixmatheval.cpp
+
+HEADERS += \
+ fixmatheval.h