Skip to content

Commit

Permalink
first commit: add vpu folder add patch for rocket-chip add LICENSE.SZ…
Browse files Browse the repository at this point in the history
…U, LICENSE.UCTECHIP add TODO list
  • Loading branch information
liangzhanhao committed Jun 19, 2020
1 parent f56bba2 commit 3ec3447
Show file tree
Hide file tree
Showing 60 changed files with 13,891 additions and 2 deletions.
1,797 changes: 1,797 additions & 0 deletions 0001-integrate-VPU-which-is-corresponding-to-0.8-release-.patch

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions LICENSE.SZU
Original file line number Diff line number Diff line change
@@ -0,0 1,29 @@
BSD 3-Clause License

Copyright (c) 2020, Shenzhen University
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2 changes: 1 addition & 1 deletion LICENSE → LICENSE.UCTECHIP
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright 2020-2021 UC TECH IP, Co.,Ltd.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
54 changes: 53 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 1,53 @@
# rocket_chip_vpu
# rocket_chip_vpu

the repository contains VPU source code writen in Chisel, corresponding to rocket-chip and patch for rocket-chip.
* VPU implementation is base on 0.8-release [RVV SPEC](https://github.com/riscv/riscv-v-spec/releases/tag/0.8).
* patch for rocket-chip is base on commit [26a18fa6](https://github.com/chipsalliance/rocket-chip/tree/26a18fa60e96daa1bfc0229630d25a60d700c0bf).

## Usage
### checkout commit 26a18fa6 of rocket-chip

```
$ git clone https://github.com/chipsalliance/rocket-chip.git
$ cd rocket-chip
$ git checkout 26a18fa6
$ git submodule update --init --recursive
```

### set up rocket-chip environment

git clone [rocket-tools](https://github.com/chipsalliance/rocket-tools), then do as README.md of rocket-chip describes:
* Install [rocket-tools "Ubuntu Packages Needed"](https://github.com/chipsalliance/rocket-tools/blob/master/README.md);
* Install rocket-tools
* Install [chisel3 "dependancies": sbt, verilator(optional)](https://github.com/freechipsproject/chisel3/blob/master/SETUP.md)

### copy and appply the patch to rocket-chip

```
$ cd rocket_chip_vpu
$ cp 0001-integrate-VPU-which-is-corresponding-to-0.8-release-.patch /path/to/clone/rocket-chip
$ cd /path/to/clone/rocket-chip
$ git am 0001-integrate-VPU-which-is-corresponding-to-0.8-release-.patch
```

### make verilog
first copy vpu folder to rocket-chip
```
$ cp vpu /path/to/clone/rocket-chip
```

then make verilog
```
$ cd /patch/to/clone/rocket-chip/vsim
$ make verilog CONFIG=freechips.rocketchip.system.VPUConfig
```

## compile VPU only(optional)

VPU depends on [hardfloat](https://github.com/ucb-bar/berkeley-hardfloat) repo. To compile VPU, the most direct way is to copy all scala files to vpu/src/main/scala/hardfloat
```
$ cd vpu
$ mkdir -p src/scala/main/hardfloat
$ cp /path/to/clone/hardfloat/src/main/scala/* src/scala/main/hardfloat
$ make verilog
```
12 changes: 12 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -0,0 1,12 @@
update VPU to riscv-v-spec 1.0 version
deal with vsetvl[i] insts in CSR module instead of VCSR module
improve VPU's architecture and preformance
improve testharness
XLen must be binding on XLEN parameter
FLen must be binding on FLEN parameter
realize dot and fdot insts
improve Zvediv extension implementation
update to match Rocket's FPU which supports Half-precision
update MulDiv module
VReduction module support until 1024 width element
mix VScalarMove VSlide VRGather VCompress modules, using addressing like model to implement instead
23 changes: 23 additions & 0 deletions vpu/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 1,23 @@
PROJECT ?= VPU
PROJECTPACKAGE := $(shell echo $(PROJECT) | tr A-Z a-z)
PROJECTMAIN ?= $(PROJECT)Main
PROJECTVER ?= $(PROJECT)Verilog
PROJECTREPL ?= $(PROJECT)Repl
SBT ?= sbt -J-Xmx8G -J-Xss32M

help:
@echo "usage: make main PROJECT=..."
@echo " OR: make verilog PROJECT=..."
@echo " OR: make repl PROJECT=..."

main:
$(SBT) 'test:runMain $(PROJECTPACKAGE).$(PROJECTMAIN) --backend-name verilator'

verilog:
rm -rf generated_verilog/$(PROJECT)
$(SBT) 'test:runMain $(PROJECTPACKAGE).$(PROJECTVER) -fsm --target-dir generated_verilog/$(PROJECT)'

repl:
$(SBT) 'test:runMain $(PROJECTPACKAGE).$(PROJECTREPL)'

.PHONY: help main verilog repl
54 changes: 54 additions & 0 deletions vpu/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 1,54 @@
def scalacOptionsVersion(scalaVersion: String): Seq[String] = {
Seq() {
// If we're building with Scala > 2.11, enable the compile option
// switch to support our anonymous Bundle definitions:
// https://github.com/scala/bug/issues/10047
CrossVersion.partialVersion(scalaVersion) match {
case Some((2, scalaMajor: Long)) if scalaMajor < 12 => Seq()
case _ => Seq("-Xsource:2.11")
}
}
}

def javacOptionsVersion(scalaVersion: String): Seq[String] = {
Seq() {
// Scala 2.12 requires Java 8. We continue to generate
// Java 7 compatible code for Scala 2.11
// for compatibility with old clients.
CrossVersion.partialVersion(scalaVersion) match {
case Some((2, scalaMajor: Long)) if scalaMajor < 12 =>
Seq("-source", "1.7", "-target", "1.7")
case _ =>
Seq("-source", "1.8", "-target", "1.8")
}
}
}

name := "vpu"

organization := "UCTECHIP"

version := "0.0.1"

//scalaVersion := "2.11.12"
scalaVersion := "2.12.4"

crossScalaVersions := Seq("2.11.12", "2.12.4")

resolvers = Seq(
Resolver.sonatypeRepo("snapshots"),
Resolver.sonatypeRepo("releases")
)

// Provide a managed dependency on X if -DXVersion="" is supplied on the command line.
val defaultVersions = Map(
"chisel3" -> "3.1. ",
"chisel-iotesters" -> "1.2. "
)

libraryDependencies = (Seq("chisel3","chisel-iotesters").map {
dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep "Version", defaultVersions(dep)) })

scalacOptions = scalacOptionsVersion(scalaVersion.value)

javacOptions = javacOptionsVersion(scalaVersion.value)
1 change: 1 addition & 0 deletions vpu/project/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 1 @@
sbt.version = 1.2.7
1 change: 1 addition & 0 deletions vpu/project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 1 @@
logLevel := Level.Warn
205 changes: 205 additions & 0 deletions vpu/src/main/scala/Decode.scala
Original file line number Diff line number Diff line change
@@ -0,0 1,205 @@
// See LICENSE.Berkeley for license details.
// See LICENSE.UCTECHIP for license details.
// See LICENSE.SZU for license details.

package vpu

import Chisel._
import scala.collection.mutable.{ArrayBuffer, Map}

object DecodeLogic
{
def term(lit: BitPat) =
new Term(lit.value, BigInt(2).pow(lit.getWidth)-(lit.mask 1))
def logic(addr: UInt, addrWidth: Int, cache: Map[Term,Bool], terms: Seq[Term]) = {
terms.map { t =>
cache.getOrElseUpdate(t, (if (t.mask == 0) addr else addr & Bits(BigInt(2).pow(addrWidth)-(t.mask 1), addrWidth)) === Bits(t.value, addrWidth))
}.foldLeft(Bool(false))(_||_)
}
def apply(addr: UInt, default: BitPat, mapping: Iterable[(BitPat, BitPat)]): UInt = {
val cache = caches.getOrElseUpdate(addr, Map[Term,Bool]())
val dterm = term(default)
val (keys, values) = mapping.unzip
val addrWidth = keys.map(_.getWidth).max
val terms = keys.toList.map(k => term(k))
val termvalues = terms zip values.toList.map(term(_))

for (t <- keys.zip(terms).tails; if !t.isEmpty)
for (u <- t.tail)
assert(!t.head._2.intersects(u._2), "DecodeLogic: keys " t.head " and " u " overlap")

Cat((0 until default.getWidth.max(values.map(_.getWidth).max)).map({ case (i: Int) =>
val mint = termvalues.filter { case (k,t) => ((t.mask >> i) & 1) == 0 && ((t.value >> i) & 1) == 1 }.map(_._1)
val maxt = termvalues.filter { case (k,t) => ((t.mask >> i) & 1) == 0 && ((t.value >> i) & 1) == 0 }.map(_._1)
val dc = termvalues.filter { case (k,t) => ((t.mask >> i) & 1) == 1 }.map(_._1)

if (((dterm.mask >> i) & 1) != 0) {
logic(addr, addrWidth, cache, SimplifyDC(mint, maxt, addrWidth))
} else {
val defbit = (dterm.value.toInt >> i) & 1
val t = if (defbit == 0) mint else maxt
val bit = logic(addr, addrWidth, cache, Simplify(t, dc, addrWidth))
if (defbit == 0) bit else ~bit
}
}).reverse)
}
def apply(addr: UInt, default: Seq[BitPat], mappingIn: Iterable[(BitPat, Seq[BitPat])]): Seq[UInt] = {
val mapping = ArrayBuffer.fill(default.size)(ArrayBuffer[(BitPat, BitPat)]())
for ((key, values) <- mappingIn)
for ((value, i) <- values zipWithIndex)
mapping(i) = key -> value
for ((thisDefault, thisMapping) <- default zip mapping)
yield apply(addr, thisDefault, thisMapping)
}
def apply(addr: UInt, default: Seq[BitPat], mappingIn: List[(UInt, Seq[BitPat])]): Seq[UInt] =
apply(addr, default, mappingIn.map(m => (BitPat(m._1), m._2)).asInstanceOf[Iterable[(BitPat, Seq[BitPat])]])
def apply(addr: UInt, trues: Iterable[UInt], falses: Iterable[UInt]): Bool =
apply(addr, BitPat.dontCare(1), trues.map(BitPat(_) -> BitPat("b1")) falses.map(BitPat(_) -> BitPat("b0"))).asBool
private val caches = Map[UInt,Map[Term,Bool]]()
}

class Term(val value: BigInt, val mask: BigInt = 0)
{
var prime = true

def covers(x: Term) = ((value ^ x.value) &~ mask | x.mask &~ mask).signum == 0
def intersects(x: Term) = ((value ^ x.value) &~ mask &~ x.mask).signum == 0
override def equals(that: Any) = that match {
case x: Term => x.value == value && x.mask == mask
case _ => false
}
override def hashCode = value.toInt
def < (that: Term) = value < that.value || value == that.value && mask < that.mask
def similar(x: Term) = {
val diff = value - x.value
mask == x.mask && value > x.value && (diff & diff-1) == 0
}
def merge(x: Term) = {
prime = false
x.prime = false
val bit = value - x.value
new Term(value &~ bit, mask | bit)
}

override def toString = value.toString(16) "-" mask.toString(16) (if (prime) "p" else "")
}

object Simplify
{
def getPrimeImplicants(implicants: Seq[Term], bits: Int) = {
var prime = List[Term]()
implicants.foreach(_.prime = true)
val cols = (0 to bits).map(b => implicants.filter(b == _.mask.bitCount))
val table = cols.map(c => (0 to bits).map(b => collection.mutable.Set(c.filter(b == _.value.bitCount):_*)))
for (i <- 0 to bits) {
for (j <- 0 until bits-i)
table(i)(j).foreach(a => table(i 1)(j) = table(i)(j 1).filter(_.similar(a)).map(_.merge(a)))
for (r <- table(i))
for (p <- r; if p.prime)
prime = p :: prime
}
prime.sortWith(_<_)
}
def getEssentialPrimeImplicants(prime: Seq[Term], minterms: Seq[Term]): (Seq[Term],Seq[Term],Seq[Term]) = {
val primeCovers = prime.map(p => minterms.filter(p covers _))
for (((icover, pi), i) <- (primeCovers zip prime).zipWithIndex) {
for (((jcover, pj), j) <- (primeCovers zip prime).zipWithIndex.drop(i 1)) {
if (icover.size > jcover.size && jcover.forall(pi covers _))
return getEssentialPrimeImplicants(prime.filter(_ != pj), minterms)
}
}

val essentiallyCovered = minterms.filter(t => prime.count(_ covers t) == 1)
val essential = prime.filter(p => essentiallyCovered.exists(p covers _))
val nonessential = prime.filterNot(essential contains _)
val uncovered = minterms.filterNot(t => essential.exists(_ covers t))
if (essential.isEmpty || uncovered.isEmpty)
(essential, nonessential, uncovered)
else {
val (a, b, c) = getEssentialPrimeImplicants(nonessential, uncovered)
(essential a, b, c)
}
}
def getCost(cover: Seq[Term], bits: Int) = cover.map(bits - _.mask.bitCount).sum
def cheaper(a: List[Term], b: List[Term], bits: Int) = {
val ca = getCost(a, bits)
val cb = getCost(b, bits)
def listLess(a: List[Term], b: List[Term]): Boolean = !b.isEmpty && (a.isEmpty || a.head < b.head || a.head == b.head && listLess(a.tail, b.tail))
ca < cb || ca == cb && listLess(a.sortWith(_<_), b.sortWith(_<_))
}
def getCover(implicants: Seq[Term], minterms: Seq[Term], bits: Int) = {
if (minterms.nonEmpty) {
val cover = minterms.map(m => implicants.filter(_.covers(m)))
val all = cover.tail.foldLeft(cover.head.map(Set(_)))((c0, c1) => c0.flatMap(a => c1.map(a _)))
all.map(_.toList).reduceLeft((a, b) => if (cheaper(a, b, bits)) a else b)
} else
Seq[Term]()
}
def stringify(s: Seq[Term], bits: Int) = s.map(t => (0 until bits).map(i => if ((t.mask & (1 << i)) != 0) "x" else ((t.value >> i) & 1).toString).reduceLeft(_ _).reverse).reduceLeft(_ " " _)

def apply(minterms: Seq[Term], dontcares: Seq[Term], bits: Int) = {
val prime = getPrimeImplicants(minterms dontcares, bits)
minterms.foreach(t => assert(prime.exists(_.covers(t))))
val (eprime, prime2, uncovered) = getEssentialPrimeImplicants(prime, minterms)
val cover = eprime getCover(prime2, uncovered, bits)
minterms.foreach(t => assert(cover.exists(_.covers(t)))) // sanity check
cover
}
}

object SimplifyDC
{
def getImplicitDC(maxterms: Seq[Term], term: Term, bits: Int, above: Boolean): Term = {
for (i <- 0 until bits) {
var t: Term = null
if (above && ((term.value | term.mask) & (BigInt(1) << i)) == 0)
t = new Term(term.value | (BigInt(1) << i), term.mask)
else if (!above && (term.value & (BigInt(1) << i)) != 0)
t = new Term(term.value & ~(BigInt(1) << i), term.mask)
if (t != null && !maxterms.exists(_.intersects(t)))
return t
}
null
}
def getPrimeImplicants(minterms: Seq[Term], maxterms: Seq[Term], bits: Int) = {
var prime = List[Term]()
minterms.foreach(_.prime = true)
var mint = minterms.map(t => new Term(t.value, t.mask))
val cols = (0 to bits).map(b => mint.filter(b == _.mask.bitCount))
val table = cols.map(c => (0 to bits).map(b => collection.mutable.Set(c.filter(b == _.value.bitCount):_*)))

for (i <- 0 to bits) {
for (j <- 0 until bits-i) {
table(i)(j).foreach(a => table(i 1)(j) = table(i)(j 1).filter(_ similar a).map(_ merge a))
}
for (j <- 0 until bits-i) {
for (a <- table(i)(j).filter(_.prime)) {
val dc = getImplicitDC(maxterms, a, bits, true)
if (dc != null)
table(i 1)(j) = dc merge a
}
for (a <- table(i)(j 1).filter(_.prime)) {
val dc = getImplicitDC(maxterms, a, bits, false)
if (dc != null)
table(i 1)(j) = a merge dc
}
}
for (r <- table(i))
for (p <- r; if p.prime)
prime = p :: prime
}
prime.sortWith(_<_)
}

def verify(cover: Seq[Term], minterms: Seq[Term], maxterms: Seq[Term]) = {
assert(minterms.forall(t => cover.exists(_ covers t)))
assert(maxterms.forall(t => !cover.exists(_ intersects t)))
}
def apply(minterms: Seq[Term], maxterms: Seq[Term], bits: Int) = {
val prime = getPrimeImplicants(minterms, maxterms, bits)
val (eprime, prime2, uncovered) = Simplify.getEssentialPrimeImplicants(prime, minterms)
val cover = eprime Simplify.getCover(prime2, uncovered, bits)
verify(cover, minterms, maxterms)
cover
}
}
Loading

0 comments on commit 3ec3447

Please sign in to comment.