summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/chisel3/package.scala14
-rw-r--r--src/test/scala/chiselTests/RangeSpec.scala104
2 files changed, 117 insertions, 1 deletions
diff --git a/src/main/scala/chisel3/package.scala b/src/main/scala/chisel3/package.scala
index 3cdda971..29aa6528 100644
--- a/src/main/scala/chisel3/package.scala
+++ b/src/main/scala/chisel3/package.scala
@@ -3,7 +3,7 @@
package object chisel3 { // scalastyle:ignore package.object.name
import scala.language.experimental.macros
- import internal.firrtl.Width
+ import internal.firrtl.{Width, NumericBound}
import internal.sourceinfo.{SourceInfo, SourceInfoTransform}
import util.BitPat
@@ -202,5 +202,17 @@ package object chisel3 { // scalastyle:ignore package.object.name
implicit def fromBigIntToIntParam(x: BigInt): IntParam = IntParam(x)
implicit def fromDoubleToDoubleParam(x: Double): DoubleParam = DoubleParam(x)
implicit def fromStringToStringParam(x: String): StringParam = StringParam(x)
+
+ implicit class ChiselRange(val sc: StringContext) extends AnyVal {
+ /** Specifies a range using mathematical range notation. Variables can be interpolated using
+ * standard string interpolation syntax.
+ * @example {{{
+ * UInt(range"[0, 2)")
+ * UInt(range"[0, $myInt)")
+ * UInt(range"[0, ${myInt + 2})")
+ * }}}
+ */
+ def range(args: Any*): (NumericBound[Int], NumericBound[Int]) = macro chisel3.internal.RangeTransform.apply
+ }
}
}
diff --git a/src/test/scala/chiselTests/RangeSpec.scala b/src/test/scala/chiselTests/RangeSpec.scala
new file mode 100644
index 00000000..e2313f34
--- /dev/null
+++ b/src/test/scala/chiselTests/RangeSpec.scala
@@ -0,0 +1,104 @@
+// See LICENSE for license details.
+
+package chiselTests
+
+import chisel3._
+import chisel3.experimental.ChiselRange
+
+import chisel3.internal.firrtl.{Open, Closed}
+import org.scalatest.{Matchers, FreeSpec}
+
+class RangeSpec extends FreeSpec with Matchers {
+ "Ranges can be specified for UInt, SInt, and FixedPoint" - {
+ "invalid range specifiers should fail at compile time" in {
+ assertDoesNotCompile(""" range"" """)
+ assertDoesNotCompile(""" range"[]" """)
+ assertDoesNotCompile(""" range"0" """)
+ assertDoesNotCompile(""" range"[0]" """)
+ assertDoesNotCompile(""" range"[0, 1" """)
+ assertDoesNotCompile(""" range"0, 1]" """)
+ assertDoesNotCompile(""" range"[0, 1, 2]" """)
+ assertDoesNotCompile(""" range"[a]" """)
+ assertDoesNotCompile(""" range"[a, b]" """)
+ assertCompiles(""" range"[0, 1]" """) // syntax sanity check
+ }
+
+ "range macros should allow open and closed bounds" in {
+ range"[-1, 1)" should be( (Closed(-1), Open(1)) )
+ range"[-1, 1]" should be( (Closed(-1), Closed(1)) )
+ range"(-1, 1]" should be( (Open(-1), Closed(1)) )
+ range"(-1, 1)" should be( (Open(-1), Open(1)) )
+ }
+
+ "range specifiers should be whitespace tolerant" in {
+ range"[-1,1)" should be( (Closed(-1), Open(1)) )
+ range" [-1,1) " should be( (Closed(-1), Open(1)) )
+ range" [ -1 , 1 ) " should be( (Closed(-1), Open(1)) )
+ range" [ -1 , 1 ) " should be( (Closed(-1), Open(1)) )
+ }
+
+ "range macros should work with interpolated variables" in {
+ val a = 10
+ val b = -3
+
+ range"[$b, $a)" should be( (Closed(b), Open(a)) )
+ range"[${a + b}, $a)" should be( (Closed(a + b), Open(a)) )
+ range"[${-3 - 7}, ${-3 + a})" should be( (Closed(-10), Open(-3 + a)) )
+
+ def number(n: Int): Int = n
+ range"[${number(1)}, ${number(3)})" should be( (Closed(1), Open(3)) )
+ }
+
+ "UInt should get the correct width from a range" in {
+ UInt(range"[0, 8)").getWidth should be (3)
+ UInt(range"[0, 8]").getWidth should be (4)
+ UInt(range"[0, 0]").getWidth should be (1)
+ }
+
+ "SInt should get the correct width from a range" in {
+ SInt(range"[0, 8)").getWidth should be (4)
+ SInt(range"[0, 8]").getWidth should be (5)
+ SInt(range"[-4, 4)").getWidth should be (3)
+ SInt(range"[0, 0]").getWidth should be (1)
+ }
+
+ "UInt should check that the range is valid" in {
+ an [IllegalArgumentException] should be thrownBy {
+ UInt(range"[1, 0]")
+ }
+ an [IllegalArgumentException] should be thrownBy {
+ UInt(range"[-1, 1]")
+ }
+ an [IllegalArgumentException] should be thrownBy {
+ UInt(range"(0,0]")
+ }
+ an [IllegalArgumentException] should be thrownBy {
+ UInt(range"[0,0)")
+ }
+ an [IllegalArgumentException] should be thrownBy {
+ UInt(range"(0,0)")
+ }
+ an [IllegalArgumentException] should be thrownBy {
+ UInt(range"(0,1)")
+ }
+ }
+
+ "SInt should check that the range is valid" in {
+ an [IllegalArgumentException] should be thrownBy {
+ SInt(range"[1, 0]")
+ }
+ an [IllegalArgumentException] should be thrownBy {
+ SInt(range"(0,0]")
+ }
+ an [IllegalArgumentException] should be thrownBy {
+ SInt(range"[0,0)")
+ }
+ an [IllegalArgumentException] should be thrownBy {
+ SInt(range"(0,0)")
+ }
+ an [IllegalArgumentException] should be thrownBy {
+ SInt(range"(0,1)")
+ }
+ }
+ }
+}