Added namespace to project
This commit is contained in:
parent
e2981d8a50
commit
fb84f197bf
|
@ -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
|
||||||
|
|
567
inc/BASE_ISA.h
567
inc/BASE_ISA.h
|
@ -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
|
||||||
|
|
|
@ -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
150
inc/CPU.h
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
108
inc/Memory.h
108
inc/Memory.h
|
@ -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__ */
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
280
inc/Registers.h
280
inc/Registers.h
|
@ -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
|
||||||
|
|
71
inc/Timer.h
71
inc/Timer.h
|
@ -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
|
||||||
|
|
55
inc/Trace.h
55
inc/Trace.h
|
@ -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
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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;
|
switch (opcode()) {
|
||||||
break;
|
case A_LR:
|
||||||
case A_SC:
|
return OP_A_LR;
|
||||||
return OP_A_SC;
|
break;
|
||||||
break;
|
case A_SC:
|
||||||
case A_AMOSWAP:
|
return OP_A_SC;
|
||||||
return OP_A_AMOSWAP;
|
break;
|
||||||
break;
|
case A_AMOSWAP:
|
||||||
case A_AMOADD:
|
return OP_A_AMOSWAP;
|
||||||
return OP_A_AMOADD;
|
break;
|
||||||
break;
|
case A_AMOADD:
|
||||||
case A_AMOXOR:
|
return OP_A_AMOADD;
|
||||||
return OP_A_AMOXOR;
|
break;
|
||||||
break;
|
case A_AMOXOR:
|
||||||
case A_AMOAND:
|
return OP_A_AMOXOR;
|
||||||
return OP_A_AMOAND;
|
break;
|
||||||
break;
|
case A_AMOAND:
|
||||||
case A_AMOOR:
|
return OP_A_AMOAND;
|
||||||
return OP_A_AMOOR;
|
break;
|
||||||
break;
|
case A_AMOOR:
|
||||||
case A_AMOMIN:
|
return OP_A_AMOOR;
|
||||||
return OP_A_AMOMIN;
|
break;
|
||||||
break;
|
case A_AMOMIN:
|
||||||
case A_AMOMAX:
|
return OP_A_AMOMIN;
|
||||||
return OP_A_AMOMAX;
|
break;
|
||||||
break;
|
case A_AMOMAX:
|
||||||
case A_AMOMINU:
|
return OP_A_AMOMAX;
|
||||||
return OP_A_AMOMINU;
|
break;
|
||||||
break;
|
case A_AMOMINU:
|
||||||
case A_AMOMAXU:
|
return OP_A_AMOMINU;
|
||||||
return OP_A_AMOMAXU;
|
break;
|
||||||
break;
|
case A_AMOMAXU:
|
||||||
[[unlikely]] default:
|
return OP_A_AMOMAXU;
|
||||||
return OP_A_ERROR;
|
break;
|
||||||
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));
|
|
||||||
|
|
||||||
// swap
|
mem_addr = regs->getValue(rs1);
|
||||||
aux = regs->getValue(rs2);
|
data = mem_intf->readDataMem(mem_addr, 4);
|
||||||
regs->setValue(rs2, static_cast<int32_t>(data));
|
perf->dataMemoryRead();
|
||||||
|
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);
|
||||||
|
perf->dataMemoryWrite();
|
||||||
|
|
||||||
return true;
|
logger->debug("{} ns. PC: 0x{:x}. A.AMOSWAP");
|
||||||
}
|
|
||||||
|
|
||||||
bool A_extension::Exec_A_AMOADD() const {
|
return true;
|
||||||
std::uint32_t mem_addr;
|
}
|
||||||
int rd, rs1, rs2;
|
|
||||||
std::uint32_t data;
|
|
||||||
|
|
||||||
/* These instructions must be atomic */
|
bool A_extension::Exec_A_AMOADD() const {
|
||||||
|
std::uint32_t mem_addr;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
std::uint32_t data;
|
||||||
|
|
||||||
rd = get_rd();
|
/* These instructions must be atomic */
|
||||||
rs1 = get_rs1();
|
|
||||||
rs2 = get_rs2();
|
|
||||||
|
|
||||||
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);
|
||||||
|
perf->dataMemoryRead();
|
||||||
|
|
||||||
// add
|
regs->setValue(rd, static_cast<int32_t>(data));
|
||||||
data = data + regs->getValue(rs2);
|
|
||||||
|
|
||||||
mem_intf->writeDataMem(mem_addr, data, 4);
|
// add
|
||||||
perf->dataMemoryWrite();
|
data = data + regs->getValue(rs2);
|
||||||
|
|
||||||
logger->debug("{} ns. PC: 0x{:x}. A.AMOADD");
|
mem_intf->writeDataMem(mem_addr, data, 4);
|
||||||
|
perf->dataMemoryWrite();
|
||||||
|
|
||||||
return true;
|
logger->debug("{} ns. PC: 0x{:x}. A.AMOADD");
|
||||||
}
|
|
||||||
|
|
||||||
bool A_extension::Exec_A_AMOXOR() const {
|
return true;
|
||||||
std::uint32_t mem_addr;
|
}
|
||||||
int rd, rs1, rs2;
|
|
||||||
std::uint32_t data;
|
|
||||||
|
|
||||||
/* These instructions must be atomic */
|
bool A_extension::Exec_A_AMOXOR() const {
|
||||||
|
std::uint32_t mem_addr;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
std::uint32_t data;
|
||||||
|
|
||||||
rd = get_rd();
|
/* These instructions must be atomic */
|
||||||
rs1 = get_rs1();
|
|
||||||
rs2 = get_rs2();
|
|
||||||
|
|
||||||
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);
|
||||||
|
perf->dataMemoryRead();
|
||||||
|
|
||||||
// add
|
regs->setValue(rd, static_cast<int32_t>(data));
|
||||||
data = data ^ regs->getValue(rs2);
|
|
||||||
|
|
||||||
mem_intf->writeDataMem(mem_addr, data, 4);
|
// add
|
||||||
perf->dataMemoryWrite();
|
data = data ^ regs->getValue(rs2);
|
||||||
|
|
||||||
logger->debug("{} ns. PC: 0x{:x}. A.AMOXOR");
|
mem_intf->writeDataMem(mem_addr, data, 4);
|
||||||
|
perf->dataMemoryWrite();
|
||||||
|
|
||||||
return true;
|
logger->debug("{} ns. PC: 0x{:x}. A.AMOXOR");
|
||||||
}
|
|
||||||
bool A_extension::Exec_A_AMOAND() const {
|
|
||||||
std::uint32_t mem_addr;
|
|
||||||
int rd, rs1, rs2;
|
|
||||||
std::uint32_t data;
|
|
||||||
|
|
||||||
/* These instructions must be atomic */
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
rd = get_rd();
|
bool A_extension::Exec_A_AMOAND() 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);
|
/* These instructions must be atomic */
|
||||||
data = mem_intf->readDataMem(mem_addr, 4);
|
|
||||||
perf->dataMemoryRead();
|
|
||||||
|
|
||||||
regs->setValue(rd, static_cast<int32_t>(data));
|
rd = get_rd();
|
||||||
|
rs1 = get_rs1();
|
||||||
|
rs2 = get_rs2();
|
||||||
|
|
||||||
// add
|
mem_addr = regs->getValue(rs1);
|
||||||
data = data & regs->getValue(rs2);
|
data = mem_intf->readDataMem(mem_addr, 4);
|
||||||
|
perf->dataMemoryRead();
|
||||||
|
|
||||||
mem_intf->writeDataMem(mem_addr, data, 4);
|
regs->setValue(rd, static_cast<int32_t>(data));
|
||||||
perf->dataMemoryWrite();
|
|
||||||
|
|
||||||
logger->debug("{} ns. PC: 0x{:x}. A.AMOAND");
|
// add
|
||||||
|
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;
|
|
||||||
std::uint32_t data;
|
|
||||||
|
|
||||||
/* These instructions must be atomic */
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
rd = get_rd();
|
bool A_extension::Exec_A_AMOOR() 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);
|
/* These instructions must be atomic */
|
||||||
data = mem_intf->readDataMem(mem_addr, 4);
|
|
||||||
perf->dataMemoryRead();
|
|
||||||
|
|
||||||
regs->setValue(rd, static_cast<int32_t>(data));
|
rd = get_rd();
|
||||||
|
rs1 = get_rs1();
|
||||||
|
rs2 = get_rs2();
|
||||||
|
|
||||||
// add
|
mem_addr = regs->getValue(rs1);
|
||||||
data = data | regs->getValue(rs2);
|
data = mem_intf->readDataMem(mem_addr, 4);
|
||||||
|
perf->dataMemoryRead();
|
||||||
|
|
||||||
mem_intf->writeDataMem(mem_addr, data, 4);
|
regs->setValue(rd, static_cast<int32_t>(data));
|
||||||
perf->dataMemoryWrite();
|
|
||||||
|
|
||||||
logger->debug("{} ns. PC: 0x{:x}. A.AMOOR");
|
// add
|
||||||
|
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;
|
|
||||||
std::uint32_t data;
|
|
||||||
std::uint32_t aux;
|
|
||||||
|
|
||||||
/* These instructions must be atomic */
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
rd = get_rd();
|
bool A_extension::Exec_A_AMOMIN() const {
|
||||||
rs1 = get_rs1();
|
std::uint32_t mem_addr;
|
||||||
rs2 = get_rs2();
|
int rd, rs1, rs2;
|
||||||
|
std::uint32_t data;
|
||||||
|
std::uint32_t aux;
|
||||||
|
|
||||||
mem_addr = regs->getValue(rs1);
|
/* These instructions must be atomic */
|
||||||
data = mem_intf->readDataMem(mem_addr, 4);
|
|
||||||
perf->dataMemoryRead();
|
|
||||||
|
|
||||||
regs->setValue(rd, static_cast<int32_t>(data));
|
rd = get_rd();
|
||||||
|
rs1 = get_rs1();
|
||||||
|
rs2 = get_rs2();
|
||||||
|
|
||||||
// min
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem_intf->writeDataMem(mem_addr, aux, 4);
|
regs->setValue(rd, static_cast<int32_t>(data));
|
||||||
perf->dataMemoryWrite();
|
|
||||||
|
|
||||||
logger->debug("{} ns. PC: 0x{:x}. A.AMOMIN");
|
// min
|
||||||
|
aux = regs->getValue(rs2);
|
||||||
|
if ((int32_t) data < (int32_t) aux) {
|
||||||
|
aux = data;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
mem_intf->writeDataMem(mem_addr, aux, 4);
|
||||||
}
|
perf->dataMemoryWrite();
|
||||||
bool A_extension::Exec_A_AMOMAX() const {
|
|
||||||
std::uint32_t mem_addr;
|
|
||||||
int rd, rs1, rs2;
|
|
||||||
std::uint32_t data;
|
|
||||||
std::uint32_t aux;
|
|
||||||
|
|
||||||
/* These instructions must be atomic */
|
logger->debug("{} ns. PC: 0x{:x}. A.AMOMIN");
|
||||||
|
|
||||||
rd = get_rd();
|
return true;
|
||||||
rs1 = get_rs1();
|
}
|
||||||
rs2 = get_rs2();
|
|
||||||
|
|
||||||
mem_addr = regs->getValue(rs1);
|
bool A_extension::Exec_A_AMOMAX() const {
|
||||||
data = mem_intf->readDataMem(mem_addr, 4);
|
std::uint32_t mem_addr;
|
||||||
perf->dataMemoryRead();
|
int rd, rs1, rs2;
|
||||||
|
std::uint32_t data;
|
||||||
|
std::uint32_t aux;
|
||||||
|
|
||||||
regs->setValue(rd, static_cast<int32_t>(data));
|
/* These instructions must be atomic */
|
||||||
|
|
||||||
// >
|
rd = get_rd();
|
||||||
aux = regs->getValue(rs2);
|
rs1 = get_rs1();
|
||||||
if ((int32_t) data > (int32_t) aux) {
|
rs2 = get_rs2();
|
||||||
aux = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem_intf->writeDataMem(mem_addr, aux, 4);
|
mem_addr = regs->getValue(rs1);
|
||||||
perf->dataMemoryWrite();
|
data = mem_intf->readDataMem(mem_addr, 4);
|
||||||
|
perf->dataMemoryRead();
|
||||||
|
|
||||||
logger->debug("{} ns. PC: 0x{:x}. A.AMOMAX");
|
regs->setValue(rd, static_cast<int32_t>(data));
|
||||||
|
|
||||||
return true;
|
// >
|
||||||
}
|
aux = regs->getValue(rs2);
|
||||||
bool A_extension::Exec_A_AMOMINU() const {
|
if ((int32_t) data > (int32_t) aux) {
|
||||||
std::uint32_t mem_addr;
|
aux = data;
|
||||||
int rd, rs1, rs2;
|
}
|
||||||
std::uint32_t data;
|
|
||||||
std::uint32_t aux;
|
mem_intf->writeDataMem(mem_addr, aux, 4);
|
||||||
|
perf->dataMemoryWrite();
|
||||||
/* These instructions must be atomic */
|
|
||||||
|
logger->debug("{} ns. PC: 0x{:x}. A.AMOMAX");
|
||||||
rd = get_rd();
|
|
||||||
rs1 = get_rs1();
|
return true;
|
||||||
rs2 = get_rs2();
|
}
|
||||||
|
|
||||||
mem_addr = regs->getValue(rs1);
|
bool A_extension::Exec_A_AMOMINU() const {
|
||||||
data = mem_intf->readDataMem(mem_addr, 4);
|
std::uint32_t mem_addr;
|
||||||
perf->dataMemoryRead();
|
int rd, rs1, rs2;
|
||||||
|
std::uint32_t data;
|
||||||
regs->setValue(rd, static_cast<int32_t>(data));
|
std::uint32_t aux;
|
||||||
|
|
||||||
// min
|
/* These instructions must be atomic */
|
||||||
aux = regs->getValue(rs2);
|
|
||||||
if (data < aux) {
|
rd = get_rd();
|
||||||
aux = data;
|
rs1 = get_rs1();
|
||||||
}
|
rs2 = get_rs2();
|
||||||
|
|
||||||
mem_intf->writeDataMem(mem_addr, aux, 4);
|
mem_addr = regs->getValue(rs1);
|
||||||
perf->dataMemoryWrite();
|
data = mem_intf->readDataMem(mem_addr, 4);
|
||||||
|
perf->dataMemoryRead();
|
||||||
logger->debug("{} ns. PC: 0x{:x}. A.AMOMINU");
|
|
||||||
|
regs->setValue(rd, static_cast<int32_t>(data));
|
||||||
return true;
|
|
||||||
}
|
// min
|
||||||
bool A_extension::Exec_A_AMOMAXU() const {
|
aux = regs->getValue(rs2);
|
||||||
std::uint32_t mem_addr;
|
if (data < aux) {
|
||||||
int rd, rs1, rs2;
|
aux = data;
|
||||||
std::uint32_t data;
|
}
|
||||||
std::uint32_t aux;
|
|
||||||
|
mem_intf->writeDataMem(mem_addr, aux, 4);
|
||||||
/* These instructions must be atomic */
|
perf->dataMemoryWrite();
|
||||||
|
|
||||||
rd = get_rd();
|
logger->debug("{} ns. PC: 0x{:x}. A.AMOMINU");
|
||||||
rs1 = get_rs1();
|
|
||||||
rs2 = get_rs2();
|
return true;
|
||||||
|
}
|
||||||
mem_addr = regs->getValue(rs1);
|
|
||||||
data = mem_intf->readDataMem(mem_addr, 4);
|
bool A_extension::Exec_A_AMOMAXU() const {
|
||||||
perf->dataMemoryRead();
|
std::uint32_t mem_addr;
|
||||||
|
int rd, rs1, rs2;
|
||||||
regs->setValue(rd, static_cast<int32_t>(data));
|
std::uint32_t data;
|
||||||
|
std::uint32_t aux;
|
||||||
// max
|
|
||||||
aux = regs->getValue(rs2);
|
/* These instructions must be atomic */
|
||||||
if (data > aux) {
|
|
||||||
aux = data;
|
rd = get_rd();
|
||||||
}
|
rs1 = get_rs1();
|
||||||
|
rs2 = get_rs2();
|
||||||
mem_intf->writeDataMem(mem_addr, aux, 4);
|
|
||||||
perf->dataMemoryWrite();
|
mem_addr = regs->getValue(rs1);
|
||||||
|
data = mem_intf->readDataMem(mem_addr, 4);
|
||||||
logger->debug("{} ns. PC: 0x{:x}. A.AMOMAXU");
|
perf->dataMemoryRead();
|
||||||
|
|
||||||
return true;
|
regs->setValue(rd, static_cast<int32_t>(data));
|
||||||
}
|
|
||||||
|
// max
|
||||||
void A_extension::TLB_reserve(std::uint32_t address) {
|
aux = regs->getValue(rs2);
|
||||||
TLB_A_Entries.insert(address);
|
if (data > aux) {
|
||||||
}
|
aux = data;
|
||||||
|
}
|
||||||
bool A_extension::TLB_reserved(std::uint32_t address) {
|
|
||||||
if (TLB_A_Entries.count(address) == 1) {
|
mem_intf->writeDataMem(mem_addr, aux, 4);
|
||||||
TLB_A_Entries.erase(address);
|
perf->dataMemoryWrite();
|
||||||
return true;
|
|
||||||
} else {
|
logger->debug("{} ns. PC: 0x{:x}. A.AMOMAXU");
|
||||||
return false;
|
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool A_extension::process_instruction(Instruction &inst) {
|
void A_extension::TLB_reserve(std::uint32_t address) {
|
||||||
bool PC_not_affected = true;
|
TLB_A_Entries.insert(address);
|
||||||
|
}
|
||||||
setInstr(inst.getInstr());
|
|
||||||
|
bool A_extension::TLB_reserved(std::uint32_t address) {
|
||||||
switch (decode()) {
|
if (TLB_A_Entries.count(address) == 1) {
|
||||||
case OP_A_LR:
|
TLB_A_Entries.erase(address);
|
||||||
Exec_A_LR();
|
return true;
|
||||||
break;
|
} else {
|
||||||
case OP_A_SC:
|
return false;
|
||||||
Exec_A_SC();
|
}
|
||||||
break;
|
}
|
||||||
case OP_A_AMOSWAP:
|
|
||||||
Exec_A_AMOSWAP();
|
bool A_extension::process_instruction(Instruction &inst) {
|
||||||
break;
|
bool PC_not_affected = true;
|
||||||
case OP_A_AMOADD:
|
|
||||||
Exec_A_AMOADD();
|
setInstr(inst.getInstr());
|
||||||
break;
|
|
||||||
case OP_A_AMOXOR:
|
switch (decode()) {
|
||||||
Exec_A_AMOXOR();
|
case OP_A_LR:
|
||||||
break;
|
Exec_A_LR();
|
||||||
case OP_A_AMOAND:
|
break;
|
||||||
Exec_A_AMOAND();
|
case OP_A_SC:
|
||||||
break;
|
Exec_A_SC();
|
||||||
case OP_A_AMOOR:
|
break;
|
||||||
Exec_A_AMOOR();
|
case OP_A_AMOSWAP:
|
||||||
break;
|
Exec_A_AMOSWAP();
|
||||||
case OP_A_AMOMIN:
|
break;
|
||||||
Exec_A_AMOMIN();
|
case OP_A_AMOADD:
|
||||||
break;
|
Exec_A_AMOADD();
|
||||||
case OP_A_AMOMAX:
|
break;
|
||||||
Exec_A_AMOMAX();
|
case OP_A_AMOXOR:
|
||||||
break;
|
Exec_A_AMOXOR();
|
||||||
case OP_A_AMOMINU:
|
break;
|
||||||
Exec_A_AMOMINU();
|
case OP_A_AMOAND:
|
||||||
break;
|
Exec_A_AMOAND();
|
||||||
case OP_A_AMOMAXU:
|
break;
|
||||||
Exec_A_AMOMAXU();
|
case OP_A_AMOOR:
|
||||||
break;
|
Exec_A_AMOOR();
|
||||||
[[unlikely]] default:
|
break;
|
||||||
std::cout << "A instruction not implemented yet" << std::endl;
|
case OP_A_AMOMIN:
|
||||||
inst.dump();
|
Exec_A_AMOMIN();
|
||||||
NOP();
|
break;
|
||||||
break;
|
case OP_A_AMOMAX:
|
||||||
}
|
Exec_A_AMOMAX();
|
||||||
|
break;
|
||||||
return PC_not_affected;
|
case OP_A_AMOMINU:
|
||||||
}
|
Exec_A_AMOMINU();
|
||||||
|
break;
|
||||||
|
case OP_A_AMOMAXU:
|
||||||
|
Exec_A_AMOMAXU();
|
||||||
|
break;
|
||||||
|
[[unlikely]] default:
|
||||||
|
std::cout << "A instruction not implemented yet" << std::endl;
|
||||||
|
inst.dump();
|
||||||
|
NOP();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PC_not_affected;
|
||||||
|
}
|
||||||
|
}
|
2439
src/BASE_ISA.cpp
2439
src/BASE_ISA.cpp
File diff suppressed because it is too large
Load Diff
103
src/BusCtrl.cpp
103
src/BusCtrl.cpp
|
@ -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,
|
|
||||||
sc_dt::uint64 end) {
|
|
||||||
cpu_instr_socket->invalidate_direct_mem_ptr(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void BusCtrl::invalidate_direct_mem_ptr(sc_dt::uint64 start,
|
||||||
|
sc_dt::uint64 end) {
|
||||||
|
cpu_instr_socket->invalidate_direct_mem_ptr(start, end);
|
||||||
|
}
|
||||||
|
}
|
386
src/CPU.cpp
386
src/CPU.cpp
|
@ -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;
|
||||||
}
|
}
|
||||||
|
}
|
1294
src/C_extension.cpp
1294
src/C_extension.cpp
File diff suppressed because it is too large
Load Diff
398
src/Debug.cpp
398
src/Debug.cpp
|
@ -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());
|
void Debug::send_packet(int conn, const std::string &msg) {
|
||||||
|
std::string frame = "+$" + msg + "#" + compute_checksum_string(msg);
|
||||||
|
|
||||||
::send(conn, iobuf, frame.size(), 0);
|
memcpy(iobuf, frame.c_str(), frame.size());
|
||||||
}
|
|
||||||
|
|
||||||
std::string Debug::receive_packet() {
|
::send(conn, iobuf, frame.size(), 0);
|
||||||
int nbytes = ::recv(conn, iobuf, bufsize, 0);
|
}
|
||||||
|
|
||||||
if (nbytes == 0) {
|
std::string Debug::receive_packet() {
|
||||||
return "";
|
int nbytes = ::recv(conn, iobuf, bufsize, 0);
|
||||||
} else if (nbytes == 1) {
|
|
||||||
return std::string("+");
|
|
||||||
} else {
|
|
||||||
char *start = strchr(iobuf, '$');
|
|
||||||
char *end = strchr(iobuf, '#');
|
|
||||||
|
|
||||||
std::string message(start + 1, end - (start + 1));
|
if (nbytes == 0) {
|
||||||
|
return "";
|
||||||
|
} else if (nbytes == 1) {
|
||||||
|
return std::string("+");
|
||||||
|
} else {
|
||||||
|
char *start = strchr(iobuf, '$');
|
||||||
|
char *end = strchr(iobuf, '#');
|
||||||
|
|
||||||
return message;
|
std::string message(start + 1, end - (start + 1));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Debug::handle_gdb_loop() {
|
return message;
|
||||||
std::cout << "Handle_GDB_Loop\n";
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Registers *register_bank = dbg_cpu->getRegisterBank();
|
void Debug::handle_gdb_loop() {
|
||||||
|
std::cout << "Handle_GDB_Loop\n";
|
||||||
|
|
||||||
while (true) {
|
Registers *register_bank = dbg_cpu->getRegisterBank();
|
||||||
std::string msg = receive_packet();
|
|
||||||
|
|
||||||
if (msg.size() == 0) {
|
while (true) {
|
||||||
std::cout << "remote connection seems to be closed, terminating ..."
|
std::string msg = receive_packet();
|
||||||
<< 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;
|
if (msg.size() == 0) {
|
||||||
stream << std::setfill('0') << std::hex;
|
std::cout << "remote connection seems to be closed, terminating ..."
|
||||||
for (int i = 1; i < 32; i++) {
|
<< std::endl;
|
||||||
stream << std::setw(8) << register_bank->getValue(i);
|
break;
|
||||||
}
|
} else if (msg == "+") {
|
||||||
send_packet(conn, stream.str());
|
// NOTE: just ignore this message, nothing to do in this case
|
||||||
} else if (boost::starts_with(msg, "p")) {
|
} else if (boost::starts_with(msg, "qSupported")) {
|
||||||
long n = strtol(msg.c_str() + 1, 0, 16);
|
send_packet(conn, "PacketSize=256;swbreak+;hwbreak+;vContSupported+;multiprocess-");
|
||||||
int reg_value;
|
} else if (msg == "vMustReplyEmpty") {
|
||||||
if (n < 32) {
|
send_packet(conn, "");
|
||||||
reg_value = register_bank->getValue(n);
|
} else if (msg == "Hg0") {
|
||||||
} else if (n == 32) {
|
send_packet(conn, "OK");
|
||||||
reg_value = register_bank->getPC();
|
} else if (msg == "Hc0") {
|
||||||
} else {
|
send_packet(conn, "");
|
||||||
// see: https://github.com/riscv/riscv-gnu-toolchain/issues/217
|
} else if (msg == "qTStatus") {
|
||||||
// risc-v register 834
|
send_packet(conn, "");
|
||||||
reg_value = register_bank->getCSR(n - 65);
|
} else if (msg == "?") {
|
||||||
}
|
send_packet(conn, "S05");
|
||||||
std::stringstream stream;
|
} else if (msg == "qfThreadInfo") {
|
||||||
stream << std::setfill('0') << std::hex;
|
send_packet(conn, "");
|
||||||
stream << std::setw(8) << htonl(reg_value);
|
} else if (boost::starts_with(msg, "qL")) {
|
||||||
send_packet(conn, stream.str());
|
send_packet(conn, "");
|
||||||
} else if (boost::starts_with(msg, "P")) {
|
} else if (msg == "Hc-1") {
|
||||||
char * pEnd;
|
send_packet(conn, "OK");
|
||||||
long reg = strtol(msg.c_str() + 1, &pEnd, 16);
|
} else if (msg == "qC") {
|
||||||
int val = strtol(pEnd + 1, 0, 16);
|
send_packet(conn, "-1");
|
||||||
register_bank->setValue(reg + 1, val);
|
} else if (msg == "qAttached") {
|
||||||
send_packet(conn, "OK");
|
send_packet(conn, "0"); // 0 process started, 1 attached to process
|
||||||
} else if (boost::starts_with(msg, "m")) {
|
} else if (msg == "g") {
|
||||||
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);
|
std::stringstream stream;
|
||||||
dbg_trans.set_command(tlm::TLM_READ_COMMAND);
|
stream << std::setfill('0') << std::hex;
|
||||||
dbg_trans.set_address(addr);
|
for (int i = 1; i < 32; i++) {
|
||||||
dbg_trans.set_data_length(len);
|
stream << std::setw(8) << register_bank->getValue(i);
|
||||||
dbg_mem->transport_dbg(dbg_trans);
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
std::stringstream stream;
|
dbg_trans.set_data_ptr(pyld_array);
|
||||||
stream << std::setfill('0') << std::hex;
|
dbg_trans.set_command(tlm::TLM_READ_COMMAND);
|
||||||
for (auto &c : pyld_array) {
|
dbg_trans.set_address(addr);
|
||||||
stream << std::setw(2) << (0xFF & c);
|
dbg_trans.set_data_length(len);
|
||||||
}
|
dbg_mem->transport_dbg(dbg_trans);
|
||||||
|
|
||||||
send_packet(conn, stream.str());
|
std::stringstream stream;
|
||||||
|
stream << std::setfill('0') << std::hex;
|
||||||
|
for (auto &c: pyld_array) {
|
||||||
|
stream << std::setw(2) << (0xFF & c);
|
||||||
|
}
|
||||||
|
|
||||||
} else if (boost::starts_with(msg, "M")) {
|
send_packet(conn, stream.str());
|
||||||
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);
|
} else if (boost::starts_with(msg, "M")) {
|
||||||
if (search != breakpoints.end()) {
|
printf("M TBD\n");
|
||||||
breakpoint_hit = true;
|
send_packet(conn, "OK");
|
||||||
}
|
} else if (boost::starts_with(msg, "X")) {
|
||||||
} while ((breakpoint_hit == false) && (bkpt == false));
|
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();
|
||||||
|
|
||||||
std::cout << "Breakpoint hit at 0x" << std::hex << register_bank->getPC() << std::endl;
|
auto search = breakpoints.find(currentPC);
|
||||||
send_packet(conn, "S05");
|
if (search != breakpoints.end()) {
|
||||||
} else if (msg == "s") {
|
breakpoint_hit = true;
|
||||||
|
}
|
||||||
|
} while ((breakpoint_hit == false) && (bkpt == false));
|
||||||
|
|
||||||
bool breakpoint;
|
std::cout << "Breakpoint hit at 0x" << std::hex << register_bank->getPC() << std::endl;
|
||||||
dbg_cpu->CPU_step();
|
send_packet(conn, "S05");
|
||||||
|
} else if (msg == "s") {
|
||||||
|
|
||||||
uint32_t currentPC = register_bank->getPC();
|
bool breakpoint;
|
||||||
auto search = breakpoints.find(currentPC);
|
dbg_cpu->CPU_step();
|
||||||
if (search != breakpoints.end()) {
|
|
||||||
breakpoint = true;
|
|
||||||
} else {
|
|
||||||
breakpoint = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (breakpoint) {
|
uint32_t currentPC = register_bank->getPC();
|
||||||
send_packet(conn, "S03");
|
auto search = breakpoints.find(currentPC);
|
||||||
} else {
|
if (search != breakpoints.end()) {
|
||||||
send_packet(conn, "S05");
|
breakpoint = true;
|
||||||
}
|
} else {
|
||||||
|
breakpoint = false;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (boost::starts_with(msg, "vKill")) {
|
if (breakpoint) {
|
||||||
send_packet(conn, "OK");
|
send_packet(conn, "S03");
|
||||||
break;
|
} else {
|
||||||
} else if (boost::starts_with(msg, "Z1")) {
|
send_packet(conn, "S05");
|
||||||
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) {
|
} else if (boost::starts_with(msg, "vKill")) {
|
||||||
unsigned sum = 0;
|
send_packet(conn, "OK");
|
||||||
for (auto c : msg) {
|
break;
|
||||||
sum += unsigned(c);
|
} else if (boost::starts_with(msg, "Z1")) {
|
||||||
}
|
char *pEnd;
|
||||||
sum = sum % 256;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char low = nibble_to_hex[sum & 0xf];
|
std::string Debug::compute_checksum_string(const std::string &msg) {
|
||||||
char high = nibble_to_hex[(sum & (0xf << 4)) >> 4];
|
unsigned sum = 0;
|
||||||
|
for (auto c: msg) {
|
||||||
|
sum += unsigned(c);
|
||||||
|
}
|
||||||
|
sum = sum % 256;
|
||||||
|
|
||||||
return {high, low};
|
char low = nibble_to_hex[sum & 0xf];
|
||||||
}
|
char high = nibble_to_hex[(sum & (0xf << 4)) >> 4];
|
||||||
|
|
||||||
|
return {high, low};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
break;
|
|
||||||
case M_MULH:
|
|
||||||
return OP_M_MULH;
|
|
||||||
break;
|
|
||||||
case M_MULHSU:
|
|
||||||
return OP_M_MULHSU;
|
|
||||||
break;
|
|
||||||
case M_MULHU:
|
|
||||||
return OP_M_MULHU;
|
|
||||||
break;
|
|
||||||
case M_DIV:
|
|
||||||
return OP_M_DIV;
|
|
||||||
break;
|
|
||||||
case M_DIVU:
|
|
||||||
return OP_M_DIVU;
|
|
||||||
break;
|
|
||||||
case M_REM:
|
|
||||||
return OP_M_REM;
|
|
||||||
break;
|
|
||||||
case M_REMU:
|
|
||||||
return OP_M_REMU;
|
|
||||||
break;
|
|
||||||
[[unlikely]] default:
|
|
||||||
return OP_M_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return OP_M_ERROR;
|
switch (opcode()) {
|
||||||
}
|
case M_MUL:
|
||||||
|
return OP_M_MUL;
|
||||||
|
break;
|
||||||
|
case M_MULH:
|
||||||
|
return OP_M_MULH;
|
||||||
|
break;
|
||||||
|
case M_MULHSU:
|
||||||
|
return OP_M_MULHSU;
|
||||||
|
break;
|
||||||
|
case M_MULHU:
|
||||||
|
return OP_M_MULHU;
|
||||||
|
break;
|
||||||
|
case M_DIV:
|
||||||
|
return OP_M_DIV;
|
||||||
|
break;
|
||||||
|
case M_DIVU:
|
||||||
|
return OP_M_DIVU;
|
||||||
|
break;
|
||||||
|
case M_REM:
|
||||||
|
return OP_M_REM;
|
||||||
|
break;
|
||||||
|
case M_REMU:
|
||||||
|
return OP_M_REMU;
|
||||||
|
break;
|
||||||
|
[[unlikely]] default:
|
||||||
|
return OP_M_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
bool M_extension::Exec_M_MUL() const {
|
return OP_M_ERROR;
|
||||||
int rd, rs1, rs2;
|
}
|
||||||
std::int32_t multiplier, multiplicand;
|
|
||||||
std::int64_t result;
|
|
||||||
|
|
||||||
rd = get_rd();
|
bool M_extension::Exec_M_MUL() const {
|
||||||
rs1 = get_rs1();
|
int rd, rs1, rs2;
|
||||||
rs2 = get_rs2();
|
std::int32_t multiplier, multiplicand;
|
||||||
|
std::int64_t result;
|
||||||
|
|
||||||
multiplier = static_cast<std::int32_t>(regs->getValue(rs1));
|
rd = get_rd();
|
||||||
multiplicand = static_cast<std::int32_t>(regs->getValue(rs2));
|
rs1 = get_rs1();
|
||||||
|
rs2 = get_rs2();
|
||||||
|
|
||||||
result = static_cast<std::int64_t>(multiplier * multiplicand);
|
multiplier = static_cast<std::int32_t>(regs->getValue(rs1));
|
||||||
result = result & 0x00000000FFFFFFFF;
|
multiplicand = static_cast<std::int32_t>(regs->getValue(rs2));
|
||||||
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(),
|
result = static_cast<std::int64_t>(multiplier * multiplicand);
|
||||||
rs1, rs2, rd, result);
|
result = result & 0x00000000FFFFFFFF;
|
||||||
|
regs->setValue(rd, static_cast<std::int32_t>(result));
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
|
||||||
bool M_extension::Exec_M_MULH() const {
|
return true;
|
||||||
int rd, rs1, rs2;
|
}
|
||||||
std::int32_t multiplier, multiplicand;
|
|
||||||
std::int64_t result;
|
|
||||||
std::int32_t ret_value;
|
|
||||||
|
|
||||||
rd = get_rd();
|
bool M_extension::Exec_M_MULH() const {
|
||||||
rs1 = get_rs1();
|
int rd, rs1, rs2;
|
||||||
rs2 = get_rs2();
|
std::int32_t multiplier, multiplicand;
|
||||||
|
std::int64_t result;
|
||||||
|
std::int32_t ret_value;
|
||||||
|
|
||||||
multiplier = static_cast<std::int32_t>(regs->getValue(rs1));
|
rd = get_rd();
|
||||||
multiplicand = static_cast<std::int32_t>(regs->getValue(rs2));
|
rs1 = get_rs1();
|
||||||
|
rs2 = get_rs2();
|
||||||
|
|
||||||
result = static_cast<std::int64_t>(multiplier) * static_cast<std::int64_t>(multiplicand);
|
multiplier = static_cast<std::int32_t>(regs->getValue(rs1));
|
||||||
|
multiplicand = static_cast<std::int32_t>(regs->getValue(rs2));
|
||||||
|
|
||||||
ret_value = static_cast<std::int32_t>((result >> 32) & 0x00000000FFFFFFFF);
|
result = static_cast<std::int64_t>(multiplier) * static_cast<std::int64_t>(multiplicand);
|
||||||
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(),
|
ret_value = static_cast<std::int32_t>((result >> 32) & 0x00000000FFFFFFFF);
|
||||||
rs1, rs2, rd, result);
|
regs->setValue(rd, ret_value);
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
|
||||||
bool M_extension::Exec_M_MULHSU() const {
|
return true;
|
||||||
int rd, rs1, rs2;
|
}
|
||||||
std::int32_t multiplier;
|
|
||||||
std::uint32_t multiplicand;
|
|
||||||
std::int64_t result;
|
|
||||||
|
|
||||||
rd = get_rd();
|
bool M_extension::Exec_M_MULHSU() const {
|
||||||
rs1 = get_rs1();
|
int rd, rs1, rs2;
|
||||||
rs2 = get_rs2();
|
std::int32_t multiplier;
|
||||||
|
std::uint32_t multiplicand;
|
||||||
|
std::int64_t result;
|
||||||
|
|
||||||
multiplier = static_cast<std::int32_t>(regs->getValue(rs1));
|
rd = get_rd();
|
||||||
multiplicand = regs->getValue(rs2);
|
rs1 = get_rs1();
|
||||||
|
rs2 = get_rs2();
|
||||||
|
|
||||||
result = static_cast<std::int64_t>(multiplier * static_cast<std::uint64_t>(multiplicand));
|
multiplier = static_cast<std::int32_t>(regs->getValue(rs1));
|
||||||
result = (result >> 32) & 0x00000000FFFFFFFF;
|
multiplicand = regs->getValue(rs2);
|
||||||
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(),
|
result = static_cast<std::int64_t>(multiplier * static_cast<std::uint64_t>(multiplicand));
|
||||||
rs1, rs2, rd, result);
|
result = (result >> 32) & 0x00000000FFFFFFFF;
|
||||||
|
regs->setValue(rd, static_cast<std::int32_t>(result));
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
|
||||||
bool M_extension::Exec_M_MULHU() const {
|
return true;
|
||||||
int rd, rs1, rs2;
|
}
|
||||||
std::uint32_t multiplier, multiplicand;
|
|
||||||
std::uint64_t result;
|
|
||||||
std::int32_t ret_value;
|
|
||||||
|
|
||||||
rd = get_rd();
|
bool M_extension::Exec_M_MULHU() const {
|
||||||
rs1 = get_rs1();
|
int rd, rs1, rs2;
|
||||||
rs2 = get_rs2();
|
std::uint32_t multiplier, multiplicand;
|
||||||
|
std::uint64_t result;
|
||||||
|
std::int32_t ret_value;
|
||||||
|
|
||||||
multiplier = static_cast<std::int32_t>(regs->getValue(rs1));
|
rd = get_rd();
|
||||||
multiplicand = static_cast<std::int32_t>(regs->getValue(rs2));
|
rs1 = get_rs1();
|
||||||
|
rs2 = get_rs2();
|
||||||
|
|
||||||
result = static_cast<std::uint64_t>(multiplier) * static_cast<std::uint64_t>(multiplicand);
|
multiplier = static_cast<std::int32_t>(regs->getValue(rs1));
|
||||||
ret_value = static_cast<std::int32_t>((result >> 32) & 0x00000000FFFFFFFF);
|
multiplicand = static_cast<std::int32_t>(regs->getValue(rs2));
|
||||||
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(),
|
result = static_cast<std::uint64_t>(multiplier) * static_cast<std::uint64_t>(multiplicand);
|
||||||
rs1, rs2, rd, result);
|
ret_value = static_cast<std::int32_t>((result >> 32) & 0x00000000FFFFFFFF);
|
||||||
|
regs->setValue(rd, ret_value);
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
|
||||||
bool M_extension::Exec_M_DIV() const {
|
return true;
|
||||||
int rd, rs1, rs2;
|
}
|
||||||
std::int32_t divisor, dividend;
|
|
||||||
std::int64_t result;
|
|
||||||
|
|
||||||
rd = get_rd();
|
bool M_extension::Exec_M_DIV() const {
|
||||||
rs1 = get_rs1();
|
int rd, rs1, rs2;
|
||||||
rs2 = get_rs2();
|
std::int32_t divisor, dividend;
|
||||||
|
std::int64_t result;
|
||||||
|
|
||||||
dividend = static_cast<std::int32_t>(regs->getValue(rs1));
|
rd = get_rd();
|
||||||
divisor = static_cast<std::int32_t>(regs->getValue(rs2));
|
rs1 = get_rs1();
|
||||||
|
rs2 = get_rs2();
|
||||||
|
|
||||||
if (divisor == 0) {
|
dividend = static_cast<std::int32_t>(regs->getValue(rs1));
|
||||||
result = -1;
|
divisor = static_cast<std::int32_t>(regs->getValue(rs2));
|
||||||
} 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));
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), regs->getPC(),
|
regs->setValue(rd, static_cast<std::int32_t>(result));
|
||||||
rs1, rs2, rd, result);
|
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
|
||||||
bool M_extension::Exec_M_DIVU() const {
|
return true;
|
||||||
int rd, rs1, rs2;
|
}
|
||||||
std::uint32_t divisor, dividend;
|
|
||||||
std::uint64_t result;
|
|
||||||
|
|
||||||
rd = get_rd();
|
bool M_extension::Exec_M_DIVU() const {
|
||||||
rs1 = get_rs1();
|
int rd, rs1, rs2;
|
||||||
rs2 = get_rs2();
|
std::uint32_t divisor, dividend;
|
||||||
|
std::uint64_t result;
|
||||||
|
|
||||||
dividend = regs->getValue(rs1);
|
rd = get_rd();
|
||||||
divisor = regs->getValue(rs2);
|
rs1 = get_rs1();
|
||||||
|
rs2 = get_rs2();
|
||||||
|
|
||||||
if (divisor == 0) {
|
dividend = regs->getValue(rs1);
|
||||||
result = -1;
|
divisor = regs->getValue(rs2);
|
||||||
} else {
|
|
||||||
result = dividend / divisor;
|
|
||||||
result = result & 0x00000000FFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
regs->setValue(rd, static_cast<std::int32_t>(result));
|
if (divisor == 0) {
|
||||||
|
result = -1;
|
||||||
|
} else {
|
||||||
|
result = dividend / divisor;
|
||||||
|
result = result & 0x00000000FFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), regs->getPC(),
|
regs->setValue(rd, static_cast<std::int32_t>(result));
|
||||||
rs1, rs2, rd, result);
|
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
|
||||||
bool M_extension::Exec_M_REM() const {
|
return true;
|
||||||
int rd, rs1, rs2;
|
}
|
||||||
std::int32_t divisor, dividend;
|
|
||||||
std::int32_t result;
|
|
||||||
|
|
||||||
rd = get_rd();
|
bool M_extension::Exec_M_REM() const {
|
||||||
rs1 = get_rs1();
|
int rd, rs1, rs2;
|
||||||
rs2 = get_rs2();
|
std::int32_t divisor, dividend;
|
||||||
|
std::int32_t result;
|
||||||
|
|
||||||
dividend = static_cast<std::int32_t>(regs->getValue(rs1));
|
rd = get_rd();
|
||||||
divisor = static_cast<std::int32_t>(regs->getValue(rs2));
|
rs1 = get_rs1();
|
||||||
|
rs2 = get_rs2();
|
||||||
|
|
||||||
if (divisor == 0) {
|
dividend = static_cast<std::int32_t>(regs->getValue(rs1));
|
||||||
result = dividend;
|
divisor = static_cast<std::int32_t>(regs->getValue(rs2));
|
||||||
} else if ((divisor == -1) && (dividend == static_cast<std::int32_t>(0x80000000)) ) {
|
|
||||||
result = 0;
|
|
||||||
} else {
|
|
||||||
result = dividend % divisor;
|
|
||||||
}
|
|
||||||
|
|
||||||
regs->setValue(rd, result);
|
if (divisor == 0) {
|
||||||
|
result = dividend;
|
||||||
|
} else if ((divisor == -1) && (dividend == static_cast<std::int32_t>(0x80000000))) {
|
||||||
|
result = 0;
|
||||||
|
} else {
|
||||||
|
result = dividend % divisor;
|
||||||
|
}
|
||||||
|
|
||||||
logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), regs->getPC(),
|
regs->setValue(rd, result);
|
||||||
rs1, rs2, rd, result);
|
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
|
||||||
bool M_extension::Exec_M_REMU() const {
|
return true;
|
||||||
int rd, rs1, rs2;
|
}
|
||||||
std::uint32_t divisor, dividend;
|
|
||||||
std::uint32_t result;
|
|
||||||
|
|
||||||
rd = get_rd();
|
bool M_extension::Exec_M_REMU() const {
|
||||||
rs1 = get_rs1();
|
int rd, rs1, rs2;
|
||||||
rs2 = get_rs2();
|
std::uint32_t divisor, dividend;
|
||||||
|
std::uint32_t result;
|
||||||
|
|
||||||
dividend = static_cast<std::int32_t>(regs->getValue(rs1));
|
rd = get_rd();
|
||||||
divisor = static_cast<std::int32_t>(regs->getValue(rs2));
|
rs1 = get_rs1();
|
||||||
|
rs2 = get_rs2();
|
||||||
|
|
||||||
if (divisor == 0) {
|
dividend = static_cast<std::int32_t>(regs->getValue(rs1));
|
||||||
result = dividend;
|
divisor = static_cast<std::int32_t>(regs->getValue(rs2));
|
||||||
} else {
|
|
||||||
result = dividend % divisor;
|
|
||||||
}
|
|
||||||
|
|
||||||
regs->setValue(rd, static_cast<std::int32_t>(result));
|
if (divisor == 0) {
|
||||||
|
result = dividend;
|
||||||
|
} else {
|
||||||
|
result = dividend % divisor;
|
||||||
|
}
|
||||||
|
|
||||||
logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), regs->getPC(),
|
regs->setValue(rd, static_cast<std::int32_t>(result));
|
||||||
rs1, rs2, rd, result);
|
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
|
||||||
bool M_extension::process_instruction(Instruction &inst) {
|
return true;
|
||||||
bool PC_not_affected = true;
|
}
|
||||||
|
|
||||||
setInstr(inst.getInstr());
|
bool M_extension::process_instruction(Instruction &inst) {
|
||||||
|
bool PC_not_affected = true;
|
||||||
|
|
||||||
switch (decode()) {
|
setInstr(inst.getInstr());
|
||||||
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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
355
src/Memory.cpp
355
src/Memory.cpp
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
void Registers::dump() {
|
initCSR();
|
||||||
std::cout << "************************************" << std::endl;
|
register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory
|
||||||
std::cout << "Registers dump" << std::dec << std::endl;
|
register_PC = 0x80000000; // default _start address
|
||||||
std::cout << std::setfill('0') << std::uppercase;
|
}
|
||||||
std::cout << "x0 (zero): 0x" << std::right << std::setw(8)
|
|
||||||
<< std::hex << register_bank[0];
|
|
||||||
std::cout << " x1 (ra): 0x" << std::right << std::setw(8)
|
|
||||||
<< std::hex << register_bank[1];
|
|
||||||
std::cout << " x2 (sp): 0x" << std::right << std::setw(8)
|
|
||||||
<< std::hex << register_bank[2];
|
|
||||||
std::cout << " x3 (gp): 0x" << std::right << std::setw(8)
|
|
||||||
<< std::hex << register_bank[3] << std::endl;
|
|
||||||
|
|
||||||
std::cout << "x4 (tp): 0x" << std::right << std::setw(8)
|
void Registers::dump() {
|
||||||
<< std::hex << register_bank[4];
|
std::cout << "************************************" << std::endl;
|
||||||
std::cout << " x5 (t0): 0x" << std::right << std::setw(8)
|
std::cout << "Registers dump" << std::dec << std::endl;
|
||||||
<< std::hex << register_bank[5];
|
std::cout << std::setfill('0') << std::uppercase;
|
||||||
std::cout << " x6 (t1): 0x" << std::right << std::setw(8)
|
std::cout << "x0 (zero): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[6];
|
<< std::hex << register_bank[0];
|
||||||
std::cout << " x7 (t2): 0x" << std::right << std::setw(8)
|
std::cout << " x1 (ra): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[7] << std::endl;
|
<< std::hex << register_bank[1];
|
||||||
|
std::cout << " x2 (sp): 0x" << std::right << std::setw(8)
|
||||||
|
<< std::hex << register_bank[2];
|
||||||
|
std::cout << " x3 (gp): 0x" << std::right << std::setw(8)
|
||||||
|
<< std::hex << register_bank[3] << std::endl;
|
||||||
|
|
||||||
std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8)
|
std::cout << "x4 (tp): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[8];
|
<< std::hex << register_bank[4];
|
||||||
std::cout << " x9 (s1): 0x" << std::right << std::setw(8)
|
std::cout << " x5 (t0): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[9];
|
<< std::hex << register_bank[5];
|
||||||
std::cout << " x10 (a0): 0x" << std::right << std::setw(8)
|
std::cout << " x6 (t1): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[10];
|
<< std::hex << register_bank[6];
|
||||||
std::cout << " x11 (a1): 0x" << std::right << std::setw(8)
|
std::cout << " x7 (t2): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[11] << std::endl;
|
<< std::hex << register_bank[7] << std::endl;
|
||||||
|
|
||||||
std::cout << "x12 (a2): 0x" << std::right << std::setw(8)
|
std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[12];
|
<< std::hex << register_bank[8];
|
||||||
std::cout << " x13 (a3): 0x" << std::right << std::setw(8)
|
std::cout << " x9 (s1): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[13];
|
<< std::hex << register_bank[9];
|
||||||
std::cout << " x14 (a4): 0x" << std::right << std::setw(8)
|
std::cout << " x10 (a0): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[14];
|
<< std::hex << register_bank[10];
|
||||||
std::cout << " x15 (a5): 0x" << std::right << std::setw(8)
|
std::cout << " x11 (a1): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[15] << std::endl;
|
<< std::hex << register_bank[11] << std::endl;
|
||||||
|
|
||||||
std::cout << "x16 (a6): 0x" << std::right << std::setw(8)
|
std::cout << "x12 (a2): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[16];
|
<< std::hex << register_bank[12];
|
||||||
std::cout << " x17 (a7): 0x" << std::right << std::setw(8)
|
std::cout << " x13 (a3): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[17];
|
<< std::hex << register_bank[13];
|
||||||
std::cout << " x18 (s2): 0x" << std::right << std::setw(8)
|
std::cout << " x14 (a4): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[18];
|
<< std::hex << register_bank[14];
|
||||||
std::cout << " x19 (s3): 0x" << std::right << std::setw(8)
|
std::cout << " x15 (a5): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[19] << std::endl;
|
<< std::hex << register_bank[15] << std::endl;
|
||||||
|
|
||||||
std::cout << "x20 (s4): 0x" << std::right << std::setw(8)
|
std::cout << "x16 (a6): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[20];
|
<< std::hex << register_bank[16];
|
||||||
std::cout << " x21 (s5): 0x" << std::right << std::setw(8)
|
std::cout << " x17 (a7): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[21];
|
<< std::hex << register_bank[17];
|
||||||
std::cout << " x22 (s6): 0x" << std::right << std::setw(8)
|
std::cout << " x18 (s2): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[22];
|
<< std::hex << register_bank[18];
|
||||||
std::cout << " x23 (s7): 0x" << std::right << std::setw(8)
|
std::cout << " x19 (s3): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[23] << std::endl;
|
<< std::hex << register_bank[19] << std::endl;
|
||||||
|
|
||||||
std::cout << "x24 (s8): 0x" << std::right << std::setw(8)
|
std::cout << "x20 (s4): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[24];
|
<< std::hex << register_bank[20];
|
||||||
std::cout << " x25 (s9): 0x" << std::right << std::setw(8)
|
std::cout << " x21 (s5): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[25];
|
<< std::hex << register_bank[21];
|
||||||
std::cout << " x26 (s10): 0x" << std::right << std::setw(8)
|
std::cout << " x22 (s6): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[26];
|
<< std::hex << register_bank[22];
|
||||||
std::cout << " x27 (s11): 0x" << std::right << std::setw(8)
|
std::cout << " x23 (s7): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[27] << std::endl;
|
<< std::hex << register_bank[23] << std::endl;
|
||||||
|
|
||||||
std::cout << "x28 (t3): 0x" << std::right << std::setw(8)
|
std::cout << "x24 (s8): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[28];
|
<< std::hex << register_bank[24];
|
||||||
std::cout << " x29 (t4): 0x" << std::right << std::setw(8)
|
std::cout << " x25 (s9): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[29];
|
<< std::hex << register_bank[25];
|
||||||
std::cout << " x30 (t5): 0x" << std::right << std::setw(8)
|
std::cout << " x26 (s10): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[30];
|
<< std::hex << register_bank[26];
|
||||||
std::cout << " x31 (t6): 0x" << std::right << std::setw(8)
|
std::cout << " x27 (s11): 0x" << std::right << std::setw(8)
|
||||||
<< std::hex << register_bank[31] << std::endl;
|
<< std::hex << register_bank[27] << std::endl;
|
||||||
|
|
||||||
std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl;
|
std::cout << "x28 (t3): 0x" << std::right << std::setw(8)
|
||||||
std::cout << "************************************" << std::endl;
|
<< std::hex << register_bank[28];
|
||||||
}
|
std::cout << " x29 (t4): 0x" << std::right << std::setw(8)
|
||||||
|
<< std::hex << register_bank[29];
|
||||||
|
std::cout << " x30 (t5): 0x" << std::right << std::setw(8)
|
||||||
|
<< std::hex << register_bank[30];
|
||||||
|
std::cout << " x31 (t6): 0x" << std::right << std::setw(8)
|
||||||
|
<< std::hex << register_bank[31] << std::endl;
|
||||||
|
|
||||||
void Registers::setValue(int reg_num, std::int32_t value) {
|
std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl;
|
||||||
if ((reg_num != 0) && (reg_num < 32)) {
|
std::cout << "************************************" << std::endl;
|
||||||
register_bank[reg_num] = value;
|
}
|
||||||
perf->registerWrite();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint32_t Registers::getValue(int reg_num) const {
|
void Registers::setValue(int reg_num, std::int32_t value) {
|
||||||
if ((reg_num >= 0) && (reg_num < 32)) {
|
if ((reg_num != 0) && (reg_num < 32)) {
|
||||||
perf->registerRead();
|
register_bank[reg_num] = value;
|
||||||
return register_bank[reg_num];
|
perf->registerWrite();
|
||||||
} else {
|
}
|
||||||
return static_cast<std::int32_t>(0xFFFFFFFF);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint32_t Registers::getPC() const {
|
std::uint32_t Registers::getValue(int reg_num) const {
|
||||||
return register_PC;
|
if ((reg_num >= 0) && (reg_num < 32)) {
|
||||||
}
|
perf->registerRead();
|
||||||
|
return register_bank[reg_num];
|
||||||
|
} else {
|
||||||
|
return static_cast<std::int32_t>(0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Registers::setPC(std::uint32_t new_pc) {
|
std::uint32_t Registers::getPC() const {
|
||||||
register_PC = new_pc;
|
return register_PC;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t Registers::getCSR(const int csr) {
|
void Registers::setPC(std::uint32_t new_pc) {
|
||||||
std::uint32_t ret_value;
|
register_PC = new_pc;
|
||||||
|
}
|
||||||
|
|
||||||
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(
|
|
||||||
sc_core::sc_time_stamp()
|
|
||||||
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
|
||||||
& 0x00000000FFFFFFFF;
|
|
||||||
break;
|
|
||||||
case CSR_CYCLEH:
|
|
||||||
case CSR_MCYCLEH:
|
|
||||||
ret_value = static_cast<std::uint32_t>((std::uint64_t) (sc_core::sc_time(
|
|
||||||
sc_core::sc_time_stamp()
|
|
||||||
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
|
||||||
>> 32 & 0x00000000FFFFFFFF);
|
|
||||||
break;
|
|
||||||
case CSR_TIME:
|
|
||||||
ret_value = static_cast<std::uint64_t>(sc_core::sc_time(
|
|
||||||
sc_core::sc_time_stamp()
|
|
||||||
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
|
||||||
& 0x00000000FFFFFFFF;
|
|
||||||
break;
|
|
||||||
case CSR_TIMEH:
|
|
||||||
ret_value = static_cast<std::uint32_t>((std::uint64_t) (sc_core::sc_time(
|
|
||||||
sc_core::sc_time_stamp()
|
|
||||||
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
|
||||||
>> 32 & 0x00000000FFFFFFFF);
|
|
||||||
break;
|
|
||||||
[[likely]] default:
|
|
||||||
ret_value = CSR[csr];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Registers::setCSR(int csr, std::uint32_t value) {
|
switch (csr) {
|
||||||
/* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to be writable,
|
case CSR_CYCLE:
|
||||||
* but Volume II: Privileged Architecture v1.10 says MISA is writable (?)
|
case CSR_MCYCLE:
|
||||||
*/
|
ret_value = static_cast<std::uint64_t>(sc_core::sc_time(
|
||||||
if (csr != CSR_MISA) {
|
sc_core::sc_time_stamp()
|
||||||
CSR[csr] = value;
|
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
||||||
}
|
& 0x00000000FFFFFFFF;
|
||||||
}
|
break;
|
||||||
|
case CSR_CYCLEH:
|
||||||
|
case CSR_MCYCLEH:
|
||||||
|
ret_value = static_cast<std::uint32_t>((std::uint64_t) (sc_core::sc_time(
|
||||||
|
sc_core::sc_time_stamp()
|
||||||
|
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
||||||
|
>> 32 & 0x00000000FFFFFFFF);
|
||||||
|
break;
|
||||||
|
case CSR_TIME:
|
||||||
|
ret_value = static_cast<std::uint64_t>(sc_core::sc_time(
|
||||||
|
sc_core::sc_time_stamp()
|
||||||
|
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
||||||
|
& 0x00000000FFFFFFFF;
|
||||||
|
break;
|
||||||
|
case CSR_TIMEH:
|
||||||
|
ret_value = static_cast<std::uint32_t>((std::uint64_t) (sc_core::sc_time(
|
||||||
|
sc_core::sc_time_stamp()
|
||||||
|
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
||||||
|
>> 32 & 0x00000000FFFFFFFF);
|
||||||
|
break;
|
||||||
|
[[likely]] default:
|
||||||
|
ret_value = CSR[csr];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret_value;
|
||||||
|
}
|
||||||
|
|
||||||
void Registers::initCSR() {
|
void Registers::setCSR(int csr, std::uint32_t value) {
|
||||||
CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION
|
/* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to be writable,
|
||||||
| MISA_A_EXTENSION | MISA_I_BASE;
|
* but Volume II: Privileged Architecture v1.10 says MISA is writable (?)
|
||||||
CSR[CSR_MSTATUS] = MISA_MXL;
|
*/
|
||||||
}
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
158
src/Timer.cpp
158
src/Timer.cpp
|
@ -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) {
|
||||||
|
|
||||||
SC_THREAD(run);
|
socket.register_b_transport(this, &Timer::b_transport);
|
||||||
}
|
|
||||||
|
|
||||||
[[noreturn]] void Timer::run() {
|
SC_THREAD(run);
|
||||||
|
}
|
||||||
|
|
||||||
auto *irq_trans = new tlm::tlm_generic_payload;
|
[[noreturn]] void Timer::run() {
|
||||||
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) {
|
auto *irq_trans = new tlm::tlm_generic_payload;
|
||||||
wait(timer_event);
|
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
|
||||||
irq_line->b_transport(*irq_trans, delay);
|
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);
|
||||||
|
|
||||||
void Timer::b_transport(tlm::tlm_generic_payload &trans,
|
while (true) {
|
||||||
sc_core::sc_time &delay) {
|
wait(timer_event);
|
||||||
|
irq_line->b_transport(*irq_trans, delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tlm::tlm_command cmd = trans.get_command();
|
void Timer::b_transport(tlm::tlm_generic_payload &trans,
|
||||||
sc_dt::uint64 addr = trans.get_address();
|
sc_core::sc_time &delay) {
|
||||||
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;
|
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) {
|
if (cmd == tlm::TLM_WRITE_COMMAND) {
|
||||||
memcpy(&aux_value, ptr, len);
|
memcpy(&aux_value, ptr, len);
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case TIMER_MEMORY_ADDRESS_LO:
|
case TIMER_MEMORY_ADDRESS_LO:
|
||||||
m_mtime.range(31, 0) = aux_value;
|
m_mtime.range(31, 0) = aux_value;
|
||||||
break;
|
break;
|
||||||
case TIMER_MEMORY_ADDRESS_HI:
|
case TIMER_MEMORY_ADDRESS_HI:
|
||||||
m_mtime.range(63, 32) = aux_value;
|
m_mtime.range(63, 32) = aux_value;
|
||||||
break;
|
break;
|
||||||
case TIMERCMP_MEMORY_ADDRESS_LO:
|
case TIMERCMP_MEMORY_ADDRESS_LO:
|
||||||
m_mtimecmp.range(31, 0) = aux_value;
|
m_mtimecmp.range(31, 0) = aux_value;
|
||||||
break;
|
break;
|
||||||
case TIMERCMP_MEMORY_ADDRESS_HI:
|
case TIMERCMP_MEMORY_ADDRESS_HI:
|
||||||
m_mtimecmp.range(63, 32) = aux_value;
|
m_mtimecmp.range(63, 32) = aux_value;
|
||||||
|
|
||||||
std::uint64_t notify_time;
|
std::uint64_t notify_time;
|
||||||
// notify needs relative time, mtimecmp works in absolute time
|
// notify needs relative time, mtimecmp works in absolute time
|
||||||
notify_time = m_mtimecmp - m_mtime;
|
notify_time = m_mtimecmp - m_mtime;
|
||||||
|
|
||||||
timer_event.notify(sc_core::sc_time(notify_time, sc_core::SC_NS));
|
timer_event.notify(sc_core::sc_time(notify_time, sc_core::SC_NS));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
|
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else { // TLM_READ_COMMAND
|
} else { // TLM_READ_COMMAND
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case TIMER_MEMORY_ADDRESS_LO:
|
case TIMER_MEMORY_ADDRESS_LO:
|
||||||
m_mtime = sc_core::sc_time_stamp().value();
|
m_mtime = sc_core::sc_time_stamp().value();
|
||||||
aux_value = m_mtime.range(31, 0);
|
aux_value = m_mtime.range(31, 0);
|
||||||
break;
|
break;
|
||||||
case TIMER_MEMORY_ADDRESS_HI:
|
case TIMER_MEMORY_ADDRESS_HI:
|
||||||
aux_value = m_mtime.range(63, 32);
|
aux_value = m_mtime.range(63, 32);
|
||||||
break;
|
break;
|
||||||
case TIMERCMP_MEMORY_ADDRESS_LO:
|
case TIMERCMP_MEMORY_ADDRESS_LO:
|
||||||
aux_value = m_mtimecmp.range(31, 0);
|
aux_value = m_mtimecmp.range(31, 0);
|
||||||
break;
|
break;
|
||||||
case TIMERCMP_MEMORY_ADDRESS_HI:
|
case TIMERCMP_MEMORY_ADDRESS_HI:
|
||||||
aux_value = m_mtimecmp.range(63, 32);
|
aux_value = m_mtimecmp.range(63, 32);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
|
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(ptr, &aux_value, len);
|
memcpy(ptr, &aux_value, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
trans.set_response_status(tlm::TLM_OK_RESPONSE);
|
trans.set_response_status(tlm::TLM_OK_RESPONSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
137
src/Trace.cpp
137
src/Trace.cpp
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
execvp("xterm", argv);
|
char *argv[3];
|
||||||
}
|
argv[0] = (char *) ("xterm");
|
||||||
|
argv[1] = arg;
|
||||||
|
argv[2] = nullptr;
|
||||||
|
|
||||||
void Trace::xtermKill() {
|
execvp("xterm", argv);
|
||||||
|
}
|
||||||
|
|
||||||
if (-1 != ptSlave) { // Close down the slave
|
void Trace::xtermKill() {
|
||||||
close(ptSlave); // Close the FD
|
|
||||||
ptSlave = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (-1 != ptMaster) { // Close down the master
|
if (-1 != ptSlave) { // Close down the slave
|
||||||
close(ptMaster);
|
close(ptSlave); // Close the FD
|
||||||
ptMaster = -1;
|
ptSlave = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xtermPid > 0) { // Kill the terminal
|
if (-1 != ptMaster) { // Close down the master
|
||||||
kill(xtermPid, SIGKILL);
|
close(ptMaster);
|
||||||
waitpid(xtermPid, nullptr, 0);
|
ptMaster = -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Trace::xtermSetup() {
|
if (xtermPid > 0) { // Kill the terminal
|
||||||
ptMaster = open("/dev/ptmx", O_RDWR);
|
kill(xtermPid, SIGKILL);
|
||||||
|
waitpid(xtermPid, nullptr, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ptMaster != -1) {
|
void Trace::xtermSetup() {
|
||||||
grantpt(ptMaster);
|
ptMaster = open("/dev/ptmx", O_RDWR);
|
||||||
|
|
||||||
unlockpt(ptMaster);
|
if (ptMaster != -1) {
|
||||||
|
grantpt(ptMaster);
|
||||||
|
|
||||||
char *ptSlaveName = ptsname(ptMaster);
|
unlockpt(ptMaster);
|
||||||
ptSlave = open(ptSlaveName, O_RDWR); // In and out are the same
|
|
||||||
|
|
||||||
struct termios termInfo{};
|
char *ptSlaveName = ptsname(ptMaster);
|
||||||
tcgetattr(ptSlave, &termInfo);
|
ptSlave = open(ptSlaveName, O_RDWR); // In and out are the same
|
||||||
|
|
||||||
termInfo.c_lflag &= ~ECHO;
|
struct termios termInfo{};
|
||||||
termInfo.c_lflag &= ~ICANON;
|
tcgetattr(ptSlave, &termInfo);
|
||||||
tcsetattr(ptSlave, TCSADRAIN, &termInfo);
|
|
||||||
|
|
||||||
xtermPid = fork();
|
termInfo.c_lflag &= ~ECHO;
|
||||||
|
termInfo.c_lflag &= ~ICANON;
|
||||||
|
tcsetattr(ptSlave, TCSADRAIN, &termInfo);
|
||||||
|
|
||||||
if (xtermPid == 0) {
|
xtermPid = fork();
|
||||||
xtermLaunch(ptSlaveName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SC_HAS_PROCESS(Trace);
|
if (xtermPid == 0) {
|
||||||
Trace::Trace(sc_core::sc_module_name const &name) :
|
xtermLaunch(ptSlaveName);
|
||||||
sc_module(name), socket("socket") {
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
socket.register_b_transport(this, &Trace::b_transport);
|
SC_HAS_PROCESS(Trace);
|
||||||
|
|
||||||
xtermSetup();
|
Trace::Trace(sc_core::sc_module_name const &name) :
|
||||||
}
|
sc_module(name), socket("socket") {
|
||||||
|
|
||||||
Trace::~Trace() {
|
socket.register_b_transport(this, &Trace::b_transport);
|
||||||
xtermKill();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Trace::b_transport(tlm::tlm_generic_payload &trans,
|
xtermSetup();
|
||||||
sc_core::sc_time &delay) {
|
}
|
||||||
|
|
||||||
unsigned char *ptr = trans.get_data_ptr();
|
Trace::~Trace() {
|
||||||
delay = sc_core::SC_ZERO_TIME;
|
xtermKill();
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t a = write(ptSlave, ptr, 1);
|
void Trace::b_transport(tlm::tlm_generic_payload &trans,
|
||||||
(void) a;
|
sc_core::sc_time &delay) {
|
||||||
|
|
||||||
trans.set_response_status(tlm::TLM_OK_RESPONSE);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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) {
|
extension_base::~extension_base() = default;
|
||||||
m_instr = sc_dt::sc_uint<32>(p_instr);
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
void extension_base::RaiseException(std::uint32_t cause, std::uint32_t inst) {
|
||||||
m_cause = regs->getCSR(CSR_MSTATUS);
|
std::uint32_t new_pc, current_pc, m_cause;
|
||||||
m_cause |= cause;
|
|
||||||
|
|
||||||
new_pc = regs->getCSR(CSR_MTVEC);
|
current_pc = regs->getPC();
|
||||||
|
m_cause = regs->getCSR(CSR_MSTATUS);
|
||||||
|
m_cause |= cause;
|
||||||
|
|
||||||
regs->setCSR(CSR_MEPC, current_pc);
|
new_pc = regs->getCSR(CSR_MTVEC);
|
||||||
|
|
||||||
if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) {
|
regs->setCSR(CSR_MEPC, current_pc);
|
||||||
regs->setCSR(CSR_MTVAL, inst);
|
|
||||||
} else {
|
|
||||||
regs->setCSR(CSR_MTVAL, current_pc);
|
|
||||||
}
|
|
||||||
|
|
||||||
regs->setCSR(CSR_MCAUSE, cause);
|
if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) {
|
||||||
regs->setCSR(CSR_MSTATUS, m_cause);
|
regs->setCSR(CSR_MTVAL, inst);
|
||||||
|
} else {
|
||||||
|
regs->setCSR(CSR_MTVAL, current_pc);
|
||||||
|
}
|
||||||
|
|
||||||
regs->setPC(new_pc);
|
regs->setCSR(CSR_MCAUSE, cause);
|
||||||
|
regs->setCSR(CSR_MSTATUS, m_cause);
|
||||||
|
|
||||||
logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC(),
|
regs->setPC(new_pc);
|
||||||
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());
|
bool extension_base::NOP() {
|
||||||
sc_core::sc_stop();
|
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue