Emit hammer IR from MacroCompiler (#50)

This commit is contained in:
Colin Schmidt
2019-03-25 22:52:39 -07:00
committed by edwardcwang
parent fdad525007
commit affd033f0a
4 changed files with 44 additions and 12 deletions

View File

@@ -18,6 +18,7 @@ import firrtl.CompilerUtils.getLoweringTransforms
import mdf.macrolib.{PolarizedPort, PortPolarity, SRAMMacro, SRAMGroup, SRAMCompiler}
import scala.collection.mutable.{ArrayBuffer, HashMap}
import java.io.{File, FileWriter}
import scala.io.{Source}
import Utils._
case class MacroCompilerException(msg: String) extends Exception(msg)
@@ -76,12 +77,14 @@ object MacroCompilerAnnotation {
* @param mem Path to memory lib
* @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 hammerIR Path to HammerIR output or None (not generated in this case)
* @param costMetric Cost metric to use
* @param mode Compiler mode (see CompilerMode)
* @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], 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])
/**
@@ -104,6 +107,7 @@ object MacroCompilerAnnotation {
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.
@@ -262,7 +266,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
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,
"mem and lib should have an equal number of ports")
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 = {
var firstLib = true
val modules = (mems, libs) match {
case (Some(mems), Some(libs)) =>
// 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
// 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 =>
/* Palmer: FIXME: This just assumes the Chisel and vendor ports are in the same
* order, but I'm starting with what actually gets generated. */
@@ -623,7 +628,18 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
modules
}
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
@@ -638,7 +654,7 @@ class MacroCompilerTransform extends Transform {
def execute(state: CircuitState) = getMyAnnotations(state) match {
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) {
throw new UnsupportedOperationException("Not implemented yet")
}
@@ -686,7 +702,7 @@ class MacroCompilerTransform extends Transform {
}.getOrElse(Seq.empty)
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) {
libs.get
} else {
@@ -729,6 +745,7 @@ object MacroCompiler extends App {
case object Library extends MacroParam
case object Verilog extends MacroParam
case object Firrtl extends MacroParam
case object HammerIR extends MacroParam
case object CostFunc extends MacroParam
case object Mode 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",
" -v, --verilog: Verilog output",
" -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\")",
" -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",
@@ -769,6 +787,8 @@ object MacroCompiler extends App {
parseArgs(map + (Verilog -> value), costMap, forcedMemories, tail)
case ("-f" | "--firrtl") :: value :: 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 =>
parseArgs(map + (CostFunc -> value), costMap, forcedMemories, tail)
case ("-cp" | "--cost-param") :: value1 :: value2 :: tail =>
@@ -802,6 +822,7 @@ object MacroCompiler extends App {
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),
@@ -839,6 +860,17 @@ object MacroCompiler extends App {
}
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 {
// Warn user
System.err println "WARNING: Empty *.mems.conf file. No memories generated."

View File

@@ -78,7 +78,7 @@ object Utils {
}
def readConfFromString(str: String): Seq[mdf.macrolib.Macro] = {
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 = {
@@ -167,10 +167,10 @@ object Utils {
}
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)
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))), 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) =>

View File

@@ -99,7 +99,7 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
val macros = mems map (_.blackbox)
val circuit = Circuit(NoInfo, macros, macros.last.name)
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),
RemoveEmpty)
val result: Circuit = (passes foldLeft circuit)((c, pass) => pass run c)

2
mdf

Submodule mdf updated: e9befe89eb...94839b30ba