Skip to content
Merged
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
4 changes: 2 additions & 2 deletions build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ object `package` extends ChipModule {
mvn"org.chipsalliance:::chisel-plugin:${chiselVersion}",
)

object test extends ScalaTests, TestModule.ScalaTest {
object test extends ScalaTests, TestModule.ScalaTest, FreshForkPath {
def moduleDeps = super.moduleDeps ++ Seq(testchipip)

def mvnDeps = Seq(
Expand Down Expand Up @@ -124,7 +124,7 @@ object `package` extends ChipModule {
mvn"org.chipsalliance:::chisel-plugin:${chiselVersion}",
)

object test extends ScalaTests, TestModule.ScalaTest {
object test extends ScalaTests, TestModule.ScalaTest, FreshForkPath {
def mvnDeps = Seq(
mvn"org.scalatest::scalatest:3.2.19",
)
Expand Down
16 changes: 15 additions & 1 deletion module.mill
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,22 @@ package build
import mill._
import scalalib._

trait ChipModule extends ScalaModule {
trait ChipModule extends ScalaModule, FreshForkPath {
def scalaVersion = "2.13.18"
def chiselVersion = "7.9.0"
}

/** Mill's `javaHomePathForkEnv` reads `Task.env` inside a cached task, so a
* forked JVM (tests, `run`, `runMain`) keeps the PATH from the first run
* forever. Re-read it on every run instead: tools like espresso are found
* through it. Test objects don't inherit this from their parent module, so
* each one mixes it in.
*/
trait FreshForkPath extends javalib.RunModule {
def shellPath = Task.Input { Task.env.find(_._1.equalsIgnoreCase("PATH")).map(_._2) }

override def javaHomePathForkEnv = Task {
val javaHomeBin = (javaHome().fold(os.Path(sys.props("java.home")))(_.path) / "bin").toString
Map("PATH" -> (javaHomeBin +: shellPath().toSeq).mkString(java.io.File.pathSeparator))
}
}
28 changes: 27 additions & 1 deletion src/Iris.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,33 @@ class IrisSystem(implicit p: Parameters)
with testchipip.serdes.CanHavePeripheryTLSerial
with sifive.blocks.devices.uart.HasPeripheryUART
with edu.berkeley.cs.chippy.clocking.HasChippyPRCI
with constellation.soc.CanHaveGlobalNoC
with constellation.soc.CanHaveGlobalNoC {
Espresso.requireOnPath()
}

/** Constellation's route computers minimize their routing tables with Chisel's
* `decoder`, which quietly falls back to Quine-McCluskey when it cannot launch
* espresso. On the Iris NoC that fallback runs for a long time and then dies
* inside RouteComputer with "Vector cannot have negative size -2147483648", so
* fail before elaboration instead.
*/
object Espresso {
private lazy val check: Unit =
try os.proc("espresso").call(stdin = ".i 1\n.o 1\n.type fr\n1 1\n.e\n")
catch {
// The same failure that makes Chisel's decoder fall back to QMC.
case e: java.io.IOException =>
throw new IllegalStateException(
s"""Cannot run espresso (${e.getMessage}).
|Iris needs espresso on PATH to generate its NoC: without it,
|Chisel's decoder falls back to Quine-McCluskey, which blows up on
|the route computers. Install it from
|https://github.com/chipsalliance/espresso (see README.md).""".stripMargin
)
}

def requireOnPath(): Unit = check
}

class IrisTop(implicit p: Parameters) extends LazyModule with BindingScope {
val system = LazyModule(new IrisSystem)
Expand Down
Loading