aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack2015-10-12 17:38:12 -0700
committerJack2015-10-12 17:38:12 -0700
commitbf4488870e1def4d76297dd8fdd795a82bc4ded3 (patch)
tree7ed187d79c4221ee0b4adb2b7f70674572154cb9
parent09ef2e42b00174e99124477b443a472e8664708f (diff)
Added initial support for debug printing for lit based testing, most types of printVars still missing. Added Logger class for debug printing
-rw-r--r--src/main/scala/firrtl/Logger.scala59
-rw-r--r--src/main/scala/firrtl/Test.scala60
-rw-r--r--src/main/scala/firrtl/Utils.scala135
3 files changed, 219 insertions, 35 deletions
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"@<t:${tpe.get.serialize}>")
+ }
+
+ 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 <input> -o <output>
+ Usage: java -cp utils/bin/firrtl.jar firrtl.Test [options] -i <input> -o <output>
"""
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"@<t:${tpe.get.wipeWidth.serialize}>"
+ }
+ 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
}
}