diff --git a/inc/CPU.h b/inc/CPU.h index d95cb9f..5843109 100644 --- a/inc/CPU.h +++ b/inc/CPU.h @@ -15,10 +15,11 @@ #include "tlm_utils/simple_initiator_socket.h" #include "memory.h" -#include "Instruction.h" #include "Execute.h" #include "Registers.h" #include "Log.h" +#include "Instruction.h" +#include "C_Instruction.h" using namespace sc_core; using namespace sc_dt; @@ -52,10 +53,11 @@ private: * @param inst instruction to execute * @return true if PC is affected by instruction */ - bool process_default_instruction(Instruction &inst); + bool process_base_instruction(Instruction &inst); + + bool process_c_instruction(Instruction &inst); - void CPU_thread(void); }; diff --git a/inc/Execute.h b/inc/Execute.h index bf2a7a2..53de892 100644 --- a/inc/Execute.h +++ b/inc/Execute.h @@ -16,6 +16,7 @@ #include "memory.h" #include "Instruction.h" +#include "C_Instruction.h" #include "Registers.h" #include "Log.h" @@ -43,7 +44,7 @@ public: void LUI(Instruction &inst); void AUIPC(Instruction &inst); - void JAL(Instruction &inst); + void JAL(Instruction &inst, bool c_extension = false, int m_rd = 1); void JALR(Instruction &inst); void BEQ(Instruction &inst); @@ -55,7 +56,7 @@ public: void LB(Instruction &inst); void LH(Instruction &inst); - void LW(Instruction &inst); + void LW(Instruction &inst, bool c_extension = false); void LBU(Instruction &inst); void LHU(Instruction &inst); @@ -65,7 +66,7 @@ public: void SBU(Instruction &inst); void SHU(Instruction &inst); - void ADDI(Instruction &inst); + void ADDI(Instruction &inst, bool c_extension = false); void SLTI(Instruction &inst); void SLTIU(Instruction &inst); void XORI(Instruction &inst); @@ -87,6 +88,9 @@ public: void OR(Instruction &inst); void AND(Instruction &inst); + void FENCE(Instruction &inst); + void ECALL(Instruction &inst); + void CSRRW(Instruction &inst); void CSRRS(Instruction &inst); void CSRRC(Instruction &inst); @@ -94,6 +98,19 @@ public: void CSRRSI(Instruction &inst); void CSRRCI(Instruction &inst); + void MRET(Instruction &inst); + + /* C Extensions */ + void C_JR(Instruction &inst); + void C_MV(Instruction &inst); + void C_LWSP(Instruction &inst); + void C_ADDI4SPN(Instruction &inst); + void C_ADDI16SP(Instruction &inst); + void C_SWSP(Instruction &inst); + void C_BEQZ(Instruction &inst); + void C_BNEZ(Instruction &inst); + void C_LI(Instruction &inst); + void NOP(Instruction &inst); private: diff --git a/inc/Instruction.h b/inc/Instruction.h index 9c22365..897b52e 100644 --- a/inc/Instruction.h +++ b/inc/Instruction.h @@ -14,6 +14,23 @@ using namespace sc_core; using namespace sc_dt; using namespace std; +typedef enum { + BASE_EXTENSION, + M_EXTENSION, + A_EXTENSION, + F_EXTENSION, + D_EXTENSION, + Q_EXTENSION, + L_EXTENSION, + C_EXTENSION, + R_EXTENSION, + J_EXTENSION, + P_EXTENSION, + V_EXTENSION, + N_EXTENSION, + UNKNOWN_EXTENSION +} extension_t; + typedef enum { OP_LUI, OP_AUIPC, @@ -58,6 +75,21 @@ OP_SRA, OP_OR, OP_AND, +OP_FENCE, +OP_ECALL, +OP_EBREAK, + +OP_CSRRW, +OP_CSRRS, +OP_CSRRC, +OP_CSRRWI, +OP_CSRRSI, +OP_CSRRCI, + +OP_URET, +OP_SRET, +OP_MRET, + OP_ERROR } opCodes; @@ -116,6 +148,21 @@ typedef enum { 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, + ECALL_F3= 0b000, + CSRRW = 0b001, + CSRRS = 0b010, + CSRRC = 0b011, + CSRRWI = 0b101, + CSRRSI = 0b110, + CSRRCI = 0b111, } Codes; /** @@ -311,7 +358,11 @@ public: } inline int32_t get_csr() { - return get_imm_I(); + int32_t aux = 0; + + aux = m_instr.range(31, 20); + + return aux; } /** @@ -320,6 +371,18 @@ public: */ opCodes decode(); + /** + * @brief returns what instruction extension + * @return extension + */ + extension_t check_extension(); + + + uint32_t getInstr() { + return m_instr; + } + + inline void dump() { cout << hex << "0x" << m_instr << dec << endl; } diff --git a/inc/Memory.h b/inc/Memory.h index 7245a61..9f9f5b9 100644 --- a/inc/Memory.h +++ b/inc/Memory.h @@ -48,14 +48,12 @@ public: // ********************************************* // TLM-2 forward DMI method // ********************************************* - virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data); // ********************************************* // TLM-2 debug transport method // ********************************************* - virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans); private: diff --git a/src/CPU.cpp b/src/CPU.cpp index 9b9192e..7cd2dc2 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -1,4 +1,3 @@ - #include "CPU.h" SC_HAS_PROCESS(CPU); @@ -22,7 +21,69 @@ CPU::~CPU() { cout << "*********************************************" << endl; } -bool CPU::process_default_instruction(Instruction &inst) { +bool CPU::process_c_instruction(Instruction &inst) { + bool PC_not_affected = true; + + C_Instruction c_inst(inst.getInstr()); + + switch(c_inst.decode()) { + case OP_C_ADDI4SPN: + exec->C_ADDI4SPN(inst); + break; + case OP_C_LW: + exec->LW(inst, true); + break; + case OP_C_ADDI: + exec->ADDI(inst, true); + break; + case OP_C_JAL: + exec->JAL(inst, true, 1); + PC_not_affected = false; + break; + case OP_C_J: + exec->JAL(inst, true, 0); + PC_not_affected = false; + break; + case OP_C_LI: + exec->C_LI(inst); + break; + case OP_C_LWSP: + exec->C_LWSP(inst); + break; + case OP_C_JR: + exec->C_JR(inst); + PC_not_affected = false; + break; + case OP_C_MV: + exec->C_MV(inst); + break; + case OP_C_SWSP: + exec->C_SWSP(inst); + break; + case OP_C_ADDI16SP: + exec->C_ADDI16SP(inst); + break; + case OP_C_BEQZ: + exec->C_BEQZ(inst); + PC_not_affected = false; + break; + case OP_C_BNEZ: + exec->C_BNEZ(inst); + PC_not_affected = false; + break; + default: + std::cout << "C instruction not implemented yet" << endl; + inst.dump(); + exec->NOP(inst); + //sc_stop(); + break; + + } + + return PC_not_affected; +} + +bool CPU::process_base_instruction(Instruction &inst) { bool PC_not_affected = true; switch(inst.decode()) { @@ -156,7 +217,40 @@ bool CPU::process_default_instruction(Instruction &inst) { exec->CSRRC(inst); break; #endif + case OP_FENCE: + exec->FENCE(inst); + break; + case OP_ECALL: + exec->ECALL(inst); + break; + case OP_CSRRW: + exec->CSRRW(inst); + break; + case OP_CSRRS: + exec->CSRRS(inst); + break; + case OP_CSRRC: + exec->CSRRC(inst); + break; + case OP_CSRRWI: + exec->CSRRWI(inst); + break; + case OP_CSRRSI: + exec->CSRRSI(inst); + break; + case OP_CSRRCI: + exec->CSRRCI(inst); + break; + + case OP_MRET: + exec->MRET(inst); + PC_not_affected = false; + break; default: + std::cout << "Wrong instruction" << endl; + inst.dump(); + exec->NOP(inst); + //sc_stop(); break; } @@ -173,6 +267,7 @@ void CPU::CPU_thread(void) { uint32_t INSTR; sc_time delay = SC_ZERO_TIME; bool PC_not_affected; + bool incPCby2 = false; trans->set_command( tlm::TLM_READ_COMMAND ); trans->set_data_ptr( reinterpret_cast(&INSTR) ); @@ -197,14 +292,26 @@ void CPU::CPU_thread(void) { log->SC_log(Log::INFO) << "PC: " << hex << register_bank->getPC() << dec << endl; - Instruction inst(INSTR); /* check what type of instruction is and execute it */ + switch(inst.check_extension()) { + case BASE_EXTENSION: + PC_not_affected = process_base_instruction(inst); + incPCby2 = false; + break; + case C_EXTENSION: + PC_not_affected = process_c_instruction(inst); + incPCby2 = true; + break; + default: + std::cout << "Extension not implemented yet" << std::endl; + inst.dump(); + exec->NOP(inst); + } - PC_not_affected = process_default_instruction(inst); // default: @@ -215,7 +322,7 @@ void CPU::CPU_thread(void) { perf->instructionsInc(); if (PC_not_affected == true) { - register_bank->incPC(); + register_bank->incPC(incPCby2); } } // while(1) } // CPU_thread diff --git a/src/Execute.cpp b/src/Execute.cpp index a949e2c..4b6f8db 100644 --- a/src/Execute.cpp +++ b/src/Execute.cpp @@ -30,28 +30,39 @@ void Execute::AUIPC(Instruction &inst) { imm = inst.get_imm_U() << 12; new_pc = regs->getPC() + imm; - regs->setPC(new_pc); regs->setValue(rd, new_pc); log->SC_log(Log::INFO) << "AUIPC x" << rd << " + PC -> PC (" << new_pc << ")" << endl; } -void Execute::JAL(Instruction &inst) { +void Execute::JAL(Instruction &inst, bool c_extension, int m_rd) { int32_t mem_addr = 0; int rd; int new_pc, old_pc; - rd = inst.get_rd(); - mem_addr = inst.get_imm_J(); + if (c_extension == false) { + rd = inst.get_rd(); + mem_addr = inst.get_imm_J(); + old_pc = regs->getPC(); + new_pc = old_pc + mem_addr; - old_pc = regs->getPC(); + regs->setPC(new_pc); + old_pc = old_pc + 4; + regs->setValue(rd, old_pc); + } else { + C_Instruction c_inst(inst.getInstr()); - new_pc = old_pc + mem_addr; - regs->setPC(new_pc); + rd = m_rd; + mem_addr = c_inst.get_imm_J(); + old_pc = regs->getPC(); - old_pc = old_pc + 4; - regs->setValue(rd, old_pc); + new_pc = old_pc + mem_addr; + regs->setPC(new_pc); + + old_pc = old_pc + 2; + regs->setValue(rd, old_pc); + } log->SC_log(Log::INFO) << dec << "JAL: x" << rd << " <- 0x" << hex << old_pc << dec << " PC + " << mem_addr << " -> PC (0x" @@ -226,21 +237,29 @@ void Execute::LH(Instruction &inst) { << hex < x" << rd << endl; } -void Execute::LW(Instruction &inst) { +void Execute::LW(Instruction &inst, bool c_extension) { uint32_t mem_addr = 0; int rd, rs1; int32_t imm = 0; uint32_t data; - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); + if (c_extension == false) { + rd = inst.get_rd(); + rs1 = inst.get_rs1(); + imm = inst.get_imm_I(); + } else { + C_Instruction c_inst(inst.getInstr()); + + rd = c_inst.get_rdp(); + rs1 = c_inst.get_rs1p(); + imm = c_inst.get_imm_L(); + } mem_addr = imm + regs->getValue(rs1); data = readDataMem(mem_addr, 4); regs->setValue(rd, data); - log->SC_log(Log::INFO) << "LW: x" << rs1 << " + " << imm << " (@0x" + log->SC_log(Log::INFO) << "C.LW: x" << rs1 << " + " << imm << " (@0x" << hex < x" << rd << endl; } @@ -338,14 +357,22 @@ void Execute::SW(Instruction &inst) { << " (@0x" << hex << mem_addr << dec << ")" << endl; } -void Execute::ADDI(Instruction &inst) { +void Execute::ADDI(Instruction &inst, bool c_extension) { int rd, rs1; int32_t imm = 0; int32_t calc; - rd = inst.get_rd(); - rs1 = inst.get_rs1(); - imm = inst.get_imm_I(); + if (c_extension == false) { + rd = inst.get_rd(); + rs1 = inst.get_rs1(); + imm = inst.get_imm_I(); + } else { + C_Instruction c_inst(inst.getInstr()); + + rd = c_inst.get_rd(); + rs1 = rd; + imm = c_inst.get_imm_I(); + } calc = regs->getValue(rs1) + imm; regs->setValue(rd, calc); @@ -658,6 +685,20 @@ void Execute::AND(Instruction &inst) { << "-> x" << rd << endl; } +void Execute::FENCE(Instruction &inst) { + log->SC_log(Log::INFO) << "FENCE" << endl; +} + +void Execute::ECALL(Instruction &inst) { + + log->SC_log(Log::INFO) << "ECALL" << endl; + std::cout << "ECALL Instruction called, stopping simulation" << endl; + regs->dump(); + cout << "Simulation time " << sc_time_stamp() << endl; + perf->dump(); + + SC_REPORT_ERROR("Execute", "ECALL"); +} void Execute::CSRRW(Instruction &inst) { int rd, rs1; int csr; @@ -667,13 +708,11 @@ void Execute::CSRRW(Instruction &inst) { rs1 = inst.get_rs1(); csr = inst.get_csr(); - if (rd == 0) { - return; - } - /* These operations must be atomical */ - aux = regs->getCSR(csr); - regs->setValue(rd, aux); + if (rd != 0) { + aux = regs->getCSR(csr); + regs->setValue(rd, aux); + } aux = regs->getValue(rs1); regs->setCSR(csr, aux); @@ -731,6 +770,267 @@ void Execute::CSRRC(Instruction &inst) { << ". x" << rs1 << " & CSR #" << csr << endl; } +void Execute::CSRRWI(Instruction &inst) { + int rd, rs1; + int csr; + uint32_t aux; + + rd = inst.get_rd(); + rs1 = inst.get_rs1(); + csr = inst.get_csr(); + + + /* These operations must be atomical */ + if (rd != 0) { + aux = regs->getCSR(csr); + regs->setValue(rd, aux); + } + aux = rs1; + regs->setCSR(csr, aux); + + log->SC_log(Log::INFO) << "CSRRWI: CSR #" << csr << " -> x" << rd + << ". x" << rs1 << "-> CSR #" << csr << endl; +} + +void Execute::CSRRSI(Instruction &inst) { + int rd, rs1; + int csr; + uint32_t bitmask, aux; + + rd = inst.get_rd(); + rs1 = inst.get_rs1(); + csr = inst.get_csr(); + + if (rs1 == 0) { + return; + } + + /* These operations must be atomical */ + aux = regs->getCSR(csr); + regs->setValue(rd, aux); + + bitmask = rs1; + aux = aux | bitmask; + regs->setCSR(csr, aux); + + log->SC_log(Log::INFO) << "CSRRSI: CSR #" << csr << " -> x" << rd + << ". x" << rs1 << " & CSR #" << csr << endl; +} + +void Execute::CSRRCI(Instruction &inst) { + int rd, rs1; + int csr; + uint32_t bitmask, aux; + + rd = inst.get_rd(); + rs1 = inst.get_rs1(); + csr = inst.get_csr(); + + if (rs1 == 0) { + return; + } + + /* These operations must be atomical */ + aux = regs->getCSR(csr); + regs->setValue(rd, aux); + + bitmask = rs1; + aux = aux & ~bitmask; + regs->setCSR(csr, aux); + + log->SC_log(Log::INFO) << "CSRRCI: CSR #" << csr << " -> x" << rd + << ". x" << rs1 << " & CSR #" << csr << endl; +} + +void Execute::MRET(Instruction &inst) { + uint32_t new_pc = 0; + + new_pc = regs->getCSR(0x341); + regs->setPC(new_pc); + + log->SC_log(Log::INFO) << "MRET: PC <- 0x" << hex << new_pc << endl; +} + +void Execute::C_JR(Instruction &inst) { + uint32_t mem_addr = 0; + int rd, rs1; + int new_pc, old_pc; + + C_Instruction c_inst(inst.getInstr()); + + rd = 0; + rs1 = c_inst.get_rs1(); + mem_addr = 0; + + std::cout << "rs1 :" << rs1 << std::endl; + old_pc = regs->getPC(); + regs->setValue(rd, old_pc + 4); + + + new_pc = (regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE; + regs->setPC(new_pc); + + log->SC_log(Log::INFO) << "JR: x" << dec << rd << " <- 0x" << hex << old_pc + 4 + << " PC <- 0x" << hex << new_pc << endl; +} + +void Execute::C_MV(Instruction &inst) { + int rd, rs1, rs2; + uint32_t calc; + + C_Instruction c_inst(inst.getInstr()); + + rd = c_inst.get_rd(); + rs1 = 0; + rs2 = c_inst.get_rs2(); + + calc = regs->getValue(rs1) + regs->getValue(rs2); + regs->setValue(rd, calc); + + log->SC_log(Log::INFO) << "MV: x" << rs1 << " + x" << rs2 << " -> x" << rd << endl; +} + +void Execute::C_LWSP(Instruction &inst) { + uint32_t mem_addr = 0; + int rd, rs1; + int32_t imm = 0; + uint32_t data; + + C_Instruction c_inst(inst.getInstr()); + + rd = c_inst.get_rd(); + rs1 = c_inst.get_rs1(); + imm = c_inst.get_imm_LWSP(); + + mem_addr = imm + regs->getValue(rs1); + data = readDataMem(mem_addr, 4); + regs->setValue(rd, data); + + log->SC_log(Log::INFO) << "C.LWSP: x" << rs1 << " + " << imm << " (@0x" + << hex < x" << rd << endl; +} + +void Execute::C_ADDI4SPN(Instruction &inst) { + int rd, rs1; + int32_t imm = 0; + int32_t calc; + + C_Instruction c_inst(inst.getInstr()); + + rd = c_inst.get_rdp(); + rs1 = 2; + imm = c_inst.get_imm_ADDI4SPN(); + + calc = regs->getValue(rs1) + imm; + regs->setValue(rd, calc); + + log->SC_log(Log::INFO) << dec << "ADDI4SPN: x" << rs1 << " + " << imm << " -> x" << rd << endl; +} + +void Execute::C_ADDI16SP(Instruction &inst) { + // addi x2, x2, nzimm[9:4] + int rd, rs1; + int32_t imm = 0; + int32_t calc; + + C_Instruction c_inst(inst.getInstr()); + + rd = 2; + rs1 = 2; + imm = c_inst.get_imm_ADDI16SP(); + + + calc = regs->getValue(rs1) + imm; + regs->setValue(rd, calc); + + log->SC_log(Log::INFO) << dec << "ADDI16SP: x" << rs1 << " + " << imm << " -> x" << rd << endl; +} + +void Execute::C_SWSP(Instruction &inst) { + // sw rs2, offset(x2) + uint32_t mem_addr = 0; + int rs1, rs2; + int32_t imm = 0; + uint32_t data; + + C_Instruction c_inst(inst.getInstr()); + + rs1 = 2; + rs2 = 2; + imm = c_inst.get_imm_CSS(); + + mem_addr = imm + regs->getValue(rs1); + data = regs->getValue(rs2); + + writeDataMem(mem_addr, data, 4); + + log->SC_log(Log::INFO) << "SWSP: x" << dec << rs2 << "(0x" << hex << data + << ") -> x" << dec << rs1 << " + " << imm + << " (@0x" << hex << mem_addr << dec << ")" << endl; + +} + +void Execute::C_BEQZ(Instruction &inst) { + int rs1; + int new_pc = 0; + uint32_t val1; + C_Instruction c_inst(inst.getInstr()); + + rs1 = c_inst.get_rs1p(); + val1 = regs->getValue(rs1); + + if (val1 == 0) { + new_pc = regs->getPC() + c_inst.get_imm_CB(); + regs->setPC(new_pc); + } else { + regs->incPC(true); //PC <- PC +2 + } + + log->SC_log(Log::INFO) << "C.BEQZ: x" << rs1 << "(" << val1 + << ") == 0? -> PC (" << new_pc << ")" << endl; +} + +void Execute::C_BNEZ(Instruction &inst) { + int rs1; + int new_pc = 0; + uint32_t val1; + C_Instruction c_inst(inst.getInstr()); + + rs1 = c_inst.get_rs1p(); + val1 = regs->getValue(rs1); + + if (val1 != 0) { + new_pc = regs->getPC() + c_inst.get_imm_CB(); + regs->setPC(new_pc); + } else { + regs->incPC(true); //PC <- PC +2 + } + + log->SC_log(Log::INFO) << "C.BNEZ: x" << rs1 << "(" << val1 + << ") == 0? -> PC (" << new_pc << ")" << endl; +} + +void Execute::C_LI(Instruction &inst) { + + int rd, rs1; + int32_t imm = 0; + int32_t calc; + + C_Instruction c_inst(inst.getInstr()); + + rd = c_inst.get_rd(); + rs1 = 0; + imm = c_inst.get_imm_ADDI(); + + calc = regs->getValue(rs1) + imm; + regs->setValue(rd, calc); + + log->SC_log(Log::INFO) << dec << "LI: x" << rs1 << " + " << imm << " -> x" << rd << endl; + +} + + + void Execute::NOP(Instruction &inst) { cout << endl; regs->dump(); diff --git a/src/Instruction.cpp b/src/Instruction.cpp index e19e130..503eec8 100644 --- a/src/Instruction.cpp +++ b/src/Instruction.cpp @@ -112,8 +112,64 @@ opCodes Instruction::decode() { return OP_AND; } } /* ADD */ - return OP_ERROR; + 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; + } + 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; + } + } default: return OP_ERROR; } } + + +extension_t Instruction::check_extension() { + if (m_instr.range(1,0) == 0b11) { + return BASE_EXTENSION; + } else if (m_instr.range(1,0) == 0b00) { + return C_EXTENSION; + } else if (m_instr.range(1,0) == 0b01) { + return C_EXTENSION; + } else if (m_instr.range(1,0) == 0b10) { + return C_EXTENSION; + } else if (m_instr.range(6,0) == 0b0110011) { + return M_EXTENSION; + } else if (m_instr.range(6,0) == 0b0101111) { + return A_EXTENSION; + } else { + return UNKNOWN_EXTENSION; + } +} diff --git a/src/Registers.cpp b/src/Registers.cpp index caceb43..94391f5 100644 --- a/src/Registers.cpp +++ b/src/Registers.cpp @@ -2,7 +2,8 @@ Registers::Registers() { - memset(register_bank, 0, sizeof(int32_t)*32); // 32 registers of 32 bits each + memset(register_bank, 0, sizeof(uint32_t)*32); // 32 registers of 32 bits each + memset(CSR, 0, sizeof(uint32_t)*4096); perf = Performance::getInstance(); register_bank[sp] = 1024-1; // SP points to end of memory