diff options
| author | azidar | 2015-10-06 14:28:24 -0700 |
|---|---|---|
| committer | azidar | 2015-10-06 14:28:24 -0700 |
| commit | 2485d20374166b27c06c475a4aef365761a818f7 (patch) | |
| tree | 627b3c180ba41d7619b1acc8be03e2195dd208aa | |
| parent | 62e922b0e7ea5f90c14a918ab09ce04a28f082d4 (diff) | |
| parent | 0a9dfbe9f58338fc8af11015f6e9227e0cb46ea4 (diff) | |
Merge branch 'master' of github.com:ucb-bar/firrtl
Conflicts:
README.md
43 files changed, 1668 insertions, 221 deletions
@@ -29,7 +29,14 @@ spec/spec.toc spec/spec.out spec/spec.synctex.gz notes/*.docx -build.sbt -target -project -src/main/scala + +# sbt specific +.cache +.history +.lib/ +dist/* +target/ +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ @@ -46,3 +46,9 @@ `make check` 1. Build and test: `make` + +#### Scala implementation +The Scala FIRRTL implementation relies upon sbt. +Example use: + `sbt -mem 2048 "run-main Example <input> <output>` +This command will read in <input> FIRRTL file, parse it, then output the AST to <output> diff --git a/build.sbt b/build.sbt new file mode 100644 index 00000000..0a083994 --- /dev/null +++ b/build.sbt @@ -0,0 +1,14 @@ +lazy val root = (project in file(".")). + settings( + name := "firrtl", + version := "1.0", + scalaVersion := "2.11.4" + ) + +antlr4Settings + +antlr4GenVisitor in Antlr4 := true // default = false + +antlr4GenListener in Antlr4 := false // default = true + +antlr4PackageName in Antlr4 := Option("firrtl.antlr") diff --git a/project/sbt-antlr4.sbt b/project/sbt-antlr4.sbt new file mode 100644 index 00000000..df6819fa --- /dev/null +++ b/project/sbt-antlr4.sbt @@ -0,0 +1,3 @@ +resolvers += "simplytyped" at "http://simplytyped.github.io/repo/releases" + +addSbtPlugin("com.simplytyped" % "sbt-antlr4" % "0.7.7") diff --git a/src/main/antlr4/FIRRTL.g4 b/src/main/antlr4/FIRRTL.g4 new file mode 100644 index 00000000..08697bb1 --- /dev/null +++ b/src/main/antlr4/FIRRTL.g4 @@ -0,0 +1,207 @@ +// Jack Koenig +// UC Berkeley ASPIRE Lab +// July 9, 2015 + +grammar FIRRTL; + +/*------------------------------------------------------------------ + * PARSER RULES + *------------------------------------------------------------------*/ + +// TODO add [info] support (all over the place) +// TODO Fix connect +// TODO Add partial connect +// TODO Should FIRRTL keywords be legal IDs? + +// Does there have to be at least one module? +circuit + : 'circuit' id ':' '{' module* '}' + ; + +// TODO Add support for extmodule +module + : 'module' id ':' '{' port* blockStmt '}' + ; + +port + : portKind id ':' type + ; + +portKind + : 'input' + | 'output' + ; + +type + : 'UInt' '<' width '>' + | 'SInt' '<' width '>' + | 'Clock' + | '{' field* '}' // Bundle + | type '[' IntLit ']' // Vector + ; + +field + : orientation id ':' type + ; + +// FIXME This is what the spec says it should be +//orientation +// : 'default' +// | 'reverse' +// ; +orientation + : 'flip' + | // Nothing + ; + +width + : IntLit + | '?' + ; + +// Much faster than replacing blockStmt with stmt+ +blockStmt + : (stmt)* + ; + +stmt + : 'wire' id ':' type + | 'reg' id ':' type exp exp + | 'smem' id ':' type exp + | 'cmem' id ':' type exp + | 'inst' id (':' | 'of') id // FIXME which should it be? ':' or 'of' + | 'node' id '=' exp + | 'poison' id ':' type // Poison, FIXME + | dir 'accessor' id '=' exp '[' exp ']' exp? // FIXME what is this extra exp? + | exp ':=' exp // Connect + | 'onreset' exp ':=' exp + | exp '<>' exp // Bulk Connect + | exp '[' IntLit 'through' IntLit ']' ':=' exp // SubWordConnect + | 'when' exp ':' '{' blockStmt '}' ( 'else' ':' '{' blockStmt '}' )? + | 'assert' exp + | 'skip' + ; + +// Accessor Direction +dir + : 'infer' + | 'read' + | 'write' + | 'rdwr' + ; + +// TODO implement +// What is exp? +exp + : '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 ']' + | primop '(' exp* IntLit* ')' // FIXME Need a big check here + ; + +id + : Id + | keyword + ; + +// FIXME need to make sure this is exhaustive including all FIRRTL keywords that are legal IDs +keyword + : primop + | dir + | 'inst' + ; + +primop + : 'add' + | 'sub' + | 'addw' + | 'subw' + | 'mul' + | 'div' + | 'mod' + | 'quo' + | 'rem' + | 'lt' + | 'leq' + | 'gt' + | 'geq' + | 'eq' + | 'neq' + | 'mux' + | 'pad' + | 'asUInt' + | 'asSInt' + | 'shl' + | 'shr' + | 'dshl' + | 'dshr' + | 'cvt' + | 'neg' + | 'not' + | 'and' + | 'or' + | 'xor' + | 'andr' + | 'orr' + | 'xorr' + | 'cat' + | 'bit' + | 'bits' + ; + +/*------------------------------------------------------------------ + * LEXER RULES + *------------------------------------------------------------------*/ + +Id + : IdNondigit + ( IdNondigit + | Digit + )* + ; + +fragment +IdNondigit + : Nondigit + | [~!@#$%^*-+=?/] + ; + +// Should enforcing signed, non-neg, and positive ints be done in parser? +// => YES +IntLit + : '0' + | ( '+' | '-' )? [1-9] ( Digit )* + | '"' 'h' ( HexDigit )+ '"' + ; + +fragment +Nondigit + : [a-zA-Z_] + ; + +fragment +Digit + : [0-9] + ; + +fragment +HexDigit + : [a-zA-Z0-9] + ; + +Comment + : ';' ~[\r\n]* + -> skip + ; + +Whitespace + : [ \t,]+ + -> skip + ; + +Newline + : ( '\r'? '\n' )+ + -> skip + ; diff --git a/src/main/scala/Example.scala b/src/main/scala/Example.scala new file mode 100644 index 00000000..210a50fb --- /dev/null +++ b/src/main/scala/Example.scala @@ -0,0 +1,19 @@ +import java.io._ +import firrtl._ +import firrtl.Utils._ + +object Example +{ + // Example use of Scala FIRRTL parser and serialization + def main(args: Array[String]) + { + val inputFile = args(0) + + // Parse file + val ast = firrtl.Parser.parse(inputFile) + + val writer = new PrintWriter(new File(args(1))) + writer.write(ast.serialize) // serialize returns String + writer.close() + } +} diff --git a/src/main/scala/firrtl/IR.scala b/src/main/scala/firrtl/IR.scala new file mode 100644 index 00000000..c52c45a4 --- /dev/null +++ b/src/main/scala/firrtl/IR.scala @@ -0,0 +1,110 @@ +package firrtl + +import scala.collection.Seq + +// Should this be defined elsewhere? +case class FileInfo(file: String, line: Int, column: Int) { + override def toString(): String = s"$file@$line.$column" +} + +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 + +// TODO stanza ir has types on many of these, why? Is it the type of what we're referencing? +// 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 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 + +trait AccessorDir extends AST +case object Infer extends AccessorDir +case object Read extends AccessorDir +case object Write extends AccessorDir +case object RdWr extends AccessorDir + +trait Stmt extends AST +case class DefWire(info: FileInfo, name: String, tpe: Type) extends Stmt +case class DefReg(info: FileInfo, name: String, tpe: Type, clock: Exp, reset: Exp) extends Stmt +case class DefMemory(info: FileInfo, name: String, seq: Boolean, tpe: Type, clock: Exp) extends Stmt +case class DefInst(info: FileInfo, name: String, module: Exp) extends Stmt +case class DefNode(info: FileInfo, name: String, value: Exp) extends Stmt +case class DefPoison(info: FileInfo, name: String, tpe: Type) extends Stmt +case class DefAccessor(info: FileInfo, name: String, dir: AccessorDir, source: Exp, index: Exp) extends Stmt +case class OnReset(info: FileInfo, lhs: Exp, rhs: Exp) extends Stmt +case class Connect(info: FileInfo, lhs: Exp, rhs: Exp) extends Stmt +case class BulkConnect(info: FileInfo, lhs: Exp, rhs: Exp) extends Stmt +case class When(info: FileInfo, pred: Exp, conseq: Stmt, alt: Stmt) extends Stmt +case class Assert(info: FileInfo, pred: Exp) extends Stmt +case class Block(stmts: Seq[Stmt]) extends Stmt +case object EmptyStmt extends Stmt + +trait Width extends AST +case class IntWidth(width: BigInt) extends Width +case object UnknownWidth extends Width + +trait FieldDir extends AST +case object Default extends FieldDir +case object Reverse extends FieldDir + +case class Field(name: String, dir: FieldDir, tpe: Type) extends AST + +trait Type extends AST +case class UIntType(width: Width) extends Type +case class SIntType(width: Width) extends Type +case object ClockType extends Type +case class BundleType(fields: Seq[Field]) extends Type +case class VectorType(tpe: Type, size: BigInt) extends Type +case object UnknownType extends Type + +trait PortDir extends AST +case object Input extends PortDir +case object Output extends PortDir + +case class Port(info: FileInfo, name: String, dir: PortDir, tpe: Type) extends AST + +case class Module(info: FileInfo, name: String, ports: Seq[Port], stmt: Stmt) extends AST + +case class Circuit(info: FileInfo, name: String, modules: Seq[Module]) extends AST + + diff --git a/src/main/scala/firrtl/Parser.scala b/src/main/scala/firrtl/Parser.scala new file mode 100644 index 00000000..35e41222 --- /dev/null +++ b/src/main/scala/firrtl/Parser.scala @@ -0,0 +1,44 @@ +package firrtl + +import org.antlr.v4.runtime._; +import org.antlr.v4.runtime.atn._; +import org.antlr.v4.runtime.tree._; +import java.io.FileInputStream +import scala.collection.JavaConverters._ +import scala.io.Source +import Utils._ +import antlr._ + +object Parser +{ + + /** Takes a firrtl filename, returns AST (root node is Circuit) + * + * Currently must be standard FIRRTL file + * Parser performs conversion to machine firrtl + */ + def parse(filename: String): Circuit = { + //val antlrStream = new ANTLRInputStream(input.reader) + val fixedInput = Translator.addBrackets(Source.fromFile(filename).getLines) + val antlrStream = new ANTLRInputStream(fixedInput.result) + val lexer = new FIRRTLLexer(antlrStream) + val tokens = new CommonTokenStream(lexer) + val parser = new FIRRTLParser(tokens) + + // FIXME Dangerous + parser.getInterpreter.setPredictionMode(PredictionMode.SLL) + + // Concrete Syntax Tree + val cst = parser.circuit + + val visitor = new Visitor(filename) + //val ast = visitor.visitCircuit(cst) match { + val ast = visitor.visit(cst) match { + case c: Circuit => c + case x => throw new ClassCastException("Error! AST not rooted with Circuit node!") + } + + ast + } + +} diff --git a/src/main/scala/firrtl/Translator.scala b/src/main/scala/firrtl/Translator.scala new file mode 100644 index 00000000..eba78b39 --- /dev/null +++ b/src/main/scala/firrtl/Translator.scala @@ -0,0 +1,115 @@ + +/* TODO + * - Add support for comments (that being said, current Scopers regex should ignore commented lines) + * - Add better error messages for illformed FIRRTL + * - Add support for files that do not have a circuit (like a module by itself in a file) + * - Improve performance? Replace regex? + * - Add proper commnad-line arguments? + * - Wrap in Reader subclass. This would have less memory footprint than creating a large string + */ + +package firrtl + +import scala.io.Source +import scala.collection.mutable.Stack +import scala.collection.mutable.StringBuilder +import java.io._ + + +object Translator +{ + + def addBrackets(inputIt: Iterator[String]): StringBuilder = { + def countSpaces(s: String): Int = s.prefixLength(_ == ' ') + + val Scopers = """\s*(circuit|module|when|else)(.*)""".r + + // Function start + val it = inputIt.zipWithIndex + var ret = new StringBuilder() + + if( !it.hasNext ) throw new Exception("Empty file!") + + // Find circuit before starting scope checks + var line = it.next + while ( it.hasNext && !line._1.contains("circuit") ) { + ret ++= line._1 + "\n" + line = it.next + } + ret ++= line._1 + " { \n" + if( !it.hasNext ) throw new Exception("No circuit in file!") + + + val scope = Stack[Int]() + scope.push(countSpaces(line._1)) + var newScope = true // indicates if increasing scope spacing is legal on next line + + while( it.hasNext ) { + it.next match { case (text, lineNum) => + val spaces = countSpaces(text) + + val l = if (text.length > spaces ) { // Check that line has text in it + if (newScope) { + scope.push(countSpaces(text)) + } else { + + // Check if change in current scope + if( spaces < scope.top ) { + while( spaces < scope.top ) { + // Close scopes (adding brackets as we go) + scope.pop() + ret.deleteCharAt(ret.lastIndexOf("\n")) // Put on previous line + ret ++= " }\n" + } + if( spaces != scope.top ) + throw new Exception("Spacing does not match scope on line : " + lineNum + " : " + scope.top) + } + else if( spaces > scope.top ) + throw new Exception("Invalid increase in scope on line " + lineNum) + } + // Now match on legal scope increasers + text match { + case Scopers(keyword, _* ) => { + newScope = true + text + " { " + } + case _ => { + newScope = false + text + } + } + } // if( text.length > spaces ) + else { + text // empty lines + } + + ret ++= l + "\n" + } // it.next match + } // while( it.hasNext ) + + // Print any closing braces + while( scope.top > 0 ) { + scope.pop() + ret.deleteCharAt(ret.lastIndexOf("\n")) // Put on previous line + ret ++= " }\n" + } + + ret + } + + def main(args: Array[String]) { + + try { + val translation = addBrackets(Source.fromFile(args(0)).getLines) + + val writer = new PrintWriter(new File(args(1))) + writer.write(translation.result) + writer.close() + } catch { + case e: Exception => { + throw new Exception("USAGE: Translator <input file> <output file>\n" + e) + } + } + } + +} diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala new file mode 100644 index 00000000..916408bc --- /dev/null +++ b/src/main/scala/firrtl/Utils.scala @@ -0,0 +1,194 @@ +// Utility functions for FIRRTL IR + +/* TODO + * - Adopt style more similar to Chisel3 Emitter? + */ + +package firrtl + +import scala.collection.mutable.StringBuilder + +object Utils { + + implicit class BigIntUtils(bi: BigInt){ + def serialize(): String = + "\"h0" + bi.toString(16) + "\"" + } + + implicit class PrimOpUtils(op: PrimOp) { + def serialize(): 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 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 r: Ref => r.name + case s: Subfield => s"${s.exp.serialize}.${s.name}" + case s: Subindex => s"${s.exp.serialize}[${s.value}]" + case p: DoPrimOp => + s"${p.op.serialize}(" + (p.args.map(_.serialize) ++ p.consts.map(_.toString)).mkString(", ") + ")" + } + } + + // AccessorDir + implicit class AccessorDirUtils(dir: AccessorDir) { + def serialize(): String = + dir match { + case Infer => "infer" + case Read => "read" + case Write => "write" + case RdWr => "rdwr" + } + } + + + implicit class StmtUtils(stmt: Stmt) { + def serialize(): String = + 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") + + s" ${m.name} : ${m.tpe.serialize}, ${m.clock.serialize}" + case i: DefInst => s"inst ${i.name} of ${i.module.serialize}" + case n: DefNode => s"node ${n.name} = ${n.value.serialize}" + case p: DefPoison => s"poison ${p.name} : ${p.tpe.serialize}" + case a: DefAccessor => s"${a.dir.serialize} accessor ${a.name} = ${a.source.serialize}[${a.index.serialize}]" + case c: Connect => s"${c.lhs.serialize} := ${c.rhs.serialize}" + case o: OnReset => s"onreset ${o.lhs.serialize} := ${o.rhs.serialize}" + case b: BulkConnect => s"${b.lhs.serialize} <> ${b.rhs.serialize}" + case w: When => { + var str = new StringBuilder(s"when ${w.pred.serialize} : ") + withIndent { str ++= w.conseq.serialize } + if( w.alt != EmptyStmt ) { + str ++= newline + "else :" + withIndent { str ++= w.alt.serialize } + } + str.result + } + //case b: Block => b.stmts.map(newline ++ _.serialize).mkString + case b: Block => { + val s = new StringBuilder + b.stmts.foreach { s ++= newline ++ _.serialize } + s.result + } + case a: Assert => s"assert ${a.pred.serialize}" + case EmptyStmt => "skip" + } + } + + implicit class WidthUtils(w: Width) { + def serialize(): String = + w match { + case UnknownWidth => "?" + case w: IntWidth => w.width.toString + } + } + + implicit class FieldDirUtils(dir: FieldDir) { + def serialize(): String = + dir match { + case Reverse => "flip " + case Default => "" + } + } + + implicit class FieldUtils(field: Field) { + def serialize(): String = + s"${field.dir.serialize} ${field.name} : ${field.tpe.serialize}" + } + + implicit class TypeUtils(t: Type) { + def serialize(): String = { + val commas = ", " // for mkString in BundleType + 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: BundleType => s"{ ${t.fields.map(_.serialize).mkString(commas)} }" + case t: VectorType => s"${t.tpe.serialize}[${t.size}]" + } + } + } + + implicit class PortDirUtils(p: PortDir) { + def serialize(): String = + p match { + case Input => "input" + case Output => "output" + } + } + + implicit class PortUtils(p: Port) { + def serialize(): String = + s"${p.dir.serialize} ${p.name} : ${p.tpe.serialize}" + } + + implicit class ModuleUtils(m: Module) { + def serialize(): String = { + var s = new StringBuilder(s"module ${m.name} : ") + withIndent { + s ++= m.ports.map(newline ++ _.serialize).mkString + s ++= newline ++ m.stmt.serialize + } + s.toString + } + } + + implicit class CircuitUtils(c: Circuit) { + def serialize(): 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.toString + } + } + + private var indentLevel = 0 + private def newline = "\n" + (" " * indentLevel) + private def indent(): Unit = indentLevel += 1 + private def unindent() { require(indentLevel > 0); indentLevel -= 1 } + private def withIndent(f: => Unit) { indent(); f; unindent() } + +} 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 + } +} diff --git a/src/main/stanza/compilers.stanza b/src/main/stanza/compilers.stanza index 1e978a2e..0ea9a367 100644 --- a/src/main/stanza/compilers.stanza +++ b/src/main/stanza/compilers.stanza @@ -25,7 +25,7 @@ public defmethod passes (c:StandardFlo) -> List<Pass> : CheckGenders() ExpandAccessors() LowerToGround() - ExpandIndexedConnects() + InlineIndexed() ExpandWhens() InferWidths() Pad() @@ -44,7 +44,7 @@ public defstruct StandardVerilog <: Compiler : public defmethod passes (c:StandardVerilog) -> List<Pass> : to-list $ [ RemoveSpecialChars() ;R - RemoveScopes() ;R + ;RemoveScopes() ;R CheckHighForm() ;R TempElimination() ;R ToWorkingIR() ;R -> W @@ -56,15 +56,17 @@ public defmethod passes (c:StandardVerilog) -> List<Pass> : CheckTypes() ;R ExpandAccessors() ;W LowerToGround() ;W - ExpandIndexedConnects() ;W + ;ExpandIndexedConnects() ;W + InlineIndexed() InferTypes() ;R CheckGenders() ;W ExpandWhens() ;W InferWidths() ;R + ToRealIR() ;W -> R + CheckWidths() ;R Pad() ;R ConstProp() ;R SplitExp() ;R - ToRealIR() ;W -> R CheckWidths() ;R CheckHighForm() ;R CheckLowForm() ;R diff --git a/src/main/stanza/custom-compiler.stanza b/src/main/stanza/custom-compiler.stanza index 36a6474f..0f43da58 100644 --- a/src/main/stanza/custom-compiler.stanza +++ b/src/main/stanza/custom-compiler.stanza @@ -28,7 +28,7 @@ public defmethod passes (c:InstrumentedVerilog) -> List<Pass> : CheckGenders() ExpandAccessors() LowerToGround() - ExpandIndexedConnects() + InlineIndexed() InferTypes() CheckGenders() ExpandWhens() diff --git a/src/main/stanza/ir-utils.stanza b/src/main/stanza/ir-utils.stanza index a234ff81..27acedb3 100644 --- a/src/main/stanza/ir-utils.stanza +++ b/src/main/stanza/ir-utils.stanza @@ -9,6 +9,11 @@ public defmulti print-debug (o:OutputStream, e:Expression|Stmt|Type|Port|Field|M ;============== GENSYM STUFF ====================== +defn generated? (s:String) -> False|Int : + for i in 1 to length(s) - 1 find : + val sub = substring(s,i + 1) + s[i] == '_' and digits?(sub) and s[i - 1] != '_' + public defn firrtl-gensym (s:Symbol) -> Symbol : firrtl-gensym(s,HashTable<Symbol,Int>(symbol-hash)) public defn firrtl-gensym (sym-hash:HashTable<Symbol,Int>) -> Symbol : @@ -31,11 +36,11 @@ public defn firrtl-gensym (s:Symbol,sym-hash:HashTable<Symbol,Int>) -> Symbol : sym-hash[s] = 0 s val s* = to-string(s) - val i* = for i in 0 to length(s*) - 1 find : - s*[i] == '_' and digits?(substring(s*,i + 1)) - match(i*) : + val i* = generated?(s*) + val nex = match(i*) : (i:False) : get-name(s) (i:Int) : get-name(to-symbol(substring(s*,0,i))) + nex public defn get-sym-hash (m:InModule) -> HashTable<Symbol,Int> : get-sym-hash(m,list()) @@ -45,8 +50,7 @@ public defn get-sym-hash (m:InModule,keywords:Streamable<Symbol>) -> HashTable<S sym-hash[k] = 0 defn add-name (s:Symbol) -> False : val s* = to-string(s) - val i* = for i in 0 to length(s*) - 1 find : - s*[i] == '_' and digits?(substring(s*,i + 1)) + val i* = generated?(s*) match(i*) : (i:False) : if key?(sym-hash,s) : diff --git a/src/main/stanza/passes.stanza b/src/main/stanza/passes.stanza index 99fb8172..0c812535 100644 --- a/src/main/stanza/passes.stanza +++ b/src/main/stanza/passes.stanza @@ -21,7 +21,8 @@ public val standard-passes = to-list $ [ CheckGenders() ExpandAccessors() LowerToGround() - ExpandIndexedConnects() + ;ExpandIndexedConnects() + InlineIndexed() ExpandWhens() InferWidths() Inline() @@ -67,17 +68,19 @@ public defstruct WIndex <: Expression : type: Type with: (as-method => true) gender: Gender with: (as-method => true) -defstruct ConnectToIndexed <: Stmt : +defstruct DecFromIndexer <: Stmt : info: FileInfo with: (as-method => true) index: Expression - locs: List<Expression> - exp: Expression + exps: List<Expression> + name: Symbol + type: Type -defstruct ConnectFromIndexed <: Stmt : +defstruct DecToIndexer <: Stmt : info: FileInfo with: (as-method => true) index: Expression - loc: Expression exps: List<Expression> + name: Symbol + type: Type ;================ WORKING IR UTILS ========================= @@ -259,12 +262,12 @@ defmethod print (o:OutputStream, e:WIndex) : print-all(o,[exp(e) "[" value(e) "]"]) print-debug(o,e as ?) -defmethod print (o:OutputStream, c:ConnectToIndexed) : - print-all(o, [locs(c) "[" index(c) "] := " exp(c)]) +defmethod print (o:OutputStream, c:DecFromIndexer) : + print-all(o, ["indexer " exps(c) "[" index(c) "] = " name(c) " : " type(c)]) print-debug(o,c as ?) -defmethod print (o:OutputStream, c:ConnectFromIndexed) : - print-all(o, [loc(c) " := " exps(c) "[" index(c) "]" ]) +defmethod print (o:OutputStream, c:DecToIndexer) : + print-all(o, ["indexer " name(c) " = " exps(c) "[" index(c) "] : " type(c)]) print-debug(o,c as ?) defmethod map (f: Expression -> Expression, e: WSubfield) : @@ -272,10 +275,10 @@ defmethod map (f: Expression -> Expression, e: WSubfield) : defmethod map (f: Expression -> Expression, e: WIndex) : WIndex(f(exp(e)), value(e), type(e), gender(e)) -defmethod map (f: Expression -> Expression, c:ConnectToIndexed) : - ConnectToIndexed(info(c),f(index(c)), map(f, locs(c)), f(exp(c))) -defmethod map (f: Expression -> Expression, c:ConnectFromIndexed) : - ConnectFromIndexed(info(c),f(index(c)), f(loc(c)), map(f, exps(c))) +defmethod map (f: Expression -> Expression, c:DecFromIndexer) : + DecFromIndexer(info(c),f(index(c)), map(f, exps(c)), name(c), type(c)) +defmethod map (f: Expression -> Expression, c:DecToIndexer) : + DecToIndexer(info(c),f(index(c)), map(f, exps(c)), name(c), type(c)) defmethod map (f: Type -> Type, e: WRef) : WRef(name(e), f(type(e)), kind(e), gender(e)) @@ -297,7 +300,7 @@ public defmethod short-name (b:RemoveSpecialChars) -> String : "rem-spec-chars" defn get-new-string (n:Char) -> String : switch {n == _} : - '_' : "_" + '_' : "__" '~' : "$A" '!' : "$B" '@' : "$C" @@ -850,12 +853,12 @@ defn resolve-genders (c:Circuit) : resolve-genders(m,c) ;;============== EXPAND ACCESSORS ================================ -; This pass expands non-memory accessors into ConnectToIndexed or +; This pass expands non-memory accessors into DecFromIndexer or ; ConnectFromIndexed. All elements of the vector are ; explicitly written out, then indexed. Depending on the gender -; of the accessor, it is transformed into ConnectToIndexed (male) or -; ConnectFromIndexed (female) -; Eg: +; of the accessor, it is transformed into DecFromIndexer (male) or +; DecToIndexer (female) + public defstruct ExpandAccessors <: Pass public defmethod pass (b:ExpandAccessors) -> (Circuit -> Circuit) : expand-accessors public defmethod name (b:ExpandAccessors) -> String : "Expand Accessors" @@ -876,18 +879,11 @@ defn expand-stmt (s:Stmt) -> Stmt : if mem? : s else : val vtype = type(type(source(s)) as VectorType) - val wire = DefWire(info(s),name(s),vtype) switch {acc-dir(s) == _} : - READ : Begin{list(wire,_)} $ ConnectFromIndexed( - info(s), - index(s), - WRef(name(wire),vtype,NodeKind(),FEMALE), - expand-vector(source(s))) - WRITE : Begin{list(wire,_)} $ ConnectToIndexed( - info(s), - index(s), - expand-vector(source(s)), - WRef(name(wire),vtype,NodeKind(),MALE)) + READ : DecToIndexer(info(s),index(s),expand-vector(source(s)), + name(s), vtype) + WRITE : DecFromIndexer(info(s),index(s),expand-vector(source(s)), + name(s), vtype) INFER : error("Shouldn't be here") RDWR : error("Haven't implemented RDWR yet") (s) : map(expand-stmt,s) @@ -897,8 +893,9 @@ defn expand-accessors (c:Circuit) : val modules* = for m in modules(c) map : match(m) : - (m:InModule) : InModule(info(m),name(m),ports(m),expand-stmt(body(m))) (m:ExModule) : m + (m:InModule) : + InModule(info(m),name(m),ports(m),expand-stmt(body(m))) ;;=============== LOWERING TO GROUND TYPES ============================= ; All non-ground (elevated) types (Vectors, Bundles) are expanded out to @@ -1091,46 +1088,31 @@ defn lower (body:Stmt) -> Stmt : switch fn ([x,y]) : lgender == x and rgender == y : [FEMALE,MALE] : Connect(info(s),l*,r*) [MALE,FEMALE] : Connect(info(s),r*,l*) - (s:ConnectFromIndexed) : Begin(ls) where : + (s:DecToIndexer|DecFromIndexer) : Begin(ls) where : val ctable = HashTable<Symbol,Vector<EF>>(symbol-hash) val index* = exp(head $ expand-expr(index(s))) for e in exps(s) do : - for (r in expand-expr(e),l in expand-expr(loc(s))) do : - val n = name(exp(l) as WRef) + for (r in expand-expr(e), ntf in generate-entry(name(s),type(s))) do: + val n = name(ntf) val x = get?(ctable,n,Vector<EF>()) add(x,r) ctable[n] = x - val ls = for l in expand-expr(loc(s)) map : - val n = name(exp(l) as WRef) - val lgender = FEMALE * flip(l) + val default-gender = match(s) : + (s:DecToIndexer) : FEMALE + (s:DecFromIndexer) : MALE + val ls = for ntf in generate-entry(name(s),type(s)) map : + val n = name(ntf) + val dec-gender = default-gender * flip(ntf) for x in ctable[n] do : - if (flip(x) * MALE) == lgender : error("Shouldn't be here") - val rgender = lgender * REVERSE - val l* = set-gender(exp(l),lgender,flip(l)) - val exps = to-list $ for e in ctable[n] map : set-gender(exp(e),rgender,flip(e)) - switch fn ([x,y]) : lgender == x and rgender == y : - [FEMALE,MALE] : ConnectFromIndexed(info(s),index*,l*,exps) - [MALE,FEMALE] : ConnectToIndexed(info(s),index*,exps,l*) - (s:ConnectToIndexed) : Begin(ls) where : - val ctable = HashTable<Symbol,Vector<EF>>(symbol-hash) - val index* = exp(head $ expand-expr(index(s))) - for e in locs(s) do : - for (l in expand-expr(e),r in expand-expr(exp(s))) do : - val n = name(exp(r) as WRef) - val x = get?(ctable,n,Vector<EF>()) - add(x,l) - ctable[n] = x - val ls = for r in expand-expr(exp(s)) map : - val n = name(exp(r) as WRef) - val rgender = MALE * flip(r) - for x in ctable[n] do : - if (flip(x) * FEMALE) == rgender : error("Shouldn't be here") - val lgender = rgender * REVERSE - val r* = set-gender(exp(r),rgender,flip(r)) - val locs = to-list $ for e in ctable[n] map : set-gender(exp(e),lgender,flip(e)) - switch fn ([x,y]) : lgender == x and rgender == y : - [FEMALE,MALE] : ConnectToIndexed(info(s),index*,locs,r*) - [MALE,FEMALE] : ConnectFromIndexed(info(s),index*,r*,locs) + if (flip(x) * swap(default-gender)) == dec-gender : + error("Shouldn't be here") + val exps-gender = swap(dec-gender) + ;val l* = set-gender(exp(l),lgender,flip(ntf)) + val exps = to-list $ for e in ctable[n] map : + set-gender(exp(e),exps-gender,flip(e)) + switch fn ([x,y]) : dec-gender == x and exps-gender == y : + [FEMALE,MALE] : DecToIndexer(info(s),index*,exps,name(ntf),type(ntf)) + [MALE,FEMALE] : DecFromIndexer(info(s),index*,exps,name(ntf),type(ntf)) (s:Conditionally) : Conditionally(info(s),exp(head $ expand-expr(pred(s))),lower-stmt(conseq(s)),lower-stmt(alt(s))) (s:Begin|EmptyStmt) : map(lower-stmt,s) @@ -1154,66 +1136,155 @@ defn lower-to-ground (c:Circuit) -> Circuit : ;;=========== CONVERT MULTI CONNECTS to WHEN ================ -; This pass converts ConnectToIndexed and ConnectFromIndexed +; This pass converts DecFromIndexer and DecToIndexer ; into a series of when statements. TODO what about initial ; values? -public defstruct ExpandIndexedConnects <: Pass -public defmethod pass (b:ExpandIndexedConnects) -> (Circuit -> Circuit) : expand-connect-indexed -public defmethod name (b:ExpandIndexedConnects) -> String : "Expand Indexed Connects" -public defmethod short-name (b:ExpandIndexedConnects) -> String : "expand-indexed-connects" - -defn expand-connect-indexed-stmt (s: Stmt,sh:HashTable<Symbol,Int>) -> Stmt : - defn equality (e1:Expression,e2:Expression) -> Expression : - DoPrim(EQUIV-OP,list(e1,e2),List(),UIntType(UnknownWidth())) - defn get-name (e:Expression) -> Symbol : - match(e) : - (e:WRef) : name(e) - (e:WSubfield) : symbol-join([get-name(exp(e)) `. name(e)]) - (e:WIndex) : symbol-join([get-name(exp(e)) `. to-symbol(value(e))]) - (e) : `T - match(s) : - (s:ConnectToIndexed) : Begin $ - if length(locs(s)) == 0 : list(EmptyStmt()) - else : - val ref = WRef(firrtl-gensym(get-name(index(s)),sh),type(index(s)),NodeKind(),UNKNOWN-GENDER) - append( - list(DefNode(info(s),name(ref),index(s))) - to-list $ - for (i in 0 to false, l in locs(s)) stream : Conditionally( - info(s), - equality(ref,UIntValue(BigIntLit(i),UnknownWidth())), - Connect(info(s),l,exp(s)), - EmptyStmt() - ) - ) - (s:ConnectFromIndexed) : Begin $ - if length(exps(s)) == 0 : list(EmptyStmt()) - else : - val ref = WRef(firrtl-gensym(get-name(index(s)),sh),type(index(s)),NodeKind(),UNKNOWN-GENDER) - append( - list(Connect(info(s),loc(s),head(exps(s))),DefNode(info(s),name(ref),index(s))) - to-list $ - for (i in 1 to false, e in tail(exps(s))) stream : Conditionally( - info(s), - equality(ref,UIntValue(BigIntLit(i),UnknownWidth())), - Connect(info(s),loc(s),e), - EmptyStmt() - ) - ) - (s) : map(expand-connect-indexed-stmt{_,sh},s) - -defn expand-connect-indexed (m: Module) -> Module : - match(m) : - (m:InModule) : - val sh = get-sym-hash(m,keys(v-keywords)) - InModule(info(m),name(m),ports(m),expand-connect-indexed-stmt(body(m),sh)) - (m:ExModule) : m +;public defstruct ExpandIndexedConnects <: Pass +;public defmethod pass (b:ExpandIndexedConnects) -> (Circuit -> Circuit) : expand-connect-indexed +;public defmethod name (b:ExpandIndexedConnects) -> String : "Expand Indexed Connects" +;public defmethod short-name (b:ExpandIndexedConnects) -> String : "expand-indexed-connects" +; +;defn expand-connect-indexed-stmt (s: Stmt,sh:HashTable<Symbol,Int>) -> Stmt : +; defn equality (e1:Expression,e2:Expression) -> Expression : +; DoPrim(EQUIV-OP,list(e1,e2),List(),UIntType(UnknownWidth())) +; defn get-name (e:Expression) -> Symbol : +; match(e) : +; (e:WRef) : name(e) +; (e:WSubfield) : symbol-join([get-name(exp(e)) `. name(e)]) +; (e:WIndex) : symbol-join([get-name(exp(e)) `. to-symbol(value(e))]) +; (e) : `F +; match(s) : +; (s:DecFromIndexer) : Begin $ +; if length(locs(s)) == 0 : list(EmptyStmt()) +; else : +; val ref = WRef(firrtl-gensym(get-name(index(s)),sh),type(index(s)),NodeKind(),UNKNOWN-GENDER) +; append( +; list(DefNode(info(s),name(ref),index(s))) +; to-list $ +; for (i in 0 to false, l in locs(s)) stream : Conditionally( +; info(s), +; equality(ref,UIntValue(BigIntLit(i),UnknownWidth())), +; Connect(info(s),l,exp(s)), +; EmptyStmt() +; ) +; ) +; (s:DecToIndexer) : Begin $ +; if length(exps(s)) == 0 : list(EmptyStmt()) +; else : +; val ref = WRef(firrtl-gensym(get-name(index(s)),sh),type(index(s)),NodeKind(),UNKNOWN-GENDER) +; append( +; list(Connect(info(s),loc(s),head(exps(s))),DefNode(info(s),name(ref),index(s))) +; to-list $ +; for (i in 1 to false, e in tail(exps(s))) stream : Conditionally( +; info(s), +; equality(ref,UIntValue(BigIntLit(i),UnknownWidth())), +; Connect(info(s),loc(s),e), +; EmptyStmt() +; ) +; ) +; (s) : map(expand-connect-indexed-stmt{_,sh},s) +; +;defn expand-connect-indexed (m: Module) -> Module : +; match(m) : +; (m:InModule) : +; val sh = get-sym-hash(m,keys(v-keywords)) +; InModule(info(m),name(m),ports(m),expand-connect-indexed-stmt(body(m),sh)) +; (m:ExModule) : m +; +;defn expand-connect-indexed (c: Circuit) -> Circuit : +; Circuit(info(c),modules*, main(c)) where : +; val modules* = +; for m in modules(c) map : +; expand-connect-indexed(m) + +;;================ INLINE ACCESSORS ========================= +; This pass inlines all accessors to non-memory vector typed +; components. + +public defstruct InlineIndexed <: Pass +public defmethod pass (b:InlineIndexed) -> (Circuit -> Circuit) : inline-indexed +public defmethod name (b:InlineIndexed) -> String : "Inline Indexers" +public defmethod short-name (b:InlineIndexed) -> String : "inline-indexers" + +;------------ Helper Functions -------------- +defn get-name (e:Expression) -> Symbol : + match(e) : + (e:WRef) : name(e) + (e:WSubfield) : symbol-join([get-name(exp(e)) `. name(e)]) + (e:WIndex) : symbol-join([get-name(exp(e)) `. to-symbol(value(e))]) + (e) : `F + +defn equality (e1:Expression,i:Int) -> Expression : + DoPrim(EQUIV-OP,list(e1,UIntValue(BigIntLit(i),UnknownWidth())), + List(),UIntType(UnknownWidth())) + + +;------------- Inline Accessors ------------- + + + +defn inline-indexed-m (m:InModule) -> InModule : + val sh = get-sym-hash(m,keys(v-keywords)) + val ih = HashTable<Symbol,Stmt>(symbol-hash) + defn inline-indexed-s (s:Stmt) -> Stmt : + val stmts = Vector<Stmt>() + + defn expand-indexed (indexer:WRef,indexed-dec:Stmt) -> Expression : + val index = index(indexed-dec as DecFromIndexer|DecToIndexer) + val index-name = firrtl-gensym(get-name(index),sh) + val index-ref = WRef(index-name,type(index),NodeKind(),MALE) + + val replace-name = firrtl-gensym(get-name(indexer),sh) + val replace-ref = WRef(replace-name,type(indexer),kind(indexer),gender(indexer)) + + add(stmts, DefWire(info(indexed-dec),name(replace-ref),type(replace-ref))) + add(stmts, DefNode(info(indexed-dec),index-name,index)) + match(indexed-dec) : + (s:DecFromIndexer) : + if (gender(replace-ref) != FEMALE) : error("Shouldn't be here") + for (i in 0 to false, e in exps(s)) do : + val eq = equality(index-ref,i) + val cond = Conditionally(info(s),eq,Connect(info(s),e,replace-ref),EmptyStmt()) + add(stmts,map(inline-indexed-s,cond)) + (s:DecToIndexer) : + if (gender(replace-ref) != MALE) : error("Shouldn't be here") + val cnct = Connect(info(s),replace-ref,head(exps(s))) + add(stmts,map(inline-indexed-e,cnct)) + ;println-all(["exps: " exps(s)]) + for (i in 1 to false, e in tail(exps(s))) do : + val eq = equality(index-ref,i) + val cond = Conditionally(info(s),eq,Connect(info(s),replace-ref,e),EmptyStmt()) + add(stmts,map(inline-indexed-s,cond)) + replace-ref + + defn inline-indexed-e (e:Expression) -> Expression : + match(map(inline-indexed-e,e)) : + (e:WRef) : + if key?(ih,name(e)) : + val indexer = ih[name(e)] + expand-indexed(e,indexer) + else : e + (e) : e -defn expand-connect-indexed (c: Circuit) -> Circuit : - Circuit(info(c),modules*, main(c)) where : - val modules* = - for m in modules(c) map : - expand-connect-indexed(m) + match(s) : + (s:DecFromIndexer|DecToIndexer) : + ih[name(s)] = s + firrtl-gensym(name(s),sh) + add(stmts,EmptyStmt()) + (s) : + val s* = map(inline-indexed-e,s) + add(stmts,map(inline-indexed-s,s*)) + if length(stmts) == 1 : stmts[0] + else : Begin(to-list(stmts)) + + InModule(info(m),name(m),ports(m),inline-indexed-s(body(m))) + +public defn inline-indexed (c:Circuit) -> Circuit : + Circuit{info(c),_,main(c)} $ + for m in modules(c) map : + match(m) : + (m:ExModule) : m + (m:InModule) : inline-indexed-m(m) ;;================ EXPAND WHENS ============================= ; This pass does three things: remove last connect semantics, @@ -1448,7 +1519,9 @@ defn merge-resets (assign:HashTable<Symbol,SymbolicValue>, resets:HashTable<Symb val table = HashTable<Symbol,SymbolicValue>(symbol-hash) for i in get-unique-keys(list(assign,resets)) do : table[i] = match(get?(assign,i,false),get?(resets,i,false)) : - (a:SymbolicValue,r:SymbolicValue) : SVMux(rsignals[i],r,a) + (a:SymbolicValue,r:SymbolicValue) : + if r typeof SVNul : a + else : SVMux(rsignals[i],r,a) (a:SymbolicValue,r:False) : a (a:False,r:SymbolicValue) : SVMux(rsignals[i],r,SVNul()) (a:False,r:False) : error("Shouldn't be here") @@ -1466,8 +1539,9 @@ defn build-tables (s:Stmt, flattn[name(s)] = true (s:DefRegister) : assign[name(s)] = SVNul() - flattn[name(s)] = false + flattn[name(s)] = true rsignals[name(s)] = reset(s) + resets[name(s)] = SVNul() (s:DefAccessor) : assign[name(s)] = SVNul() flattn[name(s)] = false @@ -1513,6 +1587,12 @@ defn build-tables (s:Stmt, for x in assign-a do : println-debug(x) println-debug("TABLE") for x in assign do : println-debug(x) + println-debug("RESET-C") + for x in resets-c do : println-debug(x) + println-debug("RESET-A") + for x in resets-a do : println-debug(x) + println-debug("RESET") + for x in resets do : println-debug(x) (s:Connect|OnReset) : val key* = match(loc(s)) : (e:WRef) : name(e) @@ -2171,6 +2251,33 @@ defn inline-instances (c:Circuit) : val top = (for m in modules(c) find : name(m) == main(c)) as InModule Circuit(info(c),list(InModule(info(top),name(top),ports(top),inline-inst(body(top)))),main(c)) +;================= Bring to Real IR ======================== +; Returns a new Circuit with only real IR nodes. +public defstruct ToRealIR <: Pass +public defmethod pass (b:ToRealIR) -> (Circuit -> Circuit) : to-real-ir +public defmethod name (b:ToRealIR) -> String : "Real IR" +public defmethod short-name (b:ToRealIR) -> String : "real-ir" + +defn to-real-ir (c:Circuit) : + defn to-exp (e:Expression) : + match(map(to-exp,e)) : + (e:WRef) : Ref(name(e), type(e)) + (e:WSubfield) : Subfield(exp(e),name(e),type(e)) + (e:WIndex) : error("Shouldn't be here") + (e) : e + defn to-stmt (s:Stmt) : + match(map(to-exp,s)) : + (e:DecFromIndexer) : error("Shouldn't be here") + (e:DecToIndexer) : error("Shouldn't be here") + (e) : map(to-stmt,e) + + Circuit(info(c),modules*, main(c)) where : + val modules* = + for m in modules(c) map : + match(m) : + (m:InModule) : InModule(info(m),name(m), ports(m), to-stmt(body(m))) + (m:ExModule) : m + ;================= Split Expressions ======================== ; Intended to only work on low firrtl @@ -2181,7 +2288,7 @@ public defmethod short-name (b:SplitExp) -> String : "split-expressions" defn full-name (e:Expression) -> Symbol|False : match(e) : - (e:WRef) : name(e) + (e:Ref) : name(e) (e) : false defn split-exp (c:Circuit) : @@ -2195,13 +2302,13 @@ defn split-exp (c:Circuit) : ;all-same-type? = false ;if not all-same-type? : ;val n* = - ; if n typeof False : firrtl-gensym(`T,sh) + ; if n typeof False : firrtl-gensym(`F,sh) ; else : firrtl-gensym(symbol-join([n as Symbol temp-delin]),sh) val n* = - if n typeof False : firrtl-gensym(`T,sh) + if n typeof False : firrtl-gensym(`F,sh) else : firrtl-gensym(n as Symbol,sh) add(v,DefNode(info,n*,map(split-exp-e{_,n,info},e))) - WRef(n*,type(e),NodeKind(),UNKNOWN-GENDER) + Ref(n*,type(e)) ;else : e (e) : map(split-exp-e{_,n,info},e) defn f (s:Stmt) -> False: split-exp-s(s,v,sh) @@ -2242,33 +2349,6 @@ defn split-exp (c:Circuit) : InModule(info(m),name(m),ports(m),Begin(to-list(v))) (m:ExModule) : m -;================= Bring to Real IR ======================== -; Returns a new Circuit with only real IR nodes. -public defstruct ToRealIR <: Pass -public defmethod pass (b:ToRealIR) -> (Circuit -> Circuit) : to-real-ir -public defmethod name (b:ToRealIR) -> String : "Real IR" -public defmethod short-name (b:ToRealIR) -> String : "real-ir" - -defn to-real-ir (c:Circuit) : - defn to-exp (e:Expression) : - match(map(to-exp,e)) : - (e:WRef) : Ref(name(e), type(e)) - (e:WSubfield) : Subfield(exp(e),name(e),type(e)) - (e:WIndex) : error("Shouldn't be here") - (e) : e - defn to-stmt (s:Stmt) : - match(map(to-exp,s)) : - (e:ConnectToIndexed) : error("Shouldn't be here") - (e:ConnectFromIndexed) : error("Shouldn't be here") - (e) : map(to-stmt,e) - - Circuit(info(c),modules*, main(c)) where : - val modules* = - for m in modules(c) map : - match(m) : - (m:InModule) : InModule(info(m),name(m), ports(m), to-stmt(body(m))) - (m:ExModule) : m - ;================= Special Rename ======================== ; Returns a new Circuit with only real IR nodes. public defstruct SpecialRename <: Pass : @@ -2381,7 +2461,7 @@ defn pad-widths-e (desired:Long,e:Expression) -> Expression : else : map(pad-widths-e{new-desired,_},e) trim-pad(desired, e*) - (e:WRef|WSubfield|WIndex) : + (e:Ref|Subfield|Index) : trim-pad(desired, e) (e:UIntValue) : val i = int-width!(type(e)) diff --git a/src/main/stanza/verilog.stanza b/src/main/stanza/verilog.stanza index c4a52d5e..1a495835 100644 --- a/src/main/stanza/verilog.stanza +++ b/src/main/stanza/verilog.stanza @@ -155,6 +155,10 @@ defn emit (e:Expression) -> String : for x in tail(args(e)) do : v = concat(v, [" ^ " emit(x)]) v + (e) : + println(["Expression:" e]) + error("Unknown expression") + defn emit-module (m:InModule) : diff --git a/test/errors/high-form/RemoveScope.fir b/test/errors/high-form/RemoveScope.fir index 395c6492..16498fd8 100644 --- a/test/errors/high-form/RemoveScope.fir +++ b/test/errors/high-form/RemoveScope.fir @@ -1,4 +1,5 @@ ; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s +; XFAIL: * ; CHECK: Done! circuit Top : diff --git a/test/errors/high-form/Unique.fir b/test/errors/high-form/Unique.fir index ea2bb881..60201b92 100644 --- a/test/errors/high-form/Unique.fir +++ b/test/errors/high-form/Unique.fir @@ -1,5 +1,4 @@ ; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s -; XFAIL: * ; CHECK: Reference x does not have a unique name. ; CHECK: Reference p does not have a unique name. diff --git a/test/features/Link.fir b/test/features/Link.fir index 721f4727..040ac2c5 100644 --- a/test/features/Link.fir +++ b/test/features/Link.fir @@ -1,4 +1,4 @@ -; RUN: firrtl -i %s -m /Users/cusgadmin/code/stanza/firrtl/test/features/Queue.fir -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s +; RUN: firrtl -i %s -m %S/Queue.fir -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s ;CHECK: Lower To Ground circuit Top : module Top : diff --git a/test/passes/expand-accessors/accessor-mem.fir b/test/passes/expand-accessors/accessor-mem.fir index 1c055b48..6f8b63e3 100644 --- a/test/passes/expand-accessors/accessor-mem.fir +++ b/test/passes/expand-accessors/accessor-mem.fir @@ -8,16 +8,17 @@ circuit top : wire i : UInt<4> i := UInt(1) infer accessor a = m[i] ;CHECK: read accessor a = m[i] - infer accessor b = a[i] ;CHECK: b := (a[0] a[1])[i] - infer accessor c = b[i] ;CHECK: c := (b[0] b[1])[i] + infer accessor b = a[i] ;CHECK: indexer b = (a[0] a[1])[i] : UInt<32>[2] + infer accessor c = b[i] ;CHECK: indexer c = (b[0] b[1])[i] : UInt<32> wire j : UInt<32> j := c infer accessor x = m[i] ;CHECK: write accessor x = m[i] - infer accessor y = x[i] ;CHECK: (x[0] x[1])[i] := y + infer accessor y = x[i] ;CHECK: indexer (x[0] x[1])[i] = y : UInt<32>[2] y[0] := UInt(1) y[1] := UInt(1) - infer accessor z = y[i] ;CHECK: (y[0] y[1])[i] := z + infer accessor z = y[i] ;CHECK: indexer (y[0] y[1])[i] = z : UInt<32> z := j ; CHECK: Finished Expand Accessors +; CHECK: Done! diff --git a/test/passes/expand-accessors/accessor-vec.fir b/test/passes/expand-accessors/accessor-vec.fir index c505fbaf..96a5c74c 100644 --- a/test/passes/expand-accessors/accessor-vec.fir +++ b/test/passes/expand-accessors/accessor-vec.fir @@ -14,19 +14,19 @@ circuit top : m[1][1][1] := UInt(1) wire i : UInt i := UInt(1) - infer accessor a = m[i] ;CHECK: a := (m[0] m[1])[i] - infer accessor b = a[i] ;CHECK: b := (a[0] a[1])[i] - infer accessor c = b[i] ;CHECK: c := (b[0] b[1])[i] + infer accessor a = m[i] ;CHECK: indexer a = (m[0] m[1])[i] : UInt<32>[2][2] + infer accessor b = a[i] ;CHECK: indexer b = (a[0] a[1])[i] : UInt<32>[2] + infer accessor c = b[i] ;CHECK: indexer c = (b[0] b[1])[i] : UInt<32> wire j : UInt j := c - infer accessor x = m[i] ;CHECK: (m[0] m[1])[i] := x + infer accessor x = m[i] ;CHECK: indexer (m[0] m[1])[i] = x : UInt<32>[2][2] x[0][0] := UInt(1) x[1][0] := UInt(1) x[0][1] := UInt(1) x[1][1] := UInt(1) - infer accessor y = x[i] ;CHECK: (x[0] x[1])[i] := y - infer accessor z = y[i] ;CHECK: (y[0] y[1])[i] := z + infer accessor y = x[i] ;CHECK: indexer (x[0] x[1])[i] = y : UInt<32>[2] + infer accessor z = y[i] ;CHECK: indexer (y[0] y[1])[i] = z : UInt<32> y[0] := UInt(1) y[1] := UInt(1) z := j @@ -34,13 +34,14 @@ circuit top : wire p : {n : UInt<32>[2]} p.n[0] := UInt(1) p.n[1] := UInt(1) - infer accessor q = p.n[i] ;CHECK: (p.n[0] p.n[1])[i] := q + infer accessor q = p.n[i] ;CHECK: indexer (p.n[0] p.n[1])[i] = q : UInt<32> q := j wire r : {m : UInt<32>}[2] r[0].m := UInt(1) r[1].m := UInt(1) - infer accessor s = r[i] ;CHECK: s := (r[0] r[1])[i] + infer accessor s = r[i] ;CHECK: indexer s = (r[0] r[1])[i] : { m : UInt<32>} j := s.m ; CHECK: Finished Expand Accessors +; CHECK: Done! diff --git a/test/passes/expand-accessors/simple.fir b/test/passes/expand-accessors/simple.fir new file mode 100644 index 00000000..7f5a4eb8 --- /dev/null +++ b/test/passes/expand-accessors/simple.fir @@ -0,0 +1,15 @@ +; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s + +;CHECK: Expand Accessors +circuit top : + module top : + output o : UInt + wire m : UInt<32>[2] + wire i : UInt + m[0] := UInt("h1") + m[1] := UInt("h1") + i := UInt("h1") + infer accessor a = m[i] ;CHECK: indexer a = (m$0 m$1)[i] : UInt<32> + o := a + + diff --git a/test/passes/expand-accessors/simple2.fir b/test/passes/expand-accessors/simple2.fir new file mode 100644 index 00000000..54f8a507 --- /dev/null +++ b/test/passes/expand-accessors/simple2.fir @@ -0,0 +1,17 @@ +; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s + +;CHECK: Expand Accessors +circuit top : + module top : + output o1 : UInt + output o2 : UInt + wire m : UInt<32>[2] + wire i : UInt + m[0] := UInt("h1") + m[1] := UInt("h1") + i := UInt("h1") + infer accessor a = m[i] ;CHECK: indexer a = (m$0 m$1)[i] : UInt<32> + o1 := a + o2 := a + + diff --git a/test/passes/expand-whens/reg-and-when.fir b/test/passes/expand-whens/reg-and-when.fir index 9d23acf9..ac678b6d 100644 --- a/test/passes/expand-whens/reg-and-when.fir +++ b/test/passes/expand-whens/reg-and-when.fir @@ -1,5 +1,5 @@ ; RUN: firrtl -i %s -o %s.v -X verilog -p cd 2>&1 | tee %s.out ; cat %s.v | FileCheck %s -; CHECK: out_slow_bits <= fromhost_q$deq$valid ? fromhost_q$deq$bits : tohost_q$deq$bits; +; CHECK: out__slow__bits <= fromhost__q$deq$valid ? fromhost__q$deq$bits : tohost__q$deq$bits; circuit Top : module Top : input clock : Clock diff --git a/test/passes/expand-whens/reg-dwoc.fir b/test/passes/expand-whens/reg-dwoc.fir index c5ea4b41..60bd43a8 100644 --- a/test/passes/expand-whens/reg-dwoc.fir +++ b/test/passes/expand-whens/reg-dwoc.fir @@ -1,4 +1,4 @@ -; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s +; RUN: firrtl -i %s -o %s.v -X verilog -p cd 2>&1 | tee %s.out | FileCheck %s circuit top : module top : input clk : Clock diff --git a/test/passes/expand-whens/reg-wdc.fir b/test/passes/expand-whens/reg-wdc.fir index a748dcc2..c6439860 100644 --- a/test/passes/expand-whens/reg-wdc.fir +++ b/test/passes/expand-whens/reg-wdc.fir @@ -1,5 +1,4 @@ ; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s -; XFAIL: * circuit top : module top : input clk : Clock @@ -16,8 +15,9 @@ circuit top : ; CHECK: module top : ; CHECK: wire p : UInt ; CHECK: reg r : UInt, clk, reset -; CHECK: p := UInt("h00000001") -; CHECK-NOT: when p : r := UInt("h00000002") +; CHECK: p := UInt("h1") +; CHECK-NOT: when p : r := UInt("h2") ; CHECK: Finished Expand Whens +; CHECK: Done! diff --git a/test/passes/expand-whens/reg-wdoc.fir b/test/passes/expand-whens/reg-wdoc.fir index 646397b8..de0bbfd6 100644 --- a/test/passes/expand-whens/reg-wdoc.fir +++ b/test/passes/expand-whens/reg-wdoc.fir @@ -1,5 +1,4 @@ ; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s -; XFAIL: * circuit top : module top : input clk : Clock @@ -17,8 +16,8 @@ circuit top : ; CHECK: module top : ; CHECK: wire p : UInt ; CHECK: reg r : UInt, clk, reset -; CHECK: p := UInt("h00000001") -; CHECK-NOT: when p : r := mux(reset, UInt("h00000001"), UInt("h00000002")) +; CHECK: p := UInt("h1") +; CHECK-NOT: when p : r := mux(reset, UInt("h1"), UInt("h2")) ; CHECK: Finished Expand Whens diff --git a/test/passes/infer-types/primops.fir b/test/passes/infer-types/primops.fir index 94f481f7..ac057c68 100644 --- a/test/passes/infer-types/primops.fir +++ b/test/passes/infer-types/primops.fir @@ -157,10 +157,10 @@ circuit top : node wnot = not(a) ;CHECK: node wnot = not(a@<t:UInt>)@<t:UInt> node unot = not(c) ;CHECK: node unot = not(c@<t:SInt>)@<t:SInt> - node wand_ = and(a, b) ;CHECK: node wand_ = and(a@<t:UInt>, b@<t:UInt>)@<t:UInt> + node WAND = and(a, b) ;CHECK: node WAND = and(a@<t:UInt>, b@<t:UInt>)@<t:UInt> node uand = and(c, d) ;CHECK: node uand = and(c@<t:SInt>, d@<t:SInt>)@<t:SInt> - node wor_ = or(a, b) ;CHECK: node wor_ = or(a@<t:UInt>, b@<t:UInt>)@<t:UInt> + node WOR = or(a, b) ;CHECK: node WOR = or(a@<t:UInt>, b@<t:UInt>)@<t:UInt> node uor = or(c, d) ;CHECK: node uor = or(c@<t:SInt>, d@<t:SInt>)@<t:SInt> node wxor = xor(a, b) ;CHECK: node wxor = xor(a@<t:UInt>, b@<t:UInt>)@<t:UInt> diff --git a/test/passes/expand-connect-indexed/bundle-vecs.fir b/test/passes/inline-indexers/bundle-vecs.fir index c41794e3..28826056 100644 --- a/test/passes/expand-connect-indexed/bundle-vecs.fir +++ b/test/passes/inline-indexers/bundle-vecs.fir @@ -1,6 +1,6 @@ ; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s -; CHECK: Expand Indexed Connects +; CHECK: Inline Indexers circuit top : module top : wire i : UInt @@ -20,16 +20,17 @@ circuit top : infer accessor b = a[i] - ; CHECK: wire b{{[_$]+}}x : UInt<32> - ; CHECK: wire b{{[_$]+}}y : UInt<32> - ; CHECK: b{{[_$]+}}x := a{{[_$]+}}0{{[_$]+}}x + ; CHECK: wire b{{[_$]+}}x_1 : UInt<32> ; CHECK: node i_1 = i - ; CHECK: when eqv(i_1, UInt("h1")) : b{{[_$]+}}x := a{{[_$]+}}1{{[_$]+}}x + ; CHECK: b{{[_$]+}}x_1 := a{{[_$]+}}0{{[_$]+}}x + ; CHECK: when eqv(i_1, UInt("h1")) : b{{[_$]+}}x_1 := a{{[_$]+}}1{{[_$]+}}x + ; CHECK: wire b{{[_$]+}}y_1 : UInt<32> ; CHECK: node i_2 = i - ; CHECK: when eqv(i_2, UInt("h0")) : a{{[_$]+}}0{{[_$]+}}y := b{{[_$]+}}y - ; CHECK: when eqv(i_2, UInt("h1")) : a{{[_$]+}}1{{[_$]+}}y := b{{[_$]+}}y + ; CHECK: when eqv(i_2, UInt("h0")) : a{{[_$]+}}0{{[_$]+}}y := b{{[_$]+}}y_1 + ; CHECK: when eqv(i_2, UInt("h1")) : a{{[_$]+}}1{{[_$]+}}y := b{{[_$]+}}y_1 j := b.x b.y := UInt(1) -; CHECK: Finished Expand Indexed Connects +; CHECK: Finished Inline Indexers +; CHECK: Done! diff --git a/test/passes/expand-connect-indexed/init-vecs.fir b/test/passes/inline-indexers/init-vecs.fir index 7d64a117..149215c3 100644 --- a/test/passes/expand-connect-indexed/init-vecs.fir +++ b/test/passes/inline-indexers/init-vecs.fir @@ -1,7 +1,6 @@ ; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s -; XFAIL: * -; CHECK: Expand Indexed Connects +; CHECK: Inline Indexers circuit top : module top : wire outs : UInt<32>[2][1] diff --git a/test/passes/inline-indexers/simple.fir b/test/passes/inline-indexers/simple.fir new file mode 100644 index 00000000..ca186e97 --- /dev/null +++ b/test/passes/inline-indexers/simple.fir @@ -0,0 +1,20 @@ +; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s + +;CHECK: Inline Indexers +circuit top : + module top : + output o : UInt + wire m : UInt<32>[2] + wire i : UInt + m[0] := UInt("h1") + m[1] := UInt("h1") + i := UInt("h1") + infer accessor a = m[i] + o := a + +;CHECK: a_1 := m$0 +;CHECK: when eqv(i_1, UInt("h1")) : a_1 := m$1 + + + +;CHECK: Done! diff --git a/test/passes/inline-indexers/simple2.fir b/test/passes/inline-indexers/simple2.fir new file mode 100644 index 00000000..3b7d92af --- /dev/null +++ b/test/passes/inline-indexers/simple2.fir @@ -0,0 +1,26 @@ +; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s + +;CHECK: Inline Indexers +circuit top : + module top : + output o1 : UInt + output o2 : UInt + wire m : UInt<32>[2] + wire i : UInt + m[0] := UInt("h1") + m[1] := UInt("h1") + i := UInt("h1") + infer accessor a = m[i] + o1 := a + o2 := a + +;CHECK: wire a_1 : UInt<32> +;CHECK: a_1 := m$0 +;CHECK: when eqv(i_1, UInt("h1")) : a_1 := m$1 +;CHECK: wire a_2 : UInt<32> +;CHECK: a_2 := m$0 +;CHECK: when eqv(i_2, UInt("h1")) : a_2 := m$1 + + + +;CHECK: Done! diff --git a/test/passes/inline-indexers/simple3.fir b/test/passes/inline-indexers/simple3.fir new file mode 100644 index 00000000..688958a0 --- /dev/null +++ b/test/passes/inline-indexers/simple3.fir @@ -0,0 +1,20 @@ +; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s + +;CHECK: Inline Indexers +circuit top : + module top : + input in : UInt<32> + input i : UInt<1> + wire m : UInt<32>[2] + m[0] := UInt("h1") + m[1] := UInt("h1") + infer accessor a = m[i] + a := in + +;CHECK: wire a_1 : UInt<32> +;CHECK: when eqv(i_1, UInt("h0")) : m$0 := a_1 +;CHECK: when eqv(i_1, UInt("h1")) : m$1 := a_1 + + + +;CHECK: Done! diff --git a/test/passes/inline-indexers/simple4.fir b/test/passes/inline-indexers/simple4.fir new file mode 100644 index 00000000..df045456 --- /dev/null +++ b/test/passes/inline-indexers/simple4.fir @@ -0,0 +1,25 @@ +; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s + +;CHECK: Inline Indexers +circuit top : + module top : + input in : {x : UInt<32>, y : UInt<32>} + input i : UInt<1> + wire m : {x : UInt<32>, y : UInt<32>}[2] + m[0].x := UInt("h1") + m[0].y := UInt("h1") + m[1].x := UInt("h1") + m[1].y := UInt("h1") + infer accessor a = m[i] + a.x := in.x + +;CHECK: wire a$x_1 : UInt<32> +;CHECK: node i_1 = i +;CHECK: when eqv(i_1, UInt("h0")) : m$0$x := a$x_1 +;CHECK: when eqv(i_1, UInt("h1")) : m$1$x := a$x_1 +;CHECK: a$x_1 := in$x +;CHECK: Finished Inline Indexers +;CHECK: Done! + + + diff --git a/test/passes/inline-indexers/simple5.fir b/test/passes/inline-indexers/simple5.fir new file mode 100644 index 00000000..1da83cab --- /dev/null +++ b/test/passes/inline-indexers/simple5.fir @@ -0,0 +1,21 @@ +; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s + +;CHECK: Inline Indexers +circuit top : + module top : + output o : UInt + o := UInt(1) + wire m : UInt<32>[2] + wire i : UInt + m[0] := UInt("h1") + m[1] := UInt("h1") + i := UInt("h1") + when i : + infer accessor a = m[i] + o := a + +;CHECK: when i : +;CHECK: a_1 := m$0 +;CHECK: when eqv(i_1, UInt("h1")) : a_1 := m$1 +;CHECK: Finished Inline Indexers +;CHECK: Done! diff --git a/test/passes/inline-indexers/simple6.fir b/test/passes/inline-indexers/simple6.fir new file mode 100644 index 00000000..e94efc7a --- /dev/null +++ b/test/passes/inline-indexers/simple6.fir @@ -0,0 +1,45 @@ +; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s + +;CHECK: Inline Indexers +circuit top : + module top : + input value : UInt<32> + input in : {x : UInt<32>, y : UInt<32>} + wire m :{x : UInt<32>, y : UInt<32>}[2][2] + wire i : UInt + wire j : UInt + + m[0][0] := in + m[1][0] := in + m[0][1] := in + m[1][1] := in + i := UInt("h1") + j := UInt("h1") + + write accessor a = m[i] + write accessor b = a[j] + b.x := value + +;CHECK: wire b$x_1 : UInt<32> +;CHECK: node j_1 = j +;CHECK: when eqv(j_1, UInt("h0")) : +;CHECK: wire a$0$x_1 : UInt<32> +;CHECK: node i_1 = i +;CHECK: when eqv(i_1, UInt("h0")) : +;CHECK: m$0$0$x := a$0$x_1 +;CHECK: when eqv(i_1, UInt("h1")) : +;CHECK: m$1$0$x := a$0$x_1 +;CHECK: a$0$x_1 := b$x_1 +;CHECK: when eqv(j_1, UInt("h1")) : +;CHECK: wire a$1$x_1 : UInt<32> +;CHECK: node i_2 = i +;CHECK: when eqv(i_2, UInt("h0")) : +;CHECK: m$0$1$x := a$1$x_1 +;CHECK: when eqv(i_2, UInt("h1")) : +;CHECK: m$1$1$x := a$1$x_1 +;CHECK: a$1$x_1 := b$x_1 +;CHECK: b$x_1 := value + + + +;CHECK: Done! diff --git a/test/passes/inline-indexers/simple7.fir b/test/passes/inline-indexers/simple7.fir new file mode 100644 index 00000000..cc9c6231 --- /dev/null +++ b/test/passes/inline-indexers/simple7.fir @@ -0,0 +1,13 @@ +; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s + +;CHECK: Inline Indexers +circuit top : + module top : + output out : UInt<64> + input index : UInt<1> + wire T_292 : UInt<64>[2] + T_292[0] := UInt(1) + T_292[1] := UInt(1) + infer accessor T_297 = T_292[index] + out := T_297 +;CHECK: Done! diff --git a/test/passes/inline-indexers/simple8.fir b/test/passes/inline-indexers/simple8.fir new file mode 100644 index 00000000..a02395a7 --- /dev/null +++ b/test/passes/inline-indexers/simple8.fir @@ -0,0 +1,240 @@ +; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s + +;CHECK: Inline Indexers +circuit top : + module top : + output resp : UInt<128>[4] + input write : {flip ready : UInt<1>, valid : UInt<1>, bits : {way_en : UInt<4>, addr : UInt<12>, wmask : UInt<2>, data : UInt<128>}} + input read : {flip ready : UInt<1>, valid : UInt<1>, bits : {way_en : UInt<4>, addr : UInt<12>}} + input clock : Clock + input reset : UInt<1> + + resp[0] := UInt<1>("h00") + resp[1] := UInt<1>("h00") + resp[2] := UInt<1>("h00") + resp[3] := UInt<1>("h00") + write.ready := UInt<1>("h00") + read.ready := UInt<1>("h00") + node waddr = shr(write.bits.addr, 4) + node raddr = shr(read.bits.addr, 4) + node T_65 = bits(write.bits.way_en, 1, 0) + node T_66 = bits(read.bits.way_en, 1, 0) + wire T_75 : UInt<128>[2] + T_75[0] := UInt<1>("h00") + T_75[1] := UInt<1>("h00") + reg T_81 : UInt<12>, clock, reset + when read.valid : + T_81 := read.bits.addr + skip + cmem T_84 : UInt<128>[256], clock + node T_86 = neq(T_65, UInt<1>("h00")) + node T_87 = and(T_86, write.valid) + node T_88 = bit(write.bits.wmask, 0) + node T_89 = and(T_87, T_88) + when T_89 : + node T_90 = bits(write.bits.data, 63, 0) + node T_91 = cat(T_90, T_90) + node T_92 = bit(T_65, 0) + node T_93 = bit(T_65, 1) + wire T_95 : UInt<1>[2] + T_95[0] := T_92 + T_95[1] := T_93 + node T_100 = subw(UInt<64>("h00"), T_95[0]) + node T_102 = subw(UInt<64>("h00"), T_95[1]) + wire T_104 : UInt<64>[2] + T_104[0] := T_100 + T_104[1] := T_102 + node T_108 = cat(T_104[1], T_104[0]) + infer accessor T_109 = T_84[waddr] + node T_110 = not(T_108) + node T_111 = and(T_109, T_110) + node T_112 = and(T_91, T_108) + node T_113 = or(T_111, T_112) + wire T_114 : UInt<128> + T_114 := UInt<1>("h00") + T_114 := T_113 + infer accessor T_116 = T_84[waddr] + T_116 := T_114 + skip + node T_118 = neq(T_66, UInt<1>("h00")) + node T_119 = and(T_118, read.valid) + reg T_120 : UInt<8>, clock, reset + when T_119 : + T_120 := raddr + skip + infer accessor T_121 = T_84[T_120] + T_75[0] := T_121 + cmem T_124 : UInt<128>[256], clock + node T_126 = neq(T_65, UInt<1>("h00")) + node T_127 = and(T_126, write.valid) + node T_128 = bit(write.bits.wmask, 1) + node T_129 = and(T_127, T_128) + when T_129 : + node T_130 = bits(write.bits.data, 127, 64) + node T_131 = cat(T_130, T_130) + node T_132 = bit(T_65, 0) + node T_133 = bit(T_65, 1) + wire T_135 : UInt<1>[2] + T_135[0] := T_132 + T_135[1] := T_133 + node T_140 = subw(UInt<64>("h00"), T_135[0]) + node T_142 = subw(UInt<64>("h00"), T_135[1]) + wire T_144 : UInt<64>[2] + T_144[0] := T_140 + T_144[1] := T_142 + node T_148 = cat(T_144[1], T_144[0]) + infer accessor T_149 = T_124[waddr] + node T_150 = not(T_148) + node T_151 = and(T_149, T_150) + node T_152 = and(T_131, T_148) + node T_153 = or(T_151, T_152) + wire T_154 : UInt<128> + T_154 := UInt<1>("h00") + T_154 := T_153 + infer accessor T_156 = T_124[waddr] + T_156 := T_154 + skip + node T_158 = neq(T_66, UInt<1>("h00")) + node T_159 = and(T_158, read.valid) + reg T_160 : UInt<8>, clock, reset + when T_159 : + T_160 := raddr + skip + infer accessor T_161 = T_124[T_160] + T_75[1] := T_161 + node T_162 = bits(T_75[0], 63, 0) + node T_163 = bits(T_75[1], 63, 0) + wire T_165 : UInt<64>[2] + T_165[0] := T_162 + T_165[1] := T_163 + node T_169 = bits(T_81, 3, 3) + infer accessor T_170 = T_165[T_169] + wire T_172 : UInt<64>[2] + T_172[0] := T_170 + T_172[1] := T_165[1] + node T_176 = cat(T_172[1], T_172[0]) + resp[0] := T_176 + node T_177 = bits(T_75[0], 127, 64) + node T_178 = bits(T_75[1], 127, 64) + wire T_180 : UInt<64>[2] + T_180[0] := T_177 + T_180[1] := T_178 + node T_184 = bits(T_81, 3, 3) + infer accessor T_185 = T_180[T_184] + wire T_187 : UInt<64>[2] + T_187[0] := T_185 + T_187[1] := T_180[1] + node T_191 = cat(T_187[1], T_187[0]) + resp[1] := T_191 + node T_192 = bits(write.bits.way_en, 3, 2) + node T_193 = bits(read.bits.way_en, 3, 2) + wire T_202 : UInt<128>[2] + T_202[0] := UInt<1>("h00") + T_202[1] := UInt<1>("h00") + reg T_208 : UInt<12>, clock, reset + when read.valid : + T_208 := read.bits.addr + skip + cmem T_211 : UInt<128>[256], clock + node T_213 = neq(T_192, UInt<1>("h00")) + node T_214 = and(T_213, write.valid) + node T_215 = bit(write.bits.wmask, 0) + node T_216 = and(T_214, T_215) + when T_216 : + node T_217 = bits(write.bits.data, 63, 0) + node T_218 = cat(T_217, T_217) + node T_219 = bit(T_192, 0) + node T_220 = bit(T_192, 1) + wire T_222 : UInt<1>[2] + T_222[0] := T_219 + T_222[1] := T_220 + node T_227 = subw(UInt<64>("h00"), T_222[0]) + node T_229 = subw(UInt<64>("h00"), T_222[1]) + wire T_231 : UInt<64>[2] + T_231[0] := T_227 + T_231[1] := T_229 + node T_235 = cat(T_231[1], T_231[0]) + infer accessor T_236 = T_211[waddr] + node T_237 = not(T_235) + node T_238 = and(T_236, T_237) + node T_239 = and(T_218, T_235) + node T_240 = or(T_238, T_239) + wire T_241 : UInt<128> + T_241 := UInt<1>("h00") + T_241 := T_240 + infer accessor T_243 = T_211[waddr] + T_243 := T_241 + skip + node T_245 = neq(T_193, UInt<1>("h00")) + node T_246 = and(T_245, read.valid) + reg T_247 : UInt<8>, clock, reset + when T_246 : + T_247 := raddr + skip + infer accessor T_248 = T_211[T_247] + T_202[0] := T_248 + cmem T_251 : UInt<128>[256], clock + node T_253 = neq(T_192, UInt<1>("h00")) + node T_254 = and(T_253, write.valid) + node T_255 = bit(write.bits.wmask, 1) + node T_256 = and(T_254, T_255) + when T_256 : + node T_257 = bits(write.bits.data, 127, 64) + node T_258 = cat(T_257, T_257) + node T_259 = bit(T_192, 0) + node T_260 = bit(T_192, 1) + wire T_262 : UInt<1>[2] + T_262[0] := T_259 + T_262[1] := T_260 + node T_267 = subw(UInt<64>("h00"), T_262[0]) + node T_269 = subw(UInt<64>("h00"), T_262[1]) + wire T_271 : UInt<64>[2] + T_271[0] := T_267 + T_271[1] := T_269 + node T_275 = cat(T_271[1], T_271[0]) + infer accessor T_276 = T_251[waddr] + node T_277 = not(T_275) + node T_278 = and(T_276, T_277) + node T_279 = and(T_258, T_275) + node T_280 = or(T_278, T_279) + wire T_281 : UInt<128> + T_281 := UInt<1>("h00") + T_281 := T_280 + infer accessor T_283 = T_251[waddr] + T_283 := T_281 + skip + node T_285 = neq(T_193, UInt<1>("h00")) + node T_286 = and(T_285, read.valid) + reg T_287 : UInt<8>, clock, reset + when T_286 : + T_287 := raddr + skip + infer accessor T_288 = T_251[T_287] + T_202[1] := T_288 + node T_289 = bits(T_202[0], 63, 0) + node T_290 = bits(T_202[1], 63, 0) + wire T_292 : UInt<64>[2] + T_292[0] := T_289 + T_292[1] := T_290 + node T_296 = bits(T_208, 3, 3) + infer accessor T_297 = T_292[T_296] + wire T_299 : UInt<64>[2] + T_299[0] := T_297 + T_299[1] := T_292[1] + node T_303 = cat(T_299[1], T_299[0]) + resp[2] := T_303 + node T_304 = bits(T_202[0], 127, 64) + node T_305 = bits(T_202[1], 127, 64) + wire T_307 : UInt<64>[2] + T_307[0] := T_304 + T_307[1] := T_305 + node T_311 = bits(T_208, 3, 3) + infer accessor T_312 = T_307[T_311] + wire T_314 : UInt<64>[2] + T_314[0] := T_312 + T_314[1] := T_307[1] + node T_318 = cat(T_314[1], T_314[0]) + resp[3] := T_318 + read.ready := UInt<1>("h01") + write.ready := UInt<1>("h01") +;CHECK: Done! diff --git a/test/passes/inline-indexers/simple9.fir b/test/passes/inline-indexers/simple9.fir new file mode 100644 index 00000000..a40abb17 --- /dev/null +++ b/test/passes/inline-indexers/simple9.fir @@ -0,0 +1,18 @@ +; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s + +;CHECK: Inline Indexers +circuit top : + module top : + input T_4910 : UInt<1> + input T_4581 : UInt<1> + input reset : UInt<1> + input clock : Clock + output out : UInt<1> + reg T_4590 : UInt<1>[2], clock, reset + T_4590[0] := UInt(0) + T_4590[1] := UInt(0) + out := UInt(0) + when T_4910 : + infer accessor T_4911 = T_4590[T_4581] + out := T_4911 +;CHECK: Done! diff --git a/test/passes/lower-to-ground/accessor.fir b/test/passes/lower-to-ground/accessor.fir index fd261e1e..4d55d0f6 100644 --- a/test/passes/lower-to-ground/accessor.fir +++ b/test/passes/lower-to-ground/accessor.fir @@ -14,13 +14,11 @@ circuit top : ; CHECK: wire a{{[_$]+}}3 : UInt<32> infer accessor b = a[i] - ; CHECK: wire b : UInt<32> - ; CHECK: b := (a{{[_$]+}}0 a{{[_$]+}}1 a{{[_$]+}}2 a{{[_$]+}}3)[i] + ; CHECK: indexer b = (a{{[_$]+}}0 a{{[_$]+}}1 a{{[_$]+}}2 a{{[_$]+}}3)[i] : UInt<32> j := b infer accessor c = a[i] - ; CHECK: wire c : UInt<32> - ; CHECK: (a{{[_$]+}}0 a{{[_$]+}}1 a{{[_$]+}}2 a{{[_$]+}}3)[i] := c + ; CHECK: indexer (a{{[_$]+}}0 a{{[_$]+}}1 a{{[_$]+}}2 a{{[_$]+}}3)[i] = c : UInt<32> c := j cmem p : UInt<32>[4],clk diff --git a/test/passes/lower-to-ground/bundle-vecs.fir b/test/passes/lower-to-ground/bundle-vecs.fir index 17927aef..7d37e65c 100644 --- a/test/passes/lower-to-ground/bundle-vecs.fir +++ b/test/passes/lower-to-ground/bundle-vecs.fir @@ -13,17 +13,13 @@ circuit top : ; CHECK: wire a{{[_$]+}}1{{[_$]+}}y : UInt<32> infer accessor b = a[i] - ; CHECK: wire b{{[_$]+}}x : UInt<32> - ; CHECK: wire b{{[_$]+}}y : UInt<32> - ; CHECK: b{{[_$]+}}x := (a{{[_$]+}}0{{[_$]+}}x a{{[_$]+}}1{{[_$]+}}x)[i] - ; CHECK: (a{{[_$]+}}0{{[_$]+}}y a{{[_$]+}}1{{[_$]+}}y)[i] := b{{[_$]+}}y + ; CHECK: indexer b{{[_$]+}}x = (a{{[_$]+}}0{{[_$]+}}x a{{[_$]+}}1{{[_$]+}}x)[i] : UInt<32> + ; CHECK: indexer (a{{[_$]+}}0{{[_$]+}}y a{{[_$]+}}1{{[_$]+}}y)[i] = b{{[_$]+}}y : UInt<32> j := b infer accessor c = a[i] - ; CHECK: wire c{{[_$]+}}x : UInt<32> - ; CHECK: wire c{{[_$]+}}y : UInt<32> - ; CHECK: (a{{[_$]+}}0{{[_$]+}}x a{{[_$]+}}1{{[_$]+}}x)[i] := c{{[_$]+}}x - ; CHECK: c{{[_$]+}}y := (a{{[_$]+}}0{{[_$]+}}y a{{[_$]+}}1{{[_$]+}}y)[i] + ; CHECK: indexer (a{{[_$]+}}0{{[_$]+}}x a{{[_$]+}}1{{[_$]+}}x)[i] = c{{[_$]+}}x : UInt<32> + ; CHECK: indexer c{{[_$]+}}y = (a{{[_$]+}}0{{[_$]+}}y a{{[_$]+}}1{{[_$]+}}y)[i] : UInt<32> c := j diff --git a/test/passes/lower-to-ground/nested-vec.fir b/test/passes/lower-to-ground/nested-vec.fir index d484a6dc..aa208b01 100644 --- a/test/passes/lower-to-ground/nested-vec.fir +++ b/test/passes/lower-to-ground/nested-vec.fir @@ -15,10 +15,8 @@ circuit top : ; CHECK: wire a{{[_$]+}}1{{[_$]+}}y : UInt<32> infer accessor b = a[i] - ; CHECK: wire b{{[_$]+}}x : UInt<32> - ; CHECK: wire b{{[_$]+}}y : UInt<32> - ; CHECK: b{{[_$]+}}x := (a{{[_$]+}}0{{[_$]+}}x a{{[_$]+}}1{{[_$]+}}x)[i] - ; CHECK: (a{{[_$]+}}0{{[_$]+}}y a{{[_$]+}}1{{[_$]+}}y)[i] := b{{[_$]+}}y + ; CHECK: indexer b{{[_$]+}}x = (a{{[_$]+}}0{{[_$]+}}x a{{[_$]+}}1{{[_$]+}}x)[i] : UInt<32> + ; CHECK: indexer (a{{[_$]+}}0{{[_$]+}}y a{{[_$]+}}1{{[_$]+}}y)[i] = b{{[_$]+}}y : UInt<32> j := b cmem m : { x : UInt<32>, y : UInt<32> }[2],clk diff --git a/test/passes/split-exp/split-in-when.fir b/test/passes/split-exp/split-in-when.fir index ddf6a155..58819d22 100644 --- a/test/passes/split-exp/split-in-when.fir +++ b/test/passes/split-exp/split-in-when.fir @@ -13,11 +13,11 @@ circuit Top : when bit(subw(a,c),3) : out := mux(eqv(bits(UInt(32),4,0),UInt(13)),addw(a,addw(b,c)),subw(c,b)) -;CHECK: node T = subw(a, c) +;CHECK: node F = subw(a, c) ;CHECK: node out_1 = eqv(UInt("h0"), UInt("hd")) ;CHECK: node out_3 = addw(b, c) ;CHECK: node out_2 = addw(a, out_3) ;CHECK: node out_4 = subw(c, b) -;CHECK: when bit(T, 3) : out := mux(out_1, out_2, out_4) +;CHECK: when bit(F, 3) : out := mux(out_1, out_2, out_4) ;CHECK: Finished Split Expressions |
