--- /dev/null
+test_run_dir
/** Vector of pipeline ALUs */
class AluVector(implicit p: Parameters) extends Module {
+ val aluBits = p(CoreKey).accBits
val io = IO(new Bundle {
val opcode = Input(UInt(C_ALU_OP_BITS.W))
val acc_a = new TensorMasterData(tensorType = "acc")
--- /dev/null
+/*
+ * 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 unittest.util._
+import vta.core._
+
+class TestAluVector(c: AluVector) extends PeekPokeTester(c) {
+
+ /* alu_ref
+ *
+ * This is a software function used as a reference for the hardware
+ */
+ def aluRef(opcode: Int, a: Array[Int], b: Array[Int], width: Int) : Array[Int] = {
+ val size = a.length
+ val mask = helper.getMask(log2Ceil(width))
+ val res = Array.fill(size) {0}
+
+ if (opcode == 1) {
+ for (i <- 0 until size) {
+ res(i) = if (a(i) < b(i)) b(i) else a(i)
+ }
+ } else if (opcode == 2) {
+ for (i <- 0 until size) {
+ res(i) = a(i) + b(i)
+ }
+ } else if (opcode == 3) {
+ for (i <- 0 until size) {
+ res(i) = a(i) >> (b(i) & mask).toInt
+ }
+ } else if (opcode == 4) {
+ // HLS shift left by >> negative number
+ // b always < 0 when opcode == 4
+ for (i <- 0 until size) {
+ res(i) = a(i) << ((-1*b(i)) & mask)
+ }
+ } else {
+ // default
+ for (i <- 0 until size) {
+ res(i) = if (a(i) < b(i)) a(i) else b(i)
+ }
+ }
+ return res
+ }
+
+ val num_ops = ALU_OP_NUM
+ for (i <- 0 until num_ops) {
+ // generate data based on bits
+ val bits = c.aluBits
+ val dataGen = new RandomArray(c.blockOut, bits)
+ val op = i
+ val in_a = dataGen.any
+ val in_b = if (op != 4) dataGen.any else dataGen.negative
+ val mask = helper.getMask(bits)
+ val res = aluRef(op, in_a, in_b, bits)
+
+ for (i <- 0 until c.blockOut) {
+ poke(c.io.acc_a.data.bits(0)(i), in_a(i) & mask)
+ poke(c.io.acc_b.data.bits(0)(i), in_b(i) & mask)
+ }
+ poke(c.io.opcode, op)
+
+ poke(c.io.acc_a.data.valid, 1)
+ poke(c.io.acc_b.data.valid, 1)
+ poke(c.io.acc_y.data.valid, 1)
+
+ step(1)
+
+ poke(c.io.acc_a.data.valid, 0)
+ poke(c.io.acc_b.data.valid, 0)
+ poke(c.io.acc_y.data.valid, 0)
+
+ // wait for valid signal
+ while (peek(c.io.acc_y.data.valid) == BigInt(0)) {
+ step(1) // advance clock
+ }
+ if (peek(c.io.acc_y.data.valid) == BigInt(1)) {
+ for (i <- 0 until c.blockOut) {
+ expect(c.io.acc_y.data.bits(0)(i), res(i) & mask)
+ }
+ }
+ }
+}
import chisel3._
import chisel3.iotesters.{Driver, TesterOptionsManager}
+import unittest.util._
import vta.core._
import vta.util.config._
import vta.shell._
Driver.execute(() => new MatrixVectorMultiplication, manager) {
(c) => new TestMatrixVectorMultiplication(c)
}
- }
+ },
+ "alu" -> { (manager: TesterOptionsManager) =>
+ Driver.execute(() => new AluVector, manager) {
+ (c) => new TestAluVector(c)
+ }
+ }
)
def main(args: Array[String]): Unit = {
import chisel3._
import chisel3.util._
import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}
-import scala.util.Random
import scala.math.pow
+import unittest.util._
import vta.core._
class TestMatrixVectorMultiplication(c: MatrixVectorMultiplication) extends PeekPokeTester(c) {
for (i <- 0 until size) {
var dot = 0
for (j <- 0 until size) {
- dot += wgt(i)(j) * inp(j)
+ dot += wgt(i)(j) * inp(j)
}
res(i) = dot * pow(2, shift).toInt
}
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}
+ // generate data based on bits
+ val inpGen = new RandomArray(c.size, c.inpBits)
+ val wgtGen = new RandomArray(c.size, c.wgtBits)
+ val in_a = inpGen.any
+ val in_b = Array.fill(c.size) { wgtGen.any }
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
+ val inpMask = helper.getMask(c.inpBits)
+ val wgtMask = helper.getMask(c.wgtBits)
+ val accMask = helper.getMask(c.accBits)
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.wgt.data.bits(i)(j), in_b(i)(j) & wgtMask)
}
}
// wait for valid signal
while (peek(c.io.acc_o.data.valid) == BigInt(0)) {
- step(1) // advance clock
+ 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)
- }
+ for (i <- 0 until c.size) {
+ expect(c.io.acc_o.data.bits(0)(i), res(i) & accMask)
+ }
}
}
-
}
--- /dev/null
+/*
+ * 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.util
+
+import scala.math.pow
+
+object helper {
+ def getMask(bits: Int) : Long = {
+ if (bits <= 0) throw new IllegalArgumentException ("bits should be greater than 0")
+ return (pow(2, bits) - 1).toLong
+ }
+}
--- /dev/null
+/*
+ * 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.util
+
+import scala.util.Random
+import scala.math.pow
+
+class RandomArray(val len: Int, val bits: Int) {
+ val r = new Random
+ if (bits < 1) throw new IllegalArgumentException ("bits should be greater than 1")
+
+ def any : Array[Int] = {
+ return Array.fill(len) { r.nextInt(pow(2, bits).toInt) - pow(2, bits-1).toInt }
+ }
+
+ def positive : Array[Int] = {
+ return Array.fill(len) { r.nextInt(pow(2, bits-1).toInt) }
+ }
+
+ def negative : Array[Int] = {
+ return Array.fill(len) { 0 - r.nextInt(pow(2, bits-1).toInt) }
+ }
+}
* under the License.
*/
-package unittest
+package unittest.util
// taken from https://github.com/freechipsproject/chisel-testers
import scala.collection.mutable.ArrayBuffer