diff --git a/build.sbt b/build.sbt index fd9638b1..d8840865 100644 --- a/build.sbt +++ b/build.sbt @@ -7,15 +7,14 @@ val defaultVersions = Map( lazy val commonSettings = Seq( organization := "edu.berkeley.cs", - version := "0.1-SNAPSHOT", + version := "0.4-SNAPSHOT", scalaVersion := "2.12.10", scalacOptions := Seq("-deprecation", "-feature", "-language:reflectiveCalls", "-Xsource:2.11"), libraryDependencies ++= Seq("chisel3","chisel-iotesters").map { dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) }, - libraryDependencies in Test ++= Seq( - "org.scalatest" %% "scalatest" % "2.2.5" % "test", - "org.scalacheck" %% "scalacheck" % "1.12.4" % "test" + libraryDependencies ++= Seq( + "org.scalatest" %% "scalatest" % "3.2.2" % "test", ), resolvers ++= Seq( Resolver.sonatypeRepo("snapshots"), @@ -31,9 +30,6 @@ lazy val macros = (project in file("macros")) .dependsOn(mdf) .settings(commonSettings) .settings( - libraryDependencies ++= Seq( - "edu.berkeley.cs" %% "firrtl-interpreter" % "1.4.+" % Test - ), mainClass := Some("barstools.macros.MacroCompiler") ) .enablePlugins(sbtassembly.AssemblyPlugin) diff --git a/iocell/src/main/scala/chisel/Analog.scala b/iocell/src/main/scala/barstools/iocell/chisel/Analog.scala similarity index 61% rename from iocell/src/main/scala/chisel/Analog.scala rename to iocell/src/main/scala/barstools/iocell/chisel/Analog.scala index e1b4fc78..0cdfc493 100644 --- a/iocell/src/main/scala/chisel/Analog.scala +++ b/iocell/src/main/scala/barstools/iocell/chisel/Analog.scala @@ -6,8 +6,10 @@ import chisel3._ import chisel3.util.{HasBlackBoxResource} import chisel3.experimental.{Analog, IntParam} -class AnalogConst(value: Int, width: Int = 1) extends BlackBox(Map("CONST" -> IntParam(value), "WIDTH" -> IntParam(width))) with HasBlackBoxResource{ - val io = IO(new Bundle {val io = Analog(width.W) } ) +class AnalogConst(value: Int, width: Int = 1) + extends BlackBox(Map("CONST" -> IntParam(value), "WIDTH" -> IntParam(width))) + with HasBlackBoxResource { + val io = IO(new Bundle { val io = Analog(width.W) }) addResource("/barstools/iocell/vsrc/Analog.v") } diff --git a/iocell/src/main/scala/chisel/IOCell.scala b/iocell/src/main/scala/barstools/iocell/chisel/IOCell.scala similarity index 73% rename from iocell/src/main/scala/chisel/IOCell.scala rename to iocell/src/main/scala/barstools/iocell/chisel/IOCell.scala index a5926030..d244d298 100644 --- a/iocell/src/main/scala/chisel/IOCell.scala +++ b/iocell/src/main/scala/barstools/iocell/chisel/IOCell.scala @@ -4,7 +4,7 @@ package barstools.iocell.chisel import chisel3._ import chisel3.util.{Cat, HasBlackBoxResource} -import chisel3.experimental.{Analog, DataMirror, IO, BaseModule} +import chisel3.experimental.{Analog, BaseModule, DataMirror, IO} // The following four IO cell bundle types are bare-minimum functional connections // for modeling 4 different IO cell scenarios. The intention is that the user @@ -13,24 +13,22 @@ import chisel3.experimental.{Analog, DataMirror, IO, BaseModule} // (https://github.com/sifive/sifive-blocks/blob/master/src/main/scala/devices/pinctrl/PinCtrl.scala), // but we want to avoid a dependency on an external libraries. -/** - * The base IO bundle for an analog signal (typically something with no digital buffers inside) - * pad: off-chip (external) connection - * core: internal connection - */ +/** The base IO bundle for an analog signal (typically something with no digital buffers inside) + * pad: off-chip (external) connection + * core: internal connection + */ class AnalogIOCellBundle extends Bundle { - val pad = Analog(1.W) // Pad/bump signal (off-chip) - val core = Analog(1.W) // core signal (on-chip) + val pad = Analog(1.W) // Pad/bump signal (off-chip) + val core = Analog(1.W) // core signal (on-chip) } -/** - * The base IO bundle for a signal with runtime-controllable direction - * pad: off-chip (external) connection - * i: input to chip logic (output from IO cell) - * ie: enable signal for i - * o: output from chip logic (input to IO cell) - * oe: enable signal for o - */ +/** The base IO bundle for a signal with runtime-controllable direction + * pad: off-chip (external) connection + * i: input to chip logic (output from IO cell) + * ie: enable signal for i + * o: output from chip logic (input to IO cell) + * oe: enable signal for o + */ class DigitalGPIOCellBundle extends Bundle { val pad = Analog(1.W) val i = Output(Bool()) @@ -39,24 +37,22 @@ class DigitalGPIOCellBundle extends Bundle { val oe = Input(Bool()) } -/** - * The base IO bundle for a digital output signal - * pad: off-chip (external) connection - * o: output from chip logic (input to IO cell) - * oe: enable signal for o - */ +/** The base IO bundle for a digital output signal + * pad: off-chip (external) connection + * o: output from chip logic (input to IO cell) + * oe: enable signal for o + */ class DigitalOutIOCellBundle extends Bundle { val pad = Output(Bool()) val o = Input(Bool()) val oe = Input(Bool()) } -/** - * The base IO bundle for a digital input signal - * pad: off-chip (external) connection - * i: input to chip logic (output from IO cell) - * ie: enable signal for i - */ +/** The base IO bundle for a digital input signal + * pad: off-chip (external) connection + * i: input to chip logic (output from IO cell) + * ie: enable signal for i + */ class DigitalInIOCellBundle extends Bundle { val pad = Input(Bool()) val i = Output(Bool()) @@ -102,11 +98,10 @@ class GenericDigitalOutIOCell extends GenericIOCell with DigitalOutIOCell { val io = IO(new DigitalOutIOCellBundle) } - trait IOCellTypeParams { def analog(): AnalogIOCell - def gpio(): DigitalGPIOCell - def input(): DigitalInIOCell + def gpio(): DigitalGPIOCell + def input(): DigitalInIOCell def output(): DigitalOutIOCell } @@ -118,47 +113,49 @@ case class GenericIOCellParams() extends IOCellTypeParams { } object IOCell { - /** - * From within a RawModule or MultiIOModule context, generate new module IOs from a given - * signal and return the new IO and a Seq containing all generated IO cells. - * @param coreSignal The signal onto which to add IO cells - * @param name An optional name or name prefix to use for naming IO cells - * @param abstractResetAsAsync When set, will coerce abstract resets to - * AsyncReset, and otherwise to Bool (sync reset) - * @return A tuple of (the generated IO data node, a Seq of all generated IO cell instances) - */ - def generateIOFromSignal[T <: Data](coreSignal: T, name: String, - typeParams: IOCellTypeParams = GenericIOCellParams(), - abstractResetAsAsync: Boolean = false): (T, Seq[IOCell]) = - { + + /** From within a RawModule or MultiIOModule context, generate new module IOs from a given + * signal and return the new IO and a Seq containing all generated IO cells. + * @param coreSignal The signal onto which to add IO cells + * @param name An optional name or name prefix to use for naming IO cells + * @param abstractResetAsAsync When set, will coerce abstract resets to + * AsyncReset, and otherwise to Bool (sync reset) + * @return A tuple of (the generated IO data node, a Seq of all generated IO cell instances) + */ + def generateIOFromSignal[T <: Data]( + coreSignal: T, + name: String, + typeParams: IOCellTypeParams = GenericIOCellParams(), + abstractResetAsAsync: Boolean = false + ): (T, Seq[IOCell]) = { val padSignal = IO(DataMirror.internal.chiselTypeClone[T](coreSignal)).suggestName(name) val resetFn = if (abstractResetAsAsync) toAsyncReset else toSyncReset val iocells = IOCell.generateFromSignal(coreSignal, padSignal, Some(s"iocell_$name"), typeParams, resetFn) (padSignal, iocells) } - /** - * Connect two identical signals together by adding IO cells between them and return a Seq - * containing all generated IO cells. - * @param coreSignal The core-side (internal) signal onto which to connect/add IO cells - * @param padSignal The pad-side (external) signal onto which to connect IO cells - * @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 + /** Connect two identical signals together by adding IO cells between them and return a Seq + * containing all generated IO cells. + * @param coreSignal The core-side (internal) signal onto which to connect/add IO cells + * @param padSignal The pad-side (external) signal onto which to connect IO cells + * @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 toAsyncReset: (Reset) => AsyncReset = _.asAsyncReset def generateFromSignal[T <: Data, R <: Reset]( - coreSignal: T, - padSignal: T, - name: Option[String] = None, - typeParams: IOCellTypeParams = GenericIOCellParams(), - concretizeResetFn : (Reset) => R = toSyncReset): Seq[IOCell] = - { + coreSignal: T, + padSignal: T, + name: Option[String] = None, + typeParams: IOCellTypeParams = GenericIOCellParams(), + concretizeResetFn: (Reset) => R = toSyncReset + ): Seq[IOCell] = { def genCell[T <: Data]( - castToBool: (T) => Bool, - castFromBool: (Bool) => T)( - coreSignal: T, - padSignal: T): Seq[IOCell] = { + castToBool: (T) => Bool, + castFromBool: (Bool) => T + )(coreSignal: T, + padSignal: T + ): Seq[IOCell] = { DataMirror.directionOf(coreSignal) match { case ActualDirection.Input => { val iocell = typeParams.input() @@ -188,7 +185,10 @@ object IOCell { if (coreSignal.getWidth == 0) { Seq() } else { - require(coreSignal.getWidth == 1, "Analogs wider than 1 bit are not supported because we can't bit-select Analogs (https://github.com/freechipsproject/chisel3/issues/536)") + require( + coreSignal.getWidth == 1, + "Analogs wider than 1 bit are not supported because we can't bit-select Analogs (https://github.com/freechipsproject/chisel3/issues/536)" + ) val iocell = typeParams.analog() name.foreach(n => iocell.suggestName(n)) iocell.io.core <> coreSignal @@ -204,7 +204,7 @@ object IOCell { // This dummy assignment will prevent invalid firrtl from being emitted DataMirror.directionOf(coreSignal) match { case ActualDirection.Input => coreSignal := 0.U - case _ => {} + case _ => {} } Seq() } else { diff --git a/macros/src/main/scala/SynFlops.scala b/macros/src/main/scala/SynFlops.scala deleted file mode 100644 index f815b4cb..00000000 --- a/macros/src/main/scala/SynFlops.scala +++ /dev/null @@ -1,141 +0,0 @@ -// See LICENSE for license details. - -package barstools.macros - -import firrtl._ -import firrtl.ir._ -import firrtl.Utils._ -import firrtl.passes.MemPortUtils.{memPortField, memType} -import Utils._ - -class SynFlopsPass(synflops: Boolean, libs: Seq[Macro]) extends firrtl.passes.Pass { - val extraMods = scala.collection.mutable.ArrayBuffer.empty[Module] - lazy val libMods = (libs map { lib => lib.src.name -> { - val (dataType, dataWidth) = (lib.src.ports foldLeft (None: Option[BigInt]))((res, port) => - (res, port.maskPort) match { - case (_, None) => - res - case (None, Some(_)) => - Some(port.effectiveMaskGran) - case (Some(x), Some(_)) => - assert(x == port.effectiveMaskGran) - res - } - ) match { - case None => (UIntType(IntWidth(lib.src.width)), lib.src.width) - case Some(gran) => (UIntType(IntWidth(gran)), gran.intValue) - } - - val maxDepth = min(lib.src.depth, 1<<26) - val numMems = lib.src.depth / maxDepth - - // Change macro to be mapped onto to look like the below mem - // by changing its depth, and width - val lib_macro = new Macro(lib.src.copy(name="split_"+lib.src.name, - depth = maxDepth, width = dataWidth, ports = lib.src.ports.map(p => - p.copy(width = p.width.map(_ => dataWidth), depth = p.depth.map(_ => maxDepth), - maskGran = p.maskGran.map(_ => dataWidth))))) - val mod_macro = (new MacroCompilerPass(None,None,None,None)).compile(lib, lib_macro) - val (real_mod, real_macro) = mod_macro.get - - val mem = DefMemory( - NoInfo, - "ram", - dataType, - maxDepth, - 1, // writeLatency - 1, // readLatency. This is possible because of VerilogMemDelays - real_macro.readers.indices map (i => s"R_$i"), - real_macro.writers.indices map (i => s"W_$i"), - real_macro.readwriters.indices map (i => s"RW_$i") - ) - - 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 { - case (Some(en_port), Some(re_port)) => - and(portToExpression(en_port), - portToExpression(re_port)) - case (Some(en_port), None) => portToExpression(en_port) - case (None, Some(re_port)) => portToExpression(re_port) - case (None, None) => one - } - val data = memPortField(mem, s"R_$i", "data") - val read = data - Seq( - Connect(NoInfo, memPortField(mem, s"R_$i", "clk"), clock), - Connect(NoInfo, memPortField(mem, s"R_$i", "addr"), address), - Connect(NoInfo, memPortField(mem, s"R_$i", "en"), enable), - Connect(NoInfo, WRef(r.src.output.get.name), read) - ) - } - - val writeConnects = real_macro.writers.zipWithIndex flatMap { case (w, i) => - val clock = portToExpression(w.src.clock.get) - val address = portToExpression(w.src.address) - val enable = (w.src.chipEnable, w.src.writeEnable) match { - case (Some(en), Some(we)) => - and(portToExpression(en), - portToExpression(we)) - case (Some(en), None) => portToExpression(en) - case (None, Some(we)) => portToExpression(we) - case (None, None) => zero // is it possible? - } - val mask = w.src.maskPort match { - case Some(m) => portToExpression(m) - case None => one - } - val data = memPortField(mem, s"W_$i", "data") - val write = portToExpression(w.src.input.get) - Seq( - Connect(NoInfo, memPortField(mem, s"W_$i", "clk"), clock), - Connect(NoInfo, memPortField(mem, s"W_$i", "addr"), address), - Connect(NoInfo, memPortField(mem, s"W_$i", "en"), enable), - Connect(NoInfo, memPortField(mem, s"W_$i", "mask"), mask), - Connect(NoInfo, data, write) - ) - } - - val readwriteConnects = real_macro.readwriters.zipWithIndex flatMap { case (rw, i) => - val clock = portToExpression(rw.src.clock.get) - val address = portToExpression(rw.src.address) - val wmode = rw.src.writeEnable match { - case Some(we) => portToExpression(we) - case None => zero // is it possible? - } - val wmask = rw.src.maskPort match { - case Some(wm) => portToExpression(wm) - case None => one - } - val enable = (rw.src.chipEnable, rw.src.readEnable) match { - case (Some(en), Some(re)) => - and(portToExpression(en), or(portToExpression(re), wmode)) - case (Some(en), None) => portToExpression(en) - case (None, Some(re)) => or(portToExpression(re), wmode) - case (None, None) => one - } - val wdata = memPortField(mem, s"RW_$i", "wdata") - val rdata = memPortField(mem, s"RW_$i", "rdata") - val write = portToExpression(rw.src.input.get) - val read = rdata - Seq( - Connect(NoInfo, memPortField(mem, s"RW_$i", "clk"), clock), - Connect(NoInfo, memPortField(mem, s"RW_$i", "addr"), address), - Connect(NoInfo, memPortField(mem, s"RW_$i", "en"), enable), - Connect(NoInfo, memPortField(mem, s"RW_$i", "wmode"), wmode), - Connect(NoInfo, memPortField(mem, s"RW_$i", "wmask"), wmask), - Connect(NoInfo, WRef(rw.src.output.get.name), read), - Connect(NoInfo, wdata, write) - ) - } - - extraMods.append(real_macro.module(Block(mem +: (readConnects ++ writeConnects ++ readwriteConnects)))) - real_mod - }}).toMap - - def run(c: Circuit): Circuit = { - if (!synflops) c - else c.copy(modules = (c.modules map (m => libMods.getOrElse(m.name, m))) ++ extraMods) - } -} diff --git a/macros/src/main/scala/Utils.scala b/macros/src/main/scala/Utils.scala deleted file mode 100644 index c416ca6a..00000000 --- a/macros/src/main/scala/Utils.scala +++ /dev/null @@ -1,221 +0,0 @@ -// See LICENSE for license details. - -package barstools.macros - -import firrtl._ -import firrtl.ir._ -import firrtl.PrimOps -import firrtl.passes.memlib.{MemConf, MemPort, ReadPort, WritePort, ReadWritePort, MaskedWritePort, MaskedReadWritePort} -import firrtl.Utils.BoolType -import mdf.macrolib.{Constant, MacroPort, SRAMMacro} -import mdf.macrolib.{PolarizedPort, PortPolarity, ActiveLow, ActiveHigh, NegativeEdge, PositiveEdge, MacroExtraPort} -import java.io.File -import scala.language.implicitConversions - -object MacroCompilerMath { - def ceilLog2(x: BigInt): Int = (x-1).bitLength -} - -class FirrtlMacroPort(port: MacroPort) { - val src = port - - val isReader = port.output.nonEmpty && port.input.isEmpty - val isWriter = port.input.nonEmpty && port.output.isEmpty - val isReadWriter = port.input.nonEmpty && port.output.nonEmpty - - val addrType = UIntType(IntWidth(MacroCompilerMath.ceilLog2(port.depth.get) max 1)) - val dataType = UIntType(IntWidth(port.width.get)) - val maskType = UIntType(IntWidth(port.width.get / port.effectiveMaskGran)) - - // Bundle representing this macro port. - val tpe = BundleType(Seq( - Field(port.address.name, Flip, addrType)) ++ - (port.clock map (p => Field(p.name, Flip, ClockType))) ++ - (port.input map (p => Field(p.name, Flip, dataType))) ++ - (port.output map (p => Field(p.name, Default, dataType))) ++ - (port.chipEnable map (p => Field(p.name, Flip, BoolType))) ++ - (port.readEnable map (p => Field(p.name, Flip, BoolType))) ++ - (port.writeEnable map (p => Field(p.name, Flip, BoolType))) ++ - (port.maskPort map (p => Field(p.name, Flip, maskType))) - ) - val ports = tpe.fields map (f => Port( - NoInfo, f.name, f.flip match { case Default => Output case Flip => Input }, f.tpe)) -} - -// Reads an SRAMMacro and generates firrtl blackboxes. -class Macro(srcMacro: SRAMMacro) { - val src = srcMacro - - val firrtlPorts = srcMacro.ports map { new FirrtlMacroPort(_) } - - val writers = firrtlPorts filter (p => p.isWriter) - val readers = firrtlPorts filter (p => p.isReader) - val readwriters = firrtlPorts filter (p => p.isReadWriter) - - val sortedPorts = writers ++ readers ++ readwriters - val extraPorts = srcMacro.extraPorts map { p => - assert(p.portType == Constant) // TODO: release it? - val name = p.name - val width = BigInt(p.width.toLong) - val value = BigInt(p.value.toLong) - (name -> UIntLiteral(value, IntWidth(width))) - } - - // Bundle representing this memory blackbox - val tpe = BundleType(firrtlPorts flatMap (_.tpe.fields)) - - private val modPorts = (firrtlPorts flatMap (_.ports)) ++ - (extraPorts map { case (name, value) => Port(NoInfo, name, Input, value.tpe) }) - val blackbox = ExtModule(NoInfo, srcMacro.name, modPorts, srcMacro.name, Nil) - def module(body: Statement) = Module(NoInfo, srcMacro.name, modPorts, body) -} - -object Utils { - def filterForSRAM(s: Option[Seq[mdf.macrolib.Macro]]): Option[Seq[mdf.macrolib.SRAMMacro]] = { - s match { - case Some(l:Seq[mdf.macrolib.Macro]) => Some(l filter { _.isInstanceOf[mdf.macrolib.SRAMMacro] } map { m => m.asInstanceOf[mdf.macrolib.SRAMMacro] }) - case _ => None - } - } - // This utility reads a conf in and returns MDF like mdf.macrolib.Utils.readMDFFromPath - def readConfFromPath(path: Option[String]): Option[Seq[mdf.macrolib.Macro]] = { - path.map((p) => Utils.readConfFromString(scala.io.Source.fromFile(p).mkString)) - } - def readConfFromString(str: String): Seq[mdf.macrolib.Macro] = { - MemConf.fromString(str).map { m:MemConf => - val ports = m.ports.map { case (port, num) => Seq.fill(num)(port) } reduce (_ ++ _) - SRAMMacro(m.name, m.width, m.depth, Utils.portSpecToFamily(ports), Utils.portSpecToMacroPort(m.width, m.depth, m.maskGranularity, ports)) - } - } - def portSpecToFamily(ports: Seq[MemPort]): String = { - val numR = ports.count(_ match { case ReadPort => true; case _ => false}) - val numW = ports.count(_ match { case WritePort|MaskedWritePort => true; case _ => false}) - val numRW = ports.count(_ match { case ReadWritePort|MaskedReadWritePort => true; case _ => false}) - val numRStr = if(numR > 0) s"${numR}r" else "" - val numWStr = if(numW > 0) s"${numW}w" else "" - val numRWStr = if(numRW > 0) s"${numRW}rw" else "" - return numRStr + numWStr + numRWStr - } - // This translates between two represenations of ports - def portSpecToMacroPort(width: Int, depth: BigInt, maskGran: Option[Int], ports: Seq[MemPort]): Seq[MacroPort] = { - var numR = 0 - var numW = 0 - var numRW = 0 - ports.map { _ match { - case ReadPort => { - val portName = s"R${numR}" - numR += 1 - MacroPort( - width=Some(width), depth=Some(depth), - address=PolarizedPort(s"${portName}_addr", ActiveHigh), - clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), - readEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), - output=Some(PolarizedPort(s"${portName}_data", ActiveHigh)) - ) } - case WritePort => { - val portName = s"W${numW}" - numW += 1 - MacroPort( - width=Some(width), depth=Some(depth), - address=PolarizedPort(s"${portName}_addr", ActiveHigh), - clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), - writeEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), - input=Some(PolarizedPort(s"${portName}_data", ActiveHigh)) - ) } - case MaskedWritePort => { - val portName = s"W${numW}" - numW += 1 - MacroPort( - width=Some(width), depth=Some(depth), - address=PolarizedPort(s"${portName}_addr", ActiveHigh), - clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), - writeEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), - maskPort=Some(PolarizedPort(s"${portName}_mask", ActiveHigh)), - maskGran=maskGran, - input=Some(PolarizedPort(s"${portName}_data", ActiveHigh)) - ) } - case ReadWritePort => { - val portName = s"RW${numRW}" - numRW += 1 - MacroPort( - width=Some(width), depth=Some(depth), - address=PolarizedPort(s"${portName}_addr", ActiveHigh), - clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), - chipEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), - writeEnable=Some(PolarizedPort(s"${portName}_wmode", ActiveHigh)), - input=Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)), - output=Some(PolarizedPort(s"${portName}_rdata", ActiveHigh)) - ) } - case MaskedReadWritePort => { - val portName = s"RW${numRW}" - numRW += 1 - MacroPort( - width=Some(width), depth=Some(depth), - address=PolarizedPort(s"${portName}_addr", ActiveHigh), - clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), - chipEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), - writeEnable=Some(PolarizedPort(s"${portName}_wmode", ActiveHigh)), - maskPort=Some(PolarizedPort(s"${portName}_wmask", ActiveHigh)), - maskGran=maskGran, - input=Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)), - output=Some(PolarizedPort(s"${portName}_rdata", ActiveHigh)) - ) } - }} - } - def findSRAMCompiler(s: Option[Seq[mdf.macrolib.Macro]]): Option[mdf.macrolib.SRAMCompiler] = { - s match { - case Some(l:Seq[mdf.macrolib.Macro]) => - l collectFirst { - case x: mdf.macrolib.SRAMCompiler => x - } - case _ => None - } - } - def buildSRAMMacros(s: mdf.macrolib.SRAMCompiler): Seq[mdf.macrolib.SRAMMacro] = { - for (g <- s.groups; d <- g.depth; w <- g.width; vt <- g.vt) - yield mdf.macrolib.SRAMMacro(makeName(g, d, w, vt), w, d, g.family, g.ports.map(_.copy(width=Some(w), depth=Some(d))), vt, g.mux, g.extraPorts) - } - def buildSRAMMacro(g: mdf.macrolib.SRAMGroup, d: Int, w: Int, vt: String): mdf.macrolib.SRAMMacro = { - return mdf.macrolib.SRAMMacro(makeName(g, d, w, vt), w, d, g.family, g.ports.map(_.copy(width=Some(w), depth=Some(d))), vt, g.mux, g.extraPorts) - } - def makeName(g: mdf.macrolib.SRAMGroup, depth: Int, width: Int, vt: String): String = { - g.name.foldLeft(""){ (builder, next) => - next match { - case "depth"|"DEPTH" => builder + depth - case "width"|"WIDTH" => builder + width - case "vt" => builder + vt.toLowerCase - case "VT" => builder + vt.toUpperCase - case "family" => builder + g.family.toLowerCase - case "FAMILY" => builder + g.family.toUpperCase - case "mux"|"MUX" => builder + g.mux - case other => builder + other - } - } - } - - def and(e1: Expression, e2: Expression) = - DoPrim(PrimOps.And, Seq(e1, e2), Nil, e1.tpe) - def or(e1: Expression, e2: Expression) = - DoPrim(PrimOps.Or, Seq(e1, e2), Nil, e1.tpe) - def bits(e: Expression, high: BigInt, low: BigInt): Expression = - DoPrim(PrimOps.Bits, Seq(e), Seq(high, low), UIntType(IntWidth(high-low+1))) - def bits(e: Expression, idx: BigInt): Expression = bits(e, idx, idx) - def cat(es: Seq[Expression]): Expression = - if (es.size == 1) es.head - else DoPrim(PrimOps.Cat, Seq(es.head, cat(es.tail)), Nil, UnknownType) - def not(e: Expression) = - DoPrim(PrimOps.Not, Seq(e), Nil, e.tpe) - - // Convert a port to a FIRRTL expression, handling polarity along the way. - def portToExpression(pp: PolarizedPort): Expression = - portToExpression(WRef(pp.name), Some(pp.polarity)) - - def portToExpression(exp: Expression, polarity: Option[PortPolarity]): Expression = - polarity match { - case Some(ActiveLow) | Some(NegativeEdge) => not(exp) - case _ => exp - } - - // Check if a number is a power of two - def isPowerOfTwo(x: Int): Boolean = (x & (x - 1)) == 0 -} diff --git a/macros/src/main/scala/CostMetric.scala b/macros/src/main/scala/barstools/macros/CostMetric.scala similarity index 69% rename from macros/src/main/scala/CostMetric.scala rename to macros/src/main/scala/barstools/macros/CostMetric.scala index b80324aa..3b9de124 100644 --- a/macros/src/main/scala/CostMetric.scala +++ b/macros/src/main/scala/barstools/macros/CostMetric.scala @@ -2,27 +2,25 @@ package barstools.macros -/** - * Trait which can calculate the cost of compiling a memory against a certain - * library memory macro using a cost function. - */ +/** Trait which can calculate the cost of compiling a memory against a certain + * library memory macro using a cost function. + */ // TODO: eventually explore compiling a single target memory using multiple // different kinds of target memory. trait CostMetric extends Serializable { - /** - * Cost function that returns the cost of compiling a memory using a certain - * macro. - * - * @param mem Memory macro to compile (target memory) - * @param lib Library memory macro to use (library memory) - * @return The cost of this compile, defined by this cost metric, or None if - * it cannot be compiled. - */ + + /** Cost function that returns the cost of compiling a memory using a certain + * macro. + * + * @param mem Memory macro to compile (target memory) + * @param lib Library memory macro to use (library memory) + * @return The cost of this compile, defined by this cost metric, or None if + * it cannot be compiled. + */ def cost(mem: Macro, lib: Macro): Option[Double] - /** - * Helper function to return the map of arguments (or an empty map if there are none). - */ + /** Helper function to return the map of arguments (or an empty map if there are none). + */ def commandLineParams(): Map[String, String] // We also want this to show up for the class itself. @@ -40,8 +38,9 @@ trait CostMetricCompanion { // Some default cost functions. /** Palmer's old metric. - * TODO: figure out what is the difference between this metric and the current - * default metric and either revive or delete this metric. */ + * TODO: figure out what is the difference between this metric and the current + * default metric and either revive or delete this metric. + */ object OldMetric extends CostMetric with CostMetricCompanion { override def cost(mem: Macro, lib: Macro): Option[Double] = { /* Palmer: A quick cost function (that must be kept in sync with @@ -58,17 +57,17 @@ object OldMetric extends CostMetric with CostMetricCompanion { override def construct(m: Map[String, String]) = OldMetric } -/** - * An external cost function. - * Calls the specified path with paths to the JSON MDF representation of the mem - * and lib macros. The external executable should print a Double. - * None will be returned if the external executable does not print a valid - * Double. - */ +/** An external cost function. + * Calls the specified path with paths to the JSON MDF representation of the mem + * and lib macros. The external executable should print a Double. + * None will be returned if the external executable does not print a valid + * Double. + */ class ExternalMetric(path: String) extends CostMetric { import mdf.macrolib.Utils.writeMacroToPath + import java.io._ - import scala.language.postfixOps // for !! postfix op + import scala.language.postfixOps import sys.process._ override def cost(mem: Macro, lib: Macro): Option[Double] = { @@ -104,7 +103,7 @@ object ExternalMetric extends CostMetricCompanion { override def construct(m: Map[String, String]) = { val pathOption = m.get("path") pathOption match { - case Some(path:String) => new ExternalMetric(path) + case Some(path: String) => new ExternalMetric(path) case _ => throw new IllegalArgumentException("ExternalMetric missing option 'path'") } } @@ -114,14 +113,17 @@ object ExternalMetric extends CostMetricCompanion { // TODO: write tests for this function to make sure it selects the right things object DefaultMetric extends CostMetric with CostMetricCompanion { override def cost(mem: Macro, lib: Macro): Option[Double] = { - val memMask = mem.src.ports map (_.maskGran) find (_.isDefined) map (_.get) - val libMask = lib.src.ports map (_.maskGran) find (_.isDefined) map (_.get) + val memMask = mem.src.ports.map(_.maskGran).find(_.isDefined).map(_.get) + val libMask = lib.src.ports.map(_.maskGran).find(_.isDefined).map(_.get) val memWidth = (memMask, libMask) match { case (None, _) => mem.src.width - case (Some(p), None) => (mem.src.width/p)*math.ceil(p.toDouble/lib.src.width)*lib.src.width //We map the mask to distinct memories + case (Some(p), None) => + (mem.src.width / p) * math.ceil( + p.toDouble / lib.src.width + ) * lib.src.width //We map the mask to distinct memories case (Some(p), Some(m)) => { - if(m <= p) (mem.src.width/p)*math.ceil(p.toDouble/m)*m //Using multiple m's to create a p (integeraly) - else (mem.src.width/p)*m //Waste the extra maskbits + if (m <= p) (mem.src.width / p) * math.ceil(p.toDouble / m) * m //Using multiple m's to create a p (integeraly) + else (mem.src.width / p) * m //Waste the extra maskbits } } val depthCost = math.ceil(mem.src.depth.toDouble / lib.src.depth.toDouble) @@ -129,10 +131,10 @@ object DefaultMetric extends CostMetric with CostMetricCompanion { val bitsCost = (lib.src.depth * lib.src.width).toDouble // Fraction of wasted bits plus const per mem val requestedBits = (mem.src.depth * mem.src.width).toDouble - val bitsWasted = depthCost*widthCost*bitsCost - requestedBits + val bitsWasted = depthCost * widthCost * bitsCost - requestedBits val wastedConst = 0.05 // 0 means waste as few bits with no regard for instance count - val costPerInst = wastedConst*depthCost*widthCost - Some(1.0*bitsWasted/requestedBits+costPerInst) + val costPerInst = wastedConst * depthCost * widthCost + Some(1.0 * bitsWasted / requestedBits + costPerInst) } override def commandLineParams = Map() @@ -147,10 +149,11 @@ object MacroCompilerUtil { // Adapted from https://stackoverflow.com/a/134918 /** Serialize an arbitrary object to String. - * Used to pass structured values through as an annotation. */ + * Used to pass structured values through as an annotation. + */ def objToString(o: Serializable): String = { val baos: ByteArrayOutputStream = new ByteArrayOutputStream - val oos: ObjectOutputStream = new ObjectOutputStream(baos) + val oos: ObjectOutputStream = new ObjectOutputStream(baos) oos.writeObject(o) oos.close() return Base64.getEncoder.encodeToString(baos.toByteArray) @@ -167,6 +170,7 @@ object MacroCompilerUtil { } object CostMetric { + /** Define some default metric. */ val default: CostMetric = DefaultMetric @@ -177,13 +181,12 @@ object CostMetric { registerCostMetric(ExternalMetric) registerCostMetric(DefaultMetric) - /** - * Register a cost metric. - * @param createFuncHelper Companion object to fetch the name and construct - * the metric. - */ + /** Register a cost metric. + * @param createFuncHelper Companion object to fetch the name and construct + * the metric. + */ def registerCostMetric(createFuncHelper: CostMetricCompanion): Unit = { - costMetricCreators.update(createFuncHelper.name, createFuncHelper) + costMetricCreators.update(createFuncHelper.name(), createFuncHelper) } /** Select a cost metric from string. */ @@ -193,7 +196,7 @@ object CostMetric { } else if (!costMetricCreators.contains(m)) { throw new IllegalArgumentException("Invalid cost metric " + m) } else { - costMetricCreators.get(m).get.construct(params) + costMetricCreators(m).construct(params) } } } diff --git a/macros/src/main/scala/MacroCompiler.scala b/macros/src/main/scala/barstools/macros/MacroCompiler.scala similarity index 65% rename from macros/src/main/scala/MacroCompiler.scala rename to macros/src/main/scala/barstools/macros/MacroCompiler.scala index c057baa6..bfcf78da 100644 --- a/macros/src/main/scala/MacroCompiler.scala +++ b/macros/src/main/scala/barstools/macros/MacroCompiler.scala @@ -1,25 +1,24 @@ // See LICENSE for license details. -/** - * Terminology note: - * mem - target memory to compile, in design (e.g. Mem() in rocket) - * lib - technology SRAM(s) to use to compile mem - */ +/** Terminology note: + * mem - target memory to compile, in design (e.g. Mem() in rocket) + * lib - technology SRAM(s) to use to compile mem + */ package barstools.macros -import firrtl._ -import firrtl.ir._ -import firrtl.PrimOps +import barstools.macros.Utils._ import firrtl.Utils._ import firrtl.annotations._ -import firrtl.transforms.{NoDCEAnnotation} -import firrtl.CompilerUtils.getLoweringTransforms -import mdf.macrolib.{PolarizedPort, PortPolarity, SRAMMacro, SRAMGroup, SRAMCompiler} -import scala.collection.mutable.{ArrayBuffer, HashMap} +import firrtl.ir._ +import firrtl.stage.{FirrtlSourceAnnotation, FirrtlStage, Forms, OutputFileAnnotation, RunFirrtlTransformAnnotation} +import firrtl.transforms.NoDCEAnnotation +import firrtl.{PrimOps, _} +import mdf.macrolib._ + import java.io.{File, FileWriter} -import scala.io.{Source} -import Utils._ +import scala.collection.mutable.{ArrayBuffer, HashMap} +import scala.io.Source case class MacroCompilerException(msg: String) extends Exception(msg) @@ -30,56 +29,75 @@ case class MacroCompilerAnnotation(content: String) extends NoTargetAnnotation { def params: Params = MacroCompilerUtil.objFromString(content).asInstanceOf[Params] } - -/** - * The MacroCompilerAnnotation to trigger the macro compiler. - * Note that this annotation does NOT actually target any modules for - * compilation. It simply holds all the settings for the memory compiler. The - * actual selection of which memories to compile is set in the Params. - * - * To use, simply annotate the entire circuit itself with this annotation and - * include [[MacroCompilerTransform]]. - * - */ +/** The MacroCompilerAnnotation to trigger the macro compiler. + * Note that this annotation does NOT actually target any modules for + * compilation. It simply holds all the settings for the memory compiler. The + * actual selection of which memories to compile is set in the Params. + * + * To use, simply annotate the entire circuit itself with this annotation and + * include [[MacroCompilerTransform]]. + */ object MacroCompilerAnnotation { + /** Macro compiler mode. */ sealed trait CompilerMode + /** Strict mode - must compile all memories or error out. */ case object Strict extends CompilerMode + /** Synflops mode - compile all memories with synflops (do not map to lib at all). */ case object Synflops extends CompilerMode + /** CompileAndSynflops mode - compile all memories and create mock versions of the target libs with synflops. */ case object CompileAndSynflops extends CompilerMode - /** FallbackSynflops - compile all memories to SRAM when possible and fall back to synflops if a memory fails. **/ + + /** FallbackSynflops - compile all memories to SRAM when possible and fall back to synflops if a memory fails. * */ case object FallbackSynflops extends CompilerMode - /** CompileAvailable - compile what is possible and do nothing with uncompiled memories. **/ + + /** CompileAvailable - compile what is possible and do nothing with uncompiled memories. * */ case object CompileAvailable extends CompilerMode - /** - * The default mode for the macro compiler. - * TODO: Maybe set the default to FallbackSynflops (typical for - * vlsi_mem_gen-like scripts) once it's implemented? - */ + /** The default mode for the macro compiler. + * TODO: Maybe set the default to FallbackSynflops (typical for + * vlsi_mem_gen-like scripts) once it's implemented? + */ val Default = CompileAvailable // Options as list of (CompilerMode, command-line name, description) val options: Seq[(CompilerMode, String, String)] = Seq( (Default, "default", "Select the default option from below."), (Strict, "strict", "Compile all memories to library or return an error."), - (Synflops, "synflops", "Produces synthesizable flop-based memories for all memories (do not map to lib at all); likely useful for simulation purposes."), - (CompileAndSynflops, "compileandsynflops", "Compile all memories and create mock versions of the target libs with synflops; likely also useful for simulation purposes."), - (FallbackSynflops, "fallbacksynflops", "Compile all memories to library when possible and fall back to synthesizable flop-based memories when library synth is not possible."), - (CompileAvailable, "compileavailable", "Compile all memories to library when possible and do nothing in case of errors. (default)") + ( + Synflops, + "synflops", + "Produces synthesizable flop-based memories for all memories (do not map to lib at all); likely useful for simulation purposes." + ), + ( + CompileAndSynflops, + "compileandsynflops", + "Compile all memories and create mock versions of the target libs with synflops; likely also useful for simulation purposes." + ), + ( + FallbackSynflops, + "fallbacksynflops", + "Compile all memories to library when possible and fall back to synthesizable flop-based memories when library synth is not possible." + ), + ( + CompileAvailable, + "compileavailable", + "Compile all memories to library when possible and do nothing in case of errors. (default)" + ) ) /** Helper function to select a compiler mode. */ - def stringToCompilerMode(str: String): CompilerMode = options.collectFirst { case (mode, cmd, _) if cmd == str => mode } match { + def stringToCompilerMode(str: String): CompilerMode = options.collectFirst { + case (mode, cmd, _) if cmd == str => mode + } match { case Some(x) => x - case None => throw new IllegalArgumentException("No such compiler mode " + str) + case None => throw new IllegalArgumentException("No such compiler mode " + str) } - /** - * Parameters associated to this MacroCompilerAnnotation. + /** Parameters associated to this MacroCompilerAnnotation. * * @param mem Path to memory lib * @param memFormat Type of memory lib (Some("conf"), Some("mdf"), or None (defaults to mdf)) @@ -90,26 +108,34 @@ object MacroCompilerAnnotation { * @param forceCompile Set of memories to force compiling to lib regardless of the mode * @param forceSynflops Set of memories to force compiling as flops regardless of the mode */ - case class Params(mem: String, memFormat: Option[String], lib: Option[String], hammerIR: Option[String], - costMetric: CostMetric, mode: CompilerMode, useCompiler: Boolean, - forceCompile: Set[String], forceSynflops: Set[String]) - - /** - * Create a MacroCompilerAnnotation. - * @param c Top-level circuit name (see class description) - * @param p Parameters (see above). - */ + case class Params( + mem: String, + memFormat: Option[String], + lib: Option[String], + hammerIR: Option[String], + costMetric: CostMetric, + mode: CompilerMode, + useCompiler: Boolean, + forceCompile: Set[String], + forceSynflops: Set[String]) + + /** Create a MacroCompilerAnnotation. + * @param c Top-level circuit name (see class description) + * @param p Parameters (see above). + */ def apply(c: String, p: Params): MacroCompilerAnnotation = MacroCompilerAnnotation(MacroCompilerUtil.objToString(p)) } -class MacroCompilerPass(mems: Option[Seq[Macro]], - libs: Option[Seq[Macro]], - compilers: Option[SRAMCompiler], - hammerIR: Option[String], - costMetric: CostMetric = CostMetric.default, - mode: MacroCompilerAnnotation.CompilerMode = MacroCompilerAnnotation.Default) extends firrtl.passes.Pass { +class MacroCompilerPass( + mems: Option[Seq[Macro]], + libs: Option[Seq[Macro]], + compilers: Option[SRAMCompiler], + hammerIR: Option[String], + costMetric: CostMetric = CostMetric.default, + mode: MacroCompilerAnnotation.CompilerMode = MacroCompilerAnnotation.Default) + extends firrtl.passes.Pass { // Helper function to check the legality of bitPairs. // e.g. ((0,21), (22,43)) is legal // ((0,21), (22,21)) is illegal and will throw an assert @@ -121,8 +147,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], }) } - /** - * Calculate bit pairs. + /** Calculate bit pairs. * This is a list of submemories by width. * The tuples are (lsb, msb) inclusive. * Example: (0, 7) and (8, 15) might be a split for a width=16 memory into two width=8 target memories. @@ -133,7 +158,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], * @return Bit pairs or empty list if there was an error. */ private def calculateBitPairs(mem: Macro, lib: Macro): Seq[(BigInt, BigInt)] = { - val pairedPorts = mem.sortedPorts zip lib.sortedPorts + val pairedPorts = mem.sortedPorts.zip(lib.sortedPorts) val bitPairs = ArrayBuffer[(BigInt, BigInt)]() var currentLSB: BigInt = 0 @@ -204,7 +229,9 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], splitMemory(memMask.get) } else { // e.g. mem mask = 13, lib width = 8 - System.err.println(s"Unmasked target memory: unaligned mem maskGran $p with lib (${lib.src.name}) width ${libPort.src.width.get} not supported") + System.err.println( + s"Unmasked target memory: unaligned mem maskGran $p with lib (${lib.src.name}) width ${libPort.src.width.get} not supported" + ) return Seq() } } @@ -267,9 +294,11 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], } def compile(mem: Macro, lib: Macro): Option[(Module, Macro)] = { - assert(mem.sortedPorts.lengthCompare(lib.sortedPorts.length) == 0, - "mem and lib should have an equal number of ports") - val pairedPorts = mem.sortedPorts zip lib.sortedPorts + assert( + mem.sortedPorts.lengthCompare(lib.sortedPorts.length) == 0, + "mem and lib should have an equal number of ports" + ) + val pairedPorts = mem.sortedPorts.zip(lib.sortedPorts) // Width mapping. See calculateBitPairs. val bitPairs: Seq[(BigInt, BigInt)] = calculateBitPairs(mem, lib) @@ -288,14 +317,14 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], /* Palmer: If we've got a parallel memory then we've got to take the * address bits into account. */ if (mem.src.depth > lib.src.depth) { - mem.src.ports foreach { port => + mem.src.ports.foreach { port => val high = MacroCompilerMath.ceilLog2(mem.src.depth) val low = MacroCompilerMath.ceilLog2(lib.src.depth) val ref = WRef(port.address.name) val nodeName = s"${ref.name}_sel" - val tpe = UIntType(IntWidth(high-low)) + val tpe = UIntType(IntWidth(high - low)) selects(ref.name) = WRef(nodeName, tpe) - stmts += DefNode(NoInfo, nodeName, bits(ref, high-1, low)) + stmts += DefNode(NoInfo, nodeName, bits(ref, high - 1, low)) // Donggyu: output selection should be piped if (port.output.isDefined) { val regName = s"${ref.name}_sel_reg" @@ -304,7 +333,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], and(WRef(ce.name, BoolType), WRef(re.name, BoolType)) case (Some(ce), None) => WRef(ce.name, BoolType) case (None, Some(re)) => WRef(re.name, BoolType) - case (None, None) => one + case (None, None) => one } selectRegs(ref.name) = WRef(regName, tpe) stmts += DefRegister(NoInfo, regName, tpe, WRef(port.clock.get.name), zero, WRef(regName)) @@ -318,18 +347,18 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], // Create the instance. stmts += WDefInstance(NoInfo, name, lib.src.name, lib.tpe) // Connect extra ports of the lib. - stmts ++= lib.extraPorts map { case (portName, portValue) => + stmts ++= lib.extraPorts.map { case (portName, portValue) => Connect(NoInfo, WSubField(WRef(name), portName), portValue) } } for ((memPort, libPort) <- pairedPorts) { - val addrMatch = selects get memPort.src.address.name match { + val addrMatch = selects.get(memPort.src.address.name) match { case None => one case Some(addr) => val index = UIntLiteral(i, IntWidth(bitWidth(addr.tpe))) DoPrim(PrimOps.Eq, Seq(addr, index), Nil, index.tpe) } - val addrMatchReg = selectRegs get memPort.src.address.name match { + val addrMatchReg = selectRegs.get(memPort.src.address.name) match { case None => one case Some(reg) => val index = UIntLiteral(i, IntWidth(bitWidth(reg.tpe))) @@ -342,29 +371,22 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], for (((low, high), j) <- bitPairs.zipWithIndex) { val inst = WRef(s"mem_${i}_${j}", lib.tpe) - def connectPorts2(mem: Expression, - lib: String, - polarity: Option[PortPolarity]): Statement = + def connectPorts2(mem: Expression, lib: String, polarity: Option[PortPolarity]): Statement = Connect(NoInfo, WSubField(inst, lib), portToExpression(mem, polarity)) - def connectPorts(mem: Expression, - lib: String, - polarity: PortPolarity): Statement = + def connectPorts(mem: Expression, lib: String, polarity: PortPolarity): Statement = connectPorts2(mem, lib, Some(polarity)) // Clock port mapping /* Palmer: FIXME: I don't handle memories with read/write clocks yet. */ /* Colin not all libPorts have clocks but all memPorts do*/ libPort.src.clock.foreach { cPort => - stmts += connectPorts(WRef(memPort.src.clock.get.name), - cPort.name, - cPort.polarity) } + stmts += connectPorts(WRef(memPort.src.clock.get.name), cPort.name, cPort.polarity) + } // Adress port mapping /* Palmer: The address port to a memory is just the low-order bits of * the top address. */ - stmts += connectPorts(WRef(memPort.src.address.name), - libPort.src.address.name, - libPort.src.address.polarity) + stmts += connectPorts(WRef(memPort.src.address.name), libPort.src.address.name, libPort.src.address.polarity) // Output port mapping (memPort.src.output, libPort.src.output) match { @@ -374,20 +396,20 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], * done after generating all the memories. This saves up the * output statements for later. */ val name = s"${mem}_${i}_${j}" // This name is the output from the instance (mem vs ${mem}). - val exp = portToExpression(bits(WSubField(inst, lib), high-low, 0), Some(lib_polarity)) + val exp = portToExpression(bits(WSubField(inst, lib), high - low, 0), Some(lib_polarity)) stmts += DefNode(NoInfo, name, exp) cats += WRef(name) case (None, Some(lib)) => - /* Palmer: If the inner memory has an output port but the outer - * one doesn't then it's safe to just leave the outer - * port floating. */ + /* Palmer: If the inner memory has an output port but the outer + * one doesn't then it's safe to just leave the outer + * port floating. */ case (None, None) => - /* Palmer: If there's no output ports at all (ie, read-only - * port on the memory) then just don't worry about it, - * there's nothing to do. */ + /* Palmer: If there's no output ports at all (ie, read-only + * port on the memory) then just don't worry about it, + * there's nothing to do. */ case (Some(PolarizedPort(mem, _)), None) => - System.err println "WARNING: Unable to match output ports on memory" - System.err println s" outer output port: ${mem}" + System.err.println("WARNING: Unable to match output ports on memory") + System.err.println(s" outer output port: ${mem}") return None } @@ -397,7 +419,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], /* Palmer: The input port to a memory just needs to happen in parallel, * this does a part select to narrow the memory down. */ stmts += connectPorts(bits(WRef(mem), high, low), lib, lib_polarity) - case (None, Some(lib)) => + case (None, Some(lib)) => /* Palmer: If the inner memory has an input port but the other * one doesn't then it's safe to just leave the inner * port floating. This should be handled by the @@ -406,12 +428,12 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], //Firrtl cares about dangling inputs now tie it off stmts += IsInvalid(NoInfo, WSubField(inst, lib.name)) case (None, None) => - /* Palmer: If there's no input ports at all (ie, read-only - * port on the memory) then just don't worry about it, - * there's nothing to do. */ + /* Palmer: If there's no input ports at all (ie, read-only + * port on the memory) then just don't worry about it, + * there's nothing to do. */ case (Some(PolarizedPort(mem, _)), None) => - System.err println "WARNING: Unable to match input ports on memory" - System.err println s" outer input port: ${mem}" + System.err.println("WARNING: Unable to match input ports on memory") + System.err.println(s" outer input port: ${mem}") return None } @@ -430,26 +452,33 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], // Example: if we have a lib whose maskGran is 8 but our mem's maskGran is 4. // The other case is if we're using a larger lib than mem. val usingLessThanLibMaskGran = (memPort.src.maskGran.get < libPort.src.effectiveMaskGran) - val effectiveLibWidth = if (usingLessThanLibMaskGran) - memPort.src.maskGran.get - else - libPort.src.width.get - - cat(((0 until libPort.src.width.get by libPort.src.effectiveMaskGran) map (i => { - if (usingLessThanLibMaskGran && i >= effectiveLibWidth) { - // If the memMaskGran is smaller than the lib's gran, then - // zero out the upper bits. - zero - } else { - if ((low + i) >= memPort.src.width.get) { - // If our bit is larger than the whole width of the mem, just zero out the upper bits. - zero - } else { - // Pick the appropriate bit from the mem mask. - bits(WRef(mem), (low + i) / memPort.src.effectiveMaskGran) - } - } - })).reverse) + val effectiveLibWidth = + if (usingLessThanLibMaskGran) + memPort.src.maskGran.get + else + libPort.src.width.get + + cat( + ( + (0 until libPort.src.width.get by libPort.src.effectiveMaskGran) + .map(i => { + if (usingLessThanLibMaskGran && i >= effectiveLibWidth) { + // If the memMaskGran is smaller than the lib's gran, then + // zero out the upper bits. + zero + } else { + if ((low + i) >= memPort.src.width.get) { + // If our bit is larger than the whole width of the mem, just zero out the upper bits. + zero + } else { + // Pick the appropriate bit from the mem mask. + bits(WRef(mem), (low + i) / memPort.src.effectiveMaskGran) + } + } + }) + ) + .reverse + ) } case None => /* If there is a lib mask port but no mem mask port, just turn on @@ -483,7 +512,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], // Chip enable port mapping val memChipEnable = memPort.src.chipEnable match { case Some(PolarizedPort(mem, _)) => WRef(mem) - case None => one + case None => one } // Read enable port mapping @@ -502,7 +531,11 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], * implement the outer memory's collection of ports using what * the inner memory has availiable. */ ((libPort.src.maskPort, libPort.src.writeEnable, libPort.src.chipEnable): @unchecked) match { - case (Some(PolarizedPort(mask, mask_polarity)), Some(PolarizedPort(we, we_polarity)), Some(PolarizedPort(en, en_polarity))) => + case ( + Some(PolarizedPort(mask, mask_polarity)), + Some(PolarizedPort(we, we_polarity)), + Some(PolarizedPort(en, en_polarity)) + ) => /* Palmer: This is the simple option: every port exists. */ stmts += connectPorts(memMask, mask, mask_polarity) stmts += connectPorts(andAddrMatch(memWriteEnable), we, we_polarity) @@ -510,8 +543,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], case (Some(PolarizedPort(mask, mask_polarity)), Some(PolarizedPort(we, we_polarity)), None) => /* Palmer: If we don't have a chip enable but do have mask ports. */ stmts += connectPorts(memMask, mask, mask_polarity) - stmts += connectPorts(andAddrMatch(and(memWriteEnable, memChipEnable)), - we, we_polarity) + stmts += connectPorts(andAddrMatch(and(memWriteEnable, memChipEnable)), we, we_polarity) case (None, Some(PolarizedPort(we, we_polarity)), chipEnable) => if (bitWidth(memMask.tpe) == 1) { /* Palmer: If we're expected to provide mask ports without a @@ -519,13 +551,15 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], * write enable port instead of the mask port. */ chipEnable match { case Some(PolarizedPort(en, en_polarity)) => { - stmts += connectPorts(andAddrMatch(and(memWriteEnable, memMask)), - we, we_polarity) + stmts += connectPorts(andAddrMatch(and(memWriteEnable, memMask)), we, we_polarity) stmts += connectPorts(andAddrMatch(memChipEnable), en, en_polarity) } case _ => { - stmts += connectPorts(andAddrMatch(and(and(memWriteEnable, memChipEnable), memMask)), - we, we_polarity) + stmts += connectPorts( + andAddrMatch(and(and(memWriteEnable, memChipEnable), memMask)), + we, + we_polarity + ) } } } else { @@ -533,8 +567,8 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], return None } case (None, None, None) => - // No write ports to match up (this may be a read-only port). - // This isn't necessarily an error condition. + // No write ports to match up (this may be a read-only port). + // This isn't necessarily an error condition. } } // Cat macro outputs for selection @@ -542,7 +576,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], case Some(PolarizedPort(mem, _)) if cats.nonEmpty => val name = s"${mem}_${i}" stmts += DefNode(NoInfo, name, cat(cats.toSeq.reverse)) - (outputs getOrElseUpdate (mem, ArrayBuffer[(Expression, Expression)]())) += + (outputs.getOrElseUpdate(mem, ArrayBuffer[(Expression, Expression)]())) += (addrMatchReg -> WRef(name)) case _ => } @@ -550,15 +584,17 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], } // Connect mem outputs val zeroOutputValue: Expression = UIntLiteral(0, IntWidth(mem.src.width)) - mem.src.ports foreach { port => + mem.src.ports.foreach { port => port.output match { - case Some(PolarizedPort(mem, _)) => outputs get mem match { - case Some(select) => - val output = (select foldRight (zeroOutputValue)) { - case ((cond, tval), fval) => Mux(cond, tval, fval, fval.tpe) } - stmts += Connect(NoInfo, WRef(mem), output) - case None => - } + case Some(PolarizedPort(mem, _)) => + outputs.get(mem) match { + case Some(select) => + val output = (select.foldRight(zeroOutputValue)) { case ((cond, tval), fval) => + Mux(cond, tval, fval, fval.tpe) + } + stmts += Connect(NoInfo, WRef(mem), output) + case None => + } case None => } } @@ -573,123 +609,138 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], // Try to compile each of the memories in mems. // The 'state' is c.modules, which is a list of all the firrtl modules // in the 'circuit'. - (mems foldLeft c.modules){ (modules, mem) => - - val sram = mem.src - def groupMatchesMask(group: SRAMGroup, mem:SRAMMacro): Boolean = { - val memMask = mem.ports map (_.maskGran) find (_.isDefined) map (_.get) - val libMask = group.ports map (_.maskGran) find (_.isDefined) map (_.get) - (memMask, libMask) match { - case (None, _) => true - case (Some(_), None) => false - case (Some(m), Some(l)) => l <= m //Ignore memories that don't have nice mask + (mems.foldLeft(c.modules)) { (modules, mem) => + val sram = mem.src + def groupMatchesMask(group: SRAMGroup, mem: SRAMMacro): Boolean = { + val memMask = mem.ports.map(_.maskGran).find(_.isDefined).map(_.get) + val libMask = group.ports.map(_.maskGran).find(_.isDefined).map(_.get) + (memMask, libMask) match { + case (None, _) => true + case (Some(_), None) => false + case (Some(m), Some(l)) => l <= m //Ignore memories that don't have nice mask + } } - } - // Add compiler memories that might map well to libs - val compLibs = compilers match { - case Some(SRAMCompiler(_, groups)) => { - groups.filter(g => g.family == sram.family && groupMatchesMask(g, sram)).map( g => { - for(w <- g.width; d <- g.depth if((sram.width % w == 0) && (sram.depth % d == 0))) - yield Seq(new Macro(buildSRAMMacro(g, d, w, g.vt.head))) - } ) + // Add compiler memories that might map well to libs + val compLibs = compilers match { + case Some(SRAMCompiler(_, groups)) => { + groups + .filter(g => g.family == sram.family && groupMatchesMask(g, sram)) + .map(g => { + for { + w <- g.width + d <- g.depth if ((sram.width % w == 0) && (sram.depth % d == 0)) + } yield Seq(new Macro(buildSRAMMacro(g, d, w, g.vt.head))) + }) + } + case None => Seq() } - case None => Seq() - } - val fullLibs = libs ++ compLibs.flatten.flatten - - // Try to compile mem against each lib in libs, keeping track of the - // best compiled version, external lib used, and cost. - val (best, cost) = (fullLibs foldLeft (None: Option[(Module, Macro)], Double.MaxValue)){ - case ((best, cost), lib) if mem.src.ports.size != lib.src.ports.size => - /* Palmer: FIXME: This just assumes the Chisel and vendor ports are in the same - * order, but I'm starting with what actually gets generated. */ - System.err println s"INFO: unable to compile ${mem.src.name} using ${lib.src.name} port count must match" - (best, cost) - case ((best, cost), lib) => - // Run the cost function to evaluate this potential compile. - costMetric.cost(mem, lib) match { - case Some(newCost) => { - //System.err.println(s"Cost of ${lib.src.name} for ${mem.src.name}: ${newCost}") - // Try compiling - compile(mem, lib) match { - // If it was successful and the new cost is lower - case Some(p) if (newCost < cost) => (Some(p), newCost) - case _ => (best, cost) + val fullLibs = libs ++ compLibs.flatten.flatten + + // Try to compile mem against each lib in libs, keeping track of the + // best compiled version, external lib used, and cost. + val (best, cost) = (fullLibs.foldLeft(None: Option[(Module, Macro)], Double.MaxValue)) { + case ((best, cost), lib) if mem.src.ports.size != lib.src.ports.size => + /* Palmer: FIXME: This just assumes the Chisel and vendor ports are in the same + * order, but I'm starting with what actually gets generated. */ + System.err.println(s"INFO: unable to compile ${mem.src.name} using ${lib.src.name} port count must match") + (best, cost) + case ((best, cost), lib) => + // Run the cost function to evaluate this potential compile. + costMetric.cost(mem, lib) match { + case Some(newCost) => { + //System.err.println(s"Cost of ${lib.src.name} for ${mem.src.name}: ${newCost}") + // Try compiling + compile(mem, lib) match { + // If it was successful and the new cost is lower + case Some(p) if (newCost < cost) => (Some(p), newCost) + case _ => (best, cost) + } } + case _ => (best, cost) // Cost function rejected this combination. } - case _ => (best, cost) // Cost function rejected this combination. - } - } - - // If we were able to compile anything, then replace the original module - // in the modules list with a compiled version, as well as the extmodule - // stub for the lib. - best match { - case None => { - if (mode == MacroCompilerAnnotation.Strict) - throw new MacroCompilerException(s"Target memory ${mem.src.name} could not be compiled and strict mode is activated - aborting.") - else - modules } - case Some((mod, bb)) => - hammerIR match { - case Some(f) => { - val hammerIRWriter = new FileWriter(new File(f), !firstLib) - if(firstLib) hammerIRWriter.write("[\n") - hammerIRWriter.write(bb.src.toJSON().toString()) - hammerIRWriter.write("\n,\n") - hammerIRWriter.close() - firstLib = false - } - case None => + + // If we were able to compile anything, then replace the original module + // in the modules list with a compiled version, as well as the extmodule + // stub for the lib. + best match { + case None => { + if (mode == MacroCompilerAnnotation.Strict) + throw new MacroCompilerException( + s"Target memory ${mem.src.name} could not be compiled and strict mode is activated - aborting." + ) + else + modules } - (modules filterNot (m => m.name == mod.name || m.name == bb.blackbox.name)) ++ Seq(mod, bb.blackbox) + case Some((mod, bb)) => + hammerIR match { + case Some(f) => { + val hammerIRWriter = new FileWriter(new File(f), !firstLib) + if (firstLib) hammerIRWriter.write("[\n") + hammerIRWriter.write(bb.src.toJSON().toString()) + hammerIRWriter.write("\n,\n") + hammerIRWriter.close() + firstLib = false + } + case None => + } + (modules.filterNot(m => m.name == mod.name || m.name == bb.blackbox.name)) ++ Seq(mod, bb.blackbox) + } } - } case _ => c.modules } c.copy(modules = modules) } } -class MacroCompilerTransform extends Transform { - def inputForm = MidForm - def outputForm = MidForm +class MacroCompilerTransform extends Transform with DependencyAPIMigration { + override def prerequisites = Forms.LowForm + override def optionalPrerequisites = Forms.LowFormOptimized + override def optionalPrerequisiteOf = Forms.LowEmitters + override def invalidates(a: Transform) = false def execute(state: CircuitState) = state.annotations.collect { case a: MacroCompilerAnnotation => a } match { case Seq(anno: MacroCompilerAnnotation) => - val MacroCompilerAnnotation.Params(memFile, memFileFormat, libFile, hammerIR, costMetric, mode, useCompiler, forceCompile, forceSynflops) = anno.params + val MacroCompilerAnnotation.Params( + memFile, + memFileFormat, + libFile, + hammerIR, + costMetric, + mode, + useCompiler, + forceCompile, + forceSynflops + ) = anno.params if (mode == MacroCompilerAnnotation.FallbackSynflops) { throw new UnsupportedOperationException("Not implemented yet") } // Check that we don't have any modules both forced to compile and synflops. - assert((forceCompile intersect forceSynflops).isEmpty, "Cannot have modules both forced to compile and synflops") + assert((forceCompile.intersect(forceSynflops)).isEmpty, "Cannot have modules both forced to compile and synflops") // Read, eliminate None, get only SRAM, make firrtl macro val mems: Option[Seq[Macro]] = (memFileFormat match { case Some("conf") => Utils.readConfFromPath(Some(memFile)) - case _ => mdf.macrolib.Utils.readMDFFromPath(Some(memFile)) + case _ => mdf.macrolib.Utils.readMDFFromPath(Some(memFile)) }) match { - case Some(x:Seq[mdf.macrolib.Macro]) => - Some(Utils.filterForSRAM(Some(x)) getOrElse(List()) map {new Macro(_)}) + case Some(x: Seq[mdf.macrolib.Macro]) => + Some(Utils.filterForSRAM(Some(x)).getOrElse(List()).map { new Macro(_) }) case _ => None } val libs: Option[Seq[Macro]] = mdf.macrolib.Utils.readMDFFromPath(libFile) match { - case Some(x:Seq[mdf.macrolib.Macro]) => - Some(Utils.filterForSRAM(Some(x)) getOrElse(List()) map {new Macro(_)}) + case Some(x: Seq[mdf.macrolib.Macro]) => + Some(Utils.filterForSRAM(Some(x)).getOrElse(List()).map { new Macro(_) }) case _ => None } val compilers: Option[mdf.macrolib.SRAMCompiler] = mdf.macrolib.Utils.readMDFFromPath(libFile) match { - case Some(x:Seq[mdf.macrolib.Macro]) => - if(useCompiler){ + case Some(x: Seq[mdf.macrolib.Macro]) => + if (useCompiler) { findSRAMCompiler(Some(x)) - } - else None + } else None case _ => None } - // Helper function to turn a set of mem names into a Seq[Macro]. def setToSeqMacro(names: Set[String]): Seq[Macro] = { names.toSeq.map(memName => mems.get.collectFirst { case m if m.src.name == memName => m }.get) @@ -707,21 +758,25 @@ class MacroCompilerTransform extends Transform { val transforms = Seq( new MacroCompilerPass(memCompile, libs, compilers, hammerIR, costMetric, mode), - new SynFlopsPass(true, memSynflops ++ (if (mode == MacroCompilerAnnotation.CompileAndSynflops) { - libs.get - } else { - Seq.empty - }))) - (transforms foldLeft state) ((s, xform) => xform runTransform s).copy(form = outputForm) + new SynFlopsPass( + true, + memSynflops ++ (if (mode == MacroCompilerAnnotation.CompileAndSynflops) { + libs.get + } else { + Seq.empty + }) + ) + ) + (transforms.foldLeft(state))((s, xform) => xform.runTransform(s)) case _ => state } } -// FIXME: Use firrtl.LowerFirrtlOptimizations -class MacroCompilerOptimizations extends SeqTransform { - def inputForm: CircuitForm = LowForm - - def outputForm: CircuitForm = LowForm +class MacroCompilerOptimizations extends SeqTransform with DependencyAPIMigration { + override def prerequisites = Forms.LowForm + override def optionalPrerequisites = Forms.LowFormOptimized + override def optionalPrerequisiteOf = Forms.LowEmitters + override def invalidates(a: Transform) = false def transforms: Seq[Transform] = Seq( passes.RemoveValidIf, @@ -730,16 +785,8 @@ class MacroCompilerOptimizations extends SeqTransform { new firrtl.transforms.ConstantPropagation, passes.Legalize, passes.SplitExpressions, - passes.CommonSubexpressionElimination) -} - -class MacroCompiler extends Compiler { - def emitter: Emitter = new VerilogEmitter - - def transforms: Seq[Transform] = - Seq(new MacroCompilerTransform) ++ - getLoweringTransforms(firrtl.ChirrtlForm, firrtl.LowForm) ++ - Seq(new MacroCompilerOptimizations) + passes.CommonSubexpressionElimination + ) } object MacroCompiler extends App { @@ -757,8 +804,9 @@ object MacroCompiler extends App { type MacroParamMap = Map[MacroParam, String] type CostParamMap = Map[String, String] type ForcedMemories = (Set[String], Set[String]) - val modeOptions: Seq[String] = MacroCompilerAnnotation.options - .map { case (_, cmd, description) => s" $cmd: $description" } + val modeOptions: Seq[String] = MacroCompilerAnnotation.options.map { case (_, cmd, description) => + s" $cmd: $description" + } val usage: String = (Seq( "Options:", " -n, --macro-conf: The set of macros to compile in firrtl-generated conf format (exclusive with -m)", @@ -773,16 +821,20 @@ object MacroCompiler extends App { " --force-compile [mem]: Force the given memory to be compiled to target libs regardless of the mode", " --force-synflops [mem]: Force the given memory to be compiled via synflops regardless of the mode", " --mode:" - ) ++ modeOptions) mkString "\n" - - def parseArgs(map: MacroParamMap, costMap: CostParamMap, forcedMemories: ForcedMemories, - args: List[String]): (MacroParamMap, CostParamMap, ForcedMemories) = + ) ++ modeOptions).mkString("\n") + + def parseArgs( + map: MacroParamMap, + costMap: CostParamMap, + forcedMemories: ForcedMemories, + args: List[String] + ): (MacroParamMap, CostParamMap, ForcedMemories) = args match { case Nil => (map, costMap, forcedMemories) case ("-n" | "--macro-conf") :: value :: tail => - parseArgs(map + (Macros -> value) + (MacrosFormat -> "conf"), costMap, forcedMemories, tail) + parseArgs(map + (Macros -> value) + (MacrosFormat -> "conf"), costMap, forcedMemories, tail) case ("-m" | "--macro-mdf") :: value :: tail => - parseArgs(map + (Macros -> value) + (MacrosFormat -> "mdf"), costMap, forcedMemories, tail) + parseArgs(map + (Macros -> value) + (MacrosFormat -> "mdf"), costMap, forcedMemories, tail) case ("-l" | "--library") :: value :: tail => parseArgs(map + (Library -> value), costMap, forcedMemories, tail) case ("-u" | "--use-compiler") :: tail => @@ -810,11 +862,17 @@ object MacroCompiler extends App { } def run(args: List[String]) { - val (params, costParams, forcedMemories) = parseArgs(Map[MacroParam, String](), Map[String, String](), (Set.empty, Set.empty), args) + val (params, costParams, forcedMemories) = + parseArgs(Map[MacroParam, String](), Map[String, String](), (Set.empty, Set.empty), args) try { val macros = params.get(MacrosFormat) match { - case Some("conf") => Utils.filterForSRAM(Utils.readConfFromPath(params.get(Macros))).get map (x => (new Macro(x)).blackbox) - case _ => Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(params.get(Macros))).get map (x => (new Macro(x)).blackbox) + case Some("conf") => + Utils.filterForSRAM(Utils.readConfFromPath(params.get(Macros))).get.map(x => (new Macro(x)).blackbox) + case _ => + Utils + .filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(params.get(Macros))) + .get + .map(x => (new Macro(x)).blackbox) } if (macros.nonEmpty) { @@ -822,35 +880,39 @@ object MacroCompiler extends App { // determined as the firrtl "top-level module". val circuit = Circuit(NoInfo, macros, macros.last.name) val annotations = AnnotationSeq( - Seq(MacroCompilerAnnotation( - circuit.main, - MacroCompilerAnnotation.Params( - params.get(Macros).get, params.get(MacrosFormat), params.get(Library), - params.get(HammerIR), - CostMetric.getCostMetric(params.getOrElse(CostFunc, "default"), costParams), - MacroCompilerAnnotation.stringToCompilerMode(params.getOrElse(Mode, "default")), - params.contains(UseCompiler), - forceCompile = forcedMemories._1, forceSynflops = forcedMemories._2 + Seq( + MacroCompilerAnnotation( + circuit.main, + MacroCompilerAnnotation.Params( + params(Macros), + params.get(MacrosFormat), + params.get(Library), + params.get(HammerIR), + CostMetric.getCostMetric(params.getOrElse(CostFunc, "default"), costParams), + MacroCompilerAnnotation.stringToCompilerMode(params.getOrElse(Mode, "default")), + params.contains(UseCompiler), + forceCompile = forcedMemories._1, + forceSynflops = forcedMemories._2 + ) ) - )) + ) ) // The actual MacroCompilerTransform basically just generates an input circuit - val macroCompilerInput = CircuitState(circuit, MidForm, annotations) + val macroCompilerInput = CircuitState(circuit, annotations) val macroCompiled = (new MacroCompilerTransform).execute(macroCompilerInput) - - // Since the MacroCompiler defines its own CLI, reconcile this with FIRRTL options - val firOptions = new ExecutionOptionsManager("macrocompiler") with HasFirrtlOptions { - firrtlOptions = FirrtlExecutionOptions( - outputFileNameOverride = params.get(Verilog).getOrElse(""), - noDCE = true, - firrtlSource = Some(macroCompiled.circuit.serialize) - ) - } - // Run FIRRTL compiler - Driver.execute(firOptions) + (new FirrtlStage).execute( + Array.empty, + Seq( + OutputFileAnnotation(params.getOrElse(Verilog, "")), + RunFirrtlTransformAnnotation(new VerilogEmitter), + EmitCircuitAnnotation(classOf[VerilogEmitter]), + NoDCEAnnotation, + FirrtlSourceAnnotation(macroCompiled.circuit.serialize) + ) + ) params.get(HammerIR) match { case Some(hammerIRFile: String) => { @@ -865,7 +927,7 @@ object MacroCompiler extends App { } } else { // Warn user - System.err println "WARNING: Empty *.mems.conf file. No memories generated." + System.err.println("WARNING: Empty *.mems.conf file. No memories generated.") // Emit empty verilog file if no macros found params.get(Verilog) match { @@ -879,8 +941,11 @@ object MacroCompiler extends App { } } catch { case e: java.util.NoSuchElementException => - e.printStackTrace() - println(usage) + if (args.isEmpty) { + println("Command line arguments must be specified") + } else { + e.printStackTrace() + } e.printStackTrace() sys.exit(1) case e: MacroCompilerException => diff --git a/macros/src/main/scala/barstools/macros/SynFlops.scala b/macros/src/main/scala/barstools/macros/SynFlops.scala new file mode 100644 index 00000000..77ea4c96 --- /dev/null +++ b/macros/src/main/scala/barstools/macros/SynFlops.scala @@ -0,0 +1,151 @@ +// See LICENSE for license details. + +package barstools.macros + +import barstools.macros.Utils._ +import firrtl.Utils._ +import firrtl._ +import firrtl.ir._ +import firrtl.passes.MemPortUtils.memPortField + +class SynFlopsPass(synflops: Boolean, libs: Seq[Macro]) extends firrtl.passes.Pass { + val extraMods = scala.collection.mutable.ArrayBuffer.empty[Module] + lazy val libMods = (libs.map { lib => + lib.src.name -> { + val (dataType, dataWidth) = (lib.src.ports.foldLeft(None: Option[BigInt]))((res, port) => + (res, port.maskPort) match { + case (_, None) => + res + case (None, Some(_)) => + Some(port.effectiveMaskGran) + case (Some(x), Some(_)) => + assert(x == port.effectiveMaskGran) + res + } + ) match { + case None => (UIntType(IntWidth(lib.src.width)), lib.src.width) + case Some(gran) => (UIntType(IntWidth(gran)), gran.intValue) + } + + val maxDepth = min(lib.src.depth, 1 << 26) + val numMems = lib.src.depth / maxDepth + + // Change macro to be mapped onto to look like the below mem + // by changing its depth, and width + val lib_macro = new Macro( + lib.src.copy( + name = "split_" + lib.src.name, + depth = maxDepth, + width = dataWidth, + ports = lib.src.ports.map(p => + p.copy( + width = p.width.map(_ => dataWidth), + depth = p.depth.map(_ => maxDepth), + maskGran = p.maskGran.map(_ => dataWidth) + ) + ) + ) + ) + val mod_macro = (new MacroCompilerPass(None, None, None, None)).compile(lib, lib_macro) + val (real_mod, real_macro) = mod_macro.get + + val mem = DefMemory( + NoInfo, + "ram", + dataType, + maxDepth, + 1, // writeLatency + 1, // readLatency. This is possible because of VerilogMemDelays + real_macro.readers.indices.map(i => s"R_$i"), + real_macro.writers.indices.map(i => s"W_$i"), + real_macro.readwriters.indices.map(i => s"RW_$i") + ) + + 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 { + case (Some(en_port), Some(re_port)) => + and(portToExpression(en_port), portToExpression(re_port)) + case (Some(en_port), None) => portToExpression(en_port) + case (None, Some(re_port)) => portToExpression(re_port) + case (None, None) => one + } + val data = memPortField(mem, s"R_$i", "data") + val read = data + Seq( + Connect(NoInfo, memPortField(mem, s"R_$i", "clk"), clock), + Connect(NoInfo, memPortField(mem, s"R_$i", "addr"), address), + Connect(NoInfo, memPortField(mem, s"R_$i", "en"), enable), + Connect(NoInfo, WRef(r.src.output.get.name), read) + ) + } + + val writeConnects = real_macro.writers.zipWithIndex.flatMap { case (w, i) => + val clock = portToExpression(w.src.clock.get) + val address = portToExpression(w.src.address) + val enable = (w.src.chipEnable, w.src.writeEnable) match { + case (Some(en), Some(we)) => + and(portToExpression(en), portToExpression(we)) + case (Some(en), None) => portToExpression(en) + case (None, Some(we)) => portToExpression(we) + case (None, None) => zero // is it possible? + } + val mask = w.src.maskPort match { + case Some(m) => portToExpression(m) + case None => one + } + val data = memPortField(mem, s"W_$i", "data") + val write = portToExpression(w.src.input.get) + Seq( + Connect(NoInfo, memPortField(mem, s"W_$i", "clk"), clock), + Connect(NoInfo, memPortField(mem, s"W_$i", "addr"), address), + Connect(NoInfo, memPortField(mem, s"W_$i", "en"), enable), + Connect(NoInfo, memPortField(mem, s"W_$i", "mask"), mask), + Connect(NoInfo, data, write) + ) + } + + val readwriteConnects = real_macro.readwriters.zipWithIndex.flatMap { case (rw, i) => + val clock = portToExpression(rw.src.clock.get) + val address = portToExpression(rw.src.address) + val wmode = rw.src.writeEnable match { + case Some(we) => portToExpression(we) + case None => zero // is it possible? + } + val wmask = rw.src.maskPort match { + case Some(wm) => portToExpression(wm) + case None => one + } + val enable = (rw.src.chipEnable, rw.src.readEnable) match { + case (Some(en), Some(re)) => + and(portToExpression(en), or(portToExpression(re), wmode)) + case (Some(en), None) => portToExpression(en) + case (None, Some(re)) => or(portToExpression(re), wmode) + case (None, None) => one + } + val wdata = memPortField(mem, s"RW_$i", "wdata") + val rdata = memPortField(mem, s"RW_$i", "rdata") + val write = portToExpression(rw.src.input.get) + val read = rdata + Seq( + Connect(NoInfo, memPortField(mem, s"RW_$i", "clk"), clock), + Connect(NoInfo, memPortField(mem, s"RW_$i", "addr"), address), + Connect(NoInfo, memPortField(mem, s"RW_$i", "en"), enable), + Connect(NoInfo, memPortField(mem, s"RW_$i", "wmode"), wmode), + Connect(NoInfo, memPortField(mem, s"RW_$i", "wmask"), wmask), + Connect(NoInfo, WRef(rw.src.output.get.name), read), + Connect(NoInfo, wdata, write) + ) + } + + extraMods.append(real_macro.module(Block(mem +: (readConnects ++ writeConnects ++ readwriteConnects)))) + real_mod + } + }).toMap + + def run(c: Circuit): Circuit = { + if (!synflops) c + else c.copy(modules = (c.modules.map(m => libMods.getOrElse(m.name, m))) ++ extraMods) + } +} diff --git a/macros/src/main/scala/barstools/macros/Utils.scala b/macros/src/main/scala/barstools/macros/Utils.scala new file mode 100644 index 00000000..9afa51f3 --- /dev/null +++ b/macros/src/main/scala/barstools/macros/Utils.scala @@ -0,0 +1,269 @@ +// See LICENSE for license details. + +package barstools.macros + +import firrtl.Utils.BoolType +import firrtl.ir._ +import firrtl.passes.memlib._ +import firrtl.{PrimOps, _} +import mdf.macrolib.{Input => _, Output => _, _} + +import scala.language.implicitConversions + +object MacroCompilerMath { + def ceilLog2(x: BigInt): Int = (x - 1).bitLength +} + +class FirrtlMacroPort(port: MacroPort) { + val src = port + + val isReader = port.output.nonEmpty && port.input.isEmpty + val isWriter = port.input.nonEmpty && port.output.isEmpty + val isReadWriter = port.input.nonEmpty && port.output.nonEmpty + + val addrType = UIntType(IntWidth(MacroCompilerMath.ceilLog2(port.depth.get).max(1))) + val dataType = UIntType(IntWidth(port.width.get)) + val maskType = UIntType(IntWidth(port.width.get / port.effectiveMaskGran)) + + // Bundle representing this macro port. + val tpe = BundleType( + Seq(Field(port.address.name, Flip, addrType)) ++ + (port.clock.map(p => Field(p.name, Flip, ClockType))) ++ + (port.input.map(p => Field(p.name, Flip, dataType))) ++ + (port.output.map(p => Field(p.name, Default, dataType))) ++ + (port.chipEnable.map(p => Field(p.name, Flip, BoolType))) ++ + (port.readEnable.map(p => Field(p.name, Flip, BoolType))) ++ + (port.writeEnable.map(p => Field(p.name, Flip, BoolType))) ++ + (port.maskPort.map(p => Field(p.name, Flip, maskType))) + ) + val ports = tpe.fields.map(f => + Port( + NoInfo, + f.name, + f.flip match { + case Default => Output + case Flip => Input + }, + f.tpe + ) + ) +} + +// Reads an SRAMMacro and generates firrtl blackboxes. +class Macro(srcMacro: SRAMMacro) { + val src = srcMacro + + val firrtlPorts = srcMacro.ports.map { new FirrtlMacroPort(_) } + + val writers = firrtlPorts.filter(p => p.isWriter) + val readers = firrtlPorts.filter(p => p.isReader) + val readwriters = firrtlPorts.filter(p => p.isReadWriter) + + val sortedPorts = writers ++ readers ++ readwriters + val extraPorts = srcMacro.extraPorts.map { p => + assert(p.portType == Constant) // TODO: release it? + val name = p.name + val width = BigInt(p.width.toLong) + val value = BigInt(p.value.toLong) + (name -> UIntLiteral(value, IntWidth(width))) + } + + // Bundle representing this memory blackbox + val tpe = BundleType(firrtlPorts.flatMap(_.tpe.fields)) + + private val modPorts = (firrtlPorts.flatMap(_.ports)) ++ + (extraPorts.map { case (name, value) => Port(NoInfo, name, Input, value.tpe) }) + val blackbox = ExtModule(NoInfo, srcMacro.name, modPorts, srcMacro.name, Nil) + def module(body: Statement) = Module(NoInfo, srcMacro.name, modPorts, body) +} + +object Utils { + def filterForSRAM(s: Option[Seq[mdf.macrolib.Macro]]): Option[Seq[mdf.macrolib.SRAMMacro]] = { + s match { + case Some(l: Seq[mdf.macrolib.Macro]) => + Some(l.filter { _.isInstanceOf[mdf.macrolib.SRAMMacro] }.map { m => m.asInstanceOf[mdf.macrolib.SRAMMacro] }) + case _ => None + } + } + // This utility reads a conf in and returns MDF like mdf.macrolib.Utils.readMDFFromPath + def readConfFromPath(path: Option[String]): Option[Seq[mdf.macrolib.Macro]] = { + path.map((p) => Utils.readConfFromString(scala.io.Source.fromFile(p).mkString)) + } + def readConfFromString(str: String): Seq[mdf.macrolib.Macro] = { + MemConf.fromString(str).map { m: MemConf => + val ports = m.ports.map { case (port, num) => Seq.fill(num)(port) }.reduce(_ ++ _) + SRAMMacro( + m.name, + m.width, + m.depth, + Utils.portSpecToFamily(ports), + Utils.portSpecToMacroPort(m.width, m.depth, m.maskGranularity, ports) + ) + } + } + def portSpecToFamily(ports: Seq[MemPort]): String = { + val numR = ports.count(_ match { case ReadPort => true; case _ => false }) + val numW = ports.count(_ match { case WritePort | MaskedWritePort => true; case _ => false }) + val numRW = ports.count(_ match { case ReadWritePort | MaskedReadWritePort => true; case _ => false }) + val numRStr = if (numR > 0) s"${numR}r" else "" + val numWStr = if (numW > 0) s"${numW}w" else "" + val numRWStr = if (numRW > 0) s"${numRW}rw" else "" + return numRStr + numWStr + numRWStr + } + // This translates between two represenations of ports + def portSpecToMacroPort(width: Int, depth: BigInt, maskGran: Option[Int], ports: Seq[MemPort]): Seq[MacroPort] = { + var numR = 0 + var numW = 0 + var numRW = 0 + ports.map { + _ match { + case ReadPort => { + val portName = s"R${numR}" + numR += 1 + MacroPort( + width = Some(width), + depth = Some(depth), + address = PolarizedPort(s"${portName}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), + readEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)), + output = Some(PolarizedPort(s"${portName}_data", ActiveHigh)) + ) + } + case WritePort => { + val portName = s"W${numW}" + numW += 1 + MacroPort( + width = Some(width), + depth = Some(depth), + address = PolarizedPort(s"${portName}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), + writeEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)), + input = Some(PolarizedPort(s"${portName}_data", ActiveHigh)) + ) + } + case MaskedWritePort => { + val portName = s"W${numW}" + numW += 1 + MacroPort( + width = Some(width), + depth = Some(depth), + address = PolarizedPort(s"${portName}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), + writeEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)), + maskPort = Some(PolarizedPort(s"${portName}_mask", ActiveHigh)), + maskGran = maskGran, + input = Some(PolarizedPort(s"${portName}_data", ActiveHigh)) + ) + } + case ReadWritePort => { + val portName = s"RW${numRW}" + numRW += 1 + MacroPort( + width = Some(width), + depth = Some(depth), + address = PolarizedPort(s"${portName}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), + chipEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)), + writeEnable = Some(PolarizedPort(s"${portName}_wmode", ActiveHigh)), + input = Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)), + output = Some(PolarizedPort(s"${portName}_rdata", ActiveHigh)) + ) + } + case MaskedReadWritePort => { + val portName = s"RW${numRW}" + numRW += 1 + MacroPort( + width = Some(width), + depth = Some(depth), + address = PolarizedPort(s"${portName}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), + chipEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)), + writeEnable = Some(PolarizedPort(s"${portName}_wmode", ActiveHigh)), + maskPort = Some(PolarizedPort(s"${portName}_wmask", ActiveHigh)), + maskGran = maskGran, + input = Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)), + output = Some(PolarizedPort(s"${portName}_rdata", ActiveHigh)) + ) + } + } + } + } + def findSRAMCompiler(s: Option[Seq[mdf.macrolib.Macro]]): Option[mdf.macrolib.SRAMCompiler] = { + s match { + case Some(l: Seq[mdf.macrolib.Macro]) => + l.collectFirst { case x: mdf.macrolib.SRAMCompiler => + x + } + case _ => None + } + } + def buildSRAMMacros(s: mdf.macrolib.SRAMCompiler): Seq[mdf.macrolib.SRAMMacro] = { + for { + g <- s.groups + d <- g.depth + w <- g.width + vt <- g.vt + } yield mdf.macrolib.SRAMMacro( + makeName(g, d, w, vt), + w, + d, + g.family, + g.ports.map(_.copy(width = Some(w), depth = Some(d))), + vt, + g.mux, + g.extraPorts + ) + } + def buildSRAMMacro(g: mdf.macrolib.SRAMGroup, d: Int, w: Int, vt: String): mdf.macrolib.SRAMMacro = { + return mdf.macrolib.SRAMMacro( + makeName(g, d, w, vt), + w, + d, + g.family, + g.ports.map(_.copy(width = Some(w), depth = Some(d))), + vt, + g.mux, + g.extraPorts + ) + } + def makeName(g: mdf.macrolib.SRAMGroup, depth: Int, width: Int, vt: String): String = { + g.name.foldLeft("") { (builder, next) => + next match { + case "depth" | "DEPTH" => builder + depth + case "width" | "WIDTH" => builder + width + case "vt" => builder + vt.toLowerCase + case "VT" => builder + vt.toUpperCase + case "family" => builder + g.family.toLowerCase + case "FAMILY" => builder + g.family.toUpperCase + case "mux" | "MUX" => builder + g.mux + case other => builder + other + } + } + } + + def and(e1: Expression, e2: Expression) = + DoPrim(PrimOps.And, Seq(e1, e2), Nil, e1.tpe) + def or(e1: Expression, e2: Expression) = + DoPrim(PrimOps.Or, Seq(e1, e2), Nil, e1.tpe) + def bits(e: Expression, high: BigInt, low: BigInt): Expression = + DoPrim(PrimOps.Bits, Seq(e), Seq(high, low), UIntType(IntWidth(high - low + 1))) + def bits(e: Expression, idx: BigInt): Expression = bits(e, idx, idx) + def cat(es: Seq[Expression]): Expression = + if (es.size == 1) es.head + else DoPrim(PrimOps.Cat, Seq(es.head, cat(es.tail)), Nil, UnknownType) + def not(e: Expression) = + DoPrim(PrimOps.Not, Seq(e), Nil, e.tpe) + + // Convert a port to a FIRRTL expression, handling polarity along the way. + def portToExpression(pp: PolarizedPort): Expression = + portToExpression(WRef(pp.name), Some(pp.polarity)) + + def portToExpression(exp: Expression, polarity: Option[PortPolarity]): Expression = + polarity match { + case Some(ActiveLow) | Some(NegativeEdge) => not(exp) + case _ => exp + } + + // Check if a number is a power of two + def isPowerOfTwo(x: Int): Boolean = (x & (x - 1)) == 0 +} diff --git a/macros/src/test/resources/lib-MaskPortTest.json b/macros/src/test/resources/lib-MaskPortTest.json index 72df7947..784aeafb 100644 --- a/macros/src/test/resources/lib-MaskPortTest.json +++ b/macros/src/test/resources/lib-MaskPortTest.json @@ -1,27 +1,29 @@ [ { - "type" : "sram", - "name" : "fake_mem", - "width" : 64, - "depth" : "512", - "mux" : 4, - "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" : "wen", - "write enable port polarity" : "active high", - "read enable port name" : "ren", - "read enable port polarity" : "active high", - "output port name" : "dataout", - "output port polarity" : "active high", - "input port name" : "datain", - "input port polarity" : "active high", - "mask port name" : "mport", - "mask port polarity" : "active low", - "mask granularity" : 1 - } ] + "type": "sram", + "name": "fake_mem", + "width": 64, + "depth": "512", + "mux": 4, + "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": "wen", + "write enable port polarity": "active high", + "read enable port name": "ren", + "read enable port polarity": "active high", + "output port name": "dataout", + "output port polarity": "active high", + "input port name": "datain", + "input port polarity": "active high", + "mask port name": "mport", + "mask port polarity": "active low", + "mask granularity": 1 + } + ] } ] diff --git a/macros/src/test/resources/lib-WriteEnableTest.json b/macros/src/test/resources/lib-WriteEnableTest.json index be7852a6..50acef41 100644 --- a/macros/src/test/resources/lib-WriteEnableTest.json +++ b/macros/src/test/resources/lib-WriteEnableTest.json @@ -1,24 +1,26 @@ [ { - "type" : "sram", - "name" : "fake_mem", - "width" : 64, - "depth" : "4096", - "mux" : 4, - "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" : "wen", - "write enable port polarity" : "active high", - "read enable port name" : "ren", - "read enable port polarity" : "active high", - "output port name" : "dataout", - "output port polarity" : "active high", - "input port name" : "datain", - "input port polarity" : "active high" - } ] + "type": "sram", + "name": "fake_mem", + "width": 64, + "depth": "4096", + "mux": 4, + "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": "wen", + "write enable port polarity": "active high", + "read enable port name": "ren", + "read enable port polarity": "active high", + "output port name": "dataout", + "output port polarity": "active high", + "input port name": "datain", + "input port polarity": "active high" + } + ] } ] diff --git a/macros/src/test/scala/MacroCompilerSpec.scala b/macros/src/test/scala/MacroCompilerSpec.scala deleted file mode 100644 index 8cdcf354..00000000 --- a/macros/src/test/scala/MacroCompilerSpec.scala +++ /dev/null @@ -1,453 +0,0 @@ -// See LICENSE for license details. - -package barstools.macros - -import firrtl.ir.{Circuit, NoInfo} -import firrtl.passes.RemoveEmpty -import firrtl.Parser.parse - -import java.io.{File, StringWriter} - -import mdf.macrolib.SRAMMacro - -abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalatest.Matchers { - import scala.language.implicitConversions - implicit def String2SomeString(i: String): Option[String] = Some(i) - val testDir: String = "test_run_dir/macros" - new File(testDir).mkdirs // Make sure the testDir exists - - // Override these to change the prefixing of macroDir and testDir - val memPrefix: String = testDir - val libPrefix: String = testDir - val vPrefix: String = testDir - - // Override this to use a different cost metric. - // If this is None, the compile() call will not have any -c/-cp arguments, and - // execute() will use CostMetric.default. - val costMetric: Option[CostMetric] = None - private def getCostMetric: CostMetric = costMetric.getOrElse(CostMetric.default) - - private def costMetricCmdLine = { - costMetric match { - case None => Nil - case Some(m) => { - val name = m.name - val params = m.commandLineParams - List("-c", name) ++ params.flatMap{ case (key, value) => List("-cp", key, value) } - } - } - } - - private def args(mem: String, lib: Option[String], v: String, synflops: Boolean, useCompiler: Boolean) = - List("-m", mem.toString, "-v", v) ++ - (lib match { case None => Nil case Some(l) => List("-l", l.toString) }) ++ - costMetricCmdLine ++ - (if (synflops) List("--mode", "synflops") else Nil) ++ - (if (useCompiler) List("--use-compiler") else Nil) - - // Run the full compiler as if from the command line interface. - // Generates the Verilog; useful in testing since an error will throw an - // exception. - def compile(mem: String, lib: String, v: String, synflops: Boolean) { - compile(mem, Some(lib), v, synflops) - } - def compile(mem: String, lib: Option[String], v: String, synflops: Boolean, useCompiler: Boolean = false) { - var mem_full = concat(memPrefix, mem) - var lib_full = concat(libPrefix, lib) - var v_full = concat(vPrefix, v) - - MacroCompiler.run(args(mem_full, lib_full, v_full, synflops, useCompiler)) - } - - // Helper functions to write macro libraries to the given files. - def writeToLib(lib: String, libs: Seq[mdf.macrolib.Macro]) = { - mdf.macrolib.Utils.writeMDFToPath(Some(concat(libPrefix, lib)), libs) - } - - def writeToMem(mem: String, mems: Seq[mdf.macrolib.Macro]) = { - mdf.macrolib.Utils.writeMDFToPath(Some(concat(memPrefix, mem)), mems) - } - - // Convenience function for running both compile, execute, and test at once. - def compileExecuteAndTest(mem: String, lib: Option[String], v: String, output: String, synflops: Boolean = false, useCompiler: Boolean = false): Unit = { - compile(mem, lib, v, synflops, useCompiler) - val result = execute(mem, lib, synflops, useCompiler) - test(result, output) - } - - // Compare FIRRTL outputs after reparsing output with ScalaTest ("should be"). - def test(result: Circuit, output: String): Unit = { - val gold = RemoveEmpty run parse(output) - (result.serialize) should be (gold.serialize) - } - - // Execute the macro compiler and returns a Circuit containing the output of - // the memory compiler. - def execute(memFile: Option[String], libFile: Option[String], synflops: Boolean): Circuit = execute(memFile, libFile, synflops, false) - def execute(memFile: Option[String], libFile: Option[String], synflops: Boolean, useCompiler: Boolean): Circuit = { - var mem_full = concat(memPrefix, memFile) - var lib_full = concat(libPrefix, libFile) - - require(memFile.isDefined) - val mems: Seq[Macro] = Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(mem_full)).get map (new Macro(_)) - val libs: Option[Seq[Macro]] = if(useCompiler) { - Utils.findSRAMCompiler(mdf.macrolib.Utils.readMDFFromPath(lib_full)).map{x => Utils.buildSRAMMacros(x).map(new Macro(_)) } - } else { - Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(lib_full)) match { - case Some(x) => Some(x map (new Macro(_))) - case None => None - } - } - val macros = mems map (_.blackbox) - val circuit = Circuit(NoInfo, macros, macros.last.name) - val passes = Seq( - new MacroCompilerPass(Some(mems), libs, None, None, getCostMetric, if (synflops) MacroCompilerAnnotation.Synflops else MacroCompilerAnnotation.Default), - new SynFlopsPass(synflops, libs getOrElse mems), - RemoveEmpty) - val result: Circuit = (passes foldLeft circuit)((c, pass) => pass run c) - result - } - - - // Helper method to deal with String + Option[String] - private def concat(a: String, b: String): String = {a + "/" + b} - private def concat(a: String, b: Option[String]): Option[String] = { - b match { - case Some(b2:String) => Some(a + "/" + b2) - case _ => None - } - } -} - -// A collection of standard SRAM generators. -trait HasSRAMGenerator { - import mdf.macrolib._ - import scala.language.implicitConversions - implicit def Int2SomeInt(i: Int): Option[Int] = Some(i) - implicit def BigInt2SomeBigInt(i: BigInt): Option[BigInt] = Some(i) - - - // Generate a standard (read/write/combo) port for testing. - // Helper methods for optional width argument - def generateTestPort( - prefix: String, - width: Option[Int], - depth: Option[BigInt], - maskGran: Option[Int] = None, - read: Boolean, - readEnable: Boolean = false, - write: Boolean, - writeEnable: Boolean = false - ): MacroPort = { - val realPrefix = if (prefix == "") "" else prefix + "_" - - MacroPort( - address = PolarizedPort(name = realPrefix + "addr", polarity = ActiveHigh), - clock = Some(PolarizedPort(name = realPrefix + "clk", polarity = PositiveEdge)), - - readEnable = if (readEnable) Some(PolarizedPort(name = realPrefix + "read_en", polarity = ActiveHigh)) else None, - writeEnable = if (writeEnable) Some(PolarizedPort(name = realPrefix + "write_en", polarity = ActiveHigh)) else None, - - output = if (read) Some(PolarizedPort(name = realPrefix + "dout", polarity = ActiveHigh)) else None, - input = if (write) Some(PolarizedPort(name = realPrefix + "din", polarity = ActiveHigh)) else None, - - maskPort = maskGran match { - case Some(x: Int) => Some(PolarizedPort(name = realPrefix + "mask", polarity = ActiveHigh)) - case _ => None - }, - maskGran = maskGran, - - width = width, depth = depth // These numbers don't matter here. - ) - } - - // Generate a read port for testing. - def generateReadPort(prefix: String, width: Option[Int], depth: Option[BigInt], readEnable: Boolean = false): MacroPort = { - generateTestPort(prefix, width, depth, write = false, read = true, readEnable = readEnable) - } - - // Generate a write port for testing. - def generateWritePort(prefix: String, width: Option[Int], depth: Option[BigInt], maskGran: Option[Int] = None, writeEnable: Boolean = true): MacroPort = { - generateTestPort(prefix, width, depth, maskGran = maskGran, write = true, read = false, writeEnable = writeEnable) - } - - // Generate a simple read-write port for testing. - def generateReadWritePort(prefix: String, width: Option[Int], depth: Option[BigInt], maskGran: Option[Int] = None): MacroPort = { - generateTestPort( - prefix, width, depth, maskGran = maskGran, - write = true, writeEnable = true, - read = true, readEnable = false - ) - } - - // Generate a "simple" SRAM (active high/positive edge, 1 read-write port). - def generateSRAM(name: String, prefix: String, width: Int, depth: BigInt, maskGran: Option[Int] = None, extraPorts: Seq[MacroExtraPort] = List()): SRAMMacro = { - SRAMMacro( - name = name, - width = width, - depth = depth, - family = "1rw", - ports = Seq(generateReadWritePort(prefix, width, depth, maskGran)), - extraPorts = extraPorts - ) - } - - // Generate a "simple" SRAM group (active high/positive edge, 1 read-write port). - def generateSimpleSRAMGroup(prefix: String, mux: Int, depth: Range, width: Range, maskGran: Option[Int] = None, extraPorts: Seq[MacroExtraPort] = List()): SRAMGroup = { - SRAMGroup(Seq("mygroup_", "width", "x", "depth", "_", "VT"), "1rw", Seq("svt", "lvt", "ulvt"), mux, depth, width, Seq(generateReadWritePort(prefix, None, None, maskGran))) - } - - // 'vt': ('svt','lvt','ulvt'), 'mux': 2, 'depth': range(16,513,8), 'width': range(8,289,2), 'ports': 1 - // 'vt': ('svt','lvt','ulvt'), 'mux': 4, 'depth': range(32,1025,16), 'width': range(4,145), 'ports': 1} - def generateSRAMCompiler(name: String, prefix: String): mdf.macrolib.SRAMCompiler = { - SRAMCompiler(name, Seq( - generateSimpleSRAMGroup(prefix, 2, Range(16, 512, 8), Range(8, 288, 2)), - generateSimpleSRAMGroup(prefix, 4, Range(32, 1024, 16), Range(4, 144, 1)) - )) - } -} - -// Generic "simple" test generator. -// Set up scaffolding for generating memories, files, etc. -// Override this generator to specify the expected FIRRTL output. -trait HasSimpleTestGenerator { - this: MacroCompilerSpec with HasSRAMGenerator => - // Override these with "override lazy val". - // Why lazy? These are used in the constructor here so overriding non-lazily - // would be too late. - def useCompiler: Boolean = false - def memWidth: Int - def libWidth: Int - def memDepth: BigInt - def libDepth: BigInt - def memMaskGran: Option[Int] = None - def libMaskGran: Option[Int] = None - def extraPorts: Seq[mdf.macrolib.MacroExtraPort] = List() - def extraTag: String = "" - - // "Effective" libMaskGran by considering write_enable. - val effectiveLibMaskGran = libMaskGran.getOrElse(libWidth) - - // Override this in the sub-generator if you need a more specific name. - // Defaults to using reflection to pull the name of the test using this - // generator. - def generatorType: String = this.getClass.getSimpleName - - //require (memDepth >= libDepth) - - // Convenience variables to check if a mask exists. - val memHasMask = memMaskGran != None - val libHasMask = libMaskGran != None - // We need to figure out how many mask bits there are in the mem. - val memMaskBits = if (memHasMask) memWidth / memMaskGran.get else 0 - val libMaskBits = if (libHasMask) libWidth / libMaskGran.get else 0 - - val extraTagPrefixed = if (extraTag == "") "" else ("-" + extraTag) - - val mem = s"mem-${generatorType}${extraTagPrefixed}.json" - val lib = s"lib-${generatorType}${extraTagPrefixed}.json" - val v = s"${generatorType}${extraTagPrefixed}.v" - - lazy val mem_name = "target_memory" - val mem_addr_width = MacroCompilerMath.ceilLog2(memDepth) - - lazy val lib_name = "awesome_lib_mem" - val lib_addr_width = MacroCompilerMath.ceilLog2(libDepth) - - // Override these to change the port prefixes if needed. - def libPortPrefix: String = "lib" - def memPortPrefix: String = "outer" - - // These generate "simple" SRAMs (1 masked read-write port) by default, - // but can be overridden if need be. - def generateLibSRAM() = generateSRAM(lib_name, libPortPrefix, libWidth, libDepth, libMaskGran, extraPorts) - def generateMemSRAM() = generateSRAM(mem_name, memPortPrefix, memWidth, memDepth, memMaskGran) - - def libSRAM = generateLibSRAM - def memSRAM = generateMemSRAM - - def libSRAMs: Seq[SRAMMacro] = Seq(libSRAM) - def memSRAMs: Seq[SRAMMacro] = Seq(memSRAM) - - writeToLib(lib, libSRAMs) - writeToMem(mem, memSRAMs) - - // For masks, width it's a bit tricky since we have to consider cases like - // memMaskGran = 4 and libMaskGran = 8. - // Consider the actually usable libWidth in cases like the above. - val usableLibWidth = if (memMaskGran.getOrElse(Int.MaxValue) < effectiveLibMaskGran) memMaskGran.get else libWidth - - // Number of lib instances needed to hold the mem, in both directions. - // Round up (e.g. 1.5 instances = effectively 2 instances) - val depthInstances = math.ceil(memDepth.toFloat / libDepth.toFloat).toInt - val widthInstances = math.ceil(memWidth.toFloat / usableLibWidth).toInt - - // Number of width bits in the last width-direction memory. - // e.g. if memWidth = 16 and libWidth = 8, this would be 8 since the last memory 0_1 has 8 bits of input width. - // e.g. if memWidth = 9 and libWidth = 8, this would be 1 since the last memory 0_1 has 1 bit of input width. - lazy val lastWidthBits = if (memWidth % usableLibWidth == 0) usableLibWidth else (memWidth % usableLibWidth) - lazy val selectBits = mem_addr_width - lib_addr_width - - /** - * Convenience function to generate a mask statement. - * @param widthInst Width instance (mem_0_x) - * @param depthInst Depth instance (mem_x_0) - */ - def generateMaskStatement(widthInst: Int, depthInst: Int): String = { - // Width of this submemory. - val myMemWidth = if (widthInst == widthInstances - 1) lastWidthBits else usableLibWidth - // Base bit of this submemory. - // e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this - // would be 16. - val myBaseBit = usableLibWidth*widthInst - - if (libMaskGran.isDefined) { - if (memMaskGran.isEmpty) { - // If there is no memory mask, we should just turn all the lib mask - // bits high. - s"""mem_${depthInst}_${widthInst}.lib_mask <= UInt<${libMaskBits}>("h${((1 << libMaskBits) - 1).toHexString}")""" - } else { - // Calculate which bit of outer_mask contains the given bit. - // e.g. if memMaskGran = 2, libMaskGran = 1 and libWidth = 4, then - // calculateMaskBit({0, 1}) = 0 and calculateMaskBit({1, 2}) = 1 - def calculateMaskBit(bit:Int): Int = bit / memMaskGran.getOrElse(memWidth) - - val bitsArr = ((libMaskBits - 1 to 0 by -1) map (x => { - if (x*libMaskGran.get > myMemWidth) { - // If we have extra mask bits leftover after the effective width, - // disable those bits. - """UInt<1>("h0")""" - } else { - val outerMaskBit = calculateMaskBit(x*libMaskGran.get + myBaseBit) - s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" - } - })) - val maskVal = bitsArr.reduceRight((bit, rest) => s"cat($bit, $rest)") - s"mem_${depthInst}_${widthInst}.lib_mask <= ${maskVal}" - } - } else "" - } - - /** Helper function to generate a port. - * - * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") - * @param addrWidth Address port width - * @param width data width - * @param write Has a write port? - * @param writeEnable Has a write enable port? - * @param read Has a read port? - * @param readEnable Has a read enable port? - * @param mask Mask granularity (# bits) of the port or None. - * @param extraPorts Extra ports (name, # bits) - */ - def generatePort(prefix: String, addrWidth: Int, width: Int, write: Boolean, writeEnable: Boolean, read: Boolean, readEnable: Boolean, mask: Option[Int], extraPorts: Seq[(String, Int)] = Seq()): String = { - val realPrefix = if (prefix == "") "" else prefix + "_" - - val readStr = if (read) s"output ${realPrefix}dout : UInt<$width>" else "" - val writeStr = if (write) s"input ${realPrefix}din : UInt<$width>" else "" - val readEnableStr = if (readEnable) s"input ${realPrefix}read_en : UInt<1>" else "" - val writeEnableStr = if (writeEnable) s"input ${realPrefix}write_en : UInt<1>" else "" - val maskStr = mask match { - case Some(maskBits: Int) => s"input ${realPrefix}mask : UInt<$maskBits>" - case _ => "" - } - val extraPortsStr = extraPorts.map { case (name, bits) => s" input $name : UInt<$bits>" }.mkString("\n") - s""" - input ${realPrefix}addr : UInt<$addrWidth> - input ${realPrefix}clk : Clock - $writeStr - $readStr - $readEnableStr - $writeEnableStr - $maskStr -$extraPortsStr - """ - } - - /** - * Helper function to generate a RW footer port. - * - * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") - * @param readEnable Has a read enable port? - * @param mask Mask granularity (# bits) of the port or None. - * @param extraPorts Extra ports (name, # bits) - */ - def generateReadWriteFooterPort(prefix: String, readEnable: Boolean, mask: Option[Int], extraPorts: Seq[(String, Int)] = Seq()): String = { - generatePort(prefix, lib_addr_width, libWidth, - write = true, writeEnable = true, read = true, readEnable = readEnable, mask = mask, extraPorts = extraPorts) - } - - /** Helper function to generate a RW header port. - * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") - * @param readEnable Has a read enable port? - * @param mask Mask granularity (# bits) of the port or None. */ - def generateReadWriteHeaderPort(prefix: String, readEnable: Boolean, mask: Option[Int]): String = { - generatePort(prefix, mem_addr_width, memWidth, - write=true, writeEnable=true, read=true, readEnable=readEnable, mask) - } - - // Generate the header memory ports. - def generateHeaderPorts(): String = { - require (memSRAM.ports.size == 1, "Header generator only supports single RW port mem") - generateReadWriteHeaderPort(memPortPrefix, memSRAM.ports(0).readEnable.isDefined, if (memHasMask) Some(memMaskBits) else None) - } - - // Generate the header (contains the circuit statement and the target memory - // module. - def generateHeader(): String = { - s""" -circuit $mem_name : - module $mem_name : -${generateHeaderPorts} - """ - } - - // Generate the target memory ports. - def generateFooterPorts(): String = { - require(libSRAM.ports.size == 1, "Footer generator only supports single RW port mem") - generateReadWriteFooterPort(libPortPrefix, libSRAM.ports(0).readEnable.isDefined, - if (libHasMask) Some(libMaskBits) else None, extraPorts.map(p => (p.name, p.width))) - } - - // Generate the footer (contains the target memory extmodule declaration by default). - def generateFooter(): String = { - s""" - extmodule $lib_name : -${generateFooterPorts} - - defname = $lib_name - """ - } - - // Abstract method to generate body; to be overridden by specific generator type. - def generateBody(): String - - // Generate the entire output from header, body, and footer. - def generateOutput(): String = { - s""" -${generateHeader} -${generateBody} -${generateFooter} - """ - } - - val output = generateOutput() -} - -// Use this trait for tests that invoke the memory compiler without lib. -trait HasNoLibTestGenerator extends HasSimpleTestGenerator { - this: MacroCompilerSpec with HasSRAMGenerator => - - // If there isn't a lib, then the "lib" will become a FIRRTL "mem", which - // in turn becomes synthesized flops. - // Therefore, make "lib" width/depth equal to the mem. - override lazy val libDepth = memDepth - override lazy val libWidth = memWidth - override lazy val lib_name = mem_name - // Do the same for port names. - override lazy val libPortPrefix = memPortPrefix - - // If there is no lib, don't generate a body. - override def generateBody = "" -} - diff --git a/macros/src/test/scala/CostFunction.scala b/macros/src/test/scala/barstools/macros/CostFunction.scala similarity index 86% rename from macros/src/test/scala/CostFunction.scala rename to macros/src/test/scala/barstools/macros/CostFunction.scala index b8a27f7f..ceb7a61a 100644 --- a/macros/src/test/scala/CostFunction.scala +++ b/macros/src/test/scala/barstools/macros/CostFunction.scala @@ -4,10 +4,9 @@ import mdf.macrolib._ /** Tests to check that the cost function mechanism is working properly. */ -/** - * A test metric that simply favours memories with smaller widths, to test that - * the metric is chosen properly. - */ +/** A test metric that simply favours memories with smaller widths, to test that + * the metric is chosen properly. + */ object TestMinWidthMetric extends CostMetric with CostMetricCompanion { // Smaller width = lower cost = favoured override def cost(mem: Macro, lib: Macro): Option[Double] = Some(lib.src.width) @@ -30,29 +29,29 @@ class SelectCostMetric extends MacroCompilerSpec with HasSRAMGenerator { val libSRAMs = Seq( SRAMMacro( - name="SRAM_WIDTH_128", - depth=BigInt(1024), - width=128, - family="1rw", - ports=Seq( + name = "SRAM_WIDTH_128", + depth = BigInt(1024), + width = 128, + family = "1rw", + ports = Seq( generateReadWritePort("", 128, BigInt(1024)) ) ), SRAMMacro( - name="SRAM_WIDTH_64", - depth=BigInt(1024), - width=64, - family="1rw", - ports=Seq( + name = "SRAM_WIDTH_64", + depth = BigInt(1024), + width = 64, + family = "1rw", + ports = Seq( generateReadWritePort("", 64, BigInt(1024)) ) ), SRAMMacro( - name="SRAM_WIDTH_32", - depth=BigInt(1024), - width=32, - family="1rw", - ports=Seq( + name = "SRAM_WIDTH_32", + depth = BigInt(1024), + width = 32, + family = "1rw", + ports = Seq( generateReadWritePort("", 32, BigInt(1024)) ) ) @@ -65,7 +64,7 @@ class SelectCostMetric extends MacroCompilerSpec with HasSRAMGenerator { // Check that the min width SRAM was chosen, even though it is less efficient. val output = -""" + """ circuit target_memory : module target_memory : input addr : UInt<10> diff --git a/macros/src/test/scala/Functional.scala b/macros/src/test/scala/barstools/macros/Functional.scala similarity index 100% rename from macros/src/test/scala/Functional.scala rename to macros/src/test/scala/barstools/macros/Functional.scala diff --git a/macros/src/test/scala/barstools/macros/MacroCompilerSpec.scala b/macros/src/test/scala/barstools/macros/MacroCompilerSpec.scala new file mode 100644 index 00000000..2b239227 --- /dev/null +++ b/macros/src/test/scala/barstools/macros/MacroCompilerSpec.scala @@ -0,0 +1,556 @@ +// See LICENSE for license details. + +package barstools.macros + +import firrtl.Parser.parse +import firrtl.ir.{Circuit, NoInfo} +import firrtl.passes.RemoveEmpty +import mdf.macrolib.SRAMMacro +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import java.io.File + +abstract class MacroCompilerSpec extends AnyFlatSpec with Matchers { + import scala.language.implicitConversions + implicit def String2SomeString(i: String): Option[String] = Some(i) + val testDir: String = "test_run_dir/macros" + new File(testDir).mkdirs // Make sure the testDir exists + + // Override these to change the prefixing of macroDir and testDir + val memPrefix: String = testDir + val libPrefix: String = testDir + val vPrefix: String = testDir + + // Override this to use a different cost metric. + // If this is None, the compile() call will not have any -c/-cp arguments, and + // execute() will use CostMetric.default. + val costMetric: Option[CostMetric] = None + private def getCostMetric: CostMetric = costMetric.getOrElse(CostMetric.default) + + private def costMetricCmdLine = { + costMetric match { + case None => Nil + case Some(m) => { + val name = m.name + val params = m.commandLineParams + List("-c", name) ++ params.flatMap { case (key, value) => List("-cp", key, value) } + } + } + } + + private def args(mem: String, lib: Option[String], v: String, synflops: Boolean, useCompiler: Boolean) = + List("-m", mem.toString, "-v", v) ++ + (lib match { + case None => Nil + case Some(l) => List("-l", l.toString) + }) ++ + costMetricCmdLine ++ + (if (synflops) List("--mode", "synflops") else Nil) ++ + (if (useCompiler) List("--use-compiler") else Nil) + + // Run the full compiler as if from the command line interface. + // Generates the Verilog; useful in testing since an error will throw an + // exception. + def compile(mem: String, lib: String, v: String, synflops: Boolean) { + compile(mem, Some(lib), v, synflops) + } + def compile(mem: String, lib: Option[String], v: String, synflops: Boolean, useCompiler: Boolean = false) { + var mem_full = concat(memPrefix, mem) + var lib_full = concat(libPrefix, lib) + var v_full = concat(vPrefix, v) + + MacroCompiler.run(args(mem_full, lib_full, v_full, synflops, useCompiler)) + } + + // Helper functions to write macro libraries to the given files. + def writeToLib(lib: String, libs: Seq[mdf.macrolib.Macro]) = { + mdf.macrolib.Utils.writeMDFToPath(Some(concat(libPrefix, lib)), libs) + } + + def writeToMem(mem: String, mems: Seq[mdf.macrolib.Macro]) = { + mdf.macrolib.Utils.writeMDFToPath(Some(concat(memPrefix, mem)), mems) + } + + // Convenience function for running both compile, execute, and test at once. + def compileExecuteAndTest( + mem: String, + lib: Option[String], + v: String, + output: String, + synflops: Boolean = false, + useCompiler: Boolean = false + ): Unit = { + compile(mem, lib, v, synflops, useCompiler) + val result = execute(mem, lib, synflops, useCompiler) + test(result, output) + } + + // Compare FIRRTL outputs after reparsing output with ScalaTest ("should be"). + def test(result: Circuit, output: String): Unit = { + val gold = RemoveEmpty.run(parse(output)) + (result.serialize) should be(gold.serialize) + } + + // Execute the macro compiler and returns a Circuit containing the output of + // the memory compiler. + def execute(memFile: Option[String], libFile: Option[String], synflops: Boolean): Circuit = + execute(memFile, libFile, synflops, false) + def execute(memFile: Option[String], libFile: Option[String], synflops: Boolean, useCompiler: Boolean): Circuit = { + var mem_full = concat(memPrefix, memFile) + var lib_full = concat(libPrefix, libFile) + + require(memFile.isDefined) + val mems: Seq[Macro] = Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(mem_full)).get.map(new Macro(_)) + val libs: Option[Seq[Macro]] = if (useCompiler) { + Utils.findSRAMCompiler(mdf.macrolib.Utils.readMDFFromPath(lib_full)).map { x => + Utils.buildSRAMMacros(x).map(new Macro(_)) + } + } else { + Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(lib_full)) match { + case Some(x) => Some(x.map(new Macro(_))) + case None => None + } + } + val macros = mems.map(_.blackbox) + val circuit = Circuit(NoInfo, macros, macros.last.name) + val passes = Seq( + new MacroCompilerPass( + Some(mems), + libs, + None, + None, + getCostMetric, + if (synflops) MacroCompilerAnnotation.Synflops else MacroCompilerAnnotation.Default + ), + new SynFlopsPass(synflops, libs.getOrElse(mems)), + RemoveEmpty + ) + val result: Circuit = (passes.foldLeft(circuit))((c, pass) => pass.run(c)) + result + } + + // Helper method to deal with String + Option[String] + private def concat(a: String, b: String): String = { a + "/" + b } + private def concat(a: String, b: Option[String]): Option[String] = { + b match { + case Some(b2: String) => Some(a + "/" + b2) + case _ => None + } + } +} + +// A collection of standard SRAM generators. +trait HasSRAMGenerator { + import mdf.macrolib._ + + import scala.language.implicitConversions + implicit def Int2SomeInt(i: Int): Option[Int] = Some(i) + implicit def BigInt2SomeBigInt(i: BigInt): Option[BigInt] = Some(i) + + // Generate a standard (read/write/combo) port for testing. + // Helper methods for optional width argument + def generateTestPort( + prefix: String, + width: Option[Int], + depth: Option[BigInt], + maskGran: Option[Int] = None, + read: Boolean, + readEnable: Boolean = false, + write: Boolean, + writeEnable: Boolean = false + ): MacroPort = { + val realPrefix = if (prefix == "") "" else prefix + "_" + + MacroPort( + address = PolarizedPort(name = realPrefix + "addr", polarity = ActiveHigh), + clock = Some(PolarizedPort(name = realPrefix + "clk", polarity = PositiveEdge)), + readEnable = if (readEnable) Some(PolarizedPort(name = realPrefix + "read_en", polarity = ActiveHigh)) else None, + writeEnable = + if (writeEnable) Some(PolarizedPort(name = realPrefix + "write_en", polarity = ActiveHigh)) else None, + output = if (read) Some(PolarizedPort(name = realPrefix + "dout", polarity = ActiveHigh)) else None, + input = if (write) Some(PolarizedPort(name = realPrefix + "din", polarity = ActiveHigh)) else None, + maskPort = maskGran match { + case Some(x: Int) => Some(PolarizedPort(name = realPrefix + "mask", polarity = ActiveHigh)) + case _ => None + }, + maskGran = maskGran, + width = width, + depth = depth // These numbers don't matter here. + ) + } + + // Generate a read port for testing. + def generateReadPort( + prefix: String, + width: Option[Int], + depth: Option[BigInt], + readEnable: Boolean = false + ): MacroPort = { + generateTestPort(prefix, width, depth, write = false, read = true, readEnable = readEnable) + } + + // Generate a write port for testing. + def generateWritePort( + prefix: String, + width: Option[Int], + depth: Option[BigInt], + maskGran: Option[Int] = None, + writeEnable: Boolean = true + ): MacroPort = { + generateTestPort(prefix, width, depth, maskGran = maskGran, write = true, read = false, writeEnable = writeEnable) + } + + // Generate a simple read-write port for testing. + def generateReadWritePort( + prefix: String, + width: Option[Int], + depth: Option[BigInt], + maskGran: Option[Int] = None + ): MacroPort = { + generateTestPort( + prefix, + width, + depth, + maskGran = maskGran, + write = true, + writeEnable = true, + read = true, + readEnable = false + ) + } + + // Generate a "simple" SRAM (active high/positive edge, 1 read-write port). + def generateSRAM( + name: String, + prefix: String, + width: Int, + depth: BigInt, + maskGran: Option[Int] = None, + extraPorts: Seq[MacroExtraPort] = List() + ): SRAMMacro = { + SRAMMacro( + name = name, + width = width, + depth = depth, + family = "1rw", + ports = Seq(generateReadWritePort(prefix, width, depth, maskGran)), + extraPorts = extraPorts + ) + } + + // Generate a "simple" SRAM group (active high/positive edge, 1 read-write port). + def generateSimpleSRAMGroup( + prefix: String, + mux: Int, + depth: Range, + width: Range, + maskGran: Option[Int] = None, + extraPorts: Seq[MacroExtraPort] = List() + ): SRAMGroup = { + SRAMGroup( + Seq("mygroup_", "width", "x", "depth", "_", "VT"), + "1rw", + Seq("svt", "lvt", "ulvt"), + mux, + depth, + width, + Seq(generateReadWritePort(prefix, None, None, maskGran)) + ) + } + + // 'vt': ('svt','lvt','ulvt'), 'mux': 2, 'depth': range(16,513,8), 'width': range(8,289,2), 'ports': 1 + // 'vt': ('svt','lvt','ulvt'), 'mux': 4, 'depth': range(32,1025,16), 'width': range(4,145), 'ports': 1} + def generateSRAMCompiler(name: String, prefix: String): mdf.macrolib.SRAMCompiler = { + SRAMCompiler( + name, + Seq( + generateSimpleSRAMGroup(prefix, 2, Range(16, 512, 8), Range(8, 288, 2)), + generateSimpleSRAMGroup(prefix, 4, Range(32, 1024, 16), Range(4, 144, 1)) + ) + ) + } +} + +// Generic "simple" test generator. +// Set up scaffolding for generating memories, files, etc. +// Override this generator to specify the expected FIRRTL output. +trait HasSimpleTestGenerator { + this: MacroCompilerSpec with HasSRAMGenerator => + // Override these with "override lazy val". + // Why lazy? These are used in the constructor here so overriding non-lazily + // would be too late. + def useCompiler: Boolean = false + def memWidth: Int + def libWidth: Int + def memDepth: BigInt + def libDepth: BigInt + def memMaskGran: Option[Int] = None + def libMaskGran: Option[Int] = None + def extraPorts: Seq[mdf.macrolib.MacroExtraPort] = List() + def extraTag: String = "" + + // "Effective" libMaskGran by considering write_enable. + val effectiveLibMaskGran = libMaskGran.getOrElse(libWidth) + + // Override this in the sub-generator if you need a more specific name. + // Defaults to using reflection to pull the name of the test using this + // generator. + def generatorType: String = this.getClass.getSimpleName + + //require (memDepth >= libDepth) + + // Convenience variables to check if a mask exists. + val memHasMask = memMaskGran != None + val libHasMask = libMaskGran != None + // We need to figure out how many mask bits there are in the mem. + val memMaskBits = if (memHasMask) memWidth / memMaskGran.get else 0 + val libMaskBits = if (libHasMask) libWidth / libMaskGran.get else 0 + + val extraTagPrefixed = if (extraTag == "") "" else ("-" + extraTag) + + val mem = s"mem-${generatorType}${extraTagPrefixed}.json" + val lib = s"lib-${generatorType}${extraTagPrefixed}.json" + val v = s"${generatorType}${extraTagPrefixed}.v" + + lazy val mem_name = "target_memory" + val mem_addr_width = MacroCompilerMath.ceilLog2(memDepth) + + lazy val lib_name = "awesome_lib_mem" + val lib_addr_width = MacroCompilerMath.ceilLog2(libDepth) + + // Override these to change the port prefixes if needed. + def libPortPrefix: String = "lib" + def memPortPrefix: String = "outer" + + // These generate "simple" SRAMs (1 masked read-write port) by default, + // but can be overridden if need be. + def generateLibSRAM() = generateSRAM(lib_name, libPortPrefix, libWidth, libDepth, libMaskGran, extraPorts) + def generateMemSRAM() = generateSRAM(mem_name, memPortPrefix, memWidth, memDepth, memMaskGran) + + def libSRAM = generateLibSRAM + def memSRAM = generateMemSRAM + + def libSRAMs: Seq[SRAMMacro] = Seq(libSRAM) + def memSRAMs: Seq[SRAMMacro] = Seq(memSRAM) + + writeToLib(lib, libSRAMs) + writeToMem(mem, memSRAMs) + + // For masks, width it's a bit tricky since we have to consider cases like + // memMaskGran = 4 and libMaskGran = 8. + // Consider the actually usable libWidth in cases like the above. + val usableLibWidth = if (memMaskGran.getOrElse(Int.MaxValue) < effectiveLibMaskGran) memMaskGran.get else libWidth + + // Number of lib instances needed to hold the mem, in both directions. + // Round up (e.g. 1.5 instances = effectively 2 instances) + val depthInstances = math.ceil(memDepth.toFloat / libDepth.toFloat).toInt + val widthInstances = math.ceil(memWidth.toFloat / usableLibWidth).toInt + + // Number of width bits in the last width-direction memory. + // e.g. if memWidth = 16 and libWidth = 8, this would be 8 since the last memory 0_1 has 8 bits of input width. + // e.g. if memWidth = 9 and libWidth = 8, this would be 1 since the last memory 0_1 has 1 bit of input width. + lazy val lastWidthBits = if (memWidth % usableLibWidth == 0) usableLibWidth else (memWidth % usableLibWidth) + lazy val selectBits = mem_addr_width - lib_addr_width + + /** Convenience function to generate a mask statement. + * @param widthInst Width instance (mem_0_x) + * @param depthInst Depth instance (mem_x_0) + */ + def generateMaskStatement(widthInst: Int, depthInst: Int): String = { + // Width of this submemory. + val myMemWidth = if (widthInst == widthInstances - 1) lastWidthBits else usableLibWidth + // Base bit of this submemory. + // e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this + // would be 16. + val myBaseBit = usableLibWidth * widthInst + + if (libMaskGran.isDefined) { + if (memMaskGran.isEmpty) { + // If there is no memory mask, we should just turn all the lib mask + // bits high. + s"""mem_${depthInst}_${widthInst}.lib_mask <= UInt<${libMaskBits}>("h${((1 << libMaskBits) - 1).toHexString}")""" + } else { + // Calculate which bit of outer_mask contains the given bit. + // e.g. if memMaskGran = 2, libMaskGran = 1 and libWidth = 4, then + // calculateMaskBit({0, 1}) = 0 and calculateMaskBit({1, 2}) = 1 + def calculateMaskBit(bit: Int): Int = bit / memMaskGran.getOrElse(memWidth) + + val bitsArr = ((libMaskBits - 1 to 0 by -1).map(x => { + if (x * libMaskGran.get > myMemWidth) { + // If we have extra mask bits leftover after the effective width, + // disable those bits. + """UInt<1>("h0")""" + } else { + val outerMaskBit = calculateMaskBit(x * libMaskGran.get + myBaseBit) + s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" + } + })) + val maskVal = bitsArr.reduceRight((bit, rest) => s"cat($bit, $rest)") + s"mem_${depthInst}_${widthInst}.lib_mask <= ${maskVal}" + } + } else "" + } + + /** Helper function to generate a port. + * + * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") + * @param addrWidth Address port width + * @param width data width + * @param write Has a write port? + * @param writeEnable Has a write enable port? + * @param read Has a read port? + * @param readEnable Has a read enable port? + * @param mask Mask granularity (# bits) of the port or None. + * @param extraPorts Extra ports (name, # bits) + */ + def generatePort( + prefix: String, + addrWidth: Int, + width: Int, + write: Boolean, + writeEnable: Boolean, + read: Boolean, + readEnable: Boolean, + mask: Option[Int], + extraPorts: Seq[(String, Int)] = Seq() + ): String = { + val realPrefix = if (prefix == "") "" else prefix + "_" + + val readStr = if (read) s"output ${realPrefix}dout : UInt<$width>" else "" + val writeStr = if (write) s"input ${realPrefix}din : UInt<$width>" else "" + val readEnableStr = if (readEnable) s"input ${realPrefix}read_en : UInt<1>" else "" + val writeEnableStr = if (writeEnable) s"input ${realPrefix}write_en : UInt<1>" else "" + val maskStr = mask match { + case Some(maskBits: Int) => s"input ${realPrefix}mask : UInt<$maskBits>" + case _ => "" + } + val extraPortsStr = extraPorts.map { case (name, bits) => s" input $name : UInt<$bits>" }.mkString("\n") + s""" + input ${realPrefix}addr : UInt<$addrWidth> + input ${realPrefix}clk : Clock + $writeStr + $readStr + $readEnableStr + $writeEnableStr + $maskStr +$extraPortsStr + """ + } + + /** Helper function to generate a RW footer port. + * + * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") + * @param readEnable Has a read enable port? + * @param mask Mask granularity (# bits) of the port or None. + * @param extraPorts Extra ports (name, # bits) + */ + def generateReadWriteFooterPort( + prefix: String, + readEnable: Boolean, + mask: Option[Int], + extraPorts: Seq[(String, Int)] = Seq() + ): String = { + generatePort( + prefix, + lib_addr_width, + libWidth, + write = true, + writeEnable = true, + read = true, + readEnable = readEnable, + mask = mask, + extraPorts = extraPorts + ) + } + + /** Helper function to generate a RW header port. + * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") + * @param readEnable Has a read enable port? + * @param mask Mask granularity (# bits) of the port or None. + */ + def generateReadWriteHeaderPort(prefix: String, readEnable: Boolean, mask: Option[Int]): String = { + generatePort( + prefix, + mem_addr_width, + memWidth, + write = true, + writeEnable = true, + read = true, + readEnable = readEnable, + mask + ) + } + + // Generate the header memory ports. + def generateHeaderPorts(): String = { + require(memSRAM.ports.size == 1, "Header generator only supports single RW port mem") + generateReadWriteHeaderPort( + memPortPrefix, + memSRAM.ports(0).readEnable.isDefined, + if (memHasMask) Some(memMaskBits) else None + ) + } + + // Generate the header (contains the circuit statement and the target memory + // module. + def generateHeader(): String = { + s""" +circuit $mem_name : + module $mem_name : +${generateHeaderPorts} + """ + } + + // Generate the target memory ports. + def generateFooterPorts(): String = { + require(libSRAM.ports.size == 1, "Footer generator only supports single RW port mem") + generateReadWriteFooterPort( + libPortPrefix, + libSRAM.ports(0).readEnable.isDefined, + if (libHasMask) Some(libMaskBits) else None, + extraPorts.map(p => (p.name, p.width)) + ) + } + + // Generate the footer (contains the target memory extmodule declaration by default). + def generateFooter(): String = { + s""" + extmodule $lib_name : +${generateFooterPorts} + + defname = $lib_name + """ + } + + // Abstract method to generate body; to be overridden by specific generator type. + def generateBody(): String + + // Generate the entire output from header, body, and footer. + def generateOutput(): String = { + s""" +${generateHeader} +${generateBody} +${generateFooter} + """ + } + + val output = generateOutput() +} + +// Use this trait for tests that invoke the memory compiler without lib. +trait HasNoLibTestGenerator extends HasSimpleTestGenerator { + this: MacroCompilerSpec with HasSRAMGenerator => + + // If there isn't a lib, then the "lib" will become a FIRRTL "mem", which + // in turn becomes synthesized flops. + // Therefore, make "lib" width/depth equal to the mem. + override lazy val libDepth = memDepth + override lazy val libWidth = memWidth + override lazy val lib_name = mem_name + // Do the same for port names. + override lazy val libPortPrefix = memPortPrefix + + // If there is no lib, don't generate a body. + override def generateBody = "" +} diff --git a/macros/src/test/scala/Masks.scala b/macros/src/test/scala/barstools/macros/Masks.scala similarity index 55% rename from macros/src/test/scala/Masks.scala rename to macros/src/test/scala/barstools/macros/Masks.scala index a091a42a..c472669a 100644 --- a/macros/src/test/scala/Masks.scala +++ b/macros/src/test/scala/barstools/macros/Masks.scala @@ -1,37 +1,39 @@ package barstools.macros -import mdf.macrolib._ - // Test the ability of the compiler to deal with various mask combinations. trait MasksTestSettings { this: MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator => - override lazy val memDepth = BigInt(2048) - override lazy val libDepth = BigInt(1024) + override lazy val memDepth = BigInt(2048) + override lazy val libDepth = BigInt(1024) } // Try all four different kinds of mask config: -/** - * - * Non-masked mem Masked mem - * --------------------------------- - * Non-masked lib | | | - * --------------------------------- - * Masked lib | | | - * --------------------------------- - */ - -class Masks_FourTypes_NonMaskedMem_NonMaskedLib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +/** Non-masked mem Masked mem + * --------------------------------- + * Non-masked lib | | | + * --------------------------------- + * Masked lib | | | + * --------------------------------- + */ + +class Masks_FourTypes_NonMaskedMem_NonMaskedLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 32 override lazy val memMaskGran = None - override lazy val libWidth = 8 + override lazy val libWidth = 8 override lazy val libMaskGran = None compileExecuteAndTest(mem, lib, v, output) } -class Masks_FourTypes_NonMaskedMem_MaskedLib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class Masks_FourTypes_NonMaskedMem_MaskedLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 32 override lazy val memMaskGran = None @@ -41,7 +43,10 @@ class Masks_FourTypes_NonMaskedMem_MaskedLib extends MacroCompilerSpec with HasS compileExecuteAndTest(mem, lib, v, output) } -class Masks_FourTypes_MaskedMem_NonMaskedLib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class Masks_FourTypes_MaskedMem_NonMaskedLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 32 override lazy val memMaskGran = Some(8) @@ -51,7 +56,10 @@ class Masks_FourTypes_MaskedMem_NonMaskedLib extends MacroCompilerSpec with HasS compileExecuteAndTest(mem, lib, v, output) } -class Masks_FourTypes_MaskedMem_NonMaskedLib_SmallerMaskGran extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class Masks_FourTypes_MaskedMem_NonMaskedLib_SmallerMaskGran + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 32 override lazy val memMaskGran = Some(4) @@ -61,7 +69,10 @@ class Masks_FourTypes_MaskedMem_NonMaskedLib_SmallerMaskGran extends MacroCompil compileExecuteAndTest(mem, lib, v, output) } -class Masks_FourTypes_MaskedMem_MaskedLib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class Masks_FourTypes_MaskedMem_MaskedLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 32 override lazy val memMaskGran = Some(8) @@ -71,7 +82,10 @@ class Masks_FourTypes_MaskedMem_MaskedLib extends MacroCompilerSpec with HasSRAM compileExecuteAndTest(mem, lib, v, output) } -class Masks_FourTypes_MaskedMem_MaskedLib_SameMaskGran extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class Masks_FourTypes_MaskedMem_MaskedLib_SameMaskGran + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 32 override lazy val memMaskGran = Some(8) @@ -81,7 +95,10 @@ class Masks_FourTypes_MaskedMem_MaskedLib_SameMaskGran extends MacroCompilerSpec compileExecuteAndTest(mem, lib, v, output) } -class Masks_FourTypes_MaskedMem_MaskedLib_SmallerMaskGran extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class Masks_FourTypes_MaskedMem_MaskedLib_SmallerMaskGran + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 64 override lazy val memMaskGran = Some(4) @@ -105,7 +122,11 @@ class Masks_BitMaskedMem_NonMaskedLib extends MacroCompilerSpec with HasSRAMGene // FPGA-style byte-masked memories. -class Masks_FPGAStyle_32_8 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_FPGAStyle_32_8 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 32 override lazy val memMaskGran = Some(32) override lazy val libMaskGran = Some(8) @@ -115,7 +136,11 @@ class Masks_FPGAStyle_32_8 extends MacroCompilerSpec with HasSRAMGenerator with // Simple powers of two with bit-masked lib. -class Masks_PowersOfTwo_8_1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_8_1 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 64 override lazy val memMaskGran = Some(8) override lazy val libMaskGran = Some(1) @@ -123,7 +148,11 @@ class Masks_PowersOfTwo_8_1 extends MacroCompilerSpec with HasSRAMGenerator with compileExecuteAndTest(mem, lib, v, output) } -class Masks_PowersOfTwo_16_1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_16_1 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 64 override lazy val memMaskGran = Some(16) override lazy val libMaskGran = Some(1) @@ -131,7 +160,11 @@ class Masks_PowersOfTwo_16_1 extends MacroCompilerSpec with HasSRAMGenerator wit compileExecuteAndTest(mem, lib, v, output) } -class Masks_PowersOfTwo_32_1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_32_1 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 64 override lazy val memMaskGran = Some(32) override lazy val libMaskGran = Some(1) @@ -139,7 +172,11 @@ class Masks_PowersOfTwo_32_1 extends MacroCompilerSpec with HasSRAMGenerator wit compileExecuteAndTest(mem, lib, v, output) } -class Masks_PowersOfTwo_64_1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_64_1 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 64 override lazy val memMaskGran = Some(64) override lazy val libMaskGran = Some(1) @@ -149,7 +186,11 @@ class Masks_PowersOfTwo_64_1 extends MacroCompilerSpec with HasSRAMGenerator wit // Simple powers of two with non bit-masked lib. -class Masks_PowersOfTwo_32_4 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_32_4 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 128 override lazy val memMaskGran = Some(32) override lazy val libMaskGran = Some(4) @@ -157,7 +198,11 @@ class Masks_PowersOfTwo_32_4 extends MacroCompilerSpec with HasSRAMGenerator wit compileExecuteAndTest(mem, lib, v, output) } -class Masks_PowersOfTwo_32_8 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_32_8 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 128 override lazy val memMaskGran = Some(32) override lazy val libMaskGran = Some(8) @@ -165,7 +210,11 @@ class Masks_PowersOfTwo_32_8 extends MacroCompilerSpec with HasSRAMGenerator wit compileExecuteAndTest(mem, lib, v, output) } -class Masks_PowersOfTwo_8_8 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_8_8 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 128 override lazy val memMaskGran = Some(8) override lazy val libMaskGran = Some(8) @@ -175,7 +224,11 @@ class Masks_PowersOfTwo_8_8 extends MacroCompilerSpec with HasSRAMGenerator with // Width as a multiple of the mask, bit-masked lib -class Masks_IntegerMaskMultiple_20_10 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_20_10 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 20 override lazy val memMaskGran = Some(10) override lazy val libMaskGran = Some(1) @@ -183,16 +236,24 @@ class Masks_IntegerMaskMultiple_20_10 extends MacroCompilerSpec with HasSRAMGene compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_21_7 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_21_7 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 21 override lazy val memMaskGran = Some(21) override lazy val libMaskGran = Some(7) - it should "be enabled when non-power of two masks are supported" is (pending) + (it should "be enabled when non-power of two masks are supported").is(pending) //~ compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_21_21 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_21_21 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 21 override lazy val memMaskGran = Some(21) override lazy val libMaskGran = Some(1) @@ -200,7 +261,11 @@ class Masks_IntegerMaskMultiple_21_21 extends MacroCompilerSpec with HasSRAMGene compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_84_21 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_84_21 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 84 override lazy val memMaskGran = Some(21) override lazy val libMaskGran = Some(1) @@ -208,7 +273,11 @@ class Masks_IntegerMaskMultiple_84_21 extends MacroCompilerSpec with HasSRAMGene compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_92_23 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_92_23 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 92 override lazy val memMaskGran = Some(23) override lazy val libMaskGran = Some(1) @@ -216,7 +285,11 @@ class Masks_IntegerMaskMultiple_92_23 extends MacroCompilerSpec with HasSRAMGene compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_117_13 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_117_13 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 117 override lazy val memMaskGran = Some(13) override lazy val libMaskGran = Some(1) @@ -224,7 +297,11 @@ class Masks_IntegerMaskMultiple_117_13 extends MacroCompilerSpec with HasSRAMGen compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_160_20 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_160_20 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 160 override lazy val memMaskGran = Some(20) override lazy val libMaskGran = Some(1) @@ -232,7 +309,11 @@ class Masks_IntegerMaskMultiple_160_20 extends MacroCompilerSpec with HasSRAMGen compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_184_23 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_184_23 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 184 override lazy val memMaskGran = Some(23) override lazy val libMaskGran = Some(1) @@ -242,11 +323,15 @@ class Masks_IntegerMaskMultiple_184_23 extends MacroCompilerSpec with HasSRAMGen // Width as an non-integer multiple of the mask, bit-masked lib -class Masks_NonIntegerMaskMultiple_32_3 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_NonIntegerMaskMultiple_32_3 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 32 override lazy val memMaskGran = Some(3) override lazy val libMaskGran = Some(1) - it should "be enabled when non-power of two masks are supported" is (pending) + (it should "be enabled when non-power of two masks are supported").is(pending) //~ compileExecuteAndTest(mem, lib, v, output) } diff --git a/macros/src/test/scala/MultiPort.scala b/macros/src/test/scala/barstools/macros/MultiPort.scala similarity index 76% rename from macros/src/test/scala/MultiPort.scala rename to macros/src/test/scala/barstools/macros/MultiPort.scala index 3899f835..1968f6aa 100644 --- a/macros/src/test/scala/MultiPort.scala +++ b/macros/src/test/scala/barstools/macros/MultiPort.scala @@ -13,42 +13,70 @@ class SplitWidth_2rw extends MacroCompilerSpec with HasSRAMGenerator with HasSim override def generateMemSRAM() = { SRAMMacro( - name=mem_name, - width=memWidth, - depth=memDepth, - family="2rw", - ports=Seq(generateTestPort( - "portA", memWidth, Some(memDepth), maskGran=memMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - ), generateTestPort( - "portB", memWidth, Some(memDepth), maskGran=memMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = mem_name, + width = memWidth, + depth = memDepth, + family = "2rw", + ports = Seq( + generateTestPort( + "portA", + memWidth, + Some(memDepth), + maskGran = memMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ), + generateTestPort( + "portB", + memWidth, + Some(memDepth), + maskGran = memMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateLibSRAM() = { SRAMMacro( - name=lib_name, - width=libWidth, - depth=libDepth, - family="2rw", - ports=Seq(generateTestPort( - "portA", libWidth, libDepth, - write=true, writeEnable=true, - read=true, readEnable=true - ), generateTestPort( - "portB", libWidth, libDepth, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = lib_name, + width = libWidth, + depth = libDepth, + family = "2rw", + ports = Seq( + generateTestPort( + "portA", + libWidth, + libDepth, + write = true, + writeEnable = true, + read = true, + readEnable = true + ), + generateTestPort( + "portB", + libWidth, + libDepth, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateHeaderPorts() = { - generateReadWriteHeaderPort("portA", true, Some(memMaskBits)) + "\n" + generateReadWriteHeaderPort("portB", true, Some(memMaskBits)) + generateReadWriteHeaderPort("portA", true, Some(memMaskBits)) + "\n" + generateReadWriteHeaderPort( + "portB", + true, + Some(memMaskBits) + ) } override def generateFooterPorts() = { @@ -56,7 +84,7 @@ class SplitWidth_2rw extends MacroCompilerSpec with HasSRAMGenerator with HasSim } override def generateBody() = -""" + """ inst mem_0_0 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem inst mem_0_2 of awesome_lib_mem @@ -128,56 +156,112 @@ class SplitWidth_1r_1w extends MacroCompilerSpec with HasSRAMGenerator with HasS override def generateMemSRAM() = { SRAMMacro( - name=mem_name, - width=memWidth, - depth=memDepth, - family="1r1w", - ports=Seq(generateTestPort( - "portA", memWidth, Some(memDepth), maskGran=memMaskGran, - write=false, writeEnable=false, - read=true, readEnable=true - ), generateTestPort( - "portB", memWidth, Some(memDepth), maskGran=memMaskGran, - write=true, writeEnable=true, - read=false, readEnable=false - )) + name = mem_name, + width = memWidth, + depth = memDepth, + family = "1r1w", + ports = Seq( + generateTestPort( + "portA", + memWidth, + Some(memDepth), + maskGran = memMaskGran, + write = false, + writeEnable = false, + read = true, + readEnable = true + ), + generateTestPort( + "portB", + memWidth, + Some(memDepth), + maskGran = memMaskGran, + write = true, + writeEnable = true, + read = false, + readEnable = false + ) + ) ) } override def generateLibSRAM() = { SRAMMacro( - name=lib_name, - width=libWidth, - depth=libDepth, - family="1r1w", - ports=Seq(generateTestPort( - "portA", libWidth, libDepth, - write=false, writeEnable=false, - read=true, readEnable=true - ), generateTestPort( - "portB", libWidth, libDepth, - write=true, writeEnable=true, - read=false, readEnable=false - )) + name = lib_name, + width = libWidth, + depth = libDepth, + family = "1r1w", + ports = Seq( + generateTestPort( + "portA", + libWidth, + libDepth, + write = false, + writeEnable = false, + read = true, + readEnable = true + ), + generateTestPort( + "portB", + libWidth, + libDepth, + write = true, + writeEnable = true, + read = false, + readEnable = false + ) + ) ) } override def generateHeaderPorts() = { - generatePort("portA", mem_addr_width, memWidth, - write=false, writeEnable=false, read=true, readEnable=true, Some(memMaskBits)) + "\n" + - generatePort("portB", mem_addr_width, memWidth, - write=true, writeEnable=true, read=false, readEnable=false, Some(memMaskBits)) + generatePort( + "portA", + mem_addr_width, + memWidth, + write = false, + writeEnable = false, + read = true, + readEnable = true, + Some(memMaskBits) + ) + "\n" + + generatePort( + "portB", + mem_addr_width, + memWidth, + write = true, + writeEnable = true, + read = false, + readEnable = false, + Some(memMaskBits) + ) } override def generateFooterPorts() = { - generatePort("portA", lib_addr_width, libWidth, - write=false, writeEnable=false, read=true, readEnable=true, None) + "\n" + - generatePort("portB", lib_addr_width, libWidth, - write=true, writeEnable=true, read=false, readEnable=false, None) + generatePort( + "portA", + lib_addr_width, + libWidth, + write = false, + writeEnable = false, + read = true, + readEnable = true, + None + ) + "\n" + + generatePort( + "portB", + lib_addr_width, + libWidth, + write = true, + writeEnable = true, + read = false, + readEnable = false, + None + ) } override def generateBody() = -""" + """ inst mem_0_0 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem inst mem_0_2 of awesome_lib_mem @@ -234,42 +318,70 @@ class SplitWidth_2rw_differentMasks extends MacroCompilerSpec with HasSRAMGenera override def generateMemSRAM() = { println(memMaskGranB) SRAMMacro( - name=mem_name, - width=memWidth, - depth=memDepth, - family="2rw", - ports=Seq(generateTestPort( - "portA", memWidth, Some(memDepth), maskGran=memMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - ), generateTestPort( - "portB", memWidth, Some(memDepth), maskGran=Some(memMaskGranB), - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = mem_name, + width = memWidth, + depth = memDepth, + family = "2rw", + ports = Seq( + generateTestPort( + "portA", + memWidth, + Some(memDepth), + maskGran = memMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ), + generateTestPort( + "portB", + memWidth, + Some(memDepth), + maskGran = Some(memMaskGranB), + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateLibSRAM() = { SRAMMacro( - name=lib_name, - width=libWidth, - depth=libDepth, - family="2rw", - ports=Seq(generateTestPort( - "portA", libWidth, libDepth, - write=true, writeEnable=true, - read=true, readEnable=true - ), generateTestPort( - "portB", libWidth, libDepth, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = lib_name, + width = libWidth, + depth = libDepth, + family = "2rw", + ports = Seq( + generateTestPort( + "portA", + libWidth, + libDepth, + write = true, + writeEnable = true, + read = true, + readEnable = true + ), + generateTestPort( + "portB", + libWidth, + libDepth, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateHeaderPorts() = { - generateReadWriteHeaderPort("portA", true, Some(memMaskBits)) + "\n" + generateReadWriteHeaderPort("portB", true, Some(memWidth / memMaskGranB)) + generateReadWriteHeaderPort("portA", true, Some(memMaskBits)) + "\n" + generateReadWriteHeaderPort( + "portB", + true, + Some(memWidth / memMaskGranB) + ) } override def generateFooterPorts() = { @@ -277,7 +389,7 @@ class SplitWidth_2rw_differentMasks extends MacroCompilerSpec with HasSRAMGenera } override def generateBody() = -""" + """ inst mem_0_0 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem inst mem_0_2 of awesome_lib_mem diff --git a/macros/src/test/scala/SRAMCompiler.scala b/macros/src/test/scala/barstools/macros/SRAMCompiler.scala similarity index 85% rename from macros/src/test/scala/SRAMCompiler.scala rename to macros/src/test/scala/barstools/macros/SRAMCompiler.scala index 5cae4745..17f49601 100644 --- a/macros/src/test/scala/SRAMCompiler.scala +++ b/macros/src/test/scala/barstools/macros/SRAMCompiler.scala @@ -1,7 +1,5 @@ package barstools.macros -import mdf.macrolib._ - class SRAMCompiler extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { val compiler = generateSRAMCompiler("awesome", "A") val verilog = s"v-SRAMCompiler.v" @@ -15,8 +13,7 @@ class SRAMCompiler extends MacroCompilerSpec with HasSRAMGenerator with HasSimpl writeToLib(lib, Seq(compiler)) - writeToMem(mem, Seq(generateSRAM("mymem", "X", 8, 16))) - compileExecuteAndTest(mem, Some(lib), verilog, output=output, false, true) + compileExecuteAndTest(mem, Some(lib), verilog, output = output, false, true) } diff --git a/macros/src/test/scala/SimpleSplitDepth.scala b/macros/src/test/scala/barstools/macros/SimpleSplitDepth.scala similarity index 86% rename from macros/src/test/scala/SimpleSplitDepth.scala rename to macros/src/test/scala/barstools/macros/SimpleSplitDepth.scala index e3560f9a..5a7fc77d 100644 --- a/macros/src/test/scala/SimpleSplitDepth.scala +++ b/macros/src/test/scala/barstools/macros/SimpleSplitDepth.scala @@ -1,40 +1,41 @@ package barstools.macros -import mdf.macrolib._ - // Test the depth splitting aspect of the memory compiler. // This file is for simple tests: one read-write port, powers of two sizes, etc. // For example, implementing a 4096x32 memory using four 1024x32 memories. trait HasSimpleDepthTestGenerator extends HasSimpleTestGenerator { this: MacroCompilerSpec with HasSRAMGenerator => - def width: Int + def width: Int - override lazy val memWidth = width - override lazy val libWidth = width + override lazy val memWidth = width + override lazy val libWidth = width - // Generate a depth-splitting body. - override def generateBody(): String = { - val output = new StringBuilder + // Generate a depth-splitting body. + override def generateBody(): String = { + val output = new StringBuilder - if (selectBits > 0) { - output.append ( -s""" + if (selectBits > 0) { + output.append( + s""" node ${memPortPrefix}_addr_sel = bits(${memPortPrefix}_addr, ${mem_addr_width - 1}, $lib_addr_width) reg ${memPortPrefix}_addr_sel_reg : UInt<${selectBits}>, ${memPortPrefix}_clk with : reset => (UInt<1>("h0"), ${memPortPrefix}_addr_sel_reg) ${memPortPrefix}_addr_sel_reg <= mux(UInt<1>("h1"), ${memPortPrefix}_addr_sel, ${memPortPrefix}_addr_sel_reg) """ - ) - } + ) + } - for (i <- 0 to depthInstances - 1) { - val maskStatement = generateMaskStatement(0, i) - val enableIdentifier = if (selectBits > 0) s"""eq(${memPortPrefix}_addr_sel, UInt<${selectBits}>("h${i.toHexString}"))""" else "UInt<1>(\"h1\")" - val chipEnable = s"""UInt<1>("h1")""" - val writeEnable = if (memMaskGran.isEmpty) s"and(${memPortPrefix}_write_en, ${chipEnable})" else s"${memPortPrefix}_write_en" - output.append( - s""" + for (i <- 0 to depthInstances - 1) { + val maskStatement = generateMaskStatement(0, i) + val enableIdentifier = + if (selectBits > 0) s"""eq(${memPortPrefix}_addr_sel, UInt<${selectBits}>("h${i.toHexString}"))""" + else "UInt<1>(\"h1\")" + val chipEnable = s"""UInt<1>("h1")""" + val writeEnable = + if (memMaskGran.isEmpty) s"and(${memPortPrefix}_write_en, ${chipEnable})" else s"${memPortPrefix}_write_en" + output.append( + s""" inst mem_${i}_0 of ${lib_name} mem_${i}_0.${libPortPrefix}_clk <= ${memPortPrefix}_clk mem_${i}_0.${libPortPrefix}_addr <= ${memPortPrefix}_addr @@ -44,26 +45,29 @@ s""" mem_${i}_0.${libPortPrefix}_write_en <= and(and(${writeEnable}, UInt<1>("h1")), ${enableIdentifier}) node ${memPortPrefix}_dout_${i} = ${memPortPrefix}_dout_${i}_0 """ - ) - } - def generate_outer_dout_tree(i:Int, depthInstances: Int): String = { - if (i > depthInstances - 1) { - s"""UInt<${libWidth}>("h0")""" - } else { - s"""mux(eq(${memPortPrefix}_addr_sel_reg, UInt<%d>("h%s")), ${memPortPrefix}_dout_%d, %s)""".format( - selectBits, i.toHexString, i, generate_outer_dout_tree(i + 1, depthInstances) - ) - } - } - output append s" ${memPortPrefix}_dout <= " - if (selectBits > 0) { - output append generate_outer_dout_tree(0, depthInstances) + ) + } + def generate_outer_dout_tree(i: Int, depthInstances: Int): String = { + if (i > depthInstances - 1) { + s"""UInt<${libWidth}>("h0")""" } else { - output append s"""mux(UInt<1>("h1"), ${memPortPrefix}_dout_0, UInt<${libWidth}>("h0"))""" + s"""mux(eq(${memPortPrefix}_addr_sel_reg, UInt<%d>("h%s")), ${memPortPrefix}_dout_%d, %s)""".format( + selectBits, + i.toHexString, + i, + generate_outer_dout_tree(i + 1, depthInstances) + ) } - - output.toString } + output.append(s" ${memPortPrefix}_dout <= ") + if (selectBits > 0) { + output.append(generate_outer_dout_tree(0, depthInstances)) + } else { + output.append(s"""mux(UInt<1>("h1"), ${memPortPrefix}_dout_0, UInt<${libWidth}>("h0"))""") + } + + output.toString + } } // Try different widths @@ -156,7 +160,10 @@ class SplitDepth2048x8_mrw_lib8 extends MacroCompilerSpec with HasSRAMGenerator } // Non-bit level mask -class SplitDepth2048x64_mrw_mem32_lib8 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { +class SplitDepth2048x64_mrw_mem32_lib8 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator { override lazy val width = 64 override lazy val memDepth = BigInt(2048) override lazy val libDepth = BigInt(1024) @@ -167,7 +174,10 @@ class SplitDepth2048x64_mrw_mem32_lib8 extends MacroCompilerSpec with HasSRAMGen } // Bit level mask -class SplitDepth2048x32_mrw_mem16_lib1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { +class SplitDepth2048x32_mrw_mem16_lib1 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator { override lazy val width = 32 override lazy val memDepth = BigInt(2048) override lazy val libDepth = BigInt(1024) @@ -215,7 +225,7 @@ class SplitDepth2048x32_mrw_mem3_lib1 extends MacroCompilerSpec with HasSRAMGene override lazy val memMaskGran = Some(3) override lazy val libMaskGran = Some(1) - it should "be enabled when non-power of two masks are supported" is (pending) + (it should "be enabled when non-power of two masks are supported").is(pending) //compileExecuteAndTest(mem, lib, v, output) } @@ -226,7 +236,7 @@ class SplitDepth2048x32_mrw_mem7_lib1 extends MacroCompilerSpec with HasSRAMGene override lazy val memMaskGran = Some(7) override lazy val libMaskGran = Some(1) - it should "be enabled when non-power of two masks are supported" is (pending) + (it should "be enabled when non-power of two masks are supported").is(pending) //compileExecuteAndTest(mem, lib, v, output) } @@ -237,7 +247,7 @@ class SplitDepth2048x32_mrw_mem9_lib1 extends MacroCompilerSpec with HasSRAMGene override lazy val memMaskGran = Some(9) override lazy val libMaskGran = Some(1) - it should "be enabled when non-power of two masks are supported" is (pending) + (it should "be enabled when non-power of two masks are supported").is(pending) //compileExecuteAndTest(mem, lib, v, output) } @@ -249,12 +259,12 @@ class SplitDepth2048x8_extraPort extends MacroCompilerSpec with HasSRAMGenerator override lazy val memDepth = BigInt(2048) override lazy val libDepth = BigInt(1024) override lazy val extraPorts = List( - MacroExtraPort(name="extra_port", width=8, portType=Constant, value=0xff) + MacroExtraPort(name = "extra_port", width = 8, portType = Constant, value = 0xff) ) override lazy val extraTag = "extraPort" override def generateOutput(): String = -""" + """ circuit target_memory : module target_memory : input outer_addr : UInt<11> @@ -319,22 +329,22 @@ class SplitDepth_SplitPortsNonMasked extends MacroCompilerSpec with HasSRAMGener val v = "split_depth-r-w-split-lib-split-mem.v" val libMacro = SRAMMacro( - name="awesome_lib_mem", - width=width, - depth=libDepth, - family="1r1w", - ports=Seq( + name = "awesome_lib_mem", + width = width, + depth = libDepth, + family = "1r1w", + ports = Seq( generateReadPort("innerA", width, libDepth), generateWritePort("innerB", width, libDepth) ) ) val memMacro = SRAMMacro( - name="target_memory", - width=width, - depth=memDepth, - family="1r1w", - ports=Seq( + name = "target_memory", + width = width, + depth = memDepth, + family = "1r1w", + ports = Seq( generateReadPort("outerB", width, memDepth), generateWritePort("outerA", width, memDepth) ) @@ -344,7 +354,7 @@ class SplitDepth_SplitPortsNonMasked extends MacroCompilerSpec with HasSRAMGener writeToLib(lib, Seq(libMacro)) val output = -""" + """ circuit target_memory : module target_memory : input outerB_addr : UInt<11> @@ -406,11 +416,11 @@ circuit target_memory : val v = "split_depth-r-w-regular-lib-split-mem.v" val memMacro = SRAMMacro( - name="target_memory", - width=width, - depth=memDepth, - family="1r1w", - ports=Seq( + name = "target_memory", + width = width, + depth = memDepth, + family = "1r1w", + ports = Seq( generateReadPort("outerB", width, memDepth), generateWritePort("outerA", width, memDepth) ) @@ -420,7 +430,7 @@ circuit target_memory : writeToLib(lib, Seq(generateSRAM("awesome_lib_mem", "lib", width, libDepth))) val output = -""" + """ TODO """ @@ -439,11 +449,11 @@ TODO val v = "split_depth-r-w-split-lib-regular-mem.v" val libMacro = SRAMMacro( - name="awesome_lib_mem", - width=width, - depth=libDepth, - family="1rw", - ports=Seq( + name = "awesome_lib_mem", + width = width, + depth = libDepth, + family = "1rw", + ports = Seq( generateReadPort("innerA", width, libDepth), generateWritePort("innerB", width, libDepth) ) @@ -453,7 +463,7 @@ TODO writeToLib(lib, Seq(libMacro)) val output = -""" + """ TODO """ @@ -480,22 +490,22 @@ class SplitDepth_SplitPortsMasked extends MacroCompilerSpec with HasSRAMGenerato val v = "split_depth-r-mw-split-lib-split-mem.v" val libMacro = SRAMMacro( - name="awesome_lib_mem", - width=width, - depth=libDepth, - family="1r1w", - ports=Seq( + name = "awesome_lib_mem", + width = width, + depth = libDepth, + family = "1r1w", + ports = Seq( generateReadPort("innerA", width, libDepth), generateWritePort("innerB", width, libDepth, libMaskGran) ) ) val memMacro = SRAMMacro( - name="target_memory", - width=width, - depth=memDepth, - family="1r1w", - ports=Seq( + name = "target_memory", + width = width, + depth = memDepth, + family = "1r1w", + ports = Seq( generateReadPort("outerB", width, memDepth), generateWritePort("outerA", width, memDepth, memMaskGran) ) @@ -505,7 +515,7 @@ class SplitDepth_SplitPortsMasked extends MacroCompilerSpec with HasSRAMGenerato writeToLib(lib, Seq(libMacro)) val output = -""" + """ circuit target_memory : module target_memory : input outerB_addr : UInt<11> @@ -571,11 +581,11 @@ circuit target_memory : val v = "split_depth-r-mw-regular-lib-split-mem.v" val memMacro = SRAMMacro( - name="target_memory", - width=width, - depth=memDepth, - family="1r1w", - ports=Seq( + name = "target_memory", + width = width, + depth = memDepth, + family = "1r1w", + ports = Seq( generateReadPort("outerB", width, memDepth), generateWritePort("outerA", width, memDepth, memMaskGran) ) @@ -585,7 +595,7 @@ circuit target_memory : writeToLib(lib, Seq(generateSRAM("awesome_lib_mem", "lib", width, libDepth, libMaskGran))) val output = -""" + """ TODO """ @@ -604,11 +614,11 @@ TODO val v = "split_depth-r-mw-split-lib-regular-mem.v" val libMacro = SRAMMacro( - name="awesome_lib_mem", - width=width, - depth=libDepth, - family="1rw", - ports=Seq( + name = "awesome_lib_mem", + width = width, + depth = libDepth, + family = "1rw", + ports = Seq( generateReadPort("innerA", width, libDepth), generateWritePort("innerB", width, libDepth, libMaskGran) ) @@ -618,7 +628,7 @@ TODO writeToLib(lib, Seq(libMacro)) val output = -""" + """ TODO """ diff --git a/macros/src/test/scala/SimpleSplitWidth.scala b/macros/src/test/scala/barstools/macros/SimpleSplitWidth.scala similarity index 75% rename from macros/src/test/scala/SimpleSplitWidth.scala rename to macros/src/test/scala/barstools/macros/SimpleSplitWidth.scala index 843eed49..3cd0a6df 100644 --- a/macros/src/test/scala/SimpleSplitWidth.scala +++ b/macros/src/test/scala/barstools/macros/SimpleSplitWidth.scala @@ -5,43 +5,45 @@ package barstools.macros trait HasSimpleWidthTestGenerator extends HasSimpleTestGenerator { this: MacroCompilerSpec with HasSRAMGenerator => - def depth: BigInt + def depth: BigInt - override lazy val memDepth = depth - override lazy val libDepth = depth + override lazy val memDepth = depth + override lazy val libDepth = depth - override def generateBody(): String = { - val output = new StringBuilder + override def generateBody(): String = { + val output = new StringBuilder - // Generate mem_0_ lines for number of width instances. - output.append( - ((0 to widthInstances - 1) map {i:Int => s""" + // Generate mem_0_ lines for number of width instances. + output.append( + ((0 to widthInstances - 1).map { i: Int => + s""" inst mem_0_${i} of ${lib_name} """ - }).reduceLeft(_ + _) - ) + }).reduceLeft(_ + _) + ) - // Generate submemory connection blocks. - output append (for (i <- 0 to widthInstances - 1) yield { - // Width of this submemory. - val myMemWidth = if (i == widthInstances - 1) lastWidthBits else usableLibWidth - // Base bit of this submemory. - // e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this - // would be 16. - val myBaseBit = usableLibWidth*i - - val maskStatement = generateMaskStatement(i, 0) - - // We need to use writeEnable as a crude "mask" if mem has a mask but - // lib does not. - val writeEnableBit = if (libMaskGran.isEmpty && memMaskGran.isDefined) { - val outerMaskBit = myBaseBit / memMaskGran.get - s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" - } else """UInt<1>("h1")""" - val chipEnable = s"""UInt<1>("h1")""" - val writeEnableExpr = if (libMaskGran.isEmpty) s"and(${memPortPrefix}_write_en, ${chipEnable})" else s"${memPortPrefix}_write_en" - -s""" + // Generate submemory connection blocks. + output.append((for (i <- 0 to widthInstances - 1) yield { + // Width of this submemory. + val myMemWidth = if (i == widthInstances - 1) lastWidthBits else usableLibWidth + // Base bit of this submemory. + // e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this + // would be 16. + val myBaseBit = usableLibWidth * i + + val maskStatement = generateMaskStatement(i, 0) + + // We need to use writeEnable as a crude "mask" if mem has a mask but + // lib does not. + val writeEnableBit = if (libMaskGran.isEmpty && memMaskGran.isDefined) { + val outerMaskBit = myBaseBit / memMaskGran.get + s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" + } else """UInt<1>("h1")""" + val chipEnable = s"""UInt<1>("h1")""" + val writeEnableExpr = + if (libMaskGran.isEmpty) s"and(${memPortPrefix}_write_en, ${chipEnable})" else s"${memPortPrefix}_write_en" + + s""" mem_0_${i}.${libPortPrefix}_clk <= ${memPortPrefix}_clk mem_0_${i}.${libPortPrefix}_addr <= ${memPortPrefix}_addr node ${memPortPrefix}_dout_0_${i} = bits(mem_0_${i}.${libPortPrefix}_dout, ${myMemWidth - 1}, 0) @@ -49,24 +51,23 @@ s""" ${maskStatement} mem_0_${i}.${libPortPrefix}_write_en <= and(and(${writeEnableExpr}, ${writeEnableBit}), UInt<1>("h1")) """ - }).reduceLeft(_ + _) - - // Generate final output that concats together the sub-memories. - // e.g. cat(outer_dout_0_2, cat(outer_dout_0_1, outer_dout_0_0)) - output append { - val doutStatements = ((widthInstances - 1 to 0 by -1) map (i => s"${memPortPrefix}_dout_0_${i}")) - val catStmt = doutStatements.init.foldRight(doutStatements.last)((l: String, r: String) => s"cat($l, $r)") -s""" + }).reduceLeft(_ + _)) + + // Generate final output that concats together the sub-memories. + // e.g. cat(outer_dout_0_2, cat(outer_dout_0_1, outer_dout_0_0)) + output.append { + val doutStatements = ((widthInstances - 1 to 0 by -1).map(i => s"${memPortPrefix}_dout_0_${i}")) + val catStmt = doutStatements.init.foldRight(doutStatements.last)((l: String, r: String) => s"cat($l, $r)") + s""" node ${memPortPrefix}_dout_0 = ${catStmt} """ - } + } - output append -s""" + output.append(s""" ${memPortPrefix}_dout <= mux(UInt<1>("h1"), ${memPortPrefix}_dout_0, UInt<${memWidth}>("h0")) -""" - output.toString - } +""") + output.toString + } } // Try different widths against a base memory width of 8. @@ -268,7 +269,10 @@ class SplitWidth1024x16_mem11_rw extends MacroCompilerSpec with HasSRAMGenerator // Masked RAM -class SplitWidth1024x8_memGran_8_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x8_memGran_8_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 8 override lazy val libWidth = 8 @@ -278,7 +282,10 @@ class SplitWidth1024x8_memGran_8_libGran_1_rw extends MacroCompilerSpec with Has compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x16_memGran_8_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_8_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 @@ -288,7 +295,10 @@ class SplitWidth1024x16_memGran_8_libGran_1_rw extends MacroCompilerSpec with Ha compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x16_memGran_8_libGran_8_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_8_libGran_8_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 @@ -298,7 +308,10 @@ class SplitWidth1024x16_memGran_8_libGran_8_rw extends MacroCompilerSpec with Ha compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x128_memGran_8_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x128_memGran_8_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 128 override lazy val libWidth = 32 @@ -308,7 +321,10 @@ class SplitWidth1024x128_memGran_8_libGran_1_rw extends MacroCompilerSpec with H compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x16_memGran_4_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_4_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 @@ -318,7 +334,10 @@ class SplitWidth1024x16_memGran_4_libGran_1_rw extends MacroCompilerSpec with Ha compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x16_memGran_2_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_2_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 @@ -328,7 +347,10 @@ class SplitWidth1024x16_memGran_2_libGran_1_rw extends MacroCompilerSpec with Ha compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x16_memGran_16_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_16_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 @@ -360,7 +382,10 @@ class SplitWidth1024x16_libGran_1_rw extends MacroCompilerSpec with HasSRAMGener // Non-memMask and non-1 libMask -class SplitWidth1024x16_memGran_8_libGran_2_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_8_libGran_2_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 @@ -372,21 +397,27 @@ class SplitWidth1024x16_memGran_8_libGran_2_rw extends MacroCompilerSpec with Ha // Non-power of two memGran -class SplitWidth1024x16_memGran_9_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_9_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 override lazy val memMaskGran = Some(9) override lazy val libMaskGran = Some(1) - it should "be enabled when non-power of two masks are supported" is (pending) + (it should "be enabled when non-power of two masks are supported").is(pending) //~ compile(mem, lib, v, false) //~ execute(mem, lib, false, output) } // Read enable -class SplitWidth1024x32_readEnable_Lib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x32_readEnable_Lib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { import mdf.macrolib._ override lazy val depth = BigInt(1024) @@ -395,20 +426,27 @@ class SplitWidth1024x32_readEnable_Lib extends MacroCompilerSpec with HasSRAMGen override def generateLibSRAM() = { SRAMMacro( - name=lib_name, - width=libWidth, - depth=libDepth, - family="1rw", - ports=Seq(generateTestPort( - "lib", Some(libWidth), Some(libDepth), maskGran=libMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = lib_name, + width = libWidth, + depth = libDepth, + family = "1rw", + ports = Seq( + generateTestPort( + "lib", + Some(libWidth), + Some(libDepth), + maskGran = libMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateBody() = -""" + """ inst mem_0_0 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem inst mem_0_2 of awesome_lib_mem @@ -444,7 +482,10 @@ class SplitWidth1024x32_readEnable_Lib extends MacroCompilerSpec with HasSRAMGen compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x32_readEnable_Mem extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x32_readEnable_Mem + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { import mdf.macrolib._ override lazy val depth = BigInt(1024) @@ -453,15 +494,22 @@ class SplitWidth1024x32_readEnable_Mem extends MacroCompilerSpec with HasSRAMGen override def generateMemSRAM() = { SRAMMacro( - name=mem_name, - width=memWidth, - depth=memDepth, - family="1rw", - ports=Seq(generateTestPort( - "outer", Some(memWidth), Some(memDepth), maskGran=memMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = mem_name, + width = memWidth, + depth = memDepth, + family = "1rw", + ports = Seq( + generateTestPort( + "outer", + Some(memWidth), + Some(memDepth), + maskGran = memMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } @@ -470,7 +518,10 @@ class SplitWidth1024x32_readEnable_Mem extends MacroCompilerSpec with HasSRAMGen compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x32_readEnable_LibMem extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x32_readEnable_LibMem + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { import mdf.macrolib._ override lazy val depth = BigInt(1024) @@ -479,34 +530,48 @@ class SplitWidth1024x32_readEnable_LibMem extends MacroCompilerSpec with HasSRAM override def generateLibSRAM() = { SRAMMacro( - name=lib_name, - width=libWidth, - depth=libDepth, - family="1rw", - ports=Seq(generateTestPort( - "lib", Some(libWidth), Some(libDepth), maskGran=libMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = lib_name, + width = libWidth, + depth = libDepth, + family = "1rw", + ports = Seq( + generateTestPort( + "lib", + Some(libWidth), + Some(libDepth), + maskGran = libMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateMemSRAM() = { SRAMMacro( - name=mem_name, - width=memWidth, - depth=memDepth, - family="1rw", - ports=Seq(generateTestPort( - "outer", Some(memWidth), Some(memDepth), maskGran=memMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = mem_name, + width = memWidth, + depth = memDepth, + family = "1rw", + ports = Seq( + generateTestPort( + "outer", + Some(memWidth), + Some(memDepth), + maskGran = memMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateBody() = -""" + """ inst mem_0_0 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem inst mem_0_2 of awesome_lib_mem diff --git a/macros/src/test/scala/SpecificExamples.scala b/macros/src/test/scala/barstools/macros/SpecificExamples.scala similarity index 98% rename from macros/src/test/scala/SpecificExamples.scala rename to macros/src/test/scala/barstools/macros/SpecificExamples.scala index e41932bb..334e3a73 100644 --- a/macros/src/test/scala/SpecificExamples.scala +++ b/macros/src/test/scala/barstools/macros/SpecificExamples.scala @@ -29,8 +29,8 @@ class WriteEnableTest extends MacroCompilerSpec with HasSRAMGenerator { override val libPrefix = "macros/src/test/resources" - val memSRAMs = mdf.macrolib.Utils.readMDFFromString( -""" + val memSRAMs = mdf.macrolib.Utils + .readMDFFromString(""" [ { "type" : "sram", "name" : "cc_banks_0_ext", @@ -58,7 +58,7 @@ class WriteEnableTest extends MacroCompilerSpec with HasSRAMGenerator { writeToMem(mem, memSRAMs) val output = -""" + """ circuit cc_banks_0_ext : module cc_banks_0_ext : input RW0_addr : UInt<12> @@ -99,8 +99,8 @@ class MaskPortTest extends MacroCompilerSpec with HasSRAMGenerator { override val libPrefix = "macros/src/test/resources" - val memSRAMs = mdf.macrolib.Utils.readMDFFromString( -""" + val memSRAMs = mdf.macrolib.Utils + .readMDFFromString(""" [ { "type" : "sram", "name" : "cc_dir_ext", @@ -131,7 +131,7 @@ class MaskPortTest extends MacroCompilerSpec with HasSRAMGenerator { writeToMem(mem, memSRAMs) val output = -""" + """ circuit cc_dir_ext : module cc_dir_ext : input RW0_addr : UInt<9> @@ -183,8 +183,8 @@ class BOOMTest extends MacroCompilerSpec with HasSRAMGenerator { override val libPrefix = "macros/src/test/resources" - val memSRAMs = mdf.macrolib.Utils.readMDFFromString( -""" + val memSRAMs = mdf.macrolib.Utils + .readMDFFromString(""" [ { "type" : "sram", "name" : "_T_182_ext", @@ -354,7 +354,7 @@ class BOOMTest extends MacroCompilerSpec with HasSRAMGenerator { writeToMem(mem, memSRAMs) val output = // TODO: check correctness... -""" + """ circuit smem_0_ext : module _T_182_ext : input R0_addr : UInt<6> @@ -1350,14 +1350,14 @@ circuit smem_0_ext : class SmallTagArrayTest extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleTestGenerator { // Test that mapping a smaller memory using a larger lib can still work. - override def memWidth: Int = 26 - override def memDepth: BigInt = BigInt(2) - override def memMaskGran: Option[Int] = Some(26) + override def memWidth: Int = 26 + override def memDepth: BigInt = BigInt(2) + override def memMaskGran: Option[Int] = Some(26) override def memPortPrefix: String = "" - override def libWidth: Int = 32 - override def libDepth: BigInt = BigInt(64) - override def libMaskGran: Option[Int] = Some(1) + override def libWidth: Int = 32 + override def libDepth: BigInt = BigInt(64) + override def libMaskGran: Option[Int] = Some(1) override def libPortPrefix: String = "" override def extraPorts: Seq[MacroExtraPort] = Seq( @@ -1388,73 +1388,73 @@ class RocketChipTest extends MacroCompilerSpec with HasSRAMGenerator { val libSRAMs = Seq( SRAMMacro( - name="SRAM1RW1024x8", - depth=1024, - width=8, - family="1rw", - ports=Seq( + name = "SRAM1RW1024x8", + depth = 1024, + width = 8, + family = "1rw", + ports = Seq( generateReadWritePort("", 8, BigInt(1024)) ) ), SRAMMacro( - name="SRAM1RW512x32", - depth=512, - width=32, - family="1rw", - ports=Seq( + name = "SRAM1RW512x32", + depth = 512, + width = 32, + family = "1rw", + ports = Seq( generateReadWritePort("", 32, BigInt(512)) ) ), SRAMMacro( - name="SRAM1RW64x128", - depth=64, - width=128, - family="1rw", - ports=Seq( + name = "SRAM1RW64x128", + depth = 64, + width = 128, + family = "1rw", + ports = Seq( generateReadWritePort("", 128, BigInt(64)) ) ), SRAMMacro( - name="SRAM1RW64x32", - depth=64, - width=32, - family="1rw", - ports=Seq( + name = "SRAM1RW64x32", + depth = 64, + width = 32, + family = "1rw", + ports = Seq( generateReadWritePort("", 32, BigInt(64)) ) ), SRAMMacro( - name="SRAM1RW64x8", - depth=64, - width=8, - family="1rw", - ports=Seq( + name = "SRAM1RW64x8", + depth = 64, + width = 8, + family = "1rw", + ports = Seq( generateReadWritePort("", 8, BigInt(64)) ) ), SRAMMacro( - name="SRAM1RW512x8", - depth=512, - width=8, - family="1rw", - ports=Seq( + name = "SRAM1RW512x8", + depth = 512, + width = 8, + family = "1rw", + ports = Seq( generateReadWritePort("", 8, BigInt(512)) ) ), SRAMMacro( - name="SRAM2RW64x32", - depth=64, - width=32, - family="1r1w", - ports=Seq( + name = "SRAM2RW64x32", + depth = 64, + width = 32, + family = "1r1w", + ports = Seq( generateReadPort("portA", 32, BigInt(64)), generateWritePort("portB", 32, BigInt(64)) ) ) ) - val memSRAMs = mdf.macrolib.Utils.readMDFFromString( -""" + val memSRAMs = mdf.macrolib.Utils + .readMDFFromString(""" [ { "type": "sram", @@ -1537,7 +1537,7 @@ class RocketChipTest extends MacroCompilerSpec with HasSRAMGenerator { writeToMem(mem, memSRAMs) val output = // TODO: check correctness... -""" + """ circuit T_2172_ext : module tag_array_ext : input RW0_addr : UInt<6> diff --git a/macros/src/test/scala/SynFlops.scala b/macros/src/test/scala/barstools/macros/SynFlops.scala similarity index 87% rename from macros/src/test/scala/SynFlops.scala rename to macros/src/test/scala/barstools/macros/SynFlops.scala index f12161a1..0d39220e 100644 --- a/macros/src/test/scala/SynFlops.scala +++ b/macros/src/test/scala/barstools/macros/SynFlops.scala @@ -4,13 +4,13 @@ package barstools.macros trait HasSynFlopsTestGenerator extends HasSimpleTestGenerator { this: MacroCompilerSpec with HasSRAMGenerator => - def generateFlops: String = { -s""" + def generateFlops: String = { + s""" inst mem_0_0 of split_${lib_name} mem_0_0.${libPortPrefix}_clk <= ${libPortPrefix}_clk mem_0_0.${libPortPrefix}_addr <= ${libPortPrefix}_addr - node ${libPortPrefix}_dout_0_0 = bits(mem_0_0.${libPortPrefix}_dout, ${libWidth-1}, 0) - mem_0_0.${libPortPrefix}_din <= bits(${libPortPrefix}_din, ${libWidth-1}, 0) + node ${libPortPrefix}_dout_0_0 = bits(mem_0_0.${libPortPrefix}_dout, ${libWidth - 1}, 0) + mem_0_0.${libPortPrefix}_din <= bits(${libPortPrefix}_din, ${libWidth - 1}, 0) mem_0_0.${libPortPrefix}_write_en <= and(and(and(${libPortPrefix}_write_en, UInt<1>("h1")), UInt<1>("h1")), UInt<1>("h1")) node ${libPortPrefix}_dout_0 = ${libPortPrefix}_dout_0_0 ${libPortPrefix}_dout <= mux(UInt<1>("h1"), ${libPortPrefix}_dout_0, UInt<${libWidth}>("h0")) @@ -37,49 +37,66 @@ s""" ${libPortPrefix}_dout <= ram.RW_0.rdata ram.RW_0.wdata <= ${libPortPrefix}_din """ - } - - // If there is no lib, put the flops definition into the body. - abstract override def generateBody = { - if (this.isInstanceOf[HasNoLibTestGenerator]) generateFlops else super.generateBody - } - - // If there is no lib, don't generate a footer, since the flops definition - // will be in the body. - override def generateFooter = { - if (this.isInstanceOf[HasNoLibTestGenerator]) "" else -s""" + } + + // If there is no lib, put the flops definition into the body. + abstract override def generateBody = { + if (this.isInstanceOf[HasNoLibTestGenerator]) generateFlops else super.generateBody + } + + // If there is no lib, don't generate a footer, since the flops definition + // will be in the body. + override def generateFooter = { + if (this.isInstanceOf[HasNoLibTestGenerator]) "" + else + s""" module ${lib_name} : ${generateFooterPorts} ${generateFlops} """ - } + } } -class Synflops2048x8_noLib extends MacroCompilerSpec with HasSRAMGenerator with HasNoLibTestGenerator with HasSynFlopsTestGenerator { +class Synflops2048x8_noLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasNoLibTestGenerator + with HasSynFlopsTestGenerator { override lazy val memDepth = BigInt(2048) override lazy val memWidth = 8 compileExecuteAndTest(mem, None, v, output, true) } -class Synflops2048x16_noLib extends MacroCompilerSpec with HasSRAMGenerator with HasNoLibTestGenerator with HasSynFlopsTestGenerator { +class Synflops2048x16_noLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasNoLibTestGenerator + with HasSynFlopsTestGenerator { override lazy val memDepth = BigInt(2048) override lazy val memWidth = 16 compileExecuteAndTest(mem, None, v, output, true) } -class Synflops8192x16_noLib extends MacroCompilerSpec with HasSRAMGenerator with HasNoLibTestGenerator with HasSynFlopsTestGenerator { +class Synflops8192x16_noLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasNoLibTestGenerator + with HasSynFlopsTestGenerator { override lazy val memDepth = BigInt(8192) override lazy val memWidth = 16 compileExecuteAndTest(mem, None, v, output, true) } -class Synflops2048x16_depth_Lib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with HasSynFlopsTestGenerator { +class Synflops2048x16_depth_Lib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with HasSynFlopsTestGenerator { override lazy val memDepth = BigInt(2048) override lazy val libDepth = BigInt(1024) override lazy val width = 16 @@ -87,7 +104,11 @@ class Synflops2048x16_depth_Lib extends MacroCompilerSpec with HasSRAMGenerator compileExecuteAndTest(mem, lib, v, output, true) } -class Synflops2048x64_width_Lib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator with HasSynFlopsTestGenerator { +class Synflops2048x64_width_Lib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator + with HasSynFlopsTestGenerator { override lazy val memWidth = 64 override lazy val libWidth = 8 override lazy val depth = BigInt(1024) @@ -95,7 +116,11 @@ class Synflops2048x64_width_Lib extends MacroCompilerSpec with HasSRAMGenerator compileExecuteAndTest(mem, lib, v, output, true) } -class Synflops_SplitPorts_Read_Write extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with HasSynFlopsTestGenerator { +class Synflops_SplitPorts_Read_Write + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with HasSynFlopsTestGenerator { import mdf.macrolib._ override lazy val memDepth = BigInt(2048) @@ -103,29 +128,29 @@ class Synflops_SplitPorts_Read_Write extends MacroCompilerSpec with HasSRAMGener override lazy val width = 8 override def generateLibSRAM = SRAMMacro( - name=lib_name, - width=width, - depth=libDepth, - family="1r1w", - ports=Seq( + name = lib_name, + width = width, + depth = libDepth, + family = "1r1w", + ports = Seq( generateReadPort("innerA", width, libDepth), generateWritePort("innerB", width, libDepth) ) ) override def generateMemSRAM = SRAMMacro( - name=mem_name, - width=width, - depth=memDepth, - family="1r1w", - ports=Seq( + name = mem_name, + width = width, + depth = memDepth, + family = "1r1w", + ports = Seq( generateReadPort("outerB", width, memDepth), generateWritePort("outerA", width, memDepth) ) ) override def generateHeader = -""" + """ circuit target_memory : module target_memory : input outerB_addr : UInt<11> @@ -138,7 +163,7 @@ circuit target_memory : """ override def generateBody = -""" + """ node outerB_addr_sel = bits(outerB_addr, 10, 10) reg outerB_addr_sel_reg : UInt<1>, outerB_clk with : reset => (UInt<1>("h0"), outerB_addr_sel_reg) @@ -166,7 +191,7 @@ circuit target_memory : """ override def generateFooterPorts = -""" + """ input innerA_addr : UInt<10> input innerA_clk : Clock output innerA_dout : UInt<8> @@ -177,7 +202,7 @@ circuit target_memory : """ override def generateFlops = -""" + """ inst mem_0_0 of split_awesome_lib_mem mem_0_0.innerB_clk <= innerB_clk mem_0_0.innerB_addr <= innerB_addr @@ -222,7 +247,11 @@ circuit target_memory : } } -class Synflops_SplitPorts_MaskedMem_Read_MaskedWrite extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with HasSynFlopsTestGenerator { +class Synflops_SplitPorts_MaskedMem_Read_MaskedWrite + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with HasSynFlopsTestGenerator { import mdf.macrolib._ override lazy val memDepth = BigInt(2048) @@ -232,29 +261,29 @@ class Synflops_SplitPorts_MaskedMem_Read_MaskedWrite extends MacroCompilerSpec w override lazy val libMaskGran = Some(1) override def generateLibSRAM = SRAMMacro( - name=lib_name, - width=width, - depth=libDepth, - family="1r1w", - ports=Seq( + name = lib_name, + width = width, + depth = libDepth, + family = "1r1w", + ports = Seq( generateReadPort("innerA", width, libDepth), generateWritePort("innerB", width, libDepth, libMaskGran) ) ) override def generateMemSRAM = SRAMMacro( - name=mem_name, - width=width, - depth=memDepth, - family="1r1w", - ports=Seq( + name = mem_name, + width = width, + depth = memDepth, + family = "1r1w", + ports = Seq( generateReadPort("outerB", width, memDepth), generateWritePort("outerA", width, memDepth, memMaskGran) ) ) override def generateHeader = -""" + """ circuit target_memory : module target_memory : input outerB_addr : UInt<11> @@ -268,7 +297,7 @@ circuit target_memory : """ override def generateBody = -""" + """ node outerB_addr_sel = bits(outerB_addr, 10, 10) reg outerB_addr_sel_reg : UInt<1>, outerB_clk with : reset => (UInt<1>("h0"), outerB_addr_sel_reg) @@ -298,7 +327,7 @@ circuit target_memory : """ override def generateFooterPorts = -""" + """ input innerA_addr : UInt<10> input innerA_clk : Clock output innerA_dout : UInt<8> @@ -310,7 +339,7 @@ circuit target_memory : """ override def generateFlops = -""" + """ inst mem_0_0 of split_awesome_lib_mem inst mem_0_1 of split_awesome_lib_mem inst mem_0_2 of split_awesome_lib_mem diff --git a/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/AddSuffixToModuleNames.scala similarity index 82% rename from tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/AddSuffixToModuleNames.scala index 26de5425..e2c5620d 100644 --- a/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/AddSuffixToModuleNames.scala @@ -2,15 +2,14 @@ package barstools.tapeout.transforms +import firrtl.Mappers._ import firrtl._ +import firrtl.annotations.{CircuitTarget, ModuleTarget, SingleTargetAnnotation} import firrtl.ir._ -import firrtl.Mappers._ -import firrtl.annotations.{ModuleTarget, SingleTargetAnnotation, CircuitTarget} -import firrtl.stage.TransformManager.{TransformDependency} -import firrtl.stage.{Forms} +import firrtl.stage.Forms +import firrtl.stage.TransformManager.TransformDependency -case class KeepNameAnnotation(target: ModuleTarget) - extends SingleTargetAnnotation[ModuleTarget] { +case class KeepNameAnnotation(target: ModuleTarget) extends SingleTargetAnnotation[ModuleTarget] { def duplicate(n: ModuleTarget) = this.copy(n) } @@ -21,8 +20,8 @@ case class ModuleNameSuffixAnnotation(target: CircuitTarget, suffix: String) class AddSuffixToModuleNames extends Transform with DependencyAPIMigration { - override def prerequisites: Seq[TransformDependency] = Forms.LowForm - override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized + override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters override def invalidates(a: Transform): Boolean = false @@ -37,7 +36,7 @@ class AddSuffixToModuleNames extends Transform with DependencyAPIMigration { val excludeSet = state.circuit.modules.flatMap { case e: ExtModule => Some(e.name) case m if (m.name == state.circuit.main) => Some(m.name) - case _ => None + case _ => None }.toSet val renamer = { (name: String) => if (excludeSet(name)) name else name + suffix } diff --git a/tapeout/src/main/scala/transforms/AvoidExtModuleCollisions.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/AvoidExtModuleCollisions.scala similarity index 73% rename from tapeout/src/main/scala/transforms/AvoidExtModuleCollisions.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/AvoidExtModuleCollisions.scala index 76ca1006..127a37fa 100644 --- a/tapeout/src/main/scala/transforms/AvoidExtModuleCollisions.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/AvoidExtModuleCollisions.scala @@ -3,18 +3,18 @@ package barstools.tapeout.transforms import firrtl._ +import firrtl.annotations.NoTargetAnnotation import firrtl.ir._ -import firrtl.annotations.{NoTargetAnnotation} -import firrtl.options.{Dependency} -import firrtl.stage.TransformManager.{TransformDependency} -import firrtl.stage.{Forms} -import firrtl.passes.memlib.{ReplSeqMem} +import firrtl.options.Dependency +import firrtl.passes.memlib.ReplSeqMem +import firrtl.stage.Forms +import firrtl.stage.TransformManager.TransformDependency case class LinkExtModulesAnnotation(mustLink: Seq[ExtModule]) extends NoTargetAnnotation class AvoidExtModuleCollisions extends Transform with DependencyAPIMigration { - override def prerequisites: Seq[TransformDependency] = Forms.HighForm + override def prerequisites: Seq[TransformDependency] = Forms.HighForm override def optionalPrerequisites: Seq[TransformDependency] = Seq(Dependency[RemoveUnusedModules]) override def optionalPrerequisiteOf: Seq[TransformDependency] = { Forms.HighEmitters :+ Dependency[ReplSeqMem] @@ -24,10 +24,9 @@ class AvoidExtModuleCollisions extends Transform with DependencyAPIMigration { def execute(state: CircuitState): CircuitState = { val mustLink = state.annotations.flatMap { case LinkExtModulesAnnotation(mustLink) => mustLink - case _ => Nil + case _ => Nil } val newAnnos = state.annotations.filterNot(_.isInstanceOf[LinkExtModulesAnnotation]) state.copy(circuit = state.circuit.copy(modules = state.circuit.modules ++ mustLink), annotations = newAnnos) } } - diff --git a/tapeout/src/main/scala/transforms/ConvertToExtModPass.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/ConvertToExtModPass.scala similarity index 82% rename from tapeout/src/main/scala/transforms/ConvertToExtModPass.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/ConvertToExtModPass.scala index 04e645fd..a81937a3 100644 --- a/tapeout/src/main/scala/transforms/ConvertToExtModPass.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/ConvertToExtModPass.scala @@ -3,15 +3,14 @@ package barstools.tapeout.transforms import firrtl._ +import firrtl.annotations.{ModuleTarget, ReferenceTarget, SingleTargetAnnotation} import firrtl.ir._ -import firrtl.annotations.{ModuleTarget, SingleTargetAnnotation, ReferenceTarget} -import firrtl.stage.TransformManager.{TransformDependency} -import firrtl.stage.{Forms} -import firrtl.options.{Dependency} -import firrtl.passes.memlib.{ReplSeqMem} +import firrtl.options.Dependency +import firrtl.passes.memlib.ReplSeqMem +import firrtl.stage.Forms +import firrtl.stage.TransformManager.TransformDependency -case class ConvertToExtModAnnotation(target: ModuleTarget) - extends SingleTargetAnnotation[ModuleTarget] { +case class ConvertToExtModAnnotation(target: ModuleTarget) extends SingleTargetAnnotation[ModuleTarget] { def duplicate(n: ModuleTarget) = this.copy(n) } @@ -20,7 +19,7 @@ case class ConvertToExtModAnnotation(target: ModuleTarget) // otherwise it's left alone. class ConvertToExtMod extends Transform with DependencyAPIMigration { - override def prerequisites: Seq[TransformDependency] = Forms.HighForm + override def prerequisites: Seq[TransformDependency] = Forms.HighForm override def optionalPrerequisites: Seq[TransformDependency] = Seq.empty override def optionalPrerequisiteOf: Seq[TransformDependency] = { Forms.HighEmitters ++ Seq(Dependency[RemoveUnusedModules], Dependency[ReplSeqMem]) diff --git a/tapeout/src/main/scala/transforms/EnumerateModules.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/EnumerateModules.scala similarity index 78% rename from tapeout/src/main/scala/transforms/EnumerateModules.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/EnumerateModules.scala index 6a732d75..182b0071 100644 --- a/tapeout/src/main/scala/transforms/EnumerateModules.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/EnumerateModules.scala @@ -23,10 +23,12 @@ class EnumerateModulesPass(enumerate: (Module) => Unit) extends Pass { } class EnumerateModules(enumerate: (Module) => Unit) - extends Transform with SeqTransformBased with DependencyAPIMigration { + extends Transform + with SeqTransformBased + with DependencyAPIMigration { - override def prerequisites: Seq[TransformDependency] = Forms.LowForm - override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized + override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters override def invalidates(a: Transform): Boolean = false diff --git a/tapeout/src/main/scala/transforms/Generate.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/Generate.scala similarity index 81% rename from tapeout/src/main/scala/transforms/Generate.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/Generate.scala index 17b8781d..01ea56e0 100644 --- a/tapeout/src/main/scala/transforms/Generate.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/Generate.scala @@ -5,7 +5,7 @@ import firrtl.annotations._ import firrtl.ir._ import firrtl.passes.memlib.ReplSeqMemAnnotation import firrtl.stage.FirrtlCircuitAnnotation -import firrtl.transforms.{BlackBoxResourceFileNameAnno, DedupModules} +import firrtl.transforms.BlackBoxResourceFileNameAnno import logger.LazyLogging trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions => @@ -13,130 +13,150 @@ trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions => parser.note("tapeout options") - parser.opt[String]("harness-o") + parser + .opt[String]("harness-o") .abbr("tho") .valueName("") .foreach { x => tapeoutOptions = tapeoutOptions.copy( harnessOutput = Some(x) ) - }.text { + } + .text { "use this to generate a harness at " } - parser.opt[String]("syn-top") + parser + .opt[String]("syn-top") .abbr("tst") .valueName("") .foreach { x => tapeoutOptions = tapeoutOptions.copy( synTop = Some(x) ) - }.text { + } + .text { "use this to set synTop" } - parser.opt[String]("top-fir") + parser + .opt[String]("top-fir") .abbr("tsf") .valueName("") .foreach { x => tapeoutOptions = tapeoutOptions.copy( topFir = Some(x) ) - }.text { + } + .text { "use this to set topFir" } - parser.opt[String]("top-anno-out") + parser + .opt[String]("top-anno-out") .abbr("tsaof") .valueName("") .foreach { x => tapeoutOptions = tapeoutOptions.copy( topAnnoOut = Some(x) ) - }.text { + } + .text { "use this to set topAnnoOut" } - parser.opt[String]("top-dotf-out") + parser + .opt[String]("top-dotf-out") .abbr("tdf") .valueName("") .foreach { x => tapeoutOptions = tapeoutOptions.copy( topDotfOut = Some(x) ) - }.text { + } + .text { "use this to set the filename for the top resource .f file" } - parser.opt[String]("harness-top") + parser + .opt[String]("harness-top") .abbr("tht") .valueName("") .foreach { x => tapeoutOptions = tapeoutOptions.copy( harnessTop = Some(x) ) - }.text { + } + .text { "use this to set harnessTop" } - parser.opt[String]("harness-fir") + parser + .opt[String]("harness-fir") .abbr("thf") .valueName("") .foreach { x => tapeoutOptions = tapeoutOptions.copy( harnessFir = Some(x) ) - }.text { + } + .text { "use this to set harnessFir" } - parser.opt[String]("harness-anno-out") + parser + .opt[String]("harness-anno-out") .abbr("thaof") .valueName("") .foreach { x => tapeoutOptions = tapeoutOptions.copy( harnessAnnoOut = Some(x) ) - }.text { + } + .text { "use this to set harnessAnnoOut" } - parser.opt[String]("harness-dotf-out") + parser + .opt[String]("harness-dotf-out") .abbr("hdf") .valueName("") .foreach { x => tapeoutOptions = tapeoutOptions.copy( harnessDotfOut = Some(x) ) - }.text { + } + .text { "use this to set the filename for the harness resource .f file" } - parser.opt[String]("harness-conf") + parser + .opt[String]("harness-conf") .abbr("thconf") - .valueName ("") + .valueName("") .foreach { x => tapeoutOptions = tapeoutOptions.copy( harnessConf = Some(x) ) - }.text { + } + .text { "use this to set the harness conf file location" } } case class TapeoutOptions( - harnessOutput: Option[String] = None, - synTop: Option[String] = None, - topFir: Option[String] = None, - topAnnoOut: Option[String] = None, - topDotfOut: Option[String] = None, - harnessTop: Option[String] = None, - harnessFir: Option[String] = None, + harnessOutput: Option[String] = None, + synTop: Option[String] = None, + topFir: Option[String] = None, + topAnnoOut: Option[String] = None, + topDotfOut: Option[String] = None, + harnessTop: Option[String] = None, + harnessFir: Option[String] = None, harnessAnnoOut: Option[String] = None, harnessDotfOut: Option[String] = None, - harnessConf: Option[String] = None -) extends LazyLogging + harnessConf: Option[String] = None) + extends LazyLogging // Requires two phases, one to collect modules below synTop in the hierarchy // and a second to remove those modules to generate the test harness @@ -190,9 +210,9 @@ sealed trait GenerateTopAndHarnessApp extends LazyLogging { this: App => annoFile.foreach { annoPath => val outputFile = new java.io.PrintWriter(annoPath) outputFile.write(JsonProtocol.serialize(res.circuitState.annotations.filter(_ match { - case da: DeletedAnnotation => false - case ec: EmittedComponent => false - case ea: EmittedAnnotation[_] => false + case da: DeletedAnnotation => false + case ec: EmittedComponent => false + case ea: EmittedAnnotation[_] => false case fca: FirrtlCircuitAnnotation => false case _ => true }))) @@ -207,7 +227,7 @@ sealed trait GenerateTopAndHarnessApp extends LazyLogging { this: App => result match { case x: FirrtlExecutionSuccess => dump(x, tapeoutOptions.topFir, tapeoutOptions.topAnnoOut) - x.circuitState.circuit.modules.collect{ case e: ExtModule => e } + x.circuitState.circuit.modules.collect { case e: ExtModule => e } case x => throw new Exception(s"executeTop failed while executing FIRRTL!\n${x}") } @@ -220,9 +240,9 @@ sealed trait GenerateTopAndHarnessApp extends LazyLogging { this: App => val harnessAnnos = tapeoutOptions.harnessDotfOut.map(BlackBoxResourceFileNameAnno(_)).toSeq ++ - harnessTop.map(ht => ModuleNameSuffixAnnotation(rootCircuitTarget, s"_in${ht}")) ++ - synTop.map(st => ConvertToExtModAnnotation(rootCircuitTarget.module(st))) :+ - LinkExtModulesAnnotation(topExtModules) + harnessTop.map(ht => ModuleNameSuffixAnnotation(rootCircuitTarget, s"_in${ht}")) ++ + synTop.map(st => ConvertToExtModAnnotation(rootCircuitTarget.module(st))) :+ + LinkExtModulesAnnotation(topExtModules) // For harness run, change some firrtlOptions (below) for harness phase // customTransforms: setup harness transforms, add AvoidExtModuleCollisions @@ -233,7 +253,7 @@ sealed trait GenerateTopAndHarnessApp extends LazyLogging { this: App => outputFileNameOverride = tapeoutOptions.harnessOutput.get, annotations = firrtlOptions.annotations.map({ case ReplSeqMemAnnotation(i, o) => ReplSeqMemAnnotation(i, tapeoutOptions.harnessConf.get) - case a => a + case a => a }) ++ harnessAnnos ) val harnessResult = firrtl.Driver.execute(optionsManager) diff --git a/tapeout/src/main/scala/transforms/ReParentCircuit.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/ReParentCircuit.scala similarity index 66% rename from tapeout/src/main/scala/transforms/ReParentCircuit.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/ReParentCircuit.scala index cbf4d2f8..10356176 100644 --- a/tapeout/src/main/scala/transforms/ReParentCircuit.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/ReParentCircuit.scala @@ -3,20 +3,18 @@ package barstools.tapeout.transforms import firrtl._ -import firrtl.ir._ import firrtl.annotations._ -import firrtl.options.{Dependency} -import firrtl.stage.TransformManager.{TransformDependency} -import firrtl.stage.{Forms} +import firrtl.options.Dependency +import firrtl.stage.Forms +import firrtl.stage.TransformManager.TransformDependency -case class ReParentCircuitAnnotation(target: ModuleTarget) - extends SingleTargetAnnotation[ModuleTarget] { +case class ReParentCircuitAnnotation(target: ModuleTarget) extends SingleTargetAnnotation[ModuleTarget] { def duplicate(n: ModuleTarget) = this.copy(n) } class ReParentCircuit extends Transform with DependencyAPIMigration { - override def prerequisites: Seq[TransformDependency] = Forms.HighForm + override def prerequisites: Seq[TransformDependency] = Forms.HighForm override def optionalPrerequisites: Seq[TransformDependency] = Seq.empty override def optionalPrerequisiteOf: Seq[TransformDependency] = { Forms.HighEmitters :+ Dependency[RemoveUnusedModules] @@ -25,8 +23,8 @@ class ReParentCircuit extends Transform with DependencyAPIMigration { def execute(state: CircuitState): CircuitState = { val c = state.circuit - val newTopName = state.annotations.collectFirst { - case ReParentCircuitAnnotation(tgt) => tgt.module + val newTopName = state.annotations.collectFirst { case ReParentCircuitAnnotation(tgt) => + tgt.module } val newCircuit = c.copy(main = newTopName.getOrElse(c.main)) val mainRename = newTopName.map { s => diff --git a/tapeout/src/main/scala/transforms/RemoveUnusedModules.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/RemoveUnusedModules.scala similarity index 72% rename from tapeout/src/main/scala/transforms/RemoveUnusedModules.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/RemoveUnusedModules.scala index 3feb6736..5d1cbc6c 100644 --- a/tapeout/src/main/scala/transforms/RemoveUnusedModules.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/RemoveUnusedModules.scala @@ -3,18 +3,18 @@ package barstools.tapeout.transforms import firrtl._ +import firrtl.annotations.ModuleTarget import firrtl.ir._ -import firrtl.annotations.{ModuleTarget} -import firrtl.stage.TransformManager.{TransformDependency} -import firrtl.options.{Dependency} -import firrtl.stage.{Forms} -import firrtl.passes.memlib.{ReplSeqMem} +import firrtl.options.Dependency +import firrtl.passes.memlib.ReplSeqMem +import firrtl.stage.Forms +import firrtl.stage.TransformManager.TransformDependency // Removes all the unused modules in a circuit by recursing through every // instance (starting at the main module) class RemoveUnusedModules extends Transform with DependencyAPIMigration { - override def prerequisites: Seq[TransformDependency] = Forms.HighForm + override def prerequisites: Seq[TransformDependency] = Forms.HighForm override def optionalPrerequisites: Seq[TransformDependency] = Seq.empty override def optionalPrerequisiteOf: Seq[TransformDependency] = { Forms.HighEmitters :+ Dependency[ReplSeqMem] @@ -22,8 +22,8 @@ class RemoveUnusedModules extends Transform with DependencyAPIMigration { override def invalidates(a: Transform): Boolean = false def execute(state: CircuitState): CircuitState = { - val modulesByName = state.circuit.modules.map{ - case m: Module => (m.name, Some(m)) + val modulesByName = state.circuit.modules.map { + case m: Module => (m.name, Some(m)) case m: ExtModule => (m.name, None) }.toMap @@ -33,7 +33,7 @@ class RemoveUnusedModules extends Transform with DependencyAPIMigration { def someStatements(statement: Statement): Seq[Statement] = statement match { case b: Block => - b.stmts.map{ someStatements(_) } + b.stmts.map { someStatements(_) } .foldLeft(Seq[Statement]())(_ ++ _) case when: Conditionally => someStatements(when.conseq) ++ someStatements(when.alt) @@ -41,11 +41,11 @@ class RemoveUnusedModules extends Transform with DependencyAPIMigration { case _ => Seq() } - someStatements(m.body).map{ - case s: DefInstance => Set(s.module) | getUsedModules(modulesByName(s.module)) - case _ => Set[String]() - }.foldLeft(Set(m.name))(_ | _) - } + someStatements(m.body).map { + case s: DefInstance => Set(s.module) | getUsedModules(modulesByName(s.module)) + case _ => Set[String]() + }.foldLeft(Set(m.name))(_ | _) + } case None => Set.empty[String] } @@ -57,7 +57,7 @@ class RemoveUnusedModules extends Transform with DependencyAPIMigration { val renames = state.renames.getOrElse(RenameMap()) - state.circuit.modules.filterNot { usedModuleSet contains _.name } foreach { x => + state.circuit.modules.filterNot { usedModuleSet contains _.name }.foreach { x => renames.record(ModuleTarget(state.circuit.main, x.name), Nil) } diff --git a/tapeout/src/main/scala/transforms/ResetInverter.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/ResetInverter.scala similarity index 86% rename from tapeout/src/main/scala/transforms/ResetInverter.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/ResetInverter.scala index 1ccb1888..33d2f78a 100644 --- a/tapeout/src/main/scala/transforms/ResetInverter.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/ResetInverter.scala @@ -20,10 +20,9 @@ object ResetN extends Pass { // Only works on Modules with a Bool port named reset def invertReset(mod: Module): Module = { // Check that it actually has reset - require(mod.ports.exists(p => p.name == "reset" && p.tpe == Bool), - "Can only invert reset on a module with reset!") + require(mod.ports.exists(p => p.name == "reset" && p.tpe == Bool), "Can only invert reset on a module with reset!") // Rename "reset" to "reset_n" - val portsx = mod.ports map { + val portsx = mod.ports.map { case Port(info, "reset", Input, Bool) => Port(info, "reset_n", Input, Bool) case other => other @@ -34,7 +33,7 @@ object ResetN extends Pass { } def run(c: Circuit): Circuit = { - c.copy(modules = c.modules map { + c.copy(modules = c.modules.map { case mod: Module if mod.name == c.main => invertReset(mod) case other => other }) @@ -43,8 +42,8 @@ object ResetN extends Pass { class ResetInverterTransform extends Transform with DependencyAPIMigration { - override def prerequisites: Seq[TransformDependency] = Forms.LowForm - override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized + override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters override def invalidates(a: Transform): Boolean = false @@ -64,7 +63,7 @@ trait ResetInverter { def invert[T <: chisel3.internal.LegacyModule](module: T): Unit = { chisel3.experimental.annotate(new chisel3.experimental.ChiselAnnotation with RunFirrtlTransform { def transformClass: Class[_ <: Transform] = classOf[ResetInverterTransform] - def toFirrtl: Annotation = ResetInverterAnnotation(module.toNamed) + def toFirrtl: Annotation = ResetInverterAnnotation(module.toNamed) }) } } diff --git a/tapeout/src/main/scala/transforms/retime/Retime.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/retime/Retime.scala similarity index 62% rename from tapeout/src/main/scala/transforms/retime/Retime.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/retime/Retime.scala index 010ef40b..931af88d 100644 --- a/tapeout/src/main/scala/transforms/retime/Retime.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/retime/Retime.scala @@ -14,23 +14,24 @@ case class RetimeAnnotation(target: Named) extends SingleTargetAnnotation[Named] class RetimeTransform extends Transform with DependencyAPIMigration { - override def prerequisites: Seq[TransformDependency] = Forms.LowForm - override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized + override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters override def invalidates(a: Transform): Boolean = false override def execute(state: CircuitState): CircuitState = { state.annotations.filter(_.isInstanceOf[RetimeAnnotation]) match { case Nil => state - case seq => seq.foreach { - case RetimeAnnotation(ModuleName(module, CircuitName(_))) => - logger.info(s"Retiming module $module") - case RetimeAnnotation(ComponentName(name, ModuleName(module, CircuitName(_)))) => - logger.info(s"Retiming instance $module.$name") - case _ => - throw new Exception(s"There should be RetimeAnnotations, got ${seq.mkString(" -- ")}") - } - state + case seq => + seq.foreach { + case RetimeAnnotation(ModuleName(module, CircuitName(_))) => + logger.info(s"Retiming module $module") + case RetimeAnnotation(ComponentName(name, ModuleName(module, CircuitName(_)))) => + logger.info(s"Retiming instance $module.$name") + case _ => + throw new Exception(s"There should be RetimeAnnotations, got ${seq.mkString(" -- ")}") + } + state } } } @@ -41,7 +42,7 @@ trait RetimeLib { def retime[T <: chisel3.internal.LegacyModule](module: T): Unit = { chisel3.experimental.annotate(new chisel3.experimental.ChiselAnnotation with RunFirrtlTransform { def transformClass: Class[_ <: Transform] = classOf[RetimeTransform] - def toFirrtl: Annotation = RetimeAnnotation(module.toNamed) + def toFirrtl: Annotation = RetimeAnnotation(module.toNamed) }) } } diff --git a/tapeout/src/main/scala/transforms/utils/FileUtils.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/utils/FileUtils.scala similarity index 78% rename from tapeout/src/main/scala/transforms/utils/FileUtils.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/utils/FileUtils.scala index ded0474d..86bf43de 100644 --- a/tapeout/src/main/scala/transforms/utils/FileUtils.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/utils/FileUtils.scala @@ -1,6 +1,6 @@ // See LICENSE for license details. -package barstools.tapeout.transforms +package barstools.tapeout.transforms.utils import chisel3.experimental.{ChiselAnnotation, annotate} import firrtl._ @@ -12,7 +12,7 @@ import firrtl.transforms.BlackBoxTargetDirAnno object WriteConfig { def apply(dir: String, file: String, contents: String): Unit = { val writer = new java.io.PrintWriter(new java.io.File(s"$dir/$file")) - writer write contents + writer.write(contents) writer.close() } } @@ -22,14 +22,14 @@ object GetTargetDir { val annos = state.annotations val destDir = annos.map { case BlackBoxTargetDirAnno(s) => Some(s) - case _ => None + case _ => None }.flatten val loc = { if (destDir.isEmpty) "." else destDir.head } val targetDir = new java.io.File(loc) - if(!targetDir.exists()) FileUtils.makeDirectory(targetDir.getAbsolutePath) + if (!targetDir.exists()) FileUtils.makeDirectory(targetDir.getAbsolutePath) loc } } @@ -53,8 +53,8 @@ case class TechnologyLocationAnnotation(dir: String) extends SingleTargetAnnotat class TechnologyLocation extends Transform with DependencyAPIMigration { - override def prerequisites: Seq[TransformDependency] = Forms.LowForm - override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized + override def prerequisites: Seq[TransformDependency] = Forms.LowForm + override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters def execute(state: CircuitState): CircuitState = { @@ -65,18 +65,15 @@ class TechnologyLocation extends Transform with DependencyAPIMigration { val annos = state.annotations val dir = annos.flatMap { case TechnologyLocationAnnotation(dir) => Some(dir) - case _ => None + case _ => None } dir.length match { case 0 => "" case 1 => val targetDir = new java.io.File(dir.head) - if(!targetDir.exists()) throw new Exception(s"Technology yaml directory $targetDir doesn't exist!") + if (!targetDir.exists()) throw new Exception(s"Technology yaml directory $targetDir doesn't exist!") dir.head case _ => throw new Exception("Only 1 tech directory annotation allowed!") } } } - - - diff --git a/tapeout/src/main/scala/transforms/utils/LowerAnnotations.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/utils/LowerAnnotations.scala similarity index 54% rename from tapeout/src/main/scala/transforms/utils/LowerAnnotations.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/utils/LowerAnnotations.scala index a11bfa19..45502d6d 100644 --- a/tapeout/src/main/scala/transforms/utils/LowerAnnotations.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/utils/LowerAnnotations.scala @@ -1,5 +1,5 @@ -package barstools.tapeout.transforms +package barstools.tapeout.transforms.utils object LowerName { - def apply(s: String): String = s.replace(".", "_").replace("[", "_")replace("]", "") -} \ No newline at end of file + def apply(s: String): String = s.replace(".", "_").replace("[", "_").replace("]", "") +} diff --git a/tapeout/src/main/scala/transforms/utils/ProgrammaticBundle.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/utils/ProgrammaticBundle.scala similarity index 72% rename from tapeout/src/main/scala/transforms/utils/ProgrammaticBundle.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/utils/ProgrammaticBundle.scala index d73d05db..66200e61 100644 --- a/tapeout/src/main/scala/transforms/utils/ProgrammaticBundle.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/utils/ProgrammaticBundle.scala @@ -1,20 +1,21 @@ -package barstools.tapeout.transforms +package barstools.tapeout.transforms.utils import chisel3._ + import scala.collection.immutable.ListMap class CustomBundle[T <: Data](elts: (String, T)*) extends Record { - val elements = ListMap(elts map { case (field, elt) => field -> chiselTypeOf(elt) }: _*) + val elements = ListMap(elts.map { case (field, elt) => field -> chiselTypeOf(elt) }: _*) def apply(elt: String): T = elements(elt) - def apply(elt: Int): T = elements(elt.toString) + def apply(elt: Int): T = elements(elt.toString) override def cloneType = (new CustomBundle(elements.toList: _*)).asInstanceOf[this.type] } class CustomIndexedBundle[T <: Data](elts: (Int, T)*) extends Record { // Must be String, Data - val elements = ListMap(elts map { case (field, elt) => field.toString -> chiselTypeOf(elt) }: _*) + val elements = ListMap(elts.map { case (field, elt) => field.toString -> chiselTypeOf(elt) }: _*) // TODO: Make an equivalent to the below work publicly (or only on subclasses?) - def indexedElements = ListMap(elts map { case (field, elt) => field -> chiselTypeOf(elt) }: _*) + def indexedElements = ListMap(elts.map { case (field, elt) => field -> chiselTypeOf(elt) }: _*) def apply(elt: Int): T = elements(elt.toString) override def cloneType = (new CustomIndexedBundle(indexedElements.toList: _*)).asInstanceOf[this.type] } @@ -22,5 +23,7 @@ class CustomIndexedBundle[T <: Data](elts: (Int, T)*) extends Record { object CustomIndexedBundle { def apply[T <: Data](gen: T, idxs: Seq[Int]) = new CustomIndexedBundle(idxs.map(_ -> gen): _*) // Allows Vecs of elements of different types/widths - def apply[T <: Data](gen: Seq[T]) = new CustomIndexedBundle(gen.zipWithIndex.map{ case (elt, field) => field -> elt }: _*) + def apply[T <: Data](gen: Seq[T]) = new CustomIndexedBundle(gen.zipWithIndex.map { case (elt, field) => + field -> elt + }: _*) } diff --git a/tapeout/src/main/scala/transforms/utils/YamlHelpers.scala b/tapeout/src/main/scala/barstools/tapeout/transforms/utils/YamlHelpers.scala similarity index 80% rename from tapeout/src/main/scala/transforms/utils/YamlHelpers.scala rename to tapeout/src/main/scala/barstools/tapeout/transforms/utils/YamlHelpers.scala index 6754136d..9a226de5 100644 --- a/tapeout/src/main/scala/transforms/utils/YamlHelpers.scala +++ b/tapeout/src/main/scala/barstools/tapeout/transforms/utils/YamlHelpers.scala @@ -1,21 +1,22 @@ -package barstools.tapeout.transforms +package barstools.tapeout.transforms.utils import net.jcazevedo.moultingyaml._ + import java.io.File class YamlFileReader(resource: String) { - def parse[A](file: String = "")(implicit reader: YamlReader[A]) : Seq[A] = { + def parse[A](file: String = "")(implicit reader: YamlReader[A]): Seq[A] = { // If the user doesn't provide a Yaml file name, use defaults val yamlString = file match { - case f if f.isEmpty => + case f if f.isEmpty => // Use example config if no file is provided val stream = getClass.getResourceAsStream(resource) io.Source.fromInputStream(stream).mkString - case f if new File(f).exists => + case f if new File(f).exists => scala.io.Source.fromFile(f).getLines.mkString("\n") - case _ => + case _ => throw new Exception("No valid Yaml file found!") } yamlString.parseYamls.map(x => reader.read(x)) } -} \ No newline at end of file +} diff --git a/tapeout/src/test/scala/transforms/ResetInverterSpec.scala b/tapeout/src/test/scala/barstools/tapeout/transforms/ResetInverterSpec.scala similarity index 63% rename from tapeout/src/test/scala/transforms/ResetInverterSpec.scala rename to tapeout/src/test/scala/barstools/tapeout/transforms/ResetInverterSpec.scala index 9f23c3a8..701c7845 100644 --- a/tapeout/src/test/scala/transforms/ResetInverterSpec.scala +++ b/tapeout/src/test/scala/barstools/tapeout/transforms/ResetInverterSpec.scala @@ -3,9 +3,10 @@ package barstools.tapeout.transforms import chisel3._ -import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} import firrtl.{EmittedFirrtlCircuitAnnotation, EmittedFirrtlModuleAnnotation} -import org.scalatest.{FreeSpec, Matchers} +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should.Matchers class ExampleModuleNeedsResetInverted extends Module with ResetInverter { val io = IO(new Bundle { @@ -19,7 +20,7 @@ class ExampleModuleNeedsResetInverted extends Module with ResetInverter { invert(this) } -class ResetNSpec extends FreeSpec with Matchers { +class ResetNSpec extends AnyFreeSpec with Matchers { "Inverting reset needs to be done throughout module in Chirrtl" in { val chirrtl = (new ChiselStage).emitChirrtl(new ExampleModuleNeedsResetInverted) chirrtl should include("input reset :") @@ -29,14 +30,17 @@ class ResetNSpec extends FreeSpec with Matchers { "Inverting reset needs to be done throughout module when generating firrtl" in { // generate low-firrtl - val firrtl = (new ChiselStage).execute( - Array("-X", "low"), - Seq(ChiselGeneratorAnnotation(() => new ExampleModuleNeedsResetInverted)) - ).collect { - case EmittedFirrtlCircuitAnnotation(a) => a - case EmittedFirrtlModuleAnnotation(a) => a - }.map(_.value) - .mkString("") + val firrtl = (new ChiselStage) + .execute( + Array("-X", "low"), + Seq(ChiselGeneratorAnnotation(() => new ExampleModuleNeedsResetInverted)) + ) + .collect { + case EmittedFirrtlCircuitAnnotation(a) => a + case EmittedFirrtlModuleAnnotation(a) => a + } + .map(_.value) + .mkString("") firrtl should include("input reset_n :") firrtl should include("node reset = not(reset_n)") diff --git a/tapeout/src/test/scala/transforms/retime/RetimeSpec.scala b/tapeout/src/test/scala/barstools/tapeout/transforms/retime/RetimeSpec.scala similarity index 67% rename from tapeout/src/test/scala/transforms/retime/RetimeSpec.scala rename to tapeout/src/test/scala/barstools/tapeout/transforms/retime/RetimeSpec.scala index 35678991..a086b0b9 100644 --- a/tapeout/src/test/scala/transforms/retime/RetimeSpec.scala +++ b/tapeout/src/test/scala/barstools/tapeout/transforms/retime/RetimeSpec.scala @@ -1,16 +1,15 @@ // See LICENSE for license details. -package barstools.tapeout.transforms.retime.test +package barstools.tapeout.transforms.retime import chisel3._ -import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} -import firrtl.{EmittedFirrtlCircuitAnnotation, EmittedFirrtlModuleAnnotation} -import barstools.tapeout.transforms.retime.RetimeLib -import firrtl.FileUtils +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import firrtl.{EmittedFirrtlCircuitAnnotation, EmittedFirrtlModuleAnnotation, FileUtils} import logger.Logger -import org.scalatest.{FlatSpec, Matchers} +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers -class RetimeSpec extends FlatSpec with Matchers { +class RetimeSpec extends AnyFlatSpec with Matchers { def normalized(s: String): String = { require(!s.contains("\n")) s.replaceAll("\\s+", " ").trim @@ -21,18 +20,20 @@ class RetimeSpec extends FlatSpec with Matchers { } def getLowFirrtl[T <: RawModule](gen: () => T, extraArgs: Array[String] = Array.empty): String = { // generate low firrtl - (new ChiselStage).execute( - Array("-X", "low") ++ extraArgs, - Seq(ChiselGeneratorAnnotation(gen)) - ).collect { - case EmittedFirrtlCircuitAnnotation(a) => a - case EmittedFirrtlModuleAnnotation(a) => a - }.map(_.value) - .mkString("") + (new ChiselStage) + .execute( + Array("-X", "low") ++ extraArgs, + Seq(ChiselGeneratorAnnotation(gen)) + ) + .collect { + case EmittedFirrtlCircuitAnnotation(a) => a + case EmittedFirrtlModuleAnnotation(a) => a + } + .map(_.value) + .mkString("") } - - behavior of "retime library" + behavior.of("retime library") it should "pass simple retime module annotation" in { val gen = () => new RetimeModule @@ -43,15 +44,18 @@ class RetimeSpec extends FlatSpec with Matchers { Logger.setOutput(captor.printStream) // generate low firrtl - val firrtl = getLowFirrtl(gen, - Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final", "--log-level", "info")) + val firrtl = getLowFirrtl( + gen, + Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final", "--log-level", "info") + ) firrtl.nonEmpty should be(true) //Make sure we got the RetimeTransform scheduled - captor.getOutputAsString should include ("barstools.tapeout.transforms.retime.RetimeTransform") + captor.getOutputAsString should include("barstools.tapeout.transforms.retime.RetimeTransform") } - val lines = FileUtils.getLines(s"test_run_dir/$dir/test_run_dir/$dir/final.anno.json") + val lines = FileUtils + .getLines(s"test_run_dir/$dir/test_run_dir/$dir/final.anno.json") .map(normalized) .mkString("\n") lines should include("barstools.tapeout.transforms.retime.RetimeAnnotation") @@ -67,15 +71,18 @@ class RetimeSpec extends FlatSpec with Matchers { Logger.setOutput(captor.printStream) // generate low firrtl - val firrtl = getLowFirrtl(gen, - Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final", "--log-level", "info")) + val firrtl = getLowFirrtl( + gen, + Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final", "--log-level", "info") + ) firrtl.nonEmpty should be(true) //Make sure we got the RetimeTransform scheduled - captor.getOutputAsString should include ("barstools.tapeout.transforms.retime.RetimeTransform") + captor.getOutputAsString should include("barstools.tapeout.transforms.retime.RetimeTransform") } - val lines = FileUtils.getLines(s"test_run_dir/$dir/test_run_dir/$dir/final.anno.json") + val lines = FileUtils + .getLines(s"test_run_dir/$dir/test_run_dir/$dir/final.anno.json") .map(normalized) .mkString("\n") lines should include("barstools.tapeout.transforms.retime.RetimeAnnotation")