Merge branch 'C_extension'

Functional (almost) execution of C extensions
This commit is contained in:
mariusmonton 2018-11-11 11:12:22 +01:00
commit 0f56cb0288
13 changed files with 1679 additions and 392 deletions

View File

@ -15,10 +15,11 @@
#include "tlm_utils/simple_initiator_socket.h" #include "tlm_utils/simple_initiator_socket.h"
#include "memory.h" #include "memory.h"
#include "Instruction.h"
#include "Execute.h" #include "Execute.h"
#include "Registers.h" #include "Registers.h"
#include "Log.h" #include "Log.h"
#include "Instruction.h"
#include "C_Instruction.h"
using namespace sc_core; using namespace sc_core;
using namespace sc_dt; using namespace sc_dt;
@ -47,6 +48,16 @@ private:
Performance *perf; Performance *perf;
Log *log; Log *log;
/**
* @brief Executes default ISA instruction
* @param inst instruction to execute
* @return true if PC is affected by instruction
*/
bool process_base_instruction(Instruction &inst);
bool process_c_instruction(Instruction &inst);
void CPU_thread(void); void CPU_thread(void);
}; };

382
inc/C_Instruction.h Normal file
View File

@ -0,0 +1,382 @@
/*!
\file Instruction.h
\brief Decode instructions part of the RISC-V
\author Màrius Montón
\date August 2018
*/
#ifndef C_INSTRUCTION__H
#define C_INSTRUCTION__H
#include "systemc"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
typedef enum {
OP_C_ADDI4SPN,
OP_C_FLD,
OP_C_LW,
OP_C_FLW,
OP_C_FSD,
OP_C_SW,
OP_C_FSW,
OP_C_NOP,
OP_C_ADDI,
OP_C_JAL,
OP_C_LI,
OP_C_ADDI16SP,
OP_C_LUI,
OP_C_SRLI,
OP_C_SRAI,
OP_C_ANDI,
OP_C_SUB,
OP_C_XOR,
OP_C_OR,
OP_C_AND,
OP_C_J,
OP_C_BEQZ,
OP_C_BNEZ,
OP_C_SLLI,
OP_C_FLDSP,
OP_C_LWSP,
OP_C_FLWSP,
OP_C_JR,
OP_C_MV,
OP_C_EBREAK,
OP_C_JALR,
OP_C_ADD,
OP_C_FSDSP,
OP_C_SWSP,
OP_C_FSWSP,
OP_C_ERROR
} op_C_Codes;
typedef enum {
C_ADDI4SPN = 0b000,
C_FLD = 0b001,
C_LW = 0b010,
C_FLW = 0b011,
C_FSD = 0b101,
C_SW = 0b110,
C_FSW = 0b111,
C_ADDI = 0b000,
C_JAL = 0b001,
C_LI = 0b010,
C_ADDI16SP = 0b011,
C_SRLI = 0b100,
C_J = 0b101,
C_BEQZ = 0b110,
C_BNEZ = 0b111,
C_SLLI = 0b000,
C_FLDSP = 0b001,
C_LWSP = 0b010,
C_FLWSP = 0b011,
C_JR = 0b100,
C_FDSP = 0b101,
C_SWSP = 0b110,
C_FWWSP = 0b111,
} C_Codes;
/**
* @brief Instruction decoding and fields access
*/
class C_Instruction{
public:
/**
* @brief Constructor
* @param instr Instruction to decode
*/
C_Instruction(sc_uint<32> instr);
/**
* @brief Access to opcode field
* @return return opcode field
*/
inline int32_t opcode() {
return m_instr.range(1,0);
}
/**
* @brief Access to rd field
* @return rd field
*/
inline int32_t get_rd() {
return m_instr.range(11, 7);
}
inline void set_rd(int32_t value) {
m_instr.range(11,7) = value;
}
inline int32_t get_rdp() {
return m_instr.range(4, 2);
}
/**
* @brief Access to rs1 field
* @return rs1 field
*/
inline int32_t get_rs1() {
return m_instr.range(11, 7);
}
inline void set_rs1(int32_t value) {
m_instr.range(11,7) = value;
}
inline int32_t get_rs1p() {
return m_instr.range(9, 7);
}
/**
* @brief Access to rs2 field
* @return rs2 field
*/
inline int32_t get_rs2() {
return m_instr.range(6, 2);
}
inline void set_rs2(int32_t value) {
m_instr.range(6,2) = value;
}
inline int32_t get_funct3() {
return m_instr.range(15, 13);
}
inline void set_funct3(int32_t value) {
m_instr.range(15,13) = value;
}
/**
* @brief Access to immediate field for I-type
* @return immediate_I field
*/
inline int32_t get_imm_I() {
int32_t aux = 0;
aux = m_instr.range(31, 20);
/* sign extension (optimize) */
if (m_instr[31] == 1) {
aux |= (0b11111111111111111111) << 12;
}
return aux;
}
inline void set_imm_I(int32_t value) {
m_instr.range(31,20) = value;
}
/**
* @brief Access to immediate field for S-type
* @return immediate_S field
*/
inline int32_t get_imm_S() {
int32_t aux = 0;
aux = m_instr.range(31, 25) << 5;
aux |= m_instr.range(11,7);
if (m_instr[31] == 1) {
aux |= (0b11111111111111111111) << 12;
}
return aux;
}
inline void set_imm_S(int32_t value) {
sc_uint<32> aux = value;
m_instr.range(31,25) = aux.range(11,5);
m_instr.range(11,7) = aux.range(4,0);
}
/**
* @brief Access to immediate field for U-type
* @return immediate_U field
*/
inline int32_t get_imm_U() {
return m_instr.range(31, 12);
}
inline void set_imm_U(int32_t value) {
m_instr.range(31,12) = (value << 12);
}
/**
* @brief Access to immediate field for B-type
* @return immediate_B field
*/
inline int32_t get_imm_B() {
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;
if (m_instr[31] == 1) {
aux |= (0b11111111111111111111) << 12;
}
return aux;
}
inline void set_imm_B(int32_t value) {
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];
}
/**
* @brief Access to immediate field for J-type
* @return immediate_J field
*/
inline int32_t get_imm_J() {
int32_t aux = 0;
aux = m_instr[12] << 11;
aux |= m_instr[11] << 4;
aux |= m_instr[10] << 9;
aux |= m_instr[9] << 8;
aux |= m_instr[8] << 10;
aux |= m_instr[7] << 6;
aux |= m_instr[6] << 7;
aux |= m_instr.range(5,3) << 1;
aux |= m_instr[2] << 5;
if (m_instr[12] == 1) {
aux |= 0b1111 << 12;
}
return aux;
}
inline void set_imm_J(int32_t value) {
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);
}
inline int32_t get_imm_L() {
int32_t aux = 0;
aux = m_instr.range(12,10) << 3;
aux |= m_instr[6] << 2;
aux |= m_instr[5] << 6;
return aux;
}
inline int32_t get_imm_LWSP() {
int32_t aux = 0;
aux = m_instr[12] << 5;
aux |= m_instr.range(6,4) << 2;
aux |= m_instr.range(3,2) << 6;
return aux;
}
inline int32_t get_imm_ADDI() {
int32_t aux = 0;
aux = m_instr[12] << 5;
aux |= m_instr.range(6,2);
if (m_instr[12] == 1) {
aux |= 0b11111111111111111111111111 << 6;
}
return aux;
}
inline int32_t get_imm_ADDI4SPN() {
int32_t aux = 0;
aux = m_instr.range(12,11) << 4;
aux |= m_instr.range(10,7) << 6;
aux |= m_instr[6] << 2;
aux |= m_instr[5] << 3;
return aux;
}
inline int32_t get_imm_ADDI16SP() {
int32_t aux = 0;
aux = m_instr[12] << 9;
aux |= m_instr[6] << 4;
aux |= m_instr[5] << 6;
aux |= m_instr[4] << 8;
aux |= m_instr[3] << 7;
aux |= m_instr[2] << 5;
if (m_instr[12] == 1) {
aux |= 0b1111111111111111111111 << 10;
}
return aux;
}
inline int32_t get_imm_CSS() {
int32_t aux = 0;
aux = m_instr.range(12,9) << 2;
aux |= m_instr.range(8,7) << 6;
return aux;
}
inline int32_t get_imm_CB() {
int32_t aux = 0;
aux = m_instr[12] << 8;
aux |= m_instr[11] << 4;
aux |= m_instr[10] << 3;
aux |= m_instr[6] << 7;
aux |= m_instr[5] << 6;
aux |= m_instr[4] << 2;
aux |= m_instr[3] << 1;
aux |= m_instr[2] << 5;
if (m_instr[12] == 1) {
aux |= 0b11111111111111111111111 << 9;
}
return aux;
}
inline int32_t get_csr() {
return get_imm_I();
}
/**
* @brief Decodes opcode of instruction
* @return opcode of instruction
*/
op_C_Codes decode();
inline void dump() {
cout << hex << "0x" << m_instr << dec << endl;
}
private:
sc_uint<32> m_instr;
};
#endif

View File

@ -16,6 +16,7 @@
#include "memory.h" #include "memory.h"
#include "Instruction.h" #include "Instruction.h"
#include "C_Instruction.h"
#include "Registers.h" #include "Registers.h"
#include "Log.h" #include "Log.h"
@ -43,7 +44,7 @@ public:
void LUI(Instruction &inst); void LUI(Instruction &inst);
void AUIPC(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 JALR(Instruction &inst);
void BEQ(Instruction &inst); void BEQ(Instruction &inst);
@ -55,7 +56,7 @@ public:
void LB(Instruction &inst); void LB(Instruction &inst);
void LH(Instruction &inst); void LH(Instruction &inst);
void LW(Instruction &inst); void LW(Instruction &inst, bool c_extension = false);
void LBU(Instruction &inst); void LBU(Instruction &inst);
void LHU(Instruction &inst); void LHU(Instruction &inst);
@ -65,7 +66,7 @@ public:
void SBU(Instruction &inst); void SBU(Instruction &inst);
void SHU(Instruction &inst); void SHU(Instruction &inst);
void ADDI(Instruction &inst); void ADDI(Instruction &inst, bool c_extension = false);
void SLTI(Instruction &inst); void SLTI(Instruction &inst);
void SLTIU(Instruction &inst); void SLTIU(Instruction &inst);
void XORI(Instruction &inst); void XORI(Instruction &inst);
@ -87,6 +88,9 @@ public:
void OR(Instruction &inst); void OR(Instruction &inst);
void AND(Instruction &inst); void AND(Instruction &inst);
void FENCE(Instruction &inst);
void ECALL(Instruction &inst);
void CSRRW(Instruction &inst); void CSRRW(Instruction &inst);
void CSRRS(Instruction &inst); void CSRRS(Instruction &inst);
void CSRRC(Instruction &inst); void CSRRC(Instruction &inst);
@ -94,6 +98,19 @@ public:
void CSRRSI(Instruction &inst); void CSRRSI(Instruction &inst);
void CSRRCI(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); void NOP(Instruction &inst);
private: private:

View File

@ -14,6 +14,23 @@ using namespace sc_core;
using namespace sc_dt; using namespace sc_dt;
using namespace std; 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 { typedef enum {
OP_LUI, OP_LUI,
OP_AUIPC, OP_AUIPC,
@ -58,6 +75,21 @@ OP_SRA,
OP_OR, OP_OR,
OP_AND, 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 OP_ERROR
} opCodes; } opCodes;
@ -116,6 +148,21 @@ typedef enum {
SRA_F7 = 0b0100000, SRA_F7 = 0b0100000,
OR_F = 0b110, OR_F = 0b110,
AND_F = 0b111, 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; } Codes;
/** /**
@ -128,7 +175,7 @@ public:
* @brief Constructor * @brief Constructor
* @param instr Instruction to decode * @param instr Instruction to decode
*/ */
Instruction(sc_int<32> instr); Instruction(sc_uint<32> instr);
/** /**
* @brief Access to opcode field * @brief Access to opcode field
@ -143,47 +190,66 @@ public:
* @brief Access to rd field * @brief Access to rd field
* @return rd field * @return rd field
*/ */
inline int32_t rd() { inline int32_t get_rd() {
return m_instr.range(11, 7); return m_instr.range(11, 7);
} }
inline void set_rd(int32_t value) {
m_instr.range(11,7) = value;
}
/** /**
* @brief Access to funct3 field * @brief Access to funct3 field
* @return funct3 field * @return funct3 field
*/ */
inline int32_t funct3() { inline int32_t get_funct3() {
return m_instr.range(14, 12); return m_instr.range(14, 12);
} }
inline void set_funct3(int32_t value) {
m_instr.range(14,12) = value;
}
/** /**
* @brief Access to rs1 field * @brief Access to rs1 field
* @return rs1 field * @return rs1 field
*/ */
inline int32_t rs1() { inline int32_t get_rs1() {
return m_instr.range(19, 15); return m_instr.range(19, 15);
} }
inline void set_rs1(int32_t value) {
m_instr.range(19,15) = value;
}
/** /**
* @brief Access to rs2 field * @brief Access to rs2 field
* @return rs2 field * @return rs2 field
*/ */
inline int32_t rs2() { inline int32_t get_rs2() {
return m_instr.range(24, 20); return m_instr.range(24, 20);
} }
inline void set_rs2(int32_t value) {
m_instr.range(24,10) = value;
}
/** /**
* @brief Access to funct7 field * @brief Access to funct7 field
* @return funct7 field * @return funct7 field
*/ */
inline int32_t funct7() { inline int32_t get_funct7() {
return m_instr.range(31, 25); return m_instr.range(31, 25);
} }
inline void set_func7(int32_t value) {
m_instr.range(31,25) = value;
}
/** /**
* @brief Access to immediate field for I-type * @brief Access to immediate field for I-type
* @return immediate_I field * @return immediate_I field
*/ */
inline int32_t imm_I() { inline int32_t get_imm_I() {
int32_t aux = 0; int32_t aux = 0;
aux = m_instr.range(31, 20); aux = m_instr.range(31, 20);
@ -196,11 +262,15 @@ public:
return aux; return aux;
} }
inline void set_imm_I(int32_t value) {
m_instr.range(31,20) = value;
}
/** /**
* @brief Access to immediate field for S-type * @brief Access to immediate field for S-type
* @return immediate_S field * @return immediate_S field
*/ */
inline int32_t imm_S() { inline int32_t get_imm_S() {
int32_t aux = 0; int32_t aux = 0;
aux = m_instr.range(31, 25) << 5; aux = m_instr.range(31, 25) << 5;
@ -213,19 +283,30 @@ public:
return aux; return aux;
} }
inline void set_imm_S(int32_t value) {
sc_uint<32> aux = value;
m_instr.range(31,25) = aux.range(11,5);
m_instr.range(11,7) = aux.range(4,0);
}
/** /**
* @brief Access to immediate field for U-type * @brief Access to immediate field for U-type
* @return immediate_U field * @return immediate_U field
*/ */
inline int32_t imm_U() { inline int32_t get_imm_U() {
return m_instr.range(31, 12); return m_instr.range(31, 12);
} }
inline void set_imm_U(int32_t value) {
m_instr.range(31,12) = (value << 12);
}
/** /**
* @brief Access to immediate field for B-type * @brief Access to immediate field for B-type
* @return immediate_B field * @return immediate_B field
*/ */
inline int32_t imm_B() { inline int32_t get_imm_B() {
int32_t aux = 0; int32_t aux = 0;
aux |= m_instr[7] << 11; aux |= m_instr[7] << 11;
@ -240,11 +321,20 @@ public:
return aux; return aux;
} }
inline void set_imm_B(int32_t value) {
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];
}
/** /**
* @brief Access to immediate field for J-type * @brief Access to immediate field for J-type
* @return immediate_J field * @return immediate_J field
*/ */
inline int32_t imm_J() { inline int32_t get_imm_J() {
int32_t aux = 0; int32_t aux = 0;
aux = m_instr[31] << 20; aux = m_instr[31] << 20;
@ -256,11 +346,25 @@ public:
if (m_instr[31] == 1) { if (m_instr[31] == 1) {
aux |= (0b111111111111) << 20; aux |= (0b111111111111) << 20;
} }
return aux; return aux;
} }
inline int32_t csr() { inline void set_imm_J(int32_t value) {
return imm_I(); 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);
}
inline int32_t get_csr() {
int32_t aux = 0;
aux = m_instr.range(31, 20);
return aux;
} }
/** /**
@ -269,11 +373,23 @@ public:
*/ */
opCodes decode(); opCodes decode();
/**
* @brief returns what instruction extension
* @return extension
*/
extension_t check_extension();
uint32_t getInstr() {
return m_instr;
}
inline void dump() { inline void dump() {
cout << hex << "0x" << m_instr << dec << endl; cout << hex << "0x" << m_instr << dec << endl;
} }
private: private:
sc_int<32> m_instr; sc_uint<32> m_instr;
}; };
#endif #endif

View File

@ -48,14 +48,12 @@ public:
// ********************************************* // *********************************************
// TLM-2 forward DMI method // TLM-2 forward DMI method
// ********************************************* // *********************************************
virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload& trans, virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload& trans,
tlm::tlm_dmi& dmi_data); tlm::tlm_dmi& dmi_data);
// ********************************************* // *********************************************
// TLM-2 debug transport method // TLM-2 debug transport method
// ********************************************* // *********************************************
virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans); virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans);
private: private:

View File

@ -14,6 +14,7 @@
#include "tlm.h" #include "tlm.h"
#include "Performance.h" #include "Performance.h"
#include "Memory.h"
using namespace sc_core; using namespace sc_core;
using namespace sc_dt; using namespace sc_dt;
@ -126,10 +127,15 @@ public:
/** /**
* Increments PC couunter to next address * Increments PC couunter to next address
*/ */
inline void incPC() { inline void incPC(bool C_ext=false) {
if (C_ext == true) {
register_PC += 2;
} else {
register_PC += 4; register_PC += 4;
} }
}
/** /**
* @brief Get CSR value * @brief Get CSR value
* @param csr CSR number to access * @param csr CSR number to access

View File

@ -1,4 +1,3 @@
#include "CPU.h" #include "CPU.h"
SC_HAS_PROCESS(CPU); SC_HAS_PROCESS(CPU);
@ -22,42 +21,71 @@ CPU::~CPU() {
cout << "*********************************************" << endl; cout << "*********************************************" << endl;
} }
/** bool CPU::process_c_instruction(Instruction &inst) {
* main thread for CPU simulation
* @brief CPU mai thread
*/
void CPU::CPU_thread(void) {
tlm::tlm_generic_payload* trans = new tlm::tlm_generic_payload;
int32_t INSTR;
sc_time delay = SC_ZERO_TIME;
bool PC_not_affected = true; bool PC_not_affected = true;
trans->set_command( tlm::TLM_READ_COMMAND ); C_Instruction c_inst(inst.getInstr());
trans->set_data_ptr( reinterpret_cast<unsigned char*>(&INSTR) );
trans->set_data_length( 4 );
trans->set_streaming_width( 4 ); // = data_length to indicate no streaming
trans->set_byte_enable_ptr( 0 ); // 0 indicates unused
trans->set_dmi_allowed( false ); // Mandatory initial value
trans->set_response_status( tlm::TLM_INCOMPLETE_RESPONSE );
register_bank->dump(); 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;
while(1) { }
/* Get new PC value */
trans->set_address( register_bank->getPC() );
instr_bus->b_transport( *trans, delay);
perf->codeMemoryRead(); return PC_not_affected;
}
if ( trans->is_response_error() ) { bool CPU::process_base_instruction(Instruction &inst) {
SC_REPORT_ERROR("CPU base", "Read memory"); bool PC_not_affected = true;
} else {
log->SC_log(Log::INFO) << "PC: " << hex << register_bank->getPC()
<< dec << endl;
Instruction inst(INSTR);
PC_not_affected = true;
switch(inst.decode()) { switch(inst.decode()) {
case OP_LUI: case OP_LUI:
exec->LUI(inst); exec->LUI(inst);
@ -189,16 +217,104 @@ void CPU::CPU_thread(void) {
exec->CSRRC(inst); exec->CSRRC(inst);
break; break;
#endif #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: default:
cout << endl << "Instruction not implemented: "; std::cout << "Wrong instruction" << endl;
inst.dump(); inst.dump();
exec->NOP(inst); 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;
bool incPCby2 = false;
trans->set_command( tlm::TLM_READ_COMMAND );
trans->set_data_ptr( reinterpret_cast<unsigned char*>(&INSTR) );
trans->set_data_length( 4 );
trans->set_streaming_width( 4 ); // = data_length to indicate no streaming
trans->set_byte_enable_ptr( 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 */
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;
default:
std::cout << "Extension not implemented yet" << std::endl;
inst.dump();
exec->NOP(inst);
} // switch (inst.check_extension())
}
perf->instructionsInc(); perf->instructionsInc();
if (PC_not_affected == true) { if (PC_not_affected == true) {
register_bank->incPC(); register_bank->incPC(incPCby2);
}
} }
} // while(1) } // while(1)
} // CPU_thread } // CPU_thread

109
src/C_Instruction.cpp Normal file
View File

@ -0,0 +1,109 @@
#include "C_Instruction.h"
C_Instruction::C_Instruction(sc_uint<32> instr) {
m_instr = instr;
}
op_C_Codes C_Instruction::decode() {
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;
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:
return OP_C_SRLI;
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;
default:
return OP_C_ERROR;
break;
}
break;
case 0b10:
switch(get_funct3()) {
case C_SLLI:
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.range(6,2) == 0) {
return OP_C_JR;
} else {
return OP_C_MV;
}
break;
case C_FDSP:
break;
case C_SWSP:
return OP_C_SWSP;
break;
case C_FWWSP:
default:
return OP_C_ERROR;
break;
}
break;
default:
return OP_C_ERROR;
break;
}
return OP_C_ERROR;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
#include "Instruction.h" #include "Instruction.h"
Instruction::Instruction(sc_int<32> instr) { Instruction::Instruction(sc_uint<32> instr) {
m_instr = instr; m_instr = instr;
} }
@ -16,7 +16,7 @@ opCodes Instruction::decode() {
case JALR: case JALR:
return OP_JALR; return OP_JALR;
case BEQ: case BEQ:
switch(funct3()) { switch(get_funct3()) {
case BEQ_F: case BEQ_F:
return OP_BEQ; return OP_BEQ;
case BNE_F: case BNE_F:
@ -32,7 +32,7 @@ opCodes Instruction::decode() {
} }
return OP_ERROR; return OP_ERROR;
case LB: case LB:
switch(funct3()) { switch(get_funct3()) {
case LB_F: case LB_F:
return OP_LB; return OP_LB;
case LH_F: case LH_F:
@ -46,7 +46,7 @@ opCodes Instruction::decode() {
} }
return OP_ERROR; return OP_ERROR;
case SB: case SB:
switch(funct3()) { switch(get_funct3()) {
case SB_F: case SB_F:
return OP_SB; return OP_SB;
case SH_F: case SH_F:
@ -56,7 +56,7 @@ opCodes Instruction::decode() {
} }
return OP_ERROR; return OP_ERROR;
case ADDI: case ADDI:
switch(funct3()) { switch(get_funct3()) {
case ADDI_F: case ADDI_F:
return OP_ADDI; return OP_ADDI;
case SLTI_F: case SLTI_F:
@ -72,7 +72,7 @@ opCodes Instruction::decode() {
case SLLI_F: case SLLI_F:
return OP_SLLI; return OP_SLLI;
case SRLI_F: case SRLI_F:
switch(funct7()) { switch(get_funct7()) {
case SRLI_F7: case SRLI_F7:
return OP_SRLI; return OP_SRLI;
case SRAI_F7: case SRAI_F7:
@ -82,9 +82,9 @@ opCodes Instruction::decode() {
} }
return OP_ERROR; return OP_ERROR;
case ADD: { case ADD: {
switch(funct3()) { switch(get_funct3()) {
case ADD_F: case ADD_F:
switch (funct7()) { switch (get_funct7()) {
case ADD_F7: case ADD_F7:
return OP_ADD; return OP_ADD;
case SUB_F7: case SUB_F7:
@ -100,7 +100,7 @@ opCodes Instruction::decode() {
case XOR_F: case XOR_F:
return OP_XOR; return OP_XOR;
case SRL_F: case SRL_F:
switch(funct7()) { switch(get_funct7()) {
case SRL_F7: case SRL_F7:
return OP_SRL; return OP_SRL;
case SRA_F7: case SRA_F7:
@ -112,8 +112,64 @@ opCodes Instruction::decode() {
return OP_AND; return OP_AND;
} }
} /* ADD */ } /* 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: default:
return OP_ERROR; 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,10 +2,12 @@
Registers::Registers() { 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(); perf = Performance::getInstance();
register_bank[sp] = 1024-1; // SP points to end of memory //register_bank[sp] = 1024-1; // SP points to end of memory
register_bank[sp] = Memory::SIZE-4;
register_PC = 0x10000; // default _start address register_PC = 0x10000; // default _start address
} }

52
tests/C/func3/Makefile Normal file
View File

@ -0,0 +1,52 @@
TARGET = func3
TARGET_ARCH=riscv32
CC = riscv32-unknown-linux-gnu-gcc
# compiling flags here
#CFLAGS = -Wall -I. -O0 -nostdlib -march=rv32i -mabi=ilp32 --entry main
CFLAGS = -Wall -I. -O0 -static
#CFLAGS = -Wall -I. -O0 -Xlinker --gc-sections -lgcc -lc -static --specs=nano.specs
LINKER = riscv32-unknown-linux-gnu-gcc
# linking flags here
LFLAGS = -I. --entry main -L/opt/riscv/riscv32-unknown-elf/lib/
LIBS = $(EXTRA_LIBS)
# change these to proper directories where each file should be
SRCDIR = ./
OBJDIR = .
BINDIR = ./
INCDIR = -I.
LIBDIR = -L.
SOURCES := $(wildcard $(SRCDIR)/*.c)
INCLUDES := $(wildcard $(INCDIR)/*.h)
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
rm = rm -f
$(BINDIR)/$(TARGET): $(OBJECTS)
# $(LINKER) $(OBJECTS) $(LFLAGS) $(LIBS) $(LIBDIR) -o $@
riscv32-unknown-linux-gnu-objdump -d $< > dump
objcopy -Oihex $< $(TARGET).hex
# @echo "Linking complete!"
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
@echo "Compiling "$<" ..."
# $(CC) $(CFLAGS) $(INCDIR) -c $< -o $@
$(CC) $(CFLAGS) $(INCDIR) $< -o $@
@echo "Done!"
.PHONY: clean
clean:
@$(rm) $(OBJECTS) *.hex dump
@echo "Cleanup complete!"
.PHONY: remove
remove: clean
@$(rm) $(BINDIR)/$(TARGET)
@echo "Executable removed!"

36
tests/C/func3/func3.c Normal file
View File

@ -0,0 +1,36 @@
#include <string.h>
#define TRACE (*(unsigned char *)0x40000000)
void print(char *msg) {
int i = 0;
while(msg[i] != '\0') {
TRACE = msg[i];
i++;
}
}
int func1(int a, int* b) {
return a - (*b);
}
void main(void) {
int x1, x2, x3;
int aux[5] = {0};
int aux2[5];
x1 = 6;
x2 = 7;
x3 = func1(x1, &x2);
if (x3 == (6-7)) {
print("OK\n");
} else {
print("ERROR\n");
}
memcpy(aux, aux2, 5);
}