summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbd <bdunahu@operationnull.com>2025-03-28 18:10:14 -0400
committerbd <bdunahu@operationnull.com>2025-03-28 18:10:14 -0400
commit136417edd709f0e2d30931d222b658ff7dd9a5a8 (patch)
tree7ecf0837278e46146360134bb43252357acfe494
parentab6d02361b04a18b7823aef0ff1cb0ff2a215ec2 (diff)
add get_instr_fields func to parse instruction fields from raw bits
-rw-r--r--inc/definitions.h27
-rw-r--r--inc/utils.h20
-rw-r--r--src/storage/cache.cc4
-rw-r--r--src/utils/utils.cc59
-rw-r--r--tests/utils.cc116
5 files changed, 213 insertions, 13 deletions
diff --git a/inc/definitions.h b/inc/definitions.h
index ff2f7c6..c9367ff 100644
--- a/inc/definitions.h
+++ b/inc/definitions.h
@@ -11,6 +11,10 @@
* The total number of words in a line
*/
#define LINE_SIZE static_cast<int>(pow(2, 2))
+/**
+ * Number of bits in a word
+ */
+#define WORD_SPEC 32
/**
* The number of bits to specify a memory word
@@ -28,7 +32,8 @@
* The total number of lines in l1 cache
*/
#define L1_CACHE_WORD_SPEC 7
-#define L1_CACHE_LINE_SPEC static_cast<unsigned int>(L1_CACHE_WORD_SPEC - LINE_SPEC)
+#define L1_CACHE_LINE_SPEC \
+ static_cast<unsigned int>(L1_CACHE_WORD_SPEC - LINE_SPEC)
#define L1_CACHE_LINES static_cast<int>(pow(2, L1_CACHE_LINE_SPEC))
/**
@@ -47,6 +52,26 @@
#define GPR_NUM 16
/**
+ * The number of bits to specify an instruction type
+ */
+#define TYPE_SIZE 2
+
+/**
+ * The number of bits to specify a register
+ */
+#define REG_SIZE 5
+
+/**
+ * The number of bits to specify an R-Type opcode.
+ */
+#define R_OPCODE_SIZE 5
+
+/**
+ * The number of bits to specify an opcode.
+ */
+#define OPCODE_SIZE 4
+
+/**
* Return the N least-significant bits from integer K using a bit mask
* @param the integer to be parsed
* @param the number of bits to be parsed
diff --git a/inc/utils.h b/inc/utils.h
index df8d374..7fed157 100644
--- a/inc/utils.h
+++ b/inc/utils.h
@@ -10,7 +10,25 @@
* @param the resulting index
* @param the resulting offset
*/
-void get_bit_fields(int address, int *tag, int *index, int *offset);
+void get_cache_fields(int address, int *tag, int *index, int *offset);
+
+/**
+ * Parse an instruction into a type, opcode, and fields. If the type is invalid,
+ * only the type field will be set.
+ * @param the resulting first field, which varies per type. To call this
+ * function properly, this field must contain the full instruction bytes on
+ * function entry.
+ * @param the resulting second field, which varies per type.
+ * @param the resulting third field, which varies per type.
+ * @param the resulting type.
+ * @param the resulting opcode.
+ */
+void get_instr_fields(
+ signed int &s1,
+ signed int &s2,
+ signed int &s3,
+ unsigned int &type,
+ unsigned int &opcode);
/**
* Formats a string using snprintf.
diff --git a/src/storage/cache.cc b/src/storage/cache.cc
index dccab47..80f59ef 100644
--- a/src/storage/cache.cc
+++ b/src/storage/cache.cc
@@ -69,7 +69,7 @@ Response Cache::process(
Response r = this->is_access_cleared(accessor, address);
if (r == OK) {
int tag, index, offset;
- get_bit_fields(address, &tag, &index, &offset);
+ get_cache_fields(address, &tag, &index, &offset);
request_handler(index, offset);
}
return r;
@@ -104,7 +104,7 @@ void Cache::handle_miss(int expected)
std::array<signed int, LINE_SIZE> *actual;
std::array<int, 2> *meta;
- get_bit_fields(expected, &tag, &index, &offset);
+ get_cache_fields(expected, &tag, &index, &offset);
r = OK;
meta = &this->meta.at(index);
actual = &this->data->at(index);
diff --git a/src/utils/utils.cc b/src/utils/utils.cc
index 3a11c2c..3b140e0 100644
--- a/src/utils/utils.cc
+++ b/src/utils/utils.cc
@@ -4,14 +4,62 @@
#include <string>
#include <vector>
-void get_bit_fields(int address, int *tag, int *index, int *offset)
+static Logger *global_log = Logger::getInstance();
+
+void get_cache_fields(int address, int *tag, int *index, int *offset)
{
- *tag = GET_MID_BITS(
- address, L1_CACHE_LINE_SPEC + LINE_SPEC, MEM_WORD_SPEC);
+ *tag = GET_MID_BITS(address, L1_CACHE_LINE_SPEC + LINE_SPEC, MEM_WORD_SPEC);
*index = GET_MID_BITS(address, LINE_SPEC, L1_CACHE_LINE_SPEC + LINE_SPEC);
*offset = GET_LS_BITS(address, LINE_SPEC);
}
+void get_instr_fields(
+ signed int &s1,
+ signed int &s2,
+ signed int &s3,
+ unsigned int &type,
+ unsigned int &opcode)
+{
+ type = GET_LS_BITS(s1, TYPE_SIZE);
+ switch (type) {
+ case 0:
+ // R-TYPE
+ opcode = GET_MID_BITS(s1, TYPE_SIZE, TYPE_SIZE + R_OPCODE_SIZE);
+ s3 = GET_MID_BITS(
+ s1, TYPE_SIZE + R_OPCODE_SIZE + (REG_SIZE * 2),
+ TYPE_SIZE + R_OPCODE_SIZE + (REG_SIZE * 3));
+ s2 = GET_MID_BITS(
+ s1, TYPE_SIZE + R_OPCODE_SIZE + REG_SIZE,
+ TYPE_SIZE + R_OPCODE_SIZE + (REG_SIZE * 2));
+ s1 = GET_MID_BITS(
+ s1, TYPE_SIZE + R_OPCODE_SIZE,
+ TYPE_SIZE + R_OPCODE_SIZE + REG_SIZE);
+ break;
+ case 1:
+ // I-TYPE
+ opcode = GET_MID_BITS(s1, TYPE_SIZE, TYPE_SIZE + OPCODE_SIZE);
+ s3 = GET_MID_BITS(
+ s1, TYPE_SIZE + OPCODE_SIZE + (REG_SIZE * 2), WORD_SPEC);
+ s2 = GET_MID_BITS(
+ s1, TYPE_SIZE + OPCODE_SIZE + REG_SIZE,
+ TYPE_SIZE + OPCODE_SIZE + (REG_SIZE * 2));
+ s1 = GET_MID_BITS(
+ s1, TYPE_SIZE + OPCODE_SIZE, TYPE_SIZE + OPCODE_SIZE + REG_SIZE);
+ break;
+ case 2:
+ // J-TYPE
+ opcode = GET_MID_BITS(s1, TYPE_SIZE, TYPE_SIZE + OPCODE_SIZE);
+ s2 = GET_MID_BITS(s1, TYPE_SIZE + OPCODE_SIZE + REG_SIZE, WORD_SPEC);
+ s1 = GET_MID_BITS(
+ s1, TYPE_SIZE + OPCODE_SIZE, TYPE_SIZE + OPCODE_SIZE + REG_SIZE);
+ break;
+ default:
+ global_log->log(
+ DEBUG,
+ string_format("%s returning invalid type: %d", __FUNCTION__, type));
+ }
+}
+
const std::string string_format(const char *const zcFormat, ...)
{
va_list vaArgs;
@@ -28,8 +76,9 @@ const std::string string_format(const char *const zcFormat, ...)
return std::string(zc.data(), iLen);
}
-int wrap_address(int address) {
- if (address < 0){
+int wrap_address(int address)
+{
+ if (address < 0) {
return ((address % MEM_WORDS) + MEM_WORDS) % MEM_WORDS;
}
return address % MEM_WORDS;
diff --git a/tests/utils.cc b/tests/utils.cc
index ea1a1ed..6c72694 100644
--- a/tests/utils.cc
+++ b/tests/utils.cc
@@ -2,26 +2,134 @@
#include "definitions.h"
#include <catch2/catch_test_macros.hpp>
-TEST_CASE("Parse arbitrary fields # one", "[cache]")
+TEST_CASE("Parse arbitrary fields # one", "[utils]")
{
int tag, index, offset;
int address = 0b0001010101;
- get_bit_fields(address, &tag, &index, &offset);
+ get_cache_fields(address, &tag, &index, &offset);
CHECK(tag == 0b000);
CHECK(index == 0b10101);
CHECK(offset == 0b01);
}
-TEST_CASE("Parse arbitrary fields # two", "[cache]")
+TEST_CASE("Parse arbitrary fields # two", "[utils]")
{
int tag, index, offset;
int address = 0b0100111011;
- get_bit_fields(address, &tag, &index, &offset);
+ get_cache_fields(address, &tag, &index, &offset);
CHECK(tag == 0b010);
CHECK(index == 0b01110);
CHECK(offset == 0b11);
}
+TEST_CASE("Parse invalid type", "[utils]")
+{
+ signed int s1 = 0, s2 = 0, s3 = 0;
+ unsigned int type = 0, opcode = 0;
+
+ s1 = 0x00FF00FF;
+ get_instr_fields(s1, s2, s3, type, opcode);
+
+ REQUIRE(type == 0b11);
+ // behavior does nothing
+ CHECK(s1 == 0x00FF00FF);
+ CHECK(s2 == 0b0);
+ CHECK(s3 == 0b0);
+ CHECK(opcode == 0b0);
+}
+
+TEST_CASE("Parse arbitrary r-type # one", "[utils]")
+{
+ signed int s1 = 0, s2 = 0, s3 = 0;
+ unsigned int type = 0, opcode = 0;
+
+ s1 = 0xCCCCCCCC;
+ get_instr_fields(s1, s2, s3, type, opcode);
+
+ REQUIRE(type == 0b00);
+ CHECK(s1 == 0b11001);
+ CHECK(s2 == 0b01100);
+ CHECK(s3 == 0b00110);
+ CHECK(opcode == 0b10011);
+}
+
+TEST_CASE("Parse arbitrary r-type # two", "[utils]")
+{
+ signed int s1 = 0, s2 = 0, s3 = 0;
+ unsigned int type = 0, opcode = 0;
+
+ s1 = 0x99AABBCC;
+ get_instr_fields(s1, s2, s3, type, opcode);
+
+ REQUIRE(type == 0b00);
+ CHECK(s1 == 0b10111);
+ CHECK(s2 == 0b01011);
+ CHECK(s3 == 0b10101);
+ CHECK(opcode == 0b10011);
+}
+
+TEST_CASE("Parse arbitrary i-type # one", "[utils]")
+{
+ signed int s1 = 0, s2 = 0, s3 = 0;
+ unsigned int type = 0, opcode = 0;
+
+ s1 = 0xDDDDDDDD;
+ get_instr_fields(s1, s2, s3, type, opcode);
+
+ REQUIRE(type == 0b01);
+ CHECK(s1 == 0b10111);
+ CHECK(s2 == 0b11011);
+ CHECK(s3 == 0xDDDD);
+ CHECK(opcode == 0b0111);
+}
+
+TEST_CASE("Parse arbitrary i-type # two", "[utils]")
+{
+ signed int s1 = 0, s2 = 0, s3 = 0;
+ unsigned int type = 0, opcode = 0;
+
+ s1 = 0xAABBCCDD;
+ get_instr_fields(s1, s2, s3, type, opcode);
+
+ REQUIRE(type == 0b01);
+ CHECK(s1 == 0b10011);
+ CHECK(s2 == 0b11001);
+ CHECK(s3 == 0xAABB);
+ CHECK(opcode == 0b0111);
+}
+
+TEST_CASE("Parse arbitrary j-type # one", "[utils]")
+{
+ signed int s1 = 0, s2 = 0, s3 = 0;
+ unsigned int type = 0, opcode = 0;
+
+ s1 = 0xEEEEEEEE;
+ get_instr_fields(s1, s2, s3, type, opcode);
+
+ REQUIRE(type == 0b10);
+ CHECK(s1 == 0b11011);
+ CHECK(s2 == 0b111011101110111011101);
+ CHECK(opcode == 0b1011);
+ // behavior does nothing
+ CHECK(s3 == 0b0);
+}
+
+TEST_CASE("Parse arbitrary j-type # two", "[utils]")
+{
+ signed int s1 = 0, s2 = 0, s3 = 0;
+ unsigned int type = 0, opcode = 0;
+
+ s1 = 0xBBCCDDEE;
+ get_instr_fields(s1, s2, s3, type, opcode);
+
+ REQUIRE(type == 0b10);
+ CHECK(s1 == 0b10111);
+ CHECK(s2 == 0b101110111100110011011);
+ CHECK(opcode == 0b1011);
+ // behavior does nothing
+ CHECK(s3 == 0b0);
+}
+
TEST_CASE("wrap address outside upper bound", "[utils]")
{
int address = MEM_WORDS + 25;