parent
1b93e7f569
commit
a2a9c95546
|
@ -0,0 +1,128 @@
|
||||||
|
/*!
|
||||||
|
\file A_Instruction.h
|
||||||
|
\brief Decode A extensions part of the RISC-V
|
||||||
|
\author Màrius Montón
|
||||||
|
\date December 2018
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef A_INSTRUCTION__H
|
||||||
|
#define A_INSTRUCTION__H
|
||||||
|
|
||||||
|
#include "systemc"
|
||||||
|
|
||||||
|
using namespace sc_core;
|
||||||
|
using namespace sc_dt;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
OP_A_LR,
|
||||||
|
OP_A_SC,
|
||||||
|
OP_A_AMOSWAP,
|
||||||
|
OP_A_AMOADD,
|
||||||
|
OP_A_AMOXOR,
|
||||||
|
OP_A_AMOAND,
|
||||||
|
OP_A_AMOOR,
|
||||||
|
OP_A_AMOMIN,
|
||||||
|
OP_A_AMOMAX,
|
||||||
|
OP_A_AMOMINU,
|
||||||
|
OP_A_AMOMAXU,
|
||||||
|
|
||||||
|
OP_A_ERROR
|
||||||
|
} op_A_Codes;
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
A_LR = 0b00010,
|
||||||
|
A_SC = 0b00011,
|
||||||
|
A_AMOSWAP = 0b00001,
|
||||||
|
A_AMOADD = 0b00000,
|
||||||
|
A_AMOXOR = 0b00100,
|
||||||
|
A_AMOAND = 0b01100,
|
||||||
|
A_AMOOR = 0b01000,
|
||||||
|
A_AMOMIN = 0b10000,
|
||||||
|
A_AMOMAX = 0b10100,
|
||||||
|
A_AMOMINU = 0b11000,
|
||||||
|
A_AMOMAXU = 0b11100,
|
||||||
|
} A_Codes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Instruction decoding and fields access
|
||||||
|
*/
|
||||||
|
class A_Instruction{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
* @param instr Instruction to decode
|
||||||
|
*/
|
||||||
|
A_Instruction(sc_uint<32> instr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Access to opcode field
|
||||||
|
* @return return opcode field
|
||||||
|
*/
|
||||||
|
inline int32_t opcode() {
|
||||||
|
return a_instr.range(31,27);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Access to rd field
|
||||||
|
* @return rd field
|
||||||
|
*/
|
||||||
|
inline int32_t get_rd() {
|
||||||
|
return a_instr.range(11, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_rd(int32_t value) {
|
||||||
|
a_instr.range(11,7) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Access to rs1 field
|
||||||
|
* @return rs1 field
|
||||||
|
*/
|
||||||
|
inline int32_t get_rs1() {
|
||||||
|
return a_instr.range(19, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_rs1(int32_t value) {
|
||||||
|
a_instr.range(19,15) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Access to rs2 field
|
||||||
|
* @return rs2 field
|
||||||
|
*/
|
||||||
|
inline int32_t get_rs2() {
|
||||||
|
return a_instr.range(24, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_rs2(int32_t value) {
|
||||||
|
a_instr.range(24,20) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline int32_t get_funct3() {
|
||||||
|
return a_instr.range(14, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_funct3(int32_t value) {
|
||||||
|
a_instr.range(14,12) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decodes opcode of instruction
|
||||||
|
* @return opcode of instruction
|
||||||
|
*/
|
||||||
|
op_A_Codes decode();
|
||||||
|
|
||||||
|
inline void dump() {
|
||||||
|
cout << hex << "0x" << a_instr << dec << endl;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
sc_uint<32> a_instr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -21,6 +21,7 @@
|
||||||
#include "Instruction.h"
|
#include "Instruction.h"
|
||||||
#include "C_Instruction.h"
|
#include "C_Instruction.h"
|
||||||
#include "M_Instruction.h"
|
#include "M_Instruction.h"
|
||||||
|
#include "A_Instruction.h"
|
||||||
|
|
||||||
using namespace sc_core;
|
using namespace sc_core;
|
||||||
using namespace sc_dt;
|
using namespace sc_dt;
|
||||||
|
@ -60,6 +61,8 @@ private:
|
||||||
|
|
||||||
bool process_m_instruction(Instruction &inst);
|
bool process_m_instruction(Instruction &inst);
|
||||||
|
|
||||||
|
bool process_a_instruction(Instruction inst);
|
||||||
|
|
||||||
void CPU_thread(void);
|
void CPU_thread(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
||||||
|
|
||||||
#include "systemc"
|
#include "systemc"
|
||||||
|
#include <set>
|
||||||
#include "tlm.h"
|
#include "tlm.h"
|
||||||
#include "tlm_utils/simple_initiator_socket.h"
|
#include "tlm_utils/simple_initiator_socket.h"
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
#include "Instruction.h"
|
#include "Instruction.h"
|
||||||
#include "C_Instruction.h"
|
#include "C_Instruction.h"
|
||||||
#include "M_Instruction.h"
|
#include "M_Instruction.h"
|
||||||
|
#include "A_Instruction.h"
|
||||||
#include "Registers.h"
|
#include "Registers.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
|
@ -102,8 +103,10 @@ public:
|
||||||
|
|
||||||
/*********************** Privileged Instructions ******************************/
|
/*********************** Privileged Instructions ******************************/
|
||||||
bool MRET(Instruction &inst);
|
bool MRET(Instruction &inst);
|
||||||
|
bool SRET(Instruction &inst);
|
||||||
bool WFI(Instruction &inst);
|
bool WFI(Instruction &inst);
|
||||||
|
bool SFENCE(Instruction &inst);
|
||||||
|
|
||||||
/* C Extensions */
|
/* C Extensions */
|
||||||
bool C_JR(Instruction &inst);
|
bool C_JR(Instruction &inst);
|
||||||
bool C_MV(Instruction &inst);
|
bool C_MV(Instruction &inst);
|
||||||
|
@ -134,6 +137,19 @@ public:
|
||||||
bool M_REM(Instruction &inst);
|
bool M_REM(Instruction &inst);
|
||||||
bool M_REMU(Instruction &inst);
|
bool M_REMU(Instruction &inst);
|
||||||
|
|
||||||
|
/* A Extensinos */
|
||||||
|
bool A_LR(Instruction &inst);
|
||||||
|
bool A_SC(Instruction &inst);
|
||||||
|
bool A_AMOSWAP(Instruction &inst);
|
||||||
|
bool A_AMOADD(Instruction &inst);
|
||||||
|
bool A_AMOXOR(Instruction &inst);
|
||||||
|
bool A_AMOAND(Instruction &inst);
|
||||||
|
bool A_AMOOR(Instruction &inst);
|
||||||
|
bool A_AMOMIN(Instruction &inst);
|
||||||
|
bool A_AMOMAX(Instruction &inst);
|
||||||
|
bool A_AMOMINU(Instruction &inst);
|
||||||
|
bool A_AMOMAXU(Instruction &inst);
|
||||||
|
|
||||||
bool NOP(Instruction &inst);
|
bool NOP(Instruction &inst);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -142,6 +158,11 @@ private:
|
||||||
|
|
||||||
void RaiseException(uint32_t cause, uint32_t inst = 0);
|
void RaiseException(uint32_t cause, uint32_t inst = 0);
|
||||||
|
|
||||||
|
std::set<uint32_t> TLB_A_Entries;
|
||||||
|
|
||||||
|
void TLB_reserve(uint32_t address);
|
||||||
|
bool TLB_reserved(uint32_t address);
|
||||||
|
|
||||||
Registers *regs;
|
Registers *regs;
|
||||||
Performance *perf;
|
Performance *perf;
|
||||||
Log *log;
|
Log *log;
|
||||||
|
|
|
@ -90,6 +90,7 @@ OP_URET,
|
||||||
OP_SRET,
|
OP_SRET,
|
||||||
OP_MRET,
|
OP_MRET,
|
||||||
OP_WFI,
|
OP_WFI,
|
||||||
|
OP_SFENCE,
|
||||||
|
|
||||||
OP_ERROR
|
OP_ERROR
|
||||||
} opCodes;
|
} opCodes;
|
||||||
|
@ -158,6 +159,8 @@ typedef enum {
|
||||||
SRET_F = 0b000100000010,
|
SRET_F = 0b000100000010,
|
||||||
MRET_F = 0b001100000010,
|
MRET_F = 0b001100000010,
|
||||||
WFI_F = 0b000100000101,
|
WFI_F = 0b000100000101,
|
||||||
|
SFENCE_F = 0b0001001,
|
||||||
|
|
||||||
ECALL_F3= 0b000,
|
ECALL_F3= 0b000,
|
||||||
CSRRW = 0b001,
|
CSRRW = 0b001,
|
||||||
CSRRS = 0b010,
|
CSRRS = 0b010,
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
#include "A_Instruction.h"
|
||||||
|
|
||||||
|
|
||||||
|
A_Instruction::A_Instruction(sc_uint<32> instr) {
|
||||||
|
a_instr = instr;
|
||||||
|
}
|
||||||
|
|
||||||
|
op_A_Codes A_Instruction::decode() {
|
||||||
|
|
||||||
|
switch (opcode()) {
|
||||||
|
case A_LR:
|
||||||
|
return OP_A_LR;
|
||||||
|
break;
|
||||||
|
case A_SC:
|
||||||
|
return OP_A_SC;
|
||||||
|
break;
|
||||||
|
case A_AMOSWAP:
|
||||||
|
return OP_A_AMOSWAP;
|
||||||
|
break;
|
||||||
|
case A_AMOADD:
|
||||||
|
return OP_A_AMOADD;
|
||||||
|
break;
|
||||||
|
case A_AMOXOR:
|
||||||
|
return OP_A_AMOXOR;
|
||||||
|
break;
|
||||||
|
case A_AMOAND:
|
||||||
|
return OP_A_AMOAND;
|
||||||
|
break;
|
||||||
|
case A_AMOOR:
|
||||||
|
return OP_A_AMOOR;
|
||||||
|
break;
|
||||||
|
case A_AMOMIN:
|
||||||
|
return OP_A_AMOMIN;
|
||||||
|
break;
|
||||||
|
case A_AMOMAX:
|
||||||
|
return OP_A_AMOMAX;
|
||||||
|
break;
|
||||||
|
case A_AMOMINU:
|
||||||
|
return OP_A_AMOMINU;
|
||||||
|
break;
|
||||||
|
case A_AMOMAXU:
|
||||||
|
return OP_A_AMOMAXU;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return OP_A_ERROR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return OP_A_ERROR;
|
||||||
|
}
|
73
src/CPU.cpp
73
src/CPU.cpp
|
@ -157,6 +157,56 @@ bool CPU::process_m_instruction(Instruction &inst) {
|
||||||
return PC_not_affected;
|
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 CPU::process_base_instruction(Instruction &inst) {
|
||||||
bool PC_not_affected = true;
|
bool PC_not_affected = true;
|
||||||
|
|
||||||
|
@ -280,17 +330,6 @@ bool CPU::process_base_instruction(Instruction &inst) {
|
||||||
case OP_AND:
|
case OP_AND:
|
||||||
exec->AND(inst);
|
exec->AND(inst);
|
||||||
break;
|
break;
|
||||||
#if 0
|
|
||||||
case OP_CSRRW:
|
|
||||||
exec->CSRRW(inst);
|
|
||||||
break;
|
|
||||||
case OP_CSRRS:
|
|
||||||
exec->CSRRS(inst);
|
|
||||||
break;
|
|
||||||
case OP_CSRRC:
|
|
||||||
exec->CSRRC(inst);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case OP_FENCE:
|
case OP_FENCE:
|
||||||
exec->FENCE(inst);
|
exec->FENCE(inst);
|
||||||
break;
|
break;
|
||||||
|
@ -323,9 +362,16 @@ bool CPU::process_base_instruction(Instruction &inst) {
|
||||||
exec->MRET(inst);
|
exec->MRET(inst);
|
||||||
PC_not_affected = false;
|
PC_not_affected = false;
|
||||||
break;
|
break;
|
||||||
|
case OP_SRET:
|
||||||
|
exec->SRET(inst);
|
||||||
|
PC_not_affected = false;
|
||||||
|
break;
|
||||||
case OP_WFI:
|
case OP_WFI:
|
||||||
exec->WFI(inst);
|
exec->WFI(inst);
|
||||||
break;
|
break;
|
||||||
|
case OP_SFENCE:
|
||||||
|
exec->SFENCE(inst);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
std::cout << "Wrong instruction" << endl;
|
std::cout << "Wrong instruction" << endl;
|
||||||
inst.dump();
|
inst.dump();
|
||||||
|
@ -361,6 +407,7 @@ void CPU::CPU_thread(void) {
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
/* Get new PC value */
|
/* Get new PC value */
|
||||||
|
//cout << "CPU: PC 0x" << hex << (uint32_t) register_bank->getPC() << endl;
|
||||||
trans->set_address( register_bank->getPC() );
|
trans->set_address( register_bank->getPC() );
|
||||||
instr_bus->b_transport( *trans, delay);
|
instr_bus->b_transport( *trans, delay);
|
||||||
|
|
||||||
|
@ -388,6 +435,10 @@ void CPU::CPU_thread(void) {
|
||||||
PC_not_affected = process_m_instruction(inst);
|
PC_not_affected = process_m_instruction(inst);
|
||||||
incPCby2 = false;
|
incPCby2 = false;
|
||||||
break;
|
break;
|
||||||
|
case A_EXTENSION:
|
||||||
|
PC_not_affected = process_a_instruction(inst);
|
||||||
|
incPCby2 = false;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
std::cout << "Extension not implemented yet" << std::endl;
|
std::cout << "Extension not implemented yet" << std::endl;
|
||||||
inst.dump();
|
inst.dump();
|
||||||
|
|
390
src/Execute.cpp
390
src/Execute.cpp
|
@ -322,8 +322,9 @@ bool Execute::LW(Instruction &inst, bool c_extension) {
|
||||||
regs->setValue(rd, data);
|
regs->setValue(rd, data);
|
||||||
|
|
||||||
log->SC_log(Log::INFO) << dec << "C.LW: x"
|
log->SC_log(Log::INFO) << dec << "C.LW: x"
|
||||||
<< rs1 << " + " << imm << " (@0x" << hex
|
<< rs1 << "(0x" << hex << regs->getValue(rs1) << ") + "
|
||||||
<< mem_addr << dec << ") -> x" << rd << endl;
|
<< dec << imm << " (@0x" << hex << mem_addr << dec << ") -> x" << rd << hex
|
||||||
|
<< " (0x" << data << ")"<< endl;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -565,20 +566,22 @@ bool Execute::ORI(Instruction &inst) {
|
||||||
|
|
||||||
bool Execute::ANDI(Instruction &inst) {
|
bool Execute::ANDI(Instruction &inst) {
|
||||||
int rd, rs1;
|
int rd, rs1;
|
||||||
int32_t imm;
|
uint32_t imm;
|
||||||
uint32_t calc;
|
uint32_t calc;
|
||||||
|
uint32_t aux;
|
||||||
|
|
||||||
rd = inst.get_rd();
|
rd = inst.get_rd();
|
||||||
rs1 = inst.get_rs1();
|
rs1 = inst.get_rs1();
|
||||||
imm = inst.get_imm_I();
|
imm = inst.get_imm_I();
|
||||||
|
|
||||||
calc = regs->getValue(rs1) & imm;
|
aux = regs->getValue(rs1);
|
||||||
|
calc = aux & imm;
|
||||||
regs->setValue(rd, calc);
|
regs->setValue(rd, calc);
|
||||||
|
|
||||||
log->SC_log(Log::INFO) << "ANDI: x"
|
log->SC_log(Log::INFO) << "ANDI: x"
|
||||||
<< rs1 << " AND "
|
<< rs1 << "(0x" << hex << aux << ") AND 0x"
|
||||||
<< imm << " -> x"
|
<< imm << " -> x"
|
||||||
<< rd << endl;
|
<< dec << rd << "(0x" << hex << calc << ")" << endl;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -662,12 +665,16 @@ bool Execute::ADD(Instruction &inst) {
|
||||||
rs2 = inst.get_rs2();
|
rs2 = inst.get_rs2();
|
||||||
|
|
||||||
calc = regs->getValue(rs1) + regs->getValue(rs2);
|
calc = regs->getValue(rs1) + regs->getValue(rs2);
|
||||||
|
|
||||||
|
// log->SC_log(Log::INFO) << "ADD 0x" << hex << regs->getValue(rs1)
|
||||||
|
// << " + 0x" << regs->getValue(rs2) << " = " << calc << endl;
|
||||||
|
|
||||||
regs->setValue(rd, calc);
|
regs->setValue(rd, calc);
|
||||||
|
|
||||||
log->SC_log(Log::INFO) << "ADD: x"
|
log->SC_log(Log::INFO) << "ADD: x" << dec
|
||||||
<< rs1 << " + x"
|
<< rs1 << " + x"
|
||||||
<< rs2 << " -> x"
|
<< rs2 << " -> x"
|
||||||
<< rd << endl;
|
<< rd << hex << "(0x" << calc << ")"<< endl;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -922,6 +929,7 @@ bool Execute::CSRRS(Instruction &inst) {
|
||||||
csr = inst.get_csr();
|
csr = inst.get_csr();
|
||||||
|
|
||||||
if (rd == 0) {
|
if (rd == 0) {
|
||||||
|
log->SC_log(Log::INFO) << "CSRRS with rd1 == 0, doing nothing." << endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -952,6 +960,7 @@ bool Execute::CSRRC(Instruction &inst) {
|
||||||
csr = inst.get_csr();
|
csr = inst.get_csr();
|
||||||
|
|
||||||
if (rd == 0) {
|
if (rd == 0) {
|
||||||
|
log->SC_log(Log::INFO) << "CSRRC with rd1 == 0, doing nothing." << endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1048,7 +1057,8 @@ bool Execute::CSRRCI(Instruction &inst) {
|
||||||
|
|
||||||
log->SC_log(Log::INFO) << "CSRRCI: CSR #"
|
log->SC_log(Log::INFO) << "CSRRCI: CSR #"
|
||||||
<< csr << " -> x" << rd
|
<< csr << " -> x" << rd
|
||||||
<< ". x" << rs1 << " & CSR #" << csr << endl;
|
<< ". x" << rs1 << " & CSR #" << csr
|
||||||
|
<< "(0x" << hex << aux << ")"<< endl;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1066,6 +1076,16 @@ bool Execute::MRET(Instruction &inst) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Execute::SRET(Instruction &inst) {
|
||||||
|
uint32_t new_pc = 0;
|
||||||
|
|
||||||
|
new_pc = regs->getCSR(CSR_SEPC);
|
||||||
|
regs->setPC(new_pc);
|
||||||
|
|
||||||
|
log->SC_log(Log::INFO) << "SRET: PC <- 0x" << hex << new_pc << endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Execute::WFI(Instruction &inst) {
|
bool Execute::WFI(Instruction &inst) {
|
||||||
log->SC_log(Log::INFO) << "WFI" << endl;
|
log->SC_log(Log::INFO) << "WFI" << endl;
|
||||||
|
@ -1073,6 +1093,12 @@ bool Execute::WFI(Instruction &inst) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Execute::SFENCE(Instruction &inst) {
|
||||||
|
log->SC_log(Log::INFO) << "SFENCE" << endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**************************** C Instructions **********************************/
|
/**************************** C Instructions **********************************/
|
||||||
|
|
||||||
bool Execute::C_JR(Instruction &inst) {
|
bool Execute::C_JR(Instruction &inst) {
|
||||||
|
@ -1390,7 +1416,8 @@ bool Execute::C_SLLI(Instruction &inst) {
|
||||||
|
|
||||||
bool Execute::C_ANDI(Instruction &inst) {
|
bool Execute::C_ANDI(Instruction &inst) {
|
||||||
int rd, rs1;
|
int rd, rs1;
|
||||||
int32_t imm;
|
uint32_t imm;
|
||||||
|
uint32_t aux;
|
||||||
uint32_t calc;
|
uint32_t calc;
|
||||||
|
|
||||||
C_Instruction c_inst(inst.getInstr());
|
C_Instruction c_inst(inst.getInstr());
|
||||||
|
@ -1399,11 +1426,12 @@ bool Execute::C_ANDI(Instruction &inst) {
|
||||||
rs1 = c_inst.get_rs1p();
|
rs1 = c_inst.get_rs1p();
|
||||||
imm = c_inst.get_imm_ADDI();
|
imm = c_inst.get_imm_ADDI();
|
||||||
|
|
||||||
calc = regs->getValue(rs1) & imm;
|
aux = regs->getValue(rs1);
|
||||||
|
calc = aux & imm;
|
||||||
regs->setValue(rd, calc);
|
regs->setValue(rd, calc);
|
||||||
|
|
||||||
log->SC_log(Log::INFO) << "C.ANDI: x"
|
log->SC_log(Log::INFO) << "C.ANDI: x"
|
||||||
<< rs1 << " AND "
|
<< rs1 << "(" << aux << ") AND "
|
||||||
<< imm << " -> x"
|
<< imm << " -> x"
|
||||||
<< rd << endl;
|
<< rd << endl;
|
||||||
|
|
||||||
|
@ -1719,6 +1747,329 @@ bool Execute::M_REMU(Instruction &inst) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Execute::A_LR(Instruction &inst) {
|
||||||
|
uint32_t mem_addr = 0;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
uint32_t data;
|
||||||
|
|
||||||
|
A_Instruction a_inst(inst.getInstr());
|
||||||
|
|
||||||
|
rd = a_inst.get_rd();
|
||||||
|
rs1 = a_inst.get_rs1();
|
||||||
|
rs2 = a_inst.get_rs2();
|
||||||
|
|
||||||
|
if (rs2 != 0) {
|
||||||
|
cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << endl;
|
||||||
|
RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_addr = regs->getValue(rs1);
|
||||||
|
data = readDataMem(mem_addr, 4);
|
||||||
|
regs->setValue(rd, data);
|
||||||
|
|
||||||
|
TLB_reserve(mem_addr);
|
||||||
|
|
||||||
|
log->SC_log(Log::INFO) << dec << "LR.W: x"
|
||||||
|
<< rs1 << " (@0x" << hex << mem_addr
|
||||||
|
<< dec << ") -> x" << rd << endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Execute::A_SC(Instruction &inst) {
|
||||||
|
uint32_t mem_addr = 0;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
uint32_t data;
|
||||||
|
|
||||||
|
A_Instruction a_inst(inst.getInstr());
|
||||||
|
|
||||||
|
rd = a_inst.get_rd();
|
||||||
|
rs1 = a_inst.get_rs1();
|
||||||
|
rs2 = a_inst.get_rs2();
|
||||||
|
|
||||||
|
mem_addr = regs->getValue(rs1);
|
||||||
|
data = regs->getValue(rs2);
|
||||||
|
|
||||||
|
if (TLB_reserved(mem_addr) == true) {
|
||||||
|
writeDataMem(mem_addr, data, 4);
|
||||||
|
regs->setValue(rd, 0); // SC writes 0 to rd on success
|
||||||
|
} else {
|
||||||
|
regs->setValue(rd, 1); // SC writes nonzero on failure
|
||||||
|
}
|
||||||
|
|
||||||
|
log->SC_log(Log::INFO) << dec << "SC.W: (@0x" <<
|
||||||
|
hex << mem_addr << dec << ") <- x" << rs2 <<
|
||||||
|
hex << "(0x" << data << ")" << endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Execute::A_AMOSWAP(Instruction &inst) {
|
||||||
|
uint32_t mem_addr = 0;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
uint32_t data;
|
||||||
|
uint32_t aux;
|
||||||
|
|
||||||
|
A_Instruction a_inst(inst.getInstr());
|
||||||
|
|
||||||
|
/* These instructions must be atomic */
|
||||||
|
|
||||||
|
rd = a_inst.get_rd();
|
||||||
|
rs1 = a_inst.get_rs1();
|
||||||
|
rs2 = a_inst.get_rs2();
|
||||||
|
|
||||||
|
mem_addr = regs->getValue(rs1);
|
||||||
|
data = readDataMem(mem_addr, 4);
|
||||||
|
|
||||||
|
regs->setValue(rd, data);
|
||||||
|
|
||||||
|
// swap
|
||||||
|
aux = regs->getValue(rs2);
|
||||||
|
regs->setValue(rs2, data);
|
||||||
|
|
||||||
|
writeDataMem(mem_addr, aux, 4);
|
||||||
|
|
||||||
|
log->SC_log(Log::INFO) << dec << "AMOSWAP " << endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Execute::A_AMOADD(Instruction &inst) {
|
||||||
|
uint32_t mem_addr = 0;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
uint32_t data;
|
||||||
|
|
||||||
|
A_Instruction a_inst(inst.getInstr());
|
||||||
|
|
||||||
|
/* These instructions must be atomic */
|
||||||
|
|
||||||
|
rd = a_inst.get_rd();
|
||||||
|
rs1 = a_inst.get_rs1();
|
||||||
|
rs2 = a_inst.get_rs2();
|
||||||
|
|
||||||
|
mem_addr = regs->getValue(rs1);
|
||||||
|
data = readDataMem(mem_addr, 4);
|
||||||
|
|
||||||
|
regs->setValue(rd, data);
|
||||||
|
|
||||||
|
// add
|
||||||
|
data = data + regs->getValue(rs2);
|
||||||
|
|
||||||
|
writeDataMem(mem_addr, data, 4);
|
||||||
|
|
||||||
|
log->SC_log(Log::INFO) << dec << "AMOADD " << endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Execute::A_AMOXOR(Instruction &inst) {
|
||||||
|
uint32_t mem_addr = 0;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
uint32_t data;
|
||||||
|
|
||||||
|
A_Instruction a_inst(inst.getInstr());
|
||||||
|
|
||||||
|
/* These instructions must be atomic */
|
||||||
|
|
||||||
|
rd = a_inst.get_rd();
|
||||||
|
rs1 = a_inst.get_rs1();
|
||||||
|
rs2 = a_inst.get_rs2();
|
||||||
|
|
||||||
|
mem_addr = regs->getValue(rs1);
|
||||||
|
data = readDataMem(mem_addr, 4);
|
||||||
|
|
||||||
|
regs->setValue(rd, data);
|
||||||
|
|
||||||
|
// add
|
||||||
|
data = data ^ regs->getValue(rs2);
|
||||||
|
|
||||||
|
writeDataMem(mem_addr, data, 4);
|
||||||
|
|
||||||
|
log->SC_log(Log::INFO) << dec << "AMOXOR " << endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Execute::A_AMOAND(Instruction &inst) {
|
||||||
|
uint32_t mem_addr = 0;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
uint32_t data;
|
||||||
|
|
||||||
|
A_Instruction a_inst(inst.getInstr());
|
||||||
|
|
||||||
|
/* These instructions must be atomic */
|
||||||
|
|
||||||
|
rd = a_inst.get_rd();
|
||||||
|
rs1 = a_inst.get_rs1();
|
||||||
|
rs2 = a_inst.get_rs2();
|
||||||
|
|
||||||
|
mem_addr = regs->getValue(rs1);
|
||||||
|
data = readDataMem(mem_addr, 4);
|
||||||
|
|
||||||
|
regs->setValue(rd, data);
|
||||||
|
|
||||||
|
// add
|
||||||
|
data = data & regs->getValue(rs2);
|
||||||
|
|
||||||
|
writeDataMem(mem_addr, data, 4);
|
||||||
|
|
||||||
|
log->SC_log(Log::INFO) << dec << "AMOAND " << endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Execute::A_AMOOR(Instruction &inst) {
|
||||||
|
uint32_t mem_addr = 0;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
uint32_t data;
|
||||||
|
|
||||||
|
A_Instruction a_inst(inst.getInstr());
|
||||||
|
|
||||||
|
/* These instructions must be atomic */
|
||||||
|
|
||||||
|
rd = a_inst.get_rd();
|
||||||
|
rs1 = a_inst.get_rs1();
|
||||||
|
rs2 = a_inst.get_rs2();
|
||||||
|
|
||||||
|
mem_addr = regs->getValue(rs1);
|
||||||
|
data = readDataMem(mem_addr, 4);
|
||||||
|
|
||||||
|
regs->setValue(rd, data);
|
||||||
|
|
||||||
|
// add
|
||||||
|
data = data | regs->getValue(rs2);
|
||||||
|
|
||||||
|
writeDataMem(mem_addr, data, 4);
|
||||||
|
|
||||||
|
log->SC_log(Log::INFO) << dec << "AMOOR " << endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Execute::A_AMOMIN(Instruction &inst) {
|
||||||
|
uint32_t mem_addr = 0;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
uint32_t data;
|
||||||
|
uint32_t aux;
|
||||||
|
|
||||||
|
A_Instruction a_inst(inst.getInstr());
|
||||||
|
|
||||||
|
/* These instructions must be atomic */
|
||||||
|
|
||||||
|
rd = a_inst.get_rd();
|
||||||
|
rs1 = a_inst.get_rs1();
|
||||||
|
rs2 = a_inst.get_rs2();
|
||||||
|
|
||||||
|
mem_addr = regs->getValue(rs1);
|
||||||
|
data = readDataMem(mem_addr, 4);
|
||||||
|
|
||||||
|
regs->setValue(rd, data);
|
||||||
|
|
||||||
|
// min
|
||||||
|
aux = regs->getValue(rs2);
|
||||||
|
if ((int32_t)data < (int32_t)aux) {
|
||||||
|
aux = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeDataMem(mem_addr, aux, 4);
|
||||||
|
|
||||||
|
log->SC_log(Log::INFO) << dec << "AMOMIN " << endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Execute::A_AMOMAX(Instruction &inst) {
|
||||||
|
uint32_t mem_addr = 0;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
uint32_t data;
|
||||||
|
uint32_t aux;
|
||||||
|
|
||||||
|
A_Instruction a_inst(inst.getInstr());
|
||||||
|
|
||||||
|
/* These instructions must be atomic */
|
||||||
|
|
||||||
|
rd = a_inst.get_rd();
|
||||||
|
rs1 = a_inst.get_rs1();
|
||||||
|
rs2 = a_inst.get_rs2();
|
||||||
|
|
||||||
|
mem_addr = regs->getValue(rs1);
|
||||||
|
data = readDataMem(mem_addr, 4);
|
||||||
|
|
||||||
|
regs->setValue(rd, data);
|
||||||
|
|
||||||
|
// >
|
||||||
|
aux = regs->getValue(rs2);
|
||||||
|
if ((int32_t)data > (int32_t)aux) {
|
||||||
|
aux = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeDataMem(mem_addr, aux, 4);
|
||||||
|
|
||||||
|
log->SC_log(Log::INFO) << dec << "AMOMAX " << endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Execute::A_AMOMINU(Instruction &inst) {
|
||||||
|
uint32_t mem_addr = 0;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
uint32_t data;
|
||||||
|
uint32_t aux;
|
||||||
|
|
||||||
|
A_Instruction a_inst(inst.getInstr());
|
||||||
|
|
||||||
|
/* These instructions must be atomic */
|
||||||
|
|
||||||
|
rd = a_inst.get_rd();
|
||||||
|
rs1 = a_inst.get_rs1();
|
||||||
|
rs2 = a_inst.get_rs2();
|
||||||
|
|
||||||
|
mem_addr = regs->getValue(rs1);
|
||||||
|
data = readDataMem(mem_addr, 4);
|
||||||
|
|
||||||
|
regs->setValue(rd, data);
|
||||||
|
|
||||||
|
// min
|
||||||
|
aux = regs->getValue(rs2);
|
||||||
|
if (data < aux) {
|
||||||
|
aux = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeDataMem(mem_addr, aux, 4);
|
||||||
|
|
||||||
|
log->SC_log(Log::INFO) << dec << "AMOMINU " << endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Execute::A_AMOMAXU(Instruction &inst) {
|
||||||
|
uint32_t mem_addr = 0;
|
||||||
|
int rd, rs1, rs2;
|
||||||
|
uint32_t data;
|
||||||
|
uint32_t aux;
|
||||||
|
|
||||||
|
A_Instruction a_inst(inst.getInstr());
|
||||||
|
|
||||||
|
/* These instructions must be atomic */
|
||||||
|
|
||||||
|
rd = a_inst.get_rd();
|
||||||
|
rs1 = a_inst.get_rs1();
|
||||||
|
rs2 = a_inst.get_rs2();
|
||||||
|
|
||||||
|
mem_addr = regs->getValue(rs1);
|
||||||
|
data = readDataMem(mem_addr, 4);
|
||||||
|
|
||||||
|
regs->setValue(rd, data);
|
||||||
|
|
||||||
|
// max
|
||||||
|
aux = regs->getValue(rs2);
|
||||||
|
if (data > aux) {
|
||||||
|
aux = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeDataMem(mem_addr, aux, 4);
|
||||||
|
|
||||||
|
log->SC_log(Log::INFO) << dec << "AMOMAXU " << endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Execute::NOP(Instruction &inst) {
|
bool Execute::NOP(Instruction &inst) {
|
||||||
cout << endl;
|
cout << endl;
|
||||||
regs->dump();
|
regs->dump();
|
||||||
|
@ -1805,3 +2156,18 @@ void Execute::RaiseException(uint32_t cause, uint32_t inst) {
|
||||||
|
|
||||||
log->SC_log(Log::INFO) << "Exception! new PC " << hex << new_pc << endl;
|
log->SC_log(Log::INFO) << "Exception! new PC " << hex << new_pc << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Execute::TLB_reserve(uint32_t address) {
|
||||||
|
TLB_A_Entries.insert(address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Execute::TLB_reserved(uint32_t address) {
|
||||||
|
if (TLB_A_Entries.count(address) == 1) {
|
||||||
|
TLB_A_Entries.erase(address);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -130,6 +130,11 @@ opCodes Instruction::decode() {
|
||||||
return OP_MRET;
|
return OP_MRET;
|
||||||
case WFI_F:
|
case WFI_F:
|
||||||
return OP_WFI;
|
return OP_WFI;
|
||||||
|
case SFENCE_F:
|
||||||
|
return OP_SFENCE;
|
||||||
|
}
|
||||||
|
if (m_instr.range(31,25) == 0b0001001) {
|
||||||
|
return OP_SFENCE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CSRRW:
|
case CSRRW:
|
||||||
|
@ -162,6 +167,8 @@ extension_t Instruction::check_extension() {
|
||||||
if ( (m_instr.range(6,0) == 0b0110011) &&
|
if ( (m_instr.range(6,0) == 0b0110011) &&
|
||||||
(m_instr.range(31,25) == 0b0000001) ){
|
(m_instr.range(31,25) == 0b0000001) ){
|
||||||
return M_EXTENSION;
|
return M_EXTENSION;
|
||||||
|
} else if (m_instr.range(6,0) == 0b0101111) {
|
||||||
|
return A_EXTENSION;
|
||||||
} else if (m_instr.range(1,0) == 0b11) {
|
} else if (m_instr.range(1,0) == 0b11) {
|
||||||
return BASE_EXTENSION;
|
return BASE_EXTENSION;
|
||||||
} else if (m_instr.range(1,0) == 0b00) {
|
} else if (m_instr.range(1,0) == 0b00) {
|
||||||
|
@ -171,7 +178,6 @@ extension_t Instruction::check_extension() {
|
||||||
} else if (m_instr.range(1,0) == 0b10) {
|
} else if (m_instr.range(1,0) == 0b10) {
|
||||||
return C_EXTENSION;
|
return C_EXTENSION;
|
||||||
} else if (m_instr.range(6,0) == 0b0101111) {
|
} else if (m_instr.range(6,0) == 0b0101111) {
|
||||||
cout << "check_extension A not yet implemented" << endl;
|
|
||||||
return A_EXTENSION;
|
return A_EXTENSION;
|
||||||
} else {
|
} else {
|
||||||
return UNKNOWN_EXTENSION;
|
return UNKNOWN_EXTENSION;
|
||||||
|
|
Loading…
Reference in New Issue