Added support for RV64I instructions

This commit is contained in:
Santosh Raghav Srivatsan 2021-11-27 12:33:30 -05:00
parent d1892bd6ec
commit 64d47f3637
9 changed files with 125 additions and 79 deletions

View file

@ -1,6 +1,6 @@
RISCV_TOOLCHAIN_PATH ?= /opt/riscv-gnu-toolchain
# simx64
RISCV64_TOOLCHAIN_PATH ?= /nethome/ssrivatsan8/riscv64-unknown-elf-toolchain
RISCV64_TOOLCHAIN_PATH ?= /nethome/ssrivatsan8/riscv
CC = $(RISCV64_TOOLCHAIN_PATH)/bin/riscv64-unknown-elf-gcc
@ -8,7 +8,7 @@ AR = $(RISCV64_TOOLCHAIN_PATH)/bin/riscv64-unknown-elf-gcc-ar
DP = $(RISCV64_TOOLCHAIN_PATH)/bin/riscv64-unknown-elf-objdump
CP = $(RISCV64_TOOLCHAIN_PATH)/bin/riscv64-unknown-elf-objcopy
CFLAGS += -O3 -march=rv64imfd -mabi=lp64d -Wstack-usage=1024 -fno-exceptions -fdata-sections -ffunction-sections
CFLAGS += -O3 -march=rv64i -mabi=lp64 -Wstack-usage=1024 -fno-exceptions -fdata-sections -ffunction-sections
CFLAGS += -I./include -I../hw
PROJECT = libvortexrt

View file

@ -22,7 +22,14 @@ inline uint64_t align_size(uint64_t size, uint64_t alignment) {
}
// Apply integer sign extension
inline uint32_t signExt(uint32_t w, uint32_t bit, uint32_t mask) {
inline uint64_t signExt(uint64_t w, uint64_t bit, uint64_t mask) {
if (w >> (bit - 1))
w |= ~mask;
return w;
}
// Apply integer sign extension
inline uint32_t signExt32(uint32_t w, uint32_t bit, uint32_t mask) {
if (w >> (bit - 1))
w |= ~mask;
return w;

View file

@ -14,8 +14,9 @@ public:
ArchDef(const std::string &/*arch*/,
int num_cores,
int num_warps,
int num_threads) {
wsize_ = 4;
int num_threads) {
// simx64
wsize_ = 8;
vsize_ = 16;
num_regs_ = 32;
num_csrs_ = 4096;

View file

@ -107,8 +107,12 @@ static const char* op_string(const Instr &instr) {
case 0: return "LBI";
case 1: return "LHI";
case 2: return "LW";
// simx64
case 3: return "LD";
case 4: return "LBU";
case 5: return "LHU";
// simx64
case 6: return "LWU";
default:
std::abort();
}
@ -117,6 +121,8 @@ static const char* op_string(const Instr &instr) {
case 0: return "SB";
case 1: return "SH";
case 2: return "SW";
// simx64
case 3: return "SD";
default:
std::abort();
}
@ -301,7 +307,7 @@ Decoder::Decoder(const ArchDef &arch) {
v_imm_mask_ = 0x7ff;
}
std::shared_ptr<Instr> Decoder::decode(Word code, Word PC) {
std::shared_ptr<Instr> Decoder::decode(uint32_t code, uint32_t PC) {
auto instr = std::make_shared<Instr>();
Opcode op = (Opcode)((code >> shift_opcode_) & opcode_mask_);
instr->setOpcode(op);
@ -310,10 +316,11 @@ std::shared_ptr<Instr> Decoder::decode(Word code, Word PC) {
Word func6 = (code >> shift_func6_) & func6_mask_;
Word func7 = (code >> shift_func7_) & func7_mask_;
int rd = (code >> shift_rd_) & reg_mask_;
int rs1 = (code >> shift_rs1_) & reg_mask_;
int rs2 = (code >> shift_rs2_) & reg_mask_;
int rs3 = (code >> shift_rs3_) & reg_mask_;
// simx64
long rd = (code >> shift_rd_) & reg_mask_;
long rs1 = (code >> shift_rs1_) & reg_mask_;
long rs2 = (code >> shift_rs2_) & reg_mask_;
long rs3 = (code >> shift_rs3_) & reg_mask_;
auto op_it = sc_instTable.find(op);
if (op_it == sc_instTable.end()) {
@ -371,7 +378,7 @@ std::shared_ptr<Instr> Decoder::decode(Word code, Word PC) {
instr->setFunc3(func3);
instr->setFunc7(func7);
if ((func3 == 5) && (op != L_INST) && (op != Opcode::FL)) {
instr->setImm(signExt(rs2, 5, reg_mask_));
instr->setImm(signExt(rs2, 6, 0x3F));
} else {
instr->setImm(signExt(code >> shift_rs2_, 12, i_imm_mask_));
}

View file

@ -13,7 +13,7 @@ class Decoder {
public:
Decoder(const ArchDef &);
std::shared_ptr<Instr> decode(Word code, Word PC);
std::shared_ptr<Instr> decode(uint32_t code, uint32_t PC);
private:

View file

@ -16,7 +16,7 @@
using namespace vortex;
static bool HasDivergentThreads(const ThreadMask &thread_mask,
const std::vector<std::vector<DoubleWord>> &reg_file,
const std::vector<std::vector<Word>> &reg_file,
unsigned reg) {
bool cond;
size_t thread_idx = 0;
@ -109,7 +109,8 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
rd_write = true;
break;
case AUIPC_INST:
rddata = ((immsrc << 12) & 0xfffff000) + PC_;
// simx64
rddata = signExt(((immsrc << 12) & 0xfffff000), 32, 0xFFFFFFFF) + PC_;
rd_write = true;
break;
case R_INST: {
@ -199,8 +200,10 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
switch (func3) {
case 0:
if (func7) {
// RV32I: SUB
rddata = rsdata[0] - rsdata[1];
} else {
// RV32I: ADD
rddata = rsdata[0] + rsdata[1];
}
break;
@ -211,25 +214,32 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
rddata = rsdata[0] << rsdata[1];
break;
case 2:
// RV32I: SLT (signed)
rddata = (WordI(rsdata[0]) < WordI(rsdata[1]));
break;
case 3:
// RV32I: SLTU (unsigned)
rddata = (Word(rsdata[0]) < Word(rsdata[1]));
break;
case 4:
// RV32I: XOR
rddata = rsdata[0] ^ rsdata[1];
break;
case 5:
if (func7) {
// RV32I: SRA
rddata = WordI(rsdata[0]) >> WordI(rsdata[1]);
} else {
// RV32I: SRL
rddata = Word(rsdata[0]) >> Word(rsdata[1]);
}
break;
case 6:
// RV32I: OR
rddata = rsdata[0] | rsdata[1];
break;
case 7:
// RV32I: AND
rddata = rsdata[0] & rsdata[1];
break;
default:
@ -241,42 +251,42 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
case I_INST:
switch (func3) {
case 0:
// ADDI
// RV32I: ADDI
rddata = rsdata[0] + immsrc;
break;
case 1:
// SLLI
// RV64I: SLLI
rddata = rsdata[0] << immsrc;
break;
case 2:
// SLTI
// RV32I: SLTI
rddata = (WordI(rsdata[0]) < WordI(immsrc));
break;
case 3: {
// SLTIU
// RV32I: SLTIU
rddata = (Word(rsdata[0]) < Word(immsrc));
} break;
case 4:
// XORI
// RV32I: XORI
rddata = rsdata[0] ^ immsrc;
break;
case 5:
if (func7) {
// SRAI
// RV64I: SRAI
Word result = WordI(rsdata[0]) >> immsrc;
rddata = result;
} else {
// SRLI
// RV64I: SRLI
Word result = Word(rsdata[0]) >> immsrc;
rddata = result;
}
break;
case 6:
// ORI
// RV32I: ORI
rddata = rsdata[0] | immsrc;
break;
case 7:
// ANDI
// RV32I: ANDI
rddata = rsdata[0] & immsrc;
break;
default:
@ -287,37 +297,37 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
case B_INST:
switch (func3) {
case 0:
// BEQ
// RV32I: BEQ
if (rsdata[0] == rsdata[1]) {
nextPC = PC_ + immsrc;
}
break;
case 1:
// BNE
// RV32I: BNE
if (rsdata[0] != rsdata[1]) {
nextPC = PC_ + immsrc;
}
break;
case 4:
// BLT
// RV32I: BLT
if (WordI(rsdata[0]) < WordI(rsdata[1])) {
nextPC = PC_ + immsrc;
}
break;
case 5:
// BGE
// RV32I: BGE
if (WordI(rsdata[0]) >= WordI(rsdata[1])) {
nextPC = PC_ + immsrc;
}
break;
case 6:
// BLTU
// RV32I: BLTU
if (Word(rsdata[0]) < Word(rsdata[1])) {
nextPC = PC_ + immsrc;
}
break;
case 7:
// BGEU
// RV32I: BGEU
if (Word(rsdata[0]) >= Word(rsdata[1])) {
nextPC = PC_ + immsrc;
}
@ -326,6 +336,7 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
pipeline->stall_warp = true;
runOnce = true;
break;
// RV32I: JAL
case JAL_INST:
rddata = nextPC;
nextPC = PC_ + immsrc;
@ -333,9 +344,10 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
runOnce = true;
rd_write = true;
break;
// RV32I: JALR
case JALR_INST:
rddata = nextPC;
nextPC = rsdata[0] + immsrc;
nextPC = HalfWord(rsdata[0]) + HalfWord(immsrc);
pipeline->stall_warp = true;
runOnce = true;
rd_write = true;
@ -343,29 +355,37 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
case L_INST: {
Word memAddr = ((rsdata[0] + immsrc) & 0xFFFFFFFC); // word aligned
Word shift_by = ((rsdata[0] + immsrc) & 0x00000003) * 8;
Word data_read = core_->dcache_read(memAddr, 4);
Word data_read = core_->dcache_read(memAddr, 8);
D(3, "LOAD MEM: ADDRESS=0x" << std::hex << memAddr << ", DATA=0x" << data_read);
switch (func3) {
case 0:
// LBI
// RV32I: LBI
rddata = signExt((data_read >> shift_by) & 0xFF, 8, 0xFF);
break;
case 1:
// LHI
// RV32I: LHI
rddata = signExt((data_read >> shift_by) & 0xFFFF, 16, 0xFFFF);
break;
case 2:
// LW
// RV32I: LW
rddata = signExt((data_read >> shift_by) & 0xFFFFFFFF, 32, 0xFFFFFFFF);
break;
case 3:
// RV64I: LD
rddata = data_read;
break;
case 4:
// LBU
// RV32I: LBU
rddata = Word((data_read >> shift_by) & 0xFF);
break;
case 5:
// LHU
// RV32I: LHU
rddata = Word((data_read >> shift_by) & 0xFFFF);
break;
case 6:
// RV64I: LWU
rddata = Word((data_read >> shift_by) & 0xFFFFFFFF);
break;
default:
std::abort();
}
@ -376,16 +396,20 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
D(3, "STORE MEM: ADDRESS=0x" << std::hex << memAddr);
switch (func3) {
case 0:
// SB
// RV32I: SB
core_->dcache_write(memAddr, rsdata[1] & 0x000000FF, 1);
break;
case 1:
// SH
core_->dcache_write(memAddr, rsdata[1], 2);
// RV32I: SH
core_->dcache_write(memAddr, rsdata[1] & 0x0000FFFF, 2);
break;
case 2:
// SW
core_->dcache_write(memAddr, rsdata[1], 4);
// RV32I: SW
core_->dcache_write(memAddr, rsdata[1] & 0xFFFFFFFF, 4);
break;
case 3:
// RV64I: SD
core_ ->dcache_write(memAddr, rsdata[1], 8);
break;
default:
std::abort();
@ -396,65 +420,68 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
switch (func3) {
case 0:
if (func7){
// SUBW
rddata = DoubleWord(rsdata[0] - rsdata[1]);
// RV64I: SUBW
rddata = signExt((HalfWord)rsdata[0] - (HalfWord)rsdata[1], 32, 0xFFFFFFFF);
}
else{
// ADDW
rddata = DoubleWord(rsdata[0] + rsdata[1]);
// RV64I: ADDW
rddata = signExt((HalfWord)rsdata[0] + (HalfWord)rsdata[1], 32, 0xFFFFFFFF);
}
break;
case 1:
// SLLW
// RV64I: SLLW
// shift amount given by rs2[4:0]
rddata = DoubleWord(rsdata[0] << rsdata[1]);
rddata = signExt((HalfWord)rsdata[0] << (HalfWord)rsdata[1], 32, 0xFFFFFFFF);
break;
case 5:
if (func7) {
// SRAW
// RV64I: SRAW
// shift amount given by rs2[4:0]
rddata = DoubleWord(WordI(rsdata[0]) >> WordI(rsdata[1]));
rddata = signExt((HalfWordI)rsdata[0] >> (HalfWordI)rsdata[1], 32, 0xFFFFFFFF);
} else {
// SRLW
// RV64I: SRLW
// shift amount given by rs2[4:0]
rddata = DoubleWord(Word(rsdata[0]) >> Word(rsdata[1]));
rddata = signExt((HalfWord)rsdata[0] >> (HalfWord)rsdata[1], 32, 0xFFFFFFFF);
}
break;
default:
std::abort();
}
rd_write = true;
} break;
// simx64
case I_INST_64: {
switch (func3) {
case 0:
// ADDIW
rddata = DoubleWord(rsdata[0] + immsrc);
// RV64I: ADDIW
rddata = signExt((HalfWord)rsdata[0] + (HalfWord)immsrc, 32, 0xFFFFFFFF);
printf("rddata\n");
break;
case 1:
// SLLIW
// RV64I: SLLIW
// rs1 shifted by lower 5 bits of imm
// Illegal exception if imm[5] != 0
rddata = DoubleWord(rsdata[0] << immsrc);
rddata = signExt((HalfWord)rsdata[0] << (HalfWord)immsrc, 32, 0xFFFFFFFF);
break;
case 5:
if (func7) {
// SRAI
// RV64I: SRAI
// rs1 shifted by lower 5 bits of imm
// Illegal exception if imm[5] != 0
Word result = DoubleWord(WordI(rsdata[0]) >> immsrc);
Word result = signExt((HalfWordI)rsdata[0] >> (HalfWordI)immsrc, 32, 0xFFFFFFFF);
rddata = result;
} else {
// SRLI
// RV64I: SRLI
// rs1 shifted by lower 5 bits of imm
// Illegal exception if imm[5] != 0
Word result = DoubleWord(Word(rsdata[0]) >> immsrc);
Word result = signExt((HalfWord)rsdata[0] >> (HalfWord)immsrc, 32, 0xFFFFFFFF);
rddata = result;
}
break;
default:
std::abort();
}
rd_write = true;
} break;
case SYS_INST: {
Word csr_addr = immsrc & 0x00000FFF;
@ -467,37 +494,37 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
}
break;
case 1:
// CSRRW
// RV32I: CSRRW
rddata = csr_value;
core_->set_csr(csr_addr, rsdata[0], t, id_);
rd_write = true;
break;
case 2:
// CSRRS
// RV32I: CSRRS
rddata = csr_value;
core_->set_csr(csr_addr, csr_value | rsdata[0], t, id_);
rd_write = true;
break;
case 3:
// CSRRC
// RV32I: CSRRC
rddata = csr_value;
core_->set_csr(csr_addr, csr_value & ~rsdata[0], t, id_);
rd_write = true;
break;
case 5:
// CSRRWI
// RV32I: CSRRWI
rddata = csr_value;
core_->set_csr(csr_addr, rsrc0, t, id_);
rd_write = true;
break;
case 6:
// CSRRSI
// RV32I: CSRRSI
rddata = csr_value;
core_->set_csr(csr_addr, csr_value | rsrc0, t, id_);
rd_write = true;
break;
case 7:
// CSRRCI
// RV32I: CSRRCI
rddata = csr_value;
core_->set_csr(csr_addr, csr_value & ~rsrc0, t, id_);
rd_write = true;
@ -506,6 +533,7 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
break;
}
} break;
// RV32I: FENCE
case FENCE:
pipeline->stall_warp = true;
runOnce = true;
@ -661,20 +689,21 @@ void Warp::execute(const Instr &instr, Pipeline *pipeline) {
case FMSUB:
case FMNMADD:
case FMNMSUB: {
int frm = get_fpu_rm(func3, core_, t, id_);
// int frm = get_fpu_rm(func3, core_, t, id_);
// simx64
Word fflags = 0;
switch (opcode) {
case FMADD:
rddata = rv_fmadd(rsdata[0], rsdata[1], rsdata[2], frm, &fflags);
// rddata = rv_fmadd(rsdata[0], rsdata[1], rsdata[2], frm, &fflags);
break;
case FMSUB:
rddata = rv_fmsub(rsdata[0], rsdata[1], rsdata[2], frm, &fflags);
// rddata = rv_fmsub(rsdata[0], rsdata[1], rsdata[2], frm, &fflags);
break;
case FMNMADD:
rddata = rv_fnmadd(rsdata[0], rsdata[1], rsdata[2], frm, &fflags);
// rddata = rv_fnmadd(rsdata[0], rsdata[1], rsdata[2], frm, &fflags);
break;
case FMNMSUB:
rddata = rv_fnmsub(rsdata[0], rsdata[1], rsdata[2], frm, &fflags);
// rddata = rv_fnmsub(rsdata[0], rsdata[1], rsdata[2], frm, &fflags);
break;
default:
break;

View file

@ -7,13 +7,15 @@
namespace vortex {
typedef uint8_t Byte;
typedef uint32_t Word;
typedef int32_t WordI;
// simx64
typedef uint64_t DoubleWord;
typedef uint64_t Word;
typedef int64_t WordI;
// simx64
typedef uint64_t Addr;
typedef uint32_t HalfWord;
typedef int32_t HalfWordI;
// simx64
typedef uint32_t Addr;
typedef uint32_t Size;
typedef std::bitset<32> RegMask;

View file

@ -14,8 +14,8 @@ Warp::Warp(Core *core, Word id)
: id_(id)
, core_(core) {
// simx64
iRegFile_.resize(core_->arch().num_threads(), std::vector<DoubleWord>(core_->arch().num_regs(), 0));
fRegFile_.resize(core_->arch().num_threads(), std::vector<DoubleWord>(core_->arch().num_regs(), 0));
iRegFile_.resize(core_->arch().num_threads(), std::vector<Word>(core_->arch().num_regs(), 0));
fRegFile_.resize(core_->arch().num_threads(), std::vector<Word>(core_->arch().num_regs(), 0));
vRegFile_.resize(core_->arch().num_regs(), std::vector<Byte>(core_->arch().vsize(), 0));
this->clear();
}

View file

@ -99,8 +99,8 @@ private:
ThreadMask tmask_;
// simx64
std::vector<std::vector<DoubleWord>> iRegFile_;
std::vector<std::vector<DoubleWord>> fRegFile_;
std::vector<std::vector<Word>> iRegFile_;
std::vector<std::vector<Word>> fRegFile_;
std::vector<std::vector<Byte>> vRegFile_;
std::stack<DomStackEntry> domStack_;