summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiuyang Liu2021-08-27 04:37:34 +0800
committerGitHub2021-08-26 20:37:34 +0000
commite74b978d5188d9cd28e3520912d858d228136e75 (patch)
tree1b391cb548b37b604c9aeb9dad39817deb805837
parent3840fec3d918f23df07a18311136ac6a1bc365e1 (diff)
add new APIs to BitPat (#2076)
* add Y and N to BitPat. * add ## for BitPat. * add rawString API. * use rawString in decoder * add select and slice to BitPat.
-rw-r--r--src/main/scala/chisel3/util/BitPat.scala53
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala2
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala2
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/TruthTable.scala18
-rw-r--r--src/test/scala/chiselTests/util/BitPatSpec.scala23
5 files changed, 78 insertions, 20 deletions
diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala
index 985d22da..0dcb2466 100644
--- a/src/main/scala/chisel3/util/BitPat.scala
+++ b/src/main/scala/chisel3/util/BitPat.scala
@@ -58,6 +58,22 @@ object BitPat {
*/
def dontCare(width: Int): BitPat = BitPat("b" + ("?" * width))
+ /** Creates a [[BitPat]] of all 1 of the specified bitwidth.
+ *
+ * @example {{{
+ * val myY = BitPat.Y(4) // equivalent to BitPat("b1111")
+ * }}}
+ */
+ def Y(width: Int = 1): BitPat = BitPat("b" + ("1" * width))
+
+ /** Creates a [[BitPat]] of all 0 of the specified bitwidth.
+ *
+ * @example {{{
+ * val myN = BitPat.N(4) // equivalent to BitPat("b0000")
+ * }}}
+ */
+ def N(width: Int = 1): BitPat = BitPat("b" + ("0" * width))
+
/** Allows BitPats to be used where a UInt is expected.
*
* @note the BitPat must not have don't care bits (will error out otherwise)
@@ -106,9 +122,11 @@ object BitPat {
*/
sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) extends SourceInfoDoc {
def getWidth: Int = width
+ def apply(x: Int): BitPat = macro SourceInfoTransform.xArg
+ def apply(x: Int, y: Int): BitPat = macro SourceInfoTransform.xyArg
def === (that: UInt): Bool = macro SourceInfoTransform.thatArg
def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg
-
+ def ## (that: BitPat): BitPat = macro SourceInfoTransform.thatArg
override def equals(obj: Any): Boolean = {
obj match {
case y: BitPat => value == y.value && mask == y.mask && getWidth == y.getWidth
@@ -117,6 +135,18 @@ sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) extends Sou
}
/** @group SourceInfoTransformMacro */
+ def do_apply(x: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): BitPat = {
+ do_apply(x, x)
+ }
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply(x: Int, y: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): BitPat = {
+ require(width > x && y >= 0, s"Invalid bit range ($x, $y), index should be bounded by (${width - 1}, 0)")
+ require(x >= y, s"Invalid bit range ($x, $y), x should be greater or equal to y.")
+ BitPat(s"b${rawString.slice(width - x - 1, width - y)}")
+ }
+
+ /** @group SourceInfoTransformMacro */
def do_=== (that: UInt)
(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = {
value.asUInt === (that & mask.asUInt)
@@ -126,12 +156,19 @@ sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) extends Sou
(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = {
!(this === that)
}
-
- override def toString = {
- "BitPat(" +
- (0 until width).map(i =>
- if (((mask >> i) & 1) == 1) if (((value >> i) & 1) == 1) "1" else "0" else "?"
- ).reverse.reduce(_ + _) +
- ")"
+ /** @group SourceInfoTransformMacro */
+ def do_##(that: BitPat)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): BitPat = {
+ new BitPat((value << that.getWidth) + that.value, (mask << that.getWidth) + that.mask, this.width + that.getWidth)
}
+
+ /** Generate raw string of a BitPat. */
+ def rawString: String = Seq.tabulate(width) { i =>
+ (value.testBit(width - i - 1), mask.testBit(width - i - 1)) match {
+ case (true, true) => "1"
+ case (false, true) => "0"
+ case (_, false) => "?"
+ }
+ }.mkString
+
+ override def toString = s"BitPat($rawString)"
}
diff --git a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala
index 3ecec048..1d725875 100644
--- a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala
@@ -18,7 +18,7 @@ object EspressoMinimizer extends Minimizer with LazyLogging {
.replace('1', '0')
.replace('t', '1')
val defaultType: Char = {
- val t = table.default.toString.drop(7).dropRight(1).toCharArray.distinct
+ val t = table.default.rawString.toCharArray.distinct
require(t.length == 1, "Internal Error: espresso only accept unified default type.")
t.head
}
diff --git a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala
index 54faa734..c1533f44 100644
--- a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala
@@ -286,7 +286,7 @@ object QMCMinimizer extends Minimizer {
if (tb.table.exists(x => x._1 == t._1)) {
tb.copy(table = tb.table.map { case (k, v) =>
if (k == t._1) {
- def ones(bitPat: BitPat) = bitPat.toString.drop(7).dropRight(1).zipWithIndex.collect{case ('1', x) => x}
+ def ones(bitPat: BitPat) = bitPat.rawString.zipWithIndex.collect{case ('1', x) => x}
(k, BitPat("b" + (0 until v.getWidth).map(i => if ((ones(v) ++ ones(t._2)).contains(i)) "1" else "?").mkString))
} else (k, v)
})
diff --git a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
index f4f200ce..683de16b 100644
--- a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
@@ -12,9 +12,9 @@ final class TruthTable(val table: Map[BitPat, BitPat], val default: BitPat) {
override def toString: String = {
def writeRow(map: (BitPat, BitPat)): String =
- s"${TruthTable.bpStr(map._1)}->${TruthTable.bpStr(map._2)}"
+ s"${map._1.rawString}->${map._2.rawString}"
- (table.map(writeRow) ++ Seq(s"${" "*(inputWidth + 2)}${TruthTable.bpStr(default)}")).toSeq.sorted.mkString("\n")
+ (table.map(writeRow) ++ Seq(s"${" "*(inputWidth + 2)}${default.rawString}")).toSeq.sorted.mkString("\n")
}
def copy(table: Map[BitPat, BitPat] = this.table, default: BitPat = this.default) = new TruthTable(table, default)
@@ -51,11 +51,11 @@ object TruthTable {
values.head._1 -> BitPat(s"b${
Seq.tabulate(outputWidth) { i =>
val outputSet = values.map(_._2)
- .map(bpStr)
+ .map(_.rawString)
.map(_ (i))
.toSet
.filterNot(_ == '?')
- require(outputSet.size != 2, s"TruthTable conflict in :\n${values.map { case (i, o) => s"${bpStr(i)}->${bpStr(o)}" }.mkString("\n")}")
+ require(outputSet.size != 2, s"TruthTable conflict in :\n${values.map { case (i, o) => s"${i.rawString}->${o.rawString}" }.mkString("\n")}")
outputSet.headOption.getOrElse('?')
}.mkString
}")
@@ -74,7 +74,7 @@ object TruthTable {
table: TruthTable
): Seq[(TruthTable, Seq[Int])] = {
def bpFilter(bitPat: BitPat, indexes: Seq[Int]): BitPat =
- BitPat(s"b${bpStr(bitPat).zipWithIndex.filter(b => indexes.contains(b._2)).map(_._1).mkString}")
+ BitPat(s"b${bitPat.rawString.zipWithIndex.filter(b => indexes.contains(b._2)).map(_._1).mkString}")
def tableFilter(indexes: Seq[Int]): Option[(TruthTable, Seq[Int])] = {
if(indexes.nonEmpty) Some((TruthTable(
@@ -84,7 +84,7 @@ object TruthTable {
}
def index(bitPat: BitPat, bpType: Char): Seq[Int] =
- bpStr(bitPat).zipWithIndex.filter(_._1 == bpType).map(_._2)
+ bitPat.rawString.zipWithIndex.filter(_._1 == bpType).map(_._2)
Seq('1', '0', '?').flatMap(t => tableFilter(index(table.default, t)))
}
@@ -99,7 +99,7 @@ object TruthTable {
tables: Seq[(TruthTable, Seq[Int])]
): TruthTable = {
def reIndex(bitPat: BitPat, table: TruthTable, indexes: Seq[Int]): Seq[(Char, Int)] =
- bpStr(table.table.map(a => a._1.toString -> a._2).getOrElse(bitPat.toString, BitPat.dontCare(indexes.size))).zip(indexes)
+ (table.table.map(a => a._1.toString -> a._2).getOrElse(bitPat.toString, BitPat.dontCare(indexes.size))).rawString.zip(indexes)
def bitPat(indexedChar: Seq[(Char, Int)]) = BitPat(s"b${indexedChar
.sortBy(_._2)
.map(_._1)
@@ -111,9 +111,7 @@ object TruthTable {
key -> bitPat(tables.flatMap { case (table, indexes) => reIndex(key, table, indexes) })
}
.toMap,
- bitPat(tables.flatMap { case (table, indexes) => bpStr(table.default).zip(indexes) })
+ bitPat(tables.flatMap { case (table, indexes) => table.default.rawString.zip(indexes) })
)
}
-
- private def bpStr(bitPat: BitPat) = bitPat.toString.drop(7).dropRight(1)
}
diff --git a/src/test/scala/chiselTests/util/BitPatSpec.scala b/src/test/scala/chiselTests/util/BitPatSpec.scala
index ca8dd85c..0c83493f 100644
--- a/src/test/scala/chiselTests/util/BitPatSpec.scala
+++ b/src/test/scala/chiselTests/util/BitPatSpec.scala
@@ -15,7 +15,30 @@ class BitPatSpec extends AnyFlatSpec with Matchers {
BitPat("b" + testPattern).toString should be (s"BitPat($testPattern)")
}
+ it should "convert a BitPat to raw form" in {
+ val testPattern = "0" * 32 + "1" * 32 + "?" * 32 + "?01" * 32
+ BitPat("b" + testPattern).rawString should be(testPattern)
+ }
+
it should "not fail if BitPat width is 0" in {
intercept[IllegalArgumentException]{BitPat("b")}
}
+
+ it should "contact BitPat via ##" in {
+ (BitPat.Y(4) ## BitPat.dontCare(3) ## BitPat.N(2)).toString should be (s"BitPat(1111???00)")
+ }
+
+ it should "index and return new BitPat" in {
+ val b = BitPat("b1001???")
+ b(0) should be(BitPat.dontCare(1))
+ b(6) should be(BitPat.Y())
+ b(5) should be(BitPat.N())
+ }
+
+ it should "slice and return new BitPat" in {
+ val b = BitPat("b1001???")
+ b(2, 0) should be(BitPat("b???"))
+ b(4, 3) should be(BitPat("b01"))
+ b(6, 6) should be(BitPat("b1"))
+ }
}