diff --git a/include/slang/ast/types/Type.h b/include/slang/ast/types/Type.h index e42eccef6..29a129413 100644 --- a/include/slang/ast/types/Type.h +++ b/include/slang/ast/types/Type.h @@ -148,6 +148,9 @@ class SLANG_EXPORT Type : public Symbol { /// Indicates whether this is a dynamic array, associative array, or a queue. bool isDynamicallySizedArray() const; + /// Indicates whether this is a packed or unpacked union. + bool isUnion() const; + /// Indicates whether this is a tagged union, packed or unpacked. bool isTaggedUnion() const; diff --git a/source/ast/types/Type.cpp b/source/ast/types/Type.cpp index 8d9f45dfb..abf00af64 100644 --- a/source/ast/types/Type.cpp +++ b/source/ast/types/Type.cpp @@ -390,6 +390,17 @@ bool Type::isHandleType() const { } } +bool Type::isUnion() const { + const Type& ct = getCanonicalType(); + switch (ct.kind) { + case SymbolKind::UnpackedUnionType: + case SymbolKind::PackedUnionType: + return true; + default: + return false; + } +} + bool Type::isTaggedUnion() const { auto& ct = getCanonicalType(); switch (ct.kind) { diff --git a/tools/reflect/CMakeLists.txt b/tools/reflect/CMakeLists.txt index 3c743dab8..316490089 100644 --- a/tools/reflect/CMakeLists.txt +++ b/tools/reflect/CMakeLists.txt @@ -4,8 +4,9 @@ # ~~~ add_library( - slang_reflect_obj_lib OBJECT src/SvStruct.cpp src/SvType.cpp src/SvEnum.cpp - src/SvTypeReflector.cpp src/SvLocalParam.cpp) + slang_reflect_obj_lib OBJECT + src/SvStruct.cpp src/SvType.cpp src/SvEnum.cpp src/SvTypeReflector.cpp + src/SvLocalParam.cpp src/SvUnion.cpp) target_include_directories(slang_reflect_obj_lib PUBLIC include ../../include) target_link_libraries(slang_reflect_obj_lib PUBLIC slang::slang) diff --git a/tools/reflect/include/ASTVisitors.h b/tools/reflect/include/ASTVisitors.h index 6bddfa915..e8ae9b162 100644 --- a/tools/reflect/include/ASTVisitors.h +++ b/tools/reflect/include/ASTVisitors.h @@ -8,26 +8,25 @@ #pragma once -#include #include #include "slang/ast/ASTVisitor.h" -#include "slang/ast/Compilation.h" #include "slang/syntax/SyntaxVisitor.h" class PublicDirectiveVisitor : public slang::syntax::SyntaxVisitor { public: - explicit PublicDirectiveVisitor(slang::parsing::TokenKind tokenKind) : tokenKind(tokenKind) {} + explicit PublicDirectiveVisitor(const slang::parsing::TokenKind tokenKind) : + tokenKind(tokenKind) {} - void visitToken(slang::parsing::Token token) { + void visitToken(const slang::parsing::Token token) { if (token.kind == tokenKind) { auto blockComments = token.trivia() | std::views::filter([](auto& v) { return v.kind == slang::parsing::TriviaKind::BlockComment; }); for (auto& blockComment : blockComments) { - isPublic = std::find(publicDirectives.begin(), publicDirectives.end(), - blockComment.getRawText()) != publicDirectives.end(); + isPublic = std::ranges::find(publicDirectives, blockComment.getRawText()) != + publicDirectives.end(); } } } @@ -38,6 +37,7 @@ class PublicDirectiveVisitor : public slang::syntax::SyntaxVisitor publicDirectives = { - "/* public */", "/*verilator public*/", "/* verilator public */"}; + constexpr static std::array publicDirectives = {"/* public */", + "/*verilator public*/", + "/* verilator public */"}; }; diff --git a/tools/reflect/include/CppEmitter.h b/tools/reflect/include/CppEmitter.h index a2286b587..87d91330e 100644 --- a/tools/reflect/include/CppEmitter.h +++ b/tools/reflect/include/CppEmitter.h @@ -16,14 +16,14 @@ #include #include -#include "slang/util/SmallVector.h" #include "slang/util/Util.h" namespace fs = std::filesystem; class HppFile { public: - explicit HppFile(std::string_view name, bool noSystemC) : fileName(std::string(name) + ".h") { + explicit HppFile(const std::string_view name, const bool noSystemC) : + fileName(std::string(name) + ".h") { includes.emplace_back("ostream"); includes.emplace_back("cstddef"); includes.emplace_back("cstdint"); @@ -35,11 +35,11 @@ class HppFile { void add(std::string&& code) { hpp << code; } void addInclude(std::string&& code) { - if (std::find(includes.begin(), includes.end(), code) == includes.end()) + if (std::ranges::find(includes, code) == includes.end()) includes.emplace_back(code); } void addIncludeHeader(std::string_view code) { - if (std::find(headers.begin(), headers.end(), code) == headers.end()) + if (std::ranges::find(headers, code) == headers.end()) headers.emplace_back(code); } void addWithIndent(std::string&& code) { hpp << indent(currentIndent) << code; } @@ -49,7 +49,7 @@ class HppFile { currentIndent--; } - std::string emit() { + std::string emit() const { auto includesTransform = std::views::transform(includes, [](const auto& inc) { return fmt::format("#include <{}>", inc); }); @@ -61,7 +61,7 @@ class HppFile { hpp.str()); } - void emitToFile(const fs::path& path) { + void emitToFile(const fs::path& path) const { auto outFile = std::ofstream(path / fileName); outFile << emit(); } @@ -73,7 +73,7 @@ class HppFile { std::string fileName; uint32_t currentIndent{0}; - std::string indent(uint64_t blocks) { + static std::string indent(const uint64_t blocks) { std::string ret; for (auto i = 0; i < blocks * 4; i++) ret += " "; @@ -83,21 +83,21 @@ class HppFile { class CppEmitter { public: - explicit CppEmitter(bool noSystemC) : noSystemC(noSystemC) {} + explicit CppEmitter(const bool noSystemC) : noSystemC(noSystemC) {} - [[nodiscard]] HppFile& newNamespace(std::string_view name) { + [[nodiscard]] HppFile& newNamespace(const std::string_view name) { hppFiles.push_back(HppFile(name, noSystemC)); return hppFiles.back(); } - std::string emit() { + std::string emit() const { std::stringstream ret; for (auto& hpp : hppFiles) ret << hpp.emit(); return std::move(ret.str()); } - void emitToFile(const fs::path& path) { + void emitToFile(const fs::path& path) const { for (auto& hpp : hppFiles) hpp.emitToFile(path); } diff --git a/tools/reflect/include/SvEnum.h b/tools/reflect/include/SvEnum.h index b3d4900c1..1c292108a 100644 --- a/tools/reflect/include/SvEnum.h +++ b/tools/reflect/include/SvEnum.h @@ -12,12 +12,11 @@ #include "slang/ast/types/AllTypes.h" -class SvEnum : public SvGeneric { +class SvEnum final : public SvGeneric { public: - explicit SvEnum(const slang::ast::TypeAliasType& type) : - SvGeneric(SvGeneric::Kind::Enum), type(type) {} + explicit SvEnum(const slang::ast::TypeAliasType& type) : SvGeneric(Kind::Enum), type(type) {} - void toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool noSystemC) const override; + void toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool) const override; private: const slang::ast::TypeAliasType& type; diff --git a/tools/reflect/include/SvGeneric.h b/tools/reflect/include/SvGeneric.h index d11c6c11d..bf6f48748 100644 --- a/tools/reflect/include/SvGeneric.h +++ b/tools/reflect/include/SvGeneric.h @@ -9,36 +9,36 @@ #pragma once #include "CppEmitter.h" - -#include "slang/ast/types/AllTypes.h" +#include using SvAliases = std::unordered_map; class SvGeneric { public: - enum class Kind { Struct, Enum, LocalParam }; - explicit SvGeneric(Kind kind) : kind(kind) {} + enum class Kind { Struct, Enum, LocalParam, Union }; + explicit SvGeneric(const Kind kind) : kind(kind) {} virtual void toCpp(HppFile&, std::string_view, const SvAliases&, bool noSystemC) const = 0; - bool isStruct() const { return kind == Kind::Struct; } - bool isEnum() const { return kind == Kind::Enum; } - bool isLocalParam() const { return kind == Kind::LocalParam; } + [[nodiscard]] bool isStruct() const { return kind == Kind::Struct; } + [[nodiscard]] bool isEnum() const { return kind == Kind::Enum; } + [[nodiscard]] bool isLocalParam() const { return kind == Kind::LocalParam; } + [[nodiscard]] bool isUnion() const { return kind == Kind::Union; } virtual ~SvGeneric() = default; protected: Kind kind; - static std::string_view resolveAlias(std::string_view typeName, const SvAliases& aliases) { - if (auto alias = aliases.find(typeName); alias != aliases.end()) + [[nodiscard]] static std::string_view resolveAlias(const std::string_view& typeName, + const SvAliases& aliases) { + if (const auto& alias = aliases.find(typeName); alias != aliases.end()) return alias->second; return typeName; } - static bool isCppReserved(std::string_view name) { - return std::find(cppReservedKeywords.begin(), cppReservedKeywords.end(), name) != - cppReservedKeywords.end(); + [[nodiscard]] static bool isCppReserved(const std::string_view name) { + return std::ranges::find(cppReservedKeywords, name) != cppReservedKeywords.end(); } static constexpr std::array cppReservedKeywords = {"alignas", diff --git a/tools/reflect/include/SvLocalParam.h b/tools/reflect/include/SvLocalParam.h index 6289b2434..faba82e5a 100644 --- a/tools/reflect/include/SvLocalParam.h +++ b/tools/reflect/include/SvLocalParam.h @@ -9,15 +9,14 @@ #pragma once #include "SvGeneric.h" -#include "SvType.h" #include #include "slang/ast/symbols/ParameterSymbols.h" -class SvLocalParam : public SvGeneric { +class SvLocalParam final : public SvGeneric { public: explicit SvLocalParam(const slang::ast::ParameterSymbol& parameter) : - SvGeneric(SvGeneric::Kind::LocalParam), parameter(parameter) {} + SvGeneric(Kind::LocalParam), parameter(parameter) {} void toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool) const override; diff --git a/tools/reflect/include/SvStruct.h b/tools/reflect/include/SvStruct.h index f9fc57765..5f6e978c6 100644 --- a/tools/reflect/include/SvStruct.h +++ b/tools/reflect/include/SvStruct.h @@ -11,11 +11,12 @@ #include "CppEmitter.h" #include "SvGeneric.h" #include "fmt/format.h" +#include -class SvStruct : public SvGeneric { +class SvStruct final : public SvGeneric { public: explicit SvStruct(const slang::ast::TypeAliasType& type) : - SvGeneric(SvGeneric::Kind::Struct), type(type) {} + SvGeneric(Kind::Struct), type(type) {} void toCpp(HppFile& hppFile, std::string_view _namespace, const SvAliases& aliases, bool noSystemC) const override; diff --git a/tools/reflect/include/SvType.h b/tools/reflect/include/SvType.h index 1e8d47970..96e715524 100644 --- a/tools/reflect/include/SvType.h +++ b/tools/reflect/include/SvType.h @@ -8,12 +8,10 @@ #pragma once -#include - #include "slang/ast/types/Type.h" namespace CppType { -enum Type { BOOL, U32, U64, SC_BV, STRUCT, ENUM }; +enum Type { BOOL, U32, U64, SC_BV, STRUCT, ENUM, UNION }; std::string toString(const Type& cppType); Type fromSize(size_t size); @@ -22,15 +20,18 @@ Type fromSize(size_t size); class SvType { public: explicit SvType(const slang::ast::Type& type); - explicit SvType(const slang::ast::Type& type, std::string_view name) : SvType(type) { + explicit SvType(const slang::ast::Type& type, const std::string_view name) : SvType(type) { this->name = name; } - bool isStruct() const { return cppType == CppType::STRUCT; } - bool isEnum() const { return cppType == CppType::ENUM; } - bool isStructOrEnum() const { return this->isStruct() || this->isEnum(); } + [[nodiscard]] bool isStruct() const { return cppType == CppType::STRUCT; } + [[nodiscard]] bool isEnum() const { return cppType == CppType::ENUM; } + [[nodiscard]] bool isUnion() const { return cppType == CppType::UNION; } + [[nodiscard]] bool isStructEnumOrUnion() const { + return this->isStruct() || this->isEnum() || this->isUnion(); + } - std::string toString() const; + [[nodiscard]] std::string toString() const; friend std::ostream& operator<<(std::ostream& os, const SvType& type); CppType::Type cppType; diff --git a/tools/reflect/include/SvTypeReflector.h b/tools/reflect/include/SvTypeReflector.h index 81b3f65d0..97e121f05 100644 --- a/tools/reflect/include/SvTypeReflector.h +++ b/tools/reflect/include/SvTypeReflector.h @@ -14,15 +14,15 @@ class SvTypeReflector { public: - explicit SvTypeReflector(std::unique_ptr compilation, bool verbose, - bool noSystemC) : - compilation(std::move(compilation)), verbose(verbose), noSystemC(noSystemC), - cppEmitter(noSystemC) {} + explicit SvTypeReflector(std::unique_ptr compilation, + const bool verbose, const bool noSystemC) : + verbose(verbose), noSystemC(noSystemC), cppEmitter(noSystemC), + compilation(std::move(compilation)) {} void reflect(); - std::string emit() { return cppEmitter.emit(); } - void emitToFile(const fs::path& path) { cppEmitter.emitToFile(path); } + std::string emit() const { return cppEmitter.emit(); } + void emitToFile(const fs::path& path) const { cppEmitter.emitToFile(path); } private: bool verbose; diff --git a/tools/reflect/include/SvUnion.h b/tools/reflect/include/SvUnion.h new file mode 100644 index 000000000..e32dd5785 --- /dev/null +++ b/tools/reflect/include/SvUnion.h @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +//! @file SvEnum.h +//! @brief Handles with SystemVerilog Enums +// +// SPDX-FileCopyrightText: Michael Popoloski +// SPDX-License-Identifier: MIT +//------------------------------------------------------------------------------ + +#pragma once + +#include "SvGeneric.h" + +#include "slang/ast/types/AllTypes.h" + +class SvUnion final : public SvGeneric { +public: + explicit SvUnion(const slang::ast::TypeAliasType& type) : SvGeneric(Kind::Union), type(type) {} + + void toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool noSystemC) const override; + +private: + const slang::ast::TypeAliasType& type; +}; diff --git a/tools/reflect/src/SvEnum.cpp b/tools/reflect/src/SvEnum.cpp index e95456d32..1191bea72 100644 --- a/tools/reflect/src/SvEnum.cpp +++ b/tools/reflect/src/SvEnum.cpp @@ -4,10 +4,9 @@ #include "SvEnum.h" #include -#include void SvEnum::toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool) const { - auto underlyingType = [&]() { + auto underlyingType = [&] { if (type.getBitstreamWidth() <= 8) return "uint8_t"sv; if (type.getBitstreamWidth() <= 16) @@ -16,9 +15,8 @@ void SvEnum::toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool) c return "uint32_t"sv; if (type.getBitstreamWidth() <= 64) return "uint64_t"sv; - else - SLANG_THROW( - std::runtime_error("Enum with $bits size bigger than 64 bits are not supported")); + SLANG_THROW( + std::runtime_error("Enum with $bits size bigger than 64 bits are not supported")); }; //** STRUCT (ENUM) DECLARATION **// hppFile.addWithIndent(fmt::format("struct {} {{\n", type.name)); @@ -62,12 +60,8 @@ void SvEnum::toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool) c hppFile.increaseIndent(); hppFile.addWithIndent("switch (__data) {\n"); hppFile.increaseIndent(); - for (const auto& member : members) - hppFile.addWithIndent( - fmt::format("case {}: type = Type::{}; break;\n", member.second, member.first)); - hppFile.addWithIndent(fmt::format( - "default: throw std::runtime_error(\"Can not create {} from provided value\");\n", - type.name)); + for (const auto& [name, value] : members) + hppFile.addWithIndent(fmt::format("case {}: type = Type::{}; break;\n", value, name)); hppFile.decreaseIndent(); hppFile.addWithIndent("}\n"); hppFile.decreaseIndent(); @@ -82,8 +76,8 @@ void SvEnum::toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool) c hppFile.increaseIndent(); hppFile.addWithIndent("switch (__data.type) {\n"); hppFile.increaseIndent(); - for (const auto& member : members) - hppFile.addWithIndent(fmt::format("case Type::{0}: os << \"{0}\"; break;\n", member.first)); + for (const auto& name : members | std::views::keys) + hppFile.addWithIndent(fmt::format("case Type::{0}: os << \"{0}\"; break;\n", name)); hppFile.decreaseIndent(); hppFile.addWithIndent("}\n"); hppFile.addWithIndent("return os;\n"); diff --git a/tools/reflect/src/SvLocalParam.cpp b/tools/reflect/src/SvLocalParam.cpp index f3306ae98..3d8da1bee 100644 --- a/tools/reflect/src/SvLocalParam.cpp +++ b/tools/reflect/src/SvLocalParam.cpp @@ -3,8 +3,11 @@ #include "SvLocalParam.h" -void unwrapUnpackedArray(const std::span constantValues, - std::vector>& values, uint64_t& biggestElementSize) { +#include + +static void unwrapUnpackedArray(const std::span constantValues, + std::vector>& values, + uint64_t& biggestElementSize) { if (constantValues.front().isUnpacked()) for (const auto& unpackedArray : constantValues) unwrapUnpackedArray(unpackedArray.elements(), values, biggestElementSize); diff --git a/tools/reflect/src/SvStruct.cpp b/tools/reflect/src/SvStruct.cpp index 24264f6f2..15fed97df 100644 --- a/tools/reflect/src/SvStruct.cpp +++ b/tools/reflect/src/SvStruct.cpp @@ -8,8 +8,8 @@ #include "slang/ast/symbols/VariableSymbols.h" #include "slang/util/OS.h" -void SvStruct::toCpp(HppFile& hppFile, std::string_view _namespace, const SvAliases& aliases, - bool noSystemC) const { +void SvStruct::toCpp(HppFile& hppFile, const std::string_view _namespace, const SvAliases& aliases, + const bool noSystemC) const { //* STRUCT DECLARATION **/ auto structName = isCppReserved(type.name) ? fmt::format("_{}", type.name) : std::string(type.name); @@ -18,8 +18,8 @@ void SvStruct::toCpp(HppFile& hppFile, std::string_view _namespace, const SvAlia std::vector> members; - size_t structSize = type.getBitstreamWidth(); - auto cppType = CppType::fromSize(structSize); + const size_t structSize = type.getBitstreamWidth(); + const auto cppType = CppType::fromSize(structSize); if (cppType == CppType::SC_BV && noSystemC) { slang::OS::printE(fmt::format("Headers for the struct {} can not be generated without " @@ -41,29 +41,27 @@ void SvStruct::toCpp(HppFile& hppFile, std::string_view _namespace, const SvAlia members.emplace_back(variableName, SvType(variable.getType(), typeName)); } - std::reverse(members.begin(), members.end()); + std::ranges::reverse(members); //** MEMBERS DECLARATION **// - for (const auto& member : members) { - if (member.second.isStructOrEnum() && _namespace != member.second._namespace) { - hppFile.addWithIndent(fmt::format("{}::{} {};\n", member.second._namespace, - member.second.toString(), member.first)); - hppFile.addIncludeHeader(member.second._namespace); + for (const auto& [name, type] : members) { + if (type.isStructEnumOrUnion() && _namespace != type._namespace) { + hppFile.addWithIndent( + fmt::format("{}::{} {};\n", type._namespace, type.toString(), name)); + hppFile.addIncludeHeader(type._namespace); } else { - hppFile.addWithIndent(fmt::format("{} {};\n", member.second.toString(), member.first)); + hppFile.addWithIndent(fmt::format("{} {};\n", type.toString(), name)); } } hppFile.add("\n"); //** GENERATE START AND WIDTH OF EACH SIGNAL **// size_t startBit = 0; - for (const auto& member : members) { - hppFile.addWithIndent( - fmt::format("static constexpr size_t {}_s = {};\n", member.first, startBit)); - hppFile.addWithIndent( - fmt::format("static constexpr size_t {}_w = {};\n", member.first, member.second.size)); - startBit += member.second.size; + for (const auto& [name, type] : members) { + hppFile.addWithIndent(fmt::format("static constexpr size_t {}_s = {};\n", name, startBit)); + hppFile.addWithIndent(fmt::format("static constexpr size_t {}_w = {};\n", name, type.size)); + startBit += type.size; } hppFile.addWithIndent(fmt::format("static constexpr size_t _size = {};\n", structSize)); hppFile.add("\n"); @@ -82,37 +80,36 @@ void SvStruct::toCpp(HppFile& hppFile, std::string_view _namespace, const SvAlia std::vector values; if (structSize > 64) { - for (const auto& member : members) { - if (member.second.size == 1) - values.emplace_back(fmt::format("__data.get_bit({0}_s)", member.first)); - else if (member.second.size > 64) + for (const auto& [name, type] : members) { + if (type.size == 1) + values.emplace_back(fmt::format("__data.get_bit({0}_s)", name)); + else if (type.size > 64) values.emplace_back( - fmt::format("__data.range({0}_s + {0}_w - 1, {0}_s)", member.first)); + fmt::format("__data.range({0}_s + {0}_w - 1, {0}_s)", name)); else - values.emplace_back(fmt::format( - "__data.range({0}_s + {0}_w - 1, {0}_s).to_uint64()", member.first)); + values.emplace_back( + fmt::format("__data.range({0}_s + {0}_w - 1, {0}_s).to_uint64()", name)); } } else { - for (const auto& member : members) - values.emplace_back(fmt::format("(__data >> {0}_s) & (~0ULL >> (64 - {1}))", - member.first, member.second.size)); + for (const auto& [name, type] : members) + values.emplace_back( + fmt::format("(__data >> {0}_s) & (~0ULL >> (64 - {1}))", name, type.size)); } for (auto i = 0; i < members.size(); i++) { - const auto& member = members[i]; + const auto& [name, type] = members[i]; const auto& value = values[i]; - if (member.second.isStructOrEnum()) - if (_namespace != member.second._namespace) - hppFile.addWithIndent(fmt::format("{} = {}::{}({});\n", member.first, - member.second._namespace, - member.second.toString(), value)); + if (type.isStructEnumOrUnion()) + if (_namespace != type._namespace) + hppFile.addWithIndent(fmt::format("{} = {}::{}({});\n", name, type._namespace, + type.toString(), value)); else - hppFile.addWithIndent(fmt::format("{} = {}({});\n", member.first, - member.second.toString(), value)); + hppFile.addWithIndent( + fmt::format("{} = {}({});\n", name, type.toString(), value)); else - hppFile.addWithIndent(fmt::format("{} = {};\n", member.first, value)); + hppFile.addWithIndent(fmt::format("{} = {};\n", name, value)); } hppFile.decreaseIndent(); @@ -128,24 +125,22 @@ void SvStruct::toCpp(HppFile& hppFile, std::string_view _namespace, const SvAlia hppFile.increaseIndent(); - for (const auto& member : members) { + for (const auto& [name, type] : members) { std::string value; - if (member.second.size == 1) - value = fmt::format("__data.get_bit({0}_s)", member.first); + if (type.size == 1) + value = fmt::format("__data.get_bit({0}_s)", name); else - value = fmt::format("__data.range({0}_s + {0}_w - 1, {0}_s).to_uint64()", - member.first); - - if (member.second.isStructOrEnum()) - if (_namespace != member.second._namespace) - hppFile.addWithIndent(fmt::format("{} = {}::{}({});\n", member.first, - member.second._namespace, - member.second.toString(), value)); + value = fmt::format("__data.range({0}_s + {0}_w - 1, {0}_s).to_uint64()", name); + + if (type.isStructEnumOrUnion()) + if (_namespace != type._namespace) + hppFile.addWithIndent(fmt::format("{} = {}::{}({});\n", name, type._namespace, + type.toString(), value)); else - hppFile.addWithIndent(fmt::format("{} = {}({});\n", member.first, - member.second.toString(), value)); + hppFile.addWithIndent( + fmt::format("{} = {}({});\n", name, type.toString(), value)); else - hppFile.addWithIndent(fmt::format("{} = {};\n", member.first, value)); + hppFile.addWithIndent(fmt::format("{} = {};\n", name, value)); } hppFile.decreaseIndent(); @@ -157,17 +152,16 @@ void SvStruct::toCpp(HppFile& hppFile, std::string_view _namespace, const SvAlia hppFile.addWithIndent(fmt::format("operator {}() const {{\n", cppTypeStr)); hppFile.increaseIndent(); hppFile.addWithIndent(fmt::format("auto ret = {}();\n", cppTypeStr)); - for (const auto& member : members) { - if (member.second.cppType == CppType::BOOL) { - hppFile.addWithIndent(fmt::format("ret.set_bit({0}_s, {0});\n", member.first)); + for (const auto& [name, type] : members) { + if (type.cppType == CppType::BOOL) { + hppFile.addWithIndent(fmt::format("ret.set_bit({0}_s, {0});\n", name)); } else { - hppFile.addWithIndent( - fmt::format("ret.range({0}_s + {0}_w - 1, {0}_s) = ", member.first)); - if (member.second.isStructOrEnum() && member.second.size > 64) - hppFile.add(fmt::format("sc_bv<{}>({});\n", member.second.size, member.first)); + hppFile.addWithIndent(fmt::format("ret.range({0}_s + {0}_w - 1, {0}_s) = ", name)); + if (type.isStructEnumOrUnion() && type.size > 64) + hppFile.add(fmt::format("sc_bv<{}>({});\n", type.size, name)); else - hppFile.add(fmt::format("{};\n", member.first)); + hppFile.add(fmt::format("{};\n", name)); } } hppFile.addWithIndent("return ret;\n"); @@ -176,9 +170,9 @@ void SvStruct::toCpp(HppFile& hppFile, std::string_view _namespace, const SvAlia hppFile.addWithIndent(fmt::format("operator {}() const {{\n", cppTypeStr)); hppFile.increaseIndent(); hppFile.addWithIndent(fmt::format("{} ret = 0;\n", cppTypeStr)); - for (const auto& member : members) { + for (const auto& name : members | std::views::keys) { hppFile.addWithIndent( - fmt::format("ret |= static_cast<{0}>({1}) << {1}_s;\n", cppTypeStr, member.first)); + fmt::format("ret |= static_cast<{0}>({1}) << {1}_s;\n", cppTypeStr, name)); } hppFile.addWithIndent("return ret;\n"); } @@ -190,17 +184,16 @@ void SvStruct::toCpp(HppFile& hppFile, std::string_view _namespace, const SvAlia hppFile.addWithIndent(fmt::format("operator sc_bv<{}>() const {{\n", structSize)); hppFile.increaseIndent(); hppFile.addWithIndent(fmt::format("auto ret = sc_bv<{}>();\n", structSize)); - for (const auto& member : members) { - if (member.second.cppType == CppType::BOOL) { - hppFile.addWithIndent(fmt::format("ret.set_bit({0}_s, {0});\n", member.first)); + for (const auto& [name, type] : members) { + if (type.cppType == CppType::BOOL) { + hppFile.addWithIndent(fmt::format("ret.set_bit({0}_s, {0});\n", name)); } else { - hppFile.addWithIndent( - fmt::format("ret.range({0}_s + {0}_w - 1, {0}_s) = ", member.first)); - if (member.second.isStructOrEnum() && member.second.size > 64) - hppFile.add(fmt::format("sc_bv<{}>({});\n", member.second.size, member.first)); + hppFile.addWithIndent(fmt::format("ret.range({0}_s + {0}_w - 1, {0}_s) = ", name)); + if (type.isStructEnumOrUnion() && type.size > 64) + hppFile.add(fmt::format("sc_bv<{}>({});\n", type.size, name)); else - hppFile.add(fmt::format("{};\n", member.first)); + hppFile.add(fmt::format("{};\n", name)); } } hppFile.addWithIndent("return ret;\n"); @@ -213,16 +206,16 @@ void SvStruct::toCpp(HppFile& hppFile, std::string_view _namespace, const SvAlia hppFile.increaseIndent(); hppFile.addWithIndent("std::stringstream ss;\n"); bool first = true; - for (const auto& member : members) { + for (const auto& [name, type] : members) { if (first) - hppFile.addWithIndent(fmt::format("ss << \"{0}\" << \" = \" << ", member.first)); + hppFile.addWithIndent(fmt::format("ss << \"{0}\" << \" = \" << ", name)); else - hppFile.addWithIndent(fmt::format("ss << \" {0}\" << \" = \" << ", member.first)); + hppFile.addWithIndent(fmt::format("ss << \" {0}\" << \" = \" << ", name)); - if (member.second.cppType == CppType::SC_BV || member.second.cppType == CppType::STRUCT) - hppFile.add(fmt::format("{0}.to_string();\n", member.first)); + if (type.cppType == CppType::SC_BV || type.cppType == CppType::STRUCT) + hppFile.add(fmt::format("{0}.to_string();\n", name)); else - hppFile.add(fmt::format("{0};\n", member.first)); + hppFile.add(fmt::format("{0};\n", name)); first = false; } @@ -240,39 +233,35 @@ void SvStruct::toCpp(HppFile& hppFile, std::string_view _namespace, const SvAlia hppFile.addWithIndent("}\n"); //* STATIC GET FUNCTIONS *// - for (const auto& member : members) { - if (member.second.isStructOrEnum() && _namespace != member.second._namespace) { + for (const auto& [name, type] : members) { + if (type.isStructEnumOrUnion() && _namespace != type._namespace) { hppFile.addWithIndent(fmt::format("static {}::{} get_{} (const {}& __data) {{\n", - member.second._namespace, member.second.toString(), - member.first, cppTypeStr)); + type._namespace, type.toString(), name, cppTypeStr)); } else { hppFile.addWithIndent(fmt::format("static {} get_{} (const {}& __data) {{\n", - member.second.toString(), member.first, cppTypeStr)); + type.toString(), name, cppTypeStr)); } hppFile.increaseIndent(); std::string value; if (cppType == CppType::SC_BV) { - if (member.second.size == 1) - value = fmt::format("__data.get_bit({0}_s)", member.first); - else if (member.second.size > 64) - value = fmt::format("__data.range({0}_s + {0}_w - 1, {0}_s)", member.first); + if (type.size == 1) + value = fmt::format("__data.get_bit({0}_s)", name); + else if (type.size > 64) + value = fmt::format("__data.range({0}_s + {0}_w - 1, {0}_s)", name); else - value = fmt::format("__data.range({0}_s + {0}_w - 1, {0}_s).to_uint64()", - member.first); + value = fmt::format("__data.range({0}_s + {0}_w - 1, {0}_s).to_uint64()", name); } else { - value = fmt::format("(__data >> {0}_s) & (~0ULL >> (64 - {1}))", member.first, - member.second.size); + value = fmt::format("(__data >> {0}_s) & (~0ULL >> (64 - {1}))", name, type.size); } - if (member.second.isStructOrEnum()) - if (_namespace != member.second._namespace) - hppFile.addWithIndent(fmt::format("return {}::{}({});\n", member.second._namespace, - member.second.toString(), value)); - else + if (type.isStructEnumOrUnion()) + if (_namespace != type._namespace) hppFile.addWithIndent( - fmt::format("return {}({});\n", member.second.toString(), value)); + fmt::format("return {}::{}({});\n", type._namespace, type.toString(), value)); + else + hppFile.addWithIndent(fmt::format("return {}({});\n", type.toString(), value)); else hppFile.addWithIndent(fmt::format("return {};\n", value)); diff --git a/tools/reflect/src/SvType.cpp b/tools/reflect/src/SvType.cpp index c127d9462..6544712b7 100644 --- a/tools/reflect/src/SvType.cpp +++ b/tools/reflect/src/SvType.cpp @@ -17,12 +17,14 @@ SvType::SvType(const Type& type) { cppType = CppType::fromSize(size); else if (type.isEnum()) cppType = CppType::ENUM; - else if (type.isStruct() || type.isUnpackedStruct()) + else if (type.isStruct()) cppType = CppType::STRUCT; + else if (type.isUnion()) + cppType = CppType::UNION; else SLANG_UNREACHABLE; - if (this->isEnum() || this->isStruct()) + if (this->isStructEnumOrUnion()) _namespace = type.getParentScope()->asSymbol().name; } @@ -33,9 +35,9 @@ std::ostream& operator<<(std::ostream& os, const SvType& type) { std::string SvType::toString() const { std::stringstream ss; if (cppType == CppType::SC_BV) - ss << fmt::format(fmt::runtime(CppType::toString(cppType)), size); - else if (this->isEnum() || this->isStruct()) - ss << fmt::format(fmt::runtime(CppType::toString(cppType)), name); + ss << format(fmt::runtime(CppType::toString(cppType)), size); + else if (this->isStructEnumOrUnion()) + ss << format(fmt::runtime(CppType::toString(cppType)), name); else ss << CppType::toString(cppType); @@ -43,7 +45,7 @@ std::string SvType::toString() const { } namespace CppType { -std::string toString(const CppType::Type& cppType) { +std::string toString(const Type& cppType) { // clang-format off switch (cppType) { case BOOL: return "bool"; @@ -52,17 +54,18 @@ std::string toString(const CppType::Type& cppType) { case SC_BV: return "sc_bv<{}>"; case STRUCT: return "{}"; case ENUM: return "{}"; + case UNION: return "{}"; } // clang-format on SLANG_UNREACHABLE; } -CppType::Type fromSize(size_t size) { +Type fromSize(const size_t size) { // clang-format off - if (size == 1) return CppType::BOOL; - else if (size <= 32) return CppType::U32; - else if (size <= 64) return CppType::U64; - else return CppType::SC_BV; + if (size == 1) return BOOL; + if (size <= 32) return U32; + if (size <= 64) return U64; + return SC_BV; // clang-format on } } // namespace CppType diff --git a/tools/reflect/src/SvTypeReflector.cpp b/tools/reflect/src/SvTypeReflector.cpp index 4d379aeba..1f49d2102 100644 --- a/tools/reflect/src/SvTypeReflector.cpp +++ b/tools/reflect/src/SvTypeReflector.cpp @@ -8,6 +8,7 @@ #include "SvGeneric.h" #include "SvLocalParam.h" #include "SvStruct.h" +#include "SvUnion.h" #include "fmt/color.h" #include "slang/util/OS.h" @@ -38,14 +39,17 @@ void SvTypeReflector::reflect() { std::unordered_map namespaces; compilation->getRoot().visit(makeVisitor([&](auto&, const TypeAliasType& type) { - if (checkPublic(type, slang::parsing::TokenKind::Semicolon)) { + if (checkPublic(type, parsing::TokenKind::Semicolon)) { if (type.isStruct()) namespaces[getNamespace(type)].members.emplace_back( std::make_unique(type)); else if (type.isEnum()) namespaces[getNamespace(type)].members.emplace_back(std::make_unique(type)); + else if (type.isUnion()) + namespaces[getNamespace(type)].members.emplace_back( + std::make_unique(type)); if (verbose) - OS::print(fmt::fg(fmt::color::yellow_green), + OS::print(fg(fmt::color::yellow_green), fmt::format("Detected {} as public\n", type.name)); } @@ -58,31 +62,34 @@ void SvTypeReflector::reflect() { namespaces[getNamespace(type)].members.emplace_back( std::make_unique(type)); if (verbose) - OS::print(fmt::fg(fmt::color::yellow_green), + OS::print(fg(fmt::color::yellow_green), fmt::format("Detected {} as public\n", type.name)); } })); - for (const auto& _namespace : namespaces) { - if (_namespace.second.members.empty()) + for (const auto& [namespaceName, namespaceMembers] : namespaces) { + if (namespaceMembers.members.empty()) continue; //** NAMESPACE DECLARATION **// - auto& hpp = cppEmitter.newNamespace(_namespace.first); - hpp.add(fmt::format("namespace {} {{\n", _namespace.first)); + auto& hpp = cppEmitter.newNamespace(namespaceName); + hpp.add(fmt::format("namespace {} {{\n", namespaceName)); hpp.increaseIndent(); //** NAMESPACE MEMBERS DECLARATION **// - for (const auto& generic : _namespace.second.members) { + for (const auto& generic : namespaceMembers.members) { if (generic->isStruct()) reinterpret_cast(generic.get()) - ->toCpp(hpp, _namespace.first, _namespace.second.aliases, noSystemC); + ->toCpp(hpp, namespaceName, namespaceMembers.aliases, noSystemC); else if (generic->isEnum()) reinterpret_cast(generic.get()) - ->toCpp(hpp, _namespace.first, _namespace.second.aliases, noSystemC); + ->toCpp(hpp, namespaceName, namespaceMembers.aliases, noSystemC); + else if (generic->isUnion()) + reinterpret_cast(generic.get()) + ->toCpp(hpp, namespaceName, namespaceMembers.aliases, noSystemC); else if (generic->isLocalParam()) reinterpret_cast(generic.get()) - ->toCpp(hpp, _namespace.first, _namespace.second.aliases, noSystemC); + ->toCpp(hpp, namespaceName, namespaceMembers.aliases, noSystemC); } hpp.decreaseIndent(); diff --git a/tools/reflect/src/SvUnion.cpp b/tools/reflect/src/SvUnion.cpp new file mode 100644 index 000000000..51743bc77 --- /dev/null +++ b/tools/reflect/src/SvUnion.cpp @@ -0,0 +1,215 @@ +// SPDX-FileCopyrightText: Michael Popoloski +// SPDX-License-Identifier: MIT + +#include "SvUnion.h" + +#include +#include +#include +#include +#include + +void SvUnion::toCpp(HppFile& hppFile, std::string_view _namespace, const SvAliases& aliases, + const bool noSystemC) const { + //* UNION DECLARATION **/ + auto unionName = isCppReserved(type.name) ? fmt::format("_{}", type.name) + : std::string(type.name); + hppFile.addWithIndent(fmt::format("struct {} {{\n", unionName)); + hppFile.increaseIndent(); + + std::vector> members; + + const size_t unionSize = type.getBitstreamWidth(); + const auto cppType = CppType::fromSize(unionSize); + hppFile.addWithIndent(fmt::format("static constexpr size_t _size = {};\n\n", unionSize)); + + if (cppType == CppType::SC_BV && noSystemC) { + slang::OS::printE(fmt::format("Headers for the union {} can not be generated without " + "SystemC support. Please remove the option --no-sc.", + type.name)); + exit(1); + } + + auto cppTypeStr = unionSize > 64 ? format(fmt::runtime(toString(cppType)), unionSize) + : toString(cppType); + + // Create a sc bit vector to store the data of the Union + hppFile.addWithIndent(fmt::format("{} union_data;\n\n", cppTypeStr)); + + // Check if some headers need to be included + for (const auto& member : type.getCanonicalType().as().members()) { + const auto& variable = member.as(); + + const auto variableName = isCppReserved(variable.name) ? fmt::format("_{}", variable.name) + : std::string(variable.name); + const auto typeName = resolveAlias(variable.getType().name, aliases); + + const auto variableType = SvType(variable.getType(), typeName); + if (variableType.isStructEnumOrUnion() && _namespace != variableType._namespace) + hppFile.addIncludeHeader(variableType._namespace); + + members.emplace_back(variableName, variableType); + } + + //** GENERATE DEFAULT CONSTRUCTOR **// + hppFile.addWithIndent(fmt::format("{}() = default;\n\n", unionName)); + + //** GENERATE CONSTRUCTOR **// + { + hppFile.addWithIndent(fmt::format("{}(const {}& __data) {{\n", unionName, cppTypeStr)); + + hppFile.increaseIndent(); + + hppFile.addWithIndent("union_data = __data;\n"); + + hppFile.decreaseIndent(); + hppFile.addWithIndent("}\n\n"); + } + + //** GENERATE SC_BV CONSTRUCTOR **// + // Note: This constructor will be generated only if the other constructor is not already + // from a sc_bv + if (!noSystemC && unionSize <= 64) { + hppFile.addWithIndent( + fmt::format("{}(const sc_bv<{}>& __data) {{\n", unionName, type.getBitstreamWidth())); + + hppFile.increaseIndent(); + + hppFile.addWithIndent("union_data = __data.to_uint64();\n"); + + hppFile.decreaseIndent(); + hppFile.addWithIndent("}\n\n"); + } + + //** GENERATE SERIALIZERS **// + + // Base serializer for the inner type of the Union + if (cppType == CppType::SC_BV) { + hppFile.addWithIndent(fmt::format("operator {}() const {{\n", cppTypeStr)); + hppFile.increaseIndent(); + hppFile.addWithIndent(fmt::format("return sc_bv<{}>(union_data);\n", unionSize)); + } + else { + hppFile.addWithIndent(fmt::format("operator {}() const {{\n", cppTypeStr)); + hppFile.increaseIndent(); + hppFile.addWithIndent("return union_data;\n"); + } + + hppFile.decreaseIndent(); + hppFile.addWithIndent("}\n\n"); + + // Other serializers for the different types of the union members + if (!members.empty()) { + std::set memberTypes = {cppTypeStr}; + for (const auto& [_, memberType] : members) { + auto memberTypeName = memberType.toString(); + + // Skip the serializer for this member if the type serializer has already been generated + if (memberTypes.contains(memberTypeName)) + continue; + memberTypes.insert(memberTypeName); + + if (_namespace != memberType._namespace) + hppFile.addWithIndent(fmt::format("operator {}::{}() const {{\n", + memberType._namespace, memberTypeName)); + else + hppFile.addWithIndent(fmt::format("operator {}() const {{\n", memberTypeName)); + + hppFile.increaseIndent(); + + constexpr auto unionVariable = "union_data"sv; + + if (memberType.isStructEnumOrUnion()) { + if (_namespace != memberType._namespace) + hppFile.addWithIndent(fmt::format("return {}::{}({});\n", memberType._namespace, + memberTypeName, unionVariable)); + else + hppFile.addWithIndent( + fmt::format("return {}({});\n", memberTypeName, unionVariable)); + } + else { + if (unionSize > 64) + hppFile.addWithIndent(fmt::format("return {};\n", unionVariable)); + else + hppFile.addWithIndent(fmt::format("return static_cast<{}>({});\n", + memberTypeName, unionVariable)); + } + + hppFile.decreaseIndent(); + hppFile.addWithIndent("}\n\n"); + } + } + + //** GENERATE EXPLICIT FUNCTIONS TO GET THE DIFFERENT UNION MEMBERS **// + if (!members.empty()) { + for (const auto& [memberName, memberType] : members) { + auto memberTypeName = memberType.toString(); + + if (_namespace != memberType._namespace) + hppFile.addWithIndent(fmt::format("{}::{} {}() const {{\n", memberType._namespace, + memberTypeName, memberName)); + else + hppFile.addWithIndent( + fmt::format("{} {}() const {{\n", memberTypeName, memberName)); + + hppFile.increaseIndent(); + + constexpr auto unionVariable = "union_data"sv; + + if (memberType.isStructEnumOrUnion()) { + if (_namespace != memberType._namespace) + hppFile.addWithIndent(fmt::format("return {}::{}({});\n", memberType._namespace, + memberTypeName, unionVariable)); + else + hppFile.addWithIndent( + fmt::format("return {}({});\n", memberTypeName, unionVariable)); + } + else { + if (unionSize > 64) + hppFile.addWithIndent(fmt::format("return {};\n", unionVariable)); + else + hppFile.addWithIndent(fmt::format("return static_cast<{}>({});\n", + memberTypeName, unionVariable)); + } + + hppFile.decreaseIndent(); + hppFile.addWithIndent("}\n\n"); + } + } + + //* GENERATE TO STRING FUNCTION *// + hppFile.addWithIndent("std::string to_string() const {\n"); + hppFile.increaseIndent(); + hppFile.addWithIndent("std::stringstream ss;\n"); + bool first = true; + for (const auto& [memberName, memberType] : members) { + if (first) + hppFile.addWithIndent(fmt::format("ss << \"{0}\" << \" = \" << ", memberName)); + else + hppFile.addWithIndent(fmt::format("ss << \" {0}\" << \" = \" << ", memberName)); + + if (memberType.cppType == CppType::SC_BV) + hppFile.add(fmt::format("static_cast<{}::{}>(*this).to_string();\n", + memberType._namespace, memberType.name, memberName)); + else + hppFile.add(fmt::format("static_cast<{}::{}>(*this);\n", memberType._namespace, + memberType.name, memberName)); + + first = false; + } + hppFile.addWithIndent("return std::move(ss.str());\n"); + hppFile.decreaseIndent(); + hppFile.addWithIndent("}\n\n"); + + //* OVERLOAD << OPERATOR *// + hppFile.addWithIndent(fmt::format( + "friend std::ostream& operator<<(std::ostream& os, const {}& __data) {{\n", unionName)); + hppFile.increaseIndent(); + hppFile.addWithIndent("os << __data.to_string();\n"); + hppFile.addWithIndent("return os;\n"); + hppFile.decreaseIndent(); + hppFile.addWithIndent("}\n"); + + hppFile.decreaseIndent(); + hppFile.addWithIndent("};\n\n"); +} diff --git a/tools/reflect/src/reflect.cpp b/tools/reflect/src/reflect.cpp index fd6394b4d..cc61f75f9 100644 --- a/tools/reflect/src/reflect.cpp +++ b/tools/reflect/src/reflect.cpp @@ -9,6 +9,7 @@ #include "ASTVisitors.h" #include "SvTypeReflector.h" #include +#include #include #include "slang/driver/Driver.h" @@ -41,7 +42,7 @@ int main(int argc, char** argv) { return 1; if (showHelp) { - slang::OS::print(fmt::format("{}", driver.cmdLine.getHelpText("slang-reflect"))); + OS::print(fmt::format("{}", driver.cmdLine.getHelpText("slang-reflect"))); return 0; } @@ -52,7 +53,7 @@ int main(int argc, char** argv) { return 0; } - bool info = verbose && *verbose; + const bool info = verbose && *verbose; fs::path outputPath = "."; if (outputDir && !toStdout) { @@ -86,13 +87,13 @@ int main(int argc, char** argv) { return 1; } - bool noSc = noSystemC.has_value() && noSystemC.value(); + const bool noSc = noSystemC.has_value() && noSystemC.value(); auto reflector = SvTypeReflector(std::move(compilation), info, noSc); reflector.reflect(); if (toStdout && *toStdout) { - std::cout << reflector.emit() << std::endl; + std::cout << reflector.emit() << '\n'; } else { OS::print("Emitting code to: " + absolute(outputPath).string() + "\n"); diff --git a/tools/tidy/src/style/NoDotVarInPortConnection.cpp b/tools/tidy/src/style/NoDotVarInPortConnection.cpp index 3dc457552..c4f6f7943 100644 --- a/tools/tidy/src/style/NoDotVarInPortConnection.cpp +++ b/tools/tidy/src/style/NoDotVarInPortConnection.cpp @@ -13,20 +13,19 @@ using namespace slang::syntax; namespace no_dot_var_in_port_connection { -struct PortConnectionVisitor : public SyntaxVisitor { +struct PortConnectionVisitor : SyntaxVisitor { void handle(const NamedPortConnectionSyntax& port) { if (!port.openParen) foundPorts.push_back(&port); } -public: std::vector foundPorts; }; -struct MainVisitor : public TidyVisitor, ASTVisitor { +struct MainVisitor : TidyVisitor, ASTVisitor { explicit MainVisitor(Diagnostics& diagnostics) : TidyVisitor(diagnostics) {} - void handle(const InstanceBodySymbol& symbol) { + void handle(const InstanceBodySymbol& symbol) const { NEEDS_SKIP_SYMBOL(symbol) if (!symbol.getSyntax()) return; @@ -43,9 +42,9 @@ struct MainVisitor : public TidyVisitor, ASTVisitor { using namespace no_dot_var_in_port_connection; -class NoDotVarInPortConnection : public TidyCheck { +class NoDotVarInPortConnection final : public TidyCheck { public: - [[maybe_unused]] explicit NoDotVarInPortConnection(TidyKind kind) : TidyCheck(kind) {} + [[maybe_unused]] explicit NoDotVarInPortConnection(const TidyKind kind) : TidyCheck(kind) {} bool check(const RootSymbol& root) override { MainVisitor visitor(diagnostics);