diff --git a/inc/A_extension.h b/inc/A_extension.h index 8d7d569..b2d08ad 100644 --- a/inc/A_extension.h +++ b/inc/A_extension.h @@ -52,59 +52,465 @@ namespace riscv_tlm { /** * @brief Instruction decoding and fields access */ - class A_extension : public extension_base { + template + class A_extension : public extension_base { public: /** * @brief Constructor, same as base class */ - using extension_base::extension_base; + using extension_base::extension_base; /** * @brief Access to opcode field * @return return opcode field */ - inline int32_t opcode() const override { - return static_cast(m_instr.range(31, 27)); + inline std::uint32_t opcode() const override { + return static_cast(this->m_instr.range(31, 27)); } /** * @brief Decodes opcode of instruction * @return opcode of instruction */ - op_A_Codes decode() const; + op_A_Codes decode() const { - inline void dump() const override { - std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + switch (opcode()) { + case A_LR: + return OP_A_LR; + break; + case A_SC: + return OP_A_SC; + break; + case A_AMOSWAP: + return OP_A_AMOSWAP; + break; + case A_AMOADD: + return OP_A_AMOADD; + break; + case A_AMOXOR: + return OP_A_AMOXOR; + break; + case A_AMOAND: + return OP_A_AMOAND; + break; + case A_AMOOR: + return OP_A_AMOOR; + break; + case A_AMOMIN: + return OP_A_AMOMIN; + break; + case A_AMOMAX: + return OP_A_AMOMAX; + break; + case A_AMOMINU: + return OP_A_AMOMINU; + break; + case A_AMOMAXU: + return OP_A_AMOMAXU; + break; + [[unlikely]] default: + return OP_A_ERROR; + break; + + } + + return OP_A_ERROR; } - bool Exec_A_LR(); + inline void dump() const override { + std::cout << std::hex << "0x" << this->m_instr << std::dec << std::endl; + } - bool Exec_A_SC(); + bool Exec_A_LR() { + std::uint32_t mem_addr = 0; + int rd, rs1, rs2; + std::uint32_t data; - bool Exec_A_AMOSWAP() const; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_A_AMOADD() const; + if (rs2 != 0) { + std::cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << std::endl; + this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr); - bool Exec_A_AMOXOR() const; + return false; + } - bool Exec_A_AMOAND() const; + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, static_cast(data)); - bool Exec_A_AMOOR() const; + TLB_reserve(mem_addr); - bool Exec_A_AMOMIN() const; + this->logger->debug("{} ns. PC: 0x{:x}. A.LR.W: x{:d}(0x{:x}) -> x{:d}(0x{:x}) ", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, mem_addr, rd, data); - bool Exec_A_AMOMAX() const; + return true; + } - bool Exec_A_AMOMINU() const; + bool Exec_A_SC() { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; - bool Exec_A_AMOMAXU() const; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool process_instruction(Instruction &inst); + mem_addr = this->regs->getValue(rs1); + data = this->regs->getValue(rs2); - void TLB_reserve(std::uint32_t address); + if (TLB_reserved(mem_addr)) { + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + this->regs->setValue(rd, 0); // SC writes 0 to rd on success + } else { + this->regs->setValue(rd, 1); // SC writes nonzero on failure + } - bool TLB_reserved(std::uint32_t address); + this->logger->debug("{} ns. PC: 0x{:x}. A.SC.W: (0x{:x}) <- x{:d}(0x{:x}) ", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + mem_addr, rs2, data); + + return true; + } + + bool Exec_A_AMOSWAP() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, static_cast(data)); + + // swap + aux = this->regs->getValue(rs2); + this->regs->setValue(rs2, static_cast(data)); + + this->mem_intf->writeDataMem(mem_addr, aux, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOSWAP"); + + return true; + } + + bool Exec_A_AMOADD() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // add + data = data + this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOADD"); + + return true; + } + + bool Exec_A_AMOXOR() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // add + data = data ^ this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOXOR"); + + return true; + } + + bool Exec_A_AMOAND() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // add + data = data & this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOAND"); + + return true; + } + + bool Exec_A_AMOOR() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // add + data = data | this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOOR"); + + return true; + } + + bool Exec_A_AMOMIN() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // min + aux = this->regs->getValue(rs2); + if ((int32_t) data < (int32_t) aux) { + aux = data; + } + + this->mem_intf->writeDataMem(mem_addr, aux, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMIN"); + + return true; + } + + bool Exec_A_AMOMAX() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // > + aux = this->regs->getValue(rs2); + if ((int32_t) data > (int32_t) aux) { + aux = data; + } + + this->mem_intf->writeDataMem(mem_addr, aux, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMAX"); + + return true; + } + + bool Exec_A_AMOMINU() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // min + aux = this->regs->getValue(rs2); + if (data < aux) { + aux = data; + } + + this->mem_intf->writeDataMem(mem_addr, aux, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMINU"); + + return true; + } + + bool Exec_A_AMOMAXU() const { + std::uint32_t mem_addr; + int rd, rs1, rs2; + std::uint32_t data; + std::uint32_t aux; + + /* These instructions must be atomic */ + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + mem_addr = this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, static_cast(data)); + + // max + aux = this->regs->getValue(rs2); + if (data > aux) { + aux = data; + } + + this->mem_intf->writeDataMem(mem_addr, aux, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMAXU"); + + return true; + } + + void TLB_reserve(std::uint32_t address) { + TLB_A_Entries.insert(address); + } + + bool TLB_reserved(std::uint32_t address) { + if (TLB_A_Entries.count(address) == 1) { + TLB_A_Entries.erase(address); + return true; + } else { + return false; + } + } + + bool process_instruction(Instruction &inst) { + bool PC_not_affected = true; + + this->setInstr(inst.getInstr()); + + switch (decode()) { + case OP_A_LR: + Exec_A_LR(); + break; + case OP_A_SC: + Exec_A_SC(); + break; + case OP_A_AMOSWAP: + Exec_A_AMOSWAP(); + break; + case OP_A_AMOADD: + Exec_A_AMOADD(); + break; + case OP_A_AMOXOR: + Exec_A_AMOXOR(); + break; + case OP_A_AMOAND: + Exec_A_AMOAND(); + break; + case OP_A_AMOOR: + Exec_A_AMOOR(); + break; + case OP_A_AMOMIN: + Exec_A_AMOMIN(); + break; + case OP_A_AMOMAX: + Exec_A_AMOMAX(); + break; + case OP_A_AMOMINU: + Exec_A_AMOMINU(); + break; + case OP_A_AMOMAXU: + Exec_A_AMOMAXU(); + break; + [[unlikely]] default: + std::cout << "A instruction not implemented yet" << std::endl; + inst.dump(); + this->NOP(); + break; + } + + return PC_not_affected; + } private: std::unordered_set TLB_A_Entries; diff --git a/inc/BASE_ISA.h b/inc/BASE_ISA.h index 3c2ec3a..5fb79df 100644 --- a/inc/BASE_ISA.h +++ b/inc/BASE_ISA.h @@ -89,23 +89,98 @@ namespace riscv_tlm { OP_ERROR } opCodes; + enum Codes { + LUI = 0b0110111, + AUIPC = 0b0010111, + JAL = 0b1101111, + JALR = 0b1100111, + + BEQ = 0b1100011, + BEQ_F = 0b000, + BNE_F = 0b001, + BLT_F = 0b100, + BGE_F = 0b101, + BLTU_F = 0b110, + BGEU_F = 0b111, + + LB = 0b0000011, + LB_F = 0b000, + LH_F = 0b001, + LW_F = 0b010, + LBU_F = 0b100, + LHU_F = 0b101, + + SB = 0b0100011, + SB_F = 0b000, + SH_F = 0b001, + SW_F = 0b010, + + ADDI = 0b0010011, + ADDI_F = 0b000, + SLTI_F = 0b010, + SLTIU_F = 0b011, + XORI_F = 0b100, + ORI_F = 0b110, + ANDI_F = 0b111, + SLLI_F = 0b001, + SRLI_F = 0b101, + SRLI_F7 = 0b0000000, + SRAI_F7 = 0b0100000, + + ADD = 0b0110011, + ADD_F = 0b000, + SUB_F = 0b000, + ADD_F7 = 0b0000000, + SUB_F7 = 0b0100000, + + SLL_F = 0b001, + SLT_F = 0b010, + SLTU_F = 0b011, + XOR_F = 0b100, + SRL_F = 0b101, + SRA_F = 0b101, + SRL_F7 = 0b0000000, + SRA_F7 = 0b0100000, + OR_F = 0b110, + AND_F = 0b111, + + FENCE = 0b0001111, + ECALL = 0b1110011, + ECALL_F = 0b000000000000, + EBREAK_F = 0b000000000001, + URET_F = 0b000000000010, + SRET_F = 0b000100000010, + MRET_F = 0b001100000010, + WFI_F = 0b000100000101, + SFENCE_F = 0b0001001, + + ECALL_F3 = 0b000, + CSRRW = 0b001, + CSRRS = 0b010, + CSRRC = 0b011, + CSRRWI = 0b101, + CSRRSI = 0b110, + CSRRCI = 0b111, + }; + /** * @brief Risc_V execute module */ - class BASE_ISA : public extension_base { + template + class BASE_ISA : public extension_base { public: /** * @brief Constructor, same as base class */ - using extension_base::extension_base; + using extension_base::extension_base; /** * @brief Access to funct7 field * @return funct7 field */ inline std::int32_t get_funct7() const { - return m_instr.range(31, 25); + return this->m_instr.range(31, 25); } /** @@ -113,7 +188,7 @@ namespace riscv_tlm { * @param value desired func7 value */ inline void set_func7(std::int32_t value) { - m_instr.range(31, 25) = value; + this->m_instr.range(31, 25) = value; } /** @@ -123,10 +198,10 @@ namespace riscv_tlm { inline std::int32_t get_imm_I() const { std::uint32_t aux = 0; - aux = m_instr.range(31, 20); + aux = this->m_instr.range(31, 20); /* sign extension (optimize) */ - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } @@ -138,7 +213,7 @@ namespace riscv_tlm { * @param value desired I value */ inline void set_imm_I(std::int32_t value) { - m_instr.range(31, 20) = value; + this->m_instr.range(31, 20) = value; } /** @@ -148,10 +223,10 @@ namespace riscv_tlm { inline std::int32_t get_imm_S() const { std::uint32_t aux = 0; - aux = m_instr.range(31, 25) << 5; - aux |= m_instr.range(11, 7); + aux = this->m_instr.range(31, 25) << 5; + aux |= this->m_instr.range(11, 7); - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } @@ -163,7 +238,7 @@ namespace riscv_tlm { * @return immediate_U field */ inline std::int32_t get_imm_U() const { - return static_cast(m_instr.range(31, 12)); + return static_cast(this->m_instr.range(31, 12)); } /** @@ -171,7 +246,7 @@ namespace riscv_tlm { * @param value desired U value */ inline void set_imm_U(std::int32_t value) { - m_instr.range(31, 12) = (value << 12); + this->m_instr.range(31, 12) = (value << 12); } /** @@ -181,12 +256,12 @@ namespace riscv_tlm { inline std::int32_t get_imm_B() const { std::int32_t aux = 0; - aux |= m_instr[7] << 11; - aux |= m_instr.range(30, 25) << 5; - aux |= m_instr[31] << 12; - aux |= m_instr.range(11, 8) << 1; + aux |= this->m_instr[7] << 11; + aux |= this->m_instr.range(30, 25) << 5; + aux |= this->m_instr[31] << 12; + aux |= this->m_instr.range(11, 8) << 1; - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } @@ -200,10 +275,10 @@ namespace riscv_tlm { inline void set_imm_B(std::int32_t value) { sc_dt::sc_uint<32> aux = value; - m_instr[31] = aux[12]; - m_instr.range(30, 25) = aux.range(10, 5); - m_instr.range(11, 7) = aux.range(4, 1); - m_instr[6] = aux[11]; + this->m_instr[31] = aux[12]; + this->m_instr.range(30, 25) = aux.range(10, 5); + this->m_instr.range(11, 7) = aux.range(4, 1); + this->m_instr[6] = aux[11]; } /** @@ -213,13 +288,13 @@ namespace riscv_tlm { inline std::int32_t get_imm_J() const { std::int32_t aux = 0; - aux = m_instr[31] << 20; - aux |= m_instr.range(19, 12) << 12; - aux |= m_instr[20] << 11; - aux |= m_instr.range(30, 21) << 1; + aux = this->m_instr[31] << 20; + aux |= this->m_instr.range(19, 12) << 12; + aux |= this->m_instr[20] << 11; + aux |= this->m_instr.range(30, 21) << 1; /* bit extension (better way to do that?) */ - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b111111111111) << 20; } @@ -233,10 +308,10 @@ namespace riscv_tlm { 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[20] = aux[11]; - m_instr.range(19, 12) = aux.range(19, 12); + this->m_instr[31] = aux[20]; + this->m_instr.range(30, 21) = aux.range(10, 1); + this->m_instr[20] = aux[11]; + this->m_instr.range(19, 12) = aux.range(19, 12); } /** @@ -244,7 +319,7 @@ namespace riscv_tlm { * @return value corresponding to inst(25:20) */ inline std::int32_t get_shamt() const { - return static_cast(m_instr.range(25, 20)); + return static_cast(this->m_instr.range(25, 20)); } /** @@ -254,7 +329,7 @@ namespace riscv_tlm { inline std::int32_t get_csr() const { std::int32_t aux = 0; - aux = static_cast(m_instr.range(31, 20)); + aux = static_cast(this->m_instr.range(31, 20)); return aux; } @@ -263,127 +338,1454 @@ namespace riscv_tlm { * @brief Access to opcode field * @return return opcode field */ - inline std::int32_t opcode() const override { - return static_cast(m_instr.range(6, 0)); + inline std::uint32_t opcode() const override { + return static_cast(this->m_instr.range(6, 0)); } - bool Exec_LUI() const; + bool Exec_LUI() const { + unsigned int rd; + std::uint32_t imm; - bool Exec_AUIPC() const; + rd = this->get_rd(); + imm = get_imm_U() << 12; + this->regs->setValue(rd, static_cast(imm)); - bool Exec_JAL() const; + this->logger->debug("{} ns. PC: 0x{:x}. LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rd, imm); - bool Exec_JALR(); + return true; + } - bool Exec_BEQ() const; + bool Exec_AUIPC() const { + unsigned int rd; + std::uint32_t imm; + std::uint32_t new_pc; - bool Exec_BNE() const; + rd = this->get_rd(); + imm = get_imm_U() << 12; + new_pc = static_cast(this->regs->getPC() + imm); - bool Exec_BLT() const; + this->regs->setValue(rd, new_pc); - bool Exec_BGE() const; + this->logger->debug("{} ns. PC: 0x{:x}. AUIPC: x{:d} <- 0x{:x} + PC (0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rd, imm, new_pc); - bool Exec_BLTU() const; + return true; + } - bool Exec_BGEU() const; + bool Exec_JAL() const { + std::int32_t mem_addr; + unsigned int rd; + std::uint32_t new_pc, old_pc; - bool Exec_LB() const; + rd = this->get_rd(); + mem_addr = get_imm_J(); + old_pc = this->regs->getPC(); + new_pc = old_pc + mem_addr; - bool Exec_LH() const; + this->regs->setPC(new_pc); - bool Exec_LW() const; + old_pc = old_pc + 4; + this->regs->setValue(rd, old_pc); - bool Exec_LBU() const; + this->logger->debug("{} ns. PC: 0x{:x}. JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rd, old_pc, mem_addr, new_pc); - bool Exec_LHU() const; + return true; + } - bool Exec_SB() const; + bool Exec_JALR() { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::uint32_t new_pc, old_pc; - bool Exec_SH() const; + rd = this->get_rd(); + rs1 = this->get_rs1(); + mem_addr = get_imm_I(); - bool Exec_SW() const; + old_pc = this->regs->getPC(); + this->regs->setValue(rd, old_pc + 4); - bool Exec_SBU() const; + new_pc = static_cast((this->regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); - bool Exec_SHU() const; + if ((new_pc & 0x00000003) != 0) { + // not aligned + this->logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x} PC <- 0x{:x}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rd, old_pc + 4, new_pc); - bool Exec_ADDI() const; + this->logger->debug("{} ns. PC: 0x{:x}. JALR : Exception"); + this->RaiseException(EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN, this->m_instr); + } else { + this->regs->setPC(new_pc); + } - bool Exec_SLTI() const; + this->logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x}. PC <- 0x{:x}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rd, old_pc + 4, new_pc); - bool Exec_SLTIU() const; + return true; + } - bool Exec_XORI() const; + bool Exec_BEQ() const { + unsigned int rs1, rs2; + std::uint32_t new_pc; - bool Exec_ORI() const; + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_ANDI() const; + if (this->regs->getValue(rs1) == this->regs->getValue(rs2)) { + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + this->regs->setPC(new_pc); + } else { + this->regs->incPC(); + new_pc = static_cast(this->regs->getPC()); + } - bool Exec_SLLI(); + this->logger->debug("{} ns. PC: 0x{:x}. BEQ: x{:d}(0x{:x}) == x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); - bool Exec_SRLI() const; + return true; + } - bool Exec_SRAI() const; + bool Exec_BNE() const { + unsigned int rs1, rs2; + std::uint32_t new_pc; + std::uint32_t val1, val2; - bool Exec_ADD() const; + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_SUB() const; + val1 = this->regs->getValue(rs1); + val2 = this->regs->getValue(rs2); - bool Exec_SLL() const; + if (val1 != val2) { + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + this->regs->setPC(new_pc); + } else { + this->regs->incPC(); + new_pc = static_cast(this->regs->getPC()); + } - bool Exec_SLT() const; + this->logger->debug("{} ns. PC: 0x{:x}. BNE: x{:d}(0x{:x}) != x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, val1, rs2, val2, new_pc); - bool Exec_SLTU() const; + return true; + } - bool Exec_XOR() const; + bool Exec_BLT() const { + unsigned int rs1, rs2; + std::uint32_t new_pc = 0; - bool Exec_SRL() const; + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_SRA() const; + if (static_cast(this->regs->getValue(rs1)) + < static_cast(this->regs->getValue(rs2))) { + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + this->regs->setPC(new_pc); + } else { + this->regs->incPC(); + } - bool Exec_OR() const; + this->logger->debug("{} ns. PC: 0x{:x}. BLT: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); - bool Exec_AND() const; + return true; + } - bool Exec_FENCE() const; + bool Exec_BGE() const { + unsigned int rs1, rs2; + std::uint32_t new_pc = 0; - bool Exec_ECALL(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_EBREAK(); + if (static_cast(this->regs->getValue(rs1)) + >= static_cast( this->regs->getValue(rs2))) { + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + this->regs->setPC(new_pc); + } else { + this->regs->incPC(); + } - bool Exec_CSRRW() const; + this->logger->debug("{} ns. PC: 0x{:x}. BGE: x{:d}(0x{:x}) > x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); - bool Exec_CSRRS() const; + return true; + } - bool Exec_CSRRC() const; + bool Exec_BLTU() const { + unsigned int rs1, rs2; + std::uint32_t new_pc; - bool Exec_CSRRWI() const; + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_CSRRSI() const; + if (static_cast(this->regs->getValue(rs1)) + < static_cast(this->regs->getValue(rs2))) { + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + this->regs->setPC(new_pc); + } else { + this->regs->incPC(); + new_pc = static_cast(this->regs->getPC()); + } - bool Exec_CSRRCI() const; + this->logger->debug("{} ns. PC: 0x{:x}. BLTU: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); - /*********************** Privileged Instructions ******************************/ - bool Exec_MRET() const; + return true; + } - bool Exec_SRET() const; + bool Exec_BGEU() const { + unsigned int rs1, rs2; - bool Exec_WFI() const; + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_SFENCE() const; + if (static_cast(this->regs->getValue(rs1)) + >= static_cast(this->regs->getValue(rs2))) { + std::uint32_t new_pc; + new_pc = static_cast(this->regs->getPC() + get_imm_B()); + + this->logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), new_pc); + + this->regs->setPC(new_pc); + } else { + this->logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), + this->regs->getPC() + 4); + this->regs->incPC(); + } + + return true; + } + + bool Exec_LB() const { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + std::int8_t data; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + this->regs->getValue(rs1); + data = static_cast(this->mem_intf->readDataMem(mem_addr, 1)); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, data); + + this->logger->debug("{} ns. PC: 0x{:x}. LB: x{:d} + x{:d}(0x{:x}) -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, mem_addr, rd); + + return true; + } + + bool Exec_LH() const { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + int16_t data; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + this->regs->getValue(rs1); + data = static_cast(this->mem_intf->readDataMem(mem_addr, 2)); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, data); + + this->logger->debug("{} ns. PC: 0x{:x}. LH: x{:d} + x{:d}(0x{:x}) -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, mem_addr, rd); + + return true; + } + + bool Exec_LW() const { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + std::uint32_t data; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, static_cast(data)); + + this->logger->debug("{} ns. PC: 0x{:x}. LW: x{:d} + x{:d}(0x{:x}) -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, mem_addr, rd); + + return true; + } + + bool Exec_LBU() const { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + std::uint8_t data; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 1); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, static_cast(data)); + + this->logger->debug("{} ns. PC: 0x{:x}. LBU: x{:d} + x{:d}(0x{:x}) -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, mem_addr, rd); + + return true; + } + + bool Exec_LHU() const { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + uint16_t data; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 2); + this->perf->dataMemoryRead(); + + this->regs->setValue(rd, data); + + this->logger->debug("{} ns. PC: 0x{:x}. LHU: x{:d} + x{:d}(0x{:x}) -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, mem_addr, rd); + + return true; + } + + bool Exec_SB() const { + std::uint32_t mem_addr; + unsigned int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + imm = get_imm_S(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 1); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. SB: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs2, rs1, imm, mem_addr); + + return true; + } + + bool Exec_SH() const { + std::uint32_t mem_addr; + unsigned int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + imm = get_imm_S(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 2); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. SH: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs2, rs1, imm, mem_addr); + + return true; + } + + bool Exec_SW() const { + std::uint32_t mem_addr; + unsigned int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + imm = get_imm_S(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. SW: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs2, rs1, imm, mem_addr); + + return true; + } + + bool Exec_ADDI() const { + unsigned int rd, rs1; + std::int32_t imm; + std::int32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + calc = static_cast(this->regs->getValue(rs1)) + imm; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. ADDI: x{:d} + x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd, calc); + + return true; + } + + bool Exec_SLTI() const { + unsigned int rd, rs1; + std::int32_t imm; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + if (static_cast(this->regs->getValue(rs1)) < imm) { + this->regs->setValue(rd, 1); + + this->logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 1 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd); + } else { + this->regs->setValue(rd, 0); + this->logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 0 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd); + } + + return true; + } + + bool Exec_SLTIU() const { + unsigned int rd, rs1; + std::int32_t imm; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + if (static_cast(this->regs->getValue(rs1)) < static_cast(imm)) { + this->regs->setValue(rd, 1); + this->logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 1 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd); + } else { + this->regs->setValue(rd, 0); + this->logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 0 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd); + } + + return true; + } + + bool Exec_XORI() const { + unsigned int rd, rs1; + std::int32_t imm; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + calc = this->regs->getValue(rs1) ^ imm; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. XORI: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd); + + return true; + } + + bool Exec_ORI() const { + unsigned int rd, rs1; + std::int32_t imm; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + calc = this->regs->getValue(rs1) | imm; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. ORI: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, imm, rd); + + return true; + } + + bool Exec_ANDI() const { + unsigned int rd, rs1; + std::uint32_t imm; + std::uint32_t calc; + std::uint32_t aux; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + imm = get_imm_I(); + + aux = this->regs->getValue(rs1); + calc = aux & imm; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, aux, imm, rd); + + return true; + } + + bool Exec_SLLI() { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = get_shamt(); + + if (rs2 >= 0x20) { + std::cout << "ILEGAL INSTRUCTION, shamt[5] != 0" << "\n"; + this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr); + + return false; + } + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) << shift; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. SLLI: x{:d} << {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_SRLI() const { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. SRLI: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_SRAI() const { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::int32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRAI: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_ADD() const { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + calc = this->regs->getValue(rs1) + this->regs->getValue(rs2); + + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. ADD: x{:d} + x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_SUB() const { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + calc = this->regs->getValue(rs1) - this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_SLL() const { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) << shift; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. SLL: x{:d} << x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_SLT() const { + unsigned int rd, rs1, rs2; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + if (this->regs->getValue(rs1) < this->regs->getValue(rs2)) { + this->regs->setValue(rd, 1); + this->logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 1 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + } else { + this->regs->setValue(rd, 0); + this->logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 0 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + } + + return true; + } + + bool Exec_SLTU() const { + unsigned int rd, rs1, rs2; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + if (static_cast(this->regs->getValue(rs1)) + < static_cast(this->regs->getValue(rs2))) { + this->regs->setValue(rd, 1); + this->logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 1 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + } else { + this->regs->setValue(rd, 0); + this->logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 0 -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + } + + return true; + } + + bool Exec_XOR() const { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + calc = this->regs->getValue(rs1) ^ this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. XOR: x{:d} XOR x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_SRL() const { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. SRL: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_SRA() const { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::int32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + shift = this->regs->getValue(rs2) & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRA: x{:d} >> {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_OR() const { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + calc = this->regs->getValue(rs1) | this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. OR: x{:d} OR x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_AND() const { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + calc = this->regs->getValue(rs1) & this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. AND: x{:d} AND x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_FENCE() const { + this->logger->debug("{} ns. PC: 0x{:x}. FENCE"); + + return true; + } + + bool Exec_ECALL() { + + this->logger->debug("{} ns. PC: 0x{:x}. ECALL"); + + std::cout << std::endl << "ECALL Instruction called, stopping simulation" + << std::endl; + this->regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; + this->perf->dump(); + +#if 0 + std::uint32_t gp_value = this->regs->getValue(Registers::gp); + if (gp_value == 1) { + std::cout << "GP value is 1, test result is OK" << "\n"; + } else { + std::cout << "GP value is " << gp_value << "\n"; + } + + sc_core::sc_stop(); +#else + this->RaiseException(11, this->m_instr); +#endif + return true; + } + + bool Exec_EBREAK() { + + this->logger->debug("{} ns. PC: 0x{:x}. EBREAK"); + std::cout << std::endl << "EBRAK Instruction called, dumping information" + << std::endl; + this->regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; + this->perf->dump(); + + this->RaiseException(11, this->m_instr); + + return false; + } + + bool Exec_CSRRW() const { + unsigned int rd, rs1; + int csr; + std::uint32_t aux; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + csr = get_csr(); + + /* These operations must be atomical */ + if (rd != 0) { + aux = this->regs->getCSR(csr); + this->regs->setValue(rd, static_cast(aux)); + } + + aux = this->regs->getValue(rs1); + this->regs->setCSR(csr, aux); + + this->logger->debug("{} ns. PC: 0x{:x}. CSRRW: CSR #{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + csr, rd, aux); + + return true; + } + + bool Exec_CSRRS() const { + unsigned int rd, rs1; + int csr; + std::uint32_t bitmask, aux, aux2; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + csr = get_csr(); + + if (rd == 0) { + this->logger->debug("{} ns. PC: 0x{:x}. CSRRS with rd1 == 0, doing nothing."); + return false; + } + + /* These operations must be atomical */ + aux = this->regs->getCSR(csr); + bitmask = this->regs->getValue(rs1); + + this->regs->setValue(rd, static_cast(aux)); + + aux2 = aux | bitmask; + this->regs->setCSR(csr, aux2); + + this->logger->debug("{} ns. PC: 0x{:x}. CSRRS: CSR #{:d}(0x{:x}) -> x{:d}(0x{:x}) & CSR #{:d} <- 0x{:x}", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + csr, aux, rd, rs1, csr, aux2); + + return true; + } + + bool Exec_CSRRC() const { + unsigned int rd, rs1; + int csr; + std::uint32_t bitmask, aux, aux2; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + csr = get_csr(); + + if (rd == 0) { + this->logger->debug("{} ns. PC: 0x{:x}. CSRRC with rd1 == 0, doing nothing."); + return true; + } + + /* These operations must be atomical */ + aux = this->regs->getCSR(csr); + bitmask = this->regs->getValue(rs1); + + this->regs->setValue(rd, static_cast(aux)); + + aux2 = aux & ~bitmask; + this->regs->setCSR(csr, aux2); + + this->logger->debug("{} ns. PC: 0x{:x}. CSRRC: CSR #{:d}(0x{:x}) -> x{:d}(0x{:x}) & CSR #{:d} <- 0x{:x}", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + csr, aux, rd, rs1, csr, aux2); + + return true; + } + + bool Exec_CSRRWI() const { + unsigned int rd, rs1; + int csr; + std::uint32_t aux; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + csr = get_csr(); + + /* These operations must be atomical */ + if (rd != 0) { + aux = this->regs->getCSR(csr); + this->regs->setValue(rd, static_cast(aux)); + } + aux = rs1; + this->regs->setCSR(csr, aux); + + this->logger->debug("{} ns. PC: 0x{:x}. CSRRWI: CSR #{:d} -> x{:d}. x{:d} -> CSR #{:d}", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + csr, rd, rs1, csr); + + return true; + } + + bool Exec_CSRRSI() const { + unsigned int rd, rs1; + int csr; + std::uint32_t bitmask, aux; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + csr = get_csr(); + + if (rs1 == 0) { + return true; + } + + /* These operations must be atomical */ + aux = this->regs->getCSR(csr); + this->regs->setValue(rd, static_cast(aux)); + + bitmask = rs1; + aux = aux | bitmask; + this->regs->setCSR(csr, aux); + + this->logger->debug("{} ns. PC: 0x{:x}. CSRRSI: CSR #{:d} -> x{:d}. x{:d} & CSR #{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + csr, rd, rs1, csr, aux); + + return true; + } + + bool Exec_CSRRCI() const { + unsigned rd, rs1; + int csr; + std::uint32_t bitmask, aux; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + csr = get_csr(); + + if (rs1 == 0) { + return true; + } + + /* These operations must be atomical */ + aux = this->regs->getCSR(csr); + this->regs->setValue(rd, static_cast(aux)); + + bitmask = rs1; + aux = aux & ~bitmask; + this->regs->setCSR(csr, aux); + + this->logger->debug("{} ns. PC: 0x{:x}. CSRRCI: CSR #{:d} -> x{:d}. x{:d} & CSR #{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + csr, rd, rs1, csr, aux); + + return true; + } + +/*********************** Privileged Instructions ******************************/ + + bool Exec_MRET() const { + std::uint32_t new_pc = 0; + + new_pc = this->regs->getCSR(CSR_MEPC); + this->regs->setPC(new_pc); + + this->logger->debug("{} ns. PC: 0x{:x}. MRET: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), new_pc); + + // update mstatus + std::uint32_t csr_temp; + csr_temp = this->regs->getCSR(CSR_MSTATUS); + if (csr_temp & MSTATUS_MPIE) { + csr_temp |= MSTATUS_MIE; + } + csr_temp |= MSTATUS_MPIE; + this->regs->setCSR(CSR_MSTATUS, csr_temp); + + return true; + } + + bool Exec_SRET() const { + std::uint32_t new_pc = 0; + + new_pc = this->regs->getCSR(CSR_SEPC); + this->regs->setPC(new_pc); + + this->logger->debug("{} ns. PC: 0x{:x}. SRET: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), + this->regs->getPC()); + return true; + } + + bool Exec_WFI() const { + this->logger->debug("{} ns. PC: 0x{:x}. WFI"); + return true; + } + + bool Exec_SFENCE() const { + this->logger->debug("{} ns. PC: 0x{:x}. SFENCE"); + return true; + } /** * @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 process_instruction(Instruction &inst, bool *breakpoint = nullptr) { + bool PC_not_affected = true; + + *breakpoint = false; + this->setInstr(inst.getInstr()); + + switch (decode()) { + case OP_LUI: + Exec_LUI(); + break; + case OP_AUIPC: + Exec_AUIPC(); + break; + case OP_JAL: + Exec_JAL(); + PC_not_affected = false; + break; + case OP_JALR: + Exec_JALR(); + PC_not_affected = false; + break; + case OP_BEQ: + Exec_BEQ(); + PC_not_affected = false; + break; + case OP_BNE: + Exec_BNE(); + PC_not_affected = false; + break; + case OP_BLT: + Exec_BLT(); + PC_not_affected = false; + break; + case OP_BGE: + Exec_BGE(); + PC_not_affected = false; + break; + case OP_BLTU: + Exec_BLTU(); + PC_not_affected = false; + break; + case OP_BGEU: + Exec_BGEU(); + PC_not_affected = false; + break; + case OP_LB: + Exec_LB(); + break; + case OP_LH: + Exec_LH(); + break; + case OP_LW: + Exec_LW(); + break; + case OP_LBU: + Exec_LBU(); + break; + case OP_LHU: + Exec_LHU(); + break; + case OP_SB: + Exec_SB(); + break; + case OP_SH: + Exec_SH(); + break; + case OP_SW: + Exec_SW(); + break; + case OP_ADDI: + Exec_ADDI(); + break; + case OP_SLTI: + Exec_SLTI(); + break; + case OP_SLTIU: + Exec_SLTIU(); + break; + case OP_XORI: + Exec_XORI(); + break; + case OP_ORI: + Exec_ORI(); + break; + case OP_ANDI: + Exec_ANDI(); + break; + case OP_SLLI: + PC_not_affected = Exec_SLLI(); + break; + case OP_SRLI: + Exec_SRLI(); + break; + case OP_SRAI: + Exec_SRAI(); + break; + case OP_ADD: + Exec_ADD(); + break; + case OP_SUB: + Exec_SUB(); + break; + case OP_SLL: + Exec_SLL(); + break; + case OP_SLT: + Exec_SLT(); + break; + case OP_SLTU: + Exec_SLTU(); + break; + case OP_XOR: + Exec_XOR(); + break; + case OP_SRL: + Exec_SRL(); + break; + case OP_SRA: + Exec_SRA(); + break; + case OP_OR: + Exec_OR(); + break; + case OP_AND: + Exec_AND(); + break; + case OP_FENCE: + Exec_FENCE(); + break; + case OP_ECALL: + Exec_ECALL(); + *breakpoint = true; + std::cout << "ECALL" << std::endl; + break; + case OP_EBREAK: + PC_not_affected = Exec_EBREAK(); +// *breakpoint = true; + break; + case OP_CSRRW: + Exec_CSRRW(); + break; + case OP_CSRRS: + Exec_CSRRS(); + break; + case OP_CSRRC: + Exec_CSRRC(); + break; + case OP_CSRRWI: + Exec_CSRRWI(); + break; + case OP_CSRRSI: + Exec_CSRRSI(); + break; + case OP_CSRRCI: + Exec_CSRRCI(); + break; + case OP_MRET: + Exec_MRET(); + PC_not_affected = false; + break; + case OP_SRET: + Exec_SRET(); + PC_not_affected = false; + break; + case OP_WFI: + Exec_WFI(); + break; + case OP_SFENCE: + Exec_SFENCE(); + break; + [[unlikely]] default: + std::cout << "Wrong instruction" << "\n"; + inst.dump(); + this->NOP(); + //sc_stop(); + break; + } + + return PC_not_affected; + } /** * @brief Decodes opcode of instruction * @return opcode of instruction */ - opCodes decode(); + opCodes decode() { + switch (opcode()) { + case LUI: + return OP_LUI; + case AUIPC: + return OP_AUIPC; + case JAL: + return OP_JAL; + case JALR: + return OP_JALR; + case BEQ: + switch (this->get_funct3()) { + case BEQ_F: + return OP_BEQ; + case BNE_F: + return OP_BNE; + case BLT_F: + return OP_BLT; + case BGE_F: + return OP_BGE; + case BLTU_F: + return OP_BLTU; + case BGEU_F: + return OP_BGEU; + } + return OP_ERROR; + case LB: + switch (this->get_funct3()) { + case LB_F: + return OP_LB; + case LH_F: + return OP_LH; + case LW_F: + return OP_LW; + case LBU_F: + return OP_LBU; + case LHU_F: + return OP_LHU; + } + return OP_ERROR; + case SB: + switch (this->get_funct3()) { + case SB_F: + return OP_SB; + case SH_F: + return OP_SH; + case SW_F: + return OP_SW; + } + return OP_ERROR; + case ADDI: + switch (this->get_funct3()) { + case ADDI_F: + return OP_ADDI; + case SLTI_F: + return OP_SLTI; + case SLTIU_F: + return OP_SLTIU; + case XORI_F: + return OP_XORI; + case ORI_F: + return OP_ORI; + case ANDI_F: + return OP_ANDI; + case SLLI_F: + return OP_SLLI; + case SRLI_F: + switch (this->get_funct7()) { + case SRLI_F7: + return OP_SRLI; + case SRAI_F7: + return OP_SRAI; + } + return OP_ERROR; + } + return OP_ERROR; + case ADD: { + switch (this->get_funct3()) { + case ADD_F: + switch (this->get_funct7()) { + case ADD_F7: + return OP_ADD; + case SUB_F7: + return OP_SUB; + default: + return OP_ADD; + } + break; + case SLL_F: + return OP_SLL; + case SLT_F: + return OP_SLT; + case SLTU_F: + return OP_SLTU; + case XOR_F: + return OP_XOR; + case SRL_F: + switch (this->get_funct7()) { + case SRL_F7: + return OP_SRL; + case SRA_F7: + return OP_SRA; + default: + return OP_ERROR; + } + case OR_F: + return OP_OR; + case AND_F: + return OP_AND; + default: + return OP_ERROR; + } + } /* ADD */ + case FENCE: + return OP_FENCE; + case ECALL: { + switch (this->get_funct3()) { + case ECALL_F3: + switch (this->get_csr()) { + case ECALL_F: + return OP_ECALL; + case EBREAK_F: + return OP_EBREAK; + case URET_F: + return OP_URET; + case SRET_F: + return OP_SRET; + case MRET_F: + return OP_MRET; + case WFI_F: + return OP_WFI; + case SFENCE_F: + return OP_SFENCE; + } + if (this->m_instr.range(31, 25) == 0b0001001) { + return OP_SFENCE; + } + break; + case CSRRW: + return OP_CSRRW; + break; + case CSRRS: + return OP_CSRRS; + break; + case CSRRC: + return OP_CSRRC; + break; + case CSRRWI: + return OP_CSRRWI; + break; + case CSRRSI: + return OP_CSRRSI; + break; + case CSRRCI: + return OP_CSRRCI; + break; + } + } + break; + default: + return OP_ERROR; + } + + return OP_ERROR; + } }; } #endif diff --git a/inc/CPU.h b/inc/CPU.h index 054c442..b3d7a12 100644 --- a/inc/CPU.h +++ b/inc/CPU.h @@ -73,10 +73,10 @@ namespace riscv_tlm { Registers *register_bank; Performance *perf; std::shared_ptr logger; - C_extension *c_inst; - M_extension *m_inst; - A_extension *a_inst; - BASE_ISA *exec; + C_extension *c_inst; + M_extension *m_inst; + A_extension *a_inst; + BASE_ISA *exec; tlm_utils::tlm_quantumkeeper *m_qk; Instruction inst; diff --git a/inc/C_extension.h b/inc/C_extension.h index 7da29f1..23f0d1d 100644 --- a/inc/C_extension.h +++ b/inc/C_extension.h @@ -95,284 +95,285 @@ namespace riscv_tlm { /** * @brief Instruction decoding and fields access */ - class C_extension : public extension_base { + template + class C_extension : public extension_base { public: /** * @brief Constructor, same as base clase */ - using extension_base::extension_base; + using extension_base::extension_base; /** * @brief Access to opcode field * @return return opcode field */ - inline std::int32_t opcode() const override { - return static_cast(m_instr.range(1, 0)); + [[nodiscard]] inline std::uint32_t opcode() const override { + return static_cast(this->m_instr.range(1, 0)); } - inline std::int32_t get_rdp() const { - return static_cast(m_instr.range(4, 2) + 8); + [[nodiscard]] inline std::uint32_t get_rdp() const { + return static_cast(this->m_instr.range(4, 2) + 8); } /** * @brief Access to rs1 field * @return rs1 field */ - inline std::int32_t get_rs1() const override { - return static_cast(m_instr.range(11, 7)); + [[nodiscard]] inline std::uint32_t get_rs1() const override { + return static_cast(this->m_instr.range(11, 7)); } - inline void set_rs1(std::int32_t value) override { - m_instr.range(11, 7) = value; + inline void set_rs1(std::uint32_t value) override { + this->m_instr.range(11, 7) = value; } - inline std::int32_t get_rs1p() const { - return static_cast(m_instr.range(9, 7) + 8); + [[nodiscard]] inline std::uint32_t get_rs1p() const { + return static_cast(this->m_instr.range(9, 7) + 8); } /** * @brief Access to rs2 field * @return rs2 field */ - inline std::int32_t get_rs2() const override { - return static_cast(m_instr.range(6, 2)); + [[nodiscard]] inline std::uint32_t get_rs2() const override { + return static_cast(this->m_instr.range(6, 2)); } - inline void set_rs2(std::int32_t value) override { - m_instr.range(6, 2) = value; + inline void set_rs2(std::uint32_t value) override { + this->m_instr.range(6, 2) = value; } - inline std::int32_t get_rs2p() const { - return static_cast(m_instr.range(4, 2) + 8); + [[nodiscard]] inline std::uint32_t get_rs2p() const { + return static_cast(this->m_instr.range(4, 2) + 8); } - inline std::int32_t get_funct3() const override { - return static_cast(m_instr.range(15, 13)); + [[nodiscard]] inline std::uint32_t get_funct3() const override { + return static_cast(this->m_instr.range(15, 13)); } - inline void set_funct3(std::int32_t value) override { - m_instr.range(15, 13) = value; + inline void set_funct3(std::uint32_t value) override { + this->m_instr.range(15, 13) = value; } /** * @brief Access to immediate field for I-type * @return immediate_I field */ - inline std::int32_t get_imm_I() const { + [[nodiscard]] inline std::int32_t get_imm_I() const { std::int32_t aux = 0; - aux = static_cast(m_instr.range(31, 20)); + aux = static_cast(this->m_instr.range(31, 20)); /* sign extension (optimize) */ - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } return aux; } - inline void set_imm_I(std::int32_t value) { - m_instr.range(31, 20) = value; + inline void set_imm_I(std::uint32_t value) { + this->m_instr.range(31, 20) = value; } /** * @brief Access to immediate field for S-type * @return immediate_S field */ - inline std::int32_t get_imm_S() const { + [[nodiscard]] inline std::int32_t get_imm_S() const { std::int32_t aux = 0; - aux = static_cast(m_instr.range(31, 25) << 5); - aux |= static_cast(m_instr.range(11, 7)); + aux = static_cast(this->m_instr.range(31, 25) << 5); + aux |= static_cast(this->m_instr.range(11, 7)); - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } return aux; } - inline void set_imm_S(std::int32_t value) { + inline void set_imm_S(std::uint32_t value) { sc_dt::sc_uint<32> aux = value; - m_instr.range(31, 25) = aux.range(11, 5); - m_instr.range(11, 7) = aux.range(4, 0); + this->m_instr.range(31, 25) = aux.range(11, 5); + this->m_instr.range(11, 7) = aux.range(4, 0); } /** * @brief Access to immediate field for U-type * @return immediate_U field */ - inline std::int32_t get_imm_U() const { - return static_cast(m_instr.range(31, 12)); + [[nodiscard]] inline std::uint32_t get_imm_U() const { + return static_cast(this->m_instr.range(31, 12)); } - inline void set_imm_U(std::int32_t value) { - m_instr.range(31, 12) = (value << 12); + inline void set_imm_U(std::uint32_t value) { + this->m_instr.range(31, 12) = (value << 12); } /** * @brief Access to immediate field for B-type * @return immediate_B field */ - inline std::int32_t get_imm_B() const { + [[nodiscard]] inline std::int32_t get_imm_B() const { std::int32_t aux = 0; - aux |= static_cast(m_instr[7] << 11); - aux |= static_cast(m_instr.range(30, 25) << 5); - aux |= static_cast(m_instr[31] << 12); - aux |= static_cast(m_instr.range(11, 8) << 1); + aux |= static_cast(this->m_instr[7] << 11); + aux |= static_cast(this->m_instr.range(30, 25) << 5); + aux |= static_cast(this->m_instr[31] << 12); + aux |= static_cast(this->m_instr.range(11, 8) << 1); - if (m_instr[31] == 1) { + if (this->m_instr[31] == 1) { aux |= (0b11111111111111111111) << 12; } return aux; } - inline void set_imm_B(std::int32_t value) { + inline void set_imm_B(std::uint32_t value) { sc_dt::sc_uint<32> aux = value; - m_instr[31] = aux[12]; - m_instr.range(30, 25) = aux.range(10, 5); - m_instr.range(11, 7) = aux.range(4, 1); - m_instr[6] = aux[11]; + this->m_instr[31] = aux[12]; + this->m_instr.range(30, 25) = aux.range(10, 5); + this->m_instr.range(11, 7) = aux.range(4, 1); + this->m_instr[6] = aux[11]; } /** * @brief Access to immediate field for J-type * @return immediate_J field */ - inline std::int32_t get_imm_J() const { + [[nodiscard]] inline std::int32_t get_imm_J() const { std::int32_t aux = 0; - aux = static_cast(m_instr[12] << 11); - aux |= static_cast(m_instr[11] << 4); - aux |= static_cast(m_instr[10] << 9); - aux |= static_cast(m_instr[9] << 8); - aux |= static_cast(m_instr[8] << 10); - aux |= static_cast(m_instr[7] << 6); - aux |= static_cast(m_instr[6] << 7); - aux |= static_cast(m_instr.range(5, 3) << 1); - aux |= static_cast(m_instr[2] << 5); + aux = static_cast(this->m_instr[12] << 11); + aux |= static_cast(this->m_instr[11] << 4); + aux |= static_cast(this->m_instr[10] << 9); + aux |= static_cast(this->m_instr[9] << 8); + aux |= static_cast(this->m_instr[8] << 10); + aux |= static_cast(this->m_instr[7] << 6); + aux |= static_cast(this->m_instr[6] << 7); + aux |= static_cast(this->m_instr.range(5, 3) << 1); + aux |= static_cast(this->m_instr[2] << 5); - if (m_instr[12] == 1) { + if (this->m_instr[12] == 1) { aux |= 0b11111111111111111111 << 12; } return aux; } - inline void set_imm_J(std::int32_t value) { + inline void set_imm_J(std::uint32_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[20] = aux[11]; - m_instr.range(19, 12) = aux.range(19, 12); + this->m_instr[31] = aux[20]; + this->m_instr.range(30, 21) = aux.range(10, 1); + this->m_instr[20] = aux[11]; + this->m_instr.range(19, 12) = aux.range(19, 12); } - inline std::int32_t get_imm_L() const { + [[nodiscard]] inline std::int32_t get_imm_L() const { std::int32_t aux = 0; - aux = static_cast(m_instr.range(12, 10) << 3); - aux |= static_cast(m_instr[6] << 2); - aux |= static_cast(m_instr[5] << 6); + aux = static_cast(this->m_instr.range(12, 10) << 3); + aux |= static_cast(this->m_instr[6] << 2); + aux |= static_cast(this->m_instr[5] << 6); return aux; } - inline std::int32_t get_imm_LWSP() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_LWSP() const { + std::uint32_t aux = 0; - aux = static_cast(m_instr[12] << 5); - aux |= static_cast(m_instr.range(6, 4) << 2); - aux |= static_cast(m_instr.range(3, 2) << 6); + aux = static_cast(this->m_instr[12] << 5); + aux |= static_cast(this->m_instr.range(6, 4) << 2); + aux |= static_cast(this->m_instr.range(3, 2) << 6); return aux; } - inline std::int32_t get_imm_ADDI() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_ADDI() const { + std::uint32_t aux = 0; - aux = static_cast(m_instr[12] << 5); - aux |= static_cast(m_instr.range(6, 2)); + aux = static_cast(this->m_instr[12] << 5); + aux |= static_cast(this->m_instr.range(6, 2)); - if (m_instr[12] == 1) { + if (this->m_instr[12] == 1) { aux |= 0b11111111111111111111111111 << 6; } return aux; } - inline std::int32_t get_imm_ADDI4SPN() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_ADDI4SPN() const { + std::uint32_t aux = 0; - aux = static_cast(m_instr.range(12, 11) << 4); - aux |= static_cast(m_instr.range(10, 7) << 6); - aux |= static_cast(m_instr[6] << 2); - aux |= static_cast(m_instr[5] << 3); + aux = static_cast(this->m_instr.range(12, 11) << 4); + aux |= static_cast(this->m_instr.range(10, 7) << 6); + aux |= static_cast(this->m_instr[6] << 2); + aux |= static_cast(this->m_instr[5] << 3); return aux; } - inline std::int32_t get_imm_ADDI16SP() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_ADDI16SP() const { + std::uint32_t aux = 0; - aux = static_cast(m_instr[12] << 9); - aux |= static_cast(m_instr[6] << 4); - aux |= static_cast(m_instr[5] << 6); - aux |= static_cast(m_instr[4] << 8); - aux |= static_cast(m_instr[3] << 7); - aux |= static_cast(m_instr[2] << 5); + aux = static_cast(this->m_instr[12] << 9); + aux |= static_cast(this->m_instr[6] << 4); + aux |= static_cast(this->m_instr[5] << 6); + aux |= static_cast(this->m_instr[4] << 8); + aux |= static_cast(this->m_instr[3] << 7); + aux |= static_cast(this->m_instr[2] << 5); - if (m_instr[12] == 1) { + if (this->m_instr[12] == 1) { aux |= 0b1111111111111111111111 << 10; } return aux; } - inline std::int32_t get_imm_CSS() const { - std::int32_t aux = 0; - aux = static_cast(m_instr.range(12, 9) << 2); - aux |= static_cast(m_instr.range(8, 7) << 6); + [[nodiscard]] inline std::uint32_t get_imm_CSS() const { + std::uint32_t aux = 0; + aux = static_cast(this->m_instr.range(12, 9) << 2); + aux |= static_cast(this->m_instr.range(8, 7) << 6); return aux; } - inline std::int32_t get_imm_CB() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_CB() const { + std::uint32_t aux = 0; - aux = static_cast(m_instr[12] << 8); - aux |= static_cast(m_instr[11] << 4); - aux |= static_cast(m_instr[10] << 3); - aux |= static_cast(m_instr[6] << 7); - aux |= static_cast(m_instr[5] << 6); - aux |= static_cast(m_instr[4] << 2); - aux |= static_cast(m_instr[3] << 1); - aux |= static_cast(m_instr[2] << 5); + aux = static_cast(this->m_instr[12] << 8); + aux |= static_cast(this->m_instr[11] << 4); + aux |= static_cast(this->m_instr[10] << 3); + aux |= static_cast(this->m_instr[6] << 7); + aux |= static_cast(this->m_instr[5] << 6); + aux |= static_cast(this->m_instr[4] << 2); + aux |= static_cast(this->m_instr[3] << 1); + aux |= static_cast(this->m_instr[2] << 5); - if (m_instr[12] == 1) { + if (this->m_instr[12] == 1) { aux |= 0b11111111111111111111111 << 9; } return aux; } - inline std::int32_t get_imm_LUI() const { - std::int32_t aux = 0; + [[nodiscard]] inline std::uint32_t get_imm_LUI() const { + std::uint32_t aux = 0; - aux = static_cast(m_instr[12] << 17); - aux |= static_cast(m_instr.range(6, 2) << 12); + aux = static_cast(this->m_instr[12] << 17); + aux |= static_cast(this->m_instr.range(6, 2) << 12); - if (m_instr[12] == 1) { + if (this->m_instr[12] == 1) { aux |= 0b111111111111111 << 17; } return aux; } - inline std::int32_t get_csr() const { + [[nodiscard]] inline std::uint32_t get_csr() const { return get_imm_I(); } @@ -380,57 +381,757 @@ namespace riscv_tlm { * @brief Decodes opcode of instruction * @return opcode of instruction */ - op_C_Codes decode() const; + [[nodiscard]] op_C_Codes decode() const { - bool Exec_C_JR(); + switch (opcode()) { - bool Exec_C_MV(); + case 0b00: + switch (get_funct3()) { + case C_ADDI4SPN: + return OP_C_ADDI4SPN; + break; + case C_FLD: + return OP_C_FLD; + break; + case C_LW: + return OP_C_LW; + break; + case C_FLW: + return OP_C_FLW; + break; + case C_FSD: + return OP_C_FSD; + break; + case C_SW: + return OP_C_SW; + break; + case C_FSW: + return OP_C_FSW; + break; + [[unlikely]] default: + return OP_C_ERROR; + break; + } + break; - bool Exec_C_LWSP(); + case 0b01: + switch (get_funct3()) { + case C_ADDI: + return OP_C_ADDI; + break; + case C_JAL: + return OP_C_JAL; + break; + case C_LI: + return OP_C_LI; + break; + case C_ADDI16SP: + return OP_C_ADDI16SP; + break; + case C_SRLI: + switch (this->m_instr.range(11, 10)) { + case C_2_SRLI: + return OP_C_SRLI; + break; + case C_2_SRAI: + return OP_C_SRAI; + break; + case C_2_ANDI: + return OP_C_ANDI; + break; + case C_2_SUB: + switch (this->m_instr.range(6, 5)) { + case C_3_SUB: + return OP_C_SUB; + break; + case C_3_XOR: + return OP_C_XOR; + break; + case C_3_OR: + return OP_C_OR; + break; + case C_3_AND: + return OP_C_AND; + break; + } + } + break; + case C_J: + return OP_C_J; + break; + case C_BEQZ: + return OP_C_BEQZ; + break; + case C_BNEZ: + return OP_C_BNEZ; + break; + [[unlikely]] default: + return OP_C_ERROR; + break; + } + break; - bool Exec_C_ADDI4SPN(); + case 0b10: + switch (get_funct3()) { + case C_SLLI: + return OP_C_SLLI; + break; + case C_FLDSP: + case C_LWSP: + return OP_C_LWSP; + break; + case C_FLWSP: + return OP_C_FLWSP; + break; + case C_JR: + if (this->m_instr[12] == 0) { + if (this->m_instr.range(6, 2) == 0) { + return OP_C_JR; + } else { + return OP_C_MV; + } + } else { + if (this->m_instr.range(11, 2) == 0) { + return OP_C_EBREAK; + } else if (this->m_instr.range(6, 2) == 0) { + return OP_C_JALR; + } else { + return OP_C_ADD; + } + } + break; + case C_FDSP: + break; + case C_SWSP: + return OP_C_SWSP; + break; + case C_FWWSP: + [[unlikely]] + default: + return OP_C_ERROR; + break; + } + break; - bool Exec_C_SLLI(); + [[unlikely]] default: - bool Exec_C_ADDI16SP(); + return OP_C_ERROR; + break; + } + return OP_C_ERROR; + } - bool Exec_C_SWSP(); + bool Exec_C_JR() { + std::uint32_t mem_addr; + unsigned int rs1; + std::uint32_t new_pc; - bool Exec_C_BEQZ(); + rs1 = get_rs1(); + mem_addr = 0; - bool Exec_C_BNEZ(); + new_pc = static_cast( + static_cast((this->regs->getValue(rs1)) + static_cast(mem_addr)) & + 0xFFFFFFFE); - bool Exec_C_LI(); + this->logger->debug("{} ns. PC: 0x{:x}. C.JR: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), new_pc); - bool Exec_C_SRLI(); + this->regs->setPC(new_pc); - bool Exec_C_SRAI(); + return true; + } - bool Exec_C_ANDI(); + bool Exec_C_MV() { + unsigned int rd, rs1, rs2; + std::uint32_t calc; - bool Exec_C_ADD(); + rd = this->get_rd(); + rs1 = 0; + rs2 = get_rs2(); - bool Exec_C_SUB(); + calc = this->regs->getValue(rs1) + this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); - bool Exec_C_XOR(); + this->logger->debug("{} ns. PC: 0x{:x}. C.MV: x{:d}(0x{:x}) + x{:d}(0x{:x}) -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), rs2, this->regs->getValue(rs2), rd, calc); - bool Exec_C_OR(); + return true; + } - bool Exec_C_AND(); + bool Exec_C_ADD() { + unsigned int rd, rs1, rs2; + std::uint32_t calc; - bool Exec_C_ADDI() const; + rd = get_rs1(); + rs1 = get_rs1(); + rs2 = get_rs2(); - bool Exec_C_JALR(); + calc = this->regs->getValue(rs1) + this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); - bool Exec_C_LW(); + this->logger->debug("{} ns. PC: 0x{:x}. C.ADD: x{:d} + x{} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); - bool Exec_C_SW(); + return true; + } - bool Exec_C_JAL(int m_rd); + bool Exec_C_LWSP() { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + std::uint32_t data; - bool Exec_C_EBREAK(); + // lw rd, offset[7:2](x2) + + rd = this->get_rd(); + rs1 = 2; + imm = static_cast(get_imm_LWSP()); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, static_cast(data)); + + this->regs->setValue(rd, data); + + this->logger->debug("{} ns. PC: 0x{:x}. C.LWSP: x{:d} + {:d}(@0x{:x}) -> x{:d}({:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, imm, mem_addr, rd, data); + + return true; + } + + bool Exec_C_ADDI4SPN() { + unsigned int rd, rs1; + std::int32_t imm; + std::int32_t calc; + + rd = get_rdp(); + rs1 = 2; + imm = static_cast(get_imm_ADDI4SPN()); + + if (imm == 0) { + this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr); + return false; + } + + calc = static_cast(this->regs->getValue(rs1)) + imm; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.ADDI4SN: x{:d} + (0x{:x}) + {:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), imm, rd, calc); + + return true; + } + + bool Exec_C_ADDI16SP() { + // addi x2, x2, nzimm[9:4] + unsigned int rd; + std::int32_t imm; + + if (this->get_rd() == 2) { + int rs1; + std::int32_t calc; + + rd = 2; + rs1 = 2; + imm = static_cast(get_imm_ADDI16SP()); + calc = static_cast(this->regs->getValue(rs1)) + imm; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.ADDI16SP: x{:d} + {:d} -> x{:d} (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, imm, rd, calc); + } else { + /* C.LUI OPCODE */ + rd = this->get_rd(); + imm = static_cast(get_imm_LUI()); + this->regs->setValue(rd, imm); + + this->logger->debug("{} ns. PC: 0x{:x}. C.LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rd, imm); + } + + return true; + } + + bool Exec_C_SWSP() { + // sw rs2, offset(x2) + std::uint32_t mem_addr; + unsigned int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = 2; + rs2 = get_rs2(); + imm = static_cast(get_imm_CSS()); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SWSP: x{:d}(0x{:x}) -> x{:d} + {} (@0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs2, data, rs1, imm, mem_addr); + + return true; + } + + bool Exec_C_BEQZ() { + unsigned int rs1; + std::uint32_t new_pc; + std::uint32_t val1; + + rs1 = get_rs1p(); + val1 = this->regs->getValue(rs1); + + if (val1 == 0) { + new_pc = static_cast(this->regs->getPC()) + get_imm_CB(); + this->regs->setPC(new_pc); + } else { + this->regs->incPCby2(); + new_pc = static_cast(this->regs->getPC()); + } + + this->logger->debug("{} ns. PC: 0x{:x}. C.BEQZ: x{:d}(0x{:x}) == 0? -> PC (0xx{:d})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, val1, new_pc); + + return true; + } + + bool Exec_C_BNEZ() { + unsigned int rs1; + std::uint32_t new_pc; + std::uint32_t val1; + + rs1 = get_rs1p(); + val1 = this->regs->getValue(rs1); + + if (val1 != 0) { + new_pc = static_cast(this->regs->getPC()) + get_imm_CB(); + this->regs->setPC(new_pc); + } else { + this->regs->incPCby2(); //PC <- PC +2 + new_pc = static_cast(this->regs->getPC()); + } + + this->logger->debug("{} ns. PC: 0x{:x}. C.BNEZ: x{:d}(0x{:x}) != 0? -> PC (0xx{:d})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, val1, new_pc); + + return true; + } + + bool Exec_C_LI() { + unsigned int rd, rs1; + std::int32_t imm; + std::int32_t calc; + + rd = this->get_rd(); + rs1 = 0; + imm = static_cast(get_imm_ADDI()); + calc = static_cast(this->regs->getValue(rs1)) + imm; + + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.LI: x{:d} ({:d}) + {:d} -> x{:d}(0x{:x}) ", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), imm, rd, calc); + + return true; + } + + bool Exec_C_SRLI() { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2(); + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SRLI: x{:d} >> {} -> x{:d}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd); + + return true; + } + + bool Exec_C_SRAI() { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::int32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2(); + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) >> shift; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SRAI: x{:d} >> {} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_C_SLLI() { + unsigned int rd, rs1, rs2; + std::uint32_t shift; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_imm_ADDI(); + + shift = rs2 & 0x1F; + + calc = static_cast(this->regs->getValue(rs1)) << shift; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SLLI: x{:d} << {} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, shift, rd, calc); + + return true; + } + + bool Exec_C_ANDI() { + unsigned int rd, rs1; + std::uint32_t imm; + std::uint32_t aux; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + imm = get_imm_ADDI(); + + aux = this->regs->getValue(rs1); + calc = aux & imm; + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, aux, imm, rd); + + return true; + } + + bool Exec_C_SUB() { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = this->regs->getValue(rs1) - this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, calc); + + return true; + } + + bool Exec_C_XOR() { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = this->regs->getValue(rs1) ^ this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.XOR: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + + return true; + } + + bool Exec_C_OR() { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = this->regs->getValue(rs1) | this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.OR: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + + return true; + } + + bool Exec_C_AND() { + unsigned int rd, rs1, rs2; + std::uint32_t calc; + + rd = get_rs1p(); + rs1 = get_rs1p(); + rs2 = get_rs2p(); + + calc = this->regs->getValue(rs1) & this->regs->getValue(rs2); + this->regs->setValue(rd, static_cast(calc)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.AND: x{:d} AND x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd); + + return true; + } + + bool Exec_C_ADDI() const { + unsigned int rd, rs1; + std::int32_t imm; + std::int32_t calc; + + rd = this->get_rd(); + rs1 = rd; + imm = static_cast(get_imm_ADDI()); + + calc = static_cast(this->regs->getValue(rs1)) + imm; + this->regs->setValue(rd, calc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.ADDI: x{:d} + {} -> x{:d}(0x{:x})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), rs1, imm, rd, calc); + + return true; + } + + bool Exec_C_JALR() { + std::uint32_t mem_addr = 0; + unsigned int rd, rs1; + std::uint32_t new_pc, old_pc; + + rd = 1; + rs1 = get_rs1(); + + old_pc = static_cast(this->regs->getPC()); + this->regs->setValue(rd, old_pc + 2); + + new_pc = static_cast((this->regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); + this->regs->setPC(new_pc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.JALR: x{:d} <- 0x{:x} PC <- 0xx{:x}", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rd, old_pc + 4, new_pc); + + return true; + } + + bool Exec_C_LW() { + std::uint32_t mem_addr; + unsigned int rd, rs1; + std::int32_t imm; + std::uint32_t data; + + rd = get_rdp(); + rs1 = get_rs1p(); + imm = get_imm_L(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->mem_intf->readDataMem(mem_addr, 4); + this->perf->dataMemoryRead(); + this->regs->setValue(rd, static_cast(data)); + + this->logger->debug("{} ns. PC: 0x{:x}. C.LW: x{:d}(0x{:x}) + {:d} (@0x{:x}) -> {:d} (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs1, this->regs->getValue(rs1), imm, mem_addr, rd, data); + + return true; + } + + bool Exec_C_SW() { + std::uint32_t mem_addr; + unsigned int rs1, rs2; + std::int32_t imm; + std::uint32_t data; + + rs1 = get_rs1p(); + rs2 = get_rs2p(); + imm = get_imm_L(); + + mem_addr = imm + this->regs->getValue(rs1); + data = this->regs->getValue(rs2); + + this->mem_intf->writeDataMem(mem_addr, data, 4); + this->perf->dataMemoryWrite(); + + this->logger->debug("{} ns. PC: 0x{:x}. C.SW: x{:d}(0x{:x}) -> x{:d} + 0x{:x}(@0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rs2, data, rs1, imm, mem_addr); + + return true; + } + + bool Exec_C_JAL(int m_rd) { + std::int32_t mem_addr; + unsigned int rd; + std::uint32_t new_pc, old_pc; + + rd = m_rd; + mem_addr = get_imm_J(); + old_pc = static_cast(this->regs->getPC()); + + new_pc = old_pc + mem_addr; + this->regs->setPC(new_pc); + + old_pc = old_pc + 2; + this->regs->setValue(rd, old_pc); + + this->logger->debug("{} ns. PC: 0x{:x}. C.JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", + sc_core::sc_time_stamp().value(), this->regs->getPC(), + rd, old_pc, mem_addr, new_pc); + + return true; + } + + bool Exec_C_EBREAK() { + + this->logger->debug("C.EBREAK"); + std::cout << "\n" << "C.EBRAK Instruction called, dumping information" + << "\n"; + this->regs->dump(); + std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; + this->perf->dump(); + + sc_core::sc_stop(); + + return true; + } + + bool process_instruction(Instruction &inst, bool *breakpoint) { + bool PC_not_affected = true; + + *breakpoint = false; + + this->setInstr(inst.getInstr()); + + switch (decode()) { + case OP_C_ADDI4SPN: + PC_not_affected = Exec_C_ADDI4SPN(); + break; + case OP_C_LW: + Exec_C_LW(); + break; + case OP_C_SW: + Exec_C_SW(); + break; + case OP_C_ADDI: + Exec_C_ADDI(); + break; + case OP_C_JAL: + Exec_C_JAL(1); + PC_not_affected = false; + break; + case OP_C_J: + Exec_C_JAL(0); + PC_not_affected = false; + break; + case OP_C_LI: + Exec_C_LI(); + break; + case OP_C_SLLI: + Exec_C_SLLI(); + break; + case OP_C_LWSP: + Exec_C_LWSP(); + break; + case OP_C_JR: + Exec_C_JR(); + PC_not_affected = false; + break; + case OP_C_MV: + Exec_C_MV(); + break; + case OP_C_JALR: + Exec_C_JALR(); + PC_not_affected = false; + break; + case OP_C_ADD: + Exec_C_ADD(); + break; + case OP_C_SWSP: + Exec_C_SWSP(); + break; + case OP_C_ADDI16SP: + Exec_C_ADDI16SP(); + break; + case OP_C_BEQZ: + Exec_C_BEQZ(); + PC_not_affected = false; + break; + case OP_C_BNEZ: + Exec_C_BNEZ(); + PC_not_affected = false; + break; + case OP_C_SRLI: + Exec_C_SRLI(); + break; + case OP_C_SRAI: + Exec_C_SRAI(); + break; + case OP_C_ANDI: + Exec_C_ANDI(); + break; + case OP_C_SUB: + Exec_C_SUB(); + break; + case OP_C_XOR: + Exec_C_XOR(); + break; + case OP_C_OR: + Exec_C_OR(); + break; + case OP_C_AND: + Exec_C_AND(); + break; + case OP_C_EBREAK: + Exec_C_EBREAK(); + std::cout << "C_EBREAK" << std::endl; + *breakpoint = true; + break; + [[unlikely]] default: + std::cout << "C instruction not implemented yet" << "\n"; + inst.dump(); + this->NOP(); + break; + } + + return PC_not_affected; + } - bool process_instruction(Instruction &inst, bool *breakpoint = nullptr); }; } diff --git a/inc/M_extension.h b/inc/M_extension.h index 073cd85..0871853 100644 --- a/inc/M_extension.h +++ b/inc/M_extension.h @@ -43,41 +43,298 @@ namespace riscv_tlm { /** * @brief Instruction decoding and fields access */ - class M_extension : public extension_base { + template + class M_extension : public extension_base { public: /** * @brief Constructor, same as base clase */ - using extension_base::extension_base; + using extension_base::extension_base; /** * @brief Decodes opcode of instruction * @return opcode of instruction */ - op_M_Codes decode() const; + [[nodiscard]] op_M_Codes decode() const { - inline void dump() const override { - std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + switch (opcode()) { + case M_MUL: + return OP_M_MUL; + break; + case M_MULH: + return OP_M_MULH; + break; + case M_MULHSU: + return OP_M_MULHSU; + break; + case M_MULHU: + return OP_M_MULHU; + break; + case M_DIV: + return OP_M_DIV; + break; + case M_DIVU: + return OP_M_DIVU; + break; + case M_REM: + return OP_M_REM; + break; + case M_REMU: + return OP_M_REMU; + break; + [[unlikely]] default: + return OP_M_ERROR; + break; + } + + return OP_M_ERROR; } - bool Exec_M_MUL() const; + inline void dump() const override { + std::cout << std::hex << "0x" << this->m_instr << std::dec << std::endl; + } - bool Exec_M_MULH() const; + void Exec_M_MUL() const { + unsigned int rd, rs1, rs2; + std::int32_t multiplier, multiplicand; + std::int64_t result; - bool Exec_M_MULHSU() const; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool Exec_M_MULHU() const; + multiplier = static_cast(extension_base::regs->getValue(rs1)); + multiplicand = static_cast(extension_base::regs->getValue(rs2)); - bool Exec_M_DIV() const; + result = static_cast(multiplier * multiplicand); + result = result & 0x00000000FFFFFFFF; + this->regs->setValue(rd, static_cast(result)); - bool Exec_M_DIVU() const; + this->logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + extension_base::regs->getPC(), + rs1, rs2, rd, result); + } - bool Exec_M_REM() const; + void Exec_M_MULH() const { + unsigned int rd, rs1, rs2; + std::int32_t multiplier, multiplicand; + std::int64_t result; + std::int32_t ret_value; - bool Exec_M_REMU() const; + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); - bool process_instruction(Instruction &inst); + multiplier = static_cast(this->regs->getValue(rs1)); + multiplicand = static_cast(this->regs->getValue(rs2)); + + result = static_cast(multiplier) * static_cast(multiplicand); + + ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); + this->regs->setValue(rd, ret_value); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_MULHSU() const { + unsigned int rd, rs1, rs2; + std::int32_t multiplier; + std::uint32_t multiplicand; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = static_cast(this->regs->getValue(rs1)); + multiplicand = this->regs->getValue(rs2); + + result = static_cast(multiplier * static_cast(multiplicand)); + result = (result >> 32) & 0x00000000FFFFFFFF; + this->regs->setValue(rd, static_cast(result)); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_MULHU() const { + unsigned int rd, rs1, rs2; + std::uint32_t multiplier, multiplicand; + std::uint64_t result; + std::int32_t ret_value; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + multiplier = static_cast(this->regs->getValue(rs1)); + multiplicand = static_cast(this->regs->getValue(rs2)); + + result = static_cast(multiplier) * static_cast(multiplicand); + ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); + this->regs->setValue(rd, ret_value); + + this->logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_DIV() const { + unsigned int rd, rs1, rs2; + std::int32_t divisor, dividend; + std::int64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1)); + divisor = static_cast(this->regs->getValue(rs2)); + + if (divisor == 0) { + result = -1; + } else if ((divisor == -1) && (dividend == static_cast(0x80000000))) { + result = 0x0000000080000000; + } else { + result = dividend / divisor; + result = result & 0x00000000FFFFFFFF; + } + + this->regs->setValue(rd, static_cast(result)); + + this->logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_DIVU() const { + unsigned int rd, rs1, rs2; + std::uint32_t divisor, dividend; + std::uint64_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = this->regs->getValue(rs1); + divisor = this->regs->getValue(rs2); + + if (divisor == 0) { + result = -1; + } else { + result = dividend / divisor; + result = result & 0x00000000FFFFFFFF; + } + + this->regs->setValue(rd, static_cast(result)); + + this->logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_REM() const { + unsigned int rd, rs1, rs2; + std::int32_t divisor, dividend; + std::int32_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1)); + divisor = static_cast(this->regs->getValue(rs2)); + + if (divisor == 0) { + result = dividend; + } else if ((divisor == -1) && (dividend == static_cast(0x80000000))) { + result = 0; + } else { + result = dividend % divisor; + } + + this->regs->setValue(rd, result); + + this->logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} / x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + void Exec_M_REMU() const { + unsigned int rd, rs1, rs2; + std::uint32_t divisor, dividend; + std::uint32_t result; + + rd = this->get_rd(); + rs1 = this->get_rs1(); + rs2 = this->get_rs2(); + + dividend = static_cast(this->regs->getValue(rs1)); + divisor = static_cast(this->regs->getValue(rs2)); + + if (divisor == 0) { + result = dividend; + } else { + result = dividend % divisor; + } + + this->regs->setValue(rd, static_cast(result)); + + this->logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} / x{:d} -> x{:d}({:d})", + sc_core::sc_time_stamp().value(), + this->regs->getPC(), + rs1, rs2, rd, result); + } + + bool process_instruction(Instruction &inst) { + this->setInstr(inst.getInstr()); + + switch (decode()) { + case OP_M_MUL: + Exec_M_MUL(); + break; + case OP_M_MULH: + Exec_M_MULH(); + break; + case OP_M_MULHSU: + Exec_M_MULHSU(); + break; + case OP_M_MULHU: + Exec_M_MULHU(); + break; + case OP_M_DIV: + Exec_M_DIV(); + break; + case OP_M_DIVU: + Exec_M_DIVU(); + break; + case OP_M_REM: + Exec_M_REM(); + break; + case OP_M_REMU: + Exec_M_REMU(); + break; + [[unlikely]] default: + std::cout << "M instruction not implemented yet" << "\n"; + inst.dump(); + //NOP(inst); + sc_core::sc_stop(); + break; + } + + return true; + } private: @@ -85,8 +342,8 @@ namespace riscv_tlm { * @brief Access to opcode field * @return return opcode field */ - inline std::int32_t opcode() const override { - return static_cast(m_instr.range(14, 12)); + [[nodiscard]] inline std::uint32_t opcode() const override { + return static_cast(this->m_instr.range(14, 12)); } }; diff --git a/inc/Registers.h b/inc/Registers.h index 0812cf5..bcd0b28 100644 --- a/inc/Registers.h +++ b/inc/Registers.h @@ -10,6 +10,7 @@ #define REGISTERS_H #define SC_INCLUDE_DYNAMIC_PROCESSES + #include #include @@ -188,11 +189,11 @@ namespace riscv_tlm { * Default constructor */ Registers() { - perf = Performance::getInstance(); + perf = Performance::getInstance(); - initCSR(); - register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory - register_PC = 0x80000000; // default _start address + initCSR(); + register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory + register_PC = 0x80000000; // default _start address }; /** @@ -200,10 +201,10 @@ namespace riscv_tlm { * @param reg_num register number * @param value register value */ - void setValue(int reg_num, T value) { - if ((reg_num != 0) && (reg_num < 32)) { - register_bank[reg_num] = value; - perf->registerWrite(); + void setValue(unsigned int reg_num, T value) { + if ((reg_num != 0) && (reg_num < 32)) { + register_bank[reg_num] = value; + perf->registerWrite(); } } @@ -212,13 +213,13 @@ namespace riscv_tlm { * @param reg_num register number * @return register value */ - T getValue(int reg_num) const { - if ((reg_num >= 0) && (reg_num < 32)) { - perf->registerRead(); - return register_bank[reg_num]; + T getValue(unsigned int reg_num) const { + if (reg_num < 32) { + perf->registerRead(); + return register_bank[reg_num]; } else { - /* TODO Exten sign for any possible T type */ - return static_cast(0xFFFFFFFF); + /* Extend sign for any possible T type */ + return static_cast(std::numeric_limits::max()); } } @@ -227,7 +228,7 @@ namespace riscv_tlm { * @return PC value */ T getPC() const { - return register_PC; + return register_PC; } /** @@ -235,7 +236,7 @@ namespace riscv_tlm { * @param new_pc new address to PC */ void setPC(T new_pc) { - register_PC = new_pc; + register_PC = new_pc; } /** @@ -255,40 +256,40 @@ namespace riscv_tlm { * @return CSR value */ T getCSR(int csr) { - T ret_value; + T ret_value; - switch (csr) { - case CSR_CYCLE: - case CSR_MCYCLE: - ret_value = static_cast(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::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(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::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; + switch (csr) { + case CSR_CYCLE: + case CSR_MCYCLE: + ret_value = static_cast(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::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(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::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; + return ret_value; } /** @@ -297,11 +298,11 @@ namespace riscv_tlm { * @param value new value to register */ void setCSR(int csr, T value) { - /* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to be writable, - * but Volume II: Privileged Architecture v1.10 says MISA is writable (?) - */ - if (csr != CSR_MISA) { - CSR[csr] = value; + /* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to be writable, + * but Volume II: Privileged Architecture v1.10 says MISA is writable (?) + */ + if (csr != CSR_MISA) { + CSR[csr] = value; } } @@ -309,83 +310,83 @@ namespace riscv_tlm { * Dump register data to console */ void dump() { - std::cout << "************************************" << std::endl; - std::cout << "Registers dump" << std::dec << std::endl; - 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 << "************************************" << std::endl; + std::cout << "Registers dump" << std::dec << std::endl; + 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) - << std::hex << register_bank[4]; - std::cout << " x5 (t0): 0x" << std::right << std::setw(8) - << std::hex << register_bank[5]; - std::cout << " x6 (t1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[6]; - std::cout << " x7 (t2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[7] << std::endl; + std::cout << "x4 (tp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[4]; + std::cout << " x5 (t0): 0x" << std::right << std::setw(8) + << std::hex << register_bank[5]; + std::cout << " x6 (t1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[6]; + std::cout << " x7 (t2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[7] << std::endl; - std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8) - << std::hex << register_bank[8]; - std::cout << " x9 (s1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[9]; - std::cout << " x10 (a0): 0x" << std::right << std::setw(8) - << std::hex << register_bank[10]; - std::cout << " x11 (a1): 0x" << std::right << std::setw(8) - << std::hex << register_bank[11] << std::endl; + std::cout << "x8 (s0/fp): 0x" << std::right << std::setw(8) + << std::hex << register_bank[8]; + std::cout << " x9 (s1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[9]; + std::cout << " x10 (a0): 0x" << std::right << std::setw(8) + << std::hex << register_bank[10]; + std::cout << " x11 (a1): 0x" << std::right << std::setw(8) + << std::hex << register_bank[11] << std::endl; - std::cout << "x12 (a2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[12]; - std::cout << " x13 (a3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[13]; - std::cout << " x14 (a4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[14]; - std::cout << " x15 (a5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[15] << std::endl; + std::cout << "x12 (a2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[12]; + std::cout << " x13 (a3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[13]; + std::cout << " x14 (a4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[14]; + std::cout << " x15 (a5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[15] << std::endl; - std::cout << "x16 (a6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[16]; - std::cout << " x17 (a7): 0x" << std::right << std::setw(8) - << std::hex << register_bank[17]; - std::cout << " x18 (s2): 0x" << std::right << std::setw(8) - << std::hex << register_bank[18]; - std::cout << " x19 (s3): 0x" << std::right << std::setw(8) - << std::hex << register_bank[19] << std::endl; + std::cout << "x16 (a6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[16]; + std::cout << " x17 (a7): 0x" << std::right << std::setw(8) + << std::hex << register_bank[17]; + std::cout << " x18 (s2): 0x" << std::right << std::setw(8) + << std::hex << register_bank[18]; + std::cout << " x19 (s3): 0x" << std::right << std::setw(8) + << std::hex << register_bank[19] << std::endl; - std::cout << "x20 (s4): 0x" << std::right << std::setw(8) - << std::hex << register_bank[20]; - std::cout << " x21 (s5): 0x" << std::right << std::setw(8) - << std::hex << register_bank[21]; - std::cout << " x22 (s6): 0x" << std::right << std::setw(8) - << std::hex << register_bank[22]; - std::cout << " x23 (s7): 0x" << std::right << std::setw(8) - << std::hex << register_bank[23] << std::endl; + std::cout << "x20 (s4): 0x" << std::right << std::setw(8) + << std::hex << register_bank[20]; + std::cout << " x21 (s5): 0x" << std::right << std::setw(8) + << std::hex << register_bank[21]; + std::cout << " x22 (s6): 0x" << std::right << std::setw(8) + << std::hex << register_bank[22]; + std::cout << " x23 (s7): 0x" << std::right << std::setw(8) + << std::hex << register_bank[23] << std::endl; - std::cout << "x24 (s8): 0x" << std::right << std::setw(8) - << std::hex << register_bank[24]; - std::cout << " x25 (s9): 0x" << std::right << std::setw(8) - << std::hex << register_bank[25]; - std::cout << " x26 (s10): 0x" << std::right << std::setw(8) - << std::hex << register_bank[26]; - std::cout << " x27 (s11): 0x" << std::right << std::setw(8) - << std::hex << register_bank[27] << std::endl; + std::cout << "x24 (s8): 0x" << std::right << std::setw(8) + << std::hex << register_bank[24]; + std::cout << " x25 (s9): 0x" << std::right << std::setw(8) + << std::hex << register_bank[25]; + std::cout << " x26 (s10): 0x" << std::right << std::setw(8) + << std::hex << register_bank[26]; + std::cout << " x27 (s11): 0x" << std::right << std::setw(8) + << std::hex << register_bank[27] << std::endl; - std::cout << "x28 (t3): 0x" << std::right << std::setw(8) - << 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; + std::cout << "x28 (t3): 0x" << std::right << std::setw(8) + << 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; - std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl; - std::cout << "************************************" << std::endl; + std::cout << "PC: 0x" << std::setw(8) << std::hex << register_PC << std::dec << std::endl; + std::cout << "************************************" << std::endl; } private: @@ -407,9 +408,9 @@ namespace riscv_tlm { Performance *perf; void initCSR() { - CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION - | MISA_A_EXTENSION | MISA_I_BASE; - CSR[CSR_MSTATUS] = MISA_MXL; + CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION + | MISA_A_EXTENSION | MISA_I_BASE; + CSR[CSR_MSTATUS] = MISA_MXL; } }; } diff --git a/inc/extension_base.h b/inc/extension_base.h index 2ae1473..3abf2e6 100644 --- a/inc/extension_base.h +++ b/inc/extension_base.h @@ -34,87 +34,88 @@ namespace riscv_tlm { public: extension_base(const T &instr, Registers *register_bank, MemoryInterface *mem_interface) : - m_instr(instr), regs(register_bank), mem_intf(mem_interface) { + m_instr(instr), regs(register_bank), mem_intf(mem_interface) { - perf = Performance::getInstance(); - logger = spdlog::get("my_logger"); + perf = Performance::getInstance(); + logger = spdlog::get("my_logger"); } virtual ~extension_base() = default; void setInstr(std::uint32_t p_instr) { - m_instr = sc_dt::sc_uint<32>(p_instr); + m_instr = sc_dt::sc_uint<32>(p_instr); } void RaiseException(std::uint32_t cause, std::uint32_t inst) { - std::uint32_t new_pc, current_pc, m_cause; + std::uint32_t new_pc, current_pc, m_cause; - current_pc = regs->getPC(); - m_cause = regs->getCSR(CSR_MSTATUS); - m_cause |= cause; + current_pc = regs->getPC(); + m_cause = regs->getCSR(CSR_MSTATUS); + m_cause |= cause; - new_pc = regs->getCSR(CSR_MTVEC); + new_pc = regs->getCSR(CSR_MTVEC); - regs->setCSR(CSR_MEPC, current_pc); + regs->setCSR(CSR_MEPC, current_pc); - if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) { - regs->setCSR(CSR_MTVAL, inst); + if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) { + regs->setCSR(CSR_MTVAL, inst); } else { - regs->setCSR(CSR_MTVAL, current_pc); + regs->setCSR(CSR_MTVAL, current_pc); } - regs->setCSR(CSR_MCAUSE, cause); - regs->setCSR(CSR_MSTATUS, m_cause); + regs->setCSR(CSR_MCAUSE, cause); + regs->setCSR(CSR_MSTATUS, m_cause); - regs->setPC(new_pc); + regs->setPC(new_pc); - logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC(), - new_pc); + logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), + regs->getPC(), + new_pc); } bool NOP() { - logger->debug("{} ns. PC: 0x{:x}. NOP! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC()); - 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; } /* pure virtual functions */ - virtual std::int32_t opcode() const = 0; + virtual T opcode() const = 0; - virtual std::int32_t get_rd() const { + virtual unsigned int get_rd() const { return m_instr.range(11, 7); } - virtual void set_rd(std::int32_t value) { + virtual void set_rd(unsigned int value) { m_instr.range(11, 7) = value; } - virtual std::int32_t get_rs1() const { + virtual unsigned int get_rs1() const { return m_instr.range(19, 15); } - virtual void set_rs1(std::int32_t value) { + virtual void set_rs1(unsigned int value) { m_instr.range(19, 15) = value; } - virtual std::int32_t get_rs2() const { + virtual unsigned int get_rs2() const { return m_instr.range(24, 20); } - virtual void set_rs2(std::int32_t value) { + virtual void set_rs2(unsigned int value) { m_instr.range(24, 20) = value; } - virtual std::int32_t get_funct3() const { + virtual unsigned int get_funct3() const { return m_instr.range(14, 12); } - virtual void set_funct3(std::int32_t value) { + virtual void set_funct3(unsigned int value) { m_instr.range(14, 12) = value; } virtual void dump() const { - std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; + std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; } protected: diff --git a/src/A_extension.cpp b/src/A_extension.cpp index b603772..5b83563 100644 --- a/src/A_extension.cpp +++ b/src/A_extension.cpp @@ -6,440 +6,4 @@ */ // SPDX-License-Identifier: GPL-3.0-or-later -#include "A_extension.h" - -namespace riscv_tlm { - - op_A_Codes A_extension::decode() const { - - switch (opcode()) { - case A_LR: - return OP_A_LR; - break; - case A_SC: - return OP_A_SC; - break; - case A_AMOSWAP: - return OP_A_AMOSWAP; - break; - case A_AMOADD: - return OP_A_AMOADD; - break; - case A_AMOXOR: - return OP_A_AMOXOR; - break; - case A_AMOAND: - return OP_A_AMOAND; - break; - case A_AMOOR: - return OP_A_AMOOR; - break; - case A_AMOMIN: - return OP_A_AMOMIN; - break; - case A_AMOMAX: - return OP_A_AMOMAX; - break; - case A_AMOMINU: - return OP_A_AMOMINU; - break; - case A_AMOMAXU: - return OP_A_AMOMAXU; - break; - [[unlikely]] default: - return OP_A_ERROR; - break; - - } - - return OP_A_ERROR; - } - - bool A_extension::Exec_A_LR() { - std::uint32_t mem_addr = 0; - int rd, rs1, rs2; - std::uint32_t data; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (rs2 != 0) { - std::cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << std::endl; - RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); - - return false; - } - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - TLB_reserve(mem_addr); - - logger->debug("{} ns. PC: 0x{:x}. A.LR.W: x{:d}(0x{:x}) -> x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, mem_addr, rd, data); - - return true; - } - - bool A_extension::Exec_A_SC() { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = regs->getValue(rs2); - - if (TLB_reserved(mem_addr)) { - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - regs->setValue(rd, 0); // SC writes 0 to rd on success - } else { - regs->setValue(rd, 1); // SC writes nonzero on failure - } - - logger->debug("{} ns. PC: 0x{:x}. A.SC.W: (0x{:x}) <- x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(), - regs->getPC(), - mem_addr, rs2, data); - - return true; - } - - bool A_extension::Exec_A_AMOSWAP() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - // swap - aux = regs->getValue(rs2); - regs->setValue(rs2, static_cast(data)); - - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOSWAP"); - - return true; - } - - bool A_extension::Exec_A_AMOADD() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // add - data = data + regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOADD"); - - return true; - } - - bool A_extension::Exec_A_AMOXOR() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // add - data = data ^ regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOXOR"); - - return true; - } - - bool A_extension::Exec_A_AMOAND() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // add - data = data & regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOAND"); - - return true; - } - - bool A_extension::Exec_A_AMOOR() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // add - data = data | regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOOR"); - - return true; - } - - bool A_extension::Exec_A_AMOMIN() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // min - aux = regs->getValue(rs2); - if ((int32_t) data < (int32_t) aux) { - aux = data; - } - - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOMIN"); - - return true; - } - - bool A_extension::Exec_A_AMOMAX() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // > - aux = regs->getValue(rs2); - if ((int32_t) data > (int32_t) aux) { - aux = data; - } - - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOMAX"); - - return true; - } - - bool A_extension::Exec_A_AMOMINU() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // min - aux = regs->getValue(rs2); - if (data < aux) { - aux = data; - } - - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOMINU"); - - return true; - } - - bool A_extension::Exec_A_AMOMAXU() const { - std::uint32_t mem_addr; - int rd, rs1, rs2; - std::uint32_t data; - std::uint32_t aux; - - /* These instructions must be atomic */ - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - mem_addr = regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - - regs->setValue(rd, static_cast(data)); - - // max - aux = regs->getValue(rs2); - if (data > aux) { - aux = data; - } - - mem_intf->writeDataMem(mem_addr, aux, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. A.AMOMAXU"); - - return true; - } - - void A_extension::TLB_reserve(std::uint32_t address) { - TLB_A_Entries.insert(address); - } - - bool A_extension::TLB_reserved(std::uint32_t address) { - if (TLB_A_Entries.count(address) == 1) { - TLB_A_Entries.erase(address); - return true; - } else { - return false; - } - } - - bool A_extension::process_instruction(Instruction &inst) { - bool PC_not_affected = true; - - setInstr(inst.getInstr()); - - switch (decode()) { - case OP_A_LR: - Exec_A_LR(); - break; - case OP_A_SC: - Exec_A_SC(); - break; - case OP_A_AMOSWAP: - Exec_A_AMOSWAP(); - break; - case OP_A_AMOADD: - Exec_A_AMOADD(); - break; - case OP_A_AMOXOR: - Exec_A_AMOXOR(); - break; - case OP_A_AMOAND: - Exec_A_AMOAND(); - break; - case OP_A_AMOOR: - Exec_A_AMOOR(); - break; - case OP_A_AMOMIN: - Exec_A_AMOMIN(); - break; - case OP_A_AMOMAX: - Exec_A_AMOMAX(); - break; - case OP_A_AMOMINU: - Exec_A_AMOMINU(); - break; - case OP_A_AMOMAXU: - Exec_A_AMOMAXU(); - break; - [[unlikely]] default: - std::cout << "A instruction not implemented yet" << std::endl; - inst.dump(); - NOP(); - break; - } - - return PC_not_affected; - } -} \ No newline at end of file +#include "A_extension.h" \ No newline at end of file diff --git a/src/BASE_ISA.cpp b/src/BASE_ISA.cpp index 3c48db6..1e65da0 100644 --- a/src/BASE_ISA.cpp +++ b/src/BASE_ISA.cpp @@ -6,1478 +6,3 @@ */ // SPDX-License-Identifier: GPL-3.0-or-later -#include "spdlog/spdlog.h" - - -#include "BASE_ISA.h" - -namespace riscv_tlm { - - enum Codes { - LUI = 0b0110111, - AUIPC = 0b0010111, - JAL = 0b1101111, - JALR = 0b1100111, - - BEQ = 0b1100011, - BEQ_F = 0b000, - BNE_F = 0b001, - BLT_F = 0b100, - BGE_F = 0b101, - BLTU_F = 0b110, - BGEU_F = 0b111, - - LB = 0b0000011, - LB_F = 0b000, - LH_F = 0b001, - LW_F = 0b010, - LBU_F = 0b100, - LHU_F = 0b101, - - SB = 0b0100011, - SB_F = 0b000, - SH_F = 0b001, - SW_F = 0b010, - - ADDI = 0b0010011, - ADDI_F = 0b000, - SLTI_F = 0b010, - SLTIU_F = 0b011, - XORI_F = 0b100, - ORI_F = 0b110, - ANDI_F = 0b111, - SLLI_F = 0b001, - SRLI_F = 0b101, - SRLI_F7 = 0b0000000, - SRAI_F7 = 0b0100000, - - ADD = 0b0110011, - ADD_F = 0b000, - SUB_F = 0b000, - ADD_F7 = 0b0000000, - SUB_F7 = 0b0100000, - - SLL_F = 0b001, - SLT_F = 0b010, - SLTU_F = 0b011, - XOR_F = 0b100, - SRL_F = 0b101, - SRA_F = 0b101, - SRL_F7 = 0b0000000, - SRA_F7 = 0b0100000, - OR_F = 0b110, - AND_F = 0b111, - - FENCE = 0b0001111, - ECALL = 0b1110011, - ECALL_F = 0b000000000000, - EBREAK_F = 0b000000000001, - URET_F = 0b000000000010, - SRET_F = 0b000100000010, - MRET_F = 0b001100000010, - WFI_F = 0b000100000101, - SFENCE_F = 0b0001001, - - ECALL_F3 = 0b000, - CSRRW = 0b001, - CSRRS = 0b010, - CSRRC = 0b011, - CSRRWI = 0b101, - CSRRSI = 0b110, - CSRRCI = 0b111, - }; - - bool BASE_ISA::Exec_LUI() const { - int rd; - std::uint32_t imm; - - rd = get_rd(); - imm = get_imm_U() << 12; - regs->setValue(rd, static_cast(imm)); - - logger->debug("{} ns. PC: 0x{:x}. LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), - rd, imm); - - return true; - } - - bool BASE_ISA::Exec_AUIPC() const { - int rd; - std::uint32_t imm; - std::uint32_t new_pc; - - rd = get_rd(); - imm = get_imm_U() << 12; - new_pc = static_cast(regs->getPC() + imm); - - regs->setValue(rd, new_pc); - - logger->debug("{} ns. PC: 0x{:x}. AUIPC: x{:d} <- 0x{:x} + PC (0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rd, imm, new_pc); - - return true; - } - - bool BASE_ISA::Exec_JAL() const { - std::int32_t mem_addr; - int rd; - std::uint32_t new_pc, old_pc; - - rd = get_rd(); - mem_addr = get_imm_J(); - old_pc = regs->getPC(); - new_pc = old_pc + mem_addr; - - regs->setPC(new_pc); - - old_pc = old_pc + 4; - regs->setValue(rd, old_pc); - - logger->debug("{} ns. PC: 0x{:x}. JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rd, old_pc, mem_addr, new_pc); - - return true; - } - - bool BASE_ISA::Exec_JALR() { - std::uint32_t mem_addr; - int rd, rs1; - std::uint32_t new_pc, old_pc; - - rd = get_rd(); - rs1 = get_rs1(); - mem_addr = get_imm_I(); - - old_pc = regs->getPC(); - regs->setValue(rd, old_pc + 4); - - new_pc = static_cast((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); - - if ((new_pc & 0x00000003) != 0) { - // not aligned - logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x} PC <- 0x{:x}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rd, old_pc + 4, new_pc); - - logger->debug("{} ns. PC: 0x{:x}. JALR : Exception"); - RaiseException(EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN, m_instr); - } else { - regs->setPC(new_pc); - } - - logger->debug("{} ns. PC: 0x{:x}. JALR: x{:d} <- 0x{:x}. PC <- 0x{:x}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rd, old_pc + 4, new_pc); - - return true; - } - - bool BASE_ISA::Exec_BEQ() const { - int rs1, rs2; - std::uint32_t new_pc; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (regs->getValue(rs1) == regs->getValue(rs2)) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. BEQ: x{:d}(0x{:x}) == x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - return true; - } - - bool BASE_ISA::Exec_BNE() const { - int rs1, rs2; - std::uint32_t new_pc; - std::uint32_t val1, val2; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - val1 = regs->getValue(rs1); - val2 = regs->getValue(rs2); - - if (val1 != val2) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. BNE: x{:d}(0x{:x}) != x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, val1, rs2, val2, new_pc); - - return true; - } - - bool BASE_ISA::Exec_BLT() const { - int rs1, rs2; - std::uint32_t new_pc = 0; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (static_cast(regs->getValue(rs1)) < static_cast(regs->getValue(rs2))) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - } - - logger->debug("{} ns. PC: 0x{:x}. BLT: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - return true; - } - - bool BASE_ISA::Exec_BGE() const { - int rs1, rs2; - std::uint32_t new_pc = 0; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (static_cast(regs->getValue(rs1)) >= static_cast( regs->getValue(rs2))) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - } - - logger->debug("{} ns. PC: 0x{:x}. BGE: x{:d}(0x{:x}) > x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - return true; - } - - bool BASE_ISA::Exec_BLTU() const { - int rs1, rs2; - std::uint32_t new_pc; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (static_cast(regs->getValue(rs1)) < static_cast(regs->getValue(rs2))) { - new_pc = static_cast(regs->getPC() + get_imm_B()); - regs->setPC(new_pc); - } else { - regs->incPC(); - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. BLTU: x{:d}(0x{:x}) < x{:d}(0x{:x})? -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - return true; - } - - bool BASE_ISA::Exec_BGEU() const { - int rs1, rs2; - - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (static_cast(regs->getValue(rs1)) >= static_cast(regs->getValue(rs2))) { - std::uint32_t new_pc; - new_pc = static_cast(regs->getPC() + get_imm_B()); - - logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), new_pc); - - regs->setPC(new_pc); - } else { - logger->debug("{} ns. PC: 0x{:x}. BGEU: x{:d}(0x{:x}) > x{:d}(0x{:x}) -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), regs->getPC() + 4); - regs->incPC(); - } - - return true; - } - - bool BASE_ISA::Exec_LB() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::int8_t data; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - mem_addr = imm + regs->getValue(rs1); - data = static_cast(mem_intf->readDataMem(mem_addr, 1)); - perf->dataMemoryRead(); - regs->setValue(rd, data); - - logger->debug("{} ns. PC: 0x{:x}. LB: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, mem_addr, rd); - - return true; - } - - bool BASE_ISA::Exec_LH() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - int16_t data; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - mem_addr = imm + regs->getValue(rs1); - data = static_cast(mem_intf->readDataMem(mem_addr, 2)); - perf->dataMemoryRead(); - regs->setValue(rd, data); - - logger->debug("{} ns. PC: 0x{:x}. LH: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, mem_addr, rd); - - return true; - } - - bool BASE_ISA::Exec_LW() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::uint32_t data; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - mem_addr = imm + regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - logger->debug("{} ns. PC: 0x{:x}. LW: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, mem_addr, rd); - - return true; - } - - bool BASE_ISA::Exec_LBU() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::uint8_t data; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - mem_addr = imm + regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 1); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - logger->debug("{} ns. PC: 0x{:x}. LBU: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, mem_addr, rd); - - return true; - } - - bool BASE_ISA::Exec_LHU() const { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - uint16_t data; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - mem_addr = imm + regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 2); - perf->dataMemoryRead(); - - regs->setValue(rd, data); - - logger->debug("{} ns. PC: 0x{:x}. LHU: x{:d} + x{:d}(0x{:x}) -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, mem_addr, rd); - - return true; - } - - bool BASE_ISA::Exec_SB() const { - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; - - rs1 = get_rs1(); - rs2 = get_rs2(); - imm = get_imm_S(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 1); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. SB: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs2, rs1, imm, mem_addr); - - return true; - } - - bool BASE_ISA::Exec_SH() const { - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; - - rs1 = get_rs1(); - rs2 = get_rs2(); - imm = get_imm_S(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 2); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. SH: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs2, rs1, imm, mem_addr); - - return true; - } - - bool BASE_ISA::Exec_SW() const { - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; - - rs1 = get_rs1(); - rs2 = get_rs2(); - imm = get_imm_S(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. SW: x{:d} -> x{:d} + 0x{:x}(@0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs2, rs1, imm, mem_addr); - - return true; - } - - bool BASE_ISA::Exec_ADDI() const { - int rd, rs1; - std::int32_t imm; - std::int32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. ADDI: x{:d} + x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SLTI() const { - int rd, rs1; - std::int32_t imm; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - if (static_cast(regs->getValue(rs1)) < imm) { - regs->setValue(rd, 1); - - logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd); - } else { - regs->setValue(rd, 0); - logger->debug("{} ns. PC: 0x{:x}. SLTI: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd); - } - - return true; - } - - bool BASE_ISA::Exec_SLTIU() const { - int rd, rs1; - std::int32_t imm; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - if (static_cast(regs->getValue(rs1)) < static_cast(imm)) { - regs->setValue(rd, 1); - logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd); - } else { - regs->setValue(rd, 0); - logger->debug("{} ns. PC: 0x{:x}. SLTIU: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd); - } - - return true; - } - - bool BASE_ISA::Exec_XORI() const { - int rd, rs1; - std::int32_t imm; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - calc = regs->getValue(rs1) ^ imm; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. XORI: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd); - - return true; - } - - bool BASE_ISA::Exec_ORI() const { - int rd, rs1; - std::int32_t imm; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - calc = regs->getValue(rs1) | imm; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. ORI: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, imm, rd); - - return true; - } - - bool BASE_ISA::Exec_ANDI() const { - int rd, rs1; - std::uint32_t imm; - std::uint32_t calc; - std::uint32_t aux; - - rd = get_rd(); - rs1 = get_rs1(); - imm = get_imm_I(); - - aux = regs->getValue(rs1); - calc = aux & imm; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, aux, imm, rd); - - return true; - } - - bool BASE_ISA::Exec_SLLI() { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_shamt(); - - if (rs2 >= 0x20) { - std::cout << "ILEGAL INSTRUCTION, shamt[5] != 0" << "\n"; - RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); - - return false; - } - - shift = rs2 & 0x1F; - - calc = static_cast(regs->getValue(rs1)) << shift; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. SLLI: x{:d} << {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SRLI() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - shift = rs2 & 0x1F; - - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. SRLI: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SRAI() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::int32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - shift = rs2 & 0x1F; - - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. SRAI: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_ADD() const { - int rd, rs1, rs2; - std::uint32_t calc; - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) + regs->getValue(rs2); - - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. ADD: x{:d} + x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SUB() const { - int rd, rs1, rs2; - std::uint32_t calc; - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) - regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SLL() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - shift = regs->getValue(rs2) & 0x1F; - - calc = static_cast(regs->getValue(rs1)) << shift; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. SLL: x{:d} << x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SLT() const { - int rd, rs1, rs2; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (regs->getValue(rs1) < regs->getValue(rs2)) { - regs->setValue(rd, 1); - logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - } else { - regs->setValue(rd, 0); - logger->debug("{} ns. PC: 0x{:x}. SLT: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - } - - return true; - } - - bool BASE_ISA::Exec_SLTU() const { - int rd, rs1, rs2; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - if (static_cast(regs->getValue(rs1)) < static_cast(regs->getValue(rs2))) { - regs->setValue(rd, 1); - logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 1 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - } else { - regs->setValue(rd, 0); - logger->debug("{} ns. PC: 0x{:x}. SLTU: x{:d} < x{:d} => 0 -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - } - - return true; - } - - bool BASE_ISA::Exec_XOR() const { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) ^ regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. XOR: x{:d} XOR x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SRL() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - shift = regs->getValue(rs2) & 0x1F; - - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. SRL: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_SRA() const { - int rd, rs1, rs2; - std::uint32_t shift; - std::int32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - shift = regs->getValue(rs2) & 0x1F; - - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. SRA: x{:d} >> {:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_OR() const { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) | regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. OR: x{:d} OR x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_AND() const { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) & regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. AND: x{:d} AND x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool BASE_ISA::Exec_FENCE() const { - logger->debug("{} ns. PC: 0x{:x}. FENCE"); - - return true; - } - - bool BASE_ISA::Exec_ECALL() { - - logger->debug("{} ns. PC: 0x{:x}. ECALL"); - - std::cout << std::endl << "ECALL Instruction called, stopping simulation" - << std::endl; - regs->dump(); - std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; - perf->dump(); - -#if 0 - std::uint32_t gp_value = regs->getValue(Registers::gp); - if (gp_value == 1) { - std::cout << "GP value is 1, test result is OK" << "\n"; - } else { - std::cout << "GP value is " << gp_value << "\n"; - } - - sc_core::sc_stop(); -#else - RaiseException(11, m_instr); -#endif - return true; - } - - bool BASE_ISA::Exec_EBREAK() { - - logger->debug("{} ns. PC: 0x{:x}. EBREAK"); - std::cout << std::endl << "EBRAK Instruction called, dumping information" - << std::endl; - regs->dump(); - std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; - perf->dump(); - - RaiseException(11, m_instr); - - return false; - } - - bool BASE_ISA::Exec_CSRRW() const { - int rd, rs1; - int csr; - std::uint32_t aux; - - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); - - /* These operations must be atomical */ - if (rd != 0) { - aux = regs->getCSR(csr); - regs->setValue(rd, static_cast(aux)); - } - - aux = regs->getValue(rs1); - regs->setCSR(csr, aux); - - logger->debug("{} ns. PC: 0x{:x}. CSRRW: CSR #{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - csr, rd, aux); - - return true; - } - - bool BASE_ISA::Exec_CSRRS() const { - int rd, rs1; - int csr; - std::uint32_t bitmask, aux, aux2; - - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); - - if (rd == 0) { - logger->debug("{} ns. PC: 0x{:x}. CSRRS with rd1 == 0, doing nothing."); - return false; - } - - /* These operations must be atomical */ - aux = regs->getCSR(csr); - bitmask = regs->getValue(rs1); - - regs->setValue(rd, static_cast(aux)); - - aux2 = aux | bitmask; - regs->setCSR(csr, aux2); - - logger->debug("{} ns. PC: 0x{:x}. CSRRS: CSR #{:d}(0x{:x}) -> x{:d}(0x{:x}) & CSR #{:d} <- 0x{:x}", - sc_core::sc_time_stamp().value(), regs->getPC(), - csr, aux, rd, rs1, csr, aux2); - - return true; - } - - bool BASE_ISA::Exec_CSRRC() const { - int rd, rs1; - int csr; - std::uint32_t bitmask, aux, aux2; - - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); - - if (rd == 0) { - logger->debug("{} ns. PC: 0x{:x}. CSRRC with rd1 == 0, doing nothing."); - return true; - } - - /* These operations must be atomical */ - aux = regs->getCSR(csr); - bitmask = regs->getValue(rs1); - - regs->setValue(rd, static_cast(aux)); - - aux2 = aux & ~bitmask; - regs->setCSR(csr, aux2); - - logger->debug("{} ns. PC: 0x{:x}. CSRRC: CSR #{:d}(0x{:x}) -> x{:d}(0x{:x}) & CSR #{:d} <- 0x{:x}", - sc_core::sc_time_stamp().value(), regs->getPC(), - csr, aux, rd, rs1, csr, aux2); - - return true; - } - - bool BASE_ISA::Exec_CSRRWI() const { - int rd, rs1; - int csr; - std::uint32_t aux; - - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); - - /* These operations must be atomical */ - if (rd != 0) { - aux = regs->getCSR(csr); - regs->setValue(rd, static_cast(aux)); - } - aux = rs1; - regs->setCSR(csr, aux); - - logger->debug("{} ns. PC: 0x{:x}. CSRRWI: CSR #{:d} -> x{:d}. x{:d} -> CSR #{:d}", - sc_core::sc_time_stamp().value(), regs->getPC(), - csr, rd, rs1, csr); - - return true; - } - - bool BASE_ISA::Exec_CSRRSI() const { - int rd, rs1; - int csr; - std::uint32_t bitmask, aux; - - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); - - if (rs1 == 0) { - return true; - } - - /* These operations must be atomical */ - aux = regs->getCSR(csr); - regs->setValue(rd, static_cast(aux)); - - bitmask = rs1; - aux = aux | bitmask; - regs->setCSR(csr, aux); - - logger->debug("{} ns. PC: 0x{:x}. CSRRSI: CSR #{:d} -> x{:d}. x{:d} & CSR #{:d}(0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - csr, rd, rs1, csr, aux); - - return true; - } - - bool BASE_ISA::Exec_CSRRCI() const { - int rd, rs1; - int csr; - std::uint32_t bitmask, aux; - - rd = get_rd(); - rs1 = get_rs1(); - csr = get_csr(); - - if (rs1 == 0) { - return true; - } - - /* These operations must be atomical */ - aux = regs->getCSR(csr); - regs->setValue(rd, static_cast(aux)); - - bitmask = rs1; - aux = aux & ~bitmask; - regs->setCSR(csr, aux); - - logger->debug("{} ns. PC: 0x{:x}. CSRRCI: CSR #{:d} -> x{:d}. x{:d} & CSR #{:d}(0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - csr, rd, rs1, csr, aux); - - return true; - } - -/*********************** Privileged Instructions ******************************/ - - bool BASE_ISA::Exec_MRET() const { - std::uint32_t new_pc = 0; - - new_pc = regs->getCSR(CSR_MEPC); - regs->setPC(new_pc); - - logger->debug("{} ns. PC: 0x{:x}. MRET: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), new_pc); - - // update mstatus - std::uint32_t csr_temp; - csr_temp = regs->getCSR(CSR_MSTATUS); - if (csr_temp & MSTATUS_MPIE) { - csr_temp |= MSTATUS_MIE; - } - csr_temp |= MSTATUS_MPIE; - regs->setCSR(CSR_MSTATUS, csr_temp); - - return true; - } - - bool BASE_ISA::Exec_SRET() const { - std::uint32_t new_pc = 0; - - new_pc = regs->getCSR(CSR_SEPC); - regs->setPC(new_pc); - - logger->debug("{} ns. PC: 0x{:x}. SRET: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC()); - return true; - } - - bool BASE_ISA::Exec_WFI() const { - logger->debug("{} ns. PC: 0x{:x}. WFI"); - return true; - } - - bool BASE_ISA::Exec_SFENCE() const { - logger->debug("{} ns. PC: 0x{:x}. SFENCE"); - return true; - } - - bool BASE_ISA::process_instruction(Instruction &inst, bool *breakpoint) { - bool PC_not_affected = true; - - *breakpoint = false; - setInstr(inst.getInstr()); - - switch (decode()) { - case OP_LUI: - Exec_LUI(); - break; - case OP_AUIPC: - Exec_AUIPC(); - break; - case OP_JAL: - Exec_JAL(); - PC_not_affected = false; - break; - case OP_JALR: - Exec_JALR(); - PC_not_affected = false; - break; - case OP_BEQ: - Exec_BEQ(); - PC_not_affected = false; - break; - case OP_BNE: - Exec_BNE(); - PC_not_affected = false; - break; - case OP_BLT: - Exec_BLT(); - PC_not_affected = false; - break; - case OP_BGE: - Exec_BGE(); - PC_not_affected = false; - break; - case OP_BLTU: - Exec_BLTU(); - PC_not_affected = false; - break; - case OP_BGEU: - Exec_BGEU(); - PC_not_affected = false; - break; - case OP_LB: - Exec_LB(); - break; - case OP_LH: - Exec_LH(); - break; - case OP_LW: - Exec_LW(); - break; - case OP_LBU: - Exec_LBU(); - break; - case OP_LHU: - Exec_LHU(); - break; - case OP_SB: - Exec_SB(); - break; - case OP_SH: - Exec_SH(); - break; - case OP_SW: - Exec_SW(); - break; - case OP_ADDI: - Exec_ADDI(); - break; - case OP_SLTI: - Exec_SLTI(); - break; - case OP_SLTIU: - Exec_SLTIU(); - break; - case OP_XORI: - Exec_XORI(); - break; - case OP_ORI: - Exec_ORI(); - break; - case OP_ANDI: - Exec_ANDI(); - break; - case OP_SLLI: - PC_not_affected = Exec_SLLI(); - break; - case OP_SRLI: - Exec_SRLI(); - break; - case OP_SRAI: - Exec_SRAI(); - break; - case OP_ADD: - Exec_ADD(); - break; - case OP_SUB: - Exec_SUB(); - break; - case OP_SLL: - Exec_SLL(); - break; - case OP_SLT: - Exec_SLT(); - break; - case OP_SLTU: - Exec_SLTU(); - break; - case OP_XOR: - Exec_XOR(); - break; - case OP_SRL: - Exec_SRL(); - break; - case OP_SRA: - Exec_SRA(); - break; - case OP_OR: - Exec_OR(); - break; - case OP_AND: - Exec_AND(); - break; - case OP_FENCE: - Exec_FENCE(); - break; - case OP_ECALL: - Exec_ECALL(); - *breakpoint = true; - std::cout << "ECALL" << std::endl; - break; - case OP_EBREAK: - PC_not_affected = Exec_EBREAK(); -// *breakpoint = true; - break; - case OP_CSRRW: - Exec_CSRRW(); - break; - case OP_CSRRS: - Exec_CSRRS(); - break; - case OP_CSRRC: - Exec_CSRRC(); - break; - case OP_CSRRWI: - Exec_CSRRWI(); - break; - case OP_CSRRSI: - Exec_CSRRSI(); - break; - case OP_CSRRCI: - Exec_CSRRCI(); - break; - case OP_MRET: - Exec_MRET(); - PC_not_affected = false; - break; - case OP_SRET: - Exec_SRET(); - PC_not_affected = false; - break; - case OP_WFI: - Exec_WFI(); - break; - case OP_SFENCE: - Exec_SFENCE(); - break; - [[unlikely]] default: - std::cout << "Wrong instruction" << "\n"; - inst.dump(); - NOP(); - //sc_stop(); - break; - } - - return PC_not_affected; - } - - opCodes BASE_ISA::decode() { - switch (opcode()) { - case LUI: - return OP_LUI; - case AUIPC: - return OP_AUIPC; - case JAL: - return OP_JAL; - case JALR: - return OP_JALR; - case BEQ: - switch (get_funct3()) { - case BEQ_F: - return OP_BEQ; - case BNE_F: - return OP_BNE; - case BLT_F: - return OP_BLT; - case BGE_F: - return OP_BGE; - case BLTU_F: - return OP_BLTU; - case BGEU_F: - return OP_BGEU; - } - return OP_ERROR; - case LB: - switch (get_funct3()) { - case LB_F: - return OP_LB; - case LH_F: - return OP_LH; - case LW_F: - return OP_LW; - case LBU_F: - return OP_LBU; - case LHU_F: - return OP_LHU; - } - return OP_ERROR; - case SB: - switch (get_funct3()) { - case SB_F: - return OP_SB; - case SH_F: - return OP_SH; - case SW_F: - return OP_SW; - } - return OP_ERROR; - case ADDI: - switch (get_funct3()) { - case ADDI_F: - return OP_ADDI; - case SLTI_F: - return OP_SLTI; - case SLTIU_F: - return OP_SLTIU; - case XORI_F: - return OP_XORI; - case ORI_F: - return OP_ORI; - case ANDI_F: - return OP_ANDI; - case SLLI_F: - return OP_SLLI; - case SRLI_F: - switch (get_funct7()) { - case SRLI_F7: - return OP_SRLI; - case SRAI_F7: - return OP_SRAI; - } - return OP_ERROR; - } - return OP_ERROR; - case ADD: { - switch (get_funct3()) { - case ADD_F: - switch (get_funct7()) { - case ADD_F7: - return OP_ADD; - case SUB_F7: - return OP_SUB; - default: - return OP_ADD; - } - break; - case SLL_F: - return OP_SLL; - case SLT_F: - return OP_SLT; - case SLTU_F: - return OP_SLTU; - case XOR_F: - return OP_XOR; - case SRL_F: - switch (get_funct7()) { - case SRL_F7: - return OP_SRL; - case SRA_F7: - return OP_SRA; - default: - return OP_ERROR; - } - case OR_F: - return OP_OR; - case AND_F: - return OP_AND; - default: - return OP_ERROR; - } - } /* ADD */ - case FENCE: - return OP_FENCE; - case ECALL: { - switch (get_funct3()) { - case ECALL_F3: - switch (get_csr()) { - case ECALL_F: - return OP_ECALL; - case EBREAK_F: - return OP_EBREAK; - case URET_F: - return OP_URET; - case SRET_F: - return OP_SRET; - case MRET_F: - return OP_MRET; - case WFI_F: - return OP_WFI; - case SFENCE_F: - return OP_SFENCE; - } - if (m_instr.range(31, 25) == 0b0001001) { - return OP_SFENCE; - } - break; - case CSRRW: - return OP_CSRRW; - break; - case CSRRS: - return OP_CSRRS; - break; - case CSRRC: - return OP_CSRRC; - break; - case CSRRWI: - return OP_CSRRWI; - break; - case CSRRSI: - return OP_CSRRSI; - break; - case CSRRCI: - return OP_CSRRCI; - break; - } - } - break; - default: - return OP_ERROR; - } - - return OP_ERROR; - } -} \ No newline at end of file diff --git a/src/CPU.cpp b/src/CPU.cpp index 31a1e4b..6289e49 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -12,8 +12,8 @@ namespace riscv_tlm { SC_HAS_PROCESS(CPU); 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) { + 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(); @@ -32,10 +32,10 @@ namespace riscv_tlm { instr_bus.register_invalidate_direct_mem_ptr(this, &CPU::invalidate_direct_mem_ptr); - exec = new BASE_ISA(0, register_bank, mem_intf); - c_inst = new C_extension(0, register_bank, mem_intf); - m_inst = new M_extension(0, register_bank, mem_intf); - a_inst = new A_extension(0, register_bank, mem_intf); + exec = new BASE_ISA(0, register_bank, mem_intf); + c_inst = new C_extension(0, register_bank, mem_intf); + 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(); m_qk->reset(); diff --git a/src/C_extension.cpp b/src/C_extension.cpp index e70f446..1c34c72 100644 --- a/src/C_extension.cpp +++ b/src/C_extension.cpp @@ -5,749 +5,3 @@ \date August 2018 */ #include "C_extension.h" - -namespace riscv_tlm { - - op_C_Codes C_extension::decode() const { - - switch (opcode()) { - - case 0b00: - switch (get_funct3()) { - case C_ADDI4SPN: - return OP_C_ADDI4SPN; - break; - case C_FLD: - return OP_C_FLD; - break; - case C_LW: - return OP_C_LW; - break; - case C_FLW: - return OP_C_FLW; - break; - case C_FSD: - return OP_C_FSD; - break; - case C_SW: - return OP_C_SW; - break; - case C_FSW: - return OP_C_FSW; - break; - [[unlikely]] default: - return OP_C_ERROR; - break; - } - break; - - case 0b01: - switch (get_funct3()) { - case C_ADDI: - return OP_C_ADDI; - break; - case C_JAL: - return OP_C_JAL; - break; - case C_LI: - return OP_C_LI; - break; - case C_ADDI16SP: - return OP_C_ADDI16SP; - break; - case C_SRLI: - switch (m_instr.range(11, 10)) { - case C_2_SRLI: - return OP_C_SRLI; - break; - case C_2_SRAI: - return OP_C_SRAI; - break; - case C_2_ANDI: - return OP_C_ANDI; - break; - case C_2_SUB: - switch (m_instr.range(6, 5)) { - case C_3_SUB: - return OP_C_SUB; - break; - case C_3_XOR: - return OP_C_XOR; - break; - case C_3_OR: - return OP_C_OR; - break; - case C_3_AND: - return OP_C_AND; - break; - } - } - break; - case C_J: - return OP_C_J; - break; - case C_BEQZ: - return OP_C_BEQZ; - break; - case C_BNEZ: - return OP_C_BNEZ; - break; - [[unlikely]] default: - return OP_C_ERROR; - break; - } - break; - - case 0b10: - switch (get_funct3()) { - case C_SLLI: - return OP_C_SLLI; - break; - case C_FLDSP: - case C_LWSP: - return OP_C_LWSP; - break; - case C_FLWSP: - return OP_C_FLWSP; - break; - case C_JR: - if (m_instr[12] == 0) { - if (m_instr.range(6, 2) == 0) { - return OP_C_JR; - } else { - return OP_C_MV; - } - } else { - if (m_instr.range(11, 2) == 0) { - return OP_C_EBREAK; - } else if (m_instr.range(6, 2) == 0) { - return OP_C_JALR; - } else { - return OP_C_ADD; - } - } - break; - case C_FDSP: - break; - case C_SWSP: - return OP_C_SWSP; - break; - case C_FWWSP: - [[unlikely]] - default: - return OP_C_ERROR; - break; - } - break; - - [[unlikely]] default: - - return OP_C_ERROR; - break; - } - return OP_C_ERROR; - } - - bool C_extension::Exec_C_JR() { - std::uint32_t mem_addr; - int rs1; - int new_pc; - - rs1 = get_rs1(); - mem_addr = 0; - - new_pc = static_cast( - static_cast((regs->getValue(rs1)) + static_cast(mem_addr)) & 0xFFFFFFFE); - - logger->debug("{} ns. PC: 0x{:x}. C.JR: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), new_pc); - - regs->setPC(new_pc); - - return true; - } - - bool C_extension::Exec_C_MV() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rd(); - rs1 = 0; - rs2 = get_rs2(); - - calc = regs->getValue(rs1) + regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.MV: x{:d}(0x{:x}) + x{:d}(0x{:x}) -> x{:d}(0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), rd, calc); - - return true; - } - - bool C_extension::Exec_C_ADD() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rs1(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - calc = regs->getValue(rs1) + regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.ADD: x{:d} + x{} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool C_extension::Exec_C_LWSP() { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::uint32_t data; - - // lw rd, offset[7:2](x2) - - rd = get_rd(); - rs1 = 2; - imm = get_imm_LWSP(); - - mem_addr = imm + regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - regs->setValue(rd, data); - - logger->debug("{} ns. PC: 0x{:x}. C.LWSP: x{:d} + {:d}(@0x{:x}) -> x{:d}({:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, mem_addr, rd, data); - - return true; - } - - bool C_extension::Exec_C_ADDI4SPN() { - int rd, rs1; - std::int32_t imm; - std::int32_t calc; - - rd = get_rdp(); - rs1 = 2; - imm = get_imm_ADDI4SPN(); - - if (imm == 0) { - RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); - return false; - } - - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. C.ADDI4SN: x{:d} + (0x{:x}) + {:d} -> x{:d}(0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), imm, rd, calc); - - return true; - } - - bool C_extension::Exec_C_ADDI16SP() { - // addi x2, x2, nzimm[9:4] - int rd; - std::int32_t imm; - - if (get_rd() == 2) { - int rs1; - std::int32_t calc; - - rd = 2; - rs1 = 2; - imm = get_imm_ADDI16SP(); - - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. C.ADDI16SP: x{:d} + {:d} -> x{:d} (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, imm, rd, calc); - } else { - /* C.LUI OPCODE */ - rd = get_rd(); - imm = get_imm_LUI(); - regs->setValue(rd, imm); - - logger->debug("{} ns. PC: 0x{:x}. C.LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), - rd, imm); - } - - return true; - } - - bool C_extension::Exec_C_SWSP() { - // sw rs2, offset(x2) - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; - - rs1 = 2; - rs2 = get_rs2(); - imm = get_imm_CSS(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. C.SWSP: x{:d}(0x{:x}) -> x{:d} + {} (@0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs2, data, rs1, imm, mem_addr); - - return true; - } - - bool C_extension::Exec_C_BEQZ() { - int rs1; - int new_pc; - std::uint32_t val1; - - rs1 = get_rs1p(); - val1 = regs->getValue(rs1); - - if (val1 == 0) { - new_pc = static_cast(regs->getPC()) + get_imm_CB(); - regs->setPC(new_pc); - } else { - regs->incPCby2(); - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. C.BEQZ: x{:d}(0x{:x}) == 0? -> PC (0xx{:d})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, val1, new_pc); - - return true; - } - - bool C_extension::Exec_C_BNEZ() { - int rs1; - int new_pc; - std::uint32_t val1; - - rs1 = get_rs1p(); - val1 = regs->getValue(rs1); - - if (val1 != 0) { - new_pc = static_cast(regs->getPC()) + get_imm_CB(); - regs->setPC(new_pc); - } else { - regs->incPCby2(); //PC <- PC +2 - new_pc = static_cast(regs->getPC()); - } - - logger->debug("{} ns. PC: 0x{:x}. C.BNEZ: x{:d}(0x{:x}) != 0? -> PC (0xx{:d})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, val1, new_pc); - - return true; - } - - bool C_extension::Exec_C_LI() { - int rd, rs1; - std::int32_t imm; - std::int32_t calc; - - rd = get_rd(); - rs1 = 0; - imm = get_imm_ADDI(); - - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. C.LI: x{:d} ({:d}) + {:d} -> x{:d}(0x{:x}) ", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), imm, rd, calc); - - return true; - } - - bool C_extension::Exec_C_SRLI() { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2(); - - shift = rs2 & 0x1F; - - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.SRLI: x{:d} >> {} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd); - - return true; - } - - bool C_extension::Exec_C_SRAI() { - int rd, rs1, rs2; - std::uint32_t shift; - std::int32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2(); - - shift = rs2 & 0x1F; - - calc = static_cast(regs->getValue(rs1)) >> shift; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. C.SRAI: x{:d} >> {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool C_extension::Exec_C_SLLI() { - int rd, rs1, rs2; - std::uint32_t shift; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_imm_ADDI(); - - shift = rs2 & 0x1F; - - calc = static_cast(regs->getValue(rs1)) << shift; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.SLLI: x{:d} << {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, shift, rd, calc); - - return true; - } - - bool C_extension::Exec_C_ANDI() { - int rd, rs1; - std::uint32_t imm; - std::uint32_t aux; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - imm = get_imm_ADDI(); - - aux = regs->getValue(rs1); - calc = aux & imm; - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, aux, imm, rd); - - return true; - } - - bool C_extension::Exec_C_SUB() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2p(); - - calc = regs->getValue(rs1) - regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, calc); - - return true; - } - - bool C_extension::Exec_C_XOR() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2p(); - - calc = regs->getValue(rs1) ^ regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.XOR: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - - return true; - } - - bool C_extension::Exec_C_OR() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2p(); - - calc = regs->getValue(rs1) | regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.OR: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - - return true; - } - - bool C_extension::Exec_C_AND() { - int rd, rs1, rs2; - std::uint32_t calc; - - rd = get_rs1p(); - rs1 = get_rs1p(); - rs2 = get_rs2p(); - - calc = regs->getValue(rs1) & regs->getValue(rs2); - regs->setValue(rd, static_cast(calc)); - - logger->debug("{} ns. PC: 0x{:x}. C.AND: x{:d} AND x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd); - - return true; - } - - bool C_extension::Exec_C_ADDI() const { - int rd, rs1; - std::int32_t imm; - std::int32_t calc; - - rd = get_rd(); - rs1 = rd; - imm = get_imm_ADDI(); - - calc = static_cast(regs->getValue(rs1)) + imm; - regs->setValue(rd, calc); - - logger->debug("{} ns. PC: 0x{:x}. C.ADDI: x{:d} + {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), - regs->getPC(), rs1, imm, rd, calc); - - return true; - } - - bool C_extension::Exec_C_JALR() { - std::uint32_t mem_addr = 0; - int rd, rs1; - int new_pc, old_pc; - - rd = 1; - rs1 = get_rs1(); - - old_pc = static_cast(regs->getPC()); - regs->setValue(rd, old_pc + 2); - - new_pc = static_cast((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); - regs->setPC(new_pc); - - logger->debug("{} ns. PC: 0x{:x}. C.JALR: x{:d} <- 0x{:x} PC <- 0xx{:x}", sc_core::sc_time_stamp().value(), - regs->getPC(), - rd, old_pc + 4, new_pc); - - return true; - } - - bool C_extension::Exec_C_LW() { - std::uint32_t mem_addr; - int rd, rs1; - std::int32_t imm; - std::uint32_t data; - - rd = get_rdp(); - rs1 = get_rs1p(); - imm = get_imm_L(); - - mem_addr = imm + regs->getValue(rs1); - data = mem_intf->readDataMem(mem_addr, 4); - perf->dataMemoryRead(); - regs->setValue(rd, static_cast(data)); - - logger->debug("{} ns. PC: 0x{:x}. C.LW: x{:d}(0x{:x}) + {:d} (@0x{:x}) -> {:d} (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs1, regs->getValue(rs1), imm, mem_addr, rd, data); - - return true; - } - - bool C_extension::Exec_C_SW() { - std::uint32_t mem_addr; - int rs1, rs2; - std::int32_t imm; - std::uint32_t data; - - rs1 = get_rs1p(); - rs2 = get_rs2p(); - imm = get_imm_L(); - - mem_addr = imm + regs->getValue(rs1); - data = regs->getValue(rs2); - - mem_intf->writeDataMem(mem_addr, data, 4); - perf->dataMemoryWrite(); - - logger->debug("{} ns. PC: 0x{:x}. C.SW: x{:d}(0x{:x}) -> x{:d} + 0x{:x}(@0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rs2, data, rs1, imm, mem_addr); - - return true; - } - - bool C_extension::Exec_C_JAL(int m_rd) { - std::int32_t mem_addr; - int rd; - int new_pc, old_pc; - - rd = m_rd; - mem_addr = get_imm_J(); - old_pc = static_cast(regs->getPC()); - - new_pc = old_pc + mem_addr; - regs->setPC(new_pc); - - old_pc = old_pc + 2; - regs->setValue(rd, old_pc); - - logger->debug("{} ns. PC: 0x{:x}. C.JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", - sc_core::sc_time_stamp().value(), regs->getPC(), - rd, old_pc, mem_addr, new_pc); - - return true; - } - - bool C_extension::Exec_C_EBREAK() { - - logger->debug("C.EBREAK"); - std::cout << "\n" << "C.EBRAK Instruction called, dumping information" - << "\n"; - regs->dump(); - std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; - perf->dump(); - - sc_core::sc_stop(); - - return true; - } - - bool C_extension::process_instruction(Instruction &inst, bool *breakpoint) { - bool PC_not_affected = true; - - *breakpoint = false; - - setInstr(inst.getInstr()); - - switch (decode()) { - case OP_C_ADDI4SPN: - PC_not_affected = Exec_C_ADDI4SPN(); - break; - case OP_C_LW: - Exec_C_LW(); - break; - case OP_C_SW: - Exec_C_SW(); - break; - case OP_C_ADDI: - Exec_C_ADDI(); - break; - case OP_C_JAL: - Exec_C_JAL(1); - PC_not_affected = false; - break; - case OP_C_J: - Exec_C_JAL(0); - PC_not_affected = false; - break; - case OP_C_LI: - Exec_C_LI(); - break; - case OP_C_SLLI: - Exec_C_SLLI(); - break; - case OP_C_LWSP: - Exec_C_LWSP(); - break; - case OP_C_JR: - Exec_C_JR(); - PC_not_affected = false; - break; - case OP_C_MV: - Exec_C_MV(); - break; - case OP_C_JALR: - Exec_C_JALR(); - PC_not_affected = false; - break; - case OP_C_ADD: - Exec_C_ADD(); - break; - case OP_C_SWSP: - Exec_C_SWSP(); - break; - case OP_C_ADDI16SP: - Exec_C_ADDI16SP(); - break; - case OP_C_BEQZ: - Exec_C_BEQZ(); - PC_not_affected = false; - break; - case OP_C_BNEZ: - Exec_C_BNEZ(); - PC_not_affected = false; - break; - case OP_C_SRLI: - Exec_C_SRLI(); - break; - case OP_C_SRAI: - Exec_C_SRAI(); - break; - case OP_C_ANDI: - Exec_C_ANDI(); - break; - case OP_C_SUB: - Exec_C_SUB(); - break; - case OP_C_XOR: - Exec_C_XOR(); - break; - case OP_C_OR: - Exec_C_OR(); - break; - case OP_C_AND: - Exec_C_AND(); - break; - case OP_C_EBREAK: - Exec_C_EBREAK(); - std::cout << "C_EBREAK" << std::endl; - *breakpoint = true; - break; - [[unlikely]] default: - std::cout << "C instruction not implemented yet" << "\n"; - inst.dump(); - NOP(); - break; - } - - return PC_not_affected; - } - -} \ No newline at end of file diff --git a/src/M_extension.cpp b/src/M_extension.cpp index a29d544..4e8fee2 100644 --- a/src/M_extension.cpp +++ b/src/M_extension.cpp @@ -8,292 +8,3 @@ #include "M_extension.h" -namespace riscv_tlm { - - op_M_Codes M_extension::decode() const { - - switch (opcode()) { - case M_MUL: - return OP_M_MUL; - break; - case M_MULH: - return OP_M_MULH; - break; - case M_MULHSU: - return OP_M_MULHSU; - break; - case M_MULHU: - return OP_M_MULHU; - break; - case M_DIV: - return OP_M_DIV; - break; - case M_DIVU: - return OP_M_DIVU; - break; - case M_REM: - return OP_M_REM; - break; - case M_REMU: - return OP_M_REMU; - break; - [[unlikely]] default: - return OP_M_ERROR; - break; - } - - return OP_M_ERROR; - } - - bool M_extension::Exec_M_MUL() const { - int rd, rs1, rs2; - std::int32_t multiplier, multiplicand; - std::int64_t result; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - multiplier = static_cast(regs->getValue(rs1)); - multiplicand = static_cast(regs->getValue(rs2)); - - result = static_cast(multiplier * multiplicand); - result = result & 0x00000000FFFFFFFF; - regs->setValue(rd, static_cast(result)); - - logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_MULH() const { - int rd, rs1, rs2; - std::int32_t multiplier, multiplicand; - std::int64_t result; - std::int32_t ret_value; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - multiplier = static_cast(regs->getValue(rs1)); - multiplicand = static_cast(regs->getValue(rs2)); - - result = static_cast(multiplier) * static_cast(multiplicand); - - ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); - regs->setValue(rd, ret_value); - - logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_MULHSU() const { - int rd, rs1, rs2; - std::int32_t multiplier; - std::uint32_t multiplicand; - std::int64_t result; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - multiplier = static_cast(regs->getValue(rs1)); - multiplicand = regs->getValue(rs2); - - result = static_cast(multiplier * static_cast(multiplicand)); - result = (result >> 32) & 0x00000000FFFFFFFF; - regs->setValue(rd, static_cast(result)); - - logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_MULHU() const { - int rd, rs1, rs2; - std::uint32_t multiplier, multiplicand; - std::uint64_t result; - std::int32_t ret_value; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - multiplier = static_cast(regs->getValue(rs1)); - multiplicand = static_cast(regs->getValue(rs2)); - - result = static_cast(multiplier) * static_cast(multiplicand); - ret_value = static_cast((result >> 32) & 0x00000000FFFFFFFF); - regs->setValue(rd, ret_value); - - logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_DIV() const { - int rd, rs1, rs2; - std::int32_t divisor, dividend; - std::int64_t result; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - dividend = static_cast(regs->getValue(rs1)); - divisor = static_cast(regs->getValue(rs2)); - - if (divisor == 0) { - result = -1; - } else if ((divisor == -1) && (dividend == static_cast(0x80000000))) { - result = 0x0000000080000000; - } else { - result = dividend / divisor; - result = result & 0x00000000FFFFFFFF; - } - - regs->setValue(rd, static_cast(result)); - - logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_DIVU() const { - int rd, rs1, rs2; - std::uint32_t divisor, dividend; - std::uint64_t result; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - dividend = regs->getValue(rs1); - divisor = regs->getValue(rs2); - - if (divisor == 0) { - result = -1; - } else { - result = dividend / divisor; - result = result & 0x00000000FFFFFFFF; - } - - regs->setValue(rd, static_cast(result)); - - logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_REM() const { - int rd, rs1, rs2; - std::int32_t divisor, dividend; - std::int32_t result; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - dividend = static_cast(regs->getValue(rs1)); - divisor = static_cast(regs->getValue(rs2)); - - if (divisor == 0) { - result = dividend; - } else if ((divisor == -1) && (dividend == static_cast(0x80000000))) { - result = 0; - } else { - result = dividend % divisor; - } - - regs->setValue(rd, result); - - logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::Exec_M_REMU() const { - int rd, rs1, rs2; - std::uint32_t divisor, dividend; - std::uint32_t result; - - rd = get_rd(); - rs1 = get_rs1(); - rs2 = get_rs2(); - - dividend = static_cast(regs->getValue(rs1)); - divisor = static_cast(regs->getValue(rs2)); - - if (divisor == 0) { - result = dividend; - } else { - result = dividend % divisor; - } - - regs->setValue(rd, static_cast(result)); - - logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), - regs->getPC(), - rs1, rs2, rd, result); - - return true; - } - - bool M_extension::process_instruction(Instruction &inst) { - bool PC_not_affected = true; - - setInstr(inst.getInstr()); - - switch (decode()) { - case OP_M_MUL: - Exec_M_MUL(); - break; - case OP_M_MULH: - Exec_M_MULH(); - break; - case OP_M_MULHSU: - Exec_M_MULHSU(); - break; - case OP_M_MULHU: - Exec_M_MULHU(); - break; - case OP_M_DIV: - Exec_M_DIV(); - break; - case OP_M_DIVU: - Exec_M_DIVU(); - break; - case OP_M_REM: - Exec_M_REM(); - break; - case OP_M_REMU: - Exec_M_REMU(); - break; - [[unlikely]] default: - std::cout << "M instruction not implemented yet" << "\n"; - inst.dump(); - //NOP(inst); - sc_core::sc_stop(); - break; - } - - return PC_not_affected; - } - -} \ No newline at end of file