aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/Visitor.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/firrtl/Visitor.scala')
-rw-r--r--src/main/scala/firrtl/Visitor.scala185
1 files changed, 185 insertions, 0 deletions
diff --git a/src/main/scala/firrtl/Visitor.scala b/src/main/scala/firrtl/Visitor.scala
new file mode 100644
index 00000000..276facce
--- /dev/null
+++ b/src/main/scala/firrtl/Visitor.scala
@@ -0,0 +1,185 @@
+/*
+ * TODO FIXME
+ * - 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?
+*/
+
+package firrtl
+
+import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
+import org.antlr.v4.runtime.ParserRuleContext
+import org.antlr.v4.runtime.tree.ErrorNode
+import org.antlr.v4.runtime.tree.TerminalNode
+import scala.collection.JavaConversions._
+import antlr._
+
+class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST]
+{
+ // Strip file path
+ private val filename = fullFilename.drop(fullFilename.lastIndexOf("/")+1)
+
+ // For some reason visitCircuit does not visit the right function
+ // FIXME for some reason this cannot be private, probably because it extends
+ // FIRRTLBaseVisitor which is in a subpackage?
+ def visit[AST](ctx: FIRRTLParser.CircuitContext): Circuit = visitCircuit(ctx)
+
+ // These regex have to change if grammar changes
+ private def string2BigInt(s: String): BigInt = {
+ // private define legal patterns
+ val HexPattern = """\"*h([a-zA-Z0-9]+)\"*""".r
+ val DecPattern = """(\+|-)?([1-9]\d*)""".r
+ val ZeroPattern = "0".r
+ s match {
+ case ZeroPattern(_*) => BigInt(0)
+ case HexPattern(hexdigits) => BigInt(hexdigits, 16)
+ case DecPattern(sign, num) => BigInt(num)
+ case _ => throw new Exception("Invalid String for conversion to BigInt " + s)
+ }
+ }
+ private def getFileInfo(ctx: ParserRuleContext): FileInfo =
+ FileInfo(filename, ctx.getStart().getLine(), ctx.getStart().getCharPositionInLine())
+
+ private def visitCircuit[AST](ctx: FIRRTLParser.CircuitContext): Circuit =
+ Circuit(getFileInfo(ctx), ctx.id.getText, ctx.module.map(visitModule))
+
+ private def visitModule[AST](ctx: FIRRTLParser.ModuleContext): Module =
+ Module(getFileInfo(ctx), ctx.id.getText, ctx.port.map(visitPort), visitBlockStmt(ctx.blockStmt))
+
+ private def visitPort[AST](ctx: FIRRTLParser.PortContext): Port =
+ Port(getFileInfo(ctx), ctx.id.getText, visitPortKind(ctx.portKind), visitType(ctx.`type`))
+
+ private def visitPortKind[AST](ctx: FIRRTLParser.PortKindContext): PortDir =
+ ctx.getText match {
+ case "input" => Input
+ case "output" => Output
+ }
+
+ // 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 "Clock" => ClockType
+ case "{" => BundleType(ctx.field.map(visitField))
+ case _ => new VectorType( visitType(ctx.`type`), string2BigInt(ctx.IntLit.getText) )
+ }
+ }
+
+ private def visitField[AST](ctx: FIRRTLParser.FieldContext): Field =
+ Field(ctx.id.getText, visitOrientation(ctx.orientation), visitType(ctx.`type`))
+
+ private def visitOrientation[AST](ctx: FIRRTLParser.OrientationContext): FieldDir =
+ ctx.getText match {
+ case "flip" => Reverse
+ case _ => Default
+ }
+
+ private def visitWidth[AST](ctx: FIRRTLParser.WidthContext): Width = {
+ val text = ctx.getText
+ text match {
+ case "?" => UnknownWidth
+ case _ => IntWidth(string2BigInt(text))
+ }
+ }
+
+ private def visitBlockStmt[AST](ctx: FIRRTLParser.BlockStmtContext): Stmt =
+ Block(ctx.stmt.map(visitStmt))
+
+ private def visitStmt[AST](ctx: FIRRTLParser.StmtContext): Stmt = {
+ val info = getFileInfo(ctx)
+
+ ctx.getChild(0).getText match {
+ case "wire" => DefWire(info, ctx.id(0).getText, visitType(ctx.`type`))
+ case "reg" => DefReg(info, ctx.id(0).getText, visitType(ctx.`type`),
+ visitExp(ctx.exp(0)), visitExp(ctx.exp(1)))
+ case "smem" => DefMemory(info, ctx.id(0).getText, true,
+ visitType(ctx.`type`), visitExp(ctx.exp(0)))
+ case "cmem" => DefMemory(info, ctx.id(0).getText, false,
+ visitType(ctx.`type`), visitExp(ctx.exp(0)))
+ case "inst" => DefInst(info, ctx.id(0).getText, Ref(ctx.id(1).getText, UnknownType))
+ case "node" => DefNode(info, ctx.id(0).getText, visitExp(ctx.exp(0)))
+ case "poison" => DefPoison(info, ctx.id(0).getText, visitType(ctx.`type`))
+ case "onreset" => OnReset(info, visitExp(ctx.exp(0)), visitExp(ctx.exp(1)))
+ case "when" => {
+ val alt = if (ctx.blockStmt.length > 1) visitBlockStmt(ctx.blockStmt(1)) else EmptyStmt
+ When(info, visitExp(ctx.exp(0)), visitBlockStmt(ctx.blockStmt(0)), alt)
+ }
+ case "assert" => Assert(info, visitExp(ctx.exp(0)))
+ case "skip" => EmptyStmt
+ // If we don't match on the first child, try the next one
+ case _ => {
+ ctx.getChild(1).getText match {
+ case "accessor" => DefAccessor(info, ctx.id(0).getText,
+ visitDir(ctx.dir), visitExp(ctx.exp(0)), visitExp(ctx.exp(1)))
+ case ":=" => Connect(info, visitExp(ctx.exp(0)), visitExp(ctx.exp(1)) )
+ case "<>" => BulkConnect(info, visitExp(ctx.exp(0)), visitExp(ctx.exp(1)) )
+ }
+ }
+ }
+ }
+
+ private def visitDir[AST](ctx: FIRRTLParser.DirContext): AccessorDir =
+ ctx.getText match {
+ case "infer" => Infer
+ case "read" => Read
+ case "write" => Write
+ case "rdwr" => RdWr // TODO remove exceptions for unmatched things
+ }
+
+ private def visitExp[AST](ctx: FIRRTLParser.ExpContext): Exp =
+ if( ctx.getChildCount == 1 )
+ 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 _ =>
+ 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 "(" =>
+ DoPrimOp(visitPrimop(ctx.primop), ctx.exp.map(visitExp), ctx.IntLit.map(x => string2BigInt(x.getText)))
+ }
+ }
+
+ // 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
+ }
+}