diff --git a/include/circt/Dialect/Moore/MooreOps.td b/include/circt/Dialect/Moore/MooreOps.td index 1a2a8b6a4cdd..3246ce13d441 100644 --- a/include/circt/Dialect/Moore/MooreOps.td +++ b/include/circt/Dialect/Moore/MooreOps.td @@ -297,6 +297,36 @@ def ConstantOp : MooreOp<"constant", [Pure]> { ]; } +def Parameter : I32EnumAttrCase<"Parameter", 0, "parameter">; +def LocalParameter : I32EnumAttrCase<"LocalParameter", 1, "localparam">; +def SpecParameter : I32EnumAttrCase<"SpecParameter", 2, "specparam">; + +def NamedConstAttr : I32EnumAttr<"NamedConst", "elaboration-time constants", + [Parameter, LocalParameter, SpecParameter]>{ + let cppNamespace = "circt::moore"; +} + +def NamedConstantOp : MooreOp<"named_constant", [ + SameOperandsAndResultType, + DeclareOpInterfaceMethods +]>{ + let summary = "An elaboration time constant expression"; + let description = [{ + Constants are named data objects that never change. SystemVerilog provides + three elaboration-time constants: parameter, localparam, and specparam. + + See IEEE 1800-2017 ยง 6.20 "Constants". + }]; + let arguments = (ins StrAttr:$name, + NamedConstAttr:$kind, + UnpackedType:$value); + let results = (outs UnpackedType:$result); + let assemblyFormat = [{ + `` custom($name) $kind $value attr-dict + `:` type($result) + }]; +} + def ConversionOp : MooreOp<"conversion", [Pure]> { let summary = "A type conversion"; let description = [{ diff --git a/lib/Conversion/ImportVerilog/Structure.cpp b/lib/Conversion/ImportVerilog/Structure.cpp index 5e5848676b8c..2d9aa059ca37 100644 --- a/lib/Conversion/ImportVerilog/Structure.cpp +++ b/lib/Conversion/ImportVerilog/Structure.cpp @@ -191,6 +191,55 @@ struct MemberVisitor { return context.convertStatement(procNode.getBody()); } + // Handle parameters. + LogicalResult visit(const slang::ast::ParameterSymbol ¶mNode) { + auto type = context.convertType(*paramNode.getDeclaredType()); + if (!type) + return failure(); + + const auto *init = paramNode.getInitializer(); + // skip parameters without value. + if (!init) + return success(); + Value initial = context.convertExpression(*init); + if (!initial) + return failure(); + + auto namedConstantOp = builder.create( + loc, type, builder.getStringAttr(paramNode.name), + paramNode.isLocalParam() + ? moore::NamedConstAttr::get(context.getContext(), + moore::NamedConst::LocalParameter) + : moore::NamedConstAttr::get(context.getContext(), + moore::NamedConst::Parameter), + initial); + context.valueSymbols.insert(¶mNode, namedConstantOp); + return success(); + } + + // Handle specparam. + LogicalResult visit(const slang::ast::SpecparamSymbol &spNode) { + auto type = context.convertType(*spNode.getDeclaredType()); + if (!type) + return failure(); + + const auto *init = spNode.getInitializer(); + // skip specparam without value. + if (!init) + return success(); + Value initial = context.convertExpression(*init); + if (!initial) + return failure(); + + auto namedConstantOp = builder.create( + loc, type, builder.getStringAttr(spNode.name), + moore::NamedConstAttr::get(context.getContext(), + moore::NamedConst::SpecParameter), + initial); + context.valueSymbols.insert(&spNode, namedConstantOp); + return success(); + } + // Ignore statement block symbols. These get generated by Slang for blocks // with variables and other declarations. For example, having an initial // procedure with a variable declaration, such as `initial begin int x; diff --git a/lib/Dialect/Moore/MooreOps.cpp b/lib/Dialect/Moore/MooreOps.cpp index 5dde616b3de4..fe16431d588c 100644 --- a/lib/Dialect/Moore/MooreOps.cpp +++ b/lib/Dialect/Moore/MooreOps.cpp @@ -133,6 +133,14 @@ void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type, APInt(type.getWidth(), (uint64_t)value, /*isSigned=*/true)); } +//===----------------------------------------------------------------------===// +// NamedConstantOp +//===----------------------------------------------------------------------===// + +void NamedConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) { + setNameFn(getResult(), getName()); +} + //===----------------------------------------------------------------------===// // ConcatOp //===----------------------------------------------------------------------===// diff --git a/test/Conversion/ImportVerilog/basic.sv b/test/Conversion/ImportVerilog/basic.sv index d36225977a09..c181dd691178 100644 --- a/test/Conversion/ImportVerilog/basic.sv +++ b/test/Conversion/ImportVerilog/basic.sv @@ -78,6 +78,25 @@ module Basic; bit [0:0] b1; bit b2 = b1; + // CHECK: [[TMP1:%.+]] = moore.constant 1 : i32 + // CHECK: [[TMP2:%.+]] = moore.conversion [[TMP1]] : !moore.i32 -> !moore.l32 + // CHECK: %p1 = moore.named_constant parameter [[TMP2]] : l32 + parameter p1 = 1; + // CHECK: %p2 = moore.named_constant parameter %p1 : l32 + parameter p2 = p1; + // CHECK: [[TMP1:%.+]] = moore.constant 2 : i32 + // CHECK: [[TMP2:%.+]] = moore.conversion [[TMP1]] : !moore.i32 -> !moore.l32 + // CHECK: %lp1 = moore.named_constant localparam [[TMP2]] : l32 + localparam lp1 = 2; + // CHECK: %lp2 = moore.named_constant localparam %lp1 : l32 + localparam lp2 = lp1; + // CHECK: [[TMP1:%.+]] = moore.constant 3 : i32 + // CHECK: [[TMP2:%.+]] = moore.conversion [[TMP1]] : !moore.i32 -> !moore.l32 + // CHECK: %sp1 = moore.named_constant specparam [[TMP2]] : l32 + specparam sp1 = 3; + // CHECK: %sp2 = moore.named_constant specparam %sp1 : l32 + specparam sp2 = sp1; + // CHECK: moore.procedure initial { // CHECK: } initial;