Skip to content

Commit ae54349

Browse files
authored
Merge pull request #4277 from chipsalliance/cd/update-circt-from-firtool-1.76.0-to-firtool-1.77.0
[cd] Bump CIRCT from firtool-1.76.0 to firtool-1.77.0
2 parents d5ccf48 + da02e6a commit ae54349

File tree

14 files changed

+491
-80
lines changed

14 files changed

+491
-80
lines changed

core/src/main/scala/chisel3/Layer.scala

+37-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import chisel3.experimental.{SourceInfo, UnlocatableSourceInfo}
66
import chisel3.internal.{Builder, HasId}
77
import chisel3.internal.firrtl.ir.{LayerBlockBegin, LayerBlockEnd, Node}
88
import chisel3.util.simpleClassName
9+
import java.nio.file.{Path, Paths}
910
import scala.annotation.tailrec
1011
import scala.collection.mutable.LinkedHashSet
1112

@@ -28,12 +29,23 @@ object layer {
2829
case object Bind extends Type
2930
}
3031

32+
sealed trait OutputDirBehavior
33+
final case object DefaultOutputDir extends OutputDirBehavior
34+
final case object NoOutputDir extends OutputDirBehavior
35+
final case class CustomOutputDir(path: Path) extends OutputDirBehavior
36+
3137
/** A layer declaration.
3238
*
3339
* @param convention how this layer should be lowered
40+
* @param outputDirBehavior an optional user-provided output directory for this layer
3441
* @param _parent the parent layer, if any
3542
*/
36-
abstract class Layer(val convention: Convention.Type)(implicit _parent: Layer, _sourceInfo: SourceInfo) {
43+
abstract class Layer(
44+
val convention: Convention.Type,
45+
val outputDirBehavior: OutputDirBehavior = DefaultOutputDir
46+
)(
47+
implicit _parent: Layer,
48+
_sourceInfo: SourceInfo) {
3749
self: Singleton =>
3850

3951
/** This establishes a new implicit val for any nested layers. */
@@ -51,6 +63,30 @@ object layer {
5163
case _ => s"${parent.fullName}.$name"
5264
}
5365

66+
/** The output directory of this layer.
67+
*
68+
* The output directory of a layer serves as a hint to the toolchain,
69+
* specifying where files related to the layer (such as a bindfile, in
70+
* verilog) should be output. If a layer has no output directory, then files
71+
* related to this layer will be placed in the default output directory.
72+
*
73+
* Unless overridden, the outputDir's name matches the name of the layer,
74+
* and is located under the parent layer's directory.
75+
*/
76+
private[chisel3] final def outputDir: Option[Path] = outputDirBehavior match {
77+
case NoOutputDir => None
78+
case CustomOutputDir(dir) => Some(dir)
79+
case DefaultOutputDir =>
80+
parent match {
81+
case Layer.Root => Some(Paths.get(name))
82+
case _ =>
83+
parent.outputDir match {
84+
case None => Some(Paths.get(name))
85+
case Some(dir) => Some(dir.resolve(name))
86+
}
87+
}
88+
}
89+
5490
@tailrec
5591
final private[chisel3] def canWriteTo(that: Layer): Boolean = that match {
5692
case null => false

core/src/main/scala/chisel3/internal/Builder.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1108,7 +1108,7 @@ private[chisel3] object Builder extends LazyLogging {
11081108
case layer.Convention.Bind => LayerConvention.Bind
11091109
case _ => ???
11101110
}
1111-
Layer(l.sourceInfo, l.name, convention, children.map(foldLayers).toSeq)
1111+
Layer(l.sourceInfo, l.name, convention, l.outputDir.map(_.toString), children.map(foldLayers).toSeq)
11121112
}
11131113

11141114
val optionDefs = groupByIntoSeq(options)(opt => opt.group).map {

core/src/main/scala/chisel3/internal/firrtl/Converter.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ private[chisel3] object Converter {
495495
val convention = layer.convention match {
496496
case LayerConvention.Bind => fir.LayerConvention.Bind
497497
}
498-
fir.Layer(convert(layer.sourceInfo), layer.name, convention, layer.children.map(convertLayer))
498+
fir.Layer(convert(layer.sourceInfo), layer.name, convention, layer.outputDir, layer.children.map(convertLayer))
499499
}
500500

501501
def convertOption(option: DefOption): fir.DefOption = {

core/src/main/scala/chisel3/internal/firrtl/IR.scala

+1
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ private[chisel3] object ir {
385385
sourceInfo: SourceInfo,
386386
name: String,
387387
convention: LayerConvention.Type,
388+
outputDir: Option[String],
388389
children: Seq[Layer])
389390

390391
case class LayerBlockBegin(sourceInfo: SourceInfo, layer: chisel3.layer.Layer) extends Command

etc/circt.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "firtool-1.76.0"
2+
"version": "firtool-1.77.0"
33
}

firrtl/src/main/scala/firrtl/ir/IR.scala

+6-1
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,12 @@ object LayerConvention {
435435
}
436436
}
437437

438-
case class Layer(info: Info, name: String, convention: LayerConvention.Type, body: Seq[Layer])
438+
case class Layer(
439+
info: Info,
440+
name: String,
441+
convention: LayerConvention.Type,
442+
outputDir: Option[String],
443+
body: Seq[Layer])
439444
extends FirrtlNode
440445
with IsDeclaration
441446
with UseSerializer

firrtl/src/main/scala/firrtl/ir/Serializer.scala

+7-1
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,13 @@ object Serializer {
566566
val layers = if (circuit.layers.nonEmpty) {
567567
implicit val b = new StringBuilder
568568
def layerIt(layer: Layer)(implicit indent: Int): Unit = {
569-
b ++= s"${NewLine}"; doIndent(); b ++= s"layer ${layer.name}, ${layer.convention} :"
569+
b ++= s"${NewLine}"
570+
doIndent()
571+
b ++= s"layer ${layer.name}, ${layer.convention}"
572+
for (d <- layer.outputDir) {
573+
b ++= ", \"" ++ d ++ "\""
574+
}
575+
b ++= " :"
570576
s(layer.info)
571577
layer.body.foreach(layerIt(_)(indent + 1))
572578
}

src/main/scala/chisel3/ltl/LTL.scala

+3-16
Original file line numberDiff line numberDiff line change
@@ -302,10 +302,6 @@ sealed trait Property {
302302

303303
/** See `Property.clock`. */
304304
def clock(clock: Clock)(implicit sourceInfo: SourceInfo): Property = Property.clock(this, clock)
305-
306-
/** See `Property.disable`. */
307-
@deprecated("Use withDisable", "Chisel 6.5")
308-
def disable(cond: Disable)(implicit sourceInfo: SourceInfo): Property = Property.disable(this, cond)
309305
}
310306

311307
/** Prefix-style utilities to work with properties.
@@ -390,14 +386,6 @@ object Property {
390386
*/
391387
def clock(prop: Property, clock: Clock)(implicit sourceInfo: SourceInfo): Property =
392388
OpaqueProperty(LTLClockIntrinsic(prop.inner, clock))
393-
394-
/** Disable the checking of a property if a condition is true. If the
395-
* condition is true at any time during the evaluation of the property, the
396-
* evaluation is aborted. Equivalent to `disable iff (cond) prop` in SVA.
397-
*/
398-
@deprecated("Use withDisable", "Chisel 6.5")
399-
def disable(prop: Property, cond: Disable)(implicit sourceInfo: SourceInfo): Property =
400-
OpaqueProperty(LTLDisableIntrinsic(prop.inner, cond.value))
401389
}
402390

403391
/** The base class for the `AssertProperty`, `AssumeProperty`, and
@@ -426,9 +414,8 @@ sealed abstract class AssertPropertyLike {
426414
)(
427415
implicit sourceInfo: SourceInfo
428416
): Unit = {
429-
val disabled = disable.fold(prop)(prop.disable(_))
430-
val clocked = clock.fold(disabled)(disabled.clock(_))
431-
createIntrinsic(label)(sourceInfo)(clocked.inner)
417+
val clocked = clock.fold(prop)(prop.clock(_))
418+
createIntrinsic(label)(sourceInfo)(clocked.inner, disable.map(!_.value))
432419
}
433420

434421
/** Assert, assume, or cover that a boolean predicate holds.
@@ -486,7 +473,7 @@ sealed abstract class AssertPropertyLike {
486473
apply(Sequence.BoolSequence(cond), Some(clock), Some(disable), Some(label))
487474
}
488475

489-
protected def createIntrinsic(label: Option[String])(implicit sourceInfo: SourceInfo): (Bool) => Unit
476+
protected def createIntrinsic(label: Option[String])(implicit sourceInfo: SourceInfo): (Bool, Option[Bool]) => Unit
490477
}
491478

492479
/** Assert that a property holds.
+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package chisel3.util.circt.dpi
4+
5+
import chisel3._
6+
7+
import chisel3.experimental.{IntParam, IntrinsicModule, Param, StringParam}
8+
9+
private object GetDPIParams {
10+
def apply(
11+
functionName: String,
12+
isClocked: Boolean,
13+
inputNames: Option[Seq[String]],
14+
outputName: Option[String] = None
15+
): Seq[(String, Param)] = {
16+
val inputNamesParam =
17+
inputNames.map(_.mkString(";")).map(x => Seq("inputNames" -> StringParam(x))).getOrElse(Seq())
18+
val outputNameParam = outputName.map(x => Seq("outputName" -> StringParam(x))).getOrElse(Seq())
19+
Seq[(String, Param)](
20+
"functionName" -> functionName,
21+
"isClocked" -> (if (isClocked) 1 else 0)
22+
) ++ inputNamesParam ++ outputNameParam
23+
}
24+
}
25+
26+
object RawClockedNonVoidFunctionCall {
27+
28+
/** Creates an intrinsic that calls non-void DPI function at its clock posedge.
29+
* The result values behave like registers and the DPI function is used as a state
30+
* transfer function of them.
31+
*
32+
* `enable` operand is used to conditionally call the DPI since DPI call could be quite
33+
* more expensive than native constructs.
34+
*
35+
* When an `enable` is false, it means the state transfer function is not called. Hence
36+
* their values will not be modified in that clock.
37+
*
38+
* Please refer https://github.com/llvm/circt/blob/main/docs/Dialects/FIRRTL/FIRRTLIntrinsics.md#dpi-intrinsic-abi for DPI function ABI.
39+
* @example {{{
40+
* val a = RawClockedNonVoidFunctionCall("dpi_func_foo", UInt(1.W), clock, enable, b, c)
41+
* }}}
42+
*/
43+
def apply[T <: Data](
44+
functionName: String,
45+
ret: => T,
46+
inputNames: Option[Seq[String]] = None,
47+
outputName: Option[String] = None
48+
)(clock: Clock,
49+
enable: Bool,
50+
data: Data*
51+
): T = {
52+
IntrinsicExpr(
53+
"circt_dpi_call",
54+
ret,
55+
GetDPIParams(functionName, true, inputNames, outputName): _*
56+
)(
57+
(Seq(clock, enable) ++ data): _*
58+
)
59+
}
60+
}
61+
62+
object RawUnclockedNonVoidFunctionCall {
63+
64+
/** Creates an intrinsic that calls non-void DPI function for its input value changes.
65+
* The DPI call is considered as a combinational logic.
66+
*
67+
* `enable` operand is used to conditionally call the DPI since DPI call could be quite
68+
* more expensive than native constructs.
69+
* When `enable` is false, results of unclocked calls are undefined and evaluated into X.
70+
*
71+
* Please refer https://github.com/llvm/circt/blob/main/docs/Dialects/FIRRTL/FIRRTLIntrinsics.md#dpi-intrinsic-abi for DPI function ABI.
72+
* @example {{{
73+
* val a = RawUnclockedNonVoidFunctionCall("dpi_func_foo", UInt(1.W), enable, b, c)
74+
* }}}
75+
*/
76+
def apply[T <: Data](
77+
functionName: String,
78+
ret: => T,
79+
inputNames: Option[Seq[String]] = None,
80+
outputName: Option[String] = None
81+
)(enable: Bool,
82+
data: Data*
83+
): T = {
84+
IntrinsicExpr(
85+
"circt_dpi_call",
86+
ret,
87+
GetDPIParams(functionName, false, inputNames, outputName): _*
88+
)(
89+
(Seq(enable) ++ data): _*
90+
)
91+
}
92+
}
93+
94+
object RawClockedVoidFunctionCall {
95+
96+
/** Creates an intrinsic that calls void DPI function at its clock posedge.
97+
*
98+
* Please refer https://github.com/llvm/circt/blob/main/docs/Dialects/FIRRTL/FIRRTLIntrinsics.md#dpi-intrinsic-abi for DPI function ABI.
99+
* @example {{{
100+
* RawClockedVoidFunctionCall("dpi_func_foo", UInt(1.W), clock, enable, b, c)
101+
* }}}
102+
*/
103+
def apply(
104+
functionName: String,
105+
inputNames: Option[Seq[String]] = None
106+
)(clock: Clock,
107+
enable: Bool,
108+
data: Data*
109+
): Unit = {
110+
Intrinsic("circt_dpi_call", GetDPIParams(functionName, true, inputNames): _*)(
111+
(Seq(clock, enable) ++ data): _*
112+
)
113+
}
114+
}
115+
116+
// A common trait for DPI functions.
117+
trait DPIFunctionImport {
118+
def functionName: String
119+
def inputNames: Option[Seq[String]] = None
120+
}
121+
122+
// Base trait for a non-void function that returns `T`.
123+
trait DPINonVoidFunctionImport[T <: Data] extends DPIFunctionImport {
124+
def ret: T
125+
def clocked: Boolean
126+
def outputName: Option[String] = None
127+
final def callWithEnable(enable: Bool, data: Data*): T =
128+
if (clocked) {
129+
RawClockedNonVoidFunctionCall(functionName, ret, inputNames, outputName)(Module.clock, enable, data: _*)
130+
} else {
131+
RawUnclockedNonVoidFunctionCall(functionName, ret, inputNames, outputName)(enable, data: _*)
132+
}
133+
final def call(data: Data*): T = callWithEnable(true.B, data: _*)
134+
}
135+
136+
// Base trait for a clocked void function.
137+
trait DPIClockedVoidFunctionImport extends DPIFunctionImport {
138+
final def callWithEnable(enable: Bool, data: Data*): Unit =
139+
RawClockedVoidFunctionCall(functionName, inputNames)(Module.clock, enable, data: _*)
140+
final def call(data: Data*): Unit = callWithEnable(true.B, data: _*)
141+
}

src/main/scala/chisel3/util/circt/LTLIntrinsics.scala

+15-11
Original file line numberDiff line numberDiff line change
@@ -145,29 +145,33 @@ private[chisel3] object LTLDisableIntrinsic {
145145

146146
/** Base class for assert, assume, and cover intrinsics. */
147147
private[chisel3] object VerifAssertLikeIntrinsic {
148-
def apply(intrinsicName: String, label: Option[String])(prop: Bool)(implicit sourceInfo: SourceInfo): Unit = {
148+
def apply(
149+
intrinsicName: String,
150+
label: Option[String]
151+
)(prop: Bool,
152+
enable: Option[Bool]
153+
)(
154+
implicit sourceInfo: SourceInfo
155+
): Unit = {
149156
val name = f"circt_verif_$intrinsicName"
150-
if (label.isEmpty)
151-
Intrinsic(name)(prop)
152-
else
153-
Intrinsic(name, "label" -> label.get)(prop)
157+
Intrinsic(name, (label.map("label" -> StringParam(_)).toSeq): _*)((Seq(prop) ++ enable.toSeq): _*)
154158
}
155159
}
156160

157161
/** A wrapper intrinsic for the CIRCT `verif.assert` operation. */
158162
private[chisel3] object VerifAssertIntrinsic {
159-
def apply(label: Option[String] = None)(prop: Bool)(implicit sourceInfo: SourceInfo) =
160-
VerifAssertLikeIntrinsic("assert", label)(prop)
163+
def apply(label: Option[String] = None)(prop: Bool, enable: Option[Bool])(implicit sourceInfo: SourceInfo) =
164+
VerifAssertLikeIntrinsic("assert", label)(prop, enable)
161165
}
162166

163167
/** A wrapper intrinsic for the CIRCT `verif.assume` operation. */
164168
private[chisel3] object VerifAssumeIntrinsic {
165-
def apply(label: Option[String] = None)(prop: Bool)(implicit sourceInfo: SourceInfo) =
166-
VerifAssertLikeIntrinsic("assume", label)(prop)
169+
def apply(label: Option[String] = None)(prop: Bool, enable: Option[Bool])(implicit sourceInfo: SourceInfo) =
170+
VerifAssertLikeIntrinsic("assume", label)(prop, enable)
167171
}
168172

169173
/** A wrapper intrinsic for the CIRCT `verif.cover` operation. */
170174
private[chisel3] object VerifCoverIntrinsic {
171-
def apply(label: Option[String] = None)(prop: Bool)(implicit sourceInfo: SourceInfo) =
172-
VerifAssertLikeIntrinsic("cover", label)(prop)
175+
def apply(label: Option[String] = None)(prop: Bool, enable: Option[Bool])(implicit sourceInfo: SourceInfo) =
176+
VerifAssertLikeIntrinsic("cover", label)(prop, enable)
173177
}

0 commit comments

Comments
 (0)