diff --git a/include/circt/Dialect/Moore/MooreOps.td b/include/circt/Dialect/Moore/MooreOps.td index fe4b7215a3d3..577cc2085d68 100644 --- a/include/circt/Dialect/Moore/MooreOps.td +++ b/include/circt/Dialect/Moore/MooreOps.td @@ -390,6 +390,14 @@ class DelayedAssignOpBase traits = []> : }]; } +class DeassignOpBase traits = []> : + MooreOp { + let arguments = (ins RefType:$dst); + let assemblyFormat = [{ + $dst attr-dict `:` type($dst) + }]; +} + // Continuous assignment def ContinuousAssignOp : AssignOpBase<"assign", [HasParent<"SVModuleOp">]> { @@ -459,6 +467,68 @@ def DelayedNonBlockingAssignOp : }]; } +// Procedural continuous assignment + +def ProceduralContinuousAssignOp : AssignOpBase<"procedural_assign", [ + HasParent<"ProcedureOp"> + ]> { + let summary = "Procedural continuous assignment (keyword: assign)"; + let description = [{ + A continuous assignment in procedure scope, such as `assign x = y;`, which + continuously drives the value on the right-hand side onto the LHS. + + LHS of assignment is a variable reference or a concatenation of variables. + + See IEEE 1800-2023 § 10.6.1 "The assign and deassign procedural statements". + }]; +} + +def ProceduralContinuousForceOp : AssignOpBase<"force", [ + HasParent<"ProcedureOp"> + ]> { + let summary = "Procedural continuous assignment (keyword: force)"; + let description = [{ + A continuous assignment in procedure scope, such as `force x = y;`, which + continuously drives the value on the right-hand side onto the LHS. + + LHS of assignment is a variable reference, a net, a constant bit-select or + part-select of a vector net, or a concatenation of these. + + It overrides an `assign` procedural continuous assignment. + + See IEEE 1800-2023 § 10.6.2 "The force and release procedural statements". + }]; +} + +def ProceduralContinuousDeassignOp : DeassignOpBase<"procedural_deassign", [ + HasParent<"ProcedureOp"> + ]> { + let summary = "Procedural continuous deassignment (keyword: deassign)"; + let description = [{ + Deassignment of a continuous assignment in procedure scope, such as `deassign x;`. + + The value of the variable shall remain the same until the variable is assigned a + new value (through a procedural or procedural continuous assignment). + + See IEEE 1800-2023 § 10.6.1 "The assign and deassign procedural statements". + }]; +} + +def ProceduralContinuousReleaseOp : DeassignOpBase<"release", [ + HasParent<"ProcedureOp"> + ]> { + let summary = "Procedural continuous deassignment (keyword: release)"; + let description = [{ + Deassignment of a continuous assignment in procedure scope, such as `release x;`. + + If the variable is driven by a continuous assignment or currently has an active + `assign` procedural continuous assignment, then it shall re-establish that + assignment. Otherwise, + + See IEEE 1800-2023 § 10.6.2 "The force and release procedural statements". + }]; +} + //===----------------------------------------------------------------------===// // Statements //===----------------------------------------------------------------------===// diff --git a/lib/Conversion/ImportVerilog/Statements.cpp b/lib/Conversion/ImportVerilog/Statements.cpp index 8aabceec5254..8e67c1ccab6b 100644 --- a/lib/Conversion/ImportVerilog/Statements.cpp +++ b/lib/Conversion/ImportVerilog/Statements.cpp @@ -1088,6 +1088,46 @@ struct StmtVisitor { return success(); } + // Handle procedural continuous assignment. + LogicalResult visit(const slang::ast::ProceduralAssignStatement &assignNode) { + const auto &expr = + assignNode.assignment.as(); + + auto lhs = context.convertLvalueExpression(expr.left()); + if (!lhs) + return failure(); + + auto rhs = context.convertRvalueExpression( + expr.right(), cast(lhs.getType()).getNestedType()); + if (!rhs) + return failure(); + + if (assignNode.isForce) { + moore::ProceduralContinuousForceOp::create(builder, loc, lhs, rhs); + } else { + // TODO: prohibit net-type lhs + moore::ProceduralContinuousAssignOp::create(builder, loc, lhs, rhs); + } + + return success(); + } + + // Handle procedural continuous deassignment. + LogicalResult + visit(const slang::ast::ProceduralDeassignStatement &deassignNode) { + auto lhs = context.convertLvalueExpression(deassignNode.lvalue); + if (!lhs) + return failure(); + + if (deassignNode.isRelease) { + moore::ProceduralContinuousReleaseOp::create(builder, loc, lhs); + } else { + moore::ProceduralContinuousDeassignOp::create(builder, loc, lhs); + } + + return success(); + } + /// Emit an error for all other statements. template LogicalResult visit(T &&stmt) { diff --git a/test/Conversion/ImportVerilog/basic.sv b/test/Conversion/ImportVerilog/basic.sv index 758c669fb15a..91b8e2396f5f 100644 --- a/test/Conversion/ImportVerilog/basic.sv +++ b/test/Conversion/ImportVerilog/basic.sv @@ -4099,6 +4099,53 @@ module QueueUnboundedLiteralTest; endmodule +// CHECK-LABEL: moore.module @ContinuousProceduralAssign(in %clear : !moore.l1, in %preset : !moore.l1) { +module ContinuousProceduralAssign ( + input clear, + input preset +); + + // CHECK: [[Q:%.+]] = moore.variable : + logic q; + + always @(clear or preset) + if (!clear) + // CHECK: [[ZERO:%.+]] = moore.constant 0 : l1 + // CHECK: moore.procedural_assign [[Q]], [[ZERO]] : l1 + assign q = 0; + else if (!preset) + // CHECK: [[ONE:%.+]] = moore.constant 1 : l1 + // CHECK: moore.procedural_assign [[Q]], [[ONE]] : l1 + assign q = 1; + else + // CHECK: moore.procedural_deassign [[Q]] : + deassign q; + +endmodule + +// CHECK-LABEL: moore.module @ContinuousProceduralForce(in %clear : !moore.l1, in %preset : !moore.l1) { +module ContinuousProceduralForce ( + input clear, + input preset +); + + // CHECK: [[Q:%.+]] = moore.variable : + logic q; + + always @(clear or preset) + if (!clear) + // CHECK: [[ZERO:%.+]] = moore.constant 0 : l1 + // CHECK: moore.force [[Q]], [[ZERO]] : l1 + force q = 0; + else if (!preset) + // CHECK: [[ONE:%.+]] = moore.constant 1 : l1 + // CHECK: moore.force [[Q]], [[ONE]] : l1 + force q = 1; + else + // CHECK: moore.release [[Q]] : + release q; + +endmodule // CHECK-LABEL: moore.module @ForkJoinTest() { diff --git a/test/Conversion/ImportVerilog/errors.sv b/test/Conversion/ImportVerilog/errors.sv index d91a6a881cc9..d3609605f170 100644 --- a/test/Conversion/ImportVerilog/errors.sv +++ b/test/Conversion/ImportVerilog/errors.sv @@ -53,13 +53,6 @@ module Foo; initial x = @* x; endmodule -// ----- -module Foo; - int a; - // expected-error @below {{unsupported statement}} - initial release a; -endmodule - // ----- module Foo; bit x, y;