summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--inc/ex.h76
-rw-r--r--inc/id.h67
-rw-r--r--inc/instr.h11
-rw-r--r--inc/instrDTO.h17
-rw-r--r--inc/stage.h6
-rw-r--r--inc/wb.h9
-rw-r--r--src/controller.cc1
-rw-r--r--src/ex.cc211
-rw-r--r--src/id.cc159
-rw-r--r--src/instr.cc11
-rw-r--r--src/mm.cc52
-rw-r--r--src/stage.cc14
-rw-r--r--src/wb.cc38
-rw-r--r--tests/id.cc39
14 files changed, 365 insertions, 346 deletions
diff --git a/inc/ex.h b/inc/ex.h
index 5a5c046..ff4041b 100644
--- a/inc/ex.h
+++ b/inc/ex.h
@@ -23,36 +23,28 @@
#include <exception>
#include <unordered_map>
-#define ADDITION_OF_GUARD(a, b) \
- (b >= 0) && (a > MAX_INT - b)
+#define ADDITION_OF_GUARD(a, b) (b >= 0) && (a > MAX_INT - b)
-#define ADDITION_UF_GUARD(a, b) \
- (b < 0) && (a < (-(MAX_INT)-1) - b)
+#define ADDITION_UF_GUARD(a, b) (b < 0) && (a < (-(MAX_INT)-1) - b)
-#define SUBTRACTION_OF_GUARD(a, b) \
- (b < 0) && (a > MAX_INT + b)
+#define SUBTRACTION_OF_GUARD(a, b) (b < 0) && (a > MAX_INT + b)
-#define SUBTRACTION_UF_GUARD(a, b) \
- (b >= 0) && (a < (-(MAX_INT)-1) + b)
+#define SUBTRACTION_UF_GUARD(a, b) (b >= 0) && (a < (-(MAX_INT)-1) + b)
-#define MULTIPLICATION_OF_GUARD(a, b) \
- (b != 0) && \
- (((b > 0) && (a > 0) && (a > MAX_INT / b)) || \
- ((b < 0) && (a < 0) && (a < MAX_INT / b)))
+#define MULTIPLICATION_OF_GUARD(a, b) \
+ (b != 0) && (((b > 0) && (a > 0) && (a > MAX_INT / b)) || \
+ ((b < 0) && (a < 0) && (a < MAX_INT / b)))
-#define MULTIPLICATION_UF_GUARD(a, b) \
- (b != 0) && (b != -1) && \
- (((b > 0) && (a < 0) && (a < (-(MAX_INT)-1) / b)) || \
- ((b < 0) && (a > 0) && (a > (-(MAX_INT)-1) / b)))
+#define MULTIPLICATION_UF_GUARD(a, b) \
+ (b != 0) && (b != -1) && \
+ (((b > 0) && (a < 0) && (a < (-(MAX_INT)-1) / b)) || \
+ ((b < 0) && (a > 0) && (a > (-(MAX_INT)-1) / b)))
-#define DIVISION_OF_GUARD(a, b) \
- ((a == -(MAX_INT) - 1) && (b == -1)) || (b == 0)
+#define DIVISION_OF_GUARD(a, b) ((a == -(MAX_INT)-1) && (b == -1)) || (b == 0)
class HaltException : public std::exception
{
- const char *what() const noexcept override {
- return "";
- }
+ const char *what() const noexcept override { return ""; }
};
class EX : public Stage
@@ -63,19 +55,57 @@ class EX : public Stage
* @param The next stage in the pipeline.
* @return A newly allocated EX object.
*/
- using Stage::Stage;
using Stage::advance;
+ using Stage::Stage;
private:
void advance_helper();
/**
+ * Handles operations involving three ints.
+ * @param slot 1, and later, the result of the mnemonic operation.
+ * @param slot 2
+ * @param slot 3
+ * @param the mnemonic
+ * @param the program counter
+ */
+ void handle_int_operations(
+ signed int &s1,
+ signed int s2,
+ signed int s3,
+ Mnemonic m,
+ unsigned int pc);
+ /**
+ * Handles operations involving three vector registers.
+ * @param slot 1, and later, the result of the mnemonic operation.
+ * @param slot 2
+ * @param slot 3
+ * @param the mnemonic
+ * @param the vector length register
+ */
+ void handle_vector_operations(
+ std::array<signed int, V_R_LIMIT> &s1,
+ std::array<signed int, V_R_LIMIT> s2,
+ Mnemonic m,
+ unsigned int v_len);
+
+ /**
+ * Handles operations involving a single vector register.
+ * Currently, this is LOADV and STOREV
+ * @param slot 1, and later, the result of the mnemonic operation.
+ * @param slot 2
+ * @param the mnemonic
+ * @param the vector length register
+ */
+ void handle_i_vector_operations(signed int &s1, signed int s2, Mnemonic m);
+ /**
* Wrapper for division functions, which detects HALT instructinos (division
* by 0).
* @param the numerator
* @param the denominator
* @param if the modulo operator should instead be used
+ * @return if the operation overflowed
*/
- void handle_divide(signed int &s1, signed int s2, bool is_mod);
+ bool handle_divide(signed int &s1, signed int s2, bool is_mod);
};
#endif /* EX_H_INCLUDED */
diff --git a/inc/id.h b/inc/id.h
index e8e9c36..5fda2b4 100644
--- a/inc/id.h
+++ b/inc/id.h
@@ -25,35 +25,13 @@
class ID : public Stage
{
public:
- using Stage::Stage;
using Stage::advance;
+ using Stage::Stage;
/* The following methods are made public so that they may be tested, and are
* not to be called from outside classes during standard execution.
*/
- /**
- * Facilitates register checkout and data hazard management.
- * It does this by checking that the register passed in is not currently
- * checked out. If true, then replaces r with the value of the register and
- * returns OK. If false, returns STALLED.
- *
- * @param the registers number, to be dereferenced.
- * @return OK if `r` is not checked out, STALLED otherwise.
- */
- Response read_guard(signed int &r);
- /**
- * Facilitates register checkout and data hazard management.
- * Checks out a register and returns it.
- *
- * @param the registers number, to be dereferenced and checked out.
- */
- 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:
@@ -82,7 +60,7 @@ class ID : public Stage
* @param the resulting third field, which varies per type.
* @param the resulting mnemonic.
*/
- void get_instr_fields(signed int &s1);
+ void get_instr_fields(signed int instr_bits);
void decode_R_type(signed int &s1);
void decode_I_type(signed int &s1);
void decode_J_type(signed int &s1);
@@ -95,6 +73,47 @@ class ID : public Stage
* @param the resulting type.
*/
void split_instr(signed int &raw, unsigned int &type, Mnemonic &m);
+ /**
+ * Facilitates register checkout and data hazard management.
+ * Checks out a register and returns it.
+ *
+ * @param the registers number, to be dereferenced and checked out.
+ */
+ template <typename T> T write_guard(int v)
+ {
+ T r;
+ // these registers shouldn't be written.
+ if (v != 0 && v != 16) {
+ // 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;
+ }
+ r = this->dereference_register<T>(v);
+ return r;
+ }
+ /**
+ * Facilitates register checkout and data hazard management.
+ * It does this by checking that the register passed in is not currently
+ * checked out. If true, then sets `result' with the value of the register
+ * and returns OK. If false, returns STALLED.
+ *
+ * @param the registers number
+ * @param the dereferenced register value
+ * @return OK if `reg` is not checked out, STALLED otherwise.
+ */
+ template <typename T> Response read_guard(int reg, T &result)
+ {
+ Response response;
+ if (this->is_checked_out(reg))
+ response = STALLED;
+ else {
+ response = OK;
+ result = this->dereference_register<T>(reg);
+ }
+ return response;
+ }
};
#endif /* ID_H_INCLUDED */
diff --git a/inc/instr.h b/inc/instr.h
index 98a1f0e..0c49a79 100644
--- a/inc/instr.h
+++ b/inc/instr.h
@@ -61,9 +61,20 @@ enum Mnemonic {
NOP,
};
+enum FieldType {
+ SI_INT,
+ R_VECT,
+ I_VECT,
+};
+
namespace instr
{
extern const std::unordered_map<unsigned int, Mnemonic> mnemonic_map;
+/**
+ * @param a mnemonic
+ * @return an enum representing the types of the decoded instruction fields.
+ */
+FieldType get_field_types(Mnemonic m);
} // namespace instr
#endif /* INSTR_H_INCLUDED */
diff --git a/inc/instrDTO.h b/inc/instrDTO.h
index f3d4597..ccc6ed9 100644
--- a/inc/instrDTO.h
+++ b/inc/instrDTO.h
@@ -19,7 +19,8 @@
#define INSTRDTO_H
#include "instr.h"
#include "pipe_spec.h"
-#include<array>
+#include <array>
+
struct U_INT_TYPE {
signed int slot_one;
@@ -33,10 +34,10 @@ struct V_TYPE {
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 VI_TYPE {
+ signed int slot_one;
+ signed int slot_two;
+ std::array<signed int, V_R_LIMIT> slot_three;
};
struct InstrDTO {
@@ -60,10 +61,14 @@ struct InstrDTO {
* The register this instruction checks out.
*/
signed int checked_out;
+ /**
+ * The currently active union member.
+ */
+ FieldType type;
union {
struct U_INT_TYPE integer;
struct V_TYPE vector;
- struct LOAD_STORE_V_TYPE load_store_vector;
+ struct VI_TYPE i_vector;
} operands;
};
diff --git a/inc/stage.h b/inc/stage.h
index 4e0c252..834b941 100644
--- a/inc/stage.h
+++ b/inc/stage.h
@@ -83,10 +83,6 @@ 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.
@@ -140,7 +136,7 @@ class Stage
}
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");
+ throw std::out_of_range("Invalid VRS index");
}
return vrs[v % GPR_NUM];
}
diff --git a/inc/wb.h b/inc/wb.h
index d3a1b93..35c9240 100644
--- a/inc/wb.h
+++ b/inc/wb.h
@@ -24,8 +24,8 @@
class WB : public Stage
{
public:
- using Stage::Stage;
using Stage::advance;
+ using Stage::Stage;
private:
void advance_helper() override;
@@ -47,6 +47,13 @@ class WB : public Stage
* STORE.
*/
bool should_jump();
+ /**
+ * @return the vector register to be stored, obtained by copying the
+ * unfilled elements in the destination register to the source. This is
+ * required to ensure what is written back only changes VECTOR_LENGTH number
+ * of elements.
+ */
+ std::array<signed int, V_R_LIMIT> copy_extra_vector_elements();
};
#endif /* WB_H_INCLUDED */
diff --git a/src/controller.cc b/src/controller.cc
index e439b30..190d3e2 100644
--- a/src/controller.cc
+++ b/src/controller.cc
@@ -32,6 +32,7 @@ Controller::Controller(Stage *stage, Storage *storage, bool is_pipelined)
this->checked_out = {};
this->gprs = {0};
this->vrs.fill({0});
+ this->vrs.at(0).fill(1); // constant 1 vector register
this->gprs.at(2) = MEM_WORDS; // set the stack pointer
}
diff --git a/src/ex.cc b/src/ex.cc
index 286c7ba..56a59d7 100644
--- a/src/ex.cc
+++ b/src/ex.cc
@@ -16,80 +16,47 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "ex.h"
+#include "instr.h"
#include "instrDTO.h"
#include "pipe_spec.h"
#include "response.h"
#include "stage.h"
+#include <stdexcept>
#include <unordered_map>
-// Switch statements for each instruction
-void EX::advance_helper()
+void EX::handle_int_operations(
+ signed int &s1, signed int s2, signed int s3, Mnemonic m, unsigned int pc)
{
- 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;
- pc = this->curr_instr->slot_B;
-
- 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);
- }
+ bool overflow, underflow;
+ overflow = get_condition(OF), underflow = get_condition(UF);
switch (m) {
case ADD:
- this->set_condition(OF, ADDITION_OF_GUARD(s1, s2));
- this->set_condition(UF, ADDITION_UF_GUARD(s1, s2));
+ overflow = ADDITION_OF_GUARD(s1, s2);
+ underflow = 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));
+ overflow = SUBTRACTION_OF_GUARD(s1, s2);
+ underflow = 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));
+ overflow = MULTIPLICATION_OF_GUARD(s1, s2);
+ underflow = MULTIPLICATION_UF_GUARD(s1, s2);
s1 = s1 * s2;
break;
case QUOT:
- this->handle_divide(s1, s2, false);
+ overflow = this->handle_divide(s1, s2, false);
+ underflow = 0;
break;
case REM:
- this->handle_divide(s1, s2, true);
+ overflow = this->handle_divide(s1, s2, true);
+ underflow = 0;
break;
case SFTR:
@@ -101,18 +68,26 @@ void EX::advance_helper()
break;
case AND:
+ overflow = false;
+ underflow = false;
s1 = s1 & s2;
break;
case OR:
+ overflow = false;
+ underflow = false;
s1 = s1 | s2;
break;
case XOR:
+ overflow = false;
+ underflow = false;
s1 = s1 ^ s2;
break;
case NOT:
+ overflow = false;
+ underflow = false;
s1 = ~s1;
break;
@@ -124,14 +99,14 @@ void EX::advance_helper()
break;
case ADDI:
- this->set_condition(OF, ADDITION_OF_GUARD(s1, s3));
- this->set_condition(UF, ADDITION_UF_GUARD(s1, s3));
+ overflow = ADDITION_OF_GUARD(s1, s3);
+ underflow = 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));
+ overflow = SUBTRACTION_OF_GUARD(s1, s3);
+ underflow = SUBTRACTION_UF_GUARD(s1, s3);
s1 = s1 - s3;
break;
@@ -144,14 +119,20 @@ void EX::advance_helper()
break;
case ANDI:
+ overflow = false;
+ underflow = false;
s1 = s1 & s3;
break;
case ORI:
+ overflow = false;
+ underflow = false;
s1 = s1 | s3;
break;
case XORI:
+ overflow = false;
+ underflow = false;
s1 = s1 ^ s3;
break;
@@ -187,72 +168,126 @@ void EX::advance_helper()
(this->get_condition(OF)) ? s1 = pc + s2 : s1 = -1;
break;
+ case RET:
+ case NOP:
+ break;
+
+ default:
+ throw std::invalid_argument(
+ "handle_int_operations received a vector operation!");
+ }
+
+ this->set_condition(OF, overflow);
+ this->set_condition(UF, underflow);
+}
+
+void EX::handle_vector_operations(
+ std::array<signed int, V_R_LIMIT> &s1,
+ std::array<signed int, V_R_LIMIT> s2,
+ Mnemonic m,
+ unsigned int v_len)
+{
+ unsigned int i;
+ bool overflow, underflow;
+
+ overflow = 0, underflow = 0;
+
+ switch (m) {
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];
+ for (i = 0; i < v_len; i++) {
+ overflow = overflow || (ADDITION_OF_GUARD(s1[i], s2[i]));
+ underflow = underflow || (ADDITION_UF_GUARD(s1[i], s2[i]));
+ s1[i] = s1[i] + s2[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];
+ for (i = 0; i < v_len; i++) {
+ overflow = overflow || (SUBTRACTION_OF_GUARD(s1[i], s2[i]));
+ underflow = underflow || (SUBTRACTION_UF_GUARD(s1[i], s2[i]));
+ s1[i] = s1[i] - s2[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];
+ for (i = 0; i < v_len; i++) {
+ overflow = overflow || (MULTIPLICATION_OF_GUARD(s1[i], s2[i]));
+ underflow = underflow || (MULTIPLICATION_UF_GUARD(s1[i], s2[i]));
+ s1[i] = s1[i] * s2[i];
}
break;
case DIVV:
- for (int i = 0; i < v_len; i++) {
- this->handle_divide(v1[i], v2[i], false);
+ for (i = 0; i < v_len; i++) {
+ // short-circuiting---this order required
+ overflow = this->handle_divide(s1[i], s2[i], false) | overflow;
}
break;
case CEV:
- int i;
+ bool eq;
+ eq = true;
for (i = 0; i < v_len; i++) {
- if (v1[i] != v2[i]) {
+ if (s1[i] != s2[i]) {
+ eq = false;
break;
}
}
- if (i == v_len) {
- this->set_condition(EQ, true);
- } else {
- this->set_condition(EQ, false);
- }
+ this->set_condition(EQ, eq);
break;
+ default:
+ throw std::invalid_argument(
+ "handle_vector_operations received an integer operation!");
+ }
+
+ this->set_condition(OF, overflow);
+ this->set_condition(UF, underflow);
+}
+
+void EX::handle_i_vector_operations(signed int &s1, signed int s2, Mnemonic m)
+{
+ switch (m) {
case LOADV:
case STOREV:
- v_base_addr = v_base_addr + v_immediate;
+ s1 = s1 + s2;
break;
case RET:
case NOP:
break;
+
+ default:
+ throw std::invalid_argument("handle_i_vector_operations did not "
+ "receive a LOADV or STOREV operation!");
}
- 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;
- }
+}
+
+void EX::advance_helper()
+{
+ unsigned int v_len_or_pc;
+ Mnemonic m;
+ m = this->curr_instr->mnemonic;
+ v_len_or_pc = this->curr_instr->slot_B;
+
+ if (this->curr_instr->type == FieldType::SI_INT) {
+ handle_int_operations(
+ this->curr_instr->operands.integer.slot_one,
+ this->curr_instr->operands.integer.slot_two,
+ this->curr_instr->operands.integer.slot_three, m, v_len_or_pc);
+ } else if (this->curr_instr->type == FieldType::R_VECT) {
+ handle_vector_operations(
+ this->curr_instr->operands.vector.slot_one,
+ this->curr_instr->operands.vector.slot_two, m, v_len_or_pc);
} else {
- this->curr_instr->operands.integer.slot_one = s1;
+ handle_i_vector_operations(
+ this->curr_instr->operands.i_vector.slot_one,
+ this->curr_instr->operands.i_vector.slot_two, m);
}
+
this->status = OK;
}
-void EX::handle_divide(signed int &s1, signed int s2, bool is_mod)
+bool EX::handle_divide(signed int &s1, signed int s2, bool is_mod)
{
- this->set_condition(OF, DIVISION_OF_GUARD(s1, s2));
- this->set_condition(UF, false);
+ bool ret;
+
+ ret = DIVISION_OF_GUARD(s1, s2);
if (s2 == 0) {
// handle everything here
this->curr_instr->operands.integer.slot_one = MAX_INT;
@@ -264,4 +299,6 @@ void EX::handle_divide(signed int &s1, signed int s2, bool is_mod)
} else {
s1 = (is_mod) ? (s1 % s2) : (s1 / s2);
}
+
+ return ret;
}
diff --git a/src/id.cc b/src/id.cc
index e4790ef..85637a6 100644
--- a/src/id.cc
+++ b/src/id.cc
@@ -22,87 +22,34 @@
#include "response.h"
#include "stage.h"
-Response ID::read_guard(signed int &v)
-{
- Response r;
- if (this->is_checked_out(v))
- r = STALLED;
- else {
- r = OK;
- v = this->dereference_register<signed int>(v);
- }
- return r;
-}
-
-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;
- vrs = this->dereference_register<std::array<signed int, V_R_LIMIT>>(v);
- }
- return r;
-}
-
-void ID::write_guard(signed int &v)
-{
- // 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;
- }
- 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;
-
if (this->curr_instr->mnemonic == NOP)
this->status = OK;
else {
// instuction in bits in s1
- s1 = this->curr_instr->slot_A;
- get_instr_fields(s1);
+ get_instr_fields(this->curr_instr->slot_A);
}
}
-void ID::get_instr_fields(signed int &s1)
+void ID::get_instr_fields(signed int instr_bits)
{
unsigned int type;
Mnemonic m;
- this->split_instr(s1, type, m);
+ this->split_instr(instr_bits, type, m);
this->curr_instr->mnemonic = m;
+ this->curr_instr->type = instr::get_field_types(m);
switch (type) {
case 0b00:
- this->decode_R_type(s1);
+ this->decode_R_type(instr_bits);
break;
case 0b01:
- this->decode_I_type(s1);
+ this->decode_I_type(instr_bits);
break;
case 0b10:
- this->decode_J_type(s1);
+ this->decode_J_type(instr_bits);
break;
case 0b11:
- // not defined, m = NOP
this->status = OK;
}
}
@@ -127,13 +74,13 @@ Response ID::set_vlen()
{
signed int vlen_reg = 4;
Response r;
- r = this->read_guard(vlen_reg);
+ r = this->read_guard<signed int>(vlen_reg, vlen_reg);
vlen_reg = vlen_reg & 0xf;
if (r == OK) {
if (vlen_reg > V_R_LIMIT) {
- this->curr_instr->slot_A = V_R_LIMIT;
+ this->curr_instr->slot_B = V_R_LIMIT;
} else {
- this->curr_instr->slot_A = vlen_reg;
+ this->curr_instr->slot_B = vlen_reg;
}
}
return r;
@@ -143,8 +90,7 @@ void ID::decode_R_type(signed int &s1)
{
unsigned int s0b, s1b, s2b;
signed int s2, s3;
- Response r1, r2;
- Response r3 = OK;
+ Response r1, r2, r3;
s0b = REG_SIZE;
s1b = s0b + REG_SIZE;
@@ -153,17 +99,18 @@ void ID::decode_R_type(signed int &s1)
s2 = GET_MID_BITS(s1, s0b, s1b);
s1 = GET_LS_BITS(s1, s0b);
- if (this->is_vector_type(this->curr_instr->mnemonic)) {
- r1 = this->read_vec_guard(
+ if (this->curr_instr->type == SI_INT) {
+ r1 = this->read_guard<signed int>(
+ s1, this->curr_instr->operands.integer.slot_one);
+ r2 = this->read_guard<signed int>(
+ s2, this->curr_instr->operands.integer.slot_two);
+ r3 = OK;
+ } else {
+ r1 = this->read_guard<std::array<signed int, V_R_LIMIT>>(
s1, this->curr_instr->operands.vector.slot_one);
- r2 = this->read_vec_guard(
+ r2 = this->read_guard<std::array<signed int, V_R_LIMIT>>(
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;
@@ -177,14 +124,14 @@ void ID::decode_R_type(signed int &s1)
case MULV:
case DIVV:
if (this->status == OK) {
- this->write_vec_guard(
- s3, this->curr_instr->operands.vector.slot_three);
+ this->curr_instr->operands.vector.slot_three =
+ this->write_guard<std::array<signed int, V_R_LIMIT>>(s3);
}
break;
default:
if (this->status == OK) {
- this->write_guard(s3);
- this->curr_instr->operands.integer.slot_three = s3;
+ this->curr_instr->operands.integer.slot_three =
+ this->write_guard<signed int>(s3);
}
}
}
@@ -199,7 +146,7 @@ void ID::decode_I_type(signed int &s1)
s0b = REG_SIZE;
s1b = s0b + REG_SIZE;
s2b = WORD_SPEC - LINE_SPEC - OPCODE_SIZE;
- // s3 is immediate
+ // s3 is slot_two
s3 = GET_BITS_SIGN_EXTEND(s1, s1b, s2b);
switch (this->curr_instr->mnemonic) {
@@ -210,41 +157,40 @@ void ID::decode_I_type(signed int &s1)
// both operands are read values
// s1 is base address
- r1 = this->read_guard(s1);
+ r1 = this->read_guard<signed int>(s1, s1);
this->curr_instr->operands.integer.slot_one = s1;
// s2 is value to be stored
- r2 = this->read_guard(s2);
+ r2 = this->read_guard<signed int>(s2, s2);
this->curr_instr->operands.integer.slot_two = s2;
this->status = (r1 == OK && r2 == OK) ? OK : STALLED;
return;
case STOREV:
- this->curr_instr->operands.load_store_vector.immediate = s3;
+ this->curr_instr->operands.i_vector.slot_two = 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;
+ r1 = this->read_guard<signed int>(s1, s1);
+ this->curr_instr->operands.i_vector.slot_one = s1;
// vector value to be stored
- r2 = this->read_vec_guard(
- s2, this->curr_instr->operands.load_store_vector.vector_register);
+ r2 = this->read_guard<std::array<signed int, V_R_LIMIT>>(
+ s2, this->curr_instr->operands.i_vector.slot_three);
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;
+ this->curr_instr->operands.i_vector.slot_two = 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;
+ r1 = this->read_guard<signed int>(s1, s1);
+ this->curr_instr->operands.i_vector.slot_one = 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->curr_instr->operands.i_vector.slot_three =
+ this->write_guard<std::array<signed int, V_R_LIMIT>>(s2);
this->status = (r1 == OK && r3 == OK) ? OK : STALLED;
return;
case LOAD:
@@ -258,11 +204,11 @@ void ID::decode_I_type(signed int &s1)
s1 = GET_LS_BITS(s1, s0b);
}
- r1 = this->read_guard(s1);
+ r1 = this->read_guard<signed int>(s1, s1);
this->curr_instr->operands.integer.slot_one = s1;
if (r1 == OK) {
- this->write_guard(s2);
- this->curr_instr->operands.integer.slot_two = s2;
+ this->curr_instr->operands.integer.slot_two =
+ this->write_guard<int>(s2);
}
this->status = r1;
}
@@ -284,14 +230,16 @@ void ID::decode_J_type(signed int &s1)
s2 = s1; // source
s3 = 2; // stack pointer
s1 = -1; // increment amount
- r1 = this->read_guard(s2);
+
this->curr_instr->operands.integer.slot_one = s1;
- this->curr_instr->operands.integer.slot_two = s2;
+ r1 = this->read_guard<signed int>(
+ s2, this->curr_instr->operands.integer.slot_two);
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;
+ // we write the stack pointer
+ this->curr_instr->operands.integer.slot_three =
+ this->write_guard<int>(s3);
}
this->status = (r1 == OK && r2 == OK) ? OK : STALLED;
break;
@@ -303,10 +251,11 @@ void ID::decode_J_type(signed int &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->curr_instr->operands.integer.slot_two =
+ this->write_guard<int>(s2);
+ // we write the stack pointer
+ this->curr_instr->operands.integer.slot_three =
+ this->write_guard<int>(s3);
}
this->status = r1;
break;
@@ -314,9 +263,9 @@ void ID::decode_J_type(signed int &s1)
s1 = 1; // link register
[[fallthrough]];
default:
- this->status = this->read_guard(s1);
- if(this->status == OK){
- this->curr_instr->operands.integer.slot_one = s1;
+ this->status = this->read_guard<signed int>(
+ s1, this->curr_instr->operands.integer.slot_one);
+ if (this->status == OK) {
this->curr_instr->operands.integer.slot_two = s2;
this->curr_instr->operands.integer.slot_three = s3;
}
diff --git a/src/instr.cc b/src/instr.cc
index 9bd951b..ee2d37f 100644
--- a/src/instr.cc
+++ b/src/instr.cc
@@ -37,4 +37,15 @@ const std::unordered_map<unsigned int, Mnemonic> mnemonic_map = {
{0b0011010, BUF}, {0b0011110, BOF}, {0b0100010, PUSH},
{0b0100110, POP}, {0b0101010, RET},
};
+
+FieldType get_field_types(Mnemonic m)
+{
+ if (m == ADDV || m == SUBV || m == MULV || m == DIVV || m == CEV) {
+ return R_VECT;
+ } else if (m == STOREV || m == LOADV) {
+ return I_VECT;
+ } else {
+ return SI_INT;
+ }
+}
} // namespace instr
diff --git a/src/mm.cc b/src/mm.cc
index 8134cf5..ac77433 100644
--- a/src/mm.cc
+++ b/src/mm.cc
@@ -24,7 +24,6 @@ void MM::advance_helper()
{
signed int data;
int i;
- int vector_delay = VECTOR_MEM_DELAY;
switch (this->curr_instr->mnemonic) {
case LOAD:
@@ -36,32 +35,6 @@ 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:
@@ -73,31 +46,6 @@ 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 4eab7d3..7db3539 100644
--- a/src/stage.cc
+++ b/src/stage.cc
@@ -71,20 +71,6 @@ InstrDTO *Stage::advance(Response p)
return r;
}
-bool Stage::is_vector_type(Mnemonic m)
-{
- return (
- m == ADDV || m == SUBV || m == MULV || m == DIVV || m == CEV ||
- m == LOADV || m == STOREV);
-}
-
-bool Stage::is_logical(Mnemonic m)
-{
- return (
- m == ANDI || m == ORI || m == XORI || m == AND || m == OR || m == XOR ||
- m == NOT);
-}
-
InstrDTO *Stage::get_instr() { return this->curr_instr; }
void Stage::set_condition(CC c, bool v)
diff --git a/src/wb.cc b/src/wb.cc
index 0dae5f2..bfdbc3a 100644
--- a/src/wb.cc
+++ b/src/wb.cc
@@ -16,6 +16,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "wb.h"
+#include "instr.h"
#include "instrDTO.h"
#include "response.h"
#include "stage.h"
@@ -51,15 +52,21 @@ void WB::write_handler()
this->checked_out.pop_front();
reg = this->curr_instr->checked_out;
-
- 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);
+
+ switch (this->curr_instr->type) {
+ case SI_INT:
+ this->store_register<signed int>(
+ reg, this->curr_instr->operands.integer.slot_one);
+ break;
+ case R_VECT:
+ this->store_register<std::array<signed int, V_R_LIMIT>>(
+ reg, this->copy_extra_vector_elements());
+ break;
+ case I_VECT:
+ this->store_register<std::array<signed int, V_R_LIMIT>>(
+ reg, this->curr_instr->operands.i_vector.slot_three);
+ // todo, use copy_extra_vector_elements
+ break;
}
}
@@ -68,7 +75,6 @@ void WB::jump_handler()
if (this->curr_instr->operands.integer.slot_one > 0) {
if (this->curr_instr->mnemonic == JAL)
this->gprs[1] = this->curr_instr->slot_B + 1;
- ;
this->pc = this->curr_instr->operands.integer.slot_one;
this->checked_out = {};
this->next->squash();
@@ -85,3 +91,15 @@ bool WB::should_jump()
else
return false;
}
+
+std::array<signed int, V_R_LIMIT> WB::copy_extra_vector_elements()
+{
+ int i;
+ std::array<signed int, V_R_LIMIT> v;
+
+ v = this->curr_instr->operands.vector.slot_one;
+ for (i = V_R_LIMIT - 1; i >= this->curr_instr->slot_B; --i) {
+ v[i] = this->curr_instr->operands.vector.slot_three[i];
+ }
+ return v;
+}
diff --git a/tests/id.cc b/tests/id.cc
index a81e967..b52ad9c 100644
--- a/tests/id.cc
+++ b/tests/id.cc
@@ -118,7 +118,7 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary r-type # two", "[id]")
signed int t;
InstrDTO *i;
- t = this->encode_R_type(0b10000, 0b01000, 0b00100, 0b10, 0b0);
+ t = this->encode_R_type(0b1000, 0b01000, 0b00100, 0b10, 0b0);
i = this->decode_bits(t);
CHECK(i->operands.integer.slot_one == 0x00000000); // registers are empty
@@ -129,6 +129,22 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary r-type # two", "[id]")
delete i;
}
+TEST_CASE_METHOD(IDFixture, "Parse arbitrary r-type # three", "[id]")
+{
+ signed int t;
+ InstrDTO *i;
+
+ t = this->encode_R_type(0b10000, 0b10001, 0b10101, 0b1110, 0b0);
+ i = this->decode_bits(t);
+
+ CHECK(i->operands.integer.slot_one == 0x00000000); // registers are empty
+ CHECK(i->operands.integer.slot_two == 0x00000000);
+ CHECK(i->operands.integer.slot_three == 0x00000000);
+ CHECK(i->mnemonic == MULV);
+
+ delete i;
+}
+
TEST_CASE_METHOD(IDFixture, "Parse arbitrary i-type # one", "[id]")
{
signed int t;
@@ -150,7 +166,7 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary i-type # two", "[id]")
signed int t;
InstrDTO *i;
- t = this->encode_I_type(0xCC, 0b101, 0b110, 0b1011, 0b1);
+ t = this->encode_I_type(0xCC, 0b10101, 0b00110, 0b11011, 0b1);
i = this->decode_bits(t);
CHECK(i->operands.integer.slot_one == 0x00000000); // registers are empty
@@ -166,7 +182,7 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary j-type # one", "[id]")
signed int t;
InstrDTO *i;
- t = this->encode_J_type(0x3456, 0b10101, 0b0111, 0b10);
+ t = this->encode_J_type(0x3456, 0b101, 0b0111, 0b10);
i = this->decode_bits(t);
CHECK(i->operands.integer.slot_one == 0x00000000); // registers are empty
@@ -181,7 +197,7 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary j-type # two", "[id]")
signed int t;
InstrDTO *i;
- t = this->encode_J_type(0xBBCCF, 0b10101, 0b0011, 0b10);
+ t = this->encode_J_type(0xBBCCF, 0b00101, 0b0011, 0b10);
i = this->decode_bits(t);
t = 0xFFFBBCCF;
@@ -191,18 +207,3 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary j-type # two", "[id]")
delete i;
}
-
-TEST_CASE_METHOD(IDFixture, "read does not conflict with read", "[id]")
-{
- signed int v;
- Response r;
-
- v = 0b1;
- r = this->d->read_guard(v);
- CHECK(v == 0b0);
- REQUIRE(r == OK);
-
- v = 0b1;
- this->d->read_guard(v);
- REQUIRE(v == 0b0);
-}