Reformat all scala files in macros

- Mostly this reformat comments and large argument lists to classes and methods
This commit is contained in:
chick
2021-02-03 17:50:36 -08:00
parent 93f86a5bc6
commit 68c3425493
15 changed files with 1743 additions and 1204 deletions

View File

@@ -2,27 +2,25 @@
package barstools.macros package barstools.macros
/** /** Trait which can calculate the cost of compiling a memory against a certain
* Trait which can calculate the cost of compiling a memory against a certain * library memory macro using a cost function.
* library memory macro using a cost function. */
*/
// TODO: eventually explore compiling a single target memory using multiple // TODO: eventually explore compiling a single target memory using multiple
// different kinds of target memory. // different kinds of target memory.
trait CostMetric extends Serializable { trait CostMetric extends Serializable {
/**
* Cost function that returns the cost of compiling a memory using a certain /** Cost function that returns the cost of compiling a memory using a certain
* macro. * macro.
* *
* @param mem Memory macro to compile (target memory) * @param mem Memory macro to compile (target memory)
* @param lib Library memory macro to use (library memory) * @param lib Library memory macro to use (library memory)
* @return The cost of this compile, defined by this cost metric, or None if * @return The cost of this compile, defined by this cost metric, or None if
* it cannot be compiled. * it cannot be compiled.
*/ */
def cost(mem: Macro, lib: Macro): Option[Double] 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] def commandLineParams(): Map[String, String]
// We also want this to show up for the class itself. // We also want this to show up for the class itself.
@@ -40,8 +38,9 @@ trait CostMetricCompanion {
// Some default cost functions. // Some default cost functions.
/** Palmer's old metric. /** Palmer's old metric.
* TODO: figure out what is the difference between this metric and the current * TODO: figure out what is the difference between this metric and the current
* default metric and either revive or delete this metric. */ * default metric and either revive or delete this metric.
*/
object OldMetric extends CostMetric with CostMetricCompanion { object OldMetric extends CostMetric with CostMetricCompanion {
override def cost(mem: Macro, lib: Macro): Option[Double] = { override def cost(mem: Macro, lib: Macro): Option[Double] = {
/* Palmer: A quick cost function (that must be kept in sync with /* Palmer: A quick cost function (that must be kept in sync with
@@ -58,13 +57,12 @@ object OldMetric extends CostMetric with CostMetricCompanion {
override def construct(m: Map[String, String]) = OldMetric override def construct(m: Map[String, String]) = OldMetric
} }
/** /** An external cost function.
* An external cost function. * Calls the specified path with paths to the JSON MDF representation of the mem
* Calls the specified path with paths to the JSON MDF representation of the mem * and lib macros. The external executable should print a Double.
* and lib macros. The external executable should print a Double. * None will be returned if the external executable does not print a valid
* None will be returned if the external executable does not print a valid * Double.
* Double. */
*/
class ExternalMetric(path: String) extends CostMetric { class ExternalMetric(path: String) extends CostMetric {
import mdf.macrolib.Utils.writeMacroToPath import mdf.macrolib.Utils.writeMacroToPath
@@ -105,7 +103,7 @@ object ExternalMetric extends CostMetricCompanion {
override def construct(m: Map[String, String]) = { override def construct(m: Map[String, String]) = {
val pathOption = m.get("path") val pathOption = m.get("path")
pathOption match { pathOption match {
case Some(path:String) => new ExternalMetric(path) case Some(path: String) => new ExternalMetric(path)
case _ => throw new IllegalArgumentException("ExternalMetric missing option 'path'") case _ => throw new IllegalArgumentException("ExternalMetric missing option 'path'")
} }
} }
@@ -115,14 +113,17 @@ object ExternalMetric extends CostMetricCompanion {
// TODO: write tests for this function to make sure it selects the right things // TODO: write tests for this function to make sure it selects the right things
object DefaultMetric extends CostMetric with CostMetricCompanion { object DefaultMetric extends CostMetric with CostMetricCompanion {
override def cost(mem: Macro, lib: Macro): Option[Double] = { override def cost(mem: Macro, lib: Macro): Option[Double] = {
val memMask = mem.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 libMask = lib.src.ports.map(_.maskGran).find(_.isDefined).map(_.get)
val memWidth = (memMask, libMask) match { val memWidth = (memMask, libMask) match {
case (None, _) => mem.src.width 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)) => { 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) 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 else (mem.src.width / p) * m //Waste the extra maskbits
} }
} }
val depthCost = math.ceil(mem.src.depth.toDouble / lib.src.depth.toDouble) val depthCost = math.ceil(mem.src.depth.toDouble / lib.src.depth.toDouble)
@@ -130,10 +131,10 @@ object DefaultMetric extends CostMetric with CostMetricCompanion {
val bitsCost = (lib.src.depth * lib.src.width).toDouble val bitsCost = (lib.src.depth * lib.src.width).toDouble
// Fraction of wasted bits plus const per mem // Fraction of wasted bits plus const per mem
val requestedBits = (mem.src.depth * mem.src.width).toDouble 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 wastedConst = 0.05 // 0 means waste as few bits with no regard for instance count
val costPerInst = wastedConst*depthCost*widthCost val costPerInst = wastedConst * depthCost * widthCost
Some(1.0*bitsWasted/requestedBits+costPerInst) Some(1.0 * bitsWasted / requestedBits + costPerInst)
} }
override def commandLineParams = Map() override def commandLineParams = Map()
@@ -148,10 +149,11 @@ object MacroCompilerUtil {
// Adapted from https://stackoverflow.com/a/134918 // Adapted from https://stackoverflow.com/a/134918
/** Serialize an arbitrary object to String. /** 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 = { def objToString(o: Serializable): String = {
val baos: ByteArrayOutputStream = new ByteArrayOutputStream val baos: ByteArrayOutputStream = new ByteArrayOutputStream
val oos: ObjectOutputStream = new ObjectOutputStream(baos) val oos: ObjectOutputStream = new ObjectOutputStream(baos)
oos.writeObject(o) oos.writeObject(o)
oos.close() oos.close()
return Base64.getEncoder.encodeToString(baos.toByteArray) return Base64.getEncoder.encodeToString(baos.toByteArray)
@@ -168,6 +170,7 @@ object MacroCompilerUtil {
} }
object CostMetric { object CostMetric {
/** Define some default metric. */ /** Define some default metric. */
val default: CostMetric = DefaultMetric val default: CostMetric = DefaultMetric
@@ -178,11 +181,10 @@ object CostMetric {
registerCostMetric(ExternalMetric) registerCostMetric(ExternalMetric)
registerCostMetric(DefaultMetric) registerCostMetric(DefaultMetric)
/** /** Register a cost metric.
* Register a cost metric. * @param createFuncHelper Companion object to fetch the name and construct
* @param createFuncHelper Companion object to fetch the name and construct * the metric.
* the metric. */
*/
def registerCostMetric(createFuncHelper: CostMetricCompanion): Unit = { def registerCostMetric(createFuncHelper: CostMetricCompanion): Unit = {
costMetricCreators.update(createFuncHelper.name, createFuncHelper) costMetricCreators.update(createFuncHelper.name, createFuncHelper)
} }

View File

@@ -1,10 +1,9 @@
// See LICENSE for license details. // See LICENSE for license details.
/** /** Terminology note:
* Terminology note: * mem - target memory to compile, in design (e.g. Mem() in rocket)
* mem - target memory to compile, in design (e.g. Mem() in rocket) * lib - technology SRAM(s) to use to compile mem
* lib - technology SRAM(s) to use to compile mem */
*/
package barstools.macros package barstools.macros
@@ -29,56 +28,75 @@ case class MacroCompilerAnnotation(content: String) extends NoTargetAnnotation {
def params: Params = MacroCompilerUtil.objFromString(content).asInstanceOf[Params] 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
* The MacroCompilerAnnotation to trigger the macro compiler. * compilation. It simply holds all the settings for the memory compiler. The
* Note that this annotation does NOT actually target any modules for * actual selection of which memories to compile is set in the Params.
* 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]].
* To use, simply annotate the entire circuit itself with this annotation and */
* include [[MacroCompilerTransform]].
*
*/
object MacroCompilerAnnotation { object MacroCompilerAnnotation {
/** Macro compiler mode. */ /** Macro compiler mode. */
sealed trait CompilerMode sealed trait CompilerMode
/** Strict mode - must compile all memories or error out. */ /** Strict mode - must compile all memories or error out. */
case object Strict extends CompilerMode case object Strict extends CompilerMode
/** Synflops mode - compile all memories with synflops (do not map to lib at all). */ /** Synflops mode - compile all memories with synflops (do not map to lib at all). */
case object Synflops extends CompilerMode case object Synflops extends CompilerMode
/** CompileAndSynflops mode - compile all memories and create mock versions of the target libs with synflops. */ /** CompileAndSynflops mode - compile all memories and create mock versions of the target libs with synflops. */
case object CompileAndSynflops extends CompilerMode 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 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 case object CompileAvailable extends CompilerMode
/** /** The default mode for the macro compiler.
* The default mode for the macro compiler. * TODO: Maybe set the default to FallbackSynflops (typical for
* TODO: Maybe set the default to FallbackSynflops (typical for * vlsi_mem_gen-like scripts) once it's implemented?
* vlsi_mem_gen-like scripts) once it's implemented? */
*/
val Default = CompileAvailable val Default = CompileAvailable
// Options as list of (CompilerMode, command-line name, description) // Options as list of (CompilerMode, command-line name, description)
val options: Seq[(CompilerMode, String, String)] = Seq( val options: Seq[(CompilerMode, String, String)] = Seq(
(Default, "default", "Select the default option from below."), (Default, "default", "Select the default option from below."),
(Strict, "strict", "Compile all memories to library or return an error."), (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."), Synflops,
(FallbackSynflops, "fallbacksynflops", "Compile all memories to library when possible and fall back to synthesizable flop-based memories when library synth is not possible."), "synflops",
(CompileAvailable, "compileavailable", "Compile all memories to library when possible and do nothing in case of errors. (default)") "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. */ /** 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 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 mem Path to memory lib
* @param memFormat Type of memory lib (Some("conf"), Some("mdf"), or None (defaults to mdf)) * @param memFormat Type of memory lib (Some("conf"), Some("mdf"), or None (defaults to mdf))
@@ -89,26 +107,34 @@ object MacroCompilerAnnotation {
* @param forceCompile Set of memories to force compiling to lib regardless of the mode * @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 * @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], case class Params(
costMetric: CostMetric, mode: CompilerMode, useCompiler: Boolean, mem: String,
forceCompile: Set[String], forceSynflops: Set[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.
* Create a MacroCompilerAnnotation. * @param c Top-level circuit name (see class description)
* @param c Top-level circuit name (see class description) * @param p Parameters (see above).
* @param p Parameters (see above). */
*/
def apply(c: String, p: Params): MacroCompilerAnnotation = def apply(c: String, p: Params): MacroCompilerAnnotation =
MacroCompilerAnnotation(MacroCompilerUtil.objToString(p)) MacroCompilerAnnotation(MacroCompilerUtil.objToString(p))
} }
class MacroCompilerPass(mems: Option[Seq[Macro]], class MacroCompilerPass(
libs: Option[Seq[Macro]], mems: Option[Seq[Macro]],
compilers: Option[SRAMCompiler], libs: Option[Seq[Macro]],
hammerIR: Option[String], compilers: Option[SRAMCompiler],
costMetric: CostMetric = CostMetric.default, hammerIR: Option[String],
mode: MacroCompilerAnnotation.CompilerMode = MacroCompilerAnnotation.Default) extends firrtl.passes.Pass { costMetric: CostMetric = CostMetric.default,
mode: MacroCompilerAnnotation.CompilerMode = MacroCompilerAnnotation.Default)
extends firrtl.passes.Pass {
// Helper function to check the legality of bitPairs. // Helper function to check the legality of bitPairs.
// e.g. ((0,21), (22,43)) is legal // e.g. ((0,21), (22,43)) is legal
// ((0,21), (22,21)) is illegal and will throw an assert // ((0,21), (22,21)) is illegal and will throw an assert
@@ -120,8 +146,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
}) })
} }
/** /** Calculate bit pairs.
* Calculate bit pairs.
* This is a list of submemories by width. * This is a list of submemories by width.
* The tuples are (lsb, msb) inclusive. * 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. * Example: (0, 7) and (8, 15) might be a split for a width=16 memory into two width=8 target memories.
@@ -132,7 +157,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
* @return Bit pairs or empty list if there was an error. * @return Bit pairs or empty list if there was an error.
*/ */
private def calculateBitPairs(mem: Macro, lib: Macro): Seq[(BigInt, BigInt)] = { 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)]() val bitPairs = ArrayBuffer[(BigInt, BigInt)]()
var currentLSB: BigInt = 0 var currentLSB: BigInt = 0
@@ -203,7 +228,9 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
splitMemory(memMask.get) splitMemory(memMask.get)
} else { } else {
// e.g. mem mask = 13, lib width = 8 // 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() return Seq()
} }
} }
@@ -266,9 +293,11 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
} }
def compile(mem: Macro, lib: Macro): Option[(Module, Macro)] = { def compile(mem: Macro, lib: Macro): Option[(Module, Macro)] = {
assert(mem.sortedPorts.lengthCompare(lib.sortedPorts.length) == 0, assert(
"mem and lib should have an equal number of ports") mem.sortedPorts.lengthCompare(lib.sortedPorts.length) == 0,
val pairedPorts = mem.sortedPorts zip lib.sortedPorts "mem and lib should have an equal number of ports"
)
val pairedPorts = mem.sortedPorts.zip(lib.sortedPorts)
// Width mapping. See calculateBitPairs. // Width mapping. See calculateBitPairs.
val bitPairs: Seq[(BigInt, BigInt)] = calculateBitPairs(mem, lib) val bitPairs: Seq[(BigInt, BigInt)] = calculateBitPairs(mem, lib)
@@ -287,14 +316,14 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
/* Palmer: If we've got a parallel memory then we've got to take the /* Palmer: If we've got a parallel memory then we've got to take the
* address bits into account. */ * address bits into account. */
if (mem.src.depth > lib.src.depth) { 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 high = MacroCompilerMath.ceilLog2(mem.src.depth)
val low = MacroCompilerMath.ceilLog2(lib.src.depth) val low = MacroCompilerMath.ceilLog2(lib.src.depth)
val ref = WRef(port.address.name) val ref = WRef(port.address.name)
val nodeName = s"${ref.name}_sel" val nodeName = s"${ref.name}_sel"
val tpe = UIntType(IntWidth(high-low)) val tpe = UIntType(IntWidth(high - low))
selects(ref.name) = WRef(nodeName, tpe) 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 // Donggyu: output selection should be piped
if (port.output.isDefined) { if (port.output.isDefined) {
val regName = s"${ref.name}_sel_reg" val regName = s"${ref.name}_sel_reg"
@@ -303,7 +332,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
and(WRef(ce.name, BoolType), WRef(re.name, BoolType)) and(WRef(ce.name, BoolType), WRef(re.name, BoolType))
case (Some(ce), None) => WRef(ce.name, BoolType) case (Some(ce), None) => WRef(ce.name, BoolType)
case (None, Some(re)) => WRef(re.name, BoolType) case (None, Some(re)) => WRef(re.name, BoolType)
case (None, None) => one case (None, None) => one
} }
selectRegs(ref.name) = WRef(regName, tpe) selectRegs(ref.name) = WRef(regName, tpe)
stmts += DefRegister(NoInfo, regName, tpe, WRef(port.clock.get.name), zero, WRef(regName)) stmts += DefRegister(NoInfo, regName, tpe, WRef(port.clock.get.name), zero, WRef(regName))
@@ -317,18 +346,18 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
// Create the instance. // Create the instance.
stmts += WDefInstance(NoInfo, name, lib.src.name, lib.tpe) stmts += WDefInstance(NoInfo, name, lib.src.name, lib.tpe)
// Connect extra ports of the lib. // 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) Connect(NoInfo, WSubField(WRef(name), portName), portValue)
} }
} }
for ((memPort, libPort) <- pairedPorts) { 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 None => one
case Some(addr) => case Some(addr) =>
val index = UIntLiteral(i, IntWidth(bitWidth(addr.tpe))) val index = UIntLiteral(i, IntWidth(bitWidth(addr.tpe)))
DoPrim(PrimOps.Eq, Seq(addr, index), Nil, index.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 None => one
case Some(reg) => case Some(reg) =>
val index = UIntLiteral(i, IntWidth(bitWidth(reg.tpe))) val index = UIntLiteral(i, IntWidth(bitWidth(reg.tpe)))
@@ -341,29 +370,22 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
for (((low, high), j) <- bitPairs.zipWithIndex) { for (((low, high), j) <- bitPairs.zipWithIndex) {
val inst = WRef(s"mem_${i}_${j}", lib.tpe) val inst = WRef(s"mem_${i}_${j}", lib.tpe)
def connectPorts2(mem: Expression, def connectPorts2(mem: Expression, lib: String, polarity: Option[PortPolarity]): Statement =
lib: String,
polarity: Option[PortPolarity]): Statement =
Connect(NoInfo, WSubField(inst, lib), portToExpression(mem, polarity)) Connect(NoInfo, WSubField(inst, lib), portToExpression(mem, polarity))
def connectPorts(mem: Expression, def connectPorts(mem: Expression, lib: String, polarity: PortPolarity): Statement =
lib: String,
polarity: PortPolarity): Statement =
connectPorts2(mem, lib, Some(polarity)) connectPorts2(mem, lib, Some(polarity))
// Clock port mapping // Clock port mapping
/* Palmer: FIXME: I don't handle memories with read/write clocks yet. */ /* Palmer: FIXME: I don't handle memories with read/write clocks yet. */
/* Colin not all libPorts have clocks but all memPorts do*/ /* Colin not all libPorts have clocks but all memPorts do*/
libPort.src.clock.foreach { cPort => libPort.src.clock.foreach { cPort =>
stmts += connectPorts(WRef(memPort.src.clock.get.name), stmts += connectPorts(WRef(memPort.src.clock.get.name), cPort.name, cPort.polarity)
cPort.name, }
cPort.polarity) }
// Adress port mapping // Adress port mapping
/* Palmer: The address port to a memory is just the low-order bits of /* Palmer: The address port to a memory is just the low-order bits of
* the top address. */ * the top address. */
stmts += connectPorts(WRef(memPort.src.address.name), stmts += connectPorts(WRef(memPort.src.address.name), libPort.src.address.name, libPort.src.address.polarity)
libPort.src.address.name,
libPort.src.address.polarity)
// Output port mapping // Output port mapping
(memPort.src.output, libPort.src.output) match { (memPort.src.output, libPort.src.output) match {
@@ -373,20 +395,20 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
* done after generating all the memories. This saves up the * done after generating all the memories. This saves up the
* output statements for later. */ * output statements for later. */
val name = s"${mem}_${i}_${j}" // This name is the output from the instance (mem vs ${mem}). 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) stmts += DefNode(NoInfo, name, exp)
cats += WRef(name) cats += WRef(name)
case (None, Some(lib)) => case (None, Some(lib)) =>
/* Palmer: If the inner memory has an output port but the outer /* Palmer: If the inner memory has an output port but the outer
* one doesn't then it's safe to just leave the outer * one doesn't then it's safe to just leave the outer
* port floating. */ * port floating. */
case (None, None) => case (None, None) =>
/* Palmer: If there's no output ports at all (ie, read-only /* Palmer: If there's no output ports at all (ie, read-only
* port on the memory) then just don't worry about it, * port on the memory) then just don't worry about it,
* there's nothing to do. */ * there's nothing to do. */
case (Some(PolarizedPort(mem, _)), None) => case (Some(PolarizedPort(mem, _)), None) =>
System.err println "WARNING: Unable to match output ports on memory" System.err.println("WARNING: Unable to match output ports on memory")
System.err println s" outer output port: ${mem}" System.err.println(s" outer output port: ${mem}")
return None return None
} }
@@ -396,7 +418,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
/* Palmer: The input port to a memory just needs to happen in parallel, /* Palmer: The input port to a memory just needs to happen in parallel,
* this does a part select to narrow the memory down. */ * this does a part select to narrow the memory down. */
stmts += connectPorts(bits(WRef(mem), high, low), lib, lib_polarity) 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 /* Palmer: If the inner memory has an input port but the other
* one doesn't then it's safe to just leave the inner * one doesn't then it's safe to just leave the inner
* port floating. This should be handled by the * port floating. This should be handled by the
@@ -405,12 +427,12 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
//Firrtl cares about dangling inputs now tie it off //Firrtl cares about dangling inputs now tie it off
stmts += IsInvalid(NoInfo, WSubField(inst, lib.name)) stmts += IsInvalid(NoInfo, WSubField(inst, lib.name))
case (None, None) => case (None, None) =>
/* Palmer: If there's no input ports at all (ie, read-only /* Palmer: If there's no input ports at all (ie, read-only
* port on the memory) then just don't worry about it, * port on the memory) then just don't worry about it,
* there's nothing to do. */ * there's nothing to do. */
case (Some(PolarizedPort(mem, _)), None) => case (Some(PolarizedPort(mem, _)), None) =>
System.err println "WARNING: Unable to match input ports on memory" System.err.println("WARNING: Unable to match input ports on memory")
System.err println s" outer input port: ${mem}" System.err.println(s" outer input port: ${mem}")
return None return None
} }
@@ -429,26 +451,33 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
// Example: if we have a lib whose maskGran is 8 but our mem's maskGran is 4. // 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. // The other case is if we're using a larger lib than mem.
val usingLessThanLibMaskGran = (memPort.src.maskGran.get < libPort.src.effectiveMaskGran) val usingLessThanLibMaskGran = (memPort.src.maskGran.get < libPort.src.effectiveMaskGran)
val effectiveLibWidth = if (usingLessThanLibMaskGran) val effectiveLibWidth =
memPort.src.maskGran.get if (usingLessThanLibMaskGran)
else memPort.src.maskGran.get
libPort.src.width.get else
libPort.src.width.get
cat(((0 until libPort.src.width.get by libPort.src.effectiveMaskGran) map (i => { cat(
if (usingLessThanLibMaskGran && i >= effectiveLibWidth) { (
// If the memMaskGran is smaller than the lib's gran, then (0 until libPort.src.width.get by libPort.src.effectiveMaskGran)
// zero out the upper bits. .map(i => {
zero if (usingLessThanLibMaskGran && i >= effectiveLibWidth) {
} else { // If the memMaskGran is smaller than the lib's gran, then
if ((low + i) >= memPort.src.width.get) { // zero out the upper bits.
// If our bit is larger than the whole width of the mem, just zero out the upper bits. zero
zero } else {
} else { if ((low + i) >= memPort.src.width.get) {
// Pick the appropriate bit from the mem mask. // If our bit is larger than the whole width of the mem, just zero out the upper bits.
bits(WRef(mem), (low + i) / memPort.src.effectiveMaskGran) zero
} } else {
} // Pick the appropriate bit from the mem mask.
})).reverse) bits(WRef(mem), (low + i) / memPort.src.effectiveMaskGran)
}
}
})
)
.reverse
)
} }
case None => case None =>
/* If there is a lib mask port but no mem mask port, just turn on /* If there is a lib mask port but no mem mask port, just turn on
@@ -482,7 +511,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
// Chip enable port mapping // Chip enable port mapping
val memChipEnable = memPort.src.chipEnable match { val memChipEnable = memPort.src.chipEnable match {
case Some(PolarizedPort(mem, _)) => WRef(mem) case Some(PolarizedPort(mem, _)) => WRef(mem)
case None => one case None => one
} }
// Read enable port mapping // Read enable port mapping
@@ -501,7 +530,11 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
* implement the outer memory's collection of ports using what * implement the outer memory's collection of ports using what
* the inner memory has availiable. */ * the inner memory has availiable. */
((libPort.src.maskPort, libPort.src.writeEnable, libPort.src.chipEnable): @unchecked) match { ((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. */ /* Palmer: This is the simple option: every port exists. */
stmts += connectPorts(memMask, mask, mask_polarity) stmts += connectPorts(memMask, mask, mask_polarity)
stmts += connectPorts(andAddrMatch(memWriteEnable), we, we_polarity) stmts += connectPorts(andAddrMatch(memWriteEnable), we, we_polarity)
@@ -509,8 +542,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
case (Some(PolarizedPort(mask, mask_polarity)), Some(PolarizedPort(we, we_polarity)), None) => 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. */ /* Palmer: If we don't have a chip enable but do have mask ports. */
stmts += connectPorts(memMask, mask, mask_polarity) stmts += connectPorts(memMask, mask, mask_polarity)
stmts += connectPorts(andAddrMatch(and(memWriteEnable, memChipEnable)), stmts += connectPorts(andAddrMatch(and(memWriteEnable, memChipEnable)), we, we_polarity)
we, we_polarity)
case (None, Some(PolarizedPort(we, we_polarity)), chipEnable) => case (None, Some(PolarizedPort(we, we_polarity)), chipEnable) =>
if (bitWidth(memMask.tpe) == 1) { if (bitWidth(memMask.tpe) == 1) {
/* Palmer: If we're expected to provide mask ports without a /* Palmer: If we're expected to provide mask ports without a
@@ -518,13 +550,15 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
* write enable port instead of the mask port. */ * write enable port instead of the mask port. */
chipEnable match { chipEnable match {
case Some(PolarizedPort(en, en_polarity)) => { case Some(PolarizedPort(en, en_polarity)) => {
stmts += connectPorts(andAddrMatch(and(memWriteEnable, memMask)), stmts += connectPorts(andAddrMatch(and(memWriteEnable, memMask)), we, we_polarity)
we, we_polarity)
stmts += connectPorts(andAddrMatch(memChipEnable), en, en_polarity) stmts += connectPorts(andAddrMatch(memChipEnable), en, en_polarity)
} }
case _ => { case _ => {
stmts += connectPorts(andAddrMatch(and(and(memWriteEnable, memChipEnable), memMask)), stmts += connectPorts(
we, we_polarity) andAddrMatch(and(and(memWriteEnable, memChipEnable), memMask)),
we,
we_polarity
)
} }
} }
} else { } else {
@@ -532,8 +566,8 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
return None return None
} }
case (None, None, None) => case (None, None, None) =>
// No write ports to match up (this may be a read-only port). // No write ports to match up (this may be a read-only port).
// This isn't necessarily an error condition. // This isn't necessarily an error condition.
} }
} }
// Cat macro outputs for selection // Cat macro outputs for selection
@@ -541,7 +575,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
case Some(PolarizedPort(mem, _)) if cats.nonEmpty => case Some(PolarizedPort(mem, _)) if cats.nonEmpty =>
val name = s"${mem}_${i}" val name = s"${mem}_${i}"
stmts += DefNode(NoInfo, name, cat(cats.toSeq.reverse)) stmts += DefNode(NoInfo, name, cat(cats.toSeq.reverse))
(outputs getOrElseUpdate (mem, ArrayBuffer[(Expression, Expression)]())) += (outputs.getOrElseUpdate(mem, ArrayBuffer[(Expression, Expression)]())) +=
(addrMatchReg -> WRef(name)) (addrMatchReg -> WRef(name))
case _ => case _ =>
} }
@@ -549,15 +583,17 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
} }
// Connect mem outputs // Connect mem outputs
val zeroOutputValue: Expression = UIntLiteral(0, IntWidth(mem.src.width)) val zeroOutputValue: Expression = UIntLiteral(0, IntWidth(mem.src.width))
mem.src.ports foreach { port => mem.src.ports.foreach { port =>
port.output match { port.output match {
case Some(PolarizedPort(mem, _)) => outputs get mem match { case Some(PolarizedPort(mem, _)) =>
case Some(select) => outputs.get(mem) match {
val output = (select foldRight (zeroOutputValue)) { case Some(select) =>
case ((cond, tval), fval) => Mux(cond, tval, fval, fval.tpe) } val output = (select.foldRight(zeroOutputValue)) { case ((cond, tval), fval) =>
stmts += Connect(NoInfo, WRef(mem), output) Mux(cond, tval, fval, fval.tpe)
case None => }
} stmts += Connect(NoInfo, WRef(mem), output)
case None =>
}
case None => case None =>
} }
} }
@@ -572,79 +608,84 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
// Try to compile each of the memories in mems. // Try to compile each of the memories in mems.
// The 'state' is c.modules, which is a list of all the firrtl modules // The 'state' is c.modules, which is a list of all the firrtl modules
// in the 'circuit'. // in the 'circuit'.
(mems foldLeft c.modules){ (modules, mem) => (mems.foldLeft(c.modules)) { (modules, mem) =>
val sram = mem.src
val sram = mem.src def groupMatchesMask(group: SRAMGroup, mem: SRAMMacro): Boolean = {
def groupMatchesMask(group: SRAMGroup, mem:SRAMMacro): Boolean = { val memMask = mem.ports.map(_.maskGran).find(_.isDefined).map(_.get)
val memMask = mem.ports map (_.maskGran) find (_.isDefined) map (_.get) val libMask = group.ports.map(_.maskGran).find(_.isDefined).map(_.get)
val libMask = group.ports map (_.maskGran) find (_.isDefined) map (_.get) (memMask, libMask) match {
(memMask, libMask) match { case (None, _) => true
case (None, _) => true case (Some(_), None) => false
case (Some(_), None) => false case (Some(m), Some(l)) => l <= m //Ignore memories that don't have nice mask
case (Some(m), Some(l)) => l <= m //Ignore memories that don't have nice mask }
} }
} // Add compiler memories that might map well to libs
// Add compiler memories that might map well to libs val compLibs = compilers match {
val compLibs = compilers match { case Some(SRAMCompiler(_, groups)) => {
case Some(SRAMCompiler(_, groups)) => { groups
groups.filter(g => g.family == sram.family && groupMatchesMask(g, sram)).map( g => { .filter(g => g.family == sram.family && groupMatchesMask(g, sram))
for(w <- g.width; d <- g.depth if((sram.width % w == 0) && (sram.depth % d == 0))) .map(g => {
yield Seq(new Macro(buildSRAMMacro(g, d, w, g.vt.head))) 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
}
val fullLibs = libs ++ compLibs.flatten.flatten
// Try to compile mem against each lib in libs, keeping track of the // Try to compile mem against each lib in libs, keeping track of the
// best compiled version, external lib used, and cost. // best compiled version, external lib used, and cost.
val (best, cost) = (fullLibs foldLeft (None: Option[(Module, Macro)], Double.MaxValue)){ val (best, cost) = (fullLibs.foldLeft(None: Option[(Module, Macro)], Double.MaxValue)) {
case ((best, cost), lib) if mem.src.ports.size != lib.src.ports.size => 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 /* Palmer: FIXME: This just assumes the Chisel and vendor ports are in the same
* order, but I'm starting with what actually gets generated. */ * 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" System.err.println(s"INFO: unable to compile ${mem.src.name} using ${lib.src.name} port count must match")
(best, cost) (best, cost)
case ((best, cost), lib) => case ((best, cost), lib) =>
// Run the cost function to evaluate this potential compile. // Run the cost function to evaluate this potential compile.
costMetric.cost(mem, lib) match { costMetric.cost(mem, lib) match {
case Some(newCost) => { case Some(newCost) => {
//System.err.println(s"Cost of ${lib.src.name} for ${mem.src.name}: ${newCost}") //System.err.println(s"Cost of ${lib.src.name} for ${mem.src.name}: ${newCost}")
// Try compiling // Try compiling
compile(mem, lib) match { compile(mem, lib) match {
// If it was successful and the new cost is lower // If it was successful and the new cost is lower
case Some(p) if (newCost < cost) => (Some(p), newCost) case Some(p) if (newCost < cost) => (Some(p), newCost)
case _ => (best, cost) 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 { // If we were able to compile anything, then replace the original module
case Some(f) => { // in the modules list with a compiled version, as well as the extmodule
val hammerIRWriter = new FileWriter(new File(f), !firstLib) // stub for the lib.
if(firstLib) hammerIRWriter.write("[\n") best match {
hammerIRWriter.write(bb.src.toJSON().toString()) case None => {
hammerIRWriter.write("\n,\n") if (mode == MacroCompilerAnnotation.Strict)
hammerIRWriter.close() throw new MacroCompilerException(
firstLib = false s"Target memory ${mem.src.name} could not be compiled and strict mode is activated - aborting."
} )
case None => 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 case _ => c.modules
} }
c.copy(modules = modules) c.copy(modules = modules)
@@ -657,38 +698,46 @@ class MacroCompilerTransform extends Transform {
def execute(state: CircuitState) = state.annotations.collect { case a: MacroCompilerAnnotation => a } match { def execute(state: CircuitState) = state.annotations.collect { case a: MacroCompilerAnnotation => a } match {
case Seq(anno: MacroCompilerAnnotation) => 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) { if (mode == MacroCompilerAnnotation.FallbackSynflops) {
throw new UnsupportedOperationException("Not implemented yet") throw new UnsupportedOperationException("Not implemented yet")
} }
// Check that we don't have any modules both forced to compile and synflops. // 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 // Read, eliminate None, get only SRAM, make firrtl macro
val mems: Option[Seq[Macro]] = (memFileFormat match { val mems: Option[Seq[Macro]] = (memFileFormat match {
case Some("conf") => Utils.readConfFromPath(Some(memFile)) case Some("conf") => Utils.readConfFromPath(Some(memFile))
case _ => mdf.macrolib.Utils.readMDFFromPath(Some(memFile)) case _ => mdf.macrolib.Utils.readMDFFromPath(Some(memFile))
}) match { }) match {
case Some(x:Seq[mdf.macrolib.Macro]) => case Some(x: Seq[mdf.macrolib.Macro]) =>
Some(Utils.filterForSRAM(Some(x)) getOrElse(List()) map {new Macro(_)}) Some(Utils.filterForSRAM(Some(x)).getOrElse(List()).map { new Macro(_) })
case _ => None case _ => None
} }
val libs: Option[Seq[Macro]] = mdf.macrolib.Utils.readMDFFromPath(libFile) match { val libs: Option[Seq[Macro]] = mdf.macrolib.Utils.readMDFFromPath(libFile) match {
case Some(x:Seq[mdf.macrolib.Macro]) => case Some(x: Seq[mdf.macrolib.Macro]) =>
Some(Utils.filterForSRAM(Some(x)) getOrElse(List()) map {new Macro(_)}) Some(Utils.filterForSRAM(Some(x)).getOrElse(List()).map { new Macro(_) })
case _ => None case _ => None
} }
val compilers: Option[mdf.macrolib.SRAMCompiler] = mdf.macrolib.Utils.readMDFFromPath(libFile) match { val compilers: Option[mdf.macrolib.SRAMCompiler] = mdf.macrolib.Utils.readMDFFromPath(libFile) match {
case Some(x:Seq[mdf.macrolib.Macro]) => case Some(x: Seq[mdf.macrolib.Macro]) =>
if(useCompiler){ if (useCompiler) {
findSRAMCompiler(Some(x)) findSRAMCompiler(Some(x))
} } else None
else None
case _ => None case _ => None
} }
// Helper function to turn a set of mem names into a Seq[Macro]. // Helper function to turn a set of mem names into a Seq[Macro].
def setToSeqMacro(names: Set[String]): 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) names.toSeq.map(memName => mems.get.collectFirst { case m if m.src.name == memName => m }.get)
@@ -706,12 +755,16 @@ class MacroCompilerTransform extends Transform {
val transforms = Seq( val transforms = Seq(
new MacroCompilerPass(memCompile, libs, compilers, hammerIR, costMetric, mode), new MacroCompilerPass(memCompile, libs, compilers, hammerIR, costMetric, mode),
new SynFlopsPass(true, memSynflops ++ (if (mode == MacroCompilerAnnotation.CompileAndSynflops) { new SynFlopsPass(
libs.get true,
} else { memSynflops ++ (if (mode == MacroCompilerAnnotation.CompileAndSynflops) {
Seq.empty libs.get
}))) } else {
(transforms foldLeft state) ((s, xform) => xform runTransform s).copy(form = outputForm) Seq.empty
})
)
)
(transforms.foldLeft(state))((s, xform) => xform.runTransform(s)).copy(form = outputForm)
case _ => state case _ => state
} }
} }
@@ -729,7 +782,8 @@ class MacroCompilerOptimizations extends SeqTransform {
new firrtl.transforms.ConstantPropagation, new firrtl.transforms.ConstantPropagation,
passes.Legalize, passes.Legalize,
passes.SplitExpressions, passes.SplitExpressions,
passes.CommonSubexpressionElimination) passes.CommonSubexpressionElimination
)
} }
class MacroCompiler extends Compiler { class MacroCompiler extends Compiler {
@@ -756,8 +810,9 @@ object MacroCompiler extends App {
type MacroParamMap = Map[MacroParam, String] type MacroParamMap = Map[MacroParam, String]
type CostParamMap = Map[String, String] type CostParamMap = Map[String, String]
type ForcedMemories = (Set[String], Set[String]) type ForcedMemories = (Set[String], Set[String])
val modeOptions: Seq[String] = MacroCompilerAnnotation.options val modeOptions: Seq[String] = MacroCompilerAnnotation.options.map { case (_, cmd, description) =>
.map { case (_, cmd, description) => s" $cmd: $description" } s" $cmd: $description"
}
val usage: String = (Seq( val usage: String = (Seq(
"Options:", "Options:",
" -n, --macro-conf: The set of macros to compile in firrtl-generated conf format (exclusive with -m)", " -n, --macro-conf: The set of macros to compile in firrtl-generated conf format (exclusive with -m)",
@@ -772,16 +827,20 @@ object MacroCompiler extends App {
" --force-compile [mem]: Force the given memory to be compiled to target libs regardless of the mode", " --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", " --force-synflops [mem]: Force the given memory to be compiled via synflops regardless of the mode",
" --mode:" " --mode:"
) ++ modeOptions) mkString "\n" ) ++ modeOptions).mkString("\n")
def parseArgs(map: MacroParamMap, costMap: CostParamMap, forcedMemories: ForcedMemories, def parseArgs(
args: List[String]): (MacroParamMap, CostParamMap, ForcedMemories) = map: MacroParamMap,
costMap: CostParamMap,
forcedMemories: ForcedMemories,
args: List[String]
): (MacroParamMap, CostParamMap, ForcedMemories) =
args match { args match {
case Nil => (map, costMap, forcedMemories) case Nil => (map, costMap, forcedMemories)
case ("-n" | "--macro-conf") :: value :: tail => 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 => 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 => case ("-l" | "--library") :: value :: tail =>
parseArgs(map + (Library -> value), costMap, forcedMemories, tail) parseArgs(map + (Library -> value), costMap, forcedMemories, tail)
case ("-u" | "--use-compiler") :: tail => case ("-u" | "--use-compiler") :: tail =>
@@ -809,11 +868,17 @@ object MacroCompiler extends App {
} }
def run(args: List[String]) { 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 { try {
val macros = params.get(MacrosFormat) match { val macros = params.get(MacrosFormat) match {
case Some("conf") => Utils.filterForSRAM(Utils.readConfFromPath(params.get(Macros))).get map (x => (new Macro(x)).blackbox) case Some("conf") =>
case _ => Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(params.get(Macros))).get map (x => (new Macro(x)).blackbox) 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) { if (macros.nonEmpty) {
@@ -821,24 +886,28 @@ object MacroCompiler extends App {
// determined as the firrtl "top-level module". // determined as the firrtl "top-level module".
val circuit = Circuit(NoInfo, macros, macros.last.name) val circuit = Circuit(NoInfo, macros, macros.last.name)
val annotations = AnnotationSeq( val annotations = AnnotationSeq(
Seq(MacroCompilerAnnotation( Seq(
circuit.main, MacroCompilerAnnotation(
MacroCompilerAnnotation.Params( circuit.main,
params.get(Macros).get, params.get(MacrosFormat), params.get(Library), MacroCompilerAnnotation.Params(
params.get(HammerIR), params.get(Macros).get,
CostMetric.getCostMetric(params.getOrElse(CostFunc, "default"), costParams), params.get(MacrosFormat),
MacroCompilerAnnotation.stringToCompilerMode(params.getOrElse(Mode, "default")), params.get(Library),
params.contains(UseCompiler), params.get(HammerIR),
forceCompile = forcedMemories._1, forceSynflops = forcedMemories._2 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 // The actual MacroCompilerTransform basically just generates an input circuit
val macroCompilerInput = CircuitState(circuit, MidForm, annotations) val macroCompilerInput = CircuitState(circuit, MidForm, annotations)
val macroCompiled = (new MacroCompilerTransform).execute(macroCompilerInput) val macroCompiled = (new MacroCompilerTransform).execute(macroCompilerInput)
// Since the MacroCompiler defines its own CLI, reconcile this with FIRRTL options // Since the MacroCompiler defines its own CLI, reconcile this with FIRRTL options
val firOptions = new ExecutionOptionsManager("macrocompiler") with HasFirrtlOptions { val firOptions = new ExecutionOptionsManager("macrocompiler") with HasFirrtlOptions {
firrtlOptions = FirrtlExecutionOptions( firrtlOptions = FirrtlExecutionOptions(
@@ -864,7 +933,7 @@ object MacroCompiler extends App {
} }
} else { } else {
// Warn user // 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 // Emit empty verilog file if no macros found
params.get(Verilog) match { params.get(Verilog) match {

View File

@@ -10,132 +10,142 @@ import firrtl.passes.MemPortUtils.memPortField
class SynFlopsPass(synflops: Boolean, libs: Seq[Macro]) extends firrtl.passes.Pass { class SynFlopsPass(synflops: Boolean, libs: Seq[Macro]) extends firrtl.passes.Pass {
val extraMods = scala.collection.mutable.ArrayBuffer.empty[Module] val extraMods = scala.collection.mutable.ArrayBuffer.empty[Module]
lazy val libMods = (libs map { lib => lib.src.name -> { lazy val libMods = (libs.map { lib =>
val (dataType, dataWidth) = (lib.src.ports foldLeft (None: Option[BigInt]))((res, port) => lib.src.name -> {
(res, port.maskPort) match { val (dataType, dataWidth) = (lib.src.ports.foldLeft(None: Option[BigInt]))((res, port) =>
case (_, None) => (res, port.maskPort) match {
res case (_, None) =>
case (None, Some(_)) => res
Some(port.effectiveMaskGran) case (None, Some(_)) =>
case (Some(x), Some(_)) => Some(port.effectiveMaskGran)
assert(x == port.effectiveMaskGran) case (Some(x), Some(_)) =>
res assert(x == port.effectiveMaskGran)
res
}
) match {
case None => (UIntType(IntWidth(lib.src.width)), lib.src.width)
case Some(gran) => (UIntType(IntWidth(gran)), gran.intValue)
} }
) 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 maxDepth = min(lib.src.depth, 1 << 26)
val numMems = lib.src.depth / maxDepth val numMems = lib.src.depth / maxDepth
// Change macro to be mapped onto to look like the below mem // Change macro to be mapped onto to look like the below mem
// by changing its depth, and width // by changing its depth, and width
val lib_macro = new Macro(lib.src.copy(name="split_"+lib.src.name, val lib_macro = new Macro(
depth = maxDepth, width = dataWidth, ports = lib.src.ports.map(p => lib.src.copy(
p.copy(width = p.width.map(_ => dataWidth), depth = p.depth.map(_ => maxDepth), name = "split_" + lib.src.name,
maskGran = p.maskGran.map(_ => dataWidth))))) depth = maxDepth,
val mod_macro = (new MacroCompilerPass(None,None,None,None)).compile(lib, lib_macro) width = dataWidth,
val (real_mod, real_macro) = mod_macro.get ports = lib.src.ports.map(p =>
p.copy(
val mem = DefMemory( width = p.width.map(_ => dataWidth),
NoInfo, depth = p.depth.map(_ => maxDepth),
"ram", maskGran = p.maskGran.map(_ => dataWidth)
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 mod_macro = (new MacroCompilerPass(None, None, None, None)).compile(lib, lib_macro)
val (real_mod, real_macro) = mod_macro.get
val writeConnects = real_macro.writers.zipWithIndex flatMap { case (w, i) => val mem = DefMemory(
val clock = portToExpression(w.src.clock.get) NoInfo,
val address = portToExpression(w.src.address) "ram",
val enable = (w.src.chipEnable, w.src.writeEnable) match { dataType,
case (Some(en), Some(we)) => maxDepth,
and(portToExpression(en), 1, // writeLatency
portToExpression(we)) 1, // readLatency. This is possible because of VerilogMemDelays
case (Some(en), None) => portToExpression(en) real_macro.readers.indices.map(i => s"R_$i"),
case (None, Some(we)) => portToExpression(we) real_macro.writers.indices.map(i => s"W_$i"),
case (None, None) => zero // is it possible? real_macro.readwriters.indices.map(i => s"RW_$i")
}
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 readConnects = real_macro.readers.zipWithIndex.flatMap { case (r, i) =>
val clock = portToExpression(rw.src.clock.get) val clock = portToExpression(r.src.clock.get)
val address = portToExpression(rw.src.address) val address = portToExpression(r.src.address)
val wmode = rw.src.writeEnable match { val enable = (r.src chipEnable, r.src readEnable) match {
case Some(we) => portToExpression(we) case (Some(en_port), Some(re_port)) =>
case None => zero // is it possible? 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 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)))) val writeConnects = real_macro.writers.zipWithIndex.flatMap { case (w, i) =>
real_mod val clock = portToExpression(w.src.clock.get)
}}).toMap 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 = { def run(c: Circuit): Circuit = {
if (!synflops) c if (!synflops) c
else c.copy(modules = (c.modules map (m => libMods.getOrElse(m.name, m))) ++ extraMods) else c.copy(modules = (c.modules.map(m => libMods.getOrElse(m.name, m))) ++ extraMods)
} }
} }

View File

@@ -11,7 +11,7 @@ import mdf.macrolib.{Input => _, Output => _, _}
import scala.language.implicitConversions import scala.language.implicitConversions
object MacroCompilerMath { object MacroCompilerMath {
def ceilLog2(x: BigInt): Int = (x-1).bitLength def ceilLog2(x: BigInt): Int = (x - 1).bitLength
} }
class FirrtlMacroPort(port: MacroPort) { class FirrtlMacroPort(port: MacroPort) {
@@ -21,37 +21,46 @@ class FirrtlMacroPort(port: MacroPort) {
val isWriter = port.input.nonEmpty && port.output.isEmpty val isWriter = port.input.nonEmpty && port.output.isEmpty
val isReadWriter = port.input.nonEmpty && port.output.nonEmpty val isReadWriter = port.input.nonEmpty && port.output.nonEmpty
val addrType = UIntType(IntWidth(MacroCompilerMath.ceilLog2(port.depth.get) max 1)) val addrType = UIntType(IntWidth(MacroCompilerMath.ceilLog2(port.depth.get).max(1)))
val dataType = UIntType(IntWidth(port.width.get)) val dataType = UIntType(IntWidth(port.width.get))
val maskType = UIntType(IntWidth(port.width.get / port.effectiveMaskGran)) val maskType = UIntType(IntWidth(port.width.get / port.effectiveMaskGran))
// Bundle representing this macro port. // Bundle representing this macro port.
val tpe = BundleType(Seq( val tpe = BundleType(
Field(port.address.name, Flip, addrType)) ++ Seq(Field(port.address.name, Flip, addrType)) ++
(port.clock map (p => Field(p.name, Flip, ClockType))) ++ (port.clock.map(p => Field(p.name, Flip, ClockType))) ++
(port.input map (p => Field(p.name, Flip, dataType))) ++ (port.input.map(p => Field(p.name, Flip, dataType))) ++
(port.output map (p => Field(p.name, Default, dataType))) ++ (port.output.map(p => Field(p.name, Default, dataType))) ++
(port.chipEnable map (p => Field(p.name, Flip, BoolType))) ++ (port.chipEnable.map(p => Field(p.name, Flip, BoolType))) ++
(port.readEnable 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.writeEnable.map(p => Field(p.name, Flip, BoolType))) ++
(port.maskPort map (p => Field(p.name, Flip, maskType))) (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
)
) )
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. // Reads an SRAMMacro and generates firrtl blackboxes.
class Macro(srcMacro: SRAMMacro) { class Macro(srcMacro: SRAMMacro) {
val src = srcMacro val src = srcMacro
val firrtlPorts = srcMacro.ports map { new FirrtlMacroPort(_) } val firrtlPorts = srcMacro.ports.map { new FirrtlMacroPort(_) }
val writers = firrtlPorts filter (p => p.isWriter) val writers = firrtlPorts.filter(p => p.isWriter)
val readers = firrtlPorts filter (p => p.isReader) val readers = firrtlPorts.filter(p => p.isReader)
val readwriters = firrtlPorts filter (p => p.isReadWriter) val readwriters = firrtlPorts.filter(p => p.isReadWriter)
val sortedPorts = writers ++ readers ++ readwriters val sortedPorts = writers ++ readers ++ readwriters
val extraPorts = srcMacro.extraPorts map { p => val extraPorts = srcMacro.extraPorts.map { p =>
assert(p.portType == Constant) // TODO: release it? assert(p.portType == Constant) // TODO: release it?
val name = p.name val name = p.name
val width = BigInt(p.width.toLong) val width = BigInt(p.width.toLong)
@@ -60,10 +69,10 @@ class Macro(srcMacro: SRAMMacro) {
} }
// Bundle representing this memory blackbox // Bundle representing this memory blackbox
val tpe = BundleType(firrtlPorts flatMap (_.tpe.fields)) val tpe = BundleType(firrtlPorts.flatMap(_.tpe.fields))
private val modPorts = (firrtlPorts flatMap (_.ports)) ++ private val modPorts = (firrtlPorts.flatMap(_.ports)) ++
(extraPorts map { case (name, value) => Port(NoInfo, name, Input, value.tpe) }) (extraPorts.map { case (name, value) => Port(NoInfo, name, Input, value.tpe) })
val blackbox = ExtModule(NoInfo, srcMacro.name, modPorts, srcMacro.name, Nil) val blackbox = ExtModule(NoInfo, srcMacro.name, modPorts, srcMacro.name, Nil)
def module(body: Statement) = Module(NoInfo, srcMacro.name, modPorts, body) def module(body: Statement) = Module(NoInfo, srcMacro.name, modPorts, body)
} }
@@ -71,7 +80,8 @@ class Macro(srcMacro: SRAMMacro) {
object Utils { object Utils {
def filterForSRAM(s: Option[Seq[mdf.macrolib.Macro]]): Option[Seq[mdf.macrolib.SRAMMacro]] = { def filterForSRAM(s: Option[Seq[mdf.macrolib.Macro]]): Option[Seq[mdf.macrolib.SRAMMacro]] = {
s match { s match {
case Some(l:Seq[mdf.macrolib.Macro]) => Some(l filter { _.isInstanceOf[mdf.macrolib.SRAMMacro] } map { m => m.asInstanceOf[mdf.macrolib.SRAMMacro] }) case Some(l: Seq[mdf.macrolib.Macro]) =>
Some(l.filter { _.isInstanceOf[mdf.macrolib.SRAMMacro] }.map { m => m.asInstanceOf[mdf.macrolib.SRAMMacro] })
case _ => None case _ => None
} }
} }
@@ -80,18 +90,24 @@ object Utils {
path.map((p) => Utils.readConfFromString(scala.io.Source.fromFile(p).mkString)) path.map((p) => Utils.readConfFromString(scala.io.Source.fromFile(p).mkString))
} }
def readConfFromString(str: String): Seq[mdf.macrolib.Macro] = { def readConfFromString(str: String): Seq[mdf.macrolib.Macro] = {
MemConf.fromString(str).map { m:MemConf => MemConf.fromString(str).map { m: MemConf =>
val ports = m.ports.map { case (port, num) => Seq.fill(num)(port) } reduce (_ ++ _) 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)) 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 = { def portSpecToFamily(ports: Seq[MemPort]): String = {
val numR = ports.count(_ match { case ReadPort => true; case _ => false}) val numR = ports.count(_ match { case ReadPort => true; case _ => false })
val numW = ports.count(_ match { case WritePort|MaskedWritePort => 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 numRW = ports.count(_ match { case ReadWritePort | MaskedReadWritePort => true; case _ => false })
val numRStr = if(numR > 0) s"${numR}r" else "" val numRStr = if (numR > 0) s"${numR}r" else ""
val numWStr = if(numW > 0) s"${numW}w" else "" val numWStr = if (numW > 0) s"${numW}w" else ""
val numRWStr = if(numRW > 0) s"${numRW}rw" else "" val numRWStr = if (numRW > 0) s"${numRW}rw" else ""
return numRStr + numWStr + numRWStr return numRStr + numWStr + numRWStr
} }
// This translates between two represenations of ports // This translates between two represenations of ports
@@ -99,94 +115,128 @@ object Utils {
var numR = 0 var numR = 0
var numW = 0 var numW = 0
var numRW = 0 var numRW = 0
ports.map { _ match { ports.map {
case ReadPort => { _ match {
val portName = s"R${numR}" case ReadPort => {
numR += 1 val portName = s"R${numR}"
MacroPort( numR += 1
width=Some(width), depth=Some(depth), MacroPort(
address=PolarizedPort(s"${portName}_addr", ActiveHigh), width = Some(width),
clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), depth = Some(depth),
readEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), address = PolarizedPort(s"${portName}_addr", ActiveHigh),
output=Some(PolarizedPort(s"${portName}_data", ActiveHigh)) clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)),
) } readEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)),
case WritePort => { output = Some(PolarizedPort(s"${portName}_data", ActiveHigh))
val portName = s"W${numW}" )
numW += 1 }
MacroPort( case WritePort => {
width=Some(width), depth=Some(depth), val portName = s"W${numW}"
address=PolarizedPort(s"${portName}_addr", ActiveHigh), numW += 1
clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), MacroPort(
writeEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), width = Some(width),
input=Some(PolarizedPort(s"${portName}_data", ActiveHigh)) depth = Some(depth),
) } address = PolarizedPort(s"${portName}_addr", ActiveHigh),
case MaskedWritePort => { clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)),
val portName = s"W${numW}" writeEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)),
numW += 1 input = Some(PolarizedPort(s"${portName}_data", ActiveHigh))
MacroPort( )
width=Some(width), depth=Some(depth), }
address=PolarizedPort(s"${portName}_addr", ActiveHigh), case MaskedWritePort => {
clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), val portName = s"W${numW}"
writeEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), numW += 1
maskPort=Some(PolarizedPort(s"${portName}_mask", ActiveHigh)), MacroPort(
maskGran=maskGran, width = Some(width),
input=Some(PolarizedPort(s"${portName}_data", ActiveHigh)) depth = Some(depth),
) } address = PolarizedPort(s"${portName}_addr", ActiveHigh),
case ReadWritePort => { clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)),
val portName = s"RW${numRW}" writeEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)),
numRW += 1 maskPort = Some(PolarizedPort(s"${portName}_mask", ActiveHigh)),
MacroPort( maskGran = maskGran,
width=Some(width), depth=Some(depth), input = Some(PolarizedPort(s"${portName}_data", ActiveHigh))
address=PolarizedPort(s"${portName}_addr", ActiveHigh), )
clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), }
chipEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), case ReadWritePort => {
writeEnable=Some(PolarizedPort(s"${portName}_wmode", ActiveHigh)), val portName = s"RW${numRW}"
input=Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)), numRW += 1
output=Some(PolarizedPort(s"${portName}_rdata", ActiveHigh)) MacroPort(
) } width = Some(width),
case MaskedReadWritePort => { depth = Some(depth),
val portName = s"RW${numRW}" address = PolarizedPort(s"${portName}_addr", ActiveHigh),
numRW += 1 clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)),
MacroPort( chipEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)),
width=Some(width), depth=Some(depth), writeEnable = Some(PolarizedPort(s"${portName}_wmode", ActiveHigh)),
address=PolarizedPort(s"${portName}_addr", ActiveHigh), input = Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)),
clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), output = Some(PolarizedPort(s"${portName}_rdata", ActiveHigh))
chipEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), )
writeEnable=Some(PolarizedPort(s"${portName}_wmode", ActiveHigh)), }
maskPort=Some(PolarizedPort(s"${portName}_wmask", ActiveHigh)), case MaskedReadWritePort => {
maskGran=maskGran, val portName = s"RW${numRW}"
input=Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)), numRW += 1
output=Some(PolarizedPort(s"${portName}_rdata", ActiveHigh)) 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] = { def findSRAMCompiler(s: Option[Seq[mdf.macrolib.Macro]]): Option[mdf.macrolib.SRAMCompiler] = {
s match { s match {
case Some(l:Seq[mdf.macrolib.Macro]) => case Some(l: Seq[mdf.macrolib.Macro]) =>
l collectFirst { l.collectFirst { case x: mdf.macrolib.SRAMCompiler =>
case x: mdf.macrolib.SRAMCompiler => x x
} }
case _ => None case _ => None
} }
} }
def buildSRAMMacros(s: mdf.macrolib.SRAMCompiler): Seq[mdf.macrolib.SRAMMacro] = { def buildSRAMMacros(s: mdf.macrolib.SRAMCompiler): Seq[mdf.macrolib.SRAMMacro] = {
for (g <- s.groups; d <- g.depth; w <- g.width; vt <- g.vt) for {
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) 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 = { 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) 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 = { def makeName(g: mdf.macrolib.SRAMGroup, depth: Int, width: Int, vt: String): String = {
g.name.foldLeft(""){ (builder, next) => g.name.foldLeft("") { (builder, next) =>
next match { next match {
case "depth"|"DEPTH" => builder + depth case "depth" | "DEPTH" => builder + depth
case "width"|"WIDTH" => builder + width case "width" | "WIDTH" => builder + width
case "vt" => builder + vt.toLowerCase case "vt" => builder + vt.toLowerCase
case "VT" => builder + vt.toUpperCase case "VT" => builder + vt.toUpperCase
case "family" => builder + g.family.toLowerCase case "family" => builder + g.family.toLowerCase
case "FAMILY" => builder + g.family.toUpperCase case "FAMILY" => builder + g.family.toUpperCase
case "mux"|"MUX" => builder + g.mux case "mux" | "MUX" => builder + g.mux
case other => builder + other case other => builder + other
} }
} }
} }
@@ -196,7 +246,7 @@ object Utils {
def or(e1: Expression, e2: Expression) = def or(e1: Expression, e2: Expression) =
DoPrim(PrimOps.Or, Seq(e1, e2), Nil, e1.tpe) DoPrim(PrimOps.Or, Seq(e1, e2), Nil, e1.tpe)
def bits(e: Expression, high: BigInt, low: BigInt): Expression = def bits(e: Expression, high: BigInt, low: BigInt): Expression =
DoPrim(PrimOps.Bits, Seq(e), Seq(high, low), UIntType(IntWidth(high-low+1))) 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 bits(e: Expression, idx: BigInt): Expression = bits(e, idx, idx)
def cat(es: Seq[Expression]): Expression = def cat(es: Seq[Expression]): Expression =
if (es.size == 1) es.head if (es.size == 1) es.head
@@ -211,7 +261,7 @@ object Utils {
def portToExpression(exp: Expression, polarity: Option[PortPolarity]): Expression = def portToExpression(exp: Expression, polarity: Option[PortPolarity]): Expression =
polarity match { polarity match {
case Some(ActiveLow) | Some(NegativeEdge) => not(exp) case Some(ActiveLow) | Some(NegativeEdge) => not(exp)
case _ => exp case _ => exp
} }
// Check if a number is a power of two // Check if a number is a power of two

View File

@@ -1,27 +1,29 @@
[ [
{ {
"type" : "sram", "type": "sram",
"name" : "fake_mem", "name": "fake_mem",
"width" : 64, "width": 64,
"depth" : "512", "depth": "512",
"mux" : 4, "mux": 4,
"family" : "1rw", "family": "1rw",
"ports" : [ { "ports": [
"address port name" : "addr", {
"address port polarity" : "active high", "address port name": "addr",
"clock port name" : "clk", "address port polarity": "active high",
"clock port polarity" : "positive edge", "clock port name": "clk",
"write enable port name" : "wen", "clock port polarity": "positive edge",
"write enable port polarity" : "active high", "write enable port name": "wen",
"read enable port name" : "ren", "write enable port polarity": "active high",
"read enable port polarity" : "active high", "read enable port name": "ren",
"output port name" : "dataout", "read enable port polarity": "active high",
"output port polarity" : "active high", "output port name": "dataout",
"input port name" : "datain", "output port polarity": "active high",
"input port polarity" : "active high", "input port name": "datain",
"mask port name" : "mport", "input port polarity": "active high",
"mask port polarity" : "active low", "mask port name": "mport",
"mask granularity" : 1 "mask port polarity": "active low",
} ] "mask granularity": 1
}
]
} }
] ]

View File

@@ -1,24 +1,26 @@
[ [
{ {
"type" : "sram", "type": "sram",
"name" : "fake_mem", "name": "fake_mem",
"width" : 64, "width": 64,
"depth" : "4096", "depth": "4096",
"mux" : 4, "mux": 4,
"family" : "1rw", "family": "1rw",
"ports" : [ { "ports": [
"address port name" : "addr", {
"address port polarity" : "active high", "address port name": "addr",
"clock port name" : "clk", "address port polarity": "active high",
"clock port polarity" : "positive edge", "clock port name": "clk",
"write enable port name" : "wen", "clock port polarity": "positive edge",
"write enable port polarity" : "active high", "write enable port name": "wen",
"read enable port name" : "ren", "write enable port polarity": "active high",
"read enable port polarity" : "active high", "read enable port name": "ren",
"output port name" : "dataout", "read enable port polarity": "active high",
"output port polarity" : "active high", "output port name": "dataout",
"input port name" : "datain", "output port polarity": "active high",
"input port polarity" : "active high" "input port name": "datain",
} ] "input port polarity": "active high"
}
]
} }
] ]

View File

@@ -4,10 +4,9 @@ import mdf.macrolib._
/** Tests to check that the cost function mechanism is working properly. */ /** Tests to check that the cost function mechanism is working properly. */
/** /** A test metric that simply favours memories with smaller widths, to test that
* A test metric that simply favours memories with smaller widths, to test that * the metric is chosen properly.
* the metric is chosen properly. */
*/
object TestMinWidthMetric extends CostMetric with CostMetricCompanion { object TestMinWidthMetric extends CostMetric with CostMetricCompanion {
// Smaller width = lower cost = favoured // Smaller width = lower cost = favoured
override def cost(mem: Macro, lib: Macro): Option[Double] = Some(lib.src.width) 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( val libSRAMs = Seq(
SRAMMacro( SRAMMacro(
name="SRAM_WIDTH_128", name = "SRAM_WIDTH_128",
depth=BigInt(1024), depth = BigInt(1024),
width=128, width = 128,
family="1rw", family = "1rw",
ports=Seq( ports = Seq(
generateReadWritePort("", 128, BigInt(1024)) generateReadWritePort("", 128, BigInt(1024))
) )
), ),
SRAMMacro( SRAMMacro(
name="SRAM_WIDTH_64", name = "SRAM_WIDTH_64",
depth=BigInt(1024), depth = BigInt(1024),
width=64, width = 64,
family="1rw", family = "1rw",
ports=Seq( ports = Seq(
generateReadWritePort("", 64, BigInt(1024)) generateReadWritePort("", 64, BigInt(1024))
) )
), ),
SRAMMacro( SRAMMacro(
name="SRAM_WIDTH_32", name = "SRAM_WIDTH_32",
depth=BigInt(1024), depth = BigInt(1024),
width=32, width = 32,
family="1rw", family = "1rw",
ports=Seq( ports = Seq(
generateReadWritePort("", 32, BigInt(1024)) 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. // Check that the min width SRAM was chosen, even though it is less efficient.
val output = val output =
""" """
circuit target_memory : circuit target_memory :
module target_memory : module target_memory :
input addr : UInt<10> input addr : UInt<10>

View File

@@ -18,12 +18,12 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
// Override these to change the prefixing of macroDir and testDir // Override these to change the prefixing of macroDir and testDir
val memPrefix: String = testDir val memPrefix: String = testDir
val libPrefix: String = testDir val libPrefix: String = testDir
val vPrefix: String = testDir val vPrefix: String = testDir
// Override this to use a different cost metric. // Override this to use a different cost metric.
// If this is None, the compile() call will not have any -c/-cp arguments, and // If this is None, the compile() call will not have any -c/-cp arguments, and
// execute() will use CostMetric.default. // execute() will use CostMetric.default.
val costMetric: Option[CostMetric] = None val costMetric: Option[CostMetric] = None
private def getCostMetric: CostMetric = costMetric.getOrElse(CostMetric.default) private def getCostMetric: CostMetric = costMetric.getOrElse(CostMetric.default)
private def costMetricCmdLine = { private def costMetricCmdLine = {
@@ -32,17 +32,20 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
case Some(m) => { case Some(m) => {
val name = m.name val name = m.name
val params = m.commandLineParams val params = m.commandLineParams
List("-c", name) ++ params.flatMap{ case (key, value) => List("-cp", key, value) } 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) = private def args(mem: String, lib: Option[String], v: String, synflops: Boolean, useCompiler: Boolean) =
List("-m", mem.toString, "-v", v) ++ List("-m", mem.toString, "-v", v) ++
(lib match { case None => Nil case Some(l) => List("-l", l.toString) }) ++ (lib match {
costMetricCmdLine ++ case None => Nil
(if (synflops) List("--mode", "synflops") else Nil) ++ case Some(l) => List("-l", l.toString)
(if (useCompiler) List("--use-compiler") else Nil) }) ++
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. // Run the full compiler as if from the command line interface.
// Generates the Verilog; useful in testing since an error will throw an // Generates the Verilog; useful in testing since an error will throw an
@@ -68,7 +71,14 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
} }
// Convenience function for running both compile, execute, and test at once. // 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 = { def compileExecuteAndTest(
mem: String,
lib: Option[String],
v: String,
output: String,
synflops: Boolean = false,
useCompiler: Boolean = false
): Unit = {
compile(mem, lib, v, synflops, useCompiler) compile(mem, lib, v, synflops, useCompiler)
val result = execute(mem, lib, synflops, useCompiler) val result = execute(mem, lib, synflops, useCompiler)
test(result, output) test(result, output)
@@ -76,43 +86,53 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
// Compare FIRRTL outputs after reparsing output with ScalaTest ("should be"). // Compare FIRRTL outputs after reparsing output with ScalaTest ("should be").
def test(result: Circuit, output: String): Unit = { def test(result: Circuit, output: String): Unit = {
val gold = RemoveEmpty run parse(output) val gold = RemoveEmpty.run(parse(output))
(result.serialize) should be (gold.serialize) (result.serialize) should be(gold.serialize)
} }
// Execute the macro compiler and returns a Circuit containing the output of // Execute the macro compiler and returns a Circuit containing the output of
// the memory compiler. // 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): Circuit =
execute(memFile, libFile, synflops, false)
def execute(memFile: Option[String], libFile: Option[String], synflops: Boolean, useCompiler: Boolean): Circuit = { def execute(memFile: Option[String], libFile: Option[String], synflops: Boolean, useCompiler: Boolean): Circuit = {
var mem_full = concat(memPrefix, memFile) var mem_full = concat(memPrefix, memFile)
var lib_full = concat(libPrefix, libFile) var lib_full = concat(libPrefix, libFile)
require(memFile.isDefined) require(memFile.isDefined)
val mems: Seq[Macro] = Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(mem_full)).get map (new Macro(_)) val mems: Seq[Macro] = Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(mem_full)).get.map(new Macro(_))
val libs: Option[Seq[Macro]] = if(useCompiler) { val libs: Option[Seq[Macro]] = if (useCompiler) {
Utils.findSRAMCompiler(mdf.macrolib.Utils.readMDFFromPath(lib_full)).map{x => Utils.buildSRAMMacros(x).map(new Macro(_)) } Utils.findSRAMCompiler(mdf.macrolib.Utils.readMDFFromPath(lib_full)).map { x =>
Utils.buildSRAMMacros(x).map(new Macro(_))
}
} else { } else {
Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(lib_full)) match { Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(lib_full)) match {
case Some(x) => Some(x map (new Macro(_))) case Some(x) => Some(x.map(new Macro(_)))
case None => None case None => None
} }
} }
val macros = mems map (_.blackbox) val macros = mems.map(_.blackbox)
val circuit = Circuit(NoInfo, macros, macros.last.name) val circuit = Circuit(NoInfo, macros, macros.last.name)
val passes = Seq( val passes = Seq(
new MacroCompilerPass(Some(mems), libs, None, None, getCostMetric, if (synflops) MacroCompilerAnnotation.Synflops else MacroCompilerAnnotation.Default), new MacroCompilerPass(
new SynFlopsPass(synflops, libs getOrElse mems), Some(mems),
RemoveEmpty) libs,
val result: Circuit = (passes foldLeft circuit)((c, pass) => pass run c) 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 result
} }
// Helper method to deal with String + Option[String] // Helper method to deal with String + Option[String]
private def concat(a: String, b: String): String = {a + "/" + b} private def concat(a: String, b: String): String = { a + "/" + b }
private def concat(a: String, b: Option[String]): Option[String] = { private def concat(a: String, b: Option[String]): Option[String] = {
b match { b match {
case Some(b2:String) => Some(a + "/" + b2) case Some(b2: String) => Some(a + "/" + b2)
case _ => None case _ => None
} }
} }
@@ -123,20 +143,19 @@ trait HasSRAMGenerator {
import mdf.macrolib._ import mdf.macrolib._
import scala.language.implicitConversions import scala.language.implicitConversions
implicit def Int2SomeInt(i: Int): Option[Int] = Some(i) implicit def Int2SomeInt(i: Int): Option[Int] = Some(i)
implicit def BigInt2SomeBigInt(i: BigInt): Option[BigInt] = Some(i) implicit def BigInt2SomeBigInt(i: BigInt): Option[BigInt] = Some(i)
// Generate a standard (read/write/combo) port for testing. // Generate a standard (read/write/combo) port for testing.
// Helper methods for optional width argument // Helper methods for optional width argument
def generateTestPort( def generateTestPort(
prefix: String, prefix: String,
width: Option[Int], width: Option[Int],
depth: Option[BigInt], depth: Option[BigInt],
maskGran: Option[Int] = None, maskGran: Option[Int] = None,
read: Boolean, read: Boolean,
readEnable: Boolean = false, readEnable: Boolean = false,
write: Boolean, write: Boolean,
writeEnable: Boolean = false writeEnable: Boolean = false
): MacroPort = { ): MacroPort = {
val realPrefix = if (prefix == "") "" else prefix + "_" val realPrefix = if (prefix == "") "" else prefix + "_"
@@ -144,44 +163,70 @@ trait HasSRAMGenerator {
MacroPort( MacroPort(
address = PolarizedPort(name = realPrefix + "addr", polarity = ActiveHigh), address = PolarizedPort(name = realPrefix + "addr", polarity = ActiveHigh),
clock = Some(PolarizedPort(name = realPrefix + "clk", polarity = PositiveEdge)), clock = Some(PolarizedPort(name = realPrefix + "clk", polarity = PositiveEdge)),
readEnable = if (readEnable) Some(PolarizedPort(name = realPrefix + "read_en", polarity = ActiveHigh)) else None, 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, 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, output = if (read) Some(PolarizedPort(name = realPrefix + "dout", polarity = ActiveHigh)) else None,
input = if (write) Some(PolarizedPort(name = realPrefix + "din", polarity = ActiveHigh)) else None, input = if (write) Some(PolarizedPort(name = realPrefix + "din", polarity = ActiveHigh)) else None,
maskPort = maskGran match { maskPort = maskGran match {
case Some(x: Int) => Some(PolarizedPort(name = realPrefix + "mask", polarity = ActiveHigh)) case Some(x: Int) => Some(PolarizedPort(name = realPrefix + "mask", polarity = ActiveHigh))
case _ => None case _ => None
}, },
maskGran = maskGran, maskGran = maskGran,
width = width,
width = width, depth = depth // These numbers don't matter here. depth = depth // These numbers don't matter here.
) )
} }
// Generate a read port for testing. // Generate a read port for testing.
def generateReadPort(prefix: String, width: Option[Int], depth: Option[BigInt], readEnable: Boolean = false): MacroPort = { def generateReadPort(
prefix: String,
width: Option[Int],
depth: Option[BigInt],
readEnable: Boolean = false
): MacroPort = {
generateTestPort(prefix, width, depth, write = false, read = true, readEnable = readEnable) generateTestPort(prefix, width, depth, write = false, read = true, readEnable = readEnable)
} }
// Generate a write port for testing. // Generate a write port for testing.
def generateWritePort(prefix: String, width: Option[Int], depth: Option[BigInt], maskGran: Option[Int] = None, writeEnable: Boolean = true): MacroPort = { 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) generateTestPort(prefix, width, depth, maskGran = maskGran, write = true, read = false, writeEnable = writeEnable)
} }
// Generate a simple read-write port for testing. // Generate a simple read-write port for testing.
def generateReadWritePort(prefix: String, width: Option[Int], depth: Option[BigInt], maskGran: Option[Int] = None): MacroPort = { def generateReadWritePort(
prefix: String,
width: Option[Int],
depth: Option[BigInt],
maskGran: Option[Int] = None
): MacroPort = {
generateTestPort( generateTestPort(
prefix, width, depth, maskGran = maskGran, prefix,
write = true, writeEnable = true, width,
read = true, readEnable = false depth,
maskGran = maskGran,
write = true,
writeEnable = true,
read = true,
readEnable = false
) )
} }
// Generate a "simple" SRAM (active high/positive edge, 1 read-write port). // 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 = { def generateSRAM(
name: String,
prefix: String,
width: Int,
depth: BigInt,
maskGran: Option[Int] = None,
extraPorts: Seq[MacroExtraPort] = List()
): SRAMMacro = {
SRAMMacro( SRAMMacro(
name = name, name = name,
width = width, width = width,
@@ -193,17 +238,35 @@ trait HasSRAMGenerator {
} }
// Generate a "simple" SRAM group (active high/positive edge, 1 read-write port). // 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 = { def generateSimpleSRAMGroup(
SRAMGroup(Seq("mygroup_", "width", "x", "depth", "_", "VT"), "1rw", Seq("svt", "lvt", "ulvt"), mux, depth, width, Seq(generateReadWritePort(prefix, None, None, maskGran))) 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': 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} // '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 = { def generateSRAMCompiler(name: String, prefix: String): mdf.macrolib.SRAMCompiler = {
SRAMCompiler(name, Seq( SRAMCompiler(
generateSimpleSRAMGroup(prefix, 2, Range(16, 512, 8), Range(8, 288, 2)), name,
generateSimpleSRAMGroup(prefix, 4, Range(32, 1024, 16), Range(4, 144, 1)) Seq(
)) generateSimpleSRAMGroup(prefix, 2, Range(16, 512, 8), Range(8, 288, 2)),
generateSimpleSRAMGroup(prefix, 4, Range(32, 1024, 16), Range(4, 144, 1))
)
)
} }
} }
@@ -212,147 +275,156 @@ trait HasSRAMGenerator {
// Override this generator to specify the expected FIRRTL output. // Override this generator to specify the expected FIRRTL output.
trait HasSimpleTestGenerator { trait HasSimpleTestGenerator {
this: MacroCompilerSpec with HasSRAMGenerator => this: MacroCompilerSpec with HasSRAMGenerator =>
// Override these with "override lazy val". // Override these with "override lazy val".
// Why lazy? These are used in the constructor here so overriding non-lazily // Why lazy? These are used in the constructor here so overriding non-lazily
// would be too late. // would be too late.
def useCompiler: Boolean = false def useCompiler: Boolean = false
def memWidth: Int def memWidth: Int
def libWidth: Int def libWidth: Int
def memDepth: BigInt def memDepth: BigInt
def libDepth: BigInt def libDepth: BigInt
def memMaskGran: Option[Int] = None def memMaskGran: Option[Int] = None
def libMaskGran: Option[Int] = None def libMaskGran: Option[Int] = None
def extraPorts: Seq[mdf.macrolib.MacroExtraPort] = List() def extraPorts: Seq[mdf.macrolib.MacroExtraPort] = List()
def extraTag: String = "" def extraTag: String = ""
// "Effective" libMaskGran by considering write_enable. // "Effective" libMaskGran by considering write_enable.
val effectiveLibMaskGran = libMaskGran.getOrElse(libWidth) val effectiveLibMaskGran = libMaskGran.getOrElse(libWidth)
// Override this in the sub-generator if you need a more specific name. // 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 // Defaults to using reflection to pull the name of the test using this
// generator. // generator.
def generatorType: String = this.getClass.getSimpleName def generatorType: String = this.getClass.getSimpleName
//require (memDepth >= libDepth) //require (memDepth >= libDepth)
// Convenience variables to check if a mask exists. // Convenience variables to check if a mask exists.
val memHasMask = memMaskGran != None val memHasMask = memMaskGran != None
val libHasMask = libMaskGran != None val libHasMask = libMaskGran != None
// We need to figure out how many mask bits there are in the mem. // We need to figure out how many mask bits there are in the mem.
val memMaskBits = if (memHasMask) memWidth / memMaskGran.get else 0 val memMaskBits = if (memHasMask) memWidth / memMaskGran.get else 0
val libMaskBits = if (libHasMask) libWidth / libMaskGran.get else 0 val libMaskBits = if (libHasMask) libWidth / libMaskGran.get else 0
val extraTagPrefixed = if (extraTag == "") "" else ("-" + extraTag) val extraTagPrefixed = if (extraTag == "") "" else ("-" + extraTag)
val mem = s"mem-${generatorType}${extraTagPrefixed}.json" val mem = s"mem-${generatorType}${extraTagPrefixed}.json"
val lib = s"lib-${generatorType}${extraTagPrefixed}.json" val lib = s"lib-${generatorType}${extraTagPrefixed}.json"
val v = s"${generatorType}${extraTagPrefixed}.v" val v = s"${generatorType}${extraTagPrefixed}.v"
lazy val mem_name = "target_memory" lazy val mem_name = "target_memory"
val mem_addr_width = MacroCompilerMath.ceilLog2(memDepth) val mem_addr_width = MacroCompilerMath.ceilLog2(memDepth)
lazy val lib_name = "awesome_lib_mem" lazy val lib_name = "awesome_lib_mem"
val lib_addr_width = MacroCompilerMath.ceilLog2(libDepth) val lib_addr_width = MacroCompilerMath.ceilLog2(libDepth)
// Override these to change the port prefixes if needed. // Override these to change the port prefixes if needed.
def libPortPrefix: String = "lib" def libPortPrefix: String = "lib"
def memPortPrefix: String = "outer" def memPortPrefix: String = "outer"
// These generate "simple" SRAMs (1 masked read-write port) by default, // These generate "simple" SRAMs (1 masked read-write port) by default,
// but can be overridden if need be. // but can be overridden if need be.
def generateLibSRAM() = generateSRAM(lib_name, libPortPrefix, libWidth, libDepth, libMaskGran, extraPorts) def generateLibSRAM() = generateSRAM(lib_name, libPortPrefix, libWidth, libDepth, libMaskGran, extraPorts)
def generateMemSRAM() = generateSRAM(mem_name, memPortPrefix, memWidth, memDepth, memMaskGran) def generateMemSRAM() = generateSRAM(mem_name, memPortPrefix, memWidth, memDepth, memMaskGran)
def libSRAM = generateLibSRAM def libSRAM = generateLibSRAM
def memSRAM = generateMemSRAM def memSRAM = generateMemSRAM
def libSRAMs: Seq[SRAMMacro] = Seq(libSRAM) def libSRAMs: Seq[SRAMMacro] = Seq(libSRAM)
def memSRAMs: Seq[SRAMMacro] = Seq(memSRAM) def memSRAMs: Seq[SRAMMacro] = Seq(memSRAM)
writeToLib(lib, libSRAMs) writeToLib(lib, libSRAMs)
writeToMem(mem, memSRAMs) writeToMem(mem, memSRAMs)
// For masks, width it's a bit tricky since we have to consider cases like // For masks, width it's a bit tricky since we have to consider cases like
// memMaskGran = 4 and libMaskGran = 8. // memMaskGran = 4 and libMaskGran = 8.
// Consider the actually usable libWidth in cases like the above. // Consider the actually usable libWidth in cases like the above.
val usableLibWidth = if (memMaskGran.getOrElse(Int.MaxValue) < effectiveLibMaskGran) memMaskGran.get else libWidth val usableLibWidth = if (memMaskGran.getOrElse(Int.MaxValue) < effectiveLibMaskGran) memMaskGran.get else libWidth
// Number of lib instances needed to hold the mem, in both directions. // Number of lib instances needed to hold the mem, in both directions.
// Round up (e.g. 1.5 instances = effectively 2 instances) // Round up (e.g. 1.5 instances = effectively 2 instances)
val depthInstances = math.ceil(memDepth.toFloat / libDepth.toFloat).toInt val depthInstances = math.ceil(memDepth.toFloat / libDepth.toFloat).toInt
val widthInstances = math.ceil(memWidth.toFloat / usableLibWidth).toInt val widthInstances = math.ceil(memWidth.toFloat / usableLibWidth).toInt
// Number of width bits in the last width-direction memory. // 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 = 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. // 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 lastWidthBits = if (memWidth % usableLibWidth == 0) usableLibWidth else (memWidth % usableLibWidth)
lazy val selectBits = mem_addr_width - lib_addr_width lazy val selectBits = mem_addr_width - lib_addr_width
/** /** Convenience function to generate a mask statement.
* Convenience function to generate a mask statement. * @param widthInst Width instance (mem_0_x)
* @param widthInst Width instance (mem_0_x) * @param depthInst Depth instance (mem_x_0)
* @param depthInst Depth instance (mem_x_0) */
*/ def generateMaskStatement(widthInst: Int, depthInst: Int): String = {
def generateMaskStatement(widthInst: Int, depthInst: Int): String = { // Width of this submemory.
// Width of this submemory. val myMemWidth = if (widthInst == widthInstances - 1) lastWidthBits else usableLibWidth
val myMemWidth = if (widthInst == widthInstances - 1) lastWidthBits else usableLibWidth // Base bit of this submemory.
// Base bit of this submemory. // e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this
// e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this // would be 16.
// would be 16. val myBaseBit = usableLibWidth * widthInst
val myBaseBit = usableLibWidth*widthInst
if (libMaskGran.isDefined) { if (libMaskGran.isDefined) {
if (memMaskGran.isEmpty) { if (memMaskGran.isEmpty) {
// If there is no memory mask, we should just turn all the lib mask // If there is no memory mask, we should just turn all the lib mask
// bits high. // bits high.
s"""mem_${depthInst}_${widthInst}.lib_mask <= UInt<${libMaskBits}>("h${((1 << libMaskBits) - 1).toHexString}")""" s"""mem_${depthInst}_${widthInst}.lib_mask <= UInt<${libMaskBits}>("h${((1 << libMaskBits) - 1).toHexString}")"""
} else { } else {
// Calculate which bit of outer_mask contains the given bit. // Calculate which bit of outer_mask contains the given bit.
// e.g. if memMaskGran = 2, libMaskGran = 1 and libWidth = 4, then // e.g. if memMaskGran = 2, libMaskGran = 1 and libWidth = 4, then
// calculateMaskBit({0, 1}) = 0 and calculateMaskBit({1, 2}) = 1 // calculateMaskBit({0, 1}) = 0 and calculateMaskBit({1, 2}) = 1
def calculateMaskBit(bit:Int): Int = bit / memMaskGran.getOrElse(memWidth) def calculateMaskBit(bit: Int): Int = bit / memMaskGran.getOrElse(memWidth)
val bitsArr = ((libMaskBits - 1 to 0 by -1) map (x => { val bitsArr = ((libMaskBits - 1 to 0 by -1).map(x => {
if (x*libMaskGran.get > myMemWidth) { if (x * libMaskGran.get > myMemWidth) {
// If we have extra mask bits leftover after the effective width, // If we have extra mask bits leftover after the effective width,
// disable those bits. // disable those bits.
"""UInt<1>("h0")""" """UInt<1>("h0")"""
} else { } else {
val outerMaskBit = calculateMaskBit(x*libMaskGran.get + myBaseBit) val outerMaskBit = calculateMaskBit(x * libMaskGran.get + myBaseBit)
s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})"
} }
})) }))
val maskVal = bitsArr.reduceRight((bit, rest) => s"cat($bit, $rest)") val maskVal = bitsArr.reduceRight((bit, rest) => s"cat($bit, $rest)")
s"mem_${depthInst}_${widthInst}.lib_mask <= ${maskVal}" 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") } else ""
s""" }
/** 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}addr : UInt<$addrWidth>
input ${realPrefix}clk : Clock input ${realPrefix}clk : Clock
$writeStr $writeStr
@@ -362,92 +434,121 @@ trait HasSimpleTestGenerator {
$maskStr $maskStr
$extraPortsStr $extraPortsStr
""" """
} }
/** /** Helper function to generate a RW footer port.
* Helper function to generate a RW footer port. *
* * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk")
* @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") * @param readEnable Has a read enable port?
* @param readEnable Has a read enable port? * @param mask Mask granularity (# bits) of the port or None.
* @param mask Mask granularity (# bits) of the port or None. * @param extraPorts Extra ports (name, # bits)
* @param extraPorts Extra ports (name, # bits) */
*/ def generateReadWriteFooterPort(
def generateReadWriteFooterPort(prefix: String, readEnable: Boolean, mask: Option[Int], extraPorts: Seq[(String, Int)] = Seq()): String = { prefix: String,
generatePort(prefix, lib_addr_width, libWidth, readEnable: Boolean,
write = true, writeEnable = true, read = true, readEnable = readEnable, mask = mask, extraPorts = extraPorts) 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. /** Helper function to generate a RW header port.
* @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk")
* @param readEnable Has a read enable port? * @param readEnable Has a read enable port?
* @param mask Mask granularity (# bits) of the port or None. */ * @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, def generateReadWriteHeaderPort(prefix: String, readEnable: Boolean, mask: Option[Int]): String = {
write=true, writeEnable=true, read=true, readEnable=readEnable, mask) generatePort(
} prefix,
mem_addr_width,
memWidth,
write = true,
writeEnable = true,
read = true,
readEnable = readEnable,
mask
)
}
// Generate the header memory ports. // Generate the header memory ports.
def generateHeaderPorts(): String = { def generateHeaderPorts(): String = {
require (memSRAM.ports.size == 1, "Header generator only supports single RW port mem") 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) generateReadWriteHeaderPort(
} memPortPrefix,
memSRAM.ports(0).readEnable.isDefined,
if (memHasMask) Some(memMaskBits) else None
)
}
// Generate the header (contains the circuit statement and the target memory // Generate the header (contains the circuit statement and the target memory
// module. // module.
def generateHeader(): String = { def generateHeader(): String = {
s""" s"""
circuit $mem_name : circuit $mem_name :
module $mem_name : module $mem_name :
${generateHeaderPorts} ${generateHeaderPorts}
""" """
} }
// Generate the target memory ports. // Generate the target memory ports.
def generateFooterPorts(): String = { def generateFooterPorts(): String = {
require(libSRAM.ports.size == 1, "Footer generator only supports single RW port mem") require(libSRAM.ports.size == 1, "Footer generator only supports single RW port mem")
generateReadWriteFooterPort(libPortPrefix, libSRAM.ports(0).readEnable.isDefined, generateReadWriteFooterPort(
if (libHasMask) Some(libMaskBits) else None, extraPorts.map(p => (p.name, p.width))) 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). // Generate the footer (contains the target memory extmodule declaration by default).
def generateFooter(): String = { def generateFooter(): String = {
s""" s"""
extmodule $lib_name : extmodule $lib_name :
${generateFooterPorts} ${generateFooterPorts}
defname = $lib_name defname = $lib_name
""" """
} }
// Abstract method to generate body; to be overridden by specific generator type. // Abstract method to generate body; to be overridden by specific generator type.
def generateBody(): String def generateBody(): String
// Generate the entire output from header, body, and footer. // Generate the entire output from header, body, and footer.
def generateOutput(): String = { def generateOutput(): String = {
s""" s"""
${generateHeader} ${generateHeader}
${generateBody} ${generateBody}
${generateFooter} ${generateFooter}
""" """
} }
val output = generateOutput() val output = generateOutput()
} }
// Use this trait for tests that invoke the memory compiler without lib. // Use this trait for tests that invoke the memory compiler without lib.
trait HasNoLibTestGenerator extends HasSimpleTestGenerator { trait HasNoLibTestGenerator extends HasSimpleTestGenerator {
this: MacroCompilerSpec with HasSRAMGenerator => this: MacroCompilerSpec with HasSRAMGenerator =>
// If there isn't a lib, then the "lib" will become a FIRRTL "mem", which // If there isn't a lib, then the "lib" will become a FIRRTL "mem", which
// in turn becomes synthesized flops. // in turn becomes synthesized flops.
// Therefore, make "lib" width/depth equal to the mem. // Therefore, make "lib" width/depth equal to the mem.
override lazy val libDepth = memDepth override lazy val libDepth = memDepth
override lazy val libWidth = memWidth override lazy val libWidth = memWidth
override lazy val lib_name = mem_name override lazy val lib_name = mem_name
// Do the same for port names. // Do the same for port names.
override lazy val libPortPrefix = memPortPrefix override lazy val libPortPrefix = memPortPrefix
// If there is no lib, don't generate a body. // If there is no lib, don't generate a body.
override def generateBody = "" override def generateBody = ""
} }

View File

@@ -4,32 +4,36 @@ package barstools.macros
trait MasksTestSettings { trait MasksTestSettings {
this: MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator => this: MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator =>
override lazy val memDepth = BigInt(2048) override lazy val memDepth = BigInt(2048)
override lazy val libDepth = BigInt(1024) override lazy val libDepth = BigInt(1024)
} }
// Try all four different kinds of mask config: // Try all four different kinds of mask config:
/** /** Non-masked mem Masked mem
* * ---------------------------------
* Non-masked mem Masked mem * Non-masked lib | | |
* --------------------------------- * ---------------------------------
* Non-masked lib | | | * Masked lib | | |
* --------------------------------- * ---------------------------------
* Masked lib | | | */
* ---------------------------------
*/
class Masks_FourTypes_NonMaskedMem_NonMaskedLib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { class Masks_FourTypes_NonMaskedMem_NonMaskedLib
extends MacroCompilerSpec
with HasSRAMGenerator
with HasSimpleWidthTestGenerator {
override lazy val depth = BigInt(1024) override lazy val depth = BigInt(1024)
override lazy val memWidth = 32 override lazy val memWidth = 32
override lazy val memMaskGran = None override lazy val memMaskGran = None
override lazy val libWidth = 8 override lazy val libWidth = 8
override lazy val libMaskGran = None override lazy val libMaskGran = None
compileExecuteAndTest(mem, lib, v, output) 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 depth = BigInt(1024)
override lazy val memWidth = 32 override lazy val memWidth = 32
override lazy val memMaskGran = None override lazy val memMaskGran = None
@@ -39,7 +43,10 @@ class Masks_FourTypes_NonMaskedMem_MaskedLib extends MacroCompilerSpec with HasS
compileExecuteAndTest(mem, lib, v, output) 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 depth = BigInt(1024)
override lazy val memWidth = 32 override lazy val memWidth = 32
override lazy val memMaskGran = Some(8) override lazy val memMaskGran = Some(8)
@@ -49,7 +56,10 @@ class Masks_FourTypes_MaskedMem_NonMaskedLib extends MacroCompilerSpec with HasS
compileExecuteAndTest(mem, lib, v, output) 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 depth = BigInt(1024)
override lazy val memWidth = 32 override lazy val memWidth = 32
override lazy val memMaskGran = Some(4) override lazy val memMaskGran = Some(4)
@@ -59,7 +69,10 @@ class Masks_FourTypes_MaskedMem_NonMaskedLib_SmallerMaskGran extends MacroCompil
compileExecuteAndTest(mem, lib, v, output) 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 depth = BigInt(1024)
override lazy val memWidth = 32 override lazy val memWidth = 32
override lazy val memMaskGran = Some(8) override lazy val memMaskGran = Some(8)
@@ -69,7 +82,10 @@ class Masks_FourTypes_MaskedMem_MaskedLib extends MacroCompilerSpec with HasSRAM
compileExecuteAndTest(mem, lib, v, output) 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 depth = BigInt(1024)
override lazy val memWidth = 32 override lazy val memWidth = 32
override lazy val memMaskGran = Some(8) override lazy val memMaskGran = Some(8)
@@ -79,7 +95,10 @@ class Masks_FourTypes_MaskedMem_MaskedLib_SameMaskGran extends MacroCompilerSpec
compileExecuteAndTest(mem, lib, v, output) 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 depth = BigInt(1024)
override lazy val memWidth = 64 override lazy val memWidth = 64
override lazy val memMaskGran = Some(4) override lazy val memMaskGran = Some(4)
@@ -103,7 +122,11 @@ class Masks_BitMaskedMem_NonMaskedLib extends MacroCompilerSpec with HasSRAMGene
// FPGA-style byte-masked memories. // 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 width = 32
override lazy val memMaskGran = Some(32) override lazy val memMaskGran = Some(32)
override lazy val libMaskGran = Some(8) override lazy val libMaskGran = Some(8)
@@ -113,7 +136,11 @@ class Masks_FPGAStyle_32_8 extends MacroCompilerSpec with HasSRAMGenerator with
// Simple powers of two with bit-masked lib. // 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 width = 64
override lazy val memMaskGran = Some(8) override lazy val memMaskGran = Some(8)
override lazy val libMaskGran = Some(1) override lazy val libMaskGran = Some(1)
@@ -121,7 +148,11 @@ class Masks_PowersOfTwo_8_1 extends MacroCompilerSpec with HasSRAMGenerator with
compileExecuteAndTest(mem, lib, v, output) 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 width = 64
override lazy val memMaskGran = Some(16) override lazy val memMaskGran = Some(16)
override lazy val libMaskGran = Some(1) override lazy val libMaskGran = Some(1)
@@ -129,7 +160,11 @@ class Masks_PowersOfTwo_16_1 extends MacroCompilerSpec with HasSRAMGenerator wit
compileExecuteAndTest(mem, lib, v, output) 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 width = 64
override lazy val memMaskGran = Some(32) override lazy val memMaskGran = Some(32)
override lazy val libMaskGran = Some(1) override lazy val libMaskGran = Some(1)
@@ -137,7 +172,11 @@ class Masks_PowersOfTwo_32_1 extends MacroCompilerSpec with HasSRAMGenerator wit
compileExecuteAndTest(mem, lib, v, output) 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 width = 64
override lazy val memMaskGran = Some(64) override lazy val memMaskGran = Some(64)
override lazy val libMaskGran = Some(1) override lazy val libMaskGran = Some(1)
@@ -147,7 +186,11 @@ class Masks_PowersOfTwo_64_1 extends MacroCompilerSpec with HasSRAMGenerator wit
// Simple powers of two with non bit-masked lib. // 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 width = 128
override lazy val memMaskGran = Some(32) override lazy val memMaskGran = Some(32)
override lazy val libMaskGran = Some(4) override lazy val libMaskGran = Some(4)
@@ -155,7 +198,11 @@ class Masks_PowersOfTwo_32_4 extends MacroCompilerSpec with HasSRAMGenerator wit
compileExecuteAndTest(mem, lib, v, output) 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 width = 128
override lazy val memMaskGran = Some(32) override lazy val memMaskGran = Some(32)
override lazy val libMaskGran = Some(8) override lazy val libMaskGran = Some(8)
@@ -163,7 +210,11 @@ class Masks_PowersOfTwo_32_8 extends MacroCompilerSpec with HasSRAMGenerator wit
compileExecuteAndTest(mem, lib, v, output) 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 width = 128
override lazy val memMaskGran = Some(8) override lazy val memMaskGran = Some(8)
override lazy val libMaskGran = Some(8) override lazy val libMaskGran = Some(8)
@@ -173,7 +224,11 @@ class Masks_PowersOfTwo_8_8 extends MacroCompilerSpec with HasSRAMGenerator with
// Width as a multiple of the mask, bit-masked lib // 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 width = 20
override lazy val memMaskGran = Some(10) override lazy val memMaskGran = Some(10)
override lazy val libMaskGran = Some(1) override lazy val libMaskGran = Some(1)
@@ -181,16 +236,24 @@ class Masks_IntegerMaskMultiple_20_10 extends MacroCompilerSpec with HasSRAMGene
compileExecuteAndTest(mem, lib, v, output) 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 width = 21
override lazy val memMaskGran = Some(21) override lazy val memMaskGran = Some(21)
override lazy val libMaskGran = Some(7) 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) //~ 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 width = 21
override lazy val memMaskGran = Some(21) override lazy val memMaskGran = Some(21)
override lazy val libMaskGran = Some(1) override lazy val libMaskGran = Some(1)
@@ -198,7 +261,11 @@ class Masks_IntegerMaskMultiple_21_21 extends MacroCompilerSpec with HasSRAMGene
compileExecuteAndTest(mem, lib, v, output) 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 width = 84
override lazy val memMaskGran = Some(21) override lazy val memMaskGran = Some(21)
override lazy val libMaskGran = Some(1) override lazy val libMaskGran = Some(1)
@@ -206,7 +273,11 @@ class Masks_IntegerMaskMultiple_84_21 extends MacroCompilerSpec with HasSRAMGene
compileExecuteAndTest(mem, lib, v, output) 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 width = 92
override lazy val memMaskGran = Some(23) override lazy val memMaskGran = Some(23)
override lazy val libMaskGran = Some(1) override lazy val libMaskGran = Some(1)
@@ -214,7 +285,11 @@ class Masks_IntegerMaskMultiple_92_23 extends MacroCompilerSpec with HasSRAMGene
compileExecuteAndTest(mem, lib, v, output) 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 width = 117
override lazy val memMaskGran = Some(13) override lazy val memMaskGran = Some(13)
override lazy val libMaskGran = Some(1) override lazy val libMaskGran = Some(1)
@@ -222,7 +297,11 @@ class Masks_IntegerMaskMultiple_117_13 extends MacroCompilerSpec with HasSRAMGen
compileExecuteAndTest(mem, lib, v, output) 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 width = 160
override lazy val memMaskGran = Some(20) override lazy val memMaskGran = Some(20)
override lazy val libMaskGran = Some(1) override lazy val libMaskGran = Some(1)
@@ -230,7 +309,11 @@ class Masks_IntegerMaskMultiple_160_20 extends MacroCompilerSpec with HasSRAMGen
compileExecuteAndTest(mem, lib, v, output) 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 width = 184
override lazy val memMaskGran = Some(23) override lazy val memMaskGran = Some(23)
override lazy val libMaskGran = Some(1) override lazy val libMaskGran = Some(1)
@@ -240,11 +323,15 @@ class Masks_IntegerMaskMultiple_184_23 extends MacroCompilerSpec with HasSRAMGen
// Width as an non-integer multiple of the mask, bit-masked lib // 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 width = 32
override lazy val memMaskGran = Some(3) override lazy val memMaskGran = Some(3)
override lazy val libMaskGran = Some(1) 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) //~ compileExecuteAndTest(mem, lib, v, output)
} }

View File

@@ -13,42 +13,70 @@ class SplitWidth_2rw extends MacroCompilerSpec with HasSRAMGenerator with HasSim
override def generateMemSRAM() = { override def generateMemSRAM() = {
SRAMMacro( SRAMMacro(
name=mem_name, name = mem_name,
width=memWidth, width = memWidth,
depth=memDepth, depth = memDepth,
family="2rw", family = "2rw",
ports=Seq(generateTestPort( ports = Seq(
"portA", memWidth, Some(memDepth), maskGran=memMaskGran, generateTestPort(
write=true, writeEnable=true, "portA",
read=true, readEnable=true memWidth,
), generateTestPort( Some(memDepth),
"portB", memWidth, Some(memDepth), maskGran=memMaskGran, maskGran = memMaskGran,
write=true, writeEnable=true, write = true,
read=true, readEnable=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() = { override def generateLibSRAM() = {
SRAMMacro( SRAMMacro(
name=lib_name, name = lib_name,
width=libWidth, width = libWidth,
depth=libDepth, depth = libDepth,
family="2rw", family = "2rw",
ports=Seq(generateTestPort( ports = Seq(
"portA", libWidth, libDepth, generateTestPort(
write=true, writeEnable=true, "portA",
read=true, readEnable=true libWidth,
), generateTestPort( libDepth,
"portB", libWidth, libDepth, write = true,
write=true, writeEnable=true, writeEnable = true,
read=true, readEnable=true read = true,
)) readEnable = true
),
generateTestPort(
"portB",
libWidth,
libDepth,
write = true,
writeEnable = true,
read = true,
readEnable = true
)
)
) )
} }
override def generateHeaderPorts() = { 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() = { override def generateFooterPorts() = {
@@ -56,7 +84,7 @@ class SplitWidth_2rw extends MacroCompilerSpec with HasSRAMGenerator with HasSim
} }
override def generateBody() = override def generateBody() =
""" """
inst mem_0_0 of awesome_lib_mem inst mem_0_0 of awesome_lib_mem
inst mem_0_1 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem
inst mem_0_2 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() = { override def generateMemSRAM() = {
SRAMMacro( SRAMMacro(
name=mem_name, name = mem_name,
width=memWidth, width = memWidth,
depth=memDepth, depth = memDepth,
family="1r1w", family = "1r1w",
ports=Seq(generateTestPort( ports = Seq(
"portA", memWidth, Some(memDepth), maskGran=memMaskGran, generateTestPort(
write=false, writeEnable=false, "portA",
read=true, readEnable=true memWidth,
), generateTestPort( Some(memDepth),
"portB", memWidth, Some(memDepth), maskGran=memMaskGran, maskGran = memMaskGran,
write=true, writeEnable=true, write = false,
read=false, readEnable=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() = { override def generateLibSRAM() = {
SRAMMacro( SRAMMacro(
name=lib_name, name = lib_name,
width=libWidth, width = libWidth,
depth=libDepth, depth = libDepth,
family="1r1w", family = "1r1w",
ports=Seq(generateTestPort( ports = Seq(
"portA", libWidth, libDepth, generateTestPort(
write=false, writeEnable=false, "portA",
read=true, readEnable=true libWidth,
), generateTestPort( libDepth,
"portB", libWidth, libDepth, write = false,
write=true, writeEnable=true, writeEnable = false,
read=false, readEnable=false read = true,
)) readEnable = true
),
generateTestPort(
"portB",
libWidth,
libDepth,
write = true,
writeEnable = true,
read = false,
readEnable = false
)
)
) )
} }
override def generateHeaderPorts() = { override def generateHeaderPorts() = {
generatePort("portA", mem_addr_width, memWidth, generatePort(
write=false, writeEnable=false, read=true, readEnable=true, Some(memMaskBits)) + "\n" + "portA",
generatePort("portB", mem_addr_width, memWidth, mem_addr_width,
write=true, writeEnable=true, read=false, readEnable=false, Some(memMaskBits)) 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() = { override def generateFooterPorts() = {
generatePort("portA", lib_addr_width, libWidth, generatePort(
write=false, writeEnable=false, read=true, readEnable=true, None) + "\n" + "portA",
generatePort("portB", lib_addr_width, libWidth, lib_addr_width,
write=true, writeEnable=true, read=false, readEnable=false, None) 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() = override def generateBody() =
""" """
inst mem_0_0 of awesome_lib_mem inst mem_0_0 of awesome_lib_mem
inst mem_0_1 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem
inst mem_0_2 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() = { override def generateMemSRAM() = {
println(memMaskGranB) println(memMaskGranB)
SRAMMacro( SRAMMacro(
name=mem_name, name = mem_name,
width=memWidth, width = memWidth,
depth=memDepth, depth = memDepth,
family="2rw", family = "2rw",
ports=Seq(generateTestPort( ports = Seq(
"portA", memWidth, Some(memDepth), maskGran=memMaskGran, generateTestPort(
write=true, writeEnable=true, "portA",
read=true, readEnable=true memWidth,
), generateTestPort( Some(memDepth),
"portB", memWidth, Some(memDepth), maskGran=Some(memMaskGranB), maskGran = memMaskGran,
write=true, writeEnable=true, write = true,
read=true, readEnable=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() = { override def generateLibSRAM() = {
SRAMMacro( SRAMMacro(
name=lib_name, name = lib_name,
width=libWidth, width = libWidth,
depth=libDepth, depth = libDepth,
family="2rw", family = "2rw",
ports=Seq(generateTestPort( ports = Seq(
"portA", libWidth, libDepth, generateTestPort(
write=true, writeEnable=true, "portA",
read=true, readEnable=true libWidth,
), generateTestPort( libDepth,
"portB", libWidth, libDepth, write = true,
write=true, writeEnable=true, writeEnable = true,
read=true, readEnable=true read = true,
)) readEnable = true
),
generateTestPort(
"portB",
libWidth,
libDepth,
write = true,
writeEnable = true,
read = true,
readEnable = true
)
)
) )
} }
override def generateHeaderPorts() = { 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() = { override def generateFooterPorts() = {
@@ -277,7 +389,7 @@ class SplitWidth_2rw_differentMasks extends MacroCompilerSpec with HasSRAMGenera
} }
override def generateBody() = override def generateBody() =
""" """
inst mem_0_0 of awesome_lib_mem inst mem_0_0 of awesome_lib_mem
inst mem_0_1 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem
inst mem_0_2 of awesome_lib_mem inst mem_0_2 of awesome_lib_mem

View File

@@ -13,8 +13,7 @@ class SRAMCompiler extends MacroCompilerSpec with HasSRAMGenerator with HasSimpl
writeToLib(lib, Seq(compiler)) writeToLib(lib, Seq(compiler))
writeToMem(mem, Seq(generateSRAM("mymem", "X", 8, 16))) 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)
} }

View File

@@ -6,33 +6,36 @@ package barstools.macros
trait HasSimpleDepthTestGenerator extends HasSimpleTestGenerator { trait HasSimpleDepthTestGenerator extends HasSimpleTestGenerator {
this: MacroCompilerSpec with HasSRAMGenerator => this: MacroCompilerSpec with HasSRAMGenerator =>
def width: Int def width: Int
override lazy val memWidth = width override lazy val memWidth = width
override lazy val libWidth = width override lazy val libWidth = width
// Generate a depth-splitting body. // Generate a depth-splitting body.
override def generateBody(): String = { override def generateBody(): String = {
val output = new StringBuilder val output = new StringBuilder
if (selectBits > 0) { if (selectBits > 0) {
output.append ( output.append(
s""" s"""
node ${memPortPrefix}_addr_sel = bits(${memPortPrefix}_addr, ${mem_addr_width - 1}, $lib_addr_width) node ${memPortPrefix}_addr_sel = bits(${memPortPrefix}_addr, ${mem_addr_width - 1}, $lib_addr_width)
reg ${memPortPrefix}_addr_sel_reg : UInt<${selectBits}>, ${memPortPrefix}_clk with : reg ${memPortPrefix}_addr_sel_reg : UInt<${selectBits}>, ${memPortPrefix}_clk with :
reset => (UInt<1>("h0"), ${memPortPrefix}_addr_sel_reg) reset => (UInt<1>("h0"), ${memPortPrefix}_addr_sel_reg)
${memPortPrefix}_addr_sel_reg <= mux(UInt<1>("h1"), ${memPortPrefix}_addr_sel, ${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) { for (i <- 0 to depthInstances - 1) {
val maskStatement = generateMaskStatement(0, i) 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 enableIdentifier =
val chipEnable = s"""UInt<1>("h1")""" if (selectBits > 0) s"""eq(${memPortPrefix}_addr_sel, UInt<${selectBits}>("h${i.toHexString}"))"""
val writeEnable = if (memMaskGran.isEmpty) s"and(${memPortPrefix}_write_en, ${chipEnable})" else s"${memPortPrefix}_write_en" else "UInt<1>(\"h1\")"
output.append( val chipEnable = s"""UInt<1>("h1")"""
s""" 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} inst mem_${i}_0 of ${lib_name}
mem_${i}_0.${libPortPrefix}_clk <= ${memPortPrefix}_clk mem_${i}_0.${libPortPrefix}_clk <= ${memPortPrefix}_clk
mem_${i}_0.${libPortPrefix}_addr <= ${memPortPrefix}_addr mem_${i}_0.${libPortPrefix}_addr <= ${memPortPrefix}_addr
@@ -42,26 +45,29 @@ s"""
mem_${i}_0.${libPortPrefix}_write_en <= and(and(${writeEnable}, UInt<1>("h1")), ${enableIdentifier}) mem_${i}_0.${libPortPrefix}_write_en <= and(and(${writeEnable}, UInt<1>("h1")), ${enableIdentifier})
node ${memPortPrefix}_dout_${i} = ${memPortPrefix}_dout_${i}_0 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)
) )
} }
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)
} else {
output append s"""mux(UInt<1>("h1"), ${memPortPrefix}_dout_0, UInt<${libWidth}>("h0"))"""
}
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 // Try different widths
@@ -154,7 +160,10 @@ class SplitDepth2048x8_mrw_lib8 extends MacroCompilerSpec with HasSRAMGenerator
} }
// Non-bit level mask // 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 width = 64
override lazy val memDepth = BigInt(2048) override lazy val memDepth = BigInt(2048)
override lazy val libDepth = BigInt(1024) override lazy val libDepth = BigInt(1024)
@@ -165,7 +174,10 @@ class SplitDepth2048x64_mrw_mem32_lib8 extends MacroCompilerSpec with HasSRAMGen
} }
// Bit level mask // 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 width = 32
override lazy val memDepth = BigInt(2048) override lazy val memDepth = BigInt(2048)
override lazy val libDepth = BigInt(1024) override lazy val libDepth = BigInt(1024)
@@ -213,7 +225,7 @@ class SplitDepth2048x32_mrw_mem3_lib1 extends MacroCompilerSpec with HasSRAMGene
override lazy val memMaskGran = Some(3) override lazy val memMaskGran = Some(3)
override lazy val libMaskGran = Some(1) 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) //compileExecuteAndTest(mem, lib, v, output)
} }
@@ -224,7 +236,7 @@ class SplitDepth2048x32_mrw_mem7_lib1 extends MacroCompilerSpec with HasSRAMGene
override lazy val memMaskGran = Some(7) override lazy val memMaskGran = Some(7)
override lazy val libMaskGran = Some(1) 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) //compileExecuteAndTest(mem, lib, v, output)
} }
@@ -235,7 +247,7 @@ class SplitDepth2048x32_mrw_mem9_lib1 extends MacroCompilerSpec with HasSRAMGene
override lazy val memMaskGran = Some(9) override lazy val memMaskGran = Some(9)
override lazy val libMaskGran = Some(1) 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) //compileExecuteAndTest(mem, lib, v, output)
} }
@@ -247,12 +259,12 @@ class SplitDepth2048x8_extraPort extends MacroCompilerSpec with HasSRAMGenerator
override lazy val memDepth = BigInt(2048) override lazy val memDepth = BigInt(2048)
override lazy val libDepth = BigInt(1024) override lazy val libDepth = BigInt(1024)
override lazy val extraPorts = List( 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 lazy val extraTag = "extraPort"
override def generateOutput(): String = override def generateOutput(): String =
""" """
circuit target_memory : circuit target_memory :
module target_memory : module target_memory :
input outer_addr : UInt<11> input outer_addr : UInt<11>
@@ -317,22 +329,22 @@ class SplitDepth_SplitPortsNonMasked extends MacroCompilerSpec with HasSRAMGener
val v = "split_depth-r-w-split-lib-split-mem.v" val v = "split_depth-r-w-split-lib-split-mem.v"
val libMacro = SRAMMacro( val libMacro = SRAMMacro(
name="awesome_lib_mem", name = "awesome_lib_mem",
width=width, width = width,
depth=libDepth, depth = libDepth,
family="1r1w", family = "1r1w",
ports=Seq( ports = Seq(
generateReadPort("innerA", width, libDepth), generateReadPort("innerA", width, libDepth),
generateWritePort("innerB", width, libDepth) generateWritePort("innerB", width, libDepth)
) )
) )
val memMacro = SRAMMacro( val memMacro = SRAMMacro(
name="target_memory", name = "target_memory",
width=width, width = width,
depth=memDepth, depth = memDepth,
family="1r1w", family = "1r1w",
ports=Seq( ports = Seq(
generateReadPort("outerB", width, memDepth), generateReadPort("outerB", width, memDepth),
generateWritePort("outerA", width, memDepth) generateWritePort("outerA", width, memDepth)
) )
@@ -342,7 +354,7 @@ class SplitDepth_SplitPortsNonMasked extends MacroCompilerSpec with HasSRAMGener
writeToLib(lib, Seq(libMacro)) writeToLib(lib, Seq(libMacro))
val output = val output =
""" """
circuit target_memory : circuit target_memory :
module target_memory : module target_memory :
input outerB_addr : UInt<11> input outerB_addr : UInt<11>
@@ -404,11 +416,11 @@ circuit target_memory :
val v = "split_depth-r-w-regular-lib-split-mem.v" val v = "split_depth-r-w-regular-lib-split-mem.v"
val memMacro = SRAMMacro( val memMacro = SRAMMacro(
name="target_memory", name = "target_memory",
width=width, width = width,
depth=memDepth, depth = memDepth,
family="1r1w", family = "1r1w",
ports=Seq( ports = Seq(
generateReadPort("outerB", width, memDepth), generateReadPort("outerB", width, memDepth),
generateWritePort("outerA", width, memDepth) generateWritePort("outerA", width, memDepth)
) )
@@ -418,7 +430,7 @@ circuit target_memory :
writeToLib(lib, Seq(generateSRAM("awesome_lib_mem", "lib", width, libDepth))) writeToLib(lib, Seq(generateSRAM("awesome_lib_mem", "lib", width, libDepth)))
val output = val output =
""" """
TODO TODO
""" """
@@ -437,11 +449,11 @@ TODO
val v = "split_depth-r-w-split-lib-regular-mem.v" val v = "split_depth-r-w-split-lib-regular-mem.v"
val libMacro = SRAMMacro( val libMacro = SRAMMacro(
name="awesome_lib_mem", name = "awesome_lib_mem",
width=width, width = width,
depth=libDepth, depth = libDepth,
family="1rw", family = "1rw",
ports=Seq( ports = Seq(
generateReadPort("innerA", width, libDepth), generateReadPort("innerA", width, libDepth),
generateWritePort("innerB", width, libDepth) generateWritePort("innerB", width, libDepth)
) )
@@ -451,7 +463,7 @@ TODO
writeToLib(lib, Seq(libMacro)) writeToLib(lib, Seq(libMacro))
val output = val output =
""" """
TODO TODO
""" """
@@ -478,22 +490,22 @@ class SplitDepth_SplitPortsMasked extends MacroCompilerSpec with HasSRAMGenerato
val v = "split_depth-r-mw-split-lib-split-mem.v" val v = "split_depth-r-mw-split-lib-split-mem.v"
val libMacro = SRAMMacro( val libMacro = SRAMMacro(
name="awesome_lib_mem", name = "awesome_lib_mem",
width=width, width = width,
depth=libDepth, depth = libDepth,
family="1r1w", family = "1r1w",
ports=Seq( ports = Seq(
generateReadPort("innerA", width, libDepth), generateReadPort("innerA", width, libDepth),
generateWritePort("innerB", width, libDepth, libMaskGran) generateWritePort("innerB", width, libDepth, libMaskGran)
) )
) )
val memMacro = SRAMMacro( val memMacro = SRAMMacro(
name="target_memory", name = "target_memory",
width=width, width = width,
depth=memDepth, depth = memDepth,
family="1r1w", family = "1r1w",
ports=Seq( ports = Seq(
generateReadPort("outerB", width, memDepth), generateReadPort("outerB", width, memDepth),
generateWritePort("outerA", width, memDepth, memMaskGran) generateWritePort("outerA", width, memDepth, memMaskGran)
) )
@@ -503,7 +515,7 @@ class SplitDepth_SplitPortsMasked extends MacroCompilerSpec with HasSRAMGenerato
writeToLib(lib, Seq(libMacro)) writeToLib(lib, Seq(libMacro))
val output = val output =
""" """
circuit target_memory : circuit target_memory :
module target_memory : module target_memory :
input outerB_addr : UInt<11> input outerB_addr : UInt<11>
@@ -569,11 +581,11 @@ circuit target_memory :
val v = "split_depth-r-mw-regular-lib-split-mem.v" val v = "split_depth-r-mw-regular-lib-split-mem.v"
val memMacro = SRAMMacro( val memMacro = SRAMMacro(
name="target_memory", name = "target_memory",
width=width, width = width,
depth=memDepth, depth = memDepth,
family="1r1w", family = "1r1w",
ports=Seq( ports = Seq(
generateReadPort("outerB", width, memDepth), generateReadPort("outerB", width, memDepth),
generateWritePort("outerA", width, memDepth, memMaskGran) generateWritePort("outerA", width, memDepth, memMaskGran)
) )
@@ -583,7 +595,7 @@ circuit target_memory :
writeToLib(lib, Seq(generateSRAM("awesome_lib_mem", "lib", width, libDepth, libMaskGran))) writeToLib(lib, Seq(generateSRAM("awesome_lib_mem", "lib", width, libDepth, libMaskGran)))
val output = val output =
""" """
TODO TODO
""" """
@@ -602,11 +614,11 @@ TODO
val v = "split_depth-r-mw-split-lib-regular-mem.v" val v = "split_depth-r-mw-split-lib-regular-mem.v"
val libMacro = SRAMMacro( val libMacro = SRAMMacro(
name="awesome_lib_mem", name = "awesome_lib_mem",
width=width, width = width,
depth=libDepth, depth = libDepth,
family="1rw", family = "1rw",
ports=Seq( ports = Seq(
generateReadPort("innerA", width, libDepth), generateReadPort("innerA", width, libDepth),
generateWritePort("innerB", width, libDepth, libMaskGran) generateWritePort("innerB", width, libDepth, libMaskGran)
) )
@@ -616,7 +628,7 @@ TODO
writeToLib(lib, Seq(libMacro)) writeToLib(lib, Seq(libMacro))
val output = val output =
""" """
TODO TODO
""" """

View File

@@ -5,43 +5,45 @@ package barstools.macros
trait HasSimpleWidthTestGenerator extends HasSimpleTestGenerator { trait HasSimpleWidthTestGenerator extends HasSimpleTestGenerator {
this: MacroCompilerSpec with HasSRAMGenerator => this: MacroCompilerSpec with HasSRAMGenerator =>
def depth: BigInt def depth: BigInt
override lazy val memDepth = depth override lazy val memDepth = depth
override lazy val libDepth = depth override lazy val libDepth = depth
override def generateBody(): String = { override def generateBody(): String = {
val output = new StringBuilder val output = new StringBuilder
// Generate mem_0_<i> lines for number of width instances. // Generate mem_0_<i> lines for number of width instances.
output.append( output.append(
((0 to widthInstances - 1) map {i:Int => s""" ((0 to widthInstances - 1).map { i: Int =>
s"""
inst mem_0_${i} of ${lib_name} inst mem_0_${i} of ${lib_name}
""" """
}).reduceLeft(_ + _) }).reduceLeft(_ + _)
) )
// Generate submemory connection blocks. // Generate submemory connection blocks.
output append (for (i <- 0 to widthInstances - 1) yield { output.append((for (i <- 0 to widthInstances - 1) yield {
// Width of this submemory. // Width of this submemory.
val myMemWidth = if (i == widthInstances - 1) lastWidthBits else usableLibWidth val myMemWidth = if (i == widthInstances - 1) lastWidthBits else usableLibWidth
// Base bit of this submemory. // Base bit of this submemory.
// e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this // e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this
// would be 16. // would be 16.
val myBaseBit = usableLibWidth*i val myBaseBit = usableLibWidth * i
val maskStatement = generateMaskStatement(i, 0) val maskStatement = generateMaskStatement(i, 0)
// We need to use writeEnable as a crude "mask" if mem has a mask but // We need to use writeEnable as a crude "mask" if mem has a mask but
// lib does not. // lib does not.
val writeEnableBit = if (libMaskGran.isEmpty && memMaskGran.isDefined) { val writeEnableBit = if (libMaskGran.isEmpty && memMaskGran.isDefined) {
val outerMaskBit = myBaseBit / memMaskGran.get val outerMaskBit = myBaseBit / memMaskGran.get
s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})"
} else """UInt<1>("h1")""" } else """UInt<1>("h1")"""
val chipEnable = s"""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" val writeEnableExpr =
if (libMaskGran.isEmpty) s"and(${memPortPrefix}_write_en, ${chipEnable})" else s"${memPortPrefix}_write_en"
s""" s"""
mem_0_${i}.${libPortPrefix}_clk <= ${memPortPrefix}_clk mem_0_${i}.${libPortPrefix}_clk <= ${memPortPrefix}_clk
mem_0_${i}.${libPortPrefix}_addr <= ${memPortPrefix}_addr mem_0_${i}.${libPortPrefix}_addr <= ${memPortPrefix}_addr
node ${memPortPrefix}_dout_0_${i} = bits(mem_0_${i}.${libPortPrefix}_dout, ${myMemWidth - 1}, 0) node ${memPortPrefix}_dout_0_${i} = bits(mem_0_${i}.${libPortPrefix}_dout, ${myMemWidth - 1}, 0)
@@ -49,24 +51,23 @@ s"""
${maskStatement} ${maskStatement}
mem_0_${i}.${libPortPrefix}_write_en <= and(and(${writeEnableExpr}, ${writeEnableBit}), UInt<1>("h1")) mem_0_${i}.${libPortPrefix}_write_en <= and(and(${writeEnableExpr}, ${writeEnableBit}), UInt<1>("h1"))
""" """
}).reduceLeft(_ + _) }).reduceLeft(_ + _))
// Generate final output that concats together the sub-memories. // 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)) // e.g. cat(outer_dout_0_2, cat(outer_dout_0_1, outer_dout_0_0))
output append { output.append {
val doutStatements = ((widthInstances - 1 to 0 by -1) map (i => s"${memPortPrefix}_dout_0_${i}")) 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)") val catStmt = doutStatements.init.foldRight(doutStatements.last)((l: String, r: String) => s"cat($l, $r)")
s""" s"""
node ${memPortPrefix}_dout_0 = ${catStmt} node ${memPortPrefix}_dout_0 = ${catStmt}
""" """
}
output append
s"""
${memPortPrefix}_dout <= mux(UInt<1>("h1"), ${memPortPrefix}_dout_0, UInt<${memWidth}>("h0"))
"""
output.toString
} }
output.append(s"""
${memPortPrefix}_dout <= mux(UInt<1>("h1"), ${memPortPrefix}_dout_0, UInt<${memWidth}>("h0"))
""")
output.toString
}
} }
// Try different widths against a base memory width of 8. // Try different widths against a base memory width of 8.
@@ -268,7 +269,10 @@ class SplitWidth1024x16_mem11_rw extends MacroCompilerSpec with HasSRAMGenerator
// Masked RAM // 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 depth = BigInt(1024)
override lazy val memWidth = 8 override lazy val memWidth = 8
override lazy val libWidth = 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) 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 depth = BigInt(1024)
override lazy val memWidth = 16 override lazy val memWidth = 16
override lazy val libWidth = 8 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) 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 depth = BigInt(1024)
override lazy val memWidth = 16 override lazy val memWidth = 16
override lazy val libWidth = 8 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) 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 depth = BigInt(1024)
override lazy val memWidth = 128 override lazy val memWidth = 128
override lazy val libWidth = 32 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) 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 depth = BigInt(1024)
override lazy val memWidth = 16 override lazy val memWidth = 16
override lazy val libWidth = 8 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) 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 depth = BigInt(1024)
override lazy val memWidth = 16 override lazy val memWidth = 16
override lazy val libWidth = 8 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) 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 depth = BigInt(1024)
override lazy val memWidth = 16 override lazy val memWidth = 16
override lazy val libWidth = 8 override lazy val libWidth = 8
@@ -360,7 +382,10 @@ class SplitWidth1024x16_libGran_1_rw extends MacroCompilerSpec with HasSRAMGener
// Non-memMask and non-1 libMask // 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 depth = BigInt(1024)
override lazy val memWidth = 16 override lazy val memWidth = 16
override lazy val libWidth = 8 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 // 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 depth = BigInt(1024)
override lazy val memWidth = 16 override lazy val memWidth = 16
override lazy val libWidth = 8 override lazy val libWidth = 8
override lazy val memMaskGran = Some(9) override lazy val memMaskGran = Some(9)
override lazy val libMaskGran = Some(1) 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) //~ compile(mem, lib, v, false)
//~ execute(mem, lib, false, output) //~ execute(mem, lib, false, output)
} }
// Read enable // 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._ import mdf.macrolib._
override lazy val depth = BigInt(1024) override lazy val depth = BigInt(1024)
@@ -395,20 +426,27 @@ class SplitWidth1024x32_readEnable_Lib extends MacroCompilerSpec with HasSRAMGen
override def generateLibSRAM() = { override def generateLibSRAM() = {
SRAMMacro( SRAMMacro(
name=lib_name, name = lib_name,
width=libWidth, width = libWidth,
depth=libDepth, depth = libDepth,
family="1rw", family = "1rw",
ports=Seq(generateTestPort( ports = Seq(
"lib", Some(libWidth), Some(libDepth), maskGran=libMaskGran, generateTestPort(
write=true, writeEnable=true, "lib",
read=true, readEnable=true Some(libWidth),
)) Some(libDepth),
maskGran = libMaskGran,
write = true,
writeEnable = true,
read = true,
readEnable = true
)
)
) )
} }
override def generateBody() = override def generateBody() =
""" """
inst mem_0_0 of awesome_lib_mem inst mem_0_0 of awesome_lib_mem
inst mem_0_1 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem
inst mem_0_2 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) 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._ import mdf.macrolib._
override lazy val depth = BigInt(1024) override lazy val depth = BigInt(1024)
@@ -453,15 +494,22 @@ class SplitWidth1024x32_readEnable_Mem extends MacroCompilerSpec with HasSRAMGen
override def generateMemSRAM() = { override def generateMemSRAM() = {
SRAMMacro( SRAMMacro(
name=mem_name, name = mem_name,
width=memWidth, width = memWidth,
depth=memDepth, depth = memDepth,
family="1rw", family = "1rw",
ports=Seq(generateTestPort( ports = Seq(
"outer", Some(memWidth), Some(memDepth), maskGran=memMaskGran, generateTestPort(
write=true, writeEnable=true, "outer",
read=true, readEnable=true 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) 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._ import mdf.macrolib._
override lazy val depth = BigInt(1024) override lazy val depth = BigInt(1024)
@@ -479,34 +530,48 @@ class SplitWidth1024x32_readEnable_LibMem extends MacroCompilerSpec with HasSRAM
override def generateLibSRAM() = { override def generateLibSRAM() = {
SRAMMacro( SRAMMacro(
name=lib_name, name = lib_name,
width=libWidth, width = libWidth,
depth=libDepth, depth = libDepth,
family="1rw", family = "1rw",
ports=Seq(generateTestPort( ports = Seq(
"lib", Some(libWidth), Some(libDepth), maskGran=libMaskGran, generateTestPort(
write=true, writeEnable=true, "lib",
read=true, readEnable=true Some(libWidth),
)) Some(libDepth),
maskGran = libMaskGran,
write = true,
writeEnable = true,
read = true,
readEnable = true
)
)
) )
} }
override def generateMemSRAM() = { override def generateMemSRAM() = {
SRAMMacro( SRAMMacro(
name=mem_name, name = mem_name,
width=memWidth, width = memWidth,
depth=memDepth, depth = memDepth,
family="1rw", family = "1rw",
ports=Seq(generateTestPort( ports = Seq(
"outer", Some(memWidth), Some(memDepth), maskGran=memMaskGran, generateTestPort(
write=true, writeEnable=true, "outer",
read=true, readEnable=true Some(memWidth),
)) Some(memDepth),
maskGran = memMaskGran,
write = true,
writeEnable = true,
read = true,
readEnable = true
)
)
) )
} }
override def generateBody() = override def generateBody() =
""" """
inst mem_0_0 of awesome_lib_mem inst mem_0_0 of awesome_lib_mem
inst mem_0_1 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem
inst mem_0_2 of awesome_lib_mem inst mem_0_2 of awesome_lib_mem

View File

@@ -29,8 +29,8 @@ class WriteEnableTest extends MacroCompilerSpec with HasSRAMGenerator {
override val libPrefix = "macros/src/test/resources" override val libPrefix = "macros/src/test/resources"
val memSRAMs = mdf.macrolib.Utils.readMDFFromString( val memSRAMs = mdf.macrolib.Utils
""" .readMDFFromString("""
[ { [ {
"type" : "sram", "type" : "sram",
"name" : "cc_banks_0_ext", "name" : "cc_banks_0_ext",
@@ -58,7 +58,7 @@ class WriteEnableTest extends MacroCompilerSpec with HasSRAMGenerator {
writeToMem(mem, memSRAMs) writeToMem(mem, memSRAMs)
val output = val output =
""" """
circuit cc_banks_0_ext : circuit cc_banks_0_ext :
module cc_banks_0_ext : module cc_banks_0_ext :
input RW0_addr : UInt<12> input RW0_addr : UInt<12>
@@ -99,8 +99,8 @@ class MaskPortTest extends MacroCompilerSpec with HasSRAMGenerator {
override val libPrefix = "macros/src/test/resources" override val libPrefix = "macros/src/test/resources"
val memSRAMs = mdf.macrolib.Utils.readMDFFromString( val memSRAMs = mdf.macrolib.Utils
""" .readMDFFromString("""
[ { [ {
"type" : "sram", "type" : "sram",
"name" : "cc_dir_ext", "name" : "cc_dir_ext",
@@ -131,7 +131,7 @@ class MaskPortTest extends MacroCompilerSpec with HasSRAMGenerator {
writeToMem(mem, memSRAMs) writeToMem(mem, memSRAMs)
val output = val output =
""" """
circuit cc_dir_ext : circuit cc_dir_ext :
module cc_dir_ext : module cc_dir_ext :
input RW0_addr : UInt<9> input RW0_addr : UInt<9>
@@ -183,8 +183,8 @@ class BOOMTest extends MacroCompilerSpec with HasSRAMGenerator {
override val libPrefix = "macros/src/test/resources" override val libPrefix = "macros/src/test/resources"
val memSRAMs = mdf.macrolib.Utils.readMDFFromString( val memSRAMs = mdf.macrolib.Utils
""" .readMDFFromString("""
[ { [ {
"type" : "sram", "type" : "sram",
"name" : "_T_182_ext", "name" : "_T_182_ext",
@@ -354,7 +354,7 @@ class BOOMTest extends MacroCompilerSpec with HasSRAMGenerator {
writeToMem(mem, memSRAMs) writeToMem(mem, memSRAMs)
val output = // TODO: check correctness... val output = // TODO: check correctness...
""" """
circuit smem_0_ext : circuit smem_0_ext :
module _T_182_ext : module _T_182_ext :
input R0_addr : UInt<6> input R0_addr : UInt<6>
@@ -1350,14 +1350,14 @@ circuit smem_0_ext :
class SmallTagArrayTest extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleTestGenerator { class SmallTagArrayTest extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleTestGenerator {
// Test that mapping a smaller memory using a larger lib can still work. // Test that mapping a smaller memory using a larger lib can still work.
override def memWidth: Int = 26 override def memWidth: Int = 26
override def memDepth: BigInt = BigInt(2) override def memDepth: BigInt = BigInt(2)
override def memMaskGran: Option[Int] = Some(26) override def memMaskGran: Option[Int] = Some(26)
override def memPortPrefix: String = "" override def memPortPrefix: String = ""
override def libWidth: Int = 32 override def libWidth: Int = 32
override def libDepth: BigInt = BigInt(64) override def libDepth: BigInt = BigInt(64)
override def libMaskGran: Option[Int] = Some(1) override def libMaskGran: Option[Int] = Some(1)
override def libPortPrefix: String = "" override def libPortPrefix: String = ""
override def extraPorts: Seq[MacroExtraPort] = Seq( override def extraPorts: Seq[MacroExtraPort] = Seq(
@@ -1388,73 +1388,73 @@ class RocketChipTest extends MacroCompilerSpec with HasSRAMGenerator {
val libSRAMs = Seq( val libSRAMs = Seq(
SRAMMacro( SRAMMacro(
name="SRAM1RW1024x8", name = "SRAM1RW1024x8",
depth=1024, depth = 1024,
width=8, width = 8,
family="1rw", family = "1rw",
ports=Seq( ports = Seq(
generateReadWritePort("", 8, BigInt(1024)) generateReadWritePort("", 8, BigInt(1024))
) )
), ),
SRAMMacro( SRAMMacro(
name="SRAM1RW512x32", name = "SRAM1RW512x32",
depth=512, depth = 512,
width=32, width = 32,
family="1rw", family = "1rw",
ports=Seq( ports = Seq(
generateReadWritePort("", 32, BigInt(512)) generateReadWritePort("", 32, BigInt(512))
) )
), ),
SRAMMacro( SRAMMacro(
name="SRAM1RW64x128", name = "SRAM1RW64x128",
depth=64, depth = 64,
width=128, width = 128,
family="1rw", family = "1rw",
ports=Seq( ports = Seq(
generateReadWritePort("", 128, BigInt(64)) generateReadWritePort("", 128, BigInt(64))
) )
), ),
SRAMMacro( SRAMMacro(
name="SRAM1RW64x32", name = "SRAM1RW64x32",
depth=64, depth = 64,
width=32, width = 32,
family="1rw", family = "1rw",
ports=Seq( ports = Seq(
generateReadWritePort("", 32, BigInt(64)) generateReadWritePort("", 32, BigInt(64))
) )
), ),
SRAMMacro( SRAMMacro(
name="SRAM1RW64x8", name = "SRAM1RW64x8",
depth=64, depth = 64,
width=8, width = 8,
family="1rw", family = "1rw",
ports=Seq( ports = Seq(
generateReadWritePort("", 8, BigInt(64)) generateReadWritePort("", 8, BigInt(64))
) )
), ),
SRAMMacro( SRAMMacro(
name="SRAM1RW512x8", name = "SRAM1RW512x8",
depth=512, depth = 512,
width=8, width = 8,
family="1rw", family = "1rw",
ports=Seq( ports = Seq(
generateReadWritePort("", 8, BigInt(512)) generateReadWritePort("", 8, BigInt(512))
) )
), ),
SRAMMacro( SRAMMacro(
name="SRAM2RW64x32", name = "SRAM2RW64x32",
depth=64, depth = 64,
width=32, width = 32,
family="1r1w", family = "1r1w",
ports=Seq( ports = Seq(
generateReadPort("portA", 32, BigInt(64)), generateReadPort("portA", 32, BigInt(64)),
generateWritePort("portB", 32, BigInt(64)) generateWritePort("portB", 32, BigInt(64))
) )
) )
) )
val memSRAMs = mdf.macrolib.Utils.readMDFFromString( val memSRAMs = mdf.macrolib.Utils
""" .readMDFFromString("""
[ [
{ {
"type": "sram", "type": "sram",
@@ -1537,7 +1537,7 @@ class RocketChipTest extends MacroCompilerSpec with HasSRAMGenerator {
writeToMem(mem, memSRAMs) writeToMem(mem, memSRAMs)
val output = // TODO: check correctness... val output = // TODO: check correctness...
""" """
circuit T_2172_ext : circuit T_2172_ext :
module tag_array_ext : module tag_array_ext :
input RW0_addr : UInt<6> input RW0_addr : UInt<6>

View File

@@ -4,13 +4,13 @@ package barstools.macros
trait HasSynFlopsTestGenerator extends HasSimpleTestGenerator { trait HasSynFlopsTestGenerator extends HasSimpleTestGenerator {
this: MacroCompilerSpec with HasSRAMGenerator => this: MacroCompilerSpec with HasSRAMGenerator =>
def generateFlops: String = { def generateFlops: String = {
s""" s"""
inst mem_0_0 of split_${lib_name} inst mem_0_0 of split_${lib_name}
mem_0_0.${libPortPrefix}_clk <= ${libPortPrefix}_clk mem_0_0.${libPortPrefix}_clk <= ${libPortPrefix}_clk
mem_0_0.${libPortPrefix}_addr <= ${libPortPrefix}_addr mem_0_0.${libPortPrefix}_addr <= ${libPortPrefix}_addr
node ${libPortPrefix}_dout_0_0 = bits(mem_0_0.${libPortPrefix}_dout, ${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}_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")) 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 node ${libPortPrefix}_dout_0 = ${libPortPrefix}_dout_0_0
${libPortPrefix}_dout <= mux(UInt<1>("h1"), ${libPortPrefix}_dout_0, UInt<${libWidth}>("h0")) ${libPortPrefix}_dout <= mux(UInt<1>("h1"), ${libPortPrefix}_dout_0, UInt<${libWidth}>("h0"))
@@ -37,49 +37,66 @@ s"""
${libPortPrefix}_dout <= ram.RW_0.rdata ${libPortPrefix}_dout <= ram.RW_0.rdata
ram.RW_0.wdata <= ${libPortPrefix}_din ram.RW_0.wdata <= ${libPortPrefix}_din
""" """
} }
// If there is no lib, put the flops definition into the body. // If there is no lib, put the flops definition into the body.
abstract override def generateBody = { abstract override def generateBody = {
if (this.isInstanceOf[HasNoLibTestGenerator]) generateFlops else super.generateBody if (this.isInstanceOf[HasNoLibTestGenerator]) generateFlops else super.generateBody
} }
// If there is no lib, don't generate a footer, since the flops definition // If there is no lib, don't generate a footer, since the flops definition
// will be in the body. // will be in the body.
override def generateFooter = { override def generateFooter = {
if (this.isInstanceOf[HasNoLibTestGenerator]) "" else if (this.isInstanceOf[HasNoLibTestGenerator]) ""
s""" else
s"""
module ${lib_name} : module ${lib_name} :
${generateFooterPorts} ${generateFooterPorts}
${generateFlops} ${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 memDepth = BigInt(2048)
override lazy val memWidth = 8 override lazy val memWidth = 8
compileExecuteAndTest(mem, None, v, output, true) 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 memDepth = BigInt(2048)
override lazy val memWidth = 16 override lazy val memWidth = 16
compileExecuteAndTest(mem, None, v, output, true) 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 memDepth = BigInt(8192)
override lazy val memWidth = 16 override lazy val memWidth = 16
compileExecuteAndTest(mem, None, v, output, true) 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 memDepth = BigInt(2048)
override lazy val libDepth = BigInt(1024) override lazy val libDepth = BigInt(1024)
override lazy val width = 16 override lazy val width = 16
@@ -87,7 +104,11 @@ class Synflops2048x16_depth_Lib extends MacroCompilerSpec with HasSRAMGenerator
compileExecuteAndTest(mem, lib, v, output, true) 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 memWidth = 64
override lazy val libWidth = 8 override lazy val libWidth = 8
override lazy val depth = BigInt(1024) override lazy val depth = BigInt(1024)
@@ -95,7 +116,11 @@ class Synflops2048x64_width_Lib extends MacroCompilerSpec with HasSRAMGenerator
compileExecuteAndTest(mem, lib, v, output, true) 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._ import mdf.macrolib._
override lazy val memDepth = BigInt(2048) 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 lazy val width = 8
override def generateLibSRAM = SRAMMacro( override def generateLibSRAM = SRAMMacro(
name=lib_name, name = lib_name,
width=width, width = width,
depth=libDepth, depth = libDepth,
family="1r1w", family = "1r1w",
ports=Seq( ports = Seq(
generateReadPort("innerA", width, libDepth), generateReadPort("innerA", width, libDepth),
generateWritePort("innerB", width, libDepth) generateWritePort("innerB", width, libDepth)
) )
) )
override def generateMemSRAM = SRAMMacro( override def generateMemSRAM = SRAMMacro(
name=mem_name, name = mem_name,
width=width, width = width,
depth=memDepth, depth = memDepth,
family="1r1w", family = "1r1w",
ports=Seq( ports = Seq(
generateReadPort("outerB", width, memDepth), generateReadPort("outerB", width, memDepth),
generateWritePort("outerA", width, memDepth) generateWritePort("outerA", width, memDepth)
) )
) )
override def generateHeader = override def generateHeader =
""" """
circuit target_memory : circuit target_memory :
module target_memory : module target_memory :
input outerB_addr : UInt<11> input outerB_addr : UInt<11>
@@ -138,7 +163,7 @@ circuit target_memory :
""" """
override def generateBody = override def generateBody =
""" """
node outerB_addr_sel = bits(outerB_addr, 10, 10) node outerB_addr_sel = bits(outerB_addr, 10, 10)
reg outerB_addr_sel_reg : UInt<1>, outerB_clk with : reg outerB_addr_sel_reg : UInt<1>, outerB_clk with :
reset => (UInt<1>("h0"), outerB_addr_sel_reg) reset => (UInt<1>("h0"), outerB_addr_sel_reg)
@@ -166,7 +191,7 @@ circuit target_memory :
""" """
override def generateFooterPorts = override def generateFooterPorts =
""" """
input innerA_addr : UInt<10> input innerA_addr : UInt<10>
input innerA_clk : Clock input innerA_clk : Clock
output innerA_dout : UInt<8> output innerA_dout : UInt<8>
@@ -177,7 +202,7 @@ circuit target_memory :
""" """
override def generateFlops = override def generateFlops =
""" """
inst mem_0_0 of split_awesome_lib_mem inst mem_0_0 of split_awesome_lib_mem
mem_0_0.innerB_clk <= innerB_clk mem_0_0.innerB_clk <= innerB_clk
mem_0_0.innerB_addr <= innerB_addr 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._ import mdf.macrolib._
override lazy val memDepth = BigInt(2048) 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 lazy val libMaskGran = Some(1)
override def generateLibSRAM = SRAMMacro( override def generateLibSRAM = SRAMMacro(
name=lib_name, name = lib_name,
width=width, width = width,
depth=libDepth, depth = libDepth,
family="1r1w", family = "1r1w",
ports=Seq( ports = Seq(
generateReadPort("innerA", width, libDepth), generateReadPort("innerA", width, libDepth),
generateWritePort("innerB", width, libDepth, libMaskGran) generateWritePort("innerB", width, libDepth, libMaskGran)
) )
) )
override def generateMemSRAM = SRAMMacro( override def generateMemSRAM = SRAMMacro(
name=mem_name, name = mem_name,
width=width, width = width,
depth=memDepth, depth = memDepth,
family="1r1w", family = "1r1w",
ports=Seq( ports = Seq(
generateReadPort("outerB", width, memDepth), generateReadPort("outerB", width, memDepth),
generateWritePort("outerA", width, memDepth, memMaskGran) generateWritePort("outerA", width, memDepth, memMaskGran)
) )
) )
override def generateHeader = override def generateHeader =
""" """
circuit target_memory : circuit target_memory :
module target_memory : module target_memory :
input outerB_addr : UInt<11> input outerB_addr : UInt<11>
@@ -268,7 +297,7 @@ circuit target_memory :
""" """
override def generateBody = override def generateBody =
""" """
node outerB_addr_sel = bits(outerB_addr, 10, 10) node outerB_addr_sel = bits(outerB_addr, 10, 10)
reg outerB_addr_sel_reg : UInt<1>, outerB_clk with : reg outerB_addr_sel_reg : UInt<1>, outerB_clk with :
reset => (UInt<1>("h0"), outerB_addr_sel_reg) reset => (UInt<1>("h0"), outerB_addr_sel_reg)
@@ -298,7 +327,7 @@ circuit target_memory :
""" """
override def generateFooterPorts = override def generateFooterPorts =
""" """
input innerA_addr : UInt<10> input innerA_addr : UInt<10>
input innerA_clk : Clock input innerA_clk : Clock
output innerA_dout : UInt<8> output innerA_dout : UInt<8>
@@ -310,7 +339,7 @@ circuit target_memory :
""" """
override def generateFlops = override def generateFlops =
""" """
inst mem_0_0 of split_awesome_lib_mem inst mem_0_0 of split_awesome_lib_mem
inst mem_0_1 of split_awesome_lib_mem inst mem_0_1 of split_awesome_lib_mem
inst mem_0_2 of split_awesome_lib_mem inst mem_0_2 of split_awesome_lib_mem