Remove all of the PadStuff
This commit is contained in:
@@ -1,113 +0,0 @@
|
|||||||
# Pad types must be one of digital, analog, or supply; pad names must be unique!
|
|
||||||
# This just shows you how you can template things with {{}}, if/else, and the following parameters:
|
|
||||||
# isInput: Boolean (each digital pad entry should be configurable between both input and output)
|
|
||||||
# isHorizontal: Boolean (each pad entry should be configurable between both horizontal and vertical)
|
|
||||||
# NOTE: Expects 1-bit in/out to be named in/out for digital; and 1-bit io for analog (supplies don't have ports)
|
|
||||||
# Expects module name to be obtained from {{name}} which is derived from yaml name, tpe in the Firrtl pass
|
|
||||||
# Pipe is used for stripping margins, but indentation is required before the pipe for the yaml reader to work
|
|
||||||
---
|
|
||||||
tpe: analog
|
|
||||||
name: slow_foundry
|
|
||||||
width: 0
|
|
||||||
height: 0
|
|
||||||
verilog: |
|
|
||||||
|// Foundry Analog Pad Example
|
|
||||||
|// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}}
|
|
||||||
|// Call your instance PAD
|
|
||||||
|module {{name}}(
|
|
||||||
| inout io
|
|
||||||
|);
|
|
||||||
|endmodule
|
|
||||||
---
|
|
||||||
tpe: analog
|
|
||||||
name: fast_custom
|
|
||||||
width: 0
|
|
||||||
height: 0
|
|
||||||
verilog: |
|
|
||||||
|// Custom Analog Pad Example
|
|
||||||
|// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}}
|
|
||||||
|// Call your instance PAD
|
|
||||||
|module {{name}}(
|
|
||||||
| inout io
|
|
||||||
|);
|
|
||||||
|endmodule
|
|
||||||
---
|
|
||||||
tpe: digital
|
|
||||||
name: from_tristate_foundry
|
|
||||||
width: 0
|
|
||||||
height: 0
|
|
||||||
verilog: |
|
|
||||||
|// Digital Pad Example
|
|
||||||
|// Signal Direction: {{#if isInput}}Input{{else}}Output{{/if}}
|
|
||||||
|// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}}
|
|
||||||
|// Call your instance PAD
|
|
||||||
|module {{name}}(
|
|
||||||
| input in,
|
|
||||||
| output reg out
|
|
||||||
|);
|
|
||||||
| // Where you would normally dump your pad instance
|
|
||||||
| always @* begin
|
|
||||||
| out = in;
|
|
||||||
| end
|
|
||||||
|endmodule
|
|
||||||
---
|
|
||||||
tpe: digital
|
|
||||||
name: fake_digital
|
|
||||||
width: 0
|
|
||||||
height: 0
|
|
||||||
verilog: |
|
|
||||||
|// (Fake/Unused) Digital Pad Example
|
|
||||||
|// Signal Direction: {{#if isInput}}Input{{else}}Output{{/if}}
|
|
||||||
|// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}}
|
|
||||||
|// Call your instance PAD
|
|
||||||
|module {{name}}(
|
|
||||||
| input in,
|
|
||||||
| output reg out
|
|
||||||
|);
|
|
||||||
| // Where you would normally dump your pad instance
|
|
||||||
| always @* begin
|
|
||||||
| out = in;
|
|
||||||
| end
|
|
||||||
|endmodule
|
|
||||||
---
|
|
||||||
tpe: supply
|
|
||||||
name: vdd
|
|
||||||
width: 0
|
|
||||||
height: 0
|
|
||||||
supplySetNum: 1
|
|
||||||
verilog: |
|
|
||||||
|// VDD Pad Example (No IO)
|
|
||||||
|// Can group some number together as required by the foundry
|
|
||||||
|// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}}
|
|
||||||
|// Call your instance array PAD[0:0], PAD[2:0], etc.
|
|
||||||
|module {{name}}(
|
|
||||||
|);
|
|
||||||
|endmodule
|
|
||||||
---
|
|
||||||
tpe: supply
|
|
||||||
name: vss
|
|
||||||
width: 0
|
|
||||||
height: 0
|
|
||||||
supplySetNum: 2
|
|
||||||
verilog: |
|
|
||||||
|// VSS Pad Example (No IO)
|
|
||||||
|// Can group some number together as required by the foundry
|
|
||||||
|// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}}
|
|
||||||
|// Call your instance array PAD[0:0], PAD[2:0], etc.
|
|
||||||
|module {{name}}(
|
|
||||||
|);
|
|
||||||
|endmodule
|
|
||||||
---
|
|
||||||
tpe: supply
|
|
||||||
name: avss
|
|
||||||
width: 0
|
|
||||||
height: 0
|
|
||||||
supplySetNum: 1
|
|
||||||
verilog: |
|
|
||||||
|// Analog VSS Pad Example (No IO)
|
|
||||||
|// Can group some number together as required by the foundry
|
|
||||||
|// Pad Orientation: {{#if isHorizontal}}Horizontal{{else}}Vertical{{/if}}
|
|
||||||
|// Call your instance array PAD[0:0], PAD[2:0], etc.
|
|
||||||
|module {{name}}(
|
|
||||||
|);
|
|
||||||
|endmodule
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
# Example for Innovus: https://legacy.iis.ee.ethz.ch/~vlsi2/ex05/ex05.pdf
|
|
||||||
---
|
|
||||||
file: pads.io
|
|
||||||
left: "1" # Bottom to top
|
|
||||||
top: "2" # Left to right
|
|
||||||
right: "3" # Bottom to top
|
|
||||||
bottom: "4" # Left to right
|
|
||||||
# Note: In your scripts, you should specify instance array styles
|
|
||||||
# i.e. hdl_instance_array_naming_style string (For Genus)
|
|
||||||
instanceArray: "{{signal}}[{{idx}}]"
|
|
||||||
padLine: |
|
|
||||||
| (inst name = "{{padInst}}") # Side: {{side}}, Order: {{padIdx}}
|
|
||||||
template: |
|
|
||||||
|(globals
|
|
||||||
| version = 3
|
|
||||||
| io_order = default
|
|
||||||
|)
|
|
||||||
|(iopad
|
|
||||||
| (bottomleft
|
|
||||||
| (inst name="corner_ll" cell="CORNER_EXAMPLE" )
|
|
||||||
| )
|
|
||||||
| (bottomright
|
|
||||||
| (inst name="corner_lr" orientation=MY cell="CORNER_EXAMPLE" )
|
|
||||||
| )
|
|
||||||
| (topleft
|
|
||||||
| (inst name="corner_ul" orientation=MX cell="CORNER_EXAMPLE" )
|
|
||||||
| )
|
|
||||||
| (topright
|
|
||||||
| (inst name="corner_ur" cell="CORNER_EXAMPLE" )
|
|
||||||
| )
|
|
||||||
| (left
|
|
||||||
|{{leftPads}}
|
|
||||||
| )
|
|
||||||
| (right
|
|
||||||
|{{rightPads}}
|
|
||||||
| )
|
|
||||||
| (top
|
|
||||||
|{{topPads}}
|
|
||||||
| )
|
|
||||||
| (bottom
|
|
||||||
|{{bottomPads}}
|
|
||||||
| )
|
|
||||||
|)
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
// See LICENSE for license details.
|
|
||||||
|
|
||||||
package barstools.tapeout.transforms.pads
|
|
||||||
|
|
||||||
import firrtl._
|
|
||||||
import firrtl.passes._
|
|
||||||
import barstools.tapeout.transforms._
|
|
||||||
import firrtl.options.Dependency
|
|
||||||
import firrtl.stage.Forms
|
|
||||||
import firrtl.stage.TransformManager.TransformDependency
|
|
||||||
|
|
||||||
import scala.collection.mutable
|
|
||||||
|
|
||||||
// Main Add IO Pad transform operates on low Firrtl
|
|
||||||
class AddIOPadsTransform extends Transform with SeqTransformBased with DependencyAPIMigration {
|
|
||||||
|
|
||||||
override def prerequisites: Seq[TransformDependency] = Forms.LowForm
|
|
||||||
override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized
|
|
||||||
override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters
|
|
||||||
|
|
||||||
val transformList = new mutable.ArrayBuffer[Transform]
|
|
||||||
def transforms: Seq[Transform] = transformList
|
|
||||||
|
|
||||||
override def execute(state: CircuitState): CircuitState = {
|
|
||||||
val collectedAnnos = HasPadAnnotation(state.annotations)
|
|
||||||
collectedAnnos match {
|
|
||||||
// Transform not used
|
|
||||||
case None => state
|
|
||||||
case Some(x) =>
|
|
||||||
val techLoc = (new TechnologyLocation).get(state)
|
|
||||||
// Get foundry pad templates from yaml
|
|
||||||
val foundryPads = FoundryPadsYaml.parse(techLoc)
|
|
||||||
val portPads = AnnotatePortPads(state.circuit, x.topModName, foundryPads, x.componentAnnos,
|
|
||||||
HasPadAnnotation.getSide(x.defaultPadSide))
|
|
||||||
val supplyPads = AnnotateSupplyPads(foundryPads, x.supplyAnnos)
|
|
||||||
val (circuitWithBBs, bbAnnotations) = CreatePadBBs(state.circuit, portPads, supplyPads)
|
|
||||||
val namespace = Namespace(state.circuit)
|
|
||||||
val padFrameName = namespace newName s"${x.topModName}_PadFrame"
|
|
||||||
val topInternalName = namespace newName s"${x.topModName}_Internal"
|
|
||||||
val targetDir = barstools.tapeout.transforms.GetTargetDir(state)
|
|
||||||
PadPlacementFile.generate(techLoc, targetDir, padFrameName, portPads, supplyPads)
|
|
||||||
transformList ++= Seq(
|
|
||||||
Legalize,
|
|
||||||
ResolveFlows,
|
|
||||||
// Types really need to be known...
|
|
||||||
InferTypes,
|
|
||||||
new AddPadFrame(x.topModName, padFrameName, topInternalName, portPads, supplyPads),
|
|
||||||
RemoveEmpty,
|
|
||||||
CheckInitialization,
|
|
||||||
InferTypes,
|
|
||||||
Uniquify,
|
|
||||||
ResolveKinds,
|
|
||||||
ResolveFlows
|
|
||||||
)
|
|
||||||
// Expects BlackBox helper to be run after to inline pad Verilog!
|
|
||||||
val ret = runTransforms(state)
|
|
||||||
val currentAnnos = ret.annotations
|
|
||||||
val newAnnoMap = AnnotationSeq(currentAnnos ++ bbAnnotations)
|
|
||||||
val newState = CircuitState(ret.circuit, outputForm, newAnnoMap, ret.renames)
|
|
||||||
|
|
||||||
// TODO: *.f file is overwritten on subsequent executions, but it doesn't seem to be used anywhere?
|
|
||||||
(new firrtl.transforms.BlackBoxSourceHelper).execute(newState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
// See LICENSE for license details.
|
|
||||||
|
|
||||||
package barstools.tapeout.transforms.pads
|
|
||||||
|
|
||||||
import firrtl.annotations._
|
|
||||||
import firrtl.ir._
|
|
||||||
import firrtl._
|
|
||||||
import firrtl.passes.Pass
|
|
||||||
|
|
||||||
// Analog is like UInt, SInt; it's not a direction (which is kind of weird)
|
|
||||||
// WARNING: Analog type is associated with Verilog InOut! i.e. even if digital pads are tri-statable, b/c tristate
|
|
||||||
// requires an additional ctrl signal, digital pads must be operated in a single "static" condition here; Analog will
|
|
||||||
// be paired with analog pads
|
|
||||||
|
|
||||||
class AddPadFrame(
|
|
||||||
topMod: String,
|
|
||||||
padFrameName: String,
|
|
||||||
topInternalName: String,
|
|
||||||
ioPads: Seq[PortIOPad],
|
|
||||||
supplyPads: Seq[TopSupplyPad]) extends Pass {
|
|
||||||
|
|
||||||
def run(c: Circuit): Circuit = {
|
|
||||||
// New modules consist of old modules (with top renamed to internal) + padFrame + newTop
|
|
||||||
val newMods = c.modules.map {
|
|
||||||
case mod: Module if mod.name == topMod =>
|
|
||||||
// Original top module is now internal module
|
|
||||||
mod.copy(name = topInternalName)
|
|
||||||
case m => m
|
|
||||||
} ++ Seq(buildPadFrame(), buildTopWrapper())
|
|
||||||
|
|
||||||
// Reparent so circuit top is whatever uses pads!
|
|
||||||
// TODO: Can the top level be a blackbox?
|
|
||||||
c.copy(modules = newMods, main = topMod)
|
|
||||||
}
|
|
||||||
|
|
||||||
def intName(p: PortIOPad) = s"${p.portName}_Int"
|
|
||||||
def extName(p: PortIOPad) = s"${p.portName}_Ext"
|
|
||||||
|
|
||||||
def buildTopWrapper(): Module = {
|
|
||||||
// outside -> padframe -> internal
|
|
||||||
// Top (with same name) contains 1) padframe + 2) internal signals
|
|
||||||
val padFrameInst = WDefInstance(padFrameName, padFrameName)
|
|
||||||
val topInternalInst = WDefInstance(topInternalName, topInternalName)
|
|
||||||
val padFrameRef = WRef(padFrameName)
|
|
||||||
val topInternalRef = WRef(topInternalName)
|
|
||||||
val connects = ioPads.map { p =>
|
|
||||||
val io = WRef(p.portName)
|
|
||||||
val intIo = WSubField(topInternalRef, p.portName)
|
|
||||||
val padFrameIntIo = WSubField(padFrameRef, intName(p))
|
|
||||||
val padFrameExtIo = WSubField(padFrameRef, extName(p))
|
|
||||||
p.port.tpe match {
|
|
||||||
case AnalogType(_) =>
|
|
||||||
// Analog pads only have 1 port
|
|
||||||
// If Analog port doesn't have associated pad, don't hook it up to the padframe
|
|
||||||
val analogAttachInt = Seq(Attach(NoInfo, Seq(io, intIo)))
|
|
||||||
if (p.pad.isEmpty) analogAttachInt
|
|
||||||
else analogAttachInt :+ Attach(NoInfo, Seq(io, padFrameExtIo))
|
|
||||||
case _ => p.portDirection match {
|
|
||||||
case Input =>
|
|
||||||
// input to padframe ; padframe to internal
|
|
||||||
Seq(Connect(NoInfo, padFrameExtIo, io), Connect(NoInfo, intIo, padFrameIntIo))
|
|
||||||
case Output =>
|
|
||||||
// internal to padframe ; padframe to output
|
|
||||||
Seq(Connect(NoInfo, padFrameIntIo, intIo), Connect(NoInfo, io, padFrameExtIo))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.flatten
|
|
||||||
val stmts = Seq(padFrameInst, topInternalInst) ++ connects
|
|
||||||
val ports = ioPads.map(p => p.port)
|
|
||||||
Module(NoInfo, topMod, ports = ports, body = Block(stmts))
|
|
||||||
}
|
|
||||||
|
|
||||||
def buildPadFrame(): Module = {
|
|
||||||
// Internal = connection to original RTL; External = connection to outside world
|
|
||||||
// Note that for analog pads, since there's only 1 port, only _Ext is used
|
|
||||||
val intPorts = ioPads.map(p => p.port.tpe match {
|
|
||||||
case AnalogType(_) => None
|
|
||||||
case _ => Some(p.port.copy(name = intName(p), direction = Utils.swap(p.portDirection)))
|
|
||||||
}).flatten
|
|
||||||
val extPorts = ioPads.map(p => p.port.tpe match {
|
|
||||||
// If an analog port doesn't have a pad associated with it, don't add it to the padframe
|
|
||||||
case AnalogType(_) if p.pad.isEmpty => None
|
|
||||||
case _ => Some(p.port.copy(name = extName(p)))
|
|
||||||
} ).flatten
|
|
||||||
// Only create pad black boxes for ports that require them
|
|
||||||
val ioPadInsts = ioPads.filter(x => !x.pad.isEmpty).map(p => WDefInstance(p.firrtlBBName, p.firrtlBBName))
|
|
||||||
// Connect to pad only if used ; otherwise leave dangling for Analog
|
|
||||||
// and just connect through for digital (assumes no supplies)
|
|
||||||
val connects = ioPads.map { p =>
|
|
||||||
val intRef = WRef(intName(p), p.port.tpe)
|
|
||||||
val extRef = WRef(extName(p), p.port.tpe)
|
|
||||||
p.pad match {
|
|
||||||
// No pad needed -- just connect through
|
|
||||||
case None => p.port.tpe match {
|
|
||||||
case AnalogType(_) =>
|
|
||||||
Seq(EmptyStmt)
|
|
||||||
case _ =>
|
|
||||||
val (lhs, rhs) = p.portDirection match {
|
|
||||||
case Input => (intRef, extRef)
|
|
||||||
case Output => (extRef, intRef)
|
|
||||||
}
|
|
||||||
Seq(Connect(NoInfo, lhs, rhs))
|
|
||||||
}
|
|
||||||
// Add pad
|
|
||||||
case Some(x) =>
|
|
||||||
val padRef = WRef(p.firrtlBBName)
|
|
||||||
p.port.tpe match {
|
|
||||||
// Analog type has 1:1 mapping to inout
|
|
||||||
case AnalogType(_) =>
|
|
||||||
val padIORef = WSubField(padRef, AnalogPad.ioName)
|
|
||||||
Seq(Attach(NoInfo, Seq(padIORef, extRef)))
|
|
||||||
// Normal verilog in/out can be mapped to uint, sint, or clocktype, so need cast
|
|
||||||
case _ =>
|
|
||||||
val padBBType = UIntType(getWidth(p.port.tpe))
|
|
||||||
val padInRef = WSubField(padRef, DigitalPad.inName, padBBType, UnknownFlow)
|
|
||||||
val padOutRef = WSubField(padRef, DigitalPad.outName, padBBType, UnknownFlow)
|
|
||||||
val (rhsPadIn, lhsPadOut) = p.portDirection match {
|
|
||||||
case Input => (extRef, intRef)
|
|
||||||
case Output => (intRef, extRef)
|
|
||||||
}
|
|
||||||
// Pad inputs are treated as UInts, so need to do type conversion
|
|
||||||
// from type to UInt pad input; from pad output to type
|
|
||||||
Seq(
|
|
||||||
Connect(NoInfo, padInRef, castRhs(padBBType, rhsPadIn)),
|
|
||||||
Connect(NoInfo, lhsPadOut, castRhs(p.port.tpe, padOutRef)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.flatten
|
|
||||||
val supplyPadInsts = supplyPads.map(p => p.instNames.map(n => WDefInstance(n, p.firrtlBBName))).flatten
|
|
||||||
Module(NoInfo, padFrameName, ports = intPorts ++ extPorts, body = Block(ioPadInsts ++ connects ++ supplyPadInsts))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
package barstools.tapeout.transforms.pads
|
|
||||||
|
|
||||||
import firrtl.annotations._
|
|
||||||
import firrtl._
|
|
||||||
import firrtl.ir._
|
|
||||||
import firrtl.passes._
|
|
||||||
|
|
||||||
case class TopSupplyPad(
|
|
||||||
pad: FoundryPad,
|
|
||||||
padSide: PadSide,
|
|
||||||
num: Int
|
|
||||||
) {
|
|
||||||
|
|
||||||
// TODO: These should be pulled into some common trait (supply + io)!
|
|
||||||
|
|
||||||
def arrayInstNamePrefix(mod: String): Seq[String] = {
|
|
||||||
instNames.map(n => Seq(mod, n, pad.padInstName).mkString("/"))
|
|
||||||
}
|
|
||||||
def supplySetNum = pad.getSupplySetNum
|
|
||||||
|
|
||||||
def padType = pad.padType
|
|
||||||
require(pad.padType == SupplyPad)
|
|
||||||
|
|
||||||
def padOrientation = padSide.orientation
|
|
||||||
def getPadName = pad.getName(Output/*Should be None*/, padOrientation)
|
|
||||||
def firrtlBBName = getPadName
|
|
||||||
private def instNamePrefix = Seq(firrtlBBName, padSide.serialize).mkString("_")
|
|
||||||
def instNames = (0 until num).map(i => Seq(instNamePrefix, i.toString).mkString("_"))
|
|
||||||
|
|
||||||
def createPadInline(): String = {
|
|
||||||
def getPadVerilog(): String = pad.getVerilog(Output/*Should be None*/, padOrientation)
|
|
||||||
s"""inline
|
|
||||||
|${getPadName}.v
|
|
||||||
|${getPadVerilog}""".stripMargin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object AnnotateSupplyPads {
|
|
||||||
def apply(
|
|
||||||
pads: Seq[FoundryPad],
|
|
||||||
supplyAnnos: Seq[SupplyAnnotation]
|
|
||||||
): Seq[TopSupplyPad] = {
|
|
||||||
supplyAnnos.map( a =>
|
|
||||||
pads.find(_.name == a.padName) match {
|
|
||||||
case None =>
|
|
||||||
throw new Exception(s"Supply pad ${a.padName} not found in Yaml file!")
|
|
||||||
case Some(x) =>
|
|
||||||
Seq(
|
|
||||||
TopSupplyPad(x, Left, a.leftSide),
|
|
||||||
TopSupplyPad(x, Right, a.rightSide),
|
|
||||||
TopSupplyPad(x, Top, a.topSide),
|
|
||||||
TopSupplyPad(x, Bottom, a.bottomSide))
|
|
||||||
}
|
|
||||||
).flatten.filter(_.num > 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
// See LICENSE for license details.
|
|
||||||
|
|
||||||
package barstools.tapeout.transforms.pads
|
|
||||||
|
|
||||||
import chisel3._
|
|
||||||
import chisel3.experimental._
|
|
||||||
import firrtl.Transform
|
|
||||||
import firrtl.annotations.Annotation
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
|
|
||||||
override_clock.foreach(clock := _)
|
|
||||||
override_reset.foreach(reset := _)
|
|
||||||
|
|
||||||
private val mySelf = this
|
|
||||||
|
|
||||||
// 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
|
|
||||||
)
|
|
||||||
//TODO: PORT-1.4: Remove commented code
|
|
||||||
// annotate(TargetModulePadAnnoC(this, modulePadAnnotation))
|
|
||||||
annotate(new ChiselAnnotation with RunFirrtlTransform {
|
|
||||||
override def toFirrtl: Annotation = {
|
|
||||||
TargetModulePadAnnoF(mySelf.toNamed, modulePadAnnotation)
|
|
||||||
}
|
|
||||||
def transformClass: Class[_ <: Transform] = classOf[AddIOPadsTransform]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private def extractElementNames(signal: Data): Seq[String] = {
|
|
||||||
val names = signal match {
|
|
||||||
case elt: Record =>
|
|
||||||
elt.elements.map { case (key, value) => extractElementNames(value).map(x => key + "_" + x) }.toSeq.flatten
|
|
||||||
case elt: Vec[_] =>
|
|
||||||
elt.zipWithIndex.map { case (elt, i) => extractElementNames(elt).map(x => i + "_" + x) }.toSeq.flatten
|
|
||||||
case elt: Element => Seq("")
|
|
||||||
case elt => throw new Exception(s"Cannot extractElementNames for type ${elt.getClass}")
|
|
||||||
}
|
|
||||||
names.map(s => s.stripSuffix("_"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Replace!
|
|
||||||
def extractElements(signal: Data): Seq[Element] = {
|
|
||||||
signal match {
|
|
||||||
case elt: Record =>
|
|
||||||
elt.elements.map { case (key, value) => extractElements(value) }.toSeq.flatten
|
|
||||||
case elt: Vec[_] =>
|
|
||||||
elt.map { elt => extractElements(elt) }.toSeq.flatten
|
|
||||||
case elt: Element => Seq(elt)
|
|
||||||
case elt => throw new Exception(s"Cannot extractElements for type ${elt.getClass}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(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, 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(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) }
|
|
||||||
|
|
||||||
// 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()
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
package barstools.tapeout.transforms.pads
|
|
||||||
|
|
||||||
import firrtl.annotations._
|
|
||||||
import firrtl._
|
|
||||||
import firrtl.ir._
|
|
||||||
import firrtl.transforms._
|
|
||||||
|
|
||||||
object CreatePadBBs {
|
|
||||||
|
|
||||||
private [barstools] case class UsedPadInfo(
|
|
||||||
// The following are found with both supply + io pads
|
|
||||||
padInline: String, // Verilog txt
|
|
||||||
padName: String, // Pad module name
|
|
||||||
padType: PadType, // Pad type: supply, analog, digital
|
|
||||||
// The following only affects io pads (due to using parameterized modules for bit extraction / cat)
|
|
||||||
padArrayName: String, // Name of parameterized pad wrapper (that does bit extract/cat)
|
|
||||||
firrtlBBName: String, // Unique Firrtl name of each parameterized pad wrapper
|
|
||||||
portWidth: Int // Port width for analog/digital
|
|
||||||
)
|
|
||||||
|
|
||||||
def convertToUsedPad(p: PortIOPad): UsedPadInfo = {
|
|
||||||
UsedPadInfo(
|
|
||||||
padInline = p.createPadInline,
|
|
||||||
padName = p.getPadName,
|
|
||||||
padType = p.padType,
|
|
||||||
padArrayName = p.getPadArrayName,
|
|
||||||
firrtlBBName = p.firrtlBBName,
|
|
||||||
portWidth = p.portWidth)
|
|
||||||
}
|
|
||||||
|
|
||||||
def convertToUsedPad(p: TopSupplyPad): UsedPadInfo = {
|
|
||||||
UsedPadInfo(
|
|
||||||
padInline = p.createPadInline,
|
|
||||||
padName = p.getPadName,
|
|
||||||
padType = p.padType,
|
|
||||||
// Supply pads don't require bit extraction / cat so don't care
|
|
||||||
padArrayName = p.getPadName,
|
|
||||||
firrtlBBName = p.getPadName,
|
|
||||||
portWidth = 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
def checkLegalPadName(namespace: Namespace, usedPads: Seq[UsedPadInfo]): Unit = {
|
|
||||||
usedPads foreach { x =>
|
|
||||||
if (namespace contains x.padName)
|
|
||||||
throw new Exception(s"Pad name ${x.padName} already used!")
|
|
||||||
if (namespace contains x.padArrayName)
|
|
||||||
throw new Exception(s"Pad array ${x.padArrayName} name already used!")
|
|
||||||
if (namespace contains x.firrtlBBName)
|
|
||||||
throw new Exception(s"Firrtl black box ${x.firrtlBBName} name already used!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def apply(
|
|
||||||
c: Circuit,
|
|
||||||
ioPads: Seq[PortIOPad],
|
|
||||||
supplyPads: Seq[TopSupplyPad]): (Circuit, Seq[Annotation]) = {
|
|
||||||
|
|
||||||
// Add black boxes for both supply + (used) io pads
|
|
||||||
val usedPads = ioPads.filter(x => x.pad.nonEmpty).map(convertToUsedPad(_)) ++ supplyPads.map(convertToUsedPad(_))
|
|
||||||
checkLegalPadName(Namespace(c), usedPads)
|
|
||||||
|
|
||||||
// Note that we need to check for Firrtl name uniqueness here! (due to parameterization)
|
|
||||||
val uniqueExtMods = scala.collection.mutable.ArrayBuffer[UsedPadInfo]()
|
|
||||||
usedPads foreach { x =>
|
|
||||||
if (uniqueExtMods.find(_.firrtlBBName == x.firrtlBBName).isEmpty)
|
|
||||||
uniqueExtMods += x
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collecting unique parameterized black boxes
|
|
||||||
// (for io, they're wrapped pads; for supply, they're pad modules directly)
|
|
||||||
val uniqueParameterizedBBs = scala.collection.mutable.ArrayBuffer[UsedPadInfo]()
|
|
||||||
uniqueExtMods foreach { x =>
|
|
||||||
if (uniqueParameterizedBBs.find(_.padArrayName == x.padArrayName).isEmpty)
|
|
||||||
uniqueParameterizedBBs += x
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: Firrtl is silly and doesn't implement true parameterization -- each module with
|
|
||||||
// parameterization that potentially affects # of IO needs to be uniquely identified
|
|
||||||
// (but only in Firrtl)
|
|
||||||
val bbs = uniqueExtMods.map(x => {
|
|
||||||
// Supply pads don't have ports
|
|
||||||
val ports = x.padType match {
|
|
||||||
case AnalogPad => Seq(Port(NoInfo, AnalogPad.ioName, Input, AnalogType(IntWidth(x.portWidth))))
|
|
||||||
case DigitalPad => Seq(
|
|
||||||
Port(NoInfo, DigitalPad.inName, Input, UIntType(IntWidth(x.portWidth))),
|
|
||||||
Port(NoInfo, DigitalPad.outName, Output, UIntType(IntWidth(x.portWidth)))
|
|
||||||
)
|
|
||||||
case SupplyPad => Seq.empty
|
|
||||||
case _ => throw new Exception("Port pad type invalid!")
|
|
||||||
}
|
|
||||||
// Supply black boxes are not parameterized
|
|
||||||
val params = x.padType match {
|
|
||||||
case AnalogPad | DigitalPad => Seq(IntParam(ioPads.head.widthParamName, x.portWidth))
|
|
||||||
case SupplyPad => Seq()
|
|
||||||
case _ => throw new Exception("Port pad type invalid!")
|
|
||||||
}
|
|
||||||
// Firrtl name is unique
|
|
||||||
ExtModule(NoInfo, x.firrtlBBName, ports, x.padArrayName, params)
|
|
||||||
} ).toSeq
|
|
||||||
|
|
||||||
// Add annotations to black boxes to inline Verilog from template
|
|
||||||
// Again, note the weirdness in parameterization -- just need to hook to one matching Firrtl instance
|
|
||||||
val annos = uniqueParameterizedBBs.map(x =>
|
|
||||||
BlackBoxInlineAnno(ModuleName(x.firrtlBBName, CircuitName(c.main)), x.firrtlBBName, x.padInline)
|
|
||||||
).toSeq
|
|
||||||
(c.copy(modules = c.modules ++ bbs), annos)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
// See LICENSE for license details.
|
|
||||||
|
|
||||||
package barstools.tapeout.transforms.pads
|
|
||||||
|
|
||||||
import firrtl.annotations._
|
|
||||||
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)
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
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 {
|
|
||||||
def serialize: String = PadAnnotationsYaml.serialize(this)
|
|
||||||
def getPadSide: PadSide = HasPadAnnotation.getSide(padSide)
|
|
||||||
}
|
|
||||||
|
|
||||||
case class NoIOPadAnnotation(noPad: String = "") extends IOAnnotation {
|
|
||||||
def serialize: String = PadAnnotationsYaml.serialize(this)
|
|
||||||
def field: String = "noPad:"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Firrtl version
|
|
||||||
case class TargetIOPadAnnoF(target: ComponentName, anno: IOAnnotation)
|
|
||||||
extends FirrtlPadTransformAnnotation with SingleTargetAnnotation[ComponentName] {
|
|
||||||
|
|
||||||
def duplicate(n: ComponentName): TargetIOPadAnnoF = this.copy(target = n)
|
|
||||||
def targetName: String = target.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
|
|
||||||
def serialize: String = PadAnnotationsYaml.serialize(this)
|
|
||||||
def supplyPadNames: Seq[String] = 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 with SingleTargetAnnotation[ModuleName] {
|
|
||||||
|
|
||||||
def duplicate(n: ModuleName): TargetModulePadAnnoF = this.copy(target = n)
|
|
||||||
def targetName: String = target.name
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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 {
|
|
||||||
|
|
||||||
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!")
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: PORT-1.4: Remove commented code
|
|
||||||
// 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.flatMap {
|
|
||||||
case a: TargetModulePadAnnoF => Some(a)
|
|
||||||
case a: TargetIOPadAnnoF => Some(a)
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
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]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package barstools.tapeout.transforms.pads
|
|
||||||
|
|
||||||
import firrtl._
|
|
||||||
import firrtl.ir._
|
|
||||||
|
|
||||||
abstract class PadOrientation extends FirrtlNode
|
|
||||||
case object Horizontal extends PadOrientation {
|
|
||||||
def serialize: String = "horizontal"
|
|
||||||
}
|
|
||||||
case object Vertical extends PadOrientation {
|
|
||||||
def serialize: String = "vertical"
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class PadType extends FirrtlNode
|
|
||||||
case object DigitalPad extends PadType {
|
|
||||||
def serialize: String = "digital"
|
|
||||||
def inName: String = "in"
|
|
||||||
def outName: String = "out"
|
|
||||||
}
|
|
||||||
case object AnalogPad extends PadType {
|
|
||||||
def serialize: String = "analog"
|
|
||||||
def ioName: String = "io"
|
|
||||||
}
|
|
||||||
case object SupplyPad extends PadType {
|
|
||||||
def serialize: String = "supply"
|
|
||||||
}
|
|
||||||
case object NoPad extends PadType {
|
|
||||||
def serialize: String = "none"
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class PadSide extends FirrtlNode {
|
|
||||||
def orientation: PadOrientation
|
|
||||||
}
|
|
||||||
case object Left extends PadSide {
|
|
||||||
def serialize: String = "left"
|
|
||||||
def orientation: PadOrientation = Horizontal
|
|
||||||
}
|
|
||||||
case object Right extends PadSide {
|
|
||||||
def serialize: String = "right"
|
|
||||||
def orientation: PadOrientation = Horizontal
|
|
||||||
}
|
|
||||||
case object Top extends PadSide {
|
|
||||||
def serialize: String = "top"
|
|
||||||
def orientation: PadOrientation = Vertical
|
|
||||||
}
|
|
||||||
case object Bottom extends PadSide {
|
|
||||||
def serialize: String = "bottom"
|
|
||||||
def orientation: PadOrientation = Vertical
|
|
||||||
}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
// See LICENSE for license details.
|
|
||||||
|
|
||||||
package barstools.tapeout.transforms.pads
|
|
||||||
|
|
||||||
import barstools.tapeout.transforms._
|
|
||||||
import net.jcazevedo.moultingyaml._
|
|
||||||
|
|
||||||
/** This is a hack to get around weird problem with yaml parser
|
|
||||||
* that without this gives PadPlacement defines additional fields
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
trait HasPadPlacementFields {
|
|
||||||
def file: String
|
|
||||||
def left: String
|
|
||||||
def top: String
|
|
||||||
def right: String
|
|
||||||
def bottom: String
|
|
||||||
def instanceArray: String
|
|
||||||
def padLine: String
|
|
||||||
def template: String
|
|
||||||
}
|
|
||||||
|
|
||||||
case class PadPlacementFields(
|
|
||||||
file: String,
|
|
||||||
left: String,
|
|
||||||
top: String,
|
|
||||||
right: String,
|
|
||||||
bottom: String,
|
|
||||||
instanceArray: String,
|
|
||||||
padLine: String,
|
|
||||||
template: String
|
|
||||||
) extends HasPadPlacementFields
|
|
||||||
|
|
||||||
case class PadPlacement(
|
|
||||||
file: String,
|
|
||||||
left: String,
|
|
||||||
top: String,
|
|
||||||
right: String,
|
|
||||||
bottom: String,
|
|
||||||
instanceArray: String,
|
|
||||||
padLine: String,
|
|
||||||
template: String
|
|
||||||
) extends HasPadPlacementFields {
|
|
||||||
|
|
||||||
require(instanceArray contains "{{signal}}", "Instance Array Template should contain {{signal}}")
|
|
||||||
require(instanceArray contains "{{idx}}", "Instance Array Template should contain {{idx}}")
|
|
||||||
require(padLine contains "{{padInst}}", "Pad line should contain {{padInst}}")
|
|
||||||
require(padLine contains "{{side}}", "Pad line should contain {{side}} (Can be in comments)")
|
|
||||||
require(padLine contains "{{padIdx}}", "Pad line should contain {{padIdx}} (Can be in comments)")
|
|
||||||
require(template contains "{{leftPads}}", "Pad line should contain {{leftPads}}")
|
|
||||||
require(template contains "{{rightPads}}", "Pad line should contain {{rightPads}}")
|
|
||||||
require(template contains "{{topPads}}", "Pad line should contain {{topPads}}")
|
|
||||||
require(template contains "{{bottomPads}}", "Pad line should contain {{bottomPads}}")
|
|
||||||
|
|
||||||
def getSideString(s: PadSide): String = s match {
|
|
||||||
case Left => left
|
|
||||||
case Right => right
|
|
||||||
case Top => top
|
|
||||||
case Bottom => bottom
|
|
||||||
}
|
|
||||||
|
|
||||||
import com.gilt.handlebars.scala.Handlebars
|
|
||||||
import com.gilt.handlebars.scala.binding.dynamic._
|
|
||||||
|
|
||||||
private val instanceArrayTemplate = Handlebars(instanceArray.stripMargin)
|
|
||||||
private val padLineTemplate = Handlebars(padLine.stripMargin)
|
|
||||||
private val padPlacementTemplate = Handlebars(template.stripMargin)
|
|
||||||
|
|
||||||
def getInstanceArray(p: InstanceArrayParams): String = instanceArrayTemplate(p).stripMargin
|
|
||||||
def getPadLine(p: PadLineParams): String = padLineTemplate(p).stripMargin.replace(""", "\"")
|
|
||||||
def getPadPlacement(p: PadPlacementParams): String = padPlacementTemplate(p).stripMargin.replace(""", "\"")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case class InstanceArrayParams(signal: String, idx: Int)
|
|
||||||
case class PadLineParams(padInst: String, side: String, padIdx: Int)
|
|
||||||
case class PadPlacementParams(leftPads: String, rightPads: String, topPads: String, bottomPads: String)
|
|
||||||
|
|
||||||
object PadPlacementFile extends DefaultYamlProtocol {
|
|
||||||
val exampleResource = "/PadPlacement.yaml"
|
|
||||||
implicit val _pad = yamlFormat8(PadPlacementFields)
|
|
||||||
|
|
||||||
def main(args: Array[String]): Unit = {
|
|
||||||
println(parse("RealTech/PadPlacement.yaml"))
|
|
||||||
}
|
|
||||||
|
|
||||||
def parse(file: String = ""): PadPlacement = {
|
|
||||||
val fields = (new YamlFileReader(exampleResource)).parse[PadPlacementFields](file).head
|
|
||||||
PadPlacement(
|
|
||||||
file = fields.file,
|
|
||||||
left = fields.left,
|
|
||||||
top = fields.top,
|
|
||||||
right = fields.right,
|
|
||||||
bottom = fields.bottom,
|
|
||||||
instanceArray = fields.instanceArray,
|
|
||||||
padLine = fields.padLine,
|
|
||||||
template = fields.template
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def generate(
|
|
||||||
techDir: String,
|
|
||||||
targetDir: String,
|
|
||||||
padFrameName: String,
|
|
||||||
portPads: Seq[PortIOPad],
|
|
||||||
supplyPads: Seq[TopSupplyPad]): Unit = {
|
|
||||||
|
|
||||||
val file = techDir + exampleResource
|
|
||||||
if(techDir != "" && !(new java.io.File(file)).exists())
|
|
||||||
throw new Exception("Technology directory must contain PadPlacement.yaml!")
|
|
||||||
val template = parse(if (techDir == "") "" else file)
|
|
||||||
|
|
||||||
val leftPads = scala.collection.mutable.ArrayBuffer[String]()
|
|
||||||
val rightPads = scala.collection.mutable.ArrayBuffer[String]()
|
|
||||||
val topPads = scala.collection.mutable.ArrayBuffer[String]()
|
|
||||||
val bottomPads = scala.collection.mutable.ArrayBuffer[String]()
|
|
||||||
|
|
||||||
def sort(side: PadSide, inst: String): Unit = side match {
|
|
||||||
case Left => leftPads += inst
|
|
||||||
case Right => rightPads += inst
|
|
||||||
case Top => topPads += inst
|
|
||||||
case Bottom => bottomPads += inst
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Be smarter about supply placement (+ grouping?) between signals
|
|
||||||
// Supply pad instance name: padFrameName/firrtlBBName_padSide_#num/PAD[#supplySetNum]
|
|
||||||
supplyPads foreach { p =>
|
|
||||||
val prefixes = p.arrayInstNamePrefix(padFrameName)
|
|
||||||
prefixes foreach { prefix =>
|
|
||||||
(0 until p.supplySetNum) foreach { idx =>
|
|
||||||
sort(p.padSide, template.getInstanceArray(InstanceArrayParams(prefix, idx)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// IO pad instance name: padFrameName/firrtlBBName/getPadName[#portWidth]/PAD
|
|
||||||
portPads.filter(_.pad.nonEmpty) foreach { p =>
|
|
||||||
val prefix = p.arrayInstNamePrefix(padFrameName)
|
|
||||||
(0 until p.portWidth).map(idx =>
|
|
||||||
template.getInstanceArray(InstanceArrayParams(prefix, idx)) + p.arrayInstNameSuffix
|
|
||||||
) foreach { x => sort(p.padSide, x) }
|
|
||||||
}
|
|
||||||
|
|
||||||
def getLines(pads: Seq[String], side: PadSide): String = {
|
|
||||||
val seq = pads.zipWithIndex.map{ case (p, idx) =>
|
|
||||||
template.getPadLine(PadLineParams(p, template.getSideString(side), idx)) }
|
|
||||||
seq.mkString("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
val fileContents = template.getPadPlacement(PadPlacementParams(
|
|
||||||
leftPads = getLines(leftPads.toSeq, Left),
|
|
||||||
rightPads = getLines(rightPads.toSeq, Right),
|
|
||||||
topPads = getLines(topPads.toSeq, Top),
|
|
||||||
bottomPads = getLines(bottomPads.toSeq, Bottom)
|
|
||||||
))
|
|
||||||
|
|
||||||
WriteConfig(targetDir, template.file, fileContents)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,236 +0,0 @@
|
|||||||
(globals
|
|
||||||
version = 3
|
|
||||||
io_order = default
|
|
||||||
)
|
|
||||||
(iopad
|
|
||||||
(bottomleft
|
|
||||||
(inst name="corner_ll" cell="CORNER_EXAMPLE" )
|
|
||||||
)
|
|
||||||
(bottomright
|
|
||||||
(inst name="corner_lr" orientation=MY cell="CORNER_EXAMPLE" )
|
|
||||||
)
|
|
||||||
(topleft
|
|
||||||
(inst name="corner_ul" orientation=MX cell="CORNER_EXAMPLE" )
|
|
||||||
)
|
|
||||||
(topright
|
|
||||||
(inst name="corner_ur" cell="CORNER_EXAMPLE" )
|
|
||||||
)
|
|
||||||
(left
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vdd_horizontal_left_0/PAD[0]") # Side: 1, Order: 0
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vdd_horizontal_left_1/PAD[0]") # Side: 1, Order: 1
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vdd_horizontal_left_2/PAD[0]") # Side: 1, Order: 2
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[0]/PAD") # Side: 1, Order: 3
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[1]/PAD") # Side: 1, Order: 4
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[2]/PAD") # Side: 1, Order: 5
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[3]/PAD") # Side: 1, Order: 6
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[4]/PAD") # Side: 1, Order: 7
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[5]/PAD") # Side: 1, Order: 8
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[6]/PAD") # Side: 1, Order: 9
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[7]/PAD") # Side: 1, Order: 10
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[8]/PAD") # Side: 1, Order: 11
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[9]/PAD") # Side: 1, Order: 12
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[10]/PAD") # Side: 1, Order: 13
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[11]/PAD") # Side: 1, Order: 14
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[12]/PAD") # Side: 1, Order: 15
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[13]/PAD") # Side: 1, Order: 16
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_a/pad_digital_from_tristate_foundry_horizontal_input[14]/PAD") # Side: 1, Order: 17
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[0]/PAD") # Side: 1, Order: 18
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[1]/PAD") # Side: 1, Order: 19
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[2]/PAD") # Side: 1, Order: 20
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[3]/PAD") # Side: 1, Order: 21
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[4]/PAD") # Side: 1, Order: 22
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[5]/PAD") # Side: 1, Order: 23
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[6]/PAD") # Side: 1, Order: 24
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[7]/PAD") # Side: 1, Order: 25
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[8]/PAD") # Side: 1, Order: 26
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[9]/PAD") # Side: 1, Order: 27
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[10]/PAD") # Side: 1, Order: 28
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[11]/PAD") # Side: 1, Order: 29
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[12]/PAD") # Side: 1, Order: 30
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[13]/PAD") # Side: 1, Order: 31
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_b/pad_digital_from_tristate_foundry_horizontal_input[14]/PAD") # Side: 1, Order: 32
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[0]/PAD") # Side: 1, Order: 33
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[1]/PAD") # Side: 1, Order: 34
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[2]/PAD") # Side: 1, Order: 35
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[3]/PAD") # Side: 1, Order: 36
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[4]/PAD") # Side: 1, Order: 37
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[5]/PAD") # Side: 1, Order: 38
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[6]/PAD") # Side: 1, Order: 39
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[7]/PAD") # Side: 1, Order: 40
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[8]/PAD") # Side: 1, Order: 41
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[9]/PAD") # Side: 1, Order: 42
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[10]/PAD") # Side: 1, Order: 43
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[11]/PAD") # Side: 1, Order: 44
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[12]/PAD") # Side: 1, Order: 45
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_input_array_io_c/pad_digital_from_tristate_foundry_horizontal_input[13]/PAD") # Side: 1, Order: 46
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[0]/PAD") # Side: 1, Order: 47
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[1]/PAD") # Side: 1, Order: 48
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[2]/PAD") # Side: 1, Order: 49
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[3]/PAD") # Side: 1, Order: 50
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[4]/PAD") # Side: 1, Order: 51
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[5]/PAD") # Side: 1, Order: 52
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[6]/PAD") # Side: 1, Order: 53
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[7]/PAD") # Side: 1, Order: 54
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[8]/PAD") # Side: 1, Order: 55
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[9]/PAD") # Side: 1, Order: 56
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[10]/PAD") # Side: 1, Order: 57
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[11]/PAD") # Side: 1, Order: 58
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[12]/PAD") # Side: 1, Order: 59
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[13]/PAD") # Side: 1, Order: 60
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[14]/PAD") # Side: 1, Order: 61
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_x/pad_digital_from_tristate_foundry_horizontal_output[15]/PAD") # Side: 1, Order: 62
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_analog_fast_custom_horizontal_array_io_analog1/pad_analog_fast_custom_horizontal[0]/PAD") # Side: 1, Order: 63
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_analog_fast_custom_horizontal_array_io_analog1/pad_analog_fast_custom_horizontal[1]/PAD") # Side: 1, Order: 64
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_analog_fast_custom_horizontal_array_io_analog1/pad_analog_fast_custom_horizontal[2]/PAD") # Side: 1, Order: 65
|
|
||||||
|
|
||||||
)
|
|
||||||
(right
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vss_horizontal_right_0/PAD[0]") # Side: 3, Order: 0
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vss_horizontal_right_0/PAD[1]") # Side: 3, Order: 1
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_0/pad_digital_from_tristate_foundry_horizontal_output[0]/PAD") # Side: 3, Order: 2
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_0/pad_digital_from_tristate_foundry_horizontal_output[1]/PAD") # Side: 3, Order: 3
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_0/pad_digital_from_tristate_foundry_horizontal_output[2]/PAD") # Side: 3, Order: 4
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_0/pad_digital_from_tristate_foundry_horizontal_output[3]/PAD") # Side: 3, Order: 5
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_0/pad_digital_from_tristate_foundry_horizontal_output[4]/PAD") # Side: 3, Order: 6
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_1/pad_digital_from_tristate_foundry_horizontal_output[0]/PAD") # Side: 3, Order: 7
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_1/pad_digital_from_tristate_foundry_horizontal_output[1]/PAD") # Side: 3, Order: 8
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_1/pad_digital_from_tristate_foundry_horizontal_output[2]/PAD") # Side: 3, Order: 9
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_1/pad_digital_from_tristate_foundry_horizontal_output[3]/PAD") # Side: 3, Order: 10
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_1/pad_digital_from_tristate_foundry_horizontal_output[4]/PAD") # Side: 3, Order: 11
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_2/pad_digital_from_tristate_foundry_horizontal_output[0]/PAD") # Side: 3, Order: 12
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_2/pad_digital_from_tristate_foundry_horizontal_output[1]/PAD") # Side: 3, Order: 13
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_2/pad_digital_from_tristate_foundry_horizontal_output[2]/PAD") # Side: 3, Order: 14
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_2/pad_digital_from_tristate_foundry_horizontal_output[3]/PAD") # Side: 3, Order: 15
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_horizontal_output_array_io_v_2/pad_digital_from_tristate_foundry_horizontal_output[4]/PAD") # Side: 3, Order: 16
|
|
||||||
|
|
||||||
)
|
|
||||||
(top
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_input_array_reset/pad_digital_from_tristate_foundry_vertical_input[0]/PAD") # Side: 2, Order: 0
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[0]/PAD") # Side: 2, Order: 1
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[1]/PAD") # Side: 2, Order: 2
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[2]/PAD") # Side: 2, Order: 3
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[3]/PAD") # Side: 2, Order: 4
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[4]/PAD") # Side: 2, Order: 5
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[5]/PAD") # Side: 2, Order: 6
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[6]/PAD") # Side: 2, Order: 7
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[7]/PAD") # Side: 2, Order: 8
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[8]/PAD") # Side: 2, Order: 9
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[9]/PAD") # Side: 2, Order: 10
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[10]/PAD") # Side: 2, Order: 11
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[11]/PAD") # Side: 2, Order: 12
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[12]/PAD") # Side: 2, Order: 13
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[13]/PAD") # Side: 2, Order: 14
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[14]/PAD") # Side: 2, Order: 15
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_digital_from_tristate_foundry_vertical_output_array_io_z/pad_digital_from_tristate_foundry_vertical_output[15]/PAD") # Side: 2, Order: 16
|
|
||||||
|
|
||||||
)
|
|
||||||
(bottom
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vdd_vertical_bottom_0/PAD[0]") # Side: 4, Order: 0
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_supply_vdd_vertical_bottom_1/PAD[0]") # Side: 4, Order: 1
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_analog_slow_foundry_vertical_array_io_analog2/pad_analog_slow_foundry_vertical[0]/PAD") # Side: 4, Order: 2
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_analog_slow_foundry_vertical_array_io_analog2/pad_analog_slow_foundry_vertical[1]/PAD") # Side: 4, Order: 3
|
|
||||||
|
|
||||||
(inst name = "ExampleTopModuleWithBB_PadFrame/pad_analog_slow_foundry_vertical_array_io_analog2/pad_analog_slow_foundry_vertical[2]/PAD") # Side: 4, Order: 4
|
|
||||||
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,268 +0,0 @@
|
|||||||
// See LICENSE for license details.
|
|
||||||
|
|
||||||
package barstools.tapeout.transforms.pads
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
import barstools.tapeout.transforms.HasSetTechnologyLocation
|
|
||||||
import chisel3._
|
|
||||||
import chisel3.experimental._
|
|
||||||
import chisel3.iotesters._
|
|
||||||
import chisel3.stage.ChiselStage
|
|
||||||
import chisel3.util.HasBlackBoxInline
|
|
||||||
import firrtl._
|
|
||||||
import org.scalatest.{FlatSpec, Matchers}
|
|
||||||
|
|
||||||
class BB extends BlackBox with HasBlackBoxInline {
|
|
||||||
val io = IO(new Bundle {
|
|
||||||
val c = Input(SInt(14.W))
|
|
||||||
val z = Output(SInt(16.W))
|
|
||||||
val analog1 = Analog(3.W)
|
|
||||||
val analog2 = Analog(3.W)
|
|
||||||
})
|
|
||||||
// Generates a "FakeBB.v" file with the following Verilog module
|
|
||||||
setInline(
|
|
||||||
"FakeBB.v",
|
|
||||||
s"""
|
|
||||||
|module BB(
|
|
||||||
| input [15:0] c,
|
|
||||||
| output [15:0] z,
|
|
||||||
| inout [2:0] analog1,
|
|
||||||
| inout [2:0] analog2
|
|
||||||
|);
|
|
||||||
| always @* begin
|
|
||||||
| z = 2 * c;
|
|
||||||
| analog2 = analog1 + 1;
|
|
||||||
| end
|
|
||||||
|endmodule
|
|
||||||
""".stripMargin
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// You can designate the number of different supply pads on each chip side
|
|
||||||
class ExampleTopModuleWithBB
|
|
||||||
extends TopModule(
|
|
||||||
supplyAnnos = Seq(
|
|
||||||
SupplyAnnotation(padName = "vdd", leftSide = 3, bottomSide = 2),
|
|
||||||
SupplyAnnotation(padName = "vss", rightSide = 1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
with HasSetTechnologyLocation {
|
|
||||||
val io = IO(new Bundle {
|
|
||||||
val a = Input(UInt(15.W))
|
|
||||||
val b = Input(a.cloneType)
|
|
||||||
val c = Input(SInt(14.W))
|
|
||||||
val x = Output(UInt(16.W))
|
|
||||||
val y = Output(x.cloneType)
|
|
||||||
val z = Output(SInt(16.W))
|
|
||||||
val analog1 = Analog(3.W)
|
|
||||||
val analog2 = analog1.cloneType
|
|
||||||
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)
|
|
||||||
annotatePad(io.v, Right, "from_tristate_foundry")
|
|
||||||
// Can annotate individual elements
|
|
||||||
annotatePad(io.analog1, Left, "fast_custom")
|
|
||||||
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
|
|
||||||
Seq(io.a, io.b, io.c, io.x).foreach { x => annotatePad(x, Left) }
|
|
||||||
// Some signals might not want pads associated with them
|
|
||||||
noPad(io.y)
|
|
||||||
// Clk might come directly from bump
|
|
||||||
noPad(clock)
|
|
||||||
|
|
||||||
val bb = Module(new BB())
|
|
||||||
bb.io.c := io.c
|
|
||||||
io.z := bb.io.z
|
|
||||||
bb.io.analog1 <> io.analog1
|
|
||||||
bb.io.analog2 <> io.analog2
|
|
||||||
|
|
||||||
io.x := io.a + 1.U
|
|
||||||
io.y := io.b - 1.U
|
|
||||||
|
|
||||||
io.v.foreach { lhs => lhs := io.a }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class SimpleTopModuleTester(c: ExampleTopModuleWithBB) extends PeekPokeTester(c) {
|
|
||||||
val ax = Seq(5, 3)
|
|
||||||
val bx = Seq(8, 2)
|
|
||||||
val cx = Seq(-11, -9)
|
|
||||||
for (i <- 0 until ax.length) {
|
|
||||||
poke(c.io.a, ax(i))
|
|
||||||
poke(c.io.b, bx(i))
|
|
||||||
poke(c.io.c, cx(i))
|
|
||||||
expect(c.io.x, ax(i) + 1)
|
|
||||||
expect(c.io.y, bx(i) - 1)
|
|
||||||
expect(c.io.z, 2 * cx(i))
|
|
||||||
c.io.v.foreach { out => expect(out, ax(i)) }
|
|
||||||
}
|
|
||||||
// Analog can't be peeked + poked
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notes: Annotations
|
|
||||||
// a in 15: left, default digital
|
|
||||||
// b in 15: left, default digital
|
|
||||||
// c in 14: left, default digital ; signed
|
|
||||||
// x out 16: left, default digital
|
|
||||||
// y out: NOPAD
|
|
||||||
// clk in: NOPAD
|
|
||||||
// analog1 3: left, fast_custom
|
|
||||||
// analog2 3: bottom, slow_foundry
|
|
||||||
// v (vec of 3 with 5, out): right, from_tristate_foundry
|
|
||||||
// reset in: UNSPECIFIED: top, default digital
|
|
||||||
// z out 16: UNSPECIFIED: top, default digital ; signed
|
|
||||||
// vdd, left: 3, group of 1
|
|
||||||
// vdd, bottom: 2, group of 1
|
|
||||||
// vss, right: 1, group of 2
|
|
||||||
// Notes: Used pads
|
|
||||||
// digital horizontal (from_tristate_foundry)
|
|
||||||
// in + out
|
|
||||||
// analog fast_custom horizontal
|
|
||||||
// analog slow_foundry vertical
|
|
||||||
// digital vertical (from_tristate_foundry)
|
|
||||||
// in + out
|
|
||||||
// vdd horizontal
|
|
||||||
// vdd vertical
|
|
||||||
// vss horizontal
|
|
||||||
|
|
||||||
class IOPadSpec extends FlatSpec with Matchers {
|
|
||||||
|
|
||||||
def readOutputFile(dir: String, f: String): String = {
|
|
||||||
FileUtils.getText(dir + File.separator + f)
|
|
||||||
}
|
|
||||||
def readResource(resource: String): String = {
|
|
||||||
val stream = getClass.getResourceAsStream(resource)
|
|
||||||
scala.io.Source.fromInputStream(stream).mkString
|
|
||||||
}
|
|
||||||
|
|
||||||
def checkOutputs(dir: String): Unit = {
|
|
||||||
// Show that black box source helper is run
|
|
||||||
//readOutputFile(dir, "black_box_verilog_files.f") should include ("pad_supply_vdd_horizontal.v")
|
|
||||||
|
|
||||||
val padBBEx = s"""// Digital Pad Example
|
|
||||||
|// Signal Direction: Input
|
|
||||||
|// Pad Orientation: Horizontal
|
|
||||||
|// Call your instance PAD
|
|
||||||
|module pad_digital_from_tristate_foundry_horizontal_input(
|
|
||||||
| input in,
|
|
||||||
| output reg out
|
|
||||||
|);
|
|
||||||
| // Where you would normally dump your pad instance
|
|
||||||
| always @* begin
|
|
||||||
| out = in;
|
|
||||||
| end
|
|
||||||
|endmodule
|
|
||||||
|
|
|
||||||
|module pad_digital_from_tristate_foundry_horizontal_input_array #(
|
|
||||||
| parameter int WIDTH=1
|
|
||||||
|)(
|
|
||||||
| input [WIDTH-1:0] in,
|
|
||||||
| output reg [WIDTH-1:0] out
|
|
||||||
|);
|
|
||||||
| pad_digital_from_tristate_foundry_horizontal_input pad_digital_from_tristate_foundry_horizontal_input[WIDTH-1:0](
|
|
||||||
| .in(in),
|
|
||||||
| .out(out)
|
|
||||||
| );""".stripMargin
|
|
||||||
// Make sure black box templating is OK
|
|
||||||
readOutputFile(dir, "pad_digital_from_tristate_foundry_horizontal_input_array.v") should include(padBBEx)
|
|
||||||
|
|
||||||
val verilog = readOutputFile(dir, "ExampleTopModuleWithBB.v")
|
|
||||||
// Pad frame + top should be exact
|
|
||||||
verilog should include(readResource("/PadAnnotationVerilogPart.v"))
|
|
||||||
// Pad Placement IO file should be exact
|
|
||||||
val padIO = readOutputFile(dir, "pads.io")
|
|
||||||
padIO should include(readResource("/PadPlacement.io"))
|
|
||||||
}
|
|
||||||
|
|
||||||
behavior.of("Pad Annotations")
|
|
||||||
|
|
||||||
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 {
|
|
||||||
val optionsManager = new TesterOptionsManager {
|
|
||||||
firrtlOptions = firrtlOptions.copy(
|
|
||||||
compilerName = "verilog"
|
|
||||||
)
|
|
||||||
testerOptions = testerOptions.copy(isVerbose = true, backendName = "verilator", displayBase = 10)
|
|
||||||
commonOptions = commonOptions.copy(targetDirName = "test_run_dir/PadsTB")
|
|
||||||
}
|
|
||||||
iotesters.Driver.execute(() => new ExampleTopModuleWithBB, optionsManager) { c =>
|
|
||||||
val dir = optionsManager.commonOptions.targetDirName
|
|
||||||
checkOutputs(dir)
|
|
||||||
new SimpleTopModuleTester(c)
|
|
||||||
} should be(true)
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
it should "create proper IO pads + black box in low firrtl" in {
|
|
||||||
val optionsManager = new ExecutionOptionsManager("barstools") with HasChiselExecutionOptions with HasFirrtlOptions {
|
|
||||||
firrtlOptions = firrtlOptions.copy(compilerName = "low")
|
|
||||||
commonOptions = commonOptions.copy(targetDirName = "test_run_dir/LoFirrtl")
|
|
||||||
//commonOptions = commonOptions.copy(globalLogLevel = logger.LogLevel.Info)
|
|
||||||
}
|
|
||||||
val success = chisel3.Driver.execute(optionsManager, () => new ExampleTopModuleWithBB) match {
|
|
||||||
case ChiselExecutionSuccess(_, chirrtl, Some(FirrtlExecutionSuccess(_, firrtl))) =>
|
|
||||||
firrtl should include ("ExampleTopModuleWithBB_PadFrame")
|
|
||||||
firrtl should include ("ExampleTopModuleWithBB_Internal")
|
|
||||||
firrtl should not include ("FakeBBPlaceholder")
|
|
||||||
true
|
|
||||||
case _ => false
|
|
||||||
}
|
|
||||||
success should be (true)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
it should "create proper IO pads + black box in verilog" in {
|
|
||||||
val dir = "test_run_dir/PadsVerilog"
|
|
||||||
(new ChiselStage).emitVerilog(
|
|
||||||
new ExampleTopModuleWithBB,
|
|
||||||
// Array("-td", dir, "-X", "verilog")
|
|
||||||
Array("-td", dir)
|
|
||||||
)
|
|
||||||
checkOutputs(dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user