diff options
| author | Donggyu | 2016-09-25 15:27:23 -0700 |
|---|---|---|
| committer | GitHub | 2016-09-25 15:27:23 -0700 |
| commit | 7c4fa71a062f0c18a3af13c9e8853fdec2818da9 (patch) | |
| tree | d08bd63808f505e09a35d68c7997722e62b64fea | |
| parent | 744ea401553cabfb31c7cc32aecfd8ca2764d1b8 (diff) | |
| parent | 350b0d5249c33880f867f41d4e8a0d6ffb87423f (diff) | |
Merge pull request #260 from ucb-bar/mem_latency_pipes
Mem latency pipes
| -rw-r--r-- | src/main/scala/firrtl/Emitter.scala | 251 | ||||
| -rw-r--r-- | src/main/scala/firrtl/LoweringCompilers.scala | 2 | ||||
| -rw-r--r-- | src/main/scala/firrtl/passes/VerilogMemDelays.scala | 184 |
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)) +} |
