From 139dcf818566f9f2a48d95cdab9ad9e2ac7c7978 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Wed, 17 Jul 2019 19:48:43 +0200 Subject: Simple assembler moved to separate class which is independent on Qt GUI API. Signed-off-by: Pavel Pisa --- qtmips_asm/simpleasm.cpp | 285 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 qtmips_asm/simpleasm.cpp (limited to 'qtmips_asm/simpleasm.cpp') diff --git a/qtmips_asm/simpleasm.cpp b/qtmips_asm/simpleasm.cpp new file mode 100644 index 0000000..15d50b2 --- /dev/null +++ b/qtmips_asm/simpleasm.cpp @@ -0,0 +1,285 @@ +// 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 + * Copyright (c) 2019 Pavel Pisa + * + * 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 + +#include "simpleasm.h" + +using namespace fixmatheval; + + +SymbolTableDb::SymbolTableDb(machine::SymbolTable *symtab) { + this->symtab = symtab; +} + +bool SymbolTableDb::getValue(fixmatheval::FmeValue &value, QString name) { + std::uint32_t val; + if (!symtab->name_to_value(val, name)) + return false; + value = val; + return true; +} + +void SymbolTableDb::setSymbol(QString name, std::uint32_t value, std::uint32_t size, + unsigned char info, unsigned char other) { + symtab->set_symbol(name, value, size, info, other); +} + + +std::uint64_t SimpleAsm::string_to_uint64(QString str, int base, + int *chars_taken) { + 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; +} + +SimpleAsm::SimpleAsm(QObject *parent) : Super(parent) { + clear(); +} + +SimpleAsm::~SimpleAsm() { + clear(); +} + +void SimpleAsm::clear() { + symtab = nullptr; + mem = nullptr; + while (!reloc.isEmpty()) { + delete reloc.takeFirst(); + } + error_occured = false; + fatal_occured = false; +} + +void SimpleAsm::setup(machine::MemoryAccess *mem, SymbolTableDb *symtab, + std::uint32_t address) { + this->mem = mem; + this->symtab = symtab; + this->address = address; +} + +bool SimpleAsm::process_line(QString line, QString filename, + int line_number, QString *error_ptr) { + QString error; + int pos; + QString label = ""; + pos = line.indexOf("#"); + if (pos >= 0) + line.truncate(pos); + pos = line.indexOf(";"); + if (pos >= 0) + line.truncate(pos); + pos = line.indexOf("//"); + if (pos >= 0) + line.truncate(pos); + line = line.simplified(); + pos = line.indexOf(":"); + if (pos >= 0) { + label = line.mid(0, pos); + line = line.mid(pos + 1).trimmed(); + symtab->setSymbol(label, address, 4); + } + if (line.isEmpty()) + return true; + int k = 0, l; + while (k < line.count()) { + if (!line.at(k).isSpace()) + break; + k++; + } + l = k; + while (l < line.count()) { + if (!line.at(l).isLetterOrNumber() && !(line.at(l) == '.')) + break; + l++; + } + QString op = line.mid(k, l - k).toUpper(); + if ((op == ".DATA") || (op == ".TEXT") || + (op == ".GLOBL") || (op == ".END") || + (op == ".ENT")) { + return true; + } + if (op == ".ORG") { + bool ok; + 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 = tr("line %1 .orig %2 parse error.") + .arg(QString::number(line_number), line); + emit report_message(messagetype::ERROR, filename, line_number, 0, error, ""); + error_occured = true; + fatal_occured = true; + if (error_ptr != nullptr) + *error_ptr = error; + return false; + } + address = value; + return true; + } + if ((op == ".EQU") || (op == ".SET")) { + QStringList operands = line.mid(op.size()).split(","); + if ((operands.count() > 2) || (operands.count() < 1)) { + error = tr("line %1 .set or .equ incorrect arguments number.") + .arg(QString::number(line_number)); + emit report_message(messagetype::ERROR, filename, line_number, 0, error, ""); + error_occured = true; + if (error_ptr != nullptr) + *error_ptr = error; + return false; + } + QString name = operands.at(0).trimmed(); + if ((name == "noat") || (name == "noreored")) + return true; + bool ok; + fixmatheval::FmeValue value = 1; + if (operands.count() > 1) { + fixmatheval::FmeExpression expression; + ok = expression.parse(operands.at(1), error); + if (ok) + ok = expression.eval(value, symtab, error); + if (!ok) { + error = tr("line %1 .set or .equ %2 parse error.") + .arg(QString::number(line_number), operands.at(1)); + emit report_message(messagetype::ERROR, filename, line_number, 0, error, ""); + error_occured = true; + if (error_ptr != nullptr) + *error_ptr = error; + return false; + } + } + symtab->setSymbol(name, value, 0); + return true; + } + if (op == ".WORD") { + 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, filename, line_number, 0)); + } + if (fatal_occured) + mem->write_word(address, val); + address += 4; + } + return true; + } + + std::uint32_t inst[2] = {0, 0}; + ssize_t size = machine::Instruction::code_from_string(inst, 8, line, error, + address, &reloc, filename, line_number, true); + if (size < 0) { + error = tr("line %1 instruction %2 parse error - %3.") + .arg(QString::number(line_number), line, error); + emit report_message(messagetype::ERROR, filename, line_number, 0, error, ""); + error_occured = true; + if (error_ptr != nullptr) + *error_ptr = error; + return false; + } + std::uint32_t *p = inst; + for (ssize_t l = 0; l < size; l += 4) { + if (!fatal_occured) + mem->write_word(address, *(p++)); + address += 4; + } + return true; +} + +bool SimpleAsm::finish(QString *error_ptr) { + bool error_reported = false; + foreach(machine::RelocExpression *r, reloc) { + QString error; + fixmatheval::FmeExpression expression; + if (!expression.parse(r->expression, error)) { + error = tr("expression parse error %1 at line %2, expression %3.") + .arg(error, QString::number(r->line), expression.dump()); + emit report_message(messagetype::ERROR, r->filename, r->line, 0, error, ""); + if (error_ptr != nullptr && !error_reported) + *error_ptr = error; + error_occured = true; + error_reported = true; + } else { + fixmatheval::FmeValue value; + if (!expression.eval(value, symtab, error)) { + error = tr("expression evalution error %1 at line %2 , expression %3.") + .arg(error, QString::number(r->line), expression.dump()); + emit report_message(messagetype::ERROR, r->filename, r->line, 0, error, ""); + if (error_ptr != nullptr && !error_reported) + *error_ptr = error; + error_occured = true; + error_reported = true; + } else { + if (false) + emit report_message(messagetype::INFO, r->filename, r->line, 0, + expression.dump() + " -> " + QString::number(value), ""); + machine::Instruction inst(mem->read_word(r->location, true)); + if (!inst.update(value, r)) { + error = tr("instruction update error %1 at line %2, expression %3 -> value %4.") + .arg(error, QString::number(r->line), expression.dump(), QString::number(value)); + emit report_message(messagetype::ERROR, r->filename, r->line, 0, error, ""); + if (error_ptr != nullptr && !error_reported) + *error_ptr = error; + error_occured = true; + error_reported = true; + } + if (!fatal_occured) + mem->write_word(r->location, inst.data()); + } + } + } + while (!reloc.isEmpty()) { + delete reloc.takeFirst(); + } + + emit mem->external_change_notify(mem, 0, 0xffffffff, true); + + return !error_occured; +} -- cgit v1.2.3