Skip to content
This repository has been archived by the owner on Aug 19, 2024. It is now read-only.

Commit

Permalink
Merge branch 'master' into 0.5-release
Browse files Browse the repository at this point in the history
  • Loading branch information
jackkoenig committed Jan 12, 2022
2 parents 1a1f077 + ca3d881 commit 00e3f50
Show file tree
Hide file tree
Showing 17 changed files with 252 additions and 113 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@
.bloop/
.metals/
.vscode/

# Synopsys Verdi
novas_dump.log
ucli.key
16 changes: 10 additions & 6 deletions .mergify.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
queue_rules:
- name: default
conditions:
- status-success=all tests passed
pull_request_rules:
- name: automatic squash-and-merge on CI success and review
conditions:
Expand All @@ -9,10 +13,10 @@ pull_request_rules:
- label!="DO NOT MERGE"
- label!="bp-conflict"
actions:
merge:
queue:
name: default
method: squash
strict: smart
strict_method: merge
update_method: merge
- name: backport to 0.3.x
conditions:
- merged
Expand Down Expand Up @@ -43,7 +47,7 @@ pull_request_rules:
- label!="DO NOT MERGE"
- label!="bp-conflict"
actions:
merge:
queue:
name: default
method: squash
strict: smart
strict_method: merge
update_method: merge
125 changes: 60 additions & 65 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,24 @@
# ChiselTest
*formerly known as testers2*
# chiseltest

This is **alpha software** that is currently under development, and interfaces may be subject to change (see [stability](#stability) for details).
However, it is very much in a usable state, so if you're fine living on the bleeding edge, give it a try.
Chiseltest is the _batteries-included_ testing and formal verification library for
[Chisel](https://github.com/chipsalliance/chisel3)-based RTL designs.
Chiseltest emphasizes tests that are lightweight (minimizes boilerplate code),
easy to read and write (understandability), and compose (for better test code reuse).

## Overview
ChiselTest is a test harness for [Chisel](https://github.com/chipsalliance/chisel3)-based RTL designs, currently supporting directed testing (all test stimulus manually specified - no constrained random and coverage-driven flows).
ChiselTest emphasizes tests that are lightweight (minimizes boilerplate code), easy to read and write (understandability), and compose (for better test code reuse).

The core primitives are similar to nonsynthesizable Verilog: input pin assignment (`poke`), pin value assertion (`expect`), and time advance (`step`). Threading concurrency is also supported with the use of `fork` and `join`, and concurrent accesses to wires are checked to prevent race conditions.

### Migrating from chisel-testers / iotesters
The core abstractions (`poke`, `expect`, `step`) are similar to [chisel-testers](https://github.com/freechipsproject/chisel-testers), but the syntax is inverted: instead of doing `tester.poke(wire, value)` with a Scala number value, in ChiselTest you would write `wire.poke(value)` with a Chisel literal value.
Furthermore, as no reference to the tester context is needed, test helper functions can be defined outside a test class and written as libraries.

Currently, this should support all the functionality that was in chisel-testers, and provides additional features.
This project is meant to supersede chisel-testers, and eventually may become a default part of chisel3.

Test cases written in chisel-testers cannot be directly used in ChiselTest, as the syntax is significantly different.


## Getting Started

### Installation
## Installation
To use chisel-testers as a managed dependency, add this in your build.sbt:
```scala
libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.2.1"
libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.5.0-RC2"
```

Note, `chiseltest` snapshots generally track chisel3 snapshots, and requires the use of a chisel3 snapshot.
We may introduce versioned snapshots and releases in the future, tied to a particular release of chisel3.
If you are also directly depending on the `chisel3` library, please
[make sure that your chisel3 and chiseltest versions match](https://www.chisel-lang.org/chisel3/docs/appendix/versioning.html)
to avoid linking errors.

You can also build ChiselTest locally with `publishLocal`.

### Writing a Test
ChiselTest integrates with the [ScalaTest](http://scalatest.org) framework, which provides a framework for detection and execution of unit tests.
## Writing a Test
ChiselTest integrates with the [ScalaTest](http://scalatest.org) framework,
which provides good IDE and continuous integration support for launching
unit tests.

Assuming a typical Chisel project with `MyModule` defined in `src/main/scala/MyModule.scala`:

Expand Down Expand Up @@ -99,7 +83,7 @@ In this file:
`testOnly` can also be used to run specific tests.


## Usage References
### Usage References
See the test cases for examples:
- [BasicTest](src/test/scala/chiseltest/tests/BasicTest.scala) shows basic `peek`, `poke`, and `step` functionality
- [QueueTest](src/test/scala/chiseltest/tests/QueueTest.scala) shows example uses of the DecoupledDriver library, providing functions like `enqueueNow`, `expectDequeueNow`, their sequence variants, `expectPeek`, and `expectInvalid`.
Expand All @@ -111,16 +95,6 @@ See the test cases for examples:
```
- [AlutTest](src/test/scala/chiseltest/tests/AluTest.scala) shows an example of re-using the same test for different data
- [ShiftRegisterTest](src/test/scala/chiseltest/tests/ShiftRegisterTest.scala) shows an example of using fork/join to define a test helper function, where multiple invocations of it are pipelined using `fork`.
- [VerilatorBasicTests](src/test/scala/chiseltest/experimental/tests/VerilatorBasicTests.scala) shows an example using Verilator as the simulator.
- Note: the simulator is selected by passing an annotation into the `test` function, which requires experimental imports:
```scala
import chiseltest._
```
```scala
test(new MyModule).withAnnotations(Seq(VerilatorBackendAnnotation)) { c =>
// test body here
}
```

## New Constructs
- `fork` to spawn threads, and `join` to block (wait) on a thread.
Expand All @@ -139,14 +113,26 @@ See the test cases for examples:
This fits well with the pattern of assigning a default pull-up/down to a wire, and temporarily overriding that value, for example a Decoupled `valid` signal defaulting low but driven high during an enqueue transaction.
See [TimescopeTest](src/test/scala/chiseltest/tests/TimescopeTest.scala) for examples.

## Simulator Backends

One of our goals is to keep your tests independent of the underlying simulator as much as possible.
Thus, in most cases you should be able to choose from one of our four supported backends and get the
exact same test results albeit with differences in execution speed and wave dump quality.


We provide full bindings to two popular open-source simulator:
- [treadle](https://github.com/chipsalliance/treadle): default, fast startup times, slow execution for larger circuits,
supports only VCD
- [verilator](https://www.veripool.org/wiki/verilato): enable with `VerilatorBackendAnnotation`, slow startup,
fast execution, supports VCD and FST

We also provide bindings with some feature limitations to:
- [iverilog](http://iverilog.icarus.com/): open-source, enable with `IcarusBackendAnnotation`, supports VCD, FST and LXT
- [vcs](https://www.synopsys.com/verification/simulation/vcs.html): commercial, enable with `VcsBackendAnnotation`,
supports VCD and FSDB

## Quick References
To dump VCDs (into the test_run_dir subfolder) using sbt:
```
testOnly chiseltest.tests.BasicTest -- -DwriteVcd=1
```

## Verilator Backend
### Verilator Versions

We currently support the following versions of the [verilator](https://www.veripool.org/wiki/verilator) simulator:
- `v4.028`: [Ubuntu 20.04](https://packages.ubuntu.com/focal/verilator), [Fedora 32](https://src.fedoraproject.org/rpms/verilator)
Expand All @@ -157,21 +143,30 @@ We currently support the following versions of the [verilator](https://www.verip
- `v4.202`

## Stability
These APIs may be considered stable and are unlikely to change significantly:
- Test invocation `test`
- Basic operations: `poke`, `peek`, `expect`, `step`, including on Bundles
- Basic concurrency operations: `fork`, `join`
- Decoupled library: `enqueueNow`, `expectDequeueNow`, their sequence variants, `expectPeek`, `expectInvalid` - though the names may be refactored
- `timescope` - though the name may be refactored
These are subject to change:
- Multiclock behavior, which is currently not well defined, including `poke` on clocks and `step` when there are multiple clocks.
## Roadmap
These features are on our roadmap, but are not implemented yet.
No timeframe is currently available, but feel free to let us know if some feature is critical to your use case in the relevant issue thread, and we may adjust our development priorities accordingly.
- [#14](https://github.com/ucb-bar/chisel-testers2/issues/14) support for multi-clock designs, and in particular, supporting clock poke to clock step inter-thread dependencies.
- [#28](https://github.com/ucb-bar/chisel-testers2/issues/28) faster Verilator / VCS testing using mechanisms that avoid interprocess communication, like JNI
- [#58](https://github.com/ucb-bar/chisel-testers2/issues/58) faster threading (note, unclear if there are good solutions here, especially ones that are fully API compatible - Scala generally lacks good coroutine support)
- [#60](https://github.com/ucb-bar/chisel-testers2/issues/60), [#34](https://github.com/ucb-bar/chisel-testers2/issues/34), [#2](https://github.com/ucb-bar/chisel-testers2/issues/2) support for testing non-Chisel modules, such as post-syn Verilog, or generally a separation of DUT interface and implementation
Most APIs that can be accessed through `import chiseltest._` are going to remain stable.
We are also trying to keep the API provided through `import chiseltest.formal._` relatively stable.
All other packages are considered internal and thus might change at any time.

## Migrating from chisel-testers / iotesters

### Port to new API
The core abstractions (`poke`, `expect`, `step`) are similar to
[chisel-testers](https://github.com/freechipsproject/chisel-testers), but the syntax is inverted:
instead of doing `tester.poke(wire, value)` with a Scala number value, in ChiselTest you would write `wire.poke(value)`
with a Chisel literal value.
Furthermore, as no reference to the tester context is needed,
test helper functions can be defined outside a test class and written as libraries.

### PeekPokeTester compatibility

`chiseltest` now provides a compatibility layer that makes it possible to re-use old `PeekPokeTester` based
tests with little to no changes to the code.
We ported the majority of [tests from the chisel-testers repository](https://github.com/freechipsproject/chisel-testers/tree/master/src/test/scala)
to our [new compatibility layer](https://github.com/ucb-bar/chiseltest/tree/master/src/test/scala/chiseltest/iotesters).
While the test itself can mostly remain unchanged, the old `Driver` is removed and instead tests are launched
with the new `test` syntax.

### Hardware testers

Hardware testers are synthesizeable tests, most often extending the `BasicTester` class provided by `chisel3`.
You can now directly [use these tests with `chiseltest` through the `runUntilStop` function](https://github.com/ucb-bar/chiseltest/blob/master/src/test/scala/chiseltest/tests/HardwareTestsTest.scala).
57 changes: 54 additions & 3 deletions src/main/scala/chisel3/tester/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,114 @@ import chisel3._
import chisel3.util._

package object tester {
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
implicit class testableData[T <: Data](x: T) extends chiseltest.testableData[T](x)
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
implicit class testableClock(x: Clock) extends chiseltest.testableClock(x)

@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
val fork = chiseltest.fork

def parallel(run1: => Unit, run2: => Unit): Unit = chiseltest.parallel(run1, run2)
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
def parallel(run1: => Unit, run2: => Unit): Unit = chiseltest.parallel(run1, run2)
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
def timescope(contents: => Unit): Unit = chiseltest.timescope(contents)

@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
val TestInstance = chiseltest.TestInstance
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
val ClockResolutionUtils = chiseltest.ClockResolutionUtils
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
implicit def decoupledToDriver[T <: Data](x: ReadyValidIO[T]) = chiseltest.decoupledToDriver(x)
implicit def validToDriver[T <: Data](x: ValidIO[T]) = chiseltest.validToDriver(x)
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
implicit def validToDriver[T <: Data](x: ValidIO[T]) = chiseltest.validToDriver(x)

// Exceptions
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type NotLiteralException = chiseltest.NotLiteralException
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type LiteralTypeException = chiseltest.LiteralTypeException
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type UnpokeableException = chiseltest.UnpokeableException
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type UnsupportedOperationException = chiseltest.UnsupportedOperationException

@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type ClockResolutionException = chiseltest.ClockResolutionException
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type ThreadOrderDependentException = chiseltest.ThreadOrderDependentException
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type TimeoutException = chiseltest.TimeoutException
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type TemporalParadox = chiseltest.TemporalParadox

// Standard test environment interface
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type ChiselScalatestTester = chiseltest.ChiselScalatestTester
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type ChiselUtestTester = chiseltest.ChiselUtestTester
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
val RawTester = chiseltest.RawTester

// Other chiseltest package classes
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type Region = chiseltest.Region
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
val Region = chiseltest.Region
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
val TestdriverMain = chiseltest.TestdriverMain
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
val Monitor = chiseltest.Monitor

// Stock drivers
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type ValidDriver[T <: Data] = chiseltest.ValidDriver[T]
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
val ValidDriver = chiseltest.ValidDriver

@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
type DecoupledDriver[T <: Data] = chiseltest.DecoupledDriver[T]
@deprecated("Please import from chiseltest._ instead of chisel3.tester._!", "chiseltest 0.5")
val DecoupledDriver = chiseltest.DecoupledDriver

// Subpackages
object experimental {
@deprecated(
"Please import from chiseltest.experimental._ instead of chisel3.tester.experimental._!",
"chiseltest 0.5"
)
def sanitizeFileName(name: String): String = chiseltest.experimental.sanitizeFileName(name)

@deprecated(
"Please import from chiseltest.experimental._ instead of chisel3.tester.experimental._!",
"chiseltest 0.5"
)
object UncheckedClockPeek {
implicit class PeekableClock(signal: Clock)
extends chiseltest.experimental.UncheckedClockPeek.PeekableClock(signal)
}
@deprecated(
"Please import from chiseltest.experimental._ instead of chisel3.tester.experimental._!",
"chiseltest 0.5"
)
object UncheckedClockPoke {
implicit class UncheckedPokeableClock(signal: Clock)
extends chiseltest.experimental.UncheckedClockPoke.UncheckedPokeableClock(signal)
}

@deprecated(
"Please import from chiseltest.experimental._ instead of chisel3.tester.experimental._!",
"chiseltest 0.5"
)
type AsyncResetReg = chiseltest.experimental.AsyncResetReg
@deprecated(
"Please import from chiseltest.experimental._ instead of chisel3.tester.experimental._!",
"chiseltest 0.5"
)
type AsyncResetRegScalaImpl = chiseltest.experimental.AsyncResetRegScalaImpl
@deprecated(
"Please import from chiseltest.experimental._ instead of chisel3.tester.experimental._!",
"chiseltest 0.5"
)
type AsyncResetBlackBoxFactory = chiseltest.experimental.AsyncResetBlackBoxFactory
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -230,14 +230,19 @@ private[chiseltest] class TransitionSystemSimulator(
def failedPropertiesMsg: String =
s"Failed (${failed.size}) properties in step #$index:\n${failed.map(failedMsg).mkString("\n")}"
expectedFailed match {
case None =>
assert(failed.isEmpty, "Unexpected failure!! " + failedPropertiesMsg)
case None if failed.isEmpty => // great!
case None => // oh no
println(
"Warn: Potential simulation/formal mismatch.\n" +
s"In step #$index: Unexpected failure!! " + failedPropertiesMsg
)
case Some(Seq()) => // this means that we do not know which exact property is supposed to fail
case Some(props) =>
val failedSet = failed.toSet
if (!props.toSet.subsetOf(failedSet)) {
println(
s"In step #$index: Expected properties ${props.mkString(", ")} to fail, instead ${failed.mkString(", ")} failed"
"Warn: Potential simulation/formal mismatch.\n" +
s"In step #$index: Expected properties ${props.mkString(", ")} to fail, instead ${failed.mkString(", ")} failed"
)
}
}
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/chiseltest/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ package object chiseltest {
val IcarusBackendAnnotation = simulator.IcarusBackendAnnotation
val WriteVcdAnnotation = simulator.WriteVcdAnnotation
val WriteVpdAnnotation = simulator.WriteVpdAnnotation
val WriteFsdbAnnotation = simulator.WriteFsdbAnnotation
val WriteLxtAnnotation = simulator.WriteLxtAnnotation
type WriteLxtAnnotation = simulator.WriteLxtAnnotation
val WriteFstAnnotation = simulator.WriteFstAnnotation
Expand Down
Loading

0 comments on commit 00e3f50

Please sign in to comment.