aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/Emitter.scala
diff options
context:
space:
mode:
authorDonggyu Kim2016-08-31 20:43:06 -0700
committerDonggyu Kim2016-09-25 15:02:40 -0700
commit350b0d5249c33880f867f41d4e8a0d6ffb87423f (patch)
treed08bd63808f505e09a35d68c7997722e62b64fea /src/main/scala/firrtl/Emitter.scala
parent82f89488cacf5826607b0e17b0d29af7c7627c27 (diff)
offload latency pipe generation for memories from VerilogEmitter
discussed with @azidar
Diffstat (limited to 'src/main/scala/firrtl/Emitter.scala')
-rw-r--r--src/main/scala/firrtl/Emitter.scala207
1 files changed, 60 insertions, 147 deletions
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
index adc9c132..0269a4fc 100644
--- a/src/main/scala/firrtl/Emitter.scala
+++ b/src/main/scala/firrtl/Emitter.scala
@@ -35,16 +35,17 @@ import scala.collection.mutable
import scala.sys.process._
import scala.io.Source
-import Utils._
import firrtl.ir._
import firrtl.passes._
import firrtl.Mappers._
import firrtl.PrimOps._
import firrtl.WrappedExpression._
+import Utils._
+import MemPortUtils.{memPortField, memType}
// Datastructures
-import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
+import scala.collection.mutable.{ArrayBuffer, LinkedHashMap, HashSet}
-class EmitterException(message: String) extends PassException(message)
+case class EmitterException(message: String) extends PassException(message)
trait Emitter extends LazyLogging {
def run(c: Circuit, w: Writer)
@@ -72,19 +73,6 @@ class VerilogEmitter extends Emitter {
else if (e2 == we(one)) e1.e1
else DoPrim(And, Seq(e1.e1, e2.e1), Nil, UIntType(IntWidth(1)))
}
- def OR(e1: WrappedExpression, e2: WrappedExpression): Expression = {
- if (e1 == e2) e1.e1
- else if ((e1 == we(one)) | (e2 == we(one))) one
- else if (e1 == we(zero)) e2.e1
- else if (e2 == we(zero)) e1.e1
- else DoPrim(Or, Seq(e1.e1, e2.e1), Nil, UIntType(IntWidth(1)))
- }
- def NOT(e: WrappedExpression): Expression = {
- if (e == we(one)) zero
- else if (e == we(zero)) one
- else DoPrim(Eq, Seq(e.e1, zero), Nil, UIntType(IntWidth(1)))
- }
-
def wref(n: String, t: Type) = WRef(n, t, ExpKind, UNKNOWNGENDER)
def remove_root(ex: Expression): Expression = ex match {
case ex: WSubField => ex.exp match {
@@ -171,7 +159,7 @@ class VerilogEmitter extends Emitter {
def checkArgumentLegality(e: Expression) = e match {
case _: UIntLiteral | _: SIntLiteral | _: WRef | _: WSubField =>
- case _ => throw new EmitterException(s"Can't emit ${e.getClass.getName} as PrimOp argument")
+ case _ => throw EmitterException(s"Can't emit ${e.getClass.getName} as PrimOp argument")
}
doprim.args foreach checkArgumentLegality
doprim.op match {
@@ -247,10 +235,15 @@ class VerilogEmitter extends Emitter {
def emit_verilog(m: Module)(implicit w: Writer): DefModule = {
val netlist = mutable.LinkedHashMap[WrappedExpression, Expression]()
+ val addrRegs = mutable.HashSet[WrappedExpression]()
val namespace = Namespace(m)
def build_netlist(s: Statement): Statement = s map build_netlist match {
case (s: Connect) =>
netlist(s.loc) = s.expr
+ (kind(s.loc), kind(s.expr)) match {
+ case (MemKind, RegKind) => addrRegs += s.expr
+ case _ =>
+ }
s
case (s: IsInvalid) =>
netlist(s.expr) = wref(namespace.newTemp, s.expr.tpe)
@@ -269,14 +262,14 @@ class VerilogEmitter extends Emitter {
val at_clock = mutable.LinkedHashMap[Expression,ArrayBuffer[Seq[Any]]]()
val initials = ArrayBuffer[Seq[Any]]()
val simulates = ArrayBuffer[Seq[Any]]()
- def declare (b: String, n: String, t: Type) = t match {
+ def declare(b: String, n: String, t: Type) = t match {
case (t: VectorType) =>
declares += Seq(b, " ", t.tpe, " ", n, " [0:", t.size - 1, "];")
case (t) =>
declares += Seq(b, " ", t, " ", n,";")
}
- def assign (e: Expression, value: Expression) {
- assigns += Seq("assign ", e, " = ", value, ";")
+ def assign(e: Expression, value: Expression) {
+ assigns += Seq("assign ", e, " = ", value, ";")
}
// In simulation, assign garbage under a predicate
@@ -308,9 +301,12 @@ class VerilogEmitter extends Emitter {
def addUpdate(e: Expression, tabs: String): Seq[Seq[Any]] = {
if (weq(e, r)) Nil else netlist getOrElse (e, e) match {
- case m: Mux if canFlatten(m) => {
+ case m: Mux if canFlatten(m) =>
val ifStatement = Seq(tabs, "if (", m.cond, ") begin")
- val trueCase = addUpdate(m.tval, tabs + tab)
+ val trueCase =
+ // Don't generate mux trees for mem addr pipes
+ if (addrRegs(r)) Seq(Seq(tabs + tab, r, " <= ", m.tval, ";"))
+ else addUpdate(m.tval, tabs + tab)
val elseStatement = Seq(tabs, "end else begin")
val ifNotStatement = Seq(tabs, "if (!(", m.cond, ")) begin")
val falseCase = addUpdate(m.fval, tabs + tab)
@@ -324,7 +320,6 @@ class VerilogEmitter extends Emitter {
case (false, true) =>
ifNotStatement +: falseCase :+ endStatement
}
- }
case _ => Seq(Seq(tabs, r, " <= ", e, ";"))
}
}
@@ -377,18 +372,18 @@ class VerilogEmitter extends Emitter {
}
def instantiate(n: String,m: String, es: Seq[Expression]) {
- instdeclares += Seq(m, " ", n, " (")
- es.zipWithIndex foreach {case (e, i) =>
- val s = Seq(tab, ".", remove_root(e), "(", LowerTypes.loweredName(e), ")")
- if (i != es.size - 1) instdeclares += Seq(s, ",")
- else instdeclares += s
- }
- instdeclares += Seq(");")
- es foreach { e =>
- declare("wire",LowerTypes.loweredName(e), e.tpe)
- val ex = WRef(LowerTypes.loweredName(e), e.tpe, kind(e), gender(e))
- if (gender(e) == FEMALE) assign(ex,netlist(e))
- }
+ instdeclares += Seq(m, " ", n, " (")
+ es.zipWithIndex foreach {case (e, i) =>
+ val s = Seq(tab, ".", remove_root(e), "(", LowerTypes.loweredName(e), ")")
+ if (i != es.size - 1) instdeclares += Seq(s, ",")
+ else instdeclares += s
+ }
+ instdeclares += Seq(");")
+ es foreach { e =>
+ declare("wire",LowerTypes.loweredName(e), e.tpe)
+ val ex = WRef(LowerTypes.loweredName(e), e.tpe, kind(e), gender(e))
+ if (gender(e) == FEMALE) assign(ex,netlist(e))
+ }
}
def simulate(clk: Expression, en: Expression, s: Seq[Any], cond: Option[String]) {
@@ -419,17 +414,6 @@ class VerilogEmitter extends Emitter {
Seq("$fwrite(32'h80000002,", strx, ");")
}
- def delay(e: Expression, n: Int, clk: Expression): Expression = {
- ((0 until n) foldLeft e){(ex, i) =>
- val name = namespace.newTemp
- declare("reg", name, e.tpe)
- val exx = wref(name, e.tpe)
- initialize(exx)
- update(exx, ex, clk, one)
- exx
- }
- }
-
def build_ports(): Unit = portdefs ++= m.ports.zipWithIndex map {
case (p, i) => p.direction match {
case Input =>
@@ -443,7 +427,7 @@ class VerilogEmitter extends Emitter {
def build_streams(s: Statement): Statement = s map build_streams match {
case (s: DefWire) =>
- declare("wire",s.name, s.tpe)
+ declare("wire", s.name, s.tpe)
val e = wref(s.name, s.tpe)
assign(e,netlist(e))
s
@@ -474,57 +458,43 @@ class VerilogEmitter extends Emitter {
instantiate(s.name, s.module, es)
s
case (s: DefMemory) =>
- val mem = WRef(s.name, MemPortUtils.memType(s), MemKind, UNKNOWNGENDER)
- def mem_exp (p: String, f: String) = {
- val t1 = field_type(mem.tpe, p)
- val t2 = field_type(t1, f)
- val x = WSubField(mem, p, t1, UNKNOWNGENDER)
- WSubField(x, f, t2, UNKNOWNGENDER)
- }
-
declare("reg", s.name, VectorType(s.dataType, s.depth))
initialize_mem(s)
+ if (s.readLatency != 0 || s.writeLatency != 1)
+ throw EmitterException("All memories should be transformed into " +
+ "blackboxes or combinational by previous passses")
for (r <- s.readers) {
- val data = mem_exp(r, "data")
- val addr = mem_exp(r, "addr")
- val en = mem_exp(r, "en")
+ val data = memPortField(s, r, "data")
+ val addr = memPortField(s, r, "addr")
+ val en = memPortField(s, r, "en")
// Ports should share an always@posedge, so can't have intermediary wire
- val clk = netlist(mem_exp(r, "clk"))
+ val clk = netlist(memPortField(s, r, "clk"))
declare("wire", LowerTypes.loweredName(data), data.tpe)
declare("wire", LowerTypes.loweredName(addr), addr.tpe)
- declare("wire", LowerTypes.loweredName(en), en.tpe)
+ // declare("wire", LowerTypes.loweredName(en), en.tpe)
//; Read port
assign(addr, netlist(addr)) //;Connects value to m.r.addr
- assign(en, netlist(en)) //;Connects value to m.r.en
- val addr_pipe = delay(addr,s.readLatency-1,clk)
- val en_pipe = if (weq(en,one)) one else delay(en,s.readLatency-1,clk)
- val addrx = if (s.readLatency > 0) {
- val name = namespace.newTemp
- val ref = wref(name, addr.tpe)
- declare("reg", name, addr.tpe)
- initialize(ref)
- update(ref,addr_pipe,clk,en_pipe)
- ref
- } else addr
- val mem_port = WSubAccess(mem,addrx,s.dataType,UNKNOWNGENDER)
+ // assign(en, netlist(en)) //;Connects value to m.r.en
+ val mem = WRef(s.name, memType(s), MemKind, UNKNOWNGENDER)
+ val memPort = WSubAccess(mem, addr, s.dataType, UNKNOWNGENDER)
val depthValue = UIntLiteral(s.depth, IntWidth(BigInt(s.depth).bitLength))
- val garbageGuard = DoPrim(Geq, Seq(addrx, depthValue), Seq(), UnknownType)
+ val garbageGuard = DoPrim(Geq, Seq(addr, depthValue), Seq(), UnknownType)
if ((s.depth & (s.depth - 1)) == 0)
- assign(data, mem_port)
+ assign(data, memPort)
else
- garbageAssign(data, mem_port, garbageGuard)
+ garbageAssign(data, memPort, garbageGuard)
}
for (w <- s.writers) {
- val data = mem_exp(w, "data")
- val addr = mem_exp(w, "addr")
- val mask = mem_exp(w, "mask")
- val en = mem_exp(w, "en")
+ val data = memPortField(s, w, "data")
+ val addr = memPortField(s, w, "addr")
+ val mask = memPortField(s, w, "mask")
+ val en = memPortField(s, w, "en")
//Ports should share an always@posedge, so can't have intermediary wire
- val clk = netlist(mem_exp(w, "clk"))
+ val clk = netlist(memPortField(s, w, "clk"))
declare("wire", LowerTypes.loweredName(data), data.tpe)
declare("wire", LowerTypes.loweredName(addr), addr.tpe)
@@ -532,76 +502,19 @@ class VerilogEmitter extends Emitter {
declare("wire", LowerTypes.loweredName(en), en.tpe)
//; Write port
- assign(data,netlist(data))
- assign(addr,netlist(addr))
- assign(mask,netlist(mask))
- assign(en,netlist(en))
-
- val datax = delay(data, s.writeLatency - 1, clk)
- val addrx = delay(addr, s.writeLatency - 1, clk)
- val maskx = delay(mask, s.writeLatency - 1, clk)
- val enx = delay(en, s.writeLatency - 1, clk)
- val mem_port = WSubAccess(mem, addrx, s.dataType, UNKNOWNGENDER)
- update(mem_port, datax, clk, AND(enx, maskx))
- }
-
- for (rw <- s.readwriters) {
- val wmode = mem_exp(rw, "wmode")
- val rdata = mem_exp(rw, "rdata")
- val wdata = mem_exp(rw, "wdata")
- val wmask = mem_exp(rw, "wmask")
- val addr = mem_exp(rw, "addr")
- val en = mem_exp(rw, "en")
- //Ports should share an always@posedge, so can't have intermediary wire
- val clk = netlist(mem_exp(rw, "clk"))
-
- declare("wire", LowerTypes.loweredName(wmode), wmode.tpe)
- declare("wire", LowerTypes.loweredName(rdata), rdata.tpe)
- declare("wire", LowerTypes.loweredName(wdata), wdata.tpe)
- declare("wire", LowerTypes.loweredName(wmask), wmask.tpe)
- declare("wire", LowerTypes.loweredName(addr), addr.tpe)
- declare("wire", LowerTypes.loweredName(en), en.tpe)
-
- //; Assigned to lowered wires of each
+ assign(data, netlist(data))
assign(addr, netlist(addr))
- assign(wdata, netlist(wdata))
- assign(addr, netlist(addr))
- assign(wmask, netlist(wmask))
+ assign(mask, netlist(mask))
assign(en, netlist(en))
- assign(wmode, netlist(wmode))
-
- //; Delay new signals by latency
- val raddrx = if (s.readLatency > 0) delay(addr, s.readLatency - 1, clk) else addr
- val waddrx = delay(addr,s.writeLatency - 1,clk)
- val enx = delay(en,s.writeLatency - 1,clk)
- val wmodex = delay(wmode,s.writeLatency - 1,clk)
- val wdatax = delay(wdata,s.writeLatency - 1,clk)
- val wmaskx = delay(wmask,s.writeLatency - 1,clk)
-
- val raddrxx = if (s.readLatency > 0) {
- val name = namespace.newTemp
- val ref = wref(name, raddrx.tpe)
- declare("reg", name, raddrx.tpe)
- initialize(ref)
- ref
- } else addr
- val rmem_port = WSubAccess(mem, raddrxx, s.dataType, UNKNOWNGENDER)
- assign(rdata, rmem_port)
- val wmem_port = WSubAccess(mem, waddrx, s.dataType, UNKNOWNGENDER)
-
- def declare_and_assign(exp: Expression) = {
- val name = namespace.newTemp
- val ref = wref(name, exp.tpe)
- declare("wire", name, exp.tpe)
- assign(ref, exp)
- ref
- }
- val ren = declare_and_assign(NOT(wmodex))
- val wen = declare_and_assign(AND(wmodex, wmaskx))
- if (s.readLatency > 0)
- update(raddrxx, raddrx, clk, AND(enx, ren))
- update(wmem_port, wdatax, clk, AND(enx, wen))
+
+ val mem = WRef(s.name, memType(s), MemKind, UNKNOWNGENDER)
+ val memPort = WSubAccess(mem, addr, s.dataType, UNKNOWNGENDER)
+ update(memPort, data, clk, AND(en, mask))
}
+
+ if (s.readwriters.nonEmpty)
+ throw EmitterException("All readwrite ports should be transformed into " +
+ "read & write ports by previous passes")
s
case s => s
}