aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/LICENSE.txt26
-rw-r--r--src/main/antlr4/FIRRTL.g481
-rw-r--r--src/main/resources/logback.xml26
-rw-r--r--src/main/scala/firrtl/Compiler.scala90
-rw-r--r--src/main/scala/firrtl/DebugUtils.scala27
-rw-r--r--src/main/scala/firrtl/Driver.scala163
-rw-r--r--src/main/scala/firrtl/Emitter.scala612
-rw-r--r--src/main/scala/firrtl/IR.scala136
-rw-r--r--src/main/scala/firrtl/Parser.scala37
-rw-r--r--src/main/scala/firrtl/Passes.scala453
-rw-r--r--src/main/scala/firrtl/PrimOps.scala448
-rw-r--r--src/main/scala/firrtl/Translator.scala26
-rw-r--r--src/main/scala/firrtl/Utils.scala1572
-rw-r--r--src/main/scala/firrtl/Visitor.scala161
-rw-r--r--src/main/scala/firrtl/WIR.scala221
-rw-r--r--src/main/scala/firrtl/passes/Checks.scala792
-rw-r--r--src/main/scala/firrtl/passes/Passes.scala1926
-rw-r--r--src/main/stanza/bigint.stanza402
-rw-r--r--src/main/stanza/bigint2.stanza25
-rw-r--r--src/main/stanza/chirrtl.stanza56
-rw-r--r--src/main/stanza/compilers.stanza39
-rw-r--r--src/main/stanza/custom-compiler.stanza24
-rw-r--r--src/main/stanza/custom-passes.stanza24
-rw-r--r--src/main/stanza/errors.stanza35
-rw-r--r--src/main/stanza/firrtl-ir.stanza24
-rw-r--r--src/main/stanza/firrtl-lexer.stanza24
-rw-r--r--src/main/stanza/firrtl-main.stanza24
-rw-r--r--src/main/stanza/firrtl-test-main.stanza32
-rw-r--r--src/main/stanza/firrtl.stanza24
-rw-r--r--src/main/stanza/flo.stanza24
-rw-r--r--src/main/stanza/ir-parser.stanza25
-rw-r--r--src/main/stanza/ir-utils.stanza33
-rw-r--r--src/main/stanza/passes.stanza110
-rw-r--r--src/main/stanza/primop.stanza24
-rw-r--r--src/main/stanza/symbolic-value.stanza24
-rw-r--r--src/main/stanza/verilog.stanza402
-rw-r--r--src/main/stanza/widthsolver.stanza24
37 files changed, 6537 insertions, 1659 deletions
diff --git a/src/LICENSE.txt b/src/LICENSE.txt
new file mode 100644
index 00000000..ad3748f7
--- /dev/null
+++ b/src/LICENSE.txt
@@ -0,0 +1,26 @@
+FIRRTL licence terms
+
+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.
diff --git a/src/main/antlr4/FIRRTL.g4 b/src/main/antlr4/FIRRTL.g4
index 2faef4e0..00a4c5de 100644
--- a/src/main/antlr4/FIRRTL.g4
+++ b/src/main/antlr4/FIRRTL.g4
@@ -1,3 +1,29 @@
+/*
+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.
+*/
grammar FIRRTL;
/*------------------------------------------------------------------
@@ -16,6 +42,7 @@ circuit
module
: 'module' id ':' '{' port* block '}'
+ | 'extmodule' id ':' '{' port* '}'
;
port
@@ -57,6 +84,9 @@ stmt
| 'readwriter' '=>' id
)*
'}'
+ | 'cmem' id ':' type
+ | 'smem' id ':' type
+ | mdir 'mport' id '=' id '[' exp ']' exp
| 'inst' id 'of' id
| 'node' id '=' exp
| exp '<=' exp
@@ -68,6 +98,13 @@ stmt
| 'skip'
;
+mdir
+ : 'infer'
+ | 'read'
+ | 'write'
+ | 'rdwr'
+ ;
+
ruw
: 'old'
| 'new'
@@ -93,12 +130,48 @@ id
| keyword
;
-// TODO add all keywords
keyword
- : dir
- | 'inst'
+ : 'circuit'
+ | 'module'
+ | 'extmodule'
+ | 'input'
+ | 'output'
+ | 'UInt'
+ | 'SInt'
+ | 'UBits'
+ | 'SBits'
+ | 'Clock'
+ | 'wire'
+ | 'reg'
| 'mem'
| 'reset'
+ | 'data-type'
+ | 'depth'
+ | 'read-latency'
+ | 'write-latency'
+ | 'read-under-write'
+ | 'reader'
+ | 'writer'
+ | 'readwriter'
+ | 'inst'
+ | 'node'
+ | 'is'
+ | 'invalid'
+ | 'when'
+ | 'else'
+ | 'stop'
+ | 'printf'
+ | 'skip'
+ | 'old'
+ | 'new'
+ | 'undefined'
+ | 'mux'
+ | 'validif'
+ | 'write'
+ | 'with'
+ | 'read'
+ | 'rdwr'
+ | 'infer'
;
// Parentheses are added as part of name because semantics require no space between primop and open parentheses
@@ -178,7 +251,7 @@ Id
fragment
IdNondigit
: Nondigit
- | [~!@#$%^*-+=?/]
+ | [~!@#$%^*\-+=?/]
;
Comment
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
index a6bab96e..78360578 100644
--- a/src/main/resources/logback.xml
+++ b/src/main/resources/logback.xml
@@ -1,3 +1,29 @@
+<!--
+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.
+-->
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
diff --git a/src/main/scala/firrtl/Compiler.scala b/src/main/scala/firrtl/Compiler.scala
new file mode 100644
index 00000000..0bb7510f
--- /dev/null
+++ b/src/main/scala/firrtl/Compiler.scala
@@ -0,0 +1,90 @@
+/*
+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
+
+import com.typesafe.scalalogging.LazyLogging
+import java.io.Writer
+
+import Utils._
+import firrtl.passes._
+
+trait Compiler extends LazyLogging {
+ def run(c: Circuit, w: Writer)
+}
+
+object FIRRTLCompiler extends Compiler {
+ def run(c: Circuit, w: Writer) = {
+ FIRRTLEmitter.run(c, w)
+ w.close
+ }
+}
+
+object VerilogCompiler extends Compiler {
+ // Copied from Stanza implementation
+ val passes = Seq(
+ //CheckHighForm,
+ //FromCHIRRTL,
+ CInferTypes,
+ CInferMDir,
+ RemoveCHIRRTL,
+ ToWorkingIR,
+ CheckHighForm,
+ ResolveKinds,
+ InferTypes,
+ CheckTypes,
+ ResolveGenders,
+ CheckGenders,
+ InferWidths,
+ CheckWidths,
+ PullMuxes,
+ ExpandConnects,
+ RemoveAccesses,
+ ExpandWhens,
+ CheckInitialization,
+ ConstProp,
+ ResolveKinds,
+ InferTypes,
+ ResolveGenders,
+ InferWidths,
+ LowerTypes,
+ ResolveKinds,
+ InferTypes,
+ ResolveGenders,
+ InferWidths,
+ VerilogWrap,
+ SplitExp,
+ VerilogRename
+ )
+ def run(c: Circuit, w: Writer)
+ {
+ val loweredIR = PassUtils.executePasses(c, passes)
+ VerilogEmitter.run(loweredIR, w)
+ w.close
+ }
+
+}
diff --git a/src/main/scala/firrtl/DebugUtils.scala b/src/main/scala/firrtl/DebugUtils.scala
index 8151e2a6..3f6d0af1 100644
--- a/src/main/scala/firrtl/DebugUtils.scala
+++ b/src/main/scala/firrtl/DebugUtils.scala
@@ -1,4 +1,29 @@
-// Private implicit classes and other utility functions for debugging
+/*
+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
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala
index 34a69110..c2dc0b59 100644
--- a/src/main/scala/firrtl/Driver.scala
+++ b/src/main/scala/firrtl/Driver.scala
@@ -1,3 +1,29 @@
+/*
+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
import java.io._
@@ -10,51 +36,6 @@ import com.typesafe.scalalogging.LazyLogging
import Utils._
import DebugUtils._
-import Passes._
-
-trait DriverPass {
- def run(input: String, output: String) : Unit
-}
-case class StanzaPass(val passes : Seq[String]) extends DriverPass with LazyLogging {
- def run(input : String, output : String): Unit = {
- val cmd = Seq("firrtl-stanza", "-i", input, "-o", output, "-b", "firrtl") ++ passes.flatMap(x=>Seq("-x", x))
- logger.info(cmd.mkString(" "))
- val ret = cmd.!!
- logger.info(ret)
- }
-}
-case class ScalaPass(val func : Circuit => Circuit) extends DriverPass with LazyLogging {
- def run(input : String, output : String): Unit = {
- var ast = Parser.parse(input, Source.fromFile(input).getLines)
- val newast = func(ast)
- logger.info("Writing to " + output)
- val writer = new PrintWriter(new File(output))
- writer.write(newast.serialize())
- writer.close()
- }
-}
-object StanzaPass {
- def apply(pass: String): StanzaPass = StanzaPass(Seq(pass))
-}
-
-object DriverPasses {
- private def aggregateStanzaPasses(passes: Seq[DriverPass]): Seq[DriverPass] = {
- if (passes.isEmpty) return Seq()
- val span = passes.span(x => x match {
- case p : StanzaPass => true
- case _ => false
- })
- if (span._1.isEmpty) {
- Seq(span._2.head) ++ aggregateStanzaPasses(span._2.tail)
- } else {
- Seq(StanzaPass(span._1.flatMap(x=>x.asInstanceOf[StanzaPass].passes))) ++ aggregateStanzaPasses(span._2)
- }
- }
-
- def optimize(passes: Seq[DriverPass]): Seq[DriverPass] = {
- aggregateStanzaPasses(passes)
- }
-}
object Driver extends LazyLogging {
private val usage = """
@@ -62,91 +43,11 @@ object Driver extends LazyLogging {
"""
private val defaultOptions = Map[Symbol, Any]().withDefaultValue(false)
- // Appends 0 to the filename and appends .tmp to the extension
- private def genTempFilename(filename: String): String = {
- val pat = """(.*/)([^/]*)([.][^/.]*)""".r
- val (path, name, ext) = filename match {
- case pat(path, name, ext) => (path, name, ext + ".tmp")
- case _ => ("./", "temp", ".tmp")
- }
- var count = 0
- while( Files.exists(Paths.get(path + name + count + ext )) )
- count += 1
- path + name + count + ext
- }
-
- val defaultPasses = DriverPasses.optimize(Seq(
- StanzaPass("to-firrtl"),
-
- StanzaPass("high-form-check"),
-
-// ScalaPass(renameall(Map(
-// "c"->"ccc",
-// "z"->"zzz",
-// "top"->"its_a_top_module"
-// ))),
- // StanzaPass("temp-elim"), // performance pass
- StanzaPass("to-working-ir"),
-
- StanzaPass("resolve-kinds"),
- StanzaPass("infer-types"),
- StanzaPass("check-types"),
- StanzaPass("resolve-genders"),
- StanzaPass("check-genders"),
- StanzaPass("infer-widths"),
- StanzaPass("width-check"),
-
- StanzaPass("check-kinds"),
-
- StanzaPass("expand-accessors"),
- StanzaPass("lower-to-ground"),
- StanzaPass("inline-indexers"),
- StanzaPass("infer-types"),
- //ScalaPass(inferTypes),
- StanzaPass("check-genders"),
- StanzaPass("expand-whens"),
-
- StanzaPass("real-ir"),
-
- StanzaPass("pad-widths"),
- StanzaPass("const-prop"),
- StanzaPass("split-expressions"),
- StanzaPass("width-check"),
- StanzaPass("high-form-check"),
- StanzaPass("low-form-check"),
- StanzaPass("check-init")//,
- //ScalaPass(renamec)
- ))
-
- // Parse input file and print to output
- private def firrtl(input: String, output: String)
+ private def compile(input: String, output: String, compiler: Compiler)
{
- val ast = Parser.parse(input, Source.fromFile(input).getLines)
- val writer = new PrintWriter(new File(output))
- writer.write(ast.serialize())
- writer.close()
- logger.debug(ast.toString)
- }
-
- def executePasses(ast: Circuit, passes: Seq[Circuit => Circuit]): Circuit = {
- if (passes.isEmpty) ast
- else executePasses(passes.head(ast), passes.tail)
- }
-
- private def verilog(input: String, output: String) {
- val outfile = defaultPasses.foldLeft( input ) ( (infile, pass) => {
- val outfile = genTempFilename(output)
- pass.run(infile, outfile)
- outfile
- })
-
- logger.info(outfile)
-
- // finally, convert to verilog at the end
- val cmd = Seq("firrtl-stanza", "-i", outfile, "-o", output, "-X", "verilog")
- logger.info(cmd.mkString(" "))
- val ret = cmd.!!
- logger.info(ret)
+ val parsedInput = Parser.parse(input, Source.fromFile(input).getLines)
+ val writerOutput = new PrintWriter(new File(output))
+ compiler.run(parsedInput, writerOutput)
}
def main(args: Array[String])
@@ -220,8 +121,8 @@ object Driver extends LazyLogging {
}
options('compiler) match {
- case "verilog" => verilog(input, output)
- case "firrtl" => firrtl(input, output)
+ case "verilog" => compile(input, output, VerilogCompiler)
+ case "firrtl" => compile(input, output, FIRRTLCompiler)
case other => throw new Exception("Invalid compiler! " + other)
}
}
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
new file mode 100644
index 00000000..c7bf45a2
--- /dev/null
+++ b/src/main/scala/firrtl/Emitter.scala
@@ -0,0 +1,612 @@
+/*
+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
+
+import com.typesafe.scalalogging.LazyLogging
+import java.nio.file.{Paths, Files}
+import java.io.Writer
+import java.io.Reader
+
+import scala.sys.process._
+import scala.io.Source
+
+import Utils._
+import firrtl.passes._
+import WrappedExpression._
+// Datastructures
+import scala.collection.mutable.LinkedHashMap
+import scala.collection.mutable.ArrayBuffer
+
+trait Emitter extends LazyLogging {
+ def run(c: Circuit, w: Writer)
+}
+
+object FIRRTLEmitter extends Emitter {
+ def run(c: Circuit, w: Writer) = w.write(c.serialize)
+}
+
+case class VIndent()
+case class VRandom()
+object VerilogEmitter extends Emitter {
+ val tab = " "
+ val ran = VRandom()
+ var w:Option[Writer] = None
+ var mname = ""
+ def wref (n:String,t:Type) = WRef(n,t,ExpKind(),UNKNOWNGENDER)
+ def escape (s:String) : String = {
+ val sx = ArrayBuffer[String]()
+ //sx += '"'.toString
+ var percent:Boolean = false
+ for (c <- s) {
+ if (c == '\n') sx += "\\n"
+ else if (c == '"') sx += '\\'.toString + '"'.toString
+ else {
+ if((c == 'x') && percent) sx += "h" else sx += c.toString
+ }
+ percent = (c == '%')
+ }
+ //sx += '"'.toString
+ sx.reduce(_ + _)
+ }
+ def remove_root (ex:Expression) : Expression = {
+ (ex.as[WSubField].get.exp) match {
+ case (e:WSubField) => remove_root(e)
+ case (e:WRef) => WRef(ex.as[WSubField].get.name,tpe(ex),InstanceKind(),UNKNOWNGENDER)
+ }
+ }
+ def not_empty (s:ArrayBuffer[_]) : Boolean = if (s.size == 0) false else true
+ def rand_string (t:Type) : Seq[Any] = {
+ val wx = ((long_BANG(t) + 31) / 32).toInt
+ Seq("{",wx.toString,"{",ran,"}}")
+ }
+ def emit (x:Any) = emit2(x,0)
+ def emit2 (x:Any, top:Int) : Unit = {
+ def cast (e:Expression) : Any = {
+ (tpe(e)) match {
+ case (t:UIntType) => e
+ case (t:SIntType) => Seq("$signed(",e,")")
+ }
+ }
+ (x) match {
+ case (e:Expression) => {
+ (e) match {
+ case (e:DoPrim) => emit2(op_stream(e), top + 1)
+ case (e:Mux) => emit2(Seq(e.cond," ? ",cast(e.tval)," : ",cast(e.fval)),top + 1)
+ case (e:ValidIf) => emit2(Seq(cast(e.value)),top + 1)
+ case (e:WRef) => w.get.write(e.serialize())
+ case (e:WSubField) => w.get.write(lowered_name(e))
+ case (e:WSubAccess) => w.get.write(lowered_name(e.exp) + "[" + lowered_name(e.index) + "]")
+ case (e:WSubIndex) => w.get.write(e.serialize())
+ case (_:UIntValue|_:SIntValue) => v_print(e)
+ }
+ }
+ case (t:Type) => {
+ (t) match {
+ case (_:UIntType|_:SIntType) =>
+ val wx = long_BANG(t) - 1
+ if (wx > 0) w.get.write("[" + wx + ":0]") else w.get.write("")
+ case (t:ClockType) => w.get.write("")
+ case (t:VectorType) =>
+ emit2(t.tpe, top + 1)
+ w.get.write("[" + (t.size - 1) + ":0]")
+ case (t) => error("Shouldn't be here"); w.get.write(t.serialize())
+ }
+ }
+ case (p:Direction) => {
+ p match {
+ case INPUT => w.get.write("input")
+ case OUTPUT => w.get.write("output")
+ }
+ }
+ case (s:String) => w.get.write(s)
+ case (i:Int) => w.get.write(i.toString)
+ case (i:Long) => w.get.write(i.toString)
+ case (t:VIndent) => w.get.write(" ")
+ case (r:VRandom) => w.get.write("$random")
+ case (s:Seq[Any]) => {
+ s.foreach((x:Any) => emit2(x.as[Any].get, top + 1))
+ if (top == 0) w.get.write("\n")
+ }
+ }
+ }
+
+ //;------------- PASS -----------------
+ def v_print (e:Expression) = {
+ e match {
+ case (e:UIntValue) => {
+ val str = e.value.toString(16)
+ w.get.write(long_BANG(tpe(e)).toString + "'h" + str)
+ }
+ case (e:SIntValue) => {
+ val str = e.value.toString(16)
+ w.get.write(long_BANG(tpe(e)).toString + "'sh" + str)
+ }
+ }
+ }
+ def op_stream (doprim:DoPrim) : Seq[Any] = {
+ def cast_if (e:Expression) : Any = {
+ val signed = doprim.args.find(x => tpe(x).typeof[SIntType])
+ if (signed == None) e
+ else tpe(e) match {
+ case (t:SIntType) => Seq("$signed(",e,")")
+ case (t:UIntType) => Seq("$signed({1'b0,",e,"})")
+ }
+ }
+ def cast (e:Expression) : Any = {
+ (doprim.tpe) match {
+ case (t:UIntType) => e
+ case (t:SIntType) => Seq("$signed(",e,")")
+ }
+ }
+ def cast_as (e:Expression) : Any = {
+ (tpe(e)) match {
+ case (t:UIntType) => e
+ case (t:SIntType) => Seq("$signed(",e,")")
+ }
+ }
+ def a0 () : Expression = doprim.args(0)
+ def a1 () : Expression = doprim.args(1)
+ def a2 () : Expression = doprim.args(2)
+ def c0 () : Int = doprim.consts(0).toInt
+ def c1 () : Int = doprim.consts(1).toInt
+
+ doprim.op match {
+ case ADD_OP => Seq(cast_if(a0())," + ", cast_if(a1()))
+ case ADDW_OP => Seq(cast_if(a0())," + ", cast_if(a1()))
+ case SUB_OP => Seq(cast_if(a0())," - ", cast_if(a1()))
+ case SUBW_OP => Seq(cast_if(a0())," - ", cast_if(a1()))
+ case MUL_OP => Seq(cast_if(a0())," * ", cast_if(a1()) )
+ case DIV_OP => Seq(cast_if(a0())," / ", cast_if(a1()) )
+ case REM_OP => Seq(cast_if(a0())," % ", cast_if(a1()) )
+ case LESS_OP => Seq(cast_if(a0())," < ", cast_if(a1()))
+ case LESS_EQ_OP => Seq(cast_if(a0())," <= ", cast_if(a1()))
+ case GREATER_OP => Seq(cast_if(a0())," > ", cast_if(a1()))
+ case GREATER_EQ_OP => Seq(cast_if(a0())," >= ", cast_if(a1()))
+ case EQUAL_OP => Seq(cast_if(a0())," == ", cast_if(a1()))
+ case NEQUAL_OP => Seq(cast_if(a0())," != ", cast_if(a1()))
+ case PAD_OP => {
+ val w = long_BANG(tpe(a0()))
+ val diff = (c0() - w)
+ if (w == 0) Seq(a0())
+ else doprim.tpe match {
+ case (t:SIntType) => Seq("{{",diff,"{",a0(),"[",w - 1,"]}}, ",a0()," }")
+ case (t) => Seq("{{",diff,"'d0 }, ",a0()," }")
+ }
+ }
+ case AS_UINT_OP => Seq("$unsigned(",a0(),")")
+ case AS_SINT_OP => Seq("$signed(",a0(),")")
+ case AS_CLOCK_OP => Seq("$unsigned(",a0(),")")
+ case DYN_SHIFT_LEFT_OP => Seq(cast(a0())," << ", a1())
+ case DYN_SHIFT_RIGHT_OP => {
+ (doprim.tpe) match {
+ case (t:SIntType) => Seq(cast(a0())," >>> ",a1())
+ case (t) => Seq(cast(a0())," >> ",a1())
+ }
+ }
+ case SHIFT_LEFT_OP => Seq(cast(a0())," << ",c0())
+ case SHIFT_RIGHT_OP => Seq(a0(),"[", long_BANG(tpe(a0())) - 1,":",c0(),"]")
+ case NEG_OP => Seq("-{",cast(a0()),"}")
+ case CONVERT_OP => {
+ tpe(a0()) match {
+ case (t:UIntType) => Seq("{1'b0,",cast(a0()),"}")
+ case (t:SIntType) => Seq(cast(a0()))
+ }
+ }
+ case NOT_OP => Seq("~ ",a0())
+ case AND_OP => Seq(cast_as(a0())," & ", cast_as(a1()))
+ case OR_OP => Seq(cast_as(a0())," | ", cast_as(a1()))
+ case XOR_OP => Seq(cast_as(a0())," ^ ", cast_as(a1()))
+ case AND_REDUCE_OP => {
+ val v = ArrayBuffer[Seq[Any]]()
+ for (b <- 0 until long_BANG(doprim.tpe).toInt) {
+ v += Seq(cast(a0()),"[",b,"]")
+ }
+ v.reduce(_ + " & " + _)
+ }
+ case OR_REDUCE_OP => {
+ val v = ArrayBuffer[Seq[Any]]()
+ for (b <- 0 until long_BANG(doprim.tpe).toInt) {
+ v += Seq(cast(a0()),"[",b,"]")
+ }
+ v.reduce(_ + " | " + _)
+ }
+ case XOR_REDUCE_OP => {
+ val v = ArrayBuffer[Seq[Any]]()
+ for (b <- 0 until long_BANG(doprim.tpe).toInt) {
+ v += Seq(cast(a0()),"[",b,"]")
+ }
+ v.reduce(_ + " ^ " + _)
+ }
+ case CONCAT_OP => Seq("{",cast(a0()),",",cast(a1()),"}")
+ case BITS_SELECT_OP => {
+ if (c0() == c1()) Seq(a0(),"[",c0(),"]")
+ else Seq(a0(),"[",c0(),":",c1(),"]")
+ }
+ case HEAD_OP => {
+ val w = long_BANG(tpe(a0()))
+ val high = w - 1
+ val low = w - c0()
+ Seq(a0(),"[",high,":",low,"]")
+ }
+ case TAIL_OP => {
+ val w = long_BANG(tpe(a0()))
+ val low = w - c0() - 1
+ Seq(a0(),"[",low,":",0,"]")
+ }
+ }
+ }
+
+ def emit_verilog (m:InModule) : Module = {
+ mname = m.name
+ val netlist = LinkedHashMap[WrappedExpression,Expression]()
+ val simlist = ArrayBuffer[Stmt]()
+ def build_netlist (s:Stmt) : Stmt = {
+ s match {
+ case (s:Connect) => netlist(s.loc) = s.exp
+ case (s:IsInvalid) => {
+ val n = firrtl_gensym_module(mname)
+ val e = wref(n,tpe(s.exp))
+ netlist(s.exp) = e
+ }
+ case (s:Conditionally) => simlist += s
+ case (s:DefNode) => {
+ val e = WRef(s.name,get_type(s),NodeKind(),MALE)
+ netlist(e) = s.value
+ }
+ case (s) => sMap(build_netlist,s)
+ }
+ s
+ }
+
+ val portdefs = ArrayBuffer[Seq[Any]]()
+ val declares = ArrayBuffer[Seq[Any]]()
+ val instdeclares = ArrayBuffer[Seq[Any]]()
+ val assigns = ArrayBuffer[Seq[Any]]()
+ val at_clock = 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 {
+ 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 update_and_reset (r:Expression,clk:Expression,reset:Expression,init:Expression) = {
+ if (!at_clock.contains(clk)) { at_clock(clk) = ArrayBuffer[Seq[Any]]() }
+ def add_update (e:Expression,tabs:String) : Unit = {
+ e match {
+ case (e:Mux) => {
+ at_clock(clk) += Seq(tabs,"if(",e.cond,") begin")
+ add_update(e.tval,tabs + tab)
+ at_clock(clk) += Seq(tabs,"end else begin")
+ add_update(e.fval,tabs + tab)
+ at_clock(clk) += Seq(tabs,"end")
+ }
+ case (e) => {
+ if (weq(e,r)) at_clock(clk) += Seq(tabs,";")
+ else at_clock(clk) += Seq(tabs,r," <= ",e,";")
+ }
+ }
+ }
+ val tv = init
+ val fv = netlist(r)
+ add_update(Mux(reset,tv,fv,mux_type_and_widths(tv,fv)),"")
+ }
+ def update (e:Expression,value:Expression,clk:Expression,en:Expression) = {
+ if (!at_clock.contains(clk)) at_clock(clk) = ArrayBuffer[Seq[Any]]()
+ if (weq(en,one)) at_clock(clk) += Seq(e," <= ",value,";")
+ else {
+ at_clock(clk) += Seq("if(",en,") begin")
+ at_clock(clk) += Seq(tab,e," <= ",value,";")
+ at_clock(clk) += Seq("end")
+ }
+ }
+ def initialize (e:Expression) = initials += Seq(e," = ",rand_string(tpe(e)),";")
+ def initialize_mem (n:String,i:Int,t:Type) = {
+ initials += Seq("for (initvar = 0; initvar < ",i,"; initvar = initvar+1)")
+ val index = WRef("initvar",UnknownType(),ExpKind(),UNKNOWNGENDER)
+ initials += Seq(tab,WSubAccess(wref(n,t),index,UnknownType(),FEMALE), " = ",rand_string(t),";")
+ }
+ def instantiate (n:String,m:String,es:Seq[Expression]) = {
+ instdeclares += Seq(m," ",n," (")
+ (es,0 until es.size).zipped.foreach{ (e,i) => {
+ val s = Seq(tab,".",remove_root(e),"(",lowered_name(e),")")
+ if (i != es.size - 1) instdeclares += Seq(s,",")
+ else instdeclares += s
+ }}
+ instdeclares += Seq(");")
+ for (e <- es) {
+ declare("wire",lowered_name(e),tpe(e))
+ val ex = WRef(lowered_name(e),tpe(e),kind(e),gender(e))
+ if (gender(e) == FEMALE) {
+ assign(ex,netlist(e))
+ }
+ }
+ }
+ def simulate (clk:Expression,en:Expression,s:Seq[Any]) = {
+ if (!at_clock.contains(clk)) at_clock(clk) = ArrayBuffer[Seq[Any]]()
+ at_clock(clk) += Seq("`ifndef SYNTHESIS")
+ at_clock(clk) += Seq(tab,"if(",en,") begin")
+ at_clock(clk) += Seq(tab,tab,s)
+ at_clock(clk) += Seq(tab,"end")
+ at_clock(clk) += Seq("`endif")
+ }
+ def stop (ret:Int) : Seq[Any] = {
+ Seq("$fdisplay(32'h80000002,\"",ret,"\");$finish;")
+ }
+ def printf (str:String,args:Seq[Expression]) : Seq[Any] = {
+ val q = '"'.toString
+ val strx = (Seq(q + escape(str) + q) ++ args.map(x => escape(x.serialize()))).reduce(_ + "," + _)
+ Seq("$fwrite(32'h80000002,",strx,");")
+ }
+ def delay (e:Expression, n:Int, clk:Expression) : Expression = {
+ var ex = e
+ for (i <- 0 until n) {
+ val name = firrtl_gensym_module(mname)
+ declare("reg",name,tpe(e))
+ val exx = WRef(name,tpe(e),ExpKind(),UNKNOWNGENDER)
+ update(exx,ex,clk,one)
+ ex = exx
+ }
+ ex
+ }
+ def build_ports () = {
+ (m.ports,0 until m.ports.size).zipped.foreach{(p,i) => {
+ var end = ",\n"
+ if (m.ports.size - 1 == i) end = "\n);\n"
+ p.direction match {
+ case INPUT => portdefs += 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))
+ }
+ }
+ }}
+ if (m.ports.size == 0) w.get.write(");\n")
+ }
+ def build_streams (s:Stmt) : Stmt = {
+ s match {
+ case (s:Connect) => s
+ case (s:DefWire) =>
+ declare("wire",s.name,s.tpe)
+ val e = wref(s.name,s.tpe)
+ assign(e,netlist(e))
+ case (s:DefRegister) => {
+ declare("reg",s.name,s.tpe)
+ val e = wref(s.name,s.tpe)
+ update_and_reset(e,s.clock,s.reset,s.init)
+ initialize(e)
+ }
+ case (s:IsInvalid) => {
+ val wref = netlist(s.exp).as[WRef].get
+ declare("reg",wref.name,tpe(s.exp))
+ initialize(wref)
+ }
+ case (s:DefPoison) => {
+ val n = s.name
+ val e = wref(n,s.tpe)
+ declare("reg",n,tpe(e))
+ initialize(e)
+ }
+ case (s:DefNode) => {
+ declare("wire",s.name,tpe(s.value))
+ assign(WRef(s.name,tpe(s.value),NodeKind(),MALE),s.value)
+ }
+ case (s:Stop) => simulate(s.clk,s.en,stop(s.ret))
+ case (s:Print) => simulate(s.clk,s.en,printf(s.string,s.args))
+ case (s:WDefInstance) => {
+ val es = create_exps(WRef(s.name,s.tpe,InstanceKind(),MALE))
+ instantiate(s.name,s.module,es)
+ }
+ case (s:DefMemory) => {
+ val mem = WRef(s.name,get_type(s),MemKind(s.readers ++ s.writers ++ s.readwriters),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.data_type,s.depth))
+ initialize_mem(s.name,s.depth,s.data_type)
+ for (r <- s.readers ) {
+ val data = mem_exp(r,"data")
+ val addr = mem_exp(r,"addr")
+ val en = mem_exp(r,"en")
+ val clk = mem_exp(r,"clk")
+
+ declare("wire",lowered_name(data),tpe(data))
+ declare("wire",lowered_name(addr),tpe(addr))
+ declare("wire",lowered_name(en),tpe(en))
+ declare("wire",lowered_name(clk),tpe(clk))
+
+ //; Read port
+ assign(addr,netlist(addr)) //;Connects value to m.r.addr
+ assign(en,netlist(en)) //;Connects value to m.r.en
+ assign(clk,netlist(clk)) //;Connects value to m.r.clk
+ val addrx = delay(addr,s.read_latency,clk)
+ val enx = delay(en,s.read_latency,clk)
+ val mem_port = WSubAccess(mem,addrx,UnknownType(),UNKNOWNGENDER)
+ assign(data,mem_port)
+ }
+
+ 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 clk = mem_exp(w,"clk")
+
+ declare("wire",lowered_name(data),tpe(data))
+ declare("wire",lowered_name(addr),tpe(addr))
+ declare("wire",lowered_name(mask),tpe(mask))
+ declare("wire",lowered_name(en),tpe(en))
+ declare("wire",lowered_name(clk),tpe(clk))
+
+ //; Write port
+ assign(data,netlist(data))
+ assign(addr,netlist(addr))
+ assign(mask,netlist(mask))
+ assign(en,netlist(en))
+ assign(clk,netlist(clk))
+
+ val datax = delay(data,s.write_latency - 1,clk)
+ val addrx = delay(addr,s.write_latency - 1,clk)
+ val maskx = delay(mask,s.write_latency - 1,clk)
+ val enx = delay(en,s.write_latency - 1,clk)
+ val mem_port = WSubAccess(mem,addrx,UnknownType(),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 data = mem_exp(rw,"data")
+ val mask = mem_exp(rw,"mask")
+ val addr = mem_exp(rw,"addr")
+ val en = mem_exp(rw,"en")
+ val clk = mem_exp(rw,"clk")
+
+ declare("wire",lowered_name(wmode),tpe(wmode))
+ declare("wire",lowered_name(rdata),tpe(rdata))
+ declare("wire",lowered_name(data),tpe(data))
+ declare("wire",lowered_name(mask),tpe(mask))
+ declare("wire",lowered_name(addr),tpe(addr))
+ declare("wire",lowered_name(en),tpe(en))
+ declare("wire",lowered_name(clk),tpe(clk))
+
+ //; Assigned to lowered wires of each
+ assign(clk,netlist(clk))
+ assign(addr,netlist(addr))
+ assign(data,netlist(data))
+ assign(addr,netlist(addr))
+ assign(mask,netlist(mask))
+ assign(en,netlist(en))
+ assign(wmode,netlist(wmode))
+
+ //; Delay new signals by latency
+ val raddrx = delay(addr,s.read_latency,clk)
+ val waddrx = delay(addr,s.write_latency - 1,clk)
+ val enx = delay(en,s.write_latency - 1,clk)
+ val rmodx = delay(wmode,s.write_latency - 1,clk)
+ val datax = delay(data,s.write_latency - 1,clk)
+ val maskx = delay(mask,s.write_latency - 1,clk)
+
+ //; Write
+
+ val rmem_port = WSubAccess(mem,raddrx,UnknownType(),UNKNOWNGENDER)
+ assign(rdata,rmem_port)
+ val wmem_port = WSubAccess(mem,waddrx,UnknownType(),UNKNOWNGENDER)
+ update(wmem_port,datax,clk,AND(AND(enx,maskx),wmode))
+ }
+ }
+ case (s:Begin) => sMap(build_streams _,s)
+ }
+ s
+ }
+
+ def emit_streams () = {
+ emit(Seq("module ",m.name,"("))
+ if (not_empty(portdefs)) {
+ (portdefs,0 until portdefs.size).zipped.foreach{ (x,i) => {
+ if (i != portdefs.size - 1) emit(Seq(tab,x,","))
+ else emit(Seq(tab,x))
+ }}
+ }
+ emit(Seq(");"))
+
+ if (not_empty(declares)) {
+ for (x <- declares) emit(Seq(tab,x))
+ }
+ if (not_empty(instdeclares)) {
+ for (x <- instdeclares) emit(Seq(tab,x))
+ }
+ if (not_empty(assigns)) {
+ for (x <- assigns) emit(Seq(tab,x))
+ }
+ if (not_empty(initials)) {
+ emit(Seq("`ifndef SYNTHESIS"))
+ emit(Seq(" integer initvar;"))
+ emit(Seq(" initial begin"))
+ emit(Seq(" #0.002;"))
+ for (x <- initials) {
+ emit(Seq(tab,x))
+ }
+ emit(Seq(" end"))
+ emit(Seq("`endif"))
+ }
+
+ for (clk_stream <- at_clock) {
+ if (not_empty(clk_stream._2)) {
+ emit(Seq(tab,"always @(posedge ",clk_stream._1,") begin"))
+ for (x <- clk_stream._2) {
+ emit(Seq(tab,tab,x))
+ }
+ emit(Seq(tab,"end"))
+ }
+ }
+
+ emit(Seq("endmodule"))
+ }
+
+ build_netlist(m.body)
+ build_ports()
+ build_streams(m.body)
+ emit_streams()
+ m
+ }
+
+ def run(c: Circuit, w: Writer) = {
+ this.w = Some(w)
+ for (m <- c.modules) {
+ m match {
+ case (m:InModule) => emit_verilog(m)
+ case (m:ExModule) => false
+ }
+ }
+ }
+ //def run(c: Circuit, w: Writer)
+ //{
+ // logger.debug(s"Verilog Emitter is not yet implemented in Scala")
+ // val toStanza = Files.createTempFile(Paths.get(""), "verilog", ".fir")
+ // val fromStanza = Files.createTempFile(Paths.get(""), "verilog", ".fir")
+ // Files.write(toStanza, c.serialize.getBytes)
+
+ // val cmd = Seq("firrtl-stanza", "-i", toStanza.toString, "-o", fromStanza.toString, "-b", "verilog")
+ // logger.debug(cmd.mkString(" "))
+ // val ret = cmd.!
+ // // Copy from Stanza output to user requested outputFile (we can't get filename from Writer)
+ // Source.fromFile(fromStanza.toString) foreach { w.write(_) }
+
+ // Files.delete(toStanza)
+ // Files.delete(fromStanza)
+ //}
+}
diff --git a/src/main/scala/firrtl/IR.scala b/src/main/scala/firrtl/IR.scala
index 858f48cf..5d6a6862 100644
--- a/src/main/scala/firrtl/IR.scala
+++ b/src/main/scala/firrtl/IR.scala
@@ -1,3 +1,29 @@
+/*
+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
@@ -9,64 +35,69 @@ Structure containing source locator information.
Member of most Stmt case classes.
*/
trait Info
-case object NoInfo extends Info
+case object NoInfo extends Info {
+ override def toString(): String = "NoFileInfo"
+}
case class FileInfo(file: String, line: Int, column: Int) extends Info {
override def toString(): String = s"$file@$line.$column"
}
+case class FIRRTLException(str:String) extends Exception
+
trait AST
trait PrimOp extends AST
-case object AddOp extends PrimOp
-case object SubOp extends PrimOp
-case object MulOp extends PrimOp
-case object DivOp extends PrimOp
-case object RemOp extends PrimOp
-case object LessOp extends PrimOp
-case object LessEqOp extends PrimOp
-case object GreaterOp extends PrimOp
-case object GreaterEqOp extends PrimOp
-case object EqualOp extends PrimOp
-case object NEqualOp extends PrimOp
-case object PadOp extends PrimOp
-case object AsUIntOp extends PrimOp
-case object AsSIntOp extends PrimOp
-case object AsClockOp extends PrimOp
-case object ShiftLeftOp extends PrimOp
-case object ShiftRightOp extends PrimOp
-case object DynShiftLeftOp extends PrimOp
-case object DynShiftRightOp extends PrimOp
-case object ConvertOp extends PrimOp
-case object NegOp extends PrimOp
-case object BitNotOp extends PrimOp
-case object BitAndOp extends PrimOp
-case object BitOrOp extends PrimOp
-case object BitXorOp extends PrimOp
-case object BitAndReduceOp extends PrimOp
-case object BitOrReduceOp extends PrimOp
-case object BitXorReduceOp extends PrimOp
-case object ConcatOp extends PrimOp
-case object BitsSelectOp extends PrimOp
-case object HeadOp extends PrimOp
-case object TailOp extends PrimOp
+case object ADD_OP extends PrimOp
+case object SUB_OP extends PrimOp
+case object MUL_OP extends PrimOp
+case object DIV_OP extends PrimOp
+case object REM_OP extends PrimOp
+case object LESS_OP extends PrimOp
+case object LESS_EQ_OP extends PrimOp
+case object GREATER_OP extends PrimOp
+case object GREATER_EQ_OP extends PrimOp
+case object EQUAL_OP extends PrimOp
+case object NEQUAL_OP extends PrimOp
+case object PAD_OP extends PrimOp
+case object AS_UINT_OP extends PrimOp
+case object AS_SINT_OP extends PrimOp
+case object AS_CLOCK_OP extends PrimOp
+case object SHIFT_LEFT_OP extends PrimOp
+case object SHIFT_RIGHT_OP extends PrimOp
+case object DYN_SHIFT_LEFT_OP extends PrimOp
+case object DYN_SHIFT_RIGHT_OP extends PrimOp
+case object CONVERT_OP extends PrimOp
+case object NEG_OP extends PrimOp
+case object NOT_OP extends PrimOp
+case object AND_OP extends PrimOp
+case object OR_OP extends PrimOp
+case object XOR_OP extends PrimOp
+case object AND_REDUCE_OP extends PrimOp
+case object OR_REDUCE_OP extends PrimOp
+case object XOR_REDUCE_OP extends PrimOp
+case object CONCAT_OP extends PrimOp
+case object BITS_SELECT_OP extends PrimOp
+case object HEAD_OP extends PrimOp
+case object TAIL_OP extends PrimOp
trait Expression extends AST
case class Ref(name: String, tpe: Type) extends Expression
case class SubField(exp: Expression, name: String, tpe: Type) extends Expression
-case class SubIndex(exp: Expression, value: BigInt, tpe: Type) extends Expression
+case class SubIndex(exp: Expression, value: Int, tpe: Type) extends Expression
case class SubAccess(exp: Expression, index: Expression, tpe: Type) extends Expression
case class Mux(cond: Expression, tval: Expression, fval: Expression, tpe: Type) extends Expression
case class ValidIf(cond: Expression, value: Expression, tpe: Type) extends Expression
case class UIntValue(value: BigInt, width: Width) extends Expression
case class SIntValue(value: BigInt, width: Width) extends Expression
-case class DoPrim(op: PrimOp, args: Seq[Expression], consts: Seq[BigInt], tpe: Type) extends Expression
+case class DoPrim(op: PrimOp, args: Seq[Expression], consts: Seq[BigInt], tpe: Type) extends Expression
trait Stmt extends AST
case class DefWire(info: Info, name: String, tpe: Type) extends Stmt
+case class DefPoison(info: Info, name: String, tpe: Type) extends Stmt
case class DefRegister(info: Info, name: String, tpe: Type, clock: Expression, reset: Expression, init: Expression) extends Stmt
case class DefInstance(info: Info, name: String, module: String) extends Stmt
-case class DefMemory(info: Info, name: String, dataType: Type, depth: Int, writeLatency: Int,
- readLatency: Int, readers: Seq[String], writers: Seq[String], readwriters: Seq[String]) extends Stmt
+case class DefMemory(info: Info, name: String, data_type: Type, depth: Int, write_latency: Int,
+ read_latency: Int, readers: Seq[String], writers: Seq[String], readwriters: Seq[String]) extends Stmt
case class DefNode(info: Info, name: String, value: Expression) extends Stmt
case class Conditionally(info: Info, pred: Expression, conseq: Stmt, alt: Stmt) extends Stmt
case class Begin(stmts: Seq[Stmt]) extends Stmt
@@ -75,15 +106,15 @@ case class Connect(info: Info, loc: Expression, exp: Expression) extends Stmt
case class IsInvalid(info: Info, exp: Expression) extends Stmt
case class Stop(info: Info, ret: Int, clk: Expression, en: Expression) extends Stmt
case class Print(info: Info, string: String, args: Seq[Expression], clk: Expression, en: Expression) extends Stmt
-case object Empty extends Stmt
+case class Empty() extends Stmt
trait Width extends AST
case class IntWidth(width: BigInt) extends Width
-case object UnknownWidth extends Width
+case class UnknownWidth() extends Width
trait Flip extends AST
-case object Default extends Flip
-case object Reverse extends Flip
+case object DEFAULT extends Flip
+case object REVERSE extends Flip
case class Field(name: String, flip: Flip, tpe: Type) extends AST
@@ -91,18 +122,23 @@ trait Type extends AST
case class UIntType(width: Width) extends Type
case class SIntType(width: Width) extends Type
case class BundleType(fields: Seq[Field]) extends Type
-case class VectorType(tpe: Type, size: BigInt) extends Type
-case object ClockType extends Type
-case object UnknownType extends Type
+case class VectorType(tpe: Type, size: Int) extends Type
+case class ClockType() extends Type
+case class UnknownType() extends Type
trait Direction extends AST
-case object Input extends Direction
-case object Output extends Direction
-
-case class Port(info: Info, name: String, dir: Direction, tpe: Type) extends AST
+case object INPUT extends Direction
+case object OUTPUT extends Direction
-case class Module(info: Info, name: String, ports: Seq[Port], stmt: Stmt) extends AST
+case class Port(info: Info, name: String, direction: Direction, tpe: Type) extends AST
-case class Circuit(info: Info, name: String, modules: Seq[Module]) extends AST
+trait Module extends AST {
+ val info : Info
+ val name : String
+ val ports : Seq[Port]
+}
+case class InModule(info: Info, name: String, ports: Seq[Port], body: Stmt) extends Module
+case class ExModule(info: Info, name: String, ports: Seq[Port]) extends Module
+case class Circuit(info: Info, modules: Seq[Module], main: String) extends AST
diff --git a/src/main/scala/firrtl/Parser.scala b/src/main/scala/firrtl/Parser.scala
index 98864e92..6e93e7e6 100644
--- a/src/main/scala/firrtl/Parser.scala
+++ b/src/main/scala/firrtl/Parser.scala
@@ -1,15 +1,46 @@
+/*
+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
import org.antlr.v4.runtime._;
import org.antlr.v4.runtime.atn._;
import org.antlr.v4.runtime.tree._;
+import com.typesafe.scalalogging.LazyLogging
import java.io.FileInputStream
import scala.collection.JavaConverters._
import scala.io.Source
import Utils._
import antlr._
-object Parser
+class ParserException(message: String) extends Exception(message)
+case class ParameterNotSpecifiedException(message: String) extends ParserException(message)
+case class ParameterRedefinedException(message: String) extends ParserException(message)
+
+object Parser extends LazyLogging
{
/** Takes Iterator over lines of FIRRTL, returns AST (root node is Circuit)
*
@@ -17,6 +48,7 @@ object Parser
*/
def parse(filename: String, lines: Iterator[String]): Circuit = {
val fixedInput = Translator.addBrackets(lines)
+ //logger.debug("Preprocessed Input:\n" + fixedInput.result)
val antlrStream = new ANTLRInputStream(fixedInput.result)
val lexer = new FIRRTLLexer(antlrStream)
val tokens = new CommonTokenStream(lexer)
@@ -28,6 +60,9 @@ object Parser
// Concrete Syntax Tree
val cst = parser.circuit
+ val numSyntaxErrors = parser.getNumberOfSyntaxErrors
+ if (numSyntaxErrors > 0) throw new ParserException(s"${numSyntaxErrors} syntax error(s) detected")
+
val visitor = new Visitor(filename)
//val ast = visitor.visitCircuit(cst) match {
val ast = visitor.visit(cst) match {
diff --git a/src/main/scala/firrtl/Passes.scala b/src/main/scala/firrtl/Passes.scala
index b73ee727..ac41cdf1 100644
--- a/src/main/scala/firrtl/Passes.scala
+++ b/src/main/scala/firrtl/Passes.scala
@@ -1,190 +1,283 @@
+/*
+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
import com.typesafe.scalalogging.LazyLogging
+import scala.collection.mutable.HashMap
+import scala.collection.mutable.ArrayBuffer
import Utils._
import DebugUtils._
import PrimOps._
-object Passes extends LazyLogging {
- // TODO Perhaps we should get rid of Logger since this map would be nice
- ////private val defaultLogger = Logger()
- //private def mapNameToPass = Map[String, Circuit => Circuit] (
- // "infer-types" -> inferTypes
- //)
- def nameToPass(name: String): Circuit => Circuit = {
- //mapNameToPass.getOrElse(name, throw new Exception("No Standard FIRRTL Pass of name " + name))
- name match {
- case "infer-types" => inferTypes
- // errrrrrrrrrr...
- case "renameall" => renameall(Map())
- }
- }
-
- private def toField(p: Port): Field = {
- logger.debug(s"toField called on port ${p.serialize}")
- p.dir match {
- case Input => Field(p.name, Reverse, p.tpe)
- case Output => Field(p.name, Default, p.tpe)
- }
- }
-
- /** INFER TYPES
- *
- * This pass infers the type field in all IR nodes by updating
- * and passing an environment to all statements in pre-order
- * traversal, and resolving types in expressions in post-
- * order traversal.
- * Type propagation for primary ops are defined in Primops.scala.
- * Type errors are not checked in this pass, as this is
- * postponed for a later/earlier pass.
- */
- // input -> flip
- private type TypeMap = Map[String, Type]
- private val TypeMap = Map[String, Type]().withDefaultValue(UnknownType)
- private def getBundleSubtype(t: Type, name: String): Type = {
- t match {
- case b: BundleType => {
- val tpe = b.fields.find( _.name == name )
- if (tpe.isEmpty) UnknownType
- else tpe.get.tpe
- }
- case _ => UnknownType
- }
- }
- private def getVectorSubtype(t: Type): Type = t.getType // Added for clarity
- // TODO Add genders
- private def inferExpTypes(typeMap: TypeMap)(exp: Expression): Expression = {
- logger.debug(s"inferTypes called on ${exp.getClass.getSimpleName}")
- exp.map(inferExpTypes(typeMap)) match {
- case e: UIntValue => e
- case e: SIntValue => e
- case e: Ref => Ref(e.name, typeMap(e.name))
- case e: SubField => SubField(e.exp, e.name, getBundleSubtype(e.exp.getType, e.name))
- case e: SubIndex => SubIndex(e.exp, e.value, getVectorSubtype(e.exp.getType))
- case e: SubAccess => SubAccess(e.exp, e.index, getVectorSubtype(e.exp.getType))
- case e: DoPrim => lowerAndTypePrimOp(e)
- case e: Expression => e
- }
- }
- private def inferTypes(typeMap: TypeMap, stmt: Stmt): (Stmt, TypeMap) = {
- logger.debug(s"inferTypes called on ${stmt.getClass.getSimpleName} ")
- stmt.map(inferExpTypes(typeMap)) match {
- case b: Begin => {
- var tMap = typeMap
- // TODO FIXME is map correctly called in sequential order
- val body = b.stmts.map { s =>
- val ret = inferTypes(tMap, s)
- tMap = ret._2
- ret._1
- }
- (Begin(body), tMap)
- }
- case s: DefWire => (s, typeMap ++ Map(s.name -> s.tpe))
- case s: DefRegister => (s, typeMap ++ Map(s.name -> s.tpe))
- case s: DefMemory => (s, typeMap ++ Map(s.name -> s.dataType))
- case s: DefInstance => (s, typeMap ++ Map(s.name -> typeMap(s.module)))
- case s: DefNode => (s, typeMap ++ Map(s.name -> s.value.getType))
- case s: Conditionally => { // TODO Check: Assuming else block won't see when scope
- val (conseq, cMap) = inferTypes(typeMap, s.conseq)
- val (alt, aMap) = inferTypes(typeMap, s.alt)
- (Conditionally(s.info, s.pred, conseq, alt), cMap ++ aMap)
- }
- case s: Stmt => (s, typeMap)
- }
- }
- private def inferTypes(typeMap: TypeMap, m: Module): Module = {
- logger.debug(s"inferTypes called on module ${m.name}")
-
- val pTypeMap = m.ports.map( p => p.name -> p.tpe ).toMap
-
- Module(m.info, m.name, m.ports, inferTypes(typeMap ++ pTypeMap, m.stmt)._1)
- }
- def inferTypes(c: Circuit): Circuit = {
- logger.debug(s"inferTypes called on circuit ${c.name}")
-
- // initialize typeMap with each module of circuit mapped to their bundled IO (ports converted to fields)
- val typeMap = c.modules.map(m => m.name -> BundleType(m.ports.map(toField(_)))).toMap
-
- //val typeMap = c.modules.flatMap(buildTypeMap).toMap
- Circuit(c.info, c.name, c.modules.map(inferTypes(typeMap, _)))
- }
-
- def renameall(s : String)(implicit map : Map[String,String]) : String =
- map getOrElse (s, s)
-
- def renameall(e : Expression)(implicit map : Map[String,String]) : Expression = {
- logger.debug(s"renameall called on expression ${e.toString}")
- e match {
- case p : Ref =>
- Ref(renameall(p.name), p.tpe)
- case p : SubField =>
- SubField(renameall(p.exp), renameall(p.name), p.tpe)
- case p : SubIndex =>
- SubIndex(renameall(p.exp), p.value, p.tpe)
- case p : SubAccess =>
- SubAccess(renameall(p.exp), renameall(p.index), p.tpe)
- case p : Mux =>
- Mux(renameall(p.cond), renameall(p.tval), renameall(p.fval), p.tpe)
- case p : ValidIf =>
- ValidIf(renameall(p.cond), renameall(p.value), p.tpe)
- case p : DoPrim =>
- println( p.args.map(x => renameall(x)) )
- DoPrim(p.op, p.args.map(renameall), p.consts, p.tpe)
- case p : Expression => p
- }
- }
-
- def renameall(s : Stmt)(implicit map : Map[String,String]) : Stmt = {
- logger.debug(s"renameall called on statement ${s.toString}")
-
- s match {
- case p : DefWire =>
- DefWire(p.info, renameall(p.name), p.tpe)
- case p: DefRegister =>
- DefRegister(p.info, renameall(p.name), p.tpe, p.clock, p.reset, p.init)
- case p : DefMemory =>
- DefMemory(p.info, renameall(p.name), p.dataType, p.depth, p.writeLatency, p.readLatency,
- p.readers, p.writers, p.readwriters)
- case p : DefInstance =>
- DefInstance(p.info, renameall(p.name), renameall(p.module))
- case p : DefNode =>
- DefNode(p.info, renameall(p.name), renameall(p.value))
- case p : Connect =>
- Connect(p.info, renameall(p.loc), renameall(p.exp))
- case p : BulkConnect =>
- BulkConnect(p.info, renameall(p.loc), renameall(p.exp))
- case p : IsInvalid =>
- IsInvalid(p.info, renameall(p.exp))
- case p : Stop =>
- Stop(p.info, p.ret, renameall(p.clk), renameall(p.en))
- case p : Print =>
- Print(p.info, p.string, p.args.map(renameall), renameall(p.clk), renameall(p.en))
- case p : Conditionally =>
- Conditionally(p.info, renameall(p.pred), renameall(p.conseq), renameall(p.alt))
- case p : Begin =>
- Begin(p.stmts.map(renameall))
- case p : Stmt => p
- }
- }
-
- def renameall(p : Port)(implicit map : Map[String,String]) : Port = {
- logger.debug(s"renameall called on port ${p.name}")
- Port(p.info, renameall(p.name), p.dir, p.tpe)
- }
-
- def renameall(m : Module)(implicit map : Map[String,String]) : Module = {
- logger.debug(s"renameall called on module ${m.name}")
- Module(m.info, renameall(m.name), m.ports.map(renameall(_)), renameall(m.stmt))
- }
-
- def renameall(map : Map[String,String]) : Circuit => Circuit = {
- c => {
- implicit val imap = map
- logger.debug(s"renameall called on circuit ${c.name} with %{renameto}")
- Circuit(c.info, renameall(c.name), c.modules.map(renameall(_)))
- }
- }
-}
+//@deprecated("This object will be replaced with package firrtl.passes")
+//object Passes extends LazyLogging {
+//
+//
+// // TODO Perhaps we should get rid of Logger since this map would be nice
+// ////private val defaultLogger = Logger()
+// //private def mapNameToPass = Map[String, Circuit => Circuit] (
+// // "infer-types" -> inferTypes
+// //)
+// var mname = ""
+// //def nameToPass(name: String): Circuit => Circuit = {
+// //mapNameToPass.getOrElse(name, throw new Exception("No Standard FIRRTL Pass of name " + name))
+// //name match {
+// //case "to-working-ir" => toWorkingIr
+// //case "infer-types" => inferTypes
+// // errrrrrrrrrr...
+// //case "renameall" => renameall(Map())
+// //}
+// //}
+//
+// private def toField(p: Port): Field = {
+// logger.debug(s"toField called on port ${p.serialize}")
+// p.direction match {
+// case INPUT => Field(p.name, REVERSE, p.tpe)
+// case OUTPUT => Field(p.name, DEFAULT, p.tpe)
+// }
+// }
+// // ============== RESOLVE ALL ===================
+// def resolve (c:Circuit) = {c
+// //val passes = Seq(
+// // toWorkingIr _,
+// // resolveKinds _,
+// // inferTypes _,
+// // resolveGenders _,
+// // pullMuxes _,
+// // expandConnects _,
+// // removeAccesses _)
+// //val names = Seq(
+// // "To Working IR",
+// // "Resolve Kinds",
+// // "Infer Types",
+// // "Resolve Genders",
+// // "Pull Muxes",
+// // "Expand Connects",
+// // "Remove Accesses")
+// //var c_BANG = c
+// //(names, passes).zipped.foreach {
+// // (n,p) => {
+// // println("Starting " + n)
+// // c_BANG = p(c_BANG)
+// // println(c_BANG.serialize())
+// // println("Finished " + n)
+// // }
+// //}
+// //c_BANG
+// }
+//
+//
+// // ============== RESOLVE KINDS ==================
+// // ===============================================
+//
+// // ============== INFER TYPES ==================
+//
+// // ------------------ Utils -------------------------
+//
+//
+//// =================== RESOLVE GENDERS =======================
+// // ===============================================
+//
+// // =============== PULL MUXES ====================
+// // ===============================================
+//
+//
+//
+// // ============ EXPAND CONNECTS ==================
+// // ---------------- UTILS ------------------
+//
+//
+// //---------------- Pass ---------------------
+//
+// // ===============================================
+//
+//
+//
+// // ============ REMOVE ACCESSES ==================
+// // ---------------- UTILS ------------------
+//
+//
+// /** INFER TYPES
+// *
+// * This pass infers the type field in all IR nodes by updating
+// * and passing an environment to all statements in pre-order
+// * traversal, and resolving types in expressions in post-
+// * order traversal.
+// * Type propagation for primary ops are defined in Primops.scala.
+// * Type errors are not checked in this pass, as this is
+// * postponed for a later/earlier pass.
+// */
+// // input -> flip
+// //private type TypeMap = Map[String, Type]
+// //private val TypeMap = Map[String, Type]().withDefaultValue(UnknownType)
+// //private def getBundleSubtype(t: Type, name: String): Type = {
+// // t match {
+// // case b: BundleType => {
+// // val tpe = b.fields.find( _.name == name )
+// // if (tpe.isEmpty) UnknownType
+// // else tpe.get.tpe
+// // }
+// // case _ => UnknownType
+// // }
+// //}
+// //private def getVectorSubtype(t: Type): Type = t.getType // Added for clarity
+// //// TODO Add genders
+// //private def inferExpTypes(typeMap: TypeMap)(exp: Expression): Expression = {
+// // logger.debug(s"inferTypes called on ${exp.getClass.getSimpleName}")
+// // exp.map(inferExpTypes(typeMap)) match {
+// // case e: UIntValue => e
+// // case e: SIntValue => e
+// // case e: Ref => Ref(e.name, typeMap(e.name))
+// // case e: SubField => SubField(e.exp, e.name, getBundleSubtype(e.exp.getType, e.name))
+// // case e: SubIndex => SubIndex(e.exp, e.value, getVectorSubtype(e.exp.getType))
+// // case e: SubAccess => SubAccess(e.exp, e.index, getVectorSubtype(e.exp.getType))
+// // case e: DoPrim => lowerAndTypePrimOp(e)
+// // case e: Expression => e
+// // }
+// //}
+// //private def inferTypes(typeMap: TypeMap, stmt: Stmt): (Stmt, TypeMap) = {
+// // logger.debug(s"inferTypes called on ${stmt.getClass.getSimpleName} ")
+// // stmt.map(inferExpTypes(typeMap)) match {
+// // case b: Begin => {
+// // var tMap = typeMap
+// // // TODO FIXME is map correctly called in sequential order
+// // val body = b.stmts.map { s =>
+// // val ret = inferTypes(tMap, s)
+// // tMap = ret._2
+// // ret._1
+// // }
+// // (Begin(body), tMap)
+// // }
+// // case s: DefWire => (s, typeMap ++ Map(s.name -> s.tpe))
+// // case s: DefRegister => (s, typeMap ++ Map(s.name -> s.tpe))
+// // case s: DefMemory => (s, typeMap ++ Map(s.name -> s.dataType))
+// // case s: DefInstance => (s, typeMap ++ Map(s.name -> typeMap(s.module)))
+// // case s: DefNode => (s, typeMap ++ Map(s.name -> s.value.getType))
+// // case s: Conditionally => { // TODO Check: Assuming else block won't see when scope
+// // val (conseq, cMap) = inferTypes(typeMap, s.conseq)
+// // val (alt, aMap) = inferTypes(typeMap, s.alt)
+// // (Conditionally(s.info, s.pred, conseq, alt), cMap ++ aMap)
+// // }
+// // case s: Stmt => (s, typeMap)
+// // }
+// //}
+// //private def inferTypes(typeMap: TypeMap, m: Module): Module = {
+// // logger.debug(s"inferTypes called on module ${m.name}")
+//
+// // val pTypeMap = m.ports.map( p => p.name -> p.tpe ).toMap
+//
+// // Module(m.info, m.name, m.ports, inferTypes(typeMap ++ pTypeMap, m.stmt)._1)
+// //}
+// //def inferTypes(c: Circuit): Circuit = {
+// // logger.debug(s"inferTypes called on circuit ${c.name}")
+//
+// // // initialize typeMap with each module of circuit mapped to their bundled IO (ports converted to fields)
+// // val typeMap = c.modules.map(m => m.name -> BundleType(m.ports.map(toField(_)))).toMap
+//
+// // //val typeMap = c.modules.flatMap(buildTypeMap).toMap
+// // Circuit(c.info, c.name, c.modules.map(inferTypes(typeMap, _)))
+// //}
+//
+// //def renameall(s : String)(implicit map : Map[String,String]) : String =
+// // map getOrElse (s, s)
+//
+// //def renameall(e : Expression)(implicit map : Map[String,String]) : Expression = {
+// // logger.debug(s"renameall called on expression ${e.toString}")
+// // e match {
+// // case p : Ref =>
+// // Ref(renameall(p.name), p.tpe)
+// // case p : SubField =>
+// // SubField(renameall(p.exp), renameall(p.name), p.tpe)
+// // case p : SubIndex =>
+// // SubIndex(renameall(p.exp), p.value, p.tpe)
+// // case p : SubAccess =>
+// // SubAccess(renameall(p.exp), renameall(p.index), p.tpe)
+// // case p : Mux =>
+// // Mux(renameall(p.cond), renameall(p.tval), renameall(p.fval), p.tpe)
+// // case p : ValidIf =>
+// // ValidIf(renameall(p.cond), renameall(p.value), p.tpe)
+// // case p : DoPrim =>
+// // println( p.args.map(x => renameall(x)) )
+// // DoPrim(p.op, p.args.map(renameall), p.consts, p.tpe)
+// // case p : Expression => p
+// // }
+// //}
+//
+// //def renameall(s : Stmt)(implicit map : Map[String,String]) : Stmt = {
+// // logger.debug(s"renameall called on statement ${s.toString}")
+//
+// // s match {
+// // case p : DefWire =>
+// // DefWire(p.info, renameall(p.name), p.tpe)
+// // case p: DefRegister =>
+// // DefRegister(p.info, renameall(p.name), p.tpe, p.clock, p.reset, p.init)
+// // case p : DefMemory =>
+// // DefMemory(p.info, renameall(p.name), p.dataType, p.depth, p.writeLatency, p.readLatency,
+// // p.readers, p.writers, p.readwriters)
+// // case p : DefInstance =>
+// // DefInstance(p.info, renameall(p.name), renameall(p.module))
+// // case p : DefNode =>
+// // DefNode(p.info, renameall(p.name), renameall(p.value))
+// // case p : Connect =>
+// // Connect(p.info, renameall(p.loc), renameall(p.exp))
+// // case p : BulkConnect =>
+// // BulkConnect(p.info, renameall(p.loc), renameall(p.exp))
+// // case p : IsInvalid =>
+// // IsInvalid(p.info, renameall(p.exp))
+// // case p : Stop =>
+// // Stop(p.info, p.ret, renameall(p.clk), renameall(p.en))
+// // case p : Print =>
+// // Print(p.info, p.string, p.args.map(renameall), renameall(p.clk), renameall(p.en))
+// // case p : Conditionally =>
+// // Conditionally(p.info, renameall(p.pred), renameall(p.conseq), renameall(p.alt))
+// // case p : Begin =>
+// // Begin(p.stmts.map(renameall))
+// // case p : Stmt => p
+// // }
+// //}
+//
+// //def renameall(p : Port)(implicit map : Map[String,String]) : Port = {
+// // logger.debug(s"renameall called on port ${p.name}")
+// // Port(p.info, renameall(p.name), p.dir, p.tpe)
+// //}
+//
+// //def renameall(m : Module)(implicit map : Map[String,String]) : Module = {
+// // logger.debug(s"renameall called on module ${m.name}")
+// // Module(m.info, renameall(m.name), m.ports.map(renameall(_)), renameall(m.stmt))
+// //}
+//
+// //def renameall(map : Map[String,String]) : Circuit => Circuit = {
+// // c => {
+// // implicit val imap = map
+// // logger.debug(s"renameall called on circuit ${c.name} with %{renameto}")
+// // Circuit(c.info, renameall(c.name), c.modules.map(renameall(_)))
+// // }
+// //}
+//}
diff --git a/src/main/scala/firrtl/PrimOps.scala b/src/main/scala/firrtl/PrimOps.scala
index 0da0e01e..53d87b30 100644
--- a/src/main/scala/firrtl/PrimOps.scala
+++ b/src/main/scala/firrtl/PrimOps.scala
@@ -1,3 +1,29 @@
+/*
+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
@@ -9,39 +35,44 @@ import DebugUtils._
object PrimOps extends LazyLogging {
private val mapPrimOp2String = Map[PrimOp, String](
- AddOp -> "add",
- SubOp -> "sub",
- MulOp -> "mul",
- DivOp -> "div",
- RemOp -> "rem",
- LessOp -> "lt",
- LessEqOp -> "leq",
- GreaterOp -> "gt",
- GreaterEqOp -> "geq",
- EqualOp -> "eq",
- NEqualOp -> "neq",
- PadOp -> "pad",
- AsUIntOp -> "asUInt",
- AsSIntOp -> "asSInt",
- AsClockOp -> "asClock",
- ShiftLeftOp -> "shl",
- ShiftRightOp -> "shr",
- DynShiftLeftOp -> "dshl",
- DynShiftRightOp -> "dshr",
- ConvertOp -> "cvt",
- NegOp -> "neg",
- BitNotOp -> "not",
- BitAndOp -> "and",
- BitOrOp -> "or",
- BitXorOp -> "xor",
- BitAndReduceOp -> "andr",
- BitOrReduceOp -> "orr",
- BitXorReduceOp -> "xorr",
- ConcatOp -> "cat",
- BitsSelectOp -> "bits",
- HeadOp -> "head",
- TailOp -> "tail"
+ ADD_OP -> "add",
+ SUB_OP -> "sub",
+ MUL_OP -> "mul",
+ DIV_OP -> "div",
+ REM_OP -> "rem",
+ LESS_OP -> "lt",
+ LESS_EQ_OP -> "leq",
+ GREATER_OP -> "gt",
+ GREATER_EQ_OP -> "geq",
+ EQUAL_OP -> "eq",
+ NEQUAL_OP -> "neq",
+ PAD_OP -> "pad",
+ AS_UINT_OP -> "asUInt",
+ AS_SINT_OP -> "asSInt",
+ AS_CLOCK_OP -> "asClock",
+ SHIFT_LEFT_OP -> "shl",
+ SHIFT_RIGHT_OP -> "shr",
+ DYN_SHIFT_LEFT_OP -> "dshl",
+ DYN_SHIFT_RIGHT_OP -> "dshr",
+ NEG_OP -> "neg",
+ CONVERT_OP -> "cvt",
+ NOT_OP -> "not",
+ AND_OP -> "and",
+ OR_OP -> "or",
+ XOR_OP -> "xor",
+ AND_REDUCE_OP -> "andr",
+ OR_REDUCE_OP -> "orr",
+ XOR_REDUCE_OP -> "xorr",
+ CONCAT_OP -> "cat",
+ BITS_SELECT_OP -> "bits",
+ HEAD_OP -> "head",
+ TAIL_OP -> "tail",
+
+ //This are custom, we need to refactor to enable easily extending FIRRTL with custom primops
+ ADDW_OP -> "addw",
+ SUBW_OP -> "subw"
)
+ lazy val listing: Seq[String] = PrimOps.mapPrimOp2String.map { case (k,v) => v } toSeq
private val mapString2PrimOp = mapPrimOp2String.map(_.swap)
def fromString(op: String): PrimOp = mapString2PrimOp(op)
@@ -50,67 +81,298 @@ object PrimOps extends LazyLogging {
}
// Borrowed from Stanza implementation
- def lowerAndTypePrimOp(e: DoPrim): DoPrim = {
- def uAnd(op1: Expression, op2: Expression): Type = {
- (op1.getType, op2.getType) match {
- case (t1: UIntType, t2: UIntType) => UIntType(UnknownWidth)
- case (t1: SIntType, t2) => SIntType(UnknownWidth)
- case (t1, t2: SIntType) => SIntType(UnknownWidth)
- case _ => UnknownType
- }
- }
- def ofType(op: Expression): Type = {
- op.getType match {
- case t: UIntType => UIntType(UnknownWidth)
- case t: SIntType => SIntType(UnknownWidth)
- case _ => UnknownType
- }
- }
+ def set_primop_type (e:DoPrim) : DoPrim = {
+ //println-all(["Inferencing primop type: " e])
+ def PLUS (w1:Width,w2:Width) : Width = PlusWidth(w1,w2)
+ def MAX (w1:Width,w2:Width) : Width = MaxWidth(Seq(w1,w2))
+ def MINUS (w1:Width,w2:Width) : Width = MinusWidth(w1,w2)
+ def POW (w1:Width) : Width = ExpWidth(w1)
+ def MIN (w1:Width,w2:Width) : Width = MinWidth(Seq(w1,w2))
+ val o = e.op
+ val a = e.args
+ val c = e.consts
+ def t1 () = tpe(a(0))
+ def t2 () = tpe(a(1))
+ def t3 () = tpe(a(2))
+ def w1 () = widthBANG(tpe(a(0)))
+ def w2 () = widthBANG(tpe(a(1)))
+ def w3 () = widthBANG(tpe(a(2)))
+ def c1 () = IntWidth(c(0))
+ def c2 () = IntWidth(c(1))
+ o match {
+ case ADD_OP => {
+ val t = (t1(),t2()) match {
+ case (t1:UIntType, t2:UIntType) => UIntType(PLUS(MAX(w1(),w2()),ONE))
+ case (t1:UIntType, t2:SIntType) => SIntType(PLUS(MAX(w1(),w2()),ONE))
+ case (t1:SIntType, t2:UIntType) => SIntType(PLUS(MAX(w1(),w2()),ONE))
+ case (t1:SIntType, t2:SIntType) => SIntType(PLUS(MAX(w1(),w2()),ONE))
+ case (t1, t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case SUB_OP => {
+ val t = (t1(),t2()) match {
+ case (t1:UIntType, t2:UIntType) => SIntType(PLUS(MAX(w1(),w2()),ONE))
+ case (t1:UIntType, t2:SIntType) => SIntType(PLUS(MAX(w1(),w2()),ONE))
+ case (t1:SIntType, t2:UIntType) => SIntType(PLUS(MAX(w1(),w2()),ONE))
+ case (t1:SIntType, t2:SIntType) => SIntType(PLUS(MAX(w1(),w2()),ONE))
+ case (t1, t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case MUL_OP => {
+ val t = (t1(),t2()) match {
+ case (t1:UIntType, t2:UIntType) => UIntType(PLUS(w1(),w2()))
+ case (t1:UIntType, t2:SIntType) => SIntType(PLUS(w1(),w2()))
+ case (t1:SIntType, t2:UIntType) => SIntType(PLUS(w1(),w2()))
+ case (t1:SIntType, t2:SIntType) => SIntType(PLUS(w1(),w2()))
+ case (t1, t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case DIV_OP => {
+ val t = (t1(),t2()) match {
+ case (t1:UIntType, t2:UIntType) => UIntType(w1())
+ case (t1:UIntType, t2:SIntType) => SIntType(PLUS(w1(),ONE))
+ case (t1:SIntType, t2:UIntType) => SIntType(w1())
+ case (t1:SIntType, t2:SIntType) => SIntType(PLUS(w1(),ONE))
+ case (t1, t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case REM_OP => {
+ val t = (t1(),t2()) match {
+ case (t1:UIntType, t2:UIntType) => UIntType(MIN(w1(),w2()))
+ case (t1:UIntType, t2:SIntType) => UIntType(MIN(w1(),w2()))
+ case (t1:SIntType, t2:UIntType) => SIntType(MIN(w1(),PLUS(w2(),ONE)))
+ case (t1:SIntType, t2:SIntType) => SIntType(MIN(w1(),w2()))
+ case (t1, t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case LESS_OP => {
+ val t = (t1(),t2()) match {
+ case (t1:UIntType, t2:UIntType) => BoolType()
+ case (t1:SIntType, t2:UIntType) => BoolType()
+ case (t1:UIntType, t2:SIntType) => BoolType()
+ case (t1:SIntType, t2:SIntType) => BoolType()
+ case (t1, t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case LESS_EQ_OP => {
+ val t = (t1(),t2()) match {
+ case (t1:UIntType, t2:UIntType) => BoolType()
+ case (t1:SIntType, t2:UIntType) => BoolType()
+ case (t1:UIntType, t2:SIntType) => BoolType()
+ case (t1:SIntType, t2:SIntType) => BoolType()
+ case (t1, t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case GREATER_OP => {
+ val t = (t1(),t2()) match {
+ case (t1:UIntType, t2:UIntType) => BoolType()
+ case (t1:SIntType, t2:UIntType) => BoolType()
+ case (t1:UIntType, t2:SIntType) => BoolType()
+ case (t1:SIntType, t2:SIntType) => BoolType()
+ case (t1, t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case GREATER_EQ_OP => {
+ val t = (t1(),t2()) match {
+ case (t1:UIntType, t2:UIntType) => BoolType()
+ case (t1:SIntType, t2:UIntType) => BoolType()
+ case (t1:UIntType, t2:SIntType) => BoolType()
+ case (t1:SIntType, t2:SIntType) => BoolType()
+ case (t1, t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case EQUAL_OP => {
+ val t = (t1(),t2()) match {
+ case (t1:UIntType, t2:UIntType) => BoolType()
+ case (t1:SIntType, t2:UIntType) => BoolType()
+ case (t1:UIntType, t2:SIntType) => BoolType()
+ case (t1:SIntType, t2:SIntType) => BoolType()
+ case (t1, t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case NEQUAL_OP => {
+ val t = (t1(),t2()) match {
+ case (t1:UIntType, t2:UIntType) => BoolType()
+ case (t1:SIntType, t2:UIntType) => BoolType()
+ case (t1:UIntType, t2:SIntType) => BoolType()
+ case (t1:SIntType, t2:SIntType) => BoolType()
+ case (t1, t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case PAD_OP => {
+ val t = (t1()) match {
+ case (t1:UIntType) => UIntType(MAX(w1(),c1()))
+ case (t1:SIntType) => SIntType(MAX(w1(),c1()))
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case AS_UINT_OP => {
+ val t = (t1()) match {
+ case (t1:UIntType) => UIntType(w1())
+ case (t1:SIntType) => UIntType(w1())
+ case (t1:ClockType) => UIntType(ONE)
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case AS_SINT_OP => {
+ val t = (t1()) match {
+ case (t1:UIntType) => SIntType(w1())
+ case (t1:SIntType) => SIntType(w1())
+ case (t1:ClockType) => SIntType(ONE)
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case AS_CLOCK_OP => {
+ val t = (t1()) match {
+ case (t1:UIntType) => ClockType()
+ case (t1:SIntType) => ClockType()
+ case (t1:ClockType) => ClockType()
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case SHIFT_LEFT_OP => {
+ val t = (t1()) match {
+ case (t1:UIntType) => UIntType(PLUS(w1(),c1()))
+ case (t1:SIntType) => SIntType(PLUS(w1(),c1()))
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case SHIFT_RIGHT_OP => {
+ val t = (t1()) match {
+ case (t1:UIntType) => UIntType(MINUS(w1(),c1()))
+ case (t1:SIntType) => SIntType(MINUS(w1(),c1()))
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case DYN_SHIFT_LEFT_OP => {
+ val t = (t1()) match {
+ case (t1:UIntType) => UIntType(PLUS(w1(),POW(w2())))
+ case (t1:SIntType) => SIntType(PLUS(w1(),POW(w2())))
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case DYN_SHIFT_RIGHT_OP => {
+ val t = (t1()) match {
+ case (t1:UIntType) => UIntType(w1())
+ case (t1:SIntType) => SIntType(w1())
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case CONVERT_OP => {
+ val t = (t1()) match {
+ case (t1:UIntType) => SIntType(PLUS(w1(),ONE))
+ case (t1:SIntType) => SIntType(w1())
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case NEG_OP => {
+ val t = (t1()) match {
+ case (t1:UIntType) => SIntType(PLUS(w1(),ONE))
+ case (t1:SIntType) => SIntType(PLUS(w1(),ONE))
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case NOT_OP => {
+ val t = (t1()) match {
+ case (t1:UIntType) => UIntType(w1())
+ case (t1:SIntType) => UIntType(w1())
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case AND_OP => {
+ val t = (t1(),t2()) match {
+ case (_:SIntType|_:UIntType, _:SIntType|_:UIntType) => UIntType(MAX(w1(),w2()))
+ case (t1,t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case OR_OP => {
+ val t = (t1(),t2()) match {
+ case (_:SIntType|_:UIntType, _:SIntType|_:UIntType) => UIntType(MAX(w1(),w2()))
+ case (t1,t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case XOR_OP => {
+ val t = (t1(),t2()) match {
+ case (_:SIntType|_:UIntType, _:SIntType|_:UIntType) => UIntType(MAX(w1(),w2()))
+ case (t1,t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case AND_REDUCE_OP => {
+ val t = (t1()) match {
+ case (_:UIntType|_:SIntType) => BoolType()
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case OR_REDUCE_OP => {
+ val t = (t1()) match {
+ case (_:UIntType|_:SIntType) => BoolType()
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case XOR_REDUCE_OP => {
+ val t = (t1()) match {
+ case (_:UIntType|_:SIntType) => BoolType()
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case CONCAT_OP => {
+ val t = (t1(),t2()) match {
+ case (_:UIntType|_:SIntType,_:UIntType|_:SIntType) => UIntType(PLUS(w1(),w2()))
+ case (t1, t2) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case BITS_SELECT_OP => {
+ val t = (t1()) match {
+ case (_:UIntType|_:SIntType) => UIntType(PLUS(MINUS(c1(),c2()),ONE))
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case HEAD_OP => {
+ val t = (t1()) match {
+ case (_:UIntType|_:SIntType) => UIntType(c1())
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
+ case TAIL_OP => {
+ val t = (t1()) match {
+ case (_:UIntType|_:SIntType) => UIntType(MINUS(w1(),c1()))
+ case (t1) => UnknownType()
+ }
+ DoPrim(o,a,c,t)
+ }
- logger.debug(s"lowerAndTypePrimOp on ${e.op.getClass.getSimpleName}")
- // TODO fix this
- val tpe = UIntType(UnknownWidth)
- //val tpe = e.op match {
- // case Add => uAnd(e.args(0), e.args(1))
- // case Sub => SIntType(UnknownWidth)
- // case Addw => uAnd(e.args(0), e.args(1))
- // case Subw => uAnd(e.args(0), e.args(1))
- // case Mul => uAnd(e.args(0), e.args(1))
- // case Div => uAnd(e.args(0), e.args(1))
- // case Mod => ofType(e.args(0))
- // case Quo => uAnd(e.args(0), e.args(1))
- // case Rem => ofType(e.args(1))
- // case Lt => UIntType(UnknownWidth)
- // case Leq => UIntType(UnknownWidth)
- // case Gt => UIntType(UnknownWidth)
- // case Geq => UIntType(UnknownWidth)
- // case Eq => UIntType(UnknownWidth)
- // case Neq => UIntType(UnknownWidth)
- // case Eqv => UIntType(UnknownWidth)
- // case Neqv => UIntType(UnknownWidth)
- // case Mux => ofType(e.args(1))
- // case Pad => ofType(e.args(0))
- // case AsUInt => UIntType(UnknownWidth)
- // case AsSInt => SIntType(UnknownWidth)
- // case Shl => ofType(e.args(0))
- // case Shr => ofType(e.args(0))
- // case Dshl => ofType(e.args(0))
- // case Dshr => ofType(e.args(0))
- // case Cvt => SIntType(UnknownWidth)
- // case Neg => SIntType(UnknownWidth)
- // case Not => ofType(e.args(0))
- // case And => ofType(e.args(0))
- // case Or => ofType(e.args(0))
- // case Xor => ofType(e.args(0))
- // case Andr => UIntType(UnknownWidth)
- // case Orr => UIntType(UnknownWidth)
- // case Xorr => UIntType(UnknownWidth)
- // case Cat => UIntType(UnknownWidth)
- // case Bit => UIntType(UnknownWidth)
- // case Bits => UIntType(UnknownWidth)
- // case _ => ???
- //}
- DoPrim(e.op, e.args, e.consts, tpe)
- }
+ }
+ }
}
diff --git a/src/main/scala/firrtl/Translator.scala b/src/main/scala/firrtl/Translator.scala
index 7b88e0e0..1ca20346 100644
--- a/src/main/scala/firrtl/Translator.scala
+++ b/src/main/scala/firrtl/Translator.scala
@@ -1,3 +1,29 @@
+/*
+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.
+*/
/* TODO
* - Add support for comments (that being said, current Scopers regex should ignore commented lines)
diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala
index ee974f11..251ae7b2 100644
--- a/src/main/scala/firrtl/Utils.scala
+++ b/src/main/scala/firrtl/Utils.scala
@@ -1,3 +1,29 @@
+/*
+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.
+*/
// Utility functions for FIRRTL IR
/* TODO
@@ -14,67 +40,603 @@ package firrtl
import scala.collection.mutable.StringBuilder
import java.io.PrintWriter
import PrimOps._
+import WrappedExpression._
+import firrtl.WrappedType._
+import scala.collection.mutable.ArrayBuffer
+import scala.collection.mutable.LinkedHashMap
//import scala.reflect.runtime.universe._
object Utils {
+//
+// // Is there a more elegant way to do this?
+ private type FlagMap = Map[String, Boolean]
+ private val FlagMap = Map[String, Boolean]().withDefaultValue(false)
+ implicit class WithAs[T](x: T) {
+ import scala.reflect._
+ def as[O: ClassTag]: Option[O] = x match {
+ case o: O => Some(o)
+ case _ => None }
+ def typeof[O: ClassTag]: Boolean = x match {
+ case o: O => true
+ case _ => false }
+ }
+ implicit def toWrappedExpression (x:Expression) = new WrappedExpression(x)
+ def ceil_log2(x: BigInt): BigInt = (x-1).bitLength
+ def ceil_log2(x: Int): Int = scala.math.ceil(scala.math.log(x) / scala.math.log(2)).toInt
+ val gen_names = Map[String,Int]()
+ val delin = "_"
+ val sym_hash = LinkedHashMap[String,LinkedHashMap[String,Int]]()
+ def BoolType () = { UIntType(IntWidth(1)) }
+ val one = UIntValue(BigInt(1),IntWidth(1))
+ val zero = UIntValue(BigInt(0),IntWidth(1))
+ def uint (i:Int) : UIntValue = {
+ val num_bits = req_num_bits(i)
+ val w = IntWidth(scala.math.max(1,num_bits - 1))
+ UIntValue(BigInt(i),w)
+ }
+ def req_num_bits (i: Int) : Int = {
+ val ix = if (i < 0) ((-1 * i) - 1) else i
+ ceil_log2(ix + 1) + 1
+ }
+ def firrtl_gensym (s:String):String = { firrtl_gensym(s,LinkedHashMap[String,Int]()) }
+ def firrtl_gensym (sym_hash:LinkedHashMap[String,Int]):String = { firrtl_gensym("GEN",sym_hash) }
+ def firrtl_gensym_module (s:String):String = {
+ val sh = sym_hash.getOrElse(s,LinkedHashMap[String,Int]())
+ val name = firrtl_gensym("GEN",sh)
+ sym_hash(s) = sh
+ name
+ }
+ def firrtl_gensym (s:String,sym_hash:LinkedHashMap[String,Int]):String = {
+ if (sym_hash contains s) {
+ val num = sym_hash(s) + 1
+ sym_hash += (s -> num)
+ (s + delin + num)
+ } else {
+ sym_hash += (s -> 0)
+ (s + delin + 0)
+ }
+ }
+ def AND (e1:WrappedExpression,e2:WrappedExpression) : Expression = {
+ if (e1 == e2) e1.e1
+ else if ((e1 == we(zero)) | (e2 == we(zero))) zero
+ else if (e1 == we(one)) e2.e1
+ else if (e2 == we(one)) e1.e1
+ else DoPrim(AND_OP,Seq(e1.e1,e2.e1),Seq(),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_OP,Seq(e1.e1,e2.e1),Seq(),UIntType(IntWidth(1)))
+ }
+ def EQV (e1:Expression,e2:Expression) : Expression = { DoPrim(EQUAL_OP,Seq(e1,e2),Seq(),tpe(e1)) }
+ def NOT (e1:WrappedExpression) : Expression = {
+ if (e1 == we(one)) zero
+ else if (e1 == we(zero)) one
+ else DoPrim(EQUAL_OP,Seq(e1.e1,zero),Seq(),UIntType(IntWidth(1)))
+ }
+
+
+ //def MUX (p:Expression,e1:Expression,e2:Expression) : Expression = {
+ // Mux(p,e1,e2,mux_type(tpe(e1),tpe(e2)))
+ //}
+
+ def create_mask (dt:Type) : Type = {
+ dt match {
+ case t:VectorType => VectorType(create_mask(t.tpe),t.size)
+ case t:BundleType => {
+ val fieldss = t.fields.map { f => Field(f.name,f.flip,create_mask(f.tpe)) }
+ BundleType(fieldss)
+ }
+ case t:UIntType => BoolType()
+ case t:SIntType => BoolType()
+ }
+ }
+ def create_exps (n:String, t:Type) : Seq[Expression] =
+ create_exps(WRef(n,t,ExpKind(),UNKNOWNGENDER))
+ def create_exps (e:Expression) : Seq[Expression] = {
+ e match {
+ case (e:Mux) => {
+ val e1s = create_exps(e.tval)
+ val e2s = create_exps(e.fval)
+ (e1s, e2s).zipped.map { (e1,e2) => Mux(e.cond,e1,e2,mux_type_and_widths(e1,e2)) }
+ }
+ case (e:ValidIf) => create_exps(e.value).map { e1 => ValidIf(e.cond,e1,tpe(e1)) }
+ case (e) => {
+ tpe(e) match {
+ case (t:UIntType) => Seq(e)
+ case (t:SIntType) => Seq(e)
+ case (t:ClockType) => Seq(e)
+ case (t:BundleType) => {
+ t.fields.flatMap { f => create_exps(WSubField(e,f.name,f.tpe,times(gender(e), f.flip))) }
+ }
+ case (t:VectorType) => {
+ (0 until t.size).flatMap { i => create_exps(WSubIndex(e,i,t.tpe,gender(e))) }
+ }
+ }
+ }
+ }
+ }
+ def lowered_name (e:Expression) : String = {
+ (e) match {
+ case (e:WRef) => e.name
+ case (e:WSubField) => lowered_name(e.exp) + "_" + e.name
+ case (e:WSubIndex) => lowered_name(e.exp) + "_" + e.value
+ }
+ }
+ def get_flip (t:Type, i:Int, f:Flip) : Flip = {
+ if (i >= get_size(t)) error("Shouldn't be here")
+ val x = t match {
+ case (t:UIntType) => f
+ case (t:SIntType) => f
+ case (t:ClockType) => f
+ case (t:BundleType) => {
+ var n = i
+ var ret:Option[Flip] = None
+ t.fields.foreach { x => {
+ if (n < get_size(x.tpe)) {
+ ret match {
+ case None => ret = Some(get_flip(x.tpe,n,times(x.flip,f)))
+ case ret => {}
+ }
+ } else { n = n - get_size(x.tpe) }
+ }}
+ ret.asInstanceOf[Some[Flip]].get
+ }
+ case (t:VectorType) => {
+ var n = i
+ var ret:Option[Flip] = None
+ for (j <- 0 until t.size) {
+ if (n < get_size(t.tpe)) {
+ ret = Some(get_flip(t.tpe,n,f))
+ } else {
+ n = n - get_size(t.tpe)
+ }
+ }
+ ret.asInstanceOf[Some[Flip]].get
+ }
+ }
+ x
+ }
+
+ def get_point (e:Expression) : Int = {
+ e match {
+ case (e:WRef) => 0
+ case (e:WSubField) => {
+ var i = 0
+ tpe(e.exp).asInstanceOf[BundleType].fields.find { f => {
+ val b = f.name == e.name
+ if (!b) { i = i + get_size(f.tpe)}
+ b
+ }}
+ i
+ }
+ case (e:WSubIndex) => e.value * get_size(e.tpe)
+ case (e:WSubAccess) => get_point(e.exp)
+ }
+ }
+
+//============== TYPES ================
+ def mux_type (e1:Expression,e2:Expression) : Type = mux_type(tpe(e1),tpe(e2))
+ def mux_type (t1:Type,t2:Type) : Type = {
+ if (wt(t1) == wt(t2)) {
+ (t1,t2) match {
+ case (t1:UIntType,t2:UIntType) => UIntType(UnknownWidth())
+ case (t1:SIntType,t2:SIntType) => SIntType(UnknownWidth())
+ case (t1:VectorType,t2:VectorType) => VectorType(mux_type(t1.tpe,t2.tpe),t1.size)
+ case (t1:BundleType,t2:BundleType) =>
+ BundleType((t1.fields,t2.fields).zipped.map((f1,f2) => {
+ Field(f1.name,f1.flip,mux_type(f1.tpe,f2.tpe))
+ }))
+ }
+ } else UnknownType()
+ }
+ def mux_type_and_widths (e1:Expression,e2:Expression) : Type = mux_type_and_widths(tpe(e1),tpe(e2))
+ def mux_type_and_widths (t1:Type,t2:Type) : Type = {
+ def wmax (w1:Width,w2:Width) : Width = {
+ (w1,w2) match {
+ case (w1:IntWidth,w2:IntWidth) => IntWidth(w1.width.max(w2.width))
+ case (w1,w2) => MaxWidth(Seq(w1,w2))
+ }
+ }
+ val wt1 = new WrappedType(t1)
+ val wt2 = new WrappedType(t2)
+ if (wt1 == wt2) {
+ (t1,t2) match {
+ case (t1:UIntType,t2:UIntType) => UIntType(wmax(t1.width,t2.width))
+ case (t1:SIntType,t2:SIntType) => SIntType(wmax(t1.width,t2.width))
+ case (t1:VectorType,t2:VectorType) => VectorType(mux_type_and_widths(t1.tpe,t2.tpe),t1.size)
+ case (t1:BundleType,t2:BundleType) => BundleType((t1.fields zip t2.fields).map{case (f1, f2) => Field(f1.name,f1.flip,mux_type_and_widths(f1.tpe,f2.tpe))})
+ }
+ } else UnknownType()
+ }
+ def module_type (m:Module) : Type = {
+ BundleType(m.ports.map(p => p.toField))
+ }
+ def sub_type (v:Type) : Type = {
+ v match {
+ case v:VectorType => v.tpe
+ case v => UnknownType()
+ }
+ }
+ def field_type (v:Type,s:String) : Type = {
+ v match {
+ case v:BundleType => {
+ val ft = v.fields.find(p => p.name == s)
+ ft match {
+ case ft:Some[Field] => ft.get.tpe
+ case ft => UnknownType()
+ }
+ }
+ case v => UnknownType()
+ }
+ }
+
+////=====================================
+ def widthBANG (t:Type) : Width = {
+ t match {
+ case t:UIntType => t.width
+ case t:SIntType => t.width
+ case t:ClockType => IntWidth(1)
+ case t => error("No width!")
+ }
+ }
+ def long_BANG (t:Type) : Long = {
+ (t) match {
+ case (t:UIntType) => t.width.as[IntWidth].get.width.toLong
+ case (t:SIntType) => t.width.as[IntWidth].get.width.toLong
+ case (t:BundleType) => {
+ var w = 0
+ for (f <- t.fields) { w = w + long_BANG(f.tpe).toInt }
+ w
+ }
+ case (t:VectorType) => t.size * long_BANG(t.tpe)
+ case (t:ClockType) => 1
+ }
+ }
+// =================================
+ def error(str:String) = throw new FIRRTLException(str)
+ def debug(node: AST)(implicit flags: FlagMap): String = {
+ if (!flags.isEmpty) {
+ var str = ""
+ if (flags("types")) {
+ val tpe = node.getType
+ tpe match {
+ case t:UnknownType => str += s"@<t:${tpe.wipeWidth.serialize}>"
+ }
+ }
+ str
+ }
+ else {
+ ""
+ }
+ }
+
+ implicit class BigIntUtils(bi: BigInt){
+ def serialize(implicit flags: FlagMap = FlagMap): String =
+ if (bi < BigInt(0)) "\"h" + bi.toString(16).substring(1) + "\""
+ else "\"h" + bi.toString(16) + "\""
+ }
+
+ implicit class ASTUtils(ast: AST) {
+ def getType(): Type =
+ ast match {
+ case e: Expression => e.getType
+ case s: Stmt => s.getType
+ //case f: Field => f.getType
+ case t: Type => t.getType
+ case p: Port => p.getType
+ case _ => UnknownType()
+ }
+ }
+
+ implicit class PrimOpUtils(op: PrimOp) {
+ def serialize(implicit flags: FlagMap = FlagMap): String = op.getString
+ }
+
+//// =============== EXPANSION FUNCTIONS ================
+ def get_size (t:Type) : Int = {
+ t match {
+ case (t:BundleType) => {
+ var sum = 0
+ for (f <- t.fields) {
+ sum = sum + get_size(f.tpe)
+ }
+ sum
+ }
+ case (t:VectorType) => t.size * get_size(t.tpe)
+ case (t) => 1
+ }
+ }
+ def get_valid_points (t1:Type,t2:Type,flip1:Flip,flip2:Flip) : Seq[(Int,Int)] = {
+ //;println_all(["Inside with t1:" t1 ",t2:" t2 ",f1:" flip1 ",f2:" flip2])
+ (t1,t2) match {
+ case (t1:UIntType,t2:UIntType) => if (flip1 == flip2) Seq((0, 0)) else Seq()
+ case (t1:SIntType,t2:SIntType) => if (flip1 == flip2) Seq((0, 0)) else Seq()
+ case (t1:BundleType,t2:BundleType) => {
+ val points = ArrayBuffer[(Int,Int)]()
+ var ilen = 0
+ var jlen = 0
+ for (i <- 0 until t1.fields.size) {
+ for (j <- 0 until t2.fields.size) {
+ val f1 = t1.fields(i)
+ val f2 = t2.fields(j)
+ if (f1.name == f2.name) {
+ val ls = get_valid_points(f1.tpe,f2.tpe,times(flip1, f1.flip),times(flip2, f2.flip))
+ for (x <- ls) {
+ points += ((x._1 + ilen, x._2 + jlen))
+ }
+ }
+ jlen = jlen + get_size(t2.fields(j).tpe)
+ }
+ ilen = ilen + get_size(t1.fields(i).tpe)
+ jlen = 0
+ }
+ points
+ }
+ case (t1:VectorType,t2:VectorType) => {
+ val points = ArrayBuffer[(Int,Int)]()
+ var ilen = 0
+ var jlen = 0
+ for (i <- 0 until scala.math.min(t1.size,t2.size)) {
+ val ls = get_valid_points(t1.tpe,t2.tpe,flip1,flip2)
+ for (x <- ls) {
+ val y = ((x._1 + ilen), (x._2 + jlen))
+ points += y
+ }
+ ilen = ilen + get_size(t1.tpe)
+ jlen = jlen + get_size(t2.tpe)
+ }
+ points
+ }
+ }
+ }
+// =========== GENDER/FLIP UTILS ============
+ def swap (g:Gender) : Gender = {
+ g match {
+ case UNKNOWNGENDER => UNKNOWNGENDER
+ case MALE => FEMALE
+ case FEMALE => MALE
+ case BIGENDER => BIGENDER
+ }
+ }
+ def swap (d:Direction) : Direction = {
+ d match {
+ case OUTPUT => INPUT
+ case INPUT => OUTPUT
+ }
+ }
+ def swap (f:Flip) : Flip = {
+ f match {
+ case DEFAULT => REVERSE
+ case REVERSE => DEFAULT
+ }
+ }
+ def to_dir (g:Gender) : Direction = {
+ g match {
+ case MALE => INPUT
+ case FEMALE => OUTPUT
+ }
+ }
+ def to_gender (d:Direction) : Gender = {
+ d match {
+ case INPUT => MALE
+ case OUTPUT => FEMALE
+ }
+ }
+ def field_flip (v:Type,s:String) : Flip = {
+ v match {
+ case v:BundleType => {
+ val ft = v.fields.find {p => p.name == s}
+ ft match {
+ case ft:Some[Field] => ft.get.flip
+ case ft => DEFAULT
+ }
+ }
+ case v => DEFAULT
+ }
+ }
+ def get_field (v:Type,s:String) : Field = {
+ v match {
+ case v:BundleType => {
+ val ft = v.fields.find {p => p.name == s}
+ ft match {
+ case ft:Some[Field] => ft.get
+ case ft => error("Shouldn't be here"); Field("blah",DEFAULT,UnknownType())
+ }
+ }
+ case v => error("Shouldn't be here"); Field("blah",DEFAULT,UnknownType())
+ }
+ }
+ def times (flip:Flip,d:Direction) : Direction = times(flip, d)
+ def times (d:Direction,flip:Flip) : Direction = {
+ flip match {
+ case DEFAULT => d
+ case REVERSE => swap(d)
+ }
+ }
+ def times (g:Gender,flip:Flip) : Gender = times(flip, g)
+ def times (flip:Flip,g:Gender) : Gender = {
+ flip match {
+ case DEFAULT => g
+ case REVERSE => swap(g)
+ }
+ }
+ def times (f1:Flip,f2:Flip) : Flip = {
+ f2 match {
+ case DEFAULT => f1
+ case REVERSE => swap(f1)
+ }
+ }
+
+
+// =========== ACCESSORS =========
+ def info (s:Stmt) : Info = {
+ s match {
+ case s:DefWire => s.info
+ case s:DefPoison => s.info
+ case s:DefRegister => s.info
+ case s:DefInstance => s.info
+ case s:WDefInstance => s.info
+ case s:DefMemory => s.info
+ case s:DefNode => s.info
+ case s:Conditionally => s.info
+ case s:BulkConnect => s.info
+ case s:Connect => s.info
+ case s:IsInvalid => s.info
+ case s:Stop => s.info
+ case s:Print => s.info
+ case s:Begin => NoInfo
+ case s:Empty => NoInfo
+ }
+ }
+ def gender (e:Expression) : Gender = {
+ e match {
+ case e:WRef => e.gender
+ case e:WSubField => e.gender
+ case e:WSubIndex => e.gender
+ case e:WSubAccess => e.gender
+ case e:DoPrim => MALE
+ case e:UIntValue => MALE
+ case e:SIntValue => MALE
+ case e:Mux => MALE
+ case e:ValidIf => MALE
+ case e:WInvalid => MALE
+ case e => println(e); error("Shouldn't be here")
+ }}
+ def get_gender (s:Stmt) : Gender =
+ s match {
+ case s:DefWire => BIGENDER
+ case s:DefRegister => BIGENDER
+ case s:WDefInstance => MALE
+ case s:DefNode => MALE
+ case s:DefInstance => MALE
+ case s:DefPoison => UNKNOWNGENDER
+ case s:DefMemory => MALE
+ case s:Begin => UNKNOWNGENDER
+ case s:Connect => UNKNOWNGENDER
+ case s:BulkConnect => UNKNOWNGENDER
+ case s:Stop => UNKNOWNGENDER
+ case s:Print => UNKNOWNGENDER
+ case s:Empty => UNKNOWNGENDER
+ case s:IsInvalid => UNKNOWNGENDER
+ }
+ def get_gender (p:Port) : Gender =
+ if (p.direction == INPUT) MALE else FEMALE
+ def kind (e:Expression) : Kind =
+ e match {
+ case e:WRef => e.kind
+ case e:WSubField => kind(e.exp)
+ case e:WSubIndex => kind(e.exp)
+ case e => ExpKind()
+ }
+ def tpe (e:Expression) : Type =
+ e match {
+ case e:Ref => e.tpe
+ case e:SubField => e.tpe
+ case e:SubIndex => e.tpe
+ case e:SubAccess => e.tpe
+ case e:WRef => e.tpe
+ case e:WSubField => e.tpe
+ case e:WSubIndex => e.tpe
+ case e:WSubAccess => e.tpe
+ case e:DoPrim => e.tpe
+ case e:Mux => e.tpe
+ case e:ValidIf => e.tpe
+ case e:UIntValue => UIntType(e.width)
+ case e:SIntValue => SIntType(e.width)
+ case e:WVoid => UnknownType()
+ case e:WInvalid => UnknownType()
+ }
+ def get_type (s:Stmt) : Type = {
+ s match {
+ case s:DefWire => s.tpe
+ case s:DefPoison => s.tpe
+ case s:DefRegister => s.tpe
+ case s:DefNode => tpe(s.value)
+ case s:DefMemory => {
+ val depth = s.depth
+ val addr = Field("addr",DEFAULT,UIntType(IntWidth(ceil_log2(depth))))
+ val en = Field("en",DEFAULT,BoolType())
+ val clk = Field("clk",DEFAULT,ClockType())
+ val def_data = Field("data",DEFAULT,s.data_type)
+ val rev_data = Field("data",REVERSE,s.data_type)
+ val mask = Field("mask",DEFAULT,create_mask(s.data_type))
+ val wmode = Field("wmode",DEFAULT,UIntType(IntWidth(1)))
+ val rdata = Field("rdata",REVERSE,s.data_type)
+ val read_type = BundleType(Seq(rev_data,addr,en,clk))
+ val write_type = BundleType(Seq(def_data,mask,addr,en,clk))
+ val readwrite_type = BundleType(Seq(wmode,rdata,def_data,mask,addr,en,clk))
+
+ val mem_fields = ArrayBuffer[Field]()
+ s.readers.foreach {x => mem_fields += Field(x,REVERSE,read_type)}
+ s.writers.foreach {x => mem_fields += Field(x,REVERSE,write_type)}
+ s.readwriters.foreach {x => mem_fields += Field(x,REVERSE,readwrite_type)}
+ BundleType(mem_fields)
+ }
+ case s:DefInstance => UnknownType()
+ case s:WDefInstance => s.tpe
+ case _ => UnknownType()
+ }}
+ def get_name (s:Stmt) : String = {
+ s match {
+ case s:DefWire => s.name
+ case s:DefPoison => s.name
+ case s:DefRegister => s.name
+ case s:DefNode => s.name
+ case s:DefMemory => s.name
+ case s:DefInstance => s.name
+ case s:WDefInstance => s.name
+ case _ => error("Shouldn't be here"); "blah"
+ }}
+ def get_info (s:Stmt) : Info = {
+ s match {
+ case s:DefWire => s.info
+ case s:DefPoison => s.info
+ case s:DefRegister => s.info
+ case s:DefInstance => s.info
+ case s:WDefInstance => s.info
+ case s:DefMemory => s.info
+ case s:DefNode => s.info
+ case s:Conditionally => s.info
+ case s:BulkConnect => s.info
+ case s:Connect => s.info
+ case s:IsInvalid => s.info
+ case s:Stop => s.info
+ case s:Print => s.info
+ case _ => NoInfo
+ }}
+
- // Is there a more elegant way to do this?
- private type FlagMap = Map[Symbol, Boolean]
- private val FlagMap = Map[Symbol, Boolean]().withDefaultValue(false)
-
- def debug(node: AST)(implicit flags: FlagMap): String = {
- if (!flags.isEmpty) {
- var str = ""
- if (flags('types)) {
- val tpe = node.getType
- if( tpe != UnknownType ) str += s"@<t:${tpe.wipeWidth.serialize}>"
- }
- str
- }
- else {
- ""
- }
- }
-
- implicit class BigIntUtils(bi: BigInt){
- def serialize(implicit flags: FlagMap = FlagMap): String =
- "\"h" + bi.toString(16) + "\""
- }
-
- implicit class ASTUtils(ast: AST) {
- def getType(): Type =
- ast match {
- case e: Expression => e.getType
- case s: Stmt => s.getType
- //case f: Field => f.getType
- case t: Type => t.getType
- case p: Port => p.getType
- case _ => UnknownType
- }
- }
-
- implicit class PrimOpUtils(op: PrimOp) {
- def serialize(implicit flags: FlagMap = FlagMap): String = op.getString
- }
-
- implicit class ExpUtils(exp: Expression) {
- def serialize(implicit flags: FlagMap = FlagMap): String = {
- val ret = exp match {
- case v: UIntValue => s"UInt${v.width.serialize}(${v.value.serialize})"
- case v: SIntValue => s"SInt${v.width.serialize}(${v.value.serialize})"
- case r: Ref => r.name
- case s: SubField => s"${s.exp.serialize}.${s.name}"
- case s: SubIndex => s"${s.exp.serialize}[${s.value}]"
- case s: SubAccess => s"${s.exp.serialize}[${s.index.serialize}]"
- case m: Mux => s"mux(${m.cond.serialize}, ${m.tval.serialize}, ${m.fval.serialize})"
- case v: ValidIf => s"validif(${v.cond.serialize}, ${v.value.serialize})"
- case p: DoPrim =>
- s"${p.op.serialize}(" + (p.args.map(_.serialize) ++ p.consts.map(_.toString)).mkString(", ") + ")"
- }
- ret + debug(exp)
- }
-
- def map(f: Expression => Expression): Expression =
+// =============== MAPPERS ===================
+ def sMap(f:Stmt => Stmt, stmt: Stmt): Stmt =
+ stmt match {
+ case w: Conditionally => Conditionally(w.info, w.pred, f(w.conseq), f(w.alt))
+ case b: Begin => {
+ val stmtsx = ArrayBuffer[Stmt]()
+ for (i <- 0 until b.stmts.size) {
+ stmtsx += f(b.stmts(i))
+ }
+ Begin(stmtsx)
+ }
+ case s: Stmt => s
+ }
+ def eMap(f:Expression => Expression, stmt:Stmt) : Stmt =
+ stmt match {
+ case r: DefRegister => DefRegister(r.info, r.name, r.tpe, f(r.clock), f(r.reset), f(r.init))
+ case n: DefNode => DefNode(n.info, n.name, f(n.value))
+ case c: Connect => Connect(c.info, f(c.loc), f(c.exp))
+ case b: BulkConnect => BulkConnect(b.info, f(b.loc), f(b.exp))
+ case w: Conditionally => Conditionally(w.info, f(w.pred), w.conseq, w.alt)
+ case i: IsInvalid => IsInvalid(i.info, f(i.exp))
+ case s: Stop => Stop(s.info, s.ret, f(s.clk), f(s.en))
+ case p: Print => Print(p.info, p.string, p.args.map(f), f(p.clk), f(p.en))
+ case c: CDefMPort => CDefMPort(c.info,c.name,c.tpe,c.mem,c.exps.map(f),c.direction)
+ case s: Stmt => s
+ }
+ def eMap(f: Expression => Expression, exp:Expression): Expression =
exp match {
case s: SubField => SubField(f(s.exp), s.name, s.tpe)
case s: SubIndex => SubIndex(f(s.exp), s.value, s.tpe)
@@ -82,240 +644,678 @@ object Utils {
case m: Mux => Mux(f(m.cond), f(m.tval), f(m.fval), m.tpe)
case v: ValidIf => ValidIf(f(v.cond), f(v.value), v.tpe)
case p: DoPrim => DoPrim(p.op, p.args.map(f), p.consts, p.tpe)
+ case s: WSubField => WSubField(f(s.exp), s.name, s.tpe, s.gender)
+ case s: WSubIndex => WSubIndex(f(s.exp), s.value, s.tpe, s.gender)
+ case s: WSubAccess => WSubAccess(f(s.exp), f(s.index), s.tpe, s.gender)
case e: Expression => e
}
+ def tMap (f: Type => Type, t:Type):Type = {
+ t match {
+ case t:BundleType => BundleType(t.fields.map(p => Field(p.name, p.flip, f(p.tpe))))
+ case t:VectorType => VectorType(f(t.tpe), t.size)
+ case t => t
+ }
+ }
+ def tMap (f: Type => Type, c:Expression) : Expression = {
+ c match {
+ case c:DoPrim => DoPrim(c.op,c.args,c.consts,f(c.tpe))
+ case c:Mux => Mux(c.cond,c.tval,c.fval,f(c.tpe))
+ case c:ValidIf => ValidIf(c.cond,c.value,f(c.tpe))
+ case c:WRef => WRef(c.name,f(c.tpe),c.kind,c.gender)
+ case c:WSubField => WSubField(c.exp,c.name,f(c.tpe),c.gender)
+ case c:WSubIndex => WSubIndex(c.exp,c.value,f(c.tpe),c.gender)
+ case c:WSubAccess => WSubAccess(c.exp,c.index,f(c.tpe),c.gender)
+ case c => c
+ }
+ }
+ def tMap (f: Type => Type, c:Stmt) : Stmt = {
+ c match {
+ case c:DefPoison => DefPoison(c.info,c.name,f(c.tpe))
+ case c:DefWire => DefWire(c.info,c.name,f(c.tpe))
+ case c:DefRegister => DefRegister(c.info,c.name,f(c.tpe),c.clock,c.reset,c.init)
+ case c:DefMemory => DefMemory(c.info,c.name, f(c.data_type), c.depth, c.write_latency, c.read_latency, c.readers, c.writers, c.readwriters)
+ case c:CDefMemory => CDefMemory(c.info,c.name, f(c.tpe), c.size, c.seq)
+ case c:CDefMPort => CDefMPort(c.info,c.name, f(c.tpe), c.mem, c.exps,c.direction)
+ case c => c
+ }
+ }
+ def wMap (f: Width => Width, c:Expression) : Expression = {
+ c match {
+ case c:UIntValue => UIntValue(c.value,f(c.width))
+ case c:SIntValue => SIntValue(c.value,f(c.width))
+ case c => c
+ }
+ }
+ def wMap (f: Width => Width, c:Type) : Type = {
+ c match {
+ case c:UIntType => UIntType(f(c.width))
+ case c:SIntType => SIntType(f(c.width))
+ case c => c
+ }
+ }
+ def wMap (f: Width => Width, w:Width) : Width = {
+ w match {
+ case w:MaxWidth => MaxWidth(w.args.map(f))
+ case w:MinWidth => MinWidth(w.args.map(f))
+ case w:PlusWidth => PlusWidth(f(w.arg1),f(w.arg2))
+ case w:MinusWidth => MinusWidth(f(w.arg1),f(w.arg2))
+ case w:ExpWidth => ExpWidth(f(w.arg1))
+ case w => w
+ }
+ }
+ def stMap (f: String => String, c:Stmt) : Stmt = {
+ c match {
+ case (c:DefWire) => DefWire(c.info,f(c.name),c.tpe)
+ case (c:DefPoison) => DefPoison(c.info,f(c.name),c.tpe)
+ case (c:DefRegister) => DefRegister(c.info,f(c.name), c.tpe, c.clock, c.reset, c.init)
+ case (c:DefMemory) => DefMemory(c.info,f(c.name), c.data_type, c.depth, c.write_latency, c.read_latency, c.readers, c.writers, c.readwriters)
+ case (c:DefNode) => DefNode(c.info,f(c.name),c.value)
+ case (c:DefInstance) => DefInstance(c.info,f(c.name), c.module)
+ case (c:WDefInstance) => WDefInstance(c.info,f(c.name), c.module,c.tpe)
+ case (c:CDefMemory) => CDefMemory(c.info,f(c.name),c.tpe,c.size,c.seq)
+ case (c:CDefMPort) => CDefMPort(c.info,f(c.name),c.tpe,c.mem,c.exps,c.direction)
+ case (c) => c
+ }
+ }
+ def mapr (f: Width => Width, t:Type) : Type = {
+ def apply_t (t:Type) : Type = wMap(f,tMap(apply_t _,t))
+ apply_t(t)
+ }
+ def mapr (f: Width => Width, s:Stmt) : Stmt = {
+ def apply_t (t:Type) : Type = mapr(f,t)
+ def apply_e (e:Expression) : Expression =
+ wMap(f,tMap(apply_t _,eMap(apply_e _,e)))
+ def apply_s (s:Stmt) : Stmt =
+ tMap(apply_t _,eMap(apply_e _,sMap(apply_s _,s)))
+ apply_s(s)
+ }
+ val ONE = IntWidth(1)
+ //def digits (s:String) : Boolean {
+ // val digits = "0123456789"
+ // var yes:Boolean = true
+ // for (c <- s) {
+ // if !digits.contains(c) : yes = false
+ // }
+ // yes
+ //}
+ //def generated (s:String) : Option[Int] = {
+ // (1 until s.length() - 1).find{
+ // i => {
+ // val sub = s.substring(i + 1)
+ // s.substring(i,i).equals("_") & digits(sub) & !s.substring(i - 1,i-1).equals("_")
+ // }
+ // }
+ //}
+ //def get-sym-hash (m:InModule) : LinkedHashMap[String,Int] = { get-sym-hash(m,Seq()) }
+ //def get-sym-hash (m:InModule,keywords:Seq[String]) : LinkedHashMap[String,Int] = {
+ // val sym-hash = LinkedHashMap[String,Int]()
+ // for (k <- keywords) { sym-hash += (k -> 0) }
+ // def add-name (s:String) : String = {
+ // val sx = to-string(s)
+ // val ix = generated(sx)
+ // ix match {
+ // case (i:False) => {
+ // if (sym_hash.contains(s)) {
+ // val num = sym-hash(s)
+ // sym-hash += (s -> max(num,0))
+ // } else {
+ // sym-hash += (s -> 0)
+ // }
+ // }
+ // case (i:Int) => {
+ // val name = sx.substring(0,i)
+ // val digit = to-int(substring(sx,i + 1))
+ // if key?(sym-hash,name) :
+ // val num = sym-hash[name]
+ // sym-hash[name] = max(num,digit)
+ // else :
+ // sym-hash[name] = digit
+ // }
+ // s
+ //
+ // defn to-port (p:Port) : add-name(name(p))
+ // defn to-stmt (s:Stmt) -> Stmt :
+ // map{to-stmt,_} $ map(add-name,s)
+ //
+ // to-stmt(body(m))
+ // map(to-port,ports(m))
+ // sym-hash
+ //private trait StmtMagnet {
+ // def map(stmt: Stmt): Stmt
+ //}
+ //private object StmtMagnet {
+ // implicit def forStmt(f: Stmt => Stmt) = new StmtMagnet {
+ // override def map(stmt: Stmt): Stmt =
+ // stmt match {
+ // case w: Conditionally => Conditionally(w.info, w.pred, f(w.conseq), f(w.alt))
+ // case b: Begin => Begin(b.stmts.map(f))
+ // case s: Stmt => s
+ // }
+ // }
+ // implicit def forExp(f: Expression => Expression) = new StmtMagnet {
+ // override def map(stmt: Stmt): Stmt =
+ // stmt match {
+ // case r: DefRegister => DefRegister(r.info, r.name, r.tpe, f(r.clock), f(r.reset), f(r.init))
+ // case n: DefNode => DefNode(n.info, n.name, f(n.value))
+ // case c: Connect => Connect(c.info, f(c.loc), f(c.exp))
+ // case b: BulkConnect => BulkConnect(b.info, f(b.loc), f(b.exp))
+ // case w: Conditionally => Conditionally(w.info, f(w.pred), w.conseq, w.alt)
+ // case i: IsInvalid => IsInvalid(i.info, f(i.exp))
+ // case s: Stop => Stop(s.info, s.ret, f(s.clk), f(s.en))
+ // case p: Print => Print(p.info, p.string, p.args.map(f), f(p.clk), f(p.en))
+ // case s: Stmt => s
+ // }
+ // }
+ //}
+ implicit class ExpUtils(exp: Expression) {
+ def serialize(implicit flags: FlagMap = FlagMap): String = {
+ val ret = exp match {
+ case v: UIntValue => s"UInt${v.width.serialize}(${v.value.serialize})"
+ case v: SIntValue => s"SInt${v.width.serialize}(${v.value.serialize})"
+ case r: Ref => r.name
+ case s: SubField => s"${s.exp.serialize}.${s.name}"
+ case s: SubIndex => s"${s.exp.serialize}[${s.value}]"
+ case s: SubAccess => s"${s.exp.serialize}[${s.index.serialize}]"
+ case m: Mux => s"mux(${m.cond.serialize}, ${m.tval.serialize}, ${m.fval.serialize})"
+ case v: ValidIf => s"validif(${v.cond.serialize}, ${v.value.serialize})"
+ case p: DoPrim =>
+ s"${p.op.serialize}(" + (p.args.map(_.serialize) ++ p.consts.map(_.toString)).mkString(", ") + ")"
+ case r: WRef => r.name
+ case s: WSubField => s"${s.exp.serialize}.${s.name}"
+ case s: WSubIndex => s"${s.exp.serialize}[${s.value}]"
+ case s: WSubAccess => s"${s.exp.serialize}[${s.index.serialize}]"
+ case r: WVoid => "VOID"
+ }
+ ret + debug(exp)
+ }
+ }
- def getType(): Type = {
- exp match {
- case v: UIntValue => UIntType(UnknownWidth)
- case v: SIntValue => SIntType(UnknownWidth)
- case r: Ref => r.tpe
- case s: SubField => s.tpe
- case s: SubIndex => s.tpe
- case s: SubAccess => s.tpe
- case p: DoPrim => p.tpe
- case m: Mux => m.tpe
- case v: ValidIf => v.tpe
- }
- }
- }
-
- // Some Scala implicit magic to solve type erasure on Stmt map function overloading
- private trait StmtMagnet {
- def map(stmt: Stmt): Stmt
- }
- private object StmtMagnet {
- implicit def forStmt(f: Stmt => Stmt) = new StmtMagnet {
- override def map(stmt: Stmt): Stmt =
- stmt match {
- case w: Conditionally => Conditionally(w.info, w.pred, f(w.conseq), f(w.alt))
- case b: Begin => Begin(b.stmts.map(f))
- case s: Stmt => s
- }
- }
- implicit def forExp(f: Expression => Expression) = new StmtMagnet {
- override def map(stmt: Stmt): Stmt =
- stmt match {
- case r: DefRegister => DefRegister(r.info, r.name, r.tpe, f(r.clock), f(r.reset), f(r.init))
- case n: DefNode => DefNode(n.info, n.name, f(n.value))
- case c: Connect => Connect(c.info, f(c.loc), f(c.exp))
- case b: BulkConnect => BulkConnect(b.info, f(b.loc), f(b.exp))
- case w: Conditionally => Conditionally(w.info, f(w.pred), w.conseq, w.alt)
- case i: IsInvalid => IsInvalid(i.info, f(i.exp))
- case s: Stop => Stop(s.info, s.ret, f(s.clk), f(s.en))
- case p: Print => Print(p.info, p.string, p.args.map(f), f(p.clk), f(p.en))
- case s: Stmt => s
- }
- }
- }
-
- implicit class StmtUtils(stmt: Stmt) {
- def serialize(implicit flags: FlagMap = FlagMap): String =
- {
- var ret = stmt match {
- case w: DefWire => s"wire ${w.name} : ${w.tpe.serialize}"
- case r: DefRegister =>
- val str = new StringBuilder(s"reg ${r.name} : ${r.tpe.serialize}, ${r.clock.serialize} with : ")
- withIndent {
- str ++= newline + s"reset => (${r.reset.serialize}, ${r.init.serialize})"
- }
- str
- case i: DefInstance => s"inst ${i.name} of ${i.module}"
- case m: DefMemory => {
- val str = new StringBuilder(s"mem ${m.name} : " + newline)
- withIndent {
- str ++= s"data-type => ${m.dataType.serialize}" + newline +
- s"depth => ${m.depth}" + newline +
- s"read-latency => ${m.readLatency}" + newline +
- s"write-latency => ${m.writeLatency}" + newline +
- (if (m.readers.nonEmpty) m.readers.map(r => s"reader => ${r}").mkString(newline) + newline
- else "") +
- (if (m.writers.nonEmpty) m.writers.map(w => s"writer => ${w}").mkString(newline) + newline
- else "") +
- (if (m.readwriters.nonEmpty) m.readwriters.map(rw => s"readwriter => ${rw}").mkString(newline) + newline
- else "") +
- s"read-under-write => undefined"
+ // def map(f: Expression => Expression): Expression =
+ // exp match {
+ // case s: SubField => SubField(f(s.exp), s.name, s.tpe)
+ // case s: SubIndex => SubIndex(f(s.exp), s.value, s.tpe)
+ // case s: SubAccess => SubAccess(f(s.exp), f(s.index), s.tpe)
+ // case m: Mux => Mux(f(m.cond), f(m.tval), f(m.fval), m.tpe)
+ // case v: ValidIf => ValidIf(f(v.cond), f(v.value), v.tpe)
+ // case p: DoPrim => DoPrim(p.op, p.args.map(f), p.consts, p.tpe)
+ // case s: WSubField => SubField(f(s.exp), s.name, s.tpe, s.gender)
+ // case s: WSubIndex => SubIndex(f(s.exp), s.value, s.tpe, s.gender)
+ // case s: WSubAccess => SubAccess(f(s.exp), f(s.index), s.tpe, s.gender)
+ // case e: Expression => e
+ // }
+ //}
+
+ implicit class StmtUtils(stmt: Stmt) {
+ def serialize(implicit flags: FlagMap = FlagMap): String =
+ {
+ var ret = stmt match {
+ case w: DefWire => s"wire ${w.name} : ${w.tpe.serialize}"
+ case r: DefRegister =>
+ val str = new StringBuilder(s"reg ${r.name} : ${r.tpe.serialize}, ${r.clock.serialize} with : ")
+ withIndent {
+ str ++= newline + s"reset => (${r.reset.serialize}, ${r.init.serialize})"
+ }
+ str
+ case i: DefInstance => s"inst ${i.name} of ${i.module}"
+ case i: WDefInstance => s"inst ${i.name} of ${i.module}"
+ case m: DefMemory => {
+ val str = new StringBuilder(s"mem ${m.name} : ")
+ withIndent {
+ str ++= newline +
+ s"data-type => ${m.data_type.serialize}" + newline +
+ s"depth => ${m.depth}" + newline +
+ s"read-latency => ${m.read_latency}" + newline +
+ s"write-latency => ${m.write_latency}" + newline +
+ (if (m.readers.nonEmpty) m.readers.map(r => s"reader => ${r}").mkString(newline) + newline
+ else "") +
+ (if (m.writers.nonEmpty) m.writers.map(w => s"writer => ${w}").mkString(newline) + newline
+ else "") +
+ (if (m.readwriters.nonEmpty) m.readwriters.map(rw => s"readwriter => ${rw}").mkString(newline) + newline
+ else "") +
+ s"read-under-write => undefined"
+ }
+ str.result
+ }
+ case n: DefNode => s"node ${n.name} = ${n.value.serialize}"
+ case c: Connect => s"${c.loc.serialize} <= ${c.exp.serialize}"
+ case b: BulkConnect => s"${b.loc.serialize} <- ${b.exp.serialize}"
+ case w: Conditionally => {
+ var str = new StringBuilder(s"when ${w.pred.serialize} : ")
+ withIndent { str ++= newline + w.conseq.serialize }
+ w.alt match {
+ case s:Empty => str.result
+ case s => {
+ str ++= newline + "else :"
+ withIndent { str ++= newline + w.alt.serialize }
+ str.result
+ }
+ }
+ }
+ case b: Begin => {
+ val s = new StringBuilder
+ for (i <- 0 until b.stmts.size) {
+ if (i != 0) s ++= newline ++ b.stmts(i).serialize
+ else s ++= b.stmts(i).serialize
+ }
+ s.result + debug(b)
+ }
+ case i: IsInvalid => s"${i.exp.serialize} is invalid"
+ case s: Stop => s"stop(${s.clk.serialize}, ${s.en.serialize}, ${s.ret})"
+ case p: Print => {
+ val q = '"'.toString
+ s"printf(${p.clk.serialize}, ${p.en.serialize}, ${q}${p.string}${q}" +
+ (if (p.args.nonEmpty) p.args.map(_.serialize).mkString(", ", ", ", "") else "") + ")"
+ }
+ case s:Empty => "skip"
+ case s:CDefMemory => {
+ if (s.seq) s"smem ${s.name} : ${s.tpe} [${s.size}]"
+ else s"cmem ${s.name} : ${s.tpe} [${s.size}]"
+ }
+ case s:CDefMPort => {
+ val dir = s.direction match {
+ case MInfer => "infer"
+ case MRead => "read"
+ case MWrite => "write"
+ case MReadWrite => "rdwr"
+ }
+ s"${dir} mport ${s.name} = ${s.mem}[${s.exps(0)}], s.exps(1)"
+ }
+ }
+ ret + debug(stmt)
+ }
+
+ // Using implicit types to allow overloading of function type to map, see StmtMagnet above
+ //def map[T](f: T => T)(implicit magnet: (T => T) => StmtMagnet): Stmt = magnet(f).map(stmt)
+
+ def getType(): Type =
+ stmt match {
+ case s: DefWire => s.tpe
+ case s: DefRegister => s.tpe
+ case s: DefMemory => s.data_type
+ case _ => UnknownType()
+ }
+
+ def getInfo: Info =
+ stmt match {
+ case s: DefWire => s.info
+ case s: DefPoison => s.info
+ case s: DefRegister => s.info
+ case s: DefInstance => s.info
+ case s: DefMemory => s.info
+ case s: DefNode => s.info
+ case s: Conditionally => s.info
+ case s: BulkConnect => s.info
+ case s: Connect => s.info
+ case s: IsInvalid => s.info
+ case s: Stop => s.info
+ case s: Print => s.info
+ case _ => NoInfo
+ }
+ }
+
+ implicit class WidthUtils(w: Width) {
+ def serialize(implicit flags: FlagMap = FlagMap): String = {
+ val s = w match {
+ case w:UnknownWidth => "" //"?"
+ case w: IntWidth => s"<${w.width.toString}>"
+ case w: VarWidth => s"<${w.name}>"
+ }
+ s + debug(w)
+ }
+ }
+
+ implicit class FlipUtils(f: Flip) {
+ def serialize(implicit flags: FlagMap = FlagMap): String = {
+ val s = f match {
+ case REVERSE => "flip "
+ case DEFAULT => ""
+ }
+ s + debug(f)
+ }
+ def flip(): Flip = {
+ f match {
+ case REVERSE => DEFAULT
+ case DEFAULT => REVERSE
+ }
+ }
+
+ def toDirection(): Direction = {
+ f match {
+ case DEFAULT => OUTPUT
+ case REVERSE => INPUT
+ }
+ }
+ }
+
+ implicit class FieldUtils(field: Field) {
+ def serialize(implicit flags: FlagMap = FlagMap): String =
+ s"${field.flip.serialize}${field.name} : ${field.tpe.serialize}" + debug(field)
+ def flip(): Field = Field(field.name, field.flip.flip, field.tpe)
+
+ def getType(): Type = field.tpe
+ def toPort(): Port = Port(NoInfo, field.name, field.flip.toDirection, field.tpe)
+ }
+
+ implicit class TypeUtils(t: Type) {
+ def serialize(implicit flags: FlagMap = FlagMap): String = {
+ val commas = ", " // for mkString in BundleType
+ val s = t match {
+ case c:ClockType => "Clock"
+ //case UnknownType => "UnknownType"
+ case u:UnknownType => "?"
+ case t: UIntType => s"UInt${t.width.serialize}"
+ case t: SIntType => s"SInt${t.width.serialize}"
+ case t: BundleType => s"{ ${t.fields.map(_.serialize).mkString(commas)}}"
+ case t: VectorType => s"${t.tpe.serialize}[${t.size}]"
+ }
+ s + debug(t)
+ }
+
+ def getType(): Type =
+ t match {
+ case v: VectorType => v.tpe
+ case tpe: Type => UnknownType()
+ }
+
+ def wipeWidth(): Type =
+ t match {
+ case t: UIntType => UIntType(UnknownWidth())
+ case t: SIntType => SIntType(UnknownWidth())
+ case _ => t
+ }
+ }
+
+ implicit class DirectionUtils(d: Direction) {
+ def serialize(implicit flags: FlagMap = FlagMap): String = {
+ val s = d match {
+ case INPUT => "input"
+ case OUTPUT => "output"
+ }
+ s + debug(d)
+ }
+ def toFlip(): Flip = {
+ d match {
+ case INPUT => REVERSE
+ case OUTPUT => DEFAULT
+ }
+ }
+ }
+
+ implicit class PortUtils(p: Port) {
+ def serialize(implicit flags: FlagMap = FlagMap): String =
+ s"${p.direction.serialize} ${p.name} : ${p.tpe.serialize}" + debug(p)
+ def getType(): Type = p.tpe
+ def toField(): Field = Field(p.name, p.direction.toFlip, p.tpe)
+ }
+
+ implicit class ModuleUtils(m: Module) {
+ def serialize(implicit flags: FlagMap = FlagMap): String = {
+ m match {
+ case m:InModule => {
+ var s = new StringBuilder(s"module ${m.name} : ")
+ withIndent {
+ s ++= m.ports.map(newline ++ _.serialize).mkString
+ s ++= newline ++ m.body.serialize
+ }
+ s ++= debug(m)
+ s.toString
}
- str.result
- }
- case n: DefNode => s"node ${n.name} = ${n.value.serialize}"
- case c: Connect => s"${c.loc.serialize} <= ${c.exp.serialize}"
- case b: BulkConnect => s"${b.loc.serialize} <- ${b.exp.serialize}"
- case w: Conditionally => {
- var str = new StringBuilder(s"when ${w.pred.serialize} : ")
- withIndent { str ++= w.conseq.serialize }
- if( w.alt != Empty ) {
- str ++= newline + "else :"
- withIndent { str ++= w.alt.serialize }
+ case m:ExModule => {
+ var s = new StringBuilder(s"extmodule ${m.name} : ")
+ withIndent {
+ s ++= m.ports.map(newline ++ _.serialize).mkString
+ s ++= newline
+ }
+ s ++= debug(m)
+ s.toString
}
- str.result
- }
- case b: Begin => {
- val s = new StringBuilder
- b.stmts.foreach { s ++= newline ++ _.serialize }
- s.result + debug(b)
- }
- case i: IsInvalid => s"${i.exp.serialize} is invalid"
- case s: Stop => s"stop(${s.clk.serialize}, ${s.en.serialize}, ${s.ret})"
- case p: Print => s"printf(${p.clk.serialize}, ${p.en.serialize}, ${p.string}" +
- (if (p.args.nonEmpty) p.args.map(_.serialize).mkString(", ", ", ", "") else "") + ")"
- case Empty => "skip"
- }
- ret + debug(stmt)
- }
-
- // Using implicit types to allow overloading of function type to map, see StmtMagnet above
- def map[T](f: T => T)(implicit magnet: (T => T) => StmtMagnet): Stmt = magnet(f).map(stmt)
-
- def getType(): Type =
- stmt match {
- case s: DefWire => s.tpe
- case s: DefRegister => s.tpe
- case s: DefMemory => s.dataType
- case _ => UnknownType
- }
- }
-
- implicit class WidthUtils(w: Width) {
- def serialize(implicit flags: FlagMap = FlagMap): String = {
- val s = w match {
- case UnknownWidth => "" //"?"
- case w: IntWidth => s"<${w.width.toString}>"
- }
- s + debug(w)
- }
- }
-
- implicit class FlipUtils(f: Flip) {
- def serialize(implicit flags: FlagMap = FlagMap): String = {
- val s = f match {
- case Reverse => "flip "
- case Default => ""
- }
- s + debug(f)
- }
- def flip(): Flip = {
- f match {
- case Reverse => Default
- case Default => Reverse
- }
- }
-
- def toDirection(): Direction = {
- f match {
- case Default => Output
- case Reverse => Input
- }
- }
- }
-
- implicit class FieldUtils(field: Field) {
- def serialize(implicit flags: FlagMap = FlagMap): String =
- s"${field.flip.serialize}${field.name} : ${field.tpe.serialize}" + debug(field)
- def flip(): Field = Field(field.name, field.flip.flip, field.tpe)
-
- def getType(): Type = field.tpe
- def toPort(): Port = Port(NoInfo, field.name, field.flip.toDirection, field.tpe)
- }
-
- implicit class TypeUtils(t: Type) {
- def serialize(implicit flags: FlagMap = FlagMap): String = {
- val commas = ", " // for mkString in BundleType
- val s = t match {
- case ClockType => "Clock"
- //case UnknownType => "UnknownType"
- case UnknownType => "?"
- case t: UIntType => s"UInt${t.width.serialize}"
- case t: SIntType => s"SInt${t.width.serialize}"
- case t: BundleType => s"{ ${t.fields.map(_.serialize).mkString(commas)}}"
- case t: VectorType => s"${t.tpe.serialize}[${t.size}]"
- }
- s + debug(t)
- }
-
- def getType(): Type =
- t match {
- case v: VectorType => v.tpe
- case tpe: Type => UnknownType
- }
+ }
+ }
+ }
- def wipeWidth(): Type =
- t match {
- case t: UIntType => UIntType(UnknownWidth)
- case t: SIntType => SIntType(UnknownWidth)
- case _ => t
- }
- }
-
- implicit class DirectionUtils(d: Direction) {
- def serialize(implicit flags: FlagMap = FlagMap): String = {
- val s = d match {
- case Input => "input"
- case Output => "output"
- }
- s + debug(d)
- }
- def toFlip(): Flip = {
- d match {
- case Input => Reverse
- case Output => Default
- }
- }
- }
-
- implicit class PortUtils(p: Port) {
- def serialize(implicit flags: FlagMap = FlagMap): String =
- s"${p.dir.serialize} ${p.name} : ${p.tpe.serialize}" + debug(p)
- def getType(): Type = p.tpe
- def toField(): Field = Field(p.name, p.dir.toFlip, p.tpe)
- }
-
- implicit class ModuleUtils(m: Module) {
- def serialize(implicit flags: FlagMap = FlagMap): String = {
- var s = new StringBuilder(s"module ${m.name} : ")
- withIndent {
- s ++= m.ports.map(newline ++ _.serialize).mkString
- s ++= m.stmt.serialize
- }
- s ++= debug(m)
- s.toString
- }
- }
-
- implicit class CircuitUtils(c: Circuit) {
- def serialize(implicit flags: FlagMap = FlagMap): String = {
- var s = new StringBuilder(s"circuit ${c.name} : ")
- withIndent { s ++= newline ++ c.modules.map(_.serialize).mkString(newline + newline) }
- s ++= newline ++ newline
- s ++= debug(c)
- s.toString
- }
- }
-
- private var indentLevel = 0
- private def newline = "\n" + (" " * indentLevel)
- private def indent(): Unit = indentLevel += 1
- private def unindent() { require(indentLevel > 0); indentLevel -= 1 }
- private def withIndent(f: => Unit) { indent(); f; unindent() }
+ implicit class CircuitUtils(c: Circuit) {
+ def serialize(implicit flags: FlagMap = FlagMap): String = {
+ var s = new StringBuilder(s"circuit ${c.main} : ")
+ withIndent { s ++= newline ++ c.modules.map(_.serialize).mkString(newline + newline) }
+ s ++= newline ++ newline
+ s ++= debug(c)
+ s.toString
+ }
+ }
+
+ private var indentLevel = 0
+ private def newline = "\n" + (" " * indentLevel)
+ private def indent(): Unit = indentLevel += 1
+ private def unindent() { require(indentLevel > 0); indentLevel -= 1 }
+ private def withIndent(f: => Unit) { indent(); f; unindent() }
+ val v_keywords = Map[String,Boolean]() +
+ ("alias" -> true) +
+ ("always" -> true) +
+ ("always_comb" -> true) +
+ ("always_ff" -> true) +
+ ("always_latch" -> true) +
+ ("and" -> true) +
+ ("assert" -> true) +
+ ("assign" -> true) +
+ ("assume" -> true) +
+ ("attribute" -> true) +
+ ("automatic" -> true) +
+ ("before" -> true) +
+ ("begin" -> true) +
+ ("bind" -> true) +
+ ("bins" -> true) +
+ ("binsof" -> true) +
+ ("bit" -> true) +
+ ("break" -> true) +
+ ("buf" -> true) +
+ ("bufif0" -> true) +
+ ("bufif1" -> true) +
+ ("byte" -> true) +
+ ("case" -> true) +
+ ("casex" -> true) +
+ ("casez" -> true) +
+ ("cell" -> true) +
+ ("chandle" -> true) +
+ ("class" -> true) +
+ ("clocking" -> true) +
+ ("cmos" -> true) +
+ ("config" -> true) +
+ ("const" -> true) +
+ ("constraint" -> true) +
+ ("context" -> true) +
+ ("continue" -> true) +
+ ("cover" -> true) +
+ ("covergroup" -> true) +
+ ("coverpoint" -> true) +
+ ("cross" -> true) +
+ ("deassign" -> true) +
+ ("default" -> true) +
+ ("defparam" -> true) +
+ ("design" -> true) +
+ ("disable" -> true) +
+ ("dist" -> true) +
+ ("do" -> true) +
+ ("edge" -> true) +
+ ("else" -> true) +
+ ("end" -> true) +
+ ("endattribute" -> true) +
+ ("endcase" -> true) +
+ ("endclass" -> true) +
+ ("endclocking" -> true) +
+ ("endconfig" -> true) +
+ ("endfunction" -> true) +
+ ("endgenerate" -> true) +
+ ("endgroup" -> true) +
+ ("endinterface" -> true) +
+ ("endmodule" -> true) +
+ ("endpackage" -> true) +
+ ("endprimitive" -> true) +
+ ("endprogram" -> true) +
+ ("endproperty" -> true) +
+ ("endspecify" -> true) +
+ ("endsequence" -> true) +
+ ("endtable" -> true) +
+ ("endtask" -> true) +
+ ("enum" -> true) +
+ ("event" -> true) +
+ ("expect" -> true) +
+ ("export" -> true) +
+ ("extends" -> true) +
+ ("extern" -> true) +
+ ("final" -> true) +
+ ("first_match" -> true) +
+ ("for" -> true) +
+ ("force" -> true) +
+ ("foreach" -> true) +
+ ("forever" -> true) +
+ ("fork" -> true) +
+ ("forkjoin" -> true) +
+ ("function" -> true) +
+ ("generate" -> true) +
+ ("genvar" -> true) +
+ ("highz0" -> true) +
+ ("highz1" -> true) +
+ ("if" -> true) +
+ ("iff" -> true) +
+ ("ifnone" -> true) +
+ ("ignore_bins" -> true) +
+ ("illegal_bins" -> true) +
+ ("import" -> true) +
+ ("incdir" -> true) +
+ ("include" -> true) +
+ ("initial" -> true) +
+ ("initvar" -> true) +
+ ("inout" -> true) +
+ ("input" -> true) +
+ ("inside" -> true) +
+ ("instance" -> true) +
+ ("int" -> true) +
+ ("integer" -> true) +
+ ("interconnect" -> true) +
+ ("interface" -> true) +
+ ("intersect" -> true) +
+ ("join" -> true) +
+ ("join_any" -> true) +
+ ("join_none" -> true) +
+ ("large" -> true) +
+ ("liblist" -> true) +
+ ("library" -> true) +
+ ("local" -> true) +
+ ("localparam" -> true) +
+ ("logic" -> true) +
+ ("longint" -> true) +
+ ("macromodule" -> true) +
+ ("matches" -> true) +
+ ("medium" -> true) +
+ ("modport" -> true) +
+ ("module" -> true) +
+ ("nand" -> true) +
+ ("negedge" -> true) +
+ ("new" -> true) +
+ ("nmos" -> true) +
+ ("nor" -> true) +
+ ("noshowcancelled" -> true) +
+ ("not" -> true) +
+ ("notif0" -> true) +
+ ("notif1" -> true) +
+ ("null" -> true) +
+ ("or" -> true) +
+ ("output" -> true) +
+ ("package" -> true) +
+ ("packed" -> true) +
+ ("parameter" -> true) +
+ ("pmos" -> true) +
+ ("posedge" -> true) +
+ ("primitive" -> true) +
+ ("priority" -> true) +
+ ("program" -> true) +
+ ("property" -> true) +
+ ("protected" -> true) +
+ ("pull0" -> true) +
+ ("pull1" -> true) +
+ ("pulldown" -> true) +
+ ("pullup" -> true) +
+ ("pulsestyle_onevent" -> true) +
+ ("pulsestyle_ondetect" -> true) +
+ ("pure" -> true) +
+ ("rand" -> true) +
+ ("randc" -> true) +
+ ("randcase" -> true) +
+ ("randsequence" -> true) +
+ ("rcmos" -> true) +
+ ("real" -> true) +
+ ("realtime" -> true) +
+ ("ref" -> true) +
+ ("reg" -> true) +
+ ("release" -> true) +
+ ("repeat" -> true) +
+ ("return" -> true) +
+ ("rnmos" -> true) +
+ ("rpmos" -> true) +
+ ("rtran" -> true) +
+ ("rtranif0" -> true) +
+ ("rtranif1" -> true) +
+ ("scalared" -> true) +
+ ("sequence" -> true) +
+ ("shortint" -> true) +
+ ("shortreal" -> true) +
+ ("showcancelled" -> true) +
+ ("signed" -> true) +
+ ("small" -> true) +
+ ("solve" -> true) +
+ ("specify" -> true) +
+ ("specparam" -> true) +
+ ("static" -> true) +
+ ("strength" -> true) +
+ ("string" -> true) +
+ ("strong0" -> true) +
+ ("strong1" -> true) +
+ ("struct" -> true) +
+ ("super" -> true) +
+ ("supply0" -> true) +
+ ("supply1" -> true) +
+ ("table" -> true) +
+ ("tagged" -> true) +
+ ("task" -> true) +
+ ("this" -> true) +
+ ("throughout" -> true) +
+ ("time" -> true) +
+ ("timeprecision" -> true) +
+ ("timeunit" -> true) +
+ ("tran" -> true) +
+ ("tranif0" -> true) +
+ ("tranif1" -> true) +
+ ("tri" -> true) +
+ ("tri0" -> true) +
+ ("tri1" -> true) +
+ ("triand" -> true) +
+ ("trior" -> true) +
+ ("trireg" -> true) +
+ ("type" -> true) +
+ ("typedef" -> true) +
+ ("union" -> true) +
+ ("unique" -> true) +
+ ("unsigned" -> true) +
+ ("use" -> true) +
+ ("var" -> true) +
+ ("vectored" -> true) +
+ ("virtual" -> true) +
+ ("void" -> true) +
+ ("wait" -> true) +
+ ("wait_order" -> true) +
+ ("wand" -> true) +
+ ("weak0" -> true) +
+ ("weak1" -> true) +
+ ("while" -> true) +
+ ("wildcard" -> true) +
+ ("wire" -> true) +
+ ("with" -> true) +
+ ("within" -> true) +
+ ("wor" -> true) +
+ ("xnor" -> true) +
+ ("xor" -> true) +
+ ("SYNTHESIS" -> true) +
+ ("PRINTF_COND" -> true) +
+ ("VCS" -> true)
}
diff --git a/src/main/scala/firrtl/Visitor.scala b/src/main/scala/firrtl/Visitor.scala
index ad8d24f2..5204ce8e 100644
--- a/src/main/scala/firrtl/Visitor.scala
+++ b/src/main/scala/firrtl/Visitor.scala
@@ -1,4 +1,30 @@
/*
+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.
+*/
+/*
* TODO
* - Implement UBits and SBits
* - Get correct line number for memory field errors
@@ -14,6 +40,7 @@ import org.antlr.v4.runtime.tree.TerminalNode
import scala.collection.JavaConversions._
import antlr._
import PrimOps._
+import FIRRTLParser._
class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST]
{
@@ -31,10 +58,20 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST]
val HexPattern = """\"*h([a-zA-Z0-9]+)\"*""".r
val DecPattern = """(\+|-)?([1-9]\d*)""".r
val ZeroPattern = "0".r
+ val NegPattern = "(89AaBbCcDdEeFf)".r
s match {
case ZeroPattern(_*) => BigInt(0)
- case HexPattern(hexdigits) => BigInt(hexdigits, 16)
- case DecPattern(sign, num) => BigInt(num)
+ case HexPattern(hexdigits) =>
+ hexdigits(0) match {
+ case NegPattern(_) =>{
+ BigInt("-" + hexdigits,16)
+ }
+ case _ => BigInt(hexdigits, 16)
+ }
+ case DecPattern(sign, num) => {
+ if (sign != null) BigInt(sign + num,10)
+ else BigInt(num,10)
+ }
case _ => throw new Exception("Invalid String for conversion to BigInt " + s)
}
}
@@ -43,36 +80,48 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST]
FileInfo(filename, ctx.getStart().getLine(), ctx.getStart().getCharPositionInLine())
private def visitCircuit[AST](ctx: FIRRTLParser.CircuitContext): Circuit =
- Circuit(getInfo(ctx), ctx.id.getText, ctx.module.map(visitModule))
+ Circuit(getInfo(ctx), ctx.module.map(visitModule), (ctx.id.getText))
private def visitModule[AST](ctx: FIRRTLParser.ModuleContext): Module =
- Module(getInfo(ctx), ctx.id.getText, ctx.port.map(visitPort), visitBlock(ctx.block))
-
- private def visitPort[AST](ctx: FIRRTLParser.PortContext): Port =
- Port(getInfo(ctx), ctx.id.getText, visitDir(ctx.dir), visitType(ctx.`type`))
+ ctx.getChild(0).getText match {
+ case "module" => InModule(getInfo(ctx), (ctx.id.getText), ctx.port.map(visitPort), visitBlock(ctx.block))
+ case "extmodule" => ExModule(getInfo(ctx), (ctx.id.getText), ctx.port.map(visitPort))
+ }
- private def visitDir[AST](ctx: FIRRTLParser.DirContext): Direction =
+ private def visitPort[AST](ctx: FIRRTLParser.PortContext): Port =
+ Port(getInfo(ctx), (ctx.id.getText), visitDir(ctx.dir), visitType(ctx.`type`))
+ private def visitDir[AST](ctx: FIRRTLParser.DirContext): Direction =
+ ctx.getText match {
+ case "input" => INPUT
+ case "output" => OUTPUT
+ }
+ private def visitMdir[AST](ctx: FIRRTLParser.MdirContext): MPortDir =
ctx.getText match {
- case "input" => Input
- case "output" => Output
+ case "infer" => MInfer
+ case "read" => MRead
+ case "write" => MWrite
+ case "rdwr" => MReadWrite
}
// Match on a type instead of on strings?
- private def visitType[AST](ctx: FIRRTLParser.TypeContext): Type = {
- ctx.getChild(0).getText match {
- case "UInt" => if (ctx.getChildCount > 1) UIntType(IntWidth(string2BigInt(ctx.IntLit.getText)))
- else UIntType( UnknownWidth )
- case "SInt" => if (ctx.getChildCount > 1) SIntType(IntWidth(string2BigInt(ctx.IntLit.getText)))
- else SIntType( UnknownWidth )
- case "Clock" => ClockType
- case "{" => BundleType(ctx.field.map(visitField))
- case _ => new VectorType( visitType(ctx.`type`), string2BigInt(ctx.IntLit.getText) )
+ private def visitType[AST](ctx: FIRRTLParser.TypeContext): Type = {
+ ctx.getChild(0) match {
+ case term: TerminalNode =>
+ term.getText match {
+ case "UInt" => if (ctx.getChildCount > 1) UIntType(IntWidth(string2BigInt(ctx.IntLit.getText)))
+ else UIntType( UnknownWidth() )
+ case "SInt" => if (ctx.getChildCount > 1) SIntType(IntWidth(string2BigInt(ctx.IntLit.getText)))
+ else SIntType( UnknownWidth() )
+ case "Clock" => ClockType()
+ case "{" => BundleType(ctx.field.map(visitField))
+ }
+ case tpe: TypeContext => new VectorType(visitType(ctx.`type`), string2Int(ctx.IntLit.getText))
}
}
private def visitField[AST](ctx: FIRRTLParser.FieldContext): Field = {
- val flip = if(ctx.getChild(0).getText == "flip") Reverse else Default
- Field(ctx.id.getText, flip, visitType(ctx.`type`))
+ val flip = if(ctx.getChild(0).getText == "flip") REVERSE else DEFAULT
+ Field((ctx.id.getText), flip, visitType(ctx.`type`))
}
@@ -91,7 +140,7 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST]
val seq = map getOrElse (field, Seq())
map + (field -> (seq :+ children(2)))
} else { // data-type, depth, read-latency, write-latency, read-under-write
- if (map.contains(field)) throw new Exception(s"Redefinition of mem field ${field}")
+ if (map.contains(field)) throw new ParameterRedefinedException(s"Redefinition of ${field}")
else map + (field -> Seq(children(2)))
}
parseChildren(children.drop(3), newMap) // We consume tokens in groups of three (eg. 'depth' '=>' 5)
@@ -102,15 +151,19 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST]
// Build map of different Memory fields to their values
val map = try {
parseChildren(ctx.children.drop(4), Map[String, Seq[ParseTree]]()) // First 4 tokens are 'mem' id ':' '{', skip to fields
- } catch {
- case e: Exception => throw new Exception(s"[${info}] ${e.getMessage}") // attach line number
+ } catch { // attach line number
+ case e: ParameterRedefinedException => throw new ParameterRedefinedException(s"[${info}] ${e.message}")
+ }
+ // Check for required fields
+ Seq("data-type", "depth", "read-latency", "write-latency") foreach { field =>
+ map.getOrElse(field, throw new ParameterNotSpecifiedException(s"[${info}] Required mem field ${field} not found"))
}
// Each memory field value has been left as ParseTree type, need to convert
// TODO Improve? Remove dynamic typecast of data-type
- DefMemory(info, ctx.id(0).getText, visitType(map("data-type").head.asInstanceOf[FIRRTLParser.TypeContext]),
+ DefMemory(info, (ctx.id(0).getText), visitType(map("data-type").head.asInstanceOf[FIRRTLParser.TypeContext]),
string2Int(map("depth").head.getText), string2Int(map("write-latency").head.getText),
- string2Int(map("read-latency").head.getText), map.getOrElse("reader", Seq()).map(_.getText),
- map.getOrElse("writer", Seq()).map(_.getText), map.getOrElse("readwriter", Seq()).map(_.getText))
+ string2Int(map("read-latency").head.getText), map.getOrElse("reader", Seq()).map(x => (x.getText)),
+ map.getOrElse("writer", Seq()).map(x => (x.getText)), map.getOrElse("readwriter", Seq()).map(x => (x.getText)))
}
// visitStmt
@@ -118,31 +171,47 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST]
val info = getInfo(ctx)
ctx.getChild(0).getText match {
- case "wire" => DefWire(info, ctx.id(0).getText, visitType(ctx.`type`(0)))
+ case "wire" => DefWire(info, (ctx.id(0).getText), visitType(ctx.`type`(0)))
case "reg" => {
- val name = ctx.id(0).getText
+ val name = (ctx.id(0).getText)
val tpe = visitType(ctx.`type`(0))
val reset = if (ctx.exp(1) != null) visitExp(ctx.exp(1)) else UIntValue(0, IntWidth(1))
val init = if (ctx.exp(2) != null) visitExp(ctx.exp(2)) else Ref(name, tpe)
DefRegister(info, name, tpe, visitExp(ctx.exp(0)), reset, init)
}
case "mem" => visitMem(ctx)
- case "inst" => DefInstance(info, ctx.id(0).getText, ctx.id(1).getText)
- case "node" => DefNode(info, ctx.id(0).getText, visitExp(ctx.exp(0)))
+ case "cmem" => {
+ val t = visitType(ctx.`type`(0))
+ t match {
+ case (t:VectorType) => CDefMemory(info,ctx.id(0).getText,t.tpe,t.size,false)
+ case _ => throw new ParserException(s"${info}: Must provide cmem with vector type")
+ }
+ }
+ case "smem" => {
+ val t = visitType(ctx.`type`(0))
+ t match {
+ case (t:VectorType) => CDefMemory(info,ctx.id(0).getText,t.tpe,t.size,true)
+ case _ => throw new ParserException(s"${info}: Must provide cmem with vector type")
+ }
+ }
+ case "inst" => DefInstance(info, (ctx.id(0).getText), (ctx.id(1).getText))
+ case "node" => DefNode(info, (ctx.id(0).getText), visitExp(ctx.exp(0)))
case "when" => {
- val alt = if (ctx.block.length > 1) visitBlock(ctx.block(1)) else Empty
+ val alt = if (ctx.block.length > 1) visitBlock(ctx.block(1)) else Empty()
Conditionally(info, visitExp(ctx.exp(0)), visitBlock(ctx.block(0)), alt)
}
case "stop(" => Stop(info, string2Int(ctx.IntLit(0).getText), visitExp(ctx.exp(0)), visitExp(ctx.exp(1)))
- case "printf(" => Print(info, ctx.StringLit.getText, ctx.exp.drop(2).map(visitExp),
+ // Stip first and last character of string since they are the surrounding double quotes
+ case "printf(" => Print(info, ctx.StringLit.getText.tail.init, ctx.exp.drop(2).map(visitExp),
visitExp(ctx.exp(0)), visitExp(ctx.exp(1)))
- case "skip" => Empty
+ case "skip" => Empty()
// If we don't match on the first child, try the next one
case _ => {
ctx.getChild(1).getText match {
case "<=" => Connect(info, visitExp(ctx.exp(0)), visitExp(ctx.exp(1)) )
case "<-" => BulkConnect(info, visitExp(ctx.exp(0)), visitExp(ctx.exp(1)) )
case "is" => IsInvalid(info, visitExp(ctx.exp(0)))
+ case "mport" => CDefMPort(info, ctx.id(0).getText, UnknownType(),ctx.id(1).getText,Seq(visitExp(ctx.exp(0)),visitExp(ctx.exp(1))),visitMdir(ctx.mdir))
}
}
}
@@ -157,34 +226,40 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST]
// - Add validif
private def visitExp[AST](ctx: FIRRTLParser.ExpContext): Expression =
if( ctx.getChildCount == 1 )
- Ref(ctx.getText, UnknownType)
+ Ref((ctx.getText), UnknownType())
else
ctx.getChild(0).getText match {
case "UInt" => { // This could be better
val (width, value) =
if (ctx.getChildCount > 4)
(IntWidth(string2BigInt(ctx.IntLit(0).getText)), string2BigInt(ctx.IntLit(1).getText))
- else (UnknownWidth, string2BigInt(ctx.IntLit(0).getText))
+ else {
+ val bigint = string2BigInt(ctx.IntLit(0).getText)
+ (IntWidth(BigInt(scala.math.max(bigint.bitLength,1))),bigint)
+ }
UIntValue(value, width)
}
case "SInt" => {
val (width, value) =
if (ctx.getChildCount > 4)
(IntWidth(string2BigInt(ctx.IntLit(0).getText)), string2BigInt(ctx.IntLit(1).getText))
- else (UnknownWidth, string2BigInt(ctx.IntLit(0).getText))
+ else {
+ val bigint = string2BigInt(ctx.IntLit(0).getText)
+ (IntWidth(BigInt(bigint.bitLength + 1)),bigint)
+ }
SIntValue(value, width)
}
- case "validif(" => ValidIf(visitExp(ctx.exp(0)), visitExp(ctx.exp(1)), UnknownType)
- case "mux(" => Mux(visitExp(ctx.exp(0)), visitExp(ctx.exp(1)), visitExp(ctx.exp(2)), UnknownType)
+ case "validif(" => ValidIf(visitExp(ctx.exp(0)), visitExp(ctx.exp(1)), UnknownType())
+ case "mux(" => Mux(visitExp(ctx.exp(0)), visitExp(ctx.exp(1)), visitExp(ctx.exp(2)), UnknownType())
case _ =>
ctx.getChild(1).getText match {
- case "." => new SubField(visitExp(ctx.exp(0)), ctx.id.getText, UnknownType)
+ case "." => new SubField(visitExp(ctx.exp(0)), (ctx.id.getText), UnknownType())
case "[" => if (ctx.exp(1) == null)
- new SubIndex(visitExp(ctx.exp(0)), string2BigInt(ctx.IntLit(0).getText), UnknownType)
- else new SubAccess(visitExp(ctx.exp(0)), visitExp(ctx.exp(1)), UnknownType)
+ new SubIndex(visitExp(ctx.exp(0)), string2Int(ctx.IntLit(0).getText), UnknownType())
+ else new SubAccess(visitExp(ctx.exp(0)), visitExp(ctx.exp(1)), UnknownType())
// Assume primop
case _ => DoPrim(visitPrimop(ctx.primop), ctx.exp.map(visitExp),
- ctx.IntLit.map(x => string2BigInt(x.getText)), UnknownType)
+ ctx.IntLit.map(x => string2BigInt(x.getText)), UnknownType())
}
}
diff --git a/src/main/scala/firrtl/WIR.scala b/src/main/scala/firrtl/WIR.scala
new file mode 100644
index 00000000..9c7b85ee
--- /dev/null
+++ b/src/main/scala/firrtl/WIR.scala
@@ -0,0 +1,221 @@
+/*
+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
+
+import scala.collection.Seq
+import Utils._
+import WrappedExpression._
+import WrappedWidth._
+
+trait Kind
+case class WireKind() extends Kind
+case class PoisonKind() extends Kind
+case class RegKind() extends Kind
+case class InstanceKind() extends Kind
+case class PortKind() extends Kind
+case class NodeKind() extends Kind
+case class MemKind(ports:Seq[String]) extends Kind
+case class ExpKind() extends Kind
+
+trait Gender
+case object MALE extends Gender
+case object FEMALE extends Gender
+case object BIGENDER extends Gender
+case object UNKNOWNGENDER extends Gender
+
+case class WRef(name:String,tpe:Type,kind:Kind,gender:Gender) extends Expression
+case class WSubField(exp:Expression,name:String,tpe:Type,gender:Gender) extends Expression
+case class WSubIndex(exp:Expression,value:Int,tpe:Type,gender:Gender) extends Expression
+case class WSubAccess(exp:Expression,index:Expression,tpe:Type,gender:Gender) extends Expression
+case class WVoid() extends Expression
+case class WInvalid() extends Expression
+case class WDefInstance(info:Info,name:String,module:String,tpe:Type) extends Stmt
+
+case object ADDW_OP extends PrimOp
+case object SUBW_OP extends PrimOp
+
+object WrappedExpression {
+ def apply (e:Expression) = new WrappedExpression(e)
+ def we (e:Expression) = new WrappedExpression(e)
+ def weq (e1:Expression,e2:Expression) = we(e1) == we(e2)
+}
+class WrappedExpression (val e1:Expression) {
+ override def equals (we:Any) = {
+ we match {
+ case (we:WrappedExpression) => {
+ (e1,we.e1) match {
+ case (e1:UIntValue,e2:UIntValue) => if (e1.value == e2.value) eqw(e1.width,e2.width) else false
+ case (e1:SIntValue,e2:SIntValue) => if (e1.value == e2.value) eqw(e1.width,e2.width) else false
+ case (e1:WRef,e2:WRef) => e1.name equals e2.name
+ case (e1:WSubField,e2:WSubField) => (e1.name equals e2.name) && weq(e1.exp,e2.exp)
+ case (e1:WSubIndex,e2:WSubIndex) => (e1.value == e2.value) && weq(e1.exp,e2.exp)
+ case (e1:WSubAccess,e2:WSubAccess) => weq(e1.index,e2.index) && weq(e1.exp,e2.exp)
+ case (e1:WVoid,e2:WVoid) => true
+ case (e1:WInvalid,e2:WInvalid) => true
+ case (e1:DoPrim,e2:DoPrim) => {
+ var are_equal = e1.op == e2.op
+ (e1.args,e2.args).zipped.foreach{ (x,y) => { if (!weq(x,y)) are_equal = false }}
+ (e1.consts,e2.consts).zipped.foreach{ (x,y) => { if (x != y) are_equal = false }}
+ are_equal
+ }
+ case (e1:Mux,e2:Mux) => weq(e1.cond,e2.cond) && weq(e1.tval,e2.tval) && weq(e1.fval,e2.fval)
+ case (e1:ValidIf,e2:ValidIf) => weq(e1.cond,e2.cond) && weq(e1.value,e2.value)
+ case (e1,e2) => false
+ }
+ }
+ case _ => false
+ }
+ }
+ override def hashCode = e1.serialize().hashCode
+ override def toString = e1.serialize()
+}
+
+
+case class VarWidth(name:String) extends Width
+case class PlusWidth(arg1:Width,arg2:Width) extends Width
+case class MinusWidth(arg1:Width,arg2:Width) extends Width
+case class MaxWidth(args:Seq[Width]) extends Width
+case class MinWidth(args:Seq[Width]) extends Width
+case class ExpWidth(arg1:Width) extends Width
+
+object WrappedType {
+ def apply (t:Type) = new WrappedType(t)
+ def wt (t:Type) = apply(t)
+}
+class WrappedType (val t:Type) {
+ def wt (tx:Type) = new WrappedType(tx)
+ override def equals (o:Any) : Boolean = {
+ o match {
+ case (t2:WrappedType) => {
+ (t,t2.t) match {
+ case (t1:UIntType,t2:UIntType) => true
+ case (t1:SIntType,t2:SIntType) => true
+ case (t1:ClockType,t2:ClockType) => true
+ case (t1:VectorType,t2:VectorType) => (wt(t1.tpe) == wt(t2.tpe) && t1.size == t2.size)
+ case (t1:BundleType,t2:BundleType) => {
+ var ret = true
+ (t1.fields,t2.fields).zipped.foreach{ (f1,f2) => {
+ if (f1.flip != f2.flip) ret = false
+ if (f1.name != f2.name) ret = false
+ if (wt(f1.tpe) != wt(f2.tpe)) ret = false
+ }}
+ ret
+ }
+ case (t1,t2) => false
+ }
+ }
+ case _ => false
+ }
+ }
+}
+
+object WrappedWidth {
+ def eqw (w1:Width,w2:Width) : Boolean = {
+ (new WrappedWidth(w1)) == (new WrappedWidth(w2))
+ }
+}
+
+class WrappedWidth (val w:Width) {
+ override def toString = {
+ w match {
+ case (w:VarWidth) => w.name
+ case (w:MaxWidth) => "max(" + w.args.map(_.toString).reduce(_ + _) + ")"
+ case (w:MinWidth) => "min(" + w.args.map(_.toString).reduce(_ + _) + ")"
+ case (w:PlusWidth) => "(" + w.arg1 + " + " + w.arg2 + ")"
+ case (w:MinusWidth) => "(" + w.arg1 + " - " + w.arg2 + ")"
+ case (w:ExpWidth) => "exp(" + w.arg1 + ")"
+ case (w:IntWidth) => w.width.toString
+ case (w:UnknownWidth) => "?"
+ }
+ }
+ def ww (w:Width) : WrappedWidth = new WrappedWidth(w)
+ override def equals (o:Any) : Boolean = {
+ o match {
+ case (w2:WrappedWidth) => {
+ (w,w2.w) match {
+ case (w1:VarWidth,w2:VarWidth) => w1.name.equals(w2.name)
+ case (w1:MaxWidth,w2:MaxWidth) => {
+ var ret = true
+ if (w1.args.size != w2.args.size) ret = false
+ else {
+ for (a1 <- w1.args) {
+ var found = false
+ for (a2 <- w2.args) { if (eqw(a1,a2)) found = true }
+ if (found == false) ret = false
+ }
+ }
+ ret
+ }
+ case (w1:MinWidth,w2:MinWidth) => {
+ var ret = true
+ if (w1.args.size != w2.args.size) ret = false
+ else {
+ for (a1 <- w1.args) {
+ var found = false
+ for (a2 <- w2.args) { if (eqw(a1,a2)) found = true }
+ if (found == false) ret = false
+ }
+ }
+ ret
+ }
+ case (w1:IntWidth,w2:IntWidth) => w1.width == w2.width
+ case (w1:PlusWidth,w2:PlusWidth) =>
+ (ww(w1.arg1) == ww(w2.arg1) && ww(w1.arg2) == ww(w2.arg2)) || (ww(w1.arg1) == ww(w2.arg2) && ww(w1.arg2) == ww(w2.arg1))
+ case (w1:MinusWidth,w2:MinusWidth) =>
+ (ww(w1.arg1) == ww(w2.arg1) && ww(w1.arg2) == ww(w2.arg2)) || (ww(w1.arg1) == ww(w2.arg2) && ww(w1.arg2) == ww(w2.arg1))
+ case (w1:ExpWidth,w2:ExpWidth) => ww(w1.arg1) == ww(w2.arg1)
+ case (w1:UnknownWidth,w2:UnknownWidth) => true
+ case (w1,w2) => false
+ }
+ }
+ case _ => false
+ }
+ }
+}
+
+trait Constraint
+class WGeq(val loc:Width,val exp:Width) extends Constraint {
+ override def toString = {
+ val wloc = new WrappedWidth(loc)
+ val wexp = new WrappedWidth(exp)
+ wloc.toString + " >= " + wexp.toString
+ }
+}
+object WGeq {
+ def apply (loc:Width,exp:Width) = new WGeq(loc,exp)
+}
+
+trait MPortDir
+case object MInfer extends MPortDir
+case object MRead extends MPortDir
+case object MWrite extends MPortDir
+case object MReadWrite extends MPortDir
+
+case class CDefMemory (val info: Info, val name: String, val tpe: Type, val size: Int, val seq: Boolean) extends Stmt
+case class CDefMPort (val info: Info, val name: String, val tpe: Type, val mem: String, val exps: Seq[Expression], val direction: MPortDir) extends Stmt
+
diff --git a/src/main/scala/firrtl/passes/Checks.scala b/src/main/scala/firrtl/passes/Checks.scala
new file mode 100644
index 00000000..0a07fdcb
--- /dev/null
+++ b/src/main/scala/firrtl/passes/Checks.scala
@@ -0,0 +1,792 @@
+/*
+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 com.typesafe.scalalogging.LazyLogging
+
+// Datastructures
+import scala.collection.mutable.HashMap
+import scala.collection.mutable.ArrayBuffer
+
+import firrtl._
+import firrtl.Utils._
+import firrtl.PrimOps._
+import firrtl.WrappedType._
+
+object CheckHighForm extends Pass with LazyLogging {
+ def name = "High Form Check"
+
+ // Custom Exceptions
+ class NotUniqueException(name: String) extends PassException(s"${sinfo}: [module ${mname}] Reference ${name} does not have a unique name.")
+ class IsPrefixException(prefix: String) extends PassException(s"${sinfo}: [module ${mname}] Symbol ${prefix} is a prefix.")
+ class InvalidLOCException extends PassException(s"${sinfo}: [module ${mname}] Invalid connect to an expression that is not a reference or a WritePort.")
+ class NegUIntException extends PassException(s"${sinfo}: [module ${mname}] UIntValue cannot be negative.")
+ class UndeclaredReferenceException(name: String) extends PassException(s"${sinfo}: [module ${mname}] Reference ${name} is not declared.")
+ class PoisonWithFlipException(name: String) extends PassException(s"${sinfo}: [module ${mname}] Poison ${name} cannot be a bundle type with flips.")
+ class MemWithFlipException(name: String) extends PassException(s"${sinfo}: [module ${mname}] Memory ${name} cannot be a bundle type with flips.")
+ class InvalidAccessException extends PassException(s"${sinfo}: [module ${mname}] Invalid access to non-reference.")
+ class NoTopModuleException(name: String) extends PassException(s"${sinfo}: A single module must be named ${name}.")
+ class ModuleNotDefinedException(name: String) extends PassException(s"${sinfo}: Module ${name} is not defined.")
+ class IncorrectNumArgsException(op: String, n: Int) extends PassException(s"${sinfo}: [module ${mname}] Primop ${op} requires ${n} expression arguments.")
+ class IncorrectNumConstsException(op: String, n: Int) extends PassException(s"${sinfo}: [module ${mname}] Primop ${op} requires ${n} integer arguments.")
+ class NegWidthException extends PassException(s"${sinfo}: [module ${mname}] Width cannot be negative or zero.")
+ class NegVecSizeException extends PassException(s"${sinfo}: [module ${mname}] Vector type size cannot be negative.")
+ class NegMemSizeException extends PassException(s"${sinfo}: [module ${mname}] Memory size cannot be negative or zero.")
+ // Note the following awkward strings are due to an issue with Scala string interpolation and escaped double quotes
+ class BadPrintfException(x: Char) extends PassException(s"${sinfo}: [module ${mname}] Bad printf format: " + "\"%" + x + "\"")
+ class BadPrintfTrailingException extends PassException(s"${sinfo}: [module ${mname}] Bad printf format: trailing " + "\"%\"")
+ class BadPrintfIncorrectNumException extends PassException(s"${sinfo}: [module ${mname}] Bad printf format: incorrect number of arguments")
+
+ // Trie Datastructure for prefix checking
+ case class Trie(var children: HashMap[String, Trie], var end: Boolean) {
+ def empty: Boolean = children.isEmpty
+ def add(ls: Seq[String]): Boolean = {
+ var t: Trie = this
+ var sawEnd = false
+ for (x <- ls) {
+ if (t.end) sawEnd = true
+ if (t.contains(x)) t = t.children(x)
+ else {
+ val temp = new Trie(HashMap[String,Trie](),false)
+ t.children(x) = temp
+ t = temp
+ }
+ }
+ t.end = true
+ sawEnd | !t.empty
+ }
+ def contains(s: String): Boolean = children.contains(s)
+ def contains(ls: Seq[String]): Boolean = {
+ var t: Trie = this
+ for (x <- ls) {
+ if (t.contains(x)) t = t.children(x)
+ else return false
+ }
+ t.end
+ }
+ }
+
+ // Utility functions
+ def hasFlip(t: Type): Boolean = {
+ var has = false
+ def findFlip(t: Type): Type = {
+ t match {
+ case t: BundleType => {
+ for (f <- t.fields) {
+ if (f.flip == REVERSE) has = true
+ }
+ t
+ }
+ case t: Type => t
+ }
+ }
+ findFlip(t)
+ tMap(findFlip _, t)
+ has
+ }
+
+ // TODO FIXME
+ // - Do we need to check for uniquness on port names?
+ // Global Variables
+ private var mname: String = ""
+ private var sinfo: Info = NoInfo
+ def run (c:Circuit): Circuit = {
+ val errors = ArrayBuffer[PassException]()
+ def checkHighFormPrimop(e: DoPrim) = {
+ def correctNum(ne: Option[Int], nc: Int) = {
+ ne match {
+ case Some(i) => if(e.args.length != i) errors.append(new IncorrectNumArgsException(e.op.getString, i))
+ case None => // Do Nothing
+ }
+ if (e.consts.length != nc) errors.append(new IncorrectNumConstsException(e.op.getString, nc))
+ }
+
+ e.op match {
+ case ADD_OP => correctNum(Option(2),0)
+ case SUB_OP => correctNum(Option(2),0)
+ case MUL_OP => correctNum(Option(2),0)
+ case DIV_OP => correctNum(Option(2),0)
+ case REM_OP => correctNum(Option(2),0)
+ case LESS_OP => correctNum(Option(2),0)
+ case LESS_EQ_OP => correctNum(Option(2),0)
+ case GREATER_OP => correctNum(Option(2),0)
+ case GREATER_EQ_OP => correctNum(Option(2),0)
+ case EQUAL_OP => correctNum(Option(2),0)
+ case NEQUAL_OP => correctNum(Option(2),0)
+ case PAD_OP => correctNum(Option(1),1)
+ case AS_UINT_OP => correctNum(Option(1),0)
+ case AS_SINT_OP => correctNum(Option(1),0)
+ case AS_CLOCK_OP => correctNum(Option(1),0)
+ case SHIFT_LEFT_OP => correctNum(Option(1),1)
+ case SHIFT_RIGHT_OP => correctNum(Option(1),1)
+ case DYN_SHIFT_LEFT_OP => correctNum(Option(2),0)
+ case DYN_SHIFT_RIGHT_OP => correctNum(Option(2),0)
+ case CONVERT_OP => correctNum(Option(1),0)
+ case NEG_OP => correctNum(Option(1),0)
+ case NOT_OP => correctNum(Option(1),0)
+ case AND_OP => correctNum(Option(2),0)
+ case OR_OP => correctNum(Option(2),0)
+ case XOR_OP => correctNum(Option(2),0)
+ case AND_REDUCE_OP => correctNum(None,0)
+ case OR_REDUCE_OP => correctNum(None,0)
+ case XOR_REDUCE_OP => correctNum(None,0)
+ case CONCAT_OP => correctNum(Option(2),0)
+ case BITS_SELECT_OP => correctNum(Option(1),2)
+ case HEAD_OP => correctNum(Option(1),1)
+ case TAIL_OP => correctNum(Option(1),1)
+ }
+ }
+
+ def checkFstring(s: String, i: Int) = {
+ val validFormats = "bedxs"
+ var percent = false
+ var ret = true
+ var npercents = 0
+ for (x <- s) {
+ if (!validFormats.contains(x) && percent)
+ errors.append(new BadPrintfException(x))
+ if (x == '%') npercents = npercents + 1
+ percent = (x == '%')
+ }
+ if (percent) errors.append(new BadPrintfTrailingException)
+ if (npercents != i) errors.append(new BadPrintfIncorrectNumException)
+ }
+ def checkValidLoc(e: Expression) = {
+ e match {
+ case e @ ( _: UIntValue | _: SIntValue | _: DoPrim ) => errors.append(new InvalidLOCException)
+ case _ => // Do Nothing
+ }
+ }
+ def checkHighFormW(w: Width): Width = {
+ w match {
+ case w: IntWidth =>
+ if (w.width <= BigInt(0)) errors.append(new NegWidthException)
+ case _ => // Do Nothing
+ }
+ w
+ }
+ def checkHighFormT(t: Type): Type = {
+ tMap(checkHighFormT _, t) match {
+ case t: VectorType =>
+ if (t.size < 0) errors.append(new NegVecSizeException)
+ case _ => // Do nothing
+ }
+ wMap(checkHighFormW _, t)
+ }
+
+ def checkHighFormM(m: Module): Module = {
+ val names = HashMap[String, Boolean]()
+ val mnames = HashMap[String, Boolean]()
+ val tries = Trie(HashMap[String, Trie](),false)
+ def checkHighFormE(e: Expression): Expression = {
+ def validSubexp(e: Expression): Expression = {
+ e match {
+ case (_:WRef|_:WSubField|_:WSubIndex|_:WSubAccess|_:Mux|_:ValidIf) => {} // No error
+ case _ => errors.append(new InvalidAccessException)
+ }
+ e
+ }
+ eMap(checkHighFormE _, e) match {
+ case e: WRef =>
+ if (!names.contains(e.name)) errors.append(new UndeclaredReferenceException(e.name))
+ case e: DoPrim => checkHighFormPrimop(e)
+ case (_:Mux|_:ValidIf) => {}
+ case e: WSubAccess => {
+ validSubexp(e.exp)
+ e
+ }
+ case e: UIntValue =>
+ if (e.value < 0) errors.append(new NegUIntException)
+ case e => eMap(validSubexp _, e)
+ }
+ wMap(checkHighFormW _, e)
+ tMap(checkHighFormT _, e)
+ e
+ }
+ def checkHighFormS(s: Stmt): Stmt = {
+ def checkName(name: String): String = {
+ if (names.contains(name)) errors.append(new NotUniqueException(name))
+ else names(name) = true
+ val ls: Seq[String] = name.split('$')
+ if (tries.add(ls)) errors.append(new IsPrefixException(name))
+ name
+ }
+ sinfo = s.getInfo
+
+ stMap(checkName _, s)
+ tMap(checkHighFormT _, s)
+ eMap(checkHighFormE _, s)
+ s match {
+ case s: DefPoison => {
+ if (hasFlip(s.tpe)) errors.append(new PoisonWithFlipException(s.name))
+ checkHighFormT(s.tpe)
+ }
+ case s: DefMemory => {
+ if (hasFlip(s.data_type)) errors.append(new MemWithFlipException(s.name))
+ if (s.depth <= 0) errors.append(new NegMemSizeException)
+ }
+ case s: WDefInstance => {
+ if (!c.modules.map(_.name).contains(s.module))
+ errors.append(new ModuleNotDefinedException(s.module))
+ }
+ case s: Connect => checkValidLoc(s.loc)
+ case s: BulkConnect => checkValidLoc(s.loc)
+ case s: Print => checkFstring(s.string, s.args.length)
+ case _ => // Do Nothing
+ }
+
+ sMap(checkHighFormS _, s)
+ }
+
+ mname = m.name
+ for (m <- c.modules) {
+ mnames(m.name) = true
+ }
+ for (p <- m.ports) {
+ // FIXME should we set sinfo here?
+ names(p.name) = true
+ val tpe = p.getType
+ tMap(checkHighFormT _, tpe)
+ wMap(checkHighFormW _, tpe)
+ }
+
+ m match {
+ case m: InModule => checkHighFormS(m.body)
+ case m: ExModule => // Do Nothing
+ }
+ m
+ }
+
+ var numTopM = 0
+ for (m <- c.modules) {
+ if (m.name == c.main) numTopM = numTopM + 1
+ checkHighFormM(m)
+ }
+ sinfo = c.info
+ if (numTopM != 1) errors.append(new NoTopModuleException(c.main))
+ if (errors.nonEmpty) throw new PassExceptions(errors)
+ c
+ }
+}
+
+object CheckTypes extends Pass with LazyLogging {
+ def name = "Check Types"
+ var mname = ""
+
+ // Custom Exceptions
+ class SubfieldNotInBundle(info:Info, name:String) extends PassException(s"${info}: [module ${mname} ] Subfield ${name} is not in bundle.")
+ class SubfieldOnNonBundle(info:Info, name:String) extends PassException(s"${info}: [module ${mname}] Subfield ${name} is accessed on a non-bundle.")
+ class IndexTooLarge(info:Info, value:Int) extends PassException(s"${info}: [module ${mname}] Index with value ${value} is too large.")
+ class IndexOnNonVector(info:Info) extends PassException(s"${info}: [module ${mname}] Index illegal on non-vector type.")
+ class AccessIndexNotUInt(info:Info) extends PassException(s"${info}: [module ${mname}] Access index must be a UInt type.")
+ class IndexNotUInt(info:Info) extends PassException(s"${info}: [module ${mname}] Index is not of UIntType.")
+ class EnableNotUInt(info:Info) extends PassException(s"${info}: [module ${mname}] Enable is not of UIntType.")
+ class InvalidConnect(info:Info) extends PassException(s"${info}: [module ${mname}] Type mismatch.")
+ class PrintfArgNotGround(info:Info) extends PassException(s"${info}: [module ${mname}] Printf arguments must be either UIntType or SIntType.")
+ class ReqClk(info:Info) extends PassException(s"${info}: [module ${mname}] Requires a clock typed signal.")
+ class EnNotUInt(info:Info) extends PassException(s"${info}: [module ${mname}] Enable must be a UIntType typed signal.")
+ class PredNotUInt(info:Info) extends PassException(s"${info}: [module ${mname}] Predicate not a UIntType.")
+ class OpNotGround(info:Info, op:String) extends PassException(s"${info}: [module ${mname}] Primop ${op} cannot operate on non-ground types.")
+ class OpNotUInt(info:Info, op:String,e:String) extends PassException(s"${info}: [module ${mname}] Primop ${op} requires argument ${e} to be a UInt type.")
+ class OpNotAllUInt(info:Info, op:String) extends PassException(s"${info}: [module ${mname}] Primop ${op} requires all arguments to be UInt type.")
+ class OpNotAllSameType(info:Info, op:String) extends PassException(s"${info}: [module ${mname}] Primop ${op} requires all operands to have the same type.")
+ class NodePassiveType(info:Info) extends PassException(s"${info}: [module ${mname}] Node must be a passive type.")
+ class MuxSameType(info:Info) extends PassException(s"${info}: [module ${mname}] Must mux between equivalent types.")
+ class MuxPassiveTypes(info:Info) extends PassException(s"${info}: [module ${mname}] Must mux between passive types.")
+ class MuxCondUInt(info:Info) extends PassException(s"${info}: [module ${mname}] A mux condition must be of type UInt.")
+ class ValidIfPassiveTypes(info:Info) extends PassException(s"${info}: [module ${mname}] Must validif a passive type.")
+ class ValidIfCondUInt(info:Info) extends PassException(s"${info}: [module ${mname}] A validif condition must be of type UInt.")
+ //;---------------- Helper Functions --------------
+ def ut () : UIntType = UIntType(UnknownWidth())
+ def st () : SIntType = SIntType(UnknownWidth())
+
+ def check_types_primop (e:DoPrim, errors:ArrayBuffer[PassException],info:Info) : Unit = {
+ def all_same_type (ls:Seq[Expression]) : Unit = {
+ var error = false
+ for (x <- ls) {
+ if (wt(tpe(ls.head)) != wt(tpe(x))) error = true
+ }
+ if (error) errors += new OpNotAllSameType(info,e.op.serialize())
+ }
+ def all_ground (ls:Seq[Expression]) : Unit = {
+ var error = false
+ for (x <- ls ) {
+ if (!(tpe(x).typeof[UIntType] || tpe(x).typeof[SIntType])) error = true
+ }
+ if (error) errors += new OpNotGround(info,e.op.serialize())
+ }
+ def all_uint (ls:Seq[Expression]) : Unit = {
+ var error = false
+ for (x <- ls ) {
+ if (!(tpe(x).typeof[UIntType])) error = true
+ }
+ if (error) errors += new OpNotAllUInt(info,e.op.serialize())
+ }
+ def is_uint (x:Expression) : Unit = {
+ var error = false
+ if (!(tpe(x).typeof[UIntType])) error = true
+ if (error) errors += new OpNotUInt(info,e.op.serialize(),x.serialize())
+ }
+
+ e.op match {
+ case AS_UINT_OP => {}
+ case AS_SINT_OP => {}
+ case AS_CLOCK_OP => {}
+ case DYN_SHIFT_LEFT_OP => is_uint(e.args(1)); all_ground(e.args)
+ case DYN_SHIFT_RIGHT_OP => is_uint(e.args(1)); all_ground(e.args)
+ case ADD_OP => all_ground(e.args)
+ case SUB_OP => all_ground(e.args)
+ case MUL_OP => all_ground(e.args)
+ case DIV_OP => all_ground(e.args)
+ case REM_OP => all_ground(e.args)
+ case LESS_OP => all_ground(e.args)
+ case LESS_EQ_OP => all_ground(e.args)
+ case GREATER_OP => all_ground(e.args)
+ case GREATER_EQ_OP => all_ground(e.args)
+ case EQUAL_OP => all_ground(e.args)
+ case NEQUAL_OP => all_ground(e.args)
+ case PAD_OP => all_ground(e.args)
+ case SHIFT_LEFT_OP => all_ground(e.args)
+ case SHIFT_RIGHT_OP => all_ground(e.args)
+ case CONVERT_OP => all_ground(e.args)
+ case NEG_OP => all_ground(e.args)
+ case NOT_OP => all_ground(e.args)
+ case AND_OP => all_ground(e.args)
+ case OR_OP => all_ground(e.args)
+ case XOR_OP => all_ground(e.args)
+ case AND_REDUCE_OP => all_ground(e.args)
+ case OR_REDUCE_OP => all_ground(e.args)
+ case XOR_REDUCE_OP => all_ground(e.args)
+ case CONCAT_OP => all_ground(e.args)
+ case BITS_SELECT_OP => all_ground(e.args)
+ case HEAD_OP => all_ground(e.args)
+ case TAIL_OP => all_ground(e.args)
+ }
+ }
+
+ def run (c:Circuit) : Circuit = {
+ val errors = ArrayBuffer[PassException]()
+ def passive (t:Type) : Boolean = {
+ (t) match {
+ case (_:UIntType|_:SIntType) => true
+ case (t:VectorType) => passive(t.tpe)
+ case (t:BundleType) => {
+ var p = true
+ for (x <- t.fields ) {
+ if (x.flip == REVERSE) p = false
+ if (!passive(x.tpe)) p = false
+ }
+ p
+ }
+ case (t) => true
+ }
+ }
+ def check_types_e (info:Info)(e:Expression) : Expression = {
+ (eMap(check_types_e(info) _,e)) match {
+ case (e:WRef) => e
+ case (e:WSubField) => {
+ (tpe(e.exp)) match {
+ case (t:BundleType) => {
+ val ft = t.fields.find(p => p.name == e.name)
+ if (ft == None) errors += new SubfieldNotInBundle(info,e.name)
+ }
+ case (t) => errors += new SubfieldOnNonBundle(info,e.name)
+ }
+ }
+ case (e:WSubIndex) => {
+ (tpe(e.exp)) match {
+ case (t:VectorType) => {
+ if (e.value >= t.size) errors += new IndexTooLarge(info,e.value)
+ }
+ case (t) => errors += new IndexOnNonVector(info)
+ }
+ }
+ case (e:WSubAccess) => {
+ (tpe(e.exp)) match {
+ case (t:VectorType) => false
+ case (t) => errors += new IndexOnNonVector(info)
+ }
+ (tpe(e.index)) match {
+ case (t:UIntType) => false
+ case (t) => errors += new AccessIndexNotUInt(info)
+ }
+ }
+ case (e:DoPrim) => check_types_primop(e,errors,info)
+ case (e:Mux) => {
+ if (wt(tpe(e.tval)) != wt(tpe(e.fval))) errors += new MuxSameType(info)
+ if (!passive(tpe(e))) errors += new MuxPassiveTypes(info)
+ if (!passive(tpe(e))) errors += new MuxPassiveTypes(info)
+ if (!(tpe(e.cond).typeof[UIntType])) errors += new MuxCondUInt(info)
+ }
+ case (e:ValidIf) => {
+ if (!passive(tpe(e))) errors += new ValidIfPassiveTypes(info)
+ if (!(tpe(e.cond).typeof[UIntType])) errors += new ValidIfCondUInt(info)
+ }
+ case (_:UIntValue|_:SIntValue) => false
+ }
+ e
+ }
+
+ def bulk_equals (t1:Type,t2:Type) : Boolean = {
+ (t1,t2) match {
+ case (t1:BundleType,t2:BundleType) => {
+ var same = true
+ (t1.fields, t2.fields).zipped.map{ (f1,f2) => {
+ if (f1.name == f2.name) {
+ if (f1.flip != f2.flip) same = false
+ if (!bulk_equals(f1.tpe,f2.tpe)) same = false
+ }
+ }}
+ same
+ }
+ case (t1:ClockType,t2:ClockType) => true
+ case (t1:UIntType,t2:UIntType) => true
+ case (t1:SIntType,t2:SIntType) => true
+ case (t1:VectorType,t2:VectorType) => {
+ if (bulk_equals(t1.tpe,t2.tpe)) true
+ else false
+ }
+ case (t1,t2) => false
+ }
+ }
+
+ def check_types_s (s:Stmt) : Stmt = {
+ eMap(check_types_e(get_info(s)) _,s) match {
+ case (s:Connect) => if (wt(tpe(s.loc)) != wt(tpe(s.exp))) errors += new InvalidConnect(s.info)
+ case (s:BulkConnect) => if (!bulk_equals(tpe(s.loc),tpe(s.exp)) ) errors += new InvalidConnect(s.info)
+ case (s:Stop) => {
+ if (wt(tpe(s.clk)) != wt(ClockType()) ) errors += new ReqClk(s.info)
+ if (wt(tpe(s.en)) != wt(ut()) ) errors += new EnNotUInt(s.info)
+ }
+ case (s:Print)=> {
+ for (x <- s.args ) {
+ if (wt(tpe(x)) != wt(ut()) && wt(tpe(x)) != wt(st()) ) errors += new PrintfArgNotGround(s.info)
+ }
+ if (wt(tpe(s.clk)) != wt(ClockType()) ) errors += new ReqClk(s.info)
+ if (wt(tpe(s.en)) != wt(ut()) ) errors += new EnNotUInt(s.info)
+ }
+ case (s:Conditionally) => if (wt(tpe(s.pred)) != wt(ut()) ) errors += new PredNotUInt(s.info)
+ case (s:DefNode) => if (!passive(tpe(s.value)) ) errors += new NodePassiveType(s.info)
+ case (s) => false
+ }
+ sMap(check_types_s,s)
+ }
+
+ for (m <- c.modules ) {
+ mname = m.name
+ (m) match {
+ case (m:ExModule) => false
+ case (m:InModule) => check_types_s(m.body)
+ }
+ }
+ if (errors.nonEmpty) throw new PassExceptions(errors)
+ c
+ }
+}
+
+object CheckGenders extends Pass {
+ def name = "Check Genders"
+ var mname = ""
+ class WrongGender (info:Info,expr:String,wrong:String,right:String) extends PassException(s"${info}: [module ${mname}] Expression ${expr} is used as a ${wrong} but can only be used as a ${right}.")
+
+ def dir_to_gender (d:Direction) : Gender = {
+ d match {
+ case INPUT => MALE
+ case OUTPUT => FEMALE //BI-GENDER
+ }
+ }
+
+ def as_srcsnk (g:Gender) : String = {
+ g match {
+ case MALE => "source"
+ case FEMALE => "sink"
+ case UNKNOWNGENDER => "unknown"
+ case BIGENDER => "sourceOrSink"
+ }
+ }
+
+ def run (c:Circuit): Circuit = {
+ val errors = ArrayBuffer[PassException]()
+ def get_kind (e:Expression) : Kind = {
+ (e) match {
+ case (e:WRef) => e.kind
+ case (e:WSubField) => get_kind(e.exp)
+ case (e:WSubIndex) => get_kind(e.exp)
+ case (e:WSubAccess) => get_kind(e.exp)
+ case (e) => NodeKind()
+ }
+ }
+
+ def check_gender (info:Info,genders:HashMap[String,Gender],desired:Gender)(e:Expression) : Expression = {
+ val gender = get_gender(e,genders)
+ val kindx = get_kind(e)
+ def flipQ (t:Type) : Boolean = {
+ var fQ = false
+ def flip_rec (t:Type,f:Flip) : Type = {
+ (t) match {
+ case (t:BundleType) => {
+ for (field <- t.fields) {
+ flip_rec(field.tpe,times(f, field.flip))
+ }
+ }
+ case (t:VectorType) => flip_rec(t.tpe,f)
+ case (t) => if (f == REVERSE) fQ = true
+ }
+ t
+ }
+ flip_rec(t,DEFAULT)
+ fQ
+ }
+
+ val has_flipQ = flipQ(tpe(e))
+ //println(e)
+ //println(gender)
+ //println(desired)
+ //println(kindx)
+ //println(desired == gender)
+ //if gender != desired and gender != BI-GENDER:
+ (gender,desired) match {
+ case (MALE, FEMALE) => errors += new WrongGender(info,e.serialize(),as_srcsnk(desired),as_srcsnk(gender))
+ case (FEMALE, MALE) =>
+ if ((kindx == PortKind() || kindx == InstanceKind()) && has_flipQ == false) {
+ //; OK!
+ false
+ } else {
+ //; Not Ok!
+ errors += new WrongGender(info,e.serialize(),as_srcsnk(desired),as_srcsnk(gender))
+ }
+ case _ => false
+ }
+ e
+ }
+
+ def get_gender (e:Expression,genders:HashMap[String,Gender]) : Gender = {
+ (e) match {
+ case (e:WRef) => genders(e.name)
+ case (e:WSubField) =>
+ val f = tpe(e.exp).as[BundleType].get.fields.find(f => f.name == e.name).get
+ times(get_gender(e.exp,genders),f.flip)
+ case (e:WSubIndex) => get_gender(e.exp,genders)
+ case (e:WSubAccess) => get_gender(e.exp,genders)
+ case (e:DoPrim) => MALE
+ case (e:UIntValue) => MALE
+ case (e:SIntValue) => MALE
+ case (e:Mux) => MALE
+ case (e:ValidIf) => MALE
+ }
+ }
+
+ def check_genders_e (info:Info,genders:HashMap[String,Gender])(e:Expression) : Expression = {
+ eMap(check_genders_e(info,genders) _,e)
+ (e) match {
+ case (e:WRef) => false
+ case (e:WSubField) => false
+ case (e:WSubIndex) => false
+ case (e:WSubAccess) => false
+ case (e:DoPrim) => for (e <- e.args ) { check_gender(info,genders,MALE)(e) }
+ case (e:Mux) => eMap(check_gender(info,genders,MALE) _,e)
+ case (e:ValidIf) => eMap(check_gender(info,genders,MALE) _,e)
+ case (e:UIntValue) => false
+ case (e:SIntValue) => false
+ }
+ e
+ }
+
+ def check_genders_s (genders:HashMap[String,Gender])(s:Stmt) : Stmt = {
+ eMap(check_genders_e(get_info(s),genders) _,s)
+ sMap(check_genders_s(genders) _,s)
+ (s) match {
+ case (s:DefWire) => genders(s.name) = BIGENDER
+ case (s:DefPoison) => genders(s.name) = MALE
+ case (s:DefRegister) => genders(s.name) = BIGENDER
+ case (s:DefNode) => {
+ check_gender(s.info,genders,MALE)(s.value)
+ genders(s.name) = MALE
+ }
+ case (s:DefMemory) => genders(s.name) = MALE
+ case (s:WDefInstance) => genders(s.name) = MALE
+ case (s:Connect) => {
+ check_gender(s.info,genders,FEMALE)(s.loc)
+ check_gender(s.info,genders,MALE)(s.exp)
+ }
+ case (s:Print) => {
+ for (x <- s.args ) {
+ check_gender(s.info,genders,MALE)(x)
+ }
+ check_gender(s.info,genders,MALE)(s.en)
+ check_gender(s.info,genders,MALE)(s.clk)
+ }
+ case (s:BulkConnect) => {
+ check_gender(s.info,genders,FEMALE)(s.loc)
+ check_gender(s.info,genders,MALE)(s.exp)
+ }
+ case (s:Conditionally) => {
+ check_gender(s.info,genders,MALE)(s.pred)
+ }
+ case (s:Empty) => false
+ case (s:Stop) => {
+ check_gender(s.info,genders,MALE)(s.en)
+ check_gender(s.info,genders,MALE)(s.clk)
+ }
+ case (_:Begin|_:IsInvalid) => false
+ }
+ s
+ }
+
+ for (m <- c.modules ) {
+ mname = m.name
+ val genders = HashMap[String,Gender]()
+ for (p <- m.ports) {
+ genders(p.name) = dir_to_gender(p.direction)
+ }
+ (m) match {
+ case (m:ExModule) => false
+ case (m:InModule) => check_genders_s(genders)(m.body)
+ }
+ }
+ if (errors.nonEmpty) throw new PassExceptions(errors)
+ c
+ }
+}
+
+object CheckWidths extends Pass with StanzaPass {
+ def name = "Width Check"
+ var mname = ""
+ class UninferredWidth (info:Info) extends PassException(s"${info} : [module ${mname}] Uninferred width.")
+ class WidthTooSmall (info:Info,v:String) extends PassException(s"${info} : [module ${mname} Width too small for constant ${v}.")
+ class NegWidthException(info:Info) extends PassException(s"${info}: [module ${mname}] Width cannot be negative or zero.")
+ def run (c:Circuit): Circuit = {
+ val errors = ArrayBuffer[PassException]()
+ def check_width_m (m:Module) : Unit = {
+ def check_width_w (info:Info)(w:Width) : Width = {
+ (w) match {
+ case (w:IntWidth)=> if (w.width <= 0) errors += new NegWidthException(info)
+ case (w) => errors += new UninferredWidth(info)
+ }
+ w
+ }
+ def check_width_e (info:Info)(e:Expression) : Expression = {
+ (eMap(check_width_e(info) _,e)) match {
+ case (e:UIntValue) => {
+ (e.width) match {
+ case (w:IntWidth) =>
+ if (scala.math.max(1,e.value.bitLength) > w.width) {
+ errors += new WidthTooSmall(info,e.value.serialize())
+ }
+ case (w) => errors += new UninferredWidth(info)
+ }
+ check_width_w(info)(e.width)
+ }
+ case (e:SIntValue) => {
+ (e.width) match {
+ case (w:IntWidth) =>
+ if (e.value.bitLength + 1 > w.width) errors += new WidthTooSmall(info,e.value.serialize())
+ case (w) => errors += new UninferredWidth(info)
+ }
+ check_width_w(info)(e.width)
+ }
+ case (e:DoPrim) => false
+ case (e) => false
+ }
+ e
+ }
+ def check_width_s (s:Stmt) : Stmt = {
+ eMap(check_width_e(get_info(s)) _,sMap(check_width_s _,s))
+ def tm (t:Type) : Type = mapr(check_width_w(info(s)) _,t)
+ tMap(tm _,s)
+ }
+
+ for (p <- m.ports) {
+ mapr(check_width_w(p.info) _,p.tpe)
+ }
+
+ (m) match {
+ case (m:ExModule) => {}
+ case (m:InModule) => check_width_s(m.body)
+ }
+ }
+
+ for (m <- c.modules) {
+ mname = m.name
+ check_width_m(m)
+ }
+ if (errors.nonEmpty) throw new PassExceptions(errors)
+ c
+ }
+}
+
+object CheckInitialization extends Pass with StanzaPass {
+ def name = "Check Initialization"
+ var mname = ""
+ class RefNotInitialized (info:Info, name:String) extends PassException(s"${info} : [module ${mname} Reference ${name} is not fully initialized.")
+ def run (c:Circuit): Circuit = {
+ val errors = ArrayBuffer[PassException]()
+ def check_init_m (m:InModule) : Unit = {
+ def get_name (e:Expression) : String = {
+ (e) match {
+ case (e:WRef) => e.name
+ case (e:WSubField) => get_name(e.exp) + "." + e.name
+ case (e:WSubIndex) => get_name(e.exp) + "[" + e.value + "]"
+ case (e) => error("Shouldn't be here"); ""
+ }
+ }
+ def has_voidQ (e:Expression) : Boolean = {
+ var void = false
+ def has_void (e:Expression) : Expression = {
+ (e) match {
+ case (e:WVoid) => void = true; e
+ case (e) => eMap(has_void,e)
+ }
+ }
+ has_void(e)
+ void
+ }
+ def check_init_s (s:Stmt) : Stmt = {
+ (s) match {
+ case (s:Connect) => {
+ if (has_voidQ(s.exp)) errors += new RefNotInitialized(s.info,get_name(s.loc))
+ s
+ }
+ case (s) => sMap(check_init_s,s)
+ }
+ }
+ check_init_s(m.body)
+ }
+
+ for (m <- c.modules) {
+ mname = m.name
+ (m) match {
+ case (m:InModule) => check_init_m(m)
+ case (m) => false
+ }
+ }
+
+ if (errors.nonEmpty) throw new PassExceptions(errors)
+ c
+ }
+}
diff --git a/src/main/scala/firrtl/passes/Passes.scala b/src/main/scala/firrtl/passes/Passes.scala
new file mode 100644
index 00000000..e8a2106c
--- /dev/null
+++ b/src/main/scala/firrtl/passes/Passes.scala
@@ -0,0 +1,1926 @@
+/*
+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 com.typesafe.scalalogging.LazyLogging
+import java.nio.file.{Paths, Files}
+
+// For calling Stanza
+import scala.sys.process._
+import scala.io.Source
+
+// Datastructures
+import scala.collection.mutable.LinkedHashMap
+import scala.collection.mutable.ArrayBuffer
+
+import firrtl._
+import firrtl.Utils._
+import firrtl.PrimOps._
+import firrtl.WrappedExpression._
+
+trait Pass extends LazyLogging {
+ def name: String
+ def run(c: Circuit): Circuit
+}
+
+// Error handling
+class PassException(message: String) extends Exception(message)
+class PassExceptions(exceptions: Seq[PassException]) extends Exception("\n" + exceptions.mkString("\n"))
+
+// Trait for migration, trap to Stanza implementation for passes not yet implemented in Scala
+trait StanzaPass extends LazyLogging {
+ def stanzaPass(c: Circuit, n: String): Circuit = {
+ // For migration from Stanza, handle unimplemented Passes
+ logger.debug(s"Pass ${n} is not yet implemented in Scala")
+ val stanzaPasses = Seq("resolve", n)
+ val toStanza = Files.createTempFile(Paths.get(""), n, ".fir")
+ val fromStanza = Files.createTempFile(Paths.get(""), n, ".fir")
+ Files.write(toStanza, c.serialize.getBytes)
+
+ val cmd = Seq("firrtl-stanza", "-i", toStanza.toString, "-o", fromStanza.toString, "-b", "firrtl", "-p", "c") ++
+ stanzaPasses.flatMap(x=>Seq("-x", x))
+ logger.debug(cmd.mkString(" "))
+ val ret = cmd.!
+ //println(ret)
+ val newC = Parser.parse(fromStanza.toString, Source.fromFile(fromStanza.toString).getLines)
+ Files.delete(toStanza)
+ Files.delete(fromStanza)
+ newC
+ }
+}
+
+object PassUtils extends LazyLogging {
+ val listOfPasses: Seq[Pass] = Seq(ToWorkingIR,ResolveKinds,InferTypes,ResolveGenders,InferWidths,PullMuxes,ExpandConnects,RemoveAccesses,ExpandWhens,LowerTypes)
+ lazy val mapNameToPass: Map[String, Pass] = listOfPasses.map(p => p.name -> p).toMap
+
+ def executePasses(c: Circuit, passes: Seq[Pass]): Circuit = {
+ if (passes.isEmpty) {logger.debug(s"Done!"); c}
+ else {
+ val p = passes.head
+ val name = p.name
+ logger.debug(s"Starting ${name}")
+ val x = p.run(c)
+ logger.debug(x.serialize())
+ logger.debug(s"Finished ${name}")
+ executePasses(x, passes.tail)
+ }
+ }
+}
+
+// These should be distributed into separate files
+object ToWorkingIR extends Pass {
+ private var mname = ""
+ def name = "Working IR"
+ def run (c:Circuit): Circuit = {
+ def toExp (e:Expression) : Expression = {
+ eMap(toExp _,e) match {
+ case e:Ref => WRef(e.name, e.tpe, NodeKind(), UNKNOWNGENDER)
+ case e:SubField => WSubField(e.exp, e.name, e.tpe, UNKNOWNGENDER)
+ case e:SubIndex => WSubIndex(e.exp, e.value, e.tpe, UNKNOWNGENDER)
+ case e:SubAccess => WSubAccess(e.exp, e.index, e.tpe, UNKNOWNGENDER)
+ case e => e
+ }
+ }
+ def toStmt (s:Stmt) : Stmt = {
+ eMap(toExp _,s) match {
+ case s:DefInstance => WDefInstance(s.info,s.name,s.module,UnknownType())
+ case s => sMap(toStmt _,s)
+ }
+ }
+ val modulesx = c.modules.map { m =>
+ mname = m.name
+ m match {
+ case m:InModule => InModule(m.info,m.name, m.ports, toStmt(m.body))
+ case m:ExModule => m
+ }
+ }
+ Circuit(c.info,modulesx,c.main)
+ }
+}
+
+object Resolve extends Pass with StanzaPass {
+ def name = "Resolve"
+ def run (c:Circuit): Circuit = stanzaPass(c, "resolve")
+}
+
+object ResolveKinds extends Pass {
+ private var mname = ""
+ def name = "Resolve Kinds"
+ def run (c:Circuit): Circuit = {
+ def resolve_kinds (m:Module, c:Circuit):Module = {
+ val kinds = LinkedHashMap[String,Kind]()
+ def resolve (body:Stmt) = {
+ def resolve_expr (e:Expression):Expression = {
+ e match {
+ case e:WRef => WRef(e.name,tpe(e),kinds(e.name),e.gender)
+ case e => eMap(resolve_expr,e)
+ }
+ }
+ def resolve_stmt (s:Stmt):Stmt = eMap(resolve_expr,sMap(resolve_stmt,s))
+ resolve_stmt(body)
+ }
+
+ def find (m:Module) = {
+ def find_stmt (s:Stmt):Stmt = {
+ s match {
+ case s:DefWire => kinds(s.name) = WireKind()
+ case s:DefPoison => kinds(s.name) = PoisonKind()
+ case s:DefNode => kinds(s.name) = NodeKind()
+ case s:DefRegister => kinds(s.name) = RegKind()
+ case s:WDefInstance => kinds(s.name) = InstanceKind()
+ case s:DefMemory => kinds(s.name) = MemKind(s.readers ++ s.writers ++ s.readwriters)
+ case s => false
+ }
+ sMap(find_stmt,s)
+ }
+ m.ports.foreach { p => kinds(p.name) = PortKind() }
+ m match {
+ case m:InModule => find_stmt(m.body)
+ case m:ExModule => false
+ }
+ }
+
+ mname = m.name
+ find(m)
+ m match {
+ case m:InModule => {
+ val bodyx = resolve(m.body)
+ InModule(m.info,m.name,m.ports,bodyx)
+ }
+ case m:ExModule => ExModule(m.info,m.name,m.ports)
+ }
+ }
+ val modulesx = c.modules.map(m => resolve_kinds(m,c))
+ Circuit(c.info,modulesx,c.main)
+ }
+}
+
+object InferTypes extends Pass {
+ private var mname = ""
+ def name = "Infer Types"
+ val width_name_hash = LinkedHashMap[String,Int]()
+ def set_type (s:Stmt,t:Type) : Stmt = {
+ s match {
+ case s:DefWire => DefWire(s.info,s.name,t)
+ case s:DefRegister => DefRegister(s.info,s.name,t,s.clock,s.reset,s.init)
+ case s:DefMemory => DefMemory(s.info,s.name,t,s.depth,s.write_latency,s.read_latency,s.readers,s.writers,s.readwriters)
+ case s:DefNode => s
+ case s:DefPoison => DefPoison(s.info,s.name,t)
+ }
+ }
+ def remove_unknowns_w (w:Width):Width = {
+ w match {
+ case w:UnknownWidth => VarWidth(firrtl_gensym("w",width_name_hash))
+ case w => w
+ }
+ }
+ def remove_unknowns (t:Type): Type = mapr(remove_unknowns_w _,t)
+ def run (c:Circuit): Circuit = {
+ val module_types = LinkedHashMap[String,Type]()
+ def infer_types (m:Module) : Module = {
+ val types = LinkedHashMap[String,Type]()
+ def infer_types_e (e:Expression) : Expression = {
+ eMap(infer_types_e _,e) match {
+ case e:ValidIf => ValidIf(e.cond,e.value,tpe(e.value))
+ case e:WRef => WRef(e.name, types(e.name),e.kind,e.gender)
+ case e:WSubField => WSubField(e.exp,e.name,field_type(tpe(e.exp),e.name),e.gender)
+ case e:WSubIndex => WSubIndex(e.exp,e.value,sub_type(tpe(e.exp)),e.gender)
+ case e:WSubAccess => WSubAccess(e.exp,e.index,sub_type(tpe(e.exp)),e.gender)
+ case e:DoPrim => set_primop_type(e)
+ case e:Mux => Mux(e.cond,e.tval,e.fval,mux_type_and_widths(e.tval,e.fval))
+ case e:UIntValue => e
+ case e:SIntValue => e
+ }
+ }
+ def infer_types_s (s:Stmt) : Stmt = {
+ s match {
+ case s:DefRegister => {
+ val t = remove_unknowns(get_type(s))
+ types(s.name) = t
+ eMap(infer_types_e _,set_type(s,t))
+ }
+ case s:DefWire => {
+ val sx = eMap(infer_types_e _,s)
+ val t = remove_unknowns(get_type(sx))
+ types(s.name) = t
+ set_type(sx,t)
+ }
+ case s:DefPoison => {
+ val sx = eMap(infer_types_e _,s)
+ val t = remove_unknowns(get_type(sx))
+ types(s.name) = t
+ set_type(sx,t)
+ }
+ case s:DefNode => {
+ val sx = eMap(infer_types_e _,s)
+ val t = remove_unknowns(get_type(sx))
+ types(s.name) = t
+ set_type(sx,t)
+ }
+ case s:DefMemory => {
+ val t = remove_unknowns(get_type(s))
+ types(s.name) = t
+ val dt = remove_unknowns(s.data_type)
+ set_type(s,dt)
+ }
+ case s:WDefInstance => {
+ types(s.name) = module_types(s.module)
+ WDefInstance(s.info,s.name,s.module,module_types(s.module))
+ }
+ case s => eMap(infer_types_e _,sMap(infer_types_s,s))
+ }
+ }
+
+ mname = m.name
+ m.ports.foreach(p => types(p.name) = p.tpe)
+ m match {
+ case m:InModule => InModule(m.info,m.name,m.ports,infer_types_s(m.body))
+ case m:ExModule => m
+ }
+ }
+
+ val modulesx = c.modules.map {
+ m => {
+ mname = m.name
+ val portsx = m.ports.map(p => Port(p.info,p.name,p.direction,remove_unknowns(p.tpe)))
+ m match {
+ case m:InModule => InModule(m.info,m.name,portsx,m.body)
+ case m:ExModule => ExModule(m.info,m.name,portsx)
+ }
+ }
+ }
+ modulesx.foreach(m => module_types(m.name) = module_type(m))
+ Circuit(c.info,modulesx.map({m => mname = m.name; infer_types(m)}) , c.main )
+ }
+}
+
+object ResolveGenders extends Pass {
+ private var mname = ""
+ def name = "Resolve Genders"
+ def run (c:Circuit): Circuit = {
+ def resolve_e (g:Gender)(e:Expression) : Expression = {
+ e match {
+ case e:WRef => WRef(e.name,e.tpe,e.kind,g)
+ case e:WSubField => {
+ val expx =
+ field_flip(tpe(e.exp),e.name) match {
+ case DEFAULT => resolve_e(g)(e.exp)
+ case REVERSE => resolve_e(swap(g))(e.exp)
+ }
+ WSubField(expx,e.name,e.tpe,g)
+ }
+ case e:WSubIndex => {
+ val expx = resolve_e(g)(e.exp)
+ WSubIndex(expx,e.value,e.tpe,g)
+ }
+ case e:WSubAccess => {
+ val expx = resolve_e(g)(e.exp)
+ val indexx = resolve_e(MALE)(e.index)
+ WSubAccess(expx,indexx,e.tpe,g)
+ }
+ case e => eMap(resolve_e(g) _,e)
+ }
+ }
+
+ def resolve_s (s:Stmt) : Stmt = {
+ s match {
+ case s:IsInvalid => {
+ val expx = resolve_e(FEMALE)(s.exp)
+ IsInvalid(s.info,expx)
+ }
+ case s:Connect => {
+ val locx = resolve_e(FEMALE)(s.loc)
+ val expx = resolve_e(MALE)(s.exp)
+ Connect(s.info,locx,expx)
+ }
+ case s:BulkConnect => {
+ val locx = resolve_e(FEMALE)(s.loc)
+ val expx = resolve_e(MALE)(s.exp)
+ BulkConnect(s.info,locx,expx)
+ }
+ case s => sMap(resolve_s,eMap(resolve_e(MALE) _,s))
+ }
+ }
+ val modulesx = c.modules.map {
+ m => {
+ mname = m.name
+ m match {
+ case m:InModule => {
+ val bodyx = resolve_s(m.body)
+ InModule(m.info,m.name,m.ports,bodyx)
+ }
+ case m:ExModule => m
+ }
+ }
+ }
+ Circuit(c.info,modulesx,c.main)
+ }
+}
+
+object InferWidths extends Pass {
+ def name = "Infer Widths"
+ var mname = ""
+ def solve_constraints (l:Seq[WGeq]) : LinkedHashMap[String,Width] = {
+ def unique (ls:Seq[Width]) : Seq[Width] = ls.map(w => new WrappedWidth(w)).distinct.map(_.w)
+ def make_unique (ls:Seq[WGeq]) : LinkedHashMap[String,Width] = {
+ val h = LinkedHashMap[String,Width]()
+ for (g <- ls) {
+ (g.loc) match {
+ case (w:VarWidth) => {
+ val n = w.name
+ if (h.contains(n)) h(n) = MaxWidth(Seq(g.exp,h(n))) else h(n) = g.exp
+ }
+ case (w) => w
+ }
+ }
+ h
+ }
+ def simplify (w:Width) : Width = {
+ (wMap(simplify _,w)) match {
+ case (w:MinWidth) => {
+ val v = ArrayBuffer[Width]()
+ for (wx <- w.args) {
+ (wx) match {
+ case (wx:MinWidth) => for (x <- wx.args) { v += x }
+ case (wx) => v += wx } }
+ MinWidth(unique(v)) }
+ case (w:MaxWidth) => {
+ val v = ArrayBuffer[Width]()
+ for (wx <- w.args) {
+ (wx) match {
+ case (wx:MaxWidth) => for (x <- wx.args) { v += x }
+ case (wx) => v += wx } }
+ MaxWidth(unique(v)) }
+ case (w:PlusWidth) => {
+ (w.arg1,w.arg2) match {
+ case (w1:IntWidth,w2:IntWidth) => IntWidth(w1.width + w2.width)
+ case (w1,w2) => w }}
+ case (w:MinusWidth) => {
+ (w.arg1,w.arg2) match {
+ case (w1:IntWidth,w2:IntWidth) => IntWidth(w1.width - w2.width)
+ case (w1,w2) => w }}
+ case (w:ExpWidth) => {
+ (w.arg1) match {
+ case (w1:IntWidth) => IntWidth(BigInt((scala.math.pow(2,w1.width.toDouble) - 1).toLong))
+ case (w1) => w }}
+ case (w) => w } }
+ def substitute (h:LinkedHashMap[String,Width])(w:Width) : Width = {
+ //;println-all-debug(["Substituting for [" w "]"])
+ val wx = simplify(w)
+ //;println-all-debug(["After Simplify: [" wx "]"])
+ (wMap(substitute(h) _,simplify(w))) match {
+ case (w:VarWidth) => {
+ //;("matched println-debugvarwidth!")
+ if (h.contains(w.name)) {
+ //;println-debug("Contained!")
+ //;println-all-debug(["Width: " w])
+ //;println-all-debug(["Accessed: " h[name(w)]])
+ val t = simplify(substitute(h)(h(w.name)))
+ //;val t = h[name(w)]
+ //;println-all-debug(["Width after sub: " t])
+ h(w.name) = t
+ t
+ } else w
+ }
+ case (w) => w
+ //;println-all-debug(["not varwidth!" w])
+ }
+ }
+ def b_sub (h:LinkedHashMap[String,Width])(w:Width) : Width = {
+ (wMap(b_sub(h) _,w)) match {
+ case (w:VarWidth) => if (h.contains(w.name)) h(w.name) else w
+ case (w) => w
+ }
+ }
+ def remove_cycle (n:String)(w:Width) : Width = {
+ //;println-all-debug(["Removing cycle for " n " inside " w])
+ val wx = (wMap(remove_cycle(n) _,w)) match {
+ case (w:MaxWidth) => MaxWidth(w.args.filter{ w => {
+ w match {
+ case (w:VarWidth) => !(n equals w.name)
+ case (w) => true
+ }}})
+ case (w:MinusWidth) => {
+ w.arg1 match {
+ case (v:VarWidth) => if (n == v.name) v else w
+ case (v) => w }}
+ case (w) => w
+ }
+ //;println-all-debug(["After removing cycle for " n ", returning " wx])
+ wx
+ }
+ def self_rec (n:String,w:Width) : Boolean = {
+ var has = false
+ def look (w:Width) : Width = {
+ (wMap(look _,w)) match {
+ case (w:VarWidth) => if (w.name == n) has = true
+ case (w) => w }
+ w }
+ look(w)
+ has }
+
+ //; Forward solve
+ //; Returns a solved list where each constraint undergoes:
+ //; 1) Continuous Solving (using triangular solving)
+ //; 2) Remove Cycles
+ //; 3) Move to solved if not self-recursive
+ val u = make_unique(l)
+
+ //println("======== UNIQUE CONSTRAINTS ========")
+ //for (x <- u) { println(x) }
+ //println("====================================")
+
+
+ val f = LinkedHashMap[String,Width]()
+ val o = ArrayBuffer[String]()
+ for (x <- u) {
+ //println("==== SOLUTIONS TABLE ====")
+ //for (x <- f) println(x)
+ //println("=========================")
+
+ val (n, e) = (x._1, x._2)
+ val e_sub = substitute(f)(e)
+
+ //println("Solving " + n + " => " + e)
+ //println("After Substitute: " + n + " => " + e_sub)
+ //println("==== SOLUTIONS TABLE (Post Substitute) ====")
+ //for (x <- f) println(x)
+ //println("=========================")
+
+ val ex = remove_cycle(n)(e_sub)
+
+ //println("After Remove Cycle: " + n + " => " + ex)
+ if (!self_rec(n,ex)) {
+ //println("Not rec!: " + n + " => " + ex)
+ //println("Adding [" + n + "=>" + ex + "] to Solutions Table")
+ o += n
+ f(n) = ex
+ }
+ }
+
+ //println("Forward Solved Constraints")
+ //for (x <- f) println(x)
+
+ //; Backwards Solve
+ val b = LinkedHashMap[String,Width]()
+ for (i <- 0 until o.size) {
+ val n = o(o.size - 1 - i)
+ /*
+ println("SOLVE BACK: [" + n + " => " + f(n) + "]")
+ println("==== SOLUTIONS TABLE ====")
+ for (x <- b) println(x)
+ println("=========================")
+ */
+ val ex = simplify(b_sub(b)(f(n)))
+ /*
+ println("BACK RETURN: [" + n + " => " + ex + "]")
+ */
+ b(n) = ex
+ /*
+ println("==== SOLUTIONS TABLE (Post backsolve) ====")
+ for (x <- b) println(x)
+ println("=========================")
+ */
+ }
+ b
+ }
+
+ def width_BANG (t:Type) : Width = {
+ (t) match {
+ case (t:UIntType) => t.width
+ case (t:SIntType) => t.width
+ case (t:ClockType) => IntWidth(1)
+ case (t) => error("No width!"); IntWidth(-1) } }
+ def width_BANG (e:Expression) : Width = width_BANG(tpe(e))
+ def reduce_var_widths (c:Circuit,h:LinkedHashMap[String,Width]) : Circuit = {
+ def evaluate (w:Width) : Width = {
+ def apply_2 (a:Option[BigInt],b:Option[BigInt], f: (BigInt,BigInt) => BigInt) : Option[BigInt] = {
+ (a,b) match {
+ case (a:Some[BigInt],b:Some[BigInt]) => Some(f(a.get,b.get))
+ case (a,b) => None } }
+ def apply_1 (a:Option[BigInt], f: (BigInt) => BigInt) : Option[BigInt] = {
+ (a) match {
+ case (a:Some[BigInt]) => Some(f(a.get))
+ case (a) => None } }
+ def apply_l (l:Seq[Option[BigInt]],f:(BigInt,BigInt) => BigInt) : Option[BigInt] = {
+ if (l.size == 0) Some(BigInt(0)) else apply_2(l.head,apply_l(l.tail,f),f)
+ }
+ def max (a:BigInt,b:BigInt) : BigInt = if (a >= b) a else b
+ def min (a:BigInt,b:BigInt) : BigInt = if (a >= b) b else a
+ def pow (a:BigInt,b:BigInt) : BigInt = BigInt((scala.math.pow(a.toDouble,b.toDouble) - 1).toLong)
+ def solve (w:Width) : Option[BigInt] = {
+ (w) match {
+ case (w:VarWidth) => {
+ val wx = h.get(w.name)
+ (wx) match {
+ case (wx:Some[Width]) => {
+ wx.get match {
+ case (v:VarWidth) => None
+ case (v) => solve(v) }}
+ case (None) => None }}
+ case (w:MaxWidth) => apply_l(w.args.map(solve _),max)
+ case (w:MinWidth) => apply_l(w.args.map(solve _),min)
+ case (w:PlusWidth) => apply_2(solve(w.arg1),solve(w.arg2),{_ + _})
+ case (w:MinusWidth) => apply_2(solve(w.arg1),solve(w.arg2),{_ - _})
+ case (w:ExpWidth) => apply_2(Some(BigInt(2)),solve(w.arg1),pow)
+ case (w:IntWidth) => Some(w.width)
+ case (w) => println(w); error("Shouldn't be here"); None;
+ }
+ }
+ val s = solve(w)
+ (s) match {
+ case (s:Some[BigInt]) => IntWidth(s.get)
+ case (s) => w }
+ }
+
+ def reduce_var_widths_w (w:Width) : Width = {
+ //println-all-debug(["REPLACE: " w])
+ val wx = evaluate(w)
+ //println-all-debug(["WITH: " wx])
+ wx
+ }
+
+ val modulesx = c.modules.map{ m => {
+ val portsx = m.ports.map{ p => {
+ Port(p.info,p.name,p.direction,mapr(reduce_var_widths_w _,p.tpe)) }}
+ (m) match {
+ case (m:ExModule) => ExModule(m.info,m.name,portsx)
+ case (m:InModule) => mname = m.name; InModule(m.info,m.name,portsx,mapr(reduce_var_widths_w _,m.body)) }}}
+ Circuit(c.info,modulesx,c.main)
+ }
+
+ def run (c:Circuit): Circuit = {
+ val v = ArrayBuffer[WGeq]()
+ def constrain (w1:Width,w2:Width) : Unit = v += WGeq(w1,w2)
+ def get_constraints_t (t1:Type,t2:Type,f:Flip) : Unit = {
+ (t1,t2) match {
+ case (t1:UIntType,t2:UIntType) => constrain(t1.width,t2.width)
+ case (t1:SIntType,t2:SIntType) => constrain(t1.width,t2.width)
+ case (t1:BundleType,t2:BundleType) => {
+ (t1.fields,t2.fields).zipped.foreach{ (f1,f2) => {
+ get_constraints_t(f1.tpe,f2.tpe,times(f1.flip,f)) }}}
+ case (t1:VectorType,t2:VectorType) => get_constraints_t(t1.tpe,t2.tpe,f) }}
+ def get_constraints_e (e:Expression) : Expression = {
+ (eMap(get_constraints_e _,e)) match {
+ case (e:Mux) => {
+ constrain(width_BANG(e.cond),ONE)
+ constrain(ONE,width_BANG(e.cond))
+ e }
+ case (e) => e }}
+ def get_constraints (s:Stmt) : Stmt = {
+ (eMap(get_constraints_e _,s)) match {
+ case (s:Connect) => {
+ val n = get_size(tpe(s.loc))
+ val ce_loc = create_exps(s.loc)
+ val ce_exp = create_exps(s.exp)
+ for (i <- 0 until n) {
+ val locx = ce_loc(i)
+ val expx = ce_exp(i)
+ get_flip(tpe(s.loc),i,DEFAULT) match {
+ case DEFAULT => constrain(width_BANG(locx),width_BANG(expx))
+ case REVERSE => constrain(width_BANG(expx),width_BANG(locx)) }}
+ s }
+ case (s:BulkConnect) => {
+ val ls = get_valid_points(tpe(s.loc),tpe(s.exp),DEFAULT,DEFAULT)
+ for (x <- ls) {
+ val locx = create_exps(s.loc)(x._1)
+ val expx = create_exps(s.exp)(x._2)
+ get_flip(tpe(s.loc),x._1,DEFAULT) match {
+ case DEFAULT => constrain(width_BANG(locx),width_BANG(expx))
+ case REVERSE => constrain(width_BANG(expx),width_BANG(locx)) }}
+ s }
+ case (s:DefRegister) => {
+ constrain(width_BANG(s.reset),ONE)
+ constrain(ONE,width_BANG(s.reset))
+ get_constraints_t(s.tpe,tpe(s.init),DEFAULT)
+ s }
+ case (s:Conditionally) => {
+ v += WGeq(width_BANG(s.pred),ONE)
+ v += WGeq(ONE,width_BANG(s.pred))
+ sMap(get_constraints _,s) }
+ case (s) => sMap(get_constraints _,s) }}
+
+ for (m <- c.modules) {
+ (m) match {
+ case (m:InModule) => mname = m.name; get_constraints(m.body)
+ case (m) => false }}
+ //println-debug("======== ALL CONSTRAINTS ========")
+ //for x in v do : println-debug(x)
+ //println-debug("=================================")
+ val h = solve_constraints(v)
+ //println-debug("======== SOLVED CONSTRAINTS ========")
+ //for x in h do : println-debug(x)
+ //println-debug("====================================")
+ reduce_var_widths(Circuit(c.info,c.modules,c.main),h)
+ }
+}
+
+object PullMuxes extends Pass {
+ private var mname = ""
+ def name = "Pull Muxes"
+ def run (c:Circuit): Circuit = {
+ def pull_muxes_e (e:Expression) : Expression = {
+ val ex = eMap(pull_muxes_e _,e) match {
+ case (e:WRef) => e
+ case (e:WSubField) => {
+ e.exp match {
+ case (ex:Mux) => Mux(ex.cond,WSubField(ex.tval,e.name,e.tpe,e.gender),WSubField(ex.fval,e.name,e.tpe,e.gender),e.tpe)
+ case (ex:ValidIf) => ValidIf(ex.cond,WSubField(ex.value,e.name,e.tpe,e.gender),e.tpe)
+ case (ex) => e
+ }
+ }
+ case (e:WSubIndex) => {
+ e.exp match {
+ case (ex:Mux) => Mux(ex.cond,WSubIndex(ex.tval,e.value,e.tpe,e.gender),WSubIndex(ex.fval,e.value,e.tpe,e.gender),e.tpe)
+ case (ex:ValidIf) => ValidIf(ex.cond,WSubIndex(ex.value,e.value,e.tpe,e.gender),e.tpe)
+ case (ex) => e
+ }
+ }
+ case (e:WSubAccess) => {
+ e.exp match {
+ case (ex:Mux) => Mux(ex.cond,WSubAccess(ex.tval,e.index,e.tpe,e.gender),WSubAccess(ex.fval,e.index,e.tpe,e.gender),e.tpe)
+ case (ex:ValidIf) => ValidIf(ex.cond,WSubAccess(ex.value,e.index,e.tpe,e.gender),e.tpe)
+ case (ex) => e
+ }
+ }
+ case (e:Mux) => e
+ case (e:ValidIf) => e
+ case (e) => e
+ }
+ eMap(pull_muxes_e _,ex)
+ }
+ def pull_muxes (s:Stmt) : Stmt = eMap(pull_muxes_e _,sMap(pull_muxes _,s))
+ val modulesx = c.modules.map {
+ m => {
+ mname = m.name
+ m match {
+ case (m:InModule) => InModule(m.info,m.name,m.ports,pull_muxes(m.body))
+ case (m:ExModule) => m
+ }
+ }
+ }
+ Circuit(c.info,modulesx,c.main)
+ }
+}
+
+object ExpandConnects extends Pass {
+ private var mname = ""
+ def name = "Expand Connects"
+ def run (c:Circuit): Circuit = {
+ def expand_connects (m:InModule) : InModule = {
+ mname = m.name
+ val genders = LinkedHashMap[String,Gender]()
+ def expand_s (s:Stmt) : Stmt = {
+ def set_gender (e:Expression) : Expression = {
+ eMap(set_gender _,e) match {
+ case (e:WRef) => WRef(e.name,e.tpe,e.kind,genders(e.name))
+ case (e:WSubField) => {
+ val f = get_field(tpe(e.exp),e.name)
+ val genderx = times(gender(e.exp),f.flip)
+ WSubField(e.exp,e.name,e.tpe,genderx)
+ }
+ case (e:WSubIndex) => WSubIndex(e.exp,e.value,e.tpe,gender(e.exp))
+ case (e:WSubAccess) => WSubAccess(e.exp,e.index,e.tpe,gender(e.exp))
+ case (e) => e
+ }
+ }
+ s match {
+ case (s:DefWire) => { genders(s.name) = BIGENDER; s }
+ case (s:DefRegister) => { genders(s.name) = BIGENDER; s }
+ case (s:WDefInstance) => { genders(s.name) = MALE; s }
+ case (s:DefMemory) => { genders(s.name) = MALE; s }
+ case (s:DefPoison) => { genders(s.name) = MALE; s }
+ case (s:DefNode) => { genders(s.name) = MALE; s }
+ case (s:IsInvalid) => {
+ val n = get_size(tpe(s.exp))
+ val invalids = ArrayBuffer[Stmt]()
+ val exps = create_exps(s.exp)
+ for (i <- 0 until n) {
+ val expx = exps(i)
+ val gexpx = set_gender(expx)
+ gender(gexpx) match {
+ case BIGENDER => invalids += IsInvalid(s.info,expx)
+ case FEMALE => invalids += IsInvalid(s.info,expx)
+ case _ => {}
+ }
+ }
+ if (invalids.length == 0) {
+ Empty()
+ } else if (invalids.length == 1) {
+ invalids(0)
+ } else Begin(invalids)
+ }
+ case (s:Connect) => {
+ val n = get_size(tpe(s.loc))
+ val connects = ArrayBuffer[Stmt]()
+ val locs = create_exps(s.loc)
+ val exps = create_exps(s.exp)
+ for (i <- 0 until n) {
+ val locx = locs(i)
+ val expx = exps(i)
+ val sx = get_flip(tpe(s.loc),i,DEFAULT) match {
+ case DEFAULT => Connect(s.info,locx,expx)
+ case REVERSE => Connect(s.info,expx,locx)
+ }
+ connects += sx
+ }
+ Begin(connects)
+ }
+ case (s:BulkConnect) => {
+ val ls = get_valid_points(tpe(s.loc),tpe(s.exp),DEFAULT,DEFAULT)
+ val connects = ArrayBuffer[Stmt]()
+ val locs = create_exps(s.loc)
+ val exps = create_exps(s.exp)
+ ls.foreach { x => {
+ val locx = locs(x._1)
+ val expx = exps(x._2)
+ val sx = get_flip(tpe(s.loc),x._1,DEFAULT) match {
+ case DEFAULT => Connect(s.info,locx,expx)
+ case REVERSE => Connect(s.info,expx,locx)
+ }
+ connects += sx
+ }}
+ Begin(connects)
+ }
+ case (s) => sMap(expand_s _,s)
+ }
+ }
+
+ m.ports.foreach { p => genders(p.name) = to_gender(p.direction) }
+ InModule(m.info,m.name,m.ports,expand_s(m.body))
+ }
+
+ val modulesx = c.modules.map {
+ m => {
+ m match {
+ case (m:ExModule) => m
+ case (m:InModule) => expand_connects(m)
+ }
+ }
+ }
+ Circuit(c.info,modulesx,c.main)
+ }
+}
+
+case class Location(base:Expression,guard:Expression)
+object RemoveAccesses extends Pass {
+ private var mname = ""
+ def name = "Remove Accesses"
+ def get_locations (e:Expression) : Seq[Location] = {
+ e match {
+ case (e:WRef) => create_exps(e).map(Location(_,one))
+ case (e:WSubIndex) => {
+ val ls = get_locations(e.exp)
+ val start = get_point(e)
+ val end = start + get_size(tpe(e))
+ val stride = get_size(tpe(e.exp))
+ val lsx = ArrayBuffer[Location]()
+ var c = 0
+ for (i <- 0 until ls.size) {
+ if (((i % stride) >= start) & ((i % stride) < end)) {
+ lsx += ls(i)
+ }
+ }
+ lsx
+ }
+ case (e:WSubField) => {
+ val ls = get_locations(e.exp)
+ val start = get_point(e)
+ val end = start + get_size(tpe(e))
+ val stride = get_size(tpe(e.exp))
+ val lsx = ArrayBuffer[Location]()
+ var c = 0
+ for (i <- 0 until ls.size) {
+ if (((i % stride) >= start) & ((i % stride) < end)) { lsx += ls(i) }
+ }
+ lsx
+ }
+ case (e:WSubAccess) => {
+ val ls = get_locations(e.exp)
+ val stride = get_size(tpe(e))
+ val wrap = tpe(e.exp).asInstanceOf[VectorType].size
+ val lsx = ArrayBuffer[Location]()
+ var c = 0
+ for (i <- 0 until ls.size) {
+ if ((c % wrap) == 0) { c = 0 }
+ val basex = ls(i).base
+ val guardx = AND(ls(i).guard,EQV(uint(c),e.index))
+ lsx += Location(basex,guardx)
+ if ((i + 1) % stride == 0) {
+ c = c + 1
+ }
+ }
+ lsx
+ }
+ }
+ }
+ def has_access (e:Expression) : Boolean = {
+ var ret:Boolean = false
+ def rec_has_access (e:Expression) : Expression = {
+ e match {
+ case (e:WSubAccess) => { ret = true; e }
+ case (e) => eMap(rec_has_access _,e)
+ }
+ }
+ rec_has_access(e)
+ ret
+ }
+ def run (c:Circuit): Circuit = {
+ def remove_m (m:InModule) : InModule = {
+ val sh = sym_hash
+ mname = m.name
+ def remove_s (s:Stmt) : Stmt = {
+ val stmts = ArrayBuffer[Stmt]()
+ def create_temp (e:Expression) : Expression = {
+ val n = firrtl_gensym_module(mname)
+ stmts += DefWire(info(s),n,tpe(e))
+ WRef(n,tpe(e),kind(e),gender(e))
+ }
+ def remove_e (e:Expression) : Expression = { //NOT RECURSIVE (except primops) INTENTIONALLY!
+ e match {
+ case (e:DoPrim) => eMap(remove_e,e)
+ case (e:Mux) => eMap(remove_e,e)
+ case (e:ValidIf) => eMap(remove_e,e)
+ case (e:SIntValue) => e
+ case (e:UIntValue) => e
+ case e => {
+ if (has_access(e)) {
+ val rs = get_locations(e)
+ val foo = rs.find(x => {x.guard != one})
+ foo match {
+ case None => error("Shouldn't be here")
+ case foo:Some[Location] => {
+ val temp = create_temp(e)
+ val temps = create_exps(temp)
+ def get_temp (i:Int) = temps(i % temps.size)
+ (rs,0 until rs.size).zipped.foreach {
+ (x,i) => {
+ if (i < temps.size) {
+ stmts += Connect(info(s),get_temp(i),x.base)
+ } else {
+ stmts += Conditionally(info(s),x.guard,Connect(info(s),get_temp(i),x.base),Empty())
+ }
+ }
+ }
+ temp
+ }
+ }
+ } else { e}
+ }
+ }
+ }
+
+ val sx = s match {
+ case (s:Connect) => {
+ if (has_access(s.loc)) {
+ val ls = get_locations(s.loc)
+ val locx =
+ if (ls.size == 1 & weq(ls(0).guard,one)) s.loc
+ else {
+ val temp = create_temp(s.loc)
+ for (x <- ls) { stmts += Conditionally(s.info,x.guard,Connect(s.info,x.base,temp),Empty()) }
+ temp
+ }
+ Connect(s.info,locx,remove_e(s.exp))
+ } else { Connect(s.info,s.loc,remove_e(s.exp)) }
+ }
+ case (s) => sMap(remove_s,eMap(remove_e,s))
+ }
+ stmts += sx
+ if (stmts.size != 1) Begin(stmts) else stmts(0)
+ }
+ InModule(m.info,m.name,m.ports,remove_s(m.body))
+ }
+
+ val modulesx = c.modules.map{
+ m => {
+ m match {
+ case (m:ExModule) => m
+ case (m:InModule) => remove_m(m)
+ }
+ }
+ }
+ Circuit(c.info,modulesx,c.main)
+ }
+}
+
+object ExpandWhens extends Pass {
+ def name = "Expand Whens"
+ var mname = ""
+// ; ========== Expand When Utilz ==========
+ def add (hash:LinkedHashMap[WrappedExpression,Expression],key:WrappedExpression,value:Expression) = {
+ hash += (key -> value)
+ }
+
+ def get_entries (hash:LinkedHashMap[WrappedExpression,Expression],exps:Seq[Expression]) : LinkedHashMap[WrappedExpression,Expression] = {
+ val hashx = LinkedHashMap[WrappedExpression,Expression]()
+ exps.foreach { e => {
+ val value = hash.get(e)
+ value match {
+ case (value:Some[Expression]) => add(hashx,e,value.get)
+ case (None) => {}
+ }
+ }}
+ hashx
+ }
+ def get_female_refs (n:String,t:Type,g:Gender) : Seq[Expression] = {
+ val exps = create_exps(WRef(n,t,ExpKind(),g))
+ val expsx = ArrayBuffer[Expression]()
+ def get_gender (t:Type, i:Int, g:Gender) : Gender = {
+ val f = get_flip(t,i,DEFAULT)
+ times(g, f)
+ }
+ for (i <- 0 until exps.size) {
+ get_gender(t,i,g) match {
+ case BIGENDER => expsx += exps(i)
+ case FEMALE => expsx += exps(i)
+ case _ => false
+ }
+ }
+ expsx
+ }
+
+ // ------------ Pass -------------------
+ def run (c:Circuit): Circuit = {
+ def void_all (m:InModule) : InModule = {
+ mname = m.name
+ def void_all_s (s:Stmt) : Stmt = {
+ (s) match {
+ case (_:DefWire|_:DefRegister|_:WDefInstance|_:DefMemory) => {
+ val voids = ArrayBuffer[Stmt]()
+ for (e <- get_female_refs(get_name(s),get_type(s),get_gender(s))) {
+ voids += Connect(get_info(s),e,WVoid())
+ }
+ Begin(Seq(s,Begin(voids)))
+ }
+ case (s) => sMap(void_all_s _,s)
+ }
+ }
+ val voids = ArrayBuffer[Stmt]()
+ for (p <- m.ports) {
+ for (e <- get_female_refs(p.name,p.tpe,get_gender(p))) {
+ voids += Connect(p.info,e,WVoid())
+ }
+ }
+ val bodyx = void_all_s(m.body)
+ InModule(m.info,m.name,m.ports,Begin(Seq(Begin(voids),bodyx)))
+ }
+ def expand_whens (m:InModule) : Tuple2[LinkedHashMap[WrappedExpression,Expression],ArrayBuffer[Stmt]] = {
+ val simlist = ArrayBuffer[Stmt]()
+ mname = m.name
+ def expand_whens (netlist:LinkedHashMap[WrappedExpression,Expression],p:Expression)(s:Stmt) : Stmt = {
+ (s) match {
+ case (s:Connect) => netlist(s.loc) = s.exp
+ case (s:IsInvalid) => netlist(s.exp) = WInvalid()
+ case (s:Conditionally) => {
+ val exps = ArrayBuffer[Expression]()
+ def prefetch (s:Stmt) : Stmt = {
+ (s) match {
+ case (s:Connect) => exps += s.loc; s
+ case (s) => sMap(prefetch _,s)
+ }
+ }
+ prefetch(s.conseq)
+ val c_netlist = get_entries(netlist,exps)
+ expand_whens(c_netlist,AND(p,s.pred))(s.conseq)
+ expand_whens(netlist,AND(p,NOT(s.pred)))(s.alt)
+ for (lvalue <- c_netlist.keys) {
+ val value = netlist.get(lvalue)
+ (value) match {
+ case (value:Some[Expression]) => {
+ val tv = c_netlist(lvalue)
+ val fv = value.get
+ val res = (tv,fv) match {
+ case (tv:WInvalid,fv:WInvalid) => WInvalid()
+ case (tv:WInvalid,fv) => ValidIf(NOT(s.pred),fv,tpe(fv))
+ case (tv,fv:WInvalid) => ValidIf(s.pred,tv,tpe(tv))
+ case (tv,fv) => Mux(s.pred,tv,fv,mux_type_and_widths(tv,fv))
+ }
+ netlist(lvalue) = res
+ }
+ case (None) => add(netlist,lvalue,c_netlist(lvalue))
+ }
+ }
+ }
+ case (s:Print) => {
+ if (weq(p,one)) {
+ simlist += s
+ } else {
+ simlist += Print(s.info,s.string,s.args,s.clk,AND(p,s.en))
+ }
+ }
+ case (s:Stop) => {
+ if (weq(p,one)) {
+ simlist += s
+ } else {
+ simlist += Stop(s.info,s.ret,s.clk,AND(p,s.en))
+ }
+ }
+ case (s) => sMap(expand_whens(netlist,p) _, s)
+ }
+ s
+ }
+ val netlist = LinkedHashMap[WrappedExpression,Expression]()
+ expand_whens(netlist,one)(m.body)
+
+ //println("Netlist:")
+ //println(netlist)
+ //println("Simlist:")
+ //println(simlist)
+ ( netlist, simlist )
+ }
+
+ def create_module (netlist:LinkedHashMap[WrappedExpression,Expression],simlist:ArrayBuffer[Stmt],m:InModule) : InModule = {
+ mname = m.name
+ val stmts = ArrayBuffer[Stmt]()
+ val connections = ArrayBuffer[Stmt]()
+ def replace_void (e:Expression)(rvalue:Expression) : Expression = {
+ (rvalue) match {
+ case (rv:WVoid) => e
+ case (rv) => eMap(replace_void(e) _,rv)
+ }
+ }
+ def create (s:Stmt) : Stmt = {
+ (s) match {
+ case (_:DefWire|_:WDefInstance|_:DefMemory) => {
+ stmts += s
+ for (e <- get_female_refs(get_name(s),get_type(s),get_gender(s))) {
+ val rvalue = netlist(e)
+ val con = (rvalue) match {
+ case (rvalue:WInvalid) => IsInvalid(get_info(s),e)
+ case (rvalue) => Connect(get_info(s),e,rvalue)
+ }
+ connections += con
+ }
+ }
+ case (s:DefRegister) => {
+ stmts += s
+ for (e <- get_female_refs(get_name(s),get_type(s),get_gender(s))) {
+ val rvalue = replace_void(e)(netlist(e))
+ val con = (rvalue) match {
+ case (rvalue:WInvalid) => IsInvalid(get_info(s),e)
+ case (rvalue) => Connect(get_info(s),e,rvalue)
+ }
+ connections += con
+ }
+ }
+ case (_:DefPoison|_:DefNode) => stmts += s
+ case (s) => sMap(create _,s)
+ }
+ s
+ }
+ create(m.body)
+ for (p <- m.ports) {
+ for (e <- get_female_refs(p.name,p.tpe,get_gender(p))) {
+ val rvalue = netlist(e)
+ val con = (rvalue) match {
+ case (rvalue:WInvalid) => IsInvalid(p.info,e)
+ case (rvalue) => Connect(p.info,e,rvalue)
+ }
+ connections += con
+ }
+ }
+ for (x <- simlist) { stmts += x }
+ InModule(m.info,m.name,m.ports,Begin(Seq(Begin(stmts),Begin(connections))))
+ }
+
+ val voided_modules = c.modules.map{ m => {
+ (m) match {
+ case (m:ExModule) => m
+ case (m:InModule) => void_all(m)
+ } } }
+ val modulesx = voided_modules.map{ m => {
+ (m) match {
+ case (m:ExModule) => m
+ case (m:InModule) => {
+ val (netlist, simlist) = expand_whens(m)
+ create_module(netlist,simlist,m)
+ }
+ }}}
+ Circuit(c.info,modulesx,c.main)
+ }
+}
+
+object ConstProp extends Pass {
+ def name = "Constant Propogation"
+ var mname = ""
+ def const_prop_e (e:Expression) : Expression = {
+ eMap(const_prop_e _,e) match {
+ case (e:DoPrim) => {
+ e.op match {
+ case SHIFT_RIGHT_OP => {
+ (e.args(0)) match {
+ case (x:UIntValue) => {
+ val b = x.value >> e.consts(0).toInt
+ UIntValue(b,tpe(e).as[UIntType].get.width)
+ }
+ case (x:SIntValue) => {
+ val b = x.value >> e.consts(0).toInt
+ SIntValue(b,tpe(e).as[SIntType].get.width)
+ }
+ case (x) => e
+ }
+ }
+ case BITS_SELECT_OP => {
+ e.args(0) match {
+ case (x:UIntValue) => {
+ val hi = e.consts(0).toInt
+ val lo = e.consts(1).toInt
+ require(hi >= lo)
+ val b = (x.value >> lo) & ((BigInt(1) << (hi - lo + 1)) - 1)
+ UIntValue(b,tpe(e).as[UIntType].get.width)
+ }
+ case (x) => {
+ if (long_BANG(tpe(e)) == long_BANG(tpe(x))) {
+ tpe(x) match {
+ case (t:UIntType) => x
+ case _ => DoPrim(AS_UINT_OP,Seq(x),Seq(),tpe(e))
+ }
+ }
+ else e
+ }
+ }
+ }
+ case (_) => e
+ }
+ }
+ case (e) => e
+ }
+ }
+ def const_prop_s (s:Stmt) : Stmt = eMap(const_prop_e _, sMap(const_prop_s _,s))
+ def run (c:Circuit): Circuit = {
+ val modulesx = c.modules.map{ m => {
+ m match {
+ case (m:ExModule) => m
+ case (m:InModule) => {
+ mname = m.name
+ InModule(m.info,m.name,m.ports,const_prop_s(m.body))
+ }
+ }
+ }}
+ Circuit(c.info,modulesx,c.main)
+ }
+}
+
+object LoToVerilog extends Pass with StanzaPass {
+ def name = "Lo To Verilog"
+ def run (c:Circuit): Circuit = stanzaPass(c, "lo-to-verilog")
+}
+
+object FromCHIRRTL extends Pass with StanzaPass {
+ def name = "From CHIRRTL"
+ def run (c:Circuit): Circuit = stanzaPass(c, "from-chirrtl")
+}
+
+object VerilogWrap extends Pass {
+ def name = "Verilog Wrap"
+ var mname = ""
+ def v_wrap_e (e:Expression) : Expression = {
+ eMap(v_wrap_e _,e) match {
+ case (e:DoPrim) => {
+ def a0 () = e.args(0)
+ if (e.op == TAIL_OP) {
+ (a0()) match {
+ case (e0:DoPrim) => {
+ if (e0.op == ADD_OP) DoPrim(ADDW_OP,e0.args,Seq(),tpe(e))
+ else if (e0.op == SUB_OP) DoPrim(SUBW_OP,e0.args,Seq(),tpe(e))
+ else e
+ }
+ case (e0) => e
+ }
+ }
+ else e
+ }
+ case (e) => e
+ }
+ }
+ def v_wrap_s (s:Stmt) : Stmt = eMap(v_wrap_e _,sMap(v_wrap_s _,s))
+ def run (c:Circuit): Circuit = {
+ val modulesx = c.modules.map{ m => {
+ (m) match {
+ case (m:InModule) => {
+ mname = m.name
+ InModule(m.info,m.name,m.ports,v_wrap_s(m.body))
+ }
+ case (m:ExModule) => m
+ }
+ }}
+ Circuit(c.info,modulesx,c.main)
+ }
+}
+
+object SplitExp extends Pass {
+ def name = "Split Expressions"
+ var mname = ""
+ def split_exp (m:InModule) : InModule = {
+ mname = m.name
+ val v = ArrayBuffer[Stmt]()
+ def split_exp_s (s:Stmt) : Stmt = {
+ def split (e:Expression) : Expression = {
+ val n = firrtl_gensym_module(mname)
+ v += DefNode(info(s),n,e)
+ WRef(n,tpe(e),kind(e),gender(e))
+ }
+ def split_exp_e (i:Int)(e:Expression) : Expression = {
+ eMap(split_exp_e(i + 1) _,e) match {
+ case (e:DoPrim) => if (i > 0) split(e) else e
+ case (e) => e
+ }
+ }
+ eMap(split_exp_e(0) _,s) match {
+ case (s:Begin) => sMap(split_exp_s _,s)
+ case (s) => v += s; s
+ }
+ }
+ split_exp_s(m.body)
+ InModule(m.info,m.name,m.ports,Begin(v))
+ }
+
+ def run (c:Circuit): Circuit = {
+ val modulesx = c.modules.map{ m => {
+ (m) match {
+ case (m:InModule) => split_exp(m)
+ case (m:ExModule) => m
+ }
+ }}
+ Circuit(c.info,modulesx,c.main)
+ }
+}
+
+object VerilogRename extends Pass {
+ def name = "Verilog Rename"
+ def run (c:Circuit): Circuit = {
+ def verilog_rename_n (n:String) : String = {
+ if (v_keywords.contains(n)) (n + "$") else n
+ }
+ def verilog_rename_e (e:Expression) : Expression = {
+ (e) match {
+ case (e:WRef) => WRef(verilog_rename_n(e.name),e.tpe,kind(e),gender(e))
+ case (e) => eMap(verilog_rename_e,e)
+ }
+ }
+ def verilog_rename_s (s:Stmt) : Stmt = {
+ stMap(verilog_rename_n _,eMap(verilog_rename_e _,sMap(verilog_rename_s _,s)))
+ }
+ val modulesx = c.modules.map{ m => {
+ val portsx = m.ports.map{ p => {
+ Port(p.info,verilog_rename_n(p.name),p.direction,p.tpe)
+ }}
+ m match {
+ case (m:InModule) => InModule(m.info,m.name,portsx,verilog_rename_s(m.body))
+ case (m:ExModule) => m
+ }
+ }}
+ Circuit(c.info,modulesx,c.main)
+ }
+}
+
+object LowerTypes extends Pass {
+ def name = "Lower Types"
+ var mname = ""
+ def is_ground (t:Type) : Boolean = {
+ (t) match {
+ case (_:UIntType|_:SIntType) => true
+ case (t) => false
+ }
+ }
+ def data (ex:Expression) : Boolean = {
+ (kind(ex)) match {
+ case (k:MemKind) => (ex) match {
+ case (_:WRef|_:WSubIndex) => false
+ case (ex:WSubField) => {
+ var yes = ex.name match {
+ case "rdata" => true
+ case "data" => true
+ case "mask" => true
+ case _ => false
+ }
+ yes && ((ex.exp) match {
+ case (e:WSubField) => kind(e).as[MemKind].get.ports.contains(e.name) && (e.exp.typeof[WRef])
+ case (e) => false
+ })
+ }
+ case (ex) => false
+ }
+ case (k) => false
+ }
+ }
+ def expand_name (e:Expression) : Seq[String] = {
+ val names = ArrayBuffer[String]()
+ def expand_name_e (e:Expression) : Expression = {
+ (eMap(expand_name_e _,e)) match {
+ case (e:WRef) => names += e.name
+ case (e:WSubField) => names += e.name
+ case (e:WSubIndex) => names += e.value.toString
+ }
+ e
+ }
+ expand_name_e(e)
+ names
+ }
+ def lower_other_mem (e:Expression, dt:Type) : Seq[Expression] = {
+ val names = expand_name(e)
+ if (names.size < 3) error("Shouldn't be here")
+ create_exps(names(0),dt).map{ x => {
+ var base = lowered_name(x)
+ for (i <- 0 until names.size) {
+ if (i >= 3) base = base + "_" + names(i)
+ }
+ val m = WRef(base, UnknownType(), kind(e), UNKNOWNGENDER)
+ val p = WSubField(m,names(1),UnknownType(),UNKNOWNGENDER)
+ WSubField(p,names(2),UnknownType(),UNKNOWNGENDER)
+ }}
+ }
+ def lower_data_mem (e:Expression) : Expression = {
+ val names = expand_name(e)
+ if (names.size < 3) error("Shouldn't be here")
+ else {
+ var base = names(0)
+ for (i <- 0 until names.size) {
+ if (i >= 3) base = base + "_" + names(i)
+ }
+ val m = WRef(base, UnknownType(), kind(e), UNKNOWNGENDER)
+ val p = WSubField(m,names(1),UnknownType(),UNKNOWNGENDER)
+ WSubField(p,names(2),UnknownType(),UNKNOWNGENDER)
+ }
+ }
+ def merge (a:String,b:String,x:String) : String = a + x + b
+ def root_ref (e:Expression) : WRef = {
+ (e) match {
+ case (e:WRef) => e
+ case (e:WSubField) => root_ref(e.exp)
+ case (e:WSubIndex) => root_ref(e.exp)
+ case (e:WSubAccess) => root_ref(e.exp)
+ }
+ }
+
+ //;------------- Pass ------------------
+
+ def lower_types (m:Module) : Module = {
+ val mdt = LinkedHashMap[String,Type]()
+ mname = m.name
+ def lower_types (s:Stmt) : Stmt = {
+ def lower_mem (e:Expression) : Seq[Expression] = {
+ val names = expand_name(e)
+ if (Seq("data","mask","rdata").contains(names(2))) Seq(lower_data_mem(e))
+ else lower_other_mem(e,mdt(root_ref(e).name))
+ }
+ def lower_types_e (e:Expression) : Expression = {
+ e match {
+ case (_:WRef|_:UIntValue|_:SIntValue) => e
+ case (_:WSubField|_:WSubIndex) => {
+ (kind(e)) match {
+ case (k:InstanceKind) => {
+ val names = expand_name(e)
+ var n = names(1)
+ for (i <- 0 until names.size) {
+ if (i > 1) n = n + "_" + names(i)
+ }
+ WSubField(root_ref(e),n,tpe(e),gender(e))
+ }
+ case (k:MemKind) => {
+ if (gender(e) != FEMALE) lower_mem(e)(0)
+ else e
+ }
+ case (k) => WRef(lowered_name(e),tpe(e),kind(e),gender(e))
+ }
+ }
+ case (e:DoPrim) => eMap(lower_types_e _,e)
+ case (e:Mux) => eMap(lower_types_e _,e)
+ case (e:ValidIf) => eMap(lower_types_e _,e)
+ }
+ }
+ (s) match {
+ case (s:DefWire) => {
+ if (is_ground(s.tpe)) s else {
+ val es = create_exps(s.name,s.tpe)
+ val stmts = (es, 0 until es.size).zipped.map{ (e,i) => {
+ DefWire(s.info,lowered_name(e),tpe(e))
+ }}
+ Begin(stmts)
+ }
+ }
+ case (s:DefPoison) => {
+ if (is_ground(s.tpe)) s else {
+ val es = create_exps(s.name,s.tpe)
+ val stmts = (es, 0 until es.size).zipped.map{ (e,i) => {
+ DefPoison(s.info,lowered_name(e),tpe(e))
+ }}
+ Begin(stmts)
+ }
+ }
+ case (s:DefRegister) => {
+ if (is_ground(s.tpe)) s else {
+ val es = create_exps(s.name,s.tpe)
+ val inits = create_exps(s.init)
+ val stmts = (es, 0 until es.size).zipped.map{ (e,i) => {
+ val init = lower_types_e(inits(i))
+ DefRegister(s.info,lowered_name(e),tpe(e),s.clock,s.reset,init)
+ }}
+ Begin(stmts)
+ }
+ }
+ case (s:WDefInstance) => {
+ val fieldsx = s.tpe.as[BundleType].get.fields.flatMap{ f => {
+ val es = create_exps(WRef(f.name,f.tpe,ExpKind(),times(f.flip,MALE)))
+ es.map{ e => {
+ gender(e) match {
+ case MALE => Field(lowered_name(e),DEFAULT,f.tpe)
+ case FEMALE => Field(lowered_name(e),REVERSE,f.tpe)
+ }
+ }}
+ }}
+ WDefInstance(s.info,s.name,s.module,BundleType(fieldsx))
+ }
+ case (s:DefMemory) => {
+ mdt(s.name) = s.data_type
+ if (is_ground(s.data_type)) s else {
+ val es = create_exps(s.name,s.data_type)
+ val stmts = es.map{ e => {
+ DefMemory(s.info,lowered_name(e),tpe(e),s.depth,s.write_latency,s.read_latency,s.readers,s.writers,s.readwriters)
+ }}
+ Begin(stmts)
+ }
+ }
+ case (s:IsInvalid) => {
+ val sx = eMap(lower_types_e _,s).as[IsInvalid].get
+ kind(sx.exp) match {
+ case (k:MemKind) => {
+ val es = lower_mem(sx.exp)
+ Begin(es.map(e => {IsInvalid(sx.info,e)}))
+ }
+ case (_) => sx
+ }
+ }
+ case (s:Connect) => {
+ val sx = eMap(lower_types_e _,s).as[Connect].get
+ kind(sx.loc) match {
+ case (k:MemKind) => {
+ val es = lower_mem(sx.loc)
+ Begin(es.map(e => {Connect(sx.info,e,sx.exp)}))
+ }
+ case (_) => sx
+ }
+ }
+ case (s:DefNode) => {
+ val locs = create_exps(s.name,tpe(s.value))
+ val n = locs.size
+ val nodes = ArrayBuffer[Stmt]()
+ val exps = create_exps(s.value)
+ for (i <- 0 until n) {
+ val locx = locs(i)
+ val expx = exps(i)
+ nodes += DefNode(s.info,lowered_name(locx),lower_types_e(expx))
+ }
+ if (n == 1) nodes(0) else Begin(nodes)
+ }
+ case (s) => eMap(lower_types_e _,sMap(lower_types _,s))
+ }
+ }
+
+ val portsx = m.ports.flatMap{ p => {
+ val es = create_exps(WRef(p.name,p.tpe,PortKind(),to_gender(p.direction)))
+ es.map(e => { Port(p.info,lowered_name(e),to_dir(gender(e)),tpe(e)) })
+ }}
+ (m) match {
+ case (m:ExModule) => ExModule(m.info,m.name,portsx)
+ case (m:InModule) => InModule(m.info,m.name,portsx,lower_types(m.body))
+ }
+ }
+
+ def run (c:Circuit) : Circuit = {
+ val modulesx = c.modules.map(m => lower_types(m))
+ Circuit(c.info,modulesx,c.main)
+ }
+}
+
+object CInferTypes extends Pass {
+ def name = "CInfer Types"
+ var mname = ""
+ def set_type (s:Stmt,t:Type) : Stmt = {
+ (s) match {
+ case (s:DefWire) => DefWire(s.info,s.name,t)
+ case (s:DefRegister) => DefRegister(s.info,s.name,t,s.clock,s.reset,s.init)
+ case (s:CDefMemory) => CDefMemory(s.info,s.name,t,s.size,s.seq)
+ case (s:CDefMPort) => CDefMPort(s.info,s.name,t,s.mem,s.exps,s.direction)
+ case (s:DefNode) => s
+ case (s:DefPoison) => DefPoison(s.info,s.name,t)
+ }
+ }
+
+ def to_field (p:Port) : Field = {
+ if (p.direction == OUTPUT) Field(p.name,DEFAULT,p.tpe)
+ else if (p.direction == INPUT) Field(p.name,REVERSE,p.tpe)
+ else error("Shouldn't be here"); Field(p.name,REVERSE,p.tpe)
+ }
+ def module_type (m:Module) : Type = BundleType(m.ports.map(p => to_field(p)))
+ def field_type (v:Type,s:String) : Type = {
+ (v) match {
+ case (v:BundleType) => {
+ val ft = v.fields.find(p => p.name == s)
+ if (ft != None) ft.get.tpe
+ else UnknownType()
+ }
+ case (v) => UnknownType()
+ }
+ }
+ def sub_type (v:Type) : Type =
+ (v) match {
+ case (v:VectorType) => v.tpe
+ case (v) => UnknownType()
+ }
+ def run (c:Circuit) : Circuit = {
+ val module_types = LinkedHashMap[String,Type]()
+ def infer_types (m:Module) : Module = {
+ val types = LinkedHashMap[String,Type]()
+ def infer_types_e (e:Expression) : Expression = {
+ (eMap(infer_types_e _,e)) match {
+ case (e:Ref) => Ref(e.name, types.getOrElse(e.name,UnknownType()))
+ case (e:SubField) => SubField(e.exp,e.name,field_type(tpe(e.exp),e.name))
+ case (e:SubIndex) => SubIndex(e.exp,e.value,sub_type(tpe(e.exp)))
+ case (e:SubAccess) => SubAccess(e.exp,e.index,sub_type(tpe(e.exp)))
+ case (e:DoPrim) => set_primop_type(e)
+ case (e:Mux) => Mux(e.cond,e.tval,e.fval,mux_type(e.tval,e.tval))
+ case (e:ValidIf) => ValidIf(e.cond,e.value,tpe(e.value))
+ case (_:UIntValue|_:SIntValue) => e
+ }
+ }
+ def infer_types_s (s:Stmt) : Stmt = {
+ (s) match {
+ case (s:DefRegister) => {
+ types(s.name) = s.tpe
+ eMap(infer_types_e _,s)
+ s
+ }
+ case (s:DefWire) => {
+ types(s.name) = s.tpe
+ s
+ }
+ case (s:DefPoison) => {
+ types(s.name) = s.tpe
+ s
+ }
+ case (s:DefNode) => {
+ val sx = eMap(infer_types_e _,s)
+ val t = get_type(sx)
+ types(s.name) = t
+ sx
+ }
+ case (s:DefMemory) => {
+ types(s.name) = get_type(s)
+ s
+ }
+ case (s:CDefMPort) => {
+ val t = types.getOrElse(s.mem,UnknownType())
+ types(s.name) = t
+ CDefMPort(s.info,s.name,t,s.mem,s.exps,s.direction)
+ }
+ case (s:CDefMemory) => {
+ types(s.name) = s.tpe
+ s
+ }
+ case (s:DefInstance) => {
+ types(s.name) = module_types.getOrElse(s.module,UnknownType())
+ s
+ }
+ case (s) => eMap(infer_types_e _,sMap(infer_types_s _,s))
+ }
+ }
+ for (p <- m.ports) {
+ types(p.name) = p.tpe
+ }
+ (m) match {
+ case (m:InModule) => InModule(m.info,m.name,m.ports,infer_types_s(m.body))
+ case (m:ExModule) => m
+ }
+ }
+
+ //; MAIN
+ for (m <- c.modules) {
+ module_types(m.name) = module_type(m)
+ }
+ val modulesx = c.modules.map(m => infer_types(m))
+ Circuit(c.info, modulesx, c.main)
+ }
+}
+
+object CInferMDir extends Pass {
+ def name = "CInfer MDir"
+ var mname = ""
+ def run (c:Circuit) : Circuit = {
+ def infer_mdir (m:Module) : Module = {
+ val mports = LinkedHashMap[String,MPortDir]()
+ def infer_mdir_e (dir:MPortDir)(e:Expression) : Expression = {
+ (eMap(infer_mdir_e(dir) _,e)) match {
+ case (e:Ref) => {
+ if (mports.contains(e.name)) {
+ val new_mport_dir = {
+ (mports(e.name),dir) match {
+ case (MInfer,MInfer) => error("Shouldn't be here")
+ case (MInfer,MWrite) => MWrite
+ case (MInfer,MRead) => MRead
+ case (MInfer,MReadWrite) => MReadWrite
+ case (MWrite,MInfer) => error("Shouldn't be here")
+ case (MWrite,MWrite) => MWrite
+ case (MWrite,MRead) => MReadWrite
+ case (MWrite,MReadWrite) => MReadWrite
+ case (MRead,MInfer) => error("Shouldn't be here")
+ case (MRead,MWrite) => MReadWrite
+ case (MRead,MRead) => MRead
+ case (MRead,MReadWrite) => MReadWrite
+ case (MReadWrite,MInfer) => error("Shouldn't be here")
+ case (MReadWrite,MWrite) => MReadWrite
+ case (MReadWrite,MRead) => MReadWrite
+ case (MReadWrite,MReadWrite) => MReadWrite
+ }
+ }
+ mports(e.name) = new_mport_dir
+ }
+ e
+ }
+ case (e) => e
+ }
+ }
+ def infer_mdir_s (s:Stmt) : Stmt = {
+ (s) match {
+ case (s:CDefMPort) => {
+ mports(s.name) = s.direction
+ eMap(infer_mdir_e(MRead) _,s)
+ }
+ case (s:Connect) => {
+ infer_mdir_e(MRead)(s.exp)
+ infer_mdir_e(MWrite)(s.loc)
+ s
+ }
+ case (s:BulkConnect) => {
+ infer_mdir_e(MRead)(s.exp)
+ infer_mdir_e(MWrite)(s.loc)
+ s
+ }
+ case (s) => eMap(infer_mdir_e(MRead) _, sMap(infer_mdir_s,s))
+ }
+ }
+ def set_mdir_s (s:Stmt) : Stmt = {
+ (s) match {
+ case (s:CDefMPort) =>
+ CDefMPort(s.info,s.name,s.tpe,s.mem,s.exps,mports(s.name))
+ case (s) => sMap(set_mdir_s _,s)
+ }
+ }
+ (m) match {
+ case (m:InModule) => {
+ infer_mdir_s(m.body)
+ InModule(m.info,m.name,m.ports,set_mdir_s(m.body))
+ }
+ case (m:ExModule) => m
+ }
+ }
+
+ //; MAIN
+ Circuit(c.info, c.modules.map(m => infer_mdir(m)), c.main)
+ }
+}
+
+case class MPort( val name : String, val clk : Expression)
+case class MPorts( val readers : ArrayBuffer[MPort], val writers : ArrayBuffer[MPort], val readwriters : ArrayBuffer[MPort])
+case class DataRef( val exp : Expression, val male : String, val female : String, val mask : String, val rdwrite : Boolean)
+
+object RemoveCHIRRTL extends Pass {
+ def name = "Remove CHIRRTL"
+ var mname = ""
+ def create_exps (e:Expression) : Seq[Expression] = {
+ (e) match {
+ case (e:Mux)=>
+ (create_exps(e.tval),create_exps(e.fval)).zipped.map((e1,e2) => {
+ Mux(e.cond,e1,e2,mux_type(e1,e2))
+ })
+ case (e:ValidIf) =>
+ create_exps(e.value).map(e1 => {
+ ValidIf(e.cond,e1,tpe(e1))
+ })
+ case (e) => (tpe(e)) match {
+ case (_:UIntType|_:SIntType|_:ClockType) => Seq(e)
+ case (t:BundleType) =>
+ t.fields.flatMap(f => create_exps(SubField(e,f.name,f.tpe)))
+ case (t:VectorType)=>
+ (0 until t.size).flatMap(i => create_exps(SubIndex(e,i,t.tpe)))
+ case (t:UnknownType) => Seq(e)
+ }
+ }
+ }
+ def run (c:Circuit) : Circuit = {
+ def remove_chirrtl_m (m:InModule) : InModule = {
+ val hash = LinkedHashMap[String,MPorts]()
+ val repl = LinkedHashMap[String,DataRef]()
+ val ut = UnknownType()
+ val mport_types = LinkedHashMap[String,Type]()
+ def EMPs () : MPorts = MPorts(ArrayBuffer[MPort](),ArrayBuffer[MPort](),ArrayBuffer[MPort]())
+ def collect_mports (s:Stmt) : Stmt = {
+ (s) match {
+ case (s:CDefMPort) => {
+ val mports = hash.getOrElse(s.mem,EMPs())
+ s.direction match {
+ case MRead => mports.readers += MPort(s.name,s.exps(1))
+ case MWrite => mports.writers += MPort(s.name,s.exps(1))
+ case MReadWrite => mports.readwriters += MPort(s.name,s.exps(1))
+ }
+ hash(s.mem) = mports
+ s
+ }
+ case (s) => sMap(collect_mports _,s)
+ }
+ }
+ def collect_refs (s:Stmt) : Stmt = {
+ (s) match {
+ case (s:CDefMemory) => {
+ mport_types(s.name) = s.tpe
+ val stmts = ArrayBuffer[Stmt]()
+ val taddr = UIntType(IntWidth(scala.math.max(1,ceil_log2(s.size))))
+ val tdata = s.tpe
+ def set_poison (vec:Seq[MPort],addr:String) : Unit = {
+ for (r <- vec ) {
+ stmts += IsInvalid(s.info,SubField(SubField(Ref(s.name,ut),r.name,ut),addr,taddr))
+ stmts += Connect(s.info,SubField(SubField(Ref(s.name,ut),r.name,ut),"clk",taddr),r.clk)
+ }
+ }
+ def set_enable (vec:Seq[MPort],en:String) : Unit = {
+ for (r <- vec ) {
+ stmts += Connect(s.info,SubField(SubField(Ref(s.name,ut),r.name,ut),en,taddr),zero)
+ }}
+ def set_wmode (vec:Seq[MPort],wmode:String) : Unit = {
+ for (r <- vec) {
+ stmts += Connect(s.info,SubField(SubField(Ref(s.name,ut),r.name,ut),wmode,taddr),zero)
+ }}
+ def set_write (vec:Seq[MPort],data:String,mask:String) : Unit = {
+ val tmask = create_mask(s.tpe)
+ for (r <- vec ) {
+ stmts += IsInvalid(s.info,SubField(SubField(Ref(s.name,ut),r.name,ut),data,tdata))
+ for (x <- create_exps(SubField(SubField(Ref(s.name,ut),r.name,ut),mask,tmask)) ) {
+ stmts += Connect(s.info,x,zero)
+ }}}
+ val rds = (hash.getOrElse(s.name,EMPs())).readers
+ set_poison(rds,"addr")
+ set_enable(rds,"en")
+ val wrs = (hash.getOrElse(s.name,EMPs())).writers
+ set_poison(wrs,"addr")
+ set_enable(wrs,"en")
+ set_write(wrs,"data","mask")
+ val rws = (hash.getOrElse(s.name,EMPs())).readwriters
+ set_poison(rws,"addr")
+ set_wmode(rws,"wmode")
+ set_enable(rws,"en")
+ set_write(rws,"data","mask")
+ val read_l = if (s.seq) 1 else 0
+ val mem = DefMemory(s.info,s.name,s.tpe,s.size,1,read_l,rds.map(_.name),wrs.map(_.name),rws.map(_.name))
+ Begin(Seq(mem,Begin(stmts)))
+ }
+ case (s:CDefMPort) => {
+ mport_types(s.name) = mport_types(s.mem)
+ val addrs = ArrayBuffer[String]()
+ val ens = ArrayBuffer[String]()
+ val masks = ArrayBuffer[String]()
+ s.direction match {
+ case MReadWrite => {
+ repl(s.name) = DataRef(SubField(Ref(s.mem,ut),s.name,ut),"rdata","data","mask",true)
+ addrs += "addr"
+ ens += "en"
+ masks += "mask"
+ }
+ case MWrite => {
+ repl(s.name) = DataRef(SubField(Ref(s.mem,ut),s.name,ut),"data","data","mask",false)
+ addrs += "addr"
+ ens += "en"
+ masks += "mask"
+ }
+ case _ => {
+ repl(s.name) = DataRef(SubField(Ref(s.mem,ut),s.name,ut),"data","data","blah",false)
+ addrs += "addr"
+ ens += "en"
+ }
+ }
+ val stmts = ArrayBuffer[Stmt]()
+ for (x <- addrs ) {
+ stmts += Connect(s.info,SubField(SubField(Ref(s.mem,ut),s.name,ut),x,ut),s.exps(0))
+ }
+ for (x <- ens ) {
+ stmts += Connect(s.info,SubField(SubField(Ref(s.mem,ut),s.name,ut),x,ut),one)
+ }
+ Begin(stmts)
+ }
+ case (s) => sMap(collect_refs _,s)
+ }
+ }
+ def remove_chirrtl_s (s:Stmt) : Stmt = {
+ var has_write_mport = false
+ var has_readwrite_mport:Option[Expression] = None
+ def remove_chirrtl_e (g:Gender)(e:Expression) : Expression = {
+ (e) match {
+ case (e:Ref) => {
+ if (repl.contains(e.name)) {
+ val vt = repl(e.name)
+ g match {
+ case MALE => SubField(vt.exp,vt.male,e.tpe)
+ case FEMALE => {
+ has_write_mport = true
+ if (vt.rdwrite == true)
+ has_readwrite_mport = Some(SubField(vt.exp,"wmode",UIntType(IntWidth(1))))
+ SubField(vt.exp,vt.female,e.tpe)
+ }
+ }
+ } else e
+ }
+ case (e:SubAccess) => SubAccess(remove_chirrtl_e(g)(e.exp),remove_chirrtl_e(MALE)(e.index),e.tpe)
+ case (e) => eMap(remove_chirrtl_e(g) _,e)
+ }
+ }
+ def get_mask (e:Expression) : Expression = {
+ (eMap(get_mask _,e)) match {
+ case (e:Ref) => {
+ if (repl.contains(e.name)) {
+ val vt = repl(e.name)
+ val t = create_mask(e.tpe)
+ SubField(vt.exp,vt.mask,t)
+ } else e
+ }
+ case (e) => e
+ }
+ }
+ (s) match {
+ case (s:Connect) => {
+ val stmts = ArrayBuffer[Stmt]()
+ val rocx = remove_chirrtl_e(MALE)(s.exp)
+ val locx = remove_chirrtl_e(FEMALE)(s.loc)
+ stmts += Connect(s.info,locx,rocx)
+ if (has_write_mport) {
+ val e = get_mask(s.loc)
+ for (x <- create_exps(e) ) {
+ stmts += Connect(s.info,x,one)
+ }
+ if (has_readwrite_mport != None) {
+ val wmode = has_readwrite_mport.get
+ stmts += Connect(s.info,wmode,one)
+ }
+ }
+ if (stmts.size > 1) Begin(stmts)
+ else stmts(0)
+ }
+ case (s:BulkConnect) => {
+ val stmts = ArrayBuffer[Stmt]()
+ val locx = remove_chirrtl_e(FEMALE)(s.loc)
+ val rocx = remove_chirrtl_e(MALE)(s.exp)
+ stmts += BulkConnect(s.info,locx,rocx)
+ if (has_write_mport != false) {
+ val ls = get_valid_points(tpe(s.loc),tpe(s.exp),DEFAULT,DEFAULT)
+ val locs = create_exps(get_mask(s.loc))
+ for (x <- ls ) {
+ val locx = locs(x._1)
+ stmts += Connect(s.info,locx,one)
+ }
+ if (has_readwrite_mport != None) {
+ val wmode = has_readwrite_mport.get
+ stmts += Connect(s.info,wmode,one)
+ }
+ }
+ if (stmts.size > 1) Begin(stmts)
+ else stmts(0)
+ }
+ case (s) => eMap(remove_chirrtl_e(MALE) _, sMap(remove_chirrtl_s,s))
+ }
+ }
+ collect_mports(m.body)
+ val sx = collect_refs(m.body)
+ InModule(m.info,m.name, m.ports, remove_chirrtl_s(sx))
+ }
+ val modulesx = c.modules.map{ m => {
+ (m) match {
+ case (m:InModule) => remove_chirrtl_m(m)
+ case (m:ExModule) => m
+ }}}
+ Circuit(c.info,modulesx, c.main)
+ }
+}
diff --git a/src/main/stanza/bigint.stanza b/src/main/stanza/bigint.stanza
deleted file mode 100644
index bc13bdbf..00000000
--- a/src/main/stanza/bigint.stanza
+++ /dev/null
@@ -1,402 +0,0 @@
-defpackage bigint :
- import core
- import verse
-
-val val-n-bytes = 4
-val val-n-bits = val-n-bytes * 8
-val val-all-ones = -1 ;; TODO
-val val-n-half-bits = 32 / 2
-defn val-n-words (nbits: Int) -> Int : 1 + (nbits - 1) / 32
-defn val-n-half-words (nbits: Int) -> Int : (1 + (nbits - 1)) / val-n-half-bits
-defn val-top-bit (v: Int) -> Int : v >> (32 - 1)
-defn val-n-full-words (nbits: Int) -> Int : nbits / 32
-defn val-n-word-bits (nbits: Int) -> Int : nbits % 32
-defn mask-val (n: Int) : -1 >> (32 - n)
-
-public defclass BigInt <: Gettable & Settable & Lengthable
-public defmulti to-bin (b: BigInt) -> String
-public defmulti to-hex (b: BigInt) -> String
-public defmulti num-words (b: BigInt) -> Int
-public defmulti dat (b: BigInt) -> Array<Int>
-public defn BigInt (len: Int) :
- val d = Array<Int>(val-n-words(len))
- new BigInt :
- defmethod get (this, i: Int) -> Int : d[i]
- defmethod set (this, i: Int, x: Int) : d[i] = x & -1
- defmethod dat (this) -> Array<Int> : d
- defmethod length (this) -> Int : len
- defmethod num-words (this) -> Int : length(d)
- defmethod to-hex (this) -> String :
- defn as-hex (i: Int) -> String :
- val str = "0123456789abcdef"
- substring(str,i,i + 1)
- var str = "h"
- ;println(to-bin(this))
- for i in 0 to len by 4 do :
- val pos = len - 4 - i
- ;println(pos)
- val digit = (d[pos / 32] >> (pos % 32)) & 15
- ;println(digit)
- val hex = as-hex(digit)
- ;println(hex)
- if str == "h" and hex == "0" and (i + 4 < len) : false
- else : str = string-join([str hex])
- string-join([ "\"" str "\""])
- defmethod to-bin (this) -> String :
- string-join $
- generate<Char> :
- defn* loop (pos:Int) :
- if (pos >= 0) :
- yield(if (d[pos / 32] >> (pos % 32))&1 == 1: '1' else: '0')
- loop(pos - 1)
- loop(len - 1)
- ;defmethod to-string (this) : string-join(["BigInt<" len ">(" to-bin(this) ")"])
- defmethod to-string (this) : to-hex(this)
-
-defmethod print (o:OutputStream, b:BigInt) :
- print(o, to-string(b))
-
-defn assert (cond:True|False, msg:String) : if not cond: error(msg)
-
-defn assert (cond:True|False) : assert(cond, "failure")
-
-;; loop macro with starting values
-
-;; defn map-range (s:Int, e:Int, f: (Int) -> False) :
-;; for i in s to e do : f(i)
-
-defn map! (f: (Int, Int) -> Int, d: BigInt, s0: BigInt, s1: BigInt) -> BigInt :
- ;; assert(length(d) == length(s0) and length(s0) == length(s1),
- ;; string-join(["LENS != " num-words(d) " " num-words(s0) " " num-words(s1)]))
- for i in 0 to num-words(d) do :
- d[i] = f(s0[i], s1[i])
- d
-
-defn mask! (d: BigInt) -> BigInt :
- val n-full-words = val-n-full-words(length(d))
- val n-word-bits = val-n-word-bits(length(d))
- for i in 0 to n-full-words do :
- d[i] = -1
- for i in n-full-words to num-words(d) do :
- d[i] = 0
- if n-word-bits > 0 :
- d[n-full-words] = mask-val(n-word-bits)
- d
-
-defn trim! (d:BigInt) -> BigInt :
- val n-full-words = val-n-full-words(length(d))
- val n-word-bits = val-n-word-bits(length(d))
- if n-word-bits > 0 :
- d[n-full-words] = d[n-full-words] & mask-val(n-word-bits)
- d
-
-defn extract! (d:BigInt, s0:BigInt, e:Int, s:Int) -> BigInt : trim!(rsh!(d, s0, s))
-
-public defn bits (s0:BigInt, e:Int, s:Int) -> BigInt : extract!(BigInt(e - s + 1), s0, e, s)
-
-public defn bit (s0:BigInt, s:Int) -> Int :
- val wi = s / 32
- val bi = s % 32
- s0[wi] >> bi
-
-defn inject! (d:BigInt, s0:BigInt, f:BigInt, start:Int) -> BigInt :
- val bw = length(f)
- val msk = mask!(BigInt(bw))
- val msk-lsh = msk << start
- val inv-msk-lsh = bit-invert!(msk-lsh, msk-lsh)
- val f-lsh = f << start
- (s0 & inv-msk-lsh) | f-lsh
-
-defn map! (f: (Int) -> Int, d: BigInt, s0: BigInt) -> BigInt :
- ;; assert(length(d) == length(s0), string-join(["LENS != " num-words(d) " " num-words(s0)]))
- for i in 0 to num-words(d) do :
- d[i] = f(s0[i])
- d
-
-defn fill! (f: (Int) -> Int, b: BigInt) :
- for i in 0 to num-words(b) do :
- b[i] = f(i)
- b
-
-public defmethod equal? (x:BigInt, y:BigInt) -> True|False :
- val tf =
- if num-words(x) != num-words(y) :
- false
- else :
- var eq? = true
- for i in 0 to num-words(x) do :
- val e = (x[i] == y[i])
- ;if not e : ;println-all(["NOT-EQUAL " x " AND " y " i=" i " X[i] " x[i] " Y[i] " y[i]])
- eq? = eq? and e
- eq?
- ;println-all(["EQUAL? " x " AND " y " " tf])
- tf
-
-public defn less?! (diff:BigInt, x:BigInt, y:BigInt) -> True|False :
- sub!(diff, x, y)
- val-top-bit(diff[num-words(diff) - 1]) == 1
-
-public defn less? (x:BigInt, y:BigInt) -> True|False : op(less?!, x, y)
-
-public defn less-eq?! (diff:BigInt, x:BigInt, y:BigInt) -> True|False :
- sub!(diff, y, x)
- val-top-bit(diff[num-words(diff) - 1]) == 0
-
-public defn less-eq? (x:BigInt, y:BigInt) -> True|False : op(less-eq?!, x, y)
-
-public defn greater?! (diff:BigInt, x:BigInt, y:BigInt) -> True|False : not less-eq?!(diff, x, y)
-
-public defn greater? (x:BigInt, y:BigInt) -> True|False : op(greater?!, x, y)
-
-public defn greater-eq?! (diff:BigInt, x:BigInt, y:BigInt) -> True|False : not less?!(diff, x, y)
-
-public defn greater-eq? (x:BigInt, y:BigInt) -> True|False : op(greater-eq?!, x, y)
-
-defn as-digit (c: Char) -> Int :
- index-of("0123456789abcdef", c) as Int
-
-public defn BigIntLit (f: (Int) -> Int, len: Int) :
- fill!(f, BigInt(len))
-
-public defn BigIntLit (x: Int, w: Int) :
- fill!({_ + x}, BigInt(w))
-
-public defn BigIntLit (x: Int) : BigIntLit(x, sizeof(x))
-
-public defn BigIntLit (s: String) : BigIntLit(s, -1)
-
-public defn BigIntLit (s: String, w:Int) :
- val base = s[0]
- val shamt = if base == 'b': 1 else if base == 'h': 4 else: 2
- val digits = substring(s, 1)
- val len = if w == -1: length(digits) * shamt else: w
- val lit = BigInt(len)
- ;; println-all(["BASE " base " SHAMT " shamt " DIGITS " digits])
- for i in 0 to num-words(lit) do :
- lit[i] = 0
- for i in 0 to length(digits) do :
- val off = (length(digits) - 1 - i) * shamt
- val wi = off / 32
- val bi = off % 32
- lit[wi] = lit[wi] | (as-digit(digits[i]) << bi)
- ;; println-all(["OFF " off " wi " wi " bi " bi " lit[wi] " lit[wi] " => " lit])
- ;; println-all(["RES = " lit])
- lit
-
-public defn sizeof (in: Int) -> Int :
- max(1, ceil-log2(in + 1))
-
-defn op (f:(BigInt, BigInt, BigInt) -> True|False, x:BigInt, y:BigInt) -> True|False :
- f(BigInt(max(length(x), length(y))), x, y)
-
-defn op (f:(BigInt, BigInt, BigInt) -> BigInt, x:BigInt, y:BigInt) -> BigInt :
- f(BigInt(max(length(x), length(y))), x, y)
-
-defn op (f:(BigInt, BigInt) -> BigInt, x:BigInt) -> BigInt :
- f(BigInt(length(x)), x)
-
-defn int (x: True|False) -> Int : if x : 1 else : 0
-
-public defn plus! (d: BigInt, s0: BigInt, s1: BigInt) -> BigInt :
- var carry = false
- for i in 0 to num-words(d) do :
- d[i] = s0[i] + s1[i] + int(carry)
- carry = ((s0[i] + s1[i]) < s0[i]) or (d[i] < int(carry))
- d
-
-public defn plus (x:BigInt, y:BigInt) -> BigInt : op(plus!, x, y)
-
-public defn cat! (d: BigInt, s0: BigInt, s1: BigInt) -> BigInt :
- lsh!(d, s0, length(s1))
- ;; println-all([" LSH! " s0 " " length(s1) " => " d])
- for i in 0 to num-words(s1) do :
- d[i] = d[i] | s1[i]
- d
-
-public defn cat (x:BigInt, y:BigInt) -> BigInt :
- ;; println-all(["> CAT " x " " y])
- val res = cat!(BigInt(length(x) + length(y)), x, y)
- ;; println-all(["< CAT " x " " y " => " res])
- res
-
-public defn cat (args:Streamable<BigInt>) -> BigInt :
- reduce(cat, args)
-
-public defn sub! (d: BigInt, s0: BigInt, s1: BigInt) -> BigInt :
- var borrow = false
- for i in 0 to num-words(d) do :
- d[i] = s0[i] - s1[i] + int(borrow)
- borrow = (s0[i] < (s0[i] - s1[i])) or (s0[i] - s1[i]) < d[i]
- d
-
-public defn sub (x:BigInt, y:BigInt) -> BigInt : op(sub!, x, y)
-
-public defn neg! (d: BigInt, s0: BigInt) -> BigInt :
- var borrow = false
- for i in 0 to num-words(d) do :
- d[i] = neg(s0[i]) - int(borrow)
- borrow = (s0[i] > 0) or (d[i] > 0)
- d
-
-public defn neg (x:BigInt) -> BigInt : op(neg!, x)
-
-public defn neg? (x:BigInt) -> True|False :
- val nw = num-words(x)
- val msb = x[nw - 1] >> (length(x) - nw * 32 - 1)
- if msb == 0 : false
- else : true
-
-public defn rsha! (d:BigInt, s0:BigInt, amount:Int) -> BigInt :
- val w = length(s0)
- val nw = num-words(d)
- val n-shift-bits = amount % 32
- val n-shift-words = amount / 32
- val n-rev-shift-bits = 32 - n-shift-bits
- val is-zero-carry = n-shift-bits == 0
- val msb = s0[nw - 1] >> (w - nw * 32 - 1)
- var carry = 0;
-
- if msb == 0 :
- for i in 0 to n-shift-words do :
- d[nw - i - 1] = 0
-
- defn* loopy (i:Int) :
- if i >= n-shift-words :
- val x = s0[i]
- d[i - n-shift-words] = (x >> n-shift-bits) | carry
- carry = if is-zero-carry: 0 else: x << n-rev-shift-bits
- loopy(i - 1)
- loopy(nw - 1)
-
- if msb != 0 :
- val boundary = (w - amount)
-
- defn* loop (i:Int) :
- if i >= 0 :
- val idx = i * 32
- if idx > boundary :
- d[i] = -1
- loop(i - 1)
- else :
- d[i] = d[i] | (-1 << (boundary - idx))
- d[nw - 1] = d[nw - 1] & (-1 >> ((nw - 1) * 32 - w))
- loop(nw - 1)
- d
-
-public defn signed-shift-right (b:BigInt, n:Int) -> BigInt : rsha!(BigInt(length(b)), b, n)
-
-public defn rsh! (d:BigInt, s0:BigInt, amount:Int) -> BigInt :
- val nw = num-words(d)
- var carry = 0
- val n-shift-bits = amount % 32
- val n-shift-words = amount / 32
- val n-rev-shift-bits = 32 - n-shift-bits
- val is-zero-carry = n-shift-bits == 0
- for i in 0 to n-shift-words do :
- d[nw - i - 1] = 0
- defn* loop (i:Int) :
- if i >= n-shift-words :
- val x = s0[i]
- d[i - n-shift-words] = (x >> n-shift-bits) | carry
- carry = if is-zero-carry: 0 else: x << n-rev-shift-bits
- loop(i - 1)
- loop(nw - 1)
- d
-
-public defn shift-right (b:BigInt, n:Int) -> BigInt : rsh!(BigInt(length(b)), b, n)
-
-public defn lsh! (d:BigInt, s0:BigInt, amount:Int) :
- ;; println-all(["LSH " s0 " AMOUNT " amount " INTO BIGINT<" length(d) ">"])
- val n-shift-bits = amount % 32
- val n-shift-words = amount / 32
- val n-rev-shift-bits = 32 - n-shift-bits
- val is-zero-carry = n-shift-bits == 0
- for i in 0 to num-words(d) do :
- d[i] = 0
- var carry = 0;
- ;; println-all(["LSH AMOUNT " amount " VNB " 32 " NSB " n-shift-bits " NSW " n-shift-words " NRSB " n-rev-shift-bits])
- for i in 0 to (num-words(d) - n-shift-words) do :
- val x = if i >= num-words(s0) : 0 else: s0[i]
- ;; println-all([" SHIFTING " (i + n-shift-words) " VAL " (x << n-shift-bits)])
- d[i + n-shift-words] = (x << n-shift-bits) | carry
- carry = if is-zero-carry: 0 else: x >> n-rev-shift-bits
- d
-
-public defn shift-left (b:BigInt, n:Int) -> BigInt : lsh!(BigInt(length(b) + n), b, n)
-
-;; defn mul! (d: BigInt, s0: BigInt, s1: BigInt, nb0: Int, nb1: Int) -> BigInt :
-;; ;; Adapted from Hacker's Delight, from Knuth
-;; var nbd = nb0 + nb1
-;; for i in 0 to val-n-words(nbd) do :
-;; d[i] = 0
-;;
-;; half-val-t* w = reinterpret-cast<half-val-t*>(d);
-;; half-val-t* u = reinterpret-cast<half-val-t*>(s0);
-;; half-val-t* v = reinterpret-cast<half-val-t*>(s1);
-;; val m = val-n-half-words(nb0)
-;; val n = val-n-half-words(nb1)
-;; val p = val-n-half-words(nbd)
-;;
-;; for j in 0 to n do :
-;; var k = 0
-;; for i in 0 to min(m, p - j) do :
-;; val t = u[i] * v[j] + w[i + j] + k
-;; w[i + j] = t
-;; k = t >> val-n-half-bits()
-;; if ((j + m) < p)
-;; w[j + m] = k
-;; d
-
-public defn bit-xor! (d: BigInt, s0: BigInt, s1: BigInt) : map!(bit-xor, d, s0, s1)
-
-public defn bit-xor (b0:BigInt, b1:BigInt) : op(bit-xor!, b0, b1)
-
-public defn bit-or! (d: BigInt, s0: BigInt, s1: BigInt) : map!(bit-or, d, s0, s1)
-
-public defn bit-or (b0:BigInt, b1:BigInt) : op(bit-or!, b0, b1)
-
-public defn bit-and! (d: BigInt, s0: BigInt, s1: BigInt) : map!(bit-and, d, s0, s1)
-
-public defn bit-and (b0:BigInt, b1:BigInt) : op(bit-and!, b0, b1)
-
-public defn bit-invert! (d: BigInt, s0: BigInt) : map!(bit-xor, d, s0, mask!(d))
-
-public defn bit-invert (b0:BigInt) : op(bit-invert!, b0)
-
-defn check (msg:String, x:BigInt, e:BigInt) :
- println-all([msg " " x " E " e " ? " x == e])
-
-defn check (msg:String, x:BigInt) :
- println-all([msg " " x])
-
-;;; check("Ba ", BigIntLit({ _ }, 1))
-;;; check("Bb ", BigIntLit({ _ }, 16))
-;;; check("Bc ", BigIntLit({ _ }, 32))
-;;; check("Bd ", BigIntLit({ _ }, 48))
-;;; check("Be ", BigIntLit({ _ }, 64))
-;;; check("Bf ", BigIntLit({ _ }, 65))
-;;; check("B1 ", BigIntLit(1, 8))
-;;; check("B2 ", BigIntLit(2, 8))
-;;; check("B+ ", BigIntLit(3, 8) + BigIntLit(5, 8), BigIntLit(3 + 5, 8))
-;;; check("B- ", BigIntLit(5, 8) + BigIntLit(3, 8), BigIntLit(5 + 3, 8))
-;;; check("B| ", BigIntLit(5, 8) | BigIntLit(9, 8), BigIntLit(5 | 9, 8))
-;;; check("B& ", BigIntLit(5, 8) & BigIntLit(9, 8), BigIntLit(5 & 9, 8))
-;;; check("B^ ", BigIntLit(5, 8) ^ BigIntLit(9, 8), BigIntLit(5 ^ 9, 8))
-;;; check("B< ", BigIntLit(5, 8) << 1, BigIntLit(5 << 1, 9))
-;;; check("B< ", BigIntLit(5, 3) << 10, BigIntLit(5 << 1, 13))
-;;; check("B< ", BigIntLit(5, 3) << 32, BigIntLit(5 << 1, 38))
-;;; check("B< ", BigIntLit("b1010") << 1, BigIntLit(10 << 1, 5))
-;check("S1 ", BigIntLit("hfafa") << 16, BigIntLit("hfafa0000", 32))
-;check("S1 ", BigIntLit(1,32) , BigIntLit(1,32))
-;check("S1 ", BigIntLit(0,32) , BigIntLit(0,32))
-;;; check("B< ", BigIntLit(5, 3) << 64, BigIntLit(5 << 1, 67))
-;;; check("BN ", neg(BigIntLit(2, 8)), BigIntLit(-2, 8))
-;check("S2 ", BigIntLit("b11111010") << 8, BigIntLit("b1111101000000000", 16))
-;check("C1 ", cat(BigIntLit("b11111010", 8), BigIntLit("b10111100", 8)), BigIntLit("b1111101010111100", 16))
-;check("C3 ", cat(cat(BigIntLit("b1111"), BigIntLit("b1010")), cat(BigIntLit("b1011"), BigIntLit("b1100"))), BigIntLit("b1111101010111100", 16))
-;check("C4 ", cat([BigIntLit("b1111"), BigIntLit("b1010"), BigIntLit("b1011"), BigIntLit("b1100")]), BigIntLit("b1111101010111100", 16))
-;check("C5 ", BigIntLit("b101111001"), BigIntLit("b101111001"))
-;check("C6 ", cat(BigIntLit("b1"), BigIntLit("b01111001")), BigIntLit("b101111001"))
-;check("C7 ", cat(BigIntLit("b11101"), BigIntLit("b101111001")), BigIntLit("b11101101111001"))
-;check("C8 ", cat([BigIntLit("b11"), BigIntLit("b101"), BigIntLit("b1011"), BigIntLit("b11001")]), BigIntLit("b11101101111001"))
-;check("C0 ", bits(BigIntLit("b11101101111001"), 10, 1), BigIntLit("b0110111100"))
diff --git a/src/main/stanza/bigint2.stanza b/src/main/stanza/bigint2.stanza
index deae1313..e64cd9b6 100644
--- a/src/main/stanza/bigint2.stanza
+++ b/src/main/stanza/bigint2.stanza
@@ -1,3 +1,28 @@
+;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.
+
defpackage bigint2 :
import core
import verse
diff --git a/src/main/stanza/chirrtl.stanza b/src/main/stanza/chirrtl.stanza
index 6bce8ce4..43e6d2d6 100644
--- a/src/main/stanza/chirrtl.stanza
+++ b/src/main/stanza/chirrtl.stanza
@@ -1,3 +1,27 @@
+;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.
defpackage firrtl/chirrtl :
import core
import verse
@@ -5,6 +29,17 @@ defpackage firrtl/chirrtl :
import firrtl/ir-utils
import firrtl/primops
+
+; ===============================
+public val chirrtl-passes = to-list $ [
+ CInferTypes()
+ CInferMDir()
+ RemoveCHIRRTL()
+ FromCHIRRTL()
+]
+; ===============================
+
+
; CHIRRTL Additional IR Nodes
public definterface MPortDir
public val MInfer = new MPortDir
@@ -55,7 +90,7 @@ defmethod map (f: Symbol -> Symbol, c:CDefMPort) -> CDefMPort :
public defstruct CInferTypes <: Pass
public defmethod pass (b:CInferTypes) -> (Circuit -> Circuit) : infer-types
public defmethod name (b:CInferTypes) -> String : "CInfer Types"
-public defmethod short-name (b:CInferTypes) -> String : "c-infer-types"
+public defmethod short-name (b:CInferTypes) -> String : "cinfertypes"
;--------------- Utils -----------------
@@ -149,7 +184,7 @@ defn infer-types (c:Circuit) -> Circuit :
public defstruct CInferMDir <: Pass
public defmethod pass (b:CInferMDir) -> (Circuit -> Circuit) : infer-mdir
public defmethod name (b:CInferMDir) -> String : "CInfer MDir"
-public defmethod short-name (b:CInferMDir) -> String : "cinfer-mdir"
+public defmethod short-name (b:CInferMDir) -> String : "cinfermdir"
defn infer-mdir (c:Circuit) -> Circuit :
defn infer-mdir (m:Module) -> Module :
@@ -209,7 +244,7 @@ defn infer-mdir (c:Circuit) -> Circuit :
public defstruct RemoveCHIRRTL <: Pass
public defmethod pass (b:RemoveCHIRRTL) -> (Circuit -> Circuit) : remove-chirrtl
public defmethod name (b:RemoveCHIRRTL) -> String : "Remove CHIRRTL"
-public defmethod short-name (b:RemoveCHIRRTL) -> String : "remove-chirrtl"
+public defmethod short-name (b:RemoveCHIRRTL) -> String : "removechirrtl"
defstruct MPort :
name : Symbol
@@ -411,3 +446,18 @@ defn remove-chirrtl (c:Circuit) :
(m:ExModule) : m
+;============ FromCHIRRTL ==============
+
+public defstruct FromCHIRRTL <: Pass
+public defmethod pass (b:FromCHIRRTL) -> (Circuit -> Circuit) : from-chirrtl
+public defmethod name (b:FromCHIRRTL) -> String : "From CHIRRTL"
+public defmethod short-name (b:FromCHIRRTL) -> String : "from-chirrtl"
+
+defn from-chirrtl (c:Circuit) -> Circuit :
+ val c1 = infer-types(c)
+ ;println(c1)
+ val c2 = infer-mdir(c1)
+ ;println(c2)
+ val c3 = remove-chirrtl(c2)
+ ;println(c3)
+ c3
diff --git a/src/main/stanza/compilers.stanza b/src/main/stanza/compilers.stanza
index 0d0191bf..663f28b2 100644
--- a/src/main/stanza/compilers.stanza
+++ b/src/main/stanza/compilers.stanza
@@ -1,3 +1,27 @@
+;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.
defpackage firrtl/compiler :
import core
import verse
@@ -50,14 +74,14 @@ public defmethod passes (c:StandardVerilog) -> List<Pass> :
;RemoveSpecialChars()
;TempElimination() ; Needs to check number of uses
;===============
- CInferTypes()
- CInferMDir()
- RemoveCHIRRTL()
- ;===============
- CheckHighForm()
+ ;CInferTypes()
+ ;CInferMDir()
+ ;RemoveCHIRRTL()
;===============
ToWorkingIR()
;===============
+ CheckHighForm()
+ ;===============
ResolveKinds()
InferTypes()
CheckTypes()
@@ -115,7 +139,6 @@ public defmethod backend (c:StandardFIRRTL) -> List<Pass> :
to-list $ [ FIRRTL(with-output(c)) ]
public defmethod passes (c:StandardFIRRTL) -> List<Pass> :
to-list $ [
- CheckHighForm()
FIRRTL(with-output(c))
]
@@ -176,8 +199,8 @@ public defmethod passes (c:StandardLoFIRRTL) -> List<Pass> :
]
;============= DRIVER ======================================
-public defn run-backend (c:Circuit,comp:Compiler) :
- run-passes(c,backend(comp))
+public defn run-backend (c:Circuit,pass:Pass) :
+ run-passes(c,list(pass))
public defn run-passes (c:Circuit,comp:Compiler) -> Circuit:
run-passes(c,passes(comp))
public defn run-passes (c:Circuit,ls:List<Pass>) -> Circuit:
diff --git a/src/main/stanza/custom-compiler.stanza b/src/main/stanza/custom-compiler.stanza
index 908f70ff..95686189 100644
--- a/src/main/stanza/custom-compiler.stanza
+++ b/src/main/stanza/custom-compiler.stanza
@@ -1,3 +1,27 @@
+;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.
;defpackage firrtl/custom-compiler :
; import core
; import verse
diff --git a/src/main/stanza/custom-passes.stanza b/src/main/stanza/custom-passes.stanza
index 65c5fa9b..089b9318 100644
--- a/src/main/stanza/custom-passes.stanza
+++ b/src/main/stanza/custom-passes.stanza
@@ -1,3 +1,27 @@
+;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.
;defpackage firrtl/custom-passes :
; import core
; import verse
diff --git a/src/main/stanza/errors.stanza b/src/main/stanza/errors.stanza
index a0c48dc8..6d702e9b 100644
--- a/src/main/stanza/errors.stanza
+++ b/src/main/stanza/errors.stanza
@@ -1,3 +1,27 @@
+;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.
defpackage firrtl/errors :
import core
import verse
@@ -240,7 +264,8 @@ public defn check-high-form (c:Circuit) -> Circuit :
defn check-high-form-w (w:Width) -> Width :
match(w) :
(w:IntWidth) :
- if width(w) <= to-long(0) : add(errors,NegWidth())
+ if width(w) <= to-long(0) :
+ add(errors,NegWidth())
w
(w) : w
defn check-high-form-t (t:Type) -> Type :
@@ -257,17 +282,17 @@ public defn check-high-form (c:Circuit) -> Circuit :
defn check-high-form-e (e:Expression) -> Expression :
defn valid-subexp (e:Expression) -> Expression :
match(e) :
- (e:Ref|SubField|SubIndex|SubAccess|Mux|ValidIf) : false
+ (e:WRef|WSubField|WSubIndex|WSubAccess|Mux|ValidIf) : false
(e) : add(errors,InvalidAccess())
e
match(map(check-high-form-e,e)) :
- (e:Ref) :
+ (e:WRef) :
if not key?(names,name(e)) :
add(errors,UndeclaredReference(name(e)))
(e:DoPrim) : check-high-form-primop(e)
(e:Mux|ValidIf) : e
(e:UIntValue) : false
- (e:SubAccess) :
+ (e:WSubAccess) :
valid-subexp(exp(e))
e
(e) : map(valid-subexp,e)
@@ -293,7 +318,7 @@ public defn check-high-form (c:Circuit) -> Circuit :
(s:DefMemory) :
if has-flip?(data-type(s)) : add(errors, MemWithFlip(name(s)))
if depth(s) <= 0 : add(errors,NegMemSize())
- (s:DefInstance) :
+ (s:WDefInstance) :
if not contains?(module(s),map(name,modules(c))) :
add(errors, ModuleNotDefined(module(s)))
(s:Connect) : check-valid-loc(loc(s))
diff --git a/src/main/stanza/firrtl-ir.stanza b/src/main/stanza/firrtl-ir.stanza
index e6c242bf..fdb7659a 100644
--- a/src/main/stanza/firrtl-ir.stanza
+++ b/src/main/stanza/firrtl-ir.stanza
@@ -1,3 +1,27 @@
+;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.
defpackage firrtl/ir2 :
import core
import verse
diff --git a/src/main/stanza/firrtl-lexer.stanza b/src/main/stanza/firrtl-lexer.stanza
index 9d50d8ab..1d119d00 100644
--- a/src/main/stanza/firrtl-lexer.stanza
+++ b/src/main/stanza/firrtl-lexer.stanza
@@ -1,3 +1,27 @@
+;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.
defpackage firrtl/lexer :
import core
import core/stringeater
diff --git a/src/main/stanza/firrtl-main.stanza b/src/main/stanza/firrtl-main.stanza
index e77c712e..362961af 100644
--- a/src/main/stanza/firrtl-main.stanza
+++ b/src/main/stanza/firrtl-main.stanza
@@ -1,3 +1,27 @@
+;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.
#include<"core/stringeater.stanza">
#include<"core/macro-utils.stanza">
#include<"compiler/stz-algorithms.stanza">
diff --git a/src/main/stanza/firrtl-test-main.stanza b/src/main/stanza/firrtl-test-main.stanza
index 2892cccc..4fcc9dee 100644
--- a/src/main/stanza/firrtl-test-main.stanza
+++ b/src/main/stanza/firrtl-test-main.stanza
@@ -1,3 +1,27 @@
+;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.
#include<"core/stringeater.stanza">
#include<"core/macro-utils.stanza">
#include<"compiler/stz-algorithms.stanza">
@@ -32,6 +56,8 @@ defpackage firrtl-main :
import stz/parser
import firrtl/ir-utils
import firrtl/compiler
+ import firrtl/chirrtl
+ import firrtl/firrtl
;Custom Packages
;import firrtl/custom-passes
;import firrtl/custom-compiler
@@ -48,7 +74,7 @@ defn set-printvars! (p:List<Char>) :
defn get-passes (pass-names:List<String>) -> List<Pass> :
for n in pass-names map :
- val p = for p in standard-passes find :
+ val p = for p in append(standard-passes,chirrtl-passes) find :
n == short-name(p)
if p == false :
error(to-string $ ["Unrecognized pass flag: " n])
@@ -134,8 +160,8 @@ defn main () :
if compiler == false :
var c*:Circuit = run-passes(circuit*,get-passes(to-list(pass-names)))
switch {_ == backend} :
- "verilog" : run-backend(c*,StandardVerilog(with-output))
- "firrtl" : run-backend(c*,StandardFIRRTL(with-output))
+ "verilog" : run-backend(c*,LoToVerilog(with-output))
+ "firrtl" : run-backend(c*,FIRRTL(with-output))
else : error("Invalid backend flag!")
else :
switch {_ == compiler} :
diff --git a/src/main/stanza/firrtl.stanza b/src/main/stanza/firrtl.stanza
index 2320bc81..f51a13a6 100644
--- a/src/main/stanza/firrtl.stanza
+++ b/src/main/stanza/firrtl.stanza
@@ -1,3 +1,27 @@
+;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.
defpackage firrtl/firrtl :
import core
import verse
diff --git a/src/main/stanza/flo.stanza b/src/main/stanza/flo.stanza
index 015da39a..ad04bb23 100644
--- a/src/main/stanza/flo.stanza
+++ b/src/main/stanza/flo.stanza
@@ -1,3 +1,27 @@
+;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.
defpackage firrtl/flo :
import core
import verse
diff --git a/src/main/stanza/ir-parser.stanza b/src/main/stanza/ir-parser.stanza
index 139216c3..6bbfa432 100644
--- a/src/main/stanza/ir-parser.stanza
+++ b/src/main/stanza/ir-parser.stanza
@@ -1,3 +1,27 @@
+;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.
defpackage firrtl/parser :
import core
import verse
@@ -328,6 +352,7 @@ defsyntax firrtl :
(w:IntWidth) :
if to-long(req-num-bits(b)) > width(w) :
FPE(form, "Width too small for UIntValue.")
+ if width(w) == to-long(0) : println("is zero at")
UIntValue(b, w)
(w) :
;UIntValue(b, w)
diff --git a/src/main/stanza/ir-utils.stanza b/src/main/stanza/ir-utils.stanza
index 24149649..a96d7503 100644
--- a/src/main/stanza/ir-utils.stanza
+++ b/src/main/stanza/ir-utils.stanza
@@ -1,3 +1,27 @@
+;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.
defpackage firrtl/ir-utils :
import core
import verse
@@ -147,8 +171,8 @@ public defn children (e:Expression) -> List<Expression> :
public var mname : Symbol = `blah
public defn exp-hash (e:Expression) -> Int :
turn-off-debug(false)
- val i = symbol-hash(to-symbol(string-join(map(to-string,list(mname `.... e)))))
- ;val i = symbol-hash(to-symbol(to-string(e)))
+ ;val i = symbol-hash(to-symbol(string-join(map(to-string,list(mname `.... e)))))
+ val i = symbol-hash(to-symbol(to-string(e)))
turn-on-debug(false)
i
@@ -395,8 +419,9 @@ defmethod print (o:OutputStream, e:Expression) :
(e:SubField) : print-all(o, [exp(e) "." name(e)])
(e:SubIndex) : print-all(o, [exp(e) "[" value(e) "]"])
(e:SubAccess) : print-all(o, [exp(e) "[" index(e) "]"])
- (e:UIntValue) : print-all(o, ["UInt(" value(e) ")"])
- (e:SIntValue) : print-all(o, ["SInt(" value(e) ")"])
+ (e:UIntValue) :
+ print-all(o, ["UInt<" width(e) ">(" value(e) ")"])
+ (e:SIntValue) : print-all(o, ["SInt<" width(e) ">(" value(e) ")"])
(e:DoPrim) :
print-all(o, [op(e) "("])
print-all(o, join(concat(args(e), consts(e)), ", "))
diff --git a/src/main/stanza/passes.stanza b/src/main/stanza/passes.stanza
index 75be008f..cb4607b8 100644
--- a/src/main/stanza/passes.stanza
+++ b/src/main/stanza/passes.stanza
@@ -1,3 +1,27 @@
+;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.
defpackage firrtl/passes :
import core
import verse
@@ -11,27 +35,27 @@ defpackage firrtl/passes :
;============== Pass List ================
public val standard-passes = to-list $ [
CheckHighForm()
- ;TempElimination()
ToWorkingIR()
Resolve()
ResolveKinds()
- ;CheckKinds()
InferTypes()
- ;CheckTypes()
+ CheckTypes()
ResolveGenders()
- ;CheckGenders()
- ;ExpandAccessors()
- ;LowerToGround()
- ;ExpandIndexedConnects()
- ;InlineIndexed()
- ExpandWhens()
+ CheckGenders()
InferWidths()
- ;Inline()
+ CheckWidths()
+ PullMuxes()
+ ExpandConnects()
+ RemoveAccesses()
+ ExpandWhens()
+ LowerTypes()
+ CheckInitialization()
+ ConstProp()
+ VerilogWrap()
SplitExp()
- ;CheckLowForm()
- ;ToRealIR()
- ;Pad()
- ]
+ VerilogRename()
+ Resolve()
+]
;=============== WORKING IR ================================
public definterface Kind
public defstruct WireKind <: Kind
@@ -70,11 +94,6 @@ public defstruct WSubAccess <: Expression :
index: Expression
type: Type with: (as-method => true)
gender: Gender with: (as-method => true)
-defstruct WIndexer <: Expression :
- exps: List<Expression>
- index: Expression
- type: Type with: (as-method => true)
- gender : Gender with: (as-method => true)
public defstruct WVoid <: Expression
public defstruct WInvalid <: Expression
public defstruct WDefInstance <: Stmt :
@@ -104,11 +123,6 @@ defmethod kind (e:Expression) :
(e:WRef) : kind(e)
(e:WSubField) : kind(exp(e))
(e:WSubIndex) : kind(exp(e))
- (e:WIndexer) :
- val k = kind(exps(e)[0])
- for x in exps(e) do :
- if k != kind(x) : error("All kinds of exps of WIndexer must be the same")
- k
(e) : ExpKind()
defmethod info (stmt:Begin) -> FileInfo : FileInfo()
@@ -124,10 +138,10 @@ defmethod get-type (s:WDefInstance) -> Type : type(s)
defmethod equal? (e1:Expression,e2:Expression) -> True|False :
match(e1,e2) :
(e1:UIntValue,e2:UIntValue) :
- if value(e1) == value(e2) : width(e1) == width(e2)
+ if to-int(value(e1)) == to-int(value(e2)) : width(e1) == width(e2)
else : false
(e1:SIntValue,e2:SIntValue) :
- if value(e1) == value(e2) : width(e1) == width(e2)
+ if to-int(value(e1)) == to-int(value(e2)) : width(e1) == width(e2)
else : false
(e1:WRef,e2:WRef) : name(e1) == name(e2)
(e1:WSubField,e2:WSubField) :
@@ -138,11 +152,6 @@ defmethod equal? (e1:Expression,e2:Expression) -> True|False :
(index(e1) == index(e2)) and (exp(e1) == exp(e2))
(e1:WVoid,e2:WVoid) : true
(e1:WInvalid,e2:WInvalid) : true
- (e1:WIndexer,e2:WIndexer) :
- var bool = (length(exps(e1)) == length(exps(e2)))
- for (e1* in exps(e1),e2* in exps(e2)) do :
- bool = bool and (e1* == e2*)
- bool and (index(e1) == index(e2))
(e1:DoPrim,e2:DoPrim) :
var are-equal? = op(e1) == op(e2)
for (x in args(e1),y in args(e2)) do :
@@ -296,9 +305,6 @@ defmethod print (o:OutputStream, e:WVoid) :
defmethod print (o:OutputStream, e:WInvalid) :
print(o,"INVALID")
print-debug(o,e as ?)
-defmethod print (o:OutputStream, c:WIndexer) :
- print-all(o, [exps(c) "[" index(c) "]"])
- print-debug(o,c as ?)
defmethod print (o:OutputStream, c:WDefInstance) :
print-all(o, ["inst " name(c) " of " module(c) " : " type(c)])
print-debug(o,c as ?)
@@ -797,10 +803,6 @@ defn resolve-genders (c:Circuit) :
val exp* = resolve-e(exp(e),g)
val index* = resolve-e(index(e),MALE)
WSubAccess(exp*,index*,type(e),g)
- (e:WIndexer) :
- val exps* = map(resolve-e{_,g},exps(e))
- val index* = resolve-e(index(e),MALE)
- WIndexer(exps*,index*,type(e),g)
(e) : map(resolve-e{_,g},e)
defn resolve-s (s:Stmt) -> Stmt :
@@ -1704,7 +1706,8 @@ defn resolve (c:Circuit) -> Circuit :
resolve-genders $
check-types $
infer-types $
- resolve-kinds $ c
+ resolve-kinds $
+ to-working-ir(c)
;;================= Inline Instances ========================
;; Inlines instances. Assumes module with same name as the
@@ -1776,7 +1779,7 @@ defn resolve (c:Circuit) -> Circuit :
public defstruct VerilogWrap <: Pass
public defmethod pass (b:VerilogWrap) -> (Circuit -> Circuit) : v-wrap
public defmethod name (b:VerilogWrap) -> String : "Verilog Wrap"
-public defmethod short-name (b:VerilogWrap) -> String : "v-wrap"
+public defmethod short-name (b:VerilogWrap) -> String : "verilog-wrap"
public definterface WPrimOp <: PrimOp
val ADDW-OP = new WPrimOp
@@ -2282,7 +2285,6 @@ defn root-ref (e:Expression) -> WRef :
match(e) :
(e:WRef) : e
(e:WSubField|WSubIndex|WSubAccess) : root-ref(exp(e))
- (e:WIndexer) : root-ref(exps(e)[0])
;------------- Pass ------------------
@@ -2392,7 +2394,7 @@ defn lower-types (c:Circuit) -> Circuit :
public defstruct VerilogRename <: Pass
public defmethod pass (b:VerilogRename) -> (Circuit -> Circuit) : verilog-rename
public defmethod name (b:VerilogRename) -> String : "Verilog Rename"
-public defmethod short-name (b:VerilogRename) -> String : "Verilog Rename"
+public defmethod short-name (b:VerilogRename) -> String : "verilog-rename"
defn verilog-rename (c:Circuit) -> Circuit :
defn verilog-rename-n (n:Symbol) -> Symbol :
@@ -2421,7 +2423,7 @@ public defstruct Verilog <: Pass :
with-output: (() -> False) -> False
public defmethod pass (b:Verilog) -> (Circuit -> Circuit) : emit-verilog{with-output(b),_}
public defmethod name (b:Verilog) -> String : "To Verilog"
-public defmethod short-name (b:Verilog) -> String : "To Verilog"
+public defmethod short-name (b:Verilog) -> String : "to-verilog"
;============ Utilz =============
defstruct VIndent
@@ -2899,3 +2901,25 @@ defn emit-verilog (with-output:(() -> False) -> False, c:Circuit) :
c
+;============ LoFIRRTLToVERILOG ==============
+
+public defstruct LoToVerilog <: Pass :
+ with-output: (() -> False) -> False
+public defmethod pass (b:LoToVerilog) -> (Circuit -> Circuit) : lo-to-verilog{with-output(b),_}
+public defmethod name (b:LoToVerilog) -> String : "Lo To Verilog"
+public defmethod short-name (b:LoToVerilog) -> String : "lo-to-verilog"
+
+defn lo-to-verilog (with-output:(() -> False) -> False, c:Circuit) :
+ val c1 = to-working-ir(c)
+ ;println(c1)
+ val c2 = resolve(c1)
+ ;println(c2)
+ val c3 = v-wrap(c2)
+ ;println(c3)
+ val c4 = split-exp(c3)
+ ;println(c4)
+ val c5 = verilog-rename(c4)
+ ;println(c5)
+ emit-verilog(with-output,c5)
+
+
diff --git a/src/main/stanza/primop.stanza b/src/main/stanza/primop.stanza
index 3d0b06a4..f6aa0de5 100644
--- a/src/main/stanza/primop.stanza
+++ b/src/main/stanza/primop.stanza
@@ -1,3 +1,27 @@
+;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.
defpackage firrtl/primops :
import core
import verse
diff --git a/src/main/stanza/symbolic-value.stanza b/src/main/stanza/symbolic-value.stanza
index d8ca2024..3d073f1b 100644
--- a/src/main/stanza/symbolic-value.stanza
+++ b/src/main/stanza/symbolic-value.stanza
@@ -1,3 +1,27 @@
+;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.
defpackage firrtl/symbolic-value :
import core
import verse
diff --git a/src/main/stanza/verilog.stanza b/src/main/stanza/verilog.stanza
deleted file mode 100644
index 9040a8bd..00000000
--- a/src/main/stanza/verilog.stanza
+++ /dev/null
@@ -1,402 +0,0 @@
-defpackage firrtl/verilog :
- import core
- import verse
- import firrtl/ir-utils
- import firrtl/ir2
-
-defn width! (w:Width) -> Long :
- match(w) :
- (w:IntWidth) : width(w)
- (w) : error("Non-supported width type.")
-
-defn width! (t:Type) -> Long :
- match(t) :
- (t:UIntType) : width!(width(t))
- (t:SIntType) : width!(width(t))
- (t) : error("Non-supported type.")
-
-defn emit (w:Width) -> String :
- match(w) :
- (w:IntWidth) :
- if width(w) >= to-long(1) : string-join $ ["[" width(w) - to-long(1) ":0]"] ;TODO check if need to special case 0 or 1 width wires
- else : ""
-
- (w) : error("Non-supported width type.")
-
-defn remove-subfield-s (s:Stmt) -> Stmt :
- defn remove-subfield-e (e:Expression) -> Expression :
- match(map(remove-subfield-e,e)) :
- (e:SubField) :
- Ref(to-symbol $ string-join $ [emit(exp(e)) bundle-expand-delin name(e)],type(e))
- (e) : e
- map{remove-subfield-e,_ } $ map(remove-subfield-s,s)
-
-defn get-width (t:Type) -> String :
- match(t) :
- (t:UIntType) : emit(width(t))
- (t:SIntType) : emit(width(t))
- (t:ClockType) : emit(IntWidth(1))
- (t) : error("Non-supported type.")
-
-defn get-name (e:Expression) -> Symbol :
- match(e) :
- (e:Ref) : name(e)
- (e:SubField) : error("Shouldn't be here")
- (e) : error("Shouldn't be here")
-
-defn escape (s:String) -> String :
- val s* = Vector<String>()
- add(s*,"\"");"
- var percent = false
- for c in s do :
- if c == '\n' :
- add(s*,"\\n")
- else :
- if c == 'x' and percent :
- add(s*,"h")
- else : add(s*,to-string(c))
- percent = c == '%'
- add(s*,"\"");"
- string-join(s*)
-;============ Verilog Backend =============
-
-defn emit-as-type (e:Expression,t:Type) -> String :
- match(t) :
- (t:UIntType) : emit(e)
- (t:SIntType) : string-join(["$signed(" emit(e) ")"])
-
-defn emit-signed-if-any (e:Expression,ls:List<Expression>) -> String :
- var signed? = false
- for x in ls do :
- if type(x) typeof SIntType : signed? = true
- if not signed? : emit(e)
- else :
- match(type(e)) :
- (t:SIntType) : string-join(["$signed(" emit(e) ")"])
- (t:UIntType) : string-join(["$signed({1'b0," emit(e) "})"])
-
-defn emit (e:Expression) -> String :
- match(e) :
- (e:Ref) : to-string $ name(e)
- (e:UIntValue) :
- val str = to-string(value(e))
- val out = substring(str,1,length(str) - 1)
- string-join $ [width!(type(e)) "'" out]
- (e:SIntValue) : ;string-join $ [width!(type(e)) "'s" value(e)]
- val str = to-string(value(e))
- val out = substring(str,1,length(str) - 1)
- string-join $ [width!(type(e)) "'s" out]
- (e:SubField) : error(string-join(["Non-supported expression: " to-string(e)]))
- (e:SubIndex) : error(string-join(["Non-supported expression: " to-string(e)]))
- (e:DoPrim) :
- ;val sargs = map(emit-as-type{_,type(e)},args(e))
- ;val xargs = map(emit-signed-if-any{_,args(e)},args(e))
- string-join $ switch {_ == op(e)} :
- ADD-OP : [emit-signed-if-any(args(e)[0],args(e)) " + " emit-signed-if-any(args(e)[1],args(e))]
- SUB-OP : [emit-signed-if-any(args(e)[0],args(e)) " - " emit-signed-if-any(args(e)[1],args(e))]
- MUL-OP : [emit-signed-if-any(args(e)[0],args(e)) " * " emit-signed-if-any(args(e)[1],args(e)) ]
- DIV-OP : [emit-signed-if-any(args(e)[0],args(e)) " / " emit-signed-if-any(args(e)[1],args(e)) ]
- REM-OP : [emit-signed-if-any(args(e)[0],args(e)) " % " emit-signed-if-any(args(e)[1],args(e)) ]
- QUO-OP : [emit-signed-if-any(args(e)[0],args(e)) " / " emit-signed-if-any(args(e)[1],args(e)) ]
- REM-OP : [emit-signed-if-any(args(e)[0],args(e)) " % " emit-signed-if-any(args(e)[1],args(e)) ]
- ADD-WRAP-OP : [emit-signed-if-any(args(e)[0],args(e)), " + " emit-signed-if-any(args(e)[1],args(e))]
- SUB-WRAP-OP : [emit-signed-if-any(args(e)[0],args(e)), " - " emit-signed-if-any(args(e)[1],args(e))]
- LESS-OP : [emit-signed-if-any(args(e)[0],args(e)) " < " emit-signed-if-any(args(e)[1],args(e))]
- LESS-EQ-OP : [emit-signed-if-any(args(e)[0],args(e)) " <= " emit-signed-if-any(args(e)[1],args(e))]
- GREATER-OP : [emit-signed-if-any(args(e)[0],args(e)) " > " emit-signed-if-any(args(e)[1],args(e))]
- GREATER-EQ-OP : [emit-signed-if-any(args(e)[0],args(e)) " >= " emit-signed-if-any(args(e)[1],args(e))]
- NEQUIV-OP : [emit-signed-if-any(args(e)[0],args(e)) " != " emit-signed-if-any(args(e)[1],args(e))]
- EQUIV-OP : [emit-signed-if-any(args(e)[0],args(e)) " == " emit-signed-if-any(args(e)[1],args(e))]
- NEQUAL-OP : [emit-signed-if-any(args(e)[0],args(e)) " != " emit-signed-if-any(args(e)[1],args(e))]
- EQUAL-OP : [emit-signed-if-any(args(e)[0],args(e)) " == " emit-signed-if-any(args(e)[1],args(e))]
- MUX-OP :
- val en = emit(args(e)[0])
- [en " ? " emit-as-type(args(e)[1],type(e)) " : " emit-as-type(args(e)[2],type(e))]
- PAD-OP :
- val x = args(e)[0]
- val w = width!(type(x))
- val diff = (to-long(consts(e)[0]) - w)
- if w == to-long(0) : [ emit(x) ]
- else :
- if type(e) typeof SIntType : ["{{" diff "{" emit(x) "[" w - to-long(1) "]}}, " emit(x) " }"]
- else : ["{{" diff "'d0 }, " emit(x) " }"]
- AS-UINT-OP :
- ["$unsigned(" emit(args(e)[0]) ")"]
- AS-SINT-OP :
- ["$signed(" emit(args(e)[0]) ")"]
- DYN-SHIFT-LEFT-OP : [emit-as-type(args(e)[0],type(e)) " << " emit(args(e)[1])]
- DYN-SHIFT-RIGHT-OP :
- if type(e) typeof SIntType : [emit-as-type(args(e)[0],type(e)) " >>> " emit(args(e)[1])]
- else : [emit-as-type(args(e)[0],type(e)) " >> " emit(args(e)[1])]
- SHIFT-LEFT-OP : [emit-as-type(args(e)[0],type(e)) " << " consts(e)[0]]
- SHIFT-RIGHT-OP : [emit(args(e)[0]) "[" width!(type(args(e)[0])) - to-long(1) ":" consts(e)[0] "]"]
- ;if type(e) typeof SIntType : [emit-as-type(args(e)[0],type(e)) " >>> " consts(e)[0]]
- ;else : [emit-as-type(args(e)[0],type(e)) " >> " consts(e)[0]]
- NEG-OP : ["-{" emit-as-type(args(e)[0],type(e)) "}"]
- CONVERT-OP :
- match(type(args(e)[0])) :
- (t:UIntType) : ["{1'b0," emit-as-type(args(e)[0],type(e)) "}"]
- (t:SIntType) : [emit-as-type(args(e)[0],type(e))]
- BIT-NOT-OP : ["~ " emit-as-type(args(e)[0],type(e))]
- BIT-AND-OP : [emit-as-type(args(e)[0],type(e)) " & " emit-as-type(args(e)[1],type(e))]
- BIT-OR-OP : [emit-as-type(args(e)[0],type(e)) " | " emit-as-type(args(e)[1],type(e))]
- BIT-XOR-OP : [emit-as-type(args(e)[0],type(e)) " ^ " emit-as-type(args(e)[1],type(e))]
- CONCAT-OP : ["{" emit-as-type(args(e)[0],type(e)) "," emit-as-type(args(e)[1],type(e)) "}"]
- BIT-SELECT-OP : [emit(args(e)[0]) "[" consts(e)[0] "]"]
- BITS-SELECT-OP : [emit(args(e)[0]) "[" consts(e)[0] ":" consts(e)[1] "]"]
- BIT-AND-REDUCE-OP :
- var v = emit-as-type(args(e)[0],type(e))
- for x in tail(args(e)) do :
- v = concat(v, [" & " emit(x)])
- v
- BIT-OR-REDUCE-OP :
- var v = emit-as-type(args(e)[0],type(e))
- for x in tail(args(e)) do :
- v = concat(v, [" | " emit(x)])
- v
- BIT-XOR-REDUCE-OP :
- var v = emit-as-type(args(e)[0],type(e))
- for x in tail(args(e)) do :
- v = concat(v, [" ^ " emit(x)])
- v
- (e) :
- println(["Expression:" e])
- error("Unknown expression")
-
-
-defn emit-module (m:InModule) :
-
- val body* = remove-subfield-s(body(m))
-
- val vdecs = Vector<KeyValue<Symbol,Stmt>>() ; all declarations in order, to preserve ordering
- val decs = HashTable<Symbol,Stmt>(symbol-hash) ; all declarations, for fast lookups
- val cons = HashTable<Symbol,Expression>(symbol-hash) ; all connections
- val ens = HashTable<Symbol,Expression>(symbol-hash) ; all enables
- val simuls = HashTable<Symbol,Vector<Streamable>>(symbol-hash)
- defn build-table (s:Stmt) -> False :
- match(s) :
- (s:DefWire|DefPoison|DefRegister|DefMemory|DefNode|DefInstance) :
- add(vdecs,name(s) => s)
- decs[name(s)] = s
- (s:Conditionally) :
- match(conseq(s)) :
- (c:Connect) :
- val n = get-name(loc(c))
- ens[n] = pred(s)
- cons[n] = exp(conseq(s) as Connect)
- (c:PrintfStmt) :
- val my-clk-simuls = get?(simuls,get-name(clk(c)),Vector<Streamable>())
- add(my-clk-simuls,["if(" emit(pred(s)) ") begin"])
- add(my-clk-simuls,[" $fwrite(STDERR," string-join(List(escape(string(c)),map(emit,args(c))), ", ") ");"])
- add(my-clk-simuls,["end"])
- simuls[get-name(clk(c))] = my-clk-simuls
- (c:StopStmt) :
- val my-clk-simuls = get?(simuls,get-name(clk(c)),Vector<Streamable>())
- add(my-clk-simuls,["if(" emit(pred(s)) ") begin"])
- add(my-clk-simuls,[" $fdisplay(STDERR,\"" ret(c) "\");"])
- add(my-clk-simuls,[" $finish;"])
- add(my-clk-simuls,["end"])
- simuls[get-name(clk(c))] = my-clk-simuls
- (s:PrintfStmt) :
- val my-clk-simuls = get?(simuls,get-name(clk(s)),Vector<Streamable>())
- add(my-clk-simuls,["$fwrite(STDERR," string-join(List(escape(string(s)),map(emit,args(s))), ", ") ");"])
- simuls[get-name(clk(s))] = my-clk-simuls
- (c:StopStmt) :
- val my-clk-simuls = get?(simuls,get-name(clk(c)),Vector<Streamable>())
- add(my-clk-simuls,["$fdisplay(STDERR,\"" ret(c) "\");"])
- add(my-clk-simuls,["$finish;"])
- simuls[get-name(clk(c))] = my-clk-simuls
- (s:Connect) :
- val n = get-name(loc(s))
- cons[n] = exp(s)
- (s:Begin) : do(build-table,s)
- (s) : false
-
- build-table(body*)
-
- val wires = Vector<Streamable>()
- val regs = Vector<Streamable>()
- val inits = Vector<Streamable>()
- val assigns = Vector<Streamable>()
- val updates = HashTable<Symbol,Vector<Streamable>>(symbol-hash)
- val insts = HashTable<Symbol,Symbol>(symbol-hash) ; inst -> module
- val inst-ports = HashTable<Symbol,Vector<Streamable>>(symbol-hash)
-
- val sh = get-sym-hash(m)
- val rand-value = "$random" ;"0"
- defn rand-string (w:Long) -> String : string-join(["{" ((w + to-long(31)) / to-long(32)) "{" rand-value "}};"])
-
- for x in vdecs do :
- val sym = key(x)
- match(value(x)) :
- (s:DefPoison) :
- add(regs,["reg " get-width(type(s)) " " sym ";"])
- add(inits,[sym " = " rand-string(width!(type(s)))])
- (s:DefWire) :
- add(wires,["wire " get-width(type(s)) " " sym ";"])
- add(assigns,["assign " sym " = " emit(cons[sym]) ";"])
- (s:DefRegister) :
- add(regs,["reg " get-width(type(s)) " " sym ";"])
- val my-clk-update = get?(updates,get-name(clock(s)),Vector<Streamable>())
- if key?(ens,sym) :
- add(my-clk-update,["if(" emit(ens[sym]) ") begin"])
- val x = cons[sym]
- val y = emit(x)
- add(my-clk-update,[" " sym " <= " y ";"])
- add(my-clk-update,["end"])
- else :
- add(my-clk-update,[sym " <= " emit(cons[sym]) ";"])
- updates[get-name(clock(s))] = my-clk-update
- val w = width!(type(s))
- add(inits,[sym " = " rand-string(w)])
- (s:DefMemory) :
- add(regs,["reg " get-width(type(s)) " " sym " [0:" size(s) - 1 "];"])
- add(inits,["for (initvar = 0; initvar < " size(s) "; initvar = initvar+1)"])
- add(inits,[" " sym "[initvar] = " rand-string(width!(type(s))) ])
- (s:DefNode) :
- add(wires,["wire " get-width(type(value(s))) " " sym ";"])
- add(assigns,["assign " sym " = " emit(value(s)) ";"])
- (s:DefInstance) :
- inst-ports[sym] = Vector<Streamable>()
- insts[sym] = name(module(s) as Ref)
- for f in fields(type(module(s)) as BundleType) do :
- val n* = to-symbol $ string-join $ [sym bundle-expand-delin name(f)]
- add(wires,["wire " get-width(type(f)) " " n* ";"])
- add(inst-ports[sym], ["." name(f) "( " n* " )"])
- if flip(f) == REVERSE :
- add(assigns,["assign " n* " = " emit(cons[n*]) ";"])
- ;(s:DefAccessor) :
- ; val mem-declaration = decs[name(source(s) as Ref)] as DefMemory
- ; switch {_ == acc-dir(s)} :
- ; READ :
- ; if seq?(mem-declaration) :
- ; val index* = Ref(firrtl-gensym(name(index(s) as Ref),sh),type(index(s)))
- ; add(regs,[ "reg " get-width(type(index*)) " " name(index*) ";"]) ; register index for an additional cycle
-
- ; val w = width!(type(index*))
- ; add(inits,[name(index*) " = " rand-string(w)]) ; initialize registered index
-
- ; val my-clk-update = get?(updates,get-name(clock(mem-declaration)),Vector<Streamable>())
- ; add(my-clk-update,[name(index*) " <= " emit(index(s)) ";"]) ; register index
- ; updates[get-name(clock(mem-declaration))] = my-clk-update
-
- ; ; emit read accessor
- ; add(wires,["wire " get-width(type(source(s))) " " sym ";"])
- ; add(assigns,["assign " sym " = " emit(source(s)) "[" emit(index*) "];"])
- ; else :
- ; ; emit read accessor
- ; add(wires,["wire " get-width(type(source(s))) " " sym ";"])
- ; add(assigns,["assign " sym " = " emit(source(s)) "[" emit(index(s)) "];"])
- ; WRITE :
- ; val my-clk-update = get?(updates,get-name(clock(mem-declaration)),Vector<Streamable>())
- ; if key?(ens,sym) :
- ; add(my-clk-update,["if(" emit(ens[sym]) ") begin"])
- ; add(my-clk-update,[" " emit(source(s)) "[" emit(index(s)) "] <= " emit(cons[sym]) ";"])
- ; add(my-clk-update,["end"])
- ; else :
- ; add(my-clk-update,[emit(source(s)) "[" emit(index(s)) "] <= " emit(cons[sym]) ";"])
- ; updates[get-name(clock(mem-declaration))] = my-clk-update
- ; RDWR :
- ; if seq?(mem-declaration) :
- ; ; to make it sequential, register the index for an additional cycle
- ; val index* = Ref(firrtl-gensym(name(index(s) as Ref),sh),type(index(s)))
- ; add(regs,[ "reg " get-width(type(index*)) " " name(index*) ";"])
- ; val w = width!(type(index*))
- ; add(inits,[name(index*) " = " rand-string(w)])
- ; val my-clk-update = get?(updates,get-name(clock(mem-declaration)),Vector<Streamable>())
- ; add(my-clk-update,[name(index*) " <= " emit(index(s)) ";"])
- ; updates[get-name(clock(mem-declaration))] = my-clk-update
-
- ; ; emit read accessor
- ; add(wires,["wire " get-width(type(source(s))) " " sym ";"])
- ; add(assigns,["assign " sym " = " emit(source(s)) "[" emit(index*) "];"])
- ; else :
- ; ; emit read accessor
- ; add(wires,["wire " get-width(type(source(s))) " " sym ";"])
- ; add(assigns,["assign " sym " = " emit(source(s)) "[" emit(index(s)) "];"])
- ; val my-clk-update = get?(updates,get-name(clock(mem-declaration)),Vector<Streamable>())
- ; if key?(ens,sym) :
- ; add(my-clk-update,["if(" emit(ens[sym]) ") begin"])
- ; add(my-clk-update,[" " emit(source(s)) "[" emit(index(s)) "] <= " emit(cons[sym]) ";"])
- ; add(my-clk-update,["end"])
- ; else :
- ; add(my-clk-update,[emit(source(s)) "[" emit(index(s)) "] <= " emit(cons[sym]) ";"])
- ; updates[get-name(clock(mem-declaration))] = my-clk-update
-
- ;==== Actually printing module =====
- val port-indent = " "
- print-all(["module " name(m) "(\n"])
- for (p in ports(m),i in 1 to false) do :
- var end = ",\n"
- if length(ports(m)) == i :
- end = "\n);\n"
- switch {_ == direction(p)} :
- INPUT :
- print-all([port-indent "input " get-width(type(p)) " " name(p) end])
- OUTPUT :
- print-all([port-indent "output " get-width(type(p)) " " name(p) end])
- add(assigns,["assign " name(p) " = " emit(cons[name(p)]) ";"])
- if length(ports(m)) == 0 : print(");\n")
-
- if length(simuls) != 0 : print-all([" integer STDERR = 32'h80000002;\n"])
-
- for w in wires do :
- print(" ")
- println-all(w)
- for r in regs do :
- print(" ")
- println-all(r)
-
- if length(inits) != 0 :
- println("`ifndef SYNTHESIS")
- println(" integer initvar;")
- println(" initial begin")
- println(" #0.002;")
- for i in inits do :
- print-all(" ")
- println-all(i)
- println(" end")
- println("`endif")
-
- for a in assigns do :
- print(" ")
- println-all(a)
-
- for x in insts do :
- println-all([" " value(x) " " key(x) " ("])
- ;print-all([".clk( clk )"])
- for (y in inst-ports[key(x)],i in 1 to false) do :
- print(" ")
- print-all(y)
- if length(inst-ports[key(x)]) != i :
- print(",\n")
- println("\n );")
-
- for x in updates do :
- if length(value(x)) != 0 :
- println-all([" always @(posedge " key(x) ") begin"])
- for u in value(x) do :
- print(" ")
- println-all(u)
- println(" end")
-
- for x in simuls do :
- if length(value(x)) != 0 :
- println("`ifndef SYNTHESIS")
- println-all([" always @(posedge " key(x) ") begin"])
- for u in value(x) do :
- print(" ")
- println-all(u)
- println(" end")
- println("`endif")
-
- println("endmodule")
-
-
-public defn emit-verilog (with-output:(() -> False) -> False, c:Circuit) :
- with-output $ fn () :
- for m in modules(c) do :
- match(m) :
- (m:InModule) : emit-module(m)
- (m:ExModule) : false
- c
diff --git a/src/main/stanza/widthsolver.stanza b/src/main/stanza/widthsolver.stanza
index 2b967f44..b3f72f03 100644
--- a/src/main/stanza/widthsolver.stanza
+++ b/src/main/stanza/widthsolver.stanza
@@ -1,3 +1,27 @@
+;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.
;Define the STANDALONE flag to run STANDALONE
#if-defined(STANDALONE) :
#include<"core/stringeater.stanza">