risc-v-tlm/src/M_extension.cpp

168 lines
5.7 KiB
C++

/*!
\file M_extension.h
\brief Implement M extensions part of the RISC-V
\author Màrius Montón
\date November 2018
*/
// SPDX-License-Identifier: GPL-3.0-or-later
#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);
}
}