diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 29ebb66cc..9faf28c28 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,25 +15,10 @@ jobs: strategy: matrix: scala: [2.13.10] - jvm: [8, 11] - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Scala - uses: actions/setup-java@v3 - with: - distribution: 'adopt' - java-version: ${{ matrix.jvm }} - - name: Test - run: sbt ++${{ matrix.scala }} "testOnly chiseltest.** -- -l RequiresVcs -l RequiresVerilator -l Formal -l RequiresIcarus" + jvm: [20] - integration-test: - name: Integration Tests - runs-on: ubuntu-20.04 - strategy: - matrix: - scala: [ 2.13.10 ] - jvm: [ 8, 11, 20 ] + env: + JAVA_OPTS: "--enable-preview" steps: - name: Checkout uses: actions/checkout@v3 @@ -44,186 +29,3 @@ jobs: java-version: ${{ matrix.jvm }} - name: Test run: sbt ++${{ matrix.scala }} "testOnly integration.**" - - - test-mac: - name: sbt test on mac - runs-on: macos-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Test - run: sbt "testOnly chiseltest.** -- -l RequiresVcs -l RequiresVerilator -l Formal -l RequiresIcarus" - - icarus: - name: icarus verilog - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ ubuntu-20.04, macos-latest ] - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Install Icarus Verilog for Ubuntu - if: runner.os == 'Linux' - run: | - sudo apt-get install -y iverilog - iverilog -v || true - - name: Install Icarus Verilog for MacOS - if: runner.os == 'macOS' - run: | - brew install icarus-verilog - iverilog -v || true - - name: Test - run: sbt ++${{ matrix.scala }} "testOnly chiseltest.** -- -n RequiresIcarus" - - verilator: - name: verilator regressions - runs-on: ubuntu-20.04 - strategy: - matrix: - # 4.028: Ubuntu 20.04, Fedora 32 - # 4.032: Fedora 33 - # 4.034: Chipyard - # 4.038: Ubuntu 20.10 - # 4.108: Fedora 34 - # 4.200: currently the latest version on brew (MacOS) - # 4.202: added "forcePerInstance" to support our coverage flow - version: ["4.028", "4.032", "4.034", "4.038", "4.108", "4.200", "4.202"] - - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Install Verilator Build Dependencies - run: sudo apt-get install -y git make autoconf g++ flex bison libfl2 libfl-dev - - name: Cache Verilator ${{ matrix.version }} - uses: actions/cache@v3 - id: cache-verilator - with: - path: verilator-${{ matrix.version }} - key: ${{ runner.os }}-verilator-${{ matrix.version }} - - name: Compile Verilator ${{ matrix.version }} - if: steps.cache-verilator.outputs.cache-hit != 'true' - run: | - wget https://github.com/verilator/verilator/archive/refs/tags/v${{ matrix.version }}.zip - unzip v${{ matrix.version }}.zip - cd verilator-${{ matrix.version }} - autoconf - ./configure - make - - name: Install Verilator ${{ matrix.version }} - run: | - cd verilator-${{ matrix.version }} - sudo make install - verilator --version - - name: Test - run: sbt "testOnly chiseltest.** -- -n RequiresVerilator" - - formal: - name: formal verification tests - runs-on: ubuntu-20.04 - strategy: - matrix: - backend: [z3, cvc4, btormc, bitwuzla] - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Install Z3 and CVC4 - if: runner.os == 'Linux' - run: | - sudo apt-get install -y z3 cvc4 - z3 --version - cvc4 --version - - name: Install Tabby OSS Cad Suite (from YosysHQ) - uses: ./.github/workflows/setup-oss-cad-suite - with: - osscadsuite-version: '2023-01-09' - - name: Test - run: sbt "testOnly chiseltest.** -- -n Formal -Dformal_engine=${{ matrix.backend }}" - - formal-mac: - name: formal verification tests on mac - runs-on: macos-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Install Z3 for MacOS - run: | - brew install z3 - z3 --version - - name: Test - run: sbt "testOnly chiseltest.** -- -n Formal -Dformal_engine=z3" - - doc: - name: Documentation and Formatting - runs-on: ubuntu-20.04 - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Documentation - id: doc - run: sbt doc - - name: Check Formatting - run: sbt scalafmtCheckAll - - no-warn: - name: No Warnings with Scala 2.13 for PRs - if: github.event_name == 'pull_request' - runs-on: ubuntu-20.04 - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Check for Warnings - run: sbt "set ThisBuild / scalacOptions ++= Seq(\"-Xfatal-warnings\") ; compile" - - name: Check for Warnings in Tests - run: sbt "set ThisBuild / scalacOptions ++= Seq(\"-Xfatal-warnings\") ; Test / compile" - - test-treadle: - name: sbt test for treadle on ubuntu - runs-on: ubuntu-20.04 - strategy: - matrix: - scala: [2.13.10] - jvm: [8, 11] - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Scala - uses: actions/setup-java@v3 - with: - distribution: 'adopt' - java-version: ${{ matrix.jvm }} - - name: Test - run: sbt ++${{ matrix.scala }} "testOnly treadle2.**" - - # Sentinel job to simplify how we specify which checks need to pass in branch - # protection and in Mergify - # - # When adding new jobs, please add them to `needs` below - all_tests_passed: - name: "all tests passed" - needs: [test, doc, verilator, formal, formal-mac, icarus, test-mac, no-warn, integration-test] - runs-on: ubuntu-latest - steps: - - run: echo Success! - - # sbt ci-release publishes all cross versions so this job needs to be - # separate from a Scala versions build matrix to avoid duplicate publishing - publish: - # note: we do not require a warning check for publishing! - needs: [test, doc, verilator, formal, formal-mac, icarus, test-mac, test-treadle, integration-test] - runs-on: ubuntu-20.04 - if: github.event_name == 'push' - - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup GPG (for Publish) - uses: olafurpg/setup-gpg@v3 - - name: Publish - run: sbt ci-release - env: - PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} - PGP_SECRET: ${{ secrets.PGP_SECRET }} - SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} - SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} diff --git a/build.sbt b/build.sbt index 6bece7d0a..610e0c370 100644 --- a/build.sbt +++ b/build.sbt @@ -88,3 +88,5 @@ libraryDependencies ++= Seq( ) } } + +javacOptions ++= Seq("--source", "20", "--target", "20", "--enable-preview") \ No newline at end of file diff --git a/src/main/scala/chiseltest/internal/NewThreadedBackend.scala b/src/main/scala/chiseltest/internal/NewThreadedBackend.scala new file mode 100644 index 000000000..964de36fb --- /dev/null +++ b/src/main/scala/chiseltest/internal/NewThreadedBackend.scala @@ -0,0 +1,145 @@ +package chiseltest.internal + +import chisel3.{Clock, Data, Module} +import chiseltest._ +import chiseltest.coverage.TestCoverage +import chiseltest.simulator.{SimulatorContext, StepInterrupted, StepOk} +import firrtl2.AnnotationSeq +import scala.collection.mutable + + +/** Experiment to create a more performant threaded backedn */ +class NewThreadedBackend[T <: Module]( + val dut: T, + val dataNames: Map[Data, String], + val combinationalPaths: Map[Data, Set[Data]], + tester: SimulatorContext, + coverageAnnotations: AnnotationSeq) + extends BackendInstance[T] { + + override def resolveName(signal: Data): String = { + dataNames.getOrElse(signal, signal.toString) + } + + // Circuit introspection functionality + override def getSourceClocks(signal: Data): Set[Clock] = { + throw new ClockResolutionException("ICR not available on chisel-testers2 / firrtl master") + } + + override def getSinkClocks(signal: Data): Set[Clock] = { + throw new ClockResolutionException("ICR not available on chisel-testers2 / firrtl master") + } + + override def pokeClock(signal: Clock, value: Boolean): Unit = { + throw new NotImplementedError("Poking clocks is currently no supported!") + } + + override def peekClock(signal: Clock): Boolean = { + val a = tester.peek(dataNames(signal)) + a > 0 + } + + private val previousPokes = mutable.HashMap[String, BigInt]() + override def pokeBits(signal: Data, value: BigInt): Unit = { + val name = dataNames(signal) + previousPokes.get(name) match { + case Some(oldValue) if oldValue == value => // ignore + case _ => + tester.poke(name, value) + idleCycles = 0 + previousPokes(name) = value + } + } + + override def peekBits(signal: Data): BigInt = { + val name = dataNames.getOrElse( + signal, + throw new UnpeekableException( + s"Signal $signal not found. Perhaps you're peeking a non-IO signal.\n If so, consider using the chiseltest.experimental.expose API." + ) + ) + tester.peek(name) + } + + override def doTimescope(contents: () => Unit): Unit = { + throw new NotImplementedError("This backend does not support timescopes!") + } + + override def doFork(runnable: () => Unit, name: Option[String], region: Option[Region]): Nothing = { + throw new NotImplementedError("This backend does not support threads!") + } + + override def doJoin(threads: Seq[AbstractTesterThread], stepAfter: Option[Clock]): Unit = { + throw new NotImplementedError("This backend does not support threads!") + } + + private var timeout = 1000 + private var idleCycles = 0 + + override def step(signal: Clock, cycles: Int): Unit = { + require(signal == dut.clock) + // throw any available exceptions before stepping + Context().env.checkpoint() + val delta = if (timeout == 0) cycles else Seq(cycles, timeout - idleCycles).min + tester.step(delta) match { + case StepOk => + // update and check timeout + idleCycles += delta + stepCount += delta + if (timeout > 0 && idleCycles == timeout) { + throw new TimeoutException(s"timeout on $signal at $timeout idle cycles") + } + case StepInterrupted(after, true, _) => + val msg = s"An assertion in ${dut.name} failed.\n" + + "Please consult the standard output for more details." + throw new ChiselAssertionError(msg, cycles + after) + case StepInterrupted(after, false, _) => + val msg = s"A stop() statement was triggered in ${dut.name}." + throw new StopException(msg, cycles + after) + } + } + + private var stepCount: Long = 0 + + override def getStepCount(signal: Clock): Long = { + require(signal == dut.clock) + stepCount + } + + override def setTimeout(signal: Clock, cycles: Int): Unit = { + require(signal == dut.clock, "timeout currently only supports master clock") + require(cycles >= 0, s"Negative timeout $cycles is not supported! Use 0 to disable the timeout.") + timeout = cycles + idleCycles = 0 + } + + override def run(testFn: T => Unit): AnnotationSeq = { + try { + // default reset + tester.poke("reset", 1) + tester.step(1) + tester.poke("reset", 0) + + // we only count the user steps + stepCount = 0 + + // execute use code + testFn(dut) + + // throw any exceptions that might be left over + Context().env.checkpoint() + } finally { + tester.finish() // needed to dump VCDs + terminate any external process + } + + if (tester.sim.supportsCoverage) { + generateTestCoverageAnnotation() +: coverageAnnotations + } else { Seq() } + } + + /** Generates an annotation containing the map from coverage point names to coverage counts. */ + private def generateTestCoverageAnnotation(): TestCoverage = { + TestCoverage(tester.getCoverage()) + } + +} \ No newline at end of file diff --git a/src/main/scala/chiseltest/internal/ThreadedBackend.scala b/src/main/scala/chiseltest/internal/ThreadedBackend.scala index c2b52a4cc..2a9687669 100644 --- a/src/main/scala/chiseltest/internal/ThreadedBackend.scala +++ b/src/main/scala/chiseltest/internal/ThreadedBackend.scala @@ -486,7 +486,7 @@ trait ThreadedBackend[T <: Module] extends BackendInterface { // noinspection ConvertExpressionToSAM // TODO: code analysis suggests "Convert expression to Single Abstract Method", will that work? - val thread = new Thread(new Runnable { + val thread = new Thread (new Runnable { def run(): Unit = { try { waiting.acquire() diff --git a/src/test/scala/integration/UartSendAndReceiveTest.scala b/src/test/scala/integration/UartSendAndReceiveTest.scala index 83b4c8c84..104e9ef59 100644 --- a/src/test/scala/integration/UartSendAndReceiveTest.scala +++ b/src/test/scala/integration/UartSendAndReceiveTest.scala @@ -8,7 +8,7 @@ import org.scalatest.freespec.AnyFreeSpec class UartPassThrough extends Module { val rx = IO(Input(UInt(1.W))) val tx = IO(Output(UInt(1.W))) - val Depth = 50 + val Depth = 1 val AllOnes = (BigInt(1) << Depth) - 1 tx := ShiftRegister(rx, Depth, AllOnes.U, true.B) } @@ -80,7 +80,7 @@ class UartSendAndReceiveTest extends AnyFreeSpec with ChiselScalatestTester { } "run 100 uart transactions in software" in { - test(new UartPassThrough)(runTimedTest(_, 100, bitDelay = 50)) + test(new UartPassThrough)(runTimedTest(_, 10000, bitDelay = 1)) } }