diff options
| author | Jack Koenig | 2022-01-10 10:39:52 -0800 |
|---|---|---|
| committer | Jack Koenig | 2022-01-10 15:53:55 -0800 |
| commit | 3131c0daad41dea78bede4517669e376c41a325a (patch) | |
| tree | 55baed78a6a01f80ff3952a08233ca553a19964f /src/main/scala/chisel3/util/experimental | |
| parent | dd36f97a82746cec0b25b94651581fe799e24579 (diff) | |
Apply scalafmt
Command:
sbt scalafmtAll
Diffstat (limited to 'src/main/scala/chisel3/util/experimental')
11 files changed, 255 insertions, 192 deletions
diff --git a/src/main/scala/chisel3/util/experimental/BoringUtils.scala b/src/main/scala/chisel3/util/experimental/BoringUtils.scala index f2a3e757..254f83a4 100644 --- a/src/main/scala/chisel3/util/experimental/BoringUtils.scala +++ b/src/main/scala/chisel3/util/experimental/BoringUtils.scala @@ -3,11 +3,11 @@ package chisel3.util.experimental import chisel3._ -import chisel3.experimental.{ChiselAnnotation, RunFirrtlTransform, annotate} +import chisel3.experimental.{annotate, ChiselAnnotation, RunFirrtlTransform} import chisel3.internal.{InstanceId, NamedComponent, Namespace} import firrtl.transforms.{DontTouchAnnotation, NoDedupAnnotation} -import firrtl.passes.wiring.{WiringTransform, SourceAnnotation, SinkAnnotation} -import firrtl.annotations.{ModuleName, ComponentName} +import firrtl.passes.wiring.{SinkAnnotation, SourceAnnotation, WiringTransform} +import firrtl.annotations.{ComponentName, ModuleName} import scala.concurrent.SyncVar @@ -122,20 +122,25 @@ object BoringUtils { * @note if a uniqueName is not specified, the returned name may differ from the user-provided name */ def addSource( - component: NamedComponent, - name: String, + component: NamedComponent, + name: String, disableDedup: Boolean = false, - uniqueName: Boolean = false): String = { + uniqueName: Boolean = false + ): String = { - val id = if (uniqueName) { newName(name) } else { name } + val id = if (uniqueName) { newName(name) } + else { name } val maybeDedup = if (disableDedup) { Seq(new ChiselAnnotation { def toFirrtl = NoDedupAnnotation(component.toNamed.module) }) } - else { Seq[ChiselAnnotation]() } + else { Seq[ChiselAnnotation]() } val annotations = - Seq(new ChiselAnnotation with RunFirrtlTransform { - def toFirrtl = SourceAnnotation(component.toNamed, id) - def transformClass = classOf[WiringTransform] }, - new ChiselAnnotation { def toFirrtl = DontTouchAnnotation(component.toNamed) } ) ++ maybeDedup + Seq( + new ChiselAnnotation with RunFirrtlTransform { + def toFirrtl = SourceAnnotation(component.toNamed, id) + def transformClass = classOf[WiringTransform] + }, + new ChiselAnnotation { def toFirrtl = DontTouchAnnotation(component.toNamed) } + ) ++ maybeDedup annotations.foreach(annotate(_)) id @@ -150,25 +155,28 @@ object BoringUtils { * @throws BoringUtilsException if name is expected to exist and it doesn't */ def addSink( - component: InstanceId, - name: String, + component: InstanceId, + name: String, disableDedup: Boolean = false, - forceExists: Boolean = false): Unit = { + forceExists: Boolean = false + ): Unit = { if (forceExists && !checkName(name)) { - throw new BoringUtilsException(s"Sink ID '$name' not found in BoringUtils ID namespace") } + throw new BoringUtilsException(s"Sink ID '$name' not found in BoringUtils ID namespace") + } def moduleName = component.toNamed match { - case c: ModuleName => c + case c: ModuleName => c case c: ComponentName => c.module case _ => throw new ChiselException("Can only add a Module or Component sink", null) } val maybeDedup = if (disableDedup) { Seq(new ChiselAnnotation { def toFirrtl = NoDedupAnnotation(moduleName) }) } - else { Seq[ChiselAnnotation]() } + else { Seq[ChiselAnnotation]() } val annotations = Seq(new ChiselAnnotation with RunFirrtlTransform { - def toFirrtl = SinkAnnotation(component.toNamed, name) - def transformClass = classOf[WiringTransform] }) ++ maybeDedup + def toFirrtl = SinkAnnotation(component.toNamed, name) + def transformClass = classOf[WiringTransform] + }) ++ maybeDedup annotations.foreach(annotate(_)) } @@ -181,11 +189,12 @@ object BoringUtils { * component */ def bore(source: Data, sinks: Seq[Data]): String = { - val boringName = try { - source.instanceName - } catch { - case _: Exception => "bore" - } + val boringName = + try { + source.instanceName + } catch { + case _: Exception => "bore" + } val genName = addSource(source, boringName, true, true) sinks.foreach(addSink(_, genName, true, true)) genName diff --git a/src/main/scala/chisel3/util/experimental/ForceNames.scala b/src/main/scala/chisel3/util/experimental/ForceNames.scala index bac69ed4..53ee2bd2 100644 --- a/src/main/scala/chisel3/util/experimental/ForceNames.scala +++ b/src/main/scala/chisel3/util/experimental/ForceNames.scala @@ -2,7 +2,7 @@ package chisel3.util.experimental -import chisel3.experimental.{ChiselAnnotation, RunFirrtlTransform, annotate} +import chisel3.experimental.{annotate, ChiselAnnotation, RunFirrtlTransform} import firrtl.Mappers._ import firrtl._ import firrtl.annotations._ @@ -49,7 +49,7 @@ object forceName { * @param instance Instance to name */ def apply(instance: chisel3.experimental.BaseModule, name: String): Unit = { - annotate(new ChiselAnnotation with RunFirrtlTransform { + annotate(new ChiselAnnotation with RunFirrtlTransform { def toFirrtl = { val t = instance.toAbsoluteTarget ForceNameAnnotation(t, name) @@ -64,7 +64,7 @@ object forceName { * @param instance Signal to name */ def apply(instance: chisel3.experimental.BaseModule): Unit = { - annotate(new ChiselAnnotation with RunFirrtlTransform { + annotate(new ChiselAnnotation with RunFirrtlTransform { def toFirrtl = { val t = instance.toAbsoluteTarget ForceNameAnnotation(t, instance.instanceName) @@ -80,8 +80,7 @@ object forceName { * @param target signal/instance to force the name * @param name name to force it to be */ -case class ForceNameAnnotation(target: IsMember, name: String) - extends SingleTargetAnnotation[IsMember] { +case class ForceNameAnnotation(target: IsMember, name: String) extends SingleTargetAnnotation[IsMember] { def duplicate(n: IsMember): ForceNameAnnotation = this.copy(target = n, name) // Errors if renaming to multiple targets @@ -105,6 +104,7 @@ case class ForceNameAnnotation(target: IsMember, name: String) * Could (should?) be moved to FIRRTL. */ private object ForceNamesTransform { + /** Returns the [[IsModule]] which is referred to, or if a [[ReferenceTarget]], the enclosing [[IsModule]] * * @param a signal/instance/module @@ -123,10 +123,12 @@ private object ForceNamesTransform { */ def allInstancePaths(graph: InstanceKeyGraph): IsModule => List[List[(Instance, OfModule)]] = { val lookup: String => List[List[(Instance, OfModule)]] = - str => graph.findInstancesInHierarchy(str) - .view - .map(_.map(_.toTokens).toList) - .toList + str => + graph + .findInstancesInHierarchy(str) + .view + .map(_.map(_.toTokens).toList) + .toList allInstancePaths(lookup) _ } @@ -136,8 +138,10 @@ private object ForceNamesTransform { * @param target target to get all instance paths to * @return */ - def allInstancePaths(lookup: String => List[List[(Instance, OfModule)]]) - (target: IsModule): List[List[(Instance, OfModule)]] = { + def allInstancePaths( + lookup: String => List[List[(Instance, OfModule)]] + )(target: IsModule + ): List[List[(Instance, OfModule)]] = { target match { case ModuleTarget(circuit, module) => if (circuit == module) List(List((Instance(module), OfModule(module)))) @@ -149,16 +153,13 @@ private object ForceNamesTransform { } } - /** Builds the map of module name to map of old signal/instance name to new signal/instance name * * @param state CircuitState to operate on * @param igraph built instance key graph from state's circuit * @return */ - def buildForceNameMap(state: CircuitState, - igraph: => InstanceKeyGraph - ): Option[Map[String, Map[String, String]]] = { + def buildForceNameMap(state: CircuitState, igraph: => InstanceKeyGraph): Option[Map[String, Map[String, String]]] = { val forceNames = state.annotations.collect { case f: ForceNameAnnotation => f } val badNames = mutable.HashSet[ForceNameAnnotation]() val allNameMaps = forceNames.groupBy { case f => referringIsModule(f.target) }.mapValues { value => @@ -207,9 +208,9 @@ private object ForceNamesTransform { * - Use to avoid prefixing behavior on specific instances whose enclosing modules are inlined */ class ForceNamesTransform extends Transform with DependencyAPIMigration { - override def optionalPrerequisites: Seq[TransformDependency] = Seq(Dependency[InlineInstances]) + override def optionalPrerequisites: Seq[TransformDependency] = Seq(Dependency[InlineInstances]) override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters - override def prerequisites: Seq[TransformDependency] = Seq(Dependency(LowerTypes)) + override def prerequisites: Seq[TransformDependency] = Seq(Dependency(LowerTypes)) override def invalidates(a: Transform): Boolean = firrtl.passes.InferTypes == a import ForceNamesTransform._ @@ -226,22 +227,23 @@ class ForceNamesTransform extends Transform with DependencyAPIMigration { */ private def forceNamesInModule( modToNames: Map[String, Map[String, String]], - renameMap: RenameMap, - ct: CircuitTarget, - igraph: InstanceKeyGraph - )(mod: DefModule): DefModule = { + renameMap: RenameMap, + ct: CircuitTarget, + igraph: InstanceKeyGraph + )(mod: DefModule + ): DefModule = { val mt = ct.module(mod.name) val instToOfModule = mutable.HashMap[String, String]() val names = modToNames.getOrElse(mod.name, Map.empty[String, String]) // Need to find WRef referring to mems for prefixing def onExpr(expr: Expression): Expression = expr match { - case ref @ Reference(n, _,_,_) if names.contains(n) => + case ref @ Reference(n, _, _, _) if names.contains(n) => ref.copy(name = names(n)) - case sub @ SubField(WRef(i, _, _, _), p,_,_) if instToOfModule.contains(i) => + case sub @ SubField(WRef(i, _, _, _), p, _, _) if instToOfModule.contains(i) => val newsub = modToNames.get(instToOfModule(i)) match { case Some(map) if map.contains(p) => sub.copy(name = map(p)) - case _ => sub + case _ => sub } newsub.map(onExpr) case other => other.map(onExpr) @@ -269,17 +271,19 @@ class ForceNamesTransform extends Transform with DependencyAPIMigration { } else port } - val childInstanceHasRename = igraph.getChildInstanceMap(OfModule(mod.name)).exists { - o => modToNames.contains(o._2.value) + val childInstanceHasRename = igraph.getChildInstanceMap(OfModule(mod.name)).exists { o => + modToNames.contains(o._2.value) } - if(childInstanceHasRename || modToNames.contains(mod.name)) { + if (childInstanceHasRename || modToNames.contains(mod.name)) { val ns = Namespace(mod) val conflicts = names.values.collect { case k if ns.contains(k) => k } - if(conflicts.isEmpty) { + if (conflicts.isEmpty) { mod.map(onPort).map(onStmt) } else { - throw new FirrtlUserException(s"Cannot force the following names in module ${mod.name} because they conflict: ${conflicts.mkString(",")}") + throw new FirrtlUserException( + s"Cannot force the following names in module ${mod.name} because they conflict: ${conflicts.mkString(",")}" + ) } } else mod } diff --git a/src/main/scala/chisel3/util/experimental/Inline.scala b/src/main/scala/chisel3/util/experimental/Inline.scala index 1d5fcb89..fd5c6aa5 100644 --- a/src/main/scala/chisel3/util/experimental/Inline.scala +++ b/src/main/scala/chisel3/util/experimental/Inline.scala @@ -6,7 +6,7 @@ import chisel3._ import chisel3.experimental.{BaseModule, ChiselAnnotation, RunFirrtlTransform} import firrtl.Transform import firrtl.passes.{InlineAnnotation, InlineInstances} -import firrtl.transforms.{NoDedupAnnotation, FlattenAnnotation, Flatten} +import firrtl.transforms.{Flatten, FlattenAnnotation, NoDedupAnnotation} import firrtl.annotations.Annotation /** Inlines an instance of a module @@ -40,11 +40,15 @@ import firrtl.annotations.Annotation * }}} */ trait InlineInstance { self: BaseModule => - Seq(new ChiselAnnotation with RunFirrtlTransform { - def toFirrtl: Annotation = InlineAnnotation(self.toNamed) - def transformClass: Class[_ <: Transform] = classOf[InlineInstances] }, - new ChiselAnnotation { - def toFirrtl: Annotation = NoDedupAnnotation(self.toNamed) }) + Seq( + new ChiselAnnotation with RunFirrtlTransform { + def toFirrtl: Annotation = InlineAnnotation(self.toNamed) + def transformClass: Class[_ <: Transform] = classOf[InlineInstances] + }, + new ChiselAnnotation { + def toFirrtl: Annotation = NoDedupAnnotation(self.toNamed) + } + ) .map(chisel3.experimental.annotate(_)) } @@ -75,10 +79,14 @@ trait InlineInstance { self: BaseModule => * }}} */ trait FlattenInstance { self: BaseModule => - Seq(new ChiselAnnotation with RunFirrtlTransform { - def toFirrtl: Annotation = FlattenAnnotation(self.toNamed) - def transformClass: Class[_ <: Transform] = classOf[Flatten] }, - new ChiselAnnotation { - def toFirrtl: Annotation = NoDedupAnnotation(self.toNamed) }) - .map(chisel3.experimental.annotate(_)) + Seq( + new ChiselAnnotation with RunFirrtlTransform { + def toFirrtl: Annotation = FlattenAnnotation(self.toNamed) + def transformClass: Class[_ <: Transform] = classOf[Flatten] + }, + new ChiselAnnotation { + def toFirrtl: Annotation = NoDedupAnnotation(self.toNamed) + } + ) + .map(chisel3.experimental.annotate(_)) } diff --git a/src/main/scala/chisel3/util/experimental/LoadMemoryTransform.scala b/src/main/scala/chisel3/util/experimental/LoadMemoryTransform.scala index 93981485..bd46abe9 100644 --- a/src/main/scala/chisel3/util/experimental/LoadMemoryTransform.scala +++ b/src/main/scala/chisel3/util/experimental/LoadMemoryTransform.scala @@ -3,7 +3,7 @@ package chisel3.util.experimental import chisel3._ -import chisel3.experimental.{RunFirrtlTransform, annotate, ChiselAnnotation} +import chisel3.experimental.{annotate, ChiselAnnotation, RunFirrtlTransform} import firrtl.annotations._ import firrtl.ir.{Module => _, _} import firrtl.transforms.BlackBoxInlineAnno @@ -21,11 +21,11 @@ import scala.collection.mutable case class ChiselLoadMemoryAnnotation[T <: Data]( target: MemBase[T], fileName: String, - hexOrBinary: MemoryLoadFileType.FileType = MemoryLoadFileType.Hex -) - extends ChiselAnnotation with RunFirrtlTransform { + hexOrBinary: MemoryLoadFileType.FileType = MemoryLoadFileType.Hex) + extends ChiselAnnotation + with RunFirrtlTransform { - if(fileName.isEmpty) { + if (fileName.isEmpty) { throw new Exception( s"""LoadMemory from file annotations file empty file name""" ) @@ -39,7 +39,6 @@ case class ChiselLoadMemoryAnnotation[T <: Data]( } } - /** [[loadMemoryFromFile]] is an annotation generator that helps with loading a memory from a text file as a bind module. This relies on * Verilator and Verilog's `\$readmemh` or `\$readmemb`. The [[https://github.com/freechipsproject/treadle Treadle * backend]] can also recognize this annotation and load memory at run-time. @@ -101,22 +100,20 @@ case class ChiselLoadMemoryAnnotation[T <: Data]( */ object loadMemoryFromFile { - /** Annotate a memory such that it can be initialized using a file * @param memory the memory * @param filename the file used for initialization * @param hexOrBinary whether the file uses a hex or binary number representation */ def apply[T <: Data]( - memory: MemBase[T], - fileName: String, + memory: MemBase[T], + fileName: String, hexOrBinary: MemoryLoadFileType.FileType = MemoryLoadFileType.Hex ): Unit = { annotate(ChiselLoadMemoryAnnotation(memory, fileName, hexOrBinary)) } } - /** [[loadMemoryFromFileInline]] is an annotation generator that helps with loading a memory from a text file inlined in * the Verilog module. This relies on Verilator and Verilog's `\$readmemh` or `\$readmemb`. * The [[https://github.com/freechipsproject/treadle Treadlebackend]] can also recognize this annotation and load memory at run-time. @@ -179,15 +176,14 @@ object loadMemoryFromFile { */ object loadMemoryFromFileInline { - /** Annotate a memory such that it can be initialized inline using a file * @param memory the memory * @param fileName the file used for initialization * @param hexOrBinary whether the file uses a hex or binary number representation */ def apply[T <: Data]( - memory: MemBase[T], - fileName: String, + memory: MemBase[T], + fileName: String, hexOrBinary: MemoryLoadFileType.FileType = MemoryLoadFileType.Hex ): Unit = { annotate(new ChiselAnnotation { @@ -204,14 +200,14 @@ object loadMemoryFromFileInline { * not need this transform to do that. */ class LoadMemoryTransform extends Transform { - def inputForm: CircuitForm = LowForm + def inputForm: CircuitForm = LowForm def outputForm: CircuitForm = LowForm private var memoryCounter: Int = -1 private val bindModules: mutable.ArrayBuffer[BlackBoxInlineAnno] = new mutable.ArrayBuffer() - private val verilogEmitter: VerilogEmitter = new VerilogEmitter + private val verilogEmitter: VerilogEmitter = new VerilogEmitter /** run the pass * @param circuit the circuit @@ -219,19 +215,19 @@ class LoadMemoryTransform extends Transform { * @return */ def run(circuit: Circuit, annotations: AnnotationSeq): Circuit = { - val groups = annotations - .collect{ case m: LoadMemoryAnnotation => m } + val groups = annotations.collect { case m: LoadMemoryAnnotation => m } .groupBy(_.target.serialize) - val memoryAnnotations = groups.map { case (key, annos) => + val memoryAnnotations = groups.map { + case (key, annos) => if (annos.size > 1) { throw new Exception( s"Multiple (${annos.size} found for memory $key one LoadMemoryAnnotation is allowed per memory" ) } key -> annos.head - } + } - val modulesByName = circuit.modules.collect { case module: firrtl.ir.Module => module.name -> module }.toMap + val modulesByName = circuit.modules.collect { case module: firrtl.ir.Module => module.name -> module }.toMap /* Walk the module and for memories that are annotated with [[LoadMemoryAnnotation]]s generate the bindable modules for * Verilog emission. @@ -251,32 +247,34 @@ class LoadMemoryTransform extends Transform { val writer = new java.io.StringWriter val readmem = hexOrBinary match { case MemoryLoadFileType.Binary => "$readmemb" - case MemoryLoadFileType.Hex => "$readmemh" + case MemoryLoadFileType.Hex => "$readmemh" } modulesByName.get(moduleName.name).foreach { module => - val renderer = verilogEmitter.getRenderer(module, modulesByName)(writer) - val loadFileName = lma.getFileName - - memoryCounter += 1 - val bindsToName = s"BindsTo_${memoryCounter}_${moduleName.name}" - renderer.emitVerilogBind(bindsToName, - s""" - |initial begin - | $readmem("$loadFileName", ${myModule.name}.$componentName); - |end - """.stripMargin) - val inLineText = writer.toString + "\n" + - s"""bind ${myModule.name} $bindsToName ${bindsToName}_Inst(.*);""" - - val blackBoxInline = BlackBoxInlineAnno( - moduleName, - moduleName.serialize + "." + componentName + ".v", - inLineText - ) - - bindModules += blackBoxInline - } + val renderer = verilogEmitter.getRenderer(module, modulesByName)(writer) + val loadFileName = lma.getFileName + + memoryCounter += 1 + val bindsToName = s"BindsTo_${memoryCounter}_${moduleName.name}" + renderer.emitVerilogBind( + bindsToName, + s""" + |initial begin + | $readmem("$loadFileName", ${myModule.name}.$componentName); + |end + """.stripMargin + ) + val inLineText = writer.toString + "\n" + + s"""bind ${myModule.name} $bindsToName ${bindsToName}_Inst(.*);""" + + val blackBoxInline = BlackBoxInlineAnno( + moduleName, + moduleName.serialize + "." + componentName + ".v", + inLineText + ) + + bindModules += blackBoxInline + } case _ => } @@ -284,8 +282,8 @@ class LoadMemoryTransform extends Transform { def processStatements(statement: Statement): Statement = { statement match { - case m: DefMemory => processMemory(m.name) - case s => s map processStatements + case m: DefMemory => processMemory(m.name) + case s => s.map(processStatements) } statement } @@ -299,7 +297,7 @@ class LoadMemoryTransform extends Transform { myModule } - circuit map processModule + circuit.map(processModule) } def execute(state: CircuitState): CircuitState = { @@ -309,11 +307,10 @@ class LoadMemoryTransform extends Transform { case _ => false } - if(isVerilog) { + if (isVerilog) { run(state.circuit, state.annotations) state.copy(annotations = state.annotations ++ bindModules) - } - else { + } else { state } } diff --git a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala index 4dcea99e..de2f207b 100644 --- a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala +++ b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala @@ -19,7 +19,7 @@ case object EspressoNotFoundException extends Exception */ object EspressoMinimizer extends Minimizer with LazyLogging { def minimize(table: TruthTable): TruthTable = - TruthTable.merge(TruthTable.split(table).map{case (table, indexes) => (espresso(table), indexes)}) + TruthTable.merge(TruthTable.split(table).map { case (table, indexes) => (espresso(table), indexes) }) private def espresso(table: TruthTable): TruthTable = { def writeTable(table: TruthTable): String = { @@ -34,10 +34,9 @@ object EspressoMinimizer extends Minimizer with LazyLogging { } val tableType: String = defaultType match { case '?' => "fr" - case _ => "fd" + case _ => "fd" } - val rawTable = table - .toString + val rawTable = table.toString .split("\n") .filter(_.contains("->")) .mkString("\n") @@ -69,11 +68,13 @@ object EspressoMinimizer extends Minimizer with LazyLogging { logger.trace(s"""espresso input table: |$input |""".stripMargin) - val output = try { - os.proc("espresso").call(stdin = input).out.chunks.mkString - } catch { - case e: java.io.IOException if e.getMessage.contains("error=2, No such file or directory") => throw EspressoNotFoundException - } + val output = + try { + os.proc("espresso").call(stdin = input).out.chunks.mkString + } catch { + case e: java.io.IOException if e.getMessage.contains("error=2, No such file or directory") => + throw EspressoNotFoundException + } logger.trace(s"""espresso output table: |$output |""".stripMargin) diff --git a/src/main/scala/chisel3/util/experimental/decode/Minimizer.scala b/src/main/scala/chisel3/util/experimental/decode/Minimizer.scala index 86847710..c4065ac9 100644 --- a/src/main/scala/chisel3/util/experimental/decode/Minimizer.scala +++ b/src/main/scala/chisel3/util/experimental/decode/Minimizer.scala @@ -3,6 +3,7 @@ package chisel3.util.experimental.decode abstract class Minimizer { + /** Minimize a multi-input multi-output logic function given by the truth table `table`, with function output values * on unspecified inputs treated as `default`, and return a minimized PLA-like representation of the function. * @@ -26,4 +27,4 @@ abstract class Minimizer { * }}} */ def minimize(table: TruthTable): TruthTable -}
\ No newline at end of file +} diff --git a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala index 59120221..a3481869 100644 --- a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala +++ b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala @@ -125,12 +125,15 @@ object QMCMinimizer extends Minimizer { * b: nonessential prime implicants * c: implicants that are not cover by any of the essential prime implicants */ - private def getEssentialPrimeImplicants(primes: Seq[Implicant], minterms: Seq[Implicant]): (Seq[Implicant], Seq[Implicant], Seq[Implicant]) = { + private def getEssentialPrimeImplicants( + primes: Seq[Implicant], + minterms: Seq[Implicant] + ): (Seq[Implicant], Seq[Implicant], Seq[Implicant]) = { // primeCovers(i): implicants that `prime(i)` covers val primeCovers = primes.map(p => minterms.filter(p.covers)) // eliminate prime implicants that can be covered by other prime implicants - for (((icover, pi), i) <- (primeCovers zip primes).zipWithIndex) { - for (((jcover, pj), _) <- (primeCovers zip primes).zipWithIndex.drop(i + 1)) { + for (((icover, pi), i) <- (primeCovers.zip(primes)).zipWithIndex) { + for (((jcover, pj), _) <- (primeCovers.zip(primes)).zipWithIndex.drop(i + 1)) { // we prefer prime implicants with wider implicants coverage if (icover.size > jcover.size && jcover.forall(pi.covers)) { // calculate essential prime implicants with `pj` eliminated from prime implicants table @@ -165,6 +168,7 @@ object QMCMinimizer extends Minimizer { * @return Selected nonessential prime implicants */ private def getCover(implicants: Seq[Implicant], minterms: Seq[Implicant]): Seq[Implicant] = { + /** Calculate the implementation cost (using comparators) of a list of implicants, more don't cares is cheaper * * @param cover Implicant list @@ -193,7 +197,8 @@ object QMCMinimizer extends Minimizer { * @return `a` < `b` */ @tailrec - def listLess(a: Seq[Implicant], b: Seq[Implicant]): Boolean = b.nonEmpty && (a.isEmpty || a.head < b.head || a.head == b.head && listLess(a.tail, b.tail)) + def listLess(a: Seq[Implicant], b: Seq[Implicant]): Boolean = + b.nonEmpty && (a.isEmpty || a.head < b.head || a.head == b.head && listLess(a.tail, b.tail)) ca < cb || ca == cb && listLess(a.sortWith(_ < _), b.sortWith(_ < _)) } @@ -216,8 +221,14 @@ object QMCMinimizer extends Minimizer { // extract decode table to inputs and outputs val (inputs, outputs) = table.table.unzip - require(outputs.map(_.getWidth == table.default.getWidth).reduce(_ && _), "All output BitPats and default BitPat must have the same length") - require(if (inputs.toSeq.length > 1) inputs.tail.map(_.width == inputs.head.width).reduce(_ && _) else true, "All input BitPats must have the same length") + require( + outputs.map(_.getWidth == table.default.getWidth).reduce(_ && _), + "All output BitPats and default BitPat must have the same length" + ) + require( + if (inputs.toSeq.length > 1) inputs.tail.map(_.width == inputs.head.width).reduce(_ && _) else true, + "All input BitPats must have the same length" + ) // make sure no two inputs specified in the truth table intersect for (t <- inputs.tails; if t.nonEmpty) @@ -234,9 +245,11 @@ object QMCMinimizer extends Minimizer { val outputBp = BitPat("b" + "?" * (m - i - 1) + "1" + "?" * i) // Minterms, implicants that makes the output to be 1 - val mint: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && t.value.testBit(i) }.map(_._1).map(toImplicant) + val mint: Seq[Implicant] = + table.table.filter { case (_, t) => t.mask.testBit(i) && t.value.testBit(i) }.map(_._1).map(toImplicant) // Maxterms, implicants that makes the output to be 0 - val maxt: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && !t.value.testBit(i) }.map(_._1).map(toImplicant) + val maxt: Seq[Implicant] = + table.table.filter { case (_, t) => t.mask.testBit(i) && !t.value.testBit(i) }.map(_._1).map(toImplicant) // Don't cares, implicants that can produce either 0 or 1 as output val dc: Seq[Implicant] = table.table.filter { case (_, t) => !t.mask.testBit(i) }.map(_._1).map(toImplicant) @@ -251,16 +264,14 @@ object QMCMinimizer extends Minimizer { implicants.foreach(_.isPrime = true) val cols = (0 to n).reverse.map(b => implicants.filter(b == _.bp.mask.bitCount)) - val mergeTable = cols.map( - c => (0 to n).map( - b => collection.mutable.Set(c.filter(b == _.bp.value.bitCount):_*) - ) - ) + val mergeTable = cols.map(c => (0 to n).map(b => collection.mutable.Set(c.filter(b == _.bp.value.bitCount): _*))) // O(n ^ 3) for (i <- 0 to n) { for (j <- 0 until n - i) { - mergeTable(i)(j).foreach(a => mergeTable(i + 1)(j) ++= mergeTable(i)(j + 1).filter(_ similar a).map(_ merge a)) + mergeTable(i)(j).foreach(a => + mergeTable(i + 1)(j) ++= mergeTable(i)(j + 1).filter(_.similar(a)).map(_.merge(a)) + ) } if (defaultToDc) { for (j <- 0 until n - i) { @@ -268,14 +279,14 @@ object QMCMinimizer extends Minimizer { if (a.bp.mask.testBit(i) && !a.bp.value.testBit(i)) { // this bit is `0` val t = new BitPat(a.bp.value.setBit(i), a.bp.mask, a.width) - if (!maxt.exists(_.intersects(t))) mergeTable(i + 1)(j) += t merge a + if (!maxt.exists(_.intersects(t))) mergeTable(i + 1)(j) += t.merge(a) } } for (a <- mergeTable(i)(j + 1).filter(_.isPrime)) { if (a.bp.mask.testBit(i) && a.bp.value.testBit(i)) { // this bit is `1` val t = new BitPat(a.bp.value.clearBit(i), a.bp.mask, a.width) - if (!maxt.exists(_.intersects(t))) mergeTable(i + 1)(j) += a merge t + if (!maxt.exists(_.intersects(t))) mergeTable(i + 1)(j) += a.merge(t) } } } @@ -288,20 +299,29 @@ object QMCMinimizer extends Minimizer { val (essentialPrimeImplicants, nonessentialPrimeImplicants, uncoveredImplicants) = getEssentialPrimeImplicants(primeImplicants, implicants) - (essentialPrimeImplicants ++ getCover(nonessentialPrimeImplicants, uncoveredImplicants)).map(a => (a.bp, outputBp)) + (essentialPrimeImplicants ++ getCover(nonessentialPrimeImplicants, uncoveredImplicants)).map(a => + (a.bp, outputBp) + ) }) - minimized.tail.foldLeft(table.copy(table = Seq(minimized.head))) { case (tb, t) => - 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.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) - }) - } else { - tb.copy(table = tb.table :+ t) - } + minimized.tail.foldLeft(table.copy(table = Seq(minimized.head))) { + case (tb, t) => + 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.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) + }) + } else { + tb.copy(table = tb.table :+ t) + } } } -}
\ No newline at end of file +} diff --git a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala index 322466f9..e742fd66 100644 --- a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala +++ b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala @@ -13,10 +13,11 @@ sealed class TruthTable private (val table: Seq[(BitPat, BitPat)], val default: def writeRow(map: (BitPat, BitPat)): String = s"${map._1.rawString}->${map._2.rawString}" - (table.map(writeRow) ++ Seq(s"${" "*(inputWidth + 2)}${default.rawString}")).mkString("\n") + (table.map(writeRow) ++ Seq(s"${" " * (inputWidth + 2)}${default.rawString}")).mkString("\n") } - def copy(table: Seq[(BitPat, BitPat)] = this.table, default: BitPat = this.default, sort: Boolean = this.sort) = TruthTable(table, default, sort) + def copy(table: Seq[(BitPat, BitPat)] = this.table, default: BitPat = this.default, sort: Boolean = this.sort) = + TruthTable(table, default, sort) override def equals(y: Any): Boolean = { y match { @@ -27,27 +28,36 @@ sealed class TruthTable private (val table: Seq[(BitPat, BitPat)], val default: } object TruthTable { + /** Convert a table and default output into a [[TruthTable]]. */ def apply(table: Iterable[(BitPat, BitPat)], default: BitPat, sort: Boolean = true): TruthTable = { require(table.map(_._1.getWidth).toSet.size == 1, "input width not equal.") require(table.map(_._2.getWidth).toSet.size == 1, "output width not equal.") val outputWidth = table.map(_._2.getWidth).head - val mergedTable = table.groupBy(_._1.toString).map { case (key, values) => - // merge same input inputs. - values.head._1 -> BitPat(s"b${ - Seq.tabulate(outputWidth) { i => - val outputSet = values.map(_._2) - .map(_.rawString) - .map(_ (i)) - .toSet - .filterNot(_ == '?') - 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 - }") - }.toSeq + val mergedTable = table + .groupBy(_._1.toString) + .map { + case (key, values) => + // merge same input inputs. + values.head._1 -> BitPat(s"b${Seq + .tabulate(outputWidth) { i => + val outputSet = values + .map(_._2) + .map(_.rawString) + .map(_(i)) + .toSet + .filterNot(_ == '?') + 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}") + } + .toSeq import BitPat.bitPatOrder - new TruthTable(if(sort) mergedTable.sorted else mergedTable, default, sort) + new TruthTable(if (sort) mergedTable.sorted else mergedTable, default, sort) } /** Parse TruthTable from its string representation. */ @@ -77,10 +87,17 @@ object TruthTable { 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( - table.table.map { case (in, out) => in -> bpFilter(out, indexes) }, - bpFilter(table.default, indexes) - ), indexes)) else None + if (indexes.nonEmpty) + Some( + ( + TruthTable( + table.table.map { case (in, out) => in -> bpFilter(out, indexes) }, + bpFilter(table.default, indexes) + ), + indexes + ) + ) + else None } def index(bitPat: BitPat, bpType: Char): Seq[Int] = @@ -99,7 +116,12 @@ object TruthTable { tables: Seq[(TruthTable, Seq[Int])] ): TruthTable = { def reIndex(bitPat: BitPat, table: TruthTable, indexes: Seq[Int]): Seq[(Char, Int)] = - table.table.map(a => a._1.toString -> a._2).collectFirst{ case (k, v) if k == bitPat.toString => v}.getOrElse(BitPat.dontCare(indexes.size)).rawString.zip(indexes) + table.table + .map(a => a._1.toString -> a._2) + .collectFirst { case (k, v) if k == bitPat.toString => v } + .getOrElse(BitPat.dontCare(indexes.size)) + .rawString + .zip(indexes) def bitPat(indexedChar: Seq[(Char, Int)]) = BitPat(s"b${indexedChar .sortBy(_._2) .map(_._1) diff --git a/src/main/scala/chisel3/util/experimental/decode/decoder.scala b/src/main/scala/chisel3/util/experimental/decode/decoder.scala index e0bf83b2..4feda672 100644 --- a/src/main/scala/chisel3/util/experimental/decode/decoder.scala +++ b/src/main/scala/chisel3/util/experimental/decode/decoder.scala @@ -3,13 +3,14 @@ package chisel3.util.experimental.decode import chisel3._ -import chisel3.experimental.{ChiselAnnotation, annotate} -import chisel3.util.{BitPat, pla} -import chisel3.util.experimental.{BitSet, getAnnotations} +import chisel3.experimental.{annotate, ChiselAnnotation} +import chisel3.util.{pla, BitPat} +import chisel3.util.experimental.{getAnnotations, BitSet} 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]]. @@ -71,7 +72,8 @@ object decoder extends LazyLogging { qmc(input, truthTable) } - try espresso(input, truthTable) catch { + 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) @@ -81,7 +83,6 @@ object decoder extends LazyLogging { } } - /** Generate a decoder circuit that matches the input to each bitSet. * * The resulting circuit functions like the following but is optimized with a logic minifier. @@ -104,9 +105,7 @@ object decoder extends LazyLogging { { bitSets.zipWithIndex.flatMap { case (bs, i) => - bs.terms.map(bp => - s"${bp.rawString}->${if (errorBit) "0"}${"0" * (bitSets.size - i - 1)}1${"0" * i}" - ) + bs.terms.map(bp => s"${bp.rawString}->${if (errorBit) "0"}${"0" * (bitSets.size - i - 1)}1${"0" * i}") } ++ Seq(s"${if (errorBit) "1"}${"?" * bitSets.size}") }.mkString("\n") ) diff --git a/src/main/scala/chisel3/util/experimental/getAnnotations.scala b/src/main/scala/chisel3/util/experimental/getAnnotations.scala index dc9b75ee..ac6e6bd1 100644 --- a/src/main/scala/chisel3/util/experimental/getAnnotations.scala +++ b/src/main/scala/chisel3/util/experimental/getAnnotations.scala @@ -4,6 +4,7 @@ import chisel3.internal.Builder import firrtl.AnnotationSeq object getAnnotations { + /** Returns the global Annotations */ def apply(): AnnotationSeq = Builder.annotationSeq } diff --git a/src/main/scala/chisel3/util/experimental/group.scala b/src/main/scala/chisel3/util/experimental/group.scala index e43115d0..202c95d8 100644 --- a/src/main/scala/chisel3/util/experimental/group.scala +++ b/src/main/scala/chisel3/util/experimental/group.scala @@ -3,7 +3,7 @@ package chisel3.util.experimental import chisel3._ -import chisel3.experimental.{ChiselAnnotation, RunFirrtlTransform, annotate} +import chisel3.experimental.{annotate, ChiselAnnotation, RunFirrtlTransform} import chisel3.internal.requireIsHardware import firrtl.Transform import firrtl.transforms.{GroupAnnotation, GroupComponents} @@ -46,12 +46,14 @@ object group { * @tparam T Parent type of input components */ def apply[T <: Data]( - components: Seq[T], - newModule: String, - newInstance: String, - outputSuffix: Option[String] = None, - inputSuffix: Option[String] = None - )(implicit compileOptions: CompileOptions): Unit = { + components: Seq[T], + newModule: String, + newInstance: String, + outputSuffix: Option[String] = None, + inputSuffix: Option[String] = None + )( + implicit compileOptions: CompileOptions + ): Unit = { if (compileOptions.checkSynthesizable) { components.foreach { data => requireIsHardware(data, s"Component ${data.toString} is marked to group, but is not bound.") @@ -64,4 +66,3 @@ object group { }) } } - |
