From 136417edd709f0e2d30931d222b658ff7dd9a5a8 Mon Sep 17 00:00:00 2001 From: bd Date: Fri, 28 Mar 2025 18:10:14 -0400 Subject: add get_instr_fields func to parse instruction fields from raw bits --- inc/definitions.h | 27 +++++++++++- inc/utils.h | 20 ++++++++- src/storage/cache.cc | 4 +- src/utils/utils.cc | 59 +++++++++++++++++++++++--- tests/utils.cc | 116 +++++++++++++++++++++++++++++++++++++++++++++++++-- 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(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(L1_CACHE_WORD_SPEC - LINE_SPEC) +#define L1_CACHE_LINE_SPEC \ + static_cast(L1_CACHE_WORD_SPEC - LINE_SPEC) #define L1_CACHE_LINES static_cast(pow(2, L1_CACHE_LINE_SPEC)) /** @@ -46,6 +51,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 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 *actual; std::array *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 #include -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 -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; -- cgit v1.2.3