Added A Extensions

Added SFENCE instruction
This commit is contained in:
mariusmonton 2018-12-12 18:14:35 +01:00
parent 1b93e7f569
commit a2a9c95546
8 changed files with 655 additions and 26 deletions

128
inc/A_Instruction.h Normal file
View File

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

View File

@ -21,6 +21,7 @@
#include "Instruction.h"
#include "C_Instruction.h"
#include "M_Instruction.h"
#include "A_Instruction.h"
using namespace sc_core;
using namespace sc_dt;
@ -60,6 +61,8 @@ private:
bool process_m_instruction(Instruction &inst);
bool process_a_instruction(Instruction inst);
void CPU_thread(void);
};

View File

@ -10,7 +10,7 @@
#define SC_INCLUDE_DYNAMIC_PROCESSES
#include "systemc"
#include <set>
#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
@ -18,6 +18,7 @@
#include "Instruction.h"
#include "C_Instruction.h"
#include "M_Instruction.h"
#include "A_Instruction.h"
#include "Registers.h"
#include "Log.h"
@ -102,7 +103,9 @@ public:
/*********************** Privileged Instructions ******************************/
bool MRET(Instruction &inst);
bool SRET(Instruction &inst);
bool WFI(Instruction &inst);
bool SFENCE(Instruction &inst);
/* C Extensions */
bool C_JR(Instruction &inst);
@ -134,6 +137,19 @@ public:
bool M_REM(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);
private:
@ -142,6 +158,11 @@ private:
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;
Performance *perf;
Log *log;

View File

@ -90,6 +90,7 @@ OP_URET,
OP_SRET,
OP_MRET,
OP_WFI,
OP_SFENCE,
OP_ERROR
} opCodes;
@ -158,6 +159,8 @@ typedef enum {
SRET_F = 0b000100000010,
MRET_F = 0b001100000010,
WFI_F = 0b000100000101,
SFENCE_F = 0b0001001,
ECALL_F3= 0b000,
CSRRW = 0b001,
CSRRS = 0b010,

51
src/A_Instruction.cpp Normal file
View File

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

View File

@ -157,6 +157,56 @@ bool CPU::process_m_instruction(Instruction &inst) {
return PC_not_affected;
}
bool CPU::process_a_instruction(Instruction inst) {
bool PC_not_affected = true;
A_Instruction a_inst(inst.getInstr());
switch(a_inst.decode()) {
case OP_A_LR:
exec->A_LR(inst);
break;
case OP_A_SC:
exec->A_SC(inst);
break;
case OP_A_AMOSWAP:
exec->A_AMOSWAP(inst);
break;
case OP_A_AMOADD:
exec->A_AMOADD(inst);
break;
case OP_A_AMOXOR:
exec->A_AMOXOR(inst);
break;
case OP_A_AMOAND:
exec->A_AMOAND(inst);
break;
case OP_A_AMOOR:
exec->A_AMOOR(inst);
break;
case OP_A_AMOMIN:
exec->A_AMOMIN(inst);
break;
case OP_A_AMOMAX:
exec->A_AMOMAX(inst);
break;
case OP_A_AMOMINU:
exec->A_AMOMINU(inst);
break;
case OP_A_AMOMAXU:
exec->A_AMOMAXU(inst);
break;
default:
std::cout << "A instruction not implemented yet" << endl;
inst.dump();
exec->NOP(inst);
break;
}
return PC_not_affected;
}
bool CPU::process_base_instruction(Instruction &inst) {
bool PC_not_affected = true;
@ -280,17 +330,6 @@ bool CPU::process_base_instruction(Instruction &inst) {
case OP_AND:
exec->AND(inst);
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:
exec->FENCE(inst);
break;
@ -323,9 +362,16 @@ bool CPU::process_base_instruction(Instruction &inst) {
exec->MRET(inst);
PC_not_affected = false;
break;
case OP_SRET:
exec->SRET(inst);
PC_not_affected = false;
break;
case OP_WFI:
exec->WFI(inst);
break;
case OP_SFENCE:
exec->SFENCE(inst);
break;
default:
std::cout << "Wrong instruction" << endl;
inst.dump();
@ -361,6 +407,7 @@ void CPU::CPU_thread(void) {
while(1) {
/* Get new PC value */
//cout << "CPU: PC 0x" << hex << (uint32_t) register_bank->getPC() << endl;
trans->set_address( register_bank->getPC() );
instr_bus->b_transport( *trans, delay);
@ -388,6 +435,10 @@ void CPU::CPU_thread(void) {
PC_not_affected = process_m_instruction(inst);
incPCby2 = false;
break;
case A_EXTENSION:
PC_not_affected = process_a_instruction(inst);
incPCby2 = false;
break;
default:
std::cout << "Extension not implemented yet" << std::endl;
inst.dump();

View File

@ -322,8 +322,9 @@ bool Execute::LW(Instruction &inst, bool c_extension) {
regs->setValue(rd, data);
log->SC_log(Log::INFO) << dec << "C.LW: x"
<< rs1 << " + " << imm << " (@0x" << hex
<< mem_addr << dec << ") -> x" << rd << endl;
<< rs1 << "(0x" << hex << regs->getValue(rs1) << ") + "
<< dec << imm << " (@0x" << hex << mem_addr << dec << ") -> x" << rd << hex
<< " (0x" << data << ")"<< endl;
return true;
}
@ -565,20 +566,22 @@ bool Execute::ORI(Instruction &inst) {
bool Execute::ANDI(Instruction &inst) {
int rd, rs1;
int32_t imm;
uint32_t imm;
uint32_t calc;
uint32_t aux;
rd = inst.get_rd();
rs1 = inst.get_rs1();
imm = inst.get_imm_I();
calc = regs->getValue(rs1) & imm;
aux = regs->getValue(rs1);
calc = aux & imm;
regs->setValue(rd, calc);
log->SC_log(Log::INFO) << "ANDI: x"
<< rs1 << " AND "
<< rs1 << "(0x" << hex << aux << ") AND 0x"
<< imm << " -> x"
<< rd << endl;
<< dec << rd << "(0x" << hex << calc << ")" << endl;
return true;
}
@ -662,12 +665,16 @@ bool Execute::ADD(Instruction &inst) {
rs2 = inst.get_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);
log->SC_log(Log::INFO) << "ADD: x"
log->SC_log(Log::INFO) << "ADD: x" << dec
<< rs1 << " + x"
<< rs2 << " -> x"
<< rd << endl;
<< rd << hex << "(0x" << calc << ")"<< endl;
return true;
}
@ -922,6 +929,7 @@ bool Execute::CSRRS(Instruction &inst) {
csr = inst.get_csr();
if (rd == 0) {
log->SC_log(Log::INFO) << "CSRRS with rd1 == 0, doing nothing." << endl;
return false;
}
@ -952,6 +960,7 @@ bool Execute::CSRRC(Instruction &inst) {
csr = inst.get_csr();
if (rd == 0) {
log->SC_log(Log::INFO) << "CSRRC with rd1 == 0, doing nothing." << endl;
return true;
}
@ -1048,7 +1057,8 @@ bool Execute::CSRRCI(Instruction &inst) {
log->SC_log(Log::INFO) << "CSRRCI: CSR #"
<< csr << " -> x" << rd
<< ". x" << rs1 << " & CSR #" << csr << endl;
<< ". x" << rs1 << " & CSR #" << csr
<< "(0x" << hex << aux << ")"<< endl;
return true;
}
@ -1066,6 +1076,16 @@ bool Execute::MRET(Instruction &inst) {
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) {
log->SC_log(Log::INFO) << "WFI" << endl;
@ -1073,6 +1093,12 @@ bool Execute::WFI(Instruction &inst) {
return true;
}
bool Execute::SFENCE(Instruction &inst) {
log->SC_log(Log::INFO) << "SFENCE" << endl;
return true;
}
/**************************** C Instructions **********************************/
bool Execute::C_JR(Instruction &inst) {
@ -1390,7 +1416,8 @@ bool Execute::C_SLLI(Instruction &inst) {
bool Execute::C_ANDI(Instruction &inst) {
int rd, rs1;
int32_t imm;
uint32_t imm;
uint32_t aux;
uint32_t calc;
C_Instruction c_inst(inst.getInstr());
@ -1399,11 +1426,12 @@ bool Execute::C_ANDI(Instruction &inst) {
rs1 = c_inst.get_rs1p();
imm = c_inst.get_imm_ADDI();
calc = regs->getValue(rs1) & imm;
aux = regs->getValue(rs1);
calc = aux & imm;
regs->setValue(rd, calc);
log->SC_log(Log::INFO) << "C.ANDI: x"
<< rs1 << " AND "
<< rs1 << "(" << aux << ") AND "
<< imm << " -> x"
<< rd << endl;
@ -1719,6 +1747,329 @@ bool Execute::M_REMU(Instruction &inst) {
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) {
cout << endl;
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;
}
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;
}
}

View File

@ -130,6 +130,11 @@ opCodes Instruction::decode() {
return OP_MRET;
case WFI_F:
return OP_WFI;
case SFENCE_F:
return OP_SFENCE;
}
if (m_instr.range(31,25) == 0b0001001) {
return OP_SFENCE;
}
break;
case CSRRW:
@ -162,6 +167,8 @@ extension_t Instruction::check_extension() {
if ( (m_instr.range(6,0) == 0b0110011) &&
(m_instr.range(31,25) == 0b0000001) ){
return M_EXTENSION;
} else if (m_instr.range(6,0) == 0b0101111) {
return A_EXTENSION;
} else if (m_instr.range(1,0) == 0b11) {
return BASE_EXTENSION;
} 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) {
return C_EXTENSION;
} else if (m_instr.range(6,0) == 0b0101111) {
cout << "check_extension A not yet implemented" << endl;
return A_EXTENSION;
} else {
return UNKNOWN_EXTENSION;