Changed to template classe to prepare for 64bits version

This commit is contained in:
Màrius Montón 2022-02-20 11:23:58 +01:00
parent d1fa3c752e
commit 10ed1fa653
No known key found for this signature in database
GPG Key ID: FA199E7A752699F0
12 changed files with 3202 additions and 3380 deletions

View File

@ -52,59 +52,465 @@ namespace riscv_tlm {
/** /**
* @brief Instruction decoding and fields access * @brief Instruction decoding and fields access
*/ */
class A_extension : public extension_base<std::uint32_t> { template<typename T>
class A_extension : public extension_base<T> {
public: public:
/** /**
* @brief Constructor, same as base class * @brief Constructor, same as base class
*/ */
using extension_base::extension_base; using extension_base<T>::extension_base;
/** /**
* @brief Access to opcode field * @brief Access to opcode field
* @return return opcode field * @return return opcode field
*/ */
inline int32_t opcode() const override { inline std::uint32_t opcode() const override {
return static_cast<int32_t>(m_instr.range(31, 27)); return static_cast<std::uint32_t>(this->m_instr.range(31, 27));
} }
/** /**
* @brief Decodes opcode of instruction * @brief Decodes opcode of instruction
* @return opcode of instruction * @return opcode of instruction
*/ */
op_A_Codes decode() const; op_A_Codes decode() const {
switch (opcode()) {
case A_LR:
return OP_A_LR;
break;
case A_SC:
return OP_A_SC;
break;
case A_AMOSWAP:
return OP_A_AMOSWAP;
break;
case A_AMOADD:
return OP_A_AMOADD;
break;
case A_AMOXOR:
return OP_A_AMOXOR;
break;
case A_AMOAND:
return OP_A_AMOAND;
break;
case A_AMOOR:
return OP_A_AMOOR;
break;
case A_AMOMIN:
return OP_A_AMOMIN;
break;
case A_AMOMAX:
return OP_A_AMOMAX;
break;
case A_AMOMINU:
return OP_A_AMOMINU;
break;
case A_AMOMAXU:
return OP_A_AMOMAXU;
break;
[[unlikely]] default:
return OP_A_ERROR;
break;
inline void dump() const override {
std::cout << std::hex << "0x" << m_instr << std::dec << std::endl;
} }
bool Exec_A_LR(); return OP_A_ERROR;
}
bool Exec_A_SC(); inline void dump() const override {
std::cout << std::hex << "0x" << this->m_instr << std::dec << std::endl;
}
bool Exec_A_AMOSWAP() const; bool Exec_A_LR() {
std::uint32_t mem_addr = 0;
int rd, rs1, rs2;
std::uint32_t data;
bool Exec_A_AMOADD() const; rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
bool Exec_A_AMOXOR() const; if (rs2 != 0) {
std::cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << std::endl;
this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr);
bool Exec_A_AMOAND() const; return false;
}
bool Exec_A_AMOOR() const; mem_addr = this->regs->getValue(rs1);
data = this->mem_intf->readDataMem(mem_addr, 4);
this->perf->dataMemoryRead();
this->regs->setValue(rd, static_cast<int32_t>(data));
bool Exec_A_AMOMIN() const; TLB_reserve(mem_addr);
bool Exec_A_AMOMAX() const; this->logger->debug("{} ns. PC: 0x{:x}. A.LR.W: x{:d}(0x{:x}) -> x{:d}(0x{:x}) ",
sc_core::sc_time_stamp().value(),
this->regs->getPC(),
rs1, mem_addr, rd, data);
bool Exec_A_AMOMINU() const; return true;
}
bool Exec_A_AMOMAXU() const; bool Exec_A_SC() {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
bool process_instruction(Instruction &inst); rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
void TLB_reserve(std::uint32_t address); mem_addr = this->regs->getValue(rs1);
data = this->regs->getValue(rs2);
bool TLB_reserved(std::uint32_t address); if (TLB_reserved(mem_addr)) {
this->mem_intf->writeDataMem(mem_addr, data, 4);
this->perf->dataMemoryWrite();
this->regs->setValue(rd, 0); // SC writes 0 to rd on success
} else {
this->regs->setValue(rd, 1); // SC writes nonzero on failure
}
this->logger->debug("{} ns. PC: 0x{:x}. A.SC.W: (0x{:x}) <- x{:d}(0x{:x}) ",
sc_core::sc_time_stamp().value(),
this->regs->getPC(),
mem_addr, rs2, data);
return true;
}
bool Exec_A_AMOSWAP() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
std::uint32_t aux;
/* These instructions must be atomic */
rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
mem_addr = this->regs->getValue(rs1);
data = this->mem_intf->readDataMem(mem_addr, 4);
this->perf->dataMemoryRead();
this->regs->setValue(rd, static_cast<int32_t>(data));
// swap
aux = this->regs->getValue(rs2);
this->regs->setValue(rs2, static_cast<int32_t>(data));
this->mem_intf->writeDataMem(mem_addr, aux, 4);
this->perf->dataMemoryWrite();
this->logger->debug("{} ns. PC: 0x{:x}. A.AMOSWAP");
return true;
}
bool Exec_A_AMOADD() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
/* These instructions must be atomic */
rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
mem_addr = this->regs->getValue(rs1);
data = this->mem_intf->readDataMem(mem_addr, 4);
this->perf->dataMemoryRead();
this->regs->setValue(rd, static_cast<int32_t>(data));
// add
data = data + this->regs->getValue(rs2);
this->mem_intf->writeDataMem(mem_addr, data, 4);
this->perf->dataMemoryWrite();
this->logger->debug("{} ns. PC: 0x{:x}. A.AMOADD");
return true;
}
bool Exec_A_AMOXOR() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
/* These instructions must be atomic */
rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
mem_addr = this->regs->getValue(rs1);
data = this->mem_intf->readDataMem(mem_addr, 4);
this->perf->dataMemoryRead();
this->regs->setValue(rd, static_cast<int32_t>(data));
// add
data = data ^ this->regs->getValue(rs2);
this->mem_intf->writeDataMem(mem_addr, data, 4);
this->perf->dataMemoryWrite();
this->logger->debug("{} ns. PC: 0x{:x}. A.AMOXOR");
return true;
}
bool Exec_A_AMOAND() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
/* These instructions must be atomic */
rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
mem_addr = this->regs->getValue(rs1);
data = this->mem_intf->readDataMem(mem_addr, 4);
this->perf->dataMemoryRead();
this->regs->setValue(rd, static_cast<int32_t>(data));
// add
data = data & this->regs->getValue(rs2);
this->mem_intf->writeDataMem(mem_addr, data, 4);
this->perf->dataMemoryWrite();
this->logger->debug("{} ns. PC: 0x{:x}. A.AMOAND");
return true;
}
bool Exec_A_AMOOR() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
/* These instructions must be atomic */
rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
mem_addr = this->regs->getValue(rs1);
data = this->mem_intf->readDataMem(mem_addr, 4);
this->perf->dataMemoryRead();
this->regs->setValue(rd, static_cast<int32_t>(data));
// add
data = data | this->regs->getValue(rs2);
this->mem_intf->writeDataMem(mem_addr, data, 4);
this->perf->dataMemoryWrite();
this->logger->debug("{} ns. PC: 0x{:x}. A.AMOOR");
return true;
}
bool Exec_A_AMOMIN() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
std::uint32_t aux;
/* These instructions must be atomic */
rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
mem_addr = this->regs->getValue(rs1);
data = this->mem_intf->readDataMem(mem_addr, 4);
this->perf->dataMemoryRead();
this->regs->setValue(rd, static_cast<int32_t>(data));
// min
aux = this->regs->getValue(rs2);
if ((int32_t) data < (int32_t) aux) {
aux = data;
}
this->mem_intf->writeDataMem(mem_addr, aux, 4);
this->perf->dataMemoryWrite();
this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMIN");
return true;
}
bool Exec_A_AMOMAX() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
std::uint32_t aux;
/* These instructions must be atomic */
rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
mem_addr = this->regs->getValue(rs1);
data = this->mem_intf->readDataMem(mem_addr, 4);
this->perf->dataMemoryRead();
this->regs->setValue(rd, static_cast<int32_t>(data));
// >
aux = this->regs->getValue(rs2);
if ((int32_t) data > (int32_t) aux) {
aux = data;
}
this->mem_intf->writeDataMem(mem_addr, aux, 4);
this->perf->dataMemoryWrite();
this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMAX");
return true;
}
bool Exec_A_AMOMINU() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
std::uint32_t aux;
/* These instructions must be atomic */
rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
mem_addr = this->regs->getValue(rs1);
data = this->mem_intf->readDataMem(mem_addr, 4);
this->perf->dataMemoryRead();
this->regs->setValue(rd, static_cast<int32_t>(data));
// min
aux = this->regs->getValue(rs2);
if (data < aux) {
aux = data;
}
this->mem_intf->writeDataMem(mem_addr, aux, 4);
this->perf->dataMemoryWrite();
this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMINU");
return true;
}
bool Exec_A_AMOMAXU() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
std::uint32_t aux;
/* These instructions must be atomic */
rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
mem_addr = this->regs->getValue(rs1);
data = this->mem_intf->readDataMem(mem_addr, 4);
this->perf->dataMemoryRead();
this->regs->setValue(rd, static_cast<int32_t>(data));
// max
aux = this->regs->getValue(rs2);
if (data > aux) {
aux = data;
}
this->mem_intf->writeDataMem(mem_addr, aux, 4);
this->perf->dataMemoryWrite();
this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMAXU");
return true;
}
void TLB_reserve(std::uint32_t address) {
TLB_A_Entries.insert(address);
}
bool TLB_reserved(std::uint32_t address) {
if (TLB_A_Entries.count(address) == 1) {
TLB_A_Entries.erase(address);
return true;
} else {
return false;
}
}
bool process_instruction(Instruction &inst) {
bool PC_not_affected = true;
this->setInstr(inst.getInstr());
switch (decode()) {
case OP_A_LR:
Exec_A_LR();
break;
case OP_A_SC:
Exec_A_SC();
break;
case OP_A_AMOSWAP:
Exec_A_AMOSWAP();
break;
case OP_A_AMOADD:
Exec_A_AMOADD();
break;
case OP_A_AMOXOR:
Exec_A_AMOXOR();
break;
case OP_A_AMOAND:
Exec_A_AMOAND();
break;
case OP_A_AMOOR:
Exec_A_AMOOR();
break;
case OP_A_AMOMIN:
Exec_A_AMOMIN();
break;
case OP_A_AMOMAX:
Exec_A_AMOMAX();
break;
case OP_A_AMOMINU:
Exec_A_AMOMINU();
break;
case OP_A_AMOMAXU:
Exec_A_AMOMAXU();
break;
[[unlikely]] default:
std::cout << "A instruction not implemented yet" << std::endl;
inst.dump();
this->NOP();
break;
}
return PC_not_affected;
}
private: private:
std::unordered_set<std::uint32_t> TLB_A_Entries; std::unordered_set<std::uint32_t> TLB_A_Entries;

File diff suppressed because it is too large Load Diff

View File

@ -73,10 +73,10 @@ namespace riscv_tlm {
Registers<std::uint32_t> *register_bank; Registers<std::uint32_t> *register_bank;
Performance *perf; Performance *perf;
std::shared_ptr<spdlog::logger> logger; std::shared_ptr<spdlog::logger> logger;
C_extension *c_inst; C_extension<std::uint32_t> *c_inst;
M_extension *m_inst; M_extension<std::uint32_t> *m_inst;
A_extension *a_inst; A_extension<std::uint32_t> *a_inst;
BASE_ISA *exec; BASE_ISA<std::uint32_t> *exec;
tlm_utils::tlm_quantumkeeper *m_qk; tlm_utils::tlm_quantumkeeper *m_qk;
Instruction inst; Instruction inst;

File diff suppressed because it is too large Load Diff

View File

@ -43,41 +43,298 @@ namespace riscv_tlm {
/** /**
* @brief Instruction decoding and fields access * @brief Instruction decoding and fields access
*/ */
class M_extension : public extension_base<std::uint32_t> { template<typename T>
class M_extension : public extension_base<T> {
public: public:
/** /**
* @brief Constructor, same as base clase * @brief Constructor, same as base clase
*/ */
using extension_base::extension_base; using extension_base<T>::extension_base;
/** /**
* @brief Decodes opcode of instruction * @brief Decodes opcode of instruction
* @return opcode of instruction * @return opcode of instruction
*/ */
op_M_Codes decode() const; [[nodiscard]] op_M_Codes decode() const {
inline void dump() const override { switch (opcode()) {
std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; 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;
} }
bool Exec_M_MUL() const; return OP_M_ERROR;
}
bool Exec_M_MULH() const; inline void dump() const override {
std::cout << std::hex << "0x" << this->m_instr << std::dec << std::endl;
}
bool Exec_M_MULHSU() const; void Exec_M_MUL() const {
unsigned int rd, rs1, rs2;
std::int32_t multiplier, multiplicand;
std::int64_t result;
bool Exec_M_MULHU() const; rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
bool Exec_M_DIV() const; multiplier = static_cast<std::int32_t>(extension_base<T>::regs->getValue(rs1));
multiplicand = static_cast<std::int32_t>(extension_base<T>::regs->getValue(rs2));
bool Exec_M_DIVU() const; result = static_cast<std::int64_t>(multiplier * multiplicand);
result = result & 0x00000000FFFFFFFF;
this->regs->setValue(rd, static_cast<std::int32_t>(result));
bool Exec_M_REM() const; this->logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})",
sc_core::sc_time_stamp().value(),
extension_base<T>::regs->getPC(),
rs1, rs2, rd, result);
}
bool Exec_M_REMU() const; void Exec_M_MULH() const {
unsigned int rd, rs1, rs2;
std::int32_t multiplier, multiplicand;
std::int64_t result;
std::int32_t ret_value;
bool process_instruction(Instruction &inst); 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(),
this->regs->getPC(),
rs1, rs2, rd, result);
}
void 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);
}
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 {
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));
divisor = static_cast<std::int32_t>(this->regs->getValue(rs2));
if (divisor == 0) {
result = -1;
} else if ((divisor == -1) && (dividend == static_cast<std::int32_t>(0x80000000))) {
result = 0x0000000080000000;
} else {
result = dividend / divisor;
result = result & 0x00000000FFFFFFFF;
}
this->regs->setValue(rd, static_cast<std::int32_t>(result));
this->logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})",
sc_core::sc_time_stamp().value(),
this->regs->getPC(),
rs1, rs2, rd, result);
}
void Exec_M_DIVU() const {
unsigned int rd, rs1, rs2;
std::uint32_t divisor, dividend;
std::uint64_t result;
rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
dividend = this->regs->getValue(rs1);
divisor = this->regs->getValue(rs2);
if (divisor == 0) {
result = -1;
} else {
result = dividend / divisor;
result = result & 0x00000000FFFFFFFF;
}
this->regs->setValue(rd, static_cast<std::int32_t>(result));
this->logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})",
sc_core::sc_time_stamp().value(),
this->regs->getPC(),
rs1, rs2, rd, result);
}
void Exec_M_REM() const {
unsigned int rd, rs1, rs2;
std::int32_t divisor, dividend;
std::int32_t result;
rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
dividend = static_cast<std::int32_t>(this->regs->getValue(rs1));
divisor = static_cast<std::int32_t>(this->regs->getValue(rs2));
if (divisor == 0) {
result = dividend;
} else if ((divisor == -1) && (dividend == static_cast<std::int32_t>(0x80000000))) {
result = 0;
} else {
result = dividend % divisor;
}
this->regs->setValue(rd, result);
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);
}
void Exec_M_REMU() const {
unsigned int rd, rs1, rs2;
std::uint32_t divisor, dividend;
std::uint32_t result;
rd = this->get_rd();
rs1 = this->get_rs1();
rs2 = this->get_rs2();
dividend = static_cast<std::int32_t>(this->regs->getValue(rs1));
divisor = static_cast<std::int32_t>(this->regs->getValue(rs2));
if (divisor == 0) {
result = dividend;
} else {
result = dividend % divisor;
}
this->regs->setValue(rd, static_cast<std::int32_t>(result));
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);
}
bool process_instruction(Instruction &inst) {
this->setInstr(inst.getInstr());
switch (decode()) {
case OP_M_MUL:
Exec_M_MUL();
break;
case OP_M_MULH:
Exec_M_MULH();
break;
case OP_M_MULHSU:
Exec_M_MULHSU();
break;
case OP_M_MULHU:
Exec_M_MULHU();
break;
case OP_M_DIV:
Exec_M_DIV();
break;
case OP_M_DIVU:
Exec_M_DIVU();
break;
case OP_M_REM:
Exec_M_REM();
break;
case OP_M_REMU:
Exec_M_REMU();
break;
[[unlikely]] default:
std::cout << "M instruction not implemented yet" << "\n";
inst.dump();
//NOP(inst);
sc_core::sc_stop();
break;
}
return true;
}
private: private:
@ -85,8 +342,8 @@ namespace riscv_tlm {
* @brief Access to opcode field * @brief Access to opcode field
* @return return opcode field * @return return opcode field
*/ */
inline std::int32_t opcode() const override { [[nodiscard]] inline std::uint32_t opcode() const override {
return static_cast<std::int32_t>(m_instr.range(14, 12)); return static_cast<std::uint32_t>(this->m_instr.range(14, 12));
} }
}; };

View File

@ -10,6 +10,7 @@
#define REGISTERS_H #define REGISTERS_H
#define SC_INCLUDE_DYNAMIC_PROCESSES #define SC_INCLUDE_DYNAMIC_PROCESSES
#include <iomanip> #include <iomanip>
#include <unordered_map> #include <unordered_map>
@ -200,7 +201,7 @@ namespace riscv_tlm {
* @param reg_num register number * @param reg_num register number
* @param value register value * @param value register value
*/ */
void setValue(int reg_num, T value) { void setValue(unsigned int reg_num, T value) {
if ((reg_num != 0) && (reg_num < 32)) { if ((reg_num != 0) && (reg_num < 32)) {
register_bank[reg_num] = value; register_bank[reg_num] = value;
perf->registerWrite(); perf->registerWrite();
@ -212,13 +213,13 @@ namespace riscv_tlm {
* @param reg_num register number * @param reg_num register number
* @return register value * @return register value
*/ */
T getValue(int reg_num) const { T getValue(unsigned int reg_num) const {
if ((reg_num >= 0) && (reg_num < 32)) { if (reg_num < 32) {
perf->registerRead(); perf->registerRead();
return register_bank[reg_num]; return register_bank[reg_num];
} else { } else {
/* TODO Exten sign for any possible T type */ /* Extend sign for any possible T type */
return static_cast<T>(0xFFFFFFFF); return static_cast<T>(std::numeric_limits<T>::max());
} }
} }

View File

@ -68,7 +68,8 @@ namespace riscv_tlm {
regs->setPC(new_pc); regs->setPC(new_pc);
logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC(), logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(),
regs->getPC(),
new_pc); new_pc);
} }
@ -79,37 +80,37 @@ namespace riscv_tlm {
} }
/* pure virtual functions */ /* pure virtual functions */
virtual std::int32_t opcode() const = 0; virtual T opcode() const = 0;
virtual std::int32_t get_rd() const { virtual unsigned int get_rd() const {
return m_instr.range(11, 7); return m_instr.range(11, 7);
} }
virtual void set_rd(std::int32_t value) { virtual void set_rd(unsigned int value) {
m_instr.range(11, 7) = value; m_instr.range(11, 7) = value;
} }
virtual std::int32_t get_rs1() const { virtual unsigned int get_rs1() const {
return m_instr.range(19, 15); return m_instr.range(19, 15);
} }
virtual void set_rs1(std::int32_t value) { virtual void set_rs1(unsigned int value) {
m_instr.range(19, 15) = value; m_instr.range(19, 15) = value;
} }
virtual std::int32_t get_rs2() const { virtual unsigned int get_rs2() const {
return m_instr.range(24, 20); return m_instr.range(24, 20);
} }
virtual void set_rs2(std::int32_t value) { virtual void set_rs2(unsigned int value) {
m_instr.range(24, 20) = value; m_instr.range(24, 20) = value;
} }
virtual std::int32_t get_funct3() const { virtual unsigned int get_funct3() const {
return m_instr.range(14, 12); return m_instr.range(14, 12);
} }
virtual void set_funct3(std::int32_t value) { virtual void set_funct3(unsigned int value) {
m_instr.range(14, 12) = value; m_instr.range(14, 12) = value;
} }

View File

@ -7,439 +7,3 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
#include "A_extension.h" #include "A_extension.h"
namespace riscv_tlm {
op_A_Codes A_extension::decode() const {
switch (opcode()) {
case A_LR:
return OP_A_LR;
break;
case A_SC:
return OP_A_SC;
break;
case A_AMOSWAP:
return OP_A_AMOSWAP;
break;
case A_AMOADD:
return OP_A_AMOADD;
break;
case A_AMOXOR:
return OP_A_AMOXOR;
break;
case A_AMOAND:
return OP_A_AMOAND;
break;
case A_AMOOR:
return OP_A_AMOOR;
break;
case A_AMOMIN:
return OP_A_AMOMIN;
break;
case A_AMOMAX:
return OP_A_AMOMAX;
break;
case A_AMOMINU:
return OP_A_AMOMINU;
break;
case A_AMOMAXU:
return OP_A_AMOMAXU;
break;
[[unlikely]] default:
return OP_A_ERROR;
break;
}
return OP_A_ERROR;
}
bool A_extension::Exec_A_LR() {
std::uint32_t mem_addr = 0;
int rd, rs1, rs2;
std::uint32_t data;
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
if (rs2 != 0) {
std::cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << std::endl;
RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr);
return false;
}
mem_addr = regs->getValue(rs1);
data = mem_intf->readDataMem(mem_addr, 4);
perf->dataMemoryRead();
regs->setValue(rd, static_cast<int32_t>(data));
TLB_reserve(mem_addr);
logger->debug("{} ns. PC: 0x{:x}. A.LR.W: x{:d}(0x{:x}) -> x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, mem_addr, rd, data);
return true;
}
bool A_extension::Exec_A_SC() {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
mem_addr = regs->getValue(rs1);
data = regs->getValue(rs2);
if (TLB_reserved(mem_addr)) {
mem_intf->writeDataMem(mem_addr, data, 4);
perf->dataMemoryWrite();
regs->setValue(rd, 0); // SC writes 0 to rd on success
} else {
regs->setValue(rd, 1); // SC writes nonzero on failure
}
logger->debug("{} ns. PC: 0x{:x}. A.SC.W: (0x{:x}) <- x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(),
regs->getPC(),
mem_addr, rs2, data);
return true;
}
bool A_extension::Exec_A_AMOSWAP() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
std::uint32_t aux;
/* These instructions must be atomic */
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
mem_addr = regs->getValue(rs1);
data = mem_intf->readDataMem(mem_addr, 4);
perf->dataMemoryRead();
regs->setValue(rd, static_cast<int32_t>(data));
// swap
aux = regs->getValue(rs2);
regs->setValue(rs2, static_cast<int32_t>(data));
mem_intf->writeDataMem(mem_addr, aux, 4);
perf->dataMemoryWrite();
logger->debug("{} ns. PC: 0x{:x}. A.AMOSWAP");
return true;
}
bool A_extension::Exec_A_AMOADD() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
/* These instructions must be atomic */
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
mem_addr = regs->getValue(rs1);
data = mem_intf->readDataMem(mem_addr, 4);
perf->dataMemoryRead();
regs->setValue(rd, static_cast<int32_t>(data));
// add
data = data + regs->getValue(rs2);
mem_intf->writeDataMem(mem_addr, data, 4);
perf->dataMemoryWrite();
logger->debug("{} ns. PC: 0x{:x}. A.AMOADD");
return true;
}
bool A_extension::Exec_A_AMOXOR() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
/* These instructions must be atomic */
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
mem_addr = regs->getValue(rs1);
data = mem_intf->readDataMem(mem_addr, 4);
perf->dataMemoryRead();
regs->setValue(rd, static_cast<int32_t>(data));
// add
data = data ^ regs->getValue(rs2);
mem_intf->writeDataMem(mem_addr, data, 4);
perf->dataMemoryWrite();
logger->debug("{} ns. PC: 0x{:x}. A.AMOXOR");
return true;
}
bool A_extension::Exec_A_AMOAND() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
/* These instructions must be atomic */
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
mem_addr = regs->getValue(rs1);
data = mem_intf->readDataMem(mem_addr, 4);
perf->dataMemoryRead();
regs->setValue(rd, static_cast<int32_t>(data));
// add
data = data & regs->getValue(rs2);
mem_intf->writeDataMem(mem_addr, data, 4);
perf->dataMemoryWrite();
logger->debug("{} ns. PC: 0x{:x}. A.AMOAND");
return true;
}
bool A_extension::Exec_A_AMOOR() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
/* These instructions must be atomic */
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
mem_addr = regs->getValue(rs1);
data = mem_intf->readDataMem(mem_addr, 4);
perf->dataMemoryRead();
regs->setValue(rd, static_cast<int32_t>(data));
// add
data = data | regs->getValue(rs2);
mem_intf->writeDataMem(mem_addr, data, 4);
perf->dataMemoryWrite();
logger->debug("{} ns. PC: 0x{:x}. A.AMOOR");
return true;
}
bool A_extension::Exec_A_AMOMIN() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
std::uint32_t aux;
/* These instructions must be atomic */
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
mem_addr = regs->getValue(rs1);
data = mem_intf->readDataMem(mem_addr, 4);
perf->dataMemoryRead();
regs->setValue(rd, static_cast<int32_t>(data));
// min
aux = regs->getValue(rs2);
if ((int32_t) data < (int32_t) aux) {
aux = data;
}
mem_intf->writeDataMem(mem_addr, aux, 4);
perf->dataMemoryWrite();
logger->debug("{} ns. PC: 0x{:x}. A.AMOMIN");
return true;
}
bool A_extension::Exec_A_AMOMAX() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
std::uint32_t aux;
/* These instructions must be atomic */
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
mem_addr = regs->getValue(rs1);
data = mem_intf->readDataMem(mem_addr, 4);
perf->dataMemoryRead();
regs->setValue(rd, static_cast<int32_t>(data));
// >
aux = regs->getValue(rs2);
if ((int32_t) data > (int32_t) aux) {
aux = data;
}
mem_intf->writeDataMem(mem_addr, aux, 4);
perf->dataMemoryWrite();
logger->debug("{} ns. PC: 0x{:x}. A.AMOMAX");
return true;
}
bool A_extension::Exec_A_AMOMINU() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
std::uint32_t aux;
/* These instructions must be atomic */
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
mem_addr = regs->getValue(rs1);
data = mem_intf->readDataMem(mem_addr, 4);
perf->dataMemoryRead();
regs->setValue(rd, static_cast<int32_t>(data));
// min
aux = regs->getValue(rs2);
if (data < aux) {
aux = data;
}
mem_intf->writeDataMem(mem_addr, aux, 4);
perf->dataMemoryWrite();
logger->debug("{} ns. PC: 0x{:x}. A.AMOMINU");
return true;
}
bool A_extension::Exec_A_AMOMAXU() const {
std::uint32_t mem_addr;
int rd, rs1, rs2;
std::uint32_t data;
std::uint32_t aux;
/* These instructions must be atomic */
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
mem_addr = regs->getValue(rs1);
data = mem_intf->readDataMem(mem_addr, 4);
perf->dataMemoryRead();
regs->setValue(rd, static_cast<int32_t>(data));
// max
aux = regs->getValue(rs2);
if (data > aux) {
aux = data;
}
mem_intf->writeDataMem(mem_addr, aux, 4);
perf->dataMemoryWrite();
logger->debug("{} ns. PC: 0x{:x}. A.AMOMAXU");
return true;
}
void A_extension::TLB_reserve(std::uint32_t address) {
TLB_A_Entries.insert(address);
}
bool A_extension::TLB_reserved(std::uint32_t address) {
if (TLB_A_Entries.count(address) == 1) {
TLB_A_Entries.erase(address);
return true;
} else {
return false;
}
}
bool A_extension::process_instruction(Instruction &inst) {
bool PC_not_affected = true;
setInstr(inst.getInstr());
switch (decode()) {
case OP_A_LR:
Exec_A_LR();
break;
case OP_A_SC:
Exec_A_SC();
break;
case OP_A_AMOSWAP:
Exec_A_AMOSWAP();
break;
case OP_A_AMOADD:
Exec_A_AMOADD();
break;
case OP_A_AMOXOR:
Exec_A_AMOXOR();
break;
case OP_A_AMOAND:
Exec_A_AMOAND();
break;
case OP_A_AMOOR:
Exec_A_AMOOR();
break;
case OP_A_AMOMIN:
Exec_A_AMOMIN();
break;
case OP_A_AMOMAX:
Exec_A_AMOMAX();
break;
case OP_A_AMOMINU:
Exec_A_AMOMINU();
break;
case OP_A_AMOMAXU:
Exec_A_AMOMAXU();
break;
[[unlikely]] default:
std::cout << "A instruction not implemented yet" << std::endl;
inst.dump();
NOP();
break;
}
return PC_not_affected;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -12,8 +12,8 @@ namespace riscv_tlm {
SC_HAS_PROCESS(CPU); SC_HAS_PROCESS(CPU);
CPU::CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug) : CPU::CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug) :
sc_module(name), instr_bus("instr_bus"), inst(0), default_time(10, sc_module(name), instr_bus("instr_bus"), inst(0),
sc_core::SC_NS), INSTR(0) { default_time(10, sc_core::SC_NS), INSTR(0) {
register_bank = new Registers<std::uint32_t>(); register_bank = new Registers<std::uint32_t>();
mem_intf = new MemoryInterface(); mem_intf = new MemoryInterface();
@ -32,10 +32,10 @@ namespace riscv_tlm {
instr_bus.register_invalidate_direct_mem_ptr(this, instr_bus.register_invalidate_direct_mem_ptr(this,
&CPU::invalidate_direct_mem_ptr); &CPU::invalidate_direct_mem_ptr);
exec = new BASE_ISA(0, register_bank, mem_intf); exec = new BASE_ISA<std::uint32_t>(0, register_bank, mem_intf);
c_inst = new C_extension(0, register_bank, mem_intf); c_inst = new C_extension<std::uint32_t>(0, register_bank, mem_intf);
m_inst = new M_extension(0, register_bank, mem_intf); m_inst = new M_extension<std::uint32_t>(0, register_bank, mem_intf);
a_inst = new A_extension(0, register_bank, mem_intf); a_inst = new A_extension<std::uint32_t>(0, register_bank, mem_intf);
m_qk = new tlm_utils::tlm_quantumkeeper(); m_qk = new tlm_utils::tlm_quantumkeeper();
m_qk->reset(); m_qk->reset();

View File

@ -5,749 +5,3 @@
\date August 2018 \date August 2018
*/ */
#include "C_extension.h" #include "C_extension.h"
namespace riscv_tlm {
op_C_Codes C_extension::decode() const {
switch (opcode()) {
case 0b00:
switch (get_funct3()) {
case C_ADDI4SPN:
return OP_C_ADDI4SPN;
break;
case C_FLD:
return OP_C_FLD;
break;
case C_LW:
return OP_C_LW;
break;
case C_FLW:
return OP_C_FLW;
break;
case C_FSD:
return OP_C_FSD;
break;
case C_SW:
return OP_C_SW;
break;
case C_FSW:
return OP_C_FSW;
break;
[[unlikely]] default:
return OP_C_ERROR;
break;
}
break;
case 0b01:
switch (get_funct3()) {
case C_ADDI:
return OP_C_ADDI;
break;
case C_JAL:
return OP_C_JAL;
break;
case C_LI:
return OP_C_LI;
break;
case C_ADDI16SP:
return OP_C_ADDI16SP;
break;
case C_SRLI:
switch (m_instr.range(11, 10)) {
case C_2_SRLI:
return OP_C_SRLI;
break;
case C_2_SRAI:
return OP_C_SRAI;
break;
case C_2_ANDI:
return OP_C_ANDI;
break;
case C_2_SUB:
switch (m_instr.range(6, 5)) {
case C_3_SUB:
return OP_C_SUB;
break;
case C_3_XOR:
return OP_C_XOR;
break;
case C_3_OR:
return OP_C_OR;
break;
case C_3_AND:
return OP_C_AND;
break;
}
}
break;
case C_J:
return OP_C_J;
break;
case C_BEQZ:
return OP_C_BEQZ;
break;
case C_BNEZ:
return OP_C_BNEZ;
break;
[[unlikely]] default:
return OP_C_ERROR;
break;
}
break;
case 0b10:
switch (get_funct3()) {
case C_SLLI:
return OP_C_SLLI;
break;
case C_FLDSP:
case C_LWSP:
return OP_C_LWSP;
break;
case C_FLWSP:
return OP_C_FLWSP;
break;
case C_JR:
if (m_instr[12] == 0) {
if (m_instr.range(6, 2) == 0) {
return OP_C_JR;
} else {
return OP_C_MV;
}
} else {
if (m_instr.range(11, 2) == 0) {
return OP_C_EBREAK;
} else if (m_instr.range(6, 2) == 0) {
return OP_C_JALR;
} else {
return OP_C_ADD;
}
}
break;
case C_FDSP:
break;
case C_SWSP:
return OP_C_SWSP;
break;
case C_FWWSP:
[[unlikely]]
default:
return OP_C_ERROR;
break;
}
break;
[[unlikely]] default:
return OP_C_ERROR;
break;
}
return OP_C_ERROR;
}
bool C_extension::Exec_C_JR() {
std::uint32_t mem_addr;
int rs1;
int new_pc;
rs1 = get_rs1();
mem_addr = 0;
new_pc = static_cast<std::int32_t>(
static_cast<std::int32_t>((regs->getValue(rs1)) + static_cast<std::int32_t>(mem_addr)) & 0xFFFFFFFE);
logger->debug("{} ns. PC: 0x{:x}. C.JR: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), new_pc);
regs->setPC(new_pc);
return true;
}
bool C_extension::Exec_C_MV() {
int rd, rs1, rs2;
std::uint32_t calc;
rd = get_rd();
rs1 = 0;
rs2 = get_rs2();
calc = regs->getValue(rs1) + regs->getValue(rs2);
regs->setValue(rd, static_cast<std::int32_t>(calc));
logger->debug("{} ns. PC: 0x{:x}. C.MV: x{:d}(0x{:x}) + x{:d}(0x{:x}) -> x{:d}(0x{:x})",
sc_core::sc_time_stamp().value(), regs->getPC(),
rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), rd, calc);
return true;
}
bool C_extension::Exec_C_ADD() {
int rd, rs1, rs2;
std::uint32_t calc;
rd = get_rs1();
rs1 = get_rs1();
rs2 = get_rs2();
calc = regs->getValue(rs1) + regs->getValue(rs2);
regs->setValue(rd, static_cast<std::int32_t>(calc));
logger->debug("{} ns. PC: 0x{:x}. C.ADD: x{:d} + x{} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd, calc);
return true;
}
bool C_extension::Exec_C_LWSP() {
std::uint32_t mem_addr;
int rd, rs1;
std::int32_t imm;
std::uint32_t data;
// lw rd, offset[7:2](x2)
rd = get_rd();
rs1 = 2;
imm = get_imm_LWSP();
mem_addr = imm + regs->getValue(rs1);
data = mem_intf->readDataMem(mem_addr, 4);
perf->dataMemoryRead();
regs->setValue(rd, static_cast<std::int32_t>(data));
regs->setValue(rd, data);
logger->debug("{} ns. PC: 0x{:x}. C.LWSP: x{:d} + {:d}(@0x{:x}) -> x{:d}({:x})",
sc_core::sc_time_stamp().value(), regs->getPC(),
rs1, imm, mem_addr, rd, data);
return true;
}
bool C_extension::Exec_C_ADDI4SPN() {
int rd, rs1;
std::int32_t imm;
std::int32_t calc;
rd = get_rdp();
rs1 = 2;
imm = get_imm_ADDI4SPN();
if (imm == 0) {
RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr);
return false;
}
calc = static_cast<std::int32_t>(regs->getValue(rs1)) + imm;
regs->setValue(rd, calc);
logger->debug("{} ns. PC: 0x{:x}. C.ADDI4SN: x{:d} + (0x{:x}) + {:d} -> x{:d}(0x{:x})",
sc_core::sc_time_stamp().value(), regs->getPC(),
rs1, regs->getValue(rs1), imm, rd, calc);
return true;
}
bool C_extension::Exec_C_ADDI16SP() {
// addi x2, x2, nzimm[9:4]
int rd;
std::int32_t imm;
if (get_rd() == 2) {
int rs1;
std::int32_t calc;
rd = 2;
rs1 = 2;
imm = get_imm_ADDI16SP();
calc = static_cast<std::int32_t>(regs->getValue(rs1)) + imm;
regs->setValue(rd, calc);
logger->debug("{} ns. PC: 0x{:x}. C.ADDI16SP: x{:d} + {:d} -> x{:d} (0x{:x})",
sc_core::sc_time_stamp().value(), regs->getPC(),
rs1, imm, rd, calc);
} else {
/* C.LUI OPCODE */
rd = get_rd();
imm = get_imm_LUI();
regs->setValue(rd, imm);
logger->debug("{} ns. PC: 0x{:x}. C.LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(),
rd, imm);
}
return true;
}
bool C_extension::Exec_C_SWSP() {
// sw rs2, offset(x2)
std::uint32_t mem_addr;
int rs1, rs2;
std::int32_t imm;
std::uint32_t data;
rs1 = 2;
rs2 = get_rs2();
imm = get_imm_CSS();
mem_addr = imm + regs->getValue(rs1);
data = regs->getValue(rs2);
mem_intf->writeDataMem(mem_addr, data, 4);
perf->dataMemoryWrite();
logger->debug("{} ns. PC: 0x{:x}. C.SWSP: x{:d}(0x{:x}) -> x{:d} + {} (@0x{:x})",
sc_core::sc_time_stamp().value(), regs->getPC(),
rs2, data, rs1, imm, mem_addr);
return true;
}
bool C_extension::Exec_C_BEQZ() {
int rs1;
int new_pc;
std::uint32_t val1;
rs1 = get_rs1p();
val1 = regs->getValue(rs1);
if (val1 == 0) {
new_pc = static_cast<std::int32_t>(regs->getPC()) + get_imm_CB();
regs->setPC(new_pc);
} else {
regs->incPCby2();
new_pc = static_cast<std::int32_t>(regs->getPC());
}
logger->debug("{} ns. PC: 0x{:x}. C.BEQZ: x{:d}(0x{:x}) == 0? -> PC (0xx{:d})",
sc_core::sc_time_stamp().value(), regs->getPC(),
rs1, val1, new_pc);
return true;
}
bool C_extension::Exec_C_BNEZ() {
int rs1;
int new_pc;
std::uint32_t val1;
rs1 = get_rs1p();
val1 = regs->getValue(rs1);
if (val1 != 0) {
new_pc = static_cast<std::int32_t>(regs->getPC()) + get_imm_CB();
regs->setPC(new_pc);
} else {
regs->incPCby2(); //PC <- PC +2
new_pc = static_cast<std::int32_t>(regs->getPC());
}
logger->debug("{} ns. PC: 0x{:x}. C.BNEZ: x{:d}(0x{:x}) != 0? -> PC (0xx{:d})",
sc_core::sc_time_stamp().value(), regs->getPC(),
rs1, val1, new_pc);
return true;
}
bool C_extension::Exec_C_LI() {
int rd, rs1;
std::int32_t imm;
std::int32_t calc;
rd = get_rd();
rs1 = 0;
imm = get_imm_ADDI();
calc = static_cast<std::int32_t>(regs->getValue(rs1)) + imm;
regs->setValue(rd, calc);
logger->debug("{} ns. PC: 0x{:x}. C.LI: x{:d} ({:d}) + {:d} -> x{:d}(0x{:x}) ",
sc_core::sc_time_stamp().value(), regs->getPC(),
rs1, regs->getValue(rs1), imm, rd, calc);
return true;
}
bool C_extension::Exec_C_SRLI() {
int rd, rs1, rs2;
std::uint32_t shift;
std::uint32_t calc;
rd = get_rs1p();
rs1 = get_rs1p();
rs2 = get_rs2();
shift = rs2 & 0x1F;
calc = static_cast<std::uint32_t>(regs->getValue(rs1)) >> shift;
regs->setValue(rd, static_cast<std::int32_t>(calc));
logger->debug("{} ns. PC: 0x{:x}. C.SRLI: x{:d} >> {} -> x{:d}", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, shift, rd);
return true;
}
bool C_extension::Exec_C_SRAI() {
int rd, rs1, rs2;
std::uint32_t shift;
std::int32_t calc;
rd = get_rs1p();
rs1 = get_rs1p();
rs2 = get_rs2();
shift = rs2 & 0x1F;
calc = static_cast<std::int32_t>(regs->getValue(rs1)) >> shift;
regs->setValue(rd, calc);
logger->debug("{} ns. PC: 0x{:x}. C.SRAI: x{:d} >> {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, shift, rd, calc);
return true;
}
bool C_extension::Exec_C_SLLI() {
int rd, rs1, rs2;
std::uint32_t shift;
std::uint32_t calc;
rd = get_rs1p();
rs1 = get_rs1p();
rs2 = get_imm_ADDI();
shift = rs2 & 0x1F;
calc = static_cast<std::uint32_t>(regs->getValue(rs1)) << shift;
regs->setValue(rd, static_cast<std::int32_t>(calc));
logger->debug("{} ns. PC: 0x{:x}. C.SLLI: x{:d} << {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, shift, rd, calc);
return true;
}
bool C_extension::Exec_C_ANDI() {
int rd, rs1;
std::uint32_t imm;
std::uint32_t aux;
std::uint32_t calc;
rd = get_rs1p();
rs1 = get_rs1p();
imm = get_imm_ADDI();
aux = regs->getValue(rs1);
calc = aux & imm;
regs->setValue(rd, static_cast<std::int32_t>(calc));
logger->debug("{} ns. PC: 0x{:x}. C.ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, aux, imm, rd);
return true;
}
bool C_extension::Exec_C_SUB() {
int rd, rs1, rs2;
std::uint32_t calc;
rd = get_rs1p();
rs1 = get_rs1p();
rs2 = get_rs2p();
calc = regs->getValue(rs1) - regs->getValue(rs2);
regs->setValue(rd, static_cast<std::int32_t>(calc));
logger->debug("{} ns. PC: 0x{:x}. C.SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd, calc);
return true;
}
bool C_extension::Exec_C_XOR() {
int rd, rs1, rs2;
std::uint32_t calc;
rd = get_rs1p();
rs1 = get_rs1p();
rs2 = get_rs2p();
calc = regs->getValue(rs1) ^ regs->getValue(rs2);
regs->setValue(rd, static_cast<std::int32_t>(calc));
logger->debug("{} ns. PC: 0x{:x}. C.XOR: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd);
return true;
}
bool C_extension::Exec_C_OR() {
int rd, rs1, rs2;
std::uint32_t calc;
rd = get_rs1p();
rs1 = get_rs1p();
rs2 = get_rs2p();
calc = regs->getValue(rs1) | regs->getValue(rs2);
regs->setValue(rd, static_cast<std::int32_t>(calc));
logger->debug("{} ns. PC: 0x{:x}. C.OR: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd);
return true;
}
bool C_extension::Exec_C_AND() {
int rd, rs1, rs2;
std::uint32_t calc;
rd = get_rs1p();
rs1 = get_rs1p();
rs2 = get_rs2p();
calc = regs->getValue(rs1) & regs->getValue(rs2);
regs->setValue(rd, static_cast<std::int32_t>(calc));
logger->debug("{} ns. PC: 0x{:x}. C.AND: x{:d} AND x{:d} -> x{:d}", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd);
return true;
}
bool C_extension::Exec_C_ADDI() const {
int rd, rs1;
std::int32_t imm;
std::int32_t calc;
rd = get_rd();
rs1 = rd;
imm = get_imm_ADDI();
calc = static_cast<std::int32_t>(regs->getValue(rs1)) + imm;
regs->setValue(rd, calc);
logger->debug("{} ns. PC: 0x{:x}. C.ADDI: x{:d} + {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(),
regs->getPC(), rs1, imm, rd, calc);
return true;
}
bool C_extension::Exec_C_JALR() {
std::uint32_t mem_addr = 0;
int rd, rs1;
int new_pc, old_pc;
rd = 1;
rs1 = get_rs1();
old_pc = static_cast<std::int32_t>(regs->getPC());
regs->setValue(rd, old_pc + 2);
new_pc = static_cast<std::int32_t>((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE);
regs->setPC(new_pc);
logger->debug("{} ns. PC: 0x{:x}. C.JALR: x{:d} <- 0x{:x} PC <- 0xx{:x}", sc_core::sc_time_stamp().value(),
regs->getPC(),
rd, old_pc + 4, new_pc);
return true;
}
bool C_extension::Exec_C_LW() {
std::uint32_t mem_addr;
int rd, rs1;
std::int32_t imm;
std::uint32_t data;
rd = get_rdp();
rs1 = get_rs1p();
imm = get_imm_L();
mem_addr = imm + regs->getValue(rs1);
data = mem_intf->readDataMem(mem_addr, 4);
perf->dataMemoryRead();
regs->setValue(rd, static_cast<std::int32_t>(data));
logger->debug("{} ns. PC: 0x{:x}. C.LW: x{:d}(0x{:x}) + {:d} (@0x{:x}) -> {:d} (0x{:x})",
sc_core::sc_time_stamp().value(), regs->getPC(),
rs1, regs->getValue(rs1), imm, mem_addr, rd, data);
return true;
}
bool C_extension::Exec_C_SW() {
std::uint32_t mem_addr;
int rs1, rs2;
std::int32_t imm;
std::uint32_t data;
rs1 = get_rs1p();
rs2 = get_rs2p();
imm = get_imm_L();
mem_addr = imm + regs->getValue(rs1);
data = regs->getValue(rs2);
mem_intf->writeDataMem(mem_addr, data, 4);
perf->dataMemoryWrite();
logger->debug("{} ns. PC: 0x{:x}. C.SW: x{:d}(0x{:x}) -> x{:d} + 0x{:x}(@0x{:x})",
sc_core::sc_time_stamp().value(), regs->getPC(),
rs2, data, rs1, imm, mem_addr);
return true;
}
bool C_extension::Exec_C_JAL(int m_rd) {
std::int32_t mem_addr;
int rd;
int new_pc, old_pc;
rd = m_rd;
mem_addr = get_imm_J();
old_pc = static_cast<std::int32_t>(regs->getPC());
new_pc = old_pc + mem_addr;
regs->setPC(new_pc);
old_pc = old_pc + 2;
regs->setValue(rd, old_pc);
logger->debug("{} ns. PC: 0x{:x}. C.JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})",
sc_core::sc_time_stamp().value(), regs->getPC(),
rd, old_pc, mem_addr, new_pc);
return true;
}
bool C_extension::Exec_C_EBREAK() {
logger->debug("C.EBREAK");
std::cout << "\n" << "C.EBRAK Instruction called, dumping information"
<< "\n";
regs->dump();
std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n";
perf->dump();
sc_core::sc_stop();
return true;
}
bool C_extension::process_instruction(Instruction &inst, bool *breakpoint) {
bool PC_not_affected = true;
*breakpoint = false;
setInstr(inst.getInstr());
switch (decode()) {
case OP_C_ADDI4SPN:
PC_not_affected = Exec_C_ADDI4SPN();
break;
case OP_C_LW:
Exec_C_LW();
break;
case OP_C_SW:
Exec_C_SW();
break;
case OP_C_ADDI:
Exec_C_ADDI();
break;
case OP_C_JAL:
Exec_C_JAL(1);
PC_not_affected = false;
break;
case OP_C_J:
Exec_C_JAL(0);
PC_not_affected = false;
break;
case OP_C_LI:
Exec_C_LI();
break;
case OP_C_SLLI:
Exec_C_SLLI();
break;
case OP_C_LWSP:
Exec_C_LWSP();
break;
case OP_C_JR:
Exec_C_JR();
PC_not_affected = false;
break;
case OP_C_MV:
Exec_C_MV();
break;
case OP_C_JALR:
Exec_C_JALR();
PC_not_affected = false;
break;
case OP_C_ADD:
Exec_C_ADD();
break;
case OP_C_SWSP:
Exec_C_SWSP();
break;
case OP_C_ADDI16SP:
Exec_C_ADDI16SP();
break;
case OP_C_BEQZ:
Exec_C_BEQZ();
PC_not_affected = false;
break;
case OP_C_BNEZ:
Exec_C_BNEZ();
PC_not_affected = false;
break;
case OP_C_SRLI:
Exec_C_SRLI();
break;
case OP_C_SRAI:
Exec_C_SRAI();
break;
case OP_C_ANDI:
Exec_C_ANDI();
break;
case OP_C_SUB:
Exec_C_SUB();
break;
case OP_C_XOR:
Exec_C_XOR();
break;
case OP_C_OR:
Exec_C_OR();
break;
case OP_C_AND:
Exec_C_AND();
break;
case OP_C_EBREAK:
Exec_C_EBREAK();
std::cout << "C_EBREAK" << std::endl;
*breakpoint = true;
break;
[[unlikely]] default:
std::cout << "C instruction not implemented yet" << "\n";
inst.dump();
NOP();
break;
}
return PC_not_affected;
}
}

View File

@ -8,292 +8,3 @@
#include "M_extension.h" #include "M_extension.h"
namespace riscv_tlm {
op_M_Codes M_extension::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;
[[unlikely]] default:
return OP_M_ERROR;
break;
}
return OP_M_ERROR;
}
bool M_extension::Exec_M_MUL() const {
int rd, rs1, rs2;
std::int32_t multiplier, multiplicand;
std::int64_t result;
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
multiplier = static_cast<std::int32_t>(regs->getValue(rs1));
multiplicand = static_cast<std::int32_t>(regs->getValue(rs2));
result = static_cast<std::int64_t>(multiplier * multiplicand);
result = result & 0x00000000FFFFFFFF;
regs->setValue(rd, static_cast<std::int32_t>(result));
logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd, result);
return true;
}
bool M_extension::Exec_M_MULH() const {
int rd, rs1, rs2;
std::int32_t multiplier, multiplicand;
std::int64_t result;
std::int32_t ret_value;
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
multiplier = static_cast<std::int32_t>(regs->getValue(rs1));
multiplicand = static_cast<std::int32_t>(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);
regs->setValue(rd, ret_value);
logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd, result);
return true;
}
bool M_extension::Exec_M_MULHSU() const {
int rd, rs1, rs2;
std::int32_t multiplier;
std::uint32_t multiplicand;
std::int64_t result;
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
multiplier = static_cast<std::int32_t>(regs->getValue(rs1));
multiplicand = regs->getValue(rs2);
result = static_cast<std::int64_t>(multiplier * static_cast<std::uint64_t>(multiplicand));
result = (result >> 32) & 0x00000000FFFFFFFF;
regs->setValue(rd, static_cast<std::int32_t>(result));
logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd, result);
return true;
}
bool M_extension::Exec_M_MULHU() const {
int rd, rs1, rs2;
std::uint32_t multiplier, multiplicand;
std::uint64_t result;
std::int32_t ret_value;
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
multiplier = static_cast<std::int32_t>(regs->getValue(rs1));
multiplicand = static_cast<std::int32_t>(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);
regs->setValue(rd, ret_value);
logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd, result);
return true;
}
bool M_extension::Exec_M_DIV() const {
int rd, rs1, rs2;
std::int32_t divisor, dividend;
std::int64_t result;
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
dividend = static_cast<std::int32_t>(regs->getValue(rs1));
divisor = static_cast<std::int32_t>(regs->getValue(rs2));
if (divisor == 0) {
result = -1;
} else if ((divisor == -1) && (dividend == static_cast<std::int32_t>(0x80000000))) {
result = 0x0000000080000000;
} else {
result = dividend / divisor;
result = result & 0x00000000FFFFFFFF;
}
regs->setValue(rd, static_cast<std::int32_t>(result));
logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd, result);
return true;
}
bool M_extension::Exec_M_DIVU() const {
int rd, rs1, rs2;
std::uint32_t divisor, dividend;
std::uint64_t result;
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
dividend = regs->getValue(rs1);
divisor = regs->getValue(rs2);
if (divisor == 0) {
result = -1;
} else {
result = dividend / divisor;
result = result & 0x00000000FFFFFFFF;
}
regs->setValue(rd, static_cast<std::int32_t>(result));
logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd, result);
return true;
}
bool M_extension::Exec_M_REM() const {
int rd, rs1, rs2;
std::int32_t divisor, dividend;
std::int32_t result;
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
dividend = static_cast<std::int32_t>(regs->getValue(rs1));
divisor = static_cast<std::int32_t>(regs->getValue(rs2));
if (divisor == 0) {
result = dividend;
} else if ((divisor == -1) && (dividend == static_cast<std::int32_t>(0x80000000))) {
result = 0;
} else {
result = dividend % divisor;
}
regs->setValue(rd, result);
logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd, result);
return true;
}
bool M_extension::Exec_M_REMU() const {
int rd, rs1, rs2;
std::uint32_t divisor, dividend;
std::uint32_t result;
rd = get_rd();
rs1 = get_rs1();
rs2 = get_rs2();
dividend = static_cast<std::int32_t>(regs->getValue(rs1));
divisor = static_cast<std::int32_t>(regs->getValue(rs2));
if (divisor == 0) {
result = dividend;
} else {
result = dividend % divisor;
}
regs->setValue(rd, static_cast<std::int32_t>(result));
logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(),
regs->getPC(),
rs1, rs2, rd, result);
return true;
}
bool M_extension::process_instruction(Instruction &inst) {
bool PC_not_affected = true;
setInstr(inst.getInstr());
switch (decode()) {
case OP_M_MUL:
Exec_M_MUL();
break;
case OP_M_MULH:
Exec_M_MULH();
break;
case OP_M_MULHSU:
Exec_M_MULHSU();
break;
case OP_M_MULHU:
Exec_M_MULHU();
break;
case OP_M_DIV:
Exec_M_DIV();
break;
case OP_M_DIVU:
Exec_M_DIVU();
break;
case OP_M_REM:
Exec_M_REM();
break;
case OP_M_REMU:
Exec_M_REMU();
break;
[[unlikely]] default:
std::cout << "M instruction not implemented yet" << "\n";
inst.dump();
//NOP(inst);
sc_core::sc_stop();
break;
}
return PC_not_affected;
}
}