diff --git a/macros/src/main/scala/barstools/macros/CostMetric.scala b/macros/src/main/scala/barstools/macros/CostMetric.scala index 45020163..f39303d3 100644 --- a/macros/src/main/scala/barstools/macros/CostMetric.scala +++ b/macros/src/main/scala/barstools/macros/CostMetric.scala @@ -2,27 +2,25 @@ package barstools.macros -/** - * Trait which can calculate the cost of compiling a memory against a certain - * library memory macro using a cost function. - */ +/** Trait which can calculate the cost of compiling a memory against a certain + * library memory macro using a cost function. + */ // TODO: eventually explore compiling a single target memory using multiple // different kinds of target memory. trait CostMetric extends Serializable { - /** - * Cost function that returns the cost of compiling a memory using a certain - * macro. - * - * @param mem Memory macro to compile (target memory) - * @param lib Library memory macro to use (library memory) - * @return The cost of this compile, defined by this cost metric, or None if - * it cannot be compiled. - */ + + /** Cost function that returns the cost of compiling a memory using a certain + * macro. + * + * @param mem Memory macro to compile (target memory) + * @param lib Library memory macro to use (library memory) + * @return The cost of this compile, defined by this cost metric, or None if + * it cannot be compiled. + */ def cost(mem: Macro, lib: Macro): Option[Double] - /** - * Helper function to return the map of arguments (or an empty map if there are none). - */ + /** Helper function to return the map of arguments (or an empty map if there are none). + */ def commandLineParams(): Map[String, String] // We also want this to show up for the class itself. @@ -40,8 +38,9 @@ trait CostMetricCompanion { // Some default cost functions. /** Palmer's old metric. - * TODO: figure out what is the difference between this metric and the current - * default metric and either revive or delete this metric. */ + * TODO: figure out what is the difference between this metric and the current + * default metric and either revive or delete this metric. + */ object OldMetric extends CostMetric with CostMetricCompanion { override def cost(mem: Macro, lib: Macro): Option[Double] = { /* Palmer: A quick cost function (that must be kept in sync with @@ -58,13 +57,12 @@ object OldMetric extends CostMetric with CostMetricCompanion { override def construct(m: Map[String, String]) = OldMetric } -/** - * An external cost function. - * Calls the specified path with paths to the JSON MDF representation of the mem - * and lib macros. The external executable should print a Double. - * None will be returned if the external executable does not print a valid - * Double. - */ +/** An external cost function. + * Calls the specified path with paths to the JSON MDF representation of the mem + * and lib macros. The external executable should print a Double. + * None will be returned if the external executable does not print a valid + * Double. + */ class ExternalMetric(path: String) extends CostMetric { import mdf.macrolib.Utils.writeMacroToPath @@ -105,7 +103,7 @@ object ExternalMetric extends CostMetricCompanion { override def construct(m: Map[String, String]) = { val pathOption = m.get("path") pathOption match { - case Some(path:String) => new ExternalMetric(path) + case Some(path: String) => new ExternalMetric(path) case _ => throw new IllegalArgumentException("ExternalMetric missing option 'path'") } } @@ -115,14 +113,17 @@ object ExternalMetric extends CostMetricCompanion { // TODO: write tests for this function to make sure it selects the right things object DefaultMetric extends CostMetric with CostMetricCompanion { override def cost(mem: Macro, lib: Macro): Option[Double] = { - val memMask = mem.src.ports map (_.maskGran) find (_.isDefined) map (_.get) - val libMask = lib.src.ports map (_.maskGran) find (_.isDefined) map (_.get) + val memMask = mem.src.ports.map(_.maskGran).find(_.isDefined).map(_.get) + val libMask = lib.src.ports.map(_.maskGran).find(_.isDefined).map(_.get) val memWidth = (memMask, libMask) match { case (None, _) => mem.src.width - case (Some(p), None) => (mem.src.width/p)*math.ceil(p.toDouble/lib.src.width)*lib.src.width //We map the mask to distinct memories + case (Some(p), None) => + (mem.src.width / p) * math.ceil( + p.toDouble / lib.src.width + ) * lib.src.width //We map the mask to distinct memories case (Some(p), Some(m)) => { - if(m <= p) (mem.src.width/p)*math.ceil(p.toDouble/m)*m //Using multiple m's to create a p (integeraly) - else (mem.src.width/p)*m //Waste the extra maskbits + if (m <= p) (mem.src.width / p) * math.ceil(p.toDouble / m) * m //Using multiple m's to create a p (integeraly) + else (mem.src.width / p) * m //Waste the extra maskbits } } val depthCost = math.ceil(mem.src.depth.toDouble / lib.src.depth.toDouble) @@ -130,10 +131,10 @@ object DefaultMetric extends CostMetric with CostMetricCompanion { val bitsCost = (lib.src.depth * lib.src.width).toDouble // Fraction of wasted bits plus const per mem val requestedBits = (mem.src.depth * mem.src.width).toDouble - val bitsWasted = depthCost*widthCost*bitsCost - requestedBits + val bitsWasted = depthCost * widthCost * bitsCost - requestedBits val wastedConst = 0.05 // 0 means waste as few bits with no regard for instance count - val costPerInst = wastedConst*depthCost*widthCost - Some(1.0*bitsWasted/requestedBits+costPerInst) + val costPerInst = wastedConst * depthCost * widthCost + Some(1.0 * bitsWasted / requestedBits + costPerInst) } override def commandLineParams = Map() @@ -148,10 +149,11 @@ object MacroCompilerUtil { // Adapted from https://stackoverflow.com/a/134918 /** Serialize an arbitrary object to String. - * Used to pass structured values through as an annotation. */ + * Used to pass structured values through as an annotation. + */ def objToString(o: Serializable): String = { val baos: ByteArrayOutputStream = new ByteArrayOutputStream - val oos: ObjectOutputStream = new ObjectOutputStream(baos) + val oos: ObjectOutputStream = new ObjectOutputStream(baos) oos.writeObject(o) oos.close() return Base64.getEncoder.encodeToString(baos.toByteArray) @@ -168,6 +170,7 @@ object MacroCompilerUtil { } object CostMetric { + /** Define some default metric. */ val default: CostMetric = DefaultMetric @@ -178,11 +181,10 @@ object CostMetric { registerCostMetric(ExternalMetric) registerCostMetric(DefaultMetric) - /** - * Register a cost metric. - * @param createFuncHelper Companion object to fetch the name and construct - * the metric. - */ + /** Register a cost metric. + * @param createFuncHelper Companion object to fetch the name and construct + * the metric. + */ def registerCostMetric(createFuncHelper: CostMetricCompanion): Unit = { costMetricCreators.update(createFuncHelper.name, createFuncHelper) } diff --git a/macros/src/main/scala/barstools/macros/MacroCompiler.scala b/macros/src/main/scala/barstools/macros/MacroCompiler.scala index 416f2d2c..5ecfea8f 100644 --- a/macros/src/main/scala/barstools/macros/MacroCompiler.scala +++ b/macros/src/main/scala/barstools/macros/MacroCompiler.scala @@ -1,10 +1,9 @@ // See LICENSE for license details. -/** - * Terminology note: - * mem - target memory to compile, in design (e.g. Mem() in rocket) - * lib - technology SRAM(s) to use to compile mem - */ +/** Terminology note: + * mem - target memory to compile, in design (e.g. Mem() in rocket) + * lib - technology SRAM(s) to use to compile mem + */ package barstools.macros @@ -29,56 +28,75 @@ case class MacroCompilerAnnotation(content: String) extends NoTargetAnnotation { def params: Params = MacroCompilerUtil.objFromString(content).asInstanceOf[Params] } - -/** - * The MacroCompilerAnnotation to trigger the macro compiler. - * Note that this annotation does NOT actually target any modules for - * compilation. It simply holds all the settings for the memory compiler. The - * actual selection of which memories to compile is set in the Params. - * - * To use, simply annotate the entire circuit itself with this annotation and - * include [[MacroCompilerTransform]]. - * - */ +/** The MacroCompilerAnnotation to trigger the macro compiler. + * Note that this annotation does NOT actually target any modules for + * compilation. It simply holds all the settings for the memory compiler. The + * actual selection of which memories to compile is set in the Params. + * + * To use, simply annotate the entire circuit itself with this annotation and + * include [[MacroCompilerTransform]]. + */ object MacroCompilerAnnotation { + /** Macro compiler mode. */ sealed trait CompilerMode + /** Strict mode - must compile all memories or error out. */ case object Strict extends CompilerMode + /** Synflops mode - compile all memories with synflops (do not map to lib at all). */ case object Synflops extends CompilerMode + /** CompileAndSynflops mode - compile all memories and create mock versions of the target libs with synflops. */ case object CompileAndSynflops extends CompilerMode - /** FallbackSynflops - compile all memories to SRAM when possible and fall back to synflops if a memory fails. **/ + + /** FallbackSynflops - compile all memories to SRAM when possible and fall back to synflops if a memory fails. * */ case object FallbackSynflops extends CompilerMode - /** CompileAvailable - compile what is possible and do nothing with uncompiled memories. **/ + + /** CompileAvailable - compile what is possible and do nothing with uncompiled memories. * */ case object CompileAvailable extends CompilerMode - /** - * The default mode for the macro compiler. - * TODO: Maybe set the default to FallbackSynflops (typical for - * vlsi_mem_gen-like scripts) once it's implemented? - */ + /** The default mode for the macro compiler. + * TODO: Maybe set the default to FallbackSynflops (typical for + * vlsi_mem_gen-like scripts) once it's implemented? + */ val Default = CompileAvailable // Options as list of (CompilerMode, command-line name, description) val options: Seq[(CompilerMode, String, String)] = Seq( (Default, "default", "Select the default option from below."), (Strict, "strict", "Compile all memories to library or return an error."), - (Synflops, "synflops", "Produces synthesizable flop-based memories for all memories (do not map to lib at all); likely useful for simulation purposes."), - (CompileAndSynflops, "compileandsynflops", "Compile all memories and create mock versions of the target libs with synflops; likely also useful for simulation purposes."), - (FallbackSynflops, "fallbacksynflops", "Compile all memories to library when possible and fall back to synthesizable flop-based memories when library synth is not possible."), - (CompileAvailable, "compileavailable", "Compile all memories to library when possible and do nothing in case of errors. (default)") + ( + Synflops, + "synflops", + "Produces synthesizable flop-based memories for all memories (do not map to lib at all); likely useful for simulation purposes." + ), + ( + CompileAndSynflops, + "compileandsynflops", + "Compile all memories and create mock versions of the target libs with synflops; likely also useful for simulation purposes." + ), + ( + FallbackSynflops, + "fallbacksynflops", + "Compile all memories to library when possible and fall back to synthesizable flop-based memories when library synth is not possible." + ), + ( + CompileAvailable, + "compileavailable", + "Compile all memories to library when possible and do nothing in case of errors. (default)" + ) ) /** Helper function to select a compiler mode. */ - def stringToCompilerMode(str: String): CompilerMode = options.collectFirst { case (mode, cmd, _) if cmd == str => mode } match { + def stringToCompilerMode(str: String): CompilerMode = options.collectFirst { + case (mode, cmd, _) if cmd == str => mode + } match { case Some(x) => x - case None => throw new IllegalArgumentException("No such compiler mode " + str) + case None => throw new IllegalArgumentException("No such compiler mode " + str) } - /** - * Parameters associated to this MacroCompilerAnnotation. + /** Parameters associated to this MacroCompilerAnnotation. * * @param mem Path to memory lib * @param memFormat Type of memory lib (Some("conf"), Some("mdf"), or None (defaults to mdf)) @@ -89,26 +107,34 @@ object MacroCompilerAnnotation { * @param forceCompile Set of memories to force compiling to lib regardless of the mode * @param forceSynflops Set of memories to force compiling as flops regardless of the mode */ - case class Params(mem: String, memFormat: Option[String], lib: Option[String], hammerIR: Option[String], - costMetric: CostMetric, mode: CompilerMode, useCompiler: Boolean, - forceCompile: Set[String], forceSynflops: Set[String]) + case class Params( + mem: String, + memFormat: Option[String], + lib: Option[String], + hammerIR: Option[String], + costMetric: CostMetric, + mode: CompilerMode, + useCompiler: Boolean, + forceCompile: Set[String], + forceSynflops: Set[String]) - /** - * Create a MacroCompilerAnnotation. - * @param c Top-level circuit name (see class description) - * @param p Parameters (see above). - */ + /** Create a MacroCompilerAnnotation. + * @param c Top-level circuit name (see class description) + * @param p Parameters (see above). + */ def apply(c: String, p: Params): MacroCompilerAnnotation = MacroCompilerAnnotation(MacroCompilerUtil.objToString(p)) } -class MacroCompilerPass(mems: Option[Seq[Macro]], - libs: Option[Seq[Macro]], - compilers: Option[SRAMCompiler], - hammerIR: Option[String], - costMetric: CostMetric = CostMetric.default, - mode: MacroCompilerAnnotation.CompilerMode = MacroCompilerAnnotation.Default) extends firrtl.passes.Pass { +class MacroCompilerPass( + mems: Option[Seq[Macro]], + libs: Option[Seq[Macro]], + compilers: Option[SRAMCompiler], + hammerIR: Option[String], + costMetric: CostMetric = CostMetric.default, + mode: MacroCompilerAnnotation.CompilerMode = MacroCompilerAnnotation.Default) + extends firrtl.passes.Pass { // Helper function to check the legality of bitPairs. // e.g. ((0,21), (22,43)) is legal // ((0,21), (22,21)) is illegal and will throw an assert @@ -120,8 +146,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], }) } - /** - * Calculate bit pairs. + /** Calculate bit pairs. * This is a list of submemories by width. * The tuples are (lsb, msb) inclusive. * Example: (0, 7) and (8, 15) might be a split for a width=16 memory into two width=8 target memories. @@ -132,7 +157,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], * @return Bit pairs or empty list if there was an error. */ private def calculateBitPairs(mem: Macro, lib: Macro): Seq[(BigInt, BigInt)] = { - val pairedPorts = mem.sortedPorts zip lib.sortedPorts + val pairedPorts = mem.sortedPorts.zip(lib.sortedPorts) val bitPairs = ArrayBuffer[(BigInt, BigInt)]() var currentLSB: BigInt = 0 @@ -203,7 +228,9 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], splitMemory(memMask.get) } else { // e.g. mem mask = 13, lib width = 8 - System.err.println(s"Unmasked target memory: unaligned mem maskGran $p with lib (${lib.src.name}) width ${libPort.src.width.get} not supported") + System.err.println( + s"Unmasked target memory: unaligned mem maskGran $p with lib (${lib.src.name}) width ${libPort.src.width.get} not supported" + ) return Seq() } } @@ -266,9 +293,11 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], } def compile(mem: Macro, lib: Macro): Option[(Module, Macro)] = { - assert(mem.sortedPorts.lengthCompare(lib.sortedPorts.length) == 0, - "mem and lib should have an equal number of ports") - val pairedPorts = mem.sortedPorts zip lib.sortedPorts + assert( + mem.sortedPorts.lengthCompare(lib.sortedPorts.length) == 0, + "mem and lib should have an equal number of ports" + ) + val pairedPorts = mem.sortedPorts.zip(lib.sortedPorts) // Width mapping. See calculateBitPairs. val bitPairs: Seq[(BigInt, BigInt)] = calculateBitPairs(mem, lib) @@ -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 * address bits into account. */ if (mem.src.depth > lib.src.depth) { - mem.src.ports foreach { port => + mem.src.ports.foreach { port => val high = MacroCompilerMath.ceilLog2(mem.src.depth) val low = MacroCompilerMath.ceilLog2(lib.src.depth) val ref = WRef(port.address.name) val nodeName = s"${ref.name}_sel" - val tpe = UIntType(IntWidth(high-low)) + val tpe = UIntType(IntWidth(high - low)) selects(ref.name) = WRef(nodeName, tpe) - stmts += DefNode(NoInfo, nodeName, bits(ref, high-1, low)) + stmts += DefNode(NoInfo, nodeName, bits(ref, high - 1, low)) // Donggyu: output selection should be piped if (port.output.isDefined) { val regName = s"${ref.name}_sel_reg" @@ -303,7 +332,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], and(WRef(ce.name, BoolType), WRef(re.name, BoolType)) case (Some(ce), None) => WRef(ce.name, BoolType) case (None, Some(re)) => WRef(re.name, BoolType) - case (None, None) => one + case (None, None) => one } selectRegs(ref.name) = WRef(regName, tpe) stmts += DefRegister(NoInfo, regName, tpe, WRef(port.clock.get.name), zero, WRef(regName)) @@ -317,18 +346,18 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], // Create the instance. stmts += WDefInstance(NoInfo, name, lib.src.name, lib.tpe) // Connect extra ports of the lib. - stmts ++= lib.extraPorts map { case (portName, portValue) => + stmts ++= lib.extraPorts.map { case (portName, portValue) => Connect(NoInfo, WSubField(WRef(name), portName), portValue) } } for ((memPort, libPort) <- pairedPorts) { - val addrMatch = selects get memPort.src.address.name match { + val addrMatch = selects.get(memPort.src.address.name) match { case None => one case Some(addr) => val index = UIntLiteral(i, IntWidth(bitWidth(addr.tpe))) DoPrim(PrimOps.Eq, Seq(addr, index), Nil, index.tpe) } - val addrMatchReg = selectRegs get memPort.src.address.name match { + val addrMatchReg = selectRegs.get(memPort.src.address.name) match { case None => one case Some(reg) => val index = UIntLiteral(i, IntWidth(bitWidth(reg.tpe))) @@ -341,29 +370,22 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], for (((low, high), j) <- bitPairs.zipWithIndex) { val inst = WRef(s"mem_${i}_${j}", lib.tpe) - def connectPorts2(mem: Expression, - lib: String, - polarity: Option[PortPolarity]): Statement = + def connectPorts2(mem: Expression, lib: String, polarity: Option[PortPolarity]): Statement = Connect(NoInfo, WSubField(inst, lib), portToExpression(mem, polarity)) - def connectPorts(mem: Expression, - lib: String, - polarity: PortPolarity): Statement = + def connectPorts(mem: Expression, lib: String, polarity: PortPolarity): Statement = connectPorts2(mem, lib, Some(polarity)) // Clock port mapping /* Palmer: FIXME: I don't handle memories with read/write clocks yet. */ /* Colin not all libPorts have clocks but all memPorts do*/ libPort.src.clock.foreach { cPort => - stmts += connectPorts(WRef(memPort.src.clock.get.name), - cPort.name, - cPort.polarity) } + stmts += connectPorts(WRef(memPort.src.clock.get.name), cPort.name, cPort.polarity) + } // Adress port mapping /* Palmer: The address port to a memory is just the low-order bits of * the top address. */ - stmts += connectPorts(WRef(memPort.src.address.name), - libPort.src.address.name, - libPort.src.address.polarity) + stmts += connectPorts(WRef(memPort.src.address.name), libPort.src.address.name, libPort.src.address.polarity) // Output port mapping (memPort.src.output, libPort.src.output) match { @@ -373,20 +395,20 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], * done after generating all the memories. This saves up the * output statements for later. */ val name = s"${mem}_${i}_${j}" // This name is the output from the instance (mem vs ${mem}). - val exp = portToExpression(bits(WSubField(inst, lib), high-low, 0), Some(lib_polarity)) + val exp = portToExpression(bits(WSubField(inst, lib), high - low, 0), Some(lib_polarity)) stmts += DefNode(NoInfo, name, exp) cats += WRef(name) case (None, Some(lib)) => - /* Palmer: If the inner memory has an output port but the outer - * one doesn't then it's safe to just leave the outer - * port floating. */ + /* Palmer: If the inner memory has an output port but the outer + * one doesn't then it's safe to just leave the outer + * port floating. */ case (None, None) => - /* Palmer: If there's no output ports at all (ie, read-only - * port on the memory) then just don't worry about it, - * there's nothing to do. */ + /* Palmer: If there's no output ports at all (ie, read-only + * port on the memory) then just don't worry about it, + * there's nothing to do. */ case (Some(PolarizedPort(mem, _)), None) => - System.err println "WARNING: Unable to match output ports on memory" - System.err println s" outer output port: ${mem}" + System.err.println("WARNING: Unable to match output ports on memory") + System.err.println(s" outer output port: ${mem}") return None } @@ -396,7 +418,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], /* Palmer: The input port to a memory just needs to happen in parallel, * this does a part select to narrow the memory down. */ stmts += connectPorts(bits(WRef(mem), high, low), lib, lib_polarity) - case (None, Some(lib)) => + case (None, Some(lib)) => /* Palmer: If the inner memory has an input port but the other * one doesn't then it's safe to just leave the inner * port floating. This should be handled by the @@ -405,12 +427,12 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], //Firrtl cares about dangling inputs now tie it off stmts += IsInvalid(NoInfo, WSubField(inst, lib.name)) case (None, None) => - /* Palmer: If there's no input ports at all (ie, read-only - * port on the memory) then just don't worry about it, - * there's nothing to do. */ + /* Palmer: If there's no input ports at all (ie, read-only + * port on the memory) then just don't worry about it, + * there's nothing to do. */ case (Some(PolarizedPort(mem, _)), None) => - System.err println "WARNING: Unable to match input ports on memory" - System.err println s" outer input port: ${mem}" + System.err.println("WARNING: Unable to match input ports on memory") + System.err.println(s" outer input port: ${mem}") return None } @@ -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. // The other case is if we're using a larger lib than mem. val usingLessThanLibMaskGran = (memPort.src.maskGran.get < libPort.src.effectiveMaskGran) - val effectiveLibWidth = if (usingLessThanLibMaskGran) - memPort.src.maskGran.get - else - libPort.src.width.get + val effectiveLibWidth = + if (usingLessThanLibMaskGran) + memPort.src.maskGran.get + else + libPort.src.width.get - cat(((0 until libPort.src.width.get by libPort.src.effectiveMaskGran) map (i => { - if (usingLessThanLibMaskGran && i >= effectiveLibWidth) { - // If the memMaskGran is smaller than the lib's gran, then - // zero out the upper bits. - zero - } else { - if ((low + i) >= memPort.src.width.get) { - // If our bit is larger than the whole width of the mem, just zero out the upper bits. - zero - } else { - // Pick the appropriate bit from the mem mask. - bits(WRef(mem), (low + i) / memPort.src.effectiveMaskGran) - } - } - })).reverse) + cat( + ( + (0 until libPort.src.width.get by libPort.src.effectiveMaskGran) + .map(i => { + if (usingLessThanLibMaskGran && i >= effectiveLibWidth) { + // If the memMaskGran is smaller than the lib's gran, then + // zero out the upper bits. + zero + } else { + if ((low + i) >= memPort.src.width.get) { + // If our bit is larger than the whole width of the mem, just zero out the upper bits. + zero + } else { + // Pick the appropriate bit from the mem mask. + bits(WRef(mem), (low + i) / memPort.src.effectiveMaskGran) + } + } + }) + ) + .reverse + ) } case None => /* If there is a lib mask port but no mem mask port, just turn on @@ -482,7 +511,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], // Chip enable port mapping val memChipEnable = memPort.src.chipEnable match { case Some(PolarizedPort(mem, _)) => WRef(mem) - case None => one + case None => one } // Read enable port mapping @@ -501,7 +530,11 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], * implement the outer memory's collection of ports using what * the inner memory has availiable. */ ((libPort.src.maskPort, libPort.src.writeEnable, libPort.src.chipEnable): @unchecked) match { - case (Some(PolarizedPort(mask, mask_polarity)), Some(PolarizedPort(we, we_polarity)), Some(PolarizedPort(en, en_polarity))) => + case ( + Some(PolarizedPort(mask, mask_polarity)), + Some(PolarizedPort(we, we_polarity)), + Some(PolarizedPort(en, en_polarity)) + ) => /* Palmer: This is the simple option: every port exists. */ stmts += connectPorts(memMask, mask, mask_polarity) stmts += connectPorts(andAddrMatch(memWriteEnable), we, we_polarity) @@ -509,8 +542,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], case (Some(PolarizedPort(mask, mask_polarity)), Some(PolarizedPort(we, we_polarity)), None) => /* Palmer: If we don't have a chip enable but do have mask ports. */ stmts += connectPorts(memMask, mask, mask_polarity) - stmts += connectPorts(andAddrMatch(and(memWriteEnable, memChipEnable)), - we, we_polarity) + stmts += connectPorts(andAddrMatch(and(memWriteEnable, memChipEnable)), we, we_polarity) case (None, Some(PolarizedPort(we, we_polarity)), chipEnable) => if (bitWidth(memMask.tpe) == 1) { /* Palmer: If we're expected to provide mask ports without a @@ -518,13 +550,15 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], * write enable port instead of the mask port. */ chipEnable match { case Some(PolarizedPort(en, en_polarity)) => { - stmts += connectPorts(andAddrMatch(and(memWriteEnable, memMask)), - we, we_polarity) + stmts += connectPorts(andAddrMatch(and(memWriteEnable, memMask)), we, we_polarity) stmts += connectPorts(andAddrMatch(memChipEnable), en, en_polarity) } case _ => { - stmts += connectPorts(andAddrMatch(and(and(memWriteEnable, memChipEnable), memMask)), - we, we_polarity) + stmts += connectPorts( + andAddrMatch(and(and(memWriteEnable, memChipEnable), memMask)), + we, + we_polarity + ) } } } else { @@ -532,8 +566,8 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], return None } case (None, None, None) => - // No write ports to match up (this may be a read-only port). - // This isn't necessarily an error condition. + // No write ports to match up (this may be a read-only port). + // This isn't necessarily an error condition. } } // Cat macro outputs for selection @@ -541,7 +575,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], case Some(PolarizedPort(mem, _)) if cats.nonEmpty => val name = s"${mem}_${i}" stmts += DefNode(NoInfo, name, cat(cats.toSeq.reverse)) - (outputs getOrElseUpdate (mem, ArrayBuffer[(Expression, Expression)]())) += + (outputs.getOrElseUpdate(mem, ArrayBuffer[(Expression, Expression)]())) += (addrMatchReg -> WRef(name)) case _ => } @@ -549,15 +583,17 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], } // Connect mem outputs val zeroOutputValue: Expression = UIntLiteral(0, IntWidth(mem.src.width)) - mem.src.ports foreach { port => + mem.src.ports.foreach { port => port.output match { - case Some(PolarizedPort(mem, _)) => outputs get mem match { - case Some(select) => - val output = (select foldRight (zeroOutputValue)) { - case ((cond, tval), fval) => Mux(cond, tval, fval, fval.tpe) } - stmts += Connect(NoInfo, WRef(mem), output) - case None => - } + case Some(PolarizedPort(mem, _)) => + outputs.get(mem) match { + case Some(select) => + val output = (select.foldRight(zeroOutputValue)) { case ((cond, tval), fval) => + Mux(cond, tval, fval, fval.tpe) + } + stmts += Connect(NoInfo, WRef(mem), output) + case None => + } case None => } } @@ -572,79 +608,84 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], // Try to compile each of the memories in mems. // The 'state' is c.modules, which is a list of all the firrtl modules // in the 'circuit'. - (mems foldLeft c.modules){ (modules, mem) => - - val sram = mem.src - def groupMatchesMask(group: SRAMGroup, mem:SRAMMacro): Boolean = { - val memMask = mem.ports map (_.maskGran) find (_.isDefined) map (_.get) - val libMask = group.ports map (_.maskGran) find (_.isDefined) map (_.get) - (memMask, libMask) match { - case (None, _) => true - case (Some(_), None) => false - case (Some(m), Some(l)) => l <= m //Ignore memories that don't have nice mask + (mems.foldLeft(c.modules)) { (modules, mem) => + val sram = mem.src + def groupMatchesMask(group: SRAMGroup, mem: SRAMMacro): Boolean = { + val memMask = mem.ports.map(_.maskGran).find(_.isDefined).map(_.get) + val libMask = group.ports.map(_.maskGran).find(_.isDefined).map(_.get) + (memMask, libMask) match { + case (None, _) => true + case (Some(_), None) => false + case (Some(m), Some(l)) => l <= m //Ignore memories that don't have nice mask + } } - } - // Add compiler memories that might map well to libs - val compLibs = compilers match { - case Some(SRAMCompiler(_, groups)) => { - groups.filter(g => g.family == sram.family && groupMatchesMask(g, sram)).map( g => { - for(w <- g.width; d <- g.depth if((sram.width % w == 0) && (sram.depth % d == 0))) - yield Seq(new Macro(buildSRAMMacro(g, d, w, g.vt.head))) - } ) + // Add compiler memories that might map well to libs + val compLibs = compilers match { + case Some(SRAMCompiler(_, groups)) => { + groups + .filter(g => g.family == sram.family && groupMatchesMask(g, sram)) + .map(g => { + for { + w <- g.width + d <- g.depth if ((sram.width % w == 0) && (sram.depth % d == 0)) + } yield Seq(new Macro(buildSRAMMacro(g, d, w, g.vt.head))) + }) + } + case None => Seq() } - case None => Seq() - } - val fullLibs = libs ++ compLibs.flatten.flatten + val fullLibs = libs ++ compLibs.flatten.flatten - // Try to compile mem against each lib in libs, keeping track of the - // best compiled version, external lib used, and cost. - val (best, cost) = (fullLibs foldLeft (None: Option[(Module, Macro)], Double.MaxValue)){ - case ((best, cost), lib) if mem.src.ports.size != lib.src.ports.size => - /* Palmer: FIXME: This just assumes the Chisel and vendor ports are in the same - * order, but I'm starting with what actually gets generated. */ - System.err println s"INFO: unable to compile ${mem.src.name} using ${lib.src.name} port count must match" - (best, cost) - case ((best, cost), lib) => - // Run the cost function to evaluate this potential compile. - costMetric.cost(mem, lib) match { - case Some(newCost) => { - //System.err.println(s"Cost of ${lib.src.name} for ${mem.src.name}: ${newCost}") - // Try compiling - compile(mem, lib) match { - // If it was successful and the new cost is lower - case Some(p) if (newCost < cost) => (Some(p), newCost) - case _ => (best, cost) + // Try to compile mem against each lib in libs, keeping track of the + // best compiled version, external lib used, and cost. + val (best, cost) = (fullLibs.foldLeft(None: Option[(Module, Macro)], Double.MaxValue)) { + case ((best, cost), lib) if mem.src.ports.size != lib.src.ports.size => + /* Palmer: FIXME: This just assumes the Chisel and vendor ports are in the same + * order, but I'm starting with what actually gets generated. */ + System.err.println(s"INFO: unable to compile ${mem.src.name} using ${lib.src.name} port count must match") + (best, cost) + case ((best, cost), lib) => + // Run the cost function to evaluate this potential compile. + costMetric.cost(mem, lib) match { + case Some(newCost) => { + //System.err.println(s"Cost of ${lib.src.name} for ${mem.src.name}: ${newCost}") + // Try compiling + compile(mem, lib) match { + // If it was successful and the new cost is lower + case Some(p) if (newCost < cost) => (Some(p), newCost) + case _ => (best, cost) + } } + case _ => (best, cost) // Cost function rejected this combination. } - case _ => (best, cost) // Cost function rejected this combination. - } - } - - // If we were able to compile anything, then replace the original module - // in the modules list with a compiled version, as well as the extmodule - // stub for the lib. - best match { - case None => { - if (mode == MacroCompilerAnnotation.Strict) - throw new MacroCompilerException(s"Target memory ${mem.src.name} could not be compiled and strict mode is activated - aborting.") - else - modules } - case Some((mod, bb)) => - hammerIR match { - case Some(f) => { - val hammerIRWriter = new FileWriter(new File(f), !firstLib) - if(firstLib) hammerIRWriter.write("[\n") - hammerIRWriter.write(bb.src.toJSON().toString()) - hammerIRWriter.write("\n,\n") - hammerIRWriter.close() - firstLib = false - } - case None => + + // If we were able to compile anything, then replace the original module + // in the modules list with a compiled version, as well as the extmodule + // stub for the lib. + best match { + case None => { + if (mode == MacroCompilerAnnotation.Strict) + throw new MacroCompilerException( + s"Target memory ${mem.src.name} could not be compiled and strict mode is activated - aborting." + ) + else + modules } - (modules filterNot (m => m.name == mod.name || m.name == bb.blackbox.name)) ++ Seq(mod, bb.blackbox) + case Some((mod, bb)) => + hammerIR match { + case Some(f) => { + val hammerIRWriter = new FileWriter(new File(f), !firstLib) + if (firstLib) hammerIRWriter.write("[\n") + hammerIRWriter.write(bb.src.toJSON().toString()) + hammerIRWriter.write("\n,\n") + hammerIRWriter.close() + firstLib = false + } + case None => + } + (modules.filterNot(m => m.name == mod.name || m.name == bb.blackbox.name)) ++ Seq(mod, bb.blackbox) + } } - } case _ => c.modules } c.copy(modules = modules) @@ -657,38 +698,46 @@ class MacroCompilerTransform extends Transform { def execute(state: CircuitState) = state.annotations.collect { case a: MacroCompilerAnnotation => a } match { case Seq(anno: MacroCompilerAnnotation) => - val MacroCompilerAnnotation.Params(memFile, memFileFormat, libFile, hammerIR, costMetric, mode, useCompiler, forceCompile, forceSynflops) = anno.params + val MacroCompilerAnnotation.Params( + memFile, + memFileFormat, + libFile, + hammerIR, + costMetric, + mode, + useCompiler, + forceCompile, + forceSynflops + ) = anno.params if (mode == MacroCompilerAnnotation.FallbackSynflops) { throw new UnsupportedOperationException("Not implemented yet") } // Check that we don't have any modules both forced to compile and synflops. - assert((forceCompile intersect forceSynflops).isEmpty, "Cannot have modules both forced to compile and synflops") + assert((forceCompile.intersect(forceSynflops)).isEmpty, "Cannot have modules both forced to compile and synflops") // Read, eliminate None, get only SRAM, make firrtl macro val mems: Option[Seq[Macro]] = (memFileFormat match { case Some("conf") => Utils.readConfFromPath(Some(memFile)) - case _ => mdf.macrolib.Utils.readMDFFromPath(Some(memFile)) + case _ => mdf.macrolib.Utils.readMDFFromPath(Some(memFile)) }) match { - case Some(x:Seq[mdf.macrolib.Macro]) => - Some(Utils.filterForSRAM(Some(x)) getOrElse(List()) map {new Macro(_)}) + case Some(x: Seq[mdf.macrolib.Macro]) => + Some(Utils.filterForSRAM(Some(x)).getOrElse(List()).map { new Macro(_) }) case _ => None } val libs: Option[Seq[Macro]] = mdf.macrolib.Utils.readMDFFromPath(libFile) match { - case Some(x:Seq[mdf.macrolib.Macro]) => - Some(Utils.filterForSRAM(Some(x)) getOrElse(List()) map {new Macro(_)}) + case Some(x: Seq[mdf.macrolib.Macro]) => + Some(Utils.filterForSRAM(Some(x)).getOrElse(List()).map { new Macro(_) }) case _ => None } val compilers: Option[mdf.macrolib.SRAMCompiler] = mdf.macrolib.Utils.readMDFFromPath(libFile) match { - case Some(x:Seq[mdf.macrolib.Macro]) => - if(useCompiler){ + case Some(x: Seq[mdf.macrolib.Macro]) => + if (useCompiler) { findSRAMCompiler(Some(x)) - } - else None + } else None case _ => None } - // Helper function to turn a set of mem names into a Seq[Macro]. def setToSeqMacro(names: Set[String]): Seq[Macro] = { names.toSeq.map(memName => mems.get.collectFirst { case m if m.src.name == memName => m }.get) @@ -706,12 +755,16 @@ class MacroCompilerTransform extends Transform { val transforms = Seq( new MacroCompilerPass(memCompile, libs, compilers, hammerIR, costMetric, mode), - new SynFlopsPass(true, memSynflops ++ (if (mode == MacroCompilerAnnotation.CompileAndSynflops) { - libs.get - } else { - Seq.empty - }))) - (transforms foldLeft state) ((s, xform) => xform runTransform s).copy(form = outputForm) + new SynFlopsPass( + true, + memSynflops ++ (if (mode == MacroCompilerAnnotation.CompileAndSynflops) { + libs.get + } else { + Seq.empty + }) + ) + ) + (transforms.foldLeft(state))((s, xform) => xform.runTransform(s)).copy(form = outputForm) case _ => state } } @@ -729,7 +782,8 @@ class MacroCompilerOptimizations extends SeqTransform { new firrtl.transforms.ConstantPropagation, passes.Legalize, passes.SplitExpressions, - passes.CommonSubexpressionElimination) + passes.CommonSubexpressionElimination + ) } class MacroCompiler extends Compiler { @@ -756,8 +810,9 @@ object MacroCompiler extends App { type MacroParamMap = Map[MacroParam, String] type CostParamMap = Map[String, String] type ForcedMemories = (Set[String], Set[String]) - val modeOptions: Seq[String] = MacroCompilerAnnotation.options - .map { case (_, cmd, description) => s" $cmd: $description" } + val modeOptions: Seq[String] = MacroCompilerAnnotation.options.map { case (_, cmd, description) => + s" $cmd: $description" + } val usage: String = (Seq( "Options:", " -n, --macro-conf: The set of macros to compile in firrtl-generated conf format (exclusive with -m)", @@ -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-synflops [mem]: Force the given memory to be compiled via synflops regardless of the mode", " --mode:" - ) ++ modeOptions) mkString "\n" + ) ++ modeOptions).mkString("\n") - def parseArgs(map: MacroParamMap, costMap: CostParamMap, forcedMemories: ForcedMemories, - args: List[String]): (MacroParamMap, CostParamMap, ForcedMemories) = + def parseArgs( + map: MacroParamMap, + costMap: CostParamMap, + forcedMemories: ForcedMemories, + args: List[String] + ): (MacroParamMap, CostParamMap, ForcedMemories) = args match { case Nil => (map, costMap, forcedMemories) case ("-n" | "--macro-conf") :: value :: tail => - parseArgs(map + (Macros -> value) + (MacrosFormat -> "conf"), costMap, forcedMemories, tail) + parseArgs(map + (Macros -> value) + (MacrosFormat -> "conf"), costMap, forcedMemories, tail) case ("-m" | "--macro-mdf") :: value :: tail => - parseArgs(map + (Macros -> value) + (MacrosFormat -> "mdf"), costMap, forcedMemories, tail) + parseArgs(map + (Macros -> value) + (MacrosFormat -> "mdf"), costMap, forcedMemories, tail) case ("-l" | "--library") :: value :: tail => parseArgs(map + (Library -> value), costMap, forcedMemories, tail) case ("-u" | "--use-compiler") :: tail => @@ -809,11 +868,17 @@ object MacroCompiler extends App { } def run(args: List[String]) { - val (params, costParams, forcedMemories) = parseArgs(Map[MacroParam, String](), Map[String, String](), (Set.empty, Set.empty), args) + val (params, costParams, forcedMemories) = + parseArgs(Map[MacroParam, String](), Map[String, String](), (Set.empty, Set.empty), args) try { val macros = params.get(MacrosFormat) match { - case Some("conf") => Utils.filterForSRAM(Utils.readConfFromPath(params.get(Macros))).get map (x => (new Macro(x)).blackbox) - case _ => Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(params.get(Macros))).get map (x => (new Macro(x)).blackbox) + case Some("conf") => + Utils.filterForSRAM(Utils.readConfFromPath(params.get(Macros))).get.map(x => (new Macro(x)).blackbox) + case _ => + Utils + .filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(params.get(Macros))) + .get + .map(x => (new Macro(x)).blackbox) } if (macros.nonEmpty) { @@ -821,24 +886,28 @@ object MacroCompiler extends App { // determined as the firrtl "top-level module". val circuit = Circuit(NoInfo, macros, macros.last.name) val annotations = AnnotationSeq( - Seq(MacroCompilerAnnotation( - circuit.main, - MacroCompilerAnnotation.Params( - params.get(Macros).get, params.get(MacrosFormat), params.get(Library), - params.get(HammerIR), - CostMetric.getCostMetric(params.getOrElse(CostFunc, "default"), costParams), - MacroCompilerAnnotation.stringToCompilerMode(params.getOrElse(Mode, "default")), - params.contains(UseCompiler), - forceCompile = forcedMemories._1, forceSynflops = forcedMemories._2 + Seq( + MacroCompilerAnnotation( + circuit.main, + MacroCompilerAnnotation.Params( + params.get(Macros).get, + params.get(MacrosFormat), + params.get(Library), + params.get(HammerIR), + CostMetric.getCostMetric(params.getOrElse(CostFunc, "default"), costParams), + MacroCompilerAnnotation.stringToCompilerMode(params.getOrElse(Mode, "default")), + params.contains(UseCompiler), + forceCompile = forcedMemories._1, + forceSynflops = forcedMemories._2 + ) ) - )) + ) ) // The actual MacroCompilerTransform basically just generates an input circuit val macroCompilerInput = CircuitState(circuit, MidForm, annotations) val macroCompiled = (new MacroCompilerTransform).execute(macroCompilerInput) - // Since the MacroCompiler defines its own CLI, reconcile this with FIRRTL options val firOptions = new ExecutionOptionsManager("macrocompiler") with HasFirrtlOptions { firrtlOptions = FirrtlExecutionOptions( @@ -864,7 +933,7 @@ object MacroCompiler extends App { } } else { // Warn user - System.err println "WARNING: Empty *.mems.conf file. No memories generated." + System.err.println("WARNING: Empty *.mems.conf file. No memories generated.") // Emit empty verilog file if no macros found params.get(Verilog) match { diff --git a/macros/src/main/scala/barstools/macros/SynFlops.scala b/macros/src/main/scala/barstools/macros/SynFlops.scala index df7390d0..77ea4c96 100644 --- a/macros/src/main/scala/barstools/macros/SynFlops.scala +++ b/macros/src/main/scala/barstools/macros/SynFlops.scala @@ -10,132 +10,142 @@ import firrtl.passes.MemPortUtils.memPortField class SynFlopsPass(synflops: Boolean, libs: Seq[Macro]) extends firrtl.passes.Pass { val extraMods = scala.collection.mutable.ArrayBuffer.empty[Module] - lazy val libMods = (libs map { lib => lib.src.name -> { - val (dataType, dataWidth) = (lib.src.ports foldLeft (None: Option[BigInt]))((res, port) => - (res, port.maskPort) match { - case (_, None) => - res - case (None, Some(_)) => - Some(port.effectiveMaskGran) - case (Some(x), Some(_)) => - assert(x == port.effectiveMaskGran) - res + lazy val libMods = (libs.map { lib => + lib.src.name -> { + val (dataType, dataWidth) = (lib.src.ports.foldLeft(None: Option[BigInt]))((res, port) => + (res, port.maskPort) match { + case (_, None) => + res + case (None, Some(_)) => + Some(port.effectiveMaskGran) + case (Some(x), Some(_)) => + assert(x == port.effectiveMaskGran) + res + } + ) match { + case None => (UIntType(IntWidth(lib.src.width)), lib.src.width) + case Some(gran) => (UIntType(IntWidth(gran)), gran.intValue) } - ) match { - case None => (UIntType(IntWidth(lib.src.width)), lib.src.width) - case Some(gran) => (UIntType(IntWidth(gran)), gran.intValue) - } - val maxDepth = min(lib.src.depth, 1<<26) - val numMems = lib.src.depth / maxDepth + val maxDepth = min(lib.src.depth, 1 << 26) + val numMems = lib.src.depth / maxDepth - // Change macro to be mapped onto to look like the below mem - // by changing its depth, and width - val lib_macro = new Macro(lib.src.copy(name="split_"+lib.src.name, - depth = maxDepth, width = dataWidth, ports = lib.src.ports.map(p => - p.copy(width = p.width.map(_ => dataWidth), depth = p.depth.map(_ => maxDepth), - maskGran = p.maskGran.map(_ => dataWidth))))) - val mod_macro = (new MacroCompilerPass(None,None,None,None)).compile(lib, lib_macro) - val (real_mod, real_macro) = mod_macro.get - - val mem = DefMemory( - NoInfo, - "ram", - dataType, - maxDepth, - 1, // writeLatency - 1, // readLatency. This is possible because of VerilogMemDelays - real_macro.readers.indices map (i => s"R_$i"), - real_macro.writers.indices map (i => s"W_$i"), - real_macro.readwriters.indices map (i => s"RW_$i") - ) - - val readConnects = real_macro.readers.zipWithIndex flatMap { case (r, i) => - val clock = portToExpression(r.src.clock.get) - val address = portToExpression(r.src.address) - val enable = (r.src chipEnable, r.src readEnable) match { - case (Some(en_port), Some(re_port)) => - and(portToExpression(en_port), - portToExpression(re_port)) - case (Some(en_port), None) => portToExpression(en_port) - case (None, Some(re_port)) => portToExpression(re_port) - case (None, None) => one - } - val data = memPortField(mem, s"R_$i", "data") - val read = data - Seq( - Connect(NoInfo, memPortField(mem, s"R_$i", "clk"), clock), - Connect(NoInfo, memPortField(mem, s"R_$i", "addr"), address), - Connect(NoInfo, memPortField(mem, s"R_$i", "en"), enable), - Connect(NoInfo, WRef(r.src.output.get.name), read) + // Change macro to be mapped onto to look like the below mem + // by changing its depth, and width + val lib_macro = new Macro( + lib.src.copy( + name = "split_" + lib.src.name, + depth = maxDepth, + width = dataWidth, + ports = lib.src.ports.map(p => + p.copy( + width = p.width.map(_ => dataWidth), + depth = p.depth.map(_ => maxDepth), + maskGran = p.maskGran.map(_ => dataWidth) + ) + ) + ) ) - } + val mod_macro = (new MacroCompilerPass(None, None, None, None)).compile(lib, lib_macro) + val (real_mod, real_macro) = mod_macro.get - val writeConnects = real_macro.writers.zipWithIndex flatMap { case (w, i) => - val clock = portToExpression(w.src.clock.get) - val address = portToExpression(w.src.address) - val enable = (w.src.chipEnable, w.src.writeEnable) match { - case (Some(en), Some(we)) => - and(portToExpression(en), - portToExpression(we)) - case (Some(en), None) => portToExpression(en) - case (None, Some(we)) => portToExpression(we) - case (None, None) => zero // is it possible? - } - val mask = w.src.maskPort match { - case Some(m) => portToExpression(m) - case None => one - } - val data = memPortField(mem, s"W_$i", "data") - val write = portToExpression(w.src.input.get) - Seq( - Connect(NoInfo, memPortField(mem, s"W_$i", "clk"), clock), - Connect(NoInfo, memPortField(mem, s"W_$i", "addr"), address), - Connect(NoInfo, memPortField(mem, s"W_$i", "en"), enable), - Connect(NoInfo, memPortField(mem, s"W_$i", "mask"), mask), - Connect(NoInfo, data, write) + val mem = DefMemory( + NoInfo, + "ram", + dataType, + maxDepth, + 1, // writeLatency + 1, // readLatency. This is possible because of VerilogMemDelays + real_macro.readers.indices.map(i => s"R_$i"), + real_macro.writers.indices.map(i => s"W_$i"), + real_macro.readwriters.indices.map(i => s"RW_$i") ) - } - val 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 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 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 + val writeConnects = real_macro.writers.zipWithIndex.flatMap { case (w, i) => + val clock = portToExpression(w.src.clock.get) + val address = portToExpression(w.src.address) + val enable = (w.src.chipEnable, w.src.writeEnable) match { + case (Some(en), Some(we)) => + and(portToExpression(en), portToExpression(we)) + case (Some(en), None) => portToExpression(en) + case (None, Some(we)) => portToExpression(we) + case (None, None) => zero // is it possible? + } + val mask = w.src.maskPort match { + case Some(m) => portToExpression(m) + case None => one + } + val data = memPortField(mem, s"W_$i", "data") + val write = portToExpression(w.src.input.get) + Seq( + Connect(NoInfo, memPortField(mem, s"W_$i", "clk"), clock), + Connect(NoInfo, memPortField(mem, s"W_$i", "addr"), address), + Connect(NoInfo, memPortField(mem, s"W_$i", "en"), enable), + Connect(NoInfo, memPortField(mem, s"W_$i", "mask"), mask), + Connect(NoInfo, data, write) + ) + } + + val readwriteConnects = real_macro.readwriters.zipWithIndex.flatMap { case (rw, i) => + val clock = portToExpression(rw.src.clock.get) + val address = portToExpression(rw.src.address) + val wmode = rw.src.writeEnable match { + case Some(we) => portToExpression(we) + case None => zero // is it possible? + } + val wmask = rw.src.maskPort match { + case Some(wm) => portToExpression(wm) + case None => one + } + val enable = (rw.src.chipEnable, rw.src.readEnable) match { + case (Some(en), Some(re)) => + and(portToExpression(en), or(portToExpression(re), wmode)) + case (Some(en), None) => portToExpression(en) + case (None, Some(re)) => or(portToExpression(re), wmode) + case (None, None) => one + } + val wdata = memPortField(mem, s"RW_$i", "wdata") + val rdata = memPortField(mem, s"RW_$i", "rdata") + val write = portToExpression(rw.src.input.get) + val read = rdata + Seq( + Connect(NoInfo, memPortField(mem, s"RW_$i", "clk"), clock), + Connect(NoInfo, memPortField(mem, s"RW_$i", "addr"), address), + Connect(NoInfo, memPortField(mem, s"RW_$i", "en"), enable), + Connect(NoInfo, memPortField(mem, s"RW_$i", "wmode"), wmode), + Connect(NoInfo, memPortField(mem, s"RW_$i", "wmask"), wmask), + Connect(NoInfo, WRef(rw.src.output.get.name), read), + Connect(NoInfo, wdata, write) + ) + } + + extraMods.append(real_macro.module(Block(mem +: (readConnects ++ writeConnects ++ readwriteConnects)))) + real_mod + } + }).toMap def run(c: Circuit): Circuit = { if (!synflops) c - else c.copy(modules = (c.modules map (m => libMods.getOrElse(m.name, m))) ++ extraMods) + else c.copy(modules = (c.modules.map(m => libMods.getOrElse(m.name, m))) ++ extraMods) } } diff --git a/macros/src/main/scala/barstools/macros/Utils.scala b/macros/src/main/scala/barstools/macros/Utils.scala index a65e3a8a..9afa51f3 100644 --- a/macros/src/main/scala/barstools/macros/Utils.scala +++ b/macros/src/main/scala/barstools/macros/Utils.scala @@ -11,7 +11,7 @@ import mdf.macrolib.{Input => _, Output => _, _} import scala.language.implicitConversions object MacroCompilerMath { - def ceilLog2(x: BigInt): Int = (x-1).bitLength + def ceilLog2(x: BigInt): Int = (x - 1).bitLength } class FirrtlMacroPort(port: MacroPort) { @@ -21,37 +21,46 @@ class FirrtlMacroPort(port: MacroPort) { val isWriter = port.input.nonEmpty && port.output.isEmpty val isReadWriter = port.input.nonEmpty && port.output.nonEmpty - val addrType = UIntType(IntWidth(MacroCompilerMath.ceilLog2(port.depth.get) max 1)) + val addrType = UIntType(IntWidth(MacroCompilerMath.ceilLog2(port.depth.get).max(1))) val dataType = UIntType(IntWidth(port.width.get)) val maskType = UIntType(IntWidth(port.width.get / port.effectiveMaskGran)) // Bundle representing this macro port. - val tpe = BundleType(Seq( - Field(port.address.name, Flip, addrType)) ++ - (port.clock map (p => Field(p.name, Flip, ClockType))) ++ - (port.input map (p => Field(p.name, Flip, dataType))) ++ - (port.output map (p => Field(p.name, Default, dataType))) ++ - (port.chipEnable map (p => Field(p.name, Flip, BoolType))) ++ - (port.readEnable map (p => Field(p.name, Flip, BoolType))) ++ - (port.writeEnable map (p => Field(p.name, Flip, BoolType))) ++ - (port.maskPort map (p => Field(p.name, Flip, maskType))) + val tpe = BundleType( + Seq(Field(port.address.name, Flip, addrType)) ++ + (port.clock.map(p => Field(p.name, Flip, ClockType))) ++ + (port.input.map(p => Field(p.name, Flip, dataType))) ++ + (port.output.map(p => Field(p.name, Default, dataType))) ++ + (port.chipEnable.map(p => Field(p.name, Flip, BoolType))) ++ + (port.readEnable.map(p => Field(p.name, Flip, BoolType))) ++ + (port.writeEnable.map(p => Field(p.name, Flip, BoolType))) ++ + (port.maskPort.map(p => Field(p.name, Flip, maskType))) + ) + val ports = tpe.fields.map(f => + Port( + NoInfo, + f.name, + f.flip match { + case Default => Output + case Flip => Input + }, + f.tpe + ) ) - val ports = tpe.fields map (f => Port( - NoInfo, f.name, f.flip match { case Default => Output case Flip => Input }, f.tpe)) } // Reads an SRAMMacro and generates firrtl blackboxes. class Macro(srcMacro: SRAMMacro) { val src = srcMacro - val firrtlPorts = srcMacro.ports map { new FirrtlMacroPort(_) } + val firrtlPorts = srcMacro.ports.map { new FirrtlMacroPort(_) } - val writers = firrtlPorts filter (p => p.isWriter) - val readers = firrtlPorts filter (p => p.isReader) - val readwriters = firrtlPorts filter (p => p.isReadWriter) + val writers = firrtlPorts.filter(p => p.isWriter) + val readers = firrtlPorts.filter(p => p.isReader) + val readwriters = firrtlPorts.filter(p => p.isReadWriter) val sortedPorts = writers ++ readers ++ readwriters - val extraPorts = srcMacro.extraPorts map { p => + val extraPorts = srcMacro.extraPorts.map { p => assert(p.portType == Constant) // TODO: release it? val name = p.name val width = BigInt(p.width.toLong) @@ -60,10 +69,10 @@ class Macro(srcMacro: SRAMMacro) { } // 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)) ++ - (extraPorts map { case (name, value) => Port(NoInfo, name, Input, value.tpe) }) + private val modPorts = (firrtlPorts.flatMap(_.ports)) ++ + (extraPorts.map { case (name, value) => Port(NoInfo, name, Input, value.tpe) }) val blackbox = ExtModule(NoInfo, srcMacro.name, modPorts, srcMacro.name, Nil) def module(body: Statement) = Module(NoInfo, srcMacro.name, modPorts, body) } @@ -71,7 +80,8 @@ class Macro(srcMacro: SRAMMacro) { object Utils { def filterForSRAM(s: Option[Seq[mdf.macrolib.Macro]]): Option[Seq[mdf.macrolib.SRAMMacro]] = { s match { - case Some(l:Seq[mdf.macrolib.Macro]) => Some(l filter { _.isInstanceOf[mdf.macrolib.SRAMMacro] } map { m => m.asInstanceOf[mdf.macrolib.SRAMMacro] }) + case Some(l: Seq[mdf.macrolib.Macro]) => + Some(l.filter { _.isInstanceOf[mdf.macrolib.SRAMMacro] }.map { m => m.asInstanceOf[mdf.macrolib.SRAMMacro] }) case _ => None } } @@ -80,18 +90,24 @@ object Utils { path.map((p) => Utils.readConfFromString(scala.io.Source.fromFile(p).mkString)) } def readConfFromString(str: String): Seq[mdf.macrolib.Macro] = { - MemConf.fromString(str).map { m:MemConf => - val ports = m.ports.map { case (port, num) => Seq.fill(num)(port) } reduce (_ ++ _) - SRAMMacro(m.name, m.width, m.depth, Utils.portSpecToFamily(ports), Utils.portSpecToMacroPort(m.width, m.depth, m.maskGranularity, ports)) + MemConf.fromString(str).map { m: MemConf => + val ports = m.ports.map { case (port, num) => Seq.fill(num)(port) }.reduce(_ ++ _) + SRAMMacro( + m.name, + m.width, + m.depth, + Utils.portSpecToFamily(ports), + Utils.portSpecToMacroPort(m.width, m.depth, m.maskGranularity, ports) + ) } } def portSpecToFamily(ports: Seq[MemPort]): String = { - val numR = ports.count(_ match { case ReadPort => true; case _ => false}) - val numW = ports.count(_ match { case WritePort|MaskedWritePort => true; case _ => false}) - val numRW = ports.count(_ match { case ReadWritePort|MaskedReadWritePort => true; case _ => false}) - val numRStr = if(numR > 0) s"${numR}r" else "" - val numWStr = if(numW > 0) s"${numW}w" else "" - val numRWStr = if(numRW > 0) s"${numRW}rw" else "" + val numR = ports.count(_ match { case ReadPort => true; case _ => false }) + val numW = ports.count(_ match { case WritePort | MaskedWritePort => true; case _ => false }) + val numRW = ports.count(_ match { case ReadWritePort | MaskedReadWritePort => true; case _ => false }) + val numRStr = if (numR > 0) s"${numR}r" else "" + val numWStr = if (numW > 0) s"${numW}w" else "" + val numRWStr = if (numRW > 0) s"${numRW}rw" else "" return numRStr + numWStr + numRWStr } // This translates between two represenations of ports @@ -99,94 +115,128 @@ object Utils { var numR = 0 var numW = 0 var numRW = 0 - ports.map { _ match { - case ReadPort => { - val portName = s"R${numR}" - numR += 1 - MacroPort( - width=Some(width), depth=Some(depth), - address=PolarizedPort(s"${portName}_addr", ActiveHigh), - clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), - readEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), - output=Some(PolarizedPort(s"${portName}_data", ActiveHigh)) - ) } - case WritePort => { - val portName = s"W${numW}" - numW += 1 - MacroPort( - width=Some(width), depth=Some(depth), - address=PolarizedPort(s"${portName}_addr", ActiveHigh), - clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), - writeEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), - input=Some(PolarizedPort(s"${portName}_data", ActiveHigh)) - ) } - case MaskedWritePort => { - val portName = s"W${numW}" - numW += 1 - MacroPort( - width=Some(width), depth=Some(depth), - address=PolarizedPort(s"${portName}_addr", ActiveHigh), - clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), - writeEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), - maskPort=Some(PolarizedPort(s"${portName}_mask", ActiveHigh)), - maskGran=maskGran, - input=Some(PolarizedPort(s"${portName}_data", ActiveHigh)) - ) } - case ReadWritePort => { - val portName = s"RW${numRW}" - numRW += 1 - MacroPort( - width=Some(width), depth=Some(depth), - address=PolarizedPort(s"${portName}_addr", ActiveHigh), - clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), - chipEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), - writeEnable=Some(PolarizedPort(s"${portName}_wmode", ActiveHigh)), - input=Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)), - output=Some(PolarizedPort(s"${portName}_rdata", ActiveHigh)) - ) } - case MaskedReadWritePort => { - val portName = s"RW${numRW}" - numRW += 1 - MacroPort( - width=Some(width), depth=Some(depth), - address=PolarizedPort(s"${portName}_addr", ActiveHigh), - clock=Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), - chipEnable=Some(PolarizedPort(s"${portName}_en", ActiveHigh)), - writeEnable=Some(PolarizedPort(s"${portName}_wmode", ActiveHigh)), - maskPort=Some(PolarizedPort(s"${portName}_wmask", ActiveHigh)), - maskGran=maskGran, - input=Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)), - output=Some(PolarizedPort(s"${portName}_rdata", ActiveHigh)) - ) } - }} + ports.map { + _ match { + case ReadPort => { + val portName = s"R${numR}" + numR += 1 + MacroPort( + width = Some(width), + depth = Some(depth), + address = PolarizedPort(s"${portName}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), + readEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)), + output = Some(PolarizedPort(s"${portName}_data", ActiveHigh)) + ) + } + case WritePort => { + val portName = s"W${numW}" + numW += 1 + MacroPort( + width = Some(width), + depth = Some(depth), + address = PolarizedPort(s"${portName}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), + writeEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)), + input = Some(PolarizedPort(s"${portName}_data", ActiveHigh)) + ) + } + case MaskedWritePort => { + val portName = s"W${numW}" + numW += 1 + MacroPort( + width = Some(width), + depth = Some(depth), + address = PolarizedPort(s"${portName}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), + writeEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)), + maskPort = Some(PolarizedPort(s"${portName}_mask", ActiveHigh)), + maskGran = maskGran, + input = Some(PolarizedPort(s"${portName}_data", ActiveHigh)) + ) + } + case ReadWritePort => { + val portName = s"RW${numRW}" + numRW += 1 + MacroPort( + width = Some(width), + depth = Some(depth), + address = PolarizedPort(s"${portName}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), + chipEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)), + writeEnable = Some(PolarizedPort(s"${portName}_wmode", ActiveHigh)), + input = Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)), + output = Some(PolarizedPort(s"${portName}_rdata", ActiveHigh)) + ) + } + case MaskedReadWritePort => { + val portName = s"RW${numRW}" + numRW += 1 + MacroPort( + width = Some(width), + depth = Some(depth), + address = PolarizedPort(s"${portName}_addr", ActiveHigh), + clock = Some(PolarizedPort(s"${portName}_clk", PositiveEdge)), + chipEnable = Some(PolarizedPort(s"${portName}_en", ActiveHigh)), + writeEnable = Some(PolarizedPort(s"${portName}_wmode", ActiveHigh)), + maskPort = Some(PolarizedPort(s"${portName}_wmask", ActiveHigh)), + maskGran = maskGran, + input = Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)), + output = Some(PolarizedPort(s"${portName}_rdata", ActiveHigh)) + ) + } + } + } } def findSRAMCompiler(s: Option[Seq[mdf.macrolib.Macro]]): Option[mdf.macrolib.SRAMCompiler] = { s match { - case Some(l:Seq[mdf.macrolib.Macro]) => - l collectFirst { - case x: mdf.macrolib.SRAMCompiler => x + case Some(l: Seq[mdf.macrolib.Macro]) => + l.collectFirst { case x: mdf.macrolib.SRAMCompiler => + x } case _ => None } } def buildSRAMMacros(s: mdf.macrolib.SRAMCompiler): Seq[mdf.macrolib.SRAMMacro] = { - for (g <- s.groups; d <- g.depth; w <- g.width; vt <- g.vt) - yield mdf.macrolib.SRAMMacro(makeName(g, d, w, vt), w, d, g.family, g.ports.map(_.copy(width=Some(w), depth=Some(d))), vt, g.mux, g.extraPorts) + for { + g <- s.groups + d <- g.depth + w <- g.width + vt <- g.vt + } yield mdf.macrolib.SRAMMacro( + makeName(g, d, w, vt), + w, + d, + g.family, + g.ports.map(_.copy(width = Some(w), depth = Some(d))), + vt, + g.mux, + g.extraPorts + ) } def buildSRAMMacro(g: mdf.macrolib.SRAMGroup, d: Int, w: Int, vt: String): mdf.macrolib.SRAMMacro = { - return mdf.macrolib.SRAMMacro(makeName(g, d, w, vt), w, d, g.family, g.ports.map(_.copy(width=Some(w), depth=Some(d))), vt, g.mux, g.extraPorts) + return mdf.macrolib.SRAMMacro( + makeName(g, d, w, vt), + w, + d, + g.family, + g.ports.map(_.copy(width = Some(w), depth = Some(d))), + vt, + g.mux, + g.extraPorts + ) } def makeName(g: mdf.macrolib.SRAMGroup, depth: Int, width: Int, vt: String): String = { - g.name.foldLeft(""){ (builder, next) => + g.name.foldLeft("") { (builder, next) => next match { - case "depth"|"DEPTH" => builder + depth - case "width"|"WIDTH" => builder + width - case "vt" => builder + vt.toLowerCase - case "VT" => builder + vt.toUpperCase - case "family" => builder + g.family.toLowerCase - case "FAMILY" => builder + g.family.toUpperCase - case "mux"|"MUX" => builder + g.mux - case other => builder + other + case "depth" | "DEPTH" => builder + depth + case "width" | "WIDTH" => builder + width + case "vt" => builder + vt.toLowerCase + case "VT" => builder + vt.toUpperCase + case "family" => builder + g.family.toLowerCase + case "FAMILY" => builder + g.family.toUpperCase + case "mux" | "MUX" => builder + g.mux + case other => builder + other } } } @@ -196,7 +246,7 @@ object Utils { def or(e1: Expression, e2: Expression) = DoPrim(PrimOps.Or, Seq(e1, e2), Nil, e1.tpe) def bits(e: Expression, high: BigInt, low: BigInt): Expression = - DoPrim(PrimOps.Bits, Seq(e), Seq(high, low), UIntType(IntWidth(high-low+1))) + DoPrim(PrimOps.Bits, Seq(e), Seq(high, low), UIntType(IntWidth(high - low + 1))) def bits(e: Expression, idx: BigInt): Expression = bits(e, idx, idx) def cat(es: Seq[Expression]): Expression = if (es.size == 1) es.head @@ -211,7 +261,7 @@ object Utils { def portToExpression(exp: Expression, polarity: Option[PortPolarity]): Expression = polarity match { case Some(ActiveLow) | Some(NegativeEdge) => not(exp) - case _ => exp + case _ => exp } // Check if a number is a power of two diff --git a/macros/src/test/resources/lib-MaskPortTest.json b/macros/src/test/resources/lib-MaskPortTest.json index 72df7947..784aeafb 100644 --- a/macros/src/test/resources/lib-MaskPortTest.json +++ b/macros/src/test/resources/lib-MaskPortTest.json @@ -1,27 +1,29 @@ [ { - "type" : "sram", - "name" : "fake_mem", - "width" : 64, - "depth" : "512", - "mux" : 4, - "family" : "1rw", - "ports" : [ { - "address port name" : "addr", - "address port polarity" : "active high", - "clock port name" : "clk", - "clock port polarity" : "positive edge", - "write enable port name" : "wen", - "write enable port polarity" : "active high", - "read enable port name" : "ren", - "read enable port polarity" : "active high", - "output port name" : "dataout", - "output port polarity" : "active high", - "input port name" : "datain", - "input port polarity" : "active high", - "mask port name" : "mport", - "mask port polarity" : "active low", - "mask granularity" : 1 - } ] + "type": "sram", + "name": "fake_mem", + "width": 64, + "depth": "512", + "mux": 4, + "family": "1rw", + "ports": [ + { + "address port name": "addr", + "address port polarity": "active high", + "clock port name": "clk", + "clock port polarity": "positive edge", + "write enable port name": "wen", + "write enable port polarity": "active high", + "read enable port name": "ren", + "read enable port polarity": "active high", + "output port name": "dataout", + "output port polarity": "active high", + "input port name": "datain", + "input port polarity": "active high", + "mask port name": "mport", + "mask port polarity": "active low", + "mask granularity": 1 + } + ] } ] diff --git a/macros/src/test/resources/lib-WriteEnableTest.json b/macros/src/test/resources/lib-WriteEnableTest.json index be7852a6..50acef41 100644 --- a/macros/src/test/resources/lib-WriteEnableTest.json +++ b/macros/src/test/resources/lib-WriteEnableTest.json @@ -1,24 +1,26 @@ [ { - "type" : "sram", - "name" : "fake_mem", - "width" : 64, - "depth" : "4096", - "mux" : 4, - "family" : "1rw", - "ports" : [ { - "address port name" : "addr", - "address port polarity" : "active high", - "clock port name" : "clk", - "clock port polarity" : "positive edge", - "write enable port name" : "wen", - "write enable port polarity" : "active high", - "read enable port name" : "ren", - "read enable port polarity" : "active high", - "output port name" : "dataout", - "output port polarity" : "active high", - "input port name" : "datain", - "input port polarity" : "active high" - } ] + "type": "sram", + "name": "fake_mem", + "width": 64, + "depth": "4096", + "mux": 4, + "family": "1rw", + "ports": [ + { + "address port name": "addr", + "address port polarity": "active high", + "clock port name": "clk", + "clock port polarity": "positive edge", + "write enable port name": "wen", + "write enable port polarity": "active high", + "read enable port name": "ren", + "read enable port polarity": "active high", + "output port name": "dataout", + "output port polarity": "active high", + "input port name": "datain", + "input port polarity": "active high" + } + ] } ] diff --git a/macros/src/test/scala/barstools/macros/CostFunction.scala b/macros/src/test/scala/barstools/macros/CostFunction.scala index b8a27f7f..ceb7a61a 100644 --- a/macros/src/test/scala/barstools/macros/CostFunction.scala +++ b/macros/src/test/scala/barstools/macros/CostFunction.scala @@ -4,10 +4,9 @@ import mdf.macrolib._ /** Tests to check that the cost function mechanism is working properly. */ -/** - * A test metric that simply favours memories with smaller widths, to test that - * the metric is chosen properly. - */ +/** A test metric that simply favours memories with smaller widths, to test that + * the metric is chosen properly. + */ object TestMinWidthMetric extends CostMetric with CostMetricCompanion { // Smaller width = lower cost = favoured override def cost(mem: Macro, lib: Macro): Option[Double] = Some(lib.src.width) @@ -30,29 +29,29 @@ class SelectCostMetric extends MacroCompilerSpec with HasSRAMGenerator { val libSRAMs = Seq( SRAMMacro( - name="SRAM_WIDTH_128", - depth=BigInt(1024), - width=128, - family="1rw", - ports=Seq( + name = "SRAM_WIDTH_128", + depth = BigInt(1024), + width = 128, + family = "1rw", + ports = Seq( generateReadWritePort("", 128, BigInt(1024)) ) ), SRAMMacro( - name="SRAM_WIDTH_64", - depth=BigInt(1024), - width=64, - family="1rw", - ports=Seq( + name = "SRAM_WIDTH_64", + depth = BigInt(1024), + width = 64, + family = "1rw", + ports = Seq( generateReadWritePort("", 64, BigInt(1024)) ) ), SRAMMacro( - name="SRAM_WIDTH_32", - depth=BigInt(1024), - width=32, - family="1rw", - ports=Seq( + name = "SRAM_WIDTH_32", + depth = BigInt(1024), + width = 32, + family = "1rw", + ports = Seq( generateReadWritePort("", 32, BigInt(1024)) ) ) @@ -65,7 +64,7 @@ class SelectCostMetric extends MacroCompilerSpec with HasSRAMGenerator { // Check that the min width SRAM was chosen, even though it is less efficient. val output = -""" + """ circuit target_memory : module target_memory : input addr : UInt<10> diff --git a/macros/src/test/scala/barstools/macros/MacroCompilerSpec.scala b/macros/src/test/scala/barstools/macros/MacroCompilerSpec.scala index cf84e500..9140ce24 100644 --- a/macros/src/test/scala/barstools/macros/MacroCompilerSpec.scala +++ b/macros/src/test/scala/barstools/macros/MacroCompilerSpec.scala @@ -18,12 +18,12 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate // Override these to change the prefixing of macroDir and testDir val memPrefix: String = testDir val libPrefix: String = testDir - val vPrefix: String = testDir + val vPrefix: String = testDir // Override this to use a different cost metric. // If this is None, the compile() call will not have any -c/-cp arguments, and // execute() will use CostMetric.default. - val costMetric: Option[CostMetric] = None + val costMetric: Option[CostMetric] = None private def getCostMetric: CostMetric = costMetric.getOrElse(CostMetric.default) private def costMetricCmdLine = { @@ -32,17 +32,20 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate case Some(m) => { val name = m.name 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) = List("-m", mem.toString, "-v", v) ++ - (lib match { case None => Nil case Some(l) => List("-l", l.toString) }) ++ - costMetricCmdLine ++ - (if (synflops) List("--mode", "synflops") else Nil) ++ - (if (useCompiler) List("--use-compiler") else Nil) + (lib match { + case None => Nil + case Some(l) => List("-l", l.toString) + }) ++ + costMetricCmdLine ++ + (if (synflops) List("--mode", "synflops") else Nil) ++ + (if (useCompiler) List("--use-compiler") else Nil) // Run the full compiler as if from the command line interface. // Generates the Verilog; useful in testing since an error will throw an @@ -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. - 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) val result = execute(mem, lib, synflops, useCompiler) 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"). def test(result: Circuit, output: String): Unit = { - val gold = RemoveEmpty run parse(output) - (result.serialize) should be (gold.serialize) + val gold = RemoveEmpty.run(parse(output)) + (result.serialize) should be(gold.serialize) } // Execute the macro compiler and returns a Circuit containing the output of // the memory compiler. - def execute(memFile: Option[String], libFile: Option[String], synflops: Boolean): Circuit = execute(memFile, libFile, synflops, false) + def execute(memFile: Option[String], libFile: Option[String], synflops: Boolean): Circuit = + execute(memFile, libFile, synflops, false) def execute(memFile: Option[String], libFile: Option[String], synflops: Boolean, useCompiler: Boolean): Circuit = { var mem_full = concat(memPrefix, memFile) var lib_full = concat(libPrefix, libFile) require(memFile.isDefined) - val mems: Seq[Macro] = Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(mem_full)).get map (new Macro(_)) - val libs: Option[Seq[Macro]] = if(useCompiler) { - Utils.findSRAMCompiler(mdf.macrolib.Utils.readMDFFromPath(lib_full)).map{x => Utils.buildSRAMMacros(x).map(new Macro(_)) } + val mems: Seq[Macro] = Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(mem_full)).get.map(new Macro(_)) + val libs: Option[Seq[Macro]] = if (useCompiler) { + Utils.findSRAMCompiler(mdf.macrolib.Utils.readMDFFromPath(lib_full)).map { x => + Utils.buildSRAMMacros(x).map(new Macro(_)) + } } else { Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(lib_full)) match { - case Some(x) => Some(x map (new Macro(_))) - case None => None + case Some(x) => Some(x.map(new Macro(_))) + case None => None } } - val macros = mems map (_.blackbox) + val macros = mems.map(_.blackbox) val circuit = Circuit(NoInfo, macros, macros.last.name) val passes = Seq( - new MacroCompilerPass(Some(mems), libs, None, None, getCostMetric, if (synflops) MacroCompilerAnnotation.Synflops else MacroCompilerAnnotation.Default), - new SynFlopsPass(synflops, libs getOrElse mems), - RemoveEmpty) - val result: Circuit = (passes foldLeft circuit)((c, pass) => pass run c) + new MacroCompilerPass( + Some(mems), + libs, + None, + None, + getCostMetric, + if (synflops) MacroCompilerAnnotation.Synflops else MacroCompilerAnnotation.Default + ), + new SynFlopsPass(synflops, libs.getOrElse(mems)), + RemoveEmpty + ) + val result: Circuit = (passes.foldLeft(circuit))((c, pass) => pass.run(c)) result } - // Helper method to deal with String + Option[String] - private def concat(a: String, b: String): String = {a + "/" + b} + private def concat(a: String, b: String): String = { a + "/" + b } private def concat(a: String, b: Option[String]): Option[String] = { b match { - case Some(b2:String) => Some(a + "/" + b2) + case Some(b2: String) => Some(a + "/" + b2) case _ => None } } @@ -123,20 +143,19 @@ trait HasSRAMGenerator { import mdf.macrolib._ 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) - // Generate a standard (read/write/combo) port for testing. // Helper methods for optional width argument def generateTestPort( - prefix: String, - width: Option[Int], - depth: Option[BigInt], - maskGran: Option[Int] = None, - read: Boolean, - readEnable: Boolean = false, - write: Boolean, + prefix: String, + width: Option[Int], + depth: Option[BigInt], + maskGran: Option[Int] = None, + read: Boolean, + readEnable: Boolean = false, + write: Boolean, writeEnable: Boolean = false ): MacroPort = { val realPrefix = if (prefix == "") "" else prefix + "_" @@ -144,44 +163,70 @@ trait HasSRAMGenerator { MacroPort( address = PolarizedPort(name = realPrefix + "addr", polarity = ActiveHigh), clock = Some(PolarizedPort(name = realPrefix + "clk", polarity = PositiveEdge)), - readEnable = if (readEnable) Some(PolarizedPort(name = realPrefix + "read_en", polarity = ActiveHigh)) else None, - writeEnable = if (writeEnable) Some(PolarizedPort(name = realPrefix + "write_en", polarity = ActiveHigh)) else None, - + writeEnable = + if (writeEnable) Some(PolarizedPort(name = realPrefix + "write_en", polarity = ActiveHigh)) else None, output = if (read) Some(PolarizedPort(name = realPrefix + "dout", polarity = ActiveHigh)) else None, input = if (write) Some(PolarizedPort(name = realPrefix + "din", polarity = ActiveHigh)) else None, - maskPort = maskGran match { case Some(x: Int) => Some(PolarizedPort(name = realPrefix + "mask", polarity = ActiveHigh)) case _ => None }, maskGran = maskGran, - - width = width, depth = depth // These numbers don't matter here. + width = width, + depth = depth // These numbers don't matter here. ) } // Generate a read port for testing. - def generateReadPort(prefix: String, width: Option[Int], depth: Option[BigInt], readEnable: Boolean = false): MacroPort = { + def generateReadPort( + prefix: String, + width: Option[Int], + depth: Option[BigInt], + readEnable: Boolean = false + ): MacroPort = { generateTestPort(prefix, width, depth, write = false, read = true, readEnable = readEnable) } // Generate a write port for testing. - def generateWritePort(prefix: String, width: Option[Int], depth: Option[BigInt], maskGran: Option[Int] = None, writeEnable: Boolean = true): MacroPort = { + def generateWritePort( + prefix: String, + width: Option[Int], + depth: Option[BigInt], + maskGran: Option[Int] = None, + writeEnable: Boolean = true + ): MacroPort = { generateTestPort(prefix, width, depth, maskGran = maskGran, write = true, read = false, writeEnable = writeEnable) } // Generate a simple read-write port for testing. - def generateReadWritePort(prefix: String, width: Option[Int], depth: Option[BigInt], maskGran: Option[Int] = None): MacroPort = { + def generateReadWritePort( + prefix: String, + width: Option[Int], + depth: Option[BigInt], + maskGran: Option[Int] = None + ): MacroPort = { generateTestPort( - prefix, width, depth, maskGran = maskGran, - write = true, writeEnable = true, - read = true, readEnable = false + prefix, + width, + depth, + maskGran = maskGran, + write = true, + writeEnable = true, + read = true, + readEnable = false ) } // Generate a "simple" SRAM (active high/positive edge, 1 read-write port). - def generateSRAM(name: String, prefix: String, width: Int, depth: BigInt, maskGran: Option[Int] = None, extraPorts: Seq[MacroExtraPort] = List()): SRAMMacro = { + def generateSRAM( + name: String, + prefix: String, + width: Int, + depth: BigInt, + maskGran: Option[Int] = None, + extraPorts: Seq[MacroExtraPort] = List() + ): SRAMMacro = { SRAMMacro( name = name, width = width, @@ -193,17 +238,35 @@ trait HasSRAMGenerator { } // Generate a "simple" SRAM group (active high/positive edge, 1 read-write port). - def generateSimpleSRAMGroup(prefix: String, mux: Int, depth: Range, width: Range, maskGran: Option[Int] = None, extraPorts: Seq[MacroExtraPort] = List()): SRAMGroup = { - SRAMGroup(Seq("mygroup_", "width", "x", "depth", "_", "VT"), "1rw", Seq("svt", "lvt", "ulvt"), mux, depth, width, Seq(generateReadWritePort(prefix, None, None, maskGran))) + def generateSimpleSRAMGroup( + prefix: String, + mux: Int, + depth: Range, + width: Range, + maskGran: Option[Int] = None, + extraPorts: Seq[MacroExtraPort] = List() + ): SRAMGroup = { + SRAMGroup( + Seq("mygroup_", "width", "x", "depth", "_", "VT"), + "1rw", + Seq("svt", "lvt", "ulvt"), + mux, + depth, + width, + Seq(generateReadWritePort(prefix, None, None, maskGran)) + ) } // 'vt': ('svt','lvt','ulvt'), 'mux': 2, 'depth': range(16,513,8), 'width': range(8,289,2), 'ports': 1 // 'vt': ('svt','lvt','ulvt'), 'mux': 4, 'depth': range(32,1025,16), 'width': range(4,145), 'ports': 1} def generateSRAMCompiler(name: String, prefix: String): mdf.macrolib.SRAMCompiler = { - SRAMCompiler(name, Seq( - generateSimpleSRAMGroup(prefix, 2, Range(16, 512, 8), Range(8, 288, 2)), - generateSimpleSRAMGroup(prefix, 4, Range(32, 1024, 16), Range(4, 144, 1)) - )) + SRAMCompiler( + name, + Seq( + generateSimpleSRAMGroup(prefix, 2, Range(16, 512, 8), Range(8, 288, 2)), + generateSimpleSRAMGroup(prefix, 4, Range(32, 1024, 16), Range(4, 144, 1)) + ) + ) } } @@ -212,147 +275,156 @@ trait HasSRAMGenerator { // Override this generator to specify the expected FIRRTL output. trait HasSimpleTestGenerator { this: MacroCompilerSpec with HasSRAMGenerator => - // Override these with "override lazy val". - // Why lazy? These are used in the constructor here so overriding non-lazily - // would be too late. - def useCompiler: Boolean = false - def memWidth: Int - def libWidth: Int - def memDepth: BigInt - def libDepth: BigInt - def memMaskGran: Option[Int] = None - def libMaskGran: Option[Int] = None - def extraPorts: Seq[mdf.macrolib.MacroExtraPort] = List() - def extraTag: String = "" + // Override these with "override lazy val". + // Why lazy? These are used in the constructor here so overriding non-lazily + // would be too late. + def useCompiler: Boolean = false + def memWidth: Int + def libWidth: Int + def memDepth: BigInt + def libDepth: BigInt + def memMaskGran: Option[Int] = None + def libMaskGran: Option[Int] = None + def extraPorts: Seq[mdf.macrolib.MacroExtraPort] = List() + def extraTag: String = "" - // "Effective" libMaskGran by considering write_enable. - val effectiveLibMaskGran = libMaskGran.getOrElse(libWidth) + // "Effective" libMaskGran by considering write_enable. + val effectiveLibMaskGran = libMaskGran.getOrElse(libWidth) - // Override this in the sub-generator if you need a more specific name. - // Defaults to using reflection to pull the name of the test using this - // generator. - def generatorType: String = this.getClass.getSimpleName + // Override this in the sub-generator if you need a more specific name. + // Defaults to using reflection to pull the name of the test using this + // generator. + def generatorType: String = this.getClass.getSimpleName - //require (memDepth >= libDepth) + //require (memDepth >= libDepth) - // Convenience variables to check if a mask exists. - val memHasMask = memMaskGran != None - val libHasMask = libMaskGran != None - // We need to figure out how many mask bits there are in the mem. - val memMaskBits = if (memHasMask) memWidth / memMaskGran.get else 0 - val libMaskBits = if (libHasMask) libWidth / libMaskGran.get else 0 + // Convenience variables to check if a mask exists. + val memHasMask = memMaskGran != None + val libHasMask = libMaskGran != None + // We need to figure out how many mask bits there are in the mem. + val memMaskBits = if (memHasMask) memWidth / memMaskGran.get else 0 + val libMaskBits = if (libHasMask) libWidth / libMaskGran.get else 0 - val extraTagPrefixed = if (extraTag == "") "" else ("-" + extraTag) + val extraTagPrefixed = if (extraTag == "") "" else ("-" + extraTag) - val mem = s"mem-${generatorType}${extraTagPrefixed}.json" - val lib = s"lib-${generatorType}${extraTagPrefixed}.json" - val v = s"${generatorType}${extraTagPrefixed}.v" + val mem = s"mem-${generatorType}${extraTagPrefixed}.json" + val lib = s"lib-${generatorType}${extraTagPrefixed}.json" + val v = s"${generatorType}${extraTagPrefixed}.v" - lazy val mem_name = "target_memory" - val mem_addr_width = MacroCompilerMath.ceilLog2(memDepth) + lazy val mem_name = "target_memory" + val mem_addr_width = MacroCompilerMath.ceilLog2(memDepth) - lazy val lib_name = "awesome_lib_mem" - val lib_addr_width = MacroCompilerMath.ceilLog2(libDepth) + lazy val lib_name = "awesome_lib_mem" + val lib_addr_width = MacroCompilerMath.ceilLog2(libDepth) - // Override these to change the port prefixes if needed. - def libPortPrefix: String = "lib" - def memPortPrefix: String = "outer" + // Override these to change the port prefixes if needed. + def libPortPrefix: String = "lib" + def memPortPrefix: String = "outer" - // These generate "simple" SRAMs (1 masked read-write port) by default, - // but can be overridden if need be. - def generateLibSRAM() = generateSRAM(lib_name, libPortPrefix, libWidth, libDepth, libMaskGran, extraPorts) - def generateMemSRAM() = generateSRAM(mem_name, memPortPrefix, memWidth, memDepth, memMaskGran) + // These generate "simple" SRAMs (1 masked read-write port) by default, + // but can be overridden if need be. + def generateLibSRAM() = generateSRAM(lib_name, libPortPrefix, libWidth, libDepth, libMaskGran, extraPorts) + def generateMemSRAM() = generateSRAM(mem_name, memPortPrefix, memWidth, memDepth, memMaskGran) - def libSRAM = generateLibSRAM - def memSRAM = generateMemSRAM + def libSRAM = generateLibSRAM + def memSRAM = generateMemSRAM - def libSRAMs: Seq[SRAMMacro] = Seq(libSRAM) - def memSRAMs: Seq[SRAMMacro] = Seq(memSRAM) + def libSRAMs: Seq[SRAMMacro] = Seq(libSRAM) + def memSRAMs: Seq[SRAMMacro] = Seq(memSRAM) - writeToLib(lib, libSRAMs) - writeToMem(mem, memSRAMs) + writeToLib(lib, libSRAMs) + writeToMem(mem, memSRAMs) - // For masks, width it's a bit tricky since we have to consider cases like - // memMaskGran = 4 and libMaskGran = 8. - // Consider the actually usable libWidth in cases like the above. - val usableLibWidth = if (memMaskGran.getOrElse(Int.MaxValue) < effectiveLibMaskGran) memMaskGran.get else libWidth + // For masks, width it's a bit tricky since we have to consider cases like + // memMaskGran = 4 and libMaskGran = 8. + // Consider the actually usable libWidth in cases like the above. + val usableLibWidth = if (memMaskGran.getOrElse(Int.MaxValue) < effectiveLibMaskGran) memMaskGran.get else libWidth - // Number of lib instances needed to hold the mem, in both directions. - // Round up (e.g. 1.5 instances = effectively 2 instances) - val depthInstances = math.ceil(memDepth.toFloat / libDepth.toFloat).toInt - val widthInstances = math.ceil(memWidth.toFloat / usableLibWidth).toInt + // Number of lib instances needed to hold the mem, in both directions. + // Round up (e.g. 1.5 instances = effectively 2 instances) + val depthInstances = math.ceil(memDepth.toFloat / libDepth.toFloat).toInt + val widthInstances = math.ceil(memWidth.toFloat / usableLibWidth).toInt - // Number of width bits in the last width-direction memory. - // e.g. if memWidth = 16 and libWidth = 8, this would be 8 since the last memory 0_1 has 8 bits of input width. - // e.g. if memWidth = 9 and libWidth = 8, this would be 1 since the last memory 0_1 has 1 bit of input width. - lazy val lastWidthBits = if (memWidth % usableLibWidth == 0) usableLibWidth else (memWidth % usableLibWidth) - lazy val selectBits = mem_addr_width - lib_addr_width + // Number of width bits in the last width-direction memory. + // e.g. if memWidth = 16 and libWidth = 8, this would be 8 since the last memory 0_1 has 8 bits of input width. + // e.g. if memWidth = 9 and libWidth = 8, this would be 1 since the last memory 0_1 has 1 bit of input width. + lazy val lastWidthBits = if (memWidth % usableLibWidth == 0) usableLibWidth else (memWidth % usableLibWidth) + lazy val selectBits = mem_addr_width - lib_addr_width - /** - * Convenience function to generate a mask statement. - * @param widthInst Width instance (mem_0_x) - * @param depthInst Depth instance (mem_x_0) - */ - def generateMaskStatement(widthInst: Int, depthInst: Int): String = { - // Width of this submemory. - val myMemWidth = if (widthInst == widthInstances - 1) lastWidthBits else usableLibWidth - // Base bit of this submemory. - // e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this - // would be 16. - val myBaseBit = usableLibWidth*widthInst + /** Convenience function to generate a mask statement. + * @param widthInst Width instance (mem_0_x) + * @param depthInst Depth instance (mem_x_0) + */ + def generateMaskStatement(widthInst: Int, depthInst: Int): String = { + // Width of this submemory. + val myMemWidth = if (widthInst == widthInstances - 1) lastWidthBits else usableLibWidth + // Base bit of this submemory. + // e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this + // would be 16. + val myBaseBit = usableLibWidth * widthInst - if (libMaskGran.isDefined) { - if (memMaskGran.isEmpty) { - // If there is no memory mask, we should just turn all the lib mask - // bits high. - s"""mem_${depthInst}_${widthInst}.lib_mask <= UInt<${libMaskBits}>("h${((1 << libMaskBits) - 1).toHexString}")""" - } else { - // Calculate which bit of outer_mask contains the given bit. - // e.g. if memMaskGran = 2, libMaskGran = 1 and libWidth = 4, then - // calculateMaskBit({0, 1}) = 0 and calculateMaskBit({1, 2}) = 1 - def calculateMaskBit(bit:Int): Int = bit / memMaskGran.getOrElse(memWidth) + if (libMaskGran.isDefined) { + if (memMaskGran.isEmpty) { + // If there is no memory mask, we should just turn all the lib mask + // bits high. + s"""mem_${depthInst}_${widthInst}.lib_mask <= UInt<${libMaskBits}>("h${((1 << libMaskBits) - 1).toHexString}")""" + } else { + // Calculate which bit of outer_mask contains the given bit. + // e.g. if memMaskGran = 2, libMaskGran = 1 and libWidth = 4, then + // calculateMaskBit({0, 1}) = 0 and calculateMaskBit({1, 2}) = 1 + def calculateMaskBit(bit: Int): Int = bit / memMaskGran.getOrElse(memWidth) - val bitsArr = ((libMaskBits - 1 to 0 by -1) map (x => { - if (x*libMaskGran.get > myMemWidth) { - // If we have extra mask bits leftover after the effective width, - // disable those bits. - """UInt<1>("h0")""" - } else { - val outerMaskBit = calculateMaskBit(x*libMaskGran.get + myBaseBit) - s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" - } - })) - val maskVal = bitsArr.reduceRight((bit, rest) => s"cat($bit, $rest)") - s"mem_${depthInst}_${widthInst}.lib_mask <= ${maskVal}" - } - } else "" - } - - /** Helper function to generate a port. - * - * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") - * @param addrWidth Address port width - * @param width data width - * @param write Has a write port? - * @param writeEnable Has a write enable port? - * @param read Has a read port? - * @param readEnable Has a read enable port? - * @param mask Mask granularity (# bits) of the port or None. - * @param extraPorts Extra ports (name, # bits) - */ - def generatePort(prefix: String, addrWidth: Int, width: Int, write: Boolean, writeEnable: Boolean, read: Boolean, readEnable: Boolean, mask: Option[Int], extraPorts: Seq[(String, Int)] = Seq()): String = { - val realPrefix = if (prefix == "") "" else prefix + "_" - - val readStr = if (read) s"output ${realPrefix}dout : UInt<$width>" else "" - val writeStr = if (write) s"input ${realPrefix}din : UInt<$width>" else "" - val readEnableStr = if (readEnable) s"input ${realPrefix}read_en : UInt<1>" else "" - val writeEnableStr = if (writeEnable) s"input ${realPrefix}write_en : UInt<1>" else "" - val maskStr = mask match { - case Some(maskBits: Int) => s"input ${realPrefix}mask : UInt<$maskBits>" - case _ => "" + val bitsArr = ((libMaskBits - 1 to 0 by -1).map(x => { + if (x * libMaskGran.get > myMemWidth) { + // If we have extra mask bits leftover after the effective width, + // disable those bits. + """UInt<1>("h0")""" + } else { + val outerMaskBit = calculateMaskBit(x * libMaskGran.get + myBaseBit) + s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" + } + })) + val maskVal = bitsArr.reduceRight((bit, rest) => s"cat($bit, $rest)") + s"mem_${depthInst}_${widthInst}.lib_mask <= ${maskVal}" } - val extraPortsStr = extraPorts.map { case (name, bits) => s" input $name : UInt<$bits>" }.mkString("\n") - s""" + } else "" + } + + /** Helper function to generate a port. + * + * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") + * @param addrWidth Address port width + * @param width data width + * @param write Has a write port? + * @param writeEnable Has a write enable port? + * @param read Has a read port? + * @param readEnable Has a read enable port? + * @param mask Mask granularity (# bits) of the port or None. + * @param extraPorts Extra ports (name, # bits) + */ + def generatePort( + prefix: String, + addrWidth: Int, + width: Int, + write: Boolean, + writeEnable: Boolean, + read: Boolean, + readEnable: Boolean, + mask: Option[Int], + extraPorts: Seq[(String, Int)] = Seq() + ): String = { + val realPrefix = if (prefix == "") "" else prefix + "_" + + val readStr = if (read) s"output ${realPrefix}dout : UInt<$width>" else "" + val writeStr = if (write) s"input ${realPrefix}din : UInt<$width>" else "" + val readEnableStr = if (readEnable) s"input ${realPrefix}read_en : UInt<1>" else "" + val writeEnableStr = if (writeEnable) s"input ${realPrefix}write_en : UInt<1>" else "" + val maskStr = mask match { + case Some(maskBits: Int) => s"input ${realPrefix}mask : UInt<$maskBits>" + case _ => "" + } + val extraPortsStr = extraPorts.map { case (name, bits) => s" input $name : UInt<$bits>" }.mkString("\n") + s""" input ${realPrefix}addr : UInt<$addrWidth> input ${realPrefix}clk : Clock $writeStr @@ -362,92 +434,121 @@ trait HasSimpleTestGenerator { $maskStr $extraPortsStr """ - } + } - /** - * Helper function to generate a RW footer port. - * - * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") - * @param readEnable Has a read enable port? - * @param mask Mask granularity (# bits) of the port or None. - * @param extraPorts Extra ports (name, # bits) - */ - def generateReadWriteFooterPort(prefix: String, readEnable: Boolean, mask: Option[Int], extraPorts: Seq[(String, Int)] = Seq()): String = { - generatePort(prefix, lib_addr_width, libWidth, - write = true, writeEnable = true, read = true, readEnable = readEnable, mask = mask, extraPorts = extraPorts) - } + /** Helper function to generate a RW footer port. + * + * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") + * @param readEnable Has a read enable port? + * @param mask Mask granularity (# bits) of the port or None. + * @param extraPorts Extra ports (name, # bits) + */ + def generateReadWriteFooterPort( + prefix: String, + readEnable: Boolean, + mask: Option[Int], + extraPorts: Seq[(String, Int)] = Seq() + ): String = { + generatePort( + prefix, + lib_addr_width, + libWidth, + write = true, + writeEnable = true, + read = true, + readEnable = readEnable, + mask = mask, + extraPorts = extraPorts + ) + } - /** Helper function to generate a RW header port. - * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") - * @param readEnable Has a read enable port? - * @param mask Mask granularity (# bits) of the port or None. */ - def generateReadWriteHeaderPort(prefix: String, readEnable: Boolean, mask: Option[Int]): String = { - generatePort(prefix, mem_addr_width, memWidth, - write=true, writeEnable=true, read=true, readEnable=readEnable, mask) - } + /** Helper function to generate a RW header port. + * @param prefix Memory port prefix (e.g. "x" for ports like "x_clk") + * @param readEnable Has a read enable port? + * @param mask Mask granularity (# bits) of the port or None. + */ + def generateReadWriteHeaderPort(prefix: String, readEnable: Boolean, mask: Option[Int]): String = { + generatePort( + prefix, + mem_addr_width, + memWidth, + write = true, + writeEnable = true, + read = true, + readEnable = readEnable, + mask + ) + } - // Generate the header memory ports. - def generateHeaderPorts(): String = { - require (memSRAM.ports.size == 1, "Header generator only supports single RW port mem") - generateReadWriteHeaderPort(memPortPrefix, memSRAM.ports(0).readEnable.isDefined, if (memHasMask) Some(memMaskBits) else None) - } + // Generate the header memory ports. + def generateHeaderPorts(): String = { + require(memSRAM.ports.size == 1, "Header generator only supports single RW port mem") + generateReadWriteHeaderPort( + memPortPrefix, + memSRAM.ports(0).readEnable.isDefined, + if (memHasMask) Some(memMaskBits) else None + ) + } - // Generate the header (contains the circuit statement and the target memory - // module. - def generateHeader(): String = { - s""" + // Generate the header (contains the circuit statement and the target memory + // module. + def generateHeader(): String = { + s""" circuit $mem_name : module $mem_name : ${generateHeaderPorts} """ - } + } - // Generate the target memory ports. - def generateFooterPorts(): String = { - require(libSRAM.ports.size == 1, "Footer generator only supports single RW port mem") - generateReadWriteFooterPort(libPortPrefix, libSRAM.ports(0).readEnable.isDefined, - if (libHasMask) Some(libMaskBits) else None, extraPorts.map(p => (p.name, p.width))) - } + // Generate the target memory ports. + def generateFooterPorts(): String = { + require(libSRAM.ports.size == 1, "Footer generator only supports single RW port mem") + generateReadWriteFooterPort( + libPortPrefix, + libSRAM.ports(0).readEnable.isDefined, + if (libHasMask) Some(libMaskBits) else None, + extraPorts.map(p => (p.name, p.width)) + ) + } - // Generate the footer (contains the target memory extmodule declaration by default). - def generateFooter(): String = { - s""" + // Generate the footer (contains the target memory extmodule declaration by default). + def generateFooter(): String = { + s""" extmodule $lib_name : ${generateFooterPorts} defname = $lib_name """ - } + } - // Abstract method to generate body; to be overridden by specific generator type. - def generateBody(): String + // Abstract method to generate body; to be overridden by specific generator type. + def generateBody(): String - // Generate the entire output from header, body, and footer. - def generateOutput(): String = { - s""" + // Generate the entire output from header, body, and footer. + def generateOutput(): String = { + s""" ${generateHeader} ${generateBody} ${generateFooter} """ - } + } - val output = generateOutput() + val output = generateOutput() } // Use this trait for tests that invoke the memory compiler without lib. trait HasNoLibTestGenerator extends HasSimpleTestGenerator { this: MacroCompilerSpec with HasSRAMGenerator => - // If there isn't a lib, then the "lib" will become a FIRRTL "mem", which - // in turn becomes synthesized flops. - // Therefore, make "lib" width/depth equal to the mem. - override lazy val libDepth = memDepth - override lazy val libWidth = memWidth - override lazy val lib_name = mem_name - // Do the same for port names. - override lazy val libPortPrefix = memPortPrefix + // If there isn't a lib, then the "lib" will become a FIRRTL "mem", which + // in turn becomes synthesized flops. + // Therefore, make "lib" width/depth equal to the mem. + override lazy val libDepth = memDepth + override lazy val libWidth = memWidth + override lazy val lib_name = mem_name + // Do the same for port names. + override lazy val libPortPrefix = memPortPrefix - // If there is no lib, don't generate a body. - override def generateBody = "" + // If there is no lib, don't generate a body. + override def generateBody = "" } - diff --git a/macros/src/test/scala/barstools/macros/Masks.scala b/macros/src/test/scala/barstools/macros/Masks.scala index f104c8f2..c472669a 100644 --- a/macros/src/test/scala/barstools/macros/Masks.scala +++ b/macros/src/test/scala/barstools/macros/Masks.scala @@ -4,32 +4,36 @@ package barstools.macros trait MasksTestSettings { this: MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator => - override lazy val memDepth = BigInt(2048) - override lazy val libDepth = BigInt(1024) + override lazy val memDepth = BigInt(2048) + override lazy val libDepth = BigInt(1024) } // Try all four different kinds of mask config: -/** - * - * Non-masked mem Masked mem - * --------------------------------- - * Non-masked lib | | | - * --------------------------------- - * Masked lib | | | - * --------------------------------- - */ +/** Non-masked mem Masked mem + * --------------------------------- + * Non-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 memWidth = 32 override lazy val memMaskGran = None - override lazy val libWidth = 8 + override lazy val libWidth = 8 override lazy val libMaskGran = None compileExecuteAndTest(mem, lib, v, output) } -class Masks_FourTypes_NonMaskedMem_MaskedLib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class Masks_FourTypes_NonMaskedMem_MaskedLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 32 override lazy val memMaskGran = None @@ -39,7 +43,10 @@ class Masks_FourTypes_NonMaskedMem_MaskedLib extends MacroCompilerSpec with HasS compileExecuteAndTest(mem, lib, v, output) } -class Masks_FourTypes_MaskedMem_NonMaskedLib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class Masks_FourTypes_MaskedMem_NonMaskedLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 32 override lazy val memMaskGran = Some(8) @@ -49,7 +56,10 @@ class Masks_FourTypes_MaskedMem_NonMaskedLib extends MacroCompilerSpec with HasS compileExecuteAndTest(mem, lib, v, output) } -class Masks_FourTypes_MaskedMem_NonMaskedLib_SmallerMaskGran extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class Masks_FourTypes_MaskedMem_NonMaskedLib_SmallerMaskGran + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 32 override lazy val memMaskGran = Some(4) @@ -59,7 +69,10 @@ class Masks_FourTypes_MaskedMem_NonMaskedLib_SmallerMaskGran extends MacroCompil compileExecuteAndTest(mem, lib, v, output) } -class Masks_FourTypes_MaskedMem_MaskedLib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class Masks_FourTypes_MaskedMem_MaskedLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 32 override lazy val memMaskGran = Some(8) @@ -69,7 +82,10 @@ class Masks_FourTypes_MaskedMem_MaskedLib extends MacroCompilerSpec with HasSRAM compileExecuteAndTest(mem, lib, v, output) } -class Masks_FourTypes_MaskedMem_MaskedLib_SameMaskGran extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class Masks_FourTypes_MaskedMem_MaskedLib_SameMaskGran + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 32 override lazy val memMaskGran = Some(8) @@ -79,7 +95,10 @@ class Masks_FourTypes_MaskedMem_MaskedLib_SameMaskGran extends MacroCompilerSpec compileExecuteAndTest(mem, lib, v, output) } -class Masks_FourTypes_MaskedMem_MaskedLib_SmallerMaskGran extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class Masks_FourTypes_MaskedMem_MaskedLib_SmallerMaskGran + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 64 override lazy val memMaskGran = Some(4) @@ -103,7 +122,11 @@ class Masks_BitMaskedMem_NonMaskedLib extends MacroCompilerSpec with HasSRAMGene // FPGA-style byte-masked memories. -class Masks_FPGAStyle_32_8 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_FPGAStyle_32_8 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 32 override lazy val memMaskGran = Some(32) override lazy val libMaskGran = Some(8) @@ -113,7 +136,11 @@ class Masks_FPGAStyle_32_8 extends MacroCompilerSpec with HasSRAMGenerator with // Simple powers of two with bit-masked lib. -class Masks_PowersOfTwo_8_1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_8_1 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 64 override lazy val memMaskGran = Some(8) override lazy val libMaskGran = Some(1) @@ -121,7 +148,11 @@ class Masks_PowersOfTwo_8_1 extends MacroCompilerSpec with HasSRAMGenerator with compileExecuteAndTest(mem, lib, v, output) } -class Masks_PowersOfTwo_16_1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_16_1 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 64 override lazy val memMaskGran = Some(16) override lazy val libMaskGran = Some(1) @@ -129,7 +160,11 @@ class Masks_PowersOfTwo_16_1 extends MacroCompilerSpec with HasSRAMGenerator wit compileExecuteAndTest(mem, lib, v, output) } -class Masks_PowersOfTwo_32_1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_32_1 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 64 override lazy val memMaskGran = Some(32) override lazy val libMaskGran = Some(1) @@ -137,7 +172,11 @@ class Masks_PowersOfTwo_32_1 extends MacroCompilerSpec with HasSRAMGenerator wit compileExecuteAndTest(mem, lib, v, output) } -class Masks_PowersOfTwo_64_1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_64_1 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 64 override lazy val memMaskGran = Some(64) override lazy val libMaskGran = Some(1) @@ -147,7 +186,11 @@ class Masks_PowersOfTwo_64_1 extends MacroCompilerSpec with HasSRAMGenerator wit // Simple powers of two with non bit-masked lib. -class Masks_PowersOfTwo_32_4 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_32_4 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 128 override lazy val memMaskGran = Some(32) override lazy val libMaskGran = Some(4) @@ -155,7 +198,11 @@ class Masks_PowersOfTwo_32_4 extends MacroCompilerSpec with HasSRAMGenerator wit compileExecuteAndTest(mem, lib, v, output) } -class Masks_PowersOfTwo_32_8 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_32_8 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 128 override lazy val memMaskGran = Some(32) override lazy val libMaskGran = Some(8) @@ -163,7 +210,11 @@ class Masks_PowersOfTwo_32_8 extends MacroCompilerSpec with HasSRAMGenerator wit compileExecuteAndTest(mem, lib, v, output) } -class Masks_PowersOfTwo_8_8 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_PowersOfTwo_8_8 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 128 override lazy val memMaskGran = Some(8) override lazy val libMaskGran = Some(8) @@ -173,7 +224,11 @@ class Masks_PowersOfTwo_8_8 extends MacroCompilerSpec with HasSRAMGenerator with // Width as a multiple of the mask, bit-masked lib -class Masks_IntegerMaskMultiple_20_10 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_20_10 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 20 override lazy val memMaskGran = Some(10) override lazy val libMaskGran = Some(1) @@ -181,16 +236,24 @@ class Masks_IntegerMaskMultiple_20_10 extends MacroCompilerSpec with HasSRAMGene compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_21_7 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_21_7 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 21 override lazy val memMaskGran = Some(21) override lazy val libMaskGran = Some(7) - it should "be enabled when non-power of two masks are supported" is (pending) + (it should "be enabled when non-power of two masks are supported").is(pending) //~ compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_21_21 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_21_21 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 21 override lazy val memMaskGran = Some(21) override lazy val libMaskGran = Some(1) @@ -198,7 +261,11 @@ class Masks_IntegerMaskMultiple_21_21 extends MacroCompilerSpec with HasSRAMGene compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_84_21 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_84_21 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 84 override lazy val memMaskGran = Some(21) override lazy val libMaskGran = Some(1) @@ -206,7 +273,11 @@ class Masks_IntegerMaskMultiple_84_21 extends MacroCompilerSpec with HasSRAMGene compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_92_23 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_92_23 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 92 override lazy val memMaskGran = Some(23) override lazy val libMaskGran = Some(1) @@ -214,7 +285,11 @@ class Masks_IntegerMaskMultiple_92_23 extends MacroCompilerSpec with HasSRAMGene compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_117_13 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_117_13 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 117 override lazy val memMaskGran = Some(13) override lazy val libMaskGran = Some(1) @@ -222,7 +297,11 @@ class Masks_IntegerMaskMultiple_117_13 extends MacroCompilerSpec with HasSRAMGen compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_160_20 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_160_20 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 160 override lazy val memMaskGran = Some(20) override lazy val libMaskGran = Some(1) @@ -230,7 +309,11 @@ class Masks_IntegerMaskMultiple_160_20 extends MacroCompilerSpec with HasSRAMGen compileExecuteAndTest(mem, lib, v, output) } -class Masks_IntegerMaskMultiple_184_23 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_IntegerMaskMultiple_184_23 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 184 override lazy val memMaskGran = Some(23) override lazy val libMaskGran = Some(1) @@ -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 -class Masks_NonIntegerMaskMultiple_32_3 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { +class Masks_NonIntegerMaskMultiple_32_3 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with MasksTestSettings { override lazy val width = 32 override lazy val memMaskGran = Some(3) override lazy val libMaskGran = Some(1) - it should "be enabled when non-power of two masks are supported" is (pending) + (it should "be enabled when non-power of two masks are supported").is(pending) //~ compileExecuteAndTest(mem, lib, v, output) } diff --git a/macros/src/test/scala/barstools/macros/MultiPort.scala b/macros/src/test/scala/barstools/macros/MultiPort.scala index 3899f835..1968f6aa 100644 --- a/macros/src/test/scala/barstools/macros/MultiPort.scala +++ b/macros/src/test/scala/barstools/macros/MultiPort.scala @@ -13,42 +13,70 @@ class SplitWidth_2rw extends MacroCompilerSpec with HasSRAMGenerator with HasSim override def generateMemSRAM() = { SRAMMacro( - name=mem_name, - width=memWidth, - depth=memDepth, - family="2rw", - ports=Seq(generateTestPort( - "portA", memWidth, Some(memDepth), maskGran=memMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - ), generateTestPort( - "portB", memWidth, Some(memDepth), maskGran=memMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = mem_name, + width = memWidth, + depth = memDepth, + family = "2rw", + ports = Seq( + generateTestPort( + "portA", + memWidth, + Some(memDepth), + maskGran = memMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ), + generateTestPort( + "portB", + memWidth, + Some(memDepth), + maskGran = memMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateLibSRAM() = { SRAMMacro( - name=lib_name, - width=libWidth, - depth=libDepth, - family="2rw", - ports=Seq(generateTestPort( - "portA", libWidth, libDepth, - write=true, writeEnable=true, - read=true, readEnable=true - ), generateTestPort( - "portB", libWidth, libDepth, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = lib_name, + width = libWidth, + depth = libDepth, + family = "2rw", + ports = Seq( + generateTestPort( + "portA", + libWidth, + libDepth, + write = true, + writeEnable = true, + read = true, + readEnable = true + ), + generateTestPort( + "portB", + libWidth, + libDepth, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateHeaderPorts() = { - generateReadWriteHeaderPort("portA", true, Some(memMaskBits)) + "\n" + generateReadWriteHeaderPort("portB", true, Some(memMaskBits)) + generateReadWriteHeaderPort("portA", true, Some(memMaskBits)) + "\n" + generateReadWriteHeaderPort( + "portB", + true, + Some(memMaskBits) + ) } override def generateFooterPorts() = { @@ -56,7 +84,7 @@ class SplitWidth_2rw extends MacroCompilerSpec with HasSRAMGenerator with HasSim } override def generateBody() = -""" + """ inst mem_0_0 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem inst mem_0_2 of awesome_lib_mem @@ -128,56 +156,112 @@ class SplitWidth_1r_1w extends MacroCompilerSpec with HasSRAMGenerator with HasS override def generateMemSRAM() = { SRAMMacro( - name=mem_name, - width=memWidth, - depth=memDepth, - family="1r1w", - ports=Seq(generateTestPort( - "portA", memWidth, Some(memDepth), maskGran=memMaskGran, - write=false, writeEnable=false, - read=true, readEnable=true - ), generateTestPort( - "portB", memWidth, Some(memDepth), maskGran=memMaskGran, - write=true, writeEnable=true, - read=false, readEnable=false - )) + name = mem_name, + width = memWidth, + depth = memDepth, + family = "1r1w", + ports = Seq( + generateTestPort( + "portA", + memWidth, + Some(memDepth), + maskGran = memMaskGran, + write = false, + writeEnable = false, + read = true, + readEnable = true + ), + generateTestPort( + "portB", + memWidth, + Some(memDepth), + maskGran = memMaskGran, + write = true, + writeEnable = true, + read = false, + readEnable = false + ) + ) ) } override def generateLibSRAM() = { SRAMMacro( - name=lib_name, - width=libWidth, - depth=libDepth, - family="1r1w", - ports=Seq(generateTestPort( - "portA", libWidth, libDepth, - write=false, writeEnable=false, - read=true, readEnable=true - ), generateTestPort( - "portB", libWidth, libDepth, - write=true, writeEnable=true, - read=false, readEnable=false - )) + name = lib_name, + width = libWidth, + depth = libDepth, + family = "1r1w", + ports = Seq( + generateTestPort( + "portA", + libWidth, + libDepth, + write = false, + writeEnable = false, + read = true, + readEnable = true + ), + generateTestPort( + "portB", + libWidth, + libDepth, + write = true, + writeEnable = true, + read = false, + readEnable = false + ) + ) ) } override def generateHeaderPorts() = { - generatePort("portA", mem_addr_width, memWidth, - write=false, writeEnable=false, read=true, readEnable=true, Some(memMaskBits)) + "\n" + - generatePort("portB", mem_addr_width, memWidth, - write=true, writeEnable=true, read=false, readEnable=false, Some(memMaskBits)) + generatePort( + "portA", + mem_addr_width, + memWidth, + write = false, + writeEnable = false, + read = true, + readEnable = true, + Some(memMaskBits) + ) + "\n" + + generatePort( + "portB", + mem_addr_width, + memWidth, + write = true, + writeEnable = true, + read = false, + readEnable = false, + Some(memMaskBits) + ) } override def generateFooterPorts() = { - generatePort("portA", lib_addr_width, libWidth, - write=false, writeEnable=false, read=true, readEnable=true, None) + "\n" + - generatePort("portB", lib_addr_width, libWidth, - write=true, writeEnable=true, read=false, readEnable=false, None) + generatePort( + "portA", + lib_addr_width, + libWidth, + write = false, + writeEnable = false, + read = true, + readEnable = true, + None + ) + "\n" + + generatePort( + "portB", + lib_addr_width, + libWidth, + write = true, + writeEnable = true, + read = false, + readEnable = false, + None + ) } override def generateBody() = -""" + """ inst mem_0_0 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem inst mem_0_2 of awesome_lib_mem @@ -234,42 +318,70 @@ class SplitWidth_2rw_differentMasks extends MacroCompilerSpec with HasSRAMGenera override def generateMemSRAM() = { println(memMaskGranB) SRAMMacro( - name=mem_name, - width=memWidth, - depth=memDepth, - family="2rw", - ports=Seq(generateTestPort( - "portA", memWidth, Some(memDepth), maskGran=memMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - ), generateTestPort( - "portB", memWidth, Some(memDepth), maskGran=Some(memMaskGranB), - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = mem_name, + width = memWidth, + depth = memDepth, + family = "2rw", + ports = Seq( + generateTestPort( + "portA", + memWidth, + Some(memDepth), + maskGran = memMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ), + generateTestPort( + "portB", + memWidth, + Some(memDepth), + maskGran = Some(memMaskGranB), + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateLibSRAM() = { SRAMMacro( - name=lib_name, - width=libWidth, - depth=libDepth, - family="2rw", - ports=Seq(generateTestPort( - "portA", libWidth, libDepth, - write=true, writeEnable=true, - read=true, readEnable=true - ), generateTestPort( - "portB", libWidth, libDepth, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = lib_name, + width = libWidth, + depth = libDepth, + family = "2rw", + ports = Seq( + generateTestPort( + "portA", + libWidth, + libDepth, + write = true, + writeEnable = true, + read = true, + readEnable = true + ), + generateTestPort( + "portB", + libWidth, + libDepth, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateHeaderPorts() = { - generateReadWriteHeaderPort("portA", true, Some(memMaskBits)) + "\n" + generateReadWriteHeaderPort("portB", true, Some(memWidth / memMaskGranB)) + generateReadWriteHeaderPort("portA", true, Some(memMaskBits)) + "\n" + generateReadWriteHeaderPort( + "portB", + true, + Some(memWidth / memMaskGranB) + ) } override def generateFooterPorts() = { @@ -277,7 +389,7 @@ class SplitWidth_2rw_differentMasks extends MacroCompilerSpec with HasSRAMGenera } override def generateBody() = -""" + """ inst mem_0_0 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem inst mem_0_2 of awesome_lib_mem diff --git a/macros/src/test/scala/barstools/macros/SRAMCompiler.scala b/macros/src/test/scala/barstools/macros/SRAMCompiler.scala index e4e62de7..17f49601 100644 --- a/macros/src/test/scala/barstools/macros/SRAMCompiler.scala +++ b/macros/src/test/scala/barstools/macros/SRAMCompiler.scala @@ -13,8 +13,7 @@ class SRAMCompiler extends MacroCompilerSpec with HasSRAMGenerator with HasSimpl writeToLib(lib, Seq(compiler)) - writeToMem(mem, Seq(generateSRAM("mymem", "X", 8, 16))) - compileExecuteAndTest(mem, Some(lib), verilog, output=output, false, true) + compileExecuteAndTest(mem, Some(lib), verilog, output = output, false, true) } diff --git a/macros/src/test/scala/barstools/macros/SimpleSplitDepth.scala b/macros/src/test/scala/barstools/macros/SimpleSplitDepth.scala index f016dbc7..5a7fc77d 100644 --- a/macros/src/test/scala/barstools/macros/SimpleSplitDepth.scala +++ b/macros/src/test/scala/barstools/macros/SimpleSplitDepth.scala @@ -6,33 +6,36 @@ package barstools.macros trait HasSimpleDepthTestGenerator extends HasSimpleTestGenerator { this: MacroCompilerSpec with HasSRAMGenerator => - def width: Int + def width: Int - override lazy val memWidth = width - override lazy val libWidth = width + override lazy val memWidth = width + override lazy val libWidth = width - // Generate a depth-splitting body. - override def generateBody(): String = { - val output = new StringBuilder + // Generate a depth-splitting body. + override def generateBody(): String = { + val output = new StringBuilder - if (selectBits > 0) { - output.append ( -s""" + if (selectBits > 0) { + output.append( + s""" node ${memPortPrefix}_addr_sel = bits(${memPortPrefix}_addr, ${mem_addr_width - 1}, $lib_addr_width) reg ${memPortPrefix}_addr_sel_reg : UInt<${selectBits}>, ${memPortPrefix}_clk with : reset => (UInt<1>("h0"), ${memPortPrefix}_addr_sel_reg) ${memPortPrefix}_addr_sel_reg <= mux(UInt<1>("h1"), ${memPortPrefix}_addr_sel, ${memPortPrefix}_addr_sel_reg) """ - ) - } + ) + } - for (i <- 0 to depthInstances - 1) { - val maskStatement = generateMaskStatement(0, i) - val enableIdentifier = if (selectBits > 0) s"""eq(${memPortPrefix}_addr_sel, UInt<${selectBits}>("h${i.toHexString}"))""" else "UInt<1>(\"h1\")" - val chipEnable = s"""UInt<1>("h1")""" - val writeEnable = if (memMaskGran.isEmpty) s"and(${memPortPrefix}_write_en, ${chipEnable})" else s"${memPortPrefix}_write_en" - output.append( - s""" + for (i <- 0 to depthInstances - 1) { + val maskStatement = generateMaskStatement(0, i) + val enableIdentifier = + if (selectBits > 0) s"""eq(${memPortPrefix}_addr_sel, UInt<${selectBits}>("h${i.toHexString}"))""" + else "UInt<1>(\"h1\")" + val chipEnable = s"""UInt<1>("h1")""" + val writeEnable = + if (memMaskGran.isEmpty) s"and(${memPortPrefix}_write_en, ${chipEnable})" else s"${memPortPrefix}_write_en" + output.append( + s""" inst mem_${i}_0 of ${lib_name} mem_${i}_0.${libPortPrefix}_clk <= ${memPortPrefix}_clk mem_${i}_0.${libPortPrefix}_addr <= ${memPortPrefix}_addr @@ -42,26 +45,29 @@ s""" mem_${i}_0.${libPortPrefix}_write_en <= and(and(${writeEnable}, UInt<1>("h1")), ${enableIdentifier}) node ${memPortPrefix}_dout_${i} = ${memPortPrefix}_dout_${i}_0 """ + ) + } + def generate_outer_dout_tree(i: Int, depthInstances: Int): String = { + if (i > depthInstances - 1) { + s"""UInt<${libWidth}>("h0")""" + } else { + s"""mux(eq(${memPortPrefix}_addr_sel_reg, UInt<%d>("h%s")), ${memPortPrefix}_dout_%d, %s)""".format( + selectBits, + i.toHexString, + i, + generate_outer_dout_tree(i + 1, depthInstances) ) } - 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 @@ -154,7 +160,10 @@ class SplitDepth2048x8_mrw_lib8 extends MacroCompilerSpec with HasSRAMGenerator } // Non-bit level mask -class SplitDepth2048x64_mrw_mem32_lib8 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { +class SplitDepth2048x64_mrw_mem32_lib8 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator { override lazy val width = 64 override lazy val memDepth = BigInt(2048) override lazy val libDepth = BigInt(1024) @@ -165,7 +174,10 @@ class SplitDepth2048x64_mrw_mem32_lib8 extends MacroCompilerSpec with HasSRAMGen } // Bit level mask -class SplitDepth2048x32_mrw_mem16_lib1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { +class SplitDepth2048x32_mrw_mem16_lib1 + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator { override lazy val width = 32 override lazy val memDepth = BigInt(2048) override lazy val libDepth = BigInt(1024) @@ -213,7 +225,7 @@ class SplitDepth2048x32_mrw_mem3_lib1 extends MacroCompilerSpec with HasSRAMGene override lazy val memMaskGran = Some(3) override lazy val libMaskGran = Some(1) - it should "be enabled when non-power of two masks are supported" is (pending) + (it should "be enabled when non-power of two masks are supported").is(pending) //compileExecuteAndTest(mem, lib, v, output) } @@ -224,7 +236,7 @@ class SplitDepth2048x32_mrw_mem7_lib1 extends MacroCompilerSpec with HasSRAMGene override lazy val memMaskGran = Some(7) override lazy val libMaskGran = Some(1) - it should "be enabled when non-power of two masks are supported" is (pending) + (it should "be enabled when non-power of two masks are supported").is(pending) //compileExecuteAndTest(mem, lib, v, output) } @@ -235,7 +247,7 @@ class SplitDepth2048x32_mrw_mem9_lib1 extends MacroCompilerSpec with HasSRAMGene override lazy val memMaskGran = Some(9) override lazy val libMaskGran = Some(1) - it should "be enabled when non-power of two masks are supported" is (pending) + (it should "be enabled when non-power of two masks are supported").is(pending) //compileExecuteAndTest(mem, lib, v, output) } @@ -247,12 +259,12 @@ class SplitDepth2048x8_extraPort extends MacroCompilerSpec with HasSRAMGenerator override lazy val memDepth = BigInt(2048) override lazy val libDepth = BigInt(1024) override lazy val extraPorts = List( - MacroExtraPort(name="extra_port", width=8, portType=Constant, value=0xff) + MacroExtraPort(name = "extra_port", width = 8, portType = Constant, value = 0xff) ) override lazy val extraTag = "extraPort" override def generateOutput(): String = -""" + """ circuit target_memory : module target_memory : input outer_addr : UInt<11> @@ -317,22 +329,22 @@ class SplitDepth_SplitPortsNonMasked extends MacroCompilerSpec with HasSRAMGener val v = "split_depth-r-w-split-lib-split-mem.v" val libMacro = SRAMMacro( - name="awesome_lib_mem", - width=width, - depth=libDepth, - family="1r1w", - ports=Seq( + name = "awesome_lib_mem", + width = width, + depth = libDepth, + family = "1r1w", + ports = Seq( generateReadPort("innerA", width, libDepth), generateWritePort("innerB", width, libDepth) ) ) val memMacro = SRAMMacro( - name="target_memory", - width=width, - depth=memDepth, - family="1r1w", - ports=Seq( + name = "target_memory", + width = width, + depth = memDepth, + family = "1r1w", + ports = Seq( generateReadPort("outerB", width, memDepth), generateWritePort("outerA", width, memDepth) ) @@ -342,7 +354,7 @@ class SplitDepth_SplitPortsNonMasked extends MacroCompilerSpec with HasSRAMGener writeToLib(lib, Seq(libMacro)) val output = -""" + """ circuit target_memory : module target_memory : input outerB_addr : UInt<11> @@ -404,11 +416,11 @@ circuit target_memory : val v = "split_depth-r-w-regular-lib-split-mem.v" val memMacro = SRAMMacro( - name="target_memory", - width=width, - depth=memDepth, - family="1r1w", - ports=Seq( + name = "target_memory", + width = width, + depth = memDepth, + family = "1r1w", + ports = Seq( generateReadPort("outerB", width, memDepth), generateWritePort("outerA", width, memDepth) ) @@ -418,7 +430,7 @@ circuit target_memory : writeToLib(lib, Seq(generateSRAM("awesome_lib_mem", "lib", width, libDepth))) val output = -""" + """ TODO """ @@ -437,11 +449,11 @@ TODO val v = "split_depth-r-w-split-lib-regular-mem.v" val libMacro = SRAMMacro( - name="awesome_lib_mem", - width=width, - depth=libDepth, - family="1rw", - ports=Seq( + name = "awesome_lib_mem", + width = width, + depth = libDepth, + family = "1rw", + ports = Seq( generateReadPort("innerA", width, libDepth), generateWritePort("innerB", width, libDepth) ) @@ -451,7 +463,7 @@ TODO writeToLib(lib, Seq(libMacro)) val output = -""" + """ TODO """ @@ -478,22 +490,22 @@ class SplitDepth_SplitPortsMasked extends MacroCompilerSpec with HasSRAMGenerato val v = "split_depth-r-mw-split-lib-split-mem.v" val libMacro = SRAMMacro( - name="awesome_lib_mem", - width=width, - depth=libDepth, - family="1r1w", - ports=Seq( + name = "awesome_lib_mem", + width = width, + depth = libDepth, + family = "1r1w", + ports = Seq( generateReadPort("innerA", width, libDepth), generateWritePort("innerB", width, libDepth, libMaskGran) ) ) val memMacro = SRAMMacro( - name="target_memory", - width=width, - depth=memDepth, - family="1r1w", - ports=Seq( + name = "target_memory", + width = width, + depth = memDepth, + family = "1r1w", + ports = Seq( generateReadPort("outerB", width, memDepth), generateWritePort("outerA", width, memDepth, memMaskGran) ) @@ -503,7 +515,7 @@ class SplitDepth_SplitPortsMasked extends MacroCompilerSpec with HasSRAMGenerato writeToLib(lib, Seq(libMacro)) val output = -""" + """ circuit target_memory : module target_memory : input outerB_addr : UInt<11> @@ -569,11 +581,11 @@ circuit target_memory : val v = "split_depth-r-mw-regular-lib-split-mem.v" val memMacro = SRAMMacro( - name="target_memory", - width=width, - depth=memDepth, - family="1r1w", - ports=Seq( + name = "target_memory", + width = width, + depth = memDepth, + family = "1r1w", + ports = Seq( generateReadPort("outerB", width, memDepth), generateWritePort("outerA", width, memDepth, memMaskGran) ) @@ -583,7 +595,7 @@ circuit target_memory : writeToLib(lib, Seq(generateSRAM("awesome_lib_mem", "lib", width, libDepth, libMaskGran))) val output = -""" + """ TODO """ @@ -602,11 +614,11 @@ TODO val v = "split_depth-r-mw-split-lib-regular-mem.v" val libMacro = SRAMMacro( - name="awesome_lib_mem", - width=width, - depth=libDepth, - family="1rw", - ports=Seq( + name = "awesome_lib_mem", + width = width, + depth = libDepth, + family = "1rw", + ports = Seq( generateReadPort("innerA", width, libDepth), generateWritePort("innerB", width, libDepth, libMaskGran) ) @@ -616,7 +628,7 @@ TODO writeToLib(lib, Seq(libMacro)) val output = -""" + """ TODO """ diff --git a/macros/src/test/scala/barstools/macros/SimpleSplitWidth.scala b/macros/src/test/scala/barstools/macros/SimpleSplitWidth.scala index 843eed49..3cd0a6df 100644 --- a/macros/src/test/scala/barstools/macros/SimpleSplitWidth.scala +++ b/macros/src/test/scala/barstools/macros/SimpleSplitWidth.scala @@ -5,43 +5,45 @@ package barstools.macros trait HasSimpleWidthTestGenerator extends HasSimpleTestGenerator { this: MacroCompilerSpec with HasSRAMGenerator => - def depth: BigInt + def depth: BigInt - override lazy val memDepth = depth - override lazy val libDepth = depth + override lazy val memDepth = depth + override lazy val libDepth = depth - override def generateBody(): String = { - val output = new StringBuilder + override def generateBody(): String = { + val output = new StringBuilder - // Generate mem_0_ lines for number of width instances. - output.append( - ((0 to widthInstances - 1) map {i:Int => s""" + // Generate mem_0_ lines for number of width instances. + output.append( + ((0 to widthInstances - 1).map { i: Int => + s""" inst mem_0_${i} of ${lib_name} """ - }).reduceLeft(_ + _) - ) + }).reduceLeft(_ + _) + ) - // Generate submemory connection blocks. - output append (for (i <- 0 to widthInstances - 1) yield { - // Width of this submemory. - val myMemWidth = if (i == widthInstances - 1) lastWidthBits else usableLibWidth - // Base bit of this submemory. - // e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this - // would be 16. - val myBaseBit = usableLibWidth*i + // Generate submemory connection blocks. + output.append((for (i <- 0 to widthInstances - 1) yield { + // Width of this submemory. + val myMemWidth = if (i == widthInstances - 1) lastWidthBits else usableLibWidth + // Base bit of this submemory. + // e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this + // would be 16. + val myBaseBit = usableLibWidth * i - val maskStatement = generateMaskStatement(i, 0) + val maskStatement = generateMaskStatement(i, 0) - // We need to use writeEnable as a crude "mask" if mem has a mask but - // lib does not. - val writeEnableBit = if (libMaskGran.isEmpty && memMaskGran.isDefined) { - val outerMaskBit = myBaseBit / memMaskGran.get - s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" - } else """UInt<1>("h1")""" - val chipEnable = s"""UInt<1>("h1")""" - val writeEnableExpr = if (libMaskGran.isEmpty) s"and(${memPortPrefix}_write_en, ${chipEnable})" else s"${memPortPrefix}_write_en" + // We need to use writeEnable as a crude "mask" if mem has a mask but + // lib does not. + val writeEnableBit = if (libMaskGran.isEmpty && memMaskGran.isDefined) { + val outerMaskBit = myBaseBit / memMaskGran.get + s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" + } else """UInt<1>("h1")""" + val chipEnable = s"""UInt<1>("h1")""" + val writeEnableExpr = + if (libMaskGran.isEmpty) s"and(${memPortPrefix}_write_en, ${chipEnable})" else s"${memPortPrefix}_write_en" -s""" + s""" mem_0_${i}.${libPortPrefix}_clk <= ${memPortPrefix}_clk mem_0_${i}.${libPortPrefix}_addr <= ${memPortPrefix}_addr node ${memPortPrefix}_dout_0_${i} = bits(mem_0_${i}.${libPortPrefix}_dout, ${myMemWidth - 1}, 0) @@ -49,24 +51,23 @@ s""" ${maskStatement} mem_0_${i}.${libPortPrefix}_write_en <= and(and(${writeEnableExpr}, ${writeEnableBit}), UInt<1>("h1")) """ - }).reduceLeft(_ + _) + }).reduceLeft(_ + _)) - // Generate final output that concats together the sub-memories. - // e.g. cat(outer_dout_0_2, cat(outer_dout_0_1, outer_dout_0_0)) - output append { - val doutStatements = ((widthInstances - 1 to 0 by -1) map (i => s"${memPortPrefix}_dout_0_${i}")) - val catStmt = doutStatements.init.foldRight(doutStatements.last)((l: String, r: String) => s"cat($l, $r)") -s""" + // Generate final output that concats together the sub-memories. + // e.g. cat(outer_dout_0_2, cat(outer_dout_0_1, outer_dout_0_0)) + output.append { + val doutStatements = ((widthInstances - 1 to 0 by -1).map(i => s"${memPortPrefix}_dout_0_${i}")) + val catStmt = doutStatements.init.foldRight(doutStatements.last)((l: String, r: String) => s"cat($l, $r)") + s""" node ${memPortPrefix}_dout_0 = ${catStmt} """ - } - - output append -s""" - ${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. @@ -268,7 +269,10 @@ class SplitWidth1024x16_mem11_rw extends MacroCompilerSpec with HasSRAMGenerator // Masked RAM -class SplitWidth1024x8_memGran_8_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x8_memGran_8_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 8 override lazy val libWidth = 8 @@ -278,7 +282,10 @@ class SplitWidth1024x8_memGran_8_libGran_1_rw extends MacroCompilerSpec with Has compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x16_memGran_8_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_8_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 @@ -288,7 +295,10 @@ class SplitWidth1024x16_memGran_8_libGran_1_rw extends MacroCompilerSpec with Ha compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x16_memGran_8_libGran_8_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_8_libGran_8_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 @@ -298,7 +308,10 @@ class SplitWidth1024x16_memGran_8_libGran_8_rw extends MacroCompilerSpec with Ha compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x128_memGran_8_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x128_memGran_8_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 128 override lazy val libWidth = 32 @@ -308,7 +321,10 @@ class SplitWidth1024x128_memGran_8_libGran_1_rw extends MacroCompilerSpec with H compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x16_memGran_4_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_4_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 @@ -318,7 +334,10 @@ class SplitWidth1024x16_memGran_4_libGran_1_rw extends MacroCompilerSpec with Ha compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x16_memGran_2_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_2_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 @@ -328,7 +347,10 @@ class SplitWidth1024x16_memGran_2_libGran_1_rw extends MacroCompilerSpec with Ha compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x16_memGran_16_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_16_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 @@ -360,7 +382,10 @@ class SplitWidth1024x16_libGran_1_rw extends MacroCompilerSpec with HasSRAMGener // Non-memMask and non-1 libMask -class SplitWidth1024x16_memGran_8_libGran_2_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_8_libGran_2_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 @@ -372,21 +397,27 @@ class SplitWidth1024x16_memGran_8_libGran_2_rw extends MacroCompilerSpec with Ha // Non-power of two memGran -class SplitWidth1024x16_memGran_9_libGran_1_rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x16_memGran_9_libGran_1_rw + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { override lazy val depth = BigInt(1024) override lazy val memWidth = 16 override lazy val libWidth = 8 override lazy val memMaskGran = Some(9) override lazy val libMaskGran = Some(1) - it should "be enabled when non-power of two masks are supported" is (pending) + (it should "be enabled when non-power of two masks are supported").is(pending) //~ compile(mem, lib, v, false) //~ execute(mem, lib, false, output) } // Read enable -class SplitWidth1024x32_readEnable_Lib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x32_readEnable_Lib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { import mdf.macrolib._ override lazy val depth = BigInt(1024) @@ -395,20 +426,27 @@ class SplitWidth1024x32_readEnable_Lib extends MacroCompilerSpec with HasSRAMGen override def generateLibSRAM() = { SRAMMacro( - name=lib_name, - width=libWidth, - depth=libDepth, - family="1rw", - ports=Seq(generateTestPort( - "lib", Some(libWidth), Some(libDepth), maskGran=libMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = lib_name, + width = libWidth, + depth = libDepth, + family = "1rw", + ports = Seq( + generateTestPort( + "lib", + Some(libWidth), + Some(libDepth), + maskGran = libMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateBody() = -""" + """ inst mem_0_0 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem inst mem_0_2 of awesome_lib_mem @@ -444,7 +482,10 @@ class SplitWidth1024x32_readEnable_Lib extends MacroCompilerSpec with HasSRAMGen compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x32_readEnable_Mem extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x32_readEnable_Mem + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { import mdf.macrolib._ override lazy val depth = BigInt(1024) @@ -453,15 +494,22 @@ class SplitWidth1024x32_readEnable_Mem extends MacroCompilerSpec with HasSRAMGen override def generateMemSRAM() = { SRAMMacro( - name=mem_name, - width=memWidth, - depth=memDepth, - family="1rw", - ports=Seq(generateTestPort( - "outer", Some(memWidth), Some(memDepth), maskGran=memMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = mem_name, + width = memWidth, + depth = memDepth, + family = "1rw", + ports = Seq( + generateTestPort( + "outer", + Some(memWidth), + Some(memDepth), + maskGran = memMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } @@ -470,7 +518,10 @@ class SplitWidth1024x32_readEnable_Mem extends MacroCompilerSpec with HasSRAMGen compileExecuteAndTest(mem, lib, v, output) } -class SplitWidth1024x32_readEnable_LibMem extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { +class SplitWidth1024x32_readEnable_LibMem + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator { import mdf.macrolib._ override lazy val depth = BigInt(1024) @@ -479,34 +530,48 @@ class SplitWidth1024x32_readEnable_LibMem extends MacroCompilerSpec with HasSRAM override def generateLibSRAM() = { SRAMMacro( - name=lib_name, - width=libWidth, - depth=libDepth, - family="1rw", - ports=Seq(generateTestPort( - "lib", Some(libWidth), Some(libDepth), maskGran=libMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = lib_name, + width = libWidth, + depth = libDepth, + family = "1rw", + ports = Seq( + generateTestPort( + "lib", + Some(libWidth), + Some(libDepth), + maskGran = libMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateMemSRAM() = { SRAMMacro( - name=mem_name, - width=memWidth, - depth=memDepth, - family="1rw", - ports=Seq(generateTestPort( - "outer", Some(memWidth), Some(memDepth), maskGran=memMaskGran, - write=true, writeEnable=true, - read=true, readEnable=true - )) + name = mem_name, + width = memWidth, + depth = memDepth, + family = "1rw", + ports = Seq( + generateTestPort( + "outer", + Some(memWidth), + Some(memDepth), + maskGran = memMaskGran, + write = true, + writeEnable = true, + read = true, + readEnable = true + ) + ) ) } override def generateBody() = -""" + """ inst mem_0_0 of awesome_lib_mem inst mem_0_1 of awesome_lib_mem inst mem_0_2 of awesome_lib_mem diff --git a/macros/src/test/scala/barstools/macros/SpecificExamples.scala b/macros/src/test/scala/barstools/macros/SpecificExamples.scala index e41932bb..334e3a73 100644 --- a/macros/src/test/scala/barstools/macros/SpecificExamples.scala +++ b/macros/src/test/scala/barstools/macros/SpecificExamples.scala @@ -29,8 +29,8 @@ class WriteEnableTest extends MacroCompilerSpec with HasSRAMGenerator { override val libPrefix = "macros/src/test/resources" - val memSRAMs = mdf.macrolib.Utils.readMDFFromString( -""" + val memSRAMs = mdf.macrolib.Utils + .readMDFFromString(""" [ { "type" : "sram", "name" : "cc_banks_0_ext", @@ -58,7 +58,7 @@ class WriteEnableTest extends MacroCompilerSpec with HasSRAMGenerator { writeToMem(mem, memSRAMs) val output = -""" + """ circuit cc_banks_0_ext : module cc_banks_0_ext : input RW0_addr : UInt<12> @@ -99,8 +99,8 @@ class MaskPortTest extends MacroCompilerSpec with HasSRAMGenerator { override val libPrefix = "macros/src/test/resources" - val memSRAMs = mdf.macrolib.Utils.readMDFFromString( -""" + val memSRAMs = mdf.macrolib.Utils + .readMDFFromString(""" [ { "type" : "sram", "name" : "cc_dir_ext", @@ -131,7 +131,7 @@ class MaskPortTest extends MacroCompilerSpec with HasSRAMGenerator { writeToMem(mem, memSRAMs) val output = -""" + """ circuit cc_dir_ext : module cc_dir_ext : input RW0_addr : UInt<9> @@ -183,8 +183,8 @@ class BOOMTest extends MacroCompilerSpec with HasSRAMGenerator { override val libPrefix = "macros/src/test/resources" - val memSRAMs = mdf.macrolib.Utils.readMDFFromString( -""" + val memSRAMs = mdf.macrolib.Utils + .readMDFFromString(""" [ { "type" : "sram", "name" : "_T_182_ext", @@ -354,7 +354,7 @@ class BOOMTest extends MacroCompilerSpec with HasSRAMGenerator { writeToMem(mem, memSRAMs) val output = // TODO: check correctness... -""" + """ circuit smem_0_ext : module _T_182_ext : input R0_addr : UInt<6> @@ -1350,14 +1350,14 @@ circuit smem_0_ext : class SmallTagArrayTest extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleTestGenerator { // Test that mapping a smaller memory using a larger lib can still work. - override def memWidth: Int = 26 - override def memDepth: BigInt = BigInt(2) - override def memMaskGran: Option[Int] = Some(26) + override def memWidth: Int = 26 + override def memDepth: BigInt = BigInt(2) + override def memMaskGran: Option[Int] = Some(26) override def memPortPrefix: String = "" - override def libWidth: Int = 32 - override def libDepth: BigInt = BigInt(64) - override def libMaskGran: Option[Int] = Some(1) + override def libWidth: Int = 32 + override def libDepth: BigInt = BigInt(64) + override def libMaskGran: Option[Int] = Some(1) override def libPortPrefix: String = "" override def extraPorts: Seq[MacroExtraPort] = Seq( @@ -1388,73 +1388,73 @@ class RocketChipTest extends MacroCompilerSpec with HasSRAMGenerator { val libSRAMs = Seq( SRAMMacro( - name="SRAM1RW1024x8", - depth=1024, - width=8, - family="1rw", - ports=Seq( + name = "SRAM1RW1024x8", + depth = 1024, + width = 8, + family = "1rw", + ports = Seq( generateReadWritePort("", 8, BigInt(1024)) ) ), SRAMMacro( - name="SRAM1RW512x32", - depth=512, - width=32, - family="1rw", - ports=Seq( + name = "SRAM1RW512x32", + depth = 512, + width = 32, + family = "1rw", + ports = Seq( generateReadWritePort("", 32, BigInt(512)) ) ), SRAMMacro( - name="SRAM1RW64x128", - depth=64, - width=128, - family="1rw", - ports=Seq( + name = "SRAM1RW64x128", + depth = 64, + width = 128, + family = "1rw", + ports = Seq( generateReadWritePort("", 128, BigInt(64)) ) ), SRAMMacro( - name="SRAM1RW64x32", - depth=64, - width=32, - family="1rw", - ports=Seq( + name = "SRAM1RW64x32", + depth = 64, + width = 32, + family = "1rw", + ports = Seq( generateReadWritePort("", 32, BigInt(64)) ) ), SRAMMacro( - name="SRAM1RW64x8", - depth=64, - width=8, - family="1rw", - ports=Seq( + name = "SRAM1RW64x8", + depth = 64, + width = 8, + family = "1rw", + ports = Seq( generateReadWritePort("", 8, BigInt(64)) ) ), SRAMMacro( - name="SRAM1RW512x8", - depth=512, - width=8, - family="1rw", - ports=Seq( + name = "SRAM1RW512x8", + depth = 512, + width = 8, + family = "1rw", + ports = Seq( generateReadWritePort("", 8, BigInt(512)) ) ), SRAMMacro( - name="SRAM2RW64x32", - depth=64, - width=32, - family="1r1w", - ports=Seq( + name = "SRAM2RW64x32", + depth = 64, + width = 32, + family = "1r1w", + ports = Seq( generateReadPort("portA", 32, BigInt(64)), generateWritePort("portB", 32, BigInt(64)) ) ) ) - val memSRAMs = mdf.macrolib.Utils.readMDFFromString( -""" + val memSRAMs = mdf.macrolib.Utils + .readMDFFromString(""" [ { "type": "sram", @@ -1537,7 +1537,7 @@ class RocketChipTest extends MacroCompilerSpec with HasSRAMGenerator { writeToMem(mem, memSRAMs) val output = // TODO: check correctness... -""" + """ circuit T_2172_ext : module tag_array_ext : input RW0_addr : UInt<6> diff --git a/macros/src/test/scala/barstools/macros/SynFlops.scala b/macros/src/test/scala/barstools/macros/SynFlops.scala index f12161a1..0d39220e 100644 --- a/macros/src/test/scala/barstools/macros/SynFlops.scala +++ b/macros/src/test/scala/barstools/macros/SynFlops.scala @@ -4,13 +4,13 @@ package barstools.macros trait HasSynFlopsTestGenerator extends HasSimpleTestGenerator { this: MacroCompilerSpec with HasSRAMGenerator => - def generateFlops: String = { -s""" + def generateFlops: String = { + s""" inst mem_0_0 of split_${lib_name} mem_0_0.${libPortPrefix}_clk <= ${libPortPrefix}_clk mem_0_0.${libPortPrefix}_addr <= ${libPortPrefix}_addr - node ${libPortPrefix}_dout_0_0 = bits(mem_0_0.${libPortPrefix}_dout, ${libWidth-1}, 0) - mem_0_0.${libPortPrefix}_din <= bits(${libPortPrefix}_din, ${libWidth-1}, 0) + node ${libPortPrefix}_dout_0_0 = bits(mem_0_0.${libPortPrefix}_dout, ${libWidth - 1}, 0) + mem_0_0.${libPortPrefix}_din <= bits(${libPortPrefix}_din, ${libWidth - 1}, 0) mem_0_0.${libPortPrefix}_write_en <= and(and(and(${libPortPrefix}_write_en, UInt<1>("h1")), UInt<1>("h1")), UInt<1>("h1")) node ${libPortPrefix}_dout_0 = ${libPortPrefix}_dout_0_0 ${libPortPrefix}_dout <= mux(UInt<1>("h1"), ${libPortPrefix}_dout_0, UInt<${libWidth}>("h0")) @@ -37,49 +37,66 @@ s""" ${libPortPrefix}_dout <= ram.RW_0.rdata ram.RW_0.wdata <= ${libPortPrefix}_din """ - } + } - // If there is no lib, put the flops definition into the body. - abstract override def generateBody = { - if (this.isInstanceOf[HasNoLibTestGenerator]) generateFlops else super.generateBody - } + // If there is no lib, put the flops definition into the body. + abstract override def generateBody = { + if (this.isInstanceOf[HasNoLibTestGenerator]) generateFlops else super.generateBody + } - // If there is no lib, don't generate a footer, since the flops definition - // will be in the body. - override def generateFooter = { - if (this.isInstanceOf[HasNoLibTestGenerator]) "" else -s""" + // If there is no lib, don't generate a footer, since the flops definition + // will be in the body. + override def generateFooter = { + if (this.isInstanceOf[HasNoLibTestGenerator]) "" + else + s""" module ${lib_name} : ${generateFooterPorts} ${generateFlops} """ - } + } } -class Synflops2048x8_noLib extends MacroCompilerSpec with HasSRAMGenerator with HasNoLibTestGenerator with HasSynFlopsTestGenerator { +class Synflops2048x8_noLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasNoLibTestGenerator + with HasSynFlopsTestGenerator { override lazy val memDepth = BigInt(2048) override lazy val memWidth = 8 compileExecuteAndTest(mem, None, v, output, true) } -class Synflops2048x16_noLib extends MacroCompilerSpec with HasSRAMGenerator with HasNoLibTestGenerator with HasSynFlopsTestGenerator { +class Synflops2048x16_noLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasNoLibTestGenerator + with HasSynFlopsTestGenerator { override lazy val memDepth = BigInt(2048) override lazy val memWidth = 16 compileExecuteAndTest(mem, None, v, output, true) } -class Synflops8192x16_noLib extends MacroCompilerSpec with HasSRAMGenerator with HasNoLibTestGenerator with HasSynFlopsTestGenerator { +class Synflops8192x16_noLib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasNoLibTestGenerator + with HasSynFlopsTestGenerator { override lazy val memDepth = BigInt(8192) override lazy val memWidth = 16 compileExecuteAndTest(mem, None, v, output, true) } -class Synflops2048x16_depth_Lib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with HasSynFlopsTestGenerator { +class Synflops2048x16_depth_Lib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with HasSynFlopsTestGenerator { override lazy val memDepth = BigInt(2048) override lazy val libDepth = BigInt(1024) override lazy val width = 16 @@ -87,7 +104,11 @@ class Synflops2048x16_depth_Lib extends MacroCompilerSpec with HasSRAMGenerator compileExecuteAndTest(mem, lib, v, output, true) } -class Synflops2048x64_width_Lib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator with HasSynFlopsTestGenerator { +class Synflops2048x64_width_Lib + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleWidthTestGenerator + with HasSynFlopsTestGenerator { override lazy val memWidth = 64 override lazy val libWidth = 8 override lazy val depth = BigInt(1024) @@ -95,7 +116,11 @@ class Synflops2048x64_width_Lib extends MacroCompilerSpec with HasSRAMGenerator compileExecuteAndTest(mem, lib, v, output, true) } -class Synflops_SplitPorts_Read_Write extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with HasSynFlopsTestGenerator { +class Synflops_SplitPorts_Read_Write + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with HasSynFlopsTestGenerator { import mdf.macrolib._ override lazy val memDepth = BigInt(2048) @@ -103,29 +128,29 @@ class Synflops_SplitPorts_Read_Write extends MacroCompilerSpec with HasSRAMGener override lazy val width = 8 override def generateLibSRAM = SRAMMacro( - name=lib_name, - width=width, - depth=libDepth, - family="1r1w", - ports=Seq( + name = lib_name, + width = width, + depth = libDepth, + family = "1r1w", + ports = Seq( generateReadPort("innerA", width, libDepth), generateWritePort("innerB", width, libDepth) ) ) override def generateMemSRAM = SRAMMacro( - name=mem_name, - width=width, - depth=memDepth, - family="1r1w", - ports=Seq( + name = mem_name, + width = width, + depth = memDepth, + family = "1r1w", + ports = Seq( generateReadPort("outerB", width, memDepth), generateWritePort("outerA", width, memDepth) ) ) override def generateHeader = -""" + """ circuit target_memory : module target_memory : input outerB_addr : UInt<11> @@ -138,7 +163,7 @@ circuit target_memory : """ override def generateBody = -""" + """ node outerB_addr_sel = bits(outerB_addr, 10, 10) reg outerB_addr_sel_reg : UInt<1>, outerB_clk with : reset => (UInt<1>("h0"), outerB_addr_sel_reg) @@ -166,7 +191,7 @@ circuit target_memory : """ override def generateFooterPorts = -""" + """ input innerA_addr : UInt<10> input innerA_clk : Clock output innerA_dout : UInt<8> @@ -177,7 +202,7 @@ circuit target_memory : """ override def generateFlops = -""" + """ inst mem_0_0 of split_awesome_lib_mem mem_0_0.innerB_clk <= innerB_clk mem_0_0.innerB_addr <= innerB_addr @@ -222,7 +247,11 @@ circuit target_memory : } } -class Synflops_SplitPorts_MaskedMem_Read_MaskedWrite extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with HasSynFlopsTestGenerator { +class Synflops_SplitPorts_MaskedMem_Read_MaskedWrite + extends MacroCompilerSpec + with HasSRAMGenerator + with HasSimpleDepthTestGenerator + with HasSynFlopsTestGenerator { import mdf.macrolib._ override lazy val memDepth = BigInt(2048) @@ -232,29 +261,29 @@ class Synflops_SplitPorts_MaskedMem_Read_MaskedWrite extends MacroCompilerSpec w override lazy val libMaskGran = Some(1) override def generateLibSRAM = SRAMMacro( - name=lib_name, - width=width, - depth=libDepth, - family="1r1w", - ports=Seq( + name = lib_name, + width = width, + depth = libDepth, + family = "1r1w", + ports = Seq( generateReadPort("innerA", width, libDepth), generateWritePort("innerB", width, libDepth, libMaskGran) ) ) override def generateMemSRAM = SRAMMacro( - name=mem_name, - width=width, - depth=memDepth, - family="1r1w", - ports=Seq( + name = mem_name, + width = width, + depth = memDepth, + family = "1r1w", + ports = Seq( generateReadPort("outerB", width, memDepth), generateWritePort("outerA", width, memDepth, memMaskGran) ) ) override def generateHeader = -""" + """ circuit target_memory : module target_memory : input outerB_addr : UInt<11> @@ -268,7 +297,7 @@ circuit target_memory : """ override def generateBody = -""" + """ node outerB_addr_sel = bits(outerB_addr, 10, 10) reg outerB_addr_sel_reg : UInt<1>, outerB_clk with : reset => (UInt<1>("h0"), outerB_addr_sel_reg) @@ -298,7 +327,7 @@ circuit target_memory : """ override def generateFooterPorts = -""" + """ input innerA_addr : UInt<10> input innerA_clk : Clock output innerA_dout : UInt<8> @@ -310,7 +339,7 @@ circuit target_memory : """ override def generateFlops = -""" + """ inst mem_0_0 of split_awesome_lib_mem inst mem_0_1 of split_awesome_lib_mem inst mem_0_2 of split_awesome_lib_mem