Commit 5f9c5e43 by Benjamin Tu Committed by Thierry Moreau

[VTA] [Chisel] Improved Data Gen, Added ALU Test (#3743)

* added alutest

* fix indent

* name change for cycle

* improved data gen and infra

* added alutest

* fix indent

* name change for cycle

* improved data gen and infra

* fix space

* fix indent

* fixes

* aluRef

* fix randomarary

* add

* Revert "add"

This reverts commit 87077daebbe055dee11f80e37da3a6291138e0f0.

* Revert "fix randomarary"

This reverts commit df386c1e660eb6ebcff1a1f905610573676f1589.

* Revert "aluRef"

This reverts commit 8665f0d4a7b12b796b2cb1ca6bf9cfe5613ee389.

* should fix dlmc-core
parent c3e9d0f3
......@@ -75,6 +75,7 @@ class AluReg(implicit p: Parameters) extends Module {
/** 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")
......
/*
* 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)
}
}
}
}
......@@ -22,6 +22,7 @@ package unittest
import chisel3._
import chisel3.iotesters.{Driver, TesterOptionsManager}
import unittest.util._
import vta.core._
import vta.util.config._
import vta.shell._
......@@ -45,7 +46,12 @@ object Launcher {
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 = {
......
......@@ -22,8 +22,8 @@ package unittest
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) {
......@@ -39,7 +39,7 @@ class TestMatrixVectorMultiplication(c: MatrixVectorMultiplication) extends Peek
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
}
......@@ -48,20 +48,21 @@ class TestMatrixVectorMultiplication(c: MatrixVectorMultiplication) extends Peek
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)
}
}
......@@ -79,13 +80,12 @@ class TestMatrixVectorMultiplication(c: MatrixVectorMultiplication) extends Peek
// 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)
}
}
}
}
/*
* 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
}
}
/*
* 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) }
}
}
......@@ -17,7 +17,7 @@
* under the License.
*/
package unittest
package unittest.util
// taken from https://github.com/freechipsproject/chisel-testers
import scala.collection.mutable.ArrayBuffer
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment