diff --git a/src/main/scala/dsptools/tester/DspTesterUtilities.scala b/src/main/scala/dsptools/tester/DspTesterUtilities.scala index 4b349363..a4d34776 100644 --- a/src/main/scala/dsptools/tester/DspTesterUtilities.scala +++ b/src/main/scala/dsptools/tester/DspTesterUtilities.scala @@ -13,14 +13,14 @@ import chisel3.iotesters.TestersCompatibility object DspTesterUtilities { - // Converts negative Double's to their 2's complement BigInt equivalents + // Converts signed Double's to their 2's complement BigInt equivalents (unsigned) // (totalWidth, fractionalWidth of some FixedPoint) - def toBigIntUnsigned(x: Double, totalWidth: Int, fractionalWidth: Int): BigInt = { + def signedToBigIntUnsigned(x: Double, totalWidth: Int, fractionalWidth: Int): BigInt = { val bi = FixedPoint.toBigInt(x, fractionalWidth) val neg = bi < 0 - val neededWidth = if (neg) bi.bitLength + 1 else bi.bitLength + val neededWidth = bi.bitLength + 1 require(neededWidth <= totalWidth, "Double -> BigInt width larger than total width allocated!") - if (neg) (BigInt(1) << neededWidth) + bi + if (neg) (BigInt(1) << totalWidth) + bi else bi } @@ -119,4 +119,4 @@ object DspTesterUtilities { } } -} \ No newline at end of file +} diff --git a/src/test/scala/dsptools/DspTesterSpec.scala b/src/test/scala/dsptools/DspTesterSpec.scala index 12ede60d..f54f4631 100644 --- a/src/test/scala/dsptools/DspTesterSpec.scala +++ b/src/test/scala/dsptools/DspTesterSpec.scala @@ -2,6 +2,68 @@ package dsptools +import DspTesterUtilities._ +import org.scalatest.{FlatSpec, Matchers} +import scala.math.{pow, abs} + class DspTesterSpec { } + +class DspTesterUtilitiesSpec extends FlatSpec with Matchers { + + behavior of "Tester Converters" + + it should "convert positive and negative doubles to their BigInt, fixed point equivalents" in { + + def check_conversion(value: Double, totalWidth: Int, fractionalWidth: Int, verbose: Boolean = false): Unit = { + if (verbose) { println(s"value = $value\ntotal width = $totalWidth\nfractional width = $fractionalWidth") } + var bi = signedToBigIntUnsigned(value, totalWidth, fractionalWidth) + if (verbose) { println(s"result = $bi") } + // check sign, flip if necessary + if (totalWidth > 0 && bi.testBit(totalWidth-1)) { + bi = -1 * ((bi ^ ((BigInt(1) << totalWidth) - 1)) + 1) + } + val bid = bi.toDouble / (BigInt(1) << fractionalWidth).toDouble + if (verbose) { println(s"back to double = $bid") } + val comp = scala.math.abs(bid-value) + if (verbose) { println(s"comp = $comp") } + val ref = scala.math.pow(2, -fractionalWidth) + if (verbose) { println(s"ref = $ref") } + require(abs(bid-value) < pow(2, -fractionalWidth)) + } + + // integers + var width = 14 + for (i <- -pow(2,width-1).toInt until pow(2,width-1).toInt) { + check_conversion(i, width, 0) + } + + // big integers + width = 40 + for (i <- -pow(2,width-1).toInt to pow(2,width-1).toInt by pow(2, 20).toInt) { + check_conversion(i, width, 0) + } + + // total > fractional + width = 19 + var fract = 8 + for (i <- -pow(2,width-fract-1) to pow(2,width-fract-1)-1 by 1.0/fract*0.9) { + check_conversion(i, width, fract) + } + + // total < fractional + width = 11 + fract = 17 + for (i <- -pow(2,width-fract-1) to pow(2,width-fract-1)-1 by 1.0/fract*0.9) { + check_conversion(i, width, fract) + } + + } + + it should "fail to convert doubles to BigInts when not enough space is supplied" in { + intercept[IllegalArgumentException] { signedToBigIntUnsigned(2.0, 4, 2) } + intercept[IllegalArgumentException] { signedToBigIntUnsigned(-2.25, 4, 2) } + } + +}