Skip to content

Commit

Permalink
feat: implement SerializableModuleElaborator (#4409)
Browse files Browse the repository at this point in the history
* feat: implement SerializableModuleElaborator

Signed-off-by: unlsycn <[email protected]>

* fix: return tuple of Readable from designImpl

Signed-off-by: unlsycn <[email protected]>

---------

Signed-off-by: unlsycn <[email protected]>
  • Loading branch information
unlsycn committed Sep 22, 2024
1 parent 15a25ff commit 2e4f69f
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: Apache-2.0

package chisel3.experimental.util

import geny.Readable

import chisel3.RawModule
import chisel3.experimental.{SerializableModule, SerializableModuleGenerator, SerializableModuleParameter}

import scala.reflect.runtime.universe
import scala.reflect.runtime.universe.{runtimeMirror, typeOf}

/** Mixin this trait to produce elaborators for [[SerializableModule]]
*/
trait SerializableModuleElaborator {

/**
* Implementation of a config API to serialize the [[SerializableModuleParameter]]
* @example
* {{{
* def config(parameter: MySerializableModuleParameter) =
* os.write.over(os.pwd / "config.json", configImpl(parameter))
* }}}
*/
def configImpl[P <: SerializableModuleParameter: universe.TypeTag](
parameter: P
)(
implicit rwP: upickle.default.Writer[P]
): Readable = upickle.default.write(parameter)

/**
* Implementation of a design API to elaborate [[SerializableModule]]
*
* @return A tuple of Readable, where the first is the firrtl and the second is the serializable annotations
* @example
* {{{
* def design(parameter: os.Path) = {
* val (firrtl, annos) = designImpl[MySerializableModule, MySerializableModuleParameter](os.read.stream(parameter))
* os.write.over(os.pwd / "GCD.fir", firrtl)
* os.write.over(os.pwd / "GCD.anno.json", annos)
* }
* }}}
*/
def designImpl[M <: SerializableModule[P]: universe.TypeTag, P <: SerializableModuleParameter: universe.TypeTag](
parameter: Readable
)(
implicit
rwP: upickle.default.Reader[P]
): (Readable, Readable) = {
var fir: firrtl.ir.Circuit = null
val annos = Seq(
new chisel3.stage.phases.Elaborate,
new chisel3.stage.phases.Convert
).foldLeft(
Seq(
chisel3.stage.ChiselGeneratorAnnotation(() =>
SerializableModuleGenerator(
runtimeMirror(getClass.getClassLoader)
.runtimeClass(typeOf[M].typeSymbol.asClass)
.asInstanceOf[Class[M]],
upickle.default.read[P](parameter)
).module().asInstanceOf[RawModule]
)
): firrtl.AnnotationSeq
) { case (annos, stage) => stage.transform(annos) }
.flatMap {
case firrtl.stage.FirrtlCircuitAnnotation(circuit) =>
fir = circuit
None
case _: firrtl.options.Unserializable => None
case a => Some(a)
}
val firrtlStream: Readable = fir.serialize
val annoStream: Readable = firrtl.annotations.JsonProtocol.serializeRecover(annos)
(firrtlStream, annoStream)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package chiselTests
package experimental

import chisel3._
import chiselTests.experimental.GCDSerializableModule
import chisel3.experimental.util.SerializableModuleElaborator
import geny.Readable
import upickle.default.read

class GCDSerializableModuleElaborator extends SerializableModuleElaborator {
val configPath = os.pwd / "config.json"
val firPath = os.pwd / "GCD.fir"
val annosPath = os.pwd / "GCD.anno.json"

def config(parameter: GCDSerializableModuleParameter) =
os.write.over(configPath, configImpl(parameter))

def design() = {
val (firrtl, annos) =
designImpl[GCDSerializableModule, GCDSerializableModuleParameter](os.read.stream(configPath))
os.write.over(firPath, firrtl)
os.write.over(annosPath, annos)
}
}

class SerializableModuleElaboratorSpec extends ChiselFlatSpec {
val elaborator = new GCDSerializableModuleElaborator
elaborator.config(GCDSerializableModuleParameter(16))
elaborator.design()

val firFile = os.read(elaborator.firPath)
val annosFile = os.read(elaborator.annosPath)

"SerializableModuleElaborator" should "elaborate firrtl" in {
firFile should include("module GCD")
}

"SerializableModuleElaborator" should "filter unserializable annotations" in {
(annosFile should not).include("UnserializeableAnnotation")
(annosFile should not).include("DesignAnnotation")
(annosFile should not).include("ChiselCircuitAnnotation")
}
}

0 comments on commit 2e4f69f

Please sign in to comment.