aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Izraelevitz2016-09-25 20:35:09 -0700
committerGitHub2016-09-25 20:35:09 -0700
commite54fb610c6bf0a7fe5c9c0f0e0b3acbb3728cfd0 (patch)
tree7c186c96c782f488a9ceea21abb3f60594bf98c7
parent7c4fa71a062f0c18a3af13c9e8853fdec2818da9 (diff)
Spec features added: AnalogType and Attach (#295)
* Spec features added: AnalogType and Attach AnalogType(width: Width): - Concrete syntax: wire x: AnalogType<10> - New groundtype, very restricted in use cases. - Can only declare ports and wires with Analog type - Analog types are never equivalent, thus if x and y have Analog types: x <= y is never legal. Attach(info: Info, source: Expression, exprs: Seq[Expression]): - Concrete syntax: attach x to (y, z) - New statement - Source can be any groundtyped expression (UInt, SInt, Analog, Clock) - Exprs must have an Analog type reference an instance port - Source and exprs must have identical widths Included WDefInstanceConnector to enable emission of Verilog inout Should be mostly feature complete. Need to update spec if PR gets accepted. * Fixed bug where invalidated ports aren't handled * Bugfix for VerilogPrep Intermediate wires for invalidated instance ports were not invalidated * Bugfix: calling create_exp with name/tpe Returns unknown gender, which was passing through Caused temporary wire to not be declared Because Verilog is dumb, undeclared wires are assumed to be 1bit signals * Addressed donggyukim's style comments * Reworked pass to only allow analog types in attach Restrict source to be only wire or port kind Much simpler implementation, almost identical functionality Clearer semantics (i think?) * Fixup bugs from pulling in new changes from master * comments for type eqs and small style fixes
-rw-r--r--src/main/antlr4/FIRRTL.g42
-rw-r--r--src/main/scala/firrtl/Emitter.scala47
-rw-r--r--src/main/scala/firrtl/LoweringCompilers.scala3
-rw-r--r--src/main/scala/firrtl/PrimOps.scala3
-rw-r--r--src/main/scala/firrtl/Utils.scala1
-rw-r--r--src/main/scala/firrtl/Visitor.scala3
-rw-r--r--src/main/scala/firrtl/WIR.scala13
-rw-r--r--src/main/scala/firrtl/ir/IR.scala11
-rw-r--r--src/main/scala/firrtl/passes/Checks.scala66
-rw-r--r--src/main/scala/firrtl/passes/ExpandWhens.scala11
-rw-r--r--src/main/scala/firrtl/passes/InferWidths.scala14
-rw-r--r--src/main/scala/firrtl/passes/MemUtils.scala3
-rw-r--r--src/main/scala/firrtl/passes/Passes.scala40
-rw-r--r--src/main/scala/firrtl/passes/Resolves.scala1
-rw-r--r--src/test/scala/firrtlTests/AttachSpec.scala413
15 files changed, 584 insertions, 47 deletions
diff --git a/src/main/antlr4/FIRRTL.g4 b/src/main/antlr4/FIRRTL.g4
index ef0fd7eb..1232b65f 100644
--- a/src/main/antlr4/FIRRTL.g4
+++ b/src/main/antlr4/FIRRTL.g4
@@ -79,6 +79,7 @@ type
: 'UInt' ('<' IntLit '>')?
| 'SInt' ('<' IntLit '>')?
| 'Clock'
+ | 'Analog' ('<' IntLit '>')?
| '{' field* '}' // Bundle
| type '[' IntLit ']' // Vector
;
@@ -119,6 +120,7 @@ stmt
| 'stop(' exp exp IntLit ')' info?
| 'printf(' exp exp StringLit ( exp)* ')' info?
| 'skip' info?
+ | 'attach' exp 'to' '(' exp* ')' info?
;
memField
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
index 0269a4fc..0a3068bc 100644
--- a/src/main/scala/firrtl/Emitter.scala
+++ b/src/main/scala/firrtl/Emitter.scala
@@ -64,6 +64,7 @@ case class VRandom(width: BigInt) extends Expression {
def mapType(f: Type => Type): Expression = this
def mapWidth(f: Width => Width): Expression = this
}
+
class VerilogEmitter extends Emitter {
val tab = " "
def AND(e1: WrappedExpression, e2: WrappedExpression): Expression = {
@@ -87,6 +88,7 @@ class VerilogEmitter extends Emitter {
case (t: UIntType) => e
case (t: SIntType) => Seq("$signed(",e,")")
case ClockType => e
+ case AnalogType(w) => e
}
(x) match {
case (e: DoPrim) => emit(op_stream(e), top + 1)
@@ -106,6 +108,9 @@ class VerilogEmitter extends Emitter {
val wx = bitWidth(t) - 1
if (wx > 0) w write s"[$wx:0]"
case ClockType =>
+ case t: AnalogType =>
+ val wx = bitWidth(t) - 1
+ if (wx > 0) w write s"[$wx:0]"
case (t: VectorType) =>
emit(t.tpe, top + 1)
w write s"[${t.size - 1}:0]"
@@ -371,21 +376,6 @@ class VerilogEmitter extends Emitter {
initials += Seq("`endif")
}
- def instantiate(n: String,m: String, es: Seq[Expression]) {
- instdeclares += Seq(m, " ", n, " (")
- es.zipWithIndex foreach {case (e, i) =>
- val s = Seq(tab, ".", remove_root(e), "(", LowerTypes.loweredName(e), ")")
- if (i != es.size - 1) instdeclares += Seq(s, ",")
- else instdeclares += s
- }
- instdeclares += Seq(");")
- es foreach { e =>
- declare("wire",LowerTypes.loweredName(e), e.tpe)
- val ex = WRef(LowerTypes.loweredName(e), e.tpe, kind(e), gender(e))
- if (gender(e) == FEMALE) assign(ex,netlist(e))
- }
- }
-
def simulate(clk: Expression, en: Expression, s: Seq[Any], cond: Option[String]) {
if (!at_clock.contains(clk)) at_clock(clk) = ArrayBuffer[Seq[Any]]()
at_clock(clk) += Seq("`ifndef SYNTHESIS")
@@ -415,10 +405,12 @@ class VerilogEmitter extends Emitter {
}
def build_ports(): Unit = portdefs ++= m.ports.zipWithIndex map {
- case (p, i) => p.direction match {
- case Input =>
+ case (p, i) => (p.tpe, p.direction) match {
+ case (AnalogType(_), _) =>
+ Seq("inout", " ", p.tpe, " ", p.name)
+ case (_, Input) =>
Seq(p.direction, " ", p.tpe, " ", p.name)
- case Output =>
+ case (_, Output) =>
val ex = WRef(p.name, p.tpe, PortKind, FEMALE)
assign(ex, netlist(ex))
Seq(p.direction, " ", p.tpe, " ", p.name)
@@ -427,9 +419,12 @@ class VerilogEmitter extends Emitter {
def build_streams(s: Statement): Statement = s map build_streams match {
case (s: DefWire) =>
- declare("wire", s.name, s.tpe)
- val e = wref(s.name, s.tpe)
- assign(e,netlist(e))
+ declare("wire",s.name,s.tpe)
+ val e = wref(s.name,s.tpe)
+ netlist get e match {
+ case Some(n) => assign(e,n)
+ case None =>
+ }
s
case (s: DefRegister) =>
declare("reg", s.name, s.tpe)
@@ -453,9 +448,15 @@ class VerilogEmitter extends Emitter {
case (s: Print) =>
simulate(s.clk, s.en, printf(s.string, s.args), Some("PRINTF_COND"))
s
- case (s: WDefInstance) =>
+ case (s: WDefInstanceConnector) =>
val es = create_exps(WRef(s.name, s.tpe, InstanceKind, MALE))
- instantiate(s.name, s.module, es)
+ instdeclares += Seq(s.module, " ", s.name, " (")
+ (es zip s.exprs).zipWithIndex foreach {case ((l, r), i) =>
+ val s = Seq(tab, ".", remove_root(l), "(", r, ")")
+ if (i != es.size - 1) instdeclares += Seq(s, ",")
+ else instdeclares += s
+ }
+ instdeclares += Seq(");")
s
case (s: DefMemory) =>
declare("reg", s.name, VectorType(s.dataType, s.depth))
diff --git a/src/main/scala/firrtl/LoweringCompilers.scala b/src/main/scala/firrtl/LoweringCompilers.scala
index c7b7f5dd..eb44b4c2 100644
--- a/src/main/scala/firrtl/LoweringCompilers.scala
+++ b/src/main/scala/firrtl/LoweringCompilers.scala
@@ -150,7 +150,8 @@ class EmitVerilogFromLowFirrtl(val writer: Writer) extends Transform with Simple
passes.SplitExpressions,
passes.CommonSubexpressionElimination,
passes.DeadCodeElimination,
- passes.VerilogRename)
+ passes.VerilogRename,
+ passes.VerilogPrep)
def execute(circuit: Circuit, annotationMap: AnnotationMap): TransformResult = {
val result = run(circuit, passSeq)
(new VerilogEmitter).run(result.circuit, writer)
diff --git a/src/main/scala/firrtl/PrimOps.scala b/src/main/scala/firrtl/PrimOps.scala
index a736dc3d..09cae392 100644
--- a/src/main/scala/firrtl/PrimOps.scala
+++ b/src/main/scala/firrtl/PrimOps.scala
@@ -226,18 +226,21 @@ object PrimOps extends LazyLogging {
case _: UIntType => UIntType(w1)
case _: SIntType => UIntType(w1)
case ClockType => UIntType(IntWidth(1))
+ case AnalogType(w) => UIntType(w1)
case _ => UnknownType
}
case AsSInt => t1 match {
case _: UIntType => SIntType(w1)
case _: SIntType => SIntType(w1)
case ClockType => SIntType(IntWidth(1))
+ case _: AnalogType => SIntType(w1)
case _ => UnknownType
}
case AsClock => t1 match {
case _: UIntType => ClockType
case _: SIntType => ClockType
case ClockType => ClockType
+ case _: AnalogType => ClockType
case _ => UnknownType
}
case Shl => t1 match {
diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala
index 453e9a0c..d7a1e44d 100644
--- a/src/main/scala/firrtl/Utils.scala
+++ b/src/main/scala/firrtl/Utils.scala
@@ -240,6 +240,7 @@ object Utils extends LazyLogging {
ilen + get_size(t1.tpe), jlen + get_size(t2.tpe))
})._1
case (ClockType, ClockType) => if (flip1 == flip2) Seq((0, 0)) else Nil
+ case (AnalogType(w1), AnalogType(w2)) => Nil
case _ => error("shouldn't be here")
}
}
diff --git a/src/main/scala/firrtl/Visitor.scala b/src/main/scala/firrtl/Visitor.scala
index 00ef8f1b..b8850e53 100644
--- a/src/main/scala/firrtl/Visitor.scala
+++ b/src/main/scala/firrtl/Visitor.scala
@@ -137,6 +137,8 @@ class Visitor(infoMode: InfoMode) extends FIRRTLBaseVisitor[FirrtlNode] {
case "SInt" => if (ctx.getChildCount > 1) SIntType(IntWidth(string2BigInt(ctx.IntLit.getText)))
else SIntType(UnknownWidth)
case "Clock" => ClockType
+ case "Analog" => if (ctx.getChildCount > 1) AnalogType(IntWidth(string2BigInt(ctx.IntLit.getText)))
+ else AnalogType(UnknownWidth)
case "{" => BundleType(ctx.field.map(visitField))
}
case typeContext: TypeContext => new VectorType(visitType(ctx.`type`), string2Int(ctx.IntLit.getText))
@@ -272,6 +274,7 @@ class Visitor(infoMode: InfoMode) extends FIRRTLBaseVisitor[FirrtlNode] {
case "node" => DefNode(info, ctx.id(0).getText, visitExp(ctx.exp(0)))
case "stop(" => Stop(info, string2Int(ctx.IntLit().getText), visitExp(ctx.exp(0)), visitExp(ctx.exp(1)))
+ case "attach" => Attach(info, visitExp(ctx.exp.head), ctx.exp.tail map visitExp)
case "printf(" => Print(info, visitStringLit(ctx.StringLit), ctx.exp.drop(2).map(visitExp),
visitExp(ctx.exp(0)), visitExp(ctx.exp(1)))
case "skip" => EmptyStmt
diff --git a/src/main/scala/firrtl/WIR.scala b/src/main/scala/firrtl/WIR.scala
index 4ca75858..956d7b07 100644
--- a/src/main/scala/firrtl/WIR.scala
+++ b/src/main/scala/firrtl/WIR.scala
@@ -102,6 +102,14 @@ case class WDefInstance(info: Info, name: String, module: String, tpe: Type) ext
def mapType(f: Type => Type): Statement = this.copy(tpe = f(tpe))
def mapString(f: String => String): Statement = this.copy(name = f(name))
}
+case class WDefInstanceConnector(info: Info, name: String, module: String, tpe: Type, exprs: Seq[Expression]) extends Statement with IsDeclaration {
+ def serialize: String = s"inst $name of $module with ${tpe.serialize} connected to (" + exprs.map(_.serialize).mkString(", ") + ")" + info.serialize
+ def mapExpr(f: Expression => Expression): Statement = this.copy(exprs = exprs map f)
+ def mapStmt(f: Statement => Statement): Statement = this
+ def mapType(f: Type => Type): Statement = this.copy(tpe = f(tpe))
+ def mapString(f: String => String): Statement = this.copy(name = f(name))
+}
+
// Resultant width is the same as the maximum input width
case object Addw extends PrimOp { override def toString = "addw" }
@@ -180,6 +188,11 @@ class WrappedType(val t: Type) {
case (_: UIntType, _: UIntType) => true
case (_: SIntType, _: SIntType) => true
case (ClockType, ClockType) => true
+ // Analog totally skips out of the Firrtl type system.
+ // The only way Analog can play with another Analog component is through Attach.
+ // Ohterwise, we'd need to special case it during ExpandWhens, Lowering,
+ // ExpandConnects, etc.
+ case (_: AnalogType, _: AnalogType) => false
case (t1: VectorType, t2: VectorType) =>
t1.size == t2.size && wt(t1.tpe) == wt(t2.tpe)
case (t1: BundleType, t2: BundleType) =>
diff --git a/src/main/scala/firrtl/ir/IR.scala b/src/main/scala/firrtl/ir/IR.scala
index 87072eec..35a81c14 100644
--- a/src/main/scala/firrtl/ir/IR.scala
+++ b/src/main/scala/firrtl/ir/IR.scala
@@ -250,6 +250,13 @@ case class IsInvalid(info: Info, expr: Expression) extends Statement with HasInf
def mapType(f: Type => Type): Statement = this
def mapString(f: String => String): Statement = this
}
+case class Attach(info: Info, source: Expression, exprs: Seq[Expression]) extends Statement with HasInfo {
+ def serialize: String = "attach " + source.serialize + " to (" + exprs.map(_.serialize).mkString(", ") + ")"
+ def mapStmt(f: Statement => Statement): Statement = this
+ def mapExpr(f: Expression => Expression): Statement = Attach(info, f(source), exprs map f)
+ def mapType(f: Type => Type): Statement = this
+ def mapString(f: String => String): Statement = this
+}
case class Stop(info: Info, ret: Int, clk: Expression, en: Expression) extends Statement with HasInfo {
def serialize: String = s"stop(${clk.serialize}, ${en.serialize}, $ret)" + info.serialize
def mapStmt(f: Statement => Statement): Statement = this
@@ -388,6 +395,10 @@ case object ClockType extends GroundType {
def serialize: String = "Clock"
def mapWidth(f: Width => Width): Type = this
}
+case class AnalogType(width: Width) extends GroundType {
+ def serialize: String = "Analog" + width.serialize
+ def mapWidth(f: Width => Width): Type = AnalogType(f(width))
+}
case object UnknownType extends Type {
def serialize: String = "?"
def mapType(f: Type => Type): Type = this
diff --git a/src/main/scala/firrtl/passes/Checks.scala b/src/main/scala/firrtl/passes/Checks.scala
index 03ea106c..e3c85edb 100644
--- a/src/main/scala/firrtl/passes/Checks.scala
+++ b/src/main/scala/firrtl/passes/Checks.scala
@@ -265,6 +265,8 @@ object CheckTypes extends Pass {
s"$info: [module $mname] Primop $op requires all arguments to be UInt type.")
class OpNotAllSameType(info: Info, mname: String, op: String) extends PassException(
s"$info: [module $mname] Primop $op requires all operands to have the same type.")
+ class OpNotAnalog(info: Info, mname: String, exp: String) extends PassException(
+ s"$info: [module $mname] Attach requires all arguments to be Analog type: $exp.")
class NodePassiveType(info: Info, mname: String) extends PassException(
s"$info: [module $mname] Node must be a passive type.")
class MuxSameType(info: Info, mname: String) extends PassException(
@@ -277,6 +279,12 @@ object CheckTypes extends Pass {
s"$info: [module $mname] Must validif a passive type.")
class ValidIfCondUInt(info: Info, mname: String) extends PassException(
s"$info: [module $mname] A validif condition must be of type UInt.")
+ class IllegalAnalogDeclaration(info: Info, mname: String, decName: String) extends PassException(
+ s"$info: [module $mname] Cannot declare a reg, node, or memory with an Analog type: $decName.")
+ class IllegalAttachSource(info: Info, mname: String, sourceName: String) extends PassException(
+ s"$info: [module $mname] Attach source must be a wire or port with an analog type: $sourceName.")
+ class IllegalAttachExp(info: Info, mname: String, expName: String) extends PassException(
+ s"$info: [module $mname] Attach expression must be an instance: $expName.")
//;---------------- Helper Functions --------------
def ut: UIntType = UIntType(UnknownWidth)
@@ -291,13 +299,12 @@ object CheckTypes extends Pass {
case (t: BundleType) => t.fields forall (x => x.flip == Default && passive(x.tpe))
case (t) => true
}
-
def check_types_primop(info: Info, mname: String, e: DoPrim) {
def all_same_type (ls:Seq[Expression]) {
if (ls exists (x => wt(ls.head.tpe) != wt(e.tpe)))
errors append new OpNotAllSameType(info, mname, e.op.serialize)
}
- def all_ground (ls: Seq[Expression]) {
+ def allInt(ls: Seq[Expression]) {
if (ls exists (x => x.tpe match {
case _: UIntType | _: SIntType => false
case _ => true
@@ -315,12 +322,11 @@ object CheckTypes extends Pass {
case _ => true
}) errors append new OpNotUInt(info, mname, e.op.serialize, x.serialize)
}
-
e.op match {
case AsUInt | AsSInt | AsClock =>
- case Dshl => is_uint(e.args(1)); all_ground(e.args)
- case Dshr => is_uint(e.args(1)); all_ground(e.args)
- case _ => all_ground(e.args)
+ case Dshl => is_uint(e.args(1)); allInt(e.args)
+ case Dshr => is_uint(e.args(1)); allInt(e.args)
+ case _ => allInt(e.args)
}
}
@@ -377,6 +383,7 @@ object CheckTypes extends Pass {
case (ClockType, ClockType) => flip1 == flip2
case (_: UIntType, _: UIntType) => flip1 == flip2
case (_: SIntType, _: SIntType) => flip1 == flip2
+ case (_: AnalogType, _: AnalogType) => false
case (t1: BundleType, t2: BundleType) =>
val t1_fields = (t1.fields foldLeft Map[String, (Type, Orientation)]())(
(map, f1) => map + (f1.name -> (f1.tpe, f1.flip)))
@@ -397,14 +404,35 @@ object CheckTypes extends Pass {
s match {
case (s: Connect) if wt(s.loc.tpe) != wt(s.expr.tpe) =>
errors append new InvalidConnect(info, mname, s.loc.serialize, s.expr.serialize)
- case (s:PartialConnect) if !bulk_equals(s.loc.tpe, s.expr.tpe, Default, Default) =>
+ case (s: PartialConnect) if !bulk_equals(s.loc.tpe, s.expr.tpe, Default, Default) =>
errors append new InvalidConnect(info, mname, s.loc.serialize, s.expr.serialize)
- case (s: DefRegister) if wt(s.tpe) != wt(s.init.tpe) =>
- errors append new InvalidRegInit(info, mname)
+ case (s: DefRegister) => s.tpe match {
+ case AnalogType(w) => errors append new IllegalAnalogDeclaration(info, mname, s.name)
+ case t if (wt(s.tpe) != wt(s.init.tpe)) => errors append new InvalidRegInit(info, mname)
+ case t =>
+ }
case (s: Conditionally) if wt(s.pred.tpe) != wt(ut) =>
errors append new PredNotUInt(info, mname)
- case (s: DefNode) if !passive(s.value.tpe) =>
- errors append new NodePassiveType(info, mname)
+ case (s: DefNode) => s.value.tpe match {
+ case AnalogType(w) => errors append new IllegalAnalogDeclaration(info, mname, s.name)
+ case t if !passive(s.value.tpe) => errors append new NodePassiveType(info, mname)
+ case t =>
+ }
+ case (s: Attach) =>
+ (s.source.tpe, kind(s.source)) match {
+ case (AnalogType(w), PortKind | WireKind) =>
+ case _ => errors append new IllegalAttachSource(info, mname, s.source.serialize)
+ }
+ (s.exprs foreach) { e =>
+ e.tpe match {
+ case _: AnalogType =>
+ case _ => errors append new OpNotAnalog(info, mname, e.serialize)
+ }
+ kind(e) match {
+ case InstanceKind =>
+ case _ => errors append new IllegalAttachExp(info, mname, e.serialize)
+ }
+ }
case (s: Stop) =>
if (wt(s.clk.tpe) != wt(ClockType)) errors append new ReqClk(info, mname)
if (wt(s.en.tpe) != wt(ut)) errors append new EnNotUInt(info, mname)
@@ -413,6 +441,10 @@ object CheckTypes extends Pass {
errors append new PrintfArgNotGround(info, mname)
if (wt(s.clk.tpe) != wt(ClockType)) errors append new ReqClk(info, mname)
if (wt(s.en.tpe) != wt(ut)) errors append new EnNotUInt(info, mname)
+ case (s: DefMemory) => s.dataType match {
+ case AnalogType(w) => errors append new IllegalAnalogDeclaration(info, mname, s.name)
+ case t =>
+ }
case _ =>
}
s map check_types_e(info, mname) map check_types_s(info, mname)
@@ -541,6 +573,8 @@ object CheckWidths extends Pass {
s"$info: [module $mname] Parameter $n in head operator is larger than input width $width.")
class TailWidthException(info: Info, mname: String, n: BigInt, width: BigInt) extends PassException(
s"$info: [module $mname] Parameter $n in tail operator is larger than input width $width.")
+ class AttachWidthsNotEqual(info: Info, mname: String, eName: String, source: String) extends PassException(
+ s"$info: [module $mname] Attach source $source and expression $eName must have identical widths.")
def run(c: Circuit): Circuit = {
val errors = new Errors()
@@ -581,7 +615,15 @@ object CheckWidths extends Pass {
def check_width_s(minfo: Info, mname: String)(s: Statement): Statement = {
val info = get_info(s) match { case NoInfo => minfo case x => x }
- s map check_width_e(info, mname) map check_width_s(info, mname)
+ s map check_width_e(info, mname) map check_width_s(info, mname) match {
+ case Attach(info, source, exprs) =>
+ exprs foreach ( e =>
+ if (bitWidth(e.tpe) != bitWidth(source.tpe))
+ errors append new AttachWidthsNotEqual(info, mname, e.serialize, source.serialize)
+ )
+ s
+ case _ => s
+ }
}
def check_width_p(minfo: Info, mname: String)(p: Port): Port = {
diff --git a/src/main/scala/firrtl/passes/ExpandWhens.scala b/src/main/scala/firrtl/passes/ExpandWhens.scala
index cd85c18a..f063e6eb 100644
--- a/src/main/scala/firrtl/passes/ExpandWhens.scala
+++ b/src/main/scala/firrtl/passes/ExpandWhens.scala
@@ -48,6 +48,7 @@ object ExpandWhens extends Pass {
type NodeMap = collection.mutable.HashMap[MemoizedHash[Expression], String]
type Netlist = collection.mutable.LinkedHashMap[WrappedExpression, Expression]
type Simlist = collection.mutable.ArrayBuffer[Statement]
+ type Attachlist = collection.mutable.ArrayBuffer[Statement]
type Defaults = Seq[collection.mutable.Map[WrappedExpression, Expression]]
// ========== Expand When Utilz ==========
@@ -55,9 +56,12 @@ object ExpandWhens extends Pass {
def getGender(t: Type, i: Int, g: Gender): Gender = times(g, get_flip(t, i, Default))
val exps = create_exps(WRef(n, t, ExpKind, g))
(exps.zipWithIndex foldLeft Seq[Expression]()){
- case (expsx, (exp, j)) => getGender(t, j, g) match {
- case (BIGENDER | FEMALE) => expsx :+ exp
- case _ => expsx
+ case (expsx, (exp, j)) => exp.tpe match {
+ case AnalogType(w) => expsx
+ case _ => getGender(t, j, g) match {
+ case (BIGENDER | FEMALE) => expsx :+ exp
+ case _ => expsx
+ }
}
}
}
@@ -108,6 +112,7 @@ object ExpandWhens extends Pass {
case c: IsInvalid =>
netlist(c.expr) = WInvalid
EmptyStmt
+ case c: Attach => c
case s: Conditionally =>
val conseqNetlist = new Netlist
val altNetlist = new Netlist
diff --git a/src/main/scala/firrtl/passes/InferWidths.scala b/src/main/scala/firrtl/passes/InferWidths.scala
index 1a8cc343..bf1f53b4 100644
--- a/src/main/scala/firrtl/passes/InferWidths.scala
+++ b/src/main/scala/firrtl/passes/InferWidths.scala
@@ -253,6 +253,8 @@ object InferWidths extends Pass {
WGeq(getWidth(s.pred), IntWidth(1)),
WGeq(IntWidth(1), getWidth(s.pred))
)
+ case (s: Attach) =>
+ v += WGeq(getWidth(s.source), MaxWidth(s.exprs map (e => getWidth(e.tpe))))
case _ =>
}
s map get_constraints_e map get_constraints_s
@@ -260,13 +262,13 @@ object InferWidths extends Pass {
c.modules foreach (_ map get_constraints_s)
- //println-debug("======== ALL CONSTRAINTS ========")
- //for x in v do : println-debug(x)
- //println-debug("=================================")
+ //println("======== ALL CONSTRAINTS ========")
+ //for(x <- v) println(x)
+ //println("=================================")
val h = solve_constraints(v)
- //println-debug("======== SOLVED CONSTRAINTS ========")
- //for x in h do : println-debug(x)
- //println-debug("====================================")
+ //println("======== SOLVED CONSTRAINTS ========")
+ //for(x <- h) println(x)
+ //println("====================================")
def evaluate(w: Width): Width = {
def map2(a: Option[BigInt], b: Option[BigInt], f: (BigInt,BigInt) => BigInt): Option[BigInt] =
diff --git a/src/main/scala/firrtl/passes/MemUtils.scala b/src/main/scala/firrtl/passes/MemUtils.scala
index 7e2623c4..92673433 100644
--- a/src/main/scala/firrtl/passes/MemUtils.scala
+++ b/src/main/scala/firrtl/passes/MemUtils.scala
@@ -140,8 +140,7 @@ object createMask {
def apply(dt: Type): Type = dt match {
case t: VectorType => VectorType(apply(t.tpe), t.size)
case t: BundleType => BundleType(t.fields map (f => f copy (tpe=apply(f.tpe))))
- case t: UIntType => BoolType
- case t: SIntType => BoolType
+ case t: GroundType => BoolType
}
}
diff --git a/src/main/scala/firrtl/passes/Passes.scala b/src/main/scala/firrtl/passes/Passes.scala
index a182b2af..dc0eb2a0 100644
--- a/src/main/scala/firrtl/passes/Passes.scala
+++ b/src/main/scala/firrtl/passes/Passes.scala
@@ -308,3 +308,43 @@ object VerilogRename extends Pass {
def run(c: Circuit): Circuit =
c copy (modules = (c.modules map (_ map verilogRenameP map verilogRenameS)))
}
+
+
+object VerilogPrep extends Pass {
+ def name = "Verilog Prep"
+ type InstAttaches = collection.mutable.HashMap[String, Expression]
+ def run(c: Circuit): Circuit = {
+ def buildS(attaches: InstAttaches)(s: Statement): Statement = s match {
+ case Attach(_, source, exps) =>
+ exps foreach { e => attaches(e.serialize) = source }
+ s
+ case _ => s map buildS(attaches)
+ }
+ def lowerE(e: Expression): Expression = e match {
+ case _: WRef|_: WSubField if (kind(e) == InstanceKind) =>
+ WRef(LowerTypes.loweredName(e), e.tpe, kind(e), gender(e))
+ case _ => e map lowerE
+ }
+ def lowerS(attaches: InstAttaches)(s: Statement): Statement = s match {
+ case WDefInstance(info, name, module, tpe) =>
+ val exps = create_exps(WRef(name, tpe, ExpKind, MALE))
+ val wcon = WDefInstanceConnector(info, name, module, tpe, exps.map( e => e.tpe match {
+ case AnalogType(w) => attaches(e.serialize)
+ case _ => WRef(LowerTypes.loweredName(e), e.tpe, WireKind, MALE)
+ }))
+ val wires = exps.map ( e => e.tpe match {
+ case AnalogType(w) => EmptyStmt
+ case _ => DefWire(info, LowerTypes.loweredName(e), e.tpe)
+ })
+ Block(Seq(wcon) ++ wires)
+ case Attach(info, source, exps) => EmptyStmt
+ case _ => s map lowerS(attaches) map lowerE
+ }
+ def prepModule(m: DefModule): DefModule = {
+ val attaches = new InstAttaches
+ m map buildS(attaches)
+ m map lowerS(attaches)
+ }
+ c copy (modules = (c.modules map prepModule))
+ }
+}
diff --git a/src/main/scala/firrtl/passes/Resolves.scala b/src/main/scala/firrtl/passes/Resolves.scala
index 616e30f3..49df9ba6 100644
--- a/src/main/scala/firrtl/passes/Resolves.scala
+++ b/src/main/scala/firrtl/passes/Resolves.scala
@@ -87,6 +87,7 @@ object ResolveGenders extends Pass {
}
def resolve_s(s: Statement): Statement = s match {
+ //TODO(azidar): pretty sure don't need to do anything for Attach, but not positive...
case IsInvalid(info, expr) =>
IsInvalid(info, resolve_e(FEMALE)(expr))
case Connect(info, loc, expr) =>
diff --git a/src/test/scala/firrtlTests/AttachSpec.scala b/src/test/scala/firrtlTests/AttachSpec.scala
new file mode 100644
index 00000000..d1e07eae
--- /dev/null
+++ b/src/test/scala/firrtlTests/AttachSpec.scala
@@ -0,0 +1,413 @@
+/*
+Copyright (c) 2014 - 2016 The Regents of the University of
+California (Regents). All Rights Reserved. Redistribution and use in
+source and binary forms, with or without modification, are permitted
+provided that the following conditions are met:
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of the Regents nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION
+TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+*/
+
+package firrtlTests
+
+import java.io._
+import org.scalatest._
+import org.scalatest.prop._
+import firrtl._
+import firrtl.Annotations._
+import firrtl.ir.Circuit
+import firrtl.passes._
+import firrtl.Parser.IgnoreInfo
+
+class InoutVerilog extends FirrtlFlatSpec {
+ def parse (input:String) = Parser.parse(input.split("\n").toIterator, IgnoreInfo)
+ private def executeTest(input: String, expected: Seq[String], compiler: Compiler) = {
+ val writer = new StringWriter()
+ compiler.compile(parse(input), new AnnotationMap(Seq.empty), writer)
+ val lines = writer.toString().split("\n") map normalized
+ expected foreach { e =>
+ lines should contain(e)
+ }
+ }
+ "Circuit" should "attach a module input source" in {
+ val compiler = new VerilogCompiler
+ val input =
+ """circuit Attaching :
+ | module Attaching :
+ | input an: Analog<3>
+ | inst a of A
+ | inst b of B
+ | attach an to (a.an, b.an)
+ | module A:
+ | input an: Analog<3>
+ | module B:
+ | input an: Analog<3> """.stripMargin
+ val check =
+ """module Attaching(
+ | inout [2:0] an
+ |);
+ | A a (
+ | .an(an)
+ | );
+ | B b (
+ | .an(an)
+ | );
+ |endmodule
+ |module A(
+ | inout [2:0] an
+ |);
+ |endmodule
+ |module B(
+ | inout [2:0] an
+ |);
+ |endmodule
+ |""".stripMargin.split("\n") map normalized
+ executeTest(input, check, compiler)
+ }
+
+ "Circuit" should "attach a module output source" in {
+ val compiler = new VerilogCompiler
+ val input =
+ """circuit Attaching :
+ | module Attaching :
+ | output an: Analog<3>
+ | inst a of A
+ | inst b of B
+ | attach an to (a.an, b.an)
+ | module A:
+ | input an: Analog<3>
+ | module B:
+ | input an: Analog<3> """.stripMargin
+ val check =
+ """module Attaching(
+ | inout [2:0] an
+ |);
+ | A a (
+ | .an(an)
+ | );
+ | B b (
+ | .an(an)
+ | );
+ |endmodule
+ |module A(
+ | inout [2:0] an
+ |);
+ |endmodule
+ |module B(
+ | inout [2:0] an
+ |);
+ |endmodule
+ |""".stripMargin.split("\n") map normalized
+ executeTest(input, check, compiler)
+ }
+
+ "Circuit" should "not attach an instance input source" in {
+ val compiler = new VerilogCompiler
+ val input =
+ """circuit Attaching :
+ | module Attaching :
+ | inst a of A
+ | inst b of B
+ | attach a.an to (b.an)
+ | module A:
+ | input an: Analog<3>
+ | module B:
+ | input an: Analog<3> """.stripMargin
+ intercept[CheckTypes.IllegalAttachSource] {
+ executeTest(input, Seq.empty, compiler)
+ }
+ }
+
+ "Circuit" should "attach an instance output source" in {
+ val compiler = new VerilogCompiler
+ val input =
+ """circuit Attaching :
+ | module Attaching :
+ | inst a of A
+ | inst b of B
+ | attach b.an to (a.an)
+ | module A:
+ | input an: Analog<3>
+ | module B:
+ | input an: Analog<3> """.stripMargin
+ intercept[CheckTypes.IllegalAttachSource] {
+ executeTest(input, Seq.empty, compiler)
+ }
+ }
+
+ "Circuit" should "attach a wire source" in {
+ val compiler = new VerilogCompiler
+ val input =
+ """circuit Attaching :
+ | module Attaching :
+ | wire x: Analog
+ | inst a of A
+ | attach x to (a.an)
+ | module A:
+ | input an: Analog<3> """.stripMargin
+ val check =
+ """module Attaching(
+ |);
+ | wire [2:0] x;
+ | A a (
+ | .an(x)
+ | );
+ |endmodule
+ |""".stripMargin.split("\n") map normalized
+ executeTest(input, check, compiler)
+ }
+}
+
+class AttachAnalogSpec extends FirrtlFlatSpec {
+ def parse (input:String) = Parser.parse(input.split("\n").toIterator, IgnoreInfo)
+ private def executeTest(input: String, expected: Seq[String], passes: Seq[Pass]) = {
+ val c = passes.foldLeft(Parser.parse(input.split("\n").toIterator)) {
+ (c: Circuit, p: Pass) => p.run(c)
+ }
+ val lines = c.serialize.split("\n") map normalized
+
+ expected foreach { e =>
+ lines should contain(e)
+ }
+ }
+
+ "Connecting analog types" should "throw an exception" in {
+ val passes = Seq(
+ ToWorkingIR,
+ CheckHighForm,
+ ResolveKinds,
+ InferTypes,
+ CheckTypes)
+ val input =
+ """circuit Unit :
+ | module Unit :
+ | input y: Analog<1>
+ | output x: Analog<1>
+ | x <= y""".stripMargin
+ intercept[CheckTypes.InvalidConnect] {
+ passes.foldLeft(parse(input)) {
+ (c: Circuit, p: Pass) => p.run(c)
+ }
+ }
+ }
+
+ "Declaring register with analog types" should "throw an exception" in {
+ val passes = Seq(
+ ToWorkingIR,
+ CheckHighForm,
+ ResolveKinds,
+ InferTypes,
+ CheckTypes)
+ val input =
+ """circuit Unit :
+ | module Unit :
+ | input clk: Clock
+ | reg r: Analog<2>, clk""".stripMargin
+ intercept[CheckTypes.IllegalAnalogDeclaration] {
+ passes.foldLeft(parse(input)) {
+ (c: Circuit, p: Pass) => p.run(c)
+ }
+ }
+ }
+
+ "Declaring memory with analog types" should "throw an exception" in {
+ val passes = Seq(
+ ToWorkingIR,
+ CheckHighForm,
+ ResolveKinds,
+ InferTypes,
+ CheckTypes)
+ val input =
+ """circuit Unit :
+ | module Unit :
+ | input clk: Clock
+ | mem m:
+ | data-type => Analog<2>
+ | depth => 4
+ | read-latency => 0
+ | write-latency => 1
+ | read-under-write => undefined""".stripMargin
+ intercept[CheckTypes.IllegalAnalogDeclaration] {
+ passes.foldLeft(parse(input)) {
+ (c: Circuit, p: Pass) => p.run(c)
+ }
+ }
+ }
+
+ "Declaring node with analog types" should "throw an exception" in {
+ val passes = Seq(
+ ToWorkingIR,
+ CheckHighForm,
+ ResolveKinds,
+ InferTypes,
+ CheckTypes)
+ val input =
+ """circuit Unit :
+ | module Unit :
+ | input in: Analog<2>
+ | node n = in """.stripMargin
+ intercept[CheckTypes.IllegalAnalogDeclaration] {
+ passes.foldLeft(parse(input)) {
+ (c: Circuit, p: Pass) => p.run(c)
+ }
+ }
+ }
+
+ "Attaching a non-analog source" should "not be ok" in {
+ val passes = Seq(
+ ToWorkingIR,
+ CheckHighForm,
+ ResolveKinds,
+ InferTypes,
+ CheckTypes)
+ val input =
+ """circuit Unit :
+ | module Unit :
+ | input source: UInt<2>
+ | inst a of A
+ | inst b of B
+ | attach source to (a.o, b.o)
+ | extmodule A :
+ | output o: Analog<2>
+ | extmodule B:
+ | input o: Analog<2>""".stripMargin
+ intercept[CheckTypes.IllegalAttachSource] {
+ passes.foldLeft(parse(input)) {
+ (c: Circuit, p: Pass) => p.run(c)
+ }
+ }
+ }
+
+ "Attach instance analog male source" should "not be ok." in {
+ val passes = Seq(
+ ToWorkingIR,
+ CheckHighForm,
+ ResolveKinds,
+ InferTypes,
+ CheckTypes)
+ val input =
+ """circuit Unit :
+ | module Unit :
+ | inst a of A
+ | inst b of B
+ | attach a.o to (b.o)
+ | extmodule A :
+ | output o: Analog<2>
+ | extmodule B:
+ | input o: Analog<2>""".stripMargin
+ intercept[CheckTypes.IllegalAttachSource] {
+ passes.foldLeft(parse(input)) {
+ (c: Circuit, p: Pass) => p.run(c)
+ }
+ }
+ }
+
+ "Attach instance analog female source" should "not be ok." in {
+ val passes = Seq(
+ ToWorkingIR,
+ CheckHighForm,
+ ResolveKinds,
+ InferTypes,
+ CheckTypes)
+ val input =
+ """circuit Unit :
+ | module Unit :
+ | inst a of A
+ | inst b of B
+ | attach b.o to (a.o)
+ | extmodule A :
+ | output o: Analog<2>
+ | extmodule B:
+ | input o: Analog<2>""".stripMargin
+ intercept[CheckTypes.IllegalAttachSource] {
+ passes.foldLeft(parse(input)) {
+ (c: Circuit, p: Pass) => p.run(c)
+ }
+ }
+ }
+
+ "Attach port analog expr" should "throw an exception" in {
+ val passes = Seq(
+ ToWorkingIR,
+ CheckHighForm,
+ ResolveKinds,
+ InferTypes,
+ CheckTypes)
+ val input =
+ """circuit Unit :
+ | module Unit :
+ | input i: Analog<2>
+ | input j: Analog<2>
+ | attach j to (i) """.stripMargin
+ intercept[CheckTypes.IllegalAttachExp] {
+ passes.foldLeft(parse(input)) {
+ (c: Circuit, p: Pass) => p.run(c)
+ }
+ }
+ }
+
+ "Inequal attach widths" should "throw an exception" in {
+ val passes = Seq(
+ ToWorkingIR,
+ CheckHighForm,
+ ResolveKinds,
+ InferTypes,
+ CheckTypes,
+ InferWidths,
+ CheckWidths)
+ val input =
+ """circuit Unit :
+ | module Unit :
+ | input i: Analog<3>
+ | inst a of A
+ | attach i to (a.o)
+ | extmodule A :
+ | output o: Analog<2> """.stripMargin
+ intercept[CheckWidths.AttachWidthsNotEqual] {
+ passes.foldLeft(parse(input)) {
+ (c: Circuit, p: Pass) => p.run(c)
+ }
+ }
+ }
+
+ //"Simple compound expressions" should "be split" in {
+ // val passes = Seq(
+ // ToWorkingIR,
+ // ResolveKinds,
+ // InferTypes,
+ // ResolveGenders,
+ // InferWidths,
+ // SplitExpressions
+ // )
+ // val input =
+ // """circuit Top :
+ // | module Top :
+ // | input a : UInt<32>
+ // | input b : UInt<32>
+ // | input d : UInt<32>
+ // | output c : UInt<1>
+ // | c <= geq(add(a, b),d)""".stripMargin
+ // val check = Seq(
+ // "node GEN_0 = add(a, b)",
+ // "c <= geq(GEN_0, d)"
+ // )
+ // executeTest(input, check, passes)
+ //}
+}