diff options
| author | Jack | 2015-10-12 17:38:12 -0700 |
|---|---|---|
| committer | Jack | 2015-10-12 17:38:12 -0700 |
| commit | bf4488870e1def4d76297dd8fdd795a82bc4ded3 (patch) | |
| tree | 7ed187d79c4221ee0b4adb2b7f70674572154cb9 | |
| parent | 09ef2e42b00174e99124477b443a472e8664708f (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.scala | 59 | ||||
| -rw-r--r-- | src/main/scala/firrtl/Test.scala | 60 | ||||
| -rw-r--r-- | src/main/scala/firrtl/Utils.scala | 135 |
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 } } |
