From 45946bba6942378970ae42502f7b2829c2d3c58f Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 6 Oct 2015 16:03:48 -0700 Subject: Added ability to test scala FIRRTL --- Makefile | 22 ++++++++++++--- build.sbt | 23 +++++++++++---- project/assembly.sbt | 1 + src/main/scala/firrtl/Test.scala | 61 ++++++++++++++++++++++++++++++++++++++++ test/parser/gcd.fir | 52 ++++++++++++++++++++++++++++++++++ utils/bin/firrtl-scala | 7 +++++ 6 files changed, 156 insertions(+), 10 deletions(-) create mode 100644 project/assembly.sbt create mode 100644 src/main/scala/firrtl/Test.scala create mode 100644 test/parser/gcd.fir create mode 100755 utils/bin/firrtl-scala diff --git a/Makefile b/Makefile index 3085bfaa..9e67e3e1 100644 --- a/Makefile +++ b/Makefile @@ -20,13 +20,13 @@ install-mac: cd src/lib/stanza && sudo ./stanza -platform os-x -install /usr/local/bin/stanza build-deploy: - cd $(firrtl_dir) && stanza -i firrtl-main.stanza -o $(root_dir)/utils/bin/firrtl + cd $(firrtl_dir) && stanza -i firrtl-main.stanza -o $(root_dir)/utils/bin/firrtl-stanza build: - cd $(firrtl_dir) && stanza -i firrtl-test-main.stanza -o $(root_dir)/utils/bin/firrtl + cd $(firrtl_dir) && stanza -i firrtl-test-main.stanza -o $(root_dir)/utils/bin/firrtl-stanza build-fast: - cd $(firrtl_dir) && stanza -i firrtl-test-main.stanza -o $(root_dir)/utils/bin/firrtl -flags OPTIMIZE + cd $(firrtl_dir) && stanza -i firrtl-test-main.stanza -o $(root_dir)/utils/bin/firrtl-stanza -flags OPTIMIZE check: cd $(test_dir) && lit -v . --path=$(root_dir)/utils/bin/ @@ -66,4 +66,18 @@ done: build check fail: say "fail" -.PHONY: all install build-deploy build check clean fail succeed regress +# Scala Added Makefile commands + +build-scala: + sbt "assembly" + +test-scala: + cd $(test_dir)/parser && lit -v . --path=$(root_dir)/utils/bin/ + +set-scala: + ln -f -s $(root_dir)/utils/bin/firrtl-scala $(root_dir)/utils/bin/firrtl + +set-stanza: + ln -f -s $(root_dir)/utils/bin/firrtl-stanza $(root_dir)/utils/bin/firrtl + +.PHONY: all install build-deploy build check clean fail succeed regress set-scala set-stanza build-scala diff --git a/build.sbt b/build.sbt index 0a083994..dcc38280 100644 --- a/build.sbt +++ b/build.sbt @@ -1,9 +1,20 @@ -lazy val root = (project in file(".")). - settings( - name := "firrtl", - version := "1.0", - scalaVersion := "2.11.4" - ) +organization := "edu.berkeley.cs" + +name := "firrtl" + +version := "0.1-SNAPSHOT" + +scalaVersion := "2.11.4" + +// Assembly + +assemblyJarName in assembly := "firrtl.jar" + +test in assembly := {} // Should there be tests? + +assemblyOutputPath in assembly := file("./utils/bin/firrtl.jar") + +// ANTLRv4 antlr4Settings diff --git a/project/assembly.sbt b/project/assembly.sbt new file mode 100644 index 00000000..a815d584 --- /dev/null +++ b/project/assembly.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.0") diff --git a/src/main/scala/firrtl/Test.scala b/src/main/scala/firrtl/Test.scala new file mode 100644 index 00000000..09329685 --- /dev/null +++ b/src/main/scala/firrtl/Test.scala @@ -0,0 +1,61 @@ +package firrtl + +import java.io._ +import Utils._ + +object Test +{ + private val usage = """ + Usage: java -jar firrtl.jar firrtl.Test [options] -i -o + """ + private val defaultOptions = Map[Symbol, Any]().withDefaultValue(false) + + // Parse input file and print to output + private def highFIRRTL(input: String, output: String) + { + val ast = Parser.parse(input) + val writer = new PrintWriter(new File(output)) + writer.write(ast.serialize) + writer.close() + } + + def main(args: Array[String]) + { + val arglist = args.toList + type OptionMap = Map[Symbol, Any] + + def nextOption(map: OptionMap, list: List[String]): OptionMap = { + def isSwitch(s: String) = (s(0) == '-') + list match { + case Nil => map + case "-X" :: value :: tail => + nextOption(map ++ Map('compiler -> value), tail) + //case "-d" :: tail => + // nextOption(map ++ Map('debug -> true), tail) + case "-i" :: value :: tail => + nextOption(map ++ Map('input -> value), tail) + case "-o" :: value :: tail => + nextOption(map ++ Map('output -> value), tail) + case option :: tail => + throw new Exception("Unknown option " + option) + } + } + val options = nextOption(defaultOptions, arglist) + println(options) + + val input = options('input) match { + case s: String => s + case false => throw new Exception("No input file provided!" + usage) + } + val output = options('output) match { + case s: String => s + case false => throw new Exception("No output file provided!" + usage) + } + + options('compiler) match { + case "Verilog" => throw new Exception("Verilog compiler not currently supported!") + case "HighFIRRTL" => highFIRRTL(input, output) + case other => throw new Exception("Invalid compiler! " + other) + } + } +} diff --git a/test/parser/gcd.fir b/test/parser/gcd.fir new file mode 100644 index 00000000..03eb6ba9 --- /dev/null +++ b/test/parser/gcd.fir @@ -0,0 +1,52 @@ +; RUN: firrtl -i %s -o %s.out -X HighFIRRTL && cat %s.out | FileCheck %s +circuit GCD : + module GCD : + input e : UInt<1> + input clk : Clock + input reset : UInt<1> + output z : UInt<16> + output v : UInt<1> + input a : UInt<16> + input b : UInt<16> + + reg x : UInt<16>,clk,reset + reg y : UInt<16>,clk,reset + node T_17 = gt(x, y) + when T_17 : + node T_18 = subw(x, y) + x := T_18 + else : + node T_19 = subw(y, x) + y := T_19 + when e : + x := a + y := b + z := x + node T_20 = eq(y, UInt<1>(0)) + v := T_20 + +; CHECK: circuit GCD : +; CHECK: module GCD : +; CHECK: input e : UInt<1> +; CHECK: input clk : Clock +; CHECK: input reset : UInt<1> +; CHECK: output z : UInt<16> +; CHECK: output v : UInt<1> +; CHECK: input a : UInt<16> +; CHECK: input b : UInt<16> +; CHECK: reg x : UInt<16>, clk, reset +; CHECK: reg y : UInt<16>, clk, reset +; CHECK: node T_17 = gt(x, y) +; CHECK: when T_17 : +; CHECK: node T_18 = subw(x, y) +; CHECK: x := T_18 +; CHECK: else : +; CHECK: node T_19 = subw(y, x) +; CHECK: y := T_19 +; CHECK: when e : +; CHECK: x := a +; CHECK: y := b +; CHECK: z := x +; CHECK: node T_20 = eq(y, UInt<1>("h00")) +; CHECK: v := T_20 + diff --git a/utils/bin/firrtl-scala b/utils/bin/firrtl-scala new file mode 100755 index 00000000..4d208178 --- /dev/null +++ b/utils/bin/firrtl-scala @@ -0,0 +1,7 @@ +#!/bin/bash + +# This may be a brittle way to find $(root_dir)/utils/bin, is there a better way? +path=`dirname "$0"` +cmd="java -cp ${path}/firrtl.jar firrtl.Test ${@:1}" +eval $cmd + -- cgit v1.2.3 From ac63917f4d6d22170db690542b55d636fbda608d Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 7 Oct 2015 15:31:16 -0700 Subject: Added utility map functions Stmt -> Stmt, S; Exp -> Exp, S; Exp -> Exp, E --- build.sbt | 14 +++++++----- src/main/scala/firrtl/Utils.scala | 46 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index dcc38280..f363d4cf 100644 --- a/build.sbt +++ b/build.sbt @@ -1,14 +1,18 @@ -organization := "edu.berkeley.cs" -name := "firrtl" -version := "0.1-SNAPSHOT" +lazy val root = (project in file(".")). + settings( + organization := "edu.berkeley.cs", + name := "firrtl", + version := "0.1-SNAPSHOT", + scalaVersion := "2.11.4" + ) -scalaVersion := "2.11.4" +libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value // Assembly -assemblyJarName in assembly := "firrtl.jar" +//assemblyJarName in assembly := "firrtl.jar" test in assembly := {} // Should there be tests? diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala index 916408bc..37cdcc71 100644 --- a/src/main/scala/firrtl/Utils.scala +++ b/src/main/scala/firrtl/Utils.scala @@ -2,14 +2,16 @@ /* TODO * - Adopt style more similar to Chisel3 Emitter? + * - Find way to have generic map function instead of mapE and mapS under Stmt implicits */ package firrtl import scala.collection.mutable.StringBuilder +import scala.reflect.runtime.universe._ object Utils { - + implicit class BigIntUtils(bi: BigInt){ def serialize(): String = "\"h0" + bi.toString(16) + "\"" @@ -68,6 +70,14 @@ object Utils { case p: DoPrimOp => s"${p.op.serialize}(" + (p.args.map(_.serialize) ++ p.consts.map(_.toString)).mkString(", ") + ")" } + + def map(f: Exp => Exp): Exp = + exp match { + case s: Subfield => Subfield(f(s.exp), s.name, s.tpe) + case s: Subindex => Subindex(f(s.exp), s.value) + case p: DoPrimOp => DoPrimOp(p.op, p.args.map(f), p.consts) + case e: Exp => e + } } // AccessorDir @@ -81,6 +91,36 @@ object Utils { } } + // 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: When => When(w.info, w.pred, f(w.conseq), f(w.alt)) + case b: Block => Block(b.stmts.map(f)) + case s: Stmt => s + } + } + implicit def forExp(f: Exp => Exp) = new StmtMagnet { + override def map(stmt: Stmt): Stmt = + stmt match { + case r: DefReg => DefReg(r.info, r.name, r.tpe, f(r.clock), f(r.reset)) + case m: DefMemory => DefMemory(m.info, m.name, m.seq, m.tpe, f(m.clock)) + case i: DefInst => DefInst(i.info, i.name, f(i.module)) + case n: DefNode => DefNode(n.info, n.name, f(n.value)) + case a: DefAccessor => DefAccessor(a.info, a.name, a.dir, f(a.source), f(a.index)) + case o: OnReset => OnReset(o.info, f(o.lhs), f(o.rhs)) + case c: Connect => Connect(c.info, f(c.lhs), f(c.rhs)) + case b: BulkConnect => BulkConnect(b.info, f(b.lhs), f(b.rhs)) + case w: When => When(w.info, f(w.pred), w.conseq, w.alt) + case a: Assert => Assert(a.info, f(a.pred)) + case s: Stmt => s + } + } + } implicit class StmtUtils(stmt: Stmt) { def serialize(): String = @@ -114,6 +154,10 @@ object Utils { case a: Assert => s"assert ${a.pred.serialize}" case EmptyStmt => "skip" } + + // 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) + } implicit class WidthUtils(w: Width) { -- cgit v1.2.3 From d1295b29d89e07645c3a4e08f2f923455a868482 Mon Sep 17 00:00:00 2001 From: Jack Date: Mon, 12 Oct 2015 16:16:15 -0700 Subject: Added FIRRTL comment removal to Translator --- src/main/scala/firrtl/Translator.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/firrtl/Translator.scala b/src/main/scala/firrtl/Translator.scala index eba78b39..a16d89d7 100644 --- a/src/main/scala/firrtl/Translator.scala +++ b/src/main/scala/firrtl/Translator.scala @@ -21,6 +21,7 @@ object Translator def addBrackets(inputIt: Iterator[String]): StringBuilder = { def countSpaces(s: String): Int = s.prefixLength(_ == ' ') + def stripComments(s: String): String = s takeWhile (!";".contains(_)) val Scopers = """\s*(circuit|module|when|else)(.*)""".r @@ -45,7 +46,8 @@ object Translator var newScope = true // indicates if increasing scope spacing is legal on next line while( it.hasNext ) { - it.next match { case (text, lineNum) => + it.next match { case (lineText, lineNum) => + val text = stripComments(lineText) val spaces = countSpaces(text) val l = if (text.length > spaces ) { // Check that line has text in it -- cgit v1.2.3 From 0c288c48382f1b31fbfb1c202867fb444e46136c Mon Sep 17 00:00:00 2001 From: Jack Date: Mon, 12 Oct 2015 16:45:21 -0700 Subject: Added support for no width to mean unknown, and print nothing instead of for unknown width. Also added test to check this --- src/main/antlr4/FIRRTL.g4 | 12 ++++------- src/main/scala/firrtl/IR.scala | 4 ++-- src/main/scala/firrtl/Utils.scala | 12 +++++------ src/main/scala/firrtl/Visitor.scala | 18 ++++++++++++---- test/parser/bundle.fir | 43 +++++++++++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 20 deletions(-) create mode 100644 test/parser/bundle.fir diff --git a/src/main/antlr4/FIRRTL.g4 b/src/main/antlr4/FIRRTL.g4 index 08697bb1..d9f3d18f 100644 --- a/src/main/antlr4/FIRRTL.g4 +++ b/src/main/antlr4/FIRRTL.g4 @@ -1,7 +1,3 @@ -// Jack Koenig -// UC Berkeley ASPIRE Lab -// July 9, 2015 - grammar FIRRTL; /*------------------------------------------------------------------ @@ -33,8 +29,8 @@ portKind ; type - : 'UInt' '<' width '>' - | 'SInt' '<' width '>' + : 'UInt' ('<' width '>')? + | 'SInt' ('<' width '>')? | 'Clock' | '{' field* '}' // Bundle | type '[' IntLit ']' // Vector @@ -93,8 +89,8 @@ dir // TODO implement // What is exp? exp - : 'UInt' '<' width '>' '(' (IntLit) ')' // FIXME what does "ints" mean? - | 'SInt' '<' width '>' '(' (IntLit) ')' // FIXME same + : 'UInt' ('<' width '>')? '(' (IntLit) ')' // FIXME what does "ints" mean? + | 'SInt' ('<' width '>')? '(' (IntLit) ')' // FIXME same | id // Ref | exp '.' id // FIXME Does this work for no space? | exp '[' IntLit ']' diff --git a/src/main/scala/firrtl/IR.scala b/src/main/scala/firrtl/IR.scala index c52c45a4..876e8641 100644 --- a/src/main/scala/firrtl/IR.scala +++ b/src/main/scala/firrtl/IR.scala @@ -50,8 +50,8 @@ case object Bits extends PrimOp // Add types, default to UNKNOWN // TODO add type trait Exp extends AST -case class UIntValue(value: BigInt, width: BigInt) extends Exp -case class SIntValue(value: BigInt, width: BigInt) extends Exp +case class UIntValue(value: BigInt, width: Width) extends Exp +case class SIntValue(value: BigInt, width: Width) extends Exp case class Ref(name: String, tpe: Type) extends Exp case class Subfield(exp: Exp, name: String, tpe: Type) extends Exp case class Subindex(exp: Exp, value: BigInt) extends Exp diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala index 37cdcc71..8a7a5b0d 100644 --- a/src/main/scala/firrtl/Utils.scala +++ b/src/main/scala/firrtl/Utils.scala @@ -62,8 +62,8 @@ object Utils { implicit class ExpUtils(exp: Exp) { def serialize(): String = exp match { - case v: UIntValue => s"UInt<${v.width}>(${v.value.serialize})" - case v: SIntValue => s"SInt<${v.width}>(${v.value.serialize})" + 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}]" @@ -163,8 +163,8 @@ object Utils { implicit class WidthUtils(w: Width) { def serialize(): String = w match { - case UnknownWidth => "?" - case w: IntWidth => w.width.toString + case UnknownWidth => "" + case w: IntWidth => s"<${w.width.toString}>" } } @@ -187,8 +187,8 @@ object Utils { t match { case ClockType => "Clock" case UnknownType => "UnknownType" - case t: UIntType => s"UInt<${t.width.serialize}>" - case t: SIntType => s"SInt<${t.width.serialize}>" + 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}]" } diff --git a/src/main/scala/firrtl/Visitor.scala b/src/main/scala/firrtl/Visitor.scala index 276facce..879ce80d 100644 --- a/src/main/scala/firrtl/Visitor.scala +++ b/src/main/scala/firrtl/Visitor.scala @@ -3,6 +3,7 @@ * - Support all integer types (not just "h...") * - In ANTLR examples they use just visit, why am I having to use visitModule or other specific functions? * - Make visit private? + * - More elegant way to insert UnknownWidth? */ package firrtl @@ -58,8 +59,10 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST] // Match on a type instead of on strings? private def visitType[AST](ctx: FIRRTLParser.TypeContext): Type = { ctx.getChild(0).getText match { - case "UInt" => UIntType( visitWidth(ctx.width) ) - case "SInt" => SIntType( visitWidth(ctx.width) ) + case "UInt" => if (ctx.getChildCount > 1) UIntType( visitWidth(ctx.width) ) + else UIntType( UnknownWidth ) + case "SInt" => if (ctx.getChildCount > 1) SIntType( visitWidth(ctx.width) ) + else SIntType( UnknownWidth ) case "Clock" => ClockType case "{" => BundleType(ctx.field.map(visitField)) case _ => new VectorType( visitType(ctx.`type`), string2BigInt(ctx.IntLit.getText) ) @@ -132,8 +135,15 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST] Ref(ctx.getText, UnknownType) else ctx.getChild(0).getText match { - case "UInt" => UIntValue(string2BigInt(ctx.IntLit(0).getText), string2BigInt(ctx.width.getText)) - case "SInt" => SIntValue(string2BigInt(ctx.IntLit(0).getText), string2BigInt(ctx.width.getText)) + case "UInt" => { + val width = if (ctx.getChildCount > 4) visitWidth(ctx.width) else UnknownWidth + UIntValue(string2BigInt(ctx.IntLit(0).getText), width) + } + //case "SInt" => SIntValue(string2BigInt(ctx.IntLit(0).getText), string2BigInt(ctx.width.getText)) + case "SInt" => { + val width = if (ctx.getChildCount > 4) visitWidth(ctx.width) else UnknownWidth + SIntValue(string2BigInt(ctx.IntLit(0).getText), width) + } case _ => ctx.getChild(1).getText match { case "." => new Subfield(visitExp(ctx.exp(0)), ctx.id.getText, UnknownType) diff --git a/test/parser/bundle.fir b/test/parser/bundle.fir new file mode 100644 index 00000000..15fa26d0 --- /dev/null +++ b/test/parser/bundle.fir @@ -0,0 +1,43 @@ +; RUN: firrtl -i %s -o %s.out -X HighFIRRTL && cat %s.out | FileCheck %s +circuit top : + module top : + wire z : { x : UInt, flip y: SInt} + z.x := UInt(1) + z.y := SInt(1) + node x = z.x + node y = z.y + wire a : UInt<3>[10] + a[0] := UInt(1) + a[1] := UInt(1) + a[2] := UInt(1) + a[3] := UInt(1) + a[4] := UInt(1) + a[5] := UInt(1) + a[6] := UInt(1) + a[7] := UInt(1) + a[8] := UInt(1) + a[9] := UInt(1) + node b = a[2] + read accessor c = a[UInt(3)] + +; CHECK: circuit top : +; CHECK: module top : +; CHECK: wire z : { x : UInt, flip y : SInt } +; CHECK: z.x := UInt("h01") +; CHECK: z.y := SInt("h01") +; CHECK: node x = z.x +; CHECK: node y = z.y +; CHECK: wire a : UInt<3>[10] +; CHECK: a[0] := UInt("h01") +; CHECK: a[1] := UInt("h01") +; CHECK: a[2] := UInt("h01") +; CHECK: a[3] := UInt("h01") +; CHECK: a[4] := UInt("h01") +; CHECK: a[5] := UInt("h01") +; CHECK: a[6] := UInt("h01") +; CHECK: a[7] := UInt("h01") +; CHECK: a[8] := UInt("h01") +; CHECK: a[9] := UInt("h01") +; CHECK: node b = a[2] +; CHECK: read accessor c = a[UInt("h03")] + -- cgit v1.2.3 From 09ef2e42b00174e99124477b443a472e8664708f Mon Sep 17 00:00:00 2001 From: Jack Date: Mon, 12 Oct 2015 16:56:08 -0700 Subject: Renamed Subindex to Index and added type information to Index and DoPrimOp --- src/main/scala/firrtl/IR.scala | 4 ++-- src/main/scala/firrtl/Utils.scala | 6 +++--- src/main/scala/firrtl/Visitor.scala | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/scala/firrtl/IR.scala b/src/main/scala/firrtl/IR.scala index 876e8641..7905612e 100644 --- a/src/main/scala/firrtl/IR.scala +++ b/src/main/scala/firrtl/IR.scala @@ -54,8 +54,8 @@ case class UIntValue(value: BigInt, width: Width) extends Exp case class SIntValue(value: BigInt, width: Width) extends Exp case class Ref(name: String, tpe: Type) extends Exp case class Subfield(exp: Exp, name: String, tpe: Type) extends Exp -case class Subindex(exp: Exp, value: BigInt) extends Exp -case class DoPrimOp(op: PrimOp, args: Seq[Exp], consts: Seq[BigInt]) extends Exp +case class Index(exp: Exp, value: BigInt, tpe: Type) extends Exp +case class DoPrimOp(op: PrimOp, args: Seq[Exp], consts: Seq[BigInt], tpe: Type) extends Exp trait AccessorDir extends AST case object Infer extends AccessorDir diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala index 8a7a5b0d..110da9a5 100644 --- a/src/main/scala/firrtl/Utils.scala +++ b/src/main/scala/firrtl/Utils.scala @@ -66,7 +66,7 @@ object Utils { 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: Index => s"${s.exp.serialize}[${s.value}]" case p: DoPrimOp => s"${p.op.serialize}(" + (p.args.map(_.serialize) ++ p.consts.map(_.toString)).mkString(", ") + ")" } @@ -74,8 +74,8 @@ object Utils { def map(f: Exp => Exp): Exp = exp match { case s: Subfield => Subfield(f(s.exp), s.name, s.tpe) - case s: Subindex => Subindex(f(s.exp), s.value) - case p: DoPrimOp => DoPrimOp(p.op, p.args.map(f), p.consts) + case i: Index => Index(f(i.exp), i.value, i.tpe) + case p: DoPrimOp => DoPrimOp(p.op, p.args.map(f), p.consts, p.tpe) case e: Exp => e } } diff --git a/src/main/scala/firrtl/Visitor.scala b/src/main/scala/firrtl/Visitor.scala index 879ce80d..8bbed2e3 100644 --- a/src/main/scala/firrtl/Visitor.scala +++ b/src/main/scala/firrtl/Visitor.scala @@ -147,9 +147,10 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST] case _ => ctx.getChild(1).getText match { case "." => new Subfield(visitExp(ctx.exp(0)), ctx.id.getText, UnknownType) - case "[" => new Subindex(visitExp(ctx.exp(0)), string2BigInt(ctx.IntLit(0).getText)) + case "[" => new Index(visitExp(ctx.exp(0)), string2BigInt(ctx.IntLit(0).getText), UnknownType) case "(" => - DoPrimOp(visitPrimop(ctx.primop), ctx.exp.map(visitExp), ctx.IntLit.map(x => string2BigInt(x.getText))) + DoPrimOp(visitPrimop(ctx.primop), ctx.exp.map(visitExp), + ctx.IntLit.map(x => string2BigInt(x.getText)), UnknownType) } } -- cgit v1.2.3 From bf4488870e1def4d76297dd8fdd795a82bc4ded3 Mon Sep 17 00:00:00 2001 From: Jack Date: Mon, 12 Oct 2015 17:38:12 -0700 Subject: Added initial support for debug printing for lit based testing, most types of printVars still missing. Added Logger class for debug printing --- src/main/scala/firrtl/Logger.scala | 59 ++++++++++++++++ src/main/scala/firrtl/Test.scala | 60 ++++++++++++++--- src/main/scala/firrtl/Utils.scala | 135 +++++++++++++++++++++++++++++-------- 3 files changed, 219 insertions(+), 35 deletions(-) create mode 100644 src/main/scala/firrtl/Logger.scala diff --git a/src/main/scala/firrtl/Logger.scala b/src/main/scala/firrtl/Logger.scala new file mode 100644 index 00000000..85969307 --- /dev/null +++ b/src/main/scala/firrtl/Logger.scala @@ -0,0 +1,59 @@ +package firrtl + +import java.io.PrintWriter +import Utils._ + +class Logger private ( + writer: PrintWriter, + printMode: Symbol, + printVars: List[Symbol]){ + + // Legal printModes: 'none, 'error, 'warn, 'info, 'debug, 'trace + require(List('none, 'error, 'warn, 'info, 'debug, 'trace) contains printMode) + val errorEnable = List('error, 'warn, 'info, 'debug, 'trace) contains printMode + val warnEnable = List('warn, 'info, 'debug, 'trace) contains printMode + val infoEnable = List('info, 'debug, 'trace) contains printMode + val debugEnable = List('debug, 'trace) contains printMode + val traceEnable = List('trace) contains printMode + val circuitEnable = printVars contains 'circuit + val debugFlags = printVars.map(_ -> true).toMap.withDefaultValue(false) + + def error(message: => String){ + if (errorEnable) writer.println(message.split("\n").map("[error] " + _).mkString("\n")) + } + def warn(message: => String){ + if (warnEnable) writer.println(message.split("\n").map("[warn] " + _).mkString("\n")) + } + def info(message: => String){ + if (infoEnable) writer.println(message.split("\n").map("[info] " + _).mkString("\n")) + } + def debug(message: => String){ + if (debugEnable) writer.println(message.split("\n").map("[debug] " + _).mkString("\n")) + } + def trace(message: => String){ + if (traceEnable) writer.println(message.split("\n").map("[trace] " + _).mkString("\n")) + } + + def printType(node: => AST){ + val tpe = node.getType + if( tpe.nonEmpty ) this.debug(s"@") + } + + def printDebug(circuit: Circuit){ + if (circuitEnable) this.debug(circuit.serialize(debugFlags)) + } + // Used if not autoflushing + def flush() = writer.flush() + +} + +object Logger +{ + def apply(writer: PrintWriter): Logger = + new Logger(writer, 'warn, List()) + def apply(writer: PrintWriter, printMode: Symbol): Logger = + new Logger(writer, printMode, List()) + def apply(writer: PrintWriter, printMode: Symbol, printVars: List[Symbol]): Logger = + new Logger(writer, printMode, printVars) + def apply(): Logger = new Logger(null, 'none, List()) +} diff --git a/src/main/scala/firrtl/Test.scala b/src/main/scala/firrtl/Test.scala index 09329685..b1e45762 100644 --- a/src/main/scala/firrtl/Test.scala +++ b/src/main/scala/firrtl/Test.scala @@ -6,17 +6,18 @@ import Utils._ object Test { private val usage = """ - Usage: java -jar firrtl.jar firrtl.Test [options] -i -o + Usage: java -cp utils/bin/firrtl.jar firrtl.Test [options] -i -o """ private val defaultOptions = Map[Symbol, Any]().withDefaultValue(false) // Parse input file and print to output - private def highFIRRTL(input: String, output: String) + private def highFIRRTL(input: String, output: String, logger: Logger) { val ast = Parser.parse(input) val writer = new PrintWriter(new File(output)) - writer.write(ast.serialize) + writer.write(ast.serialize()) writer.close() + logger.printDebug(ast) } def main(args: Array[String]) @@ -24,24 +25,54 @@ object Test val arglist = args.toList type OptionMap = Map[Symbol, Any] + // Default debug mode is 'debug + def decodeDebugMode(mode: Any): Symbol = + mode match { + case s: String => Symbol(s) + case _ => 'debug + } + + def nextPrintVar(syms: List[Symbol], chars: List[Char]): List[Symbol] = + chars match { + case Nil => syms + case 't' :: tail => nextPrintVar(syms ++ List('types), tail) + case 'k' :: tail => nextPrintVar(syms ++ List('kinds), tail) + case 'w' :: tail => nextPrintVar(syms ++ List('widths), tail) + case 'T' :: tail => nextPrintVar(syms ++ List('twidths), tail) + case 'g' :: tail => nextPrintVar(syms ++ List('genders), tail) + case 'c' :: tail => nextPrintVar(syms ++ List('circuit), tail) + case 'd' :: tail => nextPrintVar(syms ++ List('debug), tail) // Currently ignored + case 'i' :: tail => nextPrintVar(syms ++ List('info), tail) + case char :: tail => throw new Exception("Unknown print option " + char) + } + def nextOption(map: OptionMap, list: List[String]): OptionMap = { - def isSwitch(s: String) = (s(0) == '-') list match { case Nil => map case "-X" :: value :: tail => nextOption(map ++ Map('compiler -> value), tail) - //case "-d" :: tail => - // nextOption(map ++ Map('debug -> true), tail) + case "-d" :: value :: tail => + nextOption(map ++ Map('debugMode -> value), tail) + case "-l" :: value :: tail => + nextOption(map ++ Map('log -> value), tail) + case "-p" :: value :: tail => + nextOption(map ++ Map('printVars -> value), tail) case "-i" :: value :: tail => nextOption(map ++ Map('input -> value), tail) case "-o" :: value :: tail => nextOption(map ++ Map('output -> value), tail) + case ("-h" | "--help") :: tail => + nextOption(map ++ Map('help -> true), tail) case option :: tail => throw new Exception("Unknown option " + option) } } val options = nextOption(defaultOptions, arglist) - println(options) + + if (options('help) == true) { + println(usage) + System.exit(0) + } val input = options('input) match { case s: String => s @@ -51,10 +82,23 @@ object Test case s: String => s case false => throw new Exception("No output file provided!" + usage) } + val debugMode = decodeDebugMode(options('debugMode)) + val printVars = options('printVars) match { + case s: String => nextPrintVar(List(), s.toList) + case false => List() + } + implicit val logger = options('log) match { + case s: String => Logger(new PrintWriter(new FileOutputStream(s)), debugMode, printVars) + case false => Logger(new PrintWriter(System.out, true), debugMode, printVars) + } + + // -p "printVars" options only print for debugMode > 'debug, warn if -p enabled and debugMode < 'debug + if( !logger.debugEnable && !printVars.isEmpty ) + logger.warn("-p options will not print unless debugMode (-d) is debug or trace") options('compiler) match { case "Verilog" => throw new Exception("Verilog compiler not currently supported!") - case "HighFIRRTL" => highFIRRTL(input, output) + case "HighFIRRTL" => highFIRRTL(input, output, logger) case other => throw new Exception("Invalid compiler! " + other) } } diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala index 110da9a5..b50bd7b5 100644 --- a/src/main/scala/firrtl/Utils.scala +++ b/src/main/scala/firrtl/Utils.scala @@ -8,17 +8,47 @@ package firrtl import scala.collection.mutable.StringBuilder -import scala.reflect.runtime.universe._ +//import scala.reflect.runtime.universe._ object Utils { + // 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.nonEmpty ) str += s"@" + } + str + } + else { + "" + } + } + implicit class BigIntUtils(bi: BigInt){ - def serialize(): String = + def serialize(implicit flags: FlagMap = FlagMap): String = "\"h0" + bi.toString(16) + "\"" } + implicit class ASTUtils(ast: AST) { + def getType(): Option[Type] = + ast match { + case e: Exp => e.getType + case s: Stmt => s.getType + case f: Field => f.getType + case t: Type => t.getType + case p: Port => p.getType + case _ => None + } + } + implicit class PrimOpUtils(op: PrimOp) { - def serialize(): String = { + def serialize(implicit flags: FlagMap = FlagMap): String = { op match { case Add => "add" case Sub => "sub" @@ -60,8 +90,8 @@ object Utils { } implicit class ExpUtils(exp: Exp) { - def serialize(): String = - exp match { + 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 @@ -70,6 +100,8 @@ object Utils { case p: DoPrimOp => s"${p.op.serialize}(" + (p.args.map(_.serialize) ++ p.consts.map(_.toString)).mkString(", ") + ")" } + ret + debug(exp) + } def map(f: Exp => Exp): Exp = exp match { @@ -78,11 +110,23 @@ object Utils { case p: DoPrimOp => DoPrimOp(p.op, p.args.map(f), p.consts, p.tpe) case e: Exp => e } + + def getType(): Option[Type] = { + exp match { + case v: UIntValue => Option(UIntType(UnknownWidth)) + case v: SIntValue => Option(SIntType(UnknownWidth)) + case r: Ref => Option(r.tpe) + case s: Subfield => Option(s.tpe) + case i: Index => Option(i.tpe) + case p: DoPrimOp => Option(p.tpe) + case e: Exp => None + } + } } // AccessorDir implicit class AccessorDirUtils(dir: AccessorDir) { - def serialize(): String = + def serialize(implicit flags: FlagMap = FlagMap): String = dir match { case Infer => "infer" case Read => "read" @@ -123,8 +167,9 @@ object Utils { } implicit class StmtUtils(stmt: Stmt) { - def serialize(): String = - stmt match { + def serialize(implicit flags: FlagMap = FlagMap): String = + { + var ret = stmt match { case w: DefWire => s"wire ${w.name} : ${w.tpe.serialize}" case r: DefReg => s"reg ${r.name} : ${r.tpe.serialize}, ${r.clock.serialize}, ${r.reset.serialize}" case m: DefMemory => (if(m.seq) "smem" else "cmem") + @@ -149,82 +194,118 @@ object Utils { case b: Block => { val s = new StringBuilder b.stmts.foreach { s ++= newline ++ _.serialize } - s.result - } + s.result + debug(b) + } case a: Assert => s"assert ${a.pred.serialize}" case EmptyStmt => "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(): Option[Type] = + stmt match { + case w: DefWire => Option(w.tpe) + case r: DefReg => Option(r.tpe) + case m: DefMemory => Option(m.tpe) + case p: DefPoison => Option(p.tpe) + case s: Stmt => None + } } implicit class WidthUtils(w: Width) { - def serialize(): String = - w match { - case UnknownWidth => "" + 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 FieldDirUtils(dir: FieldDir) { - def serialize(): String = - dir match { + def serialize(implicit flags: FlagMap = FlagMap): String = { + val s = dir match { case Reverse => "flip " case Default => "" } + s + debug(dir) + } } implicit class FieldUtils(field: Field) { - def serialize(): String = - s"${field.dir.serialize} ${field.name} : ${field.tpe.serialize}" + def serialize(implicit flags: FlagMap = FlagMap): String = + s"${field.dir.serialize} ${field.name} : ${field.tpe.serialize}" + debug(field) + + def getType(): Option[Type] = Option(field.tpe) } implicit class TypeUtils(t: Type) { - def serialize(): String = { + def serialize(implicit flags: FlagMap = FlagMap): String = { val commas = ", " // for mkString in BundleType - t match { + val s = t match { case ClockType => "Clock" - case UnknownType => "UnknownType" + //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) } + + // TODO how does this work? + def getType(): Option[Type] = + t match { + case v: VectorType => Option(v.tpe) + case tpe: Type => None + } + + def wipeWidth(): Type = + t match { + case t: UIntType => UIntType(UnknownWidth) + case t: SIntType => SIntType(UnknownWidth) + case _ => t + } } implicit class PortDirUtils(p: PortDir) { - def serialize(): String = - p match { + def serialize(implicit flags: FlagMap = FlagMap): String = { + val s = p match { case Input => "input" case Output => "output" } + s + debug(p) + } } implicit class PortUtils(p: Port) { - def serialize(): String = - s"${p.dir.serialize} ${p.name} : ${p.tpe.serialize}" + def serialize(implicit flags: FlagMap = FlagMap): String = + s"${p.dir.serialize} ${p.name} : ${p.tpe.serialize}" + debug(p) + def getType(): Option[Type] = Option(p.tpe) } implicit class ModuleUtils(m: Module) { - def serialize(): String = { + def serialize(implicit flags: FlagMap = FlagMap): String = { var s = new StringBuilder(s"module ${m.name} : ") withIndent { s ++= m.ports.map(newline ++ _.serialize).mkString s ++= newline ++ m.stmt.serialize } + s ++= debug(m) s.toString } } implicit class CircuitUtils(c: Circuit) { - def serialize(): String = { + def serialize(implicit flags: FlagMap = FlagMap): String = { var s = new StringBuilder(s"circuit ${c.name} : ") - //withIndent { c.modules.foreach(s ++= newline ++ newline ++ _.serialize) } withIndent { s ++= newline ++ c.modules.map(_.serialize).mkString(newline + newline) } s ++= newline ++ newline + s ++= debug(c) s.toString } } -- cgit v1.2.3 From 9b737de6551e7446dfd92d86cd009b4b2f95c980 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 14 Oct 2015 13:53:22 -0700 Subject: Moved Logger to new private object DebugUtils, changed UInt/SInt value printing to match stanza implementation --- src/main/scala/firrtl/DebugUtils.scala | 63 ++++++++++++++++++++++++++++++++++ src/main/scala/firrtl/Logger.scala | 59 ------------------------------- src/main/scala/firrtl/Test.scala | 32 ++++++++++++++--- src/main/scala/firrtl/Utils.scala | 2 +- test/parser/bundle.fir | 26 +++++++------- test/parser/gcd.fir | 2 +- 6 files changed, 106 insertions(+), 78 deletions(-) create mode 100644 src/main/scala/firrtl/DebugUtils.scala delete mode 100644 src/main/scala/firrtl/Logger.scala diff --git a/src/main/scala/firrtl/DebugUtils.scala b/src/main/scala/firrtl/DebugUtils.scala new file mode 100644 index 00000000..80c0d240 --- /dev/null +++ b/src/main/scala/firrtl/DebugUtils.scala @@ -0,0 +1,63 @@ +// Private implicit classes and other utility functions for debugging + +package firrtl + +import java.io.PrintWriter +import Utils._ + +private object DebugUtils { + + + /** Private class for recording and organizing debug information */ + class Logger private ( + writer: PrintWriter, + printMode: Symbol, + printVars: List[Symbol]){ + + // Legal printModes: 'none, 'error, 'warn, 'info, 'debug, 'trace + require(List('none, 'error, 'warn, 'info, 'debug, 'trace) contains printMode) + val errorEnable = List('error, 'warn, 'info, 'debug, 'trace) contains printMode + val warnEnable = List('warn, 'info, 'debug, 'trace) contains printMode + val infoEnable = List('info, 'debug, 'trace) contains printMode + val debugEnable = List('debug, 'trace) contains printMode + val traceEnable = List('trace) contains printMode + val circuitEnable = printVars contains 'circuit + val debugFlags = printVars.map(_ -> true).toMap.withDefaultValue(false) + + def error(message: => String){ + if (errorEnable) writer.println(message.split("\n").map("[error] " + _).mkString("\n")) + } + def warn(message: => String){ + if (warnEnable) writer.println(message.split("\n").map("[warn] " + _).mkString("\n")) + } + def info(message: => String){ + if (infoEnable) writer.println(message.split("\n").map("[info] " + _).mkString("\n")) + } + def debug(message: => String){ + if (debugEnable) writer.println(message.split("\n").map("[debug] " + _).mkString("\n")) + } + def trace(message: => String){ + if (traceEnable) writer.println(message.split("\n").map("[trace] " + _).mkString("\n")) + } + def printDebug(circuit: Circuit){ + if (circuitEnable) this.debug(circuit.serialize(debugFlags)) + } + // Used if not autoflushing + def flush() = writer.flush() + + } + /** Factory object for logger + * + * Logger records and organizes debug information + */ + object Logger + { + def apply(writer: PrintWriter): Logger = + new Logger(writer, 'warn, List()) + def apply(writer: PrintWriter, printMode: Symbol): Logger = + new Logger(writer, printMode, List()) + def apply(writer: PrintWriter, printMode: Symbol, printVars: List[Symbol]): Logger = + new Logger(writer, printMode, printVars) + def apply(): Logger = new Logger(null, 'none, List()) + } +} diff --git a/src/main/scala/firrtl/Logger.scala b/src/main/scala/firrtl/Logger.scala deleted file mode 100644 index 85969307..00000000 --- a/src/main/scala/firrtl/Logger.scala +++ /dev/null @@ -1,59 +0,0 @@ -package firrtl - -import java.io.PrintWriter -import Utils._ - -class Logger private ( - writer: PrintWriter, - printMode: Symbol, - printVars: List[Symbol]){ - - // Legal printModes: 'none, 'error, 'warn, 'info, 'debug, 'trace - require(List('none, 'error, 'warn, 'info, 'debug, 'trace) contains printMode) - val errorEnable = List('error, 'warn, 'info, 'debug, 'trace) contains printMode - val warnEnable = List('warn, 'info, 'debug, 'trace) contains printMode - val infoEnable = List('info, 'debug, 'trace) contains printMode - val debugEnable = List('debug, 'trace) contains printMode - val traceEnable = List('trace) contains printMode - val circuitEnable = printVars contains 'circuit - val debugFlags = printVars.map(_ -> true).toMap.withDefaultValue(false) - - def error(message: => String){ - if (errorEnable) writer.println(message.split("\n").map("[error] " + _).mkString("\n")) - } - def warn(message: => String){ - if (warnEnable) writer.println(message.split("\n").map("[warn] " + _).mkString("\n")) - } - def info(message: => String){ - if (infoEnable) writer.println(message.split("\n").map("[info] " + _).mkString("\n")) - } - def debug(message: => String){ - if (debugEnable) writer.println(message.split("\n").map("[debug] " + _).mkString("\n")) - } - def trace(message: => String){ - if (traceEnable) writer.println(message.split("\n").map("[trace] " + _).mkString("\n")) - } - - def printType(node: => AST){ - val tpe = node.getType - if( tpe.nonEmpty ) this.debug(s"@") - } - - def printDebug(circuit: Circuit){ - if (circuitEnable) this.debug(circuit.serialize(debugFlags)) - } - // Used if not autoflushing - def flush() = writer.flush() - -} - -object Logger -{ - def apply(writer: PrintWriter): Logger = - new Logger(writer, 'warn, List()) - def apply(writer: PrintWriter, printMode: Symbol): Logger = - new Logger(writer, printMode, List()) - def apply(writer: PrintWriter, printMode: Symbol, printVars: List[Symbol]): Logger = - new Logger(writer, printMode, printVars) - def apply(): Logger = new Logger(null, 'none, List()) -} diff --git a/src/main/scala/firrtl/Test.scala b/src/main/scala/firrtl/Test.scala index b1e45762..86c3616a 100644 --- a/src/main/scala/firrtl/Test.scala +++ b/src/main/scala/firrtl/Test.scala @@ -2,6 +2,7 @@ package firrtl import java.io._ import Utils._ +import DebugUtils._ object Test { @@ -11,7 +12,7 @@ object Test private val defaultOptions = Map[Symbol, Any]().withDefaultValue(false) // Parse input file and print to output - private def highFIRRTL(input: String, output: String, logger: Logger) + private def highFIRRTL(input: String, output: String)(implicit logger: Logger) { val ast = Parser.parse(input) val writer = new PrintWriter(new File(output)) @@ -19,6 +20,21 @@ object Test writer.close() logger.printDebug(ast) } + private def verilog(input: String, output: String)(implicit logger: Logger) + { + logger.warn("Verilog compiler not fully implemented") + val ast = time("parse"){ Parser.parse(input) } + // Execute passes + //val ast2 = time("inferTypes"){ inferTypes(ast) } + val ast2 = ast + + // Output + val writer = new PrintWriter(new File(output)) + var outString = time("serialize"){ ast2.serialize() } + writer.write(outString) + writer.close() + logger.printDebug(ast2) + } def main(args: Array[String]) { @@ -89,7 +105,7 @@ object Test } implicit val logger = options('log) match { case s: String => Logger(new PrintWriter(new FileOutputStream(s)), debugMode, printVars) - case false => Logger(new PrintWriter(System.out, true), debugMode, printVars) + case false => Logger(new PrintWriter(System.err, true), debugMode, printVars) } // -p "printVars" options only print for debugMode > 'debug, warn if -p enabled and debugMode < 'debug @@ -97,9 +113,17 @@ object Test logger.warn("-p options will not print unless debugMode (-d) is debug or trace") options('compiler) match { - case "Verilog" => throw new Exception("Verilog compiler not currently supported!") - case "HighFIRRTL" => highFIRRTL(input, output, logger) + case "verilog" => verilog(input, output) + case "HighFIRRTL" => highFIRRTL(input, output) case other => throw new Exception("Invalid compiler! " + other) } } + + def time[R](str: String)(block: => R)(implicit logger: Logger): R = { + val t0 = System.currentTimeMillis() + val result = block // call-by-name + val t1 = System.currentTimeMillis() + logger.info(s"Time to ${str}: ${t1 - t0} ms") + result + } } diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala index b50bd7b5..8e9889b9 100644 --- a/src/main/scala/firrtl/Utils.scala +++ b/src/main/scala/firrtl/Utils.scala @@ -32,7 +32,7 @@ object Utils { implicit class BigIntUtils(bi: BigInt){ def serialize(implicit flags: FlagMap = FlagMap): String = - "\"h0" + bi.toString(16) + "\"" + "\"h" + bi.toString(16) + "\"" } implicit class ASTUtils(ast: AST) { diff --git a/test/parser/bundle.fir b/test/parser/bundle.fir index 15fa26d0..c9f5e226 100644 --- a/test/parser/bundle.fir +++ b/test/parser/bundle.fir @@ -23,21 +23,21 @@ circuit top : ; CHECK: circuit top : ; CHECK: module top : ; CHECK: wire z : { x : UInt, flip y : SInt } -; CHECK: z.x := UInt("h01") -; CHECK: z.y := SInt("h01") +; CHECK: z.x := UInt("h1") +; CHECK: z.y := SInt("h1") ; CHECK: node x = z.x ; CHECK: node y = z.y ; CHECK: wire a : UInt<3>[10] -; CHECK: a[0] := UInt("h01") -; CHECK: a[1] := UInt("h01") -; CHECK: a[2] := UInt("h01") -; CHECK: a[3] := UInt("h01") -; CHECK: a[4] := UInt("h01") -; CHECK: a[5] := UInt("h01") -; CHECK: a[6] := UInt("h01") -; CHECK: a[7] := UInt("h01") -; CHECK: a[8] := UInt("h01") -; CHECK: a[9] := UInt("h01") +; CHECK: a[0] := UInt("h1") +; CHECK: a[1] := UInt("h1") +; CHECK: a[2] := UInt("h1") +; CHECK: a[3] := UInt("h1") +; CHECK: a[4] := UInt("h1") +; CHECK: a[5] := UInt("h1") +; CHECK: a[6] := UInt("h1") +; CHECK: a[7] := UInt("h1") +; CHECK: a[8] := UInt("h1") +; CHECK: a[9] := UInt("h1") ; CHECK: node b = a[2] -; CHECK: read accessor c = a[UInt("h03")] +; CHECK: read accessor c = a[UInt("h3")] diff --git a/test/parser/gcd.fir b/test/parser/gcd.fir index 03eb6ba9..3a9317b8 100644 --- a/test/parser/gcd.fir +++ b/test/parser/gcd.fir @@ -47,6 +47,6 @@ circuit GCD : ; CHECK: x := a ; CHECK: y := b ; CHECK: z := x -; CHECK: node T_20 = eq(y, UInt<1>("h00")) +; CHECK: node T_20 = eq(y, UInt<1>("h0")) ; CHECK: v := T_20 -- cgit v1.2.3 From 0122af3d602608bf41df7af1703a04bb738c0531 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 14 Oct 2015 14:00:21 -0700 Subject: Updated Makefile and README to be more friendly to Scala implementation --- Makefile | 5 ++++- README.md | 8 +++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 9e67e3e1..357c3189 100644 --- a/Makefile +++ b/Makefile @@ -21,12 +21,15 @@ install-mac: build-deploy: cd $(firrtl_dir) && stanza -i firrtl-main.stanza -o $(root_dir)/utils/bin/firrtl-stanza + make set-stanza build: cd $(firrtl_dir) && stanza -i firrtl-test-main.stanza -o $(root_dir)/utils/bin/firrtl-stanza + make set-stanza build-fast: cd $(firrtl_dir) && stanza -i firrtl-test-main.stanza -o $(root_dir)/utils/bin/firrtl-stanza -flags OPTIMIZE + make set-stanza check: cd $(test_dir) && lit -v . --path=$(root_dir)/utils/bin/ @@ -80,4 +83,4 @@ set-scala: set-stanza: ln -f -s $(root_dir)/utils/bin/firrtl-stanza $(root_dir)/utils/bin/firrtl -.PHONY: all install build-deploy build check clean fail succeed regress set-scala set-stanza build-scala +.PHONY: all install build-deploy build check clean fail succeed regress set-scala set-stanza build-scala test-scala diff --git a/README.md b/README.md index 4dc9d1b7..2c2a342e 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,9 @@ `make # Build & test` #### Scala implementation -The Scala FIRRTL implementation relies upon sbt. +The Scala FIRRTL implementation relies upon sbt 0.13.6. It uses sbt-assembly to create a fat JAR. +Using a bash script and a symbolic link it can be used with the same command-line arguments as the stanza implementation. Example use: - `sbt -mem 2048 "run-main Example ` -This command will read in <input> FIRRTL file, parse it, then output the AST to <output> + `make build-scala` + `make set-scala` # Creates symbolic link, make set-stanza reverts to stanza implementation + `./utils/bin/firrtl -i -o -X ` -- cgit v1.2.3 From edd57efbadf493b331e69c8686662500fe859372 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 14 Oct 2015 14:04:33 -0700 Subject: Modified getType to return Type rather than Option[Type] which makes more sense for some applications, also fixed up printing to better match stanza implementation --- src/main/scala/firrtl/Utils.scala | 55 +++++++++++++++++++++------------------ test/parser/bundle.fir | 2 +- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala index 8e9889b9..0cf19f04 100644 --- a/src/main/scala/firrtl/Utils.scala +++ b/src/main/scala/firrtl/Utils.scala @@ -21,7 +21,8 @@ object Utils { var str = "" if (flags('types)) { val tpe = node.getType - if( tpe.nonEmpty ) str += s"@" + //if( tpe != UnknownType ) str += s"@" + str += s"@" } str } @@ -36,15 +37,17 @@ object Utils { } implicit class ASTUtils(ast: AST) { - def getType(): Option[Type] = + def getType(): Type = ast match { case e: Exp => e.getType case s: Stmt => s.getType - case f: Field => f.getType + //case f: Field => f.getType case t: Type => t.getType case p: Port => p.getType - case _ => None + case _ => UnknownType } + + //def foreach } implicit class PrimOpUtils(op: PrimOp) { @@ -111,15 +114,14 @@ object Utils { case e: Exp => e } - def getType(): Option[Type] = { + def getType(): Type = { exp match { - case v: UIntValue => Option(UIntType(UnknownWidth)) - case v: SIntValue => Option(SIntType(UnknownWidth)) - case r: Ref => Option(r.tpe) - case s: Subfield => Option(s.tpe) - case i: Index => Option(i.tpe) - case p: DoPrimOp => Option(p.tpe) - case e: Exp => None + case v: UIntValue => UIntType(UnknownWidth) + case v: SIntValue => SIntType(UnknownWidth) + case r: Ref => r.tpe + case s: Subfield => s.tpe + case i: Index => i.tpe + case p: DoPrimOp => p.tpe } } } @@ -205,13 +207,13 @@ object Utils { // 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(): Option[Type] = + def getType(): Type = stmt match { - case w: DefWire => Option(w.tpe) - case r: DefReg => Option(r.tpe) - case m: DefMemory => Option(m.tpe) - case p: DefPoison => Option(p.tpe) - case s: Stmt => None + case w: DefWire => w.tpe + case r: DefReg => r.tpe + case m: DefMemory => m.tpe + case p: DefPoison => p.tpe + case s: Stmt => UnknownType } } @@ -228,7 +230,7 @@ object Utils { implicit class FieldDirUtils(dir: FieldDir) { def serialize(implicit flags: FlagMap = FlagMap): String = { val s = dir match { - case Reverse => "flip " + case Reverse => "flip" case Default => "" } s + debug(dir) @@ -239,7 +241,7 @@ object Utils { def serialize(implicit flags: FlagMap = FlagMap): String = s"${field.dir.serialize} ${field.name} : ${field.tpe.serialize}" + debug(field) - def getType(): Option[Type] = Option(field.tpe) + def getType(): Type = field.tpe } implicit class TypeUtils(t: Type) { @@ -251,17 +253,18 @@ object Utils { 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: BundleType => s"{${t.fields.map(_.serialize).mkString(commas)}}" case t: VectorType => s"${t.tpe.serialize}[${t.size}]" } - s + debug(t) + //s + debug(t) + s } // TODO how does this work? - def getType(): Option[Type] = + def getType(): Type = t match { - case v: VectorType => Option(v.tpe) - case tpe: Type => None + case v: VectorType => v.tpe + case tpe: Type => UnknownType } def wipeWidth(): Type = @@ -285,7 +288,7 @@ object Utils { 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(): Option[Type] = Option(p.tpe) + def getType(): Type = p.tpe } implicit class ModuleUtils(m: Module) { diff --git a/test/parser/bundle.fir b/test/parser/bundle.fir index c9f5e226..c9600d10 100644 --- a/test/parser/bundle.fir +++ b/test/parser/bundle.fir @@ -22,7 +22,7 @@ circuit top : ; CHECK: circuit top : ; CHECK: module top : -; CHECK: wire z : { x : UInt, flip y : SInt } +; CHECK: wire z : { x : UInt, flip y : SInt} ; CHECK: z.x := UInt("h1") ; CHECK: z.y := SInt("h1") ; CHECK: node x = z.x -- cgit v1.2.3 From 7a7936c8fbddbffc1c4775fafeb5106ba1002dd4 Mon Sep 17 00:00:00 2001 From: Jack Date: Thu, 15 Oct 2015 13:50:36 -0700 Subject: Added infer-types pass, seems to work. Added infer-types error checking, modified Logger slightly, added Primops object for utility functions, minor changes in Utils --- Makefile | 1 + src/main/scala/firrtl/DebugUtils.scala | 7 ++- src/main/scala/firrtl/IR.scala | 6 ++ src/main/scala/firrtl/Passes.scala | 102 +++++++++++++++++++++++++++++++++ src/main/scala/firrtl/Primops.scala | 69 ++++++++++++++++++++++ src/main/scala/firrtl/Test.scala | 12 ++-- src/main/scala/firrtl/Utils.scala | 20 +++---- 7 files changed, 199 insertions(+), 18 deletions(-) create mode 100644 src/main/scala/firrtl/Passes.scala create mode 100644 src/main/scala/firrtl/Primops.scala diff --git a/Makefile b/Makefile index 357c3189..4e2e3b17 100644 --- a/Makefile +++ b/Makefile @@ -76,6 +76,7 @@ build-scala: test-scala: cd $(test_dir)/parser && lit -v . --path=$(root_dir)/utils/bin/ + cd $(test_dir)/passes/infer-types && lit -v . --path=$(root_dir)/utils/bin/ set-scala: ln -f -s $(root_dir)/utils/bin/firrtl-scala $(root_dir)/utils/bin/firrtl diff --git a/src/main/scala/firrtl/DebugUtils.scala b/src/main/scala/firrtl/DebugUtils.scala index 80c0d240..01fe4fe4 100644 --- a/src/main/scala/firrtl/DebugUtils.scala +++ b/src/main/scala/firrtl/DebugUtils.scala @@ -24,6 +24,9 @@ private object DebugUtils { val circuitEnable = printVars contains 'circuit val debugFlags = printVars.map(_ -> true).toMap.withDefaultValue(false) + def println(message: => String){ + writer.println(message) + } def error(message: => String){ if (errorEnable) writer.println(message.split("\n").map("[error] " + _).mkString("\n")) } @@ -39,8 +42,8 @@ private object DebugUtils { def trace(message: => String){ if (traceEnable) writer.println(message.split("\n").map("[trace] " + _).mkString("\n")) } - def printDebug(circuit: Circuit){ - if (circuitEnable) this.debug(circuit.serialize(debugFlags)) + def printlnDebug(circuit: Circuit){ + if (circuitEnable) this.println(circuit.serialize(debugFlags)) } // Used if not autoflushing def flush() = writer.flush() diff --git a/src/main/scala/firrtl/IR.scala b/src/main/scala/firrtl/IR.scala index 7905612e..bd9bd484 100644 --- a/src/main/scala/firrtl/IR.scala +++ b/src/main/scala/firrtl/IR.scala @@ -1,3 +1,9 @@ + +/* TODO + * - Should FileInfo be a FIRRTL node? + * + */ + package firrtl import scala.collection.Seq diff --git a/src/main/scala/firrtl/Passes.scala b/src/main/scala/firrtl/Passes.scala new file mode 100644 index 00000000..4b31b1ff --- /dev/null +++ b/src/main/scala/firrtl/Passes.scala @@ -0,0 +1,102 @@ + +package firrtl + +import Utils._ +import DebugUtils._ +import Primops._ + +object Passes { + + private def toField(p: Port)(implicit logger: Logger): Field = { + logger.trace(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 here. + * Notable cases: LetRec requires updating environment before + * resolving the subexpressions in its elements. + * 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: Exp)(implicit logger: Logger): Exp = { + logger.trace(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: Index => Index(e.exp, e.value, getVectorSubtype(e.exp.getType)) + case e: DoPrimOp => lowerAndTypePrimop(e) + case e: Exp => e + } + } + private def inferTypes(typeMap: TypeMap, stmt: Stmt)(implicit logger: Logger): (Stmt, TypeMap) = { + logger.trace(s"inferTypes called on ${stmt.getClass.getSimpleName} ") + stmt.map(inferExpTypes(typeMap)) match { + case b: Block => { + 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 + } + (Block(body), tMap) + } + case s: DefWire => (s, typeMap ++ Map(s.name -> s.tpe)) + case s: DefReg => (s, typeMap ++ Map(s.name -> s.tpe)) + case s: DefMemory => (s, typeMap ++ Map(s.name -> s.tpe)) + case s: DefInst => (s, typeMap ++ Map(s.name -> s.module.getType)) + case s: DefNode => (s, typeMap ++ Map(s.name -> s.value.getType)) + case s: DefPoison => (s, typeMap ++ Map(s.name -> s.tpe)) + case s: DefAccessor => (s, typeMap ++ Map(s.name -> getVectorSubtype(s.source.getType))) + case s: When => { // TODO Check: Assuming else block won't see when scope + val (conseq, cMap) = inferTypes(typeMap, s.conseq) + val (alt, aMap) = inferTypes(typeMap, s.alt) + (When(s.info, s.pred, conseq, alt), cMap ++ aMap) + } + case s: Stmt => (s, typeMap) + } + } + private def inferTypes(typeMap: TypeMap, m: Module)(implicit logger: Logger): Module = { + logger.trace(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)(implicit logger: Logger): Circuit = { + logger.trace(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, _))) + } + +} diff --git a/src/main/scala/firrtl/Primops.scala b/src/main/scala/firrtl/Primops.scala new file mode 100644 index 00000000..5301390c --- /dev/null +++ b/src/main/scala/firrtl/Primops.scala @@ -0,0 +1,69 @@ + +package firrtl + +import Utils._ +import DebugUtils._ + +object Primops { + + // Borrowed from Stanza implementation + def lowerAndTypePrimop(e: DoPrimOp)(implicit logger: Logger): DoPrimOp = { + def uAnd(op1: Exp, op2: Exp): 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: Exp): Type = { + op.getType match { + case t: UIntType => UIntType(UnknownWidth) + case t: SIntType => SIntType(UnknownWidth) + case _ => UnknownType + } + } + + logger.debug(s"lowerAndTypePrimop on ${e.op.getClass.getSimpleName}") + 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 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 _ => ??? + } + DoPrimOp(e.op, e.args, e.consts, tpe) + } + +} diff --git a/src/main/scala/firrtl/Test.scala b/src/main/scala/firrtl/Test.scala index 86c3616a..3a89aeef 100644 --- a/src/main/scala/firrtl/Test.scala +++ b/src/main/scala/firrtl/Test.scala @@ -3,6 +3,7 @@ package firrtl import java.io._ import Utils._ import DebugUtils._ +import Passes._ object Test { @@ -18,22 +19,25 @@ object Test val writer = new PrintWriter(new File(output)) writer.write(ast.serialize()) writer.close() - logger.printDebug(ast) + logger.printlnDebug(ast) } private def verilog(input: String, output: String)(implicit logger: Logger) { logger.warn("Verilog compiler not fully implemented") val ast = time("parse"){ Parser.parse(input) } // Execute passes - //val ast2 = time("inferTypes"){ inferTypes(ast) } - val ast2 = ast + + logger.println("Infer Types") + val ast2 = time("inferTypes"){ inferTypes(ast) } + logger.printlnDebug(ast2) + logger.println("Finished Infer Types") + //val ast2 = ast // Output val writer = new PrintWriter(new File(output)) var outString = time("serialize"){ ast2.serialize() } writer.write(outString) writer.close() - logger.printDebug(ast2) } def main(args: Array[String]) diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala index 0cf19f04..f024edc2 100644 --- a/src/main/scala/firrtl/Utils.scala +++ b/src/main/scala/firrtl/Utils.scala @@ -8,6 +8,7 @@ package firrtl import scala.collection.mutable.StringBuilder +import java.io.PrintWriter //import scala.reflect.runtime.universe._ object Utils { @@ -21,8 +22,7 @@ object Utils { var str = "" if (flags('types)) { val tpe = node.getType - //if( tpe != UnknownType ) str += s"@" - str += s"@" + if( tpe != UnknownType ) str += s"@" } str } @@ -46,8 +46,6 @@ object Utils { case p: Port => p.getType case _ => UnknownType } - - //def foreach } implicit class PrimOpUtils(op: PrimOp) { @@ -209,11 +207,11 @@ object Utils { def getType(): Type = stmt match { - case w: DefWire => w.tpe - case r: DefReg => r.tpe - case m: DefMemory => m.tpe - case p: DefPoison => p.tpe - case s: Stmt => UnknownType + case s: DefWire => s.tpe + case s: DefReg => s.tpe + case s: DefMemory => s.tpe + case s: DefPoison => s.tpe + case _ => UnknownType } } @@ -256,11 +254,9 @@ object Utils { case t: BundleType => s"{${t.fields.map(_.serialize).mkString(commas)}}" case t: VectorType => s"${t.tpe.serialize}[${t.size}]" } - //s + debug(t) - s + s + debug(t) } - // TODO how does this work? def getType(): Type = t match { case v: VectorType => v.tpe -- cgit v1.2.3 From 80c055ce93c9d5988c6158c4a91c01633f8ebf22 Mon Sep 17 00:00:00 2001 From: Jack Date: Thu, 15 Oct 2015 14:16:06 -0700 Subject: Reorganized Primops (renamed from PrimOps), added maps and functions to convert object <=> string, added eqv and neqv --- src/main/antlr4/FIRRTL.g4 | 2 + src/main/scala/firrtl/DebugUtils.scala | 63 ++++++++++++++++++++++++++++ src/main/scala/firrtl/IR.scala | 76 +++++++++++++++++----------------- src/main/scala/firrtl/Passes.scala | 2 +- src/main/scala/firrtl/Primops.scala | 52 ++++++++++++++++++++++- src/main/scala/firrtl/Utils.scala | 49 +++------------------- src/main/scala/firrtl/Visitor.scala | 43 ++----------------- 7 files changed, 164 insertions(+), 123 deletions(-) diff --git a/src/main/antlr4/FIRRTL.g4 b/src/main/antlr4/FIRRTL.g4 index d9f3d18f..96172895 100644 --- a/src/main/antlr4/FIRRTL.g4 +++ b/src/main/antlr4/FIRRTL.g4 @@ -125,6 +125,8 @@ primop | 'geq' | 'eq' | 'neq' + | 'eqv' + | 'neqv' | 'mux' | 'pad' | 'asUInt' diff --git a/src/main/scala/firrtl/DebugUtils.scala b/src/main/scala/firrtl/DebugUtils.scala index 01fe4fe4..e802d935 100644 --- a/src/main/scala/firrtl/DebugUtils.scala +++ b/src/main/scala/firrtl/DebugUtils.scala @@ -7,6 +7,69 @@ import Utils._ private object DebugUtils { + implicit class DebugASTUtils(ast: AST) { + // Is this actually any use? + def preOrderTraversal(f: AST => Unit): Unit = { + f(ast) + ast match { + case a: Block => a.stmts.foreach(_.preOrderTraversal(f)) + case a: Assert => a.pred.preOrderTraversal(f) + case a: When => { + a.pred.preOrderTraversal(f) + a.conseq.preOrderTraversal(f) + a.alt.preOrderTraversal(f) + } + case a: BulkConnect => { + a.lhs.preOrderTraversal(f) + a.rhs.preOrderTraversal(f) + } + case a: Connect => { + a.lhs.preOrderTraversal(f) + a.rhs.preOrderTraversal(f) + } + case a: OnReset => { + a.lhs.preOrderTraversal(f) + a.rhs.preOrderTraversal(f) + } + case a: DefAccessor => { + a.dir.preOrderTraversal(f) + a.source.preOrderTraversal(f) + a.index.preOrderTraversal(f) + } + case a: DefPoison => a.tpe.preOrderTraversal(f) + case a: DefNode => a.value.preOrderTraversal(f) + case a: DefInst => a.module.preOrderTraversal(f) + case a: DefMemory => { + a.tpe.preOrderTraversal(f) + a.clock.preOrderTraversal(f) + } + case a: DefReg => { + a.tpe.preOrderTraversal(f) + a.clock.preOrderTraversal(f) + a.reset.preOrderTraversal(f) + } + case a: DefWire => a.tpe.preOrderTraversal(f) + case a: Field => { + a.dir.preOrderTraversal(f) + a.tpe.preOrderTraversal(f) + } + case a: VectorType => a.tpe.preOrderTraversal(f) + case a: BundleType => a.fields.foreach(_.preOrderTraversal(f)) + case a: Port => { + a.dir.preOrderTraversal(f) + a.tpe.preOrderTraversal(f) + } + case a: Module => { + a.ports.foreach(_.preOrderTraversal(f)) + a.stmt.preOrderTraversal(f) + } + case a: Circuit => a.modules.foreach(_.preOrderTraversal(f)) + //case _ => throw new Exception(s"Unsupported FIRRTL node ${ast.getClass.getSimpleName}!") + case _ => + } + } + } + /** Private class for recording and organizing debug information */ class Logger private ( diff --git a/src/main/scala/firrtl/IR.scala b/src/main/scala/firrtl/IR.scala index bd9bd484..5eb4e9e6 100644 --- a/src/main/scala/firrtl/IR.scala +++ b/src/main/scala/firrtl/IR.scala @@ -15,42 +15,44 @@ case class FileInfo(file: String, line: Int, column: Int) { trait AST -trait PrimOp extends AST -case object Add extends PrimOp -case object Sub extends PrimOp -case object Addw extends PrimOp -case object Subw extends PrimOp -case object Mul extends PrimOp -case object Div extends PrimOp -case object Mod extends PrimOp -case object Quo extends PrimOp -case object Rem extends PrimOp -case object Lt extends PrimOp -case object Leq extends PrimOp -case object Gt extends PrimOp -case object Geq extends PrimOp -case object Eq extends PrimOp -case object Neq extends PrimOp -case object Mux extends PrimOp -case object Pad extends PrimOp -case object AsUInt extends PrimOp -case object AsSInt extends PrimOp -case object Shl extends PrimOp -case object Shr extends PrimOp -case object Dshl extends PrimOp -case object Dshr extends PrimOp -case object Cvt extends PrimOp -case object Neg extends PrimOp -case object Not extends PrimOp -case object And extends PrimOp -case object Or extends PrimOp -case object Xor extends PrimOp -case object Andr extends PrimOp -case object Orr extends PrimOp -case object Xorr extends PrimOp -case object Cat extends PrimOp -case object Bit extends PrimOp -case object Bits extends PrimOp +trait Primop extends AST +case object Add extends Primop +case object Sub extends Primop +case object Addw extends Primop +case object Subw extends Primop +case object Mul extends Primop +case object Div extends Primop +case object Mod extends Primop +case object Quo extends Primop +case object Rem extends Primop +case object Lt extends Primop +case object Leq extends Primop +case object Gt extends Primop +case object Geq extends Primop +case object Eq extends Primop +case object Neq extends Primop +case object Eqv extends Primop +case object Neqv extends Primop +case object Mux extends Primop +case object Pad extends Primop +case object AsUInt extends Primop +case object AsSInt extends Primop +case object Shl extends Primop +case object Shr extends Primop +case object Dshl extends Primop +case object Dshr extends Primop +case object Cvt extends Primop +case object Neg extends Primop +case object Not extends Primop +case object And extends Primop +case object Or extends Primop +case object Xor extends Primop +case object Andr extends Primop +case object Orr extends Primop +case object Xorr extends Primop +case object Cat extends Primop +case object Bit extends Primop +case object Bits extends Primop // TODO stanza ir has types on many of these, why? Is it the type of what we're referencing? // Add types, default to UNKNOWN @@ -61,7 +63,7 @@ case class SIntValue(value: BigInt, width: Width) extends Exp case class Ref(name: String, tpe: Type) extends Exp case class Subfield(exp: Exp, name: String, tpe: Type) extends Exp case class Index(exp: Exp, value: BigInt, tpe: Type) extends Exp -case class DoPrimOp(op: PrimOp, args: Seq[Exp], consts: Seq[BigInt], tpe: Type) extends Exp +case class DoPrimop(op: Primop, args: Seq[Exp], consts: Seq[BigInt], tpe: Type) extends Exp trait AccessorDir extends AST case object Infer extends AccessorDir diff --git a/src/main/scala/firrtl/Passes.scala b/src/main/scala/firrtl/Passes.scala index 4b31b1ff..39e6b64e 100644 --- a/src/main/scala/firrtl/Passes.scala +++ b/src/main/scala/firrtl/Passes.scala @@ -50,7 +50,7 @@ object Passes { 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: Index => Index(e.exp, e.value, getVectorSubtype(e.exp.getType)) - case e: DoPrimOp => lowerAndTypePrimop(e) + case e: DoPrimop => lowerAndTypePrimop(e) case e: Exp => e } } diff --git a/src/main/scala/firrtl/Primops.scala b/src/main/scala/firrtl/Primops.scala index 5301390c..1840b190 100644 --- a/src/main/scala/firrtl/Primops.scala +++ b/src/main/scala/firrtl/Primops.scala @@ -6,8 +6,54 @@ import DebugUtils._ object Primops { + private val mapPrimop2String = Map[Primop, String]( + Add -> "add", + Sub -> "sub", + Addw -> "addw", + Subw -> "subw", + Mul -> "mul", + Div -> "div", + Mod -> "mod", + Quo -> "quo", + Rem -> "rem", + Lt -> "lt", + Leq -> "leq", + Gt -> "gt", + Geq -> "geq", + Eq -> "eq", + Neq -> "neq", + Eqv -> "eqv", + Neqv -> "neqv", + Mux -> "mux", + Pad -> "pad", + AsUInt -> "asUInt", + AsSInt -> "asSInt", + Shl -> "shl", + Shr -> "shr", + Dshl -> "dshl", + Dshr -> "dshr", + Cvt -> "cvt", + Neg -> "neg", + Not -> "not", + And -> "and", + Or -> "or", + Xor -> "xor", + Andr -> "andr", + Orr -> "orr", + Xorr -> "xorr", + Cat -> "cat", + Bit -> "bit", + Bits -> "bits" + ) + private val mapString2Primop = mapPrimop2String.map(_.swap) + def fromString(op: String): Primop = mapString2Primop(op) + + implicit class PrimopImplicits(op: Primop){ + def getString(): String = mapPrimop2String(op) + } + // Borrowed from Stanza implementation - def lowerAndTypePrimop(e: DoPrimOp)(implicit logger: Logger): DoPrimOp = { + def lowerAndTypePrimop(e: DoPrimop)(implicit logger: Logger): DoPrimop = { def uAnd(op1: Exp, op2: Exp): Type = { (op1.getType, op2.getType) match { case (t1: UIntType, t2: UIntType) => UIntType(UnknownWidth) @@ -41,6 +87,8 @@ object Primops { 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) @@ -63,7 +111,7 @@ object Primops { case Bits => UIntType(UnknownWidth) case _ => ??? } - DoPrimOp(e.op, e.args, e.consts, tpe) + DoPrimop(e.op, e.args, e.consts, tpe) } } diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala index f024edc2..4220e07f 100644 --- a/src/main/scala/firrtl/Utils.scala +++ b/src/main/scala/firrtl/Utils.scala @@ -9,6 +9,7 @@ package firrtl import scala.collection.mutable.StringBuilder import java.io.PrintWriter +import Primops._ //import scala.reflect.runtime.universe._ object Utils { @@ -48,46 +49,8 @@ object Utils { } } - implicit class PrimOpUtils(op: PrimOp) { - def serialize(implicit flags: FlagMap = FlagMap): String = { - op match { - case Add => "add" - case Sub => "sub" - case Addw => "addw" - case Subw => "subw" - case Mul => "mul" - case Div => "div" - case Mod => "mod" - case Quo => "quo" - case Rem => "rem" - case Lt => "lt" - case Leq => "leq" - case Gt => "gt" - case Geq => "geq" - case Eq => "eq" - case Neq => "neq" - case Mux => "mux" - case Pad => "pad" - case AsUInt => "asUInt" - case AsSInt => "asSInt" - case Shl => "shl" - case Shr => "shr" - case Dshl => "dshl" - case Dshr => "dshr" - case Cvt => "cvt" - case Neg => "neg" - case Not => "not" - case And => "and" - case Or => "or" - case Xor => "xor" - case Andr => "andr" - case Orr => "orr" - case Xorr => "xorr" - case Cat => "cat" - case Bit => "bit" - case Bits => "bits" - } - } + implicit class PrimopUtils(op: Primop) { + def serialize(implicit flags: FlagMap = FlagMap): String = op.getString } implicit class ExpUtils(exp: Exp) { @@ -98,7 +61,7 @@ object Utils { case r: Ref => r.name case s: Subfield => s"${s.exp.serialize}.${s.name}" case s: Index => s"${s.exp.serialize}[${s.value}]" - case p: DoPrimOp => + case p: DoPrimop => s"${p.op.serialize}(" + (p.args.map(_.serialize) ++ p.consts.map(_.toString)).mkString(", ") + ")" } ret + debug(exp) @@ -108,7 +71,7 @@ object Utils { exp match { case s: Subfield => Subfield(f(s.exp), s.name, s.tpe) case i: Index => Index(f(i.exp), i.value, i.tpe) - case p: DoPrimOp => DoPrimOp(p.op, p.args.map(f), p.consts, p.tpe) + case p: DoPrimop => DoPrimop(p.op, p.args.map(f), p.consts, p.tpe) case e: Exp => e } @@ -119,7 +82,7 @@ object Utils { case r: Ref => r.tpe case s: Subfield => s.tpe case i: Index => i.tpe - case p: DoPrimOp => p.tpe + case p: DoPrimop => p.tpe } } } diff --git a/src/main/scala/firrtl/Visitor.scala b/src/main/scala/firrtl/Visitor.scala index 8bbed2e3..7d54ca1a 100644 --- a/src/main/scala/firrtl/Visitor.scala +++ b/src/main/scala/firrtl/Visitor.scala @@ -14,6 +14,7 @@ import org.antlr.v4.runtime.tree.ErrorNode import org.antlr.v4.runtime.tree.TerminalNode import scala.collection.JavaConversions._ import antlr._ +import Primops._ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST] { @@ -149,48 +150,10 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST] case "." => new Subfield(visitExp(ctx.exp(0)), ctx.id.getText, UnknownType) case "[" => new Index(visitExp(ctx.exp(0)), string2BigInt(ctx.IntLit(0).getText), UnknownType) case "(" => - DoPrimOp(visitPrimop(ctx.primop), ctx.exp.map(visitExp), + DoPrimop(visitPrimop(ctx.primop), ctx.exp.map(visitExp), ctx.IntLit.map(x => string2BigInt(x.getText)), UnknownType) } } - // TODO can I create this and have the opposite? create map and invert it? - private def visitPrimop[AST](ctx: FIRRTLParser.PrimopContext): PrimOp = - ctx.getText match { - case "add" => Add - case "sub" => Sub - case "addw" => Addw - case "subw" => Subw - case "mul" => Mul - case "div" => Div - case "mod" => Mod - case "quo" => Quo - case "rem" => Rem - case "lt" => Lt - case "leq" => Leq - case "gt" => Gt - case "geq" => Geq - case "eq" => Eq - case "neq" => Neq - case "mux" => Mux - case "pad" => Pad - case "asUInt" => AsUInt - case "asSInt" => AsSInt - case "shl" => Shl - case "shr" => Shr - case "dshl" => Dshl - case "dshr" => Dshr - case "cvt" => Cvt - case "neg" => Neg - case "not" => Not - case "and" => And - case "or" => Or - case "xor" => Xor - case "andr" => Andr - case "orr" => Orr - case "xorr" => Xorr - case "cat" => Cat - case "bit" => Bit - case "bits" => Bits - } + private def visitPrimop[AST](ctx: FIRRTLParser.PrimopContext): Primop = fromString(ctx.getText) } -- cgit v1.2.3