Initial RV64I verification

This commit is contained in:
Eyck Jentzsch 2017-11-23 14:48:18 +01:00
parent 7b7648d8cc
commit f1667c195a
13 changed files with 843 additions and 180 deletions

View File

@ -12,8 +12,8 @@ DBT-RISE-RiscV uses libGIS (https://github.com/vsergeev/libGIS) as well as ELFIO
**What's missing** **What's missing**
* RV64I is only preliminary verified * F & D standard extensions for 32bit to be implemented
* F & D standard extensions to be implemented * MACF &D standard extensions for 64bit to be implemented and verified
**Planned features** **Planned features**

@ -1 +1 @@
Subproject commit 3b05de8c14f5d7b5d1ff55f5f244f797992be83d Subproject commit d0422e5f8df2391df372779b06c807d456a058a3

View File

@ -12,6 +12,13 @@ InsructionSet RV32CI {
PC[XLEN](is_pc) PC[XLEN](is_pc)
} }
instructions{ instructions{
JALR(no_cont){ // overwriting the implementation if rv32i, alignment does not need to be word
encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b1100111;
args_disass: "x%rd$d, x%rs1$d, 0x%imm$x";
if(rd!=0) X[rd] <= PC+4;
val ret[XLEN] <= X[rs1]+ imm;
PC<=ret& ~0x1;
}
C.ADDI4SPN { //(RES, imm=0) C.ADDI4SPN { //(RES, imm=0)
encoding: b000 | imm[5:4] | imm[9:6] | imm[2:2] | imm[3:3] | rd[2:0] | b00; encoding: b000 | imm[5:4] | imm[9:6] | imm[2:2] | imm[3:3] | rd[2:0] | b00;
args_disass: "x%rd$d, 0x%imm$05x"; args_disass: "x%rd$d, 0x%imm$05x";

View File

@ -38,9 +38,14 @@ InsructionSet RV32IBase {
JALR(no_cont){ JALR(no_cont){
encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b1100111; encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b1100111;
args_disass: "x%rd$d, x%rs1$d, 0x%imm$x"; args_disass: "x%rd$d, x%rs1$d, 0x%imm$x";
val new_pc[XLEN] <= X[rs1]+ imm;
val align[XLEN] <= new_pc & 0x2;
if(align != 0){
raise(0, 0)
} else {
if(rd!=0) X[rd] <= PC+4; if(rd!=0) X[rd] <= PC+4;
val ret[XLEN] <= X[rs1]+ imm; PC<=new_pc & ~0x1;
PC<=ret& ~0x1; }
} }
BEQ(no_cont){ BEQ(no_cont){
encoding: imm[12:12]s |imm[10:5]s | rs2[4:0] | rs1[4:0] | b000 | imm[4:1]s | imm[11:11]s | b1100011; encoding: imm[12:12]s |imm[10:5]s | rs2[4:0] | rs1[4:0] | b000 | imm[4:1]s | imm[11:11]s | b1100011;
@ -154,18 +159,30 @@ InsructionSet RV32IBase {
SLLI { SLLI {
encoding: b0000000 | shamt[4:0] | rs1[4:0] | b001 | rd[4:0] | b0010011; encoding: b0000000 | shamt[4:0] | rs1[4:0] | b001 | rd[4:0] | b0010011;
args_disass:"x%rd$d, x%rs1$d, %shamt%"; args_disass:"x%rd$d, x%rs1$d, %shamt%";
if(shamt > 31){
raise(0,0)
} else {
if(rd != 0) X[rd] <= shll(X[rs1], shamt); if(rd != 0) X[rd] <= shll(X[rs1], shamt);
} }
}
SRLI { SRLI {
encoding: b0000000 | shamt[4:0] | rs1[4:0] | b101 | rd[4:0] | b0010011; encoding: b0000000 | shamt[4:0] | rs1[4:0] | b101 | rd[4:0] | b0010011;
args_disass:"x%rd$d, x%rs1$d, %shamt%"; args_disass:"x%rd$d, x%rs1$d, %shamt%";
if(shamt > 31){
raise(0,0)
} else {
if(rd != 0) X[rd] <= shrl(X[rs1], shamt); if(rd != 0) X[rd] <= shrl(X[rs1], shamt);
} }
}
SRAI { SRAI {
encoding: b0100000 | shamt[4:0] | rs1[4:0] | b101 | rd[4:0] | b0010011; encoding: b0100000 | shamt[4:0] | rs1[4:0] | b101 | rd[4:0] | b0010011;
args_disass:"x%rd$d, x%rs1$d, %shamt%"; args_disass:"x%rd$d, x%rs1$d, %shamt%";
if(shamt > 31){
raise(0,0)
} else {
if(rd != 0) X[rd] <= shra(X[rs1], shamt); if(rd != 0) X[rd] <= shra(X[rs1], shamt);
} }
}
ADD { ADD {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0110011; encoding: b0000000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0110011;
args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; args_disass:"x%rd$d, x%rs1$d, x%rs2$d";

View File

@ -1,4 +1,5 @@
import "RV64IBase.core_desc" import "RV64IBase.core_desc"
import "RV32A.core_desc"
InsructionSet RV64A extends RV64IBase { InsructionSet RV64A extends RV64IBase {

View File

@ -39,7 +39,7 @@ InsructionSet RV64IBase extends RV32IBase {
encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b0011011; encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b0011011;
args_disass:"x%rd$d, x%rs1$d, %imm%"; args_disass:"x%rd$d, x%rs1$d, %imm%";
if(rd != 0){ if(rd != 0){
val res[32] <= X[rs1]{32} + imm{32}; val res[32] <= X[rs1]{32} + imm;
X[rd] <= sext(res); X[rd] <= sext(res);
} }
} }

View File

@ -25,7 +25,7 @@ Core RV32IMAC provides RV32IBase,RV32M,RV32A, RV32CI {
} }
Core RV64IA provides RV64IBase,RV64A { Core RV64IA provides RV64IBase, RV64A, RV32A {
template:"vm_riscv.in.cpp"; template:"vm_riscv.in.cpp";
constants { constants {
XLEN:=64; XLEN:=64;
@ -37,7 +37,7 @@ Core RV64IA provides RV64IBase,RV64A {
fencevmal:=2; fencevmal:=2;
fencevmau:=3; fencevmau:=3;
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA // XL ZYXWVUTSRQPONMLKJIHGFEDCBA
MISA_VAL:=0b10000000000001000001000100000000; MISA_VAL:=0b10000000000001000000000100000001;
PGSIZE := 4096; //1 << 12; PGSIZE := 4096; //1 << 12;
PGMASK := 4095; //PGSIZE-1 PGMASK := 4095; //PGSIZE-1
} }

View File

@ -970,12 +970,13 @@ iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned lengt
if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) { if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
switch (hostvar >> 48) { switch (hostvar >> 48) {
case 0: case 0:
if (hostvar != 0x1) if (hostvar != 0x1){
LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
else }else{
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
}
throw(iss::simulation_stopped(hostvar)); throw(iss::simulation_stopped(hostvar));
case 0x0101: { case 0x0101: {
char c = static_cast<char>(hostvar & 0xff); char c = static_cast<char>(hostvar & 0xff);

View File

@ -28,7 +28,7 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE. // POSSIBILITY OF SUCH DAMAGE.
// //
// Created on: Fri Nov 17 20:34:49 CET 2017 // Created on: Sun Nov 19 14:05:47 CET 2017
// * rv32imac.h Author: <CoreDSL Generator> // * rv32imac.h Author: <CoreDSL Generator>
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -28,7 +28,7 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE. // POSSIBILITY OF SUCH DAMAGE.
// //
// Created on: Fri Nov 17 20:34:49 CET 2017 // Created on: Sun Nov 19 14:05:47 CET 2017
// * rv64ia.h Author: <CoreDSL Generator> // * rv64ia.h Author: <CoreDSL Generator>
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -48,7 +48,7 @@ struct rv64ia;
template<> template<>
struct traits<rv64ia> { struct traits<rv64ia> {
enum constants {XLEN=64,XLEN2=128,XLEN_BIT_MASK=63,PCLEN=64,fence=0,fencei=1,fencevmal=2,fencevmau=3,MISA_VAL=2147750144,PGSIZE=4096,PGMASK=4095}; enum constants {XLEN=64,XLEN2=128,XLEN_BIT_MASK=63,PCLEN=64,fence=0,fencei=1,fencevmal=2,fencevmau=3,MISA_VAL=2147746049,PGSIZE=4096,PGMASK=4095};
enum reg_e { enum reg_e {
X0, X0,

View File

@ -222,16 +222,24 @@ private:
****************************************************************************/ ****************************************************************************/
std::tuple<vm::continuation_e, llvm::BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr, std::tuple<vm::continuation_e, llvm::BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr,
llvm::BasicBlock *bb) { llvm::BasicBlock *bb) {
// this->gen_sync(iss::PRE_SYNC); bb->setName("illegal_instruction");
this->builder->CreateStore(this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true),
get_reg_ptr(traits<ARCH>::PC), true); this->gen_sync(iss::PRE_SYNC);
this->builder->CreateStore( if(this->disass_enabled){
this->builder->CreateAdd(this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true), /* generate console output when executing the command */
this->gen_const(64U, 1)), /* generate console output when executing the command */
get_reg_ptr(traits<ARCH>::ICOUNT), true); boost::format ins_fmter("DB x%1$d");
if (this->debugging_enabled()) this->gen_sync(iss::PRE_SYNC); ins_fmter % (uint64_t)instr;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc = pc + ((instr & 3) == 3 ? 4 : 2); pc = pc + ((instr & 3) == 3 ? 4 : 2);
this->gen_raise_trap(0, 2); // illegal instruction trap
this->gen_raise_trap(0, 2);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
this->gen_trap_check(this->leave_blk); this->gen_trap_check(this->leave_blk);
return std::make_tuple(iss::vm::BRANCH, nullptr); return std::make_tuple(iss::vm::BRANCH, nullptr);

View File

@ -215,7 +215,7 @@ private:
}; };
/* start generated code */ /* start generated code */
const InstructionDesriptor instr_descr[75] = { const InstructionDesriptor instr_descr[86] = {
/* entries are: valid value, valid mask, function ptr */ /* entries are: valid value, valid mask, function ptr */
/* instruction LWU */ /* instruction LWU */
{32, 0b00000000000000000110000000000011, 0b00000000000000000111000001111111, &this_class::__lwu}, {32, 0b00000000000000000110000000000011, 0b00000000000000000111000001111111, &this_class::__lwu},
@ -223,12 +223,6 @@ private:
{32, 0b00000000000000000011000000000011, 0b00000000000000000111000001111111, &this_class::__ld}, {32, 0b00000000000000000011000000000011, 0b00000000000000000111000001111111, &this_class::__ld},
/* instruction SD */ /* instruction SD */
{32, 0b00000000000000000011000000100011, 0b00000000000000000111000001111111, &this_class::__sd}, {32, 0b00000000000000000011000000100011, 0b00000000000000000111000001111111, &this_class::__sd},
/* instruction SLLI */
{32, 0b00000000000000000001000000010011, 0b11111100000000000111000001111111, &this_class::__slli},
/* instruction SRLI */
{32, 0b00000000000000000101000000010011, 0b11111100000000000111000001111111, &this_class::__srli},
/* instruction SRAI */
{32, 0b01000000000000000101000000010011, 0b11111100000000000111000001111111, &this_class::__srai},
/* instruction ADDIW */ /* instruction ADDIW */
{32, 0b00000000000000000000000000011011, 0b00000000000000000111000001111111, &this_class::__addiw}, {32, 0b00000000000000000000000000011011, 0b00000000000000000111000001111111, &this_class::__addiw},
/* instruction SLLIW */ /* instruction SLLIW */
@ -295,6 +289,12 @@ private:
{32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, &this_class::__ori}, {32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, &this_class::__ori},
/* instruction ANDI */ /* instruction ANDI */
{32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, &this_class::__andi}, {32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, &this_class::__andi},
/* instruction SLLI */
{32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, &this_class::__slli},
/* instruction SRLI */
{32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srli},
/* instruction SRAI */
{32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srai},
/* instruction ADD */ /* instruction ADD */
{32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__add}, {32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__add},
/* instruction SUB */ /* instruction SUB */
@ -367,6 +367,28 @@ private:
{32, 0b11000000000000000011000000101111, 0b11111000000000000111000001111111, &this_class::__amominu_d}, {32, 0b11000000000000000011000000101111, 0b11111000000000000111000001111111, &this_class::__amominu_d},
/* instruction AMOMAXU.D */ /* instruction AMOMAXU.D */
{32, 0b11100000000000000011000000101111, 0b11111000000000000111000001111111, &this_class::__amomaxu_d}, {32, 0b11100000000000000011000000101111, 0b11111000000000000111000001111111, &this_class::__amomaxu_d},
/* instruction LR.W */
{32, 0b00010000000000000010000000101111, 0b11111001111100000111000001111111, &this_class::__lr_w},
/* instruction SC.W */
{32, 0b00011000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__sc_w},
/* instruction AMOSWAP.W */
{32, 0b00001000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoswap_w},
/* instruction AMOADD.W */
{32, 0b00000000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoadd_w},
/* instruction AMOXOR.W */
{32, 0b00100000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoxor_w},
/* instruction AMOAND.W */
{32, 0b01100000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoand_w},
/* instruction AMOOR.W */
{32, 0b01000000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoor_w},
/* instruction AMOMIN.W */
{32, 0b10000000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amomin_w},
/* instruction AMOMAX.W */
{32, 0b10100000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amomax_w},
/* instruction AMOMINU.W */
{32, 0b11000000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amominu_w},
/* instruction AMOMAXU.W */
{32, 0b11100000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amomaxu_w},
}; };
// instruction LWU // instruction LWU
std::tuple<vm::continuation_e, llvm::BasicBlock*> __lwu(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ std::tuple<vm::continuation_e, llvm::BasicBlock*> __lwu(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
@ -483,111 +505,6 @@ private:
return std::make_tuple(vm::CONT, bb); return std::make_tuple(vm::CONT, bb);
} }
// instruction SLLI
std::tuple<vm::continuation_e, llvm::BasicBlock*> __slli(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("SLLI");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_shamt_val = 0 | (bit_sub<20,6>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("SLLI x%1$d, x%2$d, %3%");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_shamt_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
if(fld_rd_val != 0){
Value* X_rd_val = this->builder->CreateShl(
this->gen_reg_load(fld_rs1_val, 0),
this->gen_const(64U, fld_shamt_val));
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction SRLI
std::tuple<vm::continuation_e, llvm::BasicBlock*> __srli(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("SRLI");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_shamt_val = 0 | (bit_sub<20,6>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("SRLI x%1$d, x%2$d, %3%");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_shamt_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
if(fld_rd_val != 0){
Value* X_rd_val = this->builder->CreateLShr(
this->gen_reg_load(fld_rs1_val, 0),
this->gen_const(64U, fld_shamt_val));
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction SRAI
std::tuple<vm::continuation_e, llvm::BasicBlock*> __srai(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("SRAI");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_shamt_val = 0 | (bit_sub<20,6>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("SRAI x%1$d, x%2$d, %3%");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_shamt_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
if(fld_rd_val != 0){
Value* X_rd_val = this->builder->CreateAShr(
this->gen_reg_load(fld_rs1_val, 0),
this->gen_const(64U, fld_shamt_val));
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction ADDIW // instruction ADDIW
std::tuple<vm::continuation_e, llvm::BasicBlock*> __addiw(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ std::tuple<vm::continuation_e, llvm::BasicBlock*> __addiw(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("ADDIW"); bb->setName("ADDIW");
@ -1113,19 +1030,43 @@ private:
} }
pc=pc+4; pc=pc+4;
Value* new_pc_val = this->builder->CreateAdd(
this->gen_reg_load(fld_rs1_val, 0),
this->gen_const(64U, fld_imm_val));
Value* align_val = this->builder->CreateAnd(
new_pc_val,
this->gen_const(64U, 2));
llvm::BasicBlock* bbnext = llvm::BasicBlock::Create(this->mod->getContext(), "endif", this->func, this->leave_blk);
llvm::BasicBlock* bb_then = llvm::BasicBlock::Create(this->mod->getContext(), "thenbr", this->func, bbnext);
llvm::BasicBlock* bb_else = llvm::BasicBlock::Create(this->mod->getContext(), "elsebr", this->func, bbnext);
// this->builder->SetInsertPoint(bb);
this->gen_cond_branch(this->builder->CreateICmp(
ICmpInst::ICMP_NE,
align_val,
this->gen_const(64U, 0)),
bb_then,
bb_else);
this->builder->SetInsertPoint(bb_then);
{
this->gen_raise_trap(0, 0);
}
this->builder->CreateBr(bbnext);
this->builder->SetInsertPoint(bb_else);
{
if(fld_rd_val != 0){ if(fld_rd_val != 0){
Value* X_rd_val = this->builder->CreateAdd( Value* X_rd_val = this->builder->CreateAdd(
this->gen_reg_load(traits<ARCH>::PC, 0), this->gen_reg_load(traits<ARCH>::PC, 1),
this->gen_const(64U, 4)); this->gen_const(64U, 4));
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
} }
Value* ret_val = this->builder->CreateAdd(
this->gen_reg_load(fld_rs1_val, 0),
this->gen_const(64U, fld_imm_val));
Value* PC_val = this->builder->CreateAnd( Value* PC_val = this->builder->CreateAnd(
ret_val, new_pc_val,
this->builder->CreateNot(this->gen_const(64U, 1))); this->builder->CreateNot(this->gen_const(64U, 1)));
this->builder->CreateStore(PC_val, get_reg_ptr(traits<ARCH>::NEXT_PC), false); this->builder->CreateStore(PC_val, get_reg_ptr(traits<ARCH>::NEXT_PC), false);
}
this->builder->CreateBr(bbnext);
bb=bbnext;
this->builder->SetInsertPoint(bb);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
this->gen_trap_check(this->leave_blk); this->gen_trap_check(this->leave_blk);
return std::make_tuple(iss::vm::BRANCH, nullptr); return std::make_tuple(iss::vm::BRANCH, nullptr);
@ -1914,6 +1855,111 @@ private:
return std::make_tuple(vm::CONT, bb); return std::make_tuple(vm::CONT, bb);
} }
// instruction SLLI
std::tuple<vm::continuation_e, llvm::BasicBlock*> __slli(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("SLLI");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_shamt_val = 0 | (bit_sub<20,5>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("SLLI x%1$d, x%2$d, %3%");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_shamt_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
if(fld_rd_val != 0){
Value* X_rd_val = this->builder->CreateShl(
this->gen_reg_load(fld_rs1_val, 0),
this->gen_const(64U, fld_shamt_val));
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction SRLI
std::tuple<vm::continuation_e, llvm::BasicBlock*> __srli(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("SRLI");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_shamt_val = 0 | (bit_sub<20,5>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("SRLI x%1$d, x%2$d, %3%");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_shamt_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
if(fld_rd_val != 0){
Value* X_rd_val = this->builder->CreateLShr(
this->gen_reg_load(fld_rs1_val, 0),
this->gen_const(64U, fld_shamt_val));
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction SRAI
std::tuple<vm::continuation_e, llvm::BasicBlock*> __srai(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("SRAI");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_shamt_val = 0 | (bit_sub<20,5>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("SRAI x%1$d, x%2$d, %3%");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_shamt_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
if(fld_rd_val != 0){
Value* X_rd_val = this->builder->CreateAShr(
this->gen_reg_load(fld_rs1_val, 0),
this->gen_const(64U, fld_shamt_val));
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction ADD // instruction ADD
std::tuple<vm::continuation_e, llvm::BasicBlock*> __add(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ std::tuple<vm::continuation_e, llvm::BasicBlock*> __add(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("ADD"); bb->setName("ADD");
@ -3374,22 +3420,600 @@ private:
return std::make_tuple(vm::CONT, bb); return std::make_tuple(vm::CONT, bb);
} }
// instruction LR.W
std::tuple<vm::continuation_e, llvm::BasicBlock*> __lr_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("LR.W");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr));
uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("LR.W x%1$d, x%2$d");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
if(fld_rd_val != 0){
Value* offs_val = this->gen_reg_load(fld_rs1_val, 0);
Value* X_rd_val = this->gen_ext(
this->gen_read_mem(traits<ARCH>::MEM, offs_val, 32/8),
64,
true);
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
Value* RES_offs_val = this->gen_ext(
this->builder->CreateNeg(this->gen_const(8U, 1)),
32,
true);
this->gen_write_mem(
traits<ARCH>::RES,
offs_val,
this->builder->CreateZExtOrTrunc(RES_offs_val,this->get_type(32)));
}
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction SC.W
std::tuple<vm::continuation_e, llvm::BasicBlock*> __sc_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("SC.W");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr));
uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr));
uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("SC.W x%1$d, x%2$d, x%3$d");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
Value* offs_val = this->gen_reg_load(fld_rs1_val, 0);
Value* res1_val = this->gen_read_mem(traits<ARCH>::RES, offs_val, 32/8);
llvm::BasicBlock* bbnext = llvm::BasicBlock::Create(this->mod->getContext(), "endif", this->func, this->leave_blk);
llvm::BasicBlock* bb_then = llvm::BasicBlock::Create(this->mod->getContext(), "thenbr", this->func, bbnext);
// this->builder->SetInsertPoint(bb);
this->gen_cond_branch(this->builder->CreateICmp(
ICmpInst::ICMP_NE,
res1_val,
this->gen_const(32U, 0)),
bb_then,
bbnext);
this->builder->SetInsertPoint(bb_then);
{
Value* MEM_offs_val = this->gen_reg_load(fld_rs2_val, 1);
this->gen_write_mem(
traits<ARCH>::MEM,
offs_val,
this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32)));
}
this->builder->CreateBr(bbnext);
bb=bbnext;
this->builder->SetInsertPoint(bb);
if(fld_rd_val != 0){
Value* X_rd_val = this->gen_choose(
this->builder->CreateICmp(
ICmpInst::ICMP_NE,
res1_val,
this->gen_const(64U, 0)),
this->gen_const(64U, 0),
this->gen_const(64U, 1),
64);
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction AMOSWAP.W
std::tuple<vm::continuation_e, llvm::BasicBlock*> __amoswap_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("AMOSWAP.W");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr));
uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr));
uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("AMOSWAP.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
Value* offs_val = this->gen_reg_load(fld_rs1_val, 0);
if(fld_rd_val != 0){
Value* X_rd_val = this->gen_ext(
this->gen_read_mem(traits<ARCH>::MEM, offs_val, 32/8),
64,
true);
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
Value* MEM_offs_val = this->gen_reg_load(fld_rs2_val, 0);
this->gen_write_mem(
traits<ARCH>::MEM,
offs_val,
this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32)));
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction AMOADD.W
std::tuple<vm::continuation_e, llvm::BasicBlock*> __amoadd_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("AMOADD.W");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr));
uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr));
uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("AMOADD.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
Value* offs_val = this->gen_reg_load(fld_rs1_val, 0);
Value* res1_val = this->gen_ext(
this->gen_read_mem(traits<ARCH>::MEM, offs_val, 32/8),
64,
true);
if(fld_rd_val != 0){
Value* X_rd_val = res1_val;
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
Value* res2_val = this->builder->CreateAdd(
res1_val,
this->gen_reg_load(fld_rs2_val, 0));
Value* MEM_offs_val = res2_val;
this->gen_write_mem(
traits<ARCH>::MEM,
offs_val,
this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32)));
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction AMOXOR.W
std::tuple<vm::continuation_e, llvm::BasicBlock*> __amoxor_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("AMOXOR.W");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr));
uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr));
uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("AMOXOR.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
Value* offs_val = this->gen_reg_load(fld_rs1_val, 0);
Value* res1_val = this->gen_ext(
this->gen_read_mem(traits<ARCH>::MEM, offs_val, 32/8),
64,
true);
if(fld_rd_val != 0){
Value* X_rd_val = res1_val;
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
Value* res2_val = this->builder->CreateXor(
res1_val,
this->gen_reg_load(fld_rs2_val, 0));
Value* MEM_offs_val = res2_val;
this->gen_write_mem(
traits<ARCH>::MEM,
offs_val,
this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32)));
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction AMOAND.W
std::tuple<vm::continuation_e, llvm::BasicBlock*> __amoand_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("AMOAND.W");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr));
uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr));
uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("AMOAND.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
Value* offs_val = this->gen_reg_load(fld_rs1_val, 0);
Value* res1_val = this->gen_ext(
this->gen_read_mem(traits<ARCH>::MEM, offs_val, 32/8),
64,
true);
if(fld_rd_val != 0){
Value* X_rd_val = res1_val;
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
Value* res2_val = this->builder->CreateAnd(
res1_val,
this->gen_reg_load(fld_rs2_val, 0));
Value* MEM_offs_val = res2_val;
this->gen_write_mem(
traits<ARCH>::MEM,
offs_val,
this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32)));
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction AMOOR.W
std::tuple<vm::continuation_e, llvm::BasicBlock*> __amoor_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("AMOOR.W");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr));
uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr));
uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("AMOOR.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
Value* offs_val = this->gen_reg_load(fld_rs1_val, 0);
Value* res1_val = this->gen_ext(
this->gen_read_mem(traits<ARCH>::MEM, offs_val, 32/8),
64,
true);
if(fld_rd_val != 0){
Value* X_rd_val = res1_val;
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
Value* res2_val = this->builder->CreateOr(
res1_val,
this->gen_reg_load(fld_rs2_val, 0));
Value* MEM_offs_val = res2_val;
this->gen_write_mem(
traits<ARCH>::MEM,
offs_val,
this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32)));
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction AMOMIN.W
std::tuple<vm::continuation_e, llvm::BasicBlock*> __amomin_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("AMOMIN.W");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr));
uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr));
uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("AMOMIN.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
Value* offs_val = this->gen_reg_load(fld_rs1_val, 0);
Value* res1_val = this->gen_ext(
this->gen_read_mem(traits<ARCH>::MEM, offs_val, 32/8),
64,
true);
if(fld_rd_val != 0){
Value* X_rd_val = res1_val;
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
Value* res2_val = this->gen_choose(
this->builder->CreateICmp(
ICmpInst::ICMP_SGT,
this->gen_ext(
res1_val,
64, true),
this->gen_ext(
this->gen_reg_load(fld_rs2_val, 0),
64, true)),
this->gen_reg_load(fld_rs2_val, 0),
res1_val,
64);
Value* MEM_offs_val = res2_val;
this->gen_write_mem(
traits<ARCH>::MEM,
offs_val,
this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32)));
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction AMOMAX.W
std::tuple<vm::continuation_e, llvm::BasicBlock*> __amomax_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("AMOMAX.W");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr));
uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr));
uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("AMOMAX.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
Value* offs_val = this->gen_reg_load(fld_rs1_val, 0);
Value* res1_val = this->gen_ext(
this->gen_read_mem(traits<ARCH>::MEM, offs_val, 32/8),
64,
true);
if(fld_rd_val != 0){
Value* X_rd_val = res1_val;
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
Value* res2_val = this->gen_choose(
this->builder->CreateICmp(
ICmpInst::ICMP_SLT,
this->gen_ext(
res1_val,
64, true),
this->gen_ext(
this->gen_reg_load(fld_rs2_val, 0),
64, true)),
this->gen_reg_load(fld_rs2_val, 0),
res1_val,
64);
Value* MEM_offs_val = res2_val;
this->gen_write_mem(
traits<ARCH>::MEM,
offs_val,
this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32)));
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction AMOMINU.W
std::tuple<vm::continuation_e, llvm::BasicBlock*> __amominu_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("AMOMINU.W");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr));
uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr));
uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("AMOMINU.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
Value* offs_val = this->gen_reg_load(fld_rs1_val, 0);
Value* res1_val = this->gen_ext(
this->gen_read_mem(traits<ARCH>::MEM, offs_val, 32/8),
64,
false);
if(fld_rd_val != 0){
Value* X_rd_val = res1_val;
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
Value* res2_val = this->gen_choose(
this->builder->CreateICmp(
ICmpInst::ICMP_UGT,
res1_val,
this->gen_reg_load(fld_rs2_val, 0)),
this->gen_reg_load(fld_rs2_val, 0),
res1_val,
64);
Value* MEM_offs_val = res2_val;
this->gen_write_mem(
traits<ARCH>::MEM,
offs_val,
this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32)));
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
// instruction AMOMAXU.W
std::tuple<vm::continuation_e, llvm::BasicBlock*> __amomaxu_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
bb->setName("AMOMAXU.W");
this->gen_sync(iss::PRE_SYNC);
uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr));
uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr));
uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr));
uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr));
uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr));
if(this->disass_enabled){
/* generate console output when executing the command */
boost::format ins_fmter("AMOMAXU.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)");
ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc=pc+4;
Value* offs_val = this->gen_reg_load(fld_rs1_val, 0);
Value* res1_val = this->gen_ext(
this->gen_read_mem(traits<ARCH>::MEM, offs_val, 32/8),
64,
false);
if(fld_rd_val != 0){
Value* X_rd_val = res1_val;
this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false);
}
Value* res2_val = this->gen_choose(
this->builder->CreateICmp(
ICmpInst::ICMP_ULT,
this->gen_ext(
res1_val,
64, false),
this->gen_ext(
this->gen_reg_load(fld_rs2_val, 0),
64, false)),
this->gen_reg_load(fld_rs2_val, 0),
res1_val,
64);
Value* MEM_offs_val = res2_val;
this->gen_write_mem(
traits<ARCH>::MEM,
offs_val,
this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32)));
this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */
this->gen_trap_check(bb);
return std::make_tuple(vm::CONT, bb);
}
/* end generated code */ /* end generated code */
/**************************************************************************** /****************************************************************************
* end opcode definitions * end opcode definitions
****************************************************************************/ ****************************************************************************/
std::tuple<vm::continuation_e, llvm::BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr, std::tuple<vm::continuation_e, llvm::BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr,
llvm::BasicBlock *bb) { llvm::BasicBlock *bb) {
// this->gen_sync(iss::PRE_SYNC); bb->setName("illegal_instruction");
this->builder->CreateStore(this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true),
get_reg_ptr(traits<ARCH>::PC), true); this->gen_sync(iss::PRE_SYNC);
this->builder->CreateStore( if(this->disass_enabled){
this->builder->CreateAdd(this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true), /* generate console output when executing the command */
this->gen_const(64U, 1)), /* generate console output when executing the command */
get_reg_ptr(traits<ARCH>::ICOUNT), true); boost::format ins_fmter("DB 0x%1$x");
if (this->debugging_enabled()) this->gen_sync(iss::PRE_SYNC); ins_fmter % (uint64_t)instr;
std::vector<llvm::Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder->CreateGlobalStringPtr(ins_fmter.str()),
};
this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
}
pc = pc + ((instr & 3) == 3 ? 4 : 2); pc = pc + ((instr & 3) == 3 ? 4 : 2);
this->gen_raise_trap(0, 2); // illegal instruction trap
this->gen_raise_trap(0, 2);
this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
this->gen_trap_check(this->leave_blk); this->gen_trap_check(this->leave_blk);
return std::make_tuple(iss::vm::BRANCH, nullptr); return std::make_tuple(iss::vm::BRANCH, nullptr);

View File

@ -54,23 +54,24 @@ int main(int argc, char *argv[]) {
// clang-format off // clang-format off
desc.add_options() desc.add_options()
("help,h", "Print help message") ("help,h", "Print help message")
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity") ("loglevel,l", po::value<int>()->implicit_value(2), "Sets logging verbosity")
("log-file", po::value<std::string>(), "Sets default log file.") ("logfile,f", po::value<std::string>(), "Sets default log file.")
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly") ("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
("elf,l", po::value<std::vector<std::string>>(), "ELF file(s) to load") ("elf", po::value<std::vector<std::string>>(), "ELF file(s) to load")
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use") ("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
("input,i", po::value<std::string>(), "the elf file to load (instead of hex files)") ("input,i", po::value<std::string>(), "the elf file to load (instead of hex files)")
("dump-ir", "dump the intermediate representation") ("dump-ir", "dump the intermediate representation")
("cycles,c", po::value<int64_t>()->default_value(-1), "number of cycles to run") ("cycles,c", po::value<int64_t>()->default_value(-1), "number of cycles to run")
("systemc,s", "Run as SystemC simulation") ("systemc,s", "Run as SystemC simulation")
("time", po::value<int>(), "SystemC siimulation time in ms") ("time", po::value<int>(), "SystemC simulation time in ms")
("reset,r", po::value<std::string>(), "reset address") ("reset,r", po::value<std::string>(), "reset address")
("trace", po::value<uint8_t>(), "enable tracing, or cmbintation of 1=signals and 2=TX text, 4=TX compressed text, 6=TX in SQLite") ("trace", po::value<uint8_t>(), "enable tracing, or cmbintation of 1=signals and 2=TX text, 4=TX compressed text, 6=TX in SQLite")
("mem,m", po::value<std::string>(), "the memory input file") ("mem,m", po::value<std::string>(), "the memory input file")
("rv64", "run RV64"); ("isa", po::value<std::string>()->default_value("rv32imac"), "isa to use for simulation");
// clang-format on // clang-format on
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
try { try {
po::store(po::parse_command_line(argc, argv, desc), clim); // can throw po::store(parsed, clim); // can throw
// --help option // --help option
if (clim.count("help")) { if (clim.count("help")) {
std::cout << "DBT-RISE-RiscV simulator for RISC-V" << std::endl << desc << std::endl; std::cout << "DBT-RISE-RiscV simulator for RISC-V" << std::endl << desc << std::endl;
@ -83,14 +84,16 @@ int main(int argc, char *argv[]) {
std::cerr << desc << std::endl; std::cerr << desc << std::endl;
return 1; return 1;
} }
if (clim.count("verbose")) { std::vector<std::string> args = collect_unrecognized(parsed.options, po::include_positional);
auto l = logging::as_log_level(clim["verbose"].as<int>());
if (clim.count("loglevel")) {
auto l = logging::as_log_level(clim["loglevel"].as<int>());
LOGGER(DEFAULT)::reporting_level() = l; LOGGER(DEFAULT)::reporting_level() = l;
LOGGER(connection)::reporting_level() = l; LOGGER(connection)::reporting_level() = l;
} }
if (clim.count("log-file")) { if (clim.count("logfile")) {
// configure the connection logger // configure the connection logger
auto f = fopen(clim["log-file"].as<std::string>().c_str(), "w"); auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w");
LOG_OUTPUT(DEFAULT)::stream() = f; LOG_OUTPUT(DEFAULT)::stream() = f;
LOG_OUTPUT(connection)::stream() = f; LOG_OUTPUT(connection)::stream() = f;
} }
@ -101,19 +104,21 @@ int main(int argc, char *argv[]) {
bool dump = clim.count("dump-ir"); bool dump = clim.count("dump-ir");
// instantiate the simulator // instantiate the simulator
std::unique_ptr<iss::vm_if> vm{nullptr}; std::unique_ptr<iss::vm_if> vm{nullptr};
if (clim.count("rv64") == 1) { if (clim["isa"].as<std::string>().substr(0, 4)=="rv64") {
auto cpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64ia>(); iss::arch::rv64ia* cpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64ia>();
vm = iss::create<iss::arch::rv64ia>(cpu, clim["gdb-port"].as<unsigned>(), dump); vm = iss::create(cpu, clim["gdb-port"].as<unsigned>(), dump);
} else if (clim["isa"].as<std::string>().substr(0, 4)=="rv32") {
iss::arch::rv32imac* cpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv32imac>();
vm = iss::create(cpu, clim["gdb-port"].as<unsigned>(), dump);
} else { } else {
auto cpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv32imac>(); LOG(ERROR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
vm = iss::create<iss::arch::rv32imac>(cpu, clim["gdb-port"].as<unsigned>(), dump); return 127;
} }
if (clim.count("elf")) { if (clim.count("elf"))
for (std::string input : clim["elf"].as<std::vector<std::string>>()) vm->get_arch()->load_file(input); for (std::string input : clim["elf"].as<std::vector<std::string>>()) vm->get_arch()->load_file(input);
} else if (clim.count("mem")) { if (clim.count("mem"))
vm->get_arch()->load_file(clim["mem"].as<std::string>(), iss::arch::traits<iss::arch::rv32imac>::MEM); vm->get_arch()->load_file(clim["mem"].as<std::string>(), iss::arch::traits<iss::arch::rv32imac>::MEM);
} for (std::string input : args) vm->get_arch()->load_file(input);// treat remaining arguments as elf files
if (clim.count("disass")) { if (clim.count("disass")) {
vm->setDisassEnabled(true); vm->setDisassEnabled(true);
LOGGER(disass)::reporting_level() = logging::INFO; LOGGER(disass)::reporting_level() = logging::INFO;