blob: befeaec92b79f0a8f74d624fb7662c2dde8cd517 [file] [log] [blame]
/*
* Copyright 2023 Google LLC
*
* Licensed 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 kelvin
import chisel3._
import chisel3.util._
object VDot {
// Conv2D
def apply(en: Bool, adata: UInt, bdata: UInt,
abias: UInt, bbias: UInt, asign: Bool, bsign: Bool): UInt = {
assert(abias.getWidth == 9)
assert(bbias.getWidth == 9)
assert(adata.getWidth == 32)
assert(bdata.getWidth == 32)
val mul = Wire(Vec(4, SInt(20.W)))
// input clamps
val adatac = MuxOR(en, adata)
val bdatac = MuxOR(en, bdata)
val abiasc = MuxOR(en, abias)
val bbiasc = MuxOR(en, bbias)
for (i <- 0 until 4) {
val as = adatac(8 * i + 7) & asign
val bs = bdatac(8 * i + 7) & bsign
val aval = Cat(as, adatac(8 * i + 7, 8 * i)).asSInt +& abiasc.asSInt
val bval = Cat(bs, bdatac(8 * i + 7, 8 * i)).asSInt +& bbiasc.asSInt
val mval = aval * bval
mul(i) := mval
assert(aval.getWidth == 10)
assert(bval.getWidth == 10)
assert(mval.getWidth == 20)
}
val dotp = (mul(0) +& mul(1)) +& (mul(2) +& mul(3))
val sdotp = Cat(MuxOR(dotp(21), ~0.U(10.W)), dotp)
assert(dotp.getWidth == 22)
assert(sdotp.getWidth == 32)
sdotp
}
// Depthwise
def apply(alu: Int, en: Bool, adata: Vec[UInt], bdata: Vec[UInt],
scalar: UInt): (UInt, UInt) = {
assert(adata.length == 3)
assert(bdata.length == 3)
assert(scalar.getWidth == 32)
val sparse = scalar(3,2)
val abias = scalar(20,12)
val asign = scalar(21)
val bbias = scalar(30,22)
val bsign = scalar(31)
val sparse0 = sparse === 0.U
val sparse1 = sparse === 1.U
val sparse2 = sparse === 2.U
val w = adata(0).getWidth
val cnt = w / 32
val dout0 = Wire(Vec(cnt, UInt(32.W)))
val dout1 = Wire(Vec(cnt, UInt(32.W)))
// Input clamps and dense/sparse swizzle.
val adatac = Wire(Vec(3, Vec(cnt, UInt(32.W))))
val bdatac = Wire(Vec(3, Vec(cnt, UInt(32.W))))
val abiasc = MuxOR(en, abias)
val bbiasc = MuxOR(en, bbias)
// Sparse 1 [n-1,n,n+1].
val adata1 = Wire(Vec(cnt + 2, UInt(32.W)))
if (true) {
val lsb = (cnt - 1) * 32
val msb = lsb + 32 - 1
adata1(0) := MuxOR(en && sparse1, adata(0)(msb,lsb))
}
for (i <- 0 until cnt) {
val lsb = i * 32
val msb = lsb + 32 - 1
adata1(i + 1) := MuxOR(en && sparse1, adata(1)(msb,lsb))
}
if (true) {
val lsb = 0
val msb = 31
adata1(cnt + 1) := MuxOR(en && sparse1, adata(2)(msb,lsb))
}
// Sparse 2 [n,n+1,n+2].
val adata2 = Wire(Vec(cnt + 2, UInt(32.W)))
for (i <- 0 until cnt) {
val lsb = i * 32
val msb = lsb + 32 - 1
adata2(i) := MuxOR(en && sparse2, adata(0)(msb,lsb))
}
for (i <- 0 until 2) {
val lsb = i * 32
val msb = lsb + 32 - 1
adata2(cnt + i) := MuxOR(en && sparse2, adata(1)(msb,lsb))
}
// vdot(a,b) for sparse[0,1,2].
for (j <- 0 until 3) {
for (i <- 0 until cnt) {
val lsb = i * 32
val msb = lsb + 32 - 1
val k = i + j
val adata0 = MuxOR(en && sparse0, adata(j)(msb,lsb))
adatac(j)(i) := adata0 | adata1(k) | adata2(k)
bdatac(j)(i) := MuxOR(en, bdata(j)(msb,lsb))
}
}
for (i <- 0 until cnt) {
val ad = VecInit(adatac(0)(i), adatac(1)(i), adatac(2)(i))
val bd = VecInit(bdatac(0)(i), bdatac(1)(i), bdatac(2)(i))
val (o0, o1) = dwlane(alu, en, ad, bd, abiasc, bbiasc, asign, bsign)
dout0(i) := o0
dout1(i) := o1
}
val out0 = dout0.asUInt
val out1 = dout1.asUInt
assert(out0.getWidth == w)
assert(out1.getWidth == w)
(out0, out1)
}
private def dwlane(alu: Int, en: Bool, adata: Vec[UInt], bdata: Vec[UInt],
abias: UInt, bbias: UInt, asign: Bool, bsign: Bool):
(UInt, UInt) = {
assert(adata.length == 3)
assert(bdata.length == 3)
assert(abias.getWidth == 9)
assert(bbias.getWidth == 9)
for (i <- 0 until 3) {
assert(adata(i).getWidth == 32)
assert(bdata(i).getWidth == 32)
}
val out = Wire(Vec(2, UInt(32.W)))
for (j <- 0 until 2) {
val m = 2 * j + alu // alu[0]: {0, 2}; alu[1]: {1, 3}
val mul = Wire(Vec(3, SInt(20.W)))
for (i <- 0 until 3) {
val as = adata(i)(8 * m + 7) & asign
val bs = bdata(i)(8 * m + 7) & bsign
val aval = Cat(as, adata(i)(8 * m + 7, 8 * m)).asSInt +& abias.asSInt
val bval = Cat(bs, bdata(i)(8 * m + 7, 8 * m)).asSInt +& bbias.asSInt
val mval = aval * bval
mul(i) := mval
assert(aval.getWidth == 10)
assert(bval.getWidth == 10)
assert(mval.getWidth == 20)
}
val dotp = (mul(0) +& mul(1)) +& mul(2)
val sdotp = Cat(MuxOR(dotp(21), ~0.U(10.W)), dotp)
assert(dotp.getWidth == 22)
assert(sdotp.getWidth == 32)
out(j) := sdotp
}
(out(0), out(1))
}
}