Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stage/Phase Refactor #2234

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions src/main/scala/stage/RocketChipAnnotations.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// See LICENSE.SiFive for license details.

package freechips.rocketchip.stage

import chisel3.experimental.BaseModule

import firrtl.annotations.{Annotation, NoTargetAnnotation}
import firrtl.options.{HasShellOptions, ShellOption, Unserializable}

import freechips.rocketchip.config.Config

sealed trait RocketChipOption extends Unserializable { this: Annotation => }

case class TopModuleAnnotation(clazz: Class[_ <: Any]) extends NoTargetAnnotation with RocketChipOption

private[stage] object TopModuleAnnotation extends HasShellOptions {

override val options = Seq(
new ShellOption[String](
longOption = "top-module",
toAnnotationSeq = a => Seq(TopModuleAnnotation(Class.forName(a).asInstanceOf[Class[_ <: BaseModule]])),
helpText = "The top module to build, e.g., freechips.rocketchip.system.TestHarness",
helpValueName = Some("<module>")
)
)

}

case class ConfigAnnotation(clazz: Class[_ <: Config]) extends NoTargetAnnotation with RocketChipOption

private[stage] object ConfigAnnotation extends HasShellOptions {

override val options = Seq(
new ShellOption[String](
longOption = "config",
toAnnotationSeq = a => Seq(ConfigAnnotation(Class.forName(a).asInstanceOf[Class[_ <: Config]])),
helpText = "The configuration to use, e.g., freechips.rocketchip.system.DefaultConfig",
helpValueName = Some("<config>")
)
)

}
14 changes: 14 additions & 0 deletions src/main/scala/stage/RocketChipCli.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// See LICENSE.SiFive for license details.

package freechips.rocketchip.stage

import firrtl.options.Shell

trait RocketChipCli { this: Shell =>

parser.note("Rocket Chip Compiler Options")
Seq( TopModuleAnnotation,
ConfigAnnotation )
.foreach(_.addOptions(parser))

}
26 changes: 26 additions & 0 deletions src/main/scala/stage/RocketChipOptions.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// See LICENSE.SiFive for license details.

package freechips.rocketchip.stage

import chisel3.experimental.BaseModule

import freechips.rocketchip.config.Config

class RocketChipOptions private[stage] (
val config: Option[Class[_ <: Config]] = None,
val topModule: Option[Class[_ <: Any]] = None ) {

private[stage] def copy(
config: Option[Class[_ <: Config]] = config,
topModule: Option[Class[_ <: Any]] = topModule ): RocketChipOptions = {

new RocketChipOptions(config=config, topModule=topModule)

}

lazy val longName: Option[String] = (config, topModule) match {
case (Some(a), Some(b)) => Some(s"${a.getName}:${b.getName}")
case _ => None
}

}
33 changes: 33 additions & 0 deletions src/main/scala/stage/RocketChipStage.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// See LICENSE.SiFive for license details.

package freechips.rocketchip.stage

import firrtl.AnnotationSeq
import firrtl.options.{Phase, PreservesAll, Shell, Stage, StageMain}
import firrtl.stage.FirrtlCli

import chisel3.stage.{ChiselCli, ChiselStage}

class RocketChipStage extends Stage with PreservesAll[Phase] {

override val shell = new Shell("rocket-chip") with RocketChipCli with ChiselCli with FirrtlCli

override def run(annotations: AnnotationSeq): AnnotationSeq =
Seq(
new freechips.rocketchip.stage.phases.Checks,
new freechips.rocketchip.stage.phases.PreElaboration,
new chisel3.stage.ChiselStage,
new freechips.rocketchip.stage.phases.AddTestSuites,
new freechips.rocketchip.stage.phases.GenerateROMs,
new freechips.rocketchip.stage.phases.GenerateArtefacts
).foldLeft(annotations){ case (a, p) => p.transform(a) }

}

object RocketChipFoo extends App {

(new RocketChipStage).execute(args, Seq.empty)

}

object RocketChipMain extends StageMain(new RocketChipStage)
25 changes: 25 additions & 0 deletions src/main/scala/stage/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// See LICENSE.SiFive for license details.

package freechips.rocketchip

import firrtl.AnnotationSeq
import firrtl.options.OptionsView

import freechips.rocketchip.stage.{ConfigAnnotation, RocketChipOption, RocketChipOptions, TopModuleAnnotation}

package object stage {

implicit object RocketChipOptionsView extends OptionsView[RocketChipOptions] {

def view(annotations: AnnotationSeq): RocketChipOptions = annotations
.collect { case a: RocketChipOption => a }
.foldLeft(new RocketChipOptions()){ (c, x) =>
x match {
case TopModuleAnnotation(a) => c.copy(topModule=Some(a))
case ConfigAnnotation(a) => c.copy(config=Some(a))
}
}

}

}
38 changes: 38 additions & 0 deletions src/main/scala/stage/phases/AddTestSuites.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// See LICENSE.SiFive for license details.

package freechips.rocketchip.stage.phases

import firrtl.AnnotationSeq
import firrtl.options.{Phase, StageOptions}
import firrtl.options.Viewer.view

import freechips.rocketchip.stage.RocketChipOptions
import freechips.rocketchip.system.{RocketTestSuite, TestGeneration}

import java.io.PrintWriter

case class RocketTestSuiteAnnotation(suite: RocketTestSuite)

class AddTestSuites extends Phase {

def transform(annotations: AnnotationSeq): AnnotationSeq = {
val sopts = view[StageOptions](annotations)
val ropts = view[RocketChipOptions](annotations)

println(ropts.config, ropts.topModule)

val w = new PrintWriter(sopts.getBuildFileName(ropts.longName.get, Some(".d")))
val makefrag =
annotations
.collect{ case a: RocketTestSuiteAnnotation => a.suite }
.groupBy(_.kind)
.map { case (kind, s) => TestGeneration.gen(kind, s) }
.mkString("\n")
w.write(makefrag)
w.close()

annotations
}


}
46 changes: 46 additions & 0 deletions src/main/scala/stage/phases/Checks.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// See LICENSE.SiFive for license details.

package freechips.rocketchip.stage.phases

import firrtl.AnnotationSeq
import firrtl.annotations.Annotation
import firrtl.options.{OptionsException, Phase}

import freechips.rocketchip.stage.{ConfigAnnotation, TopModuleAnnotation}

import scala.collection.mutable

class Checks extends Phase {

override def transform(annotations: AnnotationSeq): AnnotationSeq = {
val topM, conf = mutable.ListBuffer[Annotation]()
annotations.foreach {
case a: TopModuleAnnotation => a +=: topM
case a: ConfigAnnotation => a +=: conf
case _ =>
}

if (topM.size != 1) {
val x = topM.map{ case TopModuleAnnotation(x) => x }
val (msg, suggest) = topM.size match {
case 0 => ("none found", "forget one of")
case _ => (s"""found '${x.mkString(", ")}'""", "use multiple of")
}
throw new OptionsException(
s"""|Exactly one top module be specified, but $msg. Did you $suggest the following?
| - an option or annotation: --top-module, TopModuleAnnotation""".stripMargin )}

if (conf.size != 1) {
val x = conf.map{ case ConfigAnnotation(x) => x }
val (msg, suggest) = conf.size match {
case 0 => ("none found", "forget one of")
case _ => (s"""found '${x.mkString(", ")}'""", "use multiple of")
}
throw new OptionsException(
s"""|Exactly one configuration must be specified, but $msg. Did you $suggest the following?
| - an option or annotation: --config, ConfigAnnotation""".stripMargin )}

annotations
}

}
12 changes: 12 additions & 0 deletions src/main/scala/stage/phases/GenerateArtefacts.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// See LICENSE.SiFive for license details.

package freechips.rocketchip.stage.phases

import firrtl.AnnotationSeq
import firrtl.options.Phase

class GenerateArtefacts extends Phase {

def transform(annotations: AnnotationSeq): AnnotationSeq = ???

}
12 changes: 12 additions & 0 deletions src/main/scala/stage/phases/GenerteROMs.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// See LICENSE.SiFive for license details.

package freechips.rocketchip.stage.phases

import firrtl.AnnotationSeq
import firrtl.options.Phase

class GenerateROMs extends Phase {

def transform(annotations: AnnotationSeq): AnnotationSeq = ???

}
42 changes: 42 additions & 0 deletions src/main/scala/stage/phases/PreElaboration.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// See LICENSE.SiFive for license details.

package freechips.rocketchip.stage.phases

import chisel3.RawModule
import chisel3.stage.ChiselGeneratorAnnotation

import firrtl.AnnotationSeq
import firrtl.options.Phase
import firrtl.options.Viewer.view

import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.stage.{ConfigAnnotation, RocketChipOptions, TopModuleAnnotation}

class PreElaboration extends Phase {

override def transform(annotations: AnnotationSeq): AnnotationSeq = {
val ropts = view[RocketChipOptions](annotations)

val top = ropts.topModule.get

logger.info(s"$top")

val conf = ropts.config.get

logger.info(s"$conf")

val gen = () =>
ropts
.topModule
.get
.getConstructor(classOf[Parameters])
.newInstance(ropts.config.get.newInstance) match {
case a: RawModule => a
case a: LazyModule => LazyModule(a).module
}

ChiselGeneratorAnnotation(gen) +: annotations
}

}
28 changes: 14 additions & 14 deletions src/main/scala/system/RocketTestSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,18 @@ object TestGeneration {
private val suites = collection.mutable.ListMap[String, RocketTestSuite]()

def addSuite(s: RocketTestSuite) { suites += (s.makeTargetName -> s) }

def addSuites(s: Seq[RocketTestSuite]) { s.foreach(addSuite) }

def generateMakefrag: String = {
def gen(kind: String, s: Seq[RocketTestSuite]) = {
if(s.length > 0) {
val envs = s.groupBy(_.envName)
val targets = s.map(t => s"$$(${t.makeTargetName})").mkString(" ")
s.map(_.toString).mkString("\n") +
envs.filterKeys(_ != "").map( {
case (env,envsuites) => {
val suites = envsuites.map(t => s"$$(${t.makeTargetName})").mkString(" ")
s"""
private[rocketchip] def gen(kind: String, s: Seq[RocketTestSuite]) = {
if(s.length > 0) {
val envs = s.groupBy(_.envName)
val targets = s.map(t => s"$$(${t.makeTargetName})").mkString(" ")
s.map(_.toString).mkString("\n") +
envs.filterKeys(_ != "").map( {
case (env,envsuites) => {
val suites = envsuites.map(t => s"$$(${t.makeTargetName})").mkString(" ")
s"""
run-$kind-$env-tests: $$(addprefix $$(output_dir)/, $$(addsuffix .out, $suites))
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED):(.*)/i )' $$^ /dev/null | perl -pe 'BEGIN { $$$$failed = 0 } $$$$failed = 1 if(/FAILED/i); END { exit($$$$failed) }'
run-$kind-$env-tests-debug: $$(addprefix $$(output_dir)/, $$(addsuffix .vpd, $suites))
Expand All @@ -89,17 +88,18 @@ run-$kind-tests-fst: $$(addprefix $$(output_dir)/, $$(addsuffix .fst, $targets))
run-$kind-tests-fast: $$(addprefix $$(output_dir)/, $$(addsuffix .run, $targets))
\t@echo; perl -ne 'print " [$$$$1] $$$$ARGV \\t$$$$2\\n" if( /\\*{3}(.{8})\\*{3}(.*)/ || /ASSERTION (FAILED):(.*)/i )' $$^ /dev/null | perl -pe 'BEGIN { $$$$failed = 0 } $$$$failed = 1 if(/FAILED/i); END { exit($$$$failed) }'
"""
} else { "\n" }
}
} else { "\n" }
}

def generateMakefrag: String = {
suites.values.toSeq.groupBy(_.kind).map { case (kind, s) => gen(kind, s) }.mkString("\n")
}

}

object DefaultTestSuites {
val rv32uiNames = LinkedHashSet(
"simple", "add", "addi", "and", "andi", "auipc", "beq", "bge", "bgeu", "blt", "bltu", "bne", "fence_i",
"simple", "add", "addi", "and", "andi", "auipc", "beq", "bge", "bgeu", "blt", "bltu", "bne", "fence_i",
"jal", "jalr", "lb", "lbu", "lh", "lhu", "lui", "lw", "or", "ori", "sb", "sh", "sw", "sll", "slli",
"slt", "slti", "sra", "srai", "srl", "srli", "sub", "xor", "xori")
val rv32ui = new AssemblyTestSuite("rv32ui", rv32uiNames)(_)
Expand Down