Skip to content

Commit

Permalink
[VTA] [Chisel] Added Chisel Module Unit Test Infrastructure (apache#3698
Browse files Browse the repository at this point in the history
)

* added wholething

* changed build and makefile
  • Loading branch information
BenjaminTu authored and wweic committed Sep 6, 2019
1 parent c18d451 commit 2f6f815
Show file tree
Hide file tree
Showing 6 changed files with 277 additions and 3 deletions.
4 changes: 4 additions & 0 deletions vta/hardware/chisel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ vta_dir = $(abspath ../../)
tvm_dir = $(abspath ../../../)
verilator_build_dir = $(vta_dir)/$(BUILD_NAME)/verilator
chisel_build_dir = $(vta_dir)/$(BUILD_NAME)/chisel
test_name = mvm

verilator_opt = --cc
verilator_opt += +define+RANDOMIZE_GARBAGE_ASSIGN
Expand Down Expand Up @@ -111,6 +112,9 @@ verilog_test: $(chisel_build_dir)/$(TOP_TEST).$(CONFIG).v
$(chisel_build_dir)/$(TOP_TEST).$(CONFIG).v:
sbt 'runMain vta.$(config_test) --target-dir $(chisel_build_dir) --top-name $(TOP_TEST).$(CONFIG)'

test:
sbt 'test:runMain unittest.Launcher $(test_name)'

clean:
-rm -rf target project/target project/project

Expand Down
30 changes: 30 additions & 0 deletions vta/hardware/chisel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
<!--- or more contributor license agreements. See the NOTICE file -->
<!--- distributed with this work for additional information -->
<!--- regarding copyright ownership. The ASF licenses this file -->
<!--- to you under the Apache License, Version 2.0 (the -->
<!--- "License"); you may not use this file except in compliance -->
<!--- with the License. You may obtain a copy of the License at -->

<!--- http://www.apache.org/licenses/LICENSE-2.0 -->

<!--- Unless required by applicable law or agreed to in writing, -->
<!--- software distributed under the License is distributed on an -->
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
<!--- KIND, either express or implied. See the License for the -->
<!--- specific language governing permissions and limitations -->
<!--- under the License. -->

VTA in Chisel
===================================================
For contributors who wants to test a chisel module:

- You can add your test files in `src/test/scala/unitttest`
- Add your test name and tests to the `test` object in `src/test/scala/unitttest/Launcher.scala`
- Check out the provided sample test `mvm` which tests the MatrixVectorComputation module
in `src/main/scala/core/TensorGemm.scala`

- Running unit tests: `make test test_name=your_own test_name`



10 changes: 7 additions & 3 deletions vta/hardware/chisel/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,13 @@ resolvers ++= Seq(
Resolver.sonatypeRepo("snapshots"),
Resolver.sonatypeRepo("releases"))

libraryDependencies ++= Seq(
"edu.berkeley.cs" %% "chisel3" % "3.1.7",
)
val defaultVersions = Map(
"chisel3" -> "3.1.7",
"chisel-iotesters" -> "[1.2.5,1.3-SNAPSHOT["
)

libraryDependencies ++= Seq("chisel3","chisel-iotesters").map {
dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) }

scalacOptions ++= scalacOptionsVersion(scalaVersion.value)
javacOptions ++= javacOptionsVersion(scalaVersion.value)
54 changes: 54 additions & 0 deletions vta/hardware/chisel/src/test/scala/unittest/Launcher.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package unittest
// taken from https://github.com/freechipsproject/chisel-testers

import chisel3._
import chisel3.iotesters.{Driver, TesterOptionsManager}
import vta.core._
import vta.util.config._
import vta.shell._

class TestConfig extends Config(new CoreConfig ++ new PynqConfig)

/* Launcher.
*
* The Launcher object includes a test list for the TestRunner to check.
* Users can utilize this Launcher to run custom tests.
*
* How to Use:
* When the user input: sbt 'test:runMain unittest.Launcher mvm'
* the TestRunner will look for 'mvm' in the map and executes the
* test that 'mvm' is mapped to
*/
object Launcher {
implicit val p: Parameters = new TestConfig
val tests = Map(
"mvm" -> { (manager: TesterOptionsManager) =>
Driver.execute(() => new MatrixVectorMultiplication, manager) {
(c) => new TestMatrixVectorMultiplication(c)
}
}
)

def main(args: Array[String]): Unit = {
TestRunner(tests, args)
}
}
91 changes: 91 additions & 0 deletions vta/hardware/chisel/src/test/scala/unittest/MvmTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package unittest

import chisel3._
import chisel3.util._
import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}
import scala.util.Random
import scala.math.pow
import vta.core._

class TestMatrixVectorMultiplication(c: MatrixVectorMultiplication) extends PeekPokeTester(c) {

/* mvm_ref
*
* This is a software function that computes dot product with a programmable shift
* This is used as a reference for the hardware
*/
def mvm_ref(inp: Array[Int], wgt: Array[Array[Int]], shift: Int) : Array[Int] = {
val size = inp.length
val res = Array.fill(size) {0}
for (i <- 0 until size) {
var dot = 0
for (j <- 0 until size) {
dot += wgt(i)(j) * inp(j)
}
res(i) = dot * pow(2, shift).toInt
}
return res
}

val cycles = 5
for (i <- 0 until cycles) {
val r = new Random
// generate random data based on config bits
val in_a = Array.fill(c.size) { r.nextInt(pow(2, c.inpBits).toInt) - pow(2, c.inpBits-1).toInt}
val in_b = Array.fill(c.size, c.size) { r.nextInt(pow(2, c.wgtBits).toInt) - pow(2, c.wgtBits-1).toInt}
val res = mvm_ref(in_a, in_b, 0)
val inpMask = (pow(2, c.inpBits) - 1).toLong
val wgtMask = (pow(2, c.wgtBits) - 1).toLong
val accMask = (pow(2, c.accBits) - 1).toLong

for (i <- 0 until c.size) {
poke(c.io.inp.data.bits(0)(i), in_a(i) & inpMask)
poke(c.io.acc_i.data.bits(0)(i), 0)
for (j <- 0 until c.size) {
poke(c.io.wgt.data.bits(i)(j), in_b(i)(j) & wgtMask)
}
}

poke(c.io.reset, 0)

poke(c.io.inp.data.valid, 1)
poke(c.io.wgt.data.valid, 1)
poke(c.io.acc_i.data.valid, 1)

step(1)

poke(c.io.inp.data.valid, 0)
poke(c.io.wgt.data.valid, 0)
poke(c.io.acc_i.data.valid, 0)

// wait for valid signal
while (peek(c.io.acc_o.data.valid) == BigInt(0)) {
step(1) // advance clock
}
if (peek(c.io.acc_o.data.valid) == BigInt(1)) {
for (i <- 0 until c.size) {
expect(c.io.acc_o.data.bits(0)(i), res(i) & accMask)
}
}
}

}
91 changes: 91 additions & 0 deletions vta/hardware/chisel/src/test/scala/unittest/TestRunner.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package unittest
// taken from https://github.com/freechipsproject/chisel-testers

import scala.collection.mutable.ArrayBuffer
import chisel3.iotesters._

object TestRunner {

def apply(testMap: Map[String, TesterOptionsManager => Boolean], args: Array[String]): Unit = {
var successful = 0
val errors = new ArrayBuffer[String]

val optionsManager = new TesterOptionsManager()
optionsManager.doNotExitOnHelp()

optionsManager.parse(args)

val programArgs = optionsManager.commonOptions.programArgs

if(programArgs.isEmpty) {
println("Available tests")
for(x <- testMap.keys) {
println(x)
}
println("all")
System.exit(0)
}

val testsToRun = if(programArgs.exists(x => x.toLowerCase() == "all")) {
testMap.keys
}
else {
programArgs
}

for(testName <- testsToRun) {
testMap.get(testName) match {
case Some(test) =>
println(s"Starting $testName")
try {
optionsManager.setTopName(testName)
optionsManager.setTargetDirName(s"test_run_dir/$testName")
if(test(optionsManager)) {
successful += 1
}
else {
errors += s"$testName: test error occurred"
}
}
catch {
case exception: Exception =>
exception.printStackTrace()
errors += s"$testName: exception ${exception.getMessage}"
case t : Throwable =>
errors += s"$testName: throwable ${t.getMessage}"
}
case _ =>
errors += s"Bad Test name: $testName"
}

}
if(successful > 0) {
println(s"Tests passing: $successful")
}
if(errors.nonEmpty) {
println("=" * 80)
println(s"Errors: ${errors.length}: in the following tests")
println(errors.mkString("\n"))
println("=" * 80)
}
}
}

0 comments on commit 2f6f815

Please sign in to comment.