- Made separate case class for data - Now parses - Fails later with UnknownType in firrt compiler - Fixed similar parsing problem with PadPlacement
130 lines
4.5 KiB
Scala
130 lines
4.5 KiB
Scala
// See LICENSE for license details.
|
|
|
|
package barstools.tapeout.transforms.pads
|
|
|
|
import net.jcazevedo.moultingyaml._
|
|
|
|
import firrtl._
|
|
import firrtl.ir._
|
|
import barstools.tapeout.transforms._
|
|
|
|
trait HasFoundryPadFields {
|
|
val tpe: String
|
|
val name: String
|
|
val width: Int
|
|
val height: Int
|
|
val supplySetNum: Option[Int]
|
|
val verilog: String
|
|
}
|
|
|
|
case class FoundryPadFields(
|
|
tpe: String,
|
|
name: String,
|
|
width: Int,
|
|
height: Int,
|
|
supplySetNum: Option[Int],
|
|
verilog: String)
|
|
extends HasFoundryPadFields
|
|
|
|
case class FoundryPad(
|
|
tpe: String,
|
|
name: String,
|
|
width: Int,
|
|
height: Int,
|
|
supplySetNum: Option[Int],
|
|
verilog: String)
|
|
extends HasFoundryPadFields {
|
|
|
|
def padInstName = "PAD"
|
|
|
|
require(verilog.contains("{{#if isHorizontal}}"), "All pad templates must contain '{{#if isHorizontal}}'")
|
|
require(verilog.contains("{{name}}"), "All pad templates must contain module name '{{name}}'")
|
|
require(verilog.contains(padInstName), s"All pad templates should have instances called ${padInstName}")
|
|
|
|
def getSupplySetNum = supplySetNum.getOrElse(1)
|
|
|
|
val padType = tpe match {
|
|
case "digital" =>
|
|
require(verilog.contains(DigitalPad.inName), "Digital pad template must contain input called 'in'")
|
|
require(verilog.contains(DigitalPad.outName), "Digital pad template must contain output called 'out'")
|
|
require(verilog.contains("{{#if isInput}}"), "Digital pad template must contain '{{#if isInput}}'")
|
|
DigitalPad
|
|
case "analog" =>
|
|
require(verilog.contains(AnalogPad.ioName), "Analog pad template must contain inout called 'io'")
|
|
require(!verilog.contains("{{#if isInput}}"), "Analog pad template must not contain '{{#if isInput}}'")
|
|
AnalogPad
|
|
case "supply" =>
|
|
// Supply pads don't have IO
|
|
require(!verilog.contains("{{#if isInput}}"), "Supply pad template must not contain '{{#if isInput}}'")
|
|
require(
|
|
verilog.contains(s"${padInstName}["),
|
|
"All supply pad templates should have instance arrays" +
|
|
" called ${padInstName}[n:0], where n = ${getSupplySetNum-1}"
|
|
)
|
|
require(supplySetNum.nonEmpty, "# of grouped supply pads 'supplySetNum' should be specified!")
|
|
SupplyPad
|
|
case _ => throw new Exception("Illegal pad type in config!")
|
|
}
|
|
|
|
import com.gilt.handlebars.scala.binding.dynamic._
|
|
import com.gilt.handlebars.scala.Handlebars
|
|
private val template = Handlebars(verilog)
|
|
|
|
// Make sure names don't have spaces in Verilog!
|
|
private[barstools] val correctedName = name.replace(" ", "_")
|
|
|
|
case class TemplateParams(
|
|
// isInput only used with digital pads
|
|
isInput: Boolean,
|
|
isHorizontal: Boolean) {
|
|
|
|
private val orient = if (isHorizontal) Horizontal.serialize else Vertical.serialize
|
|
private val dir = padType match {
|
|
case AnalogPad => "inout"
|
|
case SupplyPad => "none"
|
|
case DigitalPad => if (isInput) Input.serialize else Output.serialize
|
|
}
|
|
val name = {
|
|
val start = Seq("pad", tpe, correctedName, orient)
|
|
if (padType == DigitalPad) start :+ dir
|
|
else start
|
|
}.mkString("_")
|
|
}
|
|
|
|
// Note: Analog + supply don't use direction
|
|
private def getTemplateParams(dir: Direction, orient: PadOrientation): TemplateParams =
|
|
TemplateParams(isInput = (dir == Input), isHorizontal = (orient == Horizontal))
|
|
|
|
def getVerilog(dir: Direction, orient: PadOrientation): String = {
|
|
val p = getTemplateParams(dir, orient)
|
|
template(p).stripMargin
|
|
}
|
|
|
|
def getName(dir: Direction, orient: PadOrientation): String = getTemplateParams(dir, orient).name
|
|
}
|
|
|
|
object FoundryPadsYaml extends DefaultYamlProtocol {
|
|
val exampleResource = "/FoundryPads.yaml"
|
|
implicit val _pad = yamlFormat6(FoundryPadFields)
|
|
def parse(techDir: String): Seq[FoundryPad] = {
|
|
val file = techDir + exampleResource
|
|
if (techDir != "" && !(new java.io.File(file)).exists()) {
|
|
throw new Exception(s"Technology directory $techDir must contain FoundryPads.yaml!")
|
|
}
|
|
val fieldsArray = (new YamlFileReader(exampleResource)).parse[FoundryPadFields](if (techDir == "") "" else file)
|
|
val out = fieldsArray.map { fields =>
|
|
FoundryPad(
|
|
tpe = fields.tpe,
|
|
name = fields.name,
|
|
width = fields.width,
|
|
height = fields.height,
|
|
supplySetNum = fields.supplySetNum,
|
|
verilog = fields.verilog
|
|
)
|
|
}
|
|
val padNames = out.map(x => x.correctedName)
|
|
require(padNames.distinct.length == padNames.length, "Pad names must be unique!")
|
|
out
|
|
}
|
|
}
|