Implement handling of RV64 instructions in RV components
MODIFY
external/VSRTL
external/VSRTL
-Subproject commit 15e816d5d184272c8b1ebc913eeaa958ad408ffe
+Subproject commit 45237b8882ce10d1db6010c44da11752f94be133

MODIFY
src/assembler/rv64i_assembler.cpp
src/assembler/rv64i_assembler.cpp
@@ -63,6 +63,10 @@ void RV64I_Assembler::enableExtI(const ISAInfoBase* isa, InstrVec& instructions,
instructions.push_back(RType32(Token("sllw"), 0b001, 0b0000000));
instructions.push_back(RType32(Token("srlw"), 0b101, 0b0000000));
instructions.push_back(RType32(Token("sraw"), 0b101, 0b0100000));
+
+ instructions.push_back(LoadType(Token("lwu"), 0b110));
+ instructions.push_back(LoadType(Token("ld"), 0b011));
+ instructions.push_back(LoadType(Token("sd"), 0b011));
}
void RV64I_Assembler::enableExtM(const ISAInfoBase* isa, InstrVec& instructions, PseudoInstrVec& pseudoInstructions) {

MODIFY
src/processors/RISC-V/riscv.h
src/processors/RISC-V/riscv.h
#include "VSRTL/core/vsrtl_enum.h"
#include "VSRTL/interface/vsrtl_binutils.h"
-#include "VSRTL/interface/vsrtl_defines.h"
#include "VSRTL/interface/vsrtl_interface.h"
#include "rv_instrparser.h"
@@ -22,6 +21,7 @@ namespace Ripes {
template <unsigned XLEN>
constexpr Ripes::ISA XLenToRVISA() {
static_assert(XLEN == 32 || XLEN == 64, "Only supports 32- and 64-bit variants");
+ static_assert(vsrtl::VSRTL_VT_BITS >= XLEN, "Register size larger than VSRTL base type size");
if (XLEN == 32) {
return ISA::RV32I;
} else {
@@ -38,16 +38,22 @@ Enum(RVInstr, NOP,
ORI, ANDI, SLLI, SRLI, SRAI, ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND, ECALL,
/* RV32M Standard Extension */
- MUL, MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU);
+ MUL, MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU,
+
+ /* RV64I Base Instruction Set */
+ ADDIW, SLLIW, SRLIW, SRAIW, ADDW, SUBW, SLLW, SRLW, SRAW, LWU, LD, SD,
+
+ /* RV64M Standard Extension */
+ MULW, DIVW, DIVUW, REMW, REMUW);
/** Datapath enumerations */
-Enum(ALUOp, NOP, ADD, SUB, MUL, DIV, AND, OR, XOR, SL, SRA, SRL, LUI, LT, LTU, EQ, MULH, MULHU, MULHSU, DIVU, REM,
- REMU);
+Enum(ALUOp, NOP, ADD, SUB, MUL, DIV, AND, OR, XOR, SL, SRA, SRL, LUI, LT, LTU, EQ, MULH, MULHU, MULHSU, DIVU, REM, REMU,
+ SLW, SRLW, SRAW, ADDW, SUBW, MULW, DIVW, DIVUW, REMW, REMUW);
Enum(RegWrSrc, MEMREAD, ALURES, PC4);
Enum(AluSrc1, REG1, PC);
Enum(AluSrc2, REG2, IMM);
Enum(CompOp, NOP, EQ, NE, LT, LTU, GE, GEU);
-Enum(MemOp, NOP, LB, LH, LW, LBU, LHU, SB, SH, SW);
+Enum(MemOp, NOP, LB, LH, LW, LBU, LHU, SB, SH, SW, LWU, LD, SD);
Enum(ECALL, none, print_int = 1, print_char = 2, print_string = 4, exit = 10);
Enum(PcSrc, PC4 = 0, ALU = 1);

MODIFY
src/processors/RISC-V/rv_alu.h
src/processors/RISC-V/rv_alu.h
#pragma once
#include <math.h>
+#include "limits.h"
#include "riscv.h"
@@ -10,6 +11,9 @@ namespace vsrtl {
namespace core {
using namespace Ripes;
+#define DIV_OVERFLOW32 (-2147483648) //-2^(32-1)
+#define DIV_OVERFLOW64 (LLONG_MIN) //-2^(64-1)
+
template <unsigned XLEN>
class ALU : public Component {
public:
@@ -35,40 +39,68 @@ public:
const int64_t result = static_cast<int64_t>(op1.sValue()) * static_cast<uint64_t>(op2.uValue());
return VT_U(result >> 32);
}
- case ALUOp::DIV:
+
+ case ALUOp::DIVW:
+ case ALUOp::DIV: {
+ const VSRTL_VT_S overflow =
+ (ctrl.uValue() == ALUOp::DIVW) || (ctrl.uValue() == ALUOp::DIV && XLEN == 32) ? DIV_OVERFLOW32
+ : DIV_OVERFLOW64;
if (op2.sValue() == 0) {
return VT_U(-1);
- } else if (op1.sValue() == static_cast<int64_t>(-(std::pow(2, 32 - 1))) && op2.sValue() == -1) {
+ } else if (op1.sValue() == overflow && op2.sValue() == -1) {
// Overflow
- return VT_U(0x80000000); // -2^(32-1)
+ return VT_U(overflow);
} else {
return VT_U(op1.sValue() / op2.sValue());
}
+ }
- case ALUOp::DIVU:
- if (op2.sValue() == 0) {
- return VT_U(std::pow(2, 32) - 1);
+ case ALUOp::DIVUW:
+ case ALUOp::DIVU: {
+ if (op2.uValue() == 0) {
+ return VT_U(-1LL);
} else {
return op1.uValue() / op2.uValue();
}
+ }
- case ALUOp::REM:
+ case ALUOp::REMW:
+ case ALUOp::REM: {
+ const VSRTL_VT_S overflow =
+ (ctrl.uValue() == ALUOp::REMW) || (ctrl.uValue() == ALUOp::REM && XLEN == 32) ? DIV_OVERFLOW32
+ : DIV_OVERFLOW64;
if (op2.sValue() == 0) {
return op1.uValue();
- } else if (op1.sValue() == static_cast<int64_t>(-(std::pow(2, 32 - 1))) && op2.sValue() == -1) {
+ } else if (op1.sValue() == overflow && op2.sValue() == -1) {
// Overflow
return VT_U(0);
} else {
return VT_U(op1.sValue() % op2.sValue());
}
+ }
- case ALUOp::REMU:
+ case ALUOp::REMUW:
+ case ALUOp::REMU: {
+ const VSRTL_VT_S overflow =
+ (ctrl.uValue() == ALUOp::REMUW) || (ctrl.uValue() == ALUOp::REMU && XLEN == 32)
+ ? DIV_OVERFLOW32
+ : DIV_OVERFLOW64;
if (op2.uValue() == 0) {
return op1.uValue();
} else {
return op1.uValue() % op2.uValue();
}
+ if (op2.sValue() == 0) {
+ return VT_U(-1);
+ } else if (op1.sValue() == overflow && op2.sValue() == -1) {
+ // Overflow
+ return VT_U(overflow);
+ } else {
+ return VT_U(op1.sValue() / op2.sValue());
+ }
+ }
+
case ALUOp::AND:
return op1.uValue() & op2.uValue();
@@ -99,6 +131,21 @@ public:
case ALUOp::NOP:
return VT_U(0xDEADBEEF);
+ case ALUOp::ADDW:
+ return signextend<VSRTL_VT_U, 32>(op1.uValue() + op2.uValue());
+
+ case ALUOp::SUBW:
+ return signextend<VSRTL_VT_U, 32>(op1.uValue() - op2.uValue());
+
+ case ALUOp::SLW:
+ return signextend<VSRTL_VT_U, 32>(op1.uValue() << (op2.uValue() & generateBitmask(5)));
+
+ case ALUOp::SRAW:
+ return signextend<VSRTL_VT_U, 32>(op1.sValue() >> (op2.uValue() & generateBitmask(5)));
+
+ case ALUOp::SRLW:
+ return signextend<VSRTL_VT_U, 32>(op1.uValue() >> (op2.uValue() & generateBitmask(5)));
+
default:
throw std::runtime_error("Invalid ALU opcode");
}

MODIFY
src/processors/RISC-V/rv_control.h
src/processors/RISC-V/rv_control.h
@@ -46,11 +46,14 @@ public:
case RVInstr::SB: return MemOp::SB;
case RVInstr::SH: return MemOp::SH;
case RVInstr::SW: return MemOp::SW;
+ case RVInstr::SD: return MemOp::SD;
case RVInstr::LB: return MemOp::LB;
case RVInstr::LH: return MemOp::LH;
case RVInstr::LW: return MemOp::LW;
+ case RVInstr::LD: return MemOp::LD;
case RVInstr::LBU: return MemOp::LBU;
case RVInstr::LHU: return MemOp::LHU;
+ case RVInstr::LWU: return MemOp::LWU;
default:
return MemOp::NOP;
}
@@ -64,17 +67,21 @@ public:
// Arithmetic-immediate instructions
case RVInstr::ADDI: case RVInstr::SLTI: case RVInstr::SLTIU: case RVInstr::XORI:
case RVInstr::ORI: case RVInstr::ANDI: case RVInstr::SLLI: case RVInstr::SRLI:
- case RVInstr::SRAI:
+ case RVInstr::SRAI: case RVInstr::ADDIW: case RVInstr::SLLIW: case RVInstr::SRLIW:
+ case RVInstr::SRAIW:
// Arithmetic instructions
case RVInstr::MUL: case RVInstr::MULH: case RVInstr:: MULHSU: case RVInstr::MULHU:
case RVInstr::DIV: case RVInstr::DIVU: case RVInstr::REM: case RVInstr::REMU:
case RVInstr::ADD: case RVInstr::SUB: case RVInstr::SLL: case RVInstr::SLT:
case RVInstr::SLTU: case RVInstr::XOR: case RVInstr::SRL: case RVInstr::SRA:
- case RVInstr::OR: case RVInstr::AND:
+ case RVInstr::OR: case RVInstr::AND: case RVInstr::ADDW: case RVInstr::SUBW:
+ case RVInstr::SLLW: case RVInstr::SRLW: case RVInstr::SRAW: case RVInstr::MULW:
+ case RVInstr::DIVW: case RVInstr::DIVUW: case RVInstr::REMW: case RVInstr::REMUW:
// Load instructions
case RVInstr::LB: case RVInstr::LH: case RVInstr::LW: case RVInstr::LBU: case RVInstr::LHU:
+ case RVInstr::LWU: case RVInstr::LD:
// Jump instructions
case RVInstr::JALR:
@@ -87,7 +94,8 @@ public:
static RegWrSrc do_reg_wr_src_ctrl(const VSRTL_VT_U& opc) {
switch(opc){
// Load instructions
- case RVInstr::LB: case RVInstr::LH: case RVInstr::LW: case RVInstr::LBU: case RVInstr::LHU:
+ case RVInstr::LB: case RVInstr::LH: case RVInstr::LW: case RVInstr::LBU:
+ case RVInstr::LHU: case RVInstr::LWU: case RVInstr::LD:
return RegWrSrc::MEMREAD;
// Jump instructions
@@ -120,7 +128,8 @@ public:
// Arithmetic-immediate instructions
case RVInstr::ADDI: case RVInstr::SLTI: case RVInstr::SLTIU: case RVInstr::XORI:
case RVInstr::ORI: case RVInstr::ANDI: case RVInstr::SLLI: case RVInstr::SRLI:
- case RVInstr::SRAI:
+ case RVInstr::SRAI: case RVInstr::ADDIW: case RVInstr::SLLIW: case RVInstr::SRLIW:
+ case RVInstr::SRAIW:
return AluSrc2::IMM;
// Arithmetic instructions
@@ -128,12 +137,15 @@ public:
case RVInstr::DIV: case RVInstr::DIVU: case RVInstr::REM: case RVInstr::REMU:
case RVInstr::ADD: case RVInstr::SUB: case RVInstr::SLL: case RVInstr::SLT:
case RVInstr::SLTU: case RVInstr::XOR: case RVInstr::SRL: case RVInstr::SRA:
- case RVInstr::OR: case RVInstr::AND:
+ case RVInstr::OR: case RVInstr::AND: case RVInstr::ADDW: case RVInstr::SUBW:
+ case RVInstr::SLLW: case RVInstr::SRLW: case RVInstr::SRAW: case RVInstr::MULW:
+ case RVInstr::DIVW: case RVInstr::DIVUW: case RVInstr::REMW: case RVInstr::REMUW:
return AluSrc2::REG2;
// Load/Store instructions
case RVInstr::LB: case RVInstr::LH: case RVInstr::LW: case RVInstr::LBU: case RVInstr::LHU:
- case RVInstr::SB: case RVInstr::SH: case RVInstr::SW:
+ case RVInstr::SB: case RVInstr::SH: case RVInstr::SW: case RVInstr::LWU: case RVInstr::LD:
+ case RVInstr::SD:
return AluSrc2::IMM;
// Branch instructions
@@ -154,7 +166,8 @@ public:
static ALUOp do_alu_ctrl(const VSRTL_VT_U& opc) {
switch(opc) {
case RVInstr::LB: case RVInstr::LH: case RVInstr::LW: case RVInstr::LBU: case RVInstr::LHU:
- case RVInstr::SB: case RVInstr::SH: case RVInstr::SW:
+ case RVInstr::SB: case RVInstr::SH: case RVInstr::SW: case RVInstr::LWU: case RVInstr::LD:
+ case RVInstr::SD:
return ALUOp::ADD;
case RVInstr::LUI:
return ALUOp::LUI;
@@ -163,8 +176,7 @@ public:
case RVInstr::BEQ: case RVInstr::BNE: case RVInstr::BLT:
case RVInstr::BGE: case RVInstr::BLTU: case RVInstr::BGEU:
return ALUOp::ADD;
- case RVInstr::SUB:
- return ALUOp::SUB;
+ case RVInstr::SUB: return ALUOp::SUB;
case RVInstr::SLT: case RVInstr::SLTI:
return ALUOp::LT;
case RVInstr::SLTU: case RVInstr::SLTIU:
@@ -181,29 +193,36 @@ public:
return ALUOp::SRL;
case RVInstr::SRA: case RVInstr::SRAI:
return ALUOp::SRA;
- case RVInstr::MUL:
- return ALUOp::MUL;
- case RVInstr::MULH:
- return ALUOp::MULH;
- case RVInstr::MULHU:
- return ALUOp::MULHU;
- case RVInstr::MULHSU:
- return ALUOp::MULHSU;
- case RVInstr::DIV:
- return ALUOp::DIV;
- case RVInstr::DIVU:
- return ALUOp::DIVU;
- case RVInstr::REM:
- return ALUOp::REM;
- case RVInstr::REMU:
- return ALUOp::REMU;
+ case RVInstr::MUL : return ALUOp::MUL;
+ case RVInstr::MULH : return ALUOp::MULH;
+ case RVInstr::MULHU : return ALUOp::MULHU;
+ case RVInstr::MULHSU: return ALUOp::MULHSU;
+ case RVInstr::DIV : return ALUOp::DIV;
+ case RVInstr::DIVU : return ALUOp::DIVU;
+ case RVInstr::REM : return ALUOp::REM;
+ case RVInstr::REMU : return ALUOp::REMU;
+ case RVInstr::ADDIW : return ALUOp::ADDW;
+ case RVInstr::SLLIW : return ALUOp::SLW;
+ case RVInstr::SRLIW : return ALUOp::SRLW;
+ case RVInstr::SRAIW : return ALUOp::SRAW;
+ case RVInstr::ADDW : return ALUOp::ADDW ;
+ case RVInstr::SUBW : return ALUOp::SUBW ;
+ case RVInstr::SLLW : return ALUOp::SLW ;
+ case RVInstr::SRLW : return ALUOp::SRLW ;
+ case RVInstr::SRAW : return ALUOp::SRAW ;
+ case RVInstr::MULW : return ALUOp::MULW ;
+ case RVInstr::DIVW : return ALUOp::DIVW ;
+ case RVInstr::DIVUW : return ALUOp::DIVUW;
+ case RVInstr::REMW : return ALUOp::REMW ;
+ case RVInstr::REMUW : return ALUOp::REMUW;
+
default: return ALUOp::NOP;
}
}
static VSRTL_VT_U do_do_mem_write_ctrl(const VSRTL_VT_U& opc) {
switch(opc) {
- case RVInstr::SB: case RVInstr::SH: case RVInstr::SW:
+ case RVInstr::SB: case RVInstr::SH: case RVInstr::SW: case RVInstr::SD:
return 1;
default: return 0;
}
@@ -211,7 +230,8 @@ public:
static VSRTL_VT_U do_do_read_ctrl(const VSRTL_VT_U& opc) {
switch(opc) {
- case RVInstr::LB: case RVInstr::LH: case RVInstr::LW: case RVInstr::LBU: case RVInstr::LHU:
+ case RVInstr::LB: case RVInstr::LH: case RVInstr::LW: case RVInstr::LBU:
+ case RVInstr::LHU: case RVInstr::LWU: case RVInstr::LD:
return 1;
default: return 0;
}

MODIFY
src/processors/RISC-V/rv_decode.h
src/processors/RISC-V/rv_decode.h
@@ -46,10 +46,27 @@ public:
break;
}
+ case RVISA::Opcode::OPIMM32: {
+ // I-Type (32-bit, in 64-bit ISA)
+ const auto fields = RVInstrParser::getParser()->decodeI32Instr(instr.uValue());
+ switch(fields[2]) {
+ case 0b000: return RVInstr::ADDIW;
+ case 0b001: return RVInstr::SLLIW;
+ case 0b101: {
+ switch (fields[0]) {
+ case 0b0000000: return RVInstr::SRLIW;
+ case 0b0100000: return RVInstr::SRAIW;
+ }
+ }
+ default: break;
+ }
+ break;
+ }
+
case RVISA::Opcode::OP: {
// R-Type
const auto fields = RVInstrParser::getParser()->decodeR32Instr(instr.uValue());
- if (fields[0] == 0b1) {
+ if (fields[0] == 0b0000001) {
if(m_isa && m_isa->extensionEnabled("M")) {
// RV32M Standard extension
switch (fields[3]) {
@@ -91,7 +108,45 @@ public:
break;
}
break;
+ }
+ case RVISA::Opcode::OP32: {
+ // R-Type (32-bit, in 64-bit ISA)
+ const auto fields = RVInstrParser::getParser()->decodeR32Instr(instr.uValue());
+ if (fields[0] == 0b0000001) {
+ if(m_isa && m_isa->extensionEnabled("M")) {
+ // RV64M Standard extension
+ switch (fields[3]) {
+ case 0b000: return RVInstr::MULW;
+ case 0b100: return RVInstr::DIVW;
+ case 0b101: return RVInstr::DIVUW;
+ case 0b110: return RVInstr::REMW;
+ case 0b111: return RVInstr::REMUW;
+ default: break;
+ }
+ }
+ } else {
+ switch (fields[3]) {
+ case 0b000: {
+ switch (fields[0]) {
+ case 0b0000000: return RVInstr::ADDW;
+ case 0b0100000: return RVInstr::SUBW;
+ default: return RVInstr::NOP;
+ }
+ }
+ case 0b001: return RVInstr::SLLW;
+ case 0b101: {
+ switch (fields[0]) {
+ case 0b0000000: return RVInstr::SRLW;
+ case 0b0100000: return RVInstr::SRAW;
+ default: return RVInstr::NOP;
+ }
+ }
+ default: break;
+ }
+ break;
+ }
+ break;
}
case RVISA::Opcode::LOAD: {
@@ -103,6 +158,8 @@ public:
case 0b010: return RVInstr::LW;
case 0b100: return RVInstr::LBU;
case 0b101: return RVInstr::LHU;
+ case 0b110: return RVInstr::LWU;
+ case 0b011: return RVInstr::LD;
default: break;
}
break;
@@ -115,6 +172,7 @@ public:
case 0b000: return RVInstr::SB;
case 0b001: return RVInstr::SH;
case 0b010: return RVInstr::SW;
+ case 0b011: return RVInstr::SD;
default: break;
}
break;

MODIFY
src/processors/RISC-V/rv_immediate.h
src/processors/RISC-V/rv_immediate.h
@@ -40,6 +40,8 @@ public:
case RVInstr::LW:
case RVInstr::LBU:
case RVInstr::LHU:
+ case RVInstr::LWU:
+ case RVInstr::LD:
case RVInstr::ADDI:
case RVInstr::SLTI:
case RVInstr::SLTIU:
@@ -52,7 +54,8 @@ public:
return VT_U(signextend<int32_t, 12>((instr.uValue() >> 20)));
case RVInstr::SB:
case RVInstr::SH:
- case RVInstr::SW: {
+ case RVInstr::SW:
+ case RVInstr::SD: {
return VT_U(signextend<int32_t, 12>(((instr.uValue() & 0xfe000000)) >> 20) |
((instr.uValue() & 0xf80) >> 7));
}

MODIFY
src/processors/RISC-V/rv_memory.h
src/processors/RISC-V/rv_memory.h
@@ -26,6 +26,8 @@ public:
return 2;
case MemOp::SW:
return 4;
+ case MemOp::SD:
+ return 8;
default:
return 0;
}
@@ -35,14 +37,18 @@ public:
data_out << [=] {
switch (op.uValue()) {
case MemOp::LB:
- return VT_U(signextend<int32_t, 8>(mem->data_out.uValue() & 0xFF));
+ return VT_U(signextend<VSRTL_VT_U, 8>(mem->data_out.uValue() & 0xFFUL));
case MemOp::LBU:
- return mem->data_out.uValue() & 0xFF;
+ return mem->data_out.uValue() & 0xFFUL;
case MemOp::LH:
- return VT_U(signextend<int32_t, 16>(mem->data_out.uValue() & 0xFFFF));
+ return VT_U(signextend<VSRTL_VT_U, 16>(mem->data_out.uValue() & 0xFFFFUL));
case MemOp::LHU:
- return mem->data_out.uValue() & 0xFFFF;
+ return mem->data_out.uValue() & 0xFFFFUL;
case MemOp::LW:
+ return mem->data_out.uValue() & 0xFFFFFFFFUL;
+ case MemOp::LWU:
+ return VT_U(signextend<VSRTL_VT_U, 32>(mem->data_out.uValue() & 0xFFFFFFFFUL));
+ case MemOp::LD:
return mem->data_out.uValue();
default:
return mem->data_out.uValue();

Implement handling of RV64 instructions in RV components