diff --git a/include/circt/Dialect/SV/SVInOutOps.td b/include/circt/Dialect/SV/SVInOutOps.td index f3187a86bc2c..490eac896fc7 100644 --- a/include/circt/Dialect/SV/SVInOutOps.td +++ b/include/circt/Dialect/SV/SVInOutOps.td @@ -60,20 +60,25 @@ def RegOp : SVOp<"reg", [ Declare a SystemVerilog Variable Declaration of 'reg' type. See SV Spec 6.8, pp100. }]; - let arguments = (ins StrAttr:$name, OptionalAttr:$inner_sym); + let arguments = (ins + StrAttr:$name, + Optional:$init, + OptionalAttr:$inner_sym); let results = (outs InOutType:$result); let skipDefaultBuilders = 1; let builders = [ OpBuilder<(ins "::mlir::Type":$elementType, CArg<"StringAttr", "StringAttr()">:$name, - CArg<"hw::InnerSymAttr", "hw::InnerSymAttr()">:$innerSym)> + CArg<"hw::InnerSymAttr", "hw::InnerSymAttr()">:$innerSym, + CArg<"mlir::Value", "{}">:$init)> ]; // We handle the name in a custom way, so we use a customer parser/printer. let assemblyFormat = [{ - (`sym` $inner_sym^)? `` custom($name) attr-dict + (`init` $init^)? (`sym` $inner_sym^)? `` custom($name) attr-dict `:` qualified(type($result)) + custom(ref(type($result)),ref($init), type($init)) }]; let hasCanonicalizeMethod = true; diff --git a/lib/Conversion/ExportVerilog/ExportVerilog.cpp b/lib/Conversion/ExportVerilog/ExportVerilog.cpp index a8c86e068f6a..69dbfb2c4fc2 100644 --- a/lib/Conversion/ExportVerilog/ExportVerilog.cpp +++ b/lib/Conversion/ExportVerilog/ExportVerilog.cpp @@ -5019,6 +5019,14 @@ LogicalResult StmtEmitter::emitDeclaration(Operation *op) { }); } + if (auto regOp = dyn_cast(op)) { + if (auto initValue = regOp.getInit()) { + ps << PP::space << "=" << PP::space; + ps.scopedBox(PP::ibox0, + [&]() { emitExpression(initValue, opsForLocation); }); + } + } + // Try inlining an assignment into declarations. if (isa(op) && !op->getParentOp()->hasTrait()) { diff --git a/lib/Dialect/SV/SVOps.cpp b/lib/Dialect/SV/SVOps.cpp index 1607be110ce2..df46d6483f0c 100644 --- a/lib/Dialect/SV/SVOps.cpp +++ b/lib/Dialect/SV/SVOps.cpp @@ -244,9 +244,28 @@ LogicalResult LocalParamOp::verify() { // RegOp //===----------------------------------------------------------------------===// +static ParseResult +parseImplicitInitType(OpAsmParser &p, mlir::Type regType, + std::optional &initValue, + mlir::Type &initType) { + if (!initValue.has_value()) + return success(); + + hw::InOutType ioType = regType.dyn_cast(); + if (!ioType) + return p.emitError(p.getCurrentLocation(), "expected inout type for reg"); + + initType = ioType.getElementType(); + return success(); +} + +static void printImplicitInitType(OpAsmPrinter &p, Operation *op, + mlir::Type regType, mlir::Value initValue, + mlir::Type initType) {} + void RegOp::build(OpBuilder &builder, OperationState &odsState, - Type elementType, StringAttr name, - hw::InnerSymAttr innerSym) { + Type elementType, StringAttr name, hw::InnerSymAttr innerSym, + mlir::Value initValue) { if (!name) name = builder.getStringAttr(""); odsState.addAttribute("name", name); @@ -254,6 +273,8 @@ void RegOp::build(OpBuilder &builder, OperationState &odsState, odsState.addAttribute(hw::InnerSymbolTable::getInnerSymbolAttrName(), innerSym); odsState.addTypes(hw::InOutType::get(elementType)); + if (initValue) + odsState.addOperands(initValue); } /// Suggest a name for each result value based on the saved result names diff --git a/test/Conversion/ExportVerilog/sv-dialect.mlir b/test/Conversion/ExportVerilog/sv-dialect.mlir index aaef29055578..cca7d7b42cfc 100644 --- a/test/Conversion/ExportVerilog/sv-dialect.mlir +++ b/test/Conversion/ExportVerilog/sv-dialect.mlir @@ -536,6 +536,17 @@ hw.module @reg_1(%in4: i4, %in8: i8) -> (a : i3, b : i5) { hw.output %c, %d : i3,i5 } +// CHECK-LABEL: module regWithInit( +// CHECK: reg reg1 = 1'h0; +// CHECK: reg [31:0] reg2 = 32'(arg + arg); +hw.module @regWithInit(%arg : i32) { + %c0_i1 = hw.constant 0 : i1 + %reg1 = sv.reg init %c0_i1 : !hw.inout + + %init = comb.add %arg, %arg : i32 + %reg2 = sv.reg init %init : !hw.inout +} + // CHECK-LABEL: module struct_field_inout1( // CHECK-NEXT: inout struct packed {logic b; } a // CHECK-NEXT: );