Skip to content

Commit 4b40f24

Browse files
authored
Add FileCheck for unit testing (#3410)
Update SETUP.md including brief instructions on FileCheck.
1 parent 68fc902 commit 4b40f24

File tree

6 files changed

+234
-20
lines changed

6 files changed

+234
-20
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Install FileCheck
2+
3+
inputs:
4+
version:
5+
description: 'version to install'
6+
required: false
7+
default: 'FileCheck-16.0.6-test'
8+
9+
runs:
10+
using: composite
11+
steps:
12+
- id: cache-filecheck
13+
uses: actions/cache@v3
14+
with:
15+
path: FileCheck
16+
key: filecheck-${{ runner.os }}-${{ inputs.version }}
17+
18+
- shell: bash
19+
if: steps.cache-filecheck.outputs.cache-hit != 'true'
20+
run: |
21+
mkdir -p filecheck/bin
22+
wget -q https://github.com/jackkoenig/FileCheck/releases/download/${{ inputs.version }}/FileCheck-linux-x64
23+
chmod +x FileCheck-linux-x64
24+
mv FileCheck-linux-x64 filecheck/bin/FileCheck
25+
26+
- shell: bash
27+
run: echo "$(pwd)/filecheck/bin" >> $GITHUB_PATH

.github/workflows/test.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ jobs:
5858
uses: ./.github/workflows/build-slang
5959
with:
6060
version: ${{ inputs.slang }}
61+
- name: Install FileCheck
62+
run: |
63+
sudo apt update
64+
sudo apt install llvm-12-tools
65+
echo "/usr/lib/llvm-12/bin" >> $GITHUB_PATH
6166
- name: Setup Java
6267
uses: actions/setup-java@v4
6368
with:

SETUP.md

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# Chisel Local Setup
2+
Instructions for setting up your environment to run Chisel locally.
3+
4+
For a minimal setup, you only need to install [SBT (the Scala Build Tool)](http://www.scala-sbt.org), which will automatically fetch the appropriate version of Scala and Chisel based on on your project configuration.
5+
6+
[Firtool](https://github.com/llvm/circt) is required to generate Verilog.
7+
8+
[Verilator](https://www.veripool.org/wiki/verilator) is installation is required to simulate your Verilog designs.
9+
10+
[FileCheck](https://llvm.org/docs/CommandGuide/FileCheck.html) is used by many of the unit tests.
11+
Please see the FileCheck link for documentation about FileCheck's syntax with examples.
12+
Alternatively you can search the tests for examples by searching for `CHECK:` which is used to tell FileCheck to attempt to match the following text in the generated output.
13+
14+
## Ubuntu Linux
15+
16+
1. Install the JVM
17+
```bash
18+
sudo apt-get install default-jdk
19+
```
20+
21+
1. Install sbt according to the instructions from [sbt download](https://www.scala-sbt.org/download.html).
22+
23+
1. Install Firtool
24+
25+
Choose whatever version is being [used in continuous integration](.github/workflows/install-circt/action.yml)
26+
```bash
27+
wget -q -O - https://github.com/llvm/circt/releases/download/firtool-1.56.1/circt-full-shared-linux-x64.tar.gz | tar -zx
28+
```
29+
This will give you a directory called `firtool-1.56.1` containing the firtool binary, add this to your PATH as appropriate.
30+
```bash
31+
export PATH=$PATH:$PWD/firtool-1.56.1/bin
32+
```
33+
Alternatively, you can install the binary to a standard location by simply moving the binary (if you have root access).
34+
```bash
35+
mv firtool-1.56.1/bin/firtool /usr/local/bin/
36+
```
37+
38+
39+
1. Install Verilator.
40+
We recommend relatively recent verilator
41+
Follow these instructions to compile it from source.
42+
43+
1. Install prerequisites (if not installed already):
44+
```bash
45+
sudo apt-get install git make autoconf g++ flex bison
46+
```
47+
48+
2. Clone the Verilator repository:
49+
```bash
50+
git clone https://github.com/verilator/verilator
51+
```
52+
53+
3. In the Verilator repository directory, check out a known good version:
54+
```bash
55+
git pull
56+
git checkout v5.004
57+
```
58+
59+
4. In the Verilator repository directory, build and install:
60+
```bash
61+
unset VERILATOR_ROOT # For bash, unsetenv for csh
62+
autoconf # Create ./configure script
63+
./configure
64+
make
65+
sudo make install
66+
```
67+
68+
1. Install FileCheck.
69+
FileCheck can usually be found in llvm-\*-tools packages, eg.
70+
```
71+
sudo apt-get install llvm-12-tools
72+
export PATH=$PATH:/usr/lib/llvm-12/bin
73+
```
74+
75+
You can alternatively download a statically-ish linked binary from https://github.com/jackkoenig/FileCheck
76+
```
77+
mkdir filecheck
78+
cd filecheck
79+
wget -q https://github.com/jackkoenig/FileCheck/releases/download/FileCheck-16.0.6/FileCheck-linux-x64
80+
mv FileCheck-linux-x64 FileCheck
81+
chmod +x FileCheck
82+
export PATH=$PATH:$PWD
83+
```
84+
Similarly to firtool, you can install the binary to a more standard location by moving it.
85+
```
86+
mv FileCheck /usr/local/bin
87+
```
88+
89+
## Arch Linux
90+
1. Install Verilator and SBT
91+
```bash
92+
pacman -Sy verilator sbt
93+
```
94+
95+
1. Install firtool
96+
97+
See the instructions for Ubuntu above, the firtool Ubuntu binary is a "many Linux" mostly statically linked binary.
98+
99+
## Windows
100+
1. [Download and install sbt for Windows](https://www.scala-sbt.org/download.html).
101+
102+
Verilator does not appear to have native Windows support.
103+
However, Verilator works in [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10) or in other Linux-compatible environments like Cygwin.
104+
105+
There are no issues with generating Verilog from Chisel, which can be pushed to FPGA or ASIC tools.
106+
107+
## Mac OS X
108+
1. Install Verilator and SBT
109+
```bash
110+
brew install sbt verilator
111+
```
112+
113+
1. Install firtool
114+
115+
```bash
116+
wget -q -O - https://github.com/llvm/circt/releases/download/firtool-1.56.1/circt-full-shared-macos-x64.tar.gz | tar -zx
117+
```
118+
This will give you a directory called `firtool-1.56.1` containing the firtool binary, add this to your PATH as appropriate.
119+
```bash
120+
export PATH=$PATH:$PWD/firtool-1.56.1/bin
121+
```
122+
Alternatively, you can install the binary to a standard location by simply moving the binary.
123+
```bash
124+
mv firtool-1.56.1/bin/firtool /usr/local/bin/
125+
```
126+
127+
1. Install FileCheck.
128+
You can download a statically-ish linked binary from https://github.com/jackkoenig/FileCheck
129+
```
130+
mkdir filecheck
131+
cd filecheck
132+
wget -q https://github.com/jackkoenig/FileCheck/releases/download/FileCheck-16.0.6/FileCheck-macos-x64
133+
mv FileCheck-macos-x64 FileCheck
134+
chmod +x FileCheck
135+
export PATH=$PATH:$PWD
136+
```
137+
Similarly to firtool, you can install the binary to a more standard location by moving it.
138+
```
139+
mv FileCheck /usr/local/bin
140+
```

src/test/scala/chiselTests/ChiselEnum.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ class IsOneOfTester extends BasicTester {
360360
stop()
361361
}
362362

363-
class ChiselEnumSpec extends ChiselFlatSpec with Utils {
363+
class ChiselEnumSpec extends ChiselFlatSpec with Utils with FileCheck {
364364

365365
behavior.of("ChiselEnum")
366366

@@ -529,9 +529,11 @@ class ChiselEnumSpec extends ChiselFlatSpec with Utils {
529529
val out = IO(Output(MyEnum()))
530530
out := MyEnum(in)
531531
}
532-
val (log, _) = grabLog(ChiselStage.emitCHIRRTL(new MyModule))
533-
log should include("warn")
534-
log should include("Casting non-literal UInt")
532+
elaborateAndFileCheckOutAndErr(new MyModule)(
533+
"""| CHECK: [W001] Casting non-literal UInt to [[enum:[a-zA-Z0-9_$.]+]].
534+
| CHECK-SAME: You can use [[enum]].safe to cast without this warning.
535+
|""".stripMargin
536+
)
535537
}
536538

537539
it should "NOT warn if the Enum is total" in {

src/test/scala/chiselTests/ChiselSpec.scala

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,50 @@ trait ChiselRunners extends Assertions {
211211
}
212212
}
213213

214+
trait FileCheck extends BeforeAndAfterEachTestData { this: Suite =>
215+
import scala.Console.{withErr, withOut}
216+
217+
private def sanitize(n: String): String = n.replaceAll(" ", "_").replaceAll("\\W+", "")
218+
219+
private val testRunDir: os.Path = os.pwd / os.RelPath(BackendCompilationUtilities.TestDirectory)
220+
private val suiteDir: os.Path = testRunDir / sanitize(suiteName)
221+
private var checkFile: Option[os.Path] = None
222+
223+
override def beforeEach(testData: TestData): Unit = {
224+
// TODO check that these are always available
225+
val nameDir = suiteDir / sanitize(testData.name)
226+
os.makeDir.all(nameDir)
227+
checkFile = Some(nameDir / s"${sanitize(testData.text)}.check")
228+
super.beforeEach(testData) // To be stackable, must call super.beforeEach
229+
}
230+
231+
override def afterEach(testData: TestData): Unit = {
232+
checkFile = None
233+
super.afterEach(testData) // To be stackable, must call super.beforeEach
234+
}
235+
236+
/** Run FileCheck on a String against some checks */
237+
def fileCheckString(in: String, fileCheckArgs: String*)(check: String): Unit = {
238+
// Filecheck needs the thing to check in a file
239+
os.write.over(checkFile.get, check)
240+
val extraArgs = os.Shellable(fileCheckArgs)
241+
os.proc("FileCheck", checkFile.get, extraArgs).call(stdin = in)
242+
}
243+
244+
/** Elaborate a Module to FIRRTL and check the FIRRTL with FileCheck */
245+
def generateFirrtlAndFileCheck(t: => RawModule, fileCheckArgs: String*)(check: String): Unit = {
246+
fileCheckString(ChiselStage.emitCHIRRTL(t), fileCheckArgs: _*)(check)
247+
}
248+
249+
/** Elaborate a Module, capture the stdout and stderr, check stdout and stderr with FileCheck */
250+
def elaborateAndFileCheckOutAndErr(t: => RawModule, fileCheckArgs: String*)(check: String): Unit = {
251+
val outStream = new ByteArrayOutputStream()
252+
withOut(outStream)(withErr(outStream)(ChiselStage.emitCHIRRTL(t)))
253+
val result = outStream.toString
254+
fileCheckString(outStream.toString, fileCheckArgs: _*)(check)
255+
}
256+
}
257+
214258
/** Spec base class for BDD-style testers. */
215259
abstract class ChiselFlatSpec extends AnyFlatSpec with ChiselRunners with Matchers
216260

src/test/scala/chiselTests/DecoupledSpec.scala

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import chisel3._
66
import circt.stage.ChiselStage
77
import chisel3.util.Decoupled
88

9-
class DecoupledSpec extends ChiselFlatSpec {
9+
class DecoupledSpec extends ChiselFlatSpec with FileCheck {
1010
"Decoupled() and Decoupled.empty" should "give DecoupledIO with empty payloads" in {
1111
ChiselStage.emitCHIRRTL(new Module {
1212
val io = IO(new Bundle {
@@ -19,21 +19,17 @@ class DecoupledSpec extends ChiselFlatSpec {
1919
}
2020

2121
"Decoupled.map" should "apply a function to a wrapped Data" in {
22-
val chirrtl = ChiselStage
23-
.emitCHIRRTL(new Module {
24-
val enq = IO(Flipped(Decoupled(UInt(8.W))))
25-
val deq = IO(Decoupled(UInt(8.W)))
26-
deq <> enq.map(_ + 1.U)
27-
})
28-
29-
// Check for data assignment
30-
chirrtl should include("""node _deq_map_bits_T = add(enq.bits, UInt<1>(0h1)""")
31-
chirrtl should include("""node _deq_map_bits = tail(_deq_map_bits_T, 1)""")
32-
chirrtl should include("""connect _deq_map.bits, _deq_map_bits""")
33-
chirrtl should include("""connect deq, _deq_map""")
34-
35-
// Check for back-pressure (ready signal is driven in the opposite direction of bits + valid)
36-
chirrtl should include("""connect enq.ready, _deq_map.ready""")
22+
generateFirrtlAndFileCheck(new Module {
23+
val enq = IO(Flipped(Decoupled(UInt(8.W))))
24+
val deq = IO(Decoupled(UInt(8.W)))
25+
deq <> enq.map(_ + 1.U)
26+
})("""|CHECK: node [[node1:[a-zA-Z0-9_]+]] = add(enq.bits, UInt<1>(0h1))
27+
|CHECK: node [[node2:[a-zA-Z0-9_]+]] = tail([[node1]], 1)
28+
|CHECK: connect [[result:[a-zA-Z0-9_]+]].bits, [[node2]]
29+
|# Check for back-pressure (ready signal is driven in the opposite direction of bits + valid)
30+
|CHECK: connect enq.ready, [[result]].ready
31+
|CHECK: connect deq, [[result]]
32+
|""".stripMargin)
3733
}
3834

3935
"Decoupled.map" should "apply a function to a wrapped Bundle" in {

0 commit comments

Comments
 (0)