#include "CPU.h" SC_HAS_PROCESS(CPU); CPU::CPU(sc_module_name name, uint32_t PC): sc_module(name) , instr_bus("instr_bus") { register_bank = new Registers(); exec = new Execute("Execute", register_bank); perf = Performance::getInstance(); log = Log::getInstance(); register_bank->setPC(PC); SC_THREAD(CPU_thread); } CPU::~CPU() { cout << "*********************************************" << endl; register_bank->dump(); cout << "end time: " << sc_time_stamp() << endl; perf->dump(); cout << "*********************************************" << endl; } bool CPU::cpu_process_IRQ() { uint32_t csr_temp; uint32_t new_pc, old_pc; bool ret_value = false; if (interrupt == true){ csr_temp = register_bank->getCSR(CSR_MIP); if ( (csr_temp & (1 << 11) ) == 0 ) { csr_temp |= (1 << 11); // MEIP bit in MIP register (11th bit) register_bank->setCSR(CSR_MIP, csr_temp); // cout << "time: " << sc_time_stamp() << ". CPU: interrupt" << endl; log->SC_log(Log::INFO) << "Interrupt!" << endl; /* updated MEPC register */ old_pc = register_bank->getPC(); register_bank->setCSR(CSR_MEPC, old_pc); log->SC_log(Log::INFO) << "Old PC Value 0x" << hex << old_pc << endl; /* update MCAUSE register */ register_bank->setCSR(CSR_MCAUSE, 0x8000000); /* set new PC address */ new_pc = register_bank->getCSR(CSR_MTVEC); new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0 log->SC_log(Log::DEBUG) << "NEW PC Value 0x" << hex << new_pc << endl; register_bank->setPC(new_pc); ret_value = true; } } else { csr_temp = register_bank->getCSR(CSR_MIP); csr_temp &= ~(1 << 11); register_bank->setCSR(CSR_MIP, csr_temp); } return ret_value; } 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: PC_not_affected = exec->C_ADDI4SPN(inst); break; case OP_C_LW: exec->LW(inst, true); break; case OP_C_SW: exec->SW(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_SLLI: exec->C_SLLI(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_JALR: exec->JALR(inst, true); PC_not_affected = false; break; case OP_C_ADD: exec->C_ADD(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; case OP_C_SRLI: exec->C_SRLI(inst); break; case OP_C_SRAI: exec->C_SRAI(inst); break; case OP_C_ANDI: exec->C_ANDI(inst); break; case OP_C_SUB: exec->C_SUB(inst); break; case OP_C_XOR: exec->C_XOR(inst); break; case OP_C_OR: exec->C_OR(inst); break; case OP_C_AND: exec->C_AND(inst); 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_m_instruction(Instruction &inst) { bool PC_not_affected = true; M_Instruction m_inst(inst.getInstr()); switch(m_inst.decode()) { case OP_M_MUL: exec->M_MUL(inst); break; case OP_M_MULH: exec->M_MULH(inst); break; case OP_M_MULHSU: exec->M_MULHSU(inst); break; case OP_M_MULHU: exec->M_MULHU(inst); break; case OP_M_DIV: exec->M_DIV(inst); break; case OP_M_DIVU: exec->M_DIVU(inst); break; case OP_M_REM: exec->M_REM(inst); break; case OP_M_REMU: exec->M_REMU(inst); break; default: std::cout << "M instruction not implemented yet" << endl; inst.dump(); exec->NOP(inst); break; } return PC_not_affected; } bool CPU::process_a_instruction(Instruction inst) { bool PC_not_affected = true; A_Instruction a_inst(inst.getInstr()); switch(a_inst.decode()) { case OP_A_LR: exec->A_LR(inst); break; case OP_A_SC: exec->A_SC(inst); break; case OP_A_AMOSWAP: exec->A_AMOSWAP(inst); break; case OP_A_AMOADD: exec->A_AMOADD(inst); break; case OP_A_AMOXOR: exec->A_AMOXOR(inst); break; case OP_A_AMOAND: exec->A_AMOAND(inst); break; case OP_A_AMOOR: exec->A_AMOOR(inst); break; case OP_A_AMOMIN: exec->A_AMOMIN(inst); break; case OP_A_AMOMAX: exec->A_AMOMAX(inst); break; case OP_A_AMOMINU: exec->A_AMOMINU(inst); break; case OP_A_AMOMAXU: exec->A_AMOMAXU(inst); break; default: std::cout << "A instruction not implemented yet" << endl; inst.dump(); exec->NOP(inst); break; } return PC_not_affected; } bool CPU::process_base_instruction(Instruction &inst) { bool PC_not_affected = true; switch(inst.decode()) { case OP_LUI: exec->LUI(inst); break; case OP_AUIPC: exec->AUIPC(inst); break; case OP_JAL: exec->JAL(inst); PC_not_affected = false; break; case OP_JALR: exec->JALR(inst); PC_not_affected = false; break; case OP_BEQ: exec->BEQ(inst); PC_not_affected = false; break; case OP_BNE: exec->BNE(inst); PC_not_affected = false; break; case OP_BLT: exec->BLT(inst); PC_not_affected = false; break; case OP_BGE: exec->BGE(inst); PC_not_affected = false; break; case OP_BLTU: exec->BLTU(inst); PC_not_affected = false; break; case OP_BGEU: exec->BGEU(inst); PC_not_affected = false; break; case OP_LB: exec->LB(inst); break; case OP_LH: exec->LH(inst); break; case OP_LW: exec->LW(inst); break; case OP_LBU: exec->LBU(inst); break; case OP_LHU: exec->LHU(inst); break; case OP_SB: exec->SB(inst); break; case OP_SH: exec->SH(inst); break; case OP_SW: exec->SW(inst); break; case OP_ADDI: exec->ADDI(inst); break; case OP_SLTI: exec->SLTI(inst); break; case OP_SLTIU: exec->SLTIU(inst); break; case OP_XORI: exec->XORI(inst); break; case OP_ORI: exec->ORI(inst); break; case OP_ANDI: exec->ANDI(inst); break; case OP_SLLI: PC_not_affected = exec->SLLI(inst); break; case OP_SRLI: exec->SRLI(inst); break; case OP_SRAI: exec->SRAI(inst); break; case OP_ADD: exec->ADD(inst); break; case OP_SUB: exec->SUB(inst); break; case OP_SLL: exec->SLL(inst); break; case OP_SLT: exec->SLT(inst); break; case OP_SLTU: exec->SLTU(inst); break; case OP_XOR: exec->XOR(inst); break; case OP_SRL: exec->SRL(inst); break; case OP_SRA: exec->SRA(inst); break; case OP_OR: exec->OR(inst); break; case OP_AND: exec->AND(inst); break; case OP_FENCE: exec->FENCE(inst); break; case OP_ECALL: exec->ECALL(inst); break; case OP_EBREAK: exec->EBREAK(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; case OP_SRET: exec->SRET(inst); PC_not_affected = false; break; case OP_WFI: exec->WFI(inst); break; case OP_SFENCE: exec->SFENCE(inst); break; default: std::cout << "Wrong instruction" << endl; inst.dump(); exec->NOP(inst); //sc_stop(); break; } return PC_not_affected; } /** * main thread for CPU simulation * @brief CPU mai thread */ void CPU::CPU_thread(void) { tlm::tlm_generic_payload* trans = new tlm::tlm_generic_payload; uint32_t INSTR; sc_time delay = SC_ZERO_TIME; bool PC_not_affected = false; bool incPCby2 = false; trans->set_command( tlm::TLM_READ_COMMAND ); trans->set_data_ptr( reinterpret_cast(&INSTR) ); trans->set_data_length( 4 ); trans->set_streaming_width( 4 ); // = data_length to indicate no streaming trans->set_byte_enable_ptr( 0 ); // 0 indicates unused trans->set_dmi_allowed( false ); // Mandatory initial value trans->set_response_status( tlm::TLM_INCOMPLETE_RESPONSE ); //register_bank->dump(); while(1) { /* Get new PC value */ //cout << "CPU: PC 0x" << hex << (uint32_t) register_bank->getPC() << endl; trans->set_address( register_bank->getPC() ); instr_bus->b_transport( *trans, delay); perf->codeMemoryRead(); if ( trans->is_response_error() ) { SC_REPORT_ERROR("CPU base", "Read memory"); } else { log->SC_log(Log::INFO) << "PC: 0x" << hex << register_bank->getPC() << ". "; 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; case M_EXTENSION: PC_not_affected = process_m_instruction(inst); incPCby2 = false; break; case A_EXTENSION: PC_not_affected = process_a_instruction(inst); incPCby2 = false; break; default: std::cout << "Extension not implemented yet" << std::endl; inst.dump(); exec->NOP(inst); } // switch (inst.check_extension()) } perf->instructionsInc(); if (PC_not_affected == true) { register_bank->incPC(incPCby2); } /* Process IRQ (if any) */ cpu_process_IRQ(); /* Fixed instruction time to 10 ns (i.e. 100 MHz)*/ sc_core::wait(10, SC_NS); } // while(1) } // CPU_thread