Added instructions to pass riscv-tests

This commit is contained in:
mariusmonton 2018-10-15 13:51:41 +02:00
parent f17b3b75d5
commit aa526943b9
8 changed files with 584 additions and 40 deletions

View File

@ -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);
};

View File

@ -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:

View File

@ -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;
}

View File

@ -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:

View File

@ -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<unsigned char*>(&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

View File

@ -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 <<mem_addr << dec << ") -> 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 <<mem_addr << dec << ") -> 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 <<mem_addr << dec << ") -> 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();

View File

@ -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;
}
}

View File

@ -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