diff options
| author | Adam Izraelevitz | 2016-09-07 16:08:55 -0700 |
|---|---|---|
| committer | GitHub | 2016-09-07 16:08:55 -0700 |
| commit | 8beaa3be259d2a793e3a99628b2f0d38d98f5b9a (patch) | |
| tree | d6c137d446a254bae87cd015c94bf86806225042 /src | |
| parent | 5697d30179a0f2e86dc618092af63e6eb997a534 (diff) | |
| parent | 13345ce816a51cc19f93a03c4148eecf0dd2c739 (diff) | |
Merge branch 'master' into cleanup_passes
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/scala/firrtl/Emitter.scala | 972 |
1 files changed, 444 insertions, 528 deletions
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala index 6c658257..378eac6d 100644 --- a/src/main/scala/firrtl/Emitter.scala +++ b/src/main/scala/firrtl/Emitter.scala @@ -29,21 +29,19 @@ package firrtl import com.typesafe.scalalogging.LazyLogging import java.nio.file.{Paths, Files} -import java.io.Writer -import java.io.Reader +import java.io.{Reader, Writer} import scala.sys.process._ import scala.io.Source import Utils._ -import firrtl.Mappers._ +import firrtl.ir._ import firrtl.passes._ +import firrtl.Mappers._ import firrtl.PrimOps._ -import firrtl.ir._ -import WrappedExpression._ +import firrtl.WrappedExpression._ // Datastructures -import scala.collection.mutable.LinkedHashMap -import scala.collection.mutable.ArrayBuffer +import scala.collection.mutable.{ArrayBuffer, LinkedHashMap} class EmitterException(message: String) extends PassException(message) @@ -63,243 +61,186 @@ case class VRandom(width: BigInt) extends Expression { def serialize: String = "RANDOM" } class VerilogEmitter extends Emitter { - val tab = " " - var w:Option[Writer] = None - var mname = "" - def wref (n:String,t:Type) = WRef(n,t,ExpKind(),UNKNOWNGENDER) - def remove_root (ex:Expression) : Expression = { - (ex.asInstanceOf[WSubField].exp) match { - case (e:WSubField) => remove_root(e) - case (e:WRef) => WRef(ex.asInstanceOf[WSubField].name,ex.tpe,InstanceKind(),UNKNOWNGENDER) - } - } - def not_empty (s:ArrayBuffer[_]) : Boolean = if (s.size == 0) false else true - def emit (x:Any) = emit2(x,0) - def emit2 (x:Any, top:Int) : Unit = { - def cast (e:Expression) : Any = { - e.tpe match { - case (t:UIntType) => e - case (t:SIntType) => Seq("$signed(",e,")") - case ClockType => e - } - } - (x) match { - case (e:Expression) => { - (e) match { - case (e:DoPrim) => emit2(op_stream(e), top + 1) - case (e:Mux) => emit2(Seq(e.cond," ? ",cast(e.tval)," : ",cast(e.fval)),top + 1) - case (e:ValidIf) => emit2(Seq(cast(e.value)),top + 1) - case (e:WRef) => w.get.write(e.serialize) - case (e:WSubField) => w.get.write(LowerTypes.loweredName(e)) - case (e:WSubAccess) => w.get.write(LowerTypes.loweredName(e.exp) + "[" + LowerTypes.loweredName(e.index) + "]") - case (e:WSubIndex) => w.get.write(e.serialize) - case (e:Literal) => v_print(e) - case (e:VRandom) => w.get.write(s"{${e.nWords}{$$random}}") - } - } - case (t:Type) => { - (t) match { - case (_:UIntType|_:SIntType) => - val wx = long_BANG(t) - 1 - if (wx > 0) w.get.write("[" + wx + ":0]") else w.get.write("") - case ClockType => w.get.write("") - case (t:VectorType) => - emit2(t.tpe, top + 1) - w.get.write("[" + (t.size - 1) + ":0]") - case (t) => error("Shouldn't be here"); w.get.write(t.serialize) - } - } - case (p:Direction) => { - p match { - case Input => w.get.write("input") - case Output => w.get.write("output") - } - } - case (s:String) => w.get.write(s) - case (i:Int) => w.get.write(i.toString) - case (i:Long) => w.get.write(i.toString) - case (t:VIndent) => w.get.write(" ") - case (s:Seq[Any]) => { - s.foreach((x:Any) => emit2(x, top + 1)) - if (top == 0) w.get.write("\n") - } - } - } + val tab = " " + def wref(n: String, t: Type) = WRef(n, t, ExpKind(), UNKNOWNGENDER) + def remove_root(ex: Expression): Expression = ex match { + case ex: WSubField => ex.exp match { + case (e: WSubField) => remove_root(e) + case (_: WRef) => WRef(ex.name, ex.tpe, InstanceKind(), UNKNOWNGENDER) + } + case _ => error("Shouldn't be here") + } + def emit(x: Any)(implicit w: Writer) { emit(x, 0) } + def emit(x: Any, top: Int)(implicit w: Writer) { + def cast(e: Expression): Any = e.tpe match { + case (t: UIntType) => e + case (t: SIntType) => Seq("$signed(",e,")") + case ClockType => e + } + (x) match { + case (e: DoPrim) => emit(op_stream(e), top + 1) + case (e: Mux) => emit(Seq(e.cond," ? ",cast(e.tval)," : ",cast(e.fval)),top + 1) + case (e: ValidIf) => emit(Seq(cast(e.value)),top + 1) + case (e: WRef) => w write e.serialize + case (e: WSubField) => w write LowerTypes.loweredName(e) + case (e: WSubAccess) => w write ( + s"${LowerTypes.loweredName(e.exp)}[${LowerTypes.loweredName(e.index)}]") + case (e: WSubIndex) => w write e.serialize + case (e: Literal) => v_print(e) + case (e: VRandom) => w write s"{${e.nWords}{$$random}}" + case (t: UIntType) => + val wx = long_BANG(t) - 1 + if (wx > 0) w write s"[$wx:0]" + case (t: SIntType) => + val wx = long_BANG(t) - 1 + if (wx > 0) w write s"[$wx:0]" + case ClockType => + case (t: VectorType) => + emit(t.tpe, top + 1) + w write s"[${t.size - 1}:0]" + case Input => w write "input" + case Output => w write "output" + case (s: String) => w write s + case (i: Int) => w write i.toString + case (i: Long) => w write i.toString + case (t: VIndent) => w write " " + case (s: Seq[Any]) => + s foreach (emit(_, top + 1)) + if (top == 0) w write "\n" + case _ => error("Shouldn't be here") + } + } //;------------- PASS ----------------- - def v_print (e:Expression) = { - e match { - case UIntLiteral(value, IntWidth(width)) => { - val str = s"$width'h${value.toString(16)}" - w.get.write(str) - } - case SIntLiteral(value, IntWidth(width)) => { - val unsignedValue = value + (if (value < 0) BigInt(1) << width.toInt else 0) - val str = s"$width'sh${unsignedValue.toString(16)}" - w.get.write(str) - } - } + def v_print(e: Expression)(implicit w: Writer) = e match { + case UIntLiteral(value, IntWidth(width)) => + w write s"$width'h${value.toString(16)}" + case SIntLiteral(value, IntWidth(width)) => + val unsignedValue = value + (if (value < 0) BigInt(1) << width.toInt else 0) + w write s"$width'sh${unsignedValue.toString(16)}" } - def op_stream (doprim:DoPrim) : Seq[Any] = { - def cast_if (e:Expression) : Any = { - val signed = doprim.args.find(x => x.tpe match { - case _: SIntType => true - case _ => false - }) - if (signed == None) e - else e.tpe match { - case (t:SIntType) => Seq("$signed(",e,")") - case (t:UIntType) => Seq("$signed({1'b0,",e,"})") - } - } - def cast (e:Expression) : Any = { - (doprim.tpe) match { - case (t:UIntType) => e - case (t:SIntType) => Seq("$signed(",e,")") - } - } - def cast_as (e:Expression) : Any = { - (e.tpe) match { - case (t:UIntType) => e - case (t:SIntType) => Seq("$signed(",e,")") - } - } - def a0 () : Expression = doprim.args(0) - def a1 () : Expression = doprim.args(1) - def a2 () : Expression = doprim.args(2) - def c0 () : Int = doprim.consts(0).toInt - def c1 () : Int = doprim.consts(1).toInt - - def checkArgumentLegality(e: Expression) = e match { - case _: UIntLiteral => - case _: SIntLiteral => - case _: WRef => - case _: WSubField => - case _ => throw new EmitterException(s"Can't emit ${e.getClass.getName} as PrimOp argument") - } - doprim.args foreach checkArgumentLegality - - doprim.op match { - case Add => Seq(cast_if(a0())," + ", cast_if(a1())) - case Addw => Seq(cast_if(a0())," + ", cast_if(a1())) - case Sub => Seq(cast_if(a0())," - ", cast_if(a1())) - case Subw => Seq(cast_if(a0())," - ", cast_if(a1())) - case Mul => Seq(cast_if(a0())," * ", cast_if(a1()) ) - case Div => Seq(cast_if(a0())," / ", cast_if(a1()) ) - case Rem => Seq(cast_if(a0())," % ", cast_if(a1()) ) - case Lt => Seq(cast_if(a0())," < ", cast_if(a1())) - case Leq => Seq(cast_if(a0())," <= ", cast_if(a1())) - case Gt => Seq(cast_if(a0())," > ", cast_if(a1())) - case Geq => Seq(cast_if(a0())," >= ", cast_if(a1())) - case Eq => Seq(cast_if(a0())," == ", cast_if(a1())) - case Neq => Seq(cast_if(a0())," != ", cast_if(a1())) - case Pad => { - val w = long_BANG(a0().tpe) - val diff = (c0() - w) - if (w == 0) Seq(a0()) - else doprim.tpe match { - // Either sign extend or zero extend. - case (t:SIntType) => { - // If width == 1, don't extract bit - if (w == 1) Seq("{", c0(),"{", a0(), "}}") - else Seq("{{", diff, "{", a0(), "[", w - 1,"]}},", a0(), "}") - } - case (t) => Seq("{{", diff, "'d0}, ", a0(), "}") - } - } - case AsUInt => Seq("$unsigned(",a0(),")") - case AsSInt => Seq("$signed(",a0(),")") - case AsClock => Seq("$unsigned(",a0(),")") - case Dshlw => Seq(cast(a0())," << ", a1()) - case Dshl => Seq(cast(a0())," << ", a1()) - case Dshr => { - (doprim.tpe) match { - case (t:SIntType) => Seq(cast(a0())," >>> ",a1()) - case (t) => Seq(cast(a0())," >> ",a1()) - } - } - case Shlw => Seq(cast(a0())," << ", c0()) - case Shl => Seq(cast(a0())," << ",c0()) - case Shr => { - if (c0 >= long_BANG(a0.tpe)) - error("Verilog emitter does not support SHIFT_RIGHT >= arg width") - Seq(a0(),"[", long_BANG(a0().tpe) - 1,":",c0(),"]") - } - case Neg => Seq("-{",cast(a0()),"}") - case Cvt => { - a0().tpe match { - case (t:UIntType) => Seq("{1'b0,",cast(a0()),"}") - case (t:SIntType) => Seq(cast(a0())) - } - } - case Not => Seq("~ ",a0()) - case And => Seq(cast_as(a0())," & ", cast_as(a1())) - case Or => Seq(cast_as(a0())," | ", cast_as(a1())) - case Xor => Seq(cast_as(a0())," ^ ", cast_as(a1())) - case Andr => { - val v = ArrayBuffer[Seq[Any]]() - for (b <- 0 until long_BANG(doprim.tpe).toInt) { - v += Seq(cast(a0()),"[",b,"]") - } - v.reduce(_ + " & " + _) - } - case Orr => { - val v = ArrayBuffer[Seq[Any]]() - for (b <- 0 until long_BANG(doprim.tpe).toInt) { - v += Seq(cast(a0()),"[",b,"]") - } - v.reduce(_ + " | " + _) - } - case Xorr => { - val v = ArrayBuffer[Seq[Any]]() - for (b <- 0 until long_BANG(doprim.tpe).toInt) { - v += Seq(cast(a0()),"[",b,"]") - } - v.reduce(_ + " ^ " + _) - } - case Cat => Seq("{",cast(a0()),",",cast(a1()),"}") - case Bits => { - // If selecting zeroth bit and single-bit wire, just emit the wire - if (c0() == 0 && c1() == 0 && long_BANG(a0().tpe) == 1) Seq(a0()) - else if (c0() == c1()) Seq(a0(),"[",c0(),"]") - else Seq(a0(),"[",c0(),":",c1(),"]") - } - case Head => { - val w = long_BANG(a0().tpe) - val high = w - 1 - val low = w - c0() - Seq(a0(),"[",high,":",low,"]") + def op_stream(doprim: DoPrim): Seq[Any] = { + def cast_if(e: Expression): Any = { + doprim.args find (_.tpe match { + case (_: SIntType) => true + case (_) => false + }) match { + case None => e + case Some(_) => e.tpe match { + case (_: SIntType) => Seq("$signed(", e, ")") + case (_: UIntType) => Seq("$signed({1'b0,", e, "})") } - case Tail => { - val w = long_BANG(a0().tpe) - val low = w - c0() - 1 - Seq(a0(),"[",low,":",0,"]") + } + } + def cast(e: Expression): Any = doprim.tpe match { + case (t: UIntType) => e + case (t: SIntType) => Seq("$signed(",e,")") + } + def cast_as(e: Expression): Any = e.tpe match { + case (t: UIntType) => e + case (t: SIntType) => Seq("$signed(",e,")") + } + def a0: Expression = doprim.args(0) + def a1: Expression = doprim.args(1) + def c0: Int = doprim.consts(0).toInt + def c1: Int = doprim.consts(1).toInt + + def checkArgumentLegality(e: Expression) = e match { + case _: UIntLiteral | _: SIntLiteral | _: WRef | _: WSubField => + case _ => throw new EmitterException(s"Can't emit ${e.getClass.getName} as PrimOp argument") + } + doprim.args foreach checkArgumentLegality + doprim.op match { + case Add => Seq(cast_if(a0), " + ", cast_if(a1)) + case Addw => Seq(cast_if(a0), " + ", cast_if(a1)) + case Sub => Seq(cast_if(a0), " - ", cast_if(a1)) + case Subw => Seq(cast_if(a0), " - ", cast_if(a1)) + case Mul => Seq(cast_if(a0), " * ", cast_if(a1)) + case Div => Seq(cast_if(a0), " / ", cast_if(a1)) + case Rem => Seq(cast_if(a0), " % ", cast_if(a1)) + case Lt => Seq(cast_if(a0), " < ", cast_if(a1)) + case Leq => Seq(cast_if(a0), " <= ", cast_if(a1)) + case Gt => Seq(cast_if(a0), " > ", cast_if(a1)) + case Geq => Seq(cast_if(a0), " >= ", cast_if(a1)) + case Eq => Seq(cast_if(a0), " == ", cast_if(a1)) + case Neq => Seq(cast_if(a0), " != ", cast_if(a1)) + case Pad => + val w = long_BANG(a0.tpe) + val diff = (c0 - w) + if (w == 0) Seq(a0) + else doprim.tpe match { + // Either sign extend or zero extend. + // If width == 1, don't extract bit + case (_: SIntType) if w == 1 => Seq("{", c0, "{", a0, "}}") + case (_: SIntType) => Seq("{{", diff, "{", a0, "[", w - 1, "]}},", a0, "}") + case (_) => Seq("{{", diff, "'d0}, ", a0, "}") } - } + case AsUInt => Seq("$unsigned(", a0, ")") + case AsSInt => Seq("$signed(", a0, ")") + case AsClock => Seq("$unsigned(", a0, ")") + case Dshlw => Seq(cast(a0), " << ", a1) + case Dshl => Seq(cast(a0), " << ", a1) + case Dshr => (doprim.tpe) match { + case (_: SIntType) => Seq(cast(a0)," >>> ", a1) + case (_) => Seq(cast(a0), " >> ", a1) + } + case Shlw => Seq(cast(a0), " << ", c0) + case Shl => Seq(cast(a0), " << ", c0) + case Shr if c0 >= long_BANG(a0.tpe) => + error("Verilog emitter does not support SHIFT_RIGHT >= arg width") + case Shr => Seq(a0,"[", long_BANG(a0.tpe) - 1, ":", c0, "]") + case Neg => Seq("-{", cast(a0), "}") + case Cvt => a0.tpe match { + case (_: UIntType) => Seq("{1'b0,", cast(a0), "}") + case (_: SIntType) => Seq(cast(a0)) + } + case Not => Seq("~ ", a0) + case And => Seq(cast_as(a0), " & ", cast_as(a1)) + case Or => Seq(cast_as(a0), " | ", cast_as(a1)) + case Xor => Seq(cast_as(a0), " ^ ", cast_as(a1)) + case Andr => (0 until long_BANG(doprim.tpe).toInt) map ( + Seq(cast(a0), "[", _, "]")) reduce (_ + " & " + _) + case Orr => (0 until long_BANG(doprim.tpe).toInt) map ( + Seq(cast(a0), "[", _, "]")) reduce (_ + " | " + _) + case Xorr => (0 until long_BANG(doprim.tpe).toInt) map ( + Seq(cast(a0), "[", _, "]")) reduce (_ + " ^ " + _) + case Cat => Seq("{", cast(a0), ",", cast(a1), "}") + // If selecting zeroth bit and single-bit wire, just emit the wire + case Bits if c0 == 0 && c1 == 0 && long_BANG(a0.tpe) == 1 => Seq(a0) + case Bits if c0 == c1 => Seq(a0, "[", c0, "]") + case Bits => Seq(a0, "[", c0, ":", c1, "]") + case Head => + val w = long_BANG(a0.tpe) + val high = w - 1 + val low = w - c0 + Seq(a0, "[", high, ":", low, "]") + case Tail => + val w = long_BANG(a0.tpe) + val low = w - c0 - 1 + Seq(a0, "[", low, ":", 0, "]") + } } - def emit_verilog (m:Module) : DefModule = { - mname = m.name - val netlist = LinkedHashMap[WrappedExpression,Expression]() + def emit_verilog(m: Module)(implicit w: Writer): DefModule = { + val netlist = LinkedHashMap[WrappedExpression, Expression]() val simlist = ArrayBuffer[Statement]() val namespace = Namespace(m) - def build_netlist (s:Statement) : Statement = { - s match { - case (s:Connect) => netlist(s.loc) = s.expr - case (s:IsInvalid) => { - val n = namespace.newTemp - val e = wref(n,s.expr.tpe) - netlist(s.expr) = e - } - case (s:Conditionally) => simlist += s - case (s:DefNode) => { - val e = WRef(s.name,get_type(s),NodeKind(),MALE) - netlist(e) = s.value - } - case (s) => s map (build_netlist) - } - s + def build_netlist(s: Statement): Statement = s map build_netlist match { + case (s: Connect) => + netlist(s.loc) = s.expr + s + case (s: IsInvalid) => + netlist(s.expr) = wref(namespace.newTemp, s.expr.tpe) + s + case (s: Conditionally) => + simlist += s + s + case (s: DefNode) => + val e = WRef(s.name, get_type(s), NodeKind(), MALE) + netlist(e) = s.value + s + case (s) => s } val portdefs = ArrayBuffer[Seq[Any]]() @@ -309,14 +250,16 @@ class VerilogEmitter extends Emitter { val at_clock = LinkedHashMap[Expression,ArrayBuffer[Seq[Any]]]() val initials = ArrayBuffer[Seq[Any]]() val simulates = ArrayBuffer[Seq[Any]]() - def declare (b:String,n:String,t:Type) = { - t match { - case (t:VectorType) => declares += Seq(b," ",t.tpe," ",n," [0:",t.size - 1,"];") - case (t) => declares += Seq(b," ",t," ",n,";") - } + def declare (b: String, n: String, t: Type) = t match { + case (t: VectorType) => + declares += Seq(b, " ", t.tpe, " ", n, " [0:", t.size - 1, "];") + case (t) => + declares += Seq(b, " ", t, " ", n,";") + } + def assign (e: Expression, value: Expression) { + assigns += Seq("assign ", e, " = ", value, ";") } - def assign (e:Expression,value:Expression) = - assigns += Seq("assign ",e," = ",value,";") + // In simulation, assign garbage under a predicate def garbageAssign(e: Expression, syn: Expression, garbageCond: Expression) = { assigns += Seq("`ifndef RANDOMIZE_GARBAGE_ASSIGN") @@ -369,7 +312,8 @@ class VerilogEmitter extends Emitter { addUpdate(Mux(reset, tv, fv, mux_type_and_widths(tv, fv)), "") } } - def update (e:Expression,value:Expression,clk:Expression,en:Expression) = { + + def update(e: Expression, value: Expression, clk: Expression, en: Expression) { if (!at_clock.contains(clk)) at_clock(clk) = ArrayBuffer[Seq[Any]]() if (weq(en,one)) at_clock(clk) += Seq(e," <= ",value,";") else { @@ -378,46 +322,50 @@ class VerilogEmitter extends Emitter { at_clock(clk) += Seq("end") } } + // Declares an intermediate wire to hold a large enough random number. // Then, return the correct number of bits selected from the random value - def rand_string (t:Type) : Seq[Any] = { + def rand_string(t: Type) : Seq[Any] = { val nx = namespace.newTemp val rand = VRandom(long_BANG(t)) val tx = SIntType(IntWidth(rand.realWidth)) - declare("reg",nx,tx) - initials += Seq(wref(nx,tx)," = ",VRandom(long_BANG(t)),";") - Seq(nx,"[",long_BANG(t) - 1,":0]") + declare("reg",nx, tx) + initials += Seq(wref(nx, tx), " = ", VRandom(long_BANG(t)), ";") + Seq(nx, "[", long_BANG(t) - 1, ":0]") } + def initialize(e: Expression) = { initials += Seq("`ifdef RANDOMIZE_REG_INIT") initials += Seq(e, " = ", rand_string(e.tpe), ";") initials += Seq("`endif") } - def initialize_mem(s: DefMemory) = { - val index = WRef("initvar", s.dataType, ExpKind(), UNKNOWNGENDER) + + def initialize_mem(s: DefMemory) { + val index = wref("initvar", s.dataType) val rstring = rand_string(s.dataType) initials += Seq("`ifdef RANDOMIZE_MEM_INIT") initials += Seq("for (initvar = 0; initvar < ", s.depth, "; initvar = initvar+1)") - initials += Seq(tab, WSubAccess(wref(s.name, s.dataType), index, s.dataType, FEMALE), " = ", rstring,";") + initials += Seq(tab, WSubAccess(wref(s.name, s.dataType), index, s.dataType, FEMALE), + " = ", rstring,";") initials += Seq("`endif") } - def instantiate (n:String,m:String,es:Seq[Expression]) = { - instdeclares += Seq(m," ",n," (") - (es,0 until es.size).zipped.foreach{ (e,i) => { - val s = Seq(tab,".",remove_root(e),"(",LowerTypes.loweredName(e),")") - if (i != es.size - 1) instdeclares += Seq(s,",") - else instdeclares += s - }} + + 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(");") - for (e <- es) { - 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)) - } + 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]) = { + + 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") if (cond.nonEmpty) { @@ -435,261 +383,248 @@ class VerilogEmitter extends Emitter { } at_clock(clk) += Seq("`endif") } - def stop(ret: Int): Seq[Any] = { - Seq(if (ret == 0) "$finish;" else "$fatal;") - } - def printf (str:StringLit,args:Seq[Expression]) : Seq[Any] = { - val q = '"'.toString - val strx = Seq(q + VerilogStringLitHandler.escape(str) + q) ++ - args.flatMap(x => Seq(",",x)) - Seq("$fwrite(32'h80000002,",strx,");") + + def stop(ret: Int): Seq[Any] = Seq(if (ret == 0) "$finish;" else "$fatal;") + + def printf(str: StringLit, args: Seq[Expression]): Seq[Any] = { + val q = '"'.toString + val strx = s"""$q${VerilogStringLitHandler escape str}$q""" +: + (args flatMap (Seq("," , _))) + Seq("$fwrite(32'h80000002,", strx, ");") } - def delay (e:Expression, n:Int, clk:Expression) : Expression = { - ((0 until n) foldLeft e){(ex, i) => - val name = namespace.newTemp - declare("reg",name,e.tpe) - val exx = WRef(name,e.tpe,ExpKind(),UNKNOWNGENDER) - initialize(exx) - update(exx,ex,clk,one) - exx - } + + def delay(e: Expression, n: Int, clk: Expression): Expression = { + ((0 until n) foldLeft e){(ex, i) => + val name = namespace.newTemp + declare("reg", name, e.tpe) + val exx = wref(name, e.tpe) + initialize(exx) + update(exx, ex, clk, one) + exx + } } - def build_ports () = { - (m.ports,0 until m.ports.size).zipped.foreach{(p,i) => { - p.direction match { - case Input => portdefs += Seq(p.direction," ",p.tpe," ",p.name) - case Output => { - portdefs += Seq(p.direction," ",p.tpe," ",p.name) - val ex = WRef(p.name,p.tpe,PortKind(),FEMALE) - assign(ex,netlist(ex)) - } - } - }} + + def build_ports: Unit = m.ports.zipWithIndex foreach {case (p, i) => + p.direction match { + case Input => + portdefs += Seq(p.direction, " ", p.tpe, " ", p.name) + case Output => + portdefs += Seq(p.direction, " ", p.tpe, " ", p.name) + val ex = WRef(p.name, p.tpe, PortKind(), FEMALE) + assign(ex, netlist(ex)) + } } - def build_streams (s:Statement) : Statement = { - s match { - case EmptyStmt => s - case (s:Connect) => s - case (s:DefWire) => - declare("wire",s.name,s.tpe) - val e = wref(s.name,s.tpe) - assign(e,netlist(e)) - case (s:DefRegister) => { - declare("reg",s.name,s.tpe) - val e = wref(s.name,s.tpe) - update_and_reset(e,s.clock,s.reset,s.init) - initialize(e) - } - case (s:IsInvalid) => { - val wref = netlist(s.expr).asInstanceOf[WRef] - declare("wire",wref.name,s.expr.tpe) - invalidAssign(wref) - } - case (s:DefNode) => { - declare("wire",s.name,s.value.tpe) - assign(WRef(s.name,s.value.tpe,NodeKind(),MALE),s.value) - } - case (s:Stop) => { - val errorString = StringLit(s"${s.ret}\n".getBytes) - simulate(s.clk, s.en, stop(s.ret), Some("STOP_COND")) - } - case (s:Print) => simulate(s.clk, s.en, printf(s.string, s.args), Some("PRINTF_COND")) - case (s:WDefInstance) => { - val es = create_exps(WRef(s.name,s.tpe,InstanceKind(),MALE)) - instantiate(s.name,s.module,es) - } - case (s:DefMemory) => { - val mem = WRef(s.name,get_type(s),MemKind(s.readers ++ s.writers ++ s.readwriters),UNKNOWNGENDER) - def mem_exp (p:String,f:String) = { - val t1 = field_type(mem.tpe,p) - val t2 = field_type(t1,f) - val x = WSubField(mem,p,t1,UNKNOWNGENDER) - WSubField(x,f,t2,UNKNOWNGENDER) - } - - declare("reg",s.name,VectorType(s.dataType,s.depth)) - initialize_mem(s) - for (r <- s.readers ) { - val data = mem_exp(r,"data") - val addr = mem_exp(r,"addr") - val en = mem_exp(r,"en") - //Ports should share an always@posedge, so can't have intermediary wire - val clk = netlist(mem_exp(r,"clk")) - - declare("wire",LowerTypes.loweredName(data),data.tpe) - declare("wire",LowerTypes.loweredName(addr),addr.tpe) - declare("wire",LowerTypes.loweredName(en),en.tpe) - - //; Read port - assign(addr,netlist(addr)) //;Connects value to m.r.addr - assign(en,netlist(en)) //;Connects value to m.r.en - val addr_pipe = delay(addr,s.readLatency-1,clk) - val en_pipe = if (weq(en,one)) one else delay(en,s.readLatency-1,clk) - val addrx = if (s.readLatency > 0) { - val name = namespace.newTemp - val ref = WRef(name,addr.tpe,ExpKind(),UNKNOWNGENDER) - declare("reg",name,addr.tpe) - initialize(ref) - update(ref,addr_pipe,clk,en_pipe) - ref - } else addr - val mem_port = WSubAccess(mem,addrx,s.dataType,UNKNOWNGENDER) - val depthValue = UIntLiteral(s.depth, IntWidth(BigInt(s.depth).bitLength)) - val garbageGuard = DoPrim(Geq, Seq(addrx, depthValue), Seq(), UnknownType) - - if ((s.depth & (s.depth - 1)) == 0) - assign(data, mem_port) - else - garbageAssign(data, mem_port, garbageGuard) - } - - for (w <- s.writers ) { - val data = mem_exp(w,"data") - val addr = mem_exp(w,"addr") - val mask = mem_exp(w,"mask") - val en = mem_exp(w,"en") - //Ports should share an always@posedge, so can't have intermediary wire - val clk = netlist(mem_exp(w,"clk")) - - declare("wire",LowerTypes.loweredName(data),data.tpe) - declare("wire",LowerTypes.loweredName(addr),addr.tpe) - declare("wire",LowerTypes.loweredName(mask),mask.tpe) - declare("wire",LowerTypes.loweredName(en),en.tpe) - - //; Write port - assign(data,netlist(data)) - assign(addr,netlist(addr)) - assign(mask,netlist(mask)) - assign(en,netlist(en)) - - val datax = delay(data,s.writeLatency - 1,clk) - val addrx = delay(addr,s.writeLatency - 1,clk) - val maskx = delay(mask,s.writeLatency - 1,clk) - val enx = delay(en,s.writeLatency - 1,clk) - val mem_port = WSubAccess(mem,addrx,s.dataType,UNKNOWNGENDER) - update(mem_port,datax,clk,AND(enx,maskx)) - } - - for (rw <- s.readwriters) { - val wmode = mem_exp(rw,"wmode") - val rdata = mem_exp(rw,"rdata") - val wdata = mem_exp(rw,"wdata") - val wmask = mem_exp(rw,"wmask") - val addr = mem_exp(rw,"addr") - val en = mem_exp(rw,"en") - //Ports should share an always@posedge, so can't have intermediary wire - val clk = netlist(mem_exp(rw,"clk")) - - declare("wire",LowerTypes.loweredName(wmode),wmode.tpe) - declare("wire",LowerTypes.loweredName(rdata),rdata.tpe) - declare("wire",LowerTypes.loweredName(wdata),wdata.tpe) - declare("wire",LowerTypes.loweredName(wmask),wmask.tpe) - declare("wire",LowerTypes.loweredName(addr),addr.tpe) - declare("wire",LowerTypes.loweredName(en),en.tpe) - - //; Assigned to lowered wires of each - assign(addr,netlist(addr)) - assign(wdata,netlist(wdata)) - assign(addr,netlist(addr)) - assign(wmask,netlist(wmask)) - assign(en,netlist(en)) - assign(wmode,netlist(wmode)) - - //; Delay new signals by latency - val raddrx = if (s.readLatency > 0) delay(addr,s.readLatency - 1,clk) else addr - val waddrx = delay(addr,s.writeLatency - 1,clk) - val enx = delay(en,s.writeLatency - 1,clk) - val wmodex = delay(wmode,s.writeLatency - 1,clk) - val wdatax = delay(wdata,s.writeLatency - 1,clk) - val wmaskx = delay(wmask,s.writeLatency - 1,clk) - - val raddrxx = if (s.readLatency > 0) { - val name = namespace.newTemp - val ref = WRef(name,raddrx.tpe,ExpKind(),UNKNOWNGENDER) - declare("reg",name,raddrx.tpe) - initialize(ref) - ref - } else addr - val rmem_port = WSubAccess(mem,raddrxx,s.dataType,UNKNOWNGENDER) - assign(rdata,rmem_port) - val wmem_port = WSubAccess(mem,waddrx,s.dataType,UNKNOWNGENDER) - - def declare_and_assign(exp: Expression) = { - val name = namespace.newTemp - val ref = wref(name, exp.tpe) - declare("wire", name, exp.tpe) - assign(ref, exp) - ref - } - val ren = declare_and_assign(NOT(wmodex)) - val wen = declare_and_assign(AND(wmodex, wmaskx)) - if (s.readLatency > 0) - update(raddrxx,raddrx,clk,AND(enx,ren)) - update(wmem_port,wdatax,clk,AND(enx,wen)) - } + + 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)) + s + case (s: DefRegister) => + declare("reg", s.name, s.tpe) + val e = wref(s.name, s.tpe) + update_and_reset(e, s.clock, s.reset, s.init) + initialize(e) + s + case (s: IsInvalid) => + val wref = netlist(s.expr) match { case e: WRef => e } + declare("reg", wref.name, s.expr.tpe) + initialize(wref) + s + case (s: DefNode) => + declare("wire", s.name, s.value.tpe) + assign(WRef(s.name, s.value.tpe, NodeKind(), MALE), s.value) + s + case (s: Stop) => + val errorString = StringLit(s"${s.ret}\n".getBytes) + simulate(s.clk, s.en, stop(s.ret), Some("STOP_COND")) + s + case (s: Print) => + simulate(s.clk, s.en, printf(s.string, s.args), Some("PRINTF_COND")) + s + case (s: WDefInstance) => + val es = create_exps(WRef(s.name, s.tpe, InstanceKind(), MALE)) + instantiate(s.name, s.module, es) + s + case (s: DefMemory) => + val mem = WRef(s.name, get_type(s), + MemKind(s.readers ++ s.writers ++ s.readwriters), UNKNOWNGENDER) + def mem_exp (p: String, f: String) = { + val t1 = field_type(mem.tpe, p) + val t2 = field_type(t1, f) + val x = WSubField(mem, p, t1, UNKNOWNGENDER) + WSubField(x, f, t2, UNKNOWNGENDER) + } + + declare("reg", s.name, VectorType(s.dataType, s.depth)) + initialize_mem(s) + for (r <- s.readers) { + val data = mem_exp(r, "data") + val addr = mem_exp(r, "addr") + val en = mem_exp(r, "en") + // Ports should share an always@posedge, so can't have intermediary wire + val clk = netlist(mem_exp(r, "clk")) + + declare("wire", LowerTypes.loweredName(data), data.tpe) + declare("wire", LowerTypes.loweredName(addr), addr.tpe) + declare("wire", LowerTypes.loweredName(en), en.tpe) + + //; Read port + assign(addr, netlist(addr)) //;Connects value to m.r.addr + assign(en, netlist(en)) //;Connects value to m.r.en + val addr_pipe = delay(addr,s.readLatency-1,clk) + val en_pipe = if (weq(en,one)) one else delay(en,s.readLatency-1,clk) + val addrx = if (s.readLatency > 0) { + val name = namespace.newTemp + val ref = wref(name, addr.tpe) + declare("reg", name, addr.tpe) + initialize(ref) + update(ref,addr_pipe,clk,en_pipe) + ref + } else addr + val mem_port = WSubAccess(mem,addrx,s.dataType,UNKNOWNGENDER) + val depthValue = UIntLiteral(s.depth, IntWidth(BigInt(s.depth).bitLength)) + val garbageGuard = DoPrim(Geq, Seq(addrx, depthValue), Seq(), UnknownType) + + if ((s.depth & (s.depth - 1)) == 0) + assign(data, mem_port) + else + garbageAssign(data, mem_port, garbageGuard) + } + + for (w <- s.writers) { + val data = mem_exp(w, "data") + val addr = mem_exp(w, "addr") + val mask = mem_exp(w, "mask") + val en = mem_exp(w, "en") + //Ports should share an always@posedge, so can't have intermediary wire + val clk = netlist(mem_exp(w, "clk")) + + declare("wire", LowerTypes.loweredName(data), data.tpe) + declare("wire", LowerTypes.loweredName(addr), addr.tpe) + declare("wire", LowerTypes.loweredName(mask), mask.tpe) + declare("wire", LowerTypes.loweredName(en), en.tpe) + + //; Write port + assign(data,netlist(data)) + assign(addr,netlist(addr)) + assign(mask,netlist(mask)) + assign(en,netlist(en)) + + val datax = delay(data, s.writeLatency - 1, clk) + val addrx = delay(addr, s.writeLatency - 1, clk) + val maskx = delay(mask, s.writeLatency - 1, clk) + val enx = delay(en, s.writeLatency - 1, clk) + val mem_port = WSubAccess(mem, addrx, s.dataType, UNKNOWNGENDER) + update(mem_port, datax, clk, AND(enx, maskx)) + } + + for (rw <- s.readwriters) { + val wmode = mem_exp(rw, "wmode") + val rdata = mem_exp(rw, "rdata") + val wdata = mem_exp(rw, "wdata") + val wmask = mem_exp(rw, "wmask") + val addr = mem_exp(rw, "addr") + val en = mem_exp(rw, "en") + //Ports should share an always@posedge, so can't have intermediary wire + val clk = netlist(mem_exp(rw, "clk")) + + declare("wire", LowerTypes.loweredName(wmode), wmode.tpe) + declare("wire", LowerTypes.loweredName(rdata), rdata.tpe) + declare("wire", LowerTypes.loweredName(wdata), wdata.tpe) + declare("wire", LowerTypes.loweredName(wmask), wmask.tpe) + declare("wire", LowerTypes.loweredName(addr), addr.tpe) + declare("wire", LowerTypes.loweredName(en), en.tpe) + + //; Assigned to lowered wires of each + assign(addr, netlist(addr)) + assign(wdata, netlist(wdata)) + assign(addr, netlist(addr)) + assign(wmask, netlist(wmask)) + assign(en, netlist(en)) + assign(wmode, netlist(wmode)) + + //; Delay new signals by latency + val raddrx = if (s.readLatency > 0) delay(addr, s.readLatency - 1, clk) else addr + val waddrx = delay(addr,s.writeLatency - 1,clk) + val enx = delay(en,s.writeLatency - 1,clk) + val wmodex = delay(wmode,s.writeLatency - 1,clk) + val wdatax = delay(wdata,s.writeLatency - 1,clk) + val wmaskx = delay(wmask,s.writeLatency - 1,clk) + + val raddrxx = if (s.readLatency > 0) { + val name = namespace.newTemp + val ref = wref(name, raddrx.tpe) + declare("reg", name, raddrx.tpe) + initialize(ref) + ref + } else addr + val rmem_port = WSubAccess(mem, raddrxx, s.dataType, UNKNOWNGENDER) + assign(rdata, rmem_port) + val wmem_port = WSubAccess(mem, waddrx, s.dataType, UNKNOWNGENDER) + + def declare_and_assign(exp: Expression) = { + val name = namespace.newTemp + val ref = wref(name, exp.tpe) + declare("wire", name, exp.tpe) + assign(ref, exp) + ref } - case (s:Block) => s map (build_streams) - } - s + val ren = declare_and_assign(NOT(wmodex)) + val wen = declare_and_assign(AND(wmodex, wmaskx)) + if (s.readLatency > 0) + update(raddrxx, raddrx, clk, AND(enx, ren)) + update(wmem_port, wdatax, clk, AND(enx, wen)) + } + s + case s => s } - def emit_streams () = { - emit(Seq("module ",m.name,"(")) - if (not_empty(portdefs)) { - (portdefs,0 until portdefs.size).zipped.foreach{ (x,i) => { - if (i != portdefs.size - 1) emit(Seq(tab,x,",")) - else emit(Seq(tab,x)) - }} - } - emit(Seq(");")) + def emit_streams { + emit(Seq("module ", m.name, "(")) + for ((x, i) <- portdefs.zipWithIndex) { + if (i != portdefs.size - 1) + emit(Seq(tab, x, ",")) + else + emit(Seq(tab, x)) + } + emit(Seq(");")) - if (not_empty(declares)) { - for (x <- declares) emit(Seq(tab,x)) - } - if (not_empty(instdeclares)) { - for (x <- instdeclares) emit(Seq(tab,x)) - } - if (not_empty(assigns)) { - for (x <- assigns) emit(Seq(tab,x)) - } - if (not_empty(initials)) { - emit(Seq("`ifdef RANDOMIZE")) - emit(Seq(" integer initvar;")) - emit(Seq(" initial begin")) - // This enables test benches to set the random values at time 0.001, - // then start the simulation later - // Verilator does not support delay statements, so they are omitted. - emit(Seq(" `ifndef verilator")) - emit(Seq(" #0.002 begin end")) - emit(Seq(" `endif")) - for (x <- initials) { - emit(Seq(tab,x)) - } - emit(Seq(" end")) - emit(Seq("`endif")) - } - - for (clk_stream <- at_clock) { - if (not_empty(clk_stream._2)) { - emit(Seq(tab,"always @(posedge ",clk_stream._1,") begin")) - for (x <- clk_stream._2) { - emit(Seq(tab,tab,x)) - } - emit(Seq(tab,"end")) - } - } - - emit(Seq("endmodule")) + for (x <- declares) emit(Seq(tab, x)) + for (x <- instdeclares) emit(Seq(tab, x)) + for (x <- assigns) emit(Seq(tab, x)) + if (!initials.isEmpty) { + emit(Seq("`ifdef RANDOMIZE")) + emit(Seq(" integer initvar;")) + emit(Seq(" initial begin")) + // This enables test benches to set the random values at time 0.001, + // then start the simulation later + // Verilator does not support delay statements, so they are omitted. + emit(Seq(" `ifndef verilator")) + emit(Seq(" #0.002 begin end")) + emit(Seq(" `endif")) + for (x <- initials) emit(Seq(tab, x)) + emit(Seq(" end")) + emit(Seq("`endif")) + } + + for (clk_stream <- at_clock if !clk_stream._2.isEmpty) { + emit(Seq(tab, "always @(posedge ", clk_stream._1, ") begin")) + for (x <- clk_stream._2) emit(Seq(tab, tab, x)) + emit(Seq(tab, "end")) + } + emit(Seq("endmodule")) } build_netlist(m.body) - build_ports() + build_ports build_streams(m.body) - emit_streams() + emit_streams m } - def emit_preamble() { + def emit_preamble(implicit w: Writer) { emit(Seq( "`ifdef RANDOMIZE_GARBAGE_ASSIGN\n", "`define RANDOMIZE\n", @@ -706,29 +641,10 @@ class VerilogEmitter extends Emitter { } def run(c: Circuit, w: Writer) = { - this.w = Some(w) - emit_preamble() - for (m <- c.modules) { - m match { - case (m:Module) => emit_verilog(m) - case (m:ExtModule) => false - } - } + emit_preamble(w) + c.modules foreach { + case (m: Module) => emit_verilog(m)(w) + case (m: ExtModule) => + } } - //def run(c: Circuit, w: Writer) - //{ - // logger.debug(s"Verilog Emitter is not yet implemented in Scala") - // val toStanza = Files.createTempFile(Paths.get(""), "verilog", ".fir") - // val fromStanza = Files.createTempFile(Paths.get(""), "verilog", ".fir") - // Files.write(toStanza, c.serialize.getBytes) - - // val cmd = Seq("firrtl-stanza", "-i", toStanza.toString, "-o", fromStanza.toString, "-b", "verilog") - // logger.debug(cmd.mkString(" ")) - // val ret = cmd.! - // // Copy from Stanza output to user requested outputFile (we can't get filename from Writer) - // Source.fromFile(fromStanza.toString) foreach { w.write(_) } - - // Files.delete(toStanza) - // Files.delete(fromStanza) - //} } |
