Combine generates, make it a trait (#11)
* [stevo]: combine generates, make it a trait * [stevo]: add Generator ala rocket-chip, some other cleanup * [stevo]: remove Generator, since that generates firrtl... * [stevo]: still debugging * [stevo]: okay i think it works now * [stevo]: oops * Refactor new generate code. Mostly just style stuff.
This commit is contained in:
217
tapeout/src/main/scala/transforms/Generate.scala
Normal file
217
tapeout/src/main/scala/transforms/Generate.scala
Normal file
@@ -0,0 +1,217 @@
|
||||
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._
|
||||
import com.typesafe.scalalogging.LazyLogging
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
case class ParsedInput(args: Seq[String]) extends LazyLogging {
|
||||
var input: Option[String] = None
|
||||
var output: 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 "-o" => {
|
||||
output = 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)) {
|
||||
logger.error("Unknown option " + arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Requires two phases, one to collect modules below synTop in the hierarchy
|
||||
// and a second to remove those modules to generate the test harness
|
||||
sealed trait GenerateTopAndHarnessApp extends App with LazyLogging {
|
||||
lazy val options: ParsedInput = ParsedInput(args)
|
||||
lazy val input = options.input
|
||||
lazy val output = options.output
|
||||
lazy val topOutput = options.topOutput
|
||||
lazy val harnessOutput = options.harnessOutput
|
||||
lazy val annoFile = options.annoFile
|
||||
lazy val synTop = options.synTop
|
||||
lazy val harnessTop = options.harnessTop
|
||||
lazy val seqMemFlags = options.seqMemFlags
|
||||
lazy val listClocks = options.listClocks
|
||||
|
||||
private def getFirstPhasePasses(top: Boolean, harness: Boolean): Seq[Transform] = {
|
||||
val pre = Seq(
|
||||
new ReParentCircuit(synTop.get),
|
||||
new RemoveUnusedModules
|
||||
)
|
||||
|
||||
val enumerate = if (harness) { Seq(
|
||||
new EnumerateModules( { m => if (m.name != options.synTop.get) { AllModules.add(m.name) } } )
|
||||
) } else Seq()
|
||||
|
||||
val post = if (top) { Seq(
|
||||
new passes.memlib.InferReadWrite(),
|
||||
new passes.memlib.ReplSeqMem(),
|
||||
new passes.clocklist.ClockListTransform()
|
||||
) } else Seq()
|
||||
|
||||
pre ++ enumerate ++ post
|
||||
}
|
||||
|
||||
private def getFirstPhaseAnnotations(top: Boolean): AnnotationMap = {
|
||||
if (top) {
|
||||
//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]()
|
||||
}
|
||||
}
|
||||
}
|
||||
// add new annotations
|
||||
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)
|
||||
} else { AnnotationMap(Seq.empty) }
|
||||
}
|
||||
|
||||
private def getSecondPhasePasses: Seq[Transform] = {
|
||||
// always the same for now
|
||||
Seq(
|
||||
new ConvertToExtMod((m) => m.name == synTop.get),
|
||||
new RemoveUnusedModules,
|
||||
new RenameModulesAndInstances((m) => AllModules.rename(m))
|
||||
)
|
||||
}
|
||||
|
||||
// always the same for now
|
||||
private def getSecondPhaseAnnotations: AnnotationMap = AnnotationMap(Seq.empty)
|
||||
|
||||
// Top Generation
|
||||
protected def firstPhase(top: Boolean, harness: Boolean): Unit = {
|
||||
require(top || harness, "Must specify either top or harness")
|
||||
firrtl.Driver.compile(
|
||||
input.get,
|
||||
topOutput.getOrElse(output.get),
|
||||
new VerilogCompiler(),
|
||||
Parser.UseInfo,
|
||||
getFirstPhasePasses(top, harness),
|
||||
getFirstPhaseAnnotations(top)
|
||||
)
|
||||
}
|
||||
|
||||
// Harness Generation
|
||||
protected def secondPhase: Unit = {
|
||||
firrtl.Driver.compile(
|
||||
input.get,
|
||||
harnessOutput.getOrElse(output.get),
|
||||
new VerilogCompiler(),
|
||||
Parser.UseInfo,
|
||||
getSecondPhasePasses,
|
||||
getSecondPhaseAnnotations
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object GenerateTop extends GenerateTopAndHarnessApp {
|
||||
// warn about unused options
|
||||
harnessOutput.foreach(n => logger.warn(s"Not using harness output filename $n since you asked for just a top-level output."))
|
||||
topOutput.foreach(_.foreach{
|
||||
n => logger.warn(s"Not using generic output filename $n since you asked for just a top-level output and also specified a generic output.")})
|
||||
// Only need a single phase to generate the top module
|
||||
firstPhase(top = true, harness = false)
|
||||
}
|
||||
|
||||
object GenerateHarness extends GenerateTopAndHarnessApp {
|
||||
// warn about unused options
|
||||
topOutput.foreach(n => logger.warn(s"Not using top-level output filename $n since you asked for just a test harness."))
|
||||
annoFile.foreach(n => logger.warn(s"Not using annotations file $n since you asked for just a test harness."))
|
||||
seqMemFlags.filter(_ != "-o:unused.confg").foreach {
|
||||
n => logger.warn(s"Not using SeqMem flags $n since you asked for just a test harness.") }
|
||||
listClocks.filter(_ != "-o:unused.clocks").foreach {
|
||||
n => logger.warn(s"Not using clocks list $n since you asked for just a test harness.") }
|
||||
harnessOutput.foreach(_.foreach{
|
||||
n => logger.warn(s"Not using generic output filename $n since you asked for just a test harness and also specified a generic output.")})
|
||||
// Do minimal work for the first phase to generate test harness
|
||||
firstPhase(top = false, harness = true)
|
||||
secondPhase
|
||||
}
|
||||
|
||||
object GenerateTopAndHarness extends GenerateTopAndHarnessApp {
|
||||
// warn about unused options
|
||||
output.foreach(n => logger.warn(s"Not using generic output filename $n since you asked for both a top-level output and a test harness."))
|
||||
// Do everything, top and harness generation
|
||||
firstPhase(top = true, harness = true)
|
||||
secondPhase
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
// 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))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
// 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}"
|
||||
)
|
||||
))
|
||||
)
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
// 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))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user