From d86dea58cf2493ace790ca9e112a8affaa80e7ac Mon Sep 17 00:00:00 2001 From: Angie Wang Date: Fri, 17 Feb 2017 11:58:05 -0800 Subject: [PATCH] Tapeout (#4) * remove outdated files * pulled resetinverter from dsptools + setup repo * fix some package names, misc. dsptools dependencies, typo in build.sbt, + circuitstate in resetinverter pass * add more comprehensive gitignore + license back in * create directory structure to match package structure * change package names to barstools.tapeout * settled on barstools.tapeout.transforms package * make directory + build structure more amenable for multiple sub projects --- .gitignore | 329 +++++++++++++++++- LICENSE | 2 +- build.sbt | 14 +- .../ExecutionOptionsManager.scala | 126 ------- .../ExecutionOptionsManagerSpec.scala | 53 --- ...{dependencies.scala => Dependencies.scala} | 13 +- project/build.properties | 2 +- scalastyle-config.xml | 110 ++++++ scalastyle-test-config.xml | 109 ++++++ .../main/scala/transforms/ResetInverter.scala | 65 ++++ .../scala/transforms/ResetInverterSpec.scala | 39 +++ 11 files changed, 670 insertions(+), 192 deletions(-) delete mode 100644 executionoptions/src/main/scala/bar/executionoptions/ExecutionOptionsManager.scala delete mode 100644 executionoptions/src/test/scala/bar/executionoptions/ExecutionOptionsManagerSpec.scala rename project/{dependencies.scala => Dependencies.scala} (54%) create mode 100644 scalastyle-config.xml create mode 100644 scalastyle-test-config.xml create mode 100644 tapeout/src/main/scala/transforms/ResetInverter.scala create mode 100644 tapeout/src/test/scala/transforms/ResetInverterSpec.scala diff --git a/.gitignore b/.gitignore index 1f855d9b..2179f6e0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,317 @@ +### local stuff +src/main/scala/dsptools/sandbox.sc +test_run_dir/ +*.fir +*.anno +### XilinxISE template +# intermediate build files +*.bgn +*.bit +*.bld +*.cmd_log +*.drc +*.ll +*.lso +*.msd +*.msk +*.ncd +*.ngc +*.ngd +*.ngr +*.pad +*.par +*.pcf +*.prj +*.ptwx +*.rbb +*.rbd +*.stx +*.syr +*.twr +*.twx +*.unroutes +*.ut +*.xpi +*.xst +*_bitgen.xwbt +*_envsettings.html +*_map.map +*_map.mrp +*_map.ngm +*_map.xrpt +*_ngdbuild.xrpt +*_pad.csv +*_pad.txt +*_par.xrpt +*_summary.html +*_summary.xml +*_usage.xml +*_xst.xrpt + +# project-wide generated files +*.gise +par_usage_statistics.html +usage_statistics_webtalk.html +webtalk.log +webtalk_pn.xml + +# generated folders +iseconfig/ +xlnx_auto_0_xdb/ +xst/ +_ngo/ +_xmsgs/ +### Eclipse template +*.pydevproject +.metadata +.gradle +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath + +# Eclipse Core +.project + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Java annotation processor (APT) +.factorypath + +# PDT-specific +.buildpath + +# sbteclipse plugin +.target + +# TeXlipse plugin +.texlipse +### C template +# Object files +*.o +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +### SBT template +# Simple Build Tool +# http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control + +target/ +lib_managed/ +src_managed/ +project/boot/ +.history +.cache +### Emacs template +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +### Vim template +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist +*~ +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +### C++ template +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +### OSX template +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata + +## Other +*.xccheckout +*.moved-aside +*.xcuserstate +### Scala template *.class *.log -*.swp # sbt specific .cache @@ -16,3 +327,19 @@ project/plugins/project/ # Scala-IDE specific .scala_dependencies .worksheet +### Java template +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +# ignore lib from rocket build +lib diff --git a/LICENSE b/LICENSE index 3ed5e827..ad326246 100644 --- a/LICENSE +++ b/LICENSE @@ -26,4 +26,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/build.sbt b/build.sbt index eb35f36c..7374d991 100644 --- a/build.sbt +++ b/build.sbt @@ -6,11 +6,19 @@ lazy val commonSettings = Seq( organization := "edu.berkeley.cs", version := "0.1-SNAPSHOT", scalaVersion := "2.11.8", + scalacOptions := Seq("-deprecation", "-feature"), libraryDependencies ++= commonDependencies ) -lazy val executionoptions = (project in file("executionoptions")) +val defaultVersions = Map( + "chisel3" -> "3.1-SNAPSHOT", + "chisel-iotesters" -> "1.2-SNAPSHOT" +) + +lazy val tapeout = (project in file("tapeout")) .settings(commonSettings) .settings( - libraryDependencies ++= executionoptionsDependencies - ) + libraryDependencies ++= Seq("chisel3","chisel-iotesters").map { + dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) + } + ) \ No newline at end of file diff --git a/executionoptions/src/main/scala/bar/executionoptions/ExecutionOptionsManager.scala b/executionoptions/src/main/scala/bar/executionoptions/ExecutionOptionsManager.scala deleted file mode 100644 index 05a1e75c..00000000 --- a/executionoptions/src/main/scala/bar/executionoptions/ExecutionOptionsManager.scala +++ /dev/null @@ -1,126 +0,0 @@ -// See LICENSE for license details. - -package bar.executionoptions - -import scopt.OptionParser - -/** - * Use this trait to define an options class that can add its private command line options to a externally - * declared parser - */ -trait ComposableOptions - -/** - * Most of the chisel toolchain components require a topName which defines a circuit or a device under test. - * Much of the work that is done takes place in a directory. - * It would be simplest to require topName to be defined but in practice it is preferred to defer this. - * For example, in chisel, by deferring this it is possible for the execute there to first elaborate the - * circuit and then set the topName from that if it has not already been set. - */ -case class CommonOptions(topName: String = "", targetDirName: String = "test_run_dir") extends ComposableOptions - -abstract class HasParser(applicationName: String) { - final val parser: OptionParser[Unit] = new OptionParser[Unit](applicationName) {} -} - -trait HasCommonOptions { - self: ExecutionOptionsManager => - var commonOptions = CommonOptions() - - parser.note("common options") - - parser.opt[String]("top-name") - .abbr("tn") - .valueName("") - .foreach { x => - commonOptions = commonOptions.copy(topName = x) - } - .text("This options defines the top level circuit, defaults to dut when possible") - - parser.opt[String]("target-dir") - .abbr("td").valueName("") - .foreach { x => - commonOptions = commonOptions.copy(targetDirName = x) - } - .text(s"This options defines a work directory for intermediate files, default is ${commonOptions.targetDirName}") - - parser.help("help").text("prints this usage text") -} - -/** - * - * @param applicationName The name shown in the usage - */ -class ExecutionOptionsManager(val applicationName: String) extends HasParser(applicationName) with HasCommonOptions { - - def parse(args: Array[String]): Boolean = { - parser.parse(args) - } - - def showUsageAsError(): Unit = parser.showUsageAsError() - - /** - * make sure that all levels of targetDirName exist - * - * @return true if directory exists - */ - def makeTargetDir(): Boolean = { - (new java.io.File(commonOptions.targetDirName)).mkdirs() - } - - def targetDirName: String = commonOptions.targetDirName - - /** - * this function sets the topName in the commonOptions. - * It would be nicer to not need this but many chisel tools cannot determine - * the name of the device under test until other options have been parsed. - * Havin this function allows the code to set the TopName after it has been - * determined - * - * @param newTopName the topName to be used - */ - def setTopName(newTopName: String): Unit = { - commonOptions = commonOptions.copy(topName = newTopName) - } - def setTopNameIfNotSet(newTopName: String): Unit = { - if(commonOptions.topName.isEmpty) { - setTopName(newTopName) - } - } - def topName: String = commonOptions.topName - def setTargetDirName(newTargetDirName: String): Unit = { - commonOptions = commonOptions.copy(targetDirName = newTargetDirName) - } - - /** - * return a file based on targetDir, topName and suffix - * Will not add the suffix if the topName already ends with that suffix - * - * @param suffix suffix to add, removes . if present - * @param fileNameOverride this will override the topName if nonEmpty, when using this targetDir is ignored - * @return - */ - def getBuildFileName(suffix: String, fileNameOverride: String = ""): String = { - makeTargetDir() - - val baseName = if(fileNameOverride.nonEmpty) fileNameOverride else topName - val directoryName = { - if(fileNameOverride.nonEmpty) { - "" - } - else if(baseName.startsWith("./") || baseName.startsWith("/")) { - "" - } - else { - if(targetDirName.endsWith("/")) targetDirName else targetDirName + "/" - } - } - val normalizedSuffix = { - val dottedSuffix = if(suffix.startsWith(".")) suffix else s".$suffix" - if(baseName.endsWith(dottedSuffix)) "" else dottedSuffix - } - - s"$directoryName$baseName$normalizedSuffix" - } -} - diff --git a/executionoptions/src/test/scala/bar/executionoptions/ExecutionOptionsManagerSpec.scala b/executionoptions/src/test/scala/bar/executionoptions/ExecutionOptionsManagerSpec.scala deleted file mode 100644 index 8f15f940..00000000 --- a/executionoptions/src/test/scala/bar/executionoptions/ExecutionOptionsManagerSpec.scala +++ /dev/null @@ -1,53 +0,0 @@ -// See LICENSE for license details. - -package bar.executionoptions - -import org.scalatest.{Matchers, FreeSpec} - -class ExecutionOptionsManagerSpec extends FreeSpec with Matchers { - "ExecutionOptionsManager is a container for one more more ComposableOptions Block" - { - "It has a default CommonOptionsBlock" in { - val manager = new ExecutionOptionsManager("test") - manager.commonOptions.targetDirName should be ("test_run_dir") - } - "But can override defaults like this" in { - val manager = new ExecutionOptionsManager("test") { commonOptions = CommonOptions(topName = "dog") } - manager.commonOptions shouldBe a [CommonOptions] - manager.topName should be ("dog") - manager.commonOptions.topName should be ("dog") - } - "The proper way to change an option in is to copy the existing sub-option with the desired new value" in { - val manager = new ExecutionOptionsManager("test") { - commonOptions = CommonOptions(targetDirName = "fox", topName = "dog") - } - val initialCommon = manager.commonOptions - initialCommon.targetDirName should be ("fox") - initialCommon.topName should be ("dog") - - manager.commonOptions = manager.commonOptions.copy(topName = "cat") - - val afterCommon = manager.commonOptions - afterCommon.topName should be ("cat") - afterCommon.targetDirName should be ("fox") - initialCommon.topName should be ("dog") - } - "The following way of changing a manager should not be used, as it could alter other desired values" - { - "Note that the initial setting targetDirName is lost when using this method" in { - val manager = new ExecutionOptionsManager("test") { - commonOptions = CommonOptions(targetDirName = "fox", topName = "dog") - } - val initialCommon = manager.commonOptions - initialCommon.topName should be("dog") - - manager.commonOptions = CommonOptions(topName = "cat") - - val afterCommon = manager.commonOptions - initialCommon.topName should be("dog") - afterCommon.topName should be("cat") - - // This is probably bad - afterCommon.targetDirName should not be "fox" - } - } - } -} diff --git a/project/dependencies.scala b/project/Dependencies.scala similarity index 54% rename from project/dependencies.scala rename to project/Dependencies.scala index e9367cfc..6395b980 100644 --- a/project/dependencies.scala +++ b/project/Dependencies.scala @@ -4,13 +4,12 @@ import Keys._ object Dependencies { val scalatestVersion = "3.0.0" val scalatest = "org.scalatest" %% "scalatest" % scalatestVersion % "test" - val scoptVersion = "3.4.0" - val scopt = "com.github.scopt" %% "scopt" % scoptVersion + val scalacheckVersion = "1.12.4" + val scalacheck = "org.scalacheck" %% "scalacheck" % scalacheckVersion % "test" val commonDependencies: Seq[ModuleID] = Seq( - scalatest + scalatest, + scalacheck ) - val executionoptionsDependencies: Seq[ModuleID] = Seq( - scopt - ) -} + +} \ No newline at end of file diff --git a/project/build.properties b/project/build.properties index 35c88bab..7d789d45 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.12 +sbt.version=0.13.12 \ No newline at end of file diff --git a/scalastyle-config.xml b/scalastyle-config.xml new file mode 100644 index 00000000..57ef60a2 --- /dev/null +++ b/scalastyle-config.xml @@ -0,0 +1,110 @@ + + Scalastyle standard configuration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No lines ending with a ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + |\|\||&&|:=|<>|<=|>=|!=|===|<<|>>|##|unary_(~|\-%?|!))$]]> + + + + + + + + + + + diff --git a/scalastyle-test-config.xml b/scalastyle-test-config.xml new file mode 100644 index 00000000..bf32aacd --- /dev/null +++ b/scalastyle-test-config.xml @@ -0,0 +1,109 @@ + + Scalastyle configuration for Chisel3 unit tests + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No lines ending with a ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + |\|\||&&|:=|<>|<=|>=|!=|===|<<|>>|##|unary_(~|\-%?|!))$]]> + + + + + + + + + + + diff --git a/tapeout/src/main/scala/transforms/ResetInverter.scala b/tapeout/src/main/scala/transforms/ResetInverter.scala new file mode 100644 index 00000000..f0bd3449 --- /dev/null +++ b/tapeout/src/main/scala/transforms/ResetInverter.scala @@ -0,0 +1,65 @@ +// See LICENSE for license details. + +package barstools.tapeout.transforms + +import chisel3.internal.InstanceId +import firrtl.PrimOps.Not +import firrtl.annotations.{Annotation, CircuitName, ModuleName, Named} +import firrtl.ir.{Input, UIntType, IntWidth, Module, Port, DefNode, NoInfo, Reference, DoPrim, Block, Circuit} +import firrtl.passes.Pass +import firrtl.{CircuitForm, CircuitState, LowForm, Transform} + +object ResetInverterAnnotation { + def apply(target: ModuleName): Annotation = Annotation(target, classOf[ResetInverterTransform], "invert") + def unapply(a: Annotation): Option[Named] = a match { + case Annotation(m, t, "invert") if t == classOf[ResetInverterTransform] => Some(m) + case _ => None + } +} + +object ResetN extends Pass { + def name: String = "ResetN" + private val Bool = UIntType(IntWidth(1)) + // Only works on Modules with a Bool port named reset + def invertReset(mod: Module): Module = { + // Check that it actually has reset + require(mod.ports.exists(p => p.name == "reset" && p.tpe == Bool), + "Can only invert reset on a module with reset!") + // Rename "reset" to "reset_n" + val portsx = mod.ports map { + case Port(info, "reset", Input, Bool) => Port(info, "reset_n", Input, Bool) + case other => other + } + val newReset = DefNode(NoInfo, "reset", DoPrim(Not, Seq(Reference("reset_n", Bool)), Seq.empty, Bool)) + val bodyx = Block(Seq(newReset, mod.body)) + mod.copy(ports = portsx, body = bodyx) + } + + def run(c: Circuit): Circuit = + c.copy(modules = c.modules map { + case mod: Module if mod.name == c.main => invertReset(mod) + case other => other + }) +} + +class ResetInverterTransform extends Transform { + override def inputForm: CircuitForm = LowForm + override def outputForm: CircuitForm = LowForm + + override def execute(state: CircuitState): CircuitState = { + getMyAnnotations(state) match { + case Nil => CircuitState(state.circuit, LowForm) + case Seq(ResetInverterAnnotation(ModuleName(state.circuit.main, CircuitName(_)))) => + CircuitState(ResetN.run(state.circuit), LowForm) + case annotations => + throw new Exception(s"There should be only one InvertReset annotation: got ${annotations.mkString(" -- ")}") + } + } +} + +trait ResetInverter { + self: chisel3.Module => + def invert(component: InstanceId): Unit = { + annotate(chisel3.experimental.ChiselAnnotation(component, classOf[ResetInverterTransform], "invert")) + } +} diff --git a/tapeout/src/test/scala/transforms/ResetInverterSpec.scala b/tapeout/src/test/scala/transforms/ResetInverterSpec.scala new file mode 100644 index 00000000..fd49435e --- /dev/null +++ b/tapeout/src/test/scala/transforms/ResetInverterSpec.scala @@ -0,0 +1,39 @@ +// See LICENSE for license details. + +package barstools.tapeout.transforms + +import chisel3._ +import chisel3.util.RegInit +import firrtl._ +import org.scalatest.{FreeSpec, Matchers} + +class ExampleModuleNeedsResetInverted extends Module with ResetInverter { + val io = IO(new Bundle { + val out = Output(UInt(32.W)) + }) + + val r = RegInit(0.U) + + invert(this) +} + +class ResetNSpec extends FreeSpec with Matchers { + + "Inverting reset needs to be done throughout module" in { + val optionsManager = new ExecutionOptionsManager("dsptools") with HasChiselExecutionOptions with HasFirrtlOptions { + firrtlOptions = firrtlOptions.copy(compilerName = "low") + } + chisel3.Driver.execute(optionsManager, () => new ExampleModuleNeedsResetInverted) match { + case ChiselExecutionSuccess(_, chirrtl, Some(FirrtlExecutionSuccess(_, firrtl))) => + chirrtl should include ("input reset :") + chirrtl should not include "input reset_n :" + chirrtl should not include "node reset = not(reset_n)" + + firrtl should include ("input reset_n :") + firrtl should include ("node reset = not(reset_n)") + firrtl should not include "input reset :" + case _ => + // bad + } + } +} \ No newline at end of file