From 3691fe61cc43beb0e7d0f813723d4150daa79372 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Thu, 6 May 2021 16:20:50 +0000 Subject: add a simple decoder API. --- .../chisel3/util/experimental/decode/decoder.scala | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/main/scala/chisel3/util/experimental/decode/decoder.scala (limited to 'src/main/scala/chisel3/util/experimental/decode/decoder.scala') 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..2ef474e1 --- /dev/null +++ b/src/main/scala/chisel3/util/experimental/decode/decoder.scala @@ -0,0 +1,53 @@ +// 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 { + def apply(minimizer: Minimizer, input: UInt, truthTable: TruthTable): UInt = { + val minimizedTable = getAnnotations().collect { + case DecodeTableAnnotation(_, in, out) => TruthTable(in) -> TruthTable(out) + }.toMap.getOrElse( + { + logger.trace(s"""Decoder Cache Hit! + |${truthTable.table} + |""".stripMargin) + truthTable + }, { + val startTime = System.nanoTime() + val minimizedTable = minimizer.minimize(truthTable) + val totalTime = System.nanoTime() - startTime + val totalTimeInSeconds = totalTime / 1e9 + val info = f"Logic Minimize with $minimizer finished in ${totalTimeInSeconds} second" + if (totalTimeInSeconds > 5) + logger.error( + s"$info spends too long, consider using chisel3.util.experimental.DecodeTableAnnotation to cache decode result or switch to EspressoMinimizer." + ) + else logger.trace(info) + minimizedTable + } + ) + 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 + } + } +} -- cgit v1.2.3 From d2c71fbf64a4728914414bbf27803d7cf03f94ad Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Tue, 25 May 2021 04:54:14 +0000 Subject: async decoder with 5 seconds timeout. --- .../chisel3/util/experimental/decode/decoder.scala | 25 ++++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'src/main/scala/chisel3/util/experimental/decode/decoder.scala') diff --git a/src/main/scala/chisel3/util/experimental/decode/decoder.scala b/src/main/scala/chisel3/util/experimental/decode/decoder.scala index 2ef474e1..87e839d3 100644 --- a/src/main/scala/chisel3/util/experimental/decode/decoder.scala +++ b/src/main/scala/chisel3/util/experimental/decode/decoder.scala @@ -9,27 +9,34 @@ import chisel3.util.experimental.getAnnotations import firrtl.annotations.Annotation import logger.LazyLogging +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration.Duration +import scala.concurrent.{Await, Future} + object decoder extends LazyLogging { - def apply(minimizer: Minimizer, input: UInt, truthTable: TruthTable): UInt = { + def apply(minimizer: Minimizer, input: UInt, truthTable: TruthTable, timeout: Int = 5): UInt = { val minimizedTable = getAnnotations().collect { case DecodeTableAnnotation(_, in, out) => TruthTable(in) -> TruthTable(out) }.toMap.getOrElse( { - logger.trace(s"""Decoder Cache Hit! + logger.warn(s"""Decoder Cache Hit! |${truthTable.table} |""".stripMargin) truthTable }, { val startTime = System.nanoTime() - val minimizedTable = minimizer.minimize(truthTable) + val future = Future(minimizer.minimize(truthTable)) + var now = System.nanoTime() + while (!future.isCompleted) { + val elapsed = (System.nanoTime() - now) / 1e9 + now = System.nanoTime() + if(elapsed > timeout) logger.error(s"Minimizer has been executed for ${(System.nanoTime() - startTime) / 1e9} seconds.") + } + val minimizedTable = Await.result(future, Duration.Inf) val totalTime = System.nanoTime() - startTime val totalTimeInSeconds = totalTime / 1e9 - val info = f"Logic Minimize with $minimizer finished in ${totalTimeInSeconds} second" - if (totalTimeInSeconds > 5) - logger.error( - s"$info spends too long, consider using chisel3.util.experimental.DecodeTableAnnotation to cache decode result or switch to EspressoMinimizer." - ) - else logger.trace(info) + val info = f"Logic Minimize with $minimizer finished in $totalTimeInSeconds second" + logger.warn(info) minimizedTable } ) -- cgit v1.2.3 From 88b7c48c18267e55c755f4fe6615c2faf2910906 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Tue, 25 May 2021 07:22:32 +0000 Subject: remove all timeouts by review. --- .../chisel3/util/experimental/decode/decoder.scala | 30 ++-------------------- 1 file changed, 2 insertions(+), 28 deletions(-) (limited to 'src/main/scala/chisel3/util/experimental/decode/decoder.scala') diff --git a/src/main/scala/chisel3/util/experimental/decode/decoder.scala b/src/main/scala/chisel3/util/experimental/decode/decoder.scala index 87e839d3..8168824f 100644 --- a/src/main/scala/chisel3/util/experimental/decode/decoder.scala +++ b/src/main/scala/chisel3/util/experimental/decode/decoder.scala @@ -9,37 +9,11 @@ import chisel3.util.experimental.getAnnotations import firrtl.annotations.Annotation import logger.LazyLogging -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.duration.Duration -import scala.concurrent.{Await, Future} - object decoder extends LazyLogging { - def apply(minimizer: Minimizer, input: UInt, truthTable: TruthTable, timeout: Int = 5): UInt = { + def apply(minimizer: Minimizer, input: UInt, truthTable: TruthTable): UInt = { val minimizedTable = getAnnotations().collect { case DecodeTableAnnotation(_, in, out) => TruthTable(in) -> TruthTable(out) - }.toMap.getOrElse( - { - logger.warn(s"""Decoder Cache Hit! - |${truthTable.table} - |""".stripMargin) - truthTable - }, { - val startTime = System.nanoTime() - val future = Future(minimizer.minimize(truthTable)) - var now = System.nanoTime() - while (!future.isCompleted) { - val elapsed = (System.nanoTime() - now) / 1e9 - now = System.nanoTime() - if(elapsed > timeout) logger.error(s"Minimizer has been executed for ${(System.nanoTime() - startTime) / 1e9} seconds.") - } - val minimizedTable = Await.result(future, Duration.Inf) - val totalTime = System.nanoTime() - startTime - val totalTimeInSeconds = totalTime / 1e9 - val info = f"Logic Minimize with $minimizer finished in $totalTimeInSeconds second" - logger.warn(info) - minimizedTable - } - ) + }.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) -- cgit v1.2.3 From 695864f5716626a15a7798dae048d8301940a2db Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Thu, 15 Jul 2021 02:32:06 +0800 Subject: Espresso Decoder (#1964) Co-authored-by: Haoran Yuan Co-authored-by: Boyang Han --- .../chisel3/util/experimental/decode/decoder.scala | 49 ++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'src/main/scala/chisel3/util/experimental/decode/decoder.scala') diff --git a/src/main/scala/chisel3/util/experimental/decode/decoder.scala b/src/main/scala/chisel3/util/experimental/decode/decoder.scala index 8168824f..42e374d1 100644 --- a/src/main/scala/chisel3/util/experimental/decode/decoder.scala +++ b/src/main/scala/chisel3/util/experimental/decode/decoder.scala @@ -10,6 +10,13 @@ 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) @@ -31,4 +38,46 @@ object decoder extends LazyLogging { 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) + } + } } -- cgit v1.2.3