Skip to content

Commit

Permalink
Specify desiredName as defname for extmodule (#3958)
Browse files Browse the repository at this point in the history
* Specify right convention for modules

* Specify `desiredName` as `defname` for `extmodule`

Removed FixedPoint in muxes-and-input-selection.md (#3956)

Make SRAMs directly emit FIRRTL memories (#3955)

Add a new BoringUtils.drive API for boring to drive a sink. (#3960)

This API allows users to bore to a sink they plan to drive, which complements the existing API to bore from a source to read.

Support literals in DataView (#3964)

Add requireIsAnnotatable for better errors when annotating literals (#3968)
  • Loading branch information
SpriteOvO committed Apr 6, 2024
1 parent 9177535 commit dc970d9
Show file tree
Hide file tree
Showing 24 changed files with 610 additions and 117 deletions.
24 changes: 16 additions & 8 deletions core/src/main/scala/chisel3/Aggregate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
package chisel3

import chisel3.experimental.VecLiterals.AddVecLiteralConstructor
import chisel3.experimental.dataview.{isView, reifySingleData, InvalidViewException}
import chisel3.experimental.dataview.{isView, reify, reifySingleData, InvalidViewException}

import scala.collection.immutable.{SeqMap, VectorMap}
import scala.collection.mutable.{HashSet, LinkedHashMap}
Expand All @@ -29,7 +29,7 @@ sealed abstract class Aggregate extends Data {

private def checkingLitOption(checkForDontCares: Boolean): Option[BigInt] = {
// Shift the accumulated value by our width and add in our component, masked by our width.
def shiftAdd(accumulator: Option[BigInt], elt: Data): Option[BigInt] = {
def shiftAdd(elt: Data, accumulator: Option[BigInt]): Option[BigInt] = {
(accumulator, elt.litOption) match {
case (Some(accumulator), Some(eltLit)) =>
val width = elt.width.get
Expand All @@ -44,24 +44,32 @@ sealed abstract class Aggregate extends Data {
}

topBindingOpt match {
case Some(BundleLitBinding(_)) | Some(VecLitBinding(_)) =>
getElements.reverse
.foldLeft[Option[BigInt]](Some(BigInt(0)))(shiftAdd)
case Some(_: BundleLitBinding | _: VecLitBinding | _: AggregateViewBinding) =>
// Records store elements in reverse order and higher indices are more significant in Vecs
this.getElements.foldRight(Option(BigInt(0)))(shiftAdd)
case _ => None
}
}

/** Return an Aggregate's literal value if it is a literal, None otherwise.
* If any element of the aggregate is not a literal with a defined width, the result isn't a literal.
* If any element of the aggregate is not a literal (or DontCare), the result isn't a literal.
*
* @return an Aggregate's literal value if it is a literal.
* @note [[DontCare]] is allowed and will be replaced with 0. Use [[litValue]] to disallow DontCare.
* @return an Aggregate's literal value if it is a literal, None otherwise.
*/
override def litOption: Option[BigInt] = {
checkingLitOption(checkForDontCares = false)
}

/** Return an Aggregate's literal value if it is a literal, otherwise an exception is thrown.
* If any element of the aggregate is not a literal with a defined width, the result isn't a literal.
*
* @return an Aggregate's literal value if it is a literal, exception otherwise.
*/
override def litValue: BigInt = {
checkingLitOption(checkForDontCares = true).get
checkingLitOption(checkForDontCares = true).getOrElse(
throw new ChiselException(s"Cannot ask for litValue of $this as it is not a literal.")
)
}

/** Returns a Seq of the immediate contents of this Aggregate, in order.
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/chisel3/Data.scala
Original file line number Diff line number Diff line change
Expand Up @@ -373,14 +373,14 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
private[chisel3] final def isSynthesizable: Boolean = _binding.map {
case ChildBinding(parent) => parent.isSynthesizable
case _: TopBinding => true
case (_: SampleElementBinding[_] | _: MemTypeBinding[_]) => false
case (_: SampleElementBinding[_] | _: MemTypeBinding[_] | _: FirrtlMemTypeBinding) => false
}.getOrElse(false)

private[chisel3] def topBindingOpt: Option[TopBinding] = _binding.flatMap {
case ChildBinding(parent) => parent.topBindingOpt
case bindingVal: TopBinding => Some(bindingVal)
case SampleElementBinding(parent) => parent.topBindingOpt
case _: MemTypeBinding[_] => None
case (_: MemTypeBinding[_] | _: FirrtlMemTypeBinding) => None
}

private[chisel3] def topBinding: TopBinding = topBindingOpt.get
Expand Down
5 changes: 4 additions & 1 deletion core/src/main/scala/chisel3/Element.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package chisel3
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl.ir._
import chisel3.experimental.SourceInfo
import chisel3.experimental.dataview.reify
import chisel3.internal._

/** Element is a leaf data type: it cannot contain other [[Data]] objects. Example uses are for representing primitive
Expand Down Expand Up @@ -51,7 +52,9 @@ abstract class Element extends Data {

private[chisel3] def litArgOption: Option[LitArg] = topBindingOpt match {
case Some(ElementLitBinding(litArg)) => Some(litArg)
case _ => None
case Some(_: ViewBinding) =>
reify(this).litArgOption
case _ => None
}

override def litOption: Option[BigInt] = litArgOption.map(_.num)
Expand Down
11 changes: 7 additions & 4 deletions core/src/main/scala/chisel3/RawModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,9 @@ abstract class RawModule extends BaseModule {
// probes have their refs set eagerly
case _ => // don't name literals
}
} // else, don't name unbound types
}
case m: SramTarget =>
id.forceName(default = "MEM", _namespace)
}

private[chisel3] override def generateComponent(): Option[Component] = {
Expand Down Expand Up @@ -211,10 +213,11 @@ abstract class RawModule extends BaseModule {
case (true, false) if left.probeInfo.get.writable => ProbeDefine(si, left.lref, RWProbeExpr(Node(right)))
case (true, false) => ProbeDefine(si, left.lref, ProbeExpr(Node(right)))
case (false, true) => Connect(si, left.lref, ProbeRead(Node(right)))
case (false, false) =>
case (false, false) =>
// For non-probe, directly create Nodes for lhs, skipping visibility check to support BoringUtils.drive.
(left, right) match {
case (_: Property[_], _: Property[_]) => PropAssign(si, left.lref, Node(right))
case (_, _) => Connect(si, left.lref, Node(right))
case (_: Property[_], _: Property[_]) => PropAssign(si, Node(left), Node(right))
case (_, _) => Connect(si, Node(left), Node(right))
}
}
val secretCommands = if (_closed) {
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/scala/chisel3/SramTarget.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package chisel3

import chisel3.internal.NamedComponent

/** Provides an underlying target-able class for SRAM.
*/
private[chisel3] final class SramTarget extends NamedComponent {
_parent.foreach(_.addId(this))
}
4 changes: 2 additions & 2 deletions core/src/main/scala/chisel3/dontTouch.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

package chisel3

import chisel3.experimental.{annotate, requireIsHardware, ChiselAnnotation}
import chisel3.experimental.{annotate, requireIsAnnotatable, ChiselAnnotation}
import chisel3.properties.Property
import chisel3.reflect.DataMirror
import firrtl.transforms.DontTouchAnnotation
Expand Down Expand Up @@ -34,7 +34,7 @@ object dontTouch {
* @return Unmodified signal `data`
*/
def apply[T <: Data](data: T): T = {
requireIsHardware(data, "Data marked dontTouch")
requireIsAnnotatable(data, "Data marked dontTouch")
data match {
case d if DataMirror.hasProbeTypeModifier(d) => ()
case _: Property[_] => ()
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/scala/chisel3/experimental/Analog.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ final class Analog private (private[chisel3] val width: Width) extends Element {
case ChildBinding(parent) => parent.topBinding
// See https://github.com/freechipsproject/chisel3/pull/946
case SampleElementBinding(parent) => parent.topBinding
case a: MemTypeBinding[_] => a
case a: MemTypeBinding[_] => a
case a: FirrtlMemTypeBinding => a
}

targetTopBinding match {
Expand Down
14 changes: 14 additions & 0 deletions core/src/main/scala/chisel3/experimental/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ package object experimental {
}
}

/** Require that a Data can be annotated. It must be non-literal hardware.
*/
object requireIsAnnotatable {
def apply(node: Data, msg: String = ""): Unit = {
requireIsHardware(node, msg)
if (node.isLit) {
val prefix = if (msg.nonEmpty) s"$msg " else ""
throw ExpectedAnnotatableException(
s"$prefix'$node' must not be a literal."
)
}
}
}

/** Requires that a node is a chisel type (not hardware, "unbound")
*/
object requireIsChiselType {
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/scala/chisel3/internal/Binding.scala
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ private[chisel3] case class OpBinding(enclosure: RawModule, visibility: Option[W
private[chisel3] case class MemoryPortBinding(enclosure: RawModule, visibility: Option[WhenContext])
extends ConstrainedBinding
with ConditionalDeclarable
private[chisel3] case class SramPortBinding(enclosure: RawModule, visibility: Option[WhenContext])
extends ConstrainedBinding
with ConditionalDeclarable
private[chisel3] case class RegBinding(enclosure: RawModule, visibility: Option[WhenContext])
extends ConstrainedBinding
with ConditionalDeclarable
Expand All @@ -119,6 +122,12 @@ private[chisel3] case class SampleElementBinding[T <: Data](parent: Vec[T]) exte
private[chisel3] case class MemTypeBinding[T <: Data](parent: MemBase[T]) extends Binding {
def location: Option[BaseModule] = parent._parent
}

/** Special binding for Firrtl memory (SRAM) types */
private[chisel3] case class FirrtlMemTypeBinding(parent: SramTarget) extends Binding {
def location: Option[BaseModule] = parent._parent
}

// A DontCare element has a specific Binding, somewhat like a literal.
// It is a source (RHS). It may only be connected/applied to sinks.
private[chisel3] case class DontCareBinding() extends UnconstrainedBinding
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/chisel3/internal/Builder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,7 @@ private[chisel3] object Builder extends LazyLogging {
val localTarget = view.toTarget
val absTarget = view.toAbsoluteTarget
val elts = getRecursiveFields.lazily(view, "").collect { case (elt: Element, _) => elt }
for (elt <- elts) {
for (elt <- elts if !elt.isLit) {
// This is a hack to not crash when .viewAs is called on non-hardware
// It can be removed in Chisel 6.0.0 when it becomes illegal to call .viewAs on non-hardware
val targetOfViewOpt =
Expand Down
14 changes: 14 additions & 0 deletions core/src/main/scala/chisel3/internal/firrtl/Converter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,20 @@ private[chisel3] object Converter {
Some(firrtl.CDefMemory(convert(info), e.name, extractType(t, info, typeAliases), size, false))
case e @ DefSeqMemory(info, id, t, size, ruw) =>
Some(firrtl.CDefMemory(convert(info), e.name, extractType(t, info, typeAliases), size, true, ruw))
case e @ FirrtlMemory(info, id, t, size, readPortNames, writePortNames, readwritePortNames) =>
Some(
fir.DefMemory(
convert(info),
e.name,
extractType(t, info, typeAliases),
size,
1,
1,
readPortNames,
writePortNames,
readwritePortNames
)
)
case e: DefMemPort[_] =>
val info = e.sourceInfo
Some(
Expand Down
14 changes: 12 additions & 2 deletions core/src/main/scala/chisel3/internal/firrtl/IR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ private[chisel3] object ir {
// NOTE: mod eq ctx.id only occurs in Target and Named-related APIs
if (mod eq ctx.id) localName else name
}
case class Slot(imm: Node, name: String) extends Arg {
case class Slot(imm: Arg, name: String) extends Arg {
override def contextualName(ctx: Component): String = {
val immName = imm.contextualName(ctx)
if (immName.isEmpty) name else s"$immName.$name"
Expand Down Expand Up @@ -288,6 +288,16 @@ private[chisel3] object ir {
readUnderWrite: fir.ReadUnderWrite.Value)
extends Definition

case class FirrtlMemory(
sourceInfo: SourceInfo,
id: HasId,
t: Data,
size: BigInt,
readPortNames: Seq[String],
writePortNames: Seq[String],
readwritePortNames: Seq[String])
extends Definition

case class DefMemPort[T <: Data](
sourceInfo: SourceInfo,
id: T,
Expand All @@ -310,7 +320,7 @@ private[chisel3] object ir {
case class WhenEnd(sourceInfo: SourceInfo, firrtlDepth: Int, hasAlt: Boolean = false) extends Command
case class AltBegin(sourceInfo: SourceInfo) extends Command
case class OtherwiseEnd(sourceInfo: SourceInfo, firrtlDepth: Int) extends Command
case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command
case class Connect(sourceInfo: SourceInfo, loc: Arg, exp: Arg) extends Command
case class PropAssign(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command
case class Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command
case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/scala/chisel3/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,10 @@ package object chisel3 {
*/
case class ExpectedHardwareException(message: String) extends BindingException(message)

/** A function expected annotatable hardware
*/
case class ExpectedAnnotatableException(message: String) extends BindingException(message)

/** An aggregate had a mix of specified and unspecified directionality children
*/
case class MixedDirectionAggregateException(message: String) extends BindingException(message)
Expand Down
2 changes: 1 addition & 1 deletion docs/src/explanations/muxes-and-input-selection.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ Another ```Mux``` utility is the one-hot mux, ```Mux1H```. It takes a sequence o
io.selector(4) -> 11.U,
))
```
```Mux1H``` whenever possible generates *Firrtl* that is readily optimizable as low depth and/or tree. This optimization is not possible when the values are of type ```FixedPoint``` or an aggregate type that contains ```FixedPoint```s and results instead as a simple ```Mux``` tree. This behavior could be sub-optimal. As ```FixedPoint``` is still *experimental* this behavior may change in the future.
`Mux1H` whenever possible generates *Firrtl* that is readily optimizable as low depth and/or tree.
9 changes: 5 additions & 4 deletions panamaconverter/src/PanamaCIRCTConverter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -922,15 +922,16 @@ class PanamaCIRCTConverter(val circt: PanamaCIRCT, fos: Option[FirtoolOptions],
def visitDefBlackBox(defBlackBox: DefBlackBox): Unit = {
val ports = util.convert(defBlackBox.ports ++ defBlackBox.id.secretPorts, defBlackBox.topDir)
val nameAttr = circt.mlirStringAttrGet(defBlackBox.name)
val desiredNameAttr = circt.mlirStringAttrGet(defBlackBox.id.desiredName)

val builder = util
.OpBuilder("firrtl.extmodule", firCtx.circuitBlock, circt.unkLoc)
.withRegionNoBlock()
.withNamedAttr("sym_name", nameAttr)
.withNamedAttr("sym_visibility", circt.mlirStringAttrGet("private"))
.withNamedAttr("defname", nameAttr)
.withNamedAttr("defname", desiredNameAttr)
.withNamedAttr("parameters", circt.mlirArrayAttrGet(defBlackBox.params.map(p => util.convert(p._1, p._2)).toSeq))
.withNamedAttr("convention", circt.firrtlAttrGetConvention(FIRRTLConvention.Internal)) // TODO: handle it corretly
.withNamedAttr("convention", circt.firrtlAttrGetConvention(FIRRTLConvention.Scalarized)) // TODO: Make an option `scalarizeExtModules` for it
.withNamedAttr("annotations", circt.emptyArrayAttr)
val firModule = util.moduleBuilderInsertPorts(builder, ports).build()

Expand Down Expand Up @@ -966,7 +967,7 @@ class PanamaCIRCTConverter(val circt: PanamaCIRCT, fos: Option[FirtoolOptions],
.withRegion(Seq((ports.types, ports.locs)))
.withNamedAttr("sym_name", circt.mlirStringAttrGet(defModule.name))
.withNamedAttr("sym_visibility", circt.mlirStringAttrGet(if (isMainModule) "public" else "private"))
.withNamedAttr("convention", circt.firrtlAttrGetConvention(FIRRTLConvention.Internal)) // TODO: handle it corretly
.withNamedAttr("convention", circt.firrtlAttrGetConvention(if (isMainModule) FIRRTLConvention.Scalarized else FIRRTLConvention.Internal)) // TODO: Make an option `scalarizePublicModules` for it
.withNamedAttr("annotations", circt.emptyArrayAttr)
val firModule = util.moduleBuilderInsertPorts(builder, ports).build()

Expand All @@ -985,7 +986,7 @@ class PanamaCIRCTConverter(val circt: PanamaCIRCT, fos: Option[FirtoolOptions],
}

def visitConnect(connect: Connect): Unit = {
val dest = util.referTo(connect.loc.id, connect.sourceInfo)
val dest = util.referTo(connect.loc, connect.sourceInfo)
var src = util.referTo(connect.exp, connect.sourceInfo)
util.emitConnect(dest, src, util.convert(connect.sourceInfo))
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/chisel3/aop/Select.scala
Original file line number Diff line number Diff line change
Expand Up @@ -474,9 +474,9 @@ object Select {
// Given a loc, return all subcomponents of id that could be assigned to in connect
private def getEffected(a: Arg): Seq[Data] = a match {
case Node(id: Data) => DataMirror.collectAllMembers(id)
case Slot(imm, name) => Seq(imm.id.asInstanceOf[Record].elements(name))
case Index(imm, _) => getEffected(imm)
case _ => throw new InternalErrorException("Match error: a=$a")
case Slot(imm: Node, name) => Seq(imm.id.asInstanceOf[Record].elements(name))
case Index(imm, _) => getEffected(imm)
case _ => throw new InternalErrorException("Match error: a=$a")
}

// Given an arg, return the corresponding id. Don't use on a loc of a connect.
Expand Down
Loading

0 comments on commit dc970d9

Please sign in to comment.