|
- package Core
- import chisel3._
- import chisel3.core.Input
- import chisel3.iotesters.PeekPokeTester
- import utilz._
-
- /**
- The daisy multiplier creates two daisy grids, one transposed, and multiplies them.
- */
- class daisyMultiplier(dims: Dims, dataWidth: Int) extends Module {
-
- val io = IO(new Bundle {
-
- val dataInA = Input(UInt(dataWidth.W))
- val writeEnableA = Input(Bool())
-
- val dataInB = Input(UInt(dataWidth.W))
- val writeEnableB = Input(Bool())
-
- val dataOut = Output(UInt(dataWidth.W))
- val dataValid = Output(Bool())
- val done = Output(Bool())
- })
-
-
- /**
- Your implementation here
- */
- val rowCounter = RegInit(UInt(8.W), 0.U)
- val colCounter = RegInit(UInt(8.W), 0.U)
-
- val rowOutputCounter = RegInit(UInt(8.W), 0.U)
-
- val calculating = RegInit(Bool(), false.B)
- val accumulator = RegInit(UInt(8.W), 0.U)
-
- val resultReady = RegInit(Bool(), false.B)
-
-
- /**
- Following the same principle behind the the vector matrix multiplication, by
- NOT transposing the dimensions.
-
- When writing a multiplier for a 3x2 matrix it's implicit that this means a
- 3x2 matrix and 2x3, returning a 2x2 matrix. By not transposing the dimensions
- we get the same effect as in VecMat
- */
- val matrixA = Module(new daisyGrid(dims, dataWidth)).io
- val matrixB = Module(new daisyGrid(dims, dataWidth)).io
-
-
-
-
- matrixA.dataIn := io.dataInA
- matrixA.writeEnable := io.writeEnableA
-
- matrixB.dataIn := io.dataInB
- matrixB.writeEnable := io.writeEnableB
-
- ////////////////////////////////////////
- ////////////////////////////////////////
- /// Set up counter statemachine
- io.done := false.B
-
- when(colCounter === (dims.cols - 1).U){
- colCounter := 0.U
-
- when(rowCounter === (dims.rows - 1).U){
- rowCounter := 0.U
- calculating := true.B
-
- when(calculating === true.B){
-
- when(rowOutputCounter === (dims.rows - 1).U){
- io.done := true.B
- }.otherwise{
- rowOutputCounter := rowOutputCounter + 1.U
- }
-
- }
-
- }.otherwise{
- rowCounter := rowCounter + 1.U
- }
- }.otherwise{
- colCounter := colCounter + 1.U
- }
-
-
-
- ////////////////////////////////////////
- ////////////////////////////////////////
- /// set up reading patterns depending on if we are in calculating state or not
- when(calculating === true.B){
- matrixA.rowSelect := rowOutputCounter
- }.otherwise{
- matrixA.rowSelect := rowCounter
- }
-
- matrixB.rowSelect := rowCounter
-
-
-
- ////////////////////////////////////////
- ////////////////////////////////////////
- /// when we're in calculating mode, check if we have valid output
- resultReady := false.B
- io.dataValid := false.B
- when(calculating === true.B){
- when(colCounter === (dims.cols - 1).U){
- resultReady := true.B
- }
- }
-
-
- ////////////////////////////////////////
- ////////////////////////////////////////
- /// when we've got a result ready we need to flush the accumulator
- when(resultReady === true.B){
- // To flush our accumulator we simply disregard previous state
- accumulator := (matrixA.dataOut*matrixB.dataOut)
- io.dataValid := true.B
- }.otherwise{
- accumulator := accumulator + (matrixA.dataOut*matrixB.dataOut)
- }
- io.dataOut := accumulator
- }
|