Merge branch 'C_extension'
Functional (almost) execution of C extensions
This commit is contained in:
commit
0f56cb0288
13
inc/CPU.h
13
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;
|
||||
|
@ -47,6 +48,16 @@ private:
|
|||
Performance *perf;
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -128,7 +175,7 @@ public:
|
|||
* @brief Constructor
|
||||
* @param instr Instruction to decode
|
||||
*/
|
||||
Instruction(sc_int<32> instr);
|
||||
Instruction(sc_uint<32> instr);
|
||||
|
||||
/**
|
||||
* @brief Access to opcode field
|
||||
|
@ -143,47 +190,66 @@ public:
|
|||
* @brief Access to rd field
|
||||
* @return rd field
|
||||
*/
|
||||
inline int32_t rd() {
|
||||
inline int32_t get_rd() {
|
||||
return m_instr.range(11, 7);
|
||||
}
|
||||
|
||||
inline void set_rd(int32_t value) {
|
||||
m_instr.range(11,7) = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to funct3 field
|
||||
* @return funct3 field
|
||||
*/
|
||||
inline int32_t funct3() {
|
||||
inline int32_t get_funct3() {
|
||||
return m_instr.range(14, 12);
|
||||
}
|
||||
|
||||
inline void set_funct3(int32_t value) {
|
||||
m_instr.range(14,12) = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rs1 field
|
||||
* @return rs1 field
|
||||
*/
|
||||
inline int32_t rs1() {
|
||||
inline int32_t get_rs1() {
|
||||
return m_instr.range(19, 15);
|
||||
}
|
||||
|
||||
inline void set_rs1(int32_t value) {
|
||||
m_instr.range(19,15) = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rs2 field
|
||||
* @return rs2 field
|
||||
*/
|
||||
inline int32_t rs2() {
|
||||
inline int32_t get_rs2() {
|
||||
return m_instr.range(24, 20);
|
||||
}
|
||||
|
||||
inline void set_rs2(int32_t value) {
|
||||
m_instr.range(24,10) = value;
|
||||
}
|
||||
/**
|
||||
* @brief Access to funct7 field
|
||||
* @return funct7 field
|
||||
*/
|
||||
inline int32_t funct7() {
|
||||
inline int32_t get_funct7() {
|
||||
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
|
||||
* @return immediate_I field
|
||||
*/
|
||||
inline int32_t imm_I() {
|
||||
inline int32_t get_imm_I() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr.range(31, 20);
|
||||
|
@ -196,11 +262,15 @@ public:
|
|||
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 imm_S() {
|
||||
inline int32_t get_imm_S() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr.range(31, 25) << 5;
|
||||
|
@ -213,19 +283,30 @@ public:
|
|||
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 imm_U() {
|
||||
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 imm_B() {
|
||||
inline int32_t get_imm_B() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux |= m_instr[7] << 11;
|
||||
|
@ -240,11 +321,20 @@ public:
|
|||
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 imm_J() {
|
||||
inline int32_t get_imm_J() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[31] << 20;
|
||||
|
@ -256,11 +346,25 @@ public:
|
|||
if (m_instr[31] == 1) {
|
||||
aux |= (0b111111111111) << 20;
|
||||
}
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t csr() {
|
||||
return imm_I();
|
||||
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_csr() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr.range(31, 20);
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -269,11 +373,23 @@ 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;
|
||||
}
|
||||
private:
|
||||
sc_int<32> m_instr;
|
||||
sc_uint<32> m_instr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "tlm.h"
|
||||
|
||||
#include "Performance.h"
|
||||
#include "Memory.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
|
@ -126,10 +127,15 @@ public:
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get CSR value
|
||||
* @param csr CSR number to access
|
||||
|
|
182
src/CPU.cpp
182
src/CPU.cpp
|
@ -1,4 +1,3 @@
|
|||
|
||||
#include "CPU.h"
|
||||
|
||||
SC_HAS_PROCESS(CPU);
|
||||
|
@ -22,42 +21,71 @@ CPU::~CPU() {
|
|||
cout << "*********************************************" << endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 CPU::process_c_instruction(Instruction &inst) {
|
||||
bool PC_not_affected = true;
|
||||
|
||||
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 );
|
||||
C_Instruction c_inst(inst.getInstr());
|
||||
|
||||
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() ) {
|
||||
SC_REPORT_ERROR("CPU base", "Read memory");
|
||||
} else {
|
||||
log->SC_log(Log::INFO) << "PC: " << hex << register_bank->getPC()
|
||||
<< dec << endl;
|
||||
Instruction inst(INSTR);
|
||||
bool CPU::process_base_instruction(Instruction &inst) {
|
||||
bool PC_not_affected = true;
|
||||
|
||||
PC_not_affected = true;
|
||||
switch(inst.decode()) {
|
||||
case OP_LUI:
|
||||
exec->LUI(inst);
|
||||
|
@ -189,16 +217,104 @@ void CPU::CPU_thread(void) {
|
|||
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:
|
||||
cout << endl << "Instruction not implemented: ";
|
||||
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;
|
||||
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();
|
||||
|
||||
if (PC_not_affected == true) {
|
||||
register_bank->incPC();
|
||||
}
|
||||
register_bank->incPC(incPCby2);
|
||||
}
|
||||
} // while(1)
|
||||
} // CPU_thread
|
||||
|
|
|
@ -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;
|
||||
}
|
816
src/Execute.cpp
816
src/Execute.cpp
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
|||
#include "Instruction.h"
|
||||
|
||||
|
||||
Instruction::Instruction(sc_int<32> instr) {
|
||||
Instruction::Instruction(sc_uint<32> instr) {
|
||||
m_instr = instr;
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ opCodes Instruction::decode() {
|
|||
case JALR:
|
||||
return OP_JALR;
|
||||
case BEQ:
|
||||
switch(funct3()) {
|
||||
switch(get_funct3()) {
|
||||
case BEQ_F:
|
||||
return OP_BEQ;
|
||||
case BNE_F:
|
||||
|
@ -32,7 +32,7 @@ opCodes Instruction::decode() {
|
|||
}
|
||||
return OP_ERROR;
|
||||
case LB:
|
||||
switch(funct3()) {
|
||||
switch(get_funct3()) {
|
||||
case LB_F:
|
||||
return OP_LB;
|
||||
case LH_F:
|
||||
|
@ -46,7 +46,7 @@ opCodes Instruction::decode() {
|
|||
}
|
||||
return OP_ERROR;
|
||||
case SB:
|
||||
switch(funct3()) {
|
||||
switch(get_funct3()) {
|
||||
case SB_F:
|
||||
return OP_SB;
|
||||
case SH_F:
|
||||
|
@ -56,7 +56,7 @@ opCodes Instruction::decode() {
|
|||
}
|
||||
return OP_ERROR;
|
||||
case ADDI:
|
||||
switch(funct3()) {
|
||||
switch(get_funct3()) {
|
||||
case ADDI_F:
|
||||
return OP_ADDI;
|
||||
case SLTI_F:
|
||||
|
@ -72,7 +72,7 @@ opCodes Instruction::decode() {
|
|||
case SLLI_F:
|
||||
return OP_SLLI;
|
||||
case SRLI_F:
|
||||
switch(funct7()) {
|
||||
switch(get_funct7()) {
|
||||
case SRLI_F7:
|
||||
return OP_SRLI;
|
||||
case SRAI_F7:
|
||||
|
@ -82,9 +82,9 @@ opCodes Instruction::decode() {
|
|||
}
|
||||
return OP_ERROR;
|
||||
case ADD: {
|
||||
switch(funct3()) {
|
||||
switch(get_funct3()) {
|
||||
case ADD_F:
|
||||
switch (funct7()) {
|
||||
switch (get_funct7()) {
|
||||
case ADD_F7:
|
||||
return OP_ADD;
|
||||
case SUB_F7:
|
||||
|
@ -100,7 +100,7 @@ opCodes Instruction::decode() {
|
|||
case XOR_F:
|
||||
return OP_XOR;
|
||||
case SRL_F:
|
||||
switch(funct7()) {
|
||||
switch(get_funct7()) {
|
||||
case SRL_F7:
|
||||
return OP_SRL;
|
||||
case SRA_F7:
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
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
|
||||
//register_bank[sp] = 1024-1; // SP points to end of memory
|
||||
register_bank[sp] = Memory::SIZE-4;
|
||||
register_PC = 0x10000; // default _start address
|
||||
}
|
||||
|
||||
|
|
|
@ -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!"
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue