Update to chisel 3.2.x

This commit is contained in:
Colin Schmidt
2020-02-18 14:56:17 -08:00
parent 5198b3883c
commit 7de4c478c3
9 changed files with 124 additions and 122 deletions

View File

@@ -39,6 +39,11 @@ lazy val macros = (project in file("macros"))
lazy val tapeout = (project in file("tapeout")) lazy val tapeout = (project in file("tapeout"))
.settings(commonSettings) .settings(commonSettings)
.settings(Seq(
libraryDependencies ++= Seq(
"io.github.daviddenton" %% "handlebars-scala-fork" % "2.3.0"
)
))
.settings(scalacOptions in Test ++= Seq("-language:reflectiveCalls")) .settings(scalacOptions in Test ++= Seq("-language:reflectiveCalls"))
lazy val root = (project in file(".")).aggregate(macros, tapeout) lazy val root = (project in file(".")).aggregate(macros, tapeout)

View File

@@ -42,8 +42,8 @@ case object ClkGen extends ClkModType {
def serialize: String = "gen" def serialize: String = "gen"
} }
// Unlike typical SDC, starts at 0. // Unlike typical SDC, starts at 0.
// Otherwise, see pg. 63 of "Constraining Designs for Synthesis and Timing Analysis" // Otherwise, see pg. 63 of "Constraining Designs for Synthesis and Timing Analysis"
// by S. Gangadharan // by S. Gangadharan
// original clk: |-----|_____|-----|_____| // original clk: |-----|_____|-----|_____|
// edges: 0 1 2 3 4 // edges: 0 1 2 3 4
@@ -51,9 +51,9 @@ case object ClkGen extends ClkModType {
// ---> |-----------|___________| // ---> |-----------|___________|
// sources = source id's // sources = source id's
case class GeneratedClk( case class GeneratedClk(
id: String, id: String,
sources: Seq[String] = Seq(), sources: Seq[String] = Seq(),
referenceEdges: Seq[Int] = Seq(), referenceEdges: Seq[Int] = Seq(),
period: Option[Double] = None) { period: Option[Double] = None) {
require(referenceEdges.sorted == referenceEdges, "Edges must be in order for generated clk") require(referenceEdges.sorted == referenceEdges, "Edges must be in order for generated clk")
if (referenceEdges.nonEmpty) require(referenceEdges.length % 2 == 1, "# of reference edges must be odd!") if (referenceEdges.nonEmpty) require(referenceEdges.length % 2 == 1, "# of reference edges must be odd!")
@@ -64,13 +64,13 @@ case class ClkModAnnotation(tpe: String, generatedClks: Seq[GeneratedClk]) {
def modType: ClkModType = HasClkAnnotation.modType(tpe) def modType: ClkModType = HasClkAnnotation.modType(tpe)
modType match { modType match {
case ClkDiv => case ClkDiv =>
generatedClks foreach { c => generatedClks foreach { c =>
require(c.referenceEdges.nonEmpty, "Reference edges must be defined for clk divider!") require(c.referenceEdges.nonEmpty, "Reference edges must be defined for clk divider!")
require(c.sources.length == 1, "Clk divider output can only have 1 source") require(c.sources.length == 1, "Clk divider output can only have 1 source")
require(c.period.isEmpty, "No period should be specified for clk divider output") require(c.period.isEmpty, "No period should be specified for clk divider output")
} }
case ClkMux => case ClkMux =>
generatedClks foreach { c => generatedClks foreach { c =>
require(c.referenceEdges.isEmpty, "Reference edges must not be defined for clk mux!") require(c.referenceEdges.isEmpty, "Reference edges must not be defined for clk mux!")
require(c.period.isEmpty, "No period should be specified for clk mux output") require(c.period.isEmpty, "No period should be specified for clk mux output")
@@ -92,22 +92,24 @@ abstract class FirrtlClkTransformAnnotation {
} }
// Firrtl version // Firrtl version
case class TargetClkModAnnoF(target: ModuleName, anno: ClkModAnnotation) extends FirrtlClkTransformAnnotation { case class TargetClkModAnnoF(target: ModuleName, anno: ClkModAnnotation) extends FirrtlClkTransformAnnotation with SingleTargetAnnotation[ModuleName] {
def duplicate(n: ModuleName): TargetClkModAnnoF = this.copy(target = n)
def getAnno = Annotation(target, classOf[ClkSrcTransform], anno.serialize) def getAnno = Annotation(target, classOf[ClkSrcTransform], anno.serialize)
def targetName = target.name def targetName = target.name
def modType = anno.modType def modType = anno.modType
def generatedClks = anno.generatedClks def generatedClks = anno.generatedClks
def getAllClkPorts = anno.generatedClks.map(x => def getAllClkPorts = anno.generatedClks.map(x =>
List(List(x.id), x.sources).flatten).flatten.distinct.map(Seq(targetName, _).mkString(".")) List(List(x.id), x.sources).flatten).flatten.distinct.map(Seq(targetName, _).mkString("."))
} }
// Chisel version // Chisel version
case class TargetClkModAnnoC(target: Module, anno: ClkModAnnotation) { case class TargetClkModAnnoC(target: Module, anno: ClkModAnnotation) extends ChiselAnnotation {
def getAnno = ChiselAnnotation(target, classOf[ClkSrcTransform], anno.serialize) def toFirrtl = TargetClkModAnnoF(target.toNamed, anno)
} }
// Firrtl version // Firrtl version
case class TargetClkPortAnnoF(target: ComponentName, anno: ClkPortAnnotation) extends FirrtlClkTransformAnnotation { case class TargetClkPortAnnoF(target: ComponentName, anno: ClkPortAnnotation) extends FirrtlClkTransformAnnotation with SingleTargetAnnotation[ComponentName] {
def duplicate(n: ComponentName): TargetClkPortAnnoF = this.copy(target = n)
def getAnno = Annotation(target, classOf[ClkSrcTransform], anno.serialize) def getAnno = Annotation(target, classOf[ClkSrcTransform], anno.serialize)
def targetName = Seq(target.module.name, target.name).mkString(".") def targetName = Seq(target.module.name, target.name).mkString(".")
def modId = Seq(target.module.name, anno.id).mkString(".") def modId = Seq(target.module.name, anno.id).mkString(".")
@@ -115,8 +117,8 @@ case class TargetClkPortAnnoF(target: ComponentName, anno: ClkPortAnnotation) ex
} }
// Chisel version // Chisel version
case class TargetClkPortAnnoC(target: Element, anno: ClkPortAnnotation) { case class TargetClkPortAnnoC(target: Element, anno: ClkPortAnnotation) extends ChiselAnnotation {
def getAnno = ChiselAnnotation(target, classOf[ClkSrcTransform], anno.serialize) def toFirrtl = TargetClkPortAnnoF(target.toNamed, anno)
} }
object HasClkAnnotation { object HasClkAnnotation {
@@ -132,31 +134,31 @@ object HasClkAnnotation {
def unapply(a: Annotation): Option[FirrtlClkTransformAnnotation] = a match { def unapply(a: Annotation): Option[FirrtlClkTransformAnnotation] = a match {
case Annotation(f, t, s) if t == classOf[ClkSrcTransform] => f match { case Annotation(f, t, s) if t == classOf[ClkSrcTransform] => f match {
case m: ModuleName => case m: ModuleName =>
Some(TargetClkModAnnoF(m, s.parseYaml.convertTo[ClkModAnnotation])) Some(TargetClkModAnnoF(m, s.parseYaml.convertTo[ClkModAnnotation]))
case c: ComponentName => case c: ComponentName =>
Some(TargetClkPortAnnoF(c, s.parseYaml.convertTo[ClkPortAnnotation])) Some(TargetClkPortAnnoF(c, s.parseYaml.convertTo[ClkPortAnnotation]))
case _ => throw new Exception("Clk source annotation only valid on module or component!") case _ => throw new Exception("Clk source annotation only valid on module or component!")
} }
case _ => None case _ => None
} }
def apply(annos: Seq[Annotation]): Option[(Seq[TargetClkModAnnoF],Seq[TargetClkPortAnnoF])] = { def apply(annos: Seq[Annotation]): Option[(Seq[TargetClkModAnnoF],Seq[TargetClkPortAnnoF])] = {
// Get all clk-related annotations // Get all clk-related annotations
val clkAnnos = annos.map(x => unapply(x)).flatten val clkAnnos = annos.map(x => unapply(x)).flatten
val targets = clkAnnos.map(x => x.targetName) val targets = clkAnnos.map(x => x.targetName)
require(targets.distinct.length == targets.length, "Only 1 clk related annotation is allowed per component/module") require(targets.distinct.length == targets.length, "Only 1 clk related annotation is allowed per component/module")
if (clkAnnos.length == 0) None if (clkAnnos.length == 0) None
else { else {
val componentAnnos = clkAnnos.filter { val componentAnnos = clkAnnos.filter {
case TargetClkPortAnnoF(ComponentName(_, ModuleName(_, _)), _) => true case TargetClkPortAnnoF(ComponentName(_, ModuleName(_, _)), _) => true
case _ => false case _ => false
}.map(x => x.asInstanceOf[TargetClkPortAnnoF]) }.map(x => x.asInstanceOf[TargetClkPortAnnoF])
val associatedMods = componentAnnos.map(x => x.target.module.name) val associatedMods = componentAnnos.map(x => x.target.module.name)
val moduleAnnos = clkAnnos.filter { val moduleAnnos = clkAnnos.filter {
case TargetClkModAnnoF(ModuleName(m, _), _) => case TargetClkModAnnoF(ModuleName(m, _), _) =>
require(associatedMods contains m, "Clk modules should always have clk port annotations!") require(associatedMods contains m, "Clk modules should always have clk port annotations!")
true true
case _ => false case _ => false
}.map(x => x.asInstanceOf[TargetClkModAnnoF]) }.map(x => x.asInstanceOf[TargetClkModAnnoF])
Some((moduleAnnos, componentAnnos)) Some((moduleAnnos, componentAnnos))
@@ -170,29 +172,26 @@ trait IsClkModule {
self: chisel3.Module => self: chisel3.Module =>
private def doNotDedup(module: Module): Unit = {
annotate(ChiselAnnotation(module, classOf[DedupModules], "nodedup!"))
}
doNotDedup(this) doNotDedup(this)
private def extractElementNames(signal: Data): Seq[String] = { private def extractElementNames(signal: Data): Seq[String] = {
val names = signal match { val names = signal match {
case elt: Record => case elt: Record =>
elt.elements.map { case (key, value) => extractElementNames(value).map(x => key + "_" + x) }.toSeq.flatten elt.elements.map { case (key, value) => extractElementNames(value).map(x => key + "_" + x) }.toSeq.flatten
case elt: Vec[_] => case elt: Vec[_] =>
elt.zipWithIndex.map { case (elt, i) => extractElementNames(elt).map(x => i + "_" + x) }.toSeq.flatten elt.zipWithIndex.map { case (elt, i) => extractElementNames(elt).map(x => i + "_" + x) }.toSeq.flatten
case elt: Element => Seq("") case elt: Element => Seq("")
case elt => throw new Exception(s"Cannot extractElementNames for type ${elt.getClass}") case elt => throw new Exception(s"Cannot extractElementNames for type ${elt.getClass}")
} }
names.map(s => s.stripSuffix("_")) names.map(s => s.stripSuffix("_"))
} }
// TODO: Replace! // TODO: Replace!
def extractElements(signal: Data): Seq[Element] = { def extractElements(signal: Data): Seq[Element] = {
signal match { signal match {
case elt: Record => case elt: Record =>
elt.elements.map { case (key, value) => extractElements(value) }.toSeq.flatten elt.elements.map { case (key, value) => extractElements(value) }.toSeq.flatten
case elt: Vec[_] => case elt: Vec[_] =>
elt.map { elt => extractElements(elt) }.toSeq.flatten elt.map { elt => extractElements(elt) }.toSeq.flatten
case elt: Element => Seq(elt) case elt: Element => Seq(elt)
case elt => throw new Exception(s"Cannot extractElements for type ${elt.getClass}") case elt => throw new Exception(s"Cannot extractElements for type ${elt.getClass}")
@@ -200,7 +199,7 @@ trait IsClkModule {
} }
def getIOName(signal: Element): String = { def getIOName(signal: Element): String = {
val possibleNames = extractElements(io).zip(extractElementNames(io)).map { val possibleNames = extractElements(io).zip(extractElementNames(io)).map {
case (sig, name) if sig == signal => Some(name) case (sig, name) if sig == signal => Some(name)
case _ => None case _ => None
}.flatten }.flatten
@@ -208,11 +207,11 @@ trait IsClkModule {
else throw new Exception("You can only get the name of an io port!") else throw new Exception("You can only get the name of an io port!")
} }
def annotateDerivedClks(tpe: ClkModType, generatedClks: Seq[GeneratedClk]): Unit = def annotateDerivedClks(tpe: ClkModType, generatedClks: Seq[GeneratedClk]): Unit =
annotateDerivedClks(ClkModAnnotation(tpe.serialize, generatedClks)) annotateDerivedClks(ClkModAnnotation(tpe.serialize, generatedClks))
def annotateDerivedClks(anno: ClkModAnnotation): Unit = annotateDerivedClks(this, anno) def annotateDerivedClks(anno: ClkModAnnotation): Unit = annotateDerivedClks(this, anno)
def annotateDerivedClks(m: Module, anno: ClkModAnnotation): Unit = def annotateDerivedClks(m: Module, anno: ClkModAnnotation): Unit =
annotate(TargetClkModAnnoC(m, anno).getAnno) annotate(TargetClkModAnnoC(m, anno))
def annotateClkPort(p: Element): Unit = annotateClkPort(p, None, "") def annotateClkPort(p: Element): Unit = annotateClkPort(p, None, "")
def annotateClkPort(p: Element, sink: Sink): Unit = annotateClkPort(p, Some(sink), "") def annotateClkPort(p: Element, sink: Sink): Unit = annotateClkPort(p, Some(sink), "")
@@ -221,7 +220,7 @@ trait IsClkModule {
def annotateClkPort(p: Element, sink: Option[Sink], id: String): Unit = { def annotateClkPort(p: Element, sink: Option[Sink], id: String): Unit = {
// If no id is specified, it'll try to figure out a name, assuming p is an io port // If no id is specified, it'll try to figure out a name, assuming p is an io port
val newId = id match { val newId = id match {
case "" => case "" =>
getIOName(p) getIOName(p)
case _ => id case _ => id
} }
@@ -229,12 +228,12 @@ trait IsClkModule {
} }
def annotateClkPort(p: Element, anno: ClkPortAnnotation): Unit = { def annotateClkPort(p: Element, anno: ClkPortAnnotation): Unit = {
p.dir match { DataMirror.directionOf(p) match {
case chisel3.core.Direction.Input => case chisel3.core.ActualDirection.Input =>
require(anno.tag.nonEmpty, "Module inputs must be clk sinks") require(anno.tag.nonEmpty, "Module inputs must be clk sinks")
require(anno.tag.get.src.isEmpty, require(anno.tag.get.src.isEmpty,
"Clock module (not top) input clks should not have clk period, etc. specified") "Clock module (not top) input clks should not have clk period, etc. specified")
case chisel3.core.Direction.Output => case chisel3.core.ActualDirection.Output =>
require(anno.tag.isEmpty, "Module outputs must not be clk sinks (they're sources!)") require(anno.tag.isEmpty, "Module outputs must not be clk sinks (they're sources!)")
case _ => case _ =>
throw new Exception("Clk port direction must be specified!") throw new Exception("Clk port direction must be specified!")
@@ -243,6 +242,6 @@ trait IsClkModule {
case _: chisel3.core.Clock => case _: chisel3.core.Clock =>
case _ => throw new Exception("Clock port must be of type Clock") case _ => throw new Exception("Clock port must be of type Clock")
} }
annotate(TargetClkPortAnnoC(p, anno).getAnno) annotate(TargetClkPortAnnoC(p, anno))
} }
} }

View File

@@ -52,12 +52,12 @@ class AddIOPadsTransform extends Transform with SeqTransformBased {
) )
// Expects BlackBox helper to be run after to inline pad Verilog! // Expects BlackBox helper to be run after to inline pad Verilog!
val ret = runTransforms(state) val ret = runTransforms(state)
val currentAnnos = ret.annotations.getOrElse(AnnotationMap(Seq.empty)).annotations val currentAnnos = ret.annotations
val newAnnoMap = AnnotationMap(currentAnnos ++ bbAnnotations) val newAnnoMap = AnnotationSeq(currentAnnos ++ bbAnnotations)
val newState = CircuitState(ret.circuit, outputForm, Some(newAnnoMap), ret.renames) val newState = CircuitState(ret.circuit, outputForm, newAnnoMap, ret.renames)
// TODO: *.f file is overwritten on subsequent executions, but it doesn't seem to be used anywhere? // TODO: *.f file is overwritten on subsequent executions, but it doesn't seem to be used anywhere?
(new firrtl.transforms.BlackBoxSourceHelper).execute(newState) (new firrtl.transforms.BlackBoxSourceHelper).execute(newState)
} }
} }
} }

View File

@@ -22,13 +22,13 @@ case class TopSupplyPad(
require(pad.padType == SupplyPad) require(pad.padType == SupplyPad)
def padOrientation = padSide.orientation def padOrientation = padSide.orientation
def getPadName = pad.getName(NoDirection, padOrientation) def getPadName = pad.getName(Output/*Should be None*/, padOrientation)
def firrtlBBName = getPadName def firrtlBBName = getPadName
private def instNamePrefix = Seq(firrtlBBName, padSide.serialize).mkString("_") private def instNamePrefix = Seq(firrtlBBName, padSide.serialize).mkString("_")
def instNames = (0 until num).map(i => Seq(instNamePrefix, i.toString).mkString("_")) def instNames = (0 until num).map(i => Seq(instNamePrefix, i.toString).mkString("_"))
def createPadInline(): String = { def createPadInline(): String = {
def getPadVerilog(): String = pad.getVerilog(NoDirection, padOrientation) def getPadVerilog(): String = pad.getVerilog(Output/*Should be None*/, padOrientation)
s"""inline s"""inline
|${getPadName}.v |${getPadName}.v
|${getPadVerilog}""".stripMargin |${getPadVerilog}""".stripMargin
@@ -37,14 +37,14 @@ case class TopSupplyPad(
object AnnotateSupplyPads { object AnnotateSupplyPads {
def apply( def apply(
pads: Seq[FoundryPad], pads: Seq[FoundryPad],
supplyAnnos: Seq[SupplyAnnotation] supplyAnnos: Seq[SupplyAnnotation]
): Seq[TopSupplyPad] = { ): Seq[TopSupplyPad] = {
supplyAnnos.map( a => supplyAnnos.map( a =>
pads.find(_.name == a.padName) match { pads.find(_.name == a.padName) match {
case None => case None =>
throw new Exception(s"Supply pad ${a.padName} not found in Yaml file!") throw new Exception(s"Supply pad ${a.padName} not found in Yaml file!")
case Some(x) => case Some(x) =>
Seq( Seq(
TopSupplyPad(x, Left, a.leftSide), TopSupplyPad(x, Left, a.leftSide),
TopSupplyPad(x, Right, a.rightSide), TopSupplyPad(x, Right, a.rightSide),
@@ -53,4 +53,4 @@ object AnnotateSupplyPads {
} }
).flatten.filter(_.num > 0) ).flatten.filter(_.num > 0)
} }
} }

View File

@@ -8,8 +8,8 @@ import firrtl.transforms.DedupModules
// TODO: Move out of pads // TODO: Move out of pads
// NOTE: You can't really annotate outside of the module itself UNLESS you break up the compile step in 2 i.e. // NOTE: You can't really annotate outside of the module itself UNLESS you break up the compile step in 2 i.e.
// annotate post-Chisel but pre-Firrtl (unfortunate non-generator friendly downside). // annotate post-Chisel but pre-Firrtl (unfortunate non-generator friendly downside).
// It's recommended to have a Tapeout specific TopModule wrapper. // It's recommended to have a Tapeout specific TopModule wrapper.
// LIMITATION: All signals of a bus must be on the same chip side // LIMITATION: All signals of a bus must be on the same chip side
// Chisel-y annotations // Chisel-y annotations
@@ -19,14 +19,17 @@ abstract class TopModule(
coreWidth: Int = 0, coreWidth: Int = 0,
coreHeight: Int = 0, coreHeight: Int = 0,
usePads: Boolean = true, usePads: Boolean = true,
override_clock: Option[Clock] = None, override_clock: Option[Clock] = None,
override_reset: Option[Bool] = None) extends Module(override_clock, override_reset) with IsClkModule { override_reset: Option[Bool] = None) extends Module with IsClkModule {
override_clock.foreach(clock := _)
override_reset.foreach(reset := _)
override def annotateClkPort(p: Element, anno: ClkPortAnnotation): Unit = { override def annotateClkPort(p: Element, anno: ClkPortAnnotation): Unit = {
p.dir match { DataMirror.directionOf(p) match {
case chisel3.core.Direction.Input => case chisel3.core.ActualDirection.Input =>
require(anno.tag.nonEmpty, "Top Module input clks must be clk sinks") require(anno.tag.nonEmpty, "Top Module input clks must be clk sinks")
require(anno.tag.get.src.nonEmpty, require(anno.tag.get.src.nonEmpty,
"Top module input clks must have clk period, etc. specified") "Top module input clks must have clk period, etc. specified")
case _ => case _ =>
throw new Exception("Clk port direction must be specified!") throw new Exception("Clk port direction must be specified!")
@@ -35,10 +38,10 @@ abstract class TopModule(
case _: chisel3.core.Clock => case _: chisel3.core.Clock =>
case _ => throw new Exception("Clock port must be of type Clock") case _ => throw new Exception("Clock port must be of type Clock")
} }
annotate(TargetClkPortAnnoC(p, anno).getAnno) annotate(TargetClkPortAnnoC(p, anno))
} }
override def annotateDerivedClks(m: Module, anno: ClkModAnnotation): Unit = override def annotateDerivedClks(m: Module, anno: ClkModAnnotation): Unit =
throw new Exception("Top module cannot be pure clock module!") throw new Exception("Top module cannot be pure clock module!")
// Annotate module as top module (that requires pad transform) // Annotate module as top module (that requires pad transform)
@@ -52,25 +55,25 @@ abstract class TopModule(
coreHeight = coreHeight, coreHeight = coreHeight,
supplyAnnos = supplyAnnos supplyAnnos = supplyAnnos
) )
annotate(TargetModulePadAnnoC(this, modulePadAnnotation).getAnno) annotate(TargetModulePadAnnoC(this, modulePadAnnotation))
} }
// Annotate IO with side + pad name // Annotate IO with side + pad name
def annotatePad(sig: Element, side: PadSide = defaultPadSide, name: String = ""): Unit = if (usePads) { def annotatePad(sig: Element, side: PadSide = defaultPadSide, name: String = ""): Unit = if (usePads) {
val anno = IOPadAnnotation(side.serialize, name) val anno = IOPadAnnotation(side.serialize, name)
annotate(TargetIOPadAnnoC(sig, anno).getAnno) annotate(TargetIOPadAnnoC(sig, anno))
} }
def annotatePad(sig: Aggregate, name: String): Unit = annotatePad(sig, side = defaultPadSide, name) def annotatePad(sig: Aggregate, name: String): Unit = annotatePad(sig, side = defaultPadSide, name)
def annotatePad(sig: Aggregate, side: PadSide): Unit = annotatePad(sig, side, name = "") def annotatePad(sig: Aggregate, side: PadSide): Unit = annotatePad(sig, side, name = "")
def annotatePad(sig: Aggregate, side: PadSide, name: String): Unit = def annotatePad(sig: Aggregate, side: PadSide, name: String): Unit =
extractElements(sig) foreach { x => annotatePad(x, side, name) } extractElements(sig) foreach { x => annotatePad(x, side, name) }
// There may be cases where pads were inserted elsewhere. If that's the case, allow certain IO to // There may be cases where pads were inserted elsewhere. If that's the case, allow certain IO to
// not have pads auto added. Note that annotatePad and noPad are mutually exclusive! // not have pads auto added. Note that annotatePad and noPad are mutually exclusive!
def noPad(sig: Element): Unit = if (usePads) annotate(TargetIOPadAnnoC(sig, NoIOPadAnnotation()).getAnno) def noPad(sig: Element): Unit = if (usePads) annotate(TargetIOPadAnnoC(sig, NoIOPadAnnotation()))
def noPad(sig: Aggregate): Unit = extractElements(sig) foreach { x => noPad(x) } def noPad(sig: Aggregate): Unit = extractElements(sig) foreach { x => noPad(x) }
// Since this is a super class, this should be the first thing that gets run // Since this is a super class, this should be the first thing that gets run
// (at least when the module is actually at the top -- currently no guarantees otherwise :( firrtl limitation) // (at least when the module is actually at the top -- currently no guarantees otherwise :( firrtl limitation)
createPads() createPads()
} }

View File

@@ -40,7 +40,7 @@ object CreatePadBBs {
} }
def checkLegalPadName(namespace: Namespace, usedPads: Seq[UsedPadInfo]): Unit = { def checkLegalPadName(namespace: Namespace, usedPads: Seq[UsedPadInfo]): Unit = {
usedPads foreach { x => usedPads foreach { x =>
if (namespace contains x.padName) if (namespace contains x.padName)
throw new Exception(s"Pad name ${x.padName} already used!") throw new Exception(s"Pad name ${x.padName} already used!")
if (namespace contains x.padArrayName) if (namespace contains x.padArrayName)
@@ -61,21 +61,21 @@ object CreatePadBBs {
// Note that we need to check for Firrtl name uniqueness here! (due to parameterization) // Note that we need to check for Firrtl name uniqueness here! (due to parameterization)
val uniqueExtMods = scala.collection.mutable.ArrayBuffer[UsedPadInfo]() val uniqueExtMods = scala.collection.mutable.ArrayBuffer[UsedPadInfo]()
usedPads foreach { x => usedPads foreach { x =>
if (uniqueExtMods.find(_.firrtlBBName == x.firrtlBBName).isEmpty) if (uniqueExtMods.find(_.firrtlBBName == x.firrtlBBName).isEmpty)
uniqueExtMods += x uniqueExtMods += x
} }
// Collecting unique parameterized black boxes // Collecting unique parameterized black boxes
// (for io, they're wrapped pads; for supply, they're pad modules directly) // (for io, they're wrapped pads; for supply, they're pad modules directly)
val uniqueParameterizedBBs = scala.collection.mutable.ArrayBuffer[UsedPadInfo]() val uniqueParameterizedBBs = scala.collection.mutable.ArrayBuffer[UsedPadInfo]()
uniqueExtMods foreach { x => uniqueExtMods foreach { x =>
if (uniqueParameterizedBBs.find(_.padArrayName == x.padArrayName).isEmpty) if (uniqueParameterizedBBs.find(_.padArrayName == x.padArrayName).isEmpty)
uniqueParameterizedBBs += x uniqueParameterizedBBs += x
} }
// Note: Firrtl is silly and doesn't implement true parameterization -- each module with // Note: Firrtl is silly and doesn't implement true parameterization -- each module with
// parameterization that potentially affects # of IO needs to be uniquely identified // parameterization that potentially affects # of IO needs to be uniquely identified
// (but only in Firrtl) // (but only in Firrtl)
val bbs = uniqueExtMods.map(x => { val bbs = uniqueExtMods.map(x => {
// Supply pads don't have ports // Supply pads don't have ports
@@ -100,10 +100,10 @@ object CreatePadBBs {
// Add annotations to black boxes to inline Verilog from template // Add annotations to black boxes to inline Verilog from template
// Again, note the weirdness in parameterization -- just need to hook to one matching Firrtl instance // Again, note the weirdness in parameterization -- just need to hook to one matching Firrtl instance
val annos = uniqueParameterizedBBs.map(x => val annos = uniqueParameterizedBBs.map(x =>
BlackBoxSourceAnnotation(ModuleName(x.firrtlBBName, CircuitName(c.main)), x.padInline) BlackBoxInlineAnno(ModuleName(x.firrtlBBName, CircuitName(c.main)), x.firrtlBBName, x.padInline)
).toSeq ).toSeq
(c.copy(modules = c.modules ++ bbs), annos) (c.copy(modules = c.modules ++ bbs), annos)
} }
} }

View File

@@ -7,11 +7,11 @@ import firrtl.ir._
import barstools.tapeout.transforms._ import barstools.tapeout.transforms._
case class FoundryPad( case class FoundryPad(
tpe: String, tpe: String,
name: String, name: String,
width: Int, width: Int,
height: Int, height: Int,
supplySetNum: Option[Int], supplySetNum: Option[Int],
verilog: String) { verilog: String) {
def padInstName = "PAD" def padInstName = "PAD"
@@ -23,16 +23,16 @@ case class FoundryPad(
def getSupplySetNum = supplySetNum.getOrElse(1) def getSupplySetNum = supplySetNum.getOrElse(1)
val padType = tpe match { val padType = tpe match {
case "digital" => case "digital" =>
require(verilog.contains(DigitalPad.inName), "Digital pad template must contain input called 'in'") require(verilog.contains(DigitalPad.inName), "Digital pad template must contain input called 'in'")
require(verilog.contains(DigitalPad.outName), "Digital pad template must contain output called 'out'") require(verilog.contains(DigitalPad.outName), "Digital pad template must contain output called 'out'")
require(verilog.contains("{{#if isInput}}"), "Digital pad template must contain '{{#if isInput}}'") require(verilog.contains("{{#if isInput}}"), "Digital pad template must contain '{{#if isInput}}'")
DigitalPad DigitalPad
case "analog" => case "analog" =>
require(verilog.contains(AnalogPad.ioName), "Analog pad template must contain inout called 'io'") require(verilog.contains(AnalogPad.ioName), "Analog pad template must contain inout called 'io'")
require(!verilog.contains("{{#if isInput}}"), "Analog pad template must not contain '{{#if isInput}}'") require(!verilog.contains("{{#if isInput}}"), "Analog pad template must not contain '{{#if isInput}}'")
AnalogPad AnalogPad
case "supply" => case "supply" =>
// Supply pads don't have IO // Supply pads don't have IO
require(!verilog.contains("{{#if isInput}}"), "Supply pad template must not contain '{{#if isInput}}'") require(!verilog.contains("{{#if isInput}}"), "Supply pad template must not contain '{{#if isInput}}'")
require( require(
@@ -57,8 +57,8 @@ case class FoundryPad(
private val orient = if (isHorizontal) Horizontal.serialize else Vertical.serialize private val orient = if (isHorizontal) Horizontal.serialize else Vertical.serialize
private val dir = padType match { private val dir = padType match {
case AnalogPad => InOut.serialize case AnalogPad => "inout"
case SupplyPad => NoDirection.serialize case SupplyPad => "none"
case DigitalPad => if (isInput) Input.serialize else Output.serialize case DigitalPad => if (isInput) Input.serialize else Output.serialize
} }
val name = { val name = {
@@ -69,7 +69,7 @@ case class FoundryPad(
} }
// Note: Analog + supply don't use direction // Note: Analog + supply don't use direction
private def getTemplateParams(dir: Direction, orient: PadOrientation): TemplateParams = private def getTemplateParams(dir: Direction, orient: PadOrientation): TemplateParams =
TemplateParams(isInput = (dir == Input), isHorizontal = (orient == Horizontal)) TemplateParams(isInput = (dir == Input), isHorizontal = (orient == Horizontal))
def getVerilog(dir: Direction, orient: PadOrientation): String = { def getVerilog(dir: Direction, orient: PadOrientation): String = {
@@ -85,11 +85,11 @@ object FoundryPadsYaml extends DefaultYamlProtocol {
implicit val _pad = yamlFormat6(FoundryPad) implicit val _pad = yamlFormat6(FoundryPad)
def parse(techDir: String): Seq[FoundryPad] = { def parse(techDir: String): Seq[FoundryPad] = {
val file = techDir + exampleResource val file = techDir + exampleResource
if(techDir != "" && !(new java.io.File(file)).exists()) if(techDir != "" && !(new java.io.File(file)).exists())
throw new Exception("Technology directory must contain FoundryPads.yaml!") throw new Exception("Technology directory must contain FoundryPads.yaml!")
val out = (new YamlFileReader(exampleResource)).parse[FoundryPad](if (techDir == "") "" else file) val out = (new YamlFileReader(exampleResource)).parse[FoundryPad](if (techDir == "") "" else file)
val padNames = out.map(x => x.correctedName) val padNames = out.map(x => x.correctedName)
require(padNames.distinct.length == padNames.length, "Pad names must be unique!") require(padNames.distinct.length == padNames.length, "Pad names must be unique!")
out out
} }
} }

View File

@@ -21,7 +21,7 @@ abstract class FirrtlPadTransformAnnotation {
// IO Port can either be annotated with padName + padSide OR noPad (mutually exclusive) // IO Port can either be annotated with padName + padSide OR noPad (mutually exclusive)
abstract class IOAnnotation { abstract class IOAnnotation {
def serialize: String def serialize: String
} }
case class IOPadAnnotation(padSide: String, padName: String) extends IOAnnotation { case class IOPadAnnotation(padSide: String, padName: String) extends IOAnnotation {
import PadAnnotationsYaml._ import PadAnnotationsYaml._
@@ -31,29 +31,30 @@ case class IOPadAnnotation(padSide: String, padName: String) extends IOAnnotatio
case class NoIOPadAnnotation(noPad: String = "") extends IOAnnotation { case class NoIOPadAnnotation(noPad: String = "") extends IOAnnotation {
import PadAnnotationsYaml._ import PadAnnotationsYaml._
def serialize: String = this.toYaml.prettyPrint def serialize: String = this.toYaml.prettyPrint
def field = "noPad:" def field = "noPad:"
} }
// Firrtl version // Firrtl version
case class TargetIOPadAnnoF(target: ComponentName, anno: IOAnnotation) extends FirrtlPadTransformAnnotation { case class TargetIOPadAnnoF(target: ComponentName, anno: IOAnnotation) extends FirrtlPadTransformAnnotation with SingleTargetAnnotation[ComponentName] {
def duplicate(n: ComponentName): TargetIOPadAnnoF = this.copy(target = n)
def getAnno = Annotation(target, classOf[AddIOPadsTransform], anno.serialize) def getAnno = Annotation(target, classOf[AddIOPadsTransform], anno.serialize)
def targetName = target.name def targetName = target.name
} }
// Chisel version // Chisel version
case class TargetIOPadAnnoC(target: Element, anno: IOAnnotation) { case class TargetIOPadAnnoC(target: Element, anno: IOAnnotation) extends ChiselAnnotation {
def getAnno = ChiselAnnotation(target, classOf[AddIOPadsTransform], anno.serialize) def toFirrtl = TargetIOPadAnnoF(target.toNamed, anno)
} }
// A bunch of supply pads (designated by name, # on each chip side) can be associated with the top module // A bunch of supply pads (designated by name, # on each chip side) can be associated with the top module
case class SupplyAnnotation( case class SupplyAnnotation(
padName: String, padName: String,
leftSide: Int = 0, leftSide: Int = 0,
rightSide: Int = 0, rightSide: Int = 0,
topSide: Int = 0, topSide: Int = 0,
bottomSide: Int = 0) bottomSide: Int = 0)
// The chip top should have a default pad side, a pad template file, and supply annotations // The chip top should have a default pad side, a pad template file, and supply annotations
case class ModulePadAnnotation( case class ModulePadAnnotation(
defaultPadSide: String = Top.serialize, defaultPadSide: String = Top.serialize,
coreWidth: Int = 0, coreWidth: Int = 0,
coreHeight: Int = 0, coreHeight: Int = 0,
supplyAnnos: Seq[SupplyAnnotation] = Seq.empty) { supplyAnnos: Seq[SupplyAnnotation] = Seq.empty) {
import PadAnnotationsYaml._ import PadAnnotationsYaml._
@@ -63,13 +64,14 @@ case class ModulePadAnnotation(
def getDefaultPadSide: PadSide = HasPadAnnotation.getSide(defaultPadSide) def getDefaultPadSide: PadSide = HasPadAnnotation.getSide(defaultPadSide)
} }
// Firrtl version // Firrtl version
case class TargetModulePadAnnoF(target: ModuleName, anno: ModulePadAnnotation) extends FirrtlPadTransformAnnotation { case class TargetModulePadAnnoF(target: ModuleName, anno: ModulePadAnnotation) extends FirrtlPadTransformAnnotation with SingleTargetAnnotation[ModuleName] {
def getAnno = Annotation(target, classOf[AddIOPadsTransform], anno.serialize) def duplicate(n: ModuleName): TargetModulePadAnnoF = this.copy(target = n)
def getAnno = Annotation(target, classOf[AddIOPadsTransform], anno.serialize)
def targetName = target.name def targetName = target.name
} }
// Chisel version // Chisel version
case class TargetModulePadAnnoC(target: Module, anno: ModulePadAnnotation) { case class TargetModulePadAnnoC(target: Module, anno: ModulePadAnnotation) extends ChiselAnnotation {
def getAnno = ChiselAnnotation(target, classOf[AddIOPadsTransform], anno.serialize) def toFirrtl = TargetModulePadAnnoF(target.toNamed, anno)
} }
case class CollectedAnnos( case class CollectedAnnos(
@@ -95,9 +97,9 @@ object HasPadAnnotation {
def unapply(a: Annotation): Option[FirrtlPadTransformAnnotation] = a match { def unapply(a: Annotation): Option[FirrtlPadTransformAnnotation] = a match {
case Annotation(f, t, s) if t == classOf[AddIOPadsTransform] => f match { case Annotation(f, t, s) if t == classOf[AddIOPadsTransform] => f match {
case m: ModuleName => case m: ModuleName =>
Some(TargetModulePadAnnoF(m, s.parseYaml.convertTo[ModulePadAnnotation])) Some(TargetModulePadAnnoF(m, s.parseYaml.convertTo[ModulePadAnnotation]))
case c: ComponentName if s.contains(NoIOPadAnnotation().field) => case c: ComponentName if s.contains(NoIOPadAnnotation().field) =>
Some(TargetIOPadAnnoF(c, s.parseYaml.convertTo[NoIOPadAnnotation])) Some(TargetIOPadAnnoF(c, s.parseYaml.convertTo[NoIOPadAnnotation]))
case c: ComponentName => case c: ComponentName =>
Some(TargetIOPadAnnoF(c, s.parseYaml.convertTo[IOPadAnnotation])) Some(TargetIOPadAnnoF(c, s.parseYaml.convertTo[IOPadAnnotation]))
@@ -108,26 +110,26 @@ object HasPadAnnotation {
def apply(annos: Seq[Annotation]): Option[CollectedAnnos] = { def apply(annos: Seq[Annotation]): Option[CollectedAnnos] = {
// Get all pad-related annotations (config files, pad sides, pad names, etc.) // Get all pad-related annotations (config files, pad sides, pad names, etc.)
val padAnnos = annos.map(x => unapply(x)).flatten val padAnnos = annos.map(x => unapply(x)).flatten
val targets = padAnnos.map(x => x.targetName) val targets = padAnnos.map(x => x.targetName)
require(targets.distinct.length == targets.length, "Only 1 pad related annotation is allowed per component/module") require(targets.distinct.length == targets.length, "Only 1 pad related annotation is allowed per component/module")
if (padAnnos.length == 0) None if (padAnnos.length == 0) None
else { else {
val moduleAnnosTemp = padAnnos.filter { val moduleAnnosTemp = padAnnos.filter {
case TargetModulePadAnnoF(_, _) => true case TargetModulePadAnnoF(_, _) => true
case _ => false case _ => false
} }
require(moduleAnnosTemp.length == 1, "Only 1 module may be designated 'Top'") require(moduleAnnosTemp.length == 1, "Only 1 module may be designated 'Top'")
val moduleAnnos = moduleAnnosTemp.head val moduleAnnos = moduleAnnosTemp.head
val topModName = moduleAnnos.targetName val topModName = moduleAnnos.targetName
val componentAnnos = padAnnos.filter { val componentAnnos = padAnnos.filter {
case TargetIOPadAnnoF(ComponentName(_, ModuleName(n, _)), _) if n == topModName => case TargetIOPadAnnoF(ComponentName(_, ModuleName(n, _)), _) if n == topModName =>
true true
case TargetIOPadAnnoF(ComponentName(_, ModuleName(n, _)), _) if n != topModName => case TargetIOPadAnnoF(ComponentName(_, ModuleName(n, _)), _) if n != topModName =>
throw new Exception("Pad related component annotations must all be in the same top module") throw new Exception("Pad related component annotations must all be in the same top module")
case _ => false case _ => false
}.map(x => x.asInstanceOf[TargetIOPadAnnoF]) }.map(x => x.asInstanceOf[TargetIOPadAnnoF])
Some(CollectedAnnos(componentAnnos, moduleAnnos.asInstanceOf[TargetModulePadAnnoF])) Some(CollectedAnnos(componentAnnos, moduleAnnos.asInstanceOf[TargetModulePadAnnoF]))
} }
} }
} }

View File

@@ -28,13 +28,6 @@ case object NoPad extends PadType {
def serialize: String = "none" def serialize: String = "none"
} }
case object InOut extends Direction {
def serialize: String = "inout"
}
case object NoDirection extends Direction {
def serialize: String = "none"
}
abstract class PadSide extends FirrtlNode { abstract class PadSide extends FirrtlNode {
def orientation: PadOrientation def orientation: PadOrientation
} }
@@ -53,4 +46,4 @@ case object Top extends PadSide {
case object Bottom extends PadSide { case object Bottom extends PadSide {
def serialize: String = "bottom" def serialize: String = "bottom"
def orientation: PadOrientation = Vertical def orientation: PadOrientation = Vertical
} }