diff options
Diffstat (limited to 'src')
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"> |
