aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/Emitter.scala
diff options
context:
space:
mode:
authorJack Koenig2019-02-14 15:08:35 -0800
committerGitHub2019-02-14 15:08:35 -0800
commit2272044c6ab46b5148c39c124e66e1a8e9073a24 (patch)
tree83ad2141b1a3c54707dd9b33073f9217b0ae16c8 /src/main/scala/firrtl/Emitter.scala
parentd487b4cb6726e7e8d1a18f894021652594125221 (diff)
Asynchronous Reset (#1011)
Fixes #219 * Adds AsyncResetType (similar to ClockType) * Registers with reset signal of type AsyncResetType are async reset registers * Registers with async reset can only be reset to literal values * Add initialization logic for async reset registers
Diffstat (limited to 'src/main/scala/firrtl/Emitter.scala')
-rw-r--r--src/main/scala/firrtl/Emitter.scala103
1 files changed, 71 insertions, 32 deletions
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
index 8049e33c..edbe9df6 100644
--- a/src/main/scala/firrtl/Emitter.scala
+++ b/src/main/scala/firrtl/Emitter.scala
@@ -156,7 +156,7 @@ class VerilogEmitter extends SeqTransform with Emitter {
case (_: UIntType | _: SIntType | _: AnalogType) =>
val wx = bitWidth(tpe) - 1
if (wx > 0) s"[$wx:0]" else ""
- case ClockType => ""
+ case ClockType | AsyncResetType => ""
case _ => throwInternalError(s"trying to write unsupported type in the Verilog Emitter: $tpe")
}
def emit(x: Any)(implicit w: Writer) { emit(x, 0) }
@@ -297,6 +297,7 @@ class VerilogEmitter extends SeqTransform with Emitter {
case AsUInt => Seq("$unsigned(", a0, ")")
case AsSInt => Seq("$signed(", a0, ")")
case AsClock => Seq(a0)
+ case AsAsyncReset => Seq(a0)
case Dshlw => Seq(cast(a0), " << ", a1)
case Dshl => Seq(cast(a0), " << ", a1)
case Dshr => doprim.tpe match {
@@ -412,8 +413,23 @@ class VerilogEmitter extends SeqTransform with Emitter {
val assigns = ArrayBuffer[Seq[Any]]()
val attachSynAssigns = ArrayBuffer.empty[Seq[Any]]
val attachAliases = ArrayBuffer.empty[Seq[Any]]
- val at_clock = mutable.LinkedHashMap[Expression, ArrayBuffer[Seq[Any]]]()
+ // No (aka synchronous) always blocks, keyed by clock
+ val noResetAlwaysBlocks = mutable.LinkedHashMap[Expression, ArrayBuffer[Seq[Any]]]()
+ // One always block per async reset register, (Clock, Reset, Content)
+ // An alternative approach is to have one always block per combination of clock and async reset,
+ // but Formality doesn't allow more than 1 statement inside async reset always blocks
+ val asyncResetAlwaysBlocks = mutable.ArrayBuffer[(Expression, Expression, Seq[Any])]()
val initials = ArrayBuffer[Seq[Any]]()
+ // In Verilog, async reset registers are expressed using always blocks of the form:
+ // always @(posedge clock or posedge reset) begin
+ // if (reset) ...
+ // There is a fundamental mismatch between this representation which treats async reset
+ // registers as edge-triggered when in reality they are level-triggered.
+ // This can result in silicon-simulation mismatch in the case where async reset is held high
+ // upon power on with no clock, then async reset is dropped before the clock starts. In this
+ // circumstance, the async reset register will be randomized in simulation instead of being
+ // reset. To fix this, we need extra initial block logic for async reset registers
+ val asyncInitials = ArrayBuffer[Seq[Any]]()
val simulates = ArrayBuffer[Seq[Any]]()
def declare(b: String, n: String, t: Type, info: Info) = t match {
@@ -443,12 +459,13 @@ class VerilogEmitter extends SeqTransform with Emitter {
assigns += Seq("`endif // RANDOMIZE_INVALID_ASSIGN")
}
- def regUpdate(r: Expression, clk: Expression) = {
+ def regUpdate(r: Expression, clk: Expression, reset: Expression, init: Expression) = {
def addUpdate(expr: Expression, tabs: String): Seq[Seq[Any]] = {
if (weq(expr, r)) Nil // Don't bother emitting connection of register to itself
else expr match {
case m: Mux =>
if (m.tpe == ClockType) throw EmitterException("Cannot emit clock muxes directly")
+ if (m.tpe == AsyncResetType) throw EmitterException("Cannot emit async reset muxes directly")
def ifStatement = Seq(tabs, "if (", m.cond, ") begin")
@@ -471,17 +488,23 @@ class VerilogEmitter extends SeqTransform with Emitter {
case e => Seq(Seq(tabs, r, " <= ", e, ";"))
}
}
-
- at_clock.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]()) ++= addUpdate(netlist(r), "")
+ if (weq(init, r)) { // Synchronous Reset
+ noResetAlwaysBlocks.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]()) ++= addUpdate(netlist(r), "")
+ } else { // Asynchronous Reset
+ assert(reset.tpe == AsyncResetType, "Error! Synchronous reset should have been removed!")
+ val tv = init
+ val fv = netlist(r)
+ asyncResetAlwaysBlocks += ((clk, reset, addUpdate(Mux(reset, tv, fv, mux_type_and_widths(tv, fv)), "")))
+ }
}
def update(e: Expression, value: Expression, clk: Expression, en: Expression, info: Info) = {
- if (!at_clock.contains(clk)) at_clock(clk) = ArrayBuffer[Seq[Any]]()
- if (weq(en, one)) at_clock(clk) += Seq(e, " <= ", value, ";")
+ val lines = noResetAlwaysBlocks.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]())
+ if (weq(en, one)) lines += Seq(e, " <= ", value, ";")
else {
- at_clock(clk) += Seq("if(", en, ") begin")
- at_clock(clk) += Seq(tab, e, " <= ", value, ";", info)
- at_clock(clk) += Seq("end")
+ lines += Seq("if(", en, ") begin")
+ lines += Seq(tab, e, " <= ", value, ";", info)
+ lines += Seq("end")
}
}
@@ -496,10 +519,17 @@ class VerilogEmitter extends SeqTransform with Emitter {
Seq(nx, "[", bitWidth(t) - 1, ":0]")
}
- def initialize(e: Expression) = {
+ def initialize(e: Expression, reset: Expression, init: Expression) = {
initials += Seq("`ifdef RANDOMIZE_REG_INIT")
initials += Seq(e, " = ", rand_string(e.tpe), ";")
initials += Seq("`endif // RANDOMIZE_REG_INIT")
+ reset.tpe match {
+ case AsyncResetType =>
+ asyncInitials += Seq("if (", reset, ") begin")
+ asyncInitials += Seq(tab, e, " = ", init, ";")
+ asyncInitials += Seq("end")
+ case _ => // do nothing
+ }
}
def initialize_mem(s: DefMemory) {
@@ -513,22 +543,22 @@ class VerilogEmitter extends SeqTransform with Emitter {
}
def simulate(clk: Expression, en: Expression, s: Seq[Any], cond: Option[String], info: Info) = {
- if (!at_clock.contains(clk)) at_clock(clk) = ArrayBuffer[Seq[Any]]()
- at_clock(clk) += Seq("`ifndef SYNTHESIS")
+ val lines = noResetAlwaysBlocks.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]())
+ lines += Seq("`ifndef SYNTHESIS")
if (cond.nonEmpty) {
- at_clock(clk) += Seq(s"`ifdef ${cond.get}")
- at_clock(clk) += Seq(tab, s"if (`${cond.get}) begin")
- at_clock(clk) += Seq("`endif")
+ lines += Seq(s"`ifdef ${cond.get}")
+ lines += Seq(tab, s"if (`${cond.get}) begin")
+ lines += Seq("`endif")
}
- at_clock(clk) += Seq(tab, tab, "if (", en, ") begin")
- at_clock(clk) += Seq(tab, tab, tab, s, info)
- at_clock(clk) += Seq(tab, tab, "end")
+ lines += Seq(tab, tab, "if (", en, ") begin")
+ lines += Seq(tab, tab, tab, s, info)
+ lines += Seq(tab, tab, "end")
if (cond.nonEmpty) {
- at_clock(clk) += Seq(s"`ifdef ${cond.get}")
- at_clock(clk) += Seq(tab, "end")
- at_clock(clk) += Seq("`endif")
+ lines += Seq(s"`ifdef ${cond.get}")
+ lines += Seq(tab, "end")
+ lines += Seq("`endif")
}
- at_clock(clk) += Seq("`endif // SYNTHESIS")
+ lines += Seq("`endif // SYNTHESIS")
}
def stop(ret: Int): Seq[Any] = Seq(if (ret == 0) "$finish;" else "$fatal;")
@@ -614,8 +644,8 @@ class VerilogEmitter extends SeqTransform with Emitter {
case sx: DefRegister =>
declare("reg", sx.name, sx.tpe, sx.info)
val e = wref(sx.name, sx.tpe)
- regUpdate(e, sx.clock)
- initialize(e)
+ regUpdate(e, sx.clock, sx.reset, sx.init)
+ initialize(e, sx.reset, sx.init)
case sx: DefNode =>
declare("wire", sx.name, sx.value.tpe, sx.info)
assign(WRef(sx.name, sx.value.tpe, NodeKind, MALE), sx.value, sx.info)
@@ -757,9 +787,11 @@ class VerilogEmitter extends SeqTransform with Emitter {
emit(Seq("`ifndef RANDOM"))
emit(Seq("`define RANDOM $random"))
emit(Seq("`endif"))
- emit(Seq("`ifdef RANDOMIZE"))
+ emit(Seq("`ifdef RANDOMIZE_MEM_INIT"))
emit(Seq(" integer initvar;"))
- emit(Seq(" initial begin"))
+ emit(Seq("`endif"))
+ emit(Seq("initial begin"))
+ emit(Seq(" `ifdef RANDOMIZE"))
emit(Seq(" `ifdef INIT_RANDOM"))
emit(Seq(" `INIT_RANDOM"))
emit(Seq(" `endif"))
@@ -775,13 +807,20 @@ class VerilogEmitter extends SeqTransform with Emitter {
emit(Seq(" `endif"))
emit(Seq(" `endif"))
for (x <- initials) emit(Seq(tab, x))
- emit(Seq(" end"))
- emit(Seq("`endif // RANDOMIZE"))
+ emit(Seq(" `endif // RANDOMIZE"))
+ for (x <- asyncInitials) emit(Seq(tab, x))
+ emit(Seq("end"))
+ }
+
+ for ((clk, content) <- noResetAlwaysBlocks if content.nonEmpty) {
+ emit(Seq(tab, "always @(posedge ", clk, ") begin"))
+ for (line <- content) emit(Seq(tab, tab, line))
+ emit(Seq(tab, "end"))
}
- for (clk_stream <- at_clock if clk_stream._2.nonEmpty) {
- emit(Seq(tab, "always @(posedge ", clk_stream._1, ") begin"))
- for (x <- clk_stream._2) emit(Seq(tab, tab, x))
+ for ((clk, reset, content) <- asyncResetAlwaysBlocks if content.nonEmpty) {
+ emit(Seq(tab, "always @(posedge ", clk, " or posedge ", reset, ") begin"))
+ for (line <- content) emit(Seq(tab, tab, line))
emit(Seq(tab, "end"))
}
emit(Seq("endmodule"))