diff --git a/src/layui/layui/gsiDeclLayNetlistBrowserDialog.cc b/src/layui/layui/gsiDeclLayNetlistBrowserDialog.cc index 31eb0113f..825ae29c2 100644 --- a/src/layui/layui/gsiDeclLayNetlistBrowserDialog.cc +++ b/src/layui/layui/gsiDeclLayNetlistBrowserDialog.cc @@ -136,6 +136,83 @@ static lay::NetlistObjectPath second (const lay::NetlistObjectsPath *pp) return pp->second (); } +namespace { + +struct First +{ + lay::NetlistObjectsPath operator() (const lay::NetlistObjectPath &p) + { + return lay::NetlistObjectsPath::from_first (p); + } +}; + +struct Second +{ + lay::NetlistObjectsPath operator() (const lay::NetlistObjectPath &p) + { + return lay::NetlistObjectsPath::from_second (p); + } +}; + +} + +template +static lay::NetlistObjectsPath from (const lay::NetlistObjectPath &p) +{ + return Which () (p); +} + +template +static lay::NetlistObjectsPath from_net (const db::Net *net) +{ + if (! net) { + return lay::NetlistObjectsPath (); + } + + lay::NetlistObjectPath p; + p.root = net->circuit (); + p.net = net; + return Which () (p); +} + +template +static lay::NetlistObjectsPath from_device (const db::Device *device) +{ + if (! device) { + return lay::NetlistObjectsPath (); + } + + lay::NetlistObjectPath p; + p.root = device->circuit (); + p.device = device; + return Which () (p); +} + +template +static lay::NetlistObjectsPath from_circuit (const db::Circuit *circuit) +{ + if (! circuit) { + return lay::NetlistObjectsPath (); + } + + lay::NetlistObjectPath p; + p.root = circuit; + return Which () (p); +} + +template +static lay::NetlistObjectsPath from_subcircuit (const db::SubCircuit *subcircuit) +{ + if (! subcircuit) { + return lay::NetlistObjectsPath (); + } + + lay::NetlistObjectPath p; + p.root = subcircuit->circuit (); + p.path.push_back (subcircuit); + return Which () (p); +} + Class decl_NetlistObjectsPath ("lay", "NetlistObjectsPath", gsi::method_ext ("first", &first, "@brief Gets the first object's path.\n" @@ -146,6 +223,67 @@ Class decl_NetlistObjectsPath ("lay", "NetlistObjectsPa "@brief Gets the second object's path.\n" "In cases of paired netlists (LVS database), the first path points to the schematic netlist object.\n" "For the single netlist, the second path is always a null path." + ) + + gsi::method ("from_first", &from, gsi::arg ("p"), + "@brief Creates a path from given first coordinates.\n" + "Use this constructor to create a paired path from a first set of coordinates (net, circuit, device).\n" + "For single-sided databases (i.e. extracted netlist or schematic only), use the first coordinates. " + "For two-sided database (i.e. LVS cross references), use the first coordinates when you refer to " + "layout netlist objects.\n" + "\n" + "In this version, the minimum requirement for the path is to have a root.\n" + "\n" + "This constructor has been added in version 0.30.8." + ) + + gsi::method ("from_first", &from_net, gsi::arg ("net"), + "@brief Creates a path from a given net in the first netlist space.\n" + "\n" + "This constructor has been added in version 0.30.8." + ) + + gsi::method ("from_first", &from_device, gsi::arg ("device"), + "@brief Creates a path from a given device in the first netlist space.\n" + "\n" + "This constructor has been added in version 0.30.8." + ) + + gsi::method ("from_first", &from_circuit, gsi::arg ("circuit"), + "@brief Creates a path from a given circuit in the first netlist space.\n" + "\n" + "This constructor has been added in version 0.30.8." + ) + + gsi::method ("from_first", &from_subcircuit, gsi::arg ("subcircuit"), + "@brief Creates a path from a given subcircuit in the first netlist space.\n" + "\n" + "This constructor has been added in version 0.30.8." + ) + + gsi::method ("from_second", &from, gsi::arg ("p"), + "@brief Creates a path from given second coordinates.\n" + "Use this constructor to create a paired path from a second set of coordinates (net, circuit, device).\n" + "For two-sided database (i.e. LVS cross references), use the second coordinates when you refer to " + "schematic netlist objects.\n" + "\n" + "In this version, the minimum requirement for the path is to have a root.\n" + "\n" + "This constructor has been added in version 0.30.8." + ) + + gsi::method ("from_second", &from_net, gsi::arg ("net"), + "@brief Creates a path from a given net in the second netlist space.\n" + "\n" + "This constructor has been added in version 0.30.8." + ) + + gsi::method ("from_second", &from_device, gsi::arg ("device"), + "@brief Creates a path from a given device in the second netlist space.\n" + "\n" + "This constructor has been added in version 0.30.8." + ) + + gsi::method ("from_second", &from_circuit, gsi::arg ("circuit"), + "@brief Creates a path from a given circuit in the second netlist space.\n" + "\n" + "This constructor has been added in version 0.30.8." + ) + + gsi::method ("from_second", &from_subcircuit, gsi::arg ("subcircuit"), + "@brief Creates a path from a given subcircuit in the second netlist space.\n" + "\n" + "This constructor has been added in version 0.30.8." ), "@brief An object describing the instantiation of a single netlist object or a pair of those.\n" "This class is basically a pair of netlist object paths (see \\NetlistObjectPath). When derived from a single netlist view, " @@ -156,7 +294,16 @@ Class decl_NetlistObjectsPath ("lay", "NetlistObjectsPa "If the selected object isn't a matched one, either the first or second path may be a null or a partial path without a final net or device object " "or a partial path.\n" "\n" - "This class has been introduced in version 0.27.\n" + "To create a paired path from an existing object (net, device, circuit, subcircuit), use \\from_first and \\from_second.\n" + "Use \\from_first, if the object belongs to the first netlist of the database ('netlist', layout netlist in the LVS context).\n" + "Use \\from_second, if the object belongs to the second netlist of the database ('reference', schematic netlist in the LVS context).\n" + "\n" + "It is also possible to create a paired path from a full path object (including root, a subcircuit path and a target object), either " + "for the first or second side. Use \\from_first and \\from_second with a \\NetlistObjectPath argument in that case.\n" + "A minimum requirement in that case is to set the root (the origin of the path). If no subcircuit path is " + "given (see \\NetlistObjectPath#path), a suitable path leading from the target object (net or device) to the root will be constructed.\n" + "\n" + "This class has been introduced in version 0.27 and has been extended in version 0.30.8.\n" ); static lay::NetlistObjectPath current_path_first (lay::NetlistBrowserDialog *dialog) @@ -226,6 +373,8 @@ Class decl_NetlistBrowserDialog ("lay", "NetlistBrows "Changing the selection will update the highlights and navigate to the location depending on the " "settings. An \\on_selection_changed signal is not emitted.\n" "\n" + "To get a suitable path, see the \\NetlistObjectsPath#from_first and \\NetlistObjectsPath#from_second generators.\n" + "\n" "This setter has been introduced in version 0.30.8.\n" ) + gsi::method ("selected_paths", &lay::NetlistBrowserDialog::selected_paths, diff --git a/src/layui/layui/layNetlistBrowserPage.cc b/src/layui/layui/layNetlistBrowserPage.cc index 5543c94e4..66259e1cf 100644 --- a/src/layui/layui/layNetlistBrowserPage.cc +++ b/src/layui/layui/layNetlistBrowserPage.cc @@ -514,17 +514,33 @@ NetlistBrowserPage::select_path (const lay::NetlistObjectsPath &path) model = dynamic_cast (nl_directory_tree->model ()); if (model) { - nl_directory_tree->setCurrentIndex (model->index_from_path (path)); + if (lvsdb && lvsdb->cross_ref () && ! path.root.first) { + lay::NetlistObjectsPath nl_path = lay::NetlistObjectsPath::from_first (path.second ()); + // Note: translation helps generating a layout-netlist index to + // naviate to the layout netlist in case of schematic probing for example (only + // works if all path components can be translated) + if (lay::NetlistObjectsPath::translate (nl_path, *lvsdb->cross_ref ())) { + nl_directory_tree->setCurrentIndex (model->index_from_path (nl_path)); + } + } else { + nl_directory_tree->setCurrentIndex (model->index_from_path (path)); + } } model = dynamic_cast (sch_directory_tree->model ()); if (model && lvsdb && lvsdb->cross_ref ()) { - lay::NetlistObjectsPath sch_path = path; - // Note: translation helps generating a schematic-netlist index to - // naviate to the schematic netlist in case of probing for example (only - // works if all path components can be translated) - if (lay::NetlistObjectsPath::translate (sch_path, *lvsdb->cross_ref ())) { + if (! path.root.first) { + // No first path given: use second one for schematic directly. + lay::NetlistObjectsPath sch_path = lay::NetlistObjectsPath::from_first (path.second ()); sch_directory_tree->setCurrentIndex (model->index_from_path (sch_path)); + } else { + lay::NetlistObjectsPath sch_path = path; + // Note: translation helps generating a schematic-netlist index to + // naviate to the schematic netlist in case of probing for example (only + // works if all path components can be translated) + if (lay::NetlistObjectsPath::translate (sch_path, *lvsdb->cross_ref ())) { + sch_directory_tree->setCurrentIndex (model->index_from_path (sch_path)); + } } }