summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gui/gui.cc6
-rw-r--r--gui/registerview.cc53
-rw-r--r--gui/registerview.h48
-rw-r--r--gui/storageview.cc5
-rw-r--r--gui/storageview.h12
-rw-r--r--inc/ex.h12
-rw-r--r--inc/id.h14
-rw-r--r--inc/instrDTO.h12
-rw-r--r--inc/pipe_spec.h2
-rw-r--r--inc/stage.h40
-rw-r--r--src/ex.cc601
-rw-r--r--src/id.cc189
-rw-r--r--src/mm.cc52
-rw-r--r--src/stage.cc43
-rw-r--r--src/wb.cc13
15 files changed, 601 insertions, 501 deletions
diff --git a/gui/gui.cc b/gui/gui.cc
index 2581c4c..63bb4f3 100644
--- a/gui/gui.cc
+++ b/gui/gui.cc
@@ -21,6 +21,7 @@
#include "cachewaysselector.h"
#include "messages.h"
#include "storageview.h"
+#include "registerview.h"
#include "util.h"
#include <QHeaderView>
#include <QPixmap>
@@ -352,14 +353,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)),
+ LINE_SIZE,
this);
}
diff --git a/gui/registerview.cc b/gui/registerview.cc
new file mode 100644
index 0000000..5320afa
--- /dev/null
+++ b/gui/registerview.cc
@@ -0,0 +1,53 @@
+// 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 "registerview.h"
+#include "definitions.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();
+ return this->d[i.row()][i.column()];
+}
+
+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 * 4, this->is_hex);
+ }
+ return QVariant();
+}
diff --git a/gui/registerview.h b/gui/registerview.h
new file mode 100644
index 0000000..e4cb940
--- /dev/null
+++ b/gui/registerview.h
@@ -0,0 +1,48 @@
+// 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 <QAbstractTableModel>
+#include "storageview.h"
+#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;
+};
+
+#endif // REGISTERVIEW_H
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..e8f3473 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,12 +75,16 @@ 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;
diff --git a/inc/ex.h b/inc/ex.h
index c356543..5a5c046 100644
--- a/inc/ex.h
+++ b/inc/ex.h
@@ -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 */
diff --git a/inc/id.h b/inc/id.h
index aafe2e5..e8e9c36 100644
--- a/inc/id.h
+++ b/inc/id.h
@@ -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/ex.cc b/src/ex.cc
index eac24ff..03a4e59 100644
--- a/src/ex.cc
+++ b/src/ex.cc
@@ -22,415 +22,220 @@
#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;
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;
+ }
- this->curr_instr->operands.integer.slot_one = s1;
+ if(this->is_logical(m)) {
+ this->set_condition(OF, false);
+ this->set_condition(UF, false);
+ }
+
+ 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:
+ if(v_len ==0){
+
+ } else {
+ 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;
+
+ }
+
this->status = OK;
}
diff --git a/src/id.cc b/src/id.cc
index d2a8f02..aebb054 100644
--- a/src/id.cc
+++ b/src/id.cc
@@ -22,30 +22,26 @@
#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 +55,93 @@ 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,44 +150,95 @@ 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;
+ }
+
+ this->status = (r1 == OK && r2 == OK && r3 == OK) ? OK : STALLED;
- switch (m) {
+ 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)
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;
@@ -163,15 +248,18 @@ void ID::decode_I_type(
}
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,15 +268,17 @@ 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
s1 = -1; // increment amount
r1 = this->read_guard(s2);
+ 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;
@@ -199,7 +289,9 @@ void ID::decode_J_type(
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 +300,7 @@ void ID::decode_J_type(
[[fallthrough]];
default:
this->status = this->read_guard(s1);
+ this->curr_instr->operands.integer.slot_one = s1;
}
}
diff --git a/src/mm.cc b/src/mm.cc
index ac77433..8134cf5 100644
--- a/src/mm.cc
+++ b/src/mm.cc
@@ -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)
diff --git a/src/wb.cc b/src/wb.cc
index cd24c6a..0dae5f2 100644
--- a/src/wb.cc
+++ b/src/wb.cc
@@ -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()