M extension for RV64
This commit is contained in:
parent
56b00aecd8
commit
643b880be3
|
@ -25,7 +25,11 @@ namespace riscv_tlm {
|
||||||
OP_M_DIVU,
|
OP_M_DIVU,
|
||||||
OP_M_REM,
|
OP_M_REM,
|
||||||
OP_M_REMU,
|
OP_M_REMU,
|
||||||
|
OP_M_MULW,
|
||||||
|
OP_M_DIVW,
|
||||||
|
OP_M_DIVUW,
|
||||||
|
OP_M_REMW,
|
||||||
|
OP_M_REMUW,
|
||||||
OP_M_ERROR
|
OP_M_ERROR
|
||||||
} op_M_Codes;
|
} op_M_Codes;
|
||||||
|
|
||||||
|
@ -38,6 +42,11 @@ namespace riscv_tlm {
|
||||||
M_DIVU = 0b101,
|
M_DIVU = 0b101,
|
||||||
M_REM = 0b110,
|
M_REM = 0b110,
|
||||||
M_REMU = 0b111,
|
M_REMU = 0b111,
|
||||||
|
M_MULW = 0b000,
|
||||||
|
M_DIVW = 0b100,
|
||||||
|
M_DIVUW = 0b101,
|
||||||
|
M_REMW = 0b110,
|
||||||
|
M_REMUW = 0b111,
|
||||||
} M_Codes;
|
} M_Codes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,34 +70,58 @@ namespace riscv_tlm {
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] op_M_Codes decode() const {
|
[[nodiscard]] op_M_Codes decode() const {
|
||||||
|
|
||||||
switch (opcode()) {
|
if (this->m_instr.range(6,0) == 0b110011) {
|
||||||
case M_MUL:
|
switch (opcode()) {
|
||||||
return OP_M_MUL;
|
case M_MUL:
|
||||||
break;
|
return OP_M_MUL;
|
||||||
case M_MULH:
|
break;
|
||||||
return OP_M_MULH;
|
case M_MULH:
|
||||||
break;
|
return OP_M_MULH;
|
||||||
case M_MULHSU:
|
break;
|
||||||
return OP_M_MULHSU;
|
case M_MULHSU:
|
||||||
break;
|
return OP_M_MULHSU;
|
||||||
case M_MULHU:
|
break;
|
||||||
return OP_M_MULHU;
|
case M_MULHU:
|
||||||
break;
|
return OP_M_MULHU;
|
||||||
case M_DIV:
|
break;
|
||||||
return OP_M_DIV;
|
case M_DIV:
|
||||||
break;
|
return OP_M_DIV;
|
||||||
case M_DIVU:
|
break;
|
||||||
return OP_M_DIVU;
|
case M_DIVU:
|
||||||
break;
|
return OP_M_DIVU;
|
||||||
case M_REM:
|
break;
|
||||||
return OP_M_REM;
|
case M_REM:
|
||||||
break;
|
return OP_M_REM;
|
||||||
case M_REMU:
|
break;
|
||||||
return OP_M_REMU;
|
case M_REMU:
|
||||||
break;
|
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:
|
[[unlikely]] default:
|
||||||
return OP_M_ERROR;
|
return OP_M_ERROR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return OP_M_ERROR;
|
return OP_M_ERROR;
|
||||||
|
@ -100,107 +133,42 @@ namespace riscv_tlm {
|
||||||
|
|
||||||
void Exec_M_MUL() const {
|
void Exec_M_MUL() const {
|
||||||
unsigned int rd, rs1, rs2;
|
unsigned int rd, rs1, rs2;
|
||||||
std::int32_t multiplier, multiplicand;
|
signed_T multiplier, multiplicand;
|
||||||
std::int64_t result;
|
std::int64_t result;
|
||||||
|
|
||||||
rd = this->get_rd();
|
rd = this->get_rd();
|
||||||
rs1 = this->get_rs1();
|
rs1 = this->get_rs1();
|
||||||
rs2 = this->get_rs2();
|
rs2 = this->get_rs2();
|
||||||
|
|
||||||
multiplier = static_cast<std::int32_t>(extension_base<T>::regs->getValue(rs1));
|
multiplier = static_cast<signed_T>(this->regs->getValue(rs1));
|
||||||
multiplicand = static_cast<std::int32_t>(extension_base<T>::regs->getValue(rs2));
|
multiplicand = static_cast<signed_T>(this->regs->getValue(rs2));
|
||||||
|
|
||||||
result = static_cast<std::int64_t>(multiplier * multiplicand);
|
result = static_cast<std::int64_t>(multiplier * multiplicand);
|
||||||
result = result & 0x00000000FFFFFFFF;
|
|
||||||
this->regs->setValue(rd, static_cast<std::int32_t>(result));
|
|
||||||
|
|
||||||
this->logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})",
|
this->regs->setValue(rd, static_cast<signed_T>(result));
|
||||||
sc_core::sc_time_stamp().value(),
|
|
||||||
extension_base<T>::regs->getPC(),
|
|
||||||
rs1, rs2, rd, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Exec_M_MULH() const {
|
this->logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})",
|
||||||
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<std::int32_t>(this->regs->getValue(rs1));
|
|
||||||
multiplicand = static_cast<std::int32_t>(this->regs->getValue(rs2));
|
|
||||||
|
|
||||||
result = static_cast<std::int64_t>(multiplier) * static_cast<std::int64_t>(multiplicand);
|
|
||||||
|
|
||||||
ret_value = static_cast<std::int32_t>((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})",
|
|
||||||
sc_core::sc_time_stamp().value(),
|
sc_core::sc_time_stamp().value(),
|
||||||
this->regs->getPC(),
|
this->regs->getPC(),
|
||||||
rs1, rs2, rd, result);
|
rs1, rs2, multiplier, multiplicand, rd, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Exec_M_MULHSU() const {
|
void Exec_M_MULH() const;
|
||||||
unsigned int rd, rs1, rs2;
|
|
||||||
std::int32_t multiplier;
|
|
||||||
std::uint32_t multiplicand;
|
|
||||||
std::int64_t result;
|
|
||||||
|
|
||||||
rd = this->get_rd();
|
void Exec_M_MULHSU() const;
|
||||||
rs1 = this->get_rs1();
|
|
||||||
rs2 = this->get_rs2();
|
|
||||||
|
|
||||||
multiplier = static_cast<std::int32_t>(this->regs->getValue(rs1));
|
void Exec_M_MULHU() const;
|
||||||
multiplicand = this->regs->getValue(rs2);
|
|
||||||
|
|
||||||
result = static_cast<std::int64_t>(multiplier * static_cast<std::uint64_t>(multiplicand));
|
|
||||||
result = (result >> 32) & 0x00000000FFFFFFFF;
|
|
||||||
this->regs->setValue(rd, static_cast<std::int32_t>(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<std::int32_t>(this->regs->getValue(rs1));
|
|
||||||
multiplicand = static_cast<std::int32_t>(this->regs->getValue(rs2));
|
|
||||||
|
|
||||||
result = static_cast<std::uint64_t>(multiplier) * static_cast<std::uint64_t>(multiplicand);
|
|
||||||
ret_value = static_cast<std::int32_t>((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_DIV() const {
|
void Exec_M_DIV() const {
|
||||||
unsigned int rd, rs1, rs2;
|
unsigned int rd, rs1, rs2;
|
||||||
std::int32_t divisor, dividend;
|
signed_T divisor, dividend;
|
||||||
std::int64_t result;
|
std::int64_t result;
|
||||||
|
|
||||||
rd = this->get_rd();
|
rd = this->get_rd();
|
||||||
rs1 = this->get_rs1();
|
rs1 = this->get_rs1();
|
||||||
rs2 = this->get_rs2();
|
rs2 = this->get_rs2();
|
||||||
|
|
||||||
dividend = static_cast<std::int32_t>(this->regs->getValue(rs1));
|
dividend = this->regs->getValue(rs1);
|
||||||
divisor = static_cast<std::int32_t>(this->regs->getValue(rs2));
|
divisor = this->regs->getValue(rs2);
|
||||||
|
|
||||||
if (divisor == 0) {
|
if (divisor == 0) {
|
||||||
result = -1;
|
result = -1;
|
||||||
|
@ -208,10 +176,9 @@ namespace riscv_tlm {
|
||||||
result = 0x0000000080000000;
|
result = 0x0000000080000000;
|
||||||
} else {
|
} else {
|
||||||
result = dividend / divisor;
|
result = dividend / divisor;
|
||||||
result = result & 0x00000000FFFFFFFF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->regs->setValue(rd, static_cast<std::int32_t>(result));
|
this->regs->setValue(rd, result);
|
||||||
|
|
||||||
this->logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})",
|
this->logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})",
|
||||||
sc_core::sc_time_stamp().value(),
|
sc_core::sc_time_stamp().value(),
|
||||||
|
@ -221,7 +188,7 @@ namespace riscv_tlm {
|
||||||
|
|
||||||
void Exec_M_DIVU() const {
|
void Exec_M_DIVU() const {
|
||||||
unsigned int rd, rs1, rs2;
|
unsigned int rd, rs1, rs2;
|
||||||
std::uint32_t divisor, dividend;
|
unsigned_T divisor, dividend;
|
||||||
std::uint64_t result;
|
std::uint64_t result;
|
||||||
|
|
||||||
rd = this->get_rd();
|
rd = this->get_rd();
|
||||||
|
@ -235,10 +202,9 @@ namespace riscv_tlm {
|
||||||
result = -1;
|
result = -1;
|
||||||
} else {
|
} else {
|
||||||
result = dividend / divisor;
|
result = dividend / divisor;
|
||||||
result = result & 0x00000000FFFFFFFF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->regs->setValue(rd, static_cast<std::int32_t>(result));
|
this->regs->setValue(rd, result);
|
||||||
|
|
||||||
this->logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})",
|
this->logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})",
|
||||||
sc_core::sc_time_stamp().value(),
|
sc_core::sc_time_stamp().value(),
|
||||||
|
@ -248,15 +214,15 @@ namespace riscv_tlm {
|
||||||
|
|
||||||
void Exec_M_REM() const {
|
void Exec_M_REM() const {
|
||||||
unsigned int rd, rs1, rs2;
|
unsigned int rd, rs1, rs2;
|
||||||
std::int32_t divisor, dividend;
|
signed_T divisor, dividend;
|
||||||
std::int32_t result;
|
signed_T result;
|
||||||
|
|
||||||
rd = this->get_rd();
|
rd = this->get_rd();
|
||||||
rs1 = this->get_rs1();
|
rs1 = this->get_rs1();
|
||||||
rs2 = this->get_rs2();
|
rs2 = this->get_rs2();
|
||||||
|
|
||||||
dividend = static_cast<std::int32_t>(this->regs->getValue(rs1));
|
dividend = this->regs->getValue(rs1);
|
||||||
divisor = static_cast<std::int32_t>(this->regs->getValue(rs2));
|
divisor = this->regs->getValue(rs2);
|
||||||
|
|
||||||
if (divisor == 0) {
|
if (divisor == 0) {
|
||||||
result = dividend;
|
result = dividend;
|
||||||
|
@ -268,7 +234,7 @@ namespace riscv_tlm {
|
||||||
|
|
||||||
this->regs->setValue(rd, result);
|
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(),
|
sc_core::sc_time_stamp().value(),
|
||||||
this->regs->getPC(),
|
this->regs->getPC(),
|
||||||
rs1, rs2, rd, result);
|
rs1, rs2, rd, result);
|
||||||
|
@ -276,15 +242,15 @@ namespace riscv_tlm {
|
||||||
|
|
||||||
void Exec_M_REMU() const {
|
void Exec_M_REMU() const {
|
||||||
unsigned int rd, rs1, rs2;
|
unsigned int rd, rs1, rs2;
|
||||||
std::uint32_t divisor, dividend;
|
unsigned_T divisor, dividend;
|
||||||
std::uint32_t result;
|
unsigned_T result;
|
||||||
|
|
||||||
rd = this->get_rd();
|
rd = this->get_rd();
|
||||||
rs1 = this->get_rs1();
|
rs1 = this->get_rs1();
|
||||||
rs2 = this->get_rs2();
|
rs2 = this->get_rs2();
|
||||||
|
|
||||||
dividend = static_cast<std::int32_t>(this->regs->getValue(rs1));
|
dividend = this->regs->getValue(rs1);
|
||||||
divisor = static_cast<std::int32_t>(this->regs->getValue(rs2));
|
divisor = this->regs->getValue(rs2);
|
||||||
|
|
||||||
if (divisor == 0) {
|
if (divisor == 0) {
|
||||||
result = dividend;
|
result = dividend;
|
||||||
|
@ -292,14 +258,145 @@ namespace riscv_tlm {
|
||||||
result = dividend % divisor;
|
result = dividend % divisor;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->regs->setValue(rd, static_cast<std::int32_t>(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(),
|
sc_core::sc_time_stamp().value(),
|
||||||
this->regs->getPC(),
|
this->regs->getPC(),
|
||||||
rs1, rs2, rd, result);
|
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<std::uint32_t>(this->regs->getValue(rs1) & 0x00000000FFFFFFFF);
|
||||||
|
multiplicand = static_cast<std::uint32_t>(this->regs->getValue(rs2) & 0x00000000FFFFFFFF);
|
||||||
|
result = static_cast<std::int32_t>((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<std::int32_t>(this->regs->getValue(rs1) & 0x00000000FFFFFFFF);
|
||||||
|
divisor = static_cast<std::int32_t>(this->regs->getValue(rs2) & 0x00000000FFFFFFFF);
|
||||||
|
|
||||||
|
if (divisor == 0) {
|
||||||
|
result = -1;
|
||||||
|
} else if ((divisor == -1) && (dividend == static_cast<std::int32_t>(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<std::uint32_t>(this->regs->getValue(rs1) & 0x00000000FFFFFFFF);
|
||||||
|
divisor = static_cast<std::uint32_t>(this->regs->getValue(rs2) & 0x00000000FFFFFFFF);
|
||||||
|
|
||||||
|
if (divisor == 0) {
|
||||||
|
result = -1;
|
||||||
|
} else if ((divisor == 0xFFFFFFFF) && (dividend == static_cast<std::uint32_t>(0x80000000))) {
|
||||||
|
result = 0x0000000080000000;
|
||||||
|
} else {
|
||||||
|
result = static_cast<std::int32_t>(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<std::int32_t>(this->regs->getValue(rs1) & 0x00000000FFFFFFFF);
|
||||||
|
divisor = static_cast<std::int32_t>(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<std::uint32_t>(this->regs->getValue(rs1) & 0x00000000FFFFFFFF);
|
||||||
|
divisor = static_cast<std::uint32_t>(this->regs->getValue(rs2) & 0x00000000FFFFFFFF);
|
||||||
|
|
||||||
|
if (divisor == 0) {
|
||||||
|
result = static_cast<std::int32_t>(dividend);
|
||||||
|
} else {
|
||||||
|
result = static_cast<std::int32_t>(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) {
|
bool process_instruction(Instruction &inst) {
|
||||||
this->setInstr(inst.getInstr());
|
this->setInstr(inst.getInstr());
|
||||||
|
|
||||||
|
@ -328,7 +425,22 @@ namespace riscv_tlm {
|
||||||
case OP_M_REMU:
|
case OP_M_REMU:
|
||||||
Exec_M_REMU();
|
Exec_M_REMU();
|
||||||
break;
|
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";
|
std::cout << "M instruction not implemented yet" << "\n";
|
||||||
inst.dump();
|
inst.dump();
|
||||||
//NOP(inst);
|
//NOP(inst);
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace riscv_tlm {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension_t Instruction::check_extension() const {
|
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)) {
|
&& (((m_instr & 0x7F000000) >> 25) == 0b0000001)) {
|
||||||
return M_EXTENSION;
|
return M_EXTENSION;
|
||||||
} else if ((m_instr & 0x0000007F) == 0b0101111) {
|
} else if ((m_instr & 0x0000007F) == 0b0101111) {
|
||||||
|
|
|
@ -7,4 +7,162 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include "M_extension.h"
|
#include "M_extension.h"
|
||||||
|
namespace riscv_tlm {
|
||||||
|
// RV32
|
||||||
|
template<>
|
||||||
|
void M_extension<std::uint32_t>::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<std::int64_t>(multiplier) * static_cast<std::int64_t>(multiplicand);
|
||||||
|
ret_value = static_cast<std::int32_t>((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<std::uint32_t>::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<std::int32_t>(this->regs->getValue(rs1));
|
||||||
|
multiplicand = this->regs->getValue(rs2);
|
||||||
|
|
||||||
|
result = static_cast<std::int64_t>(multiplier * static_cast<std::uint64_t>(multiplicand));
|
||||||
|
result = (result >> 32) & 0x00000000FFFFFFFF;
|
||||||
|
this->regs->setValue(rd, static_cast<std::int32_t>(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<std::uint32_t>::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<std::int32_t>(this->regs->getValue(rs1));
|
||||||
|
multiplicand = static_cast<std::int32_t>(this->regs->getValue(rs2));
|
||||||
|
|
||||||
|
result = static_cast<std::uint64_t>(multiplier) * static_cast<std::uint64_t>(multiplicand);
|
||||||
|
ret_value = static_cast<std::int32_t>((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<std::uint64_t>::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<std::uint64_t>::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<std::uint64_t>::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue