Emit hammer IR from MacroCompiler (#50)
This commit is contained in:
committed by
edwardcwang
parent
fdad525007
commit
affd033f0a
@@ -18,6 +18,7 @@ import firrtl.CompilerUtils.getLoweringTransforms
|
|||||||
import mdf.macrolib.{PolarizedPort, PortPolarity, SRAMMacro, SRAMGroup, SRAMCompiler}
|
import mdf.macrolib.{PolarizedPort, PortPolarity, SRAMMacro, SRAMGroup, SRAMCompiler}
|
||||||
import scala.collection.mutable.{ArrayBuffer, HashMap}
|
import scala.collection.mutable.{ArrayBuffer, HashMap}
|
||||||
import java.io.{File, FileWriter}
|
import java.io.{File, FileWriter}
|
||||||
|
import scala.io.{Source}
|
||||||
import Utils._
|
import Utils._
|
||||||
|
|
||||||
case class MacroCompilerException(msg: String) extends Exception(msg)
|
case class MacroCompilerException(msg: String) extends Exception(msg)
|
||||||
@@ -76,12 +77,14 @@ object MacroCompilerAnnotation {
|
|||||||
* @param mem Path to memory lib
|
* @param mem Path to memory lib
|
||||||
* @param memFormat Type of memory lib (Some("conf"), Some("mdf"), or None (defaults to mdf))
|
* @param memFormat Type of memory lib (Some("conf"), Some("mdf"), or None (defaults to mdf))
|
||||||
* @param lib Path to library lib or None if no libraries
|
* @param lib Path to library lib or None if no libraries
|
||||||
|
* @param hammerIR Path to HammerIR output or None (not generated in this case)
|
||||||
* @param costMetric Cost metric to use
|
* @param costMetric Cost metric to use
|
||||||
* @param mode Compiler mode (see CompilerMode)
|
* @param mode Compiler mode (see CompilerMode)
|
||||||
* @param forceCompile Set of memories to force compiling to lib regardless of the mode
|
* @param forceCompile Set of memories to force compiling to lib regardless of the mode
|
||||||
* @param forceSynflops Set of memories to force compiling as flops regardless of the mode
|
* @param forceSynflops Set of memories to force compiling as flops regardless of the mode
|
||||||
*/
|
*/
|
||||||
case class Params(mem: String, memFormat: Option[String], lib: Option[String], costMetric: CostMetric, mode: CompilerMode, useCompiler: Boolean,
|
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])
|
forceCompile: Set[String], forceSynflops: Set[String])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,6 +107,7 @@ object MacroCompilerAnnotation {
|
|||||||
class MacroCompilerPass(mems: Option[Seq[Macro]],
|
class MacroCompilerPass(mems: Option[Seq[Macro]],
|
||||||
libs: Option[Seq[Macro]],
|
libs: Option[Seq[Macro]],
|
||||||
compilers: Option[SRAMCompiler],
|
compilers: Option[SRAMCompiler],
|
||||||
|
hammerIR: Option[String],
|
||||||
costMetric: CostMetric = CostMetric.default,
|
costMetric: CostMetric = CostMetric.default,
|
||||||
mode: MacroCompilerAnnotation.CompilerMode = MacroCompilerAnnotation.Default) extends firrtl.passes.Pass {
|
mode: MacroCompilerAnnotation.CompilerMode = MacroCompilerAnnotation.Default) extends firrtl.passes.Pass {
|
||||||
// Helper function to check the legality of bitPairs.
|
// Helper function to check the legality of bitPairs.
|
||||||
@@ -262,7 +266,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
|
|||||||
bitPairs.toSeq
|
bitPairs.toSeq
|
||||||
}
|
}
|
||||||
|
|
||||||
def compile(mem: Macro, lib: Macro): Option[(Module, ExtModule)] = {
|
def compile(mem: Macro, lib: Macro): Option[(Module, Macro)] = {
|
||||||
assert(mem.sortedPorts.lengthCompare(lib.sortedPorts.length) == 0,
|
assert(mem.sortedPorts.lengthCompare(lib.sortedPorts.length) == 0,
|
||||||
"mem and lib should have an equal number of ports")
|
"mem and lib should have an equal number of ports")
|
||||||
val pairedPorts = mem.sortedPorts zip lib.sortedPorts
|
val pairedPorts = mem.sortedPorts zip lib.sortedPorts
|
||||||
@@ -555,10 +559,11 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some((mem.module(Block(stmts.toSeq)), lib.blackbox))
|
Some((mem.module(Block(stmts.toSeq)), lib))
|
||||||
}
|
}
|
||||||
|
|
||||||
def run(c: Circuit): Circuit = {
|
def run(c: Circuit): Circuit = {
|
||||||
|
var firstLib = true
|
||||||
val modules = (mems, libs) match {
|
val modules = (mems, libs) match {
|
||||||
case (Some(mems), Some(libs)) =>
|
case (Some(mems), Some(libs)) =>
|
||||||
// Try to compile each of the memories in mems.
|
// Try to compile each of the memories in mems.
|
||||||
@@ -590,7 +595,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
|
|||||||
|
|
||||||
// Try to compile mem against each lib in libs, keeping track of the
|
// Try to compile mem against each lib in libs, keeping track of the
|
||||||
// best compiled version, external lib used, and cost.
|
// best compiled version, external lib used, and cost.
|
||||||
val (best, cost) = (fullLibs foldLeft (None: Option[(Module, ExtModule)], Double.MaxValue)){
|
val (best, cost) = (fullLibs foldLeft (None: Option[(Module, Macro)], Double.MaxValue)){
|
||||||
case ((best, cost), lib) if mem.src.ports.size != lib.src.ports.size =>
|
case ((best, cost), lib) if mem.src.ports.size != lib.src.ports.size =>
|
||||||
/* Palmer: FIXME: This just assumes the Chisel and vendor ports are in the same
|
/* Palmer: FIXME: This just assumes the Chisel and vendor ports are in the same
|
||||||
* order, but I'm starting with what actually gets generated. */
|
* order, but I'm starting with what actually gets generated. */
|
||||||
@@ -623,7 +628,18 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
|
|||||||
modules
|
modules
|
||||||
}
|
}
|
||||||
case Some((mod, bb)) =>
|
case Some((mod, bb)) =>
|
||||||
(modules filterNot (m => m.name == mod.name || m.name == bb.name)) ++ Seq(mod, bb)
|
hammerIR match {
|
||||||
|
case Some(f) => {
|
||||||
|
val hammerIRWriter = new FileWriter(new File(f), !firstLib)
|
||||||
|
if(firstLib) hammerIRWriter.write("[\n")
|
||||||
|
hammerIRWriter.write(bb.src.toJSON().toString())
|
||||||
|
hammerIRWriter.write("\n,\n")
|
||||||
|
hammerIRWriter.close()
|
||||||
|
firstLib = false
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
}
|
||||||
|
(modules filterNot (m => m.name == mod.name || m.name == bb.blackbox.name)) ++ Seq(mod, bb.blackbox)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case _ => c.modules
|
case _ => c.modules
|
||||||
@@ -638,7 +654,7 @@ class MacroCompilerTransform extends Transform {
|
|||||||
|
|
||||||
def execute(state: CircuitState) = getMyAnnotations(state) match {
|
def execute(state: CircuitState) = getMyAnnotations(state) match {
|
||||||
case Seq(MacroCompilerAnnotation(state.circuit.main,
|
case Seq(MacroCompilerAnnotation(state.circuit.main,
|
||||||
MacroCompilerAnnotation.Params(memFile, memFileFormat, libFile, costMetric, mode, useCompiler, forceCompile, forceSynflops))) =>
|
MacroCompilerAnnotation.Params(memFile, memFileFormat, libFile, hammerIR, costMetric, mode, useCompiler, forceCompile, forceSynflops))) =>
|
||||||
if (mode == MacroCompilerAnnotation.FallbackSynflops) {
|
if (mode == MacroCompilerAnnotation.FallbackSynflops) {
|
||||||
throw new UnsupportedOperationException("Not implemented yet")
|
throw new UnsupportedOperationException("Not implemented yet")
|
||||||
}
|
}
|
||||||
@@ -686,7 +702,7 @@ class MacroCompilerTransform extends Transform {
|
|||||||
}.getOrElse(Seq.empty)
|
}.getOrElse(Seq.empty)
|
||||||
|
|
||||||
val transforms = Seq(
|
val transforms = Seq(
|
||||||
new MacroCompilerPass(memCompile, libs, compilers, costMetric, mode),
|
new MacroCompilerPass(memCompile, libs, compilers, hammerIR, costMetric, mode),
|
||||||
new SynFlopsPass(true, memSynflops ++ (if (mode == MacroCompilerAnnotation.CompileAndSynflops) {
|
new SynFlopsPass(true, memSynflops ++ (if (mode == MacroCompilerAnnotation.CompileAndSynflops) {
|
||||||
libs.get
|
libs.get
|
||||||
} else {
|
} else {
|
||||||
@@ -729,6 +745,7 @@ object MacroCompiler extends App {
|
|||||||
case object Library extends MacroParam
|
case object Library extends MacroParam
|
||||||
case object Verilog extends MacroParam
|
case object Verilog extends MacroParam
|
||||||
case object Firrtl extends MacroParam
|
case object Firrtl extends MacroParam
|
||||||
|
case object HammerIR 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
|
case object UseCompiler extends MacroParam
|
||||||
@@ -746,6 +763,7 @@ object MacroCompiler extends App {
|
|||||||
" -u, --use-compiler: Flag, whether to use the memory compiler defined in library",
|
" -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)",
|
||||||
|
" -hir, --hammer-ir: Hammer-IR output currently only needed for IP compilers",
|
||||||
" -c, --cost-func: Cost function to use. Optional (default: \"default\")",
|
" -c, --cost-func: Cost function to use. Optional (default: \"default\")",
|
||||||
" -cp, --cost-param: Cost function parameter. (Optional depending on the cost function.). e.g. -c ExternalMetric -cp path /path/to/my/cost/script",
|
" -cp, --cost-param: Cost function parameter. (Optional depending on the cost function.). e.g. -c ExternalMetric -cp path /path/to/my/cost/script",
|
||||||
" --force-compile [mem]: Force the given memory to be compiled to target libs regardless of the mode",
|
" --force-compile [mem]: Force the given memory to be compiled to target libs regardless of the mode",
|
||||||
@@ -769,6 +787,8 @@ object MacroCompiler extends App {
|
|||||||
parseArgs(map + (Verilog -> value), costMap, forcedMemories, tail)
|
parseArgs(map + (Verilog -> value), costMap, forcedMemories, tail)
|
||||||
case ("-f" | "--firrtl") :: value :: tail =>
|
case ("-f" | "--firrtl") :: value :: tail =>
|
||||||
parseArgs(map + (Firrtl -> value), costMap, forcedMemories, tail)
|
parseArgs(map + (Firrtl -> value), costMap, forcedMemories, tail)
|
||||||
|
case ("-hir" | "--hammer-ir") :: value :: tail =>
|
||||||
|
parseArgs(map + (HammerIR -> value), costMap, forcedMemories, tail)
|
||||||
case ("-c" | "--cost-func") :: value :: tail =>
|
case ("-c" | "--cost-func") :: value :: tail =>
|
||||||
parseArgs(map + (CostFunc -> value), costMap, forcedMemories, tail)
|
parseArgs(map + (CostFunc -> value), costMap, forcedMemories, tail)
|
||||||
case ("-cp" | "--cost-param") :: value1 :: value2 :: tail =>
|
case ("-cp" | "--cost-param") :: value1 :: value2 :: tail =>
|
||||||
@@ -802,6 +822,7 @@ object MacroCompiler extends App {
|
|||||||
circuit.main,
|
circuit.main,
|
||||||
MacroCompilerAnnotation.Params(
|
MacroCompilerAnnotation.Params(
|
||||||
params.get(Macros).get, params.get(MacrosFormat), params.get(Library),
|
params.get(Macros).get, params.get(MacrosFormat), params.get(Library),
|
||||||
|
params.get(HammerIR),
|
||||||
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),
|
params.contains(UseCompiler),
|
||||||
@@ -839,6 +860,17 @@ object MacroCompiler extends App {
|
|||||||
}
|
}
|
||||||
case None =>
|
case None =>
|
||||||
}
|
}
|
||||||
|
params.get(HammerIR) match {
|
||||||
|
case Some(hammerIRFile: String) => {
|
||||||
|
val lines = Source.fromFile(hammerIRFile).getLines().toList
|
||||||
|
val hammerIRWriter = new FileWriter(new File(hammerIRFile))
|
||||||
|
// JSON means we need to destroy the last comma :(
|
||||||
|
lines.dropRight(1).foreach(l => hammerIRWriter.write(l + "\n"))
|
||||||
|
hammerIRWriter.write("]\n")
|
||||||
|
hammerIRWriter.close()
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Warn user
|
// Warn user
|
||||||
System.err println "WARNING: Empty *.mems.conf file. No memories generated."
|
System.err println "WARNING: Empty *.mems.conf file. No memories generated."
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ object Utils {
|
|||||||
}
|
}
|
||||||
def readConfFromString(str: String): Seq[mdf.macrolib.Macro] = {
|
def readConfFromString(str: String): Seq[mdf.macrolib.Macro] = {
|
||||||
MemConf.fromString(str).map { m:MemConf =>
|
MemConf.fromString(str).map { m:MemConf =>
|
||||||
SRAMMacro(m.name, m.width, m.depth, Utils.portSpecToFamily(m.ports), Utils.portSpecToMacroPort(m.width, m.depth, m.maskGranularity, m.ports), Seq.empty[MacroExtraPort])
|
SRAMMacro(m.name, m.width, m.depth, Utils.portSpecToFamily(m.ports), Utils.portSpecToMacroPort(m.width, m.depth, m.maskGranularity, m.ports))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def portSpecToFamily(ports: Seq[MemPort]): String = {
|
def portSpecToFamily(ports: Seq[MemPort]): String = {
|
||||||
@@ -167,10 +167,10 @@ object Utils {
|
|||||||
}
|
}
|
||||||
def buildSRAMMacros(s: mdf.macrolib.SRAMCompiler): Seq[mdf.macrolib.SRAMMacro] = {
|
def buildSRAMMacros(s: mdf.macrolib.SRAMCompiler): Seq[mdf.macrolib.SRAMMacro] = {
|
||||||
for (g <- s.groups; d <- g.depth; w <- g.width; vt <- g.vt)
|
for (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)
|
yield mdf.macrolib.SRAMMacro(makeName(g, d, w, vt), w, d, g.family, g.ports.map(_.copy(width=Some(w), depth=Some(d))), vt, g.mux, g.extraPorts)
|
||||||
}
|
}
|
||||||
def buildSRAMMacro(g: mdf.macrolib.SRAMGroup, d: Int, w: Int, vt: String): mdf.macrolib.SRAMMacro = {
|
def buildSRAMMacro(g: mdf.macrolib.SRAMGroup, d: Int, w: Int, vt: String): mdf.macrolib.SRAMMacro = {
|
||||||
return mdf.macrolib.SRAMMacro(makeName(g, d, w, vt), w, d, g.family, g.ports.map(_.copy(width=Some(w), depth=Some(d))), g.extraPorts)
|
return mdf.macrolib.SRAMMacro(makeName(g, d, w, vt), w, d, g.family, g.ports.map(_.copy(width=Some(w), depth=Some(d))), vt, g.mux, g.extraPorts)
|
||||||
}
|
}
|
||||||
def makeName(g: mdf.macrolib.SRAMGroup, depth: Int, width: Int, vt: String): String = {
|
def makeName(g: mdf.macrolib.SRAMGroup, depth: Int, width: Int, vt: String): String = {
|
||||||
g.name.foldLeft(""){ (builder, next) =>
|
g.name.foldLeft(""){ (builder, next) =>
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
|
|||||||
val macros = mems map (_.blackbox)
|
val macros = mems map (_.blackbox)
|
||||||
val circuit = Circuit(NoInfo, macros, macros.last.name)
|
val circuit = Circuit(NoInfo, macros, macros.last.name)
|
||||||
val passes = Seq(
|
val passes = Seq(
|
||||||
new MacroCompilerPass(Some(mems), libs, None, getCostMetric, if (synflops) MacroCompilerAnnotation.Synflops else MacroCompilerAnnotation.Default),
|
new MacroCompilerPass(Some(mems), libs, None, None, getCostMetric, if (synflops) MacroCompilerAnnotation.Synflops else MacroCompilerAnnotation.Default),
|
||||||
new SynFlopsPass(synflops, libs getOrElse mems),
|
new SynFlopsPass(synflops, libs getOrElse mems),
|
||||||
RemoveEmpty)
|
RemoveEmpty)
|
||||||
val result: Circuit = (passes foldLeft circuit)((c, pass) => pass run c)
|
val result: Circuit = (passes foldLeft circuit)((c, pass) => pass run c)
|
||||||
|
|||||||
2
mdf
2
mdf
Submodule mdf updated: e9befe89eb...94839b30ba
Reference in New Issue
Block a user