Added namespace to project

This commit is contained in:
mariusmonton 2021-11-29 20:35:26 +01:00
parent e2981d8a50
commit fb84f197bf
28 changed files with 4895 additions and 4632 deletions

View File

@ -17,84 +17,98 @@
#include "MemoryInterface.h" #include "MemoryInterface.h"
#include "extension_base.h" #include "extension_base.h"
typedef enum { namespace riscv_tlm {
OP_A_LR,
OP_A_SC,
OP_A_AMOSWAP,
OP_A_AMOADD,
OP_A_AMOXOR,
OP_A_AMOAND,
OP_A_AMOOR,
OP_A_AMOMIN,
OP_A_AMOMAX,
OP_A_AMOMINU,
OP_A_AMOMAXU,
OP_A_ERROR typedef enum {
} op_A_Codes; OP_A_LR,
OP_A_SC,
OP_A_AMOSWAP,
OP_A_AMOADD,
OP_A_AMOXOR,
OP_A_AMOAND,
OP_A_AMOOR,
OP_A_AMOMIN,
OP_A_AMOMAX,
OP_A_AMOMINU,
OP_A_AMOMAXU,
typedef enum { OP_A_ERROR
A_LR = 0b00010, } op_A_Codes;
A_SC = 0b00011,
A_AMOSWAP = 0b00001, typedef enum {
A_AMOADD = 0b00000, A_LR = 0b00010,
A_AMOXOR = 0b00100, A_SC = 0b00011,
A_AMOAND = 0b01100, A_AMOSWAP = 0b00001,
A_AMOOR = 0b01000, A_AMOADD = 0b00000,
A_AMOMIN = 0b10000, A_AMOXOR = 0b00100,
A_AMOMAX = 0b10100, A_AMOAND = 0b01100,
A_AMOMINU = 0b11000, A_AMOOR = 0b01000,
A_AMOMAXU = 0b11100, A_AMOMIN = 0b10000,
} A_Codes; A_AMOMAX = 0b10100,
A_AMOMINU = 0b11000,
A_AMOMAXU = 0b11100,
} A_Codes;
/** /**
* @brief Instruction decoding and fields access * @brief Instruction decoding and fields access
*/ */
class A_extension: public extension_base { class A_extension : public extension_base {
public: public:
/** /**
* @brief Constructor, same as base class * @brief Constructor, same as base class
*/ */
using extension_base::extension_base; using extension_base::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 int32_t opcode() const override {
return static_cast<int32_t>(m_instr.range(31, 27)); return static_cast<int32_t>(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;
inline void dump() const override { inline void dump() const override {
std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; std::cout << std::hex << "0x" << m_instr << std::dec << std::endl;
} }
bool Exec_A_LR(); bool Exec_A_LR();
bool Exec_A_SC();
bool Exec_A_AMOSWAP() const;
bool Exec_A_AMOADD() const;
bool Exec_A_AMOXOR() const;
bool Exec_A_AMOAND() const;
bool Exec_A_AMOOR() const;
bool Exec_A_AMOMIN() const;
bool Exec_A_AMOMAX() const;
bool Exec_A_AMOMINU() const;
bool Exec_A_AMOMAXU() const;
bool process_instruction(Instruction &inst); bool Exec_A_SC();
void TLB_reserve(std::uint32_t address); bool Exec_A_AMOSWAP() const;
bool TLB_reserved(std::uint32_t address);
private: bool Exec_A_AMOADD() const;
std::unordered_set<std::uint32_t> TLB_A_Entries;
}; bool Exec_A_AMOXOR() const;
bool Exec_A_AMOAND() const;
bool Exec_A_AMOOR() const;
bool Exec_A_AMOMIN() const;
bool Exec_A_AMOMAX() const;
bool Exec_A_AMOMINU() const;
bool Exec_A_AMOMAXU() const;
bool process_instruction(Instruction &inst);
void TLB_reserve(std::uint32_t address);
bool TLB_reserved(std::uint32_t address);
private:
std::unordered_set<std::uint32_t> TLB_A_Entries;
};
}
#endif #endif

View File

@ -23,324 +23,367 @@
#include "A_extension.h" #include "A_extension.h"
#include "Registers.h" #include "Registers.h"
typedef enum { namespace riscv_tlm {
OP_LUI,
OP_AUIPC,
OP_JAL,
OP_JALR,
OP_BEQ, typedef enum {
OP_BNE, OP_LUI,
OP_BLT, OP_AUIPC,
OP_BGE, OP_JAL,
OP_BLTU, OP_JALR,
OP_BGEU,
OP_LB, OP_BEQ,
OP_LH, OP_BNE,
OP_LW, OP_BLT,
OP_LBU, OP_BGE,
OP_LHU, OP_BLTU,
OP_BGEU,
OP_SB, OP_LB,
OP_SH, OP_LH,
OP_SW, OP_LW,
OP_LBU,
OP_LHU,
OP_ADDI, OP_SB,
OP_SLTI, OP_SH,
OP_SLTIU, OP_SW,
OP_XORI,
OP_ORI,
OP_ANDI,
OP_SLLI,
OP_SRLI,
OP_SRAI,
OP_ADD, OP_ADDI,
OP_SUB, OP_SLTI,
OP_SLL, OP_SLTIU,
OP_SLT, OP_XORI,
OP_SLTU, OP_ORI,
OP_XOR, OP_ANDI,
OP_SRL, OP_SLLI,
OP_SRA, OP_SRLI,
OP_OR, OP_SRAI,
OP_AND,
OP_FENCE, OP_ADD,
OP_ECALL, OP_SUB,
OP_EBREAK, OP_SLL,
OP_SLT,
OP_SLTU,
OP_XOR,
OP_SRL,
OP_SRA,
OP_OR,
OP_AND,
OP_CSRRW, OP_FENCE,
OP_CSRRS, OP_ECALL,
OP_CSRRC, OP_EBREAK,
OP_CSRRWI,
OP_CSRRSI,
OP_CSRRCI,
OP_URET, OP_CSRRW,
OP_SRET, OP_CSRRS,
OP_MRET, OP_CSRRC,
OP_WFI, OP_CSRRWI,
OP_SFENCE, OP_CSRRSI,
OP_CSRRCI,
OP_ERROR OP_URET,
} opCodes; OP_SRET,
OP_MRET,
OP_WFI,
OP_SFENCE,
OP_ERROR
} opCodes;
/** /**
* @brief Risc_V execute module * @brief Risc_V execute module
*/ */
class BASE_ISA: public extension_base { class BASE_ISA : public extension_base {
public: public:
/** /**
* @brief Constructor, same as base class * @brief Constructor, same as base class
*/ */
using extension_base::extension_base; using extension_base::extension_base;
/** /**
* @brief Access to funct7 field * @brief Access to funct7 field
* @return funct7 field * @return funct7 field
*/ */
inline std::int32_t get_funct7() const { inline std::int32_t get_funct7() const {
return m_instr.range(31, 25); return m_instr.range(31, 25);
} }
/** /**
* @brief Sets func7 field * @brief Sets func7 field
* @param value desired func7 value * @param value desired func7 value
*/ */
inline void set_func7(std::int32_t value) { inline void set_func7(std::int32_t value) {
m_instr.range(31, 25) = value; m_instr.range(31, 25) = value;
} }
/** /**
* @brief Gets immediate field value for I-type * @brief Gets immediate field value for I-type
* @return immediate_I field * @return immediate_I field
*/ */
inline std::int32_t get_imm_I() const { inline std::int32_t get_imm_I() const {
std::int32_t aux = 0; std::uint32_t aux = 0;
aux = m_instr.range(31, 20); aux = m_instr.range(31, 20);
/* sign extension (optimize) */ /* sign extension (optimize) */
if (m_instr[31] == 1) { if (m_instr[31] == 1) {
aux |= (0b11111111111111111111) << 12; aux |= (0b11111111111111111111) << 12;
} }
return aux; return static_cast<std::int32_t>(aux);
} }
/** /**
* @brief Sets immediate field for I-type * @brief Sets immediate field for I-type
* @param value desired I value * @param value desired I value
*/ */
inline void set_imm_I(std::int32_t value) { inline void set_imm_I(std::int32_t value) {
m_instr.range(31, 20) = value; m_instr.range(31, 20) = value;
} }
/** /**
* @brief Gets immediate field value for S-type * @brief Gets immediate field value for S-type
* @return immediate_S field * @return immediate_S field
*/ */
inline std::int32_t get_imm_S() const { inline std::int32_t get_imm_S() const {
std::int32_t aux = 0; std::uint32_t aux = 0;
aux = m_instr.range(31, 25) << 5; aux = m_instr.range(31, 25) << 5;
aux |= m_instr.range(11, 7); aux |= m_instr.range(11, 7);
if (m_instr[31] == 1) { if (m_instr[31] == 1) {
aux |= (0b11111111111111111111) << 12; aux |= (0b11111111111111111111) << 12;
} }
return aux; return static_cast<std::int32_t>(aux);
} }
/** /**
* @brief Gets immediate field value for U-type * @brief Gets immediate field value for U-type
* @return immediate_U field * @return immediate_U field
*/ */
inline std::int32_t get_imm_U() const { inline std::int32_t get_imm_U() const {
return m_instr.range(31, 12); return static_cast<std::int32_t>(m_instr.range(31, 12));
} }
/** /**
* @brief Sets immediate field for U-type * @brief Sets immediate field for U-type
* @param value desired U value * @param value desired U value
*/ */
inline void set_imm_U(std::int32_t value) { inline void set_imm_U(std::int32_t value) {
m_instr.range(31, 12) = (value << 12); m_instr.range(31, 12) = (value << 12);
} }
/** /**
* @brief Gets immediate field value for B-type * @brief Gets immediate field value for B-type
* @return immediate_B field * @return immediate_B field
*/ */
inline std::int32_t get_imm_B() const { inline std::int32_t get_imm_B() const {
std::int32_t aux = 0; std::int32_t aux = 0;
aux |= m_instr[7] << 11; aux |= m_instr[7] << 11;
aux |= m_instr.range(30, 25) << 5; aux |= m_instr.range(30, 25) << 5;
aux |= m_instr[31] << 12; aux |= m_instr[31] << 12;
aux |= m_instr.range(11, 8) << 1; aux |= m_instr.range(11, 8) << 1;
if (m_instr[31] == 1) { if (m_instr[31] == 1) {
aux |= (0b11111111111111111111) << 12; aux |= (0b11111111111111111111) << 12;
} }
return aux; return aux;
} }
/** /**
* @brief Sets immediate field for B-type * @brief Sets immediate field for B-type
* @param value desired B value * @param value desired B value
*/ */
inline void set_imm_B(std::int32_t value) { inline void set_imm_B(std::int32_t value) {
sc_dt::sc_uint<32> aux = value; sc_dt::sc_uint<32> aux = value;
m_instr[31] = aux[12]; m_instr[31] = aux[12];
m_instr.range(30, 25) = aux.range(10, 5); m_instr.range(30, 25) = aux.range(10, 5);
m_instr.range(11, 7) = aux.range(4, 1); m_instr.range(11, 7) = aux.range(4, 1);
m_instr[6] = aux[11]; m_instr[6] = aux[11];
} }
/** /**
* @brief Gets immediate field value for J-type * @brief Gets immediate field value for J-type
* @return immediate_J field * @return immediate_J field
*/ */
inline std::int32_t get_imm_J() const { inline std::int32_t get_imm_J() const {
std::int32_t aux = 0; std::int32_t aux = 0;
aux = m_instr[31] << 20; aux = m_instr[31] << 20;
aux |= m_instr.range(19, 12) << 12; aux |= m_instr.range(19, 12) << 12;
aux |= m_instr[20] << 11; aux |= m_instr[20] << 11;
aux |= m_instr.range(30, 21) << 1; aux |= m_instr.range(30, 21) << 1;
/* bit extension (better way to do that?) */ /* bit extension (better way to do that?) */
if (m_instr[31] == 1) { if (m_instr[31] == 1) {
aux |= (0b111111111111) << 20; aux |= (0b111111111111) << 20;
} }
return aux; return aux;
} }
/** /**
* @brief Sets immediate field for J-type * @brief Sets immediate field for J-type
* @param value desired J value * @param value desired J value
*/ */
inline void set_imm_J(std::int32_t value) { inline void set_imm_J(std::int32_t value) {
sc_dt::sc_uint<32> aux = (value << 20); sc_dt::sc_uint<32> aux = (value << 20);
m_instr[31] = aux[20]; m_instr[31] = aux[20];
m_instr.range(30, 21) = aux.range(10, 1); m_instr.range(30, 21) = aux.range(10, 1);
m_instr[20] = aux[11]; m_instr[20] = aux[11];
m_instr.range(19, 12) = aux.range(19, 12); m_instr.range(19, 12) = aux.range(19, 12);
} }
/** /**
* @brief Returns shamt field for Shifts instructions * @brief Returns shamt field for Shifts instructions
* @return value corresponding to inst(25:20) * @return value corresponding to inst(25:20)
*/ */
inline std::int32_t get_shamt() const { inline std::int32_t get_shamt() const {
return static_cast<std::int32_t>(m_instr.range(25, 20)); return static_cast<std::int32_t>(m_instr.range(25, 20));
} }
/** /**
* @brief Returns CSR field for CSR instructions * @brief Returns CSR field for CSR instructions
* @return value corresponding to instr(31:20) * @return value corresponding to instr(31:20)
*/ */
inline std::int32_t get_csr() const { inline std::int32_t get_csr() const {
std::int32_t aux = 0; std::int32_t aux = 0;
aux = static_cast<std::int32_t>(m_instr.range(31, 20)); aux = static_cast<std::int32_t>(m_instr.range(31, 20));
return aux; return aux;
} }
/** /**
* @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 { inline std::int32_t opcode() const override {
return static_cast<std::int32_t>(m_instr.range(6, 0)); return static_cast<std::int32_t>(m_instr.range(6, 0));
} }
bool Exec_LUI() const; bool Exec_LUI() const;
bool Exec_AUIPC() const;
bool Exec_JAL() const; bool Exec_AUIPC() const;
bool Exec_JALR();
bool Exec_BEQ() const; bool Exec_JAL() const;
bool Exec_BNE() const;
bool Exec_BLT() const;
bool Exec_BGE() const;
bool Exec_BLTU() const;
bool Exec_BGEU() const;
bool Exec_LB() const; bool Exec_JALR();
bool Exec_LH() const;
bool Exec_LW() const;
bool Exec_LBU() const;
bool Exec_LHU() const;
bool Exec_SB() const; bool Exec_BEQ() const;
bool Exec_SH() const;
bool Exec_SW() const;
bool Exec_SBU() const;
bool Exec_SHU() const;
bool Exec_ADDI() const; bool Exec_BNE() const;
bool Exec_SLTI() const;
bool Exec_SLTIU() const;
bool Exec_XORI() const;
bool Exec_ORI() const;
bool Exec_ANDI() const;
bool Exec_SLLI();
bool Exec_SRLI() const;
bool Exec_SRAI() const;
bool Exec_ADD() const; bool Exec_BLT() const;
bool Exec_SUB() const;
bool Exec_SLL() const;
bool Exec_SLT() const;
bool Exec_SLTU() const;
bool Exec_XOR() const; bool Exec_BGE() const;
bool Exec_SRL() const;
bool Exec_SRA() const;
bool Exec_OR() const;
bool Exec_AND() const;
bool Exec_FENCE() const; bool Exec_BLTU() const;
bool Exec_ECALL();
bool Exec_EBREAK();
bool Exec_CSRRW() const; bool Exec_BGEU() const;
bool Exec_CSRRS() const;
bool Exec_CSRRC() const;
bool Exec_CSRRWI() const;
bool Exec_CSRRSI() const;
bool Exec_CSRRCI() const;
/*********************** Privileged Instructions ******************************/ bool Exec_LB() const;
bool Exec_MRET() const;
bool Exec_SRET() const;
bool Exec_WFI() const;
bool Exec_SFENCE() const;
/** bool Exec_LH() const;
* @brief Executes default ISA instruction
* @param inst instruction to execute
* @return true if PC is affected by instruction
*/
bool process_instruction(Instruction &inst, bool *breakpoint = nullptr);
/** bool Exec_LW() const;
* @brief Decodes opcode of instruction
* @return opcode of instruction
*/
opCodes decode();
};
bool Exec_LBU() const;
bool Exec_LHU() const;
bool Exec_SB() const;
bool Exec_SH() const;
bool Exec_SW() const;
bool Exec_SBU() const;
bool Exec_SHU() const;
bool Exec_ADDI() const;
bool Exec_SLTI() const;
bool Exec_SLTIU() const;
bool Exec_XORI() const;
bool Exec_ORI() const;
bool Exec_ANDI() const;
bool Exec_SLLI();
bool Exec_SRLI() const;
bool Exec_SRAI() const;
bool Exec_ADD() const;
bool Exec_SUB() const;
bool Exec_SLL() const;
bool Exec_SLT() const;
bool Exec_SLTU() const;
bool Exec_XOR() const;
bool Exec_SRL() const;
bool Exec_SRA() const;
bool Exec_OR() const;
bool Exec_AND() const;
bool Exec_FENCE() const;
bool Exec_ECALL();
bool Exec_EBREAK();
bool Exec_CSRRW() const;
bool Exec_CSRRS() const;
bool Exec_CSRRC() const;
bool Exec_CSRRWI() const;
bool Exec_CSRRSI() const;
bool Exec_CSRRCI() const;
/*********************** Privileged Instructions ******************************/
bool Exec_MRET() const;
bool Exec_SRET() const;
bool Exec_WFI() const;
bool Exec_SFENCE() const;
/**
* @brief Executes default ISA instruction
* @param inst instruction to execute
* @return true if PC is affected by instruction
*/
bool process_instruction(Instruction &inst, bool *breakpoint = nullptr);
/**
* @brief Decodes opcode of instruction
* @return opcode of instruction
*/
opCodes decode();
};
}
#endif #endif

View File

@ -20,6 +20,8 @@
#include "tlm_utils/simple_initiator_socket.h" #include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h" #include "tlm_utils/simple_target_socket.h"
namespace riscv_tlm {
/** /**
* Memory mapped Trace peripheral address * Memory mapped Trace peripheral address
*/ */
@ -41,51 +43,52 @@
* It will be expanded with more ports when required (for DMA, * It will be expanded with more ports when required (for DMA,
* other peripherals, etc.) * other peripherals, etc.)
*/ */
class BusCtrl: sc_core::sc_module { class BusCtrl : sc_core::sc_module {
public: public:
/** /**
* @brief TLM target socket CPU instruction memory bus * @brief TLM target socket CPU instruction memory bus
*/ */
tlm_utils::simple_target_socket<BusCtrl> cpu_instr_socket; tlm_utils::simple_target_socket<BusCtrl> cpu_instr_socket;
/** /**
* @brief TLM target socket CPU data memory bus * @brief TLM target socket CPU data memory bus
*/ */
tlm_utils::simple_target_socket<BusCtrl> cpu_data_socket; tlm_utils::simple_target_socket<BusCtrl> cpu_data_socket;
/** /**
* @brief TLM initiator socket Main memory bus * @brief TLM initiator socket Main memory bus
*/ */
tlm_utils::simple_initiator_socket<BusCtrl> memory_socket; tlm_utils::simple_initiator_socket<BusCtrl> memory_socket;
/** /**
* @brief TLM initiator socket Trace module * @brief TLM initiator socket Trace module
*/ */
tlm_utils::simple_initiator_socket<BusCtrl> trace_socket; tlm_utils::simple_initiator_socket<BusCtrl> trace_socket;
/** /**
* @brief TLM initiator socket Trace module * @brief TLM initiator socket Trace module
*/ */
tlm_utils::simple_initiator_socket<BusCtrl> timer_socket; tlm_utils::simple_initiator_socket<BusCtrl> timer_socket;
/** /**
* @brief constructor * @brief constructor
* @param name module's name * @param name module's name
*/ */
explicit BusCtrl(sc_core::sc_module_name const &name); explicit BusCtrl(sc_core::sc_module_name const &name);
/** /**
* @brief TLM-2 blocking mechanism * @brief TLM-2 blocking mechanism
* @param trans transtractino to perform * @param trans transtractino to perform
* @param delay delay associated to this transaction * @param delay delay associated to this transaction
*/ */
virtual void b_transport(tlm::tlm_generic_payload &trans, virtual void b_transport(tlm::tlm_generic_payload &trans,
sc_core::sc_time &delay); sc_core::sc_time &delay);
private: private:
bool instr_direct_mem_ptr(tlm::tlm_generic_payload&, bool instr_direct_mem_ptr(tlm::tlm_generic_payload &,
tlm::tlm_dmi &dmi_data); tlm::tlm_dmi &dmi_data);
void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end);
};
void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end);
};
}
#endif #endif

150
inc/CPU.h
View File

@ -26,99 +26,101 @@
#include "M_extension.h" #include "M_extension.h"
#include "A_extension.h" #include "A_extension.h"
namespace riscv_tlm {
/** /**
* @brief ISC_V CPU model * @brief ISC_V CPU model
* @param name name of the module * @param name name of the module
*/ */
class CPU: sc_core::sc_module { class CPU : sc_core::sc_module {
public: public:
/** /**
* @brief Instruction Memory bus socket * @brief Instruction Memory bus socket
* @param trans transction to perfoem * @param trans transction to perfoem
* @param delay time to annotate * @param delay time to annotate
*/ */
tlm_utils::simple_initiator_socket<CPU> instr_bus; tlm_utils::simple_initiator_socket<CPU> instr_bus;
/** /**
* @brief IRQ line socket * @brief IRQ line socket
* @param trans transction to perform (empty) * @param trans transction to perform (empty)
* @param delay time to annotate * @param delay time to annotate
*/ */
tlm_utils::simple_target_socket<CPU> irq_line_socket; tlm_utils::simple_target_socket<CPU> irq_line_socket;
/** /**
* @brief Constructor * @brief Constructor
* @param name Module name * @param name Module name
* @param PC Program Counter initialize value * @param PC Program Counter initialize value
* @param debug To start debugging * @param debug To start debugging
*/ */
CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug); CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug);
/** /**
* @brief Destructor * @brief Destructor
*/ */
~CPU() override; ~CPU() override;
MemoryInterface *mem_intf; MemoryInterface *mem_intf;
bool CPU_step(); bool CPU_step();
Registers *getRegisterBank() {return register_bank;} Registers *getRegisterBank() { return register_bank; }
private: private:
Registers *register_bank; Registers *register_bank;
Performance *perf; Performance *perf;
std::shared_ptr<spdlog::logger> logger; std::shared_ptr<spdlog::logger> logger;
C_extension *c_inst; C_extension *c_inst;
M_extension *m_inst; M_extension *m_inst;
A_extension *a_inst; A_extension *a_inst;
BASE_ISA *exec; BASE_ISA *exec;
tlm_utils::tlm_quantumkeeper *m_qk; tlm_utils::tlm_quantumkeeper *m_qk;
Instruction inst; Instruction inst;
bool interrupt; bool interrupt;
std::uint32_t int_cause; std::uint32_t int_cause;
bool irq_already_down; bool irq_already_down;
sc_core::sc_time default_time; sc_core::sc_time default_time;
bool dmi_ptr_valid; bool dmi_ptr_valid;
tlm::tlm_generic_payload trans; tlm::tlm_generic_payload trans;
std::uint32_t INSTR; std::uint32_t INSTR;
unsigned char *dmi_ptr = nullptr; unsigned char *dmi_ptr = nullptr;
/**
*
* @brief Process and triggers IRQ if all conditions met
* @return true if IRQ is triggered, false otherwise
*/
bool cpu_process_IRQ();
/** /**
* * main thread for CPU simulation
* @brief Process and triggers IRQ if all conditions met * @brief CPU mai thread
* @return true if IRQ is triggered, false otherwise */
*/ [[noreturn]] void CPU_thread();
bool cpu_process_IRQ();
/** /**
* main thread for CPU simulation * @brief callback for IRQ simple socket
* @brief CPU mai thread * @param trans transaction to perform (empty)
*/ * @param delay time to annotate
[[noreturn]] void CPU_thread(); *
* it triggers an IRQ when called
*/
void call_interrupt(tlm::tlm_generic_payload &trans,
sc_core::sc_time &delay);
/** /**
* @brief callback for IRQ simple socket * DMI pointer is not longer valid
* @param trans transaction to perform (empty) * @param start memory address region start
* @param delay time to annotate * @param end memory address region end
* */
* it triggers an IRQ when called void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end);
*/ };
void call_interrupt(tlm::tlm_generic_payload &trans,
sc_core::sc_time &delay);
/**
* DMI pointer is not longer valid
* @param start memory address region start
* @param end memory address region end
*/
void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end);
};
}
#endif #endif

View File

@ -12,400 +12,426 @@
#include "systemc" #include "systemc"
#include "extension_base.h" #include "extension_base.h"
typedef enum { namespace riscv_tlm {
OP_C_ADDI4SPN,
OP_C_FLD,
OP_C_LW,
OP_C_FLW,
OP_C_FSD,
OP_C_SW,
OP_C_FSW,
OP_C_NOP, typedef enum {
OP_C_ADDI, OP_C_ADDI4SPN,
OP_C_JAL, OP_C_FLD,
OP_C_LI, OP_C_LW,
OP_C_ADDI16SP, OP_C_FLW,
OP_C_LUI, OP_C_FSD,
OP_C_SRLI, OP_C_SW,
OP_C_SRAI, OP_C_FSW,
OP_C_ANDI,
OP_C_SUB,
OP_C_XOR,
OP_C_OR,
OP_C_AND,
OP_C_J,
OP_C_BEQZ,
OP_C_BNEZ,
OP_C_SLLI, OP_C_NOP,
OP_C_FLDSP, OP_C_ADDI,
OP_C_LWSP, OP_C_JAL,
OP_C_FLWSP, OP_C_LI,
OP_C_JR, OP_C_ADDI16SP,
OP_C_MV, OP_C_LUI,
OP_C_EBREAK, OP_C_SRLI,
OP_C_JALR, OP_C_SRAI,
OP_C_ADD, OP_C_ANDI,
OP_C_FSDSP, OP_C_SUB,
OP_C_SWSP, OP_C_XOR,
OP_C_FSWSP, OP_C_OR,
OP_C_AND,
OP_C_J,
OP_C_BEQZ,
OP_C_BNEZ,
OP_C_ERROR OP_C_SLLI,
} op_C_Codes; OP_C_FLDSP,
OP_C_LWSP,
OP_C_FLWSP,
OP_C_JR,
OP_C_MV,
OP_C_EBREAK,
OP_C_JALR,
OP_C_ADD,
OP_C_FSDSP,
OP_C_SWSP,
OP_C_FSWSP,
typedef enum { OP_C_ERROR
C_ADDI4SPN = 0b000, } op_C_Codes;
C_FLD = 0b001,
C_LW = 0b010,
C_FLW = 0b011,
C_FSD = 0b101,
C_SW = 0b110,
C_FSW = 0b111,
C_ADDI = 0b000, typedef enum {
C_JAL = 0b001, C_ADDI4SPN = 0b000,
C_LI = 0b010, C_FLD = 0b001,
C_ADDI16SP = 0b011, C_LW = 0b010,
C_SRLI = 0b100, C_FLW = 0b011,
C_2_SRLI = 0b00, C_FSD = 0b101,
C_2_SRAI = 0b01, C_SW = 0b110,
C_2_ANDI = 0b10, C_FSW = 0b111,
C_2_SUB = 0b11,
C_3_SUB = 0b00,
C_3_XOR = 0b01,
C_3_OR = 0b10,
C_3_AND = 0b11,
C_J = 0b101,
C_BEQZ = 0b110,
C_BNEZ = 0b111,
C_SLLI = 0b000, C_ADDI = 0b000,
C_FLDSP = 0b001, C_JAL = 0b001,
C_LWSP = 0b010, C_LI = 0b010,
C_FLWSP = 0b011, C_ADDI16SP = 0b011,
C_JR = 0b100, C_SRLI = 0b100,
C_FDSP = 0b101, C_2_SRLI = 0b00,
C_SWSP = 0b110, C_2_SRAI = 0b01,
C_FWWSP = 0b111, C_2_ANDI = 0b10,
} C_Codes; C_2_SUB = 0b11,
C_3_SUB = 0b00,
C_3_XOR = 0b01,
C_3_OR = 0b10,
C_3_AND = 0b11,
C_J = 0b101,
C_BEQZ = 0b110,
C_BNEZ = 0b111,
C_SLLI = 0b000,
C_FLDSP = 0b001,
C_LWSP = 0b010,
C_FLWSP = 0b011,
C_JR = 0b100,
C_FDSP = 0b101,
C_SWSP = 0b110,
C_FWWSP = 0b111,
} C_Codes;
/** /**
* @brief Instruction decoding and fields access * @brief Instruction decoding and fields access
*/ */
class C_extension: public extension_base { class C_extension : public extension_base {
public: public:
/** /**
* @brief Constructor, same as base clase * @brief Constructor, same as base clase
*/ */
using extension_base::extension_base; using extension_base::extension_base;
/** /**
* @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 { inline std::int32_t opcode() const override {
return static_cast<std::int32_t>(m_instr.range(1, 0)); return static_cast<std::int32_t>(m_instr.range(1, 0));
} }
inline std::int32_t get_rdp() const { inline std::int32_t get_rdp() const {
return static_cast<std::int32_t>(m_instr.range(4, 2) + 8); return static_cast<std::int32_t>(m_instr.range(4, 2) + 8);
} }
/** /**
* @brief Access to rs1 field * @brief Access to rs1 field
* @return rs1 field * @return rs1 field
*/ */
inline std::int32_t get_rs1() const override { inline std::int32_t get_rs1() const override {
return static_cast<std::int32_t>(m_instr.range(11, 7)); return static_cast<std::int32_t>(m_instr.range(11, 7));
} }
inline void set_rs1(std::int32_t value) override { inline void set_rs1(std::int32_t value) override {
m_instr.range(11, 7) = value; m_instr.range(11, 7) = value;
} }
inline std::int32_t get_rs1p() const { inline std::int32_t get_rs1p() const {
return static_cast<std::int32_t>(m_instr.range(9, 7) + 8); return static_cast<std::int32_t>(m_instr.range(9, 7) + 8);
} }
/** /**
* @brief Access to rs2 field * @brief Access to rs2 field
* @return rs2 field * @return rs2 field
*/ */
inline std::int32_t get_rs2() const override { inline std::int32_t get_rs2() const override {
return static_cast<std::int32_t>(m_instr.range(6, 2)); return static_cast<std::int32_t>(m_instr.range(6, 2));
} }
inline void set_rs2(std::int32_t value) override { inline void set_rs2(std::int32_t value) override {
m_instr.range(6, 2) = value; m_instr.range(6, 2) = value;
} }
inline std::int32_t get_rs2p() const { inline std::int32_t get_rs2p() const {
return static_cast<std::int32_t>(m_instr.range(4, 2) + 8); return static_cast<std::int32_t>(m_instr.range(4, 2) + 8);
} }
inline std::int32_t get_funct3() const override { inline std::int32_t get_funct3() const override {
return static_cast<std::int32_t>(m_instr.range(15, 13)); return static_cast<std::int32_t>(m_instr.range(15, 13));
} }
inline void set_funct3(std::int32_t value) override { inline void set_funct3(std::int32_t value) override {
m_instr.range(15, 13) = value; m_instr.range(15, 13) = value;
} }
/** /**
* @brief Access to immediate field for I-type * @brief Access to immediate field for I-type
* @return immediate_I field * @return immediate_I field
*/ */
inline std::int32_t get_imm_I() const { inline std::int32_t get_imm_I() const {
std::int32_t aux = 0; std::int32_t aux = 0;
aux = static_cast<std::int32_t>(m_instr.range(31, 20)); aux = static_cast<std::int32_t>(m_instr.range(31, 20));
/* sign extension (optimize) */ /* sign extension (optimize) */
if (m_instr[31] == 1) { if (m_instr[31] == 1) {
aux |= (0b11111111111111111111) << 12; aux |= (0b11111111111111111111) << 12;
} }
return aux; return aux;
} }
inline void set_imm_I(std::int32_t value) { inline void set_imm_I(std::int32_t value) {
m_instr.range(31, 20) = value; m_instr.range(31, 20) = value;
} }
/** /**
* @brief Access to immediate field for S-type * @brief Access to immediate field for S-type
* @return immediate_S field * @return immediate_S field
*/ */
inline std::int32_t get_imm_S() const { inline std::int32_t get_imm_S() const {
std::int32_t aux = 0; std::int32_t aux = 0;
aux = static_cast<std::int32_t>(m_instr.range(31, 25) << 5); aux = static_cast<std::int32_t>(m_instr.range(31, 25) << 5);
aux |= static_cast<std::int32_t>(m_instr.range(11, 7)); aux |= static_cast<std::int32_t>(m_instr.range(11, 7));
if (m_instr[31] == 1) { if (m_instr[31] == 1) {
aux |= (0b11111111111111111111) << 12; aux |= (0b11111111111111111111) << 12;
} }
return aux; return aux;
} }
inline void set_imm_S(std::int32_t value) { inline void set_imm_S(std::int32_t value) {
sc_dt::sc_uint<32> aux = value; sc_dt::sc_uint<32> aux = value;
m_instr.range(31, 25) = aux.range(11, 5); m_instr.range(31, 25) = aux.range(11, 5);
m_instr.range(11, 7) = aux.range(4, 0); m_instr.range(11, 7) = aux.range(4, 0);
} }
/** /**
* @brief Access to immediate field for U-type * @brief Access to immediate field for U-type
* @return immediate_U field * @return immediate_U field
*/ */
inline std::int32_t get_imm_U() const { inline std::int32_t get_imm_U() const {
return static_cast<std::int32_t>(m_instr.range(31, 12)); return static_cast<std::int32_t>(m_instr.range(31, 12));
} }
inline void set_imm_U(std::int32_t value) { inline void set_imm_U(std::int32_t value) {
m_instr.range(31, 12) = (value << 12); m_instr.range(31, 12) = (value << 12);
} }
/** /**
* @brief Access to immediate field for B-type * @brief Access to immediate field for B-type
* @return immediate_B field * @return immediate_B field
*/ */
inline std::int32_t get_imm_B() const { inline std::int32_t get_imm_B() const {
std::int32_t aux = 0; std::int32_t aux = 0;
aux |= static_cast<std::int32_t>(m_instr[7] << 11); aux |= static_cast<std::int32_t>(m_instr[7] << 11);
aux |= static_cast<std::int32_t>(m_instr.range(30, 25) << 5); aux |= static_cast<std::int32_t>(m_instr.range(30, 25) << 5);
aux |= static_cast<std::int32_t>(m_instr[31] << 12); aux |= static_cast<std::int32_t>(m_instr[31] << 12);
aux |= static_cast<std::int32_t>(m_instr.range(11, 8) << 1); aux |= static_cast<std::int32_t>(m_instr.range(11, 8) << 1);
if (m_instr[31] == 1) { if (m_instr[31] == 1) {
aux |= (0b11111111111111111111) << 12; aux |= (0b11111111111111111111) << 12;
} }
return aux; return aux;
} }
inline void set_imm_B(std::int32_t value) { inline void set_imm_B(std::int32_t value) {
sc_dt::sc_uint<32> aux = value; sc_dt::sc_uint<32> aux = value;
m_instr[31] = aux[12]; m_instr[31] = aux[12];
m_instr.range(30, 25) = aux.range(10, 5); m_instr.range(30, 25) = aux.range(10, 5);
m_instr.range(11, 7) = aux.range(4, 1); m_instr.range(11, 7) = aux.range(4, 1);
m_instr[6] = aux[11]; m_instr[6] = aux[11];
} }
/**
* @brief Access to immediate field for J-type /**
* @return immediate_J field * @brief Access to immediate field for J-type
*/ * @return immediate_J field
inline std::int32_t get_imm_J() const { */
std::int32_t aux = 0; inline std::int32_t get_imm_J() const {
std::int32_t aux = 0;
aux = static_cast<std::int32_t>(m_instr[12] << 11);
aux |= static_cast<std::int32_t>(m_instr[11] << 4); aux = static_cast<std::int32_t>(m_instr[12] << 11);
aux |= static_cast<std::int32_t>(m_instr[10] << 9); aux |= static_cast<std::int32_t>(m_instr[11] << 4);
aux |= static_cast<std::int32_t>(m_instr[9] << 8); aux |= static_cast<std::int32_t>(m_instr[10] << 9);
aux |= static_cast<std::int32_t>(m_instr[8] << 10); aux |= static_cast<std::int32_t>(m_instr[9] << 8);
aux |= static_cast<std::int32_t>(m_instr[7] << 6); aux |= static_cast<std::int32_t>(m_instr[8] << 10);
aux |= static_cast<std::int32_t>(m_instr[6] << 7); aux |= static_cast<std::int32_t>(m_instr[7] << 6);
aux |= static_cast<std::int32_t>(m_instr.range(5, 3) << 1); aux |= static_cast<std::int32_t>(m_instr[6] << 7);
aux |= static_cast<std::int32_t>(m_instr[2] << 5); aux |= static_cast<std::int32_t>(m_instr.range(5, 3) << 1);
aux |= static_cast<std::int32_t>(m_instr[2] << 5);
if (m_instr[12] == 1) {
aux |= 0b11111111111111111111 << 12; if (m_instr[12] == 1) {
} aux |= 0b11111111111111111111 << 12;
}
return aux;
} return aux;
}
inline void set_imm_J(std::int32_t value) {
sc_dt::sc_uint<32> aux = (value << 20); inline void set_imm_J(std::int32_t value) {
sc_dt::sc_uint<32> aux = (value << 20);
m_instr[31] = aux[20];
m_instr.range(30, 21) = aux.range(10, 1); m_instr[31] = aux[20];
m_instr[20] = aux[11]; m_instr.range(30, 21) = aux.range(10, 1);
m_instr.range(19, 12) = aux.range(19, 12); m_instr[20] = aux[11];
} m_instr.range(19, 12) = aux.range(19, 12);
}
inline std::int32_t get_imm_L() const {
std::int32_t aux = 0; inline std::int32_t get_imm_L() const {
std::int32_t aux = 0;
aux = static_cast<std::int32_t>(m_instr.range(12, 10) << 3);
aux |= static_cast<std::int32_t>(m_instr[6] << 2); aux = static_cast<std::int32_t>(m_instr.range(12, 10) << 3);
aux |= static_cast<std::int32_t>(m_instr[5] << 6); aux |= static_cast<std::int32_t>(m_instr[6] << 2);
aux |= static_cast<std::int32_t>(m_instr[5] << 6);
return aux;
} return aux;
}
inline std::int32_t get_imm_LWSP() const {
std::int32_t aux = 0; inline std::int32_t get_imm_LWSP() const {
std::int32_t aux = 0;
aux = static_cast<std::int32_t>(m_instr[12] << 5);
aux |= static_cast<std::int32_t>(m_instr.range(6, 4) << 2); aux = static_cast<std::int32_t>(m_instr[12] << 5);
aux |= static_cast<std::int32_t>(m_instr.range(3, 2) << 6); aux |= static_cast<std::int32_t>(m_instr.range(6, 4) << 2);
aux |= static_cast<std::int32_t>(m_instr.range(3, 2) << 6);
return aux;
} return aux;
}
inline std::int32_t get_imm_ADDI () const {
std::int32_t aux = 0; inline std::int32_t get_imm_ADDI() const {
std::int32_t aux = 0;
aux = static_cast<std::int32_t>(m_instr[12] << 5);
aux |= static_cast<std::int32_t>(m_instr.range(6, 2)); aux = static_cast<std::int32_t>(m_instr[12] << 5);
aux |= static_cast<std::int32_t>(m_instr.range(6, 2));
if (m_instr[12] == 1) {
aux |= 0b11111111111111111111111111 << 6; if (m_instr[12] == 1) {
} aux |= 0b11111111111111111111111111 << 6;
return aux; }
} return aux;
}
inline std::int32_t get_imm_ADDI4SPN() const {
std::int32_t aux = 0; inline std::int32_t get_imm_ADDI4SPN() const {
std::int32_t aux = 0;
aux = static_cast<std::int32_t>(m_instr.range(12, 11) << 4);
aux |= static_cast<std::int32_t>(m_instr.range(10, 7) << 6); aux = static_cast<std::int32_t>(m_instr.range(12, 11) << 4);
aux |= static_cast<std::int32_t>(m_instr[6] << 2); aux |= static_cast<std::int32_t>(m_instr.range(10, 7) << 6);
aux |= static_cast<std::int32_t>(m_instr[5] << 3); aux |= static_cast<std::int32_t>(m_instr[6] << 2);
aux |= static_cast<std::int32_t>(m_instr[5] << 3);
return aux;
} return aux;
}
inline std::int32_t get_imm_ADDI16SP() const {
std::int32_t aux = 0; inline std::int32_t get_imm_ADDI16SP() const {
std::int32_t aux = 0;
aux = static_cast<std::int32_t>(m_instr[12] << 9);
aux |= static_cast<std::int32_t>(m_instr[6] << 4); aux = static_cast<std::int32_t>(m_instr[12] << 9);
aux |= static_cast<std::int32_t>(m_instr[5] << 6); aux |= static_cast<std::int32_t>(m_instr[6] << 4);
aux |= static_cast<std::int32_t>(m_instr[4] << 8); aux |= static_cast<std::int32_t>(m_instr[5] << 6);
aux |= static_cast<std::int32_t>(m_instr[3] << 7); aux |= static_cast<std::int32_t>(m_instr[4] << 8);
aux |= static_cast<std::int32_t>(m_instr[2] << 5); aux |= static_cast<std::int32_t>(m_instr[3] << 7);
aux |= static_cast<std::int32_t>(m_instr[2] << 5);
if (m_instr[12] == 1) {
aux |= 0b1111111111111111111111 << 10; if (m_instr[12] == 1) {
} aux |= 0b1111111111111111111111 << 10;
return aux; }
} return aux;
}
inline std::int32_t get_imm_CSS() const {
std::int32_t aux = 0; inline std::int32_t get_imm_CSS() const {
aux = static_cast<std::int32_t>(m_instr.range(12, 9) << 2); std::int32_t aux = 0;
aux |= static_cast<std::int32_t>(m_instr.range(8, 7) << 6); aux = static_cast<std::int32_t>(m_instr.range(12, 9) << 2);
aux |= static_cast<std::int32_t>(m_instr.range(8, 7) << 6);
return aux;
} return aux;
}
inline std::int32_t get_imm_CB() const {
std::int32_t aux = 0; inline std::int32_t get_imm_CB() const {
std::int32_t aux = 0;
aux = static_cast<std::int32_t>(m_instr[12] << 8);
aux |= static_cast<std::int32_t>(m_instr[11] << 4); aux = static_cast<std::int32_t>(m_instr[12] << 8);
aux |= static_cast<std::int32_t>(m_instr[10] << 3); aux |= static_cast<std::int32_t>(m_instr[11] << 4);
aux |= static_cast<std::int32_t>(m_instr[6] << 7); aux |= static_cast<std::int32_t>(m_instr[10] << 3);
aux |= static_cast<std::int32_t>(m_instr[5] << 6); aux |= static_cast<std::int32_t>(m_instr[6] << 7);
aux |= static_cast<std::int32_t>(m_instr[4] << 2); aux |= static_cast<std::int32_t>(m_instr[5] << 6);
aux |= static_cast<std::int32_t>(m_instr[3] << 1); aux |= static_cast<std::int32_t>(m_instr[4] << 2);
aux |= static_cast<std::int32_t>(m_instr[2] << 5); aux |= static_cast<std::int32_t>(m_instr[3] << 1);
aux |= static_cast<std::int32_t>(m_instr[2] << 5);
if (m_instr[12] == 1) {
aux |= 0b11111111111111111111111 << 9; if (m_instr[12] == 1) {
} aux |= 0b11111111111111111111111 << 9;
}
return aux;
} return aux;
}
inline std::int32_t get_imm_LUI() const {
std::int32_t aux = 0; inline std::int32_t get_imm_LUI() const {
std::int32_t aux = 0;
aux = static_cast<std::int32_t>(m_instr[12] << 17);
aux |= static_cast<std::int32_t>(m_instr.range(6, 2) << 12); aux = static_cast<std::int32_t>(m_instr[12] << 17);
aux |= static_cast<std::int32_t>(m_instr.range(6, 2) << 12);
if (m_instr[12] == 1) {
aux |= 0b111111111111111 << 17; if (m_instr[12] == 1) {
} aux |= 0b111111111111111 << 17;
}
return aux;
} return aux;
}
inline std::int32_t get_csr() const {
return get_imm_I(); inline std::int32_t get_csr() const {
} return get_imm_I();
}
/**
* @brief Decodes opcode of instruction /**
* @return opcode of instruction * @brief Decodes opcode of instruction
*/ * @return opcode of instruction
op_C_Codes decode() const; */
op_C_Codes decode() const;
bool Exec_C_JR();
bool Exec_C_MV(); bool Exec_C_JR();
bool Exec_C_LWSP();
bool Exec_C_ADDI4SPN(); bool Exec_C_MV();
bool Exec_C_SLLI();
bool Exec_C_ADDI16SP(); bool Exec_C_LWSP();
bool Exec_C_SWSP();
bool Exec_C_BEQZ(); bool Exec_C_ADDI4SPN();
bool Exec_C_BNEZ();
bool Exec_C_LI(); bool Exec_C_SLLI();
bool Exec_C_SRLI();
bool Exec_C_SRAI(); bool Exec_C_ADDI16SP();
bool Exec_C_ANDI();
bool Exec_C_ADD(); bool Exec_C_SWSP();
bool Exec_C_SUB();
bool Exec_C_XOR(); bool Exec_C_BEQZ();
bool Exec_C_OR();
bool Exec_C_AND(); bool Exec_C_BNEZ();
bool Exec_C_ADDI() const; bool Exec_C_LI();
bool Exec_C_JALR();
bool Exec_C_LW(); bool Exec_C_SRLI();
bool Exec_C_SW();
bool Exec_C_JAL(int m_rd); bool Exec_C_SRAI();
bool Exec_C_EBREAK();
bool Exec_C_ANDI();
bool process_instruction(Instruction &inst, bool *breakpoint = nullptr);
}; bool Exec_C_ADD();
bool Exec_C_SUB();
bool Exec_C_XOR();
bool Exec_C_OR();
bool Exec_C_AND();
bool Exec_C_ADDI() const;
bool Exec_C_JALR();
bool Exec_C_LW();
bool Exec_C_SW();
bool Exec_C_JAL(int m_rd);
bool Exec_C_EBREAK();
bool process_instruction(Instruction &inst, bool *breakpoint = nullptr);
};
}
#endif #endif

View File

@ -12,54 +12,58 @@
#include "systemc" #include "systemc"
#include "extension_base.h" #include "extension_base.h"
typedef enum { namespace riscv_tlm {
BASE_EXTENSION,
M_EXTENSION, typedef enum {
A_EXTENSION, BASE_EXTENSION,
F_EXTENSION, M_EXTENSION,
D_EXTENSION, A_EXTENSION,
Q_EXTENSION, F_EXTENSION,
L_EXTENSION, D_EXTENSION,
C_EXTENSION, Q_EXTENSION,
R_EXTENSION, L_EXTENSION,
J_EXTENSION, C_EXTENSION,
P_EXTENSION, R_EXTENSION,
V_EXTENSION, J_EXTENSION,
N_EXTENSION, P_EXTENSION,
UNKNOWN_EXTENSION V_EXTENSION,
} extension_t; N_EXTENSION,
UNKNOWN_EXTENSION
} extension_t;
/** /**
* @brief Instruction decoding and fields access * @brief Instruction decoding and fields access
*/ */
class Instruction { class Instruction {
public: public:
Instruction(std::uint32_t instr); Instruction(std::uint32_t instr);
/** /**
* @brief returns what instruction extension * @brief returns what instruction extension
* @return extension * @return extension
*/ */
extension_t check_extension() const; extension_t check_extension() const;
void setInstr(std::uint32_t p_instr) { void setInstr(std::uint32_t p_instr) {
m_instr = p_instr; m_instr = p_instr;
} }
/**
* @brief return instruction
* @return all instruction bits (31:0)
*/
std::uint32_t getInstr() {
return m_instr;
}
inline void dump() { /**
std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; * @brief return instruction
} * @return all instruction bits (31:0)
*/
std::uint32_t getInstr() {
return m_instr;
}
private: inline void dump() {
std::uint32_t m_instr; std::cout << std::hex << "0x" << m_instr << std::dec << std::endl;
}; }
private:
std::uint32_t m_instr;
};
}
#endif #endif

View File

@ -14,72 +14,82 @@
#include "extension_base.h" #include "extension_base.h"
#include "Registers.h" #include "Registers.h"
typedef enum { namespace riscv_tlm {
OP_M_MUL,
OP_M_MULH,
OP_M_MULHSU,
OP_M_MULHU,
OP_M_DIV,
OP_M_DIVU,
OP_M_REM,
OP_M_REMU,
OP_M_ERROR typedef enum {
} op_M_Codes; OP_M_MUL,
OP_M_MULH,
OP_M_MULHSU,
OP_M_MULHU,
OP_M_DIV,
OP_M_DIVU,
OP_M_REM,
OP_M_REMU,
typedef enum { OP_M_ERROR
M_MUL = 0b000, } op_M_Codes;
M_MULH = 0b001,
M_MULHSU = 0b010, typedef enum {
M_MULHU = 0b011, M_MUL = 0b000,
M_DIV = 0b100, M_MULH = 0b001,
M_DIVU = 0b101, M_MULHSU = 0b010,
M_REM = 0b110, M_MULHU = 0b011,
M_REMU = 0b111, M_DIV = 0b100,
} M_Codes; M_DIVU = 0b101,
M_REM = 0b110,
M_REMU = 0b111,
} M_Codes;
/** /**
* @brief Instruction decoding and fields access * @brief Instruction decoding and fields access
*/ */
class M_extension: public extension_base { class M_extension : public extension_base {
public: public:
/** /**
* @brief Constructor, same as base clase * @brief Constructor, same as base clase
*/ */
using extension_base::extension_base; using extension_base::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; op_M_Codes decode() const;
inline void dump() const override { inline void dump() const override {
std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; std::cout << std::hex << "0x" << m_instr << std::dec << std::endl;
} }
bool Exec_M_MUL() const; bool Exec_M_MUL() const;
bool Exec_M_MULH() const;
bool Exec_M_MULHSU() const;
bool Exec_M_MULHU() const;
bool Exec_M_DIV() const;
bool Exec_M_DIVU() const;
bool Exec_M_REM() const;
bool Exec_M_REMU() const;
bool process_instruction(Instruction &inst); bool Exec_M_MULH() const;
private: bool Exec_M_MULHSU() const;
/** bool Exec_M_MULHU() const;
* @brief Access to opcode field
* @return return opcode field
*/
inline std::int32_t opcode() const override {
return static_cast<std::int32_t>(m_instr.range(14, 12));
}
}; bool Exec_M_DIV() const;
bool Exec_M_DIVU() const;
bool Exec_M_REM() const;
bool Exec_M_REMU() const;
bool process_instruction(Instruction &inst);
private:
/**
* @brief Access to opcode field
* @return return opcode field
*/
inline std::int32_t opcode() const override {
return static_cast<std::int32_t>(m_instr.range(14, 12));
}
};
}
#endif #endif

View File

@ -21,72 +21,76 @@
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h" #include "spdlog/sinks/basic_file_sink.h"
namespace riscv_tlm {
/** /**
* @brief Basic TLM-2 memory * @brief Basic TLM-2 memory
*/ */
class Memory: sc_core::sc_module { class Memory : sc_core::sc_module {
public: public:
// TLM-2 socket, defaults to 32-bits wide, base protocol // TLM-2 socket, defaults to 32-bits wide, base protocol
tlm_utils::simple_target_socket<Memory> socket; tlm_utils::simple_target_socket<Memory> socket;
/* 16 MBytes */ /* 16 MBytes */
enum { enum {
SIZE = 0x1000000 SIZE = 0x1000000
}; };
const sc_core::sc_time LATENCY; const sc_core::sc_time LATENCY;
Memory(sc_core::sc_module_name const &name, std::string const &filename); Memory(sc_core::sc_module_name const &name, std::string const &filename);
explicit Memory(const sc_core::sc_module_name& name);
~Memory() override; explicit Memory(const sc_core::sc_module_name &name);
/** ~Memory() override;
* @brief Returns Program Counter read from hexfile
* @return Initial PC
*/
virtual std::uint32_t getPCfromHEX();
// TLM-2 blocking transport method /**
virtual void b_transport(tlm::tlm_generic_payload &trans, * @brief Returns Program Counter read from hexfile
sc_core::sc_time &delay); * @return Initial PC
*/
virtual std::uint32_t getPCfromHEX();
// ********************************************* // TLM-2 blocking transport method
// TLM-2 forward DMI method virtual void b_transport(tlm::tlm_generic_payload &trans,
// ********************************************* sc_core::sc_time &delay);
virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload &trans,
tlm::tlm_dmi &dmi_data);
// ********************************************* // *********************************************
// TLM-2 debug transport method // TLM-2 forward DMI method
// ********************************************* // *********************************************
virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans); virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload &trans,
tlm::tlm_dmi &dmi_data);
private: // *********************************************
// TLM-2 debug transport method
// *********************************************
virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans);
/** private:
* @brief Memory array in bytes
*/
std::array<uint8_t, Memory::SIZE> mem{};
/** /**
* @brief Log class * @brief Memory array in bytes
*/ */
std::shared_ptr<spdlog::logger> logger; std::array<uint8_t, Memory::SIZE> mem{};
/** /**
* @brief Program counter (PC) read from hex file * @brief Log class
*/ */
std::uint32_t program_counter; std::shared_ptr<spdlog::logger> logger;
/** /**
* @brief DMI can be used? * @brief Program counter (PC) read from hex file
*/ */
bool dmi_allowed; std::uint32_t program_counter;
/** /**
* @brief Read Intel hex file * @brief DMI can be used?
* @param filename file name to read */
*/ bool dmi_allowed;
void readHexFile(const std::string& filename);
}; /**
* @brief Read Intel hex file
* @param filename file name to read
*/
void readHexFile(const std::string &filename);
};
}
#endif /* __MEMORY_H__ */ #endif /* __MEMORY_H__ */

View File

@ -17,17 +17,21 @@
#include "memory.h" #include "memory.h"
namespace riscv_tlm {
/** /**
* @brief Memory Interface * @brief Memory Interface
*/ */
class MemoryInterface { class MemoryInterface {
public: public:
tlm_utils::simple_initiator_socket<MemoryInterface> data_bus; tlm_utils::simple_initiator_socket<MemoryInterface> data_bus;
MemoryInterface(); MemoryInterface();
std::uint32_t readDataMem(std::uint32_t addr, int size);
void writeDataMem(std::uint32_t addr, std::uint32_t data, int size);
};
std::uint32_t readDataMem(std::uint32_t addr, int size);
void writeDataMem(std::uint32_t addr, std::uint32_t data, int size);
};
}
#endif /* INC_MEMORYINTERFACE_H_ */ #endif /* INC_MEMORYINTERFACE_H_ */

View File

@ -19,6 +19,8 @@
#include "Performance.h" #include "Performance.h"
#include "Memory.h" #include "Memory.h"
namespace riscv_tlm {
#define MISA_A_EXTENSION (1 << 0) #define MISA_A_EXTENSION (1 << 0)
#define MISA_B_EXTENSION (1 << 1) #define MISA_B_EXTENSION (1 << 1)
#define MISA_C_EXTENSION (1 << 2) #define MISA_C_EXTENSION (1 << 2)
@ -76,7 +78,7 @@
#define MSTATUS_SPP (1 << 8) #define MSTATUS_SPP (1 << 8)
#define MSTATUS_MPP (1 << 11) #define MSTATUS_MPP (1 << 11)
#define MSTATUS_FS (1 << 13) #define MSTATUS_FS (1 << 13)
#define MSTATUS_XS (1 << 15) #define MSTATUS_XS (1 << 15)
#define MSTATUS_MPRV (1 << 17) #define MSTATUS_MPRV (1 << 17)
#define MSTATUS_SUM (1 << 18) #define MSTATUS_SUM (1 << 18)
#define MSTATUS_MXR (1 << 19) #define MSTATUS_MXR (1 << 19)
@ -110,156 +112,158 @@
/** /**
* @brief Register file implementation * @brief Register file implementation
*/ */
class Registers { class Registers {
public: public:
enum { enum {
x0 = 0, x0 = 0,
x1 = 1, x1 = 1,
x2, x2,
x3, x3,
x4, x4,
x5, x5,
x6, x6,
x7, x7,
x8, x8,
x9, x9,
x10, x10,
x11, x11,
x12, x12,
x13, x13,
x14, x14,
x15, x15,
x16, x16,
x17, x17,
x18, x18,
x19, x19,
x20, x20,
x21, x21,
x22, x22,
x23, x23,
x24, x24,
x25, x25,
x26, x26,
x27, x27,
x28, x28,
x29, x29,
x30, x30,
x31, x31,
zero = x0, zero = x0,
ra = x1, ra = x1,
sp = x2, sp = x2,
gp = x3, gp = x3,
tp = x4, tp = x4,
t0 = x5, t0 = x5,
t1 = x6, t1 = x6,
t2 = x7, t2 = x7,
s0 = x8, s0 = x8,
fp = x8, fp = x8,
s1 = x9, s1 = x9,
a0 = x10, a0 = x10,
a1 = x11, a1 = x11,
a2 = x12, a2 = x12,
a3 = x13, a3 = x13,
a4 = x14, a4 = x14,
a5 = x15, a5 = x15,
a6 = x16, a6 = x16,
a7 = x17, a7 = x17,
s2 = x18, s2 = x18,
s3 = x19, s3 = x19,
s4 = x20, s4 = x20,
s5 = x21, s5 = x21,
s6 = x22, s6 = x22,
s7 = x23, s7 = x23,
s8 = x24, s8 = x24,
s9 = x25, s9 = x25,
s10 = x26, s10 = x26,
s11 = x27, s11 = x27,
t3 = x28, t3 = x28,
t4 = x29, t4 = x29,
t5 = x30, t5 = x30,
t6 = x31 t6 = x31
}; };
/**
* Default constructor
*/
Registers();
/** /**
* Set value for a register * Default constructor
* @param reg_num register number */
* @param value register value Registers();
*/
void setValue(int reg_num, std::int32_t value);
/** /**
* Returns register value * Set value for a register
* @param reg_num register number * @param reg_num register number
* @return register value * @param value register value
*/ */
std::uint32_t getValue(int reg_num) const; void setValue(int reg_num, std::int32_t value);
/** /**
* Returns PC value * Returns register value
* @return PC value * @param reg_num register number
*/ * @return register value
std::uint32_t getPC() const; */
std::uint32_t getValue(int reg_num) const;
/** /**
* Sets arbitraty value to PC * Returns PC value
* @param new_pc new address to PC * @return PC value
*/ */
void setPC(std::uint32_t new_pc); std::uint32_t getPC() const;
/** /**
* Increments PC couunter to next address * Sets arbitraty value to PC
*/ * @param new_pc new address to PC
inline void incPC() { */
register_PC += 4; void setPC(std::uint32_t new_pc);
}
inline void incPCby2() { /**
register_PC += 2; * Increments PC couunter to next address
} */
inline void incPC() {
register_PC += 4;
}
/** inline void incPCby2() {
* @brief Get CSR value register_PC += 2;
* @param csr CSR number to access }
* @return CSR value
*/
std::uint32_t getCSR(int csr);
/** /**
* @brief Set CSR value * @brief Get CSR value
* @param csr CSR number to access * @param csr CSR number to access
* @param value new value to register * @return CSR value
*/ */
void setCSR(int csr, std::uint32_t value); std::uint32_t getCSR(int csr);
/** /**
* Dump register data to console * @brief Set CSR value
*/ * @param csr CSR number to access
void dump(); * @param value new value to register
private: */
/** void setCSR(int csr, std::uint32_t value);
* bank of registers (32 regs of 32bits each)
*/
std::array<std::uint32_t, 32> register_bank = { {0} };
/** /**
* Program counter (32 bits width) * Dump register data to console
*/ */
std::uint32_t register_PC; void dump();
/** private:
* CSR registers (4096 maximum) /**
*/ * bank of registers (32 regs of 32bits each)
std::unordered_map<std::uint32_t, unsigned int> CSR; */
std::array<std::uint32_t, 32> register_bank = {{0}};
/**
* Program counter (32 bits width)
*/
std::uint32_t register_PC;
/**
* CSR registers (4096 maximum)
*/
std::unordered_map<std::uint32_t, unsigned int> CSR;
Performance *perf; Performance *perf;
void initCSR();
};
void initCSR();
};
}
#endif #endif

View File

@ -21,50 +21,51 @@
#include "BusCtrl.h" #include "BusCtrl.h"
namespace riscv_tlm::peripherals {
/** /**
* @brief Simple timer peripheral * @brief Simple timer peripheral
* *
* It runs a 1 ns (nanoseconds) pace * It runs a 1 ns (nanoseconds) pace
* *
*/ */
class Timer: sc_core::sc_module { class Timer : sc_core::sc_module {
public: public:
// TLM-2 socket, defaults to 32-bits wide, base protocol // TLM-2 socket, defaults to 32-bits wide, base protocol
tlm_utils::simple_target_socket<Timer> socket; tlm_utils::simple_target_socket<Timer> socket;
tlm_utils::simple_initiator_socket<Timer> irq_line; tlm_utils::simple_initiator_socket<Timer> irq_line;
/** /**
* *
* @brief Constructor * @brief Constructor
* @param name module name * @param name module name
*/ */
explicit Timer(sc_core::sc_module_name const &name); explicit Timer(sc_core::sc_module_name const &name);
/** /**
* @brief Waits for event timer_event and triggers an IRQ * @brief Waits for event timer_event and triggers an IRQ
* *
* Waits for event timer_event and triggers an IRQ (if it is not already * Waits for event timer_event and triggers an IRQ (if it is not already
* triggered). * triggered).
* After that, it posts the timer_event to 20 ns in the future to clear the IRQ * After that, it posts the timer_event to 20 ns in the future to clear the IRQ
* line. * line.
* *
*/ */
[[noreturn]] void run(); [[noreturn]] void run();
/** /**
* *
* @brief TLM-2.0 socket implementation * @brief TLM-2.0 socket implementation
* @param trans TLM-2.0 transaction * @param trans TLM-2.0 transaction
* @param delay transaction delay time * @param delay transaction delay time
*/ */
virtual void b_transport(tlm::tlm_generic_payload &trans, virtual void b_transport(tlm::tlm_generic_payload &trans,
sc_core::sc_time &delay); sc_core::sc_time &delay);
private:
sc_dt::sc_uint<64> m_mtime; /**< mtime register */
sc_dt::sc_uint<64> m_mtimecmp; /**< mtimecmp register */
sc_core::sc_event timer_event; /**< event */
};
private:
sc_dt::sc_uint<64> m_mtime; /**< mtime register */
sc_dt::sc_uint<64> m_mtimecmp; /**< mtimecmp register */
sc_core::sc_event timer_event; /**< event */
};
}
#endif #endif

View File

@ -19,43 +19,46 @@
#include "tlm.h" #include "tlm.h"
#include "tlm_utils/simple_target_socket.h" #include "tlm_utils/simple_target_socket.h"
namespace riscv_tlm::peripherals {
/** /**
* @brief Simple trace peripheral * @brief Simple trace peripheral
* *
* This peripheral outputs to cout any character written to its unique register * This peripheral outputs to cout any character written to its unique register
*/ */
class Trace: sc_core::sc_module { class Trace : sc_core::sc_module {
public: public:
/** /**
* @brief Bus socket * @brief Bus socket
*/ */
tlm_utils::simple_target_socket<Trace> socket; tlm_utils::simple_target_socket<Trace> socket;
/** /**
* @brief Constructor * @brief Constructor
* @param name Module name * @param name Module name
*/ */
explicit Trace(sc_core::sc_module_name const &name); explicit Trace(sc_core::sc_module_name const &name);
/** /**
* @brief Destructor * @brief Destructor
*/ */
~Trace() override; ~Trace() override;
private: private:
// TLM-2 blocking transport method // TLM-2 blocking transport method
virtual void b_transport(tlm::tlm_generic_payload &trans, virtual void b_transport(tlm::tlm_generic_payload &trans,
sc_core::sc_time &delay); sc_core::sc_time &delay);
void xtermLaunch(char *slaveName) const; void xtermLaunch(char *slaveName) const;
void xtermKill();
void xtermSetup();
int ptSlave{}; void xtermKill();
int ptMaster{};
int xtermPid{};
};
void xtermSetup();
int ptSlave{};
int ptMaster{};
int xtermPid{};
};
}
#endif #endif

View File

@ -26,60 +26,66 @@
#define EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN 4 #define EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN 4
#define EXCEPTION_CAUSE_LOAD_ACCESS_FAULT 5 #define EXCEPTION_CAUSE_LOAD_ACCESS_FAULT 5
class extension_base { namespace riscv_tlm {
public: class extension_base {
extension_base(const sc_dt::sc_uint<32> & instr, Registers *register_bank,
MemoryInterface *mem_interface);
virtual ~extension_base() = 0;
void setInstr(std::uint32_t p_instr); public:
void RaiseException(std::uint32_t cause, std::uint32_t inst); extension_base(const sc_dt::sc_uint<32> &instr, Registers *register_bank,
bool NOP(); MemoryInterface *mem_interface);
/* pure virtual functions */ virtual ~extension_base() = 0;
virtual std::int32_t opcode() const = 0;
virtual std::int32_t get_rd() const { void setInstr(std::uint32_t p_instr);
return m_instr.range(11, 7);
}
virtual void set_rd(std::int32_t value) { void RaiseException(std::uint32_t cause, std::uint32_t inst);
m_instr.range(11, 7) = value;
}
virtual std::int32_t get_rs1() const { bool NOP();
return m_instr.range(19, 15);
}
virtual void set_rs1(std::int32_t value) { /* pure virtual functions */
m_instr.range(19, 15) = value; virtual std::int32_t opcode() const = 0;
}
virtual std::int32_t get_rs2() const { virtual std::int32_t get_rd() const {
return m_instr.range(24, 20); return m_instr.range(11, 7);
} }
virtual void set_rs2(std::int32_t value) { virtual void set_rd(std::int32_t value) {
m_instr.range(24, 20) = value; m_instr.range(11, 7) = value;
} }
virtual std::int32_t get_funct3() const { virtual std::int32_t get_rs1() const {
return m_instr.range(14, 12); return m_instr.range(19, 15);
} }
virtual void set_funct3(std::int32_t value) { virtual void set_rs1(std::int32_t value) {
m_instr.range(14, 12) = value; m_instr.range(19, 15) = value;
} }
virtual void dump() const; virtual std::int32_t get_rs2() const {
return m_instr.range(24, 20);
}
protected: virtual void set_rs2(std::int32_t value) {
sc_dt::sc_uint<32> m_instr; m_instr.range(24, 20) = value;
Registers *regs; }
Performance *perf;
MemoryInterface *mem_intf; virtual std::int32_t get_funct3() const {
std::shared_ptr<spdlog::logger> logger; return m_instr.range(14, 12);
}; }
virtual void set_funct3(std::int32_t value) {
m_instr.range(14, 12) = value;
}
virtual void dump() const;
protected:
sc_dt::sc_uint<32> m_instr;
Registers *regs;
Performance *perf;
MemoryInterface *mem_intf;
std::shared_ptr<spdlog::logger> logger;
};
}
#endif /* INC_EXTENSION_BASE_H_ */ #endif /* INC_EXTENSION_BASE_H_ */

View File

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

@ -8,64 +8,67 @@
#include "BusCtrl.h" #include "BusCtrl.h"
SC_HAS_PROCESS(BusCtrl); namespace riscv_tlm {
BusCtrl::BusCtrl(sc_core::sc_module_name const &name) :
sc_module(name), cpu_instr_socket("cpu_instr_socket"), cpu_data_socket(
"cpu_data_socket"), memory_socket("memory_socket"), trace_socket(
"trace_socket") {
cpu_instr_socket.register_b_transport(this, &BusCtrl::b_transport);
cpu_data_socket.register_b_transport(this, &BusCtrl::b_transport);
cpu_instr_socket.register_get_direct_mem_ptr(this, SC_HAS_PROCESS(BusCtrl);
&BusCtrl::instr_direct_mem_ptr);
memory_socket.register_invalidate_direct_mem_ptr(this,
&BusCtrl::invalidate_direct_mem_ptr);
}
void BusCtrl::b_transport(tlm::tlm_generic_payload &trans, BusCtrl::BusCtrl(sc_core::sc_module_name const &name) :
sc_core::sc_time &delay) { sc_module(name), cpu_instr_socket("cpu_instr_socket"), cpu_data_socket(
"cpu_data_socket"), memory_socket("memory_socket"), trace_socket(
"trace_socket") {
cpu_instr_socket.register_b_transport(this, &BusCtrl::b_transport);
cpu_data_socket.register_b_transport(this, &BusCtrl::b_transport);
sc_dt::uint64 adr = trans.get_address() / 4; cpu_instr_socket.register_get_direct_mem_ptr(this,
&BusCtrl::instr_direct_mem_ptr);
memory_socket.register_invalidate_direct_mem_ptr(this,
&BusCtrl::invalidate_direct_mem_ptr);
}
if (adr >= TO_HOST_ADDRESS / 4) { void BusCtrl::b_transport(tlm::tlm_generic_payload &trans,
std::cout << "To host\n" << std::flush; sc_core::sc_time &delay) {
sc_core::sc_stop();
return;
}
switch (adr) { sc_dt::uint64 adr = trans.get_address() / 4;
case TIMER_MEMORY_ADDRESS_HI / 4:
case TIMER_MEMORY_ADDRESS_LO / 4: if (adr >= TO_HOST_ADDRESS / 4) {
case TIMERCMP_MEMORY_ADDRESS_HI / 4: std::cout << "To host\n" << std::flush;
case TIMERCMP_MEMORY_ADDRESS_LO / 4: sc_core::sc_stop();
timer_socket->b_transport(trans, delay); return;
break; }
case TRACE_MEMORY_ADDRESS / 4:
trace_socket->b_transport(trans, delay); switch (adr) {
break; case TIMER_MEMORY_ADDRESS_HI / 4:
[[likely]] default: case TIMER_MEMORY_ADDRESS_LO / 4:
memory_socket->b_transport(trans, delay); case TIMERCMP_MEMORY_ADDRESS_HI / 4:
break; case TIMERCMP_MEMORY_ADDRESS_LO / 4:
} timer_socket->b_transport(trans, delay);
break;
case TRACE_MEMORY_ADDRESS / 4:
trace_socket->b_transport(trans, delay);
break;
[[likely]] default:
memory_socket->b_transport(trans, delay);
break;
}
#if 0 #if 0
if (cmd == tlm::TLM_READ_COMMAND) { if (cmd == tlm::TLM_READ_COMMAND) {
log->SC_log(Log::DEBUG) << "RD Address: @0x" << hex << adr << dec << endl; log->SC_log(Log::DEBUG) << "RD Address: @0x" << hex << adr << dec << endl;
} else { } else {
log->SC_log(Log::DEBUG) << "WR Address: @0x" << hex << adr << dec << endl; log->SC_log(Log::DEBUG) << "WR Address: @0x" << hex << adr << dec << endl;
} }
#endif #endif
trans.set_response_status(tlm::TLM_OK_RESPONSE); trans.set_response_status(tlm::TLM_OK_RESPONSE);
} }
bool BusCtrl::instr_direct_mem_ptr(tlm::tlm_generic_payload &gp, bool BusCtrl::instr_direct_mem_ptr(tlm::tlm_generic_payload &gp,
tlm::tlm_dmi &dmi_data) { tlm::tlm_dmi &dmi_data) {
return memory_socket->get_direct_mem_ptr(gp, dmi_data); return memory_socket->get_direct_mem_ptr(gp, dmi_data);
} }
void BusCtrl::invalidate_direct_mem_ptr(sc_dt::uint64 start, void BusCtrl::invalidate_direct_mem_ptr(sc_dt::uint64 start,
sc_dt::uint64 end) { sc_dt::uint64 end) {
cpu_instr_socket->invalidate_direct_mem_ptr(start, end); cpu_instr_socket->invalidate_direct_mem_ptr(start, end);
}
} }

View File

@ -7,222 +7,230 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
#include "CPU.h" #include "CPU.h"
SC_HAS_PROCESS(CPU); namespace riscv_tlm {
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_core::SC_NS), INSTR(0) {
register_bank = new Registers();
mem_intf = new MemoryInterface();
perf = Performance::getInstance(); SC_HAS_PROCESS(CPU);
register_bank->setPC(PC); CPU::CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug) :
register_bank->setValue(Registers::sp, (Memory::SIZE / 4) - 1); sc_module(name), instr_bus("instr_bus"), inst(0), default_time(10,
sc_core::SC_NS), INSTR(0) {
register_bank = new Registers();
mem_intf = new MemoryInterface();
irq_line_socket.register_b_transport(this, &CPU::call_interrupt); perf = Performance::getInstance();
interrupt = false;
int_cause = 0; register_bank->setPC(PC);
irq_already_down = false; register_bank->setValue(Registers::sp, (Memory::SIZE / 4) - 1);
dmi_ptr_valid = false; irq_line_socket.register_b_transport(this, &CPU::call_interrupt);
instr_bus.register_invalidate_direct_mem_ptr(this, interrupt = false;
&CPU::invalidate_direct_mem_ptr);
exec = new BASE_ISA(0, register_bank, mem_intf); int_cause = 0;
c_inst = new C_extension(0, register_bank, mem_intf); irq_already_down = false;
m_inst = new M_extension(0, register_bank, mem_intf);
a_inst = new A_extension(0, register_bank, mem_intf);
m_qk = new tlm_utils::tlm_quantumkeeper(); dmi_ptr_valid = false;
m_qk->reset(); instr_bus.register_invalidate_direct_mem_ptr(this,
&CPU::invalidate_direct_mem_ptr);
trans.set_command(tlm::TLM_READ_COMMAND); exec = new BASE_ISA(0, register_bank, mem_intf);
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&INSTR)); c_inst = new C_extension(0, register_bank, mem_intf);
trans.set_data_length(4); m_inst = new M_extension(0, register_bank, mem_intf);
trans.set_streaming_width(4); // = data_length to indicate no streaming a_inst = new A_extension(0, register_bank, mem_intf);
trans.set_byte_enable_ptr(nullptr); // 0 indicates unused
trans.set_dmi_allowed(false); // Mandatory initial value
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
if (!debug) { m_qk = new tlm_utils::tlm_quantumkeeper();
SC_THREAD(CPU_thread); m_qk->reset();
}
logger = spdlog::get("my_logger"); trans.set_command(tlm::TLM_READ_COMMAND);
} trans.set_data_ptr(reinterpret_cast<unsigned char *>(&INSTR));
trans.set_data_length(4);
trans.set_streaming_width(4); // = data_length to indicate no streaming
trans.set_byte_enable_ptr(nullptr); // 0 indicates unused
trans.set_dmi_allowed(false); // Mandatory initial value
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
CPU::~CPU() { if (!debug) {
delete register_bank; SC_THREAD(CPU_thread);
delete mem_intf;
delete exec;
delete c_inst;
delete m_inst;
delete a_inst;
delete m_qk;
}
bool CPU::cpu_process_IRQ() {
std::uint32_t csr_temp;
bool ret_value = false;
if (interrupt) {
csr_temp = register_bank->getCSR(CSR_MSTATUS);
if ((csr_temp & MSTATUS_MIE) == 0) {
logger->debug("{} ns. PC: 0x{:x}. Interrupt delayed", sc_core::sc_time_stamp().value(), register_bank->getPC());
return ret_value;
}
csr_temp = register_bank->getCSR(CSR_MIP);
if ((csr_temp & MIP_MEIP) == 0) {
csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit)
register_bank->setCSR(CSR_MIP, csr_temp);
logger->debug("{} ns. PC: 0x{:x}. Interrupt!", sc_core::sc_time_stamp().value(), register_bank->getPC());
/* updated MEPC register */
std::uint32_t old_pc = register_bank->getPC();
register_bank->setCSR(CSR_MEPC, old_pc);
logger->debug("{} ns. PC: 0x{:x}. Old PC Value 0x{:x}", sc_core::sc_time_stamp().value(), register_bank->getPC(),
old_pc);
/* update MCAUSE register */
register_bank->setCSR(CSR_MCAUSE, 0x80000000);
/* set new PC address */
std::uint32_t new_pc = register_bank->getCSR(CSR_MTVEC);
//new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0
logger->debug("{} ns. PC: 0x{:x}. NEW PC Value 0x{:x}", sc_core::sc_time_stamp().value(), register_bank->getPC(),
new_pc);
register_bank->setPC(new_pc);
ret_value = true;
interrupt = false;
irq_already_down = false;
}
} else {
if (!irq_already_down) {
csr_temp = register_bank->getCSR(CSR_MIP);
csr_temp &= ~MIP_MEIP;
register_bank->setCSR(CSR_MIP, csr_temp);
irq_already_down = true;
}
}
return ret_value;
}
bool CPU::CPU_step() {
bool PC_not_affected = false;
/* Get new PC value */
if (dmi_ptr_valid) {
/* if memory_offset at Memory module is set, this won't work */
std::memcpy(&INSTR, dmi_ptr + register_bank->getPC(), 4);
} else {
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
tlm::tlm_dmi dmi_data;
trans.set_address(register_bank->getPC());
instr_bus->b_transport(trans, delay);
if (trans.is_response_error()) {
SC_REPORT_ERROR("CPU base", "Read memory");
}
if (trans.is_dmi_allowed()) {
dmi_ptr_valid = instr_bus->get_direct_mem_ptr(trans, dmi_data);
if (dmi_ptr_valid) {
std::cout << "Get DMI_PTR " << std::endl;
dmi_ptr = dmi_data.get_dmi_ptr();
}
}
}
perf->codeMemoryRead();
inst.setInstr(INSTR);
bool breakpoint = false;
/* check what type of instruction is and execute it */
switch (inst.check_extension()) {
[[likely]] case BASE_EXTENSION:
PC_not_affected = exec->process_instruction(inst, &breakpoint);
if (PC_not_affected) {
register_bank->incPC();
} }
break;
case C_EXTENSION: logger = spdlog::get("my_logger");
PC_not_affected = c_inst->process_instruction(inst, &breakpoint); }
if (PC_not_affected) {
register_bank->incPCby2(); CPU::~CPU() {
delete register_bank;
delete mem_intf;
delete exec;
delete c_inst;
delete m_inst;
delete a_inst;
delete m_qk;
}
bool CPU::cpu_process_IRQ() {
std::uint32_t csr_temp;
bool ret_value = false;
if (interrupt) {
csr_temp = register_bank->getCSR(CSR_MSTATUS);
if ((csr_temp & MSTATUS_MIE) == 0) {
logger->debug("{} ns. PC: 0x{:x}. Interrupt delayed", sc_core::sc_time_stamp().value(),
register_bank->getPC());
return ret_value;
}
csr_temp = register_bank->getCSR(CSR_MIP);
if ((csr_temp & MIP_MEIP) == 0) {
csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit)
register_bank->setCSR(CSR_MIP, csr_temp);
logger->debug("{} ns. PC: 0x{:x}. Interrupt!", sc_core::sc_time_stamp().value(),
register_bank->getPC());
/* updated MEPC register */
std::uint32_t old_pc = register_bank->getPC();
register_bank->setCSR(CSR_MEPC, old_pc);
logger->debug("{} ns. PC: 0x{:x}. Old PC Value 0x{:x}", sc_core::sc_time_stamp().value(),
register_bank->getPC(),
old_pc);
/* update MCAUSE register */
register_bank->setCSR(CSR_MCAUSE, 0x80000000);
/* set new PC address */
std::uint32_t new_pc = register_bank->getCSR(CSR_MTVEC);
//new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0
logger->debug("{} ns. PC: 0x{:x}. NEW PC Value 0x{:x}", sc_core::sc_time_stamp().value(),
register_bank->getPC(),
new_pc);
register_bank->setPC(new_pc);
ret_value = true;
interrupt = false;
irq_already_down = false;
}
} else {
if (!irq_already_down) {
csr_temp = register_bank->getCSR(CSR_MIP);
csr_temp &= ~MIP_MEIP;
register_bank->setCSR(CSR_MIP, csr_temp);
irq_already_down = true;
}
} }
break;
case M_EXTENSION: return ret_value;
PC_not_affected = m_inst->process_instruction(inst); }
if (PC_not_affected) {
register_bank->incPC(); bool CPU::CPU_step() {
bool PC_not_affected = false;
/* Get new PC value */
if (dmi_ptr_valid) {
/* if memory_offset at Memory module is set, this won't work */
std::memcpy(&INSTR, dmi_ptr + register_bank->getPC(), 4);
} else {
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
tlm::tlm_dmi dmi_data;
trans.set_address(register_bank->getPC());
instr_bus->b_transport(trans, delay);
if (trans.is_response_error()) {
SC_REPORT_ERROR("CPU base", "Read memory");
}
if (trans.is_dmi_allowed()) {
dmi_ptr_valid = instr_bus->get_direct_mem_ptr(trans, dmi_data);
if (dmi_ptr_valid) {
std::cout << "Get DMI_PTR " << std::endl;
dmi_ptr = dmi_data.get_dmi_ptr();
}
}
} }
break;
case A_EXTENSION: perf->codeMemoryRead();
PC_not_affected = a_inst->process_instruction(inst); inst.setInstr(INSTR);
if (PC_not_affected) { bool breakpoint = false;
register_bank->incPC();
/* check what type of instruction is and execute it */
switch (inst.check_extension()) {
[[likely]] case BASE_EXTENSION:
PC_not_affected = exec->process_instruction(inst, &breakpoint);
if (PC_not_affected) {
register_bank->incPC();
}
break;
case C_EXTENSION:
PC_not_affected = c_inst->process_instruction(inst, &breakpoint);
if (PC_not_affected) {
register_bank->incPCby2();
}
break;
case M_EXTENSION:
PC_not_affected = m_inst->process_instruction(inst);
if (PC_not_affected) {
register_bank->incPC();
}
break;
case A_EXTENSION:
PC_not_affected = a_inst->process_instruction(inst);
if (PC_not_affected) {
register_bank->incPC();
}
break;
[[unlikely]] default:
std::cout << "Extension not implemented yet" << std::endl;
inst.dump();
exec->NOP();
} }
break;
[[unlikely]] default:
std::cout << "Extension not implemented yet" << std::endl;
inst.dump();
exec->NOP();
}
if (breakpoint) { if (breakpoint) {
std::cout << "Breakpoint set to true\n"; std::cout << "Breakpoint set to true\n";
} }
perf->instructionsInc(); perf->instructionsInc();
return breakpoint; return breakpoint;
} }
[[noreturn]] void CPU::CPU_thread() { [[noreturn]] void CPU::CPU_thread() {
sc_core::sc_time instr_time = default_time; sc_core::sc_time instr_time = default_time;
while (true) { while (true) {
/* Process one instruction */ /* Process one instruction */
CPU_step(); CPU_step();
/* Process IRQ (if any) */ /* Process IRQ (if any) */
cpu_process_IRQ(); cpu_process_IRQ();
/* Fixed instruction time to 10 ns (i.e. 100 MHz) */ /* Fixed instruction time to 10 ns (i.e. 100 MHz) */
//#define USE_QK //#define USE_QK
#ifdef USE_QK #ifdef USE_QK
// Model time used for additional processing // Model time used for additional processing
m_qk->inc(default_time); m_qk->inc(default_time);
if (m_qk->need_sync()) { if (m_qk->need_sync()) {
m_qk->sync(); m_qk->sync();
} }
#else #else
sc_core::wait(instr_time); sc_core::wait(instr_time);
#endif #endif
} // while(1) } // while(1)
} // CPU_thread } // CPU_thread
void CPU::call_interrupt(tlm::tlm_generic_payload &m_trans, void CPU::call_interrupt(tlm::tlm_generic_payload &m_trans,
sc_core::sc_time &delay) { sc_core::sc_time &delay) {
interrupt = true; interrupt = true;
/* Socket caller send a cause (its id) */ /* Socket caller send a cause (its id) */
memcpy(&int_cause, m_trans.get_data_ptr(), sizeof(std::uint32_t)); memcpy(&int_cause, m_trans.get_data_ptr(), sizeof(std::uint32_t));
delay = sc_core::SC_ZERO_TIME; delay = sc_core::SC_ZERO_TIME;
} }
void CPU::invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end) { void CPU::invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end) {
(void) start; (void) start;
(void) end; (void) end;
dmi_ptr_valid = false; dmi_ptr_valid = false;
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -18,234 +18,238 @@
#include "Debug.h" #include "Debug.h"
constexpr char nibble_to_hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', namespace riscv_tlm {
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
Debug::Debug(CPU *cpu, Memory* mem): sc_module(sc_core::sc_module_name("Debug")) { constexpr char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
dbg_cpu = cpu; '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
dbg_mem = mem;
int sock = socket(AF_INET, SOCK_STREAM, 0); Debug::Debug(riscv_tlm::CPU *cpu, Memory *mem) : sc_module(sc_core::sc_module_name("Debug")) {
dbg_cpu = cpu;
dbg_mem = mem;
int optval = 1; int sock = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval));
sockaddr_in addr; int optval = 1;
addr.sin_family = AF_INET; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval,
addr.sin_addr.s_addr = INADDR_ANY; sizeof(optval));
addr.sin_port = htons(1234);
bind(sock, (struct sockaddr *) &addr, sizeof(addr)); sockaddr_in addr;
listen(sock, 1); addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(1234);
socklen_t len = sizeof(addr); bind(sock, (struct sockaddr *) &addr, sizeof(addr));
conn = accept(sock, (struct sockaddr *) &addr, &len); listen(sock, 1);
handle_gdb_loop(); socklen_t len = sizeof(addr);
} conn = accept(sock, (struct sockaddr *) &addr, &len);
Debug::~Debug() { handle_gdb_loop();
}
Debug::~Debug() {
}
void Debug::send_packet(int conn, const std::string &msg) {
std::string frame = "+$" + msg + "#" + compute_checksum_string(msg);
memcpy(iobuf, frame.c_str(), frame.size());
::send(conn, iobuf, frame.size(), 0);
}
std::string Debug::receive_packet() {
int nbytes = ::recv(conn, iobuf, bufsize, 0);
if (nbytes == 0) {
return "";
} else if (nbytes == 1) {
return std::string("+");
} else {
char *start = strchr(iobuf, '$');
char *end = strchr(iobuf, '#');
std::string message(start + 1, end - (start + 1));
return message;
}
}
void Debug::handle_gdb_loop() {
std::cout << "Handle_GDB_Loop\n";
Registers *register_bank = dbg_cpu->getRegisterBank();
while (true) {
std::string msg = receive_packet();
if (msg.size() == 0) {
std::cout << "remote connection seems to be closed, terminating ..."
<< std::endl;
break;
} else if (msg == "+") {
// NOTE: just ignore this message, nothing to do in this case
} else if (boost::starts_with(msg, "qSupported")) {
send_packet(conn, "PacketSize=256;swbreak+;hwbreak+;vContSupported+;multiprocess-");
} else if (msg == "vMustReplyEmpty") {
send_packet(conn, "");
} else if (msg == "Hg0") {
send_packet(conn, "OK");
} else if (msg == "Hc0") {
send_packet(conn, "");
} else if (msg == "qTStatus") {
send_packet(conn, "");
} else if (msg == "?") {
send_packet(conn, "S05");
} else if (msg == "qfThreadInfo") {
send_packet(conn, "");
} else if (boost::starts_with(msg, "qL")) {
send_packet(conn, "");
} else if (msg == "Hc-1") {
send_packet(conn, "OK");
} else if (msg == "qC") {
send_packet(conn, "-1");
} else if (msg == "qAttached") {
send_packet(conn, "0"); // 0 process started, 1 attached to process
} else if (msg == "g") {
std::stringstream stream;
stream << std::setfill('0') << std::hex;
for (int i = 1; i < 32; i++) {
stream << std::setw(8) << register_bank->getValue(i);
}
send_packet(conn, stream.str());
} else if (boost::starts_with(msg, "p")) {
long n = strtol(msg.c_str() + 1, 0, 16);
int reg_value;
if (n < 32) {
reg_value = register_bank->getValue(n);
} else if (n == 32) {
reg_value = register_bank->getPC();
} else {
// see: https://github.com/riscv/riscv-gnu-toolchain/issues/217
// risc-v register 834
reg_value = register_bank->getCSR(n - 65);
}
std::stringstream stream;
stream << std::setfill('0') << std::hex;
stream << std::setw(8) << htonl(reg_value);
send_packet(conn, stream.str());
} else if (boost::starts_with(msg, "P")) {
char *pEnd;
long reg = strtol(msg.c_str() + 1, &pEnd, 16);
int val = strtol(pEnd + 1, 0, 16);
register_bank->setValue(reg + 1, val);
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "m")) {
char *pEnd;
long addr = strtol(msg.c_str() + 1, &pEnd, 16);;
int len = strtol(pEnd + 1, &pEnd, 16);
dbg_trans.set_data_ptr(pyld_array);
dbg_trans.set_command(tlm::TLM_READ_COMMAND);
dbg_trans.set_address(addr);
dbg_trans.set_data_length(len);
dbg_mem->transport_dbg(dbg_trans);
std::stringstream stream;
stream << std::setfill('0') << std::hex;
for (auto &c: pyld_array) {
stream << std::setw(2) << (0xFF & c);
}
send_packet(conn, stream.str());
} else if (boost::starts_with(msg, "M")) {
printf("M TBD\n");
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "X")) {
send_packet(conn, ""); // binary data unsupported
} else if (msg == "qOffsets") {
send_packet(conn, "Text=0;Data=0;Bss=0");
} else if (msg == "qSymbol::") {
send_packet(conn, "OK");
} else if (msg == "vCont?") {
send_packet(conn, "vCont;cs");
} else if (msg == "c") {
bool breakpoint_hit = false;
bool bkpt = false;
do {
bkpt = dbg_cpu->CPU_step();
uint32_t currentPC = register_bank->getPC();
auto search = breakpoints.find(currentPC);
if (search != breakpoints.end()) {
breakpoint_hit = true;
}
} while ((breakpoint_hit == false) && (bkpt == false));
std::cout << "Breakpoint hit at 0x" << std::hex << register_bank->getPC() << std::endl;
send_packet(conn, "S05");
} else if (msg == "s") {
bool breakpoint;
dbg_cpu->CPU_step();
uint32_t currentPC = register_bank->getPC();
auto search = breakpoints.find(currentPC);
if (search != breakpoints.end()) {
breakpoint = true;
} else {
breakpoint = false;
}
if (breakpoint) {
send_packet(conn, "S03");
} else {
send_packet(conn, "S05");
}
} else if (boost::starts_with(msg, "vKill")) {
send_packet(conn, "OK");
break;
} else if (boost::starts_with(msg, "Z1")) {
char *pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
breakpoints.insert(addr);
std::cout << "Breakpoint set to address 0x" << std::hex << addr << std::endl;
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "z1")) {
char *pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
breakpoints.erase(addr);
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "z0")) {
char *pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
breakpoints.erase(addr);
send_packet(conn, "");
} else if (boost::starts_with(msg, "Z0")) {
char *pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
breakpoints.insert(addr);
std::cout << "Breakpoint set to address 0x" << std::hex << addr << std::endl;
send_packet(conn, "OK");
} else {
std::cout << "unsupported message '" << msg
<< "' detected, terminating ..." << std::endl;
break;
}
}
}
std::string Debug::compute_checksum_string(const std::string &msg) {
unsigned sum = 0;
for (auto c: msg) {
sum += unsigned(c);
}
sum = sum % 256;
char low = nibble_to_hex[sum & 0xf];
char high = nibble_to_hex[(sum & (0xf << 4)) >> 4];
return {high, low};
}
} }
void Debug::send_packet(int conn, const std::string &msg) {
std::string frame = "+$" + msg + "#" + compute_checksum_string(msg);
memcpy(iobuf, frame.c_str(), frame.size());
::send(conn, iobuf, frame.size(), 0);
}
std::string Debug::receive_packet() {
int nbytes = ::recv(conn, iobuf, bufsize, 0);
if (nbytes == 0) {
return "";
} else if (nbytes == 1) {
return std::string("+");
} else {
char *start = strchr(iobuf, '$');
char *end = strchr(iobuf, '#');
std::string message(start + 1, end - (start + 1));
return message;
}
}
void Debug::handle_gdb_loop() {
std::cout << "Handle_GDB_Loop\n";
Registers *register_bank = dbg_cpu->getRegisterBank();
while (true) {
std::string msg = receive_packet();
if (msg.size() == 0) {
std::cout << "remote connection seems to be closed, terminating ..."
<< std::endl;
break;
} else if (msg == "+") {
// NOTE: just ignore this message, nothing to do in this case
} else if (boost::starts_with(msg, "qSupported")) {
send_packet(conn, "PacketSize=256;swbreak+;hwbreak+;vContSupported+;multiprocess-");
} else if (msg == "vMustReplyEmpty") {
send_packet(conn, "");
} else if (msg == "Hg0") {
send_packet(conn, "OK");
} else if (msg == "Hc0") {
send_packet(conn, "");
} else if (msg == "qTStatus") {
send_packet(conn, "");
} else if (msg == "?") {
send_packet(conn, "S05");
} else if (msg == "qfThreadInfo") {
send_packet(conn, "");
} else if (boost::starts_with(msg, "qL")) {
send_packet(conn, "");
} else if (msg == "Hc-1") {
send_packet(conn, "OK");
} else if (msg == "qC") {
send_packet(conn, "-1");
} else if (msg == "qAttached") {
send_packet(conn, "0"); // 0 process started, 1 attached to process
} else if (msg == "g") {
std::stringstream stream;
stream << std::setfill('0') << std::hex;
for (int i = 1; i < 32; i++) {
stream << std::setw(8) << register_bank->getValue(i);
}
send_packet(conn, stream.str());
} else if (boost::starts_with(msg, "p")) {
long n = strtol(msg.c_str() + 1, 0, 16);
int reg_value;
if (n < 32) {
reg_value = register_bank->getValue(n);
} else if (n == 32) {
reg_value = register_bank->getPC();
} else {
// see: https://github.com/riscv/riscv-gnu-toolchain/issues/217
// risc-v register 834
reg_value = register_bank->getCSR(n - 65);
}
std::stringstream stream;
stream << std::setfill('0') << std::hex;
stream << std::setw(8) << htonl(reg_value);
send_packet(conn, stream.str());
} else if (boost::starts_with(msg, "P")) {
char * pEnd;
long reg = strtol(msg.c_str() + 1, &pEnd, 16);
int val = strtol(pEnd + 1, 0, 16);
register_bank->setValue(reg + 1, val);
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "m")) {
char * pEnd;
long addr = strtol(msg.c_str() + 1, &pEnd, 16);;
int len = strtol(pEnd + 1, &pEnd, 16);
dbg_trans.set_data_ptr(pyld_array);
dbg_trans.set_command(tlm::TLM_READ_COMMAND);
dbg_trans.set_address(addr);
dbg_trans.set_data_length(len);
dbg_mem->transport_dbg(dbg_trans);
std::stringstream stream;
stream << std::setfill('0') << std::hex;
for (auto &c : pyld_array) {
stream << std::setw(2) << (0xFF & c);
}
send_packet(conn, stream.str());
} else if (boost::starts_with(msg, "M")) {
printf("M TBD\n");
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "X")) {
send_packet(conn, ""); // binary data unsupported
} else if (msg == "qOffsets") {
send_packet(conn, "Text=0;Data=0;Bss=0");
} else if (msg == "qSymbol::") {
send_packet(conn, "OK");
} else if (msg == "vCont?") {
send_packet(conn, "vCont;cs");
} else if (msg == "c") {
bool breakpoint_hit = false;
bool bkpt = false;
do {
bkpt = dbg_cpu->CPU_step();
uint32_t currentPC = register_bank->getPC();
auto search = breakpoints.find(currentPC);
if (search != breakpoints.end()) {
breakpoint_hit = true;
}
} while ((breakpoint_hit == false) && (bkpt == false));
std::cout << "Breakpoint hit at 0x" << std::hex << register_bank->getPC() << std::endl;
send_packet(conn, "S05");
} else if (msg == "s") {
bool breakpoint;
dbg_cpu->CPU_step();
uint32_t currentPC = register_bank->getPC();
auto search = breakpoints.find(currentPC);
if (search != breakpoints.end()) {
breakpoint = true;
} else {
breakpoint = false;
}
if (breakpoint) {
send_packet(conn, "S03");
} else {
send_packet(conn, "S05");
}
} else if (boost::starts_with(msg, "vKill")) {
send_packet(conn, "OK");
break;
} else if (boost::starts_with(msg, "Z1")) {
char * pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
breakpoints.insert(addr);
std::cout << "Breakpoint set to address 0x"<< std::hex << addr << std::endl;
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "z1")) {
char * pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
breakpoints.erase(addr);
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "z0")) {
char * pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
breakpoints.erase(addr);
send_packet(conn, "");
} else if (boost::starts_with(msg, "Z0")) {
char * pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
breakpoints.insert(addr);
std::cout << "Breakpoint set to address 0x"<< std::hex << addr << std::endl;
send_packet(conn, "OK");
} else {
std::cout << "unsupported message '" << msg
<< "' detected, terminating ..." << std::endl;
break;
}
}
}
std::string Debug::compute_checksum_string(const std::string &msg) {
unsigned sum = 0;
for (auto c : msg) {
sum += unsigned(c);
}
sum = sum % 256;
char low = nibble_to_hex[sum & 0xf];
char high = nibble_to_hex[(sum & (0xf << 4)) >> 4];
return {high, low};
}

View File

@ -8,26 +8,28 @@
#include "Instruction.h" #include "Instruction.h"
Instruction::Instruction(std::uint32_t instr) { namespace riscv_tlm {
m_instr = instr;
Instruction::Instruction(std::uint32_t instr) {
m_instr = instr;
}
extension_t Instruction::check_extension() const {
if (((m_instr & 0x0000007F) == 0b0110011)
&& (((m_instr & 0x7F000000) >> 25) == 0b0000001)) {
return M_EXTENSION;
} else if ((m_instr & 0x0000007F) == 0b0101111) {
return A_EXTENSION;
} else if ((m_instr & 0x00000003) == 0b00) {
return C_EXTENSION;
} else if ((m_instr & 0x00000003) == 0b01) {
return C_EXTENSION;
} else if ((m_instr & 0x00000003) == 0b10) {
return C_EXTENSION;
} else {
return BASE_EXTENSION;
}
}
} }
extension_t Instruction::check_extension() const {
if (((m_instr & 0x0000007F) == 0b0110011)
&& ( ((m_instr & 0x7F000000) >> 25) == 0b0000001)) {
return M_EXTENSION;
} else if ((m_instr & 0x0000007F) == 0b0101111) {
return A_EXTENSION;
} else if ((m_instr & 0x00000003) == 0b00) {
return C_EXTENSION;
} else if ((m_instr & 0x00000003) == 0b01) {
return C_EXTENSION;
} else if ((m_instr & 0x00000003) == 0b10) {
return C_EXTENSION;
} else {
return BASE_EXTENSION;
}
}

View File

@ -8,280 +8,292 @@
#include "M_extension.h" #include "M_extension.h"
op_M_Codes M_extension::decode() const { namespace riscv_tlm {
switch (opcode()) { op_M_Codes M_extension::decode() const {
case M_MUL:
return OP_M_MUL; switch (opcode()) {
break; case M_MUL:
case M_MULH: return OP_M_MUL;
return OP_M_MULH; break;
break; case M_MULH:
case M_MULHSU: return OP_M_MULH;
return OP_M_MULHSU; break;
break; case M_MULHSU:
case M_MULHU: return OP_M_MULHSU;
return OP_M_MULHU; break;
break; case M_MULHU:
case M_DIV: return OP_M_MULHU;
return OP_M_DIV; break;
break; case M_DIV:
case M_DIVU: return OP_M_DIV;
return OP_M_DIVU; break;
break; case M_DIVU:
case M_REM: return OP_M_DIVU;
return OP_M_REM; break;
break; case M_REM:
case M_REMU: return OP_M_REM;
return OP_M_REMU; break;
break; case M_REMU:
[[unlikely]] default: return OP_M_REMU;
return OP_M_ERROR; break;
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;
}
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;
} }

View File

@ -8,194 +8,199 @@
#include "Memory.h" #include "Memory.h"
SC_HAS_PROCESS(Memory); namespace riscv_tlm {
Memory::Memory(sc_core::sc_module_name const &name, std::string const &filename) :
sc_module(name), socket("socket"), LATENCY(sc_core::SC_ZERO_TIME) {
// Register callbacks for incoming interface method calls
socket.register_b_transport(this, &Memory::b_transport);
socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr);
socket.register_transport_dbg(this, &Memory::transport_dbg);
dmi_allowed = false; SC_HAS_PROCESS(Memory);
program_counter = 0;
readHexFile(filename);
logger = spdlog::get("my_logger"); Memory::Memory(sc_core::sc_module_name const &name, std::string const &filename) :
logger->debug("Using file {}", filename); sc_module(name), socket("socket"), LATENCY(sc_core::SC_ZERO_TIME) {
} // Register callbacks for incoming interface method calls
socket.register_b_transport(this, &Memory::b_transport);
socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr);
socket.register_transport_dbg(this, &Memory::transport_dbg);
Memory::Memory(sc_core::sc_module_name const& name) : dmi_allowed = false;
sc_module(name), socket("socket"), LATENCY(sc_core::SC_ZERO_TIME) { program_counter = 0;
socket.register_b_transport(this, &Memory::b_transport); readHexFile(filename);
socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr);
socket.register_transport_dbg(this, &Memory::transport_dbg);
program_counter = 0; logger = spdlog::get("my_logger");
logger->debug("Using file {}", filename);
logger = spdlog::get("my_logger");
logger->debug("Memory instantiated wihtout file");
}
Memory::~Memory() = default;
std::uint32_t Memory::getPCfromHEX() {
return program_counter;
}
void Memory::b_transport(tlm::tlm_generic_payload &trans,
sc_core::sc_time &delay) {
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 adr = trans.get_address();
unsigned char *ptr = trans.get_data_ptr();
unsigned int len = trans.get_data_length();
unsigned char *byt = trans.get_byte_enable_ptr();
unsigned int wid = trans.get_streaming_width();
// *********************************************
// Generate the appropriate error response
// *********************************************
if (adr >= sc_dt::uint64(Memory::SIZE)) {
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
return;
}
if (byt != nullptr) {
trans.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE);
return;
}
if (len > 4 || wid < len) {
trans.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE);
return;
}
// Obliged to implement read and write commands
if (cmd == tlm::TLM_READ_COMMAND) {
std::copy_n(mem.cbegin() + adr, len, ptr);
} else if (cmd == tlm::TLM_WRITE_COMMAND) {
std::copy_n(ptr, len, mem.begin() + adr);
} }
// Illustrates that b_transport may block Memory::Memory(sc_core::sc_module_name const &name) :
//sc_core::wait(delay); sc_module(name), socket("socket"), LATENCY(sc_core::SC_ZERO_TIME) {
socket.register_b_transport(this, &Memory::b_transport);
socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr);
socket.register_transport_dbg(this, &Memory::transport_dbg);
// Reset timing annotation after waiting program_counter = 0;
delay = sc_core::SC_ZERO_TIME;
// ********************************************* logger = spdlog::get("my_logger");
// Set DMI hint to indicated that DMI is supported logger->debug("Memory instantiated wihtout file");
// *********************************************
trans.set_dmi_allowed(dmi_allowed);
// Obliged to set response status to indicate successful completion
trans.set_response_status(tlm::TLM_OK_RESPONSE);
}
bool Memory::get_direct_mem_ptr(tlm::tlm_generic_payload &trans,
tlm::tlm_dmi &dmi_data) {
(void) trans;
if (!dmi_allowed) {
return false;
}
// Permit read and write access
dmi_data.allow_read_write();
// Set other details of DMI region
dmi_data.set_dmi_ptr(reinterpret_cast<unsigned char*>(&mem[0]));
dmi_data.set_start_address(0);
dmi_data.set_end_address(Memory::SIZE * 4 - 1);
dmi_data.set_read_latency(LATENCY);
dmi_data.set_write_latency(LATENCY);
return true;
}
unsigned int Memory::transport_dbg(tlm::tlm_generic_payload &trans) {
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 adr = trans.get_address();
unsigned char *ptr = trans.get_data_ptr();
unsigned int len = trans.get_data_length();
if (adr >= sc_dt::uint64(Memory::SIZE)) {
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
return 0;
}
// Calculate the number of bytes to be actually copied
unsigned int num_bytes = (len < (Memory::SIZE - adr) * 4) ? len : (Memory::SIZE - adr) * 4;
if (cmd == tlm::TLM_READ_COMMAND) {
std::copy_n(mem.cbegin() + adr, len, ptr);
} else if (cmd == tlm::TLM_WRITE_COMMAND) {
std::copy_n(ptr, len, mem.begin() + adr);
} }
return num_bytes; Memory::~Memory() = default;
}
void Memory::readHexFile(std::string const& filename) { std::uint32_t Memory::getPCfromHEX() {
std::ifstream hexfile; return program_counter;
std::string line;
std::uint32_t memory_offset = 0;
hexfile.open(filename); }
if (hexfile.is_open()) { void Memory::b_transport(tlm::tlm_generic_payload &trans,
std::uint32_t extended_address = 0; sc_core::sc_time &delay) {
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 adr = trans.get_address();
unsigned char *ptr = trans.get_data_ptr();
unsigned int len = trans.get_data_length();
unsigned char *byt = trans.get_byte_enable_ptr();
unsigned int wid = trans.get_streaming_width();
while (getline(hexfile, line)) { // *********************************************
if (line[0] == ':') { // Generate the appropriate error response
if (line.substr(7, 2) == "00") { // *********************************************
/* Data */ if (adr >= sc_dt::uint64(Memory::SIZE)) {
int byte_count; trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
std::uint32_t address; return;
byte_count = std::stoi(line.substr(1, 2), nullptr, 16); }
address = std::stoi(line.substr(3, 4), nullptr, 16); if (byt != nullptr) {
address = address + extended_address + memory_offset; trans.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE);
return;
for (int i = 0; i < byte_count; i++) { }
mem[address + i] = stol(line.substr(9 + (i * 2), 2), if (len > 4 || wid < len) {
nullptr, 16); trans.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE);
} return;
} else if (line.substr(7, 2) == "02") {
/* Extended segment address */
extended_address = stol(line.substr(9, 4), nullptr, 16)
* 16;
std::cout << "02 extended address 0x" << std::hex
<< extended_address << std::dec << std::endl;
} else if (line.substr(7, 2) == "03") {
/* Start segment address */
std::uint32_t code_segment;
code_segment = stol(line.substr(9, 4), nullptr, 16) * 16; /* ? */
program_counter = stol(line.substr(13, 4), nullptr, 16);
program_counter = program_counter + code_segment;
std::cout << "03 PC set to 0x" << std::hex
<< program_counter << std::dec << std::endl;
} else if (line.substr(7, 2) == "04") {
/* Start segment address */
memory_offset = stol(line.substr(9, 4), nullptr, 16) << 16;
extended_address = 0;
std::cout << "04 address set to 0x" << std::hex
<< extended_address << std::dec << std::endl;
std::cout << "04 offset set to 0x" << std::hex
<< memory_offset << std::dec << std::endl;
} else if (line.substr(7, 2) == "05") {
program_counter = stol(line.substr(9, 8), nullptr, 16);
std::cout << "05 PC set to 0x" << std::hex
<< program_counter << std::dec << std::endl;
}
}
}
hexfile.close();
if (memory_offset != 0) {
dmi_allowed = false;
} else {
dmi_allowed = true;
} }
} else { // Obliged to implement read and write commands
SC_REPORT_ERROR("Memory", "Open file error"); if (cmd == tlm::TLM_READ_COMMAND) {
} std::copy_n(mem.cbegin() + adr, len, ptr);
} else if (cmd == tlm::TLM_WRITE_COMMAND) {
std::copy_n(ptr, len, mem.begin() + adr);
}
// Illustrates that b_transport may block
//sc_core::wait(delay);
// Reset timing annotation after waiting
delay = sc_core::SC_ZERO_TIME;
// *********************************************
// Set DMI hint to indicated that DMI is supported
// *********************************************
trans.set_dmi_allowed(dmi_allowed);
// Obliged to set response status to indicate successful completion
trans.set_response_status(tlm::TLM_OK_RESPONSE);
}
bool Memory::get_direct_mem_ptr(tlm::tlm_generic_payload &trans,
tlm::tlm_dmi &dmi_data) {
(void) trans;
if (!dmi_allowed) {
return false;
}
// Permit read and write access
dmi_data.allow_read_write();
// Set other details of DMI region
dmi_data.set_dmi_ptr(reinterpret_cast<unsigned char *>(&mem[0]));
dmi_data.set_start_address(0);
dmi_data.set_end_address(Memory::SIZE * 4 - 1);
dmi_data.set_read_latency(LATENCY);
dmi_data.set_write_latency(LATENCY);
return true;
}
unsigned int Memory::transport_dbg(tlm::tlm_generic_payload &trans) {
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 adr = trans.get_address();
unsigned char *ptr = trans.get_data_ptr();
unsigned int len = trans.get_data_length();
if (adr >= sc_dt::uint64(Memory::SIZE)) {
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
return 0;
}
// Calculate the number of bytes to be actually copied
unsigned int num_bytes = (len < (Memory::SIZE - adr) * 4) ? len : (Memory::SIZE - adr) * 4;
if (cmd == tlm::TLM_READ_COMMAND) {
std::copy_n(mem.cbegin() + adr, len, ptr);
} else if (cmd == tlm::TLM_WRITE_COMMAND) {
std::copy_n(ptr, len, mem.begin() + adr);
}
return num_bytes;
}
void Memory::readHexFile(std::string const &filename) {
std::ifstream hexfile;
std::string line;
std::uint32_t memory_offset = 0;
hexfile.open(filename);
if (hexfile.is_open()) {
std::uint32_t extended_address = 0;
while (getline(hexfile, line)) {
if (line[0] == ':') {
if (line.substr(7, 2) == "00") {
/* Data */
int byte_count;
std::uint32_t address;
byte_count = std::stoi(line.substr(1, 2), nullptr, 16);
address = std::stoi(line.substr(3, 4), nullptr, 16);
address = address + extended_address + memory_offset;
for (int i = 0; i < byte_count; i++) {
mem[address + i] = stol(line.substr(9 + (i * 2), 2),
nullptr, 16);
}
} else if (line.substr(7, 2) == "02") {
/* Extended segment address */
extended_address = stol(line.substr(9, 4), nullptr, 16)
* 16;
std::cout << "02 extended address 0x" << std::hex
<< extended_address << std::dec << std::endl;
} else if (line.substr(7, 2) == "03") {
/* Start segment address */
std::uint32_t code_segment;
code_segment = stol(line.substr(9, 4), nullptr, 16) * 16; /* ? */
program_counter = stol(line.substr(13, 4), nullptr, 16);
program_counter = program_counter + code_segment;
std::cout << "03 PC set to 0x" << std::hex
<< program_counter << std::dec << std::endl;
} else if (line.substr(7, 2) == "04") {
/* Start segment address */
memory_offset = stol(line.substr(9, 4), nullptr, 16) << 16;
extended_address = 0;
std::cout << "04 address set to 0x" << std::hex
<< extended_address << std::dec << std::endl;
std::cout << "04 offset set to 0x" << std::hex
<< memory_offset << std::dec << std::endl;
} else if (line.substr(7, 2) == "05") {
program_counter = stol(line.substr(9, 8), nullptr, 16);
std::cout << "05 PC set to 0x" << std::hex
<< program_counter << std::dec << std::endl;
}
}
}
hexfile.close();
if (memory_offset != 0) {
dmi_allowed = false;
} else {
dmi_allowed = true;
}
} else {
SC_REPORT_ERROR("Memory", "Open file error");
}
}
} }

View File

@ -8,9 +8,10 @@
#include "MemoryInterface.h" #include "MemoryInterface.h"
namespace riscv_tlm {
MemoryInterface::MemoryInterface() : MemoryInterface::MemoryInterface() :
data_bus("data_bus") {} data_bus("data_bus") {}
/** /**
* Access data memory to get data * Access data memory to get data
@ -18,27 +19,27 @@ MemoryInterface::MemoryInterface() :
* @param size size of the data to read in bytes * @param size size of the data to read in bytes
* @return data value read * @return data value read
*/ */
std::uint32_t MemoryInterface::readDataMem(std::uint32_t addr, int size) { std::uint32_t MemoryInterface::readDataMem(std::uint32_t addr, int size) {
std::uint32_t data; std::uint32_t data;
tlm::tlm_generic_payload trans; tlm::tlm_generic_payload trans;
sc_core::sc_time delay = sc_core::SC_ZERO_TIME; sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
trans.set_command(tlm::TLM_READ_COMMAND); trans.set_command(tlm::TLM_READ_COMMAND);
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&data)); trans.set_data_ptr(reinterpret_cast<unsigned char *>(&data));
trans.set_data_length(size); trans.set_data_length(size);
trans.set_streaming_width(4); // = data_length to indicate no streaming trans.set_streaming_width(4); // = data_length to indicate no streaming
trans.set_byte_enable_ptr(nullptr); // 0 indicates unused trans.set_byte_enable_ptr(nullptr); // 0 indicates unused
trans.set_dmi_allowed(false); // Mandatory initial value trans.set_dmi_allowed(false); // Mandatory initial value
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
trans.set_address(addr); trans.set_address(addr);
data_bus->b_transport(trans, delay); data_bus->b_transport(trans, delay);
if (trans.is_response_error()) { if (trans.is_response_error()) {
SC_REPORT_ERROR("Memory", "Read memory"); SC_REPORT_ERROR("Memory", "Read memory");
} }
return data; return data;
} }
/** /**
* Acces data memory to write data * Acces data memory to write data
@ -47,18 +48,19 @@ std::uint32_t MemoryInterface::readDataMem(std::uint32_t addr, int size) {
* @param data data to write * @param data data to write
* @param size size of the data to write in bytes * @param size size of the data to write in bytes
*/ */
void MemoryInterface::writeDataMem(std::uint32_t addr, std::uint32_t data, int size) { void MemoryInterface::writeDataMem(std::uint32_t addr, std::uint32_t data, int size) {
tlm::tlm_generic_payload trans; tlm::tlm_generic_payload trans;
sc_core::sc_time delay = sc_core::SC_ZERO_TIME; sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
trans.set_command(tlm::TLM_WRITE_COMMAND); trans.set_command(tlm::TLM_WRITE_COMMAND);
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&data)); trans.set_data_ptr(reinterpret_cast<unsigned char *>(&data));
trans.set_data_length(size); trans.set_data_length(size);
trans.set_streaming_width(4); // = data_length to indicate no streaming trans.set_streaming_width(4); // = data_length to indicate no streaming
trans.set_byte_enable_ptr(nullptr); // 0 indicates unused trans.set_byte_enable_ptr(nullptr); // 0 indicates unused
trans.set_dmi_allowed(false); // Mandatory initial value trans.set_dmi_allowed(false); // Mandatory initial value
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
trans.set_address(addr); trans.set_address(addr);
data_bus->b_transport(trans, delay); data_bus->b_transport(trans, delay);
}
} }

View File

@ -8,166 +8,169 @@
#include "Registers.h" #include "Registers.h"
Registers::Registers() { namespace riscv_tlm {
perf = Performance::getInstance();
initCSR(); Registers::Registers() {
register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory perf = Performance::getInstance();
register_PC = 0x80000000; // default _start address
} initCSR();
register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory
void Registers::dump() { register_PC = 0x80000000; // default _start address
std::cout << "************************************" << std::endl; }
std::cout << "Registers dump" << std::dec << std::endl;
std::cout << std::setfill('0') << std::uppercase; void Registers::dump() {
std::cout << "x0 (zero): 0x" << std::right << std::setw(8) std::cout << "************************************" << std::endl;
<< std::hex << register_bank[0]; std::cout << "Registers dump" << std::dec << std::endl;
std::cout << " x1 (ra): 0x" << std::right << std::setw(8) std::cout << std::setfill('0') << std::uppercase;
<< std::hex << register_bank[1]; std::cout << "x0 (zero): 0x" << std::right << std::setw(8)
std::cout << " x2 (sp): 0x" << std::right << std::setw(8) << std::hex << register_bank[0];
<< std::hex << register_bank[2]; std::cout << " x1 (ra): 0x" << std::right << std::setw(8)
std::cout << " x3 (gp): 0x" << std::right << std::setw(8) << std::hex << register_bank[1];
<< std::hex << register_bank[3] << std::endl; std::cout << " x2 (sp): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[2];
std::cout << "x4 (tp): 0x" << std::right << std::setw(8) std::cout << " x3 (gp): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[4]; << std::hex << register_bank[3] << std::endl;
std::cout << " x5 (t0): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[5]; std::cout << "x4 (tp): 0x" << std::right << std::setw(8)
std::cout << " x6 (t1): 0x" << std::right << std::setw(8) << std::hex << register_bank[4];
<< std::hex << register_bank[6]; std::cout << " x5 (t0): 0x" << std::right << std::setw(8)
std::cout << " x7 (t2): 0x" << std::right << std::setw(8) << std::hex << register_bank[5];
<< std::hex << register_bank[7] << std::endl; std::cout << " x6 (t1): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[6];
std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8) std::cout << " x7 (t2): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[8]; << std::hex << register_bank[7] << std::endl;
std::cout << " x9 (s1): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[9]; std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8)
std::cout << " x10 (a0): 0x" << std::right << std::setw(8) << std::hex << register_bank[8];
<< std::hex << register_bank[10]; std::cout << " x9 (s1): 0x" << std::right << std::setw(8)
std::cout << " x11 (a1): 0x" << std::right << std::setw(8) << std::hex << register_bank[9];
<< std::hex << register_bank[11] << std::endl; std::cout << " x10 (a0): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[10];
std::cout << "x12 (a2): 0x" << std::right << std::setw(8) std::cout << " x11 (a1): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[12]; << std::hex << register_bank[11] << std::endl;
std::cout << " x13 (a3): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[13]; std::cout << "x12 (a2): 0x" << std::right << std::setw(8)
std::cout << " x14 (a4): 0x" << std::right << std::setw(8) << std::hex << register_bank[12];
<< std::hex << register_bank[14]; std::cout << " x13 (a3): 0x" << std::right << std::setw(8)
std::cout << " x15 (a5): 0x" << std::right << std::setw(8) << std::hex << register_bank[13];
<< std::hex << register_bank[15] << std::endl; std::cout << " x14 (a4): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[14];
std::cout << "x16 (a6): 0x" << std::right << std::setw(8) std::cout << " x15 (a5): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[16]; << std::hex << register_bank[15] << std::endl;
std::cout << " x17 (a7): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[17]; std::cout << "x16 (a6): 0x" << std::right << std::setw(8)
std::cout << " x18 (s2): 0x" << std::right << std::setw(8) << std::hex << register_bank[16];
<< std::hex << register_bank[18]; std::cout << " x17 (a7): 0x" << std::right << std::setw(8)
std::cout << " x19 (s3): 0x" << std::right << std::setw(8) << std::hex << register_bank[17];
<< std::hex << register_bank[19] << std::endl; std::cout << " x18 (s2): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[18];
std::cout << "x20 (s4): 0x" << std::right << std::setw(8) std::cout << " x19 (s3): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[20]; << std::hex << register_bank[19] << std::endl;
std::cout << " x21 (s5): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[21]; std::cout << "x20 (s4): 0x" << std::right << std::setw(8)
std::cout << " x22 (s6): 0x" << std::right << std::setw(8) << std::hex << register_bank[20];
<< std::hex << register_bank[22]; std::cout << " x21 (s5): 0x" << std::right << std::setw(8)
std::cout << " x23 (s7): 0x" << std::right << std::setw(8) << std::hex << register_bank[21];
<< std::hex << register_bank[23] << std::endl; std::cout << " x22 (s6): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[22];
std::cout << "x24 (s8): 0x" << std::right << std::setw(8) std::cout << " x23 (s7): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[24]; << std::hex << register_bank[23] << std::endl;
std::cout << " x25 (s9): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[25]; std::cout << "x24 (s8): 0x" << std::right << std::setw(8)
std::cout << " x26 (s10): 0x" << std::right << std::setw(8) << std::hex << register_bank[24];
<< std::hex << register_bank[26]; std::cout << " x25 (s9): 0x" << std::right << std::setw(8)
std::cout << " x27 (s11): 0x" << std::right << std::setw(8) << std::hex << register_bank[25];
<< std::hex << register_bank[27] << std::endl; std::cout << " x26 (s10): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[26];
std::cout << "x28 (t3): 0x" << std::right << std::setw(8) std::cout << " x27 (s11): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[28]; << std::hex << register_bank[27] << std::endl;
std::cout << " x29 (t4): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[29]; std::cout << "x28 (t3): 0x" << std::right << std::setw(8)
std::cout << " x30 (t5): 0x" << std::right << std::setw(8) << std::hex << register_bank[28];
<< std::hex << register_bank[30]; std::cout << " x29 (t4): 0x" << std::right << std::setw(8)
std::cout << " x31 (t6): 0x" << std::right << std::setw(8) << std::hex << register_bank[29];
<< std::hex << register_bank[31] << std::endl; std::cout << " x30 (t5): 0x" << std::right << std::setw(8)
<< std::hex << register_bank[30];
std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl; std::cout << " x31 (t6): 0x" << std::right << std::setw(8)
std::cout << "************************************" << std::endl; << std::hex << register_bank[31] << std::endl;
}
std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl;
void Registers::setValue(int reg_num, std::int32_t value) { std::cout << "************************************" << std::endl;
if ((reg_num != 0) && (reg_num < 32)) { }
register_bank[reg_num] = value;
perf->registerWrite(); void Registers::setValue(int reg_num, std::int32_t value) {
} if ((reg_num != 0) && (reg_num < 32)) {
} register_bank[reg_num] = value;
perf->registerWrite();
std::uint32_t Registers::getValue(int reg_num) const { }
if ((reg_num >= 0) && (reg_num < 32)) { }
perf->registerRead();
return register_bank[reg_num]; std::uint32_t Registers::getValue(int reg_num) const {
} else { if ((reg_num >= 0) && (reg_num < 32)) {
return static_cast<std::int32_t>(0xFFFFFFFF); perf->registerRead();
} return register_bank[reg_num];
} } else {
return static_cast<std::int32_t>(0xFFFFFFFF);
std::uint32_t Registers::getPC() const { }
return register_PC; }
}
std::uint32_t Registers::getPC() const {
void Registers::setPC(std::uint32_t new_pc) { return register_PC;
register_PC = new_pc; }
}
void Registers::setPC(std::uint32_t new_pc) {
std::uint32_t Registers::getCSR(const int csr) { register_PC = new_pc;
std::uint32_t ret_value; }
switch (csr) { std::uint32_t Registers::getCSR(const int csr) {
case CSR_CYCLE: std::uint32_t ret_value;
case CSR_MCYCLE:
ret_value = static_cast<std::uint64_t>(sc_core::sc_time( switch (csr) {
sc_core::sc_time_stamp() case CSR_CYCLE:
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) case CSR_MCYCLE:
& 0x00000000FFFFFFFF; ret_value = static_cast<std::uint64_t>(sc_core::sc_time(
break; sc_core::sc_time_stamp()
case CSR_CYCLEH: - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
case CSR_MCYCLEH: & 0x00000000FFFFFFFF;
ret_value = static_cast<std::uint32_t>((std::uint64_t) (sc_core::sc_time( break;
sc_core::sc_time_stamp() case CSR_CYCLEH:
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) case CSR_MCYCLEH:
>> 32 & 0x00000000FFFFFFFF); ret_value = static_cast<std::uint32_t>((std::uint64_t) (sc_core::sc_time(
break; sc_core::sc_time_stamp()
case CSR_TIME: - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
ret_value = static_cast<std::uint64_t>(sc_core::sc_time( >> 32 & 0x00000000FFFFFFFF);
sc_core::sc_time_stamp() break;
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) case CSR_TIME:
& 0x00000000FFFFFFFF; ret_value = static_cast<std::uint64_t>(sc_core::sc_time(
break; sc_core::sc_time_stamp()
case CSR_TIMEH: - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
ret_value = static_cast<std::uint32_t>((std::uint64_t) (sc_core::sc_time( & 0x00000000FFFFFFFF;
sc_core::sc_time_stamp() break;
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double()) case CSR_TIMEH:
>> 32 & 0x00000000FFFFFFFF); ret_value = static_cast<std::uint32_t>((std::uint64_t) (sc_core::sc_time(
break; sc_core::sc_time_stamp()
[[likely]] default: - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
ret_value = CSR[csr]; >> 32 & 0x00000000FFFFFFFF);
break; break;
} [[likely]] default:
return ret_value; ret_value = CSR[csr];
} break;
}
void Registers::setCSR(int csr, std::uint32_t value) { return ret_value;
/* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to be writable, }
* but Volume II: Privileged Architecture v1.10 says MISA is writable (?)
*/ void Registers::setCSR(int csr, std::uint32_t value) {
if (csr != CSR_MISA) { /* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to be writable,
CSR[csr] = value; * but Volume II: Privileged Architecture v1.10 says MISA is writable (?)
} */
} if (csr != CSR_MISA) {
CSR[csr] = value;
void Registers::initCSR() { }
CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION }
| MISA_A_EXTENSION | MISA_I_BASE;
CSR[CSR_MSTATUS] = MISA_MXL; void Registers::initCSR() {
CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION
| MISA_A_EXTENSION | MISA_I_BASE;
CSR[CSR_MSTATUS] = MISA_MXL;
}
} }

View File

@ -39,23 +39,23 @@ uint32_t dump_addr_end = 0;
*/ */
class Simulator : sc_core::sc_module { class Simulator : sc_core::sc_module {
public: public:
CPU *cpu; riscv_tlm::CPU *cpu;
Memory *MainMemory; riscv_tlm::Memory *MainMemory;
BusCtrl *Bus; riscv_tlm::BusCtrl *Bus;
Trace *trace; riscv_tlm::peripherals::Trace *trace;
Timer *timer; riscv_tlm::peripherals::Timer *timer;
explicit Simulator(sc_core::sc_module_name const &name): sc_module(name) { explicit Simulator(sc_core::sc_module_name const &name): sc_module(name) {
std::uint32_t start_PC; std::uint32_t start_PC;
MainMemory = new Memory("Main_Memory", filename); MainMemory = new riscv_tlm::Memory("Main_Memory", filename);
start_PC = MainMemory->getPCfromHEX(); start_PC = MainMemory->getPCfromHEX();
cpu = new CPU("cpu", start_PC, debug_session); cpu = new riscv_tlm::CPU("cpu", start_PC, debug_session);
Bus = new BusCtrl("BusCtrl"); Bus = new riscv_tlm::BusCtrl("BusCtrl");
trace = new Trace("Trace"); trace = new riscv_tlm::peripherals::Trace("Trace");
timer = new Timer("Timer"); timer = new riscv_tlm::peripherals::Timer("Timer");
cpu->instr_bus.bind(Bus->cpu_instr_socket); cpu->instr_bus.bind(Bus->cpu_instr_socket);
cpu->mem_intf->data_bus.bind(Bus->cpu_data_socket); cpu->mem_intf->data_bus.bind(Bus->cpu_data_socket);
@ -67,7 +67,7 @@ public:
timer->irq_line.bind(cpu->irq_line_socket); timer->irq_line.bind(cpu->irq_line_socket);
if (debug_session) { if (debug_session) {
Debug debug(cpu, MainMemory); riscv_tlm::Debug debug(cpu, MainMemory);
} }
} }

View File

@ -9,93 +9,97 @@
#include <cstdint> #include <cstdint>
#include "Timer.h" #include "Timer.h"
SC_HAS_PROCESS(Timer); namespace riscv_tlm::peripherals {
Timer::Timer(sc_core::sc_module_name const &name) : SC_HAS_PROCESS(Timer);
sc_module(name), socket("timer_socket"), m_mtime(0), m_mtimecmp(0) {
socket.register_b_transport(this, &Timer::b_transport); Timer::Timer(sc_core::sc_module_name const &name) :
sc_module(name), socket("timer_socket"), m_mtime(0), m_mtimecmp(0) {
socket.register_b_transport(this, &Timer::b_transport);
SC_THREAD(run);
}
[[noreturn]] void Timer::run() {
auto *irq_trans = new tlm::tlm_generic_payload;
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
std::uint32_t cause = 1 << 31 | 0x07; // Machine timer interrupt
irq_trans->set_command(tlm::TLM_WRITE_COMMAND);
irq_trans->set_data_ptr(reinterpret_cast<unsigned char *>(&cause));
irq_trans->set_data_length(4);
irq_trans->set_streaming_width(4);
irq_trans->set_byte_enable_ptr(nullptr);
irq_trans->set_dmi_allowed(false);
irq_trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
irq_trans->set_address(0);
while (true) {
wait(timer_event);
irq_line->b_transport(*irq_trans, delay);
}
}
void Timer::b_transport(tlm::tlm_generic_payload &trans,
sc_core::sc_time &delay) {
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 addr = trans.get_address();
unsigned char *ptr = trans.get_data_ptr();
unsigned int len = trans.get_data_length();
delay = sc_core::SC_ZERO_TIME;
std::uint32_t aux_value = 0;
if (cmd == tlm::TLM_WRITE_COMMAND) {
memcpy(&aux_value, ptr, len);
switch (addr) {
case TIMER_MEMORY_ADDRESS_LO:
m_mtime.range(31, 0) = aux_value;
break;
case TIMER_MEMORY_ADDRESS_HI:
m_mtime.range(63, 32) = aux_value;
break;
case TIMERCMP_MEMORY_ADDRESS_LO:
m_mtimecmp.range(31, 0) = aux_value;
break;
case TIMERCMP_MEMORY_ADDRESS_HI:
m_mtimecmp.range(63, 32) = aux_value;
std::uint64_t notify_time;
// notify needs relative time, mtimecmp works in absolute time
notify_time = m_mtimecmp - m_mtime;
timer_event.notify(sc_core::sc_time(notify_time, sc_core::SC_NS));
break;
default:
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
return;
}
} else { // TLM_READ_COMMAND
switch (addr) {
case TIMER_MEMORY_ADDRESS_LO:
m_mtime = sc_core::sc_time_stamp().value();
aux_value = m_mtime.range(31, 0);
break;
case TIMER_MEMORY_ADDRESS_HI:
aux_value = m_mtime.range(63, 32);
break;
case TIMERCMP_MEMORY_ADDRESS_LO:
aux_value = m_mtimecmp.range(31, 0);
break;
case TIMERCMP_MEMORY_ADDRESS_HI:
aux_value = m_mtimecmp.range(63, 32);
break;
default:
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
return;
}
memcpy(ptr, &aux_value, len);
}
trans.set_response_status(tlm::TLM_OK_RESPONSE);
}
SC_THREAD(run);
}
[[noreturn]] void Timer::run() {
auto *irq_trans = new tlm::tlm_generic_payload;
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
std::uint32_t cause = 1 << 31 | 0x07; // Machine timer interrupt
irq_trans->set_command(tlm::TLM_WRITE_COMMAND);
irq_trans->set_data_ptr(reinterpret_cast<unsigned char*>(&cause));
irq_trans->set_data_length(4);
irq_trans->set_streaming_width(4);
irq_trans->set_byte_enable_ptr(nullptr);
irq_trans->set_dmi_allowed(false);
irq_trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
irq_trans->set_address(0);
while (true) {
wait(timer_event);
irq_line->b_transport(*irq_trans, delay);
}
}
void Timer::b_transport(tlm::tlm_generic_payload &trans,
sc_core::sc_time &delay) {
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 addr = trans.get_address();
unsigned char *ptr = trans.get_data_ptr();
unsigned int len = trans.get_data_length();
delay = sc_core::SC_ZERO_TIME;
std::uint32_t aux_value = 0;
if (cmd == tlm::TLM_WRITE_COMMAND) {
memcpy(&aux_value, ptr, len);
switch (addr) {
case TIMER_MEMORY_ADDRESS_LO:
m_mtime.range(31, 0) = aux_value;
break;
case TIMER_MEMORY_ADDRESS_HI:
m_mtime.range(63, 32) = aux_value;
break;
case TIMERCMP_MEMORY_ADDRESS_LO:
m_mtimecmp.range(31, 0) = aux_value;
break;
case TIMERCMP_MEMORY_ADDRESS_HI:
m_mtimecmp.range(63, 32) = aux_value;
std::uint64_t notify_time;
// notify needs relative time, mtimecmp works in absolute time
notify_time = m_mtimecmp - m_mtime;
timer_event.notify(sc_core::sc_time(notify_time, sc_core::SC_NS));
break;
default:
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
return;
}
} else { // TLM_READ_COMMAND
switch (addr) {
case TIMER_MEMORY_ADDRESS_LO:
m_mtime = sc_core::sc_time_stamp().value();
aux_value = m_mtime.range(31, 0);
break;
case TIMER_MEMORY_ADDRESS_HI:
aux_value = m_mtime.range(63, 32);
break;
case TIMERCMP_MEMORY_ADDRESS_LO:
aux_value = m_mtimecmp.range(31, 0);
break;
case TIMERCMP_MEMORY_ADDRESS_HI:
aux_value = m_mtimecmp.range(63, 32);
break;
default:
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
return;
}
memcpy(ptr, &aux_value, len);
}
trans.set_response_status(tlm::TLM_OK_RESPONSE);
} }

View File

@ -20,92 +20,97 @@
#include "Trace.h" #include "Trace.h"
void Trace::xtermLaunch(char *slaveName) const { namespace riscv_tlm::peripherals {
char *arg;
char *fin = &(slaveName[strlen(slaveName) - 2]);
if ( nullptr == strchr(fin, '/')) { void Trace::xtermLaunch(char *slaveName) const {
arg = new char[2 + 1 + 1 + 20 + 1]; char *arg;
sprintf(arg, "-S%c%c%d", fin[0], fin[1], ptMaster); char *fin = &(slaveName[strlen(slaveName) - 2]);
} else {
char *slaveBase = ::basename(slaveName);
arg = new char[2 + strlen(slaveBase) + 1 + 20 + 1];
sprintf(arg, "-S%s/%d", slaveBase, ptMaster);
}
char *argv[3]; if (nullptr == strchr(fin, '/')) {
argv[0] = (char*) ("xterm"); arg = new char[2 + 1 + 1 + 20 + 1];
argv[1] = arg; sprintf(arg, "-S%c%c%d", fin[0], fin[1], ptMaster);
argv[2] = nullptr; } else {
char *slaveBase = ::basename(slaveName);
arg = new char[2 + strlen(slaveBase) + 1 + 20 + 1];
sprintf(arg, "-S%s/%d", slaveBase, ptMaster);
}
char *argv[3];
argv[0] = (char *) ("xterm");
argv[1] = arg;
argv[2] = nullptr;
execvp("xterm", argv);
}
void Trace::xtermKill() {
if (-1 != ptSlave) { // Close down the slave
close(ptSlave); // Close the FD
ptSlave = -1;
}
if (-1 != ptMaster) { // Close down the master
close(ptMaster);
ptMaster = -1;
}
if (xtermPid > 0) { // Kill the terminal
kill(xtermPid, SIGKILL);
waitpid(xtermPid, nullptr, 0);
}
}
void Trace::xtermSetup() {
ptMaster = open("/dev/ptmx", O_RDWR);
if (ptMaster != -1) {
grantpt(ptMaster);
unlockpt(ptMaster);
char *ptSlaveName = ptsname(ptMaster);
ptSlave = open(ptSlaveName, O_RDWR); // In and out are the same
struct termios termInfo{};
tcgetattr(ptSlave, &termInfo);
termInfo.c_lflag &= ~ECHO;
termInfo.c_lflag &= ~ICANON;
tcsetattr(ptSlave, TCSADRAIN, &termInfo);
xtermPid = fork();
if (xtermPid == 0) {
xtermLaunch(ptSlaveName);
}
}
}
SC_HAS_PROCESS(Trace);
Trace::Trace(sc_core::sc_module_name const &name) :
sc_module(name), socket("socket") {
socket.register_b_transport(this, &Trace::b_transport);
xtermSetup();
}
Trace::~Trace() {
xtermKill();
}
void Trace::b_transport(tlm::tlm_generic_payload &trans,
sc_core::sc_time &delay) {
unsigned char *ptr = trans.get_data_ptr();
delay = sc_core::SC_ZERO_TIME;
ssize_t a = write(ptSlave, ptr, 1);
(void) a;
trans.set_response_status(tlm::TLM_OK_RESPONSE);
}
execvp("xterm", argv);
}
void Trace::xtermKill() {
if (-1 != ptSlave) { // Close down the slave
close(ptSlave); // Close the FD
ptSlave = -1;
}
if (-1 != ptMaster) { // Close down the master
close(ptMaster);
ptMaster = -1;
}
if (xtermPid > 0) { // Kill the terminal
kill(xtermPid, SIGKILL);
waitpid(xtermPid, nullptr, 0);
}
}
void Trace::xtermSetup() {
ptMaster = open("/dev/ptmx", O_RDWR);
if (ptMaster != -1) {
grantpt(ptMaster);
unlockpt(ptMaster);
char *ptSlaveName = ptsname(ptMaster);
ptSlave = open(ptSlaveName, O_RDWR); // In and out are the same
struct termios termInfo{};
tcgetattr(ptSlave, &termInfo);
termInfo.c_lflag &= ~ECHO;
termInfo.c_lflag &= ~ICANON;
tcsetattr(ptSlave, TCSADRAIN, &termInfo);
xtermPid = fork();
if (xtermPid == 0) {
xtermLaunch(ptSlaveName);
}
}
}
SC_HAS_PROCESS(Trace);
Trace::Trace(sc_core::sc_module_name const &name) :
sc_module(name), socket("socket") {
socket.register_b_transport(this, &Trace::b_transport);
xtermSetup();
}
Trace::~Trace() {
xtermKill();
}
void Trace::b_transport(tlm::tlm_generic_payload &trans,
sc_core::sc_time &delay) {
unsigned char *ptr = trans.get_data_ptr();
delay = sc_core::SC_ZERO_TIME;
ssize_t a = write(ptSlave, ptr, 1);
(void) a;
trans.set_response_status(tlm::TLM_OK_RESPONSE);
} }

View File

@ -8,53 +8,56 @@
#include "extension_base.h" #include "extension_base.h"
extension_base::extension_base(const sc_dt::sc_uint<32> & instr, namespace riscv_tlm {
Registers *register_bank, MemoryInterface *mem_interface) :
m_instr(instr), regs(register_bank), mem_intf(mem_interface) {
perf = Performance::getInstance(); extension_base::extension_base(const sc_dt::sc_uint<32> &instr,
logger = spdlog::get("my_logger"); Registers *register_bank, MemoryInterface *mem_interface) :
} m_instr(instr), regs(register_bank), mem_intf(mem_interface) {
extension_base::~extension_base() =default; perf = Performance::getInstance();
logger = spdlog::get("my_logger");
void extension_base::setInstr(std::uint32_t p_instr) { }
m_instr = sc_dt::sc_uint<32>(p_instr);
} extension_base::~extension_base() = default;
void extension_base::dump() const { void extension_base::setInstr(std::uint32_t p_instr) {
std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; m_instr = sc_dt::sc_uint<32>(p_instr);
} }
void extension_base::RaiseException(std::uint32_t cause, std::uint32_t inst) { void extension_base::dump() const {
std::uint32_t new_pc, current_pc, m_cause; std::cout << std::hex << "0x" << m_instr << std::dec << std::endl;
}
current_pc = regs->getPC();
m_cause = regs->getCSR(CSR_MSTATUS); void extension_base::RaiseException(std::uint32_t cause, std::uint32_t inst) {
m_cause |= cause; std::uint32_t new_pc, current_pc, m_cause;
new_pc = regs->getCSR(CSR_MTVEC); current_pc = regs->getPC();
m_cause = regs->getCSR(CSR_MSTATUS);
regs->setCSR(CSR_MEPC, current_pc); m_cause |= cause;
if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) { new_pc = regs->getCSR(CSR_MTVEC);
regs->setCSR(CSR_MTVAL, inst);
} else { regs->setCSR(CSR_MEPC, current_pc);
regs->setCSR(CSR_MTVAL, current_pc);
} if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) {
regs->setCSR(CSR_MTVAL, inst);
regs->setCSR(CSR_MCAUSE, cause); } else {
regs->setCSR(CSR_MSTATUS, m_cause); regs->setCSR(CSR_MTVAL, current_pc);
}
regs->setPC(new_pc);
regs->setCSR(CSR_MCAUSE, cause);
logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC(), regs->setCSR(CSR_MSTATUS, m_cause);
new_pc);
} regs->setPC(new_pc);
bool extension_base::NOP() { logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC(),
new_pc);
logger->debug("{} ns. PC: 0x{:x}. NOP! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC()); }
sc_core::sc_stop();
return true; bool extension_base::NOP() {
logger->debug("{} ns. PC: 0x{:x}. NOP! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC());
sc_core::sc_stop();
return true;
}
} }