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:
Stevo
2017-03-22 14:37:26 -07:00
committed by Colin Schmidt
parent 2d7806ca79
commit f4a8715fa4
4 changed files with 217 additions and 276 deletions

View 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
}

View File

@@ -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))
)
)
}

View File

@@ -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}"
)
))
)
}

View File

@@ -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))
)
)
}