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:
@@ -68,7 +68,7 @@ object MacroCompilerAnnotation {
|
|||||||
* @param costMetric Cost metric to use
|
* @param costMetric Cost metric to use
|
||||||
* @param mode Compiler mode (see CompilerMode)
|
* @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.
|
* 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.
|
// Make sure we don't have a maskGran larger than the width of the memory.
|
||||||
assert (memPort.src.effectiveMaskGran <= memPort.src.width)
|
assert (memPort.src.effectiveMaskGran <= memPort.src.width.get)
|
||||||
assert (libPort.src.effectiveMaskGran <= libPort.src.width)
|
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
|
// Don't consider cases of maskGran == width as "masked" since those masks
|
||||||
// effectively function as write-enable bits.
|
// effectively function as write-enable bits.
|
||||||
val memMask = if (memPort.src.effectiveMaskGran == memPort.src.width) None else memPort.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) None else libPort.src.maskGran
|
val libMask = if (libPort.src.effectiveMaskGran == libPort.src.width.get) None else libPort.src.maskGran
|
||||||
|
|
||||||
(memMask, libMask) match {
|
(memMask, libMask) match {
|
||||||
// Neither lib nor mem is masked.
|
// Neither lib nor mem is masked.
|
||||||
@@ -163,12 +163,12 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
|
|||||||
|
|
||||||
// Only the mem is masked.
|
// Only the mem is masked.
|
||||||
case (Some(p), None) => {
|
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.
|
// If the mem mask is a multiple of the lib width, then we're good.
|
||||||
// Just roll over every lib width as usual.
|
// Just roll over every lib width as usual.
|
||||||
// e.g. lib width=4, mem maskGran={4, 8, 12, 16, ...}
|
// e.g. lib width=4, mem maskGran={4, 8, 12, 16, ...}
|
||||||
splitMemory(libWidth)
|
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.
|
// Lib width is a multiple of the mem mask.
|
||||||
// Consider the case where mem mask = 4 but lib width = 8, unmasked.
|
// Consider the case where mem mask = 4 but lib width = 8, unmasked.
|
||||||
// We can still compile, but will need to waste the extra bits.
|
// We can still compile, but will need to waste the extra bits.
|
||||||
@@ -176,13 +176,13 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
|
|||||||
} else {
|
} else {
|
||||||
// No neat multiples.
|
// No neat multiples.
|
||||||
// We might still be able to compile extremely inefficiently.
|
// 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)
|
// Compile using mem mask as the effective width. (note that lib is not masked)
|
||||||
// e.g. mem mask = 3, lib width = 8
|
// e.g. mem mask = 3, lib width = 8
|
||||||
splitMemory(memMask.get)
|
splitMemory(memMask.get)
|
||||||
} else {
|
} else {
|
||||||
// e.g. mem mask = 13, lib width = 8
|
// e.g. mem mask = 13, lib width = 8
|
||||||
System.err.println(s"Unmasked target memory: unaligned mem maskGran ${p} with lib (${lib.src.name}) width ${libPort.src.width} 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
|
return None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -378,13 +378,13 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
|
|||||||
case Some(PolarizedPort(mem, _)) =>
|
case Some(PolarizedPort(mem, _)) =>
|
||||||
/* Palmer: The bits from the outer memory's write mask that will be
|
/* Palmer: The bits from the outer memory's write mask that will be
|
||||||
* used as the write mask for this inner memory. */
|
* 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)
|
bits(WRef(mem), low / memPort.src.effectiveMaskGran)
|
||||||
} else {
|
} else {
|
||||||
require(isPowerOfTwo(libPort.src.effectiveMaskGran), "only powers of two masks supported for now")
|
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
|
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 by libPort.src.effectiveMaskGran) map (i => {
|
cat(((0 until libPort.src.width.get by libPort.src.effectiveMaskGran) map (i => {
|
||||||
if (memPort.src.maskGran.get < libPort.src.effectiveMaskGran && i >= effectiveLibWidth) {
|
if (memPort.src.maskGran.get < libPort.src.effectiveMaskGran && i >= effectiveLibWidth) {
|
||||||
// If the memMaskGran is smaller than the lib's gran, then
|
// If the memMaskGran is smaller than the lib's gran, then
|
||||||
// zero out the upper bits.
|
// 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
|
/* If there is a lib mask port but no mem mask port, just turn on
|
||||||
* all bits of the lib mask port. */
|
* all bits of the lib mask port. */
|
||||||
if (libPort.src.maskPort.isDefined) {
|
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
|
val value = (BigInt(1) << width.toInt) - 1
|
||||||
UIntLiteral(value, IntWidth(width))
|
UIntLiteral(value, IntWidth(width))
|
||||||
} else {
|
} else {
|
||||||
@@ -525,7 +525,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
|
|||||||
// Run the cost function to evaluate this potential compile.
|
// Run the cost function to evaluate this potential compile.
|
||||||
costMetric.cost(mem, lib) match {
|
costMetric.cost(mem, lib) match {
|
||||||
case Some(newCost) => {
|
case Some(newCost) => {
|
||||||
System.err.println(s"Cost of ${lib.src.name} for ${mem.src.name}: ${newCost}")
|
//System.err.println(s"Cost of ${lib.src.name} for ${mem.src.name}: ${newCost}")
|
||||||
// Try compiling
|
// Try compiling
|
||||||
compile(mem, lib) match {
|
compile(mem, lib) match {
|
||||||
// If it was successful and the new cost is lower
|
// If it was successful and the new cost is lower
|
||||||
@@ -561,7 +561,7 @@ class MacroCompilerTransform extends Transform {
|
|||||||
def inputForm = MidForm
|
def inputForm = MidForm
|
||||||
def outputForm = MidForm
|
def outputForm = MidForm
|
||||||
def execute(state: CircuitState) = getMyAnnotations(state) match {
|
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) {
|
if (mode == MacroCompilerAnnotation.FallbackSynflops) {
|
||||||
throw new UnsupportedOperationException("Not implemented yet")
|
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 {
|
val libs: Option[Seq[Macro]] = mdf.macrolib.Utils.readMDFFromPath(libFile) match {
|
||||||
case Some(x:Seq[mdf.macrolib.Macro]) =>
|
case Some(x:Seq[mdf.macrolib.Macro]) =>
|
||||||
Some(Utils.filterForSRAM(Some(x)) getOrElse(List()) map {new Macro(_)})
|
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
|
case _ => None
|
||||||
}
|
}
|
||||||
val transforms = Seq(
|
val transforms = Seq(
|
||||||
@@ -614,12 +617,14 @@ object MacroCompiler extends App {
|
|||||||
case object Firrtl extends MacroParam
|
case object Firrtl extends MacroParam
|
||||||
case object CostFunc extends MacroParam
|
case object CostFunc extends MacroParam
|
||||||
case object Mode extends MacroParam
|
case object Mode extends MacroParam
|
||||||
|
case object UseCompiler extends MacroParam
|
||||||
type MacroParamMap = Map[MacroParam, String]
|
type MacroParamMap = Map[MacroParam, String]
|
||||||
type CostParamMap = Map[String, String]
|
type CostParamMap = Map[String, String]
|
||||||
val usage = Seq(
|
val usage = Seq(
|
||||||
"Options:",
|
"Options:",
|
||||||
" -m, --macro-list: The set of macros to compile",
|
" -m, --macro-list: The set of macros to compile",
|
||||||
" -l, --library: The set of macros that have blackbox instances",
|
" -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",
|
" -v, --verilog: Verilog output",
|
||||||
" -f, --firrtl: FIRRTL output (optional)",
|
" -f, --firrtl: FIRRTL output (optional)",
|
||||||
" -c, --cost-func: Cost function to use. Optional (default: \"default\")",
|
" -c, --cost-func: Cost function to use. Optional (default: \"default\")",
|
||||||
@@ -638,6 +643,8 @@ object MacroCompiler extends App {
|
|||||||
parseArgs(map + (Macros -> value), costMap, tail)
|
parseArgs(map + (Macros -> value), costMap, tail)
|
||||||
case ("-l" | "--library") :: value :: tail =>
|
case ("-l" | "--library") :: value :: tail =>
|
||||||
parseArgs(map + (Library -> value), costMap, tail)
|
parseArgs(map + (Library -> value), costMap, tail)
|
||||||
|
case ("-u" | "--use-compiler") :: tail =>
|
||||||
|
parseArgs(map + (UseCompiler -> ""), costMap, tail)
|
||||||
case ("-v" | "--verilog") :: value :: tail =>
|
case ("-v" | "--verilog") :: value :: tail =>
|
||||||
parseArgs(map + (Verilog -> value), costMap, tail)
|
parseArgs(map + (Verilog -> value), costMap, tail)
|
||||||
case ("-f" | "--firrtl") :: value :: tail =>
|
case ("-f" | "--firrtl") :: value :: tail =>
|
||||||
@@ -669,7 +676,8 @@ object MacroCompiler extends App {
|
|||||||
MacroCompilerAnnotation.Params(
|
MacroCompilerAnnotation.Params(
|
||||||
params.get(Macros).get, params.get(Library),
|
params.get(Macros).get, params.get(Library),
|
||||||
CostMetric.getCostMetric(params.getOrElse(CostFunc, "default"), costParams),
|
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 {
|
} catch {
|
||||||
case e: java.util.NoSuchElementException =>
|
case e: java.util.NoSuchElementException =>
|
||||||
|
e.printStackTrace()
|
||||||
println(usage)
|
println(usage)
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ class FirrtlMacroPort(port: MacroPort) {
|
|||||||
val isWriter = port.input.nonEmpty && port.output.isEmpty
|
val isWriter = port.input.nonEmpty && port.output.isEmpty
|
||||||
val isReadWriter = port.input.nonEmpty && port.output.nonEmpty
|
val isReadWriter = port.input.nonEmpty && port.output.nonEmpty
|
||||||
|
|
||||||
val addrType = UIntType(IntWidth(ceilLog2(port.depth) max 1))
|
val addrType = UIntType(IntWidth(ceilLog2(port.depth.get) max 1))
|
||||||
val dataType = UIntType(IntWidth(port.width))
|
val dataType = UIntType(IntWidth(port.width.get))
|
||||||
val maskType = UIntType(IntWidth(port.width / port.effectiveMaskGran))
|
val maskType = UIntType(IntWidth(port.width.get / port.effectiveMaskGran))
|
||||||
|
|
||||||
// Bundle representing this macro port.
|
// Bundle representing this macro port.
|
||||||
val tpe = BundleType(Seq(
|
val tpe = BundleType(Seq(
|
||||||
@@ -72,6 +72,33 @@ object Utils {
|
|||||||
case _ => None
|
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) =
|
def and(e1: Expression, e2: Expression) =
|
||||||
DoPrim(PrimOps.And, Seq(e1, e2), Nil, e1.tpe)
|
DoPrim(PrimOps.And, Seq(e1, e2), Nil, e1.tpe)
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import firrtl.Utils.ceilLog2
|
|||||||
import java.io.{File, StringWriter}
|
import java.io.{File, StringWriter}
|
||||||
|
|
||||||
abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalatest.Matchers {
|
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"
|
val testDir: String = "test_run_dir/macros"
|
||||||
new File(testDir).mkdirs // Make sure the testDir exists
|
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) ++
|
List("-m", mem.toString, "-v", v) ++
|
||||||
(lib match { case None => Nil case Some(l) => List("-l", l.toString) }) ++
|
(lib match { case None => Nil case Some(l) => List("-l", l.toString) }) ++
|
||||||
costMetricCmdLine ++
|
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.
|
// Run the full compiler as if from the command line interface.
|
||||||
// Generates the Verilog; useful in testing since an error will throw an
|
// Generates the Verilog; useful in testing since an error will throw an
|
||||||
@@ -44,12 +47,12 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
|
|||||||
def compile(mem: String, lib: String, v: String, synflops: Boolean) {
|
def compile(mem: String, lib: String, v: String, synflops: Boolean) {
|
||||||
compile(mem, Some(lib), v, synflops)
|
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 mem_full = concat(memPrefix, mem)
|
||||||
var lib_full = concat(libPrefix, lib)
|
var lib_full = concat(libPrefix, lib)
|
||||||
var v_full = concat(vPrefix, v)
|
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.
|
// 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.
|
// 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 = {
|
def compileExecuteAndTest(mem: String, lib: Option[String], v: String, output: String, synflops: Boolean = false, useCompiler: Boolean = false): Unit = {
|
||||||
compile(mem, lib, v, synflops)
|
compile(mem, lib, v, synflops, useCompiler)
|
||||||
val result = execute(mem, lib, synflops)
|
val result = execute(mem, lib, synflops, useCompiler)
|
||||||
test(result, output)
|
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").
|
// Compare FIRRTL outputs after reparsing output with ScalaTest ("should be").
|
||||||
def test(result: Circuit, output: String): Unit = {
|
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
|
// Execute the macro compiler and returns a Circuit containing the output of
|
||||||
// the memory compiler.
|
// the memory compiler.
|
||||||
def execute(memFile: String, libFile: Option[String], synflops: Boolean): Circuit = {
|
def execute(memFile: Option[String], libFile: Option[String], synflops: Boolean): Circuit = execute(memFile, libFile, synflops, false)
|
||||||
execute(Some(memFile), libFile, synflops)
|
def execute(memFile: Option[String], libFile: Option[String], synflops: Boolean, useCompiler: Boolean): Circuit = {
|
||||||
}
|
|
||||||
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 = {
|
|
||||||
var mem_full = concat(memPrefix, memFile)
|
var mem_full = concat(memPrefix, memFile)
|
||||||
var lib_full = concat(libPrefix, libFile)
|
var lib_full = concat(libPrefix, libFile)
|
||||||
|
|
||||||
require(memFile.isDefined)
|
require(memFile.isDefined)
|
||||||
val mems: Seq[Macro] = Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(mem_full)).get map (new Macro(_))
|
val mems: Seq[Macro] = Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(mem_full)).get map (new Macro(_))
|
||||||
val libs: Option[Seq[Macro]] = Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(lib_full)) match {
|
val libs: Option[Seq[Macro]] = if(useCompiler) {
|
||||||
case Some(x) => Some(x map (new Macro(_)))
|
Utils.findSRAMCompiler(mdf.macrolib.Utils.readMDFFromPath(lib_full)).map{x => Utils.buildSRAMMacros(x).map(new Macro(_)) }
|
||||||
case None => None
|
} 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 macros = mems map (_.blackbox)
|
||||||
val circuit = Circuit(NoInfo, macros, macros.last.name)
|
val circuit = Circuit(NoInfo, macros, macros.last.name)
|
||||||
@@ -105,6 +104,7 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Helper method to deal with String + Option[String]
|
// Helper method to deal with String + Option[String]
|
||||||
private def concat(a: String, b: String): String = {a + "/" + b}
|
private def concat(a: String, b: String): String = {a + "/" + b}
|
||||||
private def concat(a: String, b: Option[String]): Option[String] = {
|
private def concat(a: String, b: Option[String]): Option[String] = {
|
||||||
@@ -118,12 +118,16 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
|
|||||||
// A collection of standard SRAM generators.
|
// A collection of standard SRAM generators.
|
||||||
trait HasSRAMGenerator {
|
trait HasSRAMGenerator {
|
||||||
import mdf.macrolib._
|
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.
|
// Generate a standard (read/write/combo) port for testing.
|
||||||
|
// Helper methods for optional width argument
|
||||||
def generateTestPort(
|
def generateTestPort(
|
||||||
prefix: String,
|
prefix: String,
|
||||||
width: Int,
|
width: Option[Int],
|
||||||
depth: Int,
|
depth: Option[Int],
|
||||||
maskGran: Option[Int] = None,
|
maskGran: Option[Int] = None,
|
||||||
read: Boolean,
|
read: Boolean,
|
||||||
readEnable: Boolean = false,
|
readEnable: Boolean = false,
|
||||||
@@ -133,55 +137,69 @@ trait HasSRAMGenerator {
|
|||||||
val realPrefix = if (prefix == "") "" else prefix + "_"
|
val realPrefix = if (prefix == "") "" else prefix + "_"
|
||||||
|
|
||||||
MacroPort(
|
MacroPort(
|
||||||
address=PolarizedPort(name=realPrefix + "addr", polarity=ActiveHigh),
|
address = PolarizedPort(name = realPrefix + "addr", polarity = ActiveHigh),
|
||||||
clock=PolarizedPort(name=realPrefix + "clk", polarity=PositiveEdge),
|
clock = PolarizedPort(name = realPrefix + "clk", polarity = PositiveEdge),
|
||||||
|
|
||||||
readEnable=if (readEnable) Some(PolarizedPort(name=realPrefix + "read_en", polarity=ActiveHigh)) else None,
|
readEnable = if (readEnable) Some(PolarizedPort(name = realPrefix + "read_en", polarity = ActiveHigh)) else None,
|
||||||
writeEnable=if (writeEnable) Some(PolarizedPort(name=realPrefix + "write_en", polarity=ActiveHigh)) else None,
|
writeEnable = if (writeEnable) Some(PolarizedPort(name = realPrefix + "write_en", polarity = ActiveHigh)) else None,
|
||||||
|
|
||||||
output=if (read) Some(PolarizedPort(name=realPrefix + "dout", polarity=ActiveHigh)) else None,
|
output = if (read) Some(PolarizedPort(name = realPrefix + "dout", polarity = ActiveHigh)) else None,
|
||||||
input=if (write) Some(PolarizedPort(name=realPrefix + "din", polarity=ActiveHigh)) else None,
|
input = if (write) Some(PolarizedPort(name = realPrefix + "din", polarity = ActiveHigh)) else None,
|
||||||
|
|
||||||
maskPort=maskGran match {
|
maskPort = maskGran match {
|
||||||
case Some(x:Int) => Some(PolarizedPort(name=realPrefix + "mask", polarity=ActiveHigh))
|
case Some(x: Int) => Some(PolarizedPort(name = realPrefix + "mask", polarity = ActiveHigh))
|
||||||
case _ => None
|
case _ => None
|
||||||
},
|
},
|
||||||
maskGran=maskGran,
|
maskGran = maskGran,
|
||||||
|
|
||||||
width=width, depth=depth // These numbers don't matter here.
|
width = width, depth = depth // These numbers don't matter here.
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a read port for testing.
|
// Generate a read port for testing.
|
||||||
def generateReadPort(prefix: String, width: Int, depth: Int, readEnable: Boolean = false): MacroPort = {
|
def generateReadPort(prefix: String, width: Option[Int], depth: Option[Int], readEnable: Boolean = false): MacroPort = {
|
||||||
generateTestPort(prefix, width, depth, write=false, read=true, readEnable=readEnable)
|
generateTestPort(prefix, width, depth, write = false, read = true, readEnable = readEnable)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a write port for testing.
|
// Generate a write port for testing.
|
||||||
def generateWritePort(prefix: String, width: Int, depth: Int, maskGran: Option[Int] = None, writeEnable: Boolean = true): MacroPort = {
|
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)
|
generateTestPort(prefix, width, depth, maskGran = maskGran, write = true, read = false, writeEnable = writeEnable)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a simple read-write port for testing.
|
// Generate a simple read-write port for testing.
|
||||||
def generateReadWritePort(prefix: String, width: Int, depth: Int, maskGran: Option[Int] = None): MacroPort = {
|
def generateReadWritePort(prefix: String, width: Option[Int], depth: Option[Int], maskGran: Option[Int] = None): MacroPort = {
|
||||||
generateTestPort(
|
generateTestPort(
|
||||||
prefix, width, depth, maskGran=maskGran,
|
prefix, width, depth, maskGran = maskGran,
|
||||||
write=true, writeEnable=true,
|
write = true, writeEnable = true,
|
||||||
read=true, readEnable=false
|
read = true, readEnable = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a "simple" SRAM (active high/positive edge, 1 read-write port).
|
// Generate a "simple" SRAM (active high/positive edge, 1 read-write port).
|
||||||
def generateSRAM(name: String, prefix: String, width: Int, depth: Int, maskGran: Option[Int] = None, extraPorts: Seq[MacroExtraPort] = List()): SRAMMacro = {
|
def generateSRAM(name: String, prefix: String, width: Int, depth: Int, maskGran: Option[Int] = None, extraPorts: Seq[MacroExtraPort] = List()): SRAMMacro = {
|
||||||
SRAMMacro(
|
SRAMMacro(
|
||||||
name=name,
|
name = name,
|
||||||
width=width,
|
width = width,
|
||||||
depth=depth,
|
depth = depth,
|
||||||
family="1rw",
|
family = "1rw",
|
||||||
ports=Seq(generateReadWritePort(prefix, width, depth, maskGran)),
|
ports = Seq(generateReadWritePort(prefix, width, depth, maskGran)),
|
||||||
extraPorts=extraPorts
|
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.
|
// Generic "simple" test generator.
|
||||||
@@ -192,6 +210,7 @@ trait HasSimpleTestGenerator {
|
|||||||
// Override these with "override lazy val".
|
// Override these with "override lazy val".
|
||||||
// Why lazy? These are used in the constructor here so overriding non-lazily
|
// Why lazy? These are used in the constructor here so overriding non-lazily
|
||||||
// would be too late.
|
// would be too late.
|
||||||
|
def useCompiler: Boolean = false
|
||||||
def memWidth: Int
|
def memWidth: Int
|
||||||
def libWidth: Int
|
def libWidth: Int
|
||||||
def memDepth: Int
|
def memDepth: Int
|
||||||
@@ -224,10 +243,10 @@ trait HasSimpleTestGenerator {
|
|||||||
val lib = s"lib-${generatorType}${extraTagPrefixed}.json"
|
val lib = s"lib-${generatorType}${extraTagPrefixed}.json"
|
||||||
val v = s"${generatorType}${extraTagPrefixed}.v"
|
val v = s"${generatorType}${extraTagPrefixed}.v"
|
||||||
|
|
||||||
val mem_name = "target_memory"
|
lazy val mem_name = "target_memory"
|
||||||
val mem_addr_width = ceilLog2(memDepth)
|
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)
|
val lib_addr_width = ceilLog2(libDepth)
|
||||||
|
|
||||||
// Override these to change the port prefixes if needed.
|
// 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.
|
// Number of width bits in the last width-direction memory.
|
||||||
// e.g. if memWidth = 16 and libWidth = 8, this would be 8 since the last memory 0_1 has 8 bits of input width.
|
// e.g. if memWidth = 16 and libWidth = 8, this would be 8 since the last memory 0_1 has 8 bits of input width.
|
||||||
// e.g. if memWidth = 9 and libWidth = 8, this would be 1 since the last memory 0_1 has 1 bit of input width.
|
// e.g. if memWidth = 9 and libWidth = 8, this would be 1 since the last memory 0_1 has 1 bit of input width.
|
||||||
val lastWidthBits = if (memWidth % usableLibWidth == 0) usableLibWidth else (memWidth % usableLibWidth)
|
lazy val lastWidthBits = if (memWidth % usableLibWidth == 0) usableLibWidth else (memWidth % usableLibWidth)
|
||||||
val selectBits = mem_addr_width - lib_addr_width
|
lazy val selectBits = mem_addr_width - lib_addr_width
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience function to generate a mask statement.
|
* Convenience function to generate a mask statement.
|
||||||
@@ -410,3 +429,4 @@ trait HasNoLibTestGenerator extends HasSimpleTestGenerator {
|
|||||||
// If there is no lib, don't generate a body.
|
// If there is no lib, don't generate a body.
|
||||||
override def generateBody = ""
|
override def generateBody = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
macros/src/test/scala/SRAMCompiler.scala
Normal file
22
macros/src/test/scala/SRAMCompiler.scala
Normal 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)
|
||||||
|
}
|
||||||
@@ -20,27 +20,27 @@ trait HasSimpleDepthTestGenerator extends HasSimpleTestGenerator {
|
|||||||
if (selectBits > 0) {
|
if (selectBits > 0) {
|
||||||
output.append (
|
output.append (
|
||||||
s"""
|
s"""
|
||||||
node outer_addr_sel = bits(outer_addr, ${mem_addr_width - 1}, $lib_addr_width)
|
node ${memPortPrefix}_addr_sel = bits(${memPortPrefix}_addr, ${mem_addr_width - 1}, $lib_addr_width)
|
||||||
reg outer_addr_sel_reg : UInt<${selectBits}>, outer_clk with :
|
reg ${memPortPrefix}_addr_sel_reg : UInt<${selectBits}>, ${memPortPrefix}_clk with :
|
||||||
reset => (UInt<1>("h0"), outer_addr_sel_reg)
|
reset => (UInt<1>("h0"), ${memPortPrefix}_addr_sel_reg)
|
||||||
outer_addr_sel_reg <= mux(UInt<1>("h1"), outer_addr_sel, outer_addr_sel_reg)
|
${memPortPrefix}_addr_sel_reg <= mux(UInt<1>("h1"), ${memPortPrefix}_addr_sel, ${memPortPrefix}_addr_sel_reg)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i <- 0 to depthInstances - 1) {
|
for (i <- 0 to depthInstances - 1) {
|
||||||
val maskStatement = generateMaskStatement(0, i)
|
val maskStatement = generateMaskStatement(0, i)
|
||||||
val enableIdentifier = if (selectBits > 0) s"""eq(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(
|
output.append(
|
||||||
s"""
|
s"""
|
||||||
inst mem_${i}_0 of awesome_lib_mem
|
inst mem_${i}_0 of ${lib_name}
|
||||||
mem_${i}_0.lib_clk <= outer_clk
|
mem_${i}_0.${libPortPrefix}_clk <= ${memPortPrefix}_clk
|
||||||
mem_${i}_0.lib_addr <= outer_addr
|
mem_${i}_0.${libPortPrefix}_addr <= ${memPortPrefix}_addr
|
||||||
node outer_dout_${i}_0 = bits(mem_${i}_0.lib_dout, ${width - 1}, 0)
|
node ${memPortPrefix}_dout_${i}_0 = bits(mem_${i}_0.${libPortPrefix}_dout, ${width - 1}, 0)
|
||||||
mem_${i}_0.lib_din <= bits(outer_din, ${width - 1}, 0)
|
mem_${i}_0.${libPortPrefix}_din <= bits(${memPortPrefix}_din, ${width - 1}, 0)
|
||||||
${maskStatement}
|
${maskStatement}
|
||||||
mem_${i}_0.lib_write_en <= and(and(outer_write_en, UInt<1>("h1")), ${enableIdentifier})
|
mem_${i}_0.${libPortPrefix}_write_en <= and(and(${memPortPrefix}_write_en, UInt<1>("h1")), ${enableIdentifier})
|
||||||
node outer_dout_${i} = outer_dout_${i}_0
|
node ${memPortPrefix}_dout_${i} = ${memPortPrefix}_dout_${i}_0
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -48,16 +48,16 @@ s"""
|
|||||||
if (i > depthInstances - 1) {
|
if (i > depthInstances - 1) {
|
||||||
"UInt<1>(\"h0\")"
|
"UInt<1>(\"h0\")"
|
||||||
} else {
|
} 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)
|
selectBits, i.toHexString, i, generate_outer_dout_tree(i + 1, depthInstances)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
output append " outer_dout <= "
|
output append s" ${memPortPrefix}_dout <= "
|
||||||
if (selectBits > 0) {
|
if (selectBits > 0) {
|
||||||
output append generate_outer_dout_tree(0, depthInstances)
|
output append generate_outer_dout_tree(0, depthInstances)
|
||||||
} else {
|
} 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
|
output.toString
|
||||||
|
|||||||
@@ -40,28 +40,28 @@ trait HasSimpleWidthTestGenerator extends HasSimpleTestGenerator {
|
|||||||
} else """UInt<1>("h1")"""
|
} else """UInt<1>("h1")"""
|
||||||
|
|
||||||
s"""
|
s"""
|
||||||
mem_0_${i}.lib_clk <= outer_clk
|
mem_0_${i}.${libPortPrefix}_clk <= ${memPortPrefix}_clk
|
||||||
mem_0_${i}.lib_addr <= outer_addr
|
mem_0_${i}.${libPortPrefix}_addr <= ${memPortPrefix}_addr
|
||||||
node outer_dout_0_${i} = bits(mem_0_${i}.lib_dout, ${myMemWidth - 1}, 0)
|
node ${memPortPrefix}_dout_0_${i} = bits(mem_0_${i}.${libPortPrefix}_dout, ${myMemWidth - 1}, 0)
|
||||||
mem_0_${i}.lib_din <= bits(outer_din, ${myBaseBit + myMemWidth - 1}, ${myBaseBit})
|
mem_0_${i}.${libPortPrefix}_din <= bits(${memPortPrefix}_din, ${myBaseBit + myMemWidth - 1}, ${myBaseBit})
|
||||||
${maskStatement}
|
${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(_ + _)
|
}).reduceLeft(_ + _)
|
||||||
|
|
||||||
// Generate final output that concats together the sub-memories.
|
// Generate final output that concats together the sub-memories.
|
||||||
// e.g. cat(outer_dout_0_2, cat(outer_dout_0_1, outer_dout_0_0))
|
// e.g. cat(outer_dout_0_2, cat(outer_dout_0_1, outer_dout_0_0))
|
||||||
output append {
|
output append {
|
||||||
val doutStatements = ((widthInstances - 1 to 0 by -1) map (i => s"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)")
|
val catStmt = doutStatements.init.foldRight(doutStatements.last)((l: String, r: String) => s"cat($l, $r)")
|
||||||
s"""
|
s"""
|
||||||
node outer_dout_0 = ${catStmt}
|
node ${memPortPrefix}_dout_0 = ${catStmt}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
output append
|
output append
|
||||||
"""
|
s"""
|
||||||
outer_dout <= mux(UInt<1>("h1"), outer_dout_0, UInt<1>("h0"))
|
${memPortPrefix}_dout <= mux(UInt<1>("h1"), ${memPortPrefix}_dout_0, UInt<1>("h0"))
|
||||||
"""
|
"""
|
||||||
output.toString
|
output.toString
|
||||||
}
|
}
|
||||||
@@ -398,7 +398,7 @@ class SplitWidth1024x32_readEnable_Lib extends MacroCompilerSpec with HasSRAMGen
|
|||||||
depth=libDepth,
|
depth=libDepth,
|
||||||
family="1rw",
|
family="1rw",
|
||||||
ports=Seq(generateTestPort(
|
ports=Seq(generateTestPort(
|
||||||
"lib", libWidth, libDepth, maskGran=libMaskGran,
|
"lib", Some(libWidth), Some(libDepth), maskGran=libMaskGran,
|
||||||
write=true, writeEnable=true,
|
write=true, writeEnable=true,
|
||||||
read=true, readEnable=true
|
read=true, readEnable=true
|
||||||
))
|
))
|
||||||
@@ -456,7 +456,7 @@ class SplitWidth1024x32_readEnable_Mem extends MacroCompilerSpec with HasSRAMGen
|
|||||||
depth=memDepth,
|
depth=memDepth,
|
||||||
family="1rw",
|
family="1rw",
|
||||||
ports=Seq(generateTestPort(
|
ports=Seq(generateTestPort(
|
||||||
"outer", memWidth, memDepth, maskGran=memMaskGran,
|
"outer", Some(memWidth), Some(memDepth), maskGran=memMaskGran,
|
||||||
write=true, writeEnable=true,
|
write=true, writeEnable=true,
|
||||||
read=true, readEnable=true
|
read=true, readEnable=true
|
||||||
))
|
))
|
||||||
@@ -482,7 +482,7 @@ class SplitWidth1024x32_readEnable_LibMem extends MacroCompilerSpec with HasSRAM
|
|||||||
depth=libDepth,
|
depth=libDepth,
|
||||||
family="1rw",
|
family="1rw",
|
||||||
ports=Seq(generateTestPort(
|
ports=Seq(generateTestPort(
|
||||||
"lib", libWidth, libDepth, maskGran=libMaskGran,
|
"lib", Some(libWidth), Some(libDepth), maskGran=libMaskGran,
|
||||||
write=true, writeEnable=true,
|
write=true, writeEnable=true,
|
||||||
read=true, readEnable=true
|
read=true, readEnable=true
|
||||||
))
|
))
|
||||||
@@ -496,7 +496,7 @@ class SplitWidth1024x32_readEnable_LibMem extends MacroCompilerSpec with HasSRAM
|
|||||||
depth=memDepth,
|
depth=memDepth,
|
||||||
family="1rw",
|
family="1rw",
|
||||||
ports=Seq(generateTestPort(
|
ports=Seq(generateTestPort(
|
||||||
"outer", memWidth, memDepth, maskGran=memMaskGran,
|
"outer", Some(memWidth), Some(memDepth), maskGran=memMaskGran,
|
||||||
write=true, writeEnable=true,
|
write=true, writeEnable=true,
|
||||||
read=true, readEnable=true
|
read=true, readEnable=true
|
||||||
))
|
))
|
||||||
|
|||||||
2
mdf
2
mdf
Submodule mdf updated: 2b5f3c16da...2bc5a363e2
Reference in New Issue
Block a user