/* XXX: This is copied in large part from AddAllRats above; for * maintainability, AddAllRats probably wants to be tweaked to use this * version of the code so that we don't have duplication. */ NetListListType CollectSubnets (bool SelectedOnly) { NetListListType result = { 0, 0, NULL }; NetListTypePtr Nets, Wantlist; NetTypePtr lonesome; ConnectionTypePtr onepin; /* the netlist library has the text form * ProcNetlist fills in the Netlist * structure the way the final routing * is supposed to look */ Wantlist = ProcNetlist (&PCB->NetlistLib); if (!Wantlist) { Message (_("Can't add rat lines because no netlist is loaded.\n")); return result; } /* initialize finding engine */ InitConnectionLookup (); SaveFindFlag (DRCFLAG); /* now we build another netlist (Nets) for each * net in Wantlist that shows how it actually looks now, * then fill in any missing connections with rat lines. * * we first assume each connection is separate * (no routing), then gather them into groups * if the net is all routed, the new netlist (Nets) * will have only one net entry. * Note that DrawShortestRats consumes all nets * from Nets, so *Nets is empty after the * DrawShortestRats call */ NET_LOOP (Wantlist); { Nets = GetNetListMemory (&result); CONNECTION_LOOP (net); { if (!SelectedOnly || TEST_FLAG (SELECTEDFLAG, (PinTypePtr) connection->ptr2)) { lonesome = GetNetMemory (Nets); onepin = GetConnectionMemory (lonesome); *onepin = *connection; lonesome->Style = net->Style; } } END_LOOP; /* Note that AndRats is *FALSE* here! */ GatherSubnets (Nets, SelectedOnly, false); } END_LOOP; FreeConnectionLookupMemory (); RestoreFindFlag (); return result; }
/* * copy all connections from one net into another * and then remove the first net from its netlist */ static void TransferNet (NetListTypePtr Netl, NetTypePtr SourceNet, NetTypePtr DestNet) { ConnectionTypePtr conn; CONNECTION_LOOP (SourceNet); { conn = GetConnectionMemory (DestNet); *conn = *connection; } END_LOOP; DestNet->Style = SourceNet->Style; /* free the connection memory */ FreeNetMemory (SourceNet); /* remove SourceNet from its netlist */ *SourceNet = Netl->Net[--(Netl->NetN)]; /* zero out old garbage */ memset (&Netl->Net[Netl->NetN], 0, sizeof (NetType)); }
/*! * \brief Copy all connections from one net into another and then remove * the first net from its netlist. */ static void TransferNet (NetListType *Netl, NetType *SourceNet, NetType *DestNet) { ConnectionType *conn; /* It would be worth checking if SourceNet is NULL here to avoid a segfault. Seb James. */ CONNECTION_LOOP (SourceNet); { conn = GetConnectionMemory (DestNet); *conn = *connection; } END_LOOP; DestNet->Style = SourceNet->Style; /* free the connection memory */ FreeNetMemory (SourceNet); /* remove SourceNet from its netlist */ *SourceNet = Netl->Net[--(Netl->NetN)]; /* zero out old garbage */ memset (&Netl->Net[Netl->NetN], 0, sizeof (NetType)); }
/*! * \brief AddAllRats puts the rats nest into the layout from the loaded * netlist. * * If SelectedOnly is true, it will only draw rats to selected pins and * pads. */ bool AddAllRats (bool SelectedOnly, void (*funcp) (register ConnectionType *, register ConnectionType *, register RouteStyleType *)) { NetListType *Nets, *Wantlist; NetType *lonesome; ConnectionType *onepin; bool changed, Warned = false; /* the netlist library has the text form * ProcNetlist fills in the Netlist * structure the way the final routing * is supposed to look */ Wantlist = ProcNetlist (&PCB->NetlistLib); if (!Wantlist) { Message (_("Can't add rat lines because no netlist is loaded.\n")); return (false); } changed = false; /* initialize finding engine */ InitConnectionLookup (); Nets = (NetListType *)calloc (1, sizeof (NetListType)); /* now we build another netlist (Nets) for each * net in Wantlist that shows how it actually looks now, * then fill in any missing connections with rat lines. * * we first assume each connection is separate * (no routing), then gather them into groups * if the net is all routed, the new netlist (Nets) * will have only one net entry. * Note that DrawShortestRats consumes all nets * from Nets, so *Nets is empty after the * DrawShortestRats call */ NET_LOOP (Wantlist); { CONNECTION_LOOP (net); { if (!SelectedOnly || TEST_FLAG (SELECTEDFLAG, (PinType *) connection->ptr2)) { lonesome = GetNetMemory (Nets); onepin = GetConnectionMemory (lonesome); *onepin = *connection; lonesome->Style = net->Style; } } END_LOOP; Warned |= GatherSubnets (Nets, SelectedOnly, true); if (Nets->NetN > 0) changed |= DrawShortestRats (Nets, funcp); } END_LOOP; FreeNetListMemory (Nets); free (Nets); FreeConnectionLookupMemory (); if (funcp) return (true); if (Warned || changed) Draw (); if (Warned) Settings.RatWarn = true; if (changed) { IncrementUndoSerialNumber (); if (PCB->Data->RatN > 0) { Message ("%d rat line%s remaining\n", PCB->Data->RatN, PCB->Data->RatN > 1 ? "s" : ""); } return (true); } if (!SelectedOnly && !Warned) { if (!PCB->Data->RatN && !badnet) Message (_("Congratulations!!\n" "The layout is complete and has no shorted nets.\n")); else Message (_("Nothing more to add, but there are\n" "either rat-lines in the layout, disabled nets\n" "in the net-list, or missing components\n")); } return (false); }
/*! * \brief Determine existing interconnections of the net and gather into * sub-nets. * * Initially the netlist has each connection in its own individual net * afterwards there can be many fewer nets with multiple connections * each. */ static bool GatherSubnets (NetListType *Netl, bool NoWarn, bool AndRats) { NetType *a, *b; ConnectionType *conn; Cardinal m, n; bool Warned = false; for (m = 0; Netl->NetN > 0 && m < Netl->NetN; m++) { a = &Netl->Net[m]; ClearFlagOnAllObjects (false, DRCFLAG); RatFindHook (a->Connection[0].type, a->Connection[0].ptr1, a->Connection[0].ptr2, a->Connection[0].ptr2, false, DRCFLAG, AndRats); /* now anybody connected to the first point has DRCFLAG set */ /* so move those to this subnet */ CLEAR_FLAG (DRCFLAG, (PinType *) a->Connection[0].ptr2); for (n = m + 1; n < Netl->NetN; n++) { b = &Netl->Net[n]; /* There can be only one connection in net b */ if (TEST_FLAG (DRCFLAG, (PinType *) b->Connection[0].ptr2)) { CLEAR_FLAG (DRCFLAG, (PinType *) b->Connection[0].ptr2); TransferNet (Netl, b, a); /* back up since new subnet is now at old index */ n--; } } /* now add other possible attachment points to the subnet */ /* e.g. line end-points and vias */ /* don't add non-manhattan lines, the auto-router can't route to them */ ALLLINE_LOOP (PCB->Data); { if (TEST_FLAG (DRCFLAG, line)) { conn = GetConnectionMemory (a); conn->X = line->Point1.X; conn->Y = line->Point1.Y; conn->type = LINE_TYPE; conn->ptr1 = layer; conn->ptr2 = line; conn->group = GetLayerGroupNumberByPointer (layer); conn->menu = NULL; /* agnostic view of where it belongs */ conn = GetConnectionMemory (a); conn->X = line->Point2.X; conn->Y = line->Point2.Y; conn->type = LINE_TYPE; conn->ptr1 = layer; conn->ptr2 = line; conn->group = GetLayerGroupNumberByPointer (layer); conn->menu = NULL; } } ENDALL_LOOP; /* add polygons so the auto-router can see them as targets */ ALLPOLYGON_LOOP (PCB->Data); { if (TEST_FLAG (DRCFLAG, polygon)) { conn = GetConnectionMemory (a); /* make point on a vertex */ conn->X = polygon->Clipped->contours->head.point[0]; conn->Y = polygon->Clipped->contours->head.point[1]; conn->type = POLYGON_TYPE; conn->ptr1 = layer; conn->ptr2 = polygon; conn->group = GetLayerGroupNumberByPointer (layer); conn->menu = NULL; /* agnostic view of where it belongs */ } } ENDALL_LOOP; VIA_LOOP (PCB->Data); { if (TEST_FLAG (DRCFLAG, via)) { conn = GetConnectionMemory (a); conn->X = via->X; conn->Y = via->Y; conn->type = VIA_TYPE; conn->ptr1 = via; conn->ptr2 = via; conn->group = bottom_group; } } END_LOOP; if (!NoWarn) Warned |= CheckShorts (a->Connection[0].menu); } ClearFlagOnAllObjects (false, DRCFLAG); return (Warned); }
/*! * \brief Read the library-netlist build a true Netlist structure. */ NetListType * ProcNetlist (LibraryType *net_menu) { ConnectionType *connection; ConnectionType LastPoint; NetType *net; static NetListType *Wantlist = NULL; if (!net_menu->MenuN) return (NULL); FreeNetListMemory (Wantlist); free (Wantlist); badnet = false; /* find layer groups of the component side and solder side */ bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE); top_group = GetLayerGroupNumberBySide (TOP_SIDE); Wantlist = (NetListType *)calloc (1, sizeof (NetListType)); if (Wantlist) { ALLPIN_LOOP (PCB->Data); { pin->Spare = NULL; CLEAR_FLAG (DRCFLAG, pin); } ENDALL_LOOP; ALLPAD_LOOP (PCB->Data); { pad->Spare = NULL; CLEAR_FLAG (DRCFLAG, pad); } ENDALL_LOOP; MENU_LOOP (net_menu); { if (menu->Name[0] == '*' || menu->flag == 0) { badnet = true; continue; } net = GetNetMemory (Wantlist); if (menu->Style) { STYLE_LOOP (PCB); { if (style->Name && !NSTRCMP (style->Name, menu->Style)) { net->Style = style; break; } } END_LOOP; } else /* default to NULL if none found */ net->Style = NULL; ENTRY_LOOP (menu); { if (SeekPad (entry, &LastPoint, false)) { if (TEST_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2)) Message (_ ("Error! Element %s pin %s appears multiple times in the netlist file.\n"), NAMEONPCB_NAME ((ElementType *) LastPoint.ptr1), (LastPoint.type == PIN_TYPE) ? ((PinType *) LastPoint.ptr2)-> Number : ((PadType *) LastPoint.ptr2)->Number); else { connection = GetConnectionMemory (net); *connection = LastPoint; /* indicate expect net */ connection->menu = menu; /* mark as visited */ SET_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2); if (LastPoint.type == PIN_TYPE) ((PinType *) LastPoint.ptr2)->Spare = (void *) menu; else ((PadType *) LastPoint.ptr2)->Spare = (void *) menu; } } else badnet = true; /* check for more pins with the same number */ for (; SeekPad (entry, &LastPoint, true);) { connection = GetConnectionMemory (net); *connection = LastPoint; /* indicate expect net */ connection->menu = menu; /* mark as visited */ SET_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2); if (LastPoint.type == PIN_TYPE) ((PinType *) LastPoint.ptr2)->Spare = (void *) menu; else ((PadType *) LastPoint.ptr2)->Spare = (void *) menu; } } END_LOOP; } END_LOOP; } /* clear all visit marks */ ALLPIN_LOOP (PCB->Data); { CLEAR_FLAG (DRCFLAG, pin); } ENDALL_LOOP; ALLPAD_LOOP (PCB->Data); { CLEAR_FLAG (DRCFLAG, pad); } ENDALL_LOOP; return (Wantlist); }