summaryrefslogtreecommitdiff
path: root/src/main/scala/chisel3/util/experimental/decode/decoder.scala
diff options
context:
space:
mode:
authorJack Koenig2021-09-17 21:01:26 -0700
committerJack Koenig2021-09-17 21:01:26 -0700
commit5c8c19345e6711279594cf1f9ddab33623c8eba7 (patch)
treed9d6ced3934aa4a8be3dec19ddcefe50a7a93d5a /src/main/scala/chisel3/util/experimental/decode/decoder.scala
parente63b9667d89768e0ec6dc8a9153335cb48a213a7 (diff)
parent958904cb2f2f65d02b2ab3ec6d9ec2e06d04e482 (diff)
Merge branch 'master' into 3.5-release
Diffstat (limited to 'src/main/scala/chisel3/util/experimental/decode/decoder.scala')
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/decoder.scala83
1 files changed, 83 insertions, 0 deletions
diff --git a/src/main/scala/chisel3/util/experimental/decode/decoder.scala b/src/main/scala/chisel3/util/experimental/decode/decoder.scala
new file mode 100644
index 00000000..42e374d1
--- /dev/null
+++ b/src/main/scala/chisel3/util/experimental/decode/decoder.scala
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3.util.experimental.decode
+
+import chisel3._
+import chisel3.experimental.{ChiselAnnotation, annotate}
+import chisel3.util.{BitPat, pla}
+import chisel3.util.experimental.getAnnotations
+import firrtl.annotations.Annotation
+import logger.LazyLogging
+
+object decoder extends LazyLogging {
+ /** Use a specific [[Minimizer]] to generated decoded signals.
+ *
+ * @param minimizer specific [[Minimizer]], can be [[QMCMinimizer]] or [[EspressoMinimizer]].
+ * @param input input signal that contains decode table input
+ * @param truthTable [[TruthTable]] to decode user input.
+ * @return decode table output.
+ */
+ def apply(minimizer: Minimizer, input: UInt, truthTable: TruthTable): UInt = {
+ val minimizedTable = getAnnotations().collect {
+ case DecodeTableAnnotation(_, in, out) => TruthTable(in) -> TruthTable(out)
+ }.toMap.getOrElse(truthTable, minimizer.minimize(truthTable))
+ if (minimizedTable.table.isEmpty) {
+ val outputs = Wire(UInt(minimizedTable.default.getWidth.W))
+ outputs := minimizedTable.default.value.U(minimizedTable.default.getWidth.W)
+ outputs
+ } else {
+ val (plaInput, plaOutput) =
+ pla(minimizedTable.table.toSeq, BitPat(minimizedTable.default.value.U(minimizedTable.default.getWidth.W)))
+
+ annotate(new ChiselAnnotation {
+ override def toFirrtl: Annotation =
+ DecodeTableAnnotation(plaOutput.toTarget, truthTable.toString, minimizedTable.toString)
+ })
+
+ plaInput := input
+ plaOutput
+ }
+ }
+
+ /** Use [[EspressoMinimizer]] to generated decoded signals.
+ *
+ * @param input input signal that contains decode table input
+ * @param truthTable [[TruthTable]] to decode user input.
+ * @return decode table output.
+ */
+ def espresso(input: UInt, truthTable: TruthTable): UInt = apply(EspressoMinimizer, input, truthTable)
+
+ /** Use [[QMCMinimizer]] to generated decoded signals.
+ *
+ * @param input input signal that contains decode table input
+ * @param truthTable [[TruthTable]] to decode user input.
+ * @return decode table output.
+ */
+ def qmc(input: UInt, truthTable: TruthTable): UInt = apply(QMCMinimizer, input, truthTable)
+
+ /** try to use [[EspressoMinimizer]] to decode `input` by `truthTable`
+ * if `espresso` not exist in your PATH environment it will fall back to [[QMCMinimizer]], and print a warning.
+ *
+ * @param input input signal that contains decode table input
+ * @param truthTable [[TruthTable]] to decode user input.
+ * @return decode table output.
+ */
+ def apply(input: UInt, truthTable: TruthTable): UInt = {
+ def qmcFallBack(input: UInt, truthTable: TruthTable) = {
+ """fall back to QMC.
+ |Quine-McCluskey is a NP complete algorithm, may run forever or run out of memory in large decode tables.
+ |To get rid of this warning, please use `decoder.qmc` directly, or add espresso to your PATH.
+ |""".stripMargin
+ qmc(input, truthTable)
+ }
+
+ try espresso(input, truthTable) catch {
+ case EspressoNotFoundException =>
+ logger.error(s"espresso is not found in your PATH:\n${sys.env("PATH").split(":").mkString("\n")}".stripMargin)
+ qmcFallBack(input, truthTable)
+ case e: java.io.IOException =>
+ logger.error(s"espresso failed to run with ${e.getMessage}")
+ qmcFallBack(input, truthTable)
+ }
+ }
+}