WIP: refactoring, added first tests for LVS

This commit is contained in:
Matthias Koefferlein 2019-07-06 08:52:40 +02:00
parent 15022709b4
commit 2f6aae7204
19 changed files with 1316 additions and 56 deletions

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<klayout-macro>
<description/>
<version/>
<category/>
<prolog/>
<epilog/>
<doc/>
<autorun>true</autorun>
<autorun-early>false</autorun-early>
<shortcut/>
<show-in-menu>false</show-in-menu>
<group-name/>
<menu-path/>
<interpreter>ruby</interpreter>
<dsl-interpreter-name/>
<text>
# Installs the home menu entries (needs to be done on autorun, not autorun-early)
if RBA::Application::instance &amp;&amp; RBA::Application::instance.main_window
cat = "drc"
name = cat.upcase
mw = RBA::Application::instance.main_window
mw.menu.insert_menu("tools_menu.verification_group+", cat, name)
new_action = RBA::Action::new
new_action.title = "New #{name} Script"
new_action.on_triggered do
mw.show_macro_editor(cat, true)
end
mw.menu.insert_item("tools_menu.#{cat}.end", "new_script", new_action)
edit_action = RBA::Action::new
edit_action.title = "Edit #{name} Script"
edit_action.on_triggered do
mw.show_macro_editor(cat, false)
end
mw.menu.insert_item("tools_menu.#{cat}.end", "edit_script", edit_action)
end
</text>
</klayout-macro>

View File

@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<klayout-macro>
<description/>
<version/>
<category/>
<prolog/>
<epilog/>
<doc/>
<autorun>true</autorun>
<autorun-early>false</autorun-early>
<shortcut/>
<show-in-menu>false</show-in-menu>
<group-name/>
<menu-path/>
<interpreter>ruby</interpreter>
<dsl-interpreter-name/>
<text>
# Installs the home menu entries (needs to be done on autorun, not autorun-early)
if RBA::Application::instance &amp;&amp; RBA::Application::instance.main_window
[ "drc", "lvs" ].each do |cat|
name = cat.upcase
mw = RBA::Application::instance.main_window
mw.menu.insert_menu("tools_menu.verification_group+", cat, name)
new_action = RBA::Action::new
new_action.title = "New #{name} Script"
new_action.on_triggered do
mw.show_macro_editor(cat, true)
end
mw.menu.insert_item("tools_menu.#{cat}.end", "new_script", new_action)
edit_action = RBA::Action::new
edit_action.title = "Edit #{name} Script"
edit_action.on_triggered do
mw.show_macro_editor(cat, false)
end
mw.menu.insert_item("tools_menu.#{cat}.end", "edit_script", edit_action)
end
end
</text>
</klayout-macro>

View File

@ -7,9 +7,6 @@
<file alias="_drc_source.rb">built-in-macros/_drc_source.rb</file>
<file alias="_drc_tags.rb">built-in-macros/_drc_tags.rb</file>
<file alias="drc_interpreters.lym">built-in-macros/drc_interpreters.lym</file>
<file alias="_lvs_netter.rb">built-in-macros/_lvs_netter.rb</file>
<file alias="_lvs_engine.rb">built-in-macros/_lvs_engine.rb</file>
<file alias="lvs_interpreters.lym">built-in-macros/lvs_interpreters.lym</file>
<file alias="install.lym">built-in-macros/install.lym</file>
<file alias="drc_install.lym">built-in-macros/drc_install.lym</file>
</qresource>
</RCC>

View File

@ -69,9 +69,10 @@ plugins.depends += lib rdb db
}
equals(HAVE_RUBY, "1") {
SUBDIRS += drc
MAIN_DEPENDS += drc
SUBDIRS += drc lvs
MAIN_DEPENDS += drc lvs
drc.depends += rdb lym
lvs.depends += drc
}
equals(HAVE_QTBINDINGS, "1") {

6
src/lvs/lvs.pro Normal file
View File

@ -0,0 +1,6 @@
TEMPLATE = subdirs
SUBDIRS = lvs unit_tests
unit_tests.depends += lvs

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<klayout-macro>
<description/>
<version/>
<category/>
<prolog/>
<epilog/>
<doc/>
<autorun>true</autorun>
<autorun-early>false</autorun-early>
<shortcut/>
<show-in-menu>false</show-in-menu>
<group-name/>
<menu-path/>
<interpreter>ruby</interpreter>
<dsl-interpreter-name/>
<text>
# Installs the home menu entries (needs to be done on autorun, not autorun-early)
if RBA::Application::instance &amp;&amp; RBA::Application::instance.main_window
cat = "lvs"
name = cat.upcase
mw = RBA::Application::instance.main_window
mw.menu.insert_menu("tools_menu.verification_group+", cat, name)
new_action = RBA::Action::new
new_action.title = "New #{name} Script"
new_action.on_triggered do
mw.show_macro_editor(cat, true)
end
mw.menu.insert_item("tools_menu.#{cat}.end", "new_script", new_action)
edit_action = RBA::Action::new
edit_action.title = "Edit #{name} Script"
edit_action.on_triggered do
mw.show_macro_editor(cat, false)
end
mw.menu.insert_item("tools_menu.#{cat}.end", "edit_script", edit_action)
end
</text>
</klayout-macro>

22
src/lvs/lvs/lvs.pro Normal file
View File

@ -0,0 +1,22 @@
DESTDIR = $$OUT_PWD/../..
TARGET = klayout_lvs
include($$PWD/../../lib.pri)
DEFINES += MAKE_LVS_LIBRARY
SOURCES = \
lvsForceLink.cc \
HEADERS = \
lvsCommon.h \
lvsForceLink.h \
RESOURCES = \
lvsResources.qrc
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC $$LYM_INC $$RDB_INC
DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC $$LYM_INC $$RDB_INC
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi -lklayout_lym -lklayout_rdb -lklayout_drc

51
src/lvs/lvs/lvsCommon.h Normal file
View File

@ -0,0 +1,51 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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
*/
#if !defined(HDR_lvsCommon_h)
# define HDR_lvsCommon_h
# if defined _WIN32 || defined __CYGWIN__
# ifdef MAKE_LVS_LIBRARY
# define LVS_PUBLIC __declspec(dllexport)
# else
# define LVS_PUBLIC __declspec(dllimport)
# endif
# define LVS_LOCAL
# define LVS_PUBLIC_TEMPLATE
# else
# if __GNUC__ >= 4 || defined(__clang__)
# define LVS_PUBLIC __attribute__ ((visibility ("default")))
# define LVS_PUBLIC_TEMPLATE __attribute__ ((visibility ("default")))
# define LVS_LOCAL __attribute__ ((visibility ("hidden")))
# else
# define LVS_PUBLIC
# define LVS_PUBLIC_TEMPLATE
# define LVS_LOCAL
# endif
# endif
#endif

View File

@ -0,0 +1,34 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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 "lvsForceLink.h"
#include "rdbForceLink.h"
namespace lvs
{
int _force_link_f ()
{
return 0;
}
}

View File

@ -0,0 +1,40 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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
*/
#ifndef HDR_lvsForceLink
#define HDR_lvsForceLink
#include "lvsCommon.h"
/**
* @file Include this function to force linking of the lvs module
*/
namespace lvs
{
LVS_PUBLIC int _force_link_f ();
int _force_link_target = _force_link_f ();
}
#endif

View File

@ -0,0 +1,8 @@
<RCC>
<qresource prefix="/built-in-macros">
<file alias="_lvs_netter.rb">built-in-macros/_lvs_netter.rb</file>
<file alias="_lvs_engine.rb">built-in-macros/_lvs_engine.rb</file>
<file alias="lvs_interpreters.lym">built-in-macros/lvs_interpreters.lym</file>
<file alias="lvs_install.lym">built-in-macros/lvs_install.lym</file>
</qresource>
</RCC>

View File

@ -0,0 +1,162 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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)
{
std::string input = tl::testsrc ();
input += "/testdata/lvs/inv.oas";
std::string schematic = "inv.cir"; // relative to inv.oas
std::string au_cir = tl::testsrc ();
au_cir += "/testdata/lvs/inv_layout.cir";
std::string au_lvsdb = tl::testsrc ();
au_lvsdb += "/testdata/lvs/inv.lvsdb";
std::string output_cir = this->tmp_file ("tmp.cir");
std::string output_lvsdb = this->tmp_file ("tmp.lvsdb");
lym::Macro lvs;
lvs.set_text (tl::sprintf (
"source('%s', 'INVERTER')\n"
"\n"
"deep\n"
"\n"
"# Reports generated\n"
"\n"
"# LVS report to inv.lvsdb\n"
"report_lvs('%s')\n"
"\n"
"# Write extracted netlist to inv_extracted.cir\n"
"target_netlist('%s', write_spice, 'Extracted by KLayout')\n"
"\n"
"# Drawing layers\n"
"\n"
"nwell = input(1, 0)\n"
"active = input(2, 0)\n"
"pplus = input(3, 0)\n"
"nplus = input(4, 0)\n"
"poly = input(5, 0)\n"
"contact = input(6, 0)\n"
"metal1 = input(7, 0)\n"
"metal1_lbl = labels(7, 1)\n"
"via1 = input(8, 0)\n"
"metal2 = input(9, 0)\n"
"metal2_lbl = labels(9, 1)\n"
"\n"
"# Bulk layer for terminal provisioning\n"
"\n"
"bulk = polygon_layer\n"
"\n"
"# Computed layers\n"
"\n"
"active_in_nwell = active & nwell\n"
"pactive = active_in_nwell & pplus\n"
"pgate = pactive & poly\n"
"psd = pactive - pgate\n"
"\n"
"active_outside_nwell = active - nwell\n"
"nactive = active_outside_nwell & nplus\n"
"ngate = nactive & poly\n"
"nsd = nactive - ngate\n"
"\n"
"# Device extraction\n"
"\n"
"# PMOS transistor device extraction\n"
"extract_devices(mos4('PMOS'), { 'SD' => psd, 'G' => pgate, 'W' => nwell, \n"
" 'tS' => psd, 'tD' => psd, 'tG' => poly, 'tW' => nwell })\n"
"\n"
"# NMOS transistor device extraction\n"
"extract_devices(mos4('NMOS'), { 'SD' => nsd, 'G' => ngate, 'W' => bulk, \n"
" 'tS' => nsd, 'tD' => nsd, 'tG' => poly, 'tW' => bulk })\n"
"\n"
"# Define connectivity for netlist extraction\n"
"\n"
"# Inter-layer\n"
"connect(psd, contact)\n"
"connect(nsd, contact)\n"
"connect(poly, contact)\n"
"connect(contact, metal1)\n"
"connect(metal1, metal1_lbl) # attaches labels\n"
"connect(metal1, via1)\n"
"connect(via1, metal2)\n"
"connect(metal2, metal2_lbl) # attaches labels\n"
"\n"
"# Global\n"
"connect_global(bulk, 'SUBSTRATE')\n"
"connect_global(nwell, 'NWELL')\n"
"\n"
"# Compare section\n"
"\n"
"schematic('%s')\n"
"\n"
"compare\n"
, input, output_lvsdb, output_cir, schematic)
);
lvs.set_interpreter (lym::Macro::DSLInterpreter);
lvs.set_dsl_interpreter ("lvs-dsl");
EXPECT_EQ (lvs.run (), 0);
compare_text_files (output_cir, au_cir);
compare_text_files (output_lvsdb, au_lvsdb);
}
#if 0
TEST(2)
{
lym::Macro lvs;
lvs.set_text (
"dbu 0.001\n"
"def compare(a, b, ex)\n"
" a = a.to_s\n"
" b = b.to_s\n"
" if a != b\n"
" raise(ex + \" (actual=#{a}, ref=#{b})\")\n"
" end\n"
"end\n"
"compare(0.1.um, 0.1, \"unexpected value when converting um\")\n"
"compare(0.1.micron, 0.1, \"unexpected value when converting micron\")\n"
"compare(0.1.um2, 0.1, \"unexpected value when converting um2\")\n"
"compare(0.1.mm2, 100000.0, \"unexpected value when converting mm2\")\n"
"compare(120.dbu, 0.12, \"unexpected value when converting dbu\")\n"
"compare((0.1.um + 120.dbu), 0.22, \"unexpected value when adding values\")\n"
"compare(0.1.mm, 100.0, \"unexpected value when converting mm\")\n"
"compare(1e-6.m, 1.0, \"unexpected value when converting m\")\n"
"compare(1.um, 1.0, \"unexpected value when converting integer um\")\n"
"compare(1.micron, 1.0, \"unexpected value when convering integer micron\")\n"
"compare(1.um2, 1.0, \"unexpected value when converting integer um2\")\n"
"compare(1.mm2, 1000000.0, \"unexpected value when converting integer mm2\")\n"
"compare((1.um + 120.dbu), 1.12, \"unexpected value when adding integer values\")\n"
"compare(1.mm, 1000.0, \"unexpected value when converting integer mm\")\n"
"compare(1.m, 1000000.0, \"unexpected value when converting integer m\")\n"
);
lvs.set_interpreter (lym::Macro::DSLInterpreter);
lvs.set_dsl_interpreter ("lvs-dsl");
EXPECT_EQ (lvs.run (), 0);
}
#endif

View File

@ -0,0 +1,623 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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 "dbNetlist.h"
#include "dbNetlistSpiceReader.h"
#include "lymMacro.h"
#include "tlFileUtils.h"
#if 0 // @@@
TEST(1)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_1.lvs";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au1.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = nil\n"
"$lvs_test_target = '%s'\n"
, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
db::compare_layouts (_this, layout, au, db::NoNormalization);
}
TEST(2)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_2.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/lvstest.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au2.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
db::compare_layouts (_this, layout, au, db::NoNormalization);
}
TEST(3_Flat)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_3.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/lvstest.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au3.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
db::compare_layouts (_this, layout, au, db::NoNormalization);
}
TEST(4_Hierarchical)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_4.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/lvstest.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au4.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
db::compare_layouts (_this, layout, au, db::NoNormalization);
}
TEST(5_FlatAntenna)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_5.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/antenna_l1.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au5.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
db::compare_layouts (_this, layout, au, db::NoNormalization);
}
TEST(6_HierarchicalAntenna)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_6.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/antenna_l1.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au6.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
db::compare_layouts (_this, layout, au, db::NoNormalization);
}
TEST(7_AntennaWithDiodes)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_7.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/antenna_l1.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au7.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
db::compare_layouts (_this, layout, au, db::NoNormalization);
}
TEST(8_TextsAndPolygons)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_8.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/texts.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au8.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
db::compare_layouts (_this, layout, au, db::NoNormalization);
}
static void compare_netlists (tl::TestBase *_this, const std::string &cir, const std::string &cir_au)
{
db::Netlist nl, nl_au;
db::NetlistSpiceReader reader;
{
tl::info << "Output: " << cir;
tl::InputStream is (cir);
reader.read (is, nl);
}
{
tl::info << "Golden: " << cir_au;
tl::InputStream is (cir_au);
reader.read (is, nl_au);
}
db::compare_netlist (_this, nl, nl_au);
}
TEST(9_NetlistExtraction)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_9.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/ringo.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au9a.cir";
std::string au_simplified = tl::testsrc ();
au_simplified += "/testdata/lvs/lvsSimpleTests_au9b.cir";
std::string output = this->tmp_file ("tmp.cir");
std::string output_simplified = this->tmp_file ("tmp_simplified.cir");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
"$lvs_test_target_simplified = '%s'\n"
, input, output, output_simplified)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
// verify
CHECKPOINT ();
compare_netlists (_this, output, au);
CHECKPOINT ();
compare_netlists (_this, output_simplified, au_simplified);
}
TEST(10_NetlistExtractionFlat)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_10.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/ringo.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au10a.cir";
std::string au_simplified = tl::testsrc ();
au_simplified += "/testdata/lvs/lvsSimpleTests_au10b.cir";
std::string output = this->tmp_file ("tmp.cir");
std::string output_simplified = this->tmp_file ("tmp_simplified.cir");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
"$lvs_test_target_simplified = '%s'\n"
, input, output, output_simplified)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
// verify
CHECKPOINT ();
compare_netlists (_this, output, au);
CHECKPOINT ();
compare_netlists (_this, output_simplified, au_simplified);
}
TEST(11_CustomDevices)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_11.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/vdiv.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au11a.cir";
std::string au_simplified = tl::testsrc ();
au_simplified += "/testdata/lvs/lvsSimpleTests_au11b.cir";
std::string output = this->tmp_file ("tmp.cir");
std::string output_simplified = this->tmp_file ("tmp_simplified.cir");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
"$lvs_test_target_simplified = '%s'\n"
, input, output, output_simplified)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
// verify
CHECKPOINT ();
compare_netlists (_this, output, au);
CHECKPOINT ();
compare_netlists (_this, output_simplified, au_simplified);
}
TEST(12_NetlistJoinLabels)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_12.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/implicit_nets.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au12a.cir";
std::string output = this->tmp_file ("tmp.cir");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
"$lvs_test_target_simplified = nil\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
// verify
CHECKPOINT ();
compare_netlists (_this, output, au);
}
TEST(13a_KissingCorners)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_13a.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/kissing_corners.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au13a.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
// verify
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
CHECKPOINT ();
db::compare_layouts (_this, layout, au, db::NoNormalization);
}
TEST(13b_KissingCornersDeep)
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/lvsSimpleTests_13b.lvs";
std::string input = tl::testsrc ();
input += "/testdata/lvs/kissing_corners.gds";
std::string au = tl::testsrc ();
au += "/testdata/lvs/lvsSimpleTests_au13b.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$lvs_test_source = '%s'\n"
"$lvs_test_target = '%s'\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro lvs;
lvs.load_from (rs);
EXPECT_EQ (lvs.run (), 0);
// verify
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
CHECKPOINT ();
db::compare_layouts (_this, layout, au, db::NoNormalization);
}
#endif

View File

@ -0,0 +1,16 @@
DESTDIR_UT = $$OUT_PWD/../..
DESTDIR = $$OUT_PWD/..
TARGET = lvs_tests
include($$PWD/../../lib_ut.pri)
SOURCES = \
lvsBasicTests.cc \
lvsSimpleTests.cc \
INCLUDEPATH += $$DRC_INC $$TL_INC $$RDB_INC $$DB_INC $$GSI_INC $$LYM_INC
DEPENDPATH += $$DRC_INC $$TL_INC $$RDB_INC $$DB_INC $$GSI_INC $$LYM_INC
LIBS += -L$$DESTDIR_UT -lklayout_lvs -lklayout_drc -lklayout_rdb -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_lym

239
testdata/lvs/inv.lvsdb vendored Normal file
View File

@ -0,0 +1,239 @@
#%lvsdb-klayout
# Layout
layout(
top(INVERTER)
unit(0.001)
# Layer section
# This section lists the mask layers (drawing or derived) and their connections.
# Mask layers
layer(l3 'NWELL (1/0)')
layer(l8 'POLY (5/0)')
layer(l9 'CONTACT (6/0)')
layer(l10 'METAL1 (7/0)')
layer(l11 'METAL1_LABEL (7/1)')
layer(l12 'VIA1 (8/0)')
layer(l13 'METAL2 (9/0)')
layer(l14 'METAL2_LABEL (9/1)')
layer(l15)
layer(l23)
layer(l31)
# Mask layer connectivity
connect(l3 l3)
connect(l8 l8 l9)
connect(l9 l8 l9 l10 l23 l31)
connect(l10 l9 l10 l11 l12)
connect(l11 l10 l11)
connect(l12 l10 l12 l13)
connect(l13 l12 l13 l14)
connect(l14 l13 l14)
connect(l15 l15)
connect(l23 l9 l23)
connect(l31 l9 l31)
# Global nets and connectivity
global(l3 NWELL)
global(l15 SUBSTRATE)
# Device class section
class(PMOS MOS4)
class(NMOS MOS4)
# Device abstracts section
# Device abstracts list the pin shapes of the devices.
device(D$PMOS PMOS
terminal(S
rect(l23 (-575 -750) (450 1500))
)
terminal(G
rect(l8 (-125 -750) (250 1500))
)
terminal(D
rect(l23 (125 -750) (450 1500))
)
terminal(B
rect(l3 (-125 -750) (250 1500))
)
)
device(D$NMOS NMOS
terminal(S
rect(l31 (-575 -450) (450 900))
)
terminal(G
rect(l8 (-125 -450) (250 900))
)
terminal(D
rect(l31 (125 -450) (450 900))
)
terminal(B
rect(l15 (-125 -450) (250 900))
)
)
# Circuit section
# Circuits are the hierarchical building blocks of the netlist.
circuit(INVERTER
# Nets with their geometries
net(1 name(IN)
rect(l8 (900 50) (250 1050))
rect(l8 (-250 0) (250 3100))
rect(l8 (-250 0) (250 1650))
rect(l8 (-800 -3100) (550 400))
rect(l9 (-450 -300) (200 200))
rect(l10 (-300 -300) (400 400))
rect(l11 (-201 -201) (2 2))
)
net(2 name(VSS)
rect(l9 (550 300) (200 200))
rect(l9 (-200 300) (200 200))
rect(l10 (-250 -950) (300 1050))
rect(l12 (-250 -950) (200 200))
rect(l12 (-200 300) (200 200))
rect(l13 (-750 -850) (2000 1000))
rect(l14 (-101 -851) (2 2))
rect(l31 (-1451 49) (450 900))
)
net(3 name(VDD)
rect(l9 (550 4350) (200 200))
rect(l9 (-200 300) (200 200))
rect(l9 (-200 300) (200 200))
rect(l10 (-250 -1300) (300 1600))
rect(l12 (-250 -800) (200 200))
rect(l12 (-200 300) (200 200))
rect(l13 (-750 -850) (2000 1000))
rect(l14 (-151 -851) (2 2))
rect(l23 (-1401 -851) (450 1500))
)
net(4 name(OUT)
rect(l9 (1300 4350) (200 200))
rect(l9 (-200 300) (200 200))
rect(l9 (-200 300) (200 200))
rect(l9 (-200 -5250) (200 200))
rect(l9 (-200 300) (200 200))
rect(l10 (-250 3250) (300 1400))
rect(l10 (-300 -4600) (300 3200))
rect(l10 (-300 -2900) (450 400))
rect(l10 (-450 -1550) (300 850))
rect(l11 (-51 499) (2 2))
rect(l23 (-351 2649) (450 1500))
rect(l31 (-450 -5500) (450 900))
)
net(5 name(NWELL)
rect(l3 (0 2950) (2000 3200))
)
net(6 name(SUBSTRATE))
# Devices and their connections
device(1 D$PMOS
location(1025 4950)
param(L 0.25)
param(W 1.5)
param(AS 0.675)
param(AD 0.675)
param(PS 3.9)
param(PD 3.9)
terminal(S 3)
terminal(G 1)
terminal(D 4)
terminal(B 5)
)
device(2 D$NMOS
location(1025 650)
param(L 0.25)
param(W 0.9)
param(AS 0.405)
param(AD 0.405)
param(PS 2.7)
param(PD 2.7)
terminal(S 2)
terminal(G 1)
terminal(D 4)
terminal(B 6)
)
)
)
# Reference netlist
reference(
# Device class section
class(PMOS MOS4)
class(NMOS MOS4)
# Circuit section
# Circuits are the hierarchical building blocks of the netlist.
circuit(INVERTER
# Nets
net(1 name(VSS))
net(2 name(IN))
net(3 name(OUT))
net(4 name(NWELL))
net(5 name(SUBSTRATE))
net(6 name(VDD))
# Outgoing pins and their connections to nets
pin(1)
pin(2)
pin(3)
pin(4)
pin(5)
pin(6)
# Devices and their connections
device(1 PMOS
name(P)
param(L 0.25)
param(W 1.5)
param(AS 0)
param(AD 0)
param(PS 0)
param(PD 0)
terminal(S 6)
terminal(G 2)
terminal(D 3)
terminal(B 4)
)
device(2 NMOS
name(N)
param(L 0.25)
param(W 0.9)
param(AS 0)
param(AD 0)
param(PS 0)
param(PD 0)
terminal(S 3)
terminal(G 2)
terminal(D 1)
terminal(B 5)
)
)
)
# Cross reference
xref(
circuit(INVERTER INVERTER match
xref(
net(1 2 match)
net(5 4 match)
net(4 3 match)
net(6 5 match)
net(3 6 match)
net(2 1 match)
pin(() 0 match)
pin(() 1 match)
pin(() 2 match)
pin(() 3 match)
pin(() 4 match)
pin(() 5 match)
device(2 2 match)
device(1 1 match)
)
)
)

15
testdata/lvs/inv_layout.cir vendored Normal file
View File

@ -0,0 +1,15 @@
* Extracted by KLayout
* cell INVERTER
.SUBCKT INVERTER
* net 1 IN
* net 2 VSS
* net 3 VDD
* net 4 OUT
* net 5 NWELL
* net 6 SUBSTRATE
* device instance $1 r0 *1 1.025,4.95 PMOS
M$1 3 1 4 5 PMOS L=0.25U W=1.5U AS=0.675P AD=0.675P PS=3.9U PD=3.9U
* device instance $2 r0 *1 1.025,0.65 NMOS
M$2 2 1 4 6 NMOS L=0.25U W=0.9U AS=0.405P AD=0.405P PS=2.7U PD=2.7U
.ENDS INVERTER