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

Introduce IEEE Std 1497-2001 Standard Delay Format (SDF) parsing #1083

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ ci:
autoupdate_commit_msg: "chore: update pre-commit hooks"
autofix_commit_msg: "style: pre-commit fixes"

exclude: grammar.md
exclude: '^grammar(_sdf)?.md$'

repos:
# Standard hooks
Expand Down
1 change: 1 addition & 0 deletions bindings/python/CompBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ void registerCompilation(py::module_& m) {
.def("addSearchExtension", &SourceLoader::addSearchExtension, "extension"_a)
.def("addLibraryMaps", &SourceLoader::addLibraryMaps, "pattern"_a, "basePath"_a,
"optionBag"_a)
.def("addSDFFiles", &SourceLoader::addSDFFiles, "pattern"_a, "basePath"_a, "optionBag"_a)
.def("addSeparateUnit", &SourceLoader::addSeparateUnit, "filePatterns"_a, "includePaths"_a,
"defines"_a, "libraryName"_a)
.def("loadSources", &SourceLoader::loadSources)
Expand Down
3,782 changes: 1,891 additions & 1,891 deletions docs/grammar.md

Large diffs are not rendered by default.

144 changes: 144 additions & 0 deletions docs/grammar_sdf.md

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions include/slang/driver/SourceLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ class SLANG_EXPORT SourceLoader {
void addLibraryMaps(std::string_view pattern, const std::filesystem::path& basePath,
const Bag& optionBag);

/// @brief Adds SDF files to the loader.
///
/// All files that match the given pattern will be loaded and parsed as if
/// they were SDF files.
void addSDFFiles(std::string_view pattern, const std::filesystem::path& basePath,
const Bag& optionBag);

/// @brief Adds a group of files as a separately compiled compilation unit.
///
/// Unlike files added via the @a addFiles method, files added here are
Expand All @@ -124,6 +131,9 @@ class SLANG_EXPORT SourceLoader {
const std::vector<std::string>& includePaths,
std::vector<std::string> defines, const std::string& libraryName);

/// Returns a list of all library map syntax trees that have been loaded and parsed.
const SyntaxTreeList& getSDFUnits() const { return sdfUnitTrees; }

/// Returns a list of all library map syntax trees that have been loaded and parsed.
const SyntaxTreeList& getLibraryMaps() const { return libraryMapTrees; }

Expand Down Expand Up @@ -206,6 +216,8 @@ class SLANG_EXPORT SourceLoader {
void addLibraryMapsInternal(std::string_view pattern, const std::filesystem::path& basePath,
const Bag& optionBag, bool expandEnvVars,
flat_hash_set<std::filesystem::path>& seenMaps);
void addSDFFilesInternal(std::string_view pattern, const std::filesystem::path& basePath,
const Bag& optionBag);
void createLibrary(const syntax::LibraryDeclarationSyntax& syntax,
const std::filesystem::path& basePath);
LoadResult loadAndParse(const FileEntry& fileEntry, const Bag& optionBag,
Expand All @@ -223,6 +235,7 @@ class SLANG_EXPORT SourceLoader {
flat_hash_set<std::string_view> uniqueExtensions;
std::vector<std::string> errors;
SyntaxTreeList libraryMapTrees;
SyntaxTreeList sdfUnitTrees;

static constexpr int MinFilesForThreading = 4;
};
Expand Down
4 changes: 4 additions & 0 deletions include/slang/parsing/Lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct SLANG_EXPORT LexerOptions {
uint32_t maxErrors = 16;

/// The version of the SystemVerilog language to use.
/// If set to LanguageVersion::v1497_2001 preprocessor will support
/// SDF keywords and special tokens.
LanguageVersion languageVersion = LanguageVersion::Default;

/// If true, the preprocessor will support legacy protected envelope directives,
Expand Down Expand Up @@ -88,6 +90,8 @@ class SLANG_EXPORT Lexer {
const SourceManager& sourceManager, Token sourceToken, size_t offset,
KeywordVersion keywordVersion, SmallVectorBase<Token>& results);

bool isSDFFile() { return options.languageVersion == LanguageVersion::v1497_2001; }

private:
Lexer(BufferID bufferId, std::string_view source, const char* startPtr, BumpAllocator& alloc,
Diagnostics& diagnostics, LexerOptions options);
Expand Down
4 changes: 3 additions & 1 deletion include/slang/parsing/LexerFacts.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ enum class SLANG_EXPORT KeywordVersion : uint8_t {
v1800_2009 = 5,
v1800_2012 = 6,
v1800_2017 = 7,
v1800_2023 = 8
v1800_2023 = 8,
// IEEE Standard for Standard Delay Format (SDF)
v1497_2001 = 9
};

class SLANG_EXPORT LexerFacts {
Expand Down
78 changes: 73 additions & 5 deletions include/slang/parsing/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
//------------------------------------------------------------------------------
#pragma once

#include <set>

#include "slang/parsing/NumberParser.h"
#include "slang/parsing/ParserBase.h"
#include "slang/parsing/ParserMetadata.h"
Expand Down Expand Up @@ -54,9 +56,15 @@ enum class ExpressionOptions {
BinsSelectContext = 1 << 6,

/// "dist" expressions are allowed in this context.
AllowDist = 1 << 7
AllowDist = 1 << 7,

/// Allows to parse SDF conditional port expressions
SDFCondExpr = 1 << 8,

// Allows to parse SDF timing check conditional expressions
SDFTimingCheckCondExpr = 1 << 9,
};
SLANG_BITMASK(ExpressionOptions, AllowDist)
SLANG_BITMASK(ExpressionOptions, SDFTimingCheckCondExpr)

/// Various options for parsing names.
enum class NameOptions {
Expand Down Expand Up @@ -137,6 +145,10 @@ struct SLANG_EXPORT ParserOptions {
/// Implements a full syntax parser for SystemVerilog.
class SLANG_EXPORT Parser : ParserBase, syntax::SyntaxFacts {
public:
Parser(const Parser&) = delete;
Parser(Parser&&) = delete;
Parser& operator=(const Parser&) = delete;
Parser& operator=(Parser&&) = delete;
explicit Parser(Preprocessor& preprocessor, const Bag& options = {});

/// Parse a whole compilation unit.
Expand All @@ -145,6 +157,9 @@ class SLANG_EXPORT Parser : ParserBase, syntax::SyntaxFacts {
/// Parse a library map file.
syntax::LibraryMapSyntax& parseLibraryMap();

/// Parse a standard delay format (SDF) file.
syntax::SDFUnitSyntax& parseSDFUnit();

/// Parse an expression / statement / module / class / name.
/// These are mostly for testing; only use if you know that the
/// source stream is currently looking at one of these.
Expand Down Expand Up @@ -179,17 +194,21 @@ class SLANG_EXPORT Parser : ParserBase, syntax::SyntaxFacts {
// clang-format off
syntax::ExpressionSyntax& parseMinTypMaxExpression(bitmask<ExpressionOptions> options = {});
syntax::ExpressionSyntax& parsePrimaryExpression(bitmask<ExpressionOptions> options);
syntax::ExpressionSyntax& parseSDFPrimaryExpression(bitmask<ExpressionOptions> options);
syntax::ExpressionSyntax& parseSDFScalarConstant();
syntax::ExpressionSyntax& parseIntegerExpression(bool disallowVector);
syntax::ExpressionSyntax& parseInsideExpression(syntax::ExpressionSyntax& expr);
syntax::ExpressionSyntax& parsePostfixExpression(syntax::ExpressionSyntax& expr, bitmask<ExpressionOptions> options);
syntax::ExpressionSyntax& parseSDFPostfixExpression(syntax::ExpressionSyntax& expr);
syntax::ExpressionSyntax& parseNewExpression(syntax::NameSyntax& expr, bitmask<ExpressionOptions> options);
syntax::ConcatenationExpressionSyntax& parseConcatenation(Token openBrace, syntax::ExpressionSyntax* first);
syntax::ConcatenationExpressionSyntax& parseConcatenation(Token openBrace, syntax::ExpressionSyntax* first, bool isSDFCondExpr = false);
syntax::StreamingConcatenationExpressionSyntax& parseStreamConcatenation(Token openBrace);
syntax::StreamExpressionSyntax& parseStreamExpression();
syntax::RangeListSyntax& parseRangeList();
syntax::ExpressionSyntax& parseValueRangeElement(bitmask<ExpressionOptions> options = {});
syntax::ElementSelectSyntax& parseElementSelect();
syntax::SelectorSyntax* parseElementSelector();
syntax::NameSyntax& parseSDFHierIdentifier();
syntax::NameSyntax& parseName(bitmask<NameOptions> options);
syntax::NameSyntax& parseNamePart(bitmask<NameOptions> options);
syntax::ParameterValueAssignmentSyntax* parseParameterValueAssignment();
Expand All @@ -204,7 +223,7 @@ class SLANG_EXPORT Parser : ParserBase, syntax::SyntaxFacts {
syntax::EventExpressionSyntax& parseEventExpression();
syntax::NamedBlockClauseSyntax* parseNamedBlockClause();
syntax::TimingControlSyntax* parseTimingControl();
syntax::ConditionalPredicateSyntax& parseConditionalPredicate(syntax::ExpressionSyntax& first, TokenKind endKind, Token& end);
syntax::ConditionalPredicateSyntax& parseConditionalPredicate(syntax::ExpressionSyntax& first, TokenKind endKind, Token& end, bool isSDFCondPred = false);
syntax::ConditionalPatternSyntax& parseConditionalPattern();
syntax::ConditionalStatementSyntax& parseConditionalStatement(syntax::NamedLabelSyntax* label, AttrList attributes, Token uniqueOrPriority);
syntax::ElseClauseSyntax* parseElseClause();
Expand Down Expand Up @@ -378,6 +397,54 @@ class SLANG_EXPORT Parser : ParserBase, syntax::SyntaxFacts {
syntax::MemberSyntax* parseLibraryMember();
syntax::FilePathSpecSyntax& parseFilePathSpec();
syntax::LibraryDeclarationSyntax& parseLibraryDecl();
syntax::SDFTimescaleSyntax *parseSDFTimescale();
syntax::SDFCharMemberSyntax *parseSDFCharMember(TokenKind keywordKind, bool weak = true);
syntax::SDFValueSyntax *parseSDFValue(const std::set<TokenKind>& endKinds, bool withParens = false, bool isSign = true);
syntax::SDFDelayValueSyntax* parseSDFDelayValue();
std::span<syntax::SDFDelayValueSyntax*> parseSDFDelayValueList(bool isRetain = false);
syntax::SDFValueMemberSyntax *parseSDFValueMember(TokenKind keywordKind);
syntax::SDFHeaderSyntax& parseSDFHeader();
syntax::SDFNameSyntax* parseSDFName();
syntax::SDFPortSpecSyntax* parseSDFPortSpec();
syntax::SDFPortSyntax* parseSDFPort();
syntax::SDFPortEdgeSyntax* parseSDFPortEdge();
syntax::SDFCellInstanceSyntax* parseSDFCellInstance();
syntax::SDFExceptionSyntax* parseSDFException();
syntax::SDFPathPulseSyntax *parseSDFPathPulse();
syntax::SDFRetainSyntax* parseSDFRetain();
syntax::SDFIOPathSyntax *parseSDFIOPath();
syntax::SDFCondSyntax *parseSDFCond();
syntax::SDFCondElseSyntax *parseSDFCondElse();
syntax::SDFPortDelayDefSyntax *parseSDFPortDelayDef();
syntax::SDFInterconnectSyntax *parseSDFInterconnect();
syntax::SDFNetDelaySyntax *parseSDFNetDelay();
syntax::SDFDeviceSyntax *parseSDFDevice();
syntax::SDFAbsIncDelayTypeSyntax *parseSDFAbsIncDelayType();
std::span<syntax::SDFDelayTypeSyntax*> parseSDFDelayTypes();
syntax::SDFDelaySpecSyntax *parseSDFDelaySpec();
syntax::SDFPathConstraintSyntax *parseSDFPathConstraint();
syntax::SDFPeriodConstraintSyntax *parseSDFPeriodConstraint();
syntax::SDFConstraintPathSyntax* parseSDFConstraintPath();
syntax::SDFSumDiffConstraintSyntax* parseSDFSumDiffConstraint(bool isDiff = false);
syntax::SDFSkewConstraintSyntax* parseSDFSkewConstraint();
syntax::SDFTimingEnvConstructSyntax* parseSDFTimingEnvConstruct(bool isSlack = false);
syntax::SDFEdgeSyntax* parseSDFEdge();
syntax::SDFEdgePairSyntax* parseSDFEdgePair();
syntax::SDFWaveformSyntax* parseSDFWaveform();
std::span<syntax::SDFTimingEnvDefSyntax*> parseSDFTimingEnvDefs();
syntax::SDFTimingEnvSyntax *parseSDFTimingEnv();
syntax::SDFPortTimingCheckSyntax* parseSDFPortTimingCheck();
syntax::SDFTimingCheckConditionSyntax* parseSDFTimingCheckCondition(TokenKind keywordKind);
syntax::SDFTimingCheckDefSyntax* parseSDFTimingCheckDef(bool hasTwoPorts, bool hasTwoValues, bool isSign, bool hasConds = false);
std::span<syntax::SDFTimingCheckDefSyntax*> parseSDFTimingCheckDefs();
syntax::SDFTimingCheckSyntax* parseSDFTimingCheck();
syntax::SDFLabelDefSyntax* parseSDFLabelDef();
syntax::SDFLabelTypeSyntax* parseSDFLabelType();
std::span<syntax::SDFLabelTypeSyntax*> parseSDFLabelTypes();
syntax::SDFLabelSyntax *parseSDFLabel();
std::span<syntax::SDFTimingSpecSyntax*> parseSDFTimingSpecs();
std::span<syntax::SDFCellSyntax*> parseSDFCells();
syntax::SDFDelayFileSyntax *parseSDFDelayFile();
// clang-format on

template<bool (*IsEnd)(TokenKind)>
Expand All @@ -389,7 +456,8 @@ class SLANG_EXPORT Parser : ParserBase, syntax::SyntaxFacts {

template<typename TMember, typename TParseFunc>
std::span<TMember*> parseMemberList(TokenKind endKind, Token& endToken,
syntax::SyntaxKind parentKind, TParseFunc&& parseFunc);
syntax::SyntaxKind parentKind, TParseFunc&& parseFunc,
uint32_t memberLimit = 0);

template<typename IsItemFunc, typename ParseItemFunc>
bool parseCaseItems(TokenKind caseKind, SmallVectorBase<syntax::CaseItemSyntax*>& itemBuffer,
Expand Down
8 changes: 8 additions & 0 deletions include/slang/syntax/SyntaxFacts.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class SLANG_EXPORT SyntaxFacts {
/// unary prefix operator token.
static SyntaxKind getUnaryPrefixExpression(TokenKind kind);

/// @return the kind of syntax that should be created for the given
/// unary prefix operator token of SDF expressions.
static SyntaxKind getSDFUnaryPrefixExpression(TokenKind kind);

/// @return the kind of syntax that should be created for the given
/// unary postfix operator token.
static SyntaxKind getUnaryPostfixExpression(TokenKind kind);
Expand All @@ -39,6 +43,10 @@ class SLANG_EXPORT SyntaxFacts {
/// literal token.
static SyntaxKind getLiteralExpression(TokenKind kind);

/// @return the kind of syntax that should be created for the given
/// binary operator token of SDF expressions.
static SyntaxKind getSDFBinaryExpression(TokenKind kind);

/// @return the kind of syntax that should be created for the given
/// binary operator token.
static SyntaxKind getBinaryExpression(TokenKind kind);
Expand Down
32 changes: 32 additions & 0 deletions include/slang/syntax/SyntaxTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,38 @@ class SLANG_EXPORT SyntaxTree {
SourceManager& sourceManager,
const Bag& options = {});

/// Creates a syntax tree from a standard delay format (SDF) file.
/// @a path is the path to the source file on disk.
/// @a sourceManager is the manager that owns all of the loaded source code.
/// @a options is an optional bag of lexer, preprocessor, and parser options.
/// @return the created and parsed syntax tree.
static std::shared_ptr<SyntaxTree> fromSDFFile(std::string_view path,
SourceManager& sourceManager,
const Bag& options = {});

/// Creates a syntax tree from a standard delay format (SDF) located in memory.
/// @a text is the actual source code text.
/// @a sourceManager is the manager that owns all of the loaded source code.
/// @a name is an optional name to give to the loaded source buffer.
/// @a path is an optional path to give to the loaded source buffer.
/// @a options is an optional bag of lexer, preprocessor, and parser options.
/// @return the created and parsed syntax tree.
static std::shared_ptr<SyntaxTree> fromSDFText(std::string_view text,
SourceManager& sourceManager,
std::string_view name = "source"sv,
std::string_view path = "",
const Bag& options = {});

/// Creates a syntax tree from a standard delay format (SDF) already loaded into a source
/// buffer.
/// @a buffer is the loaded source buffer.
/// @a sourceManager is the manager that owns the buffer.
/// @a options is an optional bag of lexer, preprocessor, and parser options.
/// @return the created and parsed syntax tree.
static std::shared_ptr<SyntaxTree> fromSDFBuffer(const SourceBuffer& buffer,
SourceManager& sourceManager,
const Bag& options = {});

/// Gets any diagnostics generated while parsing.
Diagnostics& diagnostics() { return diagnosticsBuffer; }

Expand Down
6 changes: 4 additions & 2 deletions include/slang/util/LanguageVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@

namespace slang {

/// Specifies SystemVerilog language versions.
enum class LanguageVersion { v1800_2017, v1800_2023, Default = v1800_2017 };
/// Specifies SystemVerilog language versions and Standard Delay Format (SDF) standard.
enum class LanguageVersion { v1800_2017, v1800_2023, v1497_2001, Default = v1800_2017 };

inline std::string_view toString(LanguageVersion lv) {
switch (lv) {
case LanguageVersion::v1800_2017:
return "1800-2017";
case LanguageVersion::v1800_2023:
return "1800-2023";
case LanguageVersion::v1497_2001:
return "1497-2001";
default:
return "";
}
Expand Down
18 changes: 18 additions & 0 deletions scripts/diagnostics.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ error MisplacedTrailingSeparator "misplaced trailing '{}'"
error ImplicitNotAllowed "expected data type (implicit type name not allowed)"
error InvalidAccessDotColon "invalid access token; '{}' should be '{}'"
error ExpectedMember "expected member"
error MemberLimitViolation "expected only {} member(s)"
error ExpectedStatement "expected statement"
error ExpectedParameterPort "expected parameter declaration"
error ExpectedNonAnsiPort "expected non-ansi port declaration"
Expand Down Expand Up @@ -153,6 +154,23 @@ error ExpectedPortList "expected parameter list or port list"
error ExpectedRsRule "expected randsequence production rule"
error ExpectedPattern "expected pattern"
error ExpectedFunctionPortList "expected function port list"
error ExpectedSDFDivider "expected '/' or '.' divider"
error ExpectedSDFMember "expected at least one {} member specified"
error InvalidSDFTimescaleUnit "invalid SDF timescale unit; expected a combination of (1 | 10 | 100 | 1.0 | 10.0 | 100.0) and (s | ms | us | ns | ps | fs)"
error InvalidSDFValueSep "invalid SDF value separator; expected ':'"
error InvalidSDFValueExpr "invalid SDF value expression"
error InvalidSDFCellInstanceIdentifier "invalid SDF cell intstance identifer expected empty identifier or '*' or hierarchical identifier"
error ExpectedSDFIdentifier "expected SDF identifier name"
error InvalidSDFPortEdgeIdentifier "invalid SDF port edge identifier; expected one of (posedge | negedge | 01 | 10 | 0z | z1 | 1z | z0)"
error InvalidSDFDelayValuesList "expected no more than {} delay values"
error InvalidSDFPathCnsPortNum "expected at least 2 port instance specified at path constraint"
error InvalidSDFSumDiffCnsPathesNum "expected at least 2 path constraint specifier at SUM/DIFF constraint"
error InvalidSDFEdgeSpec "expected posedge or negedge edge specifier"
error InvalidSDFEdgePair "expected {}"
error InvalidSDFExprScalar "invalid SDF constant scalar expression; expected one of: (0 | b0 | B0 | 1 b0 | 1 B0 | 1 | b1 | B1 | 1 b1 | 1 B1)"
error InvalidSDFInvOp "invalid inversion operator; expected '~' or '!'"
error ExpectedRealLiteralExpression "expected usigned integer or real literal"
error DifferentSDFNameSeperator "only one type ('{}') of separator should be used"
error NoLabelOnSemicolon "labels are not allowed on empty semicolon"
error DeferredDelayMustBeZero "deferred assertion delay must be zero"
error InvalidGenvarIterExpression "invalid genvar iteration expression"
Expand Down
Loading