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
|
package barstools.tapeout.transforms.pads
|
||||||
|
|
||||||
import firrtl._
|
import firrtl._
|
||||||
import firrtl.annotations._
|
|
||||||
import firrtl.passes._
|
import firrtl.passes._
|
||||||
import firrtl.ir._
|
|
||||||
import barstools.tapeout.transforms._
|
import barstools.tapeout.transforms._
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
// Main Add IO Pad transform operates on low Firrtl
|
// Main Add IO Pad transform operates on low Firrtl
|
||||||
class AddIOPadsTransform extends Transform with SeqTransformBased {
|
class AddIOPadsTransform extends Transform with SeqTransformBased with DependencyAPIMigration {
|
||||||
|
|
||||||
override def inputForm: CircuitForm = LowForm
|
|
||||||
override def outputForm: CircuitForm = LowForm
|
|
||||||
|
|
||||||
val transformList = new mutable.ArrayBuffer[Transform]
|
val transformList = new mutable.ArrayBuffer[Transform]
|
||||||
def transforms: Seq[Transform] = transformList
|
def transforms: Seq[Transform] = transformList
|
||||||
|
|
||||||
override def execute(state: CircuitState): CircuitState = {
|
override def execute(state: CircuitState): CircuitState = {
|
||||||
val collectedAnnos = HasPadAnnotation(getMyAnnotations(state))
|
val collectedAnnos = HasPadAnnotation(state.annotations)
|
||||||
collectedAnnos match {
|
collectedAnnos match {
|
||||||
// Transform not used
|
// Transform not used
|
||||||
case None => state
|
case None => state
|
||||||
|
|||||||
@@ -77,7 +77,12 @@ abstract class TopModule(
|
|||||||
// Annotate IO with side + pad name
|
// Annotate IO with side + pad name
|
||||||
def annotatePad(sig: Element, side: PadSide = defaultPadSide, name: String = ""): Unit = if (usePads) {
|
def annotatePad(sig: Element, side: PadSide = defaultPadSide, name: String = ""): Unit = if (usePads) {
|
||||||
val anno = IOPadAnnotation(side.serialize, name)
|
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, name: String): Unit = annotatePad(sig, side = defaultPadSide, name)
|
||||||
def annotatePad(sig: Aggregate, side: PadSide): Unit = annotatePad(sig, side, 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
|
// 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!
|
// 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) }
|
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
|
// 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
|
package barstools.tapeout.transforms.pads
|
||||||
|
|
||||||
import net.jcazevedo.moultingyaml._
|
import net.jcazevedo.moultingyaml._
|
||||||
@@ -85,8 +87,9 @@ object FoundryPadsYaml extends DefaultYamlProtocol {
|
|||||||
implicit val _pad = yamlFormat6(FoundryPad)
|
implicit val _pad = yamlFormat6(FoundryPad)
|
||||||
def parse(techDir: String): Seq[FoundryPad] = {
|
def parse(techDir: String): Seq[FoundryPad] = {
|
||||||
val file = techDir + exampleResource
|
val file = techDir + exampleResource
|
||||||
if(techDir != "" && !(new java.io.File(file)).exists())
|
if(techDir != "" && !(new java.io.File(file)).exists()) {
|
||||||
throw new Exception("Technology directory must contain FoundryPads.yaml!")
|
throw new Exception(s"Technology directory $techDir must contain FoundryPads.yaml!")
|
||||||
|
}
|
||||||
val out = (new YamlFileReader(exampleResource)).parse[FoundryPad](if (techDir == "") "" else file)
|
val out = (new YamlFileReader(exampleResource)).parse[FoundryPad](if (techDir == "") "" else file)
|
||||||
val padNames = out.map(x => x.correctedName)
|
val padNames = out.map(x => x.correctedName)
|
||||||
require(padNames.distinct.length == padNames.length, "Pad names must be unique!")
|
require(padNames.distinct.length == padNames.length, "Pad names must be unique!")
|
||||||
|
|||||||
@@ -3,9 +3,6 @@
|
|||||||
package barstools.tapeout.transforms.pads
|
package barstools.tapeout.transforms.pads
|
||||||
|
|
||||||
import firrtl.annotations._
|
import firrtl.annotations._
|
||||||
import chisel3.experimental._
|
|
||||||
import chisel3._
|
|
||||||
|
|
||||||
import net.jcazevedo.moultingyaml._
|
import net.jcazevedo.moultingyaml._
|
||||||
|
|
||||||
object PadAnnotationsYaml extends DefaultYamlProtocol {
|
object PadAnnotationsYaml extends DefaultYamlProtocol {
|
||||||
@@ -13,6 +10,17 @@ object PadAnnotationsYaml extends DefaultYamlProtocol {
|
|||||||
implicit val _noiopad = yamlFormat1(NoIOPadAnnotation)
|
implicit val _noiopad = yamlFormat1(NoIOPadAnnotation)
|
||||||
implicit val _supplyanno = yamlFormat5(SupplyAnnotation)
|
implicit val _supplyanno = yamlFormat5(SupplyAnnotation)
|
||||||
implicit val _modulepadanno = yamlFormat4(ModulePadAnnotation)
|
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 {
|
abstract class FirrtlPadTransformAnnotation {
|
||||||
@@ -25,14 +33,12 @@ abstract class IOAnnotation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case class IOPadAnnotation(padSide: String, padName: String) extends IOAnnotation {
|
case class IOPadAnnotation(padSide: String, padName: String) extends IOAnnotation {
|
||||||
import PadAnnotationsYaml._
|
def serialize: String = PadAnnotationsYaml.serialize(this)
|
||||||
def serialize: String = this.toYaml.prettyPrint
|
|
||||||
def getPadSide: PadSide = HasPadAnnotation.getSide(padSide)
|
def getPadSide: PadSide = HasPadAnnotation.getSide(padSide)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class NoIOPadAnnotation(noPad: String = "") extends IOAnnotation {
|
case class NoIOPadAnnotation(noPad: String = "") extends IOAnnotation {
|
||||||
import PadAnnotationsYaml._
|
def serialize: String = PadAnnotationsYaml.serialize(this)
|
||||||
def serialize: String = this.toYaml.prettyPrint
|
|
||||||
def field: String = "noPad:"
|
def field: String = "noPad:"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,12 +50,6 @@ case class TargetIOPadAnnoF(target: ComponentName, anno: IOAnnotation)
|
|||||||
def targetName: String = target.name
|
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
|
// A bunch of supply pads (designated by name, # on each chip side) can be associated with the top module
|
||||||
case class SupplyAnnotation(
|
case class SupplyAnnotation(
|
||||||
padName: String,
|
padName: String,
|
||||||
@@ -64,9 +64,9 @@ case class ModulePadAnnotation(
|
|||||||
coreWidth: Int = 0,
|
coreWidth: Int = 0,
|
||||||
coreHeight: Int = 0,
|
coreHeight: Int = 0,
|
||||||
supplyAnnos: Seq[SupplyAnnotation] = Seq.empty) {
|
supplyAnnos: Seq[SupplyAnnotation] = Seq.empty) {
|
||||||
import PadAnnotationsYaml._
|
|
||||||
def serialize: String = this.toYaml.prettyPrint
|
def serialize: String = PadAnnotationsYaml.serialize(this)
|
||||||
val supplyPadNames = supplyAnnos.map(_.padName)
|
def supplyPadNames: Seq[String] = supplyAnnos.map(_.padName)
|
||||||
require(supplyPadNames.distinct.length == supplyPadNames.length, "Supply pads should only be specified once!")
|
require(supplyPadNames.distinct.length == supplyPadNames.length, "Supply pads should only be specified once!")
|
||||||
def getDefaultPadSide: PadSide = HasPadAnnotation.getSide(defaultPadSide)
|
def getDefaultPadSide: PadSide = HasPadAnnotation.getSide(defaultPadSide)
|
||||||
}
|
}
|
||||||
@@ -91,7 +91,6 @@ case class CollectedAnnos(
|
|||||||
}
|
}
|
||||||
|
|
||||||
object HasPadAnnotation {
|
object HasPadAnnotation {
|
||||||
import PadAnnotationsYaml._
|
|
||||||
|
|
||||||
def getSide(a: String): PadSide = a match {
|
def getSide(a: String): PadSide = a match {
|
||||||
case i if i == Left.serialize => Left
|
case i if i == Left.serialize => Left
|
||||||
@@ -115,26 +114,13 @@ object HasPadAnnotation {
|
|||||||
// case _ => None
|
// 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] = {
|
def apply(annos: Seq[Annotation]): Option[CollectedAnnos] = {
|
||||||
// Get all pad-related annotations (config files, pad sides, pad names, etc.)
|
// 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)
|
val targets = padAnnos.map(x => x.targetName)
|
||||||
require(targets.distinct.length == targets.length, "Only 1 pad related annotation is allowed per component/module")
|
require(targets.distinct.length == targets.length, "Only 1 pad related annotation is allowed per component/module")
|
||||||
if (padAnnos.length == 0) {
|
if (padAnnos.length == 0) {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import firrtl.ir._
|
|||||||
import firrtl.annotations._
|
import firrtl.annotations._
|
||||||
import firrtl.Mappers._
|
import firrtl.Mappers._
|
||||||
|
|
||||||
|
|
||||||
case class KeepNameAnnotation(target: ModuleTarget)
|
case class KeepNameAnnotation(target: ModuleTarget)
|
||||||
extends SingleTargetAnnotation[ModuleTarget] {
|
extends SingleTargetAnnotation[ModuleTarget] {
|
||||||
def duplicate(n: ModuleTarget) = this.copy(n)
|
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
|
// 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
|
// allow FIRRTL to be linked together using "cat" and ExtModules don't get
|
||||||
// emitted, this should be safe.
|
// emitted, this should be safe.
|
||||||
class AddSuffixToModuleNames extends Transform {
|
class AddSuffixToModuleNames extends Transform with DependencyAPIMigration {
|
||||||
def inputForm = LowForm
|
|
||||||
def outputForm = LowForm
|
|
||||||
|
|
||||||
def processAnnos(annos: AnnotationSeq): (AnnotationSeq, (String) => String) = {
|
def processAnnos(annos: AnnotationSeq): (AnnotationSeq, (String) => String) = {
|
||||||
val whitelist = annos.collect({ case KeepNameAnnotation(tgt) => tgt.module }).toSet
|
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 {
|
class EnumerateModules(enumerate: (Module) => Unit)
|
||||||
def inputForm = LowForm
|
extends Transform with SeqTransformBased with DependencyAPIMigration {
|
||||||
def outputForm = LowForm
|
|
||||||
def transforms = Seq(new EnumerateModulesPass(enumerate))
|
def transforms: Seq[Transform] = Seq(new EnumerateModulesPass(enumerate))
|
||||||
|
|
||||||
def execute(state: CircuitState): CircuitState = {
|
def execute(state: CircuitState): CircuitState = {
|
||||||
val ret = runTransforms(state)
|
val ret = runTransforms(state)
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
package barstools.tapeout.transforms
|
package barstools.tapeout.transforms
|
||||||
|
|
||||||
import firrtl._
|
import firrtl._
|
||||||
import firrtl.ir._
|
|
||||||
import firrtl.annotations._
|
import firrtl.annotations._
|
||||||
import firrtl.stage.FirrtlCircuitAnnotation
|
import firrtl.ir._
|
||||||
import firrtl.passes.Pass
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import firrtl.annotations.AnnotationYamlProtocol._
|
|
||||||
import firrtl.passes.memlib.ReplSeqMemAnnotation
|
import firrtl.passes.memlib.ReplSeqMemAnnotation
|
||||||
|
import firrtl.stage.FirrtlCircuitAnnotation
|
||||||
import firrtl.transforms.BlackBoxResourceFileNameAnno
|
import firrtl.transforms.BlackBoxResourceFileNameAnno
|
||||||
import net.jcazevedo.moultingyaml._
|
|
||||||
import logger.LazyLogging
|
import logger.LazyLogging
|
||||||
|
|
||||||
trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions =>
|
trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions =>
|
||||||
|
|||||||
@@ -2,19 +2,15 @@
|
|||||||
|
|
||||||
package barstools.tapeout.transforms
|
package barstools.tapeout.transforms
|
||||||
|
|
||||||
import chisel3.internal.InstanceId
|
import chisel3.experimental.RunFirrtlTransform
|
||||||
import firrtl.PrimOps.Not
|
import firrtl.PrimOps.Not
|
||||||
import firrtl.annotations.{Annotation, CircuitName, ModuleName, Named}
|
import firrtl.annotations.{Annotation, CircuitName, ModuleName, SingleTargetAnnotation}
|
||||||
import firrtl.ir.{Input, UIntType, IntWidth, Module, Port, DefNode, NoInfo, Reference, DoPrim, Block, Circuit}
|
import firrtl.ir._
|
||||||
import firrtl.passes.Pass
|
import firrtl.passes.Pass
|
||||||
import firrtl.{CircuitForm, CircuitState, LowForm, Transform}
|
import firrtl.{CircuitState, DependencyAPIMigration, Transform}
|
||||||
|
|
||||||
object ResetInverterAnnotation {
|
case class ResetInverterAnnotation(target: ModuleName) extends SingleTargetAnnotation[ModuleName] {
|
||||||
def apply(target: ModuleName): Annotation = Annotation(target, classOf[ResetInverterTransform], "invert")
|
override def duplicate(n: ModuleName): Annotation = ResetInverterAnnotation(n)
|
||||||
def unapply(a: Annotation): Option[Named] = a match {
|
|
||||||
case Annotation(m, t, "invert") if t == classOf[ResetInverterTransform] => Some(m)
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object ResetN extends Pass {
|
object ResetN extends Pass {
|
||||||
@@ -42,12 +38,9 @@ object ResetN extends Pass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResetInverterTransform extends Transform {
|
class ResetInverterTransform extends Transform with DependencyAPIMigration {
|
||||||
override def inputForm: CircuitForm = LowForm
|
|
||||||
override def outputForm: CircuitForm = LowForm
|
|
||||||
|
|
||||||
override def execute(state: CircuitState): CircuitState = {
|
override def execute(state: CircuitState): CircuitState = {
|
||||||
getMyAnnotations(state) match {
|
state.annotations.filter(_.isInstanceOf[ResetInverterAnnotation]) match {
|
||||||
case Nil => state
|
case Nil => state
|
||||||
case Seq(ResetInverterAnnotation(ModuleName(state.circuit.main, CircuitName(_)))) =>
|
case Seq(ResetInverterAnnotation(ModuleName(state.circuit.main, CircuitName(_)))) =>
|
||||||
state.copy(circuit = ResetN.run(state.circuit))
|
state.copy(circuit = ResetN.run(state.circuit))
|
||||||
@@ -60,7 +53,8 @@ class ResetInverterTransform extends Transform {
|
|||||||
trait ResetInverter {
|
trait ResetInverter {
|
||||||
self: chisel3.Module =>
|
self: chisel3.Module =>
|
||||||
def invert[T <: chisel3.internal.LegacyModule](module: T): Unit = {
|
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)
|
def toFirrtl: Annotation = ResetInverterAnnotation(module.toNamed)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,27 +2,17 @@
|
|||||||
|
|
||||||
package barstools.tapeout.transforms.retime
|
package barstools.tapeout.transforms.retime
|
||||||
|
|
||||||
import chisel3.internal.InstanceId
|
import chisel3.experimental.RunFirrtlTransform
|
||||||
import firrtl.PrimOps.Not
|
import firrtl.annotations._
|
||||||
import firrtl.annotations.{Annotation, CircuitName, ModuleName, Named, ComponentName}
|
import firrtl.{CircuitState, DependencyAPIMigration, Transform}
|
||||||
import firrtl.ir.{Input, UIntType, IntWidth, Module, Port, DefNode, NoInfo, Reference, DoPrim, Block, Circuit}
|
|
||||||
import firrtl.passes.Pass
|
|
||||||
import firrtl.{CircuitForm, CircuitState, LowForm, Transform}
|
|
||||||
|
|
||||||
object RetimeAnnotation {
|
case class RetimeAnnotation(target: Named) extends SingleTargetAnnotation[Named] {
|
||||||
def apply(target: ModuleName): Annotation = Annotation(target, classOf[RetimeTransform], "retime")
|
override def duplicate(n: Named): Annotation = RetimeAnnotation(n)
|
||||||
def unapply(a: Annotation): Option[Named] = a match {
|
|
||||||
case Annotation(m, t, "retime") if t == classOf[RetimeTransform] => Some(m)
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class RetimeTransform extends Transform {
|
class RetimeTransform extends Transform with DependencyAPIMigration {
|
||||||
override def inputForm: CircuitForm = LowForm
|
|
||||||
override def outputForm: CircuitForm = LowForm
|
|
||||||
|
|
||||||
override def execute(state: CircuitState): CircuitState = {
|
override def execute(state: CircuitState): CircuitState = {
|
||||||
getMyAnnotations(state) match {
|
state.annotations.filter(_.isInstanceOf[RetimeAnnotation]) match {
|
||||||
case Nil => state
|
case Nil => state
|
||||||
case seq => seq.foreach {
|
case seq => seq.foreach {
|
||||||
case RetimeAnnotation(ModuleName(module, CircuitName(_))) =>
|
case RetimeAnnotation(ModuleName(module, CircuitName(_))) =>
|
||||||
@@ -39,8 +29,10 @@ class RetimeTransform extends Transform {
|
|||||||
|
|
||||||
trait RetimeLib {
|
trait RetimeLib {
|
||||||
self: chisel3.Module =>
|
self: chisel3.Module =>
|
||||||
|
|
||||||
def retime[T <: chisel3.internal.LegacyModule](module: T): Unit = {
|
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)
|
def toFirrtl: Annotation = RetimeAnnotation(module.toNamed)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
package barstools.tapeout.transforms
|
package barstools.tapeout.transforms
|
||||||
|
|
||||||
|
import chisel3.experimental.{ChiselAnnotation, annotate}
|
||||||
import firrtl._
|
import firrtl._
|
||||||
import firrtl.annotations._
|
import firrtl.annotations._
|
||||||
import firrtl.passes._
|
import firrtl.transforms.BlackBoxTargetDirAnno
|
||||||
import firrtl.ir._
|
|
||||||
|
|
||||||
object WriteConfig {
|
object WriteConfig {
|
||||||
def apply(dir: String, file: String, contents: String): Unit = {
|
def apply(dir: String, file: String, contents: String): Unit = {
|
||||||
@@ -17,8 +19,7 @@ object GetTargetDir {
|
|||||||
def apply(state: CircuitState): String = {
|
def apply(state: CircuitState): String = {
|
||||||
val annos = state.annotations
|
val annos = state.annotations
|
||||||
val destDir = annos.map {
|
val destDir = annos.map {
|
||||||
case Annotation(f, t, s) if t == classOf[firrtl.transforms.BlackBoxTargetDirAnno] =>
|
case BlackBoxTargetDirAnno(s) => Some(s)
|
||||||
Some(s)
|
|
||||||
case _ => None
|
case _ => None
|
||||||
}.flatten
|
}.flatten
|
||||||
val loc = {
|
val loc = {
|
||||||
@@ -31,27 +32,39 @@ object GetTargetDir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fake transform just to track Technology information directory
|
trait HasSetTechnologyLocation {
|
||||||
object TechnologyLocation {
|
self: chisel3.Module =>
|
||||||
def apply(dir: String): Annotation = {
|
|
||||||
Annotation(CircuitName("All"), classOf[TechnologyLocation], dir)
|
def setTechnologyLocation(dir: String) {
|
||||||
|
annotate(new ChiselAnnotation {
|
||||||
|
override def toFirrtl: Annotation = {
|
||||||
|
TechnologyLocationAnnotation(dir)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class TechnologyLocation extends Transform {
|
|
||||||
def inputForm: CircuitForm = LowForm
|
case class TechnologyLocationAnnotation(dir: String) extends SingleTargetAnnotation[CircuitName] {
|
||||||
def outputForm: CircuitForm = LowForm
|
val target: CircuitName = CircuitName("All")
|
||||||
def execute(state: CircuitState) = throw new Exception("Technology Location transform execution doesn't work!")
|
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 = {
|
def get(state: CircuitState): String = {
|
||||||
val annos = state.annotations
|
val annos = state.annotations
|
||||||
val dir = annos.map {
|
val dir = annos.flatMap {
|
||||||
case Annotation(f, t, s) if t == classOf[TechnologyLocation] => Some(s)
|
case TechnologyLocationAnnotation(dir) => Some(dir)
|
||||||
case _ => None
|
case _ => None
|
||||||
}.flatten
|
}
|
||||||
dir.length match {
|
dir.length match {
|
||||||
case 0 => ""
|
case 0 => ""
|
||||||
case 1 =>
|
case 1 =>
|
||||||
val targetDir = new java.io.File(dir.head)
|
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
|
dir.head
|
||||||
case _ => throw new Exception("Only 1 tech directory annotation allowed!")
|
case _ => throw new Exception("Only 1 tech directory annotation allowed!")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,64 +2,74 @@
|
|||||||
|
|
||||||
package barstools.tapeout.transforms.pads
|
package barstools.tapeout.transforms.pads
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
import barstools.tapeout.transforms.HasSetTechnologyLocation
|
||||||
import chisel3._
|
import chisel3._
|
||||||
|
import chisel3.experimental._
|
||||||
|
import chisel3.iotesters._
|
||||||
|
import chisel3.util.HasBlackBoxInline
|
||||||
import firrtl._
|
import firrtl._
|
||||||
import org.scalatest.{FlatSpec, Matchers}
|
import org.scalatest.{FlatSpec, Matchers}
|
||||||
import chisel3.experimental._
|
|
||||||
import chisel3.util.HasBlackBoxInline
|
|
||||||
import chisel3.iotesters._
|
|
||||||
|
|
||||||
class BB extends BlackBox with HasBlackBoxInline {
|
class BB extends BlackBox with HasBlackBoxInline {
|
||||||
val io = IO(new Bundle {
|
val io = IO(new Bundle {
|
||||||
val c = Input(SInt(14.W))
|
val c = Input(SInt(14.W))
|
||||||
val z = Output(SInt(16.W))
|
val z = Output(SInt(16.W))
|
||||||
val analog1 = Analog(3.W)
|
val analog1 = Analog(3.W)
|
||||||
val analog2 = analog1.chiselCloneType
|
val analog2 = Analog(3.W)
|
||||||
})
|
})
|
||||||
// Generates a "FakeBB.v" file with the following Verilog module
|
// Generates a "FakeBB.v" file with the following Verilog module
|
||||||
setInline("FakeBB.v",
|
setInline(
|
||||||
|
"FakeBB.v",
|
||||||
s"""
|
s"""
|
||||||
|module BB(
|
|module BB(
|
||||||
| input [15:0] c,
|
| input [15:0] c,
|
||||||
| output [15:0] z,
|
| output [15:0] z,
|
||||||
| inout [2:0] analog1,
|
| inout [2:0] analog1,
|
||||||
| inout [2:0] analog2
|
| inout [2:0] analog2
|
||||||
|);
|
|);
|
||||||
| always @* begin
|
| always @* begin
|
||||||
| z = 2 * c;
|
| z = 2 * c;
|
||||||
| analog2 = analog1 + 1;
|
| analog2 = analog1 + 1;
|
||||||
| end
|
| end
|
||||||
|endmodule
|
|endmodule
|
||||||
""".stripMargin)
|
""".stripMargin
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no template file is provided, it'll use the default one (example) in the resource folder
|
// If no template file is provided, it'll use the default one (example) in the resource folder
|
||||||
// Default pad side is Top if no side is specified for a given IO
|
// Default pad side is Top if no side is specified for a given IO
|
||||||
// You can designate the number of different supply pads on each chip side
|
// You can designate the number of different supply pads on each chip side
|
||||||
class ExampleTopModuleWithBB extends TopModule(
|
class ExampleTopModuleWithBB
|
||||||
supplyAnnos = Seq(
|
extends TopModule(
|
||||||
SupplyAnnotation(padName = "vdd", leftSide = 3, bottomSide = 2),
|
supplyAnnos = Seq(
|
||||||
SupplyAnnotation(padName = "vss", rightSide = 1)
|
SupplyAnnotation(padName = "vdd", leftSide = 3, bottomSide = 2),
|
||||||
)) {
|
SupplyAnnotation(padName = "vss", rightSide = 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
with HasSetTechnologyLocation {
|
||||||
val io = IO(new Bundle {
|
val io = IO(new Bundle {
|
||||||
val a = Input(UInt(15.W))
|
val a = Input(UInt(15.W))
|
||||||
val b = a.chiselCloneType
|
val b = Input(a.cloneType)
|
||||||
val c = Input(SInt(14.W))
|
val c = Input(SInt(14.W))
|
||||||
val x = Output(UInt(16.W))
|
val x = Output(UInt(16.W))
|
||||||
val y = x.chiselCloneType
|
val y = Output(x.cloneType)
|
||||||
val z = Output(SInt(16.W))
|
val z = Output(SInt(16.W))
|
||||||
val analog1 = Analog(3.W)
|
val analog1 = Analog(3.W)
|
||||||
val analog2 = analog1.chiselCloneType
|
val analog2 = analog1.cloneType
|
||||||
val v = Output(Vec(3, UInt(5.W)))
|
val v = Output(Vec(3, UInt(5.W)))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
setTechnologyLocation("./RealTech")
|
||||||
|
|
||||||
// Can annotate aggregates with pad side location + pad name (should be a name in the yaml template)
|
// Can annotate aggregates with pad side location + pad name (should be a name in the yaml template)
|
||||||
annotatePad(io.v, Right, "from_tristate_foundry")
|
annotatePad(io.v, Right, "from_tristate_foundry")
|
||||||
// Can annotate individual elements
|
// Can annotate individual elements
|
||||||
annotatePad(io.analog1, Left, "fast_custom")
|
annotatePad(io.analog1, Left, "fast_custom")
|
||||||
annotatePad(io.analog2, Bottom, "slow_foundry")
|
annotatePad(io.analog2, Bottom, "slow_foundry")
|
||||||
// Looks for a pad that matches the IO type (digital in, digital out, analog) if no name is specified
|
// Looks for a pad that matches the IO type (digital in, digital out, analog) if no name is specified
|
||||||
Seq(io.a, io.b, io.c, io.x) foreach { x => annotatePad(x, Left) }
|
Seq(io.a, io.b, io.c, io.x).foreach { x => annotatePad(x, Left) }
|
||||||
// Some signals might not want pads associated with them
|
// Some signals might not want pads associated with them
|
||||||
noPad(io.y)
|
noPad(io.y)
|
||||||
// Clk might come directly from bump
|
// Clk might come directly from bump
|
||||||
@@ -74,7 +84,7 @@ class ExampleTopModuleWithBB extends TopModule(
|
|||||||
io.x := io.a + 1.U
|
io.x := io.a + 1.U
|
||||||
io.y := io.b - 1.U
|
io.y := io.b - 1.U
|
||||||
|
|
||||||
io.v foreach { lhs => lhs := io.a }
|
io.v.foreach { lhs => lhs := io.a }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +99,7 @@ class SimpleTopModuleTester(c: ExampleTopModuleWithBB) extends PeekPokeTester(c)
|
|||||||
expect(c.io.x, ax(i) + 1)
|
expect(c.io.x, ax(i) + 1)
|
||||||
expect(c.io.y, bx(i) - 1)
|
expect(c.io.y, bx(i) - 1)
|
||||||
expect(c.io.z, 2 * cx(i))
|
expect(c.io.z, 2 * cx(i))
|
||||||
c.io.v foreach { out => expect(out, ax(i)) }
|
c.io.v.foreach { out => expect(out, ax(i)) }
|
||||||
}
|
}
|
||||||
// Analog can't be peeked + poked
|
// Analog can't be peeked + poked
|
||||||
}
|
}
|
||||||
@@ -122,61 +132,100 @@ class SimpleTopModuleTester(c: ExampleTopModuleWithBB) extends PeekPokeTester(c)
|
|||||||
|
|
||||||
class IOPadSpec extends FlatSpec with Matchers {
|
class IOPadSpec extends FlatSpec with Matchers {
|
||||||
|
|
||||||
def readOutputFile(dir: String, f: String): String =
|
def readOutputFile(dir: String, f: String): String = {
|
||||||
scala.io.Source.fromFile(Seq(dir, f).mkString("/")).getLines.mkString("\n")
|
FileUtils.getText(dir + File.separator + f)
|
||||||
|
}
|
||||||
def readResource(resource: String): String = {
|
def readResource(resource: String): String = {
|
||||||
val stream = getClass.getResourceAsStream(resource)
|
val stream = getClass.getResourceAsStream(resource)
|
||||||
scala.io.Source.fromInputStream(stream).mkString
|
scala.io.Source.fromInputStream(stream).mkString
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkOutputs(dir: String) = {
|
def checkOutputs(dir: String): Unit = {
|
||||||
// Show that black box source helper is run
|
// Show that black box source helper is run
|
||||||
//readOutputFile(dir, "black_box_verilog_files.f") should include ("pad_supply_vdd_horizontal.v")
|
//readOutputFile(dir, "black_box_verilog_files.f") should include ("pad_supply_vdd_horizontal.v")
|
||||||
|
|
||||||
val padBBEx = s"""// Digital Pad Example
|
val padBBEx = s"""// Digital Pad Example
|
||||||
|// Signal Direction: Input
|
|// Signal Direction: Input
|
||||||
|// Pad Orientation: Horizontal
|
|// Pad Orientation: Horizontal
|
||||||
|// Call your instance PAD
|
|// Call your instance PAD
|
||||||
|module pad_digital_from_tristate_foundry_horizontal_input(
|
|module pad_digital_from_tristate_foundry_horizontal_input(
|
||||||
| input in,
|
| input in,
|
||||||
| output reg out
|
| output reg out
|
||||||
|);
|
|);
|
||||||
| // Where you would normally dump your pad instance
|
| // Where you would normally dump your pad instance
|
||||||
| always @* begin
|
| always @* begin
|
||||||
| out = in;
|
| out = in;
|
||||||
| end
|
| end
|
||||||
|endmodule
|
|endmodule
|
||||||
|
|
|
|
||||||
|module pad_digital_from_tristate_foundry_horizontal_input_array #(
|
|module pad_digital_from_tristate_foundry_horizontal_input_array #(
|
||||||
| parameter int WIDTH=1
|
| parameter int WIDTH=1
|
||||||
|)(
|
|)(
|
||||||
| input [WIDTH-1:0] in,
|
| input [WIDTH-1:0] in,
|
||||||
| output reg [WIDTH-1:0] out
|
| output reg [WIDTH-1:0] out
|
||||||
|);
|
|);
|
||||||
| pad_digital_from_tristate_foundry_horizontal_input pad_digital_from_tristate_foundry_horizontal_input[WIDTH-1:0](
|
| pad_digital_from_tristate_foundry_horizontal_input pad_digital_from_tristate_foundry_horizontal_input[WIDTH-1:0](
|
||||||
| .in(in),
|
| .in(in),
|
||||||
| .out(out)
|
| .out(out)
|
||||||
| );""".stripMargin
|
| );""".stripMargin
|
||||||
// Make sure black box templating is OK
|
// Make sure black box templating is OK
|
||||||
readOutputFile(dir, "pad_digital_from_tristate_foundry_horizontal_input_array.v") should include (padBBEx)
|
readOutputFile(dir, "pad_digital_from_tristate_foundry_horizontal_input_array.v") should include(padBBEx)
|
||||||
|
|
||||||
val verilog = readOutputFile(dir, "ExampleTopModuleWithBB.v")
|
val verilog = readOutputFile(dir, "ExampleTopModuleWithBB.v")
|
||||||
// Pad frame + top should be exact
|
// Pad frame + top should be exact
|
||||||
verilog should include (readResource("/PadAnnotationVerilogPart.v"))
|
verilog should include(readResource("/PadAnnotationVerilogPart.v"))
|
||||||
// Pad Placement IO file should be exact
|
// Pad Placement IO file should be exact
|
||||||
val padIO = readOutputFile(dir, "pads.io")
|
val padIO = readOutputFile(dir, "pads.io")
|
||||||
padIO should include(readResource("/PadPlacement.io"))
|
padIO should include(readResource("/PadPlacement.io"))
|
||||||
}
|
}
|
||||||
|
|
||||||
behavior of "top module with blackbox"
|
behavior.of("Pad Annotations")
|
||||||
|
|
||||||
import barstools.tapeout.transforms._
|
it should "serialize pad annotations" in {
|
||||||
|
val noIOPadAnnotation = NoIOPadAnnotation("dog")
|
||||||
|
noIOPadAnnotation.serialize should include("noPad: dog")
|
||||||
|
|
||||||
|
val ioPadAnnotation = IOPadAnnotation("left", "oliver")
|
||||||
|
ioPadAnnotation.serialize should include(
|
||||||
|
"""padSide: left
|
||||||
|
|padName: oliver
|
||||||
|
|""".stripMargin)
|
||||||
|
|
||||||
|
val modulePadAnnotation = ModulePadAnnotation(
|
||||||
|
"top",
|
||||||
|
11,
|
||||||
|
42,
|
||||||
|
Seq(
|
||||||
|
SupplyAnnotation("mypad, 1, 2 ,3 , 4"),
|
||||||
|
SupplyAnnotation("yourpad, 9, 8, 7, 6")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
modulePadAnnotation.serialize should be(
|
||||||
|
"""defaultPadSide: top
|
||||||
|
|coreWidth: 11
|
||||||
|
|coreHeight: 42
|
||||||
|
|supplyAnnos:
|
||||||
|
|- rightSide: 0
|
||||||
|
| padName: mypad, 1, 2 ,3 , 4
|
||||||
|
| leftSide: 0
|
||||||
|
| bottomSide: 0
|
||||||
|
| topSide: 0
|
||||||
|
|- rightSide: 0
|
||||||
|
| padName: yourpad, 9, 8, 7, 6
|
||||||
|
| leftSide: 0
|
||||||
|
| bottomSide: 0
|
||||||
|
| topSide: 0
|
||||||
|
|""".stripMargin
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
behavior.of("top module with blackbox")
|
||||||
|
|
||||||
it should "pass simple testbench" in {
|
it should "pass simple testbench" in {
|
||||||
val optionsManager = new TesterOptionsManager {
|
val optionsManager = new TesterOptionsManager {
|
||||||
firrtlOptions = firrtlOptions.copy(
|
firrtlOptions = firrtlOptions.copy(
|
||||||
compilerName = "verilog"
|
compilerName = "verilog"
|
||||||
// annotations = List(TechnologyLocation("./RealTech"))
|
|
||||||
)
|
)
|
||||||
testerOptions = testerOptions.copy(isVerbose = true, backendName = "verilator", displayBase = 10)
|
testerOptions = testerOptions.copy(isVerbose = true, backendName = "verilator", displayBase = 10)
|
||||||
commonOptions = commonOptions.copy(targetDirName = "test_run_dir/PadsTB")
|
commonOptions = commonOptions.copy(targetDirName = "test_run_dir/PadsTB")
|
||||||
@@ -185,9 +234,9 @@ class IOPadSpec extends FlatSpec with Matchers {
|
|||||||
val dir = optionsManager.commonOptions.targetDirName
|
val dir = optionsManager.commonOptions.targetDirName
|
||||||
checkOutputs(dir)
|
checkOutputs(dir)
|
||||||
new SimpleTopModuleTester(c)
|
new SimpleTopModuleTester(c)
|
||||||
} should be (true)
|
} should be(true)
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
it should "create proper IO pads + black box in low firrtl" in {
|
it should "create proper IO pads + black box in low firrtl" in {
|
||||||
val optionsManager = new ExecutionOptionsManager("barstools") with HasChiselExecutionOptions with HasFirrtlOptions {
|
val optionsManager = new ExecutionOptionsManager("barstools") with HasChiselExecutionOptions with HasFirrtlOptions {
|
||||||
firrtlOptions = firrtlOptions.copy(compilerName = "low")
|
firrtlOptions = firrtlOptions.copy(compilerName = "low")
|
||||||
@@ -204,7 +253,7 @@ class IOPadSpec extends FlatSpec with Matchers {
|
|||||||
}
|
}
|
||||||
success should be (true)
|
success should be (true)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
it should "create proper IO pads + black box in verilog" in {
|
it should "create proper IO pads + black box in verilog" in {
|
||||||
val optionsManager = new ExecutionOptionsManager("barstools") with HasChiselExecutionOptions with HasFirrtlOptions {
|
val optionsManager = new ExecutionOptionsManager("barstools") with HasChiselExecutionOptions with HasFirrtlOptions {
|
||||||
firrtlOptions = firrtlOptions.copy(
|
firrtlOptions = firrtlOptions.copy(
|
||||||
@@ -218,7 +267,7 @@ class IOPadSpec extends FlatSpec with Matchers {
|
|||||||
true
|
true
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
success should be (true)
|
success should be(true)
|
||||||
val dir = optionsManager.commonOptions.targetDirName
|
val dir = optionsManager.commonOptions.targetDirName
|
||||||
checkOutputs(dir)
|
checkOutputs(dir)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
package barstools.tapeout.transforms
|
package barstools.tapeout.transforms
|
||||||
|
|
||||||
import chisel3._
|
import chisel3._
|
||||||
import firrtl._
|
import chisel3.stage.ChiselStage
|
||||||
import org.scalatest.{FreeSpec, Matchers}
|
import org.scalatest.{FreeSpec, Matchers}
|
||||||
|
|
||||||
class ExampleModuleNeedsResetInverted extends Module with ResetInverter {
|
class ExampleModuleNeedsResetInverted extends Module with ResetInverter {
|
||||||
@@ -19,22 +19,15 @@ class ExampleModuleNeedsResetInverted extends Module with ResetInverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ResetNSpec extends FreeSpec with Matchers {
|
class ResetNSpec extends FreeSpec with Matchers {
|
||||||
|
|
||||||
"Inverting reset needs to be done throughout module" in {
|
"Inverting reset needs to be done throughout module" in {
|
||||||
val optionsManager = new ExecutionOptionsManager("dsptools") with HasChiselExecutionOptions with HasFirrtlOptions {
|
val chirrtl = (new ChiselStage).emitChirrtl(new ExampleModuleNeedsResetInverted, Array())
|
||||||
firrtlOptions = firrtlOptions.copy(compilerName = "low", customTransforms = List(new ResetInverterTransform)),
|
chirrtl should include("input reset :")
|
||||||
}
|
(chirrtl should not).include("input reset_n :")
|
||||||
chisel3.Driver.execute(optionsManager, () => new ExampleModuleNeedsResetInverted) match {
|
(chirrtl should not).include("node reset = not(reset_n)")
|
||||||
case ChiselExecutionSuccess(_, chirrtl, Some(FirrtlExecutionSuccess(_, firrtl))) =>
|
|
||||||
chirrtl should include ("input reset :")
|
|
||||||
chirrtl should not include "input reset_n :"
|
|
||||||
chirrtl should not include "node reset = not(reset_n)"
|
|
||||||
|
|
||||||
firrtl should include ("input reset_n :")
|
val firrtl = (new ChiselStage).emitFirrtl(new ExampleModuleNeedsResetInverted, Array("-X", "low"))
|
||||||
firrtl should include ("node reset = not(reset_n)")
|
firrtl should include("input reset_n :")
|
||||||
firrtl should not include "input reset :"
|
firrtl should include("node reset = not(reset_n)")
|
||||||
case _ =>
|
(firrtl should not).include("input reset :")
|
||||||
// bad
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
package barstools.tapeout.transforms.retime.test
|
package barstools.tapeout.transforms.retime.test
|
||||||
|
|
||||||
import chisel3._
|
|
||||||
import firrtl._
|
|
||||||
import org.scalatest.{FlatSpec, Matchers}
|
|
||||||
import chisel3.experimental._
|
|
||||||
import chisel3.util.HasBlackBoxInline
|
|
||||||
import chisel3.iotesters._
|
|
||||||
import barstools.tapeout.transforms.retime._
|
import barstools.tapeout.transforms.retime._
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.stage.ChiselStage
|
||||||
|
import firrtl._
|
||||||
|
import logger.Logger
|
||||||
|
import org.scalatest.{FlatSpec, Matchers}
|
||||||
|
|
||||||
class RetimeSpec extends FlatSpec with Matchers {
|
class RetimeSpec extends FlatSpec with Matchers {
|
||||||
def normalized(s: String): String = {
|
def normalized(s: String): String = {
|
||||||
@@ -25,20 +24,47 @@ class RetimeSpec extends FlatSpec with Matchers {
|
|||||||
it should "pass simple retime module annotation" in {
|
it should "pass simple retime module annotation" in {
|
||||||
val gen = () => new RetimeModule()
|
val gen = () => new RetimeModule()
|
||||||
val dir = uniqueDirName(gen, "RetimeModule")
|
val dir = uniqueDirName(gen, "RetimeModule")
|
||||||
chisel3.Driver.execute(Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final"), gen) shouldBe a [ChiselExecutionSuccess]
|
|
||||||
|
|
||||||
val lines = io.Source.fromFile(s"test_run_dir/$dir/test_run_dir/$dir/final.anno.json").getLines().map(normalized).mkString("\n")
|
Logger.makeScope(Seq.empty) {
|
||||||
lines should include("barstools.tapeout.transforms.retime.RetimeTransform")
|
val captor = new Logger.OutputCaptor
|
||||||
|
Logger.setOutput(captor.printStream)
|
||||||
|
val firrtl = (new ChiselStage).emitFirrtl(
|
||||||
|
new RetimeModule(),
|
||||||
|
Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final", "--log-level", "info")
|
||||||
|
)
|
||||||
|
firrtl.nonEmpty should be(true)
|
||||||
|
//Make sure we got the RetimeTransform scheduled
|
||||||
|
captor.getOutputAsString should include ("barstools.tapeout.transforms.retime.RetimeTransform")
|
||||||
|
}
|
||||||
|
|
||||||
|
val lines = FileUtils.getLines(s"test_run_dir/$dir/test_run_dir/$dir/final.anno.json")
|
||||||
|
.map(normalized)
|
||||||
|
.mkString("\n")
|
||||||
|
lines should include("barstools.tapeout.transforms.retime.RetimeAnnotation")
|
||||||
|
lines should include(""""target":"RetimeModule.RetimeModule"""")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(azidar): need to fix/add instance annotations
|
it should "pass simple retime instance annotation" in {
|
||||||
ignore should "pass simple retime instance annotation" in {
|
|
||||||
val gen = () => new RetimeInstance()
|
val gen = () => new RetimeInstance()
|
||||||
val dir = uniqueDirName(gen, "RetimeInstance")
|
val dir = uniqueDirName(gen, "RetimeInstance")
|
||||||
chisel3.Driver.execute(Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final.anno"), gen) shouldBe a [ChiselExecutionSuccess]
|
|
||||||
|
|
||||||
val lines = io.Source.fromFile(s"test_run_dir/$dir/final.anno").getLines().map(normalized).toSeq
|
Logger.makeScope(Seq.empty) {
|
||||||
lines should contain ("Annotation(ComponentName(instance, ModuleName(RetimeInstance,CircuitName(RetimeInstance))),class barstools.tapeout.transforms.retime.RetimeTransform,retime)")
|
val captor = new Logger.OutputCaptor
|
||||||
|
Logger.setOutput(captor.printStream)
|
||||||
|
val firrtl = (new ChiselStage).emitFirrtl(
|
||||||
|
new RetimeInstance(),
|
||||||
|
Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final", "--log-level", "info")
|
||||||
|
)
|
||||||
|
firrtl.nonEmpty should be(true)
|
||||||
|
//Make sure we got the RetimeTransform scheduled
|
||||||
|
captor.getOutputAsString should include ("barstools.tapeout.transforms.retime.RetimeTransform")
|
||||||
|
}
|
||||||
|
|
||||||
|
val lines = FileUtils.getLines(s"test_run_dir/$dir/test_run_dir/$dir/final.anno.json")
|
||||||
|
.map(normalized)
|
||||||
|
.mkString("\n")
|
||||||
|
lines should include("barstools.tapeout.transforms.retime.RetimeAnnotation")
|
||||||
|
lines should include(""""target":"RetimeInstance.MyModule"""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user