Skip to content

Commit

Permalink
v1800-2023 clarification: only specific bidi switches allow UDNT conn…
Browse files Browse the repository at this point in the history
…ections
  • Loading branch information
MikePopoloski committed May 19, 2024
1 parent 3567fc0 commit c198d32
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 22 deletions.
3 changes: 2 additions & 1 deletion bindings/python/ASTBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ void registerAST(py::module_& m) {
.value("NoReference", ASTFlags::NoReference)
.value("ConfigParam", ASTFlags::ConfigParam)
.value("TypeOperator", ASTFlags::TypeOperator)
.value("ForkJoinAnyNone", ASTFlags::ForkJoinAnyNone);
.value("ForkJoinAnyNone", ASTFlags::ForkJoinAnyNone)
.value("DisallowUDNT", ASTFlags::DisallowUDNT);

py::class_<EvaluatedDimension>(m, "EvaluatedDimension")
.def_readonly("kind", &EvaluatedDimension::kind)
Expand Down
7 changes: 5 additions & 2 deletions include/slang/ast/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,12 @@ enum class SLANG_EXPORT ASTFlags : uint64_t {
TypeOperator = 1ull << 42,

/// AST binding is inside a fork-join_any or fork-join_none block.
ForkJoinAnyNone = 1ull << 43
ForkJoinAnyNone = 1ull << 43,

/// AST binding disallows nets with a user-defined nettype (UDNT).
DisallowUDNT = 1ull << 44
};
SLANG_BITMASK(ASTFlags, ForkJoinAnyNone)
SLANG_BITMASK(ASTFlags, DisallowUDNT)

// clang-format off
#define DK(x) \
Expand Down
3 changes: 2 additions & 1 deletion include/slang/ast/Expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ class SLANG_EXPORT Expression {

/// Binds an lvalue that is not a typical assignment-like context. For example, the
/// output argument of certain system tasks that accept almost any type.
static const Expression& bindLValue(const ExpressionSyntax& syntax, const ASTContext& context);
static const Expression& bindLValue(const ExpressionSyntax& syntax, const ASTContext& context,
bitmask<AssignFlags> assignFlags = {});

/// Binds the right hand side of an assignment-like expression from the given syntax nodes.
/// @param lhs The type of the left hand side, for type checking
Expand Down
2 changes: 1 addition & 1 deletion include/slang/ast/symbols/MemberSymbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ class SLANG_EXPORT PrimitiveSymbol : public Symbol, public Scope {
std::span<const TableEntry> table;
const ConstantValue* initVal = nullptr;
bool isSequential = false;
enum PrimitiveKind { UserDefined, Fixed, NInput, NOutput } primitiveKind;
enum PrimitiveKind { UserDefined, Fixed, NInput, NOutput, BiDiSwitch } primitiveKind;

PrimitiveSymbol(Compilation& compilation, std::string_view name, SourceLocation loc,
PrimitiveKind primitiveKind) :
Expand Down
2 changes: 2 additions & 0 deletions scripts/diagnostics.txt
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ error RealCoverpointWithExpr "'with' expressions are not allowed for bins of a r
error RealCoverpointTransBins "coverpoints of real expressions cannot specify transition bins"
error RealCoverpointWildcardBins "coverpoints of real expressions cannot be marked 'wildcard'"
error RealCoverpointImplicit "cannot declare implicit coverpoint for real value '{}'"
error BiDiSwitchNetTypes "bidirectional switch cannot connect nets of two different user-defined net types or a user-defined net type and a built-in net type ('{}' and '{}')"
error FatalTask "$fatal encountered{}"
error ErrorTask "$error encountered{}"
error StaticAssert "static assertion failed{}"
Expand Down Expand Up @@ -713,6 +714,7 @@ error InputPortAssign "cannot assign to input port '{}'"
error ClockVarTargetAssign "cannot write to '{}' with a continuous assignment since it's associated with an output clocking signal"
error LocalFormalVarMultiAssign "cannot bind local variable '{}' to more than one output or inout local variable formal argument"
error InterconnectReference "cannot reference interconnect net '{}' outside of a net port connection"
error GateUDNTConn "gate cannot connect to net '{}' with user-defined net type"
error UserDefPartialDriver "net '{}' with user-defined nettype cannot be partially driven"
error LocalVarEventExpr "local variable '{}' cannot be referenced in an event expression"
error RefArgForkJoin "cannot refer to 'ref' argument '{}' inside fork-join_any or fork-join_none block"
Expand Down
6 changes: 3 additions & 3 deletions source/ast/Expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,10 @@ const Expression& Expression::bindLValue(const ExpressionSyntax& lhs, const Type
context.resetFlags(astFlags));
}

const Expression& Expression::bindLValue(const ExpressionSyntax& syntax,
const ASTContext& context) {
const Expression& Expression::bindLValue(const ExpressionSyntax& syntax, const ASTContext& context,
bitmask<AssignFlags> assignFlags) {
auto& expr = bind(syntax, context, ASTFlags::LValue);
if (!expr.requireLValue(context))
if (!expr.requireLValue(context, {}, assignFlags))
return badExpr(context.getCompilation(), &expr);
return expr;
}
Expand Down
6 changes: 3 additions & 3 deletions source/ast/builtins/GateTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ void registerGateTypes(Compilation& c) {
gate(c, "pmos", {out, in, in});
gate(c, "rnmos", {out, in, in});
gate(c, "rpmos", {out, in, in});
gate(c, "tranif0", {inout, inout, in});
gate(c, "tranif1", {inout, inout, in});
gate(c, "tranif0", {inout, inout, in}, PrimitiveSymbol::BiDiSwitch);
gate(c, "tranif1", {inout, inout, in}, PrimitiveSymbol::BiDiSwitch);
gate(c, "rtranif0", {inout, inout, in});
gate(c, "rtranif1", {inout, inout, in});
gate(c, "tran", {inout, inout});
gate(c, "tran", {inout, inout}, PrimitiveSymbol::BiDiSwitch);
gate(c, "rtran", {inout, inout});
gate(c, "pullup", {out});
gate(c, "pulldown", {out});
Expand Down
16 changes: 11 additions & 5 deletions source/ast/expressions/MiscExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,17 @@ Expression& ValueExpressionBase::fromSymbol(const ASTContext& context, const Sym
if (flags.has(ASTFlags::SpecifyBlock))
context.addDiag(diag::SpecifyBlockParam, sourceRange);
}
else if (symbol.kind == SymbolKind::Net &&
symbol.as<NetSymbol>().netType.netKind == NetType::Interconnect &&
!flags.has(ASTFlags::AllowInterconnect)) {
context.addDiag(diag::InterconnectReference, sourceRange) << symbol.name;
return badExpr(comp, nullptr);
else if (symbol.kind == SymbolKind::Net) {
auto& netType = symbol.as<NetSymbol>().netType;
if (netType.netKind == NetType::Interconnect && !flags.has(ASTFlags::AllowInterconnect)) {
context.addDiag(diag::InterconnectReference, sourceRange) << symbol.name;
return badExpr(comp, nullptr);
}

if (netType.netKind == NetType::UserDefined && flags.has(ASTFlags::DisallowUDNT)) {
context.addDiag(diag::GateUDNTConn, sourceRange) << symbol.name;
return badExpr(comp, nullptr);
}
}
else if (symbol.kind == SymbolKind::ClockVar && !flags.has(ASTFlags::LValue) &&
symbol.as<ClockVarSymbol>().direction == ArgumentDirection::Out) {
Expand Down
54 changes: 48 additions & 6 deletions source/ast/symbols/InstanceSymbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1616,7 +1616,8 @@ std::span<const Expression* const> PrimitiveInstanceSymbol::getPortConnections()
SLANG_ASSERT(syntax && scope);

auto& comp = scope->getCompilation();
ASTContext context(*scope, LookupLocation::after(*this), ASTFlags::NonProcedural);
ASTContext context(*scope, LookupLocation::after(*this),
ASTFlags::NonProcedural | ASTFlags::DisallowUDNT);
context.setInstance(*this);

SmallVector<const ExpressionSyntax*> conns;
Expand Down Expand Up @@ -1644,6 +1645,7 @@ std::span<const Expression* const> PrimitiveInstanceSymbol::getPortConnections()
}
}

auto& logic_t = comp.getLogicType();
SmallVector<const Expression*> results;
if (primitiveType.primitiveKind == PrimitiveSymbol::NInput ||
primitiveType.primitiveKind == PrimitiveSymbol::NOutput) {
Expand All @@ -1663,8 +1665,7 @@ std::span<const Expression* const> PrimitiveInstanceSymbol::getPortConnections()
dir = conns.size() - 1 ? ArgumentDirection::In : ArgumentDirection::Out;

SLANG_ASSERT(conns[i]);
results.push_back(
&Expression::bindArgument(comp.getLogicType(), dir, {}, *conns[i], context));
results.push_back(&Expression::bindArgument(logic_t, dir, {}, *conns[i], context));
}
}
else {
Expand All @@ -1677,12 +1678,14 @@ std::span<const Expression* const> PrimitiveInstanceSymbol::getPortConnections()
return *ports;
}

const bool isBiDi = primitiveType.primitiveKind == PrimitiveSymbol::BiDiSwitch;
for (size_t i = 0; i < conns.size(); i++) {
if (!conns[i])
continue;

ArgumentDirection dir = ArgumentDirection::In;
switch (primitiveType.ports[i]->direction) {
auto& port = *primitiveType.ports[i];
switch (port.direction) {
case PrimitivePortDirection::In:
dir = ArgumentDirection::In;
break;
Expand All @@ -1694,8 +1697,47 @@ std::span<const Expression* const> PrimitiveInstanceSymbol::getPortConnections()
dir = ArgumentDirection::Out;
break;
}
results.push_back(
&Expression::bindArgument(comp.getLogicType(), dir, {}, *conns[i], context));

if (isBiDi && i < 2) {
// Bidirectional switches allow UDNT connections for their
// first two arguments.
ASTContext argCtx = context;
argCtx.flags &= ~ASTFlags::DisallowUDNT;
argCtx.flags |= ASTFlags::LAndRValue;
results.push_back(
&Expression::bindLValue(*conns[i], argCtx, AssignFlags::InOutPort));
}
else {
results.push_back(
&Expression::bindArgument(logic_t, dir, {}, *conns[i], context));
}
}

// Additional checking for bidi switches: the first two ports
// must be both UDNTs or neither.
if (isBiDi && results.size() >= 2) {
auto sym0 = results[0]->getSymbolReference();
auto sym1 = results[1]->getSymbolReference();
if (sym0 && sym1 && sym0->kind == SymbolKind::Net &&
sym1->kind == SymbolKind::Net) {

auto& nt0 = sym0->as<NetSymbol>().netType;
auto& nt1 = sym1->as<NetSymbol>().netType;

auto reportDiag = [&] {
auto& diag = context.addDiag(diag::BiDiSwitchNetTypes, location);
diag << nt0.name << nt1.name;
diag << results[0]->sourceRange << results[1]->sourceRange;
};

if (!nt0.isBuiltIn() && !nt1.isBuiltIn()) {
if (&nt0 != &nt1)
reportDiag();
}
else if (!nt0.isBuiltIn() || !nt1.isBuiltIn()) {
reportDiag();
}
}
}
}

Expand Down
48 changes: 48 additions & 0 deletions tests/unittests/ast/PrimitiveTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,3 +557,51 @@ endprimitive
CHECK(diags[1].code == diag::UdpEdgeInComb);
CHECK(diags[2].code == diag::UdpInvalidMinus);
}

TEST_CASE("Most gates can't attach to user-defined nettypes") {
auto tree = SyntaxTree::fromText(R"(
primitive p(output o, input i);
table
1 : 1;
endtable
endprimitive
module m;
nettype real ntr;
nettype shortreal nts;
ntr r1, r2;
rtranif1(r1, r2, 1);
ntr r3;
and(r3, 1);
ntr r4;
p p1(r4, 1);
// This one is allowed.
ntr r5, r6;
tranif1(r5, r6, 1);
ntr r7;
wire r8;
tran(r7, r8);
ntr r9;
nts r10;
tranif0(r9, r10, 0);
endmodule
)");

Compilation compilation;
compilation.addSyntaxTree(tree);

auto& diags = compilation.getAllDiagnostics();
REQUIRE(diags.size() == 6);
CHECK(diags[0].code == diag::GateUDNTConn);
CHECK(diags[1].code == diag::GateUDNTConn);
CHECK(diags[2].code == diag::GateUDNTConn);
CHECK(diags[3].code == diag::GateUDNTConn);
CHECK(diags[4].code == diag::BiDiSwitchNetTypes);
CHECK(diags[5].code == diag::BiDiSwitchNetTypes);
}

0 comments on commit c198d32

Please sign in to comment.