Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split register info class into multiple classes; one per register file #320

Merged
merged 17 commits into from
Nov 26, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 65 additions & 38 deletions src/cli/clioptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ void addCLIOptions(QCommandLineParser &parser, Ripes::CLIModeOptions &options) {
parser.addOption(QCommandLineOption(
"reginit",
"Comma-separated list of register initialization values. The register "
"value may be specified in signed, hex, or boolean notation. Format:\n"
"<register idx>=<value>,<register idx>=<value>",
"[rid:v]"));
"value may be specified in signed, hex, or boolean notation. Can be used "
"multiple times to initialize more than one register file type. Format:\n"
"<register file>:<register idx>=<value>,<register idx>=<value>",
"regfile:[rid=v]"));
parser.addOption(QCommandLineOption(
"timeout",
"Simulation timeout in milliseconds. If simulation does not finish "
Expand Down Expand Up @@ -136,44 +137,70 @@ bool parseCLIOptions(QCommandLineParser &parser, QString &errorMessage,

// Validate register initializations
if (parser.isSet("reginit")) {
QStringList regInitList = parser.value("reginit").split(",");
for (auto &regInit : regInitList) {
QStringList regInitParts = regInit.split("=");
if (regInitParts.size() != 2) {
errorMessage = "Invalid register initialization '" + regInit +
"' specified (--reginit).";
for (const auto &regFileInit : parser.values("reginit")) {
if (!regFileInit.contains(':')) {
errorMessage = "Cannot find register file type (--reginit).";
return false;
}
bool ok;
int regIdx = regInitParts[0].toInt(&ok);
if (!ok) {
errorMessage = "Invalid register index '" + regInitParts[0] +
"' specified (--reginit).";
return false;
}

auto &vstr = regInitParts[1];
VInt regVal;
if (vstr.startsWith("0x"))
regVal = decodeRadixValue(vstr, Radix::Hex, &ok);
else if (vstr.startsWith("0b"))
regVal = decodeRadixValue(vstr, Radix::Binary, &ok);
else
regVal = decodeRadixValue(vstr, Radix::Signed, &ok);

if (!ok) {
errorMessage =
"Invalid register value '" + vstr + "' specified (--reginit).";
return false;
auto regFileSplit = regFileInit.indexOf(':');
QString regFile = regFileInit.mid(0, regFileSplit);

QStringList regInitList = regFileInit.mid(regFileSplit + 1).split(",");
for (auto &regInit : regInitList) {
QStringList regInitParts = regInit.split("=");
if (regInitParts.size() != 2) {
errorMessage = "Invalid register initialization '" + regInit +
"' specified (--reginit).";
return false;
}
bool ok;
int regIdx = regInitParts[0].toInt(&ok);
if (!ok) {
errorMessage = "Invalid register index '" + regInitParts[0] +
"' specified (--reginit).";
return false;
}

auto &vstr = regInitParts[1];
VInt regVal;
if (vstr.startsWith("0x"))
regVal = decodeRadixValue(vstr, Radix::Hex, &ok);
else if (vstr.startsWith("0b"))
regVal = decodeRadixValue(vstr, Radix::Binary, &ok);
else
regVal = decodeRadixValue(vstr, Radix::Signed, &ok);
raccog marked this conversation as resolved.
Show resolved Hide resolved

if (!ok) {
errorMessage =
"Invalid register value '" + vstr + "' specified (--reginit).";
return false;
}

RegisterFileType regFileType;
if (regFile.startsWith("gpr", Qt::CaseInsensitive)) {
raccog marked this conversation as resolved.
Show resolved Hide resolved
regFileType = RegisterFileType::GPR;
} else if (regFile.startsWith("fpr", Qt::CaseInsensitive)) {
regFileType = RegisterFileType::FPR;
} else if (regFile.startsWith("csr", Qt::CaseInsensitive)) {
regFileType = RegisterFileType::CSR;
} else {
errorMessage = "Invalid register file type " + regFile +
" specified (--reginit).";
return false;
}

if (options.regInit.count(regFileType) == 0) {
options.regInit[regFileType] = {{regIdx, regVal}};
} else {
if (options.regInit.at(regFileType).count(regIdx) > 0) {
errorMessage = "Duplicate register initialization for register " +
QString::number(regIdx) + " specified (--reginit).";
return false;
}

options.regInit[regFileType][regIdx] = regVal;
}
}

if (options.regInit.count(regIdx) > 0) {
errorMessage = "Duplicate register initialization for register " +
QString::number(regIdx) + " specified (--reginit).";
return false;
}

options.regInit[regIdx] = regVal;
}
}

Expand Down
22 changes: 13 additions & 9 deletions src/cli/telemetry.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,22 +117,26 @@ class RegisterTelemetry : public Telemetry {
QVariant report(bool json) override {
QVariantMap registerMap;
auto isa = ProcessorHandler::currentISA();
auto regInfo = isa->regInfo().value();

if (json) {
for (unsigned i = 0; i < regInfo->regCnt(); i++) {
registerMap[regInfo->regName(i)] = QVariant::fromValue(
ProcessorHandler::getRegisterValue(RegisterFileType::GPR, i));
for (const auto &regFile : isa->regInfos()) {
for (unsigned i = 0; i < regFile->regCnt(); i++) {
registerMap[regFile->regName(i)] = QVariant::fromValue(
ProcessorHandler::getRegisterValue(regFile->regFileType(), i));
}
}
return registerMap;
} else {
QString outStr;
QTextStream out(&outStr);
for (unsigned i = 0; i < regInfo->regCnt(); i++) {
auto v = ProcessorHandler::getRegisterValue(RegisterFileType::GPR, i);
out << regInfo->regName(i) << ":\t"
<< encodeRadixValue(v, Radix::Signed, isa->bytes()) << "\t";
out << "(" << encodeRadixValue(v, Radix::Hex, isa->bytes()) << ")\n";
for (const auto &regFile : isa->regInfos()) {
for (unsigned i = 0; i < regFile->regCnt(); i++) {
auto v =
ProcessorHandler::getRegisterValue(regFile->regFileType(), i);
out << regFile->regName(i) << ":\t"
<< encodeRadixValue(v, Radix::Signed, isa->bytes()) << "\t";
out << "(" << encodeRadixValue(v, Radix::Hex, isa->bytes()) << ")\n";
}
}
return outStr;
}
Expand Down
9 changes: 5 additions & 4 deletions src/gotocombobox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,11 @@ AInt GoToSectionComboBox::addrForIndex(int i) {

void GoToRegisterComboBox::addTargets() {
const auto &isa = ProcessorHandler::currentISA();
const auto regInfo = isa->regInfo().value();
for (unsigned i = 0; i < regInfo->regCnt(); ++i) {
addItem(regInfo->regName(i) + " (" + regInfo->regAlias(i) + ")",
QVariant::fromValue<GoToUserData>({GoToFunction::Custom, i}));
for (const auto &regInfo : isa->regInfos()) {
for (unsigned i = 0; i < regInfo->regCnt(); ++i) {
addItem(regInfo->regName(i) + " (" + regInfo->regAlias(i) + ")",
QVariant::fromValue<GoToUserData>({GoToFunction::Custom, i}));
}
}
}

Expand Down
61 changes: 43 additions & 18 deletions src/isa/isainfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <QString>
#include <memory>
#include <set>
#include <vector>

#include "elfio/elf_types.hpp"

Expand All @@ -28,7 +29,9 @@ const static std::map<RegisterFileType, RegisterFileName> s_RegsterFileName = {
{RegisterFileType::FPR, {"FPR", "Floating-point registers"}},
{RegisterFileType::CSR, {"CSR", "Control and status registers"}}};

struct RegInfoBase {
/// An interface into a register file.
struct RegFileInfoInterface {
/// Returns this register file's type.
virtual RegisterFileType regFileType() const = 0;
/// Returns the number of registers in the instruction set.
virtual unsigned regCnt() const = 0;
Expand All @@ -47,28 +50,48 @@ struct RegInfoBase {
virtual bool regIsReadOnly(unsigned i) const = 0;
};

/// An index into a single register.
struct RegIndex {
const std::shared_ptr<const RegFileInfoInterface> file;
const unsigned index;
};

using RegInfoVec = std::vector<std::shared_ptr<const RegFileInfoInterface>>;
using RegInfoMap =
std::map<RegisterFileType, std::shared_ptr<const RegFileInfoInterface>>;

/// The ISAInfoBase class defines an interface for instruction set information.
class ISAInfoBase {
public:
virtual ~ISAInfoBase(){};
virtual QString name() const = 0;
virtual ISA isaID() const = 0;
virtual const RegInfoMap &regInfoMap() const = 0;

std::optional<const RegInfoBase *>
regInfo(RegisterFileType regFileType = RegisterFileType::GPR) const {
if (auto match = m_regInfos.find(regFileType); match != m_regInfos.end()) {
return m_regInfos.at(regFileType).get();
RegInfoVec regInfos() const {
RegInfoVec regVec;
for (const auto &regInfo : regInfoMap()) {
regVec.emplace_back(regInfo.second);
}
return regVec;
}
std::optional<const RegFileInfoInterface *>
regInfo(RegisterFileType regFileType) const {
if (auto match = regInfoMap().find(regFileType);
match != regInfoMap().end()) {
return regInfoMap().at(regFileType).get();
} else {
return {};
}
}
/// Returns the total number of registers in the instruction set.
unsigned regCnt() const {
unsigned count = 0;
for (const auto &pair : m_regInfos) {
count += pair.second->regCnt();
std::optional<std::shared_ptr<const RegFileInfoInterface>>
regInfoShared(RegisterFileType regFileType) const {
if (auto match = regInfoMap().find(regFileType);
match != regInfoMap().end()) {
return regInfoMap().at(regFileType);
} else {
return {};
}
raccog marked this conversation as resolved.
Show resolved Hide resolved
return count;
}

virtual unsigned bits() const = 0; // Register width, in bits
Expand All @@ -81,13 +104,17 @@ class ISAInfoBase {
} // Instruction width, in bytes
virtual unsigned instrByteAlignment() const {
return 0;
} // Instruction Alignment, in bytes
virtual int spReg() const { return -1; } // Stack pointer
virtual int gpReg() const { return -1; } // Global pointer
virtual int syscallReg() const { return -1; } // Syscall function register
} // Instruction Alignment, in bytes
virtual std::optional<RegIndex> spReg() const { return {}; } // Stack pointer
virtual std::optional<RegIndex> gpReg() const { return {}; } // Global pointer
virtual std::optional<RegIndex> syscallReg() const {
return {};
} // Syscall function register
// Mapping between syscall argument # and the corresponding register # wherein
// that argument is passed.
virtual int syscallArgReg(unsigned /*argIdx*/) const { return -1; }
virtual std::optional<RegIndex> syscallArgReg(unsigned /*argIdx*/) const {
return {};
}

// GCC Compile command architecture and ABI specification strings
virtual QString CCmarch() const = 0;
Expand Down Expand Up @@ -135,8 +162,6 @@ class ISAInfoBase {

protected:
ISAInfoBase() {}

std::map<RegisterFileType, std::unique_ptr<const RegInfoBase>> m_regInfos;
};

struct ProcessorISAInfo {
Expand Down
24 changes: 17 additions & 7 deletions src/isa/mipsisainfo_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ enum Function {
SYSCALL = 0b001100
};

struct MIPS_RegInfo : public RegInfoBase {
struct MIPS_GPRInfo : public RegFileInfoInterface {
RegisterFileType regFileType() const override {
return RegisterFileType::GPR;
}
Expand Down Expand Up @@ -180,18 +180,27 @@ class MIPS_ISAInfoBase : public ISAInfoBase {
public:
MIPS_ISAInfoBase() {
m_regInfos[RegisterFileType::GPR] =
std::make_unique<MIPSISA::MIPS_RegInfo>();
std::make_unique<MIPSISA::MIPS_GPRInfo>();
}

const RegInfoMap &regInfoMap() const override { return m_regInfos; }

QString name() const override { return CCmarch().toUpper(); }
int spReg() const override { return 29; }
int gpReg() const override { return 28; }
int syscallReg() const override { return 2; }
std::optional<RegIndex> spReg() const override {
return RegIndex{m_regInfos.at(RegisterFileType::GPR), 29};
}
std::optional<RegIndex> gpReg() const override {
return RegIndex{m_regInfos.at(RegisterFileType::GPR), 28};
}
std::optional<RegIndex> syscallReg() const override {
return RegIndex{m_regInfos.at(RegisterFileType::GPR), 2};
}
unsigned instrBits() const override { return 32; }
unsigned elfMachineId() const override { return EM_MIPS; }
virtual int syscallArgReg(unsigned argIdx) const override {
virtual std::optional<RegIndex>
syscallArgReg(unsigned argIdx) const override {
assert(argIdx < 2 && "MIPS only implements argument registers a0-a7");
return argIdx + 4;
return RegIndex{m_regInfos.at(RegisterFileType::GPR), argIdx + 4};
}

QString elfSupportsFlags(unsigned flags) const override {
Expand All @@ -217,6 +226,7 @@ class MIPS_ISAInfoBase : public ISAInfoBase {
protected:
QStringList m_enabledExtensions;
QStringList m_supportedExtensions = {""};
RegInfoMap m_regInfos;
};

} // namespace Ripes
2 changes: 1 addition & 1 deletion src/isa/rv_i_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ struct Bgeu : public Instr<Bgeu, Funct3::BGEU> {
namespace TypePseudo {

template <unsigned tokenIndex>
struct PseudoReg : public Ripes::PseudoReg<tokenIndex, RV_RegInfo> {};
struct PseudoReg : public Ripes::PseudoReg<tokenIndex, RV_GPRInfo> {};

template <typename PseudoInstrImpl>
struct PseudoInstrLoad : public PseudoInstruction<PseudoInstrImpl> {
Expand Down
Loading
Loading