Refactor barstools for new versions of things.

- No handlebars (not being published for Scala 2.12)
- Update for new annotations APIs

Bump sbt-dependency-graph to 0.9.2 for this scala version
This commit is contained in:
Paul Rigge
2018-12-19 22:54:46 +00:00
committed by John Wright
parent 4727d475c7
commit f310d45381
9 changed files with 122 additions and 130 deletions

View File

@@ -1,21 +1,22 @@
// See LICENSE for license details. // See LICENSE for license details.
import Dependencies._
val defaultVersions = Map( val defaultVersions = Map(
"chisel3" -> "3.1-SNAPSHOT", "chisel3" -> "3.2-SNAPSHOT",
"chisel-iotesters" -> "1.2-SNAPSHOT" "chisel-iotesters" -> "1.3-SNAPSHOT"
) )
lazy val commonSettings = Seq( lazy val commonSettings = Seq(
organization := "edu.berkeley.cs", organization := "edu.berkeley.cs",
version := "0.1-SNAPSHOT", version := "0.1-SNAPSHOT",
scalaVersion := "2.11.8", scalaVersion := "2.12.8",
scalacOptions := Seq("-deprecation", "-feature", "-language:reflectiveCalls"), scalacOptions := Seq("-deprecation", "-feature", "-language:reflectiveCalls", "-Xsource:2.11"),
libraryDependencies ++= commonDependencies,
libraryDependencies ++= Seq("chisel3","chisel-iotesters").map { libraryDependencies ++= Seq("chisel3","chisel-iotesters").map {
dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep))
}, },
libraryDependencies in Test ++= Seq(
"org.scalatest" %% "scalatest" % "2.2.5" % "test",
"org.scalacheck" %% "scalacheck" % "1.12.4" % "test"
),
resolvers ++= Seq( resolvers ++= Seq(
Resolver.sonatypeRepo("snapshots"), Resolver.sonatypeRepo("snapshots"),
Resolver.sonatypeRepo("releases") Resolver.sonatypeRepo("releases")
@@ -30,7 +31,7 @@ lazy val macros = (project in file("macros"))
.settings(commonSettings) .settings(commonSettings)
.settings(Seq( .settings(Seq(
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"edu.berkeley.cs" %% "firrtl-interpreter" % "0.1-SNAPSHOT" % Test "edu.berkeley.cs" %% "firrtl-interpreter" % "1.2-SNAPSHOT" % Test
), ),
mainClass := Some("barstools.macros.MacroCompiler") mainClass := Some("barstools.macros.MacroCompiler")
)) ))

View File

@@ -752,7 +752,7 @@ object MacroCompiler extends App {
// Note: the last macro in the input list is (seemingly arbitrarily) // Note: the last macro in the input list is (seemingly arbitrarily)
// determined as the firrtl "top-level module". // determined as the firrtl "top-level module".
val circuit = Circuit(NoInfo, macros, macros.last.name) val circuit = Circuit(NoInfo, macros, macros.last.name)
val annotations = AnnotationMap( val annotations = AnnotationSeq(
Seq(MacroCompilerAnnotation( Seq(MacroCompilerAnnotation(
circuit.main, circuit.main,
MacroCompilerAnnotation.Params( MacroCompilerAnnotation.Params(
@@ -764,7 +764,7 @@ object MacroCompiler extends App {
) )
)) ))
) )
val state = CircuitState(circuit, HighForm, Some(annotations)) val state = CircuitState(circuit, HighForm, annotations)
// Run the compiler. // Run the compiler.
val result = new MacroCompiler().compileAndEmit(state) val result = new MacroCompiler().compileAndEmit(state)

View File

@@ -1,22 +0,0 @@
import sbt._
import Keys._
object Dependencies {
val scalatestVersion = "2.2.5"
val scalatest = "org.scalatest" %% "scalatest" % scalatestVersion % "test"
val scalacheckVersion = "1.12.4"
val scalacheck = "org.scalacheck" %% "scalacheck" % scalacheckVersion % "test"
// Templating!
val handlebarsVersion = "2.1.1"
val handlebars = "com.gilt" %% "handlebars-scala" % handlebarsVersion exclude("org.slf4j", "slf4j-simple")
// org.slf4j.slf4j-simple's StaticLoggerBinder (from handlebars) conflicts with
// ch.qos.logback.logback-classic's StaticLoggerBinder (from firrtl).
val commonDependencies: Seq[ModuleID] = Seq(
scalatest,
scalacheck,
handlebars
)
}

View File

@@ -1,2 +1,2 @@
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.5") addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.5")
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.2") addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.9.2")

View File

@@ -1 +1 @@
sbt.version=0.13.12 sbt.version=1.2.7

View File

@@ -23,70 +23,78 @@ object AllModules {
} }
} }
case class ParsedInput(args: Seq[String]) extends LazyLogging { trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions =>
var input: Option[String] = None var tapeoutOptions = TapeoutOptions()
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] parser.note("tapeout options")
args.zipWithIndex.foreach{ case (arg, i) =>
arg match { parser.opt[String]("harness-o")
case "-i" => { .abbr("tho")
input = Some(args(i+1)) .valueName("<harness-output>")
usedOptions = usedOptions | Set(i+1) .foreach { x =>
} tapeoutOptions = tapeoutOptions.copy(
case "-o" => { harnessOutput = Some(x)
output = Some(args(i+1)) )
usedOptions = usedOptions | Set(i+1) }.text {
} "use this to generate a harness at <harness-output>"
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)
}
}
} }
}
parser.opt[String]("syn-top")
.abbr("tst")
.valueName("<syn-top")
.foreach { x =>
tapeoutOptions = tapeoutOptions.copy(
synTop = Some(x)
)
}.text {
"use this to set synTop"
}
parser.opt[String]("harness-top")
.abbr("tht")
.valueName("<harness-top>")
.foreach { x =>
tapeoutOptions = tapeoutOptions.copy(
harnessTop = Some(x)
)
}.text {
"use this to set harnessTop"
}
parser.opt[String]("list-clocks")
.abbr("tlc")
.valueName("<clocks>")
.foreach { x =>
tapeoutOptions = tapeoutOptions.copy(
listClocks = Some(x)
)
}.text {
"use this to list <clocks>"
}
parser.note("")
} }
case class TapeoutOptions(
input: Option[String] = None,
output: Option[String] = None,
topOutput: Option[String] = None,
harnessOutput: Option[String] = None,
annoFile: Option[String] = None,
synTop: Option[String] = None,
harnessTop: Option[String] = None,
seqMemFlags: Option[String] = Some("-o:unused.confg"),
listClocks: Option[String] = Some("-o:unused.clocks")
) extends LazyLogging
// Requires two phases, one to collect modules below synTop in the hierarchy // Requires two phases, one to collect modules below synTop in the hierarchy
// and a second to remove those modules to generate the test harness // and a second to remove those modules to generate the test harness
sealed trait GenerateTopAndHarnessApp extends App with LazyLogging { sealed trait GenerateTopAndHarnessApp extends App with LazyLogging {
lazy val options: ParsedInput = ParsedInput(args) val optionsManager = new ExecutionOptionsManager("tapeout") with HasFirrtlOptions with HasTapeoutOptions
if (!optionsManager.parse(args)) {
throw new Exception("Error parsing options!")
}
lazy val options = optionsManager.tapeoutOptions
lazy val input = options.input lazy val input = options.input
lazy val output = options.output lazy val output = options.output
lazy val topOutput = options.topOutput lazy val topOutput = options.topOutput
@@ -116,34 +124,32 @@ sealed trait GenerateTopAndHarnessApp extends App with LazyLogging {
pre ++ enumerate ++ post pre ++ enumerate ++ post
} }
private def getFirstPhaseAnnotations(top: Boolean): AnnotationMap = { private def getFirstPhaseAnnotations(top: Boolean): AnnotationSeq = {
if (top) { if (top) {
//Load annotations from file //Load annotations from file
val annotationArray = annoFile match { val annotationArray: Seq[Annotation] = annoFile match {
case None => Array[Annotation]() case None => Array[Annotation]()
case Some(fileName) => { case Some(fileName) => {
val annotations = new File(fileName) val annotations = new File(fileName)
if(annotations.exists) { if(annotations.exists) {
val annotationsYaml = io.Source.fromFile(annotations).getLines().mkString("\n").parseYaml val annotationsYaml = io.Source.fromFile(annotations).getLines().mkString("\n")
annotationsYaml.convertTo[Array[Annotation]] Seq(AnnotationUtils.fromYaml(annotationsYaml)) // TODO
} else { } else {
Array[Annotation]() Seq[Annotation]()
} }
} }
} }
// add new annotations // add new annotations
AnnotationMap(Seq( AnnotationSeq(Seq(
passes.memlib.InferReadWriteAnnotation( passes.memlib.InferReadWriteAnnotation,
s"${synTop.get}" passes.clocklist.ClockListAnnotation.parse(
),
passes.clocklist.ClockListAnnotation(
s"-c:${synTop.get}:-m:${synTop.get}:${listClocks.get}" s"-c:${synTop.get}:-m:${synTop.get}:${listClocks.get}"
), ),
passes.memlib.ReplSeqMemAnnotation( passes.memlib.ReplSeqMemAnnotation.parse(
s"-c:${synTop.get}:${seqMemFlags.get}" s"-c:${synTop.get}:${seqMemFlags.get}"
) )
) ++ annotationArray) ) ++ annotationArray)
} else { AnnotationMap(Seq.empty) } } else { AnnotationSeq(Seq.empty) }
} }
private def getSecondPhasePasses: Seq[Transform] = { private def getSecondPhasePasses: Seq[Transform] = {
@@ -156,31 +162,36 @@ sealed trait GenerateTopAndHarnessApp extends App with LazyLogging {
} }
// always the same for now // always the same for now
private def getSecondPhaseAnnotations: AnnotationMap = AnnotationMap(Seq.empty) private def getSecondPhaseAnnotations: AnnotationSeq = AnnotationSeq(Seq.empty)
// Top Generation // Top Generation
protected def firstPhase(top: Boolean, harness: Boolean): Unit = { protected def firstPhase(top: Boolean, harness: Boolean): Unit = {
require(top || harness, "Must specify either top or harness") require(top || harness, "Must specify either top or harness")
firrtl.Driver.compile(
input.get, val firrtlOptions = optionsManager.firrtlOptions
topOutput.getOrElse(output.get), optionsManager.firrtlOptions = firrtlOptions.copy(
new VerilogCompiler(), annotations = firrtlOptions.annotations ++ getFirstPhaseAnnotations(top)
Parser.UseInfo, )
getFirstPhasePasses(top, harness),
getFirstPhaseAnnotations(top) optionsManager.firrtlOptions = firrtlOptions.copy(
customTransforms = firrtlOptions.customTransforms ++ getFirstPhasePasses(top, harness)
) )
} }
// Harness Generation // Harness Generation
protected def secondPhase: Unit = { protected def secondPhase: Unit = {
firrtl.Driver.compile( val firrtlOptions = optionsManager.firrtlOptions
input.get, optionsManager.firrtlOptions = firrtlOptions.copy(
harnessOutput.getOrElse(output.get), annotations = firrtlOptions.annotations ++ getSecondPhaseAnnotations
new VerilogCompiler(),
Parser.UseInfo,
getSecondPhasePasses,
getSecondPhaseAnnotations
) )
optionsManager.firrtlOptions = firrtlOptions.copy(
customTransforms = firrtlOptions.customTransforms ++ getSecondPhasePasses
)
}
protected def execute: Unit = {
firrtl.Driver.execute(optionsManager)
} }
} }
@@ -191,6 +202,7 @@ object GenerateTop extends GenerateTopAndHarnessApp {
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.")}) 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 // Only need a single phase to generate the top module
firstPhase(top = true, harness = false) firstPhase(top = true, harness = false)
execute
} }
object GenerateHarness extends GenerateTopAndHarnessApp { object GenerateHarness extends GenerateTopAndHarnessApp {
@@ -206,6 +218,7 @@ object GenerateHarness extends GenerateTopAndHarnessApp {
// Do minimal work for the first phase to generate test harness // Do minimal work for the first phase to generate test harness
firstPhase(top = false, harness = true) firstPhase(top = false, harness = true)
secondPhase secondPhase
execute
} }
object GenerateTopAndHarness extends GenerateTopAndHarnessApp { object GenerateTopAndHarness extends GenerateTopAndHarnessApp {
@@ -214,4 +227,5 @@ object GenerateTopAndHarness extends GenerateTopAndHarnessApp {
// Do everything, top and harness generation // Do everything, top and harness generation
firstPhase(top = true, harness = true) firstPhase(top = true, harness = true)
secondPhase secondPhase
execute
} }

View File

@@ -15,13 +15,10 @@ object WriteConfig {
object GetTargetDir { object GetTargetDir {
def apply(state: CircuitState): String = { def apply(state: CircuitState): String = {
val annos = state.annotations.getOrElse(AnnotationMap(Seq.empty)).annotations val annos = state.annotations
val destDir = annos.map { val destDir = annos.map {
case Annotation(f, t, s) if t == classOf[transforms.BlackBoxSourceHelper] => case Annotation(f, t, s) if t == classOf[firrtl.transforms.BlackBoxTargetDirAnno] =>
transforms.BlackBoxSource.parse(s) match { Some(s)
case Some(transforms.BlackBoxTargetDir(dest)) => Some(dest)
case _ => None
}
case _ => None case _ => None
}.flatten }.flatten
val loc = { val loc = {
@@ -45,14 +42,14 @@ class TechnologyLocation extends Transform {
def outputForm: CircuitForm = LowForm def outputForm: CircuitForm = LowForm
def execute(state: CircuitState) = throw new Exception("Technology Location transform execution doesn't work!") def execute(state: CircuitState) = throw new Exception("Technology Location transform execution doesn't work!")
def get(state: CircuitState): String = { def get(state: CircuitState): String = {
val annos = state.annotations.getOrElse(AnnotationMap(Seq.empty)).annotations val annos = state.annotations
val dir = annos.map { val dir = annos.map {
case Annotation(f, t, s) if t == classOf[TechnologyLocation] => Some(s) case Annotation(f, t, s) if t == classOf[TechnologyLocation] => Some(s)
case _ => None case _ => None
}.flatten }.flatten
dir.length match { dir.length match {
case 0 => "" case 0 => ""
case 1 => case 1 =>
val targetDir = new java.io.File(dir.head) val targetDir = new java.io.File(dir.head)
if(!targetDir.exists()) throw new Exception("Technology yaml directory doesn't exist!") if(!targetDir.exists()) throw new Exception("Technology yaml directory doesn't exist!")
dir.head dir.head

View File

@@ -13,6 +13,8 @@ class ExampleModuleNeedsResetInverted extends Module with ResetInverter {
val r = RegInit(0.U) val r = RegInit(0.U)
io.out := r
invert(this) invert(this)
} }
@@ -35,4 +37,4 @@ class ResetNSpec extends FreeSpec with Matchers {
// bad // bad
} }
} }
} }

View File

@@ -25,10 +25,10 @@ class RetimeSpec extends FlatSpec with Matchers {
it should "pass simple retime module annotation" in { it should "pass simple retime module annotation" in {
val gen = () => new RetimeModule() val gen = () => new RetimeModule()
val dir = uniqueDirName(gen, "RetimeModule") val dir = uniqueDirName(gen, "RetimeModule")
chisel3.Driver.execute(Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final.anno"), gen) shouldBe a [ChiselExecutionSuccess] chisel3.Driver.execute(Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final"), gen) shouldBe a [ChiselExecutionSuccess]
val lines = io.Source.fromFile(s"test_run_dir/$dir/final.anno").getLines().map(normalized).toSeq val lines = io.Source.fromFile(s"test_run_dir/$dir/final.anno.json").getLines().map(normalized).mkString("\n")
lines should contain ("Annotation(ModuleName(RetimeModule,CircuitName(RetimeModule)),class barstools.tapeout.transforms.retime.RetimeTransform,retime)") lines should include("barstools.tapeout.transforms.retime.RetimeTransform")
} }
// TODO(azidar): need to fix/add instance annotations // TODO(azidar): need to fix/add instance annotations