Skip to content
This repository has been archived by the owner on Aug 20, 2024. It is now read-only.

Commit

Permalink
Merge branch 'master' into zero-width-lit
Browse files Browse the repository at this point in the history
  • Loading branch information
azidar authored Feb 20, 2019
2 parents 6c4f0a5 + afdb780 commit fd3f0c1
Show file tree
Hide file tree
Showing 42 changed files with 943 additions and 221 deletions.
16 changes: 11 additions & 5 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@

enablePlugins(SiteScaladocPlugin)

enablePlugins(GhpagesPlugin)

git.remoteRepo := "[email protected]:freechipsproject/firrtl.git"

// Firrtl code

organization := "edu.berkeley.cs"
Expand Down Expand Up @@ -73,6 +69,8 @@ libraryDependencies += "net.jcazevedo" %% "moultingyaml" % "0.4.0"

libraryDependencies += "org.json4s" %% "json4s-native" % "3.6.1"

libraryDependencies += "org.apache.commons" % "commons-text" % "1.6"

// Java PB

enablePlugins(ProtobufPlugin)
Expand Down Expand Up @@ -109,7 +107,8 @@ javaSource in Antlr4 := (sourceManaged in Compile).value
publishMavenStyle := true
publishArtifact in Test := false
pomIncludeRepository := { x => false }
// Don't add 'scm' elements if we have a git.remoteRepo definition.
// Don't add 'scm' elements if we have a git.remoteRepo definition,
// but since we don't (with the removal of ghpages), add them in below.
pomExtra := <url>http://chisel.eecs.berkeley.edu/</url>
<licenses>
<license>
Expand All @@ -118,6 +117,10 @@ pomExtra := <url>http://chisel.eecs.berkeley.edu/</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<url>https://github.com/freechipsproject/firrtl.git</url>
<connection>scm:git:github.com/freechipsproject/firrtl.git</connection>
</scm>
<developers>
<developer>
<id>jackbackrack</id>
Expand Down Expand Up @@ -158,3 +161,6 @@ scalacOptions in Compile in doc ++= Seq(
"-doc-title", name.value,
"-doc-root-content", baseDirectory.value+"/root-doc.txt"
) ++ scalacOptionsVersion(scalaVersion.value)

fork := true
Test / testForkedParallel := true
2 changes: 0 additions & 2 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ resolvers += Classpaths.sbtPluginReleases

resolvers += "jgit-repo" at "http://download.eclipse.org/jgit/maven"

addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.2")

addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.3.1")

addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.7.0")
Expand Down
Binary file modified spec/spec.pdf
Binary file not shown.
22 changes: 17 additions & 5 deletions spec/spec.tex
Original file line number Diff line number Diff line change
Expand Up @@ -1614,19 +1614,31 @@ \subsection{Prefix Uniqueness} \label{prefix_unique}

As an example \verb|firetruck$y$z| shares a prefix with \verb|firetruck$y| and \verb|firetruck|, but does not share a prefix with \verb|fire|.

\section{The Lowered FIRRTL Form}
\section{The Lowered FIRRTL Forms}

The lowered FIRRTL form, LoFIRRTL, is a restricted subset of the FIRRTL language that omits many of the higher level constructs. All conformant FIRRTL compilers must provide a {\em lowering transformation} that transforms arbitrary FIRRTL circuits into equivalent LoFIRRTL circuits.
The lowered FIRRTL forms, MidFIRRTL and LoFIRRTL, are increasingly restrictive subsets of the FIRRTL language that omit many of the higher level constructs. All conformant FIRRTL compilers must provide a {\em lowering transformation} that transforms arbitrary FIRRTL circuits into equivalent LoFIRRTL circuits. However, there are no additional requirements related to accepting or producing MidFIRRTL, as the LoFIRRTL output of the lowering transformation will already be a legal subset of MidFIRRTL.

\subsection{MidFIRRTL}

A FIRRTL circuit is defined to be a valid MidFIRRTL circuit if it obeys the following restrictions:
\begin{itemize}
\item All widths must be explicitly defined.
\item The conditional statement is not used.
\item All components are connected to exactly once.
\end{itemize}

\subsection{LoFIRRTL}

A FIRRTL circuit is defined to be a valid LoFIRRTL circuit if it obeys the following restrictions:
\begin{itemize}
\item All components must be declared with a ground type and explicit widths.
\item The partial connect statement is not used.
\item All widths must be explicitly defined.
\item The conditional statement is not used.
\item All components are connected to exactly once.
\item All components must be declared with a ground type.
\item The partial connect statement is not used.
\end{itemize}

The additional restrictions give LoFIRRTL a direct correspondence to a circuit netlist.
The first three restrictions follow from the fact that any LoFIRRTL circuit is also a legal MidFIRRTL circuit. The additional restrictions give LoFIRRTL a direct correspondence to a circuit netlist.

Low level circuit transformations can be conveniently written by first lowering a circuit to its LoFIRRTL form, then operating on the restricted (and thus simpler) subset of constructs. Note that circuit transformations are still free to generate high level constructs as they can simply be lowered again.

Expand Down
2 changes: 1 addition & 1 deletion src/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FIRRTL licence terms

Copyright (c) 2014 - 2016 The Regents of the University of
Copyright (c) 2014 - 2019 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:
Expand Down
2 changes: 2 additions & 0 deletions src/main/antlr4/FIRRTL.g4
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type
| 'SInt' ('<' intLit '>')?
| 'Fixed' ('<' intLit '>')? ('<' '<' intLit '>' '>')?
| 'Clock'
| 'AsyncReset'
| 'Analog' ('<' intLit '>')?
| '{' field* '}' // Bundle
| type '[' intLit ']' // Vector
Expand Down Expand Up @@ -253,6 +254,7 @@ primop
| 'neq('
| 'pad('
| 'asUInt('
| 'asAsyncReset('
| 'asSInt('
| 'asClock('
| 'shl('
Expand Down
6 changes: 6 additions & 0 deletions src/main/proto/firrtl.proto
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,10 @@ message Firrtl {
// Empty.
}

message AsyncResetType {
// Empty.
}

message BundleType {
message Field {
// Required.
Expand Down Expand Up @@ -299,6 +303,7 @@ message Firrtl {
VectorType vector_type = 6;
FixedType fixed_type = 7;
AnalogType analog_type = 8;
AsyncResetType async_reset_type = 9;
}
}

Expand Down Expand Up @@ -425,6 +430,7 @@ message Firrtl {
OP_SHIFT_BINARY_POINT_LEFT = 35;
OP_SHIFT_BINARY_POINT_RIGHT = 36;
OP_SET_BINARY_POINT = 37;
OP_AS_ASYNC_RESET = 38;
}

// Required.
Expand Down
116 changes: 82 additions & 34 deletions src/main/scala/firrtl/Emitter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down Expand Up @@ -297,14 +297,14 @@ 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 {
case (_: SIntType) => Seq(cast(a0)," >>> ", a1)
case (_) => Seq(cast(a0), " >> ", a1)
}
case Shlw => Seq(cast(a0), " << ", c0)
case Shl => Seq(cast(a0), " << ", c0)
case Shl => if (c0 > 0) Seq("{", cast(a0), s", $c0'h0}") else Seq(cast(a0))
case Shr if c0 >= bitWidth(a0.tpe) =>
error("Verilog emitter does not support SHIFT_RIGHT >= arg width")
case Shr => Seq(a0,"[", bitWidth(a0.tpe) - 1, ":", c0, "]")
Expand Down Expand Up @@ -413,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 {
Expand Down Expand Up @@ -444,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")

Expand All @@ -472,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")
}
}

Expand All @@ -497,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) {
Expand All @@ -514,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;")
Expand Down Expand Up @@ -615,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)
Expand Down Expand Up @@ -758,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"))
Expand All @@ -776,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"))
Expand Down Expand Up @@ -883,3 +921,13 @@ class VerilogEmitter extends SeqTransform with Emitter {
state.copy(annotations = newAnnos ++ state.annotations)
}
}

class MinimumVerilogEmitter extends VerilogEmitter with Emitter {


override def transforms = super.transforms.filter{
case _: DeadCodeElimination => false
case _ => true
}

}
Loading

0 comments on commit fd3f0c1

Please sign in to comment.