mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into lefdef-enhancments
This commit is contained in:
commit
89745fd0de
|
|
@ -16,6 +16,7 @@ node("master") {
|
|||
stage("Checkout sources") {
|
||||
|
||||
checkout scm
|
||||
checkout_private()
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 204 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 89 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -441,14 +441,16 @@ def RunMainBuildBash():
|
|||
global DeploymentF
|
||||
global DeploymentP
|
||||
global PackagePrefix
|
||||
global MacPkgDir # relative path to package directory
|
||||
global MacBinDir # relative path to binary directory
|
||||
global MacBuildDir # relative path to build directory
|
||||
global MacBuildLog # relative path to build log file
|
||||
global AbsMacPkgDir # absolute path to package directory
|
||||
global AbsMacBinDir # absolute path to binary directory
|
||||
global AbsMacBuildDir # absolute path to build directory
|
||||
global AbsMacBuildLog # absolute path to build log file
|
||||
global MacPkgDir # relative path to package directory
|
||||
global MacBinDir # relative path to binary directory
|
||||
global MacBuildDir # relative path to build directory
|
||||
global MacBuildDirQAT # relative path to build directory for QATest
|
||||
global MacBuildLog # relative path to build log file
|
||||
global AbsMacPkgDir # absolute path to package directory
|
||||
global AbsMacBinDir # absolute path to binary directory
|
||||
global AbsMacBuildDir # absolute path to build directory
|
||||
global AbsMacBuildDirQAT # absolute path to build directory for QATest
|
||||
global AbsMacBuildLog # absolute path to build log file
|
||||
|
||||
#-----------------------------------------------------
|
||||
# [1] Set parameters passed to the main Bash script
|
||||
|
|
@ -468,14 +470,16 @@ def RunMainBuildBash():
|
|||
ruby_python = "R%sP%s" % ( ruby.lower(), python.lower() )
|
||||
|
||||
# (C) Target directories and files
|
||||
MacPkgDir = "./%s%s.pkg.macos-%s-%s-%s" % (PackagePrefix, qt, Platform, mode, ruby_python)
|
||||
MacBinDir = "./%s.bin.macos-%s-%s-%s" % ( qt, Platform, mode, ruby_python)
|
||||
MacBuildDir = "./%s.build.macos-%s-%s-%s" % ( qt, Platform, mode, ruby_python)
|
||||
MacBuildLog = "./%s.build.macos-%s-%s-%s.log" % ( qt, Platform, mode, ruby_python)
|
||||
AbsMacPkgDir = "%s/%s%s.pkg.macos-%s-%s-%s" % (ProjectDir, PackagePrefix, qt, Platform, mode, ruby_python)
|
||||
AbsMacBinDir = "%s/%s.bin.macos-%s-%s-%s" % (ProjectDir, qt, Platform, mode, ruby_python)
|
||||
AbsMacBuildDir = "%s/%s.build.macos-%s-%s-%s" % (ProjectDir, qt, Platform, mode, ruby_python)
|
||||
AbsMacBuildLog = "%s/%s.build.macos-%s-%s-%s.log" % (ProjectDir, qt, Platform, mode, ruby_python)
|
||||
MacPkgDir = "./%s%s.pkg.macos-%s-%s-%s" % (PackagePrefix, qt, Platform, mode, ruby_python)
|
||||
MacBinDir = "./%s.bin.macos-%s-%s-%s" % ( qt, Platform, mode, ruby_python)
|
||||
MacBuildDir = "./%s.build.macos-%s-%s-%s" % ( qt, Platform, mode, ruby_python)
|
||||
MacBuildLog = "./%s.build.macos-%s-%s-%s.log" % ( qt, Platform, mode, ruby_python)
|
||||
AbsMacPkgDir = "%s/%s%s.pkg.macos-%s-%s-%s" % (ProjectDir, PackagePrefix, qt, Platform, mode, ruby_python)
|
||||
AbsMacBinDir = "%s/%s.bin.macos-%s-%s-%s" % (ProjectDir, qt, Platform, mode, ruby_python)
|
||||
AbsMacBuildDir = "%s/%s.build.macos-%s-%s-%s" % (ProjectDir, qt, Platform, mode, ruby_python)
|
||||
AbsMacBuildLog = "%s/%s.build.macos-%s-%s-%s.log" % (ProjectDir, qt, Platform, mode, ruby_python)
|
||||
MacBuildDirQAT = MacBuildDir + ".macQAT"
|
||||
AbsMacBuildDirQAT = AbsMacBuildDir + ".macQAT"
|
||||
|
||||
# (D) Qt5
|
||||
if ModuleQt == 'Qt5MacPorts':
|
||||
|
|
@ -554,6 +558,45 @@ def RunMainBuildBash():
|
|||
print( "### <%s>: successfully built KLayout" % myscript, file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# [4] Prepare "*.macQAT/" directory for the QATest.
|
||||
# Binaries under "*.macQAT/" such as *.dylib will be touched later.
|
||||
#------------------------------------------------------------------------
|
||||
print( "### Preparing <%s>" % MacBuildDirQAT )
|
||||
if os.path.isdir( MacBuildDirQAT ):
|
||||
shutil.rmtree( MacBuildDirQAT )
|
||||
|
||||
os.chdir( MacBuildDir )
|
||||
tarFile = "../macQATest.tar"
|
||||
tarCmdC = "tar cf %s ." % tarFile
|
||||
if subprocess.call( tarCmdC, shell=True ) != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to create <%s>" % (myscript, tarFile), file=sys.stderr )
|
||||
print( "-------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
return 1
|
||||
|
||||
os.chdir( "../" )
|
||||
os.mkdir( MacBuildDirQAT )
|
||||
os.chdir( MacBuildDirQAT )
|
||||
tarCmdX = "tar xf %s" % tarFile
|
||||
if subprocess.call( tarCmdX, shell=True ) != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to unpack <%s>" % (myscript, tarFile), file=sys.stderr )
|
||||
print( "-------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
return 1
|
||||
|
||||
os.remove( tarFile )
|
||||
os.chdir( "../" )
|
||||
shutil.copy2( "macbuild/macQAT.sh", MacBuildDirQAT )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "### <%s>: prepared the initial *.macQAT/" % myscript, file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
return 0
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
@ -573,10 +616,12 @@ def DeployBinariesForBundle():
|
|||
global MacPkgDir
|
||||
global MacBinDir
|
||||
global MacBuildDir
|
||||
global MacBuildDirQAT
|
||||
global MacBuildLog
|
||||
global AbsMacPkgDir
|
||||
global AbsMacBinDir
|
||||
global AbsMacBuildDir
|
||||
global AbsMacBuildDirQAT
|
||||
global AbsMacBuildLog
|
||||
global Version
|
||||
global DeployVerbose
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
#!/bin/bash
|
||||
|
||||
#===============================================================================
|
||||
# File: "macbuild/macQAT.sh"
|
||||
#
|
||||
# The top Bash script to run "ut_runner" after building KLayout
|
||||
# (http://www.klayout.de/index.php) version 0.26.1 or later on different Apple
|
||||
# ßMac OSX platforms.
|
||||
#
|
||||
# This script must be copied to a "*.macQAT/" directory to run.
|
||||
#===============================================================================
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Functions
|
||||
#----------------------------------------------------------------
|
||||
function GetPresentDir() {
|
||||
path=$1
|
||||
array=( `echo $path | tr -s '/' ' '`)
|
||||
last_index=`expr ${#array[@]} - 1`
|
||||
echo ${array[${last_index}]}
|
||||
return 0
|
||||
}
|
||||
|
||||
function HidePrivateDir() {
|
||||
if [ -d "../private" ]; then
|
||||
ret=$(/bin/mv ../private ../private.stash)
|
||||
fi
|
||||
}
|
||||
|
||||
function ShowPrivateDir() {
|
||||
if [ -d "../private.stash" ]; then
|
||||
ret=$(/bin/mv ../private.stash ../private)
|
||||
fi
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Variables
|
||||
#----------------------------------------------------------------
|
||||
gitSHA1=$(git rev-parse --short HEAD 2>/dev/null)
|
||||
timestamp=$(date "+%Y_%m%d_%H%M")
|
||||
presentDir=$(GetPresentDir `pwd`)
|
||||
logfile=QATest_${gitSHA1}_${timestamp}__${presentDir}.log
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Environment variables for "ut_runner"
|
||||
#----------------------------------------------------------------
|
||||
export TESTSRC=..
|
||||
export TESTTMP=QATest_${gitSHA1}_${timestamp}__${presentDir}
|
||||
export DYLD_LIBRARY_PATH=$(pwd):$(pwd)/db_plugins
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Environment variables for "ut_runner"
|
||||
#----------------------------------------------------------------
|
||||
if [ $# -eq 1 ]; then
|
||||
if [ "$1" == "-h" ]; then
|
||||
./ut_runner -h
|
||||
exit 0
|
||||
fi
|
||||
if [ "$1" == "-r" ]; then
|
||||
echo "### Dumping the log to" $logfile "..."
|
||||
HidePrivateDir
|
||||
./ut_runner -x pymod -c 2>&1 | tee $logfile
|
||||
ShowPrivateDir
|
||||
exit 0
|
||||
else
|
||||
echo ""
|
||||
echo " Git SHA1 = ${gitSHA1}"
|
||||
echo " Time stamp = ${timestamp}"
|
||||
echo " Log file = ${logfile}"
|
||||
echo " Usage:"
|
||||
echo " ./QATest.sh -h: to get the help of 'ut_runner'"
|
||||
echo " ./QATest.sh -r: to run the tests with '-c' option: continues after an error"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
echo ""
|
||||
echo " Git SHA1 = ${gitSHA1}"
|
||||
echo " Time stamp = ${timestamp}"
|
||||
echo " Log file = ${logfile}"
|
||||
echo " Usage:"
|
||||
echo " ./QATest.sh -h: to get the help of 'ut_runner'"
|
||||
echo " ./QATest.sh -r: to run the tests with '-c' option: continues after an error"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#--------------
|
||||
# End of File
|
||||
#--------------
|
||||
|
|
@ -37,6 +37,7 @@ from build4mac_util import *
|
|||
def SetGlobals():
|
||||
global ProjectDir # project directory where "build.sh" exists
|
||||
global Usage # string on usage
|
||||
global LatestOS # the latest generic OS name
|
||||
global GenOSName # generic OS name
|
||||
global Platform # platform
|
||||
global PkgDir # the package directory where "klayout.app" exists
|
||||
|
|
@ -57,8 +58,9 @@ def SetGlobals():
|
|||
global VolumeDMG # the volume name of DMG
|
||||
global TargetDMG # the name of target DMG file
|
||||
global RootApplications # reserved directory name for applications
|
||||
global CatalinaAnaconda3 # True if 'Catalina with Anaconda3'
|
||||
global CatalinaHomebrew # True if 'Catalina with Homebrew'
|
||||
global LatestOSMacPorts # True if 'LatestOS with MacPorts'
|
||||
global LatestOSHomebrew # True if 'LatestOS with Homebrew'
|
||||
global LatestOSAnaconda3 # True if 'LatestOS with Anaconda3'
|
||||
global DicLightWeight # dictionary for LW-* packages
|
||||
global Item3AppleScript # ITEM_3 in the Apple script
|
||||
# auxiliary variables on platform
|
||||
|
|
@ -98,9 +100,11 @@ def SetGlobals():
|
|||
quit()
|
||||
|
||||
release = int( Release.split(".")[0] ) # take the first of ['19', '0', '0']
|
||||
LatestOS = ""
|
||||
if release == 19:
|
||||
GenOSName = "macOS"
|
||||
Platform = "Catalina"
|
||||
LatestOS = Platform
|
||||
elif release == 18:
|
||||
GenOSName = "macOS"
|
||||
Platform = "Mojave"
|
||||
|
|
@ -144,21 +148,30 @@ def SetGlobals():
|
|||
VolumeDMG = "KLayout"
|
||||
TargetDMG = ""
|
||||
RootApplications = "/Applications"
|
||||
CatalinaAnaconda3 = False
|
||||
CatalinaHomebrew = False
|
||||
LatestOSMacPorts = False
|
||||
LatestOSHomebrew = False
|
||||
LatestOSAnaconda3 = False
|
||||
DicLightWeight = dict()
|
||||
Item3AppleScript = ""
|
||||
# Populate DicLightWeight
|
||||
DicLightWeight[ "ana3" ] = dict()
|
||||
DicLightWeight[ "brew" ] = dict()
|
||||
DicLightWeight[ "ana3" ]["zip"] = "macbuild/Resources/script-bundle-A.zip"
|
||||
DicLightWeight[ "ana3" ]["src"] = "script-bundle-A"
|
||||
DicLightWeight[ "ana3" ]["des"] = "Anaconda3User-ReadMeFirst"
|
||||
DicLightWeight[ "ana3" ]["item3"] = 'set position of item "Anaconda3User-ReadMeFirst" to {700, 400}'
|
||||
DicLightWeight[ "brew" ]["zip"] = "macbuild/Resources/script-bundle-B.zip"
|
||||
DicLightWeight[ "brew" ]["src"] = "script-bundle-B"
|
||||
DicLightWeight[ "brew" ]["des"] = "HomebrewUser-ReadMeFirst"
|
||||
DicLightWeight[ "brew" ]["item3"] = 'set position of item "HomebrewUser-ReadMeFirst" to {700, 400}'
|
||||
DicLightWeight[ "ports" ] = dict()
|
||||
DicLightWeight[ "brew" ] = dict()
|
||||
DicLightWeight[ "ana3" ] = dict()
|
||||
|
||||
DicLightWeight[ "ports" ]["zip"] = "macbuild/Resources/script-bundle-P.zip"
|
||||
DicLightWeight[ "ports" ]["src"] = "script-bundle-P"
|
||||
DicLightWeight[ "ports" ]["des"] = "MacPortsUser-ReadMeFirst"
|
||||
DicLightWeight[ "ports" ]["item3"] = 'set position of item "MacPortsUser-ReadMeFirst" to {700, 400}'
|
||||
|
||||
DicLightWeight[ "brew" ]["zip"] = "macbuild/Resources/script-bundle-B.zip"
|
||||
DicLightWeight[ "brew" ]["src"] = "script-bundle-B"
|
||||
DicLightWeight[ "brew" ]["des"] = "HomebrewUser-ReadMeFirst"
|
||||
DicLightWeight[ "brew" ]["item3"] = 'set position of item "HomebrewUser-ReadMeFirst" to {700, 400}'
|
||||
|
||||
DicLightWeight[ "ana3" ]["zip"] = "macbuild/Resources/script-bundle-A.zip"
|
||||
DicLightWeight[ "ana3" ]["src"] = "script-bundle-A"
|
||||
DicLightWeight[ "ana3" ]["des"] = "Anaconda3User-ReadMeFirst"
|
||||
DicLightWeight[ "ana3" ]["item3"] = 'set position of item "Anaconda3User-ReadMeFirst" to {700, 400}'
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
## To check the contents of the package directory
|
||||
|
|
@ -184,8 +197,9 @@ def CheckPkgDirectory():
|
|||
global PackagePrefix
|
||||
global QtIdentification
|
||||
global RubyPythonID
|
||||
global CatalinaAnaconda3
|
||||
global CatalinaHomebrew
|
||||
global LatestOSMacPorts
|
||||
global LatestOSHomebrew
|
||||
global LatestOSAnaconda3
|
||||
global DicLightWeight
|
||||
global Item3AppleScript
|
||||
|
||||
|
|
@ -224,20 +238,25 @@ def CheckPkgDirectory():
|
|||
RubyPythonID = pkgdirComponents[5]
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# [3] Check if Catalina with Anaconda3 / Homebrew
|
||||
# [3] Check if the "LatestOS" with MacPorts / Homebrew / Anaconda3
|
||||
#-----------------------------------------------------------------------------
|
||||
CatalinaAnaconda3 = Platform == "Catalina"
|
||||
CatalinaAnaconda3 &= PackagePrefix == "LW"
|
||||
CatalinaAnaconda3 &= QtIdentification == "qt5Ana3"
|
||||
CatalinaAnaconda3 &= RubyPythonID == "Rana3Pana3"
|
||||
LatestOSMacPorts = Platform == LatestOS
|
||||
LatestOSMacPorts &= PackagePrefix == "LW"
|
||||
LatestOSMacPorts &= QtIdentification == "qt5MP"
|
||||
LatestOSMacPorts &= RubyPythonID == "Rmp26Pmp37"
|
||||
|
||||
CatalinaHomebrew = Platform == "Catalina"
|
||||
CatalinaHomebrew &= PackagePrefix == "LW"
|
||||
CatalinaHomebrew &= QtIdentification == "qt5Brew"
|
||||
CatalinaHomebrew &= RubyPythonID == "Rhb27Phb37"
|
||||
LatestOSHomebrew = Platform == LatestOS
|
||||
LatestOSHomebrew &= PackagePrefix == "LW"
|
||||
LatestOSHomebrew &= QtIdentification == "qt5Brew"
|
||||
LatestOSHomebrew &= RubyPythonID == "Rhb27Phb37"
|
||||
|
||||
if CatalinaAnaconda3:
|
||||
mydic = DicLightWeight["ana3"]
|
||||
LatestOSAnaconda3 = Platform == LatestOS
|
||||
LatestOSAnaconda3 &= PackagePrefix == "LW"
|
||||
LatestOSAnaconda3 &= QtIdentification == "qt5Ana3"
|
||||
LatestOSAnaconda3 &= RubyPythonID == "Rana3Pana3"
|
||||
|
||||
if LatestOSMacPorts:
|
||||
mydic = DicLightWeight["ports"]
|
||||
srcDir = PkgDir + "/" + mydic["src"]
|
||||
desDir = PkgDir + "/" + mydic["des"]
|
||||
if OpMake:
|
||||
|
|
@ -251,7 +270,7 @@ def CheckPkgDirectory():
|
|||
shutil.rmtree(desDir)
|
||||
Item3AppleScript = mydic["item3"]
|
||||
|
||||
if CatalinaHomebrew:
|
||||
if LatestOSHomebrew:
|
||||
mydic = DicLightWeight["brew"]
|
||||
srcDir = PkgDir + "/" + mydic["src"]
|
||||
desDir = PkgDir + "/" + mydic["des"]
|
||||
|
|
@ -266,6 +285,21 @@ def CheckPkgDirectory():
|
|||
shutil.rmtree(desDir)
|
||||
Item3AppleScript = mydic["item3"]
|
||||
|
||||
if LatestOSAnaconda3:
|
||||
mydic = DicLightWeight["ana3"]
|
||||
srcDir = PkgDir + "/" + mydic["src"]
|
||||
desDir = PkgDir + "/" + mydic["des"]
|
||||
if OpMake:
|
||||
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
|
||||
zip_ref.extractall(PkgDir)
|
||||
os.rename( srcDir, desDir )
|
||||
if OpClean:
|
||||
if os.path.isdir(srcDir):
|
||||
shutil.rmtree(srcDir)
|
||||
if os.path.isdir(desDir):
|
||||
shutil.rmtree(desDir)
|
||||
Item3AppleScript = mydic["item3"]
|
||||
|
||||
#------------------------------------------------------
|
||||
# [4] Check the presence of the default bundle
|
||||
#------------------------------------------------------
|
||||
|
|
@ -437,8 +471,8 @@ def MakeTargetDMGFile(msg=""):
|
|||
WIN_WIDTH='1000', WIN_HEIGHT='500',
|
||||
FULL_PATH_DS_STORE='/Volumes/%s/.DS_Store' % VolumeDMG,
|
||||
BACKGROUND_PNG_FILE=BackgroundPNG,
|
||||
ITEM_1='%s' % BundleName, X1='860', Y1='165',
|
||||
ITEM_2='Applications', X2='860', Y2='345',
|
||||
ITEM_1='%s' % BundleName, X1='900', Y1='165',
|
||||
ITEM_2='Applications', X2='900', Y2='345',
|
||||
ITEM_3=Item3AppleScript,
|
||||
CHECK_BASH='[ -f " & dotDSStore & " ]; echo $?'
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,251 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import print_function # to use print() of Python 3 in Python >= 2.7
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
import glob
|
||||
import platform
|
||||
import optparse
|
||||
import subprocess
|
||||
|
||||
Variation = [ 'std', 'ports', 'brew', 'ana3' ]
|
||||
|
||||
Usage = "\n"
|
||||
Usage += "------------------------------------------------------------------------------------------\n"
|
||||
Usage += " nightyCatalina.py [EXPERIMENTAL] \n"
|
||||
Usage += " << To execute the jobs for making KLatyout's DMGs for macOS Catalina >> \n"
|
||||
Usage += "\n"
|
||||
Usage += "$ [python] nightyCatalina.py \n"
|
||||
Usage += " option & argument : comment on option if any | default value\n"
|
||||
Usage += " -------------------------------------------------------------------+--------------\n"
|
||||
Usage += " [--build] : build and deploy | disabled\n"
|
||||
Usage += " [--makedmg <srlno>] : make DMG | disabled\n"
|
||||
Usage += " [--cleandmg <srlno>] : clean DMG | disabled\n"
|
||||
Usage += " [--upload <dropbox>] : upload to $HOME/Dropbox/klayout/<dropbox> | disabled\n"
|
||||
Usage += " [-?|--?] : print this usage and exit | disabled\n"
|
||||
Usage += "----------------------------------------------------------------------+-------------------\n"
|
||||
|
||||
def ParseCommandLineArguments():
|
||||
global Usage
|
||||
global Build # operation flag
|
||||
global MakeDMG # operation flag
|
||||
global CleanDMG # operation flag
|
||||
global Upload # operation flag
|
||||
global SrlDMG # DMG serial number
|
||||
global Dropbox # Dropbox directory
|
||||
|
||||
p = optparse.OptionParser( usage=Usage )
|
||||
p.add_option( '--build',
|
||||
action='store_true',
|
||||
dest='build',
|
||||
default=False,
|
||||
help='build and deploy' )
|
||||
|
||||
p.add_option( '--makedmg',
|
||||
dest='makedmg',
|
||||
help='make DMG' )
|
||||
|
||||
p.add_option( '--cleandmg',
|
||||
dest='cleandmg',
|
||||
help='clean DMG' )
|
||||
|
||||
p.add_option( '--upload',
|
||||
dest='upload',
|
||||
help='upload to Dropbox' )
|
||||
|
||||
p.add_option( '-?', '--??',
|
||||
action='store_true',
|
||||
dest='checkusage',
|
||||
default=False,
|
||||
help='check usage (false)' )
|
||||
|
||||
p.set_defaults( build = False,
|
||||
makedmg = "",
|
||||
cleandmg = "",
|
||||
upload = "",
|
||||
checkusage = False )
|
||||
|
||||
opt, args = p.parse_args()
|
||||
if opt.checkusage:
|
||||
print(Usage)
|
||||
quit()
|
||||
|
||||
Build = False
|
||||
MakeDMG = False
|
||||
CleanDMG = False
|
||||
Upload = False
|
||||
|
||||
Build = opt.build
|
||||
|
||||
if not opt.makedmg == "":
|
||||
MakeDMG = True
|
||||
CleanDMG = False
|
||||
SrlDMG = int(opt.makedmg)
|
||||
|
||||
if not opt.cleandmg == "":
|
||||
MakeDMG = False
|
||||
CleanDMG = True
|
||||
SrlDMG = int(opt.cleandmg)
|
||||
|
||||
if not opt.upload == "":
|
||||
Upload = True
|
||||
Dropbox = opt.upload
|
||||
|
||||
if not (Build or MakeDMG or CleanDMG or Upload):
|
||||
print( "! No option selected" )
|
||||
print(Usage)
|
||||
quit()
|
||||
|
||||
|
||||
def BuildDeploy():
|
||||
PyBuild = "./build4mac.py"
|
||||
|
||||
Build = dict()
|
||||
Build["std"] = [ '-q', 'Qt5MacPorts', '-r', 'sys', '-p', 'sys' ]
|
||||
Build["ports"] = [ '-q', 'Qt5MacPorts', '-r', 'MP26', '-p', 'MP37' ]
|
||||
Build["brew"] = [ '-q', 'Qt5Brew', '-r', 'HB27', '-p', 'HB37' ]
|
||||
Build["ana3"] = [ '-q', 'Qt5Ana3', '-r', 'Ana3', '-p', 'Ana3' ]
|
||||
|
||||
for key in Variation:
|
||||
command1 = [ PyBuild ] + Build[key]
|
||||
if key == "std":
|
||||
command2 = [ PyBuild ] + Build[key] + ['-y']
|
||||
else:
|
||||
command2 = [ PyBuild ] + Build[key] + ['-Y']
|
||||
print(command1)
|
||||
print(command2)
|
||||
#continue
|
||||
|
||||
if subprocess.call( command1, shell=False ) != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to build KLayout" % PyBuild, file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
sys.exit(1)
|
||||
else:
|
||||
print( "", file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "### <%s>: successfully built KLayout" % PyBuild, file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
|
||||
if subprocess.call( command2, shell=False ) != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to deploy KLayout" % PyBuild, file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
sys.exit(1)
|
||||
else:
|
||||
print( "", file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "### <%s>: successfully deployed KLayout" % PyBuild, file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
|
||||
|
||||
def DMG_Make( srlDMG ):
|
||||
PyDMG = "./makeDMG4mac.py"
|
||||
Stash = "./DMGStash"
|
||||
|
||||
Pack = dict()
|
||||
Pack["std"] = [ '-p', 'ST-qt5MP.pkg.macos-Catalina-release-RsysPsys', '-s', '%d' % srlDMG, '-m' ]
|
||||
Pack["ports"] = [ '-p', 'LW-qt5MP.pkg.macos-Catalina-release-Rmp26Pmp37', '-s', '%d' % srlDMG, '-m' ]
|
||||
Pack["brew"] = [ '-p', 'LW-qt5Brew.pkg.macos-Catalina-release-Rhb27Phb37', '-s', '%d' % srlDMG, '-m' ]
|
||||
Pack["ana3"] = [ '-p', 'LW-qt5Ana3.pkg.macos-Catalina-release-Rana3Pana3', '-s', '%d' % srlDMG, '-m' ]
|
||||
|
||||
if os.path.isdir( Stash ):
|
||||
shutil.rmtree( Stash )
|
||||
os.mkdir( Stash )
|
||||
|
||||
for key in Variation:
|
||||
command3 = [ PyDMG ] + Pack[key]
|
||||
print(command3)
|
||||
#continue
|
||||
|
||||
if subprocess.call( command3, shell=False ) != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to make KLayout DMG" % PyDMG, file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
sys.exit(1)
|
||||
else:
|
||||
print( "", file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "### <%s>: successfully made KLayout DMG" % PyDMG, file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
|
||||
dmgs = glob.glob( "*.dmg*" )
|
||||
for item in dmgs:
|
||||
shutil.move( item, Stash )
|
||||
|
||||
|
||||
def DMG_Clean( srlDMG ):
|
||||
PyDMG = "./makeDMG4mac.py"
|
||||
Stash = "./DMGStash"
|
||||
|
||||
Pack = dict()
|
||||
Pack["std"] = [ '-p', 'ST-qt5MP.pkg.macos-Catalina-release-RsysPsys', '-s', '%d' % srlDMG, '-c' ]
|
||||
Pack["ports"] = [ '-p', 'LW-qt5MP.pkg.macos-Catalina-release-Rmp26Pmp37', '-s', '%d' % srlDMG, '-c' ]
|
||||
Pack["brew"] = [ '-p', 'LW-qt5Brew.pkg.macos-Catalina-release-Rhb27Phb37', '-s', '%d' % srlDMG, '-c' ]
|
||||
Pack["ana3"] = [ '-p', 'LW-qt5Ana3.pkg.macos-Catalina-release-Rana3Pana3', '-s', '%d' % srlDMG, '-c' ]
|
||||
|
||||
if os.path.isdir( Stash ):
|
||||
shutil.rmtree( Stash )
|
||||
|
||||
for key in Variation:
|
||||
command3 = [ PyDMG ] + Pack[key]
|
||||
print(command3)
|
||||
#continue
|
||||
|
||||
if subprocess.call( command3, shell=False ) != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to clean KLayout DMG" % PyDMG, file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
sys.exit(1)
|
||||
else:
|
||||
print( "", file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "### <%s>: successfully cleaned KLayout DMG" % PyDMG, file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
|
||||
|
||||
def UploadToDropbox( targetdir ):
|
||||
Stash = "./DMGStash"
|
||||
|
||||
distDir = os.environ["HOME"] + "/Dropbox/klayout/" + targetdir
|
||||
if not os.path.isdir(distDir):
|
||||
os.makedirs(distDir)
|
||||
|
||||
dmgs = glob.glob( "%s/*.dmg*" % Stash )
|
||||
for item in dmgs:
|
||||
shutil.copy2( item, distDir )
|
||||
|
||||
|
||||
def Main():
|
||||
ParseCommandLineArguments()
|
||||
|
||||
if Build:
|
||||
BuildDeploy()
|
||||
elif MakeDMG:
|
||||
DMG_Make( SrlDMG )
|
||||
elif CleanDMG:
|
||||
DMG_Clean( SrlDMG )
|
||||
elif Upload:
|
||||
UploadToDropbox( Dropbox )
|
||||
|
||||
#===================================================================================
|
||||
if __name__ == "__main__":
|
||||
Main()
|
||||
|
||||
#---------------
|
||||
# End of file
|
||||
#---------------
|
||||
|
|
@ -87,5 +87,6 @@ BD_PUBLIC int strmrun (int argc, char *argv[])
|
|||
|
||||
lym::Macro macro;
|
||||
macro.load_from (script);
|
||||
macro.set_file_path (script);
|
||||
return macro.run ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,11 @@ struct basic_array_iterator
|
|||
|
||||
virtual long index_a () const { return -1; }
|
||||
virtual long index_b () const { return -1; }
|
||||
|
||||
|
||||
virtual size_t quad_id () const { return 0; }
|
||||
virtual box_type quad_box () const { return box_type::world (); }
|
||||
virtual void skip_quad () { }
|
||||
|
||||
virtual disp_type get () const = 0;
|
||||
|
||||
virtual basic_array_iterator<Coord> *clone () const = 0;
|
||||
|
|
@ -111,8 +115,12 @@ struct ArrayBase
|
|||
|
||||
virtual bool equal (const ArrayBase *) const = 0;
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *) const = 0;
|
||||
|
||||
virtual bool less (const ArrayBase *) const = 0;
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *) const = 0;
|
||||
|
||||
virtual void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const = 0;
|
||||
|
||||
bool in_repository;
|
||||
|
|
@ -554,6 +562,12 @@ struct regular_array
|
|||
return (m_a == d->m_a && m_b == d->m_b && m_amax == d->m_amax && m_bmax == d->m_bmax);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
const regular_array<Coord> *d = static_cast<const regular_array<Coord> *> (b);
|
||||
return (m_a.equal (d->m_a) && m_b.equal (d->m_b) && m_amax == d->m_amax && m_bmax == d->m_bmax);
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const regular_array<Coord> *d = static_cast<const regular_array<Coord> *> (b);
|
||||
|
|
@ -562,6 +576,14 @@ struct regular_array
|
|||
m_amax < d->m_amax || (m_amax == d->m_amax && m_bmax < d->m_bmax)))));
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
const regular_array<Coord> *d = static_cast<const regular_array<Coord> *> (b);
|
||||
return m_a.less (d->m_a) || (m_a.equal (d->m_a) && (
|
||||
m_b.less (d->m_b) || (m_b.equal (d->m_b) && (
|
||||
m_amax < d->m_amax || (m_amax == d->m_amax && m_bmax < d->m_bmax)))));
|
||||
}
|
||||
|
||||
virtual bool is_regular_array (vector_type &a, vector_type &b, unsigned long &amax, unsigned long &bmax) const
|
||||
{
|
||||
a = m_a;
|
||||
|
|
@ -702,6 +724,18 @@ struct regular_complex_array
|
|||
return regular_array<Coord>::equal (b);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
const regular_complex_array<Coord> *d = static_cast<const regular_complex_array<Coord> *> (b);
|
||||
if (fabs (m_acos - d->m_acos) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
if (fabs (m_mag - d->m_mag) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
return regular_array<Coord>::fuzzy_equal (b);
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const regular_complex_array<Coord> *d = static_cast<const regular_complex_array<Coord> *> (b);
|
||||
|
|
@ -714,6 +748,18 @@ struct regular_complex_array
|
|||
return regular_array<Coord>::less (b);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
const regular_complex_array<Coord> *d = static_cast<const regular_complex_array<Coord> *> (b);
|
||||
if (fabs (m_acos - d->m_acos) > epsilon) {
|
||||
return m_acos < d->m_acos;
|
||||
}
|
||||
if (fabs (m_mag - d->m_mag) > epsilon) {
|
||||
return m_mag < d->m_mag;
|
||||
}
|
||||
return regular_array<Coord>::fuzzy_less (b);
|
||||
}
|
||||
|
||||
virtual void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
||||
{
|
||||
if (!no_self) {
|
||||
|
|
@ -806,6 +852,21 @@ struct iterated_array_iterator
|
|||
return new iterated_array_iterator <Coord> (*this);
|
||||
}
|
||||
|
||||
virtual size_t quad_id () const
|
||||
{
|
||||
return m_t.quad_id ();
|
||||
}
|
||||
|
||||
virtual box_type quad_box () const
|
||||
{
|
||||
return m_t.quad_box ();
|
||||
}
|
||||
|
||||
virtual void skip_quad ()
|
||||
{
|
||||
m_t.skip_quad ();
|
||||
}
|
||||
|
||||
private:
|
||||
box_tree_const_iterator m_b, m_e;
|
||||
box_tree_touching_iterator m_t;
|
||||
|
|
@ -964,6 +1025,20 @@ struct iterated_array
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_array<Coord> *d = static_cast<const iterated_array<Coord> *> (b);
|
||||
if (m_v.size () != d->m_v.size ()) {
|
||||
return false;
|
||||
}
|
||||
for (const_iterator p1 = m_v.begin (), p2 = d->m_v.begin (); p1 != m_v.end (); ++p1, ++p2) {
|
||||
if (! p1->equal (*p2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_array<Coord> *d = static_cast<const iterated_array<Coord> *> (b);
|
||||
|
|
@ -978,6 +1053,20 @@ struct iterated_array
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_array<Coord> *d = static_cast<const iterated_array<Coord> *> (b);
|
||||
if (m_v.size () != d->m_v.size ()) {
|
||||
return (m_v.size () < d->m_v.size ());
|
||||
}
|
||||
for (const_iterator p1 = m_v.begin (), p2 = d->m_v.begin (); p1 != m_v.end (); ++p1, ++p2) {
|
||||
if (! p1->equal (*p2)) {
|
||||
return (p1->less (*p2));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
||||
{
|
||||
if (!no_self) {
|
||||
|
|
@ -1085,6 +1174,18 @@ struct iterated_complex_array
|
|||
return iterated_array<Coord>::equal (b);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_complex_array<Coord> *d = static_cast<const iterated_complex_array<Coord> *> (b);
|
||||
if (fabs (m_acos - d->m_acos) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
if (fabs (m_mag - d->m_mag) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
return iterated_array<Coord>::fuzzy_equal (b);
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_complex_array<Coord> *d = static_cast<const iterated_complex_array<Coord> *> (b);
|
||||
|
|
@ -1097,6 +1198,18 @@ struct iterated_complex_array
|
|||
return iterated_array<Coord>::less (b);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_complex_array<Coord> *d = static_cast<const iterated_complex_array<Coord> *> (b);
|
||||
if (fabs (m_acos - d->m_acos) > epsilon) {
|
||||
return m_acos < d->m_acos;
|
||||
}
|
||||
if (fabs (m_mag - d->m_mag) > epsilon) {
|
||||
return m_mag < d->m_mag;
|
||||
}
|
||||
return iterated_array<Coord>::fuzzy_less (b);
|
||||
}
|
||||
|
||||
virtual complex_trans_type complex_trans (const simple_trans_type &s) const
|
||||
{
|
||||
return complex_trans_type (s, m_acos, m_mag);
|
||||
|
|
@ -1187,7 +1300,12 @@ struct single_complex_inst
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
return equal (b);
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const double epsilon = 1e-10;
|
||||
const single_complex_inst<Coord> *d = static_cast<const single_complex_inst<Coord> *> (b);
|
||||
|
|
@ -1200,6 +1318,11 @@ struct single_complex_inst
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
return less (b);
|
||||
}
|
||||
|
||||
virtual void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
||||
{
|
||||
if (!no_self) {
|
||||
|
|
@ -1420,6 +1543,36 @@ struct array_iterator
|
|||
return mp_base ? mp_base->index_b () : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For iterators supporting quads (iterated arrays), this method will return the quad ID
|
||||
*/
|
||||
size_t quad_id () const
|
||||
{
|
||||
return mp_base ? mp_base->quad_id () : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For iterators supporting quads (iterated arrays), this method will return the quad bounding box
|
||||
*
|
||||
* Note that this method will only return a valid quad box is the quad_id is non-null.
|
||||
*
|
||||
* This method will return the bounding box of all array offsets in the quad.
|
||||
*/
|
||||
db::box<Coord> quad_box () const
|
||||
{
|
||||
return mp_base ? mp_base->quad_box () : db::box<Coord>::world ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For iterators supporting quads (iterated arrays), this method will skip the current quad
|
||||
*/
|
||||
void skip_quad ()
|
||||
{
|
||||
if (mp_base) {
|
||||
mp_base->skip_quad ();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
trans_type m_trans;
|
||||
basic_array_iterator <Coord> *mp_base;
|
||||
|
|
@ -1592,6 +1745,32 @@ struct array
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The iterated array constructor
|
||||
*
|
||||
* This is basically a convenience function that creates
|
||||
* an appropriate basic_array object.
|
||||
*/
|
||||
template <class Iter>
|
||||
array (const Obj &obj, const trans_type &trans, Iter from, Iter to)
|
||||
: m_obj (obj), m_trans (trans), mp_base (new iterated_array <coord_type> (from, to))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The complex iterated array constructor
|
||||
*
|
||||
* This is basically a convenience function that creates
|
||||
* an appropriate basic_array object.
|
||||
*/
|
||||
template <class Iter>
|
||||
array (const Obj &obj, const complex_trans_type &ct, Iter from, Iter to)
|
||||
: m_obj (obj), m_trans (ct), mp_base (new iterated_complex_array <coord_type> (ct.rcos (), ct.mag (), from, to))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The singular complex instance constructor
|
||||
*
|
||||
|
|
@ -1835,6 +2014,32 @@ struct array
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the bounding box from the iterator's current quad
|
||||
*
|
||||
* The bounding box is that of all objects in the current quad and
|
||||
* is confined to the array's total bounding box.
|
||||
*/
|
||||
template <class Iter, class BoxConv>
|
||||
box_type quad_box (const Iter &iter, const BoxConv &bc) const
|
||||
{
|
||||
box_type bb;
|
||||
if (mp_base) {
|
||||
bb = mp_base->bbox (box_type (0, 0, 0, 0));
|
||||
}
|
||||
bb &= iter.quad_box ();
|
||||
|
||||
if (mp_base) {
|
||||
if (mp_base->is_complex ()) {
|
||||
return bb * box_type (mp_base->complex_trans (simple_trans_type (m_trans)) * bc (m_obj));
|
||||
} else {
|
||||
return bb * (m_trans * bc (m_obj));
|
||||
}
|
||||
} else {
|
||||
return bb * (m_trans * bc (m_obj));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The number of single instances in the array
|
||||
*/
|
||||
|
|
@ -1918,6 +2123,21 @@ struct array
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare operator for equality (fuzzy version)
|
||||
*/
|
||||
bool equal (const array<Obj, Trans> &d) const
|
||||
{
|
||||
if (! mp_base) {
|
||||
return (m_trans.equal (d.m_trans) && m_obj == d.m_obj && ! d.mp_base);
|
||||
} else {
|
||||
if (! m_trans.equal (d.m_trans) || ! (m_obj == d.m_obj) || type () != d.type ()) {
|
||||
return false;
|
||||
}
|
||||
return mp_base && mp_base->fuzzy_equal (d.mp_base);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A sorting order criterion
|
||||
*/
|
||||
|
|
@ -1943,6 +2163,31 @@ struct array
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A fuzzy sorting order criterion
|
||||
*/
|
||||
bool less (const array<Obj, Trans> &d) const
|
||||
{
|
||||
if (! (m_obj == d.m_obj)) {
|
||||
return (m_obj < d.m_obj);
|
||||
}
|
||||
if (! m_trans.equal (d.m_trans)) {
|
||||
return m_trans.less (d.m_trans);
|
||||
}
|
||||
if (type () != d.type ()) {
|
||||
return (type () < d.type ());
|
||||
}
|
||||
if (mp_base == d.mp_base) {
|
||||
return false;
|
||||
} else if (! mp_base) {
|
||||
return true;
|
||||
} else if (! d.mp_base) {
|
||||
return false;
|
||||
} else {
|
||||
return mp_base->fuzzy_less (d.mp_base);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare operator
|
||||
*
|
||||
|
|
@ -2263,7 +2508,7 @@ struct array
|
|||
}
|
||||
db::mem_stat (stat, purpose, cat, m_obj, true, (void *) this);
|
||||
if (mp_base) {
|
||||
db::mem_stat (stat, purpose, cat, *mp_base, false, (void *) this);
|
||||
mp_base->mem_stat (stat, purpose, cat, false, (void *) this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -168,40 +168,43 @@ public:
|
|||
typedef typename Tree::coord_type coord_type;
|
||||
typedef typename Tree::box_type box_type;
|
||||
|
||||
box_tree_node (box_tree_node *parent, const point_type ¢er, unsigned int quad)
|
||||
: m_center (center)
|
||||
box_tree_node (box_tree_node *parent, const point_type ¢er, const box_type &qbox, unsigned int quad)
|
||||
{
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
m_lenq[i] = 0;
|
||||
}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
mp_children[i] = 0;
|
||||
}
|
||||
mp_parent = (box_tree_node *)((char *) parent + quad);
|
||||
if (parent) {
|
||||
parent->mp_children [quad] = this;
|
||||
point_type corner;
|
||||
if (quad == 0) {
|
||||
corner = qbox.upper_right ();
|
||||
} else if (quad == 1) {
|
||||
corner = qbox.upper_left ();
|
||||
} else if (quad == 2) {
|
||||
corner = qbox.lower_left ();
|
||||
} else if (quad == 3) {
|
||||
corner = qbox.lower_right ();
|
||||
}
|
||||
|
||||
init (parent, center, corner, quad);
|
||||
}
|
||||
|
||||
~box_tree_node ()
|
||||
{
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (mp_children [i]) {
|
||||
delete mp_children [i];
|
||||
mp_children [i] = 0;
|
||||
box_tree_node *c = child (i);
|
||||
if (c) {
|
||||
delete c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
box_tree_node *clone (box_tree_node *parent = 0, unsigned int quad = 0) const
|
||||
{
|
||||
box_tree_node *n = new box_tree_node (parent, m_center, quad);
|
||||
for (unsigned int i = 0; i < 5; ++i) {
|
||||
n->m_lenq[i] = m_lenq[i];
|
||||
}
|
||||
box_tree_node *n = new box_tree_node (parent, m_center, m_corner, quad);
|
||||
n->m_lenq = m_lenq;
|
||||
n->m_len = m_len;
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
if (mp_children[i]) {
|
||||
mp_children[i]->clone (n, i);
|
||||
box_tree_node *c = child (i);
|
||||
if (c) {
|
||||
c->clone (n, i);
|
||||
} else {
|
||||
n->m_childrefs [i] = m_childrefs [i];
|
||||
}
|
||||
}
|
||||
return n;
|
||||
|
|
@ -209,17 +212,39 @@ public:
|
|||
|
||||
box_tree_node *child (int i) const
|
||||
{
|
||||
return mp_children [i];
|
||||
if ((m_childrefs [i] & 1) == 0) {
|
||||
return reinterpret_cast<box_tree_node *> (m_childrefs [i]);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void lenq (int i, size_t l)
|
||||
{
|
||||
m_lenq[i + 1] = l;
|
||||
if (i < 0) {
|
||||
m_lenq = l;
|
||||
} else {
|
||||
box_tree_node *c = child (i);
|
||||
if (c) {
|
||||
c->m_len = l;
|
||||
} else {
|
||||
m_childrefs [i] = l * 2 + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t lenq (int i) const
|
||||
{
|
||||
return m_lenq[i + 1];
|
||||
if (i < 0) {
|
||||
return m_lenq;
|
||||
} else {
|
||||
box_tree_node *c = child (i);
|
||||
if (c) {
|
||||
return c->m_len;
|
||||
} else {
|
||||
return m_childrefs [i] >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
box_tree_node *parent () const
|
||||
|
|
@ -238,8 +263,8 @@ public:
|
|||
stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat);
|
||||
}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (mp_children [i]) {
|
||||
mp_children [i]->mem_stat (stat, purpose, cat, no_self, parent);
|
||||
if (child (i)) {
|
||||
child (i)->mem_stat (stat, purpose, cat, no_self, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -249,14 +274,52 @@ public:
|
|||
return m_center;
|
||||
}
|
||||
|
||||
box_type quad_box (int quad) const
|
||||
{
|
||||
box_type qb = box_type::world ();
|
||||
if (parent ()) {
|
||||
qb = box_type (m_corner, parent ()->center ());
|
||||
}
|
||||
|
||||
switch (quad) {
|
||||
case 0: return box_type (m_center, qb.upper_right ());
|
||||
case 1: return box_type (m_center, qb.upper_left ());
|
||||
case 2: return box_type (m_center, qb.lower_left ());
|
||||
case 3: return box_type (m_center, qb.lower_right ());
|
||||
default: return qb;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
box_tree_node *mp_parent;
|
||||
size_t m_lenq [5];
|
||||
box_tree_node *mp_children [4];
|
||||
point_type m_center;
|
||||
size_t m_lenq, m_len;
|
||||
size_t m_childrefs [4];
|
||||
point_type m_center, m_corner;
|
||||
|
||||
box_tree_node (const box_tree_node &d);
|
||||
box_tree_node &operator= (const box_tree_node &d);
|
||||
|
||||
box_tree_node (box_tree_node *parent, const point_type ¢er, const point_type &corner, unsigned int quad)
|
||||
{
|
||||
init (parent, center, corner, quad);
|
||||
}
|
||||
|
||||
void init (box_tree_node *parent, const point_type ¢er, const point_type &corner, unsigned int quad)
|
||||
{
|
||||
m_center = center;
|
||||
m_corner = corner;
|
||||
|
||||
m_lenq = m_len = 0;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
m_childrefs [i] = 0;
|
||||
}
|
||||
|
||||
mp_parent = (box_tree_node *)((char *) parent + quad);
|
||||
if (parent) {
|
||||
m_len = (parent->m_childrefs [quad] >> 1);
|
||||
parent->m_childrefs [quad] = size_t (this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -459,28 +522,9 @@ public:
|
|||
box_type quad_box () const
|
||||
{
|
||||
if (! mp_node) {
|
||||
|
||||
return box_type::world ();
|
||||
|
||||
} else {
|
||||
|
||||
point_type c = mp_node->center ();
|
||||
box_type qb;
|
||||
if (! mp_node->parent ()) {
|
||||
qb = box_type::world ();
|
||||
} else {
|
||||
point_type pc = mp_node->parent ()->center ();
|
||||
qb = box_type (c - (pc - c), pc);
|
||||
}
|
||||
|
||||
switch (m_quad) {
|
||||
case 0: return box_type (c, qb.upper_right ());
|
||||
case 1: return box_type (c, qb.upper_left ());
|
||||
case 2: return box_type (c, qb.lower_left ());
|
||||
case 3: return box_type (c, qb.lower_right ());
|
||||
default: return qb;
|
||||
}
|
||||
|
||||
return mp_node->quad_box (m_quad);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -577,12 +621,16 @@ private:
|
|||
return m_quad < 4;
|
||||
}
|
||||
|
||||
// down one level
|
||||
// down as many levels as required for the next non-empty quad
|
||||
// returns true if this is possible
|
||||
bool down ()
|
||||
{
|
||||
box_tree_node *c = mp_node->child (m_quad);
|
||||
if (c) {
|
||||
while (true) {
|
||||
|
||||
box_tree_node *c = mp_node->child (m_quad);
|
||||
if (! c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mp_node = c;
|
||||
m_quad = -1;
|
||||
|
|
@ -595,12 +643,11 @@ private:
|
|||
// nothing to visit: up again
|
||||
up ();
|
||||
return false;
|
||||
} else {
|
||||
} else if (m_quad < 0) {
|
||||
// stay in main chunk
|
||||
return true;
|
||||
}
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -670,7 +717,7 @@ private:
|
|||
* whose box overlaps or touches a specified test box.
|
||||
*/
|
||||
|
||||
template <class Box, class Obj, class BoxConv, size_t min_bin = 100, size_t min_quads = 100>
|
||||
template <class Box, class Obj, class BoxConv, size_t min_bin = 100, size_t min_quads = 100, unsigned int thin_aspect = 4>
|
||||
class box_tree
|
||||
{
|
||||
public:
|
||||
|
|
@ -1175,7 +1222,16 @@ private:
|
|||
|
||||
// the bins are: overall, ur, ul, ll, lr, empty
|
||||
element_iterator qloc [6] = { from, from, from, from, from, from };
|
||||
point_type center (bbox.center ());
|
||||
point_type center;
|
||||
if (bbox.width () < bbox.height () / thin_aspect) {
|
||||
// separate by height only
|
||||
center = point_type (bbox.left (), bbox.bottom () + bbox.height () / 2);
|
||||
} else if (bbox.height () < bbox.width () / thin_aspect) {
|
||||
// separate by width only
|
||||
center = point_type (bbox.left () + bbox.width () / 2, bbox.bottom ());
|
||||
} else {
|
||||
center = bbox.center ();
|
||||
}
|
||||
|
||||
for (element_iterator e = from; e != to; ++e) {
|
||||
|
||||
|
|
@ -1224,7 +1280,7 @@ private:
|
|||
if (nn >= min_quads) {
|
||||
|
||||
// create a new node representing this tree
|
||||
box_tree_node *node = new box_tree_node (parent, center, quad);
|
||||
box_tree_node *node = new box_tree_node (parent, center, bbox, quad);
|
||||
if (parent == 0) {
|
||||
mp_root = node;
|
||||
}
|
||||
|
|
@ -1460,28 +1516,9 @@ public:
|
|||
box_type quad_box () const
|
||||
{
|
||||
if (! mp_node) {
|
||||
|
||||
return box_type::world ();
|
||||
|
||||
} else {
|
||||
|
||||
point_type c = mp_node->center ();
|
||||
box_type qb;
|
||||
if (! mp_node->parent ()) {
|
||||
qb = box_type::world ();
|
||||
} else {
|
||||
point_type pc = mp_node->parent ()->center ();
|
||||
qb = box_type (c - (pc - c), pc);
|
||||
}
|
||||
|
||||
switch (m_quad) {
|
||||
case 0: return box_type (c, qb.upper_right ());
|
||||
case 1: return box_type (c, qb.upper_left ());
|
||||
case 2: return box_type (c, qb.lower_left ());
|
||||
case 3: return box_type (c, qb.lower_right ());
|
||||
default: return qb;
|
||||
}
|
||||
|
||||
return mp_node->quad_box (m_quad);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1578,12 +1615,16 @@ private:
|
|||
return m_quad < 4;
|
||||
}
|
||||
|
||||
// down one level
|
||||
// down as many levels as required for the next non-empty quad
|
||||
// returns true if this is possible
|
||||
bool down ()
|
||||
{
|
||||
box_tree_node *c = mp_node->child (m_quad);
|
||||
if (c) {
|
||||
while (true) {
|
||||
|
||||
box_tree_node *c = mp_node->child (m_quad);
|
||||
if (! c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mp_node = c;
|
||||
m_quad = -1;
|
||||
|
|
@ -1596,12 +1637,11 @@ private:
|
|||
// nothing to visit: up again
|
||||
up ();
|
||||
return false;
|
||||
} else {
|
||||
} else if (m_quad < 0) {
|
||||
// stay in main chunk
|
||||
return true;
|
||||
}
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1638,7 +1678,7 @@ private:
|
|||
* is sorted.
|
||||
*/
|
||||
|
||||
template <class Box, class Obj, class BoxConv, size_t min_bin = 100, size_t min_quads = 100>
|
||||
template <class Box, class Obj, class BoxConv, size_t min_bin = 100, size_t min_quads = 100, unsigned int thin_aspect = 4>
|
||||
class unstable_box_tree
|
||||
{
|
||||
public:
|
||||
|
|
@ -2103,7 +2143,16 @@ private:
|
|||
}
|
||||
|
||||
obj_iterator qloc [5] = { from, from, from, from, from };
|
||||
point_type center (bbox.center ());
|
||||
point_type center;
|
||||
if (bbox.width () < bbox.height () / thin_aspect) {
|
||||
// separate by height only
|
||||
center = point_type (bbox.left (), bbox.bottom () + bbox.height () / 2);
|
||||
} else if (bbox.height () < bbox.width () / thin_aspect) {
|
||||
// separate by width only
|
||||
center = point_type (bbox.left () + bbox.width () / 2, bbox.bottom ());
|
||||
} else {
|
||||
center = bbox.center ();
|
||||
}
|
||||
|
||||
for (obj_iterator e = from; e != to; ++e) {
|
||||
|
||||
|
|
@ -2158,7 +2207,7 @@ private:
|
|||
if (nn >= min_quads) {
|
||||
|
||||
// create a new node representing this tree
|
||||
box_tree_node *node = new box_tree_node (parent, center, quad);
|
||||
box_tree_node *node = new box_tree_node (parent, center, bbox, quad);
|
||||
if (parent == 0) {
|
||||
mp_root = node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -301,6 +301,30 @@ public:
|
|||
return m_instances.transform_into (ref, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transforms the cell by the given transformation.
|
||||
*
|
||||
* The transformation is applied to all instances and shapes. Magnified transformations will
|
||||
* render magnified instances. See \transform_into for a version which avoids this.
|
||||
*
|
||||
* @param t The transformation to apply
|
||||
*/
|
||||
template <class Trans>
|
||||
void transform (const Trans &t)
|
||||
{
|
||||
m_instances.transform (t);
|
||||
for (typename shapes_map::iterator s = m_shapes_map.begin (); s != m_shapes_map.end (); ++s) {
|
||||
if (! s->second.empty ()) {
|
||||
// Note: don't use the copy ctor here - it will copy the attachment to the manager
|
||||
// and create problems when destroyed. Plus: swap would be more efficient. But by using
|
||||
// assign_transformed we get undo support for free.
|
||||
shapes_type d;
|
||||
d = s->second;
|
||||
s->second.assign_transformed (d, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transforms the cell into a new coordinate system.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -333,20 +333,40 @@ void Circuit::remove_pin (size_t id)
|
|||
|
||||
void Circuit::add_net (Net *net)
|
||||
{
|
||||
if (! net) {
|
||||
return;
|
||||
}
|
||||
if (net->circuit ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Net already part of a circuit")));
|
||||
}
|
||||
|
||||
m_nets.push_back (net);
|
||||
net->set_circuit (this);
|
||||
}
|
||||
|
||||
void Circuit::remove_net (Net *net)
|
||||
{
|
||||
if (! net) {
|
||||
return;
|
||||
}
|
||||
if (net->circuit () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Net not withing given circuit")));
|
||||
}
|
||||
|
||||
m_nets.erase (net);
|
||||
}
|
||||
|
||||
void Circuit::join_nets (Net *net, Net *with)
|
||||
{
|
||||
if (! net) {
|
||||
return;
|
||||
}
|
||||
if (net == with || ! with) {
|
||||
return;
|
||||
}
|
||||
if (net->circuit () != this || with->circuit () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Nets not withing given circuit")));
|
||||
}
|
||||
|
||||
while (with->begin_terminals () != with->end_terminals ()) {
|
||||
db::Device *device = const_cast<db::Device *> (with->begin_terminals ()->device ());
|
||||
|
|
@ -372,6 +392,13 @@ void Circuit::join_nets (Net *net, Net *with)
|
|||
|
||||
void Circuit::add_device (Device *device)
|
||||
{
|
||||
if (! device) {
|
||||
return;
|
||||
}
|
||||
if (device->circuit ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device already in a circuit")));
|
||||
}
|
||||
|
||||
device->set_circuit (this);
|
||||
|
||||
size_t id = 0;
|
||||
|
|
@ -386,11 +413,25 @@ void Circuit::add_device (Device *device)
|
|||
|
||||
void Circuit::remove_device (Device *device)
|
||||
{
|
||||
if (! device) {
|
||||
return;
|
||||
}
|
||||
if (device->circuit () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device not withing given circuit")));
|
||||
}
|
||||
|
||||
m_devices.erase (device);
|
||||
}
|
||||
|
||||
void Circuit::add_subcircuit (SubCircuit *subcircuit)
|
||||
{
|
||||
if (! subcircuit) {
|
||||
return;
|
||||
}
|
||||
if (subcircuit->circuit ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Subcircuit already in a circuit")));
|
||||
}
|
||||
|
||||
subcircuit->set_circuit (this);
|
||||
|
||||
size_t id = 0;
|
||||
|
|
@ -405,6 +446,13 @@ void Circuit::add_subcircuit (SubCircuit *subcircuit)
|
|||
|
||||
void Circuit::remove_subcircuit (SubCircuit *subcircuit)
|
||||
{
|
||||
if (! subcircuit) {
|
||||
return;
|
||||
}
|
||||
if (subcircuit->circuit () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Subcircuit not withing given circuit")));
|
||||
}
|
||||
|
||||
m_subcircuits.erase (subcircuit);
|
||||
}
|
||||
|
||||
|
|
@ -420,7 +468,12 @@ void Circuit::unregister_ref (SubCircuit *r)
|
|||
|
||||
void Circuit::flatten_subcircuit (SubCircuit *subcircuit)
|
||||
{
|
||||
tl_assert (subcircuit != 0);
|
||||
if (! subcircuit) {
|
||||
return;
|
||||
}
|
||||
if (subcircuit->circuit () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Subcircuit not withing given circuit")));
|
||||
}
|
||||
|
||||
const db::Circuit *c = subcircuit->circuit_ref ();
|
||||
|
||||
|
|
|
|||
|
|
@ -283,6 +283,12 @@ namespace std
|
|||
h = hfunc (b, h);
|
||||
h = hfunc (na, h);
|
||||
h = hfunc (nb, h);
|
||||
} else if (o.size () > 1) {
|
||||
// iterated array
|
||||
typename db::array <db::CellInst, db::simple_trans<C> >::iterator i = o.begin ();
|
||||
while (! (++i).at_end ()) {
|
||||
h = hfunc (*i, h);
|
||||
}
|
||||
}
|
||||
|
||||
if (o.is_complex ()) {
|
||||
|
|
|
|||
|
|
@ -1406,8 +1406,8 @@ private:
|
|||
struct InteractionKeyForClustersType
|
||||
: public InstanceToInstanceInteraction
|
||||
{
|
||||
InteractionKeyForClustersType (db::cell_index_type _ci1, db::cell_index_type _ci2, const db::ICplxTrans &_t21, const box_type &_box)
|
||||
: InstanceToInstanceInteraction (_ci1, 0, _ci2, 0, _t21), box (_box)
|
||||
InteractionKeyForClustersType (db::cell_index_type _ci1, db::cell_index_type _ci2, const db::ICplxTrans &_t1, const db::ICplxTrans &_t21, const box_type &_box)
|
||||
: InstanceToInstanceInteraction (_ci1, 0, _ci2, 0, _t1, _t21), box (_box)
|
||||
{ }
|
||||
|
||||
bool operator== (const InteractionKeyForClustersType &other) const
|
||||
|
|
@ -1482,18 +1482,22 @@ private:
|
|||
|
||||
InstanceToInstanceInteraction ii_key;
|
||||
db::ICplxTrans i1t, i2t;
|
||||
bool fill_cache = false;
|
||||
|
||||
// Cache is only used for single instances, non-iterated, simple or regular arrays.
|
||||
if ((! i1element.at_end () || i1.size () == 1 || ! i1.is_iterated_array ()) &&
|
||||
(! i2element.at_end () || i2.size () == 1 || ! i2.is_iterated_array ())) {
|
||||
|
||||
{
|
||||
i1t = i1element.at_end () ? i1.complex_trans () : i1.complex_trans (*i1element);
|
||||
db::ICplxTrans tt1 = t1 * i1t;
|
||||
|
||||
i2t = i2element.at_end () ? i2.complex_trans () : i2.complex_trans (*i2element);
|
||||
db::ICplxTrans tt2 = t2 * i2t;
|
||||
|
||||
db::ICplxTrans tt21 = tt1.inverted () * tt2;
|
||||
db::ICplxTrans cache_norm = tt1.inverted ();
|
||||
ii_key = InstanceToInstanceInteraction (i1.cell_index (), (! i1element.at_end () || i1.size () == 1) ? 0 : i1.cell_inst ().delegate (),
|
||||
i2.cell_index (), (! i2element.at_end () || i2.size () == 1) ? 0 : i2.cell_inst ().delegate (),
|
||||
tt21);
|
||||
cache_norm, cache_norm * tt2);
|
||||
|
||||
instance_interaction_cache_type::iterator ii = mp_instance_interaction_cache->find (ii_key);
|
||||
if (ii != mp_instance_interaction_cache->end ()) {
|
||||
|
|
@ -1511,6 +1515,9 @@ private:
|
|||
return;
|
||||
|
||||
}
|
||||
|
||||
fill_cache = true;
|
||||
|
||||
}
|
||||
|
||||
// array interactions
|
||||
|
|
@ -1611,15 +1618,19 @@ private:
|
|||
// return the list of unique interactions
|
||||
interacting_clusters.insert (interacting_clusters.end (), sorted_interactions.begin (), sorted_interactions.end ());
|
||||
|
||||
// normalize transformations in cache
|
||||
db::ICplxTrans i1ti = i1t.inverted (), i2ti = i2t.inverted ();
|
||||
for (std::vector<std::pair<ClusterInstance, ClusterInstance> >::iterator i = sorted_interactions.begin (); i != sorted_interactions.end (); ++i) {
|
||||
i->first.transform (i1ti);
|
||||
i->second.transform (i2ti);
|
||||
}
|
||||
if (fill_cache) {
|
||||
|
||||
cluster_instance_pair_list_type &cached = (*mp_instance_interaction_cache) [ii_key];
|
||||
cached.insert (cached.end (), sorted_interactions.begin (), sorted_interactions.end ());
|
||||
// normalize transformations for cache
|
||||
db::ICplxTrans i1ti = i1t.inverted (), i2ti = i2t.inverted ();
|
||||
for (std::vector<std::pair<ClusterInstance, ClusterInstance> >::iterator i = sorted_interactions.begin (); i != sorted_interactions.end (); ++i) {
|
||||
i->first.transform (i1ti);
|
||||
i->second.transform (i2ti);
|
||||
}
|
||||
|
||||
cluster_instance_pair_list_type &cached = (*mp_instance_interaction_cache) [ii_key];
|
||||
cached.insert (cached.end (), sorted_interactions.begin (), sorted_interactions.end ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1641,7 +1652,7 @@ private:
|
|||
|
||||
box_type common2 = common.transformed (t2i);
|
||||
|
||||
InteractionKeyForClustersType ikey (ci1, ci2, t21, common2);
|
||||
InteractionKeyForClustersType ikey (ci1, ci2, t1i, t21, common2);
|
||||
|
||||
typename std::map<InteractionKeyForClustersType, std::vector<std::pair<size_t, size_t> > >::const_iterator ici = m_interaction_cache_for_clusters.find (ikey);
|
||||
if (ici != m_interaction_cache_for_clusters.end ()) {
|
||||
|
|
|
|||
|
|
@ -762,13 +762,71 @@ inline bool less_array_delegates (const db::ArrayBase *a, const db::ArrayBase *b
|
|||
*/
|
||||
struct InstanceToInstanceInteraction
|
||||
{
|
||||
InstanceToInstanceInteraction (db::cell_index_type _ci1, const db::ArrayBase *_array1, db::cell_index_type _ci2, const db::ArrayBase *_array2, const db::ICplxTrans &_t21)
|
||||
: ci1 (_ci1), ci2 (_ci2), array1 (_array1), array2 (_array2), t21 (_t21)
|
||||
{ }
|
||||
InstanceToInstanceInteraction (db::cell_index_type _ci1, const db::ArrayBase *_array1, db::cell_index_type _ci2, const db::ArrayBase *_array2, const db::ICplxTrans &_tn, const db::ICplxTrans &_t21)
|
||||
: ci1 (_ci1), ci2 (_ci2), array1 (0), array2 (0), t21 (_t21)
|
||||
{
|
||||
if (_array1) {
|
||||
array1 = _array1->basic_clone ();
|
||||
static_cast<db::basic_array<db::Coord> *> (array1)->transform (_tn);
|
||||
}
|
||||
|
||||
if (_array2) {
|
||||
array2 = _array2->basic_clone ();
|
||||
static_cast<db::basic_array<db::Coord> *> (array2)->transform (_tn);
|
||||
}
|
||||
}
|
||||
|
||||
InstanceToInstanceInteraction ()
|
||||
: ci1 (0), ci2 (0), array1 (0), array2 (0)
|
||||
{ }
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
InstanceToInstanceInteraction (const InstanceToInstanceInteraction &other)
|
||||
: ci1 (other.ci1), ci2 (other.ci2),
|
||||
array1 (other.array1 ? other.array1->basic_clone () : 0),
|
||||
array2 (other.array2 ? other.array2->basic_clone () : 0),
|
||||
t21 (other.t21)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
InstanceToInstanceInteraction &operator= (const InstanceToInstanceInteraction &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
|
||||
ci1 = other.ci1;
|
||||
ci2 = other.ci2;
|
||||
|
||||
if (array1) {
|
||||
delete array1;
|
||||
}
|
||||
array1 = other.array1 ? other.array1->basic_clone () : 0;
|
||||
|
||||
if (array2) {
|
||||
delete array2;
|
||||
}
|
||||
array2 = other.array2 ? other.array2->basic_clone () : 0;
|
||||
|
||||
t21 = other.t21;
|
||||
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~InstanceToInstanceInteraction ()
|
||||
{
|
||||
if (array1) {
|
||||
delete array1;
|
||||
}
|
||||
array1 = 0;
|
||||
|
||||
if (array2) {
|
||||
delete array2;
|
||||
}
|
||||
array2 = 0;
|
||||
}
|
||||
|
||||
bool operator== (const InstanceToInstanceInteraction &other) const
|
||||
{
|
||||
|
|
@ -797,7 +855,7 @@ struct InstanceToInstanceInteraction
|
|||
}
|
||||
|
||||
db::cell_index_type ci1, ci2;
|
||||
const db::ArrayBase *array1, *array2;
|
||||
db::ArrayBase *array1, *array2;
|
||||
db::ICplxTrans t21;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ namespace db
|
|||
|
||||
static HierarchyBuilderShapeInserter def_inserter;
|
||||
|
||||
static HierarchyBuilder::cell_map_type null_map;
|
||||
static HierarchyBuilder::cell_map_type::const_iterator null_iterator = null_map.end ();
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
||||
int
|
||||
|
|
@ -168,7 +171,7 @@ HierarchyBuilder::reset ()
|
|||
m_cell_map.clear ();
|
||||
m_cells_seen.clear ();
|
||||
m_cell_stack.clear ();
|
||||
m_cm_entry = cell_map_type::const_iterator ();
|
||||
m_cm_entry = null_iterator;
|
||||
m_cm_new_entry = false;
|
||||
}
|
||||
|
||||
|
|
@ -263,14 +266,14 @@ HierarchyBuilder::end (const RecursiveShapeIterator *iter)
|
|||
m_cells_seen.clear ();
|
||||
mp_initial_cell = m_cell_stack.empty () ? 0 : m_cell_stack.front ().second.front ();
|
||||
m_cell_stack.clear ();
|
||||
m_cm_entry = cell_map_type::const_iterator ();
|
||||
m_cm_entry = null_iterator;
|
||||
m_cm_new_entry = false;
|
||||
}
|
||||
|
||||
void
|
||||
HierarchyBuilder::enter_cell (const RecursiveShapeIterator * /*iter*/, const db::Cell * /*cell*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
{
|
||||
tl_assert (m_cm_entry != m_cell_map.end () && m_cm_entry != cell_map_type::const_iterator ());
|
||||
tl_assert (m_cm_entry != m_cell_map.end () && m_cm_entry != null_iterator);
|
||||
|
||||
m_cells_seen.insert (m_cm_entry->first);
|
||||
|
||||
|
|
|
|||
|
|
@ -241,16 +241,28 @@ Instance::to_string (bool resolve_cell_name) const
|
|||
r = "cell_index=" + tl::to_string (ci.object ().cell_index ());
|
||||
}
|
||||
|
||||
if (ci.is_complex ()) {
|
||||
r += " " + ci.complex_trans ().to_string ();
|
||||
} else {
|
||||
r += " " + (*ci.begin ()).to_string ();
|
||||
}
|
||||
|
||||
db::vector<coord_type> a, b;
|
||||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
|
||||
if (ci.is_complex ()) {
|
||||
r += " " + ci.complex_trans ().to_string ();
|
||||
} else {
|
||||
r += " " + (*ci.begin ()).to_string ();
|
||||
}
|
||||
|
||||
r += " array=(" + a.to_string () + "," + b.to_string () + " " + tl::to_string (amax) + "x" + tl::to_string (bmax) + ")";
|
||||
|
||||
} else {
|
||||
|
||||
for (db::CellInstArray::iterator i = ci.begin (); ! i.at_end (); ++i) {
|
||||
if (ci.is_complex ()) {
|
||||
r += " " + ci.complex_trans (*i).to_string ();
|
||||
} else {
|
||||
r += " " + (*i).to_string ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (has_prop_id ()) {
|
||||
|
|
@ -640,13 +652,12 @@ OverlappingInstanceIteratorTraits::init (instance_iterator<OverlappingInstanceIt
|
|||
// ChildCellIterator implementation
|
||||
|
||||
ChildCellIterator::ChildCellIterator ()
|
||||
: m_iter (), m_end (), mp_insts (0)
|
||||
: m_iter (), m_end ()
|
||||
{ }
|
||||
|
||||
ChildCellIterator::ChildCellIterator (const instances_type *insts)
|
||||
: m_iter (insts->begin_sorted_insts ()),
|
||||
m_end (insts->end_sorted_insts ()),
|
||||
mp_insts (insts)
|
||||
m_end (insts->end_sorted_insts ())
|
||||
{ }
|
||||
|
||||
cell_index_type
|
||||
|
|
|
|||
|
|
@ -945,7 +945,6 @@ public:
|
|||
|
||||
private:
|
||||
inst_iterator_type m_iter, m_end;
|
||||
const instances_type *mp_insts;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1189,6 +1189,8 @@ PrintingDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperti
|
|||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
enough (tl::info) << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]" << tl::noendl;
|
||||
} else if (ci.size () > 1) {
|
||||
enough (tl::info) << " (+" << (ci.size () - 1) << " irregular locations)" << tl::noendl;
|
||||
} else {
|
||||
enough (tl::info) << "" << tl::noendl;
|
||||
}
|
||||
|
|
@ -1208,6 +1210,8 @@ PrintingDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperti
|
|||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
enough (tl::info) << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]" << tl::noendl;
|
||||
} else if (ci.size () > 1) {
|
||||
enough (tl::info) << " (+" << (ci.size () - 1) << " irregular locations)" << tl::noendl;
|
||||
} else {
|
||||
enough (tl::info) << "" << tl::noendl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1041,9 +1041,9 @@ LayoutToNetlist::build_nets (const std::vector<const db::Net *> *nets, const db:
|
|||
}
|
||||
}
|
||||
|
||||
db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::DPoint &point)
|
||||
db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::DPoint &point, std::vector<db::SubCircuit *> *sc_path_out, db::Circuit *initial_circuit)
|
||||
{
|
||||
return probe_net (of_region, db::CplxTrans (internal_layout ()->dbu ()).inverted () * point);
|
||||
return probe_net (of_region, db::CplxTrans (internal_layout ()->dbu ()).inverted () * point, sc_path_out, initial_circuit);
|
||||
}
|
||||
|
||||
size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<db::NetShape> &test_cluster, std::vector<db::InstElement> &rev_inst_path)
|
||||
|
|
@ -1077,7 +1077,7 @@ size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell
|
|||
return 0;
|
||||
}
|
||||
|
||||
db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Point &point)
|
||||
db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Point &point, std::vector<db::SubCircuit *> *sc_path_out, db::Circuit *initial_circuit)
|
||||
{
|
||||
if (! m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet")));
|
||||
|
|
@ -1089,6 +1089,14 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin
|
|||
|
||||
unsigned int layer = layer_of (of_region);
|
||||
|
||||
const db::Cell *top_cell = internal_top_cell ();
|
||||
if (initial_circuit && internal_layout ()->is_valid_cell_index (initial_circuit->cell_index ())) {
|
||||
top_cell = &internal_layout ()->cell (initial_circuit->cell_index ());
|
||||
}
|
||||
if (! top_cell) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Prepare a test cluster
|
||||
db::Box box (point - db::Vector (1, 1), point + db::Vector (1, 1));
|
||||
db::GenericRepository sr;
|
||||
|
|
@ -1097,7 +1105,7 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin
|
|||
|
||||
std::vector<db::InstElement> inst_path;
|
||||
|
||||
size_t cluster_id = search_net (db::ICplxTrans (), internal_top_cell (), test_cluster, inst_path);
|
||||
size_t cluster_id = search_net (db::ICplxTrans (), top_cell, test_cluster, inst_path);
|
||||
if (cluster_id > 0) {
|
||||
|
||||
// search_net delivers the path in reverse order
|
||||
|
|
@ -1105,7 +1113,7 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin
|
|||
|
||||
std::vector<db::cell_index_type> cell_indexes;
|
||||
cell_indexes.reserve (inst_path.size () + 1);
|
||||
cell_indexes.push_back (internal_top_cell ()->cell_index ());
|
||||
cell_indexes.push_back (top_cell->cell_index ());
|
||||
for (std::vector<db::InstElement>::const_iterator i = inst_path.begin (); i != inst_path.end (); ++i) {
|
||||
cell_indexes.push_back (i->inst_ptr.cell_index ());
|
||||
}
|
||||
|
|
@ -1142,38 +1150,57 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin
|
|||
|
||||
}
|
||||
|
||||
std::vector<db::SubCircuit *> sc_path;
|
||||
|
||||
db::Net *topmost_net = net;
|
||||
|
||||
// follow the path up in the net hierarchy using the transformation and the upper cell index as the
|
||||
// guide line
|
||||
while (! inst_path.empty () && net->pin_count () > 0) {
|
||||
while (circuit && ! inst_path.empty ()) {
|
||||
|
||||
cell_indexes.pop_back ();
|
||||
|
||||
const db::Pin *pin = circuit->pin_by_id (net->begin_pins ()->pin_id ());
|
||||
tl_assert (pin != 0);
|
||||
const db::Pin *pin = 0;
|
||||
if (net && net->pin_count () > 0) {
|
||||
pin = circuit->pin_by_id (net->begin_pins ()->pin_id ());
|
||||
tl_assert (pin != 0);
|
||||
}
|
||||
|
||||
db::DCplxTrans dtrans = dbu_trans * inst_path.back ().complex_trans () * dbu_trans_inv;
|
||||
|
||||
// try to find a parent circuit which connects to this net
|
||||
db::Circuit *upper_circuit = 0;
|
||||
db::SubCircuit *subcircuit = 0;
|
||||
db::Net *upper_net = 0;
|
||||
for (db::Circuit::refs_iterator r = circuit->begin_refs (); r != circuit->end_refs () && ! upper_net; ++r) {
|
||||
for (db::Circuit::refs_iterator r = circuit->begin_refs (); r != circuit->end_refs () && ! upper_circuit; ++r) {
|
||||
if (r->trans ().equal (dtrans) && r->circuit () && r->circuit ()->cell_index () == cell_indexes.back ()) {
|
||||
upper_net = r->net_for_pin (pin->id ());
|
||||
upper_circuit = r->circuit ();
|
||||
subcircuit = r.operator-> ();
|
||||
if (pin) {
|
||||
upper_net = subcircuit->net_for_pin (pin->id ());
|
||||
}
|
||||
upper_circuit = subcircuit->circuit ();
|
||||
}
|
||||
}
|
||||
|
||||
net = upper_net;
|
||||
|
||||
if (upper_net) {
|
||||
circuit = upper_circuit;
|
||||
net = upper_net;
|
||||
inst_path.pop_back ();
|
||||
topmost_net = upper_net;
|
||||
} else {
|
||||
break;
|
||||
sc_path.push_back (subcircuit);
|
||||
}
|
||||
|
||||
circuit = upper_circuit;
|
||||
inst_path.pop_back ();
|
||||
|
||||
}
|
||||
|
||||
return net;
|
||||
if (sc_path_out) {
|
||||
std::reverse (sc_path.begin (), sc_path.end ());
|
||||
*sc_path_out = sc_path;
|
||||
}
|
||||
|
||||
return topmost_net;
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -709,8 +709,11 @@ public:
|
|||
*
|
||||
* This variant accepts a micrometer-unit location. The location is given in the
|
||||
* coordinate space of the initial cell.
|
||||
*
|
||||
* The subcircuit path leading to the topmost net is stored in *sc_path_out if this
|
||||
* pointer is non-null.
|
||||
*/
|
||||
db::Net *probe_net (const db::Region &of_region, const db::DPoint &point);
|
||||
db::Net *probe_net (const db::Region &of_region, const db::DPoint &point, std::vector<SubCircuit *> *sc_path_out = 0, Circuit *initial_circuit = 0);
|
||||
|
||||
/**
|
||||
* @brief Finds the net by probing a specific location on the given layer
|
||||
|
|
@ -718,7 +721,7 @@ public:
|
|||
* This variant accepts a database-unit location. The location is given in the
|
||||
* coordinate space of the initial cell.
|
||||
*/
|
||||
db::Net *probe_net (const db::Region &of_region, const db::Point &point);
|
||||
db::Net *probe_net (const db::Region &of_region, const db::Point &point, std::vector<SubCircuit *> *sc_path_out = 0, Circuit *initial_circuit = 0);
|
||||
|
||||
/**
|
||||
* @brief Runs an antenna check on the extracted clusters
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ namespace tl
|
|||
*/
|
||||
template <> struct type_traits <db::Library> : public type_traits<void> {
|
||||
typedef tl::false_tag has_copy_constructor;
|
||||
typedef tl::false_tag has_public_destructor;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -265,6 +265,10 @@ void Netlist::unlock ()
|
|||
|
||||
const tl::vector<Circuit *> &Netlist::child_circuits (Circuit *circuit)
|
||||
{
|
||||
if (circuit->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Circuit not within given netlist")));
|
||||
}
|
||||
|
||||
if (! m_valid_topology) {
|
||||
validate_topology ();
|
||||
}
|
||||
|
|
@ -275,6 +279,10 @@ const tl::vector<Circuit *> &Netlist::child_circuits (Circuit *circuit)
|
|||
|
||||
const tl::vector<Circuit *> &Netlist::parent_circuits (Circuit *circuit)
|
||||
{
|
||||
if (circuit->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Circuit not within given netlist")));
|
||||
}
|
||||
|
||||
if (! m_valid_topology) {
|
||||
validate_topology ();
|
||||
}
|
||||
|
|
@ -364,18 +372,39 @@ void Netlist::clear ()
|
|||
|
||||
void Netlist::add_circuit (Circuit *circuit)
|
||||
{
|
||||
if (! circuit) {
|
||||
return;
|
||||
}
|
||||
if (circuit->netlist ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Circuit already contained in a netlist")));
|
||||
}
|
||||
|
||||
m_circuits.push_back (circuit);
|
||||
circuit->set_netlist (this);
|
||||
}
|
||||
|
||||
void Netlist::remove_circuit (Circuit *circuit)
|
||||
{
|
||||
if (! circuit) {
|
||||
return;
|
||||
}
|
||||
if (circuit->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Circuit not within given netlist")));
|
||||
}
|
||||
|
||||
circuit->set_netlist (0);
|
||||
m_circuits.erase (circuit);
|
||||
}
|
||||
|
||||
void Netlist::purge_circuit (Circuit *circuit)
|
||||
{
|
||||
if (! circuit) {
|
||||
return;
|
||||
}
|
||||
if (circuit->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Circuit not within given netlist")));
|
||||
}
|
||||
|
||||
circuit->blank ();
|
||||
remove_circuit (circuit);
|
||||
}
|
||||
|
|
@ -406,7 +435,12 @@ void Netlist::flatten_circuits (const std::vector<Circuit *> &circuits)
|
|||
|
||||
void Netlist::flatten_circuit (Circuit *circuit)
|
||||
{
|
||||
tl_assert (circuit != 0);
|
||||
if (! circuit) {
|
||||
return;
|
||||
}
|
||||
if (circuit->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Circuit not within given netlist")));
|
||||
}
|
||||
|
||||
std::vector<db::SubCircuit *> refs;
|
||||
for (db::Circuit::refs_iterator sc = circuit->begin_refs (); sc != circuit->end_refs (); ++sc) {
|
||||
|
|
@ -448,24 +482,52 @@ DeviceClass *Netlist::device_class_by_name (const std::string &name)
|
|||
|
||||
void Netlist::add_device_class (DeviceClass *device_class)
|
||||
{
|
||||
if (! device_class) {
|
||||
return;
|
||||
}
|
||||
if (device_class->netlist ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device class already contained in a netlist")));
|
||||
}
|
||||
|
||||
m_device_classes.push_back (device_class);
|
||||
device_class->set_netlist (this);
|
||||
}
|
||||
|
||||
void Netlist::remove_device_class (DeviceClass *device_class)
|
||||
{
|
||||
if (! device_class) {
|
||||
return;
|
||||
}
|
||||
if (device_class->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device class not within given netlist")));
|
||||
}
|
||||
|
||||
device_class->set_netlist (0);
|
||||
m_device_classes.erase (device_class);
|
||||
}
|
||||
|
||||
void Netlist::add_device_abstract (DeviceAbstract *device_abstract)
|
||||
{
|
||||
if (! device_abstract) {
|
||||
return;
|
||||
}
|
||||
if (device_abstract->netlist ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device abstract already contained in a netlist")));
|
||||
}
|
||||
|
||||
m_device_abstracts.push_back (device_abstract);
|
||||
device_abstract->set_netlist (this);
|
||||
}
|
||||
|
||||
void Netlist::remove_device_abstract (DeviceAbstract *device_abstract)
|
||||
{
|
||||
if (! device_abstract) {
|
||||
return;
|
||||
}
|
||||
if (device_abstract->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device abstract not within given netlist")));
|
||||
}
|
||||
|
||||
device_abstract->set_netlist (0);
|
||||
m_device_abstracts.erase (device_abstract);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -38,6 +38,8 @@ class DeviceCategorizer;
|
|||
class CircuitCategorizer;
|
||||
class CircuitMapper;
|
||||
class NetGraph;
|
||||
class SubCircuitEquivalenceTracker;
|
||||
class DeviceEquivalenceTracker;
|
||||
|
||||
/**
|
||||
* @brief A receiver for netlist compare events
|
||||
|
|
@ -285,6 +287,26 @@ public:
|
|||
return m_max_n_branch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a value indicating depth-first traversal
|
||||
*
|
||||
* With depth first (the default), the algorithm looks for further identities before moving to another
|
||||
* node. With breadth first (false), the algorithm will work in "waves" rather than digging deerly
|
||||
* into the direction of a node.
|
||||
*/
|
||||
void set_depth_first (bool df)
|
||||
{
|
||||
m_depth_first = df;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating depth-first traversal
|
||||
*/
|
||||
bool depth_first () const
|
||||
{
|
||||
return m_depth_first;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the list of circuits without matching circuit in the other netlist
|
||||
* The result can be used to flatten these circuits prior to compare.
|
||||
|
|
@ -326,8 +348,8 @@ protected:
|
|||
bool all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits) const;
|
||||
static void derive_pin_equivalence (const db::Circuit *ca, const db::Circuit *cb, CircuitPinMapper *circuit_pin_mapper);
|
||||
void do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const;
|
||||
void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, bool &good) const;
|
||||
void do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const db::CircuitPinMapper &circuit_pin_mapper, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, bool &good) const;
|
||||
void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, db::DeviceEquivalenceTracker &device_eq, bool &good) const;
|
||||
void do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const db::CircuitPinMapper &circuit_pin_mapper, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, db::SubCircuitEquivalenceTracker &subcircuit_eq, bool &good) const;
|
||||
bool handle_pin_mismatch (const NetGraph &g1, const db::Circuit *c1, const db::Pin *pin1, const NetGraph &g2, const db::Circuit *c2, const db::Pin *p2) const;
|
||||
|
||||
mutable NetlistCompareLogger *mp_logger;
|
||||
|
|
@ -339,6 +361,7 @@ protected:
|
|||
double m_res_threshold;
|
||||
size_t m_max_n_branch;
|
||||
size_t m_max_depth;
|
||||
bool m_depth_first;
|
||||
bool m_dont_consider_net_names;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,39 @@ NetlistCrossReference::per_circuit_data_for (const std::pair<const db::Circuit *
|
|||
return 0;
|
||||
}
|
||||
|
||||
const db::Pin *
|
||||
NetlistCrossReference::other_pin_for (const db::Pin *pin) const
|
||||
{
|
||||
std::map<const db::Pin *, const db::Pin *>::const_iterator i = m_other_pin.find (pin);
|
||||
if (i != m_other_pin.end ()) {
|
||||
return i->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const db::Device *
|
||||
NetlistCrossReference::other_device_for (const db::Device *device) const
|
||||
{
|
||||
std::map<const db::Device *, const db::Device *>::const_iterator i = m_other_device.find (device);
|
||||
if (i != m_other_device.end ()) {
|
||||
return i->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const db::SubCircuit *
|
||||
NetlistCrossReference::other_subcircuit_for (const db::SubCircuit *subcircuit) const
|
||||
{
|
||||
std::map<const db::SubCircuit *, const db::SubCircuit *>::const_iterator i = m_other_subcircuit.find (subcircuit);
|
||||
if (i != m_other_subcircuit.end ()) {
|
||||
return i->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const db::Circuit *
|
||||
NetlistCrossReference::other_circuit_for (const db::Circuit *circuit) const
|
||||
{
|
||||
|
|
@ -568,6 +601,16 @@ NetlistCrossReference::build_subcircuit_pin_refs (const std::pair<const db::Net
|
|||
|
||||
}
|
||||
|
||||
// Fallback for swappable pins: match based on the subcircuit alone
|
||||
if (! pb) {
|
||||
std::map<std::pair<const db::SubCircuit *, size_t>, const db::NetSubcircuitPinRef *>::iterator b = s2t_b.lower_bound (std::make_pair (sb, 0));
|
||||
if (b != s2t_b.end () && b->first.first == sb) {
|
||||
pb = b->second;
|
||||
// remove the entry so we won't find it again
|
||||
s2t_b.erase (b);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data.subcircuit_pins.push_back (std::make_pair (a->second, pb));
|
||||
|
|
|
|||
|
|
@ -256,6 +256,9 @@ public:
|
|||
return m_circuits.end ();
|
||||
}
|
||||
|
||||
const db::Pin *other_pin_for (const db::Pin *pin) const;
|
||||
const db::Device *other_device_for (const db::Device *device) const;
|
||||
const db::SubCircuit *other_subcircuit_for (const db::SubCircuit *subcircuit) const;
|
||||
const db::Circuit *other_circuit_for (const db::Circuit *circuit) const;
|
||||
const db::Net *other_net_for (const db::Net *net) const;
|
||||
const PerNetData *per_net_data_for (const std::pair<const db::Net *, const db::Net *> &nets) const;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "tlClassRegistry.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlExpression.h"
|
||||
#include "tlInternational.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -327,7 +328,7 @@ SaveLayoutOptions::get_valid_layers (const db::Layout &layout, std::vector <std:
|
|||
}
|
||||
|
||||
void
|
||||
SaveLayoutOptions::get_cells (const db::Layout &layout, std::set <db::cell_index_type> &cells, const std::vector <std::pair <unsigned int, db::LayerProperties> > &valid_layers) const
|
||||
SaveLayoutOptions::get_cells (const db::Layout &layout, std::set <db::cell_index_type> &cells, const std::vector <std::pair <unsigned int, db::LayerProperties> > &valid_layers, bool require_unique_names) const
|
||||
{
|
||||
if (m_all_cells) {
|
||||
|
||||
|
|
@ -408,6 +409,26 @@ SaveLayoutOptions::get_cells (const db::Layout &layout, std::set <db::cell_index
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
if (require_unique_names) {
|
||||
|
||||
std::map<std::string, unsigned int> use_count;
|
||||
for (std::set <db::cell_index_type>::const_iterator c = cells.begin (); c != cells.end (); ++c) {
|
||||
use_count.insert (std::make_pair (std::string (layout.cell_name (*c)), 0)).first->second += 1;
|
||||
}
|
||||
|
||||
std::vector<std::string> multi;
|
||||
for (std::map<std::string, unsigned int>::const_iterator u = use_count.begin (); u != use_count.end (); ++u) {
|
||||
if (u->second > 1) {
|
||||
multi.push_back (u->first);
|
||||
}
|
||||
}
|
||||
|
||||
if (! multi.empty ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("The following cell name(s) are used for more than one cell - can't write this layout:\n ")) + tl::join (multi, "\n "));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -413,7 +413,7 @@ public:
|
|||
*
|
||||
* It must be given a list of valid layers which is used to determine empty cells if dont_save_empty_cells is true.
|
||||
*/
|
||||
void get_cells (const db::Layout &layout, std::set <db::cell_index_type> &cells, const std::vector <std::pair <unsigned int, db::LayerProperties> > &valid_layers) const;
|
||||
void get_cells (const db::Layout &layout, std::set <db::cell_index_type> &cells, const std::vector <std::pair <unsigned int, db::LayerProperties> > &valid_layers, bool require_unique_names = true) const;
|
||||
|
||||
/**
|
||||
* @brief Sets a layout reader option by name
|
||||
|
|
|
|||
|
|
@ -546,9 +546,13 @@ ShapeIterator::advance_aref (int &mode)
|
|||
|
||||
if (mode && m_array_iterator_valid) {
|
||||
|
||||
if (mode > 0) {
|
||||
if (mode == 1) {
|
||||
array_iterator *arr_iter = (array_iterator *) m_ad.iter;
|
||||
++*arr_iter;
|
||||
} else if (mode == 2) {
|
||||
// skip array quad -> skip rest of array quad and move to shape in the next quad or to end
|
||||
do_skip_array_quad ();
|
||||
mode = 1;
|
||||
} else {
|
||||
// skip quad -> skip rest of array and move to next shape array
|
||||
skip_array (); // sets m_array_iterator_valid = false
|
||||
|
|
@ -810,9 +814,100 @@ ShapeIterator::quad_box () const
|
|||
return quad_box_generic<OverlappingRegionTag, db::unstable_layer_tag> ();
|
||||
}
|
||||
}
|
||||
|
||||
return db::Box ();
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
void
|
||||
ShapeIterator::do_skip_array_quad_iter ()
|
||||
{
|
||||
Iter *arr_iter = (Iter *) m_ad.iter;
|
||||
arr_iter->skip_quad ();
|
||||
}
|
||||
|
||||
void
|
||||
ShapeIterator::do_skip_array_quad ()
|
||||
{
|
||||
if (m_array_iterator_valid) {
|
||||
if (m_type == PolygonPtrArray) {
|
||||
do_skip_array_quad_iter<polygon_ptr_array_iterator_type> ();
|
||||
} else if (m_type == SimplePolygonPtrArray) {
|
||||
do_skip_array_quad_iter<simple_polygon_ptr_array_iterator_type> ();
|
||||
} else if (m_type == PathPtrArray) {
|
||||
do_skip_array_quad_iter<path_ptr_array_iterator_type> ();
|
||||
} else if (m_type == TextPtrArray) {
|
||||
do_skip_array_quad_iter<text_ptr_array_iterator_type> ();
|
||||
} else if (m_type == BoxArray) {
|
||||
do_skip_array_quad_iter<box_array_iterator_type> ();
|
||||
} else if (m_type == ShortBoxArray) {
|
||||
do_skip_array_quad_iter<short_box_array_iterator_type> ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
size_t
|
||||
ShapeIterator::get_array_quad_id () const
|
||||
{
|
||||
Iter *arr_iter = (Iter *) m_ad.iter;
|
||||
return arr_iter->quad_id ();
|
||||
}
|
||||
|
||||
size_t
|
||||
ShapeIterator::array_quad_id () const
|
||||
{
|
||||
if (m_array_iterator_valid) {
|
||||
if (m_type == PolygonPtrArray) {
|
||||
return get_array_quad_id<polygon_ptr_array_iterator_type> ();
|
||||
} else if (m_type == SimplePolygonPtrArray) {
|
||||
return get_array_quad_id<simple_polygon_ptr_array_iterator_type> ();
|
||||
} else if (m_type == PathPtrArray) {
|
||||
return get_array_quad_id<path_ptr_array_iterator_type> ();
|
||||
} else if (m_type == TextPtrArray) {
|
||||
return get_array_quad_id<text_ptr_array_iterator_type> ();
|
||||
} else if (m_type == BoxArray) {
|
||||
return get_array_quad_id<box_array_iterator_type> ();
|
||||
} else if (m_type == ShortBoxArray) {
|
||||
return get_array_quad_id<short_box_array_iterator_type> ();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Iter, class Array>
|
||||
db::Box
|
||||
ShapeIterator::get_array_quad_box () const
|
||||
{
|
||||
const Array *arr = m_array.basic_ptr (typename Array::tag ());
|
||||
Iter *arr_iter = (Iter *) m_ad.iter;
|
||||
db::box_convert<typename Array::object_type> bc;
|
||||
return arr->quad_box (*arr_iter, bc);
|
||||
}
|
||||
|
||||
db::Box
|
||||
ShapeIterator::array_quad_box () const
|
||||
{
|
||||
if (m_array_iterator_valid) {
|
||||
if (m_type == PolygonPtrArray) {
|
||||
return get_array_quad_box<polygon_ptr_array_iterator_type, polygon_ptr_array_type> ();
|
||||
} else if (m_type == SimplePolygonPtrArray) {
|
||||
return get_array_quad_box<simple_polygon_ptr_array_iterator_type, simple_polygon_ptr_array_type> ();
|
||||
} else if (m_type == PathPtrArray) {
|
||||
return get_array_quad_box<path_ptr_array_iterator_type, path_ptr_array_type> ();
|
||||
} else if (m_type == TextPtrArray) {
|
||||
return get_array_quad_box<text_ptr_array_iterator_type, text_ptr_array_type> ();
|
||||
} else if (m_type == BoxArray) {
|
||||
return get_array_quad_box<box_array_iterator_type, box_array_type> ();
|
||||
} else if (m_type == ShortBoxArray) {
|
||||
return get_array_quad_box<short_box_array_iterator_type, short_box_array_type> ();
|
||||
}
|
||||
}
|
||||
|
||||
return db::Box::world ();
|
||||
}
|
||||
|
||||
void
|
||||
ShapeIterator::cleanup ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -319,6 +319,33 @@ public:
|
|||
advance (-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the arrays quad ID
|
||||
*
|
||||
* The arrays quad ID is a unique identifier for the current quad for iterated arrays. This can be used to
|
||||
* detect whether the iterator entered a new quad and optimize the search in that case.
|
||||
*/
|
||||
size_t array_quad_id () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the quad box
|
||||
*
|
||||
* Gets the box the current quad uses. This box may be larger than the actual shape containers
|
||||
* bounding box. Specifically if there is no quad tree at all, this box is the world box.
|
||||
*/
|
||||
db::Box array_quad_box () const;
|
||||
|
||||
/**
|
||||
* @brief Skips the current quad
|
||||
*
|
||||
* Moves to the next quad. This method can be used to shortcut searching if we are inside
|
||||
* a quad that is not relevant for the search.
|
||||
*/
|
||||
void skip_array_quad ()
|
||||
{
|
||||
advance (2);
|
||||
}
|
||||
|
||||
private:
|
||||
// a helper union for the iter_size union
|
||||
// (basically computing the size required for all iterators for a certain shape/array type)
|
||||
|
|
@ -418,6 +445,12 @@ private:
|
|||
template <class Sh, class StableTag> db::Box quad_box_by_shape (OverlappingRegionTag) const;
|
||||
template <class RegionTag, class StableTag> db::Box quad_box_generic () const;
|
||||
|
||||
template <class Iter, class Array> db::Box get_array_quad_box () const;
|
||||
template <class Iter> size_t get_array_quad_id () const;
|
||||
|
||||
template <class Iter> void do_skip_array_quad_iter ();
|
||||
void do_skip_array_quad ();
|
||||
|
||||
template <class Sh, class StableTag, class RegionTag> bool advance_shape (int &mode);
|
||||
template <class Array> void init_array_iter (NoRegionTag);
|
||||
template <class Array> void init_array_iter (TouchingRegionTag);
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ LayerMap::prepare (db::Layout &layout)
|
|||
|
||||
// In addition, map other existing layers as well, so merging of layout is somewhat better supported
|
||||
for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) {
|
||||
if (mapped_layers.find ((*l).first) == mapped_layers.end ()) {
|
||||
if (! (*l).second->is_null () && mapped_layers.find ((*l).first) == mapped_layers.end ()) {
|
||||
map (*(*l).second, (*l).first);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,6 +119,17 @@ const Net *SubCircuit::net_for_pin (size_t pin_id) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
const NetSubcircuitPinRef *SubCircuit::netref_for_pin (size_t pin_id) const
|
||||
{
|
||||
if (pin_id < m_pin_refs.size ()) {
|
||||
Net::subcircuit_pin_iterator p = m_pin_refs [pin_id];
|
||||
if (p != Net::subcircuit_pin_iterator ()) {
|
||||
return p.operator-> ();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SubCircuit::connect_pin (size_t pin_id, Net *net)
|
||||
{
|
||||
if (net_for_pin (pin_id) == net) {
|
||||
|
|
|
|||
|
|
@ -171,6 +171,21 @@ public:
|
|||
return const_cast<Net *> (((const SubCircuit *) this)->net_for_pin (pin_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the net attached to a specific pin as a subcircuit pin ref object
|
||||
* Returns 0 if no net is attached.
|
||||
*/
|
||||
const NetSubcircuitPinRef *netref_for_pin (size_t pin_id) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the net attached to a specific pin as a subcircuit pin ref object (non-const version)
|
||||
* Returns 0 if no net is attached.
|
||||
*/
|
||||
NetSubcircuitPinRef *netref_for_pin (size_t pin_id)
|
||||
{
|
||||
return const_cast<NetSubcircuitPinRef *> (((const SubCircuit *) this)->netref_for_pin (pin_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects the given pin to the given net
|
||||
* If the net is 0 the pin is disconnected.
|
||||
|
|
|
|||
|
|
@ -198,43 +198,52 @@ TextWriter::write (const db::Layout &layout)
|
|||
|
||||
for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) {
|
||||
|
||||
std::string pfx = "";
|
||||
|
||||
if (inst->has_prop_id () && inst->prop_id () != 0) {
|
||||
pfx = "p $props";
|
||||
write_props (layout, inst->prop_id ());
|
||||
}
|
||||
|
||||
db::Vector a, b;
|
||||
unsigned long amax, bmax;
|
||||
|
||||
bool is_reg = inst->is_regular_array (a, b, amax, bmax);
|
||||
|
||||
*this << (is_reg ? "aref" : "sref") << pfx << " {" << layout.cell_name (inst->cell_index ()) << "}";
|
||||
for (db::CellInstArray::iterator i = inst->begin (); ! i.at_end (); ++i) {
|
||||
|
||||
db::Trans t = inst->front ();
|
||||
std::string pfx = "";
|
||||
|
||||
if (inst->has_prop_id () && inst->prop_id () != 0) {
|
||||
pfx = "p $props";
|
||||
write_props (layout, inst->prop_id ());
|
||||
}
|
||||
|
||||
*this << (is_reg ? "aref" : "sref") << pfx << " {" << layout.cell_name (inst->cell_index ()) << "}";
|
||||
|
||||
db::Trans t = *i;
|
||||
|
||||
if (inst->is_complex ()) {
|
||||
db::CellInstArray::complex_trans_type ct = inst->complex_trans (t);
|
||||
*this << " " << ct.angle ();
|
||||
*this << " " << (ct.is_mirror () ? 1 : 0);
|
||||
*this << " " << ct.mag ();
|
||||
} else {
|
||||
*this << " " << (t.rot () % 4) * 90.0;
|
||||
*this << " " << (t.is_mirror () ? 1 : 0);
|
||||
*this << " " << 1.0;
|
||||
}
|
||||
|
||||
if (is_reg) {
|
||||
*this << " " << int (std::max ((unsigned long) 1, amax));
|
||||
*this << " " << int (std::max ((unsigned long) 1, bmax));
|
||||
}
|
||||
*this << " " << t.disp ();
|
||||
if (is_reg) {
|
||||
*this << " " << (t.disp () + a * (long) amax);
|
||||
*this << " " << (t.disp () + b * (long) bmax);
|
||||
}
|
||||
*this << endl ();
|
||||
|
||||
if (is_reg) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (inst->is_complex ()) {
|
||||
*this << " " << inst->complex_trans ().angle ();
|
||||
*this << " " << (inst->complex_trans ().is_mirror () ? 1 : 0);
|
||||
*this << " " << inst->complex_trans ().mag ();
|
||||
} else {
|
||||
*this << " " << (t.rot () % 4) * 90.0;
|
||||
*this << " " << (t.is_mirror () ? 1 : 0);
|
||||
*this << " " << 1.0;
|
||||
}
|
||||
|
||||
if (is_reg) {
|
||||
*this << " " << int (std::max ((unsigned long) 1, amax));
|
||||
*this << " " << int (std::max ((unsigned long) 1, bmax));
|
||||
}
|
||||
*this << " " << t.disp ();
|
||||
if (is_reg) {
|
||||
*this << " " << (t.disp () + a * (long) amax);
|
||||
*this << " " << (t.disp () + b * (long) bmax);
|
||||
}
|
||||
*this << endl ();
|
||||
|
||||
}
|
||||
|
||||
end_sorted_section ();
|
||||
|
|
|
|||
|
|
@ -251,6 +251,8 @@ struct cell_inst_array_defs
|
|||
unsigned long na = 1, nb = 1;
|
||||
if (arr->is_regular_array (a, b, na, nb)) {
|
||||
*arr = C (arr->object (), t, a, b, na, nb);
|
||||
} else if (arr->is_iterated_array ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Can't set the transformation on an iterated array (layout not editable?)")));
|
||||
} else {
|
||||
*arr = C (arr->object (), t);
|
||||
}
|
||||
|
|
@ -262,6 +264,8 @@ struct cell_inst_array_defs
|
|||
unsigned long na = 1, nb = 1;
|
||||
if (arr->is_regular_array (a, b, na, nb)) {
|
||||
*arr = C (arr->object (), t, a, b, na, nb);
|
||||
} else if (arr->is_iterated_array ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Can't set the transformation on an iterated array (layout not editable?)")));
|
||||
} else {
|
||||
*arr = C (arr->object (), t);
|
||||
}
|
||||
|
|
@ -292,6 +296,8 @@ struct cell_inst_array_defs
|
|||
s += "*";
|
||||
s += tl::to_string (nb);
|
||||
s += "]";
|
||||
} else if (arr->size () > 1) {
|
||||
s += std::string (" (+") + tl::to_string (arr->size () - 1) + " irregular locations)";
|
||||
}
|
||||
|
||||
return s;
|
||||
|
|
@ -303,14 +309,27 @@ struct cell_inst_array_defs
|
|||
{
|
||||
typedef db::array<db::CellInst, db::simple_trans<typename T::target_coord_type> > target_array;
|
||||
|
||||
std::vector<typename C::vector_type> iterated;
|
||||
std::vector<typename target_array::vector_type> iterated_transformed;
|
||||
typename C::vector_type a, b;
|
||||
unsigned long amax = 0, bmax = 0;
|
||||
|
||||
if (arr.is_regular_array (a, b, amax, bmax)) {
|
||||
if (arr.is_complex ()) {
|
||||
return target_array (arr.object (), t * arr.complex_trans () * t.inverted (), t * a, t * b, amax, bmax);
|
||||
} else {
|
||||
return target_array (arr.object (), typename target_array::trans_type (t * typename C::complex_trans_type (arr.front ()) * t.inverted ()), t * a, t * b, amax, bmax);
|
||||
}
|
||||
} else if (arr.is_iterated_array (&iterated)) {
|
||||
iterated_transformed.reserve (iterated.size ());
|
||||
for (typename std::vector<typename C::vector_type>::const_iterator i = iterated.begin (); i != iterated.end (); ++i) {
|
||||
iterated_transformed.push_back (t * *i);
|
||||
}
|
||||
if (arr.is_complex ()) {
|
||||
return target_array (arr.object (), t * arr.complex_trans () * t.inverted (), iterated_transformed.begin (), iterated_transformed.end ());
|
||||
} else {
|
||||
return target_array (arr.object (), typename target_array::trans_type (t * typename C::complex_trans_type (arr.front ()) * t.inverted ()), iterated_transformed.begin (), iterated_transformed.end ());
|
||||
}
|
||||
} else if (arr.is_complex ()) {
|
||||
return target_array (arr.object (), t * arr.complex_trans () * t.inverted ());
|
||||
} else {
|
||||
|
|
@ -352,93 +371,17 @@ struct cell_inst_array_defs
|
|||
|
||||
static bool less (const C *i, const C &other)
|
||||
{
|
||||
if (i->object ().cell_index () != other.object ().cell_index ()) {
|
||||
return i->object ().cell_index () < other.object ().cell_index ();
|
||||
}
|
||||
|
||||
db::vector<coord_type> a, b;
|
||||
unsigned long na = 1, nb = 1;
|
||||
bool r = i->is_regular_array (a, b, na, nb);
|
||||
|
||||
db::vector<coord_type> aother, bother;
|
||||
unsigned long naother = 1, nbother = 1;
|
||||
bool rother = other.is_regular_array (aother, bother, naother, nbother);
|
||||
|
||||
if (r != rother) {
|
||||
return r < rother;
|
||||
} else if (r) {
|
||||
if (a.not_equal (aother)) {
|
||||
return a.less (aother);
|
||||
}
|
||||
if (b.not_equal (bother)) {
|
||||
return b.less (bother);
|
||||
}
|
||||
if (na != naother) {
|
||||
return na < naother;
|
||||
}
|
||||
if (nb != nbother) {
|
||||
return nb < nbother;
|
||||
}
|
||||
}
|
||||
|
||||
bool c = i->is_complex ();
|
||||
bool cother = other.is_complex ();
|
||||
|
||||
if (c != cother) {
|
||||
return c < cother;
|
||||
} else if (c) {
|
||||
return i->complex_trans ().less (other.complex_trans ());
|
||||
} else {
|
||||
return i->front ().less (other.front ());
|
||||
}
|
||||
return i->less (other);
|
||||
}
|
||||
|
||||
static bool equal (const C *i, const C &other)
|
||||
{
|
||||
if (i->object ().cell_index () != other.object ().cell_index ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
db::vector<coord_type> a, b;
|
||||
unsigned long na = 1, nb = 1;
|
||||
bool r = i->is_regular_array (a, b, na, nb);
|
||||
|
||||
db::vector<coord_type> aother, bother;
|
||||
unsigned long naother = 1, nbother = 1;
|
||||
bool rother = other.is_regular_array (aother, bother, naother, nbother);
|
||||
|
||||
if (r != rother) {
|
||||
return false;
|
||||
} else if (r) {
|
||||
if (a.not_equal (aother)) {
|
||||
return false;
|
||||
}
|
||||
if (b.not_equal (bother)) {
|
||||
return false;
|
||||
}
|
||||
if (na != naother) {
|
||||
return false;
|
||||
}
|
||||
if (nb != nbother) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool c = i->is_complex ();
|
||||
bool cother = other.is_complex ();
|
||||
|
||||
if (c != cother) {
|
||||
return false;
|
||||
} else if (c) {
|
||||
return i->complex_trans ().equal (other.complex_trans ());
|
||||
} else {
|
||||
return i->front ().equal (other.front ());
|
||||
}
|
||||
return i->equal (other);
|
||||
}
|
||||
|
||||
static bool not_equal (const C *i, const C &other)
|
||||
{
|
||||
return ! equal (i, other);
|
||||
return ! i->equal (other);
|
||||
}
|
||||
|
||||
static gsi::Methods methods (bool new_doc)
|
||||
|
|
@ -508,7 +451,9 @@ struct cell_inst_array_defs
|
|||
) +
|
||||
gsi::method ("size", &C::size,
|
||||
"@brief Gets the number of single instances in the array\n"
|
||||
"If the instance represents a single instance, the count is 1. Otherwise it is na*nb."
|
||||
"If the instance represents a single instance, the count is 1. Otherwise it is na*nb. "
|
||||
"Starting with version 0.27, there may be iterated instances for which the size is larger than 1, but \\is_regular_array? will return false. "
|
||||
"In this case, use \\each_trans or \\each_cplx_trans to retrieve the individual placements of the iterated instance."
|
||||
) +
|
||||
gsi::method_ext ("cell_index", &cell_index,
|
||||
"@brief Gets the cell index of the cell instantiated \n"
|
||||
|
|
@ -1618,6 +1563,28 @@ static db::Instance cell_inst_dtransform_into_cplx (db::Cell *cell, const db::In
|
|||
return cell->transform_into (inst, dbu_trans.inverted () * t * dbu_trans);
|
||||
}
|
||||
|
||||
static void cell_dtransform_simple (db::Cell *cell, const db::DTrans &t)
|
||||
{
|
||||
const db::Layout *layout = cell->layout ();
|
||||
if (! layout) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer-unit transformation")));
|
||||
}
|
||||
|
||||
db::CplxTrans dbu_trans (layout->dbu ());
|
||||
cell->transform (db::Trans (dbu_trans.inverted () * db::DCplxTrans (t) * dbu_trans));
|
||||
}
|
||||
|
||||
static void cell_dtransform_cplx (db::Cell *cell, const db::DCplxTrans &t)
|
||||
{
|
||||
const db::Layout *layout = cell->layout ();
|
||||
if (! layout) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer-unit transformation")));
|
||||
}
|
||||
|
||||
db::CplxTrans dbu_trans (layout->dbu ());
|
||||
cell->transform (dbu_trans.inverted () * t * dbu_trans);
|
||||
}
|
||||
|
||||
static void cell_dtransform_into_simple (db::Cell *cell, const db::DTrans &t)
|
||||
{
|
||||
const db::Layout *layout = cell->layout ();
|
||||
|
|
@ -2402,6 +2369,46 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"\n"
|
||||
"This variant has been introduced in version 0.25."
|
||||
) +
|
||||
gsi::method ("transform", (void (db::Cell::*)(const db::Trans &)) &db::Cell::transform, gsi::arg ("trans"),
|
||||
"@brief Transforms the cell by the given integer transformation\n"
|
||||
"\n"
|
||||
"This method transforms all instances and all shapes by the given transformation. "
|
||||
"There is a variant called \\transform_into which applies the transformation to instances "
|
||||
"in a way such that it can be applied recursively to the child cells.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.7."
|
||||
) +
|
||||
gsi::method ("transform", (void (db::Cell::*)(const db::ICplxTrans &)) &db::Cell::transform, gsi::arg ("trans"),
|
||||
"@brief Transforms the cell by the given complex integer transformation\n"
|
||||
"\n"
|
||||
"This method transforms all instances and all shapes by the given transformation. "
|
||||
"There is a variant called \\transform_into which applies the transformation to instances "
|
||||
"in a way such that it can be applied recursively to the child cells. The difference is important in "
|
||||
"the presence of magnifications: \"transform\" will leave magnified instances while \"transform_into\" "
|
||||
"will not do so but expect the magnification to be applied inside the called cells too.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.7."
|
||||
) +
|
||||
gsi::method_ext ("transform", &cell_dtransform_simple, gsi::arg ("trans"),
|
||||
"@brief Transforms the cell by the given, micrometer-unit transformation\n"
|
||||
"\n"
|
||||
"This method transforms all instances and all shapes by the given transformation. "
|
||||
"There is a variant called \\transform_into which applies the transformation to instances "
|
||||
"in a way such that it can be applied recursively to the child cells.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.7."
|
||||
) +
|
||||
gsi::method_ext ("transform", &cell_dtransform_cplx, gsi::arg ("trans"),
|
||||
"@brief Transforms the cell by the given, micrometer-unit transformation\n"
|
||||
"\n"
|
||||
"This method transforms all instances and all shapes by the given transformation. "
|
||||
"There is a variant called \\transform_into which applies the transformation to instances "
|
||||
"in a way such that it can be applied recursively to the child cells. The difference is important in "
|
||||
"the presence of magnifications: \"transform\" will leave magnified instances while \"transform_into\" "
|
||||
"will not do so but expect the magnification to be applied inside the called cells too.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.7."
|
||||
) +
|
||||
gsi::method_ext ("transform_into", &cell_dtransform_into_simple, gsi::arg ("trans"),
|
||||
"@brief Transforms the cell into a new coordinate system with the given transformation where the transformation is in micrometer units\n"
|
||||
"This method is identical to the corresponding \\transform_into method with a \\Trans argument. For this variant "
|
||||
|
|
|
|||
|
|
@ -543,7 +543,7 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
gsi::method_ext ("build_nets", &build_nets, gsi::arg ("nets"), gsi::arg ("cmap"), gsi::arg ("target"), gsi::arg ("lmap"), gsi::arg ("net_cell_name_prefix", tl::Variant (), "nil"), gsi::arg ("netname_prop", tl::Variant (), "nil"), gsi::arg ("hier_mode", db::LayoutToNetlist::BNH_Flatten, "BNH_Flatten"), gsi::arg ("circuit_cell_name_prefix", tl::Variant (), "nil"), gsi::arg ("device_cell_name_prefix", tl::Variant (), "nil"),
|
||||
"@brief Like \\build_all_nets, but with the ability to select some nets."
|
||||
) +
|
||||
gsi::method ("probe_net", (db::Net *(db::LayoutToNetlist::*) (const db::Region &, const db::DPoint &)) &db::LayoutToNetlist::probe_net, gsi::arg ("of_layer"), gsi::arg ("point"),
|
||||
gsi::method ("probe_net", (db::Net *(db::LayoutToNetlist::*) (const db::Region &, const db::DPoint &, std::vector<db::SubCircuit *> *, db::Circuit *)) &db::LayoutToNetlist::probe_net, gsi::arg ("of_layer"), gsi::arg ("point"), gsi::arg ("sc_path_out", (std::vector<db::SubCircuit *> *) 0, "nil"), gsi::arg ("initial_circuit", (db::Circuit *) 0, "nil"),
|
||||
"@brief Finds the net by probing a specific location on the given layer\n"
|
||||
"\n"
|
||||
"This method will find a net looking at the given layer at the specific position.\n"
|
||||
|
|
@ -551,20 +551,30 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"in the specified location. The function will report the topmost net from far above the\n"
|
||||
"hierarchy of circuits as possible.\n"
|
||||
"\n"
|
||||
"If \\initial_circuit is given, the probing will start from this circuit and from the "
|
||||
"cell this circuit represents. By default, the probing will start from the top circuit.\n"
|
||||
"\n"
|
||||
"If no net is found at all, 0 is returned.\n"
|
||||
"\n"
|
||||
"It is recommended to use \\probe on the netlist right after extraction.\n"
|
||||
"It is recommended to use \\probe_net on the netlist right after extraction.\n"
|
||||
"Optimization functions such as \\Netlist#purge will remove parts of the net which means\n"
|
||||
"shape to net probing may no longer work for these nets.\n"
|
||||
"\n"
|
||||
"If non-null and an array, 'sc_path_out' will receive a list of \\SubCircuits objects which lead to the "
|
||||
"net from the top circuit of the database.\n"
|
||||
"\n"
|
||||
"This variant accepts a micrometer-unit location. The location is given in the\n"
|
||||
"coordinate space of the initial cell.\n"
|
||||
"\n"
|
||||
"The \\sc_path_out and \\initial_circuit parameters have been added in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("probe_net", (db::Net *(db::LayoutToNetlist::*) (const db::Region &, const db::Point &)) &db::LayoutToNetlist::probe_net, gsi::arg ("of_layer"), gsi::arg ("point"),
|
||||
gsi::method ("probe_net", (db::Net *(db::LayoutToNetlist::*) (const db::Region &, const db::Point &, std::vector<db::SubCircuit *> *, db::Circuit *)) &db::LayoutToNetlist::probe_net, gsi::arg ("of_layer"), gsi::arg ("point"), gsi::arg ("sc_path_out", (std::vector<db::SubCircuit *> *) 0, "nil"), gsi::arg ("initial_circuit", (db::Circuit *) 0, "nil"),
|
||||
"@brief Finds the net by probing a specific location on the given layer\n"
|
||||
"See the description of the other \\probe_net variant.\n"
|
||||
"This variant accepts a database-unit location. The location is given in the\n"
|
||||
"coordinate space of the initial cell.\n"
|
||||
"\n"
|
||||
"The \\sc_path_out and \\initial_circuit parameters have been added in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("write|write_l2n", &db::LayoutToNetlist::save, gsi::arg ("path"), gsi::arg ("short_format", false),
|
||||
"@brief Writes the extracted netlist to a file.\n"
|
||||
|
|
|
|||
|
|
@ -78,7 +78,18 @@ static std::string get_technology (db::Library *lib)
|
|||
}
|
||||
}
|
||||
|
||||
static void dummy_destroy (db::Library *) { }
|
||||
|
||||
Class<db::Library> decl_Library ("db", "Library",
|
||||
gsi::method_ext ("_destroy", &dummy_destroy,
|
||||
"@brief An inactive substitute for _destroy (delete the object)\n"
|
||||
"As libraries need to be kept if cells are using them, library objects must "
|
||||
"not be deleted. Hence the default '_destroy' implementation must not be called. "
|
||||
"To keep old code working, this substitute is provided. It just returns without "
|
||||
"deleting the object.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.7."
|
||||
) +
|
||||
gsi::constructor ("new", &new_lib,
|
||||
"@brief Creates a new, empty library"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -466,6 +466,21 @@ Class<db::SubCircuit> decl_dbSubCircuit (decl_dbNetlistObject, "db", "SubCircuit
|
|||
gsi::method_ext ("disconnect_pin", &gsi::subcircuit_disconnect_pin1, gsi::arg ("pin"),
|
||||
"@brief Disconnects the given pin from any net.\n"
|
||||
"This version takes a \\Pin reference instead of a pin ID."
|
||||
) +
|
||||
gsi::method ("trans", &db::SubCircuit::trans,
|
||||
"@brief Gets the physical transformation for the subcircuit.\n"
|
||||
"\n"
|
||||
"This property applies to subcircuits derived from a layout. It specifies the "
|
||||
"placement of the respective cell.\n"
|
||||
"\n"
|
||||
"This property has been introduced in version 0.27."
|
||||
) +
|
||||
gsi::method ("trans=", &db::SubCircuit::set_trans, gsi::arg ("trans"),
|
||||
"@brief Sets the physical transformation for the subcircuit.\n"
|
||||
"\n"
|
||||
"See \\trans for details about this property.\n"
|
||||
"\n"
|
||||
"This property has been introduced in version 0.27."
|
||||
),
|
||||
"@brief A subcircuit inside a circuit.\n"
|
||||
"Circuits may instantiate other circuits as subcircuits similar to cells "
|
||||
|
|
|
|||
|
|
@ -538,6 +538,18 @@ Class<db::NetlistComparer> decl_dbNetlistComparer ("db", "NetlistComparer",
|
|||
"@brief Gets the maximum branch complexity\n"
|
||||
"See \\max_branch_complexity= for details."
|
||||
) +
|
||||
gsi::method ("dont_consider_net_names=", &db::NetlistComparer::set_dont_consider_net_names, gsi::arg ("f"),
|
||||
"@brief Sets a value indicating whether net names shall not be considered\n"
|
||||
"If this value is set to true, net names will not be considered when resolving ambiguities.\n"
|
||||
"Not considering net names usually is more expensive. The default is 'false' indicating that\n"
|
||||
"net names will be considered for ambiguity resolution.\n"
|
||||
"\n"
|
||||
"This property has been introduced in version 0.26.7.\n"
|
||||
) +
|
||||
gsi::method ("dont_consider_net_names", &db::NetlistComparer::dont_consider_net_names,
|
||||
"@brief Gets a value indicating whether net names shall not be considered\n"
|
||||
"See \\dont_consider_net_names= for details."
|
||||
) +
|
||||
gsi::method_ext ("unmatched_circuits_a", &unmatched_circuits_a, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief Returns a list of circuits in A for which there is not corresponding circuit in B\n"
|
||||
"This list can be used to flatten these circuits so they do not participate in the compare process.\n"
|
||||
|
|
|
|||
|
|
@ -403,6 +403,34 @@ Class<db::NetlistCrossReference> decl_dbNetlistCrossReference (decl_dbNetlistCom
|
|||
"The return value will be nil if no match is found. "
|
||||
"Otherwise it is the 'b' net for nets from the 'a' netlist and vice versa."
|
||||
) +
|
||||
gsi::method ("other_circuit_for", &db::NetlistCrossReference::other_circuit_for, gsi::arg ("circuit"),
|
||||
"@brief Gets the matching other circuit for a given primary circuit.\n"
|
||||
"The return value will be nil if no match is found. "
|
||||
"Otherwise it is the 'b' circuit for circuits from the 'a' netlist and vice versa."
|
||||
"\n\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("other_device_for", &db::NetlistCrossReference::other_device_for, gsi::arg ("device"),
|
||||
"@brief Gets the matching other device for a given primary device.\n"
|
||||
"The return value will be nil if no match is found. "
|
||||
"Otherwise it is the 'b' device for devices from the 'a' netlist and vice versa."
|
||||
"\n\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("other_pin_for", &db::NetlistCrossReference::other_pin_for, gsi::arg ("pin"),
|
||||
"@brief Gets the matching other pin for a given primary pin.\n"
|
||||
"The return value will be nil if no match is found. "
|
||||
"Otherwise it is the 'b' pin for pins from the 'a' netlist and vice versa."
|
||||
"\n\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("other_subcircuit_for", &db::NetlistCrossReference::other_subcircuit_for, gsi::arg ("subcircuit"),
|
||||
"@brief Gets the matching other subcircuit for a given primary subcircuit.\n"
|
||||
"The return value will be nil if no match is found. "
|
||||
"Otherwise it is the 'b' subcircuit for subcircuits from the 'a' netlist and vice versa."
|
||||
"\n\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("clear", &db::NetlistCrossReference::clear,
|
||||
"@hide\n"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -1031,4 +1031,92 @@ TEST(6U)
|
|||
|
||||
}
|
||||
|
||||
TEST(7)
|
||||
{
|
||||
Box2Box conv;
|
||||
TestTree t;
|
||||
|
||||
int n = 200000;
|
||||
|
||||
for (int i = n - 1; i >= 0; --i) {
|
||||
t.insert (db::Box (i * 10, 0, i * 10 + 5, 5));
|
||||
}
|
||||
t.sort (conv);
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("test 7 lookup");
|
||||
size_t n = 0;
|
||||
for (unsigned int i = 0; i < 2000; ++i) {
|
||||
db::Coord sx = 0, sy = 0;
|
||||
TestTree::touching_iterator it = t.begin_touching (db::Box (db::Point (2000, 0), db::Point (3000, 0)), conv);
|
||||
while (!it.at_end ()) {
|
||||
sx += abs (it->left ());
|
||||
sy += abs (it->bottom ());
|
||||
++it;
|
||||
++n;
|
||||
}
|
||||
EXPECT_EQ (sx, 252500);
|
||||
EXPECT_EQ (sy, 0);
|
||||
}
|
||||
EXPECT_EQ (n, size_t (101 * 2000));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("test 7 traverse");
|
||||
db::Coord m = std::numeric_limits<db::Coord>::max ();
|
||||
size_t n = 0;
|
||||
for (unsigned int i = 0; i < 10; ++i) {
|
||||
TestTree::touching_iterator it = t.begin_touching (db::Box (db::Point (-m,-m), db::Point (m, m)), conv);
|
||||
while (!it.at_end ()) {
|
||||
++it;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ (n, t.size () * 10);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(7U)
|
||||
{
|
||||
Box2Box conv;
|
||||
UnstableTestTree t;
|
||||
|
||||
int n = 200000;
|
||||
|
||||
for (int i = n - 1; i >= 0; --i) {
|
||||
t.insert (db::Box (i * 10, 0, i * 10 + 5, 5));
|
||||
}
|
||||
t.sort (conv);
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("test 7U lookup");
|
||||
size_t n = 0;
|
||||
for (unsigned int i = 0; i < 2000; ++i) {
|
||||
db::Coord sx = 0, sy = 0;
|
||||
UnstableTestTree::touching_iterator it = t.begin_touching (db::Box (db::Point (2000, 0), db::Point (3000, 0)), conv);
|
||||
while (!it.at_end ()) {
|
||||
sx += abs (it->left ());
|
||||
sy += abs (it->bottom ());
|
||||
++it;
|
||||
++n;
|
||||
}
|
||||
EXPECT_EQ (sx, 252500);
|
||||
EXPECT_EQ (sy, 0);
|
||||
}
|
||||
EXPECT_EQ (n, size_t (101 * 2000));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("test 7U traverse");
|
||||
db::Coord m = std::numeric_limits<db::Coord>::max ();
|
||||
size_t n = 0;
|
||||
for (unsigned int i = 0; i < 10; ++i) {
|
||||
UnstableTestTree::touching_iterator it = t.begin_touching (db::Box (db::Point (-m,-m), db::Point (m, m)), conv);
|
||||
while (!it.at_end ()) {
|
||||
++it;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ (n, t.size () * 10);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -722,6 +722,14 @@ TEST(3a)
|
|||
c0.transform_into (db::ICplxTrans (ti));
|
||||
inst = *c0.begin ();
|
||||
EXPECT_EQ (inst.to_string (), "cell_index=1 m90 -334,0");
|
||||
|
||||
c0.transform (db::Trans (5));
|
||||
inst = *c0.begin ();
|
||||
EXPECT_EQ (inst.to_string (), "cell_index=1 r270 0,-334");
|
||||
|
||||
c0.transform (db::ICplxTrans (ti));
|
||||
inst = *c0.begin ();
|
||||
EXPECT_EQ (inst.to_string (), "cell_index=1 r315 *2.5 600,-570");
|
||||
}
|
||||
|
||||
TEST(3b)
|
||||
|
|
@ -791,6 +799,73 @@ TEST(3b)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(3c)
|
||||
{
|
||||
::pi = 0;
|
||||
|
||||
db::Manager m (true);
|
||||
db::Layout g (&m);
|
||||
db::Cell &c0 (g.cell (g.add_cell ()));
|
||||
db::Cell &c1 (g.cell (g.add_cell ()));
|
||||
|
||||
db::Trans t (db::Vector (100, -100));
|
||||
c0.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (c1.cell_index ()), t), 5));
|
||||
|
||||
db::Box b (0, 100, 1000, 1200);
|
||||
c0.shapes (0).insert (db::BoxWithProperties (b, 17));
|
||||
c1.shapes (1).insert (b);
|
||||
|
||||
// Note: this requires editable mode since db::Shapes::erase is permitted in editable mode only
|
||||
// (erase is triggered by undo)
|
||||
if (db::default_editable_mode ()) {
|
||||
|
||||
m.transaction ("t");
|
||||
c0.transform (db::ICplxTrans (2.5));
|
||||
m.commit ();
|
||||
|
||||
EXPECT_EQ (c1.cell_instances (), size_t (0));
|
||||
EXPECT_EQ (c0.cell_instances (), size_t (1));
|
||||
EXPECT_EQ (c0.begin ()->to_string (), "cell_index=1 r0 *2.5 250,-250 prop_id=5");
|
||||
|
||||
EXPECT_EQ (c0.shapes (0).size (), size_t (1));
|
||||
EXPECT_EQ (c0.shapes (1).size (), size_t (0));
|
||||
EXPECT_EQ (c1.shapes (0).size (), size_t (0));
|
||||
EXPECT_EQ (c1.shapes (1).size (), size_t (1));
|
||||
|
||||
EXPECT_EQ (c0.shapes (0).begin (db::ShapeIterator::All)->to_string (), "box (0,250;2500,3000) prop_id=17");
|
||||
EXPECT_EQ (c1.shapes (1).begin (db::ShapeIterator::All)->to_string (), "box (0,100;1000,1200)");
|
||||
|
||||
m.undo ();
|
||||
|
||||
EXPECT_EQ (c1.cell_instances (), size_t (0));
|
||||
EXPECT_EQ (c0.cell_instances (), size_t (1));
|
||||
EXPECT_EQ (c0.begin ()->to_string (), "cell_index=1 r0 100,-100 prop_id=5");
|
||||
|
||||
EXPECT_EQ (c0.shapes (0).size (), size_t (1));
|
||||
EXPECT_EQ (c0.shapes (1).size (), size_t (0));
|
||||
EXPECT_EQ (c1.shapes (0).size (), size_t (0));
|
||||
EXPECT_EQ (c1.shapes (1).size (), size_t (1));
|
||||
|
||||
EXPECT_EQ (c0.shapes (0).begin (db::ShapeIterator::All)->to_string (), "box (0,100;1000,1200) prop_id=17");
|
||||
EXPECT_EQ (c1.shapes (1).begin (db::ShapeIterator::All)->to_string (), "box (0,100;1000,1200)");
|
||||
|
||||
m.redo ();
|
||||
|
||||
EXPECT_EQ (c1.cell_instances (), size_t (0));
|
||||
EXPECT_EQ (c0.cell_instances (), size_t (1));
|
||||
EXPECT_EQ (c0.begin ()->to_string (), "cell_index=1 r0 *2.5 250,-250 prop_id=5");
|
||||
|
||||
EXPECT_EQ (c0.shapes (0).size (), size_t (1));
|
||||
EXPECT_EQ (c0.shapes (1).size (), size_t (0));
|
||||
EXPECT_EQ (c1.shapes (0).size (), size_t (0));
|
||||
EXPECT_EQ (c1.shapes (1).size (), size_t (1));
|
||||
|
||||
EXPECT_EQ (c0.shapes (0).begin (db::ShapeIterator::All)->to_string (), "box (0,250;2500,3000) prop_id=17");
|
||||
EXPECT_EQ (c1.shapes (1).begin (db::ShapeIterator::All)->to_string (), "box (0,100;1000,1200)");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct map1
|
||||
{
|
||||
db::cell_index_type operator() (db::cell_index_type i) const { return 3-i; }
|
||||
|
|
|
|||
|
|
@ -1287,3 +1287,69 @@ TEST(120_HierClustersCombArrays)
|
|||
run_hc_test (_this, "comb2.gds", "comb2_au1.gds");
|
||||
run_hc_test_with_backannotation (_this, "comb2.gds", "comb2_au2.gds");
|
||||
}
|
||||
|
||||
static size_t root_nets (const db::connected_clusters<db::PolygonRef> &cc)
|
||||
{
|
||||
size_t n = 0;
|
||||
for (db::connected_clusters<db::PolygonRef>::all_iterator c = cc.begin_all (); !c.at_end (); ++c) {
|
||||
if (cc.is_root (*c)) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// issue #609
|
||||
TEST(200_issue609)
|
||||
{
|
||||
db::Layout ly;
|
||||
unsigned int l1 = 0, l2 = 0;
|
||||
|
||||
{
|
||||
db::LayerProperties p;
|
||||
db::LayerMap lmap;
|
||||
|
||||
p.layer = 1;
|
||||
p.datatype = 0;
|
||||
lmap.map (db::LDPair (p.layer, p.datatype), l1 = ly.insert_layer ());
|
||||
ly.set_properties (l1, p);
|
||||
|
||||
p.layer = 2;
|
||||
p.datatype = 0;
|
||||
lmap.map (db::LDPair (p.layer, p.datatype), l2 = ly.insert_layer ());
|
||||
ly.set_properties (l2, p);
|
||||
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
|
||||
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
|
||||
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/issue-609.oas.gz";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly, options);
|
||||
}
|
||||
|
||||
std::vector<std::string> strings;
|
||||
normalize_layer (ly, strings, l1);
|
||||
normalize_layer (ly, strings, l2);
|
||||
|
||||
// connect 1 to 1, 1 to 2
|
||||
db::Connectivity conn;
|
||||
conn.connect (l1, l1);
|
||||
conn.connect (l2, l2);
|
||||
conn.connect (l1, l2);
|
||||
|
||||
db::hier_clusters<db::PolygonRef> hc;
|
||||
hc.build (ly, ly.cell (*ly.begin_top_down ()), conn);
|
||||
|
||||
db::Layout::top_down_const_iterator td = ly.begin_top_down ();
|
||||
EXPECT_EQ (td != ly.end_top_down (), true);
|
||||
EXPECT_EQ (root_nets (hc.clusters_per_cell (*td)), size_t (1));
|
||||
++td;
|
||||
|
||||
// result needs to be a single net
|
||||
for ( ; td != ly.end_top_down (); ++td) {
|
||||
EXPECT_EQ (root_nets (hc.clusters_per_cell (*td)), size_t (0));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ TestDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperties &
|
|||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
m_os << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]";
|
||||
} else if (ci.size () > 1) {
|
||||
m_os << " (+" << (ci.size () - 1) << " irregular placements)";
|
||||
}
|
||||
if (ci.properties_id () != 0) {
|
||||
m_os << " [" << ci.properties_id () << "]" << std::endl;
|
||||
|
|
@ -112,6 +114,8 @@ TestDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperties &
|
|||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
m_os << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]";
|
||||
} else if (ci.size () > 1) {
|
||||
m_os << " (+" << (ci.size () - 1) << " irregular placements)";
|
||||
}
|
||||
if (ci.properties_id () != 0) {
|
||||
m_os << " [" << ci.properties_id () << "]" << std::endl;
|
||||
|
|
|
|||
|
|
@ -449,6 +449,7 @@ TEST(1_SimpleInverter)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -470,6 +471,7 @@ TEST(1_SimpleInverter)
|
|||
|
||||
db::NetlistCrossReference xref;
|
||||
db::NetlistComparer comp_xref (&xref);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
good = comp_xref.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -519,6 +521,7 @@ TEST(1_SimpleInverterMatchedDeviceClasses)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
comp.same_device_classes (nl1.device_class_by_name ("PMOS"), nl2.device_class_by_name ("PMOSB"));
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
|
@ -571,6 +574,7 @@ TEST(1_SimpleInverterSkippedDevices)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -594,6 +598,7 @@ TEST(1_SimpleInverterSkippedDevices)
|
|||
|
||||
db::NetlistCrossReference xref;
|
||||
db::NetlistComparer comp_xref (&xref);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
good = comp_xref.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -751,6 +756,8 @@ TEST(2_SimpleInverterWithForcedNetAssignment)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
const db::Circuit *ca = nl1.circuit_by_name ("INV");
|
||||
const db::Circuit *cb = nl2.circuit_by_name ("INV");
|
||||
comp.same_nets (ca->net_by_name ("VDD"), cb->net_by_name ("VDD"));
|
||||
|
|
@ -797,6 +804,7 @@ TEST(3_Buffer)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -852,6 +860,7 @@ TEST(4_BufferTwoPaths)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -912,6 +921,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
// Forcing the power nets into equality makes the parameter error harder to detect
|
||||
const db::Circuit *ca = nl1.circuit_by_name ("BUF");
|
||||
|
|
@ -1134,6 +1144,7 @@ TEST(5_BufferTwoPathsDifferentDeviceClasses)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
// NOTE: adding this power hint makes the device class error harder to detect
|
||||
const db::Circuit *ca = nl1.circuit_by_name ("BUF");
|
||||
|
|
@ -1147,8 +1158,8 @@ TEST(5_BufferTwoPathsDifferentDeviceClasses)
|
|||
"begin_circuit BUF BUF\n"
|
||||
"match_nets INT $10\n"
|
||||
"match_nets IN IN\n"
|
||||
"net_mismatch OUT OUT\n"
|
||||
"net_mismatch INT2 $11\n"
|
||||
"net_mismatch OUT OUT\n"
|
||||
"match_pins $0 $1\n"
|
||||
"match_pins $1 $3\n"
|
||||
"match_pins $2 $0\n"
|
||||
|
|
@ -1199,6 +1210,7 @@ TEST(6_BufferTwoPathsAdditionalResistor)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
// Forcing the power nets into equality makes the resistor error harder to detect
|
||||
const db::Circuit *ca = nl1.circuit_by_name ("BUF");
|
||||
|
|
@ -1212,8 +1224,35 @@ TEST(6_BufferTwoPathsAdditionalResistor)
|
|||
"begin_circuit BUF BUF\n"
|
||||
"net_mismatch INT $10\n"
|
||||
"match_nets IN IN\n"
|
||||
"net_mismatch INT2 $11\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_pins $0 $1\n"
|
||||
"match_pins $1 $3\n"
|
||||
"match_pins $2 $0\n"
|
||||
"match_pins $3 $2\n"
|
||||
"match_devices $1 $1\n"
|
||||
"match_devices $3 $2\n"
|
||||
"match_devices $5 $3\n"
|
||||
"match_devices $7 $4\n"
|
||||
"match_devices $2 $5\n"
|
||||
"match_devices $4 $6\n"
|
||||
"match_devices $6 $7\n"
|
||||
"match_devices $8 $8\n"
|
||||
"device_mismatch (null) $9\n"
|
||||
"end_circuit BUF BUF NOMATCH"
|
||||
);
|
||||
EXPECT_EQ (good, false);
|
||||
|
||||
comp.set_depth_first (false);
|
||||
logger.clear ();
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
"begin_circuit BUF BUF\n"
|
||||
"net_mismatch INT $10\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"net_mismatch INT2 $11\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_pins $0 $1\n"
|
||||
"match_pins $1 $3\n"
|
||||
"match_pins $2 $0\n"
|
||||
|
|
@ -1266,6 +1305,7 @@ TEST(6_BufferTwoPathsAdditionalDevices)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -1274,9 +1314,9 @@ TEST(6_BufferTwoPathsAdditionalDevices)
|
|||
"match_nets INT $11\n"
|
||||
"net_mismatch VDD VDD\n"
|
||||
"match_nets IN IN\n"
|
||||
"net_mismatch INT2 $10\n"
|
||||
"net_mismatch VSS VSS\n"
|
||||
"net_mismatch OUT OUT\n"
|
||||
"net_mismatch INT2 $10\n"
|
||||
"match_pins $0 $1\n"
|
||||
"match_pins $1 $3\n"
|
||||
"match_pins $2 $0\n"
|
||||
|
|
@ -1318,6 +1358,7 @@ TEST(7_Resistors)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -1359,6 +1400,7 @@ TEST(7_ResistorsParameterMismatch)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -1401,6 +1443,7 @@ TEST(7_ResistorsPlusOneDevice)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -1443,6 +1486,7 @@ TEST(8_Diodes)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -1484,6 +1528,7 @@ TEST(8_DiodesDontMatchOnSwappedPins)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -1531,6 +1576,7 @@ TEST(10_SimpleSubCircuits)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -1593,6 +1639,7 @@ TEST(10_SimpleSubCircuitsMatchedNames)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
EXPECT_EQ (good, false);
|
||||
|
|
@ -1761,22 +1808,22 @@ TEST(11_MismatchingSubcircuits)
|
|||
// nets are now ambiguous
|
||||
EXPECT_EQ (xref2s (xref),
|
||||
"TOP:TOP [Match]:\n"
|
||||
" pin $0:$0 [Match]\n"
|
||||
" pin $1:$1 [Match]\n"
|
||||
" pin $2:$2 [Match]\n"
|
||||
" pin $0:$2 [Match]\n"
|
||||
" pin $1:$0 [Match]\n"
|
||||
" pin $2:$1 [Match]\n"
|
||||
" pin $3:$3 [Match]\n"
|
||||
" net IN:OUT [MatchWithWarning]\n"
|
||||
" pin $0:$0\n"
|
||||
" subcircuit_pin (null):$1[$3]\n"
|
||||
" net IN:IN [MatchWithWarning]\n"
|
||||
" pin $0:$2\n"
|
||||
" subcircuit_pin (null):$2[$1]\n"
|
||||
" subcircuit_pin $1[$0]:(null)\n"
|
||||
" net OUT:VDD [MatchWithWarning]\n"
|
||||
" pin $1:$1\n"
|
||||
" net OUT:OUT [MatchWithWarning]\n"
|
||||
" pin $1:$0\n"
|
||||
" subcircuit_pin (null):$1[$3]\n"
|
||||
" subcircuit_pin $2[$1]:(null)\n"
|
||||
" net VDD:VDD [MatchWithWarning]\n"
|
||||
" pin $2:$1\n"
|
||||
" subcircuit_pin (null):$1[$0]\n"
|
||||
" subcircuit_pin (null):$2[$0]\n"
|
||||
" subcircuit_pin $2[$1]:(null)\n"
|
||||
" net VDD:IN [MatchWithWarning]\n"
|
||||
" pin $2:$2\n"
|
||||
" subcircuit_pin (null):$2[$1]\n"
|
||||
" subcircuit_pin $1[$2]:(null)\n"
|
||||
" subcircuit_pin $2[$2]:(null)\n"
|
||||
" net VSS:VSS [MatchWithWarning]\n"
|
||||
|
|
@ -1818,6 +1865,7 @@ TEST(12_MismatchingSubcircuitsDuplicates)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -1885,6 +1933,7 @@ TEST(13_MismatchingSubcircuitsAdditionalHierarchy)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -1952,6 +2001,7 @@ TEST(14_Subcircuit2Nand)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
comp.equivalent_pins (nl2.circuit_by_name ("NAND"), 0, 1);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
|
@ -2026,6 +2076,7 @@ TEST(14_Subcircuit2NandMismatchNoSwap)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
// intentionally missing: comp.equivalent_pins (nl2.circuit_by_name ("NAND"), 0, 1);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
|
@ -2116,17 +2167,14 @@ TEST(14_Subcircuit2NandMismatchNoSwap)
|
|||
" pin $4:$4 [Match]\n"
|
||||
" net IN1:INT [Mismatch]\n"
|
||||
" pin $0:(null)\n"
|
||||
" subcircuit_pin (null):$2[$2]\n"
|
||||
" subcircuit_pin $1[$0]:(null)\n"
|
||||
" subcircuit_pin $1[$0]:$2[$2]\n"
|
||||
" subcircuit_pin $2[$0]:$1[$0]\n"
|
||||
" net IN2:IN2 [Mismatch]\n"
|
||||
" pin $1:$1\n"
|
||||
" subcircuit_pin (null):$2[$0]\n"
|
||||
" subcircuit_pin $1[$1]:(null)\n"
|
||||
" subcircuit_pin $1[$1]:$2[$0]\n"
|
||||
" net INT:IN1 [Mismatch]\n"
|
||||
" pin (null):$0\n"
|
||||
" subcircuit_pin (null):$2[$1]\n"
|
||||
" subcircuit_pin $1[$2]:(null)\n"
|
||||
" subcircuit_pin $1[$2]:$2[$1]\n"
|
||||
" subcircuit_pin $2[$1]:$1[$1]\n"
|
||||
" net OUT:OUT [Match]\n"
|
||||
" pin $2:$2\n"
|
||||
|
|
@ -2177,6 +2225,7 @@ TEST(14_Subcircuit2MatchWithSwap)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
comp.equivalent_pins (nl2.circuit_by_name ("NAND"), 0, 1);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
|
@ -2256,6 +2305,7 @@ TEST(15_EmptySubCircuitTest)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -2331,6 +2381,7 @@ TEST(15_EmptySubCircuitWithoutPinNames)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -2413,6 +2464,7 @@ TEST(16_UniqueSubCircuitMatching)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -2552,8 +2604,8 @@ TEST(17_InherentlyAmbiguousDecoder)
|
|||
"match_ambiguous_nets NQ1 NQ1\n"
|
||||
"match_ambiguous_nets NQ2 NQ2\n"
|
||||
"match_nets NQ3 NQ3\n"
|
||||
"match_ambiguous_nets NA NA\n"
|
||||
"match_ambiguous_nets NB NB\n"
|
||||
"match_nets NA NA\n"
|
||||
"match_nets NB NB\n"
|
||||
"match_nets B B\n"
|
||||
"match_nets A A\n"
|
||||
"match_pins $0 $1\n"
|
||||
|
|
@ -2657,10 +2709,61 @@ TEST(17_InherentlyAmbiguousDecoder)
|
|||
"match_nets B B\n"
|
||||
"match_nets NB NB\n"
|
||||
"match_nets NA NA\n"
|
||||
"match_nets NQ0 NQ0\n"
|
||||
"match_nets NQ2 NQ2\n"
|
||||
"match_nets NQ1 NQ1\n"
|
||||
"match_nets NQ3 NQ3\n"
|
||||
"match_nets NQ2 NQ2\n"
|
||||
"match_nets NQ0 NQ0\n"
|
||||
"match_pins $0 $1\n"
|
||||
"match_pins $1 $0\n"
|
||||
"match_pins $2 $2\n"
|
||||
"match_pins $3 $3\n"
|
||||
"match_pins $4 $4\n"
|
||||
"match_pins $5 $5\n"
|
||||
"match_pins $6 $6\n"
|
||||
"match_pins $7 $7\n"
|
||||
"match_subcircuits $1 $1\n"
|
||||
"match_subcircuits $2 $2\n"
|
||||
"match_subcircuits $4 $3\n"
|
||||
"match_subcircuits $6 $4\n"
|
||||
"match_subcircuits $3 $5\n"
|
||||
"match_subcircuits $5 $6\n"
|
||||
"end_circuit DECODER DECODER MATCH"
|
||||
);
|
||||
|
||||
EXPECT_EQ (good, true);
|
||||
|
||||
comp.set_depth_first (false);
|
||||
logger.clear ();
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
"begin_circuit NAND NAND\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets INT INT\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets B B\n"
|
||||
"match_nets A A\n"
|
||||
"match_pins $0 $0\n"
|
||||
"match_pins $1 $1\n"
|
||||
"match_pins $2 $2\n"
|
||||
"match_pins $3 $3\n"
|
||||
"match_pins $4 $4\n"
|
||||
"match_devices $1 $1\n"
|
||||
"match_devices $2 $2\n"
|
||||
"match_devices $3 $3\n"
|
||||
"match_devices $4 $4\n"
|
||||
"end_circuit NAND NAND MATCH\n"
|
||||
"begin_circuit DECODER DECODER\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets NA NA\n"
|
||||
"match_nets NB NB\n"
|
||||
"match_nets B B\n"
|
||||
"match_nets NQ1 NQ1\n"
|
||||
"match_nets NQ3 NQ3\n"
|
||||
"match_nets NQ2 NQ2\n"
|
||||
"match_nets NQ0 NQ0\n"
|
||||
"match_pins $0 $1\n"
|
||||
"match_pins $1 $0\n"
|
||||
"match_pins $2 $2\n"
|
||||
|
|
@ -2735,6 +2838,7 @@ TEST(18_ClockTree)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (false);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -2744,6 +2848,190 @@ TEST(18_ClockTree)
|
|||
txt = tl::replaced (txt, "L", "X");
|
||||
txt = tl::replaced (txt, "R", "X");
|
||||
|
||||
EXPECT_EQ (txt,
|
||||
"begin_circuit INV INV\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_pins IN IN\n"
|
||||
"match_pins OUT OUT\n"
|
||||
"match_pins VDD VDD\n"
|
||||
"match_pins VSS VSS\n"
|
||||
"match_devices $1 $1\n"
|
||||
"match_devices $2 $2\n"
|
||||
"end_circuit INV INV MATCH\n"
|
||||
"begin_circuit TXEE TXEE\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets S S\n"
|
||||
"match_nets SX SX\n"
|
||||
"match_nets SX SX\n"
|
||||
"match_nets SXX SXX\n"
|
||||
"match_nets SXX SXX\n"
|
||||
"match_nets SXXX SXXX\n"
|
||||
"match_nets SXXX SXXX\n"
|
||||
"match_nets SXXX SXXX\n"
|
||||
"match_nets SXXX SXXX\n"
|
||||
"match_nets SXX SXX\n"
|
||||
"match_nets SXX SXX\n"
|
||||
"match_nets SXXX SXXX\n"
|
||||
"match_nets SXXX SXXX\n"
|
||||
"match_nets SXXX SXXX\n"
|
||||
"match_nets SXXX SXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TX TX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits T T\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TX TX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"end_circuit TXEE TXEE MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
|
||||
logger.clear ();
|
||||
|
||||
comp.set_dont_consider_net_names (true);
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
txt = logger.text ();
|
||||
// because L/R matching is ambiguous, we need to do this to
|
||||
// establish reproducability on different platforms:
|
||||
txt = tl::replaced (txt, "L", "X");
|
||||
txt = tl::replaced (txt, "R", "X");
|
||||
|
||||
EXPECT_EQ (txt,
|
||||
"begin_circuit INV INV\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_pins IN IN\n"
|
||||
"match_pins OUT OUT\n"
|
||||
"match_pins VDD VDD\n"
|
||||
"match_pins VSS VSS\n"
|
||||
"match_devices $1 $1\n"
|
||||
"match_devices $2 $2\n"
|
||||
"end_circuit INV INV MATCH\n"
|
||||
"begin_circuit TXEE TXEE\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets S S\n"
|
||||
"match_ambiguous_nets SX SX\n"
|
||||
"match_ambiguous_nets SX SX\n"
|
||||
"match_ambiguous_nets SXX SXX\n"
|
||||
"match_ambiguous_nets SXX SXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXX SXX\n"
|
||||
"match_ambiguous_nets SXX SXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TX TX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits T T\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TX TX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"end_circuit TXEE TXEE MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
|
||||
comp.set_depth_first (false);
|
||||
logger.clear ();
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
txt = logger.text ();
|
||||
// because L/R matching is ambiguous, we need to do this to
|
||||
// establish reproducability on different platforms:
|
||||
txt = tl::replaced (txt, "L", "X");
|
||||
txt = tl::replaced (txt, "R", "X");
|
||||
|
||||
EXPECT_EQ (txt,
|
||||
"begin_circuit INV INV\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_pins IN IN\n"
|
||||
"match_pins OUT OUT\n"
|
||||
"match_pins VDD VDD\n"
|
||||
"match_pins VSS VSS\n"
|
||||
"match_devices $1 $1\n"
|
||||
"match_devices $2 $2\n"
|
||||
"end_circuit INV INV MATCH\n"
|
||||
"begin_circuit TXEE TXEE\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets S S\n"
|
||||
"match_ambiguous_nets SX SX\n"
|
||||
"match_ambiguous_nets SX SX\n"
|
||||
"match_ambiguous_nets SXX SXX\n"
|
||||
"match_ambiguous_nets SXX SXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXX SXX\n"
|
||||
"match_ambiguous_nets SXX SXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_ambiguous_nets SXXX SXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TX TX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits T T\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TX TX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"match_subcircuits TXXX TXXX\n"
|
||||
"match_subcircuits TXX TXX\n"
|
||||
"end_circuit TXEE TXEE MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
|
||||
comp.set_depth_first (false);
|
||||
logger.clear ();
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
txt = logger.text ();
|
||||
// because L/R matching is ambiguous, we need to do this to
|
||||
// establish reproducability on different platforms:
|
||||
txt = tl::replaced (txt, "L", "X");
|
||||
txt = tl::replaced (txt, "R", "X");
|
||||
|
||||
EXPECT_EQ (txt,
|
||||
"begin_circuit INV INV\n"
|
||||
"match_nets VDD VDD\n"
|
||||
|
|
@ -2903,6 +3191,7 @@ TEST(19_SymmetricCircuit)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -2922,24 +3211,123 @@ TEST(19_SymmetricCircuit)
|
|||
"match_nets g1 G1\n"
|
||||
"match_nets $44 YI\n"
|
||||
"match_nets $14 WELL\n"
|
||||
"match_nets $8 NET215\n"
|
||||
"match_nets $9 NET175\n"
|
||||
"match_nets $6 NET181\n"
|
||||
"match_nets $4 NET200\n"
|
||||
"match_nets nn1 NN1\n"
|
||||
"match_ambiguous_nets nn2 NN2\n"
|
||||
"match_ambiguous_nets nn2_ NN2_\n"
|
||||
"match_ambiguous_nets q0 Q0\n"
|
||||
"match_ambiguous_nets q1 Q1\n"
|
||||
"match_nets $11 CS0\n"
|
||||
"match_nets $13 CS1\n"
|
||||
"match_nets nn2 NN2\n"
|
||||
"match_nets nn2_ NN2_\n"
|
||||
"match_nets q0 Q0\n"
|
||||
"match_nets q1 Q1\n"
|
||||
"match_nets q0_ Q0_\n"
|
||||
"match_nets $6 NET181\n"
|
||||
"match_nets nn1 NN1\n"
|
||||
"match_nets $8 NET215\n"
|
||||
"match_nets $13 CS1\n"
|
||||
"match_nets q1_ Q1_\n"
|
||||
"match_nets a0_ A0_\n"
|
||||
"match_nets $34 HNET48\n"
|
||||
"match_nets nn1_ NN1_\n"
|
||||
"match_nets a0 A0\n"
|
||||
"match_nets $35 HNET44\n"
|
||||
"match_nets nn1_ NN1_\n"
|
||||
"match_nets $9 NET175\n"
|
||||
"match_nets $4 NET200\n"
|
||||
"match_nets a0_ A0_\n"
|
||||
"match_nets $34 HNET48\n"
|
||||
"match_pins VDD VDD\n"
|
||||
"match_pins nn1_ NN1_\n"
|
||||
"match_pins nn1 NN1\n"
|
||||
"match_pins q0 Q0\n"
|
||||
"match_pins q0_ Q0_\n"
|
||||
"match_pins q1_ Q1_\n"
|
||||
"match_pins q1 Q1\n"
|
||||
"match_pins nn2 NN2\n"
|
||||
"match_pins nn2_ NN2_\n"
|
||||
"match_pins a0 A0\n"
|
||||
"match_pins a0_ A0_\n"
|
||||
"match_pins g1 G1\n"
|
||||
"match_pins g0 G0\n"
|
||||
"match_pins gtp NN3\n"
|
||||
"match_pins VSS VSS\n"
|
||||
"match_pins WELL WELL\n"
|
||||
"match_devices $30 0\n"
|
||||
"match_devices $29 1\n"
|
||||
"match_devices $9 10\n"
|
||||
"match_devices $10 11\n"
|
||||
"match_devices $36 12\n"
|
||||
"match_devices $35 13\n"
|
||||
"match_devices $34 14\n"
|
||||
"match_devices $38 15\n"
|
||||
"match_devices $37 16\n"
|
||||
"match_devices $33 17\n"
|
||||
"match_devices $27 18\n"
|
||||
"match_devices $28 19\n"
|
||||
"match_devices $17 2\n"
|
||||
"match_devices $31 20\n"
|
||||
"match_devices $32 21\n"
|
||||
"match_devices $22 22\n"
|
||||
"match_devices $26 23\n"
|
||||
"match_devices $23 24\n"
|
||||
"match_devices $43 25\n"
|
||||
"match_devices $20 26\n"
|
||||
"match_devices $25 27\n"
|
||||
"match_devices $15 28\n"
|
||||
"match_devices $14 29\n"
|
||||
"match_devices $16 3\n"
|
||||
"match_devices $18 30\n"
|
||||
"match_devices $21 31\n"
|
||||
"match_devices $13 32\n"
|
||||
"match_devices $19 33\n"
|
||||
"match_devices $7 34\n"
|
||||
"match_devices $8 35\n"
|
||||
"match_devices $24 36\n"
|
||||
"match_devices $3 37\n"
|
||||
"match_devices $6 38\n"
|
||||
"match_devices $4 39\n"
|
||||
"match_devices $39 4\n"
|
||||
"match_devices $5 40\n"
|
||||
"match_devices $2 41\n"
|
||||
"match_devices $1 42\n"
|
||||
"match_devices $40 5\n"
|
||||
"match_devices $11 6\n"
|
||||
"match_devices $12 7\n"
|
||||
"match_devices $41 8\n"
|
||||
"match_devices $42 9\n"
|
||||
"end_circuit DECODE DECODE MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
|
||||
comp.set_depth_first (false);
|
||||
logger.clear ();
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
"begin_circuit DECODE DECODE\n"
|
||||
"match_nets $41 WL1_EN_\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets $39 NET194\n"
|
||||
"match_nets g0 G0\n"
|
||||
"match_nets $40 HNET52\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets $42 NET189\n"
|
||||
"match_nets gtp NN3\n"
|
||||
"match_nets $37 NET193\n"
|
||||
"match_nets g1 G1\n"
|
||||
"match_nets $44 YI\n"
|
||||
"match_nets $14 WELL\n"
|
||||
"match_ambiguous_nets nn2 NN2\n"
|
||||
"match_ambiguous_nets nn2_ NN2_\n"
|
||||
"match_ambiguous_nets q0 Q0\n"
|
||||
"match_ambiguous_nets q1 Q1\n"
|
||||
"match_nets $11 CS0\n"
|
||||
"match_nets q0_ Q0_\n"
|
||||
"match_nets $4 NET200\n"
|
||||
"match_nets $13 CS1\n"
|
||||
"match_nets q1_ Q1_\n"
|
||||
"match_nets $9 NET175\n"
|
||||
"match_nets a0 A0\n"
|
||||
"match_nets a0_ A0_\n"
|
||||
"match_nets $35 HNET44\n"
|
||||
"match_nets $34 HNET48\n"
|
||||
"match_nets $6 NET181\n"
|
||||
"match_nets $8 NET215\n"
|
||||
"match_nets nn1 NN1\n"
|
||||
"match_nets nn1_ NN1_\n"
|
||||
"match_pins VDD VDD\n"
|
||||
"match_pins nn1_ NN1_\n"
|
||||
"match_pins nn1 NN1\n"
|
||||
|
|
@ -3060,6 +3448,7 @@ TEST(20_BusLikeConnections)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -3204,6 +3593,153 @@ TEST(20_BusLikeConnections)
|
|||
"end_circuit TOP TOP MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
|
||||
logger.clear ();
|
||||
|
||||
comp.set_dont_consider_net_names (false);
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
txt = logger.text ();
|
||||
|
||||
EXPECT_EQ (txt,
|
||||
"begin_circuit INV INV\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets OUT OUT\n"
|
||||
"match_nets IN IN\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_pins IN IN\n"
|
||||
"match_pins OUT OUT\n"
|
||||
"match_pins VDD VDD\n"
|
||||
"match_pins VSS VSS\n"
|
||||
"match_devices $1 $1\n"
|
||||
"match_devices $2 $2\n"
|
||||
"end_circuit INV INV MATCH\n"
|
||||
"begin_circuit INV8 INV8\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_ambiguous_nets IN1 A1\n"
|
||||
"match_ambiguous_nets IN2 A2\n"
|
||||
"match_ambiguous_nets IN3 A3\n"
|
||||
"match_ambiguous_nets IN4 A4\n"
|
||||
"match_ambiguous_nets IN5 A5\n"
|
||||
"match_ambiguous_nets IN6 A6\n"
|
||||
"match_ambiguous_nets IN7 A7\n"
|
||||
"match_ambiguous_nets IN8 A8\n"
|
||||
"match_nets OUT1 Q1\n"
|
||||
"match_nets OUT2 Q2\n"
|
||||
"match_nets OUT3 Q3\n"
|
||||
"match_nets OUT4 Q4\n"
|
||||
"match_nets OUT5 Q5\n"
|
||||
"match_nets OUT6 Q6\n"
|
||||
"match_nets OUT7 Q7\n"
|
||||
"match_nets OUT8 Q8\n"
|
||||
"match_pins IN1 A1\n"
|
||||
"match_pins OUT1 Q1\n"
|
||||
"match_pins IN2 A2\n"
|
||||
"match_pins OUT2 Q2\n"
|
||||
"match_pins IN3 A3\n"
|
||||
"match_pins OUT3 Q3\n"
|
||||
"match_pins IN4 A4\n"
|
||||
"match_pins OUT4 Q4\n"
|
||||
"match_pins IN5 A5\n"
|
||||
"match_pins OUT5 Q5\n"
|
||||
"match_pins IN6 A6\n"
|
||||
"match_pins OUT6 Q6\n"
|
||||
"match_pins IN7 A7\n"
|
||||
"match_pins OUT7 Q7\n"
|
||||
"match_pins IN8 A8\n"
|
||||
"match_pins OUT8 Q8\n"
|
||||
"match_pins VDD VDD\n"
|
||||
"match_pins VSS VSS\n"
|
||||
"match_subcircuits I1 I1\n"
|
||||
"match_subcircuits I8 I8\n"
|
||||
"match_subcircuits I3 I3\n"
|
||||
"match_subcircuits I7 I7\n"
|
||||
"match_subcircuits I4 I4\n"
|
||||
"match_subcircuits I2 I2\n"
|
||||
"match_subcircuits I6 I6\n"
|
||||
"match_subcircuits I5 I5\n"
|
||||
"end_circuit INV8 INV8 MATCH\n"
|
||||
"begin_circuit INV8_WRAP INV8_WRAP\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets IN8 A8\n"
|
||||
"match_nets OUT8 Q8\n"
|
||||
"match_nets IN7 A7\n"
|
||||
"match_nets OUT7 Q7\n"
|
||||
"match_nets IN6 A6\n"
|
||||
"match_nets OUT6 Q6\n"
|
||||
"match_nets IN5 A5\n"
|
||||
"match_nets OUT5 Q5\n"
|
||||
"match_nets IN4 A4\n"
|
||||
"match_nets OUT4 Q4\n"
|
||||
"match_nets IN3 A3\n"
|
||||
"match_nets OUT3 Q3\n"
|
||||
"match_nets IN2 A2\n"
|
||||
"match_nets OUT2 Q2\n"
|
||||
"match_nets IN1 A1\n"
|
||||
"match_nets OUT1 Q1\n"
|
||||
"match_pins IN1 A1\n"
|
||||
"match_pins OUT1 Q1\n"
|
||||
"match_pins IN2 A2\n"
|
||||
"match_pins OUT2 Q2\n"
|
||||
"match_pins IN3 A3\n"
|
||||
"match_pins OUT3 Q3\n"
|
||||
"match_pins IN4 A4\n"
|
||||
"match_pins OUT4 Q4\n"
|
||||
"match_pins IN5 A5\n"
|
||||
"match_pins OUT5 Q5\n"
|
||||
"match_pins IN6 A6\n"
|
||||
"match_pins OUT6 Q6\n"
|
||||
"match_pins IN7 A7\n"
|
||||
"match_pins OUT7 Q7\n"
|
||||
"match_pins IN8 A8\n"
|
||||
"match_pins OUT8 Q8\n"
|
||||
"match_pins VDD VDD\n"
|
||||
"match_pins VSS VSS\n"
|
||||
"match_subcircuits INV8 INV8\n"
|
||||
"end_circuit INV8_WRAP INV8_WRAP MATCH\n"
|
||||
"begin_circuit TOP TOP\n"
|
||||
"match_nets VSS VSS\n"
|
||||
"match_nets VDD VDD\n"
|
||||
"match_nets IN8 A8\n"
|
||||
"match_nets OUT8 Q8\n"
|
||||
"match_nets IN7 A7\n"
|
||||
"match_nets OUT7 Q7\n"
|
||||
"match_nets IN6 A6\n"
|
||||
"match_nets OUT6 Q6\n"
|
||||
"match_nets IN5 A5\n"
|
||||
"match_nets OUT5 Q5\n"
|
||||
"match_nets IN4 A4\n"
|
||||
"match_nets OUT4 Q4\n"
|
||||
"match_nets IN3 A3\n"
|
||||
"match_nets OUT3 Q3\n"
|
||||
"match_nets IN2 A2\n"
|
||||
"match_nets OUT2 Q2\n"
|
||||
"match_nets IN1 A1\n"
|
||||
"match_nets OUT1 Q1\n"
|
||||
"match_pins IN1 A1\n"
|
||||
"match_pins OUT1 Q1\n"
|
||||
"match_pins IN2 A2\n"
|
||||
"match_pins OUT2 Q2\n"
|
||||
"match_pins IN3 A3\n"
|
||||
"match_pins OUT3 Q3\n"
|
||||
"match_pins IN4 A4\n"
|
||||
"match_pins OUT4 Q4\n"
|
||||
"match_pins IN5 A5\n"
|
||||
"match_pins OUT5 Q5\n"
|
||||
"match_pins IN6 A6\n"
|
||||
"match_pins OUT6 Q6\n"
|
||||
"match_pins IN7 A7\n"
|
||||
"match_pins OUT7 Q7\n"
|
||||
"match_pins IN8 A8\n"
|
||||
"match_pins OUT8 Q8\n"
|
||||
"match_pins VDD VDD\n"
|
||||
"match_pins VSS VSS\n"
|
||||
"match_subcircuits INV8 INV8\n"
|
||||
"end_circuit TOP TOP MATCH"
|
||||
);
|
||||
EXPECT_EQ (good, true);
|
||||
}
|
||||
|
||||
TEST(21_BusLikeAmbiguousConnections)
|
||||
|
|
@ -3240,6 +3776,7 @@ TEST(21_BusLikeAmbiguousConnections)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -3412,6 +3949,7 @@ TEST(22_NodesRemoved)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -3532,6 +4070,7 @@ TEST(23_NodesRemovedWithError)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -3631,6 +4170,7 @@ TEST(24_NodesRemovedButConnectedInOther)
|
|||
|
||||
NetlistCompareTestLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
bool good = comp.compare (&nl1, &nl2);
|
||||
|
||||
|
|
@ -3722,6 +4262,7 @@ TEST(25_JoinSymmetricNets)
|
|||
|
||||
db::NetlistComparer comp;
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
// NOTE $1 and $2 are joined because they are symmetric
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
|
|
@ -3760,6 +4301,7 @@ TEST(25b_JoinSymmetricNetsMultiple)
|
|||
|
||||
db::NetlistComparer comp;
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("NAND3"));
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
nl.combine_devices ();
|
||||
|
||||
|
|
@ -3799,17 +4341,18 @@ TEST(25c_JoinSymmetricNetsMultipleMessedUp)
|
|||
|
||||
db::NetlistComparer comp;
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("NOR3"));
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
nl.combine_devices ();
|
||||
|
||||
// NOTE $1 and $2 are joined because they are symmetric
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit NOR3 (A=A,C=C,B=B,OUT=OUT,VSS=VSS,VDD=VDD);\n"
|
||||
" device PMOS $1 (S=$5,G=B,D=$3) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $1 (S=$6,G=B,D=$3) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $2 (S=OUT,G=A,D=VSS) (L=0.23,W=2.05,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $3 (S=$3,G=A,D=OUT) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $4 (S=OUT,G=B,D=VSS) (L=0.23,W=2.05,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $8 (S=VDD,G=C,D=$5) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $8 (S=VDD,G=C,D=$6) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $12 (S=VSS,G=C,D=OUT) (L=0.23,W=2.05,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
)
|
||||
|
|
@ -3838,6 +4381,7 @@ TEST(26_JoinSymmetricNets)
|
|||
|
||||
db::NetlistComparer comp;
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("RESCUBE"));
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit RESCUBE (A=A,B=B);\n"
|
||||
|
|
@ -3882,6 +4426,7 @@ TEST(27_DontJoinSymmetricNetsWithPins)
|
|||
|
||||
db::NetlistComparer comp;
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
// NOTE $1 and $2 are NOT joined because they have pins
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
|
|
@ -3914,6 +4459,8 @@ TEST(28_NoSymmetryDetectionCases)
|
|||
prep_nl (nl, nls);
|
||||
|
||||
db::NetlistComparer comp;
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
std::string sref = nl.to_string ();
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
|
||||
|
||||
|
|
@ -3936,6 +4483,8 @@ TEST(28_NoSymmetryDetectionCases)
|
|||
prep_nl (nl, nls);
|
||||
|
||||
db::NetlistComparer comp;
|
||||
comp.set_dont_consider_net_names (true);
|
||||
|
||||
std::string sref = nl.to_string ();
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
|
||||
|
||||
|
|
@ -3965,6 +4514,7 @@ TEST(28_JoinSymmetricNets)
|
|||
prep_nl (nl, nls);
|
||||
|
||||
db::NetlistComparer comp;
|
||||
comp.set_dont_consider_net_names (true);
|
||||
comp.join_symmetric_nets (nl.circuit_by_name ("INV2LOAD"));
|
||||
|
||||
// NOTE $1 and $2 are joined because they are symmetric
|
||||
|
|
|
|||
|
|
@ -407,3 +407,41 @@ TEST(6)
|
|||
"layer_map('1/0';'3/10-*';'2/0 : 2/0';'2/42 : 2/42';'2/1-41,43-* : */*')"
|
||||
);
|
||||
}
|
||||
|
||||
// issue #592
|
||||
TEST(7)
|
||||
{
|
||||
db::Layout ly;
|
||||
|
||||
unsigned int l1 = ly.insert_layer (db::LayerProperties (85, 0));
|
||||
unsigned int l2 = ly.insert_layer (db::LayerProperties (185, 0));
|
||||
ly.insert_layer ();
|
||||
ly.insert_layer ();
|
||||
|
||||
db::LayerMap lm;
|
||||
lm.map (db::LayerProperties (10001, 0), l1);
|
||||
lm.map (db::LayerProperties (10000, 0), l2);
|
||||
|
||||
EXPECT_EQ (layers_to_string (ly), "85/0,185/0,,");
|
||||
|
||||
lm.prepare (ly);
|
||||
|
||||
EXPECT_EQ (layers_to_string (ly), "85/0,185/0,,");
|
||||
|
||||
std::pair<bool, unsigned int> p;
|
||||
p = lm.logical (db::LayerProperties (85, 0));
|
||||
EXPECT_EQ (p.first, false);
|
||||
EXPECT_EQ (p.second, (unsigned int) 0);
|
||||
|
||||
p = lm.logical (db::LayerProperties (185, 0));
|
||||
EXPECT_EQ (p.first, false);
|
||||
EXPECT_EQ (p.second, (unsigned int) 0);
|
||||
|
||||
p = lm.logical (db::LayerProperties (10000, 0));
|
||||
EXPECT_EQ (p.first, true);
|
||||
EXPECT_EQ (p.second, (unsigned int) 1);
|
||||
|
||||
p = lm.logical (db::LayerProperties (10001, 0));
|
||||
EXPECT_EQ (p.first, true);
|
||||
EXPECT_EQ (p.second, (unsigned int) 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ namespace {
|
|||
// we do a initial scan and after this no more write access here.
|
||||
typedef std::map<const std::type_info *, const ClassBase *, type_info_compare> ti_to_class_map_t;
|
||||
static ti_to_class_map_t *sp_ti_to_class = 0;
|
||||
// NOTE: MacOS/clang seems to have some issue with RTTI across shared objects. This map provides a name-based fallback
|
||||
typedef std::map<std::string, const ClassBase *> tname_to_class_map_t;
|
||||
static tname_to_class_map_t *sp_tname_to_class = 0;
|
||||
|
||||
ClassBase::ClassBase (const std::string &doc, const Methods &mm, bool do_register)
|
||||
: m_initialized (false), mp_base (0), mp_parent (0), m_doc (doc), m_methods (mm)
|
||||
|
|
@ -68,6 +71,10 @@ ClassBase::ClassBase (const std::string &doc, const Methods &mm, bool do_registe
|
|||
delete sp_ti_to_class;
|
||||
sp_ti_to_class = 0;
|
||||
}
|
||||
if (sp_tname_to_class) {
|
||||
delete sp_tname_to_class;
|
||||
sp_tname_to_class = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -753,11 +760,18 @@ static void add_class_to_map (const gsi::ClassBase *c)
|
|||
if (! sp_ti_to_class) {
|
||||
sp_ti_to_class = new ti_to_class_map_t ();
|
||||
}
|
||||
if (! sp_tname_to_class) {
|
||||
sp_tname_to_class = new tname_to_class_map_t ();
|
||||
}
|
||||
|
||||
if (ti && c->is_of_type (*ti) && !sp_ti_to_class->insert (std::make_pair (ti, c)).second) {
|
||||
// Duplicate registration of this class
|
||||
tl::error << "Duplicate registration of class " << c->name () << " (type " << ti->name () << ")";
|
||||
tl_assert (false);
|
||||
if (ti && c->is_of_type (*ti)) {
|
||||
if (!sp_ti_to_class->insert (std::make_pair (ti, c)).second) {
|
||||
// Duplicate registration of this class
|
||||
tl::error << "Duplicate registration of class " << c->name () << " (type " << ti->name () << ")";
|
||||
tl_assert (false);
|
||||
} else {
|
||||
sp_tname_to_class->insert (std::make_pair (std::string (ti->name ()), c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -775,11 +789,19 @@ const ClassBase *class_by_typeinfo_no_assert (const std::type_info &ti)
|
|||
if (! sp_ti_to_class) {
|
||||
return 0;
|
||||
} else {
|
||||
std::map<const std::type_info *, const ClassBase *, type_info_compare>::const_iterator c = sp_ti_to_class->find (&ti);
|
||||
ti_to_class_map_t::const_iterator c = sp_ti_to_class->find (&ti);
|
||||
if (c != sp_ti_to_class->end ()) {
|
||||
return c->second;
|
||||
} else {
|
||||
return 0;
|
||||
// try name lookup
|
||||
tname_to_class_map_t::const_iterator cn = sp_tname_to_class->find (std::string (ti.name ()));
|
||||
if (cn != sp_tname_to_class->end ()) {
|
||||
// we can use this typeinfo as alias
|
||||
sp_ti_to_class->insert (std::make_pair (&ti, cn->second));
|
||||
return cn->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,15 @@ See <a href="/about/lvs_ref_netter.xml#align">Netter#align</a> for a description
|
|||
<p>
|
||||
See <a href="/about/lvs_ref_netter.xml#compare">Netter#compare</a> for a description of that function.
|
||||
</p>
|
||||
<a name="consider_net_names"/><h2>"consider_net_names" - Indicates whether the netlist comparer shall use net names</h2>
|
||||
<keyword name="consider_net_names"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>consider_net_names(f)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
See <a href="/about/lvs_ref_netter.xml#consider_net_names">Netter#consider_net_names</a> for a description of that function.
|
||||
</p>
|
||||
<a name="equivalent_pins"/><h2>"equivalent_pins" - Marks pins as equivalent</h2>
|
||||
<keyword name="equivalent_pins"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -85,6 +85,18 @@ corresponding circuits: the unpaired circuit will be flattened then.
|
|||
This method will return true, if the netlists are equivalent and false
|
||||
otherwise.
|
||||
</p>
|
||||
<a name="consider_net_names"/><h2>"consider_net_names" - Indicates whether the netlist comparer shall use net names</h2>
|
||||
<keyword name="consider_net_names"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>consider_net_names(f)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
If this value is set to true (the default), the netlist comparer
|
||||
will employ net names to resolve ambiguities. If set to false,
|
||||
ambiguities will be resolved based on the topology alone. Topology
|
||||
resolution is more expensive.
|
||||
</p>
|
||||
<a name="equivalent_pins"/><h2>"equivalent_pins" - Marks pins as equivalent</h2>
|
||||
<keyword name="equivalent_pins"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -285,16 +285,6 @@ static DocumentationParser &cls_documentation (const gsi::ClassBase *cls)
|
|||
}
|
||||
}
|
||||
|
||||
static const std::string &aliased_name (const gsi::ClassBase *cls)
|
||||
{
|
||||
const std::string &alias = cls_documentation (cls).alias;
|
||||
if (alias.empty ()) {
|
||||
return cls->name ();
|
||||
} else {
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string make_qualified_name (const gsi::ClassBase *cls)
|
||||
{
|
||||
std::string qname;
|
||||
|
|
@ -703,9 +693,9 @@ type_to_s (const gsi::ArgType &a, bool linked, bool for_return)
|
|||
s += "new ";
|
||||
}
|
||||
if (linked) {
|
||||
s += "<a href=\"" + escape_xml (class_doc_url (aliased_name (a.cls ()))) + "\">" + escape_xml (aliased_name (a.cls ())) + "</a>";
|
||||
s += "<a href=\"" + escape_xml (class_doc_url (make_qualified_name (a.cls ()))) + "\">" + escape_xml (make_qualified_name (a.cls ())) + "</a>";
|
||||
} else {
|
||||
s += aliased_name (a.cls ());
|
||||
s += make_qualified_name (a.cls ());
|
||||
}
|
||||
break;
|
||||
case gsi::T_vector:
|
||||
|
|
|
|||
|
|
@ -668,18 +668,21 @@ BEGIN_PROTECTED
|
|||
}
|
||||
}
|
||||
|
||||
if (collection && (force_add || (collection->begin () == collection->end () && collection->begin_children () == collection->end_children ()))) {
|
||||
bool open_template_dialog = false;
|
||||
if (! force_add && collection && (collection->begin () == collection->end () && collection->begin_children () == collection->end_children ())) {
|
||||
TipDialog td (this,
|
||||
tl::to_string (QObject::tr ("<html><body>To get started with the macro development feature, read the documentation provided: <a href=\"int:/about/macro_editor.xml\">About Macro Development</a>.</body></html>")),
|
||||
"macro-editor-basic-tips");
|
||||
open_template_dialog = td.exec_dialog () && td.will_be_shown ();
|
||||
}
|
||||
|
||||
if (collection && (force_add || open_template_dialog)) {
|
||||
lym::Macro *m = new_macro ();
|
||||
if (force_add && m) {
|
||||
set_run_macro (m);
|
||||
}
|
||||
}
|
||||
|
||||
TipDialog td (this,
|
||||
tl::to_string (QObject::tr ("<html><body>To get started with the macro development feature, read the documentation provided: <a href=\"int:/about/macro_editor.xml\">About Macro Development</a>.</body></html>")),
|
||||
"macro-editor-basic-tips");
|
||||
td.exec_dialog ();
|
||||
|
||||
} else {
|
||||
|
||||
if (! cat.empty ()) {
|
||||
|
|
|
|||
|
|
@ -161,7 +161,10 @@ void MacroTreeModel::macro_changed ()
|
|||
|
||||
void MacroTreeModel::update_data ()
|
||||
{
|
||||
emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex()) - 1, 0, QModelIndex ()));
|
||||
int rc = rowCount (QModelIndex());
|
||||
if (rc > 0) {
|
||||
emit dataChanged (index (0, 0, QModelIndex ()), index (rc - 1, 0, QModelIndex ()));
|
||||
}
|
||||
}
|
||||
|
||||
void MacroTreeModel::about_to_change ()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>432</width>
|
||||
<height>342</height>
|
||||
<height>349</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Put origin relative to cell's bounding box at ...</string>
|
||||
<string>Place this cell reference point ...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -302,6 +302,79 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>... at x:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="x_le"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>µm, y:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="y_le"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>µm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="vis_only_cbx">
|
||||
<property name="text">
|
||||
|
|
@ -322,7 +395,7 @@
|
|||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -403,7 +476,10 @@
|
|||
<tabstop>lb</tabstop>
|
||||
<tabstop>cb</tabstop>
|
||||
<tabstop>rb</tabstop>
|
||||
<tabstop>x_le</tabstop>
|
||||
<tabstop>y_le</tabstop>
|
||||
<tabstop>vis_only_cbx</tabstop>
|
||||
<tabstop>adjust_calls_cbx</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../lay/lay/layResources.qrc"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,237 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclBasic.h"
|
||||
#include "gsiSignals.h"
|
||||
#include "layNetlistBrowserDialog.h"
|
||||
#include "layLayoutView.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
// disable copy and default constructor for NetlistBrowserDialog
|
||||
template <> struct type_traits<lay::NetlistBrowserDialog> : public type_traits<void>
|
||||
{
|
||||
typedef tl::false_tag has_copy_constructor;
|
||||
typedef tl::false_tag has_default_constructor;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
static void set_root (lay::NetlistObjectPath *path, db::Circuit *r)
|
||||
{
|
||||
path->root = r;
|
||||
}
|
||||
|
||||
static db::Circuit *root (const lay::NetlistObjectPath *path)
|
||||
{
|
||||
return const_cast<db::Circuit *> (path->root);
|
||||
}
|
||||
|
||||
static void set_device (lay::NetlistObjectPath *path, db::Device *r)
|
||||
{
|
||||
path->device = r;
|
||||
}
|
||||
|
||||
static db::Device *device (const lay::NetlistObjectPath *path)
|
||||
{
|
||||
return const_cast<db::Device *> (path->device);
|
||||
}
|
||||
|
||||
static void set_net (lay::NetlistObjectPath *path, db::Net *r)
|
||||
{
|
||||
path->net = r;
|
||||
}
|
||||
|
||||
static db::Net *net (const lay::NetlistObjectPath *path)
|
||||
{
|
||||
return const_cast<db::Net *> (path->net);
|
||||
}
|
||||
|
||||
static std::vector<db::SubCircuit *> path (const lay::NetlistObjectPath *p)
|
||||
{
|
||||
std::vector<db::SubCircuit *> pp;
|
||||
pp.reserve (p->path.size ());
|
||||
for (lay::NetlistObjectPath::path_iterator i = p->path.begin (); i != p->path.end (); ++i) {
|
||||
pp.push_back (const_cast<db::SubCircuit *> (*i));
|
||||
}
|
||||
return pp;
|
||||
}
|
||||
|
||||
static void set_path (lay::NetlistObjectPath *p, const std::vector<db::SubCircuit *> &path)
|
||||
{
|
||||
p->path = lay::NetlistObjectPath::path_type (path.begin (), path.end ());
|
||||
}
|
||||
|
||||
Class<lay::NetlistObjectPath> decl_NetlistObjectPath ("lay", "NetlistObjectPath",
|
||||
gsi::method_ext ("root=", &set_root, gsi::arg ("root"),
|
||||
"@brief Sets the root circuit of the path.\n"
|
||||
"The root circuit is the circuit from which the path starts.\n"
|
||||
) +
|
||||
gsi::method_ext ("root", &root,
|
||||
"@brief Gets the root circuit of the path.\n"
|
||||
) +
|
||||
gsi::method_ext ("path=", &set_path, gsi::arg ("path"),
|
||||
"@brief Sets the path.\n"
|
||||
"The path is a list of subcircuits leading from the root to the final object. "
|
||||
"The final (net, device) object is located in the circuit called by the last subcircuit "
|
||||
"of the subcircuit chain. If the subcircuit list is empty, the final object is located inside "
|
||||
"the root object."
|
||||
) +
|
||||
gsi::method_ext ("path", &path,
|
||||
"@brief Gets the path.\n"
|
||||
) +
|
||||
gsi::method_ext ("net=", &set_net, gsi::arg ("net"),
|
||||
"@brief Sets the net the path points to.\n"
|
||||
"If the path describes the location of a net, this member will indicate it.\n"
|
||||
"The other way to describe a final object is \\device=. If neither a device nor "
|
||||
"net is given, the path describes a circuit and how it is referenced from the root."
|
||||
) +
|
||||
gsi::method_ext ("net", &net,
|
||||
"@brief Gets the net the path points to.\n"
|
||||
) +
|
||||
gsi::method_ext ("device=", &set_device, gsi::arg ("device"),
|
||||
"@brief Sets the device the path points to.\n"
|
||||
"If the path describes the location of a device, this member will indicate it.\n"
|
||||
"The other way to describe a final object is \\net=. If neither a device nor "
|
||||
"net is given, the path describes a circuit and how it is referenced from the root."
|
||||
) +
|
||||
gsi::method_ext ("device", &device,
|
||||
"@brief Gets the device the path points to.\n"
|
||||
) +
|
||||
gsi::method ("is_null?", &lay::NetlistObjectPath::is_null,
|
||||
"@brief Returns a value indicating whether the path is an empty one.\n"
|
||||
),
|
||||
"@brief An object describing the instantiation of a netlist object.\n"
|
||||
"This class describes the instantiation of a net or a device or a circuit in terms of "
|
||||
"a root circuit and a subcircuit chain leading to the indicated object.\n"
|
||||
"\n"
|
||||
"See \\net= or \\device= for the indicated object, \\path= for the subcircuit chain.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.27.\n"
|
||||
);
|
||||
|
||||
static lay::NetlistObjectPath first (const lay::NetlistObjectsPath *pp)
|
||||
{
|
||||
return pp->first ();
|
||||
}
|
||||
|
||||
static lay::NetlistObjectPath second (const lay::NetlistObjectsPath *pp)
|
||||
{
|
||||
return pp->second ();
|
||||
}
|
||||
|
||||
Class<lay::NetlistObjectsPath> decl_NetlistObjectsPath ("lay", "NetlistObjectsPath",
|
||||
gsi::method_ext ("first", &first,
|
||||
"@brief Gets the first object's path.\n"
|
||||
"In cases of paired netlists (LVS database), the first path points to the layout netlist object.\n"
|
||||
"For the single netlist, the first path is the only path supplied."
|
||||
) +
|
||||
gsi::method_ext ("second", &second,
|
||||
"@brief Gets the second object's path.\n"
|
||||
"In cases of paired netlists (LVS database), the first path points to the schematic netlist object.\n"
|
||||
"For the single netlist, the scecond path is always a null path."
|
||||
),
|
||||
"@brief An object describing the instantiation of a single netlist object or a pair of those.\n"
|
||||
"This class is basically a pair of netlist object paths (see \\NetlistObjectPath). When derived from a single netlist view, "
|
||||
"only the first path is valid and will point to the selected object (a net, a device or a circuit). The second path is null.\n"
|
||||
"\n"
|
||||
"If the path is derived from a paired netlist view (a LVS report view), the first path corresponds to the object in the layout netlist, "
|
||||
"the second one to the object in the schematic netlist.\n"
|
||||
"If the selected object isn't a matched one, either the first or second path may be a null or a partial path without a final net or device object "
|
||||
"or a partial path.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.27.\n"
|
||||
);
|
||||
|
||||
static lay::NetlistObjectPath current_path_first (lay::NetlistBrowserDialog *dialog)
|
||||
{
|
||||
return dialog->current_path ().first ();
|
||||
}
|
||||
|
||||
static lay::NetlistObjectPath current_path_second (lay::NetlistBrowserDialog *dialog)
|
||||
{
|
||||
return dialog->current_path ().second ();
|
||||
}
|
||||
|
||||
Class<lay::NetlistBrowserDialog> decl_NetlistBrowserDialog ("lay", "NetlistBrowserDialog",
|
||||
gsi::event ("on_current_db_changed", &lay::NetlistBrowserDialog::current_db_changed_event,
|
||||
"@brief This event is triggered when the current database is changed.\n"
|
||||
"The current database can be obtained with \\db."
|
||||
) +
|
||||
gsi::event ("on_selection_changed", &lay::NetlistBrowserDialog::selection_changed_event,
|
||||
"@brief This event is triggered when the selection changed.\n"
|
||||
"The selection can be obtained with \\current_path_first, \\current_path_second, \\selected_nets, \\selected_devices, \\selected_subcircuits and \\selected_circuits."
|
||||
) +
|
||||
gsi::event ("on_probe", &lay::NetlistBrowserDialog::probe_event, gsi::arg ("first_path"), gsi::arg ("second_path"),
|
||||
"@brief This event is triggered when a net is probed.\n"
|
||||
"The first path will indicate the location of the probed net in terms of two paths: one describing the instantiation of the "
|
||||
"net in layout space and one in schematic space. Both objects are \\NetlistObjectPath objects which hold the root circuit, the "
|
||||
"chain of subcircuits leading to the circuit containing the net and the net itself."
|
||||
) +
|
||||
gsi::method ("db", &lay::NetlistBrowserDialog::db,
|
||||
"@brief Gets the database the browser is connected to.\n"
|
||||
) +
|
||||
gsi::method_ext ("current_path_first", ¤t_path_first,
|
||||
"@brief Gets the path of the current object on the first (layout in case of LVS database) side.\n"
|
||||
) +
|
||||
gsi::method_ext ("current_path_second", ¤t_path_second,
|
||||
"@brief Gets the path of the current object on the second (schematic in case of LVS database) side.\n"
|
||||
) +
|
||||
gsi::method ("current_path", &lay::NetlistBrowserDialog::current_path,
|
||||
"@brief Gets the path of the current object as a path pair (combines layout and schematic object paths in case of a LVS database view).\n"
|
||||
) +
|
||||
gsi::method ("selected_paths", &lay::NetlistBrowserDialog::selected_paths,
|
||||
"@brief Gets the nets currently selected objects (paths) in the netlist database browser.\n"
|
||||
"The result is an array of path pairs. See \\NetlistObjectsPath for details about these pairs."
|
||||
),
|
||||
"@brief Represents the netlist browser dialog.\n"
|
||||
"This dialog is a part of the \\LayoutView class and can be obtained through \\LayoutView#netlist_browser.\n"
|
||||
"This interface allows to interact with the browser - mainly to get information about state changes.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.27.\n"
|
||||
);
|
||||
|
||||
static lay::NetlistBrowserDialog *netlist_browser (lay::LayoutView *lv)
|
||||
{
|
||||
return lv->get_plugin<lay::NetlistBrowserDialog> ();
|
||||
}
|
||||
|
||||
// extend lay::LayoutView with the getter for the netlist browser
|
||||
static
|
||||
gsi::ClassExt<lay::LayoutView> decl_ext_layout_view (
|
||||
gsi::method_ext ("netlist_browser", &netlist_browser,
|
||||
"@brief Gets the netlist browser object for the given layout view\n"
|
||||
"\n"
|
||||
"\nThis method has been added in version 0.27.\n"
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -702,7 +702,15 @@ BrowseInstancesForm::fill_cell_instances (const db::ICplxTrans &t, const db::Lay
|
|||
|
||||
std::string aref;
|
||||
if (r > 1 || c > 1) {
|
||||
aref = tl::sprintf ("[%ld,%ld]", c, r);
|
||||
aref = "[";
|
||||
aref += tl::to_string (c);
|
||||
aref += ",";
|
||||
aref += tl::to_string (r);
|
||||
aref += "]";
|
||||
} else if (parent_inst.size () > 1) {
|
||||
aref = "(+";
|
||||
aref += tl::to_string (parent_inst.size () - 1);
|
||||
aref += "x)";
|
||||
}
|
||||
|
||||
std::string new_path;
|
||||
|
|
|
|||
|
|
@ -868,7 +868,15 @@ BrowseShapesForm::fill_cell_instances (const db::ICplxTrans &t, const db::Layout
|
|||
|
||||
std::string aref;
|
||||
if (r > 1 || c > 1) {
|
||||
aref = tl::sprintf ("[%ld,%ld]", c, r);
|
||||
aref = "[";
|
||||
aref += tl::to_string (c);
|
||||
aref += ",";
|
||||
aref += tl::to_string (r);
|
||||
aref += "]";
|
||||
} else if (parent_inst.size () > 1) {
|
||||
aref = "(+";
|
||||
aref += tl::to_string (parent_inst.size () - 1);
|
||||
aref += "x)";
|
||||
}
|
||||
|
||||
std::string new_path;
|
||||
|
|
|
|||
|
|
@ -900,33 +900,39 @@ AlignCellOptionsDialog::~AlignCellOptionsDialog ()
|
|||
}
|
||||
|
||||
bool
|
||||
AlignCellOptionsDialog::exec_dialog (int &mode_x, int &mode_y, bool &visible_only, bool &adjust_calls)
|
||||
AlignCellOptionsDialog::exec_dialog (AlignCellOptions &data)
|
||||
{
|
||||
mp_ui->vis_only_cbx->setChecked (visible_only);
|
||||
mp_ui->adjust_calls_cbx->setChecked (adjust_calls);
|
||||
mp_ui->vis_only_cbx->setChecked (data.visible_only);
|
||||
mp_ui->adjust_calls_cbx->setChecked (data.adjust_parents);
|
||||
|
||||
QToolButton *buttons[3][3] = { { mp_ui->lb, mp_ui->cb, mp_ui->rb }, { mp_ui->lc, mp_ui->cc, mp_ui->rc }, { mp_ui->lt, mp_ui->ct, mp_ui->rt } };
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
buttons[i][j]->setChecked (j - 1 == mode_x && i - 1 == mode_y);
|
||||
buttons[i][j]->setChecked (j - 1 == data.mode_x && i - 1 == data.mode_y);
|
||||
}
|
||||
}
|
||||
|
||||
mp_ui->x_le->setText (tl::to_qstring (tl::micron_to_string (data.xpos)));
|
||||
mp_ui->y_le->setText (tl::to_qstring (tl::micron_to_string (data.ypos)));
|
||||
|
||||
if (QDialog::exec ()) {
|
||||
|
||||
visible_only = mp_ui->vis_only_cbx->isChecked ();
|
||||
adjust_calls = mp_ui->adjust_calls_cbx->isChecked ();
|
||||
data.visible_only = mp_ui->vis_only_cbx->isChecked ();
|
||||
data.adjust_parents = mp_ui->adjust_calls_cbx->isChecked ();
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
if (buttons[i][j]->isChecked ()) {
|
||||
mode_x = j - 1;
|
||||
mode_y = i - 1;
|
||||
data.mode_x = j - 1;
|
||||
data.mode_y = i - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tl::from_string (tl::to_string (mp_ui->x_le->text ()), data.xpos);
|
||||
tl::from_string (tl::to_string (mp_ui->y_le->text ()), data.ypos);
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
|
@ -934,7 +940,21 @@ AlignCellOptionsDialog::exec_dialog (int &mode_x, int &mode_y, bool &visible_onl
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AlignCellOptionsDialog::accept ()
|
||||
{
|
||||
BEGIN_PROTECTED;
|
||||
|
||||
double x = 0.0;
|
||||
tl::from_string (tl::to_string (mp_ui->x_le->text ()), x);
|
||||
tl::from_string (tl::to_string (mp_ui->y_le->text ()), x);
|
||||
|
||||
QDialog::accept ();
|
||||
|
||||
END_PROTECTED;
|
||||
}
|
||||
|
||||
void
|
||||
AlignCellOptionsDialog::button_clicked ()
|
||||
{
|
||||
QToolButton *buttons[3][3] = { { mp_ui->lb, mp_ui->cb, mp_ui->rb }, { mp_ui->lc, mp_ui->cc, mp_ui->rc }, { mp_ui->lt, mp_ui->ct, mp_ui->rt } };
|
||||
|
|
|
|||
|
|
@ -363,6 +363,21 @@ private:
|
|||
lay::LayoutView *mp_view;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A data structure holding the options for the "align cell" dialog
|
||||
*/
|
||||
struct LAYBASIC_PUBLIC AlignCellOptions
|
||||
{
|
||||
AlignCellOptions ()
|
||||
: mode_x (-1), mode_y (-1), xpos (0.0), ypos (0.0), visible_only (false), adjust_parents (true)
|
||||
{ }
|
||||
|
||||
int mode_x, mode_y;
|
||||
double xpos, ypos;
|
||||
bool visible_only;
|
||||
bool adjust_parents;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The merge operation options
|
||||
*/
|
||||
|
|
@ -375,10 +390,11 @@ public:
|
|||
AlignCellOptionsDialog (QWidget *parent);
|
||||
virtual ~AlignCellOptionsDialog ();
|
||||
|
||||
bool exec_dialog (int &mode_x, int &mode_y, bool &visible_only, bool &adjust_calls);
|
||||
bool exec_dialog (AlignCellOptions &data);
|
||||
|
||||
private slots:
|
||||
void button_clicked ();
|
||||
void accept ();
|
||||
|
||||
private:
|
||||
Ui::AlignCellOptionsDialog *mp_ui;
|
||||
|
|
|
|||
|
|
@ -236,67 +236,73 @@ SingleIndexedNetlistModel::top_circuit_count () const
|
|||
size_t
|
||||
SingleIndexedNetlistModel::net_count (const circuit_pair &circuits) const
|
||||
{
|
||||
return circuits.first->net_count ();
|
||||
return circuits.first ? circuits.first->net_count () : 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
SingleIndexedNetlistModel::net_terminal_count (const net_pair &nets) const
|
||||
{
|
||||
return nets.first->terminal_count ();
|
||||
return nets.first ? nets.first->terminal_count () : 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
SingleIndexedNetlistModel::net_subcircuit_pin_count (const net_pair &nets) const
|
||||
{
|
||||
return nets.first->subcircuit_pin_count ();
|
||||
return nets.first ? nets.first->subcircuit_pin_count () : 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
SingleIndexedNetlistModel::net_pin_count (const net_pair &nets) const
|
||||
{
|
||||
return nets.first->pin_count ();
|
||||
return nets.first ? nets.first->pin_count () : 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
SingleIndexedNetlistModel::device_count (const circuit_pair &circuits) const
|
||||
{
|
||||
return circuits.first->device_count ();
|
||||
return circuits.first ? circuits.first->device_count () : 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
SingleIndexedNetlistModel::subcircuit_pin_count (const subcircuit_pair &subcircuits) const
|
||||
{
|
||||
return subcircuits.first ? subcircuits.first->circuit_ref ()->pin_count () : 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
SingleIndexedNetlistModel::pin_count (const circuit_pair &circuits) const
|
||||
{
|
||||
return circuits.first->pin_count ();
|
||||
return circuits.first ? circuits.first->pin_count () : 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
SingleIndexedNetlistModel::subcircuit_count (const circuit_pair &circuits) const
|
||||
{
|
||||
return circuits.first->subcircuit_count ();
|
||||
return circuits.first ? circuits.first->subcircuit_count () : 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
SingleIndexedNetlistModel::child_circuit_count (const circuit_pair &circuits) const
|
||||
{
|
||||
return circuits.first->end_children () - circuits.first->begin_children ();
|
||||
return circuits.first ? (circuits.first->end_children () - circuits.first->begin_children ()) : 0;
|
||||
}
|
||||
|
||||
IndexedNetlistModel::circuit_pair
|
||||
SingleIndexedNetlistModel::parent_of (const net_pair &nets) const
|
||||
{
|
||||
return std::make_pair (nets.first->circuit (), (const db::Circuit *) 0);
|
||||
return std::make_pair (nets.first ? nets.first->circuit () : 0, (const db::Circuit *) 0);
|
||||
}
|
||||
|
||||
IndexedNetlistModel::circuit_pair
|
||||
SingleIndexedNetlistModel::parent_of (const device_pair &devices) const
|
||||
{
|
||||
return std::make_pair (devices.first->circuit (), (const db::Circuit *) 0);
|
||||
return std::make_pair (devices.first ? devices.first->circuit () : 0, (const db::Circuit *) 0);
|
||||
}
|
||||
|
||||
IndexedNetlistModel::circuit_pair
|
||||
SingleIndexedNetlistModel::parent_of (const subcircuit_pair &subcircuits) const
|
||||
{
|
||||
return std::make_pair (subcircuits.first->circuit (), (const db::Circuit *) 0);
|
||||
return std::make_pair (subcircuits.first ? subcircuits.first->circuit () : 0, (const db::Circuit *) 0);
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, IndexedNetlistModel::Status>
|
||||
|
|
@ -346,6 +352,34 @@ SingleIndexedNetlistModel::net_subcircuit_pinref_from_index (const net_pair &net
|
|||
return attr_by_object_and_index (nets, index, nets.first->begin_subcircuit_pins (), nets.first->end_subcircuit_pins (), none, none, m_subcircuit_pinref_by_net_and_index, sort_by_pin_name<db::NetSubcircuitPinRef> ());
|
||||
}
|
||||
|
||||
IndexedNetlistModel::net_subcircuit_pin_pair
|
||||
SingleIndexedNetlistModel::subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const
|
||||
{
|
||||
if (! subcircuits.first) {
|
||||
return IndexedNetlistModel::net_subcircuit_pin_pair (0, 0);
|
||||
}
|
||||
|
||||
std::map<subcircuit_pair, std::vector<net_subcircuit_pin_pair> >::iterator i = m_subcircuit_pins_by_index.find (subcircuits);
|
||||
if (i == m_subcircuit_pins_by_index.end ()) {
|
||||
|
||||
i = m_subcircuit_pins_by_index.insert (std::make_pair (subcircuits, std::vector<net_subcircuit_pin_pair> ())).first;
|
||||
|
||||
std::vector<net_subcircuit_pin_pair> &refs = i->second;
|
||||
const db::Circuit *circuit = subcircuits.first->circuit_ref ();
|
||||
for (db::Circuit::const_pin_iterator p = circuit->begin_pins (); p != circuit->end_pins (); ++p) {
|
||||
const db::NetSubcircuitPinRef *ref = subcircuits.first->netref_for_pin (p->id ());
|
||||
if (! ref) {
|
||||
m_synthetic_pinrefs.push_back (db::NetSubcircuitPinRef (const_cast<db::SubCircuit *> (subcircuits.first), p->id ()));
|
||||
ref = & m_synthetic_pinrefs.back ();
|
||||
}
|
||||
refs.push_back (net_subcircuit_pin_pair (ref, 0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return index < i->second.size () ? i->second [index] : IndexedNetlistModel::net_subcircuit_pin_pair (0, 0);
|
||||
}
|
||||
|
||||
IndexedNetlistModel::net_terminal_pair
|
||||
SingleIndexedNetlistModel::net_terminalref_from_index (const net_pair &nets, size_t index) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ public:
|
|||
virtual size_t net_subcircuit_pin_count (const net_pair &nets) const = 0;
|
||||
virtual size_t net_pin_count (const net_pair &nets) const = 0;
|
||||
virtual size_t device_count (const circuit_pair &circuits) const = 0;
|
||||
virtual size_t subcircuit_pin_count (const subcircuit_pair &subcircuits) const = 0;
|
||||
virtual size_t pin_count (const circuit_pair &circuits) const = 0;
|
||||
virtual size_t subcircuit_count (const circuit_pair &circuits) const = 0;
|
||||
virtual size_t child_circuit_count (const circuit_pair &circuits) const = 0;
|
||||
|
|
@ -95,6 +96,7 @@ public:
|
|||
virtual const db::Net *second_net_for (const db::Net *first) const = 0;
|
||||
virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const = 0;
|
||||
virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const = 0;
|
||||
virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const = 0;
|
||||
virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const = 0;
|
||||
virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const = 0;
|
||||
virtual std::pair<device_pair, Status> device_from_index (const circuit_pair &circuits, size_t index) const = 0;
|
||||
|
|
@ -149,6 +151,7 @@ public:
|
|||
virtual size_t net_pin_count (const net_pair &nets) const;
|
||||
virtual size_t device_count (const circuit_pair &circuits) const;
|
||||
virtual size_t pin_count (const circuit_pair &circuits) const;
|
||||
virtual size_t subcircuit_pin_count (const subcircuit_pair &subcircuits) const;
|
||||
virtual size_t subcircuit_count (const circuit_pair &circuits) const;
|
||||
virtual size_t child_circuit_count (const circuit_pair &circuits) const;
|
||||
|
||||
|
|
@ -163,6 +166,7 @@ public:
|
|||
virtual const db::Net *second_net_for (const db::Net *first) const;
|
||||
virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const;
|
||||
virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const;
|
||||
virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const;
|
||||
virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const;
|
||||
virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const;
|
||||
virtual std::pair<device_pair, Status> device_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
|
|
@ -194,6 +198,8 @@ private:
|
|||
mutable std::map<pin_pair, size_t> m_pin_index_by_object;
|
||||
mutable std::map<subcircuit_pair, size_t> m_subcircuit_index_by_object;
|
||||
mutable std::map<device_pair, size_t> m_device_index_by_object;
|
||||
mutable std::map<subcircuit_pair, std::vector<net_subcircuit_pin_pair> > m_subcircuit_pins_by_index;
|
||||
mutable std::list<db::NetSubcircuitPinRef> m_synthetic_pinrefs;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@
|
|||
#include "layConverters.h"
|
||||
#include "layGridNet.h"
|
||||
#include "layMove.h"
|
||||
#include "layDialogs.h"
|
||||
#include "layZoomBox.h"
|
||||
#include "layMouseTracker.h"
|
||||
#include "layTipDialog.h"
|
||||
|
|
@ -463,10 +462,6 @@ LayoutView::init (db::Manager *mgr, QWidget * /*parent*/)
|
|||
m_sel_inside_pcells = false;
|
||||
m_move_to_origin_mode_x = 0;
|
||||
m_move_to_origin_mode_y = 0;
|
||||
m_align_cell_origin_mode_x = -1;
|
||||
m_align_cell_origin_mode_y = -1;
|
||||
m_align_cell_origin_visible_layers = false;
|
||||
m_align_cell_adjust_parents = true;
|
||||
m_del_cell_mode = 0;
|
||||
m_layer_hier_mode = 0;
|
||||
m_add_other_layers = false;
|
||||
|
|
@ -5292,7 +5287,7 @@ LayoutView::cm_align_cell_origin ()
|
|||
}
|
||||
|
||||
lay::AlignCellOptionsDialog dialog (this);
|
||||
if (dialog.exec_dialog (m_align_cell_origin_mode_x, m_align_cell_origin_mode_y, m_align_cell_origin_visible_layers, m_align_cell_adjust_parents)) {
|
||||
if (dialog.exec_dialog (m_align_cell_options)) {
|
||||
|
||||
clear_selection ();
|
||||
|
||||
|
|
@ -5300,7 +5295,7 @@ LayoutView::cm_align_cell_origin ()
|
|||
|
||||
db::Box bbox;
|
||||
|
||||
if (m_align_cell_origin_visible_layers) {
|
||||
if (m_align_cell_options.visible_only) {
|
||||
for (lay::LayerPropertiesConstIterator l = begin_layers (); !l.at_end (); ++l) {
|
||||
if (! l->has_children () && l->layer_index () >= 0 && l->cellview_index () == cv_index && l->visible (true /*real*/)) {
|
||||
bbox += cell->bbox (l->layer_index ());
|
||||
|
|
@ -5311,7 +5306,7 @@ LayoutView::cm_align_cell_origin ()
|
|||
}
|
||||
|
||||
db::Coord refx, refy;
|
||||
switch (m_align_cell_origin_mode_x) {
|
||||
switch (m_align_cell_options.mode_x) {
|
||||
case -1:
|
||||
refx = bbox.left ();
|
||||
break;
|
||||
|
|
@ -5322,7 +5317,7 @@ LayoutView::cm_align_cell_origin ()
|
|||
refx = bbox.center ().x ();
|
||||
break;
|
||||
}
|
||||
switch (m_align_cell_origin_mode_y) {
|
||||
switch (m_align_cell_options.mode_y) {
|
||||
case -1:
|
||||
refy = bbox.bottom ();
|
||||
break;
|
||||
|
|
@ -5334,10 +5329,11 @@ LayoutView::cm_align_cell_origin ()
|
|||
break;
|
||||
}
|
||||
|
||||
db::Trans t (db::Vector (-refx, -refy));
|
||||
db::Layout &layout = cellview (cv_index)->layout ();
|
||||
db::Cell &nc_cell = layout.cell (cell->cell_index ());
|
||||
|
||||
db::Trans t (db::Vector (-refx + db::coord_traits<db::Coord>::rounded (m_align_cell_options.xpos / layout.dbu ()), -refy + db::coord_traits<db::Coord>::rounded (m_align_cell_options.ypos / layout.dbu ())));
|
||||
|
||||
for (unsigned int i = 0; i < layout.layers (); ++i) {
|
||||
if (layout.is_valid_layer (i)) {
|
||||
db::Shapes &shapes = nc_cell.shapes (i);
|
||||
|
|
@ -5351,7 +5347,7 @@ LayoutView::cm_align_cell_origin ()
|
|||
nc_cell.transform (*inst, t);
|
||||
}
|
||||
|
||||
if (m_align_cell_adjust_parents) {
|
||||
if (m_align_cell_options.adjust_parents) {
|
||||
|
||||
std::vector<std::pair<db::Cell *, db::Instance> > insts_to_modify;
|
||||
for (db::Cell::parent_inst_iterator pi = nc_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
#include "layPlugin.h"
|
||||
#include "layDisplayState.h"
|
||||
#include "layBookmarkList.h"
|
||||
#include "layDialogs.h"
|
||||
#include "gsi.h"
|
||||
#include "tlException.h"
|
||||
#include "tlEvents.h"
|
||||
|
|
@ -2871,9 +2872,7 @@ private:
|
|||
db::LayerProperties m_new_layer_props;
|
||||
db::DVector m_move_dist;
|
||||
int m_move_to_origin_mode_x, m_move_to_origin_mode_y;
|
||||
int m_align_cell_origin_mode_x, m_align_cell_origin_mode_y;
|
||||
bool m_align_cell_origin_visible_layers;
|
||||
bool m_align_cell_adjust_parents;
|
||||
lay::AlignCellOptions m_align_cell_options;
|
||||
int m_del_cell_mode;
|
||||
int m_layer_hier_mode;
|
||||
int m_duplicate_hier_mode;
|
||||
|
|
|
|||
|
|
@ -120,6 +120,8 @@ NetlistBrowserDialog::NetlistBrowserDialog (lay::Dispatcher *root, lay::LayoutVi
|
|||
connect (sticky_cbx, SIGNAL (clicked ()), this, SLOT (sticky_mode_clicked ()));
|
||||
|
||||
cellviews_changed ();
|
||||
|
||||
browser_page->selection_changed_event.add (this, &NetlistBrowserDialog::selection_changed);
|
||||
}
|
||||
|
||||
NetlistBrowserDialog::~NetlistBrowserDialog ()
|
||||
|
|
@ -127,6 +129,34 @@ NetlistBrowserDialog::~NetlistBrowserDialog ()
|
|||
tl::Object::detach_from_all_events ();
|
||||
}
|
||||
|
||||
db::LayoutToNetlist *
|
||||
NetlistBrowserDialog::db ()
|
||||
{
|
||||
return browser_page->db ();
|
||||
}
|
||||
|
||||
const lay::NetlistObjectsPath &
|
||||
NetlistBrowserDialog::current_path () const
|
||||
{
|
||||
if (browser_page) {
|
||||
return browser_page->current_path ();
|
||||
} else {
|
||||
static lay::NetlistObjectsPath empty;
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<lay::NetlistObjectsPath> &
|
||||
NetlistBrowserDialog::selected_paths () const
|
||||
{
|
||||
if (browser_page) {
|
||||
return browser_page->selected_paths ();
|
||||
} else {
|
||||
static std::vector<lay::NetlistObjectsPath> empty;
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NetlistBrowserDialog::configure_clicked ()
|
||||
{
|
||||
|
|
@ -254,40 +284,60 @@ NetlistBrowserDialog::probe_net (const db::DPoint &p, bool trace_path)
|
|||
|
||||
}
|
||||
|
||||
const db::Net *net = 0;
|
||||
db::Net *net = 0;
|
||||
db::Circuit *root = 0;
|
||||
std::vector<db::SubCircuit *> sc_path;
|
||||
|
||||
db::LayoutToNetlist *l2ndb = view ()->get_l2ndb (m_l2n_index);
|
||||
if (l2ndb) {
|
||||
|
||||
// determines the corresponding layer inside the database and probe the net from this region and the
|
||||
// start point.
|
||||
root = l2ndb->netlist ()->circuit_by_name (cv->layout ().cell_name (cv.cell_index ()));
|
||||
if (root) {
|
||||
|
||||
std::vector<db::Region *> regions;
|
||||
// determines the corresponding layer inside the database and probe the net from this region and the
|
||||
// start point.
|
||||
|
||||
const db::Connectivity &conn = l2ndb->connectivity ();
|
||||
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
db::LayerProperties lp = l2ndb->internal_layout ()->get_properties (*layer);
|
||||
if (! lp.is_null ()) {
|
||||
db::Region *region = l2ndb->layer_by_index (*layer);
|
||||
if (lp == cv->layout ().get_properties (start_layer)) {
|
||||
// a matching original layer is looked up with higher prio
|
||||
regions.insert (regions.begin (), region);
|
||||
} else {
|
||||
regions.push_back (region);
|
||||
std::vector<db::Region *> regions;
|
||||
|
||||
const db::Connectivity &conn = l2ndb->connectivity ();
|
||||
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
db::LayerProperties lp = l2ndb->internal_layout ()->get_properties (*layer);
|
||||
if (! lp.is_null ()) {
|
||||
db::Region *region = l2ndb->layer_by_index (*layer);
|
||||
if (lp == cv->layout ().get_properties (start_layer)) {
|
||||
// a matching original layer is looked up with higher prio
|
||||
regions.insert (regions.begin (), region);
|
||||
} else {
|
||||
regions.push_back (region);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// probe the net
|
||||
// probe the net
|
||||
|
||||
for (std::vector<db::Region *>::const_iterator r = regions.begin (); r != regions.end () && !net; ++r) {
|
||||
sc_path.clear ();
|
||||
net = l2ndb->probe_net (**r, start_point, &sc_path, root);
|
||||
}
|
||||
|
||||
for (std::vector<db::Region *>::const_iterator r = regions.begin (); r != regions.end () && !net; ++r) {
|
||||
net = l2ndb->probe_net (**r, start_point);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// select the net if one was found
|
||||
browser_page->select_net (net);
|
||||
lay::NetlistObjectPath path;
|
||||
if (net) {
|
||||
path.root = root;
|
||||
path.net = net;
|
||||
path.path = lay::NetlistObjectPath::path_type (sc_path.begin (), sc_path.end ());
|
||||
}
|
||||
|
||||
browser_page->select_path (path);
|
||||
|
||||
// emits the probe event
|
||||
// NOTE: browser_page->current_path () will hold the paired path with the schematic side being
|
||||
// expanded.
|
||||
probe_event (browser_page->current_path ().first (), browser_page->current_path ().second ());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -421,9 +471,15 @@ BEGIN_PROTECTED
|
|||
tl::log << tl::to_string (QObject::tr ("Loading file: ")) << l2ndb->filename ();
|
||||
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Loading")));
|
||||
|
||||
browser_page->set_l2ndb (0);
|
||||
l2ndb->load (l2ndb->filename ());
|
||||
browser_page->set_l2ndb (l2ndb);
|
||||
browser_page->set_db (0);
|
||||
try {
|
||||
l2ndb->load (l2ndb->filename ());
|
||||
browser_page->set_db (l2ndb);
|
||||
current_db_changed_event ();
|
||||
} catch (...) {
|
||||
current_db_changed_event ();
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -707,6 +763,8 @@ NetlistBrowserDialog::update_content ()
|
|||
central_stack->setCurrentIndex (1);
|
||||
}
|
||||
|
||||
bool db_changed = false;
|
||||
|
||||
m_saveas_action->setEnabled (l2ndb != 0);
|
||||
m_export_action->setEnabled (l2ndb != 0);
|
||||
m_unload_action->setEnabled (l2ndb != 0);
|
||||
|
|
@ -714,7 +772,10 @@ NetlistBrowserDialog::update_content ()
|
|||
m_reload_action->setEnabled (l2ndb != 0);
|
||||
|
||||
browser_page->enable_updates (false); // Avoid building the internal lists several times ...
|
||||
browser_page->set_l2ndb (l2ndb);
|
||||
if (browser_page->db () != l2ndb) {
|
||||
db_changed = true;
|
||||
browser_page->set_db (l2ndb);
|
||||
}
|
||||
browser_page->set_max_shape_count (m_max_shape_count);
|
||||
browser_page->set_highlight_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern, m_marker_intensity, m_use_original_colors, m_auto_color_enabled ? &m_auto_colors : 0);
|
||||
browser_page->set_window (m_window, m_window_dim);
|
||||
|
|
@ -740,6 +801,10 @@ NetlistBrowserDialog::update_content ()
|
|||
if (l2ndb_cb->currentIndex () != m_l2n_index) {
|
||||
l2ndb_cb->setCurrentIndex (m_l2n_index);
|
||||
}
|
||||
|
||||
if (db_changed) {
|
||||
current_db_changed_event ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -751,8 +816,16 @@ NetlistBrowserDialog::deactivated ()
|
|||
lay::Dispatcher::instance ()->config_set (cfg_l2ndb_window_state, lay::save_dialog_state (this, false /*don't store the section sizes*/).c_str ());
|
||||
}
|
||||
|
||||
browser_page->set_l2ndb (0);
|
||||
bool db_changed = false;
|
||||
if (browser_page->db () != 0) {
|
||||
db_changed = true;
|
||||
browser_page->set_db (0);
|
||||
}
|
||||
browser_page->set_view (0, 0);
|
||||
|
||||
if (db_changed) {
|
||||
current_db_changed_event ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "layNetlistBrowser.h"
|
||||
#include "layViewObject.h"
|
||||
#include "layColorPalette.h"
|
||||
#include "tlEvents.h"
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
|
@ -46,6 +47,38 @@ public:
|
|||
|
||||
void load (int lay_index, int cv_index);
|
||||
|
||||
/**
|
||||
* @brief This event is emitted after the current database changed
|
||||
*/
|
||||
tl::Event current_db_changed_event;
|
||||
|
||||
/**
|
||||
* @brief This event is emitted when a shape is probed
|
||||
* The first path is that of the layout, the second that of the schematic in case of a
|
||||
* LVS database.
|
||||
*/
|
||||
tl::event<lay::NetlistObjectPath, lay::NetlistObjectPath> probe_event;
|
||||
|
||||
/**
|
||||
* @brief Gets the current database
|
||||
*/
|
||||
db::LayoutToNetlist *db ();
|
||||
|
||||
/**
|
||||
* @brief Gets the current object's path
|
||||
*/
|
||||
const lay::NetlistObjectsPath ¤t_path () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the selected nets
|
||||
*/
|
||||
const std::vector<lay::NetlistObjectsPath> &selected_paths () const;
|
||||
|
||||
/**
|
||||
* @brief An event indicating that the selection has changed
|
||||
*/
|
||||
tl::Event selection_changed_event;
|
||||
|
||||
private:
|
||||
// implementation of the lay::Browser interface
|
||||
virtual void activated ();
|
||||
|
|
@ -64,6 +97,11 @@ private:
|
|||
void cellview_changed (int index);
|
||||
void l2ndbs_changed ();
|
||||
|
||||
void selection_changed ()
|
||||
{
|
||||
selection_changed_event ();
|
||||
}
|
||||
|
||||
public slots:
|
||||
void cv_index_changed (int);
|
||||
void l2ndb_index_changed (int);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -30,6 +30,9 @@
|
|||
#include "dbLayoutToNetlist.h"
|
||||
#include "dbLayoutVsSchematic.h"
|
||||
|
||||
#include "tlList.h"
|
||||
#include "tlTypeTraits.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QColor>
|
||||
|
||||
|
|
@ -88,6 +91,167 @@ private:
|
|||
// ----------------------------------------------------------------------------------
|
||||
// NetlistBrowserModel definition
|
||||
|
||||
class NetlistBrowserModel;
|
||||
class NetlistModelItemData;
|
||||
class RootItemData;
|
||||
class CircuitItemData;
|
||||
class CircuitNetItemData;
|
||||
class CircuitDeviceItemData;
|
||||
class CircuitSubCircuitItemData;
|
||||
|
||||
}
|
||||
|
||||
namespace tl {
|
||||
// disable copying for NetlistModelItemData
|
||||
template<> struct type_traits<lay::NetlistModelItemData>
|
||||
{
|
||||
typedef false_tag has_copy_constructor;
|
||||
};
|
||||
}
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A base class for the item data object
|
||||
*/
|
||||
class NetlistModelItemData
|
||||
: public tl::list_node<NetlistModelItemData>
|
||||
{
|
||||
public:
|
||||
typedef tl::list<NetlistModelItemData>::iterator iterator;
|
||||
|
||||
NetlistModelItemData ();
|
||||
NetlistModelItemData (NetlistModelItemData *parent);
|
||||
|
||||
virtual ~NetlistModelItemData ();
|
||||
|
||||
virtual NetlistModelItemData *parent () { return mp_parent; }
|
||||
|
||||
virtual QIcon icon (NetlistBrowserModel *model) = 0;
|
||||
virtual QString text (int column, NetlistBrowserModel *model) = 0;
|
||||
virtual QString search_text () = 0;
|
||||
virtual std::string tooltip (NetlistBrowserModel *model) = 0;
|
||||
virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model) = 0;
|
||||
|
||||
void ensure_children (NetlistBrowserModel *model);
|
||||
|
||||
void push_back (NetlistModelItemData *child);
|
||||
|
||||
iterator begin () { return m_children.begin (); }
|
||||
iterator end () { return m_children.end (); }
|
||||
|
||||
size_t child_count () { return m_children_per_index.size (); }
|
||||
size_t index () { return m_index; }
|
||||
|
||||
NetlistModelItemData *child (size_t n);
|
||||
|
||||
virtual std::pair<const db::Circuit *, const db::Circuit *> circuits_of_this ();
|
||||
std::pair<const db::Circuit *, const db::Circuit *> circuits ();
|
||||
bool derived_from_circuits (const std::pair<const db::Circuit *, const db::Circuit *> &sp);
|
||||
|
||||
virtual std::pair<const db::Device *, const db::Device *> devices_of_this ();
|
||||
std::pair<const db::Device *, const db::Device *> devices ();
|
||||
bool derived_from_devices (const std::pair<const db::Device *, const db::Device *> &sp);
|
||||
|
||||
virtual std::pair<const db::Pin *, const db::Pin *> pins_of_this ();
|
||||
std::pair<const db::Pin *, const db::Pin *> pins ();
|
||||
bool derived_from_pins (const std::pair<const db::Pin *, const db::Pin *> &sp);
|
||||
|
||||
virtual std::pair<const db::SubCircuit *, const db::SubCircuit *> subcircuits_of_this ();
|
||||
std::pair<const db::SubCircuit *, const db::SubCircuit *> subcircuits ();
|
||||
bool derived_from_subcircuits (const std::pair<const db::SubCircuit *, const db::SubCircuit *> &sp);
|
||||
|
||||
virtual std::pair<const db::Net *, const db::Net *> nets_of_this ();
|
||||
std::pair<const db::Net *, const db::Net *> nets ();
|
||||
bool derived_from_nets (const std::pair<const db::Net *, const db::Net *> &np);
|
||||
|
||||
private:
|
||||
NetlistModelItemData *mp_parent;
|
||||
tl::list<NetlistModelItemData> m_children;
|
||||
std::vector<NetlistModelItemData *> m_children_per_index;
|
||||
bool m_children_made;
|
||||
size_t m_index;
|
||||
|
||||
void set_index (size_t index) { m_index = index; }
|
||||
|
||||
virtual void do_ensure_children (NetlistBrowserModel *model) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An object describing the instantiation path of a net, a device or a (sub)circuit pair
|
||||
*
|
||||
* This object applies to pairs of these objects. A class providing a path for a single
|
||||
* object is NetlistObjectPath
|
||||
*/
|
||||
struct LAYBASIC_PUBLIC NetlistObjectPath
|
||||
{
|
||||
typedef std::list<const db::SubCircuit *> path_type;
|
||||
typedef path_type::const_iterator path_iterator;
|
||||
|
||||
NetlistObjectPath () : root (0), net (0), device (0) { }
|
||||
|
||||
bool is_null () const
|
||||
{
|
||||
return ! root;
|
||||
}
|
||||
|
||||
bool operator== (const NetlistObjectPath &other) const
|
||||
{
|
||||
return root == other.root && path == other.path && net == other.net && device == other.device;
|
||||
}
|
||||
|
||||
bool operator!= (const NetlistObjectPath &other) const
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
const db::Circuit *root;
|
||||
std::list<const db::SubCircuit *> path;
|
||||
const db::Net *net;
|
||||
const db::Device *device;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An object describing the instantiation path of a net, a device or a (sub)circuit pair
|
||||
*
|
||||
* This object applies to pairs of these objects. A class providing a path for a single
|
||||
* object is NetlistObjectPath
|
||||
*/
|
||||
struct LAYBASIC_PUBLIC NetlistObjectsPath
|
||||
{
|
||||
typedef std::list<std::pair<const db::SubCircuit *, const db::SubCircuit *> > path_type;
|
||||
typedef path_type::const_iterator path_iterator;
|
||||
|
||||
NetlistObjectsPath () { }
|
||||
|
||||
bool is_null () const
|
||||
{
|
||||
return ! root.first && ! root.second;
|
||||
}
|
||||
|
||||
static NetlistObjectsPath from_first(const NetlistObjectPath &p);
|
||||
static NetlistObjectsPath from_second (const NetlistObjectPath &p);
|
||||
|
||||
NetlistObjectPath first () const;
|
||||
NetlistObjectPath second () const;
|
||||
|
||||
bool operator== (const NetlistObjectsPath &other) const
|
||||
{
|
||||
return root == other.root && path == other.path && net == other.net && device == other.device;
|
||||
}
|
||||
|
||||
bool operator!= (const NetlistObjectsPath &other) const
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
std::pair<const db::Circuit *, const db::Circuit *> root;
|
||||
std::list<std::pair<const db::SubCircuit *, const db::SubCircuit *> > path;
|
||||
std::pair<const db::Net *, const db::Net *> net;
|
||||
std::pair<const db::Device *, const db::Device *> device;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The NetlistBrowserModel
|
||||
*
|
||||
|
|
@ -125,31 +289,70 @@ public:
|
|||
virtual QModelIndex parent (const QModelIndex &index) const;
|
||||
virtual int rowCount (const QModelIndex &parent) const;
|
||||
|
||||
QModelIndex index_from_id (void *id, int column) const;
|
||||
|
||||
int status_column () const
|
||||
{
|
||||
return m_status_column;
|
||||
}
|
||||
|
||||
std::pair<const db::Net *, const db::Net *> net_from_index (const QModelIndex &index) const;
|
||||
QModelIndex index_from_net (const std::pair<const db::Net *, const db::Net *> &net) const;
|
||||
QModelIndex index_from_net (const db::Net *net) const;
|
||||
std::pair<const db::Circuit *, const db::Circuit *> circuit_from_index (const QModelIndex &index) const;
|
||||
QModelIndex index_from_circuit (const std::pair<const db::Circuit *, const db::Circuit *> &circuit) const;
|
||||
QModelIndex index_from_circuit (const db::Circuit *circuit) const;
|
||||
|
||||
std::pair<const db::SubCircuit *, const db::SubCircuit *> subcircuit_from_index (const QModelIndex &index) const;
|
||||
|
||||
std::pair<const db::Device *, const db::Device *> device_from_index (const QModelIndex &index) const;
|
||||
|
||||
bool is_circuit_index (const QModelIndex &index) const
|
||||
int object_column () const
|
||||
{
|
||||
return is_id_circuit (index.internalPointer ());
|
||||
return m_object_column;
|
||||
}
|
||||
|
||||
int first_column () const
|
||||
{
|
||||
return m_first_column;
|
||||
}
|
||||
|
||||
int second_column () const
|
||||
{
|
||||
return m_second_column;
|
||||
}
|
||||
|
||||
IndexedNetlistModel *indexer ()
|
||||
{
|
||||
return mp_indexer.get ();
|
||||
}
|
||||
|
||||
std::pair<const db::Net *, const db::Net *> net_from_index (const QModelIndex &index, bool include_parents = true) const;
|
||||
QModelIndex index_from_net (const std::pair<const db::Net *, const db::Net *> &net) const;
|
||||
QModelIndex index_from_net (const db::Net *net) const;
|
||||
std::pair<const db::Circuit *, const db::Circuit *> circuit_from_index (const QModelIndex &index, bool include_parents = true) const;
|
||||
QModelIndex index_from_circuit (const std::pair<const db::Circuit *, const db::Circuit *> &circuit) const;
|
||||
QModelIndex index_from_circuit (const db::Circuit *circuit) const;
|
||||
QModelIndex index_from_subcircuit (const std::pair<const db::SubCircuit *, const db::SubCircuit *> &subcircuits) const;
|
||||
|
||||
std::pair<const db::SubCircuit *, const db::SubCircuit *> subcircuit_from_index (const QModelIndex &index, bool include_parents = true) const;
|
||||
|
||||
std::pair<const db::Device *, const db::Device *> device_from_index (const QModelIndex &index, bool include_parents = true) const;
|
||||
|
||||
void set_item_visibility (QTreeView *view, bool show_all, bool with_warnings);
|
||||
|
||||
QString make_link_to (const std::pair<const db::Net *, const db::Net *> &nets, int column = 0) const;
|
||||
QString make_link_to (const std::pair<const db::Device *, const db::Device *> &devices, int column = 0) const;
|
||||
QString make_link_to (const std::pair<const db::Pin *, const db::Pin *> &pins, const std::pair<const db::Circuit *, const db::Circuit *> &circuits, int column = 0) const;
|
||||
QString make_link_to (const std::pair<const db::Circuit *, const db::Circuit *> &circuits, int column = 0) const;
|
||||
QString make_link_to (const std::pair<const db::SubCircuit *, const db::SubCircuit *> &sub_circuits, int column = 0) const;
|
||||
|
||||
bool is_valid_net_pair (const std::pair<const db::Net *, const db::Net *> &net) const;
|
||||
|
||||
QIcon icon_for_nets (const std::pair<const db::Net *, const db::Net *> &net) const;
|
||||
QIcon icon_for_connection (const std::pair<const db::Net *, const db::Net *> &net) const;
|
||||
|
||||
QModelIndex index_from_url (const QString &url) const;
|
||||
|
||||
NetlistObjectsPath path_from_index (const QModelIndex &index) const;
|
||||
NetlistObjectPath spath_from_index (const QModelIndex &index) const
|
||||
{
|
||||
return path_from_index (index).first ();
|
||||
}
|
||||
|
||||
QModelIndex index_from_path (const NetlistObjectsPath &path);
|
||||
QModelIndex index_from_path (const NetlistObjectPath &path)
|
||||
{
|
||||
return index_from_path (NetlistObjectsPath::from_first (path));
|
||||
}
|
||||
|
||||
private slots:
|
||||
void colors_changed ();
|
||||
|
||||
|
|
@ -157,73 +360,18 @@ private:
|
|||
NetlistBrowserModel (const NetlistBrowserModel &);
|
||||
NetlistBrowserModel &operator= (const NetlistBrowserModel &);
|
||||
|
||||
void *make_id_circuit (size_t circuit_index) const;
|
||||
void *make_id_circuit_pin (size_t circuit_index, size_t pin_index) const;
|
||||
void *make_id_circuit_pin_net (size_t circuit_index, size_t pin_index, size_t net_index) const;
|
||||
void *make_id_circuit_net (size_t circuit_index, size_t net_index) const;
|
||||
void *make_id_circuit_net_device_terminal (size_t circuit_index, size_t net_index, size_t terminal_ref_index) const;
|
||||
void *make_id_circuit_net_device_terminal_others (size_t circuit_index, size_t net_index, size_t terminal_ref_index, size_t other_index) const;
|
||||
void *make_id_circuit_net_pin (size_t circuit_index, size_t net_index, size_t pin_index) const;
|
||||
void *make_id_circuit_net_subcircuit_pin (size_t circuit_index, size_t net_index, size_t pin_ref_index) const;
|
||||
void *make_id_circuit_net_subcircuit_pin_others (size_t circuit_index, size_t net_index, size_t pin_ref_index, size_t other_index) const;
|
||||
void *make_id_circuit_subcircuit (size_t circuit_index, size_t subcircuit_index) const;
|
||||
void *make_id_circuit_subcircuit_pin (size_t circuit_index, size_t subcircuit_index, size_t pin_index) const;
|
||||
void *make_id_circuit_device (size_t circuit_index, size_t device_index) const;
|
||||
void *make_id_circuit_device_terminal (size_t circuit_index, size_t device_index, size_t terminal_index) const;
|
||||
bool is_id_circuit (void *id) const;
|
||||
bool is_id_circuit_pin (void *id) const;
|
||||
bool is_id_circuit_pin_net (void *id) const;
|
||||
bool is_id_circuit_net (void *id) const;
|
||||
bool is_id_circuit_net_device_terminal (void *id) const;
|
||||
bool is_id_circuit_net_device_terminal_others (void *id) const;
|
||||
bool is_id_circuit_net_pin (void *id) const;
|
||||
bool is_id_circuit_net_subcircuit_pin (void *id) const;
|
||||
bool is_id_circuit_net_subcircuit_pin_others (void *id) const;
|
||||
bool is_id_circuit_subcircuit (void *id) const;
|
||||
bool is_id_circuit_subcircuit_pin (void *id) const;
|
||||
bool is_id_circuit_device (void *id) const;
|
||||
bool is_id_circuit_device_terminal (void *id) const;
|
||||
size_t circuit_index_from_id (void *id) const;
|
||||
size_t circuit_pin_index_from_id (void *id) const;
|
||||
size_t circuit_device_index_from_id (void *id) const;
|
||||
size_t circuit_device_terminal_index_from_id (void *id) const;
|
||||
size_t circuit_subcircuit_index_from_id (void *id) const;
|
||||
size_t circuit_subcircuit_pin_index_from_id (void *id) const;
|
||||
size_t circuit_net_index_from_id (void *id) const;
|
||||
size_t circuit_net_pin_index_from_id (void *id) const;
|
||||
size_t circuit_net_subcircuit_pin_index_from_id (void *id) const;
|
||||
size_t circuit_net_subcircuit_pin_other_index_from_id (void *id) const;
|
||||
size_t circuit_net_device_terminal_index_from_id (void *id) const;
|
||||
size_t circuit_net_device_terminal_other_index_from_id (void *id) const;
|
||||
std::pair<const db::Circuit *, const db::Circuit *> circuits_from_id (void *id) const;
|
||||
std::pair<const db::Net *, const db::Net *> nets_from_id (void *id) const;
|
||||
std::pair<const db::NetSubcircuitPinRef *, const db::NetSubcircuitPinRef *> net_subcircuit_pinrefs_from_id (void *id) const;
|
||||
std::pair<const db::NetTerminalRef *, const db::NetTerminalRef *> net_terminalrefs_from_id (void *id) const;
|
||||
std::pair<const db::NetPinRef *, const db::NetPinRef *> net_pinrefs_from_id (void *id) const;
|
||||
std::pair<const db::Device *, const db::Device *> devices_from_id (void *id) const;
|
||||
std::pair<const db::Pin *, const db::Pin *> pins_from_id (void *id) const;
|
||||
std::pair<const db::SubCircuit *, const db::SubCircuit *> subcircuits_from_id (void *id) const;
|
||||
QString text (const QModelIndex &index) const;
|
||||
QVariant tooltip (const QModelIndex &index) const;
|
||||
QString search_text (const QModelIndex &index) const;
|
||||
db::NetlistCrossReference::Status status (const QModelIndex &index) const;
|
||||
QIcon icon (const QModelIndex &index) const;
|
||||
QString make_link_to (const std::pair<const db::Net *, const db::Net *> &nets, int column = 0) const;
|
||||
QString make_link_to (const std::pair<const db::Device *, const db::Device *> &devices, int column = 0) const;
|
||||
QString make_link_to (const std::pair<const db::Pin *, const db::Pin *> &pins, const std::pair<const db::Circuit *, const db::Circuit *> &circuits, int column = 0) const;
|
||||
QString make_link_to (const std::pair<const db::Circuit *, const db::Circuit *> &circuits, int column = 0) const;
|
||||
QString make_link_to (const std::pair<const db::SubCircuit *, const db::SubCircuit *> &sub_circuits, int column = 0) const;
|
||||
QString build_url (const QModelIndex &index, const std::string &title) const;
|
||||
|
||||
std::pair<const db::Netlist *, const db::Netlist *> netlists () const
|
||||
{
|
||||
return std::pair<const db::Netlist *, const db::Netlist *> (mp_l2ndb->netlist (), (const db::Netlist *)0);
|
||||
}
|
||||
|
||||
bool is_valid_net_pair (const std::pair<const db::Net *, const db::Net *> &net) const;
|
||||
|
||||
QIcon icon_for_nets (const std::pair<const db::Net *, const db::Net *> &net) const;
|
||||
QIcon icon_for_connection (const std::pair<const db::Net *, const db::Net *> &net) const;
|
||||
|
||||
void show_or_hide_items (QTreeView *view, const QModelIndex &parent, bool show_all, bool with_warnings, bool with_children);
|
||||
|
||||
db::LayoutToNetlist *mp_l2ndb;
|
||||
|
|
@ -236,6 +384,9 @@ private:
|
|||
int m_status_column;
|
||||
int m_first_column;
|
||||
int m_second_column;
|
||||
std::auto_ptr<NetlistModelItemData> mp_root;
|
||||
|
||||
RootItemData *root () const;
|
||||
};
|
||||
|
||||
} // namespace lay
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ inline const db::Circuit *deref_circuit (const db::Circuit *obj)
|
|||
}
|
||||
|
||||
template <class Obj>
|
||||
static db::ICplxTrans
|
||||
static db::DCplxTrans
|
||||
trans_for (const Obj *objs, const db::Layout &ly, const db::Cell &cell, db::ContextCache &cc, const db::DCplxTrans &initial = db::DCplxTrans ())
|
||||
{
|
||||
db::DCplxTrans t = initial;
|
||||
|
|
@ -89,7 +89,6 @@ trans_for (const Obj *objs, const db::Layout &ly, const db::Cell &cell, db::Cont
|
|||
}
|
||||
|
||||
db::CplxTrans dbu_trans (ly.dbu ());
|
||||
db::ICplxTrans it = dbu_trans.inverted () * t * dbu_trans;
|
||||
|
||||
// The circuit may not be instantiated and still not be the top cell.
|
||||
// This happens if the subcell does not have connections. In this case
|
||||
|
|
@ -98,11 +97,11 @@ trans_for (const Obj *objs, const db::Layout &ly, const db::Cell &cell, db::Cont
|
|||
if (circuit && ly.is_valid_cell_index (circuit->cell_index ())) {
|
||||
std::pair<bool, db::ICplxTrans> tc = cc.find_layout_context (circuit->cell_index (), cell.cell_index ());
|
||||
if (tc.first) {
|
||||
it = tc.second * it;
|
||||
t = dbu_trans * tc.second * dbu_trans.inverted () * t;
|
||||
}
|
||||
}
|
||||
|
||||
return it;
|
||||
return t;
|
||||
}
|
||||
|
||||
NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/)
|
||||
|
|
@ -142,7 +141,8 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/)
|
|||
QAction *sep;
|
||||
directory_tree->addAction (m_show_all_action);
|
||||
directory_tree->addAction (actionCollapseAll);
|
||||
directory_tree->addAction (actionExpandAll);
|
||||
// TODO: this gives a too big tree - confine to single branches?
|
||||
// directory_tree->addAction (actionExpandAll);
|
||||
sep = new QAction (directory_tree);
|
||||
sep->setSeparator (true);
|
||||
directory_tree->addAction (sep);
|
||||
|
|
@ -306,21 +306,10 @@ NetlistBrowserPage::layer_list_changed (int)
|
|||
void
|
||||
NetlistBrowserPage::anchor_clicked (const QString &a)
|
||||
{
|
||||
QUrl url (a);
|
||||
|
||||
QString ids;
|
||||
#if QT_VERSION >= 0x050000
|
||||
ids = QUrlQuery (url.query ()).queryItemValue (QString::fromUtf8 ("id"));
|
||||
#else
|
||||
ids = url.queryItemValue (QString::fromUtf8 ("id"));
|
||||
#endif
|
||||
|
||||
if (ids.isEmpty ()) {
|
||||
return;
|
||||
NetlistBrowserModel *netlist_model = dynamic_cast<NetlistBrowserModel *> (directory_tree->model ());
|
||||
if (netlist_model) {
|
||||
navigate_to (netlist_model->index_from_url (a), true);
|
||||
}
|
||||
|
||||
void *id = reinterpret_cast<void *> (ids.toULongLong ());
|
||||
navigate_to (id, true);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -334,6 +323,7 @@ NetlistBrowserPage::current_tree_index_changed (const QModelIndex &index)
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: this could give a path ...
|
||||
std::pair<const db::Circuit *, const db::Circuit *> circuits = tree_model->circuits_from_index (index);
|
||||
QModelIndex circuit_index = netlist_model->index_from_circuit (circuits);
|
||||
|
||||
|
|
@ -355,11 +345,10 @@ NetlistBrowserPage::current_index_changed (const QModelIndex &index)
|
|||
return;
|
||||
}
|
||||
|
||||
void *id = index.internalPointer ();
|
||||
add_to_history (id, true);
|
||||
add_to_history (index, true);
|
||||
|
||||
std::pair<const db::Circuit *, const db::Circuit *> circuits = netlist_model->circuit_from_index (index);
|
||||
QModelIndex circuit_index = tree_model->index_from_circuits (circuits);
|
||||
NetlistObjectsPath path = netlist_model->path_from_index (index);
|
||||
QModelIndex circuit_index = tree_model->index_from_netpath (path);
|
||||
|
||||
m_signals_enabled = false;
|
||||
hierarchy_tree->setCurrentIndex (circuit_index);
|
||||
|
|
@ -380,6 +369,18 @@ NetlistBrowserPage::select_net (const db::Net *net)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
NetlistBrowserPage::select_path (const lay::NetlistObjectsPath &path)
|
||||
{
|
||||
if (path.is_null ()) {
|
||||
directory_tree->clearSelection ();
|
||||
} else {
|
||||
NetlistBrowserModel *model = dynamic_cast<NetlistBrowserModel *> (directory_tree->model ());
|
||||
tl_assert (model != 0);
|
||||
directory_tree->setCurrentIndex (model->index_from_path (path));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<const db::Net *>
|
||||
NetlistBrowserPage::selected_nets ()
|
||||
{
|
||||
|
|
@ -411,7 +412,7 @@ NetlistBrowserPage::selected_circuits ()
|
|||
|
||||
QModelIndexList selection = directory_tree->selectionModel ()->selectedIndexes ();
|
||||
for (QModelIndexList::const_iterator i = selection.begin (); i != selection.end (); ++i) {
|
||||
if (i->column () == 0 && model->is_circuit_index (*i)) {
|
||||
if (i->column () == 0) {
|
||||
const db::Circuit *circuit = model->circuit_from_index (*i).first;
|
||||
if (circuit) {
|
||||
circuits.push_back (circuit);
|
||||
|
|
@ -467,18 +468,23 @@ NetlistBrowserPage::selected_devices ()
|
|||
void
|
||||
NetlistBrowserPage::selection_changed ()
|
||||
{
|
||||
std::vector<const db::Net *> nets = selected_nets ();
|
||||
if (mp_info_dialog) {
|
||||
mp_info_dialog->set_nets (mp_database.get (), nets);
|
||||
NetlistBrowserModel *model = dynamic_cast<NetlistBrowserModel *> (directory_tree->model ());
|
||||
tl_assert (model != 0);
|
||||
|
||||
QModelIndexList selected = directory_tree->selectionModel ()->selectedIndexes ();
|
||||
|
||||
std::vector<lay::NetlistObjectsPath> selected_paths;
|
||||
selected_paths.reserve (selected.size ());
|
||||
for (QModelIndexList::const_iterator i = selected.begin (); i != selected.end (); ++i) {
|
||||
if (i->column () == 0) {
|
||||
selected_paths.push_back (model->path_from_index (*i));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<const db::Device *> devices = selected_devices ();
|
||||
QModelIndex current = directory_tree->selectionModel ()->currentIndex ();
|
||||
highlight (model->path_from_index (current), selected_paths);
|
||||
|
||||
std::vector<const db::SubCircuit *> subcircuits = selected_subcircuits ();
|
||||
|
||||
std::vector<const db::Circuit *> circuits = selected_circuits ();
|
||||
|
||||
highlight (nets, devices, subcircuits, circuits);
|
||||
selection_changed_event ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -518,15 +524,8 @@ NetlistBrowserPage::select_color_for_net ()
|
|||
}
|
||||
|
||||
void
|
||||
NetlistBrowserPage::navigate_to (void *id, bool fwd)
|
||||
NetlistBrowserPage::navigate_to (const QModelIndex &index, bool fwd)
|
||||
{
|
||||
NetlistBrowserTreeModel *tree_model = dynamic_cast<NetlistBrowserTreeModel *> (hierarchy_tree->model ());
|
||||
NetlistBrowserModel *netlist_model = dynamic_cast<NetlistBrowserModel *> (directory_tree->model ());
|
||||
if (! tree_model || ! netlist_model) {
|
||||
return;
|
||||
}
|
||||
|
||||
QModelIndex index = netlist_model->index_from_id (id, 0);
|
||||
if (! index.isValid ()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -536,35 +535,42 @@ NetlistBrowserPage::navigate_to (void *id, bool fwd)
|
|||
|
||||
directory_tree->setCurrentIndex (index);
|
||||
|
||||
std::pair<const db::Circuit *, const db::Circuit *> circuits = netlist_model->circuit_from_index (index);
|
||||
QModelIndex circuit_index = tree_model->index_from_circuits (circuits);
|
||||
NetlistBrowserTreeModel *tree_model = dynamic_cast<NetlistBrowserTreeModel *> (hierarchy_tree->model ());
|
||||
NetlistBrowserModel *netlist_model = dynamic_cast<NetlistBrowserModel *> (directory_tree->model ());
|
||||
if (! tree_model || ! netlist_model) {
|
||||
return;
|
||||
}
|
||||
|
||||
lay::NetlistObjectsPath path = netlist_model->path_from_index (index);
|
||||
QModelIndex circuit_index = tree_model->index_from_netpath (path);
|
||||
hierarchy_tree->setCurrentIndex (circuit_index);
|
||||
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
m_signals_enabled = true;
|
||||
|
||||
add_to_history (id, fwd);
|
||||
add_to_history (index, fwd);
|
||||
|
||||
selection_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
NetlistBrowserPage::add_to_history (void *id, bool fwd)
|
||||
NetlistBrowserPage::add_to_history (const QModelIndex &index, bool fwd)
|
||||
{
|
||||
if (! fwd) {
|
||||
if (m_history_ptr > 1) {
|
||||
--m_history_ptr;
|
||||
m_history [m_history_ptr - 1] = id;
|
||||
m_history [m_history_ptr - 1] = index;
|
||||
}
|
||||
} else if (m_history_ptr >= m_history.size ()) {
|
||||
m_history.push_back (id);
|
||||
m_history.push_back (index);
|
||||
m_history_ptr = m_history.size ();
|
||||
} else {
|
||||
if (m_history [m_history_ptr] != id) {
|
||||
if (m_history [m_history_ptr] != index) {
|
||||
m_history.erase (m_history.begin () + m_history_ptr + 1, m_history.end ());
|
||||
}
|
||||
m_history [m_history_ptr] = id;
|
||||
m_history [m_history_ptr] = index;
|
||||
++m_history_ptr;
|
||||
}
|
||||
|
||||
|
|
@ -730,7 +736,7 @@ NetlistBrowserPage::find_button_pressed ()
|
|||
|
||||
QModelIndex next = find_next (directory_tree, directory_tree->model (), re, directory_tree->currentIndex ());
|
||||
if (next.isValid ()) {
|
||||
navigate_to (next.internalPointer ());
|
||||
navigate_to (next);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -795,11 +801,12 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
|
|||
m_signals_enabled = se;
|
||||
|
||||
clear_markers ();
|
||||
highlight (std::vector<const db::Net *> (), std::vector<const db::Device *> (), std::vector<const db::SubCircuit *> (), std::vector<const db::Circuit *> ());
|
||||
|
||||
m_cell_context_cache = db::ContextCache (mp_database.get () ? mp_database->internal_layout () : 0);
|
||||
|
||||
setup_trees ();
|
||||
|
||||
selection_changed_event ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -886,21 +893,16 @@ NetlistBrowserPage::setup_trees ()
|
|||
}
|
||||
|
||||
void
|
||||
NetlistBrowserPage::highlight (const std::vector<const db::Net *> &nets, const std::vector<const db::Device *> &devices, const std::vector<const db::SubCircuit *> &subcircuits, const std::vector<const db::Circuit *> &circuits)
|
||||
NetlistBrowserPage::highlight (const NetlistObjectsPath ¤t_path, const std::vector<NetlistObjectsPath> &selected_paths)
|
||||
{
|
||||
if (nets != m_current_nets || devices != m_current_devices || subcircuits != m_current_subcircuits || circuits != m_current_circuits) {
|
||||
if (current_path != m_current_path && selected_paths != m_selected_paths) {
|
||||
|
||||
m_current_nets = nets;
|
||||
m_current_devices = devices;
|
||||
m_current_subcircuits = subcircuits;
|
||||
m_current_circuits = circuits;
|
||||
m_current_path = current_path;
|
||||
m_selected_paths = selected_paths;
|
||||
|
||||
clear_markers ();
|
||||
|
||||
if (! nets.empty () || ! devices.empty () || ! subcircuits.empty () || ! circuits.empty ()) {
|
||||
adjust_view ();
|
||||
update_highlights ();
|
||||
}
|
||||
adjust_view ();
|
||||
update_highlights ();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -928,7 +930,8 @@ bbox_for_device_abstract (const db::Layout *layout, const db::DeviceAbstract *de
|
|||
return db::Box ();
|
||||
}
|
||||
|
||||
return layout->cell (device_abstract->cell_index ()).bbox ().transformed (db::CplxTrans (layout->dbu ()).inverted () * trans * db::CplxTrans (layout->dbu ()));}
|
||||
return layout->cell (device_abstract->cell_index ()).bbox ().transformed (db::CplxTrans (layout->dbu ()).inverted () * trans * db::CplxTrans (layout->dbu ()));
|
||||
}
|
||||
|
||||
static db::Box
|
||||
bbox_for_circuit (const db::Layout *layout, const db::Circuit *circuit)
|
||||
|
|
@ -945,12 +948,6 @@ bbox_for_circuit (const db::Layout *layout, const db::Circuit *circuit)
|
|||
return layout->cell (circuit->cell_index ()).bbox ();
|
||||
}
|
||||
|
||||
static db::Box
|
||||
bbox_for_subcircuit (const db::Layout *layout, const db::SubCircuit *subcircuit)
|
||||
{
|
||||
return bbox_for_circuit (layout, subcircuit->circuit_ref ());
|
||||
}
|
||||
|
||||
void
|
||||
NetlistBrowserPage::adjust_view ()
|
||||
{
|
||||
|
|
@ -967,57 +964,80 @@ NetlistBrowserPage::adjust_view ()
|
|||
return;
|
||||
}
|
||||
|
||||
const db::Layout &original_layout = mp_view->cellview (m_cv_index)->layout ();
|
||||
const db::Circuit *top_circuit = mp_database->netlist ()->circuit_by_name (original_layout.cell_name (mp_view->cellview (m_cv_index).cell_index ()));
|
||||
|
||||
const db::Layout *layout = mp_database->internal_layout ();
|
||||
const db::Cell *cell = mp_database->internal_top_cell ();
|
||||
const db::Cell *cell = (top_circuit && layout->is_valid_cell_index (top_circuit->cell_index ()) ? &layout->cell (top_circuit->cell_index ()) : mp_database->internal_top_cell ());
|
||||
if (! layout || ! cell) {
|
||||
return;
|
||||
}
|
||||
|
||||
db::DBox bbox;
|
||||
|
||||
db::Box bbox;
|
||||
for (std::vector<lay::NetlistObjectsPath>::const_iterator path = m_selected_paths.begin (); path != m_selected_paths.end (); ++path) {
|
||||
|
||||
for (std::vector<const db::Net *>::const_iterator net = m_current_nets.begin (); net != m_current_nets.end (); ++net) {
|
||||
const db::Circuit *circuit = path->root.first;
|
||||
if (! circuit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::ICplxTrans net_trans = trans_for (*net, *layout, *cell, m_cell_context_cache);
|
||||
db::DCplxTrans trans;
|
||||
|
||||
db::cell_index_type cell_index = (*net)->circuit ()->cell_index ();
|
||||
size_t cluster_id = (*net)->cluster_id ();
|
||||
trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ());
|
||||
|
||||
const db::Connectivity &conn = mp_database->connectivity ();
|
||||
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
for (std::list<std::pair<const db::SubCircuit *, const db::SubCircuit *> >::const_iterator p = path->path.begin (); p != path->path.end () && circuit; ++p) {
|
||||
if (p->first) {
|
||||
circuit = p->first->circuit_ref ();
|
||||
trans = trans * p->first->trans ();
|
||||
} else {
|
||||
circuit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
db::Box layer_bbox;
|
||||
db::recursive_cluster_shape_iterator<db::NetShape> shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id);
|
||||
while (! shapes.at_end ()) {
|
||||
layer_bbox += shapes->bbox ();
|
||||
++shapes;
|
||||
if (! circuit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::Box ebox;
|
||||
|
||||
const db::Device *device = path->device.first;
|
||||
const db::Net *net = path->net.first;
|
||||
|
||||
if (device) {
|
||||
|
||||
ebox += bbox_for_device_abstract (layout, device->device_abstract (), db::DCplxTrans ());
|
||||
|
||||
const std::vector<db::DeviceAbstractRef> &oda = device->other_abstracts ();
|
||||
for (std::vector<db::DeviceAbstractRef>::const_iterator a = oda.begin (); a != oda.end (); ++a) {
|
||||
ebox += bbox_for_device_abstract (layout, a->device_abstract, a->trans);
|
||||
}
|
||||
|
||||
bbox += net_trans * layer_bbox;
|
||||
} else if (net) {
|
||||
|
||||
db::cell_index_type cell_index = net->circuit ()->cell_index ();
|
||||
size_t cluster_id = net->cluster_id ();
|
||||
|
||||
const db::Connectivity &conn = mp_database->connectivity ();
|
||||
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
|
||||
db::Box layer_bbox;
|
||||
db::recursive_cluster_shape_iterator<db::NetShape> shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id);
|
||||
while (! shapes.at_end ()) {
|
||||
layer_bbox += shapes->bbox ().transformed (shapes.trans ());
|
||||
++shapes;
|
||||
}
|
||||
|
||||
ebox += layer_bbox;
|
||||
|
||||
}
|
||||
|
||||
} else if (circuit) {
|
||||
ebox += bbox_for_circuit (layout, circuit);
|
||||
}
|
||||
|
||||
}
|
||||
bbox += trans * db::CplxTrans (layout->dbu ()) * ebox;
|
||||
|
||||
for (std::vector<const db::Device *>::const_iterator device = m_current_devices.begin (); device != m_current_devices.end (); ++device) {
|
||||
|
||||
db::ICplxTrans trans = trans_for (*device, *layout, *cell, m_cell_context_cache, (*device)->trans ());
|
||||
|
||||
bbox += trans * bbox_for_device_abstract (layout, (*device)->device_abstract (), db::DCplxTrans ());
|
||||
|
||||
const std::vector<db::DeviceAbstractRef> &oda = (*device)->other_abstracts ();
|
||||
for (std::vector<db::DeviceAbstractRef>::const_iterator a = oda.begin (); a != oda.end (); ++a) {
|
||||
bbox += trans * bbox_for_device_abstract (layout, a->device_abstract, a->trans);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::vector<const db::SubCircuit *>::const_iterator subcircuit = m_current_subcircuits.begin (); subcircuit != m_current_subcircuits.end (); ++subcircuit) {
|
||||
bbox += trans_for (*subcircuit, *layout, *cell, m_cell_context_cache, (*subcircuit)->trans ()) * bbox_for_subcircuit (layout, *subcircuit);
|
||||
}
|
||||
|
||||
for (std::vector<const db::Circuit *>::const_iterator circuit = m_current_circuits.begin (); circuit != m_current_circuits.end (); ++circuit) {
|
||||
bbox += trans_for (*circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ()) * bbox_for_circuit (layout, *circuit);
|
||||
}
|
||||
|
||||
if (! bbox.empty ()) {
|
||||
|
|
@ -1025,9 +1045,8 @@ NetlistBrowserPage::adjust_view ()
|
|||
std::vector<db::DCplxTrans> tv = mp_view->cv_transform_variants (m_cv_index);
|
||||
|
||||
db::DBox tv_bbox;
|
||||
db::DBox dbu_bbox = db::CplxTrans (layout->dbu ()) * bbox;
|
||||
for (std::vector<db::DCplxTrans>::const_iterator t = tv.begin (); t != tv.end (); ++t) {
|
||||
tv_bbox += *t * dbu_bbox;
|
||||
tv_bbox += *t * bbox;
|
||||
}
|
||||
|
||||
if (m_window == lay::NetlistBrowserConfig::FitNet) {
|
||||
|
|
@ -1065,12 +1084,10 @@ bool
|
|||
NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, size_t &n_markers, const std::vector<db::DCplxTrans> &tv)
|
||||
{
|
||||
const db::Layout *layout = mp_database->internal_layout ();
|
||||
const db::Cell *cell = mp_database->internal_top_cell ();
|
||||
db::ICplxTrans device_trans = trans_for (device, *layout, *cell, m_cell_context_cache, device->trans ());
|
||||
|
||||
QColor color = make_valid_color (m_colorizer.marker_color ());
|
||||
|
||||
db::Box device_bbox = bbox_for_device_abstract (layout, device->device_abstract (), db::DCplxTrans ());
|
||||
db::Box device_bbox = bbox_for_device_abstract (layout, device->device_abstract (), device->trans ());
|
||||
if (! device_bbox.empty ()) {
|
||||
|
||||
if (n_markers == m_max_shape_count) {
|
||||
|
|
@ -1080,7 +1097,7 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz
|
|||
++n_markers;
|
||||
|
||||
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
|
||||
mp_markers.back ()->set (device_bbox, device_trans, tv);
|
||||
mp_markers.back ()->set (device_bbox, db::ICplxTrans (), tv);
|
||||
mp_markers.back ()->set_color (color);
|
||||
mp_markers.back ()->set_frame_color (color);
|
||||
configure_marker (mp_markers.back (), false);
|
||||
|
|
@ -1090,7 +1107,7 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz
|
|||
const std::vector<db::DeviceAbstractRef> &oda = device->other_abstracts ();
|
||||
for (std::vector<db::DeviceAbstractRef>::const_iterator a = oda.begin (); a != oda.end (); ++a) {
|
||||
|
||||
db::Box da_box = bbox_for_device_abstract (layout, a->device_abstract, a->trans);
|
||||
db::Box da_box = bbox_for_device_abstract (layout, a->device_abstract, device->trans () * a->trans);
|
||||
if (! da_box.empty ()) {
|
||||
|
||||
if (n_markers == m_max_shape_count) {
|
||||
|
|
@ -1100,7 +1117,7 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz
|
|||
++n_markers;
|
||||
|
||||
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
|
||||
mp_markers.back ()->set (da_box, device_trans, tv);
|
||||
mp_markers.back ()->set (da_box, db::ICplxTrans (), tv);
|
||||
mp_markers.back ()->set_color (color);
|
||||
mp_markers.back ()->set_frame_color (color);
|
||||
configure_marker (mp_markers.back (), false);
|
||||
|
|
@ -1112,40 +1129,10 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
NetlistBrowserPage::produce_highlights_for_subcircuit (const db::SubCircuit *subcircuit, size_t &n_markers, const std::vector<db::DCplxTrans> &tv)
|
||||
{
|
||||
const db::Layout *layout = mp_database->internal_layout ();
|
||||
const db::Cell *cell = mp_database->internal_top_cell ();
|
||||
db::ICplxTrans subcircuit_trans = trans_for (subcircuit, *layout, *cell, m_cell_context_cache, subcircuit->trans ());
|
||||
|
||||
QColor color = make_valid_color (m_colorizer.marker_color ());
|
||||
db::Box circuit_bbox = bbox_for_subcircuit (layout, subcircuit);
|
||||
if (circuit_bbox.empty ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (n_markers == m_max_shape_count) {
|
||||
return true;
|
||||
}
|
||||
|
||||
++n_markers;
|
||||
|
||||
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
|
||||
mp_markers.back ()->set (circuit_bbox, subcircuit_trans, tv);
|
||||
mp_markers.back ()->set_color (color);
|
||||
mp_markers.back ()->set_frame_color (color);
|
||||
configure_marker (mp_markers.back (), false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
NetlistBrowserPage::produce_highlights_for_circuit (const db::Circuit *circuit, size_t &n_markers, const std::vector<db::DCplxTrans> &tv)
|
||||
{
|
||||
const db::Layout *layout = mp_database->internal_layout ();
|
||||
const db::Cell *cell = mp_database->internal_top_cell ();
|
||||
db::ICplxTrans circuit_trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ());
|
||||
|
||||
QColor color = make_valid_color (m_colorizer.marker_color ());
|
||||
db::Box circuit_bbox = bbox_for_circuit (layout, circuit);
|
||||
|
|
@ -1160,7 +1147,7 @@ NetlistBrowserPage::produce_highlights_for_circuit (const db::Circuit *circuit,
|
|||
++n_markers;
|
||||
|
||||
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
|
||||
mp_markers.back ()->set (circuit_bbox, circuit_trans, tv);
|
||||
mp_markers.back ()->set (circuit_bbox, db::ICplxTrans (), tv);
|
||||
mp_markers.back ()->set_color (color);
|
||||
mp_markers.back ()->set_frame_color (color);
|
||||
configure_marker (mp_markers.back (), false);
|
||||
|
|
@ -1172,8 +1159,6 @@ bool
|
|||
NetlistBrowserPage::produce_highlights_for_net (const db::Net *net, size_t &n_markers, const std::map<db::LayerProperties, lay::LayerPropertiesConstIterator> &display_by_lp, const std::vector<db::DCplxTrans> &tv)
|
||||
{
|
||||
const db::Layout *layout = mp_database->internal_layout ();
|
||||
const db::Cell *cell = mp_database->internal_top_cell ();
|
||||
db::ICplxTrans net_trans = trans_for (net, *layout, *cell, m_cell_context_cache);
|
||||
|
||||
db::cell_index_type cell_index = net->circuit ()->cell_index ();
|
||||
size_t cluster_id = net->cluster_id ();
|
||||
|
|
@ -1199,7 +1184,7 @@ NetlistBrowserPage::produce_highlights_for_net (const db::Net *net, size_t &n_ma
|
|||
}
|
||||
|
||||
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
|
||||
mp_markers.back ()->set (shapes->polygon_ref (), net_trans * shapes.trans (), tv);
|
||||
mp_markers.back ()->set (shapes->polygon_ref (), shapes.trans (), tv);
|
||||
|
||||
if (net_color.isValid ()) {
|
||||
|
||||
|
|
@ -1272,14 +1257,14 @@ NetlistBrowserPage::update_highlights ()
|
|||
}
|
||||
|
||||
const db::Layout &original_layout = mp_view->cellview (m_cv_index)->layout ();
|
||||
const db::Circuit *top_circuit = mp_database->netlist ()->circuit_by_name (original_layout.cell_name (mp_view->cellview (m_cv_index).cell_index ()));
|
||||
|
||||
const db::Layout *layout = mp_database->internal_layout ();
|
||||
if (! layout) {
|
||||
const db::Cell *cell = (top_circuit && layout->is_valid_cell_index (top_circuit->cell_index ()) ? &layout->cell (top_circuit->cell_index ()) : mp_database->internal_top_cell ());
|
||||
if (! layout || ! cell) {
|
||||
return;
|
||||
}
|
||||
|
||||
// a map of display properties vs. layer properties
|
||||
|
||||
std::map<db::LayerProperties, lay::LayerPropertiesConstIterator> display_by_lp;
|
||||
for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) {
|
||||
if (! lp->has_children () && lp->cellview_index () == int (m_cv_index) && lp->layer_index () >= 0 && (unsigned int) lp->layer_index () < original_layout.layers ()) {
|
||||
|
|
@ -1287,36 +1272,55 @@ NetlistBrowserPage::update_highlights ()
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<db::DCplxTrans> tv = mp_view->cv_transform_variants (m_cv_index);
|
||||
|
||||
// correct DBU differences between the storage layout and the original layout
|
||||
for (std::vector<db::DCplxTrans>::iterator t = tv.begin (); t != tv.end (); ++t) {
|
||||
*t = *t * db::DCplxTrans (layout->dbu () / original_layout.dbu ());
|
||||
}
|
||||
|
||||
size_t n_markers = 0;
|
||||
bool not_all_shapes_are_shown = false;
|
||||
|
||||
for (std::vector<const db::Net *>::const_iterator net = m_current_nets.begin (); net != m_current_nets.end () && ! not_all_shapes_are_shown; ++net) {
|
||||
if ((*net)->circuit ()) {
|
||||
not_all_shapes_are_shown = produce_highlights_for_net (*net, n_markers, display_by_lp, tv);
|
||||
}
|
||||
}
|
||||
for (std::vector<lay::NetlistObjectsPath>::const_iterator path = m_selected_paths.begin (); path != m_selected_paths.end (); ++path) {
|
||||
|
||||
for (std::vector<const db::Device *>::const_iterator device = m_current_devices.begin (); device != m_current_devices.end () && ! not_all_shapes_are_shown; ++device) {
|
||||
if ((*device)->circuit ()) {
|
||||
not_all_shapes_are_shown = produce_highlights_for_device (*device, n_markers, tv);
|
||||
const db::Circuit *circuit = path->root.first;
|
||||
if (! circuit) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<const db::SubCircuit *>::const_iterator subcircuit = m_current_subcircuits.begin (); subcircuit != m_current_subcircuits.end () && ! not_all_shapes_are_shown; ++subcircuit) {
|
||||
if ((*subcircuit)->circuit ()) {
|
||||
not_all_shapes_are_shown = produce_highlights_for_subcircuit (*subcircuit, n_markers, tv);
|
||||
// computes the transformation supplied by the path
|
||||
|
||||
db::DCplxTrans trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ());
|
||||
|
||||
for (std::list<std::pair<const db::SubCircuit *, const db::SubCircuit *> >::const_iterator p = path->path.begin (); p != path->path.end () && circuit; ++p) {
|
||||
if (p->first) {
|
||||
circuit = p->first->circuit_ref ();
|
||||
trans = trans * p->first->trans ();
|
||||
} else {
|
||||
circuit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (! circuit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// a map of display properties vs. layer properties
|
||||
|
||||
// correct DBU differences between the storage layout and the original layout
|
||||
std::vector<db::DCplxTrans> tv = mp_view->cv_transform_variants (m_cv_index);
|
||||
for (std::vector<db::DCplxTrans>::iterator t = tv.begin (); t != tv.end (); ++t) {
|
||||
*t = *t * trans * db::DCplxTrans (layout->dbu () / original_layout.dbu ());
|
||||
}
|
||||
|
||||
if (path->net.first) {
|
||||
if (produce_highlights_for_net (path->net.first, n_markers, display_by_lp, tv)) {
|
||||
not_all_shapes_are_shown = true;
|
||||
}
|
||||
} else if (path->device.first) {
|
||||
if (produce_highlights_for_device (path->device.first, n_markers, tv)) {
|
||||
not_all_shapes_are_shown = true;
|
||||
}
|
||||
} else if (circuit) {
|
||||
if (produce_highlights_for_circuit (circuit, n_markers, tv)) {
|
||||
not_all_shapes_are_shown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<const db::Circuit *>::const_iterator circuit = m_current_circuits.begin (); circuit != m_current_circuits.end () && ! not_all_shapes_are_shown; ++circuit) {
|
||||
not_all_shapes_are_shown = produce_highlights_for_circuit (*circuit, n_markers, tv);
|
||||
}
|
||||
|
||||
if (not_all_shapes_are_shown) {
|
||||
|
|
@ -1327,7 +1331,6 @@ NetlistBrowserPage::update_highlights ()
|
|||
} else {
|
||||
info_label->hide ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "dbLayoutUtils.h"
|
||||
|
||||
#include "tlObject.h"
|
||||
#include "tlEvents.h"
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
|
|
@ -90,25 +91,14 @@ public:
|
|||
/**
|
||||
* @brief Attaches the page to a L2N DB
|
||||
*/
|
||||
void set_l2ndb (db::LayoutToNetlist *database)
|
||||
{
|
||||
set_db (database);
|
||||
}
|
||||
void set_db (db::LayoutToNetlist *database);
|
||||
|
||||
/**
|
||||
* @brief Attaches the page to a LVS DB
|
||||
* @brief Gets the database the page is connected to
|
||||
*/
|
||||
void set_lvsdb (db::LayoutVsSchematic *database)
|
||||
db::LayoutToNetlist *db ()
|
||||
{
|
||||
set_db (database);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Detaches the page from any DB
|
||||
*/
|
||||
void reset_db ()
|
||||
{
|
||||
set_db (0);
|
||||
return mp_database.get ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -116,6 +106,22 @@ public:
|
|||
*/
|
||||
void select_net (const db::Net *net);
|
||||
|
||||
/**
|
||||
* @brief Selects a netlist object (a circuit, a subcircuit, a net or a device)
|
||||
*/
|
||||
void select_path (const lay::NetlistObjectPath &path)
|
||||
{
|
||||
select_path (lay::NetlistObjectsPath::from_first (path));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects a netlist object (a circuit, a subcircuit, a net or a device)
|
||||
*
|
||||
* This variant allows specifying a paired path using either an object from the first,
|
||||
* the second netlist of both.
|
||||
*/
|
||||
void select_path (const lay::NetlistObjectsPath &path);
|
||||
|
||||
/**
|
||||
* @brief Set the window type and window dimensions
|
||||
*/
|
||||
|
|
@ -162,6 +168,27 @@ public:
|
|||
*/
|
||||
void update_highlights ();
|
||||
|
||||
/**
|
||||
* @brief Gets the current object's path
|
||||
*/
|
||||
const lay::NetlistObjectsPath ¤t_path () const
|
||||
{
|
||||
return m_current_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the selected nets
|
||||
*/
|
||||
const std::vector<lay::NetlistObjectsPath> &selected_paths () const
|
||||
{
|
||||
return m_selected_paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief An event indicating that the selection has changed
|
||||
*/
|
||||
tl::Event selection_changed_event;
|
||||
|
||||
public slots:
|
||||
void export_all ();
|
||||
void export_selected ();
|
||||
|
|
@ -201,28 +228,25 @@ private:
|
|||
unsigned int m_cv_index;
|
||||
lay::Dispatcher *mp_plugin_root;
|
||||
tl::weak_ptr<db::LayoutToNetlist> mp_database;
|
||||
std::vector<void *> m_history;
|
||||
std::vector<QModelIndex> m_history;
|
||||
size_t m_history_ptr;
|
||||
bool m_signals_enabled;
|
||||
std::vector <lay::Marker *> mp_markers;
|
||||
bool m_enable_updates;
|
||||
bool m_update_needed;
|
||||
std::vector<const db::Net *> m_current_nets;
|
||||
std::vector<const db::Device *> m_current_devices;
|
||||
std::vector<const db::SubCircuit *> m_current_subcircuits;
|
||||
std::vector<const db::Circuit *> m_current_circuits;
|
||||
lay::NetlistObjectsPath m_current_path;
|
||||
std::vector<lay::NetlistObjectsPath> m_selected_paths;
|
||||
lay::NetInfoDialog *mp_info_dialog;
|
||||
tl::DeferredMethod<NetlistBrowserPage> dm_update_highlights;
|
||||
tl::DeferredMethod<NetlistBrowserPage> dm_rerun_macro;
|
||||
db::ContextCache m_cell_context_cache;
|
||||
|
||||
void set_db (db::LayoutToNetlist *l2ndb);
|
||||
void setup_trees ();
|
||||
void add_to_history (void *id, bool fwd);
|
||||
void navigate_to (void *id, bool forward = true);
|
||||
void add_to_history (const QModelIndex &index, bool fwd);
|
||||
void navigate_to (const QModelIndex &index, bool forward = true);
|
||||
void adjust_view ();
|
||||
void clear_markers ();
|
||||
void highlight (const std::vector<const db::Net *> &nets, const std::vector<const db::Device *> &devices, const std::vector<const db::SubCircuit *> &subcircuits, const std::vector<const db::Circuit *> &circuits);
|
||||
void highlight (const NetlistObjectsPath ¤t_path, const std::vector<NetlistObjectsPath> &selected_paths);
|
||||
std::vector<const db::Net *> selected_nets ();
|
||||
std::vector<const db::Device *> selected_devices ();
|
||||
std::vector<const db::SubCircuit *> selected_subcircuits ();
|
||||
|
|
@ -232,7 +256,6 @@ private:
|
|||
QColor make_valid_color (const QColor &color);
|
||||
bool produce_highlights_for_net(const db::Net *net, size_t &n_markers, const std::map<db::LayerProperties, lay::LayerPropertiesConstIterator> &display_by_lp, const std::vector<db::DCplxTrans> &tv);
|
||||
bool produce_highlights_for_device (const db::Device *device, size_t &n_markers, const std::vector<db::DCplxTrans> &tv);
|
||||
bool produce_highlights_for_subcircuit (const db::SubCircuit *subcircuit, size_t &n_markers, const std::vector<db::DCplxTrans> &tv);
|
||||
bool produce_highlights_for_circuit (const db::Circuit *circuit, size_t &n_markers, const std::vector<db::DCplxTrans> &tv);
|
||||
void configure_marker (lay::Marker *marker, bool with_fill);
|
||||
void rerun_macro ();
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "layNetlistBrowserTreeModel.h"
|
||||
#include "layIndexedNetlistModel.h"
|
||||
#include "layNetlistCrossReferenceModel.h"
|
||||
#include "layNetlistBrowserModel.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QIcon>
|
||||
|
|
@ -257,6 +258,45 @@ NetlistBrowserTreeModel::build_circuits_to_index (size_t nprod, const std::pair<
|
|||
}
|
||||
}
|
||||
|
||||
static bool is_compatible (const std::pair<const db::Circuit *, const db::Circuit *> &a, const std::pair<const db::Circuit *, const db::Circuit *> &b)
|
||||
{
|
||||
if (a.first && b.first && a.first == b.first) {
|
||||
return true;
|
||||
} else if (a.second && b.second && a.second == b.second) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex
|
||||
NetlistBrowserTreeModel::index_from_netpath (const NetlistObjectsPath &path) const
|
||||
{
|
||||
QModelIndex idx;
|
||||
|
||||
idx = index_from_circuits (path.root);
|
||||
|
||||
for (NetlistObjectsPath::path_iterator p = path.path.begin (); p != path.path.end () && idx.isValid (); ++p) {
|
||||
|
||||
std::pair<const db::Circuit *, const db::Circuit *> sc (p->first ? p->first->circuit_ref () : 0, p->second ? p->second->circuit_ref (): 0);
|
||||
std::pair<const db::Circuit *, const db::Circuit *> circuit = circuits_from_index (idx);
|
||||
|
||||
size_t count = mp_indexer->child_circuit_count (circuit);
|
||||
for (size_t n = count; n > 0; ) {
|
||||
--n;
|
||||
std::pair<const db::Circuit *, const db::Circuit *> cc = mp_indexer->child_circuit_from_index (circuit, n).first;
|
||||
if (is_compatible (sc, cc)) {
|
||||
circuit = cc;
|
||||
idx = index (n, 0, idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
QModelIndex
|
||||
NetlistBrowserTreeModel::index_from_circuits (const std::pair<const db::Circuit *, const db::Circuit *> &circuits) const
|
||||
{
|
||||
|
|
@ -382,7 +422,7 @@ NetlistBrowserTreeModel::parent (const QModelIndex &index) const
|
|||
|
||||
nprod /= nnlast;
|
||||
|
||||
return createIndex (int (ids / nprod - 1), index.column (), reinterpret_cast<void *> (ids));
|
||||
return createIndex (int (ids / nprod - 1), 0, reinterpret_cast<void *> (ids));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ namespace lay
|
|||
{
|
||||
|
||||
class IndexedNetlistModel;
|
||||
struct NetlistObjectsPath;
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// NetlistBrowserTreeModel definition
|
||||
|
|
@ -77,6 +78,7 @@ public:
|
|||
|
||||
std::pair<const db::Circuit *, const db::Circuit *> circuits_from_index (const QModelIndex &index) const;
|
||||
QModelIndex index_from_circuits (const std::pair<const db::Circuit *, const db::Circuit *> &circuits) const;
|
||||
QModelIndex index_from_netpath (const NetlistObjectsPath &path) const;
|
||||
|
||||
private:
|
||||
NetlistBrowserTreeModel (const NetlistBrowserTreeModel &);
|
||||
|
|
|
|||
|
|
@ -308,6 +308,161 @@ const db::Circuit *NetlistCrossReferenceModel::second_circuit_for (const db::Cir
|
|||
return mp_cross_ref->other_circuit_for (first);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO: borrowed from dbNetlistCrossReference.cc
|
||||
|
||||
static int string_value_compare (const std::string &a, const std::string &b)
|
||||
{
|
||||
return a == b ? 0 : (a < b ? -1 : 1);
|
||||
}
|
||||
|
||||
template <class Obj>
|
||||
struct by_expanded_name_value_compare
|
||||
{
|
||||
int operator() (const Obj &a, const Obj &b) const
|
||||
{
|
||||
return string_value_compare (a.expanded_name (), b.expanded_name ());
|
||||
}
|
||||
};
|
||||
|
||||
template <class Obj> struct net_object_compare;
|
||||
|
||||
template <>
|
||||
struct net_object_compare<db::NetSubcircuitPinRef>
|
||||
{
|
||||
int operator() (const db::NetSubcircuitPinRef &a, const db::NetSubcircuitPinRef &b) const
|
||||
{
|
||||
int ct = by_expanded_name_value_compare<db::SubCircuit> () (*a.subcircuit (), *b.subcircuit ());
|
||||
if (ct == 0) {
|
||||
return by_expanded_name_value_compare<db::Pin> () (*a.pin (), *b.pin ());
|
||||
} else {
|
||||
return ct;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class Obj, class ValueCompare>
|
||||
struct two_pointer_compare
|
||||
{
|
||||
int operator() (const Obj *a, const Obj *b) const
|
||||
{
|
||||
if ((a == 0) != (b == 0)) {
|
||||
return (a == 0) > (b == 0) ? -1 : 1;
|
||||
}
|
||||
if (a != 0) {
|
||||
return ValueCompare () (*a, *b);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class Obj, class ValueCompare>
|
||||
struct two_pair_compare
|
||||
{
|
||||
bool operator() (const std::pair<const Obj *, const Obj *> &a, const std::pair<const Obj *, const Obj *> &b)
|
||||
{
|
||||
int ct = two_pointer_compare<Obj, ValueCompare> () (a.first, b.first);
|
||||
if (ct != 0) {
|
||||
return ct < 0;
|
||||
}
|
||||
return two_pointer_compare<Obj, ValueCompare> () (a.second, b.second) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct SortNetSubCircuitPins
|
||||
: public two_pair_compare<db::NetSubcircuitPinRef, net_object_compare<db::NetSubcircuitPinRef> >
|
||||
{
|
||||
// .. nothing yet ..
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void NetlistCrossReferenceModel::ensure_subcircuit_data_built () const
|
||||
{
|
||||
if (! m_per_subcircuit_data.empty ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build the net to subcircuit ref table
|
||||
for (db::NetlistCrossReference::circuits_iterator c = mp_cross_ref->begin_circuits (); c != mp_cross_ref->end_circuits (); ++c) {
|
||||
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (*c);
|
||||
if (! data) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (db::NetlistCrossReference::PerCircuitData::subcircuit_pairs_type::const_iterator sc = data->subcircuits.begin (); sc != data->subcircuits.end (); ++sc) {
|
||||
|
||||
const std::pair<const db::SubCircuit *, const db::SubCircuit *> &sc_pair = sc->pair;
|
||||
if (sc_pair.first && sc_pair.second) {
|
||||
|
||||
PerSubCircuitCacheData &sc_data = m_per_subcircuit_data [sc_pair];
|
||||
|
||||
std::multimap<const db::Net *, const db::NetSubcircuitPinRef *> first_net_to_other_netref;
|
||||
for (size_t i = 0; i < sc_pair.second->circuit_ref ()->pin_count (); ++i) {
|
||||
const db::NetSubcircuitPinRef *n2 = sc_pair.second->netref_for_pin (i);
|
||||
if (n2) {
|
||||
const db::Net *n1 = mp_cross_ref->other_net_for (n2->net ());
|
||||
if (n1) {
|
||||
first_net_to_other_netref.insert (std::make_pair (n1, n2));
|
||||
} else {
|
||||
sc_data.nets_per_pins.push_back (std::pair<const db::NetSubcircuitPinRef *, const db::NetSubcircuitPinRef *> (0, n2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sc_pair.first->circuit_ref ()->pin_count (); ++i) {
|
||||
const db::NetSubcircuitPinRef *n1 = sc_pair.first->netref_for_pin (i);
|
||||
if (n1) {
|
||||
const db::NetSubcircuitPinRef *n2 = 0;
|
||||
std::multimap<const db::Net *, const db::NetSubcircuitPinRef *>::iterator m = first_net_to_other_netref.find (n1->net ());
|
||||
if (m != first_net_to_other_netref.end () && m->first == n1->net ()) {
|
||||
n2 = m->second;
|
||||
first_net_to_other_netref.erase (m);
|
||||
}
|
||||
sc_data.nets_per_pins.push_back (std::make_pair (n1, n2));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort (sc_data.nets_per_pins.begin (), sc_data.nets_per_pins.end (), SortNetSubCircuitPins ());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
size_t NetlistCrossReferenceModel::subcircuit_pin_count (const subcircuit_pair &subcircuits) const
|
||||
{
|
||||
ensure_subcircuit_data_built ();
|
||||
|
||||
std::map<std::pair<const db::SubCircuit *, const db::SubCircuit *>, PerSubCircuitCacheData>::const_iterator sc = m_per_subcircuit_data.find (subcircuits);
|
||||
if (sc != m_per_subcircuit_data.end ()) {
|
||||
return sc->second.nets_per_pins.size ();
|
||||
} else {
|
||||
return std::max (subcircuits.first ? subcircuits.first->circuit_ref ()->pin_count () : 0, subcircuits.second ? subcircuits.second->circuit_ref ()->pin_count () : 0);
|
||||
}
|
||||
}
|
||||
|
||||
IndexedNetlistModel::net_subcircuit_pin_pair NetlistCrossReferenceModel::subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const
|
||||
{
|
||||
ensure_subcircuit_data_built ();
|
||||
|
||||
std::map<std::pair<const db::SubCircuit *, const db::SubCircuit *>, PerSubCircuitCacheData>::const_iterator sc = m_per_subcircuit_data.find (subcircuits);
|
||||
if (sc != m_per_subcircuit_data.end ()) {
|
||||
if (index < sc->second.nets_per_pins.size ()) {
|
||||
return sc->second.nets_per_pins [index];
|
||||
} else {
|
||||
return IndexedNetlistModel::net_subcircuit_pin_pair (0, 0);
|
||||
}
|
||||
} else {
|
||||
return IndexedNetlistModel::net_subcircuit_pin_pair (subcircuits.first ? subcircuits.first->netref_for_pin (index) : 0, subcircuits.second ? subcircuits.second->netref_for_pin (index) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
IndexedNetlistModel::net_subcircuit_pin_pair NetlistCrossReferenceModel::net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const
|
||||
{
|
||||
const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ public:
|
|||
virtual size_t net_count (const circuit_pair &circuits) const;
|
||||
virtual size_t net_terminal_count (const net_pair &nets) const;
|
||||
virtual size_t net_subcircuit_pin_count (const net_pair &nets) const;
|
||||
virtual size_t subcircuit_pin_count (const subcircuit_pair &subcircuits) const;
|
||||
virtual size_t net_pin_count (const net_pair &nets) const;
|
||||
virtual size_t device_count (const circuit_pair &circuits) const;
|
||||
virtual size_t pin_count (const circuit_pair &circuits) const;
|
||||
|
|
@ -65,6 +66,7 @@ public:
|
|||
virtual const db::Net *second_net_for (const db::Net *first) const;
|
||||
virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const;
|
||||
virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const;
|
||||
virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &nets, size_t index) const;
|
||||
virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const;
|
||||
virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const;
|
||||
virtual std::pair<device_pair, Status> device_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
|
|
@ -95,6 +97,11 @@ public:
|
|||
std::map<std::pair<const db::SubCircuit *, const db::SubCircuit *>, size_t> index_of_subcircuits;
|
||||
};
|
||||
|
||||
struct PerSubCircuitCacheData
|
||||
{
|
||||
std::vector<std::pair<const db::NetSubcircuitPinRef *, const db::NetSubcircuitPinRef *> > nets_per_pins;
|
||||
};
|
||||
|
||||
tl::weak_ptr<db::NetlistCrossReference> mp_cross_ref;
|
||||
mutable std::map<net_pair, circuit_pair> m_parents_of_nets;
|
||||
mutable std::map<device_pair, circuit_pair> m_parents_of_devices;
|
||||
|
|
@ -104,6 +111,9 @@ public:
|
|||
mutable std::vector<circuit_pair> m_top_level_circuits;
|
||||
mutable std::map<std::pair<const db::Circuit *, const db::Circuit *>, PerCircuitCacheData> m_per_circuit_data;
|
||||
mutable std::map<std::pair<const db::Circuit *, const db::Circuit *>, size_t> m_index_of_circuits;
|
||||
mutable std::map<std::pair<const db::SubCircuit *, const db::SubCircuit *>, PerSubCircuitCacheData> m_per_subcircuit_data;
|
||||
|
||||
void ensure_subcircuit_data_built () const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -809,15 +809,31 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
|
|||
|
||||
} else {
|
||||
|
||||
// The array (or single instance) must be iterated instance
|
||||
// by instance
|
||||
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ++p) {
|
||||
size_t qid = 0;
|
||||
|
||||
// The array (or single instance) must be iterated instance by instance
|
||||
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ) {
|
||||
|
||||
test_snapshot (0);
|
||||
db::ICplxTrans t (cell_inst.complex_trans (*p));
|
||||
db::Box new_vp = db::Box (t.inverted () * *v);
|
||||
draw_boxes (drawing_context, new_ci, trans * t, new_vp, level + 1);
|
||||
|
||||
if (p.quad_id () > 0 && p.quad_id () != qid) {
|
||||
|
||||
qid = p.quad_id ();
|
||||
|
||||
// if the quad is very small we don't gain anything from looking further into the quad - skip this one
|
||||
db::DBox qb = trans * cell_inst.quad_box (p, bc);
|
||||
if (qb.width () < 1.0 && qb.height () < 1.0) {
|
||||
p.skip_quad ();
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
++p;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -986,7 +1002,6 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
|
|||
++inst;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1582,6 +1597,8 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
|
|||
db::Shape last_array;
|
||||
|
||||
size_t current_quad_id = 0;
|
||||
size_t current_array_quad_id = 0;
|
||||
|
||||
db::ShapeIterator shape (shapes.begin_touching (*v, db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Edges | db::ShapeIterator::Paths, mp_prop_sel, m_inv_prop_sel));
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
|
|
@ -1596,16 +1613,18 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
|
|||
}
|
||||
|
||||
if (skip) {
|
||||
|
||||
shape.skip_quad ();
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (shape.in_array ()) {
|
||||
|
||||
bool simplified = false;
|
||||
|
||||
if (shape.in_array () && last_array != shape.array ()) {
|
||||
if (last_array != shape.array ()) {
|
||||
|
||||
last_array = shape.array ();
|
||||
current_array_quad_id = 0;
|
||||
|
||||
bool simplified = false;
|
||||
|
||||
if (last_array.type () == db::Shape::PolygonPtrArray) {
|
||||
simplified = draw_array_simplified<db::Shape::polygon_ptr_array_type> (mp_renderer.get (), last_array, frame, vertex, trans);
|
||||
|
|
@ -1619,17 +1638,42 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
|
|||
simplified = draw_array_simplified<db::Shape::short_box_array_type> (mp_renderer.get (), last_array, frame, vertex, trans);
|
||||
}
|
||||
|
||||
if (simplified) {
|
||||
shape.finish_array ();
|
||||
// continue with the next shape, array or quad
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (simplified) {
|
||||
shape.finish_array ();
|
||||
} else {
|
||||
mp_renderer->draw (*shape, trans, fill, frame, vertex, text);
|
||||
++shape;
|
||||
} else {
|
||||
current_array_quad_id = 0;
|
||||
}
|
||||
|
||||
// try whether the array quad can be simplified
|
||||
|
||||
size_t aqid = shape.array_quad_id ();
|
||||
if (aqid != 0 && aqid != current_array_quad_id) {
|
||||
|
||||
current_array_quad_id = aqid;
|
||||
|
||||
db::DBox qbbox = trans * shape.array_quad_box ();
|
||||
if (qbbox.width () < 1.5 && qbbox.height () < 1.5) {
|
||||
|
||||
// draw a single box instead of the quad
|
||||
mp_renderer->draw (qbbox, fill, frame, vertex, text);
|
||||
shape.skip_array_quad ();
|
||||
|
||||
// continue with the next shape, array or quad
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mp_renderer->draw (*shape, trans, fill, frame, vertex, text);
|
||||
++shape;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1727,7 +1771,9 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
|
|||
|
||||
} else if (anything) {
|
||||
|
||||
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ++p) {
|
||||
size_t qid = 0;
|
||||
|
||||
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ) {
|
||||
|
||||
if (! m_draw_array_border_instances ||
|
||||
p.index_a () <= 0 || (unsigned long)p.index_a () == amax - 1 || p.index_b () <= 0 || (unsigned long)p.index_b () == bmax - 1) {
|
||||
|
|
@ -1736,6 +1782,21 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
|
|||
db::Box new_vp = db::Box (t.inverted () * *v);
|
||||
draw_layer (from_level, to_level, new_ci, trans * t, new_vp, level + 1, fill, frame, vertex, text, update_snapshot);
|
||||
|
||||
if (p.quad_id () > 0 && p.quad_id () != qid) {
|
||||
|
||||
qid = p.quad_id ();
|
||||
|
||||
// if the quad is very small we don't gain anything from looking further into the quad - skip this one
|
||||
db::DBox qb = trans * cell_inst.quad_box (p, bc);
|
||||
if (qb.width () < 1.0 && qb.height () < 1.0) {
|
||||
p.skip_quad ();
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
++p;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,12 +128,9 @@ TipDialog::no_pressed ()
|
|||
accept ();
|
||||
}
|
||||
|
||||
bool
|
||||
TipDialog::do_exec_dialog (button_type *button)
|
||||
static std::pair<bool, int>
|
||||
tip_dialog_status (const std::string &key)
|
||||
{
|
||||
bool must_show = true;
|
||||
mp_res = button;
|
||||
|
||||
std::string th;
|
||||
if (lay::Dispatcher::instance ()) {
|
||||
lay::Dispatcher::instance ()->config_get (cfg_tip_window_hidden, th);
|
||||
|
|
@ -148,20 +145,39 @@ TipDialog::do_exec_dialog (button_type *button)
|
|||
}
|
||||
int r = -1;
|
||||
ex.test ("=") && ex.try_read (r);
|
||||
if (k == m_key) {
|
||||
if (r >= 0) {
|
||||
*mp_res = button_type (r);
|
||||
}
|
||||
must_show = false;
|
||||
break;
|
||||
if (k == key) {
|
||||
return std::make_pair (false, r);
|
||||
}
|
||||
ex.test (",");
|
||||
}
|
||||
|
||||
if (must_show) {
|
||||
return std::make_pair (true, -1);
|
||||
}
|
||||
|
||||
bool
|
||||
TipDialog::will_be_shown ()
|
||||
{
|
||||
return tip_dialog_status (m_key).first;
|
||||
}
|
||||
|
||||
bool
|
||||
TipDialog::do_exec_dialog (button_type *button)
|
||||
{
|
||||
mp_res = button;
|
||||
|
||||
std::string th;
|
||||
if (lay::Dispatcher::instance ()) {
|
||||
lay::Dispatcher::instance ()->config_get (cfg_tip_window_hidden, th);
|
||||
}
|
||||
|
||||
std::pair<bool, int> td_status = tip_dialog_status (m_key);
|
||||
if (td_status.first) {
|
||||
exec ();
|
||||
return true;
|
||||
} else {
|
||||
if (td_status.second >= 0) {
|
||||
*mp_res = button_type (td_status.second);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,11 @@ public:
|
|||
*/
|
||||
~TipDialog ();
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the tip dialog will be shown
|
||||
*/
|
||||
bool will_be_shown ();
|
||||
|
||||
/**
|
||||
* @brief Show the dialog
|
||||
*
|
||||
|
|
|
|||
|
|
@ -183,7 +183,8 @@ SOURCES = \
|
|||
layGenericSyntaxHighlighter.cc \
|
||||
layDispatcher.cc \
|
||||
laySelectCellViewForm.cc \
|
||||
layLayoutStatisticsForm.cc
|
||||
layLayoutStatisticsForm.cc \
|
||||
gsiDeclLayNetlistBrowserDialog.cc
|
||||
|
||||
HEADERS = \
|
||||
gtf.h \
|
||||
|
|
|
|||
|
|
@ -44,90 +44,98 @@ TEST (1)
|
|||
QModelIndex inv2Index = model->index (0, 0, QModelIndex ());
|
||||
|
||||
EXPECT_EQ (model->hasChildren (inv2Index), true);
|
||||
// 4 subnodes
|
||||
EXPECT_EQ (model->rowCount (inv2Index), 3);
|
||||
// 5 pins, 5 nets, 0 subcircuits, 4 devices
|
||||
EXPECT_EQ (model->rowCount (inv2Index), 14);
|
||||
QModelIndex sn_pins = model->index (0, 0, inv2Index);
|
||||
QModelIndex sn_nets = model->index (1, 0, inv2Index);
|
||||
QModelIndex sn_devices = model->index (2, 0, inv2Index);
|
||||
// Pins
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::UserRole).toString ()), "IN");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::DisplayRole).toString ()), "IN");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Index), Qt::DisplayRole).toString ()), "$1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2Index), Qt::DisplayRole).toString ()), "OUT");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, inv2Index), Qt::DisplayRole).toString ()), "$3");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, inv2Index), Qt::DisplayRole).toString ()), "$4");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::UserRole).toString ()), "IN|NIN");
|
||||
EXPECT_EQ (model->parent (model->index (0, 0, sn_pins)) == model->parent (model->index (0, 3, sn_pins)), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::DisplayRole).toString ()), "IN");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_pins), Qt::DisplayRole).toString ()), "$1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, sn_pins), Qt::DisplayRole).toString ()), "OUT");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, sn_pins), Qt::DisplayRole).toString ()), "$3");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, sn_pins), Qt::DisplayRole).toString ()), "$4");
|
||||
// Nets
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (5, 0, inv2Index), Qt::UserRole).toString ()), "NIN");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (5, 0, inv2Index), Qt::DisplayRole).toString ()), "NIN");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (5, 2, inv2Index), Qt::DisplayRole).toString ()), "NIN (3)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (6, 0, inv2Index), Qt::DisplayRole).toString ()), "NOUT");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (6, 2, inv2Index), Qt::DisplayRole).toString ()), "NOUT (3)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (7, 0, inv2Index), Qt::DisplayRole).toString ()), "$2");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (7, 2, inv2Index), Qt::DisplayRole).toString ()), "$2 (5)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (8, 0, inv2Index), Qt::DisplayRole).toString ()), "$4");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (8, 2, inv2Index), Qt::DisplayRole).toString ()), "$4 (3)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (9, 0, inv2Index), Qt::DisplayRole).toString ()), "$5");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (9, 2, inv2Index), Qt::DisplayRole).toString ()), "$5 (3)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::UserRole).toString ()), "NIN");
|
||||
EXPECT_EQ (model->parent (model->index (0, 0, sn_nets)) == model->parent (model->index (0, 3, sn_nets)), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::DisplayRole).toString ()), "NIN");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_nets), Qt::DisplayRole).toString ()), "NIN (3)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_nets), Qt::DisplayRole).toString ()), "NOUT");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, sn_nets), Qt::DisplayRole).toString ()), "NOUT (3)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, sn_nets), Qt::DisplayRole).toString ()), "$2");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, sn_nets), Qt::DisplayRole).toString ()), "$2 (5)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, sn_nets), Qt::DisplayRole).toString ()), "$4");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, sn_nets), Qt::DisplayRole).toString ()), "$4 (3)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, sn_nets), Qt::DisplayRole).toString ()), "$5");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (4, 2, sn_nets), Qt::DisplayRole).toString ()), "$5 (3)");
|
||||
// No Subcircuits
|
||||
// Devices
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (10, 0, inv2Index), Qt::UserRole).toString ()), "$1|PMOS");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (10, 0, inv2Index), Qt::DisplayRole).toString ()), "PMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (10, 2, inv2Index), Qt::DisplayRole).toString ()), "$1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (11, 0, inv2Index), Qt::DisplayRole).toString ()), "PMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (11, 2, inv2Index), Qt::DisplayRole).toString ()), "$2");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, inv2Index), Qt::DisplayRole).toString ()), "NMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (12, 2, inv2Index), Qt::DisplayRole).toString ()), "$3");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (13, 0, inv2Index), Qt::DisplayRole).toString ()), "NMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (13, 2, inv2Index), Qt::DisplayRole).toString ()), "$4");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::UserRole).toString ()), "$1|PMOS");
|
||||
EXPECT_EQ (model->parent (model->index (0, 0, sn_devices)) == model->parent (model->index (0, 3, sn_devices)), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::DisplayRole).toString ()), "PMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_devices), Qt::DisplayRole).toString ()), "$1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_devices), Qt::DisplayRole).toString ()), "PMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, sn_devices), Qt::DisplayRole).toString ()), "$2");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, sn_devices), Qt::DisplayRole).toString ()), "NMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, sn_devices), Qt::DisplayRole).toString ()), "$3");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, sn_devices), Qt::DisplayRole).toString ()), "NMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, sn_devices), Qt::DisplayRole).toString ()), "$4");
|
||||
|
||||
EXPECT_EQ (model->hasChildren (ringoIndex), true);
|
||||
// 0 pins, 12 nets, 10 subcircuits, 0 devices
|
||||
EXPECT_EQ (model->rowCount (ringoIndex), 22);
|
||||
EXPECT_EQ (model->rowCount (ringoIndex), 2);
|
||||
sn_nets = model->index (0, 0, ringoIndex);
|
||||
QModelIndex sn_subcircuits = model->index (1, 0, ringoIndex);
|
||||
// Pins
|
||||
// Nets
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoIndex), Qt::UserRole).toString ()), "FB");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoIndex), Qt::DisplayRole).toString ()), "FB (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, ringoIndex), Qt::DisplayRole).toString ()), "VDD (10)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoIndex), Qt::DisplayRole).toString ()), "VSS (10)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, ringoIndex), Qt::DisplayRole).toString ()), "$4 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (4, 2, ringoIndex), Qt::DisplayRole).toString ()), "$5 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (5, 2, ringoIndex), Qt::DisplayRole).toString ()), "$6 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (6, 2, ringoIndex), Qt::DisplayRole).toString ()), "$7 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (7, 2, ringoIndex), Qt::DisplayRole).toString ()), "$8 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (8, 2, ringoIndex), Qt::DisplayRole).toString ()), "$9 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (9, 2, ringoIndex), Qt::DisplayRole).toString ()), "$10 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (10, 2, ringoIndex), Qt::DisplayRole).toString ()), "$11 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (11, 2, ringoIndex), Qt::DisplayRole).toString ()), "$12 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::UserRole).toString ()), "FB");
|
||||
EXPECT_EQ (model->parent (model->index (0, 0, sn_nets)) == model->parent (model->index (0, 3, sn_nets)), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_nets), Qt::DisplayRole).toString ()), "FB (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, sn_nets), Qt::DisplayRole).toString ()), "VDD (10)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, sn_nets), Qt::DisplayRole).toString ()), "VSS (10)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, sn_nets), Qt::DisplayRole).toString ()), "$4 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (4, 2, sn_nets), Qt::DisplayRole).toString ()), "$5 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (5, 2, sn_nets), Qt::DisplayRole).toString ()), "$6 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (6, 2, sn_nets), Qt::DisplayRole).toString ()), "$7 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (7, 2, sn_nets), Qt::DisplayRole).toString ()), "$8 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (8, 2, sn_nets), Qt::DisplayRole).toString ()), "$9 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (9, 2, sn_nets), Qt::DisplayRole).toString ()), "$10 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (10, 2, sn_nets), Qt::DisplayRole).toString ()), "$11 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (11, 2, sn_nets), Qt::DisplayRole).toString ()), "$12 (2)");
|
||||
// Subcircuits
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, ringoIndex), Qt::UserRole).toString ()), "INV2|$1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, ringoIndex), Qt::DisplayRole).toString ()), "<a href='int:circuit?id=0'>INV2</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (12, 2, ringoIndex), Qt::DisplayRole).toString ()), "$1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (21, 0, ringoIndex), Qt::DisplayRole).toString ()), "<a href='int:circuit?id=0'>INV2</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (21, 2, ringoIndex), Qt::DisplayRole).toString ()), "$10");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_subcircuits), Qt::UserRole).toString ()), "INV2|$1");
|
||||
EXPECT_EQ (model->parent (model->index (0, 0, sn_subcircuits)) == model->parent (model->index (0, 3, sn_subcircuits)), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_subcircuits), Qt::DisplayRole).toString ()), "<a href='int:netlist?path=0'>INV2</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_subcircuits), Qt::DisplayRole).toString ()), "$1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (9, 0, sn_subcircuits), Qt::DisplayRole).toString ()), "<a href='int:netlist?path=0'>INV2</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (9, 2, sn_subcircuits), Qt::DisplayRole).toString ()), "$10");
|
||||
// Devices
|
||||
|
||||
// OUT pin of INV2 has a single child node which is the "NOUT" net
|
||||
QModelIndex inv2PinOutIndex = model->index (2, 0, inv2Index);
|
||||
EXPECT_EQ (model->parent (inv2PinOutIndex) == inv2Index, true);
|
||||
// OUT pin of INV2 is identical with the "NOUT" net
|
||||
QModelIndex inv2PinOutIndex = model->index (2, 0, model->index (0, 0, inv2Index));
|
||||
EXPECT_EQ (model->parent (inv2PinOutIndex) == model->index (0, 0, inv2Index), true);
|
||||
EXPECT_EQ (model->hasChildren (inv2PinOutIndex), true);
|
||||
EXPECT_EQ (model->rowCount (inv2PinOutIndex), 1);
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PinOutIndex), Qt::DisplayRole).toString ()), "NOUT");
|
||||
|
||||
QModelIndex inv2PinOutIndexNet = model->index (0, 0, inv2PinOutIndex);
|
||||
EXPECT_EQ (model->parent (inv2PinOutIndexNet) == inv2PinOutIndex, true);
|
||||
EXPECT_EQ (model->hasChildren (inv2PinOutIndexNet), false);
|
||||
EXPECT_EQ (model->rowCount (inv2PinOutIndexNet), 0);
|
||||
EXPECT_EQ (model->rowCount (inv2PinOutIndex), 3);
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PinOutIndex), Qt::DisplayRole).toString ()), "D / PMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
|
||||
|
||||
// NOUT net has 1 pin, 2 devices, 0 subcircuits
|
||||
QModelIndex inv2NOutIndex = model->index (6, 0, inv2Index);
|
||||
EXPECT_EQ (model->parent (inv2NOutIndex) == inv2Index, true);
|
||||
QModelIndex inv2NOutIndex = model->index (1, 0, model->index (1, 0, inv2Index));
|
||||
EXPECT_EQ (model->parent (inv2NOutIndex) == model->index (1, 0, inv2Index), true);
|
||||
EXPECT_EQ (model->hasChildren (inv2NOutIndex), true);
|
||||
EXPECT_EQ (model->rowCount (inv2NOutIndex), 3);
|
||||
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2NOutIndex), Qt::UserRole).toString ()), "D|PMOS|$2");
|
||||
EXPECT_EQ (model->parent (model->index (0, 0, inv2NOutIndex)) == model->parent (model->index (0, 3, inv2NOutIndex)), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "D / PMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "<a href='int:device?id=24'>$2</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "$2");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "D / NMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "<a href='int:device?id=56'>$4</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "<a href='int:pin?id=18'>OUT</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "$4");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "OUT");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "");
|
||||
EXPECT_EQ (model->parent (model->index (2, 0, inv2NOutIndex)) == model->parent (model->index (2, 3, inv2NOutIndex)), true);
|
||||
|
||||
// no children for pins on nets
|
||||
QModelIndex inv2NOutPinOutIndex = model->index (2, 0, inv2NOutIndex);
|
||||
|
|
@ -137,6 +145,9 @@ TEST (1)
|
|||
|
||||
// a MOS3 transistor has three other terminals
|
||||
QModelIndex inv2NOutDeviceIndex = model->index (0, 0, inv2NOutIndex);
|
||||
QModelIndex b = model->index (0, 0, inv2NOutIndex);
|
||||
EXPECT_EQ (b.parent () == inv2NOutDeviceIndex.parent (), true);
|
||||
EXPECT_EQ (b.model () == inv2NOutDeviceIndex.model (), true);
|
||||
EXPECT_EQ (model->parent (inv2NOutDeviceIndex) == inv2NOutIndex, true);
|
||||
EXPECT_EQ (model->hasChildren (inv2NOutDeviceIndex), true);
|
||||
EXPECT_EQ (model->rowCount (inv2NOutDeviceIndex), 3);
|
||||
|
|
@ -144,67 +155,76 @@ TEST (1)
|
|||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2NOutDeviceIndex), Qt::UserRole).toString ()), "S|$5");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "S");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "G");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "D");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "D (already seen)");
|
||||
|
||||
QModelIndex inv2NOutDeviceGateIndex = model->index (1, 0, inv2NOutDeviceIndex);
|
||||
EXPECT_EQ (model->parent (inv2NOutDeviceGateIndex) == inv2NOutDeviceIndex, true);
|
||||
EXPECT_EQ (model->hasChildren (inv2NOutDeviceGateIndex), false);
|
||||
EXPECT_EQ (model->rowCount (inv2NOutDeviceGateIndex), 0);
|
||||
EXPECT_EQ (model->hasChildren (inv2NOutDeviceGateIndex), true);
|
||||
EXPECT_EQ (model->rowCount (inv2NOutDeviceGateIndex), 5);
|
||||
|
||||
// FB net has 0 pin, 0 devices, 2 subcircuits
|
||||
QModelIndex ringoFbIndex = model->index (0, 0, ringoIndex);
|
||||
EXPECT_EQ (model->parent (ringoFbIndex) == ringoIndex, true);
|
||||
QModelIndex ringoFbIndex = model->index (0, 0, sn_nets);
|
||||
EXPECT_EQ (model->parent (ringoFbIndex) == sn_nets, true);
|
||||
EXPECT_EQ (model->hasChildren (ringoFbIndex), true);
|
||||
EXPECT_EQ (model->rowCount (ringoFbIndex), 2);
|
||||
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbIndex), Qt::UserRole).toString ()), "IN|INV2|$2");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "<a href='int:pin?id=2'>IN</a> / <a href='int:circuit?id=0'>INV2</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoFbIndex), Qt::DisplayRole).toString ()), "<a href='int:subcircuit?id=23'>$2</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "<a href='int:pin?id=34'>$1</a> / <a href='int:circuit?id=0'>INV2</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, ringoFbIndex), Qt::DisplayRole).toString ()), "<a href='int:subcircuit?id=7'>$1</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "IN / <a href='int:netlist?path=0'>INV2</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoFbIndex), Qt::DisplayRole).toString ()), "<a href='int:netlist?path=1,1,1'>$2</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "$1 / <a href='int:netlist?path=0'>INV2</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, ringoFbIndex), Qt::DisplayRole).toString ()), "<a href='int:netlist?path=1,1,0'>$1</a>");
|
||||
|
||||
QModelIndex ringoFbSubcircuit2Index = model->index (0, 0, ringoFbIndex);
|
||||
EXPECT_EQ (model->parent (ringoFbSubcircuit2Index) == ringoFbIndex, true);
|
||||
EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2Index), true);
|
||||
EXPECT_EQ (model->rowCount (ringoFbSubcircuit2Index), 5);
|
||||
EXPECT_EQ (model->rowCount (ringoFbSubcircuit2Index), 1);
|
||||
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbSubcircuit2Index), Qt::UserRole).toString ()), "IN|NIN");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=2'>IN</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=5'>FB</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=34'>$1</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=18'>OUT</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=53'>$4</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=50'>$3</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=37'>VSS</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=66'>$4</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (4, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=21'>VDD</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbSubcircuit2Index), Qt::UserRole).toString ()), "NIN");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "NIN");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "NIN (3)");
|
||||
|
||||
QModelIndex ringoFbSubcircuit2InPinIndex = model->index (1, 0, ringoFbSubcircuit2Index);
|
||||
EXPECT_EQ (model->parent (ringoFbSubcircuit2InPinIndex) == ringoFbSubcircuit2Index, true);
|
||||
EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2InPinIndex), false);
|
||||
EXPECT_EQ (model->rowCount (ringoFbSubcircuit2InPinIndex), 0);
|
||||
QModelIndex ringoFbSubcircuit2InsideNetIndex = model->index (0, 0, ringoFbSubcircuit2Index);
|
||||
EXPECT_EQ (model->parent (ringoFbSubcircuit2InsideNetIndex) == ringoFbSubcircuit2Index, true);
|
||||
EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2InsideNetIndex), true);
|
||||
EXPECT_EQ (model->rowCount (ringoFbSubcircuit2InsideNetIndex), 3);
|
||||
|
||||
// Subcircuit 1 of RINGO has 5 pins
|
||||
|
||||
QModelIndex ringoSubcircuit1Index = model->index (12, 0, ringoIndex);
|
||||
EXPECT_EQ (model->parent (ringoSubcircuit1Index) == ringoIndex, true);
|
||||
QModelIndex ringoSubcircuit1Index = model->index (0, 0, sn_subcircuits);
|
||||
EXPECT_EQ (model->parent (ringoSubcircuit1Index) == sn_subcircuits, true);
|
||||
EXPECT_EQ (model->hasChildren (ringoSubcircuit1Index), true);
|
||||
EXPECT_EQ (model->rowCount (ringoSubcircuit1Index), 5);
|
||||
EXPECT_EQ (model->rowCount (ringoSubcircuit1Index), 2);
|
||||
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1Index), Qt::UserRole).toString ()), "OUT");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=18'>OUT</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoSubcircuit1Index), Qt::DisplayRole).toString ()), "");
|
||||
QModelIndex ringoSubcircuit1PinsIndex = model->index (0, 0, ringoSubcircuit1Index);
|
||||
EXPECT_EQ (model->rowCount (ringoSubcircuit1PinsIndex), 5);
|
||||
|
||||
QModelIndex ringoSubcircuit1OutPinIndex = model->index (2, 0, ringoSubcircuit1Index);
|
||||
EXPECT_EQ (model->parent (ringoSubcircuit1OutPinIndex) == ringoSubcircuit1Index, true);
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoSubcircuit1PinsIndex), Qt::UserRole).toString ()), "IN|$5");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoSubcircuit1PinsIndex), Qt::UserRole).toString ()), "FB");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1PinsIndex), Qt::UserRole).toString ()), "OUT");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1PinsIndex), Qt::DisplayRole).toString ()), "OUT");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoSubcircuit1PinsIndex), Qt::DisplayRole).toString ()), "");
|
||||
|
||||
QModelIndex ringoSubcircuit1NodeIndex = model->index (1, 0, ringoSubcircuit1Index);
|
||||
EXPECT_EQ (model->rowCount (ringoSubcircuit1NodeIndex), 3);
|
||||
|
||||
QModelIndex ringoSubcircuit1InsidePinsIndex = model->index (0, 0, ringoSubcircuit1NodeIndex);
|
||||
EXPECT_EQ (model->rowCount (ringoSubcircuit1InsidePinsIndex), 5);
|
||||
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoSubcircuit1InsidePinsIndex), Qt::UserRole).toString ()), "IN|NIN");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoSubcircuit1InsidePinsIndex), Qt::UserRole).toString ()), "$1|$2");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1InsidePinsIndex), Qt::UserRole).toString ()), "OUT|NOUT");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1InsidePinsIndex), Qt::DisplayRole).toString ()), "OUT");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoSubcircuit1InsidePinsIndex), Qt::DisplayRole).toString ()), "NOUT (3)");
|
||||
|
||||
QModelIndex ringoSubcircuit1OutPinIndex = model->index (2, 0, ringoSubcircuit1PinsIndex);
|
||||
EXPECT_EQ (model->parent (ringoSubcircuit1OutPinIndex) == ringoSubcircuit1PinsIndex, true);
|
||||
EXPECT_EQ (model->hasChildren (ringoSubcircuit1OutPinIndex), false);
|
||||
EXPECT_EQ (model->rowCount (ringoSubcircuit1OutPinIndex), 0);
|
||||
|
||||
// Device 1 of INV2 has 3 pins
|
||||
// Device 1 of INV2 has 3 terminals
|
||||
|
||||
QModelIndex inv2Device1Index = model->index (10, 0, inv2Index);
|
||||
EXPECT_EQ (model->parent (inv2Device1Index) == inv2Index, true);
|
||||
QModelIndex inv2Device1Index = model->index (0, 0, sn_devices);
|
||||
EXPECT_EQ (model->parent (inv2Device1Index) == sn_devices, true);
|
||||
EXPECT_EQ (model->hasChildren (inv2Device1Index), true);
|
||||
EXPECT_EQ (model->rowCount (inv2Device1Index), 3);
|
||||
|
||||
|
|
@ -213,8 +233,11 @@ TEST (1)
|
|||
|
||||
QModelIndex inv2Device1GateIndex = model->index (1, 0, inv2Device1Index);
|
||||
EXPECT_EQ (model->parent (inv2Device1GateIndex) == inv2Device1Index, true);
|
||||
EXPECT_EQ (model->hasChildren (inv2Device1GateIndex), false);
|
||||
EXPECT_EQ (model->rowCount (inv2Device1GateIndex), 0);
|
||||
EXPECT_EQ (model->hasChildren (inv2Device1GateIndex), true);
|
||||
EXPECT_EQ (model->rowCount (inv2Device1GateIndex), 3);
|
||||
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Device1GateIndex), Qt::UserRole).toString ()), "G|PMOS|$1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Device1GateIndex), Qt::DisplayRole).toString ()), "G / PMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5] (already seen)");
|
||||
}
|
||||
|
||||
TEST (2)
|
||||
|
|
@ -228,6 +251,7 @@ TEST (2)
|
|||
EXPECT_EQ (model->hasChildren (QModelIndex ()), true);
|
||||
// two circuits
|
||||
EXPECT_EQ (model->rowCount (QModelIndex ()), 4);
|
||||
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, QModelIndex ()), Qt::UserRole).toString ()), "INV2PAIRX");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, QModelIndex ()), Qt::DisplayRole).toString ()), "- ⇔ INV2PAIRX");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, QModelIndex ()), Qt::DisplayRole).toString ()), "");
|
||||
|
|
@ -245,26 +269,33 @@ TEST (2)
|
|||
|
||||
// INV2 circuit node
|
||||
EXPECT_EQ (model->hasChildren (inv2Index), true);
|
||||
EXPECT_EQ (model->rowCount (inv2Index), 14);
|
||||
EXPECT_EQ (model->rowCount (inv2Index), 3);
|
||||
EXPECT_EQ (model->parent (inv2Index).isValid (), false);
|
||||
|
||||
QModelIndex sn_pins = model->index (0, 0, inv2Index);
|
||||
QModelIndex sn_nets = model->index (1, 0, inv2Index);
|
||||
QModelIndex sn_devices = model->index (2, 0, inv2Index);
|
||||
EXPECT_EQ (model->rowCount (sn_pins), 6);
|
||||
EXPECT_EQ (model->rowCount (sn_nets), 6);
|
||||
EXPECT_EQ (model->rowCount (sn_devices), 2);
|
||||
|
||||
// first of pins in INV2 circuit
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::UserRole).toString ()), "$0|$0");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::DisplayRole).toString ()), "$0");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Index), Qt::DisplayRole).toString ()), "$0");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Index), Qt::DisplayRole).toString ()), "$0");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::UserRole).toString ()), "$0|$0|$1|1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::DisplayRole).toString ()), "$0");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_pins), Qt::DisplayRole).toString ()), "$1 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_pins), Qt::DisplayRole).toString ()), "1 (2)");
|
||||
|
||||
// INV2, pin 0 node
|
||||
QModelIndex inv2Pin0Index = model->index (0, 0, inv2Index);
|
||||
QModelIndex inv2Pin0Index = model->index (0, 0, sn_pins);
|
||||
EXPECT_EQ (model->hasChildren (inv2Pin0Index), true);
|
||||
EXPECT_EQ (model->rowCount (inv2Pin0Index), 1);
|
||||
EXPECT_EQ (model->parent (inv2Pin0Index) == inv2Index, true);
|
||||
EXPECT_EQ (model->rowCount (inv2Pin0Index), 2);
|
||||
EXPECT_EQ (model->parent (inv2Pin0Index) == sn_pins, true);
|
||||
|
||||
// INV2, pin 0 has one net node
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Pin0Index), Qt::UserRole).toString ()), "$1|1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Pin0Index), Qt::DisplayRole).toString ()), "$1 ⇔ 1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Pin0Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=9'>$1</a>");
|
||||
std::pair<const db::Net *, const db::Net *> nets = model->net_from_index (model->index_from_id ((void *) 9, 0));
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::UserRole).toString ()), "$0|$0|$1|1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::DisplayRole).toString ()), "$0");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_pins), Qt::DisplayRole).toString ()), "$1 (2)");
|
||||
std::pair<const db::Net *, const db::Net *> nets = model->net_from_index (model->index (0, 0, sn_pins));
|
||||
EXPECT_EQ (nets.first != 0, true);
|
||||
if (nets.first != 0) {
|
||||
EXPECT_EQ (nets.first->expanded_name (), "$1");
|
||||
|
|
@ -273,25 +304,25 @@ TEST (2)
|
|||
if (nets.second != 0) {
|
||||
EXPECT_EQ (nets.second->expanded_name (), "1");
|
||||
}
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Pin0Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=9'>1</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_pins), Qt::DisplayRole).toString ()), "1 (2)");
|
||||
|
||||
// first of nets in INV2 circuit
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (6, 0, inv2Index), Qt::UserRole).toString ()), "$1|1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (6, 0, inv2Index), Qt::DisplayRole).toString ()), "$1 ⇔ 1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (6, 2, inv2Index), Qt::DisplayRole).toString ()), "$1 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (6, 3, inv2Index), Qt::DisplayRole).toString ()), "1 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::UserRole).toString ()), "$1|1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::DisplayRole).toString ()), "$1 ⇔ 1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_nets), Qt::DisplayRole).toString ()), "$1 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_nets), Qt::DisplayRole).toString ()), "1 (2)");
|
||||
|
||||
// INV2, net 1 node
|
||||
QModelIndex inv2Net0Index = model->index (6, 0, inv2Index);
|
||||
QModelIndex inv2Net0Index = model->index (0, 0, sn_nets);
|
||||
EXPECT_EQ (model->hasChildren (inv2Net0Index), true);
|
||||
EXPECT_EQ (model->rowCount (inv2Net0Index), 2);
|
||||
EXPECT_EQ (model->parent (inv2Net0Index) == inv2Index, true);
|
||||
EXPECT_EQ (model->parent (inv2Net0Index) == sn_nets, true);
|
||||
|
||||
// INV2, net 1 has one pin and one terminal at BULK
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Net0Index), Qt::UserRole).toString ()), "B|B|PMOS|PMOS|$1|$1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Net0Index), Qt::DisplayRole).toString ()), "B / PMOS [L=0.25, W=3.5]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "<a href='int:device?id=17'>$1</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "<a href='int:device?id=17'>$1</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "$1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "$1");
|
||||
|
||||
// This terminal connects to a device with four other terminals ..
|
||||
QModelIndex inv2Net0TerminalIndex = model->index (0, 0, inv2Net0Index);
|
||||
|
|
@ -301,14 +332,14 @@ TEST (2)
|
|||
// .. whose second terminal is gate
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0TerminalIndex), Qt::UserRole).toString ()), "G|G|IN|2");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "G");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "<a href='int:net?id=73'>IN</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "<a href='int:net?id=73'>2</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "IN (3)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "2 (3)");
|
||||
|
||||
// The Pin
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0Index), Qt::UserRole).toString ()), "");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0Index), Qt::DisplayRole).toString ()), "");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=5'>$0</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=5'>$0</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "$0");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "$0");
|
||||
|
||||
// This pin does not have children
|
||||
QModelIndex inv2Net0PinIndex = model->index (1, 0, inv2Net0Index);
|
||||
|
|
@ -317,59 +348,49 @@ TEST (2)
|
|||
EXPECT_EQ (model->parent (inv2Net0PinIndex) == inv2Net0Index, true);
|
||||
|
||||
// second of nets in INV2 circuit
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (7, 0, inv2Index), Qt::UserRole).toString ()), "BULK|6");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (7, 0, inv2Index), Qt::DisplayRole).toString ()), "BULK ⇔ 6");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (7, 2, inv2Index), Qt::DisplayRole).toString ()), "BULK (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (7, 3, inv2Index), Qt::DisplayRole).toString ()), "6 (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_nets), Qt::UserRole).toString ()), "BULK|6");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_nets), Qt::DisplayRole).toString ()), "BULK ⇔ 6");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, sn_nets), Qt::DisplayRole).toString ()), "BULK (2)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, sn_nets), Qt::DisplayRole).toString ()), "6 (2)");
|
||||
|
||||
// first of devices in INV2 circuit
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, inv2Index), Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, inv2Index), Qt::DisplayRole).toString ()), "PMOS");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (12, 2, inv2Index), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (12, 3, inv2Index), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::DisplayRole).toString ()), "PMOS");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]");
|
||||
|
||||
QModelIndex inv2PairIndex = model->index (2, 0, QModelIndex ());
|
||||
EXPECT_EQ (model->parent (inv2PairIndex).isValid (), false);
|
||||
|
||||
// INV2PAIR circuit node
|
||||
EXPECT_EQ (model->hasChildren (inv2PairIndex), true);
|
||||
EXPECT_EQ (model->rowCount (inv2PairIndex), 18);
|
||||
EXPECT_EQ (model->rowCount (inv2PairIndex), 3);
|
||||
|
||||
sn_pins = model->index (0, 0, inv2PairIndex);
|
||||
sn_nets = model->index (1, 0, inv2PairIndex);
|
||||
|
||||
// first of pins in INV2 circuit
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairIndex), Qt::UserRole).toString ()), "$4");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairIndex), Qt::DisplayRole).toString ()), "- ⇔ $4");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairIndex), Qt::DisplayRole).toString ()), "");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2PairIndex), Qt::DisplayRole).toString ()), "$4");
|
||||
|
||||
// INV2, pin 0 node
|
||||
QModelIndex inv2PairPin0Index = model->index (0, 0, inv2PairIndex);
|
||||
EXPECT_EQ (model->hasChildren (inv2PairPin0Index), true);
|
||||
EXPECT_EQ (model->rowCount (inv2PairPin0Index), 1);
|
||||
EXPECT_EQ (model->parent (inv2PairPin0Index) == inv2PairIndex, true);
|
||||
|
||||
// INV2, pin 0 has one net node
|
||||
// The pin isnt't connected to any net, left side because there is no match, right side because the pin isn't connected
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairPin0Index), Qt::UserRole).toString ()), "");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairPin0Index), Qt::DisplayRole).toString ()), "-");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairPin0Index), Qt::DisplayRole).toString ()), "");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2PairPin0Index), Qt::DisplayRole).toString ()), "");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::UserRole).toString ()), "$4");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::DisplayRole).toString ()), "- ⇔ $4");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_pins), Qt::DisplayRole).toString ()), "");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_pins), Qt::DisplayRole).toString ()), "");
|
||||
|
||||
// first of nets in INV2 circuit
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (8, 0, inv2PairIndex), Qt::UserRole).toString ()), "$4");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (8, 0, inv2PairIndex), Qt::DisplayRole).toString ()), "$4 ⇔ -");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (8, 2, inv2PairIndex), Qt::DisplayRole).toString ()), "$4 (3)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (8, 3, inv2PairIndex), Qt::DisplayRole).toString ()), "");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::UserRole).toString ()), "$4");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::DisplayRole).toString ()), "$4 ⇔ -");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_nets), Qt::DisplayRole).toString ()), "$4 (3)");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_nets), Qt::DisplayRole).toString ()), "");
|
||||
|
||||
// This net has only left side which has one pin and two subcircuits
|
||||
QModelIndex inv2PairNet0Index = model->index (8, 0, inv2PairIndex);
|
||||
QModelIndex inv2PairNet0Index = model->index (0, 0, sn_nets);
|
||||
EXPECT_EQ (model->hasChildren (inv2PairNet0Index), true);
|
||||
EXPECT_EQ (model->rowCount (inv2PairNet0Index), 3);
|
||||
EXPECT_EQ (model->parent (inv2PairNet0Index) == inv2PairIndex, true);
|
||||
EXPECT_EQ (model->parent (inv2PairNet0Index) == sn_nets, true);
|
||||
|
||||
// The pin
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairNet0Index), Qt::UserRole).toString ()), "");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairNet0Index), Qt::DisplayRole).toString ()), "");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairNet0Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=38'>$3</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairNet0Index), Qt::DisplayRole).toString ()), "$3");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2PairNet0Index), Qt::DisplayRole).toString ()), "");
|
||||
|
||||
// This pin does not have children
|
||||
|
|
@ -380,18 +401,179 @@ TEST (2)
|
|||
|
||||
// The first subcircuit
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2PairNet0Index), Qt::UserRole).toString ()), "OUT|INV2|$1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2PairNet0Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=101'>OUT ⇔ -</a> / <a href='int:circuit?id=1'>INV2 ⇔ -</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2PairNet0Index), Qt::DisplayRole).toString ()), "<a href='int:subcircuit?id=46'>$1</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2PairNet0Index), Qt::DisplayRole).toString ()), "OUT ⇔ - / <a href='int:netlist?path=1'>INV2 ⇔ -</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2PairNet0Index), Qt::DisplayRole).toString ()), "<a href='int:netlist?path=2,2,1'>$1</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2PairNet0Index), Qt::DisplayRole).toString ()), "");
|
||||
|
||||
// This subcircuit has 6 other pins
|
||||
QModelIndex inv2PairNet0SubCircuit0Index = model->index (1, 0, inv2PairNet0Index);
|
||||
EXPECT_EQ (model->hasChildren (inv2PairNet0SubCircuit0Index), true);
|
||||
EXPECT_EQ (model->rowCount (inv2PairNet0SubCircuit0Index), 6);
|
||||
EXPECT_EQ (model->parent (inv2PairNet0SubCircuit0Index) == inv2PairNet0Index, true);
|
||||
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairNet0SubCircuit0Index), Qt::UserRole).toString ()), "$1");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairNet0SubCircuit0Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=5'>$0</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairNet0SubCircuit0Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=170'>$7</a>");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2PairNet0SubCircuit0Index), Qt::DisplayRole).toString ()), "");
|
||||
}
|
||||
|
||||
TEST (3)
|
||||
{
|
||||
db::LayoutToNetlist l2n;
|
||||
l2n.load (tl::testsrc () + "/testdata/lay/l2n_browser.l2n");
|
||||
|
||||
lay::NetColorizer colorizer;
|
||||
std::auto_ptr<lay::NetlistBrowserModel> model (new lay::NetlistBrowserModel (0, &l2n, &colorizer));
|
||||
|
||||
db::Circuit *root = l2n.netlist ()->circuit_by_name ("RINGO");
|
||||
EXPECT_EQ (root != 0, true);
|
||||
|
||||
lay::NetlistObjectsPath path;
|
||||
EXPECT_EQ (model->index_from_path (path).isValid (), false);
|
||||
|
||||
path.root.first = root;
|
||||
|
||||
db::Net *net = root->net_by_name ("FB");
|
||||
EXPECT_EQ (net != 0, true);
|
||||
|
||||
path.net.first = net;
|
||||
|
||||
QModelIndex index = model->index_from_path (path);
|
||||
EXPECT_EQ (index.isValid (), true);
|
||||
|
||||
EXPECT_EQ (tl::to_string (model->data (index, Qt::UserRole).toString ()), "FB");
|
||||
}
|
||||
|
||||
TEST (4)
|
||||
{
|
||||
db::LayoutToNetlist l2n;
|
||||
l2n.load (tl::testsrc () + "/testdata/lay/l2n_browser.l2n");
|
||||
|
||||
lay::NetColorizer colorizer;
|
||||
std::auto_ptr<lay::NetlistBrowserModel> model (new lay::NetlistBrowserModel (0, &l2n, &colorizer));
|
||||
|
||||
db::Circuit *root = l2n.netlist ()->circuit_by_name ("RINGO");
|
||||
EXPECT_EQ (root != 0, true);
|
||||
|
||||
lay::NetlistObjectsPath path;
|
||||
path.root.first = root;
|
||||
|
||||
db::SubCircuit *sc1 = root->begin_subcircuits ().operator-> ();
|
||||
EXPECT_EQ (sc1 != 0, true);
|
||||
path.path.push_back (std::make_pair (sc1, (db::SubCircuit *) 0));
|
||||
|
||||
db::Net *net = sc1->circuit_ref ()->net_by_name ("NOUT");
|
||||
EXPECT_EQ (net != 0, true);
|
||||
|
||||
path.net.first = net;
|
||||
|
||||
QModelIndex index = model->index_from_path (path);
|
||||
EXPECT_EQ (index.isValid (), true);
|
||||
|
||||
EXPECT_EQ (tl::to_string (model->data (index, Qt::UserRole).toString ()), "NOUT");
|
||||
}
|
||||
|
||||
// Netlist object path: single vs. pairs - first
|
||||
TEST (5)
|
||||
{
|
||||
db::LayoutVsSchematic lvs;
|
||||
lvs.load (tl::testsrc () + "/testdata/lay/lvsdb_browser.lvsdb");
|
||||
|
||||
lay::NetColorizer colorizer;
|
||||
std::auto_ptr<lay::NetlistBrowserModel> model (new lay::NetlistBrowserModel (0, &lvs, &colorizer));
|
||||
QModelIndex idx;
|
||||
|
||||
db::Circuit *root = lvs.netlist ()->circuit_by_name ("INV2PAIR");
|
||||
EXPECT_EQ (root != 0, true);
|
||||
db::Circuit *sc = lvs.netlist ()->circuit_by_name ("INV2");
|
||||
EXPECT_EQ (sc != 0, true);
|
||||
|
||||
lay::NetlistObjectPath path;
|
||||
EXPECT_EQ (path.is_null (), true);
|
||||
path.root = root;
|
||||
EXPECT_EQ (path.is_null (), false);
|
||||
|
||||
idx = model->index_from_path (path);
|
||||
EXPECT_EQ (idx.isValid (), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "INV2PAIR|INV2PAIR");
|
||||
EXPECT_EQ (path == model->path_from_index (idx).first (), true);
|
||||
|
||||
path.net = root->net_by_cluster_id (5);
|
||||
idx = model->index_from_path (lay::NetlistObjectsPath::from_first (path));
|
||||
EXPECT_EQ (idx.isValid (), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "$5|4");
|
||||
EXPECT_EQ (path == model->path_from_index (idx).first (), true);
|
||||
|
||||
path.path.push_back (root->subcircuit_by_id (1));
|
||||
EXPECT_EQ (path.path.back () != 0, true);
|
||||
EXPECT_EQ (path.path.back ()->expanded_name (), "$1");
|
||||
EXPECT_EQ (path.path.back ()->circuit_ref ()->name (), "INV2");
|
||||
|
||||
path.net = 0;
|
||||
idx = model->index_from_path (lay::NetlistObjectsPath::from_first (path));
|
||||
EXPECT_EQ (idx.isValid (), true);
|
||||
// A pure subcircuit path addresses the "Circuit" representative node of the subcircuit
|
||||
EXPECT_EQ (tl::to_string (model->data (idx, Qt::DisplayRole).toString ()), "Circuit");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->parent (idx), Qt::UserRole).toString ()), "INV2|$1");
|
||||
EXPECT_EQ (path == model->path_from_index (idx).first (), true);
|
||||
|
||||
path.net = sc->net_by_cluster_id (2);
|
||||
idx = model->index_from_path (lay::NetlistObjectsPath::from_first (path));
|
||||
EXPECT_EQ (idx.isValid (), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "IN|2");
|
||||
EXPECT_EQ (path == model->path_from_index (idx).first (), true);
|
||||
|
||||
path.net = 0;
|
||||
path.device = sc->device_by_id (1);
|
||||
idx = model->index_from_path (lay::NetlistObjectsPath::from_first (path));
|
||||
EXPECT_EQ (idx.isValid (), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS");
|
||||
EXPECT_EQ (path == model->path_from_index (idx).first (), true);
|
||||
}
|
||||
|
||||
// Netlist object path: single vs. pairs - second
|
||||
TEST (6)
|
||||
{
|
||||
db::LayoutVsSchematic lvs;
|
||||
lvs.load (tl::testsrc () + "/testdata/lay/lvsdb_browser.lvsdb");
|
||||
|
||||
lay::NetColorizer colorizer;
|
||||
std::auto_ptr<lay::NetlistBrowserModel> model (new lay::NetlistBrowserModel (0, &lvs, &colorizer));
|
||||
QModelIndex idx;
|
||||
|
||||
db::Circuit *root = lvs.reference_netlist ()->circuit_by_name ("INV2PAIR");
|
||||
EXPECT_EQ (root != 0, true);
|
||||
db::Circuit *sc = lvs.reference_netlist ()->circuit_by_name ("INV2");
|
||||
EXPECT_EQ (sc != 0, true);
|
||||
|
||||
lay::NetlistObjectPath path;
|
||||
EXPECT_EQ (path.is_null (), true);
|
||||
path.root = root;
|
||||
EXPECT_EQ (path.is_null (), false);
|
||||
|
||||
idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path));
|
||||
EXPECT_EQ (idx.isValid (), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "INV2PAIR|INV2PAIR");
|
||||
EXPECT_EQ (path == model->path_from_index (idx).second (), true);
|
||||
|
||||
path.net = root->net_by_name ("4");
|
||||
idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path));
|
||||
EXPECT_EQ (idx.isValid (), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "$5|4");
|
||||
EXPECT_EQ (path == model->path_from_index (idx).second (), true);
|
||||
|
||||
path.path.push_back (root->subcircuit_by_name ("$2"));
|
||||
EXPECT_EQ (path.path.back () != 0, true);
|
||||
EXPECT_EQ (path.path.back ()->expanded_name (), "$2");
|
||||
EXPECT_EQ (path.path.back ()->circuit_ref ()->name (), "INV2");
|
||||
|
||||
path.net = 0;
|
||||
idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path));
|
||||
EXPECT_EQ (idx.isValid (), true);
|
||||
// A pure subcircuit path addresses the "Circuit" representative node of the subcircuit
|
||||
EXPECT_EQ (tl::to_string (model->data (idx, Qt::DisplayRole).toString ()), "Circuit");
|
||||
EXPECT_EQ (tl::to_string (model->data (model->parent (idx), Qt::UserRole).toString ()), "INV2|$2");
|
||||
EXPECT_EQ (path == model->path_from_index (idx).second (), true);
|
||||
|
||||
path.net = sc->net_by_name ("2");
|
||||
idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path));
|
||||
EXPECT_EQ (idx.isValid (), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "IN|2");
|
||||
EXPECT_EQ (path == model->path_from_index (idx).second (), true);
|
||||
|
||||
path.net = 0;
|
||||
path.device = sc->device_by_id (1);
|
||||
idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path));
|
||||
EXPECT_EQ (idx.isValid (), true);
|
||||
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS");
|
||||
EXPECT_EQ (path == model->path_from_index (idx).second (), true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,6 +155,12 @@ module LVS
|
|||
# @synopsis max_depth(n)
|
||||
# See \Netter#max_depth for a description of that function.
|
||||
|
||||
# %LVS%
|
||||
# @name consider_net_names
|
||||
# @brief Indicates whether the netlist comparer shall use net names
|
||||
# @synopsis consider_net_names(f)
|
||||
# See \Netter#consider_net_names for a description of that function.
|
||||
|
||||
# %LVS%
|
||||
# @name tolerance
|
||||
# @brief Specifies compare tolerances for certain device parameters
|
||||
|
|
@ -162,7 +168,7 @@ module LVS
|
|||
# @synopsis tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance])
|
||||
# See \Netter#tolerance for a description of that function.
|
||||
|
||||
%w(schematic compare join_symmetric_nets tolerance align same_nets same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity).each do |f|
|
||||
%w(schematic compare join_symmetric_nets tolerance align same_nets same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity consider_net_names).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(*args)
|
||||
_netter.#{f}(*args)
|
||||
|
|
|
|||
|
|
@ -631,6 +631,20 @@ module LVS
|
|||
@comparer_config << lambda { |comparer| comparer.max_branch_complexity = v }
|
||||
end
|
||||
|
||||
# %LVS%
|
||||
# @name consider_net_names
|
||||
# @brief Indicates whether the netlist comparer shall use net names
|
||||
# @synopsis consider_net_names(f)
|
||||
# If this value is set to true (the default), the netlist comparer
|
||||
# will employ net names to resolve ambiguities. If set to false,
|
||||
# ambiguities will be resolved based on the topology alone. Topology
|
||||
# resolution is more expensive.
|
||||
|
||||
def consider_net_names(value)
|
||||
v = ! value
|
||||
@comparer_config << lambda { |comparer| comparer.dont_consider_net_names = v }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -251,6 +251,7 @@ void Macro::load_from (const std::string &fn)
|
|||
}
|
||||
|
||||
m_modified = true;
|
||||
m_is_file = true;
|
||||
on_changed ();
|
||||
}
|
||||
|
||||
|
|
@ -293,9 +294,6 @@ void Macro::load_from_string (const std::string &text, const std::string &url)
|
|||
void Macro::load ()
|
||||
{
|
||||
load_from (path ());
|
||||
m_modified = false;
|
||||
m_is_file = true;
|
||||
on_changed ();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -449,13 +447,13 @@ void Macro::reset_modified ()
|
|||
|
||||
bool Macro::rename (const std::string &n)
|
||||
{
|
||||
if (m_is_file) {
|
||||
if (m_is_file && parent ()) {
|
||||
std::string suffix = suffix_for_format (m_interpreter, m_dsl_interpreter, m_format);
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Renaming macro " << path () << " to " << n;
|
||||
}
|
||||
QFile f (tl::to_qstring (path ()));
|
||||
if (! f.rename (QFileInfo (QDir (tl::to_qstring (mp_parent->path ())), tl::to_qstring (n + suffix)).filePath ())) {
|
||||
if (! f.rename (QFileInfo (QDir (tl::to_qstring (parent ()->path ())), tl::to_qstring (n + suffix)).filePath ())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1294,14 +1292,15 @@ MacroCollection::add_folder (const std::string &description, const std::string &
|
|||
begin_changes ();
|
||||
|
||||
MacroCollection *mc = m_folders.insert (std::make_pair (path, new MacroCollection ())).first->second;
|
||||
mc->set_parent (this);
|
||||
mc->set_name (path);
|
||||
mc->set_description (description);
|
||||
mc->set_category (cat);
|
||||
mc->set_readonly (readonly);
|
||||
mc->scan (path);
|
||||
mc->set_parent (this);
|
||||
|
||||
on_changed ();
|
||||
on_macro_changed (0);
|
||||
|
||||
return mc;
|
||||
}
|
||||
|
|
@ -1376,7 +1375,6 @@ void MacroCollection::scan (const std::string &path)
|
|||
}
|
||||
if (! found) {
|
||||
Macro *m = m_macros.insert (std::make_pair (n, new Macro ()))->second;
|
||||
m->set_parent (this);
|
||||
m->set_interpreter (interpreter);
|
||||
m->set_autorun_default (autorun);
|
||||
m->set_autorun (autorun);
|
||||
|
|
@ -1387,6 +1385,7 @@ void MacroCollection::scan (const std::string &path)
|
|||
m->set_readonly (m_readonly);
|
||||
m->reset_modified ();
|
||||
m->set_is_file ();
|
||||
m->set_parent (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1425,6 +1424,7 @@ void MacroCollection::scan (const std::string &path)
|
|||
try {
|
||||
|
||||
std::string n = tl::to_string (QFileInfo (*f).completeBaseName ());
|
||||
std::string mp = tl::to_string (dir.absoluteFilePath (*f));
|
||||
|
||||
Macro::Format format = Macro::NoFormat;
|
||||
Macro::Interpreter interpreter = Macro::None;
|
||||
|
|
@ -1451,10 +1451,11 @@ void MacroCollection::scan (const std::string &path)
|
|||
m->set_autorun (autorun);
|
||||
m->set_interpreter (interpreter);
|
||||
m->set_dsl_interpreter (dsl_name);
|
||||
m->set_parent (this);
|
||||
m->set_name (n);
|
||||
m->load ();
|
||||
m->load_from (mp);
|
||||
m->reset_modified ();
|
||||
m->set_readonly (m_readonly);
|
||||
m->set_parent (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1478,12 +1479,12 @@ void MacroCollection::scan (const std::string &path)
|
|||
MacroCollection *&mc = m_folders.insert (std::make_pair (n, (MacroCollection *) 0)).first->second;
|
||||
if (! mc) {
|
||||
mc = new MacroCollection ();
|
||||
mc->set_parent (this);
|
||||
mc->set_name (n);
|
||||
mc->set_virtual_mode (NotVirtual);
|
||||
bool ro = (m_readonly || ! QFileInfo (dir.filePath (*f)).isWritable ());
|
||||
mc->set_readonly (ro);
|
||||
mc->scan (tl::to_string (dir.filePath (*f)));
|
||||
mc->set_parent (this);
|
||||
}
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
|
|
|||
|
|
@ -354,120 +354,130 @@ GDS2WriterBase::write_inst (double sf, const db::Instance &instance, bool normal
|
|||
|
||||
bool is_reg = instance.is_regular_array (a, b, amax, bmax);
|
||||
|
||||
db::Trans t = instance.front ();
|
||||
for (db::CellInstArray::iterator ii = instance.begin (); ! ii.at_end (); ++ii) {
|
||||
|
||||
if (normalize) {
|
||||
db::Trans t = *ii;
|
||||
|
||||
// try to normalize orthogonal arrays into "Cadence notation", that is
|
||||
// column and row vectors are positive in the coordinate system of the
|
||||
// rotated array.
|
||||
|
||||
if (is_reg) {
|
||||
if (normalize) {
|
||||
|
||||
if (amax < 2) {
|
||||
a = db::Vector ();
|
||||
}
|
||||
if (bmax < 2) {
|
||||
b = db::Vector ();
|
||||
}
|
||||
// try to normalize orthogonal arrays into "Cadence notation", that is
|
||||
// column and row vectors are positive in the coordinate system of the
|
||||
// rotated array.
|
||||
|
||||
// normalisation only works for orthogonal vectors, parallel to x or y axis, which are not parallel
|
||||
if ((a.x () == 0 || a.y () == 0) && (b.x () == 0 || b.y () == 0) && !((a.x () != 0 && b.x () != 0) || (a.y () != 0 && b.y () != 0))) {
|
||||
|
||||
db::FTrans fp = db::FTrans(t.rot ()).inverted ();
|
||||
|
||||
a.transform (fp);
|
||||
b.transform (fp);
|
||||
if (is_reg) {
|
||||
|
||||
db::Vector p;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (amax < 2) {
|
||||
a = db::Vector ();
|
||||
}
|
||||
if (bmax < 2) {
|
||||
b = db::Vector ();
|
||||
}
|
||||
|
||||
db::Vector *q = (i == 0) ? &a : &b;
|
||||
unsigned long n = (i == 0) ? amax : bmax;
|
||||
// normalisation only works for orthogonal vectors, parallel to x or y axis, which are not parallel
|
||||
if ((a.x () == 0 || a.y () == 0) && (b.x () == 0 || b.y () == 0) && !((a.x () != 0 && b.x () != 0) || (a.y () != 0 && b.y () != 0))) {
|
||||
|
||||
db::FTrans fp = db::FTrans(t.rot ()).inverted ();
|
||||
|
||||
a.transform (fp);
|
||||
b.transform (fp);
|
||||
|
||||
db::Vector p;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
|
||||
db::Vector *q = (i == 0) ? &a : &b;
|
||||
unsigned long n = (i == 0) ? amax : bmax;
|
||||
|
||||
if (n == 0) {
|
||||
*q = db::Vector ();
|
||||
} else {
|
||||
if (q->x () < 0) {
|
||||
p += db::Vector ((n - 1) * q->x (), 0);
|
||||
q->set_x (-q->x ());
|
||||
}
|
||||
if (q->y () < 0) {
|
||||
p += db::Vector (0, (n - 1) * q->y ());
|
||||
q->set_y (-q->y ());
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
*q = db::Vector ();
|
||||
} else {
|
||||
if (q->x () < 0) {
|
||||
p += db::Vector ((n - 1) * q->x (), 0);
|
||||
q->set_x (-q->x ());
|
||||
}
|
||||
if (q->y () < 0) {
|
||||
p += db::Vector (0, (n - 1) * q->y ());
|
||||
q->set_y (-q->y ());
|
||||
}
|
||||
}
|
||||
|
||||
if (a.x () != 0 || b.y () != 0) {
|
||||
std::swap (a, b);
|
||||
std::swap (amax, bmax);
|
||||
}
|
||||
|
||||
fp = db::FTrans (t.rot ());
|
||||
a.transform (fp);
|
||||
b.transform (fp);
|
||||
|
||||
t = t * db::Trans (p);
|
||||
|
||||
}
|
||||
|
||||
if (a.x () != 0 || b.y () != 0) {
|
||||
std::swap (a, b);
|
||||
std::swap (amax, bmax);
|
||||
}
|
||||
|
||||
fp = db::FTrans (t.rot ());
|
||||
a.transform (fp);
|
||||
b.transform (fp);
|
||||
|
||||
t = t * db::Trans (p);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
write_record_size (4);
|
||||
write_record (is_reg ? sAREF : sSREF);
|
||||
|
||||
write_record_size (4);
|
||||
write_record (is_reg ? sAREF : sSREF);
|
||||
write_string_record (sSNAME, m_cell_name_map.cell_name (instance.cell_index ()));
|
||||
|
||||
write_string_record (sSNAME, m_cell_name_map.cell_name (instance.cell_index ()));
|
||||
if (t.rot () != 0 || instance.is_complex ()) {
|
||||
|
||||
if (t.rot () != 0 || instance.is_complex ()) {
|
||||
write_record_size (6);
|
||||
write_record (sSTRANS);
|
||||
write_short (t.is_mirror () ? 0x8000 : 0);
|
||||
|
||||
write_record_size (6);
|
||||
write_record (sSTRANS);
|
||||
write_short (t.is_mirror () ? 0x8000 : 0);
|
||||
|
||||
if (instance.is_complex ()) {
|
||||
write_record_size (4 + 8);
|
||||
write_record (sMAG);
|
||||
write_double (instance.complex_trans ().mag ());
|
||||
write_record_size (4 + 8);
|
||||
write_record (sANGLE);
|
||||
write_double (instance.complex_trans ().angle ());
|
||||
} else {
|
||||
if ((t.rot () % 4) != 0) {
|
||||
if (instance.is_complex ()) {
|
||||
db::CellInstArray::complex_trans_type ct = instance.complex_trans (t);
|
||||
write_record_size (4 + 8);
|
||||
write_record (sMAG);
|
||||
write_double (ct.mag ());
|
||||
write_record_size (4 + 8);
|
||||
write_record (sANGLE);
|
||||
write_double ((t.rot () % 4) * 90.0);
|
||||
write_double (ct.angle ());
|
||||
} else {
|
||||
if ((t.rot () % 4) != 0) {
|
||||
write_record_size (4 + 8);
|
||||
write_record (sANGLE);
|
||||
write_double ((t.rot () % 4) * 90.0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (is_reg) {
|
||||
write_record_size (4 + 2 * 2);
|
||||
write_record (sCOLROW);
|
||||
if (amax > 32767 || bmax > 32767) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot write array references with more than 32767 columns or rows to GDS2 streams")));
|
||||
}
|
||||
write_short (std::max ((unsigned long) 1, bmax));
|
||||
write_short (std::max ((unsigned long) 1, amax));
|
||||
}
|
||||
|
||||
write_record_size (4 + (is_reg ? 3 : 1) * 2 * 4);
|
||||
write_record (sXY);
|
||||
write_int (scale (sf, t.disp ().x ()));
|
||||
write_int (scale (sf, t.disp ().y ()));
|
||||
|
||||
if (is_reg) {
|
||||
write_int (scale (sf, t.disp ().x () + b.x () * bmax));
|
||||
write_int (scale (sf, t.disp ().y () + b.y () * bmax));
|
||||
write_int (scale (sf, t.disp ().x () + a.x () * amax));
|
||||
write_int (scale (sf, t.disp ().y () + a.y () * amax));
|
||||
}
|
||||
|
||||
finish (layout, prop_id);
|
||||
|
||||
if (is_reg) {
|
||||
// we have already written all instances
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (is_reg) {
|
||||
write_record_size (4 + 2 * 2);
|
||||
write_record (sCOLROW);
|
||||
if (amax > 32767 || bmax > 32767) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot write array references with more than 32767 columns or rows to GDS2 streams")));
|
||||
}
|
||||
write_short (std::max ((unsigned long) 1, bmax));
|
||||
write_short (std::max ((unsigned long) 1, amax));
|
||||
}
|
||||
|
||||
write_record_size (4 + (is_reg ? 3 : 1) * 2 * 4);
|
||||
write_record (sXY);
|
||||
write_int (scale (sf, t.disp ().x ()));
|
||||
write_int (scale (sf, t.disp ().y ()));
|
||||
|
||||
if (is_reg) {
|
||||
write_int (scale (sf, t.disp ().x () + b.x () * bmax));
|
||||
write_int (scale (sf, t.disp ().y () + b.y () * bmax));
|
||||
write_int (scale (sf, t.disp ().x () + a.x () * amax));
|
||||
write_int (scale (sf, t.disp ().y () + a.y () * amax));
|
||||
}
|
||||
|
||||
finish (layout, prop_id);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -1129,6 +1129,40 @@ TEST(117)
|
|||
EXPECT_EQ (pp == poly, true);
|
||||
}
|
||||
|
||||
// error on duplicate cell name
|
||||
TEST(118)
|
||||
{
|
||||
db::Manager m (false);
|
||||
db::Layout layout_org (&m);
|
||||
|
||||
db::cell_index_type cid1 = layout_org.add_cell ("A");
|
||||
db::cell_index_type cid2 = layout_org.add_cell ("B");
|
||||
layout_org.rename_cell (cid2, "A"); // creates a duplicate cell
|
||||
|
||||
db::LayerProperties lp;
|
||||
lp.layer = 1;
|
||||
lp.datatype = 0;
|
||||
unsigned int lid = layout_org.insert_layer (lp);
|
||||
|
||||
layout_org.cell (cid1).shapes (lid).insert (db::Box (0, 0, 1000, 2000));
|
||||
layout_org.cell (cid2).shapes (lid).insert (db::Box (0, 0, 1000, 2000));
|
||||
|
||||
std::string tmp_file = tl::TestBase::tmp_file ("tmp_GDS2Writer_117.gds");
|
||||
|
||||
bool error = false;
|
||||
try {
|
||||
tl::OutputStream stream (tmp_file);
|
||||
db::SaveLayoutOptions options;
|
||||
db::Writer writer (options);
|
||||
writer.write (layout_org, stream);
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::warn << ex.msg ();
|
||||
error = true;
|
||||
}
|
||||
|
||||
EXPECT_EQ (error, true);
|
||||
}
|
||||
|
||||
// Extreme fracturing by max. points
|
||||
TEST(120)
|
||||
{
|
||||
|
|
@ -1153,3 +1187,4 @@ TEST(166)
|
|||
opt.max_vertex_count = 4;
|
||||
run_test (_this, "t166.oas.gz", "t166_au.gds.gz", false, opt);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2016,6 +2016,8 @@ OASISReader::do_read_placement (unsigned char r,
|
|||
|
||||
db::Vector pos (mm_placement_x.get (), mm_placement_y.get ());
|
||||
|
||||
const std::vector<db::Vector> *points = 0;
|
||||
|
||||
if ((m & 0x8) && read_repetition ()) {
|
||||
|
||||
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
||||
|
|
@ -2040,6 +2042,42 @@ OASISReader::do_read_placement (unsigned char r,
|
|||
instances.push_back (inst);
|
||||
}
|
||||
|
||||
} else if (! layout.is_editable () && (points = mm_repetition.get ().is_iterated ()) != 0) {
|
||||
|
||||
db::CellInstArray inst;
|
||||
|
||||
if (mag_set || angle < 0) {
|
||||
|
||||
db::ICplxTrans ct (mag, angle_deg, mirror, pos);
|
||||
|
||||
db::CellInstArray::iterated_complex_array_type array (ct.rcos (), ct.mag ());
|
||||
array.reserve (points->size () + 1);
|
||||
array.insert (db::Vector ());
|
||||
array.insert (points->begin (), points->end ());
|
||||
array.sort ();
|
||||
|
||||
inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()),
|
||||
db::Trans (ct), layout.array_repository ().insert (array));
|
||||
|
||||
} else {
|
||||
|
||||
db::CellInstArray::iterated_array_type array;
|
||||
array.reserve (points->size () + 1);
|
||||
array.insert (db::Vector ());
|
||||
array.insert (points->begin (), points->end ());
|
||||
array.sort ();
|
||||
|
||||
inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()),
|
||||
db::Trans (angle, mirror, pos), layout.array_repository ().insert (array));
|
||||
|
||||
}
|
||||
|
||||
if (pp.first) {
|
||||
instances_with_props.push_back (db::CellInstArrayWithProperties (inst, pp.second));
|
||||
} else {
|
||||
instances.push_back (inst);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
RepetitionIterator p = mm_repetition.get ().begin ();
|
||||
|
|
|
|||
|
|
@ -1965,11 +1965,35 @@ OASISWriter::write (const db::CellInstArray &inst, db::properties_id_type prop_i
|
|||
{
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
std::vector<db::Vector> pts;
|
||||
db::Vector a, b;
|
||||
unsigned long amax, bmax;
|
||||
bool is_reg = inst.is_regular_array (a, b, amax, bmax);
|
||||
|
||||
if (is_reg && (amax > 1 || bmax > 1)) {
|
||||
if (inst.is_iterated_array (&pts) && pts.size () > 1) {
|
||||
|
||||
// Remove the first point which is implicitly contained in the repetition
|
||||
// Note: we can do so because below we instantiate the shape at the front of the array which includes
|
||||
// the first transformation already.
|
||||
db::Vector po = pts.front ();
|
||||
std::vector<db::Vector>::iterator pw = pts.begin();
|
||||
for (std::vector<db::Vector>::iterator p = pw + 1; p != pts.end (); ++p) {
|
||||
*pw++ = *p - po;
|
||||
}
|
||||
pts.erase (pw, pts.end ());
|
||||
|
||||
db::IrregularRepetition *rep_base = new db::IrregularRepetition ();
|
||||
rep_base->points ().swap (pts);
|
||||
db::Repetition array_rep (rep_base);
|
||||
|
||||
if (rep != db::Repetition ()) {
|
||||
for (db::RepetitionIterator r = rep.begin (); ! r.at_end (); ++r) {
|
||||
write_inst_with_rep (inst, prop_id, *r, array_rep);
|
||||
}
|
||||
} else {
|
||||
write_inst_with_rep (inst, prop_id, db::Vector (), array_rep);
|
||||
}
|
||||
|
||||
} else if (inst.is_regular_array (a, b, amax, bmax) && (amax > 1 || bmax > 1)) {
|
||||
|
||||
// we cannot use the repetition - instead we write every single instance and use the repetition
|
||||
// for the array information
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef HDR_layDialogs
|
||||
#define HDR_layDialogs
|
||||
#ifndef HDR_layBooleanOperationsDialogs
|
||||
#define HDR_layBooleanOperationsDialogs
|
||||
|
||||
#include "ui_BooleanOptionsDialog.h"
|
||||
#include "ui_SizingOptionsDialog.h"
|
||||
|
|
|
|||
|
|
@ -224,6 +224,10 @@ RdbDifferenceReceiver::produce_cell_inst (const db::CellInstArrayWithProperties
|
|||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
r += tl::sprintf (" [a=%s, b=%s, na=%ld, nb=%ld]", a.to_string (), b.to_string (), amax, bmax);
|
||||
} else if (ci.size () > 1) {
|
||||
r += " (+";
|
||||
r += tl::to_string (ci.size () - 1);
|
||||
r += " irregular placements)";
|
||||
}
|
||||
|
||||
item->add_value (r);
|
||||
|
|
|
|||
|
|
@ -935,6 +935,12 @@ struct test_arg_func<gsi::VectorType>
|
|||
{
|
||||
void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose)
|
||||
{
|
||||
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Py_None) {
|
||||
// for ptr or cptr, null is an allowed value
|
||||
*ret = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (! PyTuple_Check (arg) && ! PyList_Check (arg)) {
|
||||
*ret = false;
|
||||
return;
|
||||
|
|
@ -971,6 +977,12 @@ struct test_arg_func<gsi::MapType>
|
|||
{
|
||||
void operator () (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose)
|
||||
{
|
||||
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Py_None) {
|
||||
// for ptr or cptr, null is an allowed value
|
||||
*ret = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (! PyDict_Check (arg)) {
|
||||
*ret = false;
|
||||
return;
|
||||
|
|
@ -999,6 +1011,7 @@ struct test_arg_func<gsi::MapType>
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct test_arg_func<gsi::ObjectType>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -306,7 +306,11 @@ PYAObjectBase::detach ()
|
|||
}
|
||||
}
|
||||
|
||||
detach_callbacks ();
|
||||
// NOTE: m_owned = false might mean the C++ object is already destroyed. We must not
|
||||
// modify in this case and without is_managed() there is no way of knowing the state.
|
||||
if (m_owned) {
|
||||
detach_callbacks ();
|
||||
}
|
||||
|
||||
m_obj = 0;
|
||||
m_const_ref = false;
|
||||
|
|
|
|||
|
|
@ -138,7 +138,10 @@ void SignalHandler::call (const gsi::MethodBase *meth, gsi::SerialArgs &args, gs
|
|||
std::vector<PythonRef> callables;
|
||||
callables.reserve (m_cbfuncs.size ());
|
||||
for (std::vector<CallbackFunction>::const_iterator c = m_cbfuncs.begin (); c != m_cbfuncs.end (); ++c) {
|
||||
callables.push_back (c->callable ());
|
||||
PythonRef callable = c->callable ();
|
||||
if (callable) {
|
||||
callables.push_back (c->callable ());
|
||||
}
|
||||
}
|
||||
|
||||
PythonRef result;
|
||||
|
|
|
|||
|
|
@ -402,7 +402,11 @@ Proxy::detach ()
|
|||
}
|
||||
}
|
||||
|
||||
clear_callbacks ();
|
||||
// NOTE: m_owned = false might mean the C++ object is already destroyed. We must not
|
||||
// modify in this case and without is_managed() there is no way of knowing the state.
|
||||
if (m_owned) {
|
||||
clear_callbacks ();
|
||||
}
|
||||
|
||||
m_self = Qnil;
|
||||
m_obj = 0;
|
||||
|
|
|
|||
|
|
@ -956,7 +956,7 @@ struct test_arg_func<gsi::VectorType>
|
|||
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Qnil) {
|
||||
// for pointers to vectors, nil is a valid value
|
||||
*ret = true;
|
||||
} if (TYPE (arg) != T_ARRAY) {
|
||||
} else if (TYPE (arg) != T_ARRAY) {
|
||||
*ret = false;
|
||||
} else {
|
||||
|
||||
|
|
|
|||
|
|
@ -1019,7 +1019,7 @@ InputPipe::read (char *b, size_t n)
|
|||
size_t ret = fread (b, 1, n, m_file);
|
||||
if (ret < n) {
|
||||
if (ferror (m_file)) {
|
||||
throw FilePReadErrorException (m_source, ferror (m_file));
|
||||
throw FilePReadErrorException (m_source, errno);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1049,7 +1049,7 @@ OutputPipe::OutputPipe (const std::string &path)
|
|||
OutputPipe::~OutputPipe ()
|
||||
{
|
||||
if (m_file != NULL) {
|
||||
fclose (m_file);
|
||||
_pclose (m_file);
|
||||
m_file = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -1061,7 +1061,7 @@ OutputPipe::write (const char *b, size_t n)
|
|||
size_t ret = fwrite (b, 1, n, m_file);
|
||||
if (ret < n) {
|
||||
if (ferror (m_file)) {
|
||||
throw FilePWriteErrorException (m_source, ferror (m_file));
|
||||
throw FilePWriteErrorException (m_source, errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1106,10 +1106,22 @@ size_t
|
|||
InputPipe::read (char *b, size_t n)
|
||||
{
|
||||
tl_assert (m_file != NULL);
|
||||
size_t ret = fread (b, 1, n, m_file);
|
||||
if (ret < n) {
|
||||
if (ferror (m_file)) {
|
||||
throw FilePReadErrorException (m_source, ferror (m_file));
|
||||
|
||||
bool retry = true;
|
||||
size_t ret = 0;
|
||||
|
||||
while (retry) {
|
||||
retry = false;
|
||||
ret = fread (b, 1, n, m_file);
|
||||
if (ret < n) {
|
||||
if (ferror (m_file)) {
|
||||
if (errno != EINTR) {
|
||||
throw FilePReadErrorException (m_source, errno);
|
||||
} else if (ret == 0) {
|
||||
retry = true;
|
||||
clearerr (m_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1138,7 +1150,7 @@ OutputPipe::OutputPipe (const std::string &path)
|
|||
OutputPipe::~OutputPipe ()
|
||||
{
|
||||
if (m_file != NULL) {
|
||||
fclose (m_file);
|
||||
pclose (m_file);
|
||||
m_file = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -1147,10 +1159,11 @@ void
|
|||
OutputPipe::write (const char *b, size_t n)
|
||||
{
|
||||
tl_assert (m_file != NULL);
|
||||
|
||||
size_t ret = fwrite (b, 1, n, m_file);
|
||||
if (ret < n) {
|
||||
if (ferror (m_file)) {
|
||||
throw FilePWriteErrorException (m_source, ferror (m_file));
|
||||
if (ferror (m_file) && errno != EINTR) {
|
||||
throw FilePReadErrorException (m_source, errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@ bool TestBase::do_test (bool editable, bool slow)
|
|||
{
|
||||
m_editable = editable;
|
||||
m_slow = slow;
|
||||
m_any_failed = false;
|
||||
|
||||
// Ensures the test temp directory is present
|
||||
std::string tmpdir = tl::combine_path (tl::absolute_file_path (testtmp ()), m_testdir);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue