[stevo]: adds a bunch of pad frame commits, as well as beginning work on clocking annotations and constraints * start add io pads pass * save progress adding yaml pad info * saving some semi-presentable work -- parses yaml for pad templates and associates templates with ports * added black boxes to the module; still need to hook up * added supply pad yaml example; added option to not include pad for an IO, blackboxed that cat + bit extraction functions * rewrite createbbs and some other parts of the transform * finally got blackboxhelper to work -- seems there was a typo in the firrtl pass (?) have not connected them up properly in the padframe * finished first version of pad transform; need to add bells and whistles + special case stuff * made a bunch of changes in firrtl to shorthand things * done with padframe for signals * started major refactoring; first of pad yaml stuff * forgot to update verilogTemplate -> verilog * rename ParsePadYaml -> ChipPadsYaml; moved some stuff * separated out stuff that describes pads i.e. direction, type, side * forgot to update import for yamlhelpers * trying to make the process of creating annotations more structured * saving annotation helpers but prob better to switch to yaml * saving changes -- reworking annotations * fixing some bugs; properly annotated ports with pads * annotate supply pads * lesson (re)learned. cleaned up constants * finished adding supply pads to pad frame; still need to generate io file * also committing updated transform; still without io file * big typo was causing pad verilog files not to be generated * verilator passes with transform; had to fix verilog bb typo * added unused pads; added more thorough tests + did visual inspection of output; made some port types more explicit * renamed files/classes to be clearer * started creating pad io template * update spec so that transform order matters * get rid of logger * went around in circles with blackboxhelper + way to annotate * finished adding + testing pad.io creation * starting clkgen pass -- made model for asynchronously reset clk divider + wrappers for programmatic bundling * temporarily locating albert's utility functions here * saving work on clk constraints * redid input config passing -- pass in tech directory instead; seems like getting clk sink, src, and relationship works * not done; need to pause to do tapeout-y things. the clk gen pass gets all the clks and their sources, but i need to build a proper graph to handle clks coming out of muxes
133 lines
5.3 KiB
Scala
133 lines
5.3 KiB
Scala
package barstools.tapeout.transforms.pads
|
|
|
|
import firrtl.annotations._
|
|
import chisel3.experimental._
|
|
import chisel3._
|
|
import barstools.tapeout.transforms._
|
|
import firrtl._
|
|
|
|
import net.jcazevedo.moultingyaml._
|
|
|
|
object PadAnnotationsYaml extends DefaultYamlProtocol {
|
|
implicit val _iopad = yamlFormat2(IOPadAnnotation)
|
|
implicit val _noiopad = yamlFormat1(NoIOPadAnnotation)
|
|
implicit val _supplyanno = yamlFormat5(SupplyAnnotation)
|
|
implicit val _modulepadanno = yamlFormat4(ModulePadAnnotation)
|
|
}
|
|
|
|
abstract class FirrtlPadTransformAnnotation {
|
|
def targetName: String
|
|
}
|
|
|
|
// IO Port can either be annotated with padName + padSide OR noPad (mutually exclusive)
|
|
abstract class IOAnnotation {
|
|
def serialize: String
|
|
}
|
|
case class IOPadAnnotation(padSide: String, padName: String) extends IOAnnotation {
|
|
import PadAnnotationsYaml._
|
|
def serialize: String = this.toYaml.prettyPrint
|
|
def getPadSide: PadSide = HasPadAnnotation.getSide(padSide)
|
|
}
|
|
case class NoIOPadAnnotation(noPad: String = "") extends IOAnnotation {
|
|
import PadAnnotationsYaml._
|
|
def serialize: String = this.toYaml.prettyPrint
|
|
def field = "noPad:"
|
|
}
|
|
// Firrtl version
|
|
case class TargetIOPadAnnoF(target: ComponentName, anno: IOAnnotation) extends FirrtlPadTransformAnnotation {
|
|
def getAnno = Annotation(target, classOf[AddIOPadsTransform], anno.serialize)
|
|
def targetName = target.name
|
|
}
|
|
// Chisel version
|
|
case class TargetIOPadAnnoC(target: Element, anno: IOAnnotation) {
|
|
def getAnno = ChiselAnnotation(target, classOf[AddIOPadsTransform], anno.serialize)
|
|
}
|
|
|
|
// A bunch of supply pads (designated by name, # on each chip side) can be associated with the top module
|
|
case class SupplyAnnotation(
|
|
padName: String,
|
|
leftSide: Int = 0,
|
|
rightSide: Int = 0,
|
|
topSide: Int = 0,
|
|
bottomSide: Int = 0)
|
|
// The chip top should have a default pad side, a pad template file, and supply annotations
|
|
case class ModulePadAnnotation(
|
|
defaultPadSide: String = Top.serialize,
|
|
coreWidth: Int = 0,
|
|
coreHeight: Int = 0,
|
|
supplyAnnos: Seq[SupplyAnnotation] = Seq.empty) {
|
|
import PadAnnotationsYaml._
|
|
def serialize: String = this.toYaml.prettyPrint
|
|
val supplyPadNames = supplyAnnos.map(_.padName)
|
|
require(supplyPadNames.distinct.length == supplyPadNames.length, "Supply pads should only be specified once!")
|
|
def getDefaultPadSide: PadSide = HasPadAnnotation.getSide(defaultPadSide)
|
|
}
|
|
// Firrtl version
|
|
case class TargetModulePadAnnoF(target: ModuleName, anno: ModulePadAnnotation) extends FirrtlPadTransformAnnotation {
|
|
def getAnno = Annotation(target, classOf[AddIOPadsTransform], anno.serialize)
|
|
def targetName = target.name
|
|
}
|
|
// Chisel version
|
|
case class TargetModulePadAnnoC(target: Module, anno: ModulePadAnnotation) {
|
|
def getAnno = ChiselAnnotation(target, classOf[AddIOPadsTransform], anno.serialize)
|
|
}
|
|
|
|
case class CollectedAnnos(
|
|
componentAnnos: Seq[TargetIOPadAnnoF],
|
|
moduleAnnos: TargetModulePadAnnoF) {
|
|
def supplyAnnos = moduleAnnos.anno.supplyAnnos
|
|
def defaultPadSide = moduleAnnos.anno.defaultPadSide
|
|
def topModName = moduleAnnos.targetName
|
|
def coreWidth = moduleAnnos.anno.coreWidth
|
|
def coreHeight = moduleAnnos.anno.coreHeight
|
|
}
|
|
|
|
object HasPadAnnotation {
|
|
import PadAnnotationsYaml._
|
|
|
|
def getSide(a: String): PadSide = a match {
|
|
case i if i == Left.serialize => Left
|
|
case i if i == Right.serialize => Right
|
|
case i if i == Top.serialize => Top
|
|
case i if i == Bottom.serialize => Bottom
|
|
case _ => throw new Exception(s" $a not a valid pad side annotation!")
|
|
}
|
|
|
|
def unapply(a: Annotation): Option[FirrtlPadTransformAnnotation] = a match {
|
|
case Annotation(f, t, s) if t == classOf[AddIOPadsTransform] => f match {
|
|
case m: ModuleName =>
|
|
Some(TargetModulePadAnnoF(m, s.parseYaml.convertTo[ModulePadAnnotation]))
|
|
case c: ComponentName if s.contains(NoIOPadAnnotation().field) =>
|
|
Some(TargetIOPadAnnoF(c, s.parseYaml.convertTo[NoIOPadAnnotation]))
|
|
case c: ComponentName =>
|
|
Some(TargetIOPadAnnoF(c, s.parseYaml.convertTo[IOPadAnnotation]))
|
|
case _ => throw new Exception("Annotation only valid on module or component")
|
|
}
|
|
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 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) None
|
|
else {
|
|
val moduleAnnosTemp = padAnnos.filter {
|
|
case TargetModulePadAnnoF(_, _) => true
|
|
case _ => false
|
|
}
|
|
require(moduleAnnosTemp.length == 1, "Only 1 module may be designated 'Top'")
|
|
val moduleAnnos = moduleAnnosTemp.head
|
|
val topModName = moduleAnnos.targetName
|
|
val componentAnnos = padAnnos.filter {
|
|
case TargetIOPadAnnoF(ComponentName(_, ModuleName(n, _)), _) if n == topModName =>
|
|
true
|
|
case TargetIOPadAnnoF(ComponentName(_, ModuleName(n, _)), _) if n != topModName =>
|
|
throw new Exception("Pad related component annotations must all be in the same top module")
|
|
case _ => false
|
|
}.map(x => x.asInstanceOf[TargetIOPadAnnoF])
|
|
Some(CollectedAnnos(componentAnnos, moduleAnnos.asInstanceOf[TargetModulePadAnnoF]))
|
|
}
|
|
}
|
|
} |