📄 spiceparasitic.java
字号:
{
if (shortedExports.size() > 1)
curSegmentedNets.addShortedExports(shortedExports);
}
}
/**
* Method to emit the name of a signal on an instance call (the "X" statement).
* @param no the Nodable for the cell instance being examined.
* @param subNet the Network in the cell attached to that Nodable.
* @param subSegmentedNets the SpiceSegmentedNets object for the Nodable's Cell.
* @param infstr the string buffer in which to emit the name(s).
*/
public void getParasiticName(Nodable no, Network subNet, SpiceSegmentedNets subSegmentedNets, StringBuffer infstr)
{
// connect to all exports (except power and ground of subcell net)
List<String> exportNames = new ArrayList<String>();
for (Iterator<Export> it = subNet.getExports(); it.hasNext(); )
{
// get subcell export, unless collapsed due to less than min R
Export e = it.next();
PortInst pi = e.getOriginalPort();
String name = subSegmentedNets.getNetName(pi);
if (exportNames.contains(name)) continue;
exportNames.add(name);
// ok, there is a port on the subckt on this subcell for this export,
// now get the appropriate network in this cell
pi = no.getNodeInst().findPortInstFromProto(no.getProto().findPortProto(e.getNameKey()));
name = curSegmentedNets.getNetName(pi);
infstr.append(" " + name);
}
}
/**
* Method to find the SpiceSegmentedNets object that corresponds to a given Cell.
* @param cell the Cell to find.
* @return the SpiceSegmentedNets object associated with that cell (null if none found).
*/
public SpiceSegmentedNets getSegmentedNets(Cell cell)
{
for (SpiceSegmentedNets seg : segmentedParasiticInfo)
if (seg.getCell() == cell) return seg;
return null;
}
/**
* Method called at the end of netlist writing to deal with back-annotation.
*/
public void backAnnotate()
{
Set<Cell> cellsToClear = new HashSet<Cell>();
List<PortInst> capsOnPorts = new ArrayList<PortInst>();
List<String> valsOnPorts = new ArrayList<String>();
List<ArcInst> resOnArcs = new ArrayList<ArcInst>();
List<Double> valsOnArcs = new ArrayList<Double>();
for (SpiceSegmentedNets segmentedNets : segmentedParasiticInfo)
{
Cell cell = segmentedNets.getCell();
if (cell.getView() != View.LAYOUT) continue;
// gather cells to clear capacitor values
cellsToClear.add(cell);
// gather capacitor updates
for (SpiceSegmentedNets.NetInfo info : segmentedNets.getUniqueSegments())
{
PortInst pi = info.getPortIterator().next();
if (info.getCap() > cell.getTechnology().getMinCapacitance())
{
capsOnPorts.add(pi);
valsOnPorts.add(TextUtils.formatDouble(info.getCap(), 2) + "fF");
}
}
// gather resistor updates
for (Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); )
{
ArcInst ai = it.next();
Double res = segmentedNets.getRes(ai);
resOnArcs.add(ai);
valsOnArcs.add(res);
}
}
new BackAnnotateJob(cellsToClear, capsOnPorts, valsOnPorts, resOnArcs, valsOnArcs);
}
/**
* Class to run back-annotation in a Job.
*/
private static class BackAnnotateJob extends Job
{
private Set<Cell> cellsToClear;
private List<PortInst> capsOnPorts;
private List<String> valsOnPorts;
private List<ArcInst> resOnArcs;
private List<Double> valsOnArcs;
private BackAnnotateJob(Set<Cell> cellsToClear, List<PortInst> capsOnPorts, List<String> valsOnPorts,
List<ArcInst> resOnArcs, List<Double> valsOnArcs)
{
super("Spice Layout Back Annotate", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.capsOnPorts = capsOnPorts;
this.valsOnPorts = valsOnPorts;
this.resOnArcs = resOnArcs;
this.valsOnArcs = valsOnArcs;
this.cellsToClear = cellsToClear;
startJob();
}
public boolean doIt() throws JobException
{
TextDescriptor ctd = TextDescriptor.getPortInstTextDescriptor().withDispPart(TextDescriptor.DispPos.NAMEVALUE);
TextDescriptor rtd = TextDescriptor.getArcTextDescriptor().withDispPart(TextDescriptor.DispPos.NAMEVALUE);
int capCount = 0;
int resCount = 0;
// clear caps on layout
for(Cell cell : cellsToClear)
{
// delete all C's already on layout
for (Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
for (Iterator<PortInst> pit = ni.getPortInsts(); pit.hasNext(); )
{
PortInst pi = pit.next();
Variable var = pi.getVar(ATTR_C);
if (var != null) pi.delVar(var.getKey());
}
}
}
// add new C's
for(int i=0; i<capsOnPorts.size(); i++)
{
PortInst pi = capsOnPorts.get(i);
String str = valsOnPorts.get(i);
pi.newVar(ATTR_C, str, ctd);
resCount++;
}
// add new R's
for(int i=0; i<resOnArcs.size(); i++)
{
ArcInst ai = resOnArcs.get(i);
Double res = valsOnArcs.get(i);
// delete R if no new one
Variable var = ai.getVar(ATTR_R);
if (res == null && var != null)
ai.delVar(ATTR_R);
// change R if new one
if (res != null)
{
ai.newVar(ATTR_R, res, rtd);
resCount++;
}
}
System.out.println("Back-annotated "+resCount+" Resistors and "+capCount+" Capacitors");
return true;
}
}
/**
* Method to print the netlist considering the metal lines as distribute RC(transmission lines)
*/
public void writeNewSpiceCode(Cell cell,CellNetInfo cni,Technology layoutTechnology, Spice out)
{
double scale = layoutTechnology.getScale();
networkList = new ArrayList<Network>();
arcList = new ArrayList<ArcInst>();
for (SpiceSegmentedNets segmentedNets : segmentedParasiticInfo)
{
if (segmentedNets.getCell() != cell) continue;
for( Iterator<Network> itNet = cni.getNetList().getNetworks();itNet.hasNext();)
{
Network net = itNet.next();
Iterator<ArcInst> itArc = net.getArcs();
ArcInst FirstAi = itArc.next();
double sqrs =0;
double cap=0;
double res=0;
boolean startAgain=false;
ArcInst MainAi = FirstAi;
ArcInst CurrAi = MainAi;
// Start with the head port instance of the first arc
Iterator<Connection> ConIT = MainAi.getHeadPortInst().getConnections();
PortInst MainPI = MainAi.getHeadPortInst();
n0 = segmentedNets.getNetName(MainAi.getHeadPortInst());
// If this network is not already analyzed
if (networkList == null || !networkList.contains(net))
{
networkList.add(net);
while(ConIT.hasNext())
{
Connection conn = ConIT.next();
CurrAi = conn.getArc();
// If this arc is not already analyzed.
if (!arcList.contains(CurrAi))
{
double length = CurrAi.getLambdaLength() * scale / 1000; // length in microns
double width = CurrAi.getLambdaBaseWidth() * scale / 1000; // width in microns
Poly[] polya = layoutTechnology.getShapeOfArc(CurrAi);
Poly poly = polya[0];
if (poly.isPseudoLayer()) continue;
String curLayer = poly.getLayer().getName();
// If both the arcs are of the same layer ,add resistance,
// capacitance and no. of squares and continue traversing.
// Else print the existing data and start afresh.
if((preLayer == curLayer) || preLayer == "") {
preLayer = curLayer;
arcList.add(CurrAi);
sqrs += length / width;
res += segmentedNets.getRes(CurrAi).doubleValue();
cap += segmentedNets.getArcCap(CurrAi);
} else {
preLayer = curLayer;
arcList.add(null);
arcList.add(CurrAi);
if(sqrs > 3)
{
out.multiLinePrint(false, "XP" + tLineCount + " " + n0 + " " + n1 +" RCLINE R=" + TextUtils.formatDouble(res/sqrs, 2) + " C=" + TextUtils.formatDouble(cap/sqrs, 2) + "fF len=" + TextUtils.formatDouble(sqrs, 2) + "\n");
tLineCount++;
n0=n1;
}
sqrs = 0;
res = 0.0;
cap = 0;
sqrs += length / width;
res += segmentedNets.getRes(CurrAi).doubleValue();
cap += segmentedNets.getArcCap(CurrAi);
}
// Decide which port of the current arc to use to continue traversing the network
if (MainPI == CurrAi.getHeadPortInst()) {
MainAi = CurrAi;
MainPI = MainAi.getTailPortInst();
ConIT = MainAi.getTailPortInst().getConnections();
n1 = segmentedNets.getNetName(MainAi.getTailPortInst());
} else {
MainAi = CurrAi;
MainPI = MainAi.getHeadPortInst();
ConIT = MainAi.getHeadPortInst().getConnections();
n1 = segmentedNets.getNetName(MainAi.getHeadPortInst());
}
}
// Once, one end of the network is reached, start traversing from the
// head port instance of the first arc in the other direction now.
if (!ConIT.hasNext() && !startAgain)
{
ConIT = FirstAi.getHeadPortInst().getConnections();
MainPI = FirstAi.getHeadPortInst();
startAgain = true;
if(sqrs > 3) {
out.multiLinePrint(false, "XP" + tLineCount + " " + n0 + " " + n1 +" RCLINE R=" + TextUtils.formatDouble(res/sqrs, 2) + " C=" + TextUtils.formatDouble(cap/sqrs, 2) + "fF len=" + TextUtils.formatDouble(sqrs, 2) + "\n");
tLineCount++;
}
preLayer = "";
sqrs = 0;
res = 0.0;
cap = 0;
n0=segmentedNets.getNetName(FirstAi.getHeadPortInst());
}
}
if(sqrs > 3 && res > 0 && cap >0 ) {
out.multiLinePrint(false, "XP" + tLineCount + " " + n0 + " " + n1 +" RCLINE R=" + TextUtils.formatDouble(res/sqrs, 2) + " C=" + TextUtils.formatDouble(cap/sqrs, 2) + "fF len=" + TextUtils.formatDouble(sqrs, 2) + "\n");
tLineCount++;
}
}
}
}
// Print the subckt Spice code
if (!alreadyPrinted){
out.multiLinePrint(false, ".subckt RCLINE n1 n2 \n");
out.multiLinePrint(false, "o1 n1 0 n2 0 TRC \n");
out.multiLinePrint(false, ".model TRC ltra R={R} C={C} len={len} \n");
out.multiLinePrint(false, ".ends RCLINE \n");
alreadyPrinted = true;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -