mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into devel
This commit is contained in:
commit
1a9c12ce18
|
|
@ -1,12 +1,12 @@
|
|||
Relevant KLayout version: 0.29.11<br>
|
||||
Relevant KLayout version: 0.30.2<br>
|
||||
Author: Kazzz-S<br>
|
||||
Last modified: 2025-01-19<br>
|
||||
Last modified: 2025-05-30<br>
|
||||
|
||||
# 1. Introduction
|
||||
This directory **`macbuild`** contains various files required for building KLayout (http://www.klayout.de/) version 0.29.11 or later for different 64-bit macOS, including:
|
||||
* Sonoma (14.x) : the primary development environment
|
||||
* Ventura (13.x) : experimental
|
||||
* Sequoia (15.x) : -- ditto --
|
||||
This directory **`macbuild`** contains various files required for building KLayout (http://www.klayout.de/) version 0.30.2 or later for different 64-bit macOS, including:
|
||||
* Sequoia (15.x) : the primary development environment
|
||||
* Sonoma (14.x) : experimental
|
||||
* Ventura (13.x) : -- ditto --
|
||||
|
||||
Building KLayout for the previous operating systems listed below has been discontinued.<br>
|
||||
Pre-built DMG packages are also not provided.<br>
|
||||
|
|
@ -18,7 +18,7 @@ Pre-built DMG packages are also not provided.<br>
|
|||
* Sierra (10.12)
|
||||
* El Capitan (10.11)
|
||||
|
||||
Throughout this document, the primary target machine is **Intel x86_64** with **macOS Sonoma**.<br>
|
||||
Throughout this document, the primary target machine is **Intel x86_64** with **macOS Sequoia**.<br>
|
||||
All Apple (M1|M2|M3|M4) chips are still untested, as the author does not own an (M1|M2|M3|M4) Mac.<br>
|
||||
However, some kind volunteers told me they successfully built on an Apple silicon machine.<br>
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ If you have installed Anaconda3 under $HOME/opt/anaconda3/, make a symbolic link
|
|||
/Applications/anaconda3/ ---> $HOME/opt/anaconda3/
|
||||
```
|
||||
|
||||
The migration work to "Qt6" is ongoing. You can try to use it; however, you might encounter some build and runtime errors.<br>
|
||||
The migration work to "Qt6" is ongoing. You can try to use it; however, you might encounter some build or runtime errors.<br>
|
||||
If you use **Homebrew** to build KLayout >= 0.29.0, you need "Qt6" to address [the compilation issue](https://github.com/KLayout/klayout/issues/1599).<br>
|
||||
I have also tried migrating to "Python 3.12.x" (earlier, Python 3.11.x) in this version.
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ The operating system type is detected automatically.
|
|||
```
|
||||
-----------------------------------------------------------------------------------------------------------
|
||||
<< Usage of 'build4mac.py' >>
|
||||
for building KLayout 0.29.11 or later on different Apple macOS platforms.
|
||||
for building KLayout 0.30.2 or later on different Apple macOS platforms.
|
||||
|
||||
$ [python] ./build4mac.py
|
||||
option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details) | default value
|
||||
|
|
@ -123,7 +123,7 @@ $ [python] ./build4mac.py
|
|||
```
|
||||
|
||||
# 6. Use-cases
|
||||
In this section, the actual file and directory names are those obtained on macOS Sonoma.<br>
|
||||
In this section, the actual file and directory names are those obtained on macOS Sequoia.<br>
|
||||
On different OS, those names differ accordingly.
|
||||
|
||||
### 6A. Standard build using the OS-bundled Ruby and Python with MacPorts Qt5
|
||||
|
|
@ -141,7 +141,7 @@ Confirm that you have:
|
|||
```
|
||||
As of this writing, the provided Python version is `3.9.6`.
|
||||
|
||||
1. Invoke **`build4mac.py`** with the following options: **((Notes))** These options are the default values for Sonoma, Ventura, and Sequioa.
|
||||
1. Invoke **`build4mac.py`** with the following options: **((Notes))** These options are the default values for Sequoia, Sonoma, and Ventura.
|
||||
```
|
||||
$ cd /where/'build.sh'/exists
|
||||
$ ./build4mac.py -q qt5macports -r sys -p sys
|
||||
|
|
@ -154,7 +154,7 @@ $ ./build4mac.py -q qt5macports -r sys -p sys
|
|||
$ ./build4mac.py -q qt5macports -r sys -p sys -y
|
||||
```
|
||||
The application bundle **`klayout.app`** is located under:<br>
|
||||
**`ST-qt5MP.pkg.macos-Sonoma-release-RsysPsys`** directory, where
|
||||
**`ST-qt5MP.pkg.macos-Sequoia-release-RsysPsys`** directory, where
|
||||
* "ST-" means this is a standard package.
|
||||
* "qt5MP" means that Qt5 from MacPorts is used.
|
||||
* "RsysPsys" means that Ruby is 2.6 provided by OS; Python is 3.9 provided by OS.
|
||||
|
|
@ -185,7 +185,7 @@ $ ./build4mac.py -q qt5macports -r mp33 -p mp312
|
|||
$ ./build4mac.py -q qt5macports -r mp33 -p mp312 -Y
|
||||
```
|
||||
The application bundle **`klayout.app`** is located under:<br>
|
||||
**`LW-qt5MP.pkg.macos-Sonoma-release-Rmp33Pmp312`** directory, where
|
||||
**`LW-qt5MP.pkg.macos-Sequoia-release-Rmp33Pmp312`** directory, where
|
||||
* "LW-" means this is a lightweight package.
|
||||
* "qt5MP" means that Qt5 from MacPorts is used.
|
||||
* "Rmp33Pmp312" means that Ruby is 3.3 from MacPorts; Python is 3.12 from MacPorts.
|
||||
|
|
@ -218,7 +218,7 @@ $ ./build4mac.py -q qt6brew -r hb34 -p hb312
|
|||
$ ./build4mac.py -q qt6brew -r hb34 -p hb312 -Y
|
||||
```
|
||||
The application bundle **`klayout.app`** is located under:<br>
|
||||
**`LW-qt6Brew.pkg.macos-Sonoma-release-Rhb34Phb312`** directory, where
|
||||
**`LW-qt6Brew.pkg.macos-Sequoia-release-Rhb34Phb312`** directory, where
|
||||
* "LW-" means this is a lightweight package.
|
||||
* "qt6Brew" means that Qt6 from Homebrew is used.
|
||||
* "Rhb34Phb312" means that Ruby is 3.4 from Homebrew; Python is 3.12 from Homebrew.
|
||||
|
|
@ -258,7 +258,7 @@ $ ./build4mac.py -q qt6brew -r sys -p hb311
|
|||
$ ./build4mac.py -q qt6brew -r sys -p hb311 -y
|
||||
```
|
||||
The application bundle **`klayout.app`** is located under:<br>
|
||||
**`HW-qt6Brew.pkg.macos-Sonoma-release-RsysPhb311`** directory, where
|
||||
**`HW-qt6Brew.pkg.macos-Sequoia-release-RsysPhb311`** directory, where
|
||||
* "HW-" means this is a heavyweight package because both Qt6 and Python Frameworks are deployed.
|
||||
* "qt6Brew" means that Qt6 from Homebrew is used.
|
||||
* "RsysPhb311" means that Ruby is OS-bundled; Python is 3.11 from Homebrew.
|
||||
|
|
@ -300,14 +300,14 @@ $ ./build4mac.py -q qt5macports -r sys -p hb311
|
|||
$ ./build4mac.py -q qt5macports -r sys -p hb311 -y
|
||||
```
|
||||
The application bundle **`klayout.app`** is located under:<br>
|
||||
**`HW-qt5MP.pkg.macos-Sonoma-release-RsysPhb311`** directory, where
|
||||
**`HW-qt5MP.pkg.macos-Sequoia-release-RsysPhb311`** directory, where
|
||||
* "HW-" means this is a heavyweight package because both Qt5 and Python Frameworks are deployed.
|
||||
* "qt5MP" means that Qt5 from MacPorts is used.
|
||||
* "RsysPhb311" means that Ruby is OS-bundled; Python is 3.11 from Homebrew.
|
||||
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
|
||||
|
||||
### 6F. Fully Anaconda3-flavored build with Anaconda3 Ruby 3.2 and Anaconda3 Python 3.12
|
||||
0. Install Anaconda3 (Anaconda3-2024.06-1-MacOSX-x86_64.pkg), then install Ruby 3.2 and libgit2 by
|
||||
0. Install Anaconda3 (Anaconda3-2024.10-1-MacOSX-x86_64.pkg), then install Ruby 3.2 and libgit2 by
|
||||
```
|
||||
$ conda install ruby=3.2.2
|
||||
$ conda install libgit2=1.6.4
|
||||
|
|
@ -327,7 +327,7 @@ $ ./build4mac.py -q qt5ana3 -r ana3 -p ana3
|
|||
$ ./build4mac.py -q qt5ana3 -r ana3 -p ana3 -Y
|
||||
```
|
||||
The application bundle **`klayout.app`** is located under:<br>
|
||||
**`LW-qt5Ana3.pkg.macos-Sonoma-release-Rana3Pana3`** directory, where
|
||||
**`LW-qt5Ana3.pkg.macos-Sequoia-release-Rana3Pana3`** directory, where
|
||||
* "LW-" means this is a lightweight package.
|
||||
* "qt5Ana3" means that Qt5 from Anaconda3 is used.
|
||||
* "Rana3Pana3" means that Ruby (3.2) is from Anaconda3; Python (3.12) is from Anaconda3.
|
||||
|
|
@ -394,11 +394,11 @@ makeDMG4mac.py -> macbuild/makeDMG4mac.py
|
|||
2. Invoke **`makeDMG4mac.py`** with -p and -m options, for example,
|
||||
```
|
||||
$ cd /where/'build.sh'/exists
|
||||
$ ./makeDMG4mac.py -p LW-qt5MP.pkg.macos-Sonoma-release-Rmp33Pmp312 -m
|
||||
$ ./makeDMG4mac.py -p LW-qt5MP.pkg.macos-Sequoia-release-Rmp33Pmp312 -m
|
||||
```
|
||||
This command will generate the two files below:<br>
|
||||
* **`LW-klayout-0.29.11-macOS-Sonoma-1-qt5MP-Rmp33Pmp312.dmg`** ---(1) the main DMG file
|
||||
* **`LW-klayout-0.29.11-macOS-Sonoma-1-qt5MP-Rmp33Pmp312.dmg.md5`** ---(2) MD5-value text file
|
||||
* **`LW-klayout-0.30.2-macOS-Sequoia-1-qt5MP-Rmp33Pmp312.dmg`** ---(1) the main DMG file
|
||||
* **`LW-klayout-0.30.2-macOS-Sequoia-1-qt5MP-Rmp33Pmp312.dmg.md5`** ---(2) MD5-value text file
|
||||
|
||||
# Known issues
|
||||
Because we assume some specific versions of non-OS-standard Ruby and Python, updating Homebrew, MacPorts, or Anaconda3 may cause build- and link errors.<br>
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -5,7 +5,7 @@
|
|||
# File: "macbuild/build4mac.py"
|
||||
#
|
||||
# The top Python script for building KLayout (http://www.klayout.de/index.php)
|
||||
# version 0.29.11 or later on different Apple Mac OSX platforms.
|
||||
# version 0.30.2 or later on different Apple Mac OSX platforms.
|
||||
#===============================================================================
|
||||
import sys
|
||||
import os
|
||||
|
|
@ -45,7 +45,7 @@ def GenerateUsage(platform):
|
|||
usage = "\n"
|
||||
usage += "-----------------------------------------------------------------------------------------------------------\n"
|
||||
usage += "<< Usage of 'build4mac.py' >>\n"
|
||||
usage += " for building KLayout 0.29.11 or later on different Apple macOS platforms.\n"
|
||||
usage += " for building KLayout 0.30.2 or later on different Apple macOS platforms.\n"
|
||||
usage += "\n"
|
||||
usage += "$ [python] ./build4mac.py\n"
|
||||
usage += " option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details) | default value\n"
|
||||
|
|
@ -847,29 +847,30 @@ def Build_pymod_wheel(parameters):
|
|||
cmd3_args = " <wheel file> \\\n"
|
||||
cmd4_args = " -m setup clean --all \\\n"
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
#-----------------------------------------------------------------------------------
|
||||
# [4] Make the consolidated command lines
|
||||
#--------------------------------------------------------------------
|
||||
# "caffeinate" makes the CPU run at full speed even when the screen is locked.
|
||||
#-----------------------------------------------------------------------------------
|
||||
command1 = "time"
|
||||
command1 += " \\\n %s \\\n" % parameters['python']
|
||||
command1 += " \\\n caffeinate -i %s \\\n" % parameters['python']
|
||||
command1 += cmd1_args
|
||||
command1 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
|
||||
command1 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
||||
|
||||
command2 = "time"
|
||||
command2 += " \\\n %s \\\n" % parameters['python']
|
||||
command2 += " \\\n caffeinate -i %s \\\n" % parameters['python']
|
||||
command2 += cmd2_args
|
||||
command2 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
|
||||
command2 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
||||
|
||||
command3 = "time"
|
||||
command3 += " \\\n %s \\\n" % deloc_cmd
|
||||
command3 += " \\\n caffeinate -i %s \\\n" % deloc_cmd
|
||||
command3 += cmd3_args
|
||||
command3 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
|
||||
command3 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
||||
|
||||
command4 = "time"
|
||||
command4 += " \\\n %s \\\n" % parameters['python']
|
||||
command4 += " \\\n caffeinate -i %s \\\n" % parameters['python']
|
||||
command4 += cmd4_args
|
||||
command4 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
|
||||
command4 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
||||
|
|
@ -923,10 +924,10 @@ def Build_pymod_wheel(parameters):
|
|||
# Refer to: https://github.com/Kazzz-S/klayout/issues/49#issuecomment-1432154118
|
||||
# https://pypi.org/project/delocate/
|
||||
#---------------------------------------------------------------------------------------------------------
|
||||
cmd3_args = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.29.7-cp312-cp312-macosx_12_0_x86_64.whl']
|
||||
cmd3_args = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.30.2-cp312-cp312-macosx_10_15_x86_64.whl']
|
||||
if len(cmd3_args) == 1:
|
||||
command3 = "time"
|
||||
command3 += " \\\n %s \\\n" % deloc_cmd
|
||||
command3 += " \\\n caffeinate -i %s \\\n" % deloc_cmd
|
||||
command3 += " %s \\\n" % cmd3_args[0]
|
||||
command3 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
|
||||
command3 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
||||
|
|
@ -953,13 +954,13 @@ def Build_pymod_wheel(parameters):
|
|||
#------------------------------------------------------------------------
|
||||
# [5-C] Forcibly change the wheel file name for anaconda3
|
||||
# Ref. https://github.com/Kazzz-S/klayout/issues/53
|
||||
# original: klayout-0.29.7-cp312-cp312-macosx_12_0_x86_64.whl
|
||||
# original: klayout-0.30.2-cp312-cp312-macosx_10_15_x86_64.whl
|
||||
# |
|
||||
# V
|
||||
# new: klayout-0.29.7-cp312-cp312-macosx_10_9_x86_64.whl
|
||||
# new: klayout-0.30.2-cp312-cp312-macosx_10_9_x86_64.whl
|
||||
#------------------------------------------------------------------------
|
||||
if whlTarget == "ana3":
|
||||
wheels = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.29.7-cp312-cp312-macosx_12_0_x86_64.whl']
|
||||
wheels = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.30.2-cp312-cp312-macosx_10_15_x86_64.whl']
|
||||
if not len(wheels) == 1:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-------------------------------------------------------------", file=sys.stderr )
|
||||
|
|
@ -1114,11 +1115,12 @@ def Run_Build_Command(config, parameters):
|
|||
else:
|
||||
cmd_args += " \\\n -nopython"
|
||||
|
||||
#-----------------------------------------------------
|
||||
#-----------------------------------------------------------------------------------
|
||||
# [4] Make the consolidated command line
|
||||
#-----------------------------------------------------
|
||||
# "caffeinate" makes the CPU run at full speed even when the screen is locked.
|
||||
#-----------------------------------------------------------------------------------
|
||||
command = "time"
|
||||
command += " \\\n %s" % parameters['build_cmd']
|
||||
command += " \\\n caffeinate -i %s" % parameters['build_cmd']
|
||||
command += cmd_args
|
||||
command += " 2>&1 | tee %s; \\\n" % parameters['logfile']
|
||||
command += "test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
||||
|
|
@ -1831,33 +1833,33 @@ def Deploy_Binaries_For_Bundle(config, parameters):
|
|||
|
||||
#-----------------------------------------------------------------------------------------------
|
||||
# [9] Special deployment of Python3.11 from Homebrew
|
||||
# To use Python3.1 from Homebrew on Sonoma...
|
||||
# To use Python3.11 from Homebrew on Sequoia...
|
||||
# in "/usr/local/opt/python@3.11/lib/"
|
||||
# Python.framework -> ../Frameworks/Python.framework/ <=== this symbolic was needed
|
||||
# pkgconfig/
|
||||
#
|
||||
# Use the "python3HB.py" tool to make different symbolic links [*] including the above one.
|
||||
# Sonoma{kazzz-s} lib (1)% pwd
|
||||
# Sequoia{kazzz-s} lib (1)% pwd
|
||||
# /usr/local/opt/python@3.11/lib
|
||||
# Sonoma{kazzz-s} lib (2)% ll
|
||||
# Sequoia{kazzz-s} lib (2)% ll
|
||||
# total 0
|
||||
# drwxr-xr-x 4 kazzz-s admin 128 9 21 23:03 .
|
||||
# drwxr-xr-x 14 kazzz-s admin 448 9 21 18:33 ..
|
||||
# [*] lrwxr-xr-x 1 kazzz-s admin 31 9 21 23:03 Python.framework -> ../Frameworks/Python.framework/
|
||||
# drwxr-xr-x 4 kazzz-s admin 128 9 7 10:03 pkgconfig
|
||||
#
|
||||
# Sonoma{kazzz-s} Python.framework (3)% pwd
|
||||
# Sequoia{kazzz-s} Python.framework (3)% pwd
|
||||
# /usr/local/opt/python@3.11/Frameworks/Python.framework/Versions
|
||||
# Sonoma{kazzz-s} Versions (4)% ll
|
||||
# Sequoia{kazzz-s} Versions (4)% ll
|
||||
# total 0
|
||||
# drwxr-xr-x 4 kazzz-s admin 128 9 21 23:03 .
|
||||
# drwxr-xr-x 6 kazzz-s admin 192 9 21 23:03 ..
|
||||
# drwxr-xr-x 9 kazzz-s admin 288 9 7 10:03 3.11
|
||||
# [*] lrwxr-xr-x 1 kazzz-s admin 5 9 21 23:03 Current -> 3.11/
|
||||
#
|
||||
# Sonoma{kazzz-s} Python.framework (5)% pwd
|
||||
# Sequoia{kazzz-s} Python.framework (5)% pwd
|
||||
# /usr/local/opt/python@3.11/Frameworks/Python.framework
|
||||
# Sonoma{kazzz-s} Python.framework (6)% ll
|
||||
# Sequoia{kazzz-s} Python.framework (6)% ll
|
||||
# total 0
|
||||
# drwxr-xr-x 6 kazzz-s admin 192 9 21 23:03 .
|
||||
# drwxr-xr-x 3 kazzz-s admin 96 9 7 10:03 ..
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#
|
||||
# Here are dictionaries of ...
|
||||
# different modules for building KLayout (http://www.klayout.de/index.php)
|
||||
# version 0.29.11 or later on different Apple Mac OSX platforms.
|
||||
# version 0.30.2 or later on different Apple Mac OSX platforms.
|
||||
#
|
||||
# This file is imported by 'build4mac.py' script.
|
||||
#===============================================================================
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#
|
||||
# Here are utility functions and classes ...
|
||||
# for building KLayout (http://www.klayout.de/index.php)
|
||||
# version 0.29.7 or later on different Apple Mac OSX platforms.
|
||||
# version 0.30.2 or later on different Apple Mac OSX platforms.
|
||||
#
|
||||
# This file is imported by 'build4mac.py' script.
|
||||
#========================================================================================
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# File: "macbuild/macQAT.py"
|
||||
#
|
||||
# The top Python script to run "ut_runner" after building KLayout
|
||||
# (http://www.klayout.de/index.php) version 0.29.7 or later on different
|
||||
# (http://www.klayout.de/index.php) version 0.30.2 or later on different
|
||||
# Apple Mac OSX platforms.
|
||||
#
|
||||
# This script must be copied to a "*.macQAT/" directory to run.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# File: "macbuild/macQAT.sh"
|
||||
#
|
||||
# The top Bash script to run "ut_runner" after building KLayout
|
||||
# (http://www.klayout.de/index.php) version 0.29.7 or later on different
|
||||
# (http://www.klayout.de/index.php) version 0.30.2 or later on different
|
||||
# Apple Mac OSX platforms.
|
||||
#
|
||||
# This script must be copied to a "*.macQAT/" directory to run.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# File: "macbuild/macQAT2.sh"
|
||||
#
|
||||
# The top Bash script to run "ut_runner" after building KLayout
|
||||
# (http://www.klayout.de/index.php) version 0.29.7 or later on different
|
||||
# (http://www.klayout.de/index.php) version 0.30.2 or later on different
|
||||
# Apple Mac OSX platforms.
|
||||
#
|
||||
# This script must be copied to a directory that can be found in $PATH.
|
||||
|
|
|
|||
|
|
@ -78,13 +78,13 @@ def SetGlobals():
|
|||
Usage = "\n"
|
||||
Usage += "---------------------------------------------------------------------------------------------------------\n"
|
||||
Usage += "<< Usage of 'makeDMG4mac.py' >>\n"
|
||||
Usage += " for making a DMG file of KLayout 0.29.11 or later on different Apple macOS platforms.\n"
|
||||
Usage += " for making a DMG file of KLayout 0.30.2 or later on different Apple macOS platforms.\n"
|
||||
Usage += "\n"
|
||||
Usage += "$ [python] ./makeDMG4mac.py\n"
|
||||
Usage += " option & argument : descriptions | default value\n"
|
||||
Usage += " ----------------------------------------------------------------------------------+-----------------\n"
|
||||
Usage += " <-p|--pkg <dir>> : package directory created by `build4mac.py` with [-y|-Y] | ``\n"
|
||||
Usage += " : like 'LW-qt5MP.pkg.macos-Monterey-release-Rmp33Pmp311' | \n"
|
||||
Usage += " : like 'LW-qt5MP.pkg.macos-Sequoia-release-Rmp33Pmp312' | \n"
|
||||
Usage += " <-c|--clean> : clean the work directory | disabled\n"
|
||||
Usage += " <-m|--make> : make a compressed DMG file | disabled\n"
|
||||
Usage += " : <-c|--clean> and <-m|--make> are mutually exclusive | \n"
|
||||
|
|
@ -218,17 +218,17 @@ def SetGlobals():
|
|||
## To check the contents of the package directory
|
||||
#
|
||||
# The package directory name should look like:
|
||||
# * ST-qt5MP.pkg.macos-Sonoma-release-RsysPsys
|
||||
# * LW-qt5Ana3.pkg.macos-Sonoma-release-Rana3Pana3
|
||||
# * LW-qt6Brew.pkg.macos-Sonoma-release-Rhb34Phb312 --- (1)
|
||||
# * LW-qt5MP.pkg.macos-Sonoma-release-Rmp33Pmp312
|
||||
# * HW-qt6Brew.pkg.macos-Sonoma-release-RsysPhb311
|
||||
# * ST-qt5MP.pkg.macos-Sequoia-release-RsysPsys
|
||||
# * LW-qt5Ana3.pkg.macos-Sequoia-release-Rana3Pana3
|
||||
# * LW-qt6Brew.pkg.macos-Sequoia-release-Rhb34Phb312 --- (1)
|
||||
# * LW-qt5MP.pkg.macos-Sequoia-release-Rmp33Pmp312
|
||||
# * HW-qt6Brew.pkg.macos-Sequoia-release-RsysPhb311
|
||||
#
|
||||
# * ST-qt6MP.pkg.macos-Sonoma-release-RsysPsys
|
||||
# * LW-qt6MP.pkg.macos-Sonoma-release-Rmp33Pmp312
|
||||
# * ST-qt6MP.pkg.macos-Sequoia-release-RsysPsys
|
||||
# * LW-qt6MP.pkg.macos-Sequoia-release-Rmp33Pmp312
|
||||
#
|
||||
# Generated DMG will be, for example,
|
||||
# (1) ---> LW-klayout-0.29.7-macOS-Sonoma-1-qt6Brew-Rhb34Phb312.dmg
|
||||
# (1) ---> LW-klayout-0.30.2-macOS-Sequoia-1-qt6Brew-Rhb34Phb312.dmg
|
||||
#
|
||||
# @return on success, positive integer in [MB] that tells approx. occupied disc space;
|
||||
# on failure, -1
|
||||
|
|
@ -268,15 +268,15 @@ def CheckPkgDirectory():
|
|||
|
||||
#-----------------------------------------------------------------------------------------------
|
||||
# [2] Identify (Qt, Ruby, Python) from PkgDir
|
||||
# * ST-qt5MP.pkg.macos-Sonoma-release-RsysPsys
|
||||
# * LW-qt5Ana3.pkg.macos-Sonoma-release-Rana3Pana3
|
||||
# * LW-qt6Brew.pkg.macos-Sonoma-release-Rhb34Phb312
|
||||
# * LW-qt5MP.pkg.macos-Sonoma-release-Rmp33Pmp312
|
||||
# * HW-qt6Brew.pkg.macos-Sonoma-release-RsysPhb311
|
||||
# * EX-qt5MP.pkg.macos-Sonoma-release-Rhb34Pmp312
|
||||
# * ST-qt5MP.pkg.macos-Sequoia-release-RsysPsys
|
||||
# * LW-qt5Ana3.pkg.macos-Sequoia-release-Rana3Pana3
|
||||
# * LW-qt6Brew.pkg.macos-Sequoia-release-Rhb34Phb312
|
||||
# * LW-qt5MP.pkg.macos-Sequoia-release-Rmp33Pmp312
|
||||
# * HW-qt6Brew.pkg.macos-Sequoia-release-RsysPhb311
|
||||
# * EX-qt5MP.pkg.macos-Sequoia-release-Rhb34Pmp312
|
||||
#
|
||||
# * ST-qt6MP.pkg.macos-Sonoma-release-RsysPsys
|
||||
# * LW-qt6MP.pkg.macos-Sonoma-release-Rmp33Pmp312
|
||||
# * ST-qt6MP.pkg.macos-Sequoia-release-RsysPsys
|
||||
# * LW-qt6MP.pkg.macos-Sequoia-release-Rmp33Pmp312
|
||||
#-----------------------------------------------------------------------------------------------
|
||||
# 0 1 2 3 4 5 6 7
|
||||
patQRP = r'(ST|LW|HW|EX)([-])([qt5|qt6][0-9A-Za-z]+)([.]pkg[.])([A-Za-z]+[-][A-Za-z]+[-])(release|debug)([-])([0-9A-Za-z]+)'
|
||||
|
|
|
|||
|
|
@ -339,7 +339,7 @@ def Parse_CommandLine_Arguments():
|
|||
Usage += " (3) $ ./nightlyBuild.py --test |\n"
|
||||
Usage += " (4) $ ./nightlyBuild.py --check (confirm the QA Test results) |\n"
|
||||
Usage += " (5) $ ./nightlyBuild.py --makedmg 1 |\n"
|
||||
Usage += " (6) $ ./nightlyBuild.py --upload '0.29.7' |\n"
|
||||
Usage += " (6) $ ./nightlyBuild.py --upload '0.30.2' |\n"
|
||||
Usage += " (7) $ ./nightlyBuild.py --cleandmg 1 |\n"
|
||||
Usage += "-----------------------------------------------------------------------------+----------------------------\n"
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ qtVer,target,bdType
|
|||
5,0,r
|
||||
5,1,r
|
||||
6,2,r
|
||||
6,13,r
|
||||
5,13,r
|
||||
5,4,r
|
||||
#6,0,r
|
||||
#6,1,r
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 5 and column 30.
|
|
|
@ -33,8 +33,7 @@ def SetGlobals():
|
|||
Usage += "\n"
|
||||
Usage += " option & argument : descriptions | default value\n"
|
||||
Usage += " -------------------------------------------------------------------+---------------\n"
|
||||
Usage += " <-v|--version <number>>: in ['3.8', '3.9', '3.10', '3.11', '3.12', | ''\n"
|
||||
Usage += " '3.13'] |\n"
|
||||
Usage += " <-v|--version <number>>: in ['3.11', '3.12','3.13'] | ''\n"
|
||||
Usage += " [-u|-unlink] : unlink only | disabled\n"
|
||||
Usage += " [-?|--?] : print this usage and exit | disabled\n"
|
||||
Usage += "----------------------------------------------------------------------+-----------------\n"
|
||||
|
|
@ -50,7 +49,7 @@ def Parse_CLI_Args():
|
|||
|
||||
p.add_option( '-v', '--version',
|
||||
dest='version',
|
||||
help="python3 version=['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']" )
|
||||
help="python3 version=['3.11', '3.12', '3.13']" )
|
||||
|
||||
p.add_option( '-u', '--unlink',
|
||||
action='store_true',
|
||||
|
|
@ -75,7 +74,7 @@ def Parse_CLI_Args():
|
|||
|
||||
Version = opt.version
|
||||
UnlinkOnly = opt.unlink
|
||||
if not Version in [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ]:
|
||||
if not Version in [ '3.11', '3.12', '3.13' ]:
|
||||
print( "! Unsupported Python 3 version <%s>" % Version )
|
||||
print(Usage)
|
||||
sys.exit(0)
|
||||
|
|
|
|||
|
|
@ -43,8 +43,13 @@ int converter_main (int argc, char *argv[], const std::string &format)
|
|||
generic_reader_options.add_options (cmd);
|
||||
|
||||
cmd << tl::arg ("input", &infile, "The input file (any format, may be gzip compressed)",
|
||||
"You can use '+' or ',' to supply multiple files which will be read after each other into the same layout. "
|
||||
"This provides some cheap, but risky way of merging files. Beware of cell name conflicts.")
|
||||
"Multiple files can be combined using '+' or ','. '+' will combine the files in 'blending' mode. "
|
||||
"In this mode it is possible to combine identically named cells into one cell for example. This mode "
|
||||
"needs to be used with care and there some constraints - e.g. the database unit of the involved "
|
||||
"layouts needs to be the same. When using ',' as a separator, blending is not used, but the layouts "
|
||||
"are merged by first creating two layouts and then combining them into one. This mode is more robust "
|
||||
"but does not allow cell merging. '+' combination has higher priority than ',' - i.e. 'a+b,c' is "
|
||||
"understood as '(a+b),c'.")
|
||||
<< tl::arg ("output", &outfile, tl::sprintf ("The output file (%s format)", format))
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include "bdReaderOptions.h"
|
||||
#include "dbLoadLayoutOptions.h"
|
||||
#include "dbLayerMapping.h"
|
||||
#include "dbCellMapping.h"
|
||||
#include "tlCommandLineParser.h"
|
||||
|
||||
#include "tlStream.h"
|
||||
|
|
@ -831,15 +833,28 @@ static std::string::size_type find_file_sep (const std::string &s, std::string::
|
|||
}
|
||||
}
|
||||
|
||||
static std::vector<std::string> split_file_list (const std::string &infile)
|
||||
static std::vector<std::vector<std::string> > split_file_list (const std::string &infile)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
std::vector<std::vector<std::string> > files;
|
||||
files.push_back (std::vector<std::string> ());
|
||||
|
||||
size_t p = 0;
|
||||
for (size_t pp = 0; (pp = find_file_sep (infile, p)) != std::string::npos; p = pp + 1) {
|
||||
files.push_back (std::string (infile, p, pp - p));
|
||||
while (true) {
|
||||
|
||||
size_t sep = find_file_sep (infile, p);
|
||||
if (sep == std::string::npos) {
|
||||
files.back ().push_back (std::string (infile, p));
|
||||
return files;
|
||||
}
|
||||
|
||||
files.back ().push_back (std::string (infile, p, sep - p));
|
||||
if (infile [sep] == ',') {
|
||||
files.push_back (std::vector<std::string> ());
|
||||
}
|
||||
|
||||
p = sep + 1;
|
||||
|
||||
}
|
||||
files.push_back (std::string (infile, p));
|
||||
|
||||
return files;
|
||||
}
|
||||
|
|
@ -850,16 +865,73 @@ void read_files (db::Layout &layout, const std::string &infile, const db::LoadLa
|
|||
// db::LayoutLocker locker (&layout);
|
||||
// but there are yet unknown side effects
|
||||
|
||||
// enter a LEF caching context for chaining multiple DEF with the same LEF
|
||||
db::LoadLayoutOptions local_options (options);
|
||||
local_options.set_option_by_name ("lefdef_config.lef_context_enabled", true);
|
||||
std::vector<std::vector<std::string> > files = split_file_list (infile);
|
||||
|
||||
std::vector<std::string> files = split_file_list (infile);
|
||||
for (auto ff = files.begin (); ff != files.end (); ++ff) {
|
||||
|
||||
// enter a LEF caching context for chaining multiple DEF with the same LEF
|
||||
db::LoadLayoutOptions local_options (options);
|
||||
local_options.set_option_by_name ("lefdef_config.lef_context_enabled", true);
|
||||
|
||||
db::Layout tmp;
|
||||
db::Layout *ly = (ff == files.begin () ? &layout : &tmp);
|
||||
|
||||
for (auto f = ff->begin (); f != ff->end (); ++f) {
|
||||
tl::InputStream stream (*f);
|
||||
db::Reader reader (stream);
|
||||
if (f != ff->begin ()) {
|
||||
reader.set_expected_dbu (ly->dbu ());
|
||||
}
|
||||
reader.read (*ly, local_options);
|
||||
}
|
||||
|
||||
if (ly != &layout) {
|
||||
|
||||
// Move over cells from read layout to destination ("," separated blocks).
|
||||
// This path does not imply limitations in terms of DBU compatibility etc.
|
||||
|
||||
std::vector<db::cell_index_type> cells_target;
|
||||
std::vector<db::cell_index_type> cells_source;
|
||||
|
||||
for (auto c = tmp.begin_top_down (); c != tmp.end_top_cells (); ++c) {
|
||||
|
||||
cells_source.push_back (*c);
|
||||
|
||||
// as a special rule, join ghost cells if the source top cell fits into
|
||||
// a ghost cell of the target.
|
||||
auto cell_target = layout.cell_by_name (tmp.cell_name (*c));
|
||||
if (cell_target.first && layout.cell (cell_target.second).is_ghost_cell ()) {
|
||||
cells_target.push_back (cell_target.second);
|
||||
} else {
|
||||
cells_target.push_back (layout.add_cell (tmp.cell_name (*c)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ghost cell joining also works the other way around: a top cell of destination
|
||||
// can match a ghost cell of the source
|
||||
for (auto c = tmp.end_top_cells (); c != tmp.end_top_down (); ++c) {
|
||||
|
||||
const db::Cell &cell_source = tmp.cell (*c);
|
||||
auto cell_target = layout.cell_by_name (tmp.cell_name (*c));
|
||||
|
||||
if (cell_source.is_ghost_cell () && cell_target.first) {
|
||||
cells_source.push_back (*c);
|
||||
cells_target.push_back (cell_target.second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
db::CellMapping cm;
|
||||
cm.create_multi_mapping_full (layout, cells_target, tmp, cells_source);
|
||||
|
||||
db::LayerMapping lm;
|
||||
lm.create_full (layout, tmp);
|
||||
|
||||
layout.move_tree_shapes (tmp, cm, lm);
|
||||
|
||||
}
|
||||
|
||||
for (std::vector<std::string>::const_iterator f = files.begin (); f != files.end (); ++f) {
|
||||
tl::InputStream stream (*f);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout, local_options);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -483,7 +483,7 @@ TEST(10)
|
|||
std::string input;
|
||||
for (size_t i = 0; i < sizeof (def_files) / sizeof (def_files[0]); ++i) {
|
||||
if (i > 0) {
|
||||
input += ",";
|
||||
input += "+";
|
||||
}
|
||||
input += def_dir + "/" + def_files[i];
|
||||
}
|
||||
|
|
@ -510,3 +510,201 @@ TEST(10)
|
|||
|
||||
db::compare_layouts (this, layout, input_au, db::WriteOAS);
|
||||
}
|
||||
|
||||
// Merging with +
|
||||
TEST(11_1)
|
||||
{
|
||||
std::string input_dir = tl::testdata ();
|
||||
input_dir += "/bd";
|
||||
|
||||
std::string input_au = input_dir + "/strm2oas_au_1.oas";
|
||||
std::string input = input_dir + "/strm2oas_1.oas+" + input_dir + "/strm2oas_2.oas";
|
||||
|
||||
std::string output = this->tmp_file ("strm2oas_1.oas");
|
||||
const char *argv[] = { "x",
|
||||
"--blend-mode=0",
|
||||
input.c_str (),
|
||||
output.c_str ()
|
||||
};
|
||||
|
||||
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
|
||||
|
||||
db::Layout layout;
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::LoadLayoutOptions options;
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, input_au, db::WriteOAS);
|
||||
}
|
||||
|
||||
// Merging with + not allowed on different DBUs
|
||||
TEST(11_2)
|
||||
{
|
||||
std::string input_dir = tl::testdata ();
|
||||
input_dir += "/bd";
|
||||
|
||||
std::string input_au = input_dir + "/strm2oas_au_1.oas";
|
||||
std::string input = input_dir + "/strm2oas_1.oas+" + input_dir + "/strm2oas_2_10nm.oas";
|
||||
|
||||
std::string output = this->tmp_file ("strm2oas_1.oas");
|
||||
const char *argv[] = { "x",
|
||||
"--blend-mode=0",
|
||||
input.c_str (),
|
||||
output.c_str ()
|
||||
};
|
||||
|
||||
try {
|
||||
bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name);
|
||||
EXPECT_EQ (1, 0);
|
||||
} catch (tl::Exception &ex) {
|
||||
EXPECT_EQ (ex.msg (), "Former and present database units are not compatible: 0.001 (former) vs. 0.01 (present)");
|
||||
}
|
||||
}
|
||||
|
||||
// Merging with + not allowed on different DBUs
|
||||
TEST(11_3)
|
||||
{
|
||||
std::string input_dir = tl::testdata ();
|
||||
input_dir += "/bd";
|
||||
|
||||
std::string input_au = input_dir + "/strm2oas_au_3.oas";
|
||||
std::string input = input_dir + "/strm2oas_1.oas," + input_dir + "/strm2oas_2_10nm.oas";
|
||||
|
||||
std::string output = this->tmp_file ("strm2oas_3.oas");
|
||||
const char *argv[] = { "x",
|
||||
"--blend-mode=0",
|
||||
input.c_str (),
|
||||
output.c_str ()
|
||||
};
|
||||
|
||||
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
|
||||
|
||||
db::Layout layout;
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::LoadLayoutOptions options;
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, input_au, db::WriteOAS);
|
||||
}
|
||||
|
||||
// Merging with + and , under the presence of ghost cells: test+test,top->(test)
|
||||
TEST(12_1)
|
||||
{
|
||||
std::string input_dir = tl::testdata ();
|
||||
input_dir += "/bd";
|
||||
|
||||
std::string input_au = input_dir + "/strm2oas_au_12_1.oas";
|
||||
std::string input = input_dir + "/strm2oas_a.oas+" + input_dir + "/strm2oas_b.oas," + input_dir + "/strm2oas_c.oas";
|
||||
|
||||
std::string output = this->tmp_file ("strm2oas_12_1.oas");
|
||||
const char *argv[] = { "x",
|
||||
"--blend-mode=0",
|
||||
input.c_str (),
|
||||
output.c_str ()
|
||||
};
|
||||
|
||||
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
|
||||
|
||||
db::Layout layout;
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::LoadLayoutOptions options;
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, input_au, db::WriteOAS);
|
||||
}
|
||||
|
||||
// Merging with + and , under the presence of ghost cells: top->(test),test+test
|
||||
TEST(12_2)
|
||||
{
|
||||
std::string input_dir = tl::testdata ();
|
||||
input_dir += "/bd";
|
||||
|
||||
std::string input_au = input_dir + "/strm2oas_au_12_2.oas";
|
||||
std::string input = input_dir + "/strm2oas_c.oas," + input_dir + "/strm2oas_a.oas+" + input_dir + "/strm2oas_b.oas";
|
||||
|
||||
std::string output = this->tmp_file ("strm2oas_12_2.oas");
|
||||
const char *argv[] = { "x",
|
||||
"--blend-mode=0",
|
||||
input.c_str (),
|
||||
output.c_str ()
|
||||
};
|
||||
|
||||
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
|
||||
|
||||
db::Layout layout;
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::LoadLayoutOptions options;
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, input_au, db::WriteOAS);
|
||||
}
|
||||
|
||||
// Merging with + and , under the presence of ghost cells: test+test,toptop->top->(test)
|
||||
TEST(12_3)
|
||||
{
|
||||
std::string input_dir = tl::testdata ();
|
||||
input_dir += "/bd";
|
||||
|
||||
std::string input_au = input_dir + "/strm2oas_au_12_3.oas";
|
||||
std::string input = input_dir + "/strm2oas_a.oas+" + input_dir + "/strm2oas_b.oas," + input_dir + "/strm2oas_cc.oas";
|
||||
|
||||
std::string output = this->tmp_file ("strm2oas_12_3.oas");
|
||||
const char *argv[] = { "x",
|
||||
"--blend-mode=0",
|
||||
input.c_str (),
|
||||
output.c_str ()
|
||||
};
|
||||
|
||||
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
|
||||
|
||||
db::Layout layout;
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::LoadLayoutOptions options;
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, input_au, db::WriteOAS);
|
||||
}
|
||||
|
||||
// Merging with + and , under the presence of ghost cells: toptop->top->(test),test+test
|
||||
TEST(12_4)
|
||||
{
|
||||
std::string input_dir = tl::testdata ();
|
||||
input_dir += "/bd";
|
||||
|
||||
std::string input_au = input_dir + "/strm2oas_au_12_4.oas";
|
||||
std::string input = input_dir + "/strm2oas_cc.oas," + input_dir + "/strm2oas_a.oas+" + input_dir + "/strm2oas_b.oas";
|
||||
|
||||
std::string output = this->tmp_file ("strm2oas_12_4.oas");
|
||||
const char *argv[] = { "x",
|
||||
"--blend-mode=0",
|
||||
input.c_str (),
|
||||
output.c_str ()
|
||||
};
|
||||
|
||||
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
|
||||
|
||||
db::Layout layout;
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::LoadLayoutOptions options;
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, input_au, db::WriteOAS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,8 +146,6 @@ CommonReaderBase::name_for_id (size_t id) const
|
|||
void
|
||||
CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string &cn)
|
||||
{
|
||||
m_name_for_id.insert (std::make_pair (id, cn));
|
||||
|
||||
std::map<size_t, std::pair<std::string, db::cell_index_type> >::iterator iid = m_id_map.find (id);
|
||||
std::map<std::string, std::pair<size_t, db::cell_index_type> >::iterator iname = m_name_map.find (cn);
|
||||
|
||||
|
|
@ -156,9 +154,22 @@ CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string
|
|||
}
|
||||
|
||||
if (iname != m_name_map.end () && iname->second.first != null_id && iname->second.first != id) {
|
||||
common_reader_error (tl::sprintf (tl::to_string (tr ("Same cell name %s, but different IDs: %ld and %ld")), cn, id, iname->second.first));
|
||||
|
||||
// picking a different name on name clash (issue #2088)
|
||||
std::string cn_new = cn + "_id$" + tl::to_string (id);
|
||||
for (size_t i = 0; m_name_map.find (cn_new) != m_name_map.end (); ++i) {
|
||||
cn_new = cn + "_id$" + tl::to_string (id) + "$" + tl::to_string (i);
|
||||
}
|
||||
|
||||
common_reader_warn (tl::sprintf (tl::to_string (tr ("Same cell name %s, but different IDs: %ld and %ld, renaming first to %s")), cn, id, iname->second.first, cn_new));
|
||||
rename_cell (layout, id, cn_new);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
m_name_for_id.insert (std::make_pair (id, cn));
|
||||
|
||||
if (iid != m_id_map.end () && iname != m_name_map.end ()) {
|
||||
|
||||
if (iname->second.second != iid->second.second) {
|
||||
|
|
@ -240,7 +251,7 @@ CommonReaderBase::cell_for_instance (db::Layout &layout, const std::string &cn)
|
|||
}
|
||||
|
||||
void
|
||||
CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta, bool no_duplicate_instances) const
|
||||
CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta, bool no_duplicate_instances)
|
||||
{
|
||||
const db::Cell &src_cell = layout.cell (src_cell_index);
|
||||
db::Cell &target_cell = layout.cell (target_cell_index);
|
||||
|
|
@ -284,7 +295,7 @@ CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cel
|
|||
}
|
||||
|
||||
void
|
||||
CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const
|
||||
CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta)
|
||||
{
|
||||
const db::Cell &src_cell = layout.cell (src_cell_index);
|
||||
db::Cell &target_cell = layout.cell (target_cell_index);
|
||||
|
|
@ -297,20 +308,21 @@ CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_ind
|
|||
}
|
||||
|
||||
// replace all instances of the new cell with the original one
|
||||
layout.replace_instances_of (src_cell.cell_index (), target_cell.cell_index ());
|
||||
layout.replace_instances_of (src_cell_index, target_cell_index);
|
||||
|
||||
// merge meta info
|
||||
if (with_meta) {
|
||||
auto ib = layout.begin_meta (src_cell.cell_index ());
|
||||
auto ie = layout.end_meta (src_cell.cell_index ());
|
||||
auto ib = layout.begin_meta (src_cell_index);
|
||||
auto ie = layout.end_meta (src_cell_index);
|
||||
for (auto i = ib; i != ie; ++i) {
|
||||
layout.add_meta_info (target_cell.cell_index (), i->first, i->second);
|
||||
layout.add_meta_info (target_cell_index, i->first, i->second);
|
||||
}
|
||||
}
|
||||
layout.clear_meta (src_cell.cell_index ());
|
||||
layout.clear_meta (src_cell_index);
|
||||
|
||||
// finally delete the new cell
|
||||
layout.delete_cell (src_cell.cell_index ());
|
||||
m_temp_cells.erase (src_cell_index);
|
||||
layout.delete_cell (src_cell_index);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -242,12 +242,12 @@ protected:
|
|||
/**
|
||||
* @brief Merge (and delete) the src_cell into target_cell
|
||||
*/
|
||||
void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta, bool no_duplicate_instances) const;
|
||||
void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta, bool no_duplicate_instances);
|
||||
|
||||
/**
|
||||
* @brief Merge (and delete) the src_cell into target_cell without instances
|
||||
*/
|
||||
void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const;
|
||||
void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta);
|
||||
|
||||
/**
|
||||
* @brief Gets the layer name map
|
||||
|
|
|
|||
|
|
@ -77,14 +77,16 @@ public:
|
|||
}
|
||||
|
||||
// because the rasterizer can't handle overlapping cells we need to multiply the row and columns steps
|
||||
// with an integer until the effective rasterizer pitch get big enough.
|
||||
// with an integer until the effective rasterizer pitch gets big enough.
|
||||
m_row_steps *= (m_dim.x () - 1) / (m_row_steps * m_row_step.x ()) + 1;
|
||||
m_column_steps *= (m_dim.y () - 1) / (m_column_steps * m_column_step.y ()) + 1;
|
||||
|
||||
db::Box fp_bbox = fp.box ();
|
||||
|
||||
// compensate for distortion by sheared kernel
|
||||
fp_bbox.enlarge (db::Vector (db::coord_traits<db::Coord>::rounded (double (fp_bbox.height ()) * std::abs (m_column_step.x ()) / dy), db::coord_traits<db::Coord>::rounded (double (fp_bbox.width ()) * std::abs (m_row_step.y ()) / dx)));
|
||||
db::Coord ex = std::max (std::abs (db::Coord (m_column_step.x () * m_column_steps)), std::abs (db::Coord (m_row_step.x () * m_row_steps)));
|
||||
db::Coord ey = std::max (std::abs (db::Coord (m_column_step.y () * m_column_steps)), std::abs (db::Coord (m_row_step.y () * m_row_steps)));
|
||||
fp_bbox.enlarge (db::Vector (ex, ey));
|
||||
|
||||
int columns_per_rows = (int (m_row_steps) * m_row_step.y ()) / dy;
|
||||
int rows_per_columns = (int (m_column_steps) * m_column_step.x ()) / dx;
|
||||
|
|
@ -167,6 +169,11 @@ public:
|
|||
return m_area_maps [i];
|
||||
}
|
||||
|
||||
db::AreaMap &area_map (unsigned int i)
|
||||
{
|
||||
return m_area_maps [i];
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<db::AreaMap> m_area_maps;
|
||||
db::Vector m_row_step, m_column_step;
|
||||
|
|
@ -246,7 +253,7 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
|
|||
|
||||
for (unsigned int i = 0; i < am.area_maps (); ++i) {
|
||||
|
||||
const db::AreaMap &am1 = am.area_map (i);
|
||||
db::AreaMap &am1 = am.area_map (i);
|
||||
|
||||
size_t nx = am1.nx ();
|
||||
size_t ny = am1.ny ();
|
||||
|
|
@ -263,31 +270,54 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
|
|||
++jj;
|
||||
}
|
||||
|
||||
ninsts += (jj - j);
|
||||
|
||||
db::Vector p0 = (am1.p0 () - db::Point ()) - kernel_origin;
|
||||
p0 += db::Vector (i * am1.d ().x (), j * am1.d ().y ());
|
||||
|
||||
db::CellInstArray array;
|
||||
|
||||
if (jj > j + 1) {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (), (unsigned long) (jj - j), 1);
|
||||
// try to expand the array in x direction
|
||||
size_t ii = i + 1;
|
||||
for ( ; ii < nx; ++ii) {
|
||||
bool all = true;
|
||||
for (size_t k = j; k < jj && all; ++k) {
|
||||
all = am1.get (ii, k) == am1.pixel_area ();
|
||||
}
|
||||
if (all) {
|
||||
for (size_t k = j; k < jj; ++k) {
|
||||
// disable pixel, so we do not see it again in the following columns
|
||||
am1.get (ii, k) = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ninsts += (jj - j) * (ii - i);
|
||||
|
||||
if (jj > j + 1 || ii > i + 1) {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (am1.d ().x (), 0), (unsigned long) (jj - j), (unsigned long) (ii - i));
|
||||
} else {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0));
|
||||
}
|
||||
|
||||
{
|
||||
// In case we run this from a tiling processor we need to lock against multithread races
|
||||
tl::MutexLocker locker (&db::TilingProcessor::output_lock ());
|
||||
tl_assert (cell->layout () != 0);
|
||||
tl::MutexLocker locker (&cell->layout ()->lock ());
|
||||
cell->insert (array);
|
||||
}
|
||||
|
||||
if (remaining_parts) {
|
||||
if (am1.d ().y () == am1.p ().y ()) {
|
||||
filled_regions.push_back (db::Polygon (db::Box (db::Point (), db::Point (am1.p ().x (), am1.p ().y () * db::Coord (jj - j))).moved (kernel_origin + p0)));
|
||||
if (am1.d ().y () == am1.p ().y () && am1.d ().x () == am1.p ().x ()) {
|
||||
db::Box fill_box (db::Point (), db::Point (am1.p ().x () * db::Coord (ii - i), am1.p ().y () * db::Coord (jj - j)));
|
||||
filled_regions.push_back (db::Polygon (fill_box.enlarged (fill_margin).moved (kernel_origin + p0)));
|
||||
} else {
|
||||
db::Box fill_box (db::Point (), db::Point () + am1.p ());
|
||||
fill_box.enlarge (fill_margin);
|
||||
for (size_t k = 0; k < jj - j; ++k) {
|
||||
filled_regions.push_back (db::Polygon (db::Box (db::Point (), db::Point () + am1.p ()).moved (kernel_origin + p0 + db::Vector (0, am1.d ().y () * db::Coord (k)))));
|
||||
for (size_t l = 0; l < ii - i; ++l) {
|
||||
filled_regions.push_back (db::Polygon (fill_box.moved (kernel_origin + p0 + db::Vector (am1.d ().x () * db::Coord (l), am1.d ().y () * db::Coord (k)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -314,19 +344,9 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
|
|||
if (any_fill) {
|
||||
|
||||
if (remaining_parts) {
|
||||
|
||||
std::vector <db::Polygon> fp1;
|
||||
|
||||
if (fill_margin != db::Vector ()) {
|
||||
ep.size (filled_regions, fill_margin.x (), fill_margin.y (), fp1, 3 /*mode*/, false /*=don't resolve holes*/);
|
||||
filled_regions.swap (fp1);
|
||||
fp1.clear ();
|
||||
}
|
||||
|
||||
fp1.push_back (fp0);
|
||||
ep.boolean (fp1, filled_regions, *remaining_parts, db::BooleanOp::ANotB, false /*=don't resolve holes*/);
|
||||
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1918,7 +1918,7 @@ rasterize_impl (const db::polygon<C> &polygon, db::area_map<C> &am)
|
|||
|
||||
area_type aa = a;
|
||||
|
||||
if (dx == py) {
|
||||
if (dx == px) {
|
||||
|
||||
box_type cell (x, y, xx, yy);
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ join_layer_names (std::string &s, const std::string &n)
|
|||
// ReaderBase implementation
|
||||
|
||||
ReaderBase::ReaderBase ()
|
||||
: m_warnings_as_errors (false), m_warn_level (1), m_warn_count_for_same_message (0), m_first_warning (true)
|
||||
: m_warnings_as_errors (false), m_warn_level (1), m_warn_count_for_same_message (0), m_first_warning (true), m_expected_dbu (0.0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -114,6 +114,20 @@ ReaderBase::compress_warning (const std::string &msg)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReaderBase::set_expected_dbu (double dbu)
|
||||
{
|
||||
m_expected_dbu = dbu;
|
||||
}
|
||||
|
||||
void
|
||||
ReaderBase::check_dbu (double dbu) const
|
||||
{
|
||||
if (m_expected_dbu > db::epsilon && fabs (dbu - m_expected_dbu) > db::epsilon) {
|
||||
throw ReaderException (tl::sprintf (tl::to_string (tr ("Former and present database units are not compatible: %.12g (former) vs. %.12g (present)")), m_expected_dbu, dbu));
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Reader implementation
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,33 @@ public:
|
|||
*/
|
||||
int compress_warning (const std::string &msg);
|
||||
|
||||
/**
|
||||
* @brief Sets the expected database unit
|
||||
*
|
||||
* With this value set, the reader can check if the present database unit is
|
||||
* compatible with the expected one and either take actions to scale the layouts
|
||||
* or to reject the file.
|
||||
*
|
||||
* Setting the value to 0 resets the expected DBU and will disable all checks
|
||||
* or scaling.
|
||||
*/
|
||||
void set_expected_dbu (double dbu);
|
||||
|
||||
/**
|
||||
* @brief Gets the expected database unit
|
||||
*/
|
||||
double expected_dbu () const
|
||||
{
|
||||
return m_expected_dbu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the given DBU against the expected one
|
||||
*
|
||||
* This method will raise an exception if the database units do not match.
|
||||
*/
|
||||
void check_dbu (double dbu) const;
|
||||
|
||||
protected:
|
||||
virtual void init (const db::LoadLayoutOptions &options);
|
||||
|
||||
|
|
@ -147,6 +174,7 @@ private:
|
|||
std::string m_last_warning;
|
||||
int m_warn_count_for_same_message;
|
||||
bool m_first_warning;
|
||||
double m_expected_dbu;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -231,6 +259,22 @@ public:
|
|||
return mp_actual_reader->warnings_as_errors ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the expected database unit (see ReaderBase)
|
||||
*/
|
||||
void set_expected_dbu (double dbu)
|
||||
{
|
||||
return mp_actual_reader->set_expected_dbu (dbu);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the expected database unit
|
||||
*/
|
||||
double expected_dbu () const
|
||||
{
|
||||
return mp_actual_reader->expected_dbu ();
|
||||
}
|
||||
|
||||
private:
|
||||
ReaderBase *mp_actual_reader;
|
||||
tl::InputStream &m_stream;
|
||||
|
|
|
|||
|
|
@ -500,15 +500,21 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
|
|||
}
|
||||
|
||||
if (mp_shapes) {
|
||||
|
||||
// Ensures the trees are built properly - this is important in MT contexts (i.e. TilingProcessor)
|
||||
// TODO: get rid of that const cast
|
||||
(const_cast <db::Shapes *> (mp_shapes))->update ();
|
||||
|
||||
start_shapes ();
|
||||
|
||||
} else if (mp_layout && (! m_has_layers || m_current_layer < m_layers.size ())) {
|
||||
|
||||
// Ensures the trees are built properly - this is important in MT contexts (i.e. TilingProcessor)
|
||||
mp_layout->update ();
|
||||
|
||||
new_cell (receiver);
|
||||
next_shape (receiver);
|
||||
|
||||
}
|
||||
|
||||
if (mp_layout && ! at_end ()) {
|
||||
|
|
|
|||
|
|
@ -1127,10 +1127,20 @@ void Shapes::reset_bbox_dirty ()
|
|||
|
||||
void Shapes::update ()
|
||||
{
|
||||
std::unique_ptr<tl::MutexLocker> locker;
|
||||
|
||||
// If not in a layout context, we should lock here against multiple calls from different threads.
|
||||
// In a layout context, the Layout object will do that for us.
|
||||
if (layout () == 0) {
|
||||
static tl::Mutex lock;
|
||||
locker.reset (new tl::MutexLocker (&lock));
|
||||
}
|
||||
|
||||
for (tl::vector<LayerBase *>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
|
||||
(*l)->sort ();
|
||||
(*l)->update_bbox ();
|
||||
}
|
||||
|
||||
set_dirty (false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ TextWriter::write_props (const db::Layout & /*layout*/, size_t prop_id)
|
|||
const tl::Variant &name = p->first;
|
||||
const tl::Variant &value = p->second;
|
||||
|
||||
if (name.is_long () || name.is_ulong ()) {
|
||||
if (name.can_convert_to_long ()) {
|
||||
*this << " {" << int (name.to_long ()) << " {" << value.to_string () << "}}" << endl_str ();
|
||||
} else if (name.is_a_string ()) {
|
||||
*this << " {{" << name.to_string () << "} {" << value.to_string () << "}}" << endl_str ();
|
||||
|
|
|
|||
|
|
@ -223,213 +223,305 @@ static db::Shape insert_shape_with_dcplx_trans (db::Shapes *s, const db::Shape &
|
|||
return s->insert (shape, dbu_trans.inverted () * trans * dbu_trans, pm);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief Provides protection against inserting shapes into a target that is also source
|
||||
*
|
||||
* The strategy is to use an temporary Shapes container if needed.
|
||||
*/
|
||||
class ProtectedShapes
|
||||
{
|
||||
public:
|
||||
ProtectedShapes (db::Shapes *target, const db::RecursiveShapeIterator &src)
|
||||
: mp_target (target), mp_tmp_shapes ()
|
||||
{
|
||||
if (target == src.shapes () || target->layout () == src.layout ()) {
|
||||
mp_tmp_shapes.reset (new db::Shapes ());
|
||||
}
|
||||
}
|
||||
|
||||
ProtectedShapes (db::Shapes *target, const db::Shapes &src)
|
||||
: mp_target (target), mp_tmp_shapes ()
|
||||
{
|
||||
if (target == &src || target->layout () == src.layout ()) {
|
||||
mp_tmp_shapes.reset (new db::Shapes ());
|
||||
}
|
||||
}
|
||||
|
||||
ProtectedShapes (db::Shapes *target, const db::Region &src)
|
||||
: mp_target (target), mp_tmp_shapes ()
|
||||
{
|
||||
auto iter = src.begin_iter ();
|
||||
if (target == iter.first.shapes () || target->layout () == iter.first.layout ()) {
|
||||
mp_tmp_shapes.reset (new db::Shapes ());
|
||||
}
|
||||
}
|
||||
|
||||
ProtectedShapes (db::Shapes *target, const db::Texts &src)
|
||||
: mp_target (target), mp_tmp_shapes ()
|
||||
{
|
||||
auto iter = src.begin_iter ();
|
||||
if (target == iter.first.shapes () || target->layout () == iter.first.layout ()) {
|
||||
mp_tmp_shapes.reset (new db::Shapes ());
|
||||
}
|
||||
}
|
||||
|
||||
ProtectedShapes (db::Shapes *target, const db::Edges &src)
|
||||
: mp_target (target), mp_tmp_shapes ()
|
||||
{
|
||||
auto iter = src.begin_iter ();
|
||||
if (target == iter.first.shapes () || target->layout () == iter.first.layout ()) {
|
||||
mp_tmp_shapes.reset (new db::Shapes ());
|
||||
}
|
||||
}
|
||||
|
||||
ProtectedShapes (db::Shapes *target, const db::EdgePairs &src)
|
||||
: mp_target (target), mp_tmp_shapes ()
|
||||
{
|
||||
auto iter = src.begin_iter ();
|
||||
if (target == iter.first.shapes () || target->layout () == iter.first.layout ()) {
|
||||
mp_tmp_shapes.reset (new db::Shapes ());
|
||||
}
|
||||
}
|
||||
|
||||
~ProtectedShapes ()
|
||||
{
|
||||
if (mp_tmp_shapes.get ()) {
|
||||
mp_target->insert (*mp_tmp_shapes.get ());
|
||||
}
|
||||
}
|
||||
|
||||
db::Shapes *operator-> () const
|
||||
{
|
||||
if (mp_tmp_shapes.get ()) {
|
||||
return mp_tmp_shapes.get ();
|
||||
} else {
|
||||
return mp_target;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
db::Shapes *mp_target;
|
||||
std::unique_ptr<db::Shapes> mp_tmp_shapes;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static void insert_iter (db::Shapes *sh, const db::RecursiveShapeIterator &r)
|
||||
{
|
||||
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
|
||||
// lock the layout against updates while inserting
|
||||
db::LayoutLocker locker (sh->layout ());
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::RecursiveShapeIterator i = r; !i.at_end (); ++i) {
|
||||
tl::ident_map<db::properties_id_type> pm;
|
||||
sh->insert (*i, i.trans (), pm);
|
||||
ps->insert (*i, i.trans (), pm);
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_iter_with_trans (db::Shapes *sh, const db::RecursiveShapeIterator &r, const db::ICplxTrans &trans)
|
||||
{
|
||||
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
|
||||
// lock the layout against updates while inserting
|
||||
db::LayoutLocker locker (sh->layout ());
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::RecursiveShapeIterator i = r; !i.at_end (); ++i) {
|
||||
tl::ident_map<db::properties_id_type> pm;
|
||||
sh->insert (*i, trans * i.trans (), pm);
|
||||
ps->insert (*i, trans * i.trans (), pm);
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_shapes (db::Shapes *sh, const db::Shapes &s)
|
||||
{
|
||||
sh->insert (s);
|
||||
ProtectedShapes ps (sh, s);
|
||||
ps->insert (s);
|
||||
}
|
||||
|
||||
static void insert_shapes_with_flags (db::Shapes *sh, const db::Shapes &s, unsigned int flags)
|
||||
{
|
||||
sh->insert (s, flags);
|
||||
ProtectedShapes ps (sh, s);
|
||||
ps->insert (s, flags);
|
||||
}
|
||||
|
||||
static void insert_shapes_with_trans (db::Shapes *sh, const db::Shapes &s, const db::ICplxTrans &trans)
|
||||
{
|
||||
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
|
||||
// lock the layout against updates while inserting
|
||||
db::LayoutLocker locker (sh->layout ());
|
||||
ProtectedShapes ps (sh, s);
|
||||
for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::All); !i.at_end(); ++i) {
|
||||
tl::ident_map<db::properties_id_type> pm;
|
||||
sh->insert (*i, trans, pm);
|
||||
ps->insert (*i, trans, pm);
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_shapes_with_flag_and_trans (db::Shapes *sh, const db::Shapes &s, unsigned int flags, const db::ICplxTrans &trans)
|
||||
{
|
||||
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
|
||||
// lock the layout against updates while inserting
|
||||
db::LayoutLocker locker (sh->layout ());
|
||||
ProtectedShapes ps (sh, s);
|
||||
for (db::Shapes::shape_iterator i = s.begin (flags); !i.at_end(); ++i) {
|
||||
tl::ident_map<db::properties_id_type> pm;
|
||||
sh->insert (*i, trans, pm);
|
||||
ps->insert (*i, trans, pm);
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_region (db::Shapes *sh, const db::Region &r)
|
||||
{
|
||||
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
|
||||
// lock the layout against updates while inserting
|
||||
db::LayoutLocker locker (sh->layout ());
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::Region::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (*s);
|
||||
ps->insert (*s);
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_region_with_trans (db::Shapes *sh, const db::Region &r, const db::ICplxTrans &trans)
|
||||
{
|
||||
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
|
||||
// lock the layout against updates while inserting
|
||||
db::LayoutLocker locker (sh->layout ());
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::Region::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->transformed (trans));
|
||||
ps->insert (s->transformed (trans));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_region_with_dtrans (db::Shapes *sh, const db::Region &r, const db::DCplxTrans &trans)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
db::CplxTrans dbu_trans (shapes_dbu (sh));
|
||||
db::ICplxTrans itrans = dbu_trans.inverted () * trans * dbu_trans;
|
||||
for (db::Region::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->transformed (itrans));
|
||||
ps->insert (s->transformed (itrans));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edges (db::Shapes *sh, const db::Edges &r)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::Edges::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (*s);
|
||||
ps->insert (*s);
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edges_with_trans (db::Shapes *sh, const db::Edges &r, const db::ICplxTrans &trans)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::Edges::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->transformed (trans));
|
||||
ps->insert (s->transformed (trans));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edges_with_dtrans (db::Shapes *sh, const db::Edges &r, const db::DCplxTrans &trans)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
db::CplxTrans dbu_trans (shapes_dbu (sh));
|
||||
db::ICplxTrans itrans = dbu_trans.inverted () * trans * dbu_trans;
|
||||
for (db::Edges::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->transformed (itrans));
|
||||
ps->insert (s->transformed (itrans));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edge_pairs_as_polygons (db::Shapes *sh, const db::EdgePairs &r, db::Coord e)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::EdgePairs::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->normalized ().to_simple_polygon (e));
|
||||
ps->insert (s->normalized ().to_simple_polygon (e));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edge_pairs_as_polygons_d (db::Shapes *sh, const db::EdgePairs &r, db::DCoord de)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
db::Coord e = db::coord_traits<db::Coord>::rounded (de / shapes_dbu (sh));
|
||||
for (db::EdgePairs::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->normalized ().to_simple_polygon (e));
|
||||
ps->insert (s->normalized ().to_simple_polygon (e));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edge_pairs_as_polygons_with_trans (db::Shapes *sh, const db::EdgePairs &r, const db::ICplxTrans &trans, db::Coord e)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::EdgePairs::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->normalized ().to_simple_polygon (e).transformed (trans));
|
||||
ps->insert (s->normalized ().to_simple_polygon (e).transformed (trans));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edge_pairs_as_polygons_with_dtrans (db::Shapes *sh, const db::EdgePairs &r, const db::DCplxTrans &trans, db::DCoord de)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
db::Coord e = db::coord_traits<db::Coord>::rounded (de / shapes_dbu (sh));
|
||||
db::CplxTrans dbu_trans (shapes_dbu (sh));
|
||||
db::ICplxTrans itrans = dbu_trans.inverted () * trans * dbu_trans;
|
||||
for (db::EdgePairs::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->normalized ().to_simple_polygon (e).transformed (itrans));
|
||||
ps->insert (s->normalized ().to_simple_polygon (e).transformed (itrans));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edge_pairs_as_edges (db::Shapes *sh, const db::EdgePairs &r)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::EdgePairs::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->first ());
|
||||
sh->insert (s->second ());
|
||||
ps->insert (s->first ());
|
||||
ps->insert (s->second ());
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edge_pairs_as_edges_with_trans (db::Shapes *sh, const db::EdgePairs &r, const db::ICplxTrans &trans)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::EdgePairs::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->first ().transformed (trans));
|
||||
sh->insert (s->second ().transformed (trans));
|
||||
ps->insert (s->first ().transformed (trans));
|
||||
ps->insert (s->second ().transformed (trans));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edge_pairs_as_edges_with_dtrans (db::Shapes *sh, const db::EdgePairs &r, const db::DCplxTrans &trans)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
db::CplxTrans dbu_trans (shapes_dbu (sh));
|
||||
db::ICplxTrans itrans = dbu_trans.inverted () * trans * dbu_trans;
|
||||
for (db::EdgePairs::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->first ().transformed (itrans));
|
||||
sh->insert (s->second ().transformed (itrans));
|
||||
ps->insert (s->first ().transformed (itrans));
|
||||
ps->insert (s->second ().transformed (itrans));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edge_pairs (db::Shapes *sh, const db::EdgePairs &r)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::EdgePairs::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (*s);
|
||||
ps->insert (*s);
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edge_pairs_with_trans (db::Shapes *sh, const db::EdgePairs &r, const db::ICplxTrans &trans)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::EdgePairs::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->transformed (trans));
|
||||
ps->insert (s->transformed (trans));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_edge_pairs_with_dtrans (db::Shapes *sh, const db::EdgePairs &r, const db::DCplxTrans &trans)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
db::CplxTrans dbu_trans (shapes_dbu (sh));
|
||||
db::ICplxTrans itrans = dbu_trans.inverted () * trans * dbu_trans;
|
||||
for (db::EdgePairs::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->transformed (itrans));
|
||||
ps->insert (s->transformed (itrans));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_texts (db::Shapes *sh, const db::Texts &r)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::Texts::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (*s);
|
||||
ps->insert (*s);
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_texts_with_trans (db::Shapes *sh, const db::Texts &r, const db::ICplxTrans &trans)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
for (db::Texts::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->transformed (trans));
|
||||
ps->insert (s->transformed (trans));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_texts_with_dtrans (db::Shapes *sh, const db::Texts &r, const db::DCplxTrans &trans)
|
||||
{
|
||||
ProtectedShapes ps (sh, r);
|
||||
db::CplxTrans dbu_trans (shapes_dbu (sh));
|
||||
db::ICplxTrans itrans = dbu_trans.inverted () * trans * dbu_trans;
|
||||
for (db::Texts::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->transformed (itrans));
|
||||
ps->insert (s->transformed (itrans));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -345,3 +345,35 @@ TEST(5)
|
|||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testdata () + "/algo/fill_tool_au5.oas", db::WriteOAS);
|
||||
}
|
||||
|
||||
// issue #2087
|
||||
TEST(6)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/fill_tool6.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
|
||||
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
|
||||
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
|
||||
|
||||
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
|
||||
|
||||
db::Region remaining_polygons;
|
||||
|
||||
db::Vector rs (2500, 0);
|
||||
db::Vector cs (650, 2500);
|
||||
db::Box fc_box = ly.cell (fill_cell).bbox ();
|
||||
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, fc_box, rs, cs, db::Point (), false, &remaining_polygons);
|
||||
|
||||
unsigned int l100 = ly.insert_layer (db::LayerProperties (100, 0));
|
||||
remaining_polygons.insert_into (&ly, top_cell, l100);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testdata () + "/algo/fill_tool_au6.oas", db::WriteOAS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5460,8 +5460,17 @@ CODE
|
|||
# as the reference point. The reference point will also defined the footprint of the fill cell - more precisely
|
||||
# the lower left corner. When step vectors are given, the fill cell's footprint is taken to be a rectangle
|
||||
# having the horizontal and vertical step pitch for width and height respectively. This way the fill cells
|
||||
# will be arrange seamlessly. However, the cell's dimensions can be changed, so that the fill cells
|
||||
# will be arrange seamlessly.
|
||||
#
|
||||
# However, the cell's dimensions can be changed, so that the fill cells
|
||||
# can overlap or there is a space between the cells. To change the dimensions use the "dim" method.
|
||||
# This example will use a fill cell footprint of 1x1 micrometers, regardless of the step pitch:
|
||||
#
|
||||
# @code
|
||||
# p = fill_pattern("FILL_CELL")
|
||||
# p.shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
|
||||
# p.dim(1.0, 1.0)
|
||||
# @/code
|
||||
#
|
||||
# The following example specifies a fill cell with an active area of -0.5 .. 1.5 in both directions
|
||||
# (2 micron width and height). With these dimensions the fill cell's footprint is independent of the
|
||||
|
|
@ -5474,6 +5483,18 @@ CODE
|
|||
# p.dim(2.0, 2.0)
|
||||
# @/code
|
||||
#
|
||||
# Finally, the fill cell can be given a margin: this is a space around the fill cell which needs
|
||||
# to be inside the fill region. Hence, the margin can be used to implement a distance, the fill
|
||||
# cells (more precisely: their footprints) will maintain to the outside border of the fill region.
|
||||
# The following example implements a margin of 200 nm in horizontal and 250 nm in vertical direction:
|
||||
#
|
||||
# @code
|
||||
# p = fill_pattern("FILL_CELL")
|
||||
# p.shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
|
||||
# p.dim(1.0, 1.0)
|
||||
# p.margin(0.2, 0.25)
|
||||
# @/code
|
||||
#
|
||||
# With these ingredients will can use the fill function. The first example fills the polygons
|
||||
# of "to_fill" with an orthogonal pattern of 1x1 micron rectangles with a pitch of 2 microns:
|
||||
#
|
||||
|
|
@ -5574,6 +5595,7 @@ CODE
|
|||
fill_cell = pattern.create_cell(@engine._output_layout, @engine)
|
||||
top_cell = @engine._output_cell
|
||||
fc_box = dbu_trans * pattern.cell_box(row_step.x, column_step.y)
|
||||
fill_margin = dbu_trans * pattern.fill_margin
|
||||
rs = dbu_trans * row_step
|
||||
cs = dbu_trans * column_step
|
||||
origin = origin ? dbu_trans * origin : nil
|
||||
|
|
@ -5604,6 +5626,7 @@ CODE
|
|||
tp.var("rs", rs)
|
||||
tp.var("cs", cs)
|
||||
tp.var("origin", origin)
|
||||
tp.var("fill_margin", fill_margin)
|
||||
tp.var("fc_index", fc_index)
|
||||
tp.var("repeat", repeat)
|
||||
tp.var("with_left", with_left)
|
||||
|
|
@ -5616,8 +5639,8 @@ CODE
|
|||
tile_box = tile_box & tc_box;
|
||||
var left = with_left ? Region.new : nil;
|
||||
repeat ?
|
||||
(region & tile_box).fill_multi(top_cell, fc_index, fc_box, rs, cs, Vector.new, left, _tile.bbox) :
|
||||
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, Vector.new, left, _tile.bbox);
|
||||
(region & tile_box).fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, left, _tile.bbox) :
|
||||
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, fill_margin, left, _tile.bbox);
|
||||
with_left && _output(#{result_arg}, left)
|
||||
)
|
||||
END
|
||||
|
|
@ -5639,9 +5662,9 @@ END
|
|||
|
||||
@engine.run_timed("\"#{m}\" in: #{@engine.src_line}", self.data) do
|
||||
if repeat
|
||||
self.data.fill_multi(top_cell, fc_index, fc_box, rs, cs, RBA::Vector::new, result)
|
||||
self.data.fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, result)
|
||||
else
|
||||
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, RBA::Vector::new, result)
|
||||
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, fill_margin, result)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -335,6 +335,7 @@ module DRC
|
|||
@shapes = []
|
||||
@origin = nil
|
||||
@dim = nil
|
||||
@margin = RBA::DVector::new
|
||||
end
|
||||
|
||||
def create_cell(layout, engine)
|
||||
|
|
@ -350,7 +351,11 @@ module DRC
|
|||
def cell_box(def_w, def_h)
|
||||
o = @origin || self._computed_origin
|
||||
d = @dim || RBA::DVector::new(def_w, def_h)
|
||||
RBA::DBox::new(o, o + d)
|
||||
RBA::DBox::new(o, o + d).enlarged(@margin)
|
||||
end
|
||||
|
||||
def fill_margin
|
||||
-@margin
|
||||
end
|
||||
|
||||
def default_xpitch
|
||||
|
|
@ -454,6 +459,20 @@ module DRC
|
|||
|
||||
end
|
||||
|
||||
def margin(w, h)
|
||||
|
||||
if !w.is_a?(1.class) && !w.is_a?(1.0.class)
|
||||
raise("w argument not numeric FillCell#dim")
|
||||
end
|
||||
if !h.is_a?(1.class) && !h.is_a?(1.0.class)
|
||||
raise("h argument not numeric FillCell#dim")
|
||||
end
|
||||
@margin = RBA::DVector::new(w, h)
|
||||
|
||||
self
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A wrapper for the fill step definition
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 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 "tlUnitTest.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "lymMacro.h"
|
||||
|
||||
TEST(1_IHPMetal1Fill)
|
||||
{
|
||||
test_is_long_runner ();
|
||||
|
||||
std::string rs = tl::testdata ();
|
||||
rs += "/drc/drcFullTest_1.drc";
|
||||
|
||||
std::string input = tl::testdata ();
|
||||
input += "/drc/drcFullTest_1.oas";
|
||||
|
||||
std::string au = tl::testdata ();
|
||||
au += "/drc/drcFullTest_au1.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_force_gc = true\n"
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_target = '%s'\n"
|
||||
, input, output)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
|
|
@ -10,6 +10,7 @@ SOURCES = \
|
|||
drcBasicTests.cc \
|
||||
drcGenericTests.cc \
|
||||
drcSimpleTests.cc \
|
||||
drcFullTests.cc \
|
||||
drcSuiteTests.cc \
|
||||
|
||||
INCLUDEPATH += $$DRC_INC $$TL_INC $$RDB_INC $$DB_INC $$GSI_INC $$LYM_INC
|
||||
|
|
|
|||
|
|
@ -836,6 +836,7 @@ CIFReader::do_read (db::Layout &layout)
|
|||
db::LayoutLocker locker (&layout);
|
||||
|
||||
double sf = 0.01 / m_dbu;
|
||||
check_dbu (m_dbu);
|
||||
layout.dbu (m_dbu);
|
||||
|
||||
m_cellname = "{CIF top level}";
|
||||
|
|
|
|||
|
|
@ -350,6 +350,7 @@ DXFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
|||
|
||||
db::cell_index_type top = layout.add_cell("TOP"); // TODO: make variable ..
|
||||
|
||||
check_dbu (m_dbu);
|
||||
layout.dbu (m_dbu);
|
||||
do_read (layout, top);
|
||||
cleanup (layout, top);
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@ GDS2ReaderBase::do_read (db::Layout &layout)
|
|||
|
||||
m_dbuu = dbuu;
|
||||
m_dbu = dbum * 1e6; /*in micron*/
|
||||
check_dbu (m_dbu);
|
||||
layout.dbu (m_dbu);
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
static const std::pair<db::Coord, db::Coord> ext_not_set = std::make_pair (std::numeric_limits<db::Coord>::min (), std::numeric_limits<db::Coord>::min ());
|
||||
|
||||
struct DEFImporterGroup
|
||||
{
|
||||
DEFImporterGroup (const std::string &n, const std::string &rn, const std::vector<tl::GlobPattern> &m)
|
||||
|
|
@ -133,7 +135,7 @@ DEFImporter::get_def_ext (const std::string & /*ln*/, const std::pair<db::Coord,
|
|||
return std::make_pair (de, de);
|
||||
#else
|
||||
// This implementation follows the LEFDEF 5.8 spec saying the "default extension is half the wire width":
|
||||
db::Coord de = std::min (wxy.first, wxy.second) / 2;
|
||||
auto de = std::min (wxy.second, wxy.first) / 2;
|
||||
return std::make_pair (de, de);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -355,28 +357,46 @@ DEFImporter::produce_routing_geometry (db::Cell &design, const Polygon *style, u
|
|||
bool was_path_before = false;
|
||||
|
||||
std::vector<db::Point>::const_iterator pt = pts.begin ();
|
||||
std::vector<std::pair<db::Coord, db::Coord> >::const_iterator ex = ext.begin ();
|
||||
|
||||
while (pt != pts.end ()) {
|
||||
|
||||
std::vector<db::Point>::const_iterator pt0 = pt;
|
||||
auto pt0 = pt;
|
||||
auto ex0 = ex;
|
||||
++pt;
|
||||
++ex;
|
||||
if (pt == pts.end ()) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool multipart = false;
|
||||
if (is_isotropic) {
|
||||
while (pt != pts.end () && (pt[-1].x () == pt[0].x () || pt[-1].y () == pt[0].y())) {
|
||||
while (pt != pts.end ()) {
|
||||
if (! (pt[-1].x () == pt[0].x () || pt[-1].y () == pt[0].y())) {
|
||||
// non-orthogonal segments are treated otherwise, not by paths
|
||||
break;
|
||||
}
|
||||
if (pt + 1 != pts.end () && ex[0] != ext_not_set) {
|
||||
// connection points feature non-default extensions and should not be represented by paths
|
||||
break;
|
||||
}
|
||||
++pt;
|
||||
++ex;
|
||||
multipart = true;
|
||||
}
|
||||
if (multipart) {
|
||||
--pt;
|
||||
--ex;
|
||||
}
|
||||
}
|
||||
|
||||
// The next part is the interval [pt0..pt] (pt inclusive)
|
||||
// The next part is the interval [pt0..pt] (including pt)
|
||||
|
||||
if (multipart || (pt0->x () == pt0[1].x () || pt0->y () == pt0[1].y())) {
|
||||
if (! multipart && (pt0->x () == pt0[1].x () && pt0->y () == pt0[1].y())) {
|
||||
|
||||
// ignore single-point paths
|
||||
|
||||
} else if (multipart || (pt0->x () == pt0[1].x () || pt0->y () == pt0[1].y())) {
|
||||
|
||||
db::Coord wxy, wxy_perp;
|
||||
|
||||
|
|
@ -388,33 +408,27 @@ DEFImporter::produce_routing_geometry (db::Cell &design, const Polygon *style, u
|
|||
wxy_perp = w.second;
|
||||
}
|
||||
|
||||
// compute begin extension
|
||||
// compute begin and end extensions
|
||||
db::Coord be = 0;
|
||||
if (pt0 == pts.begin ()) {
|
||||
if (pt0->x () == pt0 [1].x ()) {
|
||||
be = ext.front ().second;
|
||||
} else {
|
||||
be = ext.front ().first;
|
||||
}
|
||||
if (*ex0 != ext_not_set) {
|
||||
be = (pt0->x () == pt0 [1].x ()) ? ex0->second : ex0->first;
|
||||
} else if (was_path_before) {
|
||||
// provides the overlap to the previous segment
|
||||
be = wxy_perp / 2;
|
||||
}
|
||||
|
||||
// compute end extension
|
||||
db::Coord ee = 0;
|
||||
if (pt + 1 == pts.end ()) {
|
||||
if (pt [-1].x () == pt->x ()) {
|
||||
ee = ext.back ().second;
|
||||
} else {
|
||||
ee = ext.back ().first;
|
||||
}
|
||||
if (*ex != ext_not_set) {
|
||||
ee = (pt [-1].x () == pt->x ()) ? ex->second : ex->first;
|
||||
}
|
||||
|
||||
auto pt_from = pt0;
|
||||
auto pt_to = pt + 1;
|
||||
|
||||
// do not split away end segments if they are shorter than half the width
|
||||
// Pplit paths if "joined_paths" is off. Sorry for spending the effort before to
|
||||
// compute multipath chains.
|
||||
// But now we can keep end segments joined if they are shorter than half the width
|
||||
// to establish a proper path end in that case.
|
||||
|
||||
auto pt_from_split = pt_from;
|
||||
auto pt_to_split = pt_to;
|
||||
|
|
@ -553,10 +567,6 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
|||
const std::string *rulename = 0;
|
||||
|
||||
std::pair<db::Coord, db::Coord> w (0, 0);
|
||||
if (specialnets) {
|
||||
db::Coord n = db::coord_traits<db::Coord>::rounded (get_double () * scale);
|
||||
w = std::make_pair (n, n);
|
||||
}
|
||||
|
||||
const db::Polygon *style = 0;
|
||||
|
||||
|
|
@ -564,6 +574,9 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
|||
|
||||
if (specialnets) {
|
||||
|
||||
db::Coord n = db::coord_traits<db::Coord>::rounded (get_double () * scale);
|
||||
w = std::make_pair (n, n);
|
||||
|
||||
while (test ("+")) {
|
||||
|
||||
if (test ("STYLE")) {
|
||||
|
|
@ -598,11 +611,17 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
|||
rulename = &nondefaultrule;
|
||||
}
|
||||
|
||||
std::pair<db::Coord, db::Coord> def_ext (0, 0);
|
||||
|
||||
if (! specialnets) {
|
||||
w = get_wire_width_for_rule (*rulename, ln, layout.dbu ());
|
||||
def_ext = get_def_ext (ln, w, layout.dbu ());
|
||||
}
|
||||
|
||||
// default extension for first and last point
|
||||
std::pair<db::Coord, db::Coord> def_ext (0, 0);
|
||||
std::pair<db::Coord, db::Coord> def_ext_conn = get_def_ext (ln, w, layout.dbu ());
|
||||
|
||||
if (! specialnets) {
|
||||
// first and last extensions are half width by default for routed nets
|
||||
def_ext = def_ext_conn;
|
||||
}
|
||||
|
||||
std::map<int, db::Polygon>::const_iterator s = m_styles.find (sn);
|
||||
|
|
@ -694,7 +713,7 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
|||
y = get_double ();
|
||||
}
|
||||
pts.push_back (db::Point (db::DPoint (x * scale, y * scale)));
|
||||
std::pair<db::Coord, db::Coord> ee = def_ext;
|
||||
std::pair<db::Coord, db::Coord> ee = ext_not_set;
|
||||
if (! peek (")")) {
|
||||
db::Coord e = db::coord_traits<db::Coord>::rounded (get_double () * scale);
|
||||
ee.first = ee.second = e;
|
||||
|
|
@ -706,10 +725,20 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
|||
}
|
||||
|
||||
if (pts.size () > 1) {
|
||||
|
||||
// replace the default extensions
|
||||
if (ext.front () == ext_not_set) {
|
||||
ext.front () = def_ext;
|
||||
}
|
||||
if (ext.back () == ext_not_set) {
|
||||
ext.back () = def_ext;
|
||||
}
|
||||
|
||||
std::set <unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
|
||||
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||
produce_routing_geometry (design, style, *l, prop_id, pts, ext, w);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// continue a segment with the current point and the new mask
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti
|
|||
effective_options = *lefdef_options;
|
||||
}
|
||||
|
||||
check_dbu (effective_options.dbu ());
|
||||
layout.dbu (effective_options.dbu ());
|
||||
|
||||
std::string base_path;
|
||||
|
|
|
|||
|
|
@ -432,7 +432,7 @@ TEST(def16)
|
|||
// (complete example)
|
||||
db::LEFDEFReaderOptions opt = default_options ();
|
||||
opt.set_macro_resolution_mode (1);
|
||||
run_test (_this, "def16", "lef:a.lef+lef:tech.lef+def:a.def", "au_4b.oas.gz", opt);
|
||||
run_test (_this, "def16", "lef:a.lef+lef:tech.lef+def:a.def", "au_4c.oas.gz", opt);
|
||||
}
|
||||
|
||||
TEST(100)
|
||||
|
|
@ -1153,3 +1153,10 @@ TEST(215_multiDEF)
|
|||
|
||||
db::compare_layouts (_this, ly, fn_path + "au.oas", db::WriteOAS);
|
||||
}
|
||||
|
||||
// issue-2075
|
||||
TEST(216_line_extensions)
|
||||
{
|
||||
run_test (_this, "issue-2075", "map:test.map+lef:test.lef+def:test.def", "au.oas", default_options (), false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
|||
top_cell = layout.add_cell (top_cellname.c_str ());
|
||||
}
|
||||
|
||||
check_dbu (m_dbu);
|
||||
layout.dbu (m_dbu);
|
||||
|
||||
m_cells_to_read.clear ();
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ namespace db
|
|||
MALYReader::MALYReader (tl::InputStream &s)
|
||||
: m_stream (s),
|
||||
m_progress (tl::to_string (tr ("Reading MALY file")), 1000),
|
||||
m_dbu (0.001),
|
||||
m_last_record_line (0)
|
||||
{
|
||||
m_progress.set_format (tl::to_string (tr ("%.0fk lines")));
|
||||
|
|
@ -89,7 +88,10 @@ MALYReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
|||
init (options);
|
||||
|
||||
const db::MALYReaderOptions &specific_options = options.get_options<db::MALYReaderOptions> ();
|
||||
m_dbu = specific_options.dbu;
|
||||
double dbu = specific_options.dbu;
|
||||
|
||||
check_dbu (dbu);
|
||||
layout.dbu (dbu);
|
||||
|
||||
set_layer_map (specific_options.layer_map);
|
||||
set_create_layers (specific_options.create_other_layers);
|
||||
|
|
|
|||
|
|
@ -223,7 +223,6 @@ private:
|
|||
|
||||
tl::TextInputStream m_stream;
|
||||
tl::AbsoluteProgress m_progress;
|
||||
double m_dbu;
|
||||
unsigned int m_last_record_line;
|
||||
std::string m_record;
|
||||
std::string m_record_returned;
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ TEST(10_BasicLayout)
|
|||
{
|
||||
run_test (_this, tl::testdata (), "MALY_test10.maly", "maly_test10_au.oas");
|
||||
run_test (_this, tl::testdata (), "MALY_test10.maly", "maly_test10_lm_au.oas", "A: 10, B: 11, C: 12, D: 13");
|
||||
run_test (_this, tl::testdata (), "MALY_test10.maly", "maly_test10_dbu10nm_au.oas", 0, 0.01);
|
||||
}
|
||||
|
||||
TEST(11_Titles)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -140,14 +140,14 @@ private:
|
|||
modal_variable<db::cell_index_type> mm_placement_cell;
|
||||
modal_variable<db::Coord> mm_placement_x;
|
||||
modal_variable<db::Coord> mm_placement_y;
|
||||
modal_variable<unsigned int> mm_layer;
|
||||
modal_variable<unsigned int> mm_datatype;
|
||||
modal_variable<unsigned int> mm_textlayer;
|
||||
modal_variable<unsigned int> mm_texttype;
|
||||
modal_variable<uint32_t> mm_layer;
|
||||
modal_variable<uint32_t> mm_datatype;
|
||||
modal_variable<uint32_t> mm_textlayer;
|
||||
modal_variable<uint32_t> mm_texttype;
|
||||
modal_variable<db::Coord> mm_text_x;
|
||||
modal_variable<db::Coord> mm_text_y;
|
||||
modal_variable<std::string> mm_text_string;
|
||||
modal_variable<unsigned int> mm_text_string_id;
|
||||
modal_variable<uint64_t> mm_text_string_id;
|
||||
modal_variable<db::Coord> mm_geometry_x;
|
||||
modal_variable<db::Coord> mm_geometry_y;
|
||||
modal_variable<distance_type> mm_geometry_w;
|
||||
|
|
@ -157,17 +157,17 @@ private:
|
|||
modal_variable<db::Coord> mm_path_start_extension;
|
||||
modal_variable<db::Coord> mm_path_end_extension;
|
||||
modal_variable< std::vector<db::Point> > mm_path_point_list;
|
||||
modal_variable<unsigned int> mm_ctrapezoid_type;
|
||||
modal_variable<uint32_t> mm_ctrapezoid_type;
|
||||
modal_variable<distance_type> mm_circle_radius;
|
||||
modal_variable<db::property_names_id_type> mm_last_property_name;
|
||||
modal_variable<bool> mm_last_property_is_sprop;
|
||||
modal_variable<property_value_list> mm_last_value_list;
|
||||
|
||||
std::map <unsigned long, db::properties_id_type> m_cellname_properties;
|
||||
std::map <unsigned long, std::string> m_textstrings;
|
||||
std::map <unsigned long, const db::StringRef *> m_text_forward_references;
|
||||
std::map <unsigned long, std::string> m_propstrings;
|
||||
std::map <unsigned long, std::string> m_propnames;
|
||||
std::map <uint64_t, db::properties_id_type> m_cellname_properties;
|
||||
std::map <uint64_t, std::string> m_textstrings;
|
||||
std::map <uint64_t, const db::StringRef *> m_text_forward_references;
|
||||
std::map <uint64_t, std::string> m_propstrings;
|
||||
std::map <uint64_t, std::string> m_propnames;
|
||||
|
||||
std::map <db::cell_index_type, std::vector<tl::Variant> > m_context_strings_per_cell;
|
||||
|
||||
|
|
@ -178,8 +178,8 @@ private:
|
|||
bool m_read_properties;
|
||||
bool m_read_all_properties;
|
||||
|
||||
std::map <unsigned long, db::property_names_id_type> m_propname_forward_references;
|
||||
std::map <unsigned long, std::string> m_propvalue_forward_references;
|
||||
std::map <uint64_t, db::property_names_id_type> m_propname_forward_references;
|
||||
std::map <uint64_t, std::string> m_propvalue_forward_references;
|
||||
std::map <db::properties_id_type, std::set<db::Shapes *> > m_forward_properties_for_shapes;
|
||||
std::map <db::properties_id_type, std::set<db::Instances *> > m_forward_properties_for_instances;
|
||||
std::map <db::cell_index_type, db::PropertiesSet> m_future_cell_properties;
|
||||
|
|
@ -234,42 +234,35 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
long long get_long_long ();
|
||||
unsigned long long get_ulong_long ();
|
||||
long get_long ();
|
||||
unsigned long get_ulong ();
|
||||
unsigned long get_ulong_for_divider ();
|
||||
int get_int ();
|
||||
unsigned int get_uint ();
|
||||
int64_t get_int64 ();
|
||||
uint64_t get_uint64 ();
|
||||
uint64_t get_uint64_for_divider ();
|
||||
int32_t get_int32 ();
|
||||
uint32_t get_uint32 ();
|
||||
|
||||
void get (long long &l)
|
||||
void get (int64_t &l)
|
||||
{
|
||||
l = get_long_long ();
|
||||
l = get_int64 ();
|
||||
}
|
||||
|
||||
void get (unsigned long long &l)
|
||||
void get_size (size_t &l)
|
||||
{
|
||||
l = get_ulong_long ();
|
||||
l = get_uint64 ();
|
||||
}
|
||||
|
||||
void get (long &l)
|
||||
void get (uint64_t &l)
|
||||
{
|
||||
l = get_long ();
|
||||
l = get_uint64 ();
|
||||
}
|
||||
|
||||
void get (unsigned long &l)
|
||||
void get (int32_t &l)
|
||||
{
|
||||
l = get_ulong ();
|
||||
l = get_int32 ();
|
||||
}
|
||||
|
||||
void get (int &l)
|
||||
void get (uint32_t &l)
|
||||
{
|
||||
l = get_int ();
|
||||
}
|
||||
|
||||
void get (unsigned int &l)
|
||||
{
|
||||
l = get_uint ();
|
||||
l = get_uint32 ();
|
||||
}
|
||||
|
||||
void get (double &d)
|
||||
|
|
@ -280,12 +273,12 @@ private:
|
|||
std::string get_str ();
|
||||
void get_str (std::string &s);
|
||||
double get_real ();
|
||||
db::Vector get_gdelta (long grid = 1);
|
||||
db::Vector get_3delta (long grid = 1);
|
||||
db::Vector get_2delta (long grid = 1);
|
||||
db::Coord get_coord (long grid = 1);
|
||||
db::Coord get_ucoord (unsigned long grid = 1);
|
||||
distance_type get_ucoord_as_distance (unsigned long grid = 1);
|
||||
db::Vector get_gdelta (int64_t grid = 1);
|
||||
db::Vector get_3delta (int64_t grid = 1);
|
||||
db::Vector get_2delta (int64_t grid = 1);
|
||||
db::Coord get_coord (int64_t grid = 1);
|
||||
db::Coord get_ucoord (uint64_t grid = 1);
|
||||
distance_type get_ucoord_as_distance (uint64_t grid = 1);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "tlDeflate.h"
|
||||
#include "tlMath.h"
|
||||
#include "tlUniqueName.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
|
@ -411,7 +412,7 @@ Compressor<Obj>::flush (db::OASISWriter *writer)
|
|||
if (dd != displacements.end ()) {
|
||||
|
||||
dxy = xrep ? db::Vector (safe_diff (dd->x (), d->x ()), 0) : db::Vector (0, safe_diff (dd->y (), d->y ()));
|
||||
while (dd != displacements.end () && *dd == dd[-1] + dxy) {
|
||||
while (dd != displacements.end () && *dd == dd[-1] + dxy && nxy < std::numeric_limits<int>::max ()) {
|
||||
++dd;
|
||||
++nxy;
|
||||
}
|
||||
|
|
@ -453,7 +454,7 @@ Compressor<Obj>::flush (db::OASISWriter *writer)
|
|||
db::Vector dxy = xrep ? db::Vector (safe_diff (dd->x (), d->x ()), 0) : db::Vector (0, safe_diff (dd->y (), d->y ()));
|
||||
|
||||
int nxy = 2;
|
||||
while (dd != dwindow) {
|
||||
while (dd != dwindow && nxy < std::numeric_limits<int>::max ()) {
|
||||
disp_vector::iterator df = std::lower_bound (dd + 1, dwindow, *dd + dxy);
|
||||
if (df == dwindow || *df != *dd + dxy) {
|
||||
break;
|
||||
|
|
@ -717,45 +718,17 @@ OASISWriter::write_bytes (const char *b, size_t n)
|
|||
}
|
||||
|
||||
void
|
||||
OASISWriter::write (long long n)
|
||||
OASISWriter::write (int64_t n)
|
||||
{
|
||||
if (n < 0) {
|
||||
write (((unsigned long long) (-n) << 1) | 1);
|
||||
write (((uint64_t) (-n) << 1) | 1);
|
||||
} else {
|
||||
write ((unsigned long long) n << 1);
|
||||
write ((uint64_t) n << 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OASISWriter::write (unsigned long long n)
|
||||
{
|
||||
char buffer [50];
|
||||
char *bptr = buffer;
|
||||
|
||||
do {
|
||||
unsigned char b = n & 0x7f;
|
||||
n >>= 7;
|
||||
if (n > 0) {
|
||||
b |= 0x80;
|
||||
}
|
||||
*bptr++ = (char) b;
|
||||
} while (n > 0);
|
||||
|
||||
write_bytes (buffer, bptr - buffer);
|
||||
}
|
||||
|
||||
void
|
||||
OASISWriter::write (long n)
|
||||
{
|
||||
if (n < 0) {
|
||||
write (((unsigned long) (-n) << 1) | 1);
|
||||
} else {
|
||||
write ((unsigned long) n << 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OASISWriter::write (unsigned long n)
|
||||
OASISWriter::write (uint64_t n)
|
||||
{
|
||||
char buffer [50];
|
||||
char *bptr = buffer;
|
||||
|
|
@ -775,15 +748,15 @@ OASISWriter::write (unsigned long n)
|
|||
void
|
||||
OASISWriter::write (float d)
|
||||
{
|
||||
if (fabs (d) >= 0.5 && fabs (floor (d + 0.5) - d) < 1e-6 && fabs (d) < double (std::numeric_limits<long>::max ())) {
|
||||
if (fabs (d) >= 0.5 && fabs (floor (d + 0.5) - d) < 1e-6 && fabs (d) < double (std::numeric_limits<int64_t>::max ())) {
|
||||
|
||||
// whole number (negative or positive)
|
||||
if (d < 0.0) {
|
||||
write_byte (1);
|
||||
write ((unsigned long) floor (-d + 0.5));
|
||||
write ((uint64_t) floor (-d + 0.5));
|
||||
} else {
|
||||
write_byte (0);
|
||||
write ((unsigned long) floor (d + 0.5));
|
||||
write ((uint64_t) floor (d + 0.5));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -799,7 +772,7 @@ OASISWriter::write (float d)
|
|||
f2i.d = d;
|
||||
uint32_t i = f2i.i;
|
||||
char b[sizeof (f2i.i)];
|
||||
for (unsigned int n = 0; n < sizeof (f2i.i); n++) {
|
||||
for (size_t n = 0; n < sizeof (f2i.i); n++) {
|
||||
b[n] = char (i & 0xff);
|
||||
i >>= 8;
|
||||
}
|
||||
|
|
@ -811,15 +784,15 @@ OASISWriter::write (float d)
|
|||
void
|
||||
OASISWriter::write (double d)
|
||||
{
|
||||
if (fabs (d) >= 0.5 && fabs (floor (d + 0.5) - d) < 1e-10 && fabs (d) < double (std::numeric_limits<long>::max ())) {
|
||||
if (fabs (d) >= 0.5 && fabs (floor (d + 0.5) - d) < 1e-10 && fabs (d) < double (std::numeric_limits<int64_t>::max ())) {
|
||||
|
||||
// whole number (negative or positive)
|
||||
if (d < 0.0) {
|
||||
write_byte (1);
|
||||
write ((unsigned long) floor (-d + 0.5));
|
||||
write ((uint64_t) floor (-d + 0.5));
|
||||
} else {
|
||||
write_byte (0);
|
||||
write ((unsigned long) floor (d + 0.5));
|
||||
write ((uint64_t) floor (d + 0.5));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -848,7 +821,7 @@ void
|
|||
OASISWriter::write_bstring (const char *s)
|
||||
{
|
||||
size_t l = strlen (s);
|
||||
write (l);
|
||||
write ((uint64_t) l);
|
||||
write_bytes (s, l);
|
||||
}
|
||||
|
||||
|
|
@ -867,7 +840,7 @@ void
|
|||
OASISWriter::write_astring (const char *s)
|
||||
{
|
||||
std::string nstr = make_astring (s);
|
||||
write (nstr.size ());
|
||||
write ((uint64_t) nstr.size ());
|
||||
write_bytes (nstr.c_str (), nstr.size ());
|
||||
}
|
||||
|
||||
|
|
@ -886,7 +859,7 @@ void
|
|||
OASISWriter::write_nstring (const char *s)
|
||||
{
|
||||
std::string nstr = make_nstring (s);
|
||||
write (nstr.size ());
|
||||
write ((uint64_t) nstr.size ());
|
||||
write_bytes (nstr.c_str (), nstr.size ());
|
||||
}
|
||||
|
||||
|
|
@ -903,8 +876,8 @@ OASISWriter::write_gdelta (const db::Vector &p, double sf)
|
|||
|
||||
if (x == -y || x == y || x == 0 || y == 0) {
|
||||
|
||||
unsigned long long dir = 0;
|
||||
unsigned long long l = 0;
|
||||
uint64_t dir = 0;
|
||||
uint64_t l = 0;
|
||||
|
||||
if (x > 0) {
|
||||
l = x;
|
||||
|
|
@ -938,11 +911,11 @@ OASISWriter::write_gdelta (const db::Vector &p, double sf)
|
|||
|
||||
} else {
|
||||
|
||||
unsigned long long d;
|
||||
uint64_t d;
|
||||
if (x < 0) {
|
||||
d = ((unsigned long long) -x << 2) | 3;
|
||||
d = ((uint64_t) -x << 2) | 3;
|
||||
} else {
|
||||
d = ((unsigned long long) x << 2) | 1;
|
||||
d = ((uint64_t) x << 2) | 1;
|
||||
}
|
||||
write (d);
|
||||
write (y);
|
||||
|
|
@ -1090,8 +1063,8 @@ OASISWriter::end_cblock ()
|
|||
// RFC1951 compression:
|
||||
write_byte (0);
|
||||
|
||||
write (m_cblock_buffer.size ());
|
||||
write (m_cblock_compressed.size ());
|
||||
write ((uint64_t) m_cblock_buffer.size ());
|
||||
write ((uint64_t) m_cblock_compressed.size ());
|
||||
|
||||
write_bytes (m_cblock_compressed.data (), m_cblock_compressed.size ());
|
||||
|
||||
|
|
@ -1158,7 +1131,7 @@ OASISWriter::write_propname_table (size_t &propnames_table_pos, const std::vecto
|
|||
{
|
||||
// write the property names collected so far in the order of the ID's.
|
||||
|
||||
std::vector<std::pair<unsigned long, std::string> > rev_pn;
|
||||
std::vector<std::pair<uint64_t, std::string> > rev_pn;
|
||||
rev_pn.reserve (m_propnames.size ());
|
||||
for (auto p = m_propnames.begin (); p != m_propnames.end (); ++p) {
|
||||
rev_pn.push_back (std::make_pair (p->second, p->first));
|
||||
|
|
@ -1166,7 +1139,7 @@ OASISWriter::write_propname_table (size_t &propnames_table_pos, const std::vecto
|
|||
std::sort (rev_pn.begin (), rev_pn.end ());
|
||||
|
||||
for (auto p = rev_pn.begin (); p != rev_pn.end (); ++p) {
|
||||
tl_assert (p->first == (unsigned long)(p - rev_pn.begin ()));
|
||||
tl_assert (p->first == (uint64_t)(p - rev_pn.begin ()));
|
||||
begin_table (propnames_table_pos);
|
||||
write_record_id (7);
|
||||
write_nstring (p->second.c_str ());
|
||||
|
|
@ -1236,7 +1209,7 @@ OASISWriter::write_propstring_table (size_t &propstrings_table_pos, const std::v
|
|||
{
|
||||
// write the property strings collected so far in the order of the ID's.
|
||||
|
||||
std::vector<std::pair<unsigned long, const std::string *> > rev_ps;
|
||||
std::vector<std::pair<uint64_t, const std::string *> > rev_ps;
|
||||
rev_ps.reserve (m_propstrings.size ());
|
||||
for (auto p = m_propstrings.begin (); p != m_propstrings.end (); ++p) {
|
||||
rev_ps.push_back (std::make_pair (p->second, &p->first));
|
||||
|
|
@ -1246,7 +1219,7 @@ OASISWriter::write_propstring_table (size_t &propstrings_table_pos, const std::v
|
|||
tl_assert (rev_ps.size () == size_t (m_propstring_id));
|
||||
|
||||
for (auto p = rev_ps.begin (); p != rev_ps.end (); ++p) {
|
||||
tl_assert (p->first == (unsigned long)(p - rev_ps.begin ()));
|
||||
tl_assert (p->first == (uint64_t)(p - rev_ps.begin ()));
|
||||
begin_table (propstrings_table_pos);
|
||||
write_record_id (9);
|
||||
write_bstring (p->second->c_str ());
|
||||
|
|
@ -1334,9 +1307,9 @@ OASISWriter::write_cellname_table (size_t &cellnames_table_pos, const std::vecto
|
|||
begin_table (cellnames_table_pos);
|
||||
|
||||
write_record_id (sequential ? 3 : 4);
|
||||
write_nstring (layout.cell_name (*cell));
|
||||
write_nstring (cell_nstring (*cell));
|
||||
if (! sequential) {
|
||||
write ((unsigned long) *cell);
|
||||
write ((uint64_t) *cell);
|
||||
}
|
||||
|
||||
if (m_options.write_std_properties >= 1) {
|
||||
|
|
@ -1391,7 +1364,7 @@ OASISWriter::write_textstring_table (size_t &textstrings_table_pos, const std::v
|
|||
// write present text strings
|
||||
|
||||
// collect present strings by ID
|
||||
std::vector<std::pair<unsigned long, const std::string *> > rev_ts;
|
||||
std::vector<std::pair<uint64_t, const std::string *> > rev_ts;
|
||||
rev_ts.reserve (m_textstrings.size ());
|
||||
for (auto p = m_textstrings.begin (); p != m_textstrings.end (); ++p) {
|
||||
rev_ts.push_back (std::make_pair (p->second, &p->first));
|
||||
|
|
@ -1401,7 +1374,7 @@ OASISWriter::write_textstring_table (size_t &textstrings_table_pos, const std::v
|
|||
tl_assert (rev_ts.size () == size_t (m_textstring_id));
|
||||
|
||||
for (auto t = rev_ts.begin (); t != rev_ts.end (); ++t) {
|
||||
tl_assert (t->first == (unsigned long)(t - rev_ts.begin ()));
|
||||
tl_assert (t->first == (uint64_t)(t - rev_ts.begin ()));
|
||||
begin_table (textstrings_table_pos);
|
||||
write_record_id (5);
|
||||
write_nstring (t->second->c_str ());
|
||||
|
|
@ -1444,16 +1417,16 @@ OASISWriter::write_layername_table (size_t &layernames_table_pos, const std::vec
|
|||
write_record_id (11);
|
||||
write_nstring (l->second.name.c_str ());
|
||||
write_byte (3);
|
||||
write ((unsigned long) l->second.layer);
|
||||
write ((uint64_t) l->second.layer);
|
||||
write_byte (3);
|
||||
write ((unsigned long) l->second.datatype);
|
||||
write ((uint64_t) l->second.datatype);
|
||||
|
||||
write_record_id (12);
|
||||
write_nstring (l->second.name.c_str ());
|
||||
write_byte (3);
|
||||
write ((unsigned long) l->second.layer);
|
||||
write ((uint64_t) l->second.layer);
|
||||
write_byte (3);
|
||||
write ((unsigned long) l->second.datatype);
|
||||
write ((uint64_t) l->second.datatype);
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
|
|
@ -1476,6 +1449,31 @@ static bool skip_cell_body (const db::Cell &cref)
|
|||
return cref.is_ghost_cell () && cref.empty ();
|
||||
}
|
||||
|
||||
void
|
||||
OASISWriter::create_cell_nstrings (const db::Layout &layout, const std::set <db::cell_index_type> &cell_set)
|
||||
{
|
||||
m_cell_nstrings.clear ();
|
||||
|
||||
std::set<std::string> names;
|
||||
|
||||
for (auto c = cell_set.begin (); c != cell_set.end (); ++c) {
|
||||
|
||||
std::string cn = make_nstring (layout.cell_name (*c));
|
||||
cn = tl::unique_name (cn, names);
|
||||
|
||||
m_cell_nstrings.insert (std::make_pair (*c, cn));
|
||||
names.insert (cn);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
OASISWriter::cell_nstring (db::cell_index_type cell_index)
|
||||
{
|
||||
auto n = m_cell_nstrings.find (cell_index);
|
||||
tl_assert (n != m_cell_nstrings.end ());
|
||||
return n->second.c_str ();
|
||||
}
|
||||
|
||||
void
|
||||
OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options)
|
||||
|
|
@ -1510,6 +1508,8 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
|||
std::set <db::cell_index_type> cell_set;
|
||||
options.get_cells (layout, cell_set, layers);
|
||||
|
||||
create_cell_nstrings (layout, cell_set);
|
||||
|
||||
// create a cell index vector sorted bottom-up
|
||||
std::vector <db::cell_index_type> cells, cells_by_index;
|
||||
|
||||
|
|
@ -1602,7 +1602,7 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
|||
is_top = (cell_set.find (*p) == cell_set.end ());
|
||||
}
|
||||
if (is_top) {
|
||||
write_property_def (s_top_cell_name, tl::Variant (make_nstring (layout.cell_name (*cell))), true);
|
||||
write_property_def (s_top_cell_name, tl::Variant (cell_nstring (*cell)), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1679,7 +1679,7 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
|||
cell_positions.insert (std::make_pair (*cell, mp_stream->pos ()));
|
||||
|
||||
write_record_id (13); // CELL
|
||||
write ((unsigned long) *cell);
|
||||
write ((uint64_t) *cell);
|
||||
|
||||
reset_modal_variables ();
|
||||
|
||||
|
|
@ -1696,8 +1696,8 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
|||
|
||||
write_record_id (28);
|
||||
write_byte (char (0xf6));
|
||||
unsigned long pnid = 0;
|
||||
std::map <std::string, unsigned long>::const_iterator pni = m_propnames.find (klayout_context_name);
|
||||
uint64_t pnid = 0;
|
||||
std::map <std::string, uint64_t>::const_iterator pni = m_propnames.find (klayout_context_name);
|
||||
if (pni == m_propnames.end ()) {
|
||||
pnid = m_propname_id++;
|
||||
m_propnames.insert (std::make_pair (klayout_context_name, pnid));
|
||||
|
|
@ -1706,12 +1706,12 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
|||
}
|
||||
write (pnid);
|
||||
|
||||
write ((unsigned long) context_prop_strings.size ());
|
||||
write ((uint64_t) context_prop_strings.size ());
|
||||
|
||||
for (std::vector <std::string>::const_iterator c = context_prop_strings.begin (); c != context_prop_strings.end (); ++c) {
|
||||
write_byte (14); // b-string by reference number
|
||||
unsigned long psid = 0;
|
||||
std::map <std::string, unsigned long>::const_iterator psi = m_propstrings.find (*c);
|
||||
uint64_t psid = 0;
|
||||
std::map <std::string, uint64_t>::const_iterator psi = m_propstrings.find (*c);
|
||||
if (psi == m_propstrings.end ()) {
|
||||
psid = m_propstring_id++;
|
||||
m_propstrings.insert (std::make_pair (*c, psid)).second;
|
||||
|
|
@ -1795,23 +1795,23 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
|||
|
||||
// cellnames
|
||||
write_byte (1);
|
||||
write (cellnames_table_pos);
|
||||
write ((uint64_t) cellnames_table_pos);
|
||||
|
||||
// textstrings
|
||||
write_byte (1);
|
||||
write (textstrings_table_pos);
|
||||
write ((uint64_t) textstrings_table_pos);
|
||||
|
||||
// propnames
|
||||
write_byte (1);
|
||||
write (propnames_table_pos);
|
||||
write ((uint64_t) propnames_table_pos);
|
||||
|
||||
// propstrings
|
||||
write_byte (1);
|
||||
write (propstrings_table_pos);
|
||||
write ((uint64_t) propstrings_table_pos);
|
||||
|
||||
// layernames
|
||||
write_byte (1);
|
||||
write (layernames_table_pos);
|
||||
write ((uint64_t) layernames_table_pos);
|
||||
|
||||
// xnames (not used)
|
||||
write_byte (1);
|
||||
|
|
@ -1875,11 +1875,11 @@ OASISWriter::write (const Repetition &rep)
|
|||
|
||||
if (g <= 1) {
|
||||
write_byte (10);
|
||||
write (iterated->size () - 1);
|
||||
write ((uint64_t) iterated->size () - 1);
|
||||
g = 1;
|
||||
} else {
|
||||
write_byte (11);
|
||||
write (iterated->size () - 1);
|
||||
write ((uint64_t) iterated->size () - 1);
|
||||
write_ucoord (g, 1.0);
|
||||
}
|
||||
|
||||
|
|
@ -1909,39 +1909,39 @@ OASISWriter::write (const Repetition &rep)
|
|||
|
||||
if (b.x () == 0 && b.y () >= 0) {
|
||||
write_byte (3);
|
||||
write (bmax - 2);
|
||||
write ((uint64_t) bmax - 2);
|
||||
write_ucoord (b.y ());
|
||||
} else if (b.y () == 0 && b.x () >= 0) {
|
||||
write_byte (2);
|
||||
write (bmax - 2);
|
||||
write ((uint64_t) bmax - 2);
|
||||
write_ucoord (b.x ());
|
||||
} else {
|
||||
write_byte (9);
|
||||
write (bmax - 2);
|
||||
write ((uint64_t) bmax - 2);
|
||||
write_gdelta (b);
|
||||
}
|
||||
|
||||
} else if (b.x () == 0 && b.y () >= 0 && a.y () == 0 && a.x () >= 0) {
|
||||
|
||||
write_byte (1);
|
||||
write (amax - 2);
|
||||
write (bmax - 2);
|
||||
write ((uint64_t) amax - 2);
|
||||
write ((uint64_t) bmax - 2);
|
||||
write_ucoord (a.x ());
|
||||
write_ucoord (b.y ());
|
||||
|
||||
} else if (b.y () == 0 && b.x () >= 0 && a.x () == 0 && a.y () >= 0) {
|
||||
|
||||
write_byte (1);
|
||||
write (bmax - 2);
|
||||
write (amax - 2);
|
||||
write ((uint64_t) bmax - 2);
|
||||
write ((uint64_t) amax - 2);
|
||||
write_ucoord (b.x ());
|
||||
write_ucoord (a.y ());
|
||||
|
||||
} else {
|
||||
|
||||
write_byte (8);
|
||||
write (amax - 2);
|
||||
write (bmax - 2);
|
||||
write ((uint64_t) amax - 2);
|
||||
write ((uint64_t) bmax - 2);
|
||||
write_gdelta (a);
|
||||
write_gdelta (b);
|
||||
|
||||
|
|
@ -1985,7 +1985,7 @@ OASISWriter::write_inst_with_rep (const db::CellInstArray &inst, db::properties_
|
|||
|
||||
if (info & 0x80) {
|
||||
mm_placement_cell = inst.object ().cell_index ();
|
||||
write ((unsigned long) mm_placement_cell.get ());
|
||||
write ((uint64_t) mm_placement_cell.get ());
|
||||
}
|
||||
|
||||
if (inst.is_complex ()) {
|
||||
|
|
@ -2191,7 +2191,7 @@ OASISWriter::write_property_def (const char *name_str, const std::vector<tl::Var
|
|||
|
||||
if (! same_name) {
|
||||
|
||||
std::map <std::string, unsigned long>::const_iterator pni = m_propnames.find (name_str);
|
||||
std::map <std::string, uint64_t>::const_iterator pni = m_propnames.find (name_str);
|
||||
|
||||
// In strict mode always write property ID's: before we have issued the table we can
|
||||
// create new ID's.
|
||||
|
|
@ -2219,11 +2219,11 @@ OASISWriter::write_property_def (const char *name_str, const std::vector<tl::Var
|
|||
if (! same_value) {
|
||||
|
||||
if (pvl.size () >= 15) {
|
||||
write ((unsigned long) pvl.size ());
|
||||
write ((uint64_t) pvl.size ());
|
||||
}
|
||||
|
||||
// write property values
|
||||
for (unsigned long i = 0; i < pvl.size (); ++i) {
|
||||
for (uint64_t i = 0; i < pvl.size (); ++i) {
|
||||
|
||||
const tl::Variant &v = pvl[i];
|
||||
|
||||
|
|
@ -2234,27 +2234,27 @@ OASISWriter::write_property_def (const char *name_str, const std::vector<tl::Var
|
|||
} else if (v.is_longlong ()) {
|
||||
|
||||
write_byte (9);
|
||||
write (v.to_longlong ());
|
||||
write ((int64_t) v.to_longlong ());
|
||||
|
||||
} else if (v.is_ulonglong ()) {
|
||||
|
||||
write_byte (8);
|
||||
write (v.to_ulonglong ());
|
||||
write ((uint64_t) v.to_ulonglong ());
|
||||
|
||||
} else if (v.is_long ()) {
|
||||
|
||||
write_byte (9);
|
||||
write (v.to_long ());
|
||||
write ((int64_t) v.to_long ());
|
||||
|
||||
} else if (v.is_ulong ()) {
|
||||
|
||||
write_byte (8);
|
||||
write (v.to_ulong ());
|
||||
write ((uint64_t) v.to_ulong ());
|
||||
|
||||
} else {
|
||||
|
||||
const char *pvs = v.to_string ();
|
||||
std::map <std::string, unsigned long>::const_iterator pvi = m_propstrings.find (pvs);
|
||||
std::map <std::string, uint64_t>::const_iterator pvi = m_propstrings.find (pvs);
|
||||
|
||||
// In strict mode always write property string ID's: before we have issued the table we can
|
||||
// create new ID's.
|
||||
|
|
@ -2335,7 +2335,7 @@ OASISWriter::write_pointlist (const std::vector<db::Vector> &pointlist, bool for
|
|||
// manhattan pointlist
|
||||
write_byte (type);
|
||||
size_t implicit = for_polygons ? 1 : 0;
|
||||
write ((unsigned long) (pointlist.size () - implicit));
|
||||
write ((uint64_t) (pointlist.size () - implicit));
|
||||
|
||||
db::Vector plast (0, 0);
|
||||
for (std::vector<db::Vector>::const_iterator p = pointlist.begin (); p != pointlist.end () - implicit; ++p) {
|
||||
|
|
@ -2353,7 +2353,7 @@ OASISWriter::write_pointlist (const std::vector<db::Vector> &pointlist, bool for
|
|||
|
||||
// generic pointlist
|
||||
write_byte (4);
|
||||
write ((unsigned long) pointlist.size ());
|
||||
write ((uint64_t) pointlist.size ());
|
||||
db::Vector plast (0, 0);
|
||||
if (m_sf == 1.0) {
|
||||
for (std::vector<db::Vector>::const_iterator p = pointlist.begin (); p != pointlist.end (); ++p) {
|
||||
|
|
@ -2378,8 +2378,8 @@ OASISWriter::write (const db::Text &text, db::properties_id_type prop_id, const
|
|||
|
||||
db::Trans trans = text.trans ();
|
||||
|
||||
unsigned long text_id = 0;
|
||||
std::map <std::string, unsigned long>::const_iterator ts = m_textstrings.find (text.string ());
|
||||
uint64_t text_id = 0;
|
||||
std::map <std::string, uint64_t>::const_iterator ts = m_textstrings.find (text.string ());
|
||||
if (ts == m_textstrings.end ()) {
|
||||
text_id = m_textstring_id++;
|
||||
m_textstrings.insert (std::make_pair (text.string (), text_id));
|
||||
|
|
@ -2412,15 +2412,15 @@ OASISWriter::write (const db::Text &text, db::properties_id_type prop_id, const
|
|||
write_byte (info);
|
||||
if (info & 0x40) {
|
||||
mm_text_string = text.string ();
|
||||
write ((unsigned long) text_id);
|
||||
write ((uint64_t) text_id);
|
||||
}
|
||||
if (info & 0x01) {
|
||||
mm_textlayer = m_layer;
|
||||
write ((unsigned long) m_layer);
|
||||
write ((uint64_t) m_layer);
|
||||
}
|
||||
if (info & 0x02) {
|
||||
mm_texttype = m_datatype;
|
||||
write ((unsigned long) m_datatype);
|
||||
write ((uint64_t) m_datatype);
|
||||
}
|
||||
if (info & 0x10) {
|
||||
mm_text_x = trans.disp ().x ();
|
||||
|
|
@ -2496,11 +2496,11 @@ OASISWriter::write (const db::SimplePolygon &polygon, db::properties_id_type pro
|
|||
|
||||
if (info & 0x01) {
|
||||
mm_layer = m_layer;
|
||||
write ((unsigned long) m_layer);
|
||||
write ((uint64_t) m_layer);
|
||||
}
|
||||
if (info & 0x02) {
|
||||
mm_datatype = m_datatype;
|
||||
write ((unsigned long) m_datatype);
|
||||
write ((uint64_t) m_datatype);
|
||||
}
|
||||
if (info & 0x20) {
|
||||
mm_polygon_point_list.swap (m_pointlist);
|
||||
|
|
@ -2597,11 +2597,11 @@ OASISWriter::write (const db::Polygon &polygon, db::properties_id_type prop_id,
|
|||
|
||||
if (info & 0x01) {
|
||||
mm_layer = m_layer;
|
||||
write ((unsigned long) m_layer);
|
||||
write ((uint64_t) m_layer);
|
||||
}
|
||||
if (info & 0x02) {
|
||||
mm_datatype = m_datatype;
|
||||
write ((unsigned long) m_datatype);
|
||||
write ((uint64_t) m_datatype);
|
||||
}
|
||||
if (info & 0x20) {
|
||||
mm_polygon_point_list.swap (m_pointlist);
|
||||
|
|
@ -2667,11 +2667,11 @@ OASISWriter::write (const db::Box &box, db::properties_id_type prop_id, const db
|
|||
|
||||
if (info & 0x01) {
|
||||
mm_layer = m_layer;
|
||||
write ((unsigned long) m_layer);
|
||||
write ((uint64_t) m_layer);
|
||||
}
|
||||
if (info & 0x02) {
|
||||
mm_datatype = m_datatype;
|
||||
write ((unsigned long) m_datatype);
|
||||
write ((uint64_t) m_datatype);
|
||||
}
|
||||
|
||||
mm_geometry_w = box.width ();
|
||||
|
|
@ -2772,11 +2772,11 @@ OASISWriter::write (const db::Path &path, db::properties_id_type prop_id, const
|
|||
|
||||
if (info & 0x01) {
|
||||
mm_layer = m_layer;
|
||||
write ((unsigned long) m_layer);
|
||||
write ((uint64_t) m_layer);
|
||||
}
|
||||
if (info & 0x02) {
|
||||
mm_datatype = m_datatype;
|
||||
write ((unsigned long) m_datatype);
|
||||
write ((uint64_t) m_datatype);
|
||||
}
|
||||
if (info & 0x20) {
|
||||
mm_circle_radius = hw;
|
||||
|
|
@ -2853,11 +2853,11 @@ OASISWriter::write (const db::Path &path, db::properties_id_type prop_id, const
|
|||
|
||||
if (info & 0x01) {
|
||||
mm_layer = m_layer;
|
||||
write ((unsigned long) m_layer);
|
||||
write ((uint64_t) m_layer);
|
||||
}
|
||||
if (info & 0x02) {
|
||||
mm_datatype = m_datatype;
|
||||
write ((unsigned long) m_datatype);
|
||||
write ((uint64_t) m_datatype);
|
||||
}
|
||||
if (info & 0x40) {
|
||||
mm_path_halfwidth = hw;
|
||||
|
|
@ -3046,11 +3046,11 @@ OASISWriter::write (const db::Edge &edge, db::properties_id_type prop_id, const
|
|||
|
||||
if (info & 0x01) {
|
||||
mm_layer = m_layer;
|
||||
write ((unsigned long) m_layer);
|
||||
write ((uint64_t) m_layer);
|
||||
}
|
||||
if (info & 0x02) {
|
||||
mm_datatype = m_datatype;
|
||||
write ((unsigned long) m_datatype);
|
||||
write ((uint64_t) m_datatype);
|
||||
}
|
||||
if (info & 0x40) {
|
||||
mm_path_halfwidth = 0;
|
||||
|
|
|
|||
|
|
@ -208,14 +208,15 @@ private:
|
|||
tl::OutputMemoryStream m_cblock_buffer;
|
||||
tl::OutputMemoryStream m_cblock_compressed;
|
||||
bool m_in_cblock;
|
||||
unsigned long m_propname_id;
|
||||
unsigned long m_propstring_id;
|
||||
unsigned long m_textstring_id;
|
||||
uint64_t m_propname_id;
|
||||
uint64_t m_propstring_id;
|
||||
uint64_t m_textstring_id;
|
||||
bool m_proptables_written;
|
||||
|
||||
std::map <std::string, unsigned long> m_textstrings;
|
||||
std::map <std::string, unsigned long> m_propnames;
|
||||
std::map <std::string, unsigned long> m_propstrings;
|
||||
std::map <std::string, uint64_t> m_textstrings;
|
||||
std::map <std::string, uint64_t> m_propnames;
|
||||
std::map <std::string, uint64_t> m_propstrings;
|
||||
std::map <db::cell_index_type, std::string> m_cell_nstrings;
|
||||
|
||||
typedef std::vector<tl::Variant> property_value_list;
|
||||
|
||||
|
|
@ -223,23 +224,23 @@ private:
|
|||
modal_variable<db::cell_index_type> mm_placement_cell;
|
||||
modal_variable<db::Coord> mm_placement_x;
|
||||
modal_variable<db::Coord> mm_placement_y;
|
||||
modal_variable<unsigned int> mm_layer;
|
||||
modal_variable<unsigned int> mm_datatype;
|
||||
modal_variable<unsigned int> mm_textlayer;
|
||||
modal_variable<unsigned int> mm_texttype;
|
||||
modal_variable<uint32_t> mm_layer;
|
||||
modal_variable<uint32_t> mm_datatype;
|
||||
modal_variable<uint32_t> mm_textlayer;
|
||||
modal_variable<uint32_t> mm_texttype;
|
||||
modal_variable<db::Coord> mm_text_x;
|
||||
modal_variable<db::Coord> mm_text_y;
|
||||
modal_variable<std::string> mm_text_string;
|
||||
modal_variable<db::Coord> mm_geometry_x;
|
||||
modal_variable<db::Coord> mm_geometry_y;
|
||||
modal_variable<db::Coord> mm_geometry_w;
|
||||
modal_variable<db::Coord> mm_geometry_h;
|
||||
modal_variable<db::coord_traits<db::Coord>::distance_type> mm_geometry_w;
|
||||
modal_variable<db::coord_traits<db::Coord>::distance_type> mm_geometry_h;
|
||||
modal_variable< std::vector<db::Vector> > mm_polygon_point_list;
|
||||
modal_variable<db::Coord> mm_path_halfwidth;
|
||||
modal_variable<db::Coord> mm_path_start_extension;
|
||||
modal_variable<db::Coord> mm_path_end_extension;
|
||||
modal_variable< std::vector<db::Vector> > mm_path_point_list;
|
||||
modal_variable<unsigned int> mm_ctrapezoid_type;
|
||||
modal_variable<uint32_t> mm_ctrapezoid_type;
|
||||
modal_variable<db::Coord> mm_circle_radius;
|
||||
modal_variable<std::string> mm_last_property_name;
|
||||
modal_variable<bool> mm_last_property_is_sprop;
|
||||
|
|
@ -248,6 +249,9 @@ private:
|
|||
OASISWriterOptions m_options;
|
||||
tl::AbsoluteProgress m_progress;
|
||||
|
||||
void create_cell_nstrings (const db::Layout &layout, const std::set <db::cell_index_type> &cell_set);
|
||||
const char *cell_nstring(db::cell_index_type cell_index);
|
||||
|
||||
void write_record_id (char b);
|
||||
void write_byte (char b);
|
||||
void write_bytes (const char *b, size_t n);
|
||||
|
|
@ -273,19 +277,17 @@ private:
|
|||
|
||||
void write (double d);
|
||||
void write (float d);
|
||||
void write (long n);
|
||||
void write (unsigned long n);
|
||||
void write (long long n);
|
||||
void write (unsigned long long n);
|
||||
void write (int64_t n);
|
||||
void write (uint64_t n);
|
||||
|
||||
void write (int n)
|
||||
void write (int32_t n)
|
||||
{
|
||||
write (long (n));
|
||||
write (int64_t (n));
|
||||
}
|
||||
|
||||
void write (unsigned int n)
|
||||
void write (uint32_t n)
|
||||
{
|
||||
write ((unsigned long) (n));
|
||||
write ((uint64_t) (n));
|
||||
}
|
||||
|
||||
void write (const Repetition &rep);
|
||||
|
|
|
|||
|
|
@ -662,20 +662,37 @@ TEST(Bug_1799)
|
|||
EXPECT_EQ (ps2.value (pn).to_string (), "hello, world!");
|
||||
}
|
||||
|
||||
// Modified in #2088 to give a warning
|
||||
TEST(DuplicateCellname)
|
||||
{
|
||||
db::Manager m (false);
|
||||
db::Layout layout (&m);
|
||||
|
||||
try {
|
||||
tl::InputStream file (tl::testdata () + "/oasis/duplicate_cellname.oas");
|
||||
tl::InputStream file (tl::testdata () + "/oasis/duplicate_cellname.oas");
|
||||
db::OASISReader reader (file);
|
||||
reader.read (layout);
|
||||
|
||||
std::string fn_au (tl::testdata () + "/oasis/duplicate_cellname_au.oas");
|
||||
db::compare_layouts (_this, layout, fn_au, db::NoNormalization, 1);
|
||||
}
|
||||
|
||||
TEST(BlendCrash)
|
||||
{
|
||||
db::Manager m (false);
|
||||
db::Layout layout (&m);
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testdata () + "/oasis/blend_crash1.oas");
|
||||
db::OASISReader reader (file);
|
||||
reader.read (layout);
|
||||
EXPECT_EQ (false, true);
|
||||
} catch (tl::CancelException &ex) {
|
||||
// Seen when private test data is not installed
|
||||
throw;
|
||||
} catch (tl::Exception &ex) {
|
||||
EXPECT_EQ (ex.msg ().find ("Same cell name TOP, but different IDs: 3 and 0 (position=1070, cell=)"), size_t (0));
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testdata () + "/oasis/blend_crash2.oas");
|
||||
db::OASISReader reader (file);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
std::string fn_au (tl::testdata () + "/oasis/blend_crash_au.gds.gz");
|
||||
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2072,3 +2072,31 @@ TEST(130d)
|
|||
run_test130 (_this, true, true);
|
||||
}
|
||||
|
||||
// Issue #2088 (name duplication)
|
||||
TEST(140)
|
||||
{
|
||||
db::Layout layout_org;
|
||||
|
||||
layout_org.add_cell ("X X");
|
||||
layout_org.add_cell ("X*X");
|
||||
|
||||
std::string tmp_file = tl::TestBase::tmp_file (tl::sprintf ("tmp_dbOASISWriter140.oas"));
|
||||
|
||||
{
|
||||
tl::OutputStream out (tmp_file);
|
||||
db::SaveLayoutOptions options;
|
||||
options.set_format ("OASIS");
|
||||
db::Writer writer (options);
|
||||
writer.write (layout_org, out);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream in (tmp_file);
|
||||
db::Reader reader (in);
|
||||
db::Layout gg;
|
||||
reader.set_warnings_as_errors (true);
|
||||
reader.read (gg);
|
||||
|
||||
db::compare_layouts (_this, gg, tl::testdata () + "/oasis/dbOASISWriter40_au.gds", db::NoNormalization);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1142,6 +1142,8 @@ public:
|
|||
db::GerberImporter importer (warn_level ());
|
||||
data.setup_importer (&importer);
|
||||
|
||||
check_dbu (data.dbu);
|
||||
|
||||
importer.read (layout);
|
||||
|
||||
std::string lyr_file = data.get_layer_properties_file ();
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
source($drc_test_source)
|
||||
target($drc_test_target)
|
||||
|
||||
verbose
|
||||
|
||||
ncpu = 4
|
||||
|
||||
chip = input(189, 4)
|
||||
chip.output(189, 4)
|
||||
|
||||
# NOTE: this must not happen in tiled mode as the sealring
|
||||
# is only visible as a whole in flat mode
|
||||
sealring = source.cell("sealring")
|
||||
|
||||
metal1_seal = sealring.input(8, 0)
|
||||
metal1_seal_inner = metal1_seal.holes
|
||||
# NOTE: metal1_seal_outer is empty if there is no sealring ->
|
||||
# the full chip will be filled
|
||||
metal1_seal_outer = chip.interacting(metal1_seal_inner) - metal1_seal_inner
|
||||
|
||||
# Everything else can be done in tiled mode
|
||||
|
||||
tiles(500)
|
||||
tile_borders(2.0)
|
||||
threads(ncpu)
|
||||
|
||||
metal1 = input(8, 0)
|
||||
metal1.output(8, 0)
|
||||
metal1_fill = input(8, 22)
|
||||
metal1_nofill = input(8, 23) + metal1_seal_outer
|
||||
|
||||
metal1_dist = 0.42
|
||||
min_space_to_fill = 1.0
|
||||
|
||||
pattern = fill_pattern("METAL1_FILL1")
|
||||
pattern.shape(8, 22, box(0.0, 0.0, 5.0, 5.0))
|
||||
pattern.dim(5.0, 5.0)
|
||||
pattern.margin(metal1_dist, metal1_dist)
|
||||
|
||||
to_fill = chip - metal1_nofill - metal1
|
||||
|
||||
to_fill = to_fill.fill_with_left(pattern, hstep(7.0, 0), vstep(1.5, 7.0), multi_origin)
|
||||
|
||||
pattern = fill_pattern("METAL1_FILL2")
|
||||
pattern.shape(8, 22, box(0.0, 0.0, 2.0, 2.0))
|
||||
pattern.dim(2.0, 2.0)
|
||||
pattern.margin(metal1_dist, metal1_dist)
|
||||
|
||||
to_fill = to_fill.fill_with_left(pattern, hstep(2.42, 0), vstep(0.65, 2.42), multi_origin)
|
||||
|
||||
pattern = fill_pattern("METAL1_FILL3")
|
||||
pattern.shape(8, 22, box(0.0, 0.0, 1.2, 1.2))
|
||||
pattern.dim(1.2, 1.2)
|
||||
pattern.margin(metal1_dist, metal1_dist)
|
||||
|
||||
to_fill = to_fill.fill_with_left(pattern, hstep(1.62, 0), vstep(0.3, 1.62), multi_origin)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -14,18 +14,22 @@ f2 = extent - l1.sized(1.0)
|
|||
p1 = fill_pattern("PAT1").shape(100, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
|
||||
p2 = fill_pattern("PAT2").shape(100, 1, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
|
||||
p3 = fill_pattern("PAT3").shape(100, 2, box(0, 0, 1.um, 1.um)).shape(1000, 0, box(-0.5.um, -0.5.um, 1.5.um, 1.5.um))
|
||||
p4 = fill_pattern("PAT4").shape(100, 3, box(0, 0, 1.um, 1.um)).dim(1.um, 1.um).margin(2.um, 4.um)
|
||||
|
||||
p11 = fill_pattern("PAT11").shape(101, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
|
||||
p12 = fill_pattern("PAT12").shape(101, 1, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
|
||||
p13 = fill_pattern("PAT13").shape(101, 2, box(0, 0, 1.um, 1.um)).shape(1000, 0, box(-0.5.um, -0.5.um, 1.5.um, 1.5.um))
|
||||
p14 = fill_pattern("PAT14").shape(101, 3, box(0, 0, 1.um, 1.um)).dim(1.um, 1.um).margin(2.um, 4.um)
|
||||
|
||||
f1.fill(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0))
|
||||
f1.fill(p2, hstep(2.0, 1.0), vstep(-1.0, 2.0), auto_origin)
|
||||
f1.fill(p3)
|
||||
f1.fill(p4, hstep(2.0, 0), vstep(0, 2.0))
|
||||
|
||||
f2.fill(p11, hstep(2.0, 1.0), vstep(-1.0, 2.0))
|
||||
f2.fill(p12, hstep(2.0, 1.0), vstep(-1.0, 2.0), auto_origin)
|
||||
f2.fill(p13)
|
||||
f2.fill(p14, hstep(2.0, 0), vstep(0, 2.0))
|
||||
|
||||
l1.output(1, 0)
|
||||
f1.output(10, 0)
|
||||
|
|
|
|||
|
|
@ -11,8 +11,12 @@ l1 = input(1, 0)
|
|||
f1 = l1
|
||||
|
||||
p1 = fill_pattern("PAT1").shape(100, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
|
||||
p2 = fill_pattern("PAT1").shape(100, 1, box(0, 0, 1.um, 1.um)).dim(1.um, 1.um)
|
||||
p3 = fill_pattern("PAT1").shape(100, 2, box(0, 0, 1.um, 1.um)).dim(1.um, 1.um).margin(1.um, 2.um)
|
||||
|
||||
f1.fill_with_left(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(100, 0)
|
||||
f1.fill_with_left(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(101, 0)
|
||||
f1.fill_with_left(p2, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(101, 1)
|
||||
f1.fill_with_left(p3, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(101, 2)
|
||||
|
||||
l1.output(1, 0)
|
||||
f1.output(10, 0)
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,16 @@
|
|||
VERSION 5.8 ;
|
||||
|
||||
DESIGN test ;
|
||||
|
||||
UNITS DISTANCE MICRONS 2000 ;
|
||||
|
||||
DIEAREA ( 0 0 ) ( 6000 3000 ) ;
|
||||
|
||||
VIAS 1 ;
|
||||
END VIAS
|
||||
|
||||
NETS 1 ;
|
||||
- dummy + ROUTED M2 ( 1670 830 ) ( * * 300 ) ( 4950 * 300 ) ( * 2000 300 ) ;
|
||||
END NETS
|
||||
|
||||
END DESIGN
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
VERSION 5.8 ;
|
||||
|
||||
UNITS
|
||||
DATABASE MICRONS 2000 ;
|
||||
END UNITS
|
||||
|
||||
LAYER M2
|
||||
TYPE ROUTING ;
|
||||
WIDTH 0.2 ;
|
||||
END M2
|
||||
|
||||
END LIBRARY
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
DIEAREA ALL 108 0
|
||||
M2 NET 32 0
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1728,6 +1728,181 @@ class DBShapes_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
def test_15
|
||||
|
||||
# Various container insert methods
|
||||
|
||||
ly = RBA::Layout::new
|
||||
l1 = ly.layer(1, 0)
|
||||
top = ly.create_cell("TOP")
|
||||
top.shapes(l1).insert(RBA::Box::new(2000))
|
||||
|
||||
shapes2 = RBA::Shapes::new
|
||||
shapes2.insert(RBA::Box::new(4000))
|
||||
|
||||
shapes = RBA::Shapes::new
|
||||
shapes.insert(shapes2)
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "box (-2000,-2000;2000,2000)")
|
||||
|
||||
# self-insert
|
||||
shapes.insert(shapes)
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "box (-2000,-2000;2000,2000);box (-2000,-2000;2000,2000)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
shapes.insert(shapes2, RBA::Shapes::SBoxes)
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "box (-2000,-2000;2000,2000)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
shapes.insert(shapes2, RBA::Shapes::SPolygons)
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "")
|
||||
|
||||
shapes.clear
|
||||
|
||||
shapes.insert(shapes2, RBA::ICplxTrans::new(RBA::Vector::new(100, 200)))
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "box (-1900,-1800;2100,2200)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
shapes.insert(shapes2, RBA::Shapes::SBoxes, RBA::ICplxTrans::new(RBA::Vector::new(100, 200)))
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "box (-1900,-1800;2100,2200)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
shapes.insert(shapes2, RBA::Shapes::SPolygons, RBA::ICplxTrans::new(RBA::Vector::new(100, 200)))
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "")
|
||||
|
||||
shapes.clear
|
||||
|
||||
shapes.insert(top.begin_shapes_rec(l1))
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "box (-1000,-1000;1000,1000)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
shapes.insert(top.begin_shapes_rec(l1), RBA::ICplxTrans::new(100, 200))
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "box (-900,-800;1100,1200)")
|
||||
|
||||
top.shapes(l1).insert(top.begin_shapes_rec(l1))
|
||||
assert_equal(top.shapes(l1).each.collect { |s| s.to_s }.join(";"), "box (-1000,-1000;1000,1000);box (-1000,-1000;1000,1000)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
r = RBA::Region::new(RBA::Box::new(2000))
|
||||
shapes.insert(r)
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "polygon (-1000,-1000;-1000,1000;1000,1000;1000,-1000)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
r = RBA::Region::new(RBA::Box::new(2000))
|
||||
shapes.insert(r, RBA::ICplxTrans::new(100, 200))
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "polygon (-900,-800;-900,1200;1100,1200;1100,-800)")
|
||||
|
||||
top.shapes(l1).clear
|
||||
top.shapes(l1).insert(r, RBA::DCplxTrans::new(0.1, 0.2))
|
||||
assert_equal(top.shapes(l1).each.collect { |s| s.to_s }.join(";"), "polygon (-900,-800;-900,1200;1100,1200;1100,-800)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
r = RBA::Edges::new(RBA::Edge::new(0, 0, 1000, 2000))
|
||||
shapes.insert(r)
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "edge (0,0;1000,2000)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
r = RBA::Edges::new(RBA::Edge::new(0, 0, 1000, 2000))
|
||||
shapes.insert(r, RBA::ICplxTrans::new(100, 200))
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "edge (100,200;1100,2200)")
|
||||
|
||||
top.shapes(l1).clear
|
||||
top.shapes(l1).insert(r, RBA::DCplxTrans::new(0.1, 0.2))
|
||||
assert_equal(top.shapes(l1).each.collect { |s| s.to_s }.join(";"), "edge (100,200;1100,2200)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
r = RBA::EdgePairs::new(RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 2000), RBA::Edge::new(100, 0, 100, 2000)))
|
||||
shapes.insert_as_polygons(r, 10)
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "simple_polygon (-10,-10;-10,2010;110,2010;110,-10)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
r = RBA::EdgePairs::new(RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 2000), RBA::Edge::new(100, 0, 100, 2000)))
|
||||
shapes.insert_as_polygons(r, RBA::ICplxTrans::new(100, 200), 10)
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "simple_polygon (90,190;90,2210;210,2210;210,190)")
|
||||
|
||||
top.shapes(l1).clear
|
||||
top.shapes(l1).insert_as_polygons(r, RBA::DCplxTrans::new(0.1, 0.2), 0.01)
|
||||
assert_equal(top.shapes(l1).each.collect { |s| s.to_s }.join(";"), "simple_polygon (90,190;90,2210;210,2210;210,190)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
r = RBA::EdgePairs::new(RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 2000), RBA::Edge::new(100, 0, 100, 2000)))
|
||||
shapes.insert_as_edges(r)
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "edge (0,0;0,2000);edge (100,0;100,2000)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
r = RBA::EdgePairs::new(RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 2000), RBA::Edge::new(100, 0, 100, 2000)))
|
||||
shapes.insert_as_edges(r, RBA::ICplxTrans::new(100, 200))
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "edge (100,200;100,2200);edge (200,200;200,2200)")
|
||||
|
||||
top.shapes(l1).clear
|
||||
top.shapes(l1).insert_as_edges(r, RBA::DCplxTrans::new(0.1, 0.2))
|
||||
assert_equal(top.shapes(l1).each.collect { |s| s.to_s }.join(";"), "edge (100,200;100,2200);edge (200,200;200,2200)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
r = RBA::EdgePairs::new(RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 2000), RBA::Edge::new(100, 0, 100, 2000)))
|
||||
shapes.insert(r)
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "edge_pair (0,0;0,2000)/(100,0;100,2000)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
r = RBA::EdgePairs::new(RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 2000), RBA::Edge::new(100, 0, 100, 2000)))
|
||||
shapes.insert(r, RBA::ICplxTrans::new(100, 200))
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "edge_pair (100,200;100,2200)/(200,200;200,2200)")
|
||||
|
||||
top.shapes(l1).clear
|
||||
top.shapes(l1).insert(r, RBA::DCplxTrans::new(0.1, 0.2))
|
||||
assert_equal(top.shapes(l1).each.collect { |s| s.to_s }.join(";"), "edge_pair (100,200;100,2200)/(200,200;200,2200)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
r = RBA::Texts::new(RBA::Text::new("Text", RBA::Trans::new(100, 200)))
|
||||
shapes.insert(r)
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "text ('Text',r0 100,200)")
|
||||
|
||||
shapes.clear
|
||||
|
||||
r = RBA::Texts::new(RBA::Text::new("Text", RBA::Trans::new(100, 200)))
|
||||
shapes.insert(r, RBA::ICplxTrans::new(100, 200))
|
||||
assert_equal(shapes.each.collect { |s| s.to_s }.join(";"), "text ('Text',r0 200,400)")
|
||||
|
||||
top.shapes(l1).clear
|
||||
top.shapes(l1).insert(r, RBA::DCplxTrans::new(0.1, 0.2))
|
||||
assert_equal(top.shapes(l1).each.collect { |s| s.to_s }.join(";"), "text ('Text',r0 200,400)")
|
||||
|
||||
end
|
||||
|
||||
def test_16
|
||||
|
||||
# issue #2094
|
||||
# speedy insert -> should not take more than a few seconds
|
||||
|
||||
ly = RBA::Layout::new
|
||||
l1 = ly.layer(1, 0)
|
||||
main = ly.create_cell("MAIN")
|
||||
|
||||
box = RBA::Region::new(RBA::Box::new(4000))
|
||||
|
||||
100000.times do
|
||||
main.shapes(l1).insert(box)
|
||||
end
|
||||
|
||||
assert_equal(main.shapes(l1).size, 100000)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue