Files
chipyard/tapeout/src/main/scala/transforms/macros/SynFlops.scala
2017-10-03 11:56:30 -07:00

111 lines
4.2 KiB
Scala

// See LICENSE for license details.
package barstools.tapeout.transforms.macros
import firrtl._
import firrtl.ir._
import firrtl.Utils._
import firrtl.passes.MemPortUtils.{memPortField, memType}
import Utils._
class SynFlopsPass(synflops: Boolean, libs: Seq[Macro]) extends firrtl.passes.Pass {
lazy val libMods = (libs map { lib => lib.src.name -> {
val dataType = (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))
case Some(gran) => VectorType(UIntType(IntWidth(gran)), (lib.src.width / gran).toInt)
}
val mem = DefMemory(
NoInfo,
"ram",
dataType,
lib.src.depth,
1, // writeLatency
0, // readLatency
(lib.readers ++ lib.readwriters).indices map (i => s"R_$i"),
(lib.writers ++ lib.readwriters).indices map (i => s"W_$i"),
Nil
)
val readConnects = (lib.readers ++ lib.readwriters).zipWithIndex flatMap { case (r, i) =>
val clock = portToExpression(r.src.clock)
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 = (dataType: @unchecked) match {
case VectorType(tpe, size) => cat(((0 until size) map (k =>
WSubIndex(data, k, tpe, UNKNOWNGENDER))).reverse)
case _: UIntType => data
}
val addrReg = WRef(s"R_${i}_addr_reg", r.addrType, RegKind)
Seq(
DefRegister(NoInfo, addrReg.name, r.addrType, clock, zero, addrReg),
Connect(NoInfo, memPortField(mem, s"R_$i", "clk"), clock),
Connect(NoInfo, memPortField(mem, s"R_$i", "addr"), addrReg),
Connect(NoInfo, memPortField(mem, s"R_$i", "en"), enable),
Connect(NoInfo, WRef(r.src.output.get.name), read),
Connect(NoInfo, addrReg, Mux(enable, address, addrReg, UnknownType))
)
}
val writeConnects = (lib.writers ++ lib.readwriters).zipWithIndex flatMap { case (w, i) =>
val clock = portToExpression(w.src.clock)
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 = memPortField(mem, s"W_$i", "mask")
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)
) ++ (dataType match {
case VectorType(tpe, size) =>
val width = bitWidth(tpe).toInt
((0 until size) map (k =>
Connect(NoInfo, WSubIndex(data, k, tpe, UNKNOWNGENDER),
bits(write, (k + 1) * width - 1, k * width)))) ++
((0 until size) map (k =>
Connect(NoInfo, WSubIndex(mask, k, BoolType, UNKNOWNGENDER),
bits(WRef(w.src.maskPort.get.name), k))))
case _: UIntType =>
Seq(Connect(NoInfo, data, write), Connect(NoInfo, mask, one))
})
}
lib.module(Block(mem +: (readConnects ++ writeConnects)))
}}).toMap
def run(c: Circuit): Circuit = {
if (!synflops) c
else {
val circuit = c.copy(modules = (c.modules map (m => libMods getOrElse (m.name, m))))
// print(circuit.serialize)
circuit
}
}
}