From e4cd2b01fe5e4e89770a81443cf609657b683a67 Mon Sep 17 00:00:00 2001 From: chick Date: Thu, 10 Sep 2020 14:35:10 -0700 Subject: [PATCH 1/8] This is mess clean it up --- .scalafmt.conf | 26 ++ build.sbt | 4 +- macros/src/test/scala/MacroCompilerSpec.scala | 3 +- .../transforms/.clkgen/ClkAnnotations.scala | 247 ------------------ .../scala/transforms/.clkgen/ClkDivider.scala | 130 --------- .../transforms/.clkgen/ClkSrcTransform.scala | 34 --- .../.clkgen/CreateClkConstraints.scala | 152 ----------- .../transforms/.pads/ChiselTopModule.scala | 60 +++-- .../transforms/.pads/PadAnnotations.scala | 79 ++++-- .../scala/transforms/.clkgen/ClkGenSpec.scala | 181 ------------- 10 files changed, 120 insertions(+), 796 deletions(-) create mode 100644 .scalafmt.conf delete mode 100644 tapeout/src/main/scala/transforms/.clkgen/ClkAnnotations.scala delete mode 100644 tapeout/src/main/scala/transforms/.clkgen/ClkDivider.scala delete mode 100644 tapeout/src/main/scala/transforms/.clkgen/ClkSrcTransform.scala delete mode 100644 tapeout/src/main/scala/transforms/.clkgen/CreateClkConstraints.scala delete mode 100644 tapeout/src/test/scala/transforms/.clkgen/ClkGenSpec.scala diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 00000000..f74e5504 --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,26 @@ +version = 2.6.4 + +maxColumn = 120 +align = most +continuationIndent.defnSite = 2 +assumeStandardLibraryStripMargin = true +docstrings = ScalaDoc +lineEndings = preserve +includeCurlyBraceInSelectChains = false +danglingParentheses = true + +align.tokens.add = [ + { + code = ":" + } +] + +newlines.alwaysBeforeCurlyBraceLambdaParams = false +newlines.alwaysBeforeMultilineDef = false +newlines.implicitParamListModifierForce = [before] + +verticalMultiline.atDefnSite = true + +optIn.annotationNewlines = true + +rewrite.rules = [SortImports, PreferCurlyFors, AvoidInfix] diff --git a/build.sbt b/build.sbt index 9ec44bf7..c01a71e6 100644 --- a/build.sbt +++ b/build.sbt @@ -1,8 +1,8 @@ // See LICENSE for license details. val defaultVersions = Map( - "chisel3" -> "3.2-SNAPSHOT", - "chisel-iotesters" -> "1.3-SNAPSHOT" + "chisel3" -> "3.4-SNAPSHOT", + "chisel-iotesters" -> "1.5-SNAPSHOT" ) lazy val commonSettings = Seq( diff --git a/macros/src/test/scala/MacroCompilerSpec.scala b/macros/src/test/scala/MacroCompilerSpec.scala index dfecc0c1..0bc0f486 100644 --- a/macros/src/test/scala/MacroCompilerSpec.scala +++ b/macros/src/test/scala/MacroCompilerSpec.scala @@ -1,9 +1,10 @@ +// See LICENSE for license details. + package barstools.macros import firrtl.ir.{Circuit, NoInfo} import firrtl.passes.RemoveEmpty import firrtl.Parser.parse -import firrtl.Utils.ceilLog2 import java.io.{File, StringWriter} import mdf.macrolib.SRAMMacro diff --git a/tapeout/src/main/scala/transforms/.clkgen/ClkAnnotations.scala b/tapeout/src/main/scala/transforms/.clkgen/ClkAnnotations.scala deleted file mode 100644 index 3a2f9ba3..00000000 --- a/tapeout/src/main/scala/transforms/.clkgen/ClkAnnotations.scala +++ /dev/null @@ -1,247 +0,0 @@ -package barstools.tapeout.transforms.clkgen - -import net.jcazevedo.moultingyaml._ -import firrtl.annotations._ -import chisel3.experimental._ -import chisel3._ -import firrtl._ -import firrtl.transforms.DedupModules - -object ClkAnnotationsYaml extends DefaultYamlProtocol { - implicit val _clksrc = yamlFormat3(ClkSrc) - implicit val _sink = yamlFormat1(Sink) - implicit val _clkport = yamlFormat2(ClkPortAnnotation) - implicit val _genclk = yamlFormat4(GeneratedClk) - implicit val _clkmod = yamlFormat2(ClkModAnnotation) -} -case class ClkSrc(period: Double, waveform: Seq[Double] = Seq(), async: Seq[String] = Seq()) { - def getWaveform = if (waveform == Seq.empty) Seq(0, period/2) else waveform - // async = ids of top level clocks that are async with this clk - // Default is 50% duty cycle, period units is default - require(getWaveform.sorted == getWaveform, "Waveform edges must be in order") - require(getWaveform.length == 2, "Must specify time for rising edge, then time for falling edge") -} - -case class Sink(src: Option[ClkSrc] = None) - -case class ClkPortAnnotation(tag: Option[Sink] = None, id: String) { - import ClkAnnotationsYaml._ - def serialize: String = this.toYaml.prettyPrint -} - -abstract class ClkModType { - def serialize: String -} -case object ClkMux extends ClkModType { - def serialize: String = "mux" -} -case object ClkDiv extends ClkModType { - def serialize: String = "div" -} -case object ClkGen extends ClkModType { - def serialize: String = "gen" -} - -// Unlike typical SDC, starts at 0. -// Otherwise, see pg. 63 of "Constraining Designs for Synthesis and Timing Analysis" -// by S. Gangadharan -// original clk: |-----|_____|-----|_____| -// edges: 0 1 2 3 4 -// div. by 4, 50% duty cycle --> edges = 0, 2, 4 -// ---> |-----------|___________| -// sources = source id's -case class GeneratedClk( - id: String, - sources: Seq[String] = Seq(), - referenceEdges: Seq[Int] = Seq(), - period: Option[Double] = None) { - 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!") -} - -case class ClkModAnnotation(tpe: String, generatedClks: Seq[GeneratedClk]) { - - def modType: ClkModType = HasClkAnnotation.modType(tpe) - - modType match { - case ClkDiv => - generatedClks foreach { c => - 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.period.isEmpty, "No period should be specified for clk divider output") - } - case ClkMux => - generatedClks foreach { c => - 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.sources.nonEmpty, "Clk muxes must have sources!") - } - case ClkGen => - generatedClks foreach { c => - require(c.referenceEdges.isEmpty, "Reference edges must not be defined for clk gen!") - require(c.sources.isEmpty, "Clk generators shouldn't have constrained sources") - require(c.period.nonEmpty, "Clk generator output period should be specified!") - } - } - import ClkAnnotationsYaml._ - def serialize: String = this.toYaml.prettyPrint -} - -abstract class FirrtlClkTransformAnnotation { - def targetName: String -} - -// Firrtl version -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 targetName = target.name - def modType = anno.modType - def generatedClks = anno.generatedClks - def getAllClkPorts = anno.generatedClks.map(x => - List(List(x.id), x.sources).flatten).flatten.distinct.map(Seq(targetName, _).mkString(".")) -} - -// Chisel version -case class TargetClkModAnnoC(target: Module, anno: ClkModAnnotation) extends ChiselAnnotation { - def toFirrtl = TargetClkModAnnoF(target.toNamed, anno) -} - -// Firrtl version -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 targetName = Seq(target.module.name, target.name).mkString(".") - def modId = Seq(target.module.name, anno.id).mkString(".") - def sink = anno.tag -} - -// Chisel version -case class TargetClkPortAnnoC(target: Element, anno: ClkPortAnnotation) extends ChiselAnnotation { - def toFirrtl = TargetClkPortAnnoF(target.toNamed, anno) -} - -object HasClkAnnotation { - - import ClkAnnotationsYaml._ - - def modType(tpe: String): ClkModType = tpe match { - case s: String if s == ClkMux.serialize => ClkMux - case s: String if s == ClkDiv.serialize => ClkDiv - case s: String if s == ClkGen.serialize => ClkGen - case _ => throw new Exception("Clock module annotaiton type invalid") - } - - def unapply(a: Annotation): Option[FirrtlClkTransformAnnotation] = a match { - case Annotation(f, t, s) if t == classOf[ClkSrcTransform] => f match { - case m: ModuleName => - Some(TargetClkModAnnoF(m, s.parseYaml.convertTo[ClkModAnnotation])) - case c: ComponentName => - Some(TargetClkPortAnnoF(c, s.parseYaml.convertTo[ClkPortAnnotation])) - case _ => throw new Exception("Clk source annotation only valid on module or component!") - } - case _ => None - } - - def apply(annos: Seq[Annotation]): Option[(Seq[TargetClkModAnnoF],Seq[TargetClkPortAnnoF])] = { - // Get all clk-related annotations - val clkAnnos = annos.map(x => unapply(x)).flatten - val targets = clkAnnos.map(x => x.targetName) - require(targets.distinct.length == targets.length, "Only 1 clk related annotation is allowed per component/module") - if (clkAnnos.length == 0) None - else { - val componentAnnos = clkAnnos.filter { - case TargetClkPortAnnoF(ComponentName(_, ModuleName(_, _)), _) => true - case _ => false - }.map(x => x.asInstanceOf[TargetClkPortAnnoF]) - val associatedMods = componentAnnos.map(x => x.target.module.name) - val moduleAnnos = clkAnnos.filter { - case TargetClkModAnnoF(ModuleName(m, _), _) => - require(associatedMods contains m, "Clk modules should always have clk port annotations!") - true - case _ => false - }.map(x => x.asInstanceOf[TargetClkModAnnoF]) - Some((moduleAnnos, componentAnnos)) - } - } - -} - -// Applies to both black box + normal module -trait IsClkModule { - - self: chisel3.Module => - - doNotDedup(this) - - private def extractElementNames(signal: Data): Seq[String] = { - val names = signal match { - case elt: Record => - elt.elements.map { case (key, value) => extractElementNames(value).map(x => key + "_" + x) }.toSeq.flatten - case elt: Vec[_] => - elt.zipWithIndex.map { case (elt, i) => extractElementNames(elt).map(x => i + "_" + x) }.toSeq.flatten - case elt: Element => Seq("") - case elt => throw new Exception(s"Cannot extractElementNames for type ${elt.getClass}") - } - names.map(s => s.stripSuffix("_")) - } - - // TODO: Replace! - def extractElements(signal: Data): Seq[Element] = { - signal match { - case elt: Record => - elt.elements.map { case (key, value) => extractElements(value) }.toSeq.flatten - case elt: Vec[_] => - elt.map { elt => extractElements(elt) }.toSeq.flatten - case elt: Element => Seq(elt) - case elt => throw new Exception(s"Cannot extractElements for type ${elt.getClass}") - } - } - - def getIOName(signal: Element): String = { - val possibleNames = extractElements(io).zip(extractElementNames(io)).map { - case (sig, name) if sig == signal => Some(name) - case _ => None - }.flatten - if (possibleNames.length == 1) possibleNames.head - else throw new Exception("You can only get the name of an io port!") - } - - def annotateDerivedClks(tpe: ClkModType, generatedClks: Seq[GeneratedClk]): Unit = - annotateDerivedClks(ClkModAnnotation(tpe.serialize, generatedClks)) - def annotateDerivedClks(anno: ClkModAnnotation): Unit = annotateDerivedClks(this, anno) - def annotateDerivedClks(m: Module, anno: ClkModAnnotation): Unit = - annotate(TargetClkModAnnoC(m, anno)) - - def annotateClkPort(p: Element): Unit = annotateClkPort(p, None, "") - def annotateClkPort(p: Element, sink: Sink): Unit = annotateClkPort(p, Some(sink), "") - def annotateClkPort(p: Element, id: String): Unit = annotateClkPort(p, None, id) - def annotateClkPort(p: Element, sink: Sink, id: String): Unit = annotateClkPort(p, Some(sink), id) - 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 - val newId = id match { - case "" => - getIOName(p) - case _ => id - } - annotateClkPort(p, ClkPortAnnotation(sink, newId)) - } - - def annotateClkPort(p: Element, anno: ClkPortAnnotation): Unit = { - DataMirror.directionOf(p) match { - case chisel3.core.ActualDirection.Input => - require(anno.tag.nonEmpty, "Module inputs must be clk sinks") - require(anno.tag.get.src.isEmpty, - "Clock module (not top) input clks should not have clk period, etc. specified") - case chisel3.core.ActualDirection.Output => - require(anno.tag.isEmpty, "Module outputs must not be clk sinks (they're sources!)") - case _ => - throw new Exception("Clk port direction must be specified!") - } - p match { - case _: chisel3.core.Clock => - case _ => throw new Exception("Clock port must be of type Clock") - } - annotate(TargetClkPortAnnoC(p, anno)) - } -} diff --git a/tapeout/src/main/scala/transforms/.clkgen/ClkDivider.scala b/tapeout/src/main/scala/transforms/.clkgen/ClkDivider.scala deleted file mode 100644 index 23402982..00000000 --- a/tapeout/src/main/scala/transforms/.clkgen/ClkDivider.scala +++ /dev/null @@ -1,130 +0,0 @@ -package barstools.tapeout.transforms.clkgen - -import chisel3.experimental.{withClockAndReset, withClock, withReset} -import chisel3._ -import barstools.tapeout.transforms._ -import chisel3.util.HasBlackBoxInline - -// WARNING: ONLY WORKS WITH VERILATOR B/C YOU NEED ASYNC RESET! - -class SEClkDividerIO(phases: Seq[Int]) extends Bundle { - val reset = Input(Bool()) - val inClk = Input(Clock()) - val outClks = Output(CustomIndexedBundle(Clock(), phases)) - override def cloneType = (new SEClkDividerIO(phases)).asInstanceOf[this.type] -} - -class SEClkDividerBB(phases: Seq[Int], f: String) extends BlackBox with HasBlackBoxInline { - val verilog = scala.io.Source.fromFile(f).getLines.mkString("\n") - // names without io - val io = IO(new SEClkDividerIO(phases)) - val modName = this.getClass.getSimpleName - require(verilog contains modName, "Clk divider Verilog module must be named ClkDividerBB") - io.elements foreach { case (field, elt) => - require(verilog contains field, s"Verilog file should contain io ${field}")} - setInline(s"${modName}.v", verilog) -} - -class AsyncRegInit extends BlackBox with HasBlackBoxInline { - val io = IO(new Bundle { - val clk = Input(Clock()) - val reset = Input(Bool()) - val init = Input(Bool()) - val in = Input(Bool()) - val out = Output(Bool()) - }) - - setInline("AsyncRegInit.v", - s""" - |module AsyncRegInit( - | input clk, - | input reset, - | input init, - | input in, - | output reg out - |); - | always @ (posedge clk or posedge reset) begin - | if (reset) begin - | out <= init; - | end else begin - | out <= in; - | end - | end - |endmodule - """.stripMargin) -} - -object AsyncRegInit { - def apply(clk: Clock, reset: Bool, init: Bool): AsyncRegInit = { - val asyncRegInit = Module(new AsyncRegInit) - asyncRegInit.io.clk := clk - asyncRegInit.io.reset := reset - asyncRegInit.io.init := init - asyncRegInit - } -} - -// TODO: Convert analogFile into implicit? -// If syncReset = false, it's implied that reset is strobed before any clk rising edge happens -// i.e. when this is a clkgen fed by another clkgen --> need to adjust the indexing b/c -// you're already shifting on the first clk rising edge -class SEClkDivider(divBy: Int, phases: Seq[Int], analogFile: String = "", syncReset: Boolean = true) - extends Module with IsClkModule { - - require(phases.distinct.length == phases.length, "Phases should be distinct!") - phases foreach { p => - require(p < divBy, "Phases must be < divBy") - } - - val io = IO(new SEClkDividerIO(phases)) - - annotateClkPort(io.inClk, Sink()) - - val referenceEdges = phases.map(p => Seq(2 * p, 2 * (p + 1), 2 * (p + divBy))) - - val generatedClks = io.outClks.elements.zip(referenceEdges).map { case ((field, eltx), edges) => - val elt = eltx.asInstanceOf[Element] - annotateClkPort(elt) - GeneratedClk(getIOName(elt), sources = Seq(getIOName(io.inClk)), edges) - }.toSeq - - annotateDerivedClks(ClkDiv, generatedClks) - - require(divBy >= 1, "Clk division factor must be >= 1") - - divBy match { - case i: Int if i == 1 => - require(phases == Seq(0), "Clk division by 1 shouldn't generate new phases") - io.outClks(0) := io.inClk - case i: Int if i > 1 && analogFile == "" => - // Shift register based clock divider (duty cycle is NOT 50%) - val initVals = Seq(true.B) ++ Seq.fill(divBy - 1)(false.B) - - /************ Real design assumes asnyc reset!!! - withClockAndReset(io.inClk, io.reset) { - val regs = initVals.map(i => RegInit(i)) - // Close the loop - regs.head := regs.last - // Shift register - regs.tail.zip(regs.init) foreach { case (lhs, rhs) => lhs := rhs } - // Assign register output to correct clk out - phases foreach { idx => io.outClks(idx) := regs(idx).asClock } - } - *************/ - - val regs = initVals.map(i => AsyncRegInit(io.inClk, io.reset, i)) - regs.head.io.in := regs.last.io.out - regs.tail.zip(regs.init) foreach { case (lhs, rhs) => lhs.io.in := rhs.io.out } - phases foreach { idx => - val regIdx = if (syncReset) idx else (idx + 1) % divBy - io.outClks(idx) := regs(regIdx).io.out.asClock - } - - case _ => - if (new java.io.File(analogFile).exists) { - val bb = Module(new SEClkDividerBB(phases, analogFile)) - io <> bb.io - } - else throw new Exception("Clock divider Verilog file invalid!") - } -} diff --git a/tapeout/src/main/scala/transforms/.clkgen/ClkSrcTransform.scala b/tapeout/src/main/scala/transforms/.clkgen/ClkSrcTransform.scala deleted file mode 100644 index 0f5dc571..00000000 --- a/tapeout/src/main/scala/transforms/.clkgen/ClkSrcTransform.scala +++ /dev/null @@ -1,34 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms.clkgen - -import firrtl._ -import firrtl.passes._ - -import scala.collection.mutable - -class ClkSrcTransform extends Transform with SeqTransformBased { - - override def inputForm: CircuitForm = LowForm - override def outputForm: CircuitForm = LowForm - - val transformList = new mutable.ArrayBuffer[Transform] - def transforms = transformList - - override def execute(state: CircuitState): CircuitState = { - val collectedAnnos = HasClkAnnotation(getMyAnnotations(state)) - collectedAnnos match { - // Transform not used - case None => CircuitState(state.circuit, LowForm) - case Some((clkModAnnos, clkPortAnnos)) => - val targetDir = barstools.tapeout.transforms.GetTargetDir(state) - - transformList ++= Seq( - // InferTypes, - new CreateClkConstraints(clkModAnnos, clkPortAnnos, targetDir) - ) - val ret = runTransforms(state) - CircuitState(ret.circuit, outputForm, ret.annotations, ret.renames) - } - } -} diff --git a/tapeout/src/main/scala/transforms/.clkgen/CreateClkConstraints.scala b/tapeout/src/main/scala/transforms/.clkgen/CreateClkConstraints.scala deleted file mode 100644 index 6975eb73..00000000 --- a/tapeout/src/main/scala/transforms/.clkgen/CreateClkConstraints.scala +++ /dev/null @@ -1,152 +0,0 @@ -// See license file for details - -package barstools.tapeout.transforms.clkgen - -import firrtl.passes.clocklist._ -import firrtl.annotations._ -import firrtl.ir._ -import firrtl.Utils._ -import barstools.tapeout.transforms._ -import scala.collection.immutable.ListMap - -// TODO: Really should be moved out of memlib -import firrtl.passes.memlib.AnalysisUtils._ -import firrtl.passes._ - -// TODO: Wait until Albert merges into firrtl -import firrtl.analyses._ - -class CreateClkConstraints( - clkModAnnos: Seq[TargetClkModAnnoF], - clkPortAnnos: Seq[TargetClkPortAnnoF], - targetDir: String) extends Pass { - - // TODO: Are annotations only valid on ports? - - def run(c: Circuit): Circuit = { -/* - val top = c.main - - // Remove everything from the circuit, unless it has a clock type - // This simplifies the circuit drastically so InlineInstances doesn't take forever. - val onlyClockCircuit = RemoveAllButClocks.run(c) - - val instanceGraph = new InstanceGraph(onlyClockCircuit) - - val clkModNames = clkModAnnos.map(x => x.targetName) - // ** Module name -> Absolute path of (unique) instance - val clkMods = clkModNames.map { x => - // NoDeDup was run so only 1 instance of each module should exist - val inst = instanceGraph.findInstancesInHierarchy(x) - require(inst.length == 1, "Clk modules should have not ben dedup-ed") - // Return map of module name to absolute path as a string - // Note: absolute path doesn't contain top module + to work with inlineInstances, - // delimit with $ - x -> inst.head.tail.map(y => y.name).mkString("$") - }.toMap - - val clkPortIds = clkPortAnnos.map { a => a.modId } - require(clkPortIds.distinct.length == clkPortIds.length, "All clk port IDs must be unique!") - - val allModClkPorts = clkModAnnos.map { x => - val modClkPorts = x.getAllClkPorts - require(modClkPorts.intersect(clkPortIds).length == modClkPorts.length, - "Clks given relationships via clk modules must have been annotated as clk ports") - modClkPorts - }.flatten.distinct - - val clkPortMap = clkPortIds.zip(clkPortAnnos).toMap - val clkModMap = clkModNames.zip(clkModAnnos).toMap - - val (clkSinksTemp, clkSrcsTemp) = clkPortAnnos.partition { - case TargetClkPortAnnoF(_, ClkPortAnnotation(tag, _)) if tag.nonEmpty => true - case _ => false - } - - def convertClkPortAnnoToMap(annos: Seq[TargetClkPortAnnoF]): ListMap[String, String] = - ListMap(annos.map { x => - val target = x.target - val absPath = { - if (top == target.module.name) LowerName(target.name) - else Seq(clkMods(target.module.name), LowerName(target.name)).mkString(".") - } - x.modId -> absPath - }.sortBy(_._1): _*) - - // ** clk port -> absolute path - val clkSinks = convertClkPortAnnoToMap(clkSinksTemp) - val clkSrcs = convertClkPortAnnoToMap(clkSrcsTemp) - - clkSrcs foreach { case (id, path) => - require(allModClkPorts contains id, "All clock source properties must be defined by their respective modules") } - - // Don't inline clock modules - val modulesToInline = (c.modules.collect { - case Module(_, n, _, _) if n != top && !clkModNames.contains(n) => - ModuleName(n, CircuitName(top)) - }).toSet - - val inlineTransform = new InlineInstances - val inlinedCircuit = inlineTransform.run(onlyClockCircuit, modulesToInline, Set(), None).circuit - - val topModule = inlinedCircuit.modules.find(_.name == top).getOrElse(throwInternalError) - - // Build a hashmap of connections to use for getOrigins - val connects = getConnects(topModule) - - // Clk sinks are either inputs to clock modules or top clk inputs --> separate - // ** clk port -> absolute path - val (topClks, clkModSinks) = clkSinks.partition { - case (modId, absPath) if modId.split("\\.").head == top => true - case _ => false - } - - // Must be 1:1 originally! - def flipMapping(m: ListMap[String, String]): ListMap[String, String] = - m.map { case (a, b) => b -> a } - - val clkSrcsFlip = flipMapping(clkSrcs) - val topClksFlip = flipMapping(topClks) - - // Find origins of clk mod sinks - val clkModSinkToSourceMap = clkModSinks.map { case (sinkId, sinkAbsPath) => - val sourceAbsPath = getOrigin(connects, sinkAbsPath).serialize - val sourceId = { - // sources of sinks are generated clks or top level clk inputs - if (clkSrcsFlip.contains(sourceAbsPath)) clkSrcsFlip(sourceAbsPath) - else if (topClksFlip.contains(sourceAbsPath)) topClksFlip(sourceAbsPath) - else throw new Exception(s"Absolute path $sourceAbsPath of clk source for $sinkId not found!") - } - sinkId -> sourceId - } - - c.modules.foreach { - case mod: DefModule => - mod.ports.foreach { - case Port(_, n, dir, tpe) - if tpe == ClockType && - ((dir == Input && mod.name == top) || (dir == Output && clkModNames.contains(mod.name))) => - clkPortAnnos.find(x => - // TODO: Not sufficiently general for output clks? Might have forgotten to label a clk module... - LowerName(x.target.name) == n && x.target.module.name == mod.name).getOrElse( - throw new Exception( - s"All top module input clks/clk module output clocks must be sinks/sources! $n not annotated!")) - case _ => - } - } - - // Find sinks used to derive clk mod sources - val clkModSourceToSinkMap: Seq[(String, Seq[String])] = clkModAnnos.map(x => { - val modName = x.targetName - x.generatedClks.map(y => Seq(modName, y.id).mkString(".") -> y.sources.map(z => Seq(modName, z).mkString("."))) - } ).flatten - - topClks.foreach {x => println(s"top clk: $x")} - clkModSinks.foreach { x => println(s"clk sink: $x")} - clkSrcs.foreach { x => println(s"gen clk: $x")} - clkModSinkToSourceMap.foreach { x => println(s"sink -> src: $x")} - clkModSourceToSinkMap.foreach { x => println(s"src -> dependent sinks: $x")} -*/ - c - } -} \ No newline at end of file diff --git a/tapeout/src/main/scala/transforms/.pads/ChiselTopModule.scala b/tapeout/src/main/scala/transforms/.pads/ChiselTopModule.scala index 36979ce5..a348ff72 100644 --- a/tapeout/src/main/scala/transforms/.pads/ChiselTopModule.scala +++ b/tapeout/src/main/scala/transforms/.pads/ChiselTopModule.scala @@ -1,9 +1,11 @@ +// See LICENSE for license details. + package barstools.tapeout.transforms.pads import chisel3._ -import barstools.tapeout.transforms.clkgen._ import chisel3.experimental._ -import firrtl.transforms.DedupModules +import firrtl.Transform +import firrtl.annotations.Annotation // TODO: Move out of pads @@ -20,29 +22,12 @@ abstract class TopModule( coreHeight: Int = 0, usePads: Boolean = true, override_clock: Option[Clock] = None, - override_reset: Option[Bool] = None) extends Module with IsClkModule { + override_reset: Option[Bool] = None) extends Module { override_clock.foreach(clock := _) override_reset.foreach(reset := _) - override def annotateClkPort(p: Element, anno: ClkPortAnnotation): Unit = { - DataMirror.directionOf(p) match { - case chisel3.core.ActualDirection.Input => - require(anno.tag.nonEmpty, "Top Module input clks must be clk sinks") - require(anno.tag.get.src.nonEmpty, - "Top module input clks must have clk period, etc. specified") - case _ => - throw new Exception("Clk port direction must be specified!") - } - p match { - case _: chisel3.core.Clock => - case _ => throw new Exception("Clock port must be of type Clock") - } - annotate(TargetClkPortAnnoC(p, anno)) - } - - override def annotateDerivedClks(m: Module, anno: ClkModAnnotation): Unit = - throw new Exception("Top module cannot be pure clock module!") + private val mySelf = this // Annotate module as top module (that requires pad transform) // Specify the yaml file that indicates how pads are templated, @@ -55,7 +40,38 @@ abstract class TopModule( coreHeight = coreHeight, supplyAnnos = supplyAnnos ) - annotate(TargetModulePadAnnoC(this, modulePadAnnotation)) + //TODO: PORT-1.4: Remove commented code + // annotate(TargetModulePadAnnoC(this, modulePadAnnotation)) + annotate(new ChiselAnnotation with RunFirrtlTransform { + override def toFirrtl: Annotation = { + TargetModulePadAnnoF(mySelf.toNamed, modulePadAnnotation) + } + def transformClass: Class[_ <: Transform] = classOf[AddIOPadsTransform] + }) + } + + private def extractElementNames(signal: Data): Seq[String] = { + val names = signal match { + case elt: Record => + elt.elements.map { case (key, value) => extractElementNames(value).map(x => key + "_" + x) }.toSeq.flatten + case elt: Vec[_] => + elt.zipWithIndex.map { case (elt, i) => extractElementNames(elt).map(x => i + "_" + x) }.toSeq.flatten + case elt: Element => Seq("") + case elt => throw new Exception(s"Cannot extractElementNames for type ${elt.getClass}") + } + names.map(s => s.stripSuffix("_")) + } + + // TODO: Replace! + def extractElements(signal: Data): Seq[Element] = { + signal match { + case elt: Record => + elt.elements.map { case (key, value) => extractElements(value) }.toSeq.flatten + case elt: Vec[_] => + elt.map { elt => extractElements(elt) }.toSeq.flatten + case elt: Element => Seq(elt) + case elt => throw new Exception(s"Cannot extractElements for type ${elt.getClass}") + } } // Annotate IO with side + pad name diff --git a/tapeout/src/main/scala/transforms/.pads/PadAnnotations.scala b/tapeout/src/main/scala/transforms/.pads/PadAnnotations.scala index ed870092..c1f2d783 100644 --- a/tapeout/src/main/scala/transforms/.pads/PadAnnotations.scala +++ b/tapeout/src/main/scala/transforms/.pads/PadAnnotations.scala @@ -1,10 +1,10 @@ +// See LICENSE for license details. + package barstools.tapeout.transforms.pads import firrtl.annotations._ import chisel3.experimental._ import chisel3._ -import barstools.tapeout.transforms._ -import firrtl._ import net.jcazevedo.moultingyaml._ @@ -23,26 +23,32 @@ abstract class FirrtlPadTransformAnnotation { abstract class IOAnnotation { def serialize: String } + case class IOPadAnnotation(padSide: String, padName: String) extends IOAnnotation { import PadAnnotationsYaml._ def serialize: String = this.toYaml.prettyPrint def getPadSide: PadSide = HasPadAnnotation.getSide(padSide) } + case class NoIOPadAnnotation(noPad: String = "") extends IOAnnotation { import PadAnnotationsYaml._ def serialize: String = this.toYaml.prettyPrint - def field = "noPad:" + def field: String = "noPad:" } + // Firrtl version -case class TargetIOPadAnnoF(target: ComponentName, anno: IOAnnotation) extends FirrtlPadTransformAnnotation with SingleTargetAnnotation[ComponentName] { +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 targetName = target.name + def targetName: String = target.name } + +//TODO: PORT-1.4: Remove commented code // Chisel version -case class TargetIOPadAnnoC(target: Element, anno: IOAnnotation) extends ChiselAnnotation { - def toFirrtl = TargetIOPadAnnoF(target.toNamed, anno) -} +//case class TargetIOPadAnnoC(target: Element, anno: IOAnnotation) extends ChiselAnnotation { +// 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 case class SupplyAnnotation( @@ -51,6 +57,7 @@ case class SupplyAnnotation( rightSide: Int = 0, topSide: Int = 0, bottomSide: Int = 0) + // The chip top should have a default pad side, a pad template file, and supply annotations case class ModulePadAnnotation( defaultPadSide: String = Top.serialize, @@ -63,17 +70,16 @@ case class ModulePadAnnotation( require(supplyPadNames.distinct.length == supplyPadNames.length, "Supply pads should only be specified once!") def getDefaultPadSide: PadSide = HasPadAnnotation.getSide(defaultPadSide) } + // Firrtl version -case class TargetModulePadAnnoF(target: ModuleName, anno: ModulePadAnnotation) extends FirrtlPadTransformAnnotation with SingleTargetAnnotation[ModuleName] { +case class TargetModulePadAnnoF(target: ModuleName, anno: ModulePadAnnotation) + extends FirrtlPadTransformAnnotation with SingleTargetAnnotation[ModuleName] { + def duplicate(n: ModuleName): TargetModulePadAnnoF = this.copy(target = n) - def getAnno = Annotation(target, classOf[AddIOPadsTransform], anno.serialize) - def targetName = target.name -} -// Chisel version -case class TargetModulePadAnnoC(target: Module, anno: ModulePadAnnotation) extends ChiselAnnotation { - def toFirrtl = TargetModulePadAnnoF(target.toNamed, anno) + def targetName: String = target.name } + case class CollectedAnnos( componentAnnos: Seq[TargetIOPadAnnoF], moduleAnnos: TargetModulePadAnnoF) { @@ -95,16 +101,34 @@ object HasPadAnnotation { case _ => throw new Exception(s" $a not a valid pad side annotation!") } + //TODO: PORT-1.4: Remove commented code +// def unapply(a: Annotation): Option[FirrtlPadTransformAnnotation] = a match { +// case Annotation(f, t, s) if t == classOf[AddIOPadsTransform] => f match { +// case m: ModuleName => +// Some(TargetModulePadAnnoF(m, s.parseYaml.convertTo[ModulePadAnnotation])) +// case c: ComponentName if s.contains(NoIOPadAnnotation().field) => +// Some(TargetIOPadAnnoF(c, s.parseYaml.convertTo[NoIOPadAnnotation])) +// case c: ComponentName => +// Some(TargetIOPadAnnoF(c, s.parseYaml.convertTo[IOPadAnnotation])) +// case _ => throw new Exception("Annotation only valid on module or component") +// } +// case _ => None +// } + + //scalastyle:off cyclomatic.complexity def unapply(a: Annotation): Option[FirrtlPadTransformAnnotation] = a match { - case Annotation(f, t, s) if t == classOf[AddIOPadsTransform] => f match { - case m: ModuleName => - Some(TargetModulePadAnnoF(m, s.parseYaml.convertTo[ModulePadAnnotation])) - case c: ComponentName if s.contains(NoIOPadAnnotation().field) => - Some(TargetIOPadAnnoF(c, s.parseYaml.convertTo[NoIOPadAnnotation])) - case c: ComponentName => - Some(TargetIOPadAnnoF(c, s.parseYaml.convertTo[IOPadAnnotation])) - case _ => throw new Exception("Annotation only valid on module or component") - } + case hasTransform: RunFirrtlTransform if hasTransform.transformClass == classOf[AddIOPadsTransform] => + hasTransform match { + case hasTarget: SingleTargetAnnotation[_] => + hasTarget.target match { + case m: ModuleName => + Some(TargetModulePadAnnoF(m, s.parseYaml.convertTo[ModulePadAnnotation])) + hasTarget match { + case _ => None + } + + + } case _ => None } @@ -113,8 +137,9 @@ object HasPadAnnotation { val padAnnos = annos.map(x => unapply(x)).flatten val targets = padAnnos.map(x => x.targetName) require(targets.distinct.length == targets.length, "Only 1 pad related annotation is allowed per component/module") - if (padAnnos.length == 0) None - else { + if (padAnnos.length == 0) { + None + } else { val moduleAnnosTemp = padAnnos.filter { case TargetModulePadAnnoF(_, _) => true case _ => false diff --git a/tapeout/src/test/scala/transforms/.clkgen/ClkGenSpec.scala b/tapeout/src/test/scala/transforms/.clkgen/ClkGenSpec.scala deleted file mode 100644 index 17ae1c76..00000000 --- a/tapeout/src/test/scala/transforms/.clkgen/ClkGenSpec.scala +++ /dev/null @@ -1,181 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms.clkgen - -import chisel3._ -import firrtl._ -import org.scalatest.{FlatSpec, Matchers} -import chisel3.experimental._ -import chisel3.iotesters._ -import chisel3.util.HasBlackBoxInline -import barstools.tapeout.transforms.pads.TopModule - -// Purely to see that clk src tagging works with BBs -class FakeBBClk extends BlackBox with HasBlackBoxInline with IsClkModule { - val io = IO(new Bundle { - val inClk = Input(Clock()) - val outClk = Output(Vec(3, Clock())) - }) - - annotateClkPort(io.inClk, Sink()) - val generatedClks = io.outClk.map { case elt => - val id = getIOName(elt) - val srcId = getIOName(io.inClk) - annotateClkPort(elt.asInstanceOf[Element]) - GeneratedClk(id, Seq(srcId), Seq(0, 1, 2)) - }.toSeq - - annotateDerivedClks(ClkDiv, generatedClks) - - // Generates a "FakeBB.v" file with the following Verilog module - setInline("FakeBBClk.v", - s""" - |module FakeBBClk( - | input inClk, - | output outClk_0, - | output outClk_1, - | output outClk_2 - |); - | always @* begin - | outClk_0 = inClk; - | outClk_1 = inClk; - | outClk_2 = inClk; - | end - |endmodule - """.stripMargin) -} - -class ModWithNestedClkIO(numPhases: Int) extends Bundle { - val inClk = Input(Clock()) - val bbOutClk = Output(Vec(3, Clock())) - val clkDivOut = Output(Vec(numPhases, Clock())) -} - -class TestModWithNestedClkIO(numPhases: Int) extends Bundle { - val bbOutClk = Output(Vec(3, Bool())) - val clkDivOut = Output(Vec(numPhases, Bool())) -} - -class ModWithNestedClk(divBy: Int, phases: Seq[Int], syncReset: Boolean) extends Module { - - val io = IO(new ModWithNestedClkIO(phases.length)) - - val bb = Module(new FakeBBClk) - bb.io.inClk := io.inClk - io.bbOutClk := bb.io.outClk - val clkDiv = Module(new SEClkDivider(divBy, phases, syncReset = syncReset)) - clkDiv.io.reset := reset - clkDiv.io.inClk := io.inClk - phases.zipWithIndex.foreach { case (phase, idx) => io.clkDivOut(idx) := clkDiv.io.outClks(phase) } - -} - -class TopModuleWithClks(val divBy: Int, val phases: Seq[Int]) extends TopModule(usePads = false) { - val io = IO(new Bundle { - val gen1 = new TestModWithNestedClkIO(phases.length) - val gen2 = new TestModWithNestedClkIO(phases.length) - val gen3 = new TestModWithNestedClkIO(phases.length) - val fakeClk1 = Input(Clock()) - val fakeClk2 = Input(Clock()) - }) - - // TODO: Don't have to type Some - annotateClkPort(clock, - id = "clock", // not in io bundle - sink = Sink(Some(ClkSrc(period = 5.0, async = Seq(getIOName(io.fakeClk1))))) - ) - annotateClkPort(io.fakeClk1, Sink(Some(ClkSrc(period = 4.0)))) - annotateClkPort(io.fakeClk2, Sink(Some(ClkSrc(period = 3.0)))) - - // Most complicated: test chain of clock generators - val gen1 = Module(new ModWithNestedClk(divBy, phases, syncReset = true)) - io.gen1.bbOutClk := Vec(gen1.io.bbOutClk.map(x => x.asUInt)) - io.gen1.clkDivOut := Vec(gen1.io.clkDivOut.map(x => x.asUInt)) - gen1.io.inClk := clock - // ClkDiv on generated clk -> reset occurs before first input clk edge - val gen2 = Module(new ModWithNestedClk(divBy, phases, syncReset = false)) - io.gen2.bbOutClk := Vec(gen2.io.bbOutClk.map(x => x.asUInt)) - io.gen2.clkDivOut := Vec(gen2.io.clkDivOut.map(x => x.asUInt)) - gen2.io.inClk := gen1.io.clkDivOut.last - val gen3 = Module(new ModWithNestedClk(divBy, phases, syncReset = false)) - io.gen3.bbOutClk := Vec(gen3.io.bbOutClk.map(x => x.asUInt)) - io.gen3.clkDivOut := Vec(gen3.io.clkDivOut.map(x => x.asUInt)) - gen3.io.inClk := gen1.io.clkDivOut.last -} - -class TopModuleWithClksTester(c: TopModuleWithClks) extends PeekPokeTester(c) { - val maxT = c.divBy * c.divBy * 4 - val numSubClkOutputs = c.io.gen1.clkDivOut.length - val gen1Out = Seq.fill(numSubClkOutputs)(scala.collection.mutable.ArrayBuffer[Int]()) - val gen2Out = Seq.fill(numSubClkOutputs)(scala.collection.mutable.ArrayBuffer[Int]()) - val gen3Out = Seq.fill(numSubClkOutputs)(scala.collection.mutable.ArrayBuffer[Int]()) - reset(10) - for (t <- 0 until maxT) { - for (k <- 0 until numSubClkOutputs) { - gen1Out(k) += peek(c.io.gen1.clkDivOut(k)).intValue - gen2Out(k) += peek(c.io.gen2.clkDivOut(k)).intValue - gen3Out(k) += peek(c.io.gen3.clkDivOut(k)).intValue - } - step(1) - } - - val clkCounts = (0 until maxT) - val clkCountsModDiv = clkCounts.map(_ % c.divBy) - for (k <- 0 until numSubClkOutputs) { - val expected = clkCountsModDiv.map(x => if (x == c.phases(k)) 1 else 0) - expect(gen1Out(k) == expected, s"gen1Out($k) incorrect!") - println(s"gen1Out($k): \t${gen1Out(k).mkString("")}") - } - - val gen1ClkCounts = (0 until maxT/c.divBy).map(i => Seq.fill(c.divBy)(i)).flatten - val gen1ClkCountsModDiv = gen1ClkCounts.map(_ % c.divBy) - - for (k <- 0 until numSubClkOutputs) { - // Handle initial transient - val fillVal = if (c.phases.last == c.divBy - 1 && k == numSubClkOutputs - 1) 1 else 0 - val expected = Seq.fill(c.phases.last)(fillVal) ++ - gen1ClkCountsModDiv.map(x => if (x == c.phases(k)) 1 else 0).dropRight(c.phases.last) - expect(gen2Out(k) == expected, s"gen1Out($k) incorrect!") - println(s"gen2Out($k): \t${gen2Out(k).mkString("")}") - println(s"expected: \t${expected.mkString("")}") - } - - expect(gen2Out == gen3Out, "gen2Out should equal gen3Out") - -} - -class ClkGenSpec extends FlatSpec with Matchers { - - def readOutputFile(dir: String, f: String): String = - scala.io.Source.fromFile(Seq(dir, f).mkString("/")).getLines.mkString("\n") - def readResource(resource: String): String = { - val stream = getClass.getResourceAsStream(resource) - scala.io.Source.fromInputStream(stream).mkString - } - - def checkOutputs(dir: String) = { - } - - behavior of "top module with clk gens" - - it should "pass simple testbench" in { - val optionsManager = new TesterOptionsManager { - firrtlOptions = firrtlOptions.copy( - compilerName = "verilog" - /*annotations = List(passes.clocklist.ClockListAnnotation( - s"-c:TopModuleWithClks:-m:TopModuleWithClks:-o:test.clk" - )), - customTransforms = Seq(new passes.clocklist.ClockListTransform())*/ - ) - testerOptions = testerOptions.copy(isVerbose = false, backendName = "verilator", displayBase = 10) - commonOptions = commonOptions.copy(targetDirName = "test_run_dir/ClkTB") - } - // WARNING: TB requires that phase divBy - 1 should be at the end of the Seq to be OK during initial transient - iotesters.Driver.execute(() => new TopModuleWithClks(4, Seq(0, 1, 3)), optionsManager) { c => - val dir = optionsManager.commonOptions.targetDirName - checkOutputs(dir) - new TopModuleWithClksTester(c) - } should be (true) - } - -} \ No newline at end of file From 67de39e9579867574734de154ae1672d27976ee5 Mon Sep 17 00:00:00 2001 From: chick Date: Fri, 11 Sep 2020 17:06:19 -0700 Subject: [PATCH 2/8] Refactor tapeout for Chisel 3.4, Firrtl 1.4 - Remove clk package based on discussion with Colin - Annotations need to be refactored to using latest API - Generally that involves making annos generated by a anonymous ChiselAnnotation - The chisel annotations will use RunFirrtlTransform to queue up its associated transform - Chisel annotation provieds toFirrtl to generate Firrtl form of annotation - Usages of unapply on firrtl annotations cannot use generic unapply(target, transform, data) which has been eliminated - Have transforms use with DependencyAPIMigration to avoid deprecated `form`s - Added some 'see License comments - TechnologyLocation section of AddIOPadsSpec does not currently run because there is no content for it. - Added some tests for annotation serialization here --- .../transforms/.pads/AddIOPadsTransform.scala | 9 +- .../transforms/.pads/ChiselTopModule.scala | 18 +- .../transforms/.pads/FoundryPadsYaml.scala | 7 +- .../transforms/.pads/PadAnnotations.scala | 56 ++--- .../transforms/AddSuffixToModuleNames.scala | 5 +- .../scala/transforms/EnumerateModules.scala | 8 +- .../src/main/scala/transforms/Generate.scala | 9 +- .../main/scala/transforms/ResetInverter.scala | 26 +-- .../main/scala/transforms/retime/Retime.scala | 28 +-- .../scala/transforms/utils/FileUtils.scala | 45 ++-- .../transforms/.pads/AddIOPadsSpec.scala | 203 +++++++++++------- .../scala/transforms/ResetInverterSpec.scala | 25 +-- .../scala/transforms/retime/RetimeSpec.scala | 54 +++-- 13 files changed, 275 insertions(+), 218 deletions(-) diff --git a/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala b/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala index b586e8be..1d12adb8 100644 --- a/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala +++ b/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala @@ -3,24 +3,19 @@ package barstools.tapeout.transforms.pads import firrtl._ -import firrtl.annotations._ import firrtl.passes._ -import firrtl.ir._ import barstools.tapeout.transforms._ import scala.collection.mutable // Main Add IO Pad transform operates on low Firrtl -class AddIOPadsTransform extends Transform with SeqTransformBased { - - override def inputForm: CircuitForm = LowForm - override def outputForm: CircuitForm = LowForm +class AddIOPadsTransform extends Transform with SeqTransformBased with DependencyAPIMigration { val transformList = new mutable.ArrayBuffer[Transform] def transforms: Seq[Transform] = transformList override def execute(state: CircuitState): CircuitState = { - val collectedAnnos = HasPadAnnotation(getMyAnnotations(state)) + val collectedAnnos = HasPadAnnotation(state.annotations) collectedAnnos match { // Transform not used case None => state diff --git a/tapeout/src/main/scala/transforms/.pads/ChiselTopModule.scala b/tapeout/src/main/scala/transforms/.pads/ChiselTopModule.scala index a348ff72..5b2ed28a 100644 --- a/tapeout/src/main/scala/transforms/.pads/ChiselTopModule.scala +++ b/tapeout/src/main/scala/transforms/.pads/ChiselTopModule.scala @@ -77,7 +77,12 @@ abstract class TopModule( // Annotate IO with side + pad name def annotatePad(sig: Element, side: PadSide = defaultPadSide, name: String = ""): Unit = if (usePads) { val anno = IOPadAnnotation(side.serialize, name) - annotate(TargetIOPadAnnoC(sig, anno)) + annotate(new ChiselAnnotation with RunFirrtlTransform { + override def toFirrtl: Annotation = { + TargetIOPadAnnoF(sig.toTarget, anno) + } + def transformClass: Class[_ <: Transform] = classOf[AddIOPadsTransform] + }) } def annotatePad(sig: Aggregate, name: String): Unit = annotatePad(sig, side = defaultPadSide, name) def annotatePad(sig: Aggregate, side: PadSide): Unit = annotatePad(sig, side, name = "") @@ -86,7 +91,16 @@ abstract class TopModule( // 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! - def noPad(sig: Element): Unit = if (usePads) annotate(TargetIOPadAnnoC(sig, NoIOPadAnnotation())) + def noPad(sig: Element): Unit = { + if (usePads) { + annotate(new ChiselAnnotation with RunFirrtlTransform { + override def toFirrtl: Annotation = { + TargetIOPadAnnoF(sig.toTarget, NoIOPadAnnotation()) + } + def transformClass: Class[_ <: Transform] = classOf[AddIOPadsTransform] + }) + } + } 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 diff --git a/tapeout/src/main/scala/transforms/.pads/FoundryPadsYaml.scala b/tapeout/src/main/scala/transforms/.pads/FoundryPadsYaml.scala index 2d372a51..ef6fdde7 100644 --- a/tapeout/src/main/scala/transforms/.pads/FoundryPadsYaml.scala +++ b/tapeout/src/main/scala/transforms/.pads/FoundryPadsYaml.scala @@ -1,3 +1,5 @@ +// See LICENSE for license details. + package barstools.tapeout.transforms.pads import net.jcazevedo.moultingyaml._ @@ -85,8 +87,9 @@ object FoundryPadsYaml extends DefaultYamlProtocol { implicit val _pad = yamlFormat6(FoundryPad) def parse(techDir: String): Seq[FoundryPad] = { val file = techDir + exampleResource - if(techDir != "" && !(new java.io.File(file)).exists()) - throw new Exception("Technology directory must contain FoundryPads.yaml!") + if(techDir != "" && !(new java.io.File(file)).exists()) { + throw new Exception(s"Technology directory $techDir must contain FoundryPads.yaml!") + } val out = (new YamlFileReader(exampleResource)).parse[FoundryPad](if (techDir == "") "" else file) val padNames = out.map(x => x.correctedName) require(padNames.distinct.length == padNames.length, "Pad names must be unique!") diff --git a/tapeout/src/main/scala/transforms/.pads/PadAnnotations.scala b/tapeout/src/main/scala/transforms/.pads/PadAnnotations.scala index c1f2d783..7ca49799 100644 --- a/tapeout/src/main/scala/transforms/.pads/PadAnnotations.scala +++ b/tapeout/src/main/scala/transforms/.pads/PadAnnotations.scala @@ -3,9 +3,6 @@ package barstools.tapeout.transforms.pads import firrtl.annotations._ -import chisel3.experimental._ -import chisel3._ - import net.jcazevedo.moultingyaml._ object PadAnnotationsYaml extends DefaultYamlProtocol { @@ -13,6 +10,17 @@ object PadAnnotationsYaml extends DefaultYamlProtocol { implicit val _noiopad = yamlFormat1(NoIOPadAnnotation) implicit val _supplyanno = yamlFormat5(SupplyAnnotation) implicit val _modulepadanno = yamlFormat4(ModulePadAnnotation) + + // Putting these serialize methods here seems to fix warnings about missing implicits for the toYaml + def serialize(noIOPad: NoIOPadAnnotation): String = { + noIOPad.toYaml.prettyPrint + } + def serialize(ioPadAnnotation: IOPadAnnotation): String = { + ioPadAnnotation.toYaml.prettyPrint + } + def serialize(modulePadAnnotation: ModulePadAnnotation): String = { + modulePadAnnotation.toYaml.prettyPrint + } } abstract class FirrtlPadTransformAnnotation { @@ -25,14 +33,12 @@ abstract class IOAnnotation { } case class IOPadAnnotation(padSide: String, padName: String) extends IOAnnotation { - import PadAnnotationsYaml._ - def serialize: String = this.toYaml.prettyPrint + def serialize: String = PadAnnotationsYaml.serialize(this) def getPadSide: PadSide = HasPadAnnotation.getSide(padSide) } case class NoIOPadAnnotation(noPad: String = "") extends IOAnnotation { - import PadAnnotationsYaml._ - def serialize: String = this.toYaml.prettyPrint + def serialize: String = PadAnnotationsYaml.serialize(this) def field: String = "noPad:" } @@ -44,12 +50,6 @@ case class TargetIOPadAnnoF(target: ComponentName, anno: IOAnnotation) def targetName: String = target.name } -//TODO: PORT-1.4: Remove commented code -// Chisel version -//case class TargetIOPadAnnoC(target: Element, anno: IOAnnotation) extends ChiselAnnotation { -// 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 case class SupplyAnnotation( padName: String, @@ -64,9 +64,9 @@ case class ModulePadAnnotation( coreWidth: Int = 0, coreHeight: Int = 0, supplyAnnos: Seq[SupplyAnnotation] = Seq.empty) { - import PadAnnotationsYaml._ - def serialize: String = this.toYaml.prettyPrint - val supplyPadNames = supplyAnnos.map(_.padName) + + def serialize: String = PadAnnotationsYaml.serialize(this) + def supplyPadNames: Seq[String] = supplyAnnos.map(_.padName) require(supplyPadNames.distinct.length == supplyPadNames.length, "Supply pads should only be specified once!") def getDefaultPadSide: PadSide = HasPadAnnotation.getSide(defaultPadSide) } @@ -91,7 +91,6 @@ case class CollectedAnnos( } object HasPadAnnotation { - import PadAnnotationsYaml._ def getSide(a: String): PadSide = a match { case i if i == Left.serialize => Left @@ -115,26 +114,13 @@ object HasPadAnnotation { // case _ => None // } - //scalastyle:off cyclomatic.complexity - def unapply(a: Annotation): Option[FirrtlPadTransformAnnotation] = a match { - case hasTransform: RunFirrtlTransform if hasTransform.transformClass == classOf[AddIOPadsTransform] => - hasTransform match { - case hasTarget: SingleTargetAnnotation[_] => - hasTarget.target match { - case m: ModuleName => - Some(TargetModulePadAnnoF(m, s.parseYaml.convertTo[ModulePadAnnotation])) - hasTarget match { - case _ => None - } - - - } - case _ => None - } - def apply(annos: Seq[Annotation]): Option[CollectedAnnos] = { // Get all pad-related annotations (config files, pad sides, pad names, etc.) - val padAnnos = annos.map(x => unapply(x)).flatten + val padAnnos = annos.flatMap { + case a: TargetModulePadAnnoF => Some(a) + case a: TargetIOPadAnnoF => Some(a) + case _ => None + } val targets = padAnnos.map(x => x.targetName) require(targets.distinct.length == targets.length, "Only 1 pad related annotation is allowed per component/module") if (padAnnos.length == 0) { diff --git a/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala b/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala index 0e1a3739..ff8c1857 100644 --- a/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala +++ b/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala @@ -7,7 +7,6 @@ import firrtl.ir._ import firrtl.annotations._ import firrtl.Mappers._ - case class KeepNameAnnotation(target: ModuleTarget) extends SingleTargetAnnotation[ModuleTarget] { def duplicate(n: ModuleTarget) = this.copy(n) @@ -22,9 +21,7 @@ case class ModuleNameSuffixAnnotation(target: CircuitTarget, suffix: String) // Verilog black box and therefore can't be renamed. Since the point is to // allow FIRRTL to be linked together using "cat" and ExtModules don't get // emitted, this should be safe. -class AddSuffixToModuleNames extends Transform { - def inputForm = LowForm - def outputForm = LowForm +class AddSuffixToModuleNames extends Transform with DependencyAPIMigration { def processAnnos(annos: AnnotationSeq): (AnnotationSeq, (String) => String) = { val whitelist = annos.collect({ case KeepNameAnnotation(tgt) => tgt.module }).toSet diff --git a/tapeout/src/main/scala/transforms/EnumerateModules.scala b/tapeout/src/main/scala/transforms/EnumerateModules.scala index 11da911e..4bd2855f 100644 --- a/tapeout/src/main/scala/transforms/EnumerateModules.scala +++ b/tapeout/src/main/scala/transforms/EnumerateModules.scala @@ -20,10 +20,10 @@ class EnumerateModulesPass(enumerate: (Module) => Unit) extends Pass { } } -class EnumerateModules(enumerate: (Module) => Unit) extends Transform with SeqTransformBased { - def inputForm = LowForm - def outputForm = LowForm - def transforms = Seq(new EnumerateModulesPass(enumerate)) +class EnumerateModules(enumerate: (Module) => Unit) + extends Transform with SeqTransformBased with DependencyAPIMigration { + + def transforms: Seq[Transform] = Seq(new EnumerateModulesPass(enumerate)) def execute(state: CircuitState): CircuitState = { val ret = runTransforms(state) diff --git a/tapeout/src/main/scala/transforms/Generate.scala b/tapeout/src/main/scala/transforms/Generate.scala index 89df8b55..b48f47e1 100644 --- a/tapeout/src/main/scala/transforms/Generate.scala +++ b/tapeout/src/main/scala/transforms/Generate.scala @@ -1,16 +1,11 @@ package barstools.tapeout.transforms import firrtl._ -import firrtl.ir._ import firrtl.annotations._ -import firrtl.stage.FirrtlCircuitAnnotation -import firrtl.passes.Pass - -import java.io.File -import firrtl.annotations.AnnotationYamlProtocol._ +import firrtl.ir._ import firrtl.passes.memlib.ReplSeqMemAnnotation +import firrtl.stage.FirrtlCircuitAnnotation import firrtl.transforms.BlackBoxResourceFileNameAnno -import net.jcazevedo.moultingyaml._ import logger.LazyLogging trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions => diff --git a/tapeout/src/main/scala/transforms/ResetInverter.scala b/tapeout/src/main/scala/transforms/ResetInverter.scala index 08d84983..e6bdad45 100644 --- a/tapeout/src/main/scala/transforms/ResetInverter.scala +++ b/tapeout/src/main/scala/transforms/ResetInverter.scala @@ -2,19 +2,15 @@ package barstools.tapeout.transforms -import chisel3.internal.InstanceId +import chisel3.experimental.RunFirrtlTransform import firrtl.PrimOps.Not -import firrtl.annotations.{Annotation, CircuitName, ModuleName, Named} -import firrtl.ir.{Input, UIntType, IntWidth, Module, Port, DefNode, NoInfo, Reference, DoPrim, Block, Circuit} +import firrtl.annotations.{Annotation, CircuitName, ModuleName, SingleTargetAnnotation} +import firrtl.ir._ import firrtl.passes.Pass -import firrtl.{CircuitForm, CircuitState, LowForm, Transform} +import firrtl.{CircuitState, DependencyAPIMigration, Transform} -object ResetInverterAnnotation { - def apply(target: ModuleName): Annotation = Annotation(target, classOf[ResetInverterTransform], "invert") - def unapply(a: Annotation): Option[Named] = a match { - case Annotation(m, t, "invert") if t == classOf[ResetInverterTransform] => Some(m) - case _ => None - } +case class ResetInverterAnnotation(target: ModuleName) extends SingleTargetAnnotation[ModuleName] { + override def duplicate(n: ModuleName): Annotation = ResetInverterAnnotation(n) } object ResetN extends Pass { @@ -42,12 +38,9 @@ object ResetN extends Pass { } } -class ResetInverterTransform extends Transform { - override def inputForm: CircuitForm = LowForm - override def outputForm: CircuitForm = LowForm - +class ResetInverterTransform extends Transform with DependencyAPIMigration { override def execute(state: CircuitState): CircuitState = { - getMyAnnotations(state) match { + state.annotations.filter(_.isInstanceOf[ResetInverterAnnotation]) match { case Nil => state case Seq(ResetInverterAnnotation(ModuleName(state.circuit.main, CircuitName(_)))) => state.copy(circuit = ResetN.run(state.circuit)) @@ -60,7 +53,8 @@ class ResetInverterTransform extends Transform { trait ResetInverter { self: chisel3.Module => def invert[T <: chisel3.internal.LegacyModule](module: T): Unit = { - chisel3.experimental.annotate(new chisel3.experimental.ChiselAnnotation{ + chisel3.experimental.annotate(new chisel3.experimental.ChiselAnnotation with RunFirrtlTransform { + def transformClass: Class[_ <: Transform] = classOf[ResetInverterTransform] def toFirrtl: Annotation = ResetInverterAnnotation(module.toNamed) }) } diff --git a/tapeout/src/main/scala/transforms/retime/Retime.scala b/tapeout/src/main/scala/transforms/retime/Retime.scala index 231687bf..f790f7b3 100644 --- a/tapeout/src/main/scala/transforms/retime/Retime.scala +++ b/tapeout/src/main/scala/transforms/retime/Retime.scala @@ -2,27 +2,17 @@ package barstools.tapeout.transforms.retime -import chisel3.internal.InstanceId -import firrtl.PrimOps.Not -import firrtl.annotations.{Annotation, CircuitName, ModuleName, Named, ComponentName} -import firrtl.ir.{Input, UIntType, IntWidth, Module, Port, DefNode, NoInfo, Reference, DoPrim, Block, Circuit} -import firrtl.passes.Pass -import firrtl.{CircuitForm, CircuitState, LowForm, Transform} +import chisel3.experimental.RunFirrtlTransform +import firrtl.annotations._ +import firrtl.{CircuitState, DependencyAPIMigration, Transform} -object RetimeAnnotation { - def apply(target: ModuleName): Annotation = Annotation(target, classOf[RetimeTransform], "retime") - def unapply(a: Annotation): Option[Named] = a match { - case Annotation(m, t, "retime") if t == classOf[RetimeTransform] => Some(m) - case _ => None - } +case class RetimeAnnotation(target: Named) extends SingleTargetAnnotation[Named] { + override def duplicate(n: Named): Annotation = RetimeAnnotation(n) } -class RetimeTransform extends Transform { - override def inputForm: CircuitForm = LowForm - override def outputForm: CircuitForm = LowForm - +class RetimeTransform extends Transform with DependencyAPIMigration { override def execute(state: CircuitState): CircuitState = { - getMyAnnotations(state) match { + state.annotations.filter(_.isInstanceOf[RetimeAnnotation]) match { case Nil => state case seq => seq.foreach { case RetimeAnnotation(ModuleName(module, CircuitName(_))) => @@ -39,8 +29,10 @@ class RetimeTransform extends Transform { trait RetimeLib { self: chisel3.Module => + def retime[T <: chisel3.internal.LegacyModule](module: T): Unit = { - chisel3.experimental.annotate(new chisel3.experimental.ChiselAnnotation{ + chisel3.experimental.annotate(new chisel3.experimental.ChiselAnnotation with RunFirrtlTransform { + def transformClass: Class[_ <: Transform] = classOf[RetimeTransform] def toFirrtl: Annotation = RetimeAnnotation(module.toNamed) }) } diff --git a/tapeout/src/main/scala/transforms/utils/FileUtils.scala b/tapeout/src/main/scala/transforms/utils/FileUtils.scala index 7baf3e14..76ee45ec 100644 --- a/tapeout/src/main/scala/transforms/utils/FileUtils.scala +++ b/tapeout/src/main/scala/transforms/utils/FileUtils.scala @@ -1,9 +1,11 @@ +// See LICENSE for license details. + package barstools.tapeout.transforms +import chisel3.experimental.{ChiselAnnotation, annotate} import firrtl._ import firrtl.annotations._ -import firrtl.passes._ -import firrtl.ir._ +import firrtl.transforms.BlackBoxTargetDirAnno object WriteConfig { def apply(dir: String, file: String, contents: String): Unit = { @@ -17,8 +19,7 @@ object GetTargetDir { def apply(state: CircuitState): String = { val annos = state.annotations val destDir = annos.map { - case Annotation(f, t, s) if t == classOf[firrtl.transforms.BlackBoxTargetDirAnno] => - Some(s) + case BlackBoxTargetDirAnno(s) => Some(s) case _ => None }.flatten val loc = { @@ -31,27 +32,39 @@ object GetTargetDir { } } -// Fake transform just to track Technology information directory -object TechnologyLocation { - def apply(dir: String): Annotation = { - Annotation(CircuitName("All"), classOf[TechnologyLocation], dir) +trait HasSetTechnologyLocation { + self: chisel3.Module => + + def setTechnologyLocation(dir: String) { + annotate(new ChiselAnnotation { + override def toFirrtl: Annotation = { + TechnologyLocationAnnotation(dir) + } + }) } } -class TechnologyLocation extends Transform { - def inputForm: CircuitForm = LowForm - def outputForm: CircuitForm = LowForm - def execute(state: CircuitState) = throw new Exception("Technology Location transform execution doesn't work!") + +case class TechnologyLocationAnnotation(dir: String) extends SingleTargetAnnotation[CircuitName] { + val target: CircuitName = CircuitName("All") + override def duplicate(n: CircuitName): Annotation = TechnologyLocationAnnotation(dir) +} + +class TechnologyLocation extends Transform with DependencyAPIMigration { + def execute(state: CircuitState): CircuitState = { + throw new Exception("Technology Location transform execution doesn't work!") + } + def get(state: CircuitState): String = { val annos = state.annotations - val dir = annos.map { - case Annotation(f, t, s) if t == classOf[TechnologyLocation] => Some(s) + val dir = annos.flatMap { + case TechnologyLocationAnnotation(dir) => Some(dir) case _ => None - }.flatten + } dir.length match { case 0 => "" case 1 => val targetDir = new java.io.File(dir.head) - if(!targetDir.exists()) throw new Exception("Technology yaml directory doesn't exist!") + if(!targetDir.exists()) throw new Exception(s"Technology yaml directory $targetDir doesn't exist!") dir.head case _ => throw new Exception("Only 1 tech directory annotation allowed!") } diff --git a/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala b/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala index b578be97..43889539 100644 --- a/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala +++ b/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala @@ -2,64 +2,74 @@ package barstools.tapeout.transforms.pads +import java.io.File + +import barstools.tapeout.transforms.HasSetTechnologyLocation import chisel3._ +import chisel3.experimental._ +import chisel3.iotesters._ +import chisel3.util.HasBlackBoxInline import firrtl._ import org.scalatest.{FlatSpec, Matchers} -import chisel3.experimental._ -import chisel3.util.HasBlackBoxInline -import chisel3.iotesters._ class BB extends BlackBox with HasBlackBoxInline { val io = IO(new Bundle { val c = Input(SInt(14.W)) val z = Output(SInt(16.W)) val analog1 = Analog(3.W) - val analog2 = analog1.chiselCloneType + val analog2 = Analog(3.W) }) // Generates a "FakeBB.v" file with the following Verilog module - setInline("FakeBB.v", + setInline( + "FakeBB.v", s""" - |module BB( - | input [15:0] c, - | output [15:0] z, - | inout [2:0] analog1, - | inout [2:0] analog2 - |); - | always @* begin - | z = 2 * c; - | analog2 = analog1 + 1; - | end - |endmodule - """.stripMargin) + |module BB( + | input [15:0] c, + | output [15:0] z, + | inout [2:0] analog1, + | inout [2:0] analog2 + |); + | always @* begin + | z = 2 * c; + | analog2 = analog1 + 1; + | end + |endmodule + """.stripMargin + ) } // If no template file is provided, it'll use the default one (example) in the resource folder // Default pad side is Top if no side is specified for a given IO // You can designate the number of different supply pads on each chip side -class ExampleTopModuleWithBB extends TopModule( - supplyAnnos = Seq( - SupplyAnnotation(padName = "vdd", leftSide = 3, bottomSide = 2), - SupplyAnnotation(padName = "vss", rightSide = 1) - )) { +class ExampleTopModuleWithBB + extends TopModule( + supplyAnnos = Seq( + SupplyAnnotation(padName = "vdd", leftSide = 3, bottomSide = 2), + SupplyAnnotation(padName = "vss", rightSide = 1) + ) + ) + with HasSetTechnologyLocation { val io = IO(new Bundle { val a = Input(UInt(15.W)) - val b = a.chiselCloneType + val b = Input(a.cloneType) val c = Input(SInt(14.W)) val x = Output(UInt(16.W)) - val y = x.chiselCloneType + val y = Output(x.cloneType) val z = Output(SInt(16.W)) val analog1 = Analog(3.W) - val analog2 = analog1.chiselCloneType + val analog2 = analog1.cloneType val v = Output(Vec(3, UInt(5.W))) }) + setTechnologyLocation("./RealTech") + // Can annotate aggregates with pad side location + pad name (should be a name in the yaml template) annotatePad(io.v, Right, "from_tristate_foundry") // Can annotate individual elements annotatePad(io.analog1, Left, "fast_custom") annotatePad(io.analog2, Bottom, "slow_foundry") // Looks for a pad that matches the IO type (digital in, digital out, analog) if no name is specified - Seq(io.a, io.b, io.c, io.x) foreach { x => annotatePad(x, Left) } + Seq(io.a, io.b, io.c, io.x).foreach { x => annotatePad(x, Left) } // Some signals might not want pads associated with them noPad(io.y) // Clk might come directly from bump @@ -74,8 +84,8 @@ class ExampleTopModuleWithBB extends TopModule( io.x := io.a + 1.U io.y := io.b - 1.U - io.v foreach { lhs => lhs := io.a } - + io.v.foreach { lhs => lhs := io.a } + } class SimpleTopModuleTester(c: ExampleTopModuleWithBB) extends PeekPokeTester(c) { @@ -89,10 +99,10 @@ class SimpleTopModuleTester(c: ExampleTopModuleWithBB) extends PeekPokeTester(c) expect(c.io.x, ax(i) + 1) expect(c.io.y, bx(i) - 1) expect(c.io.z, 2 * cx(i)) - c.io.v foreach { out => expect(out, ax(i)) } + c.io.v.foreach { out => expect(out, ax(i)) } } - // Analog can't be peeked + poked -} + // Analog can't be peeked + poked +} // Notes: Annotations // a in 15: left, default digital @@ -110,7 +120,7 @@ class SimpleTopModuleTester(c: ExampleTopModuleWithBB) extends PeekPokeTester(c) // vdd, bottom: 2, group of 1 // vss, right: 1, group of 2 // Notes: Used pads -// digital horizontal (from_tristate_foundry) +// digital horizontal (from_tristate_foundry) // in + out // analog fast_custom horizontal // analog slow_foundry vertical @@ -122,72 +132,111 @@ class SimpleTopModuleTester(c: ExampleTopModuleWithBB) extends PeekPokeTester(c) class IOPadSpec extends FlatSpec with Matchers { - def readOutputFile(dir: String, f: String): String = - scala.io.Source.fromFile(Seq(dir, f).mkString("/")).getLines.mkString("\n") + def readOutputFile(dir: String, f: String): String = { + FileUtils.getText(dir + File.separator + f) + } def readResource(resource: String): String = { val stream = getClass.getResourceAsStream(resource) scala.io.Source.fromInputStream(stream).mkString } - def checkOutputs(dir: String) = { + def checkOutputs(dir: String): Unit = { // Show that black box source helper is run //readOutputFile(dir, "black_box_verilog_files.f") should include ("pad_supply_vdd_horizontal.v") val padBBEx = s"""// Digital Pad Example - |// Signal Direction: Input - |// Pad Orientation: Horizontal - |// Call your instance PAD - |module pad_digital_from_tristate_foundry_horizontal_input( - | input in, - | output reg out - |); - | // Where you would normally dump your pad instance - | always @* begin - | out = in; - | end - |endmodule - | - |module pad_digital_from_tristate_foundry_horizontal_input_array #( - | parameter int WIDTH=1 - |)( - | input [WIDTH-1:0] in, - | output reg [WIDTH-1:0] out - |); - | pad_digital_from_tristate_foundry_horizontal_input pad_digital_from_tristate_foundry_horizontal_input[WIDTH-1:0]( - | .in(in), - | .out(out) - | );""".stripMargin + |// Signal Direction: Input + |// Pad Orientation: Horizontal + |// Call your instance PAD + |module pad_digital_from_tristate_foundry_horizontal_input( + | input in, + | output reg out + |); + | // Where you would normally dump your pad instance + | always @* begin + | out = in; + | end + |endmodule + | + |module pad_digital_from_tristate_foundry_horizontal_input_array #( + | parameter int WIDTH=1 + |)( + | input [WIDTH-1:0] in, + | output reg [WIDTH-1:0] out + |); + | pad_digital_from_tristate_foundry_horizontal_input pad_digital_from_tristate_foundry_horizontal_input[WIDTH-1:0]( + | .in(in), + | .out(out) + | );""".stripMargin // Make sure black box templating is OK - readOutputFile(dir, "pad_digital_from_tristate_foundry_horizontal_input_array.v") should include (padBBEx) + readOutputFile(dir, "pad_digital_from_tristate_foundry_horizontal_input_array.v") should include(padBBEx) - val verilog = readOutputFile(dir, "ExampleTopModuleWithBB.v") + val verilog = readOutputFile(dir, "ExampleTopModuleWithBB.v") // Pad frame + top should be exact - verilog should include (readResource("/PadAnnotationVerilogPart.v")) + verilog should include(readResource("/PadAnnotationVerilogPart.v")) // Pad Placement IO file should be exact val padIO = readOutputFile(dir, "pads.io") padIO should include(readResource("/PadPlacement.io")) } - behavior of "top module with blackbox" + behavior.of("Pad Annotations") - import barstools.tapeout.transforms._ + it should "serialize pad annotations" in { + val noIOPadAnnotation = NoIOPadAnnotation("dog") + noIOPadAnnotation.serialize should include("noPad: dog") + + val ioPadAnnotation = IOPadAnnotation("left", "oliver") + ioPadAnnotation.serialize should include( + """padSide: left + |padName: oliver + |""".stripMargin) + + val modulePadAnnotation = ModulePadAnnotation( + "top", + 11, + 42, + Seq( + SupplyAnnotation("mypad, 1, 2 ,3 , 4"), + SupplyAnnotation("yourpad, 9, 8, 7, 6") + ) + ) + + modulePadAnnotation.serialize should be( + """defaultPadSide: top + |coreWidth: 11 + |coreHeight: 42 + |supplyAnnos: + |- rightSide: 0 + | padName: mypad, 1, 2 ,3 , 4 + | leftSide: 0 + | bottomSide: 0 + | topSide: 0 + |- rightSide: 0 + | padName: yourpad, 9, 8, 7, 6 + | leftSide: 0 + | bottomSide: 0 + | topSide: 0 + |""".stripMargin + ) + } + + behavior.of("top module with blackbox") it should "pass simple testbench" in { val optionsManager = new TesterOptionsManager { firrtlOptions = firrtlOptions.copy( compilerName = "verilog" - // annotations = List(TechnologyLocation("./RealTech")) ) testerOptions = testerOptions.copy(isVerbose = true, backendName = "verilator", displayBase = 10) commonOptions = commonOptions.copy(targetDirName = "test_run_dir/PadsTB") } iotesters.Driver.execute(() => new ExampleTopModuleWithBB, optionsManager) { c => val dir = optionsManager.commonOptions.targetDirName - checkOutputs(dir) + checkOutputs(dir) new SimpleTopModuleTester(c) - } should be (true) + } should be(true) } -/* + /* it should "create proper IO pads + black box in low firrtl" in { val optionsManager = new ExecutionOptionsManager("barstools") with HasChiselExecutionOptions with HasFirrtlOptions { firrtlOptions = firrtlOptions.copy(compilerName = "low") @@ -196,15 +245,15 @@ class IOPadSpec extends FlatSpec with Matchers { } val success = chisel3.Driver.execute(optionsManager, () => new ExampleTopModuleWithBB) match { case ChiselExecutionSuccess(_, chirrtl, Some(FirrtlExecutionSuccess(_, firrtl))) => - firrtl should include ("ExampleTopModuleWithBB_PadFrame") + firrtl should include ("ExampleTopModuleWithBB_PadFrame") firrtl should include ("ExampleTopModuleWithBB_Internal") - firrtl should not include ("FakeBBPlaceholder") + firrtl should not include ("FakeBBPlaceholder") true case _ => false - } + } success should be (true) - } -*/ + } + */ it should "create proper IO pads + black box in verilog" in { val optionsManager = new ExecutionOptionsManager("barstools") with HasChiselExecutionOptions with HasFirrtlOptions { firrtlOptions = firrtlOptions.copy( @@ -214,13 +263,13 @@ class IOPadSpec extends FlatSpec with Matchers { //commonOptions = commonOptions.copy(globalLogLevel = logger.LogLevel.Info) } val success = chisel3.Driver.execute(optionsManager, () => new ExampleTopModuleWithBB) match { - case ChiselExecutionSuccess(_, chirrtl, Some(FirrtlExecutionSuccess(_, verilog))) => + case ChiselExecutionSuccess(_, chirrtl, Some(FirrtlExecutionSuccess(_, verilog))) => true case _ => false - } - success should be (true) + } + success should be(true) val dir = optionsManager.commonOptions.targetDirName checkOutputs(dir) - } + } -} \ No newline at end of file +} diff --git a/tapeout/src/test/scala/transforms/ResetInverterSpec.scala b/tapeout/src/test/scala/transforms/ResetInverterSpec.scala index 07fca302..4b5de967 100644 --- a/tapeout/src/test/scala/transforms/ResetInverterSpec.scala +++ b/tapeout/src/test/scala/transforms/ResetInverterSpec.scala @@ -3,7 +3,7 @@ package barstools.tapeout.transforms import chisel3._ -import firrtl._ +import chisel3.stage.ChiselStage import org.scalatest.{FreeSpec, Matchers} class ExampleModuleNeedsResetInverted extends Module with ResetInverter { @@ -19,22 +19,15 @@ class ExampleModuleNeedsResetInverted extends Module with ResetInverter { } class ResetNSpec extends FreeSpec with Matchers { - "Inverting reset needs to be done throughout module" in { - val optionsManager = new ExecutionOptionsManager("dsptools") with HasChiselExecutionOptions with HasFirrtlOptions { - firrtlOptions = firrtlOptions.copy(compilerName = "low", customTransforms = List(new ResetInverterTransform)), - } - chisel3.Driver.execute(optionsManager, () => new ExampleModuleNeedsResetInverted) match { - case ChiselExecutionSuccess(_, chirrtl, Some(FirrtlExecutionSuccess(_, firrtl))) => - chirrtl should include ("input reset :") - chirrtl should not include "input reset_n :" - chirrtl should not include "node reset = not(reset_n)" + val chirrtl = (new ChiselStage).emitChirrtl(new ExampleModuleNeedsResetInverted, Array()) + chirrtl should include("input reset :") + (chirrtl should not).include("input reset_n :") + (chirrtl should not).include("node reset = not(reset_n)") - firrtl should include ("input reset_n :") - firrtl should include ("node reset = not(reset_n)") - firrtl should not include "input reset :" - case _ => - // bad - } + val firrtl = (new ChiselStage).emitFirrtl(new ExampleModuleNeedsResetInverted, Array("-X", "low")) + firrtl should include("input reset_n :") + firrtl should include("node reset = not(reset_n)") + (firrtl should not).include("input reset :") } } diff --git a/tapeout/src/test/scala/transforms/retime/RetimeSpec.scala b/tapeout/src/test/scala/transforms/retime/RetimeSpec.scala index 76223b71..1f2de5a8 100644 --- a/tapeout/src/test/scala/transforms/retime/RetimeSpec.scala +++ b/tapeout/src/test/scala/transforms/retime/RetimeSpec.scala @@ -2,13 +2,12 @@ package barstools.tapeout.transforms.retime.test -import chisel3._ -import firrtl._ -import org.scalatest.{FlatSpec, Matchers} -import chisel3.experimental._ -import chisel3.util.HasBlackBoxInline -import chisel3.iotesters._ import barstools.tapeout.transforms.retime._ +import chisel3._ +import chisel3.stage.ChiselStage +import firrtl._ +import logger.Logger +import org.scalatest.{FlatSpec, Matchers} class RetimeSpec extends FlatSpec with Matchers { def normalized(s: String): String = { @@ -25,20 +24,47 @@ class RetimeSpec extends FlatSpec with Matchers { it should "pass simple retime module annotation" in { val gen = () => new RetimeModule() val dir = uniqueDirName(gen, "RetimeModule") - chisel3.Driver.execute(Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final"), gen) shouldBe a [ChiselExecutionSuccess] - val lines = io.Source.fromFile(s"test_run_dir/$dir/test_run_dir/$dir/final.anno.json").getLines().map(normalized).mkString("\n") - lines should include("barstools.tapeout.transforms.retime.RetimeTransform") + Logger.makeScope(Seq.empty) { + val captor = new Logger.OutputCaptor + Logger.setOutput(captor.printStream) + val firrtl = (new ChiselStage).emitFirrtl( + new RetimeModule(), + Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final", "--log-level", "info") + ) + firrtl.nonEmpty should be(true) + //Make sure we got the RetimeTransform scheduled + captor.getOutputAsString should include ("barstools.tapeout.transforms.retime.RetimeTransform") + } + + val lines = FileUtils.getLines(s"test_run_dir/$dir/test_run_dir/$dir/final.anno.json") + .map(normalized) + .mkString("\n") + lines should include("barstools.tapeout.transforms.retime.RetimeAnnotation") + lines should include(""""target":"RetimeModule.RetimeModule"""") } - // TODO(azidar): need to fix/add instance annotations - ignore should "pass simple retime instance annotation" in { + it should "pass simple retime instance annotation" in { val gen = () => new RetimeInstance() val dir = uniqueDirName(gen, "RetimeInstance") - chisel3.Driver.execute(Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final.anno"), gen) shouldBe a [ChiselExecutionSuccess] - val lines = io.Source.fromFile(s"test_run_dir/$dir/final.anno").getLines().map(normalized).toSeq - lines should contain ("Annotation(ComponentName(instance, ModuleName(RetimeInstance,CircuitName(RetimeInstance))),class barstools.tapeout.transforms.retime.RetimeTransform,retime)") + Logger.makeScope(Seq.empty) { + val captor = new Logger.OutputCaptor + Logger.setOutput(captor.printStream) + val firrtl = (new ChiselStage).emitFirrtl( + new RetimeInstance(), + Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final", "--log-level", "info") + ) + firrtl.nonEmpty should be(true) + //Make sure we got the RetimeTransform scheduled + captor.getOutputAsString should include ("barstools.tapeout.transforms.retime.RetimeTransform") + } + + val lines = FileUtils.getLines(s"test_run_dir/$dir/test_run_dir/$dir/final.anno.json") + .map(normalized) + .mkString("\n") + lines should include("barstools.tapeout.transforms.retime.RetimeAnnotation") + lines should include(""""target":"RetimeInstance.MyModule"""") } } From d06d8cc16ce1132867359774bb2fb30d4ab676e3 Mon Sep 17 00:00:00 2001 From: chick Date: Mon, 14 Sep 2020 09:32:18 -0700 Subject: [PATCH 3/8] - FoundryPadsYaml would not parse yaml - Made separate case class for data - Now parses - Fails later with UnknownType in firrt compiler - Fixed similar parsing problem with PadPlacement --- .../transforms/.pads/FoundryPadsYaml.scala | 63 ++++++++++++++----- .../transforms/.pads/AddIOPadsSpec.scala | 20 ++---- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/tapeout/src/main/scala/transforms/.pads/FoundryPadsYaml.scala b/tapeout/src/main/scala/transforms/.pads/FoundryPadsYaml.scala index ef6fdde7..ce19a6d7 100644 --- a/tapeout/src/main/scala/transforms/.pads/FoundryPadsYaml.scala +++ b/tapeout/src/main/scala/transforms/.pads/FoundryPadsYaml.scala @@ -8,13 +8,32 @@ import firrtl._ import firrtl.ir._ import barstools.tapeout.transforms._ +trait HasFoundryPadFields { + val tpe: String + val name: String + val width: Int + val height: Int + val supplySetNum: Option[Int] + val verilog: String +} + +case class FoundryPadFields( + tpe: String, + name: String, + width: Int, + height: Int, + supplySetNum: Option[Int], + verilog: String) + extends HasFoundryPadFields + case class FoundryPad( - tpe: String, - name: String, - width: Int, - height: Int, - supplySetNum: Option[Int], - verilog: String) { + tpe: String, + name: String, + width: Int, + height: Int, + supplySetNum: Option[Int], + verilog: String) + extends HasFoundryPadFields { def padInstName = "PAD" @@ -38,8 +57,10 @@ case class FoundryPad( // Supply pads don't have IO require(!verilog.contains("{{#if isInput}}"), "Supply pad template must not contain '{{#if isInput}}'") require( - verilog.contains(s"${padInstName}["), "All supply pad templates should have instance arrays" + - " called ${padInstName}[n:0], where n = ${getSupplySetNum-1}") + verilog.contains(s"${padInstName}["), + "All supply pad templates should have instance arrays" + + " called ${padInstName}[n:0], where n = ${getSupplySetNum-1}" + ) require(supplySetNum.nonEmpty, "# of grouped supply pads 'supplySetNum' should be specified!") SupplyPad case _ => throw new Exception("Illegal pad type in config!") @@ -53,14 +74,14 @@ case class FoundryPad( private[barstools] val correctedName = name.replace(" ", "_") case class TemplateParams( - // isInput only used with digital pads - isInput: Boolean, - isHorizontal: Boolean) { + // isInput only used with digital pads + isInput: Boolean, + isHorizontal: Boolean) { private val orient = if (isHorizontal) Horizontal.serialize else Vertical.serialize private val dir = padType match { - case AnalogPad => "inout" - case SupplyPad => "none" + case AnalogPad => "inout" + case SupplyPad => "none" case DigitalPad => if (isInput) Input.serialize else Output.serialize } val name = { @@ -84,13 +105,23 @@ case class FoundryPad( object FoundryPadsYaml extends DefaultYamlProtocol { val exampleResource = "/FoundryPads.yaml" - implicit val _pad = yamlFormat6(FoundryPad) + implicit val _pad = yamlFormat6(FoundryPadFields) def parse(techDir: String): Seq[FoundryPad] = { val file = techDir + exampleResource - if(techDir != "" && !(new java.io.File(file)).exists()) { + if (techDir != "" && !(new java.io.File(file)).exists()) { throw new Exception(s"Technology directory $techDir must contain FoundryPads.yaml!") } - val out = (new YamlFileReader(exampleResource)).parse[FoundryPad](if (techDir == "") "" else file) + val fieldsArray = (new YamlFileReader(exampleResource)).parse[FoundryPadFields](if (techDir == "") "" else file) + val out = fieldsArray.map { fields => + FoundryPad( + tpe = fields.tpe, + name = fields.name, + width = fields.width, + height = fields.height, + supplySetNum = fields.supplySetNum, + verilog = fields.verilog + ) + } val padNames = out.map(x => x.correctedName) require(padNames.distinct.length == padNames.length, "Pad names must be unique!") out diff --git a/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala b/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala index 43889539..7fe42342 100644 --- a/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala +++ b/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala @@ -8,6 +8,7 @@ import barstools.tapeout.transforms.HasSetTechnologyLocation import chisel3._ import chisel3.experimental._ import chisel3.iotesters._ +import chisel3.stage.ChiselStage import chisel3.util.HasBlackBoxInline import firrtl._ import org.scalatest.{FlatSpec, Matchers} @@ -255,20 +256,11 @@ class IOPadSpec extends FlatSpec with Matchers { } */ it should "create proper IO pads + black box in verilog" in { - val optionsManager = new ExecutionOptionsManager("barstools") with HasChiselExecutionOptions with HasFirrtlOptions { - firrtlOptions = firrtlOptions.copy( - compilerName = "verilog" - ) - commonOptions = commonOptions.copy(targetDirName = "test_run_dir/PadsVerilog") - //commonOptions = commonOptions.copy(globalLogLevel = logger.LogLevel.Info) - } - val success = chisel3.Driver.execute(optionsManager, () => new ExampleTopModuleWithBB) match { - case ChiselExecutionSuccess(_, chirrtl, Some(FirrtlExecutionSuccess(_, verilog))) => - true - case _ => false - } - success should be(true) - val dir = optionsManager.commonOptions.targetDirName + val dir = "test_run_dir/PadsVerilog" + (new ChiselStage).emitFirrtl( + new ExampleTopModuleWithBB, + Array("-td", dir, "-X", "verilog") + ) checkOutputs(dir) } From 0430403920144e9c4b3ccc1d8c7fe5cfeac60ebf Mon Sep 17 00:00:00 2001 From: chick Date: Mon, 28 Sep 2020 15:20:42 -0700 Subject: [PATCH 4/8] - Simplest way to make custom transforms run in same place as they did prior to Dependency API --- .../main/scala/transforms/.pads/AddIOPadsTransform.scala | 6 ++++++ .../src/main/scala/transforms/AddSuffixToModuleNames.scala | 5 +++++ tapeout/src/main/scala/transforms/EnumerateModules.scala | 5 +++++ tapeout/src/main/scala/transforms/ResetInverter.scala | 6 ++++++ tapeout/src/main/scala/transforms/retime/Retime.scala | 6 ++++++ tapeout/src/main/scala/transforms/utils/FileUtils.scala | 6 ++++++ 6 files changed, 34 insertions(+) diff --git a/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala b/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala index 1d12adb8..b79c1093 100644 --- a/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala +++ b/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala @@ -5,12 +5,18 @@ package barstools.tapeout.transforms.pads import firrtl._ import firrtl.passes._ import barstools.tapeout.transforms._ +import firrtl.options.Dependency +import firrtl.stage.Forms +import firrtl.stage.TransformManager.TransformDependency import scala.collection.mutable // Main Add IO Pad transform operates on low Firrtl class AddIOPadsTransform extends Transform with SeqTransformBased with DependencyAPIMigration { + override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters + val transformList = new mutable.ArrayBuffer[Transform] def transforms: Seq[Transform] = transformList diff --git a/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala b/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala index ff8c1857..ada3a719 100644 --- a/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala +++ b/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala @@ -6,6 +6,8 @@ import firrtl._ import firrtl.ir._ import firrtl.annotations._ import firrtl.Mappers._ +import firrtl.stage.Forms +import firrtl.stage.TransformManager.TransformDependency case class KeepNameAnnotation(target: ModuleTarget) extends SingleTargetAnnotation[ModuleTarget] { @@ -23,6 +25,9 @@ case class ModuleNameSuffixAnnotation(target: CircuitTarget, suffix: String) // emitted, this should be safe. class AddSuffixToModuleNames extends Transform with DependencyAPIMigration { + override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters + def processAnnos(annos: AnnotationSeq): (AnnotationSeq, (String) => String) = { val whitelist = annos.collect({ case KeepNameAnnotation(tgt) => tgt.module }).toSet val newAnnos = annos.filterNot(_.isInstanceOf[ModuleNameSuffixAnnotation]) diff --git a/tapeout/src/main/scala/transforms/EnumerateModules.scala b/tapeout/src/main/scala/transforms/EnumerateModules.scala index 4bd2855f..f1f66033 100644 --- a/tapeout/src/main/scala/transforms/EnumerateModules.scala +++ b/tapeout/src/main/scala/transforms/EnumerateModules.scala @@ -5,6 +5,8 @@ package barstools.tapeout.transforms import firrtl._ import firrtl.ir._ import firrtl.passes.Pass +import firrtl.stage.Forms +import firrtl.stage.TransformManager.TransformDependency class EnumerateModulesPass(enumerate: (Module) => Unit) extends Pass { @@ -23,6 +25,9 @@ class EnumerateModulesPass(enumerate: (Module) => Unit) extends Pass { class EnumerateModules(enumerate: (Module) => Unit) extends Transform with SeqTransformBased with DependencyAPIMigration { + override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters + def transforms: Seq[Transform] = Seq(new EnumerateModulesPass(enumerate)) def execute(state: CircuitState): CircuitState = { diff --git a/tapeout/src/main/scala/transforms/ResetInverter.scala b/tapeout/src/main/scala/transforms/ResetInverter.scala index e6bdad45..2cbbd45a 100644 --- a/tapeout/src/main/scala/transforms/ResetInverter.scala +++ b/tapeout/src/main/scala/transforms/ResetInverter.scala @@ -7,6 +7,8 @@ import firrtl.PrimOps.Not import firrtl.annotations.{Annotation, CircuitName, ModuleName, SingleTargetAnnotation} import firrtl.ir._ import firrtl.passes.Pass +import firrtl.stage.Forms +import firrtl.stage.TransformManager.TransformDependency import firrtl.{CircuitState, DependencyAPIMigration, Transform} case class ResetInverterAnnotation(target: ModuleName) extends SingleTargetAnnotation[ModuleName] { @@ -39,6 +41,10 @@ object ResetN extends Pass { } class ResetInverterTransform extends Transform with DependencyAPIMigration { + + override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters + override def execute(state: CircuitState): CircuitState = { state.annotations.filter(_.isInstanceOf[ResetInverterAnnotation]) match { case Nil => state diff --git a/tapeout/src/main/scala/transforms/retime/Retime.scala b/tapeout/src/main/scala/transforms/retime/Retime.scala index f790f7b3..e554bead 100644 --- a/tapeout/src/main/scala/transforms/retime/Retime.scala +++ b/tapeout/src/main/scala/transforms/retime/Retime.scala @@ -4,6 +4,8 @@ package barstools.tapeout.transforms.retime import chisel3.experimental.RunFirrtlTransform import firrtl.annotations._ +import firrtl.stage.Forms +import firrtl.stage.TransformManager.TransformDependency import firrtl.{CircuitState, DependencyAPIMigration, Transform} case class RetimeAnnotation(target: Named) extends SingleTargetAnnotation[Named] { @@ -11,6 +13,10 @@ case class RetimeAnnotation(target: Named) extends SingleTargetAnnotation[Named] } class RetimeTransform extends Transform with DependencyAPIMigration { + + override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters + override def execute(state: CircuitState): CircuitState = { state.annotations.filter(_.isInstanceOf[RetimeAnnotation]) match { case Nil => state diff --git a/tapeout/src/main/scala/transforms/utils/FileUtils.scala b/tapeout/src/main/scala/transforms/utils/FileUtils.scala index 76ee45ec..0d38d376 100644 --- a/tapeout/src/main/scala/transforms/utils/FileUtils.scala +++ b/tapeout/src/main/scala/transforms/utils/FileUtils.scala @@ -5,6 +5,8 @@ package barstools.tapeout.transforms import chisel3.experimental.{ChiselAnnotation, annotate} import firrtl._ import firrtl.annotations._ +import firrtl.stage.Forms +import firrtl.stage.TransformManager.TransformDependency import firrtl.transforms.BlackBoxTargetDirAnno object WriteConfig { @@ -50,6 +52,10 @@ case class TechnologyLocationAnnotation(dir: String) extends SingleTargetAnnotat } class TechnologyLocation extends Transform with DependencyAPIMigration { + + override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters + def execute(state: CircuitState): CircuitState = { throw new Exception("Technology Location transform execution doesn't work!") } From f51156bf1fcebc11d82a9bb357d3134652ff4f39 Mon Sep 17 00:00:00 2001 From: chick Date: Mon, 28 Sep 2020 15:34:36 -0700 Subject: [PATCH 5/8] - Fixed ResetNSpec --- tapeout/src/main/scala/transforms/ResetInverter.scala | 3 ++- tapeout/src/test/scala/transforms/ResetInverterSpec.scala | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tapeout/src/main/scala/transforms/ResetInverter.scala b/tapeout/src/main/scala/transforms/ResetInverter.scala index 2cbbd45a..22b2a704 100644 --- a/tapeout/src/main/scala/transforms/ResetInverter.scala +++ b/tapeout/src/main/scala/transforms/ResetInverter.scala @@ -24,7 +24,8 @@ object ResetN extends Pass { "Can only invert reset on a module with reset!") // Rename "reset" to "reset_n" val portsx = mod.ports map { - case Port(info, "reset", Input, Bool) => Port(info, "reset_n", Input, Bool) + case Port(info, "reset", Input, Bool) => + Port(info, "reset_n", Input, Bool) case other => other } val newReset = DefNode(NoInfo, "reset", DoPrim(Not, Seq(Reference("reset_n", Bool)), Seq.empty, Bool)) diff --git a/tapeout/src/test/scala/transforms/ResetInverterSpec.scala b/tapeout/src/test/scala/transforms/ResetInverterSpec.scala index 4b5de967..fe204288 100644 --- a/tapeout/src/test/scala/transforms/ResetInverterSpec.scala +++ b/tapeout/src/test/scala/transforms/ResetInverterSpec.scala @@ -19,13 +19,15 @@ class ExampleModuleNeedsResetInverted extends Module with ResetInverter { } class ResetNSpec extends FreeSpec with Matchers { - "Inverting reset needs to be done throughout module" in { - val chirrtl = (new ChiselStage).emitChirrtl(new ExampleModuleNeedsResetInverted, Array()) + "Inverting reset needs to be done throughout module in Chirrtl" in { + val chirrtl = (new ChiselStage).emitChirrtl(new ExampleModuleNeedsResetInverted, Array("--no-run-firrtl")) chirrtl should include("input reset :") (chirrtl should not).include("input reset_n :") (chirrtl should not).include("node reset = not(reset_n)") + } - val firrtl = (new ChiselStage).emitFirrtl(new ExampleModuleNeedsResetInverted, Array("-X", "low")) + "Inverting reset needs to be done throughout module when generating firrtl" in { + val firrtl = (new ChiselStage).emitFirrtl(new ExampleModuleNeedsResetInverted) firrtl should include("input reset_n :") firrtl should include("node reset = not(reset_n)") (firrtl should not).include("input reset :") From 1a82c082b30d930ee68dd0f5289c2ac1309e615f Mon Sep 17 00:00:00 2001 From: chick Date: Tue, 29 Sep 2020 10:11:46 -0700 Subject: [PATCH 6/8] - Make transfrorms run in as close to same order as before - Fix parsing of PadPlacement JSON --- .../transforms/.pads/AddIOPadsTransform.scala | 1 + .../scala/transforms/.pads/PadPlacement.scala | 72 +++++++++++++++---- .../transforms/AddSuffixToModuleNames.scala | 1 + .../scala/transforms/EnumerateModules.scala | 1 + .../main/scala/transforms/ResetInverter.scala | 1 + .../main/scala/transforms/retime/Retime.scala | 1 + .../scala/transforms/utils/FileUtils.scala | 1 + .../transforms/.pads/AddIOPadsSpec.scala | 5 +- 8 files changed, 66 insertions(+), 17 deletions(-) diff --git a/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala b/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala index b79c1093..ba095879 100644 --- a/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala +++ b/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala @@ -15,6 +15,7 @@ import scala.collection.mutable class AddIOPadsTransform extends Transform with SeqTransformBased with DependencyAPIMigration { override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters val transformList = new mutable.ArrayBuffer[Transform] diff --git a/tapeout/src/main/scala/transforms/.pads/PadPlacement.scala b/tapeout/src/main/scala/transforms/.pads/PadPlacement.scala index 2d774f01..d3e99626 100644 --- a/tapeout/src/main/scala/transforms/.pads/PadPlacement.scala +++ b/tapeout/src/main/scala/transforms/.pads/PadPlacement.scala @@ -1,20 +1,46 @@ +// See LICENSE for license details. + package barstools.tapeout.transforms.pads +import barstools.tapeout.transforms._ import net.jcazevedo.moultingyaml._ -import firrtl._ -import firrtl.ir._ -import barstools.tapeout.transforms._ +/** This is a hack to get around weird problem with yaml parser + * that without this gives PadPlacement defines additional fields + * + */ +trait HasPadPlacementFields { + def file: String + def left: String + def top: String + def right: String + def bottom: String + def instanceArray: String + def padLine: String + def template: String +} + +case class PadPlacementFields( + file: String, + left: String, + top: String, + right: String, + bottom: String, + instanceArray: String, + padLine: String, + template: String +) extends HasPadPlacementFields case class PadPlacement( - file: String, - left: String, - top: String, - right: String, - bottom: String, - instanceArray: String, - padLine: String, - template: String) { + file: String, + left: String, + top: String, + right: String, + bottom: String, + instanceArray: String, + padLine: String, + template: String +) extends HasPadPlacementFields { require(instanceArray contains "{{signal}}", "Instance Array Template should contain {{signal}}") require(instanceArray contains "{{idx}}", "Instance Array Template should contain {{idx}}") @@ -33,8 +59,8 @@ case class PadPlacement( case Bottom => bottom } - import com.gilt.handlebars.scala.binding.dynamic._ import com.gilt.handlebars.scala.Handlebars + import com.gilt.handlebars.scala.binding.dynamic._ private val instanceArrayTemplate = Handlebars(instanceArray.stripMargin) private val padLineTemplate = Handlebars(padLine.stripMargin) @@ -52,10 +78,26 @@ case class PadPlacementParams(leftPads: String, rightPads: String, topPads: Stri object PadPlacementFile extends DefaultYamlProtocol { val exampleResource = "/PadPlacement.yaml" - implicit val _pad = yamlFormat8(PadPlacement) - def parse(file: String = ""): PadPlacement = { - (new YamlFileReader(exampleResource)).parse[PadPlacement](file).head + implicit val _pad = yamlFormat8(PadPlacementFields) + + def main(args: Array[String]): Unit = { + println(parse("RealTech/PadPlacement.yaml")) } + + def parse(file: String = ""): PadPlacement = { + val fields = (new YamlFileReader(exampleResource)).parse[PadPlacementFields](file).head + PadPlacement( + file = fields.file, + left = fields.left, + top = fields.top, + right = fields.right, + bottom = fields.bottom, + instanceArray = fields.instanceArray, + padLine = fields.padLine, + template = fields.template + ) + } + def generate( techDir: String, targetDir: String, diff --git a/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala b/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala index ada3a719..ab1dd487 100644 --- a/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala +++ b/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala @@ -26,6 +26,7 @@ case class ModuleNameSuffixAnnotation(target: CircuitTarget, suffix: String) class AddSuffixToModuleNames extends Transform with DependencyAPIMigration { override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters def processAnnos(annos: AnnotationSeq): (AnnotationSeq, (String) => String) = { diff --git a/tapeout/src/main/scala/transforms/EnumerateModules.scala b/tapeout/src/main/scala/transforms/EnumerateModules.scala index f1f66033..a2b499fd 100644 --- a/tapeout/src/main/scala/transforms/EnumerateModules.scala +++ b/tapeout/src/main/scala/transforms/EnumerateModules.scala @@ -26,6 +26,7 @@ class EnumerateModules(enumerate: (Module) => Unit) extends Transform with SeqTransformBased with DependencyAPIMigration { override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters def transforms: Seq[Transform] = Seq(new EnumerateModulesPass(enumerate)) diff --git a/tapeout/src/main/scala/transforms/ResetInverter.scala b/tapeout/src/main/scala/transforms/ResetInverter.scala index 22b2a704..f9282251 100644 --- a/tapeout/src/main/scala/transforms/ResetInverter.scala +++ b/tapeout/src/main/scala/transforms/ResetInverter.scala @@ -44,6 +44,7 @@ object ResetN extends Pass { class ResetInverterTransform extends Transform with DependencyAPIMigration { override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters override def execute(state: CircuitState): CircuitState = { diff --git a/tapeout/src/main/scala/transforms/retime/Retime.scala b/tapeout/src/main/scala/transforms/retime/Retime.scala index e554bead..d88217c7 100644 --- a/tapeout/src/main/scala/transforms/retime/Retime.scala +++ b/tapeout/src/main/scala/transforms/retime/Retime.scala @@ -15,6 +15,7 @@ case class RetimeAnnotation(target: Named) extends SingleTargetAnnotation[Named] class RetimeTransform extends Transform with DependencyAPIMigration { override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters override def execute(state: CircuitState): CircuitState = { diff --git a/tapeout/src/main/scala/transforms/utils/FileUtils.scala b/tapeout/src/main/scala/transforms/utils/FileUtils.scala index 0d38d376..ded0474d 100644 --- a/tapeout/src/main/scala/transforms/utils/FileUtils.scala +++ b/tapeout/src/main/scala/transforms/utils/FileUtils.scala @@ -54,6 +54,7 @@ case class TechnologyLocationAnnotation(dir: String) extends SingleTargetAnnotat class TechnologyLocation extends Transform with DependencyAPIMigration { override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters def execute(state: CircuitState): CircuitState = { diff --git a/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala b/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala index 7fe42342..12fcb411 100644 --- a/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala +++ b/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala @@ -257,9 +257,10 @@ class IOPadSpec extends FlatSpec with Matchers { */ it should "create proper IO pads + black box in verilog" in { val dir = "test_run_dir/PadsVerilog" - (new ChiselStage).emitFirrtl( + (new ChiselStage).emitVerilog( new ExampleTopModuleWithBB, - Array("-td", dir, "-X", "verilog") +// Array("-td", dir, "-X", "verilog") + Array("-td", dir) ) checkOutputs(dir) } From 8903c04c2d9b084bce5ab7a5930ee2579cce46b0 Mon Sep 17 00:00:00 2001 From: chick Date: Tue, 29 Sep 2020 10:59:48 -0700 Subject: [PATCH 7/8] - fix call to `ceilLog2` in macros --- macros/src/test/scala/MacroCompilerSpec.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/macros/src/test/scala/MacroCompilerSpec.scala b/macros/src/test/scala/MacroCompilerSpec.scala index 0bc0f486..d8e0d2df 100644 --- a/macros/src/test/scala/MacroCompilerSpec.scala +++ b/macros/src/test/scala/MacroCompilerSpec.scala @@ -248,10 +248,10 @@ trait HasSimpleTestGenerator { val v = s"${generatorType}${extraTagPrefixed}.v" lazy val mem_name = "target_memory" - val mem_addr_width = ceilLog2(memDepth) + val mem_addr_width = MacroCompilerMath.ceilLog2(memDepth) lazy val lib_name = "awesome_lib_mem" - val lib_addr_width = ceilLog2(libDepth) + val lib_addr_width = MacroCompilerMath.ceilLog2(libDepth) // Override these to change the port prefixes if needed. def libPortPrefix: String = "lib" From a1dfd4f7741d8b5ff2bb4215f17af48b26cb3177 Mon Sep 17 00:00:00 2001 From: chick Date: Wed, 30 Sep 2020 15:04:56 -0700 Subject: [PATCH 8/8] Remove all of the PadStuff --- tapeout/src/main/resources/FoundryPads.yaml | 113 -------- tapeout/src/main/resources/PadPlacement.yaml | 43 --- .../transforms/.pads/AddIOPadsTransform.scala | 65 ----- .../scala/transforms/.pads/AddPadFrame.scala | 133 --------- .../transforms/.pads/AnnotatePortPads.scala | 134 --------- .../transforms/.pads/AnnotateSupplyPads.scala | 56 ---- .../transforms/.pads/ChiselTopModule.scala | 109 ------- .../scala/transforms/.pads/CreatePadBBs.scala | 109 ------- .../transforms/.pads/FoundryPadsYaml.scala | 129 --------- .../transforms/.pads/PadAnnotations.scala | 146 ---------- .../transforms/.pads/PadDescriptors.scala | 49 ---- .../scala/transforms/.pads/PadPlacement.scala | 158 ----------- tapeout/src/test/resources/PadPlacement.io | 236 --------------- .../transforms/.pads/AddIOPadsSpec.scala | 268 ------------------ 14 files changed, 1748 deletions(-) delete mode 100644 tapeout/src/main/resources/FoundryPads.yaml delete mode 100644 tapeout/src/main/resources/PadPlacement.yaml delete mode 100644 tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala delete mode 100644 tapeout/src/main/scala/transforms/.pads/AddPadFrame.scala delete mode 100644 tapeout/src/main/scala/transforms/.pads/AnnotatePortPads.scala delete mode 100644 tapeout/src/main/scala/transforms/.pads/AnnotateSupplyPads.scala delete mode 100644 tapeout/src/main/scala/transforms/.pads/ChiselTopModule.scala delete mode 100644 tapeout/src/main/scala/transforms/.pads/CreatePadBBs.scala delete mode 100644 tapeout/src/main/scala/transforms/.pads/FoundryPadsYaml.scala delete mode 100644 tapeout/src/main/scala/transforms/.pads/PadAnnotations.scala delete mode 100644 tapeout/src/main/scala/transforms/.pads/PadDescriptors.scala delete mode 100644 tapeout/src/main/scala/transforms/.pads/PadPlacement.scala delete mode 100644 tapeout/src/test/resources/PadPlacement.io delete mode 100644 tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala diff --git a/tapeout/src/main/resources/FoundryPads.yaml b/tapeout/src/main/resources/FoundryPads.yaml deleted file mode 100644 index a6133be0..00000000 --- a/tapeout/src/main/resources/FoundryPads.yaml +++ /dev/null @@ -1,113 +0,0 @@ -# Pad types must be one of digital, analog, or supply; pad names must be unique! -# This just shows you how you can template things with {{}}, if/else, and the following parameters: -# isInput: Boolean (each digital pad entry should be configurable between both input and output) -# isHorizontal: Boolean (each pad entry should be configurable between both horizontal and vertical) -# NOTE: Expects 1-bit in/out to be named in/out for digital; and 1-bit io for analog (supplies don't have ports) -# Expects module name to be obtained from {{name}} which is derived from yaml name, tpe in the Firrtl pass -# Pipe is used for stripping margins, but indentation is required before the pipe for the yaml reader to work ---- -tpe: analog -name: slow_foundry -width: 0 -height: 0 -verilog: | - |// Foundry Analog Pad Example - |// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}} - |// Call your instance PAD - |module {{name}}( - | inout io - |); - |endmodule ---- -tpe: analog -name: fast_custom -width: 0 -height: 0 -verilog: | - |// Custom Analog Pad Example - |// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}} - |// Call your instance PAD - |module {{name}}( - | inout io - |); - |endmodule ---- -tpe: digital -name: from_tristate_foundry -width: 0 -height: 0 -verilog: | - |// Digital Pad Example - |// Signal Direction: {{#if isInput}}Input{{else}}Output{{/if}} - |// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}} - |// Call your instance PAD - |module {{name}}( - | input in, - | output reg out - |); - | // Where you would normally dump your pad instance - | always @* begin - | out = in; - | end - |endmodule ---- -tpe: digital -name: fake_digital -width: 0 -height: 0 -verilog: | - |// (Fake/Unused) Digital Pad Example - |// Signal Direction: {{#if isInput}}Input{{else}}Output{{/if}} - |// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}} - |// Call your instance PAD - |module {{name}}( - | input in, - | output reg out - |); - | // Where you would normally dump your pad instance - | always @* begin - | out = in; - | end - |endmodule ---- -tpe: supply -name: vdd -width: 0 -height: 0 -supplySetNum: 1 -verilog: | - |// VDD Pad Example (No IO) - |// Can group some number together as required by the foundry - |// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}} - |// Call your instance array PAD[0:0], PAD[2:0], etc. - |module {{name}}( - |); - |endmodule ---- -tpe: supply -name: vss -width: 0 -height: 0 -supplySetNum: 2 -verilog: | - |// VSS Pad Example (No IO) - |// Can group some number together as required by the foundry - |// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}} - |// Call your instance array PAD[0:0], PAD[2:0], etc. - |module {{name}}( - |); - |endmodule ---- -tpe: supply -name: avss -width: 0 -height: 0 -supplySetNum: 1 -verilog: | - |// Analog VSS Pad Example (No IO) - |// Can group some number together as required by the foundry - |// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}} - |// Call your instance array PAD[0:0], PAD[2:0], etc. - |module {{name}}( - |); - |endmodule diff --git a/tapeout/src/main/resources/PadPlacement.yaml b/tapeout/src/main/resources/PadPlacement.yaml deleted file mode 100644 index a8a94f1c..00000000 --- a/tapeout/src/main/resources/PadPlacement.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# Example for Innovus: https://legacy.iis.ee.ethz.ch/~vlsi2/ex05/ex05.pdf ---- -file: pads.io -left: "1" # Bottom to top -top: "2" # Left to right -right: "3" # Bottom to top -bottom: "4" # Left to right -# Note: In your scripts, you should specify instance array styles -# i.e. hdl_instance_array_naming_style string (For Genus) -instanceArray: "{{signal}}[{{idx}}]" -padLine: | - | (inst name = "{{padInst}}") # Side: {{side}}, Order: {{padIdx}} -template: | - |(globals - | version = 3 - | io_order = default - |) - |(iopad - | (bottomleft - | (inst name="corner_ll" cell="CORNER_EXAMPLE" ) - | ) - | (bottomright - | (inst name="corner_lr" orientation=MY cell="CORNER_EXAMPLE" ) - | ) - | (topleft - | (inst name="corner_ul" orientation=MX cell="CORNER_EXAMPLE" ) - | ) - | (topright - | (inst name="corner_ur" cell="CORNER_EXAMPLE" ) - | ) - | (left - |{{leftPads}} - | ) - | (right - |{{rightPads}} - | ) - | (top - |{{topPads}} - | ) - | (bottom - |{{bottomPads}} - | ) - |) \ No newline at end of file diff --git a/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala b/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala deleted file mode 100644 index ba095879..00000000 --- a/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala +++ /dev/null @@ -1,65 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms.pads - -import firrtl._ -import firrtl.passes._ -import barstools.tapeout.transforms._ -import firrtl.options.Dependency -import firrtl.stage.Forms -import firrtl.stage.TransformManager.TransformDependency - -import scala.collection.mutable - -// Main Add IO Pad transform operates on low Firrtl -class AddIOPadsTransform extends Transform with SeqTransformBased with DependencyAPIMigration { - - override def prerequisites: Seq[TransformDependency] = Forms.LowForm - override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized - override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters - - val transformList = new mutable.ArrayBuffer[Transform] - def transforms: Seq[Transform] = transformList - - override def execute(state: CircuitState): CircuitState = { - val collectedAnnos = HasPadAnnotation(state.annotations) - collectedAnnos match { - // Transform not used - case None => state - case Some(x) => - val techLoc = (new TechnologyLocation).get(state) - // Get foundry pad templates from yaml - val foundryPads = FoundryPadsYaml.parse(techLoc) - val portPads = AnnotatePortPads(state.circuit, x.topModName, foundryPads, x.componentAnnos, - HasPadAnnotation.getSide(x.defaultPadSide)) - val supplyPads = AnnotateSupplyPads(foundryPads, x.supplyAnnos) - val (circuitWithBBs, bbAnnotations) = CreatePadBBs(state.circuit, portPads, supplyPads) - val namespace = Namespace(state.circuit) - val padFrameName = namespace newName s"${x.topModName}_PadFrame" - val topInternalName = namespace newName s"${x.topModName}_Internal" - val targetDir = barstools.tapeout.transforms.GetTargetDir(state) - PadPlacementFile.generate(techLoc, targetDir, padFrameName, portPads, supplyPads) - transformList ++= Seq( - Legalize, - ResolveFlows, - // Types really need to be known... - InferTypes, - new AddPadFrame(x.topModName, padFrameName, topInternalName, portPads, supplyPads), - RemoveEmpty, - CheckInitialization, - InferTypes, - Uniquify, - ResolveKinds, - ResolveFlows - ) - // Expects BlackBox helper to be run after to inline pad Verilog! - val ret = runTransforms(state) - val currentAnnos = ret.annotations - val newAnnoMap = AnnotationSeq(currentAnnos ++ bbAnnotations) - 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? - (new firrtl.transforms.BlackBoxSourceHelper).execute(newState) - } - } -} diff --git a/tapeout/src/main/scala/transforms/.pads/AddPadFrame.scala b/tapeout/src/main/scala/transforms/.pads/AddPadFrame.scala deleted file mode 100644 index 62447bd5..00000000 --- a/tapeout/src/main/scala/transforms/.pads/AddPadFrame.scala +++ /dev/null @@ -1,133 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms.pads - -import firrtl.annotations._ -import firrtl.ir._ -import firrtl._ -import firrtl.passes.Pass - -// Analog is like UInt, SInt; it's not a direction (which is kind of weird) -// WARNING: Analog type is associated with Verilog InOut! i.e. even if digital pads are tri-statable, b/c tristate -// requires an additional ctrl signal, digital pads must be operated in a single "static" condition here; Analog will -// be paired with analog pads - -class AddPadFrame( - topMod: String, - padFrameName: String, - topInternalName: String, - ioPads: Seq[PortIOPad], - supplyPads: Seq[TopSupplyPad]) extends Pass { - - def run(c: Circuit): Circuit = { - // New modules consist of old modules (with top renamed to internal) + padFrame + newTop - val newMods = c.modules.map { - case mod: Module if mod.name == topMod => - // Original top module is now internal module - mod.copy(name = topInternalName) - case m => m - } ++ Seq(buildPadFrame(), buildTopWrapper()) - - // Reparent so circuit top is whatever uses pads! - // TODO: Can the top level be a blackbox? - c.copy(modules = newMods, main = topMod) - } - - def intName(p: PortIOPad) = s"${p.portName}_Int" - def extName(p: PortIOPad) = s"${p.portName}_Ext" - - def buildTopWrapper(): Module = { - // outside -> padframe -> internal - // Top (with same name) contains 1) padframe + 2) internal signals - val padFrameInst = WDefInstance(padFrameName, padFrameName) - val topInternalInst = WDefInstance(topInternalName, topInternalName) - val padFrameRef = WRef(padFrameName) - val topInternalRef = WRef(topInternalName) - val connects = ioPads.map { p => - val io = WRef(p.portName) - val intIo = WSubField(topInternalRef, p.portName) - val padFrameIntIo = WSubField(padFrameRef, intName(p)) - val padFrameExtIo = WSubField(padFrameRef, extName(p)) - p.port.tpe match { - case AnalogType(_) => - // Analog pads only have 1 port - // If Analog port doesn't have associated pad, don't hook it up to the padframe - val analogAttachInt = Seq(Attach(NoInfo, Seq(io, intIo))) - if (p.pad.isEmpty) analogAttachInt - else analogAttachInt :+ Attach(NoInfo, Seq(io, padFrameExtIo)) - case _ => p.portDirection match { - case Input => - // input to padframe ; padframe to internal - Seq(Connect(NoInfo, padFrameExtIo, io), Connect(NoInfo, intIo, padFrameIntIo)) - case Output => - // internal to padframe ; padframe to output - Seq(Connect(NoInfo, padFrameIntIo, intIo), Connect(NoInfo, io, padFrameExtIo)) - } - } - }.flatten - val stmts = Seq(padFrameInst, topInternalInst) ++ connects - val ports = ioPads.map(p => p.port) - Module(NoInfo, topMod, ports = ports, body = Block(stmts)) - } - - def buildPadFrame(): Module = { - // Internal = connection to original RTL; External = connection to outside world - // Note that for analog pads, since there's only 1 port, only _Ext is used - val intPorts = ioPads.map(p => p.port.tpe match { - case AnalogType(_) => None - case _ => Some(p.port.copy(name = intName(p), direction = Utils.swap(p.portDirection))) - }).flatten - val extPorts = ioPads.map(p => p.port.tpe match { - // If an analog port doesn't have a pad associated with it, don't add it to the padframe - case AnalogType(_) if p.pad.isEmpty => None - case _ => Some(p.port.copy(name = extName(p))) - } ).flatten - // Only create pad black boxes for ports that require them - val ioPadInsts = ioPads.filter(x => !x.pad.isEmpty).map(p => WDefInstance(p.firrtlBBName, p.firrtlBBName)) - // Connect to pad only if used ; otherwise leave dangling for Analog - // and just connect through for digital (assumes no supplies) - val connects = ioPads.map { p => - val intRef = WRef(intName(p), p.port.tpe) - val extRef = WRef(extName(p), p.port.tpe) - p.pad match { - // No pad needed -- just connect through - case None => p.port.tpe match { - case AnalogType(_) => - Seq(EmptyStmt) - case _ => - val (lhs, rhs) = p.portDirection match { - case Input => (intRef, extRef) - case Output => (extRef, intRef) - } - Seq(Connect(NoInfo, lhs, rhs)) - } - // Add pad - case Some(x) => - val padRef = WRef(p.firrtlBBName) - p.port.tpe match { - // Analog type has 1:1 mapping to inout - case AnalogType(_) => - val padIORef = WSubField(padRef, AnalogPad.ioName) - Seq(Attach(NoInfo, Seq(padIORef, extRef))) - // Normal verilog in/out can be mapped to uint, sint, or clocktype, so need cast - case _ => - val padBBType = UIntType(getWidth(p.port.tpe)) - val padInRef = WSubField(padRef, DigitalPad.inName, padBBType, UnknownFlow) - val padOutRef = WSubField(padRef, DigitalPad.outName, padBBType, UnknownFlow) - val (rhsPadIn, lhsPadOut) = p.portDirection match { - case Input => (extRef, intRef) - case Output => (intRef, extRef) - } - // Pad inputs are treated as UInts, so need to do type conversion - // from type to UInt pad input; from pad output to type - Seq( - Connect(NoInfo, padInRef, castRhs(padBBType, rhsPadIn)), - Connect(NoInfo, lhsPadOut, castRhs(p.port.tpe, padOutRef))) - } - } - }.flatten - val supplyPadInsts = supplyPads.map(p => p.instNames.map(n => WDefInstance(n, p.firrtlBBName))).flatten - Module(NoInfo, padFrameName, ports = intPorts ++ extPorts, body = Block(ioPadInsts ++ connects ++ supplyPadInsts)) - } - -} diff --git a/tapeout/src/main/scala/transforms/.pads/AnnotatePortPads.scala b/tapeout/src/main/scala/transforms/.pads/AnnotatePortPads.scala deleted file mode 100644 index 8164463e..00000000 --- a/tapeout/src/main/scala/transforms/.pads/AnnotatePortPads.scala +++ /dev/null @@ -1,134 +0,0 @@ -package barstools.tapeout.transforms.pads - -import firrtl.annotations._ -import firrtl._ -import firrtl.ir._ -import barstools.tapeout.transforms._ - -// TODO: Make some trait with commonalities between IO Pad + supply pad - -// Pads associated with IO Ports! (Not supplies!) -case class PortIOPad( - pad: Option[FoundryPad], - padSide: PadSide, - port: Port) { - - def arrayInstNamePrefix(mod: String): String = Seq(mod, firrtlBBName, getPadName).mkString("/") - def arrayInstNameSuffix: String = pad match { - case None => throw new Exception("Port needs to use pad to get array instance name!") - case Some(x) => "/" + x.padInstName - } - - def portName = port.name - def portWidth = bitWidth(port.tpe).intValue - def portDirection = port.direction - def padOrientation = padSide.orientation - def padType = pad match { - case None => NoPad - case Some(x) => x.padType - } - - def widthParamName = "WIDTH" - def getPadName: String = pad match { - case None => throw new Exception("Cannot get pad name when no pad specified!") - case Some(x) => x.getName(portDirection, padOrientation) - } - def getPadArrayName: String = Seq(getPadName, "array").mkString("_") - // Firrtl black box name must be unique, even though the parameterized Verilog modules don't - // need to have separate names - def firrtlBBName = Seq(getPadArrayName, portName).mkString("_") - - // Note: This includes both the pad wrapper + an additional wrapper for n-bit wide to - // multiple pad conversion! - def createPadInline(): String = { - // For blackboxing bit extraction/concatenation (with module arrays) - def io(): String = padType match { - case DigitalPad => - s"""| input [${widthParamName}-1:0] ${DigitalPad.inName}, - | output reg [${widthParamName}-1:0] ${DigitalPad.outName}""".stripMargin - case AnalogPad => - s" inout [${widthParamName}-1:0] ${AnalogPad.ioName}" - case _ => throw new Exception("IO pad can only be digital or analog") - } - def assignIO(): String = padType match { - case DigitalPad => - s"""| .${DigitalPad.inName}(${DigitalPad.inName}), - | .${DigitalPad.outName}(${DigitalPad.outName})""".stripMargin - case AnalogPad => - s" .${AnalogPad.ioName}(${AnalogPad.ioName})" - case _ => throw new Exception("IO pad can only be digital or analog") - } - def getPadVerilog(): String = pad match { - case None => throw new Exception("Cannot get Verilog when no pad specified!") - case Some(x) => x.getVerilog(portDirection, padOrientation) - } - s"""inline - |${getPadArrayName}.v - |${getPadVerilog} - |module ${getPadArrayName} #( - | parameter int ${widthParamName}=1 - |)( - |${io} - |); - | ${getPadName} ${getPadName}[${widthParamName}-1:0]( - |${assignIO} - | ); - |endmodule""".stripMargin - } -} - -object AnnotatePortPads { - def apply( - c: Circuit, - topMod: String, - pads: Seq[FoundryPad], - componentAnnos: Seq[TargetIOPadAnnoF], - defaultSide: PadSide): Seq[PortIOPad] = { - - def lowerAnnotations(): Seq[TargetIOPadAnnoF] = { - componentAnnos map { x => x.target match { - case c: ComponentName => x.copy(target = c.copy(name = LowerName(c.name))) - case _ => throw new Exception("Not a component annotation! Can't lower!") - }} - } - - // Make annotations match low form - val annos = lowerAnnotations() - - def getPortIOPad(port: Port): PortIOPad = { - val portAnnos = annos.find(_.targetName == port.name) - // Ports can only be digital or analog - val padTypeRequired = port.tpe match { - case AnalogType(_) => AnalogPad - case _ => DigitalPad - } - val validPads = pads.filter(_.padType == padTypeRequired) - require(validPads.length > 0, s"No ${padTypeRequired.serialize} pads specified in the config yaml file!") - portAnnos match { - case None => - // If no pad-related annotation is found on a port, use defaults based off of port type - PortIOPad(Some(validPads.head), defaultSide, port) - case Some(x) => - x.anno match { - case NoIOPadAnnotation(_) => - // Some ports might not want attached pads - PortIOPad(None, defaultSide, port) - case IOPadAnnotation(padSide, padName) if padName.isEmpty => - // If no pad name is used, select the first valid pad based off of port type - PortIOPad(Some(validPads.head), HasPadAnnotation.getSide(padSide), port) - case IOPadAnnotation(padSide, padName) => - // If name doesn't match any provided -- maybe someone typoed? - validPads.find(_.name == padName) match { - case None => - throw new Exception( - s"Pad name associated with ${port.name} doesn't match valid pad names. Did you typo?") - case Some(x) => - PortIOPad(Some(x), HasPadAnnotation.getSide(padSide), port) - } - } - } - } - // Top MUST be internal module - c.modules.filter(_.name == topMod).head.ports.map(x => getPortIOPad(x)) - } -} \ No newline at end of file diff --git a/tapeout/src/main/scala/transforms/.pads/AnnotateSupplyPads.scala b/tapeout/src/main/scala/transforms/.pads/AnnotateSupplyPads.scala deleted file mode 100644 index cda00791..00000000 --- a/tapeout/src/main/scala/transforms/.pads/AnnotateSupplyPads.scala +++ /dev/null @@ -1,56 +0,0 @@ -package barstools.tapeout.transforms.pads - -import firrtl.annotations._ -import firrtl._ -import firrtl.ir._ -import firrtl.passes._ - -case class TopSupplyPad( - pad: FoundryPad, - padSide: PadSide, - num: Int -) { - - // TODO: These should be pulled into some common trait (supply + io)! - - def arrayInstNamePrefix(mod: String): Seq[String] = { - instNames.map(n => Seq(mod, n, pad.padInstName).mkString("/")) - } - def supplySetNum = pad.getSupplySetNum - - def padType = pad.padType - require(pad.padType == SupplyPad) - - def padOrientation = padSide.orientation - def getPadName = pad.getName(Output/*Should be None*/, padOrientation) - def firrtlBBName = getPadName - private def instNamePrefix = Seq(firrtlBBName, padSide.serialize).mkString("_") - def instNames = (0 until num).map(i => Seq(instNamePrefix, i.toString).mkString("_")) - - def createPadInline(): String = { - def getPadVerilog(): String = pad.getVerilog(Output/*Should be None*/, padOrientation) - s"""inline - |${getPadName}.v - |${getPadVerilog}""".stripMargin - } -} - -object AnnotateSupplyPads { - def apply( - pads: Seq[FoundryPad], - supplyAnnos: Seq[SupplyAnnotation] - ): Seq[TopSupplyPad] = { - supplyAnnos.map( a => - pads.find(_.name == a.padName) match { - case None => - throw new Exception(s"Supply pad ${a.padName} not found in Yaml file!") - case Some(x) => - Seq( - TopSupplyPad(x, Left, a.leftSide), - TopSupplyPad(x, Right, a.rightSide), - TopSupplyPad(x, Top, a.topSide), - TopSupplyPad(x, Bottom, a.bottomSide)) - } - ).flatten.filter(_.num > 0) - } -} diff --git a/tapeout/src/main/scala/transforms/.pads/ChiselTopModule.scala b/tapeout/src/main/scala/transforms/.pads/ChiselTopModule.scala deleted file mode 100644 index 5b2ed28a..00000000 --- a/tapeout/src/main/scala/transforms/.pads/ChiselTopModule.scala +++ /dev/null @@ -1,109 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms.pads - -import chisel3._ -import chisel3.experimental._ -import firrtl.Transform -import firrtl.annotations.Annotation - -// 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. -// annotate post-Chisel but pre-Firrtl (unfortunate non-generator friendly downside). -// It's recommended to have a Tapeout specific TopModule wrapper. -// LIMITATION: All signals of a bus must be on the same chip side - -// Chisel-y annotations -abstract class TopModule( - supplyAnnos: Seq[SupplyAnnotation] = Seq.empty, - defaultPadSide: PadSide = Top, - coreWidth: Int = 0, - coreHeight: Int = 0, - usePads: Boolean = true, - override_clock: Option[Clock] = None, - override_reset: Option[Bool] = None) extends Module { - - override_clock.foreach(clock := _) - override_reset.foreach(reset := _) - - private val mySelf = this - - // Annotate module as top module (that requires pad transform) - // Specify the yaml file that indicates how pads are templated, - // the default chip side that pads should be placed (if nothing is specified per IO), - // and supply annotations: supply pad name, location, and # - def createPads(): Unit = if (usePads) { - val modulePadAnnotation = ModulePadAnnotation( - defaultPadSide = defaultPadSide.serialize, - coreWidth = coreWidth, - coreHeight = coreHeight, - supplyAnnos = supplyAnnos - ) - //TODO: PORT-1.4: Remove commented code - // annotate(TargetModulePadAnnoC(this, modulePadAnnotation)) - annotate(new ChiselAnnotation with RunFirrtlTransform { - override def toFirrtl: Annotation = { - TargetModulePadAnnoF(mySelf.toNamed, modulePadAnnotation) - } - def transformClass: Class[_ <: Transform] = classOf[AddIOPadsTransform] - }) - } - - private def extractElementNames(signal: Data): Seq[String] = { - val names = signal match { - case elt: Record => - elt.elements.map { case (key, value) => extractElementNames(value).map(x => key + "_" + x) }.toSeq.flatten - case elt: Vec[_] => - elt.zipWithIndex.map { case (elt, i) => extractElementNames(elt).map(x => i + "_" + x) }.toSeq.flatten - case elt: Element => Seq("") - case elt => throw new Exception(s"Cannot extractElementNames for type ${elt.getClass}") - } - names.map(s => s.stripSuffix("_")) - } - - // TODO: Replace! - def extractElements(signal: Data): Seq[Element] = { - signal match { - case elt: Record => - elt.elements.map { case (key, value) => extractElements(value) }.toSeq.flatten - case elt: Vec[_] => - elt.map { elt => extractElements(elt) }.toSeq.flatten - case elt: Element => Seq(elt) - case elt => throw new Exception(s"Cannot extractElements for type ${elt.getClass}") - } - } - - // Annotate IO with side + pad name - def annotatePad(sig: Element, side: PadSide = defaultPadSide, name: String = ""): Unit = if (usePads) { - val anno = IOPadAnnotation(side.serialize, name) - annotate(new ChiselAnnotation with RunFirrtlTransform { - override def toFirrtl: Annotation = { - TargetIOPadAnnoF(sig.toTarget, anno) - } - def transformClass: Class[_ <: Transform] = classOf[AddIOPadsTransform] - }) - } - 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, name: String): Unit = - 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 - // not have pads auto added. Note that annotatePad and noPad are mutually exclusive! - def noPad(sig: Element): Unit = { - if (usePads) { - annotate(new ChiselAnnotation with RunFirrtlTransform { - override def toFirrtl: Annotation = { - TargetIOPadAnnoF(sig.toTarget, NoIOPadAnnotation()) - } - def transformClass: Class[_ <: Transform] = classOf[AddIOPadsTransform] - }) - } - } - 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 - // (at least when the module is actually at the top -- currently no guarantees otherwise :( firrtl limitation) - createPads() -} diff --git a/tapeout/src/main/scala/transforms/.pads/CreatePadBBs.scala b/tapeout/src/main/scala/transforms/.pads/CreatePadBBs.scala deleted file mode 100644 index 5b35fbe4..00000000 --- a/tapeout/src/main/scala/transforms/.pads/CreatePadBBs.scala +++ /dev/null @@ -1,109 +0,0 @@ -package barstools.tapeout.transforms.pads - -import firrtl.annotations._ -import firrtl._ -import firrtl.ir._ -import firrtl.transforms._ - -object CreatePadBBs { - - private [barstools] case class UsedPadInfo( - // The following are found with both supply + io pads - padInline: String, // Verilog txt - padName: String, // Pad module name - padType: PadType, // Pad type: supply, analog, digital - // The following only affects io pads (due to using parameterized modules for bit extraction / cat) - padArrayName: String, // Name of parameterized pad wrapper (that does bit extract/cat) - firrtlBBName: String, // Unique Firrtl name of each parameterized pad wrapper - portWidth: Int // Port width for analog/digital - ) - - def convertToUsedPad(p: PortIOPad): UsedPadInfo = { - UsedPadInfo( - padInline = p.createPadInline, - padName = p.getPadName, - padType = p.padType, - padArrayName = p.getPadArrayName, - firrtlBBName = p.firrtlBBName, - portWidth = p.portWidth) - } - - def convertToUsedPad(p: TopSupplyPad): UsedPadInfo = { - UsedPadInfo( - padInline = p.createPadInline, - padName = p.getPadName, - padType = p.padType, - // Supply pads don't require bit extraction / cat so don't care - padArrayName = p.getPadName, - firrtlBBName = p.getPadName, - portWidth = 0) - } - - def checkLegalPadName(namespace: Namespace, usedPads: Seq[UsedPadInfo]): Unit = { - usedPads foreach { x => - if (namespace contains x.padName) - throw new Exception(s"Pad name ${x.padName} already used!") - if (namespace contains x.padArrayName) - throw new Exception(s"Pad array ${x.padArrayName} name already used!") - if (namespace contains x.firrtlBBName) - throw new Exception(s"Firrtl black box ${x.firrtlBBName} name already used!") - } - } - - def apply( - c: Circuit, - ioPads: Seq[PortIOPad], - supplyPads: Seq[TopSupplyPad]): (Circuit, Seq[Annotation]) = { - - // Add black boxes for both supply + (used) io pads - val usedPads = ioPads.filter(x => x.pad.nonEmpty).map(convertToUsedPad(_)) ++ supplyPads.map(convertToUsedPad(_)) - checkLegalPadName(Namespace(c), usedPads) - - // Note that we need to check for Firrtl name uniqueness here! (due to parameterization) - val uniqueExtMods = scala.collection.mutable.ArrayBuffer[UsedPadInfo]() - usedPads foreach { x => - if (uniqueExtMods.find(_.firrtlBBName == x.firrtlBBName).isEmpty) - uniqueExtMods += x - } - - // Collecting unique parameterized black boxes - // (for io, they're wrapped pads; for supply, they're pad modules directly) - val uniqueParameterizedBBs = scala.collection.mutable.ArrayBuffer[UsedPadInfo]() - uniqueExtMods foreach { x => - if (uniqueParameterizedBBs.find(_.padArrayName == x.padArrayName).isEmpty) - uniqueParameterizedBBs += x - } - - // Note: Firrtl is silly and doesn't implement true parameterization -- each module with - // parameterization that potentially affects # of IO needs to be uniquely identified - // (but only in Firrtl) - val bbs = uniqueExtMods.map(x => { - // Supply pads don't have ports - val ports = x.padType match { - case AnalogPad => Seq(Port(NoInfo, AnalogPad.ioName, Input, AnalogType(IntWidth(x.portWidth)))) - case DigitalPad => Seq( - Port(NoInfo, DigitalPad.inName, Input, UIntType(IntWidth(x.portWidth))), - Port(NoInfo, DigitalPad.outName, Output, UIntType(IntWidth(x.portWidth))) - ) - case SupplyPad => Seq.empty - case _ => throw new Exception("Port pad type invalid!") - } - // Supply black boxes are not parameterized - val params = x.padType match { - case AnalogPad | DigitalPad => Seq(IntParam(ioPads.head.widthParamName, x.portWidth)) - case SupplyPad => Seq() - case _ => throw new Exception("Port pad type invalid!") - } - // Firrtl name is unique - ExtModule(NoInfo, x.firrtlBBName, ports, x.padArrayName, params) - } ).toSeq - - // 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 - val annos = uniqueParameterizedBBs.map(x => - BlackBoxInlineAnno(ModuleName(x.firrtlBBName, CircuitName(c.main)), x.firrtlBBName, x.padInline) - ).toSeq - (c.copy(modules = c.modules ++ bbs), annos) - } - -} diff --git a/tapeout/src/main/scala/transforms/.pads/FoundryPadsYaml.scala b/tapeout/src/main/scala/transforms/.pads/FoundryPadsYaml.scala deleted file mode 100644 index ce19a6d7..00000000 --- a/tapeout/src/main/scala/transforms/.pads/FoundryPadsYaml.scala +++ /dev/null @@ -1,129 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms.pads - -import net.jcazevedo.moultingyaml._ - -import firrtl._ -import firrtl.ir._ -import barstools.tapeout.transforms._ - -trait HasFoundryPadFields { - val tpe: String - val name: String - val width: Int - val height: Int - val supplySetNum: Option[Int] - val verilog: String -} - -case class FoundryPadFields( - tpe: String, - name: String, - width: Int, - height: Int, - supplySetNum: Option[Int], - verilog: String) - extends HasFoundryPadFields - -case class FoundryPad( - tpe: String, - name: String, - width: Int, - height: Int, - supplySetNum: Option[Int], - verilog: String) - extends HasFoundryPadFields { - - def padInstName = "PAD" - - require(verilog.contains("{{#if isHorizontal}}"), "All pad templates must contain '{{#if isHorizontal}}'") - require(verilog.contains("{{name}}"), "All pad templates must contain module name '{{name}}'") - require(verilog.contains(padInstName), s"All pad templates should have instances called ${padInstName}") - - def getSupplySetNum = supplySetNum.getOrElse(1) - - val padType = tpe match { - case "digital" => - 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("{{#if isInput}}"), "Digital pad template must contain '{{#if isInput}}'") - DigitalPad - case "analog" => - 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}}'") - AnalogPad - case "supply" => - // Supply pads don't have IO - require(!verilog.contains("{{#if isInput}}"), "Supply pad template must not contain '{{#if isInput}}'") - require( - verilog.contains(s"${padInstName}["), - "All supply pad templates should have instance arrays" + - " called ${padInstName}[n:0], where n = ${getSupplySetNum-1}" - ) - require(supplySetNum.nonEmpty, "# of grouped supply pads 'supplySetNum' should be specified!") - SupplyPad - case _ => throw new Exception("Illegal pad type in config!") - } - - import com.gilt.handlebars.scala.binding.dynamic._ - import com.gilt.handlebars.scala.Handlebars - private val template = Handlebars(verilog) - - // Make sure names don't have spaces in Verilog! - private[barstools] val correctedName = name.replace(" ", "_") - - case class TemplateParams( - // isInput only used with digital pads - isInput: Boolean, - isHorizontal: Boolean) { - - private val orient = if (isHorizontal) Horizontal.serialize else Vertical.serialize - private val dir = padType match { - case AnalogPad => "inout" - case SupplyPad => "none" - case DigitalPad => if (isInput) Input.serialize else Output.serialize - } - val name = { - val start = Seq("pad", tpe, correctedName, orient) - if (padType == DigitalPad) start :+ dir - else start - }.mkString("_") - } - - // Note: Analog + supply don't use direction - private def getTemplateParams(dir: Direction, orient: PadOrientation): TemplateParams = - TemplateParams(isInput = (dir == Input), isHorizontal = (orient == Horizontal)) - - def getVerilog(dir: Direction, orient: PadOrientation): String = { - val p = getTemplateParams(dir, orient) - template(p).stripMargin - } - - def getName(dir: Direction, orient: PadOrientation): String = getTemplateParams(dir, orient).name -} - -object FoundryPadsYaml extends DefaultYamlProtocol { - val exampleResource = "/FoundryPads.yaml" - implicit val _pad = yamlFormat6(FoundryPadFields) - def parse(techDir: String): Seq[FoundryPad] = { - val file = techDir + exampleResource - if (techDir != "" && !(new java.io.File(file)).exists()) { - throw new Exception(s"Technology directory $techDir must contain FoundryPads.yaml!") - } - val fieldsArray = (new YamlFileReader(exampleResource)).parse[FoundryPadFields](if (techDir == "") "" else file) - val out = fieldsArray.map { fields => - FoundryPad( - tpe = fields.tpe, - name = fields.name, - width = fields.width, - height = fields.height, - supplySetNum = fields.supplySetNum, - verilog = fields.verilog - ) - } - val padNames = out.map(x => x.correctedName) - require(padNames.distinct.length == padNames.length, "Pad names must be unique!") - out - } -} diff --git a/tapeout/src/main/scala/transforms/.pads/PadAnnotations.scala b/tapeout/src/main/scala/transforms/.pads/PadAnnotations.scala deleted file mode 100644 index 7ca49799..00000000 --- a/tapeout/src/main/scala/transforms/.pads/PadAnnotations.scala +++ /dev/null @@ -1,146 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms.pads - -import firrtl.annotations._ -import net.jcazevedo.moultingyaml._ - -object PadAnnotationsYaml extends DefaultYamlProtocol { - implicit val _iopad = yamlFormat2(IOPadAnnotation) - implicit val _noiopad = yamlFormat1(NoIOPadAnnotation) - implicit val _supplyanno = yamlFormat5(SupplyAnnotation) - implicit val _modulepadanno = yamlFormat4(ModulePadAnnotation) - - // Putting these serialize methods here seems to fix warnings about missing implicits for the toYaml - def serialize(noIOPad: NoIOPadAnnotation): String = { - noIOPad.toYaml.prettyPrint - } - def serialize(ioPadAnnotation: IOPadAnnotation): String = { - ioPadAnnotation.toYaml.prettyPrint - } - def serialize(modulePadAnnotation: ModulePadAnnotation): String = { - modulePadAnnotation.toYaml.prettyPrint - } -} - -abstract class FirrtlPadTransformAnnotation { - def targetName: String -} - -// IO Port can either be annotated with padName + padSide OR noPad (mutually exclusive) -abstract class IOAnnotation { - def serialize: String -} - -case class IOPadAnnotation(padSide: String, padName: String) extends IOAnnotation { - def serialize: String = PadAnnotationsYaml.serialize(this) - def getPadSide: PadSide = HasPadAnnotation.getSide(padSide) -} - -case class NoIOPadAnnotation(noPad: String = "") extends IOAnnotation { - def serialize: String = PadAnnotationsYaml.serialize(this) - def field: String = "noPad:" -} - -// Firrtl version -case class TargetIOPadAnnoF(target: ComponentName, anno: IOAnnotation) - extends FirrtlPadTransformAnnotation with SingleTargetAnnotation[ComponentName] { - - def duplicate(n: ComponentName): TargetIOPadAnnoF = this.copy(target = n) - def targetName: String = target.name -} - -// A bunch of supply pads (designated by name, # on each chip side) can be associated with the top module -case class SupplyAnnotation( - padName: String, - leftSide: Int = 0, - rightSide: Int = 0, - topSide: Int = 0, - bottomSide: Int = 0) - -// The chip top should have a default pad side, a pad template file, and supply annotations -case class ModulePadAnnotation( - defaultPadSide: String = Top.serialize, - coreWidth: Int = 0, - coreHeight: Int = 0, - supplyAnnos: Seq[SupplyAnnotation] = Seq.empty) { - - def serialize: String = PadAnnotationsYaml.serialize(this) - def supplyPadNames: Seq[String] = supplyAnnos.map(_.padName) - require(supplyPadNames.distinct.length == supplyPadNames.length, "Supply pads should only be specified once!") - def getDefaultPadSide: PadSide = HasPadAnnotation.getSide(defaultPadSide) -} - -// Firrtl version -case class TargetModulePadAnnoF(target: ModuleName, anno: ModulePadAnnotation) - extends FirrtlPadTransformAnnotation with SingleTargetAnnotation[ModuleName] { - - def duplicate(n: ModuleName): TargetModulePadAnnoF = this.copy(target = n) - def targetName: String = target.name -} - - -case class CollectedAnnos( - componentAnnos: Seq[TargetIOPadAnnoF], - moduleAnnos: TargetModulePadAnnoF) { - def supplyAnnos = moduleAnnos.anno.supplyAnnos - def defaultPadSide = moduleAnnos.anno.defaultPadSide - def topModName = moduleAnnos.targetName - def coreWidth = moduleAnnos.anno.coreWidth - def coreHeight = moduleAnnos.anno.coreHeight -} - -object HasPadAnnotation { - - def getSide(a: String): PadSide = a match { - case i if i == Left.serialize => Left - case i if i == Right.serialize => Right - case i if i == Top.serialize => Top - case i if i == Bottom.serialize => Bottom - case _ => throw new Exception(s" $a not a valid pad side annotation!") - } - - //TODO: PORT-1.4: Remove commented code -// def unapply(a: Annotation): Option[FirrtlPadTransformAnnotation] = a match { -// case Annotation(f, t, s) if t == classOf[AddIOPadsTransform] => f match { -// case m: ModuleName => -// Some(TargetModulePadAnnoF(m, s.parseYaml.convertTo[ModulePadAnnotation])) -// case c: ComponentName if s.contains(NoIOPadAnnotation().field) => -// Some(TargetIOPadAnnoF(c, s.parseYaml.convertTo[NoIOPadAnnotation])) -// case c: ComponentName => -// Some(TargetIOPadAnnoF(c, s.parseYaml.convertTo[IOPadAnnotation])) -// case _ => throw new Exception("Annotation only valid on module or component") -// } -// case _ => None -// } - - def apply(annos: Seq[Annotation]): Option[CollectedAnnos] = { - // Get all pad-related annotations (config files, pad sides, pad names, etc.) - val padAnnos = annos.flatMap { - case a: TargetModulePadAnnoF => Some(a) - case a: TargetIOPadAnnoF => Some(a) - case _ => None - } - val targets = padAnnos.map(x => x.targetName) - require(targets.distinct.length == targets.length, "Only 1 pad related annotation is allowed per component/module") - if (padAnnos.length == 0) { - None - } else { - val moduleAnnosTemp = padAnnos.filter { - case TargetModulePadAnnoF(_, _) => true - case _ => false - } - require(moduleAnnosTemp.length == 1, "Only 1 module may be designated 'Top'") - val moduleAnnos = moduleAnnosTemp.head - val topModName = moduleAnnos.targetName - val componentAnnos = padAnnos.filter { - case TargetIOPadAnnoF(ComponentName(_, ModuleName(n, _)), _) if n == topModName => - true - case TargetIOPadAnnoF(ComponentName(_, ModuleName(n, _)), _) if n != topModName => - throw new Exception("Pad related component annotations must all be in the same top module") - case _ => false - }.map(x => x.asInstanceOf[TargetIOPadAnnoF]) - Some(CollectedAnnos(componentAnnos, moduleAnnos.asInstanceOf[TargetModulePadAnnoF])) - } - } -} diff --git a/tapeout/src/main/scala/transforms/.pads/PadDescriptors.scala b/tapeout/src/main/scala/transforms/.pads/PadDescriptors.scala deleted file mode 100644 index cb3420b1..00000000 --- a/tapeout/src/main/scala/transforms/.pads/PadDescriptors.scala +++ /dev/null @@ -1,49 +0,0 @@ -package barstools.tapeout.transforms.pads - -import firrtl._ -import firrtl.ir._ - -abstract class PadOrientation extends FirrtlNode -case object Horizontal extends PadOrientation { - def serialize: String = "horizontal" -} -case object Vertical extends PadOrientation { - def serialize: String = "vertical" -} - -abstract class PadType extends FirrtlNode -case object DigitalPad extends PadType { - def serialize: String = "digital" - def inName: String = "in" - def outName: String = "out" -} -case object AnalogPad extends PadType { - def serialize: String = "analog" - def ioName: String = "io" -} -case object SupplyPad extends PadType { - def serialize: String = "supply" -} -case object NoPad extends PadType { - def serialize: String = "none" -} - -abstract class PadSide extends FirrtlNode { - def orientation: PadOrientation -} -case object Left extends PadSide { - def serialize: String = "left" - def orientation: PadOrientation = Horizontal -} -case object Right extends PadSide { - def serialize: String = "right" - def orientation: PadOrientation = Horizontal -} -case object Top extends PadSide { - def serialize: String = "top" - def orientation: PadOrientation = Vertical -} -case object Bottom extends PadSide { - def serialize: String = "bottom" - def orientation: PadOrientation = Vertical -} diff --git a/tapeout/src/main/scala/transforms/.pads/PadPlacement.scala b/tapeout/src/main/scala/transforms/.pads/PadPlacement.scala deleted file mode 100644 index d3e99626..00000000 --- a/tapeout/src/main/scala/transforms/.pads/PadPlacement.scala +++ /dev/null @@ -1,158 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms.pads - -import barstools.tapeout.transforms._ -import net.jcazevedo.moultingyaml._ - -/** This is a hack to get around weird problem with yaml parser - * that without this gives PadPlacement defines additional fields - * - */ -trait HasPadPlacementFields { - def file: String - def left: String - def top: String - def right: String - def bottom: String - def instanceArray: String - def padLine: String - def template: String -} - -case class PadPlacementFields( - file: String, - left: String, - top: String, - right: String, - bottom: String, - instanceArray: String, - padLine: String, - template: String -) extends HasPadPlacementFields - -case class PadPlacement( - file: String, - left: String, - top: String, - right: String, - bottom: String, - instanceArray: String, - padLine: String, - template: String -) extends HasPadPlacementFields { - - require(instanceArray contains "{{signal}}", "Instance Array Template should contain {{signal}}") - require(instanceArray contains "{{idx}}", "Instance Array Template should contain {{idx}}") - require(padLine contains "{{padInst}}", "Pad line should contain {{padInst}}") - require(padLine contains "{{side}}", "Pad line should contain {{side}} (Can be in comments)") - require(padLine contains "{{padIdx}}", "Pad line should contain {{padIdx}} (Can be in comments)") - require(template contains "{{leftPads}}", "Pad line should contain {{leftPads}}") - require(template contains "{{rightPads}}", "Pad line should contain {{rightPads}}") - require(template contains "{{topPads}}", "Pad line should contain {{topPads}}") - require(template contains "{{bottomPads}}", "Pad line should contain {{bottomPads}}") - - def getSideString(s: PadSide): String = s match { - case Left => left - case Right => right - case Top => top - case Bottom => bottom - } - - import com.gilt.handlebars.scala.Handlebars - import com.gilt.handlebars.scala.binding.dynamic._ - - private val instanceArrayTemplate = Handlebars(instanceArray.stripMargin) - private val padLineTemplate = Handlebars(padLine.stripMargin) - private val padPlacementTemplate = Handlebars(template.stripMargin) - - def getInstanceArray(p: InstanceArrayParams): String = instanceArrayTemplate(p).stripMargin - def getPadLine(p: PadLineParams): String = padLineTemplate(p).stripMargin.replace(""", "\"") - def getPadPlacement(p: PadPlacementParams): String = padPlacementTemplate(p).stripMargin.replace(""", "\"") - -} - -case class InstanceArrayParams(signal: String, idx: Int) -case class PadLineParams(padInst: String, side: String, padIdx: Int) -case class PadPlacementParams(leftPads: String, rightPads: String, topPads: String, bottomPads: String) - -object PadPlacementFile extends DefaultYamlProtocol { - val exampleResource = "/PadPlacement.yaml" - implicit val _pad = yamlFormat8(PadPlacementFields) - - def main(args: Array[String]): Unit = { - println(parse("RealTech/PadPlacement.yaml")) - } - - def parse(file: String = ""): PadPlacement = { - val fields = (new YamlFileReader(exampleResource)).parse[PadPlacementFields](file).head - PadPlacement( - file = fields.file, - left = fields.left, - top = fields.top, - right = fields.right, - bottom = fields.bottom, - instanceArray = fields.instanceArray, - padLine = fields.padLine, - template = fields.template - ) - } - - def generate( - techDir: String, - targetDir: String, - padFrameName: String, - portPads: Seq[PortIOPad], - supplyPads: Seq[TopSupplyPad]): Unit = { - - val file = techDir + exampleResource - if(techDir != "" && !(new java.io.File(file)).exists()) - throw new Exception("Technology directory must contain PadPlacement.yaml!") - val template = parse(if (techDir == "") "" else file) - - val leftPads = scala.collection.mutable.ArrayBuffer[String]() - val rightPads = scala.collection.mutable.ArrayBuffer[String]() - val topPads = scala.collection.mutable.ArrayBuffer[String]() - val bottomPads = scala.collection.mutable.ArrayBuffer[String]() - - def sort(side: PadSide, inst: String): Unit = side match { - case Left => leftPads += inst - case Right => rightPads += inst - case Top => topPads += inst - case Bottom => bottomPads += inst - } - - // TODO: Be smarter about supply placement (+ grouping?) between signals - // Supply pad instance name: padFrameName/firrtlBBName_padSide_#num/PAD[#supplySetNum] - supplyPads foreach { p => - val prefixes = p.arrayInstNamePrefix(padFrameName) - prefixes foreach { prefix => - (0 until p.supplySetNum) foreach { idx => - sort(p.padSide, template.getInstanceArray(InstanceArrayParams(prefix, idx))) - } - } - } - // IO pad instance name: padFrameName/firrtlBBName/getPadName[#portWidth]/PAD - portPads.filter(_.pad.nonEmpty) foreach { p => - val prefix = p.arrayInstNamePrefix(padFrameName) - (0 until p.portWidth).map(idx => - template.getInstanceArray(InstanceArrayParams(prefix, idx)) + p.arrayInstNameSuffix - ) foreach { x => sort(p.padSide, x) } - } - - def getLines(pads: Seq[String], side: PadSide): String = { - val seq = pads.zipWithIndex.map{ case (p, idx) => - template.getPadLine(PadLineParams(p, template.getSideString(side), idx)) } - seq.mkString("\n") - } - - val fileContents = template.getPadPlacement(PadPlacementParams( - leftPads = getLines(leftPads.toSeq, Left), - rightPads = getLines(rightPads.toSeq, Right), - topPads = getLines(topPads.toSeq, Top), - bottomPads = getLines(bottomPads.toSeq, Bottom) - )) - - WriteConfig(targetDir, template.file, fileContents) - } -} \ No newline at end of file diff --git a/tapeout/src/test/resources/PadPlacement.io b/tapeout/src/test/resources/PadPlacement.io deleted file mode 100644 index 435ce274..00000000 --- a/tapeout/src/test/resources/PadPlacement.io +++ /dev/null @@ -1,236 +0,0 @@ -(globals - version = 3 - io_order = default -) -(iopad - (bottomleft - (inst name="corner_ll" cell="CORNER_EXAMPLE" ) - ) - (bottomright - (inst name="corner_lr" orientation=MY cell="CORNER_EXAMPLE" ) - ) - (topleft - (inst name="corner_ul" orientation=MX cell="CORNER_EXAMPLE" ) - ) - (topright - (inst name="corner_ur" cell="CORNER_EXAMPLE" ) - ) - (left - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vdd_horizontal_left_0/PAD[0]") # Side: 1, Order: 0 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vdd_horizontal_left_1/PAD[0]") # Side: 1, Order: 1 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vdd_horizontal_left_2/PAD[0]") # Side: 1, Order: 2 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[0]/PAD") # Side: 1, Order: 3 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[1]/PAD") # Side: 1, Order: 4 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[2]/PAD") # Side: 1, Order: 5 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[3]/PAD") # Side: 1, Order: 6 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[4]/PAD") # Side: 1, Order: 7 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[5]/PAD") # Side: 1, Order: 8 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[6]/PAD") # Side: 1, Order: 9 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[7]/PAD") # Side: 1, Order: 10 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[8]/PAD") # Side: 1, Order: 11 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[9]/PAD") # Side: 1, Order: 12 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[10]/PAD") # Side: 1, Order: 13 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[11]/PAD") # Side: 1, Order: 14 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[12]/PAD") # Side: 1, Order: 15 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[13]/PAD") # Side: 1, Order: 16 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[14]/PAD") # Side: 1, Order: 17 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[0]/PAD") # Side: 1, Order: 18 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[1]/PAD") # Side: 1, Order: 19 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[2]/PAD") # Side: 1, Order: 20 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[3]/PAD") # Side: 1, Order: 21 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[4]/PAD") # Side: 1, Order: 22 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[5]/PAD") # Side: 1, Order: 23 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[6]/PAD") # Side: 1, Order: 24 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[7]/PAD") # Side: 1, Order: 25 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[8]/PAD") # Side: 1, Order: 26 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[9]/PAD") # Side: 1, Order: 27 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[10]/PAD") # Side: 1, Order: 28 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[11]/PAD") # Side: 1, Order: 29 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[12]/PAD") # Side: 1, Order: 30 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[13]/PAD") # Side: 1, Order: 31 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[14]/PAD") # Side: 1, Order: 32 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[0]/PAD") # Side: 1, Order: 33 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[1]/PAD") # Side: 1, Order: 34 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[2]/PAD") # Side: 1, Order: 35 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[3]/PAD") # Side: 1, Order: 36 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[4]/PAD") # Side: 1, Order: 37 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[5]/PAD") # Side: 1, Order: 38 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[6]/PAD") # Side: 1, Order: 39 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[7]/PAD") # Side: 1, Order: 40 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[8]/PAD") # Side: 1, Order: 41 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[9]/PAD") # Side: 1, Order: 42 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[10]/PAD") # Side: 1, Order: 43 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[11]/PAD") # Side: 1, Order: 44 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[12]/PAD") # Side: 1, Order: 45 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[13]/PAD") # Side: 1, Order: 46 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[0]/PAD") # Side: 1, Order: 47 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[1]/PAD") # Side: 1, Order: 48 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[2]/PAD") # Side: 1, Order: 49 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[3]/PAD") # Side: 1, Order: 50 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[4]/PAD") # Side: 1, Order: 51 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[5]/PAD") # Side: 1, Order: 52 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[6]/PAD") # Side: 1, Order: 53 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[7]/PAD") # Side: 1, Order: 54 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[8]/PAD") # Side: 1, Order: 55 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[9]/PAD") # Side: 1, Order: 56 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[10]/PAD") # Side: 1, Order: 57 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[11]/PAD") # Side: 1, Order: 58 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[12]/PAD") # Side: 1, Order: 59 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[13]/PAD") # Side: 1, Order: 60 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[14]/PAD") # Side: 1, Order: 61 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[15]/PAD") # Side: 1, Order: 62 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_analog_fast_custom_horizontal_array_io_analog1/pad_analog_fast_custom_horizontal[0]/PAD") # Side: 1, Order: 63 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_analog_fast_custom_horizontal_array_io_analog1/pad_analog_fast_custom_horizontal[1]/PAD") # Side: 1, Order: 64 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_analog_fast_custom_horizontal_array_io_analog1/pad_analog_fast_custom_horizontal[2]/PAD") # Side: 1, Order: 65 - - ) - (right - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vss_horizontal_right_0/PAD[0]") # Side: 3, Order: 0 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vss_horizontal_right_0/PAD[1]") # Side: 3, Order: 1 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_0/pad_digital_from_tristate_foundry_horizontal_output[0]/PAD") # Side: 3, Order: 2 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_0/pad_digital_from_tristate_foundry_horizontal_output[1]/PAD") # Side: 3, Order: 3 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_0/pad_digital_from_tristate_foundry_horizontal_output[2]/PAD") # Side: 3, Order: 4 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_0/pad_digital_from_tristate_foundry_horizontal_output[3]/PAD") # Side: 3, Order: 5 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_0/pad_digital_from_tristate_foundry_horizontal_output[4]/PAD") # Side: 3, Order: 6 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_1/pad_digital_from_tristate_foundry_horizontal_output[0]/PAD") # Side: 3, Order: 7 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_1/pad_digital_from_tristate_foundry_horizontal_output[1]/PAD") # Side: 3, Order: 8 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_1/pad_digital_from_tristate_foundry_horizontal_output[2]/PAD") # Side: 3, Order: 9 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_1/pad_digital_from_tristate_foundry_horizontal_output[3]/PAD") # Side: 3, Order: 10 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_1/pad_digital_from_tristate_foundry_horizontal_output[4]/PAD") # Side: 3, Order: 11 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_2/pad_digital_from_tristate_foundry_horizontal_output[0]/PAD") # Side: 3, Order: 12 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_2/pad_digital_from_tristate_foundry_horizontal_output[1]/PAD") # Side: 3, Order: 13 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_2/pad_digital_from_tristate_foundry_horizontal_output[2]/PAD") # Side: 3, Order: 14 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_2/pad_digital_from_tristate_foundry_horizontal_output[3]/PAD") # Side: 3, Order: 15 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_2/pad_digital_from_tristate_foundry_horizontal_output[4]/PAD") # Side: 3, Order: 16 - - ) - (top - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_input_array_reset/pad_digital_from_tristate_foundry_vertical_input[0]/PAD") # Side: 2, Order: 0 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[0]/PAD") # Side: 2, Order: 1 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[1]/PAD") # Side: 2, Order: 2 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[2]/PAD") # Side: 2, Order: 3 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[3]/PAD") # Side: 2, Order: 4 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[4]/PAD") # Side: 2, Order: 5 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[5]/PAD") # Side: 2, Order: 6 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[6]/PAD") # Side: 2, Order: 7 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[7]/PAD") # Side: 2, Order: 8 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[8]/PAD") # Side: 2, Order: 9 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[9]/PAD") # Side: 2, Order: 10 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[10]/PAD") # Side: 2, Order: 11 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[11]/PAD") # Side: 2, Order: 12 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[12]/PAD") # Side: 2, Order: 13 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[13]/PAD") # Side: 2, Order: 14 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[14]/PAD") # Side: 2, Order: 15 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[15]/PAD") # Side: 2, Order: 16 - - ) - (bottom - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vdd_vertical_bottom_0/PAD[0]") # Side: 4, Order: 0 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vdd_vertical_bottom_1/PAD[0]") # Side: 4, Order: 1 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_analog_slow_foundry_vertical_array_io_analog2/pad_analog_slow_foundry_vertical[0]/PAD") # Side: 4, Order: 2 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_analog_slow_foundry_vertical_array_io_analog2/pad_analog_slow_foundry_vertical[1]/PAD") # Side: 4, Order: 3 - - (inst name = "ExampleTopModuleWithBB_PadFrame/pad_analog_slow_foundry_vertical_array_io_analog2/pad_analog_slow_foundry_vertical[2]/PAD") # Side: 4, Order: 4 - - ) -) \ No newline at end of file diff --git a/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala b/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala deleted file mode 100644 index 12fcb411..00000000 --- a/tapeout/src/test/scala/transforms/.pads/AddIOPadsSpec.scala +++ /dev/null @@ -1,268 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms.pads - -import java.io.File - -import barstools.tapeout.transforms.HasSetTechnologyLocation -import chisel3._ -import chisel3.experimental._ -import chisel3.iotesters._ -import chisel3.stage.ChiselStage -import chisel3.util.HasBlackBoxInline -import firrtl._ -import org.scalatest.{FlatSpec, Matchers} - -class BB extends BlackBox with HasBlackBoxInline { - val io = IO(new Bundle { - val c = Input(SInt(14.W)) - val z = Output(SInt(16.W)) - val analog1 = Analog(3.W) - val analog2 = Analog(3.W) - }) - // Generates a "FakeBB.v" file with the following Verilog module - setInline( - "FakeBB.v", - s""" - |module BB( - | input [15:0] c, - | output [15:0] z, - | inout [2:0] analog1, - | inout [2:0] analog2 - |); - | always @* begin - | z = 2 * c; - | analog2 = analog1 + 1; - | end - |endmodule - """.stripMargin - ) -} - -// If no template file is provided, it'll use the default one (example) in the resource folder -// Default pad side is Top if no side is specified for a given IO -// You can designate the number of different supply pads on each chip side -class ExampleTopModuleWithBB - extends TopModule( - supplyAnnos = Seq( - SupplyAnnotation(padName = "vdd", leftSide = 3, bottomSide = 2), - SupplyAnnotation(padName = "vss", rightSide = 1) - ) - ) - with HasSetTechnologyLocation { - val io = IO(new Bundle { - val a = Input(UInt(15.W)) - val b = Input(a.cloneType) - val c = Input(SInt(14.W)) - val x = Output(UInt(16.W)) - val y = Output(x.cloneType) - val z = Output(SInt(16.W)) - val analog1 = Analog(3.W) - val analog2 = analog1.cloneType - val v = Output(Vec(3, UInt(5.W))) - }) - - setTechnologyLocation("./RealTech") - - // Can annotate aggregates with pad side location + pad name (should be a name in the yaml template) - annotatePad(io.v, Right, "from_tristate_foundry") - // Can annotate individual elements - annotatePad(io.analog1, Left, "fast_custom") - annotatePad(io.analog2, Bottom, "slow_foundry") - // Looks for a pad that matches the IO type (digital in, digital out, analog) if no name is specified - Seq(io.a, io.b, io.c, io.x).foreach { x => annotatePad(x, Left) } - // Some signals might not want pads associated with them - noPad(io.y) - // Clk might come directly from bump - noPad(clock) - - val bb = Module(new BB()) - bb.io.c := io.c - io.z := bb.io.z - bb.io.analog1 <> io.analog1 - bb.io.analog2 <> io.analog2 - - io.x := io.a + 1.U - io.y := io.b - 1.U - - io.v.foreach { lhs => lhs := io.a } - -} - -class SimpleTopModuleTester(c: ExampleTopModuleWithBB) extends PeekPokeTester(c) { - val ax = Seq(5, 3) - val bx = Seq(8, 2) - val cx = Seq(-11, -9) - for (i <- 0 until ax.length) { - poke(c.io.a, ax(i)) - poke(c.io.b, bx(i)) - poke(c.io.c, cx(i)) - expect(c.io.x, ax(i) + 1) - expect(c.io.y, bx(i) - 1) - expect(c.io.z, 2 * cx(i)) - c.io.v.foreach { out => expect(out, ax(i)) } - } - // Analog can't be peeked + poked -} - -// Notes: Annotations -// a in 15: left, default digital -// b in 15: left, default digital -// c in 14: left, default digital ; signed -// x out 16: left, default digital -// y out: NOPAD -// clk in: NOPAD -// analog1 3: left, fast_custom -// analog2 3: bottom, slow_foundry -// v (vec of 3 with 5, out): right, from_tristate_foundry -// reset in: UNSPECIFIED: top, default digital -// z out 16: UNSPECIFIED: top, default digital ; signed -// vdd, left: 3, group of 1 -// vdd, bottom: 2, group of 1 -// vss, right: 1, group of 2 -// Notes: Used pads -// digital horizontal (from_tristate_foundry) -// in + out -// analog fast_custom horizontal -// analog slow_foundry vertical -// digital vertical (from_tristate_foundry) -// in + out -// vdd horizontal -// vdd vertical -// vss horizontal - -class IOPadSpec extends FlatSpec with Matchers { - - def readOutputFile(dir: String, f: String): String = { - FileUtils.getText(dir + File.separator + f) - } - def readResource(resource: String): String = { - val stream = getClass.getResourceAsStream(resource) - scala.io.Source.fromInputStream(stream).mkString - } - - def checkOutputs(dir: String): Unit = { - // Show that black box source helper is run - //readOutputFile(dir, "black_box_verilog_files.f") should include ("pad_supply_vdd_horizontal.v") - - val padBBEx = s"""// Digital Pad Example - |// Signal Direction: Input - |// Pad Orientation: Horizontal - |// Call your instance PAD - |module pad_digital_from_tristate_foundry_horizontal_input( - | input in, - | output reg out - |); - | // Where you would normally dump your pad instance - | always @* begin - | out = in; - | end - |endmodule - | - |module pad_digital_from_tristate_foundry_horizontal_input_array #( - | parameter int WIDTH=1 - |)( - | input [WIDTH-1:0] in, - | output reg [WIDTH-1:0] out - |); - | pad_digital_from_tristate_foundry_horizontal_input pad_digital_from_tristate_foundry_horizontal_input[WIDTH-1:0]( - | .in(in), - | .out(out) - | );""".stripMargin - // Make sure black box templating is OK - readOutputFile(dir, "pad_digital_from_tristate_foundry_horizontal_input_array.v") should include(padBBEx) - - val verilog = readOutputFile(dir, "ExampleTopModuleWithBB.v") - // Pad frame + top should be exact - verilog should include(readResource("/PadAnnotationVerilogPart.v")) - // Pad Placement IO file should be exact - val padIO = readOutputFile(dir, "pads.io") - padIO should include(readResource("/PadPlacement.io")) - } - - behavior.of("Pad Annotations") - - it should "serialize pad annotations" in { - val noIOPadAnnotation = NoIOPadAnnotation("dog") - noIOPadAnnotation.serialize should include("noPad: dog") - - val ioPadAnnotation = IOPadAnnotation("left", "oliver") - ioPadAnnotation.serialize should include( - """padSide: left - |padName: oliver - |""".stripMargin) - - val modulePadAnnotation = ModulePadAnnotation( - "top", - 11, - 42, - Seq( - SupplyAnnotation("mypad, 1, 2 ,3 , 4"), - SupplyAnnotation("yourpad, 9, 8, 7, 6") - ) - ) - - modulePadAnnotation.serialize should be( - """defaultPadSide: top - |coreWidth: 11 - |coreHeight: 42 - |supplyAnnos: - |- rightSide: 0 - | padName: mypad, 1, 2 ,3 , 4 - | leftSide: 0 - | bottomSide: 0 - | topSide: 0 - |- rightSide: 0 - | padName: yourpad, 9, 8, 7, 6 - | leftSide: 0 - | bottomSide: 0 - | topSide: 0 - |""".stripMargin - ) - } - - behavior.of("top module with blackbox") - - it should "pass simple testbench" in { - val optionsManager = new TesterOptionsManager { - firrtlOptions = firrtlOptions.copy( - compilerName = "verilog" - ) - testerOptions = testerOptions.copy(isVerbose = true, backendName = "verilator", displayBase = 10) - commonOptions = commonOptions.copy(targetDirName = "test_run_dir/PadsTB") - } - iotesters.Driver.execute(() => new ExampleTopModuleWithBB, optionsManager) { c => - val dir = optionsManager.commonOptions.targetDirName - checkOutputs(dir) - new SimpleTopModuleTester(c) - } should be(true) - } - /* - it should "create proper IO pads + black box in low firrtl" in { - val optionsManager = new ExecutionOptionsManager("barstools") with HasChiselExecutionOptions with HasFirrtlOptions { - firrtlOptions = firrtlOptions.copy(compilerName = "low") - commonOptions = commonOptions.copy(targetDirName = "test_run_dir/LoFirrtl") - //commonOptions = commonOptions.copy(globalLogLevel = logger.LogLevel.Info) - } - val success = chisel3.Driver.execute(optionsManager, () => new ExampleTopModuleWithBB) match { - case ChiselExecutionSuccess(_, chirrtl, Some(FirrtlExecutionSuccess(_, firrtl))) => - firrtl should include ("ExampleTopModuleWithBB_PadFrame") - firrtl should include ("ExampleTopModuleWithBB_Internal") - firrtl should not include ("FakeBBPlaceholder") - true - case _ => false - } - success should be (true) - } - */ - it should "create proper IO pads + black box in verilog" in { - val dir = "test_run_dir/PadsVerilog" - (new ChiselStage).emitVerilog( - new ExampleTopModuleWithBB, -// Array("-td", dir, "-X", "verilog") - Array("-td", dir) - ) - checkOutputs(dir) - } - -}