Files
chipyard/tapeout/src/main/scala/transforms/.pads/AnnotatePortPads.scala
Adam Izraelevitz 96939c9ab6 Moved clkgen -> .clkgen and pads -> .pads
They no longer compile with the latest Chisel/FIRRTL, and
may not be supported. However, future work will need them, so
this keeps the files around but are ignored by sbt.
2017-09-06 14:44:09 -07:00

134 lines
5.1 KiB
Scala

package barstools.tapeout.transforms.pads
import firrtl.annotations._
import firrtl._
import firrtl.ir._
import barstools.tapeout.transforms._
// TODO: Make some trait with commonalities between IO Pad + supply pad
// Pads associated with IO Ports! (Not supplies!)
case class PortIOPad(
pad: Option[FoundryPad],
padSide: PadSide,
port: Port) {
def arrayInstNamePrefix(mod: String): String = Seq(mod, firrtlBBName, getPadName).mkString("/")
def arrayInstNameSuffix: String = pad match {
case None => throw new Exception("Port needs to use pad to get array instance name!")
case Some(x) => "/" + x.padInstName
}
def portName = port.name
def portWidth = bitWidth(port.tpe).intValue
def portDirection = port.direction
def padOrientation = padSide.orientation
def padType = pad match {
case None => NoPad
case Some(x) => x.padType
}
def widthParamName = "WIDTH"
def getPadName: String = pad match {
case None => throw new Exception("Cannot get pad name when no pad specified!")
case Some(x) => x.getName(portDirection, padOrientation)
}
def getPadArrayName: String = Seq(getPadName, "array").mkString("_")
// Firrtl black box name must be unique, even though the parameterized Verilog modules don't
// need to have separate names
def firrtlBBName = Seq(getPadArrayName, portName).mkString("_")
// Note: This includes both the pad wrapper + an additional wrapper for n-bit wide to
// multiple pad conversion!
def createPadInline(): String = {
// For blackboxing bit extraction/concatenation (with module arrays)
def io(): String = padType match {
case DigitalPad =>
s"""| input [${widthParamName}-1:0] ${DigitalPad.inName},
| output reg [${widthParamName}-1:0] ${DigitalPad.outName}""".stripMargin
case AnalogPad =>
s" inout [${widthParamName}-1:0] ${AnalogPad.ioName}"
case _ => throw new Exception("IO pad can only be digital or analog")
}
def assignIO(): String = padType match {
case DigitalPad =>
s"""| .${DigitalPad.inName}(${DigitalPad.inName}),
| .${DigitalPad.outName}(${DigitalPad.outName})""".stripMargin
case AnalogPad =>
s" .${AnalogPad.ioName}(${AnalogPad.ioName})"
case _ => throw new Exception("IO pad can only be digital or analog")
}
def getPadVerilog(): String = pad match {
case None => throw new Exception("Cannot get Verilog when no pad specified!")
case Some(x) => x.getVerilog(portDirection, padOrientation)
}
s"""inline
|${getPadArrayName}.v
|${getPadVerilog}
|module ${getPadArrayName} #(
| parameter int ${widthParamName}=1
|)(
|${io}
|);
| ${getPadName} ${getPadName}[${widthParamName}-1:0](
|${assignIO}
| );
|endmodule""".stripMargin
}
}
object AnnotatePortPads {
def apply(
c: Circuit,
topMod: String,
pads: Seq[FoundryPad],
componentAnnos: Seq[TargetIOPadAnnoF],
defaultSide: PadSide): Seq[PortIOPad] = {
def lowerAnnotations(): Seq[TargetIOPadAnnoF] = {
componentAnnos map { x => x.target match {
case c: ComponentName => x.copy(target = c.copy(name = LowerName(c.name)))
case _ => throw new Exception("Not a component annotation! Can't lower!")
}}
}
// Make annotations match low form
val annos = lowerAnnotations()
def getPortIOPad(port: Port): PortIOPad = {
val portAnnos = annos.find(_.targetName == port.name)
// Ports can only be digital or analog
val padTypeRequired = port.tpe match {
case AnalogType(_) => AnalogPad
case _ => DigitalPad
}
val validPads = pads.filter(_.padType == padTypeRequired)
require(validPads.length > 0, s"No ${padTypeRequired.serialize} pads specified in the config yaml file!")
portAnnos match {
case None =>
// If no pad-related annotation is found on a port, use defaults based off of port type
PortIOPad(Some(validPads.head), defaultSide, port)
case Some(x) =>
x.anno match {
case NoIOPadAnnotation(_) =>
// Some ports might not want attached pads
PortIOPad(None, defaultSide, port)
case IOPadAnnotation(padSide, padName) if padName.isEmpty =>
// If no pad name is used, select the first valid pad based off of port type
PortIOPad(Some(validPads.head), HasPadAnnotation.getSide(padSide), port)
case IOPadAnnotation(padSide, padName) =>
// If name doesn't match any provided -- maybe someone typoed?
validPads.find(_.name == padName) match {
case None =>
throw new Exception(
s"Pad name associated with ${port.name} doesn't match valid pad names. Did you typo?")
case Some(x) =>
PortIOPad(Some(x), HasPadAnnotation.getSide(padSide), port)
}
}
}
}
// Top MUST be internal module
c.modules.filter(_.name == topMod).head.ports.map(x => getPortIOPad(x))
}
}