From 12842cb3a79bb6d59d61ebb2af17c4a67fd42d6e Mon Sep 17 00:00:00 2001 From: John Wright Date: Mon, 11 Feb 2019 22:54:01 -0800 Subject: [PATCH] Add MemConf and change MacroCompiler to use a conf file instead of MDF JSON --- macros/src/main/scala/MacroCompiler.scala | 8 +-- macros/src/main/scala/MemConf.scala | 55 ++++++++++++++++ macros/src/main/scala/Utils.scala | 77 ++++++++++++++++++++++- 3 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 macros/src/main/scala/MemConf.scala diff --git a/macros/src/main/scala/MacroCompiler.scala b/macros/src/main/scala/MacroCompiler.scala index 410372dd..9e0c72ed 100644 --- a/macros/src/main/scala/MacroCompiler.scala +++ b/macros/src/main/scala/MacroCompiler.scala @@ -618,7 +618,7 @@ class MacroCompilerTransform extends Transform { assert((forceCompile intersect forceSynflops).isEmpty, "Cannot have modules both forced to compile and synflops") // Read, eliminate None, get only SRAM, make firrtl macro - val mems: Option[Seq[Macro]] = mdf.macrolib.Utils.readMDFFromPath(Some(memFile)) match { + val mems: Option[Seq[Macro]] = Utils.readConfFromPath(Some(memFile)) match { case Some(x:Seq[mdf.macrolib.Macro]) => Some(Utils.filterForSRAM(Some(x)) getOrElse(List()) map {new Macro(_)}) case _ => None @@ -701,7 +701,7 @@ object MacroCompiler extends App { .map { case (_, cmd, description) => s" $cmd: $description" } val usage: String = (Seq( "Options:", - " -m, --macro-list: The set of macros to compile", + " -m, --macro-conf: The set of macros to compile in firrtl-generated conf format", " -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", @@ -717,7 +717,7 @@ object MacroCompiler extends App { args: List[String]): (MacroParamMap, CostParamMap, ForcedMemories) = args match { case Nil => (map, costMap, forcedMemories) - case ("-m" | "--macro-list") :: value :: tail => + case ("-m" | "--macro-conf") :: value :: tail => parseArgs(map + (Macros -> value), costMap, forcedMemories, tail) case ("-l" | "--library") :: value :: tail => parseArgs(map + (Library -> value), costMap, forcedMemories, tail) @@ -746,7 +746,7 @@ object MacroCompiler extends App { def run(args: List[String]) { val (params, costParams, forcedMemories) = parseArgs(Map[MacroParam, String](), Map[String, String](), (Set.empty, Set.empty), args) try { - val macros = Utils.filterForSRAM(mdf.macrolib.Utils.readMDFFromPath(params.get(Macros))).get map (x => (new Macro(x)).blackbox) + val macros = Utils.filterForSRAM(Utils.readConfFromPath(params.get(Macros))).get map (x => (new Macro(x)).blackbox) if (macros.nonEmpty) { // Note: the last macro in the input list is (seemingly arbitrarily) diff --git a/macros/src/main/scala/MemConf.scala b/macros/src/main/scala/MemConf.scala new file mode 100644 index 00000000..d277c066 --- /dev/null +++ b/macros/src/main/scala/MemConf.scala @@ -0,0 +1,55 @@ +// See LICENSE for license details. + +package barstools.macros + +import scala.util.matching._ + +sealed abstract class MemPort(val name: String) { override def toString = name } + +case object ReadPort extends MemPort("read") +case object WritePort extends MemPort("write") +case object MaskWritePort extends MemPort("mwrite") +case object ReadWritePort extends MemPort("rw") +case object MaskReadWritePort extends MemPort("mrw") + +object MemPort { + + val all = Set(ReadPort, WritePort, MaskWritePort, ReadWritePort, MaskReadWritePort) + + def apply(s: String): Option[MemPort] = MemPort.all.find(_.name == s) + + def fromString(s: String): Seq[MemPort] = { + s.split(",").toSeq.map(MemPort.apply).map(_ match { + case Some(x) => x + case _ => throw new Exception(s"Error parsing MemPort string : ${s}") + }) + } +} + +// This is based on firrtl.passes.memlib.ConfWriter +// TODO standardize this in FIRRTL +case class MemConf( + name: String, + depth: Int, + width: Int, + ports: Seq[MemPort], + maskGranularity: Option[Int] +) { + + private def portsStr = ports.map(_.name).mkString(",") + private def maskGranStr = maskGranularity.map((p) => s"mask_gran $p").getOrElse("") + + override def toString() = s"name ${name} depth ${depth} width ${width} ports ${portsStr} ${maskGranStr} " +} + +object MemConf { + + val regex = raw"\s*name\s+(\w+)\s+depth\s+(\d+)\s+width\s+(\d+)\s+ports\s+([^\s]+)\s+(?:mask_gran\s+(\d+))?\s*".r + + def fromString(s: String): Seq[MemConf] = { + s.split("\n").toSeq.map(_ match { + case MemConf.regex(name, depth, width, ports, maskGran) => MemConf(name, depth.toInt, width.toInt, MemPort.fromString(ports), Option(maskGran).map(_.toInt)) + case _ => throw new Exception(s"Error parsing MemConf string : ${s}") + }) + } +} diff --git a/macros/src/main/scala/Utils.scala b/macros/src/main/scala/Utils.scala index ded5c53f..6a420961 100644 --- a/macros/src/main/scala/Utils.scala +++ b/macros/src/main/scala/Utils.scala @@ -7,7 +7,7 @@ import firrtl.ir._ import firrtl.PrimOps import firrtl.Utils.{ceilLog2, BoolType} import mdf.macrolib.{Constant, MacroPort, SRAMMacro} -import mdf.macrolib.{PolarizedPort, PortPolarity, ActiveLow, ActiveHigh, NegativeEdge, PositiveEdge} +import mdf.macrolib.{PolarizedPort, PortPolarity, ActiveLow, ActiveHigh, NegativeEdge, PositiveEdge, MacroExtraPort} import java.io.File import scala.language.implicitConversions @@ -72,6 +72,81 @@ object Utils { case _ => None } } + // This utility reads a conf in and returns MDF like mdf.macrolib.Utils.readMDFFromPath + def readConfFromPath(path: Option[String]): Option[Seq[mdf.macrolib.Macro]] = { + path.map((p) => Utils.readConfFromString(scala.io.Source.fromFile(p).mkString)) + } + def readConfFromString(str: String): Seq[mdf.macrolib.Macro] = { + MemConf.fromString(str).map { m:MemConf => + SRAMMacro(m.name, m.width, m.depth, "", Utils.portSpecToMacroPort(m.width, m.depth, m.maskGranularity, m.ports), Seq.empty[MacroExtraPort]) + } + } + // This translates between two represenations of ports + def portSpecToMacroPort(width: Int, depth: Int, maskGran: Option[Int], ports: Seq[MemPort]): Seq[MacroPort] = { + var numR = 0 + var numW = 0 + var numRW = 0 + ports.map { _ match { + case ReadPort => { + val portName = s"R${numR}" + numR += 1 + MacroPort( + width=Some(width), depth=Some(depth), + address=PolarizedPort(s"${portName}_address", ActiveHigh), + clock=PolarizedPort(s"${portName}_clock", PositiveEdge), + readEnable=Some(PolarizedPort(s"${portName}_ren", ActiveHigh)), + output=Some(PolarizedPort(s"${portName}_data", ActiveHigh)) + ) } + case WritePort => { + val portName = s"W${numW}" + numW += 1 + MacroPort( + width=Some(width), depth=Some(depth), + address=PolarizedPort(s"${portName}_address", ActiveHigh), + clock=PolarizedPort(s"${portName}_clock", PositiveEdge), + writeEnable=Some(PolarizedPort(s"${portName}_wen", ActiveHigh)), + input=Some(PolarizedPort(s"${portName}_data", ActiveHigh)) + ) } + case MaskWritePort => { + val portName = s"W${numW}" + numW += 1 + MacroPort( + width=Some(width), depth=Some(depth), + address=PolarizedPort(s"${portName}_address", ActiveHigh), + clock=PolarizedPort(s"${portName}_clock", PositiveEdge), + writeEnable=Some(PolarizedPort(s"${portName}_wen", ActiveHigh)), + maskPort=Some(PolarizedPort(s"${portName}_mask", ActiveHigh)), + maskGran=maskGran, + input=Some(PolarizedPort(s"${portName}_data", ActiveHigh)) + ) } + case ReadWritePort => { + val portName = s"RW${numRW}" + numRW += 1 + MacroPort( + width=Some(width), depth=Some(depth), + address=PolarizedPort(s"${portName}_address", ActiveHigh), + clock=PolarizedPort(s"${portName}_clock", PositiveEdge), + writeEnable=Some(PolarizedPort(s"${portName}_wen", ActiveHigh)), + readEnable=Some(PolarizedPort(s"${portName}_ren", ActiveHigh)), + input=Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)), + output=Some(PolarizedPort(s"${portName}_rdata", ActiveHigh)) + ) } + case MaskReadWritePort => { + val portName = s"RW${numRW}" + numRW += 1 + MacroPort( + width=Some(width), depth=Some(depth), + address=PolarizedPort(s"${portName}_address", ActiveHigh), + clock=PolarizedPort(s"${portName}_clock", PositiveEdge), + writeEnable=Some(PolarizedPort(s"${portName}_wen", ActiveHigh)), + readEnable=Some(PolarizedPort(s"${portName}_ren", ActiveHigh)), + maskPort=Some(PolarizedPort(s"${portName}_mask", ActiveHigh)), + maskGran=maskGran, + input=Some(PolarizedPort(s"${portName}_wdata", ActiveHigh)), + output=Some(PolarizedPort(s"${portName}_rdata", ActiveHigh)) + ) } + }} + } def findSRAMCompiler(s: Option[Seq[mdf.macrolib.Macro]]): Option[mdf.macrolib.SRAMCompiler] = { s match { case Some(l:Seq[mdf.macrolib.Macro]) =>