diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 733ebcf6..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "mdf"] - path = mdf - url = https://github.com/ucb-bar/plsi-mdf.git diff --git a/build.sbt b/build.sbt index d8840865..2b75dbc1 100644 --- a/build.sbt +++ b/build.sbt @@ -1,8 +1,8 @@ // See LICENSE for license details. val defaultVersions = Map( - "chisel3" -> "3.4.+", - "chisel-iotesters" -> "1.5.+" + "chisel3" -> "3.5-SNAPSHOT", + "chisel-iotesters" -> "2.5-SNAPSHOT" ) lazy val commonSettings = Seq( @@ -14,7 +14,10 @@ lazy val commonSettings = Seq( dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) }, libraryDependencies ++= Seq( - "org.scalatest" %% "scalatest" % "3.2.2" % "test", + "com.typesafe.play" %% "play-json" % "2.9.2", + "org.scalatest" %% "scalatest" % "3.2.9" % "test", + "org.apache.logging.log4j" % "log4j-api" % "2.11.2", + "org.apache.logging.log4j" % "log4j-core" % "2.11.2" ), resolvers ++= Seq( Resolver.sonatypeRepo("snapshots"), @@ -23,19 +26,17 @@ lazy val commonSettings = Seq( ) ) -disablePlugins(sbtassembly.AssemblyPlugin) +//disablePlugins(sbtassembly.AssemblyPlugin) +// +//enablePlugins(sbtassembly.AssemblyPlugin) -lazy val mdf = (project in file("mdf/scalalib")) -lazy val macros = (project in file("macros")) - .dependsOn(mdf) +lazy val tapeout = (project in file(".")) .settings(commonSettings) + .settings(scalacOptions in Test ++= Seq("-language:reflectiveCalls")) + .settings(fork := true) .settings( mainClass := Some("barstools.macros.MacroCompiler") ) .enablePlugins(sbtassembly.AssemblyPlugin) -lazy val tapeout = (project in file("tapeout")) - .settings(commonSettings) - .settings(scalacOptions in Test ++= Seq("-language:reflectiveCalls")) - -lazy val root = (project in file(".")).aggregate(macros, tapeout) +//lazy val root = (project in file(".")).aggregate(tapeout) diff --git a/macros/build.sbt b/macros/build.sbt deleted file mode 100644 index 65e9704a..00000000 --- a/macros/build.sbt +++ /dev/null @@ -1 +0,0 @@ -enablePlugins(sbtassembly.AssemblyPlugin) diff --git a/mdf b/mdf deleted file mode 160000 index e588024d..00000000 --- a/mdf +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e588024d706220b73f2c97ca75d6fec8dd0d41b1 diff --git a/iocell/src/main/resources/barstools/iocell/vsrc/Analog.v b/src/main/resources/barstools/iocell/vsrc/Analog.v similarity index 100% rename from iocell/src/main/resources/barstools/iocell/vsrc/Analog.v rename to src/main/resources/barstools/iocell/vsrc/Analog.v diff --git a/iocell/src/main/resources/barstools/iocell/vsrc/IOCell.v b/src/main/resources/barstools/iocell/vsrc/IOCell.v similarity index 100% rename from iocell/src/main/resources/barstools/iocell/vsrc/IOCell.v rename to src/main/resources/barstools/iocell/vsrc/IOCell.v diff --git a/iocell/src/main/scala/barstools/iocell/chisel/Analog.scala b/src/main/scala/barstools/iocell/chisel/Analog.scala similarity index 100% rename from iocell/src/main/scala/barstools/iocell/chisel/Analog.scala rename to src/main/scala/barstools/iocell/chisel/Analog.scala diff --git a/iocell/src/main/scala/barstools/iocell/chisel/IOCell.scala b/src/main/scala/barstools/iocell/chisel/IOCell.scala similarity index 99% rename from iocell/src/main/scala/barstools/iocell/chisel/IOCell.scala rename to src/main/scala/barstools/iocell/chisel/IOCell.scala index d244d298..6d444936 100644 --- a/iocell/src/main/scala/barstools/iocell/chisel/IOCell.scala +++ b/src/main/scala/barstools/iocell/chisel/IOCell.scala @@ -141,7 +141,7 @@ object IOCell { * @param name An optional name or name prefix to use for naming IO cells * @return A Seq of all generated IO cell instances */ - val toSyncReset: (Reset) => Bool = _.toBool + val toSyncReset: (Reset) => Bool = _.asBool() val toAsyncReset: (Reset) => AsyncReset = _.asAsyncReset def generateFromSignal[T <: Data, R <: Reset]( coreSignal: T, diff --git a/macros/src/main/scala/barstools/macros/CostMetric.scala b/src/main/scala/barstools/macros/CostMetric.scala similarity index 100% rename from macros/src/main/scala/barstools/macros/CostMetric.scala rename to src/main/scala/barstools/macros/CostMetric.scala diff --git a/macros/src/main/scala/barstools/macros/MacroCompiler.scala b/src/main/scala/barstools/macros/MacroCompiler.scala similarity index 99% rename from macros/src/main/scala/barstools/macros/MacroCompiler.scala rename to src/main/scala/barstools/macros/MacroCompiler.scala index bfcf78da..6218b593 100644 --- a/macros/src/main/scala/barstools/macros/MacroCompiler.scala +++ b/src/main/scala/barstools/macros/MacroCompiler.scala @@ -8,7 +8,7 @@ package barstools.macros import barstools.macros.Utils._ -import firrtl.Utils._ +import firrtl.Utils.{BoolType, one, zero} import firrtl.annotations._ import firrtl.ir._ import firrtl.stage.{FirrtlSourceAnnotation, FirrtlStage, Forms, OutputFileAnnotation, RunFirrtlTransformAnnotation} @@ -783,7 +783,6 @@ class MacroCompilerOptimizations extends SeqTransform with DependencyAPIMigratio new firrtl.transforms.ConstantPropagation, passes.memlib.VerilogMemDelays, new firrtl.transforms.ConstantPropagation, - passes.Legalize, passes.SplitExpressions, passes.CommonSubexpressionElimination ) diff --git a/macros/src/main/scala/barstools/macros/SynFlops.scala b/src/main/scala/barstools/macros/SynFlops.scala similarity index 97% rename from macros/src/main/scala/barstools/macros/SynFlops.scala rename to src/main/scala/barstools/macros/SynFlops.scala index 77ea4c96..a6fe32a4 100644 --- a/macros/src/main/scala/barstools/macros/SynFlops.scala +++ b/src/main/scala/barstools/macros/SynFlops.scala @@ -3,7 +3,7 @@ package barstools.macros import barstools.macros.Utils._ -import firrtl.Utils._ +import firrtl.Utils.{zero, one} import firrtl._ import firrtl.ir._ import firrtl.passes.MemPortUtils.memPortField @@ -27,7 +27,7 @@ class SynFlopsPass(synflops: Boolean, libs: Seq[Macro]) extends firrtl.passes.Pa case Some(gran) => (UIntType(IntWidth(gran)), gran.intValue) } - val maxDepth = min(lib.src.depth, 1 << 26) + val maxDepth = firrtl.Utils.min(lib.src.depth, 1 << 26) val numMems = lib.src.depth / maxDepth // Change macro to be mapped onto to look like the below mem @@ -64,7 +64,7 @@ class SynFlopsPass(synflops: Boolean, libs: Seq[Macro]) extends firrtl.passes.Pa val readConnects = real_macro.readers.zipWithIndex.flatMap { case (r, i) => val clock = portToExpression(r.src.clock.get) val address = portToExpression(r.src.address) - val enable = (r.src chipEnable, r.src readEnable) match { + val enable = (r.src.chipEnable, r.src.readEnable) match { case (Some(en_port), Some(re_port)) => and(portToExpression(en_port), portToExpression(re_port)) case (Some(en_port), None) => portToExpression(en_port) diff --git a/macros/src/main/scala/barstools/macros/Utils.scala b/src/main/scala/barstools/macros/Utils.scala similarity index 100% rename from macros/src/main/scala/barstools/macros/Utils.scala rename to src/main/scala/barstools/macros/Utils.scala diff --git a/tapeout/src/main/scala/barstools/tapeout/transforms/AddSuffixToModuleNames.scala b/src/main/scala/barstools/tapeout/transforms/AddSuffixToModuleNames.scala similarity index 100% rename from tapeout/src/main/scala/barstools/tapeout/transforms/AddSuffixToModuleNames.scala rename to src/main/scala/barstools/tapeout/transforms/AddSuffixToModuleNames.scala diff --git a/tapeout/src/main/scala/barstools/tapeout/transforms/AvoidExtModuleCollisions.scala b/src/main/scala/barstools/tapeout/transforms/AvoidExtModuleCollisions.scala similarity index 100% rename from tapeout/src/main/scala/barstools/tapeout/transforms/AvoidExtModuleCollisions.scala rename to src/main/scala/barstools/tapeout/transforms/AvoidExtModuleCollisions.scala diff --git a/tapeout/src/main/scala/barstools/tapeout/transforms/ConvertToExtModPass.scala b/src/main/scala/barstools/tapeout/transforms/ConvertToExtModPass.scala similarity index 100% rename from tapeout/src/main/scala/barstools/tapeout/transforms/ConvertToExtModPass.scala rename to src/main/scala/barstools/tapeout/transforms/ConvertToExtModPass.scala diff --git a/tapeout/src/main/scala/barstools/tapeout/transforms/EnumerateModules.scala b/src/main/scala/barstools/tapeout/transforms/EnumerateModules.scala similarity index 100% rename from tapeout/src/main/scala/barstools/tapeout/transforms/EnumerateModules.scala rename to src/main/scala/barstools/tapeout/transforms/EnumerateModules.scala diff --git a/tapeout/src/main/scala/barstools/tapeout/transforms/GenerateTopAndHarness.scala b/src/main/scala/barstools/tapeout/transforms/GenerateTopAndHarness.scala similarity index 100% rename from tapeout/src/main/scala/barstools/tapeout/transforms/GenerateTopAndHarness.scala rename to src/main/scala/barstools/tapeout/transforms/GenerateTopAndHarness.scala diff --git a/tapeout/src/main/scala/barstools/tapeout/transforms/ReParentCircuit.scala b/src/main/scala/barstools/tapeout/transforms/ReParentCircuit.scala similarity index 100% rename from tapeout/src/main/scala/barstools/tapeout/transforms/ReParentCircuit.scala rename to src/main/scala/barstools/tapeout/transforms/ReParentCircuit.scala diff --git a/tapeout/src/main/scala/barstools/tapeout/transforms/RemoveUnusedModules.scala b/src/main/scala/barstools/tapeout/transforms/RemoveUnusedModules.scala similarity index 100% rename from tapeout/src/main/scala/barstools/tapeout/transforms/RemoveUnusedModules.scala rename to src/main/scala/barstools/tapeout/transforms/RemoveUnusedModules.scala diff --git a/tapeout/src/main/scala/barstools/tapeout/transforms/ResetInverter.scala b/src/main/scala/barstools/tapeout/transforms/ResetInverter.scala similarity index 97% rename from tapeout/src/main/scala/barstools/tapeout/transforms/ResetInverter.scala rename to src/main/scala/barstools/tapeout/transforms/ResetInverter.scala index 33d2f78a..29c9f0da 100644 --- a/tapeout/src/main/scala/barstools/tapeout/transforms/ResetInverter.scala +++ b/src/main/scala/barstools/tapeout/transforms/ResetInverter.scala @@ -60,7 +60,7 @@ class ResetInverterTransform extends Transform with DependencyAPIMigration { trait ResetInverter { self: chisel3.Module => - def invert[T <: chisel3.internal.LegacyModule](module: T): Unit = { + def invert[T <: chisel3.Module](module: T): Unit = { 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/barstools/tapeout/transforms/retime/Retime.scala b/src/main/scala/barstools/tapeout/transforms/retime/Retime.scala similarity index 96% rename from tapeout/src/main/scala/barstools/tapeout/transforms/retime/Retime.scala rename to src/main/scala/barstools/tapeout/transforms/retime/Retime.scala index 931af88d..1a9d6668 100644 --- a/tapeout/src/main/scala/barstools/tapeout/transforms/retime/Retime.scala +++ b/src/main/scala/barstools/tapeout/transforms/retime/Retime.scala @@ -39,7 +39,7 @@ class RetimeTransform extends Transform with DependencyAPIMigration { trait RetimeLib { self: chisel3.Module => - def retime[T <: chisel3.internal.LegacyModule](module: T): Unit = { + def retime[T <: chisel3.Module](module: T): Unit = { 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/barstools/tapeout/transforms/stage/TapeoutStage.scala b/src/main/scala/barstools/tapeout/transforms/stage/TapeoutStage.scala similarity index 100% rename from tapeout/src/main/scala/barstools/tapeout/transforms/stage/TapeoutStage.scala rename to src/main/scala/barstools/tapeout/transforms/stage/TapeoutStage.scala diff --git a/tapeout/src/main/scala/barstools/tapeout/transforms/utils/FileUtils.scala b/src/main/scala/barstools/tapeout/transforms/utils/FileUtils.scala similarity index 100% rename from tapeout/src/main/scala/barstools/tapeout/transforms/utils/FileUtils.scala rename to src/main/scala/barstools/tapeout/transforms/utils/FileUtils.scala diff --git a/tapeout/src/main/scala/barstools/tapeout/transforms/utils/LowerAnnotations.scala b/src/main/scala/barstools/tapeout/transforms/utils/LowerAnnotations.scala similarity index 100% rename from tapeout/src/main/scala/barstools/tapeout/transforms/utils/LowerAnnotations.scala rename to src/main/scala/barstools/tapeout/transforms/utils/LowerAnnotations.scala diff --git a/tapeout/src/main/scala/barstools/tapeout/transforms/utils/ProgrammaticBundle.scala b/src/main/scala/barstools/tapeout/transforms/utils/ProgrammaticBundle.scala similarity index 100% rename from tapeout/src/main/scala/barstools/tapeout/transforms/utils/ProgrammaticBundle.scala rename to src/main/scala/barstools/tapeout/transforms/utils/ProgrammaticBundle.scala diff --git a/tapeout/src/main/scala/barstools/tapeout/transforms/utils/YamlHelpers.scala b/src/main/scala/barstools/tapeout/transforms/utils/YamlHelpers.scala similarity index 77% rename from tapeout/src/main/scala/barstools/tapeout/transforms/utils/YamlHelpers.scala rename to src/main/scala/barstools/tapeout/transforms/utils/YamlHelpers.scala index 9a226de5..9b58e083 100644 --- a/tapeout/src/main/scala/barstools/tapeout/transforms/utils/YamlHelpers.scala +++ b/src/main/scala/barstools/tapeout/transforms/utils/YamlHelpers.scala @@ -1,5 +1,6 @@ package barstools.tapeout.transforms.utils +import firrtl.FileUtils import net.jcazevedo.moultingyaml._ import java.io.File @@ -10,10 +11,10 @@ class YamlFileReader(resource: String) { val yamlString = file match { case f if f.isEmpty => // Use example config if no file is provided - val stream = getClass.getResourceAsStream(resource) - io.Source.fromInputStream(stream).mkString + val stream = FileUtils.getTextResource(resource) + stream case f if new File(f).exists => - scala.io.Source.fromFile(f).getLines.mkString("\n") + FileUtils.getText(f) case _ => throw new Exception("No valid Yaml file found!") } diff --git a/src/main/scala/mdf/macrolib/ConfReader.scala b/src/main/scala/mdf/macrolib/ConfReader.scala new file mode 100644 index 00000000..ec701d6e --- /dev/null +++ b/src/main/scala/mdf/macrolib/ConfReader.scala @@ -0,0 +1,95 @@ +package mdf.macrolib + +object ConfReader { + import scala.util.matching.Regex._ + + type ConfPort = (String, Boolean) // prefix (e.g. "RW0") and true if masked + + /** Rename ports like "read" to R0, "write" to W0, and "rw" to RW0, and + * return a count of read, write, and readwrite ports. + */ + def renamePorts(ports: Seq[String]): (Seq[ConfPort], Int, Int, Int) = { + var readCount = 0 + var writeCount = 0 + var readWriteCount = 0 + ( + ports.map { + _ match { + case "read" => readCount += 1; (s"R${readCount - 1}", false) + case "write" => writeCount += 1; (s"W${writeCount - 1}", false) + case "mwrite" => writeCount += 1; (s"W${writeCount - 1}", true) + case "rw" => readWriteCount += 1; (s"RW${readWriteCount - 1}", false) + case "mrw" => readWriteCount += 1; (s"RW${readWriteCount - 1}", true) + } + }, + readCount, + writeCount, + readWriteCount + ) + } + + def generateFirrtlPort(port: ConfPort, width: Int, depth: Int, maskGran: Option[Int]): MacroPort = { + val (prefix, masked) = port + val isReadWriter = prefix.startsWith("RW") + val isReader = prefix.startsWith("R") && !isReadWriter + val isWriter = prefix.startsWith("W") + val r = if (isReadWriter) "r" else "" + val w = if (isReadWriter) "w" else "" + MacroPort( + address = PolarizedPort(s"${prefix}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"${prefix}_clk", PositiveEdge)), + writeEnable = if (isReadWriter) Some(PolarizedPort(s"${prefix}_${w}mode", ActiveHigh)) else None, + output = if (isReader || isReadWriter) Some(PolarizedPort(s"${prefix}_${w}data", ActiveHigh)) else None, + input = if (isWriter || isReadWriter) Some(PolarizedPort(s"${prefix}_${r}data", ActiveHigh)) else None, + maskPort = if (masked) Some(PolarizedPort(s"${prefix}_${w}mask", ActiveHigh)) else None, + maskGran = if (masked) maskGran else None, + width = Some(width), + depth = Some(depth) + ) + } + + /** Read a conf line into a SRAMMacro, but returns an error string in Left + * instead of throwing errors if the line is malformed. + */ + def readSingleLineSafe(line: String): Either[String, SRAMMacro] = { + val pattern = """name ([^\s]+) depth (\d+) width (\d+) ports ([a-z,]+)\s?(?:mask_gran (\d+))?""".r + pattern.findFirstMatchIn(line) match { + case Some(m: Match) => { + val name: String = m.group(1) + val depth: Int = (m.group(2)).toInt + val width: Int = (m.group(3)).toInt + val ports: Seq[String] = (m.group(4)).split(",") + val (firrtlPorts, readPortCount, writePortCount, readWritePortCount) = renamePorts(ports) + val familyStr = + (if (readPortCount > 0) s"${readPortCount}r" else "") + + (if (writePortCount > 0) s"${writePortCount}w" else "") + + (if (readWritePortCount > 0) s"${readWritePortCount}rw" else "") + val maskGran: Option[Int] = Option(m.group(5)).map(_.toInt) + Right( + SRAMMacro( + name = name, + width = width, + depth = depth, + family = familyStr, + vt = "", + mux = 1, + ports = firrtlPorts.map(generateFirrtlPort(_, width, depth, maskGran)), + extraPorts = List() + ) + ) + } + case _ => Left("Input line did not match conf regex") + } + } + + /** Read a conf line into a SRAMMacro. */ + def readSingleLine(line: String): SRAMMacro = { + readSingleLineSafe(line).right.get + } + + /** Read the contents of the conf file into a seq of SRAMMacro. */ + def readFromString(contents: String): Seq[SRAMMacro] = { + // Trim, remove empty lines, then pass to readSingleLine + contents.split("\n").map(_.trim).filter(_ != "").map(readSingleLine(_)) + } +} diff --git a/src/main/scala/mdf/macrolib/FillerMacroBase.scala b/src/main/scala/mdf/macrolib/FillerMacroBase.scala new file mode 100644 index 00000000..688871b5 --- /dev/null +++ b/src/main/scala/mdf/macrolib/FillerMacroBase.scala @@ -0,0 +1,61 @@ +package mdf.macrolib + +import play.api.libs.json._ +import scala.language.implicitConversions + +// Filler and metal filler +abstract class FillerMacroBase(name: String, vt: String) extends Macro { + override def toString(): String = { + s"${this.getClass.getSimpleName}(name=${name}, vt=${vt})" + } + + override def toJSON(): JsObject = { + JsObject( + Seq( + "type" -> JsString(typeStr), + "name" -> Json.toJson(name), + "vt" -> Json.toJson(vt) + ) + ) + } +} +object FillerMacroBase { + def parseJSON(json: Map[String, JsValue]): Option[FillerMacroBase] = { + val typee: String = json.get("type") match { + case Some(x: JsString) => + x.value match { + case "" => return None + case x => x + } + case _ => return None + } + val name: String = json.get("name") match { + case Some(x: JsString) => + x.value match { + case "" => return None + case x => x + } + case _ => return None + } + val vt: String = json.get("vt") match { + case Some(x: JsString) => + x.value match { + case "" => return None + case x => x + } + case _ => return None + } + typee match { + case "metal filler cell" => Some(MetalFillerMacro(name, vt)) + case "filler cell" => Some(FillerMacro(name, vt)) + case _ => None + } + } +} + +case class FillerMacro(name: String, vt: String) extends FillerMacroBase(name, vt) { + override def typeStr = "filler cell" +} +case class MetalFillerMacro(name: String, vt: String) extends FillerMacroBase(name, vt) { + override def typeStr = "metal filler cell" +} diff --git a/src/main/scala/mdf/macrolib/FlipChipMacro.scala b/src/main/scala/mdf/macrolib/FlipChipMacro.scala new file mode 100644 index 00000000..45b49d86 --- /dev/null +++ b/src/main/scala/mdf/macrolib/FlipChipMacro.scala @@ -0,0 +1,72 @@ +package mdf.macrolib + +import play.api.libs.json._ +import scala.collection.mutable.ListBuffer +import scala.language.implicitConversions + +// Flip Chip Macro +case class FlipChipMacro( + name: String, + bumpDimensions: (Int, Int), + bumpLocations: Seq[Seq[String]]) + extends Macro { + override def toJSON(): JsObject = { + + val output = new ListBuffer[(String, JsValue)]() + output.appendAll( + Seq( + "name" -> Json.toJson(name), + "type" -> Json.toJson(typeStr), + "bump_dimensions" -> JsArray(Seq(bumpDimensions._1, bumpDimensions._2).map { JsNumber(_) }), + "bump_locations" -> JsArray(bumpLocations.map(l => JsArray(l.map(JsString)))) + ) + ) + + JsObject(output) + } + val maxIONameSize = bumpLocations.foldLeft(0) { (size, row) => + row.foldLeft(size) { (size, str) => scala.math.max(size, str.length) } + } + def visualize: String = { + val output = new StringBuffer() + for (x <- 0 until bumpDimensions._1) { + for (y <- 0 until bumpDimensions._2) { + val name = bumpLocations(x)(y).drop(1).dropRight(1) + val extra = maxIONameSize - name.length() + val leftSpace = " " * (extra / 2) + val rightSpace = " " * (extra / 2 + extra % 2) + output.append(leftSpace + name + rightSpace + "|") + } + output.append("\n") + } + output.toString() + } + + override def typeStr = "flipchip" +} + +object FlipChipMacro { + def parseJSON(json: Map[String, JsValue]): Option[FlipChipMacro] = { + val name: String = json.get("name") match { + case Some(x: JsString) => x.as[String] + case _ => return None + } + + val bumpDimensions: (Int, Int) = json.get("bump_dimensions") match { + case Some(JsArray(x)) if x.size == 2 => + val z = x.map(_.as[JsNumber].value.intValue()) + (z(0), z(1)) + case None => return None + } + val bumpLocations: Seq[Seq[String]] = json.get("bump_locations") match { + case Some(JsArray(array)) => + array.collect { case JsArray(a2) => a2.map(_.toString) } + case _ => return None + } + // Can't have dimensions and locations which don't match + if (bumpLocations.size != bumpDimensions._1) return None + if (bumpLocations.collect { case x if x.size != bumpDimensions._2 => x }.nonEmpty) return None + + Some(FlipChipMacro(name, bumpDimensions, bumpLocations)) + } +} diff --git a/src/main/scala/mdf/macrolib/IOMacro.scala b/src/main/scala/mdf/macrolib/IOMacro.scala new file mode 100644 index 00000000..3f8ead8c --- /dev/null +++ b/src/main/scala/mdf/macrolib/IOMacro.scala @@ -0,0 +1,147 @@ +package mdf.macrolib + +import play.api.libs.json._ +import scala.collection.mutable.ListBuffer +import scala.language.implicitConversions + +sealed abstract class PortType { def toJSON(): JsString = JsString(toString) } +case object Digital extends PortType { override def toString: String = "digital" } +case object Analog extends PortType { override def toString: String = "analog" } +case object Power extends PortType { override def toString: String = "power" } +case object Ground extends PortType { override def toString: String = "ground" } +case object NoConnect extends PortType { override def toString: String = "NC" } + +sealed abstract class Direction { def toJSON(): JsString = JsString(toString) } +case object Input extends Direction { override def toString: String = "input" } +case object Output extends Direction { override def toString: String = "output" } +case object InOut extends Direction { override def toString: String = "inout" } + +sealed abstract class Termination { def toJSON(): JsValue } +case object CMOS extends Termination { override def toJSON(): JsString = JsString("CMOS") } +case class Resistive(ohms: Int) extends Termination { override def toJSON(): JsNumber = JsNumber(ohms) } + +sealed abstract class TerminationType { def toJSON(): JsString } +case object Single extends TerminationType { override def toJSON(): JsString = JsString("single") } +case object Differential extends TerminationType { override def toJSON(): JsString = JsString("differential") } + +// IO macro +case class IOMacro( + name: String, + tpe: PortType, + direction: Option[Direction] = None, + termination: Option[Termination] = None, + terminationType: Option[TerminationType] = None, + terminationReference: Option[String] = None, + matching: Seq[String] = Seq.empty[String], + bbname: Option[String] = None) + extends Macro { + override def toJSON(): JsObject = { + + val output = new ListBuffer[(String, JsValue)]() + output.appendAll( + Seq( + "name" -> Json.toJson(name), + "type" -> tpe.toJSON() + ) + ) + if (direction.isDefined) output.append("direction" -> direction.get.toJSON) + if (termination.isDefined) output.append("termination" -> termination.get.toJSON) + if (terminationType.isDefined) output.append("terminationType" -> terminationType.get.toJSON) + if (terminationReference.isDefined) output.append("terminationReference" -> JsString(terminationReference.get)) + if (matching.nonEmpty) output.append("match" -> JsArray(matching.map(JsString))) + if (bbname.nonEmpty) output.append("blackBox" -> JsString(bbname.get)) + + JsObject(output) + } + + override def typeStr = "iomacro" +} +object IOMacro { + def parseJSON(json: Map[String, JsValue]): Option[IOMacro] = { + val name: String = json.get("name") match { + case Some(x: JsString) => x.as[String] + case _ => return None + } + val tpe: PortType = json.get("type") match { + case Some(JsString("power")) => Power + case Some(JsString("ground")) => Ground + case Some(JsString("digital")) => Digital + case Some(JsString("analog")) => Analog + case Some(JsString("NC")) => NoConnect + case _ => return None + } + val direction: Option[Direction] = json.get("direction") match { + case Some(JsString("input")) => Some(Input) + case Some(JsString("output")) => Some(Output) + case Some(JsString("inout")) => Some(InOut) + case _ => None + } + val termination: Option[Termination] = json.get("termination") match { + case Some(JsNumber(x)) => Some(Resistive(x.toInt)) + case Some(JsString("CMOS")) => Some(CMOS) + case _ => None + } + val terminationType: Option[TerminationType] = json.get("terminationType") match { + case Some(JsString("differential")) => Some(Differential) + case Some(JsString("single")) => Some(Single) + case _ => None + } + val terminationRef: Option[String] = json.get("terminationReference") match { + case Some(JsString(x)) => Some(x) + case _ if terminationType.isDefined => return None + case _ => None + } + val matching: Seq[String] = json.get("match") match { + case Some(JsArray(array)) => array.map(_.as[JsString].value).toList + case _ => Seq.empty[String] + } + val bbname: Option[String] = json.get("blackBox") match { + case Some(JsString(module)) => Some(module) + case Some(_) => return None + case _ => None + } + Some(IOMacro(name, tpe, direction, termination, terminationType, terminationRef, matching, bbname)) + } +} + +case class IOProperties(name: String, top: String, ios: Seq[IOMacro]) extends Macro { + override def toJSON(): JsObject = { + val output = new ListBuffer[(String, JsValue)]() + output.appendAll( + Seq( + "name" -> Json.toJson(name), + "top" -> Json.toJson(top), + "type" -> Json.toJson(typeStr), + "ios" -> JsArray(ios.map(_.toJSON)) + ) + ) + JsObject(output) + } + + override def typeStr = "io_properties" + +} + +object IOProperties { + def parseJSON(json: Map[String, JsValue]): Option[IOProperties] = { + val name: String = json.get("name") match { + case Some(x: JsString) => x.as[String] + case _ => return None + } + val top: String = json.get("top") match { + case Some(x: JsString) => x.as[String] + case _ => return None + } + val ios: Seq[IOMacro] = json.get("ios") match { + case Some(x: JsArray) => + x.as[List[Map[String, JsValue]]].map { a => + val b = IOMacro.parseJSON(a); + if (b == None) { + return None + } else b.get + } + case _ => List() + } + Some(IOProperties(name, top, ios)) + } +} diff --git a/src/main/scala/mdf/macrolib/MacroLib.scala b/src/main/scala/mdf/macrolib/MacroLib.scala new file mode 100644 index 00000000..569c4dac --- /dev/null +++ b/src/main/scala/mdf/macrolib/MacroLib.scala @@ -0,0 +1,19 @@ +package mdf.macrolib + +import play.api.libs.json._ +import scala.collection.mutable.ListBuffer +import scala.language.implicitConversions + +// TODO: decide if we should always silently absorb errors + +// See macro_format.yml for the format description. + +// "Base class" for macros +abstract class Macro { + def name: String + + // Type of macro is determined by subclass + def typeStr: String + + def toJSON(): JsObject +} diff --git a/src/main/scala/mdf/macrolib/SRAM.scala b/src/main/scala/mdf/macrolib/SRAM.scala new file mode 100644 index 00000000..ea51b049 --- /dev/null +++ b/src/main/scala/mdf/macrolib/SRAM.scala @@ -0,0 +1,444 @@ +package mdf.macrolib + +import play.api.libs.json._ +import scala.collection.mutable.ListBuffer +import scala.language.implicitConversions + +// SRAM macro +case class SRAMMacro( + name: String, + width: Int, + depth: BigInt, + family: String, + ports: Seq[MacroPort], + vt: String = "", + mux: Int = 1, + extraPorts: Seq[MacroExtraPort] = List()) + extends Macro { + override def toJSON(): JsObject = { + val output = new ListBuffer[(String, JsValue)]() + output.appendAll( + Seq( + "type" -> JsString("sram"), + "name" -> Json.toJson(name), + "width" -> Json.toJson(width), + "depth" -> Json.toJson(depth.toString), + "mux" -> Json.toJson(mux), + "mask" -> Json.toJson(ports.exists(p => p.maskPort.isDefined)), + "ports" -> JsArray(ports.map { _.toJSON }) + ) + ) + if (family != "") { + output.appendAll(Seq("family" -> Json.toJson(family))) + } + if (vt != "") { + output.appendAll(Seq("vt" -> Json.toJson(vt))) + } + if (extraPorts.length > 0) { + output.appendAll(Seq("extra ports" -> JsArray(extraPorts.map { _.toJSON }))) + } + + JsObject(output) + } + + override def typeStr = "sram" +} +object SRAMMacro { + def parseJSON(json: Map[String, JsValue]): Option[SRAMMacro] = { + val name: String = json.get("name") match { + case Some(x: JsString) => x.as[String] + case _ => return None + } + val width: Int = json.get("width") match { + case Some(x: JsNumber) => x.value.intValue + case _ => return None + } + val depth: BigInt = json.get("depth") match { + case Some(x: JsString) => + try { BigInt(x.as[String]) } + catch { case _: Throwable => return None } + case _ => return None + } + val family: String = json.get("family") match { + case Some(x: JsString) => x.as[String] + case _ => "" // optional + } + val vt: String = json.get("vt") match { + case Some(x: JsString) => x.as[String] + case _ => "" // optional + } + val mux: Int = json.get("mux") match { + case Some(x: JsNumber) => x.value.intValue + case _ => 1 // default + } + val ports: Seq[MacroPort] = json.get("ports") match { + case Some(x: JsArray) => + x.as[List[Map[String, JsValue]]].map { a => + val b = MacroPort.parseJSON(a, width, depth); + if (b == None) { + return None + } else b.get + } + case _ => List() + } + if (ports.length == 0) { + // Can't have portless memories. + return None + } + val extraPorts: Seq[MacroExtraPort] = json.get("extra ports") match { + case Some(x: JsArray) => + x.as[List[Map[String, JsValue]]].map { a => + val b = MacroExtraPort.parseJSON(a); + if (b == None) { + return None + } else b.get + } + case _ => List() + } + Some(SRAMMacro(name, width, depth, family, ports, vt, mux, extraPorts)) + } +} + +// SRAM compiler +case class SRAMGroup( + name: Seq[String], + family: String, + vt: Seq[String], + mux: Int, + depth: Range, + width: Range, + ports: Seq[MacroPort], + extraPorts: Seq[MacroExtraPort] = List()) { + def toJSON: JsObject = { + val output = new ListBuffer[(String, JsValue)]() + output.appendAll( + Seq( + "name" -> JsArray(name.map(Json.toJson(_))), + "vt" -> JsArray(vt.map(Json.toJson(_))), + "mux" -> Json.toJson(mux), + "depth" -> JsArray(Seq(depth.start, depth.end, depth.step).map { x => Json.toJson(x) }), + "width" -> JsArray(Seq(width.start, width.end, width.step).map { x => Json.toJson(x) }), + "ports" -> JsArray(ports.map { _.toJSON }) + ) + ) + if (family != "") { + output.appendAll(Seq("family" -> Json.toJson(family))) + } + if (extraPorts.length > 0) { + output.appendAll(Seq("extra ports" -> JsArray(extraPorts.map { _.toJSON }))) + } + JsObject(output) + } +} +object SRAMGroup { + def parseJSON(json: Map[String, JsValue]): Option[SRAMGroup] = { + val family: String = json.get("family") match { + case Some(x: JsString) => x.as[String] + case _ => "" // optional + } + val name: Seq[String] = json.get("name") match { + case Some(x: JsArray) => x.as[List[JsString]].map(_.as[String]) + case _ => return None + } + val vt: Seq[String] = json.get("vt") match { + case Some(x: JsArray) => x.as[List[JsString]].map(_.as[String]) + case _ => return None + } + val mux: Int = json.get("mux") match { + case Some(x: JsNumber) => x.value.intValue + case _ => return None + } + val depth: Range = json.get("depth") match { + case Some(x: JsArray) => + val seq = x.as[List[JsNumber]].map(_.value.intValue) + Range.inclusive(seq(0), seq(1), seq(2)) + case _ => return None + } + val width: Range = json.get("width") match { + case Some(x: JsArray) => + val seq = x.as[List[JsNumber]].map(_.value.intValue) + Range.inclusive(seq(0), seq(1), seq(2)) + case _ => return None + } + val ports: Seq[MacroPort] = json.get("ports") match { + case Some(x: JsArray) => + x.as[List[Map[String, JsValue]]].map { a => + { + val b = MacroPort.parseJSON(a, None, None); + if (b == None) { + return None + } else b.get + } + } + case _ => List() + } + if (ports.length == 0) { + // Can't have portless memories. + return None + } + val extraPorts: Seq[MacroExtraPort] = json.get("extra ports") match { + case Some(x: JsArray) => + x.as[List[Map[String, JsValue]]].map { a => + { + val b = MacroExtraPort.parseJSON(a); + if (b == None) { + return None + } else b.get + } + } + case _ => List() + } + Some(SRAMGroup(name, family, vt, mux, depth, width, ports, extraPorts)) + } +} + +case class SRAMCompiler( + name: String, + groups: Seq[SRAMGroup]) + extends Macro { + override def toJSON(): JsObject = { + val output = new ListBuffer[(String, JsValue)]() + output.appendAll( + Seq( + "type" -> Json.toJson("sramcompiler"), + "name" -> Json.toJson(name), + "groups" -> JsArray(groups.map { _.toJSON }) + ) + ) + + JsObject(output) + } + + override def typeStr = "sramcompiler" +} +object SRAMCompiler { + def parseJSON(json: Map[String, JsValue]): Option[SRAMCompiler] = { + val name: String = json.get("name") match { + case Some(x: JsString) => x.as[String] + case _ => return None + } + val groups: Seq[SRAMGroup] = json.get("groups") match { + case Some(x: JsArray) => + x.as[List[Map[String, JsValue]]].map { a => + { + val b = SRAMGroup.parseJSON(a); + if (b == None) { return None } + else b.get + } + } + case _ => List() + } + if (groups.length == 0) { + // Can't have portless memories. + return None + } + Some(SRAMCompiler(name, groups)) + } +} + +// Type of extra port +sealed abstract class MacroExtraPortType +case object Constant extends MacroExtraPortType +object MacroExtraPortType { + implicit def toMacroExtraPortType(s: Any): Option[MacroExtraPortType] = { + s match { + case "constant" => Some(Constant) + case _ => None + } + } + + implicit def toString(t: MacroExtraPortType): String = { + t match { + case Constant => "constant" + case _ => "" + } + } +} + +// Extra port in SRAM +case class MacroExtraPort( + name: String, + width: Int, + portType: MacroExtraPortType, + value: BigInt) { + def toJSON(): JsObject = { + JsObject( + Seq( + "name" -> Json.toJson(name), + "width" -> Json.toJson(width), + "type" -> JsString(MacroExtraPortType.toString(portType)), + "value" -> JsNumber(BigDecimal(value)) + ) + ) + } +} +object MacroExtraPort { + def parseJSON(json: Map[String, JsValue]): Option[MacroExtraPort] = { + val name = json.get("name") match { + case Some(x: JsString) => x.value + case _ => return None + } + val width = json.get("width") match { + case Some(x: JsNumber) => x.value.intValue + case _ => return None + } + val portType: MacroExtraPortType = json.get("type") match { + case Some(x: JsString) => + MacroExtraPortType.toMacroExtraPortType(x.value) match { + case Some(t: MacroExtraPortType) => t + case _ => return None + } + case _ => return None + } + val value = json.get("value") match { + case Some(x: JsNumber) => x.value.toBigInt + case _ => return None + } + Some(MacroExtraPort(name, width, portType, value)) + } +} + +// A named port that also has polarity. +case class PolarizedPort(name: String, polarity: PortPolarity) { + def toSeqMap(prefix: String): Seq[Tuple2[String, JsValue]] = { + Seq( + prefix + " port name" -> Json.toJson(name), + prefix + " port polarity" -> JsString(polarity) + ) + } +} +object PolarizedPort { + // Parse a pair of " port name" and " port polarity" keys into a + // polarized port definition. + def parseJSON(json: Map[String, JsValue], prefix: String): Option[PolarizedPort] = { + val name = json.get(prefix + " port name") match { + case Some(x: JsString) => Some(x.value) + case _ => None + } + val polarity: Option[PortPolarity] = json.get(prefix + " port polarity") match { + case Some(x: JsString) => Some(x.value) + case _ => None + } + + (name, polarity) match { + case (Some(n: String), Some(p: PortPolarity)) => Some(PolarizedPort(n, p)) + case _ => None + } + } +} + +// A SRAM memory port +case class MacroPort( + address: PolarizedPort, + clock: Option[PolarizedPort] = None, + writeEnable: Option[PolarizedPort] = None, + readEnable: Option[PolarizedPort] = None, + chipEnable: Option[PolarizedPort] = None, + output: Option[PolarizedPort] = None, + input: Option[PolarizedPort] = None, + maskPort: Option[PolarizedPort] = None, + maskGran: Option[Int] = None, + // For internal use only; these aren't port-specific. + width: Option[Int], + depth: Option[BigInt]) { + def effectiveMaskGran = maskGran.getOrElse(width.get) + + def toJSON(): JsObject = { + val keys: Seq[Tuple2[String, Option[Any]]] = Seq( + "address" -> Some(address), + "clock" -> clock, + "write enable" -> writeEnable, + "read enable" -> readEnable, + "chip enable" -> chipEnable, + "output" -> output, + "input" -> input, + "mask" -> maskPort, + "mask granularity" -> maskGran + ) + JsObject(keys.flatMap(k => { + val (key, value) = k + value match { + case Some(x: Int) => Seq(key -> JsNumber(x)) + case Some(x: PolarizedPort) => x.toSeqMap(key) + case _ => List() + } + })) + } + + // Check that all port names are unique. + private val polarizedPorts = + List(Some(address), clock, writeEnable, readEnable, chipEnable, output, input, maskPort).flatten + assert(polarizedPorts.distinct.size == polarizedPorts.size, "All port names must be unique") +} +object MacroPort { + def parseJSON(json: Map[String, JsValue]): Option[MacroPort] = parseJSON(json, None, None) + def parseJSON(json: Map[String, JsValue], width: Int, depth: BigInt): Option[MacroPort] = + parseJSON(json, Some(width), Some(depth)) + def parseJSON(json: Map[String, JsValue], width: Option[Int], depth: Option[BigInt]): Option[MacroPort] = { + val address = PolarizedPort.parseJSON(json, "address") + if (address == None) { + return None + } + + val clock = PolarizedPort.parseJSON(json, "clock") + // TODO: validate based on family (e.g. 1rw must have a write enable, etc) + val writeEnable = PolarizedPort.parseJSON(json, "write enable") + val readEnable = PolarizedPort.parseJSON(json, "read enable") + val chipEnable = PolarizedPort.parseJSON(json, "chip enable") + + val output = PolarizedPort.parseJSON(json, "output") + val input = PolarizedPort.parseJSON(json, "input") + + val maskPort = PolarizedPort.parseJSON(json, "mask") + val maskGran: Option[Int] = json.get("mask granularity") match { + case Some(x: JsNumber) => Some(x.value.intValue) + case _ => None + } + + if (maskPort.isDefined != maskGran.isDefined) { + return None + } + + Some( + MacroPort( + width = width, + depth = depth, + address = address.get, + clock = clock, + writeEnable = writeEnable, + readEnable = readEnable, + chipEnable = chipEnable, + output = output, + input = input, + maskPort = maskPort, + maskGran = maskGran + ) + ) + } +} + +// Port polarity +trait PortPolarity +case object ActiveLow extends PortPolarity +case object ActiveHigh extends PortPolarity +case object NegativeEdge extends PortPolarity +case object PositiveEdge extends PortPolarity +object PortPolarity { + implicit def toPortPolarity(s: String): PortPolarity = (s: @unchecked) match { + case "active low" => ActiveLow + case "active high" => ActiveHigh + case "negative edge" => NegativeEdge + case "positive edge" => PositiveEdge + } + implicit def toPortPolarity(s: Option[String]): Option[PortPolarity] = + s.map(toPortPolarity) + + implicit def toString(p: PortPolarity): String = { + p match { + case ActiveLow => "active low" + case ActiveHigh => "active high" + case NegativeEdge => "negative edge" + case PositiveEdge => "positive edge" + } + } +} diff --git a/src/main/scala/mdf/macrolib/Utils.scala b/src/main/scala/mdf/macrolib/Utils.scala new file mode 100644 index 00000000..86d78a24 --- /dev/null +++ b/src/main/scala/mdf/macrolib/Utils.scala @@ -0,0 +1,96 @@ +package mdf.macrolib + +import play.api.libs.json._ + +import java.io.FileNotFoundException +import scala.collection.mutable.ListBuffer +import scala.language.implicitConversions + +object Utils { + // Read a MDF file from a String. + def readMDFFromString(str: String): Option[Seq[Macro]] = { + Json.parse(str) match { + // Make sure that the document is a list. + case arr: JsArray => { + val result: List[Option[Macro]] = arr.as[List[Map[String, JsValue]]].map { obj => + // Check the type of object. + val objTypeStr: String = obj.get("type") match { + case Some(x: JsString) => x.as[String] + case _ => return None // error, no type found + } + objTypeStr match { + case "filler cell" | "metal filler cell" => FillerMacroBase.parseJSON(obj) + case "sram" => SRAMMacro.parseJSON(obj) + case "sramcompiler" => SRAMCompiler.parseJSON(obj) + case "io_properties" => IOProperties.parseJSON(obj) + case "flipchip" => FlipChipMacro.parseJSON(obj) + case _ => None // skip unknown macro types + } + } + // Remove all the Nones and convert back to Seq[Macro] + Some(result.filter { x => x != None }.map { x => x.get }) + } + case _ => None + } + } + + // Read a MDF file from a path. + def readMDFFromPath(path: Option[String]): Option[Seq[Macro]] = { + path match { + case None => None + // Read file into string and parse + case Some(p) => + try { + Utils.readMDFFromString(scala.io.Source.fromFile(p).mkString) + } catch { + case f: FileNotFoundException => + println(s"FILE NOT FOUND $p in dir ${os.pwd}") + throw f + } + } + } + + // Write a MDF file to a String. + def writeMDFToString(s: Seq[Macro]): String = { + Json.prettyPrint(JsArray(s.map(_.toJSON))) + } + + // Write a MDF file from a path. + // Returns true upon success. + def writeMDFToPath(path: Option[String], s: Seq[Macro]): Boolean = { + path match { + case None => false + // Read file into string and parse + case Some(p: String) => { + import java.io._ + val pw = new PrintWriter(new File(p)) + pw.write(writeMDFToString(s)) + val error = pw.checkError + pw.close() + !error + } + } + } + + // Write a macro file to a String. + def writeMacroToString(s: Macro): String = { + Json.prettyPrint(s.toJSON) + } + + // Write a Macro file from a path. + // Returns true upon success. + def writeMacroToPath(path: Option[String], s: Macro): Boolean = { + path match { + case None => false + // Read file into string and parse + case Some(p: String) => { + import java.io._ + val pw = new PrintWriter(new File(p)) + pw.write(writeMacroToString(s)) + val error = pw.checkError + pw.close() + !error + } + } + } +} diff --git a/tapeout/src/test/resources/PadAnnotationVerilogPart.v b/src/test/resources/PadAnnotationVerilogPart.v similarity index 100% rename from tapeout/src/test/resources/PadAnnotationVerilogPart.v rename to src/test/resources/PadAnnotationVerilogPart.v diff --git a/src/test/resources/bumps.json b/src/test/resources/bumps.json new file mode 100644 index 00000000..21b93381 --- /dev/null +++ b/src/test/resources/bumps.json @@ -0,0 +1,41 @@ +[ + { + "name" : "example", + "type" : "flipchip", + "bump_dimensions" : [27,27], + "bump_locations" : [ + ["-", "GND", "VDDC0_SEL[0]", "VDDC0_SEL[1]", "VDDC1_SEL[0]", "VDDC1_SEL[1]", "VDDC2_SEL[0]", "VDDC2_SEL[1]", "VDDC3_SEL[0]", "VDDC3_SEL[1]", "VDDC0_EN", "VDDC1_EN", "VDDC2_EN", "VDDC3_EN", "CCLK0", "CCLK1", "CCLK2", "RESET", "BOOT", "I2C_SDA", "I2C_SCL", "SPI_SCLK", "SPI_MOSI", "SPI_MISO", "SPI_SS_L", "GND", "-"], + [ "GND", "", "", "", "GND", "GND","GPIO[1]", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8","UART_RX","UART_TX", "GND", "GND", "GND", "GND", "", "", "", "GND"], + + ["TXP0", "VDDA", "VDDA", "GND", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "GND", "VDDA", "VDDA", "TXP4"], + ["TXN0", "VDDA", "VDDA", "GND", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "GND", "VDDA", "VDDA", "TXN4"], + [ "GND", "", "", "", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "", "", "", "GND"], + ["RXP0", "VDDA", "VDDA", "GND", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "GND", "VDDA", "VDDA", "RXP4"], + ["RXN0", "VDDA", "VDDA", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "VDDA", "VDDA", "RXN4"], + [ "GND", "", "", "", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "", "", "", "GND"], + + ["TXP1", "VDDA", "VDDA", "GND", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "GND", "VDDA", "VDDA", "TXP5"], + ["TXN1", "VDDA", "VDDA", "GND", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "GND", "VDDA", "VDDA", "TXN5"], + [ "GND", "", "", "", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "", "", "", "GND"], + ["RXP1", "VDDA", "VDDA", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "VDDA", "VDDA", "RXP5"], + ["RXN1", "VDDA", "VDDA", "GND", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "GND", "GND", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "GND", "VDDA", "VDDA", "RXN5"], + [ "GND", "", "", "", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "VDDC1", "GND", "GND", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC0", "VDDC0", "VDDC0", "VDDC0", "", "", "", "GND"], + + ["TXP2", "VDDA", "VDDA", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "VDDA", "VDDA", "TXP6"], + ["TXN2", "VDDA", "VDDA", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "VDDA", "VDDA", "TXN6"], + [ "GND", "", "", "", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "", "", "", "GND"], + ["RXP2", "VDDA", "VDDA", "GND", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC2", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "VDDC3", "GND", "VDDA", "VDDA", "RXP6"], + ["RXN2", "VDDA", "VDDA", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "VDDA", "VDDA", "RXN6"], + [ "GND", "", "", "", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "GND", "", "", "", "GND"], + + ["TXP3", "VDDA", "VDDA", "GND", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "GND", "VDDA", "VDDA", "TXP7"], + ["TXN3", "VDDA", "VDDA", "GND", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "VDD0V8", "GND", "VDDA", "VDDA", "TXN7"], + [ "GND", "", "", "", "-", "SERIAL_IN_READY", "-", "-", "SERIAL_IN_VALID", "-", "-", "-", "-", "", "-", "SERIAL_OUT_VALID", "-", "-", "SERIAL_OUT_READY", "-", "-", "GPIO[0]", "-", "", "", "", "GND"], + ["RXP3", "VDDA", "VDDA", "GND", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "GND", "VDDA", "VDDA", "RXP7"], + ["RXN3", "VDDA", "VDDA", "GND", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "GND", "VDDA", "VDDA", "RXN7"], + + [ "GND", "", "", "", "GND", "GND", "GND", "GND", "GND", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8", "VDD1V8", "GND", "GND", "GND", "GND", "GND", "", "", "", "GND"], + ["-", "GND", "REFCLK0P", "REFCLK0N", "GND", "SERIAL_OUT[0]", "SERIAL_OUT[1]", "SERIAL_OUT[2]", "SERIAL_OUT[3]", "SERIAL_IN[0]", "SERIAL_IN[1]", "SERIAL_IN[2]", "SERIAL_IN[3]", "JTAG_TMS", "JTAG_TCK", "JTAG_TDO", "JTAG_TDI", "CLKSEL", "PLLCLK_OUT", "GND", "PLLREFCLKP", "PLLREFCLKN", "GND", "REFCLK1P", "REFCLK1N", "GND", "-"] + ] + } +] diff --git a/src/test/resources/io_properties.json b/src/test/resources/io_properties.json new file mode 100644 index 00000000..93b945a3 --- /dev/null +++ b/src/test/resources/io_properties.json @@ -0,0 +1,663 @@ +[ + { + "name": "My IOs", + "type": "io_properties", + "top": "EAGLE", + "ios": [ + { + "name": "GND", + "type": "ground" + }, + { + "name": "VDD0V8", + "type": "power" + }, + { + "name": "VDD1V8", + "type": "power" + }, + { + "name": "VDDC0", + "type": "power" + }, + { + "name": "VDDC1", + "type": "power" + }, + { + "name": "VDDC2", + "type": "power" + }, + { + "name": "VDDC3", + "type": "power" + }, + { + "name": "VDDA", + "type": "power" + }, + { + "name": "VDDC0_SEL[1:0]", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "VDDC1_SEL[1:0]", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "VDDC2_SEL[1:0]", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "VDDC3_SEL[1:0]", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "VDDDC0_EN", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "VDDDC1_EN", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "VDDDC2_EN", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "VDDDC3_EN", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "CCLK0", + "type": "digital", + "direction": "input", + "termination": 50, + "termination_type": "single", + "termination_reference": "GND" + }, + { + "name": "CCLK1", + "type": "digital", + "direction": "input", + "termination": 50, + "termination_type": "single", + "termination_reference": "GND" + }, + { + "name": "CCLK2", + "type": "digital", + "direction": "input", + "termination": 50, + "termination_type": "single", + "termination_reference": "GND" + }, + { + "name": "RESET", + "type": "digital", + "direction": "input", + "termination": "CMOS" + }, + { + "name": "BOOT", + "type": "digital", + "direction": "input", + "termination": "CMOS" + }, + { + "name": "I2C_SDA", + "type": "digital", + "direction": "inout", + "termination": "open-drain" + }, + { + "name": "I2C_SCL", + "type": "digital", + "direction": "inout", + "termination": "open-drain" + }, + { + "name": "SPI_SCLK", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "SPI_MOSI", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "SPI_MISO", + "type": "digital", + "direction": "input", + "termination": "CMOS" + }, + { + "name": "SPI_SS_L", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "GPIO[1:0]", + "type": "digital", + "direction": "inout", + "termination": "CMOS" + }, + { + "name": "UART_RX", + "type": "digital", + "direction": "input", + "termination": "CMOS" + }, + { + "name": "UART_TX", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "SERIAL_IN_READY", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "SERIAL_IN_VALID", + "type": "digital", + "direction": "input", + "termination": "CMOS" + }, + { + "name": "SERIAL_OUT_READY", + "type": "digital", + "direction": "input", + "termination": "CMOS" + }, + { + "name": "SERIAL_OUT_VALID", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "SERIAL_OUT[3:0]", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "SERIAL_IN[3:0]", + "type": "digital", + "direction": "input", + "termination": "CMOS" + }, + { + "name": "REFCLK0P", + "type": "analog", + "direction": "input", + "match": [ + "REFCLK0N" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "REFCLK0N", + "type": "analog", + "direction": "input", + "match": [ + "REFCLK0P" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "REFCLK1N", + "type": "analog", + "direction": "input", + "match": [ + "REFCLK1P" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "REFCLK1P", + "type": "analog", + "direction": "input", + "match": [ + "REFCLK1N" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "PLLREFCLKP", + "type": "analog", + "direction": "input", + "match": [ + "PLLREFCLKP" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "PLLREFCLKN", + "type": "analog", + "direction": "input", + "match": [ + "PLLREFCLKP" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "JTAG_TMS", + "type": "digital", + "direction": "input", + "termination": "CMOS" + }, + { + "name": "JTAG_TCK", + "type": "digital", + "direction": "input", + "termination": "CMOS" + }, + { + "name": "JTAG_TDI", + "type": "digital", + "direction": "input", + "termination": "CMOS" + }, + { + "name": "JTAG_TDO", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "PLLCLK_OUT", + "type": "digital", + "direction": "output", + "termination": "CMOS" + }, + { + "name": "TXP0", + "type": "analog", + "direction": "output", + "match": [ + "TXN0" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXN0", + "type": "analog", + "direction": "output", + "match": [ + "TXP0" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXP0", + "type": "analog", + "direction": "output", + "match": [ + "RXN0" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXN1", + "type": "analog", + "direction": "input", + "match": [ + "RXP1" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXP1", + "type": "analog", + "direction": "output", + "match": [ + "TXN1" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXN1", + "type": "analog", + "direction": "output", + "match": [ + "TXP1" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXP1", + "type": "analog", + "direction": "output", + "match": [ + "RXN1" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXN1", + "type": "analog", + "direction": "input", + "match": [ + "RXP1" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXP2", + "type": "analog", + "direction": "output", + "match": [ + "TXN2" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXN2", + "type": "analog", + "direction": "output", + "match": [ + "TXP2" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXP2", + "type": "analog", + "direction": "output", + "match": [ + "RXN2" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXN2", + "type": "analog", + "direction": "input", + "match": [ + "RXP2" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXP3", + "type": "analog", + "direction": "output", + "match": [ + "TXN3" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXN3", + "type": "analog", + "direction": "output", + "match": [ + "TXP3" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXP3", + "type": "analog", + "direction": "output", + "match": [ + "RXN3" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXN3", + "type": "analog", + "direction": "input", + "match": [ + "RXP3" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXP4", + "type": "analog", + "direction": "output", + "match": [ + "TXN4" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXN4", + "type": "analog", + "direction": "output", + "match": [ + "TXP4" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXP4", + "type": "analog", + "direction": "output", + "match": [ + "RXN4" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXN4", + "type": "analog", + "direction": "input", + "match": [ + "RXP4" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXP5", + "type": "analog", + "direction": "output", + "match": [ + "TXN5" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXN5", + "type": "analog", + "direction": "output", + "match": [ + "TXP5" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXP5", + "type": "analog", + "direction": "output", + "match": [ + "RXN5" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXN5", + "type": "analog", + "direction": "input", + "match": [ + "RXP5" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXP6", + "type": "analog", + "direction": "output", + "match": [ + "TXN6" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXN6", + "type": "analog", + "direction": "output", + "match": [ + "TXP6" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXP6", + "type": "analog", + "direction": "output", + "match": [ + "RXN6" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXN6", + "type": "analog", + "direction": "input", + "match": [ + "RXP6" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXP7", + "type": "analog", + "direction": "output", + "match": [ + "TXN7" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "TXN7", + "type": "analog", + "direction": "output", + "match": [ + "TXP7" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXP7", + "type": "analog", + "direction": "output", + "match": [ + "RXN7" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + }, + { + "name": "RXN7", + "type": "analog", + "direction": "input", + "match": [ + "RXP7" + ], + "termination": 100, + "termination_type": "differential", + "termination_reference": "GND" + } + ] + } +] diff --git a/macros/src/test/resources/lib-BOOMTest.json b/src/test/resources/lib-BOOMTest.json similarity index 100% rename from macros/src/test/resources/lib-BOOMTest.json rename to src/test/resources/lib-BOOMTest.json diff --git a/macros/src/test/resources/lib-MaskPortTest.json b/src/test/resources/lib-MaskPortTest.json similarity index 100% rename from macros/src/test/resources/lib-MaskPortTest.json rename to src/test/resources/lib-MaskPortTest.json diff --git a/macros/src/test/resources/lib-WriteEnableTest.json b/src/test/resources/lib-WriteEnableTest.json similarity index 100% rename from macros/src/test/resources/lib-WriteEnableTest.json rename to src/test/resources/lib-WriteEnableTest.json diff --git a/macros/src/test/scala/barstools/macros/CostFunction.scala b/src/test/scala/barstools/macros/CostFunction.scala similarity index 100% rename from macros/src/test/scala/barstools/macros/CostFunction.scala rename to src/test/scala/barstools/macros/CostFunction.scala diff --git a/macros/src/test/scala/barstools/macros/Functional.scala b/src/test/scala/barstools/macros/Functional.scala similarity index 100% rename from macros/src/test/scala/barstools/macros/Functional.scala rename to src/test/scala/barstools/macros/Functional.scala diff --git a/macros/src/test/scala/barstools/macros/MacroCompilerSpec.scala b/src/test/scala/barstools/macros/MacroCompilerSpec.scala similarity index 100% rename from macros/src/test/scala/barstools/macros/MacroCompilerSpec.scala rename to src/test/scala/barstools/macros/MacroCompilerSpec.scala diff --git a/macros/src/test/scala/barstools/macros/Masks.scala b/src/test/scala/barstools/macros/Masks.scala similarity index 79% rename from macros/src/test/scala/barstools/macros/Masks.scala rename to src/test/scala/barstools/macros/Masks.scala index c472669a..43d6b3d6 100644 --- a/macros/src/test/scala/barstools/macros/Masks.scala +++ b/src/test/scala/barstools/macros/Masks.scala @@ -27,7 +27,9 @@ class Masks_FourTypes_NonMaskedMem_NonMaskedLib override lazy val libWidth = 8 override lazy val libMaskGran = None - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_FourTypes_NonMaskedMem_MaskedLib @@ -40,7 +42,9 @@ class Masks_FourTypes_NonMaskedMem_MaskedLib override lazy val libWidth = 8 override lazy val libMaskGran = Some(2) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_FourTypes_MaskedMem_NonMaskedLib @@ -53,7 +57,9 @@ class Masks_FourTypes_MaskedMem_NonMaskedLib override lazy val libWidth = 8 override lazy val libMaskGran = None - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_FourTypes_MaskedMem_NonMaskedLib_SmallerMaskGran @@ -66,7 +72,9 @@ class Masks_FourTypes_MaskedMem_NonMaskedLib_SmallerMaskGran override lazy val libWidth = 8 override lazy val libMaskGran = None - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_FourTypes_MaskedMem_MaskedLib @@ -79,7 +87,9 @@ class Masks_FourTypes_MaskedMem_MaskedLib override lazy val libWidth = 16 override lazy val libMaskGran = Some(4) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_FourTypes_MaskedMem_MaskedLib_SameMaskGran @@ -92,7 +102,9 @@ class Masks_FourTypes_MaskedMem_MaskedLib_SameMaskGran override lazy val libWidth = 16 override lazy val libMaskGran = Some(8) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_FourTypes_MaskedMem_MaskedLib_SmallerMaskGran @@ -105,7 +117,9 @@ class Masks_FourTypes_MaskedMem_MaskedLib_SmallerMaskGran override lazy val libWidth = 32 override lazy val libMaskGran = Some(8) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } // Bit-mask memories to non-masked libs whose width is larger than 1. @@ -117,7 +131,9 @@ class Masks_BitMaskedMem_NonMaskedLib extends MacroCompilerSpec with HasSRAMGene override lazy val libWidth = 8 override lazy val libMaskGran = None - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } // FPGA-style byte-masked memories. @@ -131,7 +147,9 @@ class Masks_FPGAStyle_32_8 override lazy val memMaskGran = Some(32) override lazy val libMaskGran = Some(8) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } // Simple powers of two with bit-masked lib. @@ -145,7 +163,9 @@ class Masks_PowersOfTwo_8_1 override lazy val memMaskGran = Some(8) override lazy val libMaskGran = Some(1) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_PowersOfTwo_16_1 @@ -157,7 +177,9 @@ class Masks_PowersOfTwo_16_1 override lazy val memMaskGran = Some(16) override lazy val libMaskGran = Some(1) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_PowersOfTwo_32_1 @@ -169,7 +191,9 @@ class Masks_PowersOfTwo_32_1 override lazy val memMaskGran = Some(32) override lazy val libMaskGran = Some(1) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_PowersOfTwo_64_1 @@ -181,7 +205,9 @@ class Masks_PowersOfTwo_64_1 override lazy val memMaskGran = Some(64) override lazy val libMaskGran = Some(1) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } // Simple powers of two with non bit-masked lib. @@ -195,7 +221,9 @@ class Masks_PowersOfTwo_32_4 override lazy val memMaskGran = Some(32) override lazy val libMaskGran = Some(4) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_PowersOfTwo_32_8 @@ -207,7 +235,9 @@ class Masks_PowersOfTwo_32_8 override lazy val memMaskGran = Some(32) override lazy val libMaskGran = Some(8) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_PowersOfTwo_8_8 @@ -219,7 +249,9 @@ class Masks_PowersOfTwo_8_8 override lazy val memMaskGran = Some(8) override lazy val libMaskGran = Some(8) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } // Width as a multiple of the mask, bit-masked lib @@ -233,7 +265,9 @@ class Masks_IntegerMaskMultiple_20_10 override lazy val memMaskGran = Some(10) override lazy val libMaskGran = Some(1) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_IntegerMaskMultiple_21_7 @@ -258,7 +292,9 @@ class Masks_IntegerMaskMultiple_21_21 override lazy val memMaskGran = Some(21) override lazy val libMaskGran = Some(1) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_IntegerMaskMultiple_84_21 @@ -270,7 +306,9 @@ class Masks_IntegerMaskMultiple_84_21 override lazy val memMaskGran = Some(21) override lazy val libMaskGran = Some(1) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_IntegerMaskMultiple_92_23 @@ -282,7 +320,9 @@ class Masks_IntegerMaskMultiple_92_23 override lazy val memMaskGran = Some(23) override lazy val libMaskGran = Some(1) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_IntegerMaskMultiple_117_13 @@ -294,7 +334,9 @@ class Masks_IntegerMaskMultiple_117_13 override lazy val memMaskGran = Some(13) override lazy val libMaskGran = Some(1) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_IntegerMaskMultiple_160_20 @@ -306,7 +348,9 @@ class Masks_IntegerMaskMultiple_160_20 override lazy val memMaskGran = Some(20) override lazy val libMaskGran = Some(1) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class Masks_IntegerMaskMultiple_184_23 @@ -318,7 +362,9 @@ class Masks_IntegerMaskMultiple_184_23 override lazy val memMaskGran = Some(23) override lazy val libMaskGran = Some(1) - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } // Width as an non-integer multiple of the mask, bit-masked lib diff --git a/macros/src/test/scala/barstools/macros/MultiPort.scala b/src/test/scala/barstools/macros/MultiPort.scala similarity index 99% rename from macros/src/test/scala/barstools/macros/MultiPort.scala rename to src/test/scala/barstools/macros/MultiPort.scala index 1968f6aa..75eb20d7 100644 --- a/macros/src/test/scala/barstools/macros/MultiPort.scala +++ b/src/test/scala/barstools/macros/MultiPort.scala @@ -316,7 +316,6 @@ class SplitWidth_2rw_differentMasks extends MacroCompilerSpec with HasSRAMGenera lazy val memMaskGranB = 8 // these generators are run at constructor time override def generateMemSRAM() = { - println(memMaskGranB) SRAMMacro( name = mem_name, width = memWidth, diff --git a/macros/src/test/scala/barstools/macros/SRAMCompiler.scala b/src/test/scala/barstools/macros/SRAMCompiler.scala similarity index 100% rename from macros/src/test/scala/barstools/macros/SRAMCompiler.scala rename to src/test/scala/barstools/macros/SRAMCompiler.scala diff --git a/macros/src/test/scala/barstools/macros/SimpleSplitDepth.scala b/src/test/scala/barstools/macros/SimpleSplitDepth.scala similarity index 100% rename from macros/src/test/scala/barstools/macros/SimpleSplitDepth.scala rename to src/test/scala/barstools/macros/SimpleSplitDepth.scala diff --git a/macros/src/test/scala/barstools/macros/SimpleSplitWidth.scala b/src/test/scala/barstools/macros/SimpleSplitWidth.scala similarity index 100% rename from macros/src/test/scala/barstools/macros/SimpleSplitWidth.scala rename to src/test/scala/barstools/macros/SimpleSplitWidth.scala diff --git a/macros/src/test/scala/barstools/macros/SpecificExamples.scala b/src/test/scala/barstools/macros/SpecificExamples.scala similarity index 99% rename from macros/src/test/scala/barstools/macros/SpecificExamples.scala rename to src/test/scala/barstools/macros/SpecificExamples.scala index 334e3a73..1a957199 100644 --- a/macros/src/test/scala/barstools/macros/SpecificExamples.scala +++ b/src/test/scala/barstools/macros/SpecificExamples.scala @@ -27,7 +27,7 @@ class WriteEnableTest extends MacroCompilerSpec with HasSRAMGenerator { val lib = s"lib-WriteEnableTest.json" // lib. of mems to create it val v = s"WriteEnableTest.json" - override val libPrefix = "macros/src/test/resources" + override val libPrefix = "src/test/resources" val memSRAMs = mdf.macrolib.Utils .readMDFFromString(""" @@ -89,7 +89,9 @@ circuit cc_banks_0_ext : defname = fake_mem """ - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class MaskPortTest extends MacroCompilerSpec with HasSRAMGenerator { @@ -97,7 +99,7 @@ class MaskPortTest extends MacroCompilerSpec with HasSRAMGenerator { val lib = s"lib-MaskPortTest.json" // lib. of mems to create it val v = s"MaskPortTest.json" - override val libPrefix = "macros/src/test/resources" + override val libPrefix = "src/test/resources" val memSRAMs = mdf.macrolib.Utils .readMDFFromString(""" @@ -173,7 +175,9 @@ circuit cc_dir_ext : defname = fake_mem """ - compileExecuteAndTest(mem, lib, v, output) + it should "compile, exectue, and test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class BOOMTest extends MacroCompilerSpec with HasSRAMGenerator { @@ -181,10 +185,9 @@ class BOOMTest extends MacroCompilerSpec with HasSRAMGenerator { val lib = s"lib-BOOMTest.json" val v = s"BOOMTest.v" - override val libPrefix = "macros/src/test/resources" + override val libPrefix = "src/test/resources" - val memSRAMs = mdf.macrolib.Utils - .readMDFFromString(""" + val memSRAMs = mdf.macrolib.Utils.readMDFFromString(""" [ { "type" : "sram", "name" : "_T_182_ext", @@ -1345,7 +1348,9 @@ circuit smem_0_ext : defname = my_sram_1rw_64x8 """ - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute and test the boom test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class SmallTagArrayTest extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleTestGenerator { @@ -1378,7 +1383,9 @@ class SmallTagArrayTest extends MacroCompilerSpec with HasSRAMGenerator with Has | dout <= mux(UInt<1>("h1"), dout_0, UInt<26>("h0")) """.stripMargin - compileExecuteAndTest(mem, lib, v, output) + it should "compile, execute, and test, the small tag array test" in { + compileExecuteAndTest(mem, lib, v, output) + } } class RocketChipTest extends MacroCompilerSpec with HasSRAMGenerator { diff --git a/macros/src/test/scala/barstools/macros/SynFlops.scala b/src/test/scala/barstools/macros/SynFlops.scala similarity index 100% rename from macros/src/test/scala/barstools/macros/SynFlops.scala rename to src/test/scala/barstools/macros/SynFlops.scala diff --git a/tapeout/src/test/scala/barstools/tapeout/transforms/GenerateSpec.scala b/src/test/scala/barstools/tapeout/transforms/GenerateSpec.scala similarity index 68% rename from tapeout/src/test/scala/barstools/tapeout/transforms/GenerateSpec.scala rename to src/test/scala/barstools/tapeout/transforms/GenerateSpec.scala index cefd9759..b5c03c44 100644 --- a/tapeout/src/test/scala/barstools/tapeout/transforms/GenerateSpec.scala +++ b/src/test/scala/barstools/tapeout/transforms/GenerateSpec.scala @@ -7,6 +7,8 @@ import chisel3.experimental.ExtModule import chisel3.stage.ChiselStage import firrtl.FileUtils import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.must.Matchers.be +import org.scalatest.matchers.should.Matchers.convertToAnyShouldWrapper import java.io.{File, PrintWriter} @@ -57,37 +59,42 @@ class GenerateExampleTester extends MultiIOModule { } class GenerateSpec extends AnyFreeSpec { - "generate test data" in { - val targetDir = "test_run_dir/generate_spec_source" + + def generateTestData(targetDir: String): Unit = { FileUtils.makeDirectory(targetDir) - val printWriter = new PrintWriter(new File(s"$targetDir/GenerateExampleTester.fir")) - printWriter.write((new ChiselStage()).emitFirrtl(new GenerateExampleTester)) - printWriter.close() + new ChiselStage().emitFirrtl(new GenerateExampleTester, Array("--target-dir", targetDir)) - val blackBoxInverterText = """ - |module BlackBoxInverter( - | input [0:0] in, - | output [0:0] out - |); - | assign out = !in; - |endmodule - |""".stripMargin + val blackBoxInverterText = + """ + |module BlackBoxInverter( + | input [0:0] in, + | output [0:0] out + |); + | assign out = !in; + |endmodule + |""".stripMargin val printWriter2 = new PrintWriter(new File(s"$targetDir/BlackBoxInverter.v")) printWriter2.write(blackBoxInverterText) printWriter2.close() + } + "generate test data" in { + val targetDir = "test_run_dir/generate_spec_source" + generateTestData(targetDir) + new File(s"$targetDir/GenerateExampleTester.fir").exists() should be(true) } "generate top test" in { - val sourceDir = "test_run_dir/generate_spec_source" val targetDir = "test_run_dir/generate_spec" + generateTestData(targetDir) GenerateTop.main(Array( - "-i", s"$sourceDir/GenerateExampleTester.fir", + "-i", s"$targetDir/GenerateExampleTester.fir", "-o", s"$targetDir/GenerateExampleTester.v" )) + new File(s"$targetDir/GenerateExampleTester.v").exists() should be (true) } } diff --git a/src/test/scala/barstools/tapeout/transforms/GenerateTopSpec.scala b/src/test/scala/barstools/tapeout/transforms/GenerateTopSpec.scala new file mode 100644 index 00000000..a7a165a4 --- /dev/null +++ b/src/test/scala/barstools/tapeout/transforms/GenerateTopSpec.scala @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: Apache-2.0 + +package barstools.tapeout.transforms + +import chisel3.stage.ChiselStage +import firrtl.FileUtils +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should.Matchers + +import java.io.{File, PrintWriter} + +class GenerateTopSpec extends AnyFreeSpec with Matchers { + "Generate top and harness" - { + "should include the following transforms" in { + val targetDir = "test_run_dir/generate_top_and_harness" + val transformListName = s"$targetDir/ExampleModuleNeesResetInvertTransforms.log" + FileUtils.makeDirectory(targetDir) + (new ChiselStage).emitChirrtl(new ExampleModuleNeedsResetInverted, Array("--target-dir", targetDir)) + + GenerateTopAndHarness.main( + Array( + "-i", s"$targetDir/ExampleModuleNeedsResetInverted.fir", + "-ll", "info", + "--log-file", transformListName + ) + ) + + val output = FileUtils.getText(transformListName) + output should include("barstools.tapeout.transforms.AddSuffixToModuleNames") + output should include("barstools.tapeout.transforms.ConvertToExtMod") + output should include("barstools.tapeout.transforms.RemoveUnusedModules") + output should include("barstools.tapeout.transforms.AvoidExtModuleCollisions") + } + } + + "generate harness should be generated" ignore { + val targetDir = "test_run_dir/generate_top_spec" + val logOutputName = s"$targetDir/top_spec_output.log" + FileUtils.makeDirectory(targetDir) + + val input = FileUtils.getLinesResource("/BlackBoxFloatTester.fir") + val printWriter = new PrintWriter(new File(s"$targetDir/BlackBoxFloatTester.fir")) + printWriter.write(input.mkString("\n")) + printWriter.close() + + println(s"""Resource: ${input.mkString("\n")}""") + + GenerateTopAndHarness.main( + Array( + "--target-dir", "test_run_dir/generate_top_spec", + "-i", s"$targetDir/BlackBoxFloatTester.fir", + "-o", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.top.v", + "-tho", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.harness.v", + "-i", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.fir", + "--syn-top", "UnitTestSuite", + "--harness-top", "TestHarness", + "-faf", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.anno.json", + "-tsaof", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.top.anno.json", + "-tdf", "firrtl_black_box_resource_files.top.f", + "-tsf", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.top.fir", + "-thaof", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.harness.anno.json", + "-hdf", "firrtl_black_box_resource_files.harness.f", + "-thf", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.harness.fir", + "--infer-rw", + "--repl-seq-mem", "-c:TestHarness:-o:chipyard.unittest.TestHarness.IceNetUnitTestConfig.top.mems.conf", + "-thconf", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.harness.mems.conf", + "-td", "test_run_dir/from-ci", + "-ll", "info", + "--log-file", logOutputName + ) + ) + + val output = FileUtils.getText(logOutputName) + println(output) + } +} diff --git a/tapeout/src/test/scala/barstools/tapeout/transforms/ResetInverterSpec.scala b/src/test/scala/barstools/tapeout/transforms/ResetInverterSpec.scala similarity index 90% rename from tapeout/src/test/scala/barstools/tapeout/transforms/ResetInverterSpec.scala rename to src/test/scala/barstools/tapeout/transforms/ResetInverterSpec.scala index 701c7845..d18053f0 100644 --- a/tapeout/src/test/scala/barstools/tapeout/transforms/ResetInverterSpec.scala +++ b/src/test/scala/barstools/tapeout/transforms/ResetInverterSpec.scala @@ -22,7 +22,7 @@ class ExampleModuleNeedsResetInverted extends Module with ResetInverter { class ResetNSpec extends AnyFreeSpec with Matchers { "Inverting reset needs to be done throughout module in Chirrtl" in { - val chirrtl = (new ChiselStage).emitChirrtl(new ExampleModuleNeedsResetInverted) + val chirrtl = (new ChiselStage).emitChirrtl(new ExampleModuleNeedsResetInverted, Array("--target-dir", "test_run_dir/reset_n_spec")) chirrtl should include("input reset :") (chirrtl should not).include("input reset_n :") (chirrtl should not).include("node reset = not(reset_n)") @@ -32,7 +32,7 @@ class ResetNSpec extends AnyFreeSpec with Matchers { // generate low-firrtl val firrtl = (new ChiselStage) .execute( - Array("-X", "low"), + Array("-X", "low", "--target-dir", "test_run_dir/reset_inverting_spec"), Seq(ChiselGeneratorAnnotation(() => new ExampleModuleNeedsResetInverted)) ) .collect { diff --git a/tapeout/src/test/scala/barstools/tapeout/transforms/retime/RetimeSpec.scala b/src/test/scala/barstools/tapeout/transforms/retime/RetimeSpec.scala similarity index 100% rename from tapeout/src/test/scala/barstools/tapeout/transforms/retime/RetimeSpec.scala rename to src/test/scala/barstools/tapeout/transforms/retime/RetimeSpec.scala diff --git a/src/test/scala/mdf/macrolib/ConfReaderSpec.scala b/src/test/scala/mdf/macrolib/ConfReaderSpec.scala new file mode 100644 index 00000000..58680cd7 --- /dev/null +++ b/src/test/scala/mdf/macrolib/ConfReaderSpec.scala @@ -0,0 +1,101 @@ +package mdf.macrolib + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +class ConfReaderSpec extends AnyFlatSpec with Matchers { + + /** Generate a read port in accordance with RenameAnnotatedMemoryPorts. */ + def generateReadPort(num: Int, width: Int, depth: Int): MacroPort = { + MacroPort( + address = PolarizedPort(s"R${num}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"R${num}_clk", PositiveEdge)), + output = Some(PolarizedPort(s"R${num}_data", ActiveHigh)), + width = Some(width), + depth = Some(depth) + ) + } + + /** Generate a write port in accordance with RenameAnnotatedMemoryPorts. */ + def generateWritePort(num: Int, width: Int, depth: Int, maskGran: Option[Int] = None): MacroPort = { + MacroPort( + address = PolarizedPort(s"W${num}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"W${num}_clk", PositiveEdge)), + input = Some(PolarizedPort(s"W${num}_data", ActiveHigh)), + maskPort = if (maskGran.isDefined) Some(PolarizedPort(s"W${num}_mask", ActiveHigh)) else None, + maskGran = maskGran, + width = Some(184), + depth = Some(128) + ) + } + + "ConfReader" should "read a 1rw conf line" in { + val confStr = "name Foo_Bar_mem123_ext depth 128 width 184 ports mrw mask_gran 23" + ConfReader.readSingleLine(confStr) shouldBe SRAMMacro( + name = "Foo_Bar_mem123_ext", + width = 184, + depth = 128, + family = "1rw", + ports = List( + MacroPort( + address = PolarizedPort("RW0_addr", ActiveHigh), + clock = Some(PolarizedPort("RW0_clk", PositiveEdge)), + writeEnable = Some(PolarizedPort("RW0_wmode", ActiveHigh)), + output = Some(PolarizedPort("RW0_wdata", ActiveHigh)), + input = Some(PolarizedPort("RW0_rdata", ActiveHigh)), + maskPort = Some(PolarizedPort("RW0_wmask", ActiveHigh)), + maskGran = Some(23), + width = Some(184), + depth = Some(128) + ) + ), + extraPorts = List() + ) + } + + "ConfReader" should "read a 1r1w conf line" in { + val confStr = "name Foo_Bar_mem321_ext depth 128 width 184 ports read,mwrite mask_gran 23" + ConfReader.readSingleLine(confStr) shouldBe SRAMMacro( + name = "Foo_Bar_mem321_ext", + width = 184, + depth = 128, + family = "1r1w", + ports = List( + generateReadPort(0, 184, 128), + generateWritePort(0, 184, 128, Some(23)) + ), + extraPorts = List() + ) + } + + "ConfReader" should "read a mixed 1r2w conf line" in { + val confStr = "name Foo_Bar_mem321_ext depth 128 width 184 ports read,mwrite,write mask_gran 23" + ConfReader.readSingleLine(confStr) shouldBe SRAMMacro( + name = "Foo_Bar_mem321_ext", + width = 184, + depth = 128, + family = "1r2w", + ports = List( + generateReadPort(0, 184, 128), + generateWritePort(0, 184, 128, Some(23)), + generateWritePort(1, 184, 128) + ), + extraPorts = List() + ) + } + + "ConfReader" should "read a 42r29w conf line" in { + val confStr = + "name Foo_Bar_mem321_ext depth 128 width 184 ports " + (Seq.fill(42)("read") ++ Seq.fill(29)("mwrite")) + .mkString(",") + " mask_gran 23" + ConfReader.readSingleLine(confStr) shouldBe SRAMMacro( + name = "Foo_Bar_mem321_ext", + width = 184, + depth = 128, + family = "42r29w", + ports = ((0 to 41).map((num: Int) => generateReadPort(num, 184, 128))) ++ + ((0 to 28).map((num: Int) => generateWritePort(num, 184, 128, Some(23)))), + extraPorts = List() + ) + } +} diff --git a/src/test/scala/mdf/macrolib/FlipChipMacroSpec.scala b/src/test/scala/mdf/macrolib/FlipChipMacroSpec.scala new file mode 100644 index 00000000..c6a9e7ce --- /dev/null +++ b/src/test/scala/mdf/macrolib/FlipChipMacroSpec.scala @@ -0,0 +1,15 @@ +package mdf.macrolib + +import firrtl.FileUtils +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +class FlipChipMacroSpec extends AnyFlatSpec with Matchers { + "Parsing flipchipmacros" should "work" in { + val stream = FileUtils.getLinesResource("/bumps.json") + val mdf = Utils.readMDFFromString(stream.mkString("\n")) + mdf match { + case Some(Seq(fcp: FlipChipMacro)) => println(fcp.visualize) + } + } +} diff --git a/src/test/scala/mdf/macrolib/IOMacroSpec.scala b/src/test/scala/mdf/macrolib/IOMacroSpec.scala new file mode 100644 index 00000000..c6ab6e10 --- /dev/null +++ b/src/test/scala/mdf/macrolib/IOMacroSpec.scala @@ -0,0 +1,67 @@ +package mdf.macrolib + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +class IOMacroSpec extends AnyFlatSpec with Matchers { + "Ground IOs" should "be detected" in { + val json = + """{ + | "name" : "GND", + | "type" : "ground" + |}""".stripMargin + val m = JSONUtils.readStringValueMap(json).get + IOMacro.parseJSON(m) shouldBe Some(IOMacro("GND", Ground)) + } + "Power IOs" should "be detected" in { + val json = + """{ + | "name" : "VDD0V8", + | "type" : "power" + |}""".stripMargin + val m = JSONUtils.readStringValueMap(json).get + IOMacro.parseJSON(m) shouldBe Some(IOMacro("VDD0V8", Power)) + } + "Digital IOs" should "be detected" in { + val json = + """{ + | "name" : "VDDC0_SEL[1:0]", + | "type" : "digital", + | "direction" : "output", + | "termination" : "CMOS" + |}""".stripMargin + val m = JSONUtils.readStringValueMap(json).get + IOMacro.parseJSON(m) shouldBe Some(IOMacro("VDDC0_SEL[1:0]", Digital, Some(Output), Some(CMOS))) + } + "Digital IOs with termination" should "be detected" in { + val json = + """{ + | "name" : "CCLK1", + | "type" : "digital", + | "direction" : "input", + | "termination" : 50, + | "terminationType" : "single", + | "terminationReference" : "GND" + |}""".stripMargin + val m = JSONUtils.readStringValueMap(json).get + IOMacro.parseJSON(m) shouldBe Some( + IOMacro("CCLK1", Digital, Some(Input), Some(Resistive(50)), Some(Single), Some("GND")) + ) + } + "Digital IOs with matching and termination" should "be detected" in { + val json = + """{ + | "name" : "REFCLK0P", + | "type" : "analog", + | "direction" : "input", + | "match" : ["REFCLK0N"], + | "termination" : 100, + | "terminationType" : "differential", + | "terminationReference" : "GND" + |}""".stripMargin + val m = JSONUtils.readStringValueMap(json).get + IOMacro.parseJSON(m) shouldBe Some( + IOMacro("REFCLK0P", Analog, Some(Input), Some(Resistive(100)), Some(Differential), Some("GND"), List("REFCLK0N")) + ) + } +} diff --git a/src/test/scala/mdf/macrolib/IOPropertiesSpec.scala b/src/test/scala/mdf/macrolib/IOPropertiesSpec.scala new file mode 100644 index 00000000..b09422a7 --- /dev/null +++ b/src/test/scala/mdf/macrolib/IOPropertiesSpec.scala @@ -0,0 +1,15 @@ +package mdf.macrolib + +import firrtl.FileUtils +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +class IOPropertiesSpec extends AnyFlatSpec with Matchers { + "Parsing io_properties" should "work" in { + val stream = FileUtils.getLinesResource("/io_properties.json") + val mdf = Utils.readMDFFromString(stream.mkString("\n")) + mdf match { + case Some(Seq(fcp: IOProperties)) => + } + } +} diff --git a/src/test/scala/mdf/macrolib/MacroLibOutput.scala b/src/test/scala/mdf/macrolib/MacroLibOutput.scala new file mode 100644 index 00000000..85feaffa --- /dev/null +++ b/src/test/scala/mdf/macrolib/MacroLibOutput.scala @@ -0,0 +1,270 @@ +package mdf.macrolib + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import play.api.libs.json._ + +import java.io.File + +// Output tests (Scala -> JSON). +// TODO: unify these tests with the input tests? + +trait HasAwesomeMemData { + def getAwesomeMem() = { + SRAMMacro( + name = "awesome_mem", + width = 32, + depth = 1024, + family = "1rw", + ports = Seq( + MacroPort( + address = PolarizedPort(name = "addr", polarity = ActiveHigh), + clock = Some(PolarizedPort(name = "clk", polarity = PositiveEdge)), + writeEnable = Some(PolarizedPort(name = "write_enable", polarity = ActiveHigh)), + readEnable = Some(PolarizedPort(name = "read_enable", polarity = ActiveHigh)), + chipEnable = Some(PolarizedPort(name = "chip_enable", polarity = ActiveHigh)), + output = Some(PolarizedPort(name = "data_out", polarity = ActiveHigh)), + input = Some(PolarizedPort(name = "data_in", polarity = ActiveHigh)), + maskPort = Some(PolarizedPort(name = "mask", polarity = ActiveHigh)), + maskGran = Some(8), + width = Some(32), + depth = Some(1024) // These numbers don't matter. + ) + ), + extraPorts = List() + ) + } + + def getAwesomeMemJSON(): String = { + """ + | { + | "type": "sram", + | "name": "awesome_mem", + | "width": 32, + | "depth": "1024", + | "mux": 1, + | "mask":true, + | "family": "1rw", + | "ports": [ + | { + | "address port name": "addr", + | "address port polarity": "active high", + | "clock port name": "clk", + | "clock port polarity": "positive edge", + | "write enable port name": "write_enable", + | "write enable port polarity": "active high", + | "read enable port name": "read_enable", + | "read enable port polarity": "active high", + | "chip enable port name": "chip_enable", + | "chip enable port polarity": "active high", + | "output port name": "data_out", + | "output port polarity": "active high", + | "input port name": "data_in", + | "input port polarity": "active high", + | "mask port name": "mask", + | "mask port polarity": "active high", + | "mask granularity": 8 + | } + | ] + | } + |""".stripMargin + } +} + +// Tests for filler macros. +class FillerMacroOutput extends AnyFlatSpec with Matchers { + "Valid lvt macro" should "be generated" in { + val expected = """ + | { + | "type": "filler cell", + | "name": "MY_FILLER_CELL", + | "vt": "lvt" + | } + |""".stripMargin + FillerMacro("MY_FILLER_CELL", "lvt").toJSON shouldBe Json.parse(expected) + } + + "Valid metal macro" should "be generated" in { + val expected = """ + | { + | "type": "metal filler cell", + | "name": "METAL_FILLER_CELL", + | "vt": "lvt" + | } + |""".stripMargin + MetalFillerMacro("METAL_FILLER_CELL", "lvt").toJSON shouldBe Json.parse(expected) + } + + "Valid hvt macro" should "be generated" in { + val expected = """ + | { + | "type": "filler cell", + | "name": "HVT_CELL_PROP", + | "vt": "hvt" + | } + |""".stripMargin + FillerMacro("HVT_CELL_PROP", "hvt").toJSON shouldBe Json.parse(expected) + } +} + +class SRAMPortOutput extends AnyFlatSpec with Matchers { + "Extra port" should "be generated" in { + val m = MacroExtraPort( + name = "TIE_HIGH", + width = 8, + portType = Constant, + value = ((1 << 8) - 1) + ) + val expected = """ + | { + | "type": "constant", + | "name": "TIE_HIGH", + | "width": 8, + | "value": 255 + | } + |""".stripMargin + m.toJSON shouldBe Json.parse(expected) + } + + "Minimal write port" should "be generated" in { + val m = MacroPort( + address = PolarizedPort(name = "addr", polarity = ActiveHigh), + clock = Some(PolarizedPort(name = "clk", polarity = PositiveEdge)), + writeEnable = Some(PolarizedPort(name = "write_enable", polarity = ActiveHigh)), + input = Some(PolarizedPort(name = "data_in", polarity = ActiveHigh)), + width = Some(32), + depth = Some(1024) // These numbers don't matter. + ) + val expected = """ + | { + | "address port name": "addr", + | "address port polarity": "active high", + | "clock port name": "clk", + | "clock port polarity": "positive edge", + | "write enable port name": "write_enable", + | "write enable port polarity": "active high", + | "input port name": "data_in", + | "input port polarity": "active high" + | } + |""".stripMargin + m.toJSON shouldBe Json.parse(expected) + } + + "Minimal read port" should "be generated" in { + val m = MacroPort( + address = PolarizedPort(name = "addr", polarity = ActiveHigh), + clock = Some(PolarizedPort(name = "clk", polarity = PositiveEdge)), + output = Some(PolarizedPort(name = "data_out", polarity = ActiveHigh)), + width = Some(32), + depth = Some(1024) // These numbers don't matter. + ) + val expected = """ + | { + | "address port name": "addr", + | "address port polarity": "active high", + | "clock port name": "clk", + | "clock port polarity": "positive edge", + | "output port name": "data_out", + | "output port polarity": "active high" + | } + |""".stripMargin + m.toJSON shouldBe Json.parse(expected) + } + + "Masked read port" should "be generated" in { + val m = MacroPort( + address = PolarizedPort(name = "addr", polarity = ActiveHigh), + clock = Some(PolarizedPort(name = "clk", polarity = PositiveEdge)), + output = Some(PolarizedPort(name = "data_out", polarity = ActiveHigh)), + maskPort = Some(PolarizedPort(name = "mask", polarity = ActiveHigh)), + maskGran = Some(8), + width = Some(32), + depth = Some(1024) // These numbers don't matter. + ) + val expected = """ + | { + | "address port name": "addr", + | "address port polarity": "active high", + | "clock port name": "clk", + | "clock port polarity": "positive edge", + | "output port name": "data_out", + | "output port polarity": "active high", + | "mask port name": "mask", + | "mask port polarity": "active high", + | "mask granularity": 8 + | } + |""".stripMargin + m.toJSON shouldBe Json.parse(expected) + } + + "Everything port" should "be generated" in { + val m = MacroPort( + address = PolarizedPort(name = "addr", polarity = ActiveHigh), + clock = Some(PolarizedPort(name = "clk", polarity = PositiveEdge)), + writeEnable = Some(PolarizedPort(name = "write_enable", polarity = ActiveHigh)), + readEnable = Some(PolarizedPort(name = "read_enable", polarity = ActiveHigh)), + chipEnable = Some(PolarizedPort(name = "chip_enable", polarity = ActiveHigh)), + output = Some(PolarizedPort(name = "data_out", polarity = ActiveHigh)), + input = Some(PolarizedPort(name = "data_in", polarity = ActiveHigh)), + maskPort = Some(PolarizedPort(name = "mask", polarity = ActiveHigh)), + maskGran = Some(8), + width = Some(32), + depth = Some(1024) // These numbers don't matter. + ) + val expected = """ + | { + | "address port name": "addr", + | "address port polarity": "active high", + | "clock port name": "clk", + | "clock port polarity": "positive edge", + | "write enable port name": "write_enable", + | "write enable port polarity": "active high", + | "read enable port name": "read_enable", + | "read enable port polarity": "active high", + | "chip enable port name": "chip_enable", + | "chip enable port polarity": "active high", + | "output port name": "data_out", + | "output port polarity": "active high", + | "input port name": "data_in", + | "input port polarity": "active high", + | "mask port name": "mask", + | "mask port polarity": "active high", + | "mask granularity": 8 + | } + |""".stripMargin + m.toJSON shouldBe Json.parse(expected) + } +} + +class SRAMMacroOutput extends AnyFlatSpec with Matchers with HasAwesomeMemData { + "SRAM macro" should "be generated" in { + val m = getAwesomeMem + val expected = getAwesomeMemJSON + m.toJSON shouldBe Json.parse(expected) + } +} + +class InputOutput extends AnyFlatSpec with Matchers with HasAwesomeMemData { + "Read-write string" should "preserve data" in { + val mdf = List( + FillerMacro("MY_FILLER_CELL", "lvt"), + MetalFillerMacro("METAL_GEAR_FILLER", "hvt"), + getAwesomeMem + ) + Utils.readMDFFromString(Utils.writeMDFToString(mdf)) shouldBe Some(mdf) + } + + val testDir: String = "test_run_dir" + new File(testDir).mkdirs // Make sure the testDir exists + + "Read-write file" should "preserve data" in { + val mdf = List( + FillerMacro("MY_FILLER_CELL", "lvt"), + MetalFillerMacro("METAL_GEAR_FILLER", "hvt"), + getAwesomeMem + ) + val filename = testDir + "/" + "mdf_read_write_test.json" + Utils.writeMDFToPath(Some(filename), mdf) shouldBe true + Utils.readMDFFromPath(Some(filename)) shouldBe Some(mdf) + } +} diff --git a/src/test/scala/mdf/macrolib/MacroLibSpec.scala b/src/test/scala/mdf/macrolib/MacroLibSpec.scala new file mode 100644 index 00000000..fd3210bb --- /dev/null +++ b/src/test/scala/mdf/macrolib/MacroLibSpec.scala @@ -0,0 +1,406 @@ +package mdf.macrolib + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import play.api.libs.json._ + +object JSONUtils { + def readStringValueMap(str: String): Option[Map[String, JsValue]] = { + Json.parse(str) match { + case x: JsObject => Some(x.as[Map[String, JsValue]]) + case _ => None + } + } +} + +// Tests for filler macros +class FillerMacroSpec extends AnyFlatSpec with Matchers { + "Valid lvt macros" should "be detected" in { + val m = JSONUtils + .readStringValueMap(""" + | { + | "type": "filler cell", + | "name": "MY_FILLER_CELL", + | "vt": "lvt" + | } + |""".stripMargin) + .get + FillerMacroBase.parseJSON(m) shouldBe Some(FillerMacro("MY_FILLER_CELL", "lvt")) + } + + "Valid metal macro" should "be detected" in { + val m = JSONUtils + .readStringValueMap(""" + | { + | "type": "metal filler cell", + | "name": "METAL_FILLER_CELL", + | "vt": "lvt" + | } + |""".stripMargin) + .get + FillerMacroBase.parseJSON(m) shouldBe Some(MetalFillerMacro("METAL_FILLER_CELL", "lvt")) + } + + "Valid hvt macros" should "be detected" in { + val m = JSONUtils + .readStringValueMap(""" + | { + | "type": "filler cell", + | "name": "HVT_CELL_PROP", + | "vt": "hvt" + | } + |""".stripMargin) + .get + FillerMacroBase.parseJSON(m) shouldBe Some(FillerMacro("HVT_CELL_PROP", "hvt")) + } + + "Empty name macros" should "be rejected" in { + val m = JSONUtils + .readStringValueMap(""" + | { + | "type": "filler cell", + | "name": "", + | "vt": "hvt" + | } + |""".stripMargin) + .get + FillerMacroBase.parseJSON(m) shouldBe None + } + + "Empty vt macros" should "be rejected" in { + val m = JSONUtils + .readStringValueMap(""" + | { + | "type": "metal filler cell", + | "name": "DEAD_CELL", + | "vt": "" + | } + |""".stripMargin) + .get + FillerMacroBase.parseJSON(m) shouldBe None + } + + "Missing vt macros" should "be rejected" in { + val m = JSONUtils + .readStringValueMap(""" + | { + | "type": "metal filler cell", + | "name": "DEAD_CELL" + | } + |""".stripMargin) + .get + FillerMacroBase.parseJSON(m) shouldBe None + } + + "Missing name macros" should "be rejected" in { + val m = JSONUtils + .readStringValueMap(""" + | { + | "type": "filler cell", + | "vt": "" + | } + |""".stripMargin) + .get + FillerMacroBase.parseJSON(m) shouldBe None + } +} + +// Tests for SRAM type and associates. +class SRAMMacroSpec extends AnyFlatSpec with Matchers { + // Simple port which can be reused in tests + // Note: assume width=depth=simplePortConstant. + val simplePortConstant = 1024 + def simplePort( + postfix: String = "", + width: Int = simplePortConstant, + depth: Int = simplePortConstant + ): (String, MacroPort) = { + val json = s""" + { + "address port name": "A_${postfix}", + "address port polarity": "active high", + "clock port name": "CLK_${postfix}", + "clock port polarity": "positive edge", + "write enable port name": "WEN_${postfix}", + "write enable port polarity": "active high", + "read enable port name": "REN_${postfix}", + "read enable port polarity": "active high", + "chip enable port name": "CEN_${postfix}", + "chip enable port polarity": "active high", + "output port name": "OUT_${postfix}", + "output port polarity": "active high", + "input port name": "IN_${postfix}", + "input port polarity": "active high", + "mask granularity": 1, + "mask port name": "MASK_${postfix}", + "mask port polarity": "active high" + } + """ + val port = MacroPort( + address = PolarizedPort(s"A_${postfix}", ActiveHigh), + clock = Some(PolarizedPort(s"CLK_${postfix}", PositiveEdge)), + writeEnable = Some(PolarizedPort(s"WEN_${postfix}", ActiveHigh)), + readEnable = Some(PolarizedPort(s"REN_${postfix}", ActiveHigh)), + chipEnable = Some(PolarizedPort(s"CEN_${postfix}", ActiveHigh)), + output = Some(PolarizedPort(s"OUT_${postfix}", ActiveHigh)), + input = Some(PolarizedPort(s"IN_${postfix}", ActiveHigh)), + maskPort = Some(PolarizedPort(s"MASK_${postfix}", ActiveHigh)), + maskGran = Some(1), + width = Some(width), + depth = Some(depth) + ) + (json, port) + } + "Simple port" should "be valid" in { + { + val (json, port) = simplePort("Simple1") + MacroPort.parseJSON(JSONUtils.readStringValueMap(json).get, simplePortConstant, simplePortConstant) shouldBe Some( + port + ) + } + { + val (json, port) = simplePort("Simple2") + MacroPort.parseJSON(JSONUtils.readStringValueMap(json).get, simplePortConstant, simplePortConstant) shouldBe Some( + port + ) + } + { + val (json, port) = simplePort("bar") + MacroPort.parseJSON(JSONUtils.readStringValueMap(json).get, simplePortConstant, simplePortConstant) shouldBe Some( + port + ) + } + { + val (json, port) = simplePort("") + MacroPort.parseJSON(JSONUtils.readStringValueMap(json).get, simplePortConstant, simplePortConstant) shouldBe Some( + port + ) + } + } + + "Simple SRAM macro" should "be detected" in { + val (json, port) = simplePort("", 2048, 4096) + val m = JSONUtils + .readStringValueMap(s""" +{ + "type": "sram", + "name": "SRAMS_R_US", + "width": 2048, + "depth": "4096", + "family": "1rw", + "ports": [ + ${json} + ] +} + """) + .get + SRAMMacro.parseJSON(m) shouldBe Some( + SRAMMacro("SRAMS_R_US", width = 2048, depth = 4096, family = "1rw", ports = List(port), extraPorts = List()) + ) + } + + "Non-power-of-two width & depth SRAM macro" should "be detected" in { + val (json, port) = simplePort("", 1234, 8888) + val m = JSONUtils + .readStringValueMap(s""" +{ + "type": "sram", + "name": "SRAMS_R_US", + "width": 1234, + "depth": "8888", + "family": "1rw", + "ports": [ + ${json} + ] +} + """) + .get + SRAMMacro.parseJSON(m) shouldBe Some( + SRAMMacro("SRAMS_R_US", width = 1234, depth = 8888, family = "1rw", ports = List(port), extraPorts = List()) + ) + } + + "Minimal memory port" should "be detected" in { + val (json, port) = simplePort("_A", 64, 1024) + val port2 = MacroPort( + address = PolarizedPort("A_B", ActiveHigh), + clock = Some(PolarizedPort("CLK_B", PositiveEdge)), + writeEnable = Some(PolarizedPort("WEN_B", ActiveHigh)), + readEnable = None, + chipEnable = None, + output = Some(PolarizedPort("OUT_B", ActiveHigh)), + input = Some(PolarizedPort("IN_B", ActiveHigh)), + maskPort = None, + maskGran = None, + width = Some(64), + depth = Some(1024) + ) + val m = JSONUtils + .readStringValueMap(s""" +{ + "type": "sram", + "name": "SRAMS_R_US", + "width": 64, + "depth": "1024", + "family": "2rw", + "ports": [ + ${json}, + { + "address port name": "A_B", + "address port polarity": "active high", + "clock port name": "CLK_B", + "clock port polarity": "positive edge", + "write enable port name": "WEN_B", + "write enable port polarity": "active high", + "output port name": "OUT_B", + "output port polarity": "active high", + "input port name": "IN_B", + "input port polarity": "active high" + } + ] +} + """) + .get + SRAMMacro.parseJSON(m) shouldBe Some( + SRAMMacro("SRAMS_R_US", width = 64, depth = 1024, family = "2rw", ports = List(port, port2), extraPorts = List()) + ) + } + + "Extra ports" should "be detected" in { + val (json, port) = simplePort("", 2048, 4096) + val m = JSONUtils + .readStringValueMap(s""" +{ + "type": "sram", + "name": "GOT_EXTRA", + "width": 2048, + "depth": "4096", + "family": "1rw", + "ports": [ + ${json} + ], + "extra ports": [ + { + "name": "TIE_DIE", + "width": 1, + "type": "constant", + "value": 1 + }, + { + "name": "TIE_MOO", + "width": 4, + "type": "constant", + "value": 0 + } + ] +} + """) + .get + SRAMMacro.parseJSON(m) shouldBe Some( + SRAMMacro( + "GOT_EXTRA", + width = 2048, + depth = 4096, + family = "1rw", + ports = List(port), + extraPorts = List( + MacroExtraPort( + name = "TIE_DIE", + width = 1, + portType = Constant, + value = 1 + ), + MacroExtraPort( + name = "TIE_MOO", + width = 4, + portType = Constant, + value = 0 + ) + ) + ) + ) + } + + "Invalid port" should "be rejected" in { + val (json, port) = simplePort("", 2048, 4096) + val m = JSONUtils + .readStringValueMap(s""" +{ + "type": "sram", + "name": "SRAMS_R_US", + "width": 2048, + "depth": "4096", + "family": "1rw", + "ports": [ + { + "address port name": "missing_polarity", + "output port name": "missing_clock" + } + ] +} + """) + .get + SRAMMacro.parseJSON(m) shouldBe None + } + + "No ports" should "be rejected" in { + val (json, port) = simplePort("", 2048, 4096) + val m = JSONUtils + .readStringValueMap(s""" +{ + "type": "sram", + "name": "SRAMS_R_US", + "width": 2048, + "depth": "4096", + "family": "1rw" +} + """) + .get + SRAMMacro.parseJSON(m) shouldBe None + } + + "No family and ports" should "be rejected" in { + val (json, port) = simplePort("", 2048, 4096) + val m = JSONUtils + .readStringValueMap(s""" +{ + "type": "sram", + "name": "SRAMS_R_US", + "width": 2048, + "depth": "4096" +} + """) + .get + SRAMMacro.parseJSON(m) shouldBe None + } + + "String width" should "be rejected" in { + val (json, port) = simplePort("", 2048, 4096) + val m = JSONUtils + .readStringValueMap(s""" +{ + "type": "sram", + "name": "BAD_BAD_SRAM", + "width": "wide", + "depth": "4096" +} + """) + .get + SRAMMacro.parseJSON(m) shouldBe None + } + + "String depth" should "be rejected" in { + val (json, port) = simplePort("", 2048, 4096) + val m = JSONUtils + .readStringValueMap(s""" +{ + "type": "sram", + "name": "BAD_BAD_SRAM", + "width": 512, + "depth": "octopus_under_the_sea" +} + """) + .get + SRAMMacro.parseJSON(m) shouldBe None + } +} diff --git a/tapeout/src/test/scala/barstools/tapeout/transforms/GenerateTopSpec.scala b/tapeout/src/test/scala/barstools/tapeout/transforms/GenerateTopSpec.scala deleted file mode 100644 index 02afa79a..00000000 --- a/tapeout/src/test/scala/barstools/tapeout/transforms/GenerateTopSpec.scala +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package barstools.tapeout.transforms - -import firrtl.FileUtils -import org.scalatest.freespec.AnyFreeSpec -import org.scalatest.matchers.should.Matchers - -import java.io.{ByteArrayOutputStream, File, PrintStream, PrintWriter} - -class GenerateTopSpec extends AnyFreeSpec with Matchers { - "Generate top and harness" - { - "should include the following transforms" in { - val buffer = new ByteArrayOutputStream() - Console.withOut(new PrintStream(buffer)) { - GenerateTopAndHarness.main(Array("-i", "ExampleModuleNeedsResetInverted.fir", "-ll", "info")) - } - val output = buffer.toString - output should include("barstools.tapeout.transforms.AddSuffixToModuleNames") - output should include("barstools.tapeout.transforms.ConvertToExtMod") - output should include("barstools.tapeout.transforms.RemoveUnusedModules") - output should include("barstools.tapeout.transforms.AvoidExtModuleCollisions") - } - } - - "generate harness should " ignore { - val targetDir = "test_run_dir/generate_top_spec" - FileUtils.makeDirectory(targetDir) - - val stream = getClass.getResourceAsStream("/BlackBoxFloatTester.fir") - val input = scala.io.Source.fromInputStream(stream).getLines() - val printWriter = new PrintWriter(new File(s"$targetDir/BlackBoxFloatTester.fir")) - printWriter.write(input.mkString("\n")) - printWriter.close() - - println(s"""Resource: ${input.mkString("\n")}""") - - -// val buffer = new ByteArrayOutputStream() -// Console.withOut(new PrintStream(buffer)) { - GenerateTopAndHarness.main( - Array( - "--target-dir", "test_run_dir/generate_top_spec", - "-i", s"$targetDir/BlackBoxFloatTester.fir", - "-o", - "chipyard.unittest.TestHarness.IceNetUnitTestConfig.top.v", - "-tho", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.harness.v", - "-i", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.fir", - "--syn-top", "UnitTestSuite", - "--harness-top", "TestHarness", - "-faf", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.anno.json", - "-tsaof", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.top.anno.json", - "-tdf", "firrtl_black_box_resource_files.top.f", - "-tsf", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.top.fir", - "-thaof", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.harness.anno.json", - "-hdf", "firrtl_black_box_resource_files.harness.f", - "-thf", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.harness.fir", - "--infer-rw", - "--repl-seq-mem", "-c:TestHarness:-o:chipyard.unittest.TestHarness.IceNetUnitTestConfig.top.mems.conf", - "-thconf", "chipyard.unittest.TestHarness.IceNetUnitTestConfig.harness.mems.conf", - "-td", "test_run_dir/from-ci", - "-ll", "info" - ) - ) - } -// val output = buffer.toString -// println(output) -}