/* * COPYRIGHT * * cschem - modular/flexible schematics editor - lib: compile helpers * Copyright (C) 2022 Tibor 'Igor2' Palinkas * * (Supported by NLnet NGI0 PET Fund in 2022) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version.* * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 31 Milk Street, # 960789 Boston, MA 02196 USA * * Contact: * Project page: http://repo.hu/projects/sch-rnd * contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html * mailing list: http://www.repo.hu/projects/sch-rnd/contact.html */ #include "config.h" #include #include #include "abstract.h" #include "compile.h" #include "libcschem.h" #include "engine.h" #include "actions_csch.h" #include "util_compile.h" csch_anet_t *csch_cmp_merge_nets(csch_anet_t *n1, csch_anet_t *n2) { csch_anet_t *src, *dst; long n, i; if (n1 == n2) return n1; /* dst should be the one without user chosen name */ if (!n1->no_uname && !n2->no_uname) { csch_anet_t *top, *bottom; if (n1->hdepth == n2->hdepth) { rnd_message(RND_MSG_ERROR, "csch_cmp_merge_nets(): different networks '%s' and '%s' can not be connected\n", n1->name, n2->name); return NULL; } if (CSCH_CFG(hier_net_allow_rename, 0) == 0) { rnd_message(RND_MSG_ERROR, "csch_cmp_merge_nets(): the same network is explicitly named differently between hierarchi levels: '%s' and '%s'\n", n1->name, n2->name); return NULL; } if (n1->hdepth < n2->hdepth) { top = n1; bottom = n2; } else { top = n2; bottom = n1; } if (CSCH_CFG(hier_net_rename_prefer_top, 1) != 0) { dst = top; src = bottom; } else { dst = bottom; src = top; } } else if (!n1->no_uname) { dst = n1; src = n2; } else { dst = n2; src = n1; } /* switch over the concrete->abstract pointers on src net so src concrete objects know they belong to dst net now */ for(n = 0; n < src->hdr.srcs.used; n++) { csch_cgrp_t *cgrp = src->hdr.srcs.array[n]; long i; if (!csch_obj_is_grp(&cgrp->hdr)) continue; for(i = 0; i < cgrp->aid.used; i++) if (cgrp->aid.array[i] == src->hdr.aid) cgrp->aid.array[i] = dst->hdr.aid; } for(n = 0; n < src->conns.used; n++) { csch_aport_t *ap = (csch_aport_t *)src->conns.array[n]; if (ap->hdr.type == CSCH_ATYPE_PORT) ap->conn.net = NULL; /* disconnect from src */ csch_compile_connect_net_to(&dst, &ap->hdr, 1); } src->conns.used = 0; /* copy/merge all attributes */ csch_attrib_copy_all_undoable(NULL, NULL, &dst->hdr.attr, &src->hdr.attr, 0); /* copy all sources from src to dst */ for(n = 0; n < src->hdr.srcs.used; n++) csch_compile_add_source(src->hdr.srcs.array[n], &dst->hdr); /* remove sources from the source net which should become empty */ for(n = 0; n < src->hdr.srcs.used; n++) { csch_cgrp_t *obj = src->hdr.srcs.array[n]; for(i = 0; i < obj->aid.used; i++) { if (obj->aid.array[i] == src->hdr.aid) { vtl0_remove(&obj->aid, i, 1); break; } } } src->hdr.srcs.used = 0; src->hdr.ghost = "csch_cmp_merge_nets()"; return dst; } int csch_cmp_nameconn_port_net(csch_project_t *project, csch_acomp_t *comp, const char *portname, const char *netname, int require_conn, int view_id, csch_hier_path_t *hpath) { csch_aport_t *port = csch_aport_get(comp->hdr.abst, comp, portname, 1); csch_anet_t *net; /* net from the argument */ csch_ascope_t scope; char *name_glob, *name_loc; if (port == NULL) { rnd_message(RND_MSG_ERROR, "Component '%s' doesn't contain port named '%s'\n", comp->name, portname); return -1; } scope = csch_split_name_scope(&netname); /* Translate name, including hierarchical address prefixes */ csch_eng_call_namemod(project, view_id, hpath, CSCH_ENGHK_ATTRIB_NET_NAME_TO_NET_NAME, &name_glob, &name_loc, netname, FGW_AOBJ, comp, FGW_INVALID); net = csch_anet_get_at(comp->hdr.abst, comp->hlev, scope, name_loc); if (net == NULL) net = csch_anet_new(comp->hdr.abst, comp->hlev, scope, name_glob, name_loc, 0); csch_eng_free_namemod(&name_glob, &name_loc); if (net == NULL) { rnd_message(RND_MSG_ERROR, "Netname '%s' does not exist\n", netname); return -1; } if (port->conn.net == NULL) { TODO("TODO#rgc: drc/require_graphical_conn should be checked in drc"); /* TODO: cases to check: - place resistor, add conn array 4:foo; this should connect a 4th port of the resistor to network foo, with no error; csch_compile_connect_net_to() below does that properly; require_conn=0 case - place an unconnected gnd symbol; it has an 1:GND which would do the same, but with an extra drc attribute on the port this should rather throw an error; require_conn=1 case */ csch_compile_connect_net_to(&net, &port->hdr, 1); if (require_conn) { csch_attrib_t *a = csch_attrib_get(&port->hdr.attr, "drc/require_graphical_conn"); if ((a != NULL) && rnd_istrue(a->val)) { rnd_message(RND_MSG_ERROR, "Port '%s-%s' has a non-graphical connection to net %s, but no graphical connection\n", comp->name, portname, netname); return -1; } else return 0; } return 0; } return (csch_cmp_merge_nets(net, port->conn.net) != NULL) ? 0 : -1; }