risc-v-tlm/inc/extension_base.h

139 lines
3.8 KiB
C
Raw Normal View History

/*!
\file extension_base.h
\brief Base class for ISA extensions
\author Màrius Montón
\date May 2020
*/
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef INC_EXTENSION_BASE_H_
#define INC_EXTENSION_BASE_H_
#include "systemc"
#include "Instruction.h"
#include "Registers.h"
#include "MemoryInterface.h"
2021-11-25 19:11:18 +08:00
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
#define EXCEPTION_CAUSE_INSTRUCTION_MISALIGN 0
#define EXCEPTION_CAUSE_INSTRUCTION_ACCESS 1
#define EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION 2
#define EXCEPTION_CAUSE_BREAKPOINT 3
2021-11-08 16:24:43 +08:00
#define EXCEPTION_CAUSE_BREAK 3
#define EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN 4
#define EXCEPTION_CAUSE_LOAD_ACCESS_FAULT 5
2021-11-30 03:35:26 +08:00
namespace riscv_tlm {
template<typename T>
2021-11-30 03:35:26 +08:00
class extension_base {
using signed_T = typename std::make_signed<T>::type;
using unsigned_T = typename std::make_unsigned<T>::type;
2021-11-30 03:35:26 +08:00
public:
extension_base(const T &instr, Registers<T> *register_bank,
MemoryInterface *mem_interface) :
m_instr(instr), regs(register_bank), mem_intf(mem_interface) {
perf = Performance::getInstance();
logger = spdlog::get("my_logger");
}
virtual ~extension_base() = default;
void setInstr(std::uint32_t p_instr) {
m_instr = sc_dt::sc_uint<32>(p_instr);
}
void RaiseException(std::uint32_t cause, std::uint32_t inst) {
std::uint32_t new_pc, current_pc, m_cause;
current_pc = regs->getPC();
m_cause = regs->getCSR(CSR_MSTATUS);
m_cause |= cause;
new_pc = regs->getCSR(CSR_MTVEC);
2021-02-01 19:24:25 +08:00
regs->setCSR(CSR_MEPC, current_pc);
2021-02-01 19:24:25 +08:00
if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) {
regs->setCSR(CSR_MTVAL, inst);
} else {
regs->setCSR(CSR_MTVAL, current_pc);
}
2021-02-01 19:24:25 +08:00
regs->setCSR(CSR_MCAUSE, cause);
regs->setCSR(CSR_MSTATUS, m_cause);
regs->setPC(new_pc);
logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(),
regs->getPC(),
new_pc);
}
bool NOP() {
logger->debug("{} ns. PC: 0x{:x}. NOP! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC());
logger->flush();
sc_core::sc_stop();
return true;
}
2021-02-01 19:24:25 +08:00
2021-11-30 03:35:26 +08:00
/* pure virtual functions */
virtual unsigned_T opcode() const = 0;
2021-02-01 19:24:25 +08:00
virtual unsigned int get_rd() const {
2021-11-30 03:35:26 +08:00
return m_instr.range(11, 7);
}
2021-02-01 19:24:25 +08:00
virtual void set_rd(unsigned int value) {
2021-11-30 03:35:26 +08:00
m_instr.range(11, 7) = value;
}
2021-02-01 19:24:25 +08:00
virtual unsigned int get_rs1() const {
2021-11-30 03:35:26 +08:00
return m_instr.range(19, 15);
}
2021-02-01 19:24:25 +08:00
virtual void set_rs1(unsigned int value) {
2021-11-30 03:35:26 +08:00
m_instr.range(19, 15) = value;
}
virtual unsigned int get_rs2() const {
2021-11-30 03:35:26 +08:00
return m_instr.range(24, 20);
}
virtual void set_rs2(unsigned int value) {
2021-11-30 03:35:26 +08:00
m_instr.range(24, 20) = value;
}
virtual unsigned int get_funct3() const {
2021-11-30 03:35:26 +08:00
return m_instr.range(14, 12);
}
virtual void set_funct3(unsigned int value) {
2021-11-30 03:35:26 +08:00
m_instr.range(14, 12) = value;
}
// For RV64 SLLI, SRLI & SRAI
virtual unsigned int get_shamt_slli() const {
return m_instr.range(25, 20);
}
virtual void dump() const {
std::cout << std::hex << "0x" << m_instr << std::dec << std::endl;
}
2021-11-30 03:35:26 +08:00
protected:
sc_dt::sc_uint<32> m_instr;
Registers<T> *regs;
2021-11-30 03:35:26 +08:00
Performance *perf;
MemoryInterface *mem_intf;
std::shared_ptr<spdlog::logger> logger;
};
}
#endif /* INC_EXTENSION_BASE_H_ */