Move passes from pfpmp to barstools. (#5)
* Move passes from pfpmp to barstools. * add an app that does both the harness and top generation This reduces the number of firrtl.compile calls * Add the ability to read annotations file This helps with chisel annotation integration
This commit is contained in:
36
tapeout/src/main/scala/transforms/ConvertToExtModPass.scala
Normal file
36
tapeout/src/main/scala/transforms/ConvertToExtModPass.scala
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package barstools.tapeout.transforms
|
||||||
|
|
||||||
|
import firrtl._
|
||||||
|
import firrtl.ir._
|
||||||
|
import firrtl.passes.Pass
|
||||||
|
|
||||||
|
// Converts some modules to external modules, based on a given function. If
|
||||||
|
// that function returns "true" then the module is converted into an ExtModule,
|
||||||
|
// otherwise it's left alone.
|
||||||
|
class ConvertToExtModPass(classify: (Module) => Boolean) extends Pass {
|
||||||
|
def name = "Convert to External Modules"
|
||||||
|
|
||||||
|
def run(c: Circuit): Circuit = {
|
||||||
|
val modulesx = c.modules.map {
|
||||||
|
case m: ExtModule => m
|
||||||
|
case m: Module =>
|
||||||
|
if (classify(m)) {
|
||||||
|
new ExtModule(m.info, m.name, m.ports, m.name, Seq.empty)
|
||||||
|
} else {
|
||||||
|
m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Circuit(c.info, modulesx, c.main)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class ConvertToExtMod(classify: (Module) => Boolean) extends Transform with PassBased {
|
||||||
|
def inputForm = MidForm
|
||||||
|
def outputForm = MidForm
|
||||||
|
def passSeq = Seq(new ConvertToExtModPass(classify))
|
||||||
|
|
||||||
|
def execute(state: CircuitState): CircuitState = {
|
||||||
|
CircuitState(runPasses(state.circuit), state.form)
|
||||||
|
}
|
||||||
|
}
|
||||||
32
tapeout/src/main/scala/transforms/EnumerateModules.scala
Normal file
32
tapeout/src/main/scala/transforms/EnumerateModules.scala
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package barstools.tapeout.transforms
|
||||||
|
|
||||||
|
import firrtl._
|
||||||
|
import firrtl.ir._
|
||||||
|
import firrtl.passes.Pass
|
||||||
|
|
||||||
|
class EnumerateModulesPass(enumerate: (Module) => Unit) extends Pass {
|
||||||
|
def name = "Enumurate Modules"
|
||||||
|
|
||||||
|
def run(c: Circuit): Circuit = {
|
||||||
|
val modulesx = c.modules.map {
|
||||||
|
case m: ExtModule => m
|
||||||
|
case m: Module => {
|
||||||
|
enumerate(m)
|
||||||
|
m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Circuit(c.info, modulesx, c.main)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EnumerateModules(enumerate: (Module) => Unit) extends Transform with PassBased {
|
||||||
|
def inputForm = LowForm
|
||||||
|
def outputForm = LowForm
|
||||||
|
def passSeq = Seq(new EnumerateModulesPass(enumerate))
|
||||||
|
|
||||||
|
def execute(state: CircuitState): CircuitState = {
|
||||||
|
CircuitState(runPasses(state.circuit), state.form)
|
||||||
|
}
|
||||||
|
}
|
||||||
79
tapeout/src/main/scala/transforms/GenerateHarness.scala
Normal file
79
tapeout/src/main/scala/transforms/GenerateHarness.scala
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package barstools.tapeout.transforms
|
||||||
|
|
||||||
|
import firrtl._
|
||||||
|
import firrtl.ir._
|
||||||
|
import firrtl.annotations._
|
||||||
|
import firrtl.passes.Pass
|
||||||
|
|
||||||
|
object AllModules {
|
||||||
|
private var modules = Set[String]()
|
||||||
|
def add(module: String) = {
|
||||||
|
modules = modules | Set(module)
|
||||||
|
}
|
||||||
|
def rename(module: String) = {
|
||||||
|
var new_name = module
|
||||||
|
while (modules.contains(new_name))
|
||||||
|
new_name = new_name + "_inTestHarness"
|
||||||
|
new_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object GenerateHarness extends App {
|
||||||
|
var input: Option[String] = None
|
||||||
|
var output: Option[String] = None
|
||||||
|
var synTop: Option[String] = None
|
||||||
|
var harnessTop: Option[String] = None
|
||||||
|
|
||||||
|
var usedOptions = Set.empty[Integer]
|
||||||
|
args.zipWithIndex.foreach{ case (arg, i) =>
|
||||||
|
arg match {
|
||||||
|
case "-i" => {
|
||||||
|
input = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "-o" => {
|
||||||
|
output = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--syn-top" => {
|
||||||
|
synTop = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--harness-top" => {
|
||||||
|
harnessTop = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case _ => {
|
||||||
|
if (! (usedOptions contains i)) {
|
||||||
|
error("Unknown option " + arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
firrtl.Driver.compile(
|
||||||
|
input.get,
|
||||||
|
output.get,
|
||||||
|
new VerilogCompiler(),
|
||||||
|
Parser.UseInfo,
|
||||||
|
Seq(
|
||||||
|
new ReParentCircuit(synTop.get),
|
||||||
|
new RemoveUnusedModules,
|
||||||
|
new EnumerateModules( { m => if (m.name != synTop.get) { AllModules.add(m.name) } } )
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
firrtl.Driver.compile(
|
||||||
|
input.get,
|
||||||
|
output.get,
|
||||||
|
new VerilogCompiler(),
|
||||||
|
Parser.UseInfo,
|
||||||
|
Seq(
|
||||||
|
new ConvertToExtMod((m) => m.name == synTop.get),
|
||||||
|
new RemoveUnusedModules,
|
||||||
|
new RenameModulesAndInstances((m) => AllModules.rename(m))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
77
tapeout/src/main/scala/transforms/GenerateTop.scala
Normal file
77
tapeout/src/main/scala/transforms/GenerateTop.scala
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package barstools.tapeout.transforms
|
||||||
|
|
||||||
|
import firrtl._
|
||||||
|
import firrtl.ir._
|
||||||
|
import firrtl.annotations._
|
||||||
|
import firrtl.passes.Pass
|
||||||
|
|
||||||
|
object GenerateTop extends App {
|
||||||
|
var input: Option[String] = None
|
||||||
|
var output: Option[String] = None
|
||||||
|
var synTop: Option[String] = None
|
||||||
|
var harnessTop: Option[String] = None
|
||||||
|
var seqMemFlags: Option[String] = Some("-o:unused.confg")
|
||||||
|
var listClocks: Option[String] = Some("-o:unused.clocks")
|
||||||
|
|
||||||
|
var usedOptions = Set.empty[Integer]
|
||||||
|
args.zipWithIndex.foreach{ case (arg, i) =>
|
||||||
|
arg match {
|
||||||
|
case "-i" => {
|
||||||
|
input = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "-o" => {
|
||||||
|
output = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--syn-top" => {
|
||||||
|
synTop = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--harness-top" => {
|
||||||
|
harnessTop = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--seq-mem-flags" => {
|
||||||
|
seqMemFlags = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--list-clocks" => {
|
||||||
|
listClocks = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case _ => {
|
||||||
|
if (! (usedOptions contains i)) {
|
||||||
|
error("Unknown option " + arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
firrtl.Driver.compile(
|
||||||
|
input.get,
|
||||||
|
output.get,
|
||||||
|
new VerilogCompiler(),
|
||||||
|
Parser.UseInfo,
|
||||||
|
Seq(
|
||||||
|
new ReParentCircuit(synTop.get),
|
||||||
|
new RemoveUnusedModules,
|
||||||
|
new passes.memlib.InferReadWrite(),
|
||||||
|
new passes.memlib.ReplSeqMem(),
|
||||||
|
new passes.clocklist.ClockListTransform()
|
||||||
|
),
|
||||||
|
AnnotationMap(Seq(
|
||||||
|
passes.memlib.InferReadWriteAnnotation(
|
||||||
|
s"${synTop.get}"
|
||||||
|
),
|
||||||
|
passes.clocklist.ClockListAnnotation(
|
||||||
|
s"-c:${synTop.get}:-m:${synTop.get}:${listClocks.get}"
|
||||||
|
),
|
||||||
|
passes.memlib.ReplSeqMemAnnotation(
|
||||||
|
s"-c:${synTop.get}:${seqMemFlags.get}"
|
||||||
|
)
|
||||||
|
))
|
||||||
|
)
|
||||||
|
}
|
||||||
120
tapeout/src/main/scala/transforms/GenerateTopAndHarness.scala
Normal file
120
tapeout/src/main/scala/transforms/GenerateTopAndHarness.scala
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package barstools.tapeout.transforms
|
||||||
|
|
||||||
|
import firrtl._
|
||||||
|
import firrtl.ir._
|
||||||
|
import firrtl.annotations._
|
||||||
|
import firrtl.passes.Pass
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import firrtl.annotations.AnnotationYamlProtocol._
|
||||||
|
import net.jcazevedo.moultingyaml._
|
||||||
|
|
||||||
|
object GenerateTopAndHarness extends App {
|
||||||
|
var input: Option[String] = None
|
||||||
|
var topOutput: Option[String] = None
|
||||||
|
var harnessOutput: Option[String] = None
|
||||||
|
var annoFile: Option[String] = None
|
||||||
|
var synTop: Option[String] = None
|
||||||
|
var harnessTop: Option[String] = None
|
||||||
|
var seqMemFlags: Option[String] = Some("-o:unused.confg")
|
||||||
|
var listClocks: Option[String] = Some("-o:unused.clocks")
|
||||||
|
|
||||||
|
var usedOptions = Set.empty[Integer]
|
||||||
|
args.zipWithIndex.foreach{ case (arg, i) =>
|
||||||
|
arg match {
|
||||||
|
case "-i" => {
|
||||||
|
input = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--top-o" => {
|
||||||
|
topOutput = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--harness-o" => {
|
||||||
|
harnessOutput = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--anno-file" => {
|
||||||
|
annoFile = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--syn-top" => {
|
||||||
|
synTop = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--harness-top" => {
|
||||||
|
harnessTop = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--seq-mem-flags" => {
|
||||||
|
seqMemFlags = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case "--list-clocks" => {
|
||||||
|
listClocks = Some(args(i+1))
|
||||||
|
usedOptions = usedOptions | Set(i+1)
|
||||||
|
}
|
||||||
|
case _ => {
|
||||||
|
if (! (usedOptions contains i)) {
|
||||||
|
error("Unknown option " + arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Load annotations from file
|
||||||
|
val annotationArray = annoFile match {
|
||||||
|
case None => Array[Annotation]()
|
||||||
|
case Some(fileName) => {
|
||||||
|
val annotations = new File(fileName)
|
||||||
|
if(annotations.exists) {
|
||||||
|
val annotationsYaml = io.Source.fromFile(annotations).getLines().mkString("\n").parseYaml
|
||||||
|
annotationsYaml.convertTo[Array[Annotation]]
|
||||||
|
} else {
|
||||||
|
Array[Annotation]()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Top Generation
|
||||||
|
firrtl.Driver.compile(
|
||||||
|
input.get,
|
||||||
|
topOutput.get,
|
||||||
|
new VerilogCompiler(),
|
||||||
|
Parser.UseInfo,
|
||||||
|
Seq(
|
||||||
|
new ReParentCircuit(synTop.get),
|
||||||
|
new RemoveUnusedModules,
|
||||||
|
new EnumerateModules( { m => if (m.name != synTop.get) { AllModules.add(m.name) } } ),
|
||||||
|
new passes.memlib.InferReadWrite(),
|
||||||
|
new passes.memlib.ReplSeqMem(),
|
||||||
|
new passes.clocklist.ClockListTransform()
|
||||||
|
),
|
||||||
|
AnnotationMap(Seq(
|
||||||
|
passes.memlib.InferReadWriteAnnotation(
|
||||||
|
s"${synTop.get}"
|
||||||
|
),
|
||||||
|
passes.clocklist.ClockListAnnotation(
|
||||||
|
s"-c:${synTop.get}:-m:${synTop.get}:${listClocks.get}"
|
||||||
|
),
|
||||||
|
passes.memlib.ReplSeqMemAnnotation(
|
||||||
|
s"-c:${synTop.get}:${seqMemFlags.get}"
|
||||||
|
)
|
||||||
|
) ++ annotationArray)
|
||||||
|
)
|
||||||
|
|
||||||
|
//Harness Generation
|
||||||
|
firrtl.Driver.compile(
|
||||||
|
input.get,
|
||||||
|
harnessOutput.get,
|
||||||
|
new VerilogCompiler(),
|
||||||
|
Parser.UseInfo,
|
||||||
|
Seq(
|
||||||
|
new ConvertToExtMod((m) => m.name == synTop.get),
|
||||||
|
new RemoveUnusedModules,
|
||||||
|
new RenameModulesAndInstances((m) => AllModules.rename(m))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
26
tapeout/src/main/scala/transforms/ReParentCircuit.scala
Normal file
26
tapeout/src/main/scala/transforms/ReParentCircuit.scala
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package barstools.tapeout.transforms
|
||||||
|
|
||||||
|
import firrtl._
|
||||||
|
import firrtl.ir._
|
||||||
|
import firrtl.passes.Pass
|
||||||
|
|
||||||
|
// "Re-Parents" a circuit, which changes the top module to something else.
|
||||||
|
class ReParentCircuitPass(newTopName: String) extends Pass {
|
||||||
|
def name = "Re-Parent Circuit"
|
||||||
|
|
||||||
|
def run(c: Circuit): Circuit = {
|
||||||
|
Circuit(c.info, c.modules, newTopName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReParentCircuit(newTopName: String) extends Transform with PassBased {
|
||||||
|
def inputForm = HighForm
|
||||||
|
def outputForm = HighForm
|
||||||
|
def passSeq = Seq(new ReParentCircuitPass(newTopName))
|
||||||
|
|
||||||
|
def execute(state: CircuitState): CircuitState = {
|
||||||
|
CircuitState(runPasses(state.circuit), state.form)
|
||||||
|
}
|
||||||
|
}
|
||||||
59
tapeout/src/main/scala/transforms/RemoveUnusedModules.scala
Normal file
59
tapeout/src/main/scala/transforms/RemoveUnusedModules.scala
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package barstools.tapeout.transforms
|
||||||
|
|
||||||
|
import firrtl._
|
||||||
|
import firrtl.ir._
|
||||||
|
import firrtl.passes.Pass
|
||||||
|
|
||||||
|
// Removes all the unused modules in a circuit by recursing through every
|
||||||
|
// instance (starting at the main module)
|
||||||
|
class RemoveUnusedModulesPass extends Pass {
|
||||||
|
def name = "Remove Unused Modules"
|
||||||
|
|
||||||
|
def run(c: Circuit): Circuit = {
|
||||||
|
val modulesByName = c.modules.map{
|
||||||
|
case m: Module => (m.name, Some(m))
|
||||||
|
case m: ExtModule => (m.name, None)
|
||||||
|
}.toMap
|
||||||
|
|
||||||
|
def getUsedModules(om: Option[Module]): Set[String] = {
|
||||||
|
om match {
|
||||||
|
case Some(m) => {
|
||||||
|
def someStatements(statement: Statement): Seq[Statement] =
|
||||||
|
statement match {
|
||||||
|
case b: Block =>
|
||||||
|
b.stmts.map{ someStatements(_) }
|
||||||
|
.foldLeft(Seq[Statement]())(_ ++ _)
|
||||||
|
case i: DefInstance => Seq(i)
|
||||||
|
case w: WDefInstance => Seq(w)
|
||||||
|
case _ => Seq()
|
||||||
|
}
|
||||||
|
|
||||||
|
someStatements(m.body).map{
|
||||||
|
case s: DefInstance => Set(s.module) | getUsedModules(modulesByName(s.module))
|
||||||
|
case s: WDefInstance => Set(s.module) | getUsedModules(modulesByName(s.module))
|
||||||
|
case _ => Set[String]()
|
||||||
|
}.foldLeft(Set(m.name))(_ | _)
|
||||||
|
}
|
||||||
|
|
||||||
|
case None => Set.empty[String]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val usedModuleSet = getUsedModules(modulesByName(c.main))
|
||||||
|
|
||||||
|
val usedModuleSeq = c.modules.filter { usedModuleSet contains _.name }
|
||||||
|
|
||||||
|
Circuit(c.info, usedModuleSeq, c.main)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RemoveUnusedModules extends Transform with PassBased {
|
||||||
|
def inputForm = MidForm
|
||||||
|
def outputForm = MidForm
|
||||||
|
def passSeq = Seq(new RemoveUnusedModulesPass)
|
||||||
|
|
||||||
|
def execute(state: CircuitState): CircuitState = {
|
||||||
|
CircuitState(runPasses(state.circuit), state.form)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package barstools.tapeout.transforms
|
||||||
|
|
||||||
|
import firrtl._
|
||||||
|
import firrtl.ir._
|
||||||
|
import firrtl.passes.Pass
|
||||||
|
|
||||||
|
// This doesn't rename ExtModules under the assumption that they're some
|
||||||
|
// Verilog black box and therefor can't be renamed. Since the point is to
|
||||||
|
// allow FIRRTL to be linked together using "cat" and ExtModules don't get
|
||||||
|
// emitted, this should be safe.
|
||||||
|
class RenameModulesAndInstancesPass(rename: (String) => String) extends Pass {
|
||||||
|
def name = "Rename Modules and Instances"
|
||||||
|
|
||||||
|
def renameInstances(body: Statement): Statement = {
|
||||||
|
body match {
|
||||||
|
case m: DefInstance => new DefInstance(m.info, m.name, rename(m.module))
|
||||||
|
case m: WDefInstance => new WDefInstance(m.info, m.name, rename(m.module), m.tpe)
|
||||||
|
case b: Block => new Block( b.stmts map { s => renameInstances(s) } )
|
||||||
|
case s: Statement => s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def run(c: Circuit): Circuit = {
|
||||||
|
val modulesx = c.modules.map {
|
||||||
|
case m: ExtModule => m
|
||||||
|
case m: Module => new Module(m.info, rename(m.name), m.ports, renameInstances(m.body))
|
||||||
|
}
|
||||||
|
Circuit(c.info, modulesx, c.main)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RenameModulesAndInstances(rename: (String) => String) extends Transform with PassBased {
|
||||||
|
def inputForm = LowForm
|
||||||
|
def outputForm = LowForm
|
||||||
|
def passSeq = Seq(new RenameModulesAndInstancesPass(rename))
|
||||||
|
|
||||||
|
def execute(state: CircuitState): CircuitState = {
|
||||||
|
CircuitState(runPasses(state.circuit), state.form)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user