mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into wip
This commit is contained in:
commit
fd0c60761f
|
|
@ -4,7 +4,8 @@ name: Build Python Wheels
|
|||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
# Running on PRs is enough
|
||||
# push:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
|
|
@ -23,6 +24,13 @@ jobs:
|
|||
- os: "ubuntu-latest"
|
||||
cibuild: "*musllinux*"
|
||||
steps:
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
android: false
|
||||
dotnet: false
|
||||
haskell: false
|
||||
- uses: hmarr/debug-action@v2
|
||||
- name: Cancel Workflow Action
|
||||
uses: styfle/cancel-workflow-action@0.9.1
|
||||
|
|
|
|||
20
Changelog
20
Changelog
|
|
@ -1,3 +1,23 @@
|
|||
0.28.6 (2023-03-16):
|
||||
* Enhancement: %GITHUB%/issues/1249 Include expanded/collapsed state of layer properties into session
|
||||
* Bugfix: %GITHUB%/issues/1265 Issues installing klayout with pip on macOS related to libpng
|
||||
* Enhancement: %GITHUB%/issues/1271 __version__ attribute in Python modules available now
|
||||
* Bugfix: %GITHUB%/issues/1287 Goto Position (CRTL+G) is not showing the origin (0,0)
|
||||
* Bugfix: %GITHUB%/issues/1291 Better compatibility of PyQt5 and KLayout (i.e. debugger does not crash)
|
||||
* Enhancement: %GITHUB%/issues/1294 Persisting layer properties in sessions
|
||||
* Bugfix: %GITHUB%/issues/1302 Select filter is not applied in partial mode
|
||||
* Bugfix: %GITHUB%/issues/1304 Spice netlist reader: should read "M" terminals in DGS order
|
||||
* Bugfix: %GITHUB%/issues/1309 Incomplete fill (polygon rasterizer issue)
|
||||
* Bugfix: %GITHUB%/issues/1315 Cannot export layers from Marker Browser in viewer mode
|
||||
* Bugfix/enhancement: some LEF/DEF parser issues solved with the help of a new complete sample case
|
||||
* Bugfix: Avoid a segfault while editing a ruler. This happens is both a selection and a transient selection is active.
|
||||
* Enhancement: Some enhancements for image editing (e.g. selection remains after moving handles)
|
||||
* Enhancement: klayout.db Python module is auto-loaded for providing stream readers
|
||||
* Enhancement: Spice reader now supports parametric subcircuits
|
||||
* Enhancement: Build issue fixed for Qt 5.15.2 bindings
|
||||
* Enhancement: Including Python's matplotlib into Windows binaries
|
||||
* Bugfix: Reading fillcell-generated inputs again into DRC deck now also works for deep mode
|
||||
|
||||
0.28.5 (2023-02-05):
|
||||
* Bugfix: %GITHUB%/issues/1275 Region.sized after .smooth returns empty region
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
klayout (0.28.6-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
- See changelog
|
||||
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Thu, 16 Mar 2023 21:23:46 +0100
|
||||
|
||||
klayout (0.28.5-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
Relevant KLayout version: 0.28.4<br>
|
||||
Relevant KLayout version: 0.28.6<br>
|
||||
Author: Kazzz-S<br>
|
||||
Last modified: 2023-02-01<br>
|
||||
Last modified: 2023-03-19<br>
|
||||
|
||||
# 1. Introduction
|
||||
This directory **`macbuild`** contains various files required for building KLayout (http://www.klayout.de/) version 0.28.4 or later for different 64-bit macOS, including:
|
||||
This directory **`macbuild`** contains various files required for building KLayout (http://www.klayout.de/) version 0.28.6 or later for different 64-bit macOS, including:
|
||||
* Catalina (10.15.7) : the primary development environment
|
||||
* Big Sur (11.x) : experimental; Apple (M1|M2) chip is not tested since the author does not own an (M1|M2) Mac
|
||||
* Monterey (12.x) : -- ditto --
|
||||
|
|
@ -73,7 +73,7 @@ You need to have the followings:
|
|||
```
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
<< Usage of 'build4mac.py' >>
|
||||
for building KLayout 0.28.4 or later on different Apple macOS / Mac OSX platforms.
|
||||
for building KLayout 0.28.6 or later on different Apple macOS / Mac OSX platforms.
|
||||
|
||||
$ [python] ./build4mac.py
|
||||
option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details)| default value
|
||||
|
|
@ -130,7 +130,7 @@ $ [python] ./build4mac.py
|
|||
```
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
<< Usage of 'build4mac.py' >>
|
||||
for building KLayout 0.28.4 or later on different Apple macOS / Mac OSX platforms.
|
||||
for building KLayout 0.28.6 or later on different Apple macOS / Mac OSX platforms.
|
||||
|
||||
$ [python] ./build4mac.py
|
||||
option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details)| default value
|
||||
|
|
@ -236,7 +236,7 @@ $ ./build4mac.py -q qt5macports -r mp32 -p mp39
|
|||
2. Confirm successful build (it will take about one hour, depending on your machine spec).
|
||||
3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.<br>
|
||||
The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step.<br>
|
||||
If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Python Module (\*.whl, \*.egg) will be built and deployed under **klayout.app/Contents/pymod-dist/**.
|
||||
If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Python Module (\*.whl) will be built and deployed under **klayout.app/Contents/pymod-dist/**.
|
||||
|
||||
```
|
||||
$ ./build4mac.py -q qt5macports -r mp32 -p mp39 -Y
|
||||
|
|
@ -263,7 +263,7 @@ $ ./build4mac.py -q qt5brew -r hb32 -p hb39
|
|||
2. Confirm successful build (it will take about one hour, depending on your machine spec).
|
||||
3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.<br>
|
||||
The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step.<br>
|
||||
If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Python Module (\*.whl, \*.egg) will be built and deployed under **klayout.app/Contents/pymod-dist/**.
|
||||
If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Python Module (\*.whl) will be built and deployed under **klayout.app/Contents/pymod-dist/**.
|
||||
|
||||
```
|
||||
$ ./build4mac.py -q qt5brew -r hb32 -p hb39 -Y
|
||||
|
|
@ -316,7 +316,7 @@ $ ./build4mac.py -q qt5ana3 -r ana3 -p ana3
|
|||
2. Confirm successful build (it will take about one hour, depending on your machine spec).
|
||||
3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.<br>
|
||||
The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step.<br>
|
||||
If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Python Module (\*.whl, \*.egg) will be built and deployed under **klayout.app/Contents/pymod-dist/**.
|
||||
If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Python Module (\*.whl) will be built and deployed under **klayout.app/Contents/pymod-dist/**.
|
||||
|
||||
```
|
||||
$ ./build4mac.py -q qt5ana3 -r ana3 -p ana3 -Y
|
||||
|
|
@ -352,8 +352,8 @@ $ cd /where/'build.sh'/exists
|
|||
$ ./makeDMG4mac.py -p LW-qt5MP.pkg.macos-Catalina-release-Rmp32Pmp39 -m
|
||||
```
|
||||
This command will generate the two files below:<br>
|
||||
* **`LW-klayout-0.28.4-macOS-Catalina-1-qt5MP-Rmp32Pmp39.dmg`** ---(1) the main DMG file
|
||||
* **`LW-klayout-0.28.4-macOS-Catalina-1-qt5MP-Rmp32Pmp39.dmg.md5`** ---(2) MD5-value text file
|
||||
* **`LW-klayout-0.28.6-macOS-Catalina-1-qt5MP-Rmp32Pmp39.dmg`** ---(1) the main DMG file
|
||||
* **`LW-klayout-0.28.6-macOS-Catalina-1-qt5MP-Rmp32Pmp39.dmg.md5`** ---(2) MD5-value text file
|
||||
|
||||
# Known issues
|
||||
Because we assume some specific versions of non-OS-standard Ruby and Python, updating MacPorts, Homebrew, or Anaconda3 may cause build- and link errors.<br>
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -47,7 +47,7 @@ def GenerateUsage(platform):
|
|||
usage = "\n"
|
||||
usage += "---------------------------------------------------------------------------------------------------------\n"
|
||||
usage += "<< Usage of 'build4mac.py' >>\n"
|
||||
usage += " for building KLayout 0.28.4 or later on different Apple macOS / Mac OSX platforms.\n"
|
||||
usage += " for building KLayout 0.28.6 or later on different Apple macOS / Mac OSX platforms.\n"
|
||||
usage += "\n"
|
||||
usage += "$ [python] ./build4mac.py\n"
|
||||
usage += " option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details)| default value\n"
|
||||
|
|
@ -905,19 +905,31 @@ def Build_pymod(parameters):
|
|||
PymodDistDir = parameters['pymod_dist']
|
||||
# Using MacPorts
|
||||
if PymodDistDir[ModulePython] == 'dist-MP3':
|
||||
addBinPath = "/opt/local/bin"
|
||||
addIncPath = "/opt/local/include"
|
||||
addLibPath = "/opt/local/lib"
|
||||
# Using Homebrew
|
||||
elif PymodDistDir[ModulePython] == 'dist-HB3':
|
||||
addIncPath = "%s/include" % DefaultHomebrewRoot # defined in "build4mac_env.py"
|
||||
addLibPath = "%s/lib" % DefaultHomebrewRoot # defined in "build4mac_env.py"
|
||||
addBinPath = "%s/bin" % DefaultHomebrewRoot # defined in "build4mac_env.py"
|
||||
addIncPath = "%s/include" % DefaultHomebrewRoot # -- ditto --
|
||||
addLibPath = "%s/lib" % DefaultHomebrewRoot # -- ditto --
|
||||
elif PymodDistDir[ModulePython] == 'dist-ana3':
|
||||
addBinPath = "/Applications/anaconda3/bin"
|
||||
addIncPath = "/Applications/anaconda3/include"
|
||||
addLibPath = "/Applications/anaconda3/lib"
|
||||
else:
|
||||
addBinPath = ""
|
||||
addIncPath = ""
|
||||
addLibPath = ""
|
||||
|
||||
if not addBinPath == "":
|
||||
try:
|
||||
bpath = os.environ['PATH']
|
||||
except KeyError:
|
||||
os.environ['PATH'] = addBinPath
|
||||
else:
|
||||
os.environ['PATH'] = "%s:%s" % (addBinPath, bpath)
|
||||
|
||||
if not addIncPath == "":
|
||||
try:
|
||||
cpath = os.environ['CPATH']
|
||||
|
|
@ -937,10 +949,11 @@ def Build_pymod(parameters):
|
|||
#--------------------------------------------------------------------
|
||||
# [3] Set different command line parameters for building <pymod>
|
||||
#--------------------------------------------------------------------
|
||||
cmd1_args = " setup.py build \\\n"
|
||||
cmd2_args = " setup.py bdist_wheel \\\n"
|
||||
cmd3_args = " setup.py bdist_egg \\\n"
|
||||
cmd4_args = " setup.py clean --all \\\n"
|
||||
cmd1_args = " -m setup build \\\n"
|
||||
cmd2_args = " -m setup bdist_wheel \\\n"
|
||||
deloc_cmd = " delocate-wheel --ignore-missing-dependencies"
|
||||
cmd3_args = " <wheel file> \\\n"
|
||||
cmd4_args = " -m setup clean --all \\\n"
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# [4] Make the consolidated command lines
|
||||
|
|
@ -958,7 +971,7 @@ def Build_pymod(parameters):
|
|||
command2 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
||||
|
||||
command3 = "time"
|
||||
command3 += " \\\n %s \\\n" % parameters['python']
|
||||
command3 += " \\\n %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
|
||||
|
|
@ -986,6 +999,7 @@ def Build_pymod(parameters):
|
|||
print( "<Stage-4>")
|
||||
print( " ", command4 )
|
||||
print( "" )
|
||||
|
||||
if parameters['check_cmd_only']:
|
||||
return 0
|
||||
|
||||
|
|
@ -1011,11 +1025,26 @@ def Build_pymod(parameters):
|
|||
print( "", file=sys.stderr )
|
||||
return 1
|
||||
|
||||
ret = subprocess.call( command3, shell=True )
|
||||
#---------------------------------------------------------------------------------------------------------
|
||||
# Copy and relink library dependencies for wheel.
|
||||
# In this step, the "delocate-wheel" command using the desired Python must be found in the PATH.
|
||||
# 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.28.6-cp39-cp39-macosx_12_0_x86_64.whl']
|
||||
if len(cmd3_args) == 1:
|
||||
command3 = "time"
|
||||
command3 += " \\\n %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
|
||||
ret = subprocess.call( command3, shell=True )
|
||||
else:
|
||||
ret = 1
|
||||
if ret != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to build <pymod-egg>" % myscript, file=sys.stderr )
|
||||
print( "!!! <%s>: failed to <delocate-wheel>" % myscript, file=sys.stderr )
|
||||
print( "-------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
return 1
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ Ruby31MacPorts = { 'exe': '/opt/local/bin/ruby3.1',
|
|||
# install with 'sudo port install ruby32'
|
||||
# [Key Type Name] = 'MP32'
|
||||
Ruby32MacPorts = { 'exe': '/opt/local/bin/ruby3.2',
|
||||
'inc': '/opt/local/include/ruby-3.2.0',
|
||||
'inc': '/opt/local/include/ruby-3.2.1',
|
||||
'lib': '/opt/local/lib/libruby.3.2.dylib'
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ public:
|
|||
virtual void finish (bool);
|
||||
|
||||
void keep_for_healing (const db::Polygon &poly);
|
||||
void keep_for_healing (const db::Box &box);
|
||||
|
||||
private:
|
||||
size_t *mp_count;
|
||||
|
|
@ -78,6 +79,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void operator() (const db::Box &box)
|
||||
{
|
||||
if (m_healing && ! box.inside (mp_tile->enlarged (db::Vector (-1, -1)))) {
|
||||
mp_receiver->keep_for_healing (box);
|
||||
} else {
|
||||
m_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t count () const
|
||||
{
|
||||
return m_count;
|
||||
|
|
@ -110,6 +120,12 @@ HealingCountingReceiver::keep_for_healing (const db::Polygon &poly)
|
|||
m_for_healing.insert (poly);
|
||||
}
|
||||
|
||||
void
|
||||
HealingCountingReceiver::keep_for_healing (const db::Box &box)
|
||||
{
|
||||
m_for_healing.insert (box);
|
||||
}
|
||||
|
||||
void
|
||||
HealingCountingReceiver::finish (bool)
|
||||
{
|
||||
|
|
@ -132,7 +148,9 @@ public:
|
|||
void finish (bool /*success*/);
|
||||
|
||||
void keep_for_healing (const db::Polygon &poly);
|
||||
void keep_for_healing (const db::Box &box);
|
||||
void output (const db::Polygon &poly);
|
||||
void output (const db::Box &poly);
|
||||
|
||||
private:
|
||||
db::Layout *mp_layout;
|
||||
|
|
@ -167,6 +185,23 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void operator() (const db::Box &box)
|
||||
{
|
||||
if (m_healing && ! box.inside (mp_tile->enlarged (db::Vector (-1, -1)))) {
|
||||
if (mp_trans->is_complex ()) {
|
||||
mp_receiver->keep_for_healing (*mp_trans * db::Polygon (box));
|
||||
} else {
|
||||
mp_receiver->keep_for_healing (*mp_trans * box);
|
||||
}
|
||||
} else {
|
||||
if (mp_trans->is_complex ()) {
|
||||
mp_receiver->output (*mp_trans * db::Polygon (box));
|
||||
} else {
|
||||
mp_receiver->output (*mp_trans * box);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const db::Box *mp_tile;
|
||||
bool m_healing;
|
||||
|
|
@ -211,12 +246,24 @@ HealingTileLayoutOutputReceiver::keep_for_healing (const db::Polygon &poly)
|
|||
m_for_healing.insert (poly);
|
||||
}
|
||||
|
||||
void
|
||||
HealingTileLayoutOutputReceiver::keep_for_healing (const db::Box &box)
|
||||
{
|
||||
m_for_healing.insert (box);
|
||||
}
|
||||
|
||||
void
|
||||
HealingTileLayoutOutputReceiver::output (const db::Polygon &poly)
|
||||
{
|
||||
mp_cell->shapes (m_layer).insert (poly);
|
||||
}
|
||||
|
||||
void
|
||||
HealingTileLayoutOutputReceiver::output (const db::Box &box)
|
||||
{
|
||||
mp_cell->shapes (m_layer).insert (box);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
struct ResultDescriptor
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ TEST(1A_Flat)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
"Result summary (layers without differences are not shown):\n"
|
||||
|
|
@ -141,7 +141,7 @@ TEST(1A_Deep)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
"Result summary (layers without differences are not shown):\n"
|
||||
|
|
@ -321,7 +321,7 @@ TEST(2_Flat)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
""
|
||||
);
|
||||
|
|
@ -354,7 +354,7 @@ TEST(2_Deep)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
""
|
||||
);
|
||||
|
|
@ -387,7 +387,7 @@ TEST(3_Flat)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -453,7 +453,7 @@ TEST(3_FlatHeal)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -520,7 +520,7 @@ TEST(3_Deep)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -553,7 +553,7 @@ TEST(4_Flat)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -586,7 +586,7 @@ TEST(4_FlatHeal)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -619,7 +619,7 @@ TEST(4_Deep)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -652,7 +652,7 @@ TEST(5_Flat)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -685,7 +685,7 @@ TEST(5_Deep)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -718,7 +718,7 @@ TEST(6_Flat)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -751,7 +751,7 @@ TEST(6_Deep)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1146,14 +1146,14 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
|
|||
check.set_min_projection (options.min_projection);
|
||||
check.set_max_projection (options.max_projection);
|
||||
|
||||
std::vector<generic_shape_iterator<db::Polygon> > others;
|
||||
std::vector<db::RegionIterator> others;
|
||||
std::vector<bool> foreign;
|
||||
bool has_other = false;
|
||||
bool other_is_merged = true;
|
||||
|
||||
if (other == subject_regionptr () || other == foreign_regionptr ()) {
|
||||
foreign.push_back (other == foreign_regionptr ());
|
||||
others.push_back (begin_merged ());
|
||||
others.push_back (polygons);
|
||||
other_is_merged = primary_is_merged;
|
||||
} else {
|
||||
foreign.push_back (false);
|
||||
|
|
|
|||
|
|
@ -376,15 +376,12 @@ private:
|
|||
|
||||
while (cc != current) {
|
||||
rec.finish (cc->first, cc->second);
|
||||
typename std::set<std::pair<const Obj *, const Obj *> >::iterator s;
|
||||
s = seen.lower_bound (std::make_pair (cc->first, (const Obj *)0));
|
||||
auto s = seen.lower_bound (std::make_pair (cc->first, (const Obj *)0));
|
||||
auto s0 = s;
|
||||
while (s != seen.end () && s->first == cc->first) {
|
||||
seen.erase (s++);
|
||||
}
|
||||
s = seen.lower_bound (std::make_pair ((const Obj *)0, cc->first));
|
||||
while (s != seen.end () && s->second == cc->first) {
|
||||
seen.erase (s++);
|
||||
++s;
|
||||
}
|
||||
seen.erase (s0, s);
|
||||
++cc;
|
||||
}
|
||||
|
||||
|
|
@ -429,8 +426,8 @@ private:
|
|||
for (iterator_type i = f0; i != f; ++i) {
|
||||
for (iterator_type j = c; j < i; ++j) {
|
||||
if (bs_boxes_overlap (bc (*i->first), bc (*j->first), enl)) {
|
||||
if (seen.insert (std::make_pair (i->first, j->first)).second) {
|
||||
seen.insert (std::make_pair (j->first, i->first));
|
||||
if (seen.find (std::make_pair (i->first, j->first)) == seen.end () && seen.find (std::make_pair (j->first, i->first)) == seen.end ()) {
|
||||
seen.insert (std::make_pair (i->first, j->first));
|
||||
rec.add (i->first, i->second, j->first, j->second);
|
||||
if (rec.stop ()) {
|
||||
return false;
|
||||
|
|
@ -791,21 +788,23 @@ private:
|
|||
|
||||
while (cc1 != current1) {
|
||||
rec.finish1 (cc1->first, cc1->second);
|
||||
typename std::set<std::pair<const Obj1 *, const Obj2 *> >::iterator s;
|
||||
s = seen1.lower_bound (std::make_pair (cc1->first, (const Obj2 *)0));
|
||||
auto s = seen1.lower_bound (std::make_pair (cc1->first, (const Obj2 *)0));
|
||||
auto s0 = s;
|
||||
while (s != seen1.end () && s->first == cc1->first) {
|
||||
seen1.erase (s++);
|
||||
++s;
|
||||
}
|
||||
seen1.erase (s0, s);
|
||||
++cc1;
|
||||
}
|
||||
|
||||
while (cc2 != current2) {
|
||||
rec.finish2 (cc2->first, cc2->second);
|
||||
typename std::set<std::pair<const Obj2 *, const Obj1 *> >::iterator s;
|
||||
s = seen2.lower_bound (std::make_pair (cc2->first, (const Obj1 *)0));
|
||||
auto s = seen2.lower_bound (std::make_pair (cc2->first, (const Obj1 *)0));
|
||||
auto s0 = s;
|
||||
while (s != seen2.end () && s->first == cc2->first) {
|
||||
seen2.erase (s++);
|
||||
++s;
|
||||
}
|
||||
seen2.erase (s0, s);
|
||||
++cc2;
|
||||
}
|
||||
|
||||
|
|
@ -883,7 +882,7 @@ private:
|
|||
x = xx;
|
||||
|
||||
if (m_report_progress) {
|
||||
progress->set (std::min (f1 - m_pp1.begin (), f2 - m_pp2.begin ()));
|
||||
progress->set ((f1 - m_pp1.begin ()) + (f2 - m_pp2.begin ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -867,7 +867,9 @@ void DeepShapeStore::remove_ref (unsigned int layout, unsigned int layer)
|
|||
unsigned int
|
||||
DeepShapeStore::layout_for_iter (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
layout_map_type::iterator l = m_layout_map.find (std::make_pair (si, trans));
|
||||
size_t gen_id = si.layout () ? si.layout ()->hier_generation_id () : 0;
|
||||
|
||||
layout_map_type::iterator l = m_layout_map.find (std::make_pair (si, std::make_pair (gen_id, trans)));
|
||||
if (l == m_layout_map.end () || m_layouts[l->second] == 0) {
|
||||
|
||||
unsigned int layout_index;
|
||||
|
|
@ -886,7 +888,7 @@ DeepShapeStore::layout_for_iter (const db::RecursiveShapeIterator &si, const db:
|
|||
layout.dbu (si.layout ()->dbu () / trans.mag ());
|
||||
}
|
||||
|
||||
m_layout_map[std::make_pair (si, trans)] = layout_index;
|
||||
m_layout_map[std::make_pair (si, std::make_pair (gen_id, trans))] = layout_index;
|
||||
return layout_index;
|
||||
|
||||
} else {
|
||||
|
|
@ -896,7 +898,8 @@ DeepShapeStore::layout_for_iter (const db::RecursiveShapeIterator &si, const db:
|
|||
|
||||
void DeepShapeStore::make_layout (unsigned int layout_index, const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
tl_assert (m_layout_map.find (std::make_pair (si, trans)) == m_layout_map.end ());
|
||||
size_t gen_id = si.layout () ? si.layout ()->hier_generation_id () : 0;
|
||||
tl_assert (m_layout_map.find (std::make_pair (si, std::make_pair (gen_id, trans))) == m_layout_map.end ());
|
||||
|
||||
while (m_layouts.size () <= layout_index) {
|
||||
m_layouts.push_back (0);
|
||||
|
|
@ -909,7 +912,7 @@ void DeepShapeStore::make_layout (unsigned int layout_index, const db::Recursive
|
|||
layout.dbu (si.layout ()->dbu () / trans.mag ());
|
||||
}
|
||||
|
||||
m_layout_map[std::make_pair (si, trans)] = layout_index;
|
||||
m_layout_map[std::make_pair (si, std::make_pair (gen_id, trans))] = layout_index;
|
||||
}
|
||||
|
||||
DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count, const db::ICplxTrans &trans)
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ private:
|
|||
|
||||
struct DB_PUBLIC RecursiveShapeIteratorCompareForTargetHierarchy
|
||||
{
|
||||
bool operator () (const std::pair<db::RecursiveShapeIterator, db::ICplxTrans> &a, const std::pair<db::RecursiveShapeIterator, db::ICplxTrans> &b) const
|
||||
bool operator () (const std::pair<db::RecursiveShapeIterator, std::pair<size_t, db::ICplxTrans> > &a, const std::pair<db::RecursiveShapeIterator, std::pair<size_t, db::ICplxTrans> > &b) const
|
||||
{
|
||||
int cmp_iter = db::compare_iterators_with_respect_to_target_hierarchy (a.first, b.first);
|
||||
if (cmp_iter != 0) {
|
||||
|
|
@ -865,7 +865,7 @@ private:
|
|||
|
||||
void issue_variants (unsigned int layout, const std::map<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> > &var_map);
|
||||
|
||||
typedef std::map<std::pair<db::RecursiveShapeIterator, db::ICplxTrans>, unsigned int, RecursiveShapeIteratorCompareForTargetHierarchy> layout_map_type;
|
||||
typedef std::map<std::pair<db::RecursiveShapeIterator, std::pair<size_t, db::ICplxTrans> >, unsigned int, RecursiveShapeIteratorCompareForTargetHierarchy> layout_map_type;
|
||||
|
||||
// no copying
|
||||
DeepShapeStore (const DeepShapeStore &);
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ public:
|
|||
* @brief Creates an empty device parameter definition
|
||||
*/
|
||||
DeviceParameterDefinition ()
|
||||
: m_name (), m_description (), m_default_value (0.0), m_id (0), m_is_primary (true), m_si_scaling (1.0)
|
||||
: m_name (), m_description (), m_default_value (0.0), m_id (0), m_is_primary (true), m_si_scaling (1.0), m_geo_scaling (0.0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -154,8 +154,8 @@ public:
|
|||
/**
|
||||
* @brief Creates a device parameter definition with the given name and description
|
||||
*/
|
||||
DeviceParameterDefinition (const std::string &name, const std::string &description, double default_value = 0.0, bool is_primary = true, double si_scaling = 1.0)
|
||||
: m_name (name), m_description (description), m_default_value (default_value), m_id (0), m_is_primary (is_primary), m_si_scaling (si_scaling)
|
||||
DeviceParameterDefinition (const std::string &name, const std::string &description, double default_value = 0.0, bool is_primary = true, double si_scaling = 1.0, double geo_scaling = 0.0)
|
||||
: m_name (name), m_description (description), m_default_value (default_value), m_id (0), m_is_primary (is_primary), m_si_scaling (si_scaling), m_geo_scaling (geo_scaling)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -192,18 +192,10 @@ public:
|
|||
m_description = d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the parameter default value
|
||||
*/
|
||||
double default_value () const
|
||||
{
|
||||
return m_default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the SI unit scaling factor
|
||||
*
|
||||
* Some parameters are given in micrometers for example. This
|
||||
* Some parameters are given in micrometers - for example W and L of MOS devices. This
|
||||
* scaling factor gives the translation to SI units (1e-6 for micrometers).
|
||||
*/
|
||||
double si_scaling () const
|
||||
|
|
@ -212,7 +204,43 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the parameter description
|
||||
* @brief Set the SI unit scaling factor
|
||||
*/
|
||||
void set_si_scaling (double s)
|
||||
{
|
||||
m_si_scaling = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the geometry scaling exponent
|
||||
*
|
||||
* The geometry scaling exponent is used for example when applying .option scale
|
||||
* in Spice reading. It is 0 for "no scaling", 1 for linear scaling and 2 for
|
||||
* quadratic scaling.
|
||||
*/
|
||||
double geo_scaling_exponent () const
|
||||
{
|
||||
return m_geo_scaling;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the geometry scaling exponent
|
||||
*/
|
||||
void set_geo_scaling_exponent (double e)
|
||||
{
|
||||
m_geo_scaling = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the parameter default value
|
||||
*/
|
||||
double default_value () const
|
||||
{
|
||||
return m_default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the parameter default value
|
||||
*/
|
||||
void set_default_value (double d)
|
||||
{
|
||||
|
|
@ -267,6 +295,7 @@ private:
|
|||
size_t m_id;
|
||||
bool m_is_primary;
|
||||
double m_si_scaling;
|
||||
double m_geo_scaling;
|
||||
|
||||
void set_id (size_t id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -487,10 +487,10 @@ DeviceClassResistor::DeviceClassResistor ()
|
|||
equivalent_terminal_id (terminal_id_A, terminal_id_B);
|
||||
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("R", "Resistance (Ohm)", 0.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("L", "Length (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("W", "Width (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("L", "Length (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("W", "Width (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
|
@ -526,8 +526,8 @@ DeviceClassCapacitor::DeviceClassCapacitor ()
|
|||
equivalent_terminal_id (terminal_id_A, terminal_id_B);
|
||||
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("C", "Capacitance (Farad)", 0.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
|
@ -580,8 +580,8 @@ DeviceClassDiode::DeviceClassDiode ()
|
|||
add_terminal_definition (db::DeviceTerminalDefinition ("A", "Anode"));
|
||||
add_terminal_definition (db::DeviceTerminalDefinition ("C", "Cathode"));
|
||||
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
|
@ -608,12 +608,12 @@ DeviceClassMOS3Transistor::DeviceClassMOS3Transistor ()
|
|||
add_terminal_definition (db::DeviceTerminalDefinition ("D", "Drain"));
|
||||
equivalent_terminal_id (terminal_id_D, terminal_id_S);
|
||||
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("L", "Gate length (micrometer)", 0.0, true, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("W", "Gate width (micrometer)", 0.0, true, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AS", "Source area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AD", "Drain area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PS", "Source perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PD", "Drain perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("L", "Gate length (micrometer)", 0.0, true, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("W", "Gate width (micrometer)", 0.0, true, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AS", "Source area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AD", "Drain area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PS", "Source perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PD", "Drain perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -886,12 +886,12 @@ DeviceClassBJT3Transistor::DeviceClassBJT3Transistor ()
|
|||
add_terminal_definition (db::DeviceTerminalDefinition ("E", "Emitter"));
|
||||
|
||||
// NOTE: the emitter area and the emitter count are the primary parameters
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AE", "Emitter area (square micrometer)", 0.0, true, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PE", "Emitter perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AB", "Base area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PB", "Base perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AC", "Collector area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PC", "Collector perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AE", "Emitter area (square micrometer)", 0.0, true, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PE", "Emitter perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AB", "Base area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PB", "Base perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AC", "Collector area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PC", "Collector perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("NE", "Emitter count", 1.0, true));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -399,6 +399,7 @@ private:
|
|||
void read_subcircuit (const std::string &sc_name, const std::string &nc_name, const std::vector<db::Net *> &nets);
|
||||
void read_circuit (tl::Extractor &ex, const std::string &name);
|
||||
bool read_card ();
|
||||
void read_options (tl::Extractor &ex);
|
||||
void ensure_circuit ();
|
||||
std::string get_line ();
|
||||
void error (const std::string &msg);
|
||||
|
|
@ -625,6 +626,10 @@ SpiceCircuitDict::read_card ()
|
|||
std::string nc = read_name (ex, mp_netlist);
|
||||
read_circuit (ex, nc);
|
||||
|
||||
} else if (ex.test_without_case (".options")) {
|
||||
|
||||
read_options (ex);
|
||||
|
||||
} else if (ex.test_without_case (".ends")) {
|
||||
|
||||
return true;
|
||||
|
|
@ -691,6 +696,56 @@ SpiceCircuitDict::read_card ()
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
SpiceCircuitDict::read_options (tl::Extractor &ex)
|
||||
{
|
||||
while (! ex.at_end ()) {
|
||||
|
||||
std::string n;
|
||||
ex.read_word_or_quoted (n, allowed_name_chars);
|
||||
n = tl::to_lower_case (n);
|
||||
|
||||
double v = 0.0;
|
||||
std::string w;
|
||||
if (ex.test ("=")) {
|
||||
if (ex.try_read (v)) {
|
||||
// take value
|
||||
} else {
|
||||
// skip until end or next space
|
||||
ex.skip ();
|
||||
while (! ex.at_end () && ! isspace (*ex)) {
|
||||
++ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: further options?
|
||||
const double min_value = 1e-18;
|
||||
if (n == "scale") {
|
||||
if (v > min_value) {
|
||||
mp_delegate->options ().scale = v;
|
||||
}
|
||||
} else if (n == "defad") {
|
||||
if (v > min_value) {
|
||||
mp_delegate->options ().defad = v;
|
||||
}
|
||||
} else if (n == "defas") {
|
||||
if (v > min_value) {
|
||||
mp_delegate->options ().defas = v;
|
||||
}
|
||||
} else if (n == "defl") {
|
||||
if (v > min_value) {
|
||||
mp_delegate->options ().defl = v;
|
||||
}
|
||||
} else if (n == "defw") {
|
||||
if (v > min_value) {
|
||||
mp_delegate->options ().defw = v;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SpiceCircuitDict::ensure_circuit ()
|
||||
{
|
||||
|
|
@ -1162,9 +1217,9 @@ SpiceNetlistBuilder::build_global_nets ()
|
|||
NetlistSpiceReader::NetlistSpiceReader (NetlistSpiceReaderDelegate *delegate)
|
||||
: mp_delegate (delegate), m_strict (false)
|
||||
{
|
||||
static NetlistSpiceReaderDelegate std_delegate;
|
||||
if (! delegate) {
|
||||
mp_delegate.reset (&std_delegate);
|
||||
mp_default_delegate.reset (new NetlistSpiceReaderDelegate ());
|
||||
mp_delegate.reset (mp_default_delegate.get ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -64,6 +65,7 @@ public:
|
|||
|
||||
private:
|
||||
tl::weak_ptr<NetlistSpiceReaderDelegate> mp_delegate;
|
||||
std::unique_ptr<NetlistSpiceReaderDelegate> mp_default_delegate;
|
||||
bool m_strict;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -86,8 +86,20 @@ static std::string unescape_name (const std::string &n)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
NetlistSpiceReaderOptions::NetlistSpiceReaderOptions ()
|
||||
{
|
||||
scale = 1.0;
|
||||
defad = 0.0;
|
||||
defas = 0.0;
|
||||
// ngspice defaults:
|
||||
defw = 100e-6;
|
||||
defl = 100e-6;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
NetlistSpiceReaderDelegate::NetlistSpiceReaderDelegate ()
|
||||
: mp_netlist (0)
|
||||
: mp_netlist (0), m_options ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -97,6 +109,22 @@ NetlistSpiceReaderDelegate::~NetlistSpiceReaderDelegate ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void NetlistSpiceReaderDelegate::set_netlist (db::Netlist *netlist)
|
||||
{
|
||||
m_options = NetlistSpiceReaderOptions ();
|
||||
mp_netlist = netlist;
|
||||
}
|
||||
|
||||
void NetlistSpiceReaderDelegate::do_start ()
|
||||
{
|
||||
start (mp_netlist);
|
||||
}
|
||||
|
||||
void NetlistSpiceReaderDelegate::do_finish ()
|
||||
{
|
||||
finish (mp_netlist);
|
||||
}
|
||||
|
||||
void NetlistSpiceReaderDelegate::start (db::Netlist * /*netlist*/)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
@ -107,7 +135,7 @@ void NetlistSpiceReaderDelegate::finish (db::Netlist * /*netlist*/)
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool NetlistSpiceReaderDelegate::control_statement(const std::string & /*line*/)
|
||||
bool NetlistSpiceReaderDelegate::control_statement (const std::string & /*line*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -196,7 +224,8 @@ void NetlistSpiceReaderDelegate::parse_element_components (const std::string &s,
|
|||
if (ex.try_read_word (n) && ex.test ("=")) {
|
||||
|
||||
// a parameter
|
||||
pv [mp_netlist ? mp_netlist->normalize_name (n) : tl::to_upper_case (n)] = read_value (ex, variables);
|
||||
std::string pn = mp_netlist ? mp_netlist->normalize_name (n) : tl::to_upper_case (n);
|
||||
pv [pn] = read_value (ex, variables);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -231,8 +260,21 @@ void NetlistSpiceReaderDelegate::parse_element_components (const std::string &s,
|
|||
}
|
||||
}
|
||||
|
||||
void NetlistSpiceReaderDelegate::def_values_per_element (const std::string &element, std::map<std::string, tl::Variant> &pv)
|
||||
{
|
||||
if (element == "M") {
|
||||
|
||||
pv.insert (std::make_pair ("W", m_options.defw));
|
||||
pv.insert (std::make_pair ("L", m_options.defl));
|
||||
pv.insert (std::make_pair ("AD", m_options.defad));
|
||||
pv.insert (std::make_pair ("AS", m_options.defas));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void NetlistSpiceReaderDelegate::parse_element (const std::string &s, const std::string &element, std::string &model, double &value, std::vector<std::string> &nn, std::map<std::string, tl::Variant> &pv, const std::map<std::string, tl::Variant> &variables)
|
||||
{
|
||||
def_values_per_element (element, pv);
|
||||
parse_element_components (s, nn, pv, variables);
|
||||
|
||||
// interpret the parameters according to the code
|
||||
|
|
@ -337,6 +379,8 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
std::map<std::string, tl::Variant> params = pv;
|
||||
std::vector<size_t> terminal_order;
|
||||
|
||||
size_t defp = std::numeric_limits<size_t>::max ();
|
||||
|
||||
double mult = 1.0;
|
||||
auto mp = params.find ("M");
|
||||
if (mp != params.end ()) {
|
||||
|
|
@ -378,9 +422,20 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
error (tl::to_string (tr ("A 'R' element requires two or three nets")));
|
||||
}
|
||||
|
||||
// Apply multiplier
|
||||
// Apply multiplier (divider, according to ngspice manual)
|
||||
value /= mult;
|
||||
|
||||
defp = db::DeviceClassResistor::param_id_R;
|
||||
|
||||
// Apply multiplier to other parameters
|
||||
static const char *scale_params[] = { "A", "P", "W" };
|
||||
for (size_t i = 0; i < sizeof (scale_params) / sizeof (scale_params[0]); ++i) {
|
||||
auto p = params.find (scale_params [i]);
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (element == "L") {
|
||||
|
||||
if (nets.size () == 2) {
|
||||
|
|
@ -398,9 +453,11 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
error (tl::to_string (tr ("A 'L' element requires two nets")));
|
||||
}
|
||||
|
||||
// Apply multiplier
|
||||
// Apply multiplier (divider, according to ngspice manual)
|
||||
value /= mult;
|
||||
|
||||
defp = db::DeviceClassInductor::param_id_L;
|
||||
|
||||
} else if (element == "C") {
|
||||
|
||||
if (nets.size () == 2) {
|
||||
|
|
@ -432,6 +489,17 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
// Apply multiplier
|
||||
value *= mult;
|
||||
|
||||
defp = db::DeviceClassCapacitor::param_id_C;
|
||||
|
||||
// Apply multiplier to other parameters
|
||||
static const char *scale_params[] = { "A", "P" };
|
||||
for (size_t i = 0; i < sizeof (scale_params) / sizeof (scale_params[0]); ++i) {
|
||||
auto p = params.find (scale_params [i]);
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (element == "D") {
|
||||
|
||||
if (cls) {
|
||||
|
|
@ -445,10 +513,13 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
cls = make_device_class<db::DeviceClassDiode> (circuit, cn);
|
||||
}
|
||||
|
||||
// Apply multiplier to "A"
|
||||
auto p = params.find ("A");
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
// Apply multiplier
|
||||
static const char *scale_params[] = { "A", "P" };
|
||||
for (size_t i = 0; i < sizeof (scale_params) / sizeof (scale_params[0]); ++i) {
|
||||
auto p = params.find (scale_params [i]);
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (element == "Q") {
|
||||
|
|
@ -479,10 +550,13 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
}
|
||||
}
|
||||
|
||||
// Apply multiplier to "AE"
|
||||
auto p = params.find ("AE");
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
// Apply multiplier
|
||||
static const char *scale_params[] = { "AE", "PE", "AB", "PB", "AC", "PC" };
|
||||
for (size_t i = 0; i < sizeof (scale_params) / sizeof (scale_params[0]); ++i) {
|
||||
auto p = params.find (scale_params [i]);
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (element == "M") {
|
||||
|
|
@ -502,10 +576,13 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
}
|
||||
}
|
||||
|
||||
// Apply multiplier to "W"
|
||||
auto p = params.find ("W");
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
// Apply multiplier
|
||||
static const char *scale_params[] = { "W", "AD", "AS", "PD", "PS" };
|
||||
for (size_t i = 0; i < sizeof (scale_params) / sizeof (scale_params[0]); ++i) {
|
||||
auto p = params.find (scale_params [i]);
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
}
|
||||
}
|
||||
|
||||
// issue #1304
|
||||
|
|
@ -537,28 +614,38 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
}
|
||||
|
||||
|
||||
size_t defp = std::numeric_limits<size_t>::max ();
|
||||
if (dynamic_cast<db::DeviceClassCapacitor *> (cls)) {
|
||||
defp = db::DeviceClassCapacitor::param_id_C;
|
||||
} else if (dynamic_cast<db::DeviceClassResistor *> (cls)) {
|
||||
defp = db::DeviceClassResistor::param_id_R;
|
||||
} else if (dynamic_cast<db::DeviceClassInductor *> (cls)) {
|
||||
defp = db::DeviceClassInductor::param_id_L;
|
||||
}
|
||||
|
||||
std::vector<db::DeviceParameterDefinition> &pd = cls->parameter_definitions_non_const ();
|
||||
for (std::vector<db::DeviceParameterDefinition>::iterator i = pd.begin (); i != pd.end (); ++i) {
|
||||
auto v = params.find (i->name ());
|
||||
double pv = 0.0;
|
||||
if (v != params.end ()) {
|
||||
device->set_parameter_value (i->id (), v->second.to_double () / i->si_scaling ());
|
||||
pv = v->second.to_double ();
|
||||
} else if (i->id () == defp) {
|
||||
device->set_parameter_value (i->id (), value / i->si_scaling ());
|
||||
pv = value;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
device->set_parameter_value (i->id (), pv);
|
||||
}
|
||||
|
||||
apply_parameter_scaling (device);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
NetlistSpiceReaderDelegate::apply_parameter_scaling (db::Device *device) const
|
||||
{
|
||||
if (! device || ! device->device_class ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::vector<db::DeviceParameterDefinition> &pd = device->device_class ()->parameter_definitions ();
|
||||
for (auto i = pd.begin (); i != pd.end (); ++i) {
|
||||
double pv = device->parameter_value (i->id ());
|
||||
device->set_parameter_value (i->id (), pv / i->si_scaling () * pow (m_options.scale, i->geo_scaling_exponent ()));
|
||||
}
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
NetlistSpiceReaderDelegate::read_value (tl::Extractor &ex, const std::map<std::string, tl::Variant> &variables)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,6 +40,14 @@ class Circuit;
|
|||
class DeviceClass;
|
||||
class Device;
|
||||
|
||||
struct DB_PUBLIC NetlistSpiceReaderOptions
|
||||
{
|
||||
NetlistSpiceReaderOptions ();
|
||||
|
||||
double scale;
|
||||
double defad, defas, defw, defl;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A delegate to handle various forms of devices and translates them
|
||||
*
|
||||
|
|
@ -55,6 +63,22 @@ public:
|
|||
NetlistSpiceReaderDelegate ();
|
||||
virtual ~NetlistSpiceReaderDelegate ();
|
||||
|
||||
/**
|
||||
* @brief Gets the reader options
|
||||
*/
|
||||
const NetlistSpiceReaderOptions &options () const
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the reader options (non-const)
|
||||
*/
|
||||
NetlistSpiceReaderOptions &options ()
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when the netlist reading starts
|
||||
*/
|
||||
|
|
@ -122,7 +146,6 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Reads a set of string components and parameters from the string
|
||||
* A special key "param:" is recognized for starting a parameter list.
|
||||
*/
|
||||
void parse_element_components (const std::string &s, std::vector<std::string> &strings, std::map<std::string, tl::Variant> &pv, const std::map<std::string, tl::Variant> &variables);
|
||||
|
||||
|
|
@ -139,29 +162,28 @@ public:
|
|||
/**
|
||||
* @brief External interface for start
|
||||
*/
|
||||
void do_start ()
|
||||
{
|
||||
start (mp_netlist);
|
||||
}
|
||||
void do_start ();
|
||||
|
||||
/**
|
||||
* @brief External interface for finish
|
||||
*/
|
||||
void do_finish ()
|
||||
{
|
||||
finish (mp_netlist);
|
||||
}
|
||||
void do_finish ();
|
||||
|
||||
/**
|
||||
* @brief Sets the netlist
|
||||
*/
|
||||
void set_netlist (db::Netlist *netlist)
|
||||
{
|
||||
mp_netlist = netlist;
|
||||
}
|
||||
void set_netlist (db::Netlist *netlist);
|
||||
|
||||
/**
|
||||
* @brief Applies SI and geometry scaling to the device parameters
|
||||
*/
|
||||
void apply_parameter_scaling (db::Device *device) const;
|
||||
|
||||
private:
|
||||
db::Netlist *mp_netlist;
|
||||
NetlistSpiceReaderOptions m_options;
|
||||
|
||||
void def_values_per_element (const std::string &element, std::map<std::string, tl::Variant> &pv);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ static bool to_bool (const tl::Variant &v)
|
|||
}
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
NetlistSpiceReaderExpressionParser::NetlistSpiceReaderExpressionParser (const variables_type *vars)
|
||||
NetlistSpiceReaderExpressionParser::NetlistSpiceReaderExpressionParser (const variables_type *vars, double def_scale)
|
||||
: m_def_scale (def_scale)
|
||||
{
|
||||
static variables_type empty_variables;
|
||||
mp_variables = vars ? vars : &empty_variables;
|
||||
|
|
@ -202,7 +203,7 @@ NetlistSpiceReaderExpressionParser::read_atomic_value (tl::Extractor &ex, bool *
|
|||
*status = true;
|
||||
}
|
||||
|
||||
double f = 1.0;
|
||||
double f = m_def_scale;
|
||||
if (*ex == 't' || *ex == 'T') {
|
||||
f = 1e12;
|
||||
} else if (*ex == 'g' || *ex == 'G') {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class DB_PUBLIC NetlistSpiceReaderExpressionParser
|
|||
public:
|
||||
typedef std::map<std::string, tl::Variant> variables_type;
|
||||
|
||||
NetlistSpiceReaderExpressionParser (const variables_type *vars);
|
||||
NetlistSpiceReaderExpressionParser (const variables_type *vars, double def_scale = 1.0);
|
||||
|
||||
tl::Variant read (tl::Extractor &ex) const;
|
||||
tl::Variant read (const std::string &s) const;
|
||||
|
|
@ -54,6 +54,7 @@ public:
|
|||
|
||||
private:
|
||||
const variables_type *mp_variables;
|
||||
double m_def_scale;
|
||||
|
||||
tl::Variant read_atomic_value (tl::Extractor &ex, bool *status) const;
|
||||
tl::Variant read_dot_expr (tl::Extractor &ex, bool *status) const;
|
||||
|
|
|
|||
|
|
@ -1685,6 +1685,20 @@ AreaMap::bbox () const
|
|||
// -------------------------------------------------------------------------
|
||||
// Implementation of rasterize
|
||||
|
||||
static bool edge_is_partially_left_of (const db::Edge &e, const db::Edge &e_original, db::Coord x)
|
||||
{
|
||||
Coord xmin = db::edge_xmin (e);
|
||||
if (xmin < x) {
|
||||
return true;
|
||||
} else if (xmin == x && e_original.dx () != 0) {
|
||||
// the skew edge is cut partially rendering a straight vertical line (due to rounding)
|
||||
// which we will count as "left of"
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
rasterize (const db::Polygon &polygon, db::AreaMap &am)
|
||||
{
|
||||
|
|
@ -1801,7 +1815,7 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
|
|||
for (std::vector <db::Edge>::iterator e = cc; e != ff; ++e) {
|
||||
|
||||
std::pair<bool, db::Edge> ec = e->clipped (left);
|
||||
if (ec.first && db::edge_xmin (ec.second) < x) {
|
||||
if (ec.first && edge_is_partially_left_of (ec.second, *e, x)) {
|
||||
a += area_type (ec.second.dy ()) * area_type (px);
|
||||
}
|
||||
|
||||
|
|
@ -1818,7 +1832,7 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
|
|||
for (std::vector <db::Edge>::iterator e = cc; e != ff; ++e) {
|
||||
|
||||
std::pair<bool, db::Edge> ec = e->clipped (cell);
|
||||
if (ec.first && db::edge_xmin (ec.second) < xx) {
|
||||
if (ec.first && edge_is_partially_left_of (ec.second, *e, xx)) {
|
||||
aa += (area_type (ec.second.dy ()) * area_type (2 * xx - (ec.second.p2 ().x () + ec.second.p1 ().x ()))) / 2;
|
||||
a += area_type (ec.second.dy ()) * area_type (px);
|
||||
}
|
||||
|
|
@ -1832,7 +1846,7 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
|
|||
for (std::vector <db::Edge>::iterator e = cc; e != ff; ++e) {
|
||||
|
||||
std::pair<bool, db::Edge> ec = e->clipped (cell);
|
||||
if (ec.first && db::edge_xmin (ec.second) < xx) {
|
||||
if (ec.first && edge_is_partially_left_of (ec.second, *e, xx)) {
|
||||
aa += (area_type (ec.second.dy ()) * area_type (2 * xx - (ec.second.p2 ().x () + ec.second.p1 ().x ()))) / 2;
|
||||
}
|
||||
|
||||
|
|
@ -1843,7 +1857,7 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
|
|||
for (std::vector <db::Edge>::iterator e = cc; e != fff; ++e) {
|
||||
|
||||
std::pair<bool, db::Edge> wide_ec = e->clipped (wide_cell);
|
||||
if (wide_ec.first && db::edge_xmin (wide_ec.second) < x + dx) {
|
||||
if (wide_ec.first && edge_is_partially_left_of (wide_ec.second, *e, x + dx)) {
|
||||
a += area_type (wide_ec.second.dy ()) * area_type (px);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,31 @@ public:
|
|||
mp_shapes->insert (t.transformed (m_trans));
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void insert_polygon (const P &p)
|
||||
{
|
||||
if (p.is_box () && ! m_trans.is_complex ()) {
|
||||
mp_shapes->insert (p.box ().transformed (m_trans));
|
||||
} else {
|
||||
if (mp_shapes->cell () && mp_shapes->cell ()->layout ()) {
|
||||
db::polygon_ref<P, db::Disp> pr (p.transformed (m_trans), mp_shapes->cell ()->layout ()->shape_repository ());
|
||||
mp_shapes->insert (pr);
|
||||
} else {
|
||||
mp_shapes->insert (p.transformed (m_trans));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void operator() (const db::Polygon &p)
|
||||
{
|
||||
insert_polygon (p);
|
||||
}
|
||||
|
||||
void operator() (const db::SimplePolygon &p)
|
||||
{
|
||||
insert_polygon (p);
|
||||
}
|
||||
|
||||
void operator() (const db::EdgePair &ep)
|
||||
{
|
||||
mp_shapes->insert (ep.normalized ().to_polygon (m_ep_sizing).transformed (m_trans));
|
||||
|
|
|
|||
|
|
@ -135,6 +135,27 @@ private:
|
|||
TilingProcessor *mp_proc;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Delivery of tiling processor output
|
||||
* This utility is put between the container and the receiver.
|
||||
* The inserter is an object having an operator() that takes the object.
|
||||
* This function is responsible for preparing (i.e. clipping) and delivering the output.
|
||||
*/
|
||||
template <class X>
|
||||
void insert (X &inserter, const db::Box &o, const db::Box &tile, bool clip)
|
||||
{
|
||||
if (clip) {
|
||||
// clipping
|
||||
db::Box oc = o & tile;
|
||||
if (! oc.empty () && oc.width () > 0 && oc.height () > 0) {
|
||||
inserter (oc);
|
||||
}
|
||||
} else {
|
||||
// no clipping
|
||||
inserter (o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delivery of tiling processor output
|
||||
* This utility is put between the container and the receiver.
|
||||
|
|
@ -144,7 +165,10 @@ private:
|
|||
template <class X>
|
||||
void insert (X &inserter, const db::Polygon &o, const db::Box &tile, bool clip)
|
||||
{
|
||||
if (clip && ! o.box ().inside (tile)) {
|
||||
if (o.is_box ()) {
|
||||
// simple case: box
|
||||
insert (inserter, o.box (), tile, clip);
|
||||
} else if (clip && ! o.box ().inside (tile)) {
|
||||
// apply clipping
|
||||
if (o.box ().touches (tile)) {
|
||||
std::vector <db::Polygon> clipped_poly;
|
||||
|
|
@ -168,7 +192,10 @@ void insert (X &inserter, const db::Polygon &o, const db::Box &tile, bool clip)
|
|||
template <class X>
|
||||
void insert (X &inserter, const db::SimplePolygon &o, const db::Box &tile, bool clip)
|
||||
{
|
||||
if (clip && ! o.box ().inside (tile)) {
|
||||
if (o.is_box ()) {
|
||||
// simple case: box
|
||||
insert (inserter, o.box (), tile, clip);
|
||||
} else if (clip && ! o.box ().inside (tile)) {
|
||||
// apply clipping
|
||||
if (o.box ().touches (tile)) {
|
||||
std::vector <db::SimplePolygon> clipped_poly;
|
||||
|
|
@ -242,27 +269,6 @@ void insert (X &inserter, const db::Text &o, const db::Box &tile, bool clip)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delivery of tiling processor output
|
||||
* This utility is put between the container and the receiver.
|
||||
* The inserter is an object having an operator() that takes the object.
|
||||
* This function is responsible for preparing (i.e. clipping) and delivering the output.
|
||||
*/
|
||||
template <class X>
|
||||
void insert (X &inserter, const db::Box &o, const db::Box &tile, bool clip)
|
||||
{
|
||||
if (clip) {
|
||||
// clipping
|
||||
db::Box oc = o & tile;
|
||||
if (! oc.empty ()) {
|
||||
inserter (oc);
|
||||
}
|
||||
} else {
|
||||
// no clipping
|
||||
inserter (o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delivery of tiling processor output
|
||||
* This utility is put between the container and the receiver.
|
||||
|
|
|
|||
|
|
@ -790,19 +790,20 @@ Class<db::DeviceTerminalDefinition> decl_dbDeviceTerminalDefinition ("db", "Devi
|
|||
"This class has been added in version 0.26."
|
||||
);
|
||||
|
||||
static db::DeviceParameterDefinition *new_parameter_definition (const std::string &name, const std::string &description, double default_value, bool is_primary, double si_scaling)
|
||||
static db::DeviceParameterDefinition *new_parameter_definition (const std::string &name, const std::string &description, double default_value, bool is_primary, double si_scaling, double geo_scaling_exponent)
|
||||
{
|
||||
return new db::DeviceParameterDefinition (name, description, default_value, is_primary, si_scaling);
|
||||
return new db::DeviceParameterDefinition (name, description, default_value, is_primary, si_scaling, geo_scaling_exponent);
|
||||
}
|
||||
|
||||
Class<db::DeviceParameterDefinition> decl_dbDeviceParameterDefinition ("db", "DeviceParameterDefinition",
|
||||
gsi::constructor ("new", &gsi::new_parameter_definition, gsi::arg ("name"), gsi::arg ("description", std::string ()), gsi::arg ("default_value", 0.0), gsi::arg ("is_primary", true), gsi::arg ("si_scaling", 1.0),
|
||||
gsi::constructor ("new", &gsi::new_parameter_definition, gsi::arg ("name"), gsi::arg ("description", std::string ()), gsi::arg ("default_value", 0.0), gsi::arg ("is_primary", true), gsi::arg ("si_scaling", 1.0), gsi::arg ("geo_scaling_exponent", 0.0),
|
||||
"@brief Creates a new parameter definition.\n"
|
||||
"@param name The name of the parameter\n"
|
||||
"@param description The human-readable description\n"
|
||||
"@param default_value The initial value\n"
|
||||
"@param is_primary True, if the parameter is a primary parameter (see \\is_primary=)\n"
|
||||
"@param si_scaling The scaling factor to SI units\n"
|
||||
"@param geo_scaling_exponent Indicates how the parameter scales with geometrical scaling (0: no scaling, 1.0: linear, 2.0: quadratic)\n"
|
||||
) +
|
||||
gsi::method ("name", &db::DeviceParameterDefinition::name,
|
||||
"@brief Gets the name of the parameter."
|
||||
|
|
@ -834,7 +835,26 @@ Class<db::DeviceParameterDefinition> decl_dbDeviceParameterDefinition ("db", "De
|
|||
) +
|
||||
gsi::method ("si_scaling", &db::DeviceParameterDefinition::si_scaling,
|
||||
"@brief Gets the scaling factor to SI units.\n"
|
||||
"For parameters in micrometers for example, this factor will be 1e-6."
|
||||
"For parameters in micrometers - for example W and L of MOS devices - this factor can be set to 1e-6 to reflect "
|
||||
"the unit."
|
||||
) +
|
||||
gsi::method ("si_scaling=", &db::DeviceParameterDefinition::set_si_scaling,
|
||||
"@brief Sets the scaling factor to SI units.\n"
|
||||
"\n"
|
||||
"This setter has been added in version 0.28.6."
|
||||
) +
|
||||
gsi::method ("geo_scaling_exponent", &db::DeviceParameterDefinition::geo_scaling_exponent,
|
||||
"@brief Gets the geometry scaling exponent.\n"
|
||||
"This value is used when applying '.options scale' in the SPICE reader for example. "
|
||||
"It is zero for 'no scaling', 1.0 for linear scaling and 2.0 for quadratic scaling.\n"
|
||||
"\n"
|
||||
"This attribute has been added in version 0.28.6."
|
||||
) +
|
||||
gsi::method ("geo_scaling_exponent=", &db::DeviceParameterDefinition::set_geo_scaling_exponent,
|
||||
"@brief Sets the geometry scaling exponent.\n"
|
||||
"See \\geo_scaling_exponent for details.\n"
|
||||
"\n"
|
||||
"This attribute has been added in version 0.28.6."
|
||||
) +
|
||||
gsi::method ("id", &db::DeviceParameterDefinition::id,
|
||||
"@brief Gets the ID of the parameter.\n"
|
||||
|
|
@ -2749,6 +2769,16 @@ Class<ParseElementData> db_ParseElementData ("db", "ParseElementData",
|
|||
"This helper class has been introduced in version 0.27.1. Starting with version 0.28.6, named parameters can be string types too.\n"
|
||||
);
|
||||
|
||||
static double get_delegate_scale (const db::NetlistSpiceReaderDelegate *delegate)
|
||||
{
|
||||
return delegate->options ().scale;
|
||||
}
|
||||
|
||||
static void apply_parameter_scaling (const db::NetlistSpiceReaderDelegate *delegate, db::Device *device)
|
||||
{
|
||||
delegate->apply_parameter_scaling (device);
|
||||
}
|
||||
|
||||
Class<NetlistSpiceReaderDelegateImpl> db_NetlistSpiceReaderDelegate ("db", "NetlistSpiceReaderDelegate",
|
||||
gsi::method_ext ("start", &start_fb, "@hide") +
|
||||
gsi::method_ext ("finish", &finish_fb, "@hide") +
|
||||
|
|
@ -2826,6 +2856,21 @@ Class<NetlistSpiceReaderDelegateImpl> db_NetlistSpiceReaderDelegate ("db", "Netl
|
|||
"@brief Issues an error with the given message.\n"
|
||||
"Use this method to generate an error."
|
||||
) +
|
||||
gsi::method_ext ("get_scale", &get_delegate_scale,
|
||||
"@brief Gets the scale factor set with '.options scale=...'\n"
|
||||
"This method has been introduced in version 0.28.6."
|
||||
) +
|
||||
gsi::method_ext ("apply_parameter_scaling", &apply_parameter_scaling, gsi::arg ("device"),
|
||||
"@brief Applies parameter scaling to the given device\n"
|
||||
"Applies SI scaling (according to the parameter's si_scaling attribute) and "
|
||||
"geometry scaling (according to the parameter's geo_scale_exponent attribute) to "
|
||||
"the device parameters. Use this method of finish the device when you have created "
|
||||
"a custom device yourself.\n"
|
||||
"\n"
|
||||
"The geometry scale is taken from the '.options scale=...' control statement.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.6."
|
||||
) +
|
||||
gsi::method_ext ("value_from_string", &value_from_string, gsi::arg ("s"), gsi::arg ("variables", db::NetlistSpiceReader::parameters_type (), "{}"),
|
||||
"@brief Translates a string into a value\n"
|
||||
"This function simplifies the implementation of SPICE readers by providing a translation of a unit-annotated string "
|
||||
|
|
|
|||
|
|
@ -313,3 +313,35 @@ TEST(4c)
|
|||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testdata () + "/algo/fill_tool_au4c.gds");
|
||||
}
|
||||
|
||||
// issue #1309
|
||||
TEST(5)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/fill_tool5.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 (50, 0);
|
||||
db::Vector cs (0, 50);
|
||||
db::Box fc_box (db::Point (), db::Point (rs.x (), cs.y ()));
|
||||
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_au5.oas", db::WriteOAS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -704,16 +704,50 @@ TEST(18_XSchemOutput)
|
|||
" subcircuit 'PMOS4_STANDARD(L=0.15U,NF=2,W=1.5U)' XDUMMY3 (D=VDD,G=VDD,S=VDD,B=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit 'PMOS4_STANDARD(L=0.15U,NF=4,W=1.5U)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=2.685,PD=1.79);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=1.305,AD=0.87,PS=10.74,PD=7.16);\n"
|
||||
"end;\n"
|
||||
"circuit 'NMOS4_STANDARD(L=0.15U,NF=4,W=1.5U)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=2.685,PD=1.79);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=1.305,AD=0.87,PS=10.74,PD=7.16);\n"
|
||||
"end;\n"
|
||||
"circuit 'NMOS4_STANDARD(L=0.15U,NF=2,W=1.5U)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=3.58,PD=1.79);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.87,AD=0.435,PS=7.16,PD=3.58);\n"
|
||||
"end;\n"
|
||||
"circuit 'PMOS4_STANDARD(L=0.15U,NF=2,W=1.5U)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=3.58,PD=1.79);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.87,AD=0.435,PS=7.16,PD=3.58);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(19_ngspice_ref)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader19.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit .TOP ();\n"
|
||||
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=4,W=1.5)' XPMOS (D=Q,G=I,S=VDD,B=VDD);\n"
|
||||
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=4,W=1.5)' XNMOS (D=Q,G=I,S=VSS,B=VSS);\n"
|
||||
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=2,W=1.5)' XDUMMY0 (D=VSS,G=VSS,S=VSS,B=VSS);\n"
|
||||
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=2,W=1.5)' XDUMMY1 (D=VSS,G=VSS,S=VSS,B=VSS);\n"
|
||||
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=2,W=1.5)' XDUMMY2 (D=VDD,G=VDD,S=VDD,B=VDD);\n"
|
||||
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=2,W=1.5)' XDUMMY3 (D=VDD,G=VDD,S=VDD,B=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit 'PMOS4_STANDARD(L=0.15,NF=4,W=1.5)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=3.99,PD=2.66);\n"
|
||||
"end;\n"
|
||||
"circuit 'NMOS4_STANDARD(L=0.15,NF=4,W=1.5)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=3.99,PD=2.66);\n"
|
||||
"end;\n"
|
||||
"circuit 'NMOS4_STANDARD(L=0.15,NF=2,W=1.5)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=4.16,PD=2.08);\n"
|
||||
"end;\n"
|
||||
"circuit 'PMOS4_STANDARD(L=0.15,NF=2,W=1.5)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=4.16,PD=2.08);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
|
@ -828,3 +862,18 @@ TEST(100_ExpressionParser)
|
|||
EXPECT_EQ (parser.try_read ("\"1+2*(2+1)-1\"", v), true);
|
||||
EXPECT_EQ (v.to_string (), "6");
|
||||
}
|
||||
|
||||
TEST(101_ExpressionParserWithDefScale)
|
||||
{
|
||||
std::map<std::string, tl::Variant> vars;
|
||||
vars["A"] = 17.5;
|
||||
|
||||
tl::Variant v;
|
||||
|
||||
db::NetlistSpiceReaderExpressionParser parser (&vars, 1e-3);
|
||||
|
||||
EXPECT_EQ (parser.read ("1.75").to_string (), "0.00175");
|
||||
EXPECT_EQ (parser.read ("-1.75u").to_string (), "-1.75e-06");
|
||||
EXPECT_EQ (parser.read ("1.75k").to_string (), "1750");
|
||||
EXPECT_EQ (parser.read ("2*A").to_string (), "0.035");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,8 +150,8 @@ TEST(2)
|
|||
tp.queue ("_tile && _output(o3, _tile, false)");
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (ly, top, o1), "polygon (60,10;60,20;70,20;70,10);polygon (10,10;10,30;30,30;30,10)");
|
||||
EXPECT_EQ (to_s (ly, top, o2), "polygon (50,40;50,70;80,70;80,40)");
|
||||
EXPECT_EQ (to_s (ly, top, o1), "box (60,10;70,20);box (10,10;30,30)");
|
||||
EXPECT_EQ (to_s (ly, top, o2), "box (50,40;80,70)");
|
||||
EXPECT_EQ (to_s (ly, top, o3), "");
|
||||
|
||||
ly.clear_layer (o1);
|
||||
|
|
@ -164,9 +164,9 @@ TEST(2)
|
|||
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (ly, top, o1), "polygon (10,10;10,23;20,23;20,10);polygon (10,23;10,30;20,30;20,23);polygon (20,10;20,23;30,23;30,10);polygon (20,23;20,30;30,30;30,23);polygon (60,10;60,20;70,20;70,10)");
|
||||
EXPECT_EQ (to_s (ly, top, o1), "box (10,10;20,23);box (10,23;20,30);box (20,10;30,23);box (20,23;30,30);box (60,10;70,20)");
|
||||
EXPECT_EQ (to_s (ly, top, o2), "");
|
||||
EXPECT_EQ (to_s (ly, top, o3), "polygon (-5,-2;-5,23;20,23;20,-2);polygon (-5,23;-5,48;20,48;20,23);polygon (-5,48;-5,73;20,73;20,48);polygon (20,-2;20,23;45,23;45,-2);polygon (20,23;20,48;45,48;45,23);polygon (20,48;20,73;45,73;45,48);polygon (45,-2;45,23;70,23;70,-2);polygon (45,23;45,48;70,48;70,23);polygon (45,48;45,73;70,73;70,48);polygon (70,-2;70,23;95,23;95,-2);polygon (70,23;70,48;95,48;95,23);polygon (70,48;70,73;95,73;95,48);polygon (95,-2;95,23;120,23;120,-2);polygon (95,23;95,48;120,48;120,23);polygon (95,48;95,73;120,73;120,48);polygon (120,-2;120,23;145,23;145,-2);polygon (120,23;120,48;145,48;145,23);polygon (120,48;120,73;145,73;145,48)");
|
||||
EXPECT_EQ (to_s (ly, top, o3), "box (-5,-2;20,23);box (-5,23;20,48);box (-5,48;20,73);box (20,-2;45,23);box (20,23;45,48);box (20,48;45,73);box (45,-2;70,23);box (45,23;70,48);box (45,48;70,73);box (70,-2;95,23);box (70,23;95,48);box (70,48;95,73);box (95,-2;120,23);box (95,23;120,48);box (95,48;120,73);box (120,-2;145,23);box (120,23;145,48);box (120,48;145,73)");
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -185,8 +185,8 @@ TEST(2)
|
|||
tp.queue ("_output(o3, _tile)");
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (ly, top, o1), "polygon (60,10;60,20;70,20;70,10);polygon (10,10;10,30;30,30;30,10)");
|
||||
EXPECT_EQ (to_s (ly, top, o2), "polygon (50,40;50,70;80,70;80,40)");
|
||||
EXPECT_EQ (to_s (ly, top, o1), "box (60,10;70,20);box (10,10;30,30)");
|
||||
EXPECT_EQ (to_s (ly, top, o2), "box (50,40;80,70)");
|
||||
EXPECT_EQ (to_s (ly, top, o3), "");
|
||||
|
||||
ly.clear_layer (o1);
|
||||
|
|
@ -199,9 +199,9 @@ TEST(2)
|
|||
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (ly, top, o1), "polygon (10,10;10,23;20,23;20,10);polygon (10,23;10,30;20,30;20,23);polygon (20,10;20,23;30,23;30,10);polygon (20,23;20,30;30,30;30,23);polygon (60,10;60,20;70,20;70,10)");
|
||||
EXPECT_EQ (to_s (ly, top, o1), "box (10,10;20,23);box (10,23;20,30);box (20,10;30,23);box (20,23;30,30);box (60,10;70,20)");
|
||||
EXPECT_EQ (to_s (ly, top, o2), "");
|
||||
EXPECT_EQ (to_s (ly, top, o3), "polygon (-5,-2;-5,23;20,23;20,-2);polygon (-5,23;-5,48;20,48;20,23);polygon (-5,48;-5,73;20,73;20,48);polygon (20,-2;20,23;45,23;45,-2);polygon (20,23;20,48;45,48;45,23);polygon (20,48;20,73;45,73;45,48);polygon (45,-2;45,23;70,23;70,-2);polygon (45,23;45,48;70,48;70,23);polygon (45,48;45,73;70,73;70,48);polygon (70,-2;70,23;95,23;95,-2);polygon (70,23;70,48;95,48;95,23);polygon (70,48;70,73;95,73;95,48);polygon (95,-2;95,23;120,23;120,-2);polygon (95,23;95,48;120,48;120,23);polygon (95,48;95,73;120,73;120,48);polygon (120,-2;120,23;145,23;145,-2);polygon (120,23;120,48;145,48;145,23);polygon (120,48;120,73;145,73;145,48)");
|
||||
EXPECT_EQ (to_s (ly, top, o3), "box (-5,-2;20,23);box (-5,23;20,48);box (-5,48;20,73);box (20,-2;45,23);box (20,23;45,48);box (20,48;45,73);box (45,-2;70,23);box (45,23;70,48);box (45,48;70,73);box (70,-2;95,23);box (70,23;95,48);box (70,48;95,73);box (95,-2;120,23);box (95,23;120,48);box (95,48;120,73);box (120,-2;145,23);box (120,23;145,48);box (120,48;145,73)");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -348,8 +348,8 @@ TEST(4)
|
|||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (o, topo, l1o), "");
|
||||
EXPECT_EQ (to_s (o, topo, l2o), "polygon (1000,2000;1000,4000;3000,4000;3000,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l3o), "polygon (1000,2000;1000,4000;3000,4000;3000,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l2o), "box (1000,2000;3000,4000)");
|
||||
EXPECT_EQ (to_s (o, topo, l3o), "box (1000,2000;3000,4000)");
|
||||
|
||||
o.clear_layer (l1o);
|
||||
o.clear_layer (l2o);
|
||||
|
|
@ -359,8 +359,8 @@ TEST(4)
|
|||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (o, topo, l1o), "polygon (3000,2000;3000,4000;1000,4000;1000,4010;3010,4010;3010,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l2o), "polygon (1000,2000;1000,4000;3000,4000;3000,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l3o), "polygon (1000,2000;1000,4010;3010,4010;3010,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l2o), "box (1000,2000;3000,4000)");
|
||||
EXPECT_EQ (to_s (o, topo, l3o), "box (1000,2000;3010,4010)");
|
||||
|
||||
o.clear_layer (l1o);
|
||||
o.clear_layer (l2o);
|
||||
|
|
@ -370,7 +370,7 @@ TEST(4)
|
|||
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (o, topo, l1o), "polygon (1000,4000;1000,4010;1510,4010;1510,4000);polygon (1510,4000;1510,4010;2510,4010;2510,4000);polygon (3000,2000;3000,2510;3010,2510;3010,2000);polygon (3000,2510;3000,3510;3010,3510;3010,2510);polygon (3000,3510;3000,4000;2510,4000;2510,4010;3010,4010;3010,3510)");
|
||||
EXPECT_EQ (to_s (o, topo, l1o), "polygon (3000,3510;3000,4000;2510,4000;2510,4010;3010,4010;3010,3510);box (1000,4000;1510,4010);box (1510,4000;2510,4010);box (3000,2000;3010,2510);box (3000,2510;3010,3510)");
|
||||
|
||||
o.clear_layer (l1o);
|
||||
o.clear_layer (l2o);
|
||||
|
|
@ -380,9 +380,9 @@ TEST(4)
|
|||
tp.set_scale_to_dbu (false);
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (o, topo, l1o), "polygon (100,200;100,400;300,400;300,200);polygon (1000,2000;1000,4010;3010,4010;3010,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l2o), "polygon (100,200;100,400;300,400;300,200)");
|
||||
EXPECT_EQ (to_s (o, topo, l3o), "polygon (1000,2000;1000,4010;3010,4010;3010,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l1o), "box (100,200;300,400);box (1000,2000;3010,4010)");
|
||||
EXPECT_EQ (to_s (o, topo, l2o), "box (100,200;300,400)");
|
||||
EXPECT_EQ (to_s (o, topo, l3o), "box (1000,2000;3010,4010)");
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5148,9 +5148,6 @@ CODE
|
|||
|
||||
m = with_left ? "fill_with_left" : "fill"
|
||||
|
||||
# generation of new cells not tested in deep mode
|
||||
@deep && raise("#{m} command not supported in deep mode currently")
|
||||
|
||||
(@engine._output_layout && @engine._output_cell) || raise("#{m} command needs an output layout and output cell")
|
||||
|
||||
source = @engine.source
|
||||
|
|
|
|||
|
|
@ -1302,6 +1302,16 @@ TEST(47_fillWithOverlappingBoxesTiled)
|
|||
run_test (_this, "47", false);
|
||||
}
|
||||
|
||||
TEST(47b_fillWithUsingOutput)
|
||||
{
|
||||
run_test (_this, "47b", false);
|
||||
}
|
||||
|
||||
TEST(47bd_fillWithUsingOutputDeep)
|
||||
{
|
||||
run_test (_this, "47b", true);
|
||||
}
|
||||
|
||||
TEST(48_drcWithFragments)
|
||||
{
|
||||
run_test (_this, "48", false);
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ BEGIN_PROTECTED
|
|||
|
||||
try {
|
||||
|
||||
view ()->manager ()->transaction (tl::to_string (QObject::tr ("Export Markers")));
|
||||
db::Transaction transaction (view ()->is_editable () ? view ()->manager () : 0, tl::to_string (QObject::tr ("Export Markers")));
|
||||
|
||||
std::vector <const Category *> categories;
|
||||
for (rdb::Categories::const_iterator cat = rdb->categories ().begin (); cat != rdb->categories ().end (); ++cat) {
|
||||
|
|
@ -355,11 +355,9 @@ BEGIN_PROTECTED
|
|||
|
||||
}
|
||||
|
||||
view ()->manager ()->commit ();
|
||||
view ()->update_content ();
|
||||
|
||||
} catch (...) {
|
||||
view ()->manager ()->commit ();
|
||||
view ()->update_content ();
|
||||
throw;
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,27 @@
|
|||
* Test
|
||||
|
||||
.options scale=1e-6
|
||||
|
||||
.model sky130_fd_pr__pfet_01v8 NMOS level=8 version=3.3.0
|
||||
.model sky130_fd_pr__nfet_01v8 NMOS level=8 version=3.3.0
|
||||
|
||||
XXpmos Q I VDD VDD pmos4_standard w=1.5 l=0.15 nf=4
|
||||
XXnmos Q I VSS VSS nmos4_standard w=1.5 l=0.15 nf=4
|
||||
XXDUMMY0 VSS VSS VSS VSS nmos4_standard w=1.5 l=0.15 nf=2
|
||||
XXDUMMY1 VSS VSS VSS VSS nmos4_standard w=1.5 l=0.15 nf=2
|
||||
XXDUMMY2 VDD VDD VDD VDD pmos4_standard w=1.5 l=0.15 nf=2
|
||||
XXDUMMY3 VDD VDD VDD VDD pmos4_standard w=1.5 l=0.15 nf=2
|
||||
|
||||
.subckt pmos4_standard D G S B w=0.1 l=0.018 nf=4
|
||||
MM1 D G S B sky130_fd_pr__pfet_01v8 L=l W='w * nf ' ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
|
||||
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
|
||||
+ m=1
|
||||
.ends
|
||||
|
||||
.subckt nmos4_standard D G S B w=0.1 l=0.018 nf=4
|
||||
MM1 D G S B sky130_fd_pr__nfet_01v8 L=l W='w * nf ' ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
|
||||
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
|
||||
+ m=1
|
||||
.ends
|
||||
|
||||
.end
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
source $drc_test_source
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
to_fill = input(1, 0)
|
||||
|
||||
# Create a fill pattern with a 0.025x0.025 µm box at 2/0
|
||||
pattern = fill_pattern("FILL_CELL").shape(2, 0, box(0, 0, 0.025, 0.025))
|
||||
|
||||
# place every 25 nm
|
||||
to_fill.fill(pattern, hstep(0.025), vstep(0.025))
|
||||
|
||||
# compute remaining parts
|
||||
l2 = input(2, 0)
|
||||
(to_fill - l2).output(100, 0)
|
||||
|
||||
# we cannot use input(..) on the fill output if we use
|
||||
# a separate target layout, so wo do this:
|
||||
layout.layout.write($drc_test_target)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -625,14 +625,9 @@ class DBNetlist_TestClass < TestBase
|
|||
dc.terminal_definitions.each { |pd| names << pd.name }
|
||||
assert_equal(names, [])
|
||||
|
||||
pd = RBA::DeviceParameterDefinition::new("P1", "Parameter 1", 2.0)
|
||||
assert_equal(pd.default_value, 2.0)
|
||||
pd = RBA::DeviceParameterDefinition::new("P1", "Parameter 1")
|
||||
pd.default_value = 1.0
|
||||
assert_equal(pd.default_value, 1.0)
|
||||
pd.is_primary = false
|
||||
assert_equal(pd.is_primary?, false)
|
||||
pd.is_primary = true
|
||||
assert_equal(pd.is_primary?, true)
|
||||
|
||||
dc.add_parameter(pd)
|
||||
|
||||
|
|
@ -1181,6 +1176,24 @@ END
|
|||
|
||||
end
|
||||
|
||||
def test_16_deviceParameterObject
|
||||
|
||||
pd = RBA::DeviceParameterDefinition::new("P1", "Parameter 1", 2.0, false, 17.5, 2.0)
|
||||
assert_equal(pd.default_value, 2.0)
|
||||
pd.default_value = 1.0
|
||||
assert_equal(pd.default_value, 1.0)
|
||||
assert_equal(pd.is_primary?, false)
|
||||
pd.is_primary = true
|
||||
assert_equal(pd.is_primary?, true)
|
||||
assert_equal(pd.si_scaling, 17.5)
|
||||
pd.si_scaling = 1.0
|
||||
assert_equal(pd.si_scaling, 1.0)
|
||||
assert_equal(pd.geo_scaling_exponent, 2.0)
|
||||
pd.geo_scaling_exponent = 1.0
|
||||
assert_equal(pd.geo_scaling_exponent, 1.0)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
# This script is sourced to define the main version parameters
|
||||
|
||||
# The main version
|
||||
KLAYOUT_VERSION="0.28.5"
|
||||
KLAYOUT_VERSION="0.28.6"
|
||||
|
||||
# The version used for PyPI (don't use variables here!)
|
||||
KLAYOUT_PYPI_VERSION="0.28.5"
|
||||
KLAYOUT_PYPI_VERSION="0.28.6"
|
||||
|
||||
# The build date
|
||||
KLAYOUT_VERSION_DATE=$(date "+%Y-%m-%d")
|
||||
|
|
|
|||
Loading…
Reference in New Issue