Add memory compiler to macros (#29)

* Add memory compiler to macros

* Removed weird spacing

* Make sramcompiler width/depth range inclusive

* Added sramcompiler test
This commit is contained in:
Adam Izraelevitz
2018-02-16 16:01:10 -08:00
committed by GitHub
parent 8a30579a3e
commit 79c8c283cc
7 changed files with 178 additions and 100 deletions

View File

@@ -68,7 +68,7 @@ object MacroCompilerAnnotation {
* @param costMetric Cost metric to use
* @param mode Compiler mode (see CompilerMode)
*/
case class Params(mem: String, lib: Option[String], costMetric: CostMetric, mode: CompilerMode)
case class Params(mem: String, lib: Option[String], costMetric: CostMetric, mode: CompilerMode, useCompiler: Boolean)
/**
* Create a MacroCompilerAnnotation.
@@ -142,15 +142,15 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
}
// Make sure we don't have a maskGran larger than the width of the memory.
assert (memPort.src.effectiveMaskGran <= memPort.src.width)
assert (libPort.src.effectiveMaskGran <= libPort.src.width)
assert (memPort.src.effectiveMaskGran <= memPort.src.width.get)
assert (libPort.src.effectiveMaskGran <= libPort.src.width.get)
val libWidth = libPort.src.width
val libWidth = libPort.src.width.get
// Don't consider cases of maskGran == width as "masked" since those masks
// effectively function as write-enable bits.
val memMask = if (memPort.src.effectiveMaskGran == memPort.src.width) None else memPort.src.maskGran
val libMask = if (libPort.src.effectiveMaskGran == libPort.src.width) None else libPort.src.maskGran
val memMask = if (memPort.src.effectiveMaskGran == memPort.src.width.get) None else memPort.src.maskGran
val libMask = if (libPort.src.effectiveMaskGran == libPort.src.width.get) None else libPort.src.maskGran
(memMask, libMask) match {
// Neither lib nor mem is masked.
@@ -163,12 +163,12 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
// Only the mem is masked.
case (Some(p), None) => {
if (p % libPort.src.width == 0) {
if (p % libPort.src.width.get == 0) {
// If the mem mask is a multiple of the lib width, then we're good.
// Just roll over every lib width as usual.
// e.g. lib width=4, mem maskGran={4, 8, 12, 16, ...}
splitMemory(libWidth)
} else if (libPort.src.width % p == 0) {
} else if (libPort.src.width.get % p == 0) {
// Lib width is a multiple of the mem mask.
// Consider the case where mem mask = 4 but lib width = 8, unmasked.
// We can still compile, but will need to waste the extra bits.
@@ -176,13 +176,13 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
} else {
// No neat multiples.
// We might still be able to compile extremely inefficiently.
if (p < libPort.src.width) {
if (p < libPort.src.width.get) {
// Compile using mem mask as the effective width. (note that lib is not masked)
// e.g. mem mask = 3, lib width = 8
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} 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 None
}
}
@@ -378,13 +378,13 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
case Some(PolarizedPort(mem, _)) =>
/* Palmer: The bits from the outer memory's write mask that will be
* used as the write mask for this inner memory. */
if (libPort.src.effectiveMaskGran == libPort.src.width) {
if (libPort.src.effectiveMaskGran == libPort.src.width.get) {
bits(WRef(mem), low / memPort.src.effectiveMaskGran)
} else {
require(isPowerOfTwo(libPort.src.effectiveMaskGran), "only powers of two masks supported for now")
val effectiveLibWidth = if (memPort.src.maskGran.get < libPort.src.effectiveMaskGran) memPort.src.maskGran.get else libPort.src.width
cat(((0 until libPort.src.width by libPort.src.effectiveMaskGran) map (i => {
val effectiveLibWidth = if (memPort.src.maskGran.get < libPort.src.effectiveMaskGran) memPort.src.maskGran.get else libPort.src.width.get
cat(((0 until libPort.src.width.get by libPort.src.effectiveMaskGran) map (i => {
if (memPort.src.maskGran.get < libPort.src.effectiveMaskGran && i >= effectiveLibWidth) {
// If the memMaskGran is smaller than the lib's gran, then
// zero out the upper bits.
@@ -398,7 +398,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
/* If there is a lib mask port but no mem mask port, just turn on
* all bits of the lib mask port. */
if (libPort.src.maskPort.isDefined) {
val width = libPort.src.width / libPort.src.effectiveMaskGran
val width = libPort.src.width.get / libPort.src.effectiveMaskGran
val value = (BigInt(1) << width.toInt) - 1
UIntLiteral(value, IntWidth(width))
} else {
@@ -525,7 +525,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
// 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}")
//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
@@ -561,7 +561,7 @@ class MacroCompilerTransform extends Transform {
def inputForm = MidForm
def outputForm = MidForm
def execute(state: CircuitState) = getMyAnnotations(state) match {
case Seq(MacroCompilerAnnotation(state.circuit.main, MacroCompilerAnnotation.Params(memFile, libFile, costMetric, mode))) =>
case Seq(MacroCompilerAnnotation(state.circuit.main, MacroCompilerAnnotation.Params(memFile, libFile, costMetric, mode, useCompiler))) =>
if (mode == MacroCompilerAnnotation.FallbackSynflops) {
throw new UnsupportedOperationException("Not implemented yet")
}
@@ -573,7 +573,10 @@ class MacroCompilerTransform extends Transform {
}
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(_)})
if(useCompiler){
findSRAMCompiler(Some(x)).map{x => buildSRAMMacros(x).map(new Macro(_)) }
}
else Some(Utils.filterForSRAM(Some(x)) getOrElse(List()) map {new Macro(_)})
case _ => None
}
val transforms = Seq(
@@ -614,12 +617,14 @@ object MacroCompiler extends App {
case object Firrtl extends MacroParam
case object CostFunc extends MacroParam
case object Mode extends MacroParam
case object UseCompiler extends MacroParam
type MacroParamMap = Map[MacroParam, String]
type CostParamMap = Map[String, String]
val usage = Seq(
"Options:",
" -m, --macro-list: The set of macros to compile",
" -l, --library: The set of macros that have blackbox instances",
" -u, --use-compiler: Flag, whether to use the memory compiler defined in library",
" -v, --verilog: Verilog output",
" -f, --firrtl: FIRRTL output (optional)",
" -c, --cost-func: Cost function to use. Optional (default: \"default\")",
@@ -638,6 +643,8 @@ object MacroCompiler extends App {
parseArgs(map + (Macros -> value), costMap, tail)
case ("-l" | "--library") :: value :: tail =>
parseArgs(map + (Library -> value), costMap, tail)
case ("-u" | "--use-compiler") :: tail =>
parseArgs(map + (UseCompiler -> ""), costMap, tail)
case ("-v" | "--verilog") :: value :: tail =>
parseArgs(map + (Verilog -> value), costMap, tail)
case ("-f" | "--firrtl") :: value :: tail =>
@@ -669,7 +676,8 @@ object MacroCompiler extends App {
MacroCompilerAnnotation.Params(
params.get(Macros).get, params.get(Library),
CostMetric.getCostMetric(params.getOrElse(CostFunc, "default"), costParams),
MacroCompilerAnnotation.stringToCompilerMode(params.getOrElse(Mode, "default"))
MacroCompilerAnnotation.stringToCompilerMode(params.getOrElse(Mode, "default")),
params.contains(UseCompiler)
)
))
)
@@ -705,6 +713,7 @@ object MacroCompiler extends App {
}
} catch {
case e: java.util.NoSuchElementException =>
e.printStackTrace()
println(usage)
e.printStackTrace()
sys.exit(1)

View File

@@ -18,9 +18,9 @@ class FirrtlMacroPort(port: MacroPort) {
val isWriter = port.input.nonEmpty && port.output.isEmpty
val isReadWriter = port.input.nonEmpty && port.output.nonEmpty
val addrType = UIntType(IntWidth(ceilLog2(port.depth) max 1))
val dataType = UIntType(IntWidth(port.width))
val maskType = UIntType(IntWidth(port.width / port.effectiveMaskGran))
val addrType = UIntType(IntWidth(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(
@@ -72,6 +72,33 @@ object Utils {
case _ => None
}
}
def findSRAMCompiler(s: Option[Seq[mdf.macrolib.Macro]]): Option[mdf.macrolib.SRAMCompiler] = {
s match {
case Some(l:Seq[mdf.macrolib.Macro]) =>
l collectFirst {
case x: mdf.macrolib.SRAMCompiler => x
}
case _ => None
}
}
def buildSRAMMacros(s: mdf.macrolib.SRAMCompiler): Seq[mdf.macrolib.SRAMMacro] = {
for (g <- s.groups; d <- g.depth; w <- g.width; vt <- g.vt)
yield mdf.macrolib.SRAMMacro(makeName(g, d, w, vt), w, d, g.family, g.ports.map(_.copy(width=Some(w), depth=Some(d))), g.extraPorts)
}
def makeName(g: mdf.macrolib.SRAMGroup, depth: Int, width: Int, vt: String): String = {
g.name.foldLeft(""){ (builder, next) =>
next match {
case "depth"|"DEPTH" => builder + depth
case "width"|"WIDTH" => builder + width
case "vt" => builder + vt.toLowerCase
case "VT" => builder + vt.toUpperCase
case "family" => builder + g.family.toLowerCase
case "FAMILY" => builder + g.family.toUpperCase
case "mux"|"MUX" => builder + g.mux
case other => builder + other
}
}
}
def and(e1: Expression, e2: Expression) =
DoPrim(PrimOps.And, Seq(e1, e2), Nil, e1.tpe)

View File

@@ -7,6 +7,8 @@ import firrtl.Utils.ceilLog2
import java.io.{File, StringWriter}
abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalatest.Matchers {
import scala.language.implicitConversions
implicit def String2SomeString(i: String): Option[String] = Some(i)
val testDir: String = "test_run_dir/macros"
new File(testDir).mkdirs // Make sure the testDir exists
@@ -32,11 +34,12 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
}
}
private def args(mem: String, lib: Option[String], v: String, synflops: Boolean) =
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 (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
@@ -44,12 +47,12 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
def compile(mem: String, lib: String, v: String, synflops: Boolean) {
compile(mem, Some(lib), v, synflops)
}
def compile(mem: String, lib: Option[String], v: String, synflops: Boolean) {
def compile(mem: String, lib: Option[String], v: String, synflops: Boolean, useCompiler: Boolean = false) {
var mem_full = concat(memPrefix, mem)
var lib_full = concat(libPrefix, lib)
var v_full = concat(vPrefix, v)
MacroCompiler.run(args(mem_full, lib_full, v_full, synflops))
MacroCompiler.run(args(mem_full, lib_full, v_full, synflops, useCompiler))
}
// Helper functions to write macro libraries to the given files.
@@ -62,14 +65,11 @@ 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): Unit = {
compile(mem, lib, v, synflops)
val result = execute(mem, lib, synflops)
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)
}
def compileExecuteAndTest(mem: String, lib: String, v: String, output: String, synflops: Boolean = false): Unit = {
compileExecuteAndTest(mem, Some(lib), v, output, synflops)
}
// Compare FIRRTL outputs after reparsing output with ScalaTest ("should be").
def test(result: Circuit, output: String): Unit = {
@@ -79,21 +79,20 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
// Execute the macro compiler and returns a Circuit containing the output of
// the memory compiler.
def execute(memFile: String, libFile: Option[String], synflops: Boolean): Circuit = {
execute(Some(memFile), libFile, synflops)
}
def execute(memFile: String, libFile: String, synflops: Boolean): Circuit = {
execute(Some(memFile), Some(libFile), synflops)
}
def execute(memFile: Option[String], libFile: Option[String], synflops: Boolean): Circuit = {
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]] = Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(lib_full)) match {
case Some(x) => Some(x map (new Macro(_)))
case None => None
val libs: Option[Seq[Macro]] = if(useCompiler) {
Utils.findSRAMCompiler(mdf.macrolib.Utils.readMDFFromPath(lib_full)).map{x => Utils.buildSRAMMacros(x).map(new Macro(_)) }
} else {
Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(lib_full)) match {
case Some(x) => Some(x map (new Macro(_)))
case None => None
}
}
val macros = mems map (_.blackbox)
val circuit = Circuit(NoInfo, macros, macros.last.name)
@@ -105,6 +104,7 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
result
}
// Helper method to deal with String + Option[String]
private def concat(a: String, b: String): String = {a + "/" + b}
private def concat(a: String, b: Option[String]): Option[String] = {
@@ -118,12 +118,16 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
// A collection of standard SRAM generators.
trait HasSRAMGenerator {
import mdf.macrolib._
import scala.language.implicitConversions
implicit def Int2SomeInt(i: Int): Option[Int] = Some(i)
// Generate a standard (read/write/combo) port for testing.
// Helper methods for optional width argument
def generateTestPort(
prefix: String,
width: Int,
depth: Int,
width: Option[Int],
depth: Option[Int],
maskGran: Option[Int] = None,
read: Boolean,
readEnable: Boolean = false,
@@ -133,55 +137,69 @@ trait HasSRAMGenerator {
val realPrefix = if (prefix == "") "" else prefix + "_"
MacroPort(
address=PolarizedPort(name=realPrefix + "addr", polarity=ActiveHigh),
clock=PolarizedPort(name=realPrefix + "clk", polarity=PositiveEdge),
address = PolarizedPort(name = realPrefix + "addr", polarity = ActiveHigh),
clock = 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,
readEnable = if (readEnable) Some(PolarizedPort(name = realPrefix + "read_en", polarity = ActiveHigh)) else None,
writeEnable = if (writeEnable) Some(PolarizedPort(name = realPrefix + "write_en", polarity = ActiveHigh)) else None,
output=if (read) Some(PolarizedPort(name=realPrefix + "dout", polarity=ActiveHigh)) else None,
input=if (write) Some(PolarizedPort(name=realPrefix + "din", polarity=ActiveHigh)) else None,
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))
maskPort = maskGran match {
case Some(x: Int) => Some(PolarizedPort(name = realPrefix + "mask", polarity = ActiveHigh))
case _ => None
},
maskGran=maskGran,
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: Int, depth: Int, readEnable: Boolean = false): MacroPort = {
generateTestPort(prefix, width, depth, write=false, read=true, readEnable=readEnable)
def generateReadPort(prefix: String, width: Option[Int], depth: Option[Int], 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: Int, depth: Int, maskGran: Option[Int] = None, writeEnable: Boolean = true): MacroPort = {
generateTestPort(prefix, width, depth, maskGran=maskGran, write=true, read=false, writeEnable=writeEnable)
def generateWritePort(prefix: String, width: Option[Int], depth: Option[Int], 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: Int, depth: Int, maskGran: Option[Int] = None): MacroPort = {
def generateReadWritePort(prefix: String, width: Option[Int], depth: Option[Int], 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: Int, maskGran: Option[Int] = None, extraPorts: Seq[MacroExtraPort] = List()): SRAMMacro = {
SRAMMacro(
name=name,
width=width,
depth=depth,
family="1rw",
ports=Seq(generateReadWritePort(prefix, width, depth, maskGran)),
extraPorts=extraPorts
name = name,
width = width,
depth = depth,
family = "1rw",
ports = Seq(generateReadWritePort(prefix, width, depth, maskGran)),
extraPorts = extraPorts
)
}
// Generate a "simple" SRAM group (active high/positive edge, 1 read-write port).
def generateSimpleSRAMGroup(prefix: String, mux: Int, depth: Range, width: Range, maskGran: Option[Int] = None, extraPorts: Seq[MacroExtraPort] = List()): SRAMGroup = {
SRAMGroup(Seq("mygroup_", "width", "x", "depth", "_", "VT"), "1rw", Seq("svt", "lvt", "ulvt"), mux, depth, width, Seq(generateReadWritePort(prefix, None, None, maskGran)))
}
// 'vt': ('svt','lvt','ulvt'), 'mux': 2, 'depth': range(16,513,8), 'width': range(8,289,2), 'ports': 1
// 'vt': ('svt','lvt','ulvt'), 'mux': 4, 'depth': range(32,1025,16), 'width': range(4,145), 'ports': 1}
def generateSRAMCompiler(name: String, prefix: String): mdf.macrolib.SRAMCompiler = {
SRAMCompiler(name, Seq(
generateSimpleSRAMGroup(prefix, 2, Range(16, 512, 8), Range(8, 288, 2)),
generateSimpleSRAMGroup(prefix, 4, Range(32, 1024, 16), Range(4, 144, 1))
))
}
}
// Generic "simple" test generator.
@@ -192,6 +210,7 @@ trait HasSimpleTestGenerator {
// 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: Int
@@ -224,10 +243,10 @@ trait HasSimpleTestGenerator {
val lib = s"lib-${generatorType}${extraTagPrefixed}.json"
val v = s"${generatorType}${extraTagPrefixed}.v"
val mem_name = "target_memory"
lazy val mem_name = "target_memory"
val mem_addr_width = ceilLog2(memDepth)
val lib_name = "awesome_lib_mem"
lazy val lib_name = "awesome_lib_mem"
val lib_addr_width = ceilLog2(libDepth)
// Override these to change the port prefixes if needed.
@@ -258,8 +277,8 @@ trait HasSimpleTestGenerator {
// 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.
val lastWidthBits = if (memWidth % usableLibWidth == 0) usableLibWidth else (memWidth % usableLibWidth)
val selectBits = mem_addr_width - lib_addr_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.
@@ -410,3 +429,4 @@ trait HasNoLibTestGenerator extends HasSimpleTestGenerator {
// If there is no lib, don't generate a body.
override def generateBody = ""
}

View File

@@ -0,0 +1,22 @@
package barstools.macros
import mdf.macrolib._
class SRAMCompiler extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator {
val compiler = generateSRAMCompiler("awesome", "A")
val verilog = s"v-SRAMCompiler.v"
override lazy val depth = 16
override lazy val memWidth = 8
override lazy val libWidth = 8
override lazy val mem_name = "mymem"
override lazy val memPortPrefix = "X"
override lazy val lib_name = "mygroup_8x16_SVT"
override lazy val libPortPrefix = "A"
writeToLib(lib, Seq(compiler))
writeToMem(mem, Seq(generateSRAM("mymem", "X", 8, 16)))
compileExecuteAndTest(mem, Some(lib), verilog, output=output, false, true)
}

View File

@@ -20,27 +20,27 @@ trait HasSimpleDepthTestGenerator extends HasSimpleTestGenerator {
if (selectBits > 0) {
output.append (
s"""
node outer_addr_sel = bits(outer_addr, ${mem_addr_width - 1}, $lib_addr_width)
reg outer_addr_sel_reg : UInt<${selectBits}>, outer_clk with :
reset => (UInt<1>("h0"), outer_addr_sel_reg)
outer_addr_sel_reg <= mux(UInt<1>("h1"), outer_addr_sel, outer_addr_sel_reg)
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(outer_addr_sel, UInt<${selectBits}>("h${i.toHexString}"))""" else "UInt<1>(\"h1\")"
val enableIdentifier = if (selectBits > 0) s"""eq(${memPortPrefix}_addr_sel, UInt<${selectBits}>("h${i.toHexString}"))""" else "UInt<1>(\"h1\")"
output.append(
s"""
inst mem_${i}_0 of awesome_lib_mem
mem_${i}_0.lib_clk <= outer_clk
mem_${i}_0.lib_addr <= outer_addr
node outer_dout_${i}_0 = bits(mem_${i}_0.lib_dout, ${width - 1}, 0)
mem_${i}_0.lib_din <= bits(outer_din, ${width - 1}, 0)
inst mem_${i}_0 of ${lib_name}
mem_${i}_0.${libPortPrefix}_clk <= ${memPortPrefix}_clk
mem_${i}_0.${libPortPrefix}_addr <= ${memPortPrefix}_addr
node ${memPortPrefix}_dout_${i}_0 = bits(mem_${i}_0.${libPortPrefix}_dout, ${width - 1}, 0)
mem_${i}_0.${libPortPrefix}_din <= bits(${memPortPrefix}_din, ${width - 1}, 0)
${maskStatement}
mem_${i}_0.lib_write_en <= and(and(outer_write_en, UInt<1>("h1")), ${enableIdentifier})
node outer_dout_${i} = outer_dout_${i}_0
mem_${i}_0.${libPortPrefix}_write_en <= and(and(${memPortPrefix}_write_en, UInt<1>("h1")), ${enableIdentifier})
node ${memPortPrefix}_dout_${i} = ${memPortPrefix}_dout_${i}_0
"""
)
}
@@ -48,16 +48,16 @@ s"""
if (i > depthInstances - 1) {
"UInt<1>(\"h0\")"
} else {
"mux(eq(outer_addr_sel_reg, UInt<%d>(\"h%s\")), outer_dout_%d, %s)".format(
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 " outer_dout <= "
output append s" ${memPortPrefix}_dout <= "
if (selectBits > 0) {
output append generate_outer_dout_tree(0, depthInstances)
} else {
output append """mux(UInt<1>("h1"), outer_dout_0, UInt<1>("h0"))"""
output append s"""mux(UInt<1>("h1"), ${memPortPrefix}_dout_0, UInt<1>("h0"))"""
}
output.toString

View File

@@ -40,28 +40,28 @@ trait HasSimpleWidthTestGenerator extends HasSimpleTestGenerator {
} else """UInt<1>("h1")"""
s"""
mem_0_${i}.lib_clk <= outer_clk
mem_0_${i}.lib_addr <= outer_addr
node outer_dout_0_${i} = bits(mem_0_${i}.lib_dout, ${myMemWidth - 1}, 0)
mem_0_${i}.lib_din <= bits(outer_din, ${myBaseBit + myMemWidth - 1}, ${myBaseBit})
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)
mem_0_${i}.${libPortPrefix}_din <= bits(${memPortPrefix}_din, ${myBaseBit + myMemWidth - 1}, ${myBaseBit})
${maskStatement}
mem_0_${i}.lib_write_en <= and(and(outer_write_en, ${writeEnableBit}), UInt<1>("h1"))
mem_0_${i}.${libPortPrefix}_write_en <= and(and(${memPortPrefix}_write_en, ${writeEnableBit}), UInt<1>("h1"))
"""
}).reduceLeft(_ + _)
// Generate final output that concats together the sub-memories.
// e.g. cat(outer_dout_0_2, cat(outer_dout_0_1, outer_dout_0_0))
output append {
val doutStatements = ((widthInstances - 1 to 0 by -1) map (i => s"outer_dout_0_${i}"))
val doutStatements = ((widthInstances - 1 to 0 by -1) map (i => s"${memPortPrefix}_dout_0_${i}"))
val catStmt = doutStatements.init.foldRight(doutStatements.last)((l: String, r: String) => s"cat($l, $r)")
s"""
node outer_dout_0 = ${catStmt}
node ${memPortPrefix}_dout_0 = ${catStmt}
"""
}
output append
"""
outer_dout <= mux(UInt<1>("h1"), outer_dout_0, UInt<1>("h0"))
s"""
${memPortPrefix}_dout <= mux(UInt<1>("h1"), ${memPortPrefix}_dout_0, UInt<1>("h0"))
"""
output.toString
}
@@ -398,7 +398,7 @@ class SplitWidth1024x32_readEnable_Lib extends MacroCompilerSpec with HasSRAMGen
depth=libDepth,
family="1rw",
ports=Seq(generateTestPort(
"lib", libWidth, libDepth, maskGran=libMaskGran,
"lib", Some(libWidth), Some(libDepth), maskGran=libMaskGran,
write=true, writeEnable=true,
read=true, readEnable=true
))
@@ -456,7 +456,7 @@ class SplitWidth1024x32_readEnable_Mem extends MacroCompilerSpec with HasSRAMGen
depth=memDepth,
family="1rw",
ports=Seq(generateTestPort(
"outer", memWidth, memDepth, maskGran=memMaskGran,
"outer", Some(memWidth), Some(memDepth), maskGran=memMaskGran,
write=true, writeEnable=true,
read=true, readEnable=true
))
@@ -482,7 +482,7 @@ class SplitWidth1024x32_readEnable_LibMem extends MacroCompilerSpec with HasSRAM
depth=libDepth,
family="1rw",
ports=Seq(generateTestPort(
"lib", libWidth, libDepth, maskGran=libMaskGran,
"lib", Some(libWidth), Some(libDepth), maskGran=libMaskGran,
write=true, writeEnable=true,
read=true, readEnable=true
))
@@ -496,7 +496,7 @@ class SplitWidth1024x32_readEnable_LibMem extends MacroCompilerSpec with HasSRAM
depth=memDepth,
family="1rw",
ports=Seq(generateTestPort(
"outer", memWidth, memDepth, maskGran=memMaskGran,
"outer", Some(memWidth), Some(memDepth), maskGran=memMaskGran,
write=true, writeEnable=true,
read=true, readEnable=true
))

2
mdf

Submodule mdf updated: 2b5f3c16da...2bc5a363e2