Files
chipyard/src/main/scala/barstools/macros/SynFlops.scala
2021-08-10 15:40:58 -07:00

152 lines
5.9 KiB
Scala

// See LICENSE for license details.
package barstools.macros
import barstools.macros.Utils._
import firrtl.Utils.{zero, one}
import firrtl._
import firrtl.ir._
import firrtl.passes.MemPortUtils.memPortField
class SynFlopsPass(synflops: Boolean, libs: Seq[Macro]) extends firrtl.passes.Pass {
val extraMods = scala.collection.mutable.ArrayBuffer.empty[Module]
lazy val libMods = (libs.map { lib =>
lib.src.name -> {
val (dataType, dataWidth) = (lib.src.ports.foldLeft(None: Option[BigInt]))((res, port) =>
(res, port.maskPort) match {
case (_, None) =>
res
case (None, Some(_)) =>
Some(port.effectiveMaskGran)
case (Some(x), Some(_)) =>
assert(x == port.effectiveMaskGran)
res
}
) match {
case None => (UIntType(IntWidth(lib.src.width)), lib.src.width)
case Some(gran) => (UIntType(IntWidth(gran)), gran.intValue)
}
val maxDepth = firrtl.Utils.min(lib.src.depth, 1 << 26)
val numMems = lib.src.depth / maxDepth
// Change macro to be mapped onto to look like the below mem
// by changing its depth, and width
val lib_macro = new Macro(
lib.src.copy(
name = "split_" + lib.src.name,
depth = maxDepth,
width = dataWidth,
ports = lib.src.ports.map(p =>
p.copy(
width = p.width.map(_ => dataWidth),
depth = p.depth.map(_ => maxDepth),
maskGran = p.maskGran.map(_ => dataWidth)
)
)
)
)
val mod_macro = (new MacroCompilerPass(None, None, None, None)).compile(lib, lib_macro)
val (real_mod, real_macro) = mod_macro.get
val mem = DefMemory(
NoInfo,
"ram",
dataType,
maxDepth,
1, // writeLatency
1, // readLatency. This is possible because of VerilogMemDelays
real_macro.readers.indices.map(i => s"R_$i"),
real_macro.writers.indices.map(i => s"W_$i"),
real_macro.readwriters.indices.map(i => s"RW_$i")
)
val readConnects = real_macro.readers.zipWithIndex.flatMap { case (r, i) =>
val clock = portToExpression(r.src.clock.get)
val address = portToExpression(r.src.address)
val enable = (r.src.chipEnable, r.src.readEnable) match {
case (Some(en_port), Some(re_port)) =>
and(portToExpression(en_port), portToExpression(re_port))
case (Some(en_port), None) => portToExpression(en_port)
case (None, Some(re_port)) => portToExpression(re_port)
case (None, None) => one
}
val data = memPortField(mem, s"R_$i", "data")
val read = data
Seq(
Connect(NoInfo, memPortField(mem, s"R_$i", "clk"), clock),
Connect(NoInfo, memPortField(mem, s"R_$i", "addr"), address),
Connect(NoInfo, memPortField(mem, s"R_$i", "en"), enable),
Connect(NoInfo, WRef(r.src.output.get.name), read)
)
}
val writeConnects = real_macro.writers.zipWithIndex.flatMap { case (w, i) =>
val clock = portToExpression(w.src.clock.get)
val address = portToExpression(w.src.address)
val enable = (w.src.chipEnable, w.src.writeEnable) match {
case (Some(en), Some(we)) =>
and(portToExpression(en), portToExpression(we))
case (Some(en), None) => portToExpression(en)
case (None, Some(we)) => portToExpression(we)
case (None, None) => zero // is it possible?
}
val mask = w.src.maskPort match {
case Some(m) => portToExpression(m)
case None => one
}
val data = memPortField(mem, s"W_$i", "data")
val write = portToExpression(w.src.input.get)
Seq(
Connect(NoInfo, memPortField(mem, s"W_$i", "clk"), clock),
Connect(NoInfo, memPortField(mem, s"W_$i", "addr"), address),
Connect(NoInfo, memPortField(mem, s"W_$i", "en"), enable),
Connect(NoInfo, memPortField(mem, s"W_$i", "mask"), mask),
Connect(NoInfo, data, write)
)
}
val readwriteConnects = real_macro.readwriters.zipWithIndex.flatMap { case (rw, i) =>
val clock = portToExpression(rw.src.clock.get)
val address = portToExpression(rw.src.address)
val wmode = rw.src.writeEnable match {
case Some(we) => portToExpression(we)
case None => zero // is it possible?
}
val wmask = rw.src.maskPort match {
case Some(wm) => portToExpression(wm)
case None => one
}
val enable = (rw.src.chipEnable, rw.src.readEnable) match {
case (Some(en), Some(re)) =>
and(portToExpression(en), or(portToExpression(re), wmode))
case (Some(en), None) => portToExpression(en)
case (None, Some(re)) => or(portToExpression(re), wmode)
case (None, None) => one
}
val wdata = memPortField(mem, s"RW_$i", "wdata")
val rdata = memPortField(mem, s"RW_$i", "rdata")
val write = portToExpression(rw.src.input.get)
val read = rdata
Seq(
Connect(NoInfo, memPortField(mem, s"RW_$i", "clk"), clock),
Connect(NoInfo, memPortField(mem, s"RW_$i", "addr"), address),
Connect(NoInfo, memPortField(mem, s"RW_$i", "en"), enable),
Connect(NoInfo, memPortField(mem, s"RW_$i", "wmode"), wmode),
Connect(NoInfo, memPortField(mem, s"RW_$i", "wmask"), wmask),
Connect(NoInfo, WRef(rw.src.output.get.name), read),
Connect(NoInfo, wdata, write)
)
}
extraMods.append(real_macro.module(Block(mem +: (readConnects ++ writeConnects ++ readwriteConnects))))
real_mod
}
}).toMap
def run(c: Circuit): Circuit = {
if (!synflops) c
else c.copy(modules = (c.modules.map(m => libMods.getOrElse(m.name, m))) ++ extraMods)
}
}