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