aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDonggyu2016-09-25 15:27:23 -0700
committerGitHub2016-09-25 15:27:23 -0700
commit7c4fa71a062f0c18a3af13c9e8853fdec2818da9 (patch)
treed08bd63808f505e09a35d68c7997722e62b64fea
parent744ea401553cabfb31c7cc32aecfd8ca2764d1b8 (diff)
parent350b0d5249c33880f867f41d4e8a0d6ffb87423f (diff)
Merge pull request #260 from ucb-bar/mem_latency_pipes
Mem latency pipes
-rw-r--r--src/main/scala/firrtl/Emitter.scala251
-rw-r--r--src/main/scala/firrtl/LoweringCompilers.scala2
-rw-r--r--src/main/scala/firrtl/passes/VerilogMemDelays.scala184
3 files changed, 270 insertions, 167 deletions
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
index 1e7c3103..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,18 +235,19 @@ class VerilogEmitter extends Emitter {
def emit_verilog(m: Module)(implicit w: Writer): DefModule = {
val netlist = mutable.LinkedHashMap[WrappedExpression, Expression]()
- val simlist = ArrayBuffer[Statement]()
+ 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)
s
- case (s: Conditionally) =>
- simlist += s
- s
case (s: DefNode) =>
val e = WRef(s.name, s.value.tpe, NodeKind, MALE)
netlist(e) = s.value
@@ -273,23 +262,23 @@ 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
def garbageAssign(e: Expression, syn: Expression, garbageCond: Expression) = {
- assigns += Seq("`ifndef RANDOMIZE_GARBAGE_ASSIGN")
- assigns += Seq("assign ", e, " = ", syn, ";")
- assigns += Seq("`else")
- assigns += Seq("assign ", e, " = ", garbageCond, " ? ", rand_string(syn.tpe), " : ", syn, ";")
- assigns += Seq("`endif")
+ assigns += Seq("`ifndef RANDOMIZE_GARBAGE_ASSIGN")
+ assigns += Seq("assign ", e, " = ", syn, ";")
+ assigns += Seq("`else")
+ assigns += Seq("assign ", e, " = ", garbageCond, " ? ", rand_string(syn.tpe), " : ", syn, ";")
+ assigns += Seq("`endif")
}
def invalidAssign(e: Expression) = {
assigns += Seq("`ifdef RANDOMIZE_INVALID_ASSIGN")
@@ -311,19 +300,26 @@ class VerilogEmitter extends Emitter {
}
def addUpdate(e: Expression, tabs: String): Seq[Seq[Any]] = {
- netlist.getOrElse(e, e) match {
+ if (weq(e, r)) Nil else netlist getOrElse (e, e) match {
case m: Mux if canFlatten(m) =>
- val ifStatement = Seq(tabs, "if(", m.cond, ") begin")
- val trueCase = addUpdate(m.tval, tabs + tab)
+ val ifStatement = Seq(tabs, "if (", m.cond, ") begin")
+ 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)
val endStatement = Seq(tabs, "end")
- if (falseCase.isEmpty)
- ifStatement +: trueCase :+ endStatement
- else
- ifStatement +: trueCase ++: elseStatement +: falseCase :+ endStatement
- case _ if (weq(e, r)) => Seq()
+ ((trueCase.nonEmpty, falseCase.nonEmpty): @ unchecked) match {
+ case (true, true) =>
+ ifStatement +: trueCase ++: elseStatement +: falseCase :+ endStatement
+ case (true, false) =>
+ ifStatement +: trueCase :+ endStatement
+ case (false, true) =>
+ ifNotStatement +: falseCase :+ endStatement
+ }
case _ => Seq(Seq(tabs, r, " <= ", e, ";"))
}
}
@@ -331,7 +327,10 @@ class VerilogEmitter extends Emitter {
at_clock.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]()) ++= {
val tv = init
val fv = netlist(r)
- addUpdate(Mux(reset, tv, fv, mux_type_and_widths(tv, fv)), "")
+ if (weq(tv, r))
+ addUpdate(fv, "")
+ else
+ addUpdate(Mux(reset, tv, fv, mux_type_and_widths(tv, fv)), "")
}
}
@@ -373,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]) {
@@ -415,32 +414,21 @@ 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 = m.ports.zipWithIndex foreach {case (p, i) =>
- p.direction match {
+ def build_ports(): Unit = portdefs ++= m.ports.zipWithIndex map {
+ case (p, i) => p.direction match {
case Input =>
- portdefs += Seq(p.direction, " ", p.tpe, " ", p.name)
+ Seq(p.direction, " ", p.tpe, " ", p.name)
case Output =>
- portdefs += Seq(p.direction, " ", p.tpe, " ", p.name)
val ex = WRef(p.name, p.tpe, PortKind, FEMALE)
assign(ex, netlist(ex))
+ Seq(p.direction, " ", p.tpe, " ", p.name)
}
}
def build_streams(s: Statement): Statement = s map build_streams match {
case (s: DefWire) =>
- declare("wire",s.name,s.tpe)
- val e = wref(s.name,s.tpe)
+ declare("wire", s.name, s.tpe)
+ val e = wref(s.name, s.tpe)
assign(e,netlist(e))
s
case (s: DefRegister) =>
@@ -470,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)
@@ -528,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
}
diff --git a/src/main/scala/firrtl/LoweringCompilers.scala b/src/main/scala/firrtl/LoweringCompilers.scala
index cd77fa3e..c7b7f5dd 100644
--- a/src/main/scala/firrtl/LoweringCompilers.scala
+++ b/src/main/scala/firrtl/LoweringCompilers.scala
@@ -145,6 +145,8 @@ class EmitVerilogFromLowFirrtl(val writer: Writer) extends Transform with Simple
passes.ConstProp,
passes.Legalize,
passes.VerilogWrap,
+ passes.VerilogMemDelays,
+ passes.ConstProp,
passes.SplitExpressions,
passes.CommonSubexpressionElimination,
passes.DeadCodeElimination,
diff --git a/src/main/scala/firrtl/passes/VerilogMemDelays.scala b/src/main/scala/firrtl/passes/VerilogMemDelays.scala
new file mode 100644
index 00000000..99f5b071
--- /dev/null
+++ b/src/main/scala/firrtl/passes/VerilogMemDelays.scala
@@ -0,0 +1,184 @@
+/*
+Copyright (c) 2014 - 2016 The Regents of the University of
+California (Regents). All Rights Reserved. Redistribution and use in
+source and binary forms, with or without modification, are permitted
+provided that the following conditions are met:
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of the Regents nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION
+TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+*/
+
+package firrtl.passes
+
+import firrtl._
+import firrtl.ir._
+import firrtl.Utils._
+import firrtl.Mappers._
+import firrtl.PrimOps._
+import MemPortUtils._
+
+/** This pass generates delay reigsters for memories for verilog */
+object VerilogMemDelays extends Pass {
+ def name = "Verilog Memory Delays"
+ val ug = UNKNOWNGENDER
+ type Netlist = collection.mutable.HashMap[String, Expression]
+ implicit def expToString(e: Expression) = e.serialize
+ private def NOT(e: Expression) = DoPrim(Not, Seq(e), Nil, BoolType)
+ private def AND(e1: Expression, e2: Expression) = DoPrim(And, Seq(e1, e2), Nil, BoolType)
+
+ def buildNetlist(netlist: Netlist)(s: Statement): Statement = {
+ s match {
+ case Connect(_, loc, expr) => kind(loc) match {
+ case MemKind => netlist(loc) = expr
+ case _ =>
+ }
+ case _ =>
+ }
+ s map buildNetlist(netlist)
+ }
+
+ def memDelayStmt(
+ netlist: Netlist,
+ namespace: Namespace,
+ repl: Netlist)
+ (s: Statement): Statement = s map memDelayStmt(netlist, namespace, repl) match {
+ case s: DefMemory =>
+ val ports = (s.readers ++ s.writers).toSet
+ def newPortName(rw: String, p: String) = (for {
+ idx <- Stream from 0
+ newName = s"${rw}_${p}_${idx}"
+ if !ports(newName)
+ } yield newName).head
+ val rwMap = (s.readwriters map (rw =>
+ rw -> (newPortName(rw, "r"), newPortName(rw, "w")))).toMap
+ // 1. readwrite ports are split into read & write ports
+ // 2. memories are transformed into combinational
+ // because latency pipes are added for longer latencies
+ val mem = s copy (
+ readers = (s.readers ++ (s.readwriters map (rw => rwMap(rw)._1))),
+ writers = (s.writers ++ (s.readwriters map (rw => rwMap(rw)._2))),
+ readwriters = Nil, readLatency = 0, writeLatency = 1)
+ def pipe(e: Expression, // Expression to be piped
+ n: Int, // pipe depth
+ clk: Expression, // clock expression
+ cond: Expression // condition for pipes
+ ): (Expression, Seq[Statement]) = {
+ // returns
+ // 1) reference to the last pipe register
+ // 2) pipe registers and connects
+ val node = DefNode(NoInfo, namespace.newTemp, netlist(e))
+ val wref = WRef(node.name, e.tpe, NodeKind, MALE)
+ ((0 until n) foldLeft (wref, Seq[Statement](node))){case ((ex, stmts), i) =>
+ val name = namespace newName s"${LowerTypes.loweredName(e)}_pipe_$i"
+ val exx = WRef(name, e.tpe, RegKind, ug)
+ (exx, stmts ++ Seq(DefRegister(NoInfo, name, e.tpe, clk, zero, exx)) ++
+ (if (i < n - 1 && WrappedExpression.weq(cond, one)) Seq(Connect(NoInfo, exx, ex)) else {
+ val condn = namespace newName s"${LowerTypes.loweredName(e)}_en"
+ val condx = WRef(condn, BoolType, NodeKind, FEMALE)
+ Seq(DefNode(NoInfo, condn, cond),
+ Connect(NoInfo, condx, cond),
+ Connect(NoInfo, exx, Mux(condx, ex, exx, e.tpe)))
+ })
+ )
+ }
+ }
+ def readPortConnects(reader: String,
+ clk: Expression,
+ en: Expression,
+ addr: Expression) = Seq(
+ Connect(NoInfo, memPortField(mem, reader, "clk"), clk),
+ // connect latency pipes to read ports
+ Connect(NoInfo, memPortField(mem, reader, "en"), en),
+ Connect(NoInfo, memPortField(mem, reader, "addr"), addr)
+ )
+ def writePortConnects(writer: String,
+ clk: Expression,
+ en: Expression,
+ mask: Expression,
+ addr: Expression,
+ data: Expression) = Seq(
+ Connect(NoInfo, memPortField(mem, writer, "clk"), clk),
+ // connect latency pipes to write ports
+ Connect(NoInfo, memPortField(mem, writer, "en"), en),
+ Connect(NoInfo, memPortField(mem, writer, "mask"), mask),
+ Connect(NoInfo, memPortField(mem, writer, "addr"), addr),
+ Connect(NoInfo, memPortField(mem, writer, "data"), data)
+ )
+
+
+ Block(mem +: ((s.readers flatMap {reader =>
+ // generate latency pipes for read ports (enable & addr)
+ val clk = netlist(memPortField(s, reader, "clk"))
+ val (en, ss1) = pipe(memPortField(s, reader, "en"), s.readLatency - 1, clk, one)
+ val (addr, ss2) = pipe(memPortField(s, reader, "addr"), s.readLatency, clk, en)
+ ss1 ++ ss2 ++ readPortConnects(reader, clk, en, addr)
+ }) ++ (s.writers flatMap {writer =>
+ // generate latency pipes for write ports (enable, mask, addr, data)
+ val clk = netlist(memPortField(s, writer, "clk"))
+ val (en, ss1) = pipe(memPortField(s, writer, "en"), s.writeLatency - 1, clk, one)
+ val (mask, ss2) = pipe(memPortField(s, writer, "mask"), s.writeLatency - 1, clk, one)
+ val (addr, ss3) = pipe(memPortField(s, writer, "addr"), s.writeLatency - 1, clk, one)
+ val (data, ss4) = pipe(memPortField(s, writer, "data"), s.writeLatency - 1, clk, one)
+ ss1 ++ ss2 ++ ss3 ++ ss4 ++ writePortConnects(writer, clk, en, mask, addr, data)
+ }) ++ (s.readwriters flatMap {readwriter =>
+ val (reader, writer) = rwMap(readwriter)
+ val clk = netlist(memPortField(s, readwriter, "clk"))
+ // generate latency pipes for readwrite ports (enable, addr, wmode, wmask, wdata)
+ val (en, ss1) = pipe(memPortField(s, readwriter, "en"), s.readLatency - 1, clk, one)
+ val (wmode, ss2) = pipe(memPortField(s, readwriter, "wmode"), s.writeLatency - 1, clk, one)
+ val (wmask, ss3) = pipe(memPortField(s, readwriter, "wmask"), s.writeLatency - 1, clk, one)
+ val (wdata, ss4) = pipe(memPortField(s, readwriter, "wdata"), s.writeLatency - 1, clk, one)
+ val (raddr, ss5) = pipe(memPortField(s, readwriter, "addr"), s.readLatency, clk, AND(en, NOT(wmode)))
+ val (waddr, ss6) = pipe(memPortField(s, readwriter, "addr"), s.writeLatency - 1, clk, one)
+ repl(memPortField(s, readwriter, "rdata")) = memPortField(mem, reader, "data")
+ ss1 ++ ss2 ++ ss3 ++ ss4 ++ ss5 ++ ss6 ++
+ readPortConnects(reader, clk, en, raddr) ++
+ writePortConnects(writer, clk, AND(en, wmode), wmask, waddr, wdata)
+ })))
+ case s: Connect => kind(s.loc) match {
+ case MemKind => EmptyStmt
+ case _ => s
+ }
+ case s => s
+ }
+
+ def replaceExp(repl: Netlist)(e: Expression): Expression = e match {
+ case e: WSubField => repl get e match {
+ case Some(ex) => ex
+ case None => e
+ }
+ case e => e map replaceExp(repl)
+ }
+
+ def replaceStmt(repl: Netlist)(s: Statement): Statement =
+ s map replaceStmt(repl) map replaceExp(repl)
+
+ def memDelayMod(m: DefModule): DefModule = {
+ val netlist = new Netlist
+ val namespace = Namespace(m)
+ val repl = new Netlist
+ (m map buildNetlist(netlist)
+ map memDelayStmt(netlist, namespace, repl)
+ map replaceStmt(repl))
+ }
+
+ def run(c: Circuit): Circuit =
+ c copy (modules = (c.modules map memDelayMod))
+}