| /* |
| * 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._ |
| import vta.util.config._ |
| |
| class TensorAluIndexGeneratorTester(c: TensorAluIndexGenerator, alu_use_imm : Int = 0) extends PeekPokeTester(c) { |
| |
| |
| val uop_begin = 0 |
| val uop_end = 2 |
| assert(uop_begin < uop_end) |
| |
| val lp_0 = 2 |
| val lp_1 = 3 |
| val dst_0 = 1*lp_1 |
| val src_0 = 2*lp_1 |
| val dst_1 = 1 |
| val src_1 = 2 |
| |
| poke(c.io.dec.reset, 0) |
| poke(c.io.dec.alu_use_imm, alu_use_imm) |
| poke(c.io.dec.uop_begin, uop_begin) |
| poke(c.io.dec.uop_end, uop_end) |
| poke(c.io.dec.lp_0, lp_0) |
| poke(c.io.dec.lp_1, lp_1) |
| poke(c.io.dec.dst_0, dst_0) |
| poke(c.io.dec.dst_1, dst_1) |
| poke(c.io.dec.src_0, src_0) |
| poke(c.io.dec.src_1, src_1) |
| // Don't need empty_0,{push,pop}_{next,prev},op |
| |
| |
| class Mocks { |
| val uop_indices = new scala.collection.mutable.Queue[BigInt] |
| val dst_indices = new scala.collection.mutable.Queue[BigInt] |
| val src_indices = new scala.collection.mutable.Queue[BigInt] |
| |
| def logical_step() { |
| step(1) |
| if (peek(c.io.valid) == 1) { |
| expect(c.io.uop_idx, uop_indices.dequeue()) |
| expect(c.io.dst_idx, dst_indices.dequeue()) |
| } |
| if (peek(c.io.src_valid) == 1) { |
| expect(c.io.src_idx, src_indices.dequeue()) |
| } |
| } |
| |
| def test_if_done() { |
| println(s"uop_indices remaining: ${uop_indices.size}") |
| println(s"dst_indices remaining: ${dst_indices.size}") |
| println(s"src_indices remaining: ${src_indices.size}") |
| assert(uop_indices.isEmpty) |
| assert(dst_indices.isEmpty) |
| assert(src_indices.isEmpty) |
| } |
| } |
| |
| val mocks = new Mocks |
| for { |
| cnt_o <- 0 until lp_0 |
| cnt_i <- 0 until lp_1 |
| uop_idx <- uop_begin until uop_end |
| } { |
| mocks.uop_indices.enqueue(uop_idx) |
| mocks.dst_indices.enqueue(dst_0*cnt_o + dst_1*cnt_i) |
| if (alu_use_imm == 0) { |
| mocks.src_indices.enqueue(src_0*cnt_o + src_1*cnt_i) |
| } |
| } |
| |
| poke(c.io.start, 1) |
| mocks.logical_step() |
| poke(c.io.start, 0) |
| |
| val end = (uop_end-uop_begin)*lp_0*lp_1 |
| var count = 0 |
| while(peek(c.io.last) == 0 && count < 10*end + 100) { |
| mocks.logical_step() |
| count += 1 |
| } |
| mocks.test_if_done() |
| step(1) |
| } |
| |
| class TensorAluIndexGenerator_0_Test extends GenericTest("TensorAluIndexGenerator_0", (p:Parameters) => |
| new TensorAluIndexGenerator()(p), (c:TensorAluIndexGenerator) => new TensorAluIndexGeneratorTester(c, 0)) |
| |
| class TensorAluIndexGenerator_1_Test extends GenericTest("TensorAluIndexGenerator_1", (p:Parameters) => |
| new TensorAluIndexGenerator()(p), (c:TensorAluIndexGenerator) => new TensorAluIndexGeneratorTester(c, 1)) |
| |
| class TensorAluPipelinedTester(c: TensorAlu) extends PeekPokeTester(c) { |
| poke(c.io.start, 0) |
| |
| val uop_begin = 0 |
| val uop_end = 1 |
| assert(uop_begin < uop_end) |
| val alu_use_imm = 1 |
| val lp_0 = 2 |
| val lp_1 = 3 |
| val dst_0 = 1*lp_1 |
| val src_0 = 2*lp_1 |
| val dst_1 = 1 |
| val src_1 = 2 |
| |
| val dst_offset = BigInt("000", 16) |
| val src_offset = BigInt("100", 16) |
| |
| val u0 = dst_offset |
| val u1 = src_offset |
| val u2 = 0 // if src_offset is big, some bits go here |
| |
| poke(c.io.dec.reset, 0) |
| poke(c.io.dec.alu_op, 2) // ADD or ADDI 1 |
| poke(c.io.dec.alu_imm, 1) |
| poke(c.io.dec.alu_use_imm, alu_use_imm) |
| poke(c.io.dec.uop_begin, uop_begin) |
| poke(c.io.dec.uop_end, uop_end) |
| poke(c.io.dec.lp_0, lp_0) |
| poke(c.io.dec.lp_1, lp_1) |
| poke(c.io.dec.dst_0, dst_0) |
| poke(c.io.dec.dst_1, dst_1) |
| poke(c.io.dec.src_0, src_0) |
| poke(c.io.dec.src_1, src_1) |
| |
| // Don't need empty_0,{push,pop}_{next,prev},op |
| |
| poke(c.io.uop.data.bits.u0, u0) |
| poke(c.io.uop.data.bits.u1, u1) |
| poke(c.io.uop.data.bits.u2, u2) |
| |
| require(c.io.acc.splitWidth == 1, "-F- Test doesnt support acc data access split") |
| require(c.io.acc.splitLength == 1, "-F- Test doesnt support acc data access split") |
| |
| val acc = IndexedSeq.tabulate(c.io.acc.rd(0).data.bits(0).size){ i => BigInt(i) } |
| for { lhs <- c.io.acc.rd(0).data.bits} { |
| poke(lhs, acc.reverse) |
| } |
| |
| class TensorMasterMock(tm: TensorMaster) { |
| poke(tm.rd(0).data.valid, 0) |
| var valid = peek(tm.rd(0).idx.valid) |
| def logical_step(v: Option[BigInt]) { |
| poke(tm.rd(0).data.valid, valid) |
| valid = peek(tm.rd(0).idx.valid) |
| for { x <- v} expect(tm.rd(0).idx.valid, x) |
| } |
| } |
| |
| class UopMasterMock(um: UopMaster) { |
| poke(um.data.valid, 0) |
| var valid = peek(um.idx.valid) |
| def logical_step(v: Option[BigInt]) { |
| poke(um.data.valid, valid) |
| valid = peek(um.idx.valid) |
| for { x <- v} expect(um.idx.valid, x) |
| } |
| } |
| |
| class Mocks { |
| val uop_mock = new UopMasterMock(c.io.uop) |
| val acc_mock = new TensorMasterMock(c.io.acc) |
| |
| val uop_indices = new scala.collection.mutable.Queue[BigInt] |
| val acc_indices = new scala.collection.mutable.Queue[BigInt] |
| val accout_indices = new scala.collection.mutable.Queue[BigInt] |
| val out_indices = new scala.collection.mutable.Queue[BigInt] |
| |
| def logical_step() { |
| step(1) |
| uop_mock.logical_step(None) |
| acc_mock.logical_step(None) |
| if (peek(c.io.uop.idx.valid) == 1) { |
| expect(c.io.uop.idx.bits, uop_indices.dequeue()) |
| } |
| if (peek(c.io.acc.rd(0).idx.valid) == 1) { |
| expect(c.io.acc.rd(0).idx.bits, acc_indices.dequeue()) |
| } |
| if (peek(c.io.acc.wr(0).valid) == 1) { |
| expect(c.io.acc.wr(0).bits.idx, accout_indices.dequeue()) |
| } |
| if (peek(c.io.out.wr(0).valid) == 1) { |
| expect(c.io.out.wr(0).bits.idx, out_indices.dequeue()) |
| } |
| } |
| |
| def test_if_done() { |
| println(s"uop_indices remaining: ${uop_indices.size}") |
| println(s"acc_indices remaining: ${acc_indices.size}") |
| println(s"accout_indices remaining: ${accout_indices.size}") |
| println(s"out_indices remaining: ${out_indices.size}") |
| assert(uop_indices.isEmpty) |
| assert(acc_indices.isEmpty) |
| assert(accout_indices.isEmpty) |
| assert(out_indices.isEmpty) |
| } |
| } |
| |
| val mocks = new Mocks |
| for { |
| cnt_o <- 0 until lp_0 |
| cnt_i <- 0 until lp_1 |
| uop_idx <- uop_begin until uop_end |
| } { |
| mocks.uop_indices.enqueue(uop_idx) |
| mocks.acc_indices.enqueue(src_offset + src_0*cnt_o + src_1*cnt_i) |
| mocks.accout_indices.enqueue(dst_offset + dst_0*cnt_o + dst_1*cnt_i) |
| mocks.out_indices.enqueue(dst_offset + dst_0*cnt_o + dst_1*cnt_i) |
| } |
| |
| poke(c.io.start, 0) |
| step(1) |
| poke(c.io.start, 1) |
| |
| var count = 0 |
| val end = (uop_end-uop_begin)*lp_0*lp_1 |
| |
| while (peek(c.io.done) == 0 && count < 10*end + 100) { |
| mocks.logical_step() |
| poke(c.io.start, 0) |
| count += 1 |
| } |
| expect(c.io.done, 1) |
| mocks.test_if_done() |
| } |
| |
| class TensorAluPipelinedTest extends GenericTest("TensorAluPipelined", (p:Parameters) => |
| new TensorAlu()(p), (c:TensorAlu) => new TensorAluPipelinedTester(c)) |