80 lines
3.4 KiB
Scala
80 lines
3.4 KiB
Scala
package barstools.tapeout.transforms.pads
|
|
|
|
import chisel3._
|
|
import barstools.tapeout.transforms.clkgen._
|
|
import chisel3.experimental._
|
|
import firrtl.transforms.DedupModules
|
|
|
|
// TODO: Move out of pads
|
|
|
|
// NOTE: You can't really annotate outside of the module itself UNLESS you break up the compile step in 2 i.e.
|
|
// annotate post-Chisel but pre-Firrtl (unfortunate non-generator friendly downside).
|
|
// It's recommended to have a Tapeout specific TopModule wrapper.
|
|
// LIMITATION: All signals of a bus must be on the same chip side
|
|
|
|
// Chisel-y annotations
|
|
abstract class TopModule(
|
|
supplyAnnos: Seq[SupplyAnnotation] = Seq.empty,
|
|
defaultPadSide: PadSide = Top,
|
|
coreWidth: Int = 0,
|
|
coreHeight: Int = 0,
|
|
usePads: Boolean = true,
|
|
override_clock: Option[Clock] = None,
|
|
override_reset: Option[Bool] = None) extends Module with IsClkModule {
|
|
|
|
override_clock.foreach(clock := _)
|
|
override_reset.foreach(reset := _)
|
|
|
|
override def annotateClkPort(p: Element, anno: ClkPortAnnotation): Unit = {
|
|
DataMirror.directionOf(p) match {
|
|
case chisel3.core.ActualDirection.Input =>
|
|
require(anno.tag.nonEmpty, "Top Module input clks must be clk sinks")
|
|
require(anno.tag.get.src.nonEmpty,
|
|
"Top module input clks must have clk period, etc. specified")
|
|
case _ =>
|
|
throw new Exception("Clk port direction must be specified!")
|
|
}
|
|
p match {
|
|
case _: chisel3.core.Clock =>
|
|
case _ => throw new Exception("Clock port must be of type Clock")
|
|
}
|
|
annotate(TargetClkPortAnnoC(p, anno))
|
|
}
|
|
|
|
override def annotateDerivedClks(m: Module, anno: ClkModAnnotation): Unit =
|
|
throw new Exception("Top module cannot be pure clock module!")
|
|
|
|
// Annotate module as top module (that requires pad transform)
|
|
// Specify the yaml file that indicates how pads are templated,
|
|
// the default chip side that pads should be placed (if nothing is specified per IO),
|
|
// and supply annotations: supply pad name, location, and #
|
|
def createPads(): Unit = if (usePads) {
|
|
val modulePadAnnotation = ModulePadAnnotation(
|
|
defaultPadSide = defaultPadSide.serialize,
|
|
coreWidth = coreWidth,
|
|
coreHeight = coreHeight,
|
|
supplyAnnos = supplyAnnos
|
|
)
|
|
annotate(TargetModulePadAnnoC(this, modulePadAnnotation))
|
|
}
|
|
|
|
// 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))
|
|
}
|
|
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, name: String): Unit =
|
|
extractElements(sig) foreach { x => annotatePad(x, side, name) }
|
|
|
|
// 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: Aggregate): Unit = extractElements(sig) foreach { x => noPad(x) }
|
|
|
|
// Since this is a super class, this should be the first thing that gets run
|
|
// (at least when the module is actually at the top -- currently no guarantees otherwise :( firrtl limitation)
|
|
createPads()
|
|
}
|