Skip to content
This repository has been archived by the owner on Aug 19, 2024. It is now read-only.

Reintroduce FixedPoint support #706

Open
wants to merge 6 commits into
base: 5.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Setup Scala
uses: actions/setup-java@v3
with:
Expand All @@ -34,6 +36,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Test
run: sbt "testOnly chiseltest.** -- -l RequiresVcs -l RequiresVerilator -l Formal -l RequiresIcarus"

Expand All @@ -46,6 +50,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Install Icarus Verilog for Ubuntu
if: runner.os == 'Linux'
run: |
Expand Down Expand Up @@ -76,6 +82,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Install Verilator Build Dependencies
run: sudo apt-get install -y git make autoconf g++ flex bison libfl2 libfl-dev
- name: Cache Verilator ${{ matrix.version }}
Expand Down Expand Up @@ -110,6 +118,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Install Z3 and CVC4
if: runner.os == 'Linux'
run: |
Expand All @@ -129,6 +139,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Install Z3 for MacOS
run: |
brew install z3
Expand All @@ -142,6 +154,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Documentation
id: doc
run: sbt doc
Expand All @@ -155,6 +169,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Check for Warnings
run: sbt "set ThisBuild / scalacOptions ++= Seq(\"-Xfatal-warnings\") ; compile"
- name: Check for Warnings in Tests
Expand All @@ -170,6 +186,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Setup Scala
uses: actions/setup-java@v3
with:
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 = [email protected]:ucb-bar/fixedpoint.git
160 changes: 80 additions & 80 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,90 +1,90 @@
// SPDX-License-Identifier: Apache-2.0

organization := "edu.berkeley.cs"
name := "chiseltest"

// we keep in sync with chisel version names
version := "5.0.2"

scalaVersion := "2.13.10"

crossScalaVersions := Seq("2.13.10")

resolvers ++= Resolver.sonatypeOssRepos("snapshots")
resolvers ++= Resolver.sonatypeOssRepos("releases")

testFrameworks += new TestFramework("utest.runner.Framework")

publishMavenStyle := true
lazy val commonSettings = Seq(
organization := "edu.berkeley.cs",
scalaVersion := "2.13.10",
crossScalaVersions := Seq("2.13.10")
)

Test / publishArtifact := false
pomIncludeRepository := { x => false }
val chiselVersion = "5.1.0"
val firrtlVersion = "5.0.0"

// scm is set by sbt-ci-release
pomExtra := (
<url>http://chisel.eecs.berkeley.edu/</url>
<licenses>
<license>
<name>apache_v2</name>
<url>https://opensource.org/licenses/Apache-2.0</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>ducky64</id>
<name>Richard Lin</name>
</developer>
</developers>
lazy val chiseltestSettings = Seq(
name := "chiseltest",
// we keep in sync with chisel version names
version := "5.1.0",
scalacOptions := Seq(
"-deprecation",
"-feature",
"-language:reflectiveCalls",
// do not warn about firrtl imports, once the firrtl repo is removed, we will need to import the code
"-Wconf:cat=deprecation&msg=Importing from firrtl is deprecated:s",
// do not warn about firrtl deprecations
"-Wconf:cat=deprecation&msg=will not be supported as part of the migration to the MLIR-based FIRRTL Compiler:s"
),
// Always target Java8 for maximum compatibility
javacOptions ++= Seq("-source", "1.8", "-target", "1.8"),
libraryDependencies ++= Seq(
"org.chipsalliance" %% "chisel" % chiselVersion,
"edu.berkeley.cs" %% "firrtl" % firrtlVersion,
"org.scalatest" %% "scalatest" % "3.2.17",
"com.lihaoyi" %% "utest" % "0.8.1",
"net.java.dev.jna" % "jna" % "5.13.0",
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
"com.lihaoyi" %% "os-lib" % "0.8.1",
compilerPlugin(("org.chipsalliance" % "chisel-plugin" % chiselVersion).cross(CrossVersion.full))
),
resolvers ++= Resolver.sonatypeOssRepos("snapshots"),
resolvers ++= Resolver.sonatypeOssRepos("releases"),
testFrameworks += new TestFramework("utest.runner.Framework")
)

publishTo := {
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"))
lazy val publishSettings = Seq(
publishMavenStyle := true,
Test / publishArtifact := false,
pomIncludeRepository := { x => false },
// scm is set by sbt-ci-release
pomExtra :=
<url>https://github.com/ucb-bar/chiseltest/</url>
<licenses>
<license>
<name>Apache-2.0</name>
<url>https://opensource.org/licenses/Apache-2.0</url>
<distribution>repo</distribution>
</license>
<license>
<name>BSD-3-Clause</name>
<url>https://opensource.org/licenses/BSD-3-Clause</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>ekiwi</id>
<name>Kevin Laeufer</name>
<email>[email protected]</email>
</developer>
<developer>
<id>ducky64</id>
<name>Richard Lin</name>
</developer>
</developers>,
publishTo := {
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"))
}
}
}

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

scalacOptions ++= Seq(
"-language:reflectiveCalls",
"-deprecation",
"-feature",
"-Xcheckinit",
// do not warn about firrtl imports, once the firrtl repo is removed, we will need to import the code
"-Wconf:cat=deprecation&msg=Importing from firrtl is deprecated:s",
// do not warn about firrtl deprecations
"-Wconf:cat=deprecation&msg=will not be supported as part of the migration to the MLIR-based FIRRTL Compiler:s",
) ++ {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, n)) if n >= 13 => Seq("-Ymacro-annotations")
case _ => Nil
}
}
lazy val fixedpoint = (project in file("fixedpoint"))
.settings(commonSettings)

libraryDependencies ++= Seq(
"org.chipsalliance" %% "chisel" % defaultVersions("chisel3"),
"edu.berkeley.cs" %% "firrtl" % defaultVersions("firrtl"),
"org.scalatest" %% "scalatest" % "3.2.15",
"com.lihaoyi" %% "utest" % "0.8.1",
"net.java.dev.jna" % "jna" % "5.13.0",
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
"com.lihaoyi" %% "os-lib" % "0.8.1",
compilerPlugin(("org.chipsalliance" % "chisel-plugin" % defaultVersions("chisel3")).cross(CrossVersion.full))
) ++ {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, n)) if n >= 13 => Nil
case _ =>
Seq(
compilerPlugin(("org.scalamacros" % "paradise" % "2.1.1").cross(CrossVersion.full))
)
}
}
lazy val chiseltest = (project in file("."))
.dependsOn(fixedpoint)
.settings(commonSettings)
.settings(chiseltestSettings)
.settings(publishSettings)
1 change: 1 addition & 0 deletions fixedpoint
Submodule fixedpoint added at ef1640
72 changes: 71 additions & 1 deletion src/main/scala/chiseltest/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import chisel3.{
import chisel3.util.{ReadyValidIO, ValidIO}
import chisel3.experimental.BundleLiterals._
import chisel3.experimental.VecLiterals._
import fixedpoint._

/** Basic interfaces and implicit conversions for testers2
*/
Expand Down Expand Up @@ -121,6 +122,59 @@ package object chiseltest {
}
}

/** allows access to chisel FixedPoint type signals with Scala native values */
implicit class testableFixedPoint(x: FixedPoint) {
private def asFixedPoint(value: Double): FixedPoint = value.F(Utils.getFirrtlWidth(x), x.binaryPoint)
private def asFixedPoint(value: BigDecimal): FixedPoint = value.F(Utils.getFirrtlWidth(x), x.binaryPoint)
def poke(value: FixedPoint): Unit = {
require(x.binaryPoint == value.binaryPoint, "binary point mismatch")
Utils.pokeBits(x, value.litValue)
}
def poke(value: Double): Unit = poke(asFixedPoint(value))
def poke(value: BigDecimal): Unit = poke(asFixedPoint(value))
private[chiseltest] def expectInternal(value: FixedPoint, message: Option[() => String]): Unit = {
require(x.binaryPoint == value.binaryPoint, "binary point mismatch")
// for backwards compatibility reasons, we do not support epsilon when expect is called with the FixedPoint type.
Utils.expectBits(x, value.litValue, message, Some(Utils.fixedToString(x.binaryPoint)))
}
def expect(value: FixedPoint): Unit = expectInternal(value, None)
def expect(value: FixedPoint, message: => String): Unit = expectInternal(value, Some(() => message))
private[chiseltest] def expectInternal(expected: Double, epsilon: Double, userMsg: Option[() => String]): Unit = {
Utils.expectEpsilon(x, peekDouble(), expected, epsilon, userMsg)
}
def expect(value: Double): Unit = expectInternal(value, epsilon = 0.01, None)
def expect(value: Double, epsilon: Double): Unit = expectInternal(value, epsilon = epsilon, None)
def expect(value: Double, message: => String): Unit =
expectInternal(value, epsilon = 0.01, Some(() => message))
def expect(value: Double, message: => String, epsilon: Double): Unit =
expectInternal(value, epsilon = epsilon, Some(() => message))
private[chiseltest] def expectInternal(
expected: BigDecimal,
epsilon: BigDecimal,
userMsg: Option[() => String]
): Unit = {
Utils.expectEpsilon(x, peekBigDecimal(), expected, epsilon, userMsg)
}
def expect(value: BigDecimal): Unit = expectInternal(value, epsilon = 0.01, None)
def expect(value: BigDecimal, epsilon: BigDecimal): Unit = expectInternal(value, epsilon = epsilon, None)
def expect(value: BigDecimal, message: => String): Unit =
expectInternal(value, epsilon = 0.01, Some(() => message))
def expect(value: BigDecimal, message: => String, epsilon: BigDecimal): Unit =
expectInternal(value, epsilon = epsilon, Some(() => message))
def peek(): FixedPoint = {
val multiplier = BigDecimal(2).pow(x.binaryPoint.get)
(BigDecimal(Context().backend.peekBits(x)) / multiplier).F(x.binaryPoint)
}
def peekDouble(): Double = x.binaryPoint match {
case KnownBinaryPoint(bp) => FixedPoint.toDouble(Context().backend.peekBits(x), bp)
case _ => throw new Exception("Cannot peekInterval with unknown binary point location")
}
def peekBigDecimal(): BigDecimal = x.binaryPoint match {
case KnownBinaryPoint(bp) => FixedPoint.toBigDecimal(Context().backend.peekBits(x), bp)
case _ => throw new Exception("Cannot peekInterval with unknown binary point location")
}
}

implicit class testableRecord[T <: Record](x: T) {

/** Poke the given signal with a [[Record.litValue()]]
Expand Down Expand Up @@ -201,6 +255,7 @@ package object chiseltest {
case (x: Bool, value: Bool) => x.poke(value)
case (x: UInt, value: UInt) => x.poke(value)
case (x: SInt, value: SInt) => x.poke(value)
case (x: FixedPoint, value: FixedPoint) => x.poke(value)
case (x: Record, value: Record) =>
require(DataMirror.checkTypeEquivalence(x, value), s"Record type mismatch")
x.elements.zip(value.elements).foreach { case ((_, x), (_, value)) =>
Expand All @@ -223,6 +278,7 @@ package object chiseltest {
case x: Bool => x.peek().asInstanceOf[T]
case x: UInt => x.peek().asInstanceOf[T]
case x: SInt => x.peek().asInstanceOf[T]
case x: FixedPoint => x.peek().asInstanceOf[T]
case x: Record =>
val elementValueFns = x.elements.map { case (name: String, elt: Data) =>
(y: Record) => (y.elements(name), elt.peek())
Expand All @@ -243,6 +299,7 @@ package object chiseltest {
case (x: Bool, value: Bool) => x.expectInternal(value.litValue, message)
case (x: UInt, value: UInt) => x.expectInternal(value.litValue, message)
case (x: SInt, value: SInt) => x.expectInternal(value.litValue, message)
case (x: FixedPoint, value: FixedPoint) => x.expectInternal(value, message)
case (x: Record, value: Record) =>
require(DataMirror.checkTypeEquivalence(x, value), s"Record type mismatch")
x.elements.zip(value.elements).foreach { case ((_, x), (_, value)) =>
Expand Down Expand Up @@ -325,13 +382,26 @@ package object chiseltest {
}

// helps us work around the fact that signal.width is private!
def getFirrtlWidth(signal: Bits): chisel3.internal.firrtl.Width = signal.widthOption match {
def getFirrtlWidth(signal: Data): chisel3.internal.firrtl.Width = signal.widthOption match {
case Some(value) => chisel3.internal.firrtl.KnownWidth(value)
case None => chisel3.internal.firrtl.UnknownWidth()
}

def boolBitsToString(bits: BigInt): String = (bits != 0).toString

def fixedToString(binaryPoint: BinaryPoint): BigInt => String = {
def inner(bits: BigInt): String = {
binaryPoint match {
case KnownBinaryPoint(binaryPoint) =>
val bpInteger = 1 << binaryPoint
(bits.toFloat / bpInteger).toString
case UnknownBinaryPoint => "[unknown binary point]"
}
}

inner
}

def enumToString(tpe: EnumType): BigInt => String = {
def inner(bits: BigInt): String = {
val fullName = chisel3.internaltest.EnumHelpers.valueToName(tpe, bits).getOrElse("???")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class HasOddWidthSInt extends Module {
out := masked === in
}

// The poke of a negative number into an SInt input that is not a standard word size
// The poke of a negative number into an SInt or FixedPoint input that is not a standard word size
// would break in verilator if the poked value was not masked to the correct number of
// bits first. This was fixed by masking those values to the proper width before poking
class NegativeInputValuesTest extends AnyFreeSpec with ChiselScalatestTester {
Expand Down
Loading
Loading