Refactor tapeout for Chisel 3.4, Firrtl 1.4
- Remove clk package based on discussion with Colin - Annotations need to be refactored to using latest API - Generally that involves making annos generated by a anonymous ChiselAnnotation - The chisel annotations will use RunFirrtlTransform to queue up its associated transform - Chisel annotation provieds toFirrtl to generate Firrtl form of annotation - Usages of unapply on firrtl annotations cannot use generic unapply(target, transform, data) which has been eliminated - Have transforms use with DependencyAPIMigration to avoid deprecated `form`s - Added some 'see License comments - TechnologyLocation section of AddIOPadsSpec does not currently run because there is no content for it. - Added some tests for annotation serialization here
This commit is contained in:
@@ -3,24 +3,19 @@
|
||||
package barstools.tapeout.transforms.pads
|
||||
|
||||
import firrtl._
|
||||
import firrtl.annotations._
|
||||
import firrtl.passes._
|
||||
import firrtl.ir._
|
||||
import barstools.tapeout.transforms._
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
// Main Add IO Pad transform operates on low Firrtl
|
||||
class AddIOPadsTransform extends Transform with SeqTransformBased {
|
||||
|
||||
override def inputForm: CircuitForm = LowForm
|
||||
override def outputForm: CircuitForm = LowForm
|
||||
class AddIOPadsTransform extends Transform with SeqTransformBased with DependencyAPIMigration {
|
||||
|
||||
val transformList = new mutable.ArrayBuffer[Transform]
|
||||
def transforms: Seq[Transform] = transformList
|
||||
|
||||
override def execute(state: CircuitState): CircuitState = {
|
||||
val collectedAnnos = HasPadAnnotation(getMyAnnotations(state))
|
||||
val collectedAnnos = HasPadAnnotation(state.annotations)
|
||||
collectedAnnos match {
|
||||
// Transform not used
|
||||
case None => state
|
||||
|
||||
@@ -77,7 +77,12 @@ abstract class TopModule(
|
||||
// Annotate IO with side + pad name
|
||||
def annotatePad(sig: Element, side: PadSide = defaultPadSide, name: String = ""): Unit = if (usePads) {
|
||||
val anno = IOPadAnnotation(side.serialize, name)
|
||||
annotate(TargetIOPadAnnoC(sig, anno))
|
||||
annotate(new ChiselAnnotation with RunFirrtlTransform {
|
||||
override def toFirrtl: Annotation = {
|
||||
TargetIOPadAnnoF(sig.toTarget, anno)
|
||||
}
|
||||
def transformClass: Class[_ <: Transform] = classOf[AddIOPadsTransform]
|
||||
})
|
||||
}
|
||||
def annotatePad(sig: Aggregate, name: String): Unit = annotatePad(sig, side = defaultPadSide, name)
|
||||
def annotatePad(sig: Aggregate, side: PadSide): Unit = annotatePad(sig, side, name = "")
|
||||
@@ -86,7 +91,16 @@ abstract class TopModule(
|
||||
|
||||
// There may be cases where pads were inserted elsewhere. If that's the case, allow certain IO to
|
||||
// not have pads auto added. Note that annotatePad and noPad are mutually exclusive!
|
||||
def noPad(sig: Element): Unit = if (usePads) annotate(TargetIOPadAnnoC(sig, NoIOPadAnnotation()))
|
||||
def noPad(sig: Element): Unit = {
|
||||
if (usePads) {
|
||||
annotate(new ChiselAnnotation with RunFirrtlTransform {
|
||||
override def toFirrtl: Annotation = {
|
||||
TargetIOPadAnnoF(sig.toTarget, NoIOPadAnnotation())
|
||||
}
|
||||
def transformClass: Class[_ <: Transform] = classOf[AddIOPadsTransform]
|
||||
})
|
||||
}
|
||||
}
|
||||
def noPad(sig: Aggregate): Unit = extractElements(sig) foreach { x => noPad(x) }
|
||||
|
||||
// Since this is a super class, this should be the first thing that gets run
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package barstools.tapeout.transforms.pads
|
||||
|
||||
import net.jcazevedo.moultingyaml._
|
||||
@@ -85,8 +87,9 @@ object FoundryPadsYaml extends DefaultYamlProtocol {
|
||||
implicit val _pad = yamlFormat6(FoundryPad)
|
||||
def parse(techDir: String): Seq[FoundryPad] = {
|
||||
val file = techDir + exampleResource
|
||||
if(techDir != "" && !(new java.io.File(file)).exists())
|
||||
throw new Exception("Technology directory must contain FoundryPads.yaml!")
|
||||
if(techDir != "" && !(new java.io.File(file)).exists()) {
|
||||
throw new Exception(s"Technology directory $techDir must contain FoundryPads.yaml!")
|
||||
}
|
||||
val out = (new YamlFileReader(exampleResource)).parse[FoundryPad](if (techDir == "") "" else file)
|
||||
val padNames = out.map(x => x.correctedName)
|
||||
require(padNames.distinct.length == padNames.length, "Pad names must be unique!")
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
package barstools.tapeout.transforms.pads
|
||||
|
||||
import firrtl.annotations._
|
||||
import chisel3.experimental._
|
||||
import chisel3._
|
||||
|
||||
import net.jcazevedo.moultingyaml._
|
||||
|
||||
object PadAnnotationsYaml extends DefaultYamlProtocol {
|
||||
@@ -13,6 +10,17 @@ object PadAnnotationsYaml extends DefaultYamlProtocol {
|
||||
implicit val _noiopad = yamlFormat1(NoIOPadAnnotation)
|
||||
implicit val _supplyanno = yamlFormat5(SupplyAnnotation)
|
||||
implicit val _modulepadanno = yamlFormat4(ModulePadAnnotation)
|
||||
|
||||
// Putting these serialize methods here seems to fix warnings about missing implicits for the toYaml
|
||||
def serialize(noIOPad: NoIOPadAnnotation): String = {
|
||||
noIOPad.toYaml.prettyPrint
|
||||
}
|
||||
def serialize(ioPadAnnotation: IOPadAnnotation): String = {
|
||||
ioPadAnnotation.toYaml.prettyPrint
|
||||
}
|
||||
def serialize(modulePadAnnotation: ModulePadAnnotation): String = {
|
||||
modulePadAnnotation.toYaml.prettyPrint
|
||||
}
|
||||
}
|
||||
|
||||
abstract class FirrtlPadTransformAnnotation {
|
||||
@@ -25,14 +33,12 @@ abstract class IOAnnotation {
|
||||
}
|
||||
|
||||
case class IOPadAnnotation(padSide: String, padName: String) extends IOAnnotation {
|
||||
import PadAnnotationsYaml._
|
||||
def serialize: String = this.toYaml.prettyPrint
|
||||
def serialize: String = PadAnnotationsYaml.serialize(this)
|
||||
def getPadSide: PadSide = HasPadAnnotation.getSide(padSide)
|
||||
}
|
||||
|
||||
case class NoIOPadAnnotation(noPad: String = "") extends IOAnnotation {
|
||||
import PadAnnotationsYaml._
|
||||
def serialize: String = this.toYaml.prettyPrint
|
||||
def serialize: String = PadAnnotationsYaml.serialize(this)
|
||||
def field: String = "noPad:"
|
||||
}
|
||||
|
||||
@@ -44,12 +50,6 @@ case class TargetIOPadAnnoF(target: ComponentName, anno: IOAnnotation)
|
||||
def targetName: String = target.name
|
||||
}
|
||||
|
||||
//TODO: PORT-1.4: Remove commented code
|
||||
// Chisel version
|
||||
//case class TargetIOPadAnnoC(target: Element, anno: IOAnnotation) extends ChiselAnnotation {
|
||||
// def toFirrtl = TargetIOPadAnnoF(target.toNamed, anno)
|
||||
//}
|
||||
|
||||
// A bunch of supply pads (designated by name, # on each chip side) can be associated with the top module
|
||||
case class SupplyAnnotation(
|
||||
padName: String,
|
||||
@@ -64,9 +64,9 @@ case class ModulePadAnnotation(
|
||||
coreWidth: Int = 0,
|
||||
coreHeight: Int = 0,
|
||||
supplyAnnos: Seq[SupplyAnnotation] = Seq.empty) {
|
||||
import PadAnnotationsYaml._
|
||||
def serialize: String = this.toYaml.prettyPrint
|
||||
val supplyPadNames = supplyAnnos.map(_.padName)
|
||||
|
||||
def serialize: String = PadAnnotationsYaml.serialize(this)
|
||||
def supplyPadNames: Seq[String] = supplyAnnos.map(_.padName)
|
||||
require(supplyPadNames.distinct.length == supplyPadNames.length, "Supply pads should only be specified once!")
|
||||
def getDefaultPadSide: PadSide = HasPadAnnotation.getSide(defaultPadSide)
|
||||
}
|
||||
@@ -91,7 +91,6 @@ case class CollectedAnnos(
|
||||
}
|
||||
|
||||
object HasPadAnnotation {
|
||||
import PadAnnotationsYaml._
|
||||
|
||||
def getSide(a: String): PadSide = a match {
|
||||
case i if i == Left.serialize => Left
|
||||
@@ -115,26 +114,13 @@ object HasPadAnnotation {
|
||||
// case _ => None
|
||||
// }
|
||||
|
||||
//scalastyle:off cyclomatic.complexity
|
||||
def unapply(a: Annotation): Option[FirrtlPadTransformAnnotation] = a match {
|
||||
case hasTransform: RunFirrtlTransform if hasTransform.transformClass == classOf[AddIOPadsTransform] =>
|
||||
hasTransform match {
|
||||
case hasTarget: SingleTargetAnnotation[_] =>
|
||||
hasTarget.target match {
|
||||
case m: ModuleName =>
|
||||
Some(TargetModulePadAnnoF(m, s.parseYaml.convertTo[ModulePadAnnotation]))
|
||||
hasTarget match {
|
||||
case _ => None
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
case _ => None
|
||||
}
|
||||
|
||||
def apply(annos: Seq[Annotation]): Option[CollectedAnnos] = {
|
||||
// Get all pad-related annotations (config files, pad sides, pad names, etc.)
|
||||
val padAnnos = annos.map(x => unapply(x)).flatten
|
||||
val padAnnos = annos.flatMap {
|
||||
case a: TargetModulePadAnnoF => Some(a)
|
||||
case a: TargetIOPadAnnoF => Some(a)
|
||||
case _ => None
|
||||
}
|
||||
val targets = padAnnos.map(x => x.targetName)
|
||||
require(targets.distinct.length == targets.length, "Only 1 pad related annotation is allowed per component/module")
|
||||
if (padAnnos.length == 0) {
|
||||
|
||||
@@ -7,7 +7,6 @@ import firrtl.ir._
|
||||
import firrtl.annotations._
|
||||
import firrtl.Mappers._
|
||||
|
||||
|
||||
case class KeepNameAnnotation(target: ModuleTarget)
|
||||
extends SingleTargetAnnotation[ModuleTarget] {
|
||||
def duplicate(n: ModuleTarget) = this.copy(n)
|
||||
@@ -22,9 +21,7 @@ case class ModuleNameSuffixAnnotation(target: CircuitTarget, suffix: String)
|
||||
// Verilog black box and therefore can't be renamed. Since the point is to
|
||||
// allow FIRRTL to be linked together using "cat" and ExtModules don't get
|
||||
// emitted, this should be safe.
|
||||
class AddSuffixToModuleNames extends Transform {
|
||||
def inputForm = LowForm
|
||||
def outputForm = LowForm
|
||||
class AddSuffixToModuleNames extends Transform with DependencyAPIMigration {
|
||||
|
||||
def processAnnos(annos: AnnotationSeq): (AnnotationSeq, (String) => String) = {
|
||||
val whitelist = annos.collect({ case KeepNameAnnotation(tgt) => tgt.module }).toSet
|
||||
|
||||
@@ -20,10 +20,10 @@ class EnumerateModulesPass(enumerate: (Module) => Unit) extends Pass {
|
||||
}
|
||||
}
|
||||
|
||||
class EnumerateModules(enumerate: (Module) => Unit) extends Transform with SeqTransformBased {
|
||||
def inputForm = LowForm
|
||||
def outputForm = LowForm
|
||||
def transforms = Seq(new EnumerateModulesPass(enumerate))
|
||||
class EnumerateModules(enumerate: (Module) => Unit)
|
||||
extends Transform with SeqTransformBased with DependencyAPIMigration {
|
||||
|
||||
def transforms: Seq[Transform] = Seq(new EnumerateModulesPass(enumerate))
|
||||
|
||||
def execute(state: CircuitState): CircuitState = {
|
||||
val ret = runTransforms(state)
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
package barstools.tapeout.transforms
|
||||
|
||||
import firrtl._
|
||||
import firrtl.ir._
|
||||
import firrtl.annotations._
|
||||
import firrtl.stage.FirrtlCircuitAnnotation
|
||||
import firrtl.passes.Pass
|
||||
|
||||
import java.io.File
|
||||
import firrtl.annotations.AnnotationYamlProtocol._
|
||||
import firrtl.ir._
|
||||
import firrtl.passes.memlib.ReplSeqMemAnnotation
|
||||
import firrtl.stage.FirrtlCircuitAnnotation
|
||||
import firrtl.transforms.BlackBoxResourceFileNameAnno
|
||||
import net.jcazevedo.moultingyaml._
|
||||
import logger.LazyLogging
|
||||
|
||||
trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions =>
|
||||
|
||||
@@ -2,19 +2,15 @@
|
||||
|
||||
package barstools.tapeout.transforms
|
||||
|
||||
import chisel3.internal.InstanceId
|
||||
import chisel3.experimental.RunFirrtlTransform
|
||||
import firrtl.PrimOps.Not
|
||||
import firrtl.annotations.{Annotation, CircuitName, ModuleName, Named}
|
||||
import firrtl.ir.{Input, UIntType, IntWidth, Module, Port, DefNode, NoInfo, Reference, DoPrim, Block, Circuit}
|
||||
import firrtl.annotations.{Annotation, CircuitName, ModuleName, SingleTargetAnnotation}
|
||||
import firrtl.ir._
|
||||
import firrtl.passes.Pass
|
||||
import firrtl.{CircuitForm, CircuitState, LowForm, Transform}
|
||||
import firrtl.{CircuitState, DependencyAPIMigration, Transform}
|
||||
|
||||
object ResetInverterAnnotation {
|
||||
def apply(target: ModuleName): Annotation = Annotation(target, classOf[ResetInverterTransform], "invert")
|
||||
def unapply(a: Annotation): Option[Named] = a match {
|
||||
case Annotation(m, t, "invert") if t == classOf[ResetInverterTransform] => Some(m)
|
||||
case _ => None
|
||||
}
|
||||
case class ResetInverterAnnotation(target: ModuleName) extends SingleTargetAnnotation[ModuleName] {
|
||||
override def duplicate(n: ModuleName): Annotation = ResetInverterAnnotation(n)
|
||||
}
|
||||
|
||||
object ResetN extends Pass {
|
||||
@@ -42,12 +38,9 @@ object ResetN extends Pass {
|
||||
}
|
||||
}
|
||||
|
||||
class ResetInverterTransform extends Transform {
|
||||
override def inputForm: CircuitForm = LowForm
|
||||
override def outputForm: CircuitForm = LowForm
|
||||
|
||||
class ResetInverterTransform extends Transform with DependencyAPIMigration {
|
||||
override def execute(state: CircuitState): CircuitState = {
|
||||
getMyAnnotations(state) match {
|
||||
state.annotations.filter(_.isInstanceOf[ResetInverterAnnotation]) match {
|
||||
case Nil => state
|
||||
case Seq(ResetInverterAnnotation(ModuleName(state.circuit.main, CircuitName(_)))) =>
|
||||
state.copy(circuit = ResetN.run(state.circuit))
|
||||
@@ -60,7 +53,8 @@ class ResetInverterTransform extends Transform {
|
||||
trait ResetInverter {
|
||||
self: chisel3.Module =>
|
||||
def invert[T <: chisel3.internal.LegacyModule](module: T): Unit = {
|
||||
chisel3.experimental.annotate(new chisel3.experimental.ChiselAnnotation{
|
||||
chisel3.experimental.annotate(new chisel3.experimental.ChiselAnnotation with RunFirrtlTransform {
|
||||
def transformClass: Class[_ <: Transform] = classOf[ResetInverterTransform]
|
||||
def toFirrtl: Annotation = ResetInverterAnnotation(module.toNamed)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,27 +2,17 @@
|
||||
|
||||
package barstools.tapeout.transforms.retime
|
||||
|
||||
import chisel3.internal.InstanceId
|
||||
import firrtl.PrimOps.Not
|
||||
import firrtl.annotations.{Annotation, CircuitName, ModuleName, Named, ComponentName}
|
||||
import firrtl.ir.{Input, UIntType, IntWidth, Module, Port, DefNode, NoInfo, Reference, DoPrim, Block, Circuit}
|
||||
import firrtl.passes.Pass
|
||||
import firrtl.{CircuitForm, CircuitState, LowForm, Transform}
|
||||
import chisel3.experimental.RunFirrtlTransform
|
||||
import firrtl.annotations._
|
||||
import firrtl.{CircuitState, DependencyAPIMigration, Transform}
|
||||
|
||||
object RetimeAnnotation {
|
||||
def apply(target: ModuleName): Annotation = Annotation(target, classOf[RetimeTransform], "retime")
|
||||
def unapply(a: Annotation): Option[Named] = a match {
|
||||
case Annotation(m, t, "retime") if t == classOf[RetimeTransform] => Some(m)
|
||||
case _ => None
|
||||
}
|
||||
case class RetimeAnnotation(target: Named) extends SingleTargetAnnotation[Named] {
|
||||
override def duplicate(n: Named): Annotation = RetimeAnnotation(n)
|
||||
}
|
||||
|
||||
class RetimeTransform extends Transform {
|
||||
override def inputForm: CircuitForm = LowForm
|
||||
override def outputForm: CircuitForm = LowForm
|
||||
|
||||
class RetimeTransform extends Transform with DependencyAPIMigration {
|
||||
override def execute(state: CircuitState): CircuitState = {
|
||||
getMyAnnotations(state) match {
|
||||
state.annotations.filter(_.isInstanceOf[RetimeAnnotation]) match {
|
||||
case Nil => state
|
||||
case seq => seq.foreach {
|
||||
case RetimeAnnotation(ModuleName(module, CircuitName(_))) =>
|
||||
@@ -39,8 +29,10 @@ class RetimeTransform extends Transform {
|
||||
|
||||
trait RetimeLib {
|
||||
self: chisel3.Module =>
|
||||
|
||||
def retime[T <: chisel3.internal.LegacyModule](module: T): Unit = {
|
||||
chisel3.experimental.annotate(new chisel3.experimental.ChiselAnnotation{
|
||||
chisel3.experimental.annotate(new chisel3.experimental.ChiselAnnotation with RunFirrtlTransform {
|
||||
def transformClass: Class[_ <: Transform] = classOf[RetimeTransform]
|
||||
def toFirrtl: Annotation = RetimeAnnotation(module.toNamed)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package barstools.tapeout.transforms
|
||||
|
||||
import chisel3.experimental.{ChiselAnnotation, annotate}
|
||||
import firrtl._
|
||||
import firrtl.annotations._
|
||||
import firrtl.passes._
|
||||
import firrtl.ir._
|
||||
import firrtl.transforms.BlackBoxTargetDirAnno
|
||||
|
||||
object WriteConfig {
|
||||
def apply(dir: String, file: String, contents: String): Unit = {
|
||||
@@ -17,8 +19,7 @@ object GetTargetDir {
|
||||
def apply(state: CircuitState): String = {
|
||||
val annos = state.annotations
|
||||
val destDir = annos.map {
|
||||
case Annotation(f, t, s) if t == classOf[firrtl.transforms.BlackBoxTargetDirAnno] =>
|
||||
Some(s)
|
||||
case BlackBoxTargetDirAnno(s) => Some(s)
|
||||
case _ => None
|
||||
}.flatten
|
||||
val loc = {
|
||||
@@ -31,27 +32,39 @@ object GetTargetDir {
|
||||
}
|
||||
}
|
||||
|
||||
// Fake transform just to track Technology information directory
|
||||
object TechnologyLocation {
|
||||
def apply(dir: String): Annotation = {
|
||||
Annotation(CircuitName("All"), classOf[TechnologyLocation], dir)
|
||||
trait HasSetTechnologyLocation {
|
||||
self: chisel3.Module =>
|
||||
|
||||
def setTechnologyLocation(dir: String) {
|
||||
annotate(new ChiselAnnotation {
|
||||
override def toFirrtl: Annotation = {
|
||||
TechnologyLocationAnnotation(dir)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
class TechnologyLocation extends Transform {
|
||||
def inputForm: CircuitForm = LowForm
|
||||
def outputForm: CircuitForm = LowForm
|
||||
def execute(state: CircuitState) = throw new Exception("Technology Location transform execution doesn't work!")
|
||||
|
||||
case class TechnologyLocationAnnotation(dir: String) extends SingleTargetAnnotation[CircuitName] {
|
||||
val target: CircuitName = CircuitName("All")
|
||||
override def duplicate(n: CircuitName): Annotation = TechnologyLocationAnnotation(dir)
|
||||
}
|
||||
|
||||
class TechnologyLocation extends Transform with DependencyAPIMigration {
|
||||
def execute(state: CircuitState): CircuitState = {
|
||||
throw new Exception("Technology Location transform execution doesn't work!")
|
||||
}
|
||||
|
||||
def get(state: CircuitState): String = {
|
||||
val annos = state.annotations
|
||||
val dir = annos.map {
|
||||
case Annotation(f, t, s) if t == classOf[TechnologyLocation] => Some(s)
|
||||
val dir = annos.flatMap {
|
||||
case TechnologyLocationAnnotation(dir) => Some(dir)
|
||||
case _ => None
|
||||
}.flatten
|
||||
}
|
||||
dir.length match {
|
||||
case 0 => ""
|
||||
case 1 =>
|
||||
val targetDir = new java.io.File(dir.head)
|
||||
if(!targetDir.exists()) throw new Exception("Technology yaml directory doesn't exist!")
|
||||
if(!targetDir.exists()) throw new Exception(s"Technology yaml directory $targetDir doesn't exist!")
|
||||
dir.head
|
||||
case _ => throw new Exception("Only 1 tech directory annotation allowed!")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user