From fe41b8655d721876c9130f756a04a9664a97a4f9 Mon Sep 17 00:00:00 2001 From: "Fangrui.Liu" Date: Sat, 17 Feb 2024 19:51:51 +0800 Subject: [PATCH] refactored with new docs --- Makefile | 2 +- README.md | 2 + docs/images/neural_core.png | Bin 0 -> 87053 bytes docs/implementations/NeuralCore.md | 48 ++++++++++ docs/implementations/ProcessingElement.md | 20 ++--- docs/index.md | 9 +- mkdocs.yml | 3 + src/main/scala/ncore/cu/controlUnit.scala | 28 ++++++ src/main/scala/ncore/neuralCore.scala | 63 +++++++++++++ .../{procElem => ncore/pe}/procElem.scala | 20 ++--- src/main/scala/npu/npu.scala | 14 ++- .../scala/systolicArray/systolicArray.scala | 83 ------------------ .../SASpec.scala => ncore/CoreSpec.scala} | 68 +++----------- src/test/scala/ncore/cu/CUSpec.scala | 38 ++++++++ .../scala/{procElem => ncore/pe}/PESpec.scala | 20 ++--- src/test/scala/utils/printHelper.scala | 31 +++++++ 16 files changed, 257 insertions(+), 192 deletions(-) create mode 100644 docs/images/neural_core.png create mode 100644 docs/implementations/NeuralCore.md create mode 100644 src/main/scala/ncore/cu/controlUnit.scala create mode 100644 src/main/scala/ncore/neuralCore.scala rename src/main/scala/{procElem => ncore/pe}/procElem.scala (56%) delete mode 100644 src/main/scala/systolicArray/systolicArray.scala rename src/test/scala/{systolicArray/SASpec.scala => ncore/CoreSpec.scala} (65%) create mode 100644 src/test/scala/ncore/cu/CUSpec.scala rename src/test/scala/{procElem => ncore/pe}/PESpec.scala (75%) create mode 100644 src/test/scala/utils/printHelper.scala diff --git a/Makefile b/Makefile index a230762..fc4f05f 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ push-image-arm64: docker push fangruil/chisel-dev:arm64-${VER} docs: - pip3 install markdown-wavedrom mkdocs mkdocs-material python-markdown-math + pip3 install markdown-wavedrom mkdocs mkdocs-material python-markdown-math mkdocs-mermaid2-plugin mkdocs serve clean: diff --git a/README.md b/README.md index dcaa0d5..9efc23d 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ [![Documentation Status](https://readthedocs.org/projects/chisel-opennpu/badge/?version=latest)](https://chisel-opennpu.readthedocs.io/en/latest/?badge=latest) +Docs: https://chisel-opennpu.readthedocs.io + This is a chisel workbench designed for someone who like docker containers and vscode dev container plugin. DEVELOP IN PROGRESS. COMMERCIAL USE IS NOT ALLOWED. diff --git a/docs/images/neural_core.png b/docs/images/neural_core.png new file mode 100644 index 0000000000000000000000000000000000000000..5e3c40b07f9315498cf96aa332e2644fc2f279cf GIT binary patch literal 87053 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 qGgSXq82s-eOq&&=Vrkebj^oz8)z)QK*qK5C1 + + + +The overall architecture of the proposed Neural Core will look like a multi-layered 3D grid. If you look along z-axis, you will find them forming a pipeline. + +```mermaid +graph LR + subgraph I[Scratch Pad Memory] + C[SPM inbound] + F[SPM outbound] + end + + G[DMA] + + subgraph Neural Core + A[CU] + B[i-MMU] + D[PE] + E[o-MMU] + end + + + B --> |addr| C + C --> |data| B + A --> |ctrl| B + A --> |i-base-addr| B + B --> |data| D + A --> |ctrl| D + D --> |data| E + A --> |ctrl| E + E --> |addr| F + E --> |data| F + A --> |o-base-addr| E + I <--> G +``` + +Above is the pipeline of a Neural Unit (NU), which is an element of the processing element pipeline in the Neural Core. They can organize as systolic arrays or parallelized thread cores. + +This flexible architecture is managed by MMU, where all the data flow is controlled. To reduce the number of running transistors, we fused the systolic design with a parallelism design. All $\mu$-CU and i-$\mu$MMU will have a stair-like scheduling characteristics. Though this design choice may lead to high latency, I think it is still quite efficient: It preserves high throughput with fair amount of registers and arithmetic units. Of course you can have a multiplexed control set to manage this grid, but that will have more overhead. For example, you need a large piece of logic to implement the parallelism and another one to avoid bubbles in Neural Units. + +An Neural Processing Unit (NPU) can have multiple Neural Cores (NCore). Each Neural Core has a 2 dimensional grid of Neural Uint (NU). Each Neural Unit has its own micro-CU ($\mu$-CU), micro-MMU for both input and output(i-$\mu$MMU/o-$\mu$MMU) and [processing element (PE)](ProcessingElement.md). Having large registers that hold the matrix is impossible. So the design follows other NPU designs, using a Scratch Pad Memory to store input and output data. Each $\mu$MMU is directly connected to SPM to obtain a instant access to the data. \ No newline at end of file diff --git a/docs/implementations/ProcessingElement.md b/docs/implementations/ProcessingElement.md index 2a4e277..cabc09a 100644 --- a/docs/implementations/ProcessingElement.md +++ b/docs/implementations/ProcessingElement.md @@ -1,16 +1,16 @@ # Processing Element ```ascii_art - ACCUM TOP + ACCUM IN_B \ | \ | \___v___ | Proc | - LEFT ---->| Elem |-----> RIGHT - ¯¯¯|¯¯¯\ - | \ - v \ - BOTTOM OUT (to TLB mapped memory) + IN_A ---->| Elem | + ¯¯¯|¯¯¯ + | + v + OUT (to TLB mapped memory) ``` Processing Element is the fundamental element in systolic array. This is a basic implementation of a 2D PE for 2D systolic array or DSP grid. @@ -22,11 +22,9 @@ PE component will only accumulate the result if the `ACCUM` is high. This is eff wavedrom ( { signal: [ { name: "clk", wave:"P......", period: 4 }, - { name: "top_in", wave: "x====xx", data:["top_1", "top_2", "top_3", "top_4"], period: 4}, - { name: "left_in", wave: "x====xx", data:["left_1", "left_2", "left_3", "left_4"], period: 4}, + { name: "in_a", wave: "x====xx", data:["a_1", "a_2", "a_3", "a_4"], period: 4}, + { name: "in_b", wave: "x====xx", data:["b_1", "b_2", "b_3", "b_4"], period: 4}, { name: "accu", wave: "1...01.", period: 4}, - { name: "right_out", wave: "xx====x", data:["top_1", "top_2", "top_3", "top_4"], period: 4}, - { name: "bottom_out", wave: "xx====x", data:["left_1", "left_2", "left_3", "left_4"], period: 4}, - { name: "out", wave: "xx====x", data:["prod1=top_1*left_1", "prod_1 + top_2 * left_2", "prod_3=top_3 * left_3", "prod_3 + top_4 * left_4"], period: 4}, + { name: "out", wave: "xx====x", data:["prod1=a_1*b_1", "prod_1 + a_2 * b_2", "prod_3=a_3 * b_3", "prod_3 + a_4 * b_4"], period: 4}, ] } ) diff --git a/docs/index.md b/docs/index.md index 2b04404..d711efe 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,14 +4,17 @@ This is an open-source neural processing unit implementation in Chisel3. Specifically, this NPU is targeted at to be integerated to a low-power and edge-oriented SoC systems. So all design choices are facing those demands. +You can check the source code on [GitHub](https://github.com/mpskex/chisel-npu). + For overall chip design, you may find [the FullChipDesign website](https://www.fullchipdesign.com/) pretty helpful there. -## Designs +## ISA Designs - [Instructions](designs/01.isa.md) - [Memory](designs/02.memory.md) - [Buses](designs/03.bus.md) ## Implementation Details -- [Processing Element (PE)](implementations/ProcessingElement.md) -- [Systolic Array (SA)](implementations/SystolicArray.md) \ No newline at end of file +- [Neural Core (NCore)](implementations/NeuralCore.md) + - [Processing Element (PE)](implementations/ProcessingElement.md) + - [Systolic Array (SA)](implementations/SystolicArray.md) \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 69dcd77..7627440 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -4,6 +4,9 @@ repo_name: Chisel NPU theme: name: material +plugins: + - search + - mermaid2 markdown_extensions: - admonition diff --git a/src/main/scala/ncore/cu/controlUnit.scala b/src/main/scala/ncore/cu/controlUnit.scala new file mode 100644 index 0000000..d71189f --- /dev/null +++ b/src/main/scala/ncore/cu/controlUnit.scala @@ -0,0 +1,28 @@ +// See README.md for license details +package ncore.cu + +import chisel3._ + +/** + * Control unit also uses systolic array to pass instructions + */ +class ControlUnit(val n: Int = 8, val ctrl_width: Int = 8) extends Module { + val io = IO(new Bundle { + val cbus_in = Input(UInt(ctrl_width.W)) + val cbus_out = Output(Vec(n * n, UInt(ctrl_width.W))) + }) + // Assign each element with diagnal control signal + val reg = RegInit(VecInit(Seq.fill(2*n-1)(0.U(ctrl_width.W)))) + + // 1D systolic array for control + reg(0) := io.cbus_in + for(i<- 1 until 2*n-1){ + reg(i) := reg(i-1) + } + // Boardcast to all elements in the array + for(i <- 0 until n){ + for(j <- 0 until n){ + io.cbus_out(n*i+j) := reg(i+j) + } + } +} \ No newline at end of file diff --git a/src/main/scala/ncore/neuralCore.scala b/src/main/scala/ncore/neuralCore.scala new file mode 100644 index 0000000..3ef0eb9 --- /dev/null +++ b/src/main/scala/ncore/neuralCore.scala @@ -0,0 +1,63 @@ +// See README.md for license details +package ncore + +import chisel3._ + +/** + * This is the neural core design + */ + class NeuralCore(val n: Int = 8, val nbits: Int = 8, val ctrl_width: Int = 8) extends Module { + val io = IO(new Bundle { + val vec_a = Input(Vec(n, UInt(nbits.W))) // vector `a` is the left input + val vec_b = Input(Vec(n, UInt(nbits.W))) // vector `b` is the top input + val ctrl = Input(UInt(ctrl_width.W)) + val out = Output(Vec(n * n, UInt((2 * nbits + 12).W))) + }) + + // Create n x n pe blocks + val pe_io = VecInit(Seq.fill(n * n) {Module(new pe.PE(nbits)).io}) + // Create 2d register for horizontal & vertical + val pe_reg_h = RegInit(VecInit(Seq.fill((n - 1) * n)(0.U(nbits.W)))) + val pe_reg_v = RegInit(VecInit(Seq.fill((n - 1) * n)(0.U(nbits.W)))) + + // we use systolic array to pipeline the instructions + // this will avoid bubble and inst complexity + // while simplifying design with higher efficiency + val ctrl_array = Module(new cu.ControlUnit(n, ctrl_width)) + ctrl_array.io.cbus_in := io.ctrl + + for (i <- 0 until n){ + for (j <- 0 until n) { + // ==== OUTPUT ==== + // pe array's output mapped to the matrix position + io.out(n * i + j) := pe_io(n * i + j).out + + // ==== INPUT ==== + // vertical + if (i==0) { + pe_io(j).in_b := io.vec_b(j) + } else { + pe_io(n * i + j).in_b := pe_reg_v(n * (i - 1) + j) + } + if (i < n - 1 && j < n) + pe_reg_v(n * i + j) := pe_io(n * i + j).in_b + + // horizontal + if (j==0) { + pe_io(n * i).in_a := io.vec_a(i) + } else { + pe_io(n * i + j).in_a := pe_reg_h((n - 1) * i + (j - 1)) + } + if (i < n && j < n - 1) + pe_reg_h((n - 1) * i + j) := pe_io(n * i + j).in_a + + // ==== CONTROL ==== + // Currently we only have one bit control + // which is `ACCUM` + // TODO: + // Add ALU control to pe elements + val ctrl = ctrl_array.io.cbus_out(n * i + j).asBools + pe_io(n * i + j).accum := ctrl(0) + } + } + } \ No newline at end of file diff --git a/src/main/scala/procElem/procElem.scala b/src/main/scala/ncore/pe/procElem.scala similarity index 56% rename from src/main/scala/procElem/procElem.scala rename to src/main/scala/ncore/pe/procElem.scala index 503e92d..ff1a662 100644 --- a/src/main/scala/procElem/procElem.scala +++ b/src/main/scala/ncore/pe/procElem.scala @@ -1,6 +1,6 @@ // See README.md for license details. -package procElem +package ncore.pe import chisel3._ @@ -12,10 +12,8 @@ class PE(val nbits: Int = 8) extends Module { val io = IO( new Bundle { val accum = Input(Bool()) - val top_in = Input(UInt(nbits.W)) - val left_in = Input(UInt(nbits.W)) - val bottom_out = Output(UInt((nbits).W)) - val right_out = Output(UInt((nbits).W)) + val in_a = Input(UInt(nbits.W)) + val in_b = Input(UInt(nbits.W)) // The register bandwith is optimized for large transformer // The lower bound of max cap matrix size is: // 2^12 x 2^12 = (4096 x 4096) @@ -23,19 +21,11 @@ class PE(val nbits: Int = 8) extends Module { }) val res = RegInit(0.U((nbits*2 + 12).W)) - val reg_h = RegInit(0.U(nbits.W)) - val reg_v = RegInit(0.U(nbits.W)) when (io.accum) { - res := res + (io.top_in * io.left_in) + res := res + (io.in_a * io.in_b) } .otherwise { - res := (io.top_in * io.left_in) + res := (io.in_a * io.in_b) } - - reg_v := io.top_in - reg_h := io.left_in - - io.bottom_out := reg_v - io.right_out := reg_h io.out := res } \ No newline at end of file diff --git a/src/main/scala/npu/npu.scala b/src/main/scala/npu/npu.scala index d31a0c8..2fba8a3 100644 --- a/src/main/scala/npu/npu.scala +++ b/src/main/scala/npu/npu.scala @@ -4,29 +4,25 @@ import chisel3._ import java.nio.file.{Paths, Files} import java.nio.charset.StandardCharsets import circt.stage.ChiselStage -import procElem.PE +import ncore.pe.PE class NPU extends Module { val nbits: Int = 8 val io = IO(new Bundle { - val top_in = Input(UInt(nbits.W)) - val left_in = Input(UInt(nbits.W)) + val in_a = Input(UInt(nbits.W)) + val in_b = Input(UInt(nbits.W)) val accum = Input(Bool()) - val bottom_out = Output(UInt((nbits*2).W)) - val right_out = Output(UInt((nbits*2).W)) val out = Output(UInt((nbits*2).W)) }) val pe = Module(new PE(8)) // get value when ready - pe.io.top_in := io.top_in - pe.io.left_in := io.left_in + pe.io.in_a := io.in_a + pe.io.in_b := io.in_b pe.io.accum := io.accum io.out := pe.io.out - io.bottom_out := pe.io.bottom_out - io.right_out := pe.io.right_out } object Main extends App { diff --git a/src/main/scala/systolicArray/systolicArray.scala b/src/main/scala/systolicArray/systolicArray.scala deleted file mode 100644 index 6656a21..0000000 --- a/src/main/scala/systolicArray/systolicArray.scala +++ /dev/null @@ -1,83 +0,0 @@ -// See README.md for license details -package systolicArray - -import chisel3._ -import procElem._ - -/** - * Control bus also uses systolic array to pass instructions - */ -class _ControlArray(val n: Int = 8, val ctrl_width: Int = 8) extends Module { - val io = IO(new Bundle { - val cbus_in = Input(UInt(ctrl_width.W)) - val cbus_out = Output(Vec(n * n, UInt(ctrl_width.W))) - }) - // Assign each element with diagnal control signal - val reg = RegInit(VecInit(Seq.fill(2*n-1)(0.U(ctrl_width.W)))) - - // 1D systolic array for control - reg(0) := io.cbus_in - for(i<- 1 until 2*n-1){ - reg(i) := reg(i-1) - } - // Boardcast to all elements in the array - for(i <- 0 until n){ - for(j <- 0 until n){ - io.cbus_out(n*i+j) := reg(i+j) - } - } -} - -/** - * This is the systolic array design - */ - class SystolicArray(val n: Int = 8, val nbits: Int = 8, val ctrl_width: Int = 8) extends Module { - val io = IO(new Bundle { - val vec_a = Input(Vec(n, UInt(nbits.W))) // vector `a` is the left input - val vec_b = Input(Vec(n, UInt(nbits.W))) // vector `b` is the top input - val ctrl = Input(UInt(ctrl_width.W)) - val out = Output(Vec(n * n, UInt((2 * nbits + 12).W))) - }) - - // Create n x n pe blocks - val pe_io = VecInit(Seq.fill(n * n) {Module(new PE(nbits)).io}) - - // we use systolic array to pipeline the instructions - // this will avoid bubble and inst complexity - // while simplifying design with higher efficiency - val ctrl_array = Module(new _ControlArray(n, ctrl_width)) - ctrl_array.io.cbus_in := io.ctrl - // for (i <- 0 until n * n) { - // pe_io(i).accum := io.ctrl(0) - // } - - for (i <- 0 until n){ - for (j <- 0 until n) { - // ==== OUTPUT ==== - // pe array's output mapped to the matrix position - io.out(n * i + j) := pe_io(n * i + j).out - - // ==== INPUT ==== - // vertical - if (i==0) { - pe_io(j).top_in := io.vec_b(j) - } else { - pe_io(n * i + j).top_in := pe_io(n * (i - 1) + j).bottom_out - } - // horizontal - if (j==0) { - pe_io(n * i).left_in := io.vec_a(i) - } else { - pe_io(n * i + j).left_in := pe_io(n * i + (j - 1)).right_out - } - - // ==== CONTROL ==== - // Currently we only have one bit control - // which is `ACCUM` - // TODO: - // Add ALU control to pe elements - val ctrl = ctrl_array.io.cbus_out(n * i + j).asBools - pe_io(n * i + j).accum := ctrl(0) - } - } - } \ No newline at end of file diff --git a/src/test/scala/systolicArray/SASpec.scala b/src/test/scala/ncore/CoreSpec.scala similarity index 65% rename from src/test/scala/systolicArray/SASpec.scala rename to src/test/scala/ncore/CoreSpec.scala index 7dc7a5d..0f80604 100644 --- a/src/test/scala/systolicArray/SASpec.scala +++ b/src/test/scala/ncore/CoreSpec.scala @@ -1,72 +1,26 @@ //// See README.md for license details. -package systolicArray +package ncore +import testUtil._ import scala.util.Random import chisel3._ import chiseltest._ import org.scalatest.flatspec.AnyFlatSpec import chisel3.experimental.BundleLiterals._ -class SASpec extends AnyFlatSpec with ChiselScalatestTester { +class CoreSpec extends AnyFlatSpec with ChiselScalatestTester { - def printMatrix(mat: Array[Int], n: Int): Unit = { - println("[") - for (i <- 0 until n) { - var _row = "" - for (j <- 0 until n) { - _row += mat(i * n + j).toString() + ", " - } - println("[" + _row + "],") - } - println("]") - } - - def printMatrixChisel(mat: chisel3.Vec[chisel3.UInt], n: Int): Unit = { - println("[") - for (i <- 0 until n) { - var _row = "" - for (j <- 0 until n) { - _row += mat(i * n + j).peekInt().toString() + ", " - } - println("[" + _row + "],") - } - println("]") - } - - "SA" should "control with a systolic array" in { - test(new _ControlArray(4)) { dut => - val _n = 4 - val rand = new Random - var history = new Array[Int](2 * _n - 1) - var prod = 0 - for (n <- 0 until 16) { - val _cbus_in = rand.between(0, 255) - history +:= _cbus_in - dut.io.cbus_in.poke(_cbus_in) - dut.clock.step() - history = history.slice(0, 2 * _n - 1) - println("Input tick @ " + n + ": " + _cbus_in) - for(i: Int <- 0 until _n){ - for(j:Int <- 0 until _n) { - dut.io.cbus_out(_n * i + j).expect(history(i + j)) - } - } - println("Control tick @ " + n + " : ") - this.printMatrixChisel(dut.io.cbus_out, _n) - } - } - } - - "SA" should "do a normal matrix multiplication" in { - test(new SystolicArray(4, 8)) { dut => + "NeuralCore" should "do a normal matrix multiplication" in { + test(new NeuralCore(4, 8)) { dut => + val print_helper = new testUtil.PrintHelper() val _n = 4 val rand = new Random val _mat_a = new Array[Int](_n * _n) val _mat_b = new Array[Int](_n * _n) val _expected = new Array[Int](_n * _n) var _res = new Array[Int](_n * _n) - + // random initialize the for (i <- 0 until _n * _n) { _mat_a(i) = rand.between(0, 255) @@ -84,11 +38,11 @@ class SASpec extends AnyFlatSpec with ChiselScalatestTester { // print the expected results println("===== MAT A =====") - this.printMatrix(_mat_a, _n) + print_helper.printMatrix(_mat_a, _n) println("===== MAT B =====") - this.printMatrix(_mat_b, _n) + print_helper.printMatrix(_mat_b, _n) println("+++++ MAT C +++++") - this.printMatrix(_expected, _n) + print_helper.printMatrix(_expected, _n) // systolic arrays has latency of 3 * _n - 2 for (i_tick <- 0 until 3 * _n - 2) { @@ -146,7 +100,7 @@ class SASpec extends AnyFlatSpec with ChiselScalatestTester { } } println("+++++ MAT C from HW ++++") - this.printMatrix(_res, _n) + print_helper.printMatrix(_res, _n) } } } \ No newline at end of file diff --git a/src/test/scala/ncore/cu/CUSpec.scala b/src/test/scala/ncore/cu/CUSpec.scala new file mode 100644 index 0000000..03c02a7 --- /dev/null +++ b/src/test/scala/ncore/cu/CUSpec.scala @@ -0,0 +1,38 @@ +//// See README.md for license details. + +package ncore.cu + +import testUtil._ +import scala.util.Random +import chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import chisel3.experimental.BundleLiterals._ + +class CUSpec extends AnyFlatSpec with ChiselScalatestTester { + + "CU" should "send control to 2D systolic array" in { + test(new ControlUnit(4)) { dut => + val print_helper = new testUtil.PrintHelper() + val _n = 4 + val rand = new Random + var history = new Array[Int](2 * _n - 1) + var prod = 0 + for (n <- 0 until 16) { + val _cbus_in = rand.between(0, 255) + history +:= _cbus_in + dut.io.cbus_in.poke(_cbus_in) + dut.clock.step() + history = history.slice(0, 2 * _n - 1) + println("Input tick @ " + n + ": " + _cbus_in) + for(i: Int <- 0 until _n){ + for(j:Int <- 0 until _n) { + dut.io.cbus_out(_n * i + j).expect(history(i + j)) + } + } + println("Control tick @ " + n + " : ") + print_helper.printMatrixChisel(dut.io.cbus_out, _n) + } + } + } +} \ No newline at end of file diff --git a/src/test/scala/procElem/PESpec.scala b/src/test/scala/ncore/pe/PESpec.scala similarity index 75% rename from src/test/scala/procElem/PESpec.scala rename to src/test/scala/ncore/pe/PESpec.scala index 9801962..bd9c3ae 100644 --- a/src/test/scala/procElem/PESpec.scala +++ b/src/test/scala/ncore/pe/PESpec.scala @@ -1,6 +1,6 @@ // See README.md for license details. -package procElem +package ncore.pe import scala.util.Random import chisel3._ @@ -18,12 +18,10 @@ class PESpec extends AnyFlatSpec with ChiselScalatestTester { for (n <- 0 until 128) { val _top_in_ = rand.between(0, 255) val _left_in_ = rand.between(0, 255) - dut.io.top_in.poke(_top_in_) - dut.io.left_in.poke(_left_in_) + dut.io.in_a.poke(_top_in_) + dut.io.in_b.poke(_left_in_) dut.io.accum.poke(true) dut.clock.step() - dut.io.bottom_out.expect(_top_in_) - dut.io.right_out.expect(_left_in_) prod = prod + _top_in_ * _left_in_ dut.io.out.expect(prod) println("Result tick @ " + n + ": " + dut.io.out.peekInt() + " with input top: " + _top_in_ + " and left: " + _left_in_) @@ -32,24 +30,20 @@ class PESpec extends AnyFlatSpec with ChiselScalatestTester { prod = 0 var _top_in_ = rand.between(1, 255) var _left_in_ = rand.between(1, 255) - dut.io.top_in.poke(_top_in_) - dut.io.left_in.poke(_left_in_) + dut.io.in_a.poke(_top_in_) + dut.io.in_b.poke(_left_in_) dut.io.accum.poke(false) dut.clock.step() - dut.io.bottom_out.expect(_top_in_) - dut.io.right_out.expect(_left_in_) prod = prod + _top_in_ * _left_in_ dut.io.out.expect(prod) println("Result tick @ new: " + dut.io.out.peekInt() + " with input top: " + _top_in_ + " and left: " + _left_in_) _top_in_ = rand.between(1, 255) _left_in_ = rand.between(1, 255) - dut.io.top_in.poke(_top_in_) - dut.io.left_in.poke(_left_in_) + dut.io.in_a.poke(_top_in_) + dut.io.in_b.poke(_left_in_) dut.io.accum.poke(true) dut.clock.step() - dut.io.bottom_out.expect(_top_in_) - dut.io.right_out.expect(_left_in_) prod = prod + _top_in_ * _left_in_ dut.io.out.expect(prod) println("Result tick @ new's next: " + dut.io.out.peekInt() + " with input top: " + _top_in_ + " and left: " + _left_in_) diff --git a/src/test/scala/utils/printHelper.scala b/src/test/scala/utils/printHelper.scala new file mode 100644 index 0000000..c520bda --- /dev/null +++ b/src/test/scala/utils/printHelper.scala @@ -0,0 +1,31 @@ + +package testUtil + +import chisel3._ +import chiseltest._ + +class PrintHelper(){ + def printMatrix(mat: Array[Int], n: Int): Unit = { + println("[") + for (i <- 0 until n) { + var _row = "" + for (j <- 0 until n) { + _row += mat(i * n + j).toString() + ", " + } + println("[" + _row + "],") + } + println("]") + } + + def printMatrixChisel(mat: chisel3.Vec[chisel3.UInt], n: Int): Unit = { + println("[") + for (i <- 0 until n) { + var _row = "" + for (j <- 0 until n) { + _row += mat(i * n + j).peekInt().toString() + ", " + } + println("[" + _row + "],") + } + println("]") + } +} \ No newline at end of file