Added RISC-V IsaDescriptor class, and adjusted RISC-V GPR count depending on ISA base.

This commit is contained in:
Nav
2024-11-29 01:06:44 +00:00
parent cde5d83599
commit 49cf2e5e9a
7 changed files with 398 additions and 2 deletions

View File

@@ -24,6 +24,7 @@ target_sources(
${CMAKE_CURRENT_SOURCE_DIR}/RiscV/RiscV.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RiscV/RiscV.cpp
${CMAKE_CURRENT_SOURCE_DIR}/RiscV/RiscVTargetConfig.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RiscV/RiscVTargetConfig.cpp
${CMAKE_CURRENT_SOURCE_DIR}/RiscV/TargetDescriptionFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RiscV/TargetDescriptionFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/RiscV/IsaDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/RiscV/Wch/WchRiscV.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RiscV/Wch/WchRiscV.cpp
${CMAKE_CURRENT_SOURCE_DIR}/RiscV/Wch/TargetDescriptionFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RiscV/Wch/TargetDescriptionFile.cpp
) )

View File

@@ -0,0 +1,297 @@
#include "IsaDescriptor.hpp"
#include <array>
#include <cctype>
#include "src/Services/StringService.hpp"
#include "src/Exceptions/Exception.hpp"
namespace Targets::RiscV
{
using Exceptions::Exception;
IsaDescriptor::IsaDescriptor(std::string_view isaString)
: IsaDescriptor(Services::StringService::asciiToLower(isaString), 0)
{}
bool IsaDescriptor::hasExtension(IsaExtension extension) const {
return this->extensionDescriptorsByExtension.contains(extension);
}
bool IsaDescriptor::isReduced() const {
return this->baseDescriptor.base == IsaBase::RV32E || this->baseDescriptor.base == IsaBase::RV64E;
}
std::optional<std::reference_wrapper<const IsaExtensionDescriptor>> IsaDescriptor::tryGetExtensionDescriptor(
IsaExtension extension
) const {
const auto descriptorIt = this->extensionDescriptorsByExtension.find(extension);
if (descriptorIt == this->extensionDescriptorsByExtension.end()) {
return std::nullopt;
}
return std::cref(descriptorIt->second);
}
const IsaExtensionDescriptor& IsaDescriptor::getExtensionDescriptor(IsaExtension extension) const {
const auto descriptor = this->tryGetExtensionDescriptor(extension);
if (!descriptor.has_value()) {
throw Exception{"Failed to get extension descriptor in RISC-V ISA descriptor - extension not found"};
}
return descriptor->get();
}
IsaDescriptor::IsaDescriptor(std::string_view isaStringLower, std::size_t stringOffset)
: baseDescriptor(IsaDescriptor::extractBaseDescriptorFromIsaString(isaStringLower, stringOffset))
, extensionDescriptorsByExtension(
IsaDescriptor::extractExtensionDescriptorsFromIsaString(isaStringLower, stringOffset)
)
{}
IsaBaseDescriptor IsaDescriptor::extractBaseDescriptorFromIsaString(
std::string_view isaStringLower,
std::size_t& stringOffset
) {
struct BriefBaseDescriptor
{
IsaBase base;
std::string_view name;
IsaVersionNumber defaultVersion = {2, 0};
};
static constexpr auto briefDescriptors = std::to_array<BriefBaseDescriptor>({
{.base = IsaBase::RV32I, .name = "rv32i"},
{.base = IsaBase::RV32E, .name = "rv32e"},
{.base = IsaBase::RV64I, .name = "rv64i"},
{.base = IsaBase::RV64E, .name = "rv64e"},
});
for (const auto& briefDescriptor : briefDescriptors) {
if (isaStringLower.find(briefDescriptor.name) == 0) {
stringOffset += briefDescriptor.name.length();
return IsaBaseDescriptor{
.base = briefDescriptor.base,
.versionNumber = IsaDescriptor::extractVersionNumberFromIsaString(
isaStringLower,
stringOffset
).value_or(briefDescriptor.defaultVersion)
};
}
}
throw Exception{"Failed to extract RISC-V ISA base from ISA string \"" + std::string{isaStringLower} + "\""};
}
std::unordered_map<IsaExtension, IsaExtensionDescriptor> IsaDescriptor::extractExtensionDescriptorsFromIsaString(
std::string_view isaStringLower,
size_t& stringOffset
) {
struct BriefExtensionDescriptor
{
IsaExtension extension;
std::string_view name;
IsaVersionNumber defaultVersion = {2, 0};
};
static constexpr auto singleLetterBriefDescriptors = std::to_array<BriefExtensionDescriptor>({
{.extension = IsaExtension::INTEGER_MULTIPLICATION_DIVISION, .name = "m"},
{.extension = IsaExtension::ATOMICS, .name = "a"},
{.extension = IsaExtension::SINGLE_PRECISION_FLOATING_POINT, .name = "f"},
{.extension = IsaExtension::DOUBLE_PRECISION_FLOATING_POINT, .name = "d"},
{.extension = IsaExtension::BIT_MANIPULATION, .name = "b"},
{.extension = IsaExtension::COMPRESSED_INSTRUCTIONS, .name = "c"},
{.extension = IsaExtension::CRYPTOGRAPHY, .name = "k"},
});
auto output = std::unordered_map<IsaExtension, IsaExtensionDescriptor>{};
const auto commitMultiLetterExtension = [&output] (std::string_view extensionName) {
static constexpr auto multiLetterBriefDescriptors = std::to_array<BriefExtensionDescriptor>({
{.extension = IsaExtension::CSR_INSTRUCTIONS, .name = "zicsr"},
{.extension = IsaExtension::INSTRUCTION_FETCH_FENCE, .name = "zifencei"},
});
for (const auto& briefDescriptor : multiLetterBriefDescriptors) {
if (extensionName.find(briefDescriptor.name) == 0) {
auto offset = briefDescriptor.name.size();
output.emplace(
briefDescriptor.extension,
IsaExtensionDescriptor{
.extension = briefDescriptor.extension,
.versionNumber = IsaDescriptor::extractVersionNumberFromIsaString(
extensionName,
offset
).value_or(briefDescriptor.defaultVersion),
}
);
return;
}
}
};
auto multiLetterExtension = std::optional<std::string>{};
while (stringOffset <= (isaStringLower.length() - 1)) {
const auto character = isaStringLower.at(stringOffset);
if (multiLetterExtension.has_value()) {
if (character == '_') {
commitMultiLetterExtension(*multiLetterExtension);
multiLetterExtension = std::nullopt;
}
multiLetterExtension->push_back(character);
++stringOffset;
continue;
}
for (const auto& briefDescriptor : singleLetterBriefDescriptors) {
if (character == briefDescriptor.name.at(0)) {
output.emplace(
briefDescriptor.extension,
IsaExtensionDescriptor{
.extension = briefDescriptor.extension,
.versionNumber = IsaDescriptor::extractVersionNumberFromIsaString(
isaStringLower,
++stringOffset
).value_or(briefDescriptor.defaultVersion),
}
);
goto CONTINUE_OUTER;
}
}
if (character == 'g') {
const auto versionNumber = IsaDescriptor::extractVersionNumberFromIsaString(
isaStringLower,
++stringOffset
).value_or(IsaVersionNumber{2, 0});
output.emplace(
IsaExtension::INTEGER_MULTIPLICATION_DIVISION,
IsaExtensionDescriptor{
.extension = IsaExtension::INTEGER_MULTIPLICATION_DIVISION,
.versionNumber = versionNumber
}
);
output.emplace(
IsaExtension::ATOMICS,
IsaExtensionDescriptor{.extension = IsaExtension::ATOMICS, .versionNumber = versionNumber}
);
output.emplace(
IsaExtension::DOUBLE_PRECISION_FLOATING_POINT,
IsaExtensionDescriptor{
.extension = IsaExtension::DOUBLE_PRECISION_FLOATING_POINT,
.versionNumber = versionNumber
}
);
output.emplace(
IsaExtension::INSTRUCTION_FETCH_FENCE,
IsaExtensionDescriptor{
.extension = IsaExtension::INSTRUCTION_FETCH_FENCE,
.versionNumber = versionNumber
}
);
continue;
}
if (character == 'z' || character == 'x') {
multiLetterExtension = std::string{character};
++stringOffset;
continue;
}
++stringOffset;
CONTINUE_OUTER:
continue;
}
if (multiLetterExtension.has_value()) {
commitMultiLetterExtension(*multiLetterExtension);
}
// Finally, handle implied extensions
if (
output.contains(IsaExtension::DOUBLE_PRECISION_FLOATING_POINT)
&& !output.contains(IsaExtension::SINGLE_PRECISION_FLOATING_POINT)
) {
output.emplace(
IsaExtension::SINGLE_PRECISION_FLOATING_POINT,
IsaExtensionDescriptor{
.extension = IsaExtension::SINGLE_PRECISION_FLOATING_POINT,
.versionNumber = {2, 0}
}
);
}
if (
output.contains(IsaExtension::SINGLE_PRECISION_FLOATING_POINT)
&& !output.contains(IsaExtension::CSR_INSTRUCTIONS)
) {
output.emplace(
IsaExtension::CSR_INSTRUCTIONS,
IsaExtensionDescriptor{.extension = IsaExtension::CSR_INSTRUCTIONS, .versionNumber = {2, 0}}
);
}
return output;
}
std::optional<IsaVersionNumber> IsaDescriptor::extractVersionNumberFromIsaString(
std::string_view isaStringLower,
size_t& stringOffset
) {
static constexpr auto getNextDigitSequence = [] (std::string_view string, std::size_t offset) {
auto sequence = std::string{};
for (auto i = offset; i <= (string.length() - 1); ++i) {
const auto character = string.at(i);
if (!std::isdigit(character)) {
break;
}
sequence.push_back(character);
}
return !sequence.empty() ? std::optional{sequence} : std::nullopt;
};
if (isaStringLower.empty()) {
return std::nullopt;
}
const auto majorString = getNextDigitSequence(isaStringLower, stringOffset);
if (!majorString.has_value()) {
return std::nullopt;
}
stringOffset += majorString->length();
auto output = IsaVersionNumber{
.major = static_cast<std::uint16_t>(std::stoul(*majorString, nullptr, 10)),
.minor = 0
};
if ((stringOffset + 1) > (isaStringLower.length() - 1) || isaStringLower.at(stringOffset) != 'p') {
// The ISA string cannot accommodate a minor number, or the 'p' delimiter is missing
return output;
}
const auto minorString = getNextDigitSequence(isaStringLower, stringOffset + 1);
if (minorString.has_value()) {
output.minor = static_cast<std::uint16_t>(std::stoul(*minorString, nullptr, 10));
stringOffset += minorString->length() + 1;
}
return output;
}
}

View File

@@ -0,0 +1,86 @@
#pragma once
#include <cstdint>
#include <string>
#include <string_view>
#include <unordered_map>
#include <optional>
#include <functional>
namespace Targets::RiscV
{
enum class IsaBase: std::uint8_t
{
RV32I,
RV32E,
RV64I,
RV64E,
};
/**
* I've not covered all standard extensions here, as I really don't think Bloom will ever need them. If that ever
* changes, I will add the others as and when I need them.
*/
enum class IsaExtension: std::uint8_t
{
INTEGER_MULTIPLICATION_DIVISION,
ATOMICS,
SINGLE_PRECISION_FLOATING_POINT,
DOUBLE_PRECISION_FLOATING_POINT,
BIT_MANIPULATION,
COMPRESSED_INSTRUCTIONS,
CRYPTOGRAPHY,
CSR_INSTRUCTIONS,
INSTRUCTION_FETCH_FENCE,
};
struct IsaVersionNumber
{
std::uint16_t major = 0;
std::uint16_t minor = 0;
};
struct IsaBaseDescriptor
{
IsaBase base;
IsaVersionNumber versionNumber;
};
struct IsaExtensionDescriptor
{
IsaExtension extension;
IsaVersionNumber versionNumber;
};
struct IsaDescriptor
{
IsaBaseDescriptor baseDescriptor;
std::unordered_map<IsaExtension, IsaExtensionDescriptor> extensionDescriptorsByExtension;
explicit IsaDescriptor(std::string_view isaString);
bool hasExtension(IsaExtension extension) const;
bool isReduced() const;
std::optional<std::reference_wrapper<const IsaExtensionDescriptor>> tryGetExtensionDescriptor(
IsaExtension extension
) const;
const IsaExtensionDescriptor& getExtensionDescriptor(IsaExtension extension) const;
private:
IsaDescriptor(std::string_view isaStringLower, std::size_t stringOffset);
static IsaBaseDescriptor extractBaseDescriptorFromIsaString(
std::string_view isaStringLower,
std::size_t& stringOffset
);
static std::unordered_map<IsaExtension, IsaExtensionDescriptor> extractExtensionDescriptorsFromIsaString(
std::string_view isaStringLower,
std::size_t& stringOffset
);
static std::optional<IsaVersionNumber> extractVersionNumberFromIsaString(
std::string_view isaStringLower,
std::size_t& stringOffset
);
};
}

View File

@@ -21,11 +21,13 @@ namespace Targets::RiscV
) )
: targetConfig(RiscVTargetConfig{targetConfig}) : targetConfig(RiscVTargetConfig{targetConfig})
, targetDescriptionFile(targetDescriptionFile) , targetDescriptionFile(targetDescriptionFile)
, isaDescriptor(this->targetDescriptionFile.getIsaDescriptor())
, cpuRegisterAddressSpaceDescriptor(RiscV::generateCpuRegisterAddressSpaceDescriptor()) , cpuRegisterAddressSpaceDescriptor(RiscV::generateCpuRegisterAddressSpaceDescriptor())
, csrMemorySegmentDescriptor(this->cpuRegisterAddressSpaceDescriptor.getMemorySegmentDescriptor("cs_registers")) , csrMemorySegmentDescriptor(this->cpuRegisterAddressSpaceDescriptor.getMemorySegmentDescriptor("cs_registers"))
, gprMemorySegmentDescriptor(this->cpuRegisterAddressSpaceDescriptor.getMemorySegmentDescriptor("gp_registers")) , gprMemorySegmentDescriptor(this->cpuRegisterAddressSpaceDescriptor.getMemorySegmentDescriptor("gp_registers"))
, cpuPeripheralDescriptor( , cpuPeripheralDescriptor(
RiscV::generateCpuPeripheralDescriptor( RiscV::generateCpuPeripheralDescriptor(
this->isaDescriptor,
this->cpuRegisterAddressSpaceDescriptor, this->cpuRegisterAddressSpaceDescriptor,
this->csrMemorySegmentDescriptor, this->csrMemorySegmentDescriptor,
this->gprMemorySegmentDescriptor this->gprMemorySegmentDescriptor
@@ -401,6 +403,7 @@ namespace Targets::RiscV
} }
TargetPeripheralDescriptor RiscV::generateCpuPeripheralDescriptor( TargetPeripheralDescriptor RiscV::generateCpuPeripheralDescriptor(
const IsaDescriptor& isaDescriptor,
const TargetAddressSpaceDescriptor& addressSpaceDescriptor, const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& csrMemorySegmentDescriptor, const TargetMemorySegmentDescriptor& csrMemorySegmentDescriptor,
const TargetMemorySegmentDescriptor& gprMemorySegmentDescriptor const TargetMemorySegmentDescriptor& gprMemorySegmentDescriptor
@@ -427,7 +430,7 @@ namespace Targets::RiscV
} }
).first->second; ).first->second;
for (auto i = std::uint8_t{0}; i <= 31; ++i) { for (auto i = std::uint8_t{0}; i <= static_cast<std::uint8_t>(isaDescriptor.isReduced() ? 15 : 31); ++i) {
const auto key = "x" + std::to_string(i); const auto key = "x" + std::to_string(i);
gprGroup.registerDescriptorsByKey.emplace( gprGroup.registerDescriptorsByKey.emplace(
key, key,

View File

@@ -9,6 +9,7 @@
#include "RiscVTargetConfig.hpp" #include "RiscVTargetConfig.hpp"
#include "TargetDescriptionFile.hpp" #include "TargetDescriptionFile.hpp"
#include "IsaDescriptor.hpp"
#include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp" #include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp"
@@ -93,6 +94,7 @@ namespace Targets::RiscV
protected: protected:
RiscVTargetConfig targetConfig; RiscVTargetConfig targetConfig;
TargetDescriptionFile targetDescriptionFile; TargetDescriptionFile targetDescriptionFile;
IsaDescriptor isaDescriptor;
DebugToolDrivers::TargetInterfaces::RiscV::RiscVDebugInterface* riscVDebugInterface = nullptr; DebugToolDrivers::TargetInterfaces::RiscV::RiscVDebugInterface* riscVDebugInterface = nullptr;
@@ -135,6 +137,7 @@ namespace Targets::RiscV
static TargetAddressSpaceDescriptor generateCpuRegisterAddressSpaceDescriptor(); static TargetAddressSpaceDescriptor generateCpuRegisterAddressSpaceDescriptor();
static TargetPeripheralDescriptor generateCpuPeripheralDescriptor( static TargetPeripheralDescriptor generateCpuPeripheralDescriptor(
const IsaDescriptor& isaDescriptor,
const TargetAddressSpaceDescriptor& addressSpaceDescriptor, const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& csrMemorySegmentDescriptor, const TargetMemorySegmentDescriptor& csrMemorySegmentDescriptor,
const TargetMemorySegmentDescriptor& gprMemorySegmentDescriptor const TargetMemorySegmentDescriptor& gprMemorySegmentDescriptor

View File

@@ -13,4 +13,8 @@ namespace Targets::RiscV
TargetAddressSpaceDescriptor TargetDescriptionFile::getSystemAddressSpaceDescriptor() const { TargetAddressSpaceDescriptor TargetDescriptionFile::getSystemAddressSpaceDescriptor() const {
return this->targetAddressSpaceDescriptorFromAddressSpace(this->getSystemAddressSpace()); return this->targetAddressSpaceDescriptorFromAddressSpace(this->getSystemAddressSpace());
} }
IsaDescriptor TargetDescriptionFile::getIsaDescriptor() const {
return IsaDescriptor{this->getDeviceAttribute("architecture")};
}
} }

View File

@@ -2,6 +2,8 @@
#include "src/Targets/TargetDescription/TargetDescriptionFile.hpp" #include "src/Targets/TargetDescription/TargetDescriptionFile.hpp"
#include "IsaDescriptor.hpp"
namespace Targets::RiscV namespace Targets::RiscV
{ {
/** /**
@@ -15,7 +17,7 @@ namespace Targets::RiscV
explicit TargetDescriptionFile(const std::string& xmlFilePath); explicit TargetDescriptionFile(const std::string& xmlFilePath);
[[nodiscard]] const TargetDescription::AddressSpace& getSystemAddressSpace() const; [[nodiscard]] const TargetDescription::AddressSpace& getSystemAddressSpace() const;
[[nodiscard]] TargetAddressSpaceDescriptor getSystemAddressSpaceDescriptor() const; [[nodiscard]] TargetAddressSpaceDescriptor getSystemAddressSpaceDescriptor() const;
[[nodiscard]] IsaDescriptor getIsaDescriptor() const;
}; };
} }