diff --git a/inc/M_extension.h b/inc/M_extension.h index 8355ba3..9e17057 100644 --- a/inc/M_extension.h +++ b/inc/M_extension.h @@ -25,7 +25,11 @@ namespace riscv_tlm { OP_M_DIVU, OP_M_REM, OP_M_REMU, - + OP_M_MULW, + OP_M_DIVW, + OP_M_DIVUW, + OP_M_REMW, + OP_M_REMUW, OP_M_ERROR } op_M_Codes; @@ -38,6 +42,11 @@ namespace riscv_tlm { M_DIVU = 0b101, M_REM = 0b110, M_REMU = 0b111, + M_MULW = 0b000, + M_DIVW = 0b100, + M_DIVUW = 0b101, + M_REMW = 0b110, + M_REMUW = 0b111, } M_Codes; /** @@ -61,34 +70,58 @@ namespace riscv_tlm { */ [[nodiscard]] op_M_Codes decode() const { - switch (opcode()) { - case M_MUL: - return OP_M_MUL; - break; - case M_MULH: - return OP_M_MULH; - break; - case M_MULHSU: - return OP_M_MULHSU; - break; - case M_MULHU: - return OP_M_MULHU; - break; - case M_DIV: - return OP_M_DIV; - break; - case M_DIVU: - return OP_M_DIVU; - break; - case M_REM: - return OP_M_REM; - break; - case M_REMU: - return OP_M_REMU; - break; + if (this->m_instr.range(6,0) == 0b110011) { + switch (opcode()) { + case M_MUL: + return OP_M_MUL; + break; + case M_MULH: + return OP_M_MULH; + break; + case M_MULHSU: + return OP_M_MULHSU; + break; + case M_MULHU: + return OP_M_MULHU; + break; + case M_DIV: + return OP_M_DIV; + break; + case M_DIVU: + return OP_M_DIVU; + break; + case M_REM: + return OP_M_REM; + break; + case M_REMU: + return OP_M_REMU; + break; + [[unlikely]] default: + return OP_M_ERROR; + break; + } + } else { + switch (opcode()) { + case M_MULW: + return OP_M_MULW; + break; + case M_DIVW: + return OP_M_DIVW; + break; + case M_DIVUW: + return OP_M_DIVUW; + break; + case M_REMW: + return OP_M_REMW; + break; + case M_REMUW: + return OP_M_REMUW; + break; [[unlikely]] default: - return OP_M_ERROR; - break; + return OP_M_ERROR; + break; + + } } return OP_M_ERROR; @@ -100,107 +133,42 @@ namespace riscv_tlm { void Exec_M_MUL() const { unsigned int rd, rs1, rs2; - std::int32_t multiplier, multiplicand; + signed_T multiplier, multiplicand; std::int64_t result; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); - multiplier = static_cast(extension_base::regs->getValue(rs1)); - multiplicand = static_cast(extension_base::regs->getValue(rs2)); - + multiplier = static_cast(this->regs->getValue(rs1)); + multiplicand = static_cast(this->regs->getValue(rs2)); result = static_cast(multiplier * multiplicand); - result = result & 0x00000000FFFFFFFF; - this->regs->setValue(rd, static_cast(result)); - this->logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})", - sc_core::sc_time_stamp().value(), - extension_base::regs->getPC(), - rs1, rs2, rd, result); - } + this->regs->setValue(rd, static_cast(result)); - void Exec_M_MULH() const { - unsigned int rd, rs1, rs2; - std::int32_t multiplier, multiplicand; - std::int64_t result; - std::int32_t ret_value; - - rd = this->get_rd(); - rs1 = this->get_rs1(); - rs2 = this->get_rs2(); - - multiplier = static_cast(this->regs->getValue(rs1)); - multiplicand = static_cast(this->regs->getValue(rs2)); - - result = static_cast(multiplier) * static_cast(multiplicand); - - ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); - this->regs->setValue(rd, ret_value); - - this->logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d} * x{:d} -> x{:d}({:d})", + this->logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})", sc_core::sc_time_stamp().value(), this->regs->getPC(), - rs1, rs2, rd, result); + rs1, rs2, multiplier, multiplicand, rd, result); } - void Exec_M_MULHSU() const { - unsigned int rd, rs1, rs2; - std::int32_t multiplier; - std::uint32_t multiplicand; - std::int64_t result; + void Exec_M_MULH() const; - rd = this->get_rd(); - rs1 = this->get_rs1(); - rs2 = this->get_rs2(); + void Exec_M_MULHSU() const; - multiplier = static_cast(this->regs->getValue(rs1)); - multiplicand = this->regs->getValue(rs2); - - result = static_cast(multiplier * static_cast(multiplicand)); - result = (result >> 32) & 0x00000000FFFFFFFF; - this->regs->setValue(rd, static_cast(result)); - - this->logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", - sc_core::sc_time_stamp().value(), - this->regs->getPC(), - rs1, rs2, rd, result); - } - - void Exec_M_MULHU() const { - unsigned int rd, rs1, rs2; - std::uint32_t multiplier, multiplicand; - std::uint64_t result; - std::int32_t ret_value; - - rd = this->get_rd(); - rs1 = this->get_rs1(); - rs2 = this->get_rs2(); - - multiplier = static_cast(this->regs->getValue(rs1)); - multiplicand = static_cast(this->regs->getValue(rs2)); - - result = static_cast(multiplier) * static_cast(multiplicand); - ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); - this->regs->setValue(rd, ret_value); - - this->logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", - sc_core::sc_time_stamp().value(), - this->regs->getPC(), - rs1, rs2, rd, result); - } + void Exec_M_MULHU() const; void Exec_M_DIV() const { unsigned int rd, rs1, rs2; - std::int32_t divisor, dividend; + signed_T divisor, dividend; std::int64_t result; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); - dividend = static_cast(this->regs->getValue(rs1)); - divisor = static_cast(this->regs->getValue(rs2)); + dividend = this->regs->getValue(rs1); + divisor = this->regs->getValue(rs2); if (divisor == 0) { result = -1; @@ -208,10 +176,9 @@ namespace riscv_tlm { result = 0x0000000080000000; } else { result = dividend / divisor; - result = result & 0x00000000FFFFFFFF; } - this->regs->setValue(rd, static_cast(result)); + this->regs->setValue(rd, result); this->logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), @@ -221,7 +188,7 @@ namespace riscv_tlm { void Exec_M_DIVU() const { unsigned int rd, rs1, rs2; - std::uint32_t divisor, dividend; + unsigned_T divisor, dividend; std::uint64_t result; rd = this->get_rd(); @@ -235,10 +202,9 @@ namespace riscv_tlm { result = -1; } else { result = dividend / divisor; - result = result & 0x00000000FFFFFFFF; } - this->regs->setValue(rd, static_cast(result)); + this->regs->setValue(rd, result); this->logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), @@ -248,15 +214,15 @@ namespace riscv_tlm { void Exec_M_REM() const { unsigned int rd, rs1, rs2; - std::int32_t divisor, dividend; - std::int32_t result; + signed_T divisor, dividend; + signed_T result; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); - dividend = static_cast(this->regs->getValue(rs1)); - divisor = static_cast(this->regs->getValue(rs2)); + dividend = this->regs->getValue(rs1); + divisor = this->regs->getValue(rs2); if (divisor == 0) { result = dividend; @@ -268,7 +234,7 @@ namespace riscv_tlm { this->regs->setValue(rd, result); - this->logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} / x{:d} -> x{:d}({:d})", + this->logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} % x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), this->regs->getPC(), rs1, rs2, rd, result); @@ -276,15 +242,15 @@ namespace riscv_tlm { void Exec_M_REMU() const { unsigned int rd, rs1, rs2; - std::uint32_t divisor, dividend; - std::uint32_t result; + unsigned_T divisor, dividend; + unsigned_T result; rd = this->get_rd(); rs1 = this->get_rs1(); rs2 = this->get_rs2(); - dividend = static_cast(this->regs->getValue(rs1)); - divisor = static_cast(this->regs->getValue(rs2)); + dividend = this->regs->getValue(rs1); + divisor = this->regs->getValue(rs2); if (divisor == 0) { result = dividend; @@ -292,14 +258,145 @@ namespace riscv_tlm { result = dividend % divisor; } - this->regs->setValue(rd, static_cast(result)); + this->regs->setValue(rd, result); - this->logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} / x{:d} -> x{:d}({:d})", + this->logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} % x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), this->regs->getPC(), rs1, rs2, rd, result); } + void Exec_M_MULW() const { + unsigned int rd, rs1, rs2; + std::uint32_t multiplier, multiplicand; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = static_cast(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); + multiplicand = static_cast(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); + result = static_cast((multiplier * multiplicand) & 0x00000000FFFFFFFF); + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULW: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, multiplier, multiplicand, rd, result); + } + + void Exec_M_DIVW() const { + unsigned int rd, rs1, rs2; + std::int32_t divisor, dividend; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); + divisor = static_cast(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); + + if (divisor == 0) { + result = -1; + } else if ((divisor == -1) && (dividend == static_cast(0x80000000))) { + result = 0x0000000080000000; + } else { + result = dividend / divisor; + } + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.DIVW: x{:d} / x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_DIVUW() const { + unsigned int rd, rs1, rs2; + std::uint32_t divisor, dividend; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); + divisor = static_cast(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); + + if (divisor == 0) { + result = -1; + } else if ((divisor == 0xFFFFFFFF) && (dividend == static_cast(0x80000000))) { + result = 0x0000000080000000; + } else { + result = static_cast(dividend / divisor); + } + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.DIVUW: x{:d} / x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_REMW() const { + unsigned int rd, rs1, rs2; + std::int32_t divisor, dividend; + signed_T result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); + divisor = static_cast(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); + + if (divisor == 0) { + result = dividend; + } else if (divisor == -1) { + result = 0; + } else { + result = dividend % divisor; + } + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.REMW: x{:d} % x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_REMUW() const { + unsigned int rd, rs1, rs2; + std::uint32_t divisor, dividend; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); + divisor = static_cast(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); + + if (divisor == 0) { + result = static_cast(dividend); + } else { + result = static_cast(dividend % divisor); + } + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.REMUW: x{:d}({:d}) % x{:d}({:d}) -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, dividend, rs2, divisor, rd, result); + } + bool process_instruction(Instruction &inst) { this->setInstr(inst.getInstr()); @@ -328,7 +425,22 @@ namespace riscv_tlm { case OP_M_REMU: Exec_M_REMU(); break; - [[unlikely]] default: + case OP_M_MULW: + Exec_M_MULW(); + break; + case OP_M_DIVW: + Exec_M_DIVW(); + break; + case OP_M_DIVUW: + Exec_M_DIVUW(); + break; + case OP_M_REMW: + Exec_M_REMW(); + break; + case OP_M_REMUW: + Exec_M_REMUW(); + break; + [[unlikely]] default: std::cout << "M instruction not implemented yet" << "\n"; inst.dump(); //NOP(inst); diff --git a/src/Instruction.cpp b/src/Instruction.cpp index 3886289..d8caeee 100644 --- a/src/Instruction.cpp +++ b/src/Instruction.cpp @@ -15,7 +15,7 @@ namespace riscv_tlm { } extension_t Instruction::check_extension() const { - if (((m_instr & 0x0000007F) == 0b0110011) + if ((((m_instr & 0x0000007F) == 0b0110011) || ((m_instr & 0x0000007F) == 0b0111011)) && (((m_instr & 0x7F000000) >> 25) == 0b0000001)) { return M_EXTENSION; } else if ((m_instr & 0x0000007F) == 0b0101111) { diff --git a/src/M_extension.cpp b/src/M_extension.cpp index 4e8fee2..a6838b3 100644 --- a/src/M_extension.cpp +++ b/src/M_extension.cpp @@ -7,4 +7,162 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "M_extension.h" +namespace riscv_tlm { + // RV32 + template<> + void M_extension::Exec_M_MULH() const { + unsigned int rd, rs1, rs2; + signed_T multiplier, multiplicand; + std::int64_t result; + signed_T ret_value; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = this->regs->getValue(rs1); + multiplicand = this->regs->getValue(rs2); + + + result = static_cast(multiplier) * static_cast(multiplicand); + ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); + + this->regs->setValue(rd, ret_value); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, multiplier, rs2, multiplicand, rd, result); + } + + template<> + void M_extension::Exec_M_MULHSU() const { + unsigned int rd, rs1, rs2; + std::int32_t multiplier; + std::uint32_t multiplicand; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = static_cast(this->regs->getValue(rs1)); + multiplicand = this->regs->getValue(rs2); + + result = static_cast(multiplier * static_cast(multiplicand)); + result = (result >> 32) & 0x00000000FFFFFFFF; + this->regs->setValue(rd, static_cast(result)); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + template<> + void M_extension::Exec_M_MULHU() const { + unsigned int rd, rs1, rs2; + std::uint32_t multiplier, multiplicand; + std::uint64_t result; + std::int32_t ret_value; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = static_cast(this->regs->getValue(rs1)); + multiplicand = static_cast(this->regs->getValue(rs2)); + + result = static_cast(multiplier) * static_cast(multiplicand); + ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); + this->regs->setValue(rd, ret_value); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + + // RV64 + // I need to use SystemC bigint with 128 bits to perform 64 x 64 bits multiplication and keep the high half + template<> + void M_extension::Exec_M_MULH() const { + unsigned int rd, rs1, rs2; + signed_T multiplier, multiplicand; + signed_T result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = this->regs->getValue(rs1); + multiplicand = this->regs->getValue(rs2); + + sc_dt::sc_bigint<128> mul = multiplier; + sc_dt::sc_bigint<128> muld = multiplicand; + sc_dt::sc_bigint<128> res = mul * muld; + result = res.range(127, 64).to_int64(); + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, multiplier, rs2, multiplicand, rd, result); + } + + template<> + void M_extension::Exec_M_MULHSU() const { + unsigned int rd, rs1, rs2; + signed_T multiplier; + unsigned_T multiplicand; + signed_T result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = this->regs->getValue(rs1); + multiplicand = this->regs->getValue(rs2); + + sc_dt::sc_bigint<128> mul = multiplier; + sc_dt::sc_bigint<128> muld = multiplicand; + sc_dt::sc_bigint<128> res = mul * muld; + result = res.range(127, 64).to_int64(); + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + template<> + void M_extension::Exec_M_MULHU() const { + unsigned int rd, rs1, rs2; + unsigned_T multiplier, multiplicand; + unsigned_T result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = this->regs->getValue(rs1); + multiplicand = this->regs->getValue(rs2); + + sc_dt::sc_bigint<128> mul = multiplier; + sc_dt::sc_bigint<128> muld = multiplicand; + sc_dt::sc_bigint<128> res = mul * muld; + result = res.range(127, 64).to_uint64(); + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + +} \ No newline at end of file