Skip to content

Commit

Permalink
Merge pull request #246 from milovanovic/master
Browse files Browse the repository at this point in the history
Switch to Fixed-Point User Library as preparation for Chisel3.6 bump
  • Loading branch information
milovanovic authored Jul 26, 2023
2 parents 8e26fc2 + 49e63dd commit 3fb6e60
Show file tree
Hide file tree
Showing 20 changed files with 518 additions and 62 deletions.
13 changes: 6 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,18 @@ jobs:
test:
name: test
runs-on: ubuntu-latest
container:
image: ucbbar/chisel3-tools
options: --user github --entrypoint /bin/bash
env:
CONTAINER_HOME: /home/github

steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: 'true'
- name: Install Verilator
run: sudo apt-get update -y && sudo apt-get install -y verilator
- name: Setup Scala
uses: olafurpg/setup-scala@v10
uses: coursier/setup-action@v1
- name: Cache
uses: coursier/cache-action@v5
uses: coursier/cache-action@v6
- name: Documentation
id: doc
run: sbt doc
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "fixedpoint"]
path = fixedpoint
url = https://github.com/ucb-bar/fixedpoint
54 changes: 41 additions & 13 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ enablePlugins(SiteScaladocPlugin)
enablePlugins(GhpagesPlugin)

val defaultVersions = Map(
"chisel-iotesters" -> "2.5-SNAPSHOT",
"chisel3" -> "3.5-SNAPSHOT",
"chiseltest" -> "0.5-SNAPSHOT"
)

name := "dsptools"
Expand All @@ -16,9 +16,14 @@ val commonSettings = Seq(
version := "1.5-SNAPSHOT",
git.remoteRepo := "[email protected]:ucb-bar/dsptools.git",
autoAPIMappings := true,
scalaVersion := "2.12.14",
crossScalaVersions := Seq("2.13.6", "2.12.14"),
scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature", "-language:reflectiveCalls"),
scalaVersion := "2.13.10",
scalacOptions ++= Seq("-encoding",
"UTF-8",
"-unchecked",
"-deprecation",
"-feature",
"-language:reflectiveCalls",
"-Ymacro-annotations"),
javacOptions ++= Seq("-source", "1.8", "-target", "1.8"),
pomExtra := (<url>http://chisel.eecs.berkeley.edu/</url>
<licenses>
Expand Down Expand Up @@ -49,26 +54,25 @@ val commonSettings = Seq(
val v = version.value
val nexus = "https://oss.sonatype.org/"
if (v.trim.endsWith("SNAPSHOT")) {
Some("snapshots" at nexus + "content/repositories/snapshots")
}
else {
Some("releases" at nexus + "service/local/staging/deploy/maven2")
Some("snapshots".at(nexus + "content/repositories/snapshots"))
} else {
Some("releases".at(nexus + "service/local/staging/deploy/maven2"))
}
},
resolvers ++= Seq (
resolvers ++= Seq(
Resolver.sonatypeRepo("snapshots"),
Resolver.sonatypeRepo("releases")
),
libraryDependencies ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, major)) if major <= 12 => Seq()
case _ => Seq("org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.3")
case _ => Seq("org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.3")
}
},
libraryDependencies ++= Seq("chisel-iotesters").map { dep: String =>
libraryDependencies ++= Seq("chisel3", "chiseltest").map { dep: String =>
"edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep))
},
addCompilerPlugin("edu.berkeley.cs" %% "chisel3-plugin" % defaultVersions("chisel3") cross CrossVersion.full),
addCompilerPlugin(("edu.berkeley.cs" %% "chisel3-plugin" % defaultVersions("chisel3")).cross(CrossVersion.full)),
)

val dsptoolsSettings = Seq(
Expand All @@ -80,12 +84,36 @@ val dsptoolsSettings = Seq(
),
)

val fixedpointSettings = Seq(
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.2.+" % "test",
"org.scalatestplus" %% "scalacheck-1-14" % "3.2.2.0" % "test",
)
)

publishMavenStyle := true

publishArtifact in Test := false
pomIncludeRepository := { x => false }
pomIncludeRepository := { x =>
false
}

def freshProject(name: String, dir: File): Project = {
Project(id = name, base = dir / "src")
.settings(
Compile / scalaSource := baseDirectory.value / "main" / "scala",
Compile / resourceDirectory := baseDirectory.value / "main" / "resources"
)
}

lazy val fixedpoint = freshProject("fixedpoint", file("fixedpoint"))
.settings(
commonSettings,
fixedpointSettings
)

val dsptools = (project in file("."))
.dependsOn(fixedpoint)
//.enablePlugins(BuildInfoPlugin)
.enablePlugins(ScalaUnidocPlugin)
.settings(commonSettings: _*)
Expand Down
4 changes: 2 additions & 2 deletions doc/Example.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ A basic DSP Module + Tester might look like this:
package SimpleDsp

// Allows you to use Chisel Module, Bundle, etc.
import chisel3._
import chisel3.{fromDoubleToLiteral => _, fromIntToBinaryPoint => _, _}
// Allows you to use FixedPoint
import chisel3.experimental.FixedPoint
import fixedpoint._
// If you want to take advantage of type classes >> Data:RealBits (i.e. pass in FixedPoint or DspReal)
// Required for you to use operators defined via type classes (+ has special Dsp overflow behavior, etc.)
import dsptools.numbers._
Expand Down
1 change: 1 addition & 0 deletions fixedpoint
Submodule fixedpoint added at 4e6912
5 changes: 3 additions & 2 deletions rocket/src/main/scala/jtag2mm/TestMultiplexer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

package freechips.rocketchip.jtag2mm

import chisel3._
import chisel3.{fromDoubleToLiteral => _, fromIntToBinaryPoint => _, _}
import chisel3.util._
import chisel3.experimental._
import chisel3.experimental.{FixedPoint => _, _}
import fixedpoint._
//import chisel3.experimental.{withClockAndReset}

import dsptools._
Expand Down
124 changes: 124 additions & 0 deletions src/main/scala/dsptools/misc/DspTesterUtilities.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// SPDX-License-Identifier: Apache-2.0

package dsptools.misc

import chisel3.{fromDoubleToLiteral => _, fromIntToBinaryPoint => _, _}
import fixedpoint._
import dsptools.DspException
import dsptools.numbers.{DspComplex, DspReal}
import chisel3.internal.InstanceId

//scalastyle:off cyclomatic.complexity method.length
object DspTesterUtilities {

// Converts signed Double's to their 2's complement BigInt equivalents (unsigned)
// (totalWidth, fractionalWidth of some FixedPoint)
def signedToBigIntUnsigned(x: Double, totalWidth: Int, fractionalWidth: Int): BigInt = {
val bi = FixedPoint.toBigInt(x, fractionalWidth)
val neg = bi < 0
val neededWidth = bi.bitLength + 1
require(neededWidth <= totalWidth, "Double -> BigInt width larger than total width allocated!")
if (neg) {
(BigInt(1) << totalWidth) + bi
} else {
bi
}
}

// Redundant from chisel-testers
// Converts unsigned BigInt to signed BigInt (width = width of Chisel data type)
def signConvert(bigInt: BigInt, width: Int): BigInt = {
require(bigInt >= 0, "signConvert assumes bigInt is >= 0!")
// Since the bigInt is always unsigned, bitLength always gets the max # of bits required to represent bigInt
val w = bigInt.bitLength.max(width)
// Negative if MSB is set or in this case, ex: 3 bit wide: negative if >= 4
if (bigInt >= (BigInt(1) << (w - 1))) (bigInt - (BigInt(1) << w)) else bigInt
}

// Converts a positive 2's complement BigInt to a Double - used for FixedPoint
def toDoubleFromUnsigned(i: BigInt, totalWidth: Int, fractionalWidth: Int): Double = {
val signedBigInt = signConvert(i, totalWidth)
FixedPoint.toDouble(signedBigInt, fractionalWidth)
}

// For DspReal represented as BigInt from Double (unsigned)
def doubleToBigIntBits(double: Double): BigInt = {
val ret = BigInt(java.lang.Double.doubleToLongBits(double))
if (ret >= 0) ret
else (BigInt(1) << DspReal.underlyingWidth) + ret
}

// For DspReal represented as BigInt back to Double
def bigIntBitsToDouble(bigInt: BigInt): Double = {
java.lang.Double.longBitsToDouble(bigInt.toLong)
}

// Used to get signal name for printing to console
private[dsptools] def getName(signal: InstanceId): String = {
s"${signal.pathName}"
}

// Note: DspReal underlying is UInt
// Checks if a basic number is signed or unsigned
def isSigned(e: Data): Boolean = {
e match {
case _: SInt | _: FixedPoint => true
case _: DspReal | _: Bool | _: UInt => false
// Clock isn't a number, but it's still valid IO (should be treated as a Bool)
case _: Clock => false
case _ => throw DspException("Not a basic number/clock type! " + e)
}
}

// For printing to Verilog testbench (signed)
private[dsptools] def signPrefix(e: Element): String = {
def signed = isSigned(e)
if (signed) " signed "
else ""
}

// Determines if peek/poke data fits in bit width
def validRangeTest(signal: Data, value: BigInt): Unit = {
val len = value.bitLength
val neededLen = if (isSigned(signal)) len + 1 else len
require(signal.widthOption.nonEmpty, "Cannot check range of node with unknown width!")
if (neededLen > signal.getWidth)
throw DspException(s"Value: $value is not in node ${getName(signal)} range")
if (!isSigned(signal) && value < 0)
throw DspException("Negative value can't be used with unsigned")
}

// Gets information on bitwidth, binarypoint for printing in console
def bitInfo(signal: Data): String = signal.widthOption match {
case Some(width) => {
signal match {
case f: FixedPoint =>
f.binaryPoint match {
// Q integer . fractional bits
case KnownBinaryPoint(bp) => s"Q${width - 1 - bp}.$bp"
case _ => s"${width}-bit F"
}
case r: DspReal => "R"
case u: UInt => s"${width}-bit U"
case s: SInt => s"${width}-bit S"
case c: DspComplex[_] => {
val realInfo = bitInfo(c.real.asInstanceOf[Data])
val imagInfo = bitInfo(c.imag.asInstanceOf[Data])
s"[$realInfo, $imagInfo]"
}
case _ => throw DspException("Can't get bit info! Invalid type!")
}
}
case None => ""
}

// Round value if data type is integer
def roundData(data: Data, value: Double): Double = {
data match {
case _: SInt | _: UInt => value.round.toDouble
case _: DspReal | _: FixedPoint => value
case _ => throw DspException("Invalid data type for rounding determination")
}
}

}
Loading

0 comments on commit 3fb6e60

Please sign in to comment.