Parcourir la source

in 87 huey released this.. FORE!

master
peteraa il y a 6 ans
Parent
révision
b72d26883e
11 fichiers modifiés avec 1307 ajouts et 682 suppressions
  1. +624
    -682
      oppgavetekst.org
  2. +39
    -0
      src/main/scala/DotProd.scala
  3. +111
    -0
      src/main/scala/MatMul.scala
  4. +53
    -0
      src/main/scala/Matrix.scala
  5. +36
    -0
      src/main/scala/Vector.scala
  6. +109
    -0
      src/test/scala/DotProdSpec.scala
  7. +36
    -0
      src/test/scala/Example.scala
  8. +73
    -0
      src/test/scala/MatMulSpec.scala
  9. +101
    -0
      src/test/scala/MatrixSpec.scala
  10. +17
    -0
      src/test/scala/TestUtils.scala
  11. +108
    -0
      src/test/scala/VectorSpec.scala

+ 624
- 682
oppgavetekst.org
Fichier diff supprimé car celui-ci est trop grand
Voir le fichier


+ 39
- 0
src/main/scala/DotProd.scala Voir le fichier

@@ -0,0 +1,39 @@
package Ex0

import chisel3._
import chisel3.util.Counter

class DotProd(val elements: Int) extends Module {

val io = IO(
new Bundle {
val dataInA = Input(UInt(32.W))
val dataInB = Input(UInt(32.W))

val dataOut = Output(UInt(32.W))
val outputValid = Output(Bool())
}
)


/**
* Your code here
*/
val counter = Counter(elements)
val accumulator = RegInit(UInt(32.W), 0.U)
val product = io.dataInA * io.dataInB


/**
* LF
*/
when(counter.inc()){
io.outputValid := true.B
accumulator := 0.U
}.otherwise{
io.outputValid := false.B
accumulator := accumulator + product
}

io.dataOut := accumulator + product
}

+ 111
- 0
src/main/scala/MatMul.scala Voir le fichier

@@ -0,0 +1,111 @@
package Ex0

import chisel3._
import chisel3.util.Counter
import chisel3.experimental.MultiIOModule

class MatMul(val rowDimsA: Int, val colDimsA: Int) extends MultiIOModule {

val io = IO(
new Bundle {
val dataInA = Input(UInt(32.W))
val dataInB = Input(UInt(32.W))

val dataOut = Output(UInt(32.W))
val outputValid = Output(Bool())
}
)

val debug = IO(
new Bundle {
val ready = Output(Bool())
val dpValid = Output(Bool())

val rowSelA = Output(UInt(32.W))
val rowSelB = Output(UInt(32.W))
val colSel = Output(UInt(32.W))

val ma2dp = Output(UInt(32.W))
val mb2dp = Output(UInt(32.W))
}
)


/**
* Your code here
*/
val matrixA = Module(new Matrix(rowDimsA, colDimsA)).io
val matrixB = Module(new Matrix(rowDimsA, colDimsA)).io
val dotProdCalc = Module(new DotProd(colDimsA)).io

// matrixA.dataIn := 0.U
// matrixA.rowIdx := 0.U
// matrixA.colIdx := 0.U
// matrixA.readEnable := false.B

// matrixB.rowIdx := 0.U
// matrixB.colIdx := 0.U
// matrixB.dataIn := 0.U
// matrixB.readEnable := false.B

// dotProdCalc.dataInA := 0.U
// dotProdCalc.dataInB := 0.U

// io.dataOut := 0.U
// io.outputValid := false.B


/**
* LF
*/


// Get the data in
val ready = RegInit(false.B)

val (colCounter, colCounterWrap) = Counter(true.B, colDimsA)
val (rowSelA, rowSelAWrap) = Counter(colCounterWrap, rowDimsA)
val (rowSelB, _) = Counter(rowSelAWrap & ready, rowDimsA * colDimsA)

when(!ready){
ready := rowSelAWrap
matrixA.readEnable := true.B
matrixB.readEnable := true.B

matrixA.colIdx := colCounter
matrixA.rowIdx := rowSelA

matrixB.colIdx := colCounter
matrixB.rowIdx := rowSelA

}.otherwise{
matrixA.readEnable := false.B
matrixB.readEnable := false.B

matrixA.colIdx := colCounter
matrixA.rowIdx := rowSelB

matrixB.colIdx := colCounter
matrixB.rowIdx := rowSelA
}


matrixA.dataIn := io.dataInA
matrixB.dataIn := io.dataInB

dotProdCalc.dataInA := matrixA.dataOut
dotProdCalc.dataInB := matrixB.dataOut

io.dataOut := dotProdCalc.dataOut
io.outputValid := dotProdCalc.outputValid & ready

debug.ready := ready
debug.dpValid := dotProdCalc.outputValid
debug.rowSelA := rowSelA
debug.rowSelB := rowSelB
debug.colSel := colCounter

debug.ma2dp := matrixA.dataOut
debug.mb2dp := matrixB.dataOut

}

+ 53
- 0
src/main/scala/Matrix.scala Voir le fichier

@@ -0,0 +1,53 @@
package Ex0

import chisel3._

// This import statement makes the scala vector invisible, reducing confusion
import scala.collection.immutable.{ Vector => _ }

class Matrix(val rowsDim: Int, val colsDim: Int) extends Module {

val io = IO(
new Bundle {
val colIdx = Input(UInt(32.W))
val rowIdx = Input(UInt(32.W))
val dataIn = Input(UInt(32.W))
val readEnable = Input(Bool())

val dataOut = Output(UInt(32.W))
}
)

/**
* Your code here
*/

// Creates a vector of zero-initialized registers
val rows = Vec.fill(rowsDim)(Module(new Vector(colsDim)).io)

// placeholders
io.dataOut := 0.U
for(ii <- 0 until rowsDim){
rows(ii).dataIn := 0.U
rows(ii).readEnable := false.B
rows(ii).idx := 0.U
}


/**
* LF
*/
for(ii <- 0 until rowsDim){

rows(ii).dataIn := io.dataIn
rows(ii).idx := io.colIdx

when(ii.U === io.rowIdx){
rows(ii).readEnable := io.readEnable
}.otherwise{
rows(ii).readEnable := false.B
}
}
io.dataOut := rows(io.rowIdx).dataOut

}

+ 36
- 0
src/main/scala/Vector.scala Voir le fichier

@@ -0,0 +1,36 @@
package Ex0

import chisel3._


class Vector(val elements: Int) extends Module {

val io = IO(
new Bundle {
val idx = Input(UInt(32.W))
val dataIn = Input(UInt(32.W))
val readEnable = Input(Bool())

val dataOut = Output(UInt(32.W))
}
)

/**
* Your code here
*/

// Creates a vector of zero-initialized registers
val contents = RegInit(VecInit(List.fill(elements)(0.U(32.W))))

// placeholder
io.dataOut := 0.U


/**
* LF
*/
io.dataOut := contents(io.idx)
when(io.readEnable){
contents(io.idx) := io.dataIn
}
}

+ 109
- 0
src/test/scala/DotProdSpec.scala Voir le fichier

@@ -0,0 +1,109 @@
package Ex0

import chisel3._
import chisel3.iotesters.PeekPokeTester
import org.scalatest.{Matchers, FlatSpec}
import TestUtils._

class DotProdSpec extends FlatSpec with Matchers {
import DotProdTests._

val elements = scala.util.Random.nextInt(5) + 2

behavior of "DotProd"

it should "Only signal valid output at end of calculation" in {
wrapTester(
chisel3.iotesters.Driver(() => new DotProd(elements)) { c =>
new SignalsWhenDone(c)
} should be(true)
)
}


it should "Calculate the correct output" in {
wrapTester(
chisel3.iotesters.Driver(() => new DotProd(elements)) { c =>
new CalculatesCorrectResult(c)
} should be(true)
)
}


it should "Calculate the correct output and signal when appropriate" in {
wrapTester(
chisel3.iotesters.Driver(() => new DotProd(elements)) { c =>
new CalculatesCorrectResultAndSignals(c)
} should be(true)
)
}
}

object DotProdTests {

class SignalsWhenDone(c: DotProd) extends PeekPokeTester(c) {

for(ii <- 0 until c.elements - 1){
expect(c.io.outputValid, false)
step(1)
}
expect(c.io.outputValid, true)
step(1)

for(ii <- 0 until c.elements - 1){
expect(c.io.outputValid, false)
step(1)
}
expect(c.io.outputValid, true)
step(1)
}


class CalculatesCorrectResult(c: DotProd) extends PeekPokeTester(c) {

val inputsA = List.fill(c.elements)(scala.util.Random.nextInt(10))
val inputsB = List.fill(c.elements)(scala.util.Random.nextInt(10))
val expectedOutput = (for ((a, b) <- inputsA zip inputsB) yield a * b) sum

for(ii <- 0 until c.elements){
poke(c.io.dataInA, inputsA(ii))
poke(c.io.dataInB, inputsB(ii))
if(ii == c.elements - 1)
expect(c.io.dataOut, expectedOutput)
step(1)
}
}


class CalculatesCorrectResultAndSignals(c: DotProd) extends PeekPokeTester(c) {

val inputsA = List.fill(c.elements)(scala.util.Random.nextInt(10))
val inputsB = List.fill(c.elements)(scala.util.Random.nextInt(10))
val expectedOutput = (for ((a, b) <- inputsA zip inputsB) yield a * b) sum

for(ii <- 0 until c.elements){
poke(c.io.dataInA, inputsA(ii))
poke(c.io.dataInB, inputsB(ii))
if(ii == c.elements - 1){
expect(c.io.dataOut, expectedOutput)
expect(c.io.outputValid, true)
}
else
expect(c.io.outputValid, false)
step(1)
}


for(ii <- 0 until c.elements){
poke(c.io.dataInA, inputsA(ii))
poke(c.io.dataInB, inputsB(ii))
if(ii == c.elements - 1){
expect(c.io.dataOut, expectedOutput)
expect(c.io.outputValid, true)
}
else
expect(c.io.outputValid, false)
step(1)
}
}
}

+ 36
- 0
src/test/scala/Example.scala Voir le fichier

@@ -174,3 +174,39 @@ class DelayTester(c: SimpleDelay) extends PeekPokeTester(c) {
expect(c.io.dataOut, input)
}
}

class DPCsimulatorSpec extends FlatSpec with Matchers {

case class DotProdCalculator(vectorLen: Int, timeStep: Int = 0, accumulator: Int = 0){
def update(inputA: Int, inputB: Int): (Int, Boolean, DotProdCalculator) = {
val product = inputA * inputB
if(((timeStep + 1) % vectorLen) == 0)
(accumulator + product, true, this.copy(timeStep = 0, accumulator = 0))
else
(accumulator + product, false, this.copy(timeStep = this.timeStep + 1, accumulator = accumulator + product))
}
}

val myDPC = DotProdCalculator(4)
val dpcStream = Stream.iterate((0, myDPC)){ case(ts, dpc) =>
val a = scala.util.Random.nextInt(4)
val b = scala.util.Random.nextInt(4)
val (output, valid, nextDPC) = dpc.update(a, b)
val validString = if(valid) "yes" else "no"
println(s"at timestep $ts:")
println(s"INPUTS:")
println(s"inputA: $a, inputB: $b")
println(s"OUTPUTS:")
println(s"output: $output, valid: $validString\n\n")

(ts + 1, nextDPC)
}.take(20)


behavior of "Dot product simulator"

it should "Be shoehorned into a test" in {
dpcStream.last
}
}


+ 73
- 0
src/test/scala/MatMulSpec.scala Voir le fichier

@@ -0,0 +1,73 @@
package Ex0

import chisel3._
import chisel3.iotesters.PeekPokeTester
import org.scalatest.{Matchers, FlatSpec}
import TestUtils._

class MatMulSpec extends FlatSpec with Matchers {
import MatMulTests._

val rowDims = scala.util.Random.nextInt(5) + 3
val colDims = scala.util.Random.nextInt(5) + 3


behavior of "MatMul"

it should "Do shit" in {
wrapTester(
chisel3.iotesters.Driver(() => new MatMul(rowDims, colDims)) { c =>
new FullMatMul(c)
} should be(true)
)
}
}

object MatMulTests {

class TestExample(c: MatMul) extends PeekPokeTester(c) {
val mA = genMatrix(c.rowDimsA, c.colDimsA)
val mB = genMatrix(c.rowDimsA, c.colDimsA)
val mC = matrixMultiply(mA, mB.transpose)


}

class FullMatMul(c: MatMul) extends PeekPokeTester(c) {

val mA = genMatrix(c.rowDimsA, c.colDimsA)
val mB = genMatrix(c.rowDimsA, c.colDimsA)
val mC = matrixMultiply(mA, mB.transpose)

println("Multiplying")
println(printMatrix(mA))
println("With")
println(printMatrix(mB.transpose))
println("Expecting")
println(printMatrix(mC))

// Input data
for(ii <- 0 until c.colDimsA * c.rowDimsA){

val rowInputIdx = ii / c.colDimsA
val colInputIdx = ii % c.colDimsA

poke(c.io.dataInA, mA(rowInputIdx)(colInputIdx))
poke(c.io.dataInB, mB(rowInputIdx)(colInputIdx))
expect(c.io.outputValid, false, "Valid output during initialization")

step(1)
}

// Perform calculation
for(ii <- 0 until (c.rowDimsA * c.rowDimsA)){
for(kk <- 0 until c.colDimsA - 1){
expect(c.io.outputValid, false, "Valid output mistimed")
step(1)
}
expect(c.io.outputValid, true, "Valid output timing is wrong")
expect(c.io.dataOut, mC(ii / c.rowDimsA)(ii % c.rowDimsA), "Wrong value calculated")
step(1)
}
}
}

+ 101
- 0
src/test/scala/MatrixSpec.scala Voir le fichier

@@ -0,0 +1,101 @@
package Ex0

import chisel3._
import chisel3.iotesters.PeekPokeTester
import org.scalatest.{Matchers, FlatSpec}
import TestUtils._

import scala.collection.immutable.{ Vector => _ }

class MatrixSpec extends FlatSpec with Matchers {
import MatrixTests._

behavior of "Matrix"

val rowDims = scala.util.Random.nextInt(5) + 3
val colDims = scala.util.Random.nextInt(5) + 3

it should "Update its contents" in {
wrapTester(
chisel3.iotesters.Driver(() => new Matrix(10,10)) { c =>
new UpdatesData(c)
} should be(true)
)
}


it should "Retain its contents when readEnable is low" in {
wrapTester(
chisel3.iotesters.Driver(() => new Matrix(10,10)) { c =>
new UpdatesData(c)
} should be(true)
)
}
}

object MatrixTests {

class UpdatesData(c: Matrix) extends PeekPokeTester(c) {

val inputs = List.fill(c.colsDim){
List.fill(c.rowsDim)(scala.util.Random.nextInt(20) + 1)
}

poke(c.io.readEnable, true)
for(col <- 0 until c.colsDim){
for(row <- 0 until c.rowsDim){
poke(c.io.colIdx, col)
poke(c.io.rowIdx, row)
poke(c.io.dataIn, inputs(col)(row))
step(1)
}
}

for(col <- 0 until c.colsDim){
for(row <- 0 until c.rowsDim){
poke(c.io.colIdx, col)
poke(c.io.rowIdx, row)
expect(c.io.dataOut, inputs(col)(row))
step(1)
}
}
}


class RetainsData(c: Matrix) extends PeekPokeTester(c) {

val inputs = List.fill(c.colsDim){
List.fill(c.rowsDim)(scala.util.Random.nextInt(20) + 1)
}

poke(c.io.readEnable, true)
for(col <- 0 until c.colsDim){
for(row <- 0 until c.rowsDim){
poke(c.io.colIdx, col)
poke(c.io.rowIdx, row)
poke(c.io.dataIn, inputs(col)(row))
step(1)
}
}

poke(c.io.readEnable, false)

for(col <- 0 until c.colsDim){
for(row <- 0 until c.rowsDim){
poke(c.io.colIdx, col)
poke(c.io.rowIdx, row)
poke(c.io.dataIn, 0)
step(1)
}
}

for(col <- 0 until c.colsDim){
for(row <- 0 until c.rowsDim){
poke(c.io.colIdx, col)
poke(c.io.rowIdx, row)
expect(c.io.dataOut, inputs(col)(row))
step(1)
}
}
}
}

+ 17
- 0
src/test/scala/TestUtils.scala Voir le fichier

@@ -6,6 +6,23 @@ import org.scalatest.{Matchers, FlatSpec}

object TestUtils {

def genMatrix(rows: Int, cols: Int) = List.fill(rows)(
List.fill(cols)(scala.util.Random.nextInt(5))
)

def printVector(v: List[Int]): String =
v.map(x => "%3d".format(x)).mkString("[",",","]")

def printMatrix(m: List[List[Int]]): String =
"\n" + m.map(printVector).mkString("\n")

def dotProduct(xs: List[Int], ys: List[Int]): Int =
(for ((x, y) <- xs zip ys) yield x * y) sum

def matrixMultiply(ma: List[List[Int]], mb: List[List[Int]]): List[List[Int]] =
ma.map(mav => mb.transpose.map(mbv => dotProduct(mav,mbv)))


def wrapTester(test: => Unit): Unit = {
try { test }
catch {


+ 108
- 0
src/test/scala/VectorSpec.scala Voir le fichier

@@ -0,0 +1,108 @@
package Ex0

import chisel3._
import chisel3.iotesters.PeekPokeTester
import org.scalatest.{Matchers, FlatSpec}
import TestUtils._

import scala.collection.immutable.{ Vector => _ }

class VectorSpec extends FlatSpec with Matchers {
import VectorTests._

val elements = scala.util.Random.nextInt(5) + 2

behavior of "Vector"

it should "Not read data when read enable is false" in {
wrapTester(
chisel3.iotesters.Driver(() => new Vector(elements)) { c =>
new ReadEnable(c)
} should be(true)
)
}

it should "Update its registers when read enable is true" in {
wrapTester(
chisel3.iotesters.Driver(() => new Vector(elements)) { c =>
new UpdatesData(c)
} should be(true)
)
}

it should "Retain its data once read enable is set to false" in {
wrapTester(
chisel3.iotesters.Driver(() => new Vector(elements)) { c =>
new UpdatesData(c)
} should be(true)
)
}
}

object VectorTests {

class ReadEnable(c: Vector) extends PeekPokeTester(c) {

poke(c.io.dataIn, 123)
poke(c.io.readEnable, false)

for(ii <- 0 until c.elements){
poke(c.io.idx, ii)
step(1)
expect(c.io.dataOut, 0)
}

poke(c.io.dataIn, 124)
for(ii <- 0 until c.elements){
poke(c.io.idx, ii)
step(1)
expect(c.io.dataOut, 0)
}
}


class UpdatesData(c: Vector) extends PeekPokeTester(c) {

poke(c.io.readEnable, true)

for(ii <- 0 until c.elements){
poke(c.io.idx, ii)
poke(c.io.dataIn, ii)
step(1)
}

for(ii <- 0 until c.elements){
poke(c.io.idx, ii)
expect(c.io.dataOut, ii)
step(1)
}
}


class RetainsData(c: Vector) extends PeekPokeTester(c) {

poke(c.io.readEnable, true)

for(ii <- 0 until c.elements){
poke(c.io.idx, ii)
poke(c.io.dataIn, ii)
step(1)
}

poke(c.io.readEnable, false)

for(ii <- 0 until c.elements){
poke(c.io.idx, ii)
expect(c.io.dataOut, ii)
step(1)
}


for(ii <- 0 until c.elements){
poke(c.io.idx, ii)
expect(c.io.dataOut, ii)
step(1)
}
}

}

Chargement…
Annuler
Enregistrer