1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
// See LICENSE for license details.
package chisel3.internal.firrtl
import chisel3._
import chisel3.core.UserDirection
import chisel3.experimental._
import chisel3.internal.sourceinfo.{NoSourceInfo, SourceLine}
private[chisel3] object Emitter {
def emit(circuit: Circuit): String = new Emitter(circuit).toString
}
private class Emitter(circuit: Circuit) {
override def toString: String = res.toString
private def emitPort(e: Port): String = {
val dir = e.dir match {
case UserDirection.Unspecified | UserDirection.Output => "output"
case UserDirection.Flip | UserDirection.Input => "input"
}
s"$dir ${e.id.getRef.name} : ${emitType(e.id)}"
}
private def emitType(d: Data, clearDir: Boolean = false): String = d match {
case d: Clock => "Clock"
case d: UInt => s"UInt${d.width}"
case d: SInt => s"SInt${d.width}"
case d: FixedPoint => s"Fixed${d.width}${d.binaryPoint}"
case d: Analog => s"Analog${d.width}"
case d: Vec[_] => s"${emitType(d.sample_element, clearDir)}[${d.length}]"
case d: Record => {
val childClearDir = clearDir ||
d.userDirection == UserDirection.Input || d.userDirection == UserDirection.Output
def eltPort(elt: Data): String = (childClearDir, firrtlUserDirOf(elt)) match {
case (true, _) =>
s"${elt.getRef.name} : ${emitType(elt, true)}"
case (false, UserDirection.Unspecified | UserDirection.Output) =>
s"${elt.getRef.name} : ${emitType(elt, false)}"
case (false, UserDirection.Flip | UserDirection.Input) =>
s"flip ${elt.getRef.name} : ${emitType(elt, false)}"
}
d.elements.toIndexedSeq.reverse.map(e => eltPort(e._2)).mkString("{", ", ", "}")
}
}
private def firrtlUserDirOf(d: Data): UserDirection = d match {
case d: Vec[_] =>
UserDirection.fromParent(d.userDirection, firrtlUserDirOf(d.sample_element))
case d => d.userDirection
}
private def emit(e: Command, ctx: Component): String = {
val firrtlLine = e match {
case e: DefPrim[_] => s"node ${e.name} = ${e.op.name}(${e.args.map(_.fullName(ctx)).mkString(", ")})"
case e: DefWire => s"wire ${e.name} : ${emitType(e.id)}"
case e: DefReg => s"reg ${e.name} : ${emitType(e.id)}, ${e.clock.fullName(ctx)}"
case e: DefRegInit => s"reg ${e.name} : ${emitType(e.id)}, ${e.clock.fullName(ctx)} with : (reset => (${e.reset.fullName(ctx)}, ${e.init.fullName(ctx)}))"
case e: DefMemory => s"cmem ${e.name} : ${emitType(e.t)}[${e.size}]"
case e: DefSeqMemory => s"smem ${e.name} : ${emitType(e.t)}[${e.size}]"
case e: DefMemPort[_] => s"${e.dir} mport ${e.name} = ${e.source.fullName(ctx)}[${e.index.fullName(ctx)}], ${e.clock.fullName(ctx)}"
case e: Connect => s"${e.loc.fullName(ctx)} <= ${e.exp.fullName(ctx)}"
case e: BulkConnect => s"${e.loc1.fullName(ctx)} <- ${e.loc2.fullName(ctx)}"
case e: Attach => e.locs.map(_.fullName(ctx)).mkString("attach (", ", ", ")")
case e: Stop => s"stop(${e.clock.fullName(ctx)}, UInt<1>(1), ${e.ret})"
case e: Printf =>
val (fmt, args) = e.pable.unpack(ctx)
val printfArgs = Seq(e.clock.fullName(ctx), "UInt<1>(1)",
"\"" + printf.format(fmt) + "\"") ++ args
printfArgs mkString ("printf(", ", ", ")")
case e: DefInvalid => s"${e.arg.fullName(ctx)} is invalid"
case e: DefInstance => s"inst ${e.name} of ${e.id.name}"
case w: WhenBegin =>
indent()
s"when ${w.pred.fullName(ctx)} :"
case _: WhenEnd =>
unindent()
s"skip"
}
firrtlLine + e.sourceInfo.makeMessage(" " + _)
}
private def emitParam(name: String, p: Param): String = {
val str = p match {
case IntParam(value) => value.toString
case DoubleParam(value) => value.toString
case StringParam(str) => "\"" + str + "\""
case RawParam(str) => "'" + str + "'"
}
s"parameter $name = $str"
}
/** Generates the FIRRTL module declaration.
*/
private def moduleDecl(m: Component): String = m.id match {
case _: chisel3.core.BaseBlackBox => newline + s"extmodule ${m.name} : "
case _: chisel3.core.UserModule => newline + s"module ${m.name} : "
}
/** Generates the FIRRTL module definition.
*/
private def moduleDefn(m: Component): String = {
val body = new StringBuilder
withIndent {
for (p <- m.ports)
body ++= newline + emitPort(p)
body ++= newline
m match {
case bb: DefBlackBox =>
// Firrtl extmodule can overrule name
body ++= newline + s"defname = ${bb.id.desiredName}"
body ++= newline + (bb.params map { case (n, p) => emitParam(n, p) } mkString newline)
case mod: DefModule => for (cmd <- mod.commands) {
body ++= newline + emit(cmd, mod)
}
}
body ++= newline
}
body.toString()
}
/** Returns the FIRRTL declaration and body of a module, or nothing if it's a
* duplicate of something already emitted (on the basis of simple string
* matching).
*/
private def emit(m: Component): String = {
// Generate the body.
val sb = new StringBuilder
sb.append(moduleDecl(m))
sb.append(moduleDefn(m))
sb.result
}
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() }
private val res = new StringBuilder()
res ++= s";${Driver.chiselVersionString}\n"
res ++= s"circuit ${circuit.name} : "
withIndent { circuit.components.foreach(c => res ++= emit(c)) }
res ++= newline
}
|