diff options
author | bd <bdunaisky@umass.edu> | 2025-04-28 03:44:42 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-28 03:44:42 +0000 |
commit | 013a79547aa465872d0262b2f5c24e73f9556869 (patch) | |
tree | 28cc8f2ea6e5aa1a74f328de8594b0ad5995fa66 | |
parent | 5653b2a033e7a4173d2f178b5ce52384666d3d7b (diff) | |
parent | 336faf3fd701aaf962613abd1ff0a69cbdf021ce (diff) |
Merge pull request #69 from bdunahu/vector_ext
Vector ext
32 files changed, 908 insertions, 804 deletions
diff --git a/gui/cachewaysselector.cc b/gui/cachewaysselector.cc new file mode 100644 index 0000000..14dae6f --- /dev/null +++ b/gui/cachewaysselector.cc @@ -0,0 +1,58 @@ +// Simulator for the RISC-V[ECTOR] mini-ISA +// Copyright (C) 2025 Siddarth Suresh +// Copyright (C) 2025 bdunahu + +// 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 3 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, see <https://www.gnu.org/licenses/>. + +#include "cachewaysselector.h" +#include <QHBoxLayout> +#include <QLabel> +#include <QSpinBox> +#include <QVBoxLayout> + +CacheWaysSelector::CacheWaysSelector(QWidget *parent) : QWidget(parent) +{ + QVBoxLayout *v; + QHBoxLayout *l; + QSpinBox *sb; + QLabel *b; + int i; + + v = new QVBoxLayout(this); + + for (i = 1; i <= 6; ++i) { + l = new QHBoxLayout; + + b = new QLabel(QString("L%1 2^").arg(i), this); + + sb = new QSpinBox; + sb->setRange(-1, 4); + sb->setValue(-1); + + l->addWidget(b); + l->addWidget(sb); + + v->addLayout(l); + this->sbs.append(sb); + } +} + +QList<int> CacheWaysSelector::values() const +{ + QList<int> r; + for (const QSpinBox *sb : this->sbs) { + r.append(sb->value()); + } + return r; +} diff --git a/gui/dynamicwaysentry.h b/gui/cachewaysselector.h index 26b8b3e..4612b0c 100644 --- a/gui/dynamicwaysentry.h +++ b/gui/cachewaysselector.h @@ -15,37 +15,36 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. -#ifndef DYNAMICWAYSENTRY_H -#define DYNAMICWAYSENTRY_H +#ifndef CACHEWAYSSELECTOR_H +#define CACHEWAYSSELECTOR_H - -#include <QLineEdit> -#include <QStringList> -#include <QVBoxLayout> -#include <QVector> +#include <QSpinBox> #include <QWidget> -class DynamicWaysEntry : public QWidget +class CacheWaysSelector : public QWidget { + Q_OBJECT + public: - DynamicWaysEntry(QWidget *parent = nullptr); - QStringList get_entries() const; /** - * Parses a string from this entry field, if it is valid. - * @param a string - * @param -1 if the string is not suitable as a way, an integer compatible - * with the cache constructor otherwise. + * Constructor. + * This class provides a simple group of labeled spinboxs meant for + * selecting cache ways. + * @param The parent widget. + * @param a newly allocated CacheWaysSelector */ - int parse_valid_way(QString t); - private slots: - void on_number_enter(const QString &t); + explicit CacheWaysSelector(QWidget *parent = nullptr); + + /** + * @return the values in the spinboxes. + */ + QList<int> values() const; private: - QVBoxLayout *l; - QVector<QLineEdit *> fields; - QStringList entries; - void add_field(); - void remove_last_field(); + /** + * A list of spinboxes. + */ + QList<QSpinBox *> sbs; }; -#endif // DYNAMICWAYSENTRY_H +#endif // CACHEWAYSSELECTOR_H diff --git a/gui/digitlabeldelegate.cc b/gui/digitlabeldelegate.cc index 430946c..7a6a1d5 100644 --- a/gui/digitlabeldelegate.cc +++ b/gui/digitlabeldelegate.cc @@ -37,9 +37,13 @@ void DigitLabelDelegate::paint( QString t; QStyleOptionViewItem o; QStyle *s; + QVariant a; + bool e; - v = index.data(Qt::DisplayRole).toInt(); - t = format_toggled_value(v, this->is_hex); + a = index.data(Qt::DisplayRole); + v = a.toInt(); + e = a.isNull(); + t = format_toggled_value(v, this->is_hex, e); o = option; initStyleOption(&o, index); diff --git a/gui/dynamicwaysentry.cc b/gui/dynamicwaysentry.cc deleted file mode 100644 index cbd5342..0000000 --- a/gui/dynamicwaysentry.cc +++ /dev/null @@ -1,99 +0,0 @@ -// Simulator for the RISC-V[ECTOR] mini-ISA -// Copyright (C) 2025 Siddarth Suresh -// Copyright (C) 2025 bdunahu - -// 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 3 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, see <https://www.gnu.org/licenses/>. - -#include "dynamicwaysentry.h" -#include <QLabel> -#include <QLineEdit> -#include <QStringList> -#include <QVBoxLayout> -#include <QVector> -#include <QWidget> - -DynamicWaysEntry::DynamicWaysEntry(QWidget *parent) : QWidget(parent) -{ - this->l = new QVBoxLayout(this); - this->l->setAlignment(Qt::AlignTop); - this->l->setSpacing(6); - this->l->setContentsMargins(0, 0, 0, 0); - this->setLayout(l); - this->add_field(); -} - -QStringList DynamicWaysEntry::get_entries() const { return this->entries; } - -int DynamicWaysEntry::parse_valid_way(QString t) -{ - bool s; - int i; - i = t.toInt(&s); - return (s && i >= 0 && 5 > i) ? i : -1; -} - -// TODO if you enter something valid and then make it invalid, -// the next box still shows -void DynamicWaysEntry::on_number_enter(const QString &t) -{ - int i; - QLineEdit *sender_field; - - sender_field = qobject_cast<QLineEdit *>(sender()); - i = fields.indexOf(sender_field); - entries[i] = t; - - if (i == this->fields.size() - 1 && !t.isEmpty() && - (this->parse_valid_way(t) >= 0) && fields.size() < 4) - add_field(); - - // TODO, unlink, don't trash everything after - if (t.isEmpty()) { - while (this->fields.size() > i + 1) { - remove_last_field(); - } - while (entries.size() > fields.size()) { - entries.removeLast(); - } - } -} - -void DynamicWaysEntry::add_field() -{ - QLineEdit *f; - - f = new QLineEdit(this); - f->setPlaceholderText("# ways (a power of 2)"); - - this->l->addWidget(f);; - this->fields.append(f); - this->entries.append(QString()); - connect( - f, &QLineEdit::textChanged, this, &DynamicWaysEntry::on_number_enter); -} - -void DynamicWaysEntry::remove_last_field() -{ - QLineEdit *f; - - if (this->fields.isEmpty()) - return; - - f = this->fields.takeLast(); - this->l->removeWidget(f); - f->deleteLater(); - - if (!this->entries.isEmpty()) - entries.removeLast(); -} @@ -17,9 +17,10 @@ #include "gui.h" #include "./ui_gui.h" +#include "cachewaysselector.h" #include "digitlabeldelegate.h" -#include "dynamicwaysentry.h" #include "messages.h" +#include "registerview.h" #include "storageview.h" #include "util.h" #include <QHeaderView> @@ -72,6 +73,8 @@ GUI::GUI(QWidget *parent) : QMainWindow(parent), ui(new Ui::GUI) connect(worker, &Worker::wb_info, this, &GUI::onWorkerWriteBackInfo); + connect(worker, &Worker::steps_done, this, &GUI::onWorkerStepsDone); + // Display cache connect(worker, &Worker::storage, this, &GUI::onWorkerShowStorage); @@ -109,37 +112,10 @@ GUI::~GUI() delete ui; } -void displayArrayHTML(QTextEdit *textEdit, const std::array<int, GPR_NUM> &data) -{ - textEdit->setReadOnly(false); - QString tableText = "<table border='1' cellspacing='0' cellpadding='8' " - "style='border-collapse: collapse; width: 100%; " - "border: 2px solid black;'>"; - - tableText += "<tr>"; - int index = 0; - for (int value : data) { - tableText += QString("<td align='center' style='border: 2px solid " - "black; min-width: 60px; padding: 10px;'>" - "%1 <sup style='font-size: 10px; font-weight: " - "bold; color: black;'>%2</sup>" - "</td>") - .arg(QString::asprintf("%04X", value)) - .arg(index); - index++; - } - tableText += "</tr>"; - tableText += "</table>"; - - textEdit->setHtml(tableText); - textEdit->setReadOnly(true); -} - void GUI::on_worker_refresh_gui(int cycles, int pc) { ui->p_counter->set_value(pc); ui->cycle_counter->set_value(cycles); - this->set_status(get_waiting, "idle"); } void GUI::onWorkerFetchInfo(const InstrDTO *i) @@ -215,15 +191,20 @@ void GUI::onWorkerWriteBackInfo(const InstrDTO *i) } } +void GUI::onWorkerStepsDone() { this->set_status(get_waiting, "idle"); } + void GUI::onWorkerShowStorage(const QVector<QVector<int>> &data, int i) { this->tab_boxes.at(i)->set_data(data); } -void GUI::onWorkerShowRegisters(const std::array<int, GPR_NUM> &data) +void GUI::onWorkerShowRegisters( + const QVector<signed int> &gprs, const QVector<QVector<signed int>> &vrs) { - ; - // displayArrayHTML(this->tab_boxes.at(0), data); + RegisterView *rv; + + rv = dynamic_cast<RegisterView *>(this->tab_boxes.at(0)); + rv->set_data(gprs, vrs); } void GUI::on_upload_intructions_btn_clicked() @@ -301,21 +282,15 @@ void GUI::on_config_clicked() { std::vector<unsigned int> ways; QStringList entries; - signed int i; - DynamicWaysEntry *dwe = ui->cache_way_selector; + CacheWaysSelector *cws = ui->cache_ways_selector; - for (const QString &s : dwe->get_entries()) { + for (int i : cws->values()) { - if (s.isEmpty()) + // invalid + if (i == -1) continue; - i = dwe->parse_valid_way(s); - if (i >= 0) { - ways.push_back((unsigned int)i); - } else { - this->set_status(get_bad_cache, "angry"); - return; - } + ways.push_back((unsigned int)i); } if (this->p.empty()) { @@ -355,15 +330,15 @@ void GUI::make_tabs(int num) for (i = 0; i < num; ++i) { if (i == 0) { n = "Registers"; - e = new StorageView(0, this); + e = new RegisterView(GPR_NUM + V_NUM, V_R_LIMIT, this); } else if (i == num - 1) { n = "DRAM"; - e = new StorageView(MEM_LINES, this); + e = new StorageView(MEM_LINES, LINE_SIZE, this); } else { n = QString("L%1").arg(i); e = new StorageView( (1 << cache_size_mapper(this->curr_cache_levels - 1, i - 1)), - this); + LINE_SIZE, this); } t = new QTableView(ui->storage); @@ -68,9 +68,11 @@ class GUI : public QMainWindow void onWorkerWriteBackInfo(const InstrDTO *); + void onWorkerStepsDone(); + void onWorkerShowStorage(const QVector<QVector<int>> &data, int i); - void onWorkerShowRegisters(const std::array<int, GPR_NUM> &data); + void onWorkerShowRegisters(const QVector<signed int> &gprs, const QVector<QVector<signed int>> &vrs); void on_upload_intructions_btn_clicked(); @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>1499</width> + <width>1686</width> <height>621</height> </rect> </property> @@ -18,14 +18,17 @@ <item> <layout class="QGridLayout" name="gridLayout_2" rowstretch="0" columnstretch="0"> <item row="0" column="0"> - <layout class="QHBoxLayout" name="control_separator"> + <layout class="QHBoxLayout" name="control_separator" stretch="6,1"> + <property name="spacing"> + <number>6</number> + </property> <item> <layout class="QVBoxLayout" name="storage_pipe_separator"> <item> <widget class="QTabWidget" name="storage"> <property name="minimumSize"> <size> - <width>700</width> + <width>0</width> <height>0</height> </size> </property> @@ -35,7 +38,7 @@ </widget> </item> <item> - <layout class="QHBoxLayout" name="pipe_view"> + <layout class="QHBoxLayout" name="pipe_view" stretch="1,2,2,2,2,2"> <item> <widget class="QGroupBox" name="groupBox"> <property name="maximumSize"> @@ -45,7 +48,7 @@ </size> </property> <property name="title"> - <string> </string> + <string/> </property> <property name="alignment"> <set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set> @@ -93,7 +96,7 @@ <widget class="QGroupBox" name="Fetch"> <property name="minimumSize"> <size> - <width>200</width> + <width>0</width> <height>0</height> </size> </property> @@ -146,7 +149,7 @@ <widget class="QGroupBox" name="Decode"> <property name="minimumSize"> <size> - <width>200</width> + <width>0</width> <height>0</height> </size> </property> @@ -199,7 +202,7 @@ <widget class="QGroupBox" name="Execute"> <property name="minimumSize"> <size> - <width>200</width> + <width>0</width> <height>0</height> </size> </property> @@ -255,7 +258,7 @@ <widget class="QGroupBox" name="Memory"> <property name="minimumSize"> <size> - <width>200</width> + <width>0</width> <height>0</height> </size> </property> @@ -308,7 +311,7 @@ <widget class="QGroupBox" name="WriteBack"> <property name="minimumSize"> <size> - <width>200</width> + <width>0</width> <height>0</height> </size> </property> @@ -376,93 +379,14 @@ </widget> </item> <item> - <layout class="QHBoxLayout" name="cache_controls"> - <property name="sizeConstraint"> - <enum>QLayout::SizeConstraint::SetMinimumSize</enum> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Ways Selector (powers of 2)</string> </property> - <item> - <widget class="Line" name="line_8"> - <property name="orientation"> - <enum>Qt::Orientation::Vertical</enum> - </property> - </widget> - </item> - <item> - <layout class="QVBoxLayout" name="cache_way_text"> - <property name="sizeConstraint"> - <enum>QLayout::SizeConstraint::SetMinimumSize</enum> - </property> - <item> - <widget class="QLabel" name="label"> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>C1 2^</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_2"> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>C2 2^</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_3"> - <property name="minimumSize"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>C3 2^</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_4"> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>C4 2^</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="DynamicWaysEntry" name="cache_way_selector" native="true"> - <property name="minimumSize"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - </widget> - </item> - </layout> + </widget> + </item> + <item> + <widget class="CacheWaysSelector" name="cache_ways_selector" native="true"/> </item> <item> <widget class="QCheckBox" name="enable_pipeline_checkbox"> @@ -675,16 +599,16 @@ </widget> <customwidgets> <customwidget> - <class>DynamicWaysEntry</class> - <extends>QWidget</extends> - <header>dynamicwaysentry.h</header> - <container>1</container> - </customwidget> - <customwidget> <class>DigitLabel</class> <extends>QLabel</extends> <header location="global">digitlabel.h</header> </customwidget> + <customwidget> + <class>CacheWaysSelector</class> + <extends>QWidget</extends> + <header>cachewaysselector.h</header> + <container>1</container> + </customwidget> </customwidgets> <resources/> <connections/> diff --git a/gui/messages.h b/gui/messages.h index 461c461..0c38751 100644 --- a/gui/messages.h +++ b/gui/messages.h @@ -35,8 +35,6 @@ const std::vector<std::string> load_file = { const std::vector<std::string> no_instructions = { "NO PROGRAM PROVIDED", "NOTHING TO DO, GIVING UP", "INSTRUCTIONS MISSING", "404 INSTRUCTIONS NOT FOUND"}; -const std::vector<std::string> bad_cache = { - "WAYS CANNOT BE BELOW 0 OR ABOVE 4"}; const std::vector<std::string> no_pipeline = { "SIMULATION READY: NO PIPE", "PIPE OFF, SIMULATION READY"}; const std::vector<std::string> no_cache = { @@ -59,7 +57,6 @@ std::string get_load_file() { return RANDOM_MESSAGE(load_file); } * @return a friendly reminder that the simulation is not configured yet */ std::string get_no_instructions() { return RANDOM_MESSAGE(no_instructions); } -std::string get_bad_cache() { return RANDOM_MESSAGE(bad_cache); } /** * @return unsolicited complaints for successful initialization diff --git a/gui/registerview.cc b/gui/registerview.cc new file mode 100644 index 0000000..b1a1333 --- /dev/null +++ b/gui/registerview.cc @@ -0,0 +1,69 @@ +// Simulator for the RISC-V[ECTOR] mini-ISA +// Copyright (C) 2025 Siddarth Suresh +// Copyright (C) 2025 bdunahu + +// 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 3 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, see <https://www.gnu.org/licenses/>. + +#include "pipe_spec.h" +#include "registerview.h" +#include "util.h" +#include <QAbstractTableModel> +#include <QVector> + +QVariant RegisterView::data(const QModelIndex &i, int role) const +{ + Qt::Alignment a; + + if (role == Qt::TextAlignmentRole) { + a = Qt::AlignRight | Qt::AlignVCenter; + return QVariant(static_cast<int>(a)); + } + + if (!i.isValid() || role != Qt::DisplayRole) + return QVariant(); + + if (i.row() < 16) { + if (i.column() < 1) + return this->gprs[i.row()]; + else + return QVariant(); + } + + return this->vrs[i.row() - GPR_NUM][i.column() - GPR_NUM]; +} + +QVariant +RegisterView::headerData(int section, Qt::Orientation o, int role) const +{ + Qt::Alignment a; + + if (role == Qt::TextAlignmentRole) { + a = Qt::AlignRight | Qt::AlignVCenter; + return QVariant(static_cast<int>(a)); + } + + if (role != Qt::DisplayRole) + return QVariant(); + + if (o == Qt::Vertical) { + return format_toggled_value(section, this->is_hex); + } + return QVariant(); +} + +void RegisterView::set_data(const QVector<int> &gprs, const QVector<QVector<int>> &vrs) +{ + this->gprs = gprs; + this->vrs = vrs; +} diff --git a/gui/registerview.h b/gui/registerview.h new file mode 100644 index 0000000..cc5a1f8 --- /dev/null +++ b/gui/registerview.h @@ -0,0 +1,64 @@ +// Simulator for the RISC-V[ECTOR] mini-ISA +// Copyright (C) 2025 Siddarth Suresh +// Copyright (C) 2025 bdunahu + +// 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 3 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, see <https://www.gnu.org/licenses/>. + +#ifndef REGISTERVIEW_H +#define REGISTERVIEW_H + +#include "storageview.h" +#include <QAbstractTableModel> +#include <QVector> + +// see https://doc.qt.io/qt-6/qabstracttablemodel.html +class RegisterView : public StorageView +{ + Q_OBJECT + public: + using StorageView::StorageView; + + /** + * Returns a properly formatted cell, including alignment.This function is + * specific to the implementation details of QAbstractTableModel. + */ + QVariant + data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + /** + * Adds custom formatting options for row and column headers. + */ + QVariant headerData( + int section, + Qt::Orientation o, + int role = Qt::DisplayRole) const override; + + /** + * @param field to assign to `this->gprs'. + * @param field to assign to `this->vrs'. + */ + void set_data(const QVector<int> &gprs, const QVector<QVector<int>> &vrs); + + private: + /** + * The general purpose registers. + */ + QVector<int> gprs; + /** + * The vector registers. + */ + QVector<QVector<int>> vrs; +}; + +#endif // REGISTERVIEW_H diff --git a/gui/resources.qrc b/gui/resources.qrc index 569cc22..66cd6e4 100644 --- a/gui/resources.qrc +++ b/gui/resources.qrc @@ -1,6 +1,10 @@ <!DOCTYPE RCC> <RCC version="1.0"> <qresource> + <file>resources/arrow_down.png</file> + <file>resources/arrow_up.png</file> + <file>resources/arrow_down_pressed.png</file> + <file>resources/arrow_up_pressed.png</file> <file>resources/styles.qss</file> <file>resources/idle.png</file> <file>resources/angry.png</file> diff --git a/gui/resources/arrow_down.png b/gui/resources/arrow_down.png Binary files differnew file mode 100644 index 0000000..80b1753 --- /dev/null +++ b/gui/resources/arrow_down.png diff --git a/gui/resources/arrow_down_pressed.png b/gui/resources/arrow_down_pressed.png Binary files differnew file mode 100644 index 0000000..0981cf2 --- /dev/null +++ b/gui/resources/arrow_down_pressed.png diff --git a/gui/resources/arrow_up.png b/gui/resources/arrow_up.png Binary files differnew file mode 100644 index 0000000..69b65af --- /dev/null +++ b/gui/resources/arrow_up.png diff --git a/gui/resources/arrow_up_pressed.png b/gui/resources/arrow_up_pressed.png Binary files differnew file mode 100644 index 0000000..98d50ac --- /dev/null +++ b/gui/resources/arrow_up_pressed.png diff --git a/gui/resources/styles.qss b/gui/resources/styles.qss index a61035e..c6d8daa 100644 --- a/gui/resources/styles.qss +++ b/gui/resources/styles.qss @@ -4,6 +4,8 @@ color: "#00cc00"; background-color: "#000200"; border: 0px solid "#000200"; + selection-background-color: "#00cc00"; + selection-color: "#000200"; } QStatusBar { @@ -50,6 +52,66 @@ QGroupBox::title { QLabel { } +QSpinBox { + padding-right: 15px; /* make room for the arrows */ + border: none; +} + +QSpinBox::up-button { + color: "#000200"; + background-color: "#00cc00"; + subcontrol-origin: border; + subcontrol-position: top right; /* position at the top right corner */ + + width: 16px; + border: none; + subcontrol-origin: border; +} + +QSpinBox::up-arrow { + image: url(:/resources/arrow_up.png); + width: 7px; + height: 7px; +} + +QSpinBox::up-arrow:pressed { + image: url(:/resources/arrow_up_pressed.png); + width: 7px; + height: 7px; +} + +QSpinBox::up-button:pressed { + color: "#00cc00"; + background-color: "#000200"; +} + +QSpinBox::down-button { + color: "#000200"; + background-color: "#00cc00"; + subcontrol-origin: border; + subcontrol-position: bottom right; /* position at bottom right corner */ + + width: 16px; + border: none; +} + +QSpinBox::down-button:pressed { + color: "#00cc00"; + background-color: "#000200"; +} + +QSpinBox::down-arrow { + image: url(:/resources/arrow_down.png); + width: 7px; + height: 7px; +} + +QSpinBox::down-arrow:pressed { + image: url(:/resources/arrow_down_pressed.png); + width: 7px; + height: 7px; +} + QTableView { border: 0px; selection-background-color: transparent; diff --git a/gui/storageview.cc b/gui/storageview.cc index 2f444a9..60391f9 100644 --- a/gui/storageview.cc +++ b/gui/storageview.cc @@ -21,10 +21,11 @@ #include <QAbstractTableModel> #include <QVector> -StorageView::StorageView(int rows, QObject *parent) +StorageView::StorageView(int rows, int columns, QObject *parent) : QAbstractTableModel(parent) { this->r = rows; + this->c = columns; this->d.resize(rows); for (auto &row : this->d) row.resize(LINE_SIZE, 0); @@ -32,7 +33,7 @@ StorageView::StorageView(int rows, QObject *parent) int StorageView::rowCount(const QModelIndex &) const { return this->r; } -int StorageView::columnCount(const QModelIndex &) const { return LINE_SIZE; } +int StorageView::columnCount(const QModelIndex &) const { return this->c; } QVariant StorageView::data(const QModelIndex &i, int role) const { diff --git a/gui/storageview.h b/gui/storageview.h index 0518d8f..a0f8dbb 100644 --- a/gui/storageview.h +++ b/gui/storageview.h @@ -31,7 +31,7 @@ class StorageView : public QAbstractTableModel * `rows' rows. * @param the number of rows */ - StorageView(int rows, QObject *parent = nullptr); + StorageView(int rows, int columns, QObject *parent = nullptr); /** * Returns the number of rows in this table. @@ -51,13 +51,13 @@ class StorageView : public QAbstractTableModel * Returns a properly formatted cell, including alignment.This function is * specific to the implementation details of QAbstractTableModel. */ - QVariant + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; /** * Adds custom formatting options for row and column headers. */ - QVariant headerData( + virtual QVariant headerData( int section, Qt::Orientation o, int role = Qt::DisplayRole) const override; @@ -75,15 +75,21 @@ class StorageView : public QAbstractTableModel public slots: void set_hex_display(bool hex); - private: + protected: /** * The number of rows in this table. */ int r; /** + * The number of columns in this table. + */ + int c; + /** * Whether or not the headers should be displayed in hex. */ bool is_hex = true; + + private: /** * The data this table displays. */ diff --git a/gui/worker.cc b/gui/worker.cc index 0ba364b..a48888c 100644 --- a/gui/worker.cc +++ b/gui/worker.cc @@ -72,14 +72,22 @@ void Worker::runSteps(int steps) { this->ct->run_for(steps); this->update(); + emit steps_done(); } void Worker::update() { unsigned long i; + std::array<int, GPR_NUM> gprs; + std::array<std::array<signed int, V_R_LIMIT>, V_NUM> vrs; this->ct_mutex.lock(); - emit register_storage(this->ct->get_gprs()); + gprs = this->ct->get_gprs(); + vrs = this->ct->get_vrs(); + std::vector<std::array<signed int, V_R_LIMIT>> v(vrs.begin(), vrs.end()); + + emit register_storage( + QVector<int>(gprs.begin(), gprs.end()), this->data_to_QT(v)); for (i = 0; i < s.size(); ++i) emit storage(this->data_to_QT(this->s.at(i)->get_data()), i + 1); @@ -92,18 +100,3 @@ void Worker::update() emit wb_info(this->wb_stage->get_instr()); this->ct_mutex.unlock(); } - -QVector<QVector<int>> -Worker::data_to_QT(std::vector<std::array<signed int, LINE_SIZE>> data) -{ - QVector<QVector<int>> r; - QVector<int> tmp; - - r.reserve(static_cast<int>(data.size())); - - for (const auto &line : data) { - tmp = QVector<int>(line.begin(), line.end()); - r.append(tmp); - } - return r; -} diff --git a/gui/worker.h b/gui/worker.h index c62f4ed..2a362a4 100644 --- a/gui/worker.h +++ b/gui/worker.h @@ -64,14 +64,15 @@ class Worker : public QObject signals: void clock_cycles(int value, int pc); - void - storage(QVector<QVector<int>> data, int i); - void register_storage(const std::array<int, GPR_NUM> data); + void storage(QVector<QVector<int>> data, int i); + void register_storage( + QVector<signed int> gprs, QVector<QVector<signed int>> vrs); void if_info(const InstrDTO *); void id_info(const InstrDTO *); void ex_info(const InstrDTO *); void mm_info(const InstrDTO *); void wb_info(const InstrDTO *); + void steps_done(); void finished(); private: @@ -80,8 +81,21 @@ class Worker : public QObject * @param the original data * @return a less universal version of the same thing */ + template <size_t N> QVector<QVector<int>> - data_to_QT(std::vector<std::array<signed int, LINE_SIZE>> data); + data_to_QT(const std::vector<std::array<signed int, N>> &data) + { + QVector<QVector<int>> r; + QVector<int> tmp; + + r.reserve(static_cast<int>(data.size())); + + for (const auto &line : data) { + tmp = QVector<int>(line.begin(), line.end()); + r.append(tmp); + } + return r; + } /** * Sets the GUI signals to update the storage, clock cycle, and stage * displays. diff --git a/inc/controller.h b/inc/controller.h index b7fa835..cd59fc8 100644 --- a/inc/controller.h +++ b/inc/controller.h @@ -49,7 +49,11 @@ class Controller : public Stage /** * @return a copy of gprs. */ - std::array<int, GPR_NUM> get_gprs(); + std::array<signed int, GPR_NUM> get_gprs(); + /** + * @return a copy of vrs. + */ + std::array<std::array<signed int, V_R_LIMIT>, V_NUM> get_vrs(); /** * @return the pc. */ @@ -63,7 +63,7 @@ class EX : public Stage * @param The next stage in the pipeline. * @return A newly allocated EX object. */ - EX(Stage *next); + using Stage::Stage; using Stage::advance; private: @@ -76,16 +76,6 @@ class EX : public Stage * @param if the modulo operator should instead be used */ void handle_divide(signed int &s1, signed int s2, bool is_mod); - /** - * Maps each mnemonic to a function which carries out the instruction's base - * logic. - * All instructions store the result into s1. - */ - std::unordered_map< - Mnemonic, - std::function<void( - signed int &s1, signed int s2, signed int s3, unsigned int pc)>> - instr_map; }; #endif /* EX_H_INCLUDED */ @@ -50,6 +50,12 @@ class ID : public Stage */ void write_guard(signed int &r); + Response read_vec_guard(signed int r, std::array<signed int, V_R_LIMIT> &v); + + void write_vec_guard(signed int r, std::array<signed int, V_R_LIMIT> &v); + + Response set_vlen(); + private: /** * Helper for `get_instr_fields` @@ -76,10 +82,10 @@ class ID : public Stage * @param the resulting third field, which varies per type. * @param the resulting mnemonic. */ - void get_instr_fields(signed int &s1, signed int &s2, signed int &s3, Mnemonic &m); - void decode_R_type(signed int &s1, signed int &s2, signed int &s3, Mnemonic &m); - void decode_I_type(signed int &s1, signed int &s2, signed int &s3, Mnemonic &m); - void decode_J_type(signed int &s1, signed int &s2, signed int &s3, Mnemonic &m); + void get_instr_fields(signed int &s1); + void decode_R_type(signed int &s1); + void decode_I_type(signed int &s1); + void decode_J_type(signed int &s1); /** * Helper for `get_instr_fields`. * Given a raw instruction, returns the mnemonic and type. diff --git a/inc/instrDTO.h b/inc/instrDTO.h index 1402526..f3d4597 100644 --- a/inc/instrDTO.h +++ b/inc/instrDTO.h @@ -18,6 +18,8 @@ #ifndef INSTRDTO_H #define INSTRDTO_H #include "instr.h" +#include "pipe_spec.h" +#include<array> struct U_INT_TYPE { signed int slot_one; @@ -26,6 +28,15 @@ struct U_INT_TYPE { }; struct V_TYPE { + std::array<signed int, V_R_LIMIT> slot_one; + std::array<signed int, V_R_LIMIT> slot_two; + std::array<signed int, V_R_LIMIT> slot_three; +}; + +struct LOAD_STORE_V_TYPE{ + signed int base_addr; + signed int immediate; + std::array<signed int, V_R_LIMIT> vector_register; }; struct InstrDTO { @@ -52,6 +63,7 @@ struct InstrDTO { union { struct U_INT_TYPE integer; struct V_TYPE vector; + struct LOAD_STORE_V_TYPE load_store_vector; } operands; }; diff --git a/inc/pipe_spec.h b/inc/pipe_spec.h index 7d65637..d8153af 100644 --- a/inc/pipe_spec.h +++ b/inc/pipe_spec.h @@ -80,6 +80,8 @@ */ #define CACHE_DELAY 1 +#define VECTOR_MEM_DELAY 10 + /** * Return the N least-significant bits from integer K using a bit mask * @param the integer to be parsed diff --git a/inc/stage.h b/inc/stage.h index 16f1235..4e0c252 100644 --- a/inc/stage.h +++ b/inc/stage.h @@ -83,6 +83,10 @@ class Stage */ static std::deque<signed int> checked_out; + bool is_vector_type(Mnemonic m); + + bool is_logical(Mnemonic m); + protected: /** * The function expected to do the majority of the work. @@ -104,13 +108,43 @@ class Stage * @param the register number. * @param the value to store. */ - void store_register(signed int v, signed int d); + template <typename T> + void store_register(signed int v, T d) + { + if constexpr (std::is_same_v<T, signed int>) { + if (v < 0 || v >= GPR_NUM) { + throw std::out_of_range("Invalid GPR index for storing scalar"); + } + gprs[v] = d; + } + else if constexpr (std::is_same_v<T, std::array<signed int, V_R_LIMIT>>) { + if (v < GPR_NUM || v >= GPR_NUM + V_NUM) { + throw std::out_of_range("Invalid VR index for storing vector"); + } + vrs[v % GPR_NUM] = d; + } + } /** * Returns the value of the register corresponding to `v`. * @param the register number. * @return the value in the associated register. */ - signed int dereference_register(signed int v); + template <typename T> + T dereference_register(signed int v) + { + if constexpr (std::is_same_v<T, signed int>) { + if (v < 0 || v >= GPR_NUM) { + throw std::out_of_range("Invalid GPR index"); + } + return gprs[v]; + } + else if constexpr (std::is_same_v<T, std::array<signed int, V_R_LIMIT>>) { + if (v < GPR_NUM || v >= GPR_NUM + V_NUM) { + throw std::out_of_range("Invalid vector register index"); + } + return vrs[v % GPR_NUM]; + } + } /** * The shared pool of general-purpose integer registers. */ @@ -118,7 +152,7 @@ class Stage /** * The shared pool of general-purpose vector registers. */ - static std::array<signed int, V_NUM> vrs; + static std::array<std::array<signed int, V_R_LIMIT>, V_NUM> vrs; /** * The address of the currently executing instruction. */ diff --git a/src/controller.cc b/src/controller.cc index 8df4b97..a5c6691 100644 --- a/src/controller.cc +++ b/src/controller.cc @@ -15,6 +15,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. +#include "definitions.h" #include "controller.h" #include "ex.h" #include "response.h" @@ -30,6 +31,7 @@ Controller::Controller(Stage *stage, Storage *storage, bool is_pipelined) this->pc = 0x0; this->checked_out = {}; this->gprs = {0}; + this->vrs.fill({0}); this->gprs.at(2) = MEM_WORDS; // set the stack pointer } @@ -47,7 +49,12 @@ void Controller::run_for(int number) int Controller::get_clock_cycle() { return this->clock_cycle; } -std::array<int, GPR_NUM> Controller::get_gprs() { return this->gprs; } +std::array<signed int, GPR_NUM> Controller::get_gprs() { return this->gprs; } + +std::array<std::array<signed int, V_R_LIMIT>, V_NUM> Controller::get_vrs() +{ + return this->vrs; +} int Controller::get_pc() { return this->pc; } @@ -22,415 +22,230 @@ #include "stage.h" #include <unordered_map> -// clang-format off -#define INIT_INSTRUCTION(mnemonic, body) \ - {mnemonic, [this](signed int &s1, signed int s2, signed int s3, unsigned int pc) { \ - body; \ - }} -// clang-format on - -EX::EX(Stage *stage) : Stage(stage) -{ - instr_map = { - - /* R type instructions */ - INIT_INSTRUCTION( - ADD, - { - this->set_condition(OF, ADDITION_OF_GUARD(s1, s2)); - this->set_condition(UF, ADDITION_UF_GUARD(s1, s2)); - s1 = s1 + s2; - (void)pc; - (void)s3; - (void)this; - }), - - INIT_INSTRUCTION( - SUB, - { - this->set_condition(OF, SUBTRACTION_OF_GUARD(s1, s2)); - this->set_condition(UF, SUBTRACTION_UF_GUARD(s1, s2)); - s1 = s1 - s2; - (void)pc; - (void)s3; - (void)this; - }), - - INIT_INSTRUCTION( - MUL, - { - this->set_condition(OF, MULTIPLICATION_OF_GUARD(s1, s2)); - this->set_condition(UF, MULTIPLICATION_UF_GUARD(s1, s2)); - s1 = s1 * s2; - (void)pc; - (void)s3; - (void)this; - }), - - INIT_INSTRUCTION( - QUOT, - { - this->handle_divide(s1, s2, false); - (void)pc; - (void)s3; - }), - - INIT_INSTRUCTION( - REM, - { - this->handle_divide(s1, s2, true); - (void)pc; - (void)s3; - (void)this; - }), - - INIT_INSTRUCTION( - SFTR, - { - s1 = s1 >> s2; - (void)pc; - (void)s3; - (void)this; - }), - - INIT_INSTRUCTION( - SFTL, - { - s1 = s1 << s2; - (void)pc; - (void)s3; - (void)this; - }), - - INIT_INSTRUCTION( - AND, - { - this->set_condition(OF, false); - this->set_condition(UF, false); - s1 = s1 & s2; - (void)pc; - (void)s3; - (void)this; - }), - - INIT_INSTRUCTION( - OR, - { - this->set_condition(OF, false); - this->set_condition(UF, false); - s1 = s1 | s2; - (void)pc; - (void)s3; - (void)this; - }), - - INIT_INSTRUCTION( - NOT, - { - this->set_condition(OF, false); - this->set_condition(UF, false); - s1 = ~s1; - (void)pc; - (void)s3; - (void)s2; - (void)this; - }), - - INIT_INSTRUCTION( - XOR, - { - this->set_condition(OF, false); - this->set_condition(UF, false); - s1 = s1 ^ s2; - (void)pc; - (void)s3; - (void)this; - }), - - INIT_INSTRUCTION( - ADDV, - { - (void)pc; - (void)s3; - (void)s2; - (void)s1; - (void)this; - }), - - INIT_INSTRUCTION( - SUBV, - { - (void)pc; - (void)s3; - (void)s2; - (void)s1; - (void)this; - }), - - INIT_INSTRUCTION( - MULV, - { - (void)pc; - (void)s3; - (void)s2; - (void)s1; - (void)this; - }), - - INIT_INSTRUCTION( - DIVV, - { - (void)pc; - (void)s3; - (void)s2; - (void)s1; - (void)this; - }), - - INIT_INSTRUCTION( - CMP, - { - (s1 > s2) ? this->set_condition(GT, true) - : this->set_condition(GT, false); - (s1 == s2) ? this->set_condition(EQ, true) - : this->set_condition(EQ, false); - (void)pc; - (void)s3; - }), - - INIT_INSTRUCTION( - CEV, - { - (void)pc; - (void)s3; - (void)s2; - (void)s1; - (void)this; - }), - - /* I type instructions */ - INIT_INSTRUCTION( - LOAD, - { - s1 = s1 + s3; - (void)pc; - (void)s2; - (void)this; - }), - - INIT_INSTRUCTION( - LOADV, - { - (void)pc; - (void)s3; - (void)s2; - (void)s1; - (void)this; - }), - - INIT_INSTRUCTION( - ADDI, - { - this->set_condition(OF, ADDITION_OF_GUARD(s1, s3)); - this->set_condition(UF, ADDITION_UF_GUARD(s1, s3)); - s1 = s1 + s3; - (void)pc; - (void)s2; - (void)this; - }), - - INIT_INSTRUCTION( - SUBI, - { - this->set_condition(OF, SUBTRACTION_OF_GUARD(s1, s3)); - this->set_condition(UF, SUBTRACTION_UF_GUARD(s1, s3)); - s1 = s1 - s3; - (void)pc; - (void)s2; - (void)this; - }), - - INIT_INSTRUCTION( - SFTRI, - { - s1 = s1 >> s3; - (void)pc; - (void)s2; - (void)this; - }), - - INIT_INSTRUCTION( - SFTLI, - { - s1 = s1 << s3; - (void)pc; - (void)s2; - (void)this; - }), - - INIT_INSTRUCTION( - ANDI, - { - this->set_condition(OF, false); - this->set_condition(UF, false); - s1 = s1 & s3; - (void)pc; - (void)s2; - (void)this; - }), - - INIT_INSTRUCTION( - ORI, - { - this->set_condition(OF, false); - this->set_condition(UF, false); - s1 = s1 | s3; - (void)pc; - (void)s2; - (void)this; - }), - - INIT_INSTRUCTION( - XORI, - { - this->set_condition(OF, false); - this->set_condition(UF, false); - s1 = s1 ^ s3; - (void)pc; - (void)s2; - (void)this; - }), - - INIT_INSTRUCTION( - STORE, - { - s1 = s1 + s3; - (void)pc; - (void)s2; - (void)this; - }), - - INIT_INSTRUCTION( - STOREV, - { - (void)pc; - (void)s3; - (void)s2; - (void)s1; - (void)this; - }), - - /* J type instructions */ - INIT_INSTRUCTION( - JMP, - { - s1 = s1 + s2; - (void)pc; - (void)s3; - (void)this; - }), - - INIT_INSTRUCTION( - JRL, - { - s1 = pc + s2; - (void)s3; - (void)this; - }), - - INIT_INSTRUCTION( - JAL, - { - s1 = s1 + s2; - (void)pc; - (void)s3; - (void)this; - }), - - INIT_INSTRUCTION( - BEQ, - { - (this->get_condition(EQ)) ? s1 = pc + s2 : s1 = -1; - (void)s3; - }), - - INIT_INSTRUCTION( - BGT, - { - (this->get_condition(GT)) ? s1 = pc + s2 : s1 = -1; - (void)s3; - }), - - INIT_INSTRUCTION( - BUF, - { - (this->get_condition(UF)) ? s1 = pc + s2 : s1 = -1; - (void)s3; - }), - - INIT_INSTRUCTION( - BOF, - { - (this->get_condition(OF)) ? s1 = pc + s2 : s1 = -1; - (void)s3; - }), - - INIT_INSTRUCTION( - PUSH, - { - s1 = s1 + s3; - (void)pc; - (void)s2; - (void)this; - }), - - INIT_INSTRUCTION( - POP, - { - s1 = s1 + s3; - (void)pc; - (void)s2; - (void)this; - }), - - INIT_INSTRUCTION( - RET, - { - (void)pc; - (void)s3; - (void)s2; - (void)s1; - (void)this; - }), - - /* NOP */ - INIT_INSTRUCTION( - NOP, - { - (void)pc; - (void)s3; - (void)s2; - (void)s1; - (void)this; - }), - }; -} - +// Switch statements for each instruction void EX::advance_helper() { signed int s1, s2, s3; + std::array<signed int, V_R_LIMIT> v1, v2, v3; + signed int v_len, v_immediate, v_base_addr; unsigned int pc; Mnemonic m; + s1 = 0, s2 = 0, s3 = 0; + v1 = {0}, v2 = {0}, v3 = {0}; + v_len = 0, v_immediate = 0, v_base_addr = 0; m = this->curr_instr->mnemonic; - s1 = this->curr_instr->operands.integer.slot_one; - s2 = this->curr_instr->operands.integer.slot_two; - s3 = this->curr_instr->operands.integer.slot_three; pc = this->curr_instr->slot_B; - this->instr_map[m](s1, s2, s3, pc); + if (this->is_vector_type(m)) { + if (this->curr_instr->mnemonic != LOADV && + this->curr_instr->mnemonic != STOREV) { + v1 = this->curr_instr->operands.vector.slot_one; + v2 = this->curr_instr->operands.vector.slot_two; + v3 = this->curr_instr->operands.vector.slot_three; + } else { + v_immediate = + this->curr_instr->operands.load_store_vector.immediate; + v_base_addr = + this->curr_instr->operands.load_store_vector.base_addr; + } + v_len = this->curr_instr->slot_A; + if (v_len == 0) { + // clear destination vector reg + v1.fill(0); + } + } else { + s1 = this->curr_instr->operands.integer.slot_one; + s2 = this->curr_instr->operands.integer.slot_two; + s3 = this->curr_instr->operands.integer.slot_three; + } + + if (this->is_logical(m)) { + this->set_condition(OF, false); + this->set_condition(UF, false); + } - this->curr_instr->operands.integer.slot_one = s1; + switch (m) { + case ADD: + this->set_condition(OF, ADDITION_OF_GUARD(s1, s2)); + this->set_condition(UF, ADDITION_UF_GUARD(s1, s2)); + s1 = s1 + s2; + break; + + case SUB: + this->set_condition(OF, SUBTRACTION_OF_GUARD(s1, s2)); + this->set_condition(UF, SUBTRACTION_UF_GUARD(s1, s2)); + s1 = s1 - s2; + break; + + case MUL: + this->set_condition(OF, MULTIPLICATION_OF_GUARD(s1, s2)); + this->set_condition(UF, MULTIPLICATION_UF_GUARD(s1, s2)); + s1 = s1 * s2; + break; + + case QUOT: + this->handle_divide(s1, s2, false); + break; + + case REM: + this->handle_divide(s1, s2, true); + break; + + case SFTR: + s1 = s1 >> s2; + break; + + case SFTL: + s1 = s1 << s2; + break; + + case AND: + s1 = s1 & s2; + break; + + case OR: + s1 = s1 | s2; + break; + + case XOR: + s1 = s1 ^ s2; + break; + + case NOT: + s1 = ~s1; + break; + + case CMP: + (s1 > s2) ? this->set_condition(GT, true) + : this->set_condition(GT, false); + (s1 == s2) ? this->set_condition(EQ, true) + : this->set_condition(EQ, false); + break; + + case ADDI: + this->set_condition(OF, ADDITION_OF_GUARD(s1, s3)); + this->set_condition(UF, ADDITION_UF_GUARD(s1, s3)); + s1 = s1 + s3; + break; + + case SUBI: + this->set_condition(OF, SUBTRACTION_OF_GUARD(s1, s3)); + this->set_condition(UF, SUBTRACTION_UF_GUARD(s1, s3)); + s1 = s1 - s3; + break; + + case SFTRI: + s1 = s1 >> s3; + break; + + case SFTLI: + s1 = s1 << s3; + break; + + case ANDI: + s1 = s1 & s3; + break; + + case ORI: + s1 = s1 | s3; + break; + + case XORI: + s1 = s1 ^ s3; + break; + + case LOAD: + case STORE: + case PUSH: + case POP: + s1 = s1 + s3; + break; + + case JMP: + case JAL: + s1 = s1 + s2; + break; + + case JRL: + s1 = pc + s2; + break; + + case BEQ: + (this->get_condition(EQ)) ? s1 = pc + s2 : s1 = -1; + break; + + case BGT: + (this->get_condition(GT)) ? s1 = pc + s2 : s1 = -1; + break; + + case BUF: + (this->get_condition(UF)) ? s1 = pc + s2 : s1 = -1; + break; + + case BOF: + (this->get_condition(OF)) ? s1 = pc + s2 : s1 = -1; + break; + + case ADDV: + for (int i = 0; i < v_len; i++) { + this->set_condition(OF, ADDITION_OF_GUARD(v1[i], v2[i])); + this->set_condition(UF, ADDITION_UF_GUARD(v1[i], v2[i])); + v1[i] = v1[i] + v2[i]; + } + break; + case SUBV: + for (int i = 0; i < v_len; i++) { + this->set_condition(OF, SUBTRACTION_OF_GUARD(v1[i], v2[i])); + this->set_condition(UF, SUBTRACTION_UF_GUARD(v1[i], v2[i])); + v1[i] = v1[i] - v2[i]; + } + break; + case MULV: + for (int i = 0; i < v_len; i++) { + this->set_condition(OF, MULTIPLICATION_OF_GUARD(v1[i], v2[i])); + this->set_condition(UF, MULTIPLICATION_UF_GUARD(v1[i], v2[i])); + v1[i] = v1[i] * v2[i]; + } + break; + case DIVV: + for (int i = 0; i < v_len; i++) { + this->handle_divide(v1[i], v2[i], false); + } + break; + case CEV: + int i; + for (i = 0; i < v_len; i++) { + if (v1[i] != v2[i]) { + break; + } + } + if (i == v_len) { + this->set_condition(EQ, true); + } else { + this->set_condition(EQ, false); + } + break; + case LOADV: + case STOREV: + v_base_addr = v_base_addr + v_immediate; + break; + + case RET: + case NOP: + break; + } + if (this->is_vector_type(m)) { + if (this->curr_instr->mnemonic != LOADV && + this->curr_instr->mnemonic != STOREV) { + this->curr_instr->operands.vector.slot_one = v1; + } else { + this->curr_instr->operands.load_store_vector.base_addr = + v_base_addr; + } + } else { + this->curr_instr->operands.integer.slot_one = s1; + } this->status = OK; } @@ -22,30 +22,27 @@ #include "response.h" #include "stage.h" -void ID::split_instr(signed int &raw, unsigned int &type, Mnemonic &m) +Response ID::read_guard(signed int &v) { - unsigned int opcode, opcode_size; - - type = GET_LS_BITS(raw, TYPE_SIZE); - opcode_size = (type == 0b0) ? R_OPCODE_SIZE : OPCODE_SIZE; - opcode = GET_MID_BITS(raw, TYPE_SIZE, TYPE_SIZE + opcode_size); - try { - m = instr::mnemonic_map.at((opcode << TYPE_SIZE) + type); - } catch (std::out_of_range const &) { - m = NOP; + Response r; + if (this->is_checked_out(v)) + r = STALLED; + else { + r = OK; + v = this->dereference_register<signed int>(v); } - - raw = (unsigned int)raw >> (TYPE_SIZE + opcode_size); + return r; } -Response ID::read_guard(signed int &v) +Response +ID::read_vec_guard(signed int v, std::array<signed int, V_R_LIMIT> &vrs) { Response r; if (this->is_checked_out(v)) r = STALLED; else { r = OK; - v = this->dereference_register(v); + vrs = this->dereference_register<std::array<signed int, V_R_LIMIT>>(v); } return r; } @@ -59,55 +56,95 @@ void ID::write_guard(signed int &v) this->checked_out.push_back(v); this->curr_instr->checked_out = v; } - v = this->dereference_register(v); + v = this->dereference_register<signed int>(v); +} + +void ID::write_vec_guard(signed int v, std::array<signed int, V_R_LIMIT> &vrs) +{ + + // zero register shouldn't be written. + if (v != 0) { + // keep track in the instrDTO for displaying to user and writeback + // keep track in checked_out so we can still access this information! + this->checked_out.push_back(v); + this->curr_instr->checked_out = v; + } + vrs = this->dereference_register<std::array<signed int, V_R_LIMIT>>(v); } void ID::advance_helper() { - signed int s1, s2, s3; - Mnemonic m; + signed int s1; - if (curr_instr->mnemonic == NOP) + if (this->curr_instr->mnemonic == NOP) this->status = OK; else { - s1 = curr_instr->slot_A; - get_instr_fields(s1, s2, s3, m); - if (this->status == OK) { - curr_instr->operands.integer.slot_one = s1; - curr_instr->operands.integer.slot_two = s2; - curr_instr->operands.integer.slot_three = s3; - curr_instr->mnemonic = m; - } + // instuction in bits in s1 + s1 = this->curr_instr->slot_A; + get_instr_fields(s1); } } -void ID::get_instr_fields( - signed int &s1, signed int &s2, signed int &s3, Mnemonic &m) +void ID::get_instr_fields(signed int &s1) { unsigned int type; + Mnemonic m; this->split_instr(s1, type, m); - + this->curr_instr->mnemonic = m; switch (type) { case 0b00: - this->decode_R_type(s1, s2, s3, m); + this->decode_R_type(s1); break; case 0b01: - this->decode_I_type(s1, s2, s3, m); + this->decode_I_type(s1); break; case 0b10: - this->decode_J_type(s1, s2, s3, m); + this->decode_J_type(s1); break; case 0b11: - m = NOP; + // not defined, m = NOP this->status = OK; } } -void ID::decode_R_type( - signed int &s1, signed int &s2, signed int &s3, Mnemonic &m) +void ID::split_instr(signed int &raw, unsigned int &type, Mnemonic &m) +{ + unsigned int opcode, opcode_size; + + type = GET_LS_BITS(raw, TYPE_SIZE); + opcode_size = (type == 0b0) ? R_OPCODE_SIZE : OPCODE_SIZE; + opcode = GET_MID_BITS(raw, TYPE_SIZE, TYPE_SIZE + opcode_size); + try { + m = instr::mnemonic_map.at((opcode << TYPE_SIZE) + type); + } catch (std::out_of_range const &) { + m = NOP; + } + + raw = (unsigned int)raw >> (TYPE_SIZE + opcode_size); +} + +Response ID::set_vlen() +{ + signed int vlen_reg = 4; + Response r; + r = this->read_guard(vlen_reg); + vlen_reg = vlen_reg & 0xf; + if (r == OK) { + if (vlen_reg > V_R_LIMIT) { + this->curr_instr->slot_A = V_R_LIMIT; + } else { + this->curr_instr->slot_A = vlen_reg; + } + } + return r; +} + +void ID::decode_R_type(signed int &s1) { unsigned int s0b, s1b, s2b; + signed int s2, s3; Response r1, r2; + Response r3 = OK; s0b = REG_SIZE; s1b = s0b + REG_SIZE; @@ -116,62 +153,124 @@ void ID::decode_R_type( s2 = GET_MID_BITS(s1, s0b, s1b); s1 = GET_LS_BITS(s1, s0b); - r1 = this->read_guard(s1); - r2 = this->read_guard(s2); - this->status = (r1 == OK && r2 == OK) ? OK : STALLED; + if (this->is_vector_type(this->curr_instr->mnemonic)) { + r1 = this->read_vec_guard( + s1, this->curr_instr->operands.vector.slot_one); + r2 = this->read_vec_guard( + s2, this->curr_instr->operands.vector.slot_two); + r3 = this->set_vlen(); + } else { + r1 = this->read_guard(s1); + this->curr_instr->operands.integer.slot_one = s1; + r2 = this->read_guard(s2); + this->curr_instr->operands.integer.slot_two = s2; + } - switch (m) { + this->status = (r1 == OK && r2 == OK && r3 == OK) ? OK : STALLED; + + switch (this->curr_instr->mnemonic) { case CMP: case CEV: break; + case ADDV: + case SUBV: + case MULV: + case DIVV: + if (this->status == OK) { + this->write_vec_guard( + s3, this->curr_instr->operands.vector.slot_three); + } + break; default: - if (this->status == OK) + if (this->status == OK) { this->write_guard(s3); + this->curr_instr->operands.integer.slot_three = s3; + } } } -void ID::decode_I_type( - signed int &s1, signed int &s2, signed int &s3, Mnemonic &m) +void ID::decode_I_type(signed int &s1) { unsigned int s0b, s1b, s2b; + signed int s2, s3; Response r1, r2; + Response r3 = OK; s0b = REG_SIZE; s1b = s0b + REG_SIZE; s2b = WORD_SPEC - LINE_SPEC - OPCODE_SIZE; + // s3 is immediate s3 = GET_BITS_SIGN_EXTEND(s1, s1b, s2b); - switch (m) { + switch (this->curr_instr->mnemonic) { case STORE: - case STOREV: + this->curr_instr->operands.integer.slot_three = s3; s2 = GET_MID_BITS(s1, s0b, s1b); s1 = GET_LS_BITS(s1, s0b); // both operands are read values + // s1 is base address r1 = this->read_guard(s1); + this->curr_instr->operands.integer.slot_one = s1; + // s2 is value to be stored r2 = this->read_guard(s2); + this->curr_instr->operands.integer.slot_two = s2; this->status = (r1 == OK && r2 == OK) ? OK : STALLED; return; - case LOAD: + case STOREV: + this->curr_instr->operands.load_store_vector.immediate = s3; + s2 = GET_MID_BITS(s1, s0b, s1b); + s1 = GET_LS_BITS(s1, s0b); + + // base address + r1 = this->read_guard(s1); + this->curr_instr->operands.load_store_vector.base_addr = s1; + // vector value to be stored + r2 = this->read_vec_guard( + s2, this->curr_instr->operands.load_store_vector.vector_register); + r3 = this->set_vlen(); + + this->status = (r1 == OK && r2 == OK && r3 == OK) ? OK : STALLED; + return; case LOADV: + this->curr_instr->operands.load_store_vector.immediate = s3; + s2 = GET_LS_BITS(s1, s0b); + s1 = GET_MID_BITS(s1, s0b, s1b); + // base address + r1 = this->read_guard(s1); + this->curr_instr->operands.load_store_vector.base_addr = s1; + r3 = this->set_vlen(); + if (r1 == OK && r3 == OK) + // vector destination + this->write_vec_guard( + s2, + this->curr_instr->operands.load_store_vector.vector_register); + this->status = (r1 == OK && r3 == OK) ? OK : STALLED; + return; + case LOAD: + this->curr_instr->operands.integer.slot_three = s3; s2 = GET_LS_BITS(s1, s0b); s1 = GET_MID_BITS(s1, s0b, s1b); break; default: + this->curr_instr->operands.integer.slot_three = s3; s2 = GET_MID_BITS(s1, s0b, s1b); s1 = GET_LS_BITS(s1, s0b); } r1 = this->read_guard(s1); - if (r1 == OK) + this->curr_instr->operands.integer.slot_one = s1; + if (r1 == OK) { this->write_guard(s2); + this->curr_instr->operands.integer.slot_two = s2; + } this->status = r1; } -void ID::decode_J_type( - signed int &s1, signed int &s2, signed int &s3, Mnemonic &m) +void ID::decode_J_type(signed int &s1) { Response r1, r2; + signed int s2, s3; unsigned int s0b, s1b; s0b = REG_SIZE; @@ -180,26 +279,34 @@ void ID::decode_J_type( s2 = GET_BITS_SIGN_EXTEND(s1, s0b, s1b); s1 = GET_LS_BITS(s1, s0b); - switch (m) { + switch (this->curr_instr->mnemonic) { case PUSH: s2 = s1; // source - s3 = 2; // stack pointer + s3 = 2; // stack pointer s1 = -1; // increment amount r1 = this->read_guard(s2); - r2 = (this->is_checked_out(s3)) ? STALLED : OK; // we read the stack pointer + this->curr_instr->operands.integer.slot_one = s1; + this->curr_instr->operands.integer.slot_two = s2; + r2 = (this->is_checked_out(s3)) ? STALLED + : OK; // we read the stack pointer if (r1 == OK && r2 == OK) { this->write_guard(s3); // we write the stack pointer + this->curr_instr->operands.integer.slot_three = s3; } this->status = (r1 == OK && r2 == OK) ? OK : STALLED; break; case POP: s2 = s1; // destination - s3 = 2; // stack pointer - s1 = 1; // increment amount - r1 = (this->is_checked_out(s3)) ? STALLED : OK; // we read the stack pointer + s3 = 2; // stack pointer + s1 = 1; // increment amount + this->curr_instr->operands.integer.slot_one = s1; + r1 = (this->is_checked_out(s3)) ? STALLED + : OK; // we read the stack pointer if (r1 == OK) { this->write_guard(s2); + this->curr_instr->operands.integer.slot_two = s2; this->write_guard(s3); // we write the stack pointer + this->curr_instr->operands.integer.slot_three = s3; } this->status = r1; break; @@ -208,6 +315,10 @@ void ID::decode_J_type( [[fallthrough]]; default: this->status = this->read_guard(s1); + if(this->status == OK){ + this->curr_instr->operands.integer.slot_one = s1; + this->curr_instr->operands.integer.slot_two = s2; + this->curr_instr->operands.integer.slot_three = s3; + } } - } @@ -24,6 +24,7 @@ void MM::advance_helper() { signed int data; int i; + int vector_delay = VECTOR_MEM_DELAY; switch (this->curr_instr->mnemonic) { case LOAD: @@ -35,6 +36,32 @@ void MM::advance_helper() } else this->status = STALLED; break; + case LOADV: + if (vector_delay == 0){ + signed int word_address = this->curr_instr->operands.load_store_vector.base_addr; + int j = 0; + while(j < this->curr_instr->slot_A){ + i = this->storage->read_word(this, word_address, data); + this->status = i ? OK : STALLED; + if (this->status == OK) { + this->curr_instr->operands.load_store_vector.vector_register[j] = data; + // +1 or +4? + word_address += 1; + j++; + } else { + break; + } + } + if(this->status == OK){ + // if vector is loaded, reset delay + vector_delay = VECTOR_MEM_DELAY; + } else { + this->status = STALLED; + } + } else { + vector_delay--; + } + break; case PUSH: case STORE: @@ -46,6 +73,31 @@ void MM::advance_helper() this->status = STALLED; } break; + case STOREV: + if (vector_delay == 0){ + signed int word_address = this->curr_instr->operands.load_store_vector.base_addr; + int j = 0; + while(j < this->curr_instr->slot_A){ + this->storage->write_word( + this, this->curr_instr->operands.load_store_vector.vector_register[j], word_address); + this->status = i ? OK : STALLED; + if (this->status != OK) { + break; + } else { + word_address += 1; + j++; + } + } + if(this->status == OK){ + // if vector is stored , reset delay + vector_delay = VECTOR_MEM_DELAY; + } else { + this->status = STALLED; + } + } else { + vector_delay--; + } + break; case POP: i = this->storage->read_word(this, this->curr_instr->operands.integer.slot_three, data); diff --git a/src/stage.cc b/src/stage.cc index 4efe2fe..ac688d8 100644 --- a/src/stage.cc +++ b/src/stage.cc @@ -16,6 +16,7 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. #include "stage.h" +#include "pipe_spec.h" #include <array> #include <deque> @@ -29,7 +30,7 @@ Stage::Stage(Stage *next) Stage::~Stage() { delete this->next; }; std::array<int, GPR_NUM> Stage::gprs; -std::array<int, V_NUM> Stage::vrs; +std::array<std::array<signed int, V_R_LIMIT>, V_NUM> Stage::vrs; std::deque<signed int> Stage::checked_out; unsigned int Stage::pc; Storage *Stage::storage; @@ -65,40 +66,28 @@ InstrDTO *Stage::advance(Response p) return r; } -InstrDTO *Stage::get_instr() { return this->curr_instr; } - -void Stage::set_condition(CC c, bool v) +bool Stage::is_vector_type(Mnemonic m) { - if (v) - this->gprs[3] = this->gprs[3] | 1 << c; - else - this->gprs[3] = this->gprs[3] & ~(1 << c); + return ( + m == ADDV || m == SUBV || m == MULV || m == DIVV || m == CEV || + m == LOADV || m == STOREV); } -signed int Stage::dereference_register(signed int v) +bool Stage::is_logical(Mnemonic m) { - signed int r; - - if (v < 0 || v >= GPR_NUM + V_NUM) { - throw std::out_of_range( - "instruction tried to access register which does not exist"); - } - - r = (v >= GPR_NUM) ? this->vrs[v % GPR_NUM] : this->gprs[v]; - return r; + return ( + m == ANDI || m == ORI || m == XORI || m == AND || m == OR || m == XOR || + m == NOT); } -void Stage::store_register(signed int v, signed int d) -{ - if (v < 0 || v >= GPR_NUM + V_NUM) { - throw std::out_of_range( - "instruction tried to access register which does not exist"); - } +InstrDTO *Stage::get_instr() { return this->curr_instr; } - if (v >= GPR_NUM) - this->vrs[v % GPR_NUM] = d; +void Stage::set_condition(CC c, bool v) +{ + if (v) + this->gprs[3] = this->gprs[3] | 1 << c; else - this->gprs[v] = d; + this->gprs[3] = this->gprs[3] & ~(1 << c); } bool Stage::is_checked_out(signed int r) @@ -45,13 +45,22 @@ void WB::write_handler() // POP performs a second register write reg = this->checked_out.front(); this->checked_out.pop_front(); - this->store_register( + this->store_register<signed int>( reg, this->curr_instr->operands.integer.slot_three); } this->checked_out.pop_front(); reg = this->curr_instr->checked_out; - this->store_register(reg, this->curr_instr->operands.integer.slot_one); + + if(this->is_vector_type(this->curr_instr->mnemonic)) { + if(this->curr_instr->mnemonic != STOREV && this->curr_instr->mnemonic != LOADV) { + this->store_register<std::array<signed int, V_R_LIMIT>>(reg, this->curr_instr->operands.vector.slot_one); + } else { + this->store_register<std::array<signed int, V_R_LIMIT>>(reg, this->curr_instr->operands.load_store_vector.vector_register); + } + } else{ + this->store_register<signed int>(reg, this->curr_instr->operands.integer.slot_one); + } } void WB::jump_handler() |