Skip to content

Commit

Permalink
Make SRAMs directly emit FIRRTL memories (chipsalliance#3955)
Browse files Browse the repository at this point in the history
  • Loading branch information
debs-sifive authored Apr 2, 2024
1 parent 6406c41 commit feab7a7
Show file tree
Hide file tree
Showing 12 changed files with 387 additions and 90 deletions.
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
4 changes: 3 additions & 1 deletion 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
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))
}
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
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
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
2 changes: 1 addition & 1 deletion panamaconverter/src/PanamaCIRCTConverter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -986,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 feab7a7

Please sign in to comment.