Merge pull request #2065 from KLayout/feature/issue-2041

Feature/issue 2041
This commit is contained in:
Matthias Köfferlein 2025-05-29 09:42:46 +02:00 committed by GitHub
commit 6ae3737cd5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 1082 additions and 179 deletions

View File

@ -846,12 +846,20 @@ static std::vector<std::string> split_file_list (const std::string &infile)
void read_files (db::Layout &layout, const std::string &infile, const db::LoadLayoutOptions &options)
{
// We may do this:
// db::LayoutLocker locker (&layout);
// but there are yet unknown side effects
// enter a LEF caching context for chaining multiple DEF with the same LEF
db::LoadLayoutOptions local_options (options);
local_options.set_option_by_name ("lefdef_config.lef_context_enabled", true);
std::vector<std::string> files = split_file_list (infile);
for (std::vector<std::string>::const_iterator f = files.begin (); f != files.end (); ++f) {
tl::InputStream stream (*f);
db::Reader reader (stream);
reader.read (layout, options);
reader.read (layout, local_options);
}
}

View File

@ -186,3 +186,327 @@ TEST(6)
db::compare_layouts (this, layout, input_au, db::WriteGDS2);
}
// Large LEF/DEF to OAS converter test
TEST(10)
{
test_is_long_runner ();
std::string input_dir = tl::testdata_private ();
input_dir += "/lefdef/strm2oas/";
std::string lef_dir = input_dir + "/lef";
std::string def_dir = input_dir + "/def";
std::string gds_dir = input_dir + "/gds";
std::string input_au = input_dir + "/strm2oas_au.oas";
std::string output = this->tmp_file ("strm2oas.oas");
std::string map_arg = "--lefdef-map=" + input_dir + "/sky130.map";
const char *lef_files[] = {
"sky130_fd_sc_hd.tlef",
"sky130_fd_sc_hd_merged.lef",
"sky130_fd_sc_hs_merged.lef",
"sky130_ef_sc_hd__decap_20_12.lef",
"sky130_ef_sc_hd__decap_80_12.lef",
"sky130_ef_sc_hd__fill_4.lef",
"sky130_ef_sc_hd__decap_40_12.lef",
"sky130_ef_sc_hd__decap_60_12.lef",
"sky130_ef_io__analog_esd_pad.lef",
"sky130_ef_io__analog_noesd_pad.lef",
"sky130_ef_io__analog_pad.lef",
"sky130_ef_io__bare_pad.lef",
"sky130_ef_io__com_bus_slice_10um.lef",
"sky130_ef_io__com_bus_slice_1um.lef",
"sky130_ef_io__com_bus_slice_20um.lef",
"sky130_ef_io__com_bus_slice_5um.lef",
"sky130_ef_io__connect_vcchib_vccd_and_vswitch_vddio_slice_20um.lef",
"sky130_ef_io__corner_pad.lef",
"sky130_ef_io__disconnect_vccd_slice_5um.lef",
"sky130_ef_io__disconnect_vdda_slice_5um.lef",
"sky130_ef_io__gpiov2_pad.lef",
"sky130_ef_io__gpiov2_pad_wrapped.lef",
"sky130_ef_io__top_power_hvc.lef",
"sky130_ef_io__vccd_hvc_pad.lef",
"sky130_ef_io__vccd_lvc_clamped2_pad.lef",
"sky130_ef_io__vccd_lvc_clamped3_pad.lef",
"sky130_ef_io__vccd_lvc_clamped_pad.lef",
"sky130_ef_io__vccd_lvc_pad.lef",
"sky130_ef_io__vdda_hvc_clamped_pad.lef",
"sky130_ef_io__vdda_hvc_pad.lef",
"sky130_ef_io__vdda_lvc_pad.lef",
"sky130_ef_io__vddio_hvc_clamped_pad.lef",
"sky130_ef_io__vddio_hvc_pad.lef",
"sky130_ef_io__vddio_lvc_pad.lef",
"sky130_ef_io__vssa_hvc_clamped_pad.lef",
"sky130_ef_io__vssa_hvc_pad.lef",
"sky130_ef_io__vssa_lvc_pad.lef",
"sky130_ef_io__vssd_hvc_pad.lef",
"sky130_ef_io__vssd_lvc_clamped2_pad.lef",
"sky130_ef_io__vssd_lvc_clamped3_pad.lef",
"sky130_ef_io__vssd_lvc_clamped_pad.lef",
"sky130_ef_io__vssd_lvc_pad.lef",
"sky130_ef_io__vssio_hvc_clamped_pad.lef",
"sky130_ef_io__vssio_hvc_pad.lef",
"sky130_ef_io__vssio_lvc_pad.lef",
"sky130_fd_io__signal_5_sym_hv_local_5term.lef",
"sky130_fd_io__top_gpiov2.lef",
"sky130_fd_io__top_power_hvc_wpadv2.lef",
"sky130_fd_sc_hvl__a21o_1.lef",
"sky130_fd_sc_hvl__a21oi_1.lef",
"sky130_fd_sc_hvl__a22o_1.lef",
"sky130_fd_sc_hvl__a22oi_1.lef",
"sky130_fd_sc_hvl__and2_1.lef",
"sky130_fd_sc_hvl__and3_1.lef",
"sky130_fd_sc_hvl__buf_1.lef",
"sky130_fd_sc_hvl__buf_16.lef",
"sky130_fd_sc_hvl__buf_2.lef",
"sky130_fd_sc_hvl__buf_32.lef",
"sky130_fd_sc_hvl__buf_4.lef",
"sky130_fd_sc_hvl__buf_8.lef",
"sky130_fd_sc_hvl__conb_1.lef",
"sky130_fd_sc_hvl__decap_4.lef",
"sky130_fd_sc_hvl__decap_8.lef",
"sky130_fd_sc_hvl__dfrbp_1.lef",
"sky130_fd_sc_hvl__dfrtp_1.lef",
"sky130_fd_sc_hvl__dfsbp_1.lef",
"sky130_fd_sc_hvl__dfstp_1.lef",
"sky130_fd_sc_hvl__dfxbp_1.lef",
"sky130_fd_sc_hvl__dfxtp_1.lef",
"sky130_fd_sc_hvl__diode_2.lef",
"sky130_fd_sc_hvl__dlclkp_1.lef",
"sky130_fd_sc_hvl__dlrtp_1.lef",
"sky130_fd_sc_hvl__dlxtp_1.lef",
"sky130_fd_sc_hvl__einvn_1.lef",
"sky130_fd_sc_hvl__einvp_1.lef",
"sky130_fd_sc_hvl__fill_1.lef",
"sky130_fd_sc_hvl__fill_2.lef",
"sky130_fd_sc_hvl__fill_4.lef",
"sky130_fd_sc_hvl__fill_8.lef",
"sky130_fd_sc_hvl__inv_1.lef",
"sky130_fd_sc_hvl__inv_16.lef",
"sky130_fd_sc_hvl__inv_2.lef",
"sky130_fd_sc_hvl__inv_4.lef",
"sky130_fd_sc_hvl__inv_8.lef",
"sky130_fd_sc_hvl__lsbufhv2hv_hl_1.lef",
"sky130_fd_sc_hvl__lsbufhv2hv_lh_1.lef",
"sky130_fd_sc_hvl__lsbufhv2lv_1.lef",
"sky130_fd_sc_hvl__lsbufhv2lv_simple_1.lef",
"sky130_fd_sc_hvl__lsbuflv2hv_1.lef",
"sky130_fd_sc_hvl__lsbuflv2hv_clkiso_hlkg_3.lef",
"sky130_fd_sc_hvl__lsbuflv2hv_isosrchvaon_1.lef",
"sky130_fd_sc_hvl__lsbuflv2hv_symmetric_1.lef",
"sky130_fd_sc_hvl__mux2_1.lef",
"sky130_fd_sc_hvl__mux4_1.lef",
"sky130_fd_sc_hvl__nand2_1.lef",
"sky130_fd_sc_hvl__nand3_1.lef",
"sky130_fd_sc_hvl__nor2_1.lef",
"sky130_fd_sc_hvl__nor3_1.lef",
"sky130_fd_sc_hvl__o21a_1.lef",
"sky130_fd_sc_hvl__o21ai_1.lef",
"sky130_fd_sc_hvl__o22a_1.lef",
"sky130_fd_sc_hvl__o22ai_1.lef",
"sky130_fd_sc_hvl__or2_1.lef",
"sky130_fd_sc_hvl__or3_1.lef",
"sky130_fd_sc_hvl__probe_p_8.lef",
"sky130_fd_sc_hvl__probec_p_8.lef",
"sky130_fd_sc_hvl__schmittbuf_1.lef",
"sky130_fd_sc_hvl__sdfrbp_1.lef",
"sky130_fd_sc_hvl__sdfrtp_1.lef",
"sky130_fd_sc_hvl__sdfsbp_1.lef",
"sky130_fd_sc_hvl__sdfstp_1.lef",
"sky130_fd_sc_hvl__sdfxbp_1.lef",
"sky130_fd_sc_hvl__sdfxtp_1.lef",
"sky130_fd_sc_hvl__sdlclkp_1.lef",
"sky130_fd_sc_hvl__sdlxtp_1.lef",
"sky130_fd_sc_hvl__xnor2_1.lef",
"sky130_fd_sc_hvl__xor2_1.lef",
"caravel.lef",
"caravel_clocking.lef",
"caravel_core.lef",
"gpio_defaults_block.lef",
"gpio_logic_high.lef",
"housekeeping.lef",
"mgmt_protect_hv.lef",
"mprj2_logic_high.lef",
"mprj_io_buffer.lef",
"mprj_logic_high.lef",
"spare_logic_block.lef",
"user_project_wrapper.lef",
"xres_buf.lef",
"caravel_logo-stub.lef",
"caravel_motto-stub.lef",
"chip_io.lef",
"copyright_block-stub.lef",
"empty_macro.lef",
"manual_power_connections.lef",
"open_source-stub.lef",
"simple_por.lef",
"user_id_programming.lef",
"user_id_textblock-stub.lef",
"RAM128.lef"
};
std::string lefs_arg = "--lefdef-lefs=";
for (size_t i = 0; i < sizeof (lef_files) / sizeof (lef_files[0]); ++i) {
if (i > 0) {
lefs_arg += ",";
}
lefs_arg += lef_dir + "/" + lef_files[i];
}
const char *lefdef_layout_files[] = {
"sky130_fd_sc_hd.gds",
"sky130_fd_sc_hvl__sdlxtp_1.gds",
"sky130_fd_sc_hvl__decap_8.gds",
"sky130_fd_sc_hvl__decap_4.gds",
"sky130_fd_sc_hvl__nand3_1.gds",
"sky130_fd_sc_hvl__sdfxbp_1.gds",
"sky130_fd_sc_hvl__lsbufhv2hv_hl_1.gds",
"sky130_fd_sc_hvl__sdfrbp_1.gds",
"sky130_fd_sc_hvl__a21o_1.gds",
"sky130_fd_sc_hvl__inv_2.gds",
"sky130_fd_sc_hvl__inv_16.gds",
"sky130_fd_sc_hvl__inv_1.gds",
"sky130_fd_sc_hvl__inv_4.gds",
"sky130_fd_sc_hvl__inv_8.gds",
"sky130_fd_sc_hvl__nand2_1.gds",
"sky130_fd_sc_hvl__dfstp_1.gds",
"sky130_fd_sc_hvl__a22o_1.gds",
"sky130_fd_sc_hvl__schmittbuf_1.gds",
"sky130_fd_sc_hvl__a22oi_1.gds",
"sky130_fd_sc_hvl__lsbuflv2hv_1.gds",
"sky130_fd_sc_hvl__fill_4.gds",
"sky130_fd_sc_hvl__fill_1.gds",
"sky130_fd_sc_hvl__fill_2.gds",
"sky130_fd_sc_hvl__fill_8.gds",
"sky130_fd_sc_hvl__sdfrtp_1.gds",
"sky130_fd_sc_hvl__sdfxtp_1.gds",
"sky130_fd_sc_hvl__o22a_1.gds",
"sky130_fd_sc_hvl__dfsbp_1.gds",
"sky130_fd_sc_hvl__o21a_1.gds",
"sky130_fd_sc_hvl__a21oi_1.gds",
"sky130_fd_sc_hvl__buf_1.gds",
"sky130_fd_sc_hvl__buf_2.gds",
"sky130_fd_sc_hvl__buf_4.gds",
"sky130_fd_sc_hvl__buf_32.gds",
"sky130_fd_sc_hvl__buf_16.gds",
"sky130_fd_sc_hvl__buf_8.gds",
"sky130_fd_sc_hvl__einvp_1.gds",
"sky130_fd_sc_hvl__conb_1.gds",
"sky130_fd_sc_hvl__and3_1.gds",
"sky130_fd_sc_hvl__lsbufhv2lv_1.gds",
"sky130_fd_sc_hvl__and2_1.gds",
"sky130_fd_sc_hvl__nor3_1.gds",
"sky130_fd_sc_hvl__dlclkp_1.gds",
"sky130_fd_sc_hvl__lsbuflv2hv_symmetric_1.gds",
"sky130_fd_sc_hvl__sdfstp_1.gds",
"sky130_fd_sc_hvl__dfrbp_1.gds",
"sky130_fd_sc_hvl__dfxbp_1.gds",
"sky130_fd_sc_hvl__nor2_1.gds",
"sky130_fd_sc_hvl__diode_2.gds",
"sky130_fd_sc_hvl__dlrtp_1.gds",
"sky130_fd_sc_hvl__dlxtp_1.gds",
"sky130_fd_sc_hvl__lsbufhv2lv_simple_1.gds",
"sky130_fd_sc_hvl__lsbuflv2hv_clkiso_hlkg_3.gds",
"sky130_fd_sc_hvl__sdlclkp_1.gds",
"sky130_fd_sc_hvl__o22ai_1.gds",
"sky130_fd_sc_hvl__or3_1.gds",
"sky130_fd_sc_hvl__sdfsbp_1.gds",
"sky130_fd_sc_hvl__xor2_1.gds",
"sky130_fd_sc_hvl__mux4_1.gds",
"sky130_fd_sc_hvl__or2_1.gds",
"sky130_fd_sc_hvl__probe_p_8.gds",
"sky130_fd_sc_hvl__dfxtp_1.gds",
"sky130_fd_sc_hvl__mux2_1.gds",
"sky130_fd_sc_hvl__dfrtp_1.gds",
"sky130_fd_sc_hvl__lsbuflv2hv_isosrchvaon_1.gds",
"sky130_fd_sc_hvl__probec_p_8.gds",
"sky130_fd_sc_hvl__xnor2_1.gds",
"sky130_fd_sc_hvl__einvn_1.gds",
"sky130_fd_sc_hvl__o21ai_1.gds",
"sky130_fd_sc_hvl__lsbufhv2hv_lh_1.gds",
"sky130_ef_io__analog.gds",
"sky130_ef_io__bare_pad.gds",
"sky130_ef_io__connect_vcchib_vccd_and_vswitch_vddio_slice_20um.gds",
"sky130_ef_io__disconnect_vccd_slice_5um.gds",
"sky130_ef_io__disconnect_vdda_slice_5um.gds",
"sky130_ef_io__gpiov2_pad_wrapped.gds",
"sky130_ef_sc_hd__decap_12.gds",
"sky130_ef_sc_hd__decap_20_12.gds",
"sky130_ef_sc_hd__decap_40_12.gds",
"sky130_ef_sc_hd__decap_60_12.gds",
"sky130_ef_sc_hd__decap_80_12.gds",
"sky130_ef_sc_hd__fill_12.gds",
"sky130_ef_sc_hd__fill_2.gds",
"sky130_ef_sc_hd__fill_4.gds",
"sky130_ef_sc_hd__fill_8.gds",
"sky130_ef_sc_hvl__fill_8.gds",
"caravel_logo.gds.gz",
"caravel_motto.gds.gz",
"chip_io.gds.gz",
"copyright_block.gds.gz",
"empty_macro.gds.gz",
"manual_power_connections.gds.gz",
"open_source.gds.gz",
"simple_por.gds.gz",
"user_id_programming.gds.gz",
"user_id_textblock.gds.gz",
"RAM128.gds.gz"
};
std::string lefdef_layouts_arg = "--lefdef-lef-layouts=";
for (size_t i = 0; i < sizeof (lefdef_layout_files) / sizeof (lefdef_layout_files[0]); ++i) {
if (i > 0) {
lefdef_layouts_arg += ",";
}
lefdef_layouts_arg += gds_dir + "/" + lefdef_layout_files[i];
}
const char *def_files[] = {
"caravel.def",
"caravel_clocking.def",
"caravel_core.def.gz",
"gpio_defaults_block.def",
"gpio_logic_high.def",
"housekeeping.def",
"mgmt_protect_hv.def",
"mprj2_logic_high.def",
"mprj_io_buffer.def",
"mprj_logic_high.def",
"spare_logic_block.def",
"user_project_wrapper.def",
"xres_buf.def"
};
std::string input;
for (size_t i = 0; i < sizeof (def_files) / sizeof (def_files[0]); ++i) {
if (i > 0) {
input += ",";
}
input += def_dir + "/" + def_files[i];
}
const char *argv[] = { "x",
"--lefdef-no-implicit-lef",
map_arg.c_str (),
lefs_arg.c_str (),
lefdef_layouts_arg.c_str (),
input.c_str (),
output.c_str ()
};
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::LoadLayoutOptions options;
db::Reader reader (stream);
reader.read (layout, options);
}
db::compare_layouts (this, layout, input_au, db::WriteOAS);
}

View File

@ -314,8 +314,13 @@ CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_ind
}
void
CommonReaderBase::init ()
CommonReaderBase::start ()
{
m_id_map.clear ();
m_name_map.clear ();
m_temp_cells.clear ();
m_name_for_id.clear ();
m_layer_map_out.clear ();
m_multi_mapping_placeholders.clear ();
m_layer_cache.clear ();
@ -621,7 +626,7 @@ void
CommonReader::init (const LoadLayoutOptions &options)
{
ReaderBase::init (options);
CommonReaderBase::init ();
CommonReaderBase::start ();
db::CommonReaderOptions common_options = options.get_options<db::CommonReaderOptions> ();
set_conflict_resolution_mode (common_options.cell_conflict_resolution);

View File

@ -207,7 +207,7 @@ public:
/**
* @brief Re-initialize: clears the tables and caches
*/
void init ();
void start ();
/**
* @brief Sets a value indicating whether to create layers

View File

@ -53,24 +53,11 @@ struct DEFImporterGroup
};
DEFImporter::DEFImporter (int warn_level)
: LEFDEFImporter (warn_level),
m_lef_importer (warn_level)
: LEFDEFImporter (warn_level)
{
// .. nothing yet ..
}
void
DEFImporter::read_lef (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state)
{
m_lef_importer.read (stream, layout, state);
}
void
DEFImporter::finish_lef (db::Layout &layout)
{
m_lef_importer.finish_lef (layout);
}
void
DEFImporter::read_polygon (db::Polygon &poly, double scale)
{
@ -112,7 +99,7 @@ DEFImporter::read_rect (db::Polygon &poly, double scale)
std::pair<db::Coord, db::Coord>
DEFImporter::get_wire_width_for_rule (const std::string &rulename, const std::string &ln, double dbu)
{
std::pair<double, double> wxy = m_lef_importer.layer_width (ln, rulename);
std::pair<double, double> wxy = reader_state ()->lef_importer ().layer_width (ln, rulename);
db::Coord wx = db::coord_traits<db::Coord>::rounded (wxy.first / dbu);
db::Coord wy = db::coord_traits<db::Coord>::rounded (wxy.second / dbu);
@ -127,7 +114,7 @@ DEFImporter::get_wire_width_for_rule (const std::string &rulename, const std::st
}
}
std::pair<double, double> min_wxy = m_lef_importer.min_layer_width (ln);
std::pair<double, double> min_wxy = reader_state ()->lef_importer ().min_layer_width (ln);
db::Coord min_wx = db::coord_traits<db::Coord>::rounded (min_wxy.first / dbu);
db::Coord min_wy = db::coord_traits<db::Coord>::rounded (min_wxy.second / dbu);
@ -762,14 +749,19 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
}
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
if (vd != m_via_desc.end () && ! pts.empty ()) {
if (vd == m_via_desc.end ()) {
warn (tl::to_string (tr ("Invalid via name: ")) + vn);
} else if (! pts.empty ()) {
// For the via, the masks are encoded in a three-digit number (<mask-top> <mask-cut> <mask_bottom>)
unsigned int mask_top = (mask / 100) % 10;
unsigned int mask_cut = (mask / 10) % 10;
unsigned int mask_bottom = mask % 10;
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer);
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &reader_state ()->lef_importer ());
if (cell) {
if (nx <= 1 && ny <= 1) {
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ()))));
@ -953,7 +945,7 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
if (vd != m_via_desc.end ()) {
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer);
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &reader_state ()->lef_importer ());
if (cell) {
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), pt)));
}
@ -1130,7 +1122,7 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale)
std::string ln = get ();
if (m_lef_importer.is_routing_layer (ln)) {
if (reader_state ()->lef_importer ().is_routing_layer (ln)) {
if (seen_layers.find (ln) == seen_layers.end ()) {
@ -1145,7 +1137,7 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale)
}
} else if (m_lef_importer.is_cut_layer (ln)) {
} else if (reader_state ()->lef_importer ().is_cut_layer (ln)) {
geo_based_vg->set_maskshift_layer (1, ln);
has_cut_geometry = true;
@ -1195,8 +1187,10 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale)
if (rule_based_vg.get () && geo_based_vg.get ()) {
error (tl::to_string (tr ("A via can only be defined through a VIARULE or geometry, not both ways")));
} else if (rule_based_vg.get ()) {
rule_based_vg->def_local = true;
reader_state ()->register_via_cell (n, std::string (), rule_based_vg.release ());
} else if (geo_based_vg.get ()) {
geo_based_vg->def_local = true;
reader_state ()->register_via_cell (n, std::string (), geo_based_vg.release ());
} else {
error (tl::to_string (tr ("Too little information to generate a via")));
@ -1336,7 +1330,7 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale)
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
if (vd != m_via_desc.end ()) {
std::string nondefaultrule;
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer);
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &reader_state ()->lef_importer ());
if (cell) {
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (pt)));
}
@ -1549,7 +1543,7 @@ DEFImporter::read_fills (db::Layout &layout, db::Cell &design, double scale)
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
if (vd != m_via_desc.end ()) {
std::string nondefaultrule;
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer);
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &reader_state ()->lef_importer ());
if (cell) {
ensure_fill_cell (layout, design, fill_cell).insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (pt)));
}
@ -1600,6 +1594,7 @@ DEFImporter::read_styles (double scale)
}
}
void
DEFImporter::read_components (db::Layout &layout, std::list<std::pair<std::string, CellInstArray> > &instances, double scale)
{
@ -1613,9 +1608,26 @@ DEFImporter::read_components (db::Layout &layout, std::list<std::pair<std::strin
bool is_placed = false;
std::string maskshift;
std::map<std::string, MacroDesc>::const_iterator m = m_lef_importer.macros ().find (model);
if (m == m_lef_importer.macros ().end ()) {
error (tl::to_string (tr ("Macro not found in LEF file: ")) + model);
const MacroDesc *m = 0;
std::map<std::string, MacroDesc>::const_iterator im = reader_state ()->lef_importer ().macros ().find (model);
if (im == reader_state ()->lef_importer ().macros ().end ()) {
warn (tl::sprintf (tl::to_string (tr ("Macro not found in LEF file: %s - creating dummy macro")), model));
// create a dummy macro definition (no FOREIGN, size 0x0 etc.)
GeometryBasedLayoutGenerator *mg = new GeometryBasedLayoutGenerator ();
reader_state ()->register_macro_cell (model, mg);
MacroDesc macro_desc;
macro_desc.bbox = db::Box (db::Point (), db::Point ());
m = reader_state ()->lef_importer ().insert_macro (model, macro_desc);
} else {
m = &im->second;
}
while (test ("+")) {
@ -1627,7 +1639,7 @@ DEFImporter::read_components (db::Layout &layout, std::list<std::pair<std::strin
test (")");
ft = get_orient (false /*mandatory*/);
d = pt - m->second.bbox.transformed (ft).lower_left ();
d = pt - m->bbox.transformed (ft).lower_left ();
is_placed = true;
} else if (test ("UNPLACED")) {
@ -1639,7 +1651,7 @@ DEFImporter::read_components (db::Layout &layout, std::list<std::pair<std::strin
test (")");
ft = get_orient (false /*mandatory*/);
d = pt - m->second.bbox.transformed (ft).lower_left ();
d = pt - m->bbox.transformed (ft).lower_left ();
is_placed = true;
}
@ -1660,7 +1672,7 @@ DEFImporter::read_components (db::Layout &layout, std::list<std::pair<std::strin
if (is_placed) {
std::pair<db::Cell *, db::Trans> ct = reader_state ()->macro_cell (model, layout, m_component_maskshift, string2masks (maskshift), m->second, &m_lef_importer);
std::pair<db::Cell *, db::Trans> ct = reader_state ()->macro_cell (model, layout, m_component_maskshift, string2masks (maskshift), *m, &reader_state ()->lef_importer ());
if (ct.first) {
db::CellInstArray inst (db::CellInst (ct.first->cell_index ()), db::Trans (ft.rot (), d) * ct.second);
instances.push_back (std::make_pair (inst_name, inst));
@ -1684,7 +1696,7 @@ DEFImporter::do_read (db::Layout &layout)
std::list<DEFImporterGroup> groups;
std::list<std::pair<std::string, db::CellInstArray> > instances;
m_via_desc = m_lef_importer.vias ();
m_via_desc = reader_state ()->lef_importer ().vias ();
m_styles.clear ();
m_design_name.clear ();

View File

@ -48,26 +48,12 @@ public:
/**
* @brief Default constructor
*/
DEFImporter (int warn_level = 1);
/**
* @brief Read the given LEF file prior to the DEF file
*
* This method reads the layout specified into the given layout.
* Multiple LEF files can be read.
*/
void read_lef (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state);
/**
* @brief Provided for test purposes
*/
void finish_lef (Layout &layout);
DEFImporter (int warn_level);
protected:
void do_read (db::Layout &layout);
private:
LEFImporter m_lef_importer;
std::map<std::string, std::map<std::string, db::Coord> > m_nondefault_widths;
std::map<std::string, ViaDesc> m_via_desc;
std::map<int, db::Polygon> m_styles;

View File

@ -22,9 +22,11 @@
#include "dbLEFDEFImporter.h"
#include "dbLEFImporter.h"
#include "dbLayoutUtils.h"
#include "dbTechnology.h"
#include "dbShapeProcessor.h"
#include "dbCellMapping.h"
#include "tlStream.h"
#include "tlProgress.h"
@ -598,13 +600,15 @@ LEFDEFReaderOptions::LEFDEFReaderOptions ()
m_map_file (),
m_macro_resolution_mode (0),
m_read_lef_with_def (true),
m_paths_relative_to_cwd (false)
m_paths_relative_to_cwd (false),
m_lef_context_enabled (false)
{
// .. nothing yet ..
}
LEFDEFReaderOptions::LEFDEFReaderOptions (const LEFDEFReaderOptions &d)
: db::FormatSpecificReaderOptions ()
: db::FormatSpecificReaderOptions (),
m_lef_context_enabled (false)
{
operator= (d);
}
@ -951,26 +955,33 @@ LEFDEFReaderOptions::special_routing_datatype_str () const
return get_datatypes (this, &LEFDEFReaderOptions::special_routing_datatype, &LEFDEFReaderOptions::special_routing_datatype_per_mask, max_mask_number ());
}
void
LEFDEFReaderOptions::set_lef_context_enabled (bool f)
{
if (f != m_lef_context_enabled) {
mp_reader_state.reset (0);
m_lef_context_enabled = f;
}
}
db::LEFDEFReaderState *
LEFDEFReaderOptions::reader_state (db::Layout &layout, const std::string &base_path, const db::LoadLayoutOptions &options) const
{
if (m_lef_context_enabled && ! mp_reader_state.get ()) {
mp_reader_state.reset (new db::LEFDEFReaderState (this));
mp_reader_state->init (layout, base_path, options);
}
return mp_reader_state.get ();
}
// -----------------------------------------------------------------------------------
// LEFDEFLayerDelegate implementation
LEFDEFReaderState::LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout, const std::string &base_path)
LEFDEFReaderState::LEFDEFReaderState (const LEFDEFReaderOptions *tc)
: mp_importer (0), m_create_layers (true), m_has_explicit_layer_mapping (false), m_laynum (1), mp_tech_comp (tc)
{
if (! tc) {
// use default options
} else if (! tc->map_file ().empty ()) {
read_map_file (tc->map_file (), layout, base_path);
} else {
m_layer_map = tc->layer_map ();
m_create_layers = tc->read_all_layers ();
}
// .. nothing yet ..
}
LEFDEFReaderState::~LEFDEFReaderState ()
@ -988,6 +999,57 @@ LEFDEFReaderState::~LEFDEFReaderState ()
m_macro_generators.clear ();
}
void
LEFDEFReaderState::init (Layout &layout, const std::string &base_path, const LoadLayoutOptions &options)
{
if (! mp_tech_comp) {
// use default options
} else if (! mp_tech_comp->map_file ().empty ()) {
read_map_file (mp_tech_comp->map_file (), layout, base_path);
} else {
m_layer_map = mp_tech_comp->layer_map ();
m_create_layers = mp_tech_comp->read_all_layers ();
}
if (mp_tech_comp) {
m_macro_layouts = mp_tech_comp->macro_layouts ();
// Additionally read the layouts from the given paths
for (std::vector<std::string>::const_iterator l = mp_tech_comp->begin_macro_layout_files (); l != mp_tech_comp->end_macro_layout_files (); ++l) {
auto paths = correct_path (*l, layout, base_path, true);
for (auto lp = paths.begin (); lp != paths.end (); ++lp) {
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF macro layout file: ")) + *lp);
tl::InputStream macro_layout_stream (*lp);
tl::log << tl::to_string (tr ("Reading")) << " " << *lp;
db::Layout *new_layout = new db::Layout (false);
m_macro_layout_object_holder.push_back (new_layout);
m_macro_layouts.push_back (new_layout);
db::Reader reader (macro_layout_stream);
reader.read (*new_layout, options);
if (fabs (new_layout->dbu () / layout.dbu () - 1.0) > db::epsilon) {
warn (tl::sprintf (tl::to_string (tr ("DBU of macro layout file '%s' does not match reader DBU (layout DBU is %.12g, reader DBU is set to %.12g)")),
*lp, new_layout->dbu (), layout.dbu ()));
}
}
}
}
}
void
LEFDEFReaderState::error (const std::string &msg)
{
@ -1004,6 +1066,36 @@ LEFDEFReaderState::warn (const std::string &msg, int warn_level)
}
}
void
LEFDEFReaderState::ensure_lef_importer (int warn_level)
{
if (! mp_lef_importer.get ()) {
mp_lef_importer.reset (new db::LEFImporter (warn_level));
}
}
db::LEFImporter &
LEFDEFReaderState::lef_importer ()
{
tl_assert (mp_lef_importer.get () != 0);
return *mp_lef_importer;
}
void
LEFDEFReaderState::read_lef (const std::string &fn, db::Layout &layout)
{
tl::InputStream stream (fn);
lef_importer ().read (stream, layout, *this);
m_lef_files_read.insert (fn);
}
void
LEFDEFReaderState::finish_lef (db::Layout &layout)
{
lef_importer ().finish_lef (layout);
}
void
LEFDEFReaderState::register_layer (const std::string &ln)
{
@ -1715,11 +1807,76 @@ std::set<unsigned int> LEFDEFReaderState::open_layer_uncached(db::Layout &layout
}
}
void
LEFDEFReaderState::start ()
{
// Start over for a new DEF file - this function is used in LEF context mode
// i.e. when LEFs are cached during multiple DEF reads. It is called when a new DEF is read.
CommonReaderBase::start ();
m_foreign_cells.clear ();
// Remove the via generators that were added by DEF
// TODO: there is no concept for "local LEFs" currently. Even LEFs stored along
// with DEFs are considered "global".
for (auto vg = m_via_generators.begin (); vg != m_via_generators.end (); ) {
auto vg_here = vg;
++vg;
if (vg_here->second->def_local) {
delete vg_here->second;
m_via_generators.erase (vg_here);
}
}
// We always create fresh via cells for different DEFs to avoid potential
// content conflicts. Problem is: vias can be generated by both LEF (global)
// and DEF (local)
m_via_cells.clear ();
}
void
LEFDEFReaderState::finish (db::Layout &layout)
{
CommonReaderBase::finish (layout);
// Resolve unresolved COMPONENT cells
db::cell_index_type seen = std::numeric_limits<db::cell_index_type>::max ();
for (std::vector<db::Layout *>::const_iterator m = macro_layouts ().begin (); m != macro_layouts ().end (); ++m) {
std::vector<db::cell_index_type> target_cells, source_cells;
// collect the cells to pull in
for (std::map<std::string, db::cell_index_type>::iterator f = m_foreign_cells.begin (); f != m_foreign_cells.end (); ++f) {
if (f->second != seen) {
std::pair<bool, db::cell_index_type> cp = (*m)->cell_by_name (f->first.c_str ());
if (cp.first) {
target_cells.push_back (f->second);
source_cells.push_back (cp.second);
layout.cell (f->second).set_ghost_cell (false);
f->second = seen;
}
}
}
db::CellMapping cm;
cm.create_multi_mapping_full (layout, target_cells, **m, source_cells);
layout.copy_tree_shapes (**m, cm);
}
// Warn about cells that could not be resolved
for (std::map<std::string, db::cell_index_type>::iterator f = m_foreign_cells.begin (); f != m_foreign_cells.end (); ++f) {
if (f->second != seen && layout.cell (f->second).is_ghost_cell ()) {
warn (tl::sprintf (tl::to_string (tr ("Could not find a substitution layout for foreign cell '%s'")),
f->first));
}
}
// Create the layers
int lnum = 0;
std::set<int> used_numbers;
@ -1790,48 +1947,52 @@ LEFDEFReaderState::finish (db::Layout &layout)
void
LEFDEFReaderState::register_via_cell (const std::string &vn, const std::string &nondefaultrule, LEFDEFLayoutGenerator *generator)
{
if (m_via_generators.find (std::make_pair (vn, nondefaultrule)) != m_via_generators.end ()) {
delete m_via_generators [std::make_pair (vn, nondefaultrule)];
}
m_via_generators [std::make_pair (vn, nondefaultrule)] = generator;
// inserts at the end of the range
m_via_generators.insert (std::make_pair (std::make_pair (vn, nondefaultrule), generator));
}
LEFDEFLayoutGenerator *
LEFDEFReaderState::via_generator (const std::string &vn, const std::string &nondefaultrule)
{
std::map<std::pair<std::string, std::string>, LEFDEFLayoutGenerator *>::const_iterator g = m_via_generators.find (std::make_pair (vn, nondefaultrule));
if (g == m_via_generators.end () && ! nondefaultrule.empty ()) {
// default rule is fallback
g = m_via_generators.find (std::make_pair (vn, std::string ()));
return via_generator_and_rule (vn, nondefaultrule).first;
}
std::pair<LEFDEFLayoutGenerator *, std::string>
LEFDEFReaderState::via_generator_and_rule (const std::string &vn, const std::string &nondefaultrule)
{
auto key = std::make_pair (vn, nondefaultrule);
auto g = m_via_generators.upper_bound (key);
if (g != m_via_generators.begin ()) {
--g;
}
if (g != m_via_generators.end ()) {
return g->second;
if (g == m_via_generators.end () || g->first != key) {
if (nondefaultrule.empty ()) {
return std::pair<LEFDEFLayoutGenerator *, std::string> (0, std::string ());
} else {
// default rule is fallback
return via_generator_and_rule (vn, std::string ());
}
} else {
return 0;
return std::make_pair (g->second, nondefaultrule);
}
}
db::Cell *
LEFDEFReaderState::via_cell (const std::string &vn, const std::string &nondefaultrule, db::Layout &layout, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm)
{
ViaKey vk (vn, nondefaultrule, mask_bottom, mask_cut, mask_top);
auto gr = via_generator_and_rule (vn, nondefaultrule);
LEFDEFLayoutGenerator *vg = gr.first;
std::map<std::pair<std::string, std::string>, LEFDEFLayoutGenerator *>::const_iterator g = m_via_generators.find (std::make_pair (vn, nondefaultrule));
if (g == m_via_generators.end () && ! vk.nondefaultrule.empty ()) {
// default rule is fallback
g = m_via_generators.find (std::make_pair (vn, std::string ()));
vk.nondefaultrule.clear ();
}
ViaKey vk (vn, gr.second, mask_bottom, mask_cut, mask_top);
std::map<ViaKey, db::Cell *>::const_iterator i = m_via_cells.find (vk);
if (i == m_via_cells.end ()) {
db::Cell *cell = 0;
if (g != m_via_generators.end ()) {
LEFDEFLayoutGenerator *vg = g->second;
if (vg) {
std::string n = vn;
@ -1860,6 +2021,14 @@ LEFDEFReaderState::via_cell (const std::string &vn, const std::string &nondefaul
vg->create_cell (*this, layout, *cell, 0, masks, nm);
} else {
std::string details;
if (! nondefaultrule.empty () && nondefaultrule != vk.nondefaultrule) {
details = tl::sprintf (tl::to_string (tr (" (trying with NONDEFAULTRULE '%s' and without)")), nondefaultrule);
}
error (tl::sprintf (tl::to_string (tr ("Could not find a via specification with name '%s'")) + details, vn));
}
m_via_cells[vk] = cell;

View File

@ -46,6 +46,7 @@ namespace db
class LEFDEFReaderState;
class LEFDEFImporter;
class LEFImporter;
struct MacroDesc;
/**
@ -960,6 +961,25 @@ public:
m_macro_layout_files = lf;
}
/**
* @brief A hidden attribute to enable a LEF context
* LEF context are used for chaining DEF readers. This method must be
* called on local copy of the importer options. With this attribute
* set to "true", the client code can store a LEFDEFReaderState object
* in this object.
* Initially, this attribute is set to false.
* Note that this attribute is not copied.
*/
void set_lef_context_enabled (bool context);
bool lef_context_enabled () const
{
return m_lef_context_enabled;
}
// makes the reader state object if required
db::LEFDEFReaderState *reader_state (db::Layout &layout, const std::string &base_path, const LoadLayoutOptions &options) const;
private:
bool m_read_all_layers;
db::LayerMap m_layer_map;
@ -1028,6 +1048,8 @@ private:
tl::weak_collection<db::Layout> m_macro_layouts;
std::vector<std::string> m_macro_layout_files;
bool m_paths_relative_to_cwd;
bool m_lef_context_enabled;
mutable std::unique_ptr<db::LEFDEFReaderState> mp_reader_state;
};
/**
@ -1119,12 +1141,14 @@ public:
class DB_PLUGIN_PUBLIC LEFDEFLayoutGenerator
{
public:
LEFDEFLayoutGenerator () { }
LEFDEFLayoutGenerator () : def_local (false) { }
virtual ~LEFDEFLayoutGenerator () { }
virtual void create_cell (LEFDEFReaderState &reader, db::Layout &layout, db::Cell &cell, const std::vector<std::string> *maskshift_layers, const std::vector<unsigned int> &masks, const LEFDEFNumberOfMasks *nm) = 0;
virtual std::vector<std::string> maskshift_layers () const = 0;
virtual bool is_fixedmask () const = 0;
bool def_local;
};
/**
@ -1247,13 +1271,18 @@ public:
/**
* @brief Constructor
*/
LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout, const std::string &base_path = std::string ());
LEFDEFReaderState (const LEFDEFReaderOptions *tc);
/**
* @brief Destructor
*/
~LEFDEFReaderState ();
/**
* @brief Initialize with the layout and base path
*/
void init (db::Layout &layout, const std::string &base_path, const LoadLayoutOptions &options);
/**
* @brief Attaches to or detaches from an importer
*/
@ -1299,8 +1328,15 @@ public:
*/
void register_layer (const std::string &l);
/**
* @brief Start reading a file
* After the file is read, "finish" needs to be called.
*/
void start ();
/**
* @brief Finish, i.e. assign GDS layer numbers to the layers
* This is the counterpart for "start".
*/
void finish (db::Layout &layout);
@ -1364,6 +1400,44 @@ public:
*/
void warn (const std::string &msg, int warn_level = 1);
/**
* @brief Ensures the LEF importer for DEF reading is available
*/
void ensure_lef_importer (int warn_level);
/**
* @brief Gets the LEF importer for DEF reading
*/
db::LEFImporter &lef_importer ();
/**
* @brief Reads a LEF file into the LEF importer
*
* Multiple LEF files can be read.
*/
void read_lef (const std::string &fn, db::Layout &layout);
/**
* @brief Provided for test purposes
*/
void finish_lef (db::Layout &layout);
/**
* @brief Gets a value indicating whether the given LEF file was already read
*/
bool lef_file_already_read (const std::string &fn)
{
return m_lef_files_read.find (fn) != m_lef_files_read.end ();
}
/**
* @brief Gets the stored macro layouts
*/
const std::vector<db::Layout *> &macro_layouts () const
{
return m_macro_layouts;
}
protected:
virtual void common_reader_error (const std::string &msg) { error (msg); }
virtual void common_reader_warn (const std::string &msg, int warn_level) { warn (msg, warn_level); }
@ -1452,14 +1526,19 @@ private:
std::map<std::string, int> m_default_number;
const LEFDEFReaderOptions *mp_tech_comp;
std::map<ViaKey, db::Cell *> m_via_cells;
std::map<std::pair<std::string, std::string>, LEFDEFLayoutGenerator *> m_via_generators;
std::multimap<std::pair<std::string, std::string>, LEFDEFLayoutGenerator *> m_via_generators;
std::map<MacroKey, std::pair<db::Cell *, db::Trans> > m_macro_cells;
std::map<std::string, LEFDEFLayoutGenerator *> m_macro_generators;
std::map<std::string, db::cell_index_type> m_foreign_cells;
std::set<std::string> m_lef_files_read;
std::vector<db::Layout *> m_macro_layouts;
tl::shared_collection<db::Layout> m_macro_layout_object_holder;
std::unique_ptr<db::LEFImporter> mp_lef_importer;
std::set<unsigned int> open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask);
db::cell_index_type foreign_cell(Layout &layout, const std::string &name);
void read_single_map_file (const std::string &path, std::map<std::pair<std::string, LayerDetailsKey>, std::vector<db::LayerProperties> > &layer_map);
std::pair<LEFDEFLayoutGenerator *, std::string> via_generator_and_rule (const std::string &vn, const std::string &nondefaultrule);
};
/**

View File

@ -113,23 +113,39 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti
init (options);
const db::LEFDEFReaderOptions *lefdef_options = dynamic_cast<const db::LEFDEFReaderOptions *> (options.get_options (format ()));
db::LEFDEFReaderOptions effective_options;
if (lefdef_options) {
effective_options = *lefdef_options;
}
layout.dbu (effective_options.dbu ());
std::string base_path;
if (! effective_options.paths_relative_to_cwd ()) {
base_path = tl::dirname (m_stream.absolute_file_path ());
}
db::LEFDEFReaderState state (&effective_options, layout, base_path);
// If the LEF reader context (LEF caching) is enabled on the options,
// pull the state from there, otherwise create a local state.
db::LEFDEFReaderState local_state (&effective_options);
db::LEFDEFReaderState *state = 0;
if (lefdef_options) {
state = lefdef_options->reader_state (layout, base_path, options);
}
if (! state) {
local_state.init (layout, base_path, options);
state = &local_state;
}
state->ensure_lef_importer (warn_level ());
state->start ();
// Configure the conflict resolution mode
db::CommonReaderOptions common_options = options.get_options<db::CommonReaderOptions> ();
state.set_conflict_resolution_mode (common_options.cell_conflict_resolution);
layout.dbu (effective_options.dbu ());
state->set_conflict_resolution_mode (common_options.cell_conflict_resolution);
// Import LEF
if (import_lef) {
// Always produce LEF geometry when reading LEF
@ -145,13 +161,13 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti
for (auto lp = paths.begin (); lp != paths.end (); ++lp) {
tl::InputStream lef_stream (*lp);
tl::log << tl::to_string (tr ("Reading")) << " " << *lp;
importer.read (lef_stream, layout, state);
importer.read (lef_stream, layout, *state);
}
}
tl::log << tl::to_string (tr ("Reading")) << " " << m_stream.source ();
importer.read (m_stream, layout, state);
importer.read (m_stream, layout, *state);
importer.finish_lef (layout);
@ -161,20 +177,18 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti
DEFImporter importer (warn_level ());
std::set<std::string> lef_files_read;
for (std::vector<std::string>::const_iterator l = effective_options.begin_lef_files (); l != effective_options.end_lef_files (); ++l) {
auto paths = correct_path (*l, layout, base_path, true);
for (auto lp = paths.begin (); lp != paths.end (); ++lp) {
if (lef_files_read.insert (tl::normalize_path (*lp)).second) {
std::string norm_lp = tl::normalize_path (*lp);
if (! state->lef_file_already_read (norm_lp)) {
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file: ")) + *lp);
tl::InputStream lef_stream (*lp);
tl::log << tl::to_string (tr ("Reading")) << " " << *lp;
importer.read_lef (lef_stream, layout, state);
state->read_lef (norm_lp, layout);
}
@ -198,13 +212,13 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti
std::string lp = tl::combine_path (input_dir, *e);
// skip if already read (issue-1724)
if (lef_files_read.find (tl::normalize_path (lp)) == lef_files_read.end ()) {
std::string norm_lp = tl::normalize_path (lp);
if (! state->lef_file_already_read (norm_lp)) {
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file: ")) + lp);
tl::InputStream lef_stream (lp);
tl::log << tl::to_string (tr ("Reading")) << " " << lp;
importer.read_lef (lef_stream, layout, state);
state->read_lef (norm_lp, layout);
}
@ -217,78 +231,13 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti
}
tl::log << tl::to_string (tr ("Reading")) << " " << m_stream.source ();
importer.read (m_stream, layout, state);
// Resolve unresolved COMPONENT cells
std::map<std::string, db::cell_index_type> foreign_cells = state.foreign_cells ();
db::cell_index_type seen = std::numeric_limits<db::cell_index_type>::max ();
std::vector<db::Layout *> macro_layouts = effective_options.macro_layouts ();
// Additionally read the layouts from the given paths
tl::shared_collection<db::Layout> macro_layout_object_holder;
for (std::vector<std::string>::const_iterator l = effective_options.begin_macro_layout_files (); l != effective_options.end_macro_layout_files (); ++l) {
auto paths = correct_path (*l, layout, base_path, true);
for (auto lp = paths.begin (); lp != paths.end (); ++lp) {
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF macro layout file: ")) + *lp);
tl::InputStream macro_layout_stream (*lp);
tl::log << tl::to_string (tr ("Reading")) << " " << *lp;
db::Layout *new_layout = new db::Layout (false);
macro_layout_object_holder.push_back (new_layout);
macro_layouts.push_back (new_layout);
db::Reader reader (macro_layout_stream);
reader.read (*new_layout, options);
if (fabs (new_layout->dbu () / layout.dbu () - 1.0) > db::epsilon) {
importer.warn (tl::sprintf (tl::to_string (tr ("DBU of macro layout file '%s' does not match reader DBU (layout DBU is %.12g, reader DBU is set to %.12g)")),
*lp, new_layout->dbu (), layout.dbu ()));
}
}
}
for (std::vector<db::Layout *>::const_iterator m = macro_layouts.begin (); m != macro_layouts.end (); ++m) {
std::vector<db::cell_index_type> target_cells, source_cells;
// collect the cells to pull in
for (std::map<std::string, db::cell_index_type>::iterator f = foreign_cells.begin (); f != foreign_cells.end (); ++f) {
if (f->second != seen) {
std::pair<bool, db::cell_index_type> cp = (*m)->cell_by_name (f->first.c_str ());
if (cp.first) {
target_cells.push_back (f->second);
source_cells.push_back (cp.second);
layout.cell (f->second).set_ghost_cell (false);
f->second = seen;
}
}
}
db::CellMapping cm;
cm.create_multi_mapping_full (layout, target_cells, **m, source_cells);
layout.copy_tree_shapes (**m, cm);
}
// Warn about cells that could not be resolved
for (std::map<std::string, db::cell_index_type>::iterator f = foreign_cells.begin (); f != foreign_cells.end (); ++f) {
if (f->second != seen && layout.cell (f->second).is_ghost_cell ()) {
importer.warn (tl::sprintf (tl::to_string (tr ("Could not find a substitution layout for foreign cell '%s'")),
f->first));
}
}
importer.read (m_stream, layout, *state);
}
state.finish (layout);
state->finish (layout);
m_layer_map = state.layer_map ();
m_layer_map = state->layer_map ();
return m_layer_map;
}

View File

@ -122,7 +122,7 @@ public:
}
/**
* @brief Gets the
* @brief Gets the macros map
*
* The map maps the macro name to the macro description.
*/
@ -131,6 +131,14 @@ public:
return m_macros;
}
/**
* @brief Inserts a macro description for a name
*/
const MacroDesc *insert_macro (const std::string &mn, const MacroDesc &m)
{
return &m_macros.insert (std::make_pair (mn, m)).first->second;
}
/**
* @brief Finishes reading a LEF file
*

View File

@ -997,6 +997,10 @@ gsi::Class<db::LEFDEFReaderOptions> decl_lefdef_config ("db", "LEFDEFReaderConfi
"See \\read_lef_with_def for details about this property.\n"
"\n"
"This property has been added in version 0.27.\n"
) +
// special attribute to implement LEF caching
gsi::method ("lef_context_enabled=", &db::LEFDEFReaderOptions::set_lef_context_enabled,
"@hide\n"
),
"@brief Detailed LEF/DEF reader options\n"
"This class is a aggregate belonging to the \\LoadLayoutOptions class. It provides options for the LEF/DEF reader. "

View File

@ -25,6 +25,7 @@
#include "dbWriter.h"
#include "dbDEFImporter.h"
#include "dbLEFImporter.h"
#include "dbCommonReader.h"
#include "tlUnitTest.h"
#include "dbTestSupport.h"
@ -59,10 +60,13 @@ static db::LayerMap read (db::Layout &layout, const char *lef_dir, const char *f
tl::Extractor ex (filename);
db::LEFDEFReaderState ld (&options, layout, fn_path);
db::LoadLayoutOptions other_options;
db::LEFDEFReaderState ld (&options);
ld.ensure_lef_importer (1);
ld.init (layout, fn_path, other_options);
ld.set_conflict_resolution_mode (cc_mode);
db::DEFImporter imp;
db::DEFImporter imp (1);
bool any_def = false;
bool any_lef = false;
@ -92,8 +96,7 @@ static db::LayerMap read (db::Layout &layout, const char *lef_dir, const char *f
ex.read_word_or_quoted (f);
fn += f;
tl::InputStream stream (fn);
imp.read_lef (stream, layout, ld);
ld.read_lef (fn, layout);
any_lef = true;
@ -134,7 +137,7 @@ static db::LayerMap read (db::Layout &layout, const char *lef_dir, const char *f
}
if (! any_def && any_lef) {
imp.finish_lef (layout);
ld.finish_lef (layout);
}
ld.finish (layout);
@ -518,6 +521,9 @@ TEST(109_foreigncell)
options.set_macro_resolution_mode (2);
run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in.lef+def:in.def", "au_always_foreign.oas.gz", options, false);
// no macros -> warning
run_test (_this, "foreigncell", "gds:macros.gds+lef:in_tech.lef+def:in.def", "au_no_macros.oas.gz", options, false);
}
TEST(110_lefpins)
@ -895,6 +901,21 @@ TEST(132_issue1307_pin_names)
run_test (_this, "issue-1307c", "lef:in.lef+def:in.def", "au.oas", opt, false);
}
/*
TODO: need to clarify first, if invalid via specs should be errors
TEST(133_unknown_vias_are_errors)
{
db::LEFDEFReaderOptions opt = default_options ();
try {
run_test (_this, "invalid_via", "lef:tech.lef+def:comp_invalid_via.def", "au.oas", opt, false);
EXPECT_EQ (true, false);
} catch (db::LEFDEFReaderException &ex) {
EXPECT_EQ (ex.msg ().find ("Invalid via name"), size_t (0));
}
}
*/
TEST(200_lefdef_plugin)
{
db::Layout ly;
@ -1100,3 +1121,35 @@ TEST(214_issue1877)
db::compare_layouts (_this, ly, fn_path + "au.oas", db::WriteOAS);
}
// multi-DEF reader support (issue-2014)
TEST(215_multiDEF)
{
std::string fn_path (tl::testdata ());
fn_path += "/lefdef/multi_def/";
db::Layout ly;
db::LoadLayoutOptions opt;
// anything else will not make much sense
opt.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::CellConflictResolution::RenameCell;
// Test "set_option_by_name"
opt.set_option_by_name ("lefdef_config.lef_context_enabled", true);
opt.set_option_by_name ("lefdef_config.map_file", "layers.map");
opt.set_option_by_name ("lefdef_config.read_lef_with_def", true);
const char *files[] = {
"main.def",
"comp_a.def",
"comp_b.def",
"comp_c.def"
};
for (const char **fn = files; fn != files + sizeof (files) / sizeof (files[0]); ++fn) {
tl::InputStream is (fn_path + *fn);
db::Reader reader (is);
reader.read (ly, opt);
}
db::compare_layouts (_this, ly, fn_path + "au.oas", db::WriteOAS);
}

Binary file not shown.

BIN
testdata/lefdef/foreigncell/macros.gds vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,16 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN comp_invalid_via ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 10000 2000 ) ;
SPECIALNETS 2 ;
- VGND ( PIN VGND ) ( * VNB ) ( * VGND ) + USE GROUND
+ ROUTED met1 480 + SHAPE FOLLOWPIN ( 0 1000 ) ( 2000 1000 )
NEW met1 0 + SHAPE STRIPE ( 2000 1000 ) via1
+ ROUTED met2 480 + SHAPE FOLLOWPIN ( 2000 1000 ) ( 4000 1000 )
NEW met2 0 + SHAPE STRIPE ( 4000 1000 ) invalid_via ;
END SPECIALNETS
END DESIGN

89
testdata/lefdef/invalid_via/tech.lef vendored Normal file
View File

@ -0,0 +1,89 @@
VERSION 5.7 ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
USEMINSPACING OBS OFF ;
UNITS
DATABASE MICRONS 1000 ;
END UNITS
MANUFACTURINGGRID 0.005 ;
LAYER met1
TYPE ROUTING ;
DIRECTION HORIZONTAL ;
PITCH 0.34 ;
OFFSET 0.17 ;
WIDTH 0.14 ;
END met1
LAYER via
TYPE CUT ;
WIDTH 0.15 ;
SPACING 0.17 ;
END via
LAYER met2
TYPE ROUTING ;
DIRECTION VERTICAL ;
PITCH 0.46 ;
OFFSET 0.23 ;
WIDTH 0.14 ;
END met2
LAYER via2
TYPE CUT ;
WIDTH 0.2 ;
SPACING 0.2 ;
END via2
LAYER met3
TYPE ROUTING ;
DIRECTION HORIZONTAL ;
PITCH 0.68 ;
OFFSET 0.34 ;
WIDTH 0.3 ;
END met3
VIA via1 DEFAULT
LAYER via ;
RECT -0.075 -0.075 0.075 0.075 ;
LAYER met1 ;
RECT -0.16 -0.24 0.16 0.24 ;
LAYER met2 ;
RECT -0.13 -0.24 0.13 0.24 ;
END via1
VIARULE M1M2_PR GENERATE
LAYER met1 ;
ENCLOSURE 0.085 0.055 ;
LAYER met2 ;
ENCLOSURE 0.055 0.085 ;
LAYER via ;
RECT -0.075 -0.075 0.075 0.075 ;
SPACING 0.32 BY 0.32 ;
END M1M2_PR
VIA via2 DEFAULT
LAYER via2 ;
RECT -0.1 -0.1 0.1 0.1 ;
LAYER met2 ;
RECT -0.14 -0.24 0.14 0.24 ;
LAYER met3 ;
RECT -0.165 -0.165 0.165 0.165 ;
END via2
VIARULE M2M3_PR GENERATE
LAYER met2 ;
ENCLOSURE 0.04 0.085 ;
LAYER met3 ;
ENCLOSURE 0.065 0.065 ;
LAYER via2 ;
RECT -0.1 -0.1 0.1 0.1 ;
SPACING 0.4 BY 0.4 ;
END M2M3_PR
END LIBRARY

BIN
testdata/lefdef/multi_def/au.oas vendored Normal file

Binary file not shown.

20
testdata/lefdef/multi_def/comp_a.def vendored Normal file
View File

@ -0,0 +1,20 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN comp_a ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 10000 2000 ) ;
VIAS 2 ;
- via1 + VIARULE M1M2_PR + CUTSIZE 150 150 + LAYERS met1 via met2 + CUTSPACING 170 170 + ENCLOSURE 85 165 55 85 + ROWCOL 2 2 ;
- via2 + VIARULE M2M3_PR + CUTSIZE 200 200 + LAYERS met2 via2 met3 + CUTSPACING 200 200 + ENCLOSURE 40 85 65 65 + ROWCOL 3 3 ;
END VIAS
SPECIALNETS 2 ;
- VGND ( PIN VGND ) ( * VNB ) ( * VGND ) + USE GROUND
+ ROUTED met1 480 + SHAPE FOLLOWPIN ( 0 1000 ) ( 2000 1000 )
NEW met1 0 + SHAPE STRIPE ( 2000 1000 ) via1
+ ROUTED met2 480 + SHAPE FOLLOWPIN ( 2000 1000 ) ( 4000 1000 )
NEW met2 0 + SHAPE STRIPE ( 4000 1000 ) via2 ;
END SPECIALNETS
END DESIGN

12
testdata/lefdef/multi_def/comp_a.lef vendored Normal file
View File

@ -0,0 +1,12 @@
VERSION 5.7 ;
NOWIREEXTENSIONATPIN ON ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
MACRO comp_a
CLASS BLOCK ;
FOREIGN comp_a ;
ORIGIN 0.000 0.000 ;
SIZE 10000.000 BY 2000.000 ;
END comp_a
END LIBRARY

20
testdata/lefdef/multi_def/comp_b.def vendored Normal file
View File

@ -0,0 +1,20 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN comp_b ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 10000 2000 ) ;
VIAS 2 ;
- via1 + VIARULE M1M2_PR + CUTSIZE 150 150 + LAYERS met1 via met2 + CUTSPACING 170 170 + ENCLOSURE 85 165 55 85 + ROWCOL 2 1 ;
- via2 + VIARULE M2M3_PR + CUTSIZE 200 200 + LAYERS met2 via2 met3 + CUTSPACING 200 200 + ENCLOSURE 40 85 65 65 + ROWCOL 3 2 ;
END VIAS
SPECIALNETS 2 ;
- VGND ( PIN VGND ) ( * VNB ) ( * VGND ) + USE GROUND
+ ROUTED met1 480 + SHAPE FOLLOWPIN ( 0 1000 ) ( 2000 1000 )
NEW met1 0 + SHAPE STRIPE ( 2000 1000 ) via1
+ ROUTED met2 480 + SHAPE FOLLOWPIN ( 2000 1000 ) ( 4000 1000 )
NEW met2 0 + SHAPE STRIPE ( 4000 1000 ) via2 ;
END SPECIALNETS
END DESIGN

12
testdata/lefdef/multi_def/comp_b.lef vendored Normal file
View File

@ -0,0 +1,12 @@
VERSION 5.7 ;
NOWIREEXTENSIONATPIN ON ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
MACRO comp_b
CLASS BLOCK ;
FOREIGN comp_b ;
ORIGIN 0.000 0.000 ;
SIZE 10000.000 BY 2000.000 ;
END comp_b
END LIBRARY

16
testdata/lefdef/multi_def/comp_c.def vendored Normal file
View File

@ -0,0 +1,16 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN comp_c ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 10000 2000 ) ;
SPECIALNETS 2 ;
- VGND ( PIN VGND ) ( * VNB ) ( * VGND ) + USE GROUND
+ ROUTED met1 480 + SHAPE FOLLOWPIN ( 0 1000 ) ( 2000 1000 )
NEW met1 0 + SHAPE STRIPE ( 2000 1000 ) via1
+ ROUTED met2 480 + SHAPE FOLLOWPIN ( 2000 1000 ) ( 4000 1000 )
NEW met2 0 + SHAPE STRIPE ( 4000 1000 ) via2 ;
END SPECIALNETS
END DESIGN

12
testdata/lefdef/multi_def/comp_c.lef vendored Normal file
View File

@ -0,0 +1,12 @@
VERSION 5.7 ;
NOWIREEXTENSIONATPIN ON ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
MACRO comp_c
CLASS BLOCK ;
FOREIGN comp_c ;
ORIGIN 0.000 0.000 ;
SIZE 10000.000 BY 2000.000 ;
END comp_c
END LIBRARY

7
testdata/lefdef/multi_def/layers.map vendored Normal file
View File

@ -0,0 +1,7 @@
met1 VIA,LEFPIN,PIN,SPNET,NET 1 0
via VIA,LEFPIN,PIN,SPNET,NET 2 0
met2 VIA,LEFPIN,PIN,SPNET,NET 3 0
via2 VIA,LEFPIN,PIN,SPNET,NET 4 0
met3 VIA,LEFPIN,PIN,SPNET,NET 5 0
DIEAREA ALL 100 0

13
testdata/lefdef/multi_def/main.def vendored Normal file
View File

@ -0,0 +1,13 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN caravel ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 10000 10000 ) ;
COMPONENTS 4 ;
- comp_a comp_a + PLACED ( 0 0 ) N ;
- comp_b comp_b + PLACED ( 0 2000 ) N ;
- comp_c comp_c + PLACED ( 0 4000 ) N ;
#- comp_d comp_d + PLACED ( 0 4000 ) N ;
END COMPONENTS
END DESIGN

BIN
testdata/lefdef/multi_def/out.oas vendored Normal file

Binary file not shown.

89
testdata/lefdef/multi_def/tech.lef vendored Normal file
View File

@ -0,0 +1,89 @@
VERSION 5.7 ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
USEMINSPACING OBS OFF ;
UNITS
DATABASE MICRONS 1000 ;
END UNITS
MANUFACTURINGGRID 0.005 ;
LAYER met1
TYPE ROUTING ;
DIRECTION HORIZONTAL ;
PITCH 0.34 ;
OFFSET 0.17 ;
WIDTH 0.14 ;
END met1
LAYER via
TYPE CUT ;
WIDTH 0.15 ;
SPACING 0.17 ;
END via
LAYER met2
TYPE ROUTING ;
DIRECTION VERTICAL ;
PITCH 0.46 ;
OFFSET 0.23 ;
WIDTH 0.14 ;
END met2
LAYER via2
TYPE CUT ;
WIDTH 0.2 ;
SPACING 0.2 ;
END via2
LAYER met3
TYPE ROUTING ;
DIRECTION HORIZONTAL ;
PITCH 0.68 ;
OFFSET 0.34 ;
WIDTH 0.3 ;
END met3
VIA via1 DEFAULT
LAYER via ;
RECT -0.075 -0.075 0.075 0.075 ;
LAYER met1 ;
RECT -0.16 -0.24 0.16 0.24 ;
LAYER met2 ;
RECT -0.13 -0.24 0.13 0.24 ;
END via1
VIARULE M1M2_PR GENERATE
LAYER met1 ;
ENCLOSURE 0.085 0.055 ;
LAYER met2 ;
ENCLOSURE 0.055 0.085 ;
LAYER via ;
RECT -0.075 -0.075 0.075 0.075 ;
SPACING 0.32 BY 0.32 ;
END M1M2_PR
VIA via2 DEFAULT
LAYER via2 ;
RECT -0.1 -0.1 0.1 0.1 ;
LAYER met2 ;
RECT -0.14 -0.24 0.14 0.24 ;
LAYER met3 ;
RECT -0.165 -0.165 0.165 0.165 ;
END via2
VIARULE M2M3_PR GENERATE
LAYER met2 ;
ENCLOSURE 0.04 0.085 ;
LAYER met3 ;
ENCLOSURE 0.065 0.065 ;
LAYER via2 ;
RECT -0.1 -0.1 0.1 0.1 ;
SPACING 0.4 BY 0.4 ;
END M2M3_PR
END LIBRARY